跳到主要内容

屏幕共享

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

环境要求

  • iOS 系统版本 12 及以上
  • 屏幕共享功能在 RTCLib SDK 5.1.8.1 及以后支持
  • 屏幕共享库 RongRTCReplayKitExt 依赖的 RTCLib SDK 版本必须大于等于 5.1.8.1

实现方式

我们可以通过苹果的 Extension 来实现屏幕共享技术。这里将通过使用 iOS 11 之后新增的系统级别的录屏能力,来实现录制自身 App 以外手机屏幕内容的效果。

提示

受 iOS 系统的 ReplayKit 库限制,iOS 12 前在 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

提示
  • 新版本 Xcode 支持在 Target 下 Signing & Capabilities 页面中 App Groups 进行创建并关联 AppGroup,可以直接跳过如下 1-5 步。
  • 老版本 Xcode 可能无法直接使用 Xcode 创建 AppGroup,需要使用您的帐号登录 苹果开发者后台 ,进行以下 1-5 步操作来创建 AppGroup,然后再关联 AppGroup。
  1. 单击 Certificates, IDs & Profiles,在右侧的界面中单击加号。

    (height=300)

  2. 选择 App Groups,单击 Continue

    (height=300)

  3. 在弹出的表单中填写 Description 和 Identifier, 其中 Identifier 需要传入接口中的对应的 AppGroup 参数。完成后单击 Continue

    (height=300)

  4. 回到 Identifier 页面,然后单击您的 App ID,进入 Edit your App ID Configuration 页面,选中 App Groups 并单击 Edit

    (height=300)

  5. 在弹出的表单中选择您之前创建的 App Group,单击 Continue 返回 Edit your App ID Configuration 页面,单击 Save 保存。

    (height=300)

  6. 打开 Xcode,选中屏幕共享 Target(Broadcast Upload Extension) 点击 App Groups+ 按钮。

    (height=300)

  7. 输入的 AppGroup,然后点击 OK 按钮,如果输入的 AppGroup 的已经创建过,则直接关联上;如果输入的 AppGroup 没有被创建过,则创建的同时进行关联。

    (height=300)

创建 Broadcast Upload Extension:

  1. 在 Xcode 菜单依次单击 FileNewTarget...,选择 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

    在此文件中添加:

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

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

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

    (height=300)

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

    (height=300)

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

导入 SDK

融云支持使用 CocoaPods 和本地手动导入两种方式,将 RTCLib SDK 和屏幕共享扩展导入到您的应用工程中。

CocoaPods 导入(推荐)

  1. 如果您的项目中没有 Podfile 文件,您需要打开终端并进入到项目的根目录,在终端中运行 pod init 命令,之后系统会自动创建一个默认的 Podfile 文件。

  2. 在项目中的 Podfile 文件中添加如下内容:

    ruby
    target '主进程APP Target' do
    use_frameworks!
    pod 'RongCloudRTC/RongRTCLib', '~> x.y.z'
    end

    target '您的屏幕共享的 target' do
    use_frameworks!
    pod 'RongCloudRTC/RongRTCReplayKitExt', '~> x.y.z'
    end
  3. 打开终端并进入到 Podfile 文件所在的目录,在终端中运行以下命令:

    shell
    pod install
    提示

    如果终端中出现类似 CocoaPods could not find compatible versions for 等找不到相关版本的报错,可先在终端中执行 pod repo update 命令,再执行 pod install 命令。

  4. 通过 Xcode 打开项目目录下的 xcworkspace 文件加载工程。

手动集成

  1. 您可以前往融云官网 SDK 下载页面,将音视频通话(无 UI)SDK 下载到本地。

  2. 使用 Xcode 打开您的工程,然后将下载下来的 SDK 手动拖入到您的项目中:

    主进程 App Target 所需的 SDK:

    Framework
    • RongRTCLib.xcframework
    • RongIMLibCore.xcframework
    • RongRTCReplayKitExt.xcframework

    屏幕共享 Extension Target 所需的 SDK:

    Framework
    • RongRTCReplayKitExt.xcframework

    (width=300) (width=300)

  3. 修改您的项目配置。在 GeneralFrameworks, Libraries, and Embedded Binaries 中,将手动导入的 RTCLib SDK 所有的 Framework 全部改为 Embed & Sign

工程配置

  1. 音视频通话需要用到摄像头和麦克风权限,请在工程的 Info.plist 中添加如下键值:

    • Privacy - Microphone Usage Description
    • Privacy - Camera Usage Description
  2. 请将工程中 Target → Signing & Capabilities → Background Modes 如下内容勾选:

    • Audio, AirPlay, and Picture in Picture

导入头文件

在需要使用的业务层导入 RTCLib 头文件,即可使用 SDK 的方法来实现屏幕共享相关业务。

主进程 App 导入:

Objective C
#import <RongRTCLib/RongRTCLib.h>

屏幕共享 Extension 导入:

Objective C
#import <RongRTCReplayKitExt/RongRTCReplayKitExt.h>

共享实现

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

宿主 App

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

添加系统录制按钮

提示

此按钮需 iOS 12 及以上可用。

代码示例
Objective C
#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 并连接融云服务器。

代码示例
Objective C
#import <RongRTCLib/RongRTCLib.h>

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

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

}];

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

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

屏幕共享扩展结束
接口原型
Objective C
- (void)screenShareExtentionFinished;
屏幕共享扩展开始
接口原型
Objective C
- (void)screenShareExtentionStarted;
代码示例
Objective C
#import <RongRTCLib/RongRTCLib.h>

[RCRTCEngine sharedInstance].delegate = self;

// 屏幕共享扩展结束消息回调 Added from 5.1.8
- (void)screenShareExtentionFinished {
NSLog(@"屏幕共享扩展结束");
}

// 屏幕共享扩展开始消息回调 Added from 5.2.0
- (void)screenShareExtentionStarted {
NSLog(@"屏幕共享扩展开始");
}

加入房间

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

代码示例
Objective C
#import <RongRTCLib/RongRTCLib.h>

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

发布资源

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

获取屏幕共享流
接口原型
Objective C
- (RCRTCScreenShareOutputStream *)getScreenShareVideoStreamWithGroupId:(NSString *)groupId;
参数说明
参数类型是否必填说明
groupIdNSString *苹果开发者账号后台申请的 Group ID
返回值
类型说明
RCRTCScreenShareOutputStream屏幕共享输出流
代码示例
会议场景

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

Objective C
#import <RongRTCLib/RongRTCLib.h>

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 方法。

Objective C
#import <RongRTCLib/RongRTCLib.h>

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 源数据。

初始化屏幕共享引擎
接口原型
Objective C
- (void)setupWithAppGroup:(NSString *)appGroup delegate:(id<RCRTCReplayKitEngineDelegate>)delegate;
参数说明
参数类型是否必填说明
appGroupNSString *App Group 标识符
delegateid<RCRTCReplayKitEngineDelegate>屏幕共享引擎代理
发送系统数据
接口原型
Objective C
- (void)sendSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType;
参数说明
参数类型是否必填说明
sampleBufferCMSampleBufferRef系统采集的数据
sampleBufferTypeRPSampleBufferType数据类型
提示
  • sampleBufferType 当前支持 RPSampleBufferTypeVideo 和 RPSampleBufferTypeAudioApp 类型的数据帧处理。
  • RPSampleBufferTypeAudioMic 不支持,请在主 app 处理麦克风采集数据
结束广播
接口原型
Objective C
- (void)broadcastFinished;
代码示例
Objective C
#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;
}
}

@end
提示

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