Skip to content

Commit 898aca1

Browse files
modify mock to try to fix html test
1 parent af50d49 commit 898aca1

1 file changed

Lines changed: 57 additions & 13 deletions

File tree

Lines changed: 57 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,76 @@
1-
/* global AudioContext, navigator */
1+
/* global MessageChannel, navigator, setTimeout, URL, window */
22

33
/**
4-
* Mocks navigator.mediaDevices.getUserMedia for testing speechToSpeech functionality.
4+
* Mocks browser audio APIs for speechToSpeech testing.
5+
*
6+
* - Intercepts AudioContext.audioWorklet.addModule() to prevent blob execution
7+
* - Mocks AudioWorkletNode for the 'audio-recorder' processor
8+
* - Mocks navigator.mediaDevices.getUserMedia() to return a test audio stream
59
*/
610
export function setupMockMediaDevices() {
7-
if (!navigator.mediaDevices) {
8-
navigator.mediaDevices = {};
9-
}
11+
const OriginalAudioContext = window.AudioContext;
1012

13+
// Intercept AudioContext to mock audioWorklet.addModule
14+
window.AudioContext = function (options) {
15+
const ctx = new OriginalAudioContext(options);
16+
17+
ctx.audioWorklet.addModule = url => {
18+
if (url.startsWith('blob:')) {
19+
URL.revokeObjectURL(url);
20+
}
21+
return Promise.resolve();
22+
};
23+
24+
return ctx;
25+
};
26+
27+
Object.setPrototypeOf(window.AudioContext, OriginalAudioContext);
28+
window.AudioContext.prototype = OriginalAudioContext.prototype;
29+
30+
// Mock AudioWorkletNode - uses GainNode as base so source.connect() works
31+
window.AudioWorkletNode = function (context, name, options) {
32+
const node = context.createGain();
33+
const channel = new MessageChannel();
34+
let recording = false;
35+
36+
node.port = channel.port1;
37+
38+
channel.port2.onmessage = ({ data }) => {
39+
if (data.command === 'START') {
40+
recording = true;
41+
const bufferSize = options?.processorOptions?.bufferSize || 2400;
42+
setTimeout(() => {
43+
if (recording) {
44+
channel.port1.postMessage({ eventType: 'audio', audioData: new Float32Array(bufferSize) });
45+
}
46+
}, 100);
47+
} else if (data.command === 'STOP') {
48+
recording = false;
49+
}
50+
};
51+
52+
return node;
53+
};
54+
55+
// Mock getUserMedia with oscillator-based test stream
1156
navigator.mediaDevices.getUserMedia = constraints => {
12-
const audioContext = new AudioContext({ sampleRate: constraints?.audio?.sampleRate || 24000 });
13-
const oscillator = audioContext.createOscillator();
14-
const destination = audioContext.createMediaStreamDestination();
57+
const sampleRate = constraints?.audio?.sampleRate || 24000;
58+
const ctx = new OriginalAudioContext({ sampleRate });
59+
const oscillator = ctx.createOscillator();
60+
const destination = ctx.createMediaStreamDestination();
1561

1662
oscillator.connect(destination);
1763
oscillator.start();
1864

19-
const { stream } = destination;
20-
21-
stream.getTracks().forEach(track => {
65+
destination.stream.getTracks().forEach(track => {
2266
const originalStop = track.stop.bind(track);
2367
track.stop = () => {
2468
oscillator.stop();
25-
audioContext.close();
69+
ctx.close();
2670
originalStop();
2771
};
2872
});
2973

30-
return stream;
74+
return Promise.resolve(destination.stream);
3175
};
3276
}

0 commit comments

Comments
 (0)