iOS

# 屏幕共享

通过 Juphoon RTC SDK 可以在视频通话过程中实现屏幕共享,坐席可以将自己的屏幕内容,以视频的方式分享给远端参会者(访客),从而提升沟通效率,一般适用于一对一或多人视频通话、在线会议等在线金融场景。

  • 视频会议场景中,参会者可以在会议中将本地的文件、数据、网页、PPT 等画面分享给其他与会者,让其他与会者更加直观的了解讨论的内容和主题。
  • 在线金融场景中,坐席可以通过屏幕共享或者窗口共享将风险揭示等画面展示给远端的访客观看,移动端访客也可将屏幕共享给坐席观看,提升沟通效率。

# 1. 设置屏幕共享采集属性

/**
 * 设置屏幕共享采集属性
 *
 * 在调用开启屏幕共享前设置即可生效
 *
 * @param width     采集宽度,默认1280
 * @param height    采集高度,默认720
 * @param frameRate 采集帧速率,默认10
 */
- (void)setScreenCaptureProperty:(int)width height:(int)height framerate:(int)frameRate;

/**
 * 开启/关闭屏幕采集
 *
 * @note
 * 支持应用外采集,需要 iOS 12.0 及以上(不包含 iOS 13.0),需要集成屏幕采集插件,
 * 调用此方法后成功,界面上会拉起屏幕采集插件,需手动点击"开始直播"按钮进行屏幕采集,
 * @param enable 是否开启
 * @param appGroupId  extension 和 app 所处于的同一个 groupId,如果是关闭可以传空
 * @param preferredExtension 希望打开的 extension 的 ID,如果是关闭可以传空
 * @return 返回 true 表示开启/关闭屏幕共享成功,false 表示失败
 */
- (bool)enableScreenCapture:(bool)enable appGroupId:(NSString *__nullable)appGroupId preferredExtension:(NSString *__nullable)preferredExtension;

/**
 * 获得屏幕采集视频流ID
 * @return 屏幕采集视频流ID
 */
- (NSString* __nullable)getScreenCaptureId;/**
 * 设置屏幕共享采集属性
 *
 * 在调用开启屏幕共享前设置即可生效
 *
 * @param width     采集宽度,默认1280
 * @param height    采集高度,默认720
 * @param frameRate 采集帧速率,默认10
 */
- (void)setScreenCaptureProperty:(int)width height:(int)height framerate:(int)frameRate;

/**
 * 开启/关闭屏幕采集
 *
 * @note
 * 支持应用外采集,需要 iOS 12.0 及以上(不包含 iOS 13.0),需要集成屏幕采集插件,
 * 调用此方法后成功,界面上会拉起屏幕采集插件,需手动点击"开始直播"按钮进行屏幕采集,
 * @param enable 是否开启
 * @param appGroupId  extension 和 app 所处于的同一个 groupId,如果是关闭可以传空
 * @param preferredExtension 希望打开的 extension 的 ID,如果是关闭可以传空
 * @return 返回 true 表示开启/关闭屏幕共享成功,false 表示失败
 */
- (bool)enableScreenCapture:(bool)enable appGroupId:(NSString *__nullable)appGroupId preferredExtension:(NSString *__nullable)preferredExtension;

/**
 * 获得屏幕采集视频流ID
 * @return 屏幕采集视频流ID
 */
- (NSString* __nullable)getScreenCaptureId;

示例代码:

// 设置屏幕共享采集属性
[_mediaDevice setScreenCaptureProperty:1280 height:720 framerate:24];
// 开启屏幕共享
[_mediaDevice enableScreenCapture:true appGroupId:@"appGroupId" preferredExtension:@"preferredExtension"];
// 关闭屏幕共享
[_mediaDevice enableScreenCapture:false appGroupId:nil preferredExtension:nil];// 设置屏幕共享采集属性
[_mediaDevice setScreenCaptureProperty:1280 height:720 framerate:24];
// 开启屏幕共享
[_mediaDevice enableScreenCapture:true appGroupId:@"appGroupId" preferredExtension:@"preferredExtension"];
// 关闭屏幕共享
[_mediaDevice enableScreenCapture:false appGroupId:nil preferredExtension:nil];

# 2. 开启/关闭屏幕共享

通过 Juphoon RTC SDK 可以在视频通话过程中实现屏幕共享,座席可以将自己的屏幕内容,以视频的方式分享给远端参会者(访客),从而提升沟通效率,一般适用于一对一或多人视频通话、在线会议等在线金融场景。

  • 视频会议场景中,参会者可以在会议中将本地的文件、数据、网页、PPT 等画面分享给其他与会者,让其他与会者更加直观的了解讨论的内容和主题。
  • 在线金融场景中,座席可以通过屏幕共享或者窗口共享将风险揭示等画面展示给远端的访客观看,移动端访客也可将屏幕共享给座席观看,提升沟通效率。

注:发起屏幕共享需要 iOS 12.0 及以上设备。

实现屏幕共享需添加 Broadcast Upload Extension 扩展,步骤如下: 1、项目中选择 target,添加 extension,用于屏幕录制。 img img 如上所示,在添加 extension 时选中 Broadcast Upload Extension 扩展进行添加。 2、app 和 extension 加入同一个 app group 后,实现 extension 和宿主 app 间的数据共享,加入步骤如下图所示: img

img 3、然后打开工程目录下对应的 SampleHandler.hSampleHandler.m 文件,导入库 #import <ReplayKit/ReplayKit.h>,继承系统的 RPBroadcastSampleHandler 类,重写broadcastStartedWithSetupInfo、processSampleBuffer、broadcastFinished 方法,并且调用调用插件提供的方法,如下图: img img img

/**
 * @brief broadcastStartedWithSetupInfo时调用,开启屏幕共享
 * @param appGroupId app和extension共同的groupId
 * @param sampleHandler 系统回掉的RPBroadcastSampleHandler对象,包含插件信息
*/
- (void)broadcastStartedWithAppGroupId:(NSString *)appGroupId initWithSampleHandler:(RPBroadcastSampleHandler *)sampleHandler API_AVAILABLE(ios(10.0));

/**
 * @brief processSampleBuffer时调用
 * @param sampleBuffer processSampleBuffer采集上来的sampleBuffer
 * @param sampleBufferType processSampleBuffer采集上来的sampleBufferType
*/

- (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType API_AVAILABLE(ios(10.0));

/**
 * @brief broadcastFinished时调用
*/
- (void)broadcastFinished;/**
 * @brief broadcastStartedWithSetupInfo时调用,开启屏幕共享
 * @param appGroupId app和extension共同的groupId
 * @param sampleHandler 系统回掉的RPBroadcastSampleHandler对象,包含插件信息
*/
- (void)broadcastStartedWithAppGroupId:(NSString *)appGroupId initWithSampleHandler:(RPBroadcastSampleHandler *)sampleHandler API_AVAILABLE(ios(10.0));

/**
 * @brief processSampleBuffer时调用
 * @param sampleBuffer processSampleBuffer采集上来的sampleBuffer
 * @param sampleBufferType processSampleBuffer采集上来的sampleBufferType
*/

- (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType API_AVAILABLE(ios(10.0));

/**
 * @brief broadcastFinished时调用
*/
- (void)broadcastFinished;

调用 enableScreenShare (opens new window) 接口拉起屏幕共享插件时,需要传递共享插件的 bundle identify 和 Group id。

/**
 * 开启/关闭屏幕共享
 *
 * 调用此方法后成功,界面上会拉起屏幕共享插件,需手动点击"开始直播"按钮进行屏幕共享,开启成功后,通话中的所有成员会收到 {@link JRTCGuestCallback.onCallPropertyChanged: onCallPropertyChanged} 或 {@link JRTCAgentCallback.onCallPropertyChanged: onCallPropertyChanged} 回调。
 * @param enable 开启或关闭屏幕共享
 * - true: 开启屏幕共享
 * - false: 关闭屏幕共享
 * @param appGroupId  屏幕共享插件和应用所处于的同一个groupId,如果是关闭屏幕共享可以传空,iOS12及以上需要传,iOS12以下传空
 * @param preferredExtension 要打开的屏幕共享插件的ID,如果是关闭屏幕共享可以传空,iOS12及以上需要传,iOS12以下传空
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 */
- (bool)enableScreenShare:(bool)enable appGroupId:(NSString *__nullable)appGroupId preferredExtension:(NSString *__nullable)preferredExtension;/**
 * 开启/关闭屏幕共享
 *
 * 调用此方法后成功,界面上会拉起屏幕共享插件,需手动点击"开始直播"按钮进行屏幕共享,开启成功后,通话中的所有成员会收到 {@link JRTCGuestCallback.onCallPropertyChanged: onCallPropertyChanged} 或 {@link JRTCAgentCallback.onCallPropertyChanged: onCallPropertyChanged} 回调。
 * @param enable 开启或关闭屏幕共享
 * - true: 开启屏幕共享
 * - false: 关闭屏幕共享
 * @param appGroupId  屏幕共享插件和应用所处于的同一个groupId,如果是关闭屏幕共享可以传空,iOS12及以上需要传,iOS12以下传空
 * @param preferredExtension 要打开的屏幕共享插件的ID,如果是关闭屏幕共享可以传空,iOS12及以上需要传,iOS12以下传空
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 */
- (bool)enableScreenShare:(bool)enable appGroupId:(NSString *__nullable)appGroupId preferredExtension:(NSString *__nullable)preferredExtension;

屏幕共享通过 JRTCAgentCallback (opens new window) 中的 onCallPropertyChanged (opens new window) 接口上报。

/**
 * 通话属性改变回调
 * @note
 * 重点关注屏幕共享,即当{@link JRTCRoomPropChangeParam.screenShare screenShare} 属性为 true 时,去处理屏幕共享相关事件。<br>
 * 可根据 {@link JRTCGuest.shareStreamId shareStreamId} 和 {@link JRTCGuest.shareUserId shareUserId} 属性进行屏幕共享画面的渲染和停止渲染。
 * @param changeParam 通话改变的属性
 */
- (void)onCallPropertyChanged:(JRTCRoomPropChangeParam *)changeParam;/**
 * 通话属性改变回调
 * @note
 * 重点关注屏幕共享,即当{@link JRTCRoomPropChangeParam.screenShare screenShare} 属性为 true 时,去处理屏幕共享相关事件。<br>
 * 可根据 {@link JRTCGuest.shareStreamId shareStreamId} 和 {@link JRTCGuest.shareUserId shareUserId} 属性进行屏幕共享画面的渲染和停止渲染。
 * @param changeParam 通话改变的属性
 */
- (void)onCallPropertyChanged:(JRTCRoomPropChangeParam *)changeParam;

可通过 JRTCAgent.shareUserId (opens new window) 获得当前正在屏幕共享的成员用户 ID;可通过 JRTCAgent.shareStreamId (opens new window) 获得当前正在屏幕共享的 streamId 。

/**
 * 屏幕共享的视频流ID,无屏幕共享时为 nil
 *
 * 调用 {@link JRTCMediaDevice.startVideo:renderType: startVideo} 接口渲染通话中其他成员的屏幕共享画面时使用。
 */
@property (nonatomic, readonly, copy) NSString *shareStreamId;

/**
 * 发起屏幕共享者的用户ID,无屏幕共享时为 nil
 *
 * 可用来判断当前通话中是否有成员发起屏幕共享。
 */
@property (nonatomic, readonly, copy) NSString *shareUserId;/**
 * 屏幕共享的视频流ID,无屏幕共享时为 nil
 *
 * 调用 {@link JRTCMediaDevice.startVideo:renderType: startVideo} 接口渲染通话中其他成员的屏幕共享画面时使用。
 */
@property (nonatomic, readonly, copy) NSString *shareStreamId;

/**
 * 发起屏幕共享者的用户ID,无屏幕共享时为 nil
 *
 * 可用来判断当前通话中是否有成员发起屏幕共享。
 */
@property (nonatomic, readonly, copy) NSString *shareUserId;

示例代码:

// 开启屏幕共享
[_agent enableScreenShare:true appGroupId:@"groupId" preferredExtension:@"extensionId"];

// 关闭屏幕共享
[_agent enableScreenShare:false appGroupId:nil preferredExtension:nil];

// 监听到屏幕共享状态改变
- (void)onCallPropertyChange:(JCMediaChannelPropChangeParam *)changeParam {
	if (changeParam.screenShare == true) {
        if (_agent.shareUserId.length > 0) {
            // 通话中有成员屏幕共享打开,通过 _agent.shareStreamId 渲染共享画面
        } 
        else {
            // 通话中有成员屏幕共享关闭
        }
    }
}// 开启屏幕共享
[_agent enableScreenShare:true appGroupId:@"groupId" preferredExtension:@"extensionId"];

// 关闭屏幕共享
[_agent enableScreenShare:false appGroupId:nil preferredExtension:nil];

// 监听到屏幕共享状态改变
- (void)onCallPropertyChange:(JCMediaChannelPropChangeParam *)changeParam {
	if (changeParam.screenShare == true) {
        if (_agent.shareUserId.length > 0) {
            // 通话中有成员屏幕共享打开,通过 _agent.shareStreamId 渲染共享画面
        } 
        else {
            // 通话中有成员屏幕共享关闭
        }
    }
}

# 3. 暂停/恢复屏幕共享

/**
 * 暂停/继续屏幕共享
 * @note
 * 只有自己发起的屏幕共享可以使用该接口暂停,多次调用会覆盖
 * @param suspend true 暂停屏幕共享, false 继续屏幕共享
 * @param tip 暂停屏幕共享后提示文字
 * @return 接口调用结果
 * - true: 接口调用成功, 会收到 {@link JRTCAgentCallback#onRoomPropertyChanged onRoomPropertyChanged} 回调,可通过{@link #isSuspendScreenShare isSuspendScreenShare} 判断当前屏幕共享是否暂停
 * - false: 接口调用异常
 */
- (bool)suspendScreenShare:(bool)suspend tip:(NSString *_Nonnull)tip;/**
 * 暂停/继续屏幕共享
 * @note
 * 只有自己发起的屏幕共享可以使用该接口暂停,多次调用会覆盖
 * @param suspend true 暂停屏幕共享, false 继续屏幕共享
 * @param tip 暂停屏幕共享后提示文字
 * @return 接口调用结果
 * - true: 接口调用成功, 会收到 {@link JRTCAgentCallback#onRoomPropertyChanged onRoomPropertyChanged} 回调,可通过{@link #isSuspendScreenShare isSuspendScreenShare} 判断当前屏幕共享是否暂停
 * - false: 接口调用异常
 */
- (bool)suspendScreenShare:(bool)suspend tip:(NSString *_Nonnull)tip;

查询屏幕共享是否暂停

/**
 * 是否屏幕共享暂停
 * @return
 * - true: 暂停屏幕共享
 * - false: 未暂停屏幕共享
 */
- (bool)isSuspendScreenShare;/**
 * 是否屏幕共享暂停
 * @return
 * - true: 暂停屏幕共享
 * - false: 未暂停屏幕共享
 */
- (bool)isSuspendScreenShare;

暂停/恢复屏幕共享变化事件通过实现 JRTCAgentCallback (opens new window) 中的 onCallPropertyChanged (opens new window) 接口上报。

示例代码:

// 发起屏幕共享
[agent suspendScreenShare:true tip:@"屏幕共享暂停中"];
// 通话属性变化回调
- (void)onCallPropertyChanged:(JRTCRoomPropChangeParam *) propChangeParam {
    if (propChangeParam.screenShare) {
        if ([agent isSuspendScreenShare]) {
            //屏幕共享暂停中
        }
    }
}// 发起屏幕共享
[agent suspendScreenShare:true tip:@"屏幕共享暂停中"];
// 通话属性变化回调
- (void)onCallPropertyChanged:(JRTCRoomPropChangeParam *) propChangeParam {
    if (propChangeParam.screenShare) {
        if ([agent isSuspendScreenShare]) {
            //屏幕共享暂停中
        }
    }
}

# 4. 订阅/取消订阅屏幕共享的视频流

如果通话中有成员开启了屏幕共享,其他成员将收到 onCallPropertyChanged (opens new window) 的回调,并通过 shareUserId (opens new window) 获得发起屏幕共享的成员用户 ID 。

/**
 * 通话属性改变回调
 * @note
 * 重点关注屏幕共享,即当{@link JRTCRoomPropChangeParam.screenShare screenShare} 属性为 true 时,去处理屏幕共享相关事件。<br>
 * 可根据 {@link JRTCAgent.shareStreamId shareStreamId} 和 {@link JRTCAgent.shareUserId shareUserId} 属性进行屏幕共享画面的渲染和停止渲染。
 * @param changeParam 通话改变的属性
 */
- (void)onCallPropertyChanged:(JRTCRoomPropChangeParam *)changeParam;/**
 * 通话属性改变回调
 * @note
 * 重点关注屏幕共享,即当{@link JRTCRoomPropChangeParam.screenShare screenShare} 属性为 true 时,去处理屏幕共享相关事件。<br>
 * 可根据 {@link JRTCAgent.shareStreamId shareStreamId} 和 {@link JRTCAgent.shareUserId shareUserId} 属性进行屏幕共享画面的渲染和停止渲染。
 * @param changeParam 通话改变的属性
 */
- (void)onCallPropertyChanged:(JRTCRoomPropChangeParam *)changeParam;

此时可以调用 requestScreenVideo (opens new window) 方法请求订阅屏幕共享的视频流。

/**
 * 订阅通话中屏幕共享的视频流
 *
 * @param videoSize 视频请求的尺寸,详见 @ref JRTCVideoSize
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 */
- (bool)requestScreenVideo:(JRTCVideoSize* __nonnull)videoSize;/**
 * 订阅通话中屏幕共享的视频流
 *
 * @param videoSize 视频请求的尺寸,详见 @ref JRTCVideoSize
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 */
- (bool)requestScreenVideo:(JRTCVideoSize* __nonnull)videoSize;

取消订阅屏幕共享的视频流,如果不需要屏幕共享视频流,此时可以调用 unRequestScreenVideo (opens new window) 方法取消订阅屏幕共享的视频流,建议不使用时取消订阅屏幕共享的视频流,否则可能造成资源浪费。

/**
 * 取消订阅通话中屏幕共享的视频流
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 */
- (bool)unRequestScreenVideo;/**
 * 取消订阅通话中屏幕共享的视频流
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 */
- (bool)unRequestScreenVideo;

# 5. 渲染共享画面

获取屏幕共享相关参数 shareUserId (opens new window)shareStreamId (opens new window)

/**
 * 屏幕共享的视频流ID,无屏幕共享时为 nil
 *
 * 调用 {@link JRTCMediaDevice.startVideo:renderType: startVideo} 接口渲染通话中其他成员的屏幕共享画面时使用。
 */
@property (nonatomic, readonly, copy) NSString *shareStreamId;

/**
 * 发起屏幕共享者的用户ID,无屏幕共享时为 nil
 *
 * 可用来判断当前通话中是否有成员发起屏幕共享。
 */
@property (nonatomic, readonly, copy) NSString *shareUserId;/**
 * 屏幕共享的视频流ID,无屏幕共享时为 nil
 *
 * 调用 {@link JRTCMediaDevice.startVideo:renderType: startVideo} 接口渲染通话中其他成员的屏幕共享画面时使用。
 */
@property (nonatomic, readonly, copy) NSString *shareStreamId;

/**
 * 发起屏幕共享者的用户ID,无屏幕共享时为 nil
 *
 * 可用来判断当前通话中是否有成员发起屏幕共享。
 */
@property (nonatomic, readonly, copy) NSString *shareUserId;

屏幕共享开始/结束均通过实现 onCallPropertyChanged (opens new window) 接口上报。

示例代码:

- (void)onCallPropertyChanged:(JRTCRoomPropChangeParam *)changeParam {
    if (changeParam.screenShare) {
        if (_agent.shareUserId && _agent.shareStreamId) {
            // 处理屏幕共享
        } else {
            // 屏幕共享关闭,可停止渲染共享视频画面
        }
    }
}- (void)onCallPropertyChanged:(JRTCRoomPropChangeParam *)changeParam {
    if (changeParam.screenShare) {
        if (_agent.shareUserId && _agent.shareStreamId) {
            // 处理屏幕共享
        } else {
            // 屏幕共享关闭,可停止渲染共享视频画面
        }
    }
}