Fix some weird behaviour with non-spotify media players

Add DBusMessage_wrap to wrap/hide some dbus_message_* calls
pull/264/head
Lars Krämer 4 years ago
parent 6484e09f01
commit 72b86b4371

@ -52,9 +52,14 @@ public:
DBusMessageIter_wrap(DBusMessage* msg, libdbus_loader* loader)
{
m_DBus = loader;
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);
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)
@ -253,24 +258,114 @@ void string_multimap_for_each_stringify(DBusMessageIter_wrap iter, T action) {
});
}
class DBusMessage_wrap {
public:
DBusMessage_wrap(DBusMessage* msg, libdbus_loader* ldr, bool owning = false)
: m_owning(owning), m_msg(msg), m_DBus(ldr)
{}
~DBusMessage_wrap(){
free_if_owning();
}
DBusMessage_wrap(const DBusMessage_wrap&) = delete;
DBusMessage_wrap(DBusMessage_wrap&&) = default;
operator bool() const {
return m_msg != nullptr;
}
template<class T>
DBusMessage_wrap& argument(T arg) {
if(not m_msg) return *this;
if(not m_DBus->message_append_args(
m_msg,
dbus_type_identifier_v<T>,
&arg,
DBUS_TYPE_INVALID
)){
free_if_owning();
}
return *this;
}
DBusMessage_wrap send_with_reply_and_block(DBusConnection* conn) {
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,
DBUS_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() {
return DBusMessageIter_wrap(m_msg, m_DBus);
}
static 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);
}
private:
void free_if_owning() {
if(m_msg and m_owning) m_DBus->message_unref(m_msg);
m_msg = nullptr;
}
bool m_owning;
DBusMessage* m_msg;
libdbus_loader* m_DBus;
std::vector<std::string> m_args;
};
template<>
DBusMessage_wrap& DBusMessage_wrap::argument<const std::string&>(const std::string& str)
{
return argument<const char*>(str.c_str());
}
template<class T>
static void assign_metadata_value(metadata& meta, const std::string& key, const T& value) {
if(key == "PlaybackStatus") {
meta.playing = (value == "Playing");
meta.got_playback_data = true;
}
else if(key == "xesam:title"){
meta.title = value;
meta.got_song_data = true;
}
else if(key == "xesam:artist") {
if(meta.artists.empty()) meta.artists = value;
else meta.artists += ", " + value;
meta.artists = value;
meta.got_song_data = true;
}
else if(key == "xesam:album") {
meta.album = value;
meta.got_song_data = true;
}
else if(key == "mpris:artUrl"){
meta.artUrl = value;
meta.got_song_data = true;
}
}
@ -311,99 +406,76 @@ static void parse_mpris_properties(libdbus_loader& dbus, DBusMessage *msg, std::
if (not iter.is_array())
return;
std::cerr << "Parsing mpris update...\n";
string_map_for_each(iter, [&](std::string& key, DBusMessageIter_wrap it){
if(key == "Metadata"){
std::cerr << "\tMetadata:\n";
string_map_for_each(it, [&](const std::string& key, DBusMessageIter_wrap it){
if(it.is_primitive()){
auto val = it.get_stringified();
std::cerr << "\t\t" << key << " -> " << val << "\n";
assign_metadata_value(meta, key, val);
}
else if(it.is_array()){
std::string val;
array_for_each_stringify(it, [&](const std::string& str){
if(val.empty()){
val = str;
}
else {
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);
});
}
else if(key == "PlaybackStatus"){
assign_metadata_value(meta, key, it.get_stringified());
auto val = it.get_stringified();
std::cerr << "\tPlaybackStatus:\n";
std::cerr << "\t\t" << key << " -> " << val << "\n";
assign_metadata_value(meta, key, val);
}
});
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)
{
auto& dbus = dbus_mgr.dbus();
DBusError error;
DBusMessage * dbus_reply = nullptr;
DBusMessage * dbus_msg = nullptr;
// dbus-send --session --dest=org.freedesktop.DBus --type=method_call --print-reply /org/freedesktop/DBus org.freedesktop.DBus.GetNameOwner string:"org.mpris.MediaPlayer2.spotify"
if (nullptr == (dbus_msg = dbus.message_new_method_call("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "GetNameOwner"))) {
std::cerr << "MANGOHUD: " << __func__ << ": unable to allocate memory for dbus message\n";
return false;
}
if (!dbus.message_append_args (dbus_msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) {
dbus.message_unref(dbus_msg);
std::cerr << "MANGOHUD: " << __func__ << ": dbus_message_append_args failed\n";
return false;
}
dbus.error_init(&error);
if (nullptr == (dbus_reply = dbus.connection_send_with_reply_and_block(dbus_mgr.get_conn(), dbus_msg, DBUS_TIMEOUT, &error))) {
dbus.message_unref(dbus_msg);
std::cerr << "MANGOHUD: " << __func__ << ": "<< error.message << "\n";
dbus.error_free(&error);
return false;
}
const char* val = nullptr;
DBusMessageIter iter;
dbus.message_iter_init (dbus_reply, &iter);
if (dbus.message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
return false;
dbus.message_iter_get_basic(&iter, &val);
if (val)
name_owner = val;
dbus.message_unref(dbus_msg);
dbus.message_unref(dbus_reply);
dbus.error_free(&error);
auto reply = DBusMessage_wrap::new_method_call(
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"GetNameOwner",
&dbus_mgr.dbus()
).argument(name).send_with_reply_and_block(dbus_mgr.get_conn());
if(not reply) return false;
auto iter = reply.iter();
if(not iter.is_string()) return false;
name_owner = iter.get_primitive<std::string>();
return true;
}
bool dbus_get_player_property(dbusmgr::dbus_manager& dbus_mgr, metadata& meta, const char * dest, const char * prop)
{
auto& dbus = dbus_mgr.dbus();
DBusError error;
DBusMessage * dbus_reply = nullptr;
DBusMessage * dbus_msg = nullptr;
// dbus-send --print-reply --session --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:'org.mpris.MediaPlayer2.Player' string:'Metadata'
if (nullptr == (dbus_msg = dbus.message_new_method_call(dest, "/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties", "Get"))) {
std::cerr << "MANGOHUD: unable to allocate memory for dbus message" << std::endl;
return false;
}
static const char *v_STRINGS[] = {
"org.mpris.MediaPlayer2.Player",
};
if (!dbus.message_append_args (dbus_msg, DBUS_TYPE_STRING, &v_STRINGS[0], DBUS_TYPE_STRING, &prop, DBUS_TYPE_INVALID)) {
std::cerr << "MANGOHUD: dbus_message_append_args failed" << std::endl;
dbus.message_unref(dbus_msg);
return false;
}
dbus.error_init(&error);
if (nullptr == (dbus_reply = dbus.connection_send_with_reply_and_block(dbus_mgr.get_conn(), dbus_msg, DBUS_TIMEOUT, &error))) {
dbus.message_unref(dbus_msg);
std::cerr << "MANGOHUD: " << error.message << std::endl;
dbus.error_free(&error);
return false;
}
auto iter = DBusMessageIter_wrap(dbus_reply, &dbus);
auto reply = DBusMessage_wrap::new_method_call(
dest,
"/org/mpris/MediaPlayer2",
"org.freedesktop.DBus.Properties",
"Get",
&dbus_mgr.dbus()
).argument("org.mpris.MediaPlayer2.Player")
.argument(prop)
.send_with_reply_and_block(dbus_mgr.get_conn());
if(not reply) return false;
auto iter = reply.iter();
if(iter.is_array()){
string_multimap_for_each_stringify(iter, [&](const std::string& key, const std::string& val){
assign_metadata_value(meta, key, val);
@ -413,15 +485,8 @@ bool dbus_get_player_property(dbusmgr::dbus_manager& dbus_mgr, metadata& meta, c
assign_metadata_value(meta, prop, iter.get_stringified());
}
else {
dbus.message_unref(dbus_msg);
dbus.message_unref(dbus_reply);
dbus.error_free(&error);
return false;
}
dbus.message_unref(dbus_msg);
dbus.message_unref(dbus_reply);
dbus.error_free(&error);
return true;
}
@ -554,7 +619,13 @@ bool dbus_manager::handle_properties_changed(DBusMessage* msg, const char* sende
}
if (m_name_owners[m_active_player] == sender) {
std::lock_guard<std::mutex> lck(main_metadata.mtx);
main_metadata.meta = meta;
if(meta.got_song_data){
main_metadata.meta = meta;
main_metadata.meta.playing = true;
}
if(meta.got_playback_data){
main_metadata.meta.playing = meta.playing;
}
}
return true;
}
@ -665,7 +736,12 @@ bool dbus_manager::dbus_list_name_to_owner()
}
auto iter = DBusMessageIter_wrap(dbus_reply, &m_dbus_ldr);
if(not iter.is_array()) return false;
if(not iter.is_array()) {
m_dbus_ldr.message_unref(dbus_msg);
m_dbus_ldr.message_unref(dbus_reply);
m_dbus_ldr.error_free(&error);
return false;
}
array_for_each<std::string>(iter, [&](std::string name){
if(!starts_with(name.c_str(), "org.mpris.MediaPlayer2.")) return;
if(dbus_get_name_owner(dbus_mgr, owner, name.c_str())){

@ -35,6 +35,8 @@ struct metadata {
} ticker;
bool valid = false;
bool got_song_data = false;
bool got_playback_data = false;
void clear()
{

Loading…
Cancel
Save