@gjsify/webrtc 0.4.21 → 0.4.23
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/lib/esm/register/data-channel.js +1 -1
- package/lib/esm/register/error.js +1 -1
- package/lib/esm/register/media-devices.js +1 -1
- package/lib/esm/register/media.js +1 -1
- package/lib/esm/register/peer-connection.js +1 -1
- package/lib/esm/rtc-data-channel.js +1 -1
- package/lib/esm/rtc-peer-connection/sdp-negotiation.js +1 -0
- package/lib/esm/rtc-peer-connection.js +1 -1
- package/lib/types/rtc-peer-connection/sdp-negotiation.d.ts +16 -0
- package/lib/types/rtc-peer-connection.d.ts +10 -13
- package/package.json +14 -14
|
@@ -1 +1 @@
|
|
|
1
|
-
import{RTCDataChannelEvent as e}from"../rtc-events.js";import{RTCDataChannel as t}from"../rtc-data-channel.js";globalThis.RTCDataChannel===void 0&&(
|
|
1
|
+
import{RTCDataChannelEvent as e}from"../rtc-events.js";import{RTCDataChannel as t}from"../rtc-data-channel.js";const n=globalThis;n.RTCDataChannel===void 0&&(n.RTCDataChannel=t),n.RTCDataChannelEvent===void 0&&(n.RTCDataChannelEvent=e);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{RTCError as e}from"../rtc-error.js";import{RTCErrorEvent as t}from"../rtc-events.js";globalThis.RTCError===void 0&&(
|
|
1
|
+
import{RTCError as e}from"../rtc-error.js";import{RTCErrorEvent as t}from"../rtc-events.js";const n=globalThis;n.RTCError===void 0&&(n.RTCError=e),n.RTCErrorEvent===void 0&&(n.RTCErrorEvent=t);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{MediaDevices as e}from"../media-devices.js";globalThis.navigator===void 0&&(
|
|
1
|
+
import{MediaDevices as e}from"../media-devices.js";const t=globalThis;t.navigator===void 0&&(t.navigator={}),t.navigator.mediaDevices===void 0&&(t.navigator.mediaDevices=new e);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{MediaStreamTrack as e}from"../media-stream-track.js";import{MediaStream as t}from"../media-stream.js";import{RTCTrackEvent as n}from"../rtc-track-event.js";globalThis.MediaStream===void 0&&(
|
|
1
|
+
import{MediaStreamTrack as e}from"../media-stream-track.js";import{MediaStream as t}from"../media-stream.js";import{RTCTrackEvent as n}from"../rtc-track-event.js";const r=globalThis;r.MediaStream===void 0&&(r.MediaStream=t),r.MediaStreamTrack===void 0&&(r.MediaStreamTrack=e),r.RTCTrackEvent===void 0&&(r.RTCTrackEvent=n);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{RTCSessionDescription as e}from"../rtc-session-description.js";import{RTCIceCandidate as t}from"../rtc-ice-candidate.js";import{RTCPeerConnectionIceEvent as n}from"../rtc-events.js";import{RTCPeerConnection as r}from"../rtc-peer-connection.js";globalThis.RTCPeerConnection===void 0&&(
|
|
1
|
+
import{RTCSessionDescription as e}from"../rtc-session-description.js";import{RTCIceCandidate as t}from"../rtc-ice-candidate.js";import{RTCPeerConnectionIceEvent as n}from"../rtc-events.js";import{RTCPeerConnection as r}from"../rtc-peer-connection.js";const i=globalThis;i.RTCPeerConnection===void 0&&(i.RTCPeerConnection=r),i.RTCSessionDescription===void 0&&(i.RTCSessionDescription=e),i.RTCIceCandidate===void 0&&(i.RTCIceCandidate=t),i.RTCPeerConnectionIceEvent===void 0&&(i.RTCPeerConnectionIceEvent=n);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import{RTCError as e}from"./rtc-error.js";import{RTCErrorEvent as t}from"./rtc-events.js";import{DOMException as n}from"@gjsify/dom-exception";import r from"gi://GLib?version=2.0";import{DataChannelBridge as i}from"@gjsify/webrtc-native";import{Blob as a}from"@gjsify/buffer";const o={1:`connecting`,2:`open`,3:`closing`,4:`closed`};function toGBytes(e){let t;return t=ArrayBuffer.isView(e)?new Uint8Array(e.buffer,e.byteOffset,e.byteLength):new Uint8Array(e),new r.Bytes(t)}function bytesToArrayBuffer(e){let t=e.toArray?.();if(
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{RTCError as e}from"./rtc-error.js";import{RTCErrorEvent as t}from"./rtc-events.js";import{DOMException as n}from"@gjsify/dom-exception";import r from"gi://GLib?version=2.0";import{DataChannelBridge as i}from"@gjsify/webrtc-native";import{Blob as a}from"@gjsify/buffer";const o={1:`connecting`,2:`open`,3:`closing`,4:`closed`};function toGBytes(e){let t;return t=ArrayBuffer.isView(e)?new Uint8Array(e.buffer,e.byteOffset,e.byteLength):new Uint8Array(e),new r.Bytes(t)}function bytesToArrayBuffer(e){let t=e,n=t.toArray?.();if(n instanceof Uint8Array)return n.buffer.slice(n.byteOffset,n.byteOffset+n.byteLength);let r=t.get_data?.();return r instanceof Uint8Array?r.buffer.slice(r.byteOffset,r.byteOffset+r.byteLength):new ArrayBuffer(0)}var RTCDataChannel=class extends EventTarget{_native;_bridge;_binaryType=`arraybuffer`;_bufferedAmount=0;_closed=!1;_onopen=null;_onclose=null;_onerror=null;_onmessage=null;_onbufferedamountlow=null;_onclosing=null;constructor(e){super();let t=e;t.channel!==void 0&&typeof t.dispose_bridge==`function`?(this._bridge=e,this._native=this._bridge.channel):(this._native=e,this._bridge=new i({channel:this._native})),this._bridge.connect(`opened`,()=>this._handleOpen()),this._bridge.connect(`closed`,()=>this._handleClose()),this._bridge.connect(`error-occurred`,(e,t)=>this._handleError(t)),this._bridge.connect(`message-string`,(e,t)=>this._handleString(t)),this._bridge.connect(`message-data`,(e,t)=>this._handleData(t)),this._bridge.connect(`buffered-amount-low`,()=>this._handleBufferedAmountLow()),this._bridge.connect(`ready-state-changed`,()=>this._handleReadyStateChange())}get label(){return this._native.label}get ordered(){return this._native.ordered}get protocol(){return this._native.protocol}get negotiated(){return this._native.negotiated}get id(){return this._native.id>=0?this._native.id:null}get maxPacketLifeTime(){let e=this._native.max_packet_lifetime;return e>=0?e:null}get maxRetransmits(){let e=this._native.max_retransmits;return e>=0?e:null}get readyState(){return this._closed?`closed`:o[this._native.ready_state]??`connecting`}get bufferedAmount(){try{return Number(this._native.buffered_amount)||this._bufferedAmount}catch{return this._bufferedAmount}}get bufferedAmountLowThreshold(){return Number(this._native.buffered_amount_low_threshold)||0}set bufferedAmountLowThreshold(e){this._native.buffered_amount_low_threshold=e}get binaryType(){return this._binaryType}set binaryType(e){e!==`arraybuffer`&&e!==`blob`||(this._binaryType=e)}get onopen(){return this._onopen}set onopen(e){this._onopen=e}get onclose(){return this._onclose}set onclose(e){this._onclose=e}get onclosing(){return this._onclosing}set onclosing(e){this._onclosing=e}get onerror(){return this._onerror}set onerror(e){this._onerror=e}get onmessage(){return this._onmessage}set onmessage(e){this._onmessage=e}get onbufferedamountlow(){return this._onbufferedamountlow}set onbufferedamountlow(e){this._onbufferedamountlow=e}send(e){let t=this.readyState;if(t!==`open`)throw new n(`RTCDataChannel.send: readyState is '${t}', expected 'open'`,`InvalidStateError`);if(typeof e==`string`){this._native.send_string(e),this._bufferedAmount+=new TextEncoder().encode(e).byteLength;return}if(e instanceof a){e.arrayBuffer().then(e=>{try{this._native.send_data(toGBytes(e)),this._bufferedAmount+=e.byteLength}catch{}});return}if(ArrayBuffer.isView(e)){let t=toGBytes(e);this._native.send_data(t),this._bufferedAmount+=e.byteLength;return}if(e instanceof ArrayBuffer){let t=toGBytes(e);this._native.send_data(t),this._bufferedAmount+=e.byteLength;return}throw TypeError(`RTCDataChannel.send: unsupported data type`)}close(){if(!this._closed){try{this._native.close()}catch{}this._disconnectSignals(),this._closed=!0}}_disconnectSignals(){try{this._bridge.dispose_bridge()}catch{}}_handleOpen(){let e=new Event(`open`);this._onopen?.call(this,e),this.dispatchEvent(e)}_handleClose(){this._closed=!0;let e=new Event(`close`);this._onclose?.call(this,e),this.dispatchEvent(e)}_handleError(n){let r=new t(`error`,{error:new e({errorDetail:`data-channel-failure`},n||`RTCDataChannel error`)});this._onerror?.call(this,r),this.dispatchEvent(r)}_handleString(e){let t=new MessageEvent(`message`,{data:e});this._onmessage?.call(this,t),this.dispatchEvent(t)}_handleData(e){if(!e)return;let t=bytesToArrayBuffer(e),n=this._binaryType===`blob`?new a([t]):t,r=new MessageEvent(`message`,{data:n});this._onmessage?.call(this,r),this.dispatchEvent(r)}_handleBufferedAmountLow(){this._bufferedAmount=Number(this._native.buffered_amount)||0;let e=new Event(`bufferedamountlow`);this._onbufferedamountlow?.call(this,e),this.dispatchEvent(e)}_handleReadyStateChange(){if(this.readyState===`closing`){let e=new Event(`closing`);this._onclosing?.call(this,e),this.dispatchEvent(e)}}};export{RTCDataChannel};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"../_virtual/_rolldown/runtime.js";import{Gst as e}from"../gst-init.js";import{withGstPromise as t}from"../gst-utils.js";import{RTCSessionDescription as n}from"../rtc-session-description.js";import{DOMException as r}from"@gjsify/dom-exception";const i={async createOffer(r){this._rejectIfClosed(`createOffer`);let i=e.Structure.new_empty(`offer-options`);this._iceRestartNeeded&&=(this._setStructureField(i,`ice-restart`,`boolean`,!0),!1);let a=(await t(e=>{this._webrtcbin.emit(`create-offer`,i,e)})).get_value(`offer`);return n.fromGstDesc(a).toJSON()},async createAnswer(r){this._rejectIfClosed(`createAnswer`);let i=e.Structure.new_empty(`answer-options`),a=(await t(e=>{this._webrtcbin.emit(`create-answer`,i,e)})).get_value(`answer`);return n.fromGstDesc(a).toJSON()},async setLocalDescription(i){if(this._rejectIfClosed(`setLocalDescription`),!i||!i.type||!i.sdp){let e=this.signalingState;if(e===`stable`||e===`have-local-offer`)i=await this.createOffer();else if(e===`have-remote-offer`||e===`have-remote-pranswer`)i=await this.createAnswer();else throw new r(`setLocalDescription: cannot auto-create SDP in signalingState '${e}'`,`InvalidStateError`)}this._pipeline.set_state(e.State.PLAYING);let a=new n(i).toGstDesc();await t(e=>{this._webrtcbin.emit(`set-local-description`,a,e)})},async setRemoteDescription(r){if(this._rejectIfClosed(`setRemoteDescription`),!r||!r.sdp||!r.type)throw TypeError(`setRemoteDescription requires an RTCSessionDescriptionInit with sdp and type`);this._pipeline.set_state(e.State.PLAYING);let i=new n(r).toGstDesc();await t(e=>{this._webrtcbin.emit(`set-remote-description`,i,e)}),this.signalingState===`stable`&&(this._hasNegotiated=!0)},async addIceCandidate(e){if(this._rejectIfClosed(`addIceCandidate`),!e)return;let{candidate:t,sdpMLineIndex:n}=e;typeof t!=`string`||typeof n!=`number`||this._webrtcbin.emit(`add-ice-candidate`,n,t)}};function installSdpNegotiationMethods(e){Object.assign(e,i)}export{installSdpNegotiationMethods};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./_virtual/_rolldown/runtime.js";import{Gst as e,ensureWebrtcbinAvailable as t}from"./gst-init.js";import{MediaStreamTrack as n}from"./media-stream-track.js";import{MediaStream as r}from"./media-stream.js";import{gstToConnectionState as i,gstToIceConnectionState as a,gstToIceGatheringState as o,gstToSignalingState as s,w3cDirectionToGst as c}from"./gst-enum-maps.js";import{filterStatsByTrackId as l,parseGstStats as u}from"./gst-stats-parser.js";import{withGstPromise as d}from"./gst-utils.js";import{asWebRtcBin as f,asWebRtcSrcPad as p}from"./internal/gst-types.js";import{RTCSessionDescription as m}from"./rtc-session-description.js";import{RTCIceCandidate as h}from"./rtc-ice-candidate.js";import{RTCDataChannelEvent as g,RTCPeerConnectionIceEvent as _}from"./rtc-events.js";import{RTCDataChannel as v}from"./rtc-data-channel.js";import{RTCRtpSender as y}from"./rtc-rtp-sender.js";import{RTCRtpReceiver as b}from"./rtc-rtp-receiver.js";import{RTCRtpTransceiver as x}from"./rtc-rtp-transceiver.js";import{RTCTrackEvent as S}from"./rtc-track-event.js";import{RTCIceTransport as C}from"./rtc-ice-transport.js";import{RTCDtlsTransport as w}from"./rtc-dtls-transport.js";import{RTCSctpTransport as T}from"./rtc-sctp-transport.js";import{RTCCertificate as E,generateCertificate as D}from"./rtc-certificate.js";import{DOMException as O}from"@gjsify/dom-exception";import k from"gi://GLib?version=2.0";import A from"gi://GstWebRTC?version=1.0";import{WebrtcbinBridge as j}from"@gjsify/webrtc-native";import M from"gi://GObject?version=2.0";function coerceUnsignedShort(e,t){let n=Number(t);if(!Number.isFinite(n))throw TypeError(`createDataChannel: ${e} must be a finite number, got ${String(t)}`);let r=Math.trunc(n);if(r<0||r>65535)throw TypeError(`createDataChannel: ${e}=${r} is outside the [0, 65535] range`);return r}let N=0;var RTCPeerConnection=class extends EventTarget{_pipeline;_webrtcbin;_bridge;_conf;_closed=!1;_iceRestartNeeded=!1;_hasNegotiated=!1;_dataChannels=new Map;_transceivers=new Map;_senders=[];_receivers=[];_iceTransport=null;_dtlsTransport=null;_sctpTransport=null;canTrickleIceCandidates=!0;constructor(n){super(),t();let[r,i]=e.version();if(r<1||r===1&&i<20)throw new O(`@gjsify/webrtc requires GStreamer >= 1.20 (you have ${r}.${i}). webrtcbin is only stable from 1.20 onward.`,`NotSupportedError`);let a=++N;this._pipeline=new e.Pipeline({name:`gjsify-webrtc-pipeline-${a}`});let o=e.ElementFactory.make(`webrtcbin`,`gjsify-webrtcbin-${a}`);if(!o)throw Error(`Failed to create webrtcbin element`);if(this._webrtcbin=o,this._conf={...n},n?.certificates){for(let e of n.certificates)if(e instanceof E&&e.expires<=Date.now())throw new O(`RTCPeerConnection: one of the provided certificates has expired`,`InvalidAccessError`)}this._applyIceServers(n?.iceServers??[]),this._applyIceTransportPolicy(n?.iceTransportPolicy),this._applyBundlePolicy(n?.bundlePolicy),this._pipeline.add(this._webrtcbin),this._bridge=new j({bin:this._webrtcbin}),this._bridge.connect(`negotiation-needed`,()=>this._handleNegotiationNeeded()),this._bridge.connect(`icecandidate`,(e,t,n)=>this._handleIceCandidate(t,n)),this._bridge.connect(`datachannel`,(e,t)=>this._handleDataChannel(t)),this._bridge.connect(`new-transceiver`,(e,t)=>this._handleNewTransceiver(t)),this._bridge.connect(`pad-added`,(e,t)=>this._handlePadAdded(t)),this._bridge.connect(`connection-state-changed`,()=>this._dispatchStateChange(`connectionstatechange`)),this._bridge.connect(`ice-connection-state-changed`,()=>this._dispatchStateChange(`iceconnectionstatechange`)),this._bridge.connect(`ice-gathering-state-changed`,()=>this._dispatchStateChange(`icegatheringstatechange`)),this._bridge.connect(`signaling-state-changed`,()=>this._dispatchStateChange(`signalingstatechange`)),this._pipeline.set_state(e.State.PLAYING)}_applyIceServers(e){let t=!1;for(let n of e){let e=Array.isArray(n.urls)?n.urls:[n.urls];if(e.length===0)throw SyntaxError(`RTCIceServer.urls must not be empty`);for(let r of e){if(typeof r!=`string`||r.length===0)throw TypeError(`RTCIceServer.urls entries must be non-empty strings`);let e=r.indexOf(`:`);if(e<0)throw TypeError(`Invalid ICE server URL "${r}"`);let i=r.slice(0,e+1),a=r.slice(e+1);if(i===`stun:`||i===`stuns:`){if(t)continue;f(this._webrtcbin).stun_server=`${i}//${a}`,t=!0}else if(i===`turn:`||i===`turns:`){if(typeof n.username!=`string`||typeof n.credential!=`string`)throw TypeError(`TURN server credential for ${r} missing`);let e=`${i}//${encodeURIComponent(n.username)}:${encodeURIComponent(n.credential)}@${a}`;try{this._webrtcbin.emit(`add-turn-server`,e)}catch{f(this._webrtcbin).turn_server=e}}else throw TypeError(`Unsupported ICE server protocol "${i}"`)}}}_applyIceTransportPolicy(e){if(!e)return;let t=e===`relay`?A.WebRTCICETransportPolicy.RELAY:A.WebRTCICETransportPolicy.ALL;try{f(this._webrtcbin).ice_transport_policy=t}catch{}}_applyBundlePolicy(e){if(!e)return;let t;switch(e){case`balanced`:t=A.WebRTCBundlePolicy.BALANCED;break;case`max-compat`:t=A.WebRTCBundlePolicy.MAX_COMPAT;break;case`max-bundle`:t=A.WebRTCBundlePolicy.MAX_BUNDLE;break;default:return}try{f(this._webrtcbin).bundle_policy=t}catch{}}get signalingState(){if(this._closed)return`closed`;try{return s(f(this._webrtcbin).signaling_state)}catch{return`stable`}}get connectionState(){if(this._closed)return`closed`;try{return i(f(this._webrtcbin).connection_state)}catch{return`new`}}get iceConnectionState(){if(this._closed)return`closed`;try{return a(f(this._webrtcbin).ice_connection_state)}catch{return`new`}}get iceGatheringState(){try{return o(f(this._webrtcbin).ice_gathering_state)}catch{return`new`}}_descProp(e){try{let t=f(this._webrtcbin)[e];return t?m.fromGstDesc(t):null}catch{return null}}get localDescription(){return this._descProp(`local_description`)}get remoteDescription(){return this._descProp(`remote_description`)}get currentLocalDescription(){return this._descProp(`current_local_description`)}get currentRemoteDescription(){return this._descProp(`current_remote_description`)}get pendingLocalDescription(){return this._descProp(`pending_local_description`)}get pendingRemoteDescription(){return this._descProp(`pending_remote_description`)}get sctp(){return this._sctpTransport}get peerIdentity(){return Promise.reject(TypeError(`peerIdentity assertions are not implemented`))}get idpErrorInfo(){return null}get idpLoginUrl(){return null}_rejectIfClosed(e){if(this._closed)throw new O(`RTCPeerConnection.${e}: connection is closed`,`InvalidStateError`)}async createOffer(t){this._rejectIfClosed(`createOffer`);let n=e.Structure.new_empty(`offer-options`);this._iceRestartNeeded&&=(this._setStructureField(n,`ice-restart`,`boolean`,!0),!1);let r=(await d(e=>{this._webrtcbin.emit(`create-offer`,n,e)})).get_value(`offer`);return m.fromGstDesc(r).toJSON()}async createAnswer(t){this._rejectIfClosed(`createAnswer`);let n=e.Structure.new_empty(`answer-options`),r=(await d(e=>{this._webrtcbin.emit(`create-answer`,n,e)})).get_value(`answer`);return m.fromGstDesc(r).toJSON()}async setLocalDescription(t){if(this._rejectIfClosed(`setLocalDescription`),!t||!t.type||!t.sdp){let e=this.signalingState;if(e===`stable`||e===`have-local-offer`)t=await this.createOffer();else if(e===`have-remote-offer`||e===`have-remote-pranswer`)t=await this.createAnswer();else throw new O(`setLocalDescription: cannot auto-create SDP in signalingState '${e}'`,`InvalidStateError`)}this._pipeline.set_state(e.State.PLAYING);let n=new m(t).toGstDesc();await d(e=>{this._webrtcbin.emit(`set-local-description`,n,e)})}async setRemoteDescription(t){if(this._rejectIfClosed(`setRemoteDescription`),!t||!t.sdp||!t.type)throw TypeError(`setRemoteDescription requires an RTCSessionDescriptionInit with sdp and type`);this._pipeline.set_state(e.State.PLAYING);let n=new m(t).toGstDesc();await d(e=>{this._webrtcbin.emit(`set-remote-description`,n,e)}),this.signalingState===`stable`&&(this._hasNegotiated=!0)}async addIceCandidate(e){if(this._rejectIfClosed(`addIceCandidate`),!e)return;let{candidate:t,sdpMLineIndex:n}=e;typeof t!=`string`||typeof n!=`number`||this._webrtcbin.emit(`add-ice-candidate`,n,t)}createDataChannel(t,n={}){if(this._closed)throw new O(`Cannot create a data channel on a closed RTCPeerConnection`,`InvalidStateError`);if(typeof t!=`string`)throw TypeError(`createDataChannel: label must be a string`);if(new TextEncoder().encode(t).byteLength>65535)throw TypeError(`createDataChannel: label too long (> 65535 bytes)`);let r=n.maxPacketLifeTime==null?void 0:coerceUnsignedShort(`maxPacketLifeTime`,n.maxPacketLifeTime),i=n.maxRetransmits==null?void 0:coerceUnsignedShort(`maxRetransmits`,n.maxRetransmits),a=n.id==null?void 0:coerceUnsignedShort(`id`,n.id);if(r!==void 0&&i!==void 0)throw TypeError(`createDataChannel: maxPacketLifeTime and maxRetransmits are mutually exclusive`);if(n.negotiated===!0&&a===void 0)throw TypeError(`createDataChannel: negotiated=true requires an id`);if(a===65535)throw TypeError(`createDataChannel: id 65535 is reserved`);let o=e.Structure.new_empty(`data-channel-opts`);this._setStructureField(o,`ordered`,`boolean`,n.ordered),this._setStructureField(o,`max-packet-lifetime`,`int`,r),this._setStructureField(o,`max-retransmits`,`int`,i),this._setStructureField(o,`protocol`,`string`,n.protocol),this._setStructureField(o,`negotiated`,`boolean`,n.negotiated),this._setStructureField(o,`id`,`int`,a);let s=null;try{s=this._webrtcbin.emit(`create-data-channel`,t,o)}catch(e){throw Error(`create-data-channel failed: ${e?.message??e}`)}if(!s)throw Error(`webrtcbin returned null data channel (check id/label/options)`);this._ensureSctpTransport();let c=new v(s);return this._dataChannels.set(s,c),c.addEventListener(`close`,()=>{this._dataChannels.delete(s)}),c}_setStructureField(e,t,n,r){if(r==null)return;let i=new M.Value;n===`boolean`?(i.init(M.TYPE_BOOLEAN),i.set_boolean(!!r)):n===`int`?(i.init(M.TYPE_INT),i.set_int(Number(r))):n===`string`&&(i.init(M.TYPE_STRING),i.set_string(String(r))),e.set_value(t,i),i.unset()}getConfiguration(){return{...this._conf}}close(){this._closed||(this._closed=!0,k.idle_add(k.PRIORITY_DEFAULT,()=>{try{this._pipeline.set_state(e.State.NULL)}catch{}for(let e of this._dataChannels.values())try{e._disconnectSignals()}catch{}this._dataChannels.clear();for(let e of this._senders)try{e._teardownPipeline()}catch{}for(let e of this._receivers)try{e._dispose()}catch{}this._transceivers.clear(),this._senders.length=0,this._receivers.length=0,this._dtlsTransport&&this._dtlsTransport._setState(`closed`),this._iceTransport&&this._iceTransport._setState(`closed`),this._sctpTransport&&this._sctpTransport._setState(`closed`);try{this._bridge.dispose_bridge()}catch{}return k.SOURCE_REMOVE}))}addTransceiver(t,r){this._rejectIfClosed(`addTransceiver`);let i;if(typeof t==`string`){if(t!==`audio`&&t!==`video`)throw TypeError(`Failed to execute 'addTransceiver' on 'RTCPeerConnection': The provided value '${t}' is not a valid enum value of type MediaStreamTrackKind.`);i=t}else if(t instanceof n)i=t.kind;else throw TypeError(`Failed to execute 'addTransceiver' on 'RTCPeerConnection': parameter 1 is not of type 'MediaStreamTrack' or a valid MediaStreamTrackKind.`);if(r?.sendEncodings){let e=new Set;for(let t of r.sendEncodings){if(t.rid!==void 0){if(typeof t.rid!=`string`||t.rid.length===0||t.rid.length>16||!/^[a-zA-Z0-9]+$/.test(t.rid))throw TypeError(`Invalid RID value: ${t.rid}`);if(e.has(t.rid))throw TypeError(`Duplicate RID: ${t.rid}`);e.add(t.rid)}if(t.scaleResolutionDownBy!==void 0&&t.scaleResolutionDownBy<1)throw RangeError(`scaleResolutionDownBy must be >= 1.0`)}}let a=r?.direction??`sendrecv`;if(![`sendrecv`,`sendonly`,`recvonly`,`inactive`].includes(a))throw TypeError(`Failed to execute 'addTransceiver' on 'RTCPeerConnection': The provided value '${a}' is not a valid enum value of type RTCRtpTransceiverDirection.`);let o=t instanceof n&&t._gstSource,s=a===`sendrecv`||a===`sendonly`,l,u;if(o&&s){let e=t,n=new y(null,this._pipeline,this._webrtcbin);n._kind=i,n._onPipelineChanged=e=>{this._pipeline=e},n._setTrack(e),n._wirePipeline(e);let r=this._findNewGstTransceiver();if(!r)throw Error(`webrtcbin did not create a transceiver for the send pad`);l=r;let o=l.receiver??null,s=new b(i,o,this._pipeline),statsDelegate=e=>this.getStats(e);n._getStatsForTrack=statsDelegate,s._getStatsForTrack=statsDelegate;let d=this._ensureTransports();n._transport=d,s._transport=d,u=new x(l,n,s),n._transceiver=u,this._transceivers.set(l,u),this._senders.push(n),this._receivers.push(s),l.direction=c(a)}else{let r=e.Caps.from_string(`application/x-rtp,media=${i}`),o=c(a===`inactive`?`sendrecv`:a),s=this._webrtcbin.emit(`add-transceiver`,o,r);if(!s)throw Error(`webrtcbin did not create a transceiver`);l=s,u=this._transceivers.get(l),u||=this._createTransceiverWrapper(l),l.direction=c(a),t instanceof n&&u.sender._setTrack(t)}return u}addTrack(e,...t){if(this._rejectIfClosed(`addTrack`),!(e instanceof n))throw TypeError(`Failed to execute 'addTrack' on 'RTCPeerConnection': parameter 1 is not a MediaStreamTrack`);if(this._senders.find(t=>t.track===e))throw new O(`Track already exists in a sender of this connection`,`InvalidAccessError`);let r;for(let t of this._transceivers.values())if(t.sender.track===null&&!t.stopped&&t.direction!==`stopped`&&t.receiver.track.kind===e.kind){let e=t.direction;if(e===`recvonly`||e===`inactive`){r=t;break}}if(r){let t=r.direction;return r.direction=t===`recvonly`?`sendrecv`:`sendonly`,r.sender._setTrack(e),r.sender}return this.addTransceiver(e,{direction:`sendrecv`}).sender}removeTrack(e){if(this._rejectIfClosed(`removeTrack`),!this._senders.includes(e))throw new O(`sender was not created by this connection`,`InvalidAccessError`);e._setTrack(null)}getSenders(){return[...this._senders]}getReceivers(){return[...this._receivers]}getTransceivers(){return[...this._transceivers.values()]}async getStats(e){if(this._rejectIfClosed(`getStats`),e!=null&&e instanceof n){let t=this._senders.some(t=>t.track===e),n=this._receivers.some(t=>t.track===e);if(!t&&!n)throw new O(`The selector track is not associated with a sender or receiver of this connection`,`InvalidAccessError`)}let t=u(await d(e=>{this._webrtcbin.emit(`get-stats`,null,e)}));return e!=null&&e instanceof n?l(t,e.id):t}restartIce(){this._closed||(this._iceRestartNeeded=!0,this._hasNegotiated&&Promise.resolve().then(()=>{this._closed||this._handleNegotiationNeeded()}))}setConfiguration(e){if(this._rejectIfClosed(`setConfiguration`),e.bundlePolicy&&e.bundlePolicy!==(this._conf.bundlePolicy??`balanced`))throw new O(`setConfiguration: bundlePolicy cannot be changed`,`InvalidModificationError`);if(e.rtcpMuxPolicy&&e.rtcpMuxPolicy!==(this._conf.rtcpMuxPolicy??`require`))throw new O(`setConfiguration: rtcpMuxPolicy cannot be changed`,`InvalidModificationError`);e.iceServers&&this._applyIceServers(e.iceServers),e.iceTransportPolicy&&this._applyIceTransportPolicy(e.iceTransportPolicy),this._conf={...this._conf,...e}}getIdentityAssertion(){return Promise.reject(Error(`getIdentityAssertion is not implemented`))}_findNewGstTransceiver(){for(let e=0;;e++){let t=this._webrtcbin.emit(`get-transceiver`,e);if(!t)return null;if(!this._transceivers.has(t))return t}}_ensureTransports(){return this._dtlsTransport||=(this._iceTransport=new C,new w(this._iceTransport)),this._dtlsTransport}_ensureSctpTransport(){if(this._sctpTransport)return;let e=this._ensureTransports();this._sctpTransport=new T(e)}_createTransceiverWrapper(e){let t=`audio`;try{e.kind===A.WebRTCKind.VIDEO&&(t=`video`)}catch{}let n=e.receiver??null,r=e.sender??null,i=new b(t,n,this._pipeline),a=new y(r,this._pipeline,this._webrtcbin);a._kind=t,a._onPipelineChanged=e=>{this._pipeline=e};let statsDelegate=e=>this.getStats(e);a._getStatsForTrack=statsDelegate,i._getStatsForTrack=statsDelegate;let o=this._ensureTransports();a._transport=o,i._transport=o;try{let t=e.mlineindex;typeof t==`number`&&t>=0&&a._setMlineIndex(t)}catch{}let s=new x(e,a,i);return a._transceiver=s,this._transceivers.set(e,s),this._senders.push(a),this._receivers.push(i),s}_handleNegotiationNeeded(){let e=new Event(`negotiationneeded`);this._onnegotiationneeded?.call(this,e),this.dispatchEvent(e)}_handleIceCandidate(e,t){let n=new _(`icecandidate`,{candidate:new h({candidate:t,sdpMLineIndex:e})});this._onicecandidate?.call(this,n),this.dispatchEvent(n)}_handleNewTransceiver(e){this._closed||this._transceivers.has(e)||this._createTransceiverWrapper(e)}_handlePadAdded(t){if(this._closed||t.direction!==e.PadDirection.SRC)return;let n=p(t).transceiver;if(!n)return;let i=this._transceivers.get(n);i||=this._createTransceiverWrapper(n),i.receiver._connectToPad(t);let a=new r([i.receiver.track]),o=new S(`track`,{receiver:i.receiver,track:i.receiver.track,streams:[a],transceiver:i});this._ontrack?.call(this,o),this.dispatchEvent(o)}_handleDataChannel(e){this._ensureSctpTransport();let t=e.channel,n=this._dataChannels.get(t);n||(n=new v(e),this._dataChannels.set(t,n),n.addEventListener(`close`,()=>{this._dataChannels.delete(t)}));let r=new g(`datachannel`,{channel:n});this._ondatachannel?.call(this,r),this.dispatchEvent(r)}_dispatchStateChange(e){e===`connectionstatechange`?this._syncDtlsState():e===`iceconnectionstatechange`?this._syncIceState():e===`icegatheringstatechange`&&this._syncIceGatheringState();let t=new Event(e);switch(e){case`connectionstatechange`:this._onconnectionstatechange?.call(this,t);break;case`iceconnectionstatechange`:this._oniceconnectionstatechange?.call(this,t);break;case`icegatheringstatechange`:this._onicegatheringstatechange?.call(this,t);break;case`signalingstatechange`:this._onsignalingstatechange?.call(this,t);break}this.dispatchEvent(t)}_syncDtlsState(){if(!this._dtlsTransport)return;let e=this.connectionState;this._dtlsTransport._setState({new:`new`,connecting:`connecting`,connected:`connected`,disconnected:`connected`,failed:`failed`,closed:`closed`}[e]??`new`),e===`connected`&&this._sctpTransport&&this._sctpTransport._setState(`connected`)}_syncIceState(){if(!this._iceTransport)return;let e=this.iceConnectionState;this._iceTransport._setState(e)}_syncIceGatheringState(){if(!this._iceTransport)return;let e=this.iceGatheringState;this._iceTransport._setGatheringState(e)}_onconnectionstatechange=null;_ondatachannel=null;_onicecandidate=null;_oniceconnectionstatechange=null;_onicegatheringstatechange=null;_onnegotiationneeded=null;_onsignalingstatechange=null;get onconnectionstatechange(){return this._onconnectionstatechange}set onconnectionstatechange(e){this._onconnectionstatechange=e}get ondatachannel(){return this._ondatachannel}set ondatachannel(e){this._ondatachannel=e}get onicecandidate(){return this._onicecandidate}set onicecandidate(e){this._onicecandidate=e}get oniceconnectionstatechange(){return this._oniceconnectionstatechange}set oniceconnectionstatechange(e){this._oniceconnectionstatechange=e}get onicegatheringstatechange(){return this._onicegatheringstatechange}set onicegatheringstatechange(e){this._onicegatheringstatechange=e}get onnegotiationneeded(){return this._onnegotiationneeded}set onnegotiationneeded(e){this._onnegotiationneeded=e}get onsignalingstatechange(){return this._onsignalingstatechange}set onsignalingstatechange(e){this._onsignalingstatechange=e}_ontrack=null;get ontrack(){return this._ontrack}set ontrack(e){this._ontrack=e}get onicecandidateerror(){return null}set onicecandidateerror(e){}static generateCertificate(e){return D(e)}};export{RTCPeerConnection};
|
|
1
|
+
import"./_virtual/_rolldown/runtime.js";import{Gst as e,ensureWebrtcbinAvailable as t}from"./gst-init.js";import{MediaStreamTrack as n}from"./media-stream-track.js";import{MediaStream as r}from"./media-stream.js";import{gstToConnectionState as i,gstToIceConnectionState as a,gstToIceGatheringState as o,gstToSignalingState as s,w3cDirectionToGst as c}from"./gst-enum-maps.js";import{filterStatsByTrackId as l,parseGstStats as u}from"./gst-stats-parser.js";import{withGstPromise as d}from"./gst-utils.js";import{asWebRtcBin as f,asWebRtcSrcPad as p}from"./internal/gst-types.js";import{RTCSessionDescription as m}from"./rtc-session-description.js";import{RTCIceCandidate as h}from"./rtc-ice-candidate.js";import{RTCDataChannelEvent as g,RTCPeerConnectionIceEvent as _}from"./rtc-events.js";import{RTCDataChannel as v}from"./rtc-data-channel.js";import{RTCRtpSender as y}from"./rtc-rtp-sender.js";import{RTCRtpReceiver as b}from"./rtc-rtp-receiver.js";import{RTCRtpTransceiver as x}from"./rtc-rtp-transceiver.js";import{RTCTrackEvent as S}from"./rtc-track-event.js";import{RTCIceTransport as C}from"./rtc-ice-transport.js";import{RTCDtlsTransport as w}from"./rtc-dtls-transport.js";import{RTCSctpTransport as T}from"./rtc-sctp-transport.js";import{RTCCertificate as E,generateCertificate as D}from"./rtc-certificate.js";import{installSdpNegotiationMethods as O}from"./rtc-peer-connection/sdp-negotiation.js";import{DOMException as k}from"@gjsify/dom-exception";import A from"gi://GLib?version=2.0";import j from"gi://GstWebRTC?version=1.0";import{WebrtcbinBridge as M}from"@gjsify/webrtc-native";import N from"gi://GObject?version=2.0";function coerceUnsignedShort(e,t){let n=Number(t);if(!Number.isFinite(n))throw TypeError(`createDataChannel: ${e} must be a finite number, got ${String(t)}`);let r=Math.trunc(n);if(r<0||r>65535)throw TypeError(`createDataChannel: ${e}=${r} is outside the [0, 65535] range`);return r}let P=0;var RTCPeerConnection=class extends EventTarget{_pipeline;_webrtcbin;_bridge;_conf;_closed=!1;_iceRestartNeeded=!1;_hasNegotiated=!1;_dataChannels=new Map;_transceivers=new Map;_senders=[];_receivers=[];_iceTransport=null;_dtlsTransport=null;_sctpTransport=null;canTrickleIceCandidates=!0;constructor(n){super(),t();let[r,i]=e.version();if(r<1||r===1&&i<20)throw new k(`@gjsify/webrtc requires GStreamer >= 1.20 (you have ${r}.${i}). webrtcbin is only stable from 1.20 onward.`,`NotSupportedError`);let a=++P;this._pipeline=new e.Pipeline({name:`gjsify-webrtc-pipeline-${a}`});let o=e.ElementFactory.make(`webrtcbin`,`gjsify-webrtcbin-${a}`);if(!o)throw Error(`Failed to create webrtcbin element`);if(this._webrtcbin=o,this._conf={...n},n?.certificates){for(let e of n.certificates)if(e instanceof E&&e.expires<=Date.now())throw new k(`RTCPeerConnection: one of the provided certificates has expired`,`InvalidAccessError`)}this._applyIceServers(n?.iceServers??[]),this._applyIceTransportPolicy(n?.iceTransportPolicy),this._applyBundlePolicy(n?.bundlePolicy),this._pipeline.add(this._webrtcbin),this._bridge=new M({bin:this._webrtcbin}),this._bridge.connect(`negotiation-needed`,()=>this._handleNegotiationNeeded()),this._bridge.connect(`icecandidate`,(e,t,n)=>this._handleIceCandidate(t,n)),this._bridge.connect(`datachannel`,(e,t)=>this._handleDataChannel(t)),this._bridge.connect(`new-transceiver`,(e,t)=>this._handleNewTransceiver(t)),this._bridge.connect(`pad-added`,(e,t)=>this._handlePadAdded(t)),this._bridge.connect(`connection-state-changed`,()=>this._dispatchStateChange(`connectionstatechange`)),this._bridge.connect(`ice-connection-state-changed`,()=>this._dispatchStateChange(`iceconnectionstatechange`)),this._bridge.connect(`ice-gathering-state-changed`,()=>this._dispatchStateChange(`icegatheringstatechange`)),this._bridge.connect(`signaling-state-changed`,()=>this._dispatchStateChange(`signalingstatechange`)),this._pipeline.set_state(e.State.PLAYING)}_applyIceServers(e){let t=!1;for(let n of e){let e=Array.isArray(n.urls)?n.urls:[n.urls];if(e.length===0)throw SyntaxError(`RTCIceServer.urls must not be empty`);for(let r of e){if(typeof r!=`string`||r.length===0)throw TypeError(`RTCIceServer.urls entries must be non-empty strings`);let e=r.indexOf(`:`);if(e<0)throw TypeError(`Invalid ICE server URL "${r}"`);let i=r.slice(0,e+1),a=r.slice(e+1);if(i===`stun:`||i===`stuns:`){if(t)continue;f(this._webrtcbin).stun_server=`${i}//${a}`,t=!0}else if(i===`turn:`||i===`turns:`){if(typeof n.username!=`string`||typeof n.credential!=`string`)throw TypeError(`TURN server credential for ${r} missing`);let e=`${i}//${encodeURIComponent(n.username)}:${encodeURIComponent(n.credential)}@${a}`;try{this._webrtcbin.emit(`add-turn-server`,e)}catch{f(this._webrtcbin).turn_server=e}}else throw TypeError(`Unsupported ICE server protocol "${i}"`)}}}_applyIceTransportPolicy(e){if(!e)return;let t=e===`relay`?j.WebRTCICETransportPolicy.RELAY:j.WebRTCICETransportPolicy.ALL;try{f(this._webrtcbin).ice_transport_policy=t}catch{}}_applyBundlePolicy(e){if(!e)return;let t;switch(e){case`balanced`:t=j.WebRTCBundlePolicy.BALANCED;break;case`max-compat`:t=j.WebRTCBundlePolicy.MAX_COMPAT;break;case`max-bundle`:t=j.WebRTCBundlePolicy.MAX_BUNDLE;break;default:return}try{f(this._webrtcbin).bundle_policy=t}catch{}}get signalingState(){if(this._closed)return`closed`;try{return s(f(this._webrtcbin).signaling_state)}catch{return`stable`}}get connectionState(){if(this._closed)return`closed`;try{return i(f(this._webrtcbin).connection_state)}catch{return`new`}}get iceConnectionState(){if(this._closed)return`closed`;try{return a(f(this._webrtcbin).ice_connection_state)}catch{return`new`}}get iceGatheringState(){try{return o(f(this._webrtcbin).ice_gathering_state)}catch{return`new`}}_descProp(e){try{let t=f(this._webrtcbin)[e];return t?m.fromGstDesc(t):null}catch{return null}}get localDescription(){return this._descProp(`local_description`)}get remoteDescription(){return this._descProp(`remote_description`)}get currentLocalDescription(){return this._descProp(`current_local_description`)}get currentRemoteDescription(){return this._descProp(`current_remote_description`)}get pendingLocalDescription(){return this._descProp(`pending_local_description`)}get pendingRemoteDescription(){return this._descProp(`pending_remote_description`)}get sctp(){return this._sctpTransport}get peerIdentity(){return Promise.reject(TypeError(`peerIdentity assertions are not implemented`))}get idpErrorInfo(){return null}get idpLoginUrl(){return null}_rejectIfClosed(e){if(this._closed)throw new k(`RTCPeerConnection.${e}: connection is closed`,`InvalidStateError`)}createDataChannel(t,n={}){if(this._closed)throw new k(`Cannot create a data channel on a closed RTCPeerConnection`,`InvalidStateError`);if(typeof t!=`string`)throw TypeError(`createDataChannel: label must be a string`);if(new TextEncoder().encode(t).byteLength>65535)throw TypeError(`createDataChannel: label too long (> 65535 bytes)`);let r=n.maxPacketLifeTime==null?void 0:coerceUnsignedShort(`maxPacketLifeTime`,n.maxPacketLifeTime),i=n.maxRetransmits==null?void 0:coerceUnsignedShort(`maxRetransmits`,n.maxRetransmits),a=n.id==null?void 0:coerceUnsignedShort(`id`,n.id);if(r!==void 0&&i!==void 0)throw TypeError(`createDataChannel: maxPacketLifeTime and maxRetransmits are mutually exclusive`);if(n.negotiated===!0&&a===void 0)throw TypeError(`createDataChannel: negotiated=true requires an id`);if(a===65535)throw TypeError(`createDataChannel: id 65535 is reserved`);let o=e.Structure.new_empty(`data-channel-opts`);this._setStructureField(o,`ordered`,`boolean`,n.ordered),this._setStructureField(o,`max-packet-lifetime`,`int`,r),this._setStructureField(o,`max-retransmits`,`int`,i),this._setStructureField(o,`protocol`,`string`,n.protocol),this._setStructureField(o,`negotiated`,`boolean`,n.negotiated),this._setStructureField(o,`id`,`int`,a);let s=null;try{s=this._webrtcbin.emit(`create-data-channel`,t,o)}catch(e){throw Error(`create-data-channel failed: ${e?.message??e}`)}if(!s)throw Error(`webrtcbin returned null data channel (check id/label/options)`);this._ensureSctpTransport();let c=new v(s);return this._dataChannels.set(s,c),c.addEventListener(`close`,()=>{this._dataChannels.delete(s)}),c}_setStructureField(e,t,n,r){if(r==null)return;let i=new N.Value;n===`boolean`?(i.init(N.TYPE_BOOLEAN),i.set_boolean(!!r)):n===`int`?(i.init(N.TYPE_INT),i.set_int(Number(r))):n===`string`&&(i.init(N.TYPE_STRING),i.set_string(String(r))),e.set_value(t,i),i.unset()}getConfiguration(){return{...this._conf}}close(){this._closed||(this._closed=!0,A.idle_add(A.PRIORITY_DEFAULT,()=>{try{this._pipeline.set_state(e.State.NULL)}catch{}for(let e of this._dataChannels.values())try{e._disconnectSignals()}catch{}this._dataChannels.clear();for(let e of this._senders)try{e._teardownPipeline()}catch{}for(let e of this._receivers)try{e._dispose()}catch{}this._transceivers.clear(),this._senders.length=0,this._receivers.length=0,this._dtlsTransport&&this._dtlsTransport._setState(`closed`),this._iceTransport&&this._iceTransport._setState(`closed`),this._sctpTransport&&this._sctpTransport._setState(`closed`);try{this._bridge.dispose_bridge()}catch{}return A.SOURCE_REMOVE}))}addTransceiver(t,r){this._rejectIfClosed(`addTransceiver`);let i;if(typeof t==`string`){if(t!==`audio`&&t!==`video`)throw TypeError(`Failed to execute 'addTransceiver' on 'RTCPeerConnection': The provided value '${t}' is not a valid enum value of type MediaStreamTrackKind.`);i=t}else if(t instanceof n)i=t.kind;else throw TypeError(`Failed to execute 'addTransceiver' on 'RTCPeerConnection': parameter 1 is not of type 'MediaStreamTrack' or a valid MediaStreamTrackKind.`);if(r?.sendEncodings){let e=new Set;for(let t of r.sendEncodings){if(t.rid!==void 0){if(typeof t.rid!=`string`||t.rid.length===0||t.rid.length>16||!/^[a-zA-Z0-9]+$/.test(t.rid))throw TypeError(`Invalid RID value: ${t.rid}`);if(e.has(t.rid))throw TypeError(`Duplicate RID: ${t.rid}`);e.add(t.rid)}if(t.scaleResolutionDownBy!==void 0&&t.scaleResolutionDownBy<1)throw RangeError(`scaleResolutionDownBy must be >= 1.0`)}}let a=r?.direction??`sendrecv`;if(![`sendrecv`,`sendonly`,`recvonly`,`inactive`].includes(a))throw TypeError(`Failed to execute 'addTransceiver' on 'RTCPeerConnection': The provided value '${a}' is not a valid enum value of type RTCRtpTransceiverDirection.`);let o=t instanceof n&&t._gstSource,s=a===`sendrecv`||a===`sendonly`,l,u;if(o&&s){let e=t,n=new y(null,this._pipeline,this._webrtcbin);n._kind=i,n._onPipelineChanged=e=>{this._pipeline=e},n._setTrack(e),n._wirePipeline(e);let r=this._findNewGstTransceiver();if(!r)throw Error(`webrtcbin did not create a transceiver for the send pad`);l=r;let o=l.receiver??null,s=new b(i,o,this._pipeline),statsDelegate=e=>this.getStats(e);n._getStatsForTrack=statsDelegate,s._getStatsForTrack=statsDelegate;let d=this._ensureTransports();n._transport=d,s._transport=d,u=new x(l,n,s),n._transceiver=u,this._transceivers.set(l,u),this._senders.push(n),this._receivers.push(s),l.direction=c(a)}else{let r=e.Caps.from_string(`application/x-rtp,media=${i}`),o=c(a===`inactive`?`sendrecv`:a),s=this._webrtcbin.emit(`add-transceiver`,o,r);if(!s)throw Error(`webrtcbin did not create a transceiver`);l=s,u=this._transceivers.get(l),u||=this._createTransceiverWrapper(l),l.direction=c(a),t instanceof n&&u.sender._setTrack(t)}return u}addTrack(e,...t){if(this._rejectIfClosed(`addTrack`),!(e instanceof n))throw TypeError(`Failed to execute 'addTrack' on 'RTCPeerConnection': parameter 1 is not a MediaStreamTrack`);if(this._senders.find(t=>t.track===e))throw new k(`Track already exists in a sender of this connection`,`InvalidAccessError`);let r;for(let t of this._transceivers.values())if(t.sender.track===null&&!t.stopped&&t.direction!==`stopped`&&t.receiver.track.kind===e.kind){let e=t.direction;if(e===`recvonly`||e===`inactive`){r=t;break}}if(r){let t=r.direction;return r.direction=t===`recvonly`?`sendrecv`:`sendonly`,r.sender._setTrack(e),r.sender}return this.addTransceiver(e,{direction:`sendrecv`}).sender}removeTrack(e){if(this._rejectIfClosed(`removeTrack`),!this._senders.includes(e))throw new k(`sender was not created by this connection`,`InvalidAccessError`);e._setTrack(null)}getSenders(){return[...this._senders]}getReceivers(){return[...this._receivers]}getTransceivers(){return[...this._transceivers.values()]}async getStats(e){if(this._rejectIfClosed(`getStats`),e!=null&&e instanceof n){let t=this._senders.some(t=>t.track===e),n=this._receivers.some(t=>t.track===e);if(!t&&!n)throw new k(`The selector track is not associated with a sender or receiver of this connection`,`InvalidAccessError`)}let t=u(await d(e=>{this._webrtcbin.emit(`get-stats`,null,e)}));return e!=null&&e instanceof n?l(t,e.id):t}restartIce(){this._closed||(this._iceRestartNeeded=!0,this._hasNegotiated&&Promise.resolve().then(()=>{this._closed||this._handleNegotiationNeeded()}))}setConfiguration(e){if(this._rejectIfClosed(`setConfiguration`),e.bundlePolicy&&e.bundlePolicy!==(this._conf.bundlePolicy??`balanced`))throw new k(`setConfiguration: bundlePolicy cannot be changed`,`InvalidModificationError`);if(e.rtcpMuxPolicy&&e.rtcpMuxPolicy!==(this._conf.rtcpMuxPolicy??`require`))throw new k(`setConfiguration: rtcpMuxPolicy cannot be changed`,`InvalidModificationError`);e.iceServers&&this._applyIceServers(e.iceServers),e.iceTransportPolicy&&this._applyIceTransportPolicy(e.iceTransportPolicy),this._conf={...this._conf,...e}}getIdentityAssertion(){return Promise.reject(Error(`getIdentityAssertion is not implemented`))}_findNewGstTransceiver(){for(let e=0;;e++){let t=this._webrtcbin.emit(`get-transceiver`,e);if(!t)return null;if(!this._transceivers.has(t))return t}}_ensureTransports(){return this._dtlsTransport||=(this._iceTransport=new C,new w(this._iceTransport)),this._dtlsTransport}_ensureSctpTransport(){if(this._sctpTransport)return;let e=this._ensureTransports();this._sctpTransport=new T(e)}_createTransceiverWrapper(e){let t=`audio`;try{e.kind===j.WebRTCKind.VIDEO&&(t=`video`)}catch{}let n=e.receiver??null,r=e.sender??null,i=new b(t,n,this._pipeline),a=new y(r,this._pipeline,this._webrtcbin);a._kind=t,a._onPipelineChanged=e=>{this._pipeline=e};let statsDelegate=e=>this.getStats(e);a._getStatsForTrack=statsDelegate,i._getStatsForTrack=statsDelegate;let o=this._ensureTransports();a._transport=o,i._transport=o;try{let t=e.mlineindex;typeof t==`number`&&t>=0&&a._setMlineIndex(t)}catch{}let s=new x(e,a,i);return a._transceiver=s,this._transceivers.set(e,s),this._senders.push(a),this._receivers.push(i),s}_handleNegotiationNeeded(){let e=new Event(`negotiationneeded`);this._onnegotiationneeded?.call(this,e),this.dispatchEvent(e)}_handleIceCandidate(e,t){let n=new _(`icecandidate`,{candidate:new h({candidate:t,sdpMLineIndex:e})});this._onicecandidate?.call(this,n),this.dispatchEvent(n)}_handleNewTransceiver(e){this._closed||this._transceivers.has(e)||this._createTransceiverWrapper(e)}_handlePadAdded(t){if(this._closed||t.direction!==e.PadDirection.SRC)return;let n=p(t).transceiver;if(!n)return;let i=this._transceivers.get(n);i||=this._createTransceiverWrapper(n),i.receiver._connectToPad(t);let a=new r([i.receiver.track]),o=new S(`track`,{receiver:i.receiver,track:i.receiver.track,streams:[a],transceiver:i});this._ontrack?.call(this,o),this.dispatchEvent(o)}_handleDataChannel(e){this._ensureSctpTransport();let t=e.channel,n=this._dataChannels.get(t);n||(n=new v(e),this._dataChannels.set(t,n),n.addEventListener(`close`,()=>{this._dataChannels.delete(t)}));let r=new g(`datachannel`,{channel:n});this._ondatachannel?.call(this,r),this.dispatchEvent(r)}_dispatchStateChange(e){e===`connectionstatechange`?this._syncDtlsState():e===`iceconnectionstatechange`?this._syncIceState():e===`icegatheringstatechange`&&this._syncIceGatheringState();let t=new Event(e);switch(e){case`connectionstatechange`:this._onconnectionstatechange?.call(this,t);break;case`iceconnectionstatechange`:this._oniceconnectionstatechange?.call(this,t);break;case`icegatheringstatechange`:this._onicegatheringstatechange?.call(this,t);break;case`signalingstatechange`:this._onsignalingstatechange?.call(this,t);break}this.dispatchEvent(t)}_syncDtlsState(){if(!this._dtlsTransport)return;let e=this.connectionState;this._dtlsTransport._setState({new:`new`,connecting:`connecting`,connected:`connected`,disconnected:`connected`,failed:`failed`,closed:`closed`}[e]??`new`),e===`connected`&&this._sctpTransport&&this._sctpTransport._setState(`connected`)}_syncIceState(){if(!this._iceTransport)return;let e=this.iceConnectionState;this._iceTransport._setState(e)}_syncIceGatheringState(){if(!this._iceTransport)return;let e=this.iceGatheringState;this._iceTransport._setGatheringState(e)}_onconnectionstatechange=null;_ondatachannel=null;_onicecandidate=null;_oniceconnectionstatechange=null;_onicegatheringstatechange=null;_onnegotiationneeded=null;_onsignalingstatechange=null;get onconnectionstatechange(){return this._onconnectionstatechange}set onconnectionstatechange(e){this._onconnectionstatechange=e}get ondatachannel(){return this._ondatachannel}set ondatachannel(e){this._ondatachannel=e}get onicecandidate(){return this._onicecandidate}set onicecandidate(e){this._onicecandidate=e}get oniceconnectionstatechange(){return this._oniceconnectionstatechange}set oniceconnectionstatechange(e){this._oniceconnectionstatechange=e}get onicegatheringstatechange(){return this._onicegatheringstatechange}set onicegatheringstatechange(e){this._onicegatheringstatechange=e}get onnegotiationneeded(){return this._onnegotiationneeded}set onnegotiationneeded(e){this._onnegotiationneeded=e}get onsignalingstatechange(){return this._onsignalingstatechange}set onsignalingstatechange(e){this._onsignalingstatechange=e}_ontrack=null;get ontrack(){return this._ontrack}set ontrack(e){this._ontrack=e}get onicecandidateerror(){return null}set onicecandidateerror(e){}static generateCertificate(e){return D(e)}};O(RTCPeerConnection.prototype);export{RTCPeerConnection};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type RTCSessionDescriptionInit } from '../rtc-session-description.js';
|
|
2
|
+
import { RTCIceCandidate, type RTCIceCandidateInit } from '../rtc-ice-candidate.js';
|
|
3
|
+
import type { RTCOfferOptions, RTCAnswerOptions } from '../rtc-peer-connection.js';
|
|
4
|
+
export interface SdpNegotiationMethods {
|
|
5
|
+
createOffer(options?: RTCOfferOptions): Promise<RTCSessionDescriptionInit>;
|
|
6
|
+
createAnswer(options?: RTCAnswerOptions): Promise<RTCSessionDescriptionInit>;
|
|
7
|
+
setLocalDescription(description?: RTCSessionDescriptionInit): Promise<void>;
|
|
8
|
+
setRemoteDescription(description: RTCSessionDescriptionInit): Promise<void>;
|
|
9
|
+
addIceCandidate(candidate: RTCIceCandidateInit | RTCIceCandidate | null): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
declare module '../rtc-peer-connection.js' {
|
|
12
|
+
interface RTCPeerConnection extends SdpNegotiationMethods {
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/** Install SDP-negotiation methods on RTCPeerConnection.prototype. */
|
|
16
|
+
export declare function installSdpNegotiationMethods(proto: object): void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { Gst } from './gst-init.js';
|
|
2
|
+
import { RTCSessionDescription } from './rtc-session-description.js';
|
|
3
3
|
import { RTCDataChannel } from './rtc-data-channel.js';
|
|
4
4
|
import { RTCPeerConnectionIceEvent, RTCDataChannelEvent } from './rtc-events.js';
|
|
5
5
|
import { RTCRtpSender, type RTCRtpTransceiverDirection } from './rtc-rtp-sender.js';
|
|
@@ -61,13 +61,13 @@ export interface RTCRtpTransceiverInit {
|
|
|
61
61
|
}>;
|
|
62
62
|
}
|
|
63
63
|
export declare class RTCPeerConnection extends EventTarget {
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
_pipeline: Gst.Pipeline;
|
|
65
|
+
_webrtcbin: Gst.Element;
|
|
66
66
|
private _bridge;
|
|
67
67
|
private _conf;
|
|
68
68
|
private _closed;
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
_iceRestartNeeded: boolean;
|
|
70
|
+
_hasNegotiated: boolean;
|
|
71
71
|
private _dataChannels;
|
|
72
72
|
private _transceivers;
|
|
73
73
|
private _senders;
|
|
@@ -95,14 +95,9 @@ export declare class RTCPeerConnection extends EventTarget {
|
|
|
95
95
|
get peerIdentity(): Promise<never>;
|
|
96
96
|
get idpErrorInfo(): null;
|
|
97
97
|
get idpLoginUrl(): null;
|
|
98
|
-
|
|
99
|
-
createOffer(_options?: RTCOfferOptions): Promise<RTCSessionDescriptionInit>;
|
|
100
|
-
createAnswer(_options?: RTCAnswerOptions): Promise<RTCSessionDescriptionInit>;
|
|
101
|
-
setLocalDescription(description?: RTCSessionDescriptionInit): Promise<void>;
|
|
102
|
-
setRemoteDescription(description: RTCSessionDescriptionInit): Promise<void>;
|
|
103
|
-
addIceCandidate(candidate: RTCIceCandidateInit | RTCIceCandidate | null): Promise<void>;
|
|
98
|
+
_rejectIfClosed(method: string): void;
|
|
104
99
|
createDataChannel(label: string, options?: RTCDataChannelInit): RTCDataChannel;
|
|
105
|
-
|
|
100
|
+
_setStructureField(structure: Gst.Structure, name: string, type: 'boolean' | 'int' | 'string', value: unknown): void;
|
|
106
101
|
getConfiguration(): RTCConfiguration;
|
|
107
102
|
close(): void;
|
|
108
103
|
addTransceiver(trackOrKind: MediaStreamTrack | string, init?: RTCRtpTransceiverInit): RTCRtpTransceiver;
|
|
@@ -162,4 +157,6 @@ export declare class RTCPeerConnection extends EventTarget {
|
|
|
162
157
|
set onicecandidateerror(_v: EventHandler);
|
|
163
158
|
static generateCertificate(keygenAlgorithm: AlgorithmIdentifier): Promise<RTCCertificate>;
|
|
164
159
|
}
|
|
160
|
+
import './rtc-peer-connection/sdp-negotiation.js';
|
|
161
|
+
import './rtc-peer-connection/sdp-negotiation.js';
|
|
165
162
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/webrtc",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.23",
|
|
4
4
|
"description": "W3C WebRTC API for GJS using GStreamer webrtcbin as the peer-connection backend",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "lib/esm/index.js",
|
|
@@ -58,21 +58,21 @@
|
|
|
58
58
|
"peer-connection"
|
|
59
59
|
],
|
|
60
60
|
"dependencies": {
|
|
61
|
-
"@gjsify/buffer": "^0.4.
|
|
62
|
-
"@gjsify/dom-events": "^0.4.
|
|
63
|
-
"@gjsify/dom-exception": "^0.4.
|
|
64
|
-
"@gjsify/webrtc-native": "^0.4.
|
|
61
|
+
"@gjsify/buffer": "^0.4.23",
|
|
62
|
+
"@gjsify/dom-events": "^0.4.23",
|
|
63
|
+
"@gjsify/dom-exception": "^0.4.23",
|
|
64
|
+
"@gjsify/webrtc-native": "^0.4.23"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
|
-
"@girs/gjs": "4.0.
|
|
68
|
-
"@girs/glib-2.0": "2.88.0-4.0.
|
|
69
|
-
"@girs/gobject-2.0": "2.88.0-4.0.
|
|
70
|
-
"@girs/gst-1.0": "1.28.1-4.0.
|
|
71
|
-
"@girs/gstsdp-1.0": "1.0.0-4.0.
|
|
72
|
-
"@girs/gstwebrtc-1.0": "1.0.0-4.0.
|
|
73
|
-
"@gjsify/cli": "^0.4.
|
|
74
|
-
"@gjsify/unit": "^0.4.
|
|
75
|
-
"@types/node": "^25.
|
|
67
|
+
"@girs/gjs": "4.0.1",
|
|
68
|
+
"@girs/glib-2.0": "2.88.0-4.0.1",
|
|
69
|
+
"@girs/gobject-2.0": "2.88.0-4.0.1",
|
|
70
|
+
"@girs/gst-1.0": "1.28.1-4.0.1",
|
|
71
|
+
"@girs/gstsdp-1.0": "1.0.0-4.0.1",
|
|
72
|
+
"@girs/gstwebrtc-1.0": "1.0.0-4.0.1",
|
|
73
|
+
"@gjsify/cli": "^0.4.23",
|
|
74
|
+
"@gjsify/unit": "^0.4.23",
|
|
75
|
+
"@types/node": "^25.9.1",
|
|
76
76
|
"typescript": "^6.0.3"
|
|
77
77
|
}
|
|
78
78
|
}
|