关于 TRTC (实时音视频通话模式)在我司的实践 #78

简介: 关于 TRTC (实时音视频通话模式)在我司的实践 #78

什么是 TRTC


腾讯实时音视频(Tencent Real-Time Communication,TRTC)将腾讯 21 年来在网络与音视频技术上的深度积累,以多人音视频通话和低延时互动直播两大场景化方案,通过腾讯云服务向开发者开放,致力于帮助开发者快速搭建低成本、低延时、高品质的音视频互动解决方案。


TRTC 流程图



加入房间


创建流

this.client = TRTC.createClient({
    mode: 'videoCall',
    sdkAppId,
    userId,
    userSig
});
  • mode: 实时音视频通话模式,设置为,互动直播模式,设置为‘videoCall’'live'
  • sdkAppId: 您从腾讯云申请的sdkAppId
  • userId: 用户 ID,随机生成,一个房间内不允许重复的userId
  • userSig: 用户签名,基于后台算法生成,防盗刷

加入

this.client
    .join({ roomId })
    .catch(error => {
        console.error('进房失败 ' + error);
    })
    .then(() => {
        console.log('进房成功');
    });
  • roomId:后台生成的房间 Id,不能重复

发布本地流


本地推流

this.localStream = TRTC.createStream({ userId: this.userId, audio: true, video: true });
  • userId: 用户 ID,随机生成,一个房间内不允许重复的userId
  • audio: 是否从麦克风采集音频
  • 视频: 是否从摄像头采集视频

初始化本地音视频流

this.localStream
    .initialize()
    .catch(err => {
        console.error('初始化本地流失败 ' + error);
    })
    .then((res) => {
        console.log('初始化本地流成功');
        this.localStream.play('localVideo');
    });
  • localVideo: 绑定的div id


发布

this.client
    .publish(this.localStream)
    .catch(err => {
        console.error('本地流发布失败 ' + error);
    })
    .then((res) => {
        console.log('本地流发布成功');
    });
  • 本地流发布成功之后,可以注册本地推流函数,每三秒执行一次,处理异常情况。

订阅远端流


远端流增加

this.client.on('stream-added', event => {
    this.remoteStream = event.stream;
    //订阅远端流
    this.client.subscribe(this.remoteStream);
});


远端流订阅

this.client.on('stream-subscribed', event => {
    console.log('log', 'onRemoteStreamUpdate:' + event);
    this.remoteStream = event.stream;
    this.id = this.remoteStream.getId();
    const remoteVideoDom = document.querySelector('#remoteVideo');
    if(!document.querySelector(`#remoteStream-${this.id}`)) {
        const div = document.createElement('div');
        div.setAttribute('style', 'position: absolute; right: 0; left: 0; top: 0; width: 100%; height: 100%');
        div.setAttribute('id', `remoteStream-${this.id}`);
        remoteVideoDom.appendChild(div);
    }
    const videoLoading = document.querySelector('#video-loading');
    videoLoading.setAttribute('style', 'display: none;');
    // 播放远端流
    this.remoteStream.play(`remoteStream-${this.id}`);
});

可以在远端流监听成功之后,注册远端流状态变化函数,处理异常情况。


退出


取消发布本地流

this.client.unpublish(this.localStream)
    .catch((err) => {
        console.log('error', 'unpublish error:' + err);
    })
    .then((res) => {
        // 取消发布本地流成功
        console.log('log', 'unpublish error:' + res);
    });


退出房间

this.client.leave();


异常处理


本地流监听

// 每隔3秒获取本地推流情况
this.localTimer = setInterval(() => {
    this.client.getLocalVideoStats().then(stats => {
        for (let userId in stats) {
            console.log(new Date(), 'getLocalVideoStats', 'userId: ' + userId +
        'bytesSent: ' + stats[userId].bytesSent + 'local userId' + this.userId);
            if(this.userId == userId && stats[userId].bytesSent == 0) {
                this.onEvent('leave');
            }
            const bytesSentSR = (stats[userId].bytesSent - this.bytesSent) / 3000;
            if(this.userId == userId && bytesSentSR >= 20 && bytesSentSR <= 59) {
            }
            if(this.userId == userId) {
                this.bytesSent =  stats[userId].bytesSent;
            }
        }
    });
}, 3000);
  • 可在本地流发布成功后,注册本地推流变化函数,处理异常情况
  • bytesSent: 如果发送单位为 ,则表示本地断网0
  • 公式: 目前发送字节数 - 上一次发送字节数 / 3000

远端流监听

this.remoteTimer = setInterval(() => {
    this.client.getRemoteVideoStats().then(stats => {
        for (let userId in stats) {
            console.log('getRemoteVideoStats', 'userId: ' + userId +
        ' bytesReceived: ' + stats[userId].bytesReceived +
        ' packetsReceived: ' + stats[userId].packetsReceived +
        ' packetsLost: ' + stats[userId].packetsLost);
            // const bytesReceived = (stats[userId].bytesReceived - this.bytesReceived) / 3000;
            // let title = '';
            // if(this.agentId == userId && bytesReceived >= 120) {
            //     title = '当前通话,对方网络良好';
            // }
            // if(this.agentId == userId && bytesReceived >= 60 && bytesReceived <= 119) {
            //     title = '当前通话,对方网络一般';
            // }
            // if(this.agentId == userId && bytesReceived >= 20 && bytesReceived <= 59) {
            //     title = '当前通话,对方网络不佳';
            // }
            // if(this.agentId == userId) {
            //     Taro.showToast({
            //         title,
            //         icon: 'none',
            //         duration: 1000
            //     });
            //     this.bytesReceived =  stats[userId].bytesReceived;
            // }
        }
    });
}, 3000);
  • bytesReceived: 如果接受单位为 0,则表示对方断网
  • 可在远端流监听成功之后,注册远端流状态变化函数,处理异常情况
  • 公式: 目前接收字节数 - 上一次接收字节数 / 3000

目前通过 TRTC 的事件通知,搭配 ,能做到对异常处理有较好的支持。Socket


TRTC 兼容性


Android(H5)

  • 摄像头不匹配,比如,华为手机三个后置加一个前置,调用 的获取摄像头接口,返回的却是 6 个,并且没有 标注那个是后置,那个是前置,厂商问题,需要特殊适配。TRTCLabel
  • 必须使用微信游览器打开 页面,其他游览器会偶尔崩溃以及其他问题(猜测微信游览器做了适配)。H5
  • 华为 P30 部分机型,存在微信游览器环境下没有默认打开腾讯 内核,需要进行特殊处理。打开方案:1、可以在手机设置、应用管理、微信、麦克风和摄像头权限重新开启。2、通过扫描 内核开启二维码,引导开启。否则会发布流失败,因为 内核关闭,导致没有权限获取。X5X5X5
  • TRTC 对大部分机型能够有较好的支持。

iOS(H5)

  • 必须使用 游览器,其他游览器会出现各种问题。Safari
  • 需要用户手动触发播放,这时候需要在 组件上加上 、、、(SDK,4.0.0 版本以下)videoautoplaymutedplaysinlinecontrols
<Video
    id="remoteVideo"
    autoplay
    muted
    playsinline
    controls
/>
  • 切换前后置摄像头需要根据 标签进行区分,获取前后置摄像头的 ,切换流程如下:LabeldeviceId
    1、获取摄像头
TRTC.getCameras().then(devices => {
        this.cameras = devices;
    });
  • 2、选择摄像头
this.localStream.switchDevice('video', deviceId)
    .catch(err => {
        console.log('error', 'switchDevice error:' + err);
    })
    .then((res) => {
        console.log('log', 'switchDevice success' + res);
    });


小程序

  • React技术栈(我只使用了 )能够支持视频播放,但推荐更好的 技术栈,因为 有官方封装的组件。TaroVueVue
  • 手机兼容性比较好,微信环境加持。

云端混流


request({
    url: `http://fcgi.video.qcloud.com/common_access?appid=${liveSign.appId}&interface=Mix_StreamV2&t=${liveSign.t}&sign=${liveSign.liveSign}`,
    method: 'POST',
    headers: {
        'content-type': 'application/json',
    },
    body: JSON.stringify(params)
}, (error, response, body) => {
    res.send({errCode: 0});
});

通过 接口,我们能够完美的监听房间内发生的情况,录制好的视频,会上传到腾讯的云点播平台,同时也支持客户自行导出。http://fcgi.video.qcloud.com/common_access

目录
相关文章
|
Ubuntu Linux vr&ar
IM跨平台技术学习(十二):万字长文详解QQ Linux端实时音视频背后的跨平台实践
本文详细记录了新版QQ音视频通话在 Linux 平台适配开发过程中的技术方案与实现细节,希望能帮助大家理解在 Linux 平台从 0 到 1 实现音视频通话能力的过程。
913 2
|
Web App开发 编解码 算法
实时音视频聊天中超低延迟架构的思考与技术实践
1、前言 从直播在线上抓娃娃,不断变化的是玩法的创新,始终不变的是对超低延迟的苛求。实时架构是超低延迟的基石,如何在信源编码、信道编码和实时传输整个链条来构建实时架构?在实时架构的基础之上,如果通过优化采集、编码、传输、解码和渲染中的关键环节来降低延迟?本文将会介绍即构在这方面的思考与实践。
2448 0
|
存储 Dragonfly 弹性计算
2023年阿里云服务器8核16G配置收费标准与活动价格参考,价格2849.76元1年起
一般来说企业用户在选择云服务器配置的时候,8核16G配置是选择比较多的,2023年新用户租用阿里云轻量应用服务器低至108元首年,8核16G配置目前活动价格仅需2849.76元1年起,不过阿里云不同实例类型的8核16G云服务器配置,产品价格也各不相同。而在平时购买和活动期间买价格也是不一样的。本文主要为大家介绍目前阿里云服务器8核16G配置收费标准与活动价格,以供参考。
1237 0
2023年阿里云服务器8核16G配置收费标准与活动价格参考,价格2849.76元1年起
|
Web App开发 容灾 安全
非功能关键知识总结
【2月更文挑战第4天】非功能关键知识总结
1471 2
|
人工智能 Java Serverless
【MCP教程系列】搭建基于 Spring AI 的 SSE 模式 MCP 服务并自定义部署至阿里云百炼
本文详细介绍了如何基于Spring AI搭建支持SSE模式的MCP服务,并成功集成至阿里云百炼大模型平台。通过四个步骤实现从零到Agent的构建,包括项目创建、工具开发、服务测试与部署。文章还提供了具体代码示例和操作截图,帮助读者快速上手。最终,将自定义SSE MCP服务集成到百炼平台,完成智能体应用的创建与测试。适合希望了解SSE实时交互及大模型集成的开发者参考。
14756 60
|
3月前
|
移动开发 前端开发 Java
微信直连商户公众号 JSAPI 支付,详细教程+源码
JSAPI 支付用于微信公众号内的网页调起微信收银台,常见于在公众号菜单、文章页或 H5 活动页中完成支付。该方式依赖微信内置浏览器环境,非微信浏览器无法调起。
559 1
|
4月前
|
JavaScript 前端开发 API
获取股票API接口地址
StockTV提供全球股票、外汇、期货、加密货币的实时与历史数据API,支持统一密钥接入,覆盖美、日、印、中等多国市场。兼容HTTP/WS协议,适用于量化、财经应用开发。(239字)
|
JavaScript 前端开发 开发者
如何在 Visual Studio Code (VSCode) 中使用 ESLint 和 Prettier 检查代码规范并自动格式化 Vue.js 代码,包括安装插件、配置 ESLint 和 Prettier 以及 VSCode 设置的具体步骤
随着前端开发技术的快速发展,代码规范和格式化工具变得尤为重要。本文介绍了如何在 Visual Studio Code (VSCode) 中使用 ESLint 和 Prettier 检查代码规范并自动格式化 Vue.js 代码,包括安装插件、配置 ESLint 和 Prettier 以及 VSCode 设置的具体步骤。通过这些工具,可以显著提升编码效率和代码质量。
2723 4
|
移动开发 资源调度 JavaScript
Vue移动端网页(H5)预览pdf文件(pdfh5和vue-pdf)
这篇文章介绍了在Vue移动端网页中使用`pdfh5`和`vue-pdf`两个插件来实现PDF文件的预览,包括滚动查看、缩放、添加水印、分页加载、跳转指定页数等功能。
11060 1
Vue移动端网页(H5)预览pdf文件(pdfh5和vue-pdf)

热门文章

最新文章

下一篇
开通oss服务