Split volume function into read-only property and a method for setting it. Making the property read-write is too awkward and kludgy.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
+8
-114
@@ -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);
|
||||
|
||||
|
||||
@@ -3,9 +3,12 @@
|
||||
<interface name="org.gnome.ShairportSync">
|
||||
<property name="LoudnessFilterActive" type="b" access="readwrite" />
|
||||
<property name="LoudnessThreshold" type="d" access="readwrite" />
|
||||
<property name="Volume" type="d" access="readwrite" />
|
||||
<property name="Volume" type="i" access="read" />
|
||||
<method name="RemoteCommand">
|
||||
<arg name="command" type="s" direction="in" />
|
||||
</method>
|
||||
<method name="SetVolume">
|
||||
<arg name="volume" type="i" direction="in" />
|
||||
</method>
|
||||
</interface>
|
||||
</node>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<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='Volume' type='d' access='read'/>
|
||||
<property name='Position' type='x' access='read'/>
|
||||
<property name='MinimumRate' type='d' access='read'/>
|
||||
<property name='MaximumRate' type='d' access='read'/>
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user