v0.7: pre-synth buffering, session IDs, segment timeout playback

This commit is contained in:
2026-08-12 10:30:11 +00:00
parent e1739059d9
commit ecf00c1bc4
6 changed files with 285 additions and 372 deletions
+62 -17
View File
@@ -19,6 +19,7 @@ public sealed class DhcpSttSource : ISttSource
private Task? _nopTask;
private EndPoint _broadcastEp = new IPEndPoint(IPAddress.Broadcast, DhcpServerPort);
private uint _nonce;
private uint _session;
private bool _disposed;
public string InterfaceIp { get; set; } = string.Empty;
@@ -73,7 +74,9 @@ public sealed class DhcpSttSource : ISttSource
if (_cts is null)
return;
_session++;
_nonce = 0;
Log?.Invoke($"STT: session {_session} started");
SendNop();
_nopTask = NopLoopAsync(_cts.Token);
}
@@ -81,7 +84,7 @@ public sealed class DhcpSttSource : ISttSource
public void SendOff()
{
StopNop();
SendControl("HKMSTR:OFF");
SendControl($"HKMSTR:OFF {_session} {_nonce}");
}
private void StopNop()
@@ -107,7 +110,7 @@ public sealed class DhcpSttSource : ISttSource
private void SendNop()
{
_nonce++;
SendControl($"HKMSTR {_nonce}");
SendControl($"HKMSTR {_session} {_nonce}");
}
private void SendControl(string message)
@@ -158,25 +161,67 @@ public sealed class DhcpSttSource : ISttSource
if (!text.StartsWith(Magic))
continue;
if (text.StartsWith("HKMSTR:P "))
TranscriptMessage? message = ParseReply(text);
if (message is null)
continue;
TranscriptReceived?.Invoke(this, new TranscriptEventArgs
{
string transcript = text["HKMSTR:P ".Length..];
TranscriptReceived?.Invoke(this, new TranscriptEventArgs
{
Message = new TranscriptMessage(TranscriptType.Partial, transcript),
});
}
else if (text.StartsWith("HKMSTR:F "))
{
string transcript = text["HKMSTR:F ".Length..];
TranscriptReceived?.Invoke(this, new TranscriptEventArgs
{
Message = new TranscriptMessage(TranscriptType.Final, transcript),
});
}
Message = message,
});
}
}
private TranscriptMessage? ParseReply(string text)
{
// Format: HKMSTR:P <session> <text> or HKMSTR:F <session> <text>
// <text> may be empty.
string prefix;
TranscriptType type;
if (text.StartsWith("HKMSTR:P "))
{
prefix = "HKMSTR:P ";
type = TranscriptType.Partial;
}
else if (text.StartsWith("HKMSTR:F "))
{
prefix = "HKMSTR:F ";
type = TranscriptType.Final;
}
else
{
return null;
}
string rest = text[prefix.Length..];
int spaceIndex = rest.IndexOf(' ');
if (spaceIndex < 0)
{
if (uint.TryParse(rest, out uint sessionOnly))
{
if (sessionOnly != _session)
return null;
return new TranscriptMessage(type, string.Empty);
}
return null;
}
string sessionStr = rest[..spaceIndex];
if (!uint.TryParse(sessionStr, out uint session))
return null;
if (session != _session)
{
Log?.Invoke($"STT: dropping stale reply (session {session} != current {_session})");
return null;
}
string transcript = rest[(spaceIndex + 1)..];
return new TranscriptMessage(type, transcript);
}
public static List<(string Ip, string Name)> GetAvailableInterfaces()
{
var result = new List<(string, string)>();