mirror of
https://github.com/moonlight-stream/moonlight-qt
synced 2024-11-10 13:44:17 +00:00
Fixes to SDL audio renderer and autodetection support
This commit is contained in:
parent
12496e4432
commit
64bc189010
7 changed files with 59 additions and 88 deletions
|
@ -1,4 +1,4 @@
|
|||
QT += core quick network quickcontrols2 svg
|
||||
QT += core quick network quickcontrols2 svg multimedia
|
||||
CONFIG += c++11
|
||||
|
||||
unix:!macx {
|
||||
|
|
|
@ -386,14 +386,10 @@ ScrollView {
|
|||
textRole: "text"
|
||||
model: ListModel {
|
||||
id: audioListModel
|
||||
// Detection of audio channels only works on Windows
|
||||
// and even so, it's still unreliable because audio devices
|
||||
// lie about how many channels they can support. Hide the
|
||||
// option to autodetect until this is resolved.
|
||||
/*ListElement {
|
||||
ListElement {
|
||||
text: "Autodetect"
|
||||
val: StreamingPreferences.AC_AUTO
|
||||
}*/
|
||||
}
|
||||
ListElement {
|
||||
text: "Stereo"
|
||||
val: StreamingPreferences.AC_FORCE_STEREO
|
||||
|
|
|
@ -43,7 +43,7 @@ void StreamingPreferences::reload()
|
|||
enableMdns = settings.value(SER_MDNS, true).toBool();
|
||||
mouseAcceleration = settings.value(SER_MOUSEACCELERATION, false).toBool();
|
||||
audioConfig = static_cast<AudioConfig>(settings.value(SER_AUDIOCFG,
|
||||
static_cast<int>(AudioConfig::AC_FORCE_STEREO)).toInt());
|
||||
static_cast<int>(AudioConfig::AC_AUTO)).toInt());
|
||||
videoCodecConfig = static_cast<VideoCodecConfig>(settings.value(SER_VIDEOCFG,
|
||||
static_cast<int>(VideoCodecConfig::VCC_AUTO)).toInt());
|
||||
videoDecoderSelection = static_cast<VideoDecoderSelection>(settings.value(SER_VIDEODEC,
|
||||
|
|
|
@ -70,8 +70,7 @@ int Session::arInit(int /* audioConfiguration */,
|
|||
return -2;
|
||||
}
|
||||
|
||||
s_ActiveSession->m_AudioRenderer->prepareForPlayback(opusConfig);
|
||||
if (s_ActiveSession->m_AudioRenderer == nullptr) {
|
||||
if (!s_ActiveSession->m_AudioRenderer->prepareForPlayback(opusConfig)) {
|
||||
delete s_ActiveSession->m_AudioRenderer;
|
||||
opus_multistream_decoder_destroy(s_ActiveSession->m_OpusDecoder);
|
||||
return -3;
|
||||
|
@ -86,12 +85,21 @@ int Session::arInit(int /* audioConfiguration */,
|
|||
|
||||
void Session::arCleanup()
|
||||
{
|
||||
delete s_ActiveSession->m_AudioRenderer;
|
||||
// m_AudioRenderer is deleted in cleanupAudioRenderer()
|
||||
|
||||
opus_multistream_decoder_destroy(s_ActiveSession->m_OpusDecoder);
|
||||
s_ActiveSession->m_OpusDecoder = nullptr;
|
||||
}
|
||||
|
||||
// This is called on the main thread
|
||||
void Session::cleanupAudioRendererOnMainThread()
|
||||
{
|
||||
SDL_AtomicLock(&m_AudioRendererLock);
|
||||
delete m_AudioRenderer;
|
||||
m_AudioRenderer = nullptr;
|
||||
SDL_AtomicUnlock(&m_AudioRendererLock);
|
||||
}
|
||||
|
||||
void Session::arDecodeAndPlaySample(char* sampleData, int sampleLength)
|
||||
{
|
||||
int samplesDecoded;
|
||||
|
@ -103,9 +111,13 @@ void Session::arDecodeAndPlaySample(char* sampleData, int sampleLength)
|
|||
SAMPLES_PER_FRAME,
|
||||
0);
|
||||
if (samplesDecoded > 0) {
|
||||
s_ActiveSession->m_AudioRenderer->submitAudio(s_ActiveSession->m_OpusDecodeBuffer,
|
||||
static_cast<int>(sizeof(short) *
|
||||
samplesDecoded *
|
||||
s_ActiveSession->m_AudioConfig.channelCount));
|
||||
SDL_AtomicLock(&s_ActiveSession->m_AudioRendererLock);
|
||||
if (s_ActiveSession->m_AudioRenderer != nullptr) {
|
||||
s_ActiveSession->m_AudioRenderer->submitAudio(s_ActiveSession->m_OpusDecodeBuffer,
|
||||
static_cast<int>(sizeof(short) *
|
||||
samplesDecoded *
|
||||
s_ActiveSession->m_AudioConfig.channelCount));
|
||||
}
|
||||
SDL_AtomicUnlock(&s_ActiveSession->m_AudioRendererLock);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <Limelight.h>
|
||||
#include <SDL.h>
|
||||
|
||||
#include <QAudioDeviceInfo>
|
||||
#include <QtGlobal>
|
||||
|
||||
#define MIN_QUEUED_FRAMES 2
|
||||
|
@ -10,69 +11,31 @@
|
|||
#define STOP_THE_WORLD_LIMIT 20
|
||||
#define DROP_RATIO_DENOM 32
|
||||
|
||||
// Detecting this with SDL is quite problematic, so we'll use Qt's
|
||||
// multimedia framework to do so. It appears to be actually
|
||||
// accurate on Linux and macOS, unlike using SDL and relying
|
||||
// on a channel change in the format received.
|
||||
int SdlAudioRenderer::detectAudioConfiguration()
|
||||
{
|
||||
SDL_AudioSpec want, have;
|
||||
SDL_AudioDeviceID dev;
|
||||
int ret;
|
||||
|
||||
if (SDL_InitSubSystem(SDL_INIT_AUDIO) != 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SDL_InitSubSystem(SDL_INIT_AUDIO) failed: %s",
|
||||
SDL_GetError());
|
||||
return AUDIO_CONFIGURATION_STEREO;
|
||||
}
|
||||
|
||||
SDL_zero(want);
|
||||
want.freq = 48000;
|
||||
want.format = AUDIO_S16;
|
||||
want.channels = 6;
|
||||
want.samples = 1024;
|
||||
|
||||
// Try to open for 5.1 surround sound, but allow SDL to tell us that's
|
||||
// not available.
|
||||
dev = SDL_OpenAudioDevice(NULL, 0, &want, &have, SDL_AUDIO_ALLOW_CHANNELS_CHANGE);
|
||||
if (dev == 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Failed to open audio device");
|
||||
// We'll probably have issues during audio stream init, but we'll
|
||||
// try anyway
|
||||
ret = AUDIO_CONFIGURATION_STEREO;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
SDL_CloseAudioDevice(dev);
|
||||
int preferredChannelCount = QAudioDeviceInfo::defaultOutputDevice().preferredFormat().channelCount();
|
||||
|
||||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Audio device has %d channels", have.channels);
|
||||
"Audio output device prefers %d channel configuration",
|
||||
preferredChannelCount);
|
||||
|
||||
if (have.channels > 2) {
|
||||
// We don't support quadraphonic or 7.1 surround, but SDL
|
||||
// should be able to downmix or upmix better from 5.1 than
|
||||
// from stereo, so use 5.1 in non-stereo cases.
|
||||
ret = AUDIO_CONFIGURATION_51_SURROUND;
|
||||
// We can better downmix 5.1 to quad than we can upmix stereo
|
||||
if (preferredChannelCount > 2) {
|
||||
return AUDIO_CONFIGURATION_51_SURROUND;
|
||||
}
|
||||
else {
|
||||
ret = AUDIO_CONFIGURATION_STEREO;
|
||||
return AUDIO_CONFIGURATION_STEREO;
|
||||
}
|
||||
|
||||
Exit:
|
||||
SDL_QuitSubSystem(SDL_INIT_AUDIO);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool SdlAudioRenderer::testAudio(int audioConfiguration)
|
||||
{
|
||||
SDL_AudioSpec want, have;
|
||||
SDL_AudioDeviceID dev;
|
||||
bool ret;
|
||||
|
||||
if (SDL_InitSubSystem(SDL_INIT_AUDIO) != 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Audio test - SDL_InitSubSystem(SDL_INIT_AUDIO) failed: %s",
|
||||
SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_zero(want);
|
||||
want.freq = 48000;
|
||||
|
@ -88,8 +51,7 @@ bool SdlAudioRenderer::testAudio(int audioConfiguration)
|
|||
break;
|
||||
default:
|
||||
SDL_assert(false);
|
||||
ret = false;
|
||||
goto Exit;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Test audio device for functionality
|
||||
|
@ -98,8 +60,7 @@ bool SdlAudioRenderer::testAudio(int audioConfiguration)
|
|||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Audio test - Failed to open audio device: %s",
|
||||
SDL_GetError());
|
||||
ret = false;
|
||||
goto Exit;
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_CloseAudioDevice(dev);
|
||||
|
@ -107,12 +68,7 @@ bool SdlAudioRenderer::testAudio(int audioConfiguration)
|
|||
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Audio test - Successful with %d channels",
|
||||
want.channels);
|
||||
|
||||
ret = true;
|
||||
|
||||
Exit:
|
||||
SDL_QuitSubSystem(SDL_INIT_AUDIO);
|
||||
return ret;
|
||||
return true;
|
||||
}
|
||||
|
||||
SdlAudioRenderer::SdlAudioRenderer()
|
||||
|
@ -123,20 +79,18 @@ SdlAudioRenderer::SdlAudioRenderer()
|
|||
m_SampleIndex(0),
|
||||
m_BaselinePendingData(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool SdlAudioRenderer::prepareForPlayback(const OPUS_MULTISTREAM_CONFIGURATION* opusConfig)
|
||||
{
|
||||
SDL_AudioSpec want, have;
|
||||
|
||||
SDL_assert(!SDL_WasInit(SDL_INIT_AUDIO));
|
||||
if (SDL_InitSubSystem(SDL_INIT_AUDIO) != 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SDL_InitSubSystem(SDL_INIT_AUDIO) failed: %s",
|
||||
SDL_GetError());
|
||||
return -1;
|
||||
SDL_assert(SDL_WasInit(SDL_INIT_AUDIO));
|
||||
}
|
||||
}
|
||||
|
||||
bool SdlAudioRenderer::prepareForPlayback(const OPUS_MULTISTREAM_CONFIGURATION* opusConfig)
|
||||
{
|
||||
SDL_AudioSpec want, have;
|
||||
|
||||
SDL_zero(want);
|
||||
want.freq = opusConfig->sampleRate;
|
||||
|
@ -155,7 +109,7 @@ bool SdlAudioRenderer::prepareForPlayback(const OPUS_MULTISTREAM_CONFIGURATION*
|
|||
"Failed to open audio device: %s",
|
||||
SDL_GetError());
|
||||
SDL_QuitSubSystem(SDL_INIT_AUDIO);
|
||||
return -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
// SDL counts pending samples in the queued
|
||||
|
@ -182,14 +136,16 @@ bool SdlAudioRenderer::prepareForPlayback(const OPUS_MULTISTREAM_CONFIGURATION*
|
|||
// Start playback
|
||||
SDL_PauseAudioDevice(m_AudioDevice, 0);
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
SdlAudioRenderer::~SdlAudioRenderer()
|
||||
{
|
||||
// Stop playback
|
||||
SDL_PauseAudioDevice(m_AudioDevice, 1);
|
||||
SDL_CloseAudioDevice(m_AudioDevice);
|
||||
if (m_AudioDevice != 0) {
|
||||
// Stop playback
|
||||
SDL_PauseAudioDevice(m_AudioDevice, 1);
|
||||
SDL_CloseAudioDevice(m_AudioDevice);
|
||||
}
|
||||
|
||||
SDL_QuitSubSystem(SDL_INIT_AUDIO);
|
||||
SDL_assert(!SDL_WasInit(SDL_INIT_AUDIO));
|
||||
|
|
|
@ -279,7 +279,8 @@ Session::Session(NvComputer* computer, NvApp& app)
|
|||
m_DisplayOriginY(0),
|
||||
m_PendingWindowedTransition(false),
|
||||
m_OpusDecoder(nullptr),
|
||||
m_AudioRenderer(nullptr)
|
||||
m_AudioRenderer(nullptr),
|
||||
m_AudioRendererLock(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -1110,6 +1111,9 @@ DispatchDeferredCleanup:
|
|||
m_VideoDecoder = nullptr;
|
||||
SDL_AtomicUnlock(&m_DecoderLock);
|
||||
|
||||
// Destroy the audio renderer which must also be done on the main thread
|
||||
cleanupAudioRendererOnMainThread();
|
||||
|
||||
SDL_DestroyWindow(m_Window);
|
||||
if (iconSurface != nullptr) {
|
||||
SDL_FreeSurface(iconSurface);
|
||||
|
|
|
@ -54,6 +54,8 @@ private:
|
|||
|
||||
int detectAudioConfiguration();
|
||||
|
||||
void cleanupAudioRendererOnMainThread();
|
||||
|
||||
bool testAudio(int audioConfiguration);
|
||||
|
||||
void getWindowDimensions(int& x, int& y,
|
||||
|
@ -124,6 +126,7 @@ private:
|
|||
short m_OpusDecodeBuffer[MAX_CHANNELS * SAMPLES_PER_FRAME];
|
||||
IAudioRenderer* m_AudioRenderer;
|
||||
OPUS_MULTISTREAM_CONFIGURATION m_AudioConfig;
|
||||
SDL_SpinLock m_AudioRendererLock;
|
||||
|
||||
static AUDIO_RENDERER_CALLBACKS k_AudioCallbacks;
|
||||
static CONNECTION_LISTENER_CALLBACKS k_ConnCallbacks;
|
||||
|
|
Loading…
Reference in a new issue