From: Mike Brady Date: Tue, 10 Sep 2019 12:03:54 +0000 (+0100) Subject: ensure alsa mixer is initialised before trying to set volume. Normalise the 'pvol... X-Git-Tag: 3.3.3~2^2~31 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e8a92d3c3b37ff7e697cd4f7c2b7b9c4a5694102;p=thirdparty%2Fshairport-sync.git ensure alsa mixer is initialised before trying to set volume. Normalise the 'pvol' volume mesasages to the hardware devices' maximum volume when using combined hardware and software attenuation. --- diff --git a/audio_alsa.c b/audio_alsa.c index 454d27ff..22aad333 100644 --- a/audio_alsa.c +++ b/audio_alsa.c @@ -139,9 +139,8 @@ static long alsa_mix_mindb, alsa_mix_maxdb; static char *alsa_out_dev = "default"; static char *alsa_mix_dev = NULL; -static char *alsa_mix_ctrl = "Master"; +static char *alsa_mix_ctrl = NULL; static int alsa_mix_index = 0; -static int hardware_mixer = 0; static int has_softvol = 0; int64_t dither_random_number_store = 0; @@ -204,7 +203,7 @@ int precision_delay_available() { } else { pthread_cleanup_push(malloc_cleanup, silence); int use_dither = 0; - if ((hardware_mixer == 0) && (config.ignore_volume_control == 0) && + if ((alsa_mix_ctrl == NULL) && (config.ignore_volume_control == 0) && (config.airplay_volume != 0.0)) use_dither = 1; dither_random_number_store = @@ -279,7 +278,7 @@ void set_alsa_out_dev(char *dev) { alsa_out_dev = dev; } // assuming pthread cancellation is disabled int open_mixer() { int response = 0; - if (hardware_mixer) { + if (alsa_mix_ctrl != NULL) { debug(3, "Open Mixer"); int ret = 0; snd_mixer_selem_id_alloca(&alsa_mix_sid); @@ -865,15 +864,17 @@ int open_alsa_device(int do_auto_setup) { return result; } -int do_alsa_device_init_if_needed() { +int prepare_mixer() { int response = 0; - // do any alsa device initialisation (general case) if needed + // do any alsa device initialisation (general case) // at present, this is only needed if a hardware mixer is being used - // if there's a hardware mixer, it needs to be initialised before first use - if (alsa_device_initialised == 0) { - alsa_device_initialised = 1; - if (hardware_mixer) { - debug(2, "alsa: hardware mixer init"); + // if there's a hardware mixer, it needs to be initialised before use + if (alsa_mix_ctrl == NULL) { + audio_alsa.volume = NULL; + audio_alsa.parameters = NULL; + audio_alsa.mute = NULL; + } else { + debug(2, "alsa: hardware mixer prepare"); int oldState; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldState); // make this un-cancellable @@ -975,10 +976,14 @@ int do_alsa_device_init_if_needed() { pthread_cleanup_pop(0); pthread_setcancelstate(oldState, NULL); } - } return response; } +int alsa_device_init() { + return prepare_mixer(); +} + + static int init(int argc, char **argv) { // for debugging snd_output_stdio_attach(&output, stdout, 0); @@ -1050,7 +1055,6 @@ static int init(int argc, char **argv) { /* Get the Mixer Control Name. */ if (config_lookup_string(config.cfg, "alsa.mixer_control_name", &str)) { alsa_mix_ctrl = (char *)str; - hardware_mixer = 1; } /* Get the disable_synchronization setting. */ @@ -1325,7 +1329,6 @@ static int init(int argc, char **argv) { break; case 'c': alsa_mix_ctrl = optarg; - hardware_mixer = 1; break; case 'i': alsa_mix_index = strtol(optarg, NULL, 10); @@ -1412,8 +1415,9 @@ static void start(__attribute__((unused)) int i_sample_rate, stall_monitor_start_time = 0; stall_monitor_frame_count = 0; if (alsa_device_initialised == 0) { - debug(2, "alsa: start() calling do_alsa_device_init_if_needed."); - do_alsa_device_init_if_needed(); + debug(1, "alsa: start() calling alsa_device_init."); + alsa_device_init(); + alsa_device_initialised = 1; } } @@ -1799,6 +1803,11 @@ int prepare(void) { pthread_cleanup_debug_mutex_lock(&alsa_mutex, 50000, 0); if (alsa_backend_state == abm_disconnected) { + if (alsa_device_initialised == 0) { + debug(1, "alsa: prepare() calling alsa_device_init."); + alsa_device_init(); + alsa_device_initialised = 1; + } ret = do_open(1); // do auto setup if (ret == 0) debug(2, "alsa: prepare() -- opened output device"); @@ -1891,7 +1900,7 @@ void volume(double vol) { static void linear_volume(double vol) { debug(2, "Setting linear volume to %f.", vol); set_volume = vol; - if (hardware_mixer && alsa_mix_handle) { + if ((alsa_mix_ctrl == NULL) && alsa_mix_handle) { double linear_volume = pow(10, vol); // debug(1,"Linear volume is %f.",linear_volume); long int_vol = alsa_mix_minv + (alsa_mix_maxv - alsa_mix_minv) * @@ -1933,8 +1942,9 @@ void *alsa_buffer_monitor_thread_code(__attribute__((unused)) void *arg) { } if ((config.keep_dac_busy != 0) && (alsa_device_initialised == 0)) { debug(2, "alsa: alsa_buffer_monitor_thread_code() calling " - "do_alsa_device_init_if_needed."); - do_alsa_device_init_if_needed(); + "alsa_device_init."); + alsa_device_init(); + alsa_device_initialised = 1; } int sleep_time_ms = (int)(config.disable_standby_mode_silence_scan_interval * 1000); pthread_cleanup_debug_mutex_lock(&alsa_mutex, 200000, 0); @@ -1992,7 +2002,7 @@ void *alsa_buffer_monitor_thread_code(__attribute__((unused)) void *arg) { int ret; pthread_cleanup_push(malloc_cleanup, silence); int use_dither = 0; - if ((hardware_mixer == 0) && (config.ignore_volume_control == 0) && + if ((alsa_mix_ctrl == NULL) && (config.ignore_volume_control == 0) && (config.airplay_volume != 0.0)) use_dither = 1; dither_random_number_store = diff --git a/player.c b/player.c index ba1c07a6..9ad4d051 100644 --- a/player.c +++ b/player.c @@ -2689,7 +2689,6 @@ void *player_thread_func(void *arg) { void player_volume_without_notification(double airplay_volume, rtsp_conn_info *conn) { debug_mutex_lock(&conn->volume_control_mutex, 5000, 1); - debug(2, "player_volume_without_notification %f", airplay_volume); // first, see if we are hw only, sw only, both with hw attenuation on the top or both with sw // attenuation on top @@ -2701,6 +2700,7 @@ void player_volume_without_notification(double airplay_volume, rtsp_conn_info *c int32_t hw_max_db = 0, hw_min_db = 0; // zeroed to quieten an incorrect uninitialised warning int32_t sw_max_db = 0, sw_min_db = -9630; + if (config.output->parameters) { volume_mode = vol_hw_only; audio_parameters audio_information; @@ -2877,8 +2877,14 @@ void player_volume_without_notification(double airplay_volume, rtsp_conn_info *c char *dv = malloc(128); // will be freed in the metadata thread if (dv) { memset(dv, 0, 128); - snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume, scaled_attenuation / 100.0, + if (volume_mode == vol_both) { + // normalise the maximum output to the hardware device's max output + snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume, (scaled_attenuation - max_db + hw_max_db) / 100.0, + (min_db - max_db + hw_max_db) / 100.0, (max_db - max_db + hw_max_db) / 100.0); + } else { + snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume, scaled_attenuation / 100.0, min_db / 100.0, max_db / 100.0); + } send_ssnc_metadata('pvol', dv, strlen(dv), 1); } #endif @@ -2898,7 +2904,7 @@ void player_volume_without_notification(double airplay_volume, rtsp_conn_info *c #ifdef CONFIG_METADATA else { // here, send the 'pvol' metadata message when the airplay volume information - // is not being used by shairport sync to control the output volume + // is being used by shairport sync to control the output volume char *dv = malloc(128); // will be freed in the metadata thread if (dv) { memset(dv, 0, 128);