Implement meeting assistant v1

This commit is contained in:
2026-05-20 02:06:16 +02:00
parent 90df1edc03
commit 0297bcc0f6
120 changed files with 11883 additions and 180 deletions
@@ -0,0 +1,71 @@
using MeetingAssistant.Recording;
using Microsoft.Extensions.Logging.Abstractions;
namespace MeetingAssistant.Tests;
public sealed class AudioMixingTests
{
[Fact]
public async Task CompositeAudioSourceMixesMicrophoneAndSystemAudioIntoOnePcmStream()
{
var microphone = new FixedAudioSource(Pcm16(10_000));
var system = new FixedAudioSource(Pcm16(20_000));
var source = new CompositeMeetingAudioSource(
microphone,
system,
NullLogger<CompositeMeetingAudioSource>.Instance);
var chunks = await ReadChunks(source);
Assert.Single(chunks);
Assert.Equal(30_000, BitConverter.ToInt16(chunks[0].Pcm));
}
[Fact]
public async Task CompositeAudioSourceClampsMixedSamples()
{
var microphone = new FixedAudioSource(Pcm16(30_000));
var system = new FixedAudioSource(Pcm16(10_000));
var source = new CompositeMeetingAudioSource(
microphone,
system,
NullLogger<CompositeMeetingAudioSource>.Instance);
var chunks = await ReadChunks(source);
Assert.Equal(short.MaxValue, BitConverter.ToInt16(chunks[0].Pcm));
}
private static async Task<IReadOnlyList<AudioChunk>> ReadChunks(IMeetingAudioSource source)
{
var chunks = new List<AudioChunk>();
await foreach (var chunk in source.CaptureAsync(CancellationToken.None))
{
chunks.Add(chunk);
}
return chunks;
}
private static byte[] Pcm16(short sample)
{
return BitConverter.GetBytes(sample);
}
private sealed class FixedAudioSource : IMeetingAudioSource
{
private readonly AudioChunk chunk;
public FixedAudioSource(byte[] pcm)
{
chunk = new AudioChunk(pcm, 16000, 1);
}
public async IAsyncEnumerable<AudioChunk> CaptureAsync(
[System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken)
{
await Task.Yield();
yield return chunk;
}
}
}