屏幕共享,是指在视频通话或互动直播过程中将屏幕内容以视频的方式分享给其他的观众,以增强互动体验,提高沟通效率。
屏幕共享在如下场景中应用广泛:
请参考 下载示例源码 获取源码。
相关源码请查看 "/ZegoExpressExample/Examples/Others/ScreenSharing" 目录下的文件。
在实现屏幕共享功能之前,请确保:
iOS 平台是基于苹果的 Replaykit 框架实现屏幕录制,能够分享整个系统的屏幕内容。但需要当前 App (主 App 进程)额外提供一个 Extension 扩展组件(Extension 进程),用于录制屏幕,再结合 ZEGO Express SDK 相关 API 来实现屏幕共享功能。
实现屏幕共享的主要流程如下:
切换采集源为屏幕共享源
开始屏幕共享
应用内共享
跨应用共享
登录房间推流
观看远端共享屏幕
停止屏幕共享
详细的操作请参考下文。
设置采集源为屏幕共享源,则需要对视频源和音频源进行设置。
SDK 推流的“视频源”默认为摄像头源,如果需要推屏幕共享源,需要通过 setVideoSource 进行切换为屏幕共享。
[ZegoExpressEngine.shareEnigne setVideoSource:ZegoVideoSourceScreenCapture channel:ZegoPublishChannelMain];
SDK 推流的“音频源”默认为麦克风源,如果需要推屏幕共享源,需要通过 setAudioSource 进行切换为屏幕共享。
若主路使用屏幕共享功能,只有当主路音频源设置为 Microphone
时,SDK 会启动音频内部采集,维持后台保活;若设置为其他音频源类型,当应用退出后台后,屏幕共享将停止使用,建议用户自主对应用添加后台保活逻辑。
[ZegoExpressEngine.shareEnigne setAudioSource:ZegoAudioSourceTypeScreenCapture channel:ZegoPublishChannelMain];
有两种屏幕共享方式,分别为“应用内屏幕共享”和“跨应用屏幕共享”。
若用户只在应用内共享画面与声音,可以调用 startScreenCaptureInApp 接口开启屏幕共享。也可调用 broadcastFinished 接口回调屏幕共享结束通知,若屏幕采集失败可接收到失败的原因。
ZegoScreenCaptureConfig *config = [[ZegoScreenCaptureConfig alloc] init];
config.captureVideo = true;
config.captureAudio = true;
[ZegoExpressEngine.sharedEngine startScreenCaptureInApp:config];
跨应用屏幕共享是由 iOS 系统通过 Extension 扩展进程进行录制的,所以需要再额外创建扩展进程,并启动。具体请参考如下实现步骤:
Broadcast Upload Extension 的内存使用限制为 50 MB,请勿在屏幕共享的 Extension 中进行额外的内存分配。
使用 Xcode 打开项目工程文件,在菜单栏中依次点击 “File > New > Target..."。
在弹出的窗口中选择 iOS 页的 “Broadcast Upload Extension” 后,单击 “Next”。
在弹出的对话框中的 “Product Name” 一栏填写 “Broadcast Upload Extension” 的名字,例如 “ScreenShare”。选择 “Team”、“Language” 等信息后,单击 “Finish” 。
无需勾选 “Include UI Extension”。
创建完成后,您会在项目中看到该 Extension 的文件夹,结构类似如下,该文件夹用于存放屏幕共享功能的实现代码:
若用户需要共享整个系统的画面与声音,可以调用 startScreenCapture 接口开启屏幕共享。
ZegoScreenCaptureConfig *config = [[ZegoScreenCaptureConfig alloc] init];
config.captureVideo = true;
config.captureAudio = true;
[ZegoExpressEngine.sharedEngine startScreenCapture:config];
有两种启动方式,请根据需要选择实现。
您需要在 iOS 系统的控制中心,长按录屏按钮后,选择对应的 Extension 来开启录制。
苹果在 iOS 12.0 中新增了 RPSystemBroadcastPickerView,可以从 App 应用弹出启动器,供用户确认启动屏幕分享。
RPSystemBroadcastPickerView *broadcastPickerView = [[RPSystemBroadcastPickerView alloc] initWithFrame:CGRectMake(0, 0, 44, 44)];
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"ZegoExpressExample-Broadcast" ofType:@"appex" inDirectory:@"PlugIns"];
if (bundlePath) {
NSBundle *bundle = [NSBundle bundleWithPath:bundlePath];
if (bundle) {
broadcastPickerView.preferredExtension = bundle.bundleIdentifier;
for (UIView *subView in broadcastPickerView.subviews) {
if ([subView isMemberOfClass:[UIButton class]]) {
UIButton *button = (UIButton *)subView;
[button sendActionsForControlEvents:UIControlEventAllEvents];
}
}
}
}
苹果在 iOS 12.0 中新增了 RPSystemBroadcastPickerView,可以从 App 应用弹出启动器,供用户确认启动屏幕分享。但目前 RPSystemBroadcastPickerView 还不支持自定义界面,也没有官方的唤起方法。
苹果官方不推荐该方案,并有可能在新一轮的系统更新中失效,因此只是一个可选方案,选用此方案您需要自行承担风险。
如下系统回调的实现,可以在 下载示例源码 中的 “/ZegoExpressExample/Examples/Others/ScreenSharing/ZegoExpressExample-Broadcast/SampleHandler.m” 文件中查看:
系统通过 broadcastStartedWithSetupInfo 回调通知 Extension 已开始录制屏幕,您需要在该回调中,调用 ZegoReplayKitExt 类中的 setupWithDelegate 接口创建数据传输通道:
[ZegoReplayKitExt.sharedInstance setupWithDelegate:self];
在 processSampleBuffer 系统回调中,通过 ZegoReplayKitExt 类中的 sendSampleBuffer 接口发送给 ZEGO Express SDK。
[ZegoReplayKitExt.sharedInstance sendSampleBuffer:sampleBuffer withType:sampleBufferType];
系统通过 broadcastFinished 回调通知 Extension 屏幕录制已结束,若屏幕录制失败可接收到失败的原因。您可以在该回调中,调用 ZegoReplayKitExt 类中的 finished 接口停止屏幕采集并断开数据传输通道:
[ZegoReplayKitExt.sharedInstance finished];
通过上述调用 SDK 的 setupWithDelegate 方法初始化并设置代理,可以在当前类添加 <ZegoReplayKitExtHandler>
协议以及实现回调,用于监听屏幕共享结束或失败的原因。
- (void)broadcastFinished:(ZegoReplayKitExt *)broadcast reason:(ZegoReplayKitExtReason)reason {
switch (reason) {
case ZegoReplayKitExtReasonHostStop:
{
NSDictionary *userInfo = @{NSLocalizedDescriptionKey : @"Host app stop srceen capture"};
NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain code:0 userInfo:userInfo];
[self finishBroadcastWithError:error];
}
break;
case ZegoReplayKitExtReasonConnectFail:
{
NSDictionary *userInfo = @{NSLocalizedDescriptionKey : @"Connect host app fail need startScreenCapture in host app"};
NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain code:0 userInfo:userInfo];
[self finishBroadcastWithError:error];
}
break;
case ZegoReplayKitExtReasonDisconnect:
{
NSDictionary *userInfo = @{NSLocalizedDescriptionKey : @"disconnect with host app"};
NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain code:0 userInfo:userInfo];
[self finishBroadcastWithError:error];
}
break;
}
}
完成上述屏幕共享源的采集过程后,将采集到的数据源 startPublishingStream 推送到云服务器。(推送数据源的通道必须与设置采集源的通道保持一致)
[ZegoExpressEngine.sharedEngine startPublishingStream:streamID channel:ZegoPublishChannelMain];
完成以上步骤后,其他用户可以使用 startPlayingStream 接口拉取屏幕共享流。
// 拉流播放,需传入发起屏幕共享的用户推流时所用的 streamID
[[ZegoExpressEngine sharedEngine] startPlayingStream:streamID canvas:[ZegoCanvas canvasWithView:self.playView]];
用户可以调用 stopScreenCapture 接口停止共享。
[ZegoExpressEngine.sharedEngine stopScreenCapture];
iOS 是否支持共享指定区域?
iOS 系统仅支持共享整个屏幕,不支持共享指定区域。
iOS 使用屏幕共享时进入后台,为什么会停止采集?
Microphone
时,SDK 会启动音频内部采集,维持后台保活;若设置为其他音频源类型,当应用退出后台后,屏幕共享将停止使用,建议用户自主对应用添加后台保活逻辑。iOS 使用屏幕共享时出现音频播放异常,如何处理?
若使用屏幕共享功能采集并推流音频,同时又在本机使用拉流功能,会导致 iOS 系统重复采集拉流音频,导致音频播放异常,建议使用 muteAllPlayStreamAudio 禁止拉取所有音频流。
联系我们
文档反馈