mirror of
https://github.com/clangen/musikcube.git
synced 2025-03-01 10:13:22 +00:00
- Cleaned up and generalized Transport event handling
- Added some virtual destructors to interfaces
This commit is contained in:
parent
483760effd
commit
2d65ab480a
@ -41,23 +41,22 @@ using namespace musik::core::audio;
|
|||||||
|
|
||||||
static std::string TAG = "Player";
|
static std::string TAG = "Player";
|
||||||
|
|
||||||
PlayerPtr Player::Create(std::string &url, OutputPtr *output) {
|
PlayerPtr Player::Create(std::string &url, OutputPtr output) {
|
||||||
return PlayerPtr(new Player(url,output));
|
return PlayerPtr(new Player(url, output));
|
||||||
}
|
}
|
||||||
|
|
||||||
Player::Player(std::string &url, OutputPtr *output)
|
Player::Player(std::string &url, OutputPtr output)
|
||||||
: volume(1.0)
|
: volume(1.0)
|
||||||
, state(Player::Precache)
|
, state(Player::Precache)
|
||||||
, url(url)
|
, url(url)
|
||||||
, prebufferSizeBytes(0)
|
, prebufferSizeBytes(0)
|
||||||
, maxPrebufferSizeBytes(2000000)
|
, maxPrebufferSizeBytes(2000000)
|
||||||
, currentPosition(0)
|
, currentPosition(0)
|
||||||
, setPosition(-1)
|
, setPosition(-1) {
|
||||||
{
|
|
||||||
musik::debug::info(TAG, "new instance created");
|
musik::debug::info(TAG, "new instance created");
|
||||||
|
|
||||||
if (*output) {
|
if (output) {
|
||||||
this->output = *output;
|
this->output = output;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* if no output is specified, find all output plugins, and select the first one. */
|
/* if no output is specified, find all output plugins, and select the first one. */
|
||||||
|
@ -46,18 +46,17 @@
|
|||||||
|
|
||||||
namespace musik { namespace core { namespace audio {
|
namespace musik { namespace core { namespace audio {
|
||||||
|
|
||||||
class Player;
|
class Player;
|
||||||
class Transport;
|
|
||||||
typedef std::shared_ptr<Player> PlayerPtr;
|
typedef std::shared_ptr<Player> PlayerPtr;
|
||||||
|
|
||||||
class Player : public IBufferProvider {
|
class Player : public IBufferProvider {
|
||||||
public:
|
public:
|
||||||
typedef std::shared_ptr<IOutput> OutputPtr;
|
typedef std::shared_ptr<IOutput> OutputPtr;
|
||||||
|
|
||||||
static PlayerPtr Create(std::string &url,OutputPtr *output = NULL);
|
static PlayerPtr Create(std::string &url, OutputPtr output = OutputPtr());
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Player(std::string &url,OutputPtr *output);
|
Player(std::string &url, OutputPtr output);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~Player();
|
~Player();
|
||||||
@ -75,6 +74,8 @@ namespace musik { namespace core { namespace audio {
|
|||||||
double Volume();
|
double Volume();
|
||||||
void SetVolume(double volume);
|
void SetVolume(double volume);
|
||||||
|
|
||||||
|
std::string GetUrl() const { return this->url; }
|
||||||
|
|
||||||
bool Exited();
|
bool Exited();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -83,19 +84,13 @@ namespace musik { namespace core { namespace audio {
|
|||||||
PlayerEvent PlaybackAlmostEnded;
|
PlayerEvent PlaybackAlmostEnded;
|
||||||
PlayerEvent PlaybackEnded;
|
PlayerEvent PlaybackEnded;
|
||||||
PlayerEvent PlaybackError;
|
PlayerEvent PlaybackError;
|
||||||
|
|
||||||
OutputPtr output;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ThreadLoop();
|
void ThreadLoop();
|
||||||
bool PreBuffer();
|
bool PreBuffer();
|
||||||
int State();
|
int State();
|
||||||
void ReleaseAllBuffers();
|
void ReleaseAllBuffers();
|
||||||
|
|
||||||
protected:
|
|
||||||
friend class Transport;
|
|
||||||
std::string url;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef boost::scoped_ptr<boost::thread> ThreadPtr;
|
typedef boost::scoped_ptr<boost::thread> ThreadPtr;
|
||||||
typedef std::list<BufferPtr> BufferList;
|
typedef std::list<BufferPtr> BufferList;
|
||||||
@ -107,10 +102,13 @@ namespace musik { namespace core { namespace audio {
|
|||||||
Quit = 2
|
Quit = 2
|
||||||
} States;
|
} States;
|
||||||
|
|
||||||
|
OutputPtr output;
|
||||||
StreamPtr stream;
|
StreamPtr stream;
|
||||||
ThreadPtr thread;
|
ThreadPtr thread;
|
||||||
BufferList lockedBuffers;
|
BufferList lockedBuffers;
|
||||||
|
|
||||||
|
std::string url;
|
||||||
|
|
||||||
BufferList prebufferQueue;
|
BufferList prebufferQueue;
|
||||||
long prebufferSizeBytes;
|
long prebufferSizeBytes;
|
||||||
long maxPrebufferSizeBytes;
|
long maxPrebufferSizeBytes;
|
||||||
|
@ -51,7 +51,7 @@ namespace musik {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!active_) {
|
if (!active_) {
|
||||||
throw stopped_exception();
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_entry* top = queue_.front();
|
log_entry* top = queue_.front();
|
||||||
@ -101,8 +101,10 @@ static void thread_proc() {
|
|||||||
try {
|
try {
|
||||||
while (!cancel_) {
|
while (!cancel_) {
|
||||||
log_queue::log_entry* entry = queue_->pop_top();
|
log_queue::log_entry* entry = queue_->pop_top();
|
||||||
debug::string_logged(entry->level_, entry->tag_, entry->message_);
|
if (entry) {
|
||||||
delete entry;
|
debug::string_logged(entry->level_, entry->tag_, entry->message_);
|
||||||
|
delete entry;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (log_queue::stopped_exception&) {
|
catch (log_queue::stopped_exception&) {
|
||||||
|
@ -12,6 +12,8 @@ namespace musik { namespace core {
|
|||||||
sigslot::signal0<> PathsUpdated;
|
sigslot::signal0<> PathsUpdated;
|
||||||
sigslot::signal0<> TrackRefreshed;
|
sigslot::signal0<> TrackRefreshed;
|
||||||
|
|
||||||
|
virtual ~IIndexer() = 0 { }
|
||||||
|
|
||||||
virtual void AddPath(const std::string& path) = 0;
|
virtual void AddPath(const std::string& path) = 0;
|
||||||
virtual void RemovePath(const std::string& path) = 0;
|
virtual void RemovePath(const std::string& path) = 0;
|
||||||
virtual void GetPaths(std::vector<std::string>& paths) = 0;
|
virtual void GetPaths(std::vector<std::string>& paths) = 0;
|
||||||
|
@ -16,6 +16,8 @@ namespace musik { namespace core {
|
|||||||
public:
|
public:
|
||||||
sigslot::signal1<QueryPtr> QueryCompleted;
|
sigslot::signal1<QueryPtr> QueryCompleted;
|
||||||
|
|
||||||
|
virtual ~ILibrary() = 0 { }
|
||||||
|
|
||||||
virtual int Enqueue(QueryPtr query, unsigned int options = 0) = 0;
|
virtual int Enqueue(QueryPtr query, unsigned int options = 0) = 0;
|
||||||
virtual IIndexer *Indexer() = 0;
|
virtual IIndexer *Indexer() = 0;
|
||||||
virtual int Id() = 0;
|
virtual int Id() = 0;
|
||||||
|
@ -24,6 +24,8 @@ namespace musik { namespace core {
|
|||||||
Finished = 4,
|
Finished = 4,
|
||||||
} Status;
|
} Status;
|
||||||
|
|
||||||
|
virtual ~IQuery() = 0 { }
|
||||||
|
|
||||||
virtual bool Run(db::Connection &db) = 0;
|
virtual bool Run(db::Connection &db) = 0;
|
||||||
virtual int GetStatus() = 0;
|
virtual int GetStatus() = 0;
|
||||||
virtual int GetId() = 0;
|
virtual int GetId() = 0;
|
||||||
|
@ -64,7 +64,7 @@ namespace musik { namespace core {
|
|||||||
const std::string& libraryPath,
|
const std::string& libraryPath,
|
||||||
const std::string& dbFilename);
|
const std::string& dbFilename);
|
||||||
|
|
||||||
~Indexer();
|
virtual ~Indexer();
|
||||||
|
|
||||||
virtual void AddPath(const std::string& paths);
|
virtual void AddPath(const std::string& paths);
|
||||||
virtual void RemovePath(const std::string& paths);
|
virtual void RemovePath(const std::string& paths);
|
||||||
|
@ -41,115 +41,143 @@ using namespace musik::core::audio;
|
|||||||
static std::string TAG = "Transport";
|
static std::string TAG = "Transport";
|
||||||
|
|
||||||
Transport::Transport()
|
Transport::Transport()
|
||||||
:volume(1.0)
|
: volume(1.0) {
|
||||||
,gapless(true)
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Transport::~Transport(){
|
Transport::~Transport() {
|
||||||
this->nextPlayer.reset();
|
this->nextPlayer.reset();
|
||||||
this->currentPlayer.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);
|
boost::mutex::scoped_lock lock(this->stateMutex);
|
||||||
this->nextPlayer->Play();
|
this->currentPlayer = player;
|
||||||
}else{
|
|
||||||
this->nextPlayer = Player::Create(trackUrl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
musik::debug::info(TAG, "we were asked to start the track at " + url);
|
||||||
|
|
||||||
// Check if this is already Prepared
|
PlayerPtr player;
|
||||||
PlayerPtr player = this->nextPlayer;
|
|
||||||
this->nextPlayer.reset();
|
|
||||||
|
|
||||||
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
|
PlayerPtr newPlayer = this->nextPlayer;
|
||||||
if(!player || player->url != url){
|
this->nextPlayer.reset();
|
||||||
Player::OutputPtr output;
|
|
||||||
|
|
||||||
player = Player::Create(url, &output);
|
musik::debug::info(TAG, "creating a Player...");
|
||||||
player->SetVolume(this->volume);
|
|
||||||
|
|
||||||
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->RaisePlaybackEvent(Transport::EventScheduled, player);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transport::Stop(){
|
void Transport::Stop() {
|
||||||
musik::debug::info(TAG, "stop");
|
musik::debug::info(TAG, "stop");
|
||||||
this->players.clear();
|
|
||||||
this->currentPlayer.reset();
|
PlayerPtr player = NULL;
|
||||||
this->nextPlayer.reset();
|
|
||||||
this->PlaybackEnded();
|
{
|
||||||
|
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");
|
musik::debug::info(TAG, "pause");
|
||||||
|
|
||||||
// pause all players
|
PlayerPtr player;
|
||||||
for(PlayerList::iterator player=this->players.begin();player!=this->players.end();++player){
|
|
||||||
(*player)->Pause();
|
{
|
||||||
|
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");
|
musik::debug::info(TAG, "resume");
|
||||||
|
|
||||||
// Resume all players
|
PlayerPtr player;
|
||||||
for(PlayerList::iterator player=this->players.begin();player!=this->players.end();++player){
|
|
||||||
(*player)->Resume();
|
{
|
||||||
|
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 this->currentPlayer->Position();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transport::SetPosition(double seconds){
|
void Transport::SetPosition(double seconds) {
|
||||||
if(this->currentPlayer){
|
boost::mutex::scoped_lock lock(this->stateMutex);
|
||||||
|
|
||||||
|
if (this->currentPlayer) {
|
||||||
return this->currentPlayer->SetPosition(seconds);
|
return this->currentPlayer->SetPosition(seconds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double Transport::Volume() {
|
||||||
double Transport::Volume(){
|
|
||||||
return this->volume;
|
return this->volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transport::SetVolume(double volume){
|
void Transport::SetVolume(double volume) {
|
||||||
double oldVolume = this->volume;
|
double oldVolume = this->volume;
|
||||||
|
|
||||||
volume = max(0, min(1.0, volume));
|
volume = max(0, min(1.0, volume));
|
||||||
@ -160,48 +188,90 @@ void Transport::SetVolume(double volume){
|
|||||||
this->VolumeChanged();
|
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){
|
boost::mutex::scoped_lock lock(this->stateMutex);
|
||||||
(*player)->SetVolume(volume);
|
|
||||||
|
if (this->currentPlayer) {
|
||||||
|
this->currentPlayer->SetVolume(volume);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transport::OnPlaybackStarted(Player *player){
|
void Transport::OnPlaybackStarted(Player *player) {
|
||||||
if(this->currentPlayer.get()==player){
|
PlayerPtr playerForEvent;
|
||||||
this->PlaybackStarted();
|
|
||||||
|
{
|
||||||
|
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){
|
void Transport::OnPlaybackAlmostEnded(Player *player) {
|
||||||
if(this->currentPlayer.get()==player){
|
PlayerPtr playerForEvent;
|
||||||
this->PlaybackAlmostDone();
|
|
||||||
|
|
||||||
// Reuse the output
|
{
|
||||||
if(this->nextPlayer && this->gapless){
|
boost::mutex::scoped_lock lock(this->stateMutex);
|
||||||
// TODO
|
|
||||||
// this->nex
|
if (this->currentPlayer.get() == player) {
|
||||||
|
playerForEvent = this->currentPlayer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->RaisePlaybackEvent(Transport::EventAlmostDone, playerForEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transport::OnPlaybackEnded(Player *player){
|
void Transport::OnPlaybackEnded(Player *player) {
|
||||||
if(this->currentPlayer.get()==player){
|
PlayerPtr playerForEvent;
|
||||||
this->PlaybackEnded();
|
PlayerPtr nextPlayer;
|
||||||
|
|
||||||
// If the is a nextPlayer, then we should start playing right away
|
{
|
||||||
if(this->nextPlayer){
|
boost::mutex::scoped_lock lock(this->stateMutex);
|
||||||
this->Start(this->nextPlayer->url.c_str());
|
|
||||||
|
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) {
|
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);
|
||||||
|
}
|
@ -37,6 +37,7 @@
|
|||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
#include <boost/scoped_ptr.hpp>
|
#include <boost/scoped_ptr.hpp>
|
||||||
#include <sigslot/sigslot.h>
|
#include <sigslot/sigslot.h>
|
||||||
|
#include <boost/thread/mutex.hpp>
|
||||||
|
|
||||||
namespace musik { namespace core { namespace audio {
|
namespace musik { namespace core { namespace audio {
|
||||||
|
|
||||||
@ -59,26 +60,21 @@ namespace musik { namespace core { namespace audio {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
typedef enum {
|
typedef enum {
|
||||||
Started = 1,
|
EventScheduled = 0,
|
||||||
Ended = 2,
|
EventStarted = 1,
|
||||||
Error = 3
|
EventPaused = 2,
|
||||||
} PlaybackStatus;
|
EventResumed = 3,
|
||||||
|
EventAlmostDone = 4,
|
||||||
|
EventFinished = 5,
|
||||||
|
EventError = -1
|
||||||
|
} PlaybackEventType;
|
||||||
|
|
||||||
sigslot::signal1<std::string> TrackStarted;
|
sigslot::signal2<int, std::string> PlaybackEvent;
|
||||||
sigslot::signal0<> VolumeChanged;
|
sigslot::signal0<> VolumeChanged;
|
||||||
|
|
||||||
typedef sigslot::signal1<int> PlaybackStatusEvent;
|
|
||||||
PlaybackStatusEvent PlaybackStatusChange;
|
|
||||||
|
|
||||||
typedef sigslot::signal0<> PlaybackEvent;
|
|
||||||
PlaybackEvent PlaybackAlmostDone;
|
|
||||||
PlaybackEvent PlaybackStarted;
|
|
||||||
PlaybackEvent PlaybackEnded;
|
|
||||||
PlaybackEvent PlaybackPause;
|
|
||||||
PlaybackEvent PlaybackResume;
|
|
||||||
PlaybackEvent PlaybackError;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void RaisePlaybackEvent(int type, PlayerPtr player);
|
||||||
|
|
||||||
void OnPlaybackStarted(Player *player);
|
void OnPlaybackStarted(Player *player);
|
||||||
void OnPlaybackAlmostEnded(Player *player);
|
void OnPlaybackAlmostEnded(Player *player);
|
||||||
void OnPlaybackEnded(Player *player);
|
void OnPlaybackEnded(Player *player);
|
||||||
@ -86,10 +82,8 @@ namespace musik { namespace core { namespace audio {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
double volume;
|
double volume;
|
||||||
bool gapless;
|
|
||||||
|
|
||||||
typedef std::list<PlayerPtr> PlayerList;
|
boost::mutex stateMutex;
|
||||||
PlayerList players;
|
|
||||||
PlayerPtr currentPlayer;
|
PlayerPtr currentPlayer;
|
||||||
PlayerPtr nextPlayer;
|
PlayerPtr nextPlayer;
|
||||||
};
|
};
|
||||||
|
@ -191,6 +191,9 @@ int main(int argc, char* argv[])
|
|||||||
if (ch == '\t') { /* tab */
|
if (ch == '\t') { /* tab */
|
||||||
focusNextInLayout(state);
|
focusNextInLayout(state);
|
||||||
}
|
}
|
||||||
|
else if (kn == "^D") {
|
||||||
|
quit = true;
|
||||||
|
}
|
||||||
else if (kn == "ALT_K") {
|
else if (kn == "ALT_K") {
|
||||||
tp.SetVolume(tp.Volume() + 0.05); /* 5% */
|
tp.SetVolume(tp.Volume() + 0.05); /* 5% */
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ TransportWindow::TransportWindow(LibraryPtr library, Transport& transport)
|
|||||||
this->library = library;
|
this->library = library;
|
||||||
this->library->QueryCompleted.connect(this, &TransportWindow::OnQueryCompleted);
|
this->library->QueryCompleted.connect(this, &TransportWindow::OnQueryCompleted);
|
||||||
this->transport = &transport;
|
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->transport->VolumeChanged.connect(this, &TransportWindow::OnTransportVolumeChanged);
|
||||||
this->paused = false;
|
this->paused = false;
|
||||||
}
|
}
|
||||||
@ -48,9 +48,11 @@ void TransportWindow::ProcessMessage(IWindowMessage &message) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransportWindow::OnTransportStarted(std::string url) {
|
void TransportWindow::OnTransportPlaybackEvent(int eventType, std::string url) {
|
||||||
this->trackQuery.reset(new SingleTrackQuery(url));
|
if (eventType == Transport::EventStarted) {
|
||||||
this->library->Enqueue(this->trackQuery);
|
this->trackQuery.reset(new SingleTrackQuery(url));
|
||||||
|
this->library->Enqueue(this->trackQuery);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TransportWindow::OnTransportVolumeChanged() {
|
void TransportWindow::OnTransportVolumeChanged() {
|
||||||
|
@ -23,7 +23,7 @@ class TransportWindow : public Window, public sigslot::has_slots<> {
|
|||||||
void Update();
|
void Update();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void OnTransportStarted(std::string url);
|
void OnTransportPlaybackEvent(int eventType, std::string url);
|
||||||
void OnTransportVolumeChanged();
|
void OnTransportVolumeChanged();
|
||||||
void OnQueryCompleted(QueryPtr query);
|
void OnQueryCompleted(QueryPtr query);
|
||||||
|
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
class IDisplayable {
|
class IDisplayable {
|
||||||
public:
|
public:
|
||||||
|
virtual ~IDisplayable() = 0 { }
|
||||||
|
|
||||||
virtual void Show() = 0;
|
virtual void Show() = 0;
|
||||||
virtual void Hide() = 0;
|
virtual void Hide() = 0;
|
||||||
};
|
};
|
@ -4,5 +4,7 @@
|
|||||||
|
|
||||||
class IInput {
|
class IInput {
|
||||||
public:
|
public:
|
||||||
|
virtual ~IInput() = 0 { }
|
||||||
|
|
||||||
virtual void WriteChar(int64 ch) = 0;
|
virtual void WriteChar(int64 ch) = 0;
|
||||||
};
|
};
|
@ -4,5 +4,6 @@
|
|||||||
|
|
||||||
class IKeyHandler {
|
class IKeyHandler {
|
||||||
public:
|
public:
|
||||||
|
virtual ~IKeyHandler() = 0 { }
|
||||||
virtual void KeyPress(int64 ch) = 0;
|
virtual void KeyPress(int64 ch) = 0;
|
||||||
};
|
};
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
class ILayout : public IWindowGroup, public IDisplayable {
|
class ILayout : public IWindowGroup, public IDisplayable {
|
||||||
public:
|
public:
|
||||||
|
virtual ~ILayout() = 0 { }
|
||||||
virtual IWindow* FocusNext() = 0;
|
virtual IWindow* FocusNext() = 0;
|
||||||
virtual IWindow* FocusPrev() = 0;
|
virtual IWindow* FocusPrev() = 0;
|
||||||
virtual IWindow* GetFocus() = 0;
|
virtual IWindow* GetFocus() = 0;
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
class IScrollAdapter {
|
class IScrollAdapter {
|
||||||
public:
|
public:
|
||||||
|
virtual ~IScrollAdapter() = 0 { }
|
||||||
|
|
||||||
struct ScrollPosition {
|
struct ScrollPosition {
|
||||||
ScrollPosition() {
|
ScrollPosition() {
|
||||||
firstVisibleEntryIndex = 0;
|
firstVisibleEntryIndex = 0;
|
||||||
@ -22,6 +24,7 @@ class IScrollAdapter {
|
|||||||
|
|
||||||
class IEntry {
|
class IEntry {
|
||||||
public:
|
public:
|
||||||
|
virtual ~IEntry() = 0 { }
|
||||||
virtual size_t GetLineCount() = 0;
|
virtual size_t GetLineCount() = 0;
|
||||||
virtual std::string GetLine(size_t line) = 0;
|
virtual std::string GetLine(size_t line) = 0;
|
||||||
virtual std::string GetValue() = 0;
|
virtual std::string GetValue() = 0;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
class IScrollable {
|
class IScrollable {
|
||||||
public:
|
public:
|
||||||
|
virtual ~IScrollable() = 0 { }
|
||||||
virtual void ScrollToTop() = 0;
|
virtual void ScrollToTop() = 0;
|
||||||
virtual void ScrollToBottom() = 0;
|
virtual void ScrollToBottom() = 0;
|
||||||
virtual void ScrollUp(int delta = 1) = 0;
|
virtual void ScrollUp(int delta = 1) = 0;
|
||||||
|
@ -7,6 +7,7 @@ class IWindowMessage;
|
|||||||
|
|
||||||
class IWindow : public IDisplayable {
|
class IWindow : public IDisplayable {
|
||||||
public:
|
public:
|
||||||
|
virtual ~IWindow() = 0 { }
|
||||||
virtual void Repaint() = 0;
|
virtual void Repaint() = 0;
|
||||||
virtual void SetParent(IWindow* parent) = 0;
|
virtual void SetParent(IWindow* parent) = 0;
|
||||||
virtual void Show() = 0;
|
virtual void Show() = 0;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
class IWindowGroup {
|
class IWindowGroup {
|
||||||
public:
|
public:
|
||||||
|
virtual ~IWindowGroup() = 0 { }
|
||||||
virtual bool AddWindow(IWindowPtr window) = 0;
|
virtual bool AddWindow(IWindowPtr window) = 0;
|
||||||
virtual bool RemoveWindow(IWindowPtr window) = 0;
|
virtual bool RemoveWindow(IWindowPtr window) = 0;
|
||||||
virtual size_t GetWindowCount() = 0;
|
virtual size_t GetWindowCount() = 0;
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
class IWindowMessage {
|
class IWindowMessage {
|
||||||
public:
|
public:
|
||||||
|
virtual ~IWindowMessage() = 0 { }
|
||||||
virtual IWindow* Target() = 0;
|
virtual IWindow* Target() = 0;
|
||||||
virtual int MessageType() = 0;
|
virtual int MessageType() = 0;
|
||||||
virtual int64 UserData1() = 0;
|
virtual int64 UserData1() = 0;
|
||||||
|
@ -45,7 +45,7 @@ void Window::ProcessMessage(IWindowMessage &message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Window::IsAcceptingMessages() {
|
bool Window::IsAcceptingMessages() {
|
||||||
return this->IsVisible();
|
return true; //this->IsVisible();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Window::IsVisible() {
|
bool Window::IsVisible() {
|
||||||
@ -260,14 +260,16 @@ void Window::Clear() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Window::Repaint() {
|
void Window::Repaint() {
|
||||||
if (this->frame && this->content) {
|
if (this->isVisible) {
|
||||||
wnoutrefresh(this->frame);
|
if (this->frame && this->content) {
|
||||||
|
wnoutrefresh(this->frame);
|
||||||
|
|
||||||
if (this->frame != this->content) {
|
if (this->frame != this->content) {
|
||||||
wnoutrefresh(this->content);
|
wnoutrefresh(this->content);
|
||||||
|
}
|
||||||
|
|
||||||
|
drawPending = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
drawPending = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user