using MeetingAssistant.Recording; using MeetingAssistant.Transcription; using NAudio.Wave; namespace MeetingAssistant.Tests; public sealed class SpeakerAudioSampleCollectorTests { [Fact] public void CollectorWaitsForConfiguredUninterruptedSpeechDuration() { var collector = new SpeakerAudioSampleCollector( TimeSpan.FromMinutes(2), maxSamplesPerSpeaker: 3, minimumUninterruptedSpeechDuration: TimeSpan.FromSeconds(30), maximumSegmentGap: TimeSpan.FromSeconds(1)); collector.AppendAudio(CreateAudio(TimeSpan.FromSeconds(35))); collector.TryAdd(Segment(0, 12, "Guest01", "one two three four five.")); collector.TryAdd(Segment(12, 24, "Guest01", "six seven eight nine ten.")); Assert.Empty(collector.Snapshot()); collector.TryAdd(Segment(24, 31, "Guest01", "eleven twelve thirteen fourteen fifteen.")); var sample = Assert.Single(collector.Snapshot()); Assert.Equal("Guest01", sample.Speaker); Assert.Equal(TimeSpan.Zero, sample.Segment.Start); Assert.Equal(TimeSpan.FromSeconds(31), sample.Segment.End); Assert.True(ReadDuration(sample.WavBytes) >= TimeSpan.FromSeconds(30)); } [Fact] public void CollectorDoesNotCombineSpeechAcrossDifferentSpeakerInterruption() { var collector = new SpeakerAudioSampleCollector( TimeSpan.FromMinutes(2), maxSamplesPerSpeaker: 3, minimumUninterruptedSpeechDuration: TimeSpan.FromSeconds(30), maximumSegmentGap: TimeSpan.FromSeconds(1)); collector.AppendAudio(CreateAudio(TimeSpan.FromSeconds(50))); collector.TryAdd(Segment(0, 20, "Guest01", "one two three four five.")); collector.TryAdd(Segment(20, 22, "Guest02", "interrupting now.")); collector.TryAdd(Segment(22, 35, "Guest01", "six seven eight nine ten.")); Assert.DoesNotContain(collector.Snapshot(), sample => sample.Speaker == "Guest01"); } private static TranscriptionSegment Segment( double start, double end, string speaker, string text) { return new TranscriptionSegment( TimeSpan.FromSeconds(start), TimeSpan.FromSeconds(end), speaker, text); } private static AudioChunk CreateAudio(TimeSpan duration) { const int sampleRate = 16000; const int channels = 1; var bytes = new byte[(int)(duration.TotalSeconds * sampleRate * channels * sizeof(short))]; return new AudioChunk(bytes, sampleRate, channels); } private static TimeSpan ReadDuration(byte[] wavBytes) { using var reader = new WaveFileReader(new MemoryStream(wavBytes)); return reader.TotalTime; } }