mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-06-04 05:45:03 -06:00
cellMusic: fix occasional deadlock during auto-play in playlist mode
This commit is contained in:
parent
ecf77ecef0
commit
17f1fc31bc
@ -66,6 +66,7 @@ void fmt_class_string<CellMusic2Error>::format(std::string& out, u64 arg)
|
|||||||
|
|
||||||
struct music_state
|
struct music_state
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
shared_mutex mutex;
|
shared_mutex mutex;
|
||||||
|
|
||||||
vm::ptr<void(u32 event, vm::ptr<void> param, vm::ptr<void> userData)> func{};
|
vm::ptr<void(u32 event, vm::ptr<void> param, vm::ptr<void> userData)> func{};
|
||||||
@ -99,19 +100,39 @@ struct music_state
|
|||||||
switch (status)
|
switch (status)
|
||||||
{
|
{
|
||||||
case music_handler_base::player_status::end_of_media:
|
case music_handler_base::player_status::end_of_media:
|
||||||
// Let's just play the next song for now
|
// Let's just play the next song for now if we are in list mode.
|
||||||
if (current_selection_context.content_type == CELL_SEARCH_CONTENTTYPE_MUSICLIST && handler->get_state() == CELL_MUSIC_PB_STATUS_PLAY)
|
// Due to potential main thread recursion this may cause a deadlock with the internal mutex of the handler.
|
||||||
{
|
// Let's just call it from another thread instead.
|
||||||
if (const error_code error = set_playback_command(CELL_MUSIC_PB_CMD_NEXT, true))
|
m_wake_up_thread = 1;
|
||||||
{
|
m_wake_up_thread.notify_one();
|
||||||
cellMusic.error("Failed to play next track. error=0x%x", +error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
m_thread = std::make_unique<named_thread<std::function<void()>>>("cellMusic State", [this]()
|
||||||
|
{
|
||||||
|
while (thread_ctrl::state() != thread_state::aborting)
|
||||||
|
{
|
||||||
|
while (thread_ctrl::state() != thread_state::aborting && !m_wake_up_thread)
|
||||||
|
{
|
||||||
|
thread_ctrl::wait_on(m_wake_up_thread, 0);
|
||||||
|
}
|
||||||
|
m_wake_up_thread = 0;
|
||||||
|
|
||||||
|
if (thread_ctrl::state() == thread_state::aborting)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Play the next song
|
||||||
|
if (const error_code error = set_playback_command(CELL_MUSIC_PB_CMD_NEXT_TRACK))
|
||||||
|
{
|
||||||
|
cellMusic.error("Failed to play next track. error=0x%x", +error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
music_state(utils::serial& ar)
|
music_state(utils::serial& ar)
|
||||||
@ -120,6 +141,19 @@ struct music_state
|
|||||||
save(ar);
|
save(ar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~music_state()
|
||||||
|
{
|
||||||
|
if (m_thread)
|
||||||
|
{
|
||||||
|
auto& thread = *m_thread;
|
||||||
|
thread = thread_state::aborting;
|
||||||
|
m_wake_up_thread = 1;
|
||||||
|
m_wake_up_thread.notify_one();
|
||||||
|
thread();
|
||||||
|
m_thread.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void save(utils::serial& ar)
|
void save(utils::serial& ar)
|
||||||
{
|
{
|
||||||
ar(func);
|
ar(func);
|
||||||
@ -135,7 +169,7 @@ struct music_state
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: This function only uses CELL_MUSIC enums. CELL_MUSIC2 enums are identical.
|
// NOTE: This function only uses CELL_MUSIC enums. CELL_MUSIC2 enums are identical.
|
||||||
error_code set_playback_command(s32 command, bool automatic = false)
|
error_code set_playback_command(u32 command)
|
||||||
{
|
{
|
||||||
switch (command)
|
switch (command)
|
||||||
{
|
{
|
||||||
@ -150,11 +184,27 @@ struct music_state
|
|||||||
case CELL_MUSIC_PB_CMD_FASTREVERSE:
|
case CELL_MUSIC_PB_CMD_FASTREVERSE:
|
||||||
case CELL_MUSIC_PB_CMD_NEXT:
|
case CELL_MUSIC_PB_CMD_NEXT:
|
||||||
case CELL_MUSIC_PB_CMD_PREV:
|
case CELL_MUSIC_PB_CMD_PREV:
|
||||||
|
case CELL_MUSIC_PB_CMD_NEXT_TRACK:
|
||||||
{
|
{
|
||||||
std::string path;
|
std::string path;
|
||||||
|
bool automatic = false;
|
||||||
bool no_more_tracks = false;
|
bool no_more_tracks = false;
|
||||||
{
|
{
|
||||||
std::lock_guard lock(mtx);
|
std::lock_guard lock(mtx);
|
||||||
|
|
||||||
|
// Handle auto-play of the next track in the current playlist.
|
||||||
|
if (command == CELL_MUSIC_PB_CMD_NEXT_TRACK)
|
||||||
|
{
|
||||||
|
// We only auto-play the next song if we are in list mode and the music is playing.
|
||||||
|
if (current_selection_context.content_type != CELL_SEARCH_CONTENTTYPE_MUSICLIST || handler->get_state() != CELL_MUSIC_PB_STATUS_PLAY)
|
||||||
|
{
|
||||||
|
return CELL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
command = CELL_MUSIC_PB_CMD_NEXT;
|
||||||
|
automatic = true;
|
||||||
|
}
|
||||||
|
|
||||||
const std::vector<std::string>& playlist = current_selection_context.playlist;
|
const std::vector<std::string>& playlist = current_selection_context.playlist;
|
||||||
const u32 current_track = current_selection_context.current_track;
|
const u32 current_track = current_selection_context.current_track;
|
||||||
u32 next_track = current_track;
|
u32 next_track = current_track;
|
||||||
@ -208,6 +258,10 @@ struct music_state
|
|||||||
|
|
||||||
return CELL_OK;
|
return CELL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<named_thread<std::function<void()>>> m_thread;
|
||||||
|
atomic_t<u32> m_wake_up_thread{0};
|
||||||
};
|
};
|
||||||
|
|
||||||
error_code cell_music_select_contents()
|
error_code cell_music_select_contents()
|
||||||
|
|||||||
@ -90,6 +90,8 @@ enum
|
|||||||
CELL_MUSIC_PB_CMD_PREV = 4,
|
CELL_MUSIC_PB_CMD_PREV = 4,
|
||||||
CELL_MUSIC_PB_CMD_FASTFORWARD = 5,
|
CELL_MUSIC_PB_CMD_FASTFORWARD = 5,
|
||||||
CELL_MUSIC_PB_CMD_FASTREVERSE = 6,
|
CELL_MUSIC_PB_CMD_FASTREVERSE = 6,
|
||||||
|
|
||||||
|
CELL_MUSIC_PB_CMD_NEXT_TRACK = 7, // RPCS3 helper for auto-play of the next track in the current playlist
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
|
|||||||
@ -257,10 +257,8 @@ namespace logs
|
|||||||
{
|
{
|
||||||
return found.first->second->enabled.observe();
|
return found.first->second->enabled.observe();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
return level::always;
|
||||||
return level::always;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_channel_levels(const std::map<std::string, logs::level, std::less<>>& map)
|
void set_channel_levels(const std::map<std::string, logs::level, std::less<>>& map)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user