#define _DEFAULT_SOURCE #include "dbus_client.h" #include #include #include void dbusQuery( DBusMessageIter *args, DBusMessage **msg, DBusConnection *conn, const char *target, const char *object, const char *interface, const char *method, const char **params ) { DBusPendingCall *pending; // create a new method call and check for errors *msg = dbus_message_new_method_call( target, object, interface, method ); if ( *msg == NULL ) { fprintf( stderr, "Message is NULL\n" ); exit( 1 ); } // append arguments if ( params != NULL ) { dbus_message_iter_init_append( *msg, args ); // iterate through params for ( const char **param = params; *param; ++param ) { if ( !dbus_message_iter_append_basic( args, DBUS_TYPE_STRING, param ) ) { fprintf( stderr, "Out Of Memory!\n" ); exit( 1 ); } } } // send message and get a handle for a reply if ( !dbus_connection_send_with_reply( conn, *msg, &pending, -1 ) ) { fprintf( stderr, "Out Of Memory!\n" ); exit( 1 ); } if ( pending == NULL ) { fprintf( stderr, "Pending Call is NULL\n" ); exit( 1 ); } dbus_connection_flush( conn ); dbus_message_unref( *msg ); // block until we recieve a reply dbus_pending_call_block( pending ); // get the reply message *msg = dbus_pending_call_steal_reply( pending ); if ( *msg == NULL ) { fprintf( stderr, "Reply Null\n" ); exit( 1 ); } dbus_pending_call_unref( pending ); dbus_message_iter_init( *msg, args ); } DBusConnection *dbusConnect() { DBusError err; dbus_error_init( &err ); DBusConnection *conn = dbus_bus_get( DBUS_BUS_SESSION, &err ); if ( dbus_error_is_set( &err ) ) { fprintf( stderr, "Connection Error (%s)\n", err.message ); dbus_error_free( &err ); exit( 1 ); } if ( NULL == conn ) { exit( 1 ); } return conn; } void dbusDisconnect( DBusConnection *conn ) { dbus_connection_close( conn ); } char **dbusGetMediaPlayers( DBusConnection *conn ) { DBusMessageIter args; DBusMessageIter string; DBusMessage *msg = NULL; dbusQuery( &args, &msg, conn, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "ListNames", NULL ); char **ret = malloc( sizeof( char * ) ); if ( ret == NULL ) { fprintf( stderr, "Out of memory" ); exit( 1 ); } ret[0] = NULL; size_t count = 0; char *path = NULL; do { dbus_message_iter_recurse( &args, &string ); do { dbus_message_iter_get_basic( &string, &path ); if ( strstr( path, "mpris" ) != NULL ) { count++; char **new = realloc( ret, ( count + 1 ) * sizeof( char * ) ); if ( new == NULL ) { fprintf( stderr, "Out of memory" ); exit( 1 ); } ret = new; ret[count - 1] = strdup( path ); if ( ret[count - 1] == NULL ) { fprintf( stderr, "Out of memory" ); exit( 1 ); } ret[count] = NULL; } } while ( dbus_message_iter_next( &string ) ); } while ( dbus_message_iter_next( &args ) ); dbus_message_unref( msg ); return ret; } struct song_metadata dbusGetSong( DBusConnection *conn, const char *player ) { struct song_metadata ret = { 0 }; DBusMessageIter args; DBusMessageIter array; DBusMessageIter dict; DBusMessageIter dict_entry; DBusMessageIter variant; DBusMessageIter artists; DBusMessage *msg = NULL; const char *params[3] = { "org.mpris.MediaPlayer2.Player", "Metadata", NULL }; dbusQuery( &args, &msg, conn, player, "/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties", "Get", params ); char *meta_name = NULL; char *meta_val = NULL; dbus_message_iter_recurse( &args, &array ); dbus_message_iter_recurse( &array, &dict ); do { dbus_message_iter_recurse( &dict, &dict_entry ); dbus_message_iter_get_basic( &dict_entry, &meta_name ); dbus_message_iter_next( &dict_entry ); dbus_message_iter_recurse( &dict_entry, &variant ); if ( !strcmp( meta_name, "xesam:artist" ) ) { dbus_message_iter_recurse( &variant, &artists ); dbus_message_iter_get_basic( &artists, &meta_val ); ret.artist = strdup( meta_val ); } else if ( dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_STRING ) { dbus_message_iter_get_basic( &variant, &meta_val ); if ( !strcmp( meta_name, "xesam:title" ) ) ret.title = strdup( meta_val ); else if ( !strcmp( meta_name, "xesam:album" ) ) ret.album = strdup( meta_val ); else if ( !strcmp( meta_name, "xesam:url" ) ) ret.file = strdup( meta_val ); else if ( !strcmp( meta_name, "mpris:artUrl" ) ) ret.art_uri = strdup( meta_val ); } else if ( dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_INT64 ) { if ( !strcmp( meta_name, "mpris:length" ) ) { dbus_message_iter_get_basic( &variant, &ret.duration ); } } } while ( dbus_message_iter_next( &dict ) ); dbus_message_unref( msg ); const char *params2[3] = { "org.mpris.MediaPlayer2.Player", "Position", NULL }; dbusQuery( &args, &msg, conn, player, "/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties", "Get", params2 ); dbus_message_iter_recurse( &args, &variant ); dbus_message_iter_get_basic( &variant, &ret.position ); return ret; } void dbusPlayPause( DBusConnection *conn, const char *player ) { DBusMessageIter args; DBusMessage *msg = NULL; dbusQuery( &args, &msg, conn, player, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2.Player", "PlayPause", NULL ); dbus_message_unref( msg ); } void dbusNext( DBusConnection *conn, const char *player ) { DBusMessageIter args; DBusMessage *msg = NULL; dbusQuery( &args, &msg, conn, player, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2.Player", "Next", NULL ); dbus_message_unref( msg ); } void dbusPrev( DBusConnection *conn, const char *player ) { DBusMessageIter args; DBusMessage *msg = NULL; dbusQuery( &args, &msg, conn, player, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2.Player", "Previous", NULL ); dbus_message_unref( msg ); } void dbusStop( DBusConnection *conn, const char *player ) { DBusMessageIter args; DBusMessage *msg = NULL; dbusQuery( &args, &msg, conn, player, "/org/mpris/MediaPlayer2", "org.mpris.MediaPlayer2.Player", "Stop", NULL ); dbus_message_unref( msg ); } char *dbusStatus( DBusConnection *conn, const char *player ) { DBusMessageIter args; DBusMessageIter string; DBusMessage *msg = NULL; const char *params[3] = { "org.mpris.MediaPlayer2.Player", "PlaybackStatus", NULL }; dbusQuery( &args, &msg, conn, player, "/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties", "Get", params ); char *meta = NULL; dbus_message_iter_recurse( &args, &string ); dbus_message_iter_get_basic( &string, &meta ); char *ret = strdup( meta ); // free reply dbus_message_unref( msg ); return ret; } bool dbusRunning( DBusConnection *conn, const char *player ) { char *status = dbusStatus( conn, player ); bool ret = strcmp( status, "Playing" ) == 0; ret |= strcmp( status, "Paused" ) == 0; free( status ); return ret; } bool dbusPlaying( DBusConnection *conn, const char *player ) { char *status = dbusStatus( conn, player ); bool ret = strcmp( status, "Playing" ) == 0; free( status ); return ret; } void dbusFreePlayers( char **dbus_players ) { for ( char **player = dbus_players; *player; ++player ) { free( *player ); } free( dbus_players ); }