From 7803acc3dfd9c00060053aff65bdbc173cf9e106 Mon Sep 17 00:00:00 2001 From: The-Little-Wolf <116989599+The-Little-Wolf@users.noreply.github.com> Date: Tue, 15 Apr 2025 16:30:57 -0700 Subject: [PATCH] [XAM/XMP] - XMP Improvements - Proper returns for XMPContinue, XMPStop, XMPPause, XMPNext, XMPPrevious, and XMPSetPlaybackController - Set saved values in XMPGetPlaybackController - left notes --- src/xenia/apu/audio_media_player.h | 7 ++ src/xenia/kernel/xam/apps/xmp_app.cc | 105 ++++++++++++++++++--------- src/xenia/kernel/xam/apps/xmp_app.h | 13 ++-- 3 files changed, 85 insertions(+), 40 deletions(-) diff --git a/src/xenia/apu/audio_media_player.h b/src/xenia/apu/audio_media_player.h index 4343a8b9d..ac966d442 100644 --- a/src/xenia/apu/audio_media_player.h +++ b/src/xenia/apu/audio_media_player.h @@ -79,6 +79,12 @@ class AudioMediaPlayer { XmpApp::PlaybackClient GetPlaybackClient() const { return playback_client_; } uint32_t GetDashInItState() const { return dash_init_state; } + void SetPlaybackController(uint32_t playback_controller) { + playback_controller_ = playback_controller; + } + + uint32_t GetPlaybackController() const { return playback_controller_; } + bool IsTitleInPlaybackControl() const { return playback_client_ == XmpApp::PlaybackClient::kTitle || is_title_rendering_enabled_; @@ -106,6 +112,7 @@ class AudioMediaPlayer { XmpApp::PlaybackMode playback_mode_ = XmpApp::PlaybackMode::kInOrder; XmpApp::RepeatMode repeat_mode_ = XmpApp::RepeatMode::kPlaylist; XmpApp::PlaybackFlags playback_flags_ = XmpApp::PlaybackFlags::kDefault; + uint32_t playback_controller_ = 0; float volume_ = 1.0f; uint32_t dash_init_state = 0; diff --git a/src/xenia/kernel/xam/apps/xmp_app.cc b/src/xenia/kernel/xam/apps/xmp_app.cc index 95176156e..0b78a47df 100644 --- a/src/xenia/kernel/xam/apps/xmp_app.cc +++ b/src/xenia/kernel/xam/apps/xmp_app.cc @@ -117,35 +117,63 @@ X_HRESULT XmpApp::XMPPlayTitlePlaylist(uint32_t playlist_handle, return X_E_SUCCESS; } -X_HRESULT XmpApp::XMPContinue() { - XELOGD("XMPContinue()"); +X_HRESULT XmpApp::XMPAccessCheck(uint32_t xmp_client) { + /* Notes: + - A shared function that checks xmp_client, which controller and + playback_client is currently in xmp thread, and two unk variables held by + xmp thread. If any fail it returns X_E_ACCESS_DENIED; + - Used by XMPContinue, XMPStop, XMPPause, XMPNext, XMPPrevious, + XMPPlayTitlePlaylistEx, XMPPlayUserContent, XMPPlayMediaContainer, + XMPRestartPlayback, XMPSetVolumeEx, and XMPSetPlaybackBehaviorEx + */ + auto playback_client_ = + kernel_state_->emulator()->audio_media_player()->GetPlaybackClient(); + auto controller_ = + kernel_state_->emulator()->audio_media_player()->GetPlaybackController(); + if (xmp_client == 2 && + (playback_client_ != XmpApp::PlaybackClient::kSystem || controller_)) { + return X_E_ACCESS_DENIED; + } else if (!controller_) { + return X_E_ACCESS_DENIED; + } + if (controller_ == 2 || controller_ == 3) { + return X_E_ACCESS_DENIED; + } + if (xmp_client == 3 && controller_ == 1) { + return X_E_ACCESS_DENIED; + } + return X_E_SUCCESS; +} + +X_HRESULT XmpApp::XMPContinue(uint32_t xmp_client) { + XELOGD("XMPContinue(XMP Client: 0x{:08X})", xmp_client); kernel_state_->emulator()->audio_media_player()->Continue(); - return X_E_SUCCESS; + return XMPAccessCheck(xmp_client); } -X_HRESULT XmpApp::XMPStop(uint32_t unk) { +X_HRESULT XmpApp::XMPStop(uint32_t xmp_client, uint32_t unk) { assert_zero(unk); - XELOGD("XMPStop({:08X})", unk); + XELOGD("XMPStop(XMP Client: 0x{:08X}, Unk: 0x{:08X})", xmp_client, unk); kernel_state_->emulator()->audio_media_player()->Stop(true, false); - return X_E_SUCCESS; + return XMPAccessCheck(xmp_client); } -X_HRESULT XmpApp::XMPPause() { - XELOGD("XMPPause()"); +X_HRESULT XmpApp::XMPPause(uint32_t xmp_client) { + XELOGD("XMPPause(XMP Client: 0x{:08X})", xmp_client); kernel_state_->emulator()->audio_media_player()->Pause(); - return X_E_SUCCESS; + return XMPAccessCheck(xmp_client); } -X_HRESULT XmpApp::XMPNext() { - XELOGD("XMPNext()"); +X_HRESULT XmpApp::XMPNext(uint32_t xmp_client) { + XELOGD("XMPNext(XMP Client: 0x{:08X})", xmp_client); kernel_state_->emulator()->audio_media_player()->Next(); - return X_E_SUCCESS; + return XMPAccessCheck(xmp_client); } -X_HRESULT XmpApp::XMPPrevious() { - XELOGD("XMPPrevious()"); +X_HRESULT XmpApp::XMPPrevious(uint32_t xmp_client) { + XELOGD("XMPPrevious(XMP Client: 0x{:08X})", xmp_client); kernel_state_->emulator()->audio_media_player()->Previous(); - return X_E_SUCCESS; + return XMPAccessCheck(xmp_client); } X_HRESULT XmpApp::XMPGetTitlePlaylistBufferSize(uint32_t xmp_client, @@ -177,6 +205,7 @@ X_HRESULT XmpApp::XMPGetTitlePlaylistBufferSize(uint32_t xmp_client, X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, uint32_t buffer_length) { // NOTE: buffer_length may be zero or valid. + // TODO: Allow for message_ids to set extended error, only a few set length. auto buffer = memory_->TranslateVirtual(buffer_ptr); switch (message) { case 0x00070002: { @@ -191,33 +220,28 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, } case 0x00070003: { assert_true(!buffer_length || buffer_length == 4); - uint32_t xmp_client = xe::load_and_swap(buffer + 0); - assert_true(xmp_client == 0x00000002); - return XMPContinue(); + uint32_t xmp_client = xe::load_and_swap(buffer); + return XMPContinue(xmp_client); } case 0x00070004: { assert_true(!buffer_length || buffer_length == sizeof(XMP_STOP)); XMP_STOP* args = reinterpret_cast(buffer); - assert_true(args->xmp_client == 0x00000002); - return XMPStop(args->unk); + return XMPStop(args->xmp_client, args->unk); } case 0x00070005: { assert_true(!buffer_length || buffer_length == 4); - uint32_t xmp_client = xe::load_and_swap(buffer + 0); - assert_true(xmp_client == 0x00000002); - return XMPPause(); + uint32_t xmp_client = xe::load_and_swap(buffer); + return XMPPause(xmp_client); } case 0x00070006: { assert_true(!buffer_length || buffer_length == 4); - uint32_t xmp_client = xe::load_and_swap(buffer + 0); - assert_true(xmp_client == 0x00000002); - return XMPNext(); + uint32_t xmp_client = xe::load_and_swap(buffer); + return XMPNext(xmp_client); } case 0x00070007: { assert_true(!buffer_length || buffer_length == 4); - uint32_t xmp_client = xe::load_and_swap(buffer + 0); - assert_true(xmp_client == 0x00000002); - return XMPPrevious(); + uint32_t xmp_client = xe::load_and_swap(buffer); + return XMPPrevious(xmp_client); } case 0x00070008: { /* Notes: @@ -346,7 +370,10 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, return XMPDeleteTitlePlaylist(playlist_handle); } case 0x0007001A: { - // XMPSetPlaybackController + /* XMPSetPlaybackController Notes: + - if controller is equal to 4 then is uses a backup value stored at a + seperate location for both controller and playback client + */ assert_true(!buffer_length || buffer_length == sizeof(XMP_SET_PLAYBACK_CONTROLLER)); XMP_SET_PLAYBACK_CONTROLLER* args = @@ -358,9 +385,14 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, XELOGD("XMPSetPlaybackController({:08X}, {:08X}, {:08X})", uint32_t(args->xmp_client), uint32_t(args->controller), uint32_t(args->playback_client)); + if (args->controller > 4) { + return X_E_FUNCTION_FAILED; + } kernel_state_->emulator()->audio_media_player()->SetPlaybackClient( PlaybackClient(uint32_t(args->playback_client))); + kernel_state_->emulator()->audio_media_player()->SetPlaybackController( + uint32_t(args->controller)); kernel_state_->BroadcastNotification( kXNotificationXmpPlaybackControllerChanged, @@ -379,11 +411,16 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr, assert_true(args->xmp_client == 0x00000002); XELOGD("XMPGetPlaybackController({:08X}, {:08X}, {:08X})", uint32_t(args->xmp_client), uint32_t(args->controller_ptr), - uint32_t(args->locked_ptr)); + uint32_t(args->playback_client_ptr)); + + auto audio_media_player_ = + kernel_state_->emulator()->audio_media_player(); xe::store_and_swap( - memory_->TranslateVirtual(args->controller_ptr), 0); - xe::store_and_swap(memory_->TranslateVirtual(args->locked_ptr), - 0); + memory_->TranslateVirtual(args->controller_ptr), + uint32_t(audio_media_player_->GetPlaybackController())); + xe::store_and_swap( + memory_->TranslateVirtual(args->playback_client_ptr), + uint32_t(audio_media_player_->GetPlaybackClient())); if (!XThread::GetCurrentThread()->main_thread()) { // Atrain spawns a thread 82437FD0 to call this in a tight loop forever. diff --git a/src/xenia/kernel/xam/apps/xmp_app.h b/src/xenia/kernel/xam/apps/xmp_app.h index b0324fd81..2a673883b 100644 --- a/src/xenia/kernel/xam/apps/xmp_app.h +++ b/src/xenia/kernel/xam/apps/xmp_app.h @@ -126,7 +126,7 @@ static_assert_size(XMP_SET_PLAYBACK_CONTROLLER, 0xC); struct XMP_GET_PLAYBACK_CONTROLLER { xe::be xmp_client; xe::be controller_ptr; - xe::be locked_ptr; + xe::be playback_client_ptr; }; static_assert_size(XMP_GET_PLAYBACK_CONTROLLER, 0xC); @@ -252,11 +252,12 @@ class XmpApp : public App { X_HRESULT XMPDeleteTitlePlaylist(uint32_t playlist_handle); X_HRESULT XMPPlayTitlePlaylist(uint32_t playlist_handle, uint32_t song_handle); - X_HRESULT XMPContinue(); - X_HRESULT XMPStop(uint32_t unk); - X_HRESULT XMPPause(); - X_HRESULT XMPNext(); - X_HRESULT XMPPrevious(); + X_HRESULT XMPAccessCheck(uint32_t xmp_client); + X_HRESULT XMPContinue(uint32_t xmp_client); + X_HRESULT XMPStop(uint32_t xmp_client, uint32_t unk); + X_HRESULT XMPPause(uint32_t xmp_client); + X_HRESULT XMPNext(uint32_t xmp_client); + X_HRESULT XMPPrevious(uint32_t xmp_client); X_HRESULT XMPGetTitlePlaylistBufferSize(uint32_t xmp_client, uint32_t song_count, uint32_t storage_ptr);