diff --git a/dacp.c b/dacp.c index ba43689a5..4ba7a8289 100644 --- a/dacp.c +++ b/dacp.c @@ -121,6 +121,7 @@ int dacp_send_command(const char *command, char **body, ssize_t *bodysize) { // 495 Error receiving response // 494 This client is already busy // 493 Client failed to send a message + // 492 Argement out of range // try to do this transaction on the DACP server, but don't wait for more than 20 ms to be allowed // to do it. @@ -162,7 +163,7 @@ int dacp_send_command(const char *command, char **body, ssize_t *bodysize) { // only do this one at a time -- not sure it is necessary, but better safe than sorry -// int mutex_reply = pthread_mutex_timedlock(&dacp_conversation_lock, &mutex_wait_time); + // int mutex_reply = pthread_mutex_timedlock(&dacp_conversation_lock, &mutex_wait_time); int mutex_reply = pthread_mutex_lock(&dacp_conversation_lock); if (mutex_reply == 0) { @@ -662,12 +663,12 @@ int dacp_get_client_volume(int32_t *result) { } int dacp_set_include_speaker_volume(int64_t machine_number, int32_t vo) { - debug(1, "dacp_set_include_speaker_volume to %" PRId32 ".", vo); + debug(2, "dacp_set_include_speaker_volume to %" PRId32 ".", vo); char message[1000]; memset(message, 0, sizeof(message)); sprintf(message, "setproperty?include-speaker-id=%" PRId64 "&dmcp.volume=%" PRId32 "", machine_number, vo); - debug(1, "sending \"%s\"", message); + debug(2, "sending \"%s\"", message); return send_simple_dacp_command(message); // should return 204 } @@ -677,7 +678,7 @@ int dacp_set_speaker_volume(int64_t machine_number, int32_t vo) { memset(message, 0, sizeof(message)); sprintf(message, "setproperty?speaker-id=%" PRId64 "&dmcp.volume=%" PRId32 "", machine_number, vo); - debug(1, "sending \"%s\"", message); + debug(2, "sending \"%s\"", message); return send_simple_dacp_command(message); // should return 204 } @@ -852,3 +853,108 @@ int dacp_get_volume(int32_t *the_actual_volume) { } return http_response; } + +int dacp_set_volume(int32_t vo) { + int http_response = 492; // argument out of range + if ((vo >= 0) && (vo <= 100)) { + // get the information we need -- the absolute volume, the speaker list, our ID + struct dacp_speaker_stuff speaker_info[50]; + int32_t overall_volume; + http_response = dacp_get_client_volume(&overall_volume); + if (http_response == 200) { + int speaker_count; + http_response = dacp_get_speaker_list((dacp_spkr_stuff *)&speaker_info, 50, &speaker_count); + if (http_response == 200) { + // 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 active_speakers = 0; + for (i = 0; i < speaker_count; i++) { + if (speaker_info[i].speaker_number == machine_number) { + debug(2, "Our speaker number found: %ld with relative volume.", machine_number, + speaker_info[i].volume); + } + if (speaker_info[i].active == 1) { + active_speakers++; + } + } + + if (active_speakers == 1) { + // must be just this speaker + debug(2, "Remote-setting volume to %d on just one speaker.", vo); + http_response = dacp_set_include_speaker_volume(machine_number, vo); + } else if (active_speakers == 0) { + debug(2, "No speakers!"); + } else { + debug(2, "Speakers: %d, active: %d", speaker_count, active_speakers); + if (vo >= overall_volume) { + debug(2, "Multiple speakers active, but desired new volume is highest"); + http_response = dacp_set_include_speaker_volume(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(2, + "Highest other volume %d is less than or equal to the desired new volume %d.", + highest_other_volume, vo); + http_response = dacp_set_include_speaker_volume(machine_number, vo); + } else { + debug(2, "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(2, "Lower overall volume to new highest volume."); + http_response = dacp_set_include_speaker_volume( + 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(2, "Set our speaker volume relative to the highest volume."); + http_response = dacp_set_speaker_volume( + machine_number, + desired_relative_volume); // set the overall volume to the highest one + } + } + } + } else { + debug(2, "Can't get speakers list"); + } + } else { + debug(2, "Can't get client volume"); + } + + } else { + debug(2, "Invalid volume: %d -- ignored.", vo); + } + return http_response; +} diff --git a/dacp.h b/dacp.h index bd43300c6..1a04e0166 100644 --- a/dacp.h +++ b/dacp.h @@ -32,3 +32,4 @@ int dacp_set_include_speaker_volume(int64_t machine_number, int32_t vo); int dacp_get_client_volume(int32_t *result); int dacp_get_volume( int32_t *the_actual_volume); // get the speaker volume information from the DACP source +int dacp_set_volume(int32_t vo); // set the volume of our speaker diff --git a/dbus-service.c b/dbus-service.c index a9b7f67df..753d62180 100644 --- a/dbus-service.c +++ b/dbus-service.c @@ -44,118 +44,12 @@ gboolean notify_loudness_threshold_callback(ShairportSync *skeleton, return TRUE; } -gboolean notify_volume_callback(ShairportSync *skeleton, - __attribute__((unused)) gpointer user_data) { - metadata_hub_read_prolog(); - int md_speaker_volume = metadata_store.speaker_volume; - metadata_hub_read_epilog(); - gint gvo = shairport_sync_get_volume(skeleton); - int32_t vo = gvo; - if ((vo >= 0) && (vo <= 100)) { - if (vo != - md_speaker_volume) { // this is to stop an infinite loop of setting->checking->setting... - // get the information we need -- the absolute volume, the speaker list, our ID - struct dacp_speaker_stuff speaker_info[50]; - int32_t overall_volume; - int http_response = dacp_get_client_volume(&overall_volume); - if (http_response == 200) { - int speaker_count; - http_response = dacp_get_speaker_list((dacp_spkr_stuff *)&speaker_info, 50, &speaker_count); - if (http_response == 200) { - // 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 active_speakers = 0; - for (i = 0; i < speaker_count; i++) { - if (speaker_info[i].speaker_number == machine_number) { - debug(2, "Our speaker number found: %ld with relative volume.", machine_number, - speaker_info[i].volume); - } - if (speaker_info[i].active == 1) { - active_speakers++; - } - } - - if (active_speakers == 1) { - // must be just this speaker - debug(2, "Remote-setting volume to %d on just one speaker.", vo); - dacp_set_include_speaker_volume(machine_number, vo); - } else if (active_speakers == 0) { - debug(2, "No speakers!"); - } else { - debug(2, "Speakers: %d, active: %d", speaker_count, active_speakers); - if (vo >= overall_volume) { - debug(2, "Multiple speakers active, but desired new volume is highest"); - dacp_set_include_speaker_volume(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(2, - "Highest other volume %d is less than or equal to the desired new volume %d.", - highest_other_volume, vo); - dacp_set_include_speaker_volume(machine_number, vo); - } else { - debug(2, "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(2, "Lower overall volume to new highest volume."); - dacp_set_include_speaker_volume( - 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(2, "Set our speaker volume relative to the highest volume."); - dacp_set_speaker_volume( - machine_number, - desired_relative_volume); // set the overall volume to the highest one - } - } - } - } else { - debug(2, "Can't get speakers list"); - } - } else { - debug(2, "Can't get client volume"); - } - } // else { - // debug(1, "No need to remote-set volume to %d, as it is already set to this value.", vo); - // } - - } else { - debug(2, "Invalid volume: %d -- ignored.", vo); - } +static gboolean on_handle_set_volume(ShairportSync *skeleton, GDBusMethodInvocation *invocation, + const gint volume, + __attribute__((unused)) gpointer user_data) { + // debug(1, "1 Set volume to d.", volume); + dacp_set_volume(volume); + shairport_sync_complete_set_volume(skeleton, invocation); return TRUE; } @@ -194,10 +88,10 @@ static void on_dbus_name_acquired(GDBusConnection *connection, const gchar *name G_CALLBACK(notify_loudness_filter_active_callback), NULL); g_signal_connect(shairportSyncSkeleton, "notify::loudness-threshold", G_CALLBACK(notify_loudness_threshold_callback), NULL); - g_signal_connect(shairportSyncSkeleton, "notify::volume", G_CALLBACK(notify_volume_callback), - &metadata_store); g_signal_connect(shairportSyncSkeleton, "handle-remote-command", G_CALLBACK(on_handle_remote_command), NULL); + g_signal_connect(shairportSyncSkeleton, "handle-set-volume", G_CALLBACK(on_handle_set_volume), + NULL); add_metadata_watcher(dbus_metadata_watcher, NULL); diff --git a/org.gnome.ShairportSync.xml b/org.gnome.ShairportSync.xml index 8bba3609d..5d5da742b 100644 --- a/org.gnome.ShairportSync.xml +++ b/org.gnome.ShairportSync.xml @@ -3,9 +3,12 @@ - + + + + diff --git a/org.mpris.MediaPlayer2.Player.xml b/org.mpris.MediaPlayer2.Player.xml index 8ef73584a..72362379b 100755 --- a/org.mpris.MediaPlayer2.Player.xml +++ b/org.mpris.MediaPlayer2.Player.xml @@ -29,7 +29,7 @@ - + diff --git a/shairport-sync-dbus-test-client.c b/shairport-sync-dbus-test-client.c index 05ec5f7bb..eb464b02c 100644 --- a/shairport-sync-dbus-test-client.c +++ b/shairport-sync-dbus-test-client.c @@ -132,13 +132,13 @@ int main(int argc, char *argv[]) { g_print("Starting test...\n"); - shairport_sync_set_volume(SHAIRPORT_SYNC(proxy), 20); + shairport_sync_call_set_volume(SHAIRPORT_SYNC(proxy), 20, NULL, NULL, 0); sleep(5); - shairport_sync_set_volume(SHAIRPORT_SYNC(proxy), 100); + shairport_sync_call_set_volume(SHAIRPORT_SYNC(proxy), 100, NULL, NULL, 0); sleep(5); - shairport_sync_set_volume(SHAIRPORT_SYNC(proxy), 40); + shairport_sync_call_set_volume(SHAIRPORT_SYNC(proxy), 40, NULL, NULL, 0); sleep(5); - shairport_sync_set_volume(SHAIRPORT_SYNC(proxy), 60); + shairport_sync_call_set_volume(SHAIRPORT_SYNC(proxy), 60, NULL, NULL, 0); // sleep(1); /* shairport_sync_set_volume(SHAIRPORT_SYNC(proxy), 10);