diff --git a/public/CHANGELOG.md b/public/CHANGELOG.md new file mode 100644 index 0000000..a999f40 --- /dev/null +++ b/public/CHANGELOG.md @@ -0,0 +1,287 @@ +# TRTC Web SDK 版本发布日志 + +- 版本号规则:[major.minor.patch] + - major:主版本号,如有重大版本重构则该字段递增,通常各主版本间接口不兼容。 + - minor:次版本号,各次版本号间接口保持兼容,如有接口新增或优化则该字段递增。 + - patch:补丁号,如有功能改善或缺陷修复则该字段递增。 +- 我们建议您及时更新到最新版本以便获得更好的产品稳定性及在线支持! + +## 4.6.6 (2020-10-23) + +**Improvement** + +- 优化上行 peerConnection 重连逻辑 +- 优化下行 peerConnection 重连逻辑 +- 优化 TRTC.checkSystemRequirements 检测逻辑 +- 支持 Safari 屏幕分享,参考:[屏幕分享使用教程](https://trtc-1252463788.file.myqcloud.com/web/docs/tutorial-06-advanced-screencast.html) + +**Bug Fixed** + +- 修复因自动播放策略限制,手动恢复音频播放后,getAudioLevel 值为0的问题 + +## 4.6.5(2020-10-14) + +**Improvement** + +- 优化 WebSocket 信令通道重连逻辑,提升连接稳定性 +- 优化日志输出逻辑 + +**Bug Fixed** + +- Chrome 重新订阅后,getAudioLevel 接口返回值为0的问题 +- Safari 重新订阅后,播放无声的问题 +- 使用 replaceTrack 替换上行音频轨道后,getLocalVideoStats 接口返回 undefined 的问题 +- 移动设备通话过程中,切换网络类型,偶现 WebSocket 连接断开的问题 + +## 4.6.4(2020-9-24) + +**Improvement** + +- 退房后停止网络质量统计 + +**Bug Fixed** + +- 修复 Chrome 56 进房报错的问题 +- 修复移动端推旁路出现画面旋转的问题 +- 修复纯音频推流时云端录制异常的问题 +- 修复因分辨率不一致导致摄像头拔出后,自动恢复推流失败的问题 + +## 4.6.3 (2020-8-28) + +**Improvement** + +- 优化兼容性检测逻辑 +- 优化日志上报逻辑 +- 优化上行码率控制逻辑 + +## 4.6.2 (2020-8-14) + +**Improvement** + +- 优化上行码率调控逻辑 +- 优化 switchRole 参数校验逻辑 +- 优化上行网络质量计算逻辑 +- 优化错误提示信息 +- 检测当前推流采集设备变更时,自动恢复推流状态 + +**Bug Fixes** + +- 修复 unpublish 成功后,立即重新 publish 失败报错的问题 + +## 4.6.1 (2020-7-28) + +**Improvement** + +- [TRTC.isScreenShareSupported](https://trtc-1252463788.file.myqcloud.com/web/docs/TRTC.html#.isScreenShareSupported) Safari 不支持屏幕分享 +- 完善 subscribe & unsubscribe 接口的参数校验逻辑 +- 增加网络质量日志 + +**Bug Fixes** + +- 修复当未授权媒体设备,且 TRTC.createStream 接口传入的设备 ID 为空串时,SDK 报 OverconstrainedError 的问题 +- 修复上行 peerConnection 断开时没有打印日志的问题 + +## 4.6.0 (2020-7-16) + +**Feature** + +- 增加 NETWORK_QUALITY 事件 + +## 4.5.0 (2020-7-2) + +**Feature** + +- createStream 接口增加 screenAudio 参数 + +**Bug Fixes** + +- 修复 Android 浏览器中回声消除不起作用的问题 +- 修复 getTransportStats 接口返回的 rtt 值为 NAN 的问题 + +## 4.4.0 (2020-5-28) + +**Feature** + +- 支持 Chrome >= 74 屏幕分享采集系统(windows)或者当前 Tab 页面(Mac)的声音 + +## 4.3.14 (2020-4-29) + +**Bug Fixes** + +- 修复小程序音频 muted unmute 事件。 + +## 4.3.13 (2020-4-13) + +**Improvement** + +- 优化浏览器可用性检测 + +## 4.3.12 (2020-4-13) + +**Bug Fixes** + +- 修复一个潜在的RTCPeerConnection状态变化异常 + +## 4.3.11 (2020-3-28) + +**Improvement** + +- 增加手机 QQ 浏览器检测,手机 QQ 浏览器暂时无法支持 WebRTC + +**Bug Fixes** + +- 修复 Boolean 返回值类型 + +## 4.3.10 (2020-3-17) + +**Improvement** + +- 优化环境检测逻辑 +- RtcError 增加 name code + +## 4.3.9 (2020-3-13) + +**Improvement** + +- 增加部署环境自动检测 +- 优化日志 + +## 4.3.8 (2020-2-24) + +**Improvement** + +- createClient 增加 streamId userdefinerecordid 字段 + +## 4.3.7 (2020-2-21) + +**Improvement** + +- 屏幕分享时切换设备抛出异常。 + +**Bug Fixes** + +- 切换设备时释放 MediaStream,解决设备占用问题。 +- 订阅接口增加处理潜在错误。 + +## 4.3.6 (2020-2-5) + +**Bug Fixes** + +- 调整 Stream.resume() 音视频播放顺序,修复 iOS 上微信浏览器自动播放异常问题。 + +## 4.3.5 (2020-2-5) + +**Improvement** + +- 增加 publish 超时检查,提高信令发送成功率。 + +## 4.3.4 (2020-1-6) + +**Improvement** + +- 升级 core-js 至 v3.6.1。 + +**Bug Fixes** + +- unpublish 超时后向外部抛出异常事件。 +- 修复第三方库引起 V8 负优化问题。 + +## 4.3.3 (2019-12-25) + +**Improvement** + +- 增加主动检测环境是否支持 webrtc 能力。 +- 优化 sdp 响应机制。 +- 优化上报逻辑。 + +**Bug Fixes** + +- 修复 turn url 协议格式。 + +## 4.3.2 (2019-12-09) + +**Improvement** + +- 增加下行连接 ICE 断开自动重连机制。 +- 去除 STUN 打洞环节,增加内网用户连接成功率及提高连接速度。 +- 日志上报时间戳统一使用服务器校正后的 UTC 时间。 +- 优化 ICE 错误上报。 +- 增加更多关键事件上报到 avmonitor 监控。 + +**Bug Fixes** + +- 修复 WebSocket 信令通道 1005 异常重连及重连错误处理。 +- 修复下行丢包率上报问题。 + +## 4.3.1 (2019-11-23) + +**Improvement** + +- 增加通话过程中上行链路 ICE 断开自动重连机制。 + +**Bug Fixes** + +- 修复 STUN 打洞失败后 host 公网 IP 类型 ICE Candidate 不生效问题。 + +## 4.3.0(2019-11-15) + +**Feature** + +增加 Client.getTransportStats() API。 + +**Improvement** + +- 增加更详细的上报日志。 +- 事件解除绑定支持通配符。 +- 增加连接超时时间至 5s。 +- 增加发布超时时间至 5s。 + +**Bug Fixes** + +修复因 zone.js 修改原型链导致 SDK 判断异常的问题。 + +## 4.2.0(2019-11-04) + +**Feature** + +- 增加 Client.off() 接口取消客户端事件绑定。 + +**Improvement** + +- 通话状态统计优化。 +- Client.publish() 增加权限检查。 +- Stream.play()/resume() 增加自动播放错误提示。 + +**Bug Fixes** + +- LocalStream.switchDevice() 切换摄像头黑屏问题修复。 + +## 4.1.1(2019-10-24) + +**Bug Fixes** + +- 修复日志丢失问题。 +- 修复断网重连远端用户丢失问题。 + +## 4.1.0(2019-10-17) + +**Feature** + +- Stream.play() 接口支持传入 HTMLDivElement 对象。 +- 增加音频码率调控设置,开发者可通过 LocalStream.setAudioProfile() 设置音频属性,目前支持两种 Profile:standard 和 high。 + +**Bug Fixes** + +- 修复旧版本 Chrome 上的 WebAudio Context 数量受限问题。 +- 修复 replaceTrack() 未重启本地音视频播放器问题。 +- 修复 LocalStream.setScreenProfile() 自定义属性设置未生效问题。 +- 修复 audio/video player 重启及状态上报问题。 + +## 4.0.0(2019-10-11) + +TRTC Web SDK (WebRTC) 重构版本,提供 Client/Stream 模式的接口,各对象职责更明确,语义更简洁明了。 +重构版本与旧版本不兼容,除接口改动之外,还提供如下功能: + +- 视频属性 (分辨率、帧率及码率)控制完全由 App 通过 SDK 的 LocalStream.setVideoProfile() 接口设置,不再支持老版本通过腾讯云控制台的“画面设定 (Spear Role)”。 +- SDK 在 Stream 对象中封装了音视频播放器,音视频播放完全由 SDK 控制。 +- 提供远端流的订阅与取消订阅功能,开发者可以通过 Client.subscribe()/unsubscribe() 接口灵活控制远端流的音频、视频或音视频数据流的接收。 diff --git a/public/README.md b/public/README.md new file mode 100644 index 0000000..276a5ad --- /dev/null +++ b/public/README.md @@ -0,0 +1,98 @@ +本文主要介绍如何快速运行腾讯云 TRTC Web SDK Demo。 + +## 支持的平台 + +WebRTC 技术由 Google 最先提出,目前主要在桌面版 Chrome 浏览器、桌面版 Safari 浏览器以及移动版的 Safari 浏览器上有较为完整的支持,其他平台(例如 Android 平台的浏览器)支持情况均比较差。 +- 在移动端推荐使用 [小程序](https://cloud.tencent.com/document/product/647/32399) 解决方案,微信和手机 QQ 小程序均已支持,都是由各平台的 Native 技术实现,音视频性能更好,且针对主流手机品牌进行了定向适配。 +- 如果您的应用场景主要为教育场景,那么教师端推荐使用稳定性更好的 [Electron](https://cloud.tencent.com/document/product/647/38549) 解决方案,支持大小双路画面,更灵活的屏幕分享方案以及更强大而弱网络恢复能力。 + +| 操作系统 | 浏览器类型 | 浏览器最低版本要求 | 接收(播放) | 发送(上麦) | 屏幕分享 | +| :------: | :------------------: | :----------------: | :----------: | :----------: | :-----------------------: | +| Mac OS | 桌面版 Safari 浏览器 | 11+ | 支持 | 支持 | 不支持 | +| Mac OS | 桌面版 Chrome 浏览器 | 56+ | 支持 | 支持 | 支持(需要chrome72+版本) | +| Windows | 桌面版 Chrome 浏览器 | 56+ | 支持 | 支持 | 支持(需要chrome72+版本) | +| Windows | 桌面版 QQ 浏览器 | 10.4 | 支持 | 支持 | 不支持 | +| iOS | 移动版 Safari 浏览器 | 11.1.2 | 支持 | 支持 | 不支持 | +| iOS | 微信内嵌网页 | 12.1.4 | 支持 | 不支持 | 不支持 | +| Android | 移动版 QQ 浏览器 | - | 不支持 | 不支持 | 不支持 | +| Android | 移动版 UC 浏览器 | - | 不支持 | 不支持 | 不支持 | +| Android | 微信内嵌网页 | - | 不支持 | 不支持 | 不支持 | + +>! +>- 您可以在浏览器中打开 [WebRTC 能力测试](https://www.qcloudtrtc.com/webrtc-samples/abilitytest/index.html) 页面进行检测是否完整支持 WebRTC。例如公众号等浏览器环境。 +>- 由于 H.264 版权限制,华为系统的 Chrome 浏览器和以 Chrome WebView 为内核的浏览器均不支持 TRTC 的 Web 版 SDK 的正常运行。 + + +## 环境要求 +- 请使用最新版本的 Chrome 浏览器。 +- TRTC Web SDK 依赖以下端口进行数据传输,请将其加入防火墙白名单,配置完成后,您可以通过访问并体验 [官网 Demo](https://trtc-1252463788.file.myqcloud.com/web/demo/official-demo/index.html) 检查配置是否生效。 + - TCP 端口:8687 + - UDP 端口:8000;8080;8800;843;443;16285 + - 域名:qcloud.rtc.qq.com + +## 前提条件 +您已 [注册腾讯云](https://cloud.tencent.com/document/product/378/17985) 账号,并完成 [实名认证](https://cloud.tencent.com/document/product/378/3629)。 + +## 操作步骤 + +### 步骤1:创建新的应用 +1. 登录实时音视频控制台,选择【开发辅助】>【[快速跑通Demo](https://console.cloud.tencent.com/trtc/quickstart)】。 +2. 单击【立即开始】,输入应用名称,例如`TestTRTC`,单击【创建应用】。 + + +### 步骤2:下载 SDK 和 Demo 源码 +1. 鼠标移动至对应卡片,单击【[Github](https://github.com/tencentyun/TRTCSDK/tree/master/Web/TRTCSimpleDemo)】跳转至 Github(或单击【[ZIP](https://liteavsdk-1252463788.cos.ap-guangzhou.myqcloud.com/H5_latest.zip?_ga=1.195966252.185644906.1567570704)】),下载相关 SDK 及配套的 Demo 源码。 +  +2. 下载完成后,返回实时音视频控制台,单击【我已下载,下一步】,可以查看 SDKAppID 和密钥信息。 + + +### 步骤3:配置 Demo 工程文件 +1. 解压 [步骤2](#step2) 中下载的源码包。 +2. 找到并打开`Web/TRTCSimpleDemo/js/debug/GenerateTestUserSig.js`文件。 +3. 设置`GenerateTestUserSig.js`文件中的相关参数: +
+ // * 时间单位:秒 + // * 默认时间:7 x 24 x 60 x 60 = 604800 = 7 天 + // */ + // const EXPIRETIME = 604800; + + // /** + // * 计算签名用的加密密钥,获取步骤如下: + // * + // * step1. 进入腾讯云实时音视频[控制台](https://console.cloud.tencent.com/rav ),如果还没有应用就创建一个, + // * step2. 单击“应用配置”进入基础配置页面,并进一步找到“帐号体系集成”部分。 + // * step3. 点击“查看密钥”按钮,就可以看到计算 UserSig 使用的加密的密钥了,请将其拷贝并复制到如下的变量中 + // * + // * 注意:该方案仅适用于调试Demo,正式上线前请将 UserSig 计算代码和密钥迁移到您的后台服务器上,以避免加密密钥泄露导致的流量盗用。 + // * 文档:https://cloud.tencent.com/document/product/647/17275#Server + // */ + // const SECRETKEY = 'dzrUpsgeMo0ygiSmqeDVqxnLbdT3Lbbh'; + + // // a soft reminder to guide developer to configure sdkAppId/secretKey + // if (SDKAPPID === '' || SECRETKEY === '') { + // alert( + // '请先配置好您的账号信息: SDKAPPID 及 SECRETKEY ' + + // '\r\n\r\nPlease configure your SDKAPPID/SECRETKEY in js/debug/GenerateTestUserSig.js' + // ); + // } + // const generator = new LibGenerateTestUserSig(SDKAPPID, SECRETKEY, EXPIRETIME); + // const userSig = window.istow ? "eJwtzdEKgjAUBuB32XXYdJubQhcV2IWBkGYEgohOO1SypoYQvXtLvTzff85-Pig5xtZbauQjx8JoNc1QybaHGibuboWW*dBJnRNMMcYeX9a66l4oBRXybeOUMO7yOZGjAi2NM8YcczJrD8*-uZhhYRPBlhZozJfW4*f9y7EPafmgTXjdnYQagjIRY7Ye4qim20sNaRsGEWk26PsDMPg1Xg__" : "eJwtzE8LgkAQBfDvstdCJt3RTeigl6gMw-7oLUK3GCNZ1Foj*u5t6vH93sz7sEO0t16yZj6zLWDTPlMhq5au1POzkfXZAQ4Ac288aIr7RSkqmD8zzh30XG9oZKeolsYR0TYvg7b0*JsLCAIcjuMK3cx*LmyV5GFXBWGZ6m4VVaejzjax3K3fehsTpk2QJKVeTsSCfX94djN6"; + // console.log(userSig) + // window.istow = true + // return { + // sdkAppId: SDKAPPID, + // userSig:userSig + // }; + return new Promise((res)=>{ + $.ajax({ + url: window.url + 'userSig?userid=' + userID, + headers: "Bearer " + localStorage.getItem("token"), + success(data){ + res({data: data.data, id: 1400435767}) + } + }) + }) + +} diff --git a/public/js/device-testing.js b/public/js/device-testing.js new file mode 100644 index 0000000..41b1728 --- /dev/null +++ b/public/js/device-testing.js @@ -0,0 +1,838 @@ +/** + * 设备检测demo + */ +/* global $ TRTC presetting getOS getBroswer cameraId micId */ + +// 用于记录检测结果,生成检测报告 +let hasCameraDevice = false, + hasMicAndVoiceDevice = false, + hasCameraConnect, + hasVoiceConnect, + hasMicConnect, + hasNetworkConnect; +let cameraTestingResult = {}; +let voiceTestingResult = {}; +let micTestingResult = {}; +let networkTestingResult = {}; + +// 记录检测步骤,用于关闭时清空弹窗 +let completedTestingPageIdList = []; +let curTestingPageId = ''; +let localStream = null; +let client = null; +let timeout = null; +// 监听到network-quality事件的次数 +let networkQualityNum = 0; + +const deviceFailAttention = + '1. 若浏览器弹出提示,请选择“允许”' + + '2. 若杀毒软件弹出提示,请选择“允许”' + + '3. 检查浏览器设置,允许网页访问摄像头及麦克风' + + '4. 检查摄像头/麦克风是否正确连接并开启' + + '5. 尝试重新连接摄像头/麦克风' + + '6. 尝试重启电脑后重新检测'; +const networkFailAttention = + '1. 请检查设备是否联网' + '2. 请刷新网页后再次检测' + '3. 请尝试更换网络后再次检测'; + +// 网络参数对照表 +const NETWORK_QUALITY = { + '0': '未知', + '1': '极佳', + '2': '较好', + '3': '一般', + '4': '差', + '5': '极差', + '6': '断开' +}; + +// 设备检测tab页签对应的执行方法 +const pageCallbackConfig = { + 'camera-testing-body': 'startCameraTesting', + 'voice-testing-body': 'startVoiceTesting', + 'mic-testing-body': 'startMicTesting', + 'network-testing-body': 'startNetworkTesting' +}; + +// 判断是否为safari浏览器 +let isSafari = /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent); +hideVoiceForSafari(); +/** + * safari浏览器中隐藏扬声器相关检测 + */ +function hideVoiceForSafari() { + if (!isSafari) return; + $('#connect-voice').hide(); + $('#device-voice').hide(); + $('#voice-testing').hide(); + $('#voice-report').hide(); + $('#device-mic').addClass('safari'); + $('#device-network').addClass('safari'); + $('#mic-testing').addClass('safari'); + $('#network-testing').addClass('safari'); +} + +// 是否是本地路径打开 +let isFilePath = location.href.indexOf('file://') > -1; + +/** + * 设备检测初始化 + */ +async function deviceTestingInit() { + // 点击【设备检测】文字, 点击 【重新连接】按钮 + $('#device-testing-btn, #connect-again-btn').on('click', () => { + startDeviceConnect(); + }); + // 连接设备错误icon + $('#connect-attention-icon').on('mouseover', () => { + $('#connect-attention-info').show(); + }); + // 连接设备错误icon + $('#connect-attention-icon').on('mouseout', () => { + $('#connect-attention-info').hide(); + }); + // 【开始检测】开始设备检测按钮 + $('#start-test-btn').on('click', function() { + if ($(this).hasClass('start-gray')) return; + $('#device-testing-prepare').hide(); + $('#device-testing').show(); + startCameraTesting(); + }); + // 摄像头检测失败/成功 + $('#camera-fail, #camera-success').on('click', function() { + cameraTestingResult.statusResult = $(this).attr('id') === 'camera-success'; + $('#camera-testing-body').hide(); + localStream.close(); + // safari浏览器跳过扬声器检测 + isSafari ? startMicTesting() : startVoiceTesting(); + }); + // 播放器检测失败/成功 + $('#voice-fail, #voice-success').on('click', function() { + voiceTestingResult.statusResult = $(this).attr('id') === 'voice-success'; + $('#voice-testing-body').hide(); + let audioPlayer = document.querySelector('#audio-player'); + if (!audioPlayer.paused) { + audioPlayer.pause(); + } + startMicTesting(); + }); + // 麦克风测试失败/成功 + $('#mic-fail, #mic-success').on('click', function() { + micTestingResult.statusResult = $(this).attr('id') === 'mic-success'; + $('#mic-testing-body').hide(); + localStream.close(); + startNetworkTesting(); + }); + // 点击【查看检测报告】按钮 + $('#testing-report-btn').on('click', () => { + showTestingReport(); + localStream.close(); + client && client.leave(); + client && client.off('network-quality'); + }); + // 点击【重新测试】按钮 + $('#testing-again').on('click', () => { + $('#device-testing-report').hide(); + startDeviceConnect(); + completedTestingPageIdList = []; + }); + // 点击【测试完成】按钮 / 点击关闭图标 + $('#testing-finish, #device-testing-close-btn').on('click', () => { + finishDeviceTesting(); + }); + // 测试tab页切换 + $('#camera-testing, #voice-testing, #mic-testing, #network-testing').on('click', function() { + let targetPageId = $(this).attr('id') + '-body'; + if ( + targetPageId !== curTestingPageId && + completedTestingPageIdList.indexOf(targetPageId) > -1 + ) { + $(`#${curTestingPageId}`).hide(); + localStream && localStream.close(); + client && client.leave(); + client && client.off('network-quality'); + // 停止播放器的音乐 + let audioPlayer = document.querySelector('#audio-player'); + if (!audioPlayer.paused) { + audioPlayer.pause(); + } + // 展示要切换的设备检测tab页面 + $(`#${targetPageId}`).show(); + window[pageCallbackConfig[targetPageId]] && window[pageCallbackConfig[targetPageId]](); + } + }); + // 摄像头设备切换 + $('#camera-select').change(async function() { + let newCameraId = $(this) + .children('option:selected') + .val(); + localStorage.setItem('txy_webRTC_cameraId', newCameraId); + cameraTestingResult.device = { + label: $(this) + .children('option:selected') + .text(), + deviceId: $(this) + .children('option:selected') + .val(), + kind: 'videoinput' + }; + await localStream.switchDevice('video', newCameraId); + }); + // 扬声器设备切换 + $('#voice-select').change(async function() { + let newVoiceId = $(this) + .children('option:selected') + .val(); + localStorage.setItem('txy_webRTC_voiceId', newVoiceId); + voiceTestingResult.device = { + label: $(this) + .children('option:selected') + .text(), + deviceId: $(this) + .children('option:selected') + .val(), + kind: 'audiooutput' + }; + + let audioPlayer = document.querySelector('#audio-player'); + await audioPlayer.setSinkId(newVoiceId); + }); + // 麦克风设备切换 + $('#mic-select').change(async function() { + let newMicID = $(this) + .children('option:selected') + .val(); + localStorage.setItem('txy_webRTC_micId', newMicID); + micTestingResult.device = { + label: $(this) + .children('option:selected') + .text(), + deviceId: $(this) + .children('option:selected') + .val(), + kind: 'audioinput' + }; + await localStream.switchDevice('audio', newMicID); + }); + + $('body').on('click', function() { + $('#device-connect-list').hide(); + }); + + // 获取设备信息 + await getDevicesInfo(); + // 初始化设备弹窗信息 + deviceDialogInit(); +} + +/** + * 获取设备信息及网络连接信息 + */ +async function getDevicesInfo() { + let micList = await TRTC.getMicrophones(); + let voiceList = await TRTC.getSpeakers(); + let cameraList = await TRTC.getCameras(); + let index = isFilePath ? 'label' : 'deviceId'; + if (cameraList.length > 0) { + hasCameraDevice = true; + } + if (micList.length > 0) { + hasMicAndVoiceDevice = true; + } + cameraList.forEach(camera => { + if (camera[index].length > 0) { + hasCameraConnect = true; + } + }); + micList.forEach(mic => { + if (mic[index].length > 0) { + hasMicConnect = true; + } + }); + if (isSafari) { + hasVoiceConnect = true; + } else { + voiceList.forEach(voice => { + if (voice[index].length > 0) { + hasVoiceConnect = true; + } + }); + } + hasNetworkConnect = !!navigator.onLine; +} + +/** + * 判断是否展示弹窗 + */ +function deviceDialogInit() { + if (!localStorage.getItem('txy_device_testing')) { + localStorage.setItem('txy_device_testing', Date.now()); + startDeviceConnect(); + } else { + // 在首页展示设备连接结果 + let showDeviceStatus = function() { + $('#device-connect-list').show(); + timeout = setTimeout(() => { + $('#device-connect-list').hide(); + }, 3000); + $('#connect-camera').css('color', `${hasCameraConnect ? 'green' : 'red'}`); + $('#connect-voice').css('color', `${hasVoiceConnect ? 'green' : 'red'}`); + $('#connect-mic').css('color', `${hasMicConnect ? 'green' : 'red'}`); + $('#connect-network').css('color', `${hasNetworkConnect ? 'green' : 'red'}`); + if (!(hasCameraConnect && hasVoiceConnect && hasMicConnect && hasNetworkConnect)) { + $('#device-testing-btn').css('color', 'red'); + } else { + $('#device-testing-btn').css('color', 'green'); + } + }; + showDeviceStatus(); + + if (!(hasCameraConnect && hasVoiceConnect && hasMicConnect)) { + navigator.mediaDevices + .getUserMedia({ video: hasCameraDevice, audio: hasMicAndVoiceDevice }) + .then(async () => { + // 重新获取设备信息 + await getDevicesInfo(); + // 更新首页popover的option list + getDevicesList(); + // 展示连接结果 + showDeviceStatus(); + }) + .catch(err => {}); + } + } +} + +/** + * 弹窗-设备连接检查 + */ +function startDeviceConnect() { + // 显示设备检测弹窗 + $('#device-testing-root').show(); + // 设备检测弹窗-设备连接页 + $('#device-testing-prepare').show(); + + curTestingPageId = 'device-testing-prepare'; + initTestingTabTitle(); + + // 在设备检测弹窗显示设备连接信息 + let showDeviceConnectInfo = function() { + if (!(hasCameraConnect && hasVoiceConnect && hasMicConnect && hasNetworkConnect)) { + $('#device-testing-btn').css('color', 'red'); + } else { + $('#device-testing-btn').css('color', 'green'); + } + // 隐藏设备连接失败提示 + $('#connect-attention-container').hide(); + + // 设备连接中 + $('#device-loading').show(); + $('#connect-info') + .text('设备正在连接中,请稍等') + .css('color', '#cccccc'); + $('#device-camera, #device-voice, #device-mic, #device-network').removeClass( + 'connect-success connect-fail' + ); + $('#connect-again-btn').hide(); + $('#start-test-btn') + .addClass('start-gray') + .show(); + + // 设备连接结束,展示连接结果 + setTimeout(() => { + $('#device-loading').hide(); + $('#device-camera') + .removeClass('connect-success connect-fail') + .addClass(`${hasCameraConnect ? 'connect-success' : 'connect-fail'}`); + $('#device-voice') + .removeClass('connect-success connect-fail') + .addClass(`${hasVoiceConnect ? 'connect-success' : 'connect-fail'}`); + $('#device-mic') + .removeClass('connect-success connect-fail') + .addClass(`${hasMicConnect ? 'connect-success' : 'connect-fail'}`); + $('#device-network') + .removeClass('connect-success connect-fail') + .addClass(`${hasNetworkConnect ? 'connect-success' : 'connect-fail'}`); + + if (!(hasCameraConnect && hasVoiceConnect && hasMicConnect)) { + let connectInfo = hasNetworkConnect + ? '设备连接失败,请允许网页访问摄像头及麦克风' + : '设备及网络连接失败,请允许网页访问摄像头及麦克风并检查网络连接'; + $('#connect-info') + .text(connectInfo) + .css('color', 'red'); + // 显示设备连接失败引导 + $('#connect-attention-container').show(); + $('#connect-attention-info').html(deviceFailAttention); + // 切换按钮状态 + $('#start-test-btn').hide(); + $('#connect-again-btn').show(); + } + if (hasCameraConnect && hasVoiceConnect && hasMicConnect && !hasNetworkConnect) { + $('#connect-info') + .text('网络连接失败,请检查网络连接') + .css('color', 'red'); + // 显示网络连接失败引导 + $('#connect-attention-container').show(); + $('#connect-attention-info').html(networkFailAttention); + // 切换按钮状态 + $('#start-test-btn').hide(); + $('#connect-again-btn').show(); + } + if (hasCameraConnect && hasVoiceConnect && hasMicConnect && hasNetworkConnect) { + $('#connect-info') + .text('设备及网络连接成功,请开始设备检测') + .css('color', '#32CD32'); + $('#connect-again-btn').hide(); + $('#start-test-btn') + .removeClass('start-gray') + .show(); + } + }, 2000); + }; + showDeviceConnectInfo(); + + // 如果有设备未连接,唤起请求弹窗 + if (!(hasCameraConnect && hasVoiceConnect && hasMicConnect)) { + navigator.mediaDevices + .getUserMedia({ video: hasCameraDevice, audio: hasMicAndVoiceDevice }) + .then(async () => { + // 重新获取设备信息 + await getDevicesInfo(); + // 更新首页popover的option list + getDevicesList(); + // 显示设备连接信息 + showDeviceConnectInfo(); + }) + .catch(err => { + console.log('err', err.name); + }); + } +} + +/** + * 更新首页popover的option list + */ +function getDevicesList() { + // populate camera options + TRTC.getCameras().then(devices => { + $('#camera-option').empty(); + devices.forEach(device => { + if (!cameraId) { + // eslint-disable-next-line no-global-assign + cameraId = device.deviceId; + } + let div = $('