iOS

# 视频管理

Juphoon 视频能力平台支持跨平台的一对一、多对多的通话模式的高清音视频通话,Juphoon RTC SDK 供业务灵活集成应用,实现视频管理能力。

# 1. 控制视频流上传

通话中的成员可通过调用 enableUploadVideoStream (opens new window) 方法来开启关闭发送本地视频流。

/**
 * 开启/关闭发送本地视频流
 *
 * 通话中调用该方法可开启或关闭发送本地视频流。开启后,通话中的成员将看见本端画面;关闭后,房间成员将看不见本端画面  <br>
 * 通话中调用此方法成功后,服务器会更新状态并同步给通话中所有成员,即所有成员会收到 {@link JRTCGuestCallback.onMemberUpdate:changeParam: onMemberUpdate} 或 {@link JRTCAgentCallback.onMemberUpdate:changeParam: onMemberUpdate} 回调,具体可关注 {@link JRTCRoomParticipant.video video} 和 {@link JRTCRoomParticipantChangeParam.video video} <br>
 * 通话中调用此方法不影响接收其他成员的视频流
 * @param enable 开启/关闭发送本地视频流
 * - true: 开启,即发送本地视频流
 * - false: 关闭,即不发送本地视频流
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 */
- (bool)enableUploadVideoStream:(bool)enable;/**
 * 开启/关闭发送本地视频流
 *
 * 通话中调用该方法可开启或关闭发送本地视频流。开启后,通话中的成员将看见本端画面;关闭后,房间成员将看不见本端画面  <br>
 * 通话中调用此方法成功后,服务器会更新状态并同步给通话中所有成员,即所有成员会收到 {@link JRTCGuestCallback.onMemberUpdate:changeParam: onMemberUpdate} 或 {@link JRTCAgentCallback.onMemberUpdate:changeParam: onMemberUpdate} 回调,具体可关注 {@link JRTCRoomParticipant.video video} 和 {@link JRTCRoomParticipantChangeParam.video video} <br>
 * 通话中调用此方法不影响接收其他成员的视频流
 * @param enable 开启/关闭发送本地视频流
 * - true: 开启,即发送本地视频流
 * - false: 关闭,即不发送本地视频流
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 */
- (bool)enableUploadVideoStream:(bool)enable;

通话中成员视频流变化通过 JRTCAgentCallback (opens new window)onMemberUpdate (opens new window) 回调通知。

/**
 * 通话中成员属性更新回调
 *
 * 常用的有 {@link JRTCRoomParticipantChangeParam.volume 音量值}、{@link JRTCRoomParticipantChangeParam.audio 音频上传状态}、{@link JRTCRoomParticipantChangeParam.video 视频上传状态}等。<br>
 * 例如当通话中有成员关闭视频传输,通话中所有成员都会收到此回调。
 * @param participant 属性更新的成员对象
 * @param changeParam 更新的属性对象
 */
- (void)onMemberUpdate:(JRTCRoomParticipant *)participant changeParam:(JRTCRoomParticipantChangeParam *)changeParam;/**
 * 通话中成员属性更新回调
 *
 * 常用的有 {@link JRTCRoomParticipantChangeParam.volume 音量值}、{@link JRTCRoomParticipantChangeParam.audio 音频上传状态}、{@link JRTCRoomParticipantChangeParam.video 视频上传状态}等。<br>
 * 例如当通话中有成员关闭视频传输,通话中所有成员都会收到此回调。
 * @param participant 属性更新的成员对象
 * @param changeParam 更新的属性对象
 */
- (void)onMemberUpdate:(JRTCRoomParticipant *)participant changeParam:(JRTCRoomParticipantChangeParam *)changeParam;

示例代码:

// 关闭视频流发送
[_agent enableUploadVideoStream:false];

// 开启视频流发送
[_agent enableUploadVideoStream:true];

// 通话中成员属性更新回调
- (void)onMemberUpdate:(JRTCRoomParticipant *)participant changeParam:(JRTCRoomParticipantChangeParam *)changeParam {
    if (changeParam.video) {
        if (participant.video == true) {
            NSLog(@"成员 %@ 视频流打开", part.userId);
        } 
        else {
            NSLog(@"成员 %@ 视频流关闭", part.userId);   
        }  
    } 
}// 关闭视频流发送
[_agent enableUploadVideoStream:false];

// 开启视频流发送
[_agent enableUploadVideoStream:true];

// 通话中成员属性更新回调
- (void)onMemberUpdate:(JRTCRoomParticipant *)participant changeParam:(JRTCRoomParticipantChangeParam *)changeParam {
    if (changeParam.video) {
        if (participant.video == true) {
            NSLog(@"成员 %@ 视频流打开", part.userId);
        } 
        else {
            NSLog(@"成员 %@ 视频流关闭", part.userId);   
        }  
    } 
}

# 2. 视频属性设置

# 设置请求分辨率

在会议中修改对端画面的分辨率,这个参数结合访客 SVC 来使用可以实现通话中切换设置的分辨率

/**
 * 订阅通话中其他成员的视频流
 *
 * @param participant   成员对象
 * @param videoSize   视频请求的尺寸,详见 @ref JRTCVideoSize
 * @return 接口调用结果
 * - true: 接口调用成功,会收到 {@link JRTCAgentCallback.onMemberUpdate:changeParam: onMemberUpdate} 回调,具体可关注 {@link JRTCRoomParticipantChangeParam.pictureSize pictureSize} 和 {@link JRTCRoomParticipant.pictureSize pictureSize} 属性
 * - false: 接口调用异常
 */
- (bool)requestVideo:(JRTCRoomParticipant* __nonnull)participant videoSize:(JRTCVideoSize* __nonnull)videoSize;

/**
 * 取消订阅通话中其他成员的视频流
 * @param participant 成员对象
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 */
- (bool)unRequestVideo:(JRTCRoomParticipant* __nonnull)participant;

示例代码:

// 订阅成员视频流
JRTCVideoSize *size = [[JRTCVideoSize alloc] init];
size.width = 720;
size.height = 1280;
[_agent requestVideo:participant videoSize:size];

// 取消订阅成员视频流
[_agent unRequestVideo:participant];

# SVC 设置说明

根据实际订阅需求和网络状况动态调整视频发送分辨率是JSM会议的特性之一,SVC可用于设置会议视频的每一层编码分辨率。该参数在会议创建时设置,且全局统一。 详见 SVC 说明 (opens new window)。 可在座席发起回呼时,通过呼叫参数 JRTCCallCenterCallParam (opens new window)svcResolution (opens new window) 属性进行设置,通话全局属性,只有发起呼叫用户设置有效。

/**
 * svc分辨率,默认为 "1 180 250 360 600 720 1400"
 *
 * 用于自定义分层参数和码率
 *
 * 格式:
 * 高度公约数 第一层高倍数 第一层码率 第二层高倍数 第二层码率 第三层高倍数 第三层码率 第四层高倍数 第四层码率 <br>
 * 说明
 * 1)默认宽高比16:9,即 wholeRatio
 * 2)编码宽高最后被裁成16整除
 * 例如 "1 180 250 360 600 720 1400"
 * 第一层 分辨率 宽320(180*1/9*16)高 180(180*1); 码率250kbps
 * 第二层 分辨率 宽640(360*1/9*16)高 360(360*1); 码率600kbps 
 * 第三层 分辨率 宽1280(720*1/9*16)高 720(720*1); 码率1400kbps 
 * 此情况下只有三层,若需要四层,则需补充为 "1 180 250 360 600 720 1400 1080 1600" 
 * 第四层 分辨率 宽1920(1080*1/9*16)高 1080(1080*1); 码率1600kbps 
 */
@property (nonatomic, copy) NSString *svcResolution;

示例代码:

// 创建呼叫配置参数
JRTCCallCenterCallParam *param = [[JRTCCallCenterCallParam alloc] init];
// 配置SVC
param.svcResolution = @"1 180 250 360 600 720 1400 1080 1600";
// 发起呼叫
[_agent recall:@"xxx" callParam:param];

# 设置本地宽高比

设置本端视频宽高比,用于适配不同屏幕的显示需求,需在通话建立后调用。

/**
 * 设置本端视频宽高比
 *
 * 将自己的视频采集根据宽高比裁剪后进行发送,通话中其他成员收到的画面将是裁剪后的比例。<br>
 * 该方法不影响其他成员的画面在本端的显示比例,也不影响其他成员相互之间的画面显示比例。<br>
 * 必须 ***开始通话后*** 设置才能生效,即收到 {@link JRTCAgentCallback.onCallStateChanged:incomingType:inviter:reason: onCallStateChanged} 回调且 type == AgentCallStateChangeTypeTalking 时设置才生效。
 * @param ratio 视频宽高比
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 */
- (bool)setRatio:(float)ratio;

示例代码:

- (void)onCallStateChanged:(AgentCallStateChangeType)type incomingType:(CallIncomingType)incomingType inviter:(nullable JRTCInviter *)inviter reason:(CallTermReason)reason {
    if (type == AgentCallStateChangeTypeTalking) {
        // 注:在通话建立后调用才能生效
        [_agent setRatio:9/16.0];
    }
}

# 设置房间视频清晰度

如果觉得设置 SVC 不好理解,可以直接设置属性 videoDefinition (opens new window) 来调整通话视频清晰度(一组已经定义的 SVC 和 帧率),VideoDefinitionType (opens new window) 详见 API 文档。

/**
 * 设置通话视频清晰度,主要通过修改 svcResolution 参数和 maxFrameRate 参数调整清晰度,
 * 默认为 DefinitionCustom
 */
@property (nonatomic, assign) VideoDefinitionType videoDefinition;

示例代码:

// 创建呼叫配置参数
JRTCCallCenterCallParam *param = [[JRTCCallCenterCallParam alloc] init];
// 设置通话视频清晰为流畅模式,低帧率
param.videoDefinition = DefinitionFluencyFrameLow;
// 发起呼叫
[_agent recall:@"10080" callParam:param];

# 3. 视频渲染管理

渲染管理主要使用到 JRTCMediaDeviceVideoCanvas (opens new window) 类的接口。包括更新渲染视频画面、停止视频渲染等。

# 渲染视频画面

/**
 * 开始自身视频渲染
 *
 * 获取本端视频预览对象 JRTCMediaDeviceVideoCanvas ,通过此对象能获得视图用于UI显示
 * @note
 * 调用此方法时需要保证默认摄像头不为空,即 @ref defaultCamera 不为空,否则将直接返回 nil
 * @param type 渲染模式:
 * - @ref JRTCMediaDeviceRenderFullScreen : 铺满窗口,会有裁剪
 * - @ref JRTCMediaDeviceRenderFullContent : 全图像显示,会有黑边
 * - @ref JRTCMediaDeviceRenderFullAuto : 自适应
 * @return
 * - JRTCMediaDeviceVideoCanvas 对象: 开始自身视频渲染成功
 * - nil: 开始自身视频渲染失败
 */
- (JRTCMediaDeviceVideoCanvas* __nullable)startCameraVideo:(JRTCMediaDeviceRender)type;

/**
 * 开始自身视频渲染
 *
 * 获取本端视频预览对象 JRTCMediaDeviceVideoCanvas ,通过此对象能获得视图用于UI显示
 * @note
 * 调用此方法时需要保证默认摄像头不为空,即 @ref defaultCamera 不为空,否则将直接返回 nil
 * @param type 渲染模式:
 * - @ref JRTCMediaDeviceRenderFullScreen : 铺满窗口,会有裁剪
 * - @ref JRTCMediaDeviceRenderFullContent : 全图像显示,会有黑边
 * - @ref JRTCMediaDeviceRenderFullAuto : 自适应
 * @param view 渲染视图控件
 * @return
 * - JRTCMediaDeviceVideoCanvas 对象: 开始自身视频渲染成功
 * - nil: 开始自身视频渲染失败
 */
- (JRTCMediaDeviceVideoCanvas* __nullable)startCameraVideo:(JRTCMediaDeviceRender)type view:(JCView* __nonnull)view;

/**
 * 开始其他端的视频渲染
 *
 * 获取其他端的视频预览对象 JRTCMediaDeviceVideoCanvas ,通过此对象能获得视图用于UI显示
 *
 * @param streamId 视频流ID
 * @param type  渲染模式:
 * - @ref JRTCMediaDeviceRenderFullScreen : 铺满窗口,会有裁剪
 * - @ref JRTCMediaDeviceRenderFullContent : 全图像显示,会有黑边
 * - @ref JRTCMediaDeviceRenderFullAuto : 自适应
 * @return
 * - JRTCMediaDeviceVideoCanvas 对象: 开始其他端视频渲染成功
 * - nil: 开始其他端视频渲染失败
 */
- (JRTCMediaDeviceVideoCanvas* __nullable)startVideo:(NSString* __nonnull)streamId renderType:(JRTCMediaDeviceRender)type;

/**
 * 开始其他端的视频渲染
 *
 * 获取其他端的视频预览对象 JRTCMediaDeviceVideoCanvas ,通过此对象能获得视图用于UI显示
 *
 * @param streamId 视频流ID
 * @param type  渲染模式:
 * - @ref JRTCMediaDeviceRenderFullScreen : 铺满窗口,会有裁剪
 * - @ref JRTCMediaDeviceRenderFullContent : 全图像显示,会有黑边
 * - @ref JRTCMediaDeviceRenderFullAuto : 自适应
 * @param view 渲染视图控件
 * @return
 * - JRTCMediaDeviceVideoCanvas 对象: 开始其他端视频渲染成功
 * - nil: 开始其他端视频渲染失败
 */
- (JRTCMediaDeviceVideoCanvas* __nullable)startVideo:(NSString* __nonnull)streamId renderType:(JRTCMediaDeviceRender)type view:(JCView* __nonnull)view;/**
 * 开始自身视频渲染
 *
 * 获取本端视频预览对象 JRTCMediaDeviceVideoCanvas ,通过此对象能获得视图用于UI显示
 * @note
 * 调用此方法时需要保证默认摄像头不为空,即 @ref defaultCamera 不为空,否则将直接返回 nil
 * @param type 渲染模式:
 * - @ref JRTCMediaDeviceRenderFullScreen : 铺满窗口,会有裁剪
 * - @ref JRTCMediaDeviceRenderFullContent : 全图像显示,会有黑边
 * - @ref JRTCMediaDeviceRenderFullAuto : 自适应
 * @return
 * - JRTCMediaDeviceVideoCanvas 对象: 开始自身视频渲染成功
 * - nil: 开始自身视频渲染失败
 */
- (JRTCMediaDeviceVideoCanvas* __nullable)startCameraVideo:(JRTCMediaDeviceRender)type;

/**
 * 开始自身视频渲染
 *
 * 获取本端视频预览对象 JRTCMediaDeviceVideoCanvas ,通过此对象能获得视图用于UI显示
 * @note
 * 调用此方法时需要保证默认摄像头不为空,即 @ref defaultCamera 不为空,否则将直接返回 nil
 * @param type 渲染模式:
 * - @ref JRTCMediaDeviceRenderFullScreen : 铺满窗口,会有裁剪
 * - @ref JRTCMediaDeviceRenderFullContent : 全图像显示,会有黑边
 * - @ref JRTCMediaDeviceRenderFullAuto : 自适应
 * @param view 渲染视图控件
 * @return
 * - JRTCMediaDeviceVideoCanvas 对象: 开始自身视频渲染成功
 * - nil: 开始自身视频渲染失败
 */
- (JRTCMediaDeviceVideoCanvas* __nullable)startCameraVideo:(JRTCMediaDeviceRender)type view:(JCView* __nonnull)view;

/**
 * 开始其他端的视频渲染
 *
 * 获取其他端的视频预览对象 JRTCMediaDeviceVideoCanvas ,通过此对象能获得视图用于UI显示
 *
 * @param streamId 视频流ID
 * @param type  渲染模式:
 * - @ref JRTCMediaDeviceRenderFullScreen : 铺满窗口,会有裁剪
 * - @ref JRTCMediaDeviceRenderFullContent : 全图像显示,会有黑边
 * - @ref JRTCMediaDeviceRenderFullAuto : 自适应
 * @return
 * - JRTCMediaDeviceVideoCanvas 对象: 开始其他端视频渲染成功
 * - nil: 开始其他端视频渲染失败
 */
- (JRTCMediaDeviceVideoCanvas* __nullable)startVideo:(NSString* __nonnull)streamId renderType:(JRTCMediaDeviceRender)type;

/**
 * 开始其他端的视频渲染
 *
 * 获取其他端的视频预览对象 JRTCMediaDeviceVideoCanvas ,通过此对象能获得视图用于UI显示
 *
 * @param streamId 视频流ID
 * @param type  渲染模式:
 * - @ref JRTCMediaDeviceRenderFullScreen : 铺满窗口,会有裁剪
 * - @ref JRTCMediaDeviceRenderFullContent : 全图像显示,会有黑边
 * - @ref JRTCMediaDeviceRenderFullAuto : 自适应
 * @param view 渲染视图控件
 * @return
 * - JRTCMediaDeviceVideoCanvas 对象: 开始其他端视频渲染成功
 * - nil: 开始其他端视频渲染失败
 */
- (JRTCMediaDeviceVideoCanvas* __nullable)startVideo:(NSString* __nonnull)streamId renderType:(JRTCMediaDeviceRender)type view:(JCView* __nonnull)view;

示例代码:

JRTCMediaDeviceVideoCanvas *canvas = [_mediaDevice startVideo:participant.streamId renderType:JRTCMediaDeviceRenderFullScreen];
canvas.videoView.frame = CGRectMake(0, 0, 100, 100);
[self.view addSubview:canvas.videoView];JRTCMediaDeviceVideoCanvas *canvas = [_mediaDevice startVideo:participant.streamId renderType:JRTCMediaDeviceRenderFullScreen];
canvas.videoView.frame = CGRectMake(0, 0, 100, 100);
[self.view addSubview:canvas.videoView];

# 停止视频渲染

/**
 * 停止视频渲染
 * @param canvas JRTCMediaDeviceVideoCanvas 对象,由 {@link startVideo:renderType: startVideo} 或 {@link startCameraVideo: startCameraVideo} 接口返回
 */
- (void)stopVideo:(JRTCMediaDeviceVideoCanvas* __nonnull)canvas;/**
 * 停止视频渲染
 * @param canvas JRTCMediaDeviceVideoCanvas 对象,由 {@link startVideo:renderType: startVideo} 或 {@link startCameraVideo: startCameraVideo} 接口返回
 */
- (void)stopVideo:(JRTCMediaDeviceVideoCanvas* __nonnull)canvas;

注:开启渲染后必须在结束通话等不需要时进行关闭,否则会造成内存泄漏。

示例代码:

[_mediaDevice stopVideo:canvas];[_mediaDevice stopVideo:canvas];

# 视频渲染回调

调用视频渲染接口后主要关注两个回调接口 onRenderReceived (opens new window)onRenderStart (opens new window)

使用场景举例:为了提升交互体验,可以在调用渲染接口后,等收到渲染开始接口时,再显示视频画面。

/**
 * 收到第一帧数据回调
 *
 * @param canvas 视图渲染对象
 * @param ratio 宽高比
 */
- (void)onRenderReceived:(JRTCMediaDeviceVideoCanvas*)canvas ratio:(CGFloat)ratio;

/**
 * 渲染开始回调
 *
 * @param canvas 视图渲染对象
 * @param ratio 宽高比
 */
- (void)onRenderStart:(JRTCMediaDeviceVideoCanvas*)canvas ratio:(CGFloat)ratio;/**
 * 收到第一帧数据回调
 *
 * @param canvas 视图渲染对象
 * @param ratio 宽高比
 */
- (void)onRenderReceived:(JRTCMediaDeviceVideoCanvas*)canvas ratio:(CGFloat)ratio;

/**
 * 渲染开始回调
 *
 * @param canvas 视图渲染对象
 * @param ratio 宽高比
 */
- (void)onRenderStart:(JRTCMediaDeviceVideoCanvas*)canvas ratio:(CGFloat)ratio;

# 4. 视频截图

视频业务存在对当前通话截屏的业务操作,以便于记录用户的操作行为。详见 snapshotWithStreamId (opens new window)

/**
 * 截图
 *
 * @param streamId 要截图的视频流ID
 * @param path 要存放截图的文件路径
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 */
- (bool)snapshotWithStreamId:(NSString* __nonnull)streamId path:(NSString* __nonnull)path;/**
 * 截图
 *
 * @param streamId 要截图的视频流ID
 * @param path 要存放截图的文件路径
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 */
- (bool)snapshotWithStreamId:(NSString* __nonnull)streamId path:(NSString* __nonnull)path;

结果通过 JRTCMediaDeviceCallback (opens new window) 中的 onSnapshotComplete (opens new window) 接口上报。

/**
 * 截图完成回调
 *
 * @param file 截图路径
 * @param width 图片像素宽
 * @param height 图片像素高
 */
- (void)onSnapshotComplete:(NSString *)file width:(int)width height:(int)height;/**
 * 截图完成回调
 *
 * @param file 截图路径
 * @param width 图片像素宽
 * @param height 图片像素高
 */
- (void)onSnapshotComplete:(NSString *)file width:(int)width height:(int)height;

示例代码:

// 截图
// streamId 为通话中成员的 streamId
// path 为沙盒路径
[_mediaDevice snapshotWithStreamId:@"streamId" path:@"path"];

// 截图完成回调
- (void)onSnapshotComplete:(NSString *)file width:(int)width height:(int)height {
 	//截图完成
}// 截图
// streamId 为通话中成员的 streamId
// path 为沙盒路径
[_mediaDevice snapshotWithStreamId:@"streamId" path:@"path"];

// 截图完成回调
- (void)onSnapshotComplete:(NSString *)file width:(int)width height:(int)height {
 	//截图完成
}

# 5. 视频采集回调

当打开本端摄像头视频预览或者打开本地屏幕采集时,通过实现 JRTCMediaDeviceCallback (opens new window) 中的 onVideoCaptureDidStart (opens new window) 接口能收到采集开始通知。

/**
 * 视频采集开始回调
 *
 * @param streamId 视频流ID
 * @param ratio 宽高比
 */
- (void)onVideoCaptureDidStart:(NSString *)streamId ratio:(CGFloat)ratio;/**
 * 视频采集开始回调
 *
 * @param streamId 视频流ID
 * @param ratio 宽高比
 */
- (void)onVideoCaptureDidStart:(NSString *)streamId ratio:(CGFloat)ratio;

# 6. 视频异常回调

通过实现 JRTCMediaDeviceCallback (opens new window)onVideoError (opens new window) 接口来监听视频异常、采集异常、渲染错误等事件,具体原因查看参数 error 描述。

/**
 * 视频异常,渲染错误,包括摄像头采集错误回调
 *
 * @param error 异常信息
 */
- (void)onVideoError:(NSString *)error;/**
 * 视频异常,渲染错误,包括摄像头采集错误回调
 *
 * @param error 异常信息
 */
- (void)onVideoError:(NSString *)error;