精华内容
下载资源
问答
  • 测试:视频播放器、视频通话、视频类网站 测试点
    千次阅读
    2020-09-28 22:24:18


    前言

    百度和字节面试被问到视频相关的测试用例,作为一个研究方向是视频编解码的人来说,这个问题回答不好,着实尴尬,因此总结转载一下有关视频播放器和视频通话的测试点。


    一、视频播放器测试用例

    1功能测试

    • 视频资源可以正常获取,不管是服务器返回还是后台添加等
    • 视频的封面图、页面UI等正常
    • 若一个视频中涉及到上一个视频、下一个视频时点击后都能正常切换到相应的视频,且视频正常播放
    • 音量大小(如静音模式下播放时无声音)
    • 视频最大化、最小化(如切换到最大化时视频全屏播放)
    • 播放列表的播放顺序,单循环,多循环,顺序播放,随机播放(还需要考虑下视频若是后台上传的,若在后台将某视频进行增加,删除,修改操作,验证视频播放是否正常)
    • 其他逻辑:
    1. 点击视频时,视频正常播放;再次点击时暂停播放资源;
    2. 播放视频时应用切换到后台—切换到后台后暂停播放,再次进入应用为暂停状态;
    3. 播放时杀掉程序进程—视频播放结束,不保留观看进度,再次进入到该视频,从头播放
    4. 播放视频A时切换到视频列表下的视频B----播放视频B;从进度B开始播放
    5. 播放视频A时切换到其他项目下的视频C—播放视频C;再次切换到视频A时从头播放
    6. 播放时上下滚动页面—视频播放器位置恒定,滚动不影响播放

    2兼容性测试

    • 平台兼容性:如Android、IOS
    • 系统兼容性:Android4.4-8.0;IOS8.0-12;谨记哦(低版本的机型问题还是蛮多的,如IOS8系统播放器问题较多,测试要引起注意)
    • 播放器是否与其他类型播放器兼容(需要考虑播放过程中是否和音频等相冲突)

    3网络测试

    • 网络切换测试:WiFi-移动网;移动网-WiFi;WiFi-无网;无网-WiFi;无网-移动网
    • 弱网测试:弱网情况下,视频播放是否有卡顿、黑屏、闪退等情况
    • 无网进入时是否有提示info;
    • 移动网进行播放时是否有非WiFi弹框提示;
    • 播放过程中断网时,播放完已加载的部分后停止播放且有相应提示;
    • 播放过程中切换网络时有相应提示
    • 踩过的坑:Android7.1.2版本切换4G网络查看视频时,出现黑屏,卡死,崩溃等情况
    • 异常测试

    4半屏/全屏切换测试

    • 视频右下角全屏按钮,点击全屏横屏播放视频;
    • 点击收起按钮,全屏收起回到当前页半屏播放
    • 两者切换播放回到当前页面时,页面展示正常(IOSXX项目曾出现页面导航错乱的问题)

    5横竖屏切换测试

    • 旋转模式打开后,验证页面及视频播放是否正常;
    • 横屏模式下播放完视频,自动切换回竖屏模式;

    6视频中断测试

    • 播放中快进/后退进度,能正常播放本地资源,快进不卡顿,无延迟;
    • 播放中切换到后台,切换到后台后暂停播放,再次进入视频为暂停状态;
    • 视频播放时杀掉进程,则视频播放结束(是否保留观看进度具体看产品需求);

    7视频易用性测试

    • 界面是否方便,整洁(如视频封面图,片头,片尾,视频图像等各个界面)
    • 快捷键是否正确
    • 菜单是否正确
    • 图像是否清楚(在标清、高清,超清等模式下切换时视频播放正常,无卡顿黑屏闪退等问题,在切换过程中是否有加载loading的提示)
    • 拖拽滚动条(拖、拽功能用起来是否友好)
    • 是否具备播放记忆功能(即播放进度是否有记录)
    • 能否自动保存以前的播放列表

    二、视频通话测试用例

    1功能测试

    • 视频能否连接成功,声音和画面是否正常,能否同步,挂断功能是否正常,单人视频和多人视频是否正常;

    • 视频通话结束时,主叫方结束通话

    • 视频通话结束时,被叫方结束通话视频

    • 通话接通后,立即挂断视频通话

    • 主叫方发起视频通话请求,被叫方拒绝接听

    • 主叫方发起视频通话请求,被叫方不响应

    • 主叫方发起视频通话请求,被叫方不在线

    • 视频通话过程中,有电话进来

    • 视频通话过程中,收到短信提示

    • 视频通话过程中,闹钟响了

    • 视频通话中,点击Home键

    • 视频通话中,点击back键

    • 视频通话中,点击音量键

    • 视频通话中,切换摄像头

    • 视频通话中,插拔耳机视频通话中,插拔耳机

    • 视频通话中,手机死机

    • 录语音时,接收到对方视频通话请求

    • 打电话时,接收到对方视频通话请求

    • 主叫方处于断网时

    • 被叫方处于断网时

    • 主叫方网络不稳定时

    • 被叫方网络不稳定时

    • 正在看视频/聊天/听歌时,接收到视频通话请

    • WLN断网,使用SIM卡

    2性能测试

    • 压力测试——长时间视频(如12小时)是否能保持正常,cpu,内存消耗等;

    • 稳定性测试——频繁进行视频;

    • 前后台切换——与其他应用切换,视频过程中来电话、短信等;

    • 不同网络测试:wifi和流量

    3兼容性测试

    • 在安卓和IOS手机上分别测试,选择不同机型,不同系统版本测试

    4界面测试

    • 软件界面文字,图片和Logo显示正常,操作过程中出现的各种提示显示正常。

    三、视频网站测试用例

    这话题有点大,不如问某些点如何测。。。
    checklist:视频格式一般走的flv或mp4或m3u8。
    web页面:业务功能测试&广告相关测试、页面性能&流量、弱网、安全&防盗链、适配&兼容、埋点统计、渠道权限相关;
    服务端:接口、性能、安全,公司内部自用的CMS业务功能测试;
    客户端的话再加入对播放器的功能、兼容&适配、弱网、异常测试,重点做编解码的性能&MTBF,主要是配合服务端编码出来是视频做一些抓包分析和配置参数调优的活儿。
    直播推流类的,功能、性能、弱网,抓包调优。
    连麦的实现原理好多家都不一样,没接触过so不枉言。
    关于视频流量的压力测试,因为大部分都放cdn服务商那块,没自建过cdn所以没接触过so不枉言。主要还得根据业务的设计来具体聊某个点如何测,目前想到就这些。
    单个视频的完整性、流量、页面元素(声音、快进、弹幕、评论、广告等)、(性能点)毕竟视频是镶嵌在网页内的,既然是功能点


    参考文章

    参考1
    参考2
    参考3
    参考4

    放平心态,继续准备其他的面试!

    更多相关内容
  • webrtc视频通话 浏览器

    2019-01-24 10:31:12
    源代码,webrtc,基于websocket的信令服务,从0了解的话,部署起来可能有点难,最好百度先了解了解
  • WebRtc音视频通话demo

    2020-11-10 16:59:37
    基于Android开发免费开源的音视频通话demo,页面样式与微信通话一样,复制粘贴就可以集成到你的项目内.
  • 视频聊天室通过学习,我自己也做了个简单的小例子,几十行JavaScript脚本就能轻松实现视频通话;也不用去下载指定的什么浏览器,因为IE、firefox、chrome等windows平台主流浏览器全部通过,完美运行。下边就跟大伙...
  • 要可以实现的例子 web rtc技术实现的 有的请发邮箱664408127@qq.com 测试过后有加分!!
  • WebRtc 视频通话网页网页

    千次阅读 2017-05-02 17:30:45
    2011年5月开放了工程的源代码,在行业内得到了广泛的支持和应用,成为下一代视频通话的标准下面例子主要是网页网页端,其实Webrtc不仅仅在网页上,在Android 和IOS都可以的,可以跨平台的建一个简单的动态WEB项目...

    WebRtc是谷歌2010年以6820万美元收购Global IP Solutions公司而获得的一项技术。2011年5月开放了工程的源代码,在行业内得到了广泛的支持和应用,成为下一代视频通话的标准

    下面例子主要是网页对网页端,其实Webrtc不仅仅在网页上,在Android 和IOS都可以的,可以跨平台的


    建一个简单的动态WEB项目,首先是网页端,js有点多 但是注释的还比较清楚,index.jsp放在WebContent下面

    <%@ page language="java" pageEncoding="UTF-8"%><%@ page
        isELIgnored="false"%><!DOCTYPE HTML>
    <html>
    <head>
    <title>WEBRTC视频通话</title>
    <meta charset="utf-8" />
    <meta name="keywords" content="ACGIST的视频应用,webrtc" />
    <meta name="description" content="使用webrtc实现的网页视频通话。" />
    
    <style type="text/css">
    * {
        margin: 0;
        padding: 0;
        overflow-y: hidden;
    }
    
    body {
        background-color: rgb(34, 34, 34);
    }
    
    #main {
        display: none;
        -webkit-transition-property: rotation;
        -webkit-transition-duration: 2s;
        text-align: center;
        -webkit-transform-style: preserve-3d;
        width: 1200px;
        margin: 0 auto;
        padding: 60px 0;
    }
    
    #localVideo {
        box-shadow: 0 0 20px #000;
        width: 600px;
        display: inline-block;
    }
    
    #remoteVideo {
        box-shadow: 0 0 20px #000;
        width: 600px;
        display: none;
    }
    
    #miniVideo {
        box-shadow: 0 0 20px #000;
        width: 300px;
        display: none;
    }
    
    #footer {
        position: absolute;
        bottom: 0;
        width: 100%;
        height: 28px;
        background-color: #404040;
        color: #fff;
        font-size: 13px;
        font-weight: bold;
        line-height: 28px;
        text-align: center;
    }
    
    .browser {
        box-shadow: 0 0 20px #000 inset;
        width: 400px;
        margin: 200px auto;
        padding: 20px;
        text-align: center;
        color: #fff;
        font-weight: bold;
    }
    
    @media screen and (-webkit-min-device-pixel-ratio:0) {
        #main {
            display: block;
        }
        .browser {
            display: none;
        }
    }
    </style>
    </head>
    <body ondblclick="fullScreen()">
        <div class="browser">对不起暂时只支持google chrome浏览器!</div>
        <div id="main">
            <video id="localVideo" autoplay="autoplay"></video>
            <video id="remoteVideo" autoplay="autoplay"></video>
            <video id="miniVideo" autoplay="autoplay"></video>
        </div>
        <div id="footer"></div>
        <script type="text/javascript">
            var pc;
            var main; // 视频的DIV
            var errorNotice; // 错误提示DIV
            var socket; // websocket
            var localVideo; // 本地视频
            var miniVideo; // 本地小窗口
            var remoteVideo; // 远程视频
            var localStream; // 本地视频流
            var remoteStream; // 远程视频流
            var localVideoUrl; // 本地视频地址
            var initiator = ${requestScope.initiator}; // 是否已经有人在等待
    
            var started = false; // 是否开始
            var channelReady = false; // 是否打开websocket通道
    
            var channelOpenTime;
            var channelCloseTime;
            //连接类
            var PeerConnection = window.PeerConnection || window.webkitPeerConnection00
                    || window.webkitRTCPeerConnection || window.mozRTCPeerConnection;
    
            //RTC对话类
            var RTCSessionDescription = window.mozRTCSessionDescription
                    || window.RTCSessionDescription;
    
            //RTC候选对象
            var RTCIceCandidate = window.mozRTCIceCandidate || window.RTCIceCandidate;
    
            //获取本地媒体流对象
            navigator.getMedia = (navigator.getUserMedia
                    || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia);
    
            //获取远程媒体流URL
            var URL = window.webkitURL || window.URL;
    
            var mediaConstraints = {
                "has_audio" : true,
                "has_video" : true
            }; // 音频和视频
    
            // 初始化
            function initialize() {
                console.log("初始化");
            main = document.getElementById("main");
                errorNotice = document.getElementById("errorNotice");
                localVideo = document.getElementById("localVideo");
                miniVideo = document.getElementById("miniVideo");
                remoteVideo = document.getElementById("remoteVideo");
    
                noticeMsg();
                openChannel();
                getUserMedia();
            }
    
            // 获取用户的媒体
            function getUserMedia() {
                console.log("获取用户媒体");
    
                navigator.getMedia({
                    "audio" : true,
                    "video" : true
                }, onUserMediaSuccess, onUserMediaError);
            }
    
            // 获取用户媒体成功
            function onUserMediaSuccess(stream) {
                var url = URL.createObjectURL(stream);
                localVideo.style.display = "inline-block";
                remoteVideo.style.display = "none";
    
                localVideo.src = url;
                localVideoUrl = url;
                localStream = stream;
    
                if (initiator)
                    maybeStart();
            }
    
            // 开始连接
            function maybeStart() {
                if (!started && localStream && channelReady) {
                    setNotice("连接中...");
                    createPeerConnection();
                    pc.addStream(localStream);
                    started = true;
                    if (initiator)
                        doCall();
                }
            }
    
            //接受显示选择
            var mediaConstraints = {
                optional: [],
                mandatory: {
                    OfferToReceiveAudio: true,
                    OfferToReceiveVideo: true
                }
            };
    
            // 开始通话
            function doCall() {
                console.log("开始呼叫");
    
                pc.createOffer(setLocalAndSendMessage, function() {}, mediaConstraints);
            }
    
            function setLocalAndSendMessage(sessionDescription) {
                pc.setLocalDescription(sessionDescription);
                sendMessage(sessionDescription);
            }
    
            // 发送信息
            function sendMessage(message) {
                var msgJson = JSON.stringify(message);
    
                socket.send(msgJson);
    
                console.log("发送信息 : " + msgJson);
            }
    
            // 打开websocket
            function openChannel() {
                console.log("打开websocket");
    
                socket = new WebSocket(
                        "wss://localhost:8443/WebrtcDemo/video/${requestScope.uid}");
    //WSS是https
                socket.onopen = onChannelOpened;
                socket.onmessage = onChannelMessage;
                socket.onclose = onChannelClosed;
                socket.onerror = onChannelError();
            }
    
            // 设置状态
            function noticeMsg() {
                if (!initiator) {
                    setNotice("让别人加入(注意事项查看源码): https://localhost:8443/WebrtcDemo/msg?oid=${requestScope.uid }");
                } else {
                    setNotice("初始化...");
                }
            }
    
            // 打开连接
            function createPeerConnection() {
                var server = {
                    "iceServers" : [ {
                        "url" : "stun:localhost"
                    } ]
                };
    
                pc = new PeerConnection(server);
    
                pc.onicecandidate = onIceCandidate;
                pc.onconnecting = onSessionConnecting;
                pc.onopen = onSessionOpened;
                pc.onaddstream = onRemoteStreamAdded;
                pc.onremovestream = onRemoteStreamRemoved;
            }
    
            // 谁知状态
            function setNotice(msg) {
                document.getElementById("footer").innerHTML = msg;
            }
    
            // 响应
            function doAnswer() {
                pc.createAnswer(setLocalAndSendMessage, function(error) {
                    console.log('Failure callback: ' + error);
                });
            }
    
            // websocket打开
            function onChannelOpened() {
                console.log("websocket打开");
    
                channelOpenTime = new Date();
                channelReady = true;
                if (initiator)
                    maybeStart();
            }
    
            // websocket收到消息
            function onChannelMessage(message) {
                console.log("收到信息 : " + message.data);
    
                processSignalingMessage(message.data);//建立视频连接
            }
    
            // 处理消息
            function processSignalingMessage(message) {
                var msg = JSON.parse(message);
    
                if (msg.type === "offer") {
                    if (!initiator && !started)
                        maybeStart();
                    pc.setRemoteDescription(new RTCSessionDescription(msg));
                    doAnswer();
                } else if (msg.type === "answer" && started) {
                    pc.setRemoteDescription(new RTCSessionDescription(msg));
                } else if (msg.type === "candidate" && started) {
                    var candidate = new RTCIceCandidate({
                        sdpMLineIndex : msg.label,
                        candidate : msg.candidate
                    });
                    pc.addIceCandidate(candidate);
                } else if (msg.type === "bye" && started) {
                    onRemoteClose();
                } else if (msg.type === "nowaiting") {
                    onRemoteClose();
                    setNotice("对方已离开!");
                }
            }
    
            // websocket异常
            function onChannelError(event) {
                console.log("websocket异常 : " + event);
    
                //alert("websocket异常");
            }
    
            // websocket关闭
            function onChannelClosed() {
                console.log("websocket关闭");
    
                if (!channelOpenTime) {
                    channelOpenTime = new Date();
                }
                channelCloseTime = new Date();
                openChannel();
            }
    
            // 获取用户流失败
            function onUserMediaError(error) {
                console.log("获取用户流失败!");
    
                alert("获取用户流失败!");
            }
    
            // 邀请聊天:这个不是很清楚,应该是对方进入聊天室响应函数
            function onIceCandidate(event) {
                if (event.candidate) {
                    sendMessage({
                        type : "candidate",
                        label : event.candidate.sdpMLineIndex,
                        id : event.candidate.sdpMid,
                        candidate : event.candidate.candidate
                    });
                } else {
                    console.log("End of candidates.");
                }
            }
    
            // 开始连接
            function onSessionConnecting(message) {
                console.log("开始连接");
            }
    
            // 连接打开
            function onSessionOpened(message) {
                console.log("连接打开");
            }
    
            // 远程视频添加
            function onRemoteStreamAdded(event) {
                console.log("远程视频添加");
    
                var url = URL.createObjectURL(event.stream);
    
                miniVideo.src = localVideo.src;
                remoteVideo.src = url;
                remoteStream = event.stream;
                waitForRemoteVideo();
            }
    
            // 远程视频移除
            function onRemoteStreamRemoved(event) {
                console.log("远程视频移除");
            }
    
            // 远程视频关闭
            function onRemoteClose() {
                started = false;
                initiator = false;
    
                miniVideo.style.display = "none";
                remoteVideo.style.display = "none";
                localVideo.style.display = "inline-block";
    
                main.style.webkitTransform = "rotateX(360deg)";
    
                miniVideo.src = "";
                remoteVideo.src = "";
                localVideo.src = localVideoUrl;
    
                setNotice("对方已断开!");
    
                pc.close();
            }
    
            // 等待远程视频
            function waitForRemoteVideo() {
                if (remoteVideo.currentTime > 0) { // 判断远程视频长度
                    transitionToActive();
                } else {
                    setTimeout(waitForRemoteVideo, 100);
                }
            }
    
            // 接通远程视频
            function transitionToActive() {
                remoteVideo.style.display = "inline-block";
                localVideo.style.display = "none";
                main.style.webkitTransform = "rotateX(360deg)";
                setTimeout(function() {
                    localVideo.src = "";
                }, 500);
                setTimeout(function() {
                    miniVideo.style.display = "inline-block";
                    //miniVideo.style.display = "none";
                }, 1000);
    
                setNotice("连接成功!");
            }
    
            // 全屏
            function fullScreen() {
                main.webkitRequestFullScreen();
            }
    
            // 关闭窗口退出
            window.onbeforeunload = function() {
                sendMessage({
                    type : "bye"
                });
                pc.close();
                socket.close();
            }
    
            // 设置浏览器支持提示信息
            function errorNotice(msg) {
                main.style.display = "none";
    
                errorNotice.style.display = "block";
                errorNotice.innerHTML = msg;
            }
    
            if (!WebSocket) {
                errorNotice("你的浏览器不支持WebSocket!建议使用<a href=\"https://www.google.com/intl/zh-CN/chrome/browser/\" target=\"_blank\">google chrome浏览器!</a>");
            } else if (!PeerConnection) {
                errorNotice("你的浏览器不支持RTCPeerConnection!建议使用<a href=\"https://www.google.com/intl/zh-CN/chrome/browser/\" target=\"_blank\">google chrome浏览器!</a>");
            } else {
                if (window.navigator.userAgent.indexOf("Chrome") !== -1)
                    setTimeout(initialize, 1); // 加载完成调用初始化方法
            }
        </script>
    </body>
    </html>
    

    然后配置Web.xml

        <servlet>
            <servlet-name>VideoMsgServlet</servlet-name>
            <servlet-class>demo.VideoMsgServlet</servlet-class>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>VideoMsgServlet</servlet-name>
            <url-pattern>/msg</url-pattern>
        </servlet-mapping>

    VideoMsgServlet,配置入口路径

    public class VideoMsgServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;
    
        public void destroy() {
            super.destroy();
        }
    
        public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            HttpSession session = request.getSession();
    
            String oid = request.getParameter("oid");
            System.out.println("------接受oid------"+oid);
            // String uid = session.getId();
            String uid = System.currentTimeMillis() + "";
            System.out.println("------生成uid------"+uid);
            request.setAttribute("initiator", "false");
    
            if (!RtcVideo.canCreate()) {
                response.getWriter().write("不能创建通话房间,超过最大创建数量!");
                return;
            }
    
            if (!RtcVideo.canJoin(oid)) {
                response.getWriter().write("对不起对方正在通话中,你不能加入!");
                return;
            }
    
            if (RtcVideo.addUser(uid, oid)) {
                request.setAttribute("uid", uid);
            } else {
                request.setAttribute("initiator", "true");
    
                request.setAttribute("uid", uid);
                request.setAttribute("oid", oid);
            }
    
            request.getRequestDispatcher("/index.jsp").forward(request, response);
        }
    
        public void init() throws ServletException {
        }
    
    }

    WebSocket RtcVideo类主要是用于转发Websocket的数据,用于连接握手的时候用

    @ServerEndpoint("/video/{uid}")
    public class RtcVideo {
        // 最大通话数量
        private static final int MAX_COUNT = 20;
        private static final long MAX_TIME_OUT = 2 * 60 * 1000;
        // 用户和用户的对话映射
        private static final Map<String, String> user_user = Collections.synchronizedMap(new HashMap<String, String>()); 
        // 用户和websocket的session映射
        private static final Map<String, Session> sessions = Collections.synchronizedMap(new HashMap<String, Session>());
    
        /**
         * 打开websocket
         * @param session websocket的session
         * @param uid 打开用户的UID
         */
        @OnOpen
        public void onOpen(Session session, @PathParam("uid")String uid) {
            System.out.println("------open------"+uid);
            session.setMaxIdleTimeout(MAX_TIME_OUT);
            sessions.put(uid, session);
        }
    
        /**
         * websocket关闭
         * @param session 关闭的session
         * @param uid 关闭的用户标识
         */
        @OnClose
        public void onClose(Session session, @PathParam("uid")String uid) {
            remove(session, uid);
            System.out.println("------close------");
    
        }
    
        /**
         * 收到消息
         * @param message 消息内容
         * @param session 发送消息的session
         * @param uid
         */
        @OnMessage
        public void onMessage(String message, Session session, @PathParam("uid")String uid) {
            System.out.println("------message"+message);
    
            try {
                if(uid != null && user_user.get(uid) != null && RtcVideo.sessions.get(user_user.get(uid)) != null) {
                    Session osession = sessions.get(user_user.get(uid)); // 被呼叫的session
                    if(osession.isOpen())
                        osession.getAsyncRemote().sendText(new String(message.getBytes("utf-8")));
                    else
                        this.nowaiting(osession);
                } else {
                    this.nowaiting(session);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 没有人在等待
         * @param session 发送消息的session
         */
        private void nowaiting(Session session) {
            session.getAsyncRemote().sendText("{\"type\" : \"nowaiting\"}");
        }
    
        /**
         * 是否可以继续创建通话房间
         * @return 可以:true;不可以false;
         */
        public static boolean canCreate() {
            return sessions.size() <= MAX_COUNT;
        }
    
        /**
         * 判断是否可以加入
         * @param oid 被申请对话的ID
         * @return 如果能加入返回:true;否则返回false;
         */
        public static boolean canJoin(String oid) {
            return !(oid != null && user_user.containsKey(oid) && user_user.get(oid) != null);
        }
    
        /**
         * 添加视频对象
         * @param uid 申请对话的ID
         * @param oid 被申请对话的ID
         * @return 是否是创建者:如果没有申请对话ID为创建者,否则为为加入者。创建者返回:true;加入者返回:false;
         */
        public static boolean addUser(String uid, String oid) {
            if(oid != null && !oid.isEmpty()) {                                                                                        
                RtcVideo.user_user.put(uid, oid);
                RtcVideo.user_user.put(oid, uid);
    
                return false;
            } else {
                RtcVideo.user_user.put(uid, null);
    
                return true;
            }
        }
    
        /**
         * 移除聊天用户
         * @param session 移除的session
         * @param uid 移除的UID
         */
        private static void remove(Session session, String uid) {
            String oid = user_user.get(uid);
    
            if(oid != null) user_user.put(oid, null); // 设置对方无人聊天
    
            sessions.remove(uid); // 异常session
            user_user.remove(uid); // 移除自己
    
            try {
                if(session != null && session.isOpen()) session.close(); // 关闭session
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
    }

    部署到本地Tomcat服务器

    效果

    https://localhost:8080/WebrtcDemo/msg
    这里写图片描述


    https://localhost:8443/WebrtcDemo/msg?oid=1493716719713
    这里写图片描述


    注意 我的这个是Https,所有用的是Websocket WSS:,Https需要配置ketstore,如果用http,就用WS,端口默认的是8080,也可以运行的!


    部分源码Copy网上,单绝无盗版之意,谢谢!!如有不懂,在下面评论

    展开全文
  • Jitsi-meet.js如下: ``` (function e(t, n, r) { function s(o, u) { if (!n[o]) { ... var a = typeof require == "function" && require;... throw new ReferenceError("this hasn't been ...
  • 实现音视频通话(Web)网易云信音视频通话产品的基本功能包括高质量的实时音视频通话。当您成功初始化 SDK 之后,您可以简单体验本产品的基本业务流程。本文档为您展示音视频通话提供的基本业务流程。前提条件请确认您...

    实现音视频通话(Web)

    网易云信音视频通话产品的基本功能包括高质量的实时音视频通话。当您成功初始化 SDK 之后,您可以简单体验本产品的基本业务流程。本文档为您展示音视频通话提供的基本业务流程。

    前提条件

    请确认您已完成以下操作:

    快速跑通Sample Code

    注意:在运行示例项目之前,请联系商务经理开通非安全模式。非安全模式建议只在集成开发阶段使用,请在应用正式上线前改回安全模式。

    在SDK和示例代码下载页面或 Demo 体验页面下载需要体验的示例项目或 Demo 源码工程。

    在 /src/views/home/index.vue 文件中配置 App Key。

    data () {

    return {

    isSilence: false,

    isDesc: true,

    isStop: false,

    desc: '等待对方进入...',

    appkey: '', //填入您的appkey

    token: '',

    client: null,

    localUid: Math.ceil(Math.random() * 1e5),

    localStream: null,

    remoteStream: null

    }

    },

    运行项目。

    该工程使用 vue(vue-cli 4.x) 技术栈,请使用 node 开发环境 version 8+。

    // Project setup

    npm install

    // Compiles and hot-reloads for development

    npm run dev

    // Compiles and minifies for production

    npm run build

    // Lints and fixes files**

    npm run lint

    实现音视频通话

    本节主要介绍如何使用 SDK 实现音视频通话。主要流程如下图所示:

    8e37122659950a0996fec32dd9e119a1.png

    WebRTC2 中有两个重要类:

    Client

    代表一个本地客户端。Client 类的方法提供了音视频通话的主要功能,例如加入房间、发布音视频流等。

    Stream

    代表本地和远端的音视频流。Stream 类的方法用于定义音视频流对象的行为,例如流的播放控制、音视频的编码配置等。调用 Stream 方法时,请注意区分本地流和远端流对象。

    1. 引用文件

    在项目相应的前端页面文件中,对 NIM_Web_WebRTC2_vx.x.x.js 文件进行引用。

    import 方式引入:

    import WebRTC2 from '../../NIM_Web_WebRTC2_vx.x.x.js'

    script 标签引入:

    2. 初始化

    执行 createClient 方法创建 client 实例。

    //示例

    //创建client实例

    rtc.client = WebRTC2.createClient({

    appkey: 'xxx', //您的 appkey

    debug: true, //是否开启调试日志

    });

    3. 设置本地视图

    初始化成功后,可以设置设置本地视图,预览本地图像。加入房间后,可以执行 publish 方法发布自己的多媒体流至流媒体,供其他用户订阅。

    //初始化本地流并且发布

    function initLocalStream(){

    //创建本端stream实例,销毁前无需重复创建

    rtc.localStream = WebRTC2.createStream({

    uid: uid, // 本端的uid

    audio: true, // 是否从麦克风采集音频

    microphoneId: microphoneId, // 麦克风设备 deviceId,通过 getMicrophones() 获取

    video: true, // 是否从摄像头采集视频

    cameraId: cameraId // 摄像头设备 deviceId,通过 getCameras() 获取

    })

    //启动本地音视频流,销毁前无需重复初始化

    rtc.localStream.init().then(()=>{

    console.warn('音视频初始化完成,播放本地视频')

    //用于播放视频的div元素

    let div = document.getElementById('local-container')

    //开始播放本地视频流

    rtc.localStream.play(div)

    //设置播放的视频容器大小

    rtc.localStream.setLocalRenderMode({

    width: 180,

    height: 150,

    cut: true // 是否裁剪

    })

    // 将本地音视频流发布至云信服务器,加入房间前不用执行此方法。

    rtc.client.publish(rtc.localStream).then(()=>{

    console.warn('本地 publish 成功')

    })

    })

    }

    4. 加入房间

    加入房间前,请确保已完成初始化相关事项。若您的业务中涉及呼叫邀请等机制,可以使用信令。

    //加入频道

    rtc.client.join({

    channelName: '频道名称',

    uid: uid,

    token: ''

    }).then((obj) => {

    console.info('加入频道成功...')

    //初始化本地流,并且发布

    initLocalStream() //后面介绍说明

    })

    参数说明:

    参数

    说明

    token

    安全认证签名(NERTC Token)。可设置为:null。非安全模式下可设置为 null。安全性不高,建议在产品正式上线前联系对应商务经理转为安全模式。

    已获取的NERTC Token。安全模式下必须设置为获取到的 Token 。若未传入正确的 Token 将无法进入房间。

    推荐使用安全模式。

    channelName

    房间名称,设置相同房间名称的用户会进入同一个通话房间。

    注意:您也可以在加入通道前,通过创建房间接口创建房间。加入房间时,若传入的 {channelName} 未事先创建,则云信服务器内部将为其自动创建一个名为 {channelName} 的通话房间。

    uid

    用户的唯一标识 id,房间内每个用户的 uid 必须是唯一的。

    5. 设置远端视图

    音视频通话过程中,除了要显示本地的视频画面,通常也要显示参与互动的其他连麦者/主播的远端视频画面。

    通过以下回调获取相关信息:

    peer-online:监听远端用户加入通话房间的事件,并抛出对方的 uid。当本端加入房间后,也会通过此回调抛出通话房间内已有的其他用户。

    stream-added:监听远端用户发布视频流的事件,回调中携带对方的 uid 与发布的视频分辨率。

    在监听到远端用户发布视频流后,本方可以通过 subscribe 方法对其发起视频流的订阅,来将对方的视频流渲染到视频画布上。

    // 示例

    //设置要订阅音频或者视频

    remoteStream.setSubscribeConfig({

    audio: true,

    video: true

    })

    // 发起订阅

    rtc.client.subscribe(remoteStream).then(()=>{

    console.log('发起订阅对端成功')

    })

    订阅成功后,可进一步在 stream-subscribed 回调中播放远端视频流。

    //播放订阅的对端的音视频流

    rtc.client.on('stream-subscribed', evt => {

    console.warn('订阅别人的流成功的通知')

    var remoteStream = evt.stream;

    let div = document.getElementById('remote-container')

    //开始播放远端音视频流

    remoteStream.play(div).then(()=>{

    console.log('播放对端的流成功')

    remoteStream.setRemoteRenderMode({

    width: 180,

    height: 150,

    cut: true

    })

    })

    })

    6. 退出通话房间

    通过 leave() 接口退出通话房间。

    //用户无需做一些清除动作,sdk会自动做清除逻辑

    rtc.client.leave()

    7. 销毁实例

    当确定短期内不再使用音视频通话实例时,可以释放对应的对象资源。

    //一般情况下无需使用

    rtc.client.destroy()

    本篇文档内容是否对您有帮助?

    04c71eec4a2781fca7013f8beb54eb1e.png有帮助

    2739a73467429f691aa770d9f31af7ff.png我要吐槽

    如果遇到产品相关问题,您可 提交工单 或 在线客服 寻求帮助。

    您的改进建议

    ×

    问题类型

    内容错误

    内容没更新

    描述不清

    链接有误

    步骤不完整

    内容缺失(缺少代码/示例)

    其他

    更多建议

    请输入您的建议或问题(至少5个字符,至多500个字符)

    联系方式

    标记内容

    同时提交标记内容

    提交

    此文档对你是否有帮助

    ×

    04c71eec4a2781fca7013f8beb54eb1e.png有帮助

    2739a73467429f691aa770d9f31af7ff.png我要吐槽

    ×

    反馈成功

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

    展开全文
  • 用Vue+Element搭建的腾讯实时音视频通话 仅限桌面浏览器,暂未搭建其他应用 使用前请先npm install安装依赖包 然后npm run serve既可看到效果 腾讯云 SDKAPPID和SECRETKEY,需要替换为您自己账号下的 SDKAppId。 ...
  • 网页里实现文字聊天是比较容易的,但若要实现视频聊天,就比较麻烦了。这里,我们将实现一个简单的网页视频聊天Demo,可以支持所有类型的浏览器。 本Demo除了视频聊天功能外,还包含以下功能: 1.上下线通知...

    在网页里实现文字聊天是比较容易的,但若要实现视频聊天,就比较麻烦了。这里,我们将实现一个简单的网页版视频聊天Demo,可以支持所有类型的浏览器。

          本Demo除了视频聊天功能外,还包含以下功能:

    1.上下线通知:假设所有用户都是好友,任何一个用户上线,都会出现在其他人的好友列表中,下线则会从好友列表中移除。

    2.掉线后会自动进行断线重连。

    3.当同名的用户登陆时,会把前面的用户挤掉。

    4.所有在线用户之间进行文字聊天。

    5.与在线好友进行视频聊天。 

    一. Demo运行效果

        先来看看Demo的最终效果吧!

    二. JS 实现过程

    1.实现账号登录

        登录界面如下: 

       

    打开视频聊天demo网页时,会出现登录界面,输入视频服务器IP、账号(使用随机生成的就可以),点击登录按钮就可以登录到视频聊天服务器。

    调用ESFramework框架的RapidPassiveEngine()的initialize方法,以及OMCS框架的MultimediaManager的Initialize方法以完成登录。

    登录成功后会自动进入用户主界面。

            //OMCS登录
            $('#Singin').bind("click", function () {
                this.multimediaManager = MultimediaManagerFactory.GetSingleton();
                var id = document.getElementById("userID").value;//用户id
                var posw = document.getElementById("logonPassword").value;//用户密码
                var serverIP = document.getElementById("serverIP").value;//ip地址
                // var serverPort = document.getElementById("serverPort").value;//端口
                try {
                    if (this.multimediaManager.Connected() == true) {
                        this.multimediaManager.Initialize(id, posw, serverIP, 9900);             
                    } else {
                        alert("登录失败");
                        console.log("多媒体webSocket还未连成功");
                    }
                }
                catch (ex) {
                    console.log(ex);
                }
            })
            //ESFramework登录
            $('#Singin').bind("click", function () {                       
                engine.initialize({
                    serverIP: serverIP,//服务器IP
                    serverPort: serverPort,//服务器端口
                    userID: userID,//登录用户名
                    useWss: false,
                    logonPassword: hex_md5(logonPassword),//md5后的密码
                    heartBeat: 5000,//心跳间隔时间(单位为ms)
                    callBackTimeout: 5000,//回调方法超时时间(单位为ms)
                    maxLengthOfUserID: 11,//设置用户名最大长度
                    customizeHandler: new CustomizeHandler(),//用户自定义消息处理器
                    loginResutCallBack: function (loginResult) {//登录结果回调方法
                        if (loginResult.logonResult == 0) {//登录成功
                            $("#chatBox").html("登录服务器成功");
                            document.getElementById('loginid').innerHTML = '当前账号 '+userID;
                            document.getElementById('login').style.display = 'none';
                            document.getElementById('main').style.display = 'block'                      
                            //esf登录
                            engine.ContactsOutter.addEventListener(new contractsListener());//注册联系人事件
                            engine.BasicOutter.addEventListener(new basicListener());//注册基础事件
                            
                });
        };

    2. 实现文字聊天

    使用通信框架最基础的需求就是收发信息,ESFramework(WebSocket)底层已经为我们封装好了所有与信息收发相关的操作,  当RapidPassiveEngine被new出来以后,RapidPassiveEngine对象就实例化了CustomizeOutter 属性,在对象的initialize函数被调用后,即可调用CustomizeOutter 里面的相关函数来发送消息,以及实现customizeHandler后就可以处理收到的信息。

    Web端可以收到来自其它客户端或服务端的信息、大数据块、以及同步调用。

    (1)发送文字聊天消息

    发送文字聊天信息可时通过调用CustomizeOutter中send()来进行操作,再发送前点击在线用户即可改变targetUser的值从而绑定你要发送信息的对象。

    //选择聊天对象
    function selectUser(userid) {
        var selfid = document.getElementById('userID').value;
        targetUser = userid;
        $("#chatBox").html("正在与" + userid + "对话中.....");
        var shows = document.getElementById('showfather').children;
        //console.log(shows);
        for (var i= 0; i < shows.length; i++) {
            if (shows[i].id != (userid + 'show')) {
                shows[i]. className='othershow'
            }
            document.getElementById(userid + 'show').className = 'shownow'
        }
    }

    发送信息时可以自定义不同的参数,从而判断出不同的消息类型。

    //发送信息    
         $("#btn").bind("click", function () {
            if ($(".bottomtext").val() == "") {
                alert("不能发送空消息~");
                return;
            }
            else if (targetUser.length == 0) {
                alert("未选中目标用户~");
                return;
            }
            else {
                value = $(".bottomtext").val();
                var selfid=document.getElementById('userID').value;
                appendContent("自己", value,selfid);
                $(".bottomtext").val("");
                var time = [];
                var info = util.getbytes(value);
                //以下为与服务端定义的协议体
                var stream = new OStream(time);
                var bodyLen = 4 + 4 + info.length + 4;
                stream.writeInt32(bodyLen);
                stream.writeInt32(info.length);
                stream.write(info);
                stream.writeInt32(1);//发送时间  距离2016.01.01 00:00:00的总秒数
    
                engine.CustomizeOutter.send(0, stream.getBytesArray(), targetUser);
            }
        })

    (2)处理文字聊天消息

    当我们收到其他在线用户或者服务端发来的信息时,通过实现customizeHandler接口来获取和处理信息。

    我们在用户登录时调用initialize方法时转入即可自动处理接收到的信息,接收到的信息我们通过判断信息类型来执行不同的操作。

    function CustomizeHandler() {
                
                this.handleInformation = function (sourceUserID, informationType, info) {
                    if (informationType == 0)//聊天消息
                    {                  
                    } else if (informationType == 1)//视频消息
                    {                            
                    } else if (informationType == 2) {                               
                    } else if (informationType == 3) {
                    }

    (3)渲染显示文字聊天消息

    通过appendOtherContent和appendContent函数将信息在页面中渲染出来通过传入的对象OppositeID不同将收到的信息渲染到不同的聊天窗口。并且通过selectUser来切换到发送信息的用户的窗口。

    function appendContent(sendName, content, OppositeID) {
            Time = getTime();
            $("#" + OppositeID).append('<div class="selfstyle"><p class="selfname">' + sendName + ":" + Time + '</p><p>' + content + '</p></div>');
            $("#" + OppositeID).animate({ scrollTop: 99999 });
        }
    
        function appendOtherContent(sendName, content, OppositeID) {
            Time = getTime();
            selectUser(OppositeID);
            var showid = OppositeID + 'show'
            $("#" + showid).append('<div class="otherstyle"><p class="othername">' + sendName + ":" + Time + '</p><p>' + content + '</p></div>');
            $("#" + showid).animate({ scrollTop: 99999 });

    3. 实现视频聊天

          视频聊天功能可以让你与服务器上的在线用户进行视频聊天,通过OMCS服务插件来实现摄像头和麦克风的连接,所以在使用前必须打开OMCS视频服务Web插件才能正常使用。

    (1)点击视频聊天后先通过CustomizeOutter 的send向对方发送消息类型为1的视频连接请求数据,同时打开视频聊天的窗口并且打开自己的摄像头和麦克风连接

    (2)视频连接对象收到数据类型为1的视频连接请求后出接受视频连接的聊天框,可以选择接受或拒绝.

             当视频连接对象选择接受视频聊天,则会同时连接自己和对方的摄像头麦克风;

             当对方拒绝时,则关闭视频连接的请求。

             选择过后将会发送一条消息类型为2的消息给视频的发起者。

    (3)视频发起者收到数据为2的回复后,会进行判断对方的选择是接受还是拒绝,若是接受则开始连接对方的摄像头,拒绝则关闭自己的摄像头麦克风和视频连接窗口。

    (4)当某一方关闭连接或者断开连接时会发送一条消息类型为3的消息发给另一方,收到类型为3的消息后会断开自己的摄像头和麦克风连接。

    在连接过程中也可通过视频聊天窗口的控件,控制自己的摄像头麦克风的开启和关闭。

    发送视频请求时间如下(接受拒绝和关闭同理)

    $('#videomic').bind('click', function () {     
            if (targetUser.length == 0) {
                alert("未选中视频聊天用户~");
                return;
            } else {
                value = 'null';
                console.log(value);
                document.getElementById('VideoMic').style.display = 'block';
                document.getElementById('VideoHeardTxt').innerHTML = '连接中...';
                document.getElementById('VideoSelf').src = 'img/video.jpg'
                document.getElementById('VideoOther').src = 'img/head.jpg'
                ConnertVideoSelf(userID, 'VideoSelf')
                appendContent(selfid, "我发送了视频请求");
                var time = [];
                var info = util.getbytes(value);
                //以下为与服务端定义的协议体
                var stream = new OStream(time);
                var bodyLen = 4 + 4 + info.length + 4;
                stream.writeInt32(bodyLen);
                stream.writeInt32(info.length);
                stream.write(info);
                stream.writeInt32(1);//发送时间  距离2016.01.01 00:00:00的总秒数
                var userID = document.getElementById('userID').value;         
                engine.CustomizeOutter.send(1, null, targetUser);
            }
        })

    视频麦克风连接事件如下

    var microphoneConnector, dynamicCameraConnector;
    var cameraArr = [];
    var micArr = [];
    function Connectvideo(destID, whichimg) {
        var a = document.getElementById(whichimg);
        this.dynamicCameraConnector = new DynamicCameraConnector();
        this.dynamicCameraConnector.ConnectEnded = connectEnded;  //连接成功监听
        this.dynamicCameraConnector.Disconnected = disconnected;  //连接关闭监听
        this.dynamicCameraConnector.OwnerOutputChanged = videoOutput;
        this.dynamicCameraConnector.SetAutoReconnect(true);
        this.dynamicCameraConnector.AutoReconnectSucceed = videocl;
        this.dynamicCameraConnector.SetViewer(a);
        this.dynamicCameraConnector.BeginConnect(destID);//开始摄像头的连接
        cameraArr.push(this.dynamicCameraConnector);
        this.microphoneConnector = new MicrophoneConnector();
        this.microphoneConnector.ConnectEnded = microphone;
        this.microphoneConnector.OwnerOutputChanged = micOutput;
        this.microphoneConnector.SetAutoReconnect(true);
        this.microphoneConnector.AutoReconnectSucceed = miccl;
        this.microphoneConnector.BeginConnect(destID);//开始麦克风的连接
        micArr.push(this.microphoneConnector);
    }

    视频聊天的几个特性:

    (1)一方发起视频对话请求,对方同意后,即可开始视频对话。 

    (2)在对话的过程中,任何一方都可以挂断,以终止对话。 

    (3)在对话的过程中,任何一方掉线,都会自动终止对话。 

    (4)点击右下角较小视频窗口,会放大该视频显示窗口。

    (5)Web版的视频聊天可以与pc版视频聊天互通。

    三. 网页视频聊天Demo源码下载

    1. 视频聊天Demo Web端 源码(JavaScript)

    2. 视频聊天Demo 服务端+PC端 源码

    当运行本Demo的 Web端时,如果尚未安装OMCS视频服务Web插件,网页会自动提示下载安装。

    完成安装后,刷新网页,会提示启动插件,点击同意启动后,再次刷新网页即可进行正常登录了。Web插件以托盘形式运行,如下图所示:   

          

    如果不想自己编译服务端和PC客户端,可以直接下载我已经编译好的可直接运行的部署版本: VideoChat.Exe.rar

    部署版本压缩包里的服务端可以放到公网的服务器上,双击exe即可运行。PC客户端修改VideoChat.exe.config配置文件中的IP为公网服务器的IP,即可运行PC客户端测试。

    如此,PC客户端和Web端即可互通,以进行文字聊天和视频聊天。

    四. 注意事项

    1. 首先将服务端部署到服务器上,双击exe运行起来,然后再登录Web端和PC客户端测试。

    2. 一台电脑只能运行一个Demo Web端。

    3. 测试视频聊天时,两个用户最好在不同的房间,以防止声音相互干扰。

    4. Web版与在线用户聊天时,聊天内容并不是保存在云端的所以用户下线后记录会被清空。     

    展开全文
  • webRTC视频通话.txt

    2020-04-28 11:23:08
    采用WebRTC技术,实现网页视频通话技术,WebRTC提供了视频会议的核心技术,包括音视频的采集、编解码、网络传输、显示等功能,并且还支持跨平台:windows,linux,mac,android。
  • 使用Unity进行音视频通话相信大家可以在网上搜到各家的解决方案,且对摄像头画面进行实时抠像也是有成熟的插件支持,基本上五分钟就可以实现,但是在实现两者结合的过程中,还是有各种问题,需要实现这种功能的小...
  • 七牛云实时音视频 相关配置(直播空间创建,推流域名绑定) 1.创建连麦应用(创建一个音视频会话的应用) 直播空间可以先不关联 ,等一切配置好后 再回过头配置。 2.创建一个直播空间进行推流操作, 需要一个...
  • 声网agora.io视频通话Demo,视频聊天
  • 背景在之前的WebRTC实时音视频通话之语音通话设计与实践中介绍了58 TEG部门基于 WebRTC 的实时音视频通话解决方案。考虑到腾讯微信的小程序平台提供了音视频通话与直播的支持,如果能打通基于 WebRTC 的实时音视频...
  • Java实现在线视频通话

    万次阅读 2018-12-13 17:13:26
    以下都属于个人笔记 nginx -rtmp https://stackoverflow.com/questions/37442819/unknown-directive-rtmp-in-etc-nginx-nginx-conf76
  • EasyRTC系统作为TSINGSEE青犀视频开发的网页视频语音会议系统,其语音电话在网页上的实现是不可少的,在EasyRTC的MCU版本中,采用了freeswitch作为后台的RTC服务器。 FreeSWITCH支持多种通讯技术标准,包括SIP, H...
  • vue引入集成环信Web IM有2种方式 ...npm install easemob-webrtc --save //单人视频 1.2、在main.js引入 // 引入环信 import websdk from "easemob-websdk" // 白板 // 引入视频配置 import webrtc from "easemob-we
  • 基于webrtc远程视频通话及屏幕共享

    千人学习 2019-10-25 10:25:16
    远程视频通话是视频会议系统的一个重要组成部分,目前云端视频会议主要都是基于webrtc方式进行视频通话及屏幕共享。本次课程附带全部核心源码,本源码具有版权不能用于商业及传播。
  • 去年TSINGSEE青犀视频研发团队基于WEBRTC架构开了网页视频通话平台EasyRTC,EasyRTC支持微信小程序、H5页面、APP、PC客户端等接入方式之间互通,快速从零开始搭建实时音视频通信;支持多人至百万人视频通话,满足...
  • Web端轻松实现音视频聊天通话

    万次阅读 2017-04-27 13:58:41
    SDK,网上随便搜索一下就可以下载的),加上几十行JavaScript脚本就能轻松实现视频通话;也不用去下载指定的什么浏览器,因为IE、firefox、chrome等windows平台主流浏览器全部通过,完美运行。下边就跟大伙分享分享...
  • 基于WebSocket、WebRTC实现浏览器视频通话, 仅供参考,大家一起讨论学习!
  • 使用vue做的网页版微信聊天,里面主要技术点是组建间的通信,localStorage存储聊天数据,v-model数据的双向绑定等
  • 视频通话 原理分析

    万次阅读 多人点赞 2018-10-09 10:00:45
    2012年7月,微信4.2版本首次加入了视频通话功能,如今已发展了5年,在面对亿级微信用户复杂多变的网络和设备环境,微信多媒体团队在每个技术细节上不断地深耕细作,为微信用户提供了高质量的视频通话。 今年腾讯全球...
  • 基于WebRTC实现页面浏览器视频通话-原理及实现demo

    万次阅读 多人点赞 2016-10-20 10:47:07
    基于Chrome、Java、WebSocket、WebRTC实现浏览器视频通话,整个例子中Java+WebSocket起到的作用是负责客户端之间的通信,并不负责视频的传输,视频的传输依赖于WebRTC。
  • web视频聊天

    2017-07-07 17:06:50
    基于nodejs开发的web版视频聊天,代码直接可以用,请仔细看readme。
  • 网页版 网络浏览器中的网络视频和语音(音频)通话
  • 很长时间以来,实时通信能力一直是电信类专用设备(如电话、...很多人期望网页视频实时通话是一个“拿来即用”的“端到端解决方案”,只需要在web端写几行JavaScript调用甚至不需要编程就能实现浏览器之间的实时音视...
  • #内容概述 前文说了 端到端的概念 简单代码写一个demo 基础界面 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>本机端到端连接测试<...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 6,644
精华内容 2,657
关键字:

网页视频通话

友情链接: editor_zw.rar