mirror of
https://github.com/flightlessmango/MangoHud.git
synced 2024-10-31 15:20:13 +00:00
Move interactions with main_metadata into separate functions
More tidying up of the helper classes
This commit is contained in:
parent
7cc76142f1
commit
9a34b55498
390
src/dbus.cpp
390
src/dbus.cpp
@ -1,59 +1,55 @@
|
|||||||
|
#include <array>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <array>
|
|
||||||
|
#include "dbus_helpers.hpp"
|
||||||
#include "dbus_info.h"
|
#include "dbus_info.h"
|
||||||
#include "string_utils.h"
|
#include "string_utils.h"
|
||||||
#include "dbus_helpers.hpp"
|
|
||||||
|
|
||||||
using ms = std::chrono::milliseconds;
|
using ms = std::chrono::milliseconds;
|
||||||
using namespace DBus_helpers;
|
using namespace DBus_helpers;
|
||||||
#define DBUS_TIMEOUT 2000 // ms
|
#define DBUS_TIMEOUT 2000 // ms
|
||||||
|
|
||||||
struct mutexed_metadata main_metadata;
|
struct mutexed_metadata main_metadata;
|
||||||
|
|
||||||
namespace dbusmgr {
|
namespace dbusmgr {
|
||||||
dbus_manager dbus_mgr;
|
dbus_manager dbus_mgr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template <class T>
|
||||||
static void assign_metadata_value(metadata& meta, const std::string& key, const T& value) {
|
static void assign_metadata_value(metadata& meta, const std::string& key,
|
||||||
std::cerr << "Assigning Metadata: " << key << " -> " << value << "\n";
|
const T& value) {
|
||||||
if(key == "PlaybackStatus") {
|
if (key == "PlaybackStatus") {
|
||||||
meta.playing = (value == "Playing");
|
meta.playing = (value == "Playing");
|
||||||
meta.got_playback_data = true;
|
meta.got_playback_data = true;
|
||||||
}
|
} else if (key == "xesam:title") {
|
||||||
else if(key == "xesam:title"){
|
|
||||||
meta.title = value;
|
meta.title = value;
|
||||||
meta.got_song_data = true;
|
meta.got_song_data = true;
|
||||||
meta.valid = true;
|
meta.valid = true;
|
||||||
}
|
} else if (key == "xesam:artist") {
|
||||||
else if(key == "xesam:artist") {
|
|
||||||
meta.artists = value;
|
meta.artists = value;
|
||||||
meta.got_song_data = true;
|
meta.got_song_data = true;
|
||||||
meta.valid = true;
|
meta.valid = true;
|
||||||
}
|
} else if (key == "xesam:album") {
|
||||||
else if(key == "xesam:album") {
|
|
||||||
meta.album = value;
|
meta.album = value;
|
||||||
meta.got_song_data = true;
|
meta.got_song_data = true;
|
||||||
meta.valid = true;
|
meta.valid = true;
|
||||||
}
|
} else if (key == "mpris:artUrl") {
|
||||||
else if(key == "mpris:artUrl"){
|
|
||||||
meta.artUrl = value;
|
meta.artUrl = value;
|
||||||
meta.got_song_data = true;
|
meta.got_song_data = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string format_signal(const dbusmgr::DBusSignal& s)
|
std::string format_signal(const dbusmgr::DBusSignal& s) {
|
||||||
{
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "type='signal',interface='" << s.intf << "'";
|
ss << "type='signal',interface='" << s.intf << "'";
|
||||||
ss << ",member='" << s.signal << "'";
|
ss << ",member='" << s.signal << "'";
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parse_mpris_properties(libdbus_loader& dbus, DBusMessage *msg, std::string& source, metadata& meta)
|
static void parse_mpris_properties(libdbus_loader& dbus, DBusMessage* msg,
|
||||||
{
|
std::string& source, metadata& meta) {
|
||||||
/**
|
/**
|
||||||
* Expected response Format:
|
* Expected response Format:
|
||||||
* string,
|
* string,
|
||||||
@ -61,55 +57,43 @@ static void parse_mpris_properties(libdbus_loader& dbus, DBusMessage *msg, std::
|
|||||||
* "Metadata" -> multimap,
|
* "Metadata" -> multimap,
|
||||||
* "PlaybackStatus" -> string
|
* "PlaybackStatus" -> string
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
|
|
||||||
std::string key, val;
|
std::string key, val;
|
||||||
auto iter = DBusMessageIter_wrap(msg, &dbus);
|
auto iter = DBusMessageIter_wrap(msg, &dbus);
|
||||||
|
|
||||||
// Should be 'org.mpris.MediaPlayer2.Player'
|
// Should be 'org.mpris.MediaPlayer2.Player'
|
||||||
if (not iter.is_string()){
|
if (not iter.is_string()) {
|
||||||
std::cerr << "Not a string\n"; //TODO
|
std::cerr << "Not a string\n"; // TODO
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
source = iter.get_primitive<std::string>();
|
source = iter.get_primitive<std::string>();
|
||||||
|
|
||||||
if (source != "org.mpris.MediaPlayer2.Player")
|
if (source != "org.mpris.MediaPlayer2.Player") return;
|
||||||
return;
|
|
||||||
|
|
||||||
iter.next();
|
iter.next();
|
||||||
if (not iter.is_array())
|
if (not iter.is_array()) return;
|
||||||
return;
|
|
||||||
|
|
||||||
//std::cerr << "Parsing mpris update...\n";
|
iter.string_map_for_each([&](std::string& key, DBusMessageIter_wrap it) {
|
||||||
string_map_for_each(iter, [&](std::string& key, DBusMessageIter_wrap it){
|
if (key == "Metadata") {
|
||||||
if(key == "Metadata"){
|
it.string_map_for_each([&](const std::string& key,
|
||||||
//std::cerr << "\tMetadata:\n";
|
DBusMessageIter_wrap it) {
|
||||||
string_map_for_each(it, [&](const std::string& key, DBusMessageIter_wrap it){
|
std::string val;
|
||||||
if(it.is_primitive()){
|
if (it.is_primitive()) {
|
||||||
auto val = it.get_stringified();
|
val = it.get_stringified();
|
||||||
//std::cerr << "\t\t" << key << " -> " << val << "\n";
|
} else if (it.is_array()) {
|
||||||
assign_metadata_value(meta, key, val);
|
it.array_for_each_stringify([&](const std::string& str) {
|
||||||
}
|
if (val.empty()) {
|
||||||
else if(it.is_array()){
|
|
||||||
std::string val;
|
|
||||||
array_for_each_stringify(it, [&](const std::string& str){
|
|
||||||
if(val.empty()){
|
|
||||||
val = str;
|
val = str;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val += ", " + str;
|
val += ", " + str;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
//std::cerr << "\t\t" << key << " -> " << val << "\n";
|
|
||||||
assign_metadata_value(meta, key, val);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
string_multimap_for_each_stringify(it, [&](const std::string& key, const std::string& val){
|
|
||||||
assign_metadata_value(meta, key, val);
|
assign_metadata_value(meta, key, val);
|
||||||
});
|
});
|
||||||
}
|
} else if (key == "PlaybackStatus") {
|
||||||
else if(key == "PlaybackStatus"){
|
|
||||||
auto val = it.get_stringified();
|
auto val = it.get_stringified();
|
||||||
assign_metadata_value(meta, key, val);
|
assign_metadata_value(meta, key, val);
|
||||||
}
|
}
|
||||||
@ -117,47 +101,43 @@ static void parse_mpris_properties(libdbus_loader& dbus, DBusMessage *msg, std::
|
|||||||
meta.valid = (meta.artists.size() || !meta.title.empty());
|
meta.valid = (meta.artists.size() || !meta.title.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dbus_get_name_owner(dbusmgr::dbus_manager& dbus_mgr, std::string& name_owner, const char *name)
|
bool dbus_get_name_owner(dbusmgr::dbus_manager& dbus_mgr,
|
||||||
{
|
std::string& name_owner, const char* name) {
|
||||||
auto reply = DBusMessage_wrap::new_method_call(
|
auto reply =
|
||||||
"org.freedesktop.DBus",
|
DBusMessage_wrap::new_method_call(
|
||||||
"/org/freedesktop/DBus",
|
"org.freedesktop.DBus", "/org/freedesktop/DBus",
|
||||||
"org.freedesktop.DBus",
|
"org.freedesktop.DBus", "GetNameOwner", &dbus_mgr.dbus())
|
||||||
"GetNameOwner",
|
.argument(name)
|
||||||
&dbus_mgr.dbus()
|
.send_with_reply_and_block(dbus_mgr.get_conn(), DBUS_TIMEOUT);
|
||||||
).argument(name).send_with_reply_and_block(dbus_mgr.get_conn(), DBUS_TIMEOUT);
|
if (not reply) return false;
|
||||||
if(not reply) return false;
|
|
||||||
|
|
||||||
auto iter = reply.iter();
|
auto iter = reply.iter();
|
||||||
if(not iter.is_string()) return false;
|
if (not iter.is_string()) return false;
|
||||||
name_owner = iter.get_primitive<std::string>();
|
name_owner = iter.get_primitive<std::string>();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dbus_get_player_property(dbusmgr::dbus_manager& dbus_mgr, metadata& meta, const char * dest, const char * prop)
|
bool dbus_get_player_property(dbusmgr::dbus_manager& dbus_mgr, metadata& meta,
|
||||||
{
|
const char* dest, const char* prop) {
|
||||||
auto reply = DBusMessage_wrap::new_method_call(
|
auto reply =
|
||||||
dest,
|
DBusMessage_wrap::new_method_call(dest, "/org/mpris/MediaPlayer2",
|
||||||
"/org/mpris/MediaPlayer2",
|
"org.freedesktop.DBus.Properties",
|
||||||
"org.freedesktop.DBus.Properties",
|
"Get", &dbus_mgr.dbus())
|
||||||
"Get",
|
.argument("org.mpris.MediaPlayer2.Player")
|
||||||
&dbus_mgr.dbus()
|
.argument(prop)
|
||||||
).argument("org.mpris.MediaPlayer2.Player")
|
.send_with_reply_and_block(dbus_mgr.get_conn(), DBUS_TIMEOUT);
|
||||||
.argument(prop)
|
|
||||||
.send_with_reply_and_block(dbus_mgr.get_conn(), DBUS_TIMEOUT);
|
|
||||||
|
|
||||||
if(not reply) return false;
|
if (not reply) return false;
|
||||||
|
|
||||||
auto iter = reply.iter();
|
auto iter = reply.iter();
|
||||||
if(iter.is_array()){
|
if (iter.is_array()) {
|
||||||
string_multimap_for_each_stringify(iter, [&](const std::string& key, const std::string& val){
|
iter.string_multimap_for_each_stringify(
|
||||||
assign_metadata_value(meta, key, val);
|
[&](const std::string& key, const std::string& val) {
|
||||||
});
|
assign_metadata_value(meta, key, val);
|
||||||
}
|
});
|
||||||
else if(iter.is_primitive()){
|
} else if (iter.is_primitive()) {
|
||||||
assign_metadata_value(meta, prop, iter.get_stringified());
|
assign_metadata_value(meta, prop, iter.get_stringified());
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -165,8 +145,8 @@ bool dbus_get_player_property(dbusmgr::dbus_manager& dbus_mgr, metadata& meta, c
|
|||||||
|
|
||||||
namespace dbusmgr {
|
namespace dbusmgr {
|
||||||
bool dbus_manager::get_media_player_metadata(metadata& meta, std::string name) {
|
bool dbus_manager::get_media_player_metadata(metadata& meta, std::string name) {
|
||||||
if(name == "") name = m_active_player;
|
if (name == "") name = m_active_player;
|
||||||
if(name == "") return false;
|
if (name == "") return false;
|
||||||
meta.clear();
|
meta.clear();
|
||||||
dbus_get_player_property(*this, meta, name.c_str(), "Metadata");
|
dbus_get_player_property(*this, meta, name.c_str(), "Metadata");
|
||||||
dbus_get_player_property(*this, meta, name.c_str(), "PlaybackStatus");
|
dbus_get_player_property(*this, meta, name.c_str(), "PlaybackStatus");
|
||||||
@ -174,11 +154,9 @@ bool dbus_manager::get_media_player_metadata(metadata& meta, std::string name) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dbus_manager::init(const std::string& requested_player)
|
bool dbus_manager::init(const std::string& requested_player) {
|
||||||
{
|
if (m_inited) return true;
|
||||||
if (m_inited)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
m_requested_player = "org.mpris.MediaPlayer2." + requested_player;
|
m_requested_player = "org.mpris.MediaPlayer2." + requested_player;
|
||||||
|
|
||||||
if (!m_dbus_ldr.IsLoaded() && !m_dbus_ldr.Load("libdbus-1.so.3")) {
|
if (!m_dbus_ldr.IsLoaded() && !m_dbus_ldr.Load("libdbus-1.so.3")) {
|
||||||
@ -190,60 +168,65 @@ bool dbus_manager::init(const std::string& requested_player)
|
|||||||
|
|
||||||
m_dbus_ldr.threads_init_default();
|
m_dbus_ldr.threads_init_default();
|
||||||
|
|
||||||
if ( nullptr == (m_dbus_conn = m_dbus_ldr.bus_get(DBUS_BUS_SESSION, &m_error)) ) {
|
if (nullptr ==
|
||||||
|
(m_dbus_conn = m_dbus_ldr.bus_get(DBUS_BUS_SESSION, &m_error))) {
|
||||||
std::cerr << "MANGOHUD: " << m_error.message << std::endl;
|
std::cerr << "MANGOHUD: " << m_error.message << std::endl;
|
||||||
m_dbus_ldr.error_free(&m_error);
|
m_dbus_ldr.error_free(&m_error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "MANGOHUD: Connected to D-Bus as \"" << m_dbus_ldr.bus_get_unique_name(m_dbus_conn) << "\"." << std::endl;
|
std::cout << "MANGOHUD: Connected to D-Bus as \""
|
||||||
|
<< m_dbus_ldr.bus_get_unique_name(m_dbus_conn) << "\"."
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
dbus_list_name_to_owner();
|
dbus_list_name_to_owner();
|
||||||
connect_to_signals();
|
connect_to_signals();
|
||||||
|
|
||||||
select_active_player();
|
select_active_player();
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lck(main_metadata.mtx);
|
|
||||||
get_media_player_metadata(main_metadata.meta);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_inited = true;
|
m_inited = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dbus_manager::select_active_player(metadata* store_meta) {
|
bool dbus_manager::select_active_player() {
|
||||||
|
auto old_active_player = m_active_player;
|
||||||
|
m_active_player = "";
|
||||||
|
metadata meta{};
|
||||||
// If the requested player is available, use it
|
// If the requested player is available, use it
|
||||||
if(m_name_owners.count(m_requested_player) > 0) {
|
if (m_name_owners.count(m_requested_player) > 0) {
|
||||||
m_active_player = m_requested_player;
|
m_active_player = m_requested_player;
|
||||||
std::cerr << "Selecting requested player: " << m_requested_player << "\n";
|
std::cerr << "Selecting requested player: " << m_requested_player
|
||||||
if(store_meta) get_media_player_metadata(*store_meta, m_active_player);
|
<< "\n";
|
||||||
return true;
|
get_media_player_metadata(meta, m_active_player);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Else, use any player that is currently playing..
|
// Else, use any player that is currently playing..
|
||||||
for(const auto& entry : m_name_owners) {
|
if (m_active_player.empty()) {
|
||||||
const auto& name = std::get<0>(entry);
|
for (const auto& entry : m_name_owners) {
|
||||||
metadata meta;
|
const auto& name = std::get<0>(entry);
|
||||||
get_media_player_metadata(meta, name);
|
get_media_player_metadata(meta, name);
|
||||||
if(meta.playing) {
|
if (meta.playing) {
|
||||||
m_active_player = name;
|
m_active_player = name;
|
||||||
std::cerr << "Selecting fallback player: " << name << "\n";
|
std::cerr << "Selecting fallback player: " << name << "\n";
|
||||||
if(store_meta) *store_meta = meta;
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// No media players are active
|
if (not m_active_player.empty()) {
|
||||||
std::cerr << "No active players\n";
|
if (m_active_player != old_active_player) {
|
||||||
m_active_player = "";
|
onNewPlayer(meta);
|
||||||
if(store_meta) store_meta->clear();
|
}
|
||||||
return false;
|
return true;
|
||||||
|
} else {
|
||||||
|
std::cerr << "No active players\n";
|
||||||
|
if (not old_active_player.empty()) {
|
||||||
|
onNoPlayer();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dbus_manager::deinit()
|
void dbus_manager::deinit() {
|
||||||
{
|
if (!m_inited) return;
|
||||||
if (!m_inited)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// unreference system bus connection instead of closing it
|
// unreference system bus connection instead of closing it
|
||||||
if (m_dbus_conn) {
|
if (m_dbus_conn) {
|
||||||
@ -255,18 +238,17 @@ void dbus_manager::deinit()
|
|||||||
m_inited = false;
|
m_inited = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
dbus_manager::~dbus_manager()
|
dbus_manager::~dbus_manager() { deinit(); }
|
||||||
{
|
|
||||||
deinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
DBusHandlerResult dbus_manager::filter_signals(DBusConnection* conn, DBusMessage* msg, void* userData) {
|
DBusHandlerResult dbus_manager::filter_signals(DBusConnection* conn,
|
||||||
|
DBusMessage* msg,
|
||||||
|
void* userData) {
|
||||||
auto& manager = *reinterpret_cast<dbus_manager*>(userData);
|
auto& manager = *reinterpret_cast<dbus_manager*>(userData);
|
||||||
|
|
||||||
for(auto& sig : manager.m_signals) {
|
for (auto& sig : manager.m_signals) {
|
||||||
if(manager.m_dbus_ldr.message_is_signal(msg, sig.intf, sig.signal)){
|
if (manager.m_dbus_ldr.message_is_signal(msg, sig.intf, sig.signal)) {
|
||||||
auto sender = manager.m_dbus_ldr.message_get_sender(msg);
|
auto sender = manager.m_dbus_ldr.message_get_sender(msg);
|
||||||
if((manager.*(sig.handler))(msg, sender))
|
if ((manager.*(sig.handler))(msg, sender))
|
||||||
return DBUS_HANDLER_RESULT_HANDLED;
|
return DBUS_HANDLER_RESULT_HANDLED;
|
||||||
else
|
else
|
||||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||||
@ -275,7 +257,8 @@ DBusHandlerResult dbus_manager::filter_signals(DBusConnection* conn, DBusMessage
|
|||||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dbus_manager::handle_properties_changed(DBusMessage* msg, const char* sender) {
|
bool dbus_manager::handle_properties_changed(DBusMessage* msg,
|
||||||
|
const char* sender) {
|
||||||
std::string source;
|
std::string source;
|
||||||
|
|
||||||
metadata meta;
|
metadata meta;
|
||||||
@ -284,88 +267,49 @@ bool dbus_manager::handle_properties_changed(DBusMessage* msg, const char* sende
|
|||||||
std::cerr << "PropertiesChanged Signal received:\n";
|
std::cerr << "PropertiesChanged Signal received:\n";
|
||||||
std::cerr << "\tSource: " << source << "\n";
|
std::cerr << "\tSource: " << source << "\n";
|
||||||
std::cerr << "active_player: " << m_active_player << "\n";
|
std::cerr << "active_player: " << m_active_player << "\n";
|
||||||
std::cerr << "active_player's owner: " << m_name_owners[m_active_player] << "\n";
|
std::cerr << "active_player's owner: " << m_name_owners[m_active_player]
|
||||||
|
<< "\n";
|
||||||
std::cerr << "sender: " << sender << "\n";
|
std::cerr << "sender: " << sender << "\n";
|
||||||
#endif
|
#endif
|
||||||
if (source != "org.mpris.MediaPlayer2.Player")
|
if (source != "org.mpris.MediaPlayer2.Player") return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
if(m_active_player == "") {
|
if (m_active_player == "") {
|
||||||
select_active_player(&meta);
|
select_active_player();
|
||||||
|
} else if (m_name_owners[m_active_player] == sender) {
|
||||||
|
onPlayerUpdate(meta);
|
||||||
}
|
}
|
||||||
if (m_name_owners[m_active_player] == sender) {
|
|
||||||
std::lock_guard<std::mutex> lck(main_metadata.mtx);
|
|
||||||
if(meta.got_song_data){
|
|
||||||
// If the song has changed, reset the ticker
|
|
||||||
if(
|
|
||||||
main_metadata.meta.artists != meta.artists ||
|
|
||||||
main_metadata.meta.album != meta.album ||
|
|
||||||
main_metadata.meta.title != meta.title
|
|
||||||
){
|
|
||||||
main_metadata.ticker = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
main_metadata.meta = meta;
|
|
||||||
main_metadata.meta.playing = true;
|
|
||||||
}
|
|
||||||
if(meta.got_playback_data){
|
|
||||||
main_metadata.meta.playing = meta.playing;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::cerr << "Main metadata valid: " << std::boolalpha << main_metadata.meta.valid << "\n";
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dbus_manager::handle_name_owner_changed(DBusMessage* msg, const char* sender) {
|
bool dbus_manager::handle_name_owner_changed(DBusMessage* _msg,
|
||||||
DBusMessageIter iter;
|
const char* sender) {
|
||||||
m_dbus_ldr.message_iter_init (msg, &iter);
|
|
||||||
std::vector<std::string> str;
|
std::vector<std::string> str;
|
||||||
const char *value = nullptr;
|
|
||||||
|
|
||||||
while (m_dbus_ldr.message_iter_get_arg_type (&iter) == DBUS_TYPE_STRING) {
|
for (auto iter = DBusMessageIter_wrap(_msg, &m_dbus_ldr); iter;
|
||||||
m_dbus_ldr.message_iter_get_basic (&iter, &value);
|
iter.next()) {
|
||||||
str.push_back(value);
|
str.push_back(iter.get_primitive<std::string>());
|
||||||
m_dbus_ldr.message_iter_next (&iter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// register new name
|
// register new name
|
||||||
if (str.size() == 3
|
if (str.size() == 3 && starts_with(str[0], "org.mpris.MediaPlayer2.") &&
|
||||||
&& starts_with(str[0], "org.mpris.MediaPlayer2.")
|
!str[2].empty()) {
|
||||||
&& !str[2].empty()
|
|
||||||
)
|
|
||||||
{
|
|
||||||
m_name_owners[str[0]] = str[2];
|
m_name_owners[str[0]] = str[2];
|
||||||
if(str[0] == m_requested_player){
|
if (str[0] == m_requested_player) {
|
||||||
metadata tmp;
|
select_active_player();
|
||||||
select_active_player(&tmp);
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lck(main_metadata.mtx);
|
|
||||||
main_metadata.meta = tmp;
|
|
||||||
main_metadata.ticker = {};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// did a player quit?
|
// did a player quit?
|
||||||
if (str[2].empty()) {
|
if (str[2].empty()) {
|
||||||
if (str.size() == 3
|
if (str.size() == 3 && str[0] == m_active_player) {
|
||||||
&& str[0] == m_active_player
|
|
||||||
) {
|
|
||||||
metadata tmp;
|
|
||||||
m_name_owners.erase(str[0]);
|
m_name_owners.erase(str[0]);
|
||||||
select_active_player();
|
select_active_player();
|
||||||
get_media_player_metadata(tmp);
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lck(main_metadata.mtx);
|
|
||||||
std::swap(tmp, main_metadata.meta);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dbus_manager::connect_to_signals()
|
void dbus_manager::connect_to_signals() {
|
||||||
{
|
|
||||||
for (auto kv : m_signals) {
|
for (auto kv : m_signals) {
|
||||||
auto signal = format_signal(kv);
|
auto signal = format_signal(kv);
|
||||||
m_dbus_ldr.bus_add_match(m_dbus_conn, signal.c_str(), &m_error);
|
m_dbus_ldr.bus_add_match(m_dbus_conn, signal.c_str(), &m_error);
|
||||||
@ -373,17 +317,18 @@ void dbus_manager::connect_to_signals()
|
|||||||
::perror(m_error.name);
|
::perror(m_error.name);
|
||||||
::perror(m_error.message);
|
::perror(m_error.message);
|
||||||
m_dbus_ldr.error_free(&m_error);
|
m_dbus_ldr.error_free(&m_error);
|
||||||
//return;
|
// return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_dbus_ldr.connection_add_filter(m_dbus_conn, filter_signals, reinterpret_cast<void*>(this), nullptr);
|
m_dbus_ldr.connection_add_filter(m_dbus_conn, filter_signals,
|
||||||
|
reinterpret_cast<void*>(this), nullptr);
|
||||||
|
|
||||||
start_thread();
|
start_thread();
|
||||||
}
|
}
|
||||||
|
|
||||||
void dbus_manager::disconnect_from_signals()
|
void dbus_manager::disconnect_from_signals() {
|
||||||
{
|
m_dbus_ldr.connection_remove_filter(m_dbus_conn, filter_signals,
|
||||||
m_dbus_ldr.connection_remove_filter(m_dbus_conn, filter_signals, reinterpret_cast<void*>(this));
|
reinterpret_cast<void*>(this));
|
||||||
for (auto kv : m_signals) {
|
for (auto kv : m_signals) {
|
||||||
auto signal = format_signal(kv);
|
auto signal = format_signal(kv);
|
||||||
m_dbus_ldr.bus_remove_match(m_dbus_conn, signal.c_str(), &m_error);
|
m_dbus_ldr.bus_remove_match(m_dbus_conn, signal.c_str(), &m_error);
|
||||||
@ -397,51 +342,74 @@ void dbus_manager::disconnect_from_signals()
|
|||||||
stop_thread();
|
stop_thread();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dbus_manager::dbus_list_name_to_owner()
|
bool dbus_manager::dbus_list_name_to_owner() {
|
||||||
{
|
auto reply =
|
||||||
auto reply = DBusMessage_wrap::new_method_call(
|
DBusMessage_wrap::new_method_call(
|
||||||
"org.freedesktop.DBus",
|
"org.freedesktop.DBus", "/org/freedesktop/DBus",
|
||||||
"/org/freedesktop/DBus",
|
"org.freedesktop.DBus", "ListNames", &dbus_mgr.dbus())
|
||||||
"org.freedesktop.DBus",
|
.send_with_reply_and_block(dbus_mgr.get_conn(), DBUS_TIMEOUT);
|
||||||
"ListNames",
|
if (not reply) return false;
|
||||||
&dbus_mgr.dbus()
|
|
||||||
).send_with_reply_and_block(dbus_mgr.get_conn(), DBUS_TIMEOUT);
|
|
||||||
if(not reply) return false;
|
|
||||||
|
|
||||||
auto iter = reply.iter();
|
auto iter = reply.iter();
|
||||||
|
|
||||||
if(not iter.is_array()) {
|
if (not iter.is_array()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
array_for_each<std::string>(iter, [&](std::string name){
|
iter.array_for_each_value<std::string>([&](std::string name) {
|
||||||
if(!starts_with(name.c_str(), "org.mpris.MediaPlayer2.")) return;
|
if (!starts_with(name.c_str(), "org.mpris.MediaPlayer2.")) return;
|
||||||
std::string owner;
|
std::string owner;
|
||||||
if(dbus_get_name_owner(dbus_mgr, owner, name.c_str())){
|
if (dbus_get_name_owner(dbus_mgr, owner, name.c_str())) {
|
||||||
m_name_owners[name] = owner;
|
m_name_owners[name] = owner;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dbus_manager::stop_thread()
|
void dbus_manager::stop_thread() {
|
||||||
{
|
|
||||||
m_quit = true;
|
m_quit = true;
|
||||||
if (m_thread.joinable())
|
if (m_thread.joinable()) m_thread.join();
|
||||||
m_thread.join();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dbus_manager::start_thread()
|
void dbus_manager::start_thread() {
|
||||||
{
|
|
||||||
stop_thread();
|
stop_thread();
|
||||||
m_quit = false;
|
m_quit = false;
|
||||||
m_thread = std::thread(&dbus_manager::dbus_thread, this);
|
m_thread = std::thread(&dbus_manager::dbus_thread, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dbus_manager::dbus_thread()
|
void dbus_manager::dbus_thread() {
|
||||||
{
|
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
while(!m_quit && m_dbus_ldr.connection_read_write_dispatch(m_dbus_conn, 0))
|
while (!m_quit && m_dbus_ldr.connection_read_write_dispatch(m_dbus_conn, 0))
|
||||||
std::this_thread::sleep_for(10ms);
|
std::this_thread::sleep_for(10ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dbus_manager::onNoPlayer() {
|
||||||
|
std::lock_guard<std::mutex> lck(main_metadata.mtx);
|
||||||
|
main_metadata.meta = {};
|
||||||
|
main_metadata.ticker = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dbus_manager::onNewPlayer(metadata& meta) {
|
||||||
|
std::lock_guard<std::mutex> lck(main_metadata.mtx);
|
||||||
|
main_metadata.meta = meta;
|
||||||
|
main_metadata.ticker = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void dbus_manager::onPlayerUpdate(metadata& meta) {
|
||||||
|
std::lock_guard<std::mutex> lck(main_metadata.mtx);
|
||||||
|
if (meta.got_song_data) {
|
||||||
|
// If the song has changed, reset the ticker
|
||||||
|
if (main_metadata.meta.artists != meta.artists ||
|
||||||
|
main_metadata.meta.album != meta.album ||
|
||||||
|
main_metadata.meta.title != meta.title) {
|
||||||
|
main_metadata.ticker = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
main_metadata.meta = meta;
|
||||||
|
main_metadata.meta.playing = true;
|
||||||
|
}
|
||||||
|
if (meta.got_playback_data) {
|
||||||
|
main_metadata.meta.playing = meta.playing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace dbusmgr
|
||||||
|
@ -2,83 +2,86 @@
|
|||||||
#ifndef MANGOHUD_DBUS_HELPERS
|
#ifndef MANGOHUD_DBUS_HELPERS
|
||||||
#define MANGOHUD_DBUS_HELPERS
|
#define MANGOHUD_DBUS_HELPERS
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "loaders/loader_dbus.h"
|
#include "loaders/loader_dbus.h"
|
||||||
|
|
||||||
namespace DBus_helpers{
|
namespace DBus_helpers {
|
||||||
namespace detail{
|
namespace detail {
|
||||||
template<class T> struct dbus_type_identifier{};
|
// clang-format off
|
||||||
template<> struct dbus_type_identifier<uint8_t> { const int value = DBUS_TYPE_BYTE; };
|
template<class T> struct dbus_type_traits{};
|
||||||
template<> struct dbus_type_identifier<uint16_t> { const int value = DBUS_TYPE_UINT16; };
|
template<> struct dbus_type_traits<uint8_t> { const int value = DBUS_TYPE_BYTE; const bool is_fixed = true; };
|
||||||
template<> struct dbus_type_identifier<uint32_t> { const int value = DBUS_TYPE_UINT32; };
|
template<> struct dbus_type_traits<uint16_t> { const int value = DBUS_TYPE_UINT16; const bool is_fixed = true; };
|
||||||
template<> struct dbus_type_identifier<uint64_t> { const int value = DBUS_TYPE_UINT64; };
|
template<> struct dbus_type_traits<uint32_t> { const int value = DBUS_TYPE_UINT32; const bool is_fixed = true; };
|
||||||
template<> struct dbus_type_identifier<int16_t> { const int value = DBUS_TYPE_INT16; };
|
template<> struct dbus_type_traits<uint64_t> { const int value = DBUS_TYPE_UINT64; const bool is_fixed = true; };
|
||||||
template<> struct dbus_type_identifier<int32_t> { const int value = DBUS_TYPE_INT32; };
|
template<> struct dbus_type_traits<int16_t> { const int value = DBUS_TYPE_INT16; const bool is_fixed = true; };
|
||||||
template<> struct dbus_type_identifier<int64_t> { const int value = DBUS_TYPE_INT64; };
|
template<> struct dbus_type_traits<int32_t> { const int value = DBUS_TYPE_INT32; const bool is_fixed = true; };
|
||||||
template<> struct dbus_type_identifier<double> { const int value = DBUS_TYPE_DOUBLE; };
|
template<> struct dbus_type_traits<int64_t> { const int value = DBUS_TYPE_INT64; const bool is_fixed = true; };
|
||||||
template<> struct dbus_type_identifier<const char*> { const int value = DBUS_TYPE_STRING; };
|
template<> struct dbus_type_traits<double> { const int value = DBUS_TYPE_DOUBLE; const bool is_fixed = true; };
|
||||||
|
template<> struct dbus_type_traits<const char*> { const int value = DBUS_TYPE_STRING; const bool is_fixed = false; };
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
template<class T>
|
template <class T>
|
||||||
const int dbus_type_identifier_v = dbus_type_identifier<T>().value;
|
const int dbus_type_identifier = dbus_type_traits<T>().value;
|
||||||
} //namespace detail
|
|
||||||
|
template <class T>
|
||||||
|
const bool is_fixed = dbus_type_traits<T>().is_fiexd;
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
class DBusMessageIter_wrap {
|
class DBusMessageIter_wrap {
|
||||||
|
public:
|
||||||
|
DBusMessageIter_wrap(DBusMessage* msg, libdbus_loader* loader);
|
||||||
|
DBusMessageIter_wrap(DBusMessageIter iter, libdbus_loader* loader);
|
||||||
|
|
||||||
public:
|
// Type accessors
|
||||||
DBusMessageIter_wrap(DBusMessage* msg, libdbus_loader* loader)
|
int type() const noexcept { return m_type; }
|
||||||
{
|
|
||||||
m_DBus = loader;
|
|
||||||
if(msg){
|
|
||||||
m_DBus->message_iter_init(msg, &m_Iter);
|
|
||||||
m_resolved_iter = resolve_variants();
|
|
||||||
m_type = m_DBus->message_iter_get_arg_type(&m_resolved_iter);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
m_type = DBUS_TYPE_INVALID;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DBusMessageIter_wrap(DBusMessageIter iter, libdbus_loader* loader)
|
|
||||||
: m_Iter(iter), m_DBus(loader)
|
|
||||||
{
|
|
||||||
m_resolved_iter = resolve_variants();
|
|
||||||
m_type = m_DBus->message_iter_get_arg_type(&m_resolved_iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int type() const noexcept { return m_type; }
|
|
||||||
bool is_unsigned() const noexcept;
|
bool is_unsigned() const noexcept;
|
||||||
bool is_signed() const noexcept;
|
bool is_signed() const noexcept;
|
||||||
bool is_string() const noexcept;
|
bool is_string() const noexcept;
|
||||||
bool is_double() const noexcept;
|
bool is_double() const noexcept;
|
||||||
bool is_primitive() const noexcept;
|
bool is_primitive() const noexcept;
|
||||||
bool is_array() const noexcept;
|
bool is_array() const noexcept;
|
||||||
operator bool() const noexcept {
|
operator bool() const noexcept { return type() != DBUS_TYPE_INVALID; }
|
||||||
return type() != DBUS_TYPE_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Value accessors
|
||||||
template<class T>
|
// Primitives
|
||||||
|
template <class T>
|
||||||
auto get_primitive() -> T;
|
auto get_primitive() -> T;
|
||||||
auto get_unsigned() -> uint64_t;
|
auto get_unsigned() -> uint64_t;
|
||||||
auto get_signed() -> int64_t;
|
auto get_signed() -> int64_t;
|
||||||
auto get_stringified() -> std::string;
|
auto get_stringified() -> std::string;
|
||||||
|
|
||||||
|
// Composites
|
||||||
auto get_array_iter() -> DBusMessageIter_wrap;
|
auto get_array_iter() -> DBusMessageIter_wrap;
|
||||||
auto get_dict_entry_iter() -> DBusMessageIter_wrap;
|
auto get_dict_entry_iter() -> DBusMessageIter_wrap;
|
||||||
|
|
||||||
|
// Looping
|
||||||
|
template <class Callable>
|
||||||
|
void array_for_each(Callable);
|
||||||
|
template <class Callable>
|
||||||
|
void array_for_each_stringify(Callable);
|
||||||
|
template <class T, class Callable>
|
||||||
|
void array_for_each_value(Callable);
|
||||||
|
|
||||||
|
template <class Callable>
|
||||||
|
void string_map_for_each(Callable);
|
||||||
|
template <class Callable>
|
||||||
|
void string_multimap_for_each_stringify(Callable);
|
||||||
|
|
||||||
auto next() {
|
auto next() {
|
||||||
|
if (not *this) return *this;
|
||||||
m_DBus->message_iter_next(&m_Iter);
|
m_DBus->message_iter_next(&m_Iter);
|
||||||
// Resolve any variants
|
// Resolve any variants
|
||||||
m_resolved_iter = resolve_variants();
|
m_resolved_iter = resolve_variants();
|
||||||
m_type = m_DBus->message_iter_get_arg_type(&m_resolved_iter);
|
m_type = m_DBus->message_iter_get_arg_type(&m_resolved_iter);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
private:
|
|
||||||
|
private:
|
||||||
DBusMessageIter resolve_variants() {
|
DBusMessageIter resolve_variants() {
|
||||||
auto iter = m_Iter;
|
auto iter = m_Iter;
|
||||||
auto field_type = m_DBus->message_iter_get_arg_type(&m_Iter);
|
auto field_type = m_DBus->message_iter_get_arg_type(&m_Iter);
|
||||||
while(field_type == DBUS_TYPE_VARIANT){
|
while (field_type == DBUS_TYPE_VARIANT) {
|
||||||
m_DBus->message_iter_recurse(&iter, &iter);
|
m_DBus->message_iter_recurse(&iter, &iter);
|
||||||
field_type = m_DBus->message_iter_get_arg_type(&iter);
|
field_type = m_DBus->message_iter_get_arg_type(&iter);
|
||||||
}
|
}
|
||||||
@ -91,23 +94,33 @@ private:
|
|||||||
libdbus_loader* m_DBus;
|
libdbus_loader* m_DBus;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DBusMessageIter_wrap::DBusMessageIter_wrap(DBusMessage* msg,
|
||||||
|
libdbus_loader* loader) {
|
||||||
|
m_DBus = loader;
|
||||||
|
if (msg) {
|
||||||
|
m_DBus->message_iter_init(msg, &m_Iter);
|
||||||
|
m_resolved_iter = resolve_variants();
|
||||||
|
m_type = m_DBus->message_iter_get_arg_type(&m_resolved_iter);
|
||||||
|
} else {
|
||||||
|
m_type = DBUS_TYPE_INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DBusMessageIter_wrap::DBusMessageIter_wrap(DBusMessageIter iter,
|
||||||
|
libdbus_loader* loader)
|
||||||
|
: m_Iter(iter), m_DBus(loader) {
|
||||||
|
m_resolved_iter = resolve_variants();
|
||||||
|
m_type = m_DBus->message_iter_get_arg_type(&m_resolved_iter);
|
||||||
|
}
|
||||||
|
|
||||||
bool DBusMessageIter_wrap::is_unsigned() const noexcept {
|
bool DBusMessageIter_wrap::is_unsigned() const noexcept {
|
||||||
return (
|
return ((type() == DBUS_TYPE_BYTE) || (type() == DBUS_TYPE_INT16) ||
|
||||||
(type() == DBUS_TYPE_BYTE) ||
|
(type() == DBUS_TYPE_INT32) || (type() == DBUS_TYPE_INT64));
|
||||||
(type() == DBUS_TYPE_INT16) ||
|
|
||||||
(type() == DBUS_TYPE_INT32) ||
|
|
||||||
(type() == DBUS_TYPE_INT64)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DBusMessageIter_wrap::is_signed() const noexcept {
|
bool DBusMessageIter_wrap::is_signed() const noexcept {
|
||||||
return (
|
return ((type() == DBUS_TYPE_INT16) || (type() == DBUS_TYPE_INT32) ||
|
||||||
(type() == DBUS_TYPE_INT16) ||
|
(type() == DBUS_TYPE_INT64));
|
||||||
(type() == DBUS_TYPE_INT32) ||
|
|
||||||
(type() == DBUS_TYPE_INT64)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DBusMessageIter_wrap::is_string() const noexcept {
|
bool DBusMessageIter_wrap::is_string() const noexcept {
|
||||||
@ -119,24 +132,19 @@ bool DBusMessageIter_wrap::is_double() const noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool DBusMessageIter_wrap::is_primitive() const noexcept {
|
bool DBusMessageIter_wrap::is_primitive() const noexcept {
|
||||||
return (
|
return (is_double() || is_signed() || is_unsigned() || is_string());
|
||||||
is_double() ||
|
|
||||||
is_signed() ||
|
|
||||||
is_unsigned() ||
|
|
||||||
is_string()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DBusMessageIter_wrap::is_array() const noexcept {
|
bool DBusMessageIter_wrap::is_array() const noexcept {
|
||||||
return (type() == DBUS_TYPE_ARRAY);
|
return (type() == DBUS_TYPE_ARRAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
template<class T>
|
|
||||||
auto DBusMessageIter_wrap::get_primitive() -> T {
|
auto DBusMessageIter_wrap::get_primitive() -> T {
|
||||||
auto requested_type = detail::dbus_type_identifier_v<T>;
|
auto requested_type = detail::dbus_type_identifier<T>;
|
||||||
if(requested_type != type()){
|
if (requested_type != type()) {
|
||||||
std::cerr << "Type mismatch: '" << (char) requested_type << "' vs '" << (char) type() << "'\n";
|
std::cerr << "Type mismatch: '" << ((char)requested_type) << "' vs '"
|
||||||
|
<< (char)type() << "'";
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
exit(-1);
|
exit(-1);
|
||||||
#else
|
#else
|
||||||
@ -149,55 +157,53 @@ auto DBusMessageIter_wrap::get_primitive() -> T {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template <>
|
||||||
auto DBusMessageIter_wrap::get_primitive<std::string>() -> std::string {
|
auto DBusMessageIter_wrap::get_primitive<std::string>() -> std::string {
|
||||||
return std::string(get_primitive<const char*>());
|
return std::string(get_primitive<const char*>());
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t DBusMessageIter_wrap::get_unsigned() {
|
uint64_t DBusMessageIter_wrap::get_unsigned() {
|
||||||
auto t = type();
|
auto t = type();
|
||||||
switch (t)
|
switch (t) {
|
||||||
{
|
case DBUS_TYPE_BYTE:
|
||||||
case DBUS_TYPE_BYTE:
|
return get_primitive<uint8_t>();
|
||||||
return get_primitive<uint8_t>();
|
case DBUS_TYPE_UINT16:
|
||||||
case DBUS_TYPE_UINT16:
|
return get_primitive<uint16_t>();
|
||||||
return get_primitive<uint16_t>();
|
case DBUS_TYPE_UINT32:
|
||||||
case DBUS_TYPE_UINT32:
|
return get_primitive<uint32_t>();
|
||||||
return get_primitive<uint32_t>();
|
case DBUS_TYPE_UINT64:
|
||||||
case DBUS_TYPE_UINT64:
|
return get_primitive<uint64_t>();
|
||||||
return get_primitive<uint64_t>();
|
default:
|
||||||
default:
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t DBusMessageIter_wrap::get_signed() {
|
int64_t DBusMessageIter_wrap::get_signed() {
|
||||||
auto t = type();
|
auto t = type();
|
||||||
switch (t)
|
switch (t) {
|
||||||
{
|
case DBUS_TYPE_INT16:
|
||||||
case DBUS_TYPE_INT16:
|
return get_primitive<int16_t>();
|
||||||
return get_primitive<int16_t>();
|
case DBUS_TYPE_INT32:
|
||||||
case DBUS_TYPE_INT32:
|
return get_primitive<int32_t>();
|
||||||
return get_primitive<int32_t>();
|
case DBUS_TYPE_INT64:
|
||||||
case DBUS_TYPE_INT64:
|
return get_primitive<int64_t>();
|
||||||
return get_primitive<int64_t>();
|
default:
|
||||||
default:
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto DBusMessageIter_wrap::get_stringified() -> std::string {
|
auto DBusMessageIter_wrap::get_stringified() -> std::string {
|
||||||
if(is_string()) return get_primitive<std::string>();
|
if (is_string()) return get_primitive<std::string>();
|
||||||
if(is_unsigned()) return std::to_string(get_unsigned());
|
if (is_unsigned()) return std::to_string(get_unsigned());
|
||||||
if(is_signed()) return std::to_string(get_signed());
|
if (is_signed()) return std::to_string(get_signed());
|
||||||
if(is_double()) return std::to_string(get_primitive<double>());
|
if (is_double()) return std::to_string(get_primitive<double>());
|
||||||
std::cerr << "stringify failed\n";
|
std::cerr << "stringify failed\n";
|
||||||
return std::string();
|
return std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto DBusMessageIter_wrap::get_array_iter() -> DBusMessageIter_wrap {
|
auto DBusMessageIter_wrap::get_array_iter() -> DBusMessageIter_wrap {
|
||||||
if(not is_array()) {
|
if (not is_array()) {
|
||||||
std::cerr << "Not an array\n";
|
std::cerr << "Not an array; " << (char)type() << "\n";
|
||||||
return DBusMessageIter_wrap(DBusMessageIter{}, m_DBus);
|
return DBusMessageIter_wrap(DBusMessageIter{}, m_DBus);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,8 +213,8 @@ auto DBusMessageIter_wrap::get_array_iter() -> DBusMessageIter_wrap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto DBusMessageIter_wrap::get_dict_entry_iter() -> DBusMessageIter_wrap {
|
auto DBusMessageIter_wrap::get_dict_entry_iter() -> DBusMessageIter_wrap {
|
||||||
if(type() != DBUS_TYPE_DICT_ENTRY){
|
if (type() != DBUS_TYPE_DICT_ENTRY) {
|
||||||
std::cerr << "Not a dict entry\n";
|
std::cerr << "Not a dict entry" << (char)type() << "\n";
|
||||||
return DBusMessageIter_wrap(DBusMessageIter{}, m_DBus);
|
return DBusMessageIter_wrap(DBusMessageIter{}, m_DBus);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,17 +223,34 @@ auto DBusMessageIter_wrap::get_dict_entry_iter() -> DBusMessageIter_wrap {
|
|||||||
return DBusMessageIter_wrap(ret, m_DBus);
|
return DBusMessageIter_wrap(ret, m_DBus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class T, class Callable>
|
||||||
|
void DBusMessageIter_wrap::array_for_each_value(Callable action) {
|
||||||
|
auto iter = get_array_iter();
|
||||||
|
for (; iter; iter.next()) {
|
||||||
|
action(iter.get_primitive<T>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Callable>
|
||||||
|
void DBusMessageIter_wrap::array_for_each(Callable action) {
|
||||||
|
auto iter = get_array_iter();
|
||||||
|
for (; iter; iter.next()) {
|
||||||
|
action(iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Callable>
|
||||||
|
void DBusMessageIter_wrap::array_for_each_stringify(Callable action) {
|
||||||
|
auto iter = get_array_iter();
|
||||||
|
for (; iter; iter.next()) {
|
||||||
|
action(iter.get_stringified());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void DBusMessageIter_wrap::string_map_for_each(T action) {
|
||||||
// Precondition: iter points to a dict of string -> any
|
auto iter = get_array_iter();
|
||||||
// executes action(key, value_iter) for all entries
|
for (; iter; iter.next()) {
|
||||||
template<class T>
|
|
||||||
void string_map_for_each(DBusMessageIter_wrap iter, T action) {
|
|
||||||
iter = iter.get_array_iter();
|
|
||||||
for(; iter; iter.next()) {
|
|
||||||
auto it = iter.get_dict_entry_iter();
|
auto it = iter.get_dict_entry_iter();
|
||||||
auto key = it.get_primitive<std::string>();
|
auto key = it.get_primitive<std::string>();
|
||||||
|
|
||||||
@ -236,127 +259,103 @@ void string_map_for_each(DBusMessageIter_wrap iter, T action) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T, class Callable>
|
template <class T>
|
||||||
void array_for_each(DBusMessageIter_wrap iter, Callable action) {
|
void DBusMessageIter_wrap::string_multimap_for_each_stringify(T action) {
|
||||||
iter = iter.get_array_iter();
|
string_map_for_each([&action](const std::string& key, DBusMessageIter_wrap it) {
|
||||||
for(; iter; iter.next()){
|
if (it.is_array()) {
|
||||||
action(iter.get_primitive<T>());
|
it.array_for_each_stringify(
|
||||||
}
|
[&](const std::string& val) { action(key, val); });
|
||||||
|
} else if (it.is_primitive()) {
|
||||||
|
action(key, it.get_stringified());
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Callable>
|
|
||||||
void array_for_each_stringify(DBusMessageIter_wrap iter, Callable action) {
|
|
||||||
iter = iter.get_array_iter();
|
|
||||||
for(; iter; iter.next()){
|
|
||||||
action(iter.get_stringified());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
void string_multimap_for_each_stringify(DBusMessageIter_wrap iter, T action) {
|
|
||||||
string_map_for_each(iter, [&](const std::string& key, DBusMessageIter_wrap it){
|
|
||||||
if(it.is_array()){
|
|
||||||
array_for_each_stringify(it, [&](const std::string& val){
|
|
||||||
action(key, val);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if(it.is_primitive()){
|
|
||||||
action(key, it.get_stringified());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class DBusMessage_wrap {
|
class DBusMessage_wrap {
|
||||||
public:
|
public:
|
||||||
DBusMessage_wrap(DBusMessage* msg, libdbus_loader* ldr, bool owning = false)
|
DBusMessage_wrap(DBusMessage* msg, libdbus_loader* ldr, bool owning = false)
|
||||||
: m_owning(owning), m_msg(msg), m_DBus(ldr)
|
: m_owning(owning), m_msg(msg), m_DBus(ldr) {}
|
||||||
{}
|
|
||||||
|
|
||||||
~DBusMessage_wrap(){
|
~DBusMessage_wrap() { free_if_owning(); }
|
||||||
free_if_owning();
|
|
||||||
}
|
|
||||||
|
|
||||||
DBusMessage_wrap(const DBusMessage_wrap&) = delete;
|
DBusMessage_wrap(const DBusMessage_wrap&) = delete;
|
||||||
DBusMessage_wrap(DBusMessage_wrap&&) = default;
|
DBusMessage_wrap(DBusMessage_wrap&&) = default;
|
||||||
|
|
||||||
operator bool() const {
|
operator bool() const noexcept { return m_msg != nullptr; }
|
||||||
return m_msg != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
template <class T>
|
||||||
DBusMessage_wrap& argument(T arg) {
|
DBusMessage_wrap& argument(T arg);
|
||||||
if(not m_msg) return *this;
|
|
||||||
if(not m_DBus->message_append_args(
|
|
||||||
m_msg,
|
|
||||||
detail::dbus_type_identifier_v<T>,
|
|
||||||
&arg,
|
|
||||||
DBUS_TYPE_INVALID
|
|
||||||
)){
|
|
||||||
free_if_owning();
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
DBusMessage_wrap send_with_reply_and_block(DBusConnection* conn, int timeout) {
|
DBusMessage_wrap send_with_reply_and_block(DBusConnection* conn,
|
||||||
if(not m_msg){
|
int timeout);
|
||||||
return DBusMessage_wrap(nullptr, m_DBus);
|
|
||||||
}
|
|
||||||
DBusError err;
|
|
||||||
m_DBus->error_init(&err);
|
|
||||||
auto reply = m_DBus->connection_send_with_reply_and_block(
|
|
||||||
conn,
|
|
||||||
m_msg,
|
|
||||||
timeout,
|
|
||||||
&err
|
|
||||||
);
|
|
||||||
if(reply == nullptr) {
|
|
||||||
std::cerr << "MangoHud[" << __func__ << "]: " << err.message << "\n";
|
|
||||||
free_if_owning();
|
|
||||||
m_DBus->error_free(&err);
|
|
||||||
}
|
|
||||||
return DBusMessage_wrap(reply, m_DBus, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
DBusMessageIter_wrap iter() {
|
DBusMessageIter_wrap iter() { return DBusMessageIter_wrap(m_msg, m_DBus); }
|
||||||
return DBusMessageIter_wrap(m_msg, m_DBus);
|
|
||||||
}
|
|
||||||
|
|
||||||
static DBusMessage_wrap new_method_call(
|
static DBusMessage_wrap new_method_call(const std::string& bus_name,
|
||||||
const std::string& bus_name,
|
const std::string& path,
|
||||||
const std::string& path,
|
const std::string& iface,
|
||||||
const std::string& iface,
|
const std::string& method,
|
||||||
const std::string& method,
|
libdbus_loader* loader);
|
||||||
libdbus_loader* loader
|
|
||||||
){
|
private:
|
||||||
auto msg = loader->message_new_method_call(
|
void free_if_owning();
|
||||||
(bus_name.empty()) ? nullptr : bus_name.c_str(),
|
|
||||||
path.c_str(),
|
|
||||||
(iface.empty()) ? nullptr : iface.c_str(),
|
|
||||||
method.c_str()
|
|
||||||
);
|
|
||||||
return DBusMessage_wrap(msg, loader, true);
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
void free_if_owning() {
|
|
||||||
if(m_msg and m_owning) {
|
|
||||||
m_DBus->message_unref(m_msg);
|
|
||||||
}
|
|
||||||
m_msg = nullptr;
|
|
||||||
}
|
|
||||||
bool m_owning;
|
bool m_owning;
|
||||||
DBusMessage* m_msg;
|
DBusMessage* m_msg;
|
||||||
libdbus_loader* m_DBus;
|
libdbus_loader* m_DBus;
|
||||||
std::vector<std::string> m_args;
|
std::vector<std::string> m_args;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template <class T>
|
||||||
DBusMessage_wrap& DBusMessage_wrap::argument<const std::string&>(const std::string& str)
|
DBusMessage_wrap& DBusMessage_wrap::argument(T arg) {
|
||||||
{
|
if (not m_msg) return *this;
|
||||||
|
if (not m_DBus->message_append_args(m_msg, detail::dbus_type_identifier<T>,
|
||||||
|
&arg, DBUS_TYPE_INVALID)) {
|
||||||
|
free_if_owning();
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
DBusMessage_wrap& DBusMessage_wrap::argument<const std::string&>(
|
||||||
|
const std::string& str) {
|
||||||
return argument<const char*>(str.c_str());
|
return argument<const char*>(str.c_str());
|
||||||
}
|
}
|
||||||
} //namespace DBus_helpers
|
|
||||||
|
|
||||||
|
DBusMessage_wrap DBusMessage_wrap::send_with_reply_and_block(
|
||||||
|
DBusConnection* conn, int timeout) {
|
||||||
|
if (not m_msg) {
|
||||||
|
return DBusMessage_wrap(nullptr, m_DBus);
|
||||||
|
}
|
||||||
|
DBusError err;
|
||||||
|
m_DBus->error_init(&err);
|
||||||
|
auto reply = m_DBus->connection_send_with_reply_and_block(conn, m_msg,
|
||||||
|
timeout, &err);
|
||||||
|
if (reply == nullptr) {
|
||||||
|
std::cerr << "MangoHud[" << __func__ << "]: " << err.message << "\n";
|
||||||
|
free_if_owning();
|
||||||
|
m_DBus->error_free(&err);
|
||||||
|
}
|
||||||
|
return DBusMessage_wrap(reply, m_DBus, true);
|
||||||
|
}
|
||||||
|
|
||||||
#endif //MANGOHUD_DBUS_HELPERS
|
DBusMessage_wrap DBusMessage_wrap::new_method_call(const std::string& bus_name,
|
||||||
|
const std::string& path,
|
||||||
|
const std::string& iface,
|
||||||
|
const std::string& method,
|
||||||
|
libdbus_loader* loader) {
|
||||||
|
auto msg = loader->message_new_method_call(
|
||||||
|
(bus_name.empty()) ? nullptr : bus_name.c_str(), path.c_str(),
|
||||||
|
(iface.empty()) ? nullptr : iface.c_str(), method.c_str());
|
||||||
|
return DBusMessage_wrap(msg, loader, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DBusMessage_wrap::free_if_owning() {
|
||||||
|
if (m_msg and m_owning) {
|
||||||
|
m_DBus->message_unref(m_msg);
|
||||||
|
}
|
||||||
|
m_msg = nullptr;
|
||||||
|
}
|
||||||
|
} // namespace DBus_helpers
|
||||||
|
|
||||||
|
#endif // MANGOHUD_DBUS_HELPERS
|
146
src/dbus_info.h
146
src/dbus_info.h
@ -3,31 +3,31 @@
|
|||||||
#define MANGOHUD_DBUS_INFO_H
|
#define MANGOHUD_DBUS_INFO_H
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <stdexcept>
|
|
||||||
#include <thread>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <unordered_map>
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "loaders/loader_dbus.h"
|
#include "loaders/loader_dbus.h"
|
||||||
|
|
||||||
struct metadata {
|
struct metadata {
|
||||||
//std::vector<std::string> artists;
|
// std::vector<std::string> artists;
|
||||||
std::string artists; // pre-concatenate
|
std::string artists; // pre-concatenate
|
||||||
std::string title;
|
std::string title;
|
||||||
std::string album;
|
std::string album;
|
||||||
std::string something;
|
std::string something;
|
||||||
std::string artUrl;
|
std::string artUrl;
|
||||||
bool playing = false;
|
bool playing = false;
|
||||||
|
|
||||||
bool valid = false;
|
bool valid = false;
|
||||||
bool got_song_data = false;
|
bool got_song_data = false;
|
||||||
bool got_playback_data = false;
|
bool got_playback_data = false;
|
||||||
|
|
||||||
void clear()
|
void clear() {
|
||||||
{
|
|
||||||
artists.clear();
|
artists.clear();
|
||||||
title.clear();
|
title.clear();
|
||||||
album.clear();
|
album.clear();
|
||||||
@ -51,101 +51,79 @@ struct mutexed_metadata {
|
|||||||
} ticker;
|
} ticker;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SignalType
|
enum SignalType {
|
||||||
{
|
|
||||||
ST_NAMEOWNERCHANGED,
|
ST_NAMEOWNERCHANGED,
|
||||||
ST_PROPERTIESCHANGED,
|
ST_PROPERTIESCHANGED,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
extern struct mutexed_metadata main_metadata;
|
extern struct mutexed_metadata main_metadata;
|
||||||
|
|
||||||
namespace dbusmgr {
|
namespace dbusmgr {
|
||||||
|
|
||||||
class dbus_manager;
|
class dbus_manager;
|
||||||
using signal_handler_func = bool (dbus_manager::*)(DBusMessage*, const char*);
|
using signal_handler_func = bool (dbus_manager::*)(DBusMessage*, const char*);
|
||||||
|
|
||||||
struct DBusSignal
|
struct DBusSignal {
|
||||||
{
|
const char* intf;
|
||||||
const char * intf;
|
const char* signal;
|
||||||
const char * signal;
|
signal_handler_func handler;
|
||||||
signal_handler_func handler;
|
};
|
||||||
};
|
|
||||||
|
|
||||||
using callback_func = std::function<void(/*metadata*/)>;
|
class dbus_manager {
|
||||||
|
public:
|
||||||
|
dbus_manager() {}
|
||||||
|
|
||||||
enum CBENUM {
|
~dbus_manager();
|
||||||
CB_CONNECTED,
|
|
||||||
CB_DISCONNECTED,
|
|
||||||
CB_NEW_METADATA,
|
|
||||||
};
|
|
||||||
|
|
||||||
class dbus_manager
|
bool init(const std::string& requested_player);
|
||||||
{
|
void deinit();
|
||||||
public:
|
bool get_media_player_metadata(metadata& meta, std::string name = "");
|
||||||
dbus_manager()
|
void connect_to_signals();
|
||||||
{
|
void disconnect_from_signals();
|
||||||
}
|
DBusConnection* get_conn() const { return m_dbus_conn; }
|
||||||
|
|
||||||
~dbus_manager();
|
libdbus_loader& dbus() { return m_dbus_ldr; }
|
||||||
|
|
||||||
bool init(const std::string& requested_player);
|
protected:
|
||||||
void deinit();
|
void stop_thread();
|
||||||
bool get_media_player_metadata(metadata& meta, std::string name = "");
|
void start_thread();
|
||||||
void add_callback(CBENUM type, callback_func func);
|
void dbus_thread();
|
||||||
void connect_to_signals();
|
|
||||||
void disconnect_from_signals();
|
|
||||||
DBusConnection* get_conn() const {
|
|
||||||
return m_dbus_conn;
|
|
||||||
}
|
|
||||||
|
|
||||||
libdbus_loader& dbus() {
|
bool dbus_list_name_to_owner();
|
||||||
return m_dbus_ldr;
|
bool select_active_player();
|
||||||
}
|
|
||||||
|
|
||||||
|
static DBusHandlerResult filter_signals(DBusConnection*, DBusMessage*,
|
||||||
|
void*);
|
||||||
|
|
||||||
protected:
|
bool handle_properties_changed(DBusMessage*, const char*);
|
||||||
void stop_thread();
|
bool handle_name_owner_changed(DBusMessage*, const char*);
|
||||||
void start_thread();
|
|
||||||
void dbus_thread();
|
|
||||||
|
|
||||||
bool dbus_list_name_to_owner();
|
void onNewPlayer(
|
||||||
bool select_active_player(metadata* meta = nullptr);
|
metadata& meta); // A different player has become the active player
|
||||||
|
void onNoPlayer(); // There is no longer any player active
|
||||||
|
void onPlayerUpdate(
|
||||||
|
metadata& meta); // The active player has sent an update
|
||||||
|
|
||||||
static DBusHandlerResult filter_signals(DBusConnection*, DBusMessage*, void*);
|
DBusError m_error;
|
||||||
|
DBusConnection* m_dbus_conn = nullptr;
|
||||||
|
bool m_quit = false;
|
||||||
|
bool m_inited = false;
|
||||||
|
std::thread m_thread;
|
||||||
|
libdbus_loader m_dbus_ldr;
|
||||||
|
std::unordered_map<std::string, std::string> m_name_owners;
|
||||||
|
std::string m_requested_player;
|
||||||
|
std::string m_active_player;
|
||||||
|
|
||||||
bool handle_properties_changed(DBusMessage*, const char*);
|
const std::array<DBusSignal, 2> m_signals{{
|
||||||
bool handle_name_owner_changed(DBusMessage*, const char*);
|
{"org.freedesktop.DBus", "NameOwnerChanged",
|
||||||
|
&dbus_manager::handle_name_owner_changed},
|
||||||
|
{"org.freedesktop.DBus.Properties", "PropertiesChanged",
|
||||||
|
&dbus_manager::handle_properties_changed},
|
||||||
|
}};
|
||||||
|
};
|
||||||
|
|
||||||
DBusError m_error;
|
extern dbus_manager dbus_mgr;
|
||||||
DBusConnection * m_dbus_conn = nullptr;
|
} // namespace dbusmgr
|
||||||
DBusMessage * m_dbus_msg = nullptr;
|
|
||||||
DBusMessage * m_dbus_reply = nullptr;
|
|
||||||
bool m_quit = false;
|
|
||||||
bool m_inited = false;
|
|
||||||
std::thread m_thread;
|
|
||||||
std::map<CBENUM, callback_func> m_callbacks;
|
|
||||||
libdbus_loader m_dbus_ldr;
|
|
||||||
std::unordered_map<std::string, std::string> m_name_owners;
|
|
||||||
std::string m_requested_player;
|
|
||||||
std::string m_active_player;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const std::array<DBusSignal, 2> m_signals {{
|
|
||||||
{ "org.freedesktop.DBus", "NameOwnerChanged", &dbus_manager::handle_name_owner_changed },
|
|
||||||
{ "org.freedesktop.DBus.Properties", "PropertiesChanged", &dbus_manager::handle_properties_changed },
|
|
||||||
}};
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
extern dbus_manager dbus_mgr;
|
|
||||||
}
|
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
bool get_media_player_metadata(dbusmgr::dbus_manager& dbus, const std::string& name, metadata& meta);
|
bool get_media_player_metadata(dbusmgr::dbus_manager& dbus, const std::string& name, metadata& meta);
|
||||||
|
|
||||||
#endif //MANGOHUD_DBUS_INFO_H
|
#endif //MANGOHUD_DBUS_INFO_H
|
||||||
=======
|
|
||||||
//bool get_media_player_metadata(dbusmgr::dbus_manager& dbus, const std::string& name, metadata& meta);
|
|
||||||
>>>>>>> 9c064df... Change the media player functionality to allow changing active media
|
|
||||||
|
Loading…
Reference in New Issue
Block a user