"use strict";
var jQuery = require("jquery");
var Utility = require("./Utility.js");
var handleMouseEvent = require("./MouseEvent.js");
var getStats = require("./getStats");
var Condicio = require("condicio");
function StreamDisplayer(session, viewID, parentElem, turnServer, callback) {
var _this = this;
this.session = session;
this.viewID = viewID;
this.parentElem = parentElem;
// 创建播放div元素
this.displayElem = this.createDisplayElem();
// 创建流播放器
this.video = this.createVideo();
// 处理大小变化
this.handleDisplayElemSizeChange();
// 处理鼠标事件
handleMouseEvent(session, viewID, this.displayElem);
// 创建P2P连接
this.createP2PCommunication(turnServer, callback);
};
StreamDisplayer.prototype.release = function(){
this.parentElem.removeChild(this.displayElem);
};
// 创建显示元素
StreamDisplayer.prototype.createDisplayElem = function() {
var displayElem = document.createElement('div');
this.parentElem.appendChild(displayElem);
// TODO:目标是让外部能够区分显示的div,这里应该由外部想办法区分,而不应该内部处理
jQuery(this.displayElem).attr("id","bcd");
// 不让选中,避免引起闪屏
displayElem.onselectstart = function(){ return false; };
return displayElem;
};
// 创建视频播放器
StreamDisplayer.prototype.createVideo = function() {
var video = document.createElement("video");
video.autoplay = true; // 自动播放
video.muted = true; // 不输出音频
this.displayElem.appendChild(video);
//阻止默认事件,保证不影响上层事件,目的是保证最上层能正确获取鼠标消息
jQuery(video).on('mousedown', function (e){
e.preventDefault();
});
return video;
};
// 处理DispalyElem的大小变化
StreamDisplayer.prototype.handleDisplayElemSizeChange = function() {
var _this = this;
// 处理大小变化
var resizeListener = function () {
var w = jQuery(_this.parentElem).width();
var h = jQuery(_this.parentElem).height();
if (_this.video.width !== w || _this.video.height !== h) {
_this.video.width = w;
_this.video.height = h;
_this.session.request(_this.viewID, "resize", { width: w, height: h });
}
setTimeout(resizeListener, 200)
}
resizeListener();
};
// 创建PeerConnetion
function createPeerConnection(turnServer) {
var iceServer = {
"iceServers":[
{
"urls": ["turn:"+turnServer.ip+":"+ turnServer.port +"?transport=udp",
"turn:"+turnServer.ip+":"+ turnServer.port +"?transport=tcp"],
"username":turnServer.userName,
"credential":turnServer.password
}
]
};
return new RTCPeerConnection(iceServer);
};
// 向服务器注册ICE协商函数
function registerIceCandidateCallback(session, viewID, peerConnection, callback){
var callbackWrapper = function (error, result) {
if(!error) {
var candidate = new RTCIceCandidate(result.sdpObj);
peerConnection.addIceCandidate(candidate);
}
else {
callback(error);
}
};
var callbackID = Utility.genGUID();
session.registerCallback(callbackID, callbackWrapper, "IceCandidateCallback", true);
session.request(viewID, "registerIceCandidateCallback", {"callbackID": callbackID});
}
// 向服务器请求SDP
function requestSDPOffer(session, viewID, peerConnection, callback){
var callbackWrapper = function (error, offerSDP) {
if (error)
callback(error);
else {
peerConnection.setRemoteDescription(new RTCSessionDescription(offerSDP.sdpObj));
var createAnswerSucced = function(answer) {
peerConnection.setLocalDescription(answer);
var callbackError = function (error) {
if(error)
callback(error);
};
var callbackID = Utility.genGUID();
session.registerCallback(callbackID, callbackError);
session.request(viewID, "sendSDPAnswer", {"sdpObj": answer,"callbackID": callbackID});
};
peerConnection.createAnswer(createAnswerSucced, function (error) {
callback(error);
});
}
};
var callbackID = Utility.genGUID();
session.registerCallback(callbackID, callbackWrapper);
session.request(viewID, "requestSDPOffer", {"callbackID": callbackID});
}
// 向服务器发送状态信息
function loopSendStatsInfos(session, viewID, peerConnection) {
var preStatsInfo = "";
var handleStatsFunc = function(result) {
var results = result.results;
for (var i = 0; i < results.length; i++) {
if (results[i].type == 'ssrc' && !Condicio.isUndefined(results[i].googTimingFrameInfo)) {
var statsInfo = {};
var timeInfos = results[i].googTimingFrameInfo.split(",");
statsInfo.encodeTime = Number(timeInfos[3]) - Number(timeInfos[2]);
statsInfo.packetTime = Number(timeInfos[4]) - Number(timeInfos[3]);
statsInfo.sendTime = Number(timeInfos[5]) - Number(timeInfos[4]);
statsInfo.receiveTime = Number(timeInfos[9]) - Number(timeInfos[8]);
statsInfo.bufferTime = Number(timeInfos[10]) - Number(timeInfos[9]);
statsInfo.decodeTime = Number(timeInfos[11]) - Number(timeInfos[10]);
if (preStatsInfo != JSON.stringify(statsInfo)) {
session.request(viewID, "sendStatsInfo", { "statsInfo": statsInfo });
preStatsInfo = JSON.stringify(statsInfo);
}
}
}
};
getStats(peerConnection, handleStatsFunc, 50);
};
// 建立P2P通信
StreamDisplayer.prototype.createP2PCommunication = function(turnServer, callback) {
var _this = this;
var peerConnection = createPeerConnection(turnServer);
peerConnection.onaddstream = function(event) {
_this.video.srcObject = event.stream;
loopSendStatsInfos(_this.session, _this.viewID, peerConnection);
};
peerConnection.oniceconnectionstatechange = function(ev) {
var connection = ev.target;
switch(connection.iceConnectionState) {
case "connected":
callback(null);
break;
case "failed":
callback("create view3D failed: webrtc connect failed");
break;
}
}
registerIceCandidateCallback(this.session, this.viewID, peerConnection, callback);
peerConnection.onicecandidate = function(event) {
if (event.candidate !== null) {
var callbackError = function (error) {
if(error)
callback(error);
};
var callbackID = Utility.genGUID();
_this.session.registerCallback(callbackID, callbackError);
_this.session.request(_this.viewID, "sendIceCandidate", {"candidate": event.candidate,"callbackID": callbackID});
}
};
requestSDPOffer(this.session, this.viewID, peerConnection, callback);
};
module.exports = StreamDisplayer;