云信小课堂 | 音视频Web端通话前快速实现网络和设备状态检测能力

4d7a85d1af482c49a50c86702bb8da71.png

Vol. 16

62cd6c89b32d9b278deb630a66884a7b.png

在网络会议、重要直播等对音视频通话质量等要求较高的场景下,需要在通话前进行调试,例如可以进行设备检测以提前做好设备管理,或者探测网络质量以提前识别网络问题。NERTC SDK 提供通话前设备检测和网络探测的相关接口与回调方法,帮助您保证高质量的音视频通话体验。

视频讲解

 10 分钟视频详解,手把手教你接入

具体步骤

通过创建 UpClient 实例和对应的本地音视频流,以检测麦克风、摄像头、扬声器等设备的表现是否正常;通过创建 UpClient 和 DownClient 两个实例,分别模拟上/下行用户进入虚拟房间进行推拉流,以检测上行和下行网络质量,并最终判断当前网络环境的平均质量,整个过程大概花 30s 左右。

API 调用时序

e2163039c715052482b6a54a358ddde4.png

(点击放大)

一、设备检测

在您的浏览器页面进行相关检测前,请先在该页面引入 NERTC Web SDK,具体请参考集成 SDK。(https://doc.yunxin.163.com/nertc/docs/DM3MDA4NzQ?platform=web)

实现方法

1、调用 createStream 方法创建 client 实例。示例代码如下:

let upClient=null;
let downClient=null;
let localStream=null;
let remoteStream=null;
let audioDevices=null;
let videoDevices=null;
let audioOutDevices=null;
let intervalA=null;
let intervalB=null;
upClient = NERTC.createClient({
    appkey: '', //您的 appkey
    debug: true, //是否开启调试日志
});
2、调用 getDevices 方法获取本地麦克风、摄像头和扬声器设备列表。示例代码如下:
function deviceInit(){
    //确认浏览器是否符合要求
    if (!NERTC.checkSystemRequirements()) {
    alert("browser is no support webRTC");
    }
    NERTC.getDevices().then(function(devices){
        audioDevices = devices.audioIn;  //数组,麦克风设备列表,包含deviceId和label信息,网页上展示设备label信息供用户选择,实际测试时传入deviceId来打开设备确认设备是否可用
        videoDevices = devices.video;  //摄像头设备列表
        audioOutDevices = devices.audioOut; //扬声器列表
        console.log(audioDevices[0].deviceId, audioDevices[0].label);//测试打印出设备id等信息
        console.log(videoDevices[0].deviceId, videoDevices[0].label);
    }).catch(function(err){
        console.warn(err);
    })
}

( 因浏览器的安全隐私政策,若您使用的是 Chrome(81+)、Safari 或 Firefox 浏览器,则需要在获取媒体设备权限后才能获取设备 ID。简单通俗的理解:Chrome/Firefox等浏览器只要在当前页面执行过打开设备(对应stream.init()的能力)即可枚举出真正的设备Id和设备名;如果之前没有打开过设备,那枚举到的deviceId会为"",设备名可能是""或者microphone 1、camera 1这种代称;所以建议在第一次打开对应的网页枚举设备时,拿到的deviceId是什么就传入什么,就算是空字符串也没关系,浏览器会去选择第一个默认设备去打开的;Safari浏览器只有在当前页面执行一次getUserMedia(也就是Stream.init)之后才能够枚举到真正的设备Id和设备名;

设备 ID 为随机生成,部分情况下同一个设备的 ID 可能会改变,因此建议您在每次测试设备时均先调用 getDevices 方法获取最新的设备 ID。)

3、打开对应的设备以确认设备是否可以正常使用

  • 创建音频流,获取音频流音量,以检测麦克风表现是否正常。

  • 打开摄像头,以检测摄像头表现是否正常。

  • 选择扬声器设备播放音乐,以检测扬声器表现是否正常。

  • 切换麦克风和摄像头测试。

function streamCreate(){
    //监听设备相关异常
    upClient.on("accessDenied",function(evt){
        console.log("accessDenied"+JSON.stringify(evt));
    })
    upClient.on("notFound",function(evt){
        console.log("notFound"+JSON.stringify(evt));
    })
    upClient.on("deviceError",function(evt){
        console.log("deviceError"+JSON.stringify(evt));
    })
    upClient.on("beOccupied",function(evt){
        console.log("beOccupied"+JSON.stringify(evt));
    })
//1.创建音频流
    localStream = NERTC.createStream({
        uid: 112211,//传入随机字符串即可,和join时的uid对应
        audio: true,
        microphoneId: audioDevices[0].deviceId, //指定要开启的mic,填入获取到的deviceId
        video: false,
    });
    //init失败时,会通过upClient上的accessDenied、notFound、deviceError、beOccupied这几个监听事件通知
    localStream.init().then(function(){
        intervalA=setInterval(function(){
            console.log("获取mic采集的音量:"+localStream.getAudioLevel());//音量范围是0~1,大于0.1就表示音量比较正常
        //在UI层动态展示获取到的音量,让终端用户确认音量条是否变化
        //如果出现因设备本身问题导致音量一直为0或者无法打开设备的情况,可以使用WebRTC官方的demo验证这个结论的准确性 https://webrtc.github.io/samples/src/content/devices/input-output/
        //用于播放音视频的div元素
        }, 2000);
//2.打开摄像头
      let createDivL=document.createElement("div");  
      createDivL.id="NE_local";  
      createDivL.style.width='640px';  
      createDivL.style.height='480px';  
      document.body.appendChild(createDivL)
      let divL = document.getElementById('NE_local')
      localStream.open({type: "video",deviceId: videoDevices[0].deviceId,type:'video'}).then(function(){
          console.log("摄像头打开成功");//打开成功后才能去做切换、关闭摄像头的操作
          localStream.play(divL, { audio:false,video: true}).then((evt)=>{
            console.log("播放成功");//把视频画面渲染到页面上,让用户确认视频画面内容是否正常
          }).catch((evt)=>{
            console.log(evt);
          });
          localStream.setLocalRenderMode({
            width: 640,
            height: 480,
            cut: false
          })
      });
//3.选择扬声器设备播放音乐;步骤:1)调用setSinkId选择扬声器设备;2)创建一个audio标签播放音乐
    document.getElementById("audio").setSinkId(audioOutDevices[0].deviceId).then(function() { ... })
    }).catch(function(evt){
          console.log(evt);
      });
}
//4.切换麦克风和摄像头测试
function switchDevice(){
    //UI上展示设备名称,用户选择设备名称之后拿到对应的设备deviceId来进行切换操作
    //switchDevice的优势是比close+open更方便,快速切换摄像头或者麦克风;劣势是调用之前需要确保麦克风或者摄像头已经打开;并且部分移动端由于无法同时开启两个摄像头,调用switchDevice会失败,这种情况建议使用close+open的组合
    localStream.switchDevice("video", videoDevices[1].deviceId).then(function(){
        console.log('设备切换成功');  
    }).catch(function(err){
    console.log(err)
    await localStream.close({ type: "video"});//关闭摄像头,如果需要切换分辨率,关闭之后再次设置setVideoProfile
    await localStream.open({ type: "video",deviceId:videoDevices[1].deviceId});//开启摄像头,open里面也可以设置facingMode
    })
}

 二、网络探测

实现方法

具体网络质量数值说明请参考 network-quality。

(https://doc.yunxin.163.com/docs/interface/NERTC_SDK/Latest/Web/api/enums/types.networkstatus.html)

1、upClient 加入房间并推流。

function upClientPub(){      
        //监听用户实际网络质量
        upClient.on("network-quality",function(evt){
            console.log("network-quality"+JSON.stringify(evt));//检测用户上行的网络质量
        })
        upClient.join({
            channelName: "TEST",//RTC房间名
            uid: 112211, 
            token: "" //调试模式下传空即可
        }).then(function () {
            console.log('upClient加入房间成功...');//此时表示用户TCP网络正常长链接建立成功
            upClient.publish(localStream).then(function() {
                console.log('本地 publish 成功');
                intervalB=setInterval(function(){
                upClient.getTransportStats().then(function(stat){
                        console.log(stat); //获取本地网络上行预估带宽、RTT,根据这个结果判断用户UDP网络状态
                    })
                }, 2000);
            }).catch(function(err){
                console.warn(err)
            });
        }).catch(function (err) {
            console.log(err);
        });
}

2、downClient 加入房间并拉流。

function downClientSub(){
    downClient= NERTC.createClient({
        appkey: '', //您的 App key
        debug: true, //是否开启调试日志
    });
    downClient.on("network-quality",function(evt){
        console.log("network-quality"+JSON.stringify(evt));//检测用户下行的网络质量
    })
    downClient.join({
            channelName: "TEST",//RTC房间名,加入同一个房间拉流
            uid:112233, //随机用户Id
            token: "" //调试模式下传空即可
        }).then(function () {
            console.log('接收方加入房间成功...');        
        }).catch(function (err) {
            console.log(err);
        });
    //回调事件-远端用户已发流
    downClient.on('stream-added', function (evt) {
        console.log("远端有流来: " + evt.mediaType);
        remoteStream =evt.stream;
        remoteStream.setSubscribeConfig({
            audio: true,
            video: true
        });
        downClient.subscribe(remoteStream, function(){
            console.log("Subscribe stream success");
        },function (err) {
            console.log("Subscribe stream failed", err);
        });
    });
    //回调事件-远端音视频流已订阅
    downClient.on('stream-subscribed', function (evt) {
        console.log('订阅远端流成功');
        //渲染订阅到的视频流(可选)
        let createDivR=document.createElement("div");  
        createDivR.id="NE_remote";  
        createDivR.style.width='640px';  
        createDivR.style.height='480px';  
        document.body.appendChild(createDivR)
        let divRemote = document.getElementById('NE_remote');
        evt.stream.play(divRemote,{audio:true,video:true}).then(() => {
            console.log('播放对端视频流成功');           
        })
        evt.stream.setRemoteRenderMode({
            width: 640,
            height: 480,
            cut: false    //是否裁剪
        },'video');
    })
}

(您可以选择不渲染订阅的视频流,只通过 network-quality 判断下行网络的等级;但建议您将订阅的视频流渲染至画布上,以模拟较为真实的音视频通话过程,从而对当前网络状况得出更真实的判断,同时您可以调用 getRemoteAudioStats 和 getRemoteVideoStats 方法以获取更全面的统计数据。

建议将推拉流过程的时长设置为 20s 左右,以取平均网络质量数据,从而大致判断出上下行网络情况。)

3、检测 20s 左右之后完成检测,并及时销毁实例。

function destroy(){
      clearInterval(intervalA);
      clearInterval(intervalB);
      upClient.leave().then(function() {
        console.log('upClient leave成功');
      }).catch(function(err){  
        console.log(err);
      });
      downClient.leave().then(function() {
        console.log('downClient leave成功');
      }).catch(function(err){  
        console.log(err);
      });  
}

network-quality 详细值说明

在注册 on("network-quality") 网络质量监听回调后,您可以通过回调中的数值判断当前的网络状况。具体说明如下表。

数值

网络质量水平

说明

0

UNKNOWN

网络状况未知,表示当前 client 实例还没有成功建立上行/下行连接

1

EXCELLENT

网络状况极佳

2

GOOD

网络状况较

3

POOR

网络状况一般

4

BAD

网络状况差

5

VERYBAD

网络状况极差

6

DOWN

网络连接已断开

建议当 network-quality 的数值大于 3 时,您可以检查网络并尝试更换网络环境,以保证正常的音视频通话。您也可以通过降低分辨率/帧率来降低带宽消耗,减少数据传输压力。

视频中演示的完整 DEMO github 地址:https://github.com/dongsettle/troubleTool_yunxin

以上就是我们本期《云信小课堂》的内容,我们下期见!

「云信小课堂」推荐阅读

👇快速接入指南👇

(点击即可快速跳转)

音视频通话 | 构建本土「Clubhouse」

安卓端 PK 连麦 | iOS 端 PK 连麦

在线聊天室 | 聊天室内容审核

利用 UI 组件实现应用级别在线聊天室

协同办公系统 | 音视频安全检测

6b11f98b17f88bb56c10d54f9e86b3c2.png

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值