#include "apple_alac.h"
#endif
- // parameters from the source
- static unsigned char *aesiv;
- #ifdef HAVE_LIBSSL
- static AES_KEY aes;
- #endif
- static int input_rate, input_bit_depth, input_num_channels, max_frames_per_packet;
-
- static uint32_t timestamp_epoch, last_timestamp,
- maximum_timestamp_interval; // timestamp_epoch of zero means not initialised, could start at 2
- // or 1.
-
- static int input_bytes_per_frame = 4;
- static int output_bytes_per_frame;
- static int output_sample_ratio;
- static int output_rate;
- static int64_t previous_random_number = 0;
-
- // The maximum frame size change there can be is +/- 1;
- static int max_frame_size_change;
- // #define FRAME_BYTES(max_frames_per_packet) (4 * max_frames_per_packet)
- // maximal resampling shift - conservative
- //#define OUTFRAME_BYTES(max_frames_per_packet) (4 * (max_frames_per_packet + 3))
-
- #ifdef HAVE_LIBMBEDTLS
- static mbedtls_aes_context dctx;
- #endif
-
- #ifdef HAVE_LIBPOLARSSL
- static aes_context dctx;
- #endif
-
- // static pthread_t player_thread = NULL;
- static int please_stop;
- static int encrypted; // Normally the audio is encrypted, but it may not be
-
- static int
- connection_state_to_output; // if true, then play incoming stuff; if false drop everything
-
- static alac_file *decoder_info;
-
- // debug variables
- static int late_packet_message_sent;
- static uint64_t packet_count = 0;
- static int32_t last_seqno_read;
- static int decoder_in_use = 0;
-
- // interthread variables
- static int fix_volume = 0x10000;
- static pthread_mutex_t vol_mutex = PTHREAD_MUTEX_INITIALIZER;
-
+#include "loudness.h"
+
// default buffer size
// needs to be a power of 2 because of the way BUFIDX(seqno) works
- #define BUFFER_FRAMES 512
+ //#define BUFFER_FRAMES 512
#define MAX_PACKET 2048
// DAC buffer occupancy stuff
}
static inline void process_sample(int32_t sample, char **outp, enum sps_format_t format, int volume,
- int dither) {
+ int dither,rtsp_conn_info *conn) {
int64_t hyper_sample = sample;
int result;
- int64_t hyper_volume = (int64_t)volume << 16;
- hyper_sample = hyper_sample * hyper_volume; // this is 64 bit bit multiplication -- we may need to
- // dither it down to its
- // target resolution
-
+
+ if (config.loudness) {
+ hyper_sample <<= 32; // Do not apply volume as it has already been done with the Loudness DSP filter
+ } else {
+ int64_t hyper_volume = (int64_t)volume << 16;
+ hyper_sample = hyper_sample * hyper_volume; // this is 64 bit bit multiplication -- we may need to
+ // dither it down to its
+ // target resolution
+ }
+
// next, do dither, if necessary
if (dither) {
debug(1, "Output bit depth is %d.", output_bit_depth);
- if (input_bit_depth > output_bit_depth) {
- if (conn->input_bit_depth > output_bit_depth) {
++ if (conn->input_bit_depth >output_bit_depth) {
debug(1, "Dithering will be enabled because the input bit depth is greater than the output bit "
"depth");
}
}
// we need an intermediate "transition" buffer
-
- // debug(1,"Define tbuf of length
- // %d.",output_bytes_per_frame*(max_frames_per_packet*output_sample_ratio+max_frame_size_change));
-
- tbuf = malloc(sizeof(int32_t) * 2 *
- (max_frames_per_packet * output_sample_ratio + max_frame_size_change));
- if (tbuf == NULL)
- die("Failed to allocate memory for the transition buffer.");
- sbuf = 0;
- if (config.packet_stuffing == ST_soxr) { // needed for stuffing
- sbuf = malloc(sizeof(int32_t) * 2 *
- (max_frames_per_packet * output_sample_ratio + max_frame_size_change));
- if (sbuf == NULL)
- die("Failed to allocate sbuf memory for the transition buffer.");
- }
-
+
+ // if ((input_rate!=config.output_rate) || (input_bit_depth!=output_bit_depth)) {
+ // debug(1,"Define tbuf of length
+ // %d.",output_bytes_per_frame*(max_frames_per_packet*output_sample_ratio+max_frame_size_change));
+ tbuf = malloc(sizeof(int32_t) * 2 *
+ (conn->max_frames_per_packet * conn->output_sample_ratio + conn->max_frame_size_change));
+ if (tbuf == NULL)
- debug(1, "Failed to allocate memory for the transition buffer.");
++ die("Failed to allocate memory for the transition buffer.");
+ sbuf = 0;
+ if (config.packet_stuffing == ST_soxr) { // needed for stuffing
+ sbuf = malloc(sizeof(int32_t) * 2 *
+ (conn->max_frames_per_packet * conn->output_sample_ratio + conn->max_frame_size_change));
+ if (sbuf == NULL)
- debug(1, "Failed to allocate memory for the transition buffer.");
++ debug(1, "Failed to allocate memory for the sbuf buffer.");
+ }
-
// We might need an output buffer and a buffer of silence.
// The size of these dependents on the number of frames, the size of each frame and the maximum
// size change
- outbuf = malloc(output_bytes_per_frame *
- (max_frames_per_packet * output_sample_ratio + max_frame_size_change));
+ outbuf = malloc(conn->output_bytes_per_frame *
+ (conn->max_frames_per_packet * conn->output_sample_ratio + conn->max_frame_size_change));
if (outbuf == NULL)
- debug(1, "Failed to allocate memory for an output buffer.");
+ die("Failed to allocate memory for an output buffer.");
- silence = malloc(output_bytes_per_frame * max_frames_per_packet * output_sample_ratio);
+ silence = malloc(conn->output_bytes_per_frame * conn->max_frames_per_packet * conn->output_sample_ratio);
if (silence == NULL)
- debug(1, "Failed to allocate memory for a silence buffer.");
+ die("Failed to allocate memory for a silence buffer.");
- memset(silence, 0, output_bytes_per_frame * max_frames_per_packet * output_sample_ratio);
- late_packet_message_sent = 0;
- first_packet_timestamp = 0;
- missing_packets = late_packets = too_late_packets = resend_requests = 0;
- flush_rtp_timestamp = 0; // it seems this number has a special significance -- it seems to be used
+ memset(silence, 0, conn->output_bytes_per_frame * conn->max_frames_per_packet * conn->output_sample_ratio);
+ conn->first_packet_timestamp = 0;
+ conn->missing_packets = conn->late_packets = conn->too_late_packets = conn->resend_requests = 0;
+ conn->flush_rtp_timestamp = 0; // it seems this number has a special significance -- it seems to be used
// as a null operand, so we'll use it like that too
int sync_error_out_of_bounds =
0; // number of times in a row that there's been a serious sync error
// here, let's transform the frame of data, if necessary
- switch (input_bit_depth) {
- if (tbuf != NULL) { // this will be null if no changes are needed
- switch (conn->input_bit_depth) {
++ switch (conn->input_bit_depth) {
case 16: {
int i, j;
int16_t ls, rs;
} break;
default:
die("Shairport Sync only supports 16 bit input");
- }
-
- // inbuf = tbuf;
- inbuflength *= conn->output_sample_ratio;
}
- inbuflength *= output_sample_ratio;
++ inbuflength *= conn->output_sample_ratio;
+
// We have a frame of data. We need to see if we want to add or remove a frame from it to
// keep in sync.
// So we calculate the timing error for the first frame in the DAC.
if (config.no_sync != 0)
amount_to_stuff = 0; // no stuffing if it's been disabled
- float gain = fix_volume / 65536.0f;
+
+ // Apply DSP here
+ if (config.loudness
+#ifdef CONFIG_CONVOLUTION
+ || config.convolution
+#endif
+ )
+ {
+ int32_t *tbuf32 = (int32_t*)tbuf;
+ float fbuf_l[inbuflength];
+ float fbuf_r[inbuflength];
+
+ // Deinterleave, and convert to float
+ int i;
+ for (i=0; i<inbuflength; ++i)
+ {
+ fbuf_l[i] = tbuf32[2*i];
+ fbuf_r[i] = tbuf32[2*i+1];
+ }
+
+#ifdef CONFIG_CONVOLUTION
+ // Apply convolution
+ if (config.convolution)
+ {
+ convolver_process_l(fbuf_l, inbuflength);
+ convolver_process_r(fbuf_r, inbuflength);
+
+ float gain = pow(10.0, config.convolution_gain/20.0);
+ for (i=0; i<inbuflength; ++i)
+ {
+ fbuf_l[i] *= gain;
+ fbuf_r[i] *= gain;
+ }
+
+ }
+#endif
+
+ if (config.loudness)
+ {
+ // Apply volume and loudness
+ // Volume must be applied here because the loudness filter will increase the signal level and it would saturate the int32_t otherwise
++ float gain = conn->fix_volume / 65536.0f;
+ float gain_db = 20*log10(gain);
+ //debug(1, "Applying soft volume dB: %f k: %f", gain_db, gain);
+
+ for (i=0; i<inbuflength; ++i)
+ {
+ fbuf_l[i] = loudness_process(&loudness_l, fbuf_l[i] * gain);
+ fbuf_r[i] = loudness_process(&loudness_r, fbuf_r[i] * gain);
+ }
+ }
+
+ // Interleave and convert back to int32_t
+ for (i=0; i<inbuflength; ++i)
+ {
+ tbuf32[2*i] = fbuf_l[i];
+ tbuf32[2*i+1] = fbuf_r[i];
+ }
+
+ }
+
#ifdef HAVE_LIBSOXR
switch (config.packet_stuffing) {
case ST_basic:
// debug(1,"Software attenuation set to %f, i.e %f out of 65,536, for airplay volume of
// %f",software_attenuation,temp_fix_volume,airplay_volume);
- pthread_mutex_lock(&vol_mutex);
- fix_volume = temp_fix_volume;
- pthread_mutex_unlock(&vol_mutex);
-
+ pthread_mutex_lock(&conn->vol_mutex);
+ conn->fix_volume = temp_fix_volume;
+ pthread_mutex_unlock(&conn->vol_mutex);
+
+ if (config.loudness)
+ loudness_set_volume(software_attenuation/100);
+
#ifdef CONFIG_METADATA
char *dv = malloc(128); // will be freed in the metadata thread
if (dv) {