fix(android-call): no hole-punch without native video (white meeting bg)

On an Android native call the WebView turned on hole-punch (transparent
meeting grid, so native video can show BEHIND the WebView) whenever the
plugin exposed setHolePunch — but on the 2a audio-only build there is no
native video behind it, so the transparent grid revealed the white Android
window (reported: white meeting background; tiles stayed visible as they're
opaque web elements). iOS never showed this because CallKit covers the view.

Gate hole-punch on native video actually existing: new ANDROID_NATIVE_VIDEO
server flag (mirrors ANDROID_NATIVE_MEDIA, default off) exposed via
/api/meetings/config. Web: bzNativeVideoOn() — iOS always, Android only when
the flag is on (Increment 2b APK). While off, hole-punch stays off and the
grid keeps its dark background; the native-tile poll doesn't run. iOS
unchanged. Flip the flag on once the 2b native-video APK is installed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
SravanandClaude Opus 4.8 committed 2026-11-03 20:12:21 +05:30
1 parent ea4d65274e
commit ae607f44b5
3 files changed
+20 -4

No files matched your search

+9 -2
View File
@@ -4336,6 +4336,7 @@ async function unsubscribePush(){
// (onDmCall / the group invite check nativeCallOn()).
let _callkitReady=false;
let _callWebViewMedia=false; // Android Increment 1: native full-screen ring, but MEDIA stays in the WebView (iOS runs the call media natively via the plugin). Governs the answer/outgoing branches below.
let _androidNativeVideo=false; // Android Increment 2b: plugin renders native video tiles via hole-punch. OFF until a 2b APK is installed (server androidNativeVideo). While off, hole-punch stays off so the grid keeps its dark background (a transparent grid with no native video behind = white page). iOS video is always native.
let _nativeAnswered=new Set(); // rooms this device answered natively (so a "call-taken" from the server doesn't end our own call)
let _myVoipTok=''; // this device's own iOS VoIP (ios-voip) token — sent on answer so the answered-elsewhere cancel skips us
function nativeCallPlugin(){ const P=window.Capacitor&&window.Capacitor.Plugins; return (P&&P.NativeCall)||null; }
@@ -4354,8 +4355,9 @@ async function setupNativeCall(){
// Speaker/Bluetooth) and the WebView must NOT also join SFU media. Until then (default), media stays in the
// WebView (video calls included). androidNativeMedia === true → _callWebViewMedia=false (native media path).
_callWebViewMedia = !(cfg && cfg.androidNativeMedia);
_androidNativeVideo = !!(cfg && cfg.androidNativeVideo); // Increment 2b: native video tiles + hole-punch
if(!_callWebViewMedia){
console.log('[nativecall] Android native call media ON — background audio + native routing');
console.log('[nativecall] Android native call media ON — background audio + native routing' + (_androidNativeVideo?' + native video (2b)':' (audio-only; video in WebView path off)'));
// Android CAN switch the output (unlike iOS): mirror the plugin's real route into the speaker button.
try{ NC.addListener('audioRoute', (e)=>{ bzOnAndroidRoute(e); }); }catch(_){}
}
@@ -6183,10 +6185,15 @@ function bzNativeSyncTiles(){
});
try{ NC.syncVideoTiles({ tiles }); }catch(_){}
}
// Native video available? iOS: always (shipped). Android: only when a 2b-capable APK is active (server flag).
// While false we must NOT enable hole-punch — a transparent grid with no native video behind it shows the white
// page (the 2a audio-only bug). Keeps the opaque dark grid + web avatars instead.
function bzNativeVideoOn(){ try{ const p=nativePlatform(); if(p==='ios') return true; if(p==='android') return !!_androidNativeVideo; return false; }catch(_){ return false; } }
function bzNativeStartTiles(){
if(!meetNative) return;
const NC=nativeCallPlugin();
if(NC && NC.setHolePunch){ bzHolePunch=true; try{ NC.setHolePunch({ on:true }); }catch(_){} document.body.classList.add('bz-hp'); } // permanent fix: video behind transparent WebView
if(NC && NC.setHolePunch && bzNativeVideoOn()){ bzHolePunch=true; try{ NC.setHolePunch({ on:true }); }catch(_){} document.body.classList.add('bz-hp'); } // video behind transparent WebView (only when native video exists)
if(!bzNativeVideoOn()) return; // no native video (e.g. Android 2a audio-only): nothing to render; keep the normal web grid
if(_ncTileTimer) return; _ncTileTimer=setInterval(bzNativeSyncTiles, 400); bzNativeSyncTiles();
}
function bzNativeStopTiles(){