UniversalMusicController/dbus_client.c
2020-08-11 13:17:03 +02:00

253 lines
8.3 KiB
C

#define _DEFAULT_SOURCE
#include "dbus_client.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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 );
}