Remove await from audio worklet

Co-authored-by: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com>
This commit is contained in:
automated-signal
2026-04-30 18:34:46 -05:00
committed by GitHub
parent 8b837f6bec
commit 892b8d104a
7 changed files with 28 additions and 30 deletions
+1
View File
@@ -209,6 +209,7 @@ const STD_PACKAGES = new Set([
'@react-types/shared',
'@signalapp/minimask',
'@signalapp/quill-cjs',
'@signalapp/lame',
'@typescript-eslint/eslint-plugin',
'@typescript-eslint/parser',
'axe-core',
+2 -1
View File
@@ -22,8 +22,9 @@ cd -
emcc -I lame-3.100/include -Oz -DNDEBUG -flto wrapper.c \
./lame-3.100/libmp3lame/.libs/libmp3lame.a -o wrapper.mjs \
-sEXPORTED_FUNCTIONS=_wrapper_init,_wrapper_get_num_samples,_wrapper_get_in,_wrapper_get_out,_wrapper_encode,_wrapper_flush,_wrapper_get_lametag_frame,_wrapper_close \
-sEXPORTED_RUNTIME_METHODS=HEAPU8 \
-sEXPORTED_RUNTIME_METHODS=HEAPU8 -sDYNAMIC_EXECUTION=0 \
-sENVIRONMENT=worklet -sWASM=0 -sWASM_ASYNC_COMPILATION=0
sed -I '' 's/^async //' wrapper.mjs
```
## License
+1 -1
View File
@@ -12,7 +12,7 @@ const {
_wrapper_encode,
_wrapper_get_lametag_frame,
_wrapper_flush,
} = await initWrapper();
} = initWrapper();
const input = new Float32Array(
HEAPU8.buffer,
File diff suppressed because one or more lines are too long
+7 -3
View File
@@ -77,10 +77,15 @@ export class AudioRecorder {
}
if (data.type === 'complete') {
this.#state = { type: 'idle' };
chunks.push(data.finalFrame);
const result = Bytes.concatenate(chunks);
// Replace the original placeholder header with the one that has
// full audio duration (necessary for VBR encoding).
chunks[0] = data.lametagFrame;
resolve(Bytes.concatenate(chunks));
result.set(data.lametagFrame);
resolve(result);
return;
}
};
@@ -88,7 +93,6 @@ export class AudioRecorder {
const stream = await navigator.mediaDevices.getUserMedia({
audio: {
channelCount: { ideal: 1 },
autoGainControl: { ideal: false },
},
});
+1
View File
@@ -21,6 +21,7 @@ export type WorkletMessageType = Readonly<
| {
type: 'complete';
lametagFrame: Uint8Array<ArrayBuffer>;
finalFrame: Uint8Array<ArrayBuffer>;
}
>;
+15 -24
View File
@@ -5,6 +5,7 @@ import type {
WorkletMessageType,
RendererMessageType,
} from '../types/AudioRecorder.std.ts';
import { init, encode, flush, getLametagFrame } from '@signalapp/lame';
declare const sampleRate: number;
@@ -33,16 +34,7 @@ declare function registerProcessor(
const BIT_RATE = 128;
// Unfortunately `context.audioWorklet.addModule` doesn't wait for top-level
// awaits to be resolved so we have to call `registerProcessor` immediately
// and let the import resolve later on.
const lame = (async () => {
const result = await import('@signalapp/lame');
result.init(sampleRate, BIT_RATE);
return result;
})();
init(sampleRate, BIT_RATE);
class Mp3Encoder
extends AudioWorkletProcessor
@@ -53,21 +45,22 @@ class Mp3Encoder
constructor() {
super();
this.port.onmessage = async ({ data }: { data: RendererMessageType }) => {
this.port.onmessage = ({ data }: { data: RendererMessageType }) => {
if (data.type !== 'stop') {
throw new Error('Unexpected message');
}
this.#isStopped = true;
const { flush, getLametagFrame } = await lame;
this.#sendChunk(flush());
const chunk = new Uint8Array(flush());
const lametagFrame = new Uint8Array(getLametagFrame());
this.port.postMessage(
{
type: 'complete',
lametagFrame: lametagFrame,
finalFrame: chunk,
} satisfies WorkletMessageType,
[lametagFrame.buffer]
[lametagFrame.buffer, chunk.buffer]
);
};
}
@@ -83,19 +76,16 @@ class Mp3Encoder
}
const [channel] = input;
if (channel != null) {
void this.#encode(channel);
if (channel == null) {
return true;
}
return true;
}
async #encode(channel: Float32Array<ArrayBuffer>): Promise<void> {
const { encode } = await lame;
this.#sendChunk(encode(channel));
}
const shared = encode(channel);
if (shared.length === 0) {
return true;
}
#sendChunk(chunk: Uint8Array<ArrayBuffer>): void {
const copy = new Uint8Array(chunk);
const copy = new Uint8Array(shared);
this.port.postMessage(
{
type: 'chunk',
@@ -103,6 +93,7 @@ class Mp3Encoder
} satisfies WorkletMessageType,
[copy.buffer]
);
return true;
}
}