Work in progress, doesn't compile
This commit is contained in:
@@ -5,13 +5,9 @@
|
||||
#include <libconfig.h>
|
||||
|
||||
typedef struct {
|
||||
double airplay_volume;
|
||||
double current_volume_dB;
|
||||
int minimum_volume_dB;
|
||||
int maximum_volume_dB;
|
||||
int has_true_mute;
|
||||
int is_muted;
|
||||
int valid;
|
||||
int32_t minimum_volume_dB;
|
||||
int32_t maximum_volume_dB;
|
||||
} audio_parameters;
|
||||
|
||||
typedef struct {
|
||||
@@ -42,6 +38,10 @@ typedef struct {
|
||||
|
||||
// may be NULL, in which case soft volume parameters are used
|
||||
void (*parameters)(audio_parameters *info);
|
||||
|
||||
// may be NULL, in which case software muting is used.
|
||||
void (*mute)(int do_mute);
|
||||
|
||||
} audio_output;
|
||||
|
||||
audio_output *audio_get_output(char *name);
|
||||
|
||||
+12
-23
@@ -46,6 +46,7 @@ static uint32_t delay(void);
|
||||
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;
|
||||
|
||||
@@ -234,13 +235,6 @@ static int init(int argc, char **argv) {
|
||||
}
|
||||
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);
|
||||
@@ -447,35 +441,30 @@ static void stop(void) {
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -153,4 +153,5 @@ audio_output audio_ao = {.name = "ao",
|
||||
.delay = NULL,
|
||||
.play = &play,
|
||||
.volume = NULL,
|
||||
.parameters = NULL};
|
||||
.parameters = NULL,
|
||||
.mute = NULL};
|
||||
|
||||
+2
-1
@@ -60,4 +60,5 @@ audio_output audio_dummy = {.name = "dummy",
|
||||
.delay = NULL,
|
||||
.play = &play,
|
||||
.volume = NULL,
|
||||
.parameters = NULL};
|
||||
.parameters = NULL,
|
||||
.mute = NULL};
|
||||
|
||||
+2
-1
@@ -133,4 +133,5 @@ audio_output audio_pipe = {.name = "pipe",
|
||||
.delay = NULL,
|
||||
.play = &play,
|
||||
.volume = NULL,
|
||||
.parameters = NULL};
|
||||
.parameters = NULL,
|
||||
.mute = NULL};
|
||||
|
||||
+2
-1
@@ -137,4 +137,5 @@ audio_output audio_pulse = {.name = "pulse",
|
||||
.delay = NULL,
|
||||
.play = &play,
|
||||
.volume = NULL,
|
||||
.parameters = NULL};
|
||||
.parameters = NULL,
|
||||
.mute = NULL};
|
||||
|
||||
+2
-1
@@ -81,4 +81,5 @@ audio_output audio_sndio = {.name = "sndio",
|
||||
.delay = NULL,
|
||||
.play = &play,
|
||||
.volume = &volume,
|
||||
.parameters = NULL};
|
||||
.parameters = NULL,
|
||||
.mute= NULL};
|
||||
|
||||
+2
-1
@@ -96,4 +96,5 @@ audio_output audio_stdout = {.name = "stdout",
|
||||
.delay = NULL,
|
||||
.play = &play,
|
||||
.volume = NULL,
|
||||
.parameters = NULL};
|
||||
.parameters = NULL,
|
||||
.mute = NULL};
|
||||
|
||||
@@ -121,7 +121,7 @@ uint32_t uatoi(const char *nptr);
|
||||
shairport_cfg config;
|
||||
config_t config_file_stuff;
|
||||
|
||||
uint32_t buffer_occupancy;
|
||||
int32_t buffer_occupancy; // allow it to be negative because seq_diff may be negative
|
||||
int64_t session_corrections;
|
||||
uint32_t play_segment_reference_frame;
|
||||
uint64_t play_segment_reference_frame_remote_time;
|
||||
|
||||
@@ -95,7 +95,6 @@ static uint64_t packet_count = 0;
|
||||
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;
|
||||
|
||||
@@ -452,7 +451,7 @@ static abuf_t *buffer_get_frame(void) {
|
||||
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.
|
||||
@@ -838,7 +837,7 @@ static int stuff_buffer_soxr(short *inptr, short *outptr, int stuff) {
|
||||
}
|
||||
|
||||
// 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++) {
|
||||
@@ -1171,7 +1170,7 @@ static void *player_thread_func(void *arg) {
|
||||
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,
|
||||
@@ -1179,7 +1178,7 @@ static void *player_thread_func(void *arg) {
|
||||
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);
|
||||
@@ -1201,7 +1200,7 @@ static void *player_thread_func(void *arg) {
|
||||
}
|
||||
|
||||
// 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
|
||||
@@ -1218,50 +1217,71 @@ void player_volume(double f) {
|
||||
// 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
|
||||
|
||||
Reference in New Issue
Block a user