跳到主要内容

屏幕共享

融云 RTCLib SDK 为开发者提供了屏幕共享插件,屏幕共享功能以插件库形式提供,开发者可自行选择是否向项目中集成 RongRTCReplayKitExt 插件库来实现屏幕共享功能。RongRTCReplayKitExt 插件用于拓展 target 上使用。

提示
  • 屏幕共享功能在 RongRTCLib 5.1.8.1 及以后支持。
  • 屏幕共享库 RongRTCReplayKitExt 依赖的 RongRTCLib 版本必须大于等于 5.1.8.1

环境要求

  • iOS: iOS12 及以上。
  • RongRTCLib: 5.1.8.1 及以上。
  • RongRTCReplayKitExt: 5.1.8.1 及以上。

实现方式

我们可以通过苹果的 Extension 来实现屏幕共享技术。这里我们将通过使用 iOS11 之后新增的系统级别的录屏能力,来实现录制自身 App 以外,手机屏幕内容的效果(受 iOS 系统的 ReplayKit 库限制, iOS12 前在 App 中调用 Extension 启动屏幕共享时, 只能作用于 App 内, 如果退出 App 则无法得到屏幕内容)。

iOS 端的屏幕共享是通过在 Extension 中使用 RongRTCReplayKitExt 框架实现录制屏幕流的接收,然后将屏幕共享流传输到 RTCLib 实现的。由于 Apple 不支持 Extension 进程与主 app 进程通信,因此您需要为屏幕共享流单独创建一个进程。

(height=300)

实现屏幕共享的主要步骤如下:

  1. 创建 App Group,并在 XCode 中进行配置。目的是让 Extension 录屏进程可以同主 App 进程进行跨进程通信。
  2. 创建一个 Broadcast Upload Extension 用于开启屏幕共享的进程。
  3. 宿主 APP 开启屏幕共享并发布屏幕共享流。
  4. 屏幕共享 Extension 收到消息,初始化 RongRTCReplayKitExt 库, 接收系统录制数据。

集成说明

创建 App Group:

使用您的帐号登录 苹果开发者后台 ,进行以下操作,注意完成后需要重新下载对应的 Provisioning Profile。

  1. 单击【Certificates, IDs & Profiles】。
  2. 在右侧的界面中单击加号。
  3. 选择【App Groups】,单击【Continue】。
  4. 在弹出的表单中填写 Description 和 Identifier, 其中 Identifier 需要传入接口中的对应的 AppGroup 参数。完成后单击【Continue】。
  5. 回到 Identifier 页面,左上边的菜单中选择【App IDs】,然后单击您的 App ID(主 App 与 Extension 的 AppID 需要进行同样的配置)。
  6. 选中【App Groups】并单击【Edit】。
  7. 在弹出的表单中选择您之前创建的 App Group,单击【Continue】返回编辑页,单击【Save】保存。
  8. 重新下载 Provisioning Profile 并配置到 XCode 中。

创建 Broadcast Upload Extension:

  1. 在 Xcode 菜单依次单击【File】、【New】 、【Target...】,选择【Broadcast Upload Extension】,创建类型为 Broadcast Upload Extension 的新 target。

    (height=300)

  2. 在弹出的对话框中填写相关信息,不用勾选【Include UI Extension】,单击【Finish】完成创建。

  3. 在您的 屏幕共享 Target - Build Phases - Compile Sources 中添加您可能在屏幕共享 Extension 里引用类的 .m 文件名。

  4. 受限于 RongIMLib 库中的默认 2 分钟断开连接的限制,需要修改如下 pod 路径下的 .plist 配置文件:

    您的工程名/Pods/RongCloudIM/IMLibCore/RCConfig.plist

    在此文件中添加:

    <key>Connection</key>
    <dict>
    <key>ForceKeepAlive</key>
    <true/>
    </dict>

    其中:ConnectionForceKeepAlive 类型为 Key 值,ture 的类型为 Bool。

  5. 选中新增加的 Target,依次单击【+ Capability】,双击【App Groups】,如下图:

    (height=300)

    操作完成后,会在文件列表中生成一个以您自己创建的 Target 命名的 Target名.entitlements 的文件,如下图所示,选中该文件并单击 + 号填写上述步骤中的 App Group 即可。

    (height=300)

  6. 选中宿主 App 的 Target ,并按照上述步骤对宿主 App 的 Target 做同样的处理。

导入 SDK

SDK 支持通过 CocoaPods 或手动依赖 Framework 的方式导入到项目中。

CocoaPods 自动导入(推荐)

  1. 请运行以下命令更新本地的 CocoaPods 仓库列表:

    pod repo update
  2. 请在 podfile 中添加如下内容:

    target '主进程APP Target' do
    use_frameworks!
    pod 'RongCloudRTC/RongRTCLib','~> 5.1.8.1'
    end

    target '您的屏幕共享的 target' do
    use_frameworks!
    pod 'RongCloudRTC/RongRTCReplayKitExt','~> 5.1.8.1'
    end
  3. 请在终端中运行以下命令:

    pod install
  4. pod install 完成后,会自动导入指定版本的 RongIMLib,CocoaPods 会在您的工程根目录下生成一个 .xcworkspace 文件,打开即可。

手动依赖 Framework

  1. 在融云官网下载实时音视频库进行集成。下载地址

  2. 在主进程 APP Target中 导入 RongRTCLib.xcframeworkRongIMLibCore.xcframeworkRongRTCReplayKitExt.xcframework。在您的屏幕共享的 target 中导入 RongRTCReplayKitExt.xcframework

    (width=300) (width=300)

  3. 权限配置

    1. 音视频通话需要用到摄像头和麦克风权限,请在工程的 info.plist 中添加如下键值:
      • Privacy - Microphone Usage Description
      • Privacy - Camera Usage Description
    2. 请将工程中 Target -> Signing & Capabilities -> Background Modes 如下内容勾选:
      • Audio, AirPlay, and Picture in Picture

共享实现

iOS 系统上的跨应用屏幕分享,需要增加 Extension 录屏进程以配合宿主 App 进程进行推流。Extension 录屏进程由系统在需要录屏的时候创建,并负责接收系统采集的 CMSampleBufferRef 数据。

宿主 App

宿主 App 在加入房间后在需要屏幕共享时,通过点击录制按钮通知屏幕共享 target、并发布屏幕共享流。

添加系统录制按钮

提示

此按钮需 iOS12 及以上可用。

  • 示例代码:

    #import <ReplayKit/ReplayKit.h>

    // 添加录制按钮
    RPSystemBroadcastPickerView *systemBroadcastPickerView = [[RPSystemBroadcastPickerView alloc] initWithFrame:CGRectMake(0, 64, 50, 80)];
    systemBroadcastPickerView.preferredExtension = @“您的屏幕共享 target 的 Bundle Identifier”;
    systemBroadcastPickerView.backgroundColor = [UIColor colorWithRed:53.0/255.0 green:129.0/255.0 blue:242.0/255.0 alpha:1.0];
    systemBroadcastPickerView.showsMicrophoneButton = NO;
    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]initWithCustomView:systemBroadcastPickerView];

初始化并连接

初始化 SDK 并连接融云服务器。

示例代码:

[[RCCoreClient sharedCoreClient] initWithAppKey:@"您的AppKey"];
// 连接 IM
[[RCCoreClient sharedCoreClient] connectWithToken:@"您的token" dbOpened:^(RCDBErrorCode code) {

} success:^(NSString *userId) {
// 可以在此处加入房间
} error:^(RCConnectErrorCode errorCode) {
}];

监听屏幕共享流的发布与取消

在发布屏幕共享流之前,可以先设置 RCRTCEngine 的代理,通过对应的代理方法来获取发布与取消屏幕共享流的时机。

  • 示例代码:

    [RCRTCEngine sharedInstance].delegate = self;

    // 屏幕共享拓展 结束消息回调 Added from 5.1.8
    - (void)screenShareExtentionFinished {
    }
    // 屏幕共享拓展 开始消息回调 Added from 5.2.0
    - (void)screenShareExtentionStarted {
    }

加入房间

连接 SDK 成功后,配置房间信息并加入房间。

  • 示例代码:

    [[RCRTCEngine sharedInstance] joinRoom:@"您的房间号"
    completion:^(RCRTCRoom * _Nullable room, RCRTCCode code) {
    room.delegate = self;
    // 发布资源
    [self publishScreenStream];
    }];

发布资源

加入房间成功后可以发布 RCRTCScreenShareOutputStream 流。直播与会议场景发布流的方法不同,请注意区分。

  • 获取 RCRTCScreenShareOutputStream 方式

    /*!
    获取屏幕共享所需流

    @param groupId groupId 苹果开发者账号后台申请

    @remarks RCRTCEngine:RCRTCScreenShareOutputStream get 接口
    added from 5.1.8.1
    */
    - (RCRTCScreenShareOutputStream *)getDefaultVideoStreamWith:(NSString *)groupId;
  • 示例代码:

    在会议场景下,请使用 publishStream:completion 方法。

    RCRTCScreenShareOutputStream *videoOutputStream = [[RCRTCEngine sharedInstance] getScreenShareVideoStreamWithGroupId:@"您的屏幕共享 Extension 的 Group ID"];

    RCRTCVideoStreamConfig *videoConfig = videoOutputStream.videoConfig;
    videoConfig.videoSizePreset = RCRTCVideoSizePreset1280x720;
    videoConfig.videoFps = RCRTCVideoFPS24;
    [videoOutputStream setVideoConfig:videoConfig];

    [self.room.localUser publishStream:videoOutputStream
    completion:^(BOOL isSuccess, RCRTCCode desc) {}];

    在直播场景下,请使用 publishLiveStream:completion 方法。

    RCRTCScreenShareOutputStream *videoOutputStream = [[RCRTCEngine sharedInstance] getScreenShareVideoStreamWithGroupId:@"您的屏幕共享 Extension 的 Group ID"];

    RCRTCVideoStreamConfig *videoConfig = videoOutputStream.videoConfig;
    videoConfig.videoSizePreset = RCRTCVideoSizePreset1280x720;
    videoConfig.videoFps = RCRTCVideoFPS24;
    [videoOutputStream setVideoConfig:videoConfig];

    [[self.room.localUser publishLiveStream:videoOutputStream
    completion:^(BOOL isSuccess, RCRTCCode code, RCRTCLiveInfo *_Nullable liveInfo) {
    }];

屏幕共享 Extension

屏幕共享 target 在收到录制通知后,需要初始化 RongRTCReplayKitExt 库,并接收系统源数据。

SampleHandler 文件处理

在系统对应函数里这里初始化sdk,接收系统 CMSampleBufferRef 源数据。

  • 示例代码:

    #import "SampleHandler.h"
    #import <RongRTCReplayKitExt/RongRTCReplayKitExt.h>

    static NSString *const ScreenShareGroupID = @"您的屏幕共享 Extension 的 Group ID";

    @implementation SampleHandler

    - (void)broadcastStartedWithSetupInfo:(NSDictionary<NSString *, NSObject *> *)setupInfo {
    //初始化sdk
    [[RCRTCReplayKitEngine sharedInstance] setupWithAppGroup:ScreenShareGroupID delegate:self];
    }

    - (void)broadcastPaused {
    }

    - (void)broadcastResumed {
    }

    - (void)broadcastFinished {
    //结束处理
    [[RCRTCReplayKitEngine sharedInstance] broadcastFinished];
    }

    - (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType API_AVAILABLE(ios(10.0)) {
    switch (sampleBufferType) {
    case RPSampleBufferTypeVideo:
    //接收系统数据回调
    [[RCRTCReplayKitEngine sharedInstance] sendSampleBuffer:sampleBuffer withType:RPSampleBufferTypeVideo];
    break;
    case RPSampleBufferTypeAudioApp:
    // Handle audio sample buffer for app audio
    break;
    case RPSampleBufferTypeAudioMic:
    // Handle audio sample buffer for mic audio
    break;

    default:
    break;
    }
    }
提示

Broadcast Upload Extension 的内存使用限制为 50 MB,请确保屏幕共享的 Extension 内存使用不超过 50 MB。可以参考 RTC Quick DemoGitHub · Gitee)内屏幕共享的实现。