Merge branch 'master' of github.com:clangen/musikcube

This commit is contained in:
casey langen 2022-04-28 12:34:45 -07:00
commit daaa7c268f
21 changed files with 112 additions and 41 deletions

View File

@ -102,6 +102,10 @@ namespace musik {
}
}
void Shutdown() {
HideSelectedVisualizer();
}
ISpectrumVisualizer* SpectrumVisualizer() {
return spectrumVisualizer;
}

View File

@ -48,5 +48,6 @@ namespace musik { namespace core { namespace audio { namespace vis {
void SetSelectedVisualizer(std::shared_ptr<musik::core::sdk::IVisualizer> visualizer);
std::shared_ptr<musik::core::sdk::IVisualizer> SelectedVisualizer();
void HideSelectedVisualizer();
void Shutdown();
} } } }

View File

@ -158,7 +158,7 @@ mcsdk_export void mcsdk_env_init() {
mcsdk_export void mcsdk_env_release() {
if (environment_initialized) {
LibraryFactory::Instance().Shutdown();
debug::Stop();
debug::Shutdown();
message_queue->Quit();
message_queue_thread.join();
delete message_queue;
@ -227,7 +227,7 @@ mcsdk_export void mcsdk_context_release(mcsdk_context** context) {
delete internal->playback;
internal->playback = nullptr;
internal->library->Indexer()->Stop();
internal->library->Indexer()->Shutdown();
internal->library.reset();
internal->preferences.reset();
@ -250,7 +250,7 @@ mcsdk_export void mcsdk_context_release(mcsdk_context** context) {
mcsdk_export void mcsdk_set_plugin_context(mcsdk_context* context) {
if (plugin_context && plugin_context != context) {
plugin::Deinit();
plugin::Shutdown();
}
plugin_context = context;
if (plugin_context) {

View File

@ -1243,7 +1243,7 @@ mcsdk_export void mcsdk_svc_indexer_schedule(mcsdk_svc_indexer in, mcsdk_svc_ind
}
mcsdk_export void mcsdk_svc_indexer_stop(mcsdk_svc_indexer in) {
INDEXER(in)->Stop();
INDEXER(in)->Shutdown();
}
mcsdk_export mcsdk_svc_indexer_state mcsdk_svc_indexer_get_state(mcsdk_svc_indexer in) {

View File

@ -182,7 +182,7 @@ void musik::debug::Start(std::vector<musik::debug::IBackend*> backends) {
info("LOG SESSION", "---------- START ----------");
}
void musik::debug::Stop() {
void musik::debug::Shutdown() {
std::unique_lock<std::recursive_mutex> lock(mutex);
cancel = true;

View File

@ -83,7 +83,7 @@ namespace musik {
};
static void Start(std::vector<IBackend*> backends = { new SimpleFileBackend() });
static void Stop();
static void Shutdown();
static void verbose(const std::string& tag, const std::string& string) noexcept;
static void v(const std::string& tag, const std::string& string) noexcept;

View File

@ -64,7 +64,7 @@ namespace musik { namespace core {
virtual void RemovePath(const std::string& path) = 0;
virtual void GetPaths(std::vector<std::string>& paths) = 0;
virtual void Schedule(SyncType type) = 0;
virtual void Stop() = 0;
virtual void Shutdown() = 0;
virtual State GetState() = 0;
};
} }

View File

@ -140,10 +140,10 @@ Indexer::Indexer(const std::string& libraryPath, const std::string& dbFilename)
Indexer::~Indexer() {
closeLogFile();
this->Stop();
this->Shutdown();
}
void Indexer::Stop() {
void Indexer::Shutdown() {
if (this->thread) {
{
boost::mutex::scoped_lock lock(this->stateMutex);

View File

@ -80,7 +80,7 @@ namespace musik { namespace core {
void RemovePath(const std::string& path) override;
void GetPaths(std::vector<std::string>& paths) override;
void Schedule(SyncType type) override;
void Stop() override;
void Shutdown() override;
State GetState() noexcept override {
return this->state;

View File

@ -72,7 +72,7 @@ class NullIndexer: public musik::core::IIndexer {
void RemovePath(const std::string& path) noexcept override { }
void GetPaths(std::vector<std::string>& paths) noexcept override { }
void Schedule(SyncType type) noexcept override { }
void Stop() noexcept override { }
void Shutdown() noexcept override { }
State GetState() noexcept override { return StateIdle; }
} kNullIndexer;

View File

@ -49,6 +49,10 @@ using ClientPtr = PiggyWebSocketClient::ClientPtr;
using ClientMessage = PiggyWebSocketClient::ClientMessage;
using Connection = PiggyWebSocketClient::Connection;
using Message = PiggyWebSocketClient::Message;
using MessageQueue = PiggyWebSocketClient::MessageQueue;
std::recursive_mutex instanceMutex;
static std::shared_ptr<PiggyWebSocketClient> instance;
static const int64_t kLatencyTimeoutMs = INT_MAX;
static const int64_t kReconnectIntervalMs = 10000;
@ -60,7 +64,21 @@ static inline std::string generateSessionId() {
return "musikcube-" + std::to_string((unsigned long) time(nullptr));
}
PiggyWebSocketClient::PiggyWebSocketClient(IMessageQueue* messageQueue)
std::shared_ptr<PiggyWebSocketClient> PiggyWebSocketClient::Instance(MessageQueue* messageQueue) {
std::unique_lock<decltype(instanceMutex)> lock(instanceMutex);
if (!instance) {
instance = std::shared_ptr<PiggyWebSocketClient>(new PiggyWebSocketClient(messageQueue));
}
instance->SetMessageQueue(messageQueue);
return instance;
}
void PiggyWebSocketClient::Shutdown() {
std::unique_lock<decltype(instanceMutex)> lock(instanceMutex);
instance.reset();
}
PiggyWebSocketClient::PiggyWebSocketClient(MessageQueue* messageQueue)
: messageQueue(nullptr)
, sessionId(generateSessionId()) {
this->SetMessageQueue(messageQueue);
@ -157,7 +175,11 @@ void PiggyWebSocketClient::Connect(const std::string& host, unsigned short port,
void PiggyWebSocketClient::Reconnect() {
std::unique_lock<decltype(this->mutex)> lock(this->mutex);
/* Disconnect() will reset the internal URI to implicitly disable auto-reconnect;
go ahead and cache it, disconnect, then restore it. */
auto originalUri = this->uri;
this->Disconnect();
this->uri = originalUri;
#if BOOST_VERSION < 106600
io.reset();
@ -195,6 +217,7 @@ void PiggyWebSocketClient::Disconnect() {
{
std::unique_lock<decltype(this->mutex)> lock(this->mutex);
oldThread = std::unique_ptr<std::thread>(std::move(this->thread));
this->uri = "";
}
if (oldThread) {
@ -235,7 +258,8 @@ void PiggyWebSocketClient::SetState(State state) {
}
}
void PiggyWebSocketClient::SetMessageQueue(IMessageQueue* messageQueue) {
void PiggyWebSocketClient::SetMessageQueue(MessageQueue* messageQueue) {
std::unique_lock<decltype(this->mutex)> lock(this->mutex);
if (messageQueue == this->messageQueue) {
return;
}
@ -253,7 +277,7 @@ void PiggyWebSocketClient::SetMessageQueue(IMessageQueue* messageQueue) {
void PiggyWebSocketClient::ProcessMessage(IMessage& message) {
if (message.Type() == kReconnectMessage) {
std::unique_lock<decltype(this->mutex)> lock(this->mutex);
if (this->state == State::Disconnected) {
if (this->state == State::Disconnected && this->uri.length()) {
this->Reconnect();
}
this->messageQueue->Post(runtime::Message::Create(this, kReconnectMessage), kReconnectIntervalMs);

View File

@ -57,6 +57,7 @@ namespace musik { namespace core { namespace net {
using ClientMessage = websocketpp::config::asio_client::message_type::ptr;
using Connection = websocketpp::connection_hdl;
using Message = std::shared_ptr<nlohmann::json>;
using MessageQueue = musik::core::runtime::IMessageQueue;
enum class State: int {
Disconnected = 0,
@ -73,7 +74,9 @@ namespace musik { namespace core { namespace net {
sigslot::signal3<PiggyWebSocketClient*, State, State> StateChanged;
PiggyWebSocketClient(musik::core::runtime::IMessageQueue* messageQueue);
static std::shared_ptr<PiggyWebSocketClient> Instance(MessageQueue* messageQueue);
static void Shutdown();
PiggyWebSocketClient(const PiggyWebSocketClient&) = delete;
virtual ~PiggyWebSocketClient();
@ -87,9 +90,12 @@ namespace musik { namespace core { namespace net {
ConnectionError LastConnectionError() const;
std::string Uri() const;
void SetMessageQueue(musik::core::runtime::IMessageQueue* messageQueue);
void SetMessageQueue(MessageQueue* messageQueue);
void ProcessMessage(musik::core::runtime::IMessage& message) override;
protected:
PiggyWebSocketClient(MessageQueue* messageQueue);
private:
void SetState(State state);
void SetDisconnected(ConnectionError errorCode);
@ -107,7 +113,7 @@ namespace musik { namespace core { namespace net {
std::atomic<bool> quit{ false };
ConnectionError connectionError{ ConnectionError::None };
State state{ State::Disconnected };
musik::core::runtime::IMessageQueue* messageQueue;
MessageQueue* messageQueue;
};
} } }

View File

@ -412,7 +412,7 @@ namespace musik { namespace core { namespace plugin {
return environment;
}
void Deinit() {
void Shutdown() {
/* preferences */
Preferences::SavePluginPreferences();

View File

@ -50,6 +50,6 @@ namespace musik { namespace core { namespace plugin {
musik::core::sdk::IEnvironment& Environment();
void Deinit();
void Shutdown();
} } }

View File

@ -125,7 +125,7 @@ int main(int argc, char* argv[]) {
};
if (prefs->GetBool(core::prefs::keys::PiggyEnabled, false)) {
auto piggyClient = std::make_shared<PiggyWebSocketClient>(&Window::MessageQueue());
auto piggyClient = PiggyWebSocketClient::Instance(&Window::MessageQueue());
piggyClient->Connect(prefs->GetString(core::prefs::keys::PiggyHostname, "localhost"));
debuggerBackends.push_back(new PiggyDebugBackend(piggyClient));
}
@ -226,21 +226,20 @@ int main(int argc, char* argv[]) {
app.Run(mainLayout);
/* done with the app */
mainLayout->Stop();
mainLayout->Shutdown();
#ifdef WIN32
win32::HideMainWindow();
#endif
library->Indexer()->Stop();
library->Indexer()->Shutdown();
}
audio::vis::HideSelectedVisualizer();
plugin::Deinit();
PiggyWebSocketClient::Shutdown();
LibraryFactory::Instance().Shutdown();
debug::Stop();
vis::Shutdown();
plugin::Shutdown();
debug::Shutdown();
return 0;
}

View File

@ -212,7 +212,7 @@ void MainLayout::Start() {
MessageQueue().RegisterForBroadcasts(this->shared_from_this());
}
void MainLayout::Stop() {
void MainLayout::Shutdown() {
MessageQueue().UnregisterForBroadcasts(this);
}

View File

@ -43,6 +43,7 @@
#include <musikcore/support/Preferences.h>
#include <musikcore/runtime/IMessageTarget.h>
#include <musikcore/library/MasterLibrary.h>
#include <musikcore/net/PiggyWebSocketClient.h>
#include <app/util/ConsoleLogger.h>
#include <app/util/UpdateCheck.h>
@ -66,7 +67,7 @@ namespace musik {
virtual ~MainLayout();
void Start();
void Stop();
void Shutdown();
/* IWindow */
bool KeyPress(const std::string& key) override;

View File

@ -70,6 +70,7 @@ using namespace musik::core;
using namespace musik::core::audio;
using namespace musik::core::library::constants;
using namespace musik::core::sdk;
using namespace musik::core::net;
using namespace musik::cube;
using namespace cursespp;
@ -165,6 +166,8 @@ SettingsLayout::SettingsLayout(
, indexer(library->Indexer())
, playback(playback) {
this->prefs = Preferences::ForComponent(core::prefs::components::Settings);
this->piggyClient = PiggyWebSocketClient::Instance(&MessageQueue());
this->piggyClient->StateChanged.connect(this, &SettingsLayout::OnPiggyClientStateChange);
this->UpdateServerAvailability();
this->InitializeWindows();
}
@ -173,6 +176,18 @@ SettingsLayout::~SettingsLayout() {
updateCheck.Cancel();
}
void SettingsLayout::OnPiggyClientStateChange(
PiggyWebSocketClient* client,
PiggyWebSocketClient::State newState,
PiggyWebSocketClient::State oldState)
{
/* trigger a redraw on the main thread */
using State = PiggyWebSocketClient::State;
if (newState == State::Connected || newState == State::Disconnected) {
this->Post(core::message::EnvironmentUpdated);
}
}
void SettingsLayout::OnCheckboxChanged(cursespp::Checkbox* cb, bool checked) {
if (cb == syncOnStartupCheckbox.get()) {
this->prefs->SetBool(core::prefs::keys::SyncOnStartup, checked);
@ -451,8 +466,6 @@ void SettingsLayout::InitializeWindows() {
this->appVersion = std::make_shared<TextLabel>();
this->appVersion->SetContentColor(Color::TextDisabled);
this->appVersion->SetAlignment(text::AlignCenter);
std::string version = u8fmt("%s %s", VERSION, VERSION_COMMIT_HASH);
this->appVersion->SetText(u8fmt(_TSTR("console_version"), version.c_str()));
int order = 0;
this->libraryTypeDropdown->SetFocusOrder(order++);
@ -639,9 +652,23 @@ void SettingsLayout::LoadPreferences() {
this->localLibraryLayout->LoadPreferences();
this->remoteLibraryLayout->LoadPreferences();
/* version, status */
std::string piggyStatus = "";
if (this->piggyAvailable) {
if (this->piggyClient->ConnectionState() == PiggyWebSocketClient::State::Connected) {
piggyStatus = " (oo)";
}
else {
piggyStatus = " (..)";
}
}
std::string version = u8fmt("%s %s%s", VERSION, VERSION_COMMIT_HASH, piggyStatus.c_str());
this->appVersion->SetText(u8fmt(_TSTR("console_version"), version.c_str()));
this->Layout();
}
void SettingsLayout::UpdateServerAvailability() {
this->serverAvailable = !!ServerOverlay::FindServerPlugin().get();
this->piggyAvailable = this->prefs->GetBool(core::prefs::keys::PiggyEnabled, false);
}

View File

@ -49,6 +49,7 @@
#include <musikcore/audio/PlaybackService.h>
#include <musikcore/audio/MasterTransport.h>
#include <musikcore/library/MasterLibrary.h>
#include <musikcore/net/PiggyWebSocketClient.h>
#include <musikcore/support/Preferences.h>
#include <app/window/TrackListView.h>
@ -68,6 +69,7 @@ namespace musik { namespace cube {
{
public:
using MasterLibraryPtr = std::shared_ptr<musik::core::library::MasterLibrary>;
using PiggyWebSocketClient = musik::core::net::PiggyWebSocketClient;
DELETE_COPY_AND_ASSIGNMENT_DEFAULTS(SettingsLayout)
@ -110,6 +112,11 @@ namespace musik { namespace cube {
void OnLastFmDropdownActivate(cursespp::TextLabel* label);
void OnAdvancedSettingsActivate(cursespp::TextLabel* label);
void OnPiggyClientStateChange(
PiggyWebSocketClient* client,
PiggyWebSocketClient::State newState,
PiggyWebSocketClient::State oldState);
cursespp::App& app;
MasterLibraryPtr library;
musik::core::IIndexer* indexer;
@ -143,8 +150,10 @@ namespace musik { namespace cube {
std::shared_ptr<LocalLibrarySettingsLayout> localLibraryLayout;
std::shared_ptr<RemoteLibrarySettingsLayout> remoteLibraryLayout;
std::shared_ptr<PiggyWebSocketClient> piggyClient;
UpdateCheck updateCheck;
bool serverAvailable = false;
bool piggyAvailable = false;
};
} }

View File

@ -298,10 +298,10 @@ int main(int argc, char** argv) {
messageQueue.Run();
library->Indexer()->Stop();
library->Indexer()->Shutdown();
}
plugin::Deinit();
plugin::Shutdown();
remove(getLockfileFn().c_str());
}

View File

@ -460,7 +460,7 @@ void TaglibMetadataReader::ReadBasicData(const T* tag, const char* uri, ITagStor
}
this->SetTagValue("album", tag->album(), target);
this->SetSlashSeparatedValues("artist", tag->artist(), target);
this->SetTagValue("artist", tag->artist(), target);
this->SetTagValue("genre", tag->genre(), target);
this->SetTagValue("comment", tag->comment(), target);
@ -638,7 +638,7 @@ bool TaglibMetadataReader::ReadID3V2(TagLib::ID3v2::Tag *id3v2, ITagStore *track
this->SetTagValues("org.writer", allTags["TOLY"], track);
this->SetSlashSeparatedValues("publisher", allTags["TPUB"], track);
this->SetTagValues("mood", allTags["TMOO"], track);
this->SetSlashSeparatedValues("org.artist", allTags["TOPE"], track);
this->SetTagValues("org.artist", allTags["TOPE"], track);
this->SetTagValues("language", allTags["TLAN"], track);
this->SetTagValues("lyrics", allTags["USLT"], track);
this->SetTagValues("disc", allTags["TPOS"], track);
@ -696,8 +696,8 @@ bool TaglibMetadataReader::ReadID3V2(TagLib::ID3v2::Tag *id3v2, ITagStore *track
/* artists */
this->SetSlashSeparatedValues("artist", allTags["TPE1"], track);
this->SetSlashSeparatedValues("album_artist", allTags["TPE2"], track);
this->SetTagValues("artist", allTags["TPE1"], track);
this->SetTagValues("album_artist", allTags["TPE2"], track);
this->SetSlashSeparatedValues("conductor", allTags["TPE3"], track);
this->SetSlashSeparatedValues("interpreted", allTags["TPE4"], track);
@ -707,7 +707,7 @@ bool TaglibMetadataReader::ReadID3V2(TagLib::ID3v2::Tag *id3v2, ITagStore *track
TagLib::ID3v2::FrameList::Iterator it = comments.begin();
for (; it != comments.end(); ++it) {
TagLib::ID3v2::CommentsFrame *comment
const TagLib::ID3v2::CommentsFrame *comment
= dynamic_cast<TagLib::ID3v2::CommentsFrame*> (*it);
TagLib::String temp = comment->description();
@ -738,7 +738,7 @@ bool TaglibMetadataReader::ReadID3V2(TagLib::ID3v2::Tag *id3v2, ITagStore *track
static_cast<TagLib::ID3v2::AttachedPictureFrame*>(pictures.front());
TagLib::ByteVector pictureData = picture->picture();
long long size = pictureData.size();
const long long size = pictureData.size();
if (size > 32) { /* noticed that some id3tags have like a 4-8 byte size with no thumbnail */
track->SetThumbnail(pictureData.data(), size);
@ -800,7 +800,7 @@ void TaglibMetadataReader::SetTagValues(
void TaglibMetadataReader::SetSlashSeparatedValues(
const char* key, TagLib::String tagString, ITagStore *track)
{
if(!tagString.isEmpty()) {
if (!tagString.isEmpty()) {
std::string value(tagString.to8Bit(true));
std::vector<std::string> splitValues = str::split(value, "/");
std::vector<std::string>::iterator it = splitValues.begin();
@ -815,7 +815,7 @@ void TaglibMetadataReader::SetSlashSeparatedValues(
const TagLib::ID3v2::FrameList &frame,
ITagStore *track)
{
if(!frame.isEmpty()) {
if (!frame.isEmpty()) {
TagLib::ID3v2::FrameList::ConstIterator value = frame.begin();
for ( ; value != frame.end(); ++value) {
TagLib::String tagString = (*value)->toString();