Test 4a: wire NoMoreDeltas + add UpstreamSendLoop stop-and-empty exit
Code-review feedback from Task 2: - Use state.NoMoreDeltas in the output callback completion check instead of downstream.Reader.Completion.IsCompleted (spec called for it as the redundant fast path; it was dead code before). - UpstreamSendLoop now break's when StopSending && upstream channel empty, matching the spec's stated exit shape.
This commit is contained in:
@@ -323,10 +323,12 @@ static Stream OpenOutputStream(int device, Channel<short[]> downstream, SharedSt
|
|||||||
for (int i = fill; i < (int)frameCount; i++) dst[i] = 0;
|
for (int i = fill; i < (int)frameCount; i++) dst[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Completion = working chunk drained AND channel empty AND writer completed.
|
// Completion = working chunk drained AND channel empty AND no more deltas expected.
|
||||||
|
// _noMoreDeltas is the spec's "redundant fast path" — set immediately on response.done,
|
||||||
|
// avoids touching downstream.Reader.Completion (a Task allocation per callback).
|
||||||
if (state.CurrentChunk == null
|
if (state.CurrentChunk == null
|
||||||
&& downstream.Reader.Count == 0
|
&& downstream.Reader.Count == 0
|
||||||
&& downstream.Reader.Completion.IsCompleted)
|
&& state.NoMoreDeltas)
|
||||||
{
|
{
|
||||||
doneFlag.Set();
|
doneFlag.Set();
|
||||||
return StreamCallbackResult.Complete;
|
return StreamCallbackResult.Complete;
|
||||||
@@ -343,7 +345,13 @@ static async Task UpstreamSendLoop(ClientWebSocket ws, Channel<short[]> upstream
|
|||||||
{
|
{
|
||||||
await foreach (var frame in upstream.Reader.ReadAllAsync(cts.Token))
|
await foreach (var frame in upstream.Reader.ReadAllAsync(cts.Token))
|
||||||
{
|
{
|
||||||
if (state.StopSending) continue;
|
if (state.StopSending)
|
||||||
|
{
|
||||||
|
// After server VAD said the user is done, drop in-flight mic frames and exit
|
||||||
|
// once the channel is drained. Matches the spec's "_stopSending && empty" exit.
|
||||||
|
if (upstream.Reader.Count == 0) break;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
ReadOnlySpan<byte> bytes = MemoryMarshal.AsBytes(frame.AsSpan());
|
ReadOnlySpan<byte> bytes = MemoryMarshal.AsBytes(frame.AsSpan());
|
||||||
string base64 = Convert.ToBase64String(bytes);
|
string base64 = Convert.ToBase64String(bytes);
|
||||||
var msg = new { type = "input_audio_buffer.append", audio = base64 };
|
var msg = new { type = "input_audio_buffer.append", audio = base64 };
|
||||||
|
|||||||
Reference in New Issue
Block a user