diff --git a/src/core/audio/Player.cpp b/src/core/audio/Player.cpp index ec13920d4..370838c14 100644 --- a/src/core/audio/Player.cpp +++ b/src/core/audio/Player.cpp @@ -41,23 +41,22 @@ using namespace musik::core::audio; static std::string TAG = "Player"; -PlayerPtr Player::Create(std::string &url, OutputPtr *output) { - return PlayerPtr(new Player(url,output)); +PlayerPtr Player::Create(std::string &url, OutputPtr output) { + return PlayerPtr(new Player(url, output)); } -Player::Player(std::string &url, OutputPtr *output) +Player::Player(std::string &url, OutputPtr output) : volume(1.0) , state(Player::Precache) , url(url) , prebufferSizeBytes(0) , maxPrebufferSizeBytes(2000000) , currentPosition(0) -, setPosition(-1) -{ +, setPosition(-1) { musik::debug::info(TAG, "new instance created"); - if (*output) { - this->output = *output; + if (output) { + this->output = output; } else { /* if no output is specified, find all output plugins, and select the first one. */ diff --git a/src/core/audio/Player.h b/src/core/audio/Player.h index 22d4fd04d..69df266f3 100644 --- a/src/core/audio/Player.h +++ b/src/core/audio/Player.h @@ -46,18 +46,17 @@ namespace musik { namespace core { namespace audio { - class Player; - class Transport; + class Player; typedef std::shared_ptr PlayerPtr; class Player : public IBufferProvider { public: typedef std::shared_ptr OutputPtr; - static PlayerPtr Create(std::string &url,OutputPtr *output = NULL); + static PlayerPtr Create(std::string &url, OutputPtr output = OutputPtr()); private: - Player(std::string &url,OutputPtr *output); + Player(std::string &url, OutputPtr output); public: ~Player(); @@ -75,6 +74,8 @@ namespace musik { namespace core { namespace audio { double Volume(); void SetVolume(double volume); + std::string GetUrl() const { return this->url; } + bool Exited(); public: @@ -83,19 +84,13 @@ namespace musik { namespace core { namespace audio { PlayerEvent PlaybackAlmostEnded; PlayerEvent PlaybackEnded; PlayerEvent PlaybackError; - - OutputPtr output; - + private: void ThreadLoop(); bool PreBuffer(); int State(); void ReleaseAllBuffers(); - protected: - friend class Transport; - std::string url; - private: typedef boost::scoped_ptr ThreadPtr; typedef std::list BufferList; @@ -107,10 +102,13 @@ namespace musik { namespace core { namespace audio { Quit = 2 } States; + OutputPtr output; StreamPtr stream; ThreadPtr thread; BufferList lockedBuffers; + std::string url; + BufferList prebufferQueue; long prebufferSizeBytes; long maxPrebufferSizeBytes; diff --git a/src/core/debug.cpp b/src/core/debug.cpp index 0b90c92ad..bc8fad877 100755 --- a/src/core/debug.cpp +++ b/src/core/debug.cpp @@ -51,7 +51,7 @@ namespace musik { } if (!active_) { - throw stopped_exception(); + return NULL; } log_entry* top = queue_.front(); @@ -101,8 +101,10 @@ static void thread_proc() { try { while (!cancel_) { log_queue::log_entry* entry = queue_->pop_top(); - debug::string_logged(entry->level_, entry->tag_, entry->message_); - delete entry; + if (entry) { + debug::string_logged(entry->level_, entry->tag_, entry->message_); + delete entry; + } } } catch (log_queue::stopped_exception&) { diff --git a/src/core/library/IIndexer.h b/src/core/library/IIndexer.h index 2657d6d7e..fe35f1cc7 100755 --- a/src/core/library/IIndexer.h +++ b/src/core/library/IIndexer.h @@ -12,6 +12,8 @@ namespace musik { namespace core { sigslot::signal0<> PathsUpdated; sigslot::signal0<> TrackRefreshed; + virtual ~IIndexer() = 0 { } + virtual void AddPath(const std::string& path) = 0; virtual void RemovePath(const std::string& path) = 0; virtual void GetPaths(std::vector& paths) = 0; diff --git a/src/core/library/ILibrary.h b/src/core/library/ILibrary.h index 07ff6b3db..c91a7c964 100755 --- a/src/core/library/ILibrary.h +++ b/src/core/library/ILibrary.h @@ -16,6 +16,8 @@ namespace musik { namespace core { public: sigslot::signal1 QueryCompleted; + virtual ~ILibrary() = 0 { } + virtual int Enqueue(QueryPtr query, unsigned int options = 0) = 0; virtual IIndexer *Indexer() = 0; virtual int Id() = 0; diff --git a/src/core/library/IQuery.h b/src/core/library/IQuery.h index 68de1ef52..9577906bc 100755 --- a/src/core/library/IQuery.h +++ b/src/core/library/IQuery.h @@ -24,6 +24,8 @@ namespace musik { namespace core { Finished = 4, } Status; + virtual ~IQuery() = 0 { } + virtual bool Run(db::Connection &db) = 0; virtual int GetStatus() = 0; virtual int GetId() = 0; diff --git a/src/core/library/Indexer.h b/src/core/library/Indexer.h index 799a940b8..71115a19b 100644 --- a/src/core/library/Indexer.h +++ b/src/core/library/Indexer.h @@ -64,7 +64,7 @@ namespace musik { namespace core { const std::string& libraryPath, const std::string& dbFilename); - ~Indexer(); + virtual ~Indexer(); virtual void AddPath(const std::string& paths); virtual void RemovePath(const std::string& paths); diff --git a/src/core/playback/Transport.cpp b/src/core/playback/Transport.cpp index b5b237b1a..0889ef7d7 100644 --- a/src/core/playback/Transport.cpp +++ b/src/core/playback/Transport.cpp @@ -41,115 +41,143 @@ using namespace musik::core::audio; static std::string TAG = "Transport"; Transport::Transport() - :volume(1.0) - ,gapless(true) -{ +: volume(1.0) { } -Transport::~Transport(){ +Transport::~Transport() { this->nextPlayer.reset(); this->currentPlayer.reset(); - this->players.clear(); } -void Transport::PrepareNextTrack(std::string trackUrl){ +void Transport::PrepareNextTrack(std::string trackUrl) { + PlayerPtr player = Player::Create(trackUrl); - if(this->gapless && this->currentPlayer){ - this->nextPlayer = Player::Create(trackUrl,&this->currentPlayer->output); - this->nextPlayer->Play(); - }else{ - this->nextPlayer = Player::Create(trackUrl); + { + boost::mutex::scoped_lock lock(this->stateMutex); + this->currentPlayer = player; } - } -void Transport::Start(std::string url){ +void Transport::Start(std::string url) { musik::debug::info(TAG, "we were asked to start the track at " + url); - // Check if this is already Prepared - PlayerPtr player = this->nextPlayer; - this->nextPlayer.reset(); + PlayerPtr player; - musik::debug::info(TAG, "creating a Player..."); + { + boost::mutex::scoped_lock lock(this->stateMutex); - // If the nextPlayer wasn't the same as the one started, lets create a new one - if(!player || player->url != url){ - Player::OutputPtr output; + PlayerPtr newPlayer = this->nextPlayer; + this->nextPlayer.reset(); - player = Player::Create(url, &output); - player->SetVolume(this->volume); + musik::debug::info(TAG, "creating a Player..."); - musik::debug::info(TAG, "Player created successfully"); + if (!newPlayer || newPlayer->GetUrl() != url) { + newPlayer = Player::Create(url); /* non-blocking */ + newPlayer->SetVolume(this->volume); + musik::debug::info(TAG, "Player created successfully"); + } + + this->currentPlayer = newPlayer; + + this->currentPlayer->PlaybackStarted.connect(this, &Transport::OnPlaybackStarted); + this->currentPlayer->PlaybackAlmostEnded.connect(this, &Transport::OnPlaybackAlmostEnded); + this->currentPlayer->PlaybackEnded.connect(this, &Transport::OnPlaybackEnded); + this->currentPlayer->PlaybackError.connect(this, &Transport::OnPlaybackError); + + musik::debug::info(TAG, "play()"); + this->currentPlayer->Play(); + + player = this->currentPlayer; } - // Add to the players - this->players.push_front(player); - this->currentPlayer = player; - - musik::debug::info(TAG, "player added to player list"); - - // Lets connect to the signals of the currentPlayer /* FIXME event binding is reversed here */ - this->currentPlayer->PlaybackStarted.connect(this,&Transport::OnPlaybackStarted); - this->currentPlayer->PlaybackAlmostEnded.connect(this,&Transport::OnPlaybackAlmostEnded); - this->currentPlayer->PlaybackEnded.connect(this,&Transport::OnPlaybackEnded); - this->currentPlayer->PlaybackError.connect(this, &Transport::OnPlaybackError); - - musik::debug::info(TAG, "play()"); - - // Start playing - player->Play(); - this->TrackStarted(url); + this->RaisePlaybackEvent(Transport::EventScheduled, player); } -void Transport::Stop(){ +void Transport::Stop() { musik::debug::info(TAG, "stop"); - this->players.clear(); - this->currentPlayer.reset(); - this->nextPlayer.reset(); - this->PlaybackEnded(); + + PlayerPtr player = NULL; + + { + boost::mutex::scoped_lock lock(this->stateMutex); + + player = this->currentPlayer; + this->currentPlayer.reset(); + this->nextPlayer.reset(); + } + + if (player) { + this->RaisePlaybackEvent(Transport::EventFinished, player); + } } -bool Transport::Pause(){ +bool Transport::Pause() { musik::debug::info(TAG, "pause"); - // pause all players - for(PlayerList::iterator player=this->players.begin();player!=this->players.end();++player){ - (*player)->Pause(); + PlayerPtr player; + + { + boost::mutex::scoped_lock lock(this->stateMutex); + + if (this->currentPlayer) { + this->currentPlayer->Pause(); + player = this->currentPlayer; + } } - this->PlaybackPause(); - return true; + + if (player) { + this->RaisePlaybackEvent(Transport::EventPaused, player); + return true; + } + + return false; } -bool Transport::Resume(){ + +bool Transport::Resume() { musik::debug::info(TAG, "resume"); - // Resume all players - for(PlayerList::iterator player=this->players.begin();player!=this->players.end();++player){ - (*player)->Resume(); + PlayerPtr player; + + { + boost::mutex::scoped_lock lock(this->stateMutex); + + if (this->currentPlayer) { + this->currentPlayer->Resume(); + player = this->currentPlayer; + } } - this->PlaybackResume(); - return true; + + if (player) { + this->RaisePlaybackEvent(Transport::EventResumed, player); + return true; + } + + return false; } +double Transport::Position() { + boost::mutex::scoped_lock lock(this->stateMutex); -double Transport::Position(){ - if(this->currentPlayer){ + if (this->currentPlayer) { return this->currentPlayer->Position(); } + return 0; } -void Transport::SetPosition(double seconds){ - if(this->currentPlayer){ +void Transport::SetPosition(double seconds) { + boost::mutex::scoped_lock lock(this->stateMutex); + + if (this->currentPlayer) { return this->currentPlayer->SetPosition(seconds); } } - -double Transport::Volume(){ +double Transport::Volume() { return this->volume; } -void Transport::SetVolume(double volume){ +void Transport::SetVolume(double volume) { double oldVolume = this->volume; volume = max(0, min(1.0, volume)); @@ -160,48 +188,90 @@ void Transport::SetVolume(double volume){ this->VolumeChanged(); } - musik::debug::info(TAG, boost::str(boost::format("set volume %d%%") % round(volume * 100))); + musik::debug::info(TAG, boost::str( + boost::format("set volume %d%%") % round(volume * 100))); - if(this->currentPlayer){ - for(PlayerList::iterator player=this->players.begin();player!=this->players.end();++player){ - (*player)->SetVolume(volume); + { + boost::mutex::scoped_lock lock(this->stateMutex); + + if (this->currentPlayer) { + this->currentPlayer->SetVolume(volume); } } } -void Transport::OnPlaybackStarted(Player *player){ - if(this->currentPlayer.get()==player){ - this->PlaybackStarted(); +void Transport::OnPlaybackStarted(Player *player) { + PlayerPtr playerForEvent; + + { + boost::mutex::scoped_lock lock(this->stateMutex); + + if (this->currentPlayer.get() == player) { + playerForEvent = this->currentPlayer; + } + } + + if (playerForEvent) { + this->RaisePlaybackEvent(Transport::EventStarted, playerForEvent); } } -void Transport::OnPlaybackAlmostEnded(Player *player){ - if(this->currentPlayer.get()==player){ - this->PlaybackAlmostDone(); +void Transport::OnPlaybackAlmostEnded(Player *player) { + PlayerPtr playerForEvent; - // Reuse the output - if(this->nextPlayer && this->gapless){ - // TODO -// this->nex + { + boost::mutex::scoped_lock lock(this->stateMutex); + + if (this->currentPlayer.get() == player) { + playerForEvent = this->currentPlayer; } } + + this->RaisePlaybackEvent(Transport::EventAlmostDone, playerForEvent); } -void Transport::OnPlaybackEnded(Player *player){ - if(this->currentPlayer.get()==player){ - this->PlaybackEnded(); +void Transport::OnPlaybackEnded(Player *player) { + PlayerPtr playerForEvent; + PlayerPtr nextPlayer; - // If the is a nextPlayer, then we should start playing right away - if(this->nextPlayer){ - this->Start(this->nextPlayer->url.c_str()); + { + boost::mutex::scoped_lock lock(this->stateMutex); + + if (this->currentPlayer.get() == player) { + playerForEvent = this->currentPlayer; } + + if (this->nextPlayer) { + nextPlayer = this->nextPlayer; + } + } + + if (playerForEvent) { + this->RaisePlaybackEvent(Transport::EventFinished, playerForEvent); + } + + if (nextPlayer) { + this->Start(nextPlayer->GetUrl().c_str()); } } void Transport::OnPlaybackError(Player *player) { - this->PlaybackError(); -} + PlayerPtr playerForEvent; + { + boost::mutex::scoped_lock lock(this->stateMutex); + if (this->currentPlayer.get() == player) { + playerForEvent = this->currentPlayer; + } + } + if (playerForEvent) { + this->RaisePlaybackEvent(Transport::EventError, playerForEvent); + } +} +void Transport::RaisePlaybackEvent(int type, PlayerPtr player) { + std::string uri = player ? player->GetUrl() : ""; + this->PlaybackEvent(type, uri); +} \ No newline at end of file diff --git a/src/core/playback/Transport.h b/src/core/playback/Transport.h index 36c24a3eb..2308637e6 100644 --- a/src/core/playback/Transport.h +++ b/src/core/playback/Transport.h @@ -37,6 +37,7 @@ #include #include #include +#include namespace musik { namespace core { namespace audio { @@ -59,26 +60,21 @@ namespace musik { namespace core { namespace audio { public: typedef enum { - Started = 1, - Ended = 2, - Error = 3 - } PlaybackStatus; + EventScheduled = 0, + EventStarted = 1, + EventPaused = 2, + EventResumed = 3, + EventAlmostDone = 4, + EventFinished = 5, + EventError = -1 + } PlaybackEventType; - sigslot::signal1 TrackStarted; + sigslot::signal2 PlaybackEvent; sigslot::signal0<> VolumeChanged; - - typedef sigslot::signal1 PlaybackStatusEvent; - PlaybackStatusEvent PlaybackStatusChange; - - typedef sigslot::signal0<> PlaybackEvent; - PlaybackEvent PlaybackAlmostDone; - PlaybackEvent PlaybackStarted; - PlaybackEvent PlaybackEnded; - PlaybackEvent PlaybackPause; - PlaybackEvent PlaybackResume; - PlaybackEvent PlaybackError; private: + void RaisePlaybackEvent(int type, PlayerPtr player); + void OnPlaybackStarted(Player *player); void OnPlaybackAlmostEnded(Player *player); void OnPlaybackEnded(Player *player); @@ -86,10 +82,8 @@ namespace musik { namespace core { namespace audio { private: double volume; - bool gapless; - typedef std::list PlayerList; - PlayerList players; + boost::mutex stateMutex; PlayerPtr currentPlayer; PlayerPtr nextPlayer; }; diff --git a/src/musikbox/Main.cpp b/src/musikbox/Main.cpp index 589021919..9fc94dc33 100644 --- a/src/musikbox/Main.cpp +++ b/src/musikbox/Main.cpp @@ -191,6 +191,9 @@ int main(int argc, char* argv[]) if (ch == '\t') { /* tab */ focusNextInLayout(state); } + else if (kn == "^D") { + quit = true; + } else if (kn == "ALT_K") { tp.SetVolume(tp.Volume() + 0.05); /* 5% */ } diff --git a/src/musikbox/app/window/TransportWindow.cpp b/src/musikbox/app/window/TransportWindow.cpp index 8cb75f8a2..e08fa696e 100755 --- a/src/musikbox/app/window/TransportWindow.cpp +++ b/src/musikbox/app/window/TransportWindow.cpp @@ -29,7 +29,7 @@ TransportWindow::TransportWindow(LibraryPtr library, Transport& transport) this->library = library; this->library->QueryCompleted.connect(this, &TransportWindow::OnQueryCompleted); this->transport = &transport; - this->transport->TrackStarted.connect(this, &TransportWindow::OnTransportStarted); + this->transport->PlaybackEvent.connect(this, &TransportWindow::OnTransportPlaybackEvent); this->transport->VolumeChanged.connect(this, &TransportWindow::OnTransportVolumeChanged); this->paused = false; } @@ -48,9 +48,11 @@ void TransportWindow::ProcessMessage(IWindowMessage &message) { } } -void TransportWindow::OnTransportStarted(std::string url) { - this->trackQuery.reset(new SingleTrackQuery(url)); - this->library->Enqueue(this->trackQuery); +void TransportWindow::OnTransportPlaybackEvent(int eventType, std::string url) { + if (eventType == Transport::EventStarted) { + this->trackQuery.reset(new SingleTrackQuery(url)); + this->library->Enqueue(this->trackQuery); + } } void TransportWindow::OnTransportVolumeChanged() { diff --git a/src/musikbox/app/window/TransportWindow.h b/src/musikbox/app/window/TransportWindow.h index 27647533f..c4dd3e5c4 100755 --- a/src/musikbox/app/window/TransportWindow.h +++ b/src/musikbox/app/window/TransportWindow.h @@ -23,7 +23,7 @@ class TransportWindow : public Window, public sigslot::has_slots<> { void Update(); private: - void OnTransportStarted(std::string url); + void OnTransportPlaybackEvent(int eventType, std::string url); void OnTransportVolumeChanged(); void OnQueryCompleted(QueryPtr query); diff --git a/src/musikbox/cursespp/IDisplayable.h b/src/musikbox/cursespp/IDisplayable.h index 687d12597..58fb4237d 100755 --- a/src/musikbox/cursespp/IDisplayable.h +++ b/src/musikbox/cursespp/IDisplayable.h @@ -2,6 +2,8 @@ class IDisplayable { public: + virtual ~IDisplayable() = 0 { } + virtual void Show() = 0; virtual void Hide() = 0; }; \ No newline at end of file diff --git a/src/musikbox/cursespp/IInput.h b/src/musikbox/cursespp/IInput.h index 68cea1070..c61330bd4 100755 --- a/src/musikbox/cursespp/IInput.h +++ b/src/musikbox/cursespp/IInput.h @@ -4,5 +4,7 @@ class IInput { public: + virtual ~IInput() = 0 { } + virtual void WriteChar(int64 ch) = 0; }; \ No newline at end of file diff --git a/src/musikbox/cursespp/IKeyHandler.h b/src/musikbox/cursespp/IKeyHandler.h index 35627c8df..1d33bac5a 100755 --- a/src/musikbox/cursespp/IKeyHandler.h +++ b/src/musikbox/cursespp/IKeyHandler.h @@ -4,5 +4,6 @@ class IKeyHandler { public: + virtual ~IKeyHandler() = 0 { } virtual void KeyPress(int64 ch) = 0; }; \ No newline at end of file diff --git a/src/musikbox/cursespp/ILayout.h b/src/musikbox/cursespp/ILayout.h index 1705b593f..3b3653d26 100755 --- a/src/musikbox/cursespp/ILayout.h +++ b/src/musikbox/cursespp/ILayout.h @@ -5,6 +5,7 @@ class ILayout : public IWindowGroup, public IDisplayable { public: + virtual ~ILayout() = 0 { } virtual IWindow* FocusNext() = 0; virtual IWindow* FocusPrev() = 0; virtual IWindow* GetFocus() = 0; diff --git a/src/musikbox/cursespp/IScrollAdapter.h b/src/musikbox/cursespp/IScrollAdapter.h index 9ec895cb6..d43ea1108 100755 --- a/src/musikbox/cursespp/IScrollAdapter.h +++ b/src/musikbox/cursespp/IScrollAdapter.h @@ -4,6 +4,8 @@ class IScrollAdapter { public: + virtual ~IScrollAdapter() = 0 { } + struct ScrollPosition { ScrollPosition() { firstVisibleEntryIndex = 0; @@ -22,6 +24,7 @@ class IScrollAdapter { class IEntry { public: + virtual ~IEntry() = 0 { } virtual size_t GetLineCount() = 0; virtual std::string GetLine(size_t line) = 0; virtual std::string GetValue() = 0; diff --git a/src/musikbox/cursespp/IScrollable.h b/src/musikbox/cursespp/IScrollable.h index 6b31e2c32..043961fcb 100755 --- a/src/musikbox/cursespp/IScrollable.h +++ b/src/musikbox/cursespp/IScrollable.h @@ -2,6 +2,7 @@ class IScrollable { public: + virtual ~IScrollable() = 0 { } virtual void ScrollToTop() = 0; virtual void ScrollToBottom() = 0; virtual void ScrollUp(int delta = 1) = 0; diff --git a/src/musikbox/cursespp/IWindow.h b/src/musikbox/cursespp/IWindow.h index 22219a099..2a3991022 100755 --- a/src/musikbox/cursespp/IWindow.h +++ b/src/musikbox/cursespp/IWindow.h @@ -7,6 +7,7 @@ class IWindowMessage; class IWindow : public IDisplayable { public: + virtual ~IWindow() = 0 { } virtual void Repaint() = 0; virtual void SetParent(IWindow* parent) = 0; virtual void Show() = 0; diff --git a/src/musikbox/cursespp/IWindowGroup.h b/src/musikbox/cursespp/IWindowGroup.h index 64540ac0d..553ee4e2a 100755 --- a/src/musikbox/cursespp/IWindowGroup.h +++ b/src/musikbox/cursespp/IWindowGroup.h @@ -4,6 +4,7 @@ class IWindowGroup { public: + virtual ~IWindowGroup() = 0 { } virtual bool AddWindow(IWindowPtr window) = 0; virtual bool RemoveWindow(IWindowPtr window) = 0; virtual size_t GetWindowCount() = 0; diff --git a/src/musikbox/cursespp/IWindowMessage.h b/src/musikbox/cursespp/IWindowMessage.h index d47a9d94b..d9620ee6d 100755 --- a/src/musikbox/cursespp/IWindowMessage.h +++ b/src/musikbox/cursespp/IWindowMessage.h @@ -6,6 +6,7 @@ class IWindowMessage { public: + virtual ~IWindowMessage() = 0 { } virtual IWindow* Target() = 0; virtual int MessageType() = 0; virtual int64 UserData1() = 0; diff --git a/src/musikbox/cursespp/Window.cpp b/src/musikbox/cursespp/Window.cpp index 83a857ab9..230c9d354 100755 --- a/src/musikbox/cursespp/Window.cpp +++ b/src/musikbox/cursespp/Window.cpp @@ -45,7 +45,7 @@ void Window::ProcessMessage(IWindowMessage &message) { } bool Window::IsAcceptingMessages() { - return this->IsVisible(); + return true; //this->IsVisible(); } bool Window::IsVisible() { @@ -260,14 +260,16 @@ void Window::Clear() { } void Window::Repaint() { - if (this->frame && this->content) { - wnoutrefresh(this->frame); + if (this->isVisible) { + if (this->frame && this->content) { + wnoutrefresh(this->frame); - if (this->frame != this->content) { - wnoutrefresh(this->content); + if (this->frame != this->content) { + wnoutrefresh(this->content); + } + + drawPending = true; } - - drawPending = true; } }