@gjsify/webrtc 0.45.0 → 0.47.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.
@@ -1 +1 @@
1
- import"./_virtual/_rolldown/runtime.js";import{Gst as e,ensureGstInit as t}from"./gst-init.js";import{MediaStreamTrack as n}from"./media-stream-track.js";import{MediaStream as r}from"./media-stream.js";async function getUserMedia(i){if(t(),!i.audio&&!i.video)throw TypeError(`Failed to execute 'getUserMedia': At least one of audio or video must be requested`);let a=[];if(i.audio){let t=typeof i.audio==`object`?i.audio:{},r=_createAudioSource(),o=new e.Pipeline;o.add(r);let s=_buildAudioCaps(t);if(s){let t=e.ElementFactory.make(`capsfilter`,null);t.caps=e.Caps.from_string(s),o.add(t),r.link(t)}a.push(new n({kind:`audio`,label:r.name??`audio`,_gst:{source:r,pipeline:o}}))}if(i.video){let t=typeof i.video==`object`?i.video:{},r=_createVideoSource(),o=new e.Pipeline;o.add(r);let s=_buildVideoCaps(t);if(s){let t=e.ElementFactory.make(`capsfilter`,null);t.caps=e.Caps.from_string(s),o.add(t),r.link(t)}a.push(new n({kind:`video`,label:r.name??`video`,_gst:{source:r,pipeline:o}}))}return new r(a)}function _buildAudioCaps(e){let t=[];return e.sampleRate!=null&&t.push(`rate=${Math.trunc(e.sampleRate)}`),e.channelCount!=null&&t.push(`channels=${Math.trunc(e.channelCount)}`),t.length===0?null:`audio/x-raw,${t.join(`,`)}`}function _buildVideoCaps(e){let t=[];return e.width!=null&&t.push(`width=${Math.trunc(e.width)}`),e.height!=null&&t.push(`height=${Math.trunc(e.height)}`),e.frameRate!=null&&t.push(`framerate=${Math.trunc(e.frameRate)}/1`),t.length===0?null:`video/x-raw,${t.join(`,`)}`}function _createAudioSource(){for(let t of[`pipewiresrc`,`pulsesrc`,`autoaudiosrc`]){let n=e.ElementFactory.make(t,null);if(n){try{n.is_live=!0}catch{}return n}}let t=e.ElementFactory.make(`audiotestsrc`,null);return t.is_live=!0,t.wave=0,t}function _createVideoSource(){for(let t of[`pipewiresrc`,`v4l2src`,`autovideosrc`]){let n=e.ElementFactory.make(t,null);if(n)return n}let t=e.ElementFactory.make(`videotestsrc`,null);return t.is_live=!0,t.pattern=0,t}export{getUserMedia};
1
+ import"./_virtual/_rolldown/runtime.js";import{Gst as e,ensureGstInit as t}from"./gst-init.js";import{MediaStreamTrack as n}from"./media-stream-track.js";import{MediaStream as r}from"./media-stream.js";async function getUserMedia(i){if(t(),!i.audio&&!i.video)throw TypeError(`Failed to execute 'getUserMedia': At least one of audio or video must be requested`);let a=[];if(i.audio){let t=typeof i.audio==`object`?i.audio:{},r=_createAudioSource(),o=new e.Pipeline;o.add(r);let s=_buildAudioCaps(t);if(s){let t=e.ElementFactory.make(`capsfilter`,null);t.caps=e.Caps.from_string(s),o.add(t),r.link(t)}a.push(new n({kind:`audio`,label:r.name??`audio`,_gst:{source:r,pipeline:o}}))}if(i.video){let t=typeof i.video==`object`?i.video:{},r=_createVideoSource(),o=new e.Pipeline;o.add(r);let s=_buildVideoCaps(t);if(s){let t=e.ElementFactory.make(`capsfilter`,null);t.caps=e.Caps.from_string(s),o.add(t),r.link(t)}a.push(new n({kind:`video`,label:r.name??`video`,_gst:{source:r,pipeline:o}}))}return new r(a)}function _buildAudioCaps(e){let t=[];return e.sampleRate!=null&&t.push(`rate=${Math.trunc(e.sampleRate)}`),e.channelCount!=null&&t.push(`channels=${Math.trunc(e.channelCount)}`),t.length===0?null:`audio/x-raw,${t.join(`,`)}`}function _buildVideoCaps(e){let t=[];return e.width!=null&&t.push(`width=${Math.trunc(e.width)}`),e.height!=null&&t.push(`height=${Math.trunc(e.height)}`),e.frameRate!=null&&t.push(`framerate=${Math.trunc(e.frameRate)}/1`),t.length===0?null:`video/x-raw,${t.join(`,`)}`}function _probeSource(t,n){let r=e.ElementFactory.make(t,null);if(!r)return null;let i=e.ElementFactory.make(n,null),a=e.ElementFactory.make(`fakesink`,null);if(!i||!a)return r;let o=new e.Pipeline;o.add(r),o.add(i),o.add(a),r.link(i),i.link(a);let s=o.set_state(e.State.PLAYING);return s!==e.StateChangeReturn.FAILURE&&(s=o.get_state(500*Number(e.MSECOND))[0]),o.set_state(e.State.NULL),r.unlink(i),o.remove(r),s===e.StateChangeReturn.FAILURE?null:r}const i=new Map;function _chooseSource(t,n,r,a){let o=i.get(t);if(o)return e.ElementFactory.make(o,null);for(let e of n){let n=_probeSource(e,r);if(n)return i.set(t,e),n}return i.set(t,a),e.ElementFactory.make(a,null)}function _createAudioSource(){let e=_chooseSource(`audio`,[`pipewiresrc`,`pulsesrc`,`autoaudiosrc`],`audioconvert`,`audiotestsrc`);try{e.is_live=!0}catch{}return i.get(`audio`)===`audiotestsrc`&&(e.wave=0),e}function _createVideoSource(){let e=_chooseSource(`video`,[`pipewiresrc`,`v4l2src`,`autovideosrc`],`videoconvert`,`videotestsrc`);return i.get(`video`)===`videotestsrc`&&(e.is_live=!0,e.pattern=0),e}export{getUserMedia};
@@ -1 +1 @@
1
- import"./_virtual/_rolldown/runtime.js";import{PromiseBridge as e}from"@gjsify/webrtc-native";function withGstPromise(t){return new Promise((n,r)=>{let i=new e;i.connect(`replied`,(e,t)=>{n(t)}),i.connect(`rejected`,(e,t)=>{r(Error(t))}),t(i.promise)})}export{withGstPromise};
1
+ import"./_virtual/_rolldown/runtime.js";import{PromiseBridge as e}from"@gjsify/webrtc-native";function withGstPromise(t){return new Promise((n,r)=>{let i=new e;i.connect(`replied`,(e,t)=>{n(t)}),i.connect(`rejected`,(e,t)=>{r(Error(t))}),t(i.promise)})}function getRtcpCname(e){try{return e.get_by_name(`rtpbin`)?.sdes?.get_string(`cname`)??void 0}catch{return}}export{getRtcpCname,withGstPromise};
@@ -1 +1 @@
1
- import"./_virtual/_rolldown/runtime.js";import{Gst as e}from"./gst-init.js";import"@gjsify/dom-events/register/event-target";import t from"gi://GLib?version=2.0";var n=class MediaStreamTrack extends EventTarget{id;kind;label;_enabled=!0;_muted;_ended=!1;_contentHint=``;_onended=null;_onmute=null;_onunmute=null;_gstSource=null;_gstPipeline=null;_gstTee=null;_teeMultiplexer=null;_enableCallback=null;constructor(e){super(),this.id=e.id??t.uuid_string_random(),this.kind=e.kind,this.label=e.label??``,this._muted=e.muted??!1,e._gst&&(this._gstSource=e._gst.source,this._gstPipeline=e._gst.pipeline)}get enabled(){return this._enabled}set enabled(e){let t=!!e;this._enabled!==t&&(this._enabled=t,this._enableCallback?.(t))}get muted(){return this._muted}get readyState(){return this._ended?`ended`:`live`}get contentHint(){return this._contentHint}set contentHint(e){if(this.kind===`audio`){if(e!==``&&e!==`speech`&&e!==`speech-recognition`&&e!==`music`)return}else if(e!==``&&e!==`motion`&&e!==`detail`&&e!==`text`)return;this._contentHint=e}get onended(){return this._onended}set onended(e){this._onended=e}get onmute(){return this._onmute}set onmute(e){this._onmute=e}get onunmute(){return this._onunmute}set onunmute(e){this._onunmute=e}clone(){let e=new MediaStreamTrack({kind:this.kind,label:this.label,muted:this._muted});return e._enabled=this._enabled,e}stop(){if(this._ended)return;if(this._ended=!0,this._gstSource||this._gstPipeline){try{this._gstPipeline?.set_state(e.State.NULL)}catch{}try{this._gstSource?.set_state(e.State.NULL)}catch{}this._gstSource=null,this._gstPipeline=null}let t=new Event(`ended`);this._onended?.call(this,t),this.dispatchEvent(t)}getCapabilities(){return{}}getConstraints(){return{}}getSettings(){return{}}applyConstraints(e){return Promise.reject(new DOMException(`applyConstraints is not supported`,`NotSupportedError`))}_setMuted(e){if(this._muted===e)return;this._muted=e;let t=new Event(e?`mute`:`unmute`);e?this._onmute?.call(this,t):this._onunmute?.call(this,t),this.dispatchEvent(t)}_setEnableCallback(e){this._enableCallback=e}};export{n as MediaStreamTrack};
1
+ import"./_virtual/_rolldown/runtime.js";import{Gst as e}from"./gst-init.js";import"@gjsify/dom-events/register/event-target";import t from"gi://GLib?version=2.0";var n=class MediaStreamTrack extends EventTarget{id;kind;label;_enabled=!0;_muted;_ended=!1;_contentHint=``;_onended=null;_onmute=null;_onunmute=null;_gstSource=null;_gstPipeline=null;_gstTee=null;_teeMultiplexer=null;_senderConsumers=0;_enableCallback=null;constructor(e){super(),this.id=e.id??t.uuid_string_random(),this.kind=e.kind,this.label=e.label??``,this._muted=e.muted??!1,e._gst&&(this._gstSource=e._gst.source,this._gstPipeline=e._gst.pipeline)}get enabled(){return this._enabled}set enabled(e){let t=!!e;this._enabled!==t&&(this._enabled=t,this._enableCallback?.(t))}get muted(){return this._muted}get readyState(){return this._ended?`ended`:`live`}get contentHint(){return this._contentHint}set contentHint(e){if(this.kind===`audio`){if(e!==``&&e!==`speech`&&e!==`speech-recognition`&&e!==`music`)return}else if(e!==``&&e!==`motion`&&e!==`detail`&&e!==`text`)return;this._contentHint=e}get onended(){return this._onended}set onended(e){this._onended=e}get onmute(){return this._onmute}set onmute(e){this._onmute=e}get onunmute(){return this._onunmute}set onunmute(e){this._onunmute=e}clone(){let e=new MediaStreamTrack({kind:this.kind,label:this.label,muted:this._muted});return e._enabled=this._enabled,e}stop(){if(this._ended)return;if(this._ended=!0,this._gstSource||this._gstPipeline){try{this._gstPipeline?.set_state(e.State.NULL)}catch{}try{this._gstSource?.set_state(e.State.NULL)}catch{}this._gstSource=null,this._gstPipeline=null}let t=new Event(`ended`);this._onended?.call(this,t),this.dispatchEvent(t)}getCapabilities(){return{}}getConstraints(){return{}}getSettings(){return{}}applyConstraints(e){return Promise.reject(new DOMException(`applyConstraints is not supported`,`NotSupportedError`))}_setMuted(e){if(this._muted===e)return;this._muted=e;let t=new Event(e?`mute`:`unmute`);e?this._onmute?.call(this,t):this._onunmute?.call(this,t),this.dispatchEvent(t)}_setEnableCallback(e){this._enableCallback=e}};export{n as MediaStreamTrack};
@@ -1 +1 @@
1
- import"../_virtual/_rolldown/runtime.js";import{Gst as e}from"../gst-init.js";import{RTCDataChannel as t}from"../rtc-data-channel.js";import{DOMException as n}from"@gjsify/dom-exception";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}const r={createDataChannel(r,i={}){if(this._closed)throw new n(`Cannot create a data channel on a closed RTCPeerConnection`,`InvalidStateError`);if(typeof r!=`string`)throw TypeError(`createDataChannel: label must be a string`);if(new TextEncoder().encode(r).byteLength>65535)throw TypeError(`createDataChannel: label too long (> 65535 bytes)`);let a=i.maxPacketLifeTime==null?void 0:coerceUnsignedShort(`maxPacketLifeTime`,i.maxPacketLifeTime),o=i.maxRetransmits==null?void 0:coerceUnsignedShort(`maxRetransmits`,i.maxRetransmits),s=i.id==null?void 0:coerceUnsignedShort(`id`,i.id);if(a!==void 0&&o!==void 0)throw TypeError(`createDataChannel: maxPacketLifeTime and maxRetransmits are mutually exclusive`);if(i.negotiated===!0&&s===void 0)throw TypeError(`createDataChannel: negotiated=true requires an id`);if(s===65535)throw TypeError(`createDataChannel: id 65535 is reserved`);let c=e.Structure.new_empty(`data-channel-opts`);this._setStructureField(c,`ordered`,`boolean`,i.ordered),this._setStructureField(c,`max-packet-lifetime`,`int`,a),this._setStructureField(c,`max-retransmits`,`int`,o),this._setStructureField(c,`protocol`,`string`,i.protocol),this._setStructureField(c,`negotiated`,`boolean`,i.negotiated),this._setStructureField(c,`id`,`int`,s);let l=null;try{l=this._webrtcbin.emit(`create-data-channel`,r,c)}catch(e){let t=e instanceof Error?e.message:String(e);throw Error(`create-data-channel failed: ${t}`)}if(!l)throw Error(`webrtcbin returned null data channel (check id/label/options)`);this._ensureSctpTransport();let u=new t(l,this.sctp??void 0);return this._dataChannels.set(l,u),u.addEventListener(`close`,()=>{this._dataChannels.delete(l)}),u}};function installDataChannelMethods(e){Object.assign(e,r)}export{installDataChannelMethods};
1
+ import"../_virtual/_rolldown/runtime.js";import{Gst as e}from"../gst-init.js";import{RTCDataChannel as t}from"../rtc-data-channel.js";import{DOMException as n}from"@gjsify/dom-exception";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}const r={createDataChannel(r,i={}){if(this._closed)throw new n(`Cannot create a data channel on a closed RTCPeerConnection`,`InvalidStateError`);if(typeof r!=`string`)throw TypeError(`createDataChannel: label must be a string`);if(new TextEncoder().encode(r).byteLength>65535)throw TypeError(`createDataChannel: label too long (> 65535 bytes)`);let a=i.maxPacketLifeTime==null?void 0:coerceUnsignedShort(`maxPacketLifeTime`,i.maxPacketLifeTime),o=i.maxRetransmits==null?void 0:coerceUnsignedShort(`maxRetransmits`,i.maxRetransmits),s=i.id==null?void 0:coerceUnsignedShort(`id`,i.id);if(a!==void 0&&o!==void 0)throw TypeError(`createDataChannel: maxPacketLifeTime and maxRetransmits are mutually exclusive`);if(i.negotiated===!0&&s===void 0)throw TypeError(`createDataChannel: negotiated=true requires an id`);if(s===65535)throw TypeError(`createDataChannel: id 65535 is reserved`);let c=e.Structure.new_empty(`data-channel-opts`);this._setStructureField(c,`ordered`,`boolean`,i.ordered),this._setStructureField(c,`max-packet-lifetime`,`int`,a),this._setStructureField(c,`max-retransmits`,`int`,o),this._setStructureField(c,`protocol`,`string`,i.protocol),this._setStructureField(c,`negotiated`,`boolean`,i.negotiated),this._setStructureField(c,`id`,`int`,s);let l=null;try{l=this._webrtcbin.emit(`create-data-channel`,r,c)}catch(e){let t=e instanceof Error?e.message:String(e);throw Error(`create-data-channel failed: ${t}`)}if(!l)throw Error(`webrtcbin returned null data channel (check id/label/options)`);this._ensureSctpTransport();let u=new t(l,this.sctp??void 0);return this._dataChannels.set(l,u),u.addEventListener(`close`,()=>{this._dataChannels.delete(l)}),this._updateNegotiationNeeded(),u}};function installDataChannelMethods(e){Object.assign(e,r)}export{installDataChannelMethods};
@@ -1 +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
+ 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{rewriteIceCredentials as r}from"../sdp-params.js";import{DOMException as i}from"@gjsify/dom-exception";const a={async createOffer(i){this._rejectIfClosed(`createOffer`);let a=e.Structure.new_empty(`offer-options`),o=this._iceRestartNeeded;o&&(this._setStructureField(a,`ice-restart`,`boolean`,!0),this._iceRestartNeeded=!1);let s=(await t(e=>{this._webrtcbin.emit(`create-offer`,a,e)})).get_value(`offer`),c=n.fromGstDesc(s).toJSON();return o&&(c.sdp=r(c.sdp)),c},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(r){if(this._rejectIfClosed(`setLocalDescription`),!r||!r.type){let e=this.signalingState;if(e===`stable`||e===`have-local-offer`)r=await this.createOffer();else if(e===`have-remote-offer`||e===`have-remote-pranswer`)r=await this.createAnswer();else throw new i(`setLocalDescription: cannot auto-create SDP in signalingState '${e}'`,`InvalidStateError`)}if(r.type===`rollback`){let e=this.signalingState;if(e!==`have-local-offer`)throw new i(`setLocalDescription: cannot rollback in signalingState '${e}'`,`InvalidStateError`);let a=this.currentLocalDescription!==null,o=new n(r).toGstDesc();await t(e=>{this._webrtcbin.emit(`set-local-description`,o,e)}),a||this._clearTransports();return}this._pipeline.set_state(e.State.PLAYING);let a=new n(r).toGstDesc();await t(e=>{this._webrtcbin.emit(`set-local-description`,a,e)}),this._assignTransports()},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,a)}export{installSdpNegotiationMethods};
@@ -1 +1 @@
1
- import"../_virtual/_rolldown/runtime.js";import{MediaStreamTrack as e}from"../media-stream-track.js";import{filterStatsByTrackId as t,parseGstStats as n}from"../gst-stats-parser.js";import{withGstPromise as r}from"../gst-utils.js";import{DOMException as i}from"@gjsify/dom-exception";const a={async getStats(a){if(this._rejectIfClosed(`getStats`),a!=null&&a instanceof e){let e=this._senders.some(e=>e.track===a),t=this._receivers.some(e=>e.track===a);if(!e&&!t)throw new i(`The selector track is not associated with a sender or receiver of this connection`,`InvalidAccessError`)}let o=n(await r(e=>{this._webrtcbin.emit(`get-stats`,null,e)}));return a!=null&&a instanceof e?t(o,a.id):o},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 i(`setConfiguration: bundlePolicy cannot be changed`,`InvalidModificationError`);if(e.rtcpMuxPolicy&&e.rtcpMuxPolicy!==(this._conf.rtcpMuxPolicy??`require`))throw new i(`setConfiguration: rtcpMuxPolicy cannot be changed`,`InvalidModificationError`);e.iceServers&&this._applyIceServers(e.iceServers),e.iceTransportPolicy&&this._applyIceTransportPolicy(e.iceTransportPolicy),this._conf={...this._conf,...e}},getConfiguration(){return{...this._conf}}};function installStatsAndConfigMethods(e){Object.assign(e,a)}export{installStatsAndConfigMethods};
1
+ import"../_virtual/_rolldown/runtime.js";import{MediaStreamTrack as e}from"../media-stream-track.js";import{filterStatsByTrackId as t,parseGstStats as n}from"../gst-stats-parser.js";import{withGstPromise as r}from"../gst-utils.js";import{DOMException as i}from"@gjsify/dom-exception";const a={async getStats(a){if(this._rejectIfClosed(`getStats`),a!=null&&a instanceof e){let e=this._senders.some(e=>e.track===a),t=this._receivers.some(e=>e.track===a);if(!e&&!t)throw new i(`The selector track is not associated with a sender or receiver of this connection`,`InvalidAccessError`)}let o=n(await r(e=>{this._webrtcbin.emit(`get-stats`,null,e)}));return a!=null&&a instanceof e?t(o,a.id):o},restartIce(){this._closed||(this._iceRestartNeeded=!0,this._updateNegotiationNeeded())},setConfiguration(e){if(this._rejectIfClosed(`setConfiguration`),e.bundlePolicy&&e.bundlePolicy!==(this._conf.bundlePolicy??`balanced`))throw new i(`setConfiguration: bundlePolicy cannot be changed`,`InvalidModificationError`);if(e.rtcpMuxPolicy&&e.rtcpMuxPolicy!==(this._conf.rtcpMuxPolicy??`require`))throw new i(`setConfiguration: rtcpMuxPolicy cannot be changed`,`InvalidModificationError`);e.iceServers&&this._applyIceServers(e.iceServers),e.iceTransportPolicy&&this._applyIceTransportPolicy(e.iceTransportPolicy),this._conf={...this._conf,...e}},getConfiguration(){return{...this._conf}}};function installStatsAndConfigMethods(e){Object.assign(e,a)}export{installStatsAndConfigMethods};
@@ -1 +1 @@
1
- import"../_virtual/_rolldown/runtime.js";import{MediaStreamTrack as e}from"../media-stream-track.js";import{DOMException as t}from"@gjsify/dom-exception";const n={addTrack(n,...r){if(this._rejectIfClosed(`addTrack`),!(n instanceof e))throw TypeError(`Failed to execute 'addTrack' on 'RTCPeerConnection': parameter 1 is not a MediaStreamTrack`);if(this._senders.find(e=>e.track===n))throw new t(`Track already exists in a sender of this connection`,`InvalidAccessError`);let i;for(let e of this._transceivers.values())if(e.sender.track===null&&!e.stopped&&e.direction!==`stopped`&&e.receiver.track.kind===n.kind){let t=e.direction;if(t===`recvonly`||t===`inactive`){i=e;break}}if(i){let e=i.direction;return i.direction=e===`recvonly`?`sendrecv`:`sendonly`,i.sender._setTrack(n),i.sender}return this.addTransceiver(n,{direction:`sendrecv`}).sender},removeTrack(e){if(this._rejectIfClosed(`removeTrack`),!this._senders.includes(e))throw new t(`sender was not created by this connection`,`InvalidAccessError`);e._setTrack(null)},getSenders(){return[...this._senders]},getReceivers(){return[...this._receivers]},getTransceivers(){return[...this._transceivers.values()]}};function installTrackMethods(e){Object.assign(e,n)}export{installTrackMethods};
1
+ import"../_virtual/_rolldown/runtime.js";import{MediaStreamTrack as e}from"../media-stream-track.js";import{DOMException as t}from"@gjsify/dom-exception";const n={addTrack(n,...r){if(this._rejectIfClosed(`addTrack`),!(n instanceof e))throw TypeError(`Failed to execute 'addTrack' on 'RTCPeerConnection': parameter 1 is not a MediaStreamTrack`);if(this._senders.find(e=>e.track===n))throw new t(`Track already exists in a sender of this connection`,`InvalidAccessError`);let i;for(let e of this._transceivers.values())if(e.sender.track===null&&!e.stopped&&e.direction!==`stopped`&&e.receiver.track.kind===n.kind){let t=e.direction;if(t===`recvonly`||t===`inactive`){i=e;break}}if(i){let e=i.direction;return i.direction=e===`recvonly`?`sendrecv`:`sendonly`,i.sender._setTrack(n),this._updateNegotiationNeeded(),i.sender}return this.addTransceiver(n,{direction:`sendrecv`}).sender},removeTrack(e){if(this._rejectIfClosed(`removeTrack`),!this._senders.includes(e))throw new t(`sender was not created by this connection`,`InvalidAccessError`);e._setTrack(null)},getSenders(){return[...this._senders]},getReceivers(){return[...this._receivers]},getTransceivers(){return[...this._transceivers.values()]}};function installTrackMethods(e){Object.assign(e,n)}export{installTrackMethods};
@@ -1 +1 @@
1
- import"../_virtual/_rolldown/runtime.js";import{Gst as e}from"../gst-init.js";import{MediaStreamTrack as t}from"../media-stream-track.js";import{w3cDirectionToGst as n}from"../gst-enum-maps.js";import{RTCRtpSender as r}from"../rtc-rtp-sender.js";import{RTCRtpReceiver as i}from"../rtc-rtp-receiver.js";import{RTCRtpTransceiver as a}from"../rtc-rtp-transceiver.js";const o={addTransceiver(o,s){this._rejectIfClosed(`addTransceiver`);let c;if(typeof o==`string`){if(o!==`audio`&&o!==`video`)throw TypeError(`Failed to execute 'addTransceiver' on 'RTCPeerConnection': The provided value '${o}' is not a valid enum value of type MediaStreamTrackKind.`);c=o}else if(o instanceof t)c=o.kind;else throw TypeError(`Failed to execute 'addTransceiver' on 'RTCPeerConnection': parameter 1 is not of type 'MediaStreamTrack' or a valid MediaStreamTrackKind.`);if(s?.sendEncodings){let e=new Set;for(let t of s.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 l=s?.direction??`sendrecv`;if(![`sendrecv`,`sendonly`,`recvonly`,`inactive`].includes(l))throw TypeError(`Failed to execute 'addTransceiver' on 'RTCPeerConnection': The provided value '${l}' is not a valid enum value of type RTCRtpTransceiverDirection.`);let u=o instanceof t&&o._gstSource,d=l===`sendrecv`||l===`sendonly`,f,p;if(u&&d){let e=o,t=new r(null,this._pipeline,this._webrtcbin);t._kind=c,t._onPipelineChanged=e=>{this._pipeline=e},t._setTrack(e),t._wirePipeline(e);let s=this._findNewGstTransceiver();if(!s)throw Error(`webrtcbin did not create a transceiver for the send pad`);f=s;let u=f.receiver??null,d=new i(c,u,this._pipeline),statsDelegate=e=>this.getStats(e);t._getStatsForTrack=statsDelegate,d._getStatsForTrack=statsDelegate;let m=this._ensureTransports();t._transport=m,d._transport=m,p=new a(f,t,d),t._transceiver=p,this._transceivers.set(f,p),this._senders.push(t),this._receivers.push(d),f.direction=n(l)}else{let r=e.Caps.from_string(`application/x-rtp,media=${c}`),i=n(l===`inactive`?`sendrecv`:l),a=this._webrtcbin.emit(`add-transceiver`,i,r);if(!a)throw Error(`webrtcbin did not create a transceiver`);f=a,p=this._transceivers.get(f),p||=this._createTransceiverWrapper(f),f.direction=n(l),o instanceof t&&p.sender._setTrack(o)}return p}};function installTransceiverMethods(e){Object.assign(e,o)}export{installTransceiverMethods};
1
+ import"../_virtual/_rolldown/runtime.js";import{Gst as e}from"../gst-init.js";import{MediaStreamTrack as t}from"../media-stream-track.js";import{w3cDirectionToGst as n}from"../gst-enum-maps.js";import{defaultRtpCapsString as r}from"../rtp-capabilities.js";import{RTCRtpSender as i}from"../rtc-rtp-sender.js";import{RTCRtpReceiver as a}from"../rtc-rtp-receiver.js";import{RTCRtpTransceiver as o}from"../rtc-rtp-transceiver.js";const s={addTransceiver(s,c){this._rejectIfClosed(`addTransceiver`);let l;if(typeof s==`string`){if(s!==`audio`&&s!==`video`)throw TypeError(`Failed to execute 'addTransceiver' on 'RTCPeerConnection': The provided value '${s}' is not a valid enum value of type MediaStreamTrackKind.`);l=s}else if(s instanceof t)l=s.kind;else throw TypeError(`Failed to execute 'addTransceiver' on 'RTCPeerConnection': parameter 1 is not of type 'MediaStreamTrack' or a valid MediaStreamTrackKind.`);if(c?.sendEncodings){let e=new Set;for(let t of c.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 u=c?.direction??`sendrecv`;if(![`sendrecv`,`sendonly`,`recvonly`,`inactive`].includes(u))throw TypeError(`Failed to execute 'addTransceiver' on 'RTCPeerConnection': The provided value '${u}' is not a valid enum value of type RTCRtpTransceiverDirection.`);let d=s instanceof t&&s._gstSource,f=u===`sendrecv`||u===`sendonly`,p,m;if(d&&f){let e=s,t=new i(null,this._pipeline,this._webrtcbin);t._kind=l,t._onPipelineChanged=e=>{this._pipeline=e},t._setTrack(e),t._wirePipeline(e);let r=this._findNewGstTransceiver();if(!r)throw Error(`webrtcbin did not create a transceiver for the send pad`);p=r;let c=p.receiver??null,d=new a(l,c,this._pipeline),statsDelegate=e=>this.getStats(e);if(t._getStatsForTrack=statsDelegate,d._getStatsForTrack=statsDelegate,this.localDescription){let e=this._ensureTransports();t._transport=e,d._transport=e}m=new o(p,t,d),t._transceiver=m,this._transceivers.set(p,m),this._senders.push(t),this._receivers.push(d),p.direction=n(u)}else{let i=e.Caps.from_string(r(l)),a=n(u===`inactive`?`sendrecv`:u),o=this._webrtcbin.emit(`add-transceiver`,a,i);if(!o)throw Error(`webrtcbin did not create a transceiver`);p=o,m=this._transceivers.get(p),m||=this._createTransceiverWrapper(p),p.direction=n(u),s instanceof t&&m.sender._setTrack(s)}return this._updateNegotiationNeeded(),m}};function installTransceiverMethods(e){Object.assign(e,s)}export{installTransceiverMethods};
@@ -1 +1 @@
1
- import"./_virtual/_rolldown/runtime.js";import{Gst as e,ensureWebrtcbinAvailable as t}from"./gst-init.js";import{MediaStream as n}from"./media-stream.js";import{gstToConnectionState as r,gstToIceConnectionState as i,gstToIceGatheringState as a,gstToSignalingState as o}from"./gst-enum-maps.js";import{asWebRtcBin as s,asWebRtcSrcPad as c}from"./internal/gst-types.js";import{RTCSessionDescription as l}from"./rtc-session-description.js";import{RTCIceCandidate as u}from"./rtc-ice-candidate.js";import{RTCDataChannelEvent as d,RTCPeerConnectionIceEvent as f}from"./rtc-events.js";import{RTCDataChannel as p}from"./rtc-data-channel.js";import{RTCRtpSender as m}from"./rtc-rtp-sender.js";import{RTCRtpReceiver as h}from"./rtc-rtp-receiver.js";import{RTCRtpTransceiver as g}from"./rtc-rtp-transceiver.js";import{RTCTrackEvent as _}from"./rtc-track-event.js";import{RTCIceTransport as v}from"./rtc-ice-transport.js";import{RTCDtlsTransport as y}from"./rtc-dtls-transport.js";import{RTCSctpTransport as b}from"./rtc-sctp-transport.js";import{RTCCertificate as x,generateCertificate as S}from"./rtc-certificate.js";import{installSdpNegotiationMethods as C}from"./rtc-peer-connection/sdp-negotiation.js";import{installDataChannelMethods as w}from"./rtc-peer-connection/data-channel.js";import{installTransceiverMethods as T}from"./rtc-peer-connection/transceivers.js";import{installTrackMethods as E}from"./rtc-peer-connection/tracks.js";import{installStatsAndConfigMethods as D}from"./rtc-peer-connection/stats-and-config.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";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 x&&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;s(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{s(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{s(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{s(this._webrtcbin).bundle_policy=t}catch{}}get signalingState(){if(this._closed)return`closed`;try{return o(s(this._webrtcbin).signaling_state)}catch{return`stable`}}get connectionState(){if(this._closed)return`closed`;try{return r(s(this._webrtcbin).connection_state)}catch{return`new`}}get iceConnectionState(){if(this._closed)return`closed`;try{return i(s(this._webrtcbin).ice_connection_state)}catch{return`new`}}get iceGatheringState(){try{return a(s(this._webrtcbin).ice_gathering_state)}catch{return`new`}}_descProp(e){try{let t=s(this._webrtcbin)[e];return t?l.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`)}_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()}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}))}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 v,new y(this._iceTransport)),this._dtlsTransport}_ensureSctpTransport(){if(this._sctpTransport)return;let e=this._ensureTransports();this._sctpTransport=new b(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 h(t,n,this._pipeline),a=new m(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 g(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 f(`icecandidate`,{candidate:new u({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 r=c(t).transceiver;if(!r)return;let i=this._transceivers.get(r);i||=this._createTransceiverWrapper(r),i.receiver._connectToPad(t);let a=new n([i.receiver.track]),o=new _(`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 p(e,this._sctpTransport??void 0),this._dataChannels.set(t,n),n.addEventListener(`close`,()=>{this._dataChannels.delete(t)}));let r=new d(`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 S(e)}};C(RTCPeerConnection.prototype),w(RTCPeerConnection.prototype),T(RTCPeerConnection.prototype),E(RTCPeerConnection.prototype),D(RTCPeerConnection.prototype);export{RTCPeerConnection};
1
+ import"./_virtual/_rolldown/runtime.js";import{Gst as e,ensureWebrtcbinAvailable as t}from"./gst-init.js";import{MediaStream as n}from"./media-stream.js";import{gstToConnectionState as r,gstToIceConnectionState as i,gstToIceGatheringState as a,gstToSignalingState as o}from"./gst-enum-maps.js";import{asWebRtcBin as s,asWebRtcSrcPad as c}from"./internal/gst-types.js";import{RTCSessionDescription as l}from"./rtc-session-description.js";import{RTCIceCandidate as u}from"./rtc-ice-candidate.js";import{RTCDataChannelEvent as d,RTCPeerConnectionIceEvent as f}from"./rtc-events.js";import{RTCDataChannel as p}from"./rtc-data-channel.js";import{RTCRtpSender as m}from"./rtc-rtp-sender.js";import{RTCRtpReceiver as h}from"./rtc-rtp-receiver.js";import{RTCRtpTransceiver as g}from"./rtc-rtp-transceiver.js";import{RTCTrackEvent as _}from"./rtc-track-event.js";import{RTCIceTransport as v}from"./rtc-ice-transport.js";import{RTCDtlsTransport as y}from"./rtc-dtls-transport.js";import{RTCSctpTransport as b}from"./rtc-sctp-transport.js";import{RTCCertificate as x,generateCertificate as S}from"./rtc-certificate.js";import{installSdpNegotiationMethods as C}from"./rtc-peer-connection/sdp-negotiation.js";import{installDataChannelMethods as w}from"./rtc-peer-connection/data-channel.js";import{installTransceiverMethods as T}from"./rtc-peer-connection/transceivers.js";import{installTrackMethods as E}from"./rtc-peer-connection/tracks.js";import{installStatsAndConfigMethods as D}from"./rtc-peer-connection/stats-and-config.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";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 x&&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;s(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{s(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{s(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{s(this._webrtcbin).bundle_policy=t}catch{}}get signalingState(){if(this._closed)return`closed`;try{return o(s(this._webrtcbin).signaling_state)}catch{return`stable`}}get connectionState(){if(this._closed)return`closed`;try{return r(s(this._webrtcbin).connection_state)}catch{return`new`}}get iceConnectionState(){if(this._closed)return`closed`;try{return i(s(this._webrtcbin).ice_connection_state)}catch{return`new`}}get iceGatheringState(){try{return a(s(this._webrtcbin).ice_gathering_state)}catch{return`new`}}_descProp(e){try{let t=s(this._webrtcbin)[e];return t?l.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`)}_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()}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}))}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 v,new y(this._iceTransport)),this._dtlsTransport}_ensureSctpTransport(){if(this._sctpTransport)return;let e=this._ensureTransports();this._sctpTransport=new b(e)}_assignTransports(){let e=this._ensureTransports();for(let t of this._senders)t._transport=e;for(let t of this._receivers)t._transport=e}_clearTransports(){for(let e of this._senders)e._transport=null;for(let e of this._receivers)e._transport=null}_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 h(t,n,this._pipeline),a=new m(r,this._pipeline,this._webrtcbin);a._kind=t,a._onPipelineChanged=e=>{this._pipeline=e};let statsDelegate=e=>this.getStats(e);if(a._getStatsForTrack=statsDelegate,i._getStatsForTrack=statsDelegate,this.localDescription){let e=this._ensureTransports();a._transport=e,i._transport=e}try{let t=e.mlineindex;typeof t==`number`&&t>=0&&a._setMlineIndex(t)}catch{}let o=new g(e,a,i);return a._transceiver=o,this._transceivers.set(e,o),this._senders.push(a),this._receivers.push(i),o}_handleNegotiationNeeded(){if(this._closed)return;let e=new Event(`negotiationneeded`);this._onnegotiationneeded?.call(this,e),this.dispatchEvent(e)}_negotiationNeededQueued=!1;_updateNegotiationNeeded(){this._closed||this._hasNegotiated&&this.signalingState===`stable`&&(this._negotiationNeededQueued||(this._negotiationNeededQueued=!0,Promise.resolve().then(()=>{this._negotiationNeededQueued=!1,this.signalingState===`stable`&&this._handleNegotiationNeeded()})))}_handleIceCandidate(e,t){let n=new f(`icecandidate`,{candidate:new u({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 r=c(t).transceiver;if(!r)return;let i=this._transceivers.get(r);i||=this._createTransceiverWrapper(r),i.receiver._connectToPad(t);let a=new n([i.receiver.track]),o=new _(`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 p(e,this._sctpTransport??void 0),this._dataChannels.set(t,n),n.addEventListener(`close`,()=>{this._dataChannels.delete(t)}));let r=new d(`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 S(e)}};C(RTCPeerConnection.prototype),w(RTCPeerConnection.prototype),T(RTCPeerConnection.prototype),E(RTCPeerConnection.prototype),D(RTCPeerConnection.prototype);export{RTCPeerConnection};
@@ -1 +1 @@
1
- import"./_virtual/_rolldown/runtime.js";import{Gst as e}from"./gst-init.js";import{asCapsFilterElement as t,asRtpPayloaderElement as n,asValveElement as r,asVp8EncElement as i}from"./internal/gst-types.js";import{getRtpCapabilities as a}from"./rtp-capabilities.js";import{RTCDTMFSender as o}from"./rtc-dtmf-sender.js";import{TeeMultiplexer as s}from"./tee-multiplexer.js";let c=0;var RTCRtpSender=class{_gstSender;_track=null;_lastParams=null;_pipeline=null;_webrtcbin=null;_mlineIndex=-1;_elements=[];_valve=null;_linked=!1;_teeSrcPad=null;_getStatsForTrack=null;_transport=null;_dtmf=null;_kind=null;_transceiver=null;_onPipelineChanged=null;constructor(e,t,n){this._gstSender=e,this._pipeline=t??null,this._webrtcbin=n??null}get track(){return this._track}get dtmf(){if((this._track?.kind??this._kind)!==`audio`)return null;if(!this._dtmf){let e=new o;e._isStopped=()=>this._transceiver?.stopped??!1,e._getCurrentDirection=()=>this._transceiver?.currentDirection??null,this._dtmf=e}return this._dtmf}get transport(){return this._transport}_setTrack(e){e===null&&this._linked&&this._teardownPipeline(),this._track=e}_setMlineIndex(e){this._mlineIndex=e}_wirePipeline(a){if(this._linked||!this._pipeline||!this._webrtcbin)return;let o=a._gstSource;if(!o)return;let c=a,l;if(c._gstTee&&c._gstPipeline&&c._gstPipeline!==this._pipeline){let t=c._gstPipeline,n=c._gstTee;this._webrtcbin.get_parent()===this._pipeline&&(this._pipeline.set_state(e.State.NULL),this._pipeline.remove(this._webrtcbin)),t.add(this._webrtcbin),this._webrtcbin.sync_state_with_parent(),this._pipeline=t,this._onPipelineChanged?.(t);let r=n.request_pad_simple?n.request_pad_simple(`src_%u`):n.get_request_pad(`src_%u`);this._teeSrcPad=r,l=null}else if(c._teeMultiplexer){let e=c._teeMultiplexer.requestSrcPad();this._teeSrcPad=e,l=null}else if(c._gstPipeline&&c._gstPipeline!==this._pipeline){let t=c._gstPipeline,n=o.get_static_pad(`src`),r=n?.get_peer?.();r&&n.unlink(r),o.set_state(e.State.NULL),t.remove(o),this._pipeline.add(o),c._gstPipeline=this._pipeline;let i=new s(this._pipeline,o);if(c._teeMultiplexer=i,r){let e=i.requestSrcPad();e&&e.link(r)}let a=i.requestSrcPad();this._teeSrcPad=a,l=null}else{let t=c._gstPipeline;t&&t!==this._pipeline&&(o.set_state(e.State.NULL),t.remove(o),c._gstPipeline=this._pipeline),o.get_parent()!==this._pipeline&&this._pipeline.add(o),l=o}let u=r(e.ElementFactory.make(`valve`,null));u.drop=!a.enabled,this._valve=u,this._pipeline.add(u);let d=[u],f;if(a.kind===`audio`){let r=e.ElementFactory.make(`audioconvert`,null),i=e.ElementFactory.make(`audioresample`,null),a=e.ElementFactory.make(`opusenc`,null),o=n(e.ElementFactory.make(`rtpopuspay`,null));o.pt=111;let s=t(e.ElementFactory.make(`capsfilter`,null));s.caps=e.Caps.from_string(`application/x-rtp,media=audio,encoding-name=OPUS,clock-rate=48000,payload=111`),d.push(r,i,a,o,s);for(let e of d)this._pipeline.add(e);if(this._teeSrcPad){let e=u.get_static_pad(`sink`);this._teeSrcPad.link(e)}else l&&l.link(u);u.link(r),r.link(i),i.link(a),a.link(o),o.link(s),f=s}else{let r=e.ElementFactory.make(`videoconvert`,null),a=e.ElementFactory.make(`videoscale`,null),o=i(e.ElementFactory.make(`vp8enc`,null));o.deadline=1,o.keyframe_max_dist=60;let s=n(e.ElementFactory.make(`rtpvp8pay`,null));s.pt=96;let c=t(e.ElementFactory.make(`capsfilter`,null));c.caps=e.Caps.from_string(`application/x-rtp,media=video,encoding-name=VP8,clock-rate=90000,payload=96`),d.push(r,a,o,s,c);for(let e of d)this._pipeline.add(e);if(this._teeSrcPad){let e=u.get_static_pad(`sink`);this._teeSrcPad.link(e)}else l&&l.link(u);u.link(r),r.link(a),a.link(o),o.link(s),s.link(c),f=c}let p=this._mlineIndex>=0?`sink_${this._mlineIndex}`:`sink_%u`,m=this._webrtcbin.request_pad_simple?this._webrtcbin.request_pad_simple(p):this._webrtcbin.get_request_pad(p);m&&f.get_static_pad(`src`).link(m);let h=this._teeSrcPad?d:[o,...d];for(let e of h)e.sync_state_with_parent();this._elements=h,this._linked=!0,a._setEnableCallback(e=>{this._valve&&(this._valve.drop=!e)})}_teardownPipeline(){if(this._linked){if(this._track&&this._track._setEnableCallback(null),this._teeSrcPad&&this._track?._teeMultiplexer){try{this._track._teeMultiplexer.releaseSrcPad(this._teeSrcPad)}catch{}this._teeSrcPad=null}for(let t of[...this._elements].reverse())try{t.set_state(e.State.NULL),this._pipeline?.remove(t)}catch{}this._elements=[],this._valve=null,this._linked=!1}}getParameters(){return this._lastParams||={transactionId:String(++c),encodings:[],codecs:[],headerExtensions:[],rtcp:{}},{...this._lastParams,encodings:[...this._lastParams.encodings]}}async setParameters(e){if(!this._lastParams)throw new DOMException(`getParameters must be called before setParameters`,`InvalidStateError`);if(e.transactionId!==this._lastParams.transactionId)throw new DOMException(`transactionId mismatch`,`InvalidModificationError`);this._lastParams=null}async replaceTrack(t){if(t===null){this._teardownPipeline(),this._track=null;return}if(this._track!==null&&t.kind!==this._track.kind)throw TypeError(`Cannot replace track with different kind`);let n=t;if(this._linked&&n._gstSource){let t=this._elements[0],r=n._gstSource,i=n._gstPipeline;i&&i!==this._pipeline&&(r.set_state(e.State.NULL),i.remove(r),n._gstPipeline=this._pipeline),t.set_state(e.State.NULL),this._valve&&t.unlink(this._valve),this._pipeline?.remove(t),this._pipeline?.add(r),this._valve&&r.link(this._valve),r.sync_state_with_parent(),this._elements[0]=r}else n._gstSource&&this._wirePipeline(t);this._track&&this._track._setEnableCallback(null),this._track=t,this._linked&&t._setEnableCallback(e=>{this._valve&&(this._valve.drop=!e)})}async getStats(){if(this._getStatsForTrack&&this._track)return this._getStatsForTrack(this._track);let{RTCStatsReport:e}=await import(`./rtc-stats-report.js`);return new e}setStreams(...e){}static getCapabilities(e){return a(e)}};export{RTCRtpSender};
1
+ import"./_virtual/_rolldown/runtime.js";import{Gst as e}from"./gst-init.js";import{getRtcpCname as t}from"./gst-utils.js";import{asCapsFilterElement as n,asRtpPayloaderElement as r,asValveElement as i,asVp8EncElement as a,asWebRtcBin as o}from"./internal/gst-types.js";import{getRtpCapabilities as s}from"./rtp-capabilities.js";import{parseMediaSectionParams as c}from"./sdp-params.js";import{RTCDTMFSender as l}from"./rtc-dtmf-sender.js";import{TeeMultiplexer as u}from"./tee-multiplexer.js";let d=0;var RTCRtpSender=class{_gstSender;_track=null;_lastParams=null;_pipeline=null;_webrtcbin=null;_mlineIndex=-1;_elements=[];_valve=null;_linked=!1;_teeSrcPad=null;_getStatsForTrack=null;_transport=null;_dtmf=null;_kind=null;_transceiver=null;_onPipelineChanged=null;constructor(e,t,n){this._gstSender=e,this._pipeline=t??null,this._webrtcbin=n??null}get track(){return this._track}get dtmf(){if((this._track?.kind??this._kind)!==`audio`)return null;if(!this._dtmf){let e=new l;e._isStopped=()=>this._transceiver?.stopped??!1,e._getCurrentDirection=()=>this._transceiver?.currentDirection??null,this._dtmf=e}return this._dtmf}get transport(){return this._transport}_setTrack(e){e===null&&this._linked&&this._teardownPipeline(),this._track=e}_setMlineIndex(e){this._mlineIndex=e}_wirePipeline(t){if(this._linked||!this._pipeline||!this._webrtcbin)return;let o=t._gstSource;if(!o)return;let s=t,c;if(s._gstTee&&s._gstPipeline&&s._gstPipeline!==this._pipeline){let t=s._gstPipeline,n=s._gstTee;this._webrtcbin.get_parent()===this._pipeline&&(this._pipeline.set_state(e.State.NULL),this._pipeline.remove(this._webrtcbin)),t.add(this._webrtcbin),this._webrtcbin.sync_state_with_parent(),this._pipeline=t,this._onPipelineChanged?.(t);let r=n.request_pad_simple?n.request_pad_simple(`src_%u`):n.get_request_pad(`src_%u`);this._teeSrcPad=r,c=null}else if(s._teeMultiplexer){let e=s._teeMultiplexer.requestSrcPad();this._teeSrcPad=e,c=null}else if(s._gstPipeline&&s._gstPipeline!==this._pipeline&&s._senderConsumers>0){let t=s._gstPipeline,n=o.get_static_pad(`src`),r=n?.get_peer?.();r&&n.unlink(r),o.set_state(e.State.NULL),t.remove(o),this._pipeline.add(o),s._gstPipeline=this._pipeline;let i=new u(this._pipeline,o);if(s._teeMultiplexer=i,r){let e=i.requestSrcPad();e&&e.link(r)}let a=i.requestSrcPad();this._teeSrcPad=a,c=null}else{let t=s._gstPipeline;t&&t!==this._pipeline&&(o.set_state(e.State.NULL),t.remove(o),s._gstPipeline=this._pipeline),o.get_parent()!==this._pipeline&&this._pipeline.add(o),c=o}let l=i(e.ElementFactory.make(`valve`,null));l.drop=!t.enabled,this._valve=l,this._pipeline.add(l);let d=[l],f;if(t.kind===`audio`){let t=e.ElementFactory.make(`audioconvert`,null),i=e.ElementFactory.make(`audioresample`,null),a=e.ElementFactory.make(`opusenc`,null),o=r(e.ElementFactory.make(`rtpopuspay`,null));o.pt=111;let s=n(e.ElementFactory.make(`capsfilter`,null));s.caps=e.Caps.from_string(`application/x-rtp,media=audio,encoding-name=OPUS,clock-rate=48000,payload=111`),d.push(t,i,a,o,s);for(let e of d)this._pipeline.add(e);if(this._teeSrcPad){let e=l.get_static_pad(`sink`);this._teeSrcPad.link(e)}else c&&c.link(l);l.link(t),t.link(i),i.link(a),a.link(o),o.link(s),f=s}else{let t=e.ElementFactory.make(`videoconvert`,null),i=e.ElementFactory.make(`videoscale`,null),o=a(e.ElementFactory.make(`vp8enc`,null));o.deadline=1,o.keyframe_max_dist=60;let s=r(e.ElementFactory.make(`rtpvp8pay`,null));s.pt=96;let u=n(e.ElementFactory.make(`capsfilter`,null));u.caps=e.Caps.from_string(`application/x-rtp,media=video,encoding-name=VP8,clock-rate=90000,payload=96`),d.push(t,i,o,s,u);for(let e of d)this._pipeline.add(e);if(this._teeSrcPad){let e=l.get_static_pad(`sink`);this._teeSrcPad.link(e)}else c&&c.link(l);l.link(t),t.link(i),i.link(o),o.link(s),s.link(u),f=u}let p=this._mlineIndex>=0?`sink_${this._mlineIndex}`:`sink_%u`,m=this._webrtcbin.request_pad_simple?this._webrtcbin.request_pad_simple(p):this._webrtcbin.get_request_pad(p);m&&f.get_static_pad(`src`).link(m);let h=this._teeSrcPad?d:[o,...d];for(let e of h)e.sync_state_with_parent();this._elements=h,this._linked=!0,t._senderConsumers++,t._setEnableCallback(e=>{this._valve&&(this._valve.drop=!e)})}_teardownPipeline(){if(this._linked){if(this._track&&(this._track._setEnableCallback(null),this._track._senderConsumers=Math.max(0,this._track._senderConsumers-1)),this._teeSrcPad&&this._track?._teeMultiplexer){try{this._track._teeMultiplexer.releaseSrcPad(this._teeSrcPad)}catch{}this._teeSrcPad=null}for(let t of[...this._elements].reverse())try{t.set_state(e.State.NULL),this._pipeline?.remove(t)}catch{}this._elements=[],this._valve=null,this._linked=!1}}getParameters(){let e=this._negotiatedParams();this._lastParams?(this._lastParams.codecs=e.codecs,this._lastParams.headerExtensions=e.headerExtensions,this._lastParams.rtcp=e.rtcp):this._lastParams={transactionId:String(++d),encodings:[],...e};let t=this._lastParams;return{...t,encodings:[...t.encodings],codecs:t.codecs.map(e=>({...e})),headerExtensions:t.headerExtensions.map(e=>({...e})),rtcp:{...t.rtcp}}}_negotiatedParams(){let e={},n={codecs:[],headerExtensions:[],rtcp:e};if(!this._webrtcbin)return n;let r=t(this._webrtcbin);r!==void 0&&(e.cname=r);let i=o(this._webrtcbin),a=(i.current_remote_description??i.current_local_description)?.sdp?.as_text?.()??``;if(!a)return n;let s=this._track?.kind??this._kind,l=c(a,{mid:this._transceiver?.mid??void 0,mlineIndex:this._mlineIndex>=0?this._mlineIndex:void 0,kind:s??void 0});return l?(n.codecs=l.codecs,n.headerExtensions=l.headerExtensions,e.reducedSize=l.reducedSize,n):n}async setParameters(e){if(!this._lastParams)throw new DOMException(`getParameters must be called before setParameters`,`InvalidStateError`);if(e.transactionId!==this._lastParams.transactionId)throw new DOMException(`transactionId mismatch`,`InvalidModificationError`);this._lastParams=null}async replaceTrack(t){if(t===null){this._teardownPipeline(),this._track=null;return}if(this._track!==null&&t.kind!==this._track.kind)throw TypeError(`Cannot replace track with different kind`);let n=t;if(this._linked&&n._gstSource){let t=this._elements[0],r=n._gstSource,i=n._gstPipeline;i&&i!==this._pipeline&&(r.set_state(e.State.NULL),i.remove(r),n._gstPipeline=this._pipeline),t.set_state(e.State.NULL),this._valve&&t.unlink(this._valve),this._pipeline?.remove(t),this._pipeline?.add(r),this._valve&&r.link(this._valve),r.sync_state_with_parent(),this._elements[0]=r}else n._gstSource&&this._wirePipeline(t);this._track&&this._track._setEnableCallback(null),this._track=t,this._linked&&t._setEnableCallback(e=>{this._valve&&(this._valve.drop=!e)})}async getStats(){if(this._getStatsForTrack&&this._track)return this._getStatsForTrack(this._track);let{RTCStatsReport:e}=await import(`./rtc-stats-report.js`);return new e}setStreams(...e){}static getCapabilities(e){return s(e)}};export{RTCRtpSender};
@@ -1 +1 @@
1
- import"./_virtual/_rolldown/runtime.js";import"@gjsify/dom-events/register/event-target";var RTCSctpTransport=class extends EventTarget{transport;_state=`connecting`;_maxMessageSize=262144;_maxChannels=65535;_onstatechange=null;constructor(e){super(),this.transport=e}get state(){return this._state}get maxMessageSize(){return this._maxMessageSize}get maxChannels(){return this._maxChannels}get onstatechange(){return this._onstatechange}set onstatechange(e){this._onstatechange=e}_setState(e){if(this._state===e)return;this._state=e;let t=new Event(`statechange`);this._onstatechange?.call(this,t),this.dispatchEvent(t)}};export{RTCSctpTransport};
1
+ import"./_virtual/_rolldown/runtime.js";import"@gjsify/dom-events/register/event-target";var RTCSctpTransport=class extends EventTarget{transport;_state=`connecting`;_maxMessageSize=262144;_maxChannels=65535;_onstatechange=null;constructor(e){super(),this.transport=e}get state(){return this._state}get maxMessageSize(){return this._maxMessageSize}get maxChannels(){return this._maxChannels}get onstatechange(){return this._onstatechange}set onstatechange(e){this._onstatechange=e}_setMaxMessageSize(e){if(typeof e!=`number`||!Number.isFinite(e)||e<0)throw TypeError(`RTCSctpTransport: invalid max-message-size ${String(e)}`);this._maxMessageSize=e}_setState(e){if(this._state===e)return;this._state=e;let t=new Event(`statechange`);this._onstatechange?.call(this,t),this.dispatchEvent(t)}};export{RTCSctpTransport};
@@ -1 +1 @@
1
- import"./_virtual/_rolldown/runtime.js";import e from"gi://GstWebRTC?version=1.0";import t from"gi://GstSdp?version=1.0";function sdpTypeToGst(t){switch(t){case`offer`:return e.WebRTCSDPType.OFFER;case`pranswer`:return e.WebRTCSDPType.PRANSWER;case`answer`:return e.WebRTCSDPType.ANSWER;case`rollback`:return e.WebRTCSDPType.ROLLBACK}}function sdpTypeFromGst(t){switch(t){case e.WebRTCSDPType.OFFER:return`offer`;case e.WebRTCSDPType.PRANSWER:return`pranswer`;case e.WebRTCSDPType.ANSWER:return`answer`;case e.WebRTCSDPType.ROLLBACK:return`rollback`;default:return`offer`}}var n=class RTCSessionDescription{type;sdp;constructor(e){this.type=e?.type??`offer`,this.sdp=e?.sdp??``}toJSON(){return{type:this.type,sdp:this.sdp}}toGstDesc(){let[n,r]=t.SDPMessage.new_from_text(this.sdp);if(n!==t.SDPResult.OK)throw Error(`Failed to parse SDP text (GstSDPResult=${n})`);return e.WebRTCSessionDescription.new(sdpTypeToGst(this.type),r)}static fromGstDesc(e){let t=e.sdp?.as_text?.()??``;return new RTCSessionDescription({type:sdpTypeFromGst(e.type),sdp:t})}};export{n as RTCSessionDescription};
1
+ import"./_virtual/_rolldown/runtime.js";import e from"gi://GstWebRTC?version=1.0";import t from"gi://GstSdp?version=1.0";function sdpTypeToGst(t){switch(t){case`offer`:return e.WebRTCSDPType.OFFER;case`pranswer`:return e.WebRTCSDPType.PRANSWER;case`answer`:return e.WebRTCSDPType.ANSWER;case`rollback`:return e.WebRTCSDPType.ROLLBACK}}function sdpTypeFromGst(t){switch(t){case e.WebRTCSDPType.OFFER:return`offer`;case e.WebRTCSDPType.PRANSWER:return`pranswer`;case e.WebRTCSDPType.ANSWER:return`answer`;case e.WebRTCSDPType.ROLLBACK:return`rollback`;default:return`offer`}}var n=class RTCSessionDescription{type;sdp;constructor(e){this.type=e?.type??`offer`,this.sdp=e?.sdp??``}toJSON(){return{type:this.type,sdp:this.sdp}}toGstDesc(){if(this.type===`rollback`){let[n,r]=t.SDPMessage.new();if(n!==t.SDPResult.OK)throw Error(`Failed to create empty SDP message (GstSDPResult=${n})`);return e.WebRTCSessionDescription.new(e.WebRTCSDPType.ROLLBACK,r)}let[n,r]=t.SDPMessage.new_from_text(this.sdp);if(n!==t.SDPResult.OK)throw Error(`Failed to parse SDP text (GstSDPResult=${n})`);return e.WebRTCSessionDescription.new(sdpTypeToGst(this.type),r)}static fromGstDesc(e){let t=e.sdp?.as_text?.()??``;return new RTCSessionDescription({type:sdpTypeFromGst(e.type),sdp:t})}};export{n as RTCSessionDescription};
@@ -1 +1 @@
1
- import"./_virtual/_rolldown/runtime.js";const e={codecs:[{mimeType:`audio/opus`,clockRate:48e3,channels:2,sdpFmtpLine:`minptime=10;useinbandfec=1`},{mimeType:`audio/G722`,clockRate:8e3,channels:1},{mimeType:`audio/PCMU`,clockRate:8e3,channels:1},{mimeType:`audio/PCMA`,clockRate:8e3,channels:1},{mimeType:`audio/telephone-event`,clockRate:8e3,channels:1},{mimeType:`audio/red`,clockRate:48e3,channels:2}],headerExtensions:[{uri:`urn:ietf:params:rtp-hdrext:ssrc-audio-level`},{uri:`http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time`},{uri:`urn:ietf:params:rtp-hdrext:sdes:mid`}]},t={codecs:[{mimeType:`video/VP8`,clockRate:9e4},{mimeType:`video/rtx`,clockRate:9e4},{mimeType:`video/H264`,clockRate:9e4,sdpFmtpLine:`level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f`},{mimeType:`video/VP9`,clockRate:9e4},{mimeType:`video/red`,clockRate:9e4},{mimeType:`video/ulpfec`,clockRate:9e4}],headerExtensions:[{uri:`urn:ietf:params:rtp-hdrext:toffset`},{uri:`http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time`},{uri:`urn:3gpp:video-orientation`},{uri:`urn:ietf:params:rtp-hdrext:sdes:mid`},{uri:`urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id`},{uri:`urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id`}]};function getRtpCapabilities(n){return n===`audio`?e:n===`video`?t:null}export{getRtpCapabilities};
1
+ import"./_virtual/_rolldown/runtime.js";const e={codecs:[{mimeType:`audio/opus`,clockRate:48e3,channels:2,sdpFmtpLine:`minptime=10;useinbandfec=1`},{mimeType:`audio/G722`,clockRate:8e3,channels:1},{mimeType:`audio/PCMU`,clockRate:8e3,channels:1},{mimeType:`audio/PCMA`,clockRate:8e3,channels:1},{mimeType:`audio/telephone-event`,clockRate:8e3,channels:1},{mimeType:`audio/red`,clockRate:48e3,channels:2}],headerExtensions:[{uri:`urn:ietf:params:rtp-hdrext:ssrc-audio-level`},{uri:`http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time`},{uri:`urn:ietf:params:rtp-hdrext:sdes:mid`}]},t={codecs:[{mimeType:`video/VP8`,clockRate:9e4},{mimeType:`video/rtx`,clockRate:9e4},{mimeType:`video/H264`,clockRate:9e4,sdpFmtpLine:`level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f`},{mimeType:`video/VP9`,clockRate:9e4},{mimeType:`video/red`,clockRate:9e4},{mimeType:`video/ulpfec`,clockRate:9e4}],headerExtensions:[{uri:`urn:ietf:params:rtp-hdrext:toffset`},{uri:`http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time`},{uri:`urn:3gpp:video-orientation`},{uri:`urn:ietf:params:rtp-hdrext:sdes:mid`},{uri:`urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id`},{uri:`urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id`}]};function getRtpCapabilities(n){return n===`audio`?e:n===`video`?t:null}const n=111,r=96;function defaultRtpCapsString(e){return e===`audio`?`application/x-rtp,media=audio,encoding-name=OPUS,clock-rate=48000,payload=111`:`application/x-rtp,media=video,encoding-name=VP8,clock-rate=90000,payload=96`}export{n as OPUS_PAYLOAD_TYPE,r as VP8_PAYLOAD_TYPE,defaultRtpCapsString,getRtpCapabilities};
@@ -0,0 +1,3 @@
1
+ import"./_virtual/_rolldown/runtime.js";import{fillRandomBytes as e}from"@gjsify/webcrypto/random";function parseMediaSectionParams(e,t){let n=[],r=null;for(let t of e.split(/\r\n|\r|\n/)){let e=t.trimEnd();e.startsWith(`m=`)?(r=[e],n.push(r)):r&&e.length>0&&r.push(e)}let i;if(t.mid!==void 0&&(i=n.find(e=>e.includes(`a=mid:${t.mid}`))),!i&&t.mlineIndex!==void 0&&t.mlineIndex>=0&&(i=n[t.mlineIndex]),!i&&t.kind!==void 0&&(i=n.find(e=>e[0].startsWith(`m=${t.kind} `))),!i)return null;let a=i[0].split(` `),o=a[0].slice(2),s=a.slice(3).map(Number).filter(Number.isInteger),c=new Map,l=new Map,u=[],d=!1;for(let e of i){let t=/^a=rtpmap:(\d+) ([^/]+)\/(\d+)(?:\/(\d+))?/.exec(e);if(t){let e={encoding:t[2],clockRate:Number(t[3])};t[4]!==void 0&&(e.channels=Number(t[4])),c.set(Number(t[1]),e);continue}if(t=/^a=fmtp:(\d+) (.+)/.exec(e),t){l.set(Number(t[1]),t[2]);continue}if(t=/^a=extmap:(\d+)(?:\/\S+)? (\S+)/.exec(e),t){u.push({id:Number(t[1]),uri:t[2]});continue}e===`a=rtcp-rsize`&&(d=!0)}let f=[];for(let e of s){let t=c.get(e);if(!t)continue;let n={payloadType:e,mimeType:`${o}/${t.encoding}`,clockRate:t.clockRate};t.channels!==void 0&&(n.channels=t.channels);let r=l.get(e);r!==void 0&&(n.sdpFmtpLine=r),f.push(n)}return{codecs:f,headerExtensions:u,reducedSize:d}}function randomIceString(t){let n=new Uint8Array(t);e(n);let r=``;for(let e of n)r+=`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/`[e&63];return r}function rewriteIceCredentials(e){let t=new Map,n=new Map;return e.split(`\r
2
+ `).map(e=>{if(e.startsWith(`a=ice-ufrag:`)){let n=e.slice(12);return t.has(n)||t.set(n,randomIceString(8)),`a=ice-ufrag:${t.get(n)}`}if(e.startsWith(`a=ice-pwd:`)){let t=e.slice(10);return n.has(t)||n.set(t,randomIceString(24)),`a=ice-pwd:${n.get(t)}`}return e}).join(`\r
3
+ `)}export{parseMediaSectionParams,rewriteIceCredentials};
@@ -9,3 +9,14 @@ import type Gst from 'gi://Gst?version=1.0';
9
9
  * });
10
10
  */
11
11
  export declare function withGstPromise(emit: (promise: Gst.Promise) => void): Promise<Gst.Structure | null>;
12
+ /**
13
+ * Read the RTP CNAME of a webrtcbin — "the CNAME of the associated
14
+ * RTCPeerConnection" that W3C § 5.2 getParameters exposes as `rtcp.cname`.
15
+ *
16
+ * webrtcbin's internal rtpbin generates one canonical name per connection
17
+ * (used in its RTCP SDES packets) and exposes it through rtpbin's `sdes`
18
+ * GstStructure (`application/x-rtp-source-sdes, cname=(string)…`). The
19
+ * rtpbin child is class-installed by GstWebRTCBin under the fixed name
20
+ * "rtpbin".
21
+ */
22
+ export declare function getRtcpCname(webrtcbin: Gst.Element): string | undefined;
@@ -33,6 +33,14 @@ export declare class MediaStreamTrack extends EventTarget {
33
33
  _gstTee: GstNs.Element | null;
34
34
  /** @internal TeeMultiplexer for multi-PC fan-out (created on second addTrack) */
35
35
  _teeMultiplexer: TeeMultiplexer | null;
36
+ /**
37
+ * @internal Number of RTCRtpSenders currently consuming `_gstSource`.
38
+ * The FIRST consumer moves the source out of its holding pipeline (the
39
+ * one getUserMedia parked it in) into the PC pipeline; only a SECOND
40
+ * concurrent consumer inserts the TeeMultiplexer fan-out. Maintained by
41
+ * RTCRtpSender._wirePipeline / _teardownPipeline.
42
+ */
43
+ _senderConsumers: number;
36
44
  /** @internal Callback set by RTCRtpSender to control valve drop property */
37
45
  private _enableCallback;
38
46
  constructor(init: MediaStreamTrackInit);
@@ -105,8 +105,41 @@ export declare class RTCPeerConnection extends EventTarget {
105
105
  _ensureTransports(): RTCDtlsTransport;
106
106
  /** Create the SCTP transport when a data channel is first negotiated. */
107
107
  _ensureSctpTransport(): void;
108
+ /**
109
+ * @internal — attach the shared DTLS transport to every sender/receiver.
110
+ * Called when a LOCAL description is applied: per W3C § 4.4.1.5 (set
111
+ * session description → "create the DTLS transports") and the WPT
112
+ * canonical refs/wpt/webrtc/RTCRtpSender.https.html, `sender.transport` /
113
+ * `receiver.transport` is null until setLocalDescription ("null transport
114
+ * initially", "a transport after sLD(offer)") and stays null on the peer
115
+ * that only applied a REMOTE offer ("null transport after sRD(offer)").
116
+ */
117
+ _assignTransports(): void;
118
+ /**
119
+ * @internal — detach the transports again when the initial offer is
120
+ * rolled back (WPT RTCRtpSender.https.html: "null transport after
121
+ * rollback of sLD(offer)"). The caller only invokes this while no
122
+ * negotiation has completed — after a completed offer/answer the
123
+ * transports survive a renegotiation rollback.
124
+ */
125
+ _clearTransports(): void;
108
126
  _createTransceiverWrapper(gstTrans: GstWebRTC.WebRTCRTPTransceiver): RTCRtpTransceiver;
109
127
  _handleNegotiationNeeded(): void;
128
+ /** @internal — one queued negotiationneeded task per mutation burst. */
129
+ _negotiationNeededQueued: boolean;
130
+ /**
131
+ * @internal — the JS half of W3C § 4.7.3 "update the negotiation-needed
132
+ * flag", called by the mutating entry points (addTransceiver, addTrack,
133
+ * createDataChannel, restartIce). webrtcbin emits on-negotiation-needed
134
+ * for the INITIAL need but — measured on GStreamer 1.28 — does NOT
135
+ * re-emit when a transceiver or data channel is added after a completed
136
+ * offer/answer, so once `_hasNegotiated` is set the renegotiation event
137
+ * is queued here instead. The `_negotiationNeededQueued` dedupe mirrors
138
+ * the spec's [[NegotiationNeeded]] flag chain (one queued task per
139
+ * burst); the stable-state re-check on dispatch mirrors § 4.7.3 step
140
+ * "if connection's signaling state is not 'stable', abort".
141
+ */
142
+ _updateNegotiationNeeded(): void;
110
143
  private _handleIceCandidate;
111
144
  private _handleNewTransceiver;
112
145
  private _handlePadAdded;
@@ -70,10 +70,11 @@ export declare class RTCRtpSender {
70
70
  private _dtmf;
71
71
  /** @internal — the kind of media this sender handles */
72
72
  _kind: 'audio' | 'video' | null;
73
- /** @internal — back-reference for DTMF stopped/direction checks */
73
+ /** @internal — back-reference for DTMF stopped/direction checks + m-section (mid) lookup */
74
74
  _transceiver: {
75
75
  stopped: boolean;
76
76
  currentDirection: string | null;
77
+ mid: string | null;
77
78
  } | null;
78
79
  /** @internal — callback to notify RTCPeerConnection when pipeline changes (cross-pipeline fix) */
79
80
  _onPipelineChanged: ((newPipeline: GstNs.Pipeline) => void) | null;
@@ -91,6 +92,15 @@ export declare class RTCRtpSender {
91
92
  /** @internal — tear down the encoder chain on close/removeTrack */
92
93
  _teardownPipeline(): void;
93
94
  getParameters(): RTCRtpSendParameters;
95
+ /**
96
+ * Negotiated codecs/extensions/rtcp for this sender's m-section.
97
+ * W3C § 5.2 getParameters: "The codecs sequence is populated based on
98
+ * the codecs that have been negotiated for sending … in the priority
99
+ * order indicated by the remote description"; "rtcp.cname is set to the
100
+ * CNAME of the associated RTCPeerConnection". Before any negotiation
101
+ * completed the codec list is empty (there is no negotiated set yet).
102
+ */
103
+ private _negotiatedParams;
94
104
  setParameters(params: RTCRtpSendParameters): Promise<void>;
95
105
  replaceTrack(track: MediaStreamTrack | null): Promise<void>;
96
106
  getStats(): Promise<RTCStatsReport>;
@@ -14,6 +14,14 @@ export declare class RTCSctpTransport extends EventTarget {
14
14
  get maxChannels(): number | null;
15
15
  get onstatechange(): EventHandler;
16
16
  set onstatechange(v: EventHandler);
17
+ /**
18
+ * @internal — update the `maxMessageSize` ceiling, e.g. from a parsed SDP
19
+ * `a=max-message-size:N` attribute (RFC 8841 § 6.1). A value of `0` means
20
+ * the peer can handle messages of any size — `RTCDataChannel.send`'s
21
+ * enforcement skips the check entirely. Negative or non-finite values are
22
+ * rejected.
23
+ */
24
+ _setMaxMessageSize(v: number): void;
17
25
  /** @internal */
18
26
  _setState(state: RTCSctpTransportState): void;
19
27
  }
@@ -1,3 +1,14 @@
1
1
  import type { RTCRtpCapabilities } from './rtc-rtp-sender.js';
2
2
  /** Shared implementation for RTCRtpSender.getCapabilities / RTCRtpReceiver.getCapabilities. */
3
3
  export declare function getRtpCapabilities(kind: string): RTCRtpCapabilities | null;
4
+ export declare const OPUS_PAYLOAD_TYPE = 111;
5
+ export declare const VP8_PAYLOAD_TYPE = 96;
6
+ /**
7
+ * Full RTP caps for a kind-only (Path-B) `add-transceiver`. webrtcbin needs
8
+ * `encoding-name`/`clock-rate`/`payload` to build an m-section for the
9
+ * transceiver — `application/x-rtp,media=audio` alone yields an offer with
10
+ * NO m-line at all (measured on GStreamer 1.28: create-offer returned only
11
+ * the session-level `v=/o=/s=/t=` + `a=ice-options:trickle`). Mirrors the
12
+ * caps the Path-A encoder chain advertises via its capsfilter.
13
+ */
14
+ export declare function defaultRtpCapsString(kind: 'audio' | 'video'): string;
@@ -0,0 +1,49 @@
1
+ export interface SdpCodecParams {
2
+ payloadType: number;
3
+ mimeType: string;
4
+ clockRate: number;
5
+ channels?: number;
6
+ sdpFmtpLine?: string;
7
+ }
8
+ export interface SdpHeaderExtensionParams {
9
+ uri: string;
10
+ id: number;
11
+ }
12
+ export interface SdpMediaSectionParams {
13
+ codecs: SdpCodecParams[];
14
+ headerExtensions: SdpHeaderExtensionParams[];
15
+ /** `a=rtcp-rsize` present (RFC 5506 reduced-size RTCP). */
16
+ reducedSize: boolean;
17
+ }
18
+ export interface SdpMediaSectionSelector {
19
+ /** Match by `a=mid:<mid>` (RFC 5888) — the most precise selector. */
20
+ mid?: string;
21
+ /** Fall back to the m-section at this index (JSEP m-line order). */
22
+ mlineIndex?: number;
23
+ /** Last resort: the first m-section of this media kind. */
24
+ kind?: 'audio' | 'video';
25
+ }
26
+ /**
27
+ * Extract the negotiated codec/extension/rtcp parameters for ONE m-section
28
+ * of an SDP document. Returns `null` when no section matches the selector
29
+ * (e.g. before any negotiation completed).
30
+ */
31
+ export declare function parseMediaSectionParams(sdp: string, selector: SdpMediaSectionSelector): SdpMediaSectionParams | null;
32
+ /**
33
+ * Rewrite every `a=ice-ufrag:` / `a=ice-pwd:` line of an SDP with freshly
34
+ * generated credentials — the JSEP ICE-restart primitive (RFC 9429 § 3.5.1:
35
+ * "an ICE restart is indicated by generating new ICE ufrag and pwd in the
36
+ * offer"; W3C WebRTC § 4.4.3.2 restartIce). Distinct old values map to
37
+ * distinct new values, and a value repeated across m-sections
38
+ * (BUNDLE-shared credentials) keeps sharing ONE new value, preserving the
39
+ * offer's credential topology.
40
+ *
41
+ * Why rewriting instead of an engine option: GStreamer webrtcbin (≤ 1.28)
42
+ * ignores the `ice-restart` field of the create-offer options structure
43
+ * (measured: identical ufrag with and without it), but it DOES push the
44
+ * local credentials of a set-local-description SDP into its ICE agent —
45
+ * measured end-to-end: two webrtcbins complete ICE connectivity with a
46
+ * munged ufrag/pwd offer. The SDP is therefore the supported carrier for
47
+ * fresh local credentials.
48
+ */
49
+ export declare function rewriteIceCredentials(sdp: string): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjsify/webrtc",
3
- "version": "0.45.0",
3
+ "version": "0.47.0",
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",
@@ -61,20 +61,21 @@
61
61
  "peer-connection"
62
62
  ],
63
63
  "dependencies": {
64
- "@gjsify/buffer": "^0.45.0",
65
- "@gjsify/dom-events": "^0.45.0",
66
- "@gjsify/dom-exception": "^0.45.0",
67
- "@gjsify/webrtc-native": "^0.45.0"
64
+ "@gjsify/buffer": "^0.47.0",
65
+ "@gjsify/dom-events": "^0.47.0",
66
+ "@gjsify/dom-exception": "^0.47.0",
67
+ "@gjsify/webcrypto": "^0.47.0",
68
+ "@gjsify/webrtc-native": "^0.47.0"
68
69
  },
69
70
  "devDependencies": {
70
- "@girs/gjs": "^4.1.0",
71
- "@girs/glib-2.0": "^4.1.0",
72
- "@girs/gobject-2.0": "^4.1.0",
73
- "@girs/gst-1.0": "^4.1.0",
74
- "@girs/gstsdp-1.0": "^4.1.0",
75
- "@girs/gstwebrtc-1.0": "^4.1.0",
76
- "@gjsify/cli": "^0.45.0",
77
- "@gjsify/unit": "^0.45.0",
71
+ "@girs/gjs": "4.6.0",
72
+ "@girs/glib-2.0": "4.6.0",
73
+ "@girs/gobject-2.0": "4.6.0",
74
+ "@girs/gst-1.0": "4.6.0",
75
+ "@girs/gstsdp-1.0": "4.6.0",
76
+ "@girs/gstwebrtc-1.0": "4.6.0",
77
+ "@gjsify/cli": "^0.47.0",
78
+ "@gjsify/unit": "^0.47.0",
78
79
  "@types/node": "^25.9.2",
79
80
  "typescript": "^6.0.3"
80
81
  },