屏幕共享
在互动直播或视频通话中,主播或视频通话用户可以通过声网 SDK 中的屏幕共享特性,将自己的屏幕内容以视频的方式分享给其他用户或观众观看。
屏幕共享可以应用在以下场景中:
场景 | 描述 |
---|---|
在线教育 | 老师将自己的屏幕、教学课件、绘图软件或编程软件共享给学生,用于课堂示范 |
游戏直播 | 主播共享自己的游戏画面给观众 |
互动直播 | 主播共享自己的屏幕和观众互动 |
视频会议 | 会议成员共享屏幕观看 PPT 或者文档 |
远程控制 | 被控端向主控端展示自己的桌面 |
技术原理
由于 Apple 不支持在 App 主进程采集屏幕,因此你需要为屏幕共享流单独创建一个 Extension,并在 Extension 中使用 iOS 原生的 ReplayKit 框架实现录制屏幕,然后将屏幕共享流发送给主进程、实现屏幕共享。
根据实际业务场景的不同,你可以选择以下任一方式调用 API 实现屏幕共享:
- 在加入频道前调用
startScreenCapture
,然后调用joinChannelByToken
[2/4] 加入频道并设置publishScreenCaptureVideo
为true
,即可开始屏幕共享。 - 在加入频道后调用
startScreenCapture
,然后调用updateChannelWithMediaOptions
更新频道媒体选项并设置publishScreenCaptureVideo
为true
,即可开始屏幕共享。
注意事项
- 在开启屏幕共享后,声网以屏幕共享视频流的分辨率作为计费标准。默认分辨率为 1280 × 720,你也可以根据你的业务需求进行调整。详见如何确定屏幕共享视频流的分辨率?
- 受系统限制,屏幕共享只支持 iOS 12.0 及以上版本。
- 该功能对设备性能要求较高,声网推荐你使用 iPhone X 及以上设备。
- 用户在 iOS 设备上开启屏幕共享后,因系统限制,音频路由会自动切换为听筒。
- 如果当前使用通话音量,则你可以手动切换音频路由,例如,你可以根据实际需求将音频路由切换成扬声器。
- 如果当前使用媒体音量,由于系统限制,你在这种场景下无法手动切换音频路由。如果你不了解使用的是通话还是媒体音量,请参考如何区分媒体音量和通话音量。
前提条件
在实现屏幕共享前,请确保已在你的项目中实现基本的实时音视频功能。详见实现音视频互动。
项目设置
按照以下步骤修改你的项目文件。
-
前往你的项目文件夹,用 Xcode 打开
.xcodeproj
文件。 -
点击 File > New > Target..., 在弹出的窗口中选择 Broadcast Upload Extension, 点击 Next。
-
在弹出的窗口中填写 Product Name 等信息,取消勾选 Include UI Extension,点击 Finish。Xcode 会自动创建该 Extension 的文件夹,其中包含
SampleHandler.swift
文件。 -
在 Target 下选中刚创建的 Extension,点击 General,在 Deployment Info 下将 iOS 的版本设置为 12.0 或之后。
-
修改项目设置以实现屏幕共享的代码逻辑,根据实际业务需求选择以下三种方式其中之一即可:
-
如果你只需使用声网提供的
AgoraReplayKitExtension.xcframework
动态库中的功能,则:选中 Target 为刚刚创建的 Extension,在 Info 中将 NSExtension > NSExtensionPrincipalClass 所对应的 Value 从 SampleHandler 改为 AgoraReplayKitHandler。 -
如果你需要另外实现一些业务逻辑,可以继承
AgoraReplayKitHandler
类。参考如下代码修改SampleHandler.swift
文件:Swiftimport ReplayKit
import AgoraReplayKitExtension
class SampleHandler: AgoraReplayKitHandler {
override func broadcastStarted(withSetupInfo setupInfo: [String : NSObject]?) {
// 用户请求开始广播
super.broadcastStarted(withSetupInfo: setupInfo)
}
} -
如果你希望使用 iOS 原生的
SampleHandler
、不继承AgoraReplayKitHandler
类,参考如下代码修改SampleHandler.swift
文件:Swiftimport ReplayKit
import AgoraReplayKitExtension
class SampleHandler: RPBroadcastSampleHandler, AgoraReplayKitExtDelegate {
override func broadcastStarted(withSetupInfo setupInfo: [String : NSObject]?) {
// 用户请求开始广播
AgoraReplayKitExt.shareInstance().start(self)
}
override func broadcastPaused() {
// 用户请求暂停广播,屏幕共享暂停
AgoraReplayKitExt.shareInstance().pause()
}
override func broadcastResumed() {
// 用户请求恢复广播,屏幕共享恢复
AgoraReplayKitExt.shareInstance().resume()
}
override func broadcastFinished() {
// 用户请求停止广播
AgoraReplayKitExt.shareInstance().stop()
}
override func processSampleBuffer(_ sampleBuffer: CMSampleBuffer, with sampleBufferType: RPSampleBufferType) {
AgoraReplayKitExt.shareInstance().push(sampleBuffer, with: sampleBufferType)
}
func broadcastFinished(_ broadcast: AgoraReplayKitExt, reason: AgoraReplayKitExtReason) {
var tip = ""
switch reason {
case AgoraReplayKitExtReasonInitiativeStop:
tip = "AgoraReplayKitExtReasonInitiativeStop"
case AgoraReplayKitExtReasonConnectFail:
tip = "AgoraReplayKitExReasonConnectFail"
case AgoraReplayKitExtReasonDisconnect:
tip = "AgoraReplayKitExReasonDisconnect"
default: break
}
let error = NSError(domain: NSCocoaErrorDomain,
code: 0,
userInfo: [NSLocalizedFailureReasonErrorKey: tip])
self .finishBroadcastWithError(error as Error)
}
}
-
自动集成动态库
通过 Cocoapods 集成 SDK 时,你需要在 Podfile
文件中添加如下内容,指定集成屏幕共享动态库 AgoraReplayKitExtension.xcframework
,示例代码如下:
platform :ios, '9.0'
target 'Your App' do
# 只集成基础库和屏幕共享动态库
# 请使用具体的 SDK 版本号替换下面代码中的 x.y.z,可通过发版说明获取最新版本号
pod 'AgoraRtcEngine_iOS', 'x.y.z', :subspecs => ['RtcBasic', 'ReplayKit']
end
屏幕共享动态库封装了如下功能:
- 使用 Apple ReplayKit 进行屏幕录制。
- 使用 SDK 采集功能获取系统录屏数据,并发送给频道中其他用户。
实现屏幕共享
本节介绍如何在你的项目中实现屏幕共享,API 调用时序如下图所示。
设置音频场景
调用 setAudioScenario
方法,并设置音频场景为 AgoraAudioScenarioGameStreaming
(高音质场景),以提高屏幕共享时采集系统音频的成功率。
开启屏幕采集
-
调用
startScreenCapture
开启屏幕采集,并根据你的应用场景进行参数设置:captureVideo
:是否在屏幕共享时采集系统视频。captureAudio
:是否在屏幕共享时采集系统音频。captureSignalVolume
:采集的系统音量。dimensions
:视频编码的分辨率。frameRate
:视频编码帧率 (fps)。bitrate
:视频编码码率 (Kbps)。contentHint
:屏幕共享视频的内容类型。
Swift// 设置屏幕采集的参数
private lazy var screenParams: AgoraScreenCaptureParameters2 = {
let params = AgoraScreenCaptureParameters2()
params.captureVideo = true
params.captureAudio = true
let audioParams = AgoraScreenAudioParameters()
// 设置采集的系统音量
audioParams.captureSignalVolume = 50
params.audioParams = audioParams
let videoParams = AgoraScreenVideoParameters()
// 设置共享屏幕的分辨率
videoParams.dimensions = screenShareVideoDimension()
// 设置视频编码帧率
videoParams.frameRate = .fps15
// 设置视频编码码率
videoParams.bitrate = AgoraVideoBitrateStandard
params.videoParams = videoParams
return params
}()
// 开启屏幕采集
agoraKit.startScreenCapture(screenParams) -
结合用户的手动操作,使 App 开启屏幕共享。有两种方式供你参考:
- 方式一:提示用户在 iOS 系统的控制中心长按屏幕录制按钮,并选择用你创建的 Extension 开启录制。
- 方式二:使用 Apple 在 iOS 12.0 中新增的 RPSystemBroadcastPickerView,使 App 界面弹出 “开启屏幕共享” 的按钮,提示用户通过点击该按钮开启录制,示例代码如下:
信息RPSystemBroadcastPickerView
存在一些使用限制并可能在后续版本的 iOS 系统中失效。因此,请酌情使用方式二。Swiftlet frame = CGRect(x: 0, y:0, width: 60, height: 60)
// 创建 RPSystemBroadcastPickerView 对象
systemBroadcastPicker = RPSystemBroadcastPickerView(frame: frame)
systemBroadcastPicker?.showsMicrophoneButton = false
systemBroadcastPicker?.autoresizingMask = [.flexibleTopMargin, .flexibleRightMargin]
// 获取主应用程序的 Bundle Identifier
let bundleId = Bundle.main.bundleIdentifier ?? ""
// 设置 Extension 名称
systemBroadcastPicker?.preferredExtension = "\(bundleId).Agora-ScreenShare-Extension"
在频道中发布屏幕共享视频流
加入频道后,调用 updateChannelWithMediaOptions
,发布采集的屏幕共享视频流。示例代码如下:
// 在进行屏幕视频采集(state 为 capturing,souceType 为 screen)时,定义 rtcEngine 的行为
func rtcEngine(_ engine: AgoraRtcEngineKit, localVideoStateChangedOf state: AgoraVideoLocalState, error: AgoraLocalVideoStreamError, sourceType: AgoraVideoSourceType) {
switch (state, sourceType) {
case (.capturing, .screen):
// 在频道中发布屏幕采集的视频
option.publishScreenCaptureVideo = true
// 在频道中发布屏幕采集的音频
option.publishScreenCaptureAudio = true
// 不发布摄像头采集的视频
option.publishCameraTrack = false
// 使用以上 option 中的设置更新频道设置
agoraKit.updateChannel(with: option)
default: break
}
}
(可选)设置屏幕共享场景
调用 setScreenCaptureScenario
方法设置屏幕共享场景,按照实际使用场景,将 scenarioType
设置为以下任意一种:
AgoraScreenScenarioDocument
(1):文档场景AgoraScreenScenarioGaming
(2):游戏场景AgoraScreenScenarioVideo
(3):视频场景AgoraScreenScenarioRDC
(4):远程控制场景
示例代码如下:
agoraKit.setScreenCaptureScenario(.video)
(可选)更新屏幕共享
如果你要更新屏幕共享的参数,调用 updateScreenCapture
,修改屏幕共享的参数。例如:视频编码分辨率、帧率、码率。
agoraKit.updateScreenCapture(screenParams)
停止屏幕共享
调用 stopScreenCapture
,在频道内停止屏幕共享。示例代码如下:
// 停止屏幕共享
agoraKit.stopScreenCapture()
// 停止在频道中发布屏幕采集的视频
option.publishScreenCaptureVideo = false
// 停止在频道中发布屏幕采集的音频
option.publishScreenCaptureAudio = false
// 在频道中发布摄像头采集的视频
option.publishCameraTrack = true
agoraKit.updateChannel(with: option)
参考信息
介绍更多相关信息和参考页面的链接。
功能介绍
声网 SDK 的屏幕共享特性可提供以下功能,适用于各种场景下的屏幕共享。
共享整个屏幕
将你的整个屏幕进行共享,包括屏幕中的所有信息,该功能支持同时采集两块屏幕的信息并共享。
共享 App 窗口
如果你不希望将整个屏幕内容分享给其他用户,可以只共享一个 App 窗口中的画面。
共享指定区域
如果你只希望共享屏幕或 App 窗口中的一部分,可以在开启屏幕共享时设置一个共享区域,只有该区域内的画面会被分享。
高级功能
除上述功能外,你还可以在开启屏幕共享时通过调整参数,实现以下高级共享功能:
- 屏蔽指定 App 窗口:在共享屏幕时,如果你不希望暴露某个 App 窗口,可以选择将该 App 窗口屏蔽,则该窗口将不会出现在共享的屏幕中。
- 描边:如果你需要勾勒出正在共享的范围,可以对指定的 App 窗口或屏幕进行描边,并自定义描边的宽度、颜色和透明度。
- 前置指定 App 窗口:如果你同时共享了多个 App 窗口,可能会出现窗口之间互相遮挡的情况,你可以指定一个 App 窗口并将其前置,即可避免它被其他窗口遮挡。
- 设置共享场景:SDK 会根据你设置的场景自动调节 QOE (Quality of Experience) 策略。
- 在共享文档、幻灯片、表格,或者远程控制时,你可以将共享场景设置为文档场景或远程控制场景,SDK 会优先保障画质,并降低接收端看共享视频的延时。
- 在共享游戏或电影、视频直播时,你可以将共享场景设置为游戏场景或视频场景,SDK 会优先保障流畅性。
屏幕共享功能在各平台的适用情况如下:
- 桌面端(Windows 和 macOS):支持上述所有屏幕共享功能。
- 移动端(Android 和 iOS):仅支持共享整个屏幕。
优势介绍
声网提供的屏幕共享特性具备以下优势:
超高清画质体验
支持超高清视频(分辨率为 4K,帧率为 60 fps),给用户带来更加流畅、高清的极致画面体验。
多 App 支持
适配 WPS Office、Microsoft Office Power Point、Visual Studio Code、Adobe Photoshop、Windows Media Player 和 Scratch 等多款主流 App,方便用户在屏幕共享时直接共享指定 App、提升了功能易用性。
多设备支持
支持多设备同时共享,兼容 Windows 8 系统、无独立显卡的设备、双显卡设备、外接屏幕设备等,满足各种场景下的设备使用需求。
多平台适配
支持 iOS、Andriod、macOS、Windows、Web、Unity、Flutter、React Native、Unreal Engine 等平台。
高安全保障
支持仅共享 App 和屏幕中的部分区域内容,并支持屏蔽指定 App 窗口,有效保障用户信息安全。
示例项目
声网在 GitHub 提供了开源的示例项目供你参考。
- Agora-ScreenShare-Extension:实现 Extension 进程
- ScreenShare:在
AgoraRtcEngineKit
中实现屏幕共享