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.
This commit is contained in:
+30
-20
@@ -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 =
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user