diff --git a/README.md b/README.md index 5139f5ff2..ff209f366 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ yuzu emulator early access ============= -This is the source code for early-access 3009. +This is the source code for early-access 3011. ## Legal Notice diff --git a/src/audio_core/sink/cubeb_sink.cpp b/src/audio_core/sink/cubeb_sink.cpp index 36b115ad6..32c1b1cb3 100755 --- a/src/audio_core/sink/cubeb_sink.cpp +++ b/src/audio_core/sink/cubeb_sink.cpp @@ -66,10 +66,10 @@ public: const auto latency_error = cubeb_get_min_latency(ctx, ¶ms, &minimum_latency); if (latency_error != CUBEB_OK) { LOG_CRITICAL(Audio_Sink, "Error getting minimum latency, error: {}", latency_error); - minimum_latency = 256U; + minimum_latency = TargetSampleCount * 2; } - minimum_latency = std::max(minimum_latency, 256u); + minimum_latency = std::max(minimum_latency, TargetSampleCount * 2); LOG_INFO(Service_Audio, "Opening cubeb stream {} type {} with: rate {} channels {} (system channels {}) " @@ -326,4 +326,31 @@ std::vector ListCubebSinkDevices(bool capture) { return device_list; } +u32 GetCubebLatency() { + cubeb* ctx; + + 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; + } + + 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; +} + } // namespace AudioCore::Sink diff --git a/src/audio_core/sink/cubeb_sink.h b/src/audio_core/sink/cubeb_sink.h index 4b0cb160d..3302cb98d 100755 --- a/src/audio_core/sink/cubeb_sink.h +++ b/src/audio_core/sink/cubeb_sink.h @@ -96,4 +96,11 @@ private: */ std::vector ListCubebSinkDevices(bool capture); +/** + * Get the reported latency for this sink. + * + * @return Minimum latency for this sink. + */ +u32 GetCubebLatency(); + } // namespace AudioCore::Sink diff --git a/src/audio_core/sink/sdl2_sink.cpp b/src/audio_core/sink/sdl2_sink.cpp index 1bd001b94..f12ebf7fe 100755 --- a/src/audio_core/sink/sdl2_sink.cpp +++ b/src/audio_core/sink/sdl2_sink.cpp @@ -47,11 +47,7 @@ public: spec.freq = TargetSampleRate; spec.channels = static_cast(device_channels); spec.format = AUDIO_S16SYS; - if (type == StreamType::Render) { - spec.samples = TargetSampleCount; - } else { - spec.samples = 1024; - } + spec.samples = TargetSampleCount * 2; spec.callback = &SDLSinkStream::DataCallback; spec.userdata = this; @@ -240,4 +236,8 @@ std::vector ListSDLSinkDevices(bool capture) { return device_list; } +u32 GetSDLLatency() { + return TargetSampleCount * 2; +} + } // namespace AudioCore::Sink diff --git a/src/audio_core/sink/sdl2_sink.h b/src/audio_core/sink/sdl2_sink.h index f01eddc1b..27ed1ab94 100755 --- a/src/audio_core/sink/sdl2_sink.h +++ b/src/audio_core/sink/sdl2_sink.h @@ -87,4 +87,11 @@ private: */ std::vector ListSDLSinkDevices(bool capture); +/** + * Get the reported latency for this sink. + * + * @return Minimum latency for this sink. + */ +u32 GetSDLLatency(); + } // namespace AudioCore::Sink diff --git a/src/audio_core/sink/sink_details.cpp b/src/audio_core/sink/sink_details.cpp index 67bdab779..b878bf23f 100755 --- a/src/audio_core/sink/sink_details.cpp +++ b/src/audio_core/sink/sink_details.cpp @@ -21,58 +21,80 @@ namespace { struct SinkDetails { using FactoryFn = std::unique_ptr (*)(std::string_view); using ListDevicesFn = std::vector (*)(bool); + using LatencyFn = u32 (*)(); /// Name for this sink. - const char* id; + std::string_view id; /// A method to call to construct an instance of this type of sink. FactoryFn factory; /// A method to call to list available devices. ListDevicesFn list_devices; + /// Method to get the latency of this backend. + LatencyFn latency; }; // sink_details is ordered in terms of desirability, with the best choice at the top. constexpr SinkDetails sink_details[] = { #ifdef HAVE_CUBEB - SinkDetails{"cubeb", - [](std::string_view device_id) -> std::unique_ptr { - return std::make_unique(device_id); - }, - &ListCubebSinkDevices}, + SinkDetails{ + "cubeb", + [](std::string_view device_id) -> std::unique_ptr { + return std::make_unique(device_id); + }, + &ListCubebSinkDevices, + &GetCubebLatency, + }, #endif #ifdef HAVE_SDL2 - SinkDetails{"sdl2", - [](std::string_view device_id) -> std::unique_ptr { - return std::make_unique(device_id); - }, - &ListSDLSinkDevices}, + SinkDetails{ + "sdl", + [](std::string_view device_id) -> std::unique_ptr { + return std::make_unique(device_id); + }, + &ListSDLSinkDevices, + &GetSDLLatency, + }, #endif SinkDetails{"null", [](std::string_view device_id) -> std::unique_ptr { return std::make_unique(device_id); }, - [](bool capture) { return std::vector{"null"}; }}, + [](bool capture) { return std::vector{"null"}; }, []() { return 0u; }}, }; const SinkDetails& GetOutputSinkDetails(std::string_view sink_id) { - auto iter = - std::find_if(std::begin(sink_details), std::end(sink_details), - [sink_id](const auto& sink_detail) { return sink_detail.id == sink_id; }); + const auto find_backend{[](std::string_view id) { + return std::find_if(std::begin(sink_details), std::end(sink_details), + [&id](const auto& sink_detail) { return sink_detail.id == id; }); + }}; - if (sink_id == "auto" || iter == std::end(sink_details)) { - if (sink_id != "auto") { - LOG_ERROR(Audio, "Invalid sink_id {}", sink_id); + auto iter = find_backend(sink_id); + + if (sink_id == "auto") { + // 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("cubeb"); + if (iter->latency() > TargetSampleCount * 3) { + iter = find_backend("sdl"); } - // Auto-select. - // sink_details is ordered in terms of desirability, with the best choice at the front. +#else iter = std::begin(sink_details); +#endif + LOG_INFO(Service_Audio, "Auto-selecting the {} backend", iter->id); + } + + if (iter == std::end(sink_details)) { + LOG_ERROR(Audio, "Invalid sink_id {}", sink_id); + iter = find_backend("null"); } return *iter; } } // Anonymous namespace -std::vector GetSinkIDs() { - std::vector sink_ids(std::size(sink_details)); +std::vector GetSinkIDs() { + std::vector sink_ids(std::size(sink_details)); std::transform(std::begin(sink_details), std::end(sink_details), std::begin(sink_ids), [](const auto& sink) { return sink.id; }); diff --git a/src/audio_core/sink/sink_details.h b/src/audio_core/sink/sink_details.h index 3ebdb1e30..e75932898 100755 --- a/src/audio_core/sink/sink_details.h +++ b/src/audio_core/sink/sink_details.h @@ -19,7 +19,7 @@ class Sink; * * @return Vector of available sink names. */ -std::vector GetSinkIDs(); +std::vector GetSinkIDs(); /** * Gets the list of devices for a particular sink identified by the given ID. diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index e0db787fc..fad532115 100755 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp @@ -26,7 +26,7 @@ public: {10101, &IFriendService::GetFriendList, "GetFriendList"}, {10102, nullptr, "UpdateFriendInfo"}, {10110, nullptr, "GetFriendProfileImage"}, - {10120, nullptr, "IsFriendListCacheAvailable"}, + {10120, &IFriendService::CheckFriendListAvailability, "CheckFriendListAvailability"}, {10121, nullptr, "EnsureFriendListAvailable"}, {10200, nullptr, "SendFriendRequestForApplication"}, {10211, nullptr, "AddFacedFriendRequestForApplication"}, @@ -194,6 +194,17 @@ private: // TODO(ogniK): Return a buffer of u64s which are the "NetworkServiceAccountId" } + void CheckFriendListAvailability(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto uuid{rp.PopRaw()}; + + LOG_WARNING(Service_Friend, "(STUBBED) called, uuid=0x{}", uuid.RawString()); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(true); + } + KernelHelpers::ServiceContext service_context; Kernel::KEvent* completion_event; diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp index 19b8b15ef..70cc6f84b 100755 --- a/src/yuzu/configuration/configure_audio.cpp +++ b/src/yuzu/configuration/configure_audio.cpp @@ -161,8 +161,8 @@ void ConfigureAudio::InitializeAudioSinkComboBox() { ui->sink_combo_box->clear(); ui->sink_combo_box->addItem(QString::fromUtf8(AudioCore::Sink::auto_device_name)); - for (const char* id : AudioCore::Sink::GetSinkIDs()) { - ui->sink_combo_box->addItem(QString::fromUtf8(id)); + for (const auto& id : AudioCore::Sink::GetSinkIDs()) { + ui->sink_combo_box->addItem(QString::fromUtf8(id.data(), static_cast(id.length()))); } }