当前位置: 首页 > news >正文

七牛实时音视频云视频连线demo(web部分)

七牛实时音视频云视频连线demo(web部分)

官方文档:

doc.qnsdk.com/rtn/web

步骤

1.申请七牛云账号;

2.服务器上做token验证接口

3.web demo开发

注意事项
  1. 因为屏幕和摄像头采集只能在 localhost 或者 https 下完成;
  2. 因为项目涉及到和客户端视频连线,一开始客户端取不到web发布的视频流,后面仔细查看文档才知道需要把客户端打不得track流设置Master为true(默认false)
代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>视频连线</title>
</head>
<link rel="stylesheet" href="src/css/index.css">
<link rel="stylesheet" href="src/layui/css/layui.css">
<body>
<div class="title">演播室</div>
<div id="localtracks"></div>
<div class="title">远方记者</div>
<div id="subtracks"></div>
<div class="button">
    <button class="layui-btn layui-btn-normal" onclick="page.joinRoom()">加入房间</button>
    <button class="layui-btn layui-btn-normal" onclick="page.leaveRoom()">离开房间</button>
</div>
</body>
<script src="src/js/public/pili-rtc-web.js"></script>
<script src="src/js/public/jquery-3.3.1.min.js"></script>
<script src="src/layui/layui.all.js"></script>
<script>
    var page = {};
    page.uid = 6;
    page.roomname = '123456';
    page.token = '';
    myRoom = null;


    page.getToken = async function () {
        await $.ajax({
            url: '/QiuNiu/getToken',
            type: 'POST',
            data: {
                uid: page.uid,
                roomname: page.roomname
            },
            success: function (res) {
                res = JSON.parse(res)
                if (res.code == 200) {
                    page.token = res.data.token
                } else {
                    console.log(res.msg)
                    layer.msg(res.msg,{icon:2})
                }
            }
        });
    }

    page.joinRoom = function () {
        layer.prompt({title: '请输入房间号', value: page.roomname, maxlength: 64}, function(pass, index){
            const roomReg = /[a-zA-Z0-9_-]{3,64}/;
            if(roomReg.exec(pass)){
                page.roomname = pass
                layer.close(index);
                page.startConnect();
            } else {
                layer.msg('房间号必须为3位以上字母和数字组成!',{icon:2})
            }
        });
    }
    page.startConnect = async function () {
        await page.leaveRoom();
        await page.getToken();
        // 这里替换成刚刚生成的 RoomToken
        await  myRoom.joinRoomWithToken(page.token);
        await page.publish();
        page.autoSubscribe();
    }

    page.leaveRoom = async function () {
        myRoom.leaveRoom();
        $('#localtracks').html('');
        const tracks = await QNRTC.deviceManager.getLocalTracks({
            audio: {enabled: true, tag: "audio"},
            video: {enabled: true, tag: "video"},
        });

        // 遍历 tracks,逐个销毁释放
        for (const track of tracks) {
            track.release();
        }
    }
    page.publish = async function () {
        // 我们打开了 3 个参数,即采集音频,采集视频,采集屏幕共享。
        // 这个函数会返回一个列表,列表中每一项就是一个音视频轨对象
        const localTracks = await QNRTC.deviceManager.getLocalTracks({
            audio: {enabled: true, tag: "audio"},
            video: {enabled: true, tag: "video"},
        });
        for (const localTrack of localTracks) {
            localTrack.setMaster(true);
        }
        // 将刚刚的 Track 列表发布到房间中
        await myRoom.publish(localTracks);
        console.log("publish success!");

        const localElement = document.getElementById("localtracks");
        // 遍历本地采集的 Track 对象
        for (const localTrack of localTracks) {
            localTrack.setMaster(true);
            // 如果这是麦克风采集的音频 Track,我们就不播放它。
            if (localTrack.info.tag === "audio") continue;
            // 调用 Track 对象的 play 方法在这个元素下播放视频轨
            localTrack.play(localElement, true);
        }
    }

    // 这里的参数 myRoom 是指刚刚加入房间时初始化的 Session 对象, 同上
    // trackInfoList 是一个 trackInfo 的列表,订阅支持多个 track 同时订阅。
    page.subscribe =  async function (trackInfoList) {
        // 通过传入 trackId 调用订阅方法发起订阅,成功会返回相应的 Track 对象,也就是远端的 Track 列表了
        const remoteTracks = await myRoom.subscribe(trackInfoList.map(info => info.trackId));

        // 选择页面上的一个元素作为父元素,播放远端的音视频轨
        const remoteElement = document.getElementById("subtracks");
        // 遍历返回的远端 Track,调用 play 方法完成在页面上的播放
        for (const remoteTrack of remoteTracks) {
            remoteTrack.play(remoteElement);
        }
    }

    page.autoSubscribe =  function () {
        const trackInfoList = myRoom.trackInfoList;
        // 调用我们刚刚编写的 subscribe 方法
        // 注意这里我们没有使用 async/await,而是使用了 Promise,大家可以思考一下为什么
        page.subscribe(trackInfoList)
            .then(() => console.log("subscribe success!"))
            .catch(e => console.error("subscribe error", e));

        // 添加事件监听,当房间中出现新的 Track 时就会触发,参数是 trackInfo 列表
        myRoom.on("track-add", (trackInfoList) => {
            page.subscribe(trackInfoList)
                .then(() => console.log("subscribe success!"))
                .catch(e => console.error("subscribe error", e));
        });
        // 就是这样,就像监听 DOM 事件一样通过 on 方法监听相应的事件并给出处理函数即可
    }

    page.initRoom = async function () {
        myRoom = new QNRTC.TrackModeSession();
    }

    $(function () {
        page.initRoom();
    });

    // localhost 或者 127.0.0.1 访问刚刚那 2 个页面(因为屏幕和摄像头采集只能在 localhost 或者 https 下完成),
</script>
</html>
复制代码

相关文章:

  • 支付宝支撑2135亿成交额的数据库架构原理
  • ZStack--工作流引擎
  • dmidecode查看linux硬件信息
  • Octave 入门
  • 第33讲 | 区块链与供应链(二)
  • Hadoop完全分布式环境搭建(四)——基于Ubuntu16.04安装和配置Hadoop大数据环境...
  • 使用parted解决大于2T的磁盘分区
  • day29:关闭服务|
  • Python 爬虫十六式 - 第六式:JQuery的假兄弟-pyquery
  • 本科理工男如何学习Linux
  • [洛谷P2511][HAOI2008]木棍分割
  • C语言之路-2-判断
  • JavaScript面向对象名词详解
  • java对象拷贝最完全解说
  • JVM,DVM,ART
  • 「前端早读君006」移动开发必备:那些玩转H5的小技巧
  • django开发-定时任务的使用
  • Git初体验
  • MYSQL如何对数据进行自动化升级--以如果某数据表存在并且某字段不存在时则执行更新操作为例...
  • Sublime text 3 3103 注册码
  • VirtualBox 安装过程中出现 Running VMs found 错误的解决过程
  • VUE es6技巧写法(持续更新中~~~)
  • vuex 笔记整理
  • 机器学习 vs. 深度学习
  • 码农张的Bug人生 - 初来乍到
  • 一些基于React、Vue、Node.js、MongoDB技术栈的实践项目
  • kubernetes资源对象--ingress
  • !!【OpenCV学习】计算两幅图像的重叠区域
  • ###项目技术发展史
  • (20)目标检测算法之YOLOv5计算预选框、详解anchor计算
  • (2021|NIPS,扩散,无条件分数估计,条件分数估计)无分类器引导扩散
  • (C++20) consteval立即函数
  • (vue)页面文件上传获取:action地址
  • (机器学习-深度学习快速入门)第一章第一节:Python环境和数据分析
  • (强烈推荐)移动端音视频从零到上手(上)
  • (十) 初识 Docker file
  • (原创) cocos2dx使用Curl连接网络(客户端)
  • (转)母版页和相对路径
  • (转)人的集合论——移山之道
  • ***原理与防范
  • .\OBJ\test1.axf: Error: L6230W: Ignoring --entry command. Cannot find argumen 'Reset_Handler'
  • .cn根服务器被攻击之后
  • .NET 编写一个可以异步等待循环中任何一个部分的 Awaiter
  • .NET 中创建支持集合初始化器的类型
  • .NET精简框架的“无法找到资源程序集”异常释疑
  • .NET框架
  • .Net组件程序设计之线程、并发管理(一)
  • .pyc文件是什么?
  • [23] 4K4D: Real-Time 4D View Synthesis at 4K Resolution
  • [AIGC] Nacos:一个简单 yet powerful 的配置中心和服务注册中心
  • [C++] new和delete
  • [exgcd] Jzoj P1158 荒岛野人
  • [java基础揉碎]方法的重写/覆盖
  • [java进阶]——方法引用改写Lambda表达式
  • [loj#115] 无源汇有上下界可行流 网络流