# 实现屏幕共享

屏幕共享可以让您和频道中的其他成员一起分享设备里的精彩内容,您可以在频道中利用屏幕共享的功能进行文档演示、在线教育演示、视频会议以及游戏过程分享等。

通过 ReplayKit 2 的系统库,实现屏幕共享,该库仅支持iOS 11.0 以上的系统进行共享系统的屏幕,iOS11及以下的系统只能共享应用内屏幕。

# 添加 Broadcast Upload Extension 扩展

步骤一:项目中选择 target,添加 extension,用于屏幕录制。

createExtension1.jpg

createExtension2.jpg

如上所示,在添加 extension 时选中 Broadcast Upload Extension 扩展进行添加。

步骤二:app 和 extension 加入同一个 app group 后,实现 extension 和宿主 app 间的数据共享,加入步骤如下图所示。

AddToSameAppGroup1.jpgAddToSameAppGroup2.jpgAddToSameAppGroup3.jpg

JCBroadcastSampleHandler (opens new window) 里实现了数据采集,并通过 socket 传输到宿主 app。

@interface JCBroadcastSampleHandler : NSObject

 /**
  * @brief broadcastStartedWithSetupInfo时调用,开启屏幕共享
  * @param appGroupId app和extension共同的groupId
  */
 + (void)broadcastStartedWithAppGroupId:(NSString *)appGroupId initWithSampleHandler:(RPBroadcastSampleHandler *)sampleHandler;

 /**
  * @brief processSampleBuffer时调用
  * @param sampleBuffer processSampleBuffer采集上来的sampleBuffer
  * @param sampleBufferType processSampleBuffer采集上来的sampleBufferType
  */
 + (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType;

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

 /**
  * @brief broadcastResumed时调用
  */
 + (void)broadcastResumed;

 /**
  * @brief broadcastPaused时调用
  */
 + (void)broadcastPaused;

 @end

示例代码:

#import "SampleHandler.h"
#import <JMSDK/JMSDK.h>

@implementation SampleHandler

    - (void)broadcastStartedWithSetupInfo:(NSDictionary<NSString *,NSObject *> *)setupInfo {
        [JCBroadcastSampleHandler broadcastStartedWithAppGroupId:@"group.com.juphoon.uploadExTest" initWithSampleHandler:self];
    }

    - (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer withType:(RPSampleBufferType)sampleBufferType {
        [JCBroadcastSampleHandler processSampleBuffer:sampleBuffer withType:sampleBufferType];
    }

    - (void)broadcastFinished {
        [JCBroadcastSampleHandler broadcastFinished];
    }

@end

# 开启屏幕共享

开启屏幕共享,调用如下接口 enableScreenShare (opens new window),并且设置参数 enable 设置为 true

/**
 * @brief 开关屏幕共享
 * @param enable 是否开启屏幕共享
 * @param appGroupId  extension和app所处于的同一个groupId iOS11以上需要传,iOS11以下传空
 * @param preferredExtension 希望打开的extension的ID  iOS11以上需要传,iOS11以下传空
 * @return 返回 true 表示正常执行调用流程,false 表示调用异常
 */
- (bool)enableScreenShare:(bool)enable appGroupId:(NSString *)appGroupId preferredExtension:(NSString *)preferredExtension;

示例代码:

// 开启屏幕共享
[conference enableScreenShare:true appGroupId:@"group.com.juphoon.uploadExTest" preferredExtension:@"com.juphoon.conference.JCShare"];

收到 onCommandReceivedResult (opens new window) 回调,同时 commandInfo.type 为 JCConferenceCommandInfo.JCConferenceCommandInfoTypeScreenShareStart (opens new window) 时,表示成员开启屏幕共享,需要请求屏幕共享的视频流。

/**
 *  @brief              请求屏幕共享的视频流
 *  @param screenUri    屏幕分享uri
 *  @param pictureSize  视频请求尺寸类型
 *  @return             返回 true 表示正常执行调用流程,false 表示调用异常
 *  @see JCConferencePictureSize
 *  @warning 当 pictureSize 为 JCConferencePictureSizeNone 标识关闭请求
 */
- (bool)requestScreenVideo:(NSString *)screenUri pictureSize:(JCConferencePictureSize)pictureSize;

其中 pictureSize 的值有:

///初始值
JCConferencePictureSizeInit = -1,
/// 不请求
JCConferencePictureSizeNone,
/// 最小尺寸
JCConferencePictureSizeMin,
/// 小尺寸
JCConferencePictureSizeSmall,
/// 大尺寸
JCConferencePictureSizeLarge,
/// 最大尺寸
JCConferencePictureSizeMax,

请求屏幕共享的视频流后调用 JCMediaDevice (opens new window) 类中的 startVideo (opens new window) 接口,该接口能够返回 JCMediaDeviceVideoCanvas (opens new window) 这个视频对象类通过 JCMediaDeviceVideoCanvas.videoView (opens new window) 能够获取视频渲染视图。

/**
 *  @brief 获得预览视频对象,通过此对象能获得视图用于UI显示
 *  @param videoSource 渲染标识串,比如 JCMediaChannelParticipant JCCallItem 中的 renderId  JCConferenceParticipant 中的renderId

 *  @param type        渲染模式,@ref JCMediaDeviceRender
 *  @return JCMediaDeviceVideoCanvas 对象
 */
- (JCMediaDeviceVideoCanvas*)startVideo:(NSString*)videoSource renderType:(int)type;

其中 renderType 的值有:

/// 视频图像按比例填充整个渲染区域(裁剪掉超出渲染区域的部分区域)
JCMediaDeviceRenderFullScreen = 0,
/// 视频图像的内容完全呈现到渲染区域(可能会出现黑边,类似放电影的荧幕)
JCMediaDeviceRenderFullContent,
/// 自动
JCMediaDeviceRenderFullAuto,

onCommandReceivedResult (opens new window) 回调接口:

/**
* @brief 收到会议属性变化或会议其他通知
*
* @param type 消息类型
*
*/
- (void)onCommandReceivedResult:(JCConferenceCommandInfo *)commandInfo;

commandInfo.typeConferenceCommandInfo.JCConferenceCommandInfoTypeScreenShareStart (opens new window) 时,表示成员开启屏幕共享。

示例代码:

//屏幕共享开启后会收到onCommandReceivedResult回调
- (void)onCommandReceivedResult:(JCConferenceCommandInfo *)commandInfo {
    if(commandInfo.type == JCConferenceCommandInfo.JCConferenceCommandInfoTypeScreenShareStart){
        //执行开启屏幕共享成功后的操作
        _screen.canvas = [mediaDevice startVideo:conference.getConferenceInfo.screenRenderId renderType:JCMediaDeviceRenderFullContent];
        [conference requestScreenVideo:conference.getConferenceInfo.screenRenderId pictureSize:JCConferencePictureSizeLarge];
        [_renderView addSubview:_screen.canvas.videoView];
        ...
    }
}

您可以调用 JCMediaDevice 类中的 setScreenCaptureProperty 方法设置屏幕共享采集属性,包括采集的高度、宽度和帧速率。

/**
 *  @breif 设置屏幕共享采集属性
 *  @param width 采集宽度,默认640
 *  @param height 采集高度,默认360
 *  @param framerate 帧速率,默认10
 */
- (void)setScreenCaptureProperty:(int)width height:(int)height framerate:(int)framerate;

TIP

该方法可以在开启屏幕共享前调用,也可以在屏幕共享中调用;如果在屏幕共享中调用,则设置的采集属性要在下次屏幕共享开启时生效。

# 关闭屏幕共享

如果需要关闭屏幕共享,调用接口 enableScreenShare (opens new window),并且设置参数enable设置为false

/**
 * @brief 开关屏幕共享
 * @param enable 是否开启屏幕共享
 * @param appGroupId  extension和app所处于的同一个groupId iOS11以上需要传,iOS11以下传空
 * @param preferredExtension 希望打开的extension的ID  iOS11以上需要传,iOS11以下传空
 * @return 返回 true 表示正常执行调用流程,false 表示调用异常
 */
- (bool)enableScreenShare:(bool)enable appGroupId:(NSString *)appGroupId preferredExtension:(NSString *)preferredExtension;

关闭屏幕共享时,会议中的成员会收到回调 onCommandReceivedResult (opens new window)

// 关闭屏幕共享
[conference enableScreenShare:false appGroupId:@"" preferredExtension:@""];

//屏幕共享关闭后会收到onCommandReceivedResult回调
- (void)onCommandReceivedResult:(JCConferenceCommandInfo *)commandInfo {
    if(commandInfo.type == JCConferenceCommandInfo.JCConferenceCommandInfoTypeScreenShareStop){
        //执行关闭屏幕共享成功后的操作
        [conference requestScreenVideo:conference.getConferenceInfo.screenRenderId pictureSize:JCConferencePictureSizeNone];
        [mediaDevice stopVideo:_canvas];
        ...
    }
}

commandInfo.type 为 JCConferenceInfo.JCConferenceCommandInfoTypeScreenShareStop (opens new window) 时,表示成员关闭屏幕共享。

示例代码:

// 关闭屏幕共享
[conference enableScreenShare:false appGroupId:@"" preferredExtension:@""];

//屏幕共享关闭后会收到onCommandReceivedResult回调
- (void)onCommandReceivedResult:(JCConferenceCommandInfo *)commandInfo {
    if(commandInfo.type == JCConferenceCommandInfo.JCConferenceCommandInfoTypeScreenShareStop){
        //执行关闭屏幕共享成功后的操作
        [conference requestScreenVideo:conference.getConferenceInfo.screenRenderId pictureSize:JCConferencePictureSizeNone];
        [mediaDevice stopVideo:_canvas];
        ...
    }
}

# 屏幕共享使用操作

由于 ReplayKit 2仅支持 iOS 12.0 以上的机型进行系统屏幕共享, iOS12 及以下只能共享应用内屏幕。

iOS12 及以上机型开启屏幕共享。

ios12opera1.jpg

关闭屏幕共享如下图所示:

ios12opera2.jpg