mirror of
https://github.com/clangen/musikcube.git
synced 2025-03-29 19:20:28 +00:00
Propagate buffering status from Player -> Transport -> PlaybackService
-> UI and render it in TransportWindow.
This commit is contained in:
parent
b21b21dab6
commit
c644862959
@ -50,7 +50,7 @@ static std::string TAG = "CrossfadeTransport";
|
||||
|
||||
CrossfadeTransport::CrossfadeTransport()
|
||||
: volume(1.0)
|
||||
, state(PlaybackStopped)
|
||||
, playbackState(PlaybackStopped)
|
||||
, muted(false)
|
||||
, crossfader(*this)
|
||||
, active(*this, crossfader)
|
||||
@ -66,7 +66,12 @@ CrossfadeTransport::~CrossfadeTransport() {
|
||||
|
||||
PlaybackState CrossfadeTransport::GetPlaybackState() {
|
||||
Lock lock(this->stateMutex);
|
||||
return this->state;
|
||||
return this->playbackState;
|
||||
}
|
||||
|
||||
StreamState CrossfadeTransport::GetStreamState() {
|
||||
Lock lock(this->stateMutex);
|
||||
return this->activePlayerState;
|
||||
}
|
||||
|
||||
void CrossfadeTransport::PrepareNextTrack(const std::string& uri, Gain gain) {
|
||||
@ -88,6 +93,12 @@ void CrossfadeTransport::Start(const std::string& uri, Gain gain, StartMode mode
|
||||
this->active.Reset();
|
||||
this->next.TransferTo(this->active);
|
||||
|
||||
if (this->active.player) {
|
||||
this->RaiseStreamEvent(
|
||||
this->active.player->GetStreamState(),
|
||||
this->active.player);
|
||||
}
|
||||
|
||||
if (immediate) {
|
||||
this->active.Start(this->volume);
|
||||
}
|
||||
@ -98,7 +109,7 @@ void CrossfadeTransport::Start(const std::string& uri, Gain gain, StartMode mode
|
||||
}
|
||||
}
|
||||
|
||||
this->RaiseStreamEvent(StreamScheduled, this->active.player);
|
||||
this->RaiseStreamEvent(StreamBuffering, this->active.player);
|
||||
}
|
||||
|
||||
std::string CrossfadeTransport::Uri() {
|
||||
@ -176,7 +187,7 @@ void CrossfadeTransport::SetPosition(double seconds) {
|
||||
Lock lock(this->stateMutex);
|
||||
|
||||
if (this->active.player) {
|
||||
if (this->state != PlaybackPlaying) {
|
||||
if (this->playbackState != PlaybackPlaying) {
|
||||
this->SetPlaybackState(PlaybackPlaying);
|
||||
}
|
||||
this->active.player->SetPosition(seconds);
|
||||
@ -243,7 +254,7 @@ void CrossfadeTransport::SetVolume(double volume) {
|
||||
}
|
||||
}
|
||||
|
||||
void CrossfadeTransport::OnPlayerPrepared(Player* player) {
|
||||
void CrossfadeTransport::OnPlayerBuffered(Player* player) {
|
||||
{
|
||||
Lock lock(this->stateMutex);
|
||||
|
||||
@ -280,7 +291,7 @@ void CrossfadeTransport::OnPlayerPrepared(Player* player) {
|
||||
}
|
||||
|
||||
if (player == this->active.player) {
|
||||
this->RaiseStreamEvent(StreamPrepared, player);
|
||||
this->RaiseStreamEvent(StreamBuffered, player);
|
||||
this->SetPlaybackState(PlaybackPrepared);
|
||||
}
|
||||
}
|
||||
@ -364,8 +375,8 @@ void CrossfadeTransport::SetPlaybackState(int state) {
|
||||
|
||||
{
|
||||
Lock lock(this->stateMutex);
|
||||
changed = (this->state != state);
|
||||
this->state = (PlaybackState) state;
|
||||
changed = (this->playbackState != state);
|
||||
this->playbackState = (PlaybackState) state;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
@ -374,6 +385,13 @@ void CrossfadeTransport::SetPlaybackState(int state) {
|
||||
}
|
||||
|
||||
void CrossfadeTransport::RaiseStreamEvent(int type, Player* player) {
|
||||
{
|
||||
Lock lock(this->stateMutex);
|
||||
if (player == active.player) {
|
||||
this->activePlayerState = (StreamState) type;
|
||||
}
|
||||
}
|
||||
|
||||
this->StreamEvent(type, player->GetUrl());
|
||||
}
|
||||
|
||||
|
@ -83,6 +83,7 @@ namespace musik { namespace core { namespace audio {
|
||||
virtual void ReloadOutput();
|
||||
|
||||
virtual musik::core::sdk::PlaybackState GetPlaybackState();
|
||||
virtual musik::core::sdk::StreamState GetStreamState();
|
||||
|
||||
private:
|
||||
using Lock = std::unique_lock<std::recursive_mutex>;
|
||||
@ -129,13 +130,14 @@ namespace musik { namespace core { namespace audio {
|
||||
|
||||
void OnCrossfaderEmptied();
|
||||
|
||||
virtual void OnPlayerPrepared(Player* player);
|
||||
virtual void OnPlayerBuffered(Player* player);
|
||||
virtual void OnPlayerStarted(Player* player);
|
||||
virtual void OnPlayerFinished(Player* player);
|
||||
virtual void OnPlayerError(Player* player);
|
||||
virtual void OnPlayerMixPoint(Player* player, int id, double time);
|
||||
|
||||
musik::core::sdk::PlaybackState state;
|
||||
musik::core::sdk::PlaybackState playbackState;
|
||||
musik::core::sdk::StreamState activePlayerState;
|
||||
std::recursive_mutex stateMutex;
|
||||
Crossfader crossfader;
|
||||
PlayerContext active;
|
||||
|
@ -57,11 +57,12 @@ static std::string TAG = "GaplessTransport";
|
||||
instance->activePlayer->Detach(instance); \
|
||||
instance->activePlayer->Destroy(); \
|
||||
instance->activePlayer = nullptr; \
|
||||
instance->activePlayerState = StreamError; \
|
||||
}
|
||||
|
||||
GaplessTransport::GaplessTransport()
|
||||
: volume(1.0)
|
||||
, state(PlaybackStopped)
|
||||
, playbackState(PlaybackStopped)
|
||||
, activePlayer(nullptr)
|
||||
, nextPlayer(nullptr)
|
||||
, nextCanStart(false)
|
||||
@ -77,7 +78,12 @@ GaplessTransport::~GaplessTransport() {
|
||||
|
||||
PlaybackState GaplessTransport::GetPlaybackState() {
|
||||
LockT lock(this->stateMutex);
|
||||
return this->state;
|
||||
return this->playbackState;
|
||||
}
|
||||
|
||||
StreamState GaplessTransport::GetStreamState() {
|
||||
LockT lock(this->stateMutex);
|
||||
return this->activePlayerState;
|
||||
}
|
||||
|
||||
void GaplessTransport::PrepareNextTrack(const std::string& uri, Gain gain) {
|
||||
@ -121,6 +127,10 @@ void GaplessTransport::StartWithPlayer(Player* newPlayer, StartMode mode) {
|
||||
this->nextPlayer = nullptr;
|
||||
this->activePlayer = newPlayer;
|
||||
|
||||
if (newPlayer) {
|
||||
this->RaiseStreamEvent(newPlayer->GetStreamState(), newPlayer);
|
||||
}
|
||||
|
||||
/* first argument suppresses the "Stop" event from getting triggered,
|
||||
the second param is used for gapless playback -- we won't stop the output
|
||||
and will allow pending buffers to finish if we're not automatically
|
||||
@ -135,8 +145,6 @@ void GaplessTransport::StartWithPlayer(Player* newPlayer, StartMode mode) {
|
||||
newPlayer->Play();
|
||||
}
|
||||
}
|
||||
|
||||
this->RaiseStreamEvent(StreamScheduled, newPlayer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,7 +245,7 @@ void GaplessTransport::SetPosition(double seconds) {
|
||||
LockT lock(this->stateMutex);
|
||||
|
||||
if (this->activePlayer) {
|
||||
if (this->state != PlaybackPlaying) {
|
||||
if (this->playbackState != PlaybackPlaying) {
|
||||
this->SetPlaybackState(PlaybackPlaying);
|
||||
}
|
||||
this->activePlayer->SetPosition(seconds);
|
||||
@ -289,9 +297,9 @@ void GaplessTransport::SetNextCanStart(bool nextCanStart) {
|
||||
this->nextCanStart = nextCanStart;
|
||||
}
|
||||
|
||||
void GaplessTransport::OnPlayerPrepared(Player* player) {
|
||||
void GaplessTransport::OnPlayerBuffered(Player* player) {
|
||||
if (player == this->activePlayer) {
|
||||
this->RaiseStreamEvent(StreamPrepared, player);
|
||||
this->RaiseStreamEvent(StreamBuffered, player);
|
||||
this->SetPlaybackState(PlaybackPrepared);
|
||||
}
|
||||
}
|
||||
@ -372,8 +380,8 @@ void GaplessTransport::SetPlaybackState(int state) {
|
||||
|
||||
{
|
||||
LockT lock(this->stateMutex);
|
||||
changed = (this->state != state);
|
||||
this->state = (PlaybackState) state;
|
||||
changed = (this->playbackState != state);
|
||||
this->playbackState = (PlaybackState) state;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
@ -382,5 +390,11 @@ void GaplessTransport::SetPlaybackState(int state) {
|
||||
}
|
||||
|
||||
void GaplessTransport::RaiseStreamEvent(int type, Player* player) {
|
||||
{
|
||||
LockT lock(this->stateMutex);
|
||||
if (player == activePlayer) {
|
||||
this->activePlayerState = (StreamState) type;
|
||||
}
|
||||
}
|
||||
this->StreamEvent(type, player->GetUrl());
|
||||
}
|
||||
|
@ -76,6 +76,7 @@ namespace musik { namespace core { namespace audio {
|
||||
virtual void ReloadOutput();
|
||||
|
||||
virtual musik::core::sdk::PlaybackState GetPlaybackState();
|
||||
virtual musik::core::sdk::StreamState GetStreamState();
|
||||
|
||||
private:
|
||||
using LockT = std::unique_lock<std::recursive_mutex>;
|
||||
@ -93,13 +94,14 @@ namespace musik { namespace core { namespace audio {
|
||||
void SetPlaybackState(int state);
|
||||
|
||||
virtual void OnPlayerStarted(Player* player);
|
||||
virtual void OnPlayerPrepared(Player* player);
|
||||
virtual void OnPlayerBuffered(Player* player);
|
||||
virtual void OnPlayerAlmostEnded(Player* player);
|
||||
virtual void OnPlayerFinished(Player* player);
|
||||
virtual void OnPlayerError(Player* player);
|
||||
virtual void OnPlayerDestroying(Player* player);
|
||||
|
||||
musik::core::sdk::PlaybackState state;
|
||||
musik::core::sdk::PlaybackState playbackState;
|
||||
musik::core::sdk::StreamState activePlayerState;
|
||||
std::recursive_mutex stateMutex;
|
||||
std::shared_ptr<musik::core::sdk::IOutput> output;
|
||||
Player* activePlayer;
|
||||
|
@ -79,6 +79,7 @@ namespace musik { namespace core { namespace audio {
|
||||
virtual void ReloadOutput() = 0;
|
||||
|
||||
virtual musik::core::sdk::PlaybackState GetPlaybackState() = 0;
|
||||
virtual musik::core::sdk::StreamState GetStreamState() = 0;
|
||||
};
|
||||
|
||||
} } }
|
||||
|
@ -163,6 +163,10 @@ PlaybackState MasterTransport::GetPlaybackState() {
|
||||
return this->transport->GetPlaybackState();
|
||||
}
|
||||
|
||||
StreamState MasterTransport::GetStreamState() {
|
||||
return this->transport->GetStreamState();
|
||||
}
|
||||
|
||||
void MasterTransport::OnStreamEvent(int type, std::string url) {
|
||||
this->StreamEvent(type, url);
|
||||
}
|
||||
|
@ -72,6 +72,7 @@ namespace musik { namespace core { namespace audio {
|
||||
virtual void ReloadOutput();
|
||||
|
||||
virtual musik::core::sdk::PlaybackState GetPlaybackState();
|
||||
virtual musik::core::sdk::StreamState GetStreamState();
|
||||
|
||||
void SwitchTo(Type type);
|
||||
Type GetType();
|
||||
|
@ -305,15 +305,13 @@ void PlaybackService::ProcessMessage(IMessage &message) {
|
||||
}
|
||||
else if (type == MESSAGE_STREAM_EVENT) {
|
||||
StreamMessage* streamMessage = static_cast<StreamMessage*>(&message);
|
||||
|
||||
int64_t eventType = streamMessage->GetEventType();
|
||||
StreamState eventType = (StreamState) streamMessage->GetEventType();
|
||||
|
||||
if (eventType == StreamPlaying) {
|
||||
TrackPtr track;
|
||||
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(this->playlistMutex);
|
||||
|
||||
if (this->nextIndex != NO_POSITION) {
|
||||
/* in most cases when we get here it means that the next track is
|
||||
starting, so we want to update our internal index. however, because
|
||||
@ -343,6 +341,16 @@ void PlaybackService::ProcessMessage(IMessage &message) {
|
||||
|
||||
this->PrepareNextTrack();
|
||||
}
|
||||
|
||||
bool raiseStreamEvent = false;
|
||||
{
|
||||
std::unique_lock<std::recursive_mutex> lock(this->playlistMutex);
|
||||
raiseStreamEvent = this->UriAtIndex(this->index) == streamMessage->GetUri();
|
||||
}
|
||||
|
||||
if (raiseStreamEvent) {
|
||||
this->StreamStateChanged(eventType);
|
||||
}
|
||||
}
|
||||
else if (type == MESSAGE_PLAYBACK_EVENT) {
|
||||
int64_t eventType = message.UserData1();
|
||||
@ -365,7 +373,7 @@ void PlaybackService::ProcessMessage(IMessage &message) {
|
||||
(*it)->OnPlaybackStateChanged((PlaybackState) eventType);
|
||||
}
|
||||
|
||||
this->PlaybackEvent((PlaybackState) eventType);
|
||||
this->PlaybackStateChanged((PlaybackState) eventType);
|
||||
}
|
||||
else if (type == MESSAGE_PREPARE_NEXT_TRACK) {
|
||||
if (transport->GetPlaybackState() != PlaybackStopped) {
|
||||
|
@ -63,7 +63,8 @@ namespace musik { namespace core { namespace audio {
|
||||
|
||||
/* copied from Transport, but will be automatically called on the
|
||||
specified MessageQueue's thread! */
|
||||
sigslot::signal1<int> PlaybackEvent;
|
||||
sigslot::signal1<musik::core::sdk::PlaybackState> PlaybackStateChanged;
|
||||
sigslot::signal1<musik::core::sdk::StreamState> StreamStateChanged;
|
||||
sigslot::signal0<> VolumeChanged;
|
||||
sigslot::signal1<double> TimeChanged;
|
||||
|
||||
|
@ -123,7 +123,8 @@ Player::Player(
|
||||
DestroyMode destroyMode,
|
||||
EventListener *listener,
|
||||
Gain gain)
|
||||
: state(Player::Idle)
|
||||
: internalState(Player::Idle)
|
||||
, streamState(StreamBuffering)
|
||||
, stream(Stream::Create())
|
||||
, url(url)
|
||||
, currentPosition(0)
|
||||
@ -159,8 +160,8 @@ Player::~Player() {
|
||||
void Player::Play() {
|
||||
std::unique_lock<std::mutex> lock(this->queueMutex);
|
||||
|
||||
if (this->state != Player::Quit) {
|
||||
this->state = Player::Playing;
|
||||
if (this->internalState != Player::Quit) {
|
||||
this->internalState = Player::Playing;
|
||||
this->writeToOutputCondition.notify_all();
|
||||
}
|
||||
}
|
||||
@ -173,11 +174,11 @@ void Player::Destroy() {
|
||||
|
||||
std::unique_lock<std::mutex> lock(this->queueMutex);
|
||||
|
||||
if (this->state == Player::Quit && !this->thread) {
|
||||
if (this->internalState == Player::Quit && !this->thread) {
|
||||
return; /* already terminated (or terminating) */
|
||||
}
|
||||
|
||||
this->state = Player::Quit;
|
||||
this->internalState = Player::Quit;
|
||||
this->writeToOutputCondition.notify_all();
|
||||
this->thread->detach();
|
||||
delete this->thread;
|
||||
@ -258,7 +259,7 @@ void Player::AddMixPoint(int id, double time) {
|
||||
|
||||
int Player::State() {
|
||||
std::unique_lock<std::mutex> lock(this->queueMutex);
|
||||
return this->state;
|
||||
return this->internalState;
|
||||
}
|
||||
|
||||
bool Player::HasCapability(Capability c) {
|
||||
@ -297,13 +298,14 @@ void musik::core::audio::playerThreadLoop(Player* player) {
|
||||
|
||||
if (player->stream->OpenStream(player->url)) {
|
||||
for (Listener* l : player->Listeners()) {
|
||||
l->OnPlayerPrepared(player);
|
||||
player->streamState = StreamBuffered;
|
||||
l->OnPlayerBuffered(player);
|
||||
}
|
||||
|
||||
/* wait until we enter the Playing or Quit state */
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(player->queueMutex);
|
||||
while (player->state == Player::Idle) {
|
||||
while (player->internalState == Player::Idle) {
|
||||
player->writeToOutputCondition.wait(lock);
|
||||
}
|
||||
}
|
||||
@ -419,6 +421,7 @@ void musik::core::audio::playerThreadLoop(Player* player) {
|
||||
it wasn't stopped by the user. raise the "almost ended" flag. */
|
||||
if (!player->Exited()) {
|
||||
for (Listener* l : player->Listeners()) {
|
||||
player->streamState = StreamAlmostDone;
|
||||
l->OnPlayerAlmostEnded(player);
|
||||
}
|
||||
}
|
||||
@ -428,6 +431,7 @@ void musik::core::audio::playerThreadLoop(Player* player) {
|
||||
else {
|
||||
if (!player->Exited()) {
|
||||
for (Listener* l : player->Listeners()) {
|
||||
player->streamState = StreamError;
|
||||
l->OnPlayerError(player);
|
||||
}
|
||||
}
|
||||
@ -454,13 +458,15 @@ void musik::core::audio::playerThreadLoop(Player* player) {
|
||||
|
||||
if (!player->Exited()) {
|
||||
for (Listener* l : player->Listeners()) {
|
||||
player->streamState = StreamFinished;
|
||||
l->OnPlayerFinished(player);
|
||||
}
|
||||
}
|
||||
|
||||
player->state = Player::Quit;
|
||||
player->internalState = Player::Quit;
|
||||
|
||||
for (Listener* l : player->Listeners()) {
|
||||
player->streamState = StreamStopped;
|
||||
l->OnPlayerDestroying(player);
|
||||
}
|
||||
|
||||
@ -471,7 +477,7 @@ void musik::core::audio::playerThreadLoop(Player* player) {
|
||||
|
||||
bool Player::Exited() {
|
||||
std::unique_lock<std::mutex> lock(this->queueMutex);
|
||||
return (this->state == Player::Quit);
|
||||
return (this->internalState == Player::Quit);
|
||||
}
|
||||
|
||||
static inline void initHammingWindow() {
|
||||
@ -587,6 +593,7 @@ void Player::OnBufferProcessed(IBuffer *buffer) {
|
||||
}
|
||||
|
||||
if (!this->notifiedStarted) {
|
||||
this->streamState = StreamPlaying;
|
||||
this->notifiedStarted = true;
|
||||
started = true;
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ namespace musik { namespace core { namespace audio {
|
||||
};
|
||||
|
||||
struct EventListener {
|
||||
virtual void OnPlayerPrepared(Player *player) { }
|
||||
virtual void OnPlayerBuffered(Player *player) { }
|
||||
virtual void OnPlayerStarted(Player *player) { }
|
||||
virtual void OnPlayerAlmostEnded(Player *player) { }
|
||||
virtual void OnPlayerFinished(Player *player) { }
|
||||
@ -102,6 +102,8 @@ namespace musik { namespace core { namespace audio {
|
||||
|
||||
std::string GetUrl() const { return this->url; }
|
||||
|
||||
musik::core::sdk::StreamState GetStreamState() { return this->streamState; }
|
||||
|
||||
private:
|
||||
friend void playerThreadLoop(Player* player);
|
||||
|
||||
@ -135,7 +137,7 @@ namespace musik { namespace core { namespace audio {
|
||||
Idle = 0,
|
||||
Playing = 1,
|
||||
Quit = 2
|
||||
} States;
|
||||
} InternalState;
|
||||
|
||||
bool Exited();
|
||||
int State();
|
||||
@ -162,7 +164,8 @@ namespace musik { namespace core { namespace audio {
|
||||
double nextMixPoint;
|
||||
std::atomic<double> currentPosition;
|
||||
std::atomic<double> seekToPosition;
|
||||
int state;
|
||||
std::atomic<musik::core::sdk::StreamState> streamState;
|
||||
std::atomic<int> internalState;
|
||||
bool notifiedStarted;
|
||||
float* spectrum;
|
||||
DestroyMode destroyMode;
|
||||
|
@ -1019,7 +1019,7 @@ class mcsdk_audio_player_callback_proxy: public Player::EventListener {
|
||||
public:
|
||||
std::set<mcsdk_audio_player_callbacks*> callbacks;
|
||||
mcsdk_player_context_internal* context;
|
||||
virtual void OnPlayerPrepared(Player *player) {
|
||||
virtual void OnPlayerBuffered(Player *player) {
|
||||
std::unique_lock<std::mutex> lock(this->context->event_mutex);
|
||||
for (auto c : callbacks) {
|
||||
if (c->on_prepared) {
|
||||
|
@ -47,9 +47,9 @@ namespace musik {
|
||||
PlaybackPlaying = 4,
|
||||
};
|
||||
|
||||
enum StreamEventType {
|
||||
StreamScheduled = 1,
|
||||
StreamPrepared = 2,
|
||||
enum StreamState {
|
||||
StreamBuffering = 1,
|
||||
StreamBuffered = 2,
|
||||
StreamPlaying = 3,
|
||||
StreamAlmostDone = 4,
|
||||
StreamFinished = 5,
|
||||
|
@ -51,8 +51,8 @@ using namespace musik::core::sdk;
|
||||
using namespace musik::cube;
|
||||
using namespace cursespp;
|
||||
|
||||
static inline size_t longestStringLength(const std::vector<std::string>&& keys) {
|
||||
size_t max = 0;
|
||||
static inline int longestStringLength(const std::vector<std::string>&& keys) {
|
||||
int max = 0;
|
||||
for (auto& str: keys) {
|
||||
size_t len = u8cols(_TSTR(str));
|
||||
max = len > max ? len : max;
|
||||
@ -71,7 +71,7 @@ RemoteLibrarySettingsLayout::~RemoteLibrarySettingsLayout() {
|
||||
}
|
||||
|
||||
void RemoteLibrarySettingsLayout::OnLayout() {
|
||||
size_t labelWidth = longestStringLength({
|
||||
const int labelWidth = longestStringLength({
|
||||
"settings_library_type_remote_hostname",
|
||||
"settings_library_type_remote_wss_port",
|
||||
"settings_library_type_remote_http_port",
|
||||
|
@ -56,17 +56,18 @@ namespace musik {
|
||||
static const int RequeryTrackList = First + 5;
|
||||
static const int RequeryCategoryList = First + 6;
|
||||
static const int RefreshTransport = First + 7;
|
||||
static const int RefreshLogs = First + 8;
|
||||
static const int UpdateCheckFinished = First + 9;
|
||||
static const int JumpToConsole = First + 10;
|
||||
static const int JumpToLibrary = First + 11;
|
||||
static const int JumpToSettings = First + 12;
|
||||
static const int JumpToLyrics = First + 13;
|
||||
static const int JumpToHotkeys = First + 14;
|
||||
static const int JumpToPlayQueue = First + 15;
|
||||
static const int SetLastFmState = First + 16;
|
||||
static const int UpdateEqualizer = First + 17;
|
||||
static const int DebugLog = First + 18;
|
||||
static const int TransportBuffering = First + 8;
|
||||
static const int RefreshLogs = First + 9;
|
||||
static const int UpdateCheckFinished = First + 10;
|
||||
static const int JumpToConsole = First + 11;
|
||||
static const int JumpToLibrary = First + 12;
|
||||
static const int JumpToSettings = First + 13;
|
||||
static const int JumpToLyrics = First + 14;
|
||||
static const int JumpToHotkeys = First + 15;
|
||||
static const int JumpToPlayQueue = First + 16;
|
||||
static const int SetLastFmState = First + 17;
|
||||
static const int UpdateEqualizer = First + 18;
|
||||
static const int DebugLog = First + 19;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -133,6 +133,8 @@ void tokenize(const std::string& format, TokenList& tokens) {
|
||||
/* a cache of localized, pre-formatted strings we use every second. */
|
||||
static struct StringCache {
|
||||
std::string PLAYING_FORMAT;
|
||||
std::string PLAYING;
|
||||
std::string BUFFERING;
|
||||
std::string STOPPED;
|
||||
std::string EMPTY_SONG;
|
||||
std::string EMPTY_ALBUM;
|
||||
@ -146,6 +148,8 @@ static struct StringCache {
|
||||
|
||||
void Initialize() {
|
||||
PLAYING_FORMAT = _TSTR("transport_playing_format");
|
||||
PLAYING = _TSTR("transport_playing_format_playing");
|
||||
BUFFERING = _TSTR("transport_playing_format_buffering");
|
||||
STOPPED = _TSTR("transport_stopped");
|
||||
EMPTY_SONG = _TSTR("transport_empty_song");
|
||||
EMPTY_ALBUM = _TSTR("transport_empty_album");
|
||||
@ -248,6 +252,7 @@ utf8 characters and ellipsizing */
|
||||
static size_t writePlayingFormat(
|
||||
WINDOW *w,
|
||||
TransportDisplayCache& displayCache,
|
||||
bool buffering,
|
||||
size_t width)
|
||||
{
|
||||
TokenList tokens;
|
||||
@ -255,6 +260,7 @@ static size_t writePlayingFormat(
|
||||
|
||||
Color dim = Color::TextDisabled;
|
||||
Color gb = Color::TextActive;
|
||||
Color warn = Color::TextWarning;
|
||||
size_t remaining = width;
|
||||
|
||||
auto it = tokens.begin();
|
||||
@ -263,19 +269,30 @@ static size_t writePlayingFormat(
|
||||
|
||||
Color attr = dim;
|
||||
std::string value;
|
||||
size_t cols;
|
||||
size_t cols = 0;
|
||||
|
||||
if (token->type == Token::Placeholder) {
|
||||
attr = gb;
|
||||
if (token->value == "$state") {
|
||||
if (buffering) {
|
||||
attr = warn;
|
||||
value = Strings.BUFFERING;
|
||||
}
|
||||
else {
|
||||
value = Strings.PLAYING;
|
||||
}
|
||||
}
|
||||
if (token->value == "$title") {
|
||||
attr = gb;
|
||||
value = displayCache.title;
|
||||
cols = displayCache.titleCols;
|
||||
}
|
||||
else if (token->value == "$album") {
|
||||
attr = gb;
|
||||
value = displayCache.album;
|
||||
cols = displayCache.albumCols;
|
||||
}
|
||||
else if (token->value == "$artist") {
|
||||
attr = gb;
|
||||
value = displayCache.artist;
|
||||
cols = displayCache.artistCols;
|
||||
}
|
||||
@ -349,6 +366,7 @@ TransportWindow::TransportWindow(
|
||||
this->playback.Shuffled.connect(this, &TransportWindow::OnPlaybackShuffled);
|
||||
this->playback.VolumeChanged.connect(this, &TransportWindow::OnTransportVolumeChanged);
|
||||
this->playback.TimeChanged.connect(this, &TransportWindow::OnTransportTimeChanged);
|
||||
this->playback.StreamStateChanged.connect(this, &TransportWindow::OnPlaybackStreamStateChanged);
|
||||
this->paused = false;
|
||||
this->lastTime = DEFAULT_TIME;
|
||||
this->shufflePos.y = 0;
|
||||
@ -478,7 +496,7 @@ void TransportWindow::OnFocusChanged(bool focused) {
|
||||
}
|
||||
|
||||
void TransportWindow::ProcessMessage(IMessage &message) {
|
||||
int type = message.Type();
|
||||
const int type = message.Type();
|
||||
|
||||
if (type == message::RefreshTransport) {
|
||||
this->Update((TimeMode) message.UserData1());
|
||||
@ -487,6 +505,10 @@ void TransportWindow::ProcessMessage(IMessage &message) {
|
||||
DEBOUNCE_REFRESH(TimeSmooth, REFRESH_INTERVAL_MS)
|
||||
}
|
||||
}
|
||||
else if (type == message::TransportBuffering) {
|
||||
this->buffering = true;
|
||||
this->Update();
|
||||
}
|
||||
}
|
||||
|
||||
void TransportWindow::OnPlaybackServiceTrackChanged(size_t index, TrackPtr track) {
|
||||
@ -496,6 +518,17 @@ void TransportWindow::OnPlaybackServiceTrackChanged(size_t index, TrackPtr track
|
||||
DEBOUNCE_REFRESH(TimeSync, 0);
|
||||
}
|
||||
|
||||
void TransportWindow::OnPlaybackStreamStateChanged(StreamState state) {
|
||||
if (state == StreamBuffering) {
|
||||
this->Debounce(message::TransportBuffering, 0, 0, 250);
|
||||
}
|
||||
else {
|
||||
this->Remove(message::TransportBuffering);
|
||||
this->buffering = false;
|
||||
this->Update();
|
||||
}
|
||||
}
|
||||
|
||||
void TransportWindow::OnPlaybackModeChanged() {
|
||||
DEBOUNCE_REFRESH(TimeSync, 0);
|
||||
}
|
||||
@ -587,7 +620,7 @@ void TransportWindow::Update(TimeMode timeMode) {
|
||||
}
|
||||
else {
|
||||
displayCache->Update(transport, this->currentTrack);
|
||||
writePlayingFormat(c, *this->displayCache, cx - shuffleWidth);
|
||||
writePlayingFormat(c, *this->displayCache, this->buffering, cx - shuffleWidth);
|
||||
}
|
||||
|
||||
/* draw the "shuffle" label */
|
||||
|
@ -116,6 +116,7 @@ namespace musik {
|
||||
|
||||
void OnPlaybackServiceTrackChanged(size_t index, musik::core::TrackPtr track);
|
||||
void OnPlaybackModeChanged();
|
||||
void OnPlaybackStreamStateChanged(musik::core::sdk::StreamState);
|
||||
void OnTransportVolumeChanged();
|
||||
void OnTransportTimeChanged(double time);
|
||||
void OnPlaybackShuffled(bool shuffled);
|
||||
@ -131,6 +132,7 @@ namespace musik {
|
||||
musik::core::TrackPtr currentTrack;
|
||||
FocusTarget focus, lastFocus;
|
||||
std::unique_ptr<TransportDisplayCache> displayCache;
|
||||
bool buffering{ false };
|
||||
double lastTime;
|
||||
};
|
||||
}
|
||||
|
@ -193,7 +193,9 @@
|
||||
"shortcuts_tracks": "tracks",
|
||||
"shortcuts_play_queue": "play queue",
|
||||
|
||||
"transport_playing_format": "playing $title by $artist from $album",
|
||||
"transport_playing_format": "$state $title by $artist from $album",
|
||||
"transport_playing_format_playing": "playing",
|
||||
"transport_playing_format_buffering": "buffering",
|
||||
"transport_stopped": "playback is stopped",
|
||||
"transport_empty_song": "[song]",
|
||||
"transport_empty_album": "[album]",
|
||||
|
Loading…
x
Reference in New Issue
Block a user