2019-07-17 13:37:18 -04:00
|
|
|
#include <dlfcn.h>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <log/LogUtils.h>
|
|
|
|
#include <experimental/filesystem>
|
2020-02-21 14:32:25 -05:00
|
|
|
#include "teaspeak/MusicPlayer.h"
|
2019-07-17 13:37:18 -04:00
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
using namespace music;
|
|
|
|
using namespace music::manager;
|
|
|
|
|
|
|
|
namespace fs = std::experimental::filesystem;
|
|
|
|
|
|
|
|
void log::log(const Level& lvl, const std::string& msg) {
|
|
|
|
logger::logger(0)->log((spdlog::level::level_enum) lvl, "[Music] " + msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AbstractMusicPlayer::registerEventHandler(const std::string& key, const std::function<void(MusicEvent)>& function) {
|
2020-02-01 08:32:16 -05:00
|
|
|
std::lock_guard lock(this->eventLock);
|
2019-11-22 14:51:00 -05:00
|
|
|
this->eventHandlers.emplace_back(key, function);
|
2019-07-17 13:37:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void AbstractMusicPlayer::unregisterEventHandler(const std::string& string) {
|
2020-02-01 08:32:16 -05:00
|
|
|
std::lock_guard lock(this->eventLock);
|
2019-07-17 13:37:18 -04:00
|
|
|
for(const auto& entry : this->eventHandlers){
|
2019-07-19 16:55:03 -04:00
|
|
|
if(entry.first == string) {
|
2019-07-17 13:37:18 -04:00
|
|
|
this->eventHandlers.erase(find_if(this->eventHandlers.begin(), this->eventHandlers.end(), [string](const std::pair<std::string, std::function<void(MusicEvent)>>& elm){ return elm.first == string; }));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AbstractMusicPlayer::fireEvent(MusicEvent event) {
|
2020-03-26 12:34:31 -04:00
|
|
|
decltype(this->eventHandlers) handlers{};
|
|
|
|
{
|
|
|
|
std::lock_guard lock(this->eventLock);
|
|
|
|
handlers = this->eventHandlers; //Copy for remove while fire
|
|
|
|
}
|
|
|
|
for(const auto& entry : handlers)
|
2019-07-17 13:37:18 -04:00
|
|
|
entry.second(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* music::stateNames[] = {"uninitialised", "playing", "paused", "stopped"};
|
|
|
|
|
2020-02-01 08:32:16 -05:00
|
|
|
static std::mutex staticLock;
|
2019-07-17 13:37:18 -04:00
|
|
|
static std::deque<std::shared_ptr<PlayerProvider>> types;
|
|
|
|
|
|
|
|
std::deque<std::shared_ptr<PlayerProvider>> manager::registeredTypes(){ return types; }
|
|
|
|
void registerType(const std::shared_ptr<PlayerProvider>& provider) {
|
2020-02-01 08:32:16 -05:00
|
|
|
std::lock_guard l(staticLock);
|
2019-07-17 13:37:18 -04:00
|
|
|
types.push_back(provider);
|
|
|
|
}
|
|
|
|
|
|
|
|
//empty for not set
|
|
|
|
std::shared_ptr<PlayerProvider> manager::resolveProvider(const std::string& provName, const std::string& str) {
|
2020-02-01 08:32:16 -05:00
|
|
|
std::lock_guard l(staticLock);
|
2019-07-17 13:37:18 -04:00
|
|
|
vector<std::shared_ptr<PlayerProvider>> provs;
|
|
|
|
for(const auto& prov : types){
|
|
|
|
auto p = prov.get();
|
|
|
|
if(!str.empty() && prov->acceptString(str))
|
|
|
|
provs.push_back(prov);
|
|
|
|
else if(!provName.empty() && prov->providerName == provName)
|
|
|
|
provs.push_back(prov);
|
|
|
|
}
|
|
|
|
sort(provs.begin(), provs.end(), [str](const std::shared_ptr<PlayerProvider>& a, const std::shared_ptr<PlayerProvider>& b){
|
|
|
|
return a->weight(str) > b->weight(str);
|
|
|
|
});
|
|
|
|
return provs.empty() ? nullptr : provs.front();
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef std::shared_ptr<music::manager::PlayerProvider>(*create_provider_fn)();
|
|
|
|
void manager::loadProviders(const std::string& path) {
|
|
|
|
auto dir = fs::u8path(path);
|
|
|
|
if(!fs::exists(dir)){
|
|
|
|
try {
|
|
|
|
fs::create_directories(dir);
|
|
|
|
} catch (std::exception& e) {}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
deque<fs::path> paths;
|
2020-04-15 09:02:59 -04:00
|
|
|
error_code error_code{};
|
|
|
|
for(const auto& entry : fs::directory_iterator(dir, error_code)){
|
2019-07-17 13:37:18 -04:00
|
|
|
if(!entry.path().has_extension()) continue;
|
|
|
|
if(entry.path().extension().string() == ".so")
|
|
|
|
paths.push_back(entry.path());
|
|
|
|
}
|
2020-04-15 09:02:59 -04:00
|
|
|
if(error_code) {
|
|
|
|
log::log(log::err, "Failed to scan the target directory (" + dir.string() + "): " + error_code.message());
|
|
|
|
return;
|
|
|
|
}
|
2019-07-17 13:37:18 -04:00
|
|
|
std::sort(paths.begin(), paths.end(), [](const fs::path& a, const fs::path& b){ return a.filename().string() < b.filename().string(); });
|
|
|
|
|
|
|
|
int index = 0;
|
|
|
|
log::log(log::debug, "Provider load order:");
|
|
|
|
for(const auto& entry : paths)
|
|
|
|
log::log(log::debug, "[" + to_string(index++) + "] " + entry.string());
|
|
|
|
|
|
|
|
for(const auto& entry : paths){
|
|
|
|
void* provider = dlopen(entry.string().c_str(), RTLD_NOW);
|
|
|
|
if(!provider){
|
|
|
|
log::log(log::err, string() + "Could not load music provider " + entry.string() + ". Error: " + dlerror());
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
auto create_provider = reinterpret_cast<create_provider_fn>(dlsym(provider, "create_provider"));
|
|
|
|
if(!create_provider){
|
|
|
|
log::log(log::err, string() + "Could not find entry point create_provider()@" + entry.string());
|
|
|
|
dlclose(provider);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
auto mprovider = (*create_provider)();
|
|
|
|
if(!mprovider){
|
|
|
|
log::log(log::err, string() + "Could not create music provider for " + entry.string());
|
|
|
|
dlclose(provider);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
log::log(log::info, string() + "Loaded successfully provider " + mprovider->providerName);
|
|
|
|
types.push_back(mprovider);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void manager::register_provider(const std::shared_ptr<music::manager::PlayerProvider> &provider) {
|
2020-02-01 08:32:16 -05:00
|
|
|
std::lock_guard l(staticLock);
|
2019-07-17 13:37:18 -04:00
|
|
|
types.push_back(provider);
|
2019-11-22 14:51:00 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
void manager::finalizeProviders() {
|
2020-02-01 08:32:16 -05:00
|
|
|
std::lock_guard l(staticLock);
|
2019-11-22 14:51:00 -05:00
|
|
|
types.clear();
|
2019-07-17 13:37:18 -04:00
|
|
|
}
|