v0.8: TCP transport via gatuna tunnel, session IDs, pre-synth playback, server Rust rewrite

This commit is contained in:
2026-08-13 09:58:33 +00:00
parent ecf00c1bc4
commit facbfe6a5c
16 changed files with 955 additions and 638 deletions
+7 -33
View File
@@ -19,8 +19,6 @@ internal sealed class Orchestrator : IAsyncDisposable
private bool _playing;
private Task? _synthTask;
private CancellationTokenSource? _synthCts;
private System.Threading.Timer? _segmentTimer;
private static readonly TimeSpan SegmentTimeout = TimeSpan.FromMilliseconds(250);
public string OutputDeviceName { get; set; } = string.Empty;
@@ -51,7 +49,6 @@ internal sealed class Orchestrator : IAsyncDisposable
_log($"SEGMENT: \"{msg.Text}\" ({msg.Text.Length} chars)");
_pendingTexts.Enqueue(msg.Text);
EnsureSynthTask();
ResetSegmentTimer();
}
}
else
@@ -67,33 +64,11 @@ internal sealed class Orchestrator : IAsyncDisposable
_log("FINAL: (empty)");
}
CancelSegmentTimer();
TransitionToPlaying();
}
}
}
private void ResetSegmentTimer()
{
_segmentTimer?.Dispose();
_segmentTimer = new System.Threading.Timer(_ => OnSegmentTimeout(), null, SegmentTimeout, Timeout.InfiniteTimeSpan);
}
private void CancelSegmentTimer()
{
_segmentTimer?.Dispose();
_segmentTimer = null;
}
private void OnSegmentTimeout()
{
_log("STT: segment timeout, starting playback early");
lock (_stateLock)
{
TransitionToPlaying();
}
}
private void TransitionToPlaying()
{
if (_playing)
@@ -104,13 +79,11 @@ internal sealed class Orchestrator : IAsyncDisposable
if (_synthTask is null || _synthTask.IsCompleted)
{
_log("TTS: nothing to play");
CancelSegmentTimer();
}
return;
}
_playing = true;
CancelSegmentTimer();
int sampleRate = _bufferSampleRate;
var chunks = _audioBuffer.ToList();
@@ -189,7 +162,6 @@ internal sealed class Orchestrator : IAsyncDisposable
{
lock (_stateLock)
{
CancelSegmentTimer();
_synthCts?.Cancel();
_synthCts?.Dispose();
_synthTask = null;
@@ -209,7 +181,7 @@ internal sealed class Orchestrator : IAsyncDisposable
public async Task InitializeTtsAsync()
{
_log("Initializing TTS engine...");
await _tts.InitializeAsync();
await Task.Run(() => _tts.InitializeAsync());
_log($"TTS ready (sample rate: {_tts.SampleRate} Hz)");
}
@@ -269,15 +241,17 @@ internal sealed class Orchestrator : IAsyncDisposable
public async ValueTask DisposeAsync()
{
if (_disposed) return;
_currentCts?.Cancel();
_disposed = true;
try { _currentCts?.Cancel(); } catch { }
_currentCts?.Dispose();
_synthCts?.Cancel();
try { _synthCts?.Cancel(); } catch { }
_synthCts?.Dispose();
CancelSegmentTimer();
_sttSource.TranscriptReceived -= OnTranscript;
await _sttSource.DisposeAsync();
await _tts.DisposeAsync();
_audioOutput.Dispose();
_disposed = true;
}
}