fix: handlePcmChunk serialisiert — fixes Race bei kurzen Streams
Bei kurzen Saetzen (nur ein paar Chunks + sofort final) konnten die async handlePcmChunk-Calls parallel laufen. Der final-Chunk konnte native end() aufrufen BEVOR der vorherige Chunk seinen native start() abgeschlossen hatte. Der Writer-Thread startete dann mit endRequested bereits true, verarbeitete keine Chunks sauber → Audio ging verloren. Fix: Wrapper chaint alle Chunk-Calls an eine Promise-Queue: _pcmChunkQueue = Promise.resolve() handlePcmChunk → _pcmChunkQueue.then(() => _handlePcmChunkImpl(p)) So werden start/writeChunk/end garantiert in der richtigen Reihenfolge verarbeitet. Der API-Contract bleibt (gleiches return-Promise). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
cc3fac8142
commit
23ca815cb2
|
|
@ -459,7 +459,13 @@ class AudioService {
|
|||
|
||||
/** Einen PCM-Chunk aus einer audio_pcm Nachricht empfangen.
|
||||
* silent=true → nur cachen, nicht abspielen (z.B. wenn TTS geraetelokal gemutet).
|
||||
* Gibt bei final=true den Cache-Pfad zurueck (file://) oder '' wenn nicht gecached. */
|
||||
* Gibt bei final=true den Cache-Pfad zurueck (file://) oder '' wenn nicht gecached.
|
||||
*
|
||||
* Wrapper serialisiert aufeinanderfolgende Chunk-Calls via Promise-Queue —
|
||||
* sonst gabs bei kurzen Streams einen Race: final-Chunk konnte `end()` rufen
|
||||
* BEVOR der vorherige `start()` im Native-Modul fertig war. Der Writer-
|
||||
* Thread sah dann endRequested=true ohne jemals Chunks zu verarbeiten. */
|
||||
private _pcmChunkQueue: Promise<any> = Promise.resolve();
|
||||
async handlePcmChunk(payload: {
|
||||
base64: string;
|
||||
sampleRate?: number;
|
||||
|
|
@ -468,6 +474,24 @@ class AudioService {
|
|||
chunk?: number;
|
||||
final?: boolean;
|
||||
silent?: boolean;
|
||||
}): Promise<string> {
|
||||
const p = this._pcmChunkQueue.then(() => this._handlePcmChunkImpl(payload)).catch(err => {
|
||||
console.warn('[Audio] handlePcmChunk queued err:', err);
|
||||
return '';
|
||||
});
|
||||
// Chain only on the side effect — callers still get the per-call result
|
||||
this._pcmChunkQueue = p;
|
||||
return p;
|
||||
}
|
||||
|
||||
private async _handlePcmChunkImpl(payload: {
|
||||
base64: string;
|
||||
sampleRate?: number;
|
||||
channels?: number;
|
||||
messageId?: string;
|
||||
chunk?: number;
|
||||
final?: boolean;
|
||||
silent?: boolean;
|
||||
}): Promise<string> {
|
||||
const silent = !!payload.silent;
|
||||
if (!silent && !PcmStreamPlayer) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue