@wvdsh/sdk-js 1.3.20 → 1.3.21
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/dist/index.d.ts +19 -0
- package/dist/index.js +75 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -43,17 +43,24 @@ declare abstract class WavedashManager {
|
|
|
43
43
|
* e.g. a PIXI/GDevelop intro video), force-muting it before playback begins
|
|
44
44
|
* regardless of how it was created — the one path the DOM-based sources and
|
|
45
45
|
* the `muted` setter all miss.
|
|
46
|
+
*
|
|
47
|
+
* Speech synthesis (`window.speechSynthesis`): bypasses both Web Audio and HTML
|
|
48
|
+
* media entirely, so it gets its own shim — `speak()` forces the utterance's
|
|
49
|
+
* native volume to 0 while muted.
|
|
46
50
|
*/
|
|
47
51
|
declare class AudioManager extends WavedashManager {
|
|
48
52
|
private _isMuted;
|
|
49
53
|
private contexts;
|
|
50
54
|
private elements;
|
|
51
55
|
private intendedMuted;
|
|
56
|
+
private intendedUtteranceVolume;
|
|
52
57
|
private originalAudioContext;
|
|
53
58
|
private originalWebKitAudioContext;
|
|
54
59
|
private originalAudio;
|
|
55
60
|
private originalMutedDescriptor;
|
|
56
61
|
private originalPlay;
|
|
62
|
+
private originalSpeak;
|
|
63
|
+
private originalUtteranceVolumeDescriptor;
|
|
57
64
|
private mutationObserver;
|
|
58
65
|
constructor(sdk: WavedashSDK);
|
|
59
66
|
isMuted(): boolean;
|
|
@@ -78,6 +85,18 @@ declare class AudioManager extends WavedashManager {
|
|
|
78
85
|
*/
|
|
79
86
|
private trackElement;
|
|
80
87
|
private installShims;
|
|
88
|
+
/**
|
|
89
|
+
* Shim `window.speechSynthesis` so speech respects the SDK mute state.
|
|
90
|
+
*
|
|
91
|
+
* Never swallows speak(): utterances have a lifecycle the game may sequence
|
|
92
|
+
* off (onstart/onend, synth.speaking/pending checks), so every call is
|
|
93
|
+
* delegated and silenced via volume instead. Volume is sampled at speak()
|
|
94
|
+
* time, so forcing the native value to 0 right before delegating silences
|
|
95
|
+
* anything spoken while muted; in-flight speech at the mute edge is
|
|
96
|
+
* deliberately left to finish (can't be softened mid-utterance, and
|
|
97
|
+
* cancel() would discard the pending queue).
|
|
98
|
+
*/
|
|
99
|
+
private shimSpeechSynthesis;
|
|
81
100
|
private shimAudioContextClass;
|
|
82
101
|
destroy(): void;
|
|
83
102
|
}
|
package/dist/index.js
CHANGED
|
@@ -124,12 +124,16 @@ var AudioManager = class extends WavedashManager {
|
|
|
124
124
|
// HTML media elements we know about + their game-intended muted state
|
|
125
125
|
this.elements = new WeakRefSet();
|
|
126
126
|
this.intendedMuted = /* @__PURE__ */ new WeakMap();
|
|
127
|
+
// Speech synthesis utterances + their game-intended volume
|
|
128
|
+
this.intendedUtteranceVolume = /* @__PURE__ */ new WeakMap();
|
|
127
129
|
// Originals (restored on destroy)
|
|
128
130
|
this.originalAudioContext = null;
|
|
129
131
|
this.originalWebKitAudioContext = null;
|
|
130
132
|
this.originalAudio = null;
|
|
131
133
|
this.originalMutedDescriptor = null;
|
|
132
134
|
this.originalPlay = null;
|
|
135
|
+
this.originalSpeak = null;
|
|
136
|
+
this.originalUtteranceVolumeDescriptor = null;
|
|
133
137
|
this.mutationObserver = null;
|
|
134
138
|
this.handleMute = (data) => {
|
|
135
139
|
if (this._isMuted === data.isMuted) return;
|
|
@@ -275,6 +279,66 @@ var AudioManager = class extends WavedashManager {
|
|
|
275
279
|
return originalPlay.call(this);
|
|
276
280
|
};
|
|
277
281
|
})(this);
|
|
282
|
+
this.shimSpeechSynthesis();
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Shim `window.speechSynthesis` so speech respects the SDK mute state.
|
|
286
|
+
*
|
|
287
|
+
* Never swallows speak(): utterances have a lifecycle the game may sequence
|
|
288
|
+
* off (onstart/onend, synth.speaking/pending checks), so every call is
|
|
289
|
+
* delegated and silenced via volume instead. Volume is sampled at speak()
|
|
290
|
+
* time, so forcing the native value to 0 right before delegating silences
|
|
291
|
+
* anything spoken while muted; in-flight speech at the mute edge is
|
|
292
|
+
* deliberately left to finish (can't be softened mid-utterance, and
|
|
293
|
+
* cancel() would discard the pending queue).
|
|
294
|
+
*/
|
|
295
|
+
shimSpeechSynthesis() {
|
|
296
|
+
if (!window.speechSynthesis || typeof SpeechSynthesisUtterance === "undefined") {
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
this.originalUtteranceVolumeDescriptor = Object.getOwnPropertyDescriptor(
|
|
300
|
+
SpeechSynthesisUtterance.prototype,
|
|
301
|
+
"volume"
|
|
302
|
+
) ?? null;
|
|
303
|
+
const volDesc = this.originalUtteranceVolumeDescriptor;
|
|
304
|
+
if (volDesc?.get && volDesc?.set) {
|
|
305
|
+
((manager) => {
|
|
306
|
+
Object.defineProperty(SpeechSynthesisUtterance.prototype, "volume", {
|
|
307
|
+
configurable: true,
|
|
308
|
+
get() {
|
|
309
|
+
const intended = manager.intendedUtteranceVolume.get(this);
|
|
310
|
+
return intended !== void 0 ? intended : volDesc.get.call(this);
|
|
311
|
+
},
|
|
312
|
+
set(value) {
|
|
313
|
+
manager.intendedUtteranceVolume.set(this, value);
|
|
314
|
+
volDesc.set.call(this, value);
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
})(this);
|
|
318
|
+
}
|
|
319
|
+
const speechSynthesis = window.speechSynthesis;
|
|
320
|
+
const originalSpeak = speechSynthesis.speak;
|
|
321
|
+
this.originalSpeak = originalSpeak;
|
|
322
|
+
((manager) => {
|
|
323
|
+
speechSynthesis.speak = function(utterance) {
|
|
324
|
+
if (manager._isMuted) {
|
|
325
|
+
if (!manager.intendedUtteranceVolume.has(utterance)) {
|
|
326
|
+
const current = volDesc?.get ? volDesc.get.call(utterance) : utterance.volume;
|
|
327
|
+
manager.intendedUtteranceVolume.set(utterance, current);
|
|
328
|
+
}
|
|
329
|
+
if (volDesc?.set) volDesc.set.call(utterance, 0);
|
|
330
|
+
else utterance.volume = 0;
|
|
331
|
+
} else {
|
|
332
|
+
const intended = manager.intendedUtteranceVolume.get(utterance);
|
|
333
|
+
if (intended !== void 0) {
|
|
334
|
+
if (volDesc?.set) volDesc.set.call(utterance, intended);
|
|
335
|
+
else utterance.volume = intended;
|
|
336
|
+
manager.intendedUtteranceVolume.delete(utterance);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return originalSpeak.call(speechSynthesis, utterance);
|
|
340
|
+
};
|
|
341
|
+
})(this);
|
|
278
342
|
}
|
|
279
343
|
shimAudioContextClass(Original) {
|
|
280
344
|
return /* @__PURE__ */ ((manager) => class extends Original {
|
|
@@ -320,6 +384,16 @@ var AudioManager = class extends WavedashManager {
|
|
|
320
384
|
if (this.originalAudio) {
|
|
321
385
|
window.Audio = this.originalAudio;
|
|
322
386
|
}
|
|
387
|
+
if (this.originalSpeak && window.speechSynthesis) {
|
|
388
|
+
window.speechSynthesis.speak = this.originalSpeak;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
if (this.originalUtteranceVolumeDescriptor && typeof SpeechSynthesisUtterance !== "undefined") {
|
|
392
|
+
Object.defineProperty(
|
|
393
|
+
SpeechSynthesisUtterance.prototype,
|
|
394
|
+
"volume",
|
|
395
|
+
this.originalUtteranceVolumeDescriptor
|
|
396
|
+
);
|
|
323
397
|
}
|
|
324
398
|
if (this.originalPlay) {
|
|
325
399
|
HTMLMediaElement.prototype.play = this.originalPlay;
|
|
@@ -334,6 +408,7 @@ var AudioManager = class extends WavedashManager {
|
|
|
334
408
|
this.contexts.clear();
|
|
335
409
|
this.elements.clear();
|
|
336
410
|
this.intendedMuted = /* @__PURE__ */ new WeakMap();
|
|
411
|
+
this.intendedUtteranceVolume = /* @__PURE__ */ new WeakMap();
|
|
337
412
|
super.destroy();
|
|
338
413
|
}
|
|
339
414
|
};
|