Skip to content

Commit

Permalink
Reorganise D-BUS interface code and introduce an MPRIS interface.
Browse files Browse the repository at this point in the history
  • Loading branch information
mikebrady committed Nov 19, 2017
1 parent 79e610f commit 74f41a1
Show file tree
Hide file tree
Showing 17 changed files with 7,207 additions and 23 deletions.
28 changes: 27 additions & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ shairport_sync_SOURCES += mdns_dns_sd.c
endif

if USE_DBUS
shairport_sync_SOURCES += shairport-sync-dbus-service.c shairport-sync-dbus-interface.c dacp.c
shairport_sync_SOURCES += shairport-sync-dbus-service.c shairport-sync-dbus-interface.c
BUILT_SOURCES = shairport-sync-dbus-interface.h shairport-sync-dbus-interface.c
# We don't want to install this header
noinst_HEADERS = $(BUILT_SOURCES)
Expand All @@ -87,6 +87,32 @@ shairport-sync-dbus-interface.c: org.gnome.ShairportSync.xml
gdbus-codegen --interface-prefix org.gnome --generate-c-code shairport-sync-dbus-interface org.gnome.ShairportSync.xml
endif

if USE_DBUS_CORE_AND_DACP
shairport_sync_SOURCES += dacp.c
endif

if USE_MPRIS
shairport_sync_SOURCES += shairport-sync-mpris-service.c shairport-sync-mpris-interface.c shairport-sync-mpris-player-interface.c
BUILT_SOURCES = shairport-sync-mpris-interface.h shairport-sync-mpris-interface.c shairport-sync-mpris-player-interface.h shairport-sync-mpris-player-interface.c
# We don't want to install this header
noinst_HEADERS = $(BUILT_SOURCES)
# Correctly clean the generated headers, but keep the xml description
CLEANFILES = $(BUILT_SOURCES)

#Rule to generate the binding headers
shairport-sync-mpris-interface.h: org.mpris.MediaPlayer2.xml
gdbus-codegen --interface-prefix org.gnome --generate-c-code shairport-sync-mpris-interface org.mpris.MediaPlayer2.xml

shairport-sync-mpris-interface.c: org.mpris.MediaPlayer2.xml
gdbus-codegen --interface-prefix org.gnome --generate-c-code shairport-sync-mpris-interface org.mpris.MediaPlayer2.xml

shairport-sync-mpris-player-interface.h: org.mpris.MediaPlayer2.Player.xml
gdbus-codegen --interface-prefix org.gnome --generate-c-code shairport-sync-mpris-player-interface org.mpris.MediaPlayer2.Player.xml

shairport-sync-mpris-player-interface.c: org.mpris.MediaPlayer2.Player.xml
gdbus-codegen --interface-prefix org.gnome --generate-c-code shairport-sync-mpris-player-interface org.mpris.MediaPlayer2.Player.xml
endif

if USE_DBUS_CLIENT
#Make it, but don't install it anywhere
noinst_PROGRAMS = shairport-sync-dbus-test-client
Expand Down
16 changes: 15 additions & 1 deletion common.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@
#define SAFAMILY sa_family
#endif

#if defined(HAVE_DBUS) || defined(HAVE_MPRIS)
enum dbus_session_type {
DBT_system = 0, // use the session bus
DBT_session, // use the system bus
} dbt_type;
#endif

enum endian_type {
SS_LITTLE_ENDIAN = 0,
SS_PDP_ENDIAN,
Expand All @@ -42,7 +49,7 @@ enum endian_type {
enum stuffing_type {
ST_basic = 0, // straight deletion or insertion of a frame in a 352-frame packet
ST_soxr, // use libsoxr to make a 352 frame packet one frame longer or shorter
} type;
} s_type;

enum playback_mode_type {
ST_stereo = 0,
Expand Down Expand Up @@ -73,6 +80,7 @@ enum sps_format_t {

typedef struct {
config_t *cfg;
char *appName; // normally the app is called shairport-syn, but it may be symlinked
char *password;
char *service_name; // the name for the shairport service, e.g. "Shairport Sync Version %v running
// on host %h"
Expand Down Expand Up @@ -158,6 +166,12 @@ typedef struct {
int loudness;
float loudness_reference_volume_db;
int alsa_use_playback_switch_for_mute;
#if defined(HAVE_DBUS)
enum dbus_session_type dbus_service_bus_type;
#endif
#if defined(HAVE_MPRIS)
enum dbus_session_type mpris_service_bus_type;
#endif

} shairport_cfg;

Expand Down
11 changes: 11 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,17 @@ AC_ARG_WITH(dbus-test-client, [ --with-dbus-test-client = compile dbus test cli
], )
AM_CONDITIONAL([USE_DBUS_CLIENT], [test "x$HAS_DBUS_CLIENT" = "x1"])

# Look for mpris flag
AC_ARG_WITH(mpris, [ --with-mpris = choose mpris support], [
AC_MSG_RESULT(>>Including mpris support)
HAS_MPRIS=1
AC_DEFINE([HAVE_MPRIS], 1, [Needed by the compiler.])
PKG_CHECK_MODULES([GIO_UNIX], [gio-unix-2.0 >= 2.30.0],[CFLAGS="${GIO_UNIX_CFLAGS} ${CFLAGS}" LIBS="${GIO_UNIX_LIBS} ${LIBS}"],[AC_MSG_ERROR(dbus messaging support for mpris requires the glib 2.0 library -- libglib2.0-dev suggested!)])
], )
AM_CONDITIONAL([USE_MPRIS], [test "x$HAS_MPRIS" = "x1"])

AM_CONDITIONAL([USE_DBUS_CORE_AND_DACP], [test "x$HAS_MPRIS" = "x1" -o "x$HAS_DBUS" = "x1"])

if test "x${with_systemd}" = xyes ; then
# Find systemd unit dir
AC_ARG_WITH([systemdsystemunitdir],
Expand Down
44 changes: 44 additions & 0 deletions org.mpris.MediaPlayer2.Player.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http:https://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">

<node>
<interface name='org.mpris.MediaPlayer2.Player'>
<method name='Next'/>
<method name='Previous'/>
<method name='Pause'/>
<method name='PlayPause'/>
<method name='Stop'/>
<method name='StopAfterCurrent'/> <!-- Cantata addition -->
<method name='Play'/>
<method name='Seek'>
<arg direction='in' name='Offset' type='x'/>
</method>
<method name='SetPosition'>
<arg direction='in' name='TrackId' type='o'/>
<arg direction='in' name='Position' type='x'/>
</method>
<method name='OpenUri'>
<arg direction='in' name='Uri' type='s'/>
</method>
<signal name='Seeked'>
<arg name='Position' type='x'/>
</signal>
<property name='PlaybackStatus' type='s' access='read'/>
<property name='LoopStatus' type='s' access='readwrite'/>
<property name='Rate' type='d' access='readwrite'/>
<property name='Shuffle' type='b' access='readwrite'/>
<property name='Metadata' type='a{sv}' access='read'>
<annotation name="org.qtproject.QtDBus.QtTypeName" value="QVariantMap"/>
</property>
<property name='Volume' type='d' access='readwrite'/>
<property name='Position' type='x' access='read'/>
<property name='MinimumRate' type='d' access='read'/>
<property name='MaximumRate' type='d' access='read'/>
<property name='CanGoNext' type='b' access='read'/>
<property name='CanGoPrevious' type='b' access='read'/>
<property name='CanPlay' type='b' access='read'/>
<property name='CanPause' type='b' access='read'/>
<property name='CanSeek' type='b' access='read'/>
<property name='CanControl' type='b' access='read'/>
</interface>
</node>
25 changes: 25 additions & 0 deletions org.mpris.MediaPlayer2.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http:https://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">


<node>
<interface name="org.mpris.MediaPlayer2">
<method name="Raise"/>

<method name="Quit"/>

<property name="CanQuit" type="b" access="read"/>

<property name="CanRaise" type="b" access="read"/>

<property name="HasTrackList" type="b" access="read"/>

<property name="Identity" type="s" access="read"/>

<property name="DesktopEntry" type="s" access="read"/>

<property name="SupportedUriSchemes" type="as" access="read"/>

<property name="SupportedMimeTypes" type="as" access="read"/>
</interface>
</node>
2 changes: 1 addition & 1 deletion player.c
Original file line number Diff line number Diff line change
Expand Up @@ -2485,7 +2485,7 @@ void player_volume(double airplay_volume, rtsp_conn_info *conn) {
// %d.",overall_volume,relative_volume,actual_volume);
// debug(1,"Our actual speaker volume is %d.",actual_volume);
conn->dacp_volume = actual_volume; // this is needed to prevent a loop
shairport_sync_set_volume(SHAIRPORT_SYNC(skeleton), actual_volume);
shairport_sync_set_volume(SHAIRPORT_SYNC(shairportSyncSkeleton), actual_volume);
#endif
player_volume_without_notification(airplay_volume, conn);
}
Expand Down
4 changes: 4 additions & 0 deletions scripts/shairport-sync.conf
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ general =
// audio_backend_latency_offset_in_seconds = 0.0; // Set this offset to compensate for a fixed delay in the audio back end. E.g. if the output device delays by 100 ms, set this to -0.1.
// audio_backend_buffer_desired_length_in_seconds = 0.15; // If set too small, buffer underflow occurs on low-powered machines. Too long and the response time to volume changes becomes annoying. Default is 0.15 seconds in the alsa backend, 0.35 seconds in the pa backend and 1.0 seconds otherwise.
// audio_backend_silent_lead_in_time = 2.0; // This optional advanced setting, from 0.0 and 4.0 seconds, sets the length of the period of silence that precedes the start of the audio. The default is the latency, usually 2.0 seconds. Values greater than the latency are ignored. Values that are too low will affect initial synchronisation.
// dbus_service_bus = "system"; // The Shairport Sync dbus interface, if selected at compilation, will appear
// as "org.gnome.ShairportSync" on the whichever bus you specify here: "system" (default) or "session".
// mpris_service_bus = "system"; // The Shairport Sync mpris interface, if selected at compilation, will appear
// as "org.gnome.ShairportSync" on the whichever bus you specify here: "system" (default) or "session".
};


Expand Down
3 changes: 3 additions & 0 deletions shairport-sync-dbus-policy.conf
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@
<!-- Only user shairport-sync can own the Shairport Sync service -->
<policy user="shairport-sync">
<allow own="org.gnome.ShairportSync"/>
<allow own="org.mpris.MediaPlayer2.ShairportSync"/>
</policy>

<!-- Allow anyone to invoke methods on Shairport Sync server -->
<policy context="default">
<allow send_destination="org.gnome.ShairportSync"/>
<allow send_destination="org.mpris.MediaPlayer2.ShairportSync"/>
<allow receive_sender="org.gnome.ShairportSync"/>
<allow receive_sender="org.mpris.MediaPlayer2.ShairportSync"/>
</policy>

</busconfig>
50 changes: 36 additions & 14 deletions shairport-sync-dbus-service.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,37 +177,59 @@ static gboolean on_handle_remote_command(ShairportSync *skeleton, GDBusMethodInv
return TRUE;
}

static void on_name_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data) {
static void on_dbus_name_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data) {

skeleton = shairport_sync_skeleton_new();
debug(1,"Well-known interface name \"%s\" acquired for %s.",name,config.appName);
shairportSyncSkeleton = shairport_sync_skeleton_new();

g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(skeleton), connection,
g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(shairportSyncSkeleton), connection,
"/org/gnome/ShairportSync", NULL);

shairport_sync_set_loudness_threshold(SHAIRPORT_SYNC(skeleton),
shairport_sync_set_loudness_threshold(SHAIRPORT_SYNC(shairportSyncSkeleton),
config.loudness_reference_volume_db);
debug(1, "Loudness threshold is %f.", config.loudness_reference_volume_db);

if (config.loudness == 0) {
shairport_sync_set_loudness_filter_active(SHAIRPORT_SYNC(skeleton), FALSE);
shairport_sync_set_loudness_filter_active(SHAIRPORT_SYNC(shairportSyncSkeleton), FALSE);
debug(1, "Loudness is off");
} else {
shairport_sync_set_loudness_filter_active(SHAIRPORT_SYNC(skeleton), TRUE);
shairport_sync_set_loudness_filter_active(SHAIRPORT_SYNC(shairportSyncSkeleton), TRUE);
debug(1, "Loudness is on");
}

g_signal_connect(skeleton, "notify::loudness-filter-active",
g_signal_connect(shairportSyncSkeleton, "notify::loudness-filter-active",
G_CALLBACK(notify_loudness_filter_active_callback), NULL);
g_signal_connect(skeleton, "notify::loudness-threshold",
g_signal_connect(shairportSyncSkeleton, "notify::loudness-threshold",
G_CALLBACK(notify_loudness_threshold_callback), NULL);
g_signal_connect(skeleton, "notify::volume", G_CALLBACK(notify_volume_callback), NULL);
g_signal_connect(skeleton, "handle-remote-command", G_CALLBACK(on_handle_remote_command), NULL);
g_signal_connect(shairportSyncSkeleton, "notify::volume", G_CALLBACK(notify_volume_callback), NULL);
g_signal_connect(shairportSyncSkeleton, "handle-remote-command", G_CALLBACK(on_handle_remote_command), NULL);
debug(1,"Shairport Sync D-BUS service started on interface \"%s\".",name);
}

static void on_dbus_name_lost_again(GDBusConnection *connection, const gchar *name, gpointer user_data) {
warn("Could not acquire an Shairport Sync D-BUS interface.");
}

static void on_dbus_name_lost(GDBusConnection *connection, const gchar *name, gpointer user_data) {
debug(1,"Could not acquire well-known interface name \"%s\" -- will try adding the process number to the end of it.",name);
pid_t pid = getpid();
char interface_name[256] = "";
sprintf(interface_name,"org.gnome.ShairportSync.i%d",pid);
GBusType dbus_bus_type = G_BUS_TYPE_SYSTEM;
if (config.dbus_service_bus_type==DBT_session)
dbus_bus_type = G_BUS_TYPE_SESSION;
debug(1,"Looking for well-known interface name \"%s\".",interface_name);
g_bus_own_name(dbus_bus_type, interface_name, G_BUS_NAME_OWNER_FLAGS_NONE, NULL,
on_dbus_name_acquired, on_dbus_name_lost_again, NULL, NULL);
}

int start_dbus_service() {
skeleton = NULL;
g_bus_own_name(G_BUS_TYPE_SYSTEM, "org.gnome.ShairportSync", G_BUS_NAME_OWNER_FLAGS_NONE, NULL,
on_name_acquired, NULL, NULL, NULL);
// G_BUS_TYPE_SESSION or G_BUS_TYPE_SYSTEM
shairportSyncSkeleton = NULL;
GBusType dbus_bus_type = G_BUS_TYPE_SYSTEM;
if (config.dbus_service_bus_type==DBT_session)
dbus_bus_type = G_BUS_TYPE_SESSION;
debug(1,"Looking for well-known name \"org.gnome.ShairportSync\".");
g_bus_own_name(dbus_bus_type, "org.gnome.ShairportSync", G_BUS_NAME_OWNER_FLAGS_NONE, NULL,
on_dbus_name_acquired, on_dbus_name_lost, NULL, NULL);
return 0; // this is just to quieten a compiler warning
}
2 changes: 1 addition & 1 deletion shairport-sync-dbus-service.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

#include "shairport-sync-dbus-interface.h"

ShairportSync *skeleton;
ShairportSync *shairportSyncSkeleton;

int start_dbus_service();

Expand Down
Loading

0 comments on commit 74f41a1

Please sign in to comment.