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()
相關文章
相關標籤/搜索