[Xam/XMP App] - Clean up & improvements

- Clean up xmp app
- XMPGetTitlePlaylistBufferSize now returns proper errors
- Implement XMPGetDashInItState
- Add missing xnotifications
This commit is contained in:
The-Little-Wolf
2025-08-21 16:16:32 -07:00
committed by Radosław Gliński
parent 8545fe755e
commit 41b412fa76
4 changed files with 277 additions and 159 deletions

View File

@@ -77,6 +77,7 @@ class AudioMediaPlayer {
}
XmpApp::PlaybackClient GetPlaybackClient() const { return playback_client_; }
uint32_t GetDashInItState() const { return dash_init_state; }
bool IsTitleInPlaybackControl() const {
return playback_client_ == XmpApp::PlaybackClient::kTitle ||
@@ -106,6 +107,7 @@ class AudioMediaPlayer {
XmpApp::RepeatMode repeat_mode_ = XmpApp::RepeatMode::kPlaylist;
XmpApp::PlaybackFlags playback_flags_ = XmpApp::PlaybackFlags::kDefault;
float volume_ = 1.0f;
uint32_t dash_init_state = 0;
std::unordered_map<uint32_t, std::unique_ptr<XmpApp::Playlist>> playlists_;
XmpApp::Playlist* active_playlist_;

View File

@@ -148,20 +148,46 @@ X_HRESULT XmpApp::XMPPrevious() {
return X_E_SUCCESS;
}
X_HRESULT XmpApp::XMPGetTitlePlaylistBufferSize(uint32_t xmp_client,
uint32_t song_count,
uint32_t size_ptr) {
/* Note:
- Query of size for XamAlloc - the result of the alloc is passed to
0x0007000D.
- xmp_client can range from 0 - 6 but will fail on 1 and set size to zero
if its anything other than 0 or 2.
*/
XELOGD(
"XMPGetTitlePlaylistBufferSize(XMP client: 0x{:08X}, Song count: "
"0x{:08X}, Size ptr: 0x{:08X})",
xmp_client, song_count, size_ptr);
if (xmp_client == 1 || !size_ptr || !song_count) {
return X_E_INVALIDARG;
}
uint32_t size = 0;
if (xmp_client == 0 || xmp_client == 2) {
size = song_count * 0x3E8 + 0x88;
}
// We don't use the storage, so just fudge the number.
xe::store_and_swap<uint32_t>(memory_->TranslateVirtual(size_ptr), size);
return X_E_SUCCESS;
}
X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr,
uint32_t buffer_length) {
// NOTE: buffer_length may be zero or valid.
auto buffer = memory_->TranslateVirtual(buffer_ptr);
switch (message) {
case 0x00070002: {
assert_true(!buffer_length || buffer_length == 12);
uint32_t xmp_client = xe::load_and_swap<uint32_t>(buffer + 0);
uint32_t storage_ptr = xe::load_and_swap<uint32_t>(buffer + 4);
uint32_t song_handle = xe::load_and_swap<uint32_t>(buffer + 8); // 0?
uint32_t playlist_handle =
xe::load_and_swap<uint32_t>(memory_->TranslateVirtual(storage_ptr));
assert_true(xmp_client == 0x00000002);
return XMPPlayTitlePlaylist(playlist_handle, song_handle);
assert_true(!buffer_length ||
buffer_length == sizeof(XMP_PLAY_TITLE_PLAYLIST));
XMP_PLAY_TITLE_PLAYLIST* args =
reinterpret_cast<XMP_PLAY_TITLE_PLAYLIST*>(buffer);
uint32_t playlist_handle = xe::load_and_swap<uint32_t>(
memory_->TranslateVirtual(args->storage_ptr));
assert_true(args->xmp_client == 0x00000002);
return XMPPlayTitlePlaylist(playlist_handle, args->song_handle);
}
case 0x00070003: {
assert_true(!buffer_length || buffer_length == 4);
@@ -170,11 +196,10 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr,
return XMPContinue();
}
case 0x00070004: {
assert_true(!buffer_length || buffer_length == 8);
uint32_t xmp_client = xe::load_and_swap<uint32_t>(buffer + 0);
uint32_t unk = xe::load_and_swap<uint32_t>(buffer + 4);
assert_true(xmp_client == 0x00000002);
return XMPStop(unk);
assert_true(!buffer_length || buffer_length == sizeof(XMP_STOP));
XMP_STOP* args = reinterpret_cast<XMP_STOP*>(buffer);
assert_true(args->xmp_client == 0x00000002);
return XMPStop(args->unk);
}
case 0x00070005: {
assert_true(!buffer_length || buffer_length == 4);
@@ -195,20 +220,21 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr,
return XMPPrevious();
}
case 0x00070008: {
assert_true(!buffer_length || buffer_length == 16);
struct {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> playback_mode;
xe::be<uint32_t> repeat_mode;
xe::be<uint32_t> flags;
}* args = memory_->TranslateVirtual<decltype(args)>(buffer_ptr);
static_assert_size(decltype(*args), 16);
/* Notes:
- xmp_client == 2 uses kXNotificationXmpPlaybackBehaviorChanged while
the others, excluding 6 (returns X_E_ACCESS_DENIED), use
kXNotificationXmpPlaybackBehaviorChangedEx
*/
assert_true(!buffer_length ||
buffer_length == sizeof(XMP_SET_PLAYBACK_BEHAVIOR));
XMP_SET_PLAYBACK_BEHAVIOR* args =
reinterpret_cast<XMP_SET_PLAYBACK_BEHAVIOR*>(buffer);
assert_true(args->xmp_client == 0x00000002 ||
args->xmp_client == 0x00000000);
XELOGD("XMPSetPlaybackBehavior({:08X}, {:08X}, {:08X})",
uint32_t(args->playback_mode), uint32_t(args->repeat_mode),
uint32_t(args->flags));
XELOGD("XMPSetPlaybackBehavior({:08X}, {:08X}, {:08X}, {:08X})",
uint32_t(args->xmp_client), uint32_t(args->playback_mode),
uint32_t(args->repeat_mode), uint32_t(args->flags));
kernel_state_->emulator()->audio_media_player()->SetPlaybackMode(
static_cast<PlaybackMode>(uint32_t(args->playback_mode)));
@@ -222,20 +248,14 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr,
return X_E_SUCCESS;
}
case 0x00070009: {
assert_true(!buffer_length || buffer_length == 8);
uint32_t xmp_client = xe::load_and_swap<uint32_t>(buffer + 0);
uint32_t state_ptr =
xe::load_and_swap<uint32_t>(buffer + 4); // out ptr to 4b - expect 0
assert_true(xmp_client == 0x00000002);
return XMPGetStatus(state_ptr);
assert_true(!buffer_length || buffer_length == sizeof(XMP_GET_STATUS));
XMP_GET_STATUS* args = reinterpret_cast<XMP_GET_STATUS*>(buffer);
assert_true(args->xmp_client == 0x00000002);
return XMPGetStatus(args->state_ptr);
}
case 0x0007000B: {
assert_true(!buffer_length || buffer_length == 8);
struct {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> volume_ptr;
}* args = memory_->TranslateVirtual<decltype(args)>(buffer_ptr);
static_assert_size(decltype(*args), 8);
assert_true(!buffer_length || buffer_length == sizeof(XMP_GET_VOLUME));
XMP_GET_VOLUME* args = reinterpret_cast<XMP_GET_VOLUME*>(buffer);
assert_true(args->xmp_client == 0x00000002);
XELOGD("XMPGetVolume({:08X})", uint32_t(args->volume_ptr));
@@ -246,12 +266,8 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr,
return X_E_SUCCESS;
}
case 0x0007000C: {
assert_true(!buffer_length || buffer_length == 8);
struct {
xe::be<uint32_t> xmp_client;
xe::be<float> value;
}* args = memory_->TranslateVirtual<decltype(args)>(buffer_ptr);
static_assert_size(decltype(*args), 8);
assert_true(!buffer_length || buffer_length == sizeof(XMP_SET_VOLUME));
XMP_SET_VOLUME* args = reinterpret_cast<XMP_SET_VOLUME*>(buffer);
assert_true(args->xmp_client == 0x00000002);
XELOGD("XMPSetVolume({:d}, {:g})", args->xmp_client.get(),
@@ -261,19 +277,10 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr,
return X_E_SUCCESS;
}
case 0x0007000D: {
assert_true(!buffer_length || buffer_length == 36);
struct {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> storage_ptr;
xe::be<uint32_t> storage_size;
xe::be<uint32_t> songs_ptr;
xe::be<uint32_t> song_count;
xe::be<uint32_t> playlist_name_ptr;
xe::be<uint32_t> flags;
xe::be<uint32_t> song_handles_ptr;
xe::be<uint32_t> playlist_handle_ptr;
}* args = memory_->TranslateVirtual<decltype(args)>(buffer_ptr);
static_assert_size(decltype(*args), 36);
assert_true(!buffer_length ||
buffer_length == sizeof(XMP_CREATE_TITLE_PLAYLIST));
XMP_CREATE_TITLE_PLAYLIST* args =
reinterpret_cast<XMP_CREATE_TITLE_PLAYLIST*>(buffer);
xe::store_and_swap<uint32_t>(
memory_->TranslateVirtual(args->playlist_handle_ptr),
@@ -294,13 +301,10 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr,
args->storage_ptr);
}
case 0x0007000E: {
assert_true(!buffer_length || buffer_length == 12);
struct {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> unk_ptr; // 0
xe::be<uint32_t> info_ptr;
}* args = memory_->TranslateVirtual<decltype(args)>(buffer_ptr);
static_assert_size(decltype(*args), 12);
assert_true(!buffer_length ||
buffer_length == sizeof(XMP_GET_CURRENT_SONG));
XMP_GET_CURRENT_SONG* args =
reinterpret_cast<XMP_GET_CURRENT_SONG*>(buffer);
auto info = memory_->TranslateVirtual<XMP_SONGINFO*>(args->info_ptr);
assert_true(args->xmp_client == 0x00000002);
@@ -330,12 +334,10 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr,
return X_E_SUCCESS;
}
case 0x00070013: {
assert_true(!buffer_length || buffer_length == 8);
struct {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> storage_ptr;
}* args = memory_->TranslateVirtual<decltype(args)>(buffer_ptr);
static_assert_size(decltype(*args), 8);
assert_true(!buffer_length ||
buffer_length == sizeof(XMP_DELETE_TITLE_PLAYLIST));
XMP_DELETE_TITLE_PLAYLIST* args =
reinterpret_cast<XMP_DELETE_TITLE_PLAYLIST*>(buffer);
uint32_t playlist_handle = xe::load_and_swap<uint32_t>(
memory_->TranslateVirtual(args->storage_ptr));
@@ -345,19 +347,17 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr,
}
case 0x0007001A: {
// XMPSetPlaybackController
assert_true(!buffer_length || buffer_length == 12);
struct {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> controller;
xe::be<uint32_t> playback_client;
}* args = memory_->TranslateVirtual<decltype(args)>(buffer_ptr);
static_assert_size(decltype(*args), 12);
assert_true(!buffer_length ||
buffer_length == sizeof(XMP_SET_PLAYBACK_CONTROLLER));
XMP_SET_PLAYBACK_CONTROLLER* args =
reinterpret_cast<XMP_SET_PLAYBACK_CONTROLLER*>(buffer);
assert_true(
(args->xmp_client == 0x00000002 && args->controller == 0x00000000) ||
(args->xmp_client == 0x00000000 && args->controller == 0x00000001));
XELOGD("XMPSetPlaybackController({:08X}, {:08X})",
uint32_t(args->controller), uint32_t(args->playback_client));
XELOGD("XMPSetPlaybackController({:08X}, {:08X}, {:08X})",
uint32_t(args->xmp_client), uint32_t(args->controller),
uint32_t(args->playback_client));
kernel_state_->emulator()->audio_media_player()->SetPlaybackClient(
PlaybackClient(uint32_t(args->playback_client)));
@@ -371,13 +371,10 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr,
}
case 0x0007001B: {
// XMPGetPlaybackController
assert_true(!buffer_length || buffer_length == 12);
struct {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> controller_ptr;
xe::be<uint32_t> locked_ptr;
}* args = memory_->TranslateVirtual<decltype(args)>(buffer_ptr);
static_assert_size(decltype(*args), 12);
assert_true(!buffer_length ||
buffer_length == sizeof(XMP_GET_PLAYBACK_CONTROLLER));
XMP_GET_PLAYBACK_CONTROLLER* args =
reinterpret_cast<XMP_GET_PLAYBACK_CONTROLLER*>(buffer);
assert_true(args->xmp_client == 0x00000002);
XELOGD("XMPGetPlaybackController({:08X}, {:08X}, {:08X})",
@@ -401,23 +398,26 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr,
// Return buffer size is set to be items * 0x338 bytes.
// Games used in:
// 54540809, 494707D4
XMP_CREATE_USER_PLAYLIST_ENUMERATOR* args =
reinterpret_cast<XMP_CREATE_USER_PLAYLIST_ENUMERATOR*>(buffer);
XELOGD("XMPSetPlaybackController({:08X}, {:08X}, {:08X})",
uint32_t(args->xmp_client), uint32_t(args->flags),
uint32_t(args->unk_ptr));
return X_E_SUCCESS;
}
case 0x00070029: {
// XMPGetPlaybackBehavior
assert_true(!buffer_length || buffer_length == 16);
struct {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> playback_mode_ptr;
xe::be<uint32_t> repeat_mode_ptr;
xe::be<uint32_t> playback_flags_ptr;
}* args = memory_->TranslateVirtual<decltype(args)>(buffer_ptr);
static_assert_size(decltype(*args), 16);
assert_true(!buffer_length ||
buffer_length == sizeof(XMP_GET_PLAYBACK_BEHAVIOR));
XMP_GET_PLAYBACK_BEHAVIOR* args =
reinterpret_cast<XMP_GET_PLAYBACK_BEHAVIOR*>(buffer);
assert_true(args->xmp_client == 0x00000002 ||
args->xmp_client == 0x00000000);
XELOGD("XMPGetPlaybackBehavior({:08X}, {:08X}, {:08X})",
uint32_t(args->playback_mode_ptr), uint32_t(args->repeat_mode_ptr),
XELOGD("XMPGetPlaybackBehavior({:08X}, {:08X}, {:08X}, {:08X})",
uint32_t(args->xmp_client), uint32_t(args->playback_mode_ptr),
uint32_t(args->repeat_mode_ptr),
uint32_t(args->playback_flags_ptr));
if (args->playback_mode_ptr) {
xe::store_and_swap<uint32_t>(
@@ -446,76 +446,49 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr,
// XMPGetMediaSources
// Called on the NXE and Kinect dashboard after clicking on the picture,
// video, and music library
assert_true(!buffer_length || buffer_length == 20);
struct {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> unk1;
xe::be<uint32_t> unk2;
xe::be<uint32_t> unk3;
xe::be<uint32_t> unk4;
}* args = memory_->TranslateVirtual<decltype(args)>(buffer_ptr);
static_assert_size(decltype(*args), 20);
assert_true(!buffer_length ||
buffer_length == sizeof(XMP_GET_MEDIA_SOURCES));
XMP_GET_MEDIA_SOURCES* args =
reinterpret_cast<XMP_GET_MEDIA_SOURCES*>(buffer);
assert_true(args->xmp_client == 0x00000002 ||
args->xmp_client == 0x00000000);
XELOGD(
"XMPGetMediaSources({:08X}, {:08X}, {:08X}, {:08X}, {:08X}), "
"unimplemented",
args->xmp_client.get(), args->unk1.get(), args->unk2.get(),
args->unk3.get(), args->unk4.get());
args->xmp_client.get(), args->unk1.get(), args->unk1_ptr.get(),
args->unk2.get(), args->unk2_ptr.get());
return X_E_INVALIDARG;
}
case 0x0007002E: {
assert_true(!buffer_length || buffer_length == 12);
// Query of size for XamAlloc - the result of the alloc is passed to
// 0x0007000D.
struct {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> song_count;
xe::be<uint32_t> size_ptr;
}* args = memory_->TranslateVirtual<decltype(args)>(buffer_ptr);
static_assert_size(decltype(*args), 12);
assert_true(args->xmp_client == 0x00000002 ||
args->xmp_client == 0x00000000);
// We don't use the storage, so just fudge the number.
xe::store_and_swap<uint32_t>(memory_->TranslateVirtual(args->size_ptr),
args->song_count * 0x3E8 + 0x88);
return X_E_SUCCESS;
assert_true(!buffer_length ||
buffer_length == sizeof(XMP_GET_TITLE_PLAYLIST_BUFFER_SIZE));
XMP_GET_TITLE_PLAYLIST_BUFFER_SIZE* args =
reinterpret_cast<XMP_GET_TITLE_PLAYLIST_BUFFER_SIZE*>(buffer);
return XMPGetTitlePlaylistBufferSize(args->xmp_client, args->song_count,
args->size_ptr);
}
case 0x0007002F: {
// XMPDashInIt
// Called on the start up of all dashboard versions before kinect
assert_true(!buffer_length || buffer_length == 24);
struct {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> unk1;
xe::be<uint32_t> unk2;
xe::be<uint32_t> unk3;
xe::be<uint32_t> unk4;
xe::be<uint32_t> storage_ptr;
}* args = memory_->TranslateVirtual<decltype(args)>(buffer_ptr);
static_assert_size(decltype(*args), 24);
assert_true(!buffer_length || buffer_length == sizeof(XMP_DASH_INIT));
XMP_DASH_INIT* args = reinterpret_cast<XMP_DASH_INIT*>(buffer);
assert_true(args->xmp_client == 0x00000002 ||
args->xmp_client == 0x00000000);
XELOGD(
"XMPDashInIt({:08X}, {:08X}, {:08X}, {:08X}, {:08X}, {:08X}), "
"unimplemented",
args->xmp_client.get(), args->unk1.get(), args->unk2.get(),
args->unk3.get(), args->unk4.get(), args->storage_ptr.get());
args->xmp_client.get(), args->buffer_ptr.get(),
args->buffer_length.get(), args->unk1.get(), args->unk2.get(),
args->storage_ptr.get());
return X_E_INVALIDARG;
}
case 0x0007003D: {
// XMPCaptureOutput
assert_true(!buffer_length || buffer_length == 16);
struct {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> callback;
xe::be<uint32_t> context;
xe::be<uint32_t> title_render;
}* args = memory_->TranslateVirtual<decltype(args)>(buffer_ptr);
static_assert_size(decltype(*args), 16);
assert_true(!buffer_length ||
buffer_length == sizeof(XMP_CAPTURE_OUTPUT));
XMP_CAPTURE_OUTPUT* args = reinterpret_cast<XMP_CAPTURE_OUTPUT*>(buffer);
XELOGD("XMPCaptureOutput({:08X}, {:08X}, {:08X}, {:08X})",
args->xmp_client.get(), args->callback.get(), args->context.get(),
@@ -529,16 +502,13 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr,
// Called on the start up of all dashboard versions before kinect
// When it returns X_E_INVALIDARG you can access the music player up to
// version 5787
assert_true(!buffer_length || buffer_length == 16);
struct {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> unk1;
xe::be<uint32_t> storage_ptr;
xe::be<uint32_t> unk2;
}* args = memory_->TranslateVirtual<decltype(args)>(buffer_ptr);
static_assert_size(decltype(*args), 16);
assert_true(!buffer_length ||
buffer_length == sizeof(XMP_SET_MEDIA_SOURCE_WORKSPACE));
XMP_SET_MEDIA_SOURCE_WORKSPACE* args =
reinterpret_cast<XMP_SET_MEDIA_SOURCE_WORKSPACE*>(buffer);
assert_true(args->xmp_client == 0x00000002 ||
args->xmp_client == 0x00000001 ||
args->xmp_client == 0x00000000);
XELOGD(
"XMPSetMediaSourceWorkspace({:08X}, {:08X}, {:08X}, {:08X}), "
@@ -550,17 +520,14 @@ X_HRESULT XmpApp::DispatchMessageSync(uint32_t message, uint32_t buffer_ptr,
case 0x00070053: {
// Called on the blades dashboard Version 4532-5787 after clicking on the
// picture or video library. It only receives buffer
// *unk1_ptr = to some unknown value
struct {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> unk1_ptr;
}* args = memory_->TranslateVirtual<decltype(args)>(buffer_ptr);
static_assert_size(decltype(*args), 8);
XMP_GET_DASH_INIT_STATE* args =
reinterpret_cast<XMP_GET_DASH_INIT_STATE*>(buffer);
XELOGD("XMPGetDashInItState({:08X}, {:08X})", args->xmp_client.get(),
args->dash_init_state_ptr.get());
assert_true(args->xmp_client == 0x00000002 ||
args->xmp_client == 0x00000000);
XELOGD("XMPUnk70053({:08X}, {:08X}), unimplemented",
args->xmp_client.get(), args->unk1_ptr.get());
xe::store_and_swap<uint32_t>(
memory_->TranslateVirtual(args->dash_init_state_ptr),
kernel_state_->emulator()->audio_media_player()->GetDashInItState());
return X_E_SUCCESS;
}
}

View File

@@ -51,6 +51,148 @@ struct XMP_SONGINFO {
};
static_assert_size(XMP_SONGINFO, 988);
struct XMP_PLAY_TITLE_PLAYLIST {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> storage_ptr;
xe::be<uint32_t> song_handle;
};
static_assert_size(XMP_PLAY_TITLE_PLAYLIST, 0xC);
struct XMP_STOP {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> unk;
};
static_assert_size(XMP_STOP, 0x8);
struct XMP_SET_PLAYBACK_BEHAVIOR {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> playback_mode;
xe::be<uint32_t> repeat_mode;
xe::be<uint32_t> flags;
};
static_assert_size(XMP_SET_PLAYBACK_BEHAVIOR, 0x10);
struct XMP_GET_STATUS {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> state_ptr;
};
static_assert_size(XMP_GET_STATUS, 0x8);
struct XMP_GET_VOLUME {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> volume_ptr;
};
static_assert_size(XMP_GET_VOLUME, 0x8);
struct XMP_SET_VOLUME {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> value;
};
static_assert_size(XMP_SET_VOLUME, 0x8);
struct XMP_CREATE_TITLE_PLAYLIST {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> storage_ptr;
xe::be<uint32_t> storage_size;
xe::be<uint32_t> songs_ptr;
xe::be<uint32_t> song_count;
xe::be<uint32_t> playlist_name_ptr;
xe::be<uint32_t> flags;
xe::be<uint32_t> song_handles_ptr;
xe::be<uint32_t> playlist_handle_ptr;
};
static_assert_size(XMP_CREATE_TITLE_PLAYLIST, 0x24);
struct XMP_GET_CURRENT_SONG {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> unk_ptr;
xe::be<uint32_t> info_ptr;
};
static_assert_size(XMP_GET_CURRENT_SONG, 0xC);
struct XMP_DELETE_TITLE_PLAYLIST {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> storage_ptr;
};
static_assert_size(XMP_DELETE_TITLE_PLAYLIST, 0x8);
struct XMP_SET_PLAYBACK_CONTROLLER {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> controller;
xe::be<uint32_t> playback_client;
};
static_assert_size(XMP_SET_PLAYBACK_CONTROLLER, 0xC);
struct XMP_GET_PLAYBACK_CONTROLLER {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> controller_ptr;
xe::be<uint32_t> locked_ptr;
};
static_assert_size(XMP_GET_PLAYBACK_CONTROLLER, 0xC);
struct XMP_CREATE_USER_PLAYLIST_ENUMERATOR {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> flags;
xe::be<uint32_t> unk_ptr;
};
static_assert_size(XMP_CREATE_USER_PLAYLIST_ENUMERATOR, 0xC);
struct XMP_GET_PLAYBACK_BEHAVIOR {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> playback_mode_ptr;
xe::be<uint32_t> repeat_mode_ptr;
xe::be<uint32_t> playback_flags_ptr;
};
static_assert_size(XMP_GET_PLAYBACK_BEHAVIOR, 0x10);
struct XMP_GET_MEDIA_SOURCES {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> unk1;
xe::be<uint32_t> unk1_ptr;
xe::be<uint32_t> unk2;
xe::be<uint32_t> unk2_ptr;
};
static_assert_size(XMP_GET_MEDIA_SOURCES, 0x14);
struct XMP_GET_TITLE_PLAYLIST_BUFFER_SIZE {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> song_count;
xe::be<uint32_t> size_ptr;
};
static_assert_size(XMP_GET_TITLE_PLAYLIST_BUFFER_SIZE, 0xC);
struct XMP_DASH_INIT {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> buffer_ptr; // used by XamEnumerate
xe::be<uint32_t> buffer_length; // used by XamEnumerate
xe::be<uint32_t> unk1;
xe::be<uint32_t> unk2;
xe::be<uint32_t> storage_ptr;
};
static_assert_size(XMP_DASH_INIT, 0x18);
struct XMP_CAPTURE_OUTPUT {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> callback;
xe::be<uint32_t> context;
xe::be<uint32_t> title_render;
};
static_assert_size(XMP_CAPTURE_OUTPUT, 0x10);
struct XMP_SET_MEDIA_SOURCE_WORKSPACE {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> unk1;
xe::be<uint32_t> storage_ptr;
xe::be<uint32_t> unk2;
};
static_assert_size(XMP_SET_MEDIA_SOURCE_WORKSPACE, 0x10);
struct XMP_GET_DASH_INIT_STATE {
xe::be<uint32_t> xmp_client;
xe::be<uint32_t> dash_init_state_ptr;
};
static_assert_size(XMP_GET_DASH_INIT_STATE, 0x8);
class XmpApp : public App {
public:
enum class State : uint32_t {
@@ -115,6 +257,9 @@ class XmpApp : public App {
X_HRESULT XMPPause();
X_HRESULT XMPNext();
X_HRESULT XMPPrevious();
X_HRESULT XMPGetTitlePlaylistBufferSize(uint32_t xmp_client,
uint32_t song_count,
uint32_t storage_ptr);
X_HRESULT DispatchMessageSync(uint32_t message, uint32_t buffer_ptr,
uint32_t buffer_length) override;

View File

@@ -122,10 +122,12 @@ typedef uint32_t X_HRESULT;
#define X_E_NOT_IMPLEMENTED static_cast<X_HRESULT>(0x80004001L)
#define X_E_FAIL static_cast<X_HRESULT>(0x80004005L)
#define X_E_NO_MORE_FILES X_HRESULT_FROM_WIN32(X_ERROR_NO_MORE_FILES)
#define X_E_NOT_SUPPORTED X_HRESULT_FROM_WIN32(X_ERROR_NOT_SUPPORTED)
#define X_E_INVALIDARG X_HRESULT_FROM_WIN32(X_ERROR_INVALID_PARAMETER)
#define X_E_DEVICE_NOT_CONNECTED X_HRESULT_FROM_WIN32(X_ERROR_DEVICE_NOT_CONNECTED)
#define X_E_NOTFOUND X_HRESULT_FROM_WIN32(X_ERROR_NOT_FOUND)
#define X_E_NO_SUCH_USER X_HRESULT_FROM_WIN32(X_ERROR_NO_SUCH_USER)
#define X_E_FUNCTION_FAILED X_HRESULT_FROM_WIN32(X_ERROR_FUNCTION_FAILED)
// Sockets/networking.
#define X_INVALID_SOCKET (uint32_t)(~0)
@@ -257,6 +259,8 @@ enum : XNotificationID {
kXNotificationXmpTitlePlayListContentChanged = 0x8A000005,
kXNotificationXmpLocalMediaContentChanged = 0x8A000006,
kXNotificationXmpDashNowPlayingQueueModeChanged = 0x8A000007,
kXNotificationXmpDashInItChanged = 0x8A000009,
kXNotificationXmpPlaybackBehaviorChangedEx = 0x8A00000A,
// XNotification Party
kXNotificationPartyMembersChanged = 0x0E040002,