初始化

音视频的接入需要依赖 IM 的账号系统,所以音视频的初始化需要依赖 IM 实例,这里需要首先初始化 IM,再初始化音视频

初始化 IM

初始化 IM, 完成 IM 的登录连接操作 请参照 IM 初始化章节

请注意IM连接成功后方可进行音视频通话,否则音视频通话会失败

初始化音视频

PC Agent 和 WebRTC 的初始化方式不太一样,这里分别举例

初始化音视频(PC Agent)

以下是示例代码

const netcall = Netcall.getInstance({
  kickLast: false,
  nim: nim,
  container: document.getElementById('container'),
  remoteContainer: document.getElementById('remoteContainer'),
  mirror: true,
  mirrorRemote: true
});
参数名 类型 说明
kickLast bool 是否踢掉上次的通话, 默认 false
nim object 音视频通话是基于 IM 的, 需要传入 NIM 初始化后的实例
container dom 播放自己视频画面的容器节点
remoteContainer dom 播放对方画面的容器节点
mirror bool 是否对自己的画面进行镜像处理, 默认 false, 一般来讲请将此参数设置为 true(既自己看自己是反项的)
mirrorRemote bool 是否对对方的画面进行镜像处理, 默认 false

初始化信令

Web 音视频通话依赖于 PC 插件, 所以在使用任何音视频通话功能之前, 需要先建立和 PC 插件之间的信令通道, 示例代码如下

var signalInited = false;
// 信令通道初始化完毕之后, 开发者可以启用音视频通话相关的 UI, 比如说展示呼叫别人的按钮
// 信令通道初始化失败的时候, 请展示错误并禁用所有音视频通话相关的 UI
netcall
  .initSignal()
  .then(function() {
    console.log('signalInited');
    signalInited = true;
  })
  .catch(function(err) {
    console.log('initSignalError', err);
    signalInited = false;
  });
// 当信令通道断开时, 会触发 signalClosed 事件
netcall.on('signalClosed', function() {
  console.log('on signalClosed');
  signalInited = false;
  netcall.hangup();
});
// 初始化过程中会通过 devices 事件回传所有的设备列表
netcall.on('devices', function(obj) {
  console.log('on devices', obj);
});

停止信令

当音视频通话结束之后, 需要停止信令通道, 然后禁用所有音视频通话相关的 UI, 示例代码如下

netcall.stopSignal();

初始化音视频(WebRTC)

以下是示例代码

// SDK重命名
const Netcall = WebRTC;
const netcall = Netcall.getInstance({
  nim: nim,
  container: document.getElementById('container'),
  remoteContainer: document.getElementById('remoteContainer'),
  // 是否开启日志打印
  debug: true
});
参数名 类型 说明
nim object 音视频通话是基于 IM 的, 需要传入 NIM 初始化后的实例
container dom 播放自己视频画面的容器节点
remoteContainer dom 播放对方画面的容器节点
debug bool 是否开启日志打印,默认 false

初始注册事件监听

在初始化音视频通话之后, 在进行音视频通话之前, 请先注册监听一些音视频通话通知事件, 基本上所有的音视频通话操作都是异步的, 而且这些操作会触发音视频通话的某些事件, 具体事件会在各个操作里面详细介绍.

被叫收到呼叫的通知

// 是否被叫中
let beCalling = false;
// 呼叫类型
let type = null;
// 被叫信息
let beCalledInfo = null;
// 是否正忙
let busy = false;
// 开启监听
netcall.on('beCalling', function(obj) {
  console.log('on beCalling', obj);
  const channelId = obj.channelId;
  // 被叫回应主叫自己已经收到了通话请求
  netcall.control({
    channelId,
    command: Netcall.NETCALL_CONTROL_COMMAND_START_NOTIFY_RECEIVED
  });
  // 只有在没有通话并且没有被叫的时候才记录被叫信息, 否则通知对方忙并拒绝通话
  if (!netcall.calling && !beCalling) {
    type = obj.type;
    beCalling = true;
    beCalledInfo = obj;
  } else {
    if (netcall.calling) {
      busy = netcall.notCurrentChannelId(obj);
    } else if (beCalling) {
      busy = beCalledInfo.channelId !== channelId;
    }
    if (busy) {
      netcall.control({
        channelId,
        command: Netcall.NETCALL_CONTROL_COMMAND_BUSY
      });
      // 拒绝通话
      netcall.response({
        accepted: false,
        beCalledInfo: obj
      });
    }
  }
});
obj 属性 类型 说明
account string 主叫 account
type number 主叫发起的通话类型(音频还是视频)
channelId string 该通呼叫会话的唯一 id 值,开发者可用于判断是否是同一通呼叫

主叫收到被叫接受的通知

// 被叫接受的通知
netcall.on('callAccepted', function(obj) {
  console.log('on callAccepted', obj);
  // 取消呼叫倒计时
  clearCallTimer();
  // 可以开启音视频连接操作。。。
});

obj 为呼叫应答的回调通知对象

obj 属性 类型 说明
account string 被叫账号
type number 音视频呼叫类型:音频、视频

主叫收到被叫拒绝的通知

// 被叫拒绝的通知
netcall.on('callRejected', function(obj) {
  console.log('on callRejected', obj);
  // 取消呼叫倒计时
  clearCallTimer();
  // 挂断
  hangup();
  // 做清理工作
  resetWhenHangup();
});

obj 为呼叫应答的回调通知对象

obj 属性 类型 说明
account string 被叫账号
type number 音视频呼叫类型:音频、视频

通话中收到远端的控制指令

netcall.on('control', function(obj) {
  console.log('收到指令', obj);
});

obj 为指令通知对象

param 属性 类型 说明
channelId number 需要发送指令的房间 id
command number 指令类型,具体值请参照这里

收到挂断通知

netcall.on('hangup', function(obj) {
  console.log('on hangup', obj);
  // 判断需要挂断的通话是否是当前正在进行中的通话
  if (!beCalledInfo || beCalledInfo.channelId === obj.channelId) {
    // 清理工作
    resetWhenHangup();
  }
});

obj 收到的挂断通知对象

obj 属性 类型 说明
timetag string 时间戳
channelId string 当前通话的唯一 id 值
account string 对方账号
type number 挂断类型:0 为正常挂断,-1 位异常挂断(超时等)

其他端已处理的通知

netcall.on('callerAckSync', function(obj) {
  console.log('其他端已经做了处理', obj);
});

obj 为其他端已处理的回调对象

obj 属性 类型 说明
timetag string 时间戳
channelId string 当前通话的唯一 id 值
type number 通话类型:音频、视频
accepted bool 其他端做出的应答:接受、拒绝
fromClientType string 从什么类型的终端做出的应答:IOS、Android 等

用户加入房间通知

netcall.on('joinChannel', function(obj) {
  // 通知上层有其他用户加入了房间,上层做相应逻辑和UI处理
  // 这里可以预览加入的同学的视频流
  // 播放对方声音
  netcall
    .startDevice({
      type: Netcall.DEVICE_TYPE_AUDIO_OUT_CHAT
    })
    .catch(function() {
      console.log('播放对方的声音失败');
    });

  // 预览加入的同学的视频流
  netcall.startRemoteStream({
    account: obj.account,
    node: document.getElementById('remoteContainer')
  });

  // 设置对方预览画面大小
  netcall.setVideoViewRemoteSize({
    account: 'testAccount',
    with: 500,
    height: 500,
    cut: true
  });
});

obj 为通知消息对象

obj 属性 类型 说明
account string 新加入同伴的 accid
channelId number 加入的房间 id
返回类型 方法名 说明
promise netcall.startDevice 播放对方声音
promise netcall.startRemoteStream 预览对方视频画面
promise netcall.setVideoViewRemoteSize 设置对方画面大小

用户离开房间通知

netcall.on('leaveChannel', function(obj) {
  // 通知上层有其他用户离开了会议,上层做相应逻辑和UI处理

  // 停止预览该同伴的视频流
  netcall.stopRemoteStream({
    account: obj.account
  });
});

obj 为通知消息对象

obj 属性 类型 说明
account string 离开同伴的 accid
channelId number 离开的房间 id
返回类型 方法名 说明
promise netcall.stopRemoteStream 停止预览对方视频画面

音量大小实时回调通知

netcall.on('audioVolume', function(obj) {
  console.log('音量', obj);
});

obj 为当前正在房间中所有人的音量对象,具体如下

obj 属性 类型 说明
obj['self'] obj 自己的音量对象
obj['self'].status float 自己的音量大小值
obj['accountA'] obj 账号accountA的音量对象
obj['accountA'].status float 账号accountA的音量大小值

收到用户媒体流的通知

netcall.on('remoteTrack', function(obj) {
  console.log('收到远程轨道信息', obj);
  // 音频:播放对方的音频
  if (obj.track.kind === 'audio') {
    // 播放对方声音
    netcall
      .startDevice({
        type: Netcall.DEVICE_TYPE_AUDIO_OUT_CHAT
      })
      .catch(function() {
        console.log('播放对方的声音失败');
      });
  }

  // 视频:展示对方的画面
  if (obj.track.kind === 'video') {
    // 预览加入的同学的视频流
    netcall.startRemoteStream({
      uid: obj.uid,
      node: document.getElementById('remoteContainer')
    });

    // 设置对方预览画面大小
    netcall.setVideoViewRemoteSize({
      uid: 'testUid',
      with: 500,
      height: 500,
      cut: true
    });
  }
});

obj 为通知消息对象

obj 属性 类型 说明
uid string 新加入同伴的 uid
channelId number 加入的房间 id
返回类型 方法名 说明
promise netcall.startDevice 播放对方声音
promise netcall.startRemoteStream 预览对方视频画面
promise netcall.setVideoViewRemoteSize 设置对方画面大小

设备新增通知

netcall.on('deviceAdd', function(devices) {
  console.log('新增设备列表', devices);
}

devices 当前新增的设备列表数组

devices[0]属性 类型 说明
deviceId string 设备 id 值
label string 设置标签名

设备移除通知

netcall.on('deviceRemove', function(devices) {
  console.log('移除设备列表', devices);
}

devices 当前移除的设备列表数组

devices[0]属性 类型 说明
deviceId string 设备 id 值
label string 设置标签名

设备状态变化通知

netcall.on('deviceStatus', function(obj) {
  console.log('设备状态发生变化', obj);

  // 检查摄像头
  netcall.getDevicesOfType(WebRTC.DEVICE_TYPE_VIDEO).then(function(devices) {
    console.log('摄像头', devices);
  });

  // 检查麦克风
  netcall.getDevicesOfType(WebRTC.DEVICE_TYPE_AUDIO_IN).then(function(devices) {
    console.log('麦克风', devices);
  });

  // 检查扬声器
  netcall
    .getDevicesOfType(WebRTC.DEVICE_TYPE_AUDIO_OUT_CHAT)
    .then(function(devices) {
      console.log('扬声器', devices);
    });
});

devices 当前检测设备类型返回的设备列表数组

devices[0]属性 类型 说明
deviceId string 设备 id 值
label string 设置标签名

音视频清理

音视频网络通话相关功能调用结束后(即通话结束后),需要在 SDK 清理前,主动清理音视频功能。这里列一下最常见的清理步骤

graph TB A(Start) --> B[上层逻辑清理自己维护的各种状态: calling等] B --> C[清空各种计时器: 如果有的话] C --> D[netcall.stopLocalStream: 停止本地视频预览] D --> E[netcall.stopRemoteStream: 停止对端视频预览] E --> F[netcall.stopDevice: 停止播放本地音频] F --> G[netcall.stopDevice: 停止播放远程音频] G --> H[netcall.stopDevice: 停止设备麦克风] H --> I[netcall.stopDevice: 停止设备摄像头] I --> J(End)
返回类型 方法名 说明
void netcall.stopLocalStream 停止本地视频预览
void netcall.stopRemoteStream 停止对端视频预览
void netcall.stopDevice 停止设备麦克风
void netcall.stopDevice 停止设备摄像头
void netcall.stopDevice 停止播放本地音频
void netcall.stopDevice 停止播放远程音频
// 清除上层逻辑自己维护的各种状态
clear();

// 停止本地视频预览
netcall.stopLocalStream();

// 停止对端视频预览
netcall.stopRemoteStream();

// 停止设备麦克风
netcall.stopDevice(Netcall.DEVICE_TYPE_AUDIO_IN);

// 停止设备摄像头
netcall.stopDevice(Netcall.DEVICE_TYPE_VIDEO);

// 停止播放本地音频
netcall.stopDevice(Netcall.DEVICE_TYPE_AUDIO_OUT_LOCAL);

// 停止播放对端音频
netcall.stopDevice(Netcall.DEVICE_TYPE_AUDIO_OUT_CHAT);