@gjsify/webaudio 0.18.0 → 0.20.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{AudioNode as e}from"./audio-node.js";import{AudioParam as t}from"./audio-param.js";import{GstPlayer as n}from"./gst-player.js";import{GainNode as r}from"./gain-node.js";var AudioBufferSourceNode=class extends e{buffer=null;loop=!1;loopStart=0;loopEnd=0;playbackRate;onended=null;_player=null;_started=!1;constructor(){super(0,1),this.playbackRate=new t(1,.0625,16)}start(e=0,t=0,r){if(this._started)throw new DOMException(`AudioBufferSourceNode can only be started once`,`InvalidStateError`);if(this._started=!0,!this.buffer)return;let i=this._findGainNode(),a=i?i.gain.value:1;this._player=new n({audioBuffer:this.buffer,volume:a,loop:this.loop,offset:t,duration:r,playbackRate:this.playbackRate.value,onEnded:()=>{i&&i._activePlayers.delete(this._player),this._player=null,this.onended?.()}}),i&&this._player&&i._activePlayers.add(this._player)}stop(e=0){this._player&&this._player.stop()}_findGainNode(){for(let e of this._outputs){if(e instanceof r)return e;for(let t of e._outputs)if(t instanceof r)return t}return null}};export{AudioBufferSourceNode};
1
+ import"./_virtual/_rolldown/runtime.js";import{AudioNode as e}from"./audio-node.js";import{AudioParam as t}from"./audio-param.js";import{GstPlayer as n}from"./gst-player.js";import{GainNode as r}from"./gain-node.js";var AudioBufferSourceNode=class extends e{buffer=null;loop=!1;loopStart=0;loopEnd=0;playbackRate;onended=null;_player=null;_started=!1;constructor(){super(0,1),this.playbackRate=new t(1,.0625,16)}start(e=0,t=0,r){if(this._started)throw new DOMException(`AudioBufferSourceNode can only be started once`,`InvalidStateError`);if(this._started=!0,!this.buffer)return;let i=this._findGainNode(),a=i?i.gain.value:1;try{this._player=new n({audioBuffer:this.buffer,volume:a,loop:this.loop,offset:t,duration:r,playbackRate:this.playbackRate.value,onEnded:()=>{i&&i._activePlayers.delete(this._player),this._player=null,this.onended?.()}})}catch(e){console.warn(`[webaudio] AudioBufferSourceNode.start: GStreamer playback unavailable, continuing silent:`,e),this._player=null,queueMicrotask(()=>this.onended?.());return}i&&this._player&&i._activePlayers.add(this._player)}stop(e=0){this._player&&this._player.stop()}_findGainNode(){for(let e of this._outputs){if(e instanceof r)return e;for(let t of e._outputs)if(t instanceof r)return t}return null}};export{AudioBufferSourceNode};
@@ -1 +1 @@
1
- import"./_virtual/_rolldown/runtime.js";import{Gst as e,ensureGstInit as t}from"./gst-init.js";import{AudioBuffer as n}from"./audio-buffer.js";import"gi://GstApp?version=1.0";function decodeAudioDataSync(r){if(t(),!(r instanceof ArrayBuffer)||r.byteLength===0)throw new DOMException(`Unable to decode audio data`,`EncodingError`);let i=e.parse_launch(`appsrc name=src ! decodebin ! audioconvert ! audioresample ! capsfilter caps=audio/x-raw,format=F32LE,layout=interleaved ! appsink name=sink sync=false`),a=i.get_by_name(`src`),o=i.get_by_name(`sink`);i.set_state(e.State.PLAYING);let s=new Uint8Array(r);a.push_buffer(e.Buffer.new_wrapped(s)),a.end_of_stream();let c=[],l=0,u=0;for(;;){let t=o.try_pull_sample(2*Number(e.SECOND));if(!t)break;if(l===0){let e=t.get_caps();if(e){let t=e.get_structure(0);[,l]=t.get_int(`rate`),[,u]=t.get_int(`channels`)}}let n=t.get_buffer();if(!n)continue;let[r,i]=n.map(e.MapFlags.READ);r&&(c.push(new Uint8Array(i.data)),n.unmap(i))}if(i.set_state(e.State.NULL),l===0||u===0)throw new DOMException(`Unable to decode audio data`,`EncodingError`);let d=0;for(let e of c)d+=e.length;let f=d/(4*u),p=new n({numberOfChannels:u,length:f,sampleRate:l}),m=0;for(let e of c){let t=new Float32Array(e.buffer,e.byteOffset,e.length/4),n=t.length/u;for(let e=0;e<n;e++)for(let n=0;n<u;n++)p._channelData[n][m+e]=t[e*u+n];m+=n}return p}export{decodeAudioDataSync};
1
+ import"./_virtual/_rolldown/runtime.js";import{Gst as e,ensureGstInit as t,isGstStreamingUnsafe as n}from"./gst-init.js";import{AudioBuffer as r}from"./audio-buffer.js";import"gi://GstApp?version=1.0";function decodeAudioDataSync(i){if(n()||(t(),!(i instanceof ArrayBuffer)||i.byteLength===0))throw new DOMException(`Unable to decode audio data`,`EncodingError`);let a=e.parse_launch(`appsrc name=src ! decodebin ! audioconvert ! audioresample ! capsfilter caps=audio/x-raw,format=F32LE,layout=interleaved ! appsink name=sink sync=false`),o=a.get_by_name(`src`),s=a.get_by_name(`sink`);a.set_state(e.State.PLAYING);let c=new Uint8Array(i);o.push_buffer(e.Buffer.new_wrapped(c)),o.end_of_stream();let l=[],u=0,d=0;for(;;){let t=s.try_pull_sample(2*Number(e.SECOND));if(!t)break;if(u===0){let e=t.get_caps();if(e){let t=e.get_structure(0);[,u]=t.get_int(`rate`),[,d]=t.get_int(`channels`)}}let n=t.get_buffer();if(!n)continue;let[r,i]=n.map(e.MapFlags.READ);r&&(l.push(new Uint8Array(i.data)),n.unmap(i))}if(a.set_state(e.State.NULL),u===0||d===0)throw new DOMException(`Unable to decode audio data`,`EncodingError`);let f=0;for(let e of l)f+=e.length;let p=f/(4*d),m=new r({numberOfChannels:d,length:p,sampleRate:u}),h=0;for(let e of l){let t=new Float32Array(e.buffer,e.byteOffset,e.length/4),n=t.length/d;for(let e=0;e<n;e++)for(let n=0;n<d;n++)m._channelData[n][h+e]=t[e*d+n];h+=n}return m}export{decodeAudioDataSync};
@@ -1 +1 @@
1
- import"./_virtual/_rolldown/runtime.js";import e from"gi://Gst?version=1.0";let t=!1;function ensureGstInit(){t||=(e.init(null),!0)}export{e as Gst,ensureGstInit};
1
+ import"./_virtual/_rolldown/runtime.js";import e from"gi://Gst?version=1.0";let t=!1;function ensureGstInit(){t||=(e.init(null),!0)}function isGstStreamingUnsafe(){let e=globalThis;return e.Bun!==void 0||e.Deno!==void 0}export{e as Gst,ensureGstInit,isGstStreamingUnsafe};
@@ -1,3 +1,25 @@
1
1
  import Gst from 'gi://Gst?version=1.0';
2
2
  export declare function ensureGstInit(): void;
3
+ /**
4
+ * Whether a GStreamer pipeline that spins its own streaming threads
5
+ * (`decodebin`, `playbin`, …) is UNSAFE to run on the current runtime.
6
+ *
7
+ * Under the `@gjsify/node-gi` reverse bridge, **bun** and **deno** drive the
8
+ * GLib main context with a pure `iterateMainContext` pump and no libuv
9
+ * coupling. GStreamer's own streaming threads then race the JS engine's
10
+ * garbage collector during pipeline teardown (a GObject finalize firing on a
11
+ * streaming thread while the engine drains its toggle-ref queue) and
12
+ * NONDETERMINISTICALLY segfault the process — reproduced on bun with the
13
+ * synchronous `decodebin` decode path; deno shares the same pump so is guarded
14
+ * defensively. GJS (native GStreamer) and Node (uv-coupled main loop) drive the
15
+ * identical pipeline safely, so they are NOT affected.
16
+ *
17
+ * Callers use this to fail cleanly (a rejected `EncodingError`, which every
18
+ * WebAudio consumer already handles) instead of crashing. This closes no
19
+ * working capability: GStreamer decode does not function on the node target at
20
+ * all (decodebin returns no samples via the reverse bridge), so the only
21
+ * behavior change is turning a nondeterministic crash into a clean rejection.
22
+ * Tracked as a node-gi GStreamer-threading follow-up.
23
+ */
24
+ export declare function isGstStreamingUnsafe(): boolean;
3
25
  export { Gst };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjsify/webaudio",
3
- "version": "0.18.0",
3
+ "version": "0.20.0",
4
4
  "description": "Web Audio API for GJS using GStreamer as audio backend",
5
5
  "type": "module",
6
6
  "module": "lib/esm/index.js",
@@ -42,7 +42,7 @@
42
42
  "audio-api"
43
43
  ],
44
44
  "dependencies": {
45
- "@gjsify/dom-events": "^0.18.0"
45
+ "@gjsify/dom-events": "^0.20.0"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@girs/gjs": "^4.1.0",
@@ -51,8 +51,8 @@
51
51
  "@girs/gstapp-1.0": "^4.1.0",
52
52
  "@girs/gstaudio-1.0": "^4.1.0",
53
53
  "@girs/gstbase-1.0": "^4.1.0",
54
- "@gjsify/cli": "^0.18.0",
55
- "@gjsify/unit": "^0.18.0",
54
+ "@gjsify/cli": "^0.20.0",
55
+ "@gjsify/unit": "^0.20.0",
56
56
  "@types/node": "^25.9.2",
57
57
  "typescript": "^6.0.3"
58
58
  },