写点什么

如何基于 PANO SDK 实现 iOS 端屏幕共享互动

用户头像
拍乐云Pano
关注
发布于: 2021 年 04 月 28 日
如何基于 PANO SDK 实现 iOS 端屏幕共享互动

前言

屏幕共享作为视频通话功能中一项核心的技术能力,被广泛应用于教育、金融、视频会议等行业场景,提升在线互动的效率和执行力。通过屏幕共享,能解决在线教育、智慧课堂等场景中共享教学内容的痛点;也能满足在线理财、视频客服、金融双录场景中共享金融应用的痛点;还能高效连接企业内外,打破时间空间的限制,提供内外部会议、员工培训、企业直播等全场景解决方案。

拍乐云音视频 PaaS 云平台除了提供桌面端和 Android 端屏幕共享能力外,新增 iOS 端屏幕共享 SDK,本篇技术教程将教大家如何快速在 iOS 端接入屏幕共享功能,接入即用、高效开发,实现高清 ScreenShare。

实现原理

iOS 上实现系统级屏幕共享需要通过 Broadcast Upload Extension 录屏扩展配合主 App 进行。录屏扩展负责接收屏幕图像数据,并通过 Socket 通信将数据回传给主 App,由主 App 负责发送数据。

接入流程

一、 配置 App Group(可选)

App 开发文档中对 App Group 进行了如下解释:

Apps within a group can communicate with other members in the group using IPC mechanisms including Mach IPC, POSIX semaphores and shared memory, and UNIX domain sockets.

因此当我们使用 App Group ,便能通过 UNIX domain sockets 来获取更加稳定高效的数据传输。

注意:选择不配置 App Group 依然可以使用屏幕共享的功能,但可能影响数据传输稳定性。所以建议尽量正确配置 App Group 以获得最佳体验。

1、通过 Xcode,选择主 App 的 Target,单击 Signing & Capabilities;

2、点击下方+ Capability;

3、在弹出框中双击选择 App Groups;

4、点击+新增 App Group ID,在弹出框中填入自定义 ID;

5、完成后在 App Groups 中选中对应的 App Group ID。

二、 创建 Broadcast Upload Extension

1、在 Xcode 工程中,选中对应 Project,点击 Targets 列表底部+添加按钮,并选中 Broadcast Upload Extension;

2、点击下一步后,在弹出框中填写相关信息,不用勾选 Include UI Extension,点击 Finish 完成创建;

3、将从官网下载的 SDK 压缩包中 PanoReplayKitExt.framework(下称扩展 SDK)添加到 Extension 的 Target 中;

4、如果选择配置 App Group ID 模式,则选中刚创建的 Extension 的 Target,执行在步骤 1 配置 App Group 对主 App 相同的设置(可选)。

三、 对接 Extension 数据采集

创建 Extension 的 Target 中,Xcode 会自动生成 SampleHandler 类文件,引入 PanoReplayKitExt 头文件并按照如下添加代码,即可完成数据采集部分逻辑。

1、在系统启动 Extension 时初始化扩展 SDK 并配置代理,替换 kAppGroupId 为设置的 App Group ID 如果按照上述步骤配置过:

- (void)broadcastStartedWithSetupInfo:(NSDictionary<NSString *,NSObject *> *)setupInfo {   // User has requested to start the broadcast. Setup info from the UI extension can be supplied but optional.  [PanoScreenSharingExt.sharedInstance setupWithAppGroup:kAppGroupId delegate:self];}
复制代码

2、在用户手动停止屏幕共享时通知扩展 SDK 结束共享:

- (void)broadcastFinished {   // User has requested to finish the broadcast.  [PanoScreenSharingExt.sharedInstance finishScreenSharing];}
复制代码

3、在系统数据采集方法中将 sampleBuffer 传递给扩展 SDK:

- (void)processSampleBuffer:                  (CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType {   switch (sampleBufferType) {       case RPSampleBufferTypeVideo:           // Handle video sample buffer          [PanoScreenSharingExt.sharedInstance             sendVideoSampleBuffer:sampleBuffer];           break;       case RPSampleBufferTypeAudioApp:           // Handle audio sample buffer for app audio           break;       case RPSampleBufferTypeAudioMic:           // Handle audio sample buffer for mic audio           break;              default:           break;  }}
复制代码

注意 扩展 SDK 只需要接收 Video 数据

4、实现扩展 SDK 代理回调,并处理与非用户结束共享事件:

- (void)screenSharingFinished:           (PanoScreenSharingResult)reason {   NSString *log;   switch (reason) {       case                            PanoScreenSharingResultVersionMismatch:           log = @"PanoReplayKitExt SDK version is mismatch with Pano SDK";           break;       case PanoScreenSharingResultCloseByHost:           log = @"Screen share is closed by host app";           break;       case PanoScreenSharingResultDisconnected:           log = @"The connect with host app is  abnormally disconnected";           break;       default:           break;  }   NSError *error = [NSError errorWithDomain:NSStringFromClass([self classForCoder]) code:0 userInfo:@{ NSLocalizedFailureReasonErrorKey : log }];  [self finishBroadcastWithError:error];}
复制代码

四、 对接主 App 数据接收

在用户触发屏幕共享前,需要先在主 App 侧,使用 Pano SDK 开启屏幕共享,让主 App 准备接收 Extension 的录屏数据,按照如下步骤进行对接:

1、确保调用屏幕共享接口前,已经加入频道中。

2、调用 startScreenWithAppGroupId:方法,传入步骤 1 配置 App Group 中配置的 App Group ID, 如果没有则传入 nil。调用成功后 SDK 则进入等待屏幕共享数据状态。

3、在 onScreenStartResult:代理回调方法中判断屏幕共享状态。

4、等待用户通过 iOS 系统控制中心触发屏幕录制,或者通过步骤 5 使用系统提供的 RPSystemBroadcastPickerView 类来启动。控制中心启动需要用户长按屏幕录制按钮,并在弹出列表中选中当前 Extension 来启动,如下图示例:

5、通过系统提供的 RPSystemBroadcastPickerView 类可以实现从主 App 内唤起屏幕录制页面,将如下代码添加至需要启动屏幕录制的地方(可选):

-(void)launchBroadcastPickerView                      API_AVAILABLE(ios(12.0)){   if (!self.broadcastPickerView)  {              RPSystemBroadcastPickerView                                              *pickerView = [[RPSystemBroadcastPickerView alloc] initWithFrame:CGRectMake(0, 0, 44, 44)];       pickerView.showsMicrophoneButton = NO;       pickerView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin;       NSString *pluginPath = [NSBundle mainBundle].builtInPlugInsPath;       NSArray *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:pluginPath error:nil];       for (NSString *content in contents) {           if (![content hasSuffix:@".appex"]) {               continue;          }           NSBundle *bundle = [NSBundle bundleWithPath:[[NSURL fileURLWithPath:pluginPath] URLByAppendingPathComponent:content].path];           if (bundle) {               NSString *identifier = [bundle.infoDictionary valueForKeyPath:@"NSExtension.NSExtensionPointIdentifier"];               if ([identifier isEqualToString:@"com.apple.broadcast-services-upload"]) {                   pickerView.preferredExtension = bundle.bundleIdentifier;              }          }      }       self.broadcastPickerView = pickerView;  }   for (UIView *view in self.broadcastPickerView.subviews) {       if ([view isKindOfClass:[UIButton class]]) {          [(UIButton *)view sendActionsForControlEvents:UIControlEventAllEvents];      }  }}
复制代码

注意:RPSystemBroadcastPicker-View 需要 iOS 12 以上支持。通过 RPSystemBroadcastPicker-View 目前不支持自定义界面,仅能唤起屏幕录制启动页面供用户启动。苹果官方并不推荐此方案,可能随着系统更新被禁止,因此您需要自行承担风险来选用此方案。

6、通过调用 stopScreen 来停止屏幕共享,用户也可以手动通过系统控制中心来停止。

五 、频道中其他用户观看屏幕共享

1、在 Pano SDK 代理回调 onUserScreen-Start: 中接收用户开启屏幕共享事件:

- (void)onUserScreenStart:(UInt64)userId {   dispatch_async(dispatch_get_main_queue(), ^{       // Must be called from main thread.      [self.engineKit subscribeScreen:userId withView:self.playView];  });}
复制代码

2、实现 Pano SDK 代理回调接受其他屏幕共享事件:

- (void)onUserScreenStop:(UInt64)userId {   // Handle user stop screen sharing}- (void)onUserScreenMute:(UInt64)userId {   // Handle user mute screen sharing}- (void)onUserScreenUnmute:(UInt64)userId {   // Handle user unmute screen sharing}
复制代码

注意:当用户停止屏幕共享时,Pano SDK 会自动取消订阅,不需要再调用 unsubscribeScreen:。

示例代码

相关示例代码我们已经开源在 GitHub 中 ScreenSharing 目录下,包含完整的屏幕共享发送与接收逻辑,您可以通过 README 或者结合上文跑通示例 Demo。https://github.com/PanoVideo/video-call-samples/tree/main/iOS/ScreenSharing关注拍乐云 Pano,获取更多实时音视频、互动白板相关的技术教程、开源实践和技术心得。


用户头像

拍乐云Pano

关注

Be Sharp,be simple 2020.06.28 加入

我们是一家由顶级音视频团队构建的实时通信Paas云服务公司,在音视频领域拥有超过二十年的技术积累。 我们通过提供极简、稳定和安全的SDK服务,让你的应用轻松实现音视频通话、互动白板、互动直播等能力。

评论

发布
暂无评论
如何基于 PANO SDK 实现 iOS 端屏幕共享互动