SUBDIRS = man
-if USE_DBUS
- SUBDIRS += dbus/src dbus/data
-else
-if USE_DBUS_CLIENT
- SUBDIRS += dbus/src dbus/data
-endif
-endif
-
bin_PROGRAMS = shairport-sync
if USE_DBUS_CLIENT
-noinst_PROGRAMS = dbus/src/shairport-sync-dbus-client
+noinst_PROGRAMS = shairport-sync-dbus-test-client
endif
shairport_sync_SOURCES = shairport.c rtsp.c mdns.c mdns_external.c common.c rtp.c player.c alac.c audio.c loudness.c
endif
if USE_DBUS
-shairport_sync_SOURCES += dbus/src/shairport-sync-dbus-service.c dbus/src/shairport-sync-dbus-interface.c dacp.c
+shairport_sync_SOURCES += shairport-sync-dbus-service.c shairport-sync-dbus-interface.c dacp.c
+endif
+
+if USE_DBUS_CLIENT
+shairport_sync_dbus_test_client_SOURCES = shairport-sync-dbus-interface.c shairport-sync-dbus-interface.h shairport-sync-dbus-test-client.c
+endif
+
+if USE_DBUS
+BUILT_SOURCES = shairport-sync-dbus-interface.h shairport-sync-dbus-interface.c org.gnome.ShairportSync.service
+# 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)
+#EXTRA_DIST = org.gnome.ShairportSync.xml
+
+#Rule to generate the binding headers
+shairport-sync-dbus-interface.h: org.gnome.ShairportSync.xml
+ gdbus-codegen --interface-prefix org.gnome --generate-c-code shairport-sync-dbus-interface org.gnome.ShairportSync.xml
+
+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
+
+# Dbus service file
+
+interfacesdir = $(DESTDIR)/usr/local/share/dbus-1/interfaces
+interfaces_DATA = org.gnome.ShairportSync.xml
+
+servicedir = $(DESTDIR)/usr/local/share/dbus-1/services
+service_in_files = org.gnome.ShairportSync.service.in
+service_DATA = $(service_in_files:.service.in=.service)
+EXTRA_DIST = $(service_in_files) org.gnome.ShairportSync.xml
+
+# Rule to make the service file with bindir expanded
+$(service_DATA): $(service_in_files) Makefile
+ @sed -e "s|\@bindir\@|$(bindir)|" $? > $@
+
+clean-local:
+ rm -rf $(service_DATA)
+
endif
install-exec-hook:
cp scripts/shairport-sync.conf $(DESTDIR)$(sysconfdir)/shairport-sync.conf.sample
[ -f $(DESTDIR)$(sysconfdir)/shairport-sync.conf ] || cp scripts/shairport-sync.conf $(DESTDIR)$(sysconfdir)/shairport-sync.conf
if USE_DBUS
- cp dbus/config/system-bus-policy/shairport-sync.conf $(DESTDIR)$(sysconfdir)/dbus-1/system.d/shairport-sync.conf
+ cp shairport-sync-dbus-policy.conf $(DESTDIR)$(sysconfdir)/dbus-1/system.d/shairport-sync.conf
endif
endif
if INSTALL_SYSTEMV
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+
+#include "config.h"
+
+#include "common.h"
+#include "player.h"
+#include "rtsp.h"
+
+#include "rtp.h"
+
+#include "dacp.h"
+
+#include "shairport-sync-dbus-service.h"
+
+gboolean notify_loudness_filter_active_callback(ShairportSync *skeleton, gpointer user_data) {
+ debug(1, "\"notify_loudness_filter_active_callback\" called.");
+ if (shairport_sync_get_loudness_filter_active(skeleton)) {
+ debug(1, "activating loudness filter");
+ config.loudness = 1;
+ } else {
+ debug(1, "deactivating loudness filter");
+ config.loudness = 0;
+ }
+ return TRUE;
+}
+
+gboolean notify_loudness_threshold_callback(ShairportSync *skeleton, gpointer user_data) {
+ gdouble th = shairport_sync_get_loudness_threshold(skeleton);
+ if ((th <= 0.0) && (th >= -100.0)) {
+ debug(1, "Setting loudness threshhold to %f.", th);
+ config.loudness_reference_volume_db = th;
+ } else {
+ debug(1, "Invalid loudness threshhold: %f. Ignored.", th);
+ }
+ return TRUE;
+}
+
+gboolean notify_volume_callback(ShairportSync *skeleton, gpointer user_data) {
+ gint vo = shairport_sync_get_volume(skeleton);
+ if ((vo >= 0) && (vo <= 100)) {
+ if (playing_conn) {
+ if (vo !=
+ playing_conn
+ ->dacp_volume) { // this is to stop an infinite loop of setting->checking->setting...
+ // debug(1, "Remote-setting volume to %d.", vo);
+ // get the information we need -- the absolute volume, the speaker list, our ID
+ struct dacp_speaker_stuff speaker_info[50];
+ int32_t overall_volume = dacp_get_client_volume(playing_conn);
+ int speaker_count =
+ dacp_get_speaker_list(playing_conn, (dacp_spkr_stuff *)&speaker_info, 50);
+
+ // get our machine number
+ uint16_t *hn = (uint16_t *)config.hw_addr;
+ uint32_t *ln = (uint32_t *)(config.hw_addr + 2);
+ uint64_t t1 = ntohs(*hn);
+ uint64_t t2 = ntohl(*ln);
+ int64_t machine_number = (t1 << 32) + t2; // this form is useful
+
+ // Let's find our own speaker in the array and pick up its relative volume
+ int i;
+ int32_t relative_volume = 0;
+ int32_t active_speakers = 0;
+ for (i = 0; i < speaker_count; i++) {
+ if (speaker_info[i].speaker_number == machine_number) {
+ // debug(1,"Our speaker number found: %ld.",machine_number);
+ relative_volume = speaker_info[i].volume;
+ }
+ if (speaker_info[i].active == 1) {
+ active_speakers++;
+ }
+ }
+
+ if (active_speakers == 1) {
+ // must be just this speaker
+ dacp_set_include_speaker_volume(playing_conn, machine_number, vo);
+ } else if (active_speakers == 0) {
+ debug(1, "No speakers!");
+ } else {
+ // debug(1, "Speakers: %d, active: %d",speaker_count,active_speakers);
+ if (vo >= overall_volume) {
+ // debug(1,"Multiple speakers active, but desired new volume is highest");
+ dacp_set_include_speaker_volume(playing_conn, machine_number, vo);
+ } else {
+ // the desired volume is less than the current overall volume and there is more than one
+ // speaker
+ // we must find out the highest other speaker volume.
+ // If the desired volume is less than it, we must set the current_overall volume to that
+ // highest volume
+ // and set our volume relative to it.
+ // If the desired volume is greater than the highest current volume, then we can just go
+ // ahead
+ // with dacp_set_include_speaker_volume, setting the new current overall volume to the
+ // desired new level
+ // with the speaker at 100%
+
+ int32_t highest_other_volume = 0;
+ for (i = 0; i < speaker_count; i++) {
+ if ((speaker_info[i].speaker_number != machine_number) &&
+ (speaker_info[i].active == 1) &&
+ (speaker_info[i].volume > highest_other_volume)) {
+ highest_other_volume = speaker_info[i].volume;
+ }
+ }
+ highest_other_volume = (highest_other_volume * overall_volume + 50) / 100;
+ if (highest_other_volume <= vo) {
+ // debug(1,"Highest other volume %d is less than or equal to the desired new volume
+ // %d.",highest_other_volume,vo);
+ dacp_set_include_speaker_volume(playing_conn, machine_number, vo);
+ } else {
+ // debug(1,"Highest other volume %d is greater than the desired new volume
+ // %d.",highest_other_volume,vo);
+ // if the present overall volume is higher than the highest other volume at present,
+ // then bring it down to it.
+ if (overall_volume > highest_other_volume) {
+ // debug(1,"Lower overall volume to new highest volume.");
+ dacp_set_include_speaker_volume(
+ playing_conn, machine_number,
+ highest_other_volume); // set the overall volume to the highest one
+ }
+ int32_t desired_relative_volume =
+ (vo * 100 + (highest_other_volume / 2)) / highest_other_volume;
+ // debug(1,"Set our speaker volume relative to the highest volume.");
+ dacp_set_speaker_volume(
+ playing_conn, machine_number,
+ desired_relative_volume); // set the overall volume to the highest one
+ }
+ }
+ }
+ // } else {
+ // debug(1, "No need to remote-set volume to %d, as it is already set to this
+ // value.",playing_conn->dacp_volume);
+ }
+ } else
+ debug(1, "no thread playing -- ignored.");
+ } else {
+ debug(1, "Invalid volume: %d -- ignored.", vo);
+ }
+ return TRUE;
+}
+
+static gboolean on_handle_remote_command(ShairportSync *skeleton, GDBusMethodInvocation *invocation,
+ const gchar *command, gpointer user_data) {
+ debug(1, "RemoteCommand with command \"%s\".", command);
+ if (playing_conn) {
+ char server_reply[2000];
+ ssize_t reply_size =
+ dacp_send_client_command(playing_conn, command, server_reply, sizeof(server_reply));
+ if (reply_size >= 0) {
+ // not interested in the response.
+ // if (strstr(server_reply, "HTTP/1.1 204") == server_reply) {
+ // debug(1,"Client response is No Content");
+ // } else if (strstr(server_reply, "HTTP/1.1 200 OK") != server_reply) {
+ // debug("Client response is OK, with content");
+ // } else {
+
+ if (strstr(server_reply, "HTTP/1.1 204") != server_reply) {
+ debug(1,
+ "Client request to server responded with %d characters starting with this response:",
+ strlen(server_reply));
+ int i;
+ for (i = 0; i < reply_size; i++)
+ if (server_reply[i] < ' ')
+ debug(1, "%d %02x", i, server_reply[i]);
+ else
+ debug(1, "%d %02x '%c'", i, server_reply[i], server_reply[i]);
+ // sprintf((char *)message + 2 * i, "%02x", server_reply[i]);
+ // debug(1,"Content is \"%s\".",message);
+ }
+ } else {
+ debug(1, "Error at rtp_send_client_command");
+ }
+ } else {
+ debug(1, "no thread playing -- RemoteCommand ignored.");
+ }
+ shairport_sync_complete_remote_command(skeleton, invocation);
+ return TRUE;
+}
+
+static void on_name_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data) {
+
+ skeleton = shairport_sync_skeleton_new();
+
+ g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(skeleton), connection,
+ "/org/gnome/ShairportSync", NULL);
+
+ shairport_sync_set_loudness_threshold(SHAIRPORT_SYNC(skeleton),
+ 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);
+ debug(1, "Loudness is off");
+ } else {
+ shairport_sync_set_loudness_filter_active(SHAIRPORT_SYNC(skeleton), TRUE);
+ debug(1, "Loudness is on");
+ }
+
+ g_signal_connect(skeleton, "notify::loudness-filter-active",
+ G_CALLBACK(notify_loudness_filter_active_callback), NULL);
+ g_signal_connect(skeleton, "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);
+}
+
+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
+ return 0; // this is just to quieten a compiler warning
+}