摘要:示例当用户从连接或断开链接时,将被调用,该方法的回调函数包含两个参数连接到相同房间名的用户在我们的示例程序当中,该方法的回调函数将建立一系列用于拨打给当前已连接到房间内的其他用户的按钮。
EasyRTC 概览
EasyRTC基于webRTC。WebRTC是W3C/IETF用于浏览器间实时音视频沟通以及数据传输的一个实现方案。WebRTC只需要一个轻量负荷的服务器就可以支持点对点(P2P)间的任何数据传输。
EasyRTC由客户端(浏览器端)的JS库与基于node.js的后端服务器组成。WebRTC已经被各个浏览器(google chrome, firefox, opera, etc)所支持,因此无需额外的浏览器插件。
Google Chrome对WebRTC的API有着最广泛的支持,Opera现在采用与Chrome相同的内核引擎,因此所有API行为与chrome基本一致。Firefox对WebRTC的Data Channel有着十分良好的实现,但仅提供了基础的视频功能。
一旦WebRTC被标准化,它将有着巨大的潜能为音视频会议,多用户游戏,以及许多其他的基于音视频,数据传输的应用提供支持。
如同其他的软件,强大的功能往往伴随着复杂的内部实现。WebRTC有着十分曲折的学习曲线,对开发人员不够友好。为了简化具体的开发流程,我们(Priologic)构建了EasyRTC框架。
构建一个基于WebRTC的应用通常有如下步骤。
将本地摄像头、麦克风获取到的数据输出成media stream对象
与信令服务器建立连接
通过浏览器与目标用户建立p2p通信
将media stream绑定到
通过使用EasyRTC,一些步骤可以被简化到一个简单的通信(call)当中,
能极大地简化开发流程,尤其是当开发人员需要投入更多的精力于多平台支持当中。
此文档是编写基于WebRTC应用的一个基本教程,但并未包含EasyRTC的所有API。
术语callbakck(回调函数)
Media Stream 浏览器音视频输出对象
Peer Connection 点对点连接
Server
安装EasyRTC与获取支持EasyRTC的安装十分简单,多数平台可在10分钟内完成。我们提供了Windows,Linux,Mac的安装向导。EasyRTC的源码可在[https://github.com/priologic/...]获取。在doc目录下可以获取到客户端与服务端的所有HTML说明文档
视频会议html 略
页面载入完成(onload)后调用初始化函数(initialization function)。
初始化函数的最主要作用是调用EasyRTC.easyApp方法。该方法有如下参数
applicationName - String 应用名,如"Company_Chat_Line"
self-video-id - String video标签id
array-of-caller-video-ids - Array 包含了其他用户(除当前用户)的video标签id
successCallback - 连接成功时回调函数
初始化函数可以使用EasyRTC.setRoomOccupantListener来注册一个回调函数,以用于获取当前已连接到同一房间内的其他用户id,。
示例:
function my_init() { easyrtc.setRoomOccupantListener(loggedInListener) easyrtc.easyApp("Company_chat_line", "self", ["caller"], id => { console.info("My id is " + id) }) }
当用户从"Company_chat_line"连接或断开链接时,easyrtc.setRoomOccupantListener将被调用,该方法的回调函数包含两个参数:
String room name
Array 连接到相同房间名的用户id
在我们的示例程序当中,该方法的回调函数将建立一系列用于“拨打”给当前已连接到房间内的其他用户的按钮。
html 略
多数情况下可以忽略room_name参数,除非你的应用允许用户同时连接到多个房间。
在现实的应用当中,我们不会使用easyrtc的默认id当作按钮的label属性。我们将使用类似姓名,职位等建立起与easyrtc id相关联的内容以用作按钮的label属性。
初始化一个call,我们只需要调用 easyrtc.call 方法,传入目标用户的id,该方法包含三个回调函数:
successCallback(id)
errorCallback(errorCode, errorText)
accepted(wasAccepted, id) 指明该call是否被接受
示例代码:
function performCall(id) { easyrtc.call(id, id => { console.info("completed call to " + id) }, errorMessage => { console.error("err: " + errorMessage) }, (accepted, bywho) => { console.info(accepted ? "accepted" : "rejected" + " by " + bywho) }) }
html 略
视频会议(Advanced)在上一节,我们大致地描述了构建一个视频会议应用的最简单情形。
在这一节,我们将进一步深入。
除了调用easyrtc.easyApp,你也可以调用easyrtc.initMediaSource来直接获取本地设备的media stream,成功之后可以调用easyrtc.connect方法来连接到信令服务器。这也是easyrtc.easyApp的内部实现。
html略
注意: easyrtc.getLocalStream和easyrtc.setVideoObjectSrc,前者用于当easyrtc.initMediaSource调用完成,从本地摄像头和麦克风获取media stream,后者用于将media stream与video标签绑定。一起使用便可以十分便携地供用户实时观察到他们自己的图像。
我们还需要两个其他函数
一个用于提供远程用户的media stream
easyrtc.setStreamAcceptor((callerId, stream) => { let video = document.getElementById("caller") easyrtc.setVideoObjectSrc(video, stream) })
一个用于检测远程用户是否挂起(离线)。该函数用于清除对应的video标签
easyrtc.setOnStreamClosed(callerId => { easyrtc.setVideoObjectSrc(document.getElementById("caller"), "") })
整个js文件如下
// 设置远程用户的media stream 的关联video标签 easyrtc.setStreamAcceptor((callerId, stream) => { let video = document.getElementById("caller") // 绑定media stream到video标签对象 easyrtc.setVideoObjectSrc(video, stream) }) // 当远程media strem 关闭 easyrtc.setOnStreamClosed(callerId => { // 清除关联的video标签内容 easyrtc.setVideoObjectSrc(document.getElementById("caller"), "") }) // 初始化函数 function my_init() { // 设置监听器,获取当前在线的用户 easyrtc.setRoomOccupantListener(loggedInListener) // 连接成功处理函数 let connectSuccess = myId => { console.info("My easyrtc id is " + myId) } // 连接失败 创建本地media stream对象失败时调用函数 let connectFailure = (errorCode, errText) => { console.error(errText) } // 初始化本地media stream easyrtc.initMediaSource(() => { let selfVideo = document.getElementById("self") // 绑定本地media stream 到video tag easyrtc.setVideoObjectSrc(selfVideo, easyrtc.getLocalStream()) // 连接到服务器 easyrtc.connect("Company_Chat_line", connectSuccess, connectFailure) }, connectFailure) } // 当获取到当前房间内在线用户 function loggedInListener(roomName, otherPeers) { let otherClientDiv = document.getElementById("otherClients") while(otherClientDiv.hasChildNodes()) { // 移除最后一个 “text ” otherClientDiv.removeChild(otherClientDiv.lastChild) } for (let i in otherPeers) { let button = document.createElement("button") // 为每一个远程用户创建一个按钮监听器 button.onclick = easyrtcId => { // 发起连接 return (easyrtcId) => performCall(easyrtcId) }(i) let label = document.createTextNode(i) button.appendChild(label) otherClientDiv.appendChild(button) } } function performCall(id) { easyrtc.call(id, id => { console.info("completed call to " + id) }, (errorCode, errText) => { console.error("err: " + errorText) }, (accepted, bywho) => { console.info(accepted ? "accepted" : "rejected" + " by " + bywho) }) }使用多个本地media stream源
使用多个media stream的基本思想是,你需要为每个media stream命名。
当你调用initMediaSource,它的第三个参数便是media stream的名字,
如:
easyrtc.initMediaStream(success, failure, yourname)
如果你没有传入第三个参数,则该media stream会得到一个默认的"default"。
使用easyrtc.getLocalMediaIds以获取所有本地media stream的名字
let ids = easyrtc.getLocalMediaIds() ids.map(id => console.info(id))
当你初始化一个call,可以传入一个stream name的数组作为第五个参数,同样的,当你接受call时,你可以传入一个stream name的数组作为accept回调函数的第二个参数。
easyrtc.call(otherEasyrtcId, successCB, failCB, wasAcceptedCB, ["first_name", "second_name", "etc"]) easyrtc.setAcceptChecker((otherGuy, acceptCallback) => { acceptCallback(true, ["first_name", "second_name"]) })
你也可以通过使用easyrtc.addStreamToCall向一个已存在的call添加meida stream。该方法接受三个参数,接受stream的id,stream的名字,以及一个optional的回调处理函数。
注意:EasyApp 框架并不是专门为多media stream而设计的。它的初衷便是假定只有单个本地media stream。
如果你想使用media stream,那么你就必须自己将这些media stream绑定到video标签。
EasyRTC允许注册一个在用户每次收到call时都将被调用的函数。该函数接受远程用户的id,以及一个报告函数(reporting function)作为参数,报告函数接受一个参数,true接受对话,false拒绝对话。
easyrtc.setAcceptChecker( function(easyrtcid, acceptor){ if( easyrtc.idToName(easyrtcid) === "Fred" ){ acceptor(true); } else if( easyrtc.idToName(easyrtcid) === "Barney" ){ setTimeout( function(){ acceptor(true, ["myOtherCam"]); // myOtherCam presumed to a streamName }, 10000); } else{ acceptor(false); } });加入或离开房间
Room是EasyRTC的一个隔离(compartmentalize)功能,目的是为用户建立起一个个“chat rooms”。
房间的行为受服务器安装的EasyRTC Server的配置所影响(详见服务器模块文档)。默认行为如下:
除非用户在连接前指定了所要加入的房间名,否则将会加入默认的“default”房间。
一个用户可以是多个房间的成员
每个用户所加入的任一个房间发生变化时(用户的加入,离开),都会触发roomOccupantListener函数
加入一个不存在的房间将会创建它
加入房间
easyrtc.joinRoom(roomName, roomParameters, successCallback, failureCallback)
其中,roomParameters是Application specific(不详),可以为空。joinRoom可以在任何时候调用任意多次,但successCallback, failureCallback只会在成功与信令服务器建立连接之后才会被调用。
离开房间
easyrtc.leaveRoom(roomName, successCallback, failureCallback)
leaveRoom的性质同joinRoom
监听Error你可以通过easyrtc.setOnError注册一个error callback用以处理错误。该函数接受一个形如{"errorCode": "errorCode", "errorText": "errorText"}的对象。
easyrtc.setOnError(errEvent => { console.error(errEvent.errorText) })发送消息
你可以通过调用easyrtc.sendDataWS来使用websocket通信,
easyrtc.sendDataWS(destination, messageType, messageData, ackHandler) easyrtc.sendDataWS("xkxkxkxkxk9c93", "contactInfo", {firstName: "jack", lastName: "smith"}, ackMsg => { // ackMsg 为来自服务器的确认信息 if (ackMsg.msgType === "error") { console.error(ackMsg.msgData.errorText) } })
注意: 通过websocket通信意味着你指定信息要通过服务器转发
destination 可以是peer的id,或者是一个指定了一个或多个目标id的js对象,或者房间(详见文档)。
messageType需要自行指定,ackHandler处理来自服务器的确认信息
处理来自其他用户的信息:
easyrtc.setPeerListener((sender_id, msgType, msgData, targeting) => {
if (msgType === "contactInfo") { console.info(sender_id + " is named " + msgData.firstName + " " + msgData.lastName) }
})
其中,当使用WebRTC的data channel发送数据时,targeting为null,否则为{targetEasyrtcid, targetGroup, targetRoom}当中的一个。
你也可以为特定的msgType或sender指定监听器,在这种情况下,每次将只有一个监听器会被调用,指定的监听器将被优先调用。
使用Data Channels在使用data channel之前,发送者和接收者都必须启用data channels。
easyrtc.enableDataChannels(true)
之后便可监听与特定用户的datachannel的 ready 和 close 事件,
easyrtc.setDataChannelOpenListener(sourceEasyrtcId => console.info("channel is open ") ) easyrtc.setDataChannelCloseListener(sourceEasyrtcid => console.info("channel is close ") )
open监听器被调用之后,便可以通过easyrtc.sendDataP2P来发送消息:
easyrtc.sendDataP2P(targetEasyrtcid, "contactInfo", {firstName: "jack", lastName: "smith"})
监听data channels消息与websocket消息一致
获取当前连接数通过easyrtc.getConnectionCount来获取当前用户的连接数,该函数返回一个number
挂起通过easyrtc.hangup(peerId)来挂起与特定用户的连接
easyrtc.hangupAll()来挂起与所有用户的连接
与服务器断开链接easyrtc.disconnect()
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/92451.html
摘要:毕竟官方文档才是未经提炼的纯技术点,读书不能只读二手书。目前网上能找到的中文文档基本都是基于的,但截至此文发布,最新的稳定版都已经是了。翻译过程中主要参考官方英文文档,以及极客学院的官方文档中文翻译。 前言 相信很多开发者和我一样,在学习一门技术的时候,通过网上的各种教程和视频入门之后会发现自己遇到一个上升瓶颈。造成这个瓶颈的很大一部分原因,我认为是进阶教程的知识点过于分散,同时高质量...
摘要:关于本文档本文档的目的,是全面地解释的,即可作为参考文档,同时也包含了概念的讲解。但有的全新的实验性的,或者存在危险性的部分则会被重新设计。稳定级别锁定只会有安全性能或相关的修复。不接受对此做修改的建议。 关于本文档 本文档的目的,是全面地解释Node.js的API,即可作为参考文档,同时也包含了概念的讲解。每个章节都描述了一个内置模块或一个高阶概念(high-level concep...
阅读 2436·2019-08-30 15:52
阅读 2237·2019-08-30 12:51
阅读 2832·2019-08-29 18:41
阅读 2812·2019-08-29 17:04
阅读 810·2019-08-29 15:11
阅读 1719·2019-08-28 18:02
阅读 3602·2019-08-26 10:22
阅读 2510·2019-08-26 10:12