iOS

# 音视频录制

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

# 1. 本地录制

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

录制通话在本地生成视频文件。

调用下面的接口 enableLocalRecord (opens new window) 开启或关闭本地录制

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

/**
 * 是否正在本地录制
 *
 * @return 是否正在本地录制
 * - true: 正在本地录制中
 * - false: 未进行本地录制
 */
public abstract boolean isLocalRecording();

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

示例代码:

//开启本地录制
JRTCRecordLocalParam param = new JRTCRecordLocalParam();
param.setFilePath("/sdcard/1.mp4");//设置录制文件名称
param.setRecVideo(true);//录制包含视频
param.setRecAudio(true);//录制包含音频
param.setIncludeSelf(true);//录制包含自己
param.setFrameRate(24);
param.setMergeMode(JRTCEnum.VIDEO_MERGE_MODE_INTELLIGENT_LAYOUT);
param.setVideoWidth(640);//录制视频宽
param.setVideoHeight(360);//录制视频高
Map<String, String> watermarkTextMap map = new HashMap();
map.put("name", "我是占位符");// 会替换配置文件中 $@name@$ 占位符内容
param.setWatermarkTextMap(map);//设置水印
List<JRTCRecordLocalParam.RecordLayout> layoutList = new ArrayList();
JRTCRecordLocalParam.RecordLayout layout0 = new JRTCRecordLocalParam.RecordLayout();
//设置布局位置视频流标识
layout0.setId(agent.getParticipants().get(0).getUserId());//房间中其他成员用户ID
//layout0.setId(agent.getShareStreamId());//房间中屏幕共享视频流ID
//layout0.setId(mediaDevice.getScreenCaptureId());//屏幕采集视频流ID
//layout0.setId(mediaDevice.getOpenedCameras().get(0).cameraId);//本地摄像头视频流ID
layout0.setPosition(0);//设置布局位置为0
layoutList.add(layout0);
JRTCRecordLocalParam.RecordLayout layout1 = new JRTCRecordLocalParam.RecordLayout();
layout1.setId("streamId1");
layout1.setPosition(1);//设置布局位置为1
layoutList.add(layout1);
param.setLayoutList(layoutList);//设置录制成员布局列表,mergeMode 为自定义布局需要
param.setConfigFilePath("/sdcard/record.cfg");//本地录制配置配置路径
agent.enableLocalRecord(true, param);

//关闭本地录制
agent.enableLocalRecord(false, null);

更新本地录制自定义布局 updateLocalRecordLayout (opens new window),当本地录制已经在进行时,可以通过该接口实时更新本地录制布局

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

示例代码:

List<JRTCRecordLocalParam.RecordLayout> layoutList = new ArrayList();
JRTCRecordLocalParam.RecordLayout layout1 = new JRTCRecordLocalParam.RecordLayout();
layout1.setId("streamId0");
layout1.setPosition(0);
layoutList.add(layout1);

JRTCRecordLocalParam.RecordLayout layout2 = new JRTCRecordLocalParam.RecordLayout();
layout1.setId("streamId1");
layout1.setPosition(1);
layoutList.add(layout2);

agent.updateLocalRecordLayout(layoutList);

通过配置文件实现本地录制

流程图如下

img

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

{
 "default" : {   //录制配置类型, 固定值.
     "videoRecord" : {   //视频录制配置, 固定值.
          "layout" : [        //自定义布局,mergeMode 字段为自定义布局模式 {@link JRTCEnum#VIDEO_MERGE_MODE_CUSTOM_LAYOUT VIDEO_MERGE_MODE_CUSTOM_LAYOUT(4)} 时生效, JSON数组格式, 可同时设置多个, 实际应用时通过窗口号区分.
              {
                  "posX" : 0.25,                  //画面左上角的横坐标(双精度浮点数类型), 代表占画面总宽度的比例.
                  "posY" : 0.26805556000000003,   //画面左上角的纵坐标(双精度浮点数类型), 代表占画面总高度的比例.
                  "width" : 0.1140625,            //画面的宽度(双精度浮点数类型), 代表占画面总宽度的比例.
                  "height" : 0.47916666000000002, //画面的高度(双精度浮点数类型), 代表占画面总高度的比例.
                  "window" : 0                    //窗口号(大于或等于的整数), 在使用 {@link RecordLayout#setLayoutList(List) setLayoutList} 自定义视频窗口布局时需要, 对应于用户自定义的位置信息 {@link RecordLayout#setPosition(int)} setPosition} 设置布局位置.
              },
              {
                  "posX" : 0.49609375,            //画面左顶点的横坐标(双精度浮点数类型), 范围为[0, 1], 代表占画面总宽度的比例.
                  "posY" : 0.033333334999999999,  //画面左顶点的纵坐标(双精度浮点数类型), 范围为[0, 1], 代表占画面总高度的比例.
                  "width" : 0.36406250000000001,  //画面的宽度(双精度浮点数类型), 范围为[0, 1], 代表占画面总宽度的比例.
                  "height" : 0.94027775999999996, //画面的高度(双精度浮点数类型) 范围为[0, 1], 代表占画面总高度的比例.
                  "window" : 1                    //窗口号(大于或等于的整数), 在使用 {@link RecordLayout#setLayoutList(List) setLayoutList} 自定义视频窗口布局时需要, 对应于用户自定义的位置信息 {@link RecordLayout#setPosition(int)} setPosition} 设置布局位置.
              }
          ],
          "mergeBitrate" : 0, //设置录制视频的码率, 单位为千比特每秒(kbps), 默认值为0, 此时码率由内部媒体算法进行自适应调节
          "mergeFPS" : 30,    //设置录制视频的帧率, 单位为每秒传输帧数(fps), 默认值为20.
          "mergeWidth" : 1280,//设置录制视频的宽度, 默认值为 640
          "mergeHeight" : 720,//设置录制视频的高度, 默认值为 360
          "mergeMode" : 4,    //设置媒体推流的视频合并模式, 默认值为 {@link JRTCEnum#VIDEO_MERGE_MODE_INTELLIGENT_LAYOUT VIDEO_MERGE_MODE_INTELLIGENT_LAYOUT(5)}, 目前可支持自定义布局 {@link JRTCEnum#VIDEO_MERGE_MODE_CUSTOM_LAYOUT VIDEO_MERGE_MODE_CUSTOM_LAYOUT(4)} 和智能布局 {@link JRTCEnum#VIDEO_MERGE_MODE_INTELLIGENT_LAYOUT VIDEO_MERGE_MODE_INTELLIGENT_LAYOUT(5)}.
          "mergeModeI" : 1,   //设置智能分屏模式下的布局样式(无屏幕共享), 默认值为自由布局 {@link JRTCEnum#INTELLIGENT_MERGE_MODE_FREE_LAYOUT INTELLIGENT_MERGE_MODE_FREE_LAYOUT(1)}, 有效值参考 {@link JRTCEnum.IntelligentMergeMode 智能分屏模式下的布局样式(无屏幕共享)}, 本字段仅在 mergeMode 为智能布局 {@link JRTCEnum#VIDEO_MERGE_MODE_INTELLIGENT_LAYOUT VIDEO_MERGE_MODE_INTELLIGENT_LAYOUT(5)} 时生效.
          "screenShareType" : 1 //设置智能分屏模式下的布局样式(有屏幕共享), 默认值为屏幕共享独占 {@link JRTCEnum#SCS_MERGE_MODE_SCREEN_SHARE SCS_MERGE_MODE_SCREEN_SHARE(1)}, 有效值参考 {@link JRTCEnum.ScsMergeMode 智能分屏模式下的布局样式(有屏幕共享)}, 本字段仅在 mergeMode 为智能布局 {@link JRTCEnum#VIDEO_MERGE_MODE_INTELLIGENT_LAYOUT VIDEO_MERGE_MODE_INTELLIGENT_LAYOUT(5)} 时生效.
      },
      "watermark" : { //水印配置, 固定值.
          "picture" : [   //图片水印配置, 固定值, 图片水印目前只支持 png 格式.
              {
                  "enable" : true,    //是否启用(布尔类型).
                  "pcUrl" : "http://192.168.17.60:10042/protected_files/6afa960e-fe4a-49ae-a939-48c788122192?attname=juphoon.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 #setWatermarkTextMap(Map) setWatermarkTextMap} 设置的自定义文本水印信息获取其对应值, "$@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(String, int, int) startAudioRecord} 同时开启)
 * @param streamId      视频流ID, (包括摄像头ID、文件视频源ID、屏幕采集流ID等)
 * @param recordParam   录制参数
 * @see JRTCRecordVideoCaptureParam
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 */
public abstract boolean startVideoCaptureRecord(@NonNull String streamId, @NonNull JRTCRecordVideoCaptureParam recordParam);

/**
 * 关闭视频录制(本地录制,不需要建立通信)
 * @param streamId 视频流ID (包括摄像头ID、文件视频源ID、屏幕采集流ID等)
 * @return 关闭视频录制是否成功
 */
public abstract boolean stopVideoCaptureRecord(@NonNull String streamId);

/**
 * 开启音频录制(本地录制,不需要建立通信,不能和视频录制 {@link #startVideoCaptureRecord startVideoCaptureRecord} 同时开启)
 * @param filePath 保存的文件路径,必须包含文件名(xxx.wav或者xxx.pcm)
 * @param audioSource 录制文件音频源
 * @param fileType 录制文件编码封装类型
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 */
public abstract boolean startAudioRecord(@NonNull String filePath, @RecordAudioSource int audioSource, @AudioRecordFileType int fileType);

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

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

/**
 * 图片水印
 */
public static class Image extends JRTCRecordWatermark {
    /**
     * 图片水印构造方法
     *
     * @param posX 相对于原点(左上角),X轴坐标(右为正数)
     * @param posY 相对于原点(左上角),Y轴坐标(下为正数)
     * @param filePath 图片路径
     */
    public Image(int posX, int posY, String filePath);

    /**
     * 图片水印构造方法
     *
     * @param posX 相对于原点(左上角),X轴坐标(右为正数)
     * @param posY 相对于原点(左上角),Y轴坐标(下为正数)
     * @param bitmap 图片对象
     */
    public Image(int posX, int posY, Bitmap bitmap);
}
/**
 * 文字水印
 */
public static class Text extends JRTCRecordWatermark {
    /**
     * 文字水印构造方法
     *
     * @param posX 相对于原点(左上角),X轴坐标(右为正数)
     * @param posY 相对于原点(左上角),Y轴坐标(下为正数)
     * @param typeface  字体样式
     * @param textColor 字体颜色
     * @param textSize  字体大小
     * @param text      水印内容
     */
    public Text(int posX, int posY, Typeface typeface, @ColorInt int textColor, float textSize, String text);
}

/**
 * 时间戳水印
 */
public static class TimeStamp extends Text {
    /**
     * 时间戳水印构造方法
     *
     * @param posX 相对于原点(左上角),X轴坐标(右为正数)
     * @param posY 相对于原点(左上角),Y轴坐标(下为正数)
     * @param typeface   字体样式
     * @param textColor  字体颜色
     * @param textSize   字体大小
     * @param dateFormat 时间戳格式化参数
     */
    public TimeStamp(int posX, int posY, Typeface typeface, @ColorInt int textColor, int textSize, SimpleDateFormat dateFormat);
}

示例代码

// 打开摄像头
mediaDevice.startCamera();
// 打开麦克风
mediaDevice.startAudioInput();
JRTCRecordVideoCaptureParam captureParam = new JRTCRecordVideoCaptureParam();
captureParam.setFilePath("/sdcard/1.mp4");//设置录制文件路径
captureParam.setAudioSource(JRTCMediaDevice.RECORD_AUDIO_FROM_MICROPHONE);
captureParam.setFileType(JCMediaDevice.VIDEO_RECORD_FILE_MP4_H264);
captureParam.setWidth(640);
captureParam.setHeight(360);
List<JRTCRecordWatermark> watermarkList = new ArrayList<>();
JRTCRecordWatermark.Text textWatermark = new JRTCRecordWatermark.Text(10, 10, Typeface.DEFAULT, Color.BLACK, 30, "测试水印");
watermarkList.add(textWatermark); //文本水印
JRTCRecordWatermark.TimeStamp timeStampWatermark = new JRTCRecordWatermark.TimeStamp(10, 100, Typeface.DEFAULT, Color.BLACK, 30, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"));
watermarkList.add(timeStampWatermark); //时间戳水印
JRTCRecordWatermark.Image imageWatermark = new JRTCRecordWatermark.Image(300, 300, BitmapFactory.decodeFile("/sdcard/icon.png"));
watermarkList.add(imageWatermark);//图片水印
captureParam.setWatermarkList(watermarkList);
// 开启本地视频录制
mediaDevice.startVideoCaptureRecord(mediaDevice.getCurrentCamera().cameraId, captureParam);
// 关闭本地视频录制
mediaDevice.stopVideoCaptureRecord(mediaDevice.getCurrentCamera().cameraId);

// 开启本地音频录制
mediaDevice.startAudioRecord("/sdcard/1.wav",JRTCMediaDevice.AUDIO_RECORD_FILE_PCM);
// 关闭本地音频录制
mediaDevice.stopAudioRecord();

# 3. 远程录制

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

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

# 开启远程录制

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

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

# 远程录制接口一

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

/**
 * 获取远程视频录制状态
 *
 * @return 远程视频录制状态,详见 {@link JRTCEnum.RemoteRecordState}
 * - {@link JRTCEnum#RECORD_STATE_NONE RECORD_STATE_NONE} : 无法进行视频录制。用户不在频道中或者加入频道时没有设置视频录制参数
 * - {@link JRTCEnum#RECORD_STATE_READY RECORD_STATE_READY} : 可以开启视频录制。用户在加入频道时设置了录制参数,并且没有在录制视频
 * - {@link JRTCEnum#RECORD_STATE_RUNNING RECORD_STATE_RUNNING} : 视频录制中。用户在加入频道时设置了录制参数,并且正在视频录制中
 */
@JRTCEnum.RemoteRecordState
 public abstract int getRemoteRecordState();

远端录制参数详见 JRTCRecordRemoteParam (opens new window)

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

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

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

示例代码:

JRTCRecordRemoteParam param = new JRTCRecordRemoteParam();
param.setRecordVideo(true);
...
param.setwatermarkTextMap("{'guest':'juphoon001'}");
//开启远程录制
agent.enableRemoteRecord(true, param);
//关闭远程录制
agent.enableRemoteRecord(false, null);

// 获取远程视频录制状态
agent.getRemoteRecordState();

//远程录制状态发生改变
public void onCallPropertyChanged(JRTCRoom.PropChangeParam propChangeParam) {
    if (propChangeParam.recordState) {
        if (agent.getRemoteRecordState == JRTCEnum.RECORD_STATE_RUNNING) {
           //当前正在远程录制
        } 
    }
}

# 远程录制接口二

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

/**
 * 开始/停止远程录制(经过排队机)
 * <p>
 * 仅在 {@link #isAutoRecord} == false 时调用接口有效,即访客发起呼叫时,呼叫参数 {@link JRTCCallCenterCallParam#autoRecord} 需要为 false 。<br>
 * 由服务器自动开启远程录制,即 {@link #isAutoRecord} == true 时,水印内容由业务管理平台配置。<br>
 * 调用接口手动开启远程录制时,水印内容由参数 watermarkText 决定。
 *
 * @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: 接口调用异常
 */
public abstract boolean controlRecord(@AgentRecordAction int action, JRTCRecordControlParam recordParam);

示例代码:

JRTCRecordControlParam param = new JRTCRecordControlParam();
param.watermarkTextMap = new HashMap<String, String>();
param.watermarkTextMap.put("key1", "水印内容");
param.watermarkTextMap.put("key2", "水印内容");
param.extraInfo = "";
boolean result = agent.controlRecord(param.action, param);

# 是否自动开启远程录制

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

/**
 * 是否由服务器自动开启录制
 * <p>
 * 由访客 {@link JRTCCallCenterCallParam#autoRecord autoRecord} 属性决定,在通话状态为 {@link JRTCCallCenter#CALL_STATE_TALKING CALL_STATE_TALKING} 时可以获取 <br>
 * 如果当前为自动录制模式,即 isAutoRecord == true,则座席的 {@link #controlRecord} 远程录制接口不生效
 */
public abstract boolean isAutoRecord();

# 远程录制异常回调

详见 onDeliveryAbort (opens new window)

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

# 水印

开启服务器音视频录制接口,支持配置文字水印,录制完成后视频保存于服务端。

Juphoon RTC SDK 支持以下三种画布水印设置:

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

# 注意事项

public void setWatermarkTextMap(Map<String, String> watermarkTextMap);

# 添加、修改或删除水印

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

img

# 自定义布局

在系统管理平台端中的录制配置目录下,可以配置录制的一些参数,为了录制布局更加灵活,还提供了自定义布局,自定义布局可以配置每个录制流的位置和大小。

系统管理平台端默认使用的是智能分屏,如需切换自定义布局,在系统管理平台端修改如下:

img

img

配置每个成员的布局位置和大小,配置完成后点保存:

图中的0,1表示每个窗口对应的窗口位置,终端开启远程录制绑定视频流和窗口位置需要用到。

img

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

使用 enableRemoteRecord (opens new window) 示例代码:

JRTCRecordRemoteParam param = new JRTCRecordRemoteParam();
param.setFrameRate(24);
param.setIBitrate(500);
// 设置录制合并模式为自定义布局模式
param.setMergeMode(VIDEO_MERGE_MODE_CUSTOM_LAYOUT);
param.setVideoWidth(640);
param.setvVideoHeight(360);
param.setRecordVideo(true);
param.layoutType = "default";//设置录制样式,对应业务管理平台上录制配置中的编号ID, 不传则用默认
List<JRTCRecordRemoteParam.RecordLayout> layoutList = new ArrayList<>();
int window = 0; // windows表示窗口id,需要事先在系统管理平台中配置完成
for (JRTCRoomParticipant participant : mGuest.getParticipants()) {
    JRTCRecordRemoteParam.RecordLayout layout = new JRTCRecordRemoteParam.RecordLayout();
    // 绑定成员的流
    layout.setId(participant.get(0).getUserId(), true);
    // 设置系统管理平台中对应的窗口位置
    layout.setPosition(window);
    layoutList.add(layout);
    window++;
}

// 判断通话中是否有屏幕共享存在
if (!TextUtils.isEmpty(mGuest.getShareUserId())) {
    JRTCRecordRemoteParam.RecordLayout layout = new JRTCRecordRemoteParam.RecordLayout();
    // 绑定屏幕共享的流
    layout.setId(mGuest.getShareStreamId(), false);
    // 绑定系统管理平台中对应的窗口位置
    layout.setPosition(windows);
    layoutList.add(layout);
}

// 开启远程录制
agent.enableRemoteRecord(true, param);

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

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

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

示例代码:

JRTCRecordRemoteParam param = new JRTCRecordRemoteParam();
// ......远程录制参数设置
// 开启远程录制
agent.enableRemoteRecord(true, param);
List<JRTCRecordRemoteParam.RecordLayout> layoutList = new ArrayList<>();
JRTCRecordRemoteParam.RecordLayout layout = new JRTCRecordRemoteParam.RecordLayout();
layout.setId("成员用户ID", true);
// 设置系统管理平台中对应的窗口位置
layout.setPosition(0);
layoutList.add(layout);
//......设置其他成员视频流或者屏幕共享流对应窗口位置
//更新录制自定义布局
boolean result = agent.updateRemoteRecordLayout(layoutList);
// 关闭远程录制
agent.enableRemoteRecord(false, null);

# 更新远程录制水印信息

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

/**
 * 更新远程录制水印信息
 *
 * @param watermarkTextMap 水印信息
 * @return 接口调用结果
 * - true: 接口调用成功
 * - false: 接口调用异常
 */
public abstract boolean updateRemoteRecordWatermark(Map<String, String> watermarkTextMap);

示例代码:

JRTCRecordRemoteParam param = new JRTCRecordRemoteParam();
Map<String, String> watermarkTextMap1 = new HashMap<String, String>();
watermarkTextMap1.put("w1", "张三");
watermarkTextMap1.put("w2", "李四");
param.setWatermarkTextMap(watermarkTextMap1);//初始水印
// ......远程录制参数设置
// 开启远程录制
agent.enableRemoteRecord(true, param);
Map<String, String> watermarkTextMap2 = new HashMap<String, String>();
watermarkTextMap2.put("w1", "李四");//修改水印信息
watermarkTextMap2.put("w2", "王五");//修改水印信息
boolean result = agent.updateRemoteRecordWatermark(watermarkTextMap2);//更改录制水印信息
// 关闭远程录制
agent.enableRemoteRecord(false, null);