在视频通话或互动直播中进行屏幕共享,可以将说话人或主播的屏幕内容,以视频的方式分享给其他说话人或观众观看,以提高沟通效率。
屏幕共享在如下场景中应用广泛:
本文介绍如何使用 4.x Unity SDK 在 Android, iOS,macOS 和 Windows 平台实现屏幕共享。
在实现屏幕共享前,请确保已在你的项目中实现基本的实时音视频功能。详见开始音视频通话或开始互动直播。
视频共享编码属性 ScreenCaptureParameters
类中各参数的设置可能会影响计费。如果你将 dimensions
参数设为默认值,会按照 1920 × 1080 进行计费。
声网在 GitHub 上提供屏幕共享的示例项目供你参考。
本节介绍如何在 Android 平台上实现屏幕共享。
在 Android 平台实现屏幕共享时,只需要调用 StartScreenCapture
即可开启屏幕共享:
方案 1:在加入频道前调用 StartScreenCapture
,然后调用 JoinChannel
[2/2] 加入频道并设置 publishScreenCaptureVideo
为 true
,即可开始屏幕共享。
方案 2:在加入频道后调用 StartScreenCapture
,然后调用 UpdateChannelMediaOptions
设置 publishScreenCaptureVideo
为 true
,即可开始屏幕共享。
// 方案1:
加入频道前调用 StartScreenCapture 开启屏幕共享。
ScreenCaptureParameters2 screenCaptureParameters2 = new ScreenCaptureParameters2();
screenCaptureParameters2.captureVideo = true;
screenCaptureParameters2.captureAudio = true;
RtcEngine.StartScreenCapture(screenCaptureParameters2);
// 调用 JoinChannel 加入频道。
ChannelMediaOptions channelMediaOptions = new ChannelMediaOptions();
channelMediaOptions.publishScreenCaptureVideo.SetValue(true);
channelMediaOptions.publishScreenCaptureAudio.SetValue(true);
channelMediaOptions.publishCameraTrack.SetValue(false);
channelMediaOptions.publishMicrophoneTrack.SetValue(false);
RtcEngine.JoinChannel("token", "channelId", uid, channelMediaOptions);
// 方案2:
调用 JoinChannel 加入频道。
RtcEngine.JoinChannel(_token, _channelName);
ScreenCaptureParameters2 screenCaptureParameters2 = new ScreenCaptureParameters2();
screenCaptureParameters2.captureVideo = true;
screenCaptureParameters2.captureAudio = true;
// 开启屏幕共享。
RtcEngine.StartScreenCapture(screenCaptureParameters2);
ChannelMediaOptions channelMediaOptions = new ChannelMediaOptions();
channelMediaOptions.publishScreenCaptureVideo.SetValue(true);
channelMediaOptions.publishScreenCaptureAudio.SetValue(true);
channelMediaOptions.publishCameraTrack.SetValue(false);
channelMediaOptions.publishMicrophoneTrack.SetValue(false);
// 更新频道媒体选项。
RtcEngine.UpdateChannelMediaOptions(channelMediaOptions);
iOS 端的屏幕共享是通过在 Extension 中使用 iOS 原生的 ReplayKit 框架实现录制屏幕,然后将屏幕共享流作为一个用户加入频道实现的。由于 Apple 不支持在主 app 进程采集屏幕,因此你需要为屏幕共享流单独创建一个 Extension。
在 Unity Editor 中打包 iOS 项目,导出 Xcode 工程。
前往你的项目文件夹,用 Xcode 打开 unity-iphone/.xcodeproj
文件夹。
创建一个 Broadcast Upload Extension 用于开启屏幕共享的进程:
a. 在 Xcode 中,点击 File > New > Target..., 在弹出的窗口中选择 Broadcast Upload Extension, 点击 Next。
b. 在弹出的窗口中填写 Product Name 等信息,取消勾选 Include UI Extension,点击 Finish。Xcode 会自动创建该 Extension 的文件夹,其中包含 SampleHandler.h
文件。
c. 在 Target 下选中刚创建的 Extension,点击 General,在 Deployment Info 下将 iOS 的版本设置为 12.0 或之后。
如果你只需使用声网提供的 AgoraReplayKitExtension.framework
中的功能,将 Target
选择为刚刚创建的 Extension,在 Info 中选择 NSExtension > NSExtensionPrincipalClass, 将所对应的 Value 从 $(PRODUCT_MODULE_NAME}.SampleHandler 改为 AgoraReplayKitHandler。
如果你还需要自定义一些业务逻辑,修改方式为:将如下代码替换到 SampleHandler.h
文件中:
#import "SampleHandler.h"
#import "AgoraReplayKitExt.h"
#import <sys/time.h>
@interface SampleHandler ()<AgoraReplayKitExtDelegate>
@end
@implementation SampleHandler
- (void)broadcastStartedWithSetupInfo:(NSDictionary<NSString *,NSObject *> *)setupInfo {
[[AgoraReplayKitExt shareInstance] start:self];
}
- (void)broadcastPaused {
NSLog(@"broadcastPaused");
[[AgoraReplayKitExt shareInstance] pause];
}
- (void)broadcastResumed {
NSLog(@"broadcastResumed");
[[AgoraReplayKitExt shareInstance] resume];
}
- (void)broadcastFinished {
NSLog(@"broadcastFinished");
[[AgoraReplayKitExt shareInstance] stop];
}
- (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType {
[[AgoraReplayKitExt shareInstance] pushSampleBuffer:sampleBuffer withType:sampleBufferType];
}
#pragma mark - AgoraReplayKitExtDelegate
- (void)broadcastFinished:(AgoraReplayKitExt *_Nonnull)broadcast reason:(AgoraReplayKitExtReason)reason {
switch (reason) {
case AgoraReplayKitExtReasonInitiativeStop:
{
}
break;
case AgoraReplayKitExtReasonConnectFail:
{
}
break;
case AgoraReplayKitExtReasonDisconnect:
{
}
break;
default:
break;
}
}
@end
在 TARGETS 中选中你创建的 Extension, 在 General/Frameworks and Libraries 中添加 Frameworks/Agora-RTC-Plugin/Agora-Unity-RTC-SDK/Plugins/iOS/ 路径下所有 Framework。
调用 StartScreenCapture
,并结合用户的手动操作,使 app 开启屏幕共享。例如:提示用户在 iOS 系统的控制中心长按屏幕录制按钮,并选择用你创建的 Extension 开启录制。
屏幕共享功能目前存在一些使用限制和注意事项,同时会产生费用,声网推荐你在调用 API 前先阅读如下 API 参考:
Windows 或 macOS 系统为每个屏幕分配一个唯一的 Display ID,为每个窗口分配一个唯一的 Window ID,因此声网提供以下两种屏幕共享方案:
GetScreenCaptureSources
获取 Display ID,然后调用 StartScreenCaptureByDisplayId
开始屏幕共享。GetScreenCaptureSources
获取 Window ID,然后调用 StartScreenCaptureByWindowId
开始屏幕共享。本节介绍如何在 macOS 和 Windows 平台实现屏幕共享。
获取可共享的屏幕和窗口列表。
调用 GetScreenCaptureSources
方法,获取需要共享屏幕的 Display ID 或窗口的 Window ID。
SIZE thumbSize = new SIZE(360,240);
SIZE iconSize = new SIZE(360,240);
ScreenCaptureSourceInfo[] screenCaptureSourceInfos = RtcEngine.GetScreenCaptureSources(thumbSize, iconSize, true);
共享指定屏幕或窗口。
根据共享对象的不同,调用 StartScreenCaptureByDisplayId
或 StartScreenCaptureByWindowId
方法开始屏幕共享。
ScreenCaptureSourceInfo info = screenCaptureSourceInfos[0];
if (info.type == ScreenCaptureSourceType.ScreenCaptureSourceType_Screen)
{
ulong displayId = info.sourceId;
RtcEngine.StartScreenCaptureByDisplayId((uint)displayId, default(Rectangle),default(ScreenCaptureParameters));
}
else if (info.type == ScreenCaptureSourceType.ScreenCaptureSourceType_Window)
{
ulong windowId = info.sourceId;
RtcEngine.StartScreenCaptureByWindowId(windowId, default(Rectangle),default(ScreenCaptureParameters));
}
加入频道并发布屏幕共享流。
如果仅需发布屏幕共享流,在你的项目中添加如下代码:
ChannelMediaOptions options = new ChannelMediaOptions();
options.publishCameraTrack.SetValue(false);
options.publishScreenTrack.SetValue(true);
#if UNITY_ANDROID || UNITY_IPHONE
options.publishScreenCaptureAudio.SetValue(true);
options.publishScreenCaptureVideo.SetValue(true);
#endif
RtcEngine.UpdateChannelMediaOptions(options);
如需发布屏幕共享流和本地摄像头采集的视频流,在你的项目中添加如下代码:
// 加入一路频道并且推送摄像头流
RtcEngine.EnableAudio();
RtcEngine.EnableVideo();
RtcEngine.SetClientRole(CLIENT_ROLE_TYPE.CLIENT_ROLE_BROADCASTER);
ChannelMediaOptions options = new ChannelMediaOptions();
options.autoSubscribeAudio.SetValue(true);
options.autoSubscribeVideo.SetValue(true);
options.publishCameraTrack.SetValue(true);
options.publishScreenTrack.SetValue(false);
options.enableAudioRecordingOrPlayout.SetValue(true);
options.clientRoleType.SetValue(CLIENT_ROLE_TYPE.CLIENT_ROLE_BROADCASTER);
RtcEngine.JoinChannel(_token, _channelName, this.Uid1, options);
// 加入一路频道并且推送屏幕共享流
ChannelMediaOptions options = new ChannelMediaOptions();
options.autoSubscribeAudio.SetValue(false);
options.autoSubscribeVideo.SetValue(false);
options.publishCameraTrack.SetValue(false);
options.publishScreenTrack.SetValue(true);
options.enableAudioRecordingOrPlayout.SetValue(false);
#if UNITY_ANDROID || UNITY_IPHONE
options.publishScreenCaptureAudio.SetValue(true);
options.publishScreenCaptureVideo.SetValue(true);
#endif
options.clientRoleType.SetValue(CLIENT_ROLE_TYPE.CLIENT_ROLE_BROADCASTER);
var ret = RtcEngine.JoinChannelEx(_token, new RtcConnection(_channelName, this.Uid2), options);