You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 01:42:19