diff options
Diffstat (limited to 'src/PlayerThread.cxx')
-rw-r--r-- | src/PlayerThread.cxx | 146 |
1 files changed, 68 insertions, 78 deletions
diff --git a/src/PlayerThread.cxx b/src/PlayerThread.cxx index 356559e37..9f342ad5d 100644 --- a/src/PlayerThread.cxx +++ b/src/PlayerThread.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * Copyright (C) 2003-2014 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -19,21 +19,21 @@ #include "config.h" #include "PlayerThread.hxx" -#include "DecoderThread.hxx" -#include "DecoderControl.hxx" +#include "PlayerListener.hxx" +#include "decoder/DecoderThread.hxx" +#include "decoder/DecoderControl.hxx" #include "MusicPipe.hxx" #include "MusicBuffer.hxx" #include "MusicChunk.hxx" -#include "Song.hxx" -#include "Main.hxx" +#include "DetachedSong.hxx" #include "system/FatalError.hxx" #include "CrossFade.hxx" #include "PlayerControl.hxx" -#include "OutputAll.hxx" +#include "output/MultipleOutputs.hxx" #include "tag/Tag.hxx" #include "Idle.hxx" -#include "GlobalEvents.hxx" #include "util/Domain.hxx" +#include "thread/Name.hxx" #include "Log.hxx" #include <string.h> @@ -93,7 +93,7 @@ class Player { /** * the song currently being played */ - Song *song; + DetachedSong *song; /** * is cross fading enabled? @@ -125,7 +125,7 @@ class Player { /** * The time stamp of the chunk most recently sent to the * output thread. This attribute is only used if - * audio_output_all_get_elapsed_time() didn't return a usable + * MultipleOutputs::GetElapsedTime() didn't return a usable * value; the output thread can estimate the elapsed time more * precisely. */ @@ -228,8 +228,8 @@ private: bool WaitForDecoder(); /** - * Wrapper for audio_output_all_open(). Upon failure, it pauses the - * player. + * Wrapper for MultipleOutputs::Open(). Upon failure, it + * pauses the player. * * @return true on success */ @@ -291,12 +291,12 @@ Player::StartDecoder(MusicPipe &_pipe) assert(queued || pc.command == PlayerCommand::SEEK); assert(pc.next_song != nullptr); - unsigned start_ms = pc.next_song->start_ms; + unsigned start_ms = pc.next_song->GetStartMS(); if (pc.command == PlayerCommand::SEEK) start_ms += (unsigned)(pc.seek_where * 1000); - dc.Start(pc.next_song->DupDetached(), - start_ms, pc.next_song->end_ms, + dc.Start(new DetachedSong(*pc.next_song), + start_ms, pc.next_song->GetEndMS(), buffer, _pipe); } @@ -330,7 +330,7 @@ Player::WaitForDecoder() if (error.IsDefined()) { pc.SetError(PlayerError::DECODER, std::move(error)); - pc.next_song->Free(); + delete pc.next_song; pc.next_song = nullptr; pc.Unlock(); @@ -340,9 +340,7 @@ Player::WaitForDecoder() pc.ClearTaggedSong(); - if (song != nullptr) - song->Free(); - + delete song; song = pc.next_song; elapsed_time = 0.0; @@ -361,7 +359,7 @@ Player::WaitForDecoder() pc.Unlock(); /* call syncPlaylistWithQueue() in the main thread */ - GlobalEvents::Emit(GlobalEvents::PLAYLIST); + pc.listener.OnPlayerSync(); return true; } @@ -371,19 +369,20 @@ Player::WaitForDecoder() * indicated by the decoder plugin. */ static double -real_song_duration(const Song *song, double decoder_duration) +real_song_duration(const DetachedSong &song, double decoder_duration) { - assert(song != nullptr); - if (decoder_duration <= 0.0) /* the decoder plugin didn't provide information; fall back to Song::GetDuration() */ - return song->GetDuration(); + return song.GetDuration(); - if (song->end_ms > 0 && song->end_ms / 1000.0 < decoder_duration) - return (song->end_ms - song->start_ms) / 1000.0; + const unsigned start_ms = song.GetStartMS(); + const unsigned end_ms = song.GetEndMS(); - return decoder_duration - song->start_ms / 1000.0; + if (end_ms > 0 && end_ms / 1000.0 < decoder_duration) + return (end_ms - start_ms) / 1000.0; + + return decoder_duration - start_ms / 1000.0; } bool @@ -394,7 +393,7 @@ Player::OpenOutput() pc.state == PlayerState::PAUSE); Error error; - if (audio_output_all_open(play_audio_format, buffer, error)) { + if (pc.outputs.Open(play_audio_format, buffer, error)) { output_open = true; paused = false; @@ -445,13 +444,13 @@ Player::CheckDecoderStartup() pc.Unlock(); if (output_open && - !audio_output_all_wait(pc, 1)) + !pc.outputs.Wait(pc, 1)) /* the output devices havn't finished playing all chunks yet - wait for that */ return true; pc.Lock(); - pc.total_time = real_song_duration(dc.song, dc.total_time); + pc.total_time = real_song_duration(*dc.song, dc.total_time); pc.audio_format = dc.in_audio_format; pc.Unlock(); @@ -461,10 +460,10 @@ Player::CheckDecoderStartup() decoder_starting = false; if (!paused && !OpenOutput()) { - const auto uri = dc.song->GetURI(); FormatError(player_domain, "problems opening audio device " - "while playing \"%s\"", uri.c_str()); + "while playing \"%s\"", + dc.song->GetURI()); return true; } @@ -505,7 +504,7 @@ Player::SendSilence() memset(chunk->data, 0, chunk->length); Error error; - if (!audio_output_all_play(chunk, error)) { + if (!pc.outputs.Play(chunk, error)) { LogError(error); buffer.Return(chunk); return false; @@ -519,7 +518,7 @@ Player::SeekDecoder() { assert(pc.next_song != nullptr); - const unsigned start_ms = pc.next_song->start_ms; + const unsigned start_ms = pc.next_song->GetStartMS(); if (!dc.LockIsCurrentSong(*pc.next_song)) { /* the decoder is already decoding the "next" song - @@ -545,7 +544,7 @@ Player::SeekDecoder() ClearAndReplacePipe(dc.pipe); } - pc.next_song->Free(); + delete pc.next_song; pc.next_song = nullptr; queued = false; } @@ -583,7 +582,7 @@ Player::SeekDecoder() /* re-fill the buffer after seeking */ buffering = true; - audio_output_all_cancel(); + pc.outputs.Cancel(); return true; } @@ -600,7 +599,7 @@ Player::ProcessCommand() case PlayerCommand::UPDATE_AUDIO: pc.Unlock(); - audio_output_all_enable_disable(); + pc.outputs.EnableDisable(); pc.Lock(); pc.CommandFinished(); break; @@ -619,7 +618,7 @@ Player::ProcessCommand() paused = !paused; if (paused) { - audio_output_all_pause(); + pc.outputs.Pause(); pc.Lock(); pc.state = PlayerState::PAUSE; @@ -661,7 +660,7 @@ Player::ProcessCommand() pc.Lock(); } - pc.next_song->Free(); + delete pc.next_song; pc.next_song = nullptr; queued = false; pc.CommandFinished(); @@ -670,11 +669,11 @@ Player::ProcessCommand() case PlayerCommand::REFRESH: if (output_open && !paused) { pc.Unlock(); - audio_output_all_check(); + pc.outputs.Check(); pc.Lock(); } - pc.elapsed_time = audio_output_all_get_elapsed_time(); + pc.elapsed_time = pc.outputs.GetElapsedTime(); if (pc.elapsed_time < 0.0) pc.elapsed_time = elapsed_time; @@ -684,23 +683,20 @@ Player::ProcessCommand() } static void -update_song_tag(PlayerControl &pc, Song *song, const Tag &new_tag) +update_song_tag(PlayerControl &pc, DetachedSong &song, const Tag &new_tag) { - if (song->IsFile()) + if (song.IsFile()) /* don't update tags of local files, only remote streams may change tags dynamically */ return; - Tag *old_tag = song->tag; - song->tag = new Tag(new_tag); - - delete old_tag; + song.SetTag(new_tag); - pc.LockSetTaggedSong(*song); + pc.LockSetTaggedSong(song); /* the main thread will update the playlist version when he receives this event */ - GlobalEvents::Emit(GlobalEvents::TAG); + pc.listener.OnPlayerTagModified(); /* notify all clients that the tag of the current song has changed */ @@ -716,7 +712,7 @@ update_song_tag(PlayerControl &pc, Song *song, const Tag &new_tag) */ static bool play_chunk(PlayerControl &pc, - Song *song, struct music_chunk *chunk, + DetachedSong &song, struct music_chunk *chunk, MusicBuffer &buffer, const AudioFormat format, Error &error) @@ -737,7 +733,7 @@ play_chunk(PlayerControl &pc, /* send the chunk to the audio outputs */ - if (!audio_output_all_play(chunk, error)) + if (!pc.outputs.Play(chunk, error)) return false; pc.total_play_time += (double)chunk->length / @@ -748,7 +744,7 @@ play_chunk(PlayerControl &pc, inline bool Player::PlayNextChunk() { - if (!audio_output_all_wait(pc, 64)) + if (!pc.outputs.Wait(pc, 64)) /* the output pipe is still large enough, don't send another chunk */ return true; @@ -839,7 +835,7 @@ Player::PlayNextChunk() /* play the current chunk */ Error error; - if (!play_chunk(pc, song, chunk, buffer, play_audio_format, error)) { + if (!play_chunk(pc, *song, chunk, buffer, play_audio_format, error)) { LogError(error); buffer.Return(chunk); @@ -883,14 +879,11 @@ Player::SongBorder() { xfade_state = CrossFadeState::UNKNOWN; - { - const auto uri = song->GetURI(); - FormatDefault(player_domain, "played \"%s\"", uri.c_str()); - } + FormatDefault(player_domain, "played \"%s\"", song->GetURI()); ReplacePipe(dc.pipe); - audio_output_all_song_border(); + pc.outputs.SongBorder(); if (!WaitForDecoder()) return false; @@ -940,7 +933,7 @@ Player::Run() pc.command == PlayerCommand::EXIT || pc.command == PlayerCommand::CLOSE_AUDIO) { pc.Unlock(); - audio_output_all_cancel(); + pc.outputs.Cancel(); break; } @@ -956,7 +949,7 @@ Player::Run() /* not enough decoded buffer space yet */ if (!paused && output_open && - audio_output_all_check() < 4 && + pc.outputs.Check() < 4 && !SendSilence()) break; @@ -1036,7 +1029,7 @@ Player::Run() to the audio output */ PlayNextChunk(); - } else if (audio_output_all_check() > 0) { + } else if (pc.outputs.Check() > 0) { /* not enough data from decoder, but the output thread is still busy, so it's okay */ @@ -1061,7 +1054,7 @@ Player::Run() if (pipe->IsEmpty()) { /* wait for the hardware to finish playback */ - audio_output_all_drain(); + pc.outputs.Drain(); break; } } else if (output_open) { @@ -1082,9 +1075,8 @@ Player::Run() delete cross_fade_tag; if (song != nullptr) { - const auto uri = song->GetURI(); - FormatDefault(player_domain, "played \"%s\"", uri.c_str()); - song->Free(); + FormatDefault(player_domain, "played \"%s\"", song->GetURI()); + delete song; } pc.Lock(); @@ -1093,7 +1085,7 @@ Player::Run() if (queued) { assert(pc.next_song != nullptr); - pc.next_song->Free(); + delete pc.next_song; pc.next_song = nullptr; } @@ -1115,6 +1107,8 @@ player_task(void *arg) { PlayerControl &pc = *(PlayerControl *)arg; + SetThreadName("player"); + DecoderControl dc(pc.mutex, pc.cond); decoder_thread_start(dc); @@ -1130,22 +1124,20 @@ player_task(void *arg) pc.Unlock(); do_play(pc, dc, buffer); - GlobalEvents::Emit(GlobalEvents::PLAYLIST); + pc.listener.OnPlayerSync(); pc.Lock(); break; case PlayerCommand::STOP: pc.Unlock(); - audio_output_all_cancel(); + pc.outputs.Cancel(); pc.Lock(); /* fall through */ case PlayerCommand::PAUSE: - if (pc.next_song != nullptr) { - pc.next_song->Free(); - pc.next_song = nullptr; - } + delete pc.next_song; + pc.next_song = nullptr; pc.CommandFinished(); break; @@ -1153,7 +1145,7 @@ player_task(void *arg) case PlayerCommand::CLOSE_AUDIO: pc.Unlock(); - audio_output_all_release(); + pc.outputs.Release(); pc.Lock(); pc.CommandFinished(); @@ -1164,7 +1156,7 @@ player_task(void *arg) case PlayerCommand::UPDATE_AUDIO: pc.Unlock(); - audio_output_all_enable_disable(); + pc.outputs.EnableDisable(); pc.Lock(); pc.CommandFinished(); break; @@ -1174,16 +1166,14 @@ player_task(void *arg) dc.Quit(); - audio_output_all_close(); + pc.outputs.Close(); player_command_finished(pc); return; case PlayerCommand::CANCEL: - if (pc.next_song != nullptr) { - pc.next_song->Free(); - pc.next_song = nullptr; - } + delete pc.next_song; + pc.next_song = nullptr; pc.CommandFinished(); break; |