@gjsify/webrtc 0.51.1 → 0.53.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -14,6 +14,12 @@ npm install @gjsify/webrtc
14
14
  yarn add @gjsify/webrtc
15
15
  ```
16
16
 
17
+ The GStreamer side comes from the system: `webrtcbin` (gst-plugins-bad) and libnice's
18
+ GStreamer plugin for ICE. On Fedora `dnf install gstreamer1-plugins-bad-free libnice-gstreamer1`,
19
+ on Debian/Ubuntu `apt install gstreamer1.0-plugins-bad gstreamer1.0-nice`, on macOS
20
+ `brew install gstreamer libnice-gstreamer`. The native bridge (`@gjsify/webrtc-native`)
21
+ ships prebuilt for `linux-{x64,arm64,ppc64,s390x,riscv64}` and `darwin-{arm64,x64}`.
22
+
17
23
  ## Usage
18
24
 
19
25
  ```typescript
@@ -40,6 +46,33 @@ pc.onicecandidate = (event) => {
40
46
  };
41
47
  ```
42
48
 
49
+ ## Audio device selection
50
+
51
+ On `ensureGstInit()` (the first `RTCPeerConnection`, `getUserMedia`, or any
52
+ other GStreamer-touching call), this package sets the `openalsrc` and
53
+ `openalsink` GStreamer plugin features' rank to `Gst.Rank.NONE` in the
54
+ **process-wide** GStreamer registry — it affects every pipeline in the
55
+ process, including ones built outside this package.
56
+
57
+ Why: `getUserMedia({ audio: true })`'s capture source falls through to
58
+ `autoaudiosrc` when PipeWire/Pulse/V4L2 aren't reachable, and `autoaudiosrc`
59
+ tries registered audio sources in rank order until one opens. `openalsrc`
60
+ (and its sink counterpart, reachable the same way through `autoaudiosink`)
61
+ is the one candidate whose `open()` does not fail fast: OpenAL Soft's
62
+ device backend runs its own nested connection probe synchronously inside
63
+ the GStreamer state change, which can stall the whole process for tens of
64
+ seconds (measured in CI — `[ALSOFT] Failed to connect PipeWire` followed by
65
+ 30+ seconds of silence, hit while moving a shared track's source between
66
+ peer connections). `autoaudiosrc`/`autoaudiosink` already fall back to
67
+ `audiotestsrc`/`fakesink` when nothing opens, in well under 100ms —
68
+ deranking `openalsrc`/`openalsink` restores that existing fallback instead
69
+ of leaving it reachable through the one candidate that defeats it.
70
+
71
+ Set `GJSIFY_GST_KEEP_OPENAL=1` to opt out, if a host genuinely needs OpenAL
72
+ Soft as its audio backend. This also un-deranks `openalsink` for
73
+ `@gjsify/webaudio` if both are loaded in the same process — the two
74
+ packages share the one GStreamer registry.
75
+
43
76
  ## License
44
77
 
45
78
  MIT
@@ -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 _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
+ 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(t),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(t),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)}const a=[`device`,`target_object`,`path`],o=new Set;function _bindDevice(e,t,n){if(n){for(let e of a)if(e in t){t[e]=n;return}o.has(e)||(o.add(e),console.warn(`getUserMedia: deviceId ${JSON.stringify(n)} ignored — ${t.name} has no device property, so the ${e} source is the host default. getSupportedConstraints() reports deviceId: true.`))}}function _createAudioSource(e){let t=_chooseSource(`audio`,[`pipewiresrc`,`pulsesrc`,`autoaudiosrc`],`audioconvert`,`audiotestsrc`);try{t.is_live=!0}catch{}return i.get(`audio`)===`audiotestsrc`&&(t.wave=0),_bindDevice(`audio`,t,e.deviceId),t}function _createVideoSource(e){let t=_chooseSource(`video`,[`pipewiresrc`,`v4l2src`,`autovideosrc`],`videoconvert`,`videotestsrc`);return i.get(`video`)===`videotestsrc`&&(t.is_live=!0,t.pattern=0),_bindDevice(`video`,t,e.deviceId),t}export{getUserMedia};
@@ -1,11 +1,13 @@
1
- import"./_virtual/_rolldown/runtime.js";import e from"gi://Gst?version=1.0";import{DOMException as t}from"@gjsify/dom-exception";let n=!1;function ensureGstInit(){n||=(e.init(null),!0)}function ensureWebrtcbinAvailable(){ensureGstInit(),e.ElementFactory.find(`webrtcbin`)||throwNotSupported(e.ElementFactory.find(`dtlsenc`)!==null||e.ElementFactory.find(`sctpenc`)!==null?`GStreamer element "webrtcbin" not available, but gst-plugins-bad IS installed
1
+ import"./_virtual/_rolldown/runtime.js";import e from"gi://Gst?version=1.0";import t from"gi://GLib?version=2.0";import{DOMException as n}from"@gjsify/dom-exception";let r=!1;const i=[`openalsrc`,`openalsink`];function excludeUnboundedAutodetectCandidates(n=t.getenv(`GJSIFY_GST_KEEP_OPENAL`)===`1`){if(n)return;let r=e.Registry.get();for(let t of i)r.lookup_feature(t)?.set_rank(e.Rank.NONE)}function ensureGstInit(){r||=(e.init(null),excludeUnboundedAutodetectCandidates(),!0)}function ensureWebrtcbinAvailable(){ensureGstInit(),e.ElementFactory.find(`webrtcbin`)||throwNotSupported(e.ElementFactory.find(`dtlsenc`)!==null||e.ElementFactory.find(`sctpenc`)!==null?`GStreamer element "webrtcbin" not available, but gst-plugins-bad IS installed
2
2
  (its dtls/sctp elements are registered). This distro does not ship the
3
3
  plugin — verify with: ls /usr/lib/gstreamer-1.0/libgstwebrtc.so
4
4
  Alpine/postmarketOS: absent since Alpine v3.24; no package provides it.
5
5
  Otherwise: install the plugin from source, or use a distro that ships it.`:`GStreamer element "webrtcbin" not available. Install gst-plugins-bad:
6
6
  Fedora: dnf install gstreamer1-plugins-bad-free gstreamer1-plugins-bad-free-extras
7
7
  Ubuntu/Debian: apt install gstreamer1.0-plugins-bad
8
- Alpine/postmarketOS: apk add gst-plugins-bad`),e.ElementFactory.find(`nicesrc`)||throwNotSupported(`GStreamer "nice" plugin (libnice-gstreamer) not available — required by webrtcbin.
8
+ Alpine/postmarketOS: apk add gst-plugins-bad
9
+ macOS (Homebrew): brew install gstreamer`),e.ElementFactory.find(`nicesrc`)||throwNotSupported(`GStreamer "nice" plugin (libnice-gstreamer) not available — required by webrtcbin.
9
10
  Fedora: dnf install libnice-gstreamer1
10
11
  Ubuntu/Debian: apt install gstreamer1.0-nice
11
- Verify with: gst-inspect-1.0 nicesrc`)}function throwNotSupported(e){throw new t(e,`NotSupportedError`)}export{e as Gst,ensureGstInit,ensureWebrtcbinAvailable};
12
+ macOS: brew install libnice-gstreamer
13
+ Verify with: gst-inspect-1.0 nicesrc`)}function throwNotSupported(e){throw new n(e,`NotSupportedError`)}export{e as Gst,ensureGstInit,ensureWebrtcbinAvailable,excludeUnboundedAutodetectCandidates};
@@ -1 +1 @@
1
- import"./_virtual/_rolldown/runtime.js";import{Gst as e,ensureGstInit as t}from"./gst-init.js";import{getUserMedia as n}from"./get-user-media.js";import{MediaDeviceInfo as r}from"./media-device-info.js";import"@gjsify/dom-events/register/event-target";import i from"gi://GLib?version=2.0";const a={"Audio/Source":`audioinput`,"Video/Source":`videoinput`,"Audio/Sink":`audiooutput`};let o=!1;function isDeviceMonitorSafe(){return!(i.getenv(`CI`)||!i.getenv(`DISPLAY`)&&!i.getenv(`WAYLAND_DISPLAY`))}var MediaDevices=class extends EventTarget{_ondevicechange=null;get ondevicechange(){return this._ondevicechange}set ondevicechange(e){this._ondevicechange=e}async getUserMedia(e){if(!e)throw TypeError(`Failed to execute 'getUserMedia' on 'MediaDevices': At least one of audio or video must be requested`);let t=await n(e);return o=!0,t}async enumerateDevices(){t();let n=null,i=[];try{if(!isDeviceMonitorSafe())return i;n=new e.DeviceMonitor,n.set_show_all_devices(!0);let t=e.Caps.from_string(`audio/x-raw`),s=e.Caps.from_string(`video/x-raw`);if(t&&(n.add_filter(`Audio/Source`,t),n.add_filter(`Audio/Sink`,t)),s&&n.add_filter(`Video/Source`,s),!n.start())return i;let c;try{c=n.get_devices()??[]}catch{return i}for(let e of c){let t=e.get_device_class?.()??``,n=a[t];if(!n)continue;let s=e.get_display_name?.()??``,c=``,l=``;try{let t=e.get_properties?.();if(t){let e=t.n_fields();for(let n=0;n<e;n++){let e=t.nth_field_name(n);if(e===`persistent-id`||e===`node.name`){let n=t.get_value(e);n&&!c&&(c=String(n))}if(e===`group-id`){let n=t.get_value(e);n&&(l=String(n))}}}}catch{}c||=s||`${n}-${i.length}`,o?i.push(new r({deviceId:c,kind:n,label:s,groupId:l})):i.some(e=>e.kind===n)||i.push(new r({deviceId:``,kind:n,label:``,groupId:``}))}}catch{return i}finally{try{n?.stop()}catch{}}let s={audioinput:0,videoinput:1,audiooutput:2};return i.sort((e,t)=>(s[e.kind]??3)-(s[t.kind]??3)),i}getSupportedConstraints(){return{deviceId:!0,width:!0,height:!0,frameRate:!0,sampleRate:!0,channelCount:!0,aspectRatio:!1,facingMode:!1,resizeMode:!1,echoCancellation:!1,autoGainControl:!1,noiseSuppression:!1,latency:!1,groupId:!1}}};export{MediaDevices};
1
+ import"./_virtual/_rolldown/runtime.js";import{Gst as e,ensureGstInit as t}from"./gst-init.js";import{getUserMedia as n}from"./get-user-media.js";import{MediaDeviceInfo as r}from"./media-device-info.js";import i from"gi://GLib?version=2.0";import"@gjsify/dom-events/register/event-target";const a={"Audio/Source":`audioinput`,"Video/Source":`videoinput`,"Audio/Sink":`audiooutput`};let o=!1;function isDeviceMonitorSafe(){return!(i.getenv(`CI`)||!i.getenv(`DISPLAY`)&&!i.getenv(`WAYLAND_DISPLAY`))}var MediaDevices=class extends EventTarget{_ondevicechange=null;get ondevicechange(){return this._ondevicechange}set ondevicechange(e){this._ondevicechange=e}async getUserMedia(e){if(!e)throw TypeError(`Failed to execute 'getUserMedia' on 'MediaDevices': At least one of audio or video must be requested`);let t=await n(e);return o=!0,t}async enumerateDevices(){t();let n=null,i=[];try{if(!isDeviceMonitorSafe())return i;n=new e.DeviceMonitor,n.set_show_all_devices(!0);let t=e.Caps.from_string(`audio/x-raw`),s=e.Caps.from_string(`video/x-raw`);if(t&&(n.add_filter(`Audio/Source`,t),n.add_filter(`Audio/Sink`,t)),s&&n.add_filter(`Video/Source`,s),!n.start())return i;let c;try{c=n.get_devices()??[]}catch{return i}for(let e of c){let t=e.get_device_class?.()??``,n=a[t];if(!n)continue;let s=e.get_display_name?.()??``,c=``,l=``;try{let t=e.get_properties?.();if(t){let e=t.n_fields();for(let n=0;n<e;n++){let e=t.nth_field_name(n);if(e===`persistent-id`||e===`node.name`){let n=t.get_value(e);n&&!c&&(c=String(n))}if(e===`group-id`){let n=t.get_value(e);n&&(l=String(n))}}}}catch{}c||=s||`${n}-${i.length}`,o?i.push(new r({deviceId:c,kind:n,label:s,groupId:l})):i.some(e=>e.kind===n)||i.push(new r({deviceId:``,kind:n,label:``,groupId:``}))}}catch{return i}finally{try{n?.stop()}catch{}}let s={audioinput:0,videoinput:1,audiooutput:2};return i.sort((e,t)=>(s[e.kind]??3)-(s[t.kind]??3)),i}getSupportedConstraints(){return{deviceId:!0,width:!0,height:!0,frameRate:!0,sampleRate:!0,channelCount:!0,aspectRatio:!1,facingMode:!1,resizeMode:!1,echoCancellation:!1,autoGainControl:!1,noiseSuppression:!1,latency:!1,groupId:!1}}};export{MediaDevices};
@@ -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;_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
+ import"./_virtual/_rolldown/runtime.js";import{Gst as e}from"./gst-init.js";import t from"gi://GLib?version=2.0";import"@gjsify/dom-events/register/event-target";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"@gjsify/dom-events/register/event-target";import e from"gi://GLib?version=2.0";var t=class MediaStream extends EventTarget{id;_tracks=new Map;_onaddtrack=null;_onremovetrack=null;constructor(t){if(super(),this.id=e.uuid_string_random(),t instanceof MediaStream)for(let e of t.getTracks())this._tracks.set(e.id,e.clone());else if(Array.isArray(t))for(let e of t)this._tracks.set(e.id,e)}get active(){for(let e of this._tracks.values())if(e.readyState===`live`)return!0;return!1}get onaddtrack(){return this._onaddtrack}set onaddtrack(e){this._onaddtrack=e}get onremovetrack(){return this._onremovetrack}set onremovetrack(e){this._onremovetrack=e}getTracks(){return[...this._tracks.values()]}getAudioTracks(){return this.getTracks().filter(e=>e.kind===`audio`)}getVideoTracks(){return this.getTracks().filter(e=>e.kind===`video`)}getTrackById(e){return this._tracks.get(e)??null}addTrack(e){if(this._tracks.has(e.id))return;this._tracks.set(e.id,e);let t=new MediaStreamTrackEvent(`addtrack`,{track:e});this._onaddtrack?.call(this,t),this.dispatchEvent(t)}removeTrack(e){if(!this._tracks.delete(e.id))return;let t=new MediaStreamTrackEvent(`removetrack`,{track:e});this._onremovetrack?.call(this,t),this.dispatchEvent(t)}clone(){return new MediaStream(this)}},MediaStreamTrackEvent=class extends Event{track;constructor(e,t){super(e,t),this.track=t.track}};export{t as MediaStream,MediaStreamTrackEvent};
1
+ import"./_virtual/_rolldown/runtime.js";import e from"gi://GLib?version=2.0";import"@gjsify/dom-events/register/event-target";var t=class MediaStream extends EventTarget{id;_tracks=new Map;_onaddtrack=null;_onremovetrack=null;constructor(t){if(super(),this.id=e.uuid_string_random(),t instanceof MediaStream)for(let e of t.getTracks())this._tracks.set(e.id,e.clone());else if(Array.isArray(t))for(let e of t)this._tracks.set(e.id,e)}get active(){for(let e of this._tracks.values())if(e.readyState===`live`)return!0;return!1}get onaddtrack(){return this._onaddtrack}set onaddtrack(e){this._onaddtrack=e}get onremovetrack(){return this._onremovetrack}set onremovetrack(e){this._onremovetrack=e}getTracks(){return[...this._tracks.values()]}getAudioTracks(){return this.getTracks().filter(e=>e.kind===`audio`)}getVideoTracks(){return this.getTracks().filter(e=>e.kind===`video`)}getTrackById(e){return this._tracks.get(e)??null}addTrack(e){if(this._tracks.has(e.id))return;this._tracks.set(e.id,e);let t=new MediaStreamTrackEvent(`addtrack`,{track:e});this._onaddtrack?.call(this,t),this.dispatchEvent(t)}removeTrack(e){if(!this._tracks.delete(e.id))return;let t=new MediaStreamTrackEvent(`removetrack`,{track:e});this._onremovetrack?.call(this,t),this.dispatchEvent(t)}clone(){return new MediaStream(this)}},MediaStreamTrackEvent=class extends Event{track;constructor(e,t){super(e,t),this.track=t.track}};export{t as MediaStream,MediaStreamTrackEvent};
@@ -1 +1 @@
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
+ import{MediaDevices as e}from"../media-devices.js";import"@gjsify/node-globals/register/navigator";const t=globalThis;t.navigator.mediaDevices===void 0&&(t.navigator.mediaDevices=new e);
@@ -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,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;_sctpTransport=null;constructor(e,t){super(),this._sctpTransport=t??null;let n=e;n.channel!==void 0&&typeof n.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`){let t=new TextEncoder().encode(e).byteLength;this._enforceMaxMessageSize(t),this._native.send_string(e),this._bufferedAmount+=t;return}if(e instanceof a){e.arrayBuffer().then(e=>{try{this._enforceMaxMessageSize(e.byteLength)}catch(e){this._handleError(e instanceof Error?e.message:String(e));return}try{this._native.send_data(toGBytes(e)),this._bufferedAmount+=e.byteLength}catch{}});return}if(ArrayBuffer.isView(e)){this._enforceMaxMessageSize(e.byteLength);let t=toGBytes(e);this._native.send_data(t),this._bufferedAmount+=e.byteLength;return}if(e instanceof ArrayBuffer){this._enforceMaxMessageSize(e.byteLength);let t=toGBytes(e);this._native.send_data(t),this._bufferedAmount+=e.byteLength;return}throw TypeError(`RTCDataChannel.send: unsupported data type`)}_enforceMaxMessageSize(e){if(!this._sctpTransport)return;let t=this._sctpTransport.maxMessageSize;if(!(t<=0)&&e>t)throw new n(`RTCDataChannel.send: data (${e} bytes) exceeds the SCTP max-message-size of ${t} bytes. Split into smaller frames before sending.`,`OperationError`)}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};
1
+ import"./_virtual/_rolldown/runtime.js";import{RTCError as e}from"./rtc-error.js";import{RTCErrorEvent as t}from"./rtc-events.js";import n from"gi://GLib?version=2.0";import{DOMException as r}from"@gjsify/dom-exception";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 n.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;_sctpTransport=null;constructor(e,t){super(),this._sctpTransport=t??null;let n=e;n.channel!==void 0&&typeof n.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 r(`RTCDataChannel.send: readyState is '${t}', expected 'open'`,`InvalidStateError`);if(typeof e==`string`){let t=new TextEncoder().encode(e).byteLength;this._enforceMaxMessageSize(t),this._native.send_string(e),this._bufferedAmount+=t;return}if(e instanceof a){e.arrayBuffer().then(e=>{try{this._enforceMaxMessageSize(e.byteLength)}catch(e){this._handleError(e instanceof Error?e.message:String(e));return}try{this._native.send_data(toGBytes(e)),this._bufferedAmount+=e.byteLength}catch{}});return}if(ArrayBuffer.isView(e)){this._enforceMaxMessageSize(e.byteLength);let t=toGBytes(e);this._native.send_data(t),this._bufferedAmount+=e.byteLength;return}if(e instanceof ArrayBuffer){this._enforceMaxMessageSize(e.byteLength);let t=toGBytes(e);this._native.send_data(t),this._bufferedAmount+=e.byteLength;return}throw TypeError(`RTCDataChannel.send: unsupported data type`)}_enforceMaxMessageSize(e){if(!this._sctpTransport)return;let t=this._sctpTransport.maxMessageSize;if(!(t<=0)&&e>t)throw new r(`RTCDataChannel.send: data (${e} bytes) exceeds the SCTP max-message-size of ${t} bytes. Split into smaller frames before sending.`,`OperationError`)}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};
@@ -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,emitWebRtcBin as l}from"./internal/gst-types.js";import{RTCSessionDescription as u}from"./rtc-session-description.js";import{RTCIceCandidate as d}from"./rtc-ice-candidate.js";import{RTCDataChannelEvent as f,RTCPeerConnectionIceEvent as p}from"./rtc-events.js";import{RTCDataChannel as m}from"./rtc-data-channel.js";import{RTCRtpSender as h}from"./rtc-rtp-sender.js";import{RTCRtpReceiver as g}from"./rtc-rtp-receiver.js";import{RTCRtpTransceiver as _}from"./rtc-rtp-transceiver.js";import{RTCTrackEvent as v}from"./rtc-track-event.js";import{RTCIceTransport as y}from"./rtc-ice-transport.js";import{RTCDtlsTransport as b}from"./rtc-dtls-transport.js";import{RTCSctpTransport as x}from"./rtc-sctp-transport.js";import{RTCCertificate as S,generateCertificate as C}from"./rtc-certificate.js";import{installSdpNegotiationMethods as w}from"./rtc-peer-connection/sdp-negotiation.js";import{installDataChannelMethods as T}from"./rtc-peer-connection/data-channel.js";import{installTransceiverMethods as E}from"./rtc-peer-connection/transceivers.js";import{installTrackMethods as D}from"./rtc-peer-connection/tracks.js";import{installStatsAndConfigMethods as O}from"./rtc-peer-connection/stats-and-config.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";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 S&&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;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{l(this._webrtcbin,`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`?j.WebRTCICETransportPolicy.RELAY:j.WebRTCICETransportPolicy.ALL;try{s(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{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?u.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`)}_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()}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}))}getIdentityAssertion(){return Promise.reject(Error(`getIdentityAssertion is not implemented`))}_findNewGstTransceiver(){for(let e=0;;e++){let t=l(this._webrtcbin,`get-transceiver`,e);if(!t)return null;if(!this._transceivers.has(t))return t}}_ensureTransports(){return this._dtlsTransport||=(this._iceTransport=new y,new b(this._iceTransport)),this._dtlsTransport}_ensureSctpTransport(){if(this._sctpTransport)return;let e=this._ensureTransports();this._sctpTransport=new x(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===j.WebRTCKind.VIDEO&&(t=`video`)}catch{}let n=e.receiver??null,r=e.sender??null,i=new g(t,n,this._pipeline),a=new h(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 _(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 p(`icecandidate`,{candidate:new d({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 v(`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 m(e,this._sctpTransport??void 0),this._dataChannels.set(t,n),n.addEventListener(`close`,()=>{this._dataChannels.delete(t)}));let r=new f(`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 C(e)}};w(RTCPeerConnection.prototype),T(RTCPeerConnection.prototype),E(RTCPeerConnection.prototype),D(RTCPeerConnection.prototype),O(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,emitWebRtcBin as l}from"./internal/gst-types.js";import{RTCSessionDescription as u}from"./rtc-session-description.js";import{RTCIceCandidate as d}from"./rtc-ice-candidate.js";import{RTCDataChannelEvent as f,RTCPeerConnectionIceEvent as p}from"./rtc-events.js";import{RTCDataChannel as m}from"./rtc-data-channel.js";import{RTCRtpSender as h}from"./rtc-rtp-sender.js";import{RTCRtpReceiver as g}from"./rtc-rtp-receiver.js";import{RTCRtpTransceiver as _}from"./rtc-rtp-transceiver.js";import{RTCTrackEvent as v}from"./rtc-track-event.js";import{RTCIceTransport as y}from"./rtc-ice-transport.js";import{RTCDtlsTransport as b}from"./rtc-dtls-transport.js";import{RTCSctpTransport as x}from"./rtc-sctp-transport.js";import{RTCCertificate as S,generateCertificate as C}from"./rtc-certificate.js";import{installSdpNegotiationMethods as w}from"./rtc-peer-connection/sdp-negotiation.js";import{installDataChannelMethods as T}from"./rtc-peer-connection/data-channel.js";import{installTransceiverMethods as E}from"./rtc-peer-connection/transceivers.js";import{installTrackMethods as D}from"./rtc-peer-connection/tracks.js";import{installStatsAndConfigMethods as O}from"./rtc-peer-connection/stats-and-config.js";import k from"gi://GLib?version=2.0";import{DOMException as A}from"@gjsify/dom-exception";import j from"gi://GstWebRTC?version=1.0";import{WebrtcbinBridge as M}from"@gjsify/webrtc-native";import N from"gi://GObject?version=2.0";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 A(`@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 S&&e.expires<=Date.now())throw new A(`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;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{l(this._webrtcbin,`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`?j.WebRTCICETransportPolicy.RELAY:j.WebRTCICETransportPolicy.ALL;try{s(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{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?u.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 A(`RTCPeerConnection.${e}: connection is closed`,`InvalidStateError`)}_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()}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=l(this._webrtcbin,`get-transceiver`,e);if(!t)return null;if(!this._transceivers.has(t))return t}}_ensureTransports(){return this._dtlsTransport||=(this._iceTransport=new y,new b(this._iceTransport)),this._dtlsTransport}_ensureSctpTransport(){if(this._sctpTransport)return;let e=this._ensureTransports();this._sctpTransport=new x(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===j.WebRTCKind.VIDEO&&(t=`video`)}catch{}let n=e.receiver??null,r=e.sender??null,i=new g(t,n,this._pipeline),a=new h(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 _(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 p(`icecandidate`,{candidate:new d({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 v(`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 m(e,this._sctpTransport??void 0),this._dataChannels.set(t,n),n.addEventListener(`close`,()=>{this._dataChannels.delete(t)}));let r=new f(`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 C(e)}};w(RTCPeerConnection.prototype),T(RTCPeerConnection.prototype),E(RTCPeerConnection.prototype),D(RTCPeerConnection.prototype),O(RTCPeerConnection.prototype);export{RTCPeerConnection};
@@ -1 +1 @@
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
+ 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;function releaseDownstreamStreamingThread(t){if(!t)return;let n=e.Event.new_flush_start();t.direction===e.PadDirection.SRC?t.push_event(n):t.send_event(n)}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&&(releaseDownstreamStreamingThread(n),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 t=i.requestSrcPad();t&&t.link(r),r.send_event(e.Event.new_flush_stop(!0))}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)),releaseDownstreamStreamingThread(this._valve?.get_static_pad(`sink`)),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};
@@ -0,0 +1,2 @@
1
+ declare const _default: () => Promise<void>;
2
+ export default _default;
@@ -1,4 +1,6 @@
1
1
  import Gst from 'gi://Gst?version=1.0';
2
+ /** TEST SEAM (exported) — see the `keepOpenal` parameter doc above. */
3
+ export declare function excludeUnboundedAutodetectCandidates(keepOpenal?: boolean): void;
2
4
  export declare function ensureGstInit(): void;
3
5
  /** Throws if the `webrtcbin` element is not registered (gst-plugins-bad missing). */
4
6
  export declare function ensureWebrtcbinAvailable(): void;
@@ -1 +1 @@
1
- export {};
1
+ import '@gjsify/node-globals/register/navigator';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjsify/webrtc",
3
- "version": "0.51.1",
3
+ "version": "0.53.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,21 +61,23 @@
61
61
  "peer-connection"
62
62
  ],
63
63
  "dependencies": {
64
- "@gjsify/buffer": "^0.51.1",
65
- "@gjsify/dom-events": "^0.51.1",
66
- "@gjsify/dom-exception": "^0.51.1",
67
- "@gjsify/webcrypto": "^0.51.1",
68
- "@gjsify/webrtc-native": "^0.51.1"
64
+ "@gjsify/buffer": "^0.53.0",
65
+ "@gjsify/dom-events": "^0.53.0",
66
+ "@gjsify/dom-exception": "^0.53.0",
67
+ "@gjsify/node-globals": "^0.53.0",
68
+ "@gjsify/webcrypto": "^0.53.0",
69
+ "@gjsify/webrtc-native": "^0.53.0"
69
70
  },
70
71
  "devDependencies": {
71
- "@girs/gjs": "5.0.0",
72
- "@girs/glib-2.0": "5.0.0",
73
- "@girs/gobject-2.0": "5.0.0",
74
- "@girs/gst-1.0": "5.0.0",
75
- "@girs/gstsdp-1.0": "5.0.0",
76
- "@girs/gstwebrtc-1.0": "5.0.0",
77
- "@gjsify/cli": "^0.51.1",
78
- "@gjsify/unit": "^0.51.1",
72
+ "@girs/gio-2.0": "5.4.0",
73
+ "@girs/gjs": "5.4.0",
74
+ "@girs/glib-2.0": "5.4.0",
75
+ "@girs/gobject-2.0": "5.4.0",
76
+ "@girs/gst-1.0": "5.4.0",
77
+ "@girs/gstsdp-1.0": "5.4.0",
78
+ "@girs/gstwebrtc-1.0": "5.4.0",
79
+ "@gjsify/cli": "^0.53.0",
80
+ "@gjsify/unit": "^0.53.0",
79
81
  "@types/node": "^25.9.2",
80
82
  "typescript": "^6.0.3"
81
83
  },