iOS

# 音视频录制

在开展在线理财、开户、面签等业务时,应国家监管要求,必须提供录音录像服务,形成交易记录的视频,存档备查。Juphoon RTC SDK 在音视频通话过程中,支持全程进行实时的服务器录制或本地录制,录制的场景画面覆盖座席画面和所有终端类型的访客画面,按需可支持多摄像头、多屏幕合成录制,满足用户记录业务办理全过程录制的需求。

# 1. 本地录制

本地录制支持实时的通话过程音频录制,录制文件保存在用户本地设备中,适用于通话过程录音录像场景等其他音视频相关场景。优点不受网络影响,录制画面质量高,减少带宽压力。 本地录制在本地生成视频文件。

/**
 * 开启/关闭本地录制
 * @param enable 开启或关闭本地录制
 * - true: 开启本地录制
 * - false: 关闭本地录制
 * @param recordParam 本地录制参数配置,当 enable == true 时,{@link JRTCRecordLocalParam.filePath} 必须设置,其余参数不设置则使用默认配置;当 enable == false 时,recordParam 可传 nil
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 */
- (bool)enableLocalRecord:(bool)enable recordParam:(JRTCRecordLocalParam *)recordParam;

本地录制参数详见 JRTCRecordLocalParam (opens new window)

示例代码:

    // 创建并配置本地录制参数
    JRTCRecordLocalParam *param = [[JRTCRecordLocalParam alloc] init];
    param.filePath = @"录制文件本地保存路径";
    param.frameRate = 24;
    param.mergeMode = VideoMergeModeCustomLayout;
    param.videoWidth = 640;
    param.videoHeight = 360;
    // 设置只录制音频
    param.recVideo = false;
    param.watermarkTextDic = @{@"key" : @"value"};

    JRTCRecordLocalLayout *layout = [JRTCRecordLocalLayout new];
    layout.position = 0;
    [layout setId:(_agent.participants[0]).streamId isUserId:NO];
    
//    [layout setId:_agent.callId isUserId:NO];//双会议其他房间的通话唯一标识,用于第二个房间的屏幕共享视频流
//
//    [layout setId:_agent.shareStreamId isUserId:NO];//房间中屏幕共享视频流ID
//
//    [layout setId: [_mediaDecice getScreenCaptureId] isUserId:NO];//本地摄像头视频流ID


    JRTCRecordLocalLayout *layout1 = [JRTCRecordLocalLayout new];
    [layout setId:@"stream1" isUserId:NO];//设置布局位置设置布局中视频流标识,视频流ID或者屏幕共享流ID
    layout1.position = 1;//设置布局位置为1
    param.layoutArray = @[layout, layout1];
    param.configFilePath = @"xxx";//应用中存储的配置文件路径

    // 开启本地录制
    [_agent enableLocalRecord:true recordParam:param];
    // 关闭本地录制
    [_agent enableLocalRecord:false recordParam:nil];

更新本地录制自定义布局 agent.updateLocalRecordLayout (opens new window)

/**
 * 更新本地录制自定义布局
 *
 * @param layoutList 需要更新的布局列表
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 */
- (bool)updateLocalRecordLayout:(NSArray<JRTCRecordLocalLayout*>* __nonnull)layoutList;

示例代码:

    JRTCRecordLocalLayout *layout1 = [JRTCRecordLocalLayout new];
    [layout1 setId: @"id1" isUserId:NO];
    layout1.position = 0;
    
    JRTCRecordLocalLayout *layout2 = [JRTCRecordLocalLayout new];
    [layout2 setId: @"id2" isUserId:NO];
    layout2.position = 1;
    bool ret = [_agent updateLocalRecordLayout:@[layout1, layout2]];

通过配置文件实现本地录制 流程图如下:img

本地录制配置文件示例如下:

{
    "default" : {   //录制配置类型, 固定值.<br/>
        "videoRecord" : {   //视频录制配置, 固定值.
             "layout" : [        //自定义布局,mergeMode 字段为自定义布局模式 4 时生效, JSON数组格式, 可同时设置多个, 实际应用时通过窗口号区分.
                 {
                     "posX" : 0.25,                  //画面左上角的横坐标(双精度浮点数类型), 代表占画面总宽度的比例.
                     "posY" : 0.26805556000000003,   //画面左上角的纵坐标(双精度浮点数类型), 代表占画面总高度的比例.
                     "width" : 0.1140625,            //画面的宽度(双精度浮点数类型), 代表占画面总宽度的比例.
                     "height" : 0.47916666000000002, //画面的高度(双精度浮点数类型), 代表占画面总高度的比例.
                     "window" : 0                    //窗口号(大于或等于的整数), 在使用属性 {@link layoutArray layoutArray} 自定义视频窗口布局时需要, 对应于用户自定义的位置信息 {@link JRTCRecordLocalLayout.setPosition: setPosition} 设置布局位置.
                 },
                 {
                     "posX" : 0.49609375,            //画面左顶点的横坐标(双精度浮点数类型), 范围为[0, 1], 代表占画面总宽度的比例.
                     "posY" : 0.033333334999999999,  //画面左顶点的纵坐标(双精度浮点数类型), 范围为[0, 1], 代表占画面总高度的比例.
                     "width" : 0.36406250000000001,  //画面的宽度(双精度浮点数类型), 范围为[0, 1], 代表占画面总宽度的比例.
                     "height" : 0.94027775999999996, //画面的高度(双精度浮点数类型) 范围为[0, 1], 代表占画面总高度的比例.
                     "window" : 1                    //窗口号(大于或等于的整数), 在使用属性 {@link layoutArray layoutArray} 自定义视频窗口布局时需要, 对应于用户自定义的位置信息 {@link RecordLayout#setPosition(int)} setPosition} 设置布局位置.
                 }
             ],
             "mergeBitrate" : 0, //设置录制视频的码率, 单位为千比特每秒(kbps), 默认值为0, 此时码率由内部媒体算法进行自适应调节
             "mergeFPS" : 30,    //设置录制视频的帧率, 单位为每秒传输帧数(fps), 默认值为20.
             "mergeWidth" : 1280,//设置录制视频的宽度, 默认值为 640
             "mergeHeight" : 720,//设置录制视频的高度, 默认值为 360
             "mergeMode" : 4,    //设置媒体推流的视频合并模式, 默认值为智能布局 5, 目前可支持自定义布局 4 和智能布局 5.
             "mergeModeI" : 1,   //设置智能分屏模式下的布局样式(无屏幕共享), 默认值为自由布局 1, 有效值参考 {@link IntelligentMergeMode 智能分屏模式下的布局样式(无屏幕共享)}, 本字段仅在 mergeMode 为智能布局 5 时生效.
             "screenShareType" : 1 //设置智能分屏模式下的布局样式(有屏幕共享), 默认值为屏幕共享独占 1, 有效值参考 {@link ScsMergeMode 智能分屏模式下的布局样式(有屏幕共享)}, 本字段仅在 mergeMode 为智能布局 5 时生效.
         },
         "watermark" : { //水印配置, 固定值.
             "picture" : [   //图片水印配置, 固定值, 图片水印目前只支持 png 格式.
                 {
                     "enable" : true,    //是否启用(布尔类型).
                     "pcUrl" : "http://xxx/xxx.png",  //图片水印链接地址.
                     "index" : 1,        //水印的序号.
                     "state" : 1,        //水印的状态. 设置值为1表示使用水印,设置值为2表示关闭水印.
                     "posX" : 0,         //相对于基准位置的水平偏移值(整数类型), 负值向左偏移, 正值向右偏移, 实际大小非比例值.
                     "posY" : 600        //相对于基准位置的垂直偏移值(整数类型), 负值向上偏移, 正值向下偏移, 实际大小非比例值.
                 }
             ],
             "text" : {  //文本水印配置, 固定值.
                 "enable" : true,    //是否启用(布尔类型).
                 "memo" : [          //文本水印样式配置(JSON数组类型), 如果不设置就使用默认全局样式.
                     "Dialogue: 0,0:00:00.0,60:00:00.0,Default,,0,0,0,,{\\pos(34, 56)\\an7}菊风文本水印1$@name@$",
                     "Dialogue: 0,0:00:00.0,60:00:00.0,Default,,0,0,0,,{\\pos(50, 100)\\an7}菊风文本水印2"
                     //数组的每个元素为一条 ASS 字幕的 event 字符串, 支持通过标签来设置各种文字特效, 添加的event字符串必须是utf-8编码, 否则中文会出现乱码. ASS 格式规范下载地址: http://www.perlfu.co.uk/projects/asa/ass-specs.doc
                     //其中以 "$@" 开始并且以 "@$" 结束的部分内容"$@name@$"将提取出关键字"name", 通过解析用户通过属性 {@link watermarkTextDic watermarkTextDic} 设置的自定义文本水印信息获取其对应值, "$@name@$"格式的内容被其对应值替换后就是实际应用的 event 字符串, "$@xxx@$" 格式的内容支持同时设置多个.
                 ],
                 "style" : {         //文本水印格式, 固定值.
                     "enable" : true,        //格式是否启用(布尔类型).
                     "alignment" : 0,        //对齐方式, 有效值参考 0:左对齐;1:居中对齐;2:右对齐;
                     "backColor" : 16777215, //背景颜色(整数类型), 10进制颜色代码.
                     "blod" : false,         //是否使用粗体(布尔类型).
                     "fontColor" : 16777215, //字体颜色(整数类型), 10进制颜色代码.
                     "fontFile" : "SourceHanSansCN-Normal.otf",//字体文件路径,Windows系统上只能用相对路径(相对配置文件所在路径),不可以带盘符,建议和配置文件放在同个目录下.
                     "fontSize" : 36,        //字体尺寸(整数类型).
                     "italic" : true,        //是否使用斜体(布尔类型).
                     "underline" : false     //是否带有下划线(布尔类型).
                 }
             },
             "timestamp" : { //时间戳水印配置, 固定值.
                 "enable" : true,    //是否启用(布尔类型).
                 "basePosType" : 0,  //水印基准位置类型(整数类型), 有效值参考 0:左上;1:左下;2:右上;3:右下;4:居中;
                 "borderWidth" : 2,  //字体边界宽度(整数类型), 取值范围为[0, 5].
                 "fontFile" : "SourceHanSansCN-Normal.otf",//字体文件路径,Windows系统上只能用相对路径(相对配置文件所在路径),不可以带盘符,建议和配置文件放在同个目录下.
                 "fontColor" : 0, //字体颜色(整数类型), 有效值参考 0:红色;1:黄色;2:绿色;3:青色;4:蓝色;5:洋红色;6:白色;7:中和色;8:黑色;
                 "fontSize" : 36,    //字体尺寸(整数类型).
                 "isMs" : true,      //是否显示毫秒值(布尔类型).
                 "posX" : 0,         //相对于基准位置的水平偏移值(整数类型), 负值向左偏移, 正值向右偏移, 实际大小非比例值.
                 "posY" : 0          //相对于基准位置的垂直偏移值(整数类型), 负值向上偏移, 正值向下偏移, 实际大小非比例值.
             }
         }
     }
}

配置样例文件(不带注解):📎record.cfg.zip (opens new window)

# 2. 本地音视频录制(不需要建立通信)

调用 startVideoCaptureRecord (opens new window)stopVideoCaptureRecord (opens new window)startAudioRecord (opens new window)stopAudioRecord (opens new window) 接口开启或关闭本地音视频录制,视频录制参数详见:JRTCRecordVideoCaptureParam (opens new window)

/**
 * 开启视频录制(本地录制,不需要建立通信,不能和音频录制 {@link #startAudioRecord:audioSource:fileType: startAudioRecord} 同时开启)
 * @param streamId 视频流ID, (包括摄像头ID、文件视频源ID、屏幕ID等)
 * @param recordParam 录制参数
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 */
- (bool)startVideoCaptureRecord:(NSString *_Nonnull)streamId recordParam:(JRTCRecordVideoCaptureParam *_Nonnull)recordParam;
/**
 * 关闭视频录制(本地录制,不需要建立通信,不能和音频同时录制)
 * @param streamId 视频流ID, (包括摄像头ID、文件视频源ID、屏幕ID等)
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
*/
- (bool)stopVideoCaptureRecord:(NSString *_Nonnull)streamId;

/**
 * 开启音频录制(本地录制,不需要建立通信,不能和视频录制 {@link #startVideoCaptureRecord startVideoCaptureRecord} 同时开启)
 * @param filePath 存储路径
 * @param audioSource 录制文件音频源
 * @param fileType 文件类型,必须包含文件名(xxx.wav或者pcm)
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 */
- (bool)startAudioRecord:(NSString *_Nullable)filePath audioSource:(JRTCRecordAudioSource)audioSource fileType:(JRTCAudioRecordFileType)fileType;

/**
 * 停止音频录制(本地录制,不需要建立通信)
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
*/
- (bool)stopAudioRecord;

录制水印:本地录制支持图片、文字、时间戳水印,通过录制参数设置,详见:JRTCRecordWatermarkImage (opens new window) , JRTCRecordWatermarkText (opens new window) , JRTCRecordWatermarkTimeStamp (opens new window)

/**
 * 图片水印
 */
@interface JRTCRecordWatermarkImage : JRTCRecordWatermark

/**
 * 初始化图片水印
 *
 * @param posX 相对于原点(左上角),X轴坐标(右为正数)
 * @param posY 相对于原点(左上角),Y轴坐标(下为正数)
 * @param filePath 图片路径
 */
- (instancetype)initPosX:(int)posX posY:(int)posY filePath:(NSString *)filePath;

/**
 * 初始化图片水印
 *
 * @param posX 相对于原点(左上角),X轴坐标(右为正数)
 * @param posY 相对于原点(左上角),Y轴坐标(下为正数)
 * @param image 图片对象
 */
- (instancetype)initPosX:(int)posX posY:(int)posY image:(UIImage *)image;

@end

/**
 * 文字水印
 */
@interface JRTCRecordWatermarkText : JRTCRecordWatermark

/**
 * 初始化文字水印
 *
 * @param posX 相对于原点(左上角),X轴坐标(右为正数)
 * @param posY 相对于原点(左上角),Y轴坐标(下为正数)
 * @param fontSize 字体大小
 * @param textColor 文字颜色 16进制rgba转成NSUInteger
 * @param text 文本内容
 */
- (instancetype)initPosX:(int)posX posY:(int)posY fontSize:(int)fontSize textColor:(NSUInteger)textColor text:(NSString *)text;

@end

/**
 * 时间戳水印
 */
@interface JRTCRecordWatermarkTimeStamp : JRTCRecordWatermarkText

/**
 * 初始化文字水印
 *
 * @param posX 相对于原点(左上角),X轴坐标(右为正数)
 * @param posY 相对于原点(左上角),Y轴坐标(下为正数)
 * @param fontSize 字体大小
 * @param textColor 文字颜色 16进制rgba转成NSUInteger
 * @param dateFormat 时间戳格式化参数,默认为yyyy-MM-dd HH:mm:ss.SSS
 */
- (instancetype)initPosX:(int)posX posY:(int)posY fontSize:(int)fontSize textColor:(NSUInteger)textColor dateFormat:(NSDateFormatter * _Nullable)dateFormat;

@end

/**
 * 初始化图片水印
 *
 * @param posX 相对于原点(左上角),X轴坐标(右为正数)
 * @param posY 相对于原点(左上角),Y轴坐标(下为正数)
 * @param filePath 图片路径
 */
- (instancetype)initPosX:(int)posX posY:(int)posY filePath:(NSString *)filePath;

/**
 * 初始化图片水印
 *
 * @param posX 相对于原点(左上角),X轴坐标(右为正数)
 * @param posY 相对于原点(左上角),Y轴坐标(下为正数)
 * @param image 图片对象
 */
- (instancetype)initPosX:(int)posX posY:(int)posY image:(UIImage *)image;

@end

示例代码:

// 打开摄像头
[_mediaDevice startCamera];
// 打开麦克风
[_mediaDevice startAudioInput];
JRTCRecordCaptureParam *param = [[JRTCRecordCaptureParam alloc] init];
param.filePath = @"/var/mobile/Containers/Data/Application/14D9F931-630F-43CE-A834-123D00A5651E/Documents/1.mp4";
param.audioSource = JRTCRecordAudioFromMicrophone;
param.fileType = JRTCVideoRecordFileMp4H264;
param.width = 640;
param.height = 360;
NSMutableArray *watermarkList = [NSMutableArray array];
JRTCRecordWatermarkText *text = [[JRTCRecordWatermarkText alloc] initPosX:10 posY:10 fontSize:30 textColor:0x00FF00FF text:@"测试水印"];
[watermarkList addObject:text];//文本水印
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss.SSS";
JRTCRecordWatermarkTimeStamp *timeStamp = [[JRTCRecordWatermarkTimeStamp alloc] initPosX:10 posY:100 fontSize:30 textColor:0x00FF00FF dateFormat:formatter];
[watermarkList addObject:timeStamp];//时间戳水印
JRTCRecordWatermarkImage *image = [[JRTCRecordWatermarkImage alloc] initPosX:300 posY:300 filePath:@"/var/mobile/Containers/Data/Application/14D9F931-630F-43CE-A834-123D00A5651E/Documents/icon.png"];
[watermarkList addObject:image];//图片水印
param.watermarkList = watermarkList;
// 开启本地视频录制
[_mediaDevice startVideoCaptureRecord:_mediaDevice.currentCamera.cameraId recordParam:param];
// 关闭本地视频录制
[_mediaDevice stopVideoCaptureRecord:_mediaDevice.currentCamera.cameraId];

// 开启本地音频录制
[_mediaDevice startAudioRecord:@"/var/mobile/Containers/Data/Application/14D9F931-630F-43CE-A834-123D00A5651E/Documents/1.wav" fileType:JRTCAudioRecordFilePcm fileType:JRTCAudioRecordFilePcm];
// 关闭本地音频录制
[_mediaDevice stopAudioRecord];

# 3. 远程录制

在线上金融的应用场景中,考虑取证、质检、审核、存档和回放等需求,常需要将整个视频通话过程录制,并存储。

Juphoon RTC SDK 的远程录制,通过会场服务将收到的所有终端数据发送给录制服务器,进行实时录制。在实际的集成中,当sdk初始化完成后,集成方通过加入会场的方式将需要进行录制的音视频流上传至服务器并进行实时录制。

# 开启远程录制

远程录制提供两个方法,enableRemoteRecord (opens new window)controlRecord (opens new window)

访客在发起呼叫或者座席回呼的时候可以携带 JRTCCallCenterCallParam.autoRecord (opens new window) 参数来设置是否在通话开始后就进行远程录制。如果该次通话没有设置自动远程录制,则可以通过终端来触发录制,在服务端形成通话过程的视频文件。录制的配置(如水印、时间戳等)与自动录制的相同,都来自系统管理平台后台的配置。

/**
 * 开启/关闭远程录制
 *
 * 当呼叫参数 {@link JRTCCallCenterCallParam.autoRecord autoRecord} == false 时,可通过此接口开启服务端录制。<br>
 * 可通过 {@link getRemoteRecordState} 接口获取当前服务器录制状态。
 * @param enable 开启或关闭远程录制
 * - true: 开启视频录制
 * - false: 关闭视频录制
 * @param recordParam 录制参数,当 enable == false 时,可传 nil;当 enable == true 且按照默认配置进行录制可传 nil
 * @return 接口调用结果
 * - true: 接口调用成功,录制状态通过 {@link JRTCAgentCallback.onCallPropertyChanged: onCallPropertyChanged} 回调获得,具体可关注 {@link JRTCRoomPropChangeParam.recordState recordState}
 * - false: 接口调用异常
 */
- (bool)enableRemoteRecord:(bool)enable recordParam:(JRTCRecordRemoteParam *)recordParam;

/**
 * 获取远程视频录制状态,参见:
 * - @ref RecordStateNone : 无法进行视频录制。用户不在房间中或者加入房间时没有设置视频录制参数
 * - @ref RecordStateReady : 可以开启视频录制。用户在加入房间时设置了录制参数,并且没有在录制视频
 * - @ref RecordStateRunning : 视频录制中。用户在加入房间时设置了录制参数,并且正在视频录制中
 */
- (RecordState)getRemoteRecordState;

通话属性改变详见 JRTCRoomPropChangeParam (opens new window) ,录制状态具体可关注 getRemoteRecordState (opens new window)

录制状态改变通过 onCallPropertyChanged (opens new window) 回调通知到坐席。

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

通话属性改变详见 JRTCRoomPropChangeParam (opens new window) ,录制状态具体可关注 getRemoteRecordState (opens new window) 。 示例代码:

JRTCRecordRemoteParam *recordRemoteParam = [JRTCRecordRemoteParam new];
recordRemoteParam.recordVideo = true;
...
// 开启远程录制
[_agent enableRemoteRecord:true recordParam:recordRemoteParam];

// 关闭远程录制
[_agent enableRemoteRecord:false recordParam:recordRemoteParam];

// 获取录制状态
[_agent getRemoteRecordState];


- (void)onCallPropertyChanged:(JRTCRoomPropChangeParam *)changeParam {
    if (changeParam.remoteRecordState) {
        if ([_agent getRemoteRecordState] == RecordStateRunning) {
            //当前正在远程录制
        }
    }
}

# 远程录制接口二

通过 controlRecord (opens new window) 开始和停止远程视频录制。

/**
 * 开启/关闭远程录制
 *
 * 仅在 @ref isAutoRecord == false 时调用接口有效,即访客发起呼叫时,呼叫参数 {@link JRTCCallCenterCallParam.autoRecord} 需要为 false 。<br>
 * 由服务器自动开启远程录制,即 isAutoRecord == true 时,水印内容由业务管理平台配置。<br>
 * 调用接口手动开启远程录制时,水印内容由参数 watermarkText 决定。
 * @param action 打开或停止录制
 * - @ref AgentRecordActionStart: 打开录制
 * - @ref AgentRecordActionStop: 停止录制
 * @param watermarkText 水印内容
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 */
- (bool)controlRecord:(AgentRecordAction)action watermarkText:(NSString *)watermarkText DEPRECATED_MSG_ATTRIBUTE("该方法即将废弃,请使用 controlRecord:recordParam: 替换");

/**
 * 开启/关闭远程录制
 *
 * 仅在 {@link #isAutoRecord} == false 时调用接口有效,即访客发起呼叫时,呼叫参数 {@link JRTCCallCenterCallParam#autoRecord} 需要为 false 。<br>
 * 由服务器自动开启远程录制,即 {@link #isAutoRecord} == true 时,水印内容由业务管理平台配置。<br>
 * 调用接口手动开启远程录制时,水印内容由参数 recordParam.watermarkTextMap 决定。
 * @param action 打开或停止录制
 * - {@link JRTCCallCenter#AGENT_RECORD_ACTION_START AGENT_RECORD_ACTION_START} : 打开录制
 * - {@link JRTCCallCenter#AGENT_RECORD_ACTION_STOP AGENT_RECORD_ACTION_STOP} : 停止录制
 * @param recordParam 录制参数对象
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 */
- (bool)controlRecord:(AgentRecordAction)action recordParam:(JRTCRecordControlParam *)recordParam;

示例代码:

JRTCRecordControlParam *recordControlParam = [JRTCRecordControlParam new];
recordControlParam.extraInfo = @"1213";
recordControlParam.watermarkTextDic = @{@"key": @"value"};
[_agent controlRecord:AgentRecordActionStart recordParam:recordControlParam];

# 是否自动开启远程录制

通过 autoRecord (opens new window) 判断是否由服务器自动开启远程录制,自动录制开启不能手动控制开始/停止远程录制。

/**
 * 是否由服务器自动开启录制,默认为 true
 *
 * 例如当录制文件需要自定义水印时,此参数应设为 false,由座席手动调用 {@link JRTCAgent.controlRecord:watermarkText: controlRecord} 接口携带水印参数开启录制。
 */
@property (nonatomic, assign) bool autoRecord;

# 远程录制异常回调

详见 onDeliveryAbort (opens new window)

/**
 * 录制异常回调
 *
 * 远程录制异常退出时会上报此回调。
 * @param isShutDown 录制异常时服务器是否自动结束通话
 * - true: 自动结束通话
 * - false: 不自动结束通话
 * @param deliveryUserId 录制异常的用户ID
 * @param reason 录制异常的原因
 */
- (void)onDeliveryAbort:(bool)isShutDown deliveryUserId:(NSString *)deliveryUserId reason:(NSString *)reason;

# 水印

开启服务器音视频录制接口,支持配置文字水印,录制完成后视频保存于服务端。 Juphoon RTC SDK 支持以下三种画布水印设置:

  • 文字水印:使用一段文字信息作为水印,支持设置字体和字号。
  • 动态时间戳水印:使用当前时间戳作为水印,显示格式为“2021-03-18 14:30:35"。
  • 静态图片水印:使用图片作为水印。

# 注意事项

  • 其中自定义水印内容通过 JRTCRecordRemoteParam (opens new window) 对象的 watermarkTextDic 属性配置,服务端进行录制时将会把水印内容中的占位符替换成键值对中占位符对应 Key 的 Value 值。
/**
* 水印串
*/
@property (nonatomic, strong) NSDictionary<NSString*, NSString*> *watermarkTextDic;

# 添加、修改或删除水印

  • 文字水印,如要求水印内容需具备客户经理工号、姓名、地理位置、经纬度;则需要终端开启录制时通过 watermarkTextDic 设置: {"userInfo": "工号+姓名"} 、{"location":"地理位置"}、{"JWD": "经纬度"}这样的键值对;具体体现和系统管理平台端配置如下 ,红框内就是文字水印,支持在业务管理平台调整位置和字体颜色等,而$@xxx$@最终会替换成键xxx对应的值,如$@userInfo$@,替换成“工号+姓名”,$@location$@,替换成“地理位置”,$@JWD$@,替换成“经纬度”。
  • 图片水印,在业务管理平台支持配置图片水印,目前知支持 png 格式图片,可以自由调整位置。
  • 时间戳水印,在业务管理平台支持配置时间戳水印,可以自由调整位置,字体颜色、大小等。

具体体现和系统管理平台端配置如下: img

# 自定义布局

在系统管理平台端中的录制配置目录下,可以配置录制的一些参数,为了录制布局更加灵活,还提供了自定义布局,自定义布局可以配置每个录制流的位置和大小。 系统管理平台端默认使用的是智能分屏,如需切换自定义布局,在系统管理平台端修改如下: img

img 配置每个成员的布局位置和大小,配置完成后点保存: 图中的0,1表示每个窗口对应的窗口位置,后续需要用到。

img 以上就是系统管理平台端的配置,实现自定义布局还需要在代码中绑定对应的窗口位置,参考代码如下:

JRTCRecordRemoteParam *param = [JRTCRecordRemoteParam alloc] init];
param.fileName = @"test.mp4";
param.frameRate = 24;
param.iBitrate = 500;
// 设置录制合并模式为自定义布局模式
param.mergeMode = VideoMergeModeCustomLayout;
param.videoWidth = 640;
param.videoHeight = 360;
param.recordVideo = true;
param.layoutType = @"default";//设置录制样式,对应业务管理平台上录制配置中的编号ID, 不传则用默认
NSMutableArray *layoutList = [NSMutableArray array];
int window = 0; // windows表示窗口位置,需要事先在系统管理平台中配置完成
for (JRTCRoomParticipant *participant in self.room.participants) {
    JRTCRecordRemoteLayout *layout = [JRTCRecordRemoteLayout new];
    // 绑定成员的流
    [layout setId:participant.userId isUserId:YES];
    // 设置系统管理平台中对应的窗口位置
    [layout setPosition:windows];
    [layoutList addObject:layout];
    window ++;
}

if (self.room.shareStreamId && self.room.shareUserId.length > 0) {
    JRTCRecordRemoteLayout *layout = [JRTCRecordRemoteLayout new];
    [layout setId:self.room.shareStreamId isUserId:NO];
    [layout setPosition:windows];
    [layoutList addObject:layout];
}

// 开启远程录制
[_agent enableRemoteRecord:true recordParam:param];

# 更新远程录制自定义布局

如果需要在远程录制已经开启的情况下更改录制布局,使用场景:比如录制中有新成员加入,需要调整布局位置,可以使用如下接口,需要在远程录制进行中调用。详见:updateRemoteRecordLayout (opens new window)

/**
 * 更新远程录制自定义布局
 *
 * @param layoutList 需要更新的布局列表
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 */
-(bool)updateRemoteRecordLayout:(NSArray<JRTCRecordRemoteLayout *> *)layoutList;
/**
 * 更新远程录制自定义布局
 *
 * @param layoutList 需要更新的布局列表
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 */
-(bool)updateRemoteRecordLayout:(NSArray<JRTCRecordRemoteLayout *> *)layoutList;

示例代码:

JRTCRecordRemoteParam *param = [JRTCRecordRemoteParam new];
// ......远程录制参数设置
// 开启远程录制
[_agent enableRemoteRecord:true recordParam:param];
NSMutableArray *layoutArray = [NSMutableArray array];
JRTCRecordRemoteLayout *layout = [JRTCRecordRemoteLayout new];
[layout setPosition: 0];
[layout setId:@"成员用户ID" isUserId:true];
[layoutArray addObject:layout];
//......设置其他成员视频流或者屏幕共享流对应窗口位置
//更新录制自定义布局
bool result = [_agent updateRemoteRecordLayout:layoutArray];
// 关闭远程录制
[_agent enableRemoteRecord:false recordParam:nil];

# 更新远程录制水印信息

如果需要在远程录制已经开启的情况下更改水印信息,使用场景:比如录制中有成员离开,需要修改该成员原先位置水印标签(可能是用户名字),可以使用如下接口,需要在远程录制进行中调用。详见:updateRemoteRecordWatermark (opens new window)

/**
 * 更新远程录制水印信息
 *
 * @param watermarkTextDic 水印信息
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 */
- (bool)updateRemoteRecordWatermark:(NSDictionary * __nonnull)watermarkTextDic;

示例代码:

JRTCRecordRemoteParam *param = [JRTCRecordRemoteParam new];
NSDictionary *dic1 = @{"w1": "张三", "w2": "李四"};
param.watermarkTextDic = dic1;//初始水印
// ......远程录制参数设置
// 开启远程录制
[_agent enableRemoteRecord:true recordParam:param];
NSDictionary *dic2 = @{"w1": "李四", "w2": "王五"};//修改水印信息
bool result = [_agent updateRemoteRecordWatermark: dic2];////更改录制水印信息
//关闭远程录制
[_agent enableRemoteRecord:false recordParam:nil];