static void volume(double vol);
static void linear_volume(double vol);
static void parameters(audio_parameters *info);
+static void mute(int do_mute);
static int has_mute = 0;
static double set_volume;
}
debug(1, "Hardware mixer has dB volume from %f to %f.", (1.0 * alsa_mix_mindb) / 100.0,
(1.0 * alsa_mix_maxdb) / 100.0);
- if (config.volume_range_db) {
- long suggested_alsa_min_db = alsa_mix_maxdb - (long)trunc(config.volume_range_db*100);
- if (suggested_alsa_min_db > alsa_mix_mindb)
- alsa_mix_mindb = suggested_alsa_min_db;
- else
- inform("The volume_range_db setting, %f is greater than the native range of the mixer %f, so it is ignored.",config.volume_range_db,(alsa_mix_maxdb-alsa_mix_mindb)/100.0);
- }
} else {
// use the linear scale and do the db conversion ourselves
debug(1, "note: the hardware mixer specified -- \"%s\" -- does not have a dB volume scale, so it can't be used.",alsa_mix_ctrl);
}
static void parameters(audio_parameters *info) {
- info->has_true_mute = has_mute;
- info->is_muted = ((has_mute) && (set_volume == -144.0));
info->minimum_volume_dB = alsa_mix_mindb;
info->maximum_volume_dB = alsa_mix_maxdb;
- info->airplay_volume = set_volume;
- info->current_volume_dB = vol2attn(set_volume, alsa_mix_maxdb, alsa_mix_mindb);
}
static void volume(double vol) {
- // debug(1,"Volume called %f.",vol);
- set_volume = vol;
- double vol_setting = vol2attn(vol, alsa_mix_maxdb, alsa_mix_mindb);
// debug(1,"Setting volume db to %f, for volume input of %f.",vol_setting/100,vol);
- if (snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol_setting, -1) != 0)
+ if (snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol, -1) != 0)
die("Failed to set playback dB volume");
- if (has_mute)
- snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, (vol != -144.0));
}
static void linear_volume(double vol) {
- set_volume = vol;
- double vol_setting = vol2attn(vol, 0, alsa_mix_mindb)/2000;
- // debug(1,"Adjusted volume is %f.",vol_setting);
- double linear_volume = pow(10, vol_setting);
+ 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) * linear_volume;
// debug(1,"Setting volume to %ld, for volume input of %f.",int_vol,vol);
if (snd_mixer_selem_set_playback_volume_all(alsa_mix_elem, int_vol) != 0)
die("Failed to set playback volume");
- if (has_mute)
- snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, (vol != -144.0));
+}
+
+static void mute(int do_mute) {
+ if (has_mute) {
+ if (do_mute)
+ snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, 0);
+ else
+ snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, 1);
+ }
}
static int32_t last_seqno_read;
// interthread variables
-static double software_mixer_volume = 1.0;
static int fix_volume = 0x10000;
static pthread_mutex_t vol_mutex = PTHREAD_MUTEX_INITIALIZER;
if (ab_synced) {
do {
curframe = audio_buffer + BUFIDX(ab_read);
- if (curframe->ready) {
+ if ((ab_read!=ab_write) && (curframe->ready)) { // it could be synced and empty, under exceptional circumstances, with the frame unused, thus apparently ready
if (curframe->sequence_number != ab_read) {
// some kind of sync problem has occurred.
}
// finally, adjust the volume, if necessary
- if (software_mixer_volume != 1.0) {
+ if (fix_volume != 65536.0) {
// pthread_mutex_lock(&vol_mutex);
op = outptr;
for (i = 0; i < frame_size + stuff; i++) {
inform("Sync error: %.1f (frames); net correction: %.1f (ppm); corrections: %.1f "
"(ppm); missing packets %llu; late packets %llu; too late packets %llu; "
"resend requests %llu; min DAC queue size %lli, min and max buffer occupancy "
- "%u and %u.",
+ "%d and %d.",
moving_average_sync_error, moving_average_correction * 1000000 / 352,
moving_average_insertions_plus_deletions * 1000000 / 352, missing_packets,
late_packets, too_late_packets, resend_requests, minimum_dac_queue_size,
else
inform("Synchronisation disabled. Missing packets %llu; late packets %llu; too late packets %llu; "
"resend requests %llu; min and max buffer occupancy "
- "%u and %u.",
+ "%d and %d.",
missing_packets,
late_packets, too_late_packets, resend_requests,
minimum_buffer_occupancy, maximum_buffer_occupancy);
}
// takes the volume as specified by the airplay protocol
-void player_volume(double f) {
+void player_volume(double airplay_volume) {
// The volume ranges -144.0 (mute) or -30 -- 0. See
// http://git.zx2c4.com/Airtunes2/about/#setting-volume
// or 20 times the log of the ratio. Then multiplied by 100 for convenience.
// Thus, we ask our vol2attn function for an appropriate dB between -96.3 and 0 dB and translate
// it back to a number.
-
- double linear_volume = 0.0;
-
- if (config.output->volume) {
- // debug(1,"Set volume to %f.",f);
- config.output->volume(f); // volume will be sent as metadata by the config.output device
- linear_volume = 1.0; // no attenuation needed -- this value is used as a flag to avoid calculations
- }
-
- if (config.output->parameters)
+
+
+ // get the audio parameters
+
+ int32_t min,max;
+
+ if (config.output->parameters) {
config.output->parameters(&audio_information);
- else {
- long mindb = -9630;
- if (config.volume_range_db) {
- long suggested_alsa_min_db = -(long)trunc(config.volume_range_db*100);
- if (suggested_alsa_min_db > mindb)
- mindb = suggested_alsa_min_db;
- else
- inform("The volume_range_db setting, %f is greater than the native range of the mixer %f, so it is ignored.",config.volume_range_db,mindb/100.0);
- }
- double scaled_volume = vol2attn(f, 0, mindb);
- linear_volume = pow(10, scaled_volume / 2000);
- audio_information.airplay_volume = f;
- audio_information.minimum_volume_dB = mindb;
- audio_information.maximum_volume_dB = 0;
- audio_information.current_volume_dB = scaled_volume;
- audio_information.has_true_mute = 0;
- audio_information.is_muted = 0;
- // debug(1,"Minimum software volume set to %d centi-dB",f,mindb);
+ max = audio_information.maximum_volume_dB;
+ min = audio_information.minimum_volume_dB;
+ } else {
+ max = 0;
+ min = -9630;
}
- audio_information.valid = 1;
- // debug(1,"Software volume set to %f on scale with a %f dB",f,linear_volume);
+
+ double temp_fix_volume = 65536.0;
+ double scaled_volume;
+
+ if (airplay_volume==-144.0) { // if we are muting
+ scaled_volume = min; // this is just for the metadata
+ if (config.output->mute)
+ config.output->mute(1); // use real mute if it's there
+ else if (config.output->volume) {
+ config.output_.volume(min); // otherwise set the output to the lowest value
+ temp_fix_volume = 0; // and set the software multiplier to 0.
+ }
+ } else { // not muting
+
+ if (config.volume_range_db) {
+ int32_t possible_min = max - (int)trunc(config.volume_range_db*100);
+ if (possible_min > min)
+ min = possible_min;
+ }
+
+ // now we have the true desired range, get the volume that is being set
+ scaled_volume = vol2attn(airplay_volume, max, min);
+ double software_volume = 0; dB or attenuation
+
+ if (config.output->volume) {
+ if (scaled_volume>=min) {
+ config.output->volume(scaled_volume);
+ } else {
+ config.output->volume(min);
+ software_volume = scaled_volume-min; // this is the attenuation in dB needed in software
+ }
+ } else {
+ software_volume = scaled_volume;
+ }
+ if (config.output->mute) // if there is hardware mute...
+ config.output->mute(0); // turn it off
+ temp_fix_volume = 65536.0 * pow(10, software_volume / 2000);
+ }
+ // debug(1,"Software volume set to %f on scale with a %f dB",airplay_volume,pow(10, software_volume / 2000));
pthread_mutex_lock(&vol_mutex);
- software_mixer_volume = linear_volume;
- fix_volume = 65536.0 * software_mixer_volume;
+ fix_volume = temp_fix_volume;
pthread_mutex_unlock(&vol_mutex);
+
#ifdef CONFIG_METADATA
char *dv = malloc(128); // will be freed in the metadata thread
if (dv) {
memset(dv, 0, 128);
- snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", audio_information.airplay_volume,
- audio_information.current_volume_dB / 100.0,
- audio_information.minimum_volume_dB / 100.0,
- audio_information.maximum_volume_dB / 100.0);
+ snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume,
+ scaled_volume / 100.0,
+ min / 100.0,
+ max / 100.0);
send_ssnc_metadata('pvol', dv, strlen(dv), 1);
}
#endif