Important work towards eventual support of gapless playback:

- Transport: cleaned up memory management model -- shared_ptr<Player>
  was causing lots of unnecessary complication. The players are
  encapsulated, so switched to just Player*

- Player's destructor wasn't virtual! Caused some strange problems.

- Integrated next track loading in PlayerService!
This commit is contained in:
casey 2016-05-23 22:33:40 -07:00
parent 65a4d33823
commit b544ea6f1f
22 changed files with 239 additions and 311 deletions

View File

@ -41,16 +41,16 @@ using namespace musik::core::audio;
static std::string TAG = "Player";
PlayerPtr Player::Create(std::string &url, OutputPtr output) {
PlayerPtr Player::Create(const std::string &url, OutputPtr output) {
return PlayerPtr(new Player(url, output));
}
Player::Player(std::string &url, OutputPtr output)
Player::Player(const std::string &url, OutputPtr output)
: volume(1.0)
, state(Player::Precache)
, url(url)
, prebufferSizeBytes(0)
, maxPrebufferSizeBytes(2000000)
, maxPrebufferSizeBytes(100000)
, currentPosition(0)
, setPosition(-1) {
musik::debug::info(TAG, "new instance created");

View File

@ -53,12 +53,9 @@ namespace musik { namespace core { namespace audio {
public:
typedef std::shared_ptr<IOutput> OutputPtr;
static PlayerPtr Create(std::string &url, OutputPtr output = OutputPtr());
private:
Player(std::string &url, OutputPtr output);
static PlayerPtr Create(const std::string &url, OutputPtr output = OutputPtr());
public:
Player(const std::string &url, OutputPtr output = OutputPtr());
~Player();
virtual void OnBufferProcessed(IBuffer *buffer);

View File

@ -75,7 +75,7 @@ namespace musik { namespace core { namespace audio {
BufferPtr GetEmptyBuffer();
void LoadDecoderPlugins();
private:
private:
typedef std::list<BufferPtr> BufferList;
typedef std::shared_ptr<IDecoderFactory> DecoderFactoryPtr;
typedef std::vector<DecoderFactoryPtr> DecoderFactoryList;

View File

@ -64,7 +64,7 @@ inline std::string u16to8(const std::wstring& u16) {
return result;
}
inline static int u8len(const std::string& str) {
inline static size_t u8len(const std::string& str) {
try {
return utf8::distance(str.begin(), str.end());
}

View File

@ -95,7 +95,7 @@ void LibraryTrack::SetThumbnail(const char *data, long size) {
}
std::string LibraryTrack::URI() {
return this->GetValue("path");
return this->GetValue("filename");
}
Track::MetadataIteratorRange LibraryTrack::GetValues(const char* metakey) {

View File

@ -35,111 +35,124 @@
#include <core/debug.h>
#include <core/playback/Transport.h>
#include <core/plugin/PluginFactory.h>
#include <boost/thread/future.hpp>
using namespace musik::core::audio;
static std::string TAG = "Transport";
#define RESET_NEXT_PLAYER() \
delete this->nextPlayer; \
this->nextPlayer = NULL;
static void pausePlayer(Player* p) {
p->Pause();
}
static void resumePlayer(Player* p) {
p->Resume();
}
static void deletePlayer(Player* p) {
delete p;
}
Transport::Transport()
: volume(1.0)
, state(StateStopped) {
, state(PlaybackStopped)
, nextPlayer(NULL) {
}
Transport::~Transport() {
this->nextPlayer.reset();
this->currentPlayer.reset();
}
Transport::PlaybackState Transport::GetPlaybackState() {
boost::mutex::scoped_lock lock(this->stateMutex);
boost::recursive_mutex::scoped_lock lock(this->stateMutex);
return this->state;
}
void Transport::PrepareNextTrack(std::string trackUrl) {
PlayerPtr player = Player::Create(trackUrl);
{
boost::mutex::scoped_lock lock(this->stateMutex);
this->currentPlayer = player;
}
void Transport::PrepareNextTrack(const std::string& trackUrl) {
boost::recursive_mutex::scoped_lock lock(this->stateMutex);
this->nextPlayer = new Player(trackUrl);
}
void Transport::Start(std::string url) {
void Transport::Start(const std::string& url) {
musik::debug::info(TAG, "we were asked to start the track at " + url);
/* TODO FIXME: hack; the player is reference counted, we don't want the count
to reach zero within the critical section, because its background thread may
raise an event and cause a deadlock. do we really need shared_ptrs for these
Player instances? */
PlayerPtr current;
Player* newPlayer = new Player(url);
newPlayer->SetVolume(this->volume);
musik::debug::info(TAG, "Player created successfully");
PlayerPtr player;
this->StartWithPlayer(newPlayer);
}
{
boost::mutex::scoped_lock lock(this->stateMutex);
void Transport::StartWithPlayer(Player* newPlayer) {
if (newPlayer) {
{
boost::recursive_mutex::scoped_lock lock(this->stateMutex);
PlayerPtr newPlayer = this->nextPlayer;
this->nextPlayer.reset();
if (newPlayer != nextPlayer) {
delete nextPlayer;
}
musik::debug::info(TAG, "creating a Player...");
this->nextPlayer = NULL;
if (!newPlayer || newPlayer->GetUrl() != url) {
newPlayer = Player::Create(url); /* non-blocking */
newPlayer->SetVolume(this->volume);
musik::debug::info(TAG, "Player created successfully");
newPlayer->PlaybackStarted.connect(this, &Transport::OnPlaybackStarted);
newPlayer->PlaybackAlmostEnded.connect(this, &Transport::OnPlaybackAlmostEnded);
newPlayer->PlaybackEnded.connect(this, &Transport::OnPlaybackEnded);
newPlayer->PlaybackError.connect(this, &Transport::OnPlaybackError);
musik::debug::info(TAG, "play()");
this->active.push_front(newPlayer);
newPlayer->Play();
}
current = this->currentPlayer; /* see hack note above. */
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(); /* non-blocking */
player = this->currentPlayer;
this->RaiseStreamEvent(Transport::StreamScheduled, newPlayer);
}
this->RaisePlaybackEvent(Transport::EventScheduled, player);
}
void Transport::Stop() {
musik::debug::info(TAG, "stop");
PlayerPtr player = NULL;
{
boost::mutex::scoped_lock lock(this->stateMutex);
std::list<Player*> toDelete;
player = this->currentPlayer;
this->currentPlayer.reset();
this->nextPlayer.reset();
{
boost::recursive_mutex::scoped_lock lock(this->stateMutex);
RESET_NEXT_PLAYER();
std::swap(toDelete, this->active);
}
/* do the actual delete outside of the critical section! the players run
in a background thread that will emit a signal on completion, but the
destructor joins(). */
std::for_each(toDelete.begin(), toDelete.end(), deletePlayer);
this->active.clear();
if (player) {
this->RaisePlaybackEvent(Transport::EventStopped, player);
this->SetPlaybackState(PlaybackStopped);
}
}
bool Transport::Pause() {
musik::debug::info(TAG, "pause");
PlayerPtr player;
size_t count = 0;
{
boost::mutex::scoped_lock lock(this->stateMutex);
if (this->currentPlayer) {
this->currentPlayer->Pause();
player = this->currentPlayer;
}
boost::recursive_mutex::scoped_lock lock(this->stateMutex);
std::for_each(this->active.begin(), this->active.end(), pausePlayer);
count = this->active.size();
}
if (player) {
this->RaisePlaybackEvent(Transport::EventPaused, player);
if (count) {
this->SetPlaybackState(PlaybackPaused);
return true;
}
@ -149,19 +162,16 @@ bool Transport::Pause() {
bool Transport::Resume() {
musik::debug::info(TAG, "resume");
PlayerPtr player;
size_t count = 0;
{
boost::mutex::scoped_lock lock(this->stateMutex);
if (this->currentPlayer) {
this->currentPlayer->Resume();
player = this->currentPlayer;
}
boost::recursive_mutex::scoped_lock lock(this->stateMutex);
std::for_each(this->active.begin(), this->active.end(), resumePlayer);
count = this->active.size();
}
if (player) {
this->RaisePlaybackEvent(Transport::EventResumed, player);
if (count) {
this->SetPlaybackState(Transport::PlaybackPlaying);
return true;
}
@ -169,29 +179,30 @@ bool Transport::Resume() {
}
double Transport::Duration() {
boost::mutex::scoped_lock lock(this->stateMutex);
boost::recursive_mutex::scoped_lock lock(this->stateMutex);
if (this->currentPlayer) {
return this->currentPlayer->Position();
if (!this->active.empty()) {
return this->active.front()->Position();
}
return 0;
}
double Transport::Position() {
boost::mutex::scoped_lock lock(this->stateMutex);
boost::recursive_mutex::scoped_lock lock(this->stateMutex);
if (this->currentPlayer) {
return this->currentPlayer->Position();
if (!this->active.empty()) {
return this->active.front()->Position();
}
return 0;
}
void Transport::SetPosition(double seconds) {
boost::mutex::scoped_lock lock(this->stateMutex);
boost::recursive_mutex::scoped_lock lock(this->stateMutex);
if (this->currentPlayer) {
return this->currentPlayer->SetPosition(seconds);
if (!this->active.empty()) {
return this->active.front()->SetPosition(seconds);
}
}
@ -214,104 +225,67 @@ void Transport::SetVolume(double volume) {
boost::format("set volume %d%%") % round(volume * 100)));
{
boost::mutex::scoped_lock lock(this->stateMutex);
boost::recursive_mutex::scoped_lock lock(this->stateMutex);
if (this->currentPlayer) {
this->currentPlayer->SetVolume(volume);
if (!this->active.empty()) {
this->active.front()->SetVolume(volume);
}
}
}
void Transport::OnPlaybackStarted(Player *player) {
PlayerPtr playerForEvent;
void Transport::OnPlaybackStarted(Player* player) {
this->RaiseStreamEvent(Transport::StreamPlaying, player);
this->SetPlaybackState(Transport::PlaybackPlaying);
}
void Transport::OnPlaybackAlmostEnded(Player* player) {
this->RaiseStreamEvent(Transport::StreamAlmostDone, player);
}
void Transport::RemoveActive(Player* player) {
boost::recursive_mutex::scoped_lock lock(this->stateMutex);
std::list<Player*>::iterator it =
std::find(this->active.begin(), this->active.end(), player);
if (it != this->active.end()) {
delete (*it);
this->active.erase(it);
}
}
void Transport::OnPlaybackEnded(Player* player) {
this->RaiseStreamEvent(Transport::StreamFinished, player);
if (this->nextPlayer) {
this->StartWithPlayer(this->nextPlayer);
}
else {
this->SetPlaybackState(Transport::PlaybackStopped);
}
boost::async(boost::bind(&Transport::RemoveActive, this, player));
}
void Transport::OnPlaybackError(Player* player) {
this->RaiseStreamEvent(Transport::StreamError, player);
this->SetPlaybackState(Transport::PlaybackStopped);
boost::async(boost::bind(&Transport::RemoveActive, this, player));
}
void Transport::SetPlaybackState(int state) {
bool changed = false;
{
boost::mutex::scoped_lock lock(this->stateMutex);
if (this->currentPlayer.get() == player) {
playerForEvent = this->currentPlayer;
}
boost::recursive_mutex::scoped_lock lock(this->stateMutex);
this->state = (PlaybackState) state;
}
if (playerForEvent) {
this->RaisePlaybackEvent(Transport::EventPlaying, playerForEvent);
if (changed) {
this->PlaybackEvent(state);
}
}
void Transport::OnPlaybackAlmostEnded(Player *player) {
PlayerPtr playerForEvent;
{
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) {
PlayerPtr playerForEvent;
PlayerPtr nextPlayer;
{
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::EventStopped, playerForEvent);
}
if (nextPlayer) {
this->Start(nextPlayer->GetUrl().c_str());
}
}
void Transport::OnPlaybackError(Player *player) {
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) {
/* TODO FIXME: should be either decoupled or merged with the playback
event enum. */
switch (type) {
case EventPlaying:
case EventResumed:
this->state = StatePlaying;
break;
case EventStopped:
case EventError:
this->state = StateStopped;
break;
case EventPaused:
this->state = StatePaused;
break;
}
std::string uri = player ? player->GetUrl() : "";
this->PlaybackEvent(type, uri);
void Transport::RaiseStreamEvent(int type, Player* player) {
this->StreamEvent(type, player->GetUrl());
}

View File

@ -34,6 +34,7 @@
#include <core/config.h>
#include <core/audio/Player.h>
#include <core/sdk/IOutput.h>
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>
#include <sigslot/sigslot.h>
@ -43,30 +44,29 @@ namespace musik { namespace core { namespace audio {
class Transport : public sigslot::has_slots<> {
public:
sigslot::signal2<int, std::string> PlaybackEvent;
sigslot::signal2<int, std::string> StreamEvent;
sigslot::signal1<int> PlaybackEvent;
sigslot::signal0<> VolumeChanged;
typedef enum {
StateStopped,
StatePaused,
StatePlaying
PlaybackStopped,
PlaybackPaused,
PlaybackPlaying
} PlaybackState;
typedef enum {
EventScheduled = 0,
EventPlaying = 1,
EventPaused = 2,
EventResumed = 3,
EventAlmostDone = 4,
EventStopped = 5,
EventError = -1
} PlaybackEventType;
StreamScheduled = 0,
StreamPlaying = 1,
StreamAlmostDone = 4,
StreamFinished = 5,
StreamError = -1
} StreamEventType;
Transport();
~Transport();
void PrepareNextTrack(std::string trackUrl);
void Start(std::string trackUrl);
void PrepareNextTrack(const std::string& trackUrl);
void Start(const std::string& trackUrl);
void Stop();
bool Pause();
bool Resume();
@ -81,20 +81,24 @@ namespace musik { namespace core { namespace audio {
PlaybackState GetPlaybackState();
private:
void RaisePlaybackEvent(int type, PlayerPtr player);
void StartWithPlayer(Player* player);
void RemoveActive(Player* player);
void OnPlaybackStarted(Player *player);
void OnPlaybackAlmostEnded(Player *player);
void OnPlaybackEnded(Player *player);
void OnPlaybackError(Player *player);
void RaiseStreamEvent(int type, Player* player);
void SetPlaybackState(int state);
void OnPlaybackStarted(Player* player);
void OnPlaybackAlmostEnded(Player* player);
void OnPlaybackEnded(Player* player);
void OnPlaybackError(Player* player);
private:
double volume;
PlaybackState state;
boost::mutex stateMutex;
PlayerPtr currentPlayer;
PlayerPtr nextPlayer;
boost::recursive_mutex stateMutex;
Player* nextPlayer;
std::list<Player*> active;
};

View File

@ -49,9 +49,9 @@
#include <dlfcn.h>
#endif
namespace musik{ namespace core{
namespace musik { namespace core {
class PluginFactory{
class PluginFactory {
public:
static PluginFactory& Instance() {

View File

@ -44,6 +44,8 @@ namespace musik { namespace core { namespace audio {
//////////////////////////////////////////
class IBufferProvider {
public:
virtual ~IBufferProvider() = 0 { }
//////////////////////////////////////////
///\brief
///Release used by the output to notify the player a buffer has finished

View File

@ -42,43 +42,11 @@ namespace musik { namespace core { namespace audio {
class IOutput {
public:
//////////////////////////////////////////
///\brief
///Destroy the object
///
///The Destroy method is used so that it's guaranteed that the object is
///destroyed inside the right DLL/exe
//////////////////////////////////////////
virtual void Destroy() = 0;
//////////////////////////////////////////
///\brief
///Pause the current output
//////////////////////////////////////////
virtual void Pause() = 0;
//////////////////////////////////////////
///\brief
///resume a paused output
//////////////////////////////////////////
virtual void Resume() = 0;
//////////////////////////////////////////
///\brief
///Set the volume on this output
//////////////////////////////////////////
virtual void SetVolume(double volume) = 0;
//////////////////////////////////////////
///\brief
///Clear internal buffers. Used when setting new position in a stream
//////////////////////////////////////////
virtual void Stop() = 0;
//////////////////////////////////////////
///\brief
///Play this buffer
//////////////////////////////////////////
virtual bool Play(IBuffer *buffer, IBufferProvider *provider) = 0;
};

View File

@ -39,29 +39,12 @@
#include <core/config.h>
#include <utf8/utf8.h>
//////////////////////////////////////////
///\brief
///Get the directory where plugin-dlls are located.
///
///\returns
///String with the directory
///
///\see
///<GetApplicationDirectory>
//////////////////////////////////////////
std::string musik::core::GetPluginDirectory(){
std::string sDirectory(GetApplicationDirectory());
sDirectory.append("plugins/");
return sDirectory;
}
//////////////////////////////////////////
///\brief
///Get path to where the application is located.
///
///\returns
///String with the path
//////////////////////////////////////////
std::string musik::core::GetApplicationDirectory() {
std::string sDirectory;
@ -98,17 +81,6 @@ std::string musik::core::GetDataDirectory(){
return directory;
}
//////////////////////////////////////////
///\brief
///Find out the full path to a file.
///
///\param sFile
///File to get the full path to.
///
///\returns
///String with path.
//////////////////////////////////////////
std::string musik::core::GetPath(const std::string &sFile){
std::string sPath;

View File

@ -39,28 +39,12 @@
#include <string>
#include <core/config.h>
namespace musik{ namespace core{
namespace musik { namespace core {
/*****************************
Path to where the executable is located.
*****************************/
std::string GetApplicationDirectory();
/*****************************
Path to where the executable is located.
*****************************/
std::string GetDataDirectory();
/*****************************
Get the full path of the sFile
*****************************/
std::string GetPath(const std::string &sFile);
/*****************************
Path to where plugins are located.
*****************************/
std::string GetPluginDirectory();
UINT64 Checksum(char *data,unsigned int bytes);
} }

View File

@ -44,6 +44,7 @@
#include <app/layout/LibraryLayout.h>
#include <app/window/OutputWindow.h>
#include <app/util/GlobalHotkeys.h>
#include <app/service/PlaybackService.h>
#include <boost/locale.hpp>
#include <boost/filesystem/path.hpp>
@ -171,12 +172,14 @@ int main(int argc, char* argv[])
Transport tp;
tp.SetVolume(0.75);
PlaybackService playback(tp);
using musik::core::LibraryFactory;
LibraryPtr library = LibraryFactory::Libraries().at(0);
GlobalHotkeys globalHotkeys(tp, library);
ILayoutPtr libraryLayout(new LibraryLayout(tp, library));
ILayoutPtr libraryLayout(new LibraryLayout(playback, library));
ILayoutPtr consoleLayout(new MainLayout(tp, library));
int64 ch;

View File

@ -13,9 +13,10 @@ using namespace musik::core::library::constants;
#define TRANSPORT_HEIGHT 3
#define DEFAULT_CATEGORY Track::ALBUM_ID
LibraryLayout::LibraryLayout(Transport& transport, LibraryPtr library)
LibraryLayout::LibraryLayout(PlaybackService& playback, LibraryPtr library)
: LayoutBase()
, transport(transport) {
, playback(playback)
, transport(playback.GetTransport()) {
this->library = library;
this->InitializeWindows();
}
@ -43,7 +44,7 @@ void LibraryLayout::Layout() {
void LibraryLayout::InitializeWindows() {
this->categoryList.reset(new CategoryListView(this->library, DEFAULT_CATEGORY));
this->trackList.reset(new TrackListView(this->transport, this->library));
this->trackList.reset(new TrackListView(this->playback, this->library));
this->transportView.reset(new TransportWindow(this->library, this->transport));
this->AddWindow(this->categoryList);
@ -106,10 +107,10 @@ bool LibraryLayout::KeyPress(int64 ch) {
/* copied from GlobalHotkeys. should probably be generalized
at some point. */
int state = this->transport.GetPlaybackState();
if (state == Transport::StatePaused) {
if (state == Transport::PlaybackPaused) {
this->transport.Resume();
}
else if (state == Transport::StatePlaying) {
else if (state == Transport::PlaybackPlaying) {
this->transport.Pause();
}
}

View File

@ -5,6 +5,7 @@
#include <app/window/CategoryListView.h>
#include <app/window/TrackListView.h>
#include <app/window/TransportWindow.h>
#include <app/service/PlaybackService.h>
#include <core/playback/Transport.h>
#include <core/library/ILibrary.h>
@ -16,7 +17,7 @@ using musik::core::audio::Transport;
class LibraryLayout : public LayoutBase, public sigslot::has_slots<> {
public:
LibraryLayout(Transport& transport, LibraryPtr library);
LibraryLayout(PlaybackService& playback, LibraryPtr library);
virtual ~LibraryLayout();
virtual void Layout();
@ -34,6 +35,7 @@ class LibraryLayout : public LayoutBase, public sigslot::has_slots<> {
void OnCategoryViewInvalidated(
ListWindow *view, size_t selectedIndex);
PlaybackService& playback;
Transport& transport;
LibraryPtr library;
std::shared_ptr<CategoryListView> categoryList;

View File

@ -1,41 +1,65 @@
#include <stdafx.h>
#include "PlaybackService.h"
#include <cursespp/MessageQueue.h>
#include <cursespp/Message.h>
#include <core/playback/Transport.h>
#include <core/library/LocalLibraryConstants.h>
using musik::core::audio::Transport;
using namespace musik::core::library::constants;
#define URI_AT_INDEX(x) this->playlist.at(index + 1)->URI()
#define URI_AT_INDEX(x) this->playlist.at(x)->URI()
#define MESSAGE_START_NEXT_TRACK 2000
class StreamEvent : public IMessage {
};
PlaybackService::PlaybackService(Transport& transport)
: transport(transport) {
transport.PlaybackEvent.connect(this, &PlaybackService::OnTransportEvent);
this->index = this->next = (size_t) -1;
transport.StreamEvent.connect(this, &PlaybackService::OnStreamEvent);
this->index = (size_t) -1;
}
void PlaybackService::ProcessMessage(IMessage &message) {
if (message.MessageType() == MESSAGE_START_NEXT_TRACK) {
if (this->playlist.size() > index + 1) {
++index;
std::string uri = URI_AT_INDEX(index);
transport.Start(uri);
}
else {
transport.Stop();
index = (size_t)-1;
}
}
}
void PlaybackService::Start(std::vector<TrackPtr>& tracks, size_t index) {
this->playlist.clear();
std::copy(tracks.begin(), tracks.end(), this->playlist.begin());
std::copy(tracks.begin(), tracks.end(), std::back_inserter(this->playlist));
this->Start(index);
}
void PlaybackService::Start(size_t index) {
transport.Start(URI_AT_INDEX(index));
transport.Stop();
std::string uri = URI_AT_INDEX(index);
transport.Start(uri);
this->index = index;
}
void PlaybackService::OnTransportEvent(int eventType, std::string uri) {
if (eventType == Transport::EventAlmostDone) {
if (this->playlist.size() > index + 1) {
std::string uri = URI_AT_INDEX(index + 1);
transport.PrepareNextTrack(uri);
void PlaybackService::OnStreamEvent(int eventType, std::string uri) {
//if (eventType == Transport::StreamFinished) {
// MessageQueue::Instance().Post(
// Message::Create(this, MESSAGE_START_NEXT_TRACK, 0, 0));
//}
if (eventType == Transport::StreamAlmostDone) {
if (this->playlist.size() > this->index + 1) {
this->transport.PrepareNextTrack(URI_AT_INDEX(index + 1));
index++;
}
}
}

View File

@ -24,9 +24,9 @@ class PlaybackService : public IMessageTarget, public sigslot::has_slots<> {
size_t Count() { return this->playlist.size(); }
private:
void OnTransportEvent(int eventType, std::string uri);
void OnStreamEvent(int eventType, std::string uri);
Transport& transport;
std::vector<TrackPtr> playlist;
size_t index, next;
size_t index;
};

View File

@ -17,10 +17,10 @@ bool GlobalHotkeys::Handle(int64 ch) {
if (kn == "^P") {
int state = this->transport.GetPlaybackState();
if (state == Transport::StatePaused) {
if (state == Transport::PlaybackPaused) {
this->transport.Resume();
}
else if (state == Transport::StatePlaying) {
else if (state == Transport::PlaybackPlaying) {
this->transport.Pause();
}
}

View File

@ -30,10 +30,10 @@ using std::setw;
using std::setfill;
using std::setiosflags;
TrackListView::TrackListView(Transport& transport, LibraryPtr library, IWindow *parent)
: ListWindow(parent) {
TrackListView::TrackListView(PlaybackService& playback, LibraryPtr library, IWindow *parent)
: ListWindow(parent)
, playback(playback) {
this->SetContentColor(BOX_COLOR_WHITE_ON_BLACK);
this->transport = &transport;
this->library = library;
this->library->QueryCompleted.connect(this, &TrackListView::OnQueryCompleted);
this->adapter = new Adapter(*this);
@ -58,10 +58,7 @@ bool TrackListView::KeyPress(int64 ch) {
if (ch == '\n') { /* return */
size_t selected = this->GetSelectedIndex();
if (this->metadata && this->metadata->size() > selected) {
TrackPtr track = this->metadata->at(selected);
std::string fn = track->GetValue(Track::FILENAME);
this->transport->Stop();
this->transport->Start(fn);
playback.Start(*this->metadata, selected);
return true;
}
}

View File

@ -3,10 +3,10 @@
#include <cursespp/curses_config.h>
#include <cursespp/ScrollAdapterBase.h>
#include <cursespp/IKeyHandler.h>
#include <cursespp/ListWindow.h>
#include <app/query/TrackListViewQuery.h>
#include <app/service/PlaybackService.h>
#include <core/playback/Transport.h>
#include <core/library/ILibrary.h>
@ -17,7 +17,7 @@ using musik::core::audio::Transport;
class TrackListView : public ListWindow, public sigslot::has_slots<> {
public:
TrackListView(Transport& transport, LibraryPtr library, IWindow *parent = NULL);
TrackListView(PlaybackService& playback, LibraryPtr library, IWindow *parent = NULL);
~TrackListView();
virtual void ProcessMessage(IMessage &message);
@ -45,6 +45,6 @@ class TrackListView : public ListWindow, public sigslot::has_slots<> {
std::shared_ptr<TrackListViewQuery> query;
std::shared_ptr<std::vector<TrackPtr>> metadata;
Adapter* adapter;
Transport* transport;
PlaybackService& playback;
LibraryPtr library;
};

View File

@ -43,7 +43,7 @@ TransportWindow::TransportWindow(LibraryPtr library, Transport& transport)
this->library = library;
this->library->QueryCompleted.connect(this, &TransportWindow::OnQueryCompleted);
this->transport = &transport;
this->transport->PlaybackEvent.connect(this, &TransportWindow::OnTransportPlaybackEvent);
this->transport->StreamEvent.connect(this, &TransportWindow::OnTransportStreamEvent);
this->transport->VolumeChanged.connect(this, &TransportWindow::OnTransportVolumeChanged);
this->paused = false;
}
@ -65,8 +65,8 @@ void TransportWindow::ProcessMessage(IMessage &message) {
}
}
void TransportWindow::OnTransportPlaybackEvent(int eventType, std::string url) {
if (eventType == Transport::EventPlaying) {
void TransportWindow::OnTransportStreamEvent(int eventType, std::string url) {
if (eventType == Transport::StreamPlaying) {
this->trackQuery.reset(new SingleTrackQuery(url));
this->library->Enqueue(this->trackQuery);
SCHEDULE_REFRESH(0)
@ -88,7 +88,7 @@ void TransportWindow::Update() {
this->Clear();
WINDOW *c = this->GetContent();
bool paused = (transport->GetPlaybackState() == Transport::StatePaused);
bool paused = (transport->GetPlaybackState() == Transport::PlaybackPaused);
int64 gb = COLOR_PAIR(BOX_COLOR_GREEN_ON_BLACK);
/* playing SONG TITLE from ALBUM NAME */

View File

@ -23,7 +23,7 @@ class TransportWindow : public Window, public sigslot::has_slots<> {
void Update();
private:
void OnTransportPlaybackEvent(int eventType, std::string url);
void OnTransportStreamEvent(int eventType, std::string url);
void OnTransportVolumeChanged();
void OnQueryCompleted(QueryPtr query);