double suggested_volume(rtsp_conn_info *conn) {
double response = config.airplay_volume;
- if (conn) {
- if (conn->own_airplay_volume_set != 0) {
- response = conn->own_airplay_volume;
- } else if (config.airplay_volume > config.high_threshold_airplay_volume) {
- int64_t volume_validity_time = config.limit_to_high_volume_threshold_time_in_minutes;
- // zero means never check the volume
- if (volume_validity_time != 0) {
- // If the volume is higher than the high volume threshold
- // and enough time has gone past, suggest the default volume.
- uint64_t time_now = get_absolute_time_in_ns();
- int64_t time_since_last_access_to_volume_info =
- time_now - config.last_access_to_volume_info_time;
-
- volume_validity_time = volume_validity_time * 60; // to seconds
- volume_validity_time = volume_validity_time * 1000000000; // to nanoseconds
-
- if ((config.airplay_volume > config.high_threshold_airplay_volume) &&
- ((config.last_access_to_volume_info_time == 0) ||
- (time_since_last_access_to_volume_info > volume_validity_time))) {
-
- debug(2,
- "the current volume %.6f is higher than the high volume threshold %.6f, so the "
- "default volume %.6f is suggested.",
- config.airplay_volume, config.high_threshold_airplay_volume,
- config.default_airplay_volume);
- response = config.default_airplay_volume;
- }
+ if ((conn != NULL) && (conn->own_airplay_volume_set != 0)) {
+ response = conn->own_airplay_volume;
+ } else if (config.airplay_volume > config.high_threshold_airplay_volume) {
+ int64_t volume_validity_time = config.limit_to_high_volume_threshold_time_in_minutes;
+ // zero means never check the volume
+ if (volume_validity_time != 0) {
+ // If the volume is higher than the high volume threshold
+ // and enough time has gone past, suggest the default volume.
+ uint64_t time_now = get_absolute_time_in_ns();
+ int64_t time_since_last_access_to_volume_info =
+ time_now - config.last_access_to_volume_info_time;
+
+ volume_validity_time = volume_validity_time * 60; // to seconds
+ volume_validity_time = volume_validity_time * 1000000000; // to nanoseconds
+
+ if ((config.airplay_volume > config.high_threshold_airplay_volume) &&
+ ((config.last_access_to_volume_info_time == 0) ||
+ (time_since_last_access_to_volume_info > volume_validity_time))) {
+
+ debug(2,
+ "the current volume %.6f is higher than the high volume threshold %.6f, so the "
+ "default volume %.6f is suggested.",
+ config.airplay_volume, config.high_threshold_airplay_volume,
+ config.default_airplay_volume);
+ response = config.default_airplay_volume;
}
}
}
free(conns[i]);
conns[i] = NULL;
}
- if (conns[i] != NULL)
+ if (conns[i] != NULL) {
+ debug(1, "Airplay Volume for connection %d is %.6f.", conns[i]->connection_number,
+ suggested_volume(conns[i]));
connection_count++;
+ }
}
debug_mutex_unlock(&conns_lock, 3);
+
if (old_connection_count != connection_count) {
- if (connection_count == 0)
+ if (connection_count == 0) {
debug(2, "No active connections.");
- else if (connection_count == 1)
+ } else if (connection_count == 1)
debug(2, "One active connection.");
else
debug(2, "%d active connections.", connection_count);
old_connection_count = connection_count;
}
+ debug(1, "Airplay Volume for new connections is %.6f.", suggested_volume(NULL));
}
// park a null at the line ending, and return the next line pointer
FD_SET(sockfd[i], &fds);
ret = select(maxfd + 1, &fds, 0, 0, &tv);
+
if (ret < 0) {
if (errno == EINTR)
continue;
// "standard" makes the volume change more quickly at lower volumes and slower at higher volumes.
// "flat" makes the volume change at the same rate at all volumes.
// volume_control_combined_hardware_priority = "no"; // when extending the volume range by combining the built-in software attenuator with the hardware mixer attenuator, set this to "yes" to reduce volume by using the hardware mixer first, then the built-in software attenuator.
+
+// default_airplay_volume = 24.0; // this is the suggested volume after a reset or after the high_volume_threshold has been exceed and the high_volume_idle_timeout_in_minutes has passed
+
+// The following settings are for dealing with potentially surprising high ("very loud") volume levels.
+// When a new play session starts, it usually requests a suggested volume level from Shairport Sync. This is normally the volume level of the last session.
+// This can cause unpleasant surprises if the last session was (a) very loud and (b) a long time ago.
+// Thus, the user could be unpleasantly surprised by the volume level of the new session.
+
+// To deal with this, when the last session volume is "very loud", the following two settings will lower the suggested volume after a period of idleness:
+
+// high_threshold_airplay_volume = -16.0; // airplay volume greater or equal to this is "very loud"
+// high_volume_idle_timeout_in_minutes = 0; // if the current volume is "very loud" and the device is not playing for more than this time, suggest the default volume for new connections instead of the current volume.
+// Note 1: This timeout is set to 0 by default to disable this feature. Set it to some positive number, e.g. 180 to activate the feature.
+// Note 2: Not all applications use the suggested volume: MacOS Music and Mac OS System Sounds use their own settings.
+
// run_this_when_volume_is_set = "/full/path/to/application/and/args"; // Run the specified application whenever the volume control is set or changed.
// The desired AirPlay volume is appended to the end of the command line – leave a space if you want it treated as an extra argument.
-// AirPlay volume goes from 0 to -30 and -144 means "mute".
+// AirPlay volume goes from 0.0 to -30.0 and -144.0 means "mute".
// audio_backend_latency_offset_in_seconds = 0.0; // This is added to the latency requested by the player to delay or advance the output by a fixed amount.
// Use it, for example, to compensate for a fixed delay in the audio back end.
-16.0; // if the volume exceeds this, reset to the default volume if idle for the
// limit_to_high_volume_threshold_time_in_minutes time
config.limit_to_high_volume_threshold_time_in_minutes =
- 3 * 60; // after this time in minutes, if the volume is higher, use the default_airplay_volume volume
- // for new play sessions.
+ 0; // after this time in minutes, if the volume is higher, use the default_airplay_volume
+ // volume for new play sessions.
config.fixedLatencyOffset = 11025; // this sounds like it works properly.
config.diagnostic_drop_packet_fraction = 0.0;
config.active_state_timeout = 10.0;
config.volume_max_db_set = 1;
}
+ /* Get the optional default_volume setting. */
+ if (config_lookup_float(config.cfg, "general.default_airplay_volume", &dvalue)) {
+ // debug(1, "Default airplay volume setting of %f on the -30.0 to 0 scale", dvalue);
+ if ((dvalue >= -30.0) && (dvalue <= 0.0)) {
+ config.default_airplay_volume = dvalue;
+ } else {
+ warn("The default airplay volume setting must be between -30.0 and 0.0.");
+ }
+ }
+
+ /* Get the optional high_volume_threshold setting. */
+ if (config_lookup_float(config.cfg, "general.high_threshold_airplay_volume", &dvalue)) {
+ // debug(1, "High threshold airplay volume setting of %f on the -30.0 to 0 scale", dvalue);
+ if ((dvalue >= -30.0) && (dvalue <= 0.0)) {
+ config.high_threshold_airplay_volume = dvalue;
+ } else {
+ warn("The high threshold airplay volume setting must be between -30.0 and 0.0.");
+ }
+ }
+
+ /* Get the optional high volume idle tiomeout setting. */
+ if (config_lookup_float(config.cfg, "general.high_volume_idle_timeout_in_minutes", &dvalue)) {
+ // debug(1, "High high_volume_idle_timeout_in_minutes setting of %f", dvalue);
+ if (dvalue >= 0.0) {
+ config.limit_to_high_volume_threshold_time_in_minutes = dvalue;
+ } else {
+ warn("The high volume idle timeout in minutes setting must be 0.0 or greater. A setting "
+ "of 0.0 disables the high volume check.");
+ }
+ }
+
if (config_lookup_string(config.cfg, "general.run_this_when_volume_is_set", &str)) {
config.cmd_set_volume = (char *)str;
}
debug(1, "busy timeout time is %d.", config.timeout);
debug(1, "drift tolerance is %f seconds.", config.tolerance);
debug(1, "password is \"%s\".", strnull(config.password));
+ debug(1, "default airplay volume is %.6f.", config.default_airplay_volume);
+ debug(1, "high threshold airplay volume is %.6f.", config.high_threshold_airplay_volume);
+ if (config.limit_to_high_volume_threshold_time_in_minutes == 0)
+ debug(1, "check for higher-than-threshold volume for new play session is disabled.");
+ else
+ debug(1,
+ "suggest default airplay volume for new play session instead of higher-than-threshold "
+ "airplay volume after %d minutes.",
+ config.limit_to_high_volume_threshold_time_in_minutes);
debug(1, "ignore_volume_control is %d.", config.ignore_volume_control);
if (config.volume_max_db_set)
debug(1, "volume_max_db is %d.", config.volume_max_db);