diff --git a/app/main.cpp b/app/main.cpp index c4e76b0a..8709aaa5 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -53,12 +53,8 @@ int main(int argc, char *argv[]) if (engine.rootObjects().isEmpty()) return -1; - // Ensure that SDL is always initialized since we may need to use it - // for non-streaming purposes (like checking on audio devices) SDL_SetMainReady(); - if (SDL_Init(SDL_INIT_VIDEO | - SDL_INIT_AUDIO | - SDL_INIT_GAMECONTROLLER) != 0) { + if (SDL_Init(0) != 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_Init() failed: %s", SDL_GetError()); diff --git a/app/streaming/audio.cpp b/app/streaming/audio.cpp index bedcc5ed..7a372453 100644 --- a/app/streaming/audio.cpp +++ b/app/streaming/audio.cpp @@ -23,6 +23,14 @@ int Session::sdlDetermineAudioConfiguration() { 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; @@ -38,7 +46,8 @@ int Session::sdlDetermineAudioConfiguration() "Failed to open audio device"); // We'll probably have issues during audio stream init, but we'll // try anyway - return AUDIO_CONFIGURATION_STEREO; + ret = AUDIO_CONFIGURATION_STEREO; + goto Exit; } SDL_CloseAudioDevice(dev); @@ -50,11 +59,15 @@ int Session::sdlDetermineAudioConfiguration() // 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. - return AUDIO_CONFIGURATION_51_SURROUND; + ret = AUDIO_CONFIGURATION_51_SURROUND; } else { - return AUDIO_CONFIGURATION_STEREO; + ret = AUDIO_CONFIGURATION_STEREO; } + +Exit: + SDL_QuitSubSystem(SDL_INIT_AUDIO); + return ret; } int Session::sdlAudioInit(int /* audioConfiguration */, @@ -64,6 +77,14 @@ int Session::sdlAudioInit(int /* audioConfiguration */, SDL_AudioSpec want, have; int error; + 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 AUDIO_CONFIGURATION_STEREO; + } + SDL_zero(want); want.freq = opusConfig->sampleRate; want.format = AUDIO_S16; @@ -80,6 +101,7 @@ int Session::sdlAudioInit(int /* audioConfiguration */, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to open audio device: %s", SDL_GetError()); + SDL_QuitSubSystem(SDL_INIT_AUDIO); return -1; } @@ -95,6 +117,7 @@ int Session::sdlAudioInit(int /* audioConfiguration */, error); SDL_CloseAudioDevice(s_AudioDevice); s_AudioDevice = 0; + SDL_QuitSubSystem(SDL_INIT_AUDIO); return -2; } @@ -140,7 +163,10 @@ void Session::sdlAudioCleanup() s_AudioDevice = 0; opus_multistream_decoder_destroy(s_OpusDecoder); - s_OpusDecoder = NULL; + s_OpusDecoder = nullptr; + + SDL_QuitSubSystem(SDL_INIT_AUDIO); + SDL_assert(!SDL_WasInit(SDL_INIT_AUDIO)); } void Session::sdlAudioDecodeAndPlaySample(char* sampleData, int sampleLength) diff --git a/app/streaming/input.cpp b/app/streaming/input.cpp index c12f76d0..db19a603 100644 --- a/app/streaming/input.cpp +++ b/app/streaming/input.cpp @@ -23,6 +23,15 @@ const int SdlInputHandler::k_ButtonMap[] = { SdlInputHandler::SdlInputHandler(bool multiController) : m_MultiController(multiController) { + // We need to reinit this each time, since you only get + // an initial set of gamepad arrival events once per init. + SDL_assert(!SDL_WasInit(SDL_INIT_GAMECONTROLLER)); + if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) != 0) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) failed: %s", + SDL_GetError()); + } + if (!m_MultiController) { // Player 1 is always present in non-MC mode m_GamepadMask = 0x1; @@ -38,6 +47,9 @@ SdlInputHandler::~SdlInputHandler() SDL_GameControllerClose(m_GamepadState[i].controller); } } + + SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER); + SDL_assert(!SDL_WasInit(SDL_INIT_GAMECONTROLLER)); } void SdlInputHandler::handleKeyEvent(SDL_KeyboardEvent* event) diff --git a/app/streaming/session.cpp b/app/streaming/session.cpp index 95cb07a3..19c09888 100644 --- a/app/streaming/session.cpp +++ b/app/streaming/session.cpp @@ -149,23 +149,35 @@ bool Session::isHardwareDecodeAvailable(StreamingPreferences::VideoDecoderSelect { IVideoDecoder* decoder; + if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "SDL_InitSubSystem(SDL_INIT_VIDEO) failed: %s", + SDL_GetError()); + return false; + } + SDL_Window* window = SDL_CreateWindow("", 0, 0, width, height, SDL_WINDOW_HIDDEN); if (!window) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create window for hardware decode test: %s", SDL_GetError()); + SDL_QuitSubSystem(SDL_INIT_VIDEO); return false; } if (!chooseDecoder(vds, window, videoFormat, width, height, frameRate, decoder)) { SDL_DestroyWindow(window); + SDL_QuitSubSystem(SDL_INIT_VIDEO); return false; } SDL_DestroyWindow(window); bool ret = decoder->isHardwareAccelerated(); + delete decoder; + SDL_QuitSubSystem(SDL_INIT_VIDEO); + return ret; } @@ -335,9 +347,6 @@ class DeferredSessionCleanupTask : public QRunnable { // Finish cleanup of the connection state LiStopConnection(); - if (Session::s_ActiveSession->m_Window != nullptr) { - SDL_DestroyWindow(Session::s_ActiveSession->m_Window); - } // Allow another session to start now that we're cleaned up Session::s_ActiveSession = nullptr; @@ -473,6 +482,16 @@ void Session::exec() return; } + SDL_assert(!SDL_WasInit(SDL_INIT_VIDEO)); + if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "SDL_InitSubSystem(SDL_INIT_VIDEO) failed: %s", + SDL_GetError()); + emit displayLaunchError(QString::fromLocal8Bit(SDL_GetError())); + s_ActiveSessionSemaphore.release(); + return; + } + int flags = SDL_WINDOW_HIDDEN; int x, y, width, height; if (m_Preferences.fullScreen) { @@ -493,6 +512,7 @@ void Session::exec() "SDL_CreateWindow() failed: %s", SDL_GetError()); s_ActiveSessionSemaphore.release(); + SDL_QuitSubSystem(SDL_INIT_VIDEO); return; } @@ -519,6 +539,7 @@ void Session::exec() // We already displayed an error dialog in the stage failure // listener. s_ActiveSessionSemaphore.release(); + SDL_QuitSubSystem(SDL_INIT_VIDEO); return; } @@ -634,9 +655,6 @@ DispatchDeferredCleanup: // so we can return to the Qt GUI ASAP. SDL_SetRelativeMouseMode(SDL_FALSE); SDL_EnableScreenSaver(); - if (m_Window != nullptr) { - SDL_HideWindow(m_Window); - } // Destroy the decoder, since this must be done on the main thread SDL_AtomicLock(&m_DecoderLock); @@ -644,6 +662,10 @@ DispatchDeferredCleanup: m_VideoDecoder = nullptr; SDL_AtomicUnlock(&m_DecoderLock); + SDL_DestroyWindow(m_Window); + SDL_QuitSubSystem(SDL_INIT_VIDEO); + SDL_assert(!SDL_WasInit(SDL_INIT_VIDEO)); + // Cleanup can take a while, so dispatch it to a worker thread. // When it is complete, it will release our s_ActiveSessionSemaphore // reference.