player/Control: use class Error as C++ exception, throw it

This commit is contained in:
Max Kellermann 2016-09-08 10:29:49 +02:00
parent 3da4648112
commit 6e52ab285a
9 changed files with 150 additions and 141 deletions

View File

@ -129,35 +129,32 @@ struct Partition final : QueueListener, PlayerListener, MixerListener {
playlist.Stop(pc); playlist.Stop(pc);
} }
bool PlayPosition(int position, Error &error) { void PlayPosition(int position) {
return playlist.PlayPosition(pc, position, error); return playlist.PlayPosition(pc, position);
} }
bool PlayId(int id, Error &error) { void PlayId(int id) {
return playlist.PlayId(pc, id, error); return playlist.PlayId(pc, id);
} }
bool PlayNext(Error &error) { void PlayNext() {
return playlist.PlayNext(pc, error); return playlist.PlayNext(pc);
} }
bool PlayPrevious(Error &error) { void PlayPrevious() {
return playlist.PlayPrevious(pc, error); return playlist.PlayPrevious(pc);
} }
bool SeekSongPosition(unsigned song_position, void SeekSongPosition(unsigned song_position, SongTime seek_time) {
SongTime seek_time, Error &error) { playlist.SeekSongPosition(pc, song_position, seek_time);
return playlist.SeekSongPosition(pc, song_position, seek_time,
error);
} }
bool SeekSongId(unsigned song_id, SongTime seek_time, Error &error) { void SeekSongId(unsigned song_id, SongTime seek_time) {
return playlist.SeekSongId(pc, song_id, seek_time, error); playlist.SeekSongId(pc, song_id, seek_time);
} }
bool SeekCurrent(SignedSongTime seek_time, bool relative, void SeekCurrent(SignedSongTime seek_time, bool relative) {
Error &error) { playlist.SeekCurrent(pc, seek_time, relative);
return playlist.SeekCurrent(pc, seek_time, relative, error);
} }
void SetRepeat(bool new_value) { void SetRepeat(bool new_value) {

View File

@ -62,10 +62,8 @@ handle_play(Client &client, Request args, gcc_unused Response &r)
{ {
int song = args.ParseOptional(0, -1); int song = args.ParseOptional(0, -1);
Error error; client.partition.PlayPosition(song);
return client.partition.PlayPosition(song, error) return CommandResult::OK;
? CommandResult::OK
: print_error(r, error);
} }
CommandResult CommandResult
@ -73,10 +71,8 @@ handle_playid(Client &client, Request args, gcc_unused Response &r)
{ {
int id = args.ParseOptional(0, -1); int id = args.ParseOptional(0, -1);
Error error; client.partition.PlayId(id);
return client.partition.PlayId(id, error) return CommandResult::OK;
? CommandResult::OK
: print_error(r, error);
} }
CommandResult CommandResult
@ -223,20 +219,16 @@ handle_next(Client &client, gcc_unused Request args, gcc_unused Response &r)
playlist.queue.single = single; playlist.queue.single = single;
}; };
Error error; client.partition.PlayNext();
return client.partition.PlayNext(error) return CommandResult::OK;
? CommandResult::OK
: print_error(r, error);
} }
CommandResult CommandResult
handle_previous(Client &client, gcc_unused Request args, handle_previous(Client &client, gcc_unused Request args,
gcc_unused Response &r) gcc_unused Response &r)
{ {
Error error; client.partition.PlayPrevious();
return client.partition.PlayPrevious(error) return CommandResult::OK;
? CommandResult::OK
: print_error(r, error);
} }
CommandResult CommandResult
@ -281,40 +273,34 @@ handle_clearerror(Client &client, gcc_unused Request args,
} }
CommandResult CommandResult
handle_seek(Client &client, Request args, Response &r) handle_seek(Client &client, Request args, gcc_unused Response &r)
{ {
unsigned song = args.ParseUnsigned(0); unsigned song = args.ParseUnsigned(0);
SongTime seek_time = args.ParseSongTime(1); SongTime seek_time = args.ParseSongTime(1);
Error error; client.partition.SeekSongPosition(song, seek_time);
return client.partition.SeekSongPosition(song, seek_time, error) return CommandResult::OK;
? CommandResult::OK
: print_error(r, error);
} }
CommandResult CommandResult
handle_seekid(Client &client, Request args, Response &r) handle_seekid(Client &client, Request args, gcc_unused Response &r)
{ {
unsigned id = args.ParseUnsigned(0); unsigned id = args.ParseUnsigned(0);
SongTime seek_time = args.ParseSongTime(1); SongTime seek_time = args.ParseSongTime(1);
Error error; client.partition.SeekSongId(id, seek_time);
return client.partition.SeekSongId(id, seek_time, error) return CommandResult::OK;
? CommandResult::OK
: print_error(r, error);
} }
CommandResult CommandResult
handle_seekcur(Client &client, Request args, Response &r) handle_seekcur(Client &client, Request args, gcc_unused Response &r)
{ {
const char *p = args.front(); const char *p = args.front();
bool relative = *p == '+' || *p == '-'; bool relative = *p == '+' || *p == '-';
SignedSongTime seek_time = ParseCommandArgSignedSongTime(p); SignedSongTime seek_time = ParseCommandArgSignedSongTime(p);
Error error; client.partition.SeekCurrent(seek_time, relative);
return client.partition.SeekCurrent(seek_time, relative, error) return CommandResult::OK;
? CommandResult::OK
: print_error(r, error);
} }
CommandResult CommandResult

View File

@ -49,20 +49,18 @@ PlayerControl::~PlayerControl()
delete tagged_song; delete tagged_song;
} }
bool void
PlayerControl::Play(DetachedSong *song, Error &error_r) PlayerControl::Play(DetachedSong *song)
{ {
assert(song != nullptr); assert(song != nullptr);
const ScopeLock protect(mutex); const ScopeLock protect(mutex);
bool success = SeekLocked(song, SongTime::zero(), error_r); SeekLocked(song, SongTime::zero());
if (success && state == PlayerState::PAUSE) if (state == PlayerState::PAUSE)
/* if the player was paused previously, we need to /* if the player was paused previously, we need to
unpause it */ unpause it */
PauseLocked(); PauseLocked();
return success;
} }
void void
@ -203,8 +201,8 @@ PlayerControl::LockEnqueueSong(DetachedSong *song)
EnqueueSongLocked(song); EnqueueSongLocked(song);
} }
bool void
PlayerControl::SeekLocked(DetachedSong *song, SongTime t, Error &error_r) PlayerControl::SeekLocked(DetachedSong *song, SongTime t)
{ {
assert(song != nullptr); assert(song != nullptr);
@ -226,28 +224,23 @@ PlayerControl::SeekLocked(DetachedSong *song, SongTime t, Error &error_r)
if (error_type != PlayerError::NONE) { if (error_type != PlayerError::NONE) {
assert(error.IsDefined()); assert(error.IsDefined());
error_r.Set(error); throw error;
return false;
} }
assert(!error.IsDefined()); assert(!error.IsDefined());
return true;
} }
bool void
PlayerControl::LockSeek(DetachedSong *song, SongTime t, Error &error_r) PlayerControl::LockSeek(DetachedSong *song, SongTime t)
{ {
assert(song != nullptr); assert(song != nullptr);
{ {
const ScopeLock protect(mutex); const ScopeLock protect(mutex);
if (!SeekLocked(song, t, error_r)) SeekLocked(song, t);
return false;
} }
idle_add(IDLE_PLAYER); idle_add(IDLE_PLAYER);
return true;
} }
void void

View File

@ -308,10 +308,12 @@ private:
public: public:
/** /**
* Throws std::runtime_error or #Error on error.
*
* @param song the song to be queued; the given instance will * @param song the song to be queued; the given instance will
* be owned and freed by the player * be owned and freed by the player
*/ */
bool Play(DetachedSong *song, Error &error); void Play(DetachedSong *song);
/** /**
* see PlayerCommand::CANCEL * see PlayerCommand::CANCEL
@ -425,7 +427,10 @@ private:
SynchronousCommand(PlayerCommand::QUEUE); SynchronousCommand(PlayerCommand::QUEUE);
} }
bool SeekLocked(DetachedSong *song, SongTime t, Error &error_r); /**
* Throws std::runtime_error or #Error on error.
*/
void SeekLocked(DetachedSong *song, SongTime t);
public: public:
/** /**
@ -437,12 +442,12 @@ public:
/** /**
* Makes the player thread seek the specified song to a position. * Makes the player thread seek the specified song to a position.
* *
* Throws std::runtime_error or #Error on error.
*
* @param song the song to be queued; the given instance will be owned * @param song the song to be queued; the given instance will be owned
* and freed by the player * and freed by the player
* @return true on success, false on failure (e.g. if MPD isn't
* playing currently)
*/ */
bool LockSeek(DetachedSong *song, SongTime t, Error &error_r); void LockSeek(DetachedSong *song, SongTime t);
void SetCrossFade(float cross_fade_seconds); void SetCrossFade(float cross_fade_seconds);

View File

@ -151,8 +151,8 @@ playlist::UpdateQueuedSong(PlayerControl &pc, const DetachedSong *prev)
} }
} }
bool void
playlist::PlayOrder(PlayerControl &pc, unsigned order, Error &error) playlist::PlayOrder(PlayerControl &pc, unsigned order)
{ {
playing = true; playing = true;
queued = -1; queued = -1;
@ -163,12 +163,9 @@ playlist::PlayOrder(PlayerControl &pc, unsigned order, Error &error)
current = order; current = order;
if (!pc.Play(new DetachedSong(song), error)) pc.Play(new DetachedSong(song));
return false;
SongStarted(); SongStarted();
return true;
} }
void void
@ -227,8 +224,11 @@ playlist::ResumePlayback(PlayerControl &pc)
Stop(pc); Stop(pc);
else else
/* continue playback at the next song */ /* continue playback at the next song */
/* TODO: log error? */ try {
PlayNext(pc, IgnoreError()); PlayNext(pc);
} catch (...) {
/* TODO: log error? */
}
} }
void void

View File

@ -275,41 +275,63 @@ public:
void Stop(PlayerControl &pc); void Stop(PlayerControl &pc);
bool PlayPosition(PlayerControl &pc, int position, Error &error); /**
* Throws std::runtime_error or #Error on error.
*/
void PlayPosition(PlayerControl &pc, int position);
bool PlayOrder(PlayerControl &pc, unsigned order, Error &error); /**
* Throws std::runtime_error or #Error on error.
*/
void PlayOrder(PlayerControl &pc, unsigned order);
bool PlayId(PlayerControl &pc, int id, Error &error); /**
* Throws std::runtime_error or #Error on error.
*/
void PlayId(PlayerControl &pc, int id);
bool PlayNext(PlayerControl &pc, Error &error); /**
* Throws std::runtime_error or #Error on error.
*/
void PlayNext(PlayerControl &pc);
bool PlayPrevious(PlayerControl &pc, Error &error); /**
* Throws std::runtime_error or #Error on error.
*/
void PlayPrevious(PlayerControl &pc);
bool SeekSongOrder(PlayerControl &pc, /**
* Throws std::runtime_error or #Error on error.
*/
void SeekSongOrder(PlayerControl &pc,
unsigned song_order, unsigned song_order,
SongTime seek_time, SongTime seek_time);
Error &error);
bool SeekSongPosition(PlayerControl &pc, /**
* Throws std::runtime_error or #Error on error.
*/
void SeekSongPosition(PlayerControl &pc,
unsigned sonag_position, unsigned sonag_position,
SongTime seek_time, SongTime seek_time);
Error &error);
bool SeekSongId(PlayerControl &pc, /**
unsigned song_id, SongTime seek_time, * Throws std::runtime_error or #Error on error.
Error &error); */
void SeekSongId(PlayerControl &pc,
unsigned song_id, SongTime seek_time);
/** /**
* Seek within the current song. Fails if MPD is not currently * Seek within the current song. Fails if MPD is not currently
* playing. * playing.
* *
* Throws std::runtime_error or #Error on error.
*
* @param seek_time the time * @param seek_time the time
* @param relative if true, then the specified time is relative to the * @param relative if true, then the specified time is relative to the
* current position * current position
*/ */
bool SeekCurrent(PlayerControl &pc, void SeekCurrent(PlayerControl &pc,
SignedSongTime seek_time, bool relative, SignedSongTime seek_time, bool relative);
Error &error);
bool GetRepeat() const { bool GetRepeat() const {
return queue.repeat; return queue.repeat;

View File

@ -56,8 +56,8 @@ playlist::Stop(PlayerControl &pc)
} }
} }
bool void
playlist::PlayPosition(PlayerControl &pc, int song, Error &error) playlist::PlayPosition(PlayerControl &pc, int song)
{ {
pc.LockClearError(); pc.LockClearError();
@ -66,13 +66,13 @@ playlist::PlayPosition(PlayerControl &pc, int song, Error &error)
/* play any song ("current" song, or the first song */ /* play any song ("current" song, or the first song */
if (queue.IsEmpty()) if (queue.IsEmpty())
return true; return;
if (playing) { if (playing) {
/* already playing: unpause playback, just in /* already playing: unpause playback, just in
case it was paused, and return */ case it was paused, and return */
pc.LockSetPause(false); pc.LockSetPause(false);
return true; return;
} }
/* select a song: "current" song, or the first one */ /* select a song: "current" song, or the first one */
@ -102,24 +102,26 @@ playlist::PlayPosition(PlayerControl &pc, int song, Error &error)
stop_on_error = false; stop_on_error = false;
error_count = 0; error_count = 0;
return PlayOrder(pc, i, error); PlayOrder(pc, i);
} }
bool void
playlist::PlayId(PlayerControl &pc, int id, Error &error) playlist::PlayId(PlayerControl &pc, int id)
{ {
if (id == -1) if (id == -1) {
return PlayPosition(pc, id, error); PlayPosition(pc, id);
return;
}
int song = queue.IdToPosition(id); int song = queue.IdToPosition(id);
if (song < 0) if (song < 0)
throw PlaylistError::NoSuchSong(); throw PlaylistError::NoSuchSong();
return PlayPosition(pc, song, error); PlayPosition(pc, song);
} }
bool void
playlist::PlayNext(PlayerControl &pc, Error &error) playlist::PlayNext(PlayerControl &pc)
{ {
if (!playing) if (!playing)
throw PlaylistError::NotPlaying(); throw PlaylistError::NotPlaying();
@ -156,19 +158,16 @@ playlist::PlayNext(PlayerControl &pc, Error &error)
discard them anyway */ discard them anyway */
} }
if (!PlayOrder(pc, next_order, error)) PlayOrder(pc, next_order);
return false;
} }
/* Consume mode removes each played songs. */ /* Consume mode removes each played songs. */
if (queue.consume) if (queue.consume)
DeleteOrder(pc, old_current); DeleteOrder(pc, old_current);
return true;
} }
bool void
playlist::PlayPrevious(PlayerControl &pc, Error &error) playlist::PlayPrevious(PlayerControl &pc)
{ {
if (!playing) if (!playing)
throw PlaylistError::NotPlaying(); throw PlaylistError::NotPlaying();
@ -188,12 +187,11 @@ playlist::PlayPrevious(PlayerControl &pc, Error &error)
order = current; order = current;
} }
return PlayOrder(pc, order, error); PlayOrder(pc, order);
} }
bool void
playlist::SeekSongOrder(PlayerControl &pc, unsigned i, SongTime seek_time, playlist::SeekSongOrder(PlayerControl &pc, unsigned i, SongTime seek_time)
Error &error)
{ {
assert(queue.IsValidOrder(i)); assert(queue.IsValidOrder(i));
@ -215,20 +213,19 @@ playlist::SeekSongOrder(PlayerControl &pc, unsigned i, SongTime seek_time,
queued = -1; queued = -1;
if (!pc.LockSeek(new DetachedSong(queue.GetOrder(i)), seek_time, error)) { try {
pc.LockSeek(new DetachedSong(queue.GetOrder(i)), seek_time);
} catch (...) {
UpdateQueuedSong(pc, queued_song); UpdateQueuedSong(pc, queued_song);
return false; throw;
} }
UpdateQueuedSong(pc, nullptr); UpdateQueuedSong(pc, nullptr);
return true;
} }
bool void
playlist::SeekSongPosition(PlayerControl &pc, unsigned song, playlist::SeekSongPosition(PlayerControl &pc, unsigned song,
SongTime seek_time, SongTime seek_time)
Error &error)
{ {
if (!queue.IsValidPosition(song)) if (!queue.IsValidPosition(song))
throw PlaylistError::BadRange(); throw PlaylistError::BadRange();
@ -237,24 +234,22 @@ playlist::SeekSongPosition(PlayerControl &pc, unsigned song,
? queue.PositionToOrder(song) ? queue.PositionToOrder(song)
: song; : song;
return SeekSongOrder(pc, i, seek_time, error); SeekSongOrder(pc, i, seek_time);
} }
bool void
playlist::SeekSongId(PlayerControl &pc, unsigned id, SongTime seek_time, playlist::SeekSongId(PlayerControl &pc, unsigned id, SongTime seek_time)
Error &error)
{ {
int song = queue.IdToPosition(id); int song = queue.IdToPosition(id);
if (song < 0) if (song < 0)
throw PlaylistError::NoSuchSong(); throw PlaylistError::NoSuchSong();
return SeekSongPosition(pc, song, seek_time, error); SeekSongPosition(pc, song, seek_time);
} }
bool void
playlist::SeekCurrent(PlayerControl &pc, playlist::SeekCurrent(PlayerControl &pc,
SignedSongTime seek_time, bool relative, SignedSongTime seek_time, bool relative)
Error &error)
{ {
if (!playing) if (!playing)
throw PlaylistError::NotPlaying(); throw PlaylistError::NotPlaying();
@ -274,5 +269,5 @@ playlist::SeekCurrent(PlayerControl &pc,
if (seek_time.IsNegative()) if (seek_time.IsNegative())
seek_time = SignedSongTime::zero(); seek_time = SignedSongTime::zero();
return SeekSongOrder(pc, current, SongTime(seek_time), error); SeekSongOrder(pc, current, SongTime(seek_time));
} }

View File

@ -238,8 +238,11 @@ playlist::DeleteInternal(PlayerControl &pc,
if (current >= 0 && !paused) if (current >= 0 && !paused)
/* play the song after the deleted one */ /* play the song after the deleted one */
/* TODO: log error? */ try {
PlayOrder(pc, current, IgnoreError()); PlayOrder(pc, current);
} catch (...) {
/* TODO: log error? */
}
else { else {
/* stop the player */ /* stop the player */

View File

@ -195,12 +195,20 @@ playlist_state_restore(const char *line, TextFile &file,
if (state == PlayerState::STOP /* && config_option */) if (state == PlayerState::STOP /* && config_option */)
playlist.current = current; playlist.current = current;
else if (seek_time.count() == 0) else if (seek_time.count() == 0) {
/* TODO: log error? */ try {
playlist.PlayPosition(pc, current, IgnoreError()); playlist.PlayPosition(pc, current);
else } catch (...) {
playlist.SeekSongPosition(pc, current, seek_time, /* TODO: log error? */
IgnoreError()); }
} else {
try {
playlist.SeekSongPosition(pc, current,
seek_time);
} catch (...) {
/* TODO: log error? */
}
}
if (state == PlayerState::PAUSE) if (state == PlayerState::PAUSE)
pc.LockPause(); pc.LockPause();