mirror of
https://github.com/moonlight-stream/moonlight-qt.git
synced 2025-07-02 07:46:07 +00:00
Audio latency tweaks and fix for PulseAudio with A2DP
This commit is contained in:
parent
8612e6726d
commit
d1640e3bb8
@ -4,13 +4,21 @@
|
|||||||
|
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
|
|
||||||
// This determines the size of the buffers we'll
|
// GFE sends us packets in 5 ms chunks
|
||||||
// get from CoreAudio. Since GFE sends us packets
|
|
||||||
// in 5 ms chunks, we'll give them to the OS in
|
|
||||||
// buffers of the same size. It is also the minimum
|
|
||||||
// size that we will write when called to fill a buffer.
|
|
||||||
const double SoundIoAudioRenderer::k_RawSampleLengthSec = 0.005;
|
const double SoundIoAudioRenderer::k_RawSampleLengthSec = 0.005;
|
||||||
|
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
// PulseAudio and ALSA require more than just 5 ms samples
|
||||||
|
// for some reason, so write a minimum of 20 ms each time to
|
||||||
|
// prevent underruns on Bluetooth.
|
||||||
|
const double SoundIoAudioRenderer::k_MinSampleLengthSec = 0.020;
|
||||||
|
#else
|
||||||
|
// This determines the size of the buffers we'll
|
||||||
|
// get from CoreAudio. It is also the minimum
|
||||||
|
// size that we will write when called to fill a buffer.
|
||||||
|
const double SoundIoAudioRenderer::k_MinSampleLengthSec = k_RawSampleLengthSec;
|
||||||
|
#endif
|
||||||
|
|
||||||
SoundIoAudioRenderer::SoundIoAudioRenderer()
|
SoundIoAudioRenderer::SoundIoAudioRenderer()
|
||||||
: m_OpusChannelCount(0),
|
: m_OpusChannelCount(0),
|
||||||
m_SoundIo(nullptr),
|
m_SoundIo(nullptr),
|
||||||
@ -164,7 +172,7 @@ bool SoundIoAudioRenderer::prepareForPlayback(const OPUS_MULTISTREAM_CONFIGURATI
|
|||||||
|
|
||||||
m_OutputStream->format = SoundIoFormatS16NE;
|
m_OutputStream->format = SoundIoFormatS16NE;
|
||||||
m_OutputStream->sample_rate = opusConfig->sampleRate;
|
m_OutputStream->sample_rate = opusConfig->sampleRate;
|
||||||
m_OutputStream->software_latency = k_RawSampleLengthSec;
|
m_OutputStream->software_latency = k_MinSampleLengthSec;
|
||||||
m_OutputStream->name = "Moonlight";
|
m_OutputStream->name = "Moonlight";
|
||||||
m_OutputStream->userdata = this;
|
m_OutputStream->userdata = this;
|
||||||
m_OutputStream->error_callback = sioErrorCallback;
|
m_OutputStream->error_callback = sioErrorCallback;
|
||||||
@ -225,12 +233,18 @@ bool SoundIoAudioRenderer::prepareForPlayback(const OPUS_MULTISTREAM_CONFIGURATI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Buffer up to 6 packets of audio (30 ms) to smooth
|
// Buffer at least 2 audio packets to smooth out network packet delivery jitter or
|
||||||
// out network packet delivery jitter
|
// 15 ms, whichever is greater.
|
||||||
|
int packetsToBuffer = qMax((int)(k_MinSampleLengthSec / k_RawSampleLengthSec) * 2, 3);
|
||||||
|
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Audio buffer size: %d packets",
|
||||||
|
packetsToBuffer);
|
||||||
|
|
||||||
m_RingBuffer = soundio_ring_buffer_create(m_SoundIo,
|
m_RingBuffer = soundio_ring_buffer_create(m_SoundIo,
|
||||||
m_OutputStream->bytes_per_sample *
|
m_OutputStream->bytes_per_sample *
|
||||||
m_OpusChannelCount *
|
m_OpusChannelCount *
|
||||||
SAMPLES_PER_FRAME * 6);
|
SAMPLES_PER_FRAME *
|
||||||
|
packetsToBuffer);
|
||||||
if (m_RingBuffer == nullptr) {
|
if (m_RingBuffer == nullptr) {
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
"soundio_ring_buffer_create() failed");
|
"soundio_ring_buffer_create() failed");
|
||||||
@ -245,6 +259,11 @@ bool SoundIoAudioRenderer::prepareForPlayback(const OPUS_MULTISTREAM_CONFIGURATI
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HACK: For some reason, a constant latency hangs around in the audio pipeline
|
||||||
|
// unless we wait for the audio stream to drain before actually submitting any samples.
|
||||||
|
// This is a gross hack, but it works remarkably well.
|
||||||
|
SDL_Delay(500);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,7 +357,7 @@ void SoundIoAudioRenderer::sioWriteCallback(SoundIoOutStream* stream, int frameC
|
|||||||
// Ensure we always write at least a buffer, even if it's silence, to avoid
|
// Ensure we always write at least a buffer, even if it's silence, to avoid
|
||||||
// busy looping when no audio data is available while libsoundio tries to keep
|
// busy looping when no audio data is available while libsoundio tries to keep
|
||||||
// us from starving the output device.
|
// us from starving the output device.
|
||||||
frameCountMin = qMax(frameCountMin, (int)(stream->sample_rate * k_RawSampleLengthSec));
|
frameCountMin = qMax(frameCountMin, (int)(stream->sample_rate * k_MinSampleLengthSec));
|
||||||
frameCountMin = qMin(frameCountMin, frameCountMax);
|
frameCountMin = qMin(frameCountMin, frameCountMax);
|
||||||
|
|
||||||
// Clamp framesLeft to frameCountMin to ensure that we never write more than one sample.
|
// Clamp framesLeft to frameCountMin to ensure that we never write more than one sample.
|
||||||
|
@ -36,4 +36,5 @@ private:
|
|||||||
bool m_Errored;
|
bool m_Errored;
|
||||||
|
|
||||||
static const double k_RawSampleLengthSec;
|
static const double k_RawSampleLengthSec;
|
||||||
|
static const double k_MinSampleLengthSec;
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user