UNPKG

pixelstream-cn

Version:

基于虚幻引擎的像素流平台

212 lines (201 loc) 6.71 kB
const ToClientMessageType = { QualityControlOwnership: 0, Response: 1, Command: 2, FreezeFrame: 3, UnfreezeFrame: 4, VideoEncoderAvgQP: 5, } export default class Webrtc{ constructor(){ this.audio=null; this.stream=null; this.pc=null; this.dcClient=null; } //设置ice处理函数 setIceCandidateHandel(fn){ this.iceCandidateHandel=fn; return this; } //设置媒体流处理函数 setStreamHandel(fn){ this.streamHandel=fn; this.streamHandel(this.stream); return this; } setAudioHandel(fn){ this.audioHandel=fn; this.audioHandel(this.audio); return this; } //设置数据通道打开处理函数 setDataChannelOpenHandel(fn){ this.dataChannelOpenHandel =fn; return this; } //设置数据通道关闭处理函数 setDataChannelCloseHandel(fn){ this.dataChannelCloseHandel =fn; return this; } //設置速率事件動作 setSpeedHandel(fn){ this.speedHandel=fn; return this; } //发送动作 send(action){ // if(this.dcClient && this.dcClient.readyState == 'open'){ this.sendBuffer(action.buffer); if(action.promise){ return action.promise; } // } return this; } sendBuffer(buffer){ if(this.dcClient && this.dcClient.readyState == "open"){ this.dcClient.send(buffer); } return this; } message(message){ this.dataChannelMessageHandel = ((type,response)=>{ switch(type){ case ToClientMessageType.QualityControlOwnership: message.qualityControlOwnershipHandel(response); break; case ToClientMessageType.Response: try { let result=JSON.parse(response); if(result.message){ callback.runFunction(result.message,result); } } catch (error) { console.warn("返回的数据非json字符串"); } message.responseHandel(response); break; case ToClientMessageType.Command: message.commandHandel(response); break; case ToClientMessageType.FreezeFrame: message.freezeFrameHandel(response); break; case ToClientMessageType.UnfreezeFrame: message.unfreezeFrameHandel(response); break; case ToClientMessageType.VideoEncoderAvgQP: message.videoEncoderAvgQPHandel(response); break; } }); return this; } async init(config){ let _this = this; this.pc = new RTCPeerConnection(config); this.pc.addEventListener('icecandidate', (e) => { if (e.candidate && e.candidate.candidate) { if(_this.iceCandidateHandel){ _this.iceCandidateHandel(e.candidate); } } }) this.pc.addEventListener('track', (e) => { if(e.track.kind == "audio"){ _this.audio=e.streams[0]; if(_this.audioHandel){ _this.audioHandel(_this.audio); } return; }else if(e.receiver.track.kind=="video"){ _this.stream=e.streams[0]; if(_this.streamHandel){ _this.streamHandel(_this.stream); } } }) this.dcClient = this.pc.createDataChannel('cirrus', { ordered: true }) this.dcClient.onopen = function (e) { _this.dataChannelOpenHandel(e); } this.dcClient.onclose = function (e) { _this.dataChannelCloseHandel(e); } this.dcClient.onmessage = function (e) { let data = e.data var view = new Uint8Array(data) let response = new TextDecoder('utf-16').decode(data.slice(1)); if(_this.dataChannelMessageHandel){ _this.dataChannelMessageHandel(view[0],response); } if(view[0]==5){ if(_this.speedHandel){ _this.speedHandel(response); } } } let offer = await this.getOffer(); return offer; } async getOffer() { let offer = await this.pc.createOffer({ offerToReceiveAudio: 1, // 1开启 0关闭 offerToReceiveVideo: 1, voiceActivityDetection: false }) //设置压缩率和立体声 offer.sdp = offer.sdp.replace('useinbandfec=1', 'maxaveragebitrate=510000;sprop-stereo=1;stereo=1;useinbandfec=1'); // offer.sdp = offer.sdp.replace(/(a=extmap-allow-mixed)\r\n/gm, ""); await this.pc.setLocalDescription(offer) return offer } setAnswer(answer){ if(!this.pc){ return; } var answerDesc = new RTCSessionDescription(answer) this.pc.setRemoteDescription(answerDesc) } setIceCandidate(candidate){ if(!this.pc){ return; } let rtcCandidate = new RTCIceCandidate(candidate) this.pc.addIceCandidate(rtcCandidate).then((_) => { }) } close(){ if(this.dcClient){ this.dcClient.onopen=null; this.dcClient.onmessage=null; this.dcClient.onclose=null; if(this.dcClient.readyState == "open" || this.dcClient.readyState == "connecting"){ this.dcClient.close(); } this.dcClient=null; } this.stopStream(this.audio); this.stopStream(this.stream); this.audio=null; this.stream=null; if(this.pc){ if(this.pc.signalingState != "closed"){ this.pc.close(); } this.pc=null; } } stopStream(stream){ if(!stream || !stream.getTracks){ return; } stream.getTracks().forEach(track=>{ if(track.readyState != "ended"){ track.stop(); } }); } }