From 8f2779ac2f7889a01a651b77bb459fd4f690fbfa Mon Sep 17 00:00:00 2001 From: jajajhhz Date: Mon, 1 Jun 2026 16:34:11 +0800 Subject: [PATCH 1/2] Fix black screen: subscribe to Media Gateway streams via live mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The viewer hardcoded createClient({ mode: 'rtc' }). Streams injected by Agora Media Gateway (RTMP/SRT ingest, e.g. the deviceShifu cameras) join the channel as live-broadcast hosts, which an rtc/communication-mode client cannot see — so remoteUsers stays 0 and the page renders black. Switch to live-broadcast mode and set the client role before joining (audience for viewers, host for publishers) so the viewer subscribes to the camera's video track. Co-Authored-By: Claude Opus 4.8 --- src/lib/agora-config.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/lib/agora-config.ts b/src/lib/agora-config.ts index ae1c231..88901d6 100644 --- a/src/lib/agora-config.ts +++ b/src/lib/agora-config.ts @@ -20,7 +20,7 @@ export class AgoraClient { constructor(config: AgoraConfig) { this.config = { - mode: 'rtc', + mode: 'live', codec: 'vp8', ...config }; @@ -31,10 +31,12 @@ export class AgoraClient { const AgoraRTC = (await import('agora-rtc-sdk-ng')).default; - // Force RTC mode and VP8 codec for video streaming + // Use live-broadcast mode so the client can subscribe to streams injected + // by Agora Media Gateway (RTMP/SRT ingest), which join the channel as + // live-broadcast hosts. An rtc/communication-mode client cannot see them. this.client = AgoraRTC.createClient({ - mode: 'rtc', - codec: 'vp8' + mode: this.config.mode || 'live', + codec: this.config.codec || 'vp8' }); this.setupEventListeners(); @@ -205,6 +207,10 @@ export class AgoraClient { } } + // In live-broadcast mode every client must declare its role before joining: + // publishers join as hosts, viewers as audience so they subscribe to hosts. + await this.client.setClientRole(role === 'publisher' ? 'host' : 'audience'); + const uid = await this.client.join( this.config.appId.trim(), this.config.channel.trim(), From c17f45f461538525d074eb5ed87b98a995628da8 Mon Sep 17 00:00:00 2001 From: jajajhhz Date: Mon, 1 Jun 2026 17:04:05 +0800 Subject: [PATCH 2/2] Also coerce numeric uid to Number to avoid user-account mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A string uid (e.g. from a URL query param) makes the SDK join in user-account mode, where the client does not receive the Media Gateway host's published stream — another cause of the black screen. Join with an integer uid when the value is numeric. Co-Authored-By: Claude Opus 4.8 --- src/lib/agora-config.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/lib/agora-config.ts b/src/lib/agora-config.ts index 88901d6..2e7c637 100644 --- a/src/lib/agora-config.ts +++ b/src/lib/agora-config.ts @@ -211,11 +211,20 @@ export class AgoraClient { // publishers join as hosts, viewers as audience so they subscribe to hosts. await this.client.setClientRole(role === 'publisher' ? 'host' : 'audience'); + // Coerce a numeric uid to a Number. The cameras are injected by Media + // Gateway with integer uids; joining with a *string* uid puts us in + // user-account mode, where we don't receive the host's published stream + // (black screen). Keep genuinely non-numeric accounts as-is. + const joinUid = + this.config.uid === undefined || this.config.uid === null || this.config.uid === '' + ? null + : (isNaN(Number(this.config.uid)) ? this.config.uid : Number(this.config.uid)); + const uid = await this.client.join( this.config.appId.trim(), this.config.channel.trim(), token, - this.config.uid || null + joinUid ); console.log(`Joined channel as ${role} with uid:`, uid);