Stottern bei der Audiowiedergabe mit NAudio und Opus nur bei Verbindung über das Netzwerk
Posted: 12 Jan 2025, 13:36
Ich habe ein Problem, bei dem die Audiowiedergabe beim Durchlaufen des Netzwerks (auch bekannt als mein VPS) stottert/jittert, nicht jedoch, wenn dasselbe, sondern lokal ausgeführt wird.
Ich gehe davon aus, dass es etwas mit der Wiedergabe zu tun hat Geschwindigkeit oder Pufferung, aber ich versuche seit ein paar Wochen, das Problem zu beheben, und finde keine Lösung.
Ich habe versucht, mir öffentliche Repositorys anzusehen, die etwas Ähnliches tun, aber ich bin nicht technisch genug, um sie zu verstehen Prozess.
So wird die Wiedergabe initialisiert, wenn die App startet:
Ich empfange dann Pakete aus dem Netzwerk und füge sie dieser JitterBuffer-Klasse hinzu:
Beachten Sie, dass die Jitter-Puffergröße hier 100 ms beträgt.
Und so erhalte ich Frames von diesem JitterBuffer, um sie einem BufferedWaveProvider hinzuzufügen:
Diese PlayFromBuffer-Methode wird alle 20 ms mithilfe eines Timers aufgerufen, der immer dann gestartet wird, wenn der Benutzer eine Taste drückt, um die Wiedergabe zu starten.
Außerdem Wenn es relevant ist, nehme ich das Audio folgendermaßen auf:
Jede Hilfe ist willkommen.
Ich gehe davon aus, dass es etwas mit der Wiedergabe zu tun hat Geschwindigkeit oder Pufferung, aber ich versuche seit ein paar Wochen, das Problem zu beheben, und finde keine Lösung.
Ich habe versucht, mir öffentliche Repositorys anzusehen, die etwas Ähnliches tun, aber ich bin nicht technisch genug, um sie zu verstehen Prozess.
So wird die Wiedergabe initialisiert, wenn die App startet:
Code: Select all
public static void Initialize()
{
waveProvider = new BufferedWaveProvider(new WaveFormat(48000, 1))
{
BufferDuration = TimeSpan.FromSeconds(5),
DiscardOnBufferOverflow = false
};
waveOut = new WaveOutEvent();
waveOut.Init(waveProvider);
}
Code: Select all
public class JitterBuffer(int maxBufferSize)
{
private readonly SortedDictionary buffer = [];
private readonly int maxBufferSize = maxBufferSize;
public void AddFrame(short[] frame, int sequenceNumber)
{
if (buffer.Count >= maxBufferSize)
{
buffer.Remove(buffer.Keys.First()); // Remove the oldest frame if the buffer is full
}
buffer[sequenceNumber] = frame;
}
public short[]? GetFrame()
{
if (buffer.Count > 0)
{
var firstKey = buffer.Keys.First();
var firstValue = buffer[firstKey];
buffer.Remove(firstKey);
return firstValue;
}
// Return null if the buffer is empty
return null;
}
public int BufferSize => buffer.Count;
}
Und so erhalte ich Frames von diesem JitterBuffer, um sie einem BufferedWaveProvider hinzuzufügen:
Code: Select all
public static void PlayFromBuffer(object? state)
{
short[]? frame = jitterBuffer.GetFrame();
if (frame != null)
{
byte[] byteBuffer = new byte[frame.Length * sizeof(short)];
Buffer.BlockCopy(frame, 0, byteBuffer, 0, byteBuffer.Length);
waveProvider.AddSamples(byteBuffer, 0, byteBuffer.Length);
}
}
Außerdem Wenn es relevant ist, nehme ich das Audio folgendermaßen auf:
Code: Select all
public static void Initialize()
{
waveIn = new WaveInEvent
{
DeviceNumber = 0, // Use default recording device
WaveFormat = new WaveFormat(48000, 1)
};
waveIn.DataAvailable += OnDataAvailable;
waveIn.RecordingStopped += WaveIn_RecordingStopped;
}
// waveIn.StartRecording is called in a separate method
private static void OnDataAvailable(object? sender, WaveInEventArgs a)
{
// Convert buffer to short PCM samples and accumulate
short[] pcmBuffer = new short[a.BytesRecorded / 2];
Buffer.BlockCopy(a.Buffer, 0, pcmBuffer, 0, a.BytesRecorded);
pcmAccumulationBuffer.AddRange(pcmBuffer);
// This method calls Opus to encode then packages it into a packet and is sent to the server
AudioCodec.Process(pcmAccumulationBuffer);
}