EasyRTC官方tutorial [译文]

EasyRTC

概览

EasyRTC基于webRTC。WebRTC是W3C/IETF用于浏览器间实时音视频沟通以及数据传输的一个实现方案。WebRTC只须要一个轻量负荷的服务器就能够支持点对点(P2P)间的任何数据传输。javascript

EasyRTC由客户端(浏览器端)的JS库与基于node.js的后端服务器组成。WebRTC已经被各个浏览器(google chrome, firefox, opera, etc)所支持,所以无需额外的浏览器插件。html

Google Chrome对WebRTC的API有着最普遍的支持,Opera如今采用与Chrome相同的内核引擎,所以全部API行为与chrome基本一致。Firefox对WebRTC的Data Channel有着十分良好的实现,但仅提供了基础的视频功能。java

一旦WebRTC被标准化,它将有着巨大的潜能为音视频会议,多用户游戏,以及许多其余的基于音视频,数据传输的应用提供支持。node

如同其余的软件,强大的功能每每伴随着复杂的内部实现。WebRTC有着十分曲折的学习曲线,对开发人员不够友好。为了简化具体的开发流程,咱们(Priologic)构建了EasyRTC框架。git

构建一个基于WebRTC的应用一般有以下步骤。github

  • 将本地摄像头、麦克风获取到的数据输出成media stream对象
  • 与信令服务器创建链接
  • 经过浏览器与目标用户创建p2p通讯
  • 将media stream绑定到<video>

经过使用EasyRTC,一些步骤能够被简化到一个简单的通讯(call)当中,
能极大地简化开发流程,尤为是当开发人员须要投入更多的精力于多平台支持当中。web

此文档是编写基于WebRTC应用的一个基本教程,但并未包含EasyRTC的全部API。chrome

术语

  • 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标签。

屏幕分享

只使用音频或视频功能

拒绝远程对话(call)

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()
相关文章
相关标签/搜索