diff --git a/Source/HTTPServer.js b/Source/HTTPServer.js index 991dfd7..47bc01b 100644 --- a/Source/HTTPServer.js +++ b/Source/HTTPServer.js @@ -22,6 +22,12 @@ app.get("/script",(request, response)=>{ app.get("/index.js.map",(request, response)=>{ response.sendFile(resolve("./script/index.js.map")) }); +app.get("/webrtc.js",(request, response)=>{ + response.sendFile(resolve("./script/webrtc.js")) +}); +app.get("/webrtc.adapter.js",(request, response)=>{ + response.sendFile(resolve("./script/webrtc.adapter.js")) +}); app.get("*",(request, response)=>{ response.sendFile(resolve("./script/status.xml")) }); \ No newline at end of file diff --git a/script/webrtc.adapter.js b/script/webrtc.adapter.js new file mode 100644 index 0000000..9d3fe38 --- /dev/null +++ b/script/webrtc.adapter.js @@ -0,0 +1 @@ +!function(e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).adapter=e()}(function(){return function n(i,o,a){function s(t,e){if(!o[t]){if(!i[t]){var r="function"==typeof require&&require;if(!e&&r)return r(t,!0);if(c)return c(t,!0);throw(e=new Error("Cannot find module '"+t+"'")).code="MODULE_NOT_FOUND",e}r=o[t]={exports:{}},i[t][0].call(r.exports,function(e){return s(i[t][1][e]||e)},r,r.exports,n,i,o,a)}return o[t].exports}for(var c="function"==typeof require&&require,e=0;e>24]),e})},r.shimMaxMessageSize=function(e,o){var a;e.RTCPeerConnection&&("sctp"in e.RTCPeerConnection.prototype||Object.defineProperty(e.RTCPeerConnection.prototype,"sctp",{get:function(){return void 0===this._sctp?null:this._sctp}}),a=e.RTCPeerConnection.prototype.setRemoteDescription,e.RTCPeerConnection.prototype.setRemoteDescription=function(){var e,t,r,n,i;return this._sctp=null,"chrome"===o.browser&&76<=o.version&&"plan-b"===this.getConfiguration().sdpSemantics&&Object.defineProperty(this,"sctp",{get:function(){return void 0===this._sctp?null:this._sctp},enumerable:!0,configurable:!0}),function(e){if(!e||!e.sdp)return!1;e=s.default.splitSections(e.sdp);return e.shift(),e.some(function(e){e=s.default.parseMLine(e);return e&&"application"===e.kind&&-1!==e.protocol.indexOf("SCTP")})}(arguments[0])&&(t=function(e){e=e.sdp.match(/mozilla...THIS_IS_SDPARTA-(\d+)/);if(null===e||e.length<2)return-1;e=parseInt(e[1],10);return e!=e?-1:e}(arguments[0]),n=t,i=65536,n=i="firefox"===o.browser?o.version<57?-1===n?16384:2147483637:o.version<60?57===o.version?65535:65536:2147483637:i,i=arguments[0],t=t,r=65536,"firefox"===o.browser&&57===o.version&&(r=65535),0<(i=s.default.matchPrefix(i.sdp,"a=max-message-size:")).length?r=parseInt(i[0].substr(19),10):"firefox"===o.browser&&-1!==t&&(r=2147483637),i=r,e=void 0,e=0===n&&0===i?Number.POSITIVE_INFINITY:0===n||0===i?Math.max(n,i):Math.min(n,i),t={},Object.defineProperty(t,"maxMessageSize",{get:function(){return e}}),this._sctp=t),a.apply(this,arguments)})},r.shimSendThrowTypeError=function(e){var t;function r(t,r){var n=t.send;t.send=function(){var e=arguments[0],e=e.length||e.size||e.byteLength;if("open"===t.readyState&&r.sctp&&e>r.sctp.maxMessageSize)throw new TypeError("Message too large (can send a maximum of "+r.sctp.maxMessageSize+" bytes)");return n.apply(t,arguments)}}e.RTCPeerConnection&&"createDataChannel"in e.RTCPeerConnection.prototype&&(t=e.RTCPeerConnection.prototype.createDataChannel,e.RTCPeerConnection.prototype.createDataChannel=function(){var e=t.apply(this,arguments);return r(e,this),e},n.wrapPeerConnectionEvent(e,"datachannel",function(e){return r(e.channel,e.target),e}))},r.shimConnectionState=function(e){var r;!e.RTCPeerConnection||"connectionState"in e.RTCPeerConnection.prototype||(r=e.RTCPeerConnection.prototype,Object.defineProperty(r,"connectionState",{get:function(){return{completed:"connected",checking:"connecting"}[this.iceConnectionState]||this.iceConnectionState},enumerable:!0,configurable:!0}),Object.defineProperty(r,"onconnectionstatechange",{get:function(){return this._onconnectionstatechange||null},set:function(e){this._onconnectionstatechange&&(this.removeEventListener("connectionstatechange",this._onconnectionstatechange),delete this._onconnectionstatechange),e&&this.addEventListener("connectionstatechange",this._onconnectionstatechange=e)},enumerable:!0,configurable:!0}),["setLocalDescription","setRemoteDescription"].forEach(function(e){var t=r[e];r[e]=function(){return this._connectionstatechangepoly||(this._connectionstatechangepoly=function(e){var t,r=e.target;return r._lastConnectionState!==r.connectionState&&(r._lastConnectionState=r.connectionState,t=new Event("connectionstatechange",e),r.dispatchEvent(t)),e},this.addEventListener("iceconnectionstatechange",this._connectionstatechangepoly)),t.apply(this,arguments)}}))},r.removeExtmapAllowMixed=function(r,e){var n;!r.RTCPeerConnection||"chrome"===e.browser&&71<=e.version||"safari"===e.browser&&605<=e.version||(n=r.RTCPeerConnection.prototype.setRemoteDescription,r.RTCPeerConnection.prototype.setRemoteDescription=function(e){var t;return e&&e.sdp&&-1!==e.sdp.indexOf("\na=extmap-allow-mixed")&&(t=e.sdp.split("\n").filter(function(e){return"a=extmap-allow-mixed"!==e.trim()}).join("\n"),r.RTCSessionDescription&&e instanceof r.RTCSessionDescription?arguments[0]=new r.RTCSessionDescription({type:e.type,sdp:t}):e.sdp=t),n.apply(this,arguments)})},r.shimAddIceCandidateNullOrEmpty=function(e,t){var r;e.RTCPeerConnection&&e.RTCPeerConnection.prototype&&((r=e.RTCPeerConnection.prototype.addIceCandidate)&&0!==r.length&&(e.RTCPeerConnection.prototype.addIceCandidate=function(){return arguments[0]?("chrome"===t.browser&&t.version<78||"firefox"===t.browser&&t.version<68||"safari"===t.browser)&&arguments[0]&&""===arguments[0].candidate?Promise.resolve():r.apply(this,arguments):(arguments[1]&&arguments[1].apply(null),Promise.resolve())}))},r.shimParameterlessSetLocalDescription=function(e,t){var r;e.RTCPeerConnection&&e.RTCPeerConnection.prototype&&((r=e.RTCPeerConnection.prototype.setLocalDescription)&&0!==r.length&&(e.RTCPeerConnection.prototype.setLocalDescription=function(){var t=this,e=arguments[0]||{};if("object"!==(void 0===e?"undefined":o(e))||e.type&&e.sdp)return r.apply(this,arguments);if(!(e={type:e.type,sdp:e.sdp}).type)switch(this.signalingState){case"stable":case"have-local-offer":case"have-remote-pranswer":e.type="offer";break;default:e.type="answer"}return e.sdp||"offer"!==e.type&&"answer"!==e.type?r.apply(this,[e]):("offer"===e.type?this.createOffer:this.createAnswer).apply(this).then(function(e){return r.apply(t,[e])})}))},e("sdp")),s=(r=r)&&r.__esModule?r:{default:r},n=function(e){{if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r]);return t.default=e,t}}(e("./utils"))},{"./utils":11,sdp:12}],7:[function(e,t,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0}),r.shimGetDisplayMedia=r.shimGetUserMedia=void 0;var a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},n=e("./getusermedia"),i=(Object.defineProperty(r,"shimGetUserMedia",{enumerable:!0,get:function(){return n.shimGetUserMedia}}),e("./getdisplaymedia"));Object.defineProperty(r,"shimGetDisplayMedia",{enumerable:!0,get:function(){return i.shimGetDisplayMedia}}),r.shimOnTrack=function(e){"object"===(void 0===e?"undefined":a(e))&&e.RTCTrackEvent&&"receiver"in e.RTCTrackEvent.prototype&&!("transceiver"in e.RTCTrackEvent.prototype)&&Object.defineProperty(e.RTCTrackEvent.prototype,"transceiver",{get:function(){return{receiver:this.receiver}}})},r.shimPeerConnection=function(n,i){var o,r;"object"===(void 0===n?"undefined":a(n))&&(n.RTCPeerConnection||n.mozRTCPeerConnection)&&(!n.RTCPeerConnection&&n.mozRTCPeerConnection&&(n.RTCPeerConnection=n.mozRTCPeerConnection),i.version<53&&["setLocalDescription","setRemoteDescription","addIceCandidate"].forEach(function(e){var t=n.RTCPeerConnection.prototype[e],r=function(e,t,r){t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r;return e}({},e,function(){return arguments[0]=new("addIceCandidate"===e?n.RTCIceCandidate:n.RTCSessionDescription)(arguments[0]),t.apply(this,arguments)});n.RTCPeerConnection.prototype[e]=r[e]}),o={inboundrtp:"inbound-rtp",outboundrtp:"outbound-rtp",candidatepair:"candidate-pair",localcandidate:"local-candidate",remotecandidate:"remote-candidate"},r=n.RTCPeerConnection.prototype.getStats,n.RTCPeerConnection.prototype.getStats=function(){var e=Array.prototype.slice.call(arguments),t=e[0],n=e[1],e=e[2];return r.apply(this,[t||null]).then(function(r){if(i.version<53&&!n)try{r.forEach(function(e){e.type=o[e.type]||e.type})}catch(e){if("TypeError"!==e.name)throw e;r.forEach(function(e,t){r.set(t,Object.assign({},e,{type:o[e.type]||e.type}))})}return r}).then(n,e)})},r.shimSenderGetStats=function(e){var r,t;"object"===(void 0===e?"undefined":a(e))&&e.RTCPeerConnection&&e.RTCRtpSender&&(e.RTCRtpSender&&"getStats"in e.RTCRtpSender.prototype||((r=e.RTCPeerConnection.prototype.getSenders)&&(e.RTCPeerConnection.prototype.getSenders=function(){var t=this,e=r.apply(this,[]);return e.forEach(function(e){return e._pc=t}),e}),(t=e.RTCPeerConnection.prototype.addTrack)&&(e.RTCPeerConnection.prototype.addTrack=function(){var e=t.apply(this,arguments);return e._pc=this,e}),e.RTCRtpSender.prototype.getStats=function(){return this.track?this._pc.getStats(this.track):Promise.resolve(new Map)}))},r.shimReceiverGetStats=function(e){var r;"object"===(void 0===e?"undefined":a(e))&&e.RTCPeerConnection&&e.RTCRtpSender&&(e.RTCRtpSender&&"getStats"in e.RTCRtpReceiver.prototype||((r=e.RTCPeerConnection.prototype.getReceivers)&&(e.RTCPeerConnection.prototype.getReceivers=function(){var t=this,e=r.apply(this,[]);return e.forEach(function(e){return e._pc=t}),e}),o.wrapPeerConnectionEvent(e,"track",function(e){return e.receiver._pc=e.srcElement,e}),e.RTCRtpReceiver.prototype.getStats=function(){return this._pc.getStats(this.track)}))},r.shimRemoveStream=function(e){!e.RTCPeerConnection||"removeStream"in e.RTCPeerConnection.prototype||(e.RTCPeerConnection.prototype.removeStream=function(t){var r=this;o.deprecated("removeStream","removeTrack"),this.getSenders().forEach(function(e){e.track&&t.getTracks().includes(e.track)&&r.removeTrack(e)})})},r.shimRTCDataChannel=function(e){e.DataChannel&&!e.RTCDataChannel&&(e.RTCDataChannel=e.DataChannel)},r.shimAddTransceiver=function(e){var i;"object"!==(void 0===e?"undefined":a(e))||!e.RTCPeerConnection||(i=e.RTCPeerConnection.prototype.addTransceiver)&&(e.RTCPeerConnection.prototype.addTransceiver=function(){this.setParametersPromises=[];var e,t=arguments[1]&&arguments[1].sendEncodings,r=0<(t=[].concat(function(e){{if(Array.isArray(e)){for(var t=0,r=Array(e.length);t= 1.0");if("maxFramerate"in e&&!(0<=parseFloat(e.maxFramerate)))throw new RangeError("max_framerate must be >= 0.0")}),i.apply(this,arguments));return!r||"encodings"in(r=(e=n.sender).getParameters())&&(1!==r.encodings.length||0!==Object.keys(r.encodings[0]).length)||(r.encodings=t,e.sendEncodings=t,this.setParametersPromises.push(e.setParameters(r).then(function(){delete e.sendEncodings}).catch(function(){delete e.sendEncodings}))),n})},r.shimGetParameters=function(e){var t;"object"!==(void 0===e?"undefined":a(e))||!e.RTCRtpSender||(t=e.RTCRtpSender.prototype.getParameters)&&(e.RTCRtpSender.prototype.getParameters=function(){var e=t.apply(this,arguments);return"encodings"in e||(e.encodings=[].concat(this.sendEncodings||[{}])),e})},r.shimCreateOffer=function(e){var r;"object"===(void 0===e?"undefined":a(e))&&e.RTCPeerConnection&&(r=e.RTCPeerConnection.prototype.createOffer,e.RTCPeerConnection.prototype.createOffer=function(){var e=this,t=arguments;return this.setParametersPromises&&this.setParametersPromises.length?Promise.all(this.setParametersPromises).then(function(){return r.apply(e,t)}).finally(function(){e.setParametersPromises=[]}):r.apply(this,arguments)})},r.shimCreateAnswer=function(e){var r;"object"===(void 0===e?"undefined":a(e))&&e.RTCPeerConnection&&(r=e.RTCPeerConnection.prototype.createAnswer,e.RTCPeerConnection.prototype.createAnswer=function(){var e=this,t=arguments;return this.setParametersPromises&&this.setParametersPromises.length?Promise.all(this.setParametersPromises).then(function(){return r.apply(e,t)}).finally(function(){e.setParametersPromises=[]}):r.apply(this,arguments)})};var o=function(e){{if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r]);return t.default=e,t}}(e("../utils"))},{"../utils":11,"./getdisplaymedia":8,"./getusermedia":9}],8:[function(e,t,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0}),r.shimGetDisplayMedia=function(t,r){t.navigator.mediaDevices&&"getDisplayMedia"in t.navigator.mediaDevices||t.navigator.mediaDevices&&(t.navigator.mediaDevices.getDisplayMedia=function(e){return e&&e.video?(!0===e.video?e.video={mediaSource:r}:e.video.mediaSource=r,t.navigator.mediaDevices.getUserMedia(e)):((e=new DOMException("getDisplayMedia without video constraints is undefined")).name="NotFoundError",e.code=8,Promise.reject(e))})}},{}],9:[function(e,t,r){"use strict";Object.defineProperty(r,"__esModule",{value:!0});var s="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e};r.shimGetUserMedia=function(e,t){var n=e&&e.navigator,e=e&&e.MediaStreamTrack;{var r,i,o,a;n.getUserMedia=function(e,t,r){c.deprecated("navigator.getUserMedia","navigator.mediaDevices.getUserMedia"),n.mediaDevices.getUserMedia(e).then(t,r)},55=r&&parseInt(e[r],10)}function c(e){return"[object Object]"===Object.prototype.toString.call(e)}function p(t,r,n){r&&!n.has(r.id)&&(n.set(r.id,r),Object.keys(r).forEach(function(e){e.endsWith("Id")?p(t,t.get(r[e]),n):e.endsWith("Ids")&&r[e].forEach(function(e){p(t,t.get(e),n)})}))}},{}],12:[function(e,t,r){"use strict";var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},p={generateIdentifier:function(){return Math.random().toString(36).substr(2,10)}};p.localCName=p.generateIdentifier(),p.splitLines=function(e){return e.trim().split("\n").map(function(e){return e.trim()})},p.splitSections=function(e){return e.split("\nm=").map(function(e,t){return(0n&&(n=e.maxptime)}),0} + */ + this.recaivingStream = new Map(); + /** + * @type {Map} + */ + this.sendingStream = new Map(); + this.rtc.addEventListener("connectionstatechange",(...args)=>{ + this.eventConnectionState(...args); + }) + this.rtc.addEventListener("icecandidate",(...args)=>{ + this.eventIcecandidate(...args); + }) + this.rtc.addEventListener("iceconnectionstatechange",(...args)=>{ + this.eventICEConnectionState(...args); + }) + this.rtc.addEventListener("icegatheringstatechange",(...args)=>{ + this.eventICEGatherinState(...args); + }) + this.rtc.addEventListener("negotiationneeded",(...args)=>{ + this.eventNogationNeeded(...args); + }) + this.rtc.addEventListener("signalingstatechange",(...args)=>{ + this.eventSignalingState(...args); + }) + this.rtc.addEventListener("track",(...args)=>{ + this.eventTrack(...args); + }) + this.rtc.addEventListener("datachannel",(...args)=>{ + this.eventDatachannel(...args); + }) + let events = {}; + /** + * @param {Function} callback + */ + this.addEventListener = function(event,callback){ + (events[event] || (events[event]=[])).push(callback); + }; + this.on = this.addEventListener; + this.dispatch = async (event,...args) => { + if(events[event]) for (const callback of events[event]) { + await callback(...args) + } + } + this.emit = this.dispatch; + /** + * @type {RTCDataChannel} + */ + this.channel = null; + + this.on('input',async (data)=>{ + switch(data.type) + { + case "icecandidate":{ + await this.rtc.addIceCandidate(new RTCIceCandidate(data.value)); + break; + } + case "offer":{ + await this.rtc.setRemoteDescription(new RTCSessionDescription(data.value)); + let answer = await this.rtc.createAnswer({ + offerToReceiveAudio: true, + offerToReceiveVideo: true + }) + await this.rtc.setLocalDescription(answer); + this.send({ + type: 'answer', + value: answer + }); + break; + } + case "answer":{ + await this.rtc.setRemoteDescription(new RTCSessionDescription(data.value)) + break; + } + case "streamInfo":{ + let {id,value} = data; + if(!this.recaivingStream.has(id)) + { + this.recaivingStream.set(id,{ + stream: null + }); + }; + Object.assign(this.recaivingStream.get(id), value); + this.send({ + type:'streamAccept', + id + }) + break; + } + case "streamRemoved":{ + let {id} = data; + this.emit('stream:stopped', this.recaivingStream.get(id)); + this.sendingStream.delete(id); + break; + } + case "streamAccept":{ + let {id} = data; + let {stream} = this.sendingStream.get(id); + let senders = []; + for (const track of stream.getTracks()) { + senders.push(this.rtc.addTrack(track, stream)); + }; + stream.senders = senders; + break; + } + case "message":{ + this.emit('message', data.payload); + break; + } + } + }) +}; +WebRTC.channels = new Map(); +WebRTC.prototype.connect = function(object){ + if(!this.channel) + { + this.createDefaultDataChannel(); + } +}; +WebRTC.prototype.sendMessage = function(object){ + this.send({ + type:'message', + payload: object + }); +}; +WebRTC.prototype.createDefaultDataChannel = function(){ + let dt = this.rtc.createDataChannel(":default:",{ + ordered: true + }); + dt.addEventListener("open",()=>{ + this.channel = dt; + console.log(...rtcLabel, this.id, dt.label + ' veri kanalı açıldı'); + WebRTC.channels.set(this.id, this); + }); + dt.addEventListener("message",({data})=>{ + let pack = JSON.parse(data); + console.log(...rtcLabel, this.id, dt.label + ' P2P Pack ', pack); + this.emit('input', pack); + }) + dt.addEventListener("close",()=>{ + this.channel = null; + console.log(...rtcLabel, this.id, dt.label + ' veri kanalı kapandı'); + }) +}; +WebRTC.prototype.destroy = function(){ + this.active = false; + if(this.channel) + { + this.channel.close(); + this.channel = null; + } + if(this.rtc) + { + this.rtc.close(); + this.rtc = null; + }; + this.emit('disconnected'); + WebRTC.channels.delete(this.id); +} +/** + * + * @param {RTCDataChannelEvent} event + */ +WebRTC.prototype.eventDatachannel = function(event){ + console.log(...rtcLabel, this.id, event.channel.label + ' veri kanalı açıldı'); + if(event.channel.label == ':default:'){ + WebRTC.channels.set(this.id, this); + this.channel = event.channel + } + event.channel.addEventListener("message",({data})=>{ + let pack = JSON.parse(data); + console.log(...rtcLabel, this.id, event.channel.label + ' P2P Pack ', pack); + this.emit('input', pack); + }) + event.channel.addEventListener("close",()=>{ + this.channel = null; + WebRTC.channels.delete(this.id); + WebRTC.requireGC = true; + console.log(...rtcLabel, this.id, event.channel.label + ' veri kanalı kapandı'); + }) +}; +WebRTC.requireGC = false; +setInterval(()=>{ + if(WebRTC.requireGC == false) return; + let img = document.createElement("img"); + img.src = window.URL.createObjectURL(new Blob([new ArrayBuffer(5e+7)])); + img.onerror = function() { + window.URL.revokeObjectURL(this.src); + img = null; + console.log("WebRTC Pool connections garbage connection microtask completed") + }; + WebRTC.requireGC = false; +}, 3000) +WebRTC.prototype.send = function(object){ + if(this.channel?.readyState == "open") + { + this.channel.send(JSON.stringify(object)); + }else{ + this.emit('output', object); + } +}; +let rtcLabel = ["%cRTC","color:red;font-weight:bold"]; +WebRTC.prototype.eventConnectionState = function(){ + this.connectionStatus = this.rtc.connectionState; + if(this.connectionStatus == 'connected') + { + if(this.active == false) + { + this.emit('connected'); + this.active = true; + } + }; + if(this.connectionStatus == 'failed' || this.connectionStatus == "disconnected" || this.connectionStatus == "closed") + { + if(this.active) + { + this.destroy(); + } + } + console.log(...rtcLabel, this.id, "connectionStatus", this.connectionStatus) +}; +/** + * + * @param {RTCPeerConnectionIceEvent} event + */ +WebRTC.prototype.eventIcecandidate = function(event){ + console.log(...rtcLabel, this.id, 'ice created'); + if(event.candidate) + { + this.send({ + type:'icecandidate', + value: event.candidate + }) + } +}; +WebRTC.prototype.eventICEConnectionState = function(){ + this.iceStatus = this.rtc.iceConnectionState; + console.log(...rtcLabel, this.id, "iceStatus",this.iceStatus) +}; +WebRTC.prototype.eventICEGatherinState = function(){ + this.gatheringStatus = this.rtc.iceGatheringState; + console.log(...rtcLabel, this.id, "gatheringStatus",this.gatheringStatus) +}; +WebRTC.prototype.eventNogationNeeded = async function(){ + console.log(...rtcLabel, this.id, "requested nogation"); + let offer = await this.rtc.createOffer({ + iceRestart: true, + offerToReceiveAudio: true, + offerToReceiveVideo: true + }); + await this.rtc.setLocalDescription(offer); + this.send({ + type: 'offer', + value: offer + }); +}; +WebRTC.prototype.eventSignalingState = function(){ + this.signalingStatus = this.rtc.signalingState; + console.log(...rtcLabel, this.id, "signalingStatus",this.signalingStatus) +}; +/** + * @param {RTCTrackEvent} event + */ +WebRTC.prototype.eventTrack = function(event){ + if(event.streams.length) + { + for (const stream of event.streams) { + if(this.recaivingStream.get(stream.id).stream == null) + { + this.recaivingStream.get(stream.id).stream = stream; + this.emit('stream:added', this.recaivingStream.get(stream.id)); + }else{ + this.recaivingStream.get(stream.id).stream = stream; + } + } + } +}; +/** + * @param {MediaStream} stream + * @param {string} name + * @param {any} info + */ +WebRTC.prototype.sendStream = function(stream,name,info){ + this.send({ + type: 'streamInfo', + id: stream.id, + value: { + ...info, + name: name + } + }); + this.sendingStream.set(stream.id,{ + ...info, + name: name, + stream + }); +}; +/** + * @param {MediaStream} stream + * @param {string} name + * @param {any} info + */ +WebRTC.prototype.stopStream = function(_stream){ + if(this.connectionStatus != 'connected'){ + return + } + if(this.sendingStream.has(_stream.id)) + { + let {stream} = this.sendingStream.get(_stream.id); + + for (const track of stream.getTracks()) { + for (const RTCPSender of this.rtc.getSenders()) { + if(RTCPSender.track?.id == track.id) + { + this.rtc.removeTrack(RTCPSender); + } + } + } + + this.send({ + type: 'streamRemoved', + id: stream.id + }); + this.sendingStream.delete(_stream.id) + } +}; +/** + * @param {string} name + * @param {any} info + */ +WebRTC.prototype.stopAllStreams = function(){ + if(this.connectionStatus != 'connected'){ + return + } + for (const [id, {stream}] of this.sendingStream) { + for (const track of stream.getTracks()) { + for (const RTCPSender of this.rtc.getSenders()) { + if(RTCPSender.track?.id == track.id) + { + this.rtc.removeTrack(RTCPSender); + } + } + } + this.send({ + type: 'streamRemoved', + id: stream.id + }); + }; + + this.sendingStream.clear(); +}; + +WebRTC.getCamera = async (options) => { + return navigator.mediaDevices.getUserMedia({ + video: options || { + frameRate: 10, + width: 640, + height: 480 + } + }) +} +WebRTC.getMicrophone = async (options) => { + return navigator.mediaDevices.getUserMedia({ + audio: options || { + channelCount: 1, + sampleRate: 16000, + sampleSize: 16, + volume: 1 + } + }) +} +WebRTC.getDisplay = async (videoOptions) => { + return navigator.mediaDevices.getDisplayMedia({ + video: videoOptions || true + }) +} \ No newline at end of file