diff --git a/src/audio_core/sink/cubeb_sink.cpp b/src/audio_core/sink/cubeb_sink.cpp index 49efae8e3..4e08b7bac 100644 --- a/src/audio_core/sink/cubeb_sink.cpp +++ b/src/audio_core/sink/cubeb_sink.cpp @@ -334,6 +334,48 @@ std::vector ListCubebSinkDevices(bool capture) { return device_list; } +/* REVERSION TO 3833 - function GetCubebLatency REINTRODUCED FROM 3833 - DIABLO 3 FIX */ +u32 GetCubebLatency() { + cubeb* ctx; + +#ifdef _WIN32 + auto com_init_result = CoInitializeEx(nullptr, COINIT_MULTITHREADED); +#endif + + // Init cubeb + if (cubeb_init(&ctx, "yuzu Latency Getter", nullptr) != CUBEB_OK) { + LOG_CRITICAL(Audio_Sink, "cubeb_init failed"); + // Return a large latency so we choose SDL instead. + return 10000u; + } + +#ifdef _WIN32 + if (SUCCEEDED(com_init_result)) { + CoUninitialize(); + } +#endif + + // Get min latency + cubeb_stream_params params{}; + params.rate = TargetSampleRate; + params.channels = 2; + params.format = CUBEB_SAMPLE_S16LE; + params.prefs = CUBEB_STREAM_PREF_NONE; + params.layout = CUBEB_LAYOUT_STEREO; + + u32 latency{0}; + const auto latency_error = cubeb_get_min_latency(ctx, ¶ms, &latency); + if (latency_error != CUBEB_OK) { + LOG_CRITICAL(Audio_Sink, "Error getting minimum latency, error: {}", latency_error); + latency = TargetSampleCount * 2; + } + latency = std::max(latency, TargetSampleCount * 2); + cubeb_destroy(ctx); + return latency; +} + +// REVERTED back to 3833 - Below namespace section and function IsCubebSuitable() removed, reverting to GetCubebLatency() above. - DIABLO 3 FIX +/* namespace { static long TmpDataCallback(cubeb_stream*, void*, const void*, void*, long) { return TargetSampleCount; @@ -400,5 +442,6 @@ bool IsCubebSuitable() { return true; #endif } +*/ } // namespace AudioCore::Sink diff --git a/src/audio_core/sink/cubeb_sink.h b/src/audio_core/sink/cubeb_sink.h index f49a6fdaa..bddc28915 100644 --- a/src/audio_core/sink/cubeb_sink.h +++ b/src/audio_core/sink/cubeb_sink.h @@ -96,12 +96,20 @@ private: */ std::vector ListCubebSinkDevices(bool capture); +// REVERSION - function GetCubebLatency() reintroduced from EA-3833 - DIABLO 3 FIX +/** + * Get the reported latency for this sink. + * + * @return Minimum latency for this sink. + */ +u32 GetCubebLatency(); + /** * Check if this backend is suitable for use. * Checks if enabled, its latency, whether it opens successfully, etc. * * @return True is this backend is suitable, false otherwise. */ -bool IsCubebSuitable(); +// bool IsCubebSuitable(); // REVERTED BACK TO GetCubebLatency() FROM 3833 } // namespace AudioCore::Sink diff --git a/src/audio_core/sink/sdl2_sink.cpp b/src/audio_core/sink/sdl2_sink.cpp index 7dd155ff0..ebbe1b163 100644 --- a/src/audio_core/sink/sdl2_sink.cpp +++ b/src/audio_core/sink/sdl2_sink.cpp @@ -230,6 +230,13 @@ std::vector ListSDLSinkDevices(bool capture) { return device_list; } +/* REVERSION to 3833 - function GetSDLLatency() REINTRODUCED FROM 3833 - DIABLO 3 FIX */ +u32 GetSDLLatency() { + return TargetSampleCount * 2; +} + +// REVERTED back to 3833 - Below function IsSDLSuitable() removed, reverting to GetSDLLatency() above. - DIABLO 3 FIX +/* bool IsSDLSuitable() { #if !defined(HAVE_SDL2) return false; @@ -267,5 +274,6 @@ bool IsSDLSuitable() { return true; #endif } +*/ } // namespace AudioCore::Sink diff --git a/src/audio_core/sink/sdl2_sink.h b/src/audio_core/sink/sdl2_sink.h index 9211d2e97..5d2f67152 100644 --- a/src/audio_core/sink/sdl2_sink.h +++ b/src/audio_core/sink/sdl2_sink.h @@ -87,12 +87,20 @@ private: */ std::vector ListSDLSinkDevices(bool capture); +// REVERSION - function GetSDLLatency() reintroduced from EA-3833 - DIABLO 3 FIX /** + * Get the reported latency for this sink. + * + * @return Minimum latency for this sink. + */ +u32 GetSDLLatency(); + +/** REVERTED back to 3833 - Below function IsSDLSuitable() removed, reverting to GetSDLLatency() above. - DIABLO 3 FIX * Check if this backend is suitable for use. * Checks if enabled, its latency, whether it opens successfully, etc. * * @return True is this backend is suitable, false otherwise. */ -bool IsSDLSuitable(); +//bool IsSDLSuitable(); // REVERTED for GetSDLLatency() from EA-3833 } // namespace AudioCore::Sink diff --git a/src/audio_core/sink/sink_details.cpp b/src/audio_core/sink/sink_details.cpp index 449af659d..d3f6f9c6c 100644 --- a/src/audio_core/sink/sink_details.cpp +++ b/src/audio_core/sink/sink_details.cpp @@ -25,7 +25,8 @@ namespace { struct SinkDetails { using FactoryFn = std::unique_ptr (*)(std::string_view); using ListDevicesFn = std::vector (*)(bool); - using SuitableFn = bool (*)(); + using LatencyFn = u32 (*)(); // REINTRODUCED FROM 3833 - DIABLO 3 FIX + // using SuitableFn = bool (*)(); // REVERTED FOR ABOVE - DIABLO 3 FIX /// Name for this sink. Settings::AudioEngine id; @@ -33,10 +34,18 @@ struct SinkDetails { FactoryFn factory; /// A method to call to list available devices. ListDevicesFn list_devices; + /// Method to get the latency of this backend - REINTRODUCED FROM 3833 - DIABLO 3 FIX + LatencyFn latency; /// Check whether this backend is suitable to be used. - SuitableFn is_suitable; + /// SuitableFn is_suitable; // REVERTED FOR LatencyFn latency ABOVE - DIABLO 3 FIX }; +// NOTE TO PROBABLY FIX LATER FOR ANDROID - the return value "0u" for the first HAVE_OBOE +// section below was just copied from the null section so there's a somewhat valid value +// being returned, since the previous "true" value probably isn't compatible with the +// previous EA-3833 code. (HAVE_OBOE was introduced in a later release.) Eventually need +// to change "0u" for something else directly from the oboe_sink.cpp functions. + // sink_details is ordered in terms of desirability, with the best choice at the top. constexpr SinkDetails sink_details[] = { #ifdef HAVE_OBOE @@ -46,7 +55,7 @@ constexpr SinkDetails sink_details[] = { return std::make_unique(); }, [](bool capture) { return std::vector{"Default"}; }, - []() { return true; }, + []() { return 0u; }, }, #endif #ifdef HAVE_CUBEB @@ -56,7 +65,7 @@ constexpr SinkDetails sink_details[] = { return std::make_unique(device_id); }, &ListCubebSinkDevices, - &IsCubebSuitable, + &GetCubebLatency, }, #endif #ifdef HAVE_SDL2 @@ -66,7 +75,7 @@ constexpr SinkDetails sink_details[] = { return std::make_unique(device_id); }, &ListSDLSinkDevices, - &IsSDLSuitable, + &GetSDLLatency, }, #endif SinkDetails{ @@ -75,7 +84,7 @@ constexpr SinkDetails sink_details[] = { return std::make_unique(device_id); }, [](bool capture) { return std::vector{"null"}; }, - []() { return true; }, + []() { return 0u; }, }, }; @@ -88,6 +97,8 @@ const SinkDetails& GetOutputSinkDetails(Settings::AudioEngine sink_id) { auto iter = find_backend(sink_id); if (sink_id == Settings::AudioEngine::Auto) { + // REVERTED TO 3833 BELOW - DIABLO 3 FIX + /* // Auto-select a backend. Use the sink details ordering, preferring cubeb first, checking // that the backend is available and suitable to use. for (auto& details : sink_details) { @@ -96,14 +107,29 @@ const SinkDetails& GetOutputSinkDetails(Settings::AudioEngine sink_id) { break; } } + */ // END REVERTED CODE - DIABLO 3 FIX + + // BEGIN REINTRODUCED FROM 3833 - REPLACED CODE BLOCK ABOVE - DIABLO 3 FIX + // Auto-select a backend. Prefer CubeB, but it may report a large minimum latency which + // causes audio issues, in that case go with SDL. +#if defined(HAVE_CUBEB) && defined(HAVE_SDL2) + iter = find_backend(Settings::AudioEngine::Cubeb); + if (iter->latency() > TargetSampleCount * 3) { + iter = find_backend(Settings::AudioEngine::Sdl2); + } +#else + iter = std::begin(sink_details); +#endif + // END REINTRODUCED SECTION FROM 3833 - DIABLO 3 FIX LOG_INFO(Service_Audio, "Auto-selecting the {} backend", Settings::CanonicalizeEnum(iter->id)); + /* BEGIN REMOVED - REVERTING BACK TO 3833, this didn't exist at all. - DIABLO 3 FIX } else { if (iter != std::end(sink_details) && !iter->is_suitable()) { LOG_ERROR(Service_Audio, "Selected backend {} is not suitable, falling back to null", Settings::CanonicalizeEnum(iter->id)); iter = find_backend(Settings::AudioEngine::Null); - } + } */ // END REMOVED REVERT - DIABLO 3 FIX } if (iter == std::end(sink_details)) {