iOS

# 音视频录制

# 1. 本地音视频录制

# 配置本地音视频录制及回调

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

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

this.localRecordConfig = {
		"BridgeType": "EnableLocalRecord",
		"Enable": true,
		"SelfRecord": true,
		"FileName": "",
    "FilePath": "",
		"WatermarkText": "", // {"name":"-我是占位符","name1":"-我是占位符1"}
		// 自定义布局时需要填写布局列表和录制配置文件。
		"LayoutList": "", // [{"Window":2,"Source":"camera"},{"Window":0,"Source":"screen"},{"Window":1,"Source":"user"}]
		// 录制配置,json
		"RecordConfig": "",
		// 当填写了录制配置(json)之后,以下参数将不会生效,将根据配置json中的配置生效。
		"Fps": 15,
		"BitRate": 500,
		"ResolutionWidth": "800",
		"ResolutionHeight": "600",
	}

公共必填参数:

BridgeType :命令 type

Enable :开始/结束录制

SelfRecord :是否录制自己,录制的文件中是否包含自己的画面

FileName :文件名 ,录制保存的文件名称如 12345.mp4,不填默认为日期时分秒;

FilePath :文件路径,Windows默认路径“我的电脑/文档/juphoon/appname/record”,UOS&Kylin默认路径“home\juphoon\appname\record”;

自定义布局时,需要填写以下参数:

WatermarkText :水印按照格式显示水印,需要配置文件正确才可以显示水印;

LayoutList :成员布局,按照示例的格式设置录制文件中成员的位置,“camera”表示本地画面的位置,“screen”表示屏幕共享画面位置,“user”表示通话其他成员的画面位置。需要配置文件正确才可以调用本地录制成功;

RecordConfig :配置文件配置关于水印信息格式相关,自定义成员布局相关。设置了水印或者自定义成员布局必填;

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

【字段含义】表明录制配置文件路径的关键字(文件路径需包含文件名, 在 JSON 格式中对应值是字符串类型)。

【特别说明】注释版本示例配置和无注释版本示例配置如下, 实际使用时请参考无注释版本示例配置以免注释部分导致 JSON 解析错误。

注释版本示例配置:

{
   "default" : {   //录制配置类型, 固定值.
       "videoRecord" : {   //视频录制配置, 固定值.
            "layout" : [        //自定义布局,mergeMode字段为自定义布局模式(MTC_ROOM_COMPOSITE_MODE_LAYOUT)时生效, JSON数组格式, 可同时设置多个, 实际应用时通过窗口号区分.
                {
                    "posX" : 0.25,                  //画面左上角的横坐标(双精度浮点数类型), 代表占画面总宽度的比例.
                    "posY" : 0.26805556000000003,   //画面左上角的纵坐标(双精度浮点数类型), 代表占画面总高度的比例.
                    "width" : 0.1140625,            //画面的宽度(双精度浮点数类型), 代表占画面总宽度的比例.
                    "height" : 0.47916666000000002, //画面的高度(双精度浮点数类型), 代表占画面总高度的比例.
                    "window" : 0                    //窗口号(大于或等于的整数), 布局唯一标识, 对应于用户自定义的位置信息(MtcRoomRecUserPositionKey)设置的窗口号(MtcRoomWindowKey).
                },
                {
                    "posX" : 0.49609375,            //画面左顶点的横坐标(双精度浮点数类型), 范围为[0, 1], 代表占画面总宽度的比例.
                    "posY" : 0.033333334999999999,  //画面左顶点的纵坐标(双精度浮点数类型), 范围为[0, 1], 代表占画面总高度的比例.
                    "width" : 0.36406250000000001,  //画面的宽度(双精度浮点数类型), 范围为[0, 1], 代表占画面总宽度的比例.
                    "height" : 0.94027775999999996, //画面的高度(双精度浮点数类型) 范围为[0, 1], 代表占画面总高度的比例.
                    "window" : 1                    //窗口号(大于或等于的整数), 布局唯一标识, 对应于用户自定义的位置信息(MtcRoomRecUserPositionKey)设置的窗口号(MtcRoomWindowKey).
                }
            ],
            "mergeBitrate" : 0, //设置录制视频的码率, 单位为千比特每秒(kbps), 默认值为0, 此时码率由内部媒体算法进行自适应调节, 本字段仅在mergeMode为自定义布局(MTC_ROOM_COMPOSITE_MODE_LAYOUT)或智能布局(MTC_ROOM_COMPOSITE_MODE_INTELLEGENCE)时生效.
            "mergeFPS" : 30,    //设置录制视频的帧率, 单位为每秒传输帧数(fps), 默认值为20.
            "mergeWidth" : 1280,//设置录制视频的宽度, 默认值为640, 本字段仅在mergeMode为自定义布局(MTC_ROOM_COMPOSITE_MODE_LAYOUT)或智能布局(MTC_ROOM_COMPOSITE_MODE_INTELLEGENCE)时生效.
            "mergeHeight" : 720,//设置录制视频的高度, 默认值为360, 本字段仅在mergeMode为自定义布局(MTC_ROOM_COMPOSITE_MODE_LAYOUT)或智能布局(MTC_ROOM_COMPOSITE_MODE_INTELLEGENCE)时生效.
            "videoLevel" : 768, //设置视频质量等级, 视频等级越高录制视频的分辨率越高, 默认值为 MTC_ROOM_PS_LARGE, 有效值参考 房间图像尺寸.
            "mergeMode" : 4,    //设置录制视频的布局模式, 默认值为 MTC_ROOM_COMPOSITE_MODE_INTELLEGENCE, 目前可支持自定义布局(MTC_ROOM_COMPOSITE_MODE_LAYOUT)和智能布局(MTC_ROOM_COMPOSITE_MODE_INTELLEGENCE), 其他模式已弃用.
            "mergeModeI" : 1,   //设置智能布局普通视频模式, 默认值为 MTC_ROOM_COMPOSITE_MODE_FREE_LAYOUT_I, 有效值参考 智能布局普通视频模式, 本字段仅在mergeMode为智能布局(MTC_ROOM_COMPOSITE_MODE_INTELLEGENCE)时生效.
            "screenShareType" : 1 //设置智能布局屏幕共享模式, 默认值为 MTC_ROOM_COMPOSITE_SCREENSHARE_I, 有效值参考 智能布局屏幕共享模式, 本字段仅在mergeMode为智能布局(MTC_ROOM_COMPOSITE_MODE_INTELLEGENCE)时生效.
        },
        "watermark" : { //水印配置, 固定值.
            "picture" : [   //图片水印配置, 固定值, 图片水印目前只支持png格式.
                {
                    "enable" : true,    //是否启用(布尔类型).
                    "pcUrl" : "http://192.168.17.60:10042/protected_files/6afa960e-fe4a-49ae-a939-48c788122192?attname=juphoon.png",    //图片水印链接地址.
                    "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", 通过解析用户自定义的文本水印信息(MtcRoomRecWatermarkTextKey)获取其对应值, "$@name@$"格式的内容被其对应值替换后就是实际应用的event字符串, "$@xxx@$"格式的内容支持同时设置多个.
                ],
                "style" : {         //文本水印格式, 固定值.
                    "enable" : true,        //格式是否启用(布尔类型).
                    "alignment" : 0,        //对齐方式, 有效值参考 EN_MTC_ROOM_OSD_ALIGNMENT_TYPE.
                    "backColor" : 16777215, //背景颜色(整数类型), 10进制颜色代码.
                    "blod" : false,         //是否使用粗体(布尔类型).
                    "fontColor" : 16777215, //字体颜色(整数类型), 10进制颜色代码.
                    "fontFile" : "SourceHanSansCN-Normal.otf",//字体文件名(字符串类型).
                    "fontSize" : 36,        //字体尺寸(整数类型).
                    "italic" : true,        //是否使用斜体(布尔类型).
                    "underline" : false     //是否带有下划线(布尔类型).
                }
            },
            "timestamp" : { //时间戳水印配置, 固定值.
                "enable" : true,    //是否启用(布尔类型).
                "basePosType" : 0,  //水印基准位置类型(整数类型), 有效值参考 EN_MTC_ROOM_TTS_BASE_POSTIOS_TYPE.
                "borderWidth" : 2,  //字体边界宽度(整数类型), 取值范围为[0, 5].
                "fontFile" : "SourceHanSansCN-Normal.otf",//字体文件名(字符串类型).
                "fontColor" : 0, //字体颜色(整数类型), 有效值参考 EN_MTC_ROOM_TTS_COLOR_TYPE.
                "fontSize" : 36,    //字体尺寸(整数类型).
                "isMs" : true,      //是否显示毫秒值(布尔类型).
                "posX" : 0,         //相对于基准位置的水平偏移值(整数类型), 负值向左偏移, 正值向右偏移, 实际大小非比例值.
                "posY" : 0          //相对于基准位置的垂直偏移值(整数类型), 负值向上偏移, 正值向下偏移, 实际大小非比例值.
            }
        }
    }
 }

无注释版本示例配置:

 {
    "default" : {
        "videoRecord" : {
            "layout" : [
                {
                    "posX" : 0.25,
                    "posY" : 0.26805556000000003,
                    "width" : 0.1140625,
                    "height" : 0.47916666000000002,
                    "window" : 0
                },
                {
                    "posX" : 0.49609375,
                    "posY" : 0.033333334999999999,
                    "width" : 0.36406250000000001,
                    "height" : 0.94027775999999996,
                    "window" : 1
                }
            ],
            "mergeBitrate" : 0,
            "mergeFPS" : 30,
            "mergeWidth" : 1280,
            "mergeHeight" : 720,
            "videoLevel" : 768,
            "mergeMode" : 4,
            "mergeModeI" : 1,
            "screenShareType" : 1
        },
        "watermark" : {
            "picture" : [
                {
                    "enable" : true,
                    "pcUrl" : "http://192.168.17.60:10042/protected_files/6afa960e-fe4a-49ae-a939-48c788122192?attname=juphoon.png",
                    "posX" : 0,
                    "posY" : 600
                }
            ],
            "text" : {
                "enable" : true,
                "memo" : [
                    "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"
                ],
                "style" : {
                    "enable" : true,
                    "alignment" : 0,
                    "backColor" : 16777215,
                    "blod" : false,
                    "fontColor" : 16777215,
                    "fontFile" : "SourceHanSansCN-Normal.otf",
                    "fontSize" : 36,
                    "italic" : true,
                    "underline" : false
                }
            },
            "timestamp" : {
                "enable" : true,
                "basePosType" : 0,
                "borderWidth" : 2,
                "fontFile" : "SourceHanSansCN-Normal.otf",
                "fontColor" : 0,
                "fontSize" : 36,
                "isMs" : true,
                "posX" : 0,
                "posY" : 0
            }
        }
    }
 }

当不填写配置文件、布局列表、水印时,将会自动设置为智能布局,此时以下参数必填:

Fps :录制帧率 ,影响录制文件的帧速率

BitRate :码率,录制码率

ResolutionWidth :录制分辨率宽,视频宽

ResolutionHeight :录制分辨率高,视频高

示例代码:

var webPlugin = new WebPlugin();

/**
  * @desc 开启/关闭本地录制
  * @param {boolean} enable true开启,false关闭
  * @interface EnableLocalRecord
  */
webPlugin.EnableLocalRecord(false);

获取本地录制结果通知:

var webPlugin = new WebPlugin();

webPlugin.OnEnableLocalRecordResult = function (start, result, reason) {
  console.log('OnEnableLocalRecordResult', start, result, reason);
  var span = document.getElementById('local-record-span')
  if (start && result) {
    span.innerHTML = '关闭本地录制'
    SDK_STATE.enableLocalRecord = true;
  } else {
    span.innerHTML = '打开本地录制'
    SDK_STATE.enableLocalRecord = false;
  }
}

# 获取会议内录制配置及回调

示例代码:

var webPlugin = new WebPlugin();

/**
	* @desc 获取会议内本地录制配置
	* @interface GetLocalRecordConfig
	*/
webPlugin.GetLocalRecordConfig();

获取会议内录制配置结果通知:

var webPlugin = new WebPlugin();

/**
  * @desc 获取会议内录制配置
  * @param {String} config 配置json
  */
webPlugin.OnGetLocalRecordConfig = function(config) {
  console.log('OnGetLocalRecordConfig', config);
}

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

不需要建立通信的本地录制可以在 SDK 初始化之后随时随地的开始或者结束录制,可以录制桌面或者摄像头,可以操作录制之后的文件回放或、删除、上传等等。录制信息等数据将会存储在本地数据库中。方便了多种多样的录制业务实现。

# 本地录制(不需要建立通信)水印

可设置字体、文字、时间戳、图片、水印位置等。

# 开启水印

想要录制的文件有水印,需要开启录制前设置好参数。

var webPlugin = new WebPlugin();

	/**
	 * @desc 本地录制开启/关闭水印,非通话中,请使用 #SetCameraWatermark 替换
	 *
	 * @param {Boolean} enable
	 * - true  开启
	 * - false 关闭
	 * @param {Array} content 水印信息列表,水印信息包含字段如下:
	 * - Type {String} 水印类型,可填 text:文字水印;timestamp:时间戳水印;picture:图片水印
	 * - Text {String} 文字水印字符串
	 * - Picture {String} 图片本地路径
	 * - PosX {String} 相对于原点(左上角),X轴坐标(右为正数)
	 * - PosY {String} 相对于原点(左上角),Y轴坐标(下为正数)
	 * @param {String} font 字体路径
	 * @param {Number} fontSize 水印文字大小
	 * @param {Number} fontColor 水印文字颜色
	 * - 0 红色
	 * - 1 黄色
	 * - 2 绿色
	 * - 3 青色
	 * - 4 蓝色
	 * - 5 洋红
	 * - 6 白色
	 * - 7 黑色
	 */
function EnableWatermark(enable, fontSize, fontColor, fontPath, enableText, textPosX, textPosY, content,
                         enableTimestamp, timestampPosX, timestampPosY, enablePicture, picturePosX, picturePosY, picturePath) {
  var contentList = [];
  if (enable) {
    if (enableText) {
      var content1 = {};
      content1.Type = 'text'
      content1.Text = content;
      content1.PosX = textPosX;
      content1.PosY = textPosY;
      content1.Picture = '';
      contentList.push(content1);
    }
    if (enablePicture) {
      var content2 = {};
      content2.Type = 'picture'
      content2.Text = '';
      content2.Picture = picturePath;
      content2.PosX = picturePosX;
      content2.PosY = picturePosY;
      contentList.push(content2)
    }
    if (enableTimestamp) {
      var content3 = {};
      content3.Type = 'timestamp'
      content3.Text = '';
      content3.Picture = "";
      content3.PosX = timestampPosX;
      content3.PosY = timestampPosY;
      contentList.push(content3)
    }
  }
  webPlugin .EnableWatermark(enable, contentList, fontPath, fontSize, fontColor);
}

# 开启/关闭视频窗口

摄像头窗口,和通话窗口共用。

var webPlugin = new  WebPlugin();

function ShowVideoWindow(show) {
	webPlugin .ShowVideoWindow(show);
}

# 采集

可设置采集的分辨率、帧率、采集要不要留有黑边。采集分辨率默认16/9的视频尺寸,如果设置有黑边会在采集到的画面上下增加黑边,增加完黑白的视频宽高比为1.5。

# 采集设置

var webPlugin = new  WebPlugin();

function SetCaptureProperty() {
	var resolution = _getValueNum('select-capture-resolution');
	var fr = _getValueNum('input-capture-fr');
	console.log(resolution, fr);
	webPlugin.SetCaptureProperty(resolution, fr);
}

# 视频窗口

可设置视频界面的渲染模式。我们选择FULL_SCREEN可以将视频窗口的黑边隐藏。主要参数:VideoWindowConfig.RenderType

# 设置视频窗口

var webPlugin = new  WebPlugin();

function SetRenderUIConfig() {
	var value = _getValue("select-render-type");
	console.log("RenderType:" + value);
	webPlugin.uiConfig.VideoWindowConfig.RenderType = value;
	webPlugin.SetUIConfig();
}

# 本地录制

可以设置录制分辨率,决定录制的范围。

# 数据库设计

录制表:Record

/**
 * 自增id
 */
private String id;
/**
 * 录制类型
 */
private String streamType;
/**
 * Appkey
 */
private String appkey;
/**
 * 服务器地址
 */
private String server;
/**
 * streamId(流水号)
 */
private String serialId;
/**
 * callId
 */
private String callId;
/**
 * 订单号
 */
private String orderId;
/**
 * 额外信息
 */
private String extraInfo;
/**
 * 文件名
 */
private String fileName;
/**
 * 文件路径
 */
private String filePath;
/**
 * 文件状态
 */
private int fileState;
/**
 * 文件大小(字节)
 */
private int fileSize;
/**
 * 文件唯一id
 */
private String fileUid;
/**
 * 上传数据大小(字节)。
 */
private int transferSize;
/**
 * 创建日期
 */
private String date;
/**
 * 上传回调地址,即上传地址
 */
private String url;
/**
 * 开始录制时间(时间戳)
 */
private long startRecordTime;
/**
 * 结束录制时间(时间戳)
 */
private long stopRecordTime;
/**
 * 是否分片录制 0 - 正常录制 ;1 - 分片录制
 */
private int sliceRecord;
/**
 * 是否已确认上传
 */
private int confirmState;

配置表:Config

/**
* 自增id
*/
private String id;

/**
* 名称
*/
private String key;

/**
* 值
*/
private String value;

# 开启/关闭录制

var webPlugin = new  WebPlugin();

function localRecord() {
	if (SDK_STATE.enableLocalRecord) {
		alertDialog('结束录制', '是否结束录制?', function() {
			webPlugin.EnableLocalRecord(false);
		});
	} else {
		console.log("EnableLocalRecord-true")
		webPlugin.EnableLocalRecord(true);
	}
}

# 开启/关闭录制(不需要建立通信)

var webPlugin = new  WebPlugin();

/**
 * @desc 开启本地视频录制,不需要建立通信
 *
 * @param {String} appKey - (可选)不填则使用内部appKey
 * @param {String} server - 文件上传服务器
 * @param {String} serialId - (可选)流水号,后续可以进行设置
 * @param {String} orderId - (可选)订单号,后续可以进行设置
 * @param {String} videoSource - Desktop 录制桌面  Camera 摄像头
 * @param {String} videoEncode -设置视频录制编码格式,--H264(默认),AV1
 * @param {Number} splitInterval -设置分片录制单个文件录制时长,单位秒,<=0 不分片录制,默认不分片录制
 * @param {Object} extraInfo 随路参数
 */
function setRecordState(open) {
  if (open) {
    var appkey = _getValue('checkin-appkey');
    var value = _getValue('checkin-server');
    var start = value.indexOf('(');
    var end = value.indexOf(')');
    var server = value.substring(start + 1, end);
    var serialId = _getValue('input-serialId');
    var orderId = _getValue('input-orderId');
    var selectDOM = document.getElementById('select-record-video-source');
    var videoSource = selectDOM.options[selectDOM.selectedIndex].value;
    var videoEncode = _getValueText("select-record-video-encode");
    var splitInterval = _getValueNum("input-split-time");
    webPlugin.StartRecord(appkey, server, serialId, orderId, videoSource,videoEncode,splitInterval,"");
  } else {
    webPlugin.StopRecord(true);
  }
}

# 设置录制信息

不设置为空,设置后当前录制生效。serialId,orderId为必填参数。否则录制为异常文件,可能会上传失败。

var webPlugin = new  WebPlugin();

function setRecordInfo() {
	var serialId = _getValue('input-serialId');
	var extrainfo = _getValue('input-extrainfo');
	var orderId = _getValue('input-orderId');
	webPlugin.setRecordInfo(serialId, extrainfo, orderId);
}

# 设置录制配置

不设置会有默认值,每次设置当前录制生效

参数解释:

@param {String} fileDir - (可选) 录制文件存储路径,不填则默认位置
@param {Number} limitUploadSpeed - (可选) 上传限速,默认10000kb,可选,不填则不更新
@param {Boolean} encrypt 是否加密 true加密录制文件,false不加密录制文件
@param {Number} resolution 分辨率 -13604807201080;默认-1
@param {String} uploadMode - 文件上传模式 --full 完整模式(默认,老的upload模式),split 切片模式-可选,不填则不更新
@param {Number} timeout  - 文件上传超时时间,单位s,初始超时时间300s
@param {Boolean} autoSyncStorage   - 自动同步存储平台(切片文件上传默认true,自动提交存储)false时需调用confirmUpload接口确认上传
@param {Number} uploadFailCount  - (可选)切片文件上传连续失败次数(默认-1,小于等于0时根据文件上传超时时间超时后判定文件上传失败,否则根据切片文件上传失败次数判定文件上传失败)
@param {Number} uploadFailIntervalTime  - (可选)文件上传失败后上传下一个文件的间隔时间(单位s,初始间隔时间300s)

示例代码:

var webPlugin = new  WebPlugin();

function setRecordConfig() {
	var recordDir = _getValue('input-recorddir');
	var limitSpeed = _getValueNum('input-limitspeed');
	var encrypt = _getCheckboxValue('encrypt-check');
	var selectDOM = document.getElementById('select-record-resolution');
  var timeout = _getValueNum('input-upload-timeout');
  var uploadMode = _getValue('input-upload-mode');
  var autoSyncPortal = _getCheckboxValue('auto-sync-check');
	var resolution = selectDOM.options[selectDOM.selectedIndex].value
	webAgent.SetRecordConfig(recordDir, limitSpeed, encrypt, resolution, uploadMode, timeout, autoSyncPortal, 0, 0);
}

# 获取配置/获取配置回调

var webPlugin = new  WebPlugin();

function getRecordConfig() {
	webPlugin .GetRecordConfig();
}

webPlugin.OnGetRecordConfigResult = function(fileDir, limitUploadSpeed) {
	textarea.bespokeLocalRecord.innerHTML = textarea.bespokeLocalRecord.value +
		"&#10;OnGetRecordConfigResult&#10;" +
		"fileDir:" + fileDir + "; limitUploadSpeed:" + limitUploadSpeed;
}

# 获得运行信息

var webPlugin = new  WebPlugin();

function getRecordRunningInfo() {
	webPlugin.GetRecordRunningInfo();
}

# 获得运行信息结果/运行信息变化通知

var webPlugin = new  WebPlugin();

webPlugin.OnGetRecordRunningInfoResult = function(uploadingFileCount, totalFileCount, pendingFileCount,
	failedFileCount) {
	textarea.bespokeLocalRecord.innerHTML = textarea.bespokeLocalRecord.value +
		"&#10;OnGetRecordRunningInfoResult&#10;" +
		"总文件数:" + totalFileCount + "; 当前正在上传的文件数:" + uploadingFileCount +
		"; 待上传文件数: " + pendingFileCount + "; 失败文件数:" + failedFileCount;
}

# 运行信息结果/运行信息变化上报

var webPlugin = new  WebPlugin();

webAgent.OnRecordRunningInfoNotify = function(uploadingFileCount, totalFileCount, pendingFileCount, failedFileCount) {
	textarea.bespokeLocalRecord.innerHTML = textarea.bespokeLocalRecord.value +
		"&#10;OnRecordRunningInfoNotify&#10;" +
		"总文件数:" + totalFileCount + "; 当前正在上传的文件数:" + uploadingFileCount +
		"; 待上传文件数: " + pendingFileCount + "; 失败文件数:" + failedFileCount;
}

# 打开录制记录窗口

SDK 初始化之后可展示,此界面用于管理录制文件和录制业务。可手动操作回放、上传等。在这个界面勾选并上传后,关闭界面会在后台继续上传,关闭插件重新打开再次勾选上传时会从上次继续上传,也就是断点续传。

img

var webPlugin = new  WebPlugin();

function showUploadUI(show) {
	var orderIdTxt = _getValue('input-search-orderIds');
	var orderIds = new Array();
	if (orderIdTxt != "") {
		orderIds = orderIdTxt.split(",");
	}
	var serialId = _getValue('input-search-serialId');
	var fileState = _getValue('select-search-sate');
	var date = _getValue('input-search-date');
	var play = _getValue('select-play');
	var isPlay = true;
	if (play == "2") {
		isPlay = false;
	}
	console.log(show, orderIds, serialId, fileState, date, isPlay)
	webPlugin.ShowRecordHistoryWindow(show, orderIds, serialId, parseInt(fileState), date, isPlay);
}

# 搜索录制记录(db)

var webPlugin = new  WebPlugin();

function searchRecordData() {
	var orderIdTxt = _getValue('input-search-orderIds');
	var orderIds = new Array();
	if (orderIdTxt != "") {
		orderIds = orderIdTxt.split(",");
	}
	var serialId = _getValue('input-search-serialId');
	var fileState = _getValue('select-search-sate');
	var date = _getValue('input-search-date');
	console.log(orderIds, serialId, fileState, date)
	webPlugin.SearchRecordData(orderIds, serialId, parseInt(fileState), date);
}

# 搜索录制文件结果

返回结果未json数组

var webPlugin = new  WebPlugin();

webPlugin.OnSearchRecordDataResult = function(localRecordDataS) {
	textarea.bespokeLocalRecord.innerHTML = textarea.bespokeLocalRecord.value +
		"&#10;OnSearchRecordDataResult&#10;" +
		localRecordDataS;
}

# 删除录制记录(db)

var webPlugin = new  WebPlugin();

function deleteRecordData() {
	var serialNumber = _getValue('input-delete-serialNumber');
	console.log(serialNumber)
	webPlugin.DeleteRecordData(serialNumber);
}

# 上传录制文件

通过流水号(唯一)上传。

var webPlugin = new  WebPlugin();

function uploadRecordFile() {
	var serialNumber = _getValue('input-upload-serialNumber');
  var addressSourceType = _getValueText('select-address-source-type');
	console.log(serialNumber)
	webPlugin.UploadRecord(serialNumber,addressSourceType);
}

# 上传进度通知

var webPlugin = new  WebPlugin();

webPlugin.OnUploadRecordNotify = function(serialId, state, fileSize, transferSize, fileUrl) {
	textarea.bespokeLocalRecord.innerHTML = textarea.bespokeLocalRecord.value + "&#10;OnUploadRecordNotify&#10;" +
		"唯一流水号:" + serialId + "; 文件状态:" + state +
		"; 文件大小(字节,当 State 为 Uploading时有效 ): " + fileSize + "; 文件上传进度(字节,当 State 为 Uploading时有效):" + transferSize +
		"; 文件上传地址(当 State 为 Success时有效 ): " + fileUrl;
}

# 录制状态通知

var webPlugin = new  WebPlugin();
//state:"Start/Stop/Error"
webPlugin.OnRecordStateNotify = function(state, reason) {
	textarea.bespokeLocalRecord.innerHTML = textarea.bespokeLocalRecord.value + "&#10;OnRecordStateNotify&#10;" +
		"录制状态:" + state + "; reason:" + reason;
}

# 接口调用通用结果返回

var webPlugin = new  WebPlugin();

webPlugin.OnFunctionResult = function(functionName, result, reason) {
	switch (functionName) {
		case "StartRecord":
			if (result) {
				textarea.bespokeLocalRecord.innerHTML = textarea.bespokeLocalRecord.value + "&#10;" +
					"开始录制成功,录制中";
			} else {
				textarea.bespokeLocalRecord.innerHTML = textarea.bespokeLocalRecord.value + "&#10;" +
					"开始录制失败: " + reason;
			}
			break;
		case "StopRecord":
			textarea.bespokeLocalRecord.innerHTML = textarea.bespokeLocalRecord.value + "&#10;" + "关闭录制 :" + result;
			break;
		case "SetRecordInfo":
			textarea.bespokeLocalRecord.innerHTML = textarea.bespokeLocalRecord.value + "&#10;" +
				"SetRecordInfo : &#10;" + result + ", " + reason;;
			break;
		case "SetRecordConfig":
			textarea.bespokeLocalRecord.innerHTML = textarea.bespokeLocalRecord.value + "&#10;" +
				"SetRecordConfig : &#10;" + result;
			break;
		case "GetUploadUrl":
			textarea.bespokeLocalRecord.innerHTML = textarea.bespokeLocalRecord.value + "&#10;" +
				"GetUploadUrl : &#10;" + result + "; SerialId = " + reason;
			break;
		case "UploadFileResult":
			textarea.bespokeLocalRecord.innerHTML = textarea.bespokeLocalRecord.value + "&#10;" +
				"UploadFileResult &#10;: " + result + "; SerialId = " + reason;
			break;
		case "UploadFileError":
			textarea.bespokeLocalRecord.innerHTML = textarea.bespokeLocalRecord.value + "&#10;" +
				"UploadFileError : &#10;" + result + "; SerialId = " + reason;
			break;
		case "DeleteRecordData":
			textarea.bespokeLocalRecord.innerHTML = textarea.bespokeLocalRecord.value + "&#10;" +
				"DeleteRecordData : &#10;" + result;
			break;
		case "UploadRecord":
			textarea.bespokeLocalRecord.innerHTML = textarea.bespokeLocalRecord.value + "&#10;" +
				"UploadRecord : &#10;" + result + "; reason:" + reason;
			break;
		case "EnableWatermark":
			textarea.otherExample.innerHTML = "EnableWatermark : " + result + "; reason = " + reason;
			break;
	}
}

# 清理本地录制文件

var webPlugin = new  WebPlugin();

function clearRecordData() {
     var index = _getValue("delete_mode");
     var callId = _getValue("input-delete-callId");
     var startTime = _getValue("input-start-time");
     var endTime = _getValue("input-end-time");
	   webPlugin.ClearRecordData(index,startTime,endTime,callId);
}

# 本地录制参数配置

var webPlugin = new  WebPlugin();


function confirmLocalRecordConfig() {
	var filename = _getValue('local-reload-filename');
	var filePath = _getValue('local-reload-filePath');

  webPlugin.localRecordConfig.FileName = filename;
  webPlugin.localRecordConfig.filePath = filePath;
}

# 获取文件信息

var webPlugin = new  WebPlugin();

/**
 * 获取文件信息
 * @param {string} callId 通话唯一标识
 * @param {String} extraInfo 扩展信息
 */

function getUploadFileInfo() {
	var callId = _getValue('input-upload-callId');
	webAgent.GetUploadFileInfo(callId,"");
}

# 获取文件信息通知

var webPlugin = new  WebPlugin();

/**
 * @desc 获取文件信息结果回调
 * @note 文件信息列表包含与 callId 关联的所有上传到服务器的文件
 * @param {Boolean} result 获取录制文件信息结果
 * 当 result 为 true 时,以下值有效
 * @param {Array} fileInfoList 文件信息列表,文件信息包含字段如下:
 * - FileName {String}  文件名称
 * - BeginTimeStamp {Number}    录制开始时间
 * - EndTimeStamp {Number}  录制结束时间
 * - FileMd5sun {String}    文件Md5值
 * - Duration {Number}  录制时长(图片类型文件无效)
 * - FileSize {Number}  文件大小
 * - UploadTimeStamp {Number}   上传时间
 * - FileUrl {String}   上传地址
 * @param {String} extraInfo 扩展信息
 * 当 result 为 false时,以下值有效
 * @param {String} reason 错误信息
 */
webPlugin.OnGetUploadFileInfoResult = function (result, fileInfo, extraInfo, reason) {
    textarea.bespokeLocalRecord.innerHTML = "获取文件信息结果 : " + result + "; 文件信息 = " + fileInfo+ "; reason = "+reason;
}

# 设置本地录制视频打点信息

var webPlugin = new  WebPlugin();

/**
 * @desc 设置本地视频打点内容
 */
function setLocalRecordVideoDot() {
    var content = _getValue('input-video-dot-content');
    webPlugin.SetLocalRecordVideoDot(content);
}

# 文件确认上传

根据当前录制文件的业务流水号确定(主要针对切片录制文件的自动上传)

webPlugin.ConfirmUpload(serialId);

# 清除业务流水号相关资源

根据业务流水号清除相关的资源包括数据库及对应视频相关文件

webPlugin.ClearSerialIdData(serialId);

# 强制重传

多次上传失败调用,重新获取上传地址,需要传入录制文件的业务流水号。

示例代码:

webPlugin.ForceUpload(serialId);

# 设置额外配置

extraConfig 额外配置参数,json格式,参数如下:

{
   IsUploadSliceEvent      {boolean} 是否上报上传事件,true是,false不是。默认false。
}

示例代码:

webPlugin.SetExtraConfig(extraConfig);

# 删除上传失败数据

可选删除多少天前上传失败的数据

示例代码:

webPlugin.DeleteUploadFailData(datetime);

# 3. 远程录制

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

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

# 功能实现

如果需要进行远程音视频录制,

  1. 在加入房间的时候需要把 EnableRemoteRecord 参数设置成true,参考 4.7 章节 joinParam 的 EnableRemoteRecord 参数说明
  2. 设置远程录制参数 WebPlugin.remoteRecordConfig
  3. 调用开启/关闭远程录制接口 WebPlugin.EnableRemoteRecord

远程录制参数说明如下:

this.remoteRecordConfig = {
		"BridgeType": "EnableRemoteRecord",
		"Enable": true, //true 开启远程录制 false 关闭远程录制
		"RecordVideo": true, // 是否录制视频,true 录制视频,false 只录制音频
		"WatermarkText": "",// 水印字符串,json格式{"name":"-我是占位符","name1":"-我是占位符1"}
		"FrameRate": -1, // 录制帧率
		"MergeMode": -1, // 视频合并模式: 0 默认值; 1 自定义布局; 2 智能分屏
		"IntelligentMergeMode": -1, // 智能分屏模式下的布局样式(无屏幕共享): 0 默认值; 1 自由布局; 2 矩形布局; 3-11 大小屏放大2倍-10倍;12 大小屏放大到顶部; 13 大小屏放大到底部;14 绝对等分模式;
		// 15 绝对等分模式不带图像角度
		"ScsMergeMode": -1, // 智能分屏模式下的布局样式(有屏幕共享): 0 默认值; 1 屏幕共享独占; 2 屏幕共享独占 + 其它一排它小视频不覆盖屏幕共享; 3 屏幕共享独占 + 其它一排它小视频覆盖在屏幕共享上;
		// 4 将屏幕共享和一个焦点视频内容合并; 5 忽略屏幕共享
		"VideoWidth": -1, // 录制视频的宽度
		"VideoHeight": -1,// 录制视频的高度
		"IBitrate": -1, // 录制码率
		"LayoutType": "", // 录制样式,对应业务管理平台上录制配置中的编号ID, 不传则用默认,自定义布局需要
		"LayoutList": "", // 设置录制成员布局列表,自定义布局需要,json格式。例如:[{"Position":2,"StreamId":"成员视频流ID"},{"Position":0,"Id":"用户2用户ID"},{"Position":1,"StreamId":"屏幕共享流ID"}]
        // Position 布局位置,对应业务管理平台自定义录制布局中位置,例如:0,1,2等; StreamId 布局中视频流标识 可以是房间中用户视频流ID、屏幕共享流ID;
		"SplitFileSize": 0,// 设置录制文件分割大小,单位KB。 <= 0表示不分割,默认不分割
		"FileName": "", // 存储文件名, ftp模式下可以带路径如:juphoon/1.mp4 视频文件录制后缀为mp4,如xx.mp4 音频文件录制后缀为aac,如xx.aac
		"ExtraInfo": "" // 录制自定义随路参数, json格式
	}

示例代码:

var webPlugin = new WebPlugin();
//... 其他参数
webPlugin.joinRoom.EnableRemoteRecord = true; //需要远程录制
//... 其他参数
webPlugin.Join("房间号"); //加入房间

//设置录制开启/关闭结果监听
webPlugin.OnEnableRemoteRecordResult = function(enable, result, reason) {
	console.log('OnEnableRemoteRecordResult', result);
};

webPlugin.remoteRecordConfig.RecordVideo = true; //设置是否录制视频
webPlugin.remoteRecordConfig.WatermarkText = '{"key1": "value1", "key2": "value2"}'; //设置水印json字符串
webPlugin.remoteRecordConfig.FrameRate = 24;//设置录制帧率
webPlugin.remoteRecordConfig.MergeMode = 0;//视频合并模式,枚举参考上图参数介绍
webPlugin.remoteRecordConfig.IntelligentMergeMode = 0;//智能分屏模式下的布局样式(无屏幕共享),枚举参考上图参数介绍
webPlugin.remoteRecordConfig.ScsMergeMode = 0;//智能分屏模式下的布局样式(有屏幕共享),枚举参考上图参数介绍
webPlugin.remoteRecordConfig.VideoWidth = 1280;//设置录制视频宽
webPlugin.remoteRecordConfig.VideoHeight = 720;//设置录制视频高
webPlugin.remoteRecordConfig.IBitrate = 0;//设置录制码率
webPlugin.remoteRecordConfig.SplitFileSize = -1;//设置录制文件分割大小
webPlugin.remoteRecordConfig.LayoutType = "";//设置录制样式
webPlugin.remoteRecordConfig.LayoutList = '[{"Position":2,"StreamId":"成员1视频流ID"},{"Position":0,"Id":"成员2视频流ID"},{"Position":1,"StreamId":"屏幕共享流ID"}]';//设置自定义布局成员列表
webPlugin.remoteRecordConfig.FileName = "xxx.mp4";//设置录制文件名
webPlugin.remoteRecordConfig.ExtraInfo = '{"key": "value"}';//设置随路参数
webPlugin.EnableRemoteRecord(true/false);//开启/关闭远程录制

# 接口调用通用结果返回

/**
 * @desc 开启、关闭远程录制回调
 * @param {boolean} result - true表示开启录制,false表示结束录制
 * @param {boolean} detail - true表示成功,false表示失败
 * @param {string} enable - 失败原因
 */
webPlugin.OnEnableRemoteRecordResult = function(enable, result, reason) {
    console.log('OnEnableRemoteRecordResult', result);
};

# 水印

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

Juphoon 插件支持以下三种画布水印设置:

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

# 注意事项

  • 其中自定义水印内容通过 webPlugin.remoteRecordConfig.WatermarkText 方法配置,服务端进行录制时将会把水印内容中的占位符替换成键值对中占位符对应 Key 的 Value 值。
//设置水印json字符串
webPlugin.remoteRecordConfig.WatermarkText = '{"key1": "value1", "key2": "value2"}'; 

# 添加、修改或删除水印

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

img

# 自定义布局

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

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

img

img

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

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

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

var webPlugin = new WebPlugin();

//设置需要录制视频
webPlugin.remoteRecordConfig.RecordVideo = true; 
//设置录制视频合并模式为自定义布局
webPlugin.remoteRecordConfig.MergeMode = 1;
//Position 就是上面介绍窗口位置;
//StreamId 就是视频流ID,可以是成员的视频流,也可以是屏幕共享流;
//视频流ID获取,可以先通过 webPlugin.GetConfMembers 获取成员对象列表,参考章节6.1
//每个成员对象里面包含属性 RenderId 就是视频流ID,
//如果属性UserId为固定字符串 "屏幕共享",则对应的 RenderId 就是屏幕共享流ID
webPlugin.remoteRecordConfig.LayoutList = '[{"Position":2,"StreamId":"成员1视频流ID"},{"Position":0,"Id":"成员2视频流ID"},{"Position":1,"StreamId":"屏幕共享流ID"}]';//设置自定义布局成员列表
// ... 其他参数
webPlugin.EnableRemoteRecord(true);//开启远程录制
//...
webPlugin.EnableRemoteRecord(false);//关闭远程录制

# 4. 摄像头水印

插件提供接口设置摄像头的水印信息,水印支持图片、文字、时间戳;该水印是在摄像头数据采集时添加,设置后,在本端预览、对端预览以及本地录制和服务端录制均包含该水印信息,需要在插件初始化后设置有效,支持本地预览开启前和开启后设置均可生效,接口如下:

/**
 * @desc 设置摄像头采集数据水印信息,需要在插件初始化后设置有效,结果通过 OnFunctionResult
 * @note 该水印是在采集阶段添加,设置后,本端预览、对端预览以及本地录制和服务端录制均包含该水印信息
 *
 * @param {String} cameraId 需要设置水印的摄像头ID,传空,设置所有摄像头水印
 * @param {Array} watermarkArray 水印信息列表,水印信息包含字段如下:
 * - Type {Number} 水印类型,0:图片水印;1:文字水印;2:时间戳水印;
 * - PosX {Number} 水印相对于原点(图像左上角),X轴坐标(右为正数)
 * - PosY {Number} 水印相对于原点(图像左上角),Y轴坐标(下为正数)
 * - Content {String} 如果是文字水印,传文字内容;如果是图片水印,传图片本地路径
 * - FontPath {String} 文字水印或者时间戳水印字体本地路径,不传或者传空,则默认
 * - FontSize {Number} 文字水印或者时间戳水印文字大小,单位:px
 * - FontColor {String} 文字水印或者时间戳水印文字颜色,HEX Color格式, 支持 #RRGGBB #RRGGBBAA,不传或者传空,则默认白色,即#FFFFFFFF
 * - TimeFormat {String} 时间戳显示格式,不传或者传空,则默认 yyyy-MM-dd HH:mm:ss.SSS
 * - BaseTimestamp {Number} 基准时间戳,不传,则默认当前 Unix 时间戳
 */
webPlugin.SetCameraWatermark(cameraId, watermarkArray);

设置结果通过 OnFunctionResult 上报

	/**
	 * @desc 接口调用通用结果返回
	 *
	 * @param {String} functionName - 调用的接口名
	 * - Login 登录
	 * - Logout 登出
	 * - CheckIn 签入
	 * - Checkout 签出
	 * - StartRecord 开始录制
	 * - StopRecord 关闭录制
	 * - SetRecordInfo 设置录制信息
	 * - SetRecordConfig 设置录制配置
	 * - GetUploadUrl 文件上传获取上传地址
	 * - UploadFileResult 上传文件结果
	 * - UploadFileError 上传文件失败
	 * - DeleteRecordData 删除录制文件
	 * - UploadRecord 上传录制文件
	 * - ChangeTalkingWindow 通话中修改通话界面配置
	 * - SetCameraWatermark 设置摄像头水印
	 * @param {boolean} result - 接口调用成功失败
	 * @param {String} reason - 接口调用失败原因
	 * @constructor
	 */
	webPlugin.OnFunctionResult = function(functionName, result, reason)

示例代码:

var webPlugin = new WebPlugin();
let watermarkArray = [];
let watermarkText = {};
//添加文本水印
watermarkText.Type = 1
watermarkText.PosX = 20;
watermarkText.PosY = 20;
watermarkText.Content = "我是文本水印";
watermarkText.FontPath = "C:\\SourceHanSansCN-Normal.otf";
watermarkText.FontSize = 20;
watermarkText.FontColor = "#FFFF0000";
watermarkArray.push(watermarkText);
//添加图片水印
let watermarkImage = {};
watermarkImage.Type = 0;
watermarkImage.Content = "C:\\watermark.png";
watermarkImage.PosX = 40;
watermarkImage.PosY = 40;
watermarkArray.push(watermarkImage)
//添加时间戳水印
let watermarkTimestamp = {};
watermarkTimestamp.Type = 2
watermarkTimestamp.PosX = 60;
watermarkTimestamp.PosY = 60;
watermarkTimestamp.TimeFormat = "yyyy/MM/dd HH:mm:ss.SSS";
const timestamp = new Date().getTime();
watermarkTimestamp.BaseTimestamp = timestamp;
watermarkTimestamp.FontPath = "C:\\SourceHanSansCN-Normal.otf";;
watermarkTimestamp.FontSize = 20;
watermarkTimestamp.FontColor = "#FFFF0000";
watermarkArray.push(watermarkTimestamp);
//设置水印
webPlugin.SetCameraWatermark("", watermarkArray);

webPlugin.OnFunctionResult = function(functionName, result, reason) {
  if (functionName === SetCameraWatermark) {
    if (result) {
      //水印设置成功
    } else {
      //水印设置失败
      consol.error("水印设置失败", reason);
    }
  }
}

# 5. 文件上传到影像平台结果通知

服务端录制文件或者本地录制文件上传到影像平台后,都会通过该接口回调通知

/**
 * 文件上传到影像平台结果通知
 * @note 服务端录制文件或者本地录制文件上传到影像平台后,都会通过该接口回调通知
 * @param result {Boolean} 上传结果
 * @param serialId {String} 业务id,如果是通话业务相关文件,对应的是 callId
 * @param fileInfo 文件对象
 * - FileName {String}  文件名称
 * - BeginTimeStamp {Number}    录制开始时间戳,单位 ms
 * - EndTimeStamp {Number}  录制结束时间戳,单位 ms
 * - FileMd5sun {String}    文件Md5值
 * - Duration {Number}  录制时长(图片类型时长无效),单位 ms
 * - FileSize {Number}  文件大小,单位 Byte
 * - UploadTimeStamp {Number}   上传时间,单位 ms
 */
webPlugin.OnFileUploadPlatformNotify = function(result, serialId, fileInfo) {}