usc-rtc-client 1.1.6 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Readme.md +278 -108
- package/dist/client/RtcClient.d.ts +16 -0
- package/dist/client/RtcClientBase.d.ts +32 -0
- package/dist/client/RtcClientEvent.d.ts +15 -0
- package/dist/client/RtcSignalApi.d.ts +51 -0
- package/dist/client/RtcSignalServer.d.ts +19 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.es.js +1374 -0
- package/dist/index.umd.js +6 -0
- package/dist/log/Logger.d.ts +4 -0
- package/dist/message/SignalMessage.d.ts +26 -0
- package/dist/message/SingalMessageType.d.ts +20 -0
- package/dist/peer/LocalStreamHandler.d.ts +94 -0
- package/dist/peer/RTCPeerConnectionHandler.d.ts +94 -0
- package/dist/peer/StreamUtil.d.ts +12 -0
- package/dist/session/RtcAbstractSession.d.ts +34 -0
- package/dist/session/RtcCalledSession.d.ts +10 -0
- package/dist/session/RtcCalledTyped.d.ts +9 -0
- package/dist/session/RtcInviteStatus.d.ts +8 -0
- package/dist/session/RtcSession.d.ts +24 -0
- package/dist/session/RtcSessionEvent.d.ts +11 -0
- package/dist/session/RtcSessionStatus.d.ts +5 -0
- package/dist/session/RtcSessionStatusAdapter.d.ts +1 -0
- package/dist/session/UscRtcProtocol.d.ts +6 -0
- package/dist/websocket/RtcSocketServerHandler.d.ts +31 -0
- package/dist/websocket/RtcWebSocket.d.ts +31 -0
- package/dist/websocket/RtcWebSocketEvent.d.ts +5 -0
- package/package.json +14 -13
- package/dist/index.esm.js +0 -1
- package/dist/index.js +0 -1
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
(function(k,C){typeof exports=="object"&&typeof module<"u"?C(exports):typeof define=="function"&&define.amd?define(["exports"],C):(k=typeof globalThis<"u"?globalThis:k||self,C(k.UscRtc={}))})(this,(function(k){"use strict";var C=(i=>(i.bye="bye",i.stream="stream",i.reInvite="reInvite",i.localAudioChange="localAudioChange",i.localVideoChange="localVideoChange",i.localStreamChange="localStreamChange",i))(C||{}),x=(i=>(i.connected="connected",i.disconnected="disconnected",i.invite="invite",i))(x||{}),P=(i=>(i.PTTInfo="PTTInfo",i.FPREInfo="FPREInfo",i.IMSInfo="IMSInfo",i.ERROR="error",i.SPEAKER="speaker",i.TALKING="talking",i.ACTIVE_GROUP="activeGroup",i.JOIN_INFO="joinInfo",i))(P||{}),y=(i=>(i.MESSAGE_TYPE_REGISTER="REGISTER",i.MESSAGE_TYPE_INVITE="INVITE",i.MESSAGE_TYPE_REINVITE="reINVITE",i.MESSAGE_TYPE_ICE="ICE",i.MESSAGE_TYPE_INFO="INFO",i.MESSAGE_TYPE_BYE="BYE",i))(y||{}),W=(i=>(i.FPRE="fpre",i.IMS="ims",i.PTT_QUERY_ONLINE_USER="15",i.PTT_ANSWER_ONLINE_USER="115",i.PTT_QUERY_INFO="16",i.PTT_QUERY_INFO_CONFIRM="116",i))(W||{});let K=(i=21)=>crypto.getRandomValues(new Uint8Array(i)).reduce((e,t)=>(t&=63,t<36?e+=t.toString(36):t<62?e+=(t-26).toString(36).toUpperCase():t>62?e+="-":e+="_",e),"");const ue=i=>{i!==void 0&&(i.pause(),i.removeAttribute("src"),i.removeAttribute("srcObject"))},q=(i,e)=>{i!==void 0&&e!==void 0&&(e.srcObject=i,e.play())},J=i=>{i.onaddtrack=null,i.onremovetrack=null,i.getTracks().forEach(e=>{i?.removeTrack(e),e.onended=null,e.onmute=null,e.onunmute=null,e.stop()})};let G=!1;const p=(i,...e)=>{G&&console.log(`%c usc-rtc-devtools %c ${i} %c `,"background:#35495e ; padding: 1px; border-radius: 3px 0 0 3px; color: #fff","background:#41b883 ; padding: 1px; border-radius: 0 3px 3px 0; color: #fff","background:transparent",...e)},le=(i,...e)=>{G&&console.log(`%c usc-rtc-devtools %c ${i} %c `,"background:#35495e ; padding: 1px; border-radius: 3px 0 0 3px; color: #fff","background:#ff0000 ; padding: 1px; border-radius: 0 3px 3px 0; color: #fff","background:transparent",...e)},he=()=>{G=!1},fe=()=>{G=!0};class me{static formatOffer(e){let{sdp:t}=e;if(t===void 0)throw new Error("offer sdp is empty");return t=t.split(`\r
|
|
2
|
+
`).filter(s=>s.indexOf("a=group:BUNDLE")===-1).join(`\r
|
|
3
|
+
`),e.sdp=t,e}}var D={exports:{}},B;function ve(){if(B)return D.exports;B=1;var i=typeof Reflect=="object"?Reflect:null,e=i&&typeof i.apply=="function"?i.apply:function(o,d,u){return Function.prototype.apply.call(o,d,u)},t;i&&typeof i.ownKeys=="function"?t=i.ownKeys:Object.getOwnPropertySymbols?t=function(o){return Object.getOwnPropertyNames(o).concat(Object.getOwnPropertySymbols(o))}:t=function(o){return Object.getOwnPropertyNames(o)};function s(a){console&&console.warn&&console.warn(a)}var n=Number.isNaN||function(o){return o!==o};function r(){r.init.call(this)}D.exports=r,D.exports.once=We,r.EventEmitter=r,r.prototype._events=void 0,r.prototype._eventsCount=0,r.prototype._maxListeners=void 0;var c=10;function l(a){if(typeof a!="function")throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof a)}Object.defineProperty(r,"defaultMaxListeners",{enumerable:!0,get:function(){return c},set:function(a){if(typeof a!="number"||a<0||n(a))throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received '+a+".");c=a}}),r.init=function(){(this._events===void 0||this._events===Object.getPrototypeOf(this)._events)&&(this._events=Object.create(null),this._eventsCount=0),this._maxListeners=this._maxListeners||void 0},r.prototype.setMaxListeners=function(o){if(typeof o!="number"||o<0||n(o))throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received '+o+".");return this._maxListeners=o,this};function w(a){return a._maxListeners===void 0?r.defaultMaxListeners:a._maxListeners}r.prototype.getMaxListeners=function(){return w(this)},r.prototype.emit=function(o){for(var d=[],u=1;u<arguments.length;u++)d.push(arguments[u]);var h=o==="error",v=this._events;if(v!==void 0)h=h&&v.error===void 0;else if(!h)return!1;if(h){var f;if(d.length>0&&(f=d[0]),f instanceof Error)throw f;var S=new Error("Unhandled error."+(f?" ("+f.message+")":""));throw S.context=f,S}var A=v[o];if(A===void 0)return!1;if(typeof A=="function")e(A,this,d);else for(var de=A.length,Fe=ae(A,de),u=0;u<de;++u)e(Fe[u],this,d);return!0};function E(a,o,d,u){var h,v,f;if(l(d),v=a._events,v===void 0?(v=a._events=Object.create(null),a._eventsCount=0):(v.newListener!==void 0&&(a.emit("newListener",o,d.listener?d.listener:d),v=a._events),f=v[o]),f===void 0)f=v[o]=d,++a._eventsCount;else if(typeof f=="function"?f=v[o]=u?[d,f]:[f,d]:u?f.unshift(d):f.push(d),h=w(a),h>0&&f.length>h&&!f.warned){f.warned=!0;var S=new Error("Possible EventEmitter memory leak detected. "+f.length+" "+String(o)+" listeners added. Use emitter.setMaxListeners() to increase limit");S.name="MaxListenersExceededWarning",S.emitter=a,S.type=o,S.count=f.length,s(S)}return a}r.prototype.addListener=function(o,d){return E(this,o,d,!1)},r.prototype.on=r.prototype.addListener,r.prototype.prependListener=function(o,d){return E(this,o,d,!0)};function U(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,arguments.length===0?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function R(a,o,d){var u={fired:!1,wrapFn:void 0,target:a,type:o,listener:d},h=U.bind(u);return h.listener=d,u.wrapFn=h,h}r.prototype.once=function(o,d){return l(d),this.on(o,R(this,o,d)),this},r.prototype.prependOnceListener=function(o,d){return l(d),this.prependListener(o,R(this,o,d)),this},r.prototype.removeListener=function(o,d){var u,h,v,f,S;if(l(d),h=this._events,h===void 0)return this;if(u=h[o],u===void 0)return this;if(u===d||u.listener===d)--this._eventsCount===0?this._events=Object.create(null):(delete h[o],h.removeListener&&this.emit("removeListener",o,u.listener||d));else if(typeof u!="function"){for(v=-1,f=u.length-1;f>=0;f--)if(u[f]===d||u[f].listener===d){S=u[f].listener,v=f;break}if(v<0)return this;v===0?u.shift():Ve(u,v),u.length===1&&(h[o]=u[0]),h.removeListener!==void 0&&this.emit("removeListener",o,S||d)}return this},r.prototype.off=r.prototype.removeListener,r.prototype.removeAllListeners=function(o){var d,u,h;if(u=this._events,u===void 0)return this;if(u.removeListener===void 0)return arguments.length===0?(this._events=Object.create(null),this._eventsCount=0):u[o]!==void 0&&(--this._eventsCount===0?this._events=Object.create(null):delete u[o]),this;if(arguments.length===0){var v=Object.keys(u),f;for(h=0;h<v.length;++h)f=v[h],f!=="removeListener"&&this.removeAllListeners(f);return this.removeAllListeners("removeListener"),this._events=Object.create(null),this._eventsCount=0,this}if(d=u[o],typeof d=="function")this.removeListener(o,d);else if(d!==void 0)for(h=d.length-1;h>=0;h--)this.removeListener(o,d[h]);return this};function re(a,o,d){var u=a._events;if(u===void 0)return[];var h=u[o];return h===void 0?[]:typeof h=="function"?d?[h.listener||h]:[h]:d?Ue(h):ae(h,h.length)}r.prototype.listeners=function(o){return re(this,o,!0)},r.prototype.rawListeners=function(o){return re(this,o,!1)},r.listenerCount=function(a,o){return typeof a.listenerCount=="function"?a.listenerCount(o):oe.call(a,o)},r.prototype.listenerCount=oe;function oe(a){var o=this._events;if(o!==void 0){var d=o[a];if(typeof d=="function")return 1;if(d!==void 0)return d.length}return 0}r.prototype.eventNames=function(){return this._eventsCount>0?t(this._events):[]};function ae(a,o){for(var d=new Array(o),u=0;u<o;++u)d[u]=a[u];return d}function Ve(a,o){for(;o+1<a.length;o++)a[o]=a[o+1];a.pop()}function Ue(a){for(var o=new Array(a.length),d=0;d<o.length;++d)o[d]=a[d].listener||a[d];return o}function We(a,o){return new Promise(function(d,u){function h(f){a.removeListener(o,v),u(f)}function v(){typeof a.removeListener=="function"&&a.removeListener("error",h),d([].slice.call(arguments))}ce(a,o,v,{once:!0}),o!=="error"&&qe(a,h,{once:!0})})}function qe(a,o,d){typeof a.on=="function"&&ce(a,"error",o,d)}function ce(a,o,d,u){if(typeof a.on=="function")u.once?a.once(o,d):a.on(o,d);else if(typeof a.addEventListener=="function")a.addEventListener(o,function h(v){u.once&&a.removeEventListener(o,h),d(v)});else throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type '+typeof a)}return D.exports}var F=ve();class pe extends F.EventEmitter{constructor(){super(),this.localMediaStream=new MediaStream,this.videoConstrains={width:{ideal:1920},height:{ideal:1080},frameRate:{ideal:20,max:30},aspectRatio:{ideal:16/9}},this.audioConstrants={noiseSuppression:!0,echoCancellation:!0,autoGainControl:!0},super.setMaxListeners(0)}releaseTrack(e){e!==void 0&&(this.localMediaStream?.removeTrack(e),e.stop())}addDeviceChangeListener(e){navigator.mediaDevices.addEventListener("devicechange",e)}removeDeviceChangeListener(e){navigator.mediaDevices.removeEventListener("devicechange",e)}setVideoTrack(e){this.emit(C.localVideoChange,{from:this.videoTrack,to:e}),this.videoTrack!==e&&(this.localMediaStream?.addTrack(e),this.localTractChange(this.videoTrack,e)),this.videoTrack=e}setAudioTrack(e){this.emit(C.localAudioChange,{from:this.audioTrack,to:e}),this.audioTrack!==e&&(this.localMediaStream?.addTrack(e),this.localTractChange(this.audioTrack,e)),this.audioTrack=e}renderLocalStreamToContainer(e){q(this.localMediaStream,e)}async getAllInputResource(){let e=await navigator.mediaDevices.enumerateDevices();return{audio:e.filter(t=>t.kind==="audioinput"),video:e.filter(t=>t.kind==="videoinput")}}async useDefaultDevice(e){let t={audio:!0,video:!0},s=await navigator.mediaDevices.getUserMedia(t);this.setAudioTrack(s.getAudioTracks()[0]),this.setVideoTrack(s.getVideoTracks()[0]),this.renderLocalStreamToContainer(e)}async useAudio(e){let t=e===void 0?{audio:{...this.audioConstrants},video:!1}:{video:!1,audio:{deviceId:e,...this.audioConstrants}},s=await navigator.mediaDevices.getUserMedia(t);return this.setAudioTrack(s.getAudioTracks()[0]),s.getAudioTracks()[0]}async useDeviceVideo(e){let t=e===void 0?{audio:!1,video:{...this.videoConstrains}}:{audio:!1,video:{deviceId:e,...this.videoConstrains}},s=await navigator.mediaDevices.getUserMedia(t);return this.setVideoTrack(s.getVideoTracks()[0]),s.getVideoTracks()[0]}async useDeskTopVideo(){let e=await navigator.mediaDevices.getDisplayMedia({video:{...this.videoConstrains},audio:!1});return this.setVideoTrack(e.getVideoTracks()[0]),e.getVideoTracks()[0]}disableAudio(){this.audioTrack!==void 0&&this.audioTrack.enabled&&(p("local audio status change",this.audioTrack),this.audioTrack.enabled=!1,this.setAudioTrack(this.audioTrack))}enableAudio(){this.audioTrack!==void 0&&!this.audioTrack.enabled&&(p("local audio status change",this.audioTrack),this.audioTrack.enabled=!0,this.setAudioTrack(this.audioTrack))}disableVideo(){this.videoTrack!==void 0&&this.videoTrack.enabled&&(p("local video status change",this.videoTrack),this.videoTrack.enabled=!1,this.setVideoTrack(this.videoTrack))}enableVideo(){this.videoTrack!==void 0&&!this.videoTrack.enabled&&(p("local video status change",this.videoTrack),this.videoTrack.enabled=!0,this.setVideoTrack(this.videoTrack))}close(){this.releaseTrack(this.audioTrack),this.releaseTrack(this.videoTrack),this.audioTrack=void 0,this.videoTrack=void 0,this.localMediaStream=void 0}}class ge extends pe{constructor(){super(),this.videoCodecs=[],this.audioCodecs=[],this.audioReciveCodecs=[],this.preferCodec(),this.peerConnection=this.buildConnection()}buildConnection(){let e=new RTCPeerConnection;return e.addEventListener("connectionstatechange",t=>p("connectionstatechange",t)),e.addEventListener("icecandidate",t=>{p("icecandidate",t),this.onIceCandidate(t)}),e.addEventListener("datachannel",t=>p("datachannel",t)),e.addEventListener("icecandidateerror",t=>p("icecandidateerror",t)),e.addEventListener("iceconnectionstatechange",t=>p("iceconnectionstatechange",t)),e.addEventListener("icegatheringstatechange",t=>p("icegatheringstatechange",t)),e.addEventListener("negotiationneeded",t=>p("negotiationneeded",t)),e.addEventListener("signalingstatechange",t=>p("signalingstatechange",t)),e.addEventListener("track",t=>this.reciveTrack(t)),e}async localTractChange(e,t){if(this.remoteStream!==void 0&&this.peerConnection!==void 0)if(t!==void 0){let s=this.peerConnection.getSenders().find(n=>n.track?.kind===t.kind);s!==void 0&&s.replaceTrack(t)}else{let s=this.peerConnection.getSenders().find(n=>n.track?.kind===e?.kind);s!==void 0&&this.peerConnection.removeTrack(s)}t!==void 0&&(t.onended=s=>p("local track end",s),t.onmute=s=>{p("local mute",s),this.emitLocalStreamChange()},t.onunmute=s=>{p("local unmute",s),this.emitLocalStreamChange()}),this.releaseTrack(e),this.emitLocalStreamChange()}isInMeeting(){return this.remoteStream!==void 0}hasRemoteVideo(e){return e?.getVideoTracks().some(t=>t.muted===!1&&t.readyState==="live")??!1}emitLocalStreamChange(){this.emit(C.localStreamChange,{audioOnly:!this.hasRemoteVideo(this.localMediaStream),stream:this.localMediaStream})}emitRemoteStreamChange(){this.emit(C.stream,{audioOnly:!this.hasRemoteVideo(this.remoteStream),stream:this.remoteStream})}trigerStreamChange(e=100){this.emitStreamTimeout!==void 0&&clearTimeout(this.emitStreamTimeout),this.emitStreamTimeout=setTimeout(()=>{this.emitRemoteStreamChange(),this.emitStreamTimeout=void 0},e)}reciveTrack(e){p("recive track",e),this.remoteStream===void 0&&(this.remoteStream=new MediaStream),e.track.addEventListener("ended",()=>this.trigerStreamChange()),e.track.addEventListener("mute",()=>this.trigerStreamChange(3e3)),e.track.addEventListener("unmute",()=>this.trigerStreamChange(10)),this.remoteStream.addTrack(e.track),this.trigerStreamChange()}preferCodec(e="H264",t="PCMA"){this.videoCodecs=[];let s=RTCRtpSender.getCapabilities("video");s!==null&&this.videoCodecs.push(...s.codecs.filter(l=>l.mimeType===`video/${e}`));let n=RTCRtpReceiver.getCapabilities("video");n!==null&&this.videoCodecs.push(...n.codecs.filter(l=>l.mimeType===`video/${e}`)),this.audioCodecs=[];let r=RTCRtpSender.getCapabilities("audio");r!==null&&this.audioCodecs.push(...r.codecs.filter(l=>l.mimeType===`audio/${t}`));let c=RTCRtpReceiver.getCapabilities("audio");c!==null&&this.audioCodecs.push(...c.codecs.filter(l=>l.mimeType===`audio/${t}`))}trackIsInPeerConnection(e){return this.peerConnection?.getSenders().some(t=>t.track?.id===e.id)??!1}updateTracks(){if(this.peerConnection===void 0||this.peerConnection.signalingState==="closed")throw new Error("session is closed !");if(this.audioTrack===void 0&&this.videoTrack===void 0){this.peerConnection.addTransceiver("audio",{direction:"recvonly"}),this.peerConnection.addTransceiver("video",{direction:"recvonly"});return}if(this.audioTrack!==void 0&&!this.trackIsInPeerConnection(this.audioTrack))try{this.peerConnection.addTrack(this.audioTrack)}catch{}if(this.videoTrack!==void 0&&!this.trackIsInPeerConnection(this.videoTrack))try{this.peerConnection.addTrack(this.videoTrack)}catch{}try{this.peerConnection.getTransceivers().forEach(e=>{e.sender.track!==null&&(e.sender.track.kind==="video"?e.setCodecPreferences([...this.videoCodecs]):e.sender.track.kind==="audio"&&e.setCodecPreferences([...this.audioCodecs]))})}catch(e){le("preferCodec error",e,this.audioCodecs,this.videoCodecs)}}async createOffer(){if(this.peerConnection===void 0)throw new Error("session is closed !");this.updateTracks();let e=await this.peerConnection.createOffer();return e=me.formatOffer(e),await this.peerConnection.setLocalDescription(e),e}async setOffer(e){if(this.peerConnection===void 0)throw new Error("session is closed !");this.updateTracks(),await this.peerConnection.setRemoteDescription({type:"offer",sdp:e})}async createAnswer(){if(this.peerConnection===void 0)throw new Error("session is closed !");this.updateTracks();let e=await this.peerConnection.createAnswer();return this.peerConnection.setLocalDescription(e),e}async setAnswer(e){if(this.peerConnection===void 0)throw new Error("session is closed !");await this.peerConnection.setRemoteDescription({type:"answer",sdp:e})}setRemoteIce(e){if(this.peerConnection===void 0)throw new Error("session is closed !");let t=new RTCIceCandidate(e);this.peerConnection.addIceCandidate(t)}closeConnection(e){e.close(),e.ontrack=null,e.onicecandidate=null,e.oniceconnectionstatechange=null,e.onsignalingstatechange=null,e.onicegatheringstatechange=null,e.onnegotiationneeded=null,e.onicecandidateerror=null,e.ondatachannel=null,e.onconnectionstatechange=null}close(){super.close(),this.peerConnection!==void 0&&(this.closeConnection(this.peerConnection),this.peerConnection=void 0),this.remoteStream!==void 0&&J(this.remoteStream)}}var I=(i=>(i[i.timeout=408]="timeout",i[i.reject=488]="reject",i[i.busy=486]="busy",i[i.notfound=404]="notfound",i[i.notAllowedMedia=415]="notAllowedMedia",i[i.ok=200]="ok",i))(I||{});class H extends ge{constructor(e,t,s){super(),this.sessionId=t,this.rtcClient=e,this.remoteNumber=s}reciveIceRequest({ice:e}){this.setRemoteIce(JSON.parse(e))}getRemoteNumber(){return this.remoteNumber}onIceCandidate(e){}destroy(e=!0){this.removeAllListeners(),this.rtcClient!==void 0&&(this.remoteNumber!==void 0&&(e&&this.rtcClient.sendBye(this.remoteNumber,this.sessionId),this.remoteNumber=void 0),this.rtcClient.removeSession(this)),this.rtcClient=void 0,super.close()}rejectCall(){let[e,t,s]=this.checkIsNotUndefined(this.rtcClient,this.remoteNumber,this.inviteSeq);e.answer(I.reject,s,t,this.sessionId),this.destroy()}async acceptCall(){if(this.inviteOffer!==void 0){await this.setOffer(this.inviteOffer);let[e,t,s]=this.checkIsNotUndefined(this.rtcClient,this.remoteNumber,this.inviteSeq),{sdp:n}=await this.createAnswer();e.answer(I.ok,s,t,this.sessionId,n)}}async pickNewConnection(){this.peerConnection!==void 0&&this.closeConnection(this.peerConnection),this.peerConnection=this.buildConnection(),this.remoteStream!==void 0&&(J(this.remoteStream),this.remoteStream=void 0,this.acceptCall())}checkIsNotUndefined(...e){for(const t of e)if(t===void 0)throw new Error("someone is undefined");return e}async sendDtmf(e){this.rtcClient?.sendDtmf(this.remoteNumber,this.sessionId,e)}playRemoteStream(e,t){const{audioOnly:s=!1,muted:n=!1}=t||{};n&&(e.muted=!0),this.on(C.stream,r=>{if(console.log("远程流",r),r.stream){const c=s?new MediaStream(r.stream.getAudioTracks()):r.stream;q(c,e)}}),this.on(C.bye,()=>{e&&(e.pause(),e.srcObject=null)})}}var b=(i=>(i.audio="audio",i.video="video",i.audioVideo="audioVideo",i.unknown="unknown",i))(b||{});class Q extends H{constructor(){super(...arguments),this.responseCallType=b.unknown}async start(){let[e,t]=this.checkIsNotUndefined(this.rtcClient,this.remoteNumber),s=await this.createOffer(),{status:n,sdp:r}=await e.invite(t,this.sessionId,s.sdp);if(n===I.ok){await this.setAnswer(r);const c=r.split(`\r
|
|
4
|
+
`),l=c.find(E=>E.startsWith("m=audio")),w=c.find(E=>E.startsWith("m=video"));this.responseCallType=l&&w?b.audioVideo:l?b.audio:w?b.video:b.unknown}return n}addRemote(e){this.remoteNumber=e}}const j=class j{constructor(e,t,s,n){this.req=e,this.seq=0,this.from=t,this.to=s,this.registerid=`${j.random}@${t}`,n!==void 0&&Object.assign(this,n)}};j.random=String(Date.now());let L=j;var N=(i=>(i.connected="connected",i.disconnected="disconnected",i.message="message",i))(N||{});const z=`(function(){"use strict";let e,n=!1;const o=self,a={},r={timeout:5*1e3,timeoutObj:null,reset(){return clearInterval(this.timeoutObj),this},sendOnline(){e.readyState===1&&e.send(JSON.stringify(Object.assign(a,{seq:++a.seq})))},start(){this.timeout!==0&&(this.timeoutObj=setInterval(()=>{this.sendOnline()},this.timeout))}};self.addEventListener("message",function(s){const t=s.data;switch(t.cmd){case"config":Object.assign(a,t.heartBeat),r.timeout=t.heartTime*1e3;break;case"start":self.postMessage({type:"webWorker",data:"启动webWorker"}),i(t.url);break;case"close":n=!0,e.close(),self.postMessage({type:"webWorker",data:"停止webWorker"}),self.postMessage({type:"close",data:"close"+new Date().toTimeString()}),self.close();break;case"msg":e.readyState===1&&e.send(JSON.stringify(t.data))}},!1);const i=function(s){e||(e=new WebSocket(s),e.onerror=function(t){c(s)},e.onclose=function(t){c(s)},e.onopen=t=>{o.postMessage({type:"open",data:"start"+new Date().toTimeString()}),r.reset().start()},e.onmessage=t=>{const l=JSON.parse(t.data);o.postMessage({type:"webSocket",data:l})})};function c(s){n||(n=!0,setTimeout(function(){e=null,i(s),n=!1},2e3))}})();
|
|
5
|
+
`,X=typeof self<"u"&&self.Blob&&new Blob(["(self.URL || self.webkitURL).revokeObjectURL(self.location.href);",z],{type:"text/javascript;charset=utf-8"});function ke(i){let e;try{if(e=X&&(self.URL||self.webkitURL).createObjectURL(X),!e)throw"";const t=new Worker(e,{name:i?.name});return t.addEventListener("error",()=>{(self.URL||self.webkitURL).revokeObjectURL(e)}),t}catch{return new Worker("data:text/javascript;charset=utf-8,"+encodeURIComponent(z),{name:i?.name})}}class we extends F.EventEmitter{constructor(e,t,s){super(),this.server=e,this.ws=new ke,this.configHeartBeat(t,s)}connect(){this.initWebsocket(),this.ws.onmessage=e=>{const{type:t,data:s}=e.data;switch(t){case"webSocket":p("websocket recive message ",s),this.emit(N.message,s);return;case"open":p("websocket connected ",this.server),this.emit(N.connected);return}}}configHeartBeat(e,t){p("websocket heartBeat",e),p("websocket heartTime",t),this.ws.postMessage({cmd:"config",heartBeat:e,heartTime:t})}initWebsocket(){this.ws.postMessage({cmd:"start",url:this.server})}send(e){this.ws.postMessage({cmd:"msg",data:e})}close(){this.ws.postMessage({cmd:"close"})}sendMessage(e){p("websocket send message ",e),e!==void 0&&this.ws!==void 0&&this.ws.postMessage({cmd:"msg",data:e})}}class Ce extends F.EventEmitter{constructor(e,t,s,n){super(),this.activeServer="",this.server=e,this.localNumber=t,this.expireTime=s,this.heartTime=n,this.localNumber===""&&(this.heartTime=0,this.localNumber="anonymous"),super.setMaxListeners(0)}async testWs(e){return e.reduce((t,s)=>t.then(n=>Promise.resolve(n),n=>new Promise((r,c)=>{const l=new WebSocket(s);l.onopen=()=>{n.push(s),l.close(),r(n)},l.onclose=()=>{c(n)}})),Promise.reject([])).then(t=>Promise.resolve(t),t=>Promise.resolve(t))}async reConnect(){this.destroy();let e=[];this.server!==void 0&&(typeof this.server=="string"?e=[this.server]:e=this.server);const t=await this.testWs(e);return new Promise((s,n)=>{if(t.length>0){this.activeServer=t[0];let r=new we(this.activeServer,new L(y.MESSAGE_TYPE_REGISTER,this.localNumber,this.localNumber,{expire:this.expireTime}),this.heartTime);r.on(N.connected,()=>{this.socketWorker=r,this.onConnected(),s()}),r.on(N.disconnected,c=>{this.socketWorker=void 0,this.onDisConnected(c),n("socketWorker connecion failed")}),r.on(N.message,c=>this.onReviceMessage(c)),r.connect()}else n("server is empty")})}sendMessage(e){if(this.socketWorker!==void 0)this.socketWorker.sendMessage(e);else throw new Error("socketWorker is closed")}destroy(){this.socketWorker!==void 0&&(this.unRegister(),this.socketWorker.close(),this.socketWorker=void 0)}}class Ee extends Ce{constructor(){super(...arguments),this.asyncProducer=new Map}async sendRespondableMessage(e){return this.sendMessage(e),new Promise(t=>this.asyncProducer.set(e.seq,t))}getAsyncResolve(e){let t=this.asyncProducer.get(e);return t!==void 0&&this.asyncProducer.delete(e),t}onDisConnected(e){this.asyncProducer.clear(),this.emit(x.disconnected,e)}onReviceMessage(e){let{status:t,seq:s}=e;t!==void 0?this.getAsyncResolve(s)?.call(void 0,e):this.processMessage(e)}}class be extends Ee{async register(){let e=new L(y.MESSAGE_TYPE_REGISTER,this.localNumber,this.localNumber,{expire:this.expireTime});return this.sendRespondableMessage(e)}unRegister(){let e=new L(y.MESSAGE_TYPE_REGISTER,this.localNumber,this.localNumber,{expire:0});this.sendMessage(e)}async invite(e,t,s){return this.sendRespondableMessage(new L(y.MESSAGE_TYPE_INVITE,this.localNumber,e,{cid:t,sdp:s}))}sendIce(e,t,s){}sendBye(e,t){return this.sendMessage(new L(y.MESSAGE_TYPE_BYE,this.localNumber,e,{cid:t}))}answer(e,t,s,n,r){this.sendMessage({status:e,seq:t,from:s,to:this.localNumber,cid:n,sdp:r})}sendPttMessage(e){this.sendMessage(e)}async sendDtmf(e,t,s){return this.sendMessage(new L(y.MESSAGE_TYPE_INFO,this.localNumber,e,{cid:t,info:{msg:"dtmf",dtmf:s}}))}}var ye;function _(){}_.prototype=Object.create(null);function m(){m.init.call(this)}m.EventEmitter=m,m.usingDomains=!1,m.prototype.domain=void 0,m.prototype._events=void 0,m.prototype._maxListeners=void 0,m.defaultMaxListeners=10,m.init=function(){this.domain=null,m.usingDomains&&ye.active,(!this._events||this._events===Object.getPrototypeOf(this)._events)&&(this._events=new _,this._eventsCount=0),this._maxListeners=this._maxListeners||void 0},m.prototype.setMaxListeners=function(e){if(typeof e!="number"||e<0||isNaN(e))throw new TypeError('"n" argument must be a positive number');return this._maxListeners=e,this};function Z(i){return i._maxListeners===void 0?m.defaultMaxListeners:i._maxListeners}m.prototype.getMaxListeners=function(){return Z(this)};function Te(i,e,t){if(e)i.call(t);else for(var s=i.length,n=M(i,s),r=0;r<s;++r)n[r].call(t)}function Se(i,e,t,s){if(e)i.call(t,s);else for(var n=i.length,r=M(i,n),c=0;c<n;++c)r[c].call(t,s)}function Le(i,e,t,s,n){if(e)i.call(t,s,n);else for(var r=i.length,c=M(i,r),l=0;l<r;++l)c[l].call(t,s,n)}function _e(i,e,t,s,n,r){if(e)i.call(t,s,n,r);else for(var c=i.length,l=M(i,c),w=0;w<c;++w)l[w].call(t,s,n,r)}function Re(i,e,t,s){if(e)i.apply(t,s);else for(var n=i.length,r=M(i,n),c=0;c<n;++c)r[c].apply(t,s)}m.prototype.emit=function(e){var t,s,n,r,c,l,w,E=e==="error";if(l=this._events,l)E=E&&l.error==null;else if(!E)return!1;if(w=this.domain,E){if(t=arguments[1],w)t||(t=new Error('Uncaught, unspecified "error" event')),t.domainEmitter=this,t.domain=w,t.domainThrown=!1,w.emit("error",t);else{if(t instanceof Error)throw t;var U=new Error('Uncaught, unspecified "error" event. ('+t+")");throw U.context=t,U}return!1}if(s=l[e],!s)return!1;var R=typeof s=="function";switch(n=arguments.length,n){case 1:Te(s,R,this);break;case 2:Se(s,R,this,arguments[1]);break;case 3:Le(s,R,this,arguments[1],arguments[2]);break;case 4:_e(s,R,this,arguments[1],arguments[2],arguments[3]);break;default:for(r=new Array(n-1),c=1;c<n;c++)r[c-1]=arguments[c];Re(s,R,this,r)}return!0};function ee(i,e,t,s){var n,r,c;if(typeof t!="function")throw new TypeError('"listener" argument must be a function');if(r=i._events,r?(r.newListener&&(i.emit("newListener",e,t.listener?t.listener:t),r=i._events),c=r[e]):(r=i._events=new _,i._eventsCount=0),!c)c=r[e]=t,++i._eventsCount;else if(typeof c=="function"?c=r[e]=s?[t,c]:[c,t]:s?c.unshift(t):c.push(t),!c.warned&&(n=Z(i),n&&n>0&&c.length>n)){c.warned=!0;var l=new Error("Possible EventEmitter memory leak detected. "+c.length+" "+e+" listeners added. Use emitter.setMaxListeners() to increase limit");l.name="MaxListenersExceededWarning",l.emitter=i,l.type=e,l.count=c.length,Ie(l)}return i}function Ie(i){typeof console.warn=="function"?console.warn(i):console.log(i)}m.prototype.addListener=function(e,t){return ee(this,e,t,!1)},m.prototype.on=m.prototype.addListener,m.prototype.prependListener=function(e,t){return ee(this,e,t,!0)};function te(i,e,t){var s=!1;function n(){i.removeListener(e,n),s||(s=!0,t.apply(i,arguments))}return n.listener=t,n}m.prototype.once=function(e,t){if(typeof t!="function")throw new TypeError('"listener" argument must be a function');return this.on(e,te(this,e,t)),this},m.prototype.prependOnceListener=function(e,t){if(typeof t!="function")throw new TypeError('"listener" argument must be a function');return this.prependListener(e,te(this,e,t)),this},m.prototype.removeListener=function(e,t){var s,n,r,c,l;if(typeof t!="function")throw new TypeError('"listener" argument must be a function');if(n=this._events,!n)return this;if(s=n[e],!s)return this;if(s===t||s.listener&&s.listener===t)--this._eventsCount===0?this._events=new _:(delete n[e],n.removeListener&&this.emit("removeListener",e,s.listener||t));else if(typeof s!="function"){for(r=-1,c=s.length;c-- >0;)if(s[c]===t||s[c].listener&&s[c].listener===t){l=s[c].listener,r=c;break}if(r<0)return this;if(s.length===1){if(s[0]=void 0,--this._eventsCount===0)return this._events=new _,this;delete n[e]}else Ne(s,r);n.removeListener&&this.emit("removeListener",e,l||t)}return this},m.prototype.off=function(i,e){return this.removeListener(i,e)},m.prototype.removeAllListeners=function(e){var t,s;if(s=this._events,!s)return this;if(!s.removeListener)return arguments.length===0?(this._events=new _,this._eventsCount=0):s[e]&&(--this._eventsCount===0?this._events=new _:delete s[e]),this;if(arguments.length===0){for(var n=Object.keys(s),r=0,c;r<n.length;++r)c=n[r],c!=="removeListener"&&this.removeAllListeners(c);return this.removeAllListeners("removeListener"),this._events=new _,this._eventsCount=0,this}if(t=s[e],typeof t=="function")this.removeListener(e,t);else if(t)do this.removeListener(e,t[t.length-1]);while(t[0]);return this},m.prototype.listeners=function(e){var t,s,n=this._events;return n?(t=n[e],t?typeof t=="function"?s=[t.listener||t]:s=Oe(t):s=[]):s=[],s},m.listenerCount=function(i,e){return typeof i.listenerCount=="function"?i.listenerCount(e):ie.call(i,e)},m.prototype.listenerCount=ie;function ie(i){var e=this._events;if(e){var t=e[i];if(typeof t=="function")return 1;if(t)return t.length}return 0}m.prototype.eventNames=function(){return this._eventsCount>0?Reflect.ownKeys(this._events):[]};function Ne(i,e){for(var t=e,s=t+1,n=i.length;s<n;t+=1,s+=1)i[t]=i[s];i.pop()}function M(i,e){for(var t=new Array(e);e--;)t[e]=i[e];return t}function Oe(i){for(var e=new Array(i.length),t=0;t<e.length;++t)e[t]=i[t].listener||i[t];return e}const g={ERROR:"error",SPEAKER:"speaker",TALKING:"talking",ACTIVE_GROUP:"activeGroup",JOIN_INFO:"joinInfo",DISCONNECTED:"disConnected"},se={400:"消息不符规范",401:"验证不通过",403:"无权利操作",404:"不存在该用户",415:"错误参数",405:"无法操作",424:"不存在XD群",425:"管理员没有",426:"已存在管理员",427:"以前被拒绝过,或者删除过",428:"超出所配置的下属管理员的数量",429:"群内无用户",430:"管理员的索引号冲突",431:"还有子管理员存在"},O={connected:"connected",disconnected:"disconnected",message:"message"},T=(i,...e)=>{console.log(`%c usc-ptt-devtools %c ${i} %c `,"background:#16aae0 ; padding: 1px; border-radius: 3px 0 0 3px; color: #fff","background:#14e04e ; padding: 1px; border-radius: 0 3px 3px 0; color: #fff","background:transparent",...e)},ne=(i,...e)=>{console.log(`%c usc-ptt-devtools %c ${i} %c `,"background:#16aae0 ; padding: 1px; border-radius: 3px 0 0 3px; color: #fff","background:#e02514 ; padding: 1px; border-radius: 0 3px 3px 0; color: #fff","background:transparent",...e)};class Me extends m{server="";ws=null;constructor(e){super(),this.server=e}connect(){this.ws=new WebSocket(this.server),this.ws.onopen=()=>{T("websocket connected ",this.server),this.emit(O.connected)},this.ws.onclose=()=>{T("websocket disconnected ",this.server),this.ws=void 0,this.emit(O.disconnected)},this.ws.onmessage=({data:e})=>{let t=JSON.parse(e);T("websocket recive message ",t),this.emit(O.message,t)}}close(){this.ws!==void 0&&(this.ws.close(),this.ws=void 0)}sendMessage(e){T("websocket send message ",e),e!==void 0&&this.ws!==void 0&&this.ws.readyState===1&&this.ws.send(JSON.stringify(e))}}class Ae extends m{socket=void 0;timer=void 0;waitinggroup=void 0;speaker="";activeGroup="";talking=!1;constructor(e,t=20,s=!0){if(super(),!e)return ne("服务器地址为空!");this.server=e,this.heartTime=t,this.autoReconnect=s}async initClient(){return this.destorySocket(),new Promise((e,t)=>{if(this.server!==void 0){let s=new Me(this.server);s.on(O.connected,()=>{this.socket=s,this.timer=setInterval(()=>{this.sendMessage({req:0})},this.heartTime*1e3),e()}),s.on(O.disconnected,()=>{this.socket=void 0,this.autoReconnect?setTimeout(()=>{this.initClient()},3e3):this.emit(g.DISCONNECTED),t("socket connecion failed")}),s.on(O.message,n=>this.onReviceMessage(n)),s.connect()}else t("server is empty")})}onReviceMessage(e){T(e);const{info:t,msg:s,res:n}=e;if(t===10&&(this.speaker=`${s.speaker}`,T(`${this.speaker}正在说话`),this.emit(g.SPEAKER,this.speaker)),t===11&&(n.code===200?(this.activeGroup=this.waitinggroup,T(`加入组${this.activeGroup}`)):(this.activeGroup="",ne(se[n.code]),this.emit(g.ERROR,se[n.code])),this.emit(g.ACTIVE_GROUP,this.activeGroup)),t===13&&(n.code===200?this.talking=!0:this.talking=!1,T(`talking:${this.talking}`),this.emit(g.TALKING,this.talking)),t===14&&(this.speaker="",T(`${this.speaker}停止说话`),this.emit(g.SPEAKER,this.speaker)),t===15){const r={user:s.number,group:s.g_num,code:s.status};T(`${r}进入组`),this.emit(g.JOIN_INFO,r)}}joinGroup(e,t,s,n){this.socket&&(this.waitinggroup=e,this.sendMessage({req:1,group:e,user:t,ptts:s,port:n}))}quitGroup(){this.socket&&(this.activeGroup="",this.emit(g.ACTIVE_GROUP,this.activeGroup),this.sendMessage({req:2}))}talk(){this.socket&&this.sendMessage({req:3})}stop(){this.talking=!1,T(`talking:${this.talking}`),this.emit(g.TALKING,this.talking),this.socket&&this.sendMessage({req:4})}sendMessage(e){if(this.socket!==void 0)this.socket.sendMessage(e);else throw new Error("socket is closed")}destorySocket(){this.socket!==void 0&&(this.socket.close(),this.socket=void 0)}destory(){this.destorySocket()}}const xe=async(i,e=20,t=!0)=>{let s=new Ae(i,e,t);return await s.initClient(),s},V=class V extends be{constructor(e){let t=e.expireTime||V.defaultExpireTime;super(e.server,e.localNumber,t,e.heartTime||(e.localNumber?5:0)),this.enablePtt=e.enablePtt,this.pttServer=e.pttServer}async initPttClient(){if(this.enablePtt)if(this.pttServer){const e=await xe(this.pttServer);if(!e)return Promise.reject("ptt客户端初始化失败!");e.on(g.ACTIVE_GROUP,t=>{this.emit(g.ACTIVE_GROUP,t)}),e.on(g.SPEAKER,t=>{this.emit(g.SPEAKER,t)}),e.on(g.TALKING,t=>{this.emit(g.TALKING,t)}),e.on(g.JOIN_INFO,t=>{this.emit(g.JOIN_INFO,t)}),e.on(g.DISCONNECTED,t=>{this.emit(g.DISCONNECTED,t)}),this.pttClient=e}else return Promise.reject("pttServer不存在")}joinGroup(e,t,s,n){this.pttClient?.joinGroup(e,t,s,n)}quitGroup(){this.pttClient?.quitGroup()}talk(){this.pttClient?.talk()}stop(){this.pttClient?.stop()}onConnected(){}onDisConnected(){super.onDisConnected()}};V.defaultExpireTime=60;let Y=V;class Pe extends H{constructor(e,t,s,n,r){super(e,t,s),this.callType=b.unknown,this.inviteSeq=r,this.inviteOffer=n;const c=n.split(`\r
|
|
6
|
+
`),l=c.find(E=>E.startsWith("m=audio")),w=c.find(E=>E.startsWith("m=video"));this.callType=l&&w?b.audioVideo:l?b.audio:w?b.video:b.unknown}}class $ extends Y{constructor(){super(...arguments),this.allSession=[]}createSession(e){let t=new Q(this,K(),e);return this.allSession.push(t),t}playRemote(e,t,s){return new Promise((n,r)=>{try{let c=new Q(this,K(),e);this.allSession.push(c),c.playRemoteStream(t,s),c.start().then(l=>{p("playRemote start status",l),l===I.ok?n(c):r(new Error(`Failed to start session, status: ${l}`))}).catch(l=>{r(l)}),c.on(C.bye,()=>{this.removeSession(c)})}catch(c){r(c)}})}processMessage(e){let{req:t}=e;if(t===y.MESSAGE_TYPE_INVITE){let s=new Pe(this,e.cid,e.from,e.sdp,e.seq);this.allSession.push(s),this.emit(x.invite,s)}else if(t===y.MESSAGE_TYPE_REINVITE){let s=this.allSession.find(n=>n.sessionId==e.cid);s!==void 0&&(s.inviteSeq=e.seq,s.inviteOffer=e.sdp,s.acceptCall(),s.emit(C.reInvite,s))}else if(t===y.MESSAGE_TYPE_ICE)this.allSession.find(s=>s.sessionId===e.cid)?.reciveIceRequest(e);else if(t===y.MESSAGE_TYPE_BYE){let s=this.allSession.find(n=>n.sessionId===e.cid);s!==void 0&&(s.emit(C.bye),s.destroy(!1))}t==W.FPRE&&this.emit(P.FPREInfo,e),t==W.IMS&&this.emit(P.IMSInfo,e)}destroy(){this.allSession!==void 0&&this.allSession.forEach(e=>{e.destroy()}),super.destroy()}removeSession(e){this.allSession!==void 0&&(this.allSession=this.allSession.filter(t=>t.sessionId!==e.sessionId))}onDisConnected(){super.onDisConnected(),this.destroy()}}const Ge=async i=>{let e=new $(i);await e.reConnect(),await e.initPttClient().catch(s=>{console.error(s)}),L.random=String(Date.now());let t=await e.register();return t.status===I.ok?e:(e.destroy(),Promise.reject(t))},De=async(i,e,t)=>{let s=new $({server:i,localNumber:""});return await s.reConnect(),await s.playRemote(e,t)},je=async()=>{await navigator.mediaDevices.getUserMedia({audio:!0,video:!0})};k.PTTEvent=P,k.RtcCalledType=b,k.RtcClient=$,k.RtcClientEvent=x,k.RtcInviteStatus=I,k.RtcSessionEvent=C,k.authDevice=je,k.createRtcClient=Ge,k.disableLog=he,k.enableLog=fe,k.playRemote=De,k.releaseStreamFromContainer=ue,k.renderStreamToContainer=q,Object.defineProperty(k,Symbol.toStringTag,{value:"Module"})}));
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { SignalMessageType } from './SingalMessageType';
|
|
2
|
+
export declare class SignalMessage {
|
|
3
|
+
static random: string;
|
|
4
|
+
/**
|
|
5
|
+
* 请求类型
|
|
6
|
+
*/
|
|
7
|
+
req: SignalMessageType;
|
|
8
|
+
/**
|
|
9
|
+
* 每次请求序列号增加1,后端设计如此
|
|
10
|
+
* 导致前端websocket通道无法复用,对于每个账号都使用单独的websocket
|
|
11
|
+
*/
|
|
12
|
+
seq: number;
|
|
13
|
+
/**
|
|
14
|
+
* 信令发送方
|
|
15
|
+
*/
|
|
16
|
+
from: string;
|
|
17
|
+
/**
|
|
18
|
+
* 信令接收方
|
|
19
|
+
*/
|
|
20
|
+
to: string;
|
|
21
|
+
/**
|
|
22
|
+
* 注册id,后端设计如此,注册成功之后,心跳注册registerid的不变,如果是新的注册,比如断网之后重新连接上,registerid要改变
|
|
23
|
+
*/
|
|
24
|
+
registerid: string;
|
|
25
|
+
constructor(req: SignalMessageType, from: string, to: string, data?: Object);
|
|
26
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 信令服务器的消息头
|
|
3
|
+
* @author xiechanglei
|
|
4
|
+
*/
|
|
5
|
+
export declare enum SignalMessageType {
|
|
6
|
+
MESSAGE_TYPE_REGISTER = "REGISTER",
|
|
7
|
+
MESSAGE_TYPE_INVITE = "INVITE",
|
|
8
|
+
MESSAGE_TYPE_REINVITE = "reINVITE",
|
|
9
|
+
MESSAGE_TYPE_ICE = "ICE",
|
|
10
|
+
MESSAGE_TYPE_INFO = "INFO",
|
|
11
|
+
MESSAGE_TYPE_BYE = "BYE"
|
|
12
|
+
}
|
|
13
|
+
export declare enum PttMessageType {
|
|
14
|
+
FPRE = "fpre",
|
|
15
|
+
IMS = "ims",
|
|
16
|
+
PTT_QUERY_ONLINE_USER = "15",
|
|
17
|
+
PTT_ANSWER_ONLINE_USER = "115",
|
|
18
|
+
PTT_QUERY_INFO = "16",
|
|
19
|
+
PTT_QUERY_INFO_CONFIRM = "116"
|
|
20
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
/**
|
|
3
|
+
* devicechange 设备输入变化
|
|
4
|
+
*/
|
|
5
|
+
export default abstract class LocalStreamHandler extends EventEmitter {
|
|
6
|
+
constructor();
|
|
7
|
+
audioTrack: MediaStreamTrack | undefined;
|
|
8
|
+
videoTrack: MediaStreamTrack | undefined;
|
|
9
|
+
localMediaStream: MediaStream | undefined;
|
|
10
|
+
videoConstrains: {
|
|
11
|
+
width: {
|
|
12
|
+
ideal: number;
|
|
13
|
+
};
|
|
14
|
+
height: {
|
|
15
|
+
ideal: number;
|
|
16
|
+
};
|
|
17
|
+
frameRate: {
|
|
18
|
+
ideal: number;
|
|
19
|
+
max: number;
|
|
20
|
+
};
|
|
21
|
+
aspectRatio: {
|
|
22
|
+
ideal: number;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
audioConstrants: {
|
|
26
|
+
noiseSuppression: boolean;
|
|
27
|
+
echoCancellation: boolean;
|
|
28
|
+
autoGainControl: boolean;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* 释放track
|
|
32
|
+
*/
|
|
33
|
+
releaseTrack(track: MediaStreamTrack | undefined): void;
|
|
34
|
+
/**
|
|
35
|
+
* 注册设备变化事件,记得组件销毁的时候remove
|
|
36
|
+
*/
|
|
37
|
+
addDeviceChangeListener(listener: any): void;
|
|
38
|
+
removeDeviceChangeListener(listener: any): void;
|
|
39
|
+
/**
|
|
40
|
+
* 设置本地视频输入流
|
|
41
|
+
*/
|
|
42
|
+
setVideoTrack(videoTrack: MediaStreamTrack): void;
|
|
43
|
+
/**
|
|
44
|
+
* 设置本地音頻输入流
|
|
45
|
+
*/
|
|
46
|
+
setAudioTrack(audioTrack: MediaStreamTrack): void;
|
|
47
|
+
abstract localTractChange(prev: MediaStreamTrack | undefined, next: MediaStreamTrack | undefined): void;
|
|
48
|
+
/**
|
|
49
|
+
* 将流渲染到dom上
|
|
50
|
+
*/
|
|
51
|
+
renderLocalStreamToContainer(container: HTMLVideoElement | HTMLAudioElement | undefined): void;
|
|
52
|
+
/**
|
|
53
|
+
* 获取所有的输入设备源
|
|
54
|
+
*/
|
|
55
|
+
getAllInputResource(): Promise<{
|
|
56
|
+
audio: MediaDeviceInfo[];
|
|
57
|
+
video: MediaDeviceInfo[];
|
|
58
|
+
}>;
|
|
59
|
+
/**
|
|
60
|
+
* 使用默认的音视频输入源
|
|
61
|
+
*/
|
|
62
|
+
useDefaultDevice(container: HTMLVideoElement | HTMLAudioElement | undefined): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* 设置本地音频输入流
|
|
65
|
+
* https://developer.mozilla.org/zh-CN/docs/Web/API/MediaDevices/getUserMedia
|
|
66
|
+
* @param deviceId 设备id,如果为空,表示使用默认输入设备
|
|
67
|
+
*/
|
|
68
|
+
useAudio(deviceId?: string): Promise<MediaStreamTrack>;
|
|
69
|
+
/**
|
|
70
|
+
* 使用设备视频流
|
|
71
|
+
*/
|
|
72
|
+
useDeviceVideo(deviceId?: string): Promise<MediaStreamTrack>;
|
|
73
|
+
/**
|
|
74
|
+
* 使用桌面视频流
|
|
75
|
+
*/
|
|
76
|
+
useDeskTopVideo(): Promise<MediaStreamTrack>;
|
|
77
|
+
/**
|
|
78
|
+
* 禁用本地音频输入
|
|
79
|
+
*/
|
|
80
|
+
disableAudio(): void;
|
|
81
|
+
/**
|
|
82
|
+
* 启用本地音频输入
|
|
83
|
+
*/
|
|
84
|
+
enableAudio(): void;
|
|
85
|
+
/**
|
|
86
|
+
* 禁用本地视频输入
|
|
87
|
+
*/
|
|
88
|
+
disableVideo(): void;
|
|
89
|
+
/**
|
|
90
|
+
* 启用本地视频输入
|
|
91
|
+
*/
|
|
92
|
+
enableVideo(): void;
|
|
93
|
+
close(): void;
|
|
94
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { default as LocalStreamHandler } from './LocalStreamHandler';
|
|
2
|
+
export interface RTCRtpCodec {
|
|
3
|
+
kind: 'audio' | 'video';
|
|
4
|
+
mimeType: string;
|
|
5
|
+
clockRate: number;
|
|
6
|
+
channels?: number;
|
|
7
|
+
sdpFmtpLine?: string;
|
|
8
|
+
rtcpFeedback?: Array<{
|
|
9
|
+
type: string;
|
|
10
|
+
parameter?: string;
|
|
11
|
+
}>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 链接流程
|
|
15
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Signaling_and_video_calling
|
|
16
|
+
* TODO 1.音频呼叫
|
|
17
|
+
* TODO 2.会话的过程中切换流
|
|
18
|
+
*/
|
|
19
|
+
export default abstract class RTCPeerConnectionHandler extends LocalStreamHandler {
|
|
20
|
+
peerConnection?: RTCPeerConnection;
|
|
21
|
+
videoCodecs: RTCRtpCodec[];
|
|
22
|
+
audioCodecs: RTCRtpCodec[];
|
|
23
|
+
audioReciveCodecs: RTCRtpCodec[];
|
|
24
|
+
remoteStream?: MediaStream;
|
|
25
|
+
emitStreamTimeout?: number;
|
|
26
|
+
constructor();
|
|
27
|
+
/**生成一个peerconnection */
|
|
28
|
+
buildConnection(): RTCPeerConnection;
|
|
29
|
+
localTractChange(prev: MediaStreamTrack | undefined, next: MediaStreamTrack | undefined): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* 是否处于会议当中
|
|
32
|
+
*/
|
|
33
|
+
isInMeeting(): boolean;
|
|
34
|
+
hasRemoteVideo(strem?: MediaStream): boolean;
|
|
35
|
+
emitLocalStreamChange(): void;
|
|
36
|
+
/**
|
|
37
|
+
* 通知用户远程的流发生了变化
|
|
38
|
+
*/
|
|
39
|
+
emitRemoteStreamChange(): void;
|
|
40
|
+
/**
|
|
41
|
+
* 做个100ms的延时来缓冲流的变化
|
|
42
|
+
*/
|
|
43
|
+
trigerStreamChange(timeout?: number): void;
|
|
44
|
+
/**
|
|
45
|
+
* 接受track时候的处理事件
|
|
46
|
+
*/
|
|
47
|
+
reciveTrack(e: RTCTrackEvent): void;
|
|
48
|
+
abstract onIceCandidate(e: RTCPeerConnectionIceEvent): any;
|
|
49
|
+
/**
|
|
50
|
+
* use custorm codec ,
|
|
51
|
+
* default is H264/PCMA,
|
|
52
|
+
* TODO 火狐浏览器没有RTCRtpSender.getCapabilities相关方法,是否在createoffer之后进行sdp协议处理来适配编码工作
|
|
53
|
+
* @param videoCodec
|
|
54
|
+
* @param audioCodec
|
|
55
|
+
*/
|
|
56
|
+
preferCodec(videoCodec?: string, audioCodec?: string): void;
|
|
57
|
+
trackIsInPeerConnection(track: MediaStreamTrack): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* 将本地的track更新到peereonnection 中
|
|
60
|
+
* 只接受流:没有本地stream rtcPeerConnection.addTransceiver("video", {direction: "recvonly"});rtcPeerConnection.addTransceiver("audio", {direction: "recvonly"});
|
|
61
|
+
* recvonly/sendonly/sendrecv/inactive
|
|
62
|
+
*
|
|
63
|
+
*/
|
|
64
|
+
updateTracks(): void;
|
|
65
|
+
/**
|
|
66
|
+
* create and format offer
|
|
67
|
+
*/
|
|
68
|
+
createOffer(): Promise<RTCSessionDescriptionInit>;
|
|
69
|
+
/**
|
|
70
|
+
* set offer
|
|
71
|
+
*/
|
|
72
|
+
setOffer(sdp: string): Promise<void>;
|
|
73
|
+
/**
|
|
74
|
+
* create answer
|
|
75
|
+
*/
|
|
76
|
+
createAnswer(): Promise<RTCSessionDescriptionInit>;
|
|
77
|
+
/**
|
|
78
|
+
* set answer
|
|
79
|
+
*/
|
|
80
|
+
setAnswer(sdp: string): Promise<void>;
|
|
81
|
+
/**
|
|
82
|
+
* set ice candidate
|
|
83
|
+
* @param ice
|
|
84
|
+
*/
|
|
85
|
+
setRemoteIce(ice: RTCIceCandidateInit): void;
|
|
86
|
+
/**
|
|
87
|
+
* 关闭链接
|
|
88
|
+
*/
|
|
89
|
+
closeConnection(peerConnection: RTCPeerConnection): void;
|
|
90
|
+
/**
|
|
91
|
+
* 销毁会话
|
|
92
|
+
*/
|
|
93
|
+
close(): void;
|
|
94
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 销毁dom上渲染的流
|
|
3
|
+
*/
|
|
4
|
+
export declare const releaseStreamFromContainer: (container?: HTMLVideoElement | HTMLAudioElement) => void;
|
|
5
|
+
/**
|
|
6
|
+
* 将流渲染到dom上
|
|
7
|
+
*/
|
|
8
|
+
export declare const renderStreamToContainer: (stream?: MediaStream, container?: HTMLVideoElement | HTMLAudioElement) => void;
|
|
9
|
+
/**
|
|
10
|
+
* 关闭流
|
|
11
|
+
*/
|
|
12
|
+
export declare const closeStreamAndTrack: (stream: MediaStream) => void;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { RtcClient } from '../client/RtcClient';
|
|
2
|
+
import { default as RTCPeerConnectionHandler } from '../peer/RTCPeerConnectionHandler';
|
|
3
|
+
export declare abstract class RtcAbstractSession extends RTCPeerConnectionHandler {
|
|
4
|
+
sessionId: string;
|
|
5
|
+
rtcClient: RtcClient | undefined;
|
|
6
|
+
remoteNumber: string | undefined;
|
|
7
|
+
inviteSeq?: number;
|
|
8
|
+
inviteOffer?: string;
|
|
9
|
+
constructor(rtcClient: RtcClient, sessionId: string, remoteNumber: string | undefined);
|
|
10
|
+
reciveIceRequest({ ice }: any): void;
|
|
11
|
+
getRemoteNumber(): string | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* ice candidate is trigger after createoffer or createanswer
|
|
14
|
+
*/
|
|
15
|
+
onIceCandidate(e: RTCPeerConnectionIceEvent): void;
|
|
16
|
+
/**
|
|
17
|
+
* 销毁会话
|
|
18
|
+
*/
|
|
19
|
+
destroy(isSendBye?: boolean): void;
|
|
20
|
+
rejectCall(): void;
|
|
21
|
+
acceptCall(): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* 当同一个会议又收到offer的时候,尝试重新做一个链接,
|
|
24
|
+
* 直接setoffer服务端有一些问题,使用此方案来处理一下,看看是否可行
|
|
25
|
+
*/
|
|
26
|
+
pickNewConnection(): Promise<void>;
|
|
27
|
+
checkIsNotUndefined(...x: any[]): any[];
|
|
28
|
+
sendDtmf(dtmf: string): Promise<any>;
|
|
29
|
+
playRemoteStream(container: HTMLVideoElement, options?: {
|
|
30
|
+
audioOnly?: boolean;
|
|
31
|
+
autoPlay?: boolean;
|
|
32
|
+
muted?: boolean;
|
|
33
|
+
}): void;
|
|
34
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { RtcCalledType } from './RtcCalledTyped';
|
|
2
|
+
import { RtcClient } from '../client/RtcClient';
|
|
3
|
+
import { RtcAbstractSession } from './RtcAbstractSession';
|
|
4
|
+
/**
|
|
5
|
+
* 被叫session
|
|
6
|
+
*/
|
|
7
|
+
export declare class RtcCalledSession extends RtcAbstractSession {
|
|
8
|
+
callType: RtcCalledType;
|
|
9
|
+
constructor(rtcClient: RtcClient, sessionId: string, remoteNumber: string, offerSdp: string, seq: number);
|
|
10
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { RtcAbstractSession } from './RtcAbstractSession';
|
|
2
|
+
import { RtcCalledType } from './RtcCalledTyped';
|
|
3
|
+
/**
|
|
4
|
+
* Rtc 会话对象封装
|
|
5
|
+
* 流程:
|
|
6
|
+
* 1.创建会话
|
|
7
|
+
* 1.(选择本地流/添加被叫用户)
|
|
8
|
+
* 2.发送请求
|
|
9
|
+
* 3.接受响应
|
|
10
|
+
* 4.开始会话,被拒绝(结束会话)
|
|
11
|
+
* 5.被挂断,主动挂断(结束会话)
|
|
12
|
+
* 6.用户掉线
|
|
13
|
+
*/
|
|
14
|
+
export declare class RtcSession extends RtcAbstractSession {
|
|
15
|
+
responseCallType: RtcCalledType;
|
|
16
|
+
/**
|
|
17
|
+
* 开始会话
|
|
18
|
+
*/
|
|
19
|
+
start(): Promise<any>;
|
|
20
|
+
/**
|
|
21
|
+
* 添加会话用户
|
|
22
|
+
*/
|
|
23
|
+
addRemote(remoteNumber: string): void;
|
|
24
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* rtc 会话过程中向上抛出的所有事件
|
|
3
|
+
*/
|
|
4
|
+
export declare enum RtcSessionEvent {
|
|
5
|
+
bye = "bye",
|
|
6
|
+
stream = "stream",
|
|
7
|
+
reInvite = "reInvite",
|
|
8
|
+
localAudioChange = "localAudioChange",
|
|
9
|
+
localVideoChange = "localVideoChange",
|
|
10
|
+
localStreamChange = "localStreamChange"
|
|
11
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { RtcWebSocket } from './RtcWebSocket';
|
|
3
|
+
/**
|
|
4
|
+
* 内部持有一个websocket,并且对websocket进行管理,对外提供发送消息的接口以及相关事件
|
|
5
|
+
*/
|
|
6
|
+
export declare abstract class RtcSocketServerHandler extends EventEmitter {
|
|
7
|
+
localNumber: string;
|
|
8
|
+
expireTime: number;
|
|
9
|
+
heartTime: number;
|
|
10
|
+
socketWorker?: RtcWebSocket;
|
|
11
|
+
server: string | string[];
|
|
12
|
+
activeServer: string;
|
|
13
|
+
constructor(server: string, localNumber: string, expireTime: number, heartTime: number);
|
|
14
|
+
abstract onReviceMessage(data: any): any;
|
|
15
|
+
abstract onConnected(): any;
|
|
16
|
+
abstract onDisConnected(e: CloseEvent): any;
|
|
17
|
+
abstract unRegister(): void;
|
|
18
|
+
/**
|
|
19
|
+
* 测试可用的websocket地址
|
|
20
|
+
*/
|
|
21
|
+
testWs(addrs: string[]): Promise<any>;
|
|
22
|
+
/**
|
|
23
|
+
* 修改/设置 websocket地址
|
|
24
|
+
*/
|
|
25
|
+
reConnect(): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* 发送消息
|
|
28
|
+
*/
|
|
29
|
+
sendMessage(message: any): void;
|
|
30
|
+
destroy(): void;
|
|
31
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { SignalMessage } from '../message/SignalMessage';
|
|
3
|
+
/**
|
|
4
|
+
* 对websocket进行封装
|
|
5
|
+
*/
|
|
6
|
+
export declare class RtcWebSocket extends EventEmitter {
|
|
7
|
+
/**
|
|
8
|
+
* signal server address
|
|
9
|
+
*/
|
|
10
|
+
server: string;
|
|
11
|
+
/**
|
|
12
|
+
* websocket client
|
|
13
|
+
*/
|
|
14
|
+
ws: Worker;
|
|
15
|
+
constructor(server: string, heartBeat: SignalMessage, heartTime: number);
|
|
16
|
+
/**
|
|
17
|
+
* connect to the websocket server
|
|
18
|
+
*/
|
|
19
|
+
connect(): void;
|
|
20
|
+
configHeartBeat(heartBeat: SignalMessage, heartTime: number): void;
|
|
21
|
+
initWebsocket(): void;
|
|
22
|
+
send(data: Object): void;
|
|
23
|
+
/**
|
|
24
|
+
* 主动断开websocket,不会触发重连机制
|
|
25
|
+
*/
|
|
26
|
+
close(): void;
|
|
27
|
+
/**
|
|
28
|
+
* 发送消息
|
|
29
|
+
*/
|
|
30
|
+
sendMessage(message: any): void;
|
|
31
|
+
}
|
package/package.json
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "usc-rtc-client",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "usc rtc client",
|
|
5
|
-
"main": "./dist/index.js",
|
|
5
|
+
"main": "./dist/index.umd.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"build": "
|
|
8
|
+
"build": "vite build && cp dist/index.es.js test/",
|
|
9
|
+
"publish": "pnpm run build && npm publish",
|
|
10
|
+
"release:patch": "pnpm version patch && pnpm run publish",
|
|
11
|
+
"release:minor": "pnpm version minor && pnpm run publish",
|
|
12
|
+
"release:major": "pnpm version major && pnpm run publish"
|
|
9
13
|
},
|
|
10
14
|
"exports": {
|
|
11
|
-
"import": "./dist/index.
|
|
12
|
-
"require": "./dist/index.js"
|
|
15
|
+
"import": "./dist/index.es.js",
|
|
16
|
+
"require": "./dist/index.umd.js"
|
|
13
17
|
},
|
|
14
18
|
"files": [
|
|
15
19
|
"dist"
|
|
@@ -18,20 +22,17 @@
|
|
|
18
22
|
"author": "",
|
|
19
23
|
"license": "ISC",
|
|
20
24
|
"devDependencies": {
|
|
21
|
-
"@rollup/plugin-commonjs": "^22.0.2",
|
|
22
|
-
"@rollup/plugin-node-resolve": "^13.3.0",
|
|
23
25
|
"@types/events": "^3.0.3",
|
|
24
26
|
"@types/pako": "^1.0.7",
|
|
27
|
+
"@vitejs/plugin-react": "^5.1.2",
|
|
25
28
|
"nodejs-websocket": "^1.7.2",
|
|
26
|
-
"rollup": "^2.79.1",
|
|
27
|
-
"rollup-plugin-polyfill-node": "^0.9.0",
|
|
28
|
-
"rollup-plugin-terser": "^7.0.2",
|
|
29
|
-
"rollup-plugin-ts": "^2.0.7",
|
|
30
|
-
"rollup-plugin-web-worker-loader": "^1.6.1",
|
|
31
29
|
"tslib": "^2.6.3",
|
|
32
|
-
"typescript": "^4.9.5"
|
|
30
|
+
"typescript": "^4.9.5",
|
|
31
|
+
"vite": "^7.2.7",
|
|
32
|
+
"vite-plugin-dts": "^4.5.4"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
+
"events": "^3.3.0",
|
|
35
36
|
"nanoid": "^3.3.7",
|
|
36
37
|
"pako": "^2.1.0",
|
|
37
38
|
"usc-ptt-sdk": "^1.0.5"
|