Make DBus signal handling more event-based

pull/264/head
Lars Krämer 4 years ago
parent 5850643db4
commit 4bf7a3f2f0

@ -13,9 +13,13 @@ typedef std::vector<std::pair<std::string, std::string>> string_pair_vec;
typedef std::unordered_map<std::string, string_pair_vec> string_pair_vec_map;
typedef std::unordered_map<std::string, std::string> string_map;
namespace dbusmgr {
dbus_manager dbus_mgr;
}
#define DBUS_TIMEOUT 2000 // ms
std::string format_signal(const DBusSignal& s)
std::string format_signal(const dbusmgr::DBusSignal& s)
{
std::stringstream ss;
ss << "type='signal',interface='" << s.intf << "'";
@ -144,8 +148,10 @@ static void parse_mpris_properties(libdbus_loader& dbus, DBusMessage *msg, std::
dbus.message_iter_init (msg, &stack.back());
// Should be 'org.mpris.MediaPlayer2.Player'
if (!check_msg_arg(dbus, &stack.back(), DBUS_TYPE_STRING))
if (!check_msg_arg(dbus, &stack.back(), DBUS_TYPE_STRING)){
std::cerr << "Not a string\n";
return;
}
dbus.message_iter_get_basic(&stack.back(), &val_char);
source = val_char;
@ -154,7 +160,6 @@ static void parse_mpris_properties(libdbus_loader& dbus, DBusMessage *msg, std::
return;
dbus.message_iter_next (&stack.back());
//std::cerr << "type: " << (char)dbus.message_iter_get_arg_type(&stack.back()) << std::endl;
if (!check_msg_arg(dbus, &stack.back(), DBUS_TYPE_ARRAY))
return;
@ -455,8 +460,6 @@ bool dbus_get_name_owner(dbusmgr::dbus_manager& dbus_mgr, std::string& name_owne
return true;
}
bool dbus_get_player_property(dbusmgr::dbus_manager& dbus_mgr, string_pair_vec& entries, const char * dest, const char * prop)
{
auto& dbus = dbus_mgr.dbus();
@ -595,6 +598,86 @@ dbus_manager::~dbus_manager()
deinit();
}
DBusHandlerResult dbus_manager::filter_signals(DBusConnection* conn, DBusMessage* msg, void* userData) {
auto& manager = *reinterpret_cast<dbus_manager*>(userData);
for(auto& sig : manager.m_signals) {
if(manager.m_dbus_ldr.message_is_signal(msg, sig.intf, sig.signal)){
auto sender = manager.m_dbus_ldr.message_get_sender(msg);
if((manager.*(sig.handler))(msg, sender))
return DBUS_HANDLER_RESULT_HANDLED;
else
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) {
std::string source;
string_pair_vec_map entries_map;
//parse_property_changed(msg, source, entries);
parse_mpris_properties(m_dbus_ldr, msg, source, entries_map);
#ifndef NDEBUG
std::cerr << "Source: " << source << "\n";
#endif
if (source != "org.mpris.MediaPlayer2.Player")
return false;
if(m_active_player == "") {
select_active_player();
}
#ifndef NDEBUG
std::cerr << "active_player: " << m_active_player << "\n";
std::cerr << "active_player's owner: " << m_name_owners[m_active_player] << "\n";
std::cerr << "sender: " << sender << "\n";
#endif
if (m_name_owners[m_active_player] == sender) {
assign_metadata(main_metadata, entries_map);
}
return true;
}
bool dbus_manager::handle_name_owner_changed(DBusMessage* msg, const char* sender) {
DBusMessageIter iter;
m_dbus_ldr.message_iter_init (msg, &iter);
std::vector<std::string> str;
const char *value = nullptr;
while (m_dbus_ldr.message_iter_get_arg_type (&iter) == DBUS_TYPE_STRING) {
m_dbus_ldr.message_iter_get_basic (&iter, &value);
str.push_back(value);
m_dbus_ldr.message_iter_next (&iter);
}
// register new name
if (str.size() == 3
&& starts_with(str[0], "org.mpris.MediaPlayer2.")
&& !str[2].empty()
)
{
m_name_owners[str[0]] = str[2];
if(str[0] == m_requested_player){
select_active_player();
get_media_player_metadata(main_metadata);
}
}
// did a player quit?
if (str[2].empty()) {
if (str.size() == 3
&& str[0] == m_active_player
) {
main_metadata.clear();
m_name_owners.erase(str[0]);
select_active_player();
get_media_player_metadata(main_metadata);
}
}
return true;
}
void dbus_manager::connect_to_signals()
{
for (auto kv : m_signals) {
@ -607,12 +690,14 @@ void dbus_manager::connect_to_signals()
//return;
}
}
m_dbus_ldr.connection_add_filter(m_dbus_conn, filter_signals, reinterpret_cast<void*>(this), nullptr);
start_thread();
}
void dbus_manager::disconnect_from_signals()
{
m_dbus_ldr.connection_remove_filter(m_dbus_conn, filter_signals, reinterpret_cast<void*>(this));
for (auto kv : m_signals) {
auto signal = format_signal(kv);
m_dbus_ldr.bus_remove_match(m_dbus_conn, signal.c_str(), &m_error);
@ -693,112 +778,9 @@ void dbus_manager::start_thread()
void dbus_manager::dbus_thread()
{
(void)parse_property_changed;
DBusMessage *msg = nullptr;
// loop listening for signals being emmitted
while (!m_quit) {
// non blocking read of the next available message
if (!m_dbus_ldr.connection_read_write(m_dbus_conn, 0))
return; // connection closed
msg = m_dbus_ldr.connection_pop_message(m_dbus_conn);
// loop again if we haven't read a message
if (nullptr == msg) {
std::this_thread::yield();
//std::this_thread::sleep_for(ms(10));
continue;
}
for (auto& sig : m_signals) {
if (m_dbus_ldr.message_is_signal(msg, sig.intf, sig.signal))
{
const char *sender = m_dbus_ldr.message_get_sender(msg);
#ifndef NDEBUG
std::cerr << __func__ << ": " << sig.intf << "::" << sig.signal << "\n";
std::cerr << "Sender: " << sender << "\n";
#endif
switch (sig.type) {
case ST_PROPERTIESCHANGED:
{
std::string source;
string_pair_vec_map entries_map;
//parse_property_changed(msg, source, entries);
parse_mpris_properties(m_dbus_ldr, msg, source, entries_map);
#ifndef NDEBUG
std::cerr << "Source: " << source << "\n";
#endif
if (source != "org.mpris.MediaPlayer2.Player")
break;
if(m_active_player == "") {
select_active_player();
}
#ifndef NDEBUG
std::cerr << "active_player: " << m_active_player << "\n";
std::cerr << "active_player's owner: " << m_name_owners[m_active_player] << "\n";
std::cerr << "sender: " << sender << "\n";
#endif
if (m_name_owners[m_active_player] == sender) {
assign_metadata(main_metadata, entries_map);
}
}
break;
case ST_NAMEOWNERCHANGED:
{
DBusMessageIter iter;
m_dbus_ldr.message_iter_init (msg, &iter);
std::vector<std::string> str;
const char *value = nullptr;
while (m_dbus_ldr.message_iter_get_arg_type (&iter) == DBUS_TYPE_STRING) {
m_dbus_ldr.message_iter_get_basic (&iter, &value);
str.push_back(value);
m_dbus_ldr.message_iter_next (&iter);
}
// register new name
if (str.size() == 3
&& starts_with(str[0], "org.mpris.MediaPlayer2.")
&& !str[2].empty()
)
{
m_name_owners[str[0]] = str[2];
if(str[0] == m_requested_player){
select_active_player();
get_media_player_metadata(main_metadata);
}
}
// did a player quit?
if (str[2].empty()) {
if (str.size() == 3
&& str[0] == m_active_player
) {
main_metadata.clear();
m_name_owners.erase(str[0]);
select_active_player();
get_media_player_metadata(main_metadata);
}
}
}
break;
default:
break;
}
}
}
// free the message
m_dbus_ldr.message_unref(msg);
}
using namespace std::chrono_literals;
while(!m_quit && m_dbus_ldr.connection_read_write_dispatch(m_dbus_conn, 0))
std::this_thread::sleep_for(10ms);
}
dbus_manager dbus_mgr;
}

@ -55,16 +55,21 @@ enum SignalType
ST_PROPERTIESCHANGED,
};
struct DBusSignal
{
const char * intf;
const char * signal;
SignalType type;
};
extern struct metadata main_metadata;
namespace dbusmgr {
class dbus_manager;
using signal_handler_func = bool (dbus_manager::*)(DBusMessage*, const char*);
struct DBusSignal
{
const char * intf;
const char * signal;
signal_handler_func handler;
};
using callback_func = std::function<void(/*metadata*/)>;
enum CBENUM {
@ -105,6 +110,11 @@ namespace dbusmgr {
bool dbus_list_name_to_owner();
bool select_active_player();
static DBusHandlerResult filter_signals(DBusConnection*, DBusMessage*, void*);
bool handle_properties_changed(DBusMessage*, const char*);
bool handle_name_owner_changed(DBusMessage*, const char*);
DBusError m_error;
DBusConnection * m_dbus_conn = nullptr;
DBusMessage * m_dbus_msg = nullptr;
@ -121,8 +131,8 @@ namespace dbusmgr {
const std::array<DBusSignal, 2> m_signals {{
{ "org.freedesktop.DBus", "NameOwnerChanged", ST_NAMEOWNERCHANGED },
{ "org.freedesktop.DBus.Properties", "PropertiesChanged", ST_PROPERTIESCHANGED },
{ "org.freedesktop.DBus", "NameOwnerChanged", &dbus_manager::handle_name_owner_changed },
{ "org.freedesktop.DBus.Properties", "PropertiesChanged", &dbus_manager::handle_properties_changed },
}};
};

@ -63,6 +63,14 @@ bool libdbus_loader::Load(const std::string& library_name) {
return false;
}
connection_add_filter =
reinterpret_cast<decltype(this->connection_add_filter)>(
dlsym(library_, "dbus_connection_add_filter"));
if (!connection_add_filter) {
CleanUp(true);
return false;
}
connection_pop_message =
reinterpret_cast<decltype(this->connection_pop_message)>(
dlsym(library_, "dbus_connection_pop_message"));
@ -79,6 +87,22 @@ bool libdbus_loader::Load(const std::string& library_name) {
return false;
}
connection_read_write_dispatch =
reinterpret_cast<decltype(this->connection_read_write)>(
dlsym(library_, "dbus_connection_read_write_dispatch"));
if (!connection_read_write_dispatch) {
CleanUp(true);
return false;
}
connection_remove_filter =
reinterpret_cast<decltype(this->connection_remove_filter)>(
dlsym(library_, "dbus_connection_remove_filter"));
if (!connection_remove_filter) {
CleanUp(true);
return false;
}
connection_send_with_reply_and_block =
reinterpret_cast<decltype(this->connection_send_with_reply_and_block)>(
dlsym(library_, "dbus_connection_send_with_reply_and_block"));
@ -127,6 +151,22 @@ bool libdbus_loader::Load(const std::string& library_name) {
return false;
}
message_get_interface =
reinterpret_cast<decltype(this->message_get_interface)>(
dlsym(library_, "dbus_message_get_interface"));
if (!message_get_interface) {
CleanUp(true);
return false;
}
message_get_member =
reinterpret_cast<decltype(this->message_get_member)>(
dlsym(library_, "dbus_message_get_member"));
if (!message_get_member) {
CleanUp(true);
return false;
}
message_is_signal =
reinterpret_cast<decltype(this->message_is_signal)>(
dlsym(library_, "dbus_message_is_signal"));

@ -24,14 +24,20 @@ class libdbus_loader {
decltype(&::dbus_bus_get) bus_get;
decltype(&::dbus_bus_get_unique_name) bus_get_unique_name;
decltype(&::dbus_bus_remove_match) bus_remove_match;
decltype(&::dbus_connection_add_filter) connection_add_filter;
decltype(&::dbus_connection_pop_message) connection_pop_message;
decltype(&::dbus_connection_read_write) connection_read_write;
decltype(&::dbus_connection_read_write_dispatch) connection_read_write_dispatch;
decltype(&::dbus_connection_remove_filter) connection_remove_filter;
decltype(&::dbus_connection_send_with_reply_and_block) connection_send_with_reply_and_block;
decltype(&::dbus_connection_unref) connection_unref;
decltype(&::dbus_error_free) error_free;
decltype(&::dbus_error_init) error_init;
decltype(&::dbus_error_is_set) error_is_set;
decltype(&::dbus_message_append_args) message_append_args;
decltype(&::dbus_message_get_sender) message_get_sender;
decltype(&::dbus_message_get_interface) message_get_interface;
decltype(&::dbus_message_get_member) message_get_member;
decltype(&::dbus_message_is_signal) message_is_signal;
decltype(&::dbus_message_iter_get_arg_type) message_iter_get_arg_type;
decltype(&::dbus_message_iter_get_basic) message_iter_get_basic;
@ -42,7 +48,6 @@ class libdbus_loader {
decltype(&::dbus_message_unref) message_unref;
decltype(&::dbus_move_error) move_error;
decltype(&::dbus_threads_init_default) threads_init_default;
decltype(&::dbus_message_get_sender) message_get_sender;
private:

Loading…
Cancel
Save