1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2004-2021 musikcube team
4 //
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 //
10 //    * Redistributions of source code must retain the above copyright notice,
11 //      this list of conditions and the following disclaimer.
12 //
13 //    * Redistributions in binary form must reproduce the above copyright
14 //      notice, this list of conditions and the following disclaimer in the
15 //      documentation and/or other materials provided with the distribution.
16 //
17 //    * Neither the name of the author nor the names of other contributors may
18 //      be used to endorse or promote products derived from this software
19 //      without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 // POSSIBILITY OF SUCH DAMAGE.
32 //
33 //////////////////////////////////////////////////////////////////////////////
34 
35 #include "pch.hpp"
36 #include "Plugins.h"
37 #include "PluginFactory.h"
38 
39 #include <musikcore/debug.h>
40 #include <musikcore/version.h>
41 #include <musikcore/support/Common.h>
42 #include <musikcore/support/Preferences.h>
43 #include <musikcore/io/DataStreamFactory.h>
44 #include <musikcore/audio/Buffer.h>
45 #include <musikcore/audio/Streams.h>
46 #include <musikcore/audio/Outputs.h>
47 #include <musikcore/support/Preferences.h>
48 #include <musikcore/support/PreferenceKeys.h>
49 #include <musikcore/library/LocalMetadataProxy.h>
50 #include <musikcore/library/LibraryFactory.h>
51 #include <musikcore/runtime/Message.h>
52 #include <musikcore/support/Messages.h>
53 
54 #include <musikcore/sdk/IDebug.h>
55 #include <musikcore/sdk/IIndexerNotifier.h>
56 #include <musikcore/sdk/IEnvironment.h>
57 
58 using namespace musik;
59 using namespace musik::core;
60 using namespace musik::core::audio;
61 using namespace musik::core::library::query;
62 using namespace musik::core::io;
63 using namespace musik::core::runtime;
64 using namespace musik::core::sdk;
65 
66 typedef void(*SetEnvironment)(IEnvironment*);
67 typedef void(*SetDebug)(IDebug*);
68 typedef void(*SetMetadataProxy)(IMetadataProxy*);
69 typedef void(*SetIndexerNotifier)(IIndexerNotifier*);
70 
71 static const std::string SUPEREQ_PLUGIN_GUID = "6f0ed53b-0f13-4220-9b0a-ca496b6421cc";
72 
73 static IMessageQueue* messageQueue = nullptr;
74 static ILibraryPtr defaultLibrary;
75 static IPlaybackService* playbackService = nullptr;
76 static LocalMetadataProxy* metadataProxy = nullptr;
77 static std::shared_ptr<Preferences> playbackPrefs;
78 
saveEnvironment()79 static void saveEnvironment() {
80     if (::playbackPrefs) {
81         ::playbackPrefs->Save();
82     }
83     if (::messageQueue) {
84         ::messageQueue->Broadcast(
85             Message::Create(nullptr, message::EnvironmentUpdated));
86     }
87 }
88 
broadcastEqualizerUpdated()89 static void broadcastEqualizerUpdated() {
90     if (::messageQueue) {
91         ::messageQueue->Broadcast(
92             Message::Create(nullptr, message::EqualizerUpdated));
93     }
94 }
95 
getEqualizerPluginAndPrefs(std::shared_ptr<IPlugin> & plugin,std::shared_ptr<Preferences> & prefs)96 static void getEqualizerPluginAndPrefs(
97     std::shared_ptr<IPlugin>& plugin,
98     std::shared_ptr<Preferences>& prefs)
99 {
100     plugin = PluginFactory::Instance().QueryGuid(SUPEREQ_PLUGIN_GUID);
101 
102     if (plugin) {
103         prefs = Preferences::ForPlugin(plugin->Name());
104     }
105 }
106 
107 static class Debug: public IDebug {
108     public:
Verbose(const char * tag,const char * message)109         void Verbose(const char* tag, const char* message) override {
110             musik::debug::verbose(tag, message);
111         }
112 
Info(const char * tag,const char * message)113         void Info(const char* tag, const char* message) override {
114             musik::debug::info(tag, message);
115         }
116 
Warning(const char * tag,const char * message)117         void Warning(const char* tag, const char* message) override {
118             musik::debug::warning(tag, message);
119         }
120 
Error(const char * tag,const char * message)121         void Error(const char* tag, const char* message) override {
122             musik::debug::error(tag, message);
123         }
124 } debugger;
125 
126 static class NullDebug: public IDebug { /* used during shutdown */
127     public:
Verbose(const char * tag,const char * message)128         void Verbose(const char* tag, const char* message) override {}
Info(const char * tag,const char * message)129         void Info(const char* tag, const char* message) override {}
Warning(const char * tag,const char * message)130         void Warning(const char* tag, const char* message) override {}
Error(const char * tag,const char * message)131         void Error(const char* tag, const char* message) override {}
132 } nullDebugger;
133 
134 static class Environment: public IEnvironment {
135     public:
GetPath(PathType type,char * dst,int size)136         size_t GetPath(PathType type, char* dst, int size) override {
137             std::string path;
138             switch (type) {
139                 case PathType::UserHome: path = GetHomeDirectory(); break;
140                 case PathType::Data: path = GetDataDirectory(); break;
141                 case PathType::Application: path = GetApplicationDirectory(); break;
142                 case PathType::Plugins: path = GetPluginDirectory(); break;
143                 case PathType::Library: {
144                     if (defaultLibrary) {
145                         path = GetDataDirectory() + std::to_string(defaultLibrary->Id()) + "/";
146                     }
147                     break;
148                 }
149             }
150             return CopyString(path, dst, size);
151         }
152 
GetDataStream(const char * uri,OpenFlags flags)153         IDataStream* GetDataStream(const char* uri, OpenFlags flags) override {
154             return DataStreamFactory::OpenDataStream(uri, flags);
155         }
156 
GetDecoder(IDataStream * stream)157         IDecoder* GetDecoder(IDataStream* stream) override {
158             return streams::GetDecoderForDataStream(stream);
159         }
160 
GetEncoder(const char * type)161         IEncoder* GetEncoder(const char* type) override {
162             return streams::GetEncoderForType(type);
163         }
164 
GetDebug()165         IDebug* GetDebug() override {
166             return &debugger;
167         }
168 
GetPreferences(const char * name)169         IPreferences* GetPreferences(const char* name) override {
170             return Preferences::Unmanaged(name ? name : std::string());
171         }
172 
GetBuffer(size_t samples,size_t rate=44100,size_t channels=2)173         IBuffer* GetBuffer(size_t samples, size_t rate = 44100, size_t channels = 2) override {
174             musik::core::audio::Buffer* buffer = new Buffer();
175             buffer->SetChannels(2);
176             buffer->SetSampleRate((long) rate);
177             buffer->SetSamples((long) samples);
178             return buffer;
179         }
180 
GetOutputCount()181         size_t GetOutputCount() override {
182             return outputs::GetOutputCount();
183         }
184 
GetOutputAtIndex(size_t index)185         IOutput* GetOutputAtIndex(size_t index) override {
186             return outputs::GetUnmanagedOutput(index);
187         }
188 
GetOutputWithName(const char * name)189         IOutput* GetOutputWithName(const char* name) override {
190             return outputs::GetUnmanagedOutput(name ? name : "");
191         }
192 
SetDefaultOutput(IOutput * output)193         void SetDefaultOutput(IOutput* output) override {
194             if (output) {
195                 auto current = outputs::SelectedOutput();
196                 std::string newName = output->Name();
197                 std::string currentName = current ? current->Name() : "";
198                 auto newDevice = output->GetDefaultDevice();
199                 auto currentDevice = current->GetDefaultDevice();
200                 std::string newDeviceId = newDevice ? newDevice->Id() : "";
201                 std::string currentDeviceId = currentDevice ? currentDevice->Id() : "";
202                 if (newName != currentName || newDeviceId != currentDeviceId) {
203                     outputs::SelectOutput(output);
204                     if (::playbackService) {
205                         playbackService->ReloadOutput();
206                     }
207                 }
208                 saveEnvironment();
209             }
210         }
211 
GetTransportType()212         TransportType GetTransportType() override {
213             if (::playbackPrefs) {
214                 return (TransportType) ::playbackPrefs->GetInt(
215                     prefs::keys::Transport.c_str(), (int) TransportType::Gapless);
216             }
217             return TransportType::Gapless;
218         }
219 
SetTransportType(TransportType type)220         void SetTransportType(TransportType type) override {
221             if (::playbackPrefs) {
222                 auto currentType = GetTransportType();
223                 if (currentType != type) {
224                     ::playbackPrefs->SetInt(prefs::keys::Transport.c_str(), (int) type);
225                     if (::playbackService) {
226                         ::playbackService->ReloadOutput();
227                     }
228                     saveEnvironment();
229                 }
230             }
231         }
232 
GetDefaultOutput()233         IOutput* GetDefaultOutput() override {
234             return outputs::GetUnmanagedSelectedOutput();
235         }
236 
ReindexMetadata()237         void ReindexMetadata() override {
238             if (::defaultLibrary) {
239                 ::defaultLibrary->Indexer()->Schedule(IIndexer::SyncType::Local);
240             }
241         }
242 
RebuildMetadata()243         void RebuildMetadata() override {
244             if (::defaultLibrary) {
245                 ::defaultLibrary->Indexer()->Schedule(IIndexer::SyncType::Rebuild);
246             }
247         }
248 
GetReplayGainMode()249         ReplayGainMode GetReplayGainMode() override {
250             if (::playbackPrefs) {
251                 return (ReplayGainMode) ::playbackPrefs->GetInt(
252                     prefs::keys::ReplayGainMode.c_str(),
253                     (int) ReplayGainMode::Disabled);
254             }
255             return ReplayGainMode::Disabled;
256         }
257 
SetReplayGainMode(ReplayGainMode mode)258         void SetReplayGainMode(ReplayGainMode mode) override {
259             if (::playbackPrefs) {
260                 ::playbackPrefs->SetInt(prefs::keys::ReplayGainMode.c_str(), (int) mode);
261                 saveEnvironment();
262             }
263         }
264 
GetPreampGain()265         float GetPreampGain() override {
266             if (::playbackPrefs) {
267                 return (float) ::playbackPrefs->GetDouble(
268                     prefs::keys::PreampDecibels.c_str(), 0.0f);
269             }
270             return 1.0f;
271         }
272 
SetPreampGain(float gain)273         void SetPreampGain(float gain) override {
274             if (::playbackPrefs) {
275                 if (gain > 20.0f) { gain = 20.0f; }
276                 if (gain < -20.0f) { gain = -20.0f; }
277                 ::playbackPrefs->SetDouble(prefs::keys::PreampDecibels.c_str(), gain);
278                 saveEnvironment();
279             }
280         }
281 
GetEqualizerBandValues(double target[],size_t count)282         bool GetEqualizerBandValues(double target[], size_t count) override {
283             if (count != EqualizerBandCount) {
284                 return false;
285             }
286 
287             std::shared_ptr<IPlugin> plugin;
288             std::shared_ptr<Preferences> prefs;
289             getEqualizerPluginAndPrefs(plugin, prefs);
290 
291             if (plugin && prefs) {
292                 for (size_t i = 0; i < EqualizerBandCount; i++) {
293                     target[i] = prefs->GetDouble(std::to_string(EqualizerBands[i]), 0.0);
294                 }
295 
296                 return true;
297             }
298 
299             return false;
300         }
301 
SetEqualizerBandValues(double values[],size_t count)302         bool SetEqualizerBandValues(double values[], size_t count) override {
303             if (count != EqualizerBandCount) {
304                 return false;
305             }
306 
307             std::shared_ptr<IPlugin> plugin;
308             std::shared_ptr<Preferences> prefs;
309             getEqualizerPluginAndPrefs(plugin, prefs);
310 
311             if (plugin && prefs) {
312                 for (size_t i = 0; i < EqualizerBandCount; i++) {
313                     prefs->SetDouble(std::to_string(EqualizerBands[i]), values[i]);
314                 }
315                 plugin->Reload();
316                 broadcastEqualizerUpdated();
317                 return true;
318             }
319 
320             return false;
321         }
322 
GetEqualizerEnabled()323         bool GetEqualizerEnabled() override {
324             std::shared_ptr<IPlugin> plugin;
325             std::shared_ptr<Preferences> prefs;
326             getEqualizerPluginAndPrefs(plugin, prefs);
327 
328             if (plugin && prefs) {
329                 return prefs->GetBool("enabled", false);
330             }
331 
332             return false;
333         }
334 
SetEqualizerEnabled(bool enabled)335         void SetEqualizerEnabled(bool enabled) override {
336             std::shared_ptr<IPlugin> plugin;
337             std::shared_ptr<Preferences> prefs;
338             getEqualizerPluginAndPrefs(plugin, prefs);
339 
340             if (plugin && prefs) {
341                 if (prefs->GetBool("enabled", false) != enabled) {
342                     prefs->SetBool("enabled", enabled);
343                     plugin->Reload();
344                     broadcastEqualizerUpdated();
345                 }
346             }
347         }
348 
ReloadPlaybackOutput()349         void ReloadPlaybackOutput() override {
350             if (playbackService) {
351                 playbackService->ReloadOutput();
352             }
353         }
354 
GetAppVersion()355         const char* GetAppVersion() override {
356             return VERSION;
357         }
358 
359 } environment;
360 
361 namespace musik { namespace core { namespace plugin {
362 
Init()363     void Init() {
364         /* preferences */
365         Preferences::LoadPluginPreferences();
366 
367         /* debug */
368         PluginFactory::Instance().QueryFunction<SetDebug>(
369             "SetDebug",
370             [](musik::core::sdk::IPlugin* plugin, SetDebug func) {
371             func(&debugger);
372         });
373     }
374 
Start(IMessageQueue * messageQueue,IPlaybackService * playbackService,ILibraryPtr library)375     void Start(IMessageQueue* messageQueue, IPlaybackService* playbackService, ILibraryPtr library) {
376         /* metadata proxies */
377         delete metadataProxy;
378         ::messageQueue = messageQueue;
379         ::defaultLibrary = library;
380         ::playbackService = playbackService;
381         ::playbackPrefs = Preferences::ForComponent(prefs::components::Playback);
382 
383         /* even if the local client is connected to a remote server, the metadata proxy
384         always uses the default local library. */
385         ::metadataProxy = new LocalMetadataProxy(LibraryFactory::Instance().DefaultLocalLibrary());
386 
387         PluginFactory::Instance().QueryFunction<SetMetadataProxy>(
388             "SetMetadataProxy",
389             [](musik::core::sdk::IPlugin* plugin, SetMetadataProxy func) {
390                 func(metadataProxy);
391             });
392 
393         /* indexer */
394         IIndexerNotifier* indexerNotifier =
395             dynamic_cast<IIndexerNotifier*>(library->Indexer());
396 
397         PluginFactory::Instance().QueryFunction<SetIndexerNotifier>(
398             "SetIndexerNotifier",
399             [indexerNotifier](musik::core::sdk::IPlugin* plugin, SetIndexerNotifier func) {
400                 func(indexerNotifier);
401             });
402 
403         /* environment */
404         PluginFactory::Instance().QueryFunction<SetEnvironment>(
405             "SetEnvironment",
406             [](musik::core::sdk::IPlugin* plugin, SetEnvironment func) {
407                 func(&environment);
408             });
409     }
410 
Environment()411     IEnvironment& Environment() {
412         return environment;
413     }
414 
Deinit()415     void Deinit() {
416         /* preferences */
417         Preferences::SavePluginPreferences();
418 
419         /* data providers */
420         PluginFactory::Instance().QueryFunction<SetMetadataProxy>(
421             "SetMetadataProxy",
422             [](musik::core::sdk::IPlugin* plugin, SetMetadataProxy func) {
423                 func(nullptr);
424             });
425 
426         delete metadataProxy;
427         ::messageQueue = nullptr;
428         ::metadataProxy = nullptr;
429         ::defaultLibrary.reset();
430         ::playbackService = nullptr;
431         ::playbackPrefs.reset();
432 
433         /* indexer */
434         PluginFactory::Instance().QueryFunction<SetIndexerNotifier>(
435             "SetIndexerNotifier",
436                 [](musik::core::sdk::IPlugin* plugin, SetIndexerNotifier func) {
437                 func(nullptr);
438             });
439 
440         /* environment */
441         PluginFactory::Instance().QueryFunction<SetEnvironment>(
442             "SetEnvironment",
443             [](musik::core::sdk::IPlugin* plugin, SetEnvironment func) {
444                 func(nullptr);
445             });
446 
447         /* debug */
448         PluginFactory::Instance().QueryFunction<SetDebug>(
449             "SetDebug",
450             [](musik::core::sdk::IPlugin* plugin, SetDebug func) {
451                 func(&nullDebugger);
452             });
453     }
454 
455 } } }
456