Continuing to check the high-volume limiter. Add configuration file settings for default and threshold volume settings and timeout. Include in diagnostics, set tentative defaults.

This commit is contained in:
Mike Brady
2023-01-19 12:44:26 +00:00
parent 66ca645002
commit 72f1554cbb
4 changed files with 89 additions and 30 deletions
+22 -24
View File
@@ -1704,33 +1704,31 @@ void statistics_item(const char *heading, const char *format, ...) {
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;
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
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))) {
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;
}
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;
}
}
}
+9 -3
View File
@@ -757,19 +757,24 @@ void cleanup_threads(void) {
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
@@ -5477,6 +5482,7 @@ void *rtsp_listen_loop(__attribute((unused)) void *arg) {
FD_SET(sockfd[i], &fds);
ret = select(maxfd + 1, &fds, 0, 0, &tv);
if (ret < 0) {
if (errno == EINTR)
continue;
+16 -1
View File
@@ -43,9 +43,24 @@ general =
// "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.
+42 -2
View File
@@ -471,8 +471,8 @@ int parse_options(int argc, char **argv) {
-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;
@@ -845,6 +845,37 @@ int parse_options(int argc, char **argv) {
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;
}
@@ -2392,6 +2423,15 @@ int main(int argc, char **argv) {
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);