Initial commit
This commit is contained in:
commit
2abd02f88f
24
.clang-format
Normal file
24
.clang-format
Normal file
@ -0,0 +1,24 @@
|
||||
---
|
||||
AccessModifierOffset: -4
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
BasedOnStyle: LLVM
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: 'false'
|
||||
ConstructorInitializerIndentWidth: 8
|
||||
Cpp11BracedListStyle: 'false'
|
||||
IndentWidth: '4'
|
||||
Language: Cpp
|
||||
PointerAlignment: Right
|
||||
SortIncludes: 'false'
|
||||
SpaceBeforeAssignmentOperators: 'true'
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceInEmptyParentheses: 'false'
|
||||
SpacesInAngles: 'true'
|
||||
SpacesInCStyleCastParentheses: 'true'
|
||||
SpacesInContainerLiterals: 'true'
|
||||
SpacesInParentheses: 'true'
|
||||
SpacesInSquareBrackets: 'false'
|
||||
Standard: Cpp11
|
||||
TabWidth: '4'
|
||||
UseTab: Never
|
||||
|
||||
...
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*.o
|
||||
universalmusiccontroller
|
16
Makefile
Normal file
16
Makefile
Normal file
@ -0,0 +1,16 @@
|
||||
CC ?= clang
|
||||
CFLAGS ?= -O2 -I/usr/include/dbus-1.0 -I/usr/lib/dbus-1.0/include/ -Wall -Wextra -g
|
||||
PREFIX ?= /usr/local/bin
|
||||
LDFLAGS ?= -ldbus-1 -lmpdclient
|
||||
|
||||
.PHONY: default
|
||||
default: universalmusiccontroller
|
||||
|
||||
universalmusiccontroller: main.c dbus_client.o mpd_client.o metadata.o
|
||||
$(CC) $(CFLAGS) -o $@ $^ ${LDFLAGS}
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $^ -o $@
|
||||
|
||||
clean:
|
||||
rm -Rf *.o universalmusiccontroller
|
215
dbus_client.c
Normal file
215
dbus_client.c
Normal file
@ -0,0 +1,215 @@
|
||||
#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 {
|
||||
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 );
|
||||
}
|
||||
} while ( dbus_message_iter_next( &dict ) );
|
||||
|
||||
dbus_message_unref( msg );
|
||||
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 );
|
||||
}
|
||||
|
||||
bool 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 );
|
||||
bool ret = strcmp( meta, "Playing" ) == 0;
|
||||
// free reply
|
||||
dbus_message_unref( msg );
|
||||
return ret;
|
||||
}
|
18
dbus_client.h
Normal file
18
dbus_client.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef DBUS_PLAYER_H
|
||||
#define DBUS_PLAYER_H
|
||||
#include <dbus/dbus.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "metadata.h"
|
||||
|
||||
DBusConnection *dbusConnect();
|
||||
void dbusDisconnect( DBusConnection *conn );
|
||||
char **dbusGetMediaPlayers( DBusConnection *conn );
|
||||
struct song_metadata dbusGetSong( DBusConnection *conn, const char *player );
|
||||
void dbusPlayPause( DBusConnection *conn, const char *player );
|
||||
void dbusNext( DBusConnection *conn, const char *player );
|
||||
void dbusPrev( DBusConnection *conn, const char *player );
|
||||
void dbusStop( DBusConnection *conn, const char *player );
|
||||
bool dbusStatus( DBusConnection *conn, const char *player );
|
||||
|
||||
#endif
|
39
main.c
Normal file
39
main.c
Normal file
@ -0,0 +1,39 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "metadata.h"
|
||||
#include "dbus_client.h"
|
||||
#include "mpd_client.h"
|
||||
|
||||
int main() {
|
||||
DBusConnection *conn = dbusConnect();
|
||||
|
||||
printf( "Media players on dbus:\n" );
|
||||
char **dbus_players = dbusGetMediaPlayers( conn );
|
||||
if ( dbus_players != NULL ) {
|
||||
for ( char **player = dbus_players; *player; player++ ) {
|
||||
printf( "%s\n", *player );
|
||||
struct song_metadata song = dbusGetSong( conn, *player );
|
||||
printSong( &song );
|
||||
dbusPlayPause( conn, *player );
|
||||
free( *player );
|
||||
}
|
||||
}
|
||||
free( dbus_players );
|
||||
dbusDisconnect( conn );
|
||||
|
||||
struct mpd_connection *mpd_connection = mpdConnect( 6600 );
|
||||
|
||||
if ( mpd_connection != NULL ) {
|
||||
printf( "MPD is running!\n" );
|
||||
struct song_metadata song = mpdGetSong( mpd_connection );
|
||||
printSong( &song );
|
||||
mpdPlayPause( mpd_connection );
|
||||
}
|
||||
|
||||
mpdDisconnect( mpd_connection );
|
||||
|
||||
return 0;
|
||||
}
|
18
metadata.c
Normal file
18
metadata.c
Normal file
@ -0,0 +1,18 @@
|
||||
#include "metadata.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void printSong( struct song_metadata *song ) {
|
||||
if ( song->title == NULL )
|
||||
return;
|
||||
printf( " TITLE: %s\n ALBUM: %s\n ARTIST: %s\n", song->title,
|
||||
song->album, song->artist );
|
||||
if ( song->year != NULL ) {
|
||||
printf( " YEAR: %s\n", song->year );
|
||||
}
|
||||
printf( " FILE: %s\n", song->file );
|
||||
if ( song->art_uri != NULL ) {
|
||||
printf( " ART: %s\n", song->art_uri );
|
||||
}
|
||||
}
|
15
metadata.h
Normal file
15
metadata.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef METADATA_H
|
||||
#define METADATA_H
|
||||
|
||||
struct song_metadata {
|
||||
const char *title;
|
||||
const char *artist;
|
||||
const char *album;
|
||||
const char *year;
|
||||
const char *file;
|
||||
const char *art_uri;
|
||||
};
|
||||
|
||||
void printSong( struct song_metadata *song );
|
||||
|
||||
#endif
|
73
mpd_client.c
Normal file
73
mpd_client.c
Normal file
@ -0,0 +1,73 @@
|
||||
#include "mpd_client.h"
|
||||
|
||||
#include <mpd/player.h>
|
||||
#include <mpd/song.h>
|
||||
#include <mpd/status.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "metadata.h"
|
||||
|
||||
struct mpd_connection *mpdConnect( int port ) {
|
||||
struct mpd_connection *ret = mpd_connection_new( "localhost", port, 1000 );
|
||||
if ( ret == NULL )
|
||||
return NULL;
|
||||
|
||||
if ( mpd_connection_get_error( ret ) != MPD_ERROR_SUCCESS )
|
||||
return NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void mpdDisconnect( struct mpd_connection *mpd_connection ) {
|
||||
if ( mpd_connection != NULL )
|
||||
mpd_connection_free( mpd_connection );
|
||||
}
|
||||
|
||||
struct song_metadata mpdGetSong( struct mpd_connection *mpd_connection ) {
|
||||
struct song_metadata ret = { 0 };
|
||||
struct mpd_song *song = mpd_run_current_song( mpd_connection );
|
||||
if ( song == NULL )
|
||||
goto end;
|
||||
const char *copy = mpd_song_get_tag( song, MPD_TAG_TITLE, 0 );
|
||||
if ( copy == NULL )
|
||||
goto endfree;
|
||||
// TODO check return values
|
||||
ret.title = strdup( copy );
|
||||
copy = mpd_song_get_tag( song, MPD_TAG_ARTIST, 0 );
|
||||
if( copy != NULL )
|
||||
ret.artist = strdup( copy );
|
||||
copy = mpd_song_get_tag( song, MPD_TAG_ALBUM, 0 );
|
||||
if( copy != NULL )
|
||||
ret.album = strdup( copy );
|
||||
copy = mpd_song_get_tag( song, MPD_TAG_DATE, 0 );
|
||||
if( copy != NULL )
|
||||
ret.year = strdup( copy );
|
||||
|
||||
ret.file = strdup( mpd_song_get_uri( song ) );
|
||||
endfree:
|
||||
mpd_song_free( song );
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void mpdPlayPause( struct mpd_connection *mpd_connection ) {
|
||||
mpd_send_toggle_pause( mpd_connection );
|
||||
}
|
||||
|
||||
void mpdNext( struct mpd_connection *mpd_connection ) {
|
||||
mpd_send_next( mpd_connection );
|
||||
}
|
||||
|
||||
void mpdPrev( struct mpd_connection *mpd_connection ) {
|
||||
mpd_send_previous( mpd_connection );
|
||||
}
|
||||
|
||||
void mpdStop( struct mpd_connection *mpd_connection ) {
|
||||
mpd_send_stop( mpd_connection );
|
||||
}
|
||||
|
||||
bool mpdStatus( struct mpd_connection *mpd_connection ) {
|
||||
struct mpd_status *status = mpd_recv_status( mpd_connection );
|
||||
enum mpd_state ret = mpd_status_get_state( status );
|
||||
mpd_status_free( status );
|
||||
return ret == MPD_STATE_PLAY;
|
||||
}
|
13
mpd_client.h
Normal file
13
mpd_client.h
Normal file
@ -0,0 +1,13 @@
|
||||
#include <mpd/connection.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "metadata.h"
|
||||
|
||||
struct mpd_connection *mpdConnect( int port );
|
||||
void mpdDisconnect( struct mpd_connection *mpd_connection );
|
||||
struct song_metadata mpdGetSong( struct mpd_connection *mpd_connection );
|
||||
void mpdPlayPause( struct mpd_connection *mpd_connection );
|
||||
void mpdNext( struct mpd_connection *mpd_connection );
|
||||
void mpdPrev( struct mpd_connection *mpd_connection );
|
||||
void mpdStop( struct mpd_connection *mpd_connection );
|
||||
bool mpdStatus( struct mpd_connection *mpd_connection );
|
Loading…
Reference in New Issue
Block a user