field compatibleVersion uint8_t indicating compatible version,
value must be set to 0
- field bitDepth uint8_t describes the bit depth of the source
+ field bitDepth uint8_t describes the bit depth of the
+ source
PCM
data
(maximum
field kb uint8_t currently unused tuning parameter.
value should be set to 10
- field numChannels uint8_t describes the channel count (1 = mono,
+ field numChannels uint8_t describes the channel count (1 =
+ mono,
2
=
stereo,
the encoded stream.
value of 0 indicates unknown
- field avgBitRate uint32_t the average bit rate in bits per second
+ field avgBitRate uint32_t the average bit rate in bits per
+ second
of
the
Apple
// (b) multiplies each sample by the fixedvolume (a 16-bit quantity)
// (c) dithers the result to the output size 32/24/16 bits
// (d) outputs the result in the approprate format
-// formats accepted so far include U8, S8, S16_LE, S24_LE and S32_LE on a little endinan machine.
+// formats accepted so far include U8, S8, S16_LE, S24_LE and S32_LE on a little endian machine.
// stuff: 1 means add 1; 0 means do nothing; -1 means remove 1
static int stuff_buffer_basic_32(int32_t *inptr, int length, enum sps_format_t l_output_format,
}
#ifdef HAVE_LIBSOXR
-static int stuff_buffer_soxr_32(int32_t *inptr, int length, int32_t *outptr, int stuff,
- int l_output_bit_depth) {
- return length;
+// this takes an array of signed 32-bit integers and
+// (a) uses libsoxr to
+// resample the array to have one more or one less frame, as specified in
+// stuff,
+// (b) multiplies each sample by the fixedvolume (a 16-bit quantity)
+// (c) dithers the result to the output size 32/24/16 bits
+// (d) outputs the result in the approprate format
+// formats accepted so far include U8, S8, S16_LE, S24_LE and S32_LE on a little endian machine.
+
+static int stuff_buffer_soxr_32(int32_t *inptr, int32_t *scratchBuffer, int length,
+ enum sps_format_t l_output_format, char *outptr, int stuff,
+ int dither) {
+ if (scratchBuffer == NULL) {
+ die("soxr scratchBuffer not initialised.");
+ }
+ int tstuff = stuff;
+ if ((stuff > 1) || (stuff < -1) || (length < 100)) {
+ // debug(1, "Stuff argument to stuff_buffer must be from -1 to +1 and length >100.");
+ tstuff = 0; // if any of these conditions hold, don't stuff anything/
+ }
+
+ if (tstuff) {
+ // debug(1,"Stuff %d.",stuff);
+ soxr_io_spec_t io_spec;
+ io_spec.itype = SOXR_INT32_I;
+ io_spec.otype = SOXR_INT32_I;
+ io_spec.scale = 1.0; // this seems to crash if not = 1.0
+ io_spec.e = NULL;
+ io_spec.flags = 0;
+
+ size_t odone;
+
+ soxr_error_t error = soxr_oneshot(length, length + tstuff, 2, /* Rates and # of chans. */
+ inptr, length, NULL, /* Input. */
+ scratchBuffer, length + tstuff, &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 > length + 1)
+ die("odone = %d!\n", odone);
+
+ int i;
+ int32_t *ip, *op;
+ ip = inptr;
+ op = scratchBuffer;
+
+ const int gpm = 5;
+ // keep the first (dpm) samples, to mitigate the Gibbs phenomenon
+ for (i = 0; i < gpm; i++) {
+ *op++ = *ip++;
+ *op++ = *ip++;
+ }
+
+ // keep the last (dpm) samples, to mitigate the Gibbs phenomenon
+ op = scratchBuffer + (length + tstuff - gpm) * sizeof(int32_t);
+ ip = inptr + (length - gpm) * sizeof(int32_t);
+ for (i = 0; i < gpm; i++) {
+ *op++ = *ip++;
+ *op++ = *ip++;
+ }
+
+ // now, do the volume, dither and formatting processing
+ ip = scratchBuffer;
+ char *l_outptr = outptr;
+ for (i = 0; i < length + tstuff; i++) {
+ process_sample(*ip++, &l_outptr, l_output_format, fix_volume, dither);
+ process_sample(*ip++, &l_outptr, l_output_format, fix_volume, dither);
+ //*op = dithered_vol(*op);
+ // op++;
+ //*op = dithered_vol(*op);
+ // op++;
+ };
+
+ } else { // the whole frame, if no stuffing
+
+ // now, do the volume, dither and formatting processing
+ int32_t *ip = inptr;
+ char *l_outptr = outptr;
+ int i;
+
+ for (i = 0; i < length; i++) {
+ process_sample(*ip++, &l_outptr, l_output_format, fix_volume, dither);
+ process_sample(*ip++, &l_outptr, l_output_format, fix_volume, dither);
+ //*op++ = dithered_vol(*ip++);
+ //*op++ = dithered_vol(*ip++);
+ };
+ }
+ return length + tstuff;
}
// stuff: 1 means add 1; 0 means do nothing; -1 means remove 1
static int stuff_buffer_soxr(short *inptr, int length, short *outptr, int stuff) {
signed short *inbuf, *tbuf, *silence;
+ int32_t *sbuf;
+
char *outbuf;
int inbuflength;
(max_frames_per_packet * output_sample_ratio + max_frame_size_change));
if (tbuf == NULL)
debug(1, "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)
+ debug(1, "Failed to allocate memory for the transition buffer.");
+ }
} else {
tbuf = 0;
}
case ST_soxr:
// if (amount_to_stuff) debug(1,"Soxr stuff...");
if (tbuf)
- play_samples = stuff_buffer_soxr_32((int32_t *)tbuf, inbuflength, (int32_t *)outbuf,
- amount_to_stuff, output_bit_depth);
+ play_samples = stuff_buffer_soxr_32((int32_t *)tbuf, (int32_t *)sbuf, inbuflength,
+ config.output_format, outbuf, amount_to_stuff,
+ enable_dither);
else
play_samples =
stuff_buffer_soxr(inbuf, inbuflength, (short *)outbuf, amount_to_stuff);
free(silence);
if (tbuf)
free(tbuf);
+ if (sbuf)
+ free(sbuf);
debug(1, "Shut down audio, control and timing threads");
itr.please_stop = 1;
pthread_kill(rtp_audio_thread, SIGUSR1);