Agora Flutter SDK:如何监听对端屏幕共享的开始与结束事件?
解决Agora Flutter SDK点对点通话中屏幕共享的接收端交互问题
核心问题分析
Agora RTC SDK默认会让发起方的屏幕共享流替换自身摄像头流,导致接收端无法区分两种流,且没有内置事件通知接收端共享状态变化。解决这个问题需要通过自定义信令传递状态+区分流标识的组合方案实现。
1. 用自定义信令实现屏幕共享状态通知
由于SDK未提供接收端的共享状态回调,可借助Agora RTM(实时消息)或自定义信令通道,在发起方触发共享动作时主动通知接收端:
发起方(Peer1)代码示例:
// 初始化并登录Agora RTM客户端(需提前完成配置) final agoraRtmClient = AgoraRtmClient.createInstance(appId); await agoraRtmClient.login(null, peer1Uid); // 开始屏幕共享前发送通知 await agoraRtmClient.sendMessageToPeer( peer2Uid, AgoraRtmMessage.fromText('screen_share_start'), ); // 启动屏幕共享 await agoraRtcEngine.startScreenCapture(); // 结束屏幕共享时发送通知 await agoraRtmClient.sendMessageToPeer( peer2Uid, AgoraRtmMessage.fromText('screen_share_end'), ); await agoraRtcEngine.stopScreenCapture();
接收方(Peer2)代码示例:
// 监听RTM消息,更新共享状态 agoraRtmClient.onMessageReceived = (AgoraRtmMessage message, String peerId) { if (message.text == 'screen_share_start') { setState(() { _isScreenSharingActive = true; }); } else if (message.text == 'screen_share_end') { setState(() { _isScreenSharingActive = false; _isScreenShareFullscreen = false; _isShareHidden = false; }); } };
2. 区分摄像头流与屏幕共享流
为避免共享画面覆盖摄像头窗口,发起方需使用独立UID发起屏幕共享(与主通话UID区分开,比如约定主UID+固定偏移):
发起方启动屏幕共享时使用独立UID:
// 主通话用默认UID,屏幕共享用自定义UID(示例:主UID+1000) final int _screenShareUid = peer1MainUid + 1000; await agoraRtcEngine.setClientRole(ClientRole.broadcaster); await agoraRtcEngine.joinChannel(token, channelId, null, _screenShareUid); await agoraRtcEngine.startScreenCapture();
接收方分别渲染两种流:
通过两个AgoraVideoView分别渲染主摄像头流和屏幕共享流,结合共享状态控制显示与布局:
@override Widget build(BuildContext context) { return Stack( children: [ // 主摄像头窗口(全屏时缩小到角落) Positioned( top: _isScreenShareFullscreen ? 10 : 0, right: _isScreenShareFullscreen ? 10 : 0, width: _isScreenShareFullscreen ? 120 : MediaQuery.of(context).size.width, height: _isScreenShareFullscreen ? 180 : MediaQuery.of(context).size.height, child: AgoraVideoView( controller: AgoraVideoViewController( rtcEngine: agoraRtcEngine, canvas: VideoCanvas(uid: peer1MainUid), ), ), ), // 屏幕共享窗口(仅激活且未隐藏时显示) if (_isScreenSharingActive && !_isShareHidden) Positioned.fill( child: AgoraVideoView( controller: AgoraVideoViewController( rtcEngine: agoraRtcEngine, canvas: VideoCanvas(uid: peer1ScreenShareUid), ), ), ), // 控制按钮区域 if (_isScreenSharingActive) Positioned( bottom: 20, left: 0, right: 0, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton( onPressed: () => setState(() => _isScreenShareFullscreen = !_isScreenShareFullscreen), child: Text(_isScreenShareFullscreen ? '退出全屏' : '全屏共享'), ), const SizedBox(width: 16), ElevatedButton( onPressed: () => setState(() => _isShareHidden = !_isShareHidden), child: Text(_isShareHidden ? '显示共享' : '隐藏共享'), ), ], ), ), ], ); }
3. 关键注意事项
- UID约定:双方需提前约定屏幕共享UID规则(如主UID+固定偏移),避免冲突。
- 信令可靠性:可添加信令确认机制(如接收端收到后回复
ack),确保状态通知不丢失。 - 权限处理:Android需申请
MEDIA_PROJECTION权限,iOS需开启Screen Recording权限,否则屏幕共享无法启动。 - 资源释放:结束共享后,调用
leaveChannel释放共享UID对应的通道资源,避免内存泄漏。
内容的提问来源于stack exchange,提问作者alkhatibdev
相关产品推荐
相关产品推荐

