#endif
static int sampling_rate, frame_size;
-#define FRAME_BYTES(frame_size) (4 * frame_size)
+static int bytes_per_audio_frame = 4;
+
+// The maximum frame size change there can be is +/- 1;
+static int max_frame_size_change = 1;
+// #define FRAME_BYTES(frame_size) (4 * frame_size)
// maximal resampling shift - conservative
-#define OUTFRAME_BYTES(frame_size) (4 * (frame_size + 3))
+//#define OUTFRAME_BYTES(frame_size) (4 * (frame_size + 3))
#ifdef HAVE_LIBPOLARSSL
static aes_context dctx;
uint32_t timestamp;
seq_t sequence_number;
signed short *data;
+ int length; // the length of the decoded data
} abuf_t;
static abuf_t audio_buffer[BUFFER_FRAMES];
#define BUFIDX(seqno) ((seq_t)(seqno) % BUFFER_FRAMES)
return (C & 0x80000000) == 0;
}
-static int alac_decode(short *dest, uint8_t *buf, int len) {
+static int alac_decode(short *dest, int *destlen, uint8_t *buf, int len) {
+ // parameters: where the decoded stuff goes, its length in samples,
+ // the incoming packet, the length of the incoming packet in bytes
+ // destlen should contain the allowed max number of samples on entry
+
+ if (len>MAX_PACKET) {
+ warn("Incoming audio packet size is too large at %d; it should not exceed %d.",len,MAX_PACKET);
+ return -1;
+ }
unsigned char packet[MAX_PACKET];
unsigned char packetp[MAX_PACKET];
- assert(len <= MAX_PACKET);
+ // assert(len <= MAX_PACKET);
int reply = 0; //everything okay
- int outsize=FRAME_BYTES(frame_size); // the size it should be
+ int outsize=bytes_per_audio_frame*(*destlen); // the size the output should be, in bytes
+ int toutsize = outsize;
if (encrypted) {
unsigned char iv[16];
} else {
alac_decode_frame(decoder_info, buf, dest, &outsize);
}
- if (outsize!=FRAME_BYTES(frame_size)) {
- if(outsize<FRAME_BYTES(frame_size)) {
- debug(2,"Output from alac_decode is smaller than expected. Encrypted = %d.",encrypted);
- } else {
- debug(2,"Output from alac_decode larger than expected -- truncated, but buffer overflow possible! Encrypted = %d.",encrypted);
- }
- reply = -1; // output frame is the wrong size
- }
+
+ if(outsize>toutsize) {
+ debug(2,"Output from alac_decode larger (%d bytes, not frames) than expected (%d bytes) -- truncated, but buffer overflow possible! Encrypted = %d.",outsize, toutsize, encrypted);
+ reply = -1; // output packet is the wrong size
+ }
+ *destlen = outsize / bytes_per_audio_frame;
+ if ((outsize % bytes_per_audio_frame)!=0)
+ debug(1,"Number of audio frames (%d) does not correspond exactly to the number of bytes (%d) and the audio frame size (%d).",*destlen,outsize,bytes_per_audio_frame);
return reply;
}
static void init_buffer(void) {
int i;
for (i = 0; i < BUFFER_FRAMES; i++)
- audio_buffer[i].data = malloc(OUTFRAME_BYTES(frame_size));
+ audio_buffer[i].data = malloc(bytes_per_audio_frame*(frame_size+max_frame_size_change));
ab_resync();
}
// pthread_mutex_unlock(&ab_mutex);
if (abuf) {
- if (alac_decode(abuf->data, data, len)==0) {
+ int datalen = frame_size;
+ if (alac_decode(abuf->data, &datalen, data, len)==0) {
abuf->ready = 1;
+ abuf->length = datalen;
abuf->timestamp = timestamp;
abuf->sequence_number = seqno;
// debug(2,"Zero length silence buffer needed with gross_frame_gap of %lld and dac_delay of %lld.",gross_frame_gap,dac_delay);
// the fs (number of frames of silence to play) can be zero in the DAC doesn't start ouotputting frames for a while -- it could get loaded up but not start responding for many milliseconds.
if (fs!=0) {
- silence = malloc(FRAME_BYTES(fs));
+ silence = malloc(bytes_per_audio_frame*fs);
if (silence==NULL)
debug(1,"Failed to allocate %d byte silence buffer.",fs);
else {
- memset(silence, 0, FRAME_BYTES(fs));
+ memset(silence, 0, bytes_per_audio_frame*fs);
// debug(1,"Exact frame gap is %llu; play %d frames of silence. Dac_delay is %d,
// with %d packets.",exact_frame_gap,fs,dac_delay,seq_diff(ab_read, ab_write));
config.output->play(silence, fs);
if (!curframe->ready) {
// debug(1, "Supplying a silent frame for frame %u", read);
missing_packets++;
- memset(curframe->data, 0, FRAME_BYTES(frame_size));
+ memset(curframe->data, 0, bytes_per_audio_frame*frame_size);
curframe->timestamp = 0;
}
curframe->ready = 0;
}
// stuff: 1 means add 1; 0 means do nothing; -1 means remove 1
-static int stuff_buffer_basic(short *inptr, short *outptr, int stuff) {
- if ((stuff > 1) || (stuff < -1)) {
- debug(1, "Stuff argument to stuff_buffer must be from -1 to +1.");
- return frame_size;
+static int stuff_buffer_basic(short *inptr, int length, short *outptr, int stuff) {
+ if ((stuff > 1) || (stuff < -1) || (length <100)) {
+ // debug(1, "Stuff argument to stuff_buffer must be from -1 to +1 and length >100.");
+ return length;
}
int i;
- int stuffsamp = frame_size;
+ int stuffsamp = length;
if (stuff)
- // stuffsamp = rand() % (frame_size - 1);
+ // stuffsamp = rand() % (length - 1);
stuffsamp =
- (rand() % (frame_size - 2)) + 1; // ensure there's always a sample before and after the item
+ (rand() % (length - 2)) + 1; // ensure there's always a sample before and after the item
pthread_mutex_lock(&vol_mutex);
for (i = 0; i < stuffsamp; i++) { // the whole frame, if no stuffing
inptr++;
inptr++;
}
- for (i = stuffsamp; i < frame_size + stuff; i++) {
+
+ // if you're removing, i.e. stuff < 0, copy that much less over. If you're adding, do all the rest.
+ for (i = stuffsamp; i < (stuff>0) ? length : length+stuff; i++) {
*outptr++ = dithered_vol(*inptr++);
*outptr++ = dithered_vol(*inptr++);
}
}
pthread_mutex_unlock(&vol_mutex);
- return frame_size + stuff;
+ return length + stuff;
}
#ifdef HAVE_LIBSOXR
// stuff: 1 means add 1; 0 means do nothing; -1 means remove 1
-static int stuff_buffer_soxr(short *inptr, short *outptr, int stuff) {
- if ((stuff > 1) || (stuff < -1)) {
- debug(1, "Stuff argument to sox_stuff_buffer must be from -1 to +1.");
- return frame_size;
+static int stuff_buffer_soxr(short *inptr, int length, short *outptr, int stuff) {
+ if ((stuff > 1) || (stuff < -1) || (length < 100)) {
+ // debug(1, "Stuff argument to sox_stuff_buffer must be from -1 to +1 and length must be > 100.");
+ return length;
}
int i;
short *ip, *op;
size_t odone;
- soxr_error_t error = soxr_oneshot(frame_size, frame_size + stuff, 2, /* Rates and # of chans. */
- inptr, frame_size, NULL, /* Input. */
- outptr, frame_size + stuff, &odone, /* Output. */
+ soxr_error_t error = soxr_oneshot(length, length + stuff, 2, /* Rates and # of chans. */
+ inptr, length, NULL, /* Input. */
+ outptr, length + stuff, &odone, /* Output. */
&io_spec, /* Input, output and transfer spec. */
NULL, NULL); /* Default configuration.*/
if (error)
die("soxr error: %s\n", "error: %s\n", soxr_strerror(error));
- if (odone > frame_size + 1)
+ if (odone > length + 1)
die("odone = %d!\n", odone);
const int gpm = 5;
}
// keep the last (dpm) samples, to mitigate the Gibbs phenomenon
- op = outptr + (frame_size + stuff - gpm) * sizeof(short);
- ip = inptr + (frame_size - gpm) * sizeof(short);
+ op = outptr + (length + stuff - gpm) * sizeof(short);
+ ip = inptr + (length - gpm) * sizeof(short);
for (i = 0; i < gpm; i++) {
*op++ = *ip++;
*op++ = *ip++;
if (fix_volume != 65536.0) {
// pthread_mutex_lock(&vol_mutex);
op = outptr;
- for (i = 0; i < frame_size + stuff; i++) {
+ for (i = 0; i < length + stuff; i++) {
*op = dithered_vol(*op);
op++;
*op = dithered_vol(*op);
} else { // the whole frame, if no stuffing
// pthread_mutex_lock(&vol_mutex);
- for (i = 0; i < frame_size; i++) {
+ for (i = 0; i < length; i++) {
*op++ = dithered_vol(*ip++);
*op++ = dithered_vol(*ip++);
};
// pthread_mutex_unlock(&vol_mutex);
}
- return frame_size + stuff;
+ return length + stuff;
}
#endif
initstate(time(NULL), rnstate, 256);
signed short *inbuf, *outbuf, *silence;
- outbuf = malloc(OUTFRAME_BYTES(frame_size));
+ outbuf = malloc(bytes_per_audio_frame*(frame_size+max_frame_size_change));
if (outbuf==NULL)
debug(1,"Failed to allocate memory for an output buffer.");
- silence = malloc(OUTFRAME_BYTES(frame_size));
+ silence = malloc(bytes_per_audio_frame*frame_size);
if (silence==NULL)
debug(1,"Failed to allocate memory for a silence buffer.");
- memset(silence, 0, OUTFRAME_BYTES(frame_size));
+ memset(silence, 0, bytes_per_audio_frame*frame_size);
late_packet_message_sent = 0;
first_packet_timestamp = 0;
missing_packets = late_packets = too_late_packets = resend_requests = 0;
while (!please_stop) {
abuf_t *inframe = buffer_get_frame();
if (inframe) {
- inbuf = inframe->data;
- if (inbuf) {
+ if (inframe->data) {
play_number++;
// if it's a supplied silent frame, let us know...
if (inframe->timestamp == 0) {
// debug(1,"Player has a supplied silent frame.");
last_seqno_read =
(SUCCESSOR(last_seqno_read) & 0xffff); // manage the packet out of sequence minder
- if (inbuf==NULL)
- debug(1,"NULL inbuf to play -- skipping it.");
+ if (inframe->data==NULL)
+ debug(1,"NULL inframe->data to play -- skipping it.");
else {
- if (frame_size==0)
- debug(1,"empty frame to play -- skipping it (1).");
+ if (inframe->length==0)
+ debug(1,"empty frame to play -- skipping it.");
else
- config.output->play(inbuf, frame_size);
+ config.output->play(inframe->data, inframe->length);
}
} else {
// We have a frame of data. We need to see if we want to add or remove a frame from it to
if (buffer_occupancy > maximum_buffer_occupancy)
maximum_buffer_occupancy = buffer_occupancy;
- // here, we want to check (a) if we are meant to do synchronisation, (b) if we have a delay procedure, (b) if we can get the delay.
+ // here, we want to check (a) if we are meant to do synchronisation,
+ // (b) if we have a delay procedure, (c) if we can get the delay.
+
// If any of these are false, we don't do any synchronisation stuff
int resp = -1; // use this as a flag -- if negative, we can't rely on a real known delay
// if no stuffing needed and no volume adjustment, then
// don't send to stuff_buffer_* and don't copy to outbuf; just send directly to the
// output device...
- if (inbuf==NULL)
- debug(1,"NULL inbuf to play -- skipping it.");
+ if (inframe->data==NULL)
+ debug(1,"NULL inframe->data to play -- skipping it.");
else {
- if (frame_size==0)
+ if (inframe->length==0)
debug(1,"empty frame to play -- skipping it (2).");
else
- config.output->play(inbuf, frame_size);
+ config.output->play(inframe->data, inframe->length);
}
} else {
#ifdef HAVE_LIBSOXR
switch (config.packet_stuffing) {
case ST_basic:
// if (amount_to_stuff) debug(1,"Basic stuff...");
- play_samples = stuff_buffer_basic(inbuf, outbuf, amount_to_stuff);
+ play_samples = stuff_buffer_basic(inframe->data, inframe->length, outbuf, amount_to_stuff);
break;
case ST_soxr:
// if (amount_to_stuff) debug(1,"Soxr stuff...");
- play_samples = stuff_buffer_soxr(inbuf, outbuf, amount_to_stuff);
+ play_samples = stuff_buffer_soxr(inframe->data, inframe->length, outbuf, amount_to_stuff);
break;
}
#else
// if (amount_to_stuff) debug(1,"Standard stuff...");
- play_samples = stuff_buffer_basic(inbuf, outbuf, amount_to_stuff);
+ play_samples = stuff_buffer_basic(inframe->data, inframe->length, outbuf, amount_to_stuff);
#endif
/*
if (fix_volume == 0x10000)
- if (inbuf==NULL)
- debug(1,"NULL inbuf to play -- skipping it.");
+ if (inframe->data==NULL)
+ debug(1,"NULL inframe->data to play -- skipping it.");
else {
- if (frame_size==0)
+ if (inframe->length==0)
debug(1,"empty frame to play -- skipping it (3).");
else
- config.output->play(inbuf, frame_size);
+ config.output->play(inframe->data, inframe->length);
}
else {
- play_samples = stuff_buffer_basic(inbuf, outbuf, 0); // no stuffing, but volume adjustment
+ play_samples = stuff_buffer_basic(inframe->data, inframe->length, outbuf, 0); // no stuffing, but volume adjustment
if (outbuf==NULL)
debug(1,"NULL outbuf to play -- skipping it.");
else {
- if (frame_size==0)
+ if (inframe->length==0)
debug(1,"empty frame to play -- skipping it (4).");
else
- config.output->play(outbuf, frame_size);
+ config.output->play(outbuf, play_samples);
}
}
}