output/Multiple: migrate from class Error to C++ exceptions

This commit is contained in:
Max Kellermann 2016-11-09 12:31:23 +01:00
parent 98a12c49dd
commit 445e82be75
3 changed files with 53 additions and 64 deletions

View File

@ -58,14 +58,8 @@ try {
AudioOutput *output = audio_output_new(event_loop, block, AudioOutput *output = audio_output_new(event_loop, block,
mixer_listener, mixer_listener,
pc, error); pc, error);
if (output == nullptr) { if (output == nullptr)
if (block.line > 0) throw std::runtime_error(error.GetMessage());
FormatFatalError("line %i: %s",
block.line,
error.GetMessage());
else
FatalError(error);
}
return output; return output;
} catch (const std::runtime_error &e) { } catch (const std::runtime_error &e) {
@ -192,32 +186,27 @@ MultipleOutputs::SetReplayGainMode(ReplayGainMode mode)
ao->SetReplayGainMode(mode); ao->SetReplayGainMode(mode);
} }
bool void
MultipleOutputs::Play(MusicChunk *chunk, Error &error) MultipleOutputs::Play(MusicChunk *chunk)
{ {
assert(buffer != nullptr); assert(buffer != nullptr);
assert(pipe != nullptr); assert(pipe != nullptr);
assert(chunk != nullptr); assert(chunk != nullptr);
assert(chunk->CheckFormat(input_audio_format)); assert(chunk->CheckFormat(input_audio_format));
if (!Update()) { if (!Update())
/* TODO: obtain real error */ /* TODO: obtain real error */
error.Set(output_domain, "Failed to open audio output"); throw std::runtime_error("Failed to open audio output");
return false;
}
pipe->Push(chunk); pipe->Push(chunk);
for (auto ao : outputs) for (auto ao : outputs)
ao->LockPlay(); ao->LockPlay();
return true;
} }
bool void
MultipleOutputs::Open(const AudioFormat audio_format, MultipleOutputs::Open(const AudioFormat audio_format,
MusicBuffer &_buffer, MusicBuffer &_buffer)
Error &error)
{ {
bool ret = false, enabled = false; bool ret = false, enabled = false;
@ -251,17 +240,16 @@ MultipleOutputs::Open(const AudioFormat audio_format,
ret = true; ret = true;
} }
if (!enabled) if (!enabled) {
error.Set(output_domain, "All audio outputs are disabled");
else if (!ret)
/* TODO: obtain real error */
error.Set(output_domain, "Failed to open audio output");
if (!ret)
/* close all devices if there was an error */ /* close all devices if there was an error */
Close(); Close();
throw std::runtime_error("All audio outputs are disabled");
return ret; } else if (!ret) {
/* close all devices if there was an error */
Close();
/* TODO: obtain real error */
throw std::runtime_error("Failed to open audio output");
}
} }
/** /**

View File

@ -118,13 +118,13 @@ public:
/** /**
* Opens all audio outputs which are not disabled. * Opens all audio outputs which are not disabled.
* *
* Throws #std::runtime_error on error.
*
* @param audio_format the preferred audio format * @param audio_format the preferred audio format
* @param _buffer the #music_buffer where consumed #MusicChunk objects * @param _buffer the #music_buffer where consumed #MusicChunk objects
* should be returned * should be returned
* @return true on success, false on failure
*/ */
bool Open(const AudioFormat audio_format, MusicBuffer &_buffer, void Open(const AudioFormat audio_format, MusicBuffer &_buffer);
Error &error);
/** /**
* Closes all audio outputs. * Closes all audio outputs.
@ -143,11 +143,11 @@ public:
* Enqueue a #MusicChunk object for playing, i.e. pushes it to a * Enqueue a #MusicChunk object for playing, i.e. pushes it to a
* #MusicPipe. * #MusicPipe.
* *
* Throws #std::runtime_error on error (all closed then).
*
* @param chunk the #MusicChunk object to be played * @param chunk the #MusicChunk object to be played
* @return true on success, false if no audio output was able to play
* (all closed then)
*/ */
bool Play(MusicChunk *chunk, Error &error); void Play(MusicChunk *chunk);
/** /**
* Checks if the output devices have drained their music pipe, and * Checks if the output devices have drained their music pipe, and

View File

@ -37,6 +37,8 @@
#include "thread/Name.hxx" #include "thread/Name.hxx"
#include "Log.hxx" #include "Log.hxx"
#include <stdexcept>
#include <string.h> #include <string.h>
static constexpr Domain player_domain("player"); static constexpr Domain player_domain("player");
@ -443,20 +445,10 @@ Player::OpenOutput()
assert(pc.state == PlayerState::PLAY || assert(pc.state == PlayerState::PLAY ||
pc.state == PlayerState::PAUSE); pc.state == PlayerState::PAUSE);
Error error; try {
if (pc.outputs.Open(play_audio_format, buffer, error)) { pc.outputs.Open(play_audio_format, buffer);
output_open = true; } catch (const std::runtime_error &e) {
paused = false; LogError(e);
pc.Lock();
pc.state = PlayerState::PLAY;
pc.Unlock();
idle_add(IDLE_PLAYER);
return true;
} else {
LogError(error);
output_open = false; output_open = false;
@ -465,7 +457,7 @@ Player::OpenOutput()
paused = true; paused = true;
pc.Lock(); pc.Lock();
pc.SetError(PlayerError::OUTPUT, std::move(error)); pc.SetError(PlayerError::OUTPUT, std::current_exception());
pc.state = PlayerState::PAUSE; pc.state = PlayerState::PAUSE;
pc.Unlock(); pc.Unlock();
@ -473,6 +465,17 @@ Player::OpenOutput()
return false; return false;
} }
output_open = true;
paused = false;
pc.Lock();
pc.state = PlayerState::PLAY;
pc.Unlock();
idle_add(IDLE_PLAYER);
return true;
} }
bool bool
@ -556,9 +559,10 @@ Player::SendSilence()
chunk->length = num_frames * frame_size; chunk->length = num_frames * frame_size;
PcmSilence({chunk->data, chunk->length}, play_audio_format.format); PcmSilence({chunk->data, chunk->length}, play_audio_format.format);
Error error; try {
if (!pc.outputs.Play(chunk, error)) { pc.outputs.Play(chunk);
LogError(error); } catch (const std::runtime_error &e) {
LogError(e);
buffer.Return(chunk); buffer.Return(chunk);
return false; return false;
} }
@ -770,12 +774,11 @@ update_song_tag(PlayerControl &pc, DetachedSong &song, const Tag &new_tag)
* *
* Player lock is not held. * Player lock is not held.
*/ */
static bool static void
play_chunk(PlayerControl &pc, play_chunk(PlayerControl &pc,
DetachedSong &song, MusicChunk *chunk, DetachedSong &song, MusicChunk *chunk,
MusicBuffer &buffer, MusicBuffer &buffer,
const AudioFormat format, const AudioFormat format)
Error &error)
{ {
assert(chunk->CheckFormat(format)); assert(chunk->CheckFormat(format));
@ -784,7 +787,7 @@ play_chunk(PlayerControl &pc,
if (chunk->IsEmpty()) { if (chunk->IsEmpty()) {
buffer.Return(chunk); buffer.Return(chunk);
return true; return;
} }
pc.Lock(); pc.Lock();
@ -793,12 +796,9 @@ play_chunk(PlayerControl &pc,
/* send the chunk to the audio outputs */ /* send the chunk to the audio outputs */
if (!pc.outputs.Play(chunk, error)) pc.outputs.Play(chunk);
return false;
pc.total_play_time += (double)chunk->length / pc.total_play_time += (double)chunk->length /
format.GetTimeToSize(); format.GetTimeToSize();
return true;
} }
inline bool inline bool
@ -899,15 +899,16 @@ Player::PlayNextChunk()
/* play the current chunk */ /* play the current chunk */
Error error; try {
if (!play_chunk(pc, *song, chunk, buffer, play_audio_format, error)) { play_chunk(pc, *song, chunk, buffer, play_audio_format);
LogError(error); } catch (const std::runtime_error &e) {
LogError(e);
buffer.Return(chunk); buffer.Return(chunk);
pc.Lock(); pc.Lock();
pc.SetError(PlayerError::OUTPUT, std::move(error)); pc.SetError(PlayerError::OUTPUT, std::current_exception());
/* pause: the user may resume playback as soon as an /* pause: the user may resume playback as soon as an
audio output becomes available */ audio output becomes available */