文档反馈
文档反馈

SDK 概述

网易云信 SDK 提供完善的音视频通话开发框架,提供基于网络的点对点视频通话和语音通话功能,还提供多人视频和音频会议功能,支持通话中音视频设备控制和实时音视频模式切换。

实现音视频通话功能需要用到登录认证服务和实时语音视频通话服务。

集成方式

NIM SDK 需要您通过手动下载 SDK, 然后添加到您的项目中。

下载SDK

我们提供两个SDK获取方式。分别为:

引入SDK

SDK选择

SDK引入方式

<!-- 例如 -->
<script src="NIM_Web_SDK.js">
<script>
  var nim = SDK.NIM.getInstance({
    // ...
  })
</script>
  // 使用示例
  import SDK from 'NIM_Web_SDK.js'
  const nim = SDK.NIM.getInstance({
    // ...
  })
  // Webpack 参考配置
  module: {
    rules: [
      {
        test: /\.js$/,
        loader: 'babel-loader',
        exclude: /NIM_Web_SDK.*\.js/,
        query: {
          presets: [
            // ...
          ],
          // ...
        }
        // ...
      },
      // ...
    ],
    // ...
  }

调用规则

调用方式

所有业务均通过 NIMSDK 单例调用

  // 引入SDK类的引用以后,获取SDK对象实例
  var nim = SDK.NIM.getInstance({
    // ...
  })

以发送点对点消息为例:

  var msg = nim.sendText({
    scene: 'p2p',
    to: 'account',
    text: 'hello',
    done: function sendMsgDone (error, msg) {
      // ...
    }
  })

通知方式

SDK 通过两种方式通知上层 API 调用结果:回调(callback)和委托 (delegate),两种方式都只在主线程触发(为保证浏览器兼容性,没有使用web worker)。

  // 委托通知示例
  var nim = NIM.getInstance({
    // ... 此处省略其他配置
    onmsg: function (msg) {
      // 此处为委托消息事件,消息发送成功后,成功消息也在此处处理
    }
  })
  // 回调通知示例
  var msg = nim.sendText({
    scene: 'p2p',
    to: 'account',
    text: 'hello',
    done: function sendMsgDone (error, msg) {
      // 此处为回调消息事件,仅仅通知开发者,消息是否发送成功
    }
  })

浏览器兼容性

云信 Web SDK (不包含实时音视频)兼容到 IE8

数据库兼容性

在支持数据库的浏览器上 SDK 会将数据缓存到数据库中, 后续同步都是增量更新, 加快初始化速度。

Web SDK在底层使用了indexedDb,作为数据库进行存储。由于浏览器兼容性及其本身设计上的限制/缺陷(如读写库性能问题、数据空间、没有数据库表级别锁、不能只修改对象单个字段、非阻塞等等问题),用户场景没有强烈需要本地数据存储的应用,不建议开启数据库

是否支持数据库

// 通过此 `boolean` 值来查看 SDK 在某个浏览器上是否支持数据库
NIM.support.db

其原理是结合了JavaScript"鸭子类型"探测和UserAgent识别,做判断,所以非法改写的UserAgent可能会导致报错。

不使用数据库

如果开发者不想使用数据库, 那么可以设置初始化参数dbfalse来禁用数据库

var nim = NIM.getInstance({
    db: false
});

依赖说明

初始化 SDK

初始化SDK

登录与登出

登录与登出

音视频通话(插件版)

准备工作

兼容性要求

初始化音视频通话

请参考示例代码来初始化音视频通话, 示例代码和参数解释如下:

const netcall = Netcall.getInstance({
  nim: window.nim,
  container: document.getElementById('container'),
  remoteContainer: document.getElementById('container'),
  mirror: true
})

音视频通话事件

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

初始化信令

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

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

停止信令

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

netcall.stopSignal()

发起音视频通话呼叫

在初始化信令之后, 可以发起音视频通话呼叫

const switchToAudioIfNoVideoDevice = true
let type = Netcall.DEVICE_TYPE_VIDEO
let callTimer
netcall.getDevicesOfType(type).then(obj => {
  // 在没有摄像头设备的时候切换到音频通话
  if (type === Netcall.NETCALL_TYPE_VIDEO && switchToAudioIfNoVideoDevice && !obj.devices.length) {
    type = Netcall.NETCALL_TYPE_AUDIO
  }
  netcall.call({
    type,
    account: 'callee',
    webrtcEnable: true,
    pushConfig: {
      // enable: true,
      // needBadge: true,
      // needPushNick: true,
      pushContent: '推送内容',
      custom: JSON.stringify({
        key: 'value'
      })
    },
    sessionConfig: {

    }
  }).then(obj => {
    console.log('call success', obj)
  }, err => {
    // 被叫不在线
    if (err.code === 11001) {
      console.log('callee offline', err)
    }
  })
  // 设置超时计时器
  callTimer = setTimeout(() => {
    if (!netcall.callAccepted) {
      console.log('超时未接听, hangup')
      hangup()
    }
  }, 1000 * 30)
})

清理音视频通话呼叫超时计时器

clearCallTimer () {
  clearTimeout(callTimer)
}

挂断音视频通话

function resetWhenHangup () {
  beCalledInfo = null
  beCalling = false
  clearCallTimer()
  netcall.stopLocalStream()
  netcall.stopRemoteStream()
  netcall.stopDeviceAudioIn()
  netcall.stopDeviceAudioOutLocal()
  netcall.stopDeviceAudioOutChat()
  netcall.stopDeviceVideo()
},
function hangup () {
  netcall.hangup()
  resetWhenHangup()
},

监听挂断音视频通话

当一方挂断之后, 另一方会收到 hangup 事件, 此时做一些清理工作即可

netcall.on('hangup', obj => {
  console.log('on hangup', obj)
  resetWhenHangup()
})

被呼叫

被叫用户在初始化音视频通话之后可以监听被呼叫的事件, 然后展示接听和挂断按钮

let beCalling = false
let beCalledInfo = null
netcall.on('beCalling', obj => {
  console.log('on beCalling', obj)
  // 获取通话标识符 channelId, 每一通会话的 channelId 都不一样
  const {channelId} = obj
  // 通知对方自己已经收到此次通话的请求
  netcall.control({
    channelId,
    command: Netcall.NETCALL_CONTROL_COMMAND_START_NOTIFY_RECEIVED
  })
  // 只有在没有通话并且没有被叫的时候才记录被叫信息, 否则直接挂断
  if (!netcall.calling && !beCalling) {
    beCalling = true
    beCalledInfo = obj
  } else {
    let busy = false
    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
      })
    }
  }
})

拒绝音视频通话被呼叫

可以先通知对方自己忙, 拒绝的时候需要回传在 beCalling 事件里面接收到的对象

netcall.control({
  channelId: beCalledInfo.channelId,
  command: Netcall.NETCALL_CONTROL_COMMAND_BUSY
})
netcall.response({
  accepted: false,
  beCalledInfo: beCalledInfo
})
beCalledInfo = null
beCalling = false

监听拒绝音视频通话被呼叫

当被叫拒绝音视频通话被呼叫之后, 主叫会收到 callRejected 事件, 一般来讲需要进行如下操作

netcall.on('callRejected', obj => {
  console.log('on callRejected', obj)
  clearCallTimer()
  netcall.stopLocalStream()
  netcall.stopRemoteStream()
})

接听音视频通话被呼叫

beCalling = false
netcall.initSignal().then(() => {
  return netcall.response({
    accepted: true,
    beCalledInfo: beCalledInfo,
    sessionConfig: sessionConfig
  })
}).catch(err => {
  netcall.control({
    channelId: beCalledInfo.channelId,
    command: Netcall.NETCALL_CONTROL_COMMAND_BUSY
  })
  hangup()
  beCalledInfo = null
  console.log('接听失败', err)
})

监听接听音视频通话被呼叫

netcall.on('callAccepted', obj => {
  console.log('on callAccepted', obj)
  clearCallTimer()
  if (obj.type === Netcall.NETCALL_TYPE_VIDEO) {
    startDeviceAudioIn()
    startDeviceAudioOutChat()
    startDeviceVideo()
    netcall.startLocalStream()
    netcall.startRemoteStream()
  } else {
    startDeviceAudioIn()
    startDeviceAudioOutChat()
    stopDeviceVideo()
  }
})
netcall.on('deviceStatus', obj => {
  console.log('on deviceStatus', obj)
})
netcall.on('streamResize', obj => {
  console.log('on streamResize', obj)
})
netcall.on('remoteStreamResize', obj => {
  console.log('on remoteStreamResize', obj)
})

监听音视频通话被叫操作多端同步通知

假如你在多台设备上登录了同一个账号, 此时如果被呼叫, 那么所有的设备都会收到 beCalling 事件, 当你在某台设备接听或者拒绝之后, 其它设备会收到这个操作的通知, 名字叫 callerAckSync, 收到此事件后一般来讲需要隐藏相应的被呼叫界面

netcall.on('callerAckSync', obj => {
  console.log('on callerAckSync', obj)
  if (beCalledInfo && obj.channelId === beCalledInfo.channelId) {
    beCalledInfo = false
    beCalling = false
  }
})

设置自己画面的尺寸

最终显示的画面不大于所设置的宽和高 裁剪: cut: true(默认值), 画面按照提供的宽高等比例裁剪,返回裁剪后的实际大小 cut: false, 画面不进行裁剪, 返回按原始比例放大缩小后的实际宽高

netcall.setVideoViewSize({
  width: 300,
  height: 300,
  cut: true
})

设置对方画面的尺寸

最终显示的画面不大于所设置的宽和高 裁剪: cut: true(默认值), 画面按照提供的宽高等比例裁剪,返回裁剪后的实际大小 cut: false, 画面不进行裁剪, 返回按原始比例放大缩小后的实际宽高

netcall.setVideoViewRemoteSize({
  width: 300,
  height: 300,
  cut: true
})

启动麦克风设备

可以传入 device 参数来指定开启某个特定设备; 如果不传 device 参数, 那么默认启动第一个此类设备

function startDeviceAudioIn () {
  netcall.startDevice({
    type: Netcall.DEVICE_TYPE_AUDIO_IN,
    device
  }).then(() => {
    // 通知对方自己开启了麦克风
    netcall.control({
      command: Netcall.NETCALL_CONTROL_COMMAND_NOTIFY_AUDIO_ON
    })
  }).catch(() => {
    console.log('启动麦克风失败')
  })
}

停止麦克风设备

function stopDeviceAudioIn () {
  netcall.stopDevice(Netcall.DEVICE_TYPE_AUDIO_IN).then(() => {
    // 通知对方自己关闭了麦克风
    netcall.control({
      command: Netcall.NETCALL_CONTROL_COMMAND_NOTIFY_AUDIO_OFF
    })
  })
}

启动播放自己声音的设备

可以传入 device 参数来指定开启某个特定设备; 如果不传 device 参数, 那么默认启动第一个此类设备

function startDeviceAudioOutLocal () {
  netcall.startDevice({
    type: Netcall.DEVICE_TYPE_AUDIO_OUT_LOCAL,
    device
  }).catch(() => {
    console.log('播放自己的声音失败')
  })
}

停止播放自己声音的设备

function stopDeviceAudioOutLocal () {
  netcall.stopDevice(Netcall.DEVICE_TYPE_AUDIO_OUT_LOCAL)
}

启动播放对方声音的设备

可以传入 device 参数来指定开启某个特定设备; 如果不传 device 参数, 那么默认启动第一个此类设备

function startDeviceAudioOutChat () {
  netcall.startDevice({
    type: Netcall.DEVICE_TYPE_AUDIO_OUT_CHAT,
    device
  }).catch(() => {
    console.log('播放对方的声音失败')
  })
}

停止播放对方声音的设备

function stopDeviceAudioOutChat () {
  netcall.stopDevice(Netcall.DEVICE_TYPE_AUDIO_OUT_CHAT)
}

启动摄像头设备

可以传入 device 参数来指定开启某个特定设备; 如果不传 device 参数, 那么默认启动第一个此类设备 通过参数 width 和 height 来设置摄像头捕获的视频的最大宽度和高度

function startDeviceVideo () {
  netcall.startDevice({
    type: Netcall.DEVICE_TYPE_VIDEO,
    width: 300,
    height: 300
  }).then(() => {
    // 通知对方自己开启了摄像头
    netcall.control({
      command: Netcall.NETCALL_CONTROL_COMMAND_NOTIFY_VIDEO_ON
    })
  }).catch(() => {
    // 通知对方自己的摄像头不可用
    netcall.control({
      command: Netcall.NETCALL_CONTROL_COMMAND_SELF_CAMERA_INVALID
    })
    console.log('启动摄像头失败')
  })
}

停止摄像头设备

stopDeviceVideo () {
  netcall.stopDevice(Netcall.DEVICE_TYPE_VIDEO).then(() => {
    // 通知对方自己关闭了摄像头
    netcall.control({
      command: Netcall.NETCALL_CONTROL_COMMAND_NOTIFY_VIDEO_OFF
    })
  })
}

是当前会话的channelId

// obj 需包含 channelId 属性
netcall.isCurrentChannelId(obj)

不是当前会话的channelId

// obj 需包含 channelId 属性
netcall.notCurrentChannelId(obj)

获取指定类型的所有设备

此接口返回 Promise, 可选类型有

netcall.getDevicesOfType(type)

开启本地视频流

开启之后, 会接收并绘制自己的视频数据

netcall.startLocalStream()

停止本地视频流

停止之后, 会停止接收并绘制自己的视频数据

netcall.stopLocalStream()

开启远程视频流

开启之后, 会接收并绘制对方的视频数据

netcall.startRemoteStream()

停止远程视频流

停止之后, 会停止接收并绘制对方的视频数据

netcall.stopRemoteStream()

发送音视频通话控制指令

netcall.control({
  channelId,
  command: Netcall.NETCALL_CONTROL_COMMAND_NOTIFY_AUDIO_ON
})

监听音视频通话控制指令

netcall.on('control', obj => {
  // 如果不是当前通话的指令, 直接丢掉
  if (netcall.notCurrentChannelId(obj)) {
    return
  }
  console.log('on control', obj)
  const {type} = obj
  switch (type) {
    // NETCALL_CONTROL_COMMAND_NOTIFY_AUDIO_ON 通知对方自己打开了音频
    case Netcall.NETCALL_CONTROL_COMMAND_NOTIFY_AUDIO_ON:
      console.log('对方打开了音频')
      break
    // NETCALL_CONTROL_COMMAND_NOTIFY_AUDIO_OFF 通知对方自己关闭了音频
    case Netcall.NETCALL_CONTROL_COMMAND_NOTIFY_AUDIO_OFF:
      console.log('对方关闭了音频')
      break
    // NETCALL_CONTROL_COMMAND_NOTIFY_VIDEO_ON 通知对方自己打开了视频
    case Netcall.NETCALL_CONTROL_COMMAND_NOTIFY_VIDEO_ON:
      console.log('对方打开了视频')
      break
    // NETCALL_CONTROL_COMMAND_NOTIFY_VIDEO_OFF 通知对方自己关闭了视频
    case Netcall.NETCALL_CONTROL_COMMAND_NOTIFY_VIDEO_OFF:
      console.log('对方关闭了视频')
      break
    // NETCALL_CONTROL_COMMAND_SWITCH_AUDIO_TO_VIDEO 请求从音频切换到视频
    case Netcall.NETCALL_CONTROL_COMMAND_SWITCH_AUDIO_TO_VIDEO:
      agreeSwitchAudioToVideo()
      break
    // NETCALL_CONTROL_COMMAND_SWITCH_AUDIO_TO_VIDEO_REJECT 拒绝从音频切换到视频
    case Netcall.NETCALL_CONTROL_COMMAND_SWITCH_AUDIO_TO_VIDEO_REJECT:
      break
    // NETCALL_CONTROL_COMMAND_SWITCH_AUDIO_TO_VIDEO_AGREE 同意从音频切换到视频
    case Netcall.NETCALL_CONTROL_COMMAND_SWITCH_AUDIO_TO_VIDEO_AGREE:
      switchAudioToVideo()
      break
    // NETCALL_CONTROL_COMMAND_SWITCH_VIDEO_TO_AUDIO 从视频切换到音频
    case Netcall.NETCALL_CONTROL_COMMAND_SWITCH_VIDEO_TO_AUDIO:
      switchVideoToAudio()
      break
    // NETCALL_CONTROL_COMMAND_BUSY 占线
    case Netcall.NETCALL_CONTROL_COMMAND_BUSY:
      console.log('对方忙')
      break
    // NETCALL_CONTROL_COMMAND_SELF_CAMERA_INVALID 自己的摄像头不可用
    // NETCALL_CONTROL_COMMAND_SELF_ON_BACKGROUND 自己处于后台
    // NETCALL_CONTROL_COMMAND_START_NOTIFY_RECEIVED 告诉发送方自己已经收到请求了(用于通知发送方开始播放提示音)
    // NETCALL_CONTROL_COMMAND_NOTIFY_RECORD_START 通知对方自己开始录制视频了
    // NETCALL_CONTROL_COMMAND_NOTIFY_RECORD_STOP 通知对方自己结束录制视频了
  }
})

/*
 * 音视频通话切换示例函数 begin
 */

function askSwitchVideoToAudio () {
  // 通知对方从视频切换到音频, 不需要同意直接切
  this.netcall.control({
    command: Netcall.NETCALL_CONTROL_COMMAND_SWITCH_VIDEO_TO_AUDIO
  })
  switchVideoToAudio()
}
function switchVideoToAudio () {
  stopDeviceVideo()
  netcall.switchVideoToAudio()
  netcall.stopLocalStream()
  netcall.stopRemoteStream()
}
function askSwitchAudioToVideo () {
  // 请求从音频切换到视频
  netcall.control({
    command: Netcall.NETCALL_CONTROL_COMMAND_SWITCH_AUDIO_TO_VIDEO
  })
}
function agreeSwitchAudioToVideo () {
  // 同意从音频切换到视频
  netcall.control({
    command: Netcall.NETCALL_CONTROL_COMMAND_SWITCH_AUDIO_TO_VIDEO_AGREE
  })
  switchAudioToVideo()
}
function switchAudioToVideo () {
  netcall.switchAudioToVideo()
  startDeviceVideo()
  netcall.startLocalStream()
  netcall.startRemoteStream()
}

/*
 * 音视频通话切换示例函数 end
 */

从视频模式切换为音频模式

netcall.switchVideoToAudio()

从音频模式切换为视频模式

netcall.switchAudioToVideo()

设置会话的视频质量

监听接听音视频通话被呼叫之后, 可以动态设置会话的视频质量, 可选视频质量有

netcall.setSessionVideoQuality(Netcall.CHAT_VIDEO_QUALITY_NORMAL)

设置会话的视频帧率

监听接听音视频通话被呼叫之后, 可以动态设置会话的视频帧率, 可选视频帧率有

netcall.setSessionVideoFrameRate(Netcall.CHAT_VIDEO_FRAME_RATE_NORMAL)

设置会话的视频码率

监听接听音视频通话被呼叫之后, 可以动态设置会话的视频码率, >=100000 <= 5000000 有效

netcall.setSessionVideoBitrate(0)

设置采集音量

设置采集信号的音量大小,支持设置的音量范围为 0~255。

注意:仅 Chrome 浏览器支持通过 setCaptureVolume 设置采集音量。

netcall.setCaptureVolume(100)

设置播放音量

音量大小, 0-255

netcall.setPlayVolume(100)

网络探测

netcall.netDetect().then(obj => {
  console.log('netDetect success', obj)
}, err => {
  console.log('netDetect error', err)
})

监听各种信息事件

let netStatus = {}
netcall.on('netStatus', obj => {
  netStatus = NIM.util.merge({}, netStatus, obj)
})

let statistics = {}
netcall.on('statistics', obj => {
  statistics = obj
})

let audioVolumn = {}
netcall.on('audioVolumn', obj => {
  audioVolumn = NIM.util.merge({}, audioVolumn, obj)
})

监听异常

netcall.on('error', obj => {
    if (type === 'heartBeatError') {
        // pc35秒没收到心跳包,会抛出异常(此后所有操作会返回code: 1) 需要重新建立信令
        // todo
    }
   this.addLog('on error', obj)
})

多人会议

与点对点通话的流程不同,多人会议暂不支持呼叫、推送和挂断等服务,只提供基本的预订、加入和离开会议接口。 目前呼叫方案可以参照demo使用点对点通知发送呼叫

预订会议
netcall.createChannel({
  channelName: channelName //必填
  custom: custom //可选
  webrtcEnable: webrtcEnable // 是否支持WebRTC方式接入,可选,默认为不开启
}).then(obj => {
  // 预定会议成功后的上层逻辑操作
  // eg: 初始化会议UI显示
  // eg: 加入会议
})

需要先预订,本人和其他人才能加入会议。

会议通过 channelName 字段做标识;可以通过扩展字段 custom 在会议的创建和加入之间传递自定义的额外信息。

如果需要与 WebRTC 客户端互通,需要指定 WebRTC 兼容开关 webrtcEnable 为 true, 该 WebRTC 为 Beta 版,如果没有 WebRTC 客户端参与, 不要打开该开关

同一个会议名称,只在会议使用完并且房间被销毁(所有人都离开房间)以后才可以重复使用,开发者需要保证不会出现重复预订某会议名称而不使用的情况。

预定结果通过promise的then和catch捕捉

加入会议
netcall.joinChannel({
  channelName: channelName, //必填
  type: type,
  custom: custom, //可选
  sessionConfig: sessionConfig
}).then(obj => {
  // 加入会议成功后的上层逻辑操作
  // eg: 开启摄像头
  // eg: 开启麦克风
  // eg: 开启本地流
  // eg: 设置音量采集、播放
  // eg: 设置视频画面尺寸等等,具体请参照p2p呼叫模式
})

参数解读

channelName: 会议id(必填)
type: 通话类型(音频还是视频)
sessionConfig 会话配置,具体请参考API文档
{
  videoQuality 视频分辨率
  videoFrameRate 视频帧率
  videoBitrate 视频码率
  highAudio=false 高清语音开关, 默认关闭
  recordVideo=false 视频录制开关, 默认关闭
  recordAudio=false 音频录制开关, 默认关闭
  bypassRtmp=false 推流开关, 默认关闭,推流相关配置前提开关打开
  rtmpUrl 推流地址
  rtmpRecord=false 推流录制开关, 默认关闭
  splitMode 推流的布局, 默认平铺
}

加入会议结果通过promise的then和catch捕捉

离开会议
netcall.leaveChannel().then(obj => {
  // 离开会议后的扫尾工作
})
改变自己在会议中的角色
// 观众切换到互动者
netcall.changeRoleToPlayer().then(obj => {
  // todo
})

// 互动者切换到观众
netcall.changeRoleToAudience().then(obj => {
  // todo
})
指定某用户设置是否对其静音(同p2p)
// 设置禁音
netcall.setAudioBlack(account).then(obj => {
  // todo
})

// 放开禁音
netcall.setAudioBlack(account).then(obj => {
  // todo
})

静音后将听不到该用户的声音。

需要在用户加入以后才能进行设置,该接口也可用于点对点双人通话。

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

WebRTC(Beta)

备注

  1. 从V3.9.1开始支持WebRTC, 目前该版本为待优化的测试版本,欢迎开发者提供bug反馈和优化建议,让我们一起做得更好
  2. 对于WebRTC Beta版,在有 webrtc 客户端参与的房间中需要打开该开关, 如果没有 webrtc 客户端参与,不要打开该开关。
  3. 请注意:WebRTC 的音视频支持需要开启https, http模式下无法捕捉摄像头和麦克风

兼容性要求

准备工作

初始化实时音视频

请参考示例代码来初始化实时音视频, 示例代码和参数解释如下:

const netcall = WebRTC.getInstance({
  nim: window.nim,
  container: document.getElementById('container'),
  remoteContainer: document.getElementById('container')
})

实时音视频事件

在初始化实时音视频之后, 在调用任何方法之前, 请先监听一些实时音视频事件, 基本上所有的实时音视频操作都是异步的, 而且这些操作会触发实时音视频的某些事件, 具体事件会在各个操作里面详细介绍.

发起音视频呼叫

const switchToAudioIfNoVideoDevice = true
let type = WebRTC.NETCALL_TYPE_AUDIO
let callTimer

  netcall.call({
    type,
    account: 'callee',
    pushConfig: {
      // enable: true,
      // needBadge: true,
      // needPushNick: true,
      pushContent: '推送内容',
      custom: JSON.stringify({
        key: 'value'
      })
    },
    sessionConfig: {

    }
  }).then(obj => {
    console.log('call success', obj)
    // 设置超时计时器
    callTimer = setTimeout(() => {
      if (!netcall.callAccepted) {
        console.log('超时未接听, hangup')
        hangup()
      }
    }, 1000 * 30)
  }, err => {
    // 被叫不在线
    if (err.code === 11001) {
      console.log('callee offline', err)
    }
  })

清理音视频呼叫超时计时器

clearCallTimer () {
  clearTimeout(callTimer)
}

挂断音视频通话

function resetWhenHangup () {
  beCalledInfo = null
  beCalling = false
  clearCallTimer()
  netcall.stopLocalStream()
  netcall.stopRemoteStream()
  netcall.stopDeviceAudioIn()
  netcall.stopDeviceAudioOutLocal()
  netcall.stopDeviceAudioOutChat()
  netcall.stopDeviceVideo()
},
function hangup () {
  netcall.hangup()
  resetWhenHangup()
},

监听挂断音视频通话

当一方挂断之后, 另一方会收到 hangup 事件, 此时做一些清理工作即可

netcall.on('hangup', obj => {
  console.log('on hangup', obj)
  resetWhenHangup()
})

被呼叫

被叫用户在初始化实时音视频之后可以监听被呼叫的事件, 然后展示接听和挂断按钮

let beCalling = false
let beCalledInfo = null
netcall.on('beCalling', obj => {
  console.log('on beCalling', obj)
  // 获取通话标识符 channelId, 每一通会话的 channelId 都不一样
  const {channelId} = obj
  // 通知对方自己已经收到此次通话的请求
  netcall.control({
    channelId,
    command: WebRTC.NETCALL_CONTROL_COMMAND_START_NOTIFY_RECEIVED
  })
  // 只有在没有通话并且没有被叫的时候才记录被叫信息, 否则直接挂断
  if (!netcall.calling && !beCalling) {
    beCalling = true
    beCalledInfo = obj
  } else {
    // 通知呼叫方我方繁忙
    netcall.control({
        channelId: channelId,
        command: Netcall.NETCALL_CONTROL_COMMAND_BUSY
    });
  }
})

拒绝音视频被呼叫

可以先通知对方自己忙, 拒绝的时候需要回传在 beCalling 事件里面接收到的对象

netcall.control({
  channelId: beCalledInfo.channelId,
  command: WebRTC.NETCALL_CONTROL_COMMAND_BUSY
})
netcall.response({
  accepted: false,
  beCalledInfo: beCalledInfo
})
beCalledInfo = null
beCalling = false

监听拒绝音视频被呼叫

当被叫拒绝音视频被呼叫之后, 主叫会收到 callRejected 事件, 一般来讲需要进行如下操作

netcall.on('callRejected', obj => {
  console.log('on callRejected', obj)
  clearCallTimer()
})

接听音视频被呼叫

beCalling = false
netcall.response({
  accepted: true,
  beCalledInfo: beCalledInfo,
  sessionConfig: sessionConfig
}).catch(err => {
  netcall.control({
    channelId: beCalledInfo.channelId,
    command: WebRTC.NETCALL_CONTROL_COMMAND_BUSY
  })
  hangup()
  beCalledInfo = null
  console.log('接听失败', err)
})

监听接听音视频被呼叫

netcall.on('deviceStatus', obj => { console.log('on deviceStatus', obj) })

netcall.on('joinChannel', obj => { console.log('on joinChannel', obj) netcall.startRemoteStream() })


### <span id="WebRTC_监听音视频被叫操作多端同步通知">监听音视频被叫操作多端同步通知</span>

假如你在多台设备上登录了同一个账号, 此时如果被呼叫, 那么所有的设备都会收到 `beCalling` 事件, 当你在某台设备接听或者拒绝之后, 其它设备会收到这个操作的通知, 名字叫 `callerAckSync`, 收到此事件后一般来讲需要隐藏相应的被呼叫界面

```js
netcall.on('callerAckSync', obj => {
  console.log('on callerAckSync', obj)
  if (beCalledInfo && obj.channelId === beCalledInfo.channelId) {
    beCalledInfo = false
    beCalling = false
  }
})

设置自己画面的尺寸

最终显示的画面不大于所设置的宽和高 裁剪: cut: true(默认值), 画面按照提供的宽高等比例居中裁剪,返回裁剪后的实际大小 cut: false, 画面不进行裁剪, 返回按原始比例放大缩小后的实际宽高

netcall.setVideoViewSize({
  width: 300,
  height: 300,
  cut: true
})

设置对方画面的尺寸

最终显示的画面不大于所设置的宽和高 裁剪: cut: true(默认值), 画面按照提供的宽高等比例居中裁剪,返回裁剪后的实际大小 cut: false, 画面不进行裁剪, 返回按原始比例放大缩小后的实际宽高

netcall.setVideoViewRemoteSize({
  width: 300,
  height: 300,
  cut: true
})

启动麦克风设备

可以传入 device 参数来指定开启某个特定设备; 如果不传 device 参数, 那么默认启动第一个此类设备

function startDeviceAudioIn () {
  return netcall.startDevice({
    type: WebRTC.DEVICE_TYPE_AUDIO_IN,
    device
  }).then(() => {
    // 通知对方自己开启了麦克风
    netcall.control({
      command: WebRTC.NETCALL_CONTROL_COMMAND_NOTIFY_AUDIO_ON
    })
  }).catch(() => {
    console.log('启动麦克风失败')
  })
}

停止麦克风设备

function stopDeviceAudioIn () {
  return netcall.stopDevice(WebRTC.DEVICE_TYPE_AUDIO_IN).then(() => {
    // 通知对方自己关闭了麦克风
    netcall.control({
      command: WebRTC.NETCALL_CONTROL_COMMAND_NOTIFY_AUDIO_OFF
    })
  })
}

启动播放自己声音的设备

可以传入 device 参数来指定开启某个特定设备; 如果不传 device 参数, 那么默认启动第一个此类设备

function startDeviceAudioOutLocal () {
  return netcall.startDevice({
    type: WebRTC.DEVICE_TYPE_AUDIO_OUT_LOCAL,
    device
  }).catch(() => {
    console.log('播放自己的声音失败')
  })
}

停止播放自己声音的设备

function stopDeviceAudioOutLocal () {
  return netcall.stopDevice(WebRTC.DEVICE_TYPE_AUDIO_OUT_LOCAL)
}

启动播放对方声音的设备

可以传入 device 参数来指定开启某个特定设备; 如果不传 device 参数, 那么默认启动第一个此类设备

function startDeviceAudioOutChat () {
  return netcall.startDevice({
    type: WebRTC.DEVICE_TYPE_AUDIO_OUT_CHAT,
    device
  }).catch(() => {
    console.log('播放对方的声音失败')
  })
}

停止播放对方声音的设备

function stopDeviceAudioOutChat () {
  return netcall.stopDevice(WebRTC.DEVICE_TYPE_AUDIO_OUT_CHAT)
}

启动摄像头设备

可以传入 device 参数来指定开启某个特定设备; 如果不传 device 参数, 那么默认启动第一个此类设备

function startDeviceVideo () {
  return netcall.startDevice({
    type: WebRTC.DEVICE_TYPE_VIDEO
  }).then(() => {
    // 通知对方自己开启了摄像头
    netcall.control({
      command: WebRTC.NETCALL_CONTROL_COMMAND_NOTIFY_VIDEO_ON
    })
  }).catch(() => {
    // 通知对方自己的摄像头不可用
    netcall.control({
      command: WebRTC.NETCALL_CONTROL_COMMAND_SELF_CAMERA_INVALID
    })
    console.log('启动摄像头失败')
  })
}

停止摄像头设备

stopDeviceVideo () {
  return netcall.stopDevice(WebRTC.DEVICE_TYPE_VIDEO).then(() => {
    // 通知对方自己关闭了摄像头
    netcall.control({
      command: WebRTC.NETCALL_CONTROL_COMMAND_NOTIFY_VIDEO_OFF
    })
  })
}

是当前会话的channelId

// obj 需包含 channelId 属性
netcall.isCurrentChannelId(obj)

不是当前会话的channelId

// obj 需包含 channelId 属性
netcall.notCurrentChannelId(obj)

获取指定类型的所有设备

此接口返回 Promise, 可选类型有

netcall.getDevicesOfType(type)

开始WebRtc音视频连接

开始建立WebRTC连接,发送和接收音视频数据

netcall.startRtc().then(()=>{
  // todo
}).catch(err=>{
  console.log(err)
})

开启本地视频流

开启之后, 会显示自己的视频数据

netcall.startLocalStream()

停止本地视频流

停止之后, 会停止显示自己的视频数据

netcall.stopLocalStream()

开启远程视频流

开启之后, 会显示对方的视频数据 多人会议需要传入目标account或者uid和node节点

// 这里传入account或者uid都可以
netcall.startRemoteStream({
  // account: obj.account
  uid: obj.uid,
  node: document.querySelector('#video')
})

停止远程视频流

停止之后, 会停止显示对方的视频数据 多人会议需要传入目标account或者uid

// 这里传入account或者uid都可以
netcall.stopRemoteStream({
  // account: obj.account
  uid: obj.uid
})

暂停播放自己的视频画面

netcall.suspendLocalStream()

继续播放自己的视频画面

netcall.resumeLocalStream()

暂停播放对方的视频画面

多人会议需要传入目标account或者uid

// 这里传入account或者uid都可以
netcall.suspendRemoteStream({
  // account: obj.account
  uid: obj.uid
})

继续播放对方的视频画面

多人会议需要传入目标account或者uid

// 这里传入account或者uid都可以
netcall.resumeRemoteStream({
  // account: obj.account
  uid: obj.uid
})

发送音视频通话控制指令

netcall.control({
  channelId,
  command: WebRTC.NETCALL_CONTROL_COMMAND_NOTIFY_AUDIO_ON
})

监听音视频通话控制指令

netcall.on('control', obj => {
  // 如果不是当前通话的指令, 直接丢掉
  if (netcall.notCurrentChannelId(obj)) {
    return
  }
  console.log('on control', obj)
  const {type} = obj
  switch (type) {
    // NETCALL_CONTROL_COMMAND_NOTIFY_AUDIO_ON 通知对方自己打开了音频
    case WebRTC.NETCALL_CONTROL_COMMAND_NOTIFY_AUDIO_ON:
      console.log('对方打开了音频')
      break
    // NETCALL_CONTROL_COMMAND_NOTIFY_AUDIO_OFF 通知对方自己关闭了音频
    case WebRTC.NETCALL_CONTROL_COMMAND_NOTIFY_AUDIO_OFF:
      console.log('对方关闭了音频')
      break
    // NETCALL_CONTROL_COMMAND_NOTIFY_VIDEO_ON 通知对方自己打开了视频
    case WebRTC.NETCALL_CONTROL_COMMAND_NOTIFY_VIDEO_ON:
      console.log('对方打开了视频')
      break
    // NETCALL_CONTROL_COMMAND_NOTIFY_VIDEO_OFF 通知对方自己关闭了视频
    case WebRTC.NETCALL_CONTROL_COMMAND_NOTIFY_VIDEO_OFF:
      console.log('对方关闭了视频')
      break
    // NETCALL_CONTROL_COMMAND_SWITCH_AUDIO_TO_VIDEO 请求从音频切换到视频
    case WebRTC.NETCALL_CONTROL_COMMAND_SWITCH_AUDIO_TO_VIDEO:
      agreeSwitchAudioToVideo()
      break
    // NETCALL_CONTROL_COMMAND_SWITCH_AUDIO_TO_VIDEO_REJECT 拒绝从音频切换到视频
    case WebRTC.NETCALL_CONTROL_COMMAND_SWITCH_AUDIO_TO_VIDEO_REJECT:
      break
    // NETCALL_CONTROL_COMMAND_SWITCH_AUDIO_TO_VIDEO_AGREE 同意从音频切换到视频
    case WebRTC.NETCALL_CONTROL_COMMAND_SWITCH_AUDIO_TO_VIDEO_AGREE:
      switchAudioToVideo()
      break
    // NETCALL_CONTROL_COMMAND_SWITCH_VIDEO_TO_AUDIO 从视频切换到音频
    case WebRTC.NETCALL_CONTROL_COMMAND_SWITCH_VIDEO_TO_AUDIO:
      switchVideoToAudio()
      break
    // NETCALL_CONTROL_COMMAND_BUSY 占线
    case WebRTC.NETCALL_CONTROL_COMMAND_BUSY:
      console.log('对方忙')
      break
    // NETCALL_CONTROL_COMMAND_SELF_CAMERA_INVALID 自己的摄像头不可用
    // NETCALL_CONTROL_COMMAND_SELF_ON_BACKGROUND 自己处于后台
    // NETCALL_CONTROL_COMMAND_START_NOTIFY_RECEIVED 告诉发送方自己已经收到请求了(用于通知发送方开始播放提示音)
  }
})

/*
 * 音视频切换示例函数 begin
 */

function askSwitchVideoToAudio () {
  // 通知对方从视频切换到音频, 不需要同意直接切
  this.netcall.control({
    command: WebRTC.NETCALL_CONTROL_COMMAND_SWITCH_VIDEO_TO_AUDIO
  })
  switchVideoToAudio()
}
function switchVideoToAudio () {
  stopDeviceVideo()
  netcall.stopLocalStream()
  netcall.stopRemoteStream()
  netcall.switchVideoToAudio()
}
function askSwitchAudioToVideo () {
  // 请求从音频切换到视频
  netcall.control({
    command: WebRTC.NETCALL_CONTROL_COMMAND_SWITCH_AUDIO_TO_VIDEO
  })
}
function agreeSwitchAudioToVideo () {
  // 同意从音频切换到视频
  netcall.control({
    command: WebRTC.NETCALL_CONTROL_COMMAND_SWITCH_AUDIO_TO_VIDEO_AGREE
  })
  switchAudioToVideo()
}
function switchAudioToVideo () {
  startDeviceVideo().then(function() {
    netcall.startLocalStream()
  }.bind(this)).then(function() {
    return netcall.switchAudioToVideo();
  }.bind(this)).then(function(){
    netcall.startRemoteStream()
  }.bind(this)).catch(function(e) {
    console.log(e);
  })
}

/*
 * 音视频切换示例函数 end
 */

从视频模式切换为音频模式

netcall.switchVideoToAudio()

从音频模式切换为视频模式

netcall.switchAudioToVideo()

设置会话的视频质量

设置会话的视频质量, 可选视频质量有

netcall.setSessionVideoQuality(WebRTC.CHAT_VIDEO_QUALITY_NORMAL)

设置会话的视频帧率

设置会话的视频帧率, 可选视频帧率有

netcall.setSessionVideoFrameRate(WebRTC.CHAT_VIDEO_FRAME_RATE_NORMAL)

设置采集音量

实时设置己方音频采集大小, 0-255

netcall.setCaptureVolume(100)

设置播放音量

设置对方音量播放大小, 0-255 多人会议需要传入目标account或者uid

netcall.setPlayVolume({
  account: 'testaccount'
  volume: 100
})

设置目标静音

设置后,不能听到目标声音 多人会议需要传入目标account,不设置则操作所有远程流

netcall.setAudioBlack(account)

设置目标非静音

设置后,能听到目标声音 多人会议需要传入目标account,不设置则操作所有远程流

netcall.setAudioStart(account)

显示目标画面

设置后,能看到目标视频画面 多人会议需要传入目标account,不设置则操作所有远程流

netcall.setVideoShow(account)

禁止显示目标画面

设置后,不能看到目标视频画面 多人会议需要传入目标account,不设置则操作所有远程流

netcall.setVideoBlack(account)

开启video录制

录制目标帐号的视频和音频,不传参则录制当前登录帐号的视频和音频 目前只支持webm格式的视频,可以用chrome浏览器打开

netcall.startRecordMp4({account:account}).then(function(){
  // todo
}).catch(function(){
  // todo
})

停止video录制

结束视频和音频录制,弹框选择保存本地

netcall.stopRecordMp4().then(function(){
  // todo
}).catch(function(){
  // todo
})

开启混音录制

混合本地和所有远程音频流,进行录制并保存 目前只支持webm格式的音频,可以用chrome浏览器打开

netcall.startRecordAac().then(function(){
  // todo
}).catch(function(){
  // todo
})

停止混音录制

结束混音录制,弹框选择保存本地

netcall.stopRecordAac().then(function(){
  // todo
}).catch(function(){
  // todo
})

开启多人会议

与点对点通话的流程不同,多人会议暂不支持呼叫、推送和挂断等服务,只提供基本的预订、加入和离开会议接口。 目前呼叫方案可以参照demo使用点对点通知发送呼叫

预订会议
this.netcall.createChannel({
  channelName: channelName //必填
  custom: custom //可选
}).then(function(obj) {
  // 预定会议成功后的上层逻辑操作
  // eg: 初始化会议UI显示
  // eg: 加入会议
}).catch(function(err){
  // todo
})

需要先预订,本人和其他人才能加入会议。

会议通过 channelName 字段做标识;可以通过扩展字段 custom 在会议的创建和加入之间传递自定义的额外信息。

同一个会议名称,只在会议使用完并且房间被销毁(所有人都离开房间)以后才可以重复使用,开发者需要保证不会出现重复预订某会议名称而不使用的情况。

预定结果通过promise的then和catch捕捉

加入会议
netcall.joinChannel({
  channelName: channelName,
  sessionConfig: sessionConfig
}).then(function(obj) {
  // 加入会议成功后的上层逻辑操作
  // eg: 开启摄像头
  // eg: 开启麦克风
  // eg: 开启本地流
  // eg: 设置音量采集、播放
  // eg: 设置视频画面尺寸等等,具体请参照p2p呼叫模式
  // 下面为示例代码
  console.log('joinChannel', obj)
  if (this.role === 'player') {
    changeRoleToPlayer()
  } else {
    changeRoleToAudience()
  }

  var promise;
  if (obj.type === WebRTC.NETCALL_TYPE_VIDEO) {
    promise = startDeviceVideo()
  } else {
    promise = stopDeviceVideo()
  }
  promise.then(function () {
    setVideoViewSize()
    return startDeviceAudioIn();
  }.bind(this)).then(function () {
    setCaptureVolume()
  }.bind(this)).then(function () {
    addLog("开始webrtc连接")
    return webrtc.startRtc();
  }.bind(this)).then(function () {
    addLog("webrtc连接成功")
    return startDeviceAudioOutChat();
  }.bind(this)).catch(function (e) {
    addLog("连接出错");
    console.error(e);
    hangup()
  }.bind(this))
}).catch(function(err) {
  console.error('joinChannelErr', err)
})

参数解读

channelName: 会议id(必填)
type: 通话类型(音频还是视频)
sessionConfig 会话配置,具体请参考API文档
{
  videoQuality 视频分辨率
  videoFrameRate 视频帧率
  highAudio=false 高清语音开关, 默认关闭
}

加入会议结果通过promise的then和catch捕捉

离开会议
netcall.leaveChannel().then(function(obj) {
  // 离开会议后的扫尾工作
})
改变自己在会议中的角色
// 观众切换到互动者
netcall.changeRoleToPlayer().then(function(obj) {
  // todo
})

// 互动者切换到观众
netcall.changeRoleToAudience().then(function(obj) {
  // todo
})

开启互动直播

多人模式中可以进行互动直播, 前提条件:

  1. 创建房间后以主播身份加入房间, 后续的连麦者才能加入房间, 否则连麦者直接加入房间失败
// 创建房间
netcall.createChannel({
  channelName: this.channelName,
  custom: this.channelCustom
}).then(function(obj) {
  console.log('createChannel', obj)
}).catch(function(err) {
  console.log('createChannelErr', err)
})

// 主播加入房间
netcall.joinChannel({
  channelName: this.channelName,
  type: WebRTC.NETCALL_TYPE_VIDEO,
  liveEnable: true, // 开启互动直播
  sessionConfig: {
    isHost: true, //是否是主播,
    bypassRtmp: true, //是否开启推流开关
    rtmpRecord: true, //是否开启推流录制开关
    rtmpUrl: '推流地址', //主播必须设置
    splitMode: '主播和连麦者的布局模式', // 主播必须设置
    layout: '自定义布局模式'
  }
}).then(function(obj) {
  console.log('joinChanel', obj)
}).catch(function(err) {
  console.log('createChannelErr', err)
})

// 连麦者加入房间
netcall.joinChannel({
  channelName: this.channelName,
  type: WebRTC.NETCALL_TYPE_VIDEO,
  liveEnable: true, // 开启互动直播
  sessionConfig: {
    isHost: false, //非主播,必须设置false,
    bypassRtmp: true, //是否开启推流开关
    rtmpRecord: true //是否开启推流录制开关
  }
}).then(function(obj) {
  console.log('joinChanel', obj)
}).catch(function(err) {
  console.log('createChannelErr', err)
})

监听各种信息事件


// 通话过程中,WebRTC连接断开
netcall.on('rtcConnectFailed', function(event) {

})

// 设备列表
netcall.on('devices', function(devices) {

})

// 设备列表发生变化
netcall.on('deviceStatus', function(devices) {

})

// 发现新设备
netcall.on('deviceAdd', function(devices) {

})

// 有设备被移除
netcall.on('deviceRemove', function(devices) {

})

// 音量监控
netcall.on('audioVolume', function(obj) {

})

// 有人加入多人会议房间
netcall.on('joinChannel', function(obj) {

})

// 有人离开多人会议房间
netcall.on('leaveChannel', function(obj) {

})
×

反馈成功

非常感谢您的反馈,我们会继续努力做得更好。