Echo測試示範的是發送給伺服器網關的音頻和視訊,伺服器會回傳給你,效果如下圖所示:
代碼分析
建立線程
在janus = new Janus()時,調用Janus(gatewayCallbacks)在其中有函數createSession,并且傳入下面的回調函數:
createSession建立請求,成功建立一次httpAPICall,輸出Created handle: 1747107217737787
Janus.httpAPICall(server, {
verb: 'POST',
withCredentials: withCredentials,
body: request,
success: function(json) {
Janus.debug(json);
if(json["janus"] !== "success") {
Janus.error("Ooops: " + json["error"].code + " " + json["error"].reason); // FIXME
callbacks.error(json["error"].reason);
return;
}
Janus.sessions[sessionId] = that;
eventHandler();
callbacks.success();
},
成功回調eventHandler以及echoest的sucesss
建立插件
echoest的sucesss函數如下:
定義了插值對象及對應的回調函數。
janus.attach(
{
}
this.attach = function(callbacks) { createHandle(callbacks)} 實際調用createHandle,
并把對應的回調plugin,succecss等傳入,如下圖。
在函數function createHandle(callbacks) 中,定義了插件的各個函數,并且回調echotest.js中的janus.attach中的success函數,并且輸出Plugin attached! (janus.plugin.echotest, id=1747107217737787),其函數的主要作用是傳入對應的回調函數,并且定義一個插件及其許多許應的函數,并且與伺服器進行通信:
pluginHandles[handleId] = pluginHandle;
callbacks.success(pluginHandle);
echotest = pluginHandle;定義為插件,其中定義許多函數。包括:
var pluginHandle =
{
session : that,
plugin : plugin,
id : handleId,
token : handleToken,
detached : false,
webrtcStuff : {}
getId : function() { return handleId; },
getPlugin : function() { return plugin; },
getVolume : function() { return getVolume(handleId); },
isAudioMuted : function() { return isMuted(handleId, false); },
muteAudio : function() { return mute(handleId, false, true); },
unmuteAudio : function() { return mute(handleId, false, false); },
isVideoMuted : function() { return isMuted(handleId, true); },
muteVideo : function() { return mute(handleId, true, true); },
unmuteVideo : function() { return mute(handleId, true, false); },
getBitrate : function() { return getBitrate(handleId); },
send : function(callbacks) { sendMessage(handleId, callbacks); },
data : function(callbacks) { sendData(handleId, callbacks); },
dtmf : function(callbacks) { sendDtmf(handleId, callbacks); },
consentDialog : callbacks.consentDialog,
iceState : callbacks.iceState,
mediaState : callbacks.mediaState,
webrtcState : callbacks.webrtcState,
slowLink : callbacks.slowLink,
onmessage : callbacks.onmessage,
createOffer : function(callbacks) { prepareWebrtc(handleId, callbacks); },
createAnswer : function(callbacks) { prepareWebrtc(handleId, callbacks); },
handleRemoteJsep : function(callbacks) { prepareWebrtcPeer(handleId, callbacks); },
onlocalstream : callbacks.onlocalstream,
onremotestream : callbacks.onremotestream,
ondata : callbacks.ondata,
ondataopen : callbacks.ondataopen,
oncleanup : callbacks.oncleanup,
ondetached : callbacks.ondetached,
hangup : function(sendRequest) { cleanupWebrtc(handleId, sendRequest === true); },
detach : function(callbacks) { destroyHandle(handleId, callbacks); }
}
并且向伺服器發起一次請求,通信伺服器,如果成功時,才回調echotest.js中的janus.attach中的success函數,即
success: function(pluginHandle) {
$('#details').remove();
echotest = pluginHandle;
Janus.log("Plugin attached! (" + echotest.getPlugin() + ", id=" + echotest.getId() + ")");
// Negotiate WebRTC
var body = { "audio": true, "video": true };
Janus.debug("Sending message (" + JSON.stringify(body) + ")");
echotest.send({"message": body});
Janus.debug("Trying a createOffer too (audio/video sendrecv)");
echotest.createOffer(
{
// No media provided: by default, it's sendrecv for audio and video
media: { data: true }, // Let's negotiate data channels as well
// If you want to test simulcasting (Chrome and Firefox only), then
// pass a ?simulcast=true when opening this demo page: it will turn
// the following 'simulcast' property to pass to janus.js to true
simulcast: doSimulcast,
success: function(jsep) {
Janus.debug("Got SDP!");
Janus.debug(jsep);
echotest.send({"message": body, "jsep": jsep});
},
error: function(error) {
Janus.error("WebRTC error:", error);
bootbox.alert("WebRTC error... " + JSON.stringify(error));
}
});
$('#start').removeAttr('disabled').html("Stop")
.click(function() {
$(this).attr('disabled', true);
clearInterval(bitrateTimer);
janus.destroy();
});
},
在這個函數準備向伺服器發送相應的資訊連接配接請求。
發送音視訊資訊
var body = { “audio”: true, “video”: true };
echotest.send({“message”: body});
echotest.send 實際調用sendMessage
發送的請求為:
var request = { “janus”: “message”, “body”: message, “transaction”: transaction };
Sending message to plugin (handle=3650608414117457):
響應
然後調用success函數
後面通過handleEvent 收到資訊,調用Onmessage函數。資訊如下:
echotest.createOffer函數,實際調用prepareWebrtc
Trying a createOffer too (audio/video sendrecv
列印上面消息,并且調用httpAPICall來進行通信
function eventHandler()
作用是發出httpAPICall請求,然後請求成功執行handleEvent
handleEvent 收到資訊,調用Onmessage函數。
建立offer資訊
調用echotest.createOffer,實際調用prepareWebrtc函數,其中getUserMedia
獲得本地流,并且調用streamsDone。代碼:
navigator.mediaDevices.getUserMedia(gumConstraints)
.then(function(stream) {
pluginHandle.consentDialog(false);
streamsDone(handleId, jsep, media, callbacks, stream); })
其中streamsDone 函數建立RTCPeerConnection連接配接,并且準備本地的sdp,并且調用onlocalstream把本地流顯示出來。代碼如下:
根據目前條件,選擇執行下面功能
config.pc = new RTCPeerConnection(pc_config, pc_constraints);
pluginHandle.onlocalstream(config.myStream);//顯示本地流
createOffer(handleId, media, callbacks);//調用函數 createOffe
config.pc.setRemoteDescription//如果已經有sdp資訊,遠端sdp,調用此處
在函數function createOffer(handleId, media, callbacks)中:
config.pc.createOffer 調用系統的函數,并且成功的話回調。
如果成功回調callbacks.success(jsep);即調用echotest.createOffer裡的時,成功回調,準備向伺服器發送sdp資訊:
success當,當收到本地sdp資訊時,成功回調,準備向伺服器發送sdp資訊:
success: function(jsep) {
Janus.debug(“Got SDP!”);
Janus.debug(jsep);
echotest.send({“message”: body, “jsep”: jsep});
調用sendMessage用來發送消息,如果發送成功,會收到ack包。
收到SDP資訊
當伺服器處理完成,主動向用戶端發這送sdp資訊,用戶端是通過handleEvent來處理。
else if(json["janus"] === "event") {
Janus.debug("Got a plugin event on session " + sessionId);
var callback = pluginHandle.onmessage;
if(callback !== null && callback !== undefined) {
Janus.debug("Notifying application...");
callback(data, jsep);//實際調用echotest.js中函數onmessage
}
收到消息,成功回調函數onmessage。收到遠端的SDP資訊。
并且調用echotest.handleRemoteJsep({jsep: jsep});即執行prepareWebrtcPeer
prepareWebrtcPeer的作用是設定遠端的sdp資訊,用來建立p2p連接配接config.pc.setRemoteDescription。
回調streamsDone裡面的以下函數來獲得遠端流config.pc.ontrack,這個是webrtc自已的函數,可能是回調函數,這樣拿來顯示遠端流。
config.pc.ontrack = function(event) {
pluginHandle.onremotestream(config.remoteStream);
并且回調onremotestream用來顯示遠端流。