#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
- #include "stdint_win.h"
+#include "stdint_win.h"
#else
- #include <stdint.h>
+#include <stdint.h>
#endif
#include "alac.h"
-#define _Swap32(v) do { \
- v = (((v) & 0x000000FF) << 0x18) | \
- (((v) & 0x0000FF00) << 0x08) | \
- (((v) & 0x00FF0000) >> 0x08) | \
- (((v) & 0xFF000000) >> 0x18); } while(0)
+#define _Swap32(v) \
+ do { \
+ v = (((v)&0x000000FF) << 0x18) | (((v)&0x0000FF00) << 0x08) | (((v)&0x00FF0000) >> 0x08) | \
+ (((v)&0xFF000000) >> 0x18); \
+ } while (0)
-#define _Swap16(v) do { \
- v = (((v) & 0x00FF) << 0x08) | \
- (((v) & 0xFF00) >> 0x08); } while (0)
+#define _Swap16(v) \
+ do { \
+ v = (((v)&0x00FF) << 0x08) | (((v)&0xFF00) >> 0x08); \
+ } while (0)
-struct {signed int x:24;} se_struct_24;
+struct {
+ signed int x : 24;
+} se_struct_24;
#define SignExtend24(val) (se_struct_24.x = val)
void alac_free(alac_file *alac) {
- if (alac->predicterror_buffer_a)
- free(alac->predicterror_buffer_a);
- if (alac->predicterror_buffer_b)
- free(alac->predicterror_buffer_b);
-
- if (alac->outputsamples_buffer_a)
- free(alac->outputsamples_buffer_a);
- if (alac->outputsamples_buffer_b)
- free(alac->outputsamples_buffer_b);
-
- if (alac->uncompressed_bytes_buffer_a)
- free(alac->uncompressed_bytes_buffer_a);
- if (alac->uncompressed_bytes_buffer_b)
- free(alac->uncompressed_bytes_buffer_b);
-
- free(alac);
+ if (alac->predicterror_buffer_a)
+ free(alac->predicterror_buffer_a);
+ if (alac->predicterror_buffer_b)
+ free(alac->predicterror_buffer_b);
+
+ if (alac->outputsamples_buffer_a)
+ free(alac->outputsamples_buffer_a);
+ if (alac->outputsamples_buffer_b)
+ free(alac->outputsamples_buffer_b);
+
+ if (alac->uncompressed_bytes_buffer_a)
+ free(alac->uncompressed_bytes_buffer_a);
+ if (alac->uncompressed_bytes_buffer_b)
+ free(alac->uncompressed_bytes_buffer_b);
+
+ free(alac);
}
-void alac_allocate_buffers(alac_file *alac)
-{
- alac->predicterror_buffer_a = malloc(alac->setinfo_max_samples_per_frame * 4);
- alac->predicterror_buffer_b = malloc(alac->setinfo_max_samples_per_frame * 4);
+void alac_allocate_buffers(alac_file *alac) {
+ alac->predicterror_buffer_a = malloc(alac->setinfo_max_samples_per_frame * 4);
+ alac->predicterror_buffer_b = malloc(alac->setinfo_max_samples_per_frame * 4);
- alac->outputsamples_buffer_a = malloc(alac->setinfo_max_samples_per_frame * 4);
- alac->outputsamples_buffer_b = malloc(alac->setinfo_max_samples_per_frame * 4);
+ alac->outputsamples_buffer_a = malloc(alac->setinfo_max_samples_per_frame * 4);
+ alac->outputsamples_buffer_b = malloc(alac->setinfo_max_samples_per_frame * 4);
- alac->uncompressed_bytes_buffer_a = malloc(alac->setinfo_max_samples_per_frame * 4);
- alac->uncompressed_bytes_buffer_b = malloc(alac->setinfo_max_samples_per_frame * 4);
+ alac->uncompressed_bytes_buffer_a = malloc(alac->setinfo_max_samples_per_frame * 4);
+ alac->uncompressed_bytes_buffer_b = malloc(alac->setinfo_max_samples_per_frame * 4);
}
-void alac_set_info(alac_file *alac, char *inputbuffer)
-{
+void alac_set_info(alac_file *alac, char *inputbuffer) {
char *ptr = inputbuffer;
ptr += 4; /* size */
ptr += 4; /* frma */
ptr += 4; /* 0 ? */
- alac->setinfo_max_samples_per_frame = *(uint32_t*)ptr; /* buffer size / 2 ? */
+ alac->setinfo_max_samples_per_frame = *(uint32_t *)ptr; /* buffer size / 2 ? */
if (!host_bigendian)
- _Swap32(alac->setinfo_max_samples_per_frame);
+ _Swap32(alac->setinfo_max_samples_per_frame);
ptr += 4;
- alac->setinfo_7a = *(uint8_t*)ptr;
+ alac->setinfo_7a = *(uint8_t *)ptr;
ptr += 1;
- alac->setinfo_sample_size = *(uint8_t*)ptr;
+ alac->setinfo_sample_size = *(uint8_t *)ptr;
ptr += 1;
- alac->setinfo_rice_historymult = *(uint8_t*)ptr;
+ alac->setinfo_rice_historymult = *(uint8_t *)ptr;
ptr += 1;
- alac->setinfo_rice_initialhistory = *(uint8_t*)ptr;
+ alac->setinfo_rice_initialhistory = *(uint8_t *)ptr;
ptr += 1;
- alac->setinfo_rice_kmodifier = *(uint8_t*)ptr;
+ alac->setinfo_rice_kmodifier = *(uint8_t *)ptr;
ptr += 1;
- alac->setinfo_7f = *(uint8_t*)ptr;
+ alac->setinfo_7f = *(uint8_t *)ptr;
ptr += 1;
- alac->setinfo_80 = *(uint16_t*)ptr;
+ alac->setinfo_80 = *(uint16_t *)ptr;
if (!host_bigendian)
- _Swap16(alac->setinfo_80);
+ _Swap16(alac->setinfo_80);
ptr += 2;
- alac->setinfo_82 = *(uint32_t*)ptr;
+ alac->setinfo_82 = *(uint32_t *)ptr;
if (!host_bigendian)
- _Swap32(alac->setinfo_82);
+ _Swap32(alac->setinfo_82);
ptr += 4;
- alac->setinfo_86 = *(uint32_t*)ptr;
+ alac->setinfo_86 = *(uint32_t *)ptr;
if (!host_bigendian)
- _Swap32(alac->setinfo_86);
+ _Swap32(alac->setinfo_86);
ptr += 4;
- alac->setinfo_8a_rate = *(uint32_t*)ptr;
+ alac->setinfo_8a_rate = *(uint32_t *)ptr;
if (!host_bigendian)
- _Swap32(alac->setinfo_8a_rate);
+ _Swap32(alac->setinfo_8a_rate);
alac_allocate_buffers(alac);
-
}
/* stream reading */
/* supports reading 1 to 16 bits, in big endian format */
-static uint32_t readbits_16(alac_file *alac, int bits)
-{
- uint32_t result;
- int new_accumulator;
+static uint32_t readbits_16(alac_file *alac, int bits) {
+ uint32_t result;
+ int new_accumulator;
- result = (alac->input_buffer[0] << 16) |
- (alac->input_buffer[1] << 8) |
- (alac->input_buffer[2]);
+ result = (alac->input_buffer[0] << 16) | (alac->input_buffer[1] << 8) | (alac->input_buffer[2]);
- /* shift left by the number of bits we've already read,
- * so that the top 'n' bits of the 24 bits we read will
- * be the return bits */
- result = result << alac->input_buffer_bitaccumulator;
+ /* shift left by the number of bits we've already read,
+ * so that the top 'n' bits of the 24 bits we read will
+ * be the return bits */
+ result = result << alac->input_buffer_bitaccumulator;
- result = result & 0x00ffffff;
+ result = result & 0x00ffffff;
- /* and then only want the top 'n' bits from that, where
- * n is 'bits' */
- result = result >> (24 - bits);
+ /* and then only want the top 'n' bits from that, where
+ * n is 'bits' */
+ result = result >> (24 - bits);
- new_accumulator = (alac->input_buffer_bitaccumulator + bits);
+ new_accumulator = (alac->input_buffer_bitaccumulator + bits);
- /* increase the buffer pointer if we've read over n bytes. */
- alac->input_buffer += (new_accumulator >> 3);
+ /* increase the buffer pointer if we've read over n bytes. */
+ alac->input_buffer += (new_accumulator >> 3);
- /* and the remainder goes back into the bit accumulator */
- alac->input_buffer_bitaccumulator = (new_accumulator & 7);
+ /* and the remainder goes back into the bit accumulator */
+ alac->input_buffer_bitaccumulator = (new_accumulator & 7);
- return result;
+ return result;
}
/* supports reading 1 to 32 bits, in big endian format */
-static uint32_t readbits(alac_file *alac, int bits)
-{
- int32_t result = 0;
+static uint32_t readbits(alac_file *alac, int bits) {
+ int32_t result = 0;
- if (bits > 16)
- {
- bits -= 16;
- result = readbits_16(alac, 16) << bits;
- }
+ if (bits > 16) {
+ bits -= 16;
+ result = readbits_16(alac, 16) << bits;
+ }
- result |= readbits_16(alac, bits);
+ result |= readbits_16(alac, bits);
- return result;
+ return result;
}
/* reads a single bit */
-static int readbit(alac_file *alac)
-{
- int result;
- int new_accumulator;
+static int readbit(alac_file *alac) {
+ int result;
+ int new_accumulator;
- result = alac->input_buffer[0];
+ result = alac->input_buffer[0];
- result = result << alac->input_buffer_bitaccumulator;
+ result = result << alac->input_buffer_bitaccumulator;
- result = result >> 7 & 1;
+ result = result >> 7 & 1;
- new_accumulator = (alac->input_buffer_bitaccumulator + 1);
+ new_accumulator = (alac->input_buffer_bitaccumulator + 1);
- alac->input_buffer += (new_accumulator / 8);
+ alac->input_buffer += (new_accumulator / 8);
- alac->input_buffer_bitaccumulator = (new_accumulator % 8);
+ alac->input_buffer_bitaccumulator = (new_accumulator % 8);
- return result;
+ return result;
}
-static void unreadbits(alac_file *alac, int bits)
-{
- int new_accumulator = (alac->input_buffer_bitaccumulator - bits);
+static void unreadbits(alac_file *alac, int bits) {
+ int new_accumulator = (alac->input_buffer_bitaccumulator - bits);
- alac->input_buffer += (new_accumulator >> 3);
+ alac->input_buffer += (new_accumulator >> 3);
- alac->input_buffer_bitaccumulator = (new_accumulator & 7);
- if (alac->input_buffer_bitaccumulator < 0)
- alac->input_buffer_bitaccumulator *= -1;
+ alac->input_buffer_bitaccumulator = (new_accumulator & 7);
+ if (alac->input_buffer_bitaccumulator < 0)
+ alac->input_buffer_bitaccumulator *= -1;
}
/* various implementations of count_leading_zero:
/* for some reason the unrolled version (below) is
* actually faster than this. yay intel!
*/
-static int count_leading_zeros(int input)
-{
- return __builtin_clz(input);
-}
+static int count_leading_zeros(int input) { return __builtin_clz(input); }
#elif defined(_MSC_VER) && defined(_M_IX86)
-static int count_leading_zeros(int input)
-{
- int output = 0;
- if (!input) return 32;
- __asm
- {
+static int count_leading_zeros(int input) {
+ int output = 0;
+ if (!input)
+ return 32;
+ __asm
+ {
mov eax, input;
mov edx, 0x1f;
bsr ecx, eax;
sub edx, ecx;
mov output, edx;
- }
- return output;
+ }
+ return output;
}
#else
#warning using generic count leading zeroes. You may wish to write one for your CPU / compiler
-static int count_leading_zeros(int input)
-{
- int output = 0;
- int curbyte = 0;
+static int count_leading_zeros(int input) {
+ int output = 0;
+ int curbyte = 0;
- curbyte = input >> 24;
- if (curbyte) goto found;
- output += 8;
+ curbyte = input >> 24;
+ if (curbyte)
+ goto found;
+ output += 8;
- curbyte = input >> 16;
- if (curbyte & 0xff) goto found;
- output += 8;
+ curbyte = input >> 16;
+ if (curbyte & 0xff)
+ goto found;
+ output += 8;
- curbyte = input >> 8;
- if (curbyte & 0xff) goto found;
- output += 8;
+ curbyte = input >> 8;
+ if (curbyte & 0xff)
+ goto found;
+ output += 8;
- curbyte = input;
- if (curbyte & 0xff) goto found;
- output += 8;
+ curbyte = input;
+ if (curbyte & 0xff)
+ goto found;
+ output += 8;
- return output;
+ return output;
found:
- if (!(curbyte & 0xf0))
- {
- output += 4;
- }
- else
- curbyte >>= 4;
-
- if (curbyte & 0x8)
- return output;
- if (curbyte & 0x4)
- return output + 1;
- if (curbyte & 0x2)
- return output + 2;
- if (curbyte & 0x1)
- return output + 3;
-
- /* shouldn't get here: */
- return output + 4;
+ if (!(curbyte & 0xf0)) {
+ output += 4;
+ } else
+ curbyte >>= 4;
+
+ if (curbyte & 0x8)
+ return output;
+ if (curbyte & 0x4)
+ return output + 1;
+ if (curbyte & 0x2)
+ return output + 2;
+ if (curbyte & 0x1)
+ return output + 3;
+
+ /* shouldn't get here: */
+ return output + 4;
}
#endif
#define RICE_THRESHOLD 8 // maximum number of bits for a rice prefix.
-static int32_t entropy_decode_value(alac_file* alac,
- int readSampleSize,
- int k,
- int rice_kmodifier_mask)
-{
- int32_t x = 0; // decoded value
+static int32_t entropy_decode_value(alac_file *alac, int readSampleSize, int k,
+ int rice_kmodifier_mask) {
+ int32_t x = 0; // decoded value
- // read x, number of 1s before 0 represent the rice value.
- while (x <= RICE_THRESHOLD && readbit(alac))
- {
- x++;
- }
+ // read x, number of 1s before 0 represent the rice value.
+ while (x <= RICE_THRESHOLD && readbit(alac)) {
+ x++;
+ }
- if (x > RICE_THRESHOLD)
- {
- // read the number from the bit stream (raw value)
- int32_t value;
+ if (x > RICE_THRESHOLD) {
+ // read the number from the bit stream (raw value)
+ int32_t value;
- value = readbits(alac, readSampleSize);
+ value = readbits(alac, readSampleSize);
- // mask value
- value &= (((uint32_t)0xffffffff) >> (32 - readSampleSize));
+ // mask value
+ value &= (((uint32_t)0xffffffff) >> (32 - readSampleSize));
- x = value;
- }
- else
- {
- if (k != 1)
- {
- int extraBits = readbits(alac, k);
+ x = value;
+ } else {
+ if (k != 1) {
+ int extraBits = readbits(alac, k);
- // x = x * (2^k - 1)
- x *= (((1 << k) - 1) & rice_kmodifier_mask);
+ // x = x * (2^k - 1)
+ x *= (((1 << k) - 1) & rice_kmodifier_mask);
- if (extraBits > 1)
- x += extraBits - 1;
- else
- unreadbits(alac, 1);
- }
+ if (extraBits > 1)
+ x += extraBits - 1;
+ else
+ unreadbits(alac, 1);
}
+ }
- return x;
+ return x;
}
-static void entropy_rice_decode(alac_file* alac,
- int32_t* outputBuffer,
- int outputSize,
- int readSampleSize,
- int rice_initialhistory,
- int rice_kmodifier,
- int rice_historymult,
- int rice_kmodifier_mask)
-{
- int outputCount;
- int history = rice_initialhistory;
- int signModifier = 0;
+static void entropy_rice_decode(alac_file *alac, int32_t *outputBuffer, int outputSize,
+ int readSampleSize, int rice_initialhistory, int rice_kmodifier,
+ int rice_historymult, int rice_kmodifier_mask) {
+ int outputCount;
+ int history = rice_initialhistory;
+ int signModifier = 0;
- for (outputCount = 0; outputCount < outputSize; outputCount++)
- {
- int32_t decodedValue;
- int32_t finalValue;
- int32_t k;
+ for (outputCount = 0; outputCount < outputSize; outputCount++) {
+ int32_t decodedValue;
+ int32_t finalValue;
+ int32_t k;
- k = 31 - rice_kmodifier - count_leading_zeros((history >> 9) + 3);
+ k = 31 - rice_kmodifier - count_leading_zeros((history >> 9) + 3);
- if (k < 0) k += rice_kmodifier;
- else k = rice_kmodifier;
+ if (k < 0)
+ k += rice_kmodifier;
+ else
+ k = rice_kmodifier;
- // note: don't use rice_kmodifier_mask here (set mask to 0xFFFFFFFF)
- decodedValue = entropy_decode_value(alac, readSampleSize, k, 0xFFFFFFFF);
+ // note: don't use rice_kmodifier_mask here (set mask to 0xFFFFFFFF)
+ decodedValue = entropy_decode_value(alac, readSampleSize, k, 0xFFFFFFFF);
- decodedValue += signModifier;
- finalValue = (decodedValue + 1) / 2; // inc by 1 and shift out sign bit
- if (decodedValue & 1) // the sign is stored in the low bit
- finalValue *= -1;
+ decodedValue += signModifier;
+ finalValue = (decodedValue + 1) / 2; // inc by 1 and shift out sign bit
+ if (decodedValue & 1) // the sign is stored in the low bit
+ finalValue *= -1;
- outputBuffer[outputCount] = finalValue;
+ outputBuffer[outputCount] = finalValue;
- signModifier = 0;
+ signModifier = 0;
- // update history
- history += (decodedValue * rice_historymult)
- - ((history * rice_historymult) >> 9);
+ // update history
+ history += (decodedValue * rice_historymult) - ((history * rice_historymult) >> 9);
- if (decodedValue > 0xFFFF)
- history = 0xFFFF;
+ if (decodedValue > 0xFFFF)
+ history = 0xFFFF;
- // special case, for compressed blocks of 0
- if ((history < 128) && (outputCount + 1 < outputSize))
- {
- int32_t blockSize;
+ // special case, for compressed blocks of 0
+ if ((history < 128) && (outputCount + 1 < outputSize)) {
+ int32_t blockSize;
- signModifier = 1;
+ signModifier = 1;
- k = count_leading_zeros(history) + ((history + 16) / 64) - 24;
+ k = count_leading_zeros(history) + ((history + 16) / 64) - 24;
- // note: blockSize is always 16bit
- blockSize = entropy_decode_value(alac, 16, k, rice_kmodifier_mask);
+ // note: blockSize is always 16bit
+ blockSize = entropy_decode_value(alac, 16, k, rice_kmodifier_mask);
- // got blockSize 0s
- if (blockSize > 0)
- {
- memset(&outputBuffer[outputCount + 1], 0, blockSize * sizeof(*outputBuffer));
- outputCount += blockSize;
- }
+ // got blockSize 0s
+ if (blockSize > 0) {
+ memset(&outputBuffer[outputCount + 1], 0, blockSize * sizeof(*outputBuffer));
+ outputCount += blockSize;
+ }
- if (blockSize > 0xFFFF)
- signModifier = 0;
+ if (blockSize > 0xFFFF)
+ signModifier = 0;
- history = 0;
- }
+ history = 0;
}
+ }
}
#define SIGN_EXTENDED32(val, bits) ((val << (32 - bits)) >> (32 - bits))
-#define SIGN_ONLY(v) \
- ((v < 0) ? (-1) : \
- ((v > 0) ? (1) : \
- (0)))
-
-static void predictor_decompress_fir_adapt(int32_t *error_buffer,
- int32_t *buffer_out,
- int output_size,
- int readsamplesize,
- int16_t *predictor_coef_table,
- int predictor_coef_num,
- int predictor_quantitization)
-{
- int i;
-
- /* first sample always copies */
- *buffer_out = *error_buffer;
-
- if (!predictor_coef_num)
- {
- if (output_size <= 1) return;
- memcpy(buffer_out+1, error_buffer+1, (output_size-1) * 4);
- return;
+#define SIGN_ONLY(v) ((v < 0) ? (-1) : ((v > 0) ? (1) : (0)))
+
+static void predictor_decompress_fir_adapt(int32_t *error_buffer, int32_t *buffer_out,
+ int output_size, int readsamplesize,
+ int16_t *predictor_coef_table, int predictor_coef_num,
+ int predictor_quantitization) {
+ int i;
+
+ /* first sample always copies */
+ *buffer_out = *error_buffer;
+
+ if (!predictor_coef_num) {
+ if (output_size <= 1)
+ return;
+ memcpy(buffer_out + 1, error_buffer + 1, (output_size - 1) * 4);
+ return;
+ }
+
+ if (predictor_coef_num == 0x1f) /* 11111 - max value of predictor_coef_num */
+ { /* second-best case scenario for fir decompression,
+ * error describes a small difference from the previous sample only
+ */
+ if (output_size <= 1)
+ return;
+ for (i = 0; i < output_size - 1; i++) {
+ int32_t prev_value;
+ int32_t error_value;
+
+ prev_value = buffer_out[i];
+ error_value = error_buffer[i + 1];
+ buffer_out[i + 1] = SIGN_EXTENDED32((prev_value + error_value), readsamplesize);
}
+ return;
+ }
- if (predictor_coef_num == 0x1f) /* 11111 - max value of predictor_coef_num */
- { /* second-best case scenario for fir decompression,
- * error describes a small difference from the previous sample only
- */
- if (output_size <= 1) return;
- for (i = 0; i < output_size - 1; i++)
- {
- int32_t prev_value;
- int32_t error_value;
-
- prev_value = buffer_out[i];
- error_value = error_buffer[i+1];
- buffer_out[i+1] = SIGN_EXTENDED32((prev_value + error_value), readsamplesize);
- }
- return;
- }
-
- /* read warm-up samples */
- if (predictor_coef_num > 0)
- {
- int i;
- for (i = 0; i < predictor_coef_num; i++)
- {
- int32_t val;
+ /* read warm-up samples */
+ if (predictor_coef_num > 0) {
+ int i;
+ for (i = 0; i < predictor_coef_num; i++) {
+ int32_t val;
- val = buffer_out[i] + error_buffer[i+1];
+ val = buffer_out[i] + error_buffer[i + 1];
- val = SIGN_EXTENDED32(val, readsamplesize);
+ val = SIGN_EXTENDED32(val, readsamplesize);
- buffer_out[i+1] = val;
- }
+ buffer_out[i + 1] = val;
}
+ }
#if 0
/* 4 and 8 are very common cases (the only ones i've seen). these
}
#endif
+ /* general case */
+ if (predictor_coef_num > 0) {
+ for (i = predictor_coef_num + 1; i < output_size; i++) {
+ int j;
+ int sum = 0;
+ int outval;
+ int error_val = error_buffer[i];
- /* general case */
- if (predictor_coef_num > 0)
- {
- for (i = predictor_coef_num + 1;
- i < output_size;
- i++)
- {
- int j;
- int sum = 0;
- int outval;
- int error_val = error_buffer[i];
-
- for (j = 0; j < predictor_coef_num; j++)
- {
- sum += (buffer_out[predictor_coef_num-j] - buffer_out[0]) *
- predictor_coef_table[j];
- }
+ for (j = 0; j < predictor_coef_num; j++) {
+ sum += (buffer_out[predictor_coef_num - j] - buffer_out[0]) * predictor_coef_table[j];
+ }
- outval = (1 << (predictor_quantitization-1)) + sum;
- outval = outval >> predictor_quantitization;
- outval = outval + buffer_out[0] + error_val;
- outval = SIGN_EXTENDED32(outval, readsamplesize);
+ outval = (1 << (predictor_quantitization - 1)) + sum;
+ outval = outval >> predictor_quantitization;
+ outval = outval + buffer_out[0] + error_val;
+ outval = SIGN_EXTENDED32(outval, readsamplesize);
- buffer_out[predictor_coef_num+1] = outval;
+ buffer_out[predictor_coef_num + 1] = outval;
- if (error_val > 0)
- {
- int predictor_num = predictor_coef_num - 1;
+ if (error_val > 0) {
+ int predictor_num = predictor_coef_num - 1;
- while (predictor_num >= 0 && error_val > 0)
- {
- int val = buffer_out[0] - buffer_out[predictor_coef_num - predictor_num];
- int sign = SIGN_ONLY(val);
+ while (predictor_num >= 0 && error_val > 0) {
+ int val = buffer_out[0] - buffer_out[predictor_coef_num - predictor_num];
+ int sign = SIGN_ONLY(val);
- predictor_coef_table[predictor_num] -= sign;
+ predictor_coef_table[predictor_num] -= sign;
- val *= sign; /* absolute value */
+ val *= sign; /* absolute value */
- error_val -= ((val >> predictor_quantitization) *
- (predictor_coef_num - predictor_num));
+ error_val -= ((val >> predictor_quantitization) * (predictor_coef_num - predictor_num));
- predictor_num--;
- }
- }
- else if (error_val < 0)
- {
- int predictor_num = predictor_coef_num - 1;
-
- while (predictor_num >= 0 && error_val < 0)
- {
- int val = buffer_out[0] - buffer_out[predictor_coef_num - predictor_num];
- int sign = - SIGN_ONLY(val);
+ predictor_num--;
+ }
+ } else if (error_val < 0) {
+ int predictor_num = predictor_coef_num - 1;
- predictor_coef_table[predictor_num] -= sign;
+ while (predictor_num >= 0 && error_val < 0) {
+ int val = buffer_out[0] - buffer_out[predictor_coef_num - predictor_num];
+ int sign = -SIGN_ONLY(val);
- val *= sign; /* neg value */
+ predictor_coef_table[predictor_num] -= sign;
- error_val -= ((val >> predictor_quantitization) *
- (predictor_coef_num - predictor_num));
+ val *= sign; /* neg value */
- predictor_num--;
- }
- }
+ error_val -= ((val >> predictor_quantitization) * (predictor_coef_num - predictor_num));
- buffer_out++;
+ predictor_num--;
}
+ }
+
+ buffer_out++;
}
+ }
}
-static void deinterlace_16(int32_t *buffer_a, int32_t *buffer_b,
- int16_t *buffer_out,
- int numchannels, int numsamples,
- uint8_t interlacing_shift,
- uint8_t interlacing_leftweight)
-{
- int i;
- if (numsamples <= 0) return;
-
- /* weighted interlacing */
- if (interlacing_leftweight)
- {
- for (i = 0; i < numsamples; i++)
- {
- int32_t difference, midright;
- int16_t left;
- int16_t right;
+static void deinterlace_16(int32_t *buffer_a, int32_t *buffer_b, int16_t *buffer_out,
+ int numchannels, int numsamples, uint8_t interlacing_shift,
+ uint8_t interlacing_leftweight) {
+ int i;
+ if (numsamples <= 0)
+ return;
+
+ /* weighted interlacing */
+ if (interlacing_leftweight) {
+ for (i = 0; i < numsamples; i++) {
+ int32_t difference, midright;
+ int16_t left;
+ int16_t right;
+
+ midright = buffer_a[i];
+ difference = buffer_b[i];
+
+ right = midright - ((difference * interlacing_leftweight) >> interlacing_shift);
+ left = right + difference;
+
+ /* output is always little endian */
+ if (host_bigendian) {
+ _Swap16(left);
+ _Swap16(right);
+ }
+
+ buffer_out[i * numchannels] = left;
+ buffer_out[i * numchannels + 1] = right;
+ }
- midright = buffer_a[i];
- difference = buffer_b[i];
+ return;
+ }
+ /* otherwise basic interlacing took place */
+ for (i = 0; i < numsamples; i++) {
+ int16_t left, right;
- right = midright - ((difference * interlacing_leftweight) >> interlacing_shift);
- left = right + difference;
+ left = buffer_a[i];
+ right = buffer_b[i];
- /* output is always little endian */
- if (host_bigendian)
- {
- _Swap16(left);
- _Swap16(right);
- }
+ /* output is always little endian */
+ if (host_bigendian) {
+ _Swap16(left);
+ _Swap16(right);
+ }
- buffer_out[i*numchannels] = left;
- buffer_out[i*numchannels + 1] = right;
- }
+ buffer_out[i * numchannels] = left;
+ buffer_out[i * numchannels + 1] = right;
+ }
+}
- return;
+static void deinterlace_24(int32_t *buffer_a, int32_t *buffer_b, int uncompressed_bytes,
+ int32_t *uncompressed_bytes_buffer_a,
+ int32_t *uncompressed_bytes_buffer_b, void *buffer_out, int numchannels,
+ int numsamples, uint8_t interlacing_shift,
+ uint8_t interlacing_leftweight) {
+ int i;
+ if (numsamples <= 0)
+ return;
+
+ /* weighted interlacing */
+ if (interlacing_leftweight) {
+ for (i = 0; i < numsamples; i++) {
+ int32_t difference, midright;
+ int32_t left;
+ int32_t right;
+
+ midright = buffer_a[i];
+ difference = buffer_b[i];
+
+ right = midright - ((difference * interlacing_leftweight) >> interlacing_shift);
+ left = right + difference;
+
+ if (uncompressed_bytes) {
+ uint32_t mask = ~(0xFFFFFFFF << (uncompressed_bytes * 8));
+ left <<= (uncompressed_bytes * 8);
+ right <<= (uncompressed_bytes * 8);
+
+ left |= uncompressed_bytes_buffer_a[i] & mask;
+ right |= uncompressed_bytes_buffer_b[i] & mask;
+ }
+
+ ((uint8_t *)buffer_out)[i * numchannels * 3] = (left)&0xFF;
+ ((uint8_t *)buffer_out)[i * numchannels * 3 + 1] = (left >> 8) & 0xFF;
+ ((uint8_t *)buffer_out)[i * numchannels * 3 + 2] = (left >> 16) & 0xFF;
+
+ ((uint8_t *)buffer_out)[i * numchannels * 3 + 3] = (right)&0xFF;
+ ((uint8_t *)buffer_out)[i * numchannels * 3 + 4] = (right >> 8) & 0xFF;
+ ((uint8_t *)buffer_out)[i * numchannels * 3 + 5] = (right >> 16) & 0xFF;
}
- /* otherwise basic interlacing took place */
- for (i = 0; i < numsamples; i++)
- {
- int16_t left, right;
+ return;
+ }
- left = buffer_a[i];
- right = buffer_b[i];
+ /* otherwise basic interlacing took place */
+ for (i = 0; i < numsamples; i++) {
+ int32_t left, right;
- /* output is always little endian */
- if (host_bigendian)
- {
- _Swap16(left);
- _Swap16(right);
- }
+ left = buffer_a[i];
+ right = buffer_b[i];
+
+ if (uncompressed_bytes) {
+ uint32_t mask = ~(0xFFFFFFFF << (uncompressed_bytes * 8));
+ left <<= (uncompressed_bytes * 8);
+ right <<= (uncompressed_bytes * 8);
- buffer_out[i*numchannels] = left;
- buffer_out[i*numchannels + 1] = right;
+ left |= uncompressed_bytes_buffer_a[i] & mask;
+ right |= uncompressed_bytes_buffer_b[i] & mask;
}
-}
-static void deinterlace_24(int32_t *buffer_a, int32_t *buffer_b,
- int uncompressed_bytes,
- int32_t *uncompressed_bytes_buffer_a, int32_t *uncompressed_bytes_buffer_b,
- void *buffer_out,
- int numchannels, int numsamples,
- uint8_t interlacing_shift,
- uint8_t interlacing_leftweight)
-{
- int i;
- if (numsamples <= 0) return;
+ ((uint8_t *)buffer_out)[i * numchannels * 3] = (left)&0xFF;
+ ((uint8_t *)buffer_out)[i * numchannels * 3 + 1] = (left >> 8) & 0xFF;
+ ((uint8_t *)buffer_out)[i * numchannels * 3 + 2] = (left >> 16) & 0xFF;
- /* weighted interlacing */
- if (interlacing_leftweight)
- {
- for (i = 0; i < numsamples; i++)
- {
- int32_t difference, midright;
- int32_t left;
- int32_t right;
-
- midright = buffer_a[i];
- difference = buffer_b[i];
-
- right = midright - ((difference * interlacing_leftweight) >> interlacing_shift);
- left = right + difference;
-
- if (uncompressed_bytes)
- {
- uint32_t mask = ~(0xFFFFFFFF << (uncompressed_bytes * 8));
- left <<= (uncompressed_bytes * 8);
- right <<= (uncompressed_bytes * 8);
-
- left |= uncompressed_bytes_buffer_a[i] & mask;
- right |= uncompressed_bytes_buffer_b[i] & mask;
- }
-
- ((uint8_t*)buffer_out)[i * numchannels * 3] = (left) & 0xFF;
- ((uint8_t*)buffer_out)[i * numchannels * 3 + 1] = (left >> 8) & 0xFF;
- ((uint8_t*)buffer_out)[i * numchannels * 3 + 2] = (left >> 16) & 0xFF;
-
- ((uint8_t*)buffer_out)[i * numchannels * 3 + 3] = (right) & 0xFF;
- ((uint8_t*)buffer_out)[i * numchannels * 3 + 4] = (right >> 8) & 0xFF;
- ((uint8_t*)buffer_out)[i * numchannels * 3 + 5] = (right >> 16) & 0xFF;
- }
+ ((uint8_t *)buffer_out)[i * numchannels * 3 + 3] = (right)&0xFF;
+ ((uint8_t *)buffer_out)[i * numchannels * 3 + 4] = (right >> 8) & 0xFF;
+ ((uint8_t *)buffer_out)[i * numchannels * 3 + 5] = (right >> 16) & 0xFF;
+ }
+}
- return;
- }
+void alac_decode_frame(alac_file *alac, unsigned char *inbuffer, void *outbuffer, int *outputsize) {
+ int outbuffer_allocation_size = *outputsize; // initial value
+ int channels;
+ int32_t outputsamples = alac->setinfo_max_samples_per_frame;
- /* otherwise basic interlacing took place */
- for (i = 0; i < numsamples; i++)
- {
- int32_t left, right;
+ /* setup the stream */
+ alac->input_buffer = inbuffer;
+ alac->input_buffer_bitaccumulator = 0;
- left = buffer_a[i];
- right = buffer_b[i];
+ channels = readbits(alac, 3);
- if (uncompressed_bytes)
- {
- uint32_t mask = ~(0xFFFFFFFF << (uncompressed_bytes * 8));
- left <<= (uncompressed_bytes * 8);
- right <<= (uncompressed_bytes * 8);
+ *outputsize = outputsamples * alac->bytespersample;
+ if (*outputsize > outbuffer_allocation_size) {
+ fprintf(stderr, "FIXME: Not enough space if the output buffer for audio frame - E1.\n");
+ *outputsize = 0;
+ return;
+ }
- left |= uncompressed_bytes_buffer_a[i] & mask;
- right |= uncompressed_bytes_buffer_b[i] & mask;
- }
+ switch (channels) {
+ case 0: /* 1 channel */
+ {
+ int hassize;
+ int isnotcompressed;
+ int readsamplesize;
- ((uint8_t*)buffer_out)[i * numchannels * 3] = (left) & 0xFF;
- ((uint8_t*)buffer_out)[i * numchannels * 3 + 1] = (left >> 8) & 0xFF;
- ((uint8_t*)buffer_out)[i * numchannels * 3 + 2] = (left >> 16) & 0xFF;
+ int uncompressed_bytes;
+ int ricemodifier;
- ((uint8_t*)buffer_out)[i * numchannels * 3 + 3] = (right) & 0xFF;
- ((uint8_t*)buffer_out)[i * numchannels * 3 + 4] = (right >> 8) & 0xFF;
- ((uint8_t*)buffer_out)[i * numchannels * 3 + 5] = (right >> 16) & 0xFF;
+ /* 2^result = something to do with output waiting.
+ * perhaps matters if we read > 1 frame in a pass?
+ */
+ readbits(alac, 4);
- }
+ readbits(alac, 12); /* unknown, skip 12 bits */
-}
+ hassize = readbits(alac, 1); /* the output sample size is stored soon */
-void alac_decode_frame(alac_file *alac,
- unsigned char *inbuffer,
- void *outbuffer, int *outputsize)
-{
- int outbuffer_allocation_size = *outputsize; // initial value
- int channels;
- int32_t outputsamples = alac->setinfo_max_samples_per_frame;
+ uncompressed_bytes =
+ readbits(alac, 2); /* number of bytes in the (compressed) stream that are not compressed */
- /* setup the stream */
- alac->input_buffer = inbuffer;
- alac->input_buffer_bitaccumulator = 0;
+ isnotcompressed = readbits(alac, 1); /* whether the frame is compressed */
- channels = readbits(alac, 3);
+ if (hassize) {
+ /* now read the number of samples,
+ * as a 32bit integer */
+ outputsamples = readbits(alac, 32);
+ *outputsize = outputsamples * alac->bytespersample;
+ if (*outputsize > outbuffer_allocation_size) {
+ fprintf(stderr, "FIXME: Not enough space if the output buffer for audio frame - E2.\n");
+ *outputsize = 0;
+ return;
+ }
+ }
- *outputsize = outputsamples * alac->bytespersample;
- if (*outputsize>outbuffer_allocation_size) {
- fprintf(stderr, "FIXME: Not enough space if the output buffer for audio frame - E1.\n");
- *outputsize = 0;
- return;
- }
+ readsamplesize = alac->setinfo_sample_size - (uncompressed_bytes * 8);
- switch(channels)
- {
- case 0: /* 1 channel */
- {
- int hassize;
- int isnotcompressed;
- int readsamplesize;
+ if (!isnotcompressed) { /* so it is compressed */
+ int16_t predictor_coef_table[32];
+ int predictor_coef_num;
+ int prediction_type;
+ int prediction_quantitization;
+ int i;
- int uncompressed_bytes;
- int ricemodifier;
+ /* skip 16 bits, not sure what they are. seem to be used in
+ * two channel case */
+ readbits(alac, 8);
+ readbits(alac, 8);
- /* 2^result = something to do with output waiting.
- * perhaps matters if we read > 1 frame in a pass?
- */
- readbits(alac, 4);
+ prediction_type = readbits(alac, 4);
+ prediction_quantitization = readbits(alac, 4);
- readbits(alac, 12); /* unknown, skip 12 bits */
+ ricemodifier = readbits(alac, 3);
+ predictor_coef_num = readbits(alac, 5);
- hassize = readbits(alac, 1); /* the output sample size is stored soon */
+ /* read the predictor table */
+ for (i = 0; i < predictor_coef_num; i++) {
+ predictor_coef_table[i] = (int16_t)readbits(alac, 16);
+ }
- uncompressed_bytes = readbits(alac, 2); /* number of bytes in the (compressed) stream that are not compressed */
+ if (uncompressed_bytes) {
+ int i;
+ for (i = 0; i < outputsamples; i++) {
+ alac->uncompressed_bytes_buffer_a[i] = readbits(alac, uncompressed_bytes * 8);
+ }
+ }
+
+ entropy_rice_decode(alac, alac->predicterror_buffer_a, outputsamples, readsamplesize,
+ alac->setinfo_rice_initialhistory, alac->setinfo_rice_kmodifier,
+ ricemodifier * alac->setinfo_rice_historymult / 4,
+ (1 << alac->setinfo_rice_kmodifier) - 1);
+
+ if (prediction_type == 0) { /* adaptive fir */
+ predictor_decompress_fir_adapt(alac->predicterror_buffer_a, alac->outputsamples_buffer_a,
+ outputsamples, readsamplesize, predictor_coef_table,
+ predictor_coef_num, prediction_quantitization);
+ } else {
+ fprintf(stderr, "FIXME: unhandled prediction type for compressed case: %i\n",
+ prediction_type);
+ /* i think the only other prediction type (or perhaps this is just a
+ * boolean?) runs adaptive fir twice.. like:
+ * predictor_decompress_fir_adapt(predictor_error, tempout, ...)
+ * predictor_decompress_fir_adapt(predictor_error, outputsamples ...)
+ * little strange..
+ */
+ }
- isnotcompressed = readbits(alac, 1); /* whether the frame is compressed */
+ } else { /* not compressed, easy case */
+ if (alac->setinfo_sample_size <= 16) {
+ int i;
+ for (i = 0; i < outputsamples; i++) {
+ int32_t audiobits = readbits(alac, alac->setinfo_sample_size);
- if (hassize)
- {
- /* now read the number of samples,
- * as a 32bit integer */
- outputsamples = readbits(alac, 32);
- *outputsize = outputsamples * alac->bytespersample;
- if (*outputsize>outbuffer_allocation_size) {
- fprintf(stderr, "FIXME: Not enough space if the output buffer for audio frame - E2.\n");
- *outputsize = 0;
- return;
- }
+ audiobits = SIGN_EXTENDED32(audiobits, alac->setinfo_sample_size);
+ alac->outputsamples_buffer_a[i] = audiobits;
}
+ } else {
+ int i;
+ for (i = 0; i < outputsamples; i++) {
+ int32_t audiobits;
- readsamplesize = alac->setinfo_sample_size - (uncompressed_bytes * 8);
-
- if (!isnotcompressed)
- { /* so it is compressed */
- int16_t predictor_coef_table[32];
- int predictor_coef_num;
- int prediction_type;
- int prediction_quantitization;
- int i;
-
- /* skip 16 bits, not sure what they are. seem to be used in
- * two channel case */
- readbits(alac, 8);
- readbits(alac, 8);
-
- prediction_type = readbits(alac, 4);
- prediction_quantitization = readbits(alac, 4);
-
- ricemodifier = readbits(alac, 3);
- predictor_coef_num = readbits(alac, 5);
-
- /* read the predictor table */
- for (i = 0; i < predictor_coef_num; i++)
- {
- predictor_coef_table[i] = (int16_t)readbits(alac, 16);
- }
-
- if (uncompressed_bytes)
- {
- int i;
- for (i = 0; i < outputsamples; i++)
- {
- alac->uncompressed_bytes_buffer_a[i] = readbits(alac, uncompressed_bytes * 8);
- }
- }
-
- entropy_rice_decode(alac,
- alac->predicterror_buffer_a,
- outputsamples,
- readsamplesize,
- alac->setinfo_rice_initialhistory,
- alac->setinfo_rice_kmodifier,
- ricemodifier * alac->setinfo_rice_historymult / 4,
- (1 << alac->setinfo_rice_kmodifier) - 1);
-
- if (prediction_type == 0)
- { /* adaptive fir */
- predictor_decompress_fir_adapt(alac->predicterror_buffer_a,
- alac->outputsamples_buffer_a,
- outputsamples,
- readsamplesize,
- predictor_coef_table,
- predictor_coef_num,
- prediction_quantitization);
- }
- else
- {
- fprintf(stderr, "FIXME: unhandled prediction type for compressed case: %i\n", prediction_type);
- /* i think the only other prediction type (or perhaps this is just a
- * boolean?) runs adaptive fir twice.. like:
- * predictor_decompress_fir_adapt(predictor_error, tempout, ...)
- * predictor_decompress_fir_adapt(predictor_error, outputsamples ...)
- * little strange..
- */
- }
+ audiobits = readbits(alac, 16);
+ /* special case of sign extension..
+ * as we'll be ORing the low 16bits into this */
+ audiobits = audiobits << (alac->setinfo_sample_size - 16);
+ audiobits |= readbits(alac, alac->setinfo_sample_size - 16);
+ audiobits = SignExtend24(audiobits);
+ alac->outputsamples_buffer_a[i] = audiobits;
}
- else
- { /* not compressed, easy case */
- if (alac->setinfo_sample_size <= 16)
- {
- int i;
- for (i = 0; i < outputsamples; i++)
- {
- int32_t audiobits = readbits(alac, alac->setinfo_sample_size);
-
- audiobits = SIGN_EXTENDED32(audiobits, alac->setinfo_sample_size);
-
- alac->outputsamples_buffer_a[i] = audiobits;
- }
- }
- else
- {
- int i;
- for (i = 0; i < outputsamples; i++)
- {
- int32_t audiobits;
-
- audiobits = readbits(alac, 16);
- /* special case of sign extension..
- * as we'll be ORing the low 16bits into this */
- audiobits = audiobits << (alac->setinfo_sample_size - 16);
- audiobits |= readbits(alac, alac->setinfo_sample_size - 16);
- audiobits = SignExtend24(audiobits);
-
- alac->outputsamples_buffer_a[i] = audiobits;
- }
- }
- uncompressed_bytes = 0; // always 0 for uncompressed
- }
+ }
+ uncompressed_bytes = 0; // always 0 for uncompressed
+ }
- switch(alac->setinfo_sample_size)
- {
- case 16:
- {
- int i;
- for (i = 0; i < outputsamples; i++)
- {
- int16_t sample = alac->outputsamples_buffer_a[i];
- if (host_bigendian)
- _Swap16(sample);
- ((int16_t*)outbuffer)[i * alac->numchannels] = sample;
- }
- break;
- }
- case 24:
- {
- int i;
- for (i = 0; i < outputsamples; i++)
- {
- int32_t sample = alac->outputsamples_buffer_a[i];
-
- if (uncompressed_bytes)
- {
- uint32_t mask;
- sample = sample << (uncompressed_bytes * 8);
- mask = ~(0xFFFFFFFF << (uncompressed_bytes * 8));
- sample |= alac->uncompressed_bytes_buffer_a[i] & mask;
- }
-
- ((uint8_t*)outbuffer)[i * alac->numchannels * 3] = (sample) & 0xFF;
- ((uint8_t*)outbuffer)[i * alac->numchannels * 3 + 1] = (sample >> 8) & 0xFF;
- ((uint8_t*)outbuffer)[i * alac->numchannels * 3 + 2] = (sample >> 16) & 0xFF;
- }
- break;
- }
- case 20:
- case 32:
- fprintf(stderr, "FIXME: unimplemented sample size %i\n", alac->setinfo_sample_size);
- break;
- default:
- break;
+ switch (alac->setinfo_sample_size) {
+ case 16: {
+ int i;
+ for (i = 0; i < outputsamples; i++) {
+ int16_t sample = alac->outputsamples_buffer_a[i];
+ if (host_bigendian)
+ _Swap16(sample);
+ ((int16_t *)outbuffer)[i * alac->numchannels] = sample;
+ }
+ break;
+ }
+ case 24: {
+ int i;
+ for (i = 0; i < outputsamples; i++) {
+ int32_t sample = alac->outputsamples_buffer_a[i];
+
+ if (uncompressed_bytes) {
+ uint32_t mask;
+ sample = sample << (uncompressed_bytes * 8);
+ mask = ~(0xFFFFFFFF << (uncompressed_bytes * 8));
+ sample |= alac->uncompressed_bytes_buffer_a[i] & mask;
}
- break;
+
+ ((uint8_t *)outbuffer)[i * alac->numchannels * 3] = (sample)&0xFF;
+ ((uint8_t *)outbuffer)[i * alac->numchannels * 3 + 1] = (sample >> 8) & 0xFF;
+ ((uint8_t *)outbuffer)[i * alac->numchannels * 3 + 2] = (sample >> 16) & 0xFF;
+ }
+ break;
}
- case 1: /* 2 channels */
- {
- int hassize;
- int isnotcompressed;
- int readsamplesize;
+ case 20:
+ case 32:
+ fprintf(stderr, "FIXME: unimplemented sample size %i\n", alac->setinfo_sample_size);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case 1: /* 2 channels */
+ {
+ int hassize;
+ int isnotcompressed;
+ int readsamplesize;
- int uncompressed_bytes;
+ int uncompressed_bytes;
- uint8_t interlacing_shift;
- uint8_t interlacing_leftweight;
+ uint8_t interlacing_shift;
+ uint8_t interlacing_leftweight;
- /* 2^result = something to do with output waiting.
- * perhaps matters if we read > 1 frame in a pass?
- */
- readbits(alac, 4);
+ /* 2^result = something to do with output waiting.
+ * perhaps matters if we read > 1 frame in a pass?
+ */
+ readbits(alac, 4);
- readbits(alac, 12); /* unknown, skip 12 bits */
+ readbits(alac, 12); /* unknown, skip 12 bits */
- hassize = readbits(alac, 1); /* the output sample size is stored soon */
+ hassize = readbits(alac, 1); /* the output sample size is stored soon */
- uncompressed_bytes = readbits(alac, 2); /* the number of bytes in the (compressed) stream that are not compressed */
+ uncompressed_bytes = readbits(
+ alac, 2); /* the number of bytes in the (compressed) stream that are not compressed */
- isnotcompressed = readbits(alac, 1); /* whether the frame is compressed */
+ isnotcompressed = readbits(alac, 1); /* whether the frame is compressed */
- if (hassize)
- {
- /* now read the number of samples,
- * as a 32bit integer */
- outputsamples = readbits(alac, 32);
- *outputsize = outputsamples * alac->bytespersample;
- if (*outputsize>outbuffer_allocation_size) {
- fprintf(stderr, "FIXME: Not enough space if the output buffer for audio frame - E3.\n");
- *outputsize = 0;
- return;
- }
- }
+ if (hassize) {
+ /* now read the number of samples,
+ * as a 32bit integer */
+ outputsamples = readbits(alac, 32);
+ *outputsize = outputsamples * alac->bytespersample;
+ if (*outputsize > outbuffer_allocation_size) {
+ fprintf(stderr, "FIXME: Not enough space if the output buffer for audio frame - E3.\n");
+ *outputsize = 0;
+ return;
+ }
+ }
- readsamplesize = alac->setinfo_sample_size - (uncompressed_bytes * 8) + 1;
-
- if (!isnotcompressed)
- { /* compressed */
- int16_t predictor_coef_table_a[32];
- int predictor_coef_num_a;
- int prediction_type_a;
- int prediction_quantitization_a;
- int ricemodifier_a;
-
- int16_t predictor_coef_table_b[32];
- int predictor_coef_num_b;
- int prediction_type_b;
- int prediction_quantitization_b;
- int ricemodifier_b;
-
- int i;
-
- interlacing_shift = readbits(alac, 8);
- interlacing_leftweight = readbits(alac, 8);
-
- /******** channel 1 ***********/
- prediction_type_a = readbits(alac, 4);
- prediction_quantitization_a = readbits(alac, 4);
-
- ricemodifier_a = readbits(alac, 3);
- predictor_coef_num_a = readbits(alac, 5);
-
- /* read the predictor table */
- for (i = 0; i < predictor_coef_num_a; i++)
- {
- predictor_coef_table_a[i] = (int16_t)readbits(alac, 16);
- }
-
- /******** channel 2 *********/
- prediction_type_b = readbits(alac, 4);
- prediction_quantitization_b = readbits(alac, 4);
-
- ricemodifier_b = readbits(alac, 3);
- predictor_coef_num_b = readbits(alac, 5);
-
- /* read the predictor table */
- for (i = 0; i < predictor_coef_num_b; i++)
- {
- predictor_coef_table_b[i] = (int16_t)readbits(alac, 16);
- }
-
- /*********************/
- if (uncompressed_bytes)
- { /* see mono case */
- int i;
- for (i = 0; i < outputsamples; i++)
- {
- alac->uncompressed_bytes_buffer_a[i] = readbits(alac, uncompressed_bytes * 8);
- alac->uncompressed_bytes_buffer_b[i] = readbits(alac, uncompressed_bytes * 8);
- }
- }
-
- /* channel 1 */
- entropy_rice_decode(alac,
- alac->predicterror_buffer_a,
- outputsamples,
- readsamplesize,
- alac->setinfo_rice_initialhistory,
- alac->setinfo_rice_kmodifier,
- ricemodifier_a * alac->setinfo_rice_historymult / 4,
- (1 << alac->setinfo_rice_kmodifier) - 1);
-
- if (prediction_type_a == 0)
- { /* adaptive fir */
- predictor_decompress_fir_adapt(alac->predicterror_buffer_a,
- alac->outputsamples_buffer_a,
- outputsamples,
- readsamplesize,
- predictor_coef_table_a,
- predictor_coef_num_a,
- prediction_quantitization_a);
- }
- else
- { /* see mono case */
- fprintf(stderr, "FIXME: unhandled prediction type on channel 1: %i\n", prediction_type_a);
- }
-
- /* channel 2 */
- entropy_rice_decode(alac,
- alac->predicterror_buffer_b,
- outputsamples,
- readsamplesize,
- alac->setinfo_rice_initialhistory,
- alac->setinfo_rice_kmodifier,
- ricemodifier_b * alac->setinfo_rice_historymult / 4,
- (1 << alac->setinfo_rice_kmodifier) - 1);
-
- if (prediction_type_b == 0)
- { /* adaptive fir */
- predictor_decompress_fir_adapt(alac->predicterror_buffer_b,
- alac->outputsamples_buffer_b,
- outputsamples,
- readsamplesize,
- predictor_coef_table_b,
- predictor_coef_num_b,
- prediction_quantitization_b);
- }
- else
- {
- fprintf(stderr, "FIXME: unhandled prediction type on channel 2: %i\n", prediction_type_b);
- }
- }
- else
- { /* not compressed, easy case */
- if (alac->setinfo_sample_size <= 16)
- {
- int i;
- for (i = 0; i < outputsamples; i++)
- {
- int32_t audiobits_a, audiobits_b;
-
- audiobits_a = readbits(alac, alac->setinfo_sample_size);
- audiobits_b = readbits(alac, alac->setinfo_sample_size);
-
- audiobits_a = SIGN_EXTENDED32(audiobits_a, alac->setinfo_sample_size);
- audiobits_b = SIGN_EXTENDED32(audiobits_b, alac->setinfo_sample_size);
-
- alac->outputsamples_buffer_a[i] = audiobits_a;
- alac->outputsamples_buffer_b[i] = audiobits_b;
- }
- }
- else
- {
- int i;
- for (i = 0; i < outputsamples; i++)
- {
- int32_t audiobits_a, audiobits_b;
-
- audiobits_a = readbits(alac, 16);
- audiobits_a = audiobits_a << (alac->setinfo_sample_size - 16);
- audiobits_a |= readbits(alac, alac->setinfo_sample_size - 16);
- audiobits_a = SignExtend24(audiobits_a);
-
- audiobits_b = readbits(alac, 16);
- audiobits_b = audiobits_b << (alac->setinfo_sample_size - 16);
- audiobits_b |= readbits(alac, alac->setinfo_sample_size - 16);
- audiobits_b = SignExtend24(audiobits_b);
-
- alac->outputsamples_buffer_a[i] = audiobits_a;
- alac->outputsamples_buffer_b[i] = audiobits_b;
- }
- }
- uncompressed_bytes = 0; // always 0 for uncompressed
- interlacing_shift = 0;
- interlacing_leftweight = 0;
- }
+ readsamplesize = alac->setinfo_sample_size - (uncompressed_bytes * 8) + 1;
+
+ if (!isnotcompressed) { /* compressed */
+ int16_t predictor_coef_table_a[32];
+ int predictor_coef_num_a;
+ int prediction_type_a;
+ int prediction_quantitization_a;
+ int ricemodifier_a;
+
+ int16_t predictor_coef_table_b[32];
+ int predictor_coef_num_b;
+ int prediction_type_b;
+ int prediction_quantitization_b;
+ int ricemodifier_b;
+
+ int i;
+
+ interlacing_shift = readbits(alac, 8);
+ interlacing_leftweight = readbits(alac, 8);
+
+ /******** channel 1 ***********/
+ prediction_type_a = readbits(alac, 4);
+ prediction_quantitization_a = readbits(alac, 4);
+
+ ricemodifier_a = readbits(alac, 3);
+ predictor_coef_num_a = readbits(alac, 5);
+
+ /* read the predictor table */
+ for (i = 0; i < predictor_coef_num_a; i++) {
+ predictor_coef_table_a[i] = (int16_t)readbits(alac, 16);
+ }
+
+ /******** channel 2 *********/
+ prediction_type_b = readbits(alac, 4);
+ prediction_quantitization_b = readbits(alac, 4);
- switch(alac->setinfo_sample_size)
- {
- case 16:
- {
- deinterlace_16(alac->outputsamples_buffer_a,
- alac->outputsamples_buffer_b,
- (int16_t*)outbuffer,
- alac->numchannels,
- outputsamples,
- interlacing_shift,
- interlacing_leftweight);
- break;
+ ricemodifier_b = readbits(alac, 3);
+ predictor_coef_num_b = readbits(alac, 5);
+
+ /* read the predictor table */
+ for (i = 0; i < predictor_coef_num_b; i++) {
+ predictor_coef_table_b[i] = (int16_t)readbits(alac, 16);
+ }
+
+ /*********************/
+ if (uncompressed_bytes) { /* see mono case */
+ int i;
+ for (i = 0; i < outputsamples; i++) {
+ alac->uncompressed_bytes_buffer_a[i] = readbits(alac, uncompressed_bytes * 8);
+ alac->uncompressed_bytes_buffer_b[i] = readbits(alac, uncompressed_bytes * 8);
}
- case 24:
- {
- deinterlace_24(alac->outputsamples_buffer_a,
- alac->outputsamples_buffer_b,
- uncompressed_bytes,
- alac->uncompressed_bytes_buffer_a,
- alac->uncompressed_bytes_buffer_b,
- (int16_t*)outbuffer,
- alac->numchannels,
- outputsamples,
- interlacing_shift,
- interlacing_leftweight);
- break;
+ }
+
+ /* channel 1 */
+ entropy_rice_decode(alac, alac->predicterror_buffer_a, outputsamples, readsamplesize,
+ alac->setinfo_rice_initialhistory, alac->setinfo_rice_kmodifier,
+ ricemodifier_a * alac->setinfo_rice_historymult / 4,
+ (1 << alac->setinfo_rice_kmodifier) - 1);
+
+ if (prediction_type_a == 0) { /* adaptive fir */
+ predictor_decompress_fir_adapt(alac->predicterror_buffer_a, alac->outputsamples_buffer_a,
+ outputsamples, readsamplesize, predictor_coef_table_a,
+ predictor_coef_num_a, prediction_quantitization_a);
+ } else { /* see mono case */
+ fprintf(stderr, "FIXME: unhandled prediction type on channel 1: %i\n", prediction_type_a);
+ }
+
+ /* channel 2 */
+ entropy_rice_decode(alac, alac->predicterror_buffer_b, outputsamples, readsamplesize,
+ alac->setinfo_rice_initialhistory, alac->setinfo_rice_kmodifier,
+ ricemodifier_b * alac->setinfo_rice_historymult / 4,
+ (1 << alac->setinfo_rice_kmodifier) - 1);
+
+ if (prediction_type_b == 0) { /* adaptive fir */
+ predictor_decompress_fir_adapt(alac->predicterror_buffer_b, alac->outputsamples_buffer_b,
+ outputsamples, readsamplesize, predictor_coef_table_b,
+ predictor_coef_num_b, prediction_quantitization_b);
+ } else {
+ fprintf(stderr, "FIXME: unhandled prediction type on channel 2: %i\n", prediction_type_b);
+ }
+ } else { /* not compressed, easy case */
+ if (alac->setinfo_sample_size <= 16) {
+ int i;
+ for (i = 0; i < outputsamples; i++) {
+ int32_t audiobits_a, audiobits_b;
+
+ audiobits_a = readbits(alac, alac->setinfo_sample_size);
+ audiobits_b = readbits(alac, alac->setinfo_sample_size);
+
+ audiobits_a = SIGN_EXTENDED32(audiobits_a, alac->setinfo_sample_size);
+ audiobits_b = SIGN_EXTENDED32(audiobits_b, alac->setinfo_sample_size);
+
+ alac->outputsamples_buffer_a[i] = audiobits_a;
+ alac->outputsamples_buffer_b[i] = audiobits_b;
}
- case 20:
- case 32:
- fprintf(stderr, "FIXME: unimplemented sample size %i\n", alac->setinfo_sample_size);
- break;
- default:
- break;
+ } else {
+ int i;
+ for (i = 0; i < outputsamples; i++) {
+ int32_t audiobits_a, audiobits_b;
+
+ audiobits_a = readbits(alac, 16);
+ audiobits_a = audiobits_a << (alac->setinfo_sample_size - 16);
+ audiobits_a |= readbits(alac, alac->setinfo_sample_size - 16);
+ audiobits_a = SignExtend24(audiobits_a);
+
+ audiobits_b = readbits(alac, 16);
+ audiobits_b = audiobits_b << (alac->setinfo_sample_size - 16);
+ audiobits_b |= readbits(alac, alac->setinfo_sample_size - 16);
+ audiobits_b = SignExtend24(audiobits_b);
+
+ alac->outputsamples_buffer_a[i] = audiobits_a;
+ alac->outputsamples_buffer_b[i] = audiobits_b;
}
+ }
+ uncompressed_bytes = 0; // always 0 for uncompressed
+ interlacing_shift = 0;
+ interlacing_leftweight = 0;
+ }
- break;
+ switch (alac->setinfo_sample_size) {
+ case 16: {
+ deinterlace_16(alac->outputsamples_buffer_a, alac->outputsamples_buffer_b,
+ (int16_t *)outbuffer, alac->numchannels, outputsamples, interlacing_shift,
+ interlacing_leftweight);
+ break;
}
+ case 24: {
+ deinterlace_24(alac->outputsamples_buffer_a, alac->outputsamples_buffer_b, uncompressed_bytes,
+ alac->uncompressed_bytes_buffer_a, alac->uncompressed_bytes_buffer_b,
+ (int16_t *)outbuffer, alac->numchannels, outputsamples, interlacing_shift,
+ interlacing_leftweight);
+ break;
}
+ case 20:
+ case 32:
+ fprintf(stderr, "FIXME: unimplemented sample size %i\n", alac->setinfo_sample_size);
+ break;
+ default:
+ break;
+ }
+
+ break;
+ }
+ }
}
-alac_file *alac_create(int samplesize, int numchannels)
-{
- alac_file *newfile = malloc(sizeof(alac_file));
+alac_file *alac_create(int samplesize, int numchannels) {
+ alac_file *newfile = malloc(sizeof(alac_file));
- memset(newfile, 0, sizeof(alac_file));
+ memset(newfile, 0, sizeof(alac_file));
- newfile->samplesize = samplesize;
- newfile->numchannels = numchannels;
- newfile->bytespersample = (samplesize / 8) * numchannels;
+ newfile->samplesize = samplesize;
+ newfile->numchannels = numchannels;
+ newfile->bytespersample = (samplesize / 8) * numchannels;
- return newfile;
+ return newfile;
}
-
typedef struct alac_file alac_file;
alac_file *alac_create(int samplesize, int numchannels);
-void alac_decode_frame(alac_file *alac,
- unsigned char *inbuffer,
- void *outbuffer, int *outputsize);
+void alac_decode_frame(alac_file *alac, unsigned char *inbuffer, void *outbuffer, int *outputsize);
void alac_set_info(alac_file *alac, char *inputbuffer);
void alac_allocate_buffers(alac_file *alac);
void alac_free(alac_file *alac);
-struct alac_file
-{
- unsigned char *input_buffer;
- int input_buffer_bitaccumulator; /* used so we can do arbitary
- bit reads */
+struct alac_file {
+ unsigned char *input_buffer;
+ int input_buffer_bitaccumulator; /* used so we can do arbitary
+ bit reads */
- int samplesize;
- int numchannels;
- int bytespersample;
+ int samplesize;
+ int numchannels;
+ int bytespersample;
+ /* buffers */
+ int32_t *predicterror_buffer_a;
+ int32_t *predicterror_buffer_b;
- /* buffers */
- int32_t *predicterror_buffer_a;
- int32_t *predicterror_buffer_b;
-
- int32_t *outputsamples_buffer_a;
- int32_t *outputsamples_buffer_b;
-
- int32_t *uncompressed_bytes_buffer_a;
- int32_t *uncompressed_bytes_buffer_b;
-
+ int32_t *outputsamples_buffer_a;
+ int32_t *outputsamples_buffer_b;
+ int32_t *uncompressed_bytes_buffer_a;
+ int32_t *uncompressed_bytes_buffer_b;
/* stuff from setinfo */
- uint32_t setinfo_max_samples_per_frame; /* 0x1000 = 4096 */ /* max samples per frame? */
- uint8_t setinfo_7a; /* 0x00 */
- uint8_t setinfo_sample_size; /* 0x10 */
- uint8_t setinfo_rice_historymult; /* 0x28 */
- uint8_t setinfo_rice_initialhistory; /* 0x0a */
- uint8_t setinfo_rice_kmodifier; /* 0x0e */
- uint8_t setinfo_7f; /* 0x02 */
- uint16_t setinfo_80; /* 0x00ff */
- uint32_t setinfo_82; /* 0x000020e7 */ /* max sample size?? */
- uint32_t setinfo_86; /* 0x00069fe4 */ /* bit rate (avarge)?? */
- uint32_t setinfo_8a_rate; /* 0x0000ac44 */
+ uint32_t setinfo_max_samples_per_frame; /* 0x1000 = 4096 */ /* max samples per frame? */
+ uint8_t setinfo_7a; /* 0x00 */
+ uint8_t setinfo_sample_size; /* 0x10 */
+ uint8_t setinfo_rice_historymult; /* 0x28 */
+ uint8_t setinfo_rice_initialhistory; /* 0x0a */
+ uint8_t setinfo_rice_kmodifier; /* 0x0e */
+ uint8_t setinfo_7f; /* 0x02 */
+ uint16_t setinfo_80; /* 0x00ff */
+ uint32_t setinfo_82; /* 0x000020e7 */ /* max sample size?? */
+ uint32_t setinfo_86; /* 0x00069fe4 */ /* bit rate (avarge)?? */
+ uint32_t setinfo_8a_rate; /* 0x0000ac44 */
/* end setinfo stuff */
-
};
-
#endif /* __ALAC__DECOMP_H */
-
#include <string.h>
// these are headers for the ALAC decoder, utilities and endian utilities
-#include <alac/ALACDecoder.h>
#include <alac/ALACBitUtilities.h>
+#include <alac/ALACDecoder.h>
#include <alac/EndianPortable.h>
-#include "config.h"
#include "apple_alac.h"
+#include "config.h"
typedef struct magicCookie {
ALACSpecificConfig config;
} magicCookie;
magicCookie cookie;
-ALACDecoder * theDecoder;
+ALACDecoder *theDecoder;
extern "C" int apple_alac_init(int32_t fmtp[12]) {
- memset(&cookie,0,sizeof(magicCookie));
-
- //create a magic cookie for the decoder from the fmtp information. It seems to be in the same format as a simple magic cookie
-
+ memset(&cookie, 0, sizeof(magicCookie));
+
+ // create a magic cookie for the decoder from the fmtp information. It seems to be in the same
+ // format as a simple magic cookie
+
cookie.config.frameLength = Swap32NtoB(352);
- cookie.config.compatibleVersion = fmtp[2]; // should be zero, uint8_t
- cookie.config.bitDepth = fmtp[3]; // uint8_t expected to be 16
- cookie.config.pb = fmtp[4]; // uint8_t should be 40;
- cookie.config.mb = fmtp[5]; // uint8_t should be 10;
- cookie.config.kb = fmtp[6]; // uint8_t should be 14;
- cookie.config.numChannels = fmtp[7]; // uint8_t expected to be 2
- cookie.config.maxRun = Swap16NtoB(fmtp[8]); // uint16_t expected to be 255
+ cookie.config.compatibleVersion = fmtp[2]; // should be zero, uint8_t
+ cookie.config.bitDepth = fmtp[3]; // uint8_t expected to be 16
+ cookie.config.pb = fmtp[4]; // uint8_t should be 40;
+ cookie.config.mb = fmtp[5]; // uint8_t should be 10;
+ cookie.config.kb = fmtp[6]; // uint8_t should be 14;
+ cookie.config.numChannels = fmtp[7]; // uint8_t expected to be 2
+ cookie.config.maxRun = Swap16NtoB(fmtp[8]); // uint16_t expected to be 255
cookie.config.maxFrameBytes = Swap32NtoB(fmtp[9]); // uint32_t should be 0;
- cookie.config.avgBitRate = Swap32NtoB(fmtp[10]); // uint32_t should be 0;;
- cookie.config.sampleRate = Swap32NtoB(fmtp[11]); // uint32_t expected to be 44100;
-
+ cookie.config.avgBitRate = Swap32NtoB(fmtp[10]); // uint32_t should be 0;;
+ cookie.config.sampleRate = Swap32NtoB(fmtp[11]); // uint32_t expected to be 44100;
+
theDecoder = new ALACDecoder;
- theDecoder->Init(&cookie, sizeof(magicCookie));
+ theDecoder->Init(&cookie, sizeof(magicCookie));
return 0;
}
-extern "C" int apple_alac_decode_frame(unsigned char *sampleBuffer, uint32_t bufferLength, unsigned char *dest, int *outsize)
-{
+extern "C" int apple_alac_decode_frame(unsigned char *sampleBuffer, uint32_t bufferLength,
+ unsigned char *dest, int *outsize) {
uint32_t numFrames = 0;
BitBuffer theInputBuffer;
BitBufferInit(&theInputBuffer, sampleBuffer, bufferLength);
- theDecoder->Decode(&theInputBuffer, dest, Swap32BtoN(cookie.config.frameLength), cookie.config.numChannels, &numFrames);
+ theDecoder->Decode(&theInputBuffer, dest, Swap32BtoN(cookie.config.frameLength),
+ cookie.config.numChannels, &numFrames);
*outsize = numFrames;
return 0;
}
-extern "C" int apple_alac_terminate() {
- delete(theDecoder);
-}
-
+extern "C" int apple_alac_terminate() { delete (theDecoder); }
#ifndef __APPLE_ALAC_H
#define __APPLE_ALAC_H
-#include <stdint.h>
#include "config.h"
+#include <stdint.h>
#ifdef __cplusplus
- #define EXTERNC extern "C"
+#define EXTERNC extern "C"
#else
- #define EXTERNC
+#define EXTERNC
#endif
-
EXTERNC int apple_alac_init(int32_t fmtp[12]);
EXTERNC int apple_alac_terminate();
-EXTERNC int apple_alac_decode_frame(unsigned char *sampleBuffer, uint32_t bufferLength, unsigned char *dest, int *outsize);
+EXTERNC int apple_alac_decode_frame(unsigned char *sampleBuffer, uint32_t bufferLength,
+ unsigned char *dest, int *outsize);
#undef EXTERNC
#endif /* __APPLE_ALAC_H */
-
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <stdio.h>
-#include <string.h>
#include "audio.h"
#include "config.h"
+#include <stdio.h>
+#include <string.h>
#ifdef CONFIG_SNDIO
extern audio_output audio_sndio;
#ifdef CONFIG_DUMMY
&audio_dummy,
#endif
-#ifdef CONFIG_PIPE
+#ifdef CONFIG_PIPE
&audio_pipe,
#endif
#ifdef CONFIG_STDOUT
#ifndef _AUDIO_H
#define _AUDIO_H
-#include <stdint.h>
#include <libconfig.h>
+#include <stdint.h>
typedef struct {
double current_volume_dB;
// almost certainly wrong if the buffer is empty, so put silent buffers into it to make it busy.
// will change dynamically, so keep watching it. Implemented in ALSA only.
// returns a negative error code if there's a problem
- int (*delay)(long* the_delay); // snd_pcm_sframes_t is a signed long
+ int (*delay)(long *the_delay); // snd_pcm_sframes_t is a signed long
// may be NULL, in which case soft volume is applied
void (*volume)(double vol);
// 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);
#define ALSA_PCM_NEW_HW_PARAMS_API
-#include <stdio.h>
-#include <unistd.h>
-#include <memory.h>
+#include "audio.h"
+#include "common.h"
+#include <alsa/asoundlib.h>
#include <math.h>
+#include <memory.h>
#include <pthread.h>
-#include <alsa/asoundlib.h>
-#include "common.h"
-#include "audio.h"
+#include <stdio.h>
+#include <unistd.h>
static void help(void);
static int init(int argc, char **argv);
static void play(short buf[], int samples);
static void stop(void);
static void flush(void);
-int delay(long* the_delay);
+int delay(long *the_delay);
static void volume(double vol);
static void linear_volume(double vol);
static void parameters(audio_parameters *info);
static double set_volume;
static int output_method_signalled = 0;
-audio_output audio_alsa = {
- .name = "alsa",
- .help = &help,
- .init = &init,
- .deinit = &deinit,
- .start = &start,
- .stop = &stop,
- .flush = &flush,
- .delay = &delay,
- .play = &play,
- .mute = &mute,
- .volume = &volume,
- .parameters = ¶meters
-};
+audio_output audio_alsa = {.name = "alsa",
+ .help = &help,
+ .init = &init,
+ .deinit = &deinit,
+ .start = &start,
+ .stop = &stop,
+ .flush = &flush,
+ .delay = &delay,
+ .play = &play,
+ .mute = &mute,
+ .volume = &volume,
+ .parameters = ¶meters};
static pthread_mutex_t alsa_mutex = PTHREAD_MUTEX_INITIALIZER;
static int hardware_mixer = 0;
static int has_softvol = 0;
-static snd_pcm_sframes_t (*alsa_pcm_write)(snd_pcm_t *, const void *, snd_pcm_uframes_t) = snd_pcm_writei;
+static snd_pcm_sframes_t (*alsa_pcm_write)(snd_pcm_t *, const void *,
+ snd_pcm_uframes_t) = snd_pcm_writei;
static int play_number;
static int64_t accumulated_delay, accumulated_da_delay;
int alsa_characteristics_already_listed = 0;
-static snd_pcm_uframes_t period_size_requested,buffer_size_requested;
-static int set_period_size_request,set_buffer_size_request;
-
+static snd_pcm_uframes_t period_size_requested, buffer_size_requested;
+static int set_period_size_request, set_buffer_size_request;
static void help(void) {
printf(" -d output-device set the output device [default*|...]\n"
int value;
double dvalue;
- set_period_size_request = 0;
- set_buffer_size_request = 0;
-
+ set_period_size_request = 0;
+ set_buffer_size_request = 0;
+
config.audio_backend_latency_offset = 0;
config.audio_backend_buffer_desired_length = 0.15;
if (config.cfg != NULL) {
/* Get the desired buffer size setting. */
- if (config_lookup_float(config.cfg,
- "alsa.audio_backend_buffer_desired_length", &dvalue)) {
+ if (config_lookup_float(config.cfg, "alsa.audio_backend_buffer_desired_length", &dvalue)) {
if ((dvalue < 0) || (value > 1.5))
die("Invalid alsa audio backend buffer desired length \"%f\". It "
"should be between 0 and "
}
/* Get the latency offset. */
- if (config_lookup_float(config.cfg, "alsa.audio_backend_latency_offset",
- &dvalue)) {
+ if (config_lookup_float(config.cfg, "alsa.audio_backend_latency_offset", &dvalue)) {
if ((dvalue < -1.0) || (value > 1.5))
die("Invalid alsa audio backend buffer latency offset \"%f\". It "
"should be between -1.0 and +1.5, default is 0 seconds",
alsa_mix_ctrl = (char *)str;
hardware_mixer = 1;
}
-
+
/* Get the disable_synchronization setting. */
if (config_lookup_string(config.cfg, "alsa.disable_synchronization", &str)) {
if (strcasecmp(str, "no") == 0)
else
die("Invalid disable_synchronization option choice \"%s\". It should be \"yes\" or \"no\"");
}
-
+
/* Get the output format, using the same names as aplay does*/
if (config_lookup_string(config.cfg, "alsa.output_format", &str)) {
if (strcasecmp(str, "S16_LE") == 0)
else if (strcasecmp(str, "S8") == 0)
config.output_format = SPS_FORMAT_S8;
else
- die("Invalid output format \"%s\". It should be \"U8\", \"S8\", \"S16_LE\", \"S24_LE\" or \"S32_LE\"",str);
+ die("Invalid output format \"%s\". It should be \"U8\", \"S8\", \"S16_LE\", \"S24_LE\" or "
+ "\"S32_LE\"",
+ str);
}
/* Get the output rate, which must be a multiple of 44,100*/
- if (config_lookup_int(config.cfg, "alsa.output_rate",
- &value)) {
- debug(1,"Value read for output rate is %d.",value);
- switch(value) {
- case 44100:
- case 88200:
- case 176400:
- case 352800:
- config.output_rate = value;
- break;
- default :
- die("Invalid output rate \"%d\". It should be a multiple of 44,100 up to 352,800",value);
- }
+ if (config_lookup_int(config.cfg, "alsa.output_rate", &value)) {
+ debug(1, "Value read for output rate is %d.", value);
+ switch (value) {
+ case 44100:
+ case 88200:
+ case 176400:
+ case 352800:
+ config.output_rate = value;
+ break;
+ default:
+ die("Invalid output rate \"%d\". It should be a multiple of 44,100 up to 352,800", value);
+ }
}
-
/* Get the use_mmap_if_available setting. */
if (config_lookup_string(config.cfg, "alsa.use_mmap_if_available", &str)) {
if (strcasecmp(str, "no") == 0)
die("Invalid use_mmap_if_available option choice \"%s\". It should be \"yes\" or \"no\"");
}
/* Get the optional period size value */
- if (config_lookup_int(config.cfg, "alsa.period_size",
- &value)) {
+ if (config_lookup_int(config.cfg, "alsa.period_size", &value)) {
set_period_size_request = 1;
- debug(1,"Value read for period size is %d.",value);
+ debug(1, "Value read for period size is %d.", value);
if (value < 0)
die("Invalid alsa period size setting \"%d\". It "
"must be greater than 0.",
}
/* Get the optional buffer size value */
- if (config_lookup_int(config.cfg, "alsa.buffer_size",
- &value)) {
+ if (config_lookup_int(config.cfg, "alsa.buffer_size", &value)) {
set_buffer_size_request = 1;
- debug(1,"Value read for buffer size is %d.",value);
+ debug(1, "Value read for buffer size is %d.", value);
if (value < 0)
die("Invalid alsa buffer size setting \"%d\". It "
"must be greater than 0.",
buffer_size_requested = value;
}
}
-
-
optind = 1; // optind=0 is equivalent to optind=1 plus special behaviour
argv--; // so we shift the arguments to satisfy getopt()
debug(1, "Output device name is \"%s\".", alsa_out_dev);
if (hardware_mixer) {
-
+
if (alsa_mix_dev == NULL)
alsa_mix_dev = alsa_out_dev;
open_mixer();
- if (snd_mixer_selem_get_playback_volume_range(alsa_mix_elem, &alsa_mix_minv,
- &alsa_mix_maxv) < 0)
+ if (snd_mixer_selem_get_playback_volume_range(alsa_mix_elem, &alsa_mix_minv, &alsa_mix_maxv) <
+ 0)
debug(1, "Can't read mixer's [linear] min and max volumes.");
else {
- if (snd_mixer_selem_get_playback_dB_range(alsa_mix_elem, &alsa_mix_mindb,
- &alsa_mix_maxdb) == 0) {
+ if (snd_mixer_selem_get_playback_dB_range(alsa_mix_elem, &alsa_mix_mindb, &alsa_mix_maxdb) ==
+ 0) {
- audio_alsa.volume =
- &volume; // insert the volume function now we know it can do dB stuff
+ audio_alsa.volume = &volume; // insert the volume function now we know it can do dB stuff
audio_alsa.parameters = ¶meters; // likewise the parameters stuff
if (alsa_mix_mindb == SND_CTL_TLV_DB_GAIN_MUTE) {
// Raspberry Pi does this
debug(1, "Lowest dB value is a mute -- try minimum volume +1");
- if (snd_mixer_selem_ask_playback_vol_dB(
- alsa_mix_elem, alsa_mix_minv + 1, &alsa_mix_mindb) != 0)
+ if (snd_mixer_selem_ask_playback_vol_dB(alsa_mix_elem, alsa_mix_minv + 1,
+ &alsa_mix_mindb) != 0)
debug(1, "Can't get dB value corresponding to a minimum volume + 1.");
}
- 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);
+ 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);
} else {
// use the linear scale and do the db conversion ourselves
debug(1, "note: the hardware mixer specified -- \"%s\" -- does not have "
snd_ctl_elem_id_set_interface(elem_id, SND_CTL_ELEM_IFACE_MIXER);
snd_ctl_elem_id_set_name(elem_id, alsa_mix_ctrl);
- if (snd_ctl_get_dB_range(ctl, elem_id, &alsa_mix_mindb,
- &alsa_mix_maxdb) == 0) {
- debug(1, "Volume control \"%s\" has dB volume from %f to %f.",
- alsa_mix_ctrl,
- (1.0 * alsa_mix_mindb) / 100.0,
- (1.0 * alsa_mix_maxdb) / 100.0);
+ if (snd_ctl_get_dB_range(ctl, elem_id, &alsa_mix_mindb, &alsa_mix_maxdb) == 0) {
+ debug(1, "Volume control \"%s\" has dB volume from %f to %f.", alsa_mix_ctrl,
+ (1.0 * alsa_mix_mindb) / 100.0, (1.0 * alsa_mix_maxdb) / 100.0);
has_softvol = 1;
} else {
- debug(1, "Cannot get the dB range from the volume control \"%s\"",
- alsa_mix_ctrl);
+ debug(1, "Cannot get the dB range from the volume control \"%s\"", alsa_mix_ctrl);
}
/*
}
}
if (snd_mixer_selem_has_playback_switch(alsa_mix_elem)) {
- audio_alsa.mute =
- &mute; // insert the mute function now we know it can do muting stuff
+ audio_alsa.mute = &mute; // insert the mute function now we know it can do muting stuff
debug(1, "Has mute ability.");
}
snd_mixer_close(alsa_mix_handle);
}
-
+
alsa_mix_handle = NULL;
pthread_mutex_unlock(&alsa_mutex);
return 0;
}
int open_alsa_device(void) {
-
+
const snd_pcm_uframes_t minimal_buffer_headroom =
352 * 2; // we accept this much headroom in the hardware buffer, but we'll
// accept less
alsa_out_dev);
}
- if ((config.no_mmap == 0) && (snd_pcm_hw_params_set_access(alsa_handle, alsa_params, SND_PCM_ACCESS_MMAP_INTERLEAVED) >= 0)) {
- if (output_method_signalled==0) {
- debug(1,"Output written using MMAP");
- output_method_signalled=1;
- }
+ if ((config.no_mmap == 0) &&
+ (snd_pcm_hw_params_set_access(alsa_handle, alsa_params, SND_PCM_ACCESS_MMAP_INTERLEAVED) >=
+ 0)) {
+ if (output_method_signalled == 0) {
+ debug(1, "Output written using MMAP");
+ output_method_signalled = 1;
+ }
access = SND_PCM_ACCESS_MMAP_INTERLEAVED;
alsa_pcm_write = snd_pcm_mmap_writei;
} else {
- if (output_method_signalled==0) {
- debug(1,"Output written with RW");
- output_method_signalled=1;
- }
+ if (output_method_signalled == 0) {
+ debug(1, "Output written with RW");
+ output_method_signalled = 1;
+ }
access = SND_PCM_ACCESS_RW_INTERLEAVED;
alsa_pcm_write = snd_pcm_writei;
}
ret = snd_pcm_hw_params_set_access(alsa_handle, alsa_params, access);
if (ret < 0) {
- die("audio_alsa: Access type not available for device \"%s\": %s",
- alsa_out_dev, snd_strerror(ret));
+ die("audio_alsa: Access type not available for device \"%s\": %s", alsa_out_dev,
+ snd_strerror(ret));
}
ret = snd_pcm_hw_params_set_format(alsa_handle, alsa_params, sample_format);
if (ret < 0) {
- die("audio_alsa: Sample format %d not available for device \"%s\": %s",
- sample_format, alsa_out_dev, snd_strerror(ret));
+ die("audio_alsa: Sample format %d not available for device \"%s\": %s", sample_format,
+ alsa_out_dev, snd_strerror(ret));
}
ret = snd_pcm_hw_params_set_channels(alsa_handle, alsa_params, 2);
if (ret < 0) {
- die("audio_alsa: Channels count (2) not available for device \"%s\": %s",
- alsa_out_dev, snd_strerror(ret));
+ die("audio_alsa: Channels count (2) not available for device \"%s\": %s", alsa_out_dev,
+ snd_strerror(ret));
}
- ret = snd_pcm_hw_params_set_rate_near(alsa_handle, alsa_params,
- &my_sample_rate, &dir);
+ ret = snd_pcm_hw_params_set_rate_near(alsa_handle, alsa_params, &my_sample_rate, &dir);
if (ret < 0) {
- die("audio_alsa: Rate %iHz not available for playback: %s",
- desired_sample_rate, snd_strerror(ret));
+ die("audio_alsa: Rate %iHz not available for playback: %s", desired_sample_rate,
+ snd_strerror(ret));
}
- if (set_period_size_request!=0) {
- debug(1,"Attempting to set the period size");
- ret = snd_pcm_hw_params_set_period_size_near(alsa_handle, alsa_params, &period_size_requested, &dir);
- if (ret < 0) {
- die("audio_alsa: cannot set period size of %lu: %s",
- period_size_requested, snd_strerror(ret));
- snd_pcm_uframes_t actual_period_size;
- snd_pcm_hw_params_get_period_size(alsa_params, &actual_period_size, &dir);
- if (actual_period_size!=period_size_requested)
- inform("Actual period size set to a different value than requested. Requested: %lu, actual setting: %lu",period_size_requested,actual_period_size);
- }
+ if (set_period_size_request != 0) {
+ debug(1, "Attempting to set the period size");
+ ret = snd_pcm_hw_params_set_period_size_near(alsa_handle, alsa_params, &period_size_requested,
+ &dir);
+ if (ret < 0) {
+ die("audio_alsa: cannot set period size of %lu: %s", period_size_requested,
+ snd_strerror(ret));
+ snd_pcm_uframes_t actual_period_size;
+ snd_pcm_hw_params_get_period_size(alsa_params, &actual_period_size, &dir);
+ if (actual_period_size != period_size_requested)
+ inform("Actual period size set to a different value than requested. Requested: %lu, actual "
+ "setting: %lu",
+ period_size_requested, actual_period_size);
+ }
}
- if (set_buffer_size_request!=0) {
- debug(1,"Attempting to set the buffer size to %lu",buffer_size_requested);
- ret = snd_pcm_hw_params_set_buffer_size_near(alsa_handle, alsa_params, &buffer_size_requested);
- if (ret < 0) {
- die("audio_alsa: cannot set buffer size of %lu: %s",
- buffer_size_requested, snd_strerror(ret));
- snd_pcm_uframes_t actual_buffer_size;
- snd_pcm_hw_params_get_buffer_size(alsa_params, &actual_buffer_size);
- if (actual_buffer_size!=buffer_size_requested)
- inform("Actual period size set to a different value than requested. Requested: %lu, actual setting: %lu",buffer_size,actual_buffer_size);
- }
+ if (set_buffer_size_request != 0) {
+ debug(1, "Attempting to set the buffer size to %lu", buffer_size_requested);
+ ret = snd_pcm_hw_params_set_buffer_size_near(alsa_handle, alsa_params, &buffer_size_requested);
+ if (ret < 0) {
+ die("audio_alsa: cannot set buffer size of %lu: %s", buffer_size_requested,
+ snd_strerror(ret));
+ snd_pcm_uframes_t actual_buffer_size;
+ snd_pcm_hw_params_get_buffer_size(alsa_params, &actual_buffer_size);
+ if (actual_buffer_size != buffer_size_requested)
+ inform("Actual period size set to a different value than requested. Requested: %lu, actual "
+ "setting: %lu",
+ buffer_size, actual_buffer_size);
+ }
}
ret = snd_pcm_hw_params(alsa_handle, alsa_params);
if (ret < 0) {
- die("audio_alsa: Unable to set hw parameters for device \"%s\": %s.",
- alsa_out_dev, snd_strerror(ret));
+ die("audio_alsa: Unable to set hw parameters for device \"%s\": %s.", alsa_out_dev,
+ snd_strerror(ret));
}
if (my_sample_rate != desired_sample_rate) {
ret = snd_pcm_hw_params_get_buffer_size(alsa_params, &actual_buffer_length);
if (ret < 0) {
- die("audio_alsa: Unable to get hw buffer length for device \"%s\": %s.",
- alsa_out_dev, snd_strerror(ret));
+ die("audio_alsa: Unable to get hw buffer length for device \"%s\": %s.", alsa_out_dev,
+ snd_strerror(ret));
}
- if (actual_buffer_length <
- config.audio_backend_buffer_desired_length + minimal_buffer_headroom) {
+ if (actual_buffer_length < config.audio_backend_buffer_desired_length + minimal_buffer_headroom) {
/*
// the dac buffer is too small, so let's try to set it
buffer_size =
buffer_size);
}
*/
- debug(1,"The alsa buffer is to small (%lu bytes) to accommodate the desired backend buffer length (%ld) you have chosen.",actual_buffer_length,config.audio_backend_buffer_desired_length);
+ debug(1, "The alsa buffer is to small (%lu bytes) to accommodate the desired backend buffer "
+ "length (%ld) you have chosen.",
+ actual_buffer_length, config.audio_backend_buffer_desired_length);
}
-
- if (alsa_characteristics_already_listed==0) {
- alsa_characteristics_already_listed=1;
- int log_level = 2; // the level at which debug information should be output
- int rc;
- snd_pcm_access_t access_type;
- snd_pcm_format_t format_type;
- snd_pcm_subformat_t subformat_type;
- unsigned int val, val2;
- unsigned int uval, uval2;
- int sval;
- int dir;
- snd_pcm_uframes_t frames;
-
- debug(log_level,"PCM handle name = '%s'",
- snd_pcm_name(alsa_handle));
-
-// ret = snd_pcm_hw_params_any(alsa_handle, alsa_params);
-// if (ret < 0) {
-// die("audio_alsa: Cannpot get configuration for device \"%s\": no configurations "
-// "available",
-// alsa_out_dev);
-// }
-
- debug(log_level,"alsa device parameters:");
-
- snd_pcm_hw_params_get_access(alsa_params,&access_type);
- debug(log_level," access type = %s", snd_pcm_access_name(access_type));
-
- snd_pcm_hw_params_get_format(alsa_params,&format_type);
- debug(log_level," format = '%s' (%s)",snd_pcm_format_name(format_type),snd_pcm_format_description(format_type));
-
- snd_pcm_hw_params_get_subformat(alsa_params,&subformat_type);
- debug(log_level," subformat = '%s' (%s)",snd_pcm_subformat_name(subformat_type),snd_pcm_subformat_description(subformat_type));
-
- snd_pcm_hw_params_get_channels(alsa_params, &uval);
- debug(log_level," number of channels = %u", uval);
-
- sval = snd_pcm_hw_params_get_sbits(alsa_params);
- debug(log_level," number of significant bits = %d", sval);
-
- snd_pcm_hw_params_get_rate(alsa_params, &uval, &dir);
- switch (dir) {
- case -1:
- debug(log_level," rate = %u frames per second (<).", uval);
- break;
- case 0:
- debug(log_level," rate = %u frames per second (precisely).", uval);
- break;
- case 1:
- debug(log_level," rate = %u frames per second (>).", uval);
- break;
- }
-
- if (snd_pcm_hw_params_get_rate_numden(alsa_params,&uval, &uval2)==0)
- debug(log_level," precise (rational) rate = %.3f frames per second (i.e. %u/%u).", uval, uval2, ((double)uval)/uval2);
- else
- debug(log_level," precise (rational) rate information unavailable.");
-
- snd_pcm_hw_params_get_period_time(alsa_params,&uval, &dir);
- switch (dir) {
- case -1:
- debug(log_level," period_time = %u us (<).", uval);
- break;
- case 0:
- debug(log_level," period_time = %u us (precisely).", uval);
- break;
- case 1:
- debug(log_level," period_time = %u us (>).", uval);
- break;
- }
-
- snd_pcm_hw_params_get_period_size(alsa_params,&frames, &dir);
- switch (dir) {
- case -1:
- debug(log_level," period_size = %lu frames (<).", frames);
- break;
- case 0:
- debug(log_level," period_size = %lu frames (precisely).", frames);
- break;
- case 1:
- debug(log_level," period_size = %lu frames (>).", frames);
- break;
- }
-
- snd_pcm_hw_params_get_buffer_time(alsa_params,&uval, &dir);
- switch (dir) {
- case -1:
- debug(log_level," buffer_time = %u us (<).", uval);
- break;
- case 0:
- debug(log_level," buffer_time = %u us (precisely).", uval);
- break;
- case 1:
- debug(log_level," buffer_time = %u us (>).", uval);
- break;
- }
-
- snd_pcm_hw_params_get_buffer_size(alsa_params,&frames);
- switch (dir) {
- case -1:
- debug(log_level," buffer_size = %lu frames (<).", frames);
- break;
- case 0:
- debug(log_level," buffer_size = %lu frames (precisely).", frames);
- break;
- case 1:
- debug(log_level," buffer_size = %lu frames (>).", frames);
- break;
- }
-
- snd_pcm_hw_params_get_periods(alsa_params, &uval, &dir);
- switch (dir) {
- case -1:
- debug(log_level," periods_per_buffer = %u (<).", uval);
- break;
- case 0:
- debug(log_level," periods_per_buffer = %u (precisely).", uval);
- break;
- case 1:
- debug(log_level," periods_per_buffer = %u (>).", uval);
- break;
- }
- }
-
+
+ if (alsa_characteristics_already_listed == 0) {
+ alsa_characteristics_already_listed = 1;
+ int log_level = 2; // the level at which debug information should be output
+ int rc;
+ snd_pcm_access_t access_type;
+ snd_pcm_format_t format_type;
+ snd_pcm_subformat_t subformat_type;
+ unsigned int val, val2;
+ unsigned int uval, uval2;
+ int sval;
+ int dir;
+ snd_pcm_uframes_t frames;
+
+ debug(log_level, "PCM handle name = '%s'", snd_pcm_name(alsa_handle));
+
+ // ret = snd_pcm_hw_params_any(alsa_handle, alsa_params);
+ // if (ret < 0) {
+ // die("audio_alsa: Cannpot get configuration for device \"%s\": no
+ // configurations
+ //"
+ // "available",
+ // alsa_out_dev);
+ // }
+
+ debug(log_level, "alsa device parameters:");
+
+ snd_pcm_hw_params_get_access(alsa_params, &access_type);
+ debug(log_level, " access type = %s", snd_pcm_access_name(access_type));
+
+ snd_pcm_hw_params_get_format(alsa_params, &format_type);
+ debug(log_level, " format = '%s' (%s)", snd_pcm_format_name(format_type),
+ snd_pcm_format_description(format_type));
+
+ snd_pcm_hw_params_get_subformat(alsa_params, &subformat_type);
+ debug(log_level, " subformat = '%s' (%s)", snd_pcm_subformat_name(subformat_type),
+ snd_pcm_subformat_description(subformat_type));
+
+ snd_pcm_hw_params_get_channels(alsa_params, &uval);
+ debug(log_level, " number of channels = %u", uval);
+
+ sval = snd_pcm_hw_params_get_sbits(alsa_params);
+ debug(log_level, " number of significant bits = %d", sval);
+
+ snd_pcm_hw_params_get_rate(alsa_params, &uval, &dir);
+ switch (dir) {
+ case -1:
+ debug(log_level, " rate = %u frames per second (<).", uval);
+ break;
+ case 0:
+ debug(log_level, " rate = %u frames per second (precisely).", uval);
+ break;
+ case 1:
+ debug(log_level, " rate = %u frames per second (>).", uval);
+ break;
+ }
+
+ if (snd_pcm_hw_params_get_rate_numden(alsa_params, &uval, &uval2) == 0)
+ debug(log_level, " precise (rational) rate = %.3f frames per second (i.e. %u/%u).", uval,
+ uval2, ((double)uval) / uval2);
+ else
+ debug(log_level, " precise (rational) rate information unavailable.");
+
+ snd_pcm_hw_params_get_period_time(alsa_params, &uval, &dir);
+ switch (dir) {
+ case -1:
+ debug(log_level, " period_time = %u us (<).", uval);
+ break;
+ case 0:
+ debug(log_level, " period_time = %u us (precisely).", uval);
+ break;
+ case 1:
+ debug(log_level, " period_time = %u us (>).", uval);
+ break;
+ }
+
+ snd_pcm_hw_params_get_period_size(alsa_params, &frames, &dir);
+ switch (dir) {
+ case -1:
+ debug(log_level, " period_size = %lu frames (<).", frames);
+ break;
+ case 0:
+ debug(log_level, " period_size = %lu frames (precisely).", frames);
+ break;
+ case 1:
+ debug(log_level, " period_size = %lu frames (>).", frames);
+ break;
+ }
+
+ snd_pcm_hw_params_get_buffer_time(alsa_params, &uval, &dir);
+ switch (dir) {
+ case -1:
+ debug(log_level, " buffer_time = %u us (<).", uval);
+ break;
+ case 0:
+ debug(log_level, " buffer_time = %u us (precisely).", uval);
+ break;
+ case 1:
+ debug(log_level, " buffer_time = %u us (>).", uval);
+ break;
+ }
+
+ snd_pcm_hw_params_get_buffer_size(alsa_params, &frames);
+ switch (dir) {
+ case -1:
+ debug(log_level, " buffer_size = %lu frames (<).", frames);
+ break;
+ case 0:
+ debug(log_level, " buffer_size = %lu frames (precisely).", frames);
+ break;
+ case 1:
+ debug(log_level, " buffer_size = %lu frames (>).", frames);
+ break;
+ }
+
+ snd_pcm_hw_params_get_periods(alsa_params, &uval, &dir);
+ switch (dir) {
+ case -1:
+ debug(log_level, " periods_per_buffer = %u (<).", uval);
+ break;
+ case 0:
+ debug(log_level, " periods_per_buffer = %u (precisely).", uval);
+ break;
+ case 1:
+ debug(log_level, " periods_per_buffer = %u (>).", uval);
+ break;
+ }
+ }
+
return (0);
}
static void start(int i_sample_rate, int i_sample_format) {
// debug(2,"audio_alsa start called.");
- if (i_sample_rate==0)
+ if (i_sample_rate == 0)
desired_sample_rate = 44100; // default
else
desired_sample_rate = i_sample_rate; // must be a variable
-
- if (i_sample_format==0)
- sample_format = SND_PCM_FORMAT_S16_LE; // default
+
+ if (i_sample_format == 0)
+ sample_format = SND_PCM_FORMAT_S16_LE; // default
else
sample_format = i_sample_format;
-
}
-int delay(long* the_delay) {
- //snd_pcm_sframes_t is a signed long -- hence the return of a "long"
- int reply;
+int delay(long *the_delay) {
+ // snd_pcm_sframes_t is a signed long -- hence the return of a "long"
+ int reply;
// debug(3,"audio_alsa delay called.");
if (alsa_handle == NULL) {
return -ENODEV;
reply = 0; // no error
} else {
if (snd_pcm_state(alsa_handle) == SND_PCM_STATE_XRUN) {
- *the_delay = 0;
- reply = 0; // no error
+ *the_delay = 0;
+ reply = 0; // no error
} else {
reply = -EIO;
- debug(1, "Error -- ALSA delay(): bad state: %d.",
- snd_pcm_state(alsa_handle));
+ debug(1, "Error -- ALSA delay(): bad state: %d.", snd_pcm_state(alsa_handle));
}
if ((derr = snd_pcm_prepare(alsa_handle))) {
ignore = snd_pcm_recover(alsa_handle, derr, 1);
}
pthread_mutex_unlock(&alsa_mutex);
// here, occasionally pretend there's a problem with pcm_get_delay()
- //if ((random() % 100000) < 3) // keep it pretty rare
- // reply = -EPERM; // pretend something bad has happened
+ // if ((random() % 100000) < 3) // keep it pretty rare
+ // reply = -EPERM; // pretend something bad has happened
return reply;
}
}
pthread_mutex_lock(&alsa_mutex);
ret = open_alsa_device();
if (hardware_mixer)
- open_mixer();
+ open_mixer();
pthread_mutex_unlock(&alsa_mutex);
if ((hardware_mixer) && (ret == 0) && (audio_alsa.volume))
audio_alsa.volume(set_volume);
int err, ignore;
if ((snd_pcm_state(alsa_handle) == SND_PCM_STATE_PREPARED) ||
(snd_pcm_state(alsa_handle) == SND_PCM_STATE_RUNNING)) {
- if (buf==NULL)
- debug(1,"NULL buffer passed to pcm_writei -- skipping it");
- if (samples==0)
- debug(1,"empty buffer being passed to pcm_writei -- skipping it");
- if ((samples!=0) && (buf!=NULL)) {
- err = alsa_pcm_write(alsa_handle, (char *)buf, samples);
- if (err < 0) {
- debug(1, "Error %d writing %d samples in play(): \"%s\".", err, samples,
- snd_strerror(err));
- ignore = snd_pcm_recover(alsa_handle, err, 1);
- }
+ if (buf == NULL)
+ debug(1, "NULL buffer passed to pcm_writei -- skipping it");
+ if (samples == 0)
+ debug(1, "empty buffer being passed to pcm_writei -- skipping it");
+ if ((samples != 0) && (buf != NULL)) {
+ err = alsa_pcm_write(alsa_handle, (char *)buf, samples);
+ if (err < 0) {
+ debug(1, "Error %d writing %d samples in play(): \"%s\".", err, samples,
+ snd_strerror(err));
+ ignore = snd_pcm_recover(alsa_handle, err, 1);
+ }
}
} else {
debug(1, "Error -- ALSA device in incorrect state (%d) for play.",
*/
if (!((snd_pcm_state(alsa_handle) == SND_PCM_STATE_PREPARED) ||
(snd_pcm_state(alsa_handle) == SND_PCM_STATE_RUNNING)))
- debug(1, "Flush returning unexpected state -- %d.",
- snd_pcm_state(alsa_handle));
+ debug(1, "Flush returning unexpected state -- %d.", snd_pcm_state(alsa_handle));
// flush also closes the device
snd_pcm_close(alsa_handle);
static void volume(double vol) {
pthread_mutex_lock(&alsa_mutex);
- debug(2, "Setting volume db to %f.", vol);
+ debug(2, "Setting volume db to %f.", vol);
set_volume = vol;
if (hardware_mixer && alsa_mix_handle) {
if (has_softvol) {
snd_ctl_elem_value_t *value;
long raw;
- if (snd_ctl_convert_from_dB(ctl, elem_id, (long) vol, &raw, 0) < 0)
- debug(1, "Failed converting dB gain to raw volume value for the "
- "software volume control.");
+ if (snd_ctl_convert_from_dB(ctl, elem_id, (long)vol, &raw, 0) < 0)
+ debug(1, "Failed converting dB gain to raw volume value for the "
+ "software volume control.");
snd_ctl_elem_value_alloca(&value);
snd_ctl_elem_value_set_id(value, elem_id);
snd_ctl_elem_value_set_integer(value, 0, raw);
snd_ctl_elem_value_set_integer(value, 1, raw);
if (snd_ctl_elem_write(ctl, value) < 0)
- debug(1, "Failed to set playback dB volume for the software volume "
- "control.");
+ debug(1, "Failed to set playback dB volume for the software volume "
+ "control.");
}
} else {
if (snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol, 0) != 0) {
if (hardware_mixer && alsa_mix_handle) {
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;
+ 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 (alsa_mix_handle) {
if (snd_mixer_selem_set_playback_volume_all(alsa_mix_elem, int_vol) != 0)
* OTHER DEALINGS IN THE SOFTWARE.
*/
+#include "audio.h"
+#include "common.h"
+#include <ao/ao.h>
+#include <memory.h>
#include <stdio.h>
#include <unistd.h>
-#include <memory.h>
-#include <ao/ao.h>
-#include "common.h"
-#include "audio.h"
ao_device *dev = NULL;
config.audio_backend_buffer_desired_length = 1.0;
config.audio_backend_latency_offset = 0;
-
+
// get settings from settings file first, allow them to be overridden by command line options
if (config.cfg != NULL) {
/* Get the desired buffer size setting. */
- if (config_lookup_float(config.cfg,
- "ao.audio_backend_buffer_desired_length", &dvalue)) {
+ if (config_lookup_float(config.cfg, "ao.audio_backend_buffer_desired_length", &dvalue)) {
if ((dvalue < 0) || (value > 1.5))
die("Invalid ao audio backend buffer desired length \"%f\". It "
"should be between 0 and "
}
/* Get the latency offset. */
- if (config_lookup_float(config.cfg, "ao.audio_backend_latency_offset",
- &dvalue)) {
+ if (config_lookup_float(config.cfg, "ao.audio_backend_latency_offset", &dvalue)) {
if ((dvalue < -1.0) || (value > 1.5))
die("Invalid ao audio backend buffer latency offset \"%f\". It "
"should be between -1.0 and +1.5, default is 0 seconds",
* OTHER DEALINGS IN THE SOFTWARE.
*/
+#include "audio.h"
+#include "common.h"
#include <stdio.h>
-#include <unistd.h>
#include <sys/time.h>
-#include "common.h"
-#include "audio.h"
+#include <unistd.h>
int Fs;
long long starttime, samples_played;
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <stdio.h>
-#include <unistd.h>
+#include "audio.h"
+#include "common.h"
+#include <errno.h>
#include <fcntl.h>
#include <memory.h>
+#include <stdio.h>
#include <stdlib.h>
-#include <errno.h>
-#include <sys/types.h>
#include <sys/stat.h>
-#include "common.h"
-#include "audio.h"
+#include <sys/types.h>
+#include <unistd.h>
static int fd = -1;
static void play(short buf[], int samples) {
// if the file is not open, try to open it.
if (fd == -1) {
- fd = open(pipename, O_WRONLY | O_NONBLOCK);
+ fd = open(pipename, O_WRONLY | O_NONBLOCK);
}
// if it's got a reader, write to it.
if (fd != -1) {
}
static void stop(void) {
-// Don't close the pipe just because a play session has stopped.
-// if (fd > 0)
-// close(fd);
+ // Don't close the pipe just because a play session has stopped.
+ // if (fd > 0)
+ // close(fd);
}
static int init(int argc, char **argv) {
if (config_lookup_string(config.cfg, "pipe.name", &str)) {
pipename = (char *)str;
}
-
+
if ((pipename) && (strcasecmp(pipename, "STDOUT") == 0))
die("Can't use \"pipe\" backend for STDOUT. Use the \"stdout\" backend instead.");
/* Get the desired buffer size setting. */
- if (config_lookup_float(config.cfg,
- "pipe.audio_backend_buffer_desired_length", &dvalue)) {
+ if (config_lookup_float(config.cfg, "pipe.audio_backend_buffer_desired_length", &dvalue)) {
if ((dvalue < 0) || (value > 1.5))
die("Invalid pipe audio backend buffer desired length \"%f\". It "
"should be between 0 and "
}
/* Get the latency offset. */
- if (config_lookup_float(config.cfg, "pipe.audio_backend_latency_offset",
- &dvalue)) {
+ if (config_lookup_float(config.cfg, "pipe.audio_backend_latency_offset", &dvalue)) {
if ((dvalue < -1.0) || (value > 1.5))
die("Invalid pipe audio backend buffer latency offset \"%f\". It "
"should be between -1.0 and +1.5, default is 0 seconds",
if (argc == 1)
pipename = strdup(argv[0]);
-
-
+
// here, create the pipe
if (mkfifo(pipename, 0644) && errno != EEXIST)
die("Could not create output pipe \"%s\"", pipename);
}
static void deinit(void) {
- if (fd > 0)
+ if (fd > 0)
close(fd);
}
-static void help(void) {
- printf(" pipe takes 1 argument: the name of the FIFO to write to.\n");
-}
+static void help(void) { printf(" pipe takes 1 argument: the name of the FIFO to write to.\n"); }
audio_output audio_pipe = {.name = "pipe",
.help = &help,
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <stdio.h>
-#include <unistd.h>
+#include "audio.h"
+#include "common.h"
#include <memory.h>
-#include <pulse/simple.h>
-#include <pulse/error.h>
#include <pulse/def.h>
-#include "common.h"
-#include "audio.h"
+#include <pulse/error.h>
+#include <pulse/simple.h>
+#include <stdio.h>
+#include <unistd.h>
static pa_simple *pa_dev = NULL;
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "audio.h"
+#include <sndio.h>
#include <stdio.h>
#include <unistd.h>
-#include <sndio.h>
-#include "audio.h"
static struct sio_hdl *sio;
static struct sio_par par;
.play = &play,
.volume = &volume,
.parameters = NULL,
- .mute= NULL};
+ .mute = NULL};
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <stdio.h>
-#include <unistd.h>
+#include "audio.h"
+#include "common.h"
+#include <errno.h>
#include <fcntl.h>
#include <memory.h>
+#include <stdio.h>
#include <stdlib.h>
-#include <errno.h>
-#include "common.h"
-#include "audio.h"
+#include <unistd.h>
static int fd = -1;
-static void start(int sample_rate, int sample_format) {
- fd = STDOUT_FILENO;
-}
+static void start(int sample_rate, int sample_format) { fd = STDOUT_FILENO; }
-static void play(short buf[], int samples) {
- int ignore = write(fd, buf, samples * 4);
-}
+static void play(short buf[], int samples) { int ignore = write(fd, buf, samples * 4); }
static void stop(void) {
// don't close stdout
if (config.cfg != NULL) {
/* Get the desired buffer size setting. */
- if (config_lookup_float(config.cfg,
- "stdout.audio_backend_buffer_desired_length", &dvalue)) {
+ if (config_lookup_float(config.cfg, "stdout.audio_backend_buffer_desired_length", &dvalue)) {
if ((dvalue < 0) || (dvalue > 1.5))
die("Invalid stdout audio backend buffer desired length \"%f\". It "
"should be between 0 and "
}
/* Get the latency offset. */
- if (config_lookup_float(config.cfg, "stdout.audio_backend_latency_offset",
- &dvalue)) {
+ if (config_lookup_float(config.cfg, "stdout.audio_backend_latency_offset", &dvalue)) {
if ((dvalue < -1.0) || (value > 1.5))
die("Invalid stdout audio backend buffer latency offset \"%f\". It "
"should be between -1.0 and +1.5, default is 0 seconds",
// don't close stdout
}
-static void help(void) {
- printf(" stdout takes no arguments\n");
-}
+static void help(void) { printf(" stdout takes no arguments\n"); }
audio_output audio_stdout = {.name = "stdout",
- .help = &help,
- .init = &init,
- .deinit = &deinit,
- .start = &start,
- .stop = &stop,
- .flush = NULL,
- .delay = NULL,
- .play = &play,
- .volume = NULL,
- .parameters = NULL,
- .mute = NULL};
+ .help = &help,
+ .init = &init,
+ .deinit = &deinit,
+ .start = &start,
+ .stop = &stop,
+ .flush = NULL,
+ .delay = NULL,
+ .play = &play,
+ .volume = NULL,
+ .parameters = NULL,
+ .mute = NULL};
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <memory.h>
#include <errno.h>
-#include <time.h>
-#include <unistd.h>
-#include <popt.h>
+#include <memory.h>
#include <poll.h>
+#include <popt.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
-#include <assert.h>
#include "common.h"
+#include <assert.h>
#ifdef COMPILE_FOR_OSX
#include <CoreServices/CoreServices.h>
#endif
#ifdef HAVE_LIBSSL
-#include <openssl/rsa.h>
-#include <openssl/pem.h>
-#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+#include <openssl/rsa.h>
#endif
#ifdef HAVE_LIBPOLARSSL
-#include <polarssl/version.h>
+#include "polarssl/ctr_drbg.h"
+#include "polarssl/entropy.h"
#include <polarssl/base64.h>
-#include <polarssl/x509.h>
#include <polarssl/md.h>
-#include "polarssl/entropy.h"
-#include "polarssl/ctr_drbg.h"
+#include <polarssl/version.h>
+#include <polarssl/x509.h>
#if POLARSSL_VERSION_NUMBER >= 0x01030000
#include "polarssl/compat-1.2.h"
struct timespec tn;
// can't use CLOCK_MONOTONIC_RAW as it's not implemented in OpenWrt
clock_gettime(CLOCK_MONOTONIC, &tn);
- time_now_fp = ((uint64_t)tn.tv_sec << 32) + ((uint64_t)tn.tv_nsec << 32) / 1000000000; // types okay
+ time_now_fp =
+ ((uint64_t)tn.tv_sec << 32) + ((uint64_t)tn.tv_nsec << 32) / 1000000000; // types okay
#endif
#ifdef COMPILE_FOR_OSX
uint64_t time_now_mach;
}
ssize_t non_blocking_write(int fd, const void *buf, size_t count) {
- void *ibuf = (void *)buf;
- size_t bytes_remaining = count;
- int rc = 0;
+ void *ibuf = (void *)buf;
+ size_t bytes_remaining = count;
+ int rc = 0;
struct pollfd ufds[1];
- while ((bytes_remaining>0) && (rc==0)) {
- // check that we can do some writing
- ufds[0].fd = fd;
+ while ((bytes_remaining > 0) && (rc == 0)) {
+ // check that we can do some writing
+ ufds[0].fd = fd;
ufds[0].events = POLLOUT;
rc = poll(ufds, 1, 5000);
if (rc < 0) {
} else if (rc == 0) {
// warn("non-blocking write timeout waiting for pipe to become ready for writing");
rc = -2;
- } else { //rc > 0, implying it might be ready
- size_t bytes_written = write(fd,ibuf,bytes_remaining);
- if (bytes_written==-1) {
- // debug(1,"Error %d in non_blocking_write: \"%s\".",errno,strerror(errno));
- rc = -1;
- } else {
- ibuf += bytes_written;
- bytes_remaining -= bytes_written;
- }
+ } else { // rc > 0, implying it might be ready
+ size_t bytes_written = write(fd, ibuf, bytes_remaining);
+ if (bytes_written == -1) {
+ // debug(1,"Error %d in non_blocking_write: \"%s\".",errno,strerror(errno));
+ rc = -1;
+ } else {
+ ibuf += bytes_written;
+ bytes_remaining -= bytes_written;
+ }
}
- }
- if (rc==0)
- return count-bytes_remaining; // this is just to mimic a normal write/3.
- else
- return rc;
+ }
+ if (rc == 0)
+ return count - bytes_remaining; // this is just to mimic a normal write/3.
+ else
+ return rc;
// return write(fd,buf,count);
}
-/* from http://coding.debuntu.org/c-implementing-str_replace-replace-all-occurrences-substring#comment-722 */
+/* from
+ * http://coding.debuntu.org/c-implementing-str_replace-replace-all-occurrences-substring#comment-722
+ */
-char *str_replace ( const char *string, const char *substr, const char *replacement ){
+char *str_replace(const char *string, const char *substr, const char *replacement) {
char *tok = NULL;
char *newstr = NULL;
char *oldstr = NULL;
char *head = NULL;
-
+
/* if either substr or replacement is NULL, duplicate string a let caller handle it */
- if ( substr == NULL || replacement == NULL ) return strdup (string);
- newstr = strdup (string);
+ if (substr == NULL || replacement == NULL)
+ return strdup(string);
+ newstr = strdup(string);
head = newstr;
- while ( (tok = strstr ( head, substr ))){
+ while ((tok = strstr(head, substr))) {
oldstr = newstr;
- newstr = malloc ( strlen ( oldstr ) - strlen ( substr ) + strlen ( replacement ) + 1 );
+ newstr = malloc(strlen(oldstr) - strlen(substr) + strlen(replacement) + 1);
/*failed to alloc mem, free old string and return NULL */
- if ( newstr == NULL ){
- free (oldstr);
+ if (newstr == NULL) {
+ free(oldstr);
return NULL;
}
- memcpy ( newstr, oldstr, tok - oldstr );
- memcpy ( newstr + (tok - oldstr), replacement, strlen ( replacement ) );
- memcpy ( newstr + (tok - oldstr) + strlen( replacement ), tok + strlen ( substr ), strlen ( oldstr ) - strlen ( substr ) - ( tok - oldstr ) );
- memset ( newstr + strlen ( oldstr ) - strlen ( substr ) + strlen ( replacement ) , 0, 1 );
+ memcpy(newstr, oldstr, tok - oldstr);
+ memcpy(newstr + (tok - oldstr), replacement, strlen(replacement));
+ memcpy(newstr + (tok - oldstr) + strlen(replacement), tok + strlen(substr),
+ strlen(oldstr) - strlen(substr) - (tok - oldstr));
+ memset(newstr + strlen(oldstr) - strlen(substr) + strlen(replacement), 0, 1);
/* move back head right after the last replacement */
- head = newstr + (tok - oldstr) + strlen( replacement );
- free (oldstr);
+ head = newstr + (tok - oldstr) + strlen(replacement);
+ free(oldstr);
}
return newstr;
}
/* from http://burtleburtle.net/bob/rand/smallprng.html */
typedef uint64_t u8;
-typedef struct ranctx { uint64_t a; uint64_t b; uint64_t c; uint64_t d; } ranctx;
+typedef struct ranctx {
+ uint64_t a;
+ uint64_t b;
+ uint64_t c;
+ uint64_t d;
+} ranctx;
static struct ranctx rx;
-#define rot(x,k) (((x)<<(k))|((x)>>(64-(k))))
-uint64_t ranval( ranctx *x ) {
- uint64_t e = x->a - rot(x->b, 7);
- x->a = x->b ^ rot(x->c, 13);
- x->b = x->c + rot(x->d, 37);
- x->c = x->d + e;
- x->d = e + x->a;
- return x->d;
+#define rot(x, k) (((x) << (k)) | ((x) >> (64 - (k))))
+uint64_t ranval(ranctx *x) {
+ uint64_t e = x->a - rot(x->b, 7);
+ x->a = x->b ^ rot(x->c, 13);
+ x->b = x->c + rot(x->d, 37);
+ x->c = x->d + e;
+ x->d = e + x->a;
+ return x->d;
}
-void raninit( ranctx *x, uint64_t seed ) {
- uint64_t i;
- x->a = 0xf1ea5eed, x->b = x->c = x->d = seed;
- for (i=0; i<20; ++i) {
- (void)ranval(x);
- }
+void raninit(ranctx *x, uint64_t seed) {
+ uint64_t i;
+ x->a = 0xf1ea5eed, x->b = x->c = x->d = seed;
+ for (i = 0; i < 20; ++i) {
+ (void)ranval(x);
+ }
}
-void r64init(uint64_t seed) {
- raninit(&rx,seed);
-}
+void r64init(uint64_t seed) { raninit(&rx, seed); }
-uint64_t r64u() {
- return(ranval(&rx));
-}
+uint64_t r64u() { return (ranval(&rx)); }
-int64_t r64i() {
- return(ranval(&rx)>>1);
-}
+int64_t r64i() { return (ranval(&rx) >> 1); }
#ifndef _COMMON_H
#define _COMMON_H
+#include <libconfig.h>
#include <stdint.h>
#include <sys/socket.h>
-#include <libconfig.h>
-#include "config.h"
#include "audio.h"
+#include "config.h"
#include "mdns.h"
#if defined(__APPLE__) && defined(__MACH__)
// the following enum must _exactly match the snd_pcm_format_t definition in the alsa pcm.h file.
-enum sps_format_t {
- SPS_FORMAT_UNKNOWN = -1, SPS_FORMAT_S8 = 0, SPS_FORMAT_U8, SPS_FORMAT_S16_LE,
- SPS_FORMAT_S16_BE, SPS_FORMAT_U16_LE, SPS_FORMAT_U16_BE, SPS_FORMAT_S24_LE,
- SPS_FORMAT_S24_BE, SPS_FORMAT_U24_LE, SPS_FORMAT_U24_BE, SPS_FORMAT_S32_LE,
- SPS_FORMAT_S32_BE, SPS_FORMAT_U32_LE, SPS_FORMAT_U32_BE, SPS_FORMAT_FLOAT_LE,
- SPS_FORMAT_FLOAT_BE, SPS_FORMAT_FLOAT64_LE, SPS_FORMAT_FLOAT64_BE, SPS_FORMAT_IEC958_SUBFRAME_LE,
- SPS_FORMAT_IEC958_SUBFRAME_BE, SPS_FORMAT_MU_LAW, SPS_FORMAT_A_LAW, SPS_FORMAT_IMA_ADPCM,
- SPS_FORMAT_MPEG, SPS_FORMAT_GSM, SPS_FORMAT_SPECIAL = 31, SPS_FORMAT_S24_3LE = 32,
- SPS_FORMAT_S24_3BE, SPS_FORMAT_U24_3LE, SPS_FORMAT_U24_3BE, SPS_FORMAT_S20_3LE,
- SPS_FORMAT_S20_3BE, SPS_FORMAT_U20_3LE, SPS_FORMAT_U20_3BE, SPS_FORMAT_S18_3LE,
- SPS_FORMAT_S18_3BE, SPS_FORMAT_U18_3LE, SPS_FORMAT_U18_3BE, SPS_FORMAT_G723_24,
- SPS_FORMAT_G723_24_1B, SPS_FORMAT_G723_40, SPS_FORMAT_G723_40_1B, SPS_FORMAT_DSD_U8,
- SPS_FORMAT_DSD_U16_LE, SPS_FORMAT_DSD_U32_LE, SPS_FORMAT_DSD_U16_BE, SPS_FORMAT_DSD_U32_BE,
- SPS_FORMAT_LAST = SPS_FORMAT_DSD_U32_BE, SPS_FORMAT_S16 = SPS_FORMAT_S16_LE, SPS_FORMAT_U16 = SPS_FORMAT_U16_LE, SPS_FORMAT_S24 = SPS_FORMAT_S24_LE,
- SPS_FORMAT_U24 = SPS_FORMAT_U24_LE, SPS_FORMAT_S32 = SPS_FORMAT_S32_LE, SPS_FORMAT_U32 = SPS_FORMAT_U32_LE, SPS_FORMAT_FLOAT = SPS_FORMAT_FLOAT_LE,
- SPS_FORMAT_FLOAT64 = SPS_FORMAT_FLOAT64_LE, SPS_FORMAT_IEC958_SUBFRAME = SPS_FORMAT_IEC958_SUBFRAME_LE
+enum sps_format_t {
+ SPS_FORMAT_UNKNOWN = -1,
+ SPS_FORMAT_S8 = 0,
+ SPS_FORMAT_U8,
+ SPS_FORMAT_S16_LE,
+ SPS_FORMAT_S16_BE,
+ SPS_FORMAT_U16_LE,
+ SPS_FORMAT_U16_BE,
+ SPS_FORMAT_S24_LE,
+ SPS_FORMAT_S24_BE,
+ SPS_FORMAT_U24_LE,
+ SPS_FORMAT_U24_BE,
+ SPS_FORMAT_S32_LE,
+ SPS_FORMAT_S32_BE,
+ SPS_FORMAT_U32_LE,
+ SPS_FORMAT_U32_BE,
+ SPS_FORMAT_FLOAT_LE,
+ SPS_FORMAT_FLOAT_BE,
+ SPS_FORMAT_FLOAT64_LE,
+ SPS_FORMAT_FLOAT64_BE,
+ SPS_FORMAT_IEC958_SUBFRAME_LE,
+ SPS_FORMAT_IEC958_SUBFRAME_BE,
+ SPS_FORMAT_MU_LAW,
+ SPS_FORMAT_A_LAW,
+ SPS_FORMAT_IMA_ADPCM,
+ SPS_FORMAT_MPEG,
+ SPS_FORMAT_GSM,
+ SPS_FORMAT_SPECIAL = 31,
+ SPS_FORMAT_S24_3LE = 32,
+ SPS_FORMAT_S24_3BE,
+ SPS_FORMAT_U24_3LE,
+ SPS_FORMAT_U24_3BE,
+ SPS_FORMAT_S20_3LE,
+ SPS_FORMAT_S20_3BE,
+ SPS_FORMAT_U20_3LE,
+ SPS_FORMAT_U20_3BE,
+ SPS_FORMAT_S18_3LE,
+ SPS_FORMAT_S18_3BE,
+ SPS_FORMAT_U18_3LE,
+ SPS_FORMAT_U18_3BE,
+ SPS_FORMAT_G723_24,
+ SPS_FORMAT_G723_24_1B,
+ SPS_FORMAT_G723_40,
+ SPS_FORMAT_G723_40_1B,
+ SPS_FORMAT_DSD_U8,
+ SPS_FORMAT_DSD_U16_LE,
+ SPS_FORMAT_DSD_U32_LE,
+ SPS_FORMAT_DSD_U16_BE,
+ SPS_FORMAT_DSD_U32_BE,
+ SPS_FORMAT_LAST = SPS_FORMAT_DSD_U32_BE,
+ SPS_FORMAT_S16 = SPS_FORMAT_S16_LE,
+ SPS_FORMAT_U16 = SPS_FORMAT_U16_LE,
+ SPS_FORMAT_S24 = SPS_FORMAT_S24_LE,
+ SPS_FORMAT_U24 = SPS_FORMAT_U24_LE,
+ SPS_FORMAT_S32 = SPS_FORMAT_S32_LE,
+ SPS_FORMAT_U32 = SPS_FORMAT_U32_LE,
+ SPS_FORMAT_FLOAT = SPS_FORMAT_FLOAT_LE,
+ SPS_FORMAT_FLOAT64 = SPS_FORMAT_FLOAT64_LE,
+ SPS_FORMAT_IEC958_SUBFRAME = SPS_FORMAT_IEC958_SUBFRAME_LE
} sps_format_t;
typedef struct {
config_t *cfg;
char *password;
- char *service_name; // the name for the shairport service, e.g. "Shairport Sync Version %v running on host %h"
+ char *service_name; // the name for the shairport service, e.g. "Shairport Sync Version %v running
+ // on host %h"
#ifdef CONFIG_METADATA
int metadata_enabled;
char *metadata_pipename;
int udp_port_base;
int udp_port_range;
int ignore_volume_control;
- int no_sync; // disable synchronisation, even if it's available
- int no_mmap; // disable use of mmap-based output, even if it's available
- double resyncthreshold; // if it get's out of whack my more than this number of seconds, resync. Zero means never
+ int no_sync; // disable synchronisation, even if it's available
+ int no_mmap; // disable use of mmap-based output, even if it's available
+ double resyncthreshold; // if it get's out of whack my more than this number of seconds, resync.
+ // Zero means never
// resync.
int allow_session_interruption;
int timeout; // while in play mode, exit if no packets of audio come in for more than this number
int64_t latency;
int64_t userSuppliedLatency; // overrides all other latencies -- use with caution
int64_t iTunesLatency; // supplied with --iTunesLatency option
- int64_t AirPlayLatency; // supplied with --AirPlayLatency option
- int64_t ForkedDaapdLatency; // supplied with --ForkedDaapdLatency option
+ int64_t AirPlayLatency; // supplied with --AirPlayLatency option
+ int64_t ForkedDaapdLatency; // supplied with --ForkedDaapdLatency option
int daemonise;
- int statistics_requested,use_negotiated_latencies;
+ int statistics_requested, use_negotiated_latencies;
enum playback_mode_type playback_mode;
char *cmd_start, *cmd_stop;
int cmd_blocking;
double tolerance; // allow this much drift before attempting to correct it
enum stuffing_type packet_stuffing;
int decoders_supported;
- int use_apple_decoder; // set to 1 if you want to use the apple decoder instead of the original by David Hammerton
+ int use_apple_decoder; // set to 1 if you want to use the apple decoder instead of the original by
+ // David Hammerton
char *pidfile;
// char *logfile;
// char *errfile;
char *configfile;
- char *regtype; // The regtype is the service type followed by the protocol, separated by a dot, by default “_raop._tcp.”.
+ char *regtype; // The regtype is the service type followed by the protocol, separated by a dot, by
+ // default “_raop._tcp.”.
double audio_backend_buffer_desired_length; // this will be the length in seconds of the
// audio backend buffer -- the DAC buffer for ALSA
- double audio_backend_latency_offset; // this will be the offset in seconds to compensate for any fixed latency there might be in the audio path
- uint32_t volume_range_db; // the range, in dB, from max dB to min dB. Zero means use the mixer's native range.
+ double audio_backend_latency_offset; // this will be the offset in seconds to compensate for any
+ // fixed latency there might be in the audio path
+ uint32_t volume_range_db; // the range, in dB, from max dB to min dB. Zero means use the mixer's
+ // native range.
enum sps_format_t output_format;
int output_rate;
} shairport_cfg;
ssize_t non_blocking_write(int fd, const void *buf, size_t count); // used in a few places
-/* from http://coding.debuntu.org/c-implementing-str_replace-replace-all-occurrences-substring#comment-722 */
-char *str_replace ( const char *string, const char *substr, const char *replacement );
-
+/* from
+ * http://coding.debuntu.org/c-implementing-str_replace-replace-all-occurrences-substring#comment-722
+ */
+char *str_replace(const char *string, const char *substr, const char *replacement);
// based on http://burtleburtle.net/bob/rand/smallprng.html
uint64_t r64u();
int64_t r64i();
-
int debuglev;
void die(char *format, ...);
void warn(char *format, ...);
* OTHER DEALINGS IN THE SOFTWARE.
*/
+#include "mdns.h"
+#include "common.h"
+#include "config.h"
#include <memory.h>
-#include <string.h>
#include <stdio.h>
#include <stdlib.h>
-#include "config.h"
-#include "common.h"
-#include "mdns.h"
+#include <string.h>
#ifdef CONFIG_AVAHI
extern mdns_backend mdns_avahi;
static mdns_backend *mdns_backends[] = {
#ifdef CONFIG_AVAHI
- &mdns_avahi, &mdns_external_avahi,
+ &mdns_avahi,
+ &mdns_external_avahi,
#endif
#ifdef CONFIG_HAVE_DNS_SD_H
- &mdns_dns_sd, &mdns_external_dns_sd,
+ &mdns_dns_sd,
+ &mdns_external_dns_sd,
#endif
#ifdef CONFIG_TINYSVCMDNS
&mdns_tinysvcmdns,
// "tp=UDP", "sm=false", "ek=1", "et=0,1", "cn=0,1", "ch=2", METADATA_EXPRESSION, "ss=16", \
// "sr=44100", "vn=3", "txtvers=1", config.password ? "pw=true" : "pw=false"
-#define MDNS_RECORD_WITH_METADATA \
- "sf=0x4", "fv=76400.10", "am=AirPort4,107", "vs=105.1", "tp=TCP,UDP", "vn=65537", \
- METADATA_EXPRESSION, "ss=16", "sr=44100", "da=true", "sv=false", "et=0,1", "ek=1", "cn=0,1", "ch=2", "txtvers=1", config.password ? "pw=true" : "pw=false"
+#define MDNS_RECORD_WITH_METADATA \
+ "sf=0x4", "fv=76400.10", "am=AirPort4,107", "vs=105.1", "tp=TCP,UDP", "vn=65537", \
+ METADATA_EXPRESSION, "ss=16", "sr=44100", "da=true", "sv=false", "et=0,1", "ek=1", "cn=0,1", \
+ "ch=2", "txtvers=1", config.password ? "pw=true" : "pw=false"
#endif
// "tp=UDP", "sm=false", "ek=1", "et=0,1", "cn=0,1", "ch=2", METADATA_EXPRESSION, "ss=16", "sr=44100", "vn=3", \
// "txtvers=1", config.password ? "pw=true" : "pw=false"
-#define MDNS_RECORD_WITHOUT_METADATA \
- "sf=0x4", "fv=76400.10", "am=AirPort4,107", "vs=105.1", "tp=TCP,UDP", "vn=65537", \
- "ss=16", "sr=44100", "da=true", "sv=false", "et=0,1", "ek=1", "cn=0,1", "ch=2", "txtvers=1", config.password ? "pw=true" : "pw=false"
+#define MDNS_RECORD_WITHOUT_METADATA \
+ "sf=0x4", "fv=76400.10", "am=AirPort4,107", "vs=105.1", "tp=TCP,UDP", "vn=65537", "ss=16", \
+ "sr=44100", "da=true", "sv=false", "et=0,1", "ek=1", "cn=0,1", "ch=2", "txtvers=1", \
+ config.password ? "pw=true" : "pw=false"
#endif // _MDNS_H
-
-
-
#include <stdlib.h>
-#include <string.h>
#include "common.h"
#include "mdns.h"
+#include <string.h>
#include <avahi-client/client.h>
#include <avahi-client/publish.h>
-#include <avahi-common/thread-watch.h>
-#include <avahi-common/malloc.h>
#include <avahi-common/error.h>
+#include <avahi-common/malloc.h>
+#include <avahi-common/thread-watch.h>
#include <avahi-client/lookup.h>
#include <avahi-common/alternative.h>
static char *name = NULL;
static int port = 0;
-static void resolve_callback(
- AvahiServiceResolver *r,
- AVAHI_GCC_UNUSED AvahiIfIndex interface,
- AVAHI_GCC_UNUSED AvahiProtocol protocol,
- AvahiResolverEvent event,
- const char *name,
- const char *type,
- const char *domain,
- const char *host_name,
- const AvahiAddress *address,
- uint16_t port,
- AvahiStringList *txt,
- AvahiLookupResultFlags flags,
- AVAHI_GCC_UNUSED void* userdata) {
-
- assert(r);
-
- /* Called whenever a service has been resolved successfully or timed out */
-
- switch (event) {
- case AVAHI_RESOLVER_FAILURE:
- debug(2, "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name, type, domain, avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r))));
- break;
-
- case AVAHI_RESOLVER_FOUND: {
- if (flags & AVAHI_LOOKUP_RESULT_OUR_OWN) {
- char a[AVAHI_ADDRESS_STR_MAX], *t;
-
-// debug(1, "avahi: service '%s' of type '%s' in domain '%s' added.", name, type, domain);
- avahi_address_snprint(a, sizeof(a), address);
- debug(1,"avahi: address advertised is: \"%s\".",a);
- /*
- t = avahi_string_list_to_string(txt);
- debug(1,
- "\t%s:%u (%s)\n"
- "\tTXT=%s\n"
- "\tcookie is %u\n"
- "\tis_local: %i\n"
- "\tour_own: %i\n"
- "\twide_area: %i\n"
- "\tmulticast: %i\n"
- "\tcached: %i\n",
- host_name, port, a,
- t,
- avahi_string_list_get_service_cookie(txt),
- !!(flags & AVAHI_LOOKUP_RESULT_LOCAL),
- !!(flags & AVAHI_LOOKUP_RESULT_OUR_OWN),
- !!(flags & AVAHI_LOOKUP_RESULT_WIDE_AREA),
- !!(flags & AVAHI_LOOKUP_RESULT_MULTICAST),
- !!(flags & AVAHI_LOOKUP_RESULT_CACHED));
-
- avahi_free(t);
- */
- }
- }
+static void resolve_callback(AvahiServiceResolver *r, AVAHI_GCC_UNUSED AvahiIfIndex interface,
+ AVAHI_GCC_UNUSED AvahiProtocol protocol, AvahiResolverEvent event,
+ const char *name, const char *type, const char *domain,
+ const char *host_name, const AvahiAddress *address, uint16_t port,
+ AvahiStringList *txt, AvahiLookupResultFlags flags,
+ AVAHI_GCC_UNUSED void *userdata) {
+
+ assert(r);
+
+ /* Called whenever a service has been resolved successfully or timed out */
+
+ switch (event) {
+ case AVAHI_RESOLVER_FAILURE:
+ debug(2, "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name,
+ type, domain, avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r))));
+ break;
+
+ case AVAHI_RESOLVER_FOUND: {
+ if (flags & AVAHI_LOOKUP_RESULT_OUR_OWN) {
+ char a[AVAHI_ADDRESS_STR_MAX], *t;
+
+ // debug(1, "avahi: service '%s' of type '%s' in domain '%s' added.", name, type,
+ // domain);
+ avahi_address_snprint(a, sizeof(a), address);
+ debug(1, "avahi: address advertised is: \"%s\".", a);
+ /*
+ t = avahi_string_list_to_string(txt);
+ debug(1,
+ "\t%s:%u (%s)\n"
+ "\tTXT=%s\n"
+ "\tcookie is %u\n"
+ "\tis_local: %i\n"
+ "\tour_own: %i\n"
+ "\twide_area: %i\n"
+ "\tmulticast: %i\n"
+ "\tcached: %i\n",
+ host_name, port, a,
+ t,
+ avahi_string_list_get_service_cookie(txt),
+ !!(flags & AVAHI_LOOKUP_RESULT_LOCAL),
+ !!(flags & AVAHI_LOOKUP_RESULT_OUR_OWN),
+ !!(flags & AVAHI_LOOKUP_RESULT_WIDE_AREA),
+ !!(flags & AVAHI_LOOKUP_RESULT_MULTICAST),
+ !!(flags & AVAHI_LOOKUP_RESULT_CACHED));
+
+ avahi_free(t);
+ */
}
+ }
+ }
- avahi_service_resolver_free(r);
+ avahi_service_resolver_free(r);
}
-static void browse_callback(
- AvahiServiceBrowser *b,
- AvahiIfIndex interface,
- AvahiProtocol protocol,
- AvahiBrowserEvent event,
- const char *name,
- const char *type,
- const char *domain,
- AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
- void* userdata) {
+static void browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol,
+ AvahiBrowserEvent event, const char *name, const char *type,
+ const char *domain, AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
+ void *userdata) {
- AvahiClient *c = userdata;
- assert(b);
+ AvahiClient *c = userdata;
+ assert(b);
- /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
+ /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
- switch (event) {
- case AVAHI_BROWSER_FAILURE:
+ switch (event) {
+ case AVAHI_BROWSER_FAILURE:
-// debug(1, "(Browser) %s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b))));
- return;
+ // debug(1, "(Browser) %s\n",
+ // avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b))));
+ return;
- case AVAHI_BROWSER_NEW:
-// debug(1, "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
+ case AVAHI_BROWSER_NEW:
+ // debug(1, "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name, type,
+ // domain);
- /* We ignore the returned resolver object. In the callback
- function we free it. If the server is terminated before
- the callback function is called the server will free
- the resolver for us. */
+ /* We ignore the returned resolver object. In the callback
+ function we free it. If the server is terminated before
+ the callback function is called the server will free
+ the resolver for us. */
- if (!(avahi_service_resolver_new(c, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolve_callback, c)))
- debug(1, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_client_errno(c)));
+ if (!(avahi_service_resolver_new(c, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC,
+ 0, resolve_callback, c)))
+ debug(1, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_client_errno(c)));
- break;
+ break;
- case AVAHI_BROWSER_REMOVE:
-// debug(1, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
- break;
+ case AVAHI_BROWSER_REMOVE:
+ // debug(1, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name,
+ // type, domain);
+ break;
- case AVAHI_BROWSER_ALL_FOR_NOW:
- case AVAHI_BROWSER_CACHE_EXHAUSTED:
-// debug(1, "(Browser) %s\n", event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
- break;
- }
+ case AVAHI_BROWSER_ALL_FOR_NOW:
+ case AVAHI_BROWSER_CACHE_EXHAUSTED:
+ // debug(1, "(Browser) %s\n", event == AVAHI_BROWSER_CACHE_EXHAUSTED ?
+ // "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
+ break;
+ }
}
-
-static void register_service( AvahiClient *c );
+static void register_service(AvahiClient *c);
static void egroup_callback(AvahiEntryGroup *g, AvahiEntryGroupState state,
AVAHI_GCC_UNUSED void *userdata) {
- switch ( state )
- {
- case AVAHI_ENTRY_GROUP_ESTABLISHED:
- /* The entry group has been established successfully */
- debug(1,"avahi: service '%s' successfully added.", name );
- break;
-
- case AVAHI_ENTRY_GROUP_COLLISION:
- {
- char *n;
-
- /* A service name collision with a remote service
- * happened. Let's pick a new name */
- n = avahi_alternative_service_name(name);
- avahi_free(name);
- name = n;
-
- debug(2,"avahi: service name collision, renaming service to '%s'", name );
-
- /* And recreate the services */
- register_service( avahi_entry_group_get_client( g ) );
- break;
- }
-
- case AVAHI_ENTRY_GROUP_FAILURE:
- debug(1,"avahi: entry group failure: %s", avahi_strerror( avahi_client_errno( avahi_entry_group_get_client( g ) ) ) );
- break;
-
- case AVAHI_ENTRY_GROUP_UNCOMMITED:
- debug(2,"avahi: service '%s' group is not yet commited.", name );
- break;
-
- case AVAHI_ENTRY_GROUP_REGISTERING:
- debug(2,"avahi: service '%s' group is registering.", name );
- break;
-
- default:
- debug(1,"avahi: unhandled egroup state: %d", state );
- break;
- }
+ switch (state) {
+ case AVAHI_ENTRY_GROUP_ESTABLISHED:
+ /* The entry group has been established successfully */
+ debug(1, "avahi: service '%s' successfully added.", name);
+ break;
+
+ case AVAHI_ENTRY_GROUP_COLLISION: {
+ char *n;
+
+ /* A service name collision with a remote service
+ * happened. Let's pick a new name */
+ n = avahi_alternative_service_name(name);
+ avahi_free(name);
+ name = n;
+
+ debug(2, "avahi: service name collision, renaming service to '%s'", name);
+
+ /* And recreate the services */
+ register_service(avahi_entry_group_get_client(g));
+ break;
+ }
+
+ case AVAHI_ENTRY_GROUP_FAILURE:
+ debug(1, "avahi: entry group failure: %s",
+ avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))));
+ break;
+
+ case AVAHI_ENTRY_GROUP_UNCOMMITED:
+ debug(2, "avahi: service '%s' group is not yet commited.", name);
+ break;
+
+ case AVAHI_ENTRY_GROUP_REGISTERING:
+ debug(2, "avahi: service '%s' group is registering.", name);
+ break;
+
+ default:
+ debug(1, "avahi: unhandled egroup state: %d", state);
+ break;
+ }
}
static void register_service(AvahiClient *c) {
return;
int ret;
- #ifdef CONFIG_METADATA
+#ifdef CONFIG_METADATA
if (config.metadata_enabled) {
ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, name,
- config.regtype, NULL, NULL, port, MDNS_RECORD_WITH_METADATA,
- NULL);
- if (ret==0)
- debug(1, "avahi: request to add \"%s\" service with metadata",config.regtype);
+ config.regtype, NULL, NULL, port,
+ MDNS_RECORD_WITH_METADATA, NULL);
+ if (ret == 0)
+ debug(1, "avahi: request to add \"%s\" service with metadata", config.regtype);
} else {
- #endif
+#endif
ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, name,
config.regtype, NULL, NULL, port,
MDNS_RECORD_WITHOUT_METADATA, NULL);
- if (ret==0)
- debug(1, "avahi: request to add \"%s\" service without metadata",config.regtype);
- #ifdef CONFIG_METADATA
+ if (ret == 0)
+ debug(1, "avahi: request to add \"%s\" service without metadata", config.regtype);
+#ifdef CONFIG_METADATA
}
- #endif
+#endif
if (ret < 0)
- debug(1,"avahi: avahi_entry_group_add_service failed");
+ debug(1, "avahi: avahi_entry_group_add_service failed");
else {
ret = avahi_entry_group_commit(group);
if (ret < 0)
- debug(1,"avahi: avahi_entry_group_commit failed");
+ debug(1, "avahi: avahi_entry_group_commit failed");
}
}
}
static void client_callback(AvahiClient *c, AvahiClientState state,
AVAHI_GCC_UNUSED void *userdata) {
switch (state) {
- case AVAHI_CLIENT_S_REGISTERING:
- if (group)
- avahi_entry_group_reset(group);
- break;
-
- case AVAHI_CLIENT_S_RUNNING:
- register_service(c);
- break;
-
- case AVAHI_CLIENT_FAILURE:
- debug(1,"avahi: client failure");
- break;
-
- case AVAHI_CLIENT_S_COLLISION:
- debug(2, "avahi: state is AVAHI_CLIENT_S_COLLISION...needs a rename: %s", name );
- break;
-
- case AVAHI_CLIENT_CONNECTING:
- debug(2, "avahi: received AVAHI_CLIENT_CONNECTING" );
- break;
-
- default:
- debug(1,"avahi: unexpected and unhandled avahi client state: %d", state );
- break;
+ case AVAHI_CLIENT_S_REGISTERING:
+ if (group)
+ avahi_entry_group_reset(group);
+ break;
+
+ case AVAHI_CLIENT_S_RUNNING:
+ register_service(c);
+ break;
+
+ case AVAHI_CLIENT_FAILURE:
+ debug(1, "avahi: client failure");
+ break;
+
+ case AVAHI_CLIENT_S_COLLISION:
+ debug(2, "avahi: state is AVAHI_CLIENT_S_COLLISION...needs a rename: %s", name);
+ break;
+
+ case AVAHI_CLIENT_CONNECTING:
+ debug(2, "avahi: received AVAHI_CLIENT_CONNECTING");
+ break;
+
+ default:
+ debug(1, "avahi: unexpected and unhandled avahi client state: %d", state);
+ break;
}
}
warn("couldn't create avahi client: %s!", avahi_strerror(err));
return -1;
}
-
- // we need this to detect the IPv6 number we're advertising...
- // if (!(sb = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, config.regtype, NULL, 0, browse_callback, client))) {
- // warn("Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(client)));
- // return -1;
- // }
+ // we need this to detect the IPv6 number we're advertising...
+ // if (!(sb = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
+ // config.regtype, NULL, 0, browse_callback, client))) {
+ // warn("Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(client)));
+ // return -1;
+ // }
if (avahi_threaded_poll_start(tpoll) < 0) {
warn("couldn't start avahi tpoll thread");
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <dns_sd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <arpa/inet.h>
#include "mdns.h"
#include "common.h"
+#include <arpa/inet.h>
+#include <dns_sd.h>
+#include <stdlib.h>
+#include <string.h>
static DNSServiceRef service;
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <unistd.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <string.h>
+#include "mdns.h"
+#include "common.h"
#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
#include <stdio.h>
-#include "common.h"
-#include "mdns.h"
+#include <string.h>
+#include <unistd.h>
int mdns_pid = 0;
char mdns_port[6];
sprintf(mdns_port, "%d", config.port);
- char *argvwithoutmetadata[] = {NULL, apname, config.regtype, mdns_port,
- MDNS_RECORD_WITHOUT_METADATA, NULL};
+ char *argvwithoutmetadata[] = {
+ NULL, apname, config.regtype, mdns_port, MDNS_RECORD_WITHOUT_METADATA, NULL};
#ifdef CONFIG_METADATA
char *argvwithmetadata[] = {NULL, apname, config.regtype, mdns_port, MDNS_RECORD_WITH_METADATA,
NULL};
char mdns_port[6];
sprintf(mdns_port, "%d", config.port);
- char *argvwithoutmetadata[] = {NULL, apname, config.regtype, mdns_port,
- MDNS_RECORD_WITHOUT_METADATA, NULL};
+ char *argvwithoutmetadata[] = {
+ NULL, apname, config.regtype, mdns_port, MDNS_RECORD_WITHOUT_METADATA, NULL};
#ifdef CONFIG_METADATA
char *argvwithmetadata[] = {NULL, apname, config.regtype, mdns_port, MDNS_RECORD_WITH_METADATA,
* OTHER DEALINGS IN THE SOFTWARE.
*/
+#include "mdns.h"
+#include "common.h"
+#include <ifaddrs.h>
+#include <net/if.h>
+#include <netinet/in.h>
#include <string.h>
-#include <sys/types.h>
#include <sys/socket.h>
-#include <net/if.h>
-#include <ifaddrs.h>
+#include <sys/types.h>
#include <unistd.h>
-#include <netinet/in.h>
-#include "common.h"
-#include "mdns.h"
#include "tinysvcmdns.h"
#endif
txt = txtwithoutmetadata;
-
+
if (config.regtype == NULL)
die("tinysvcmdns: regtype is null");
- char* extendedregtype = malloc(strlen(config.regtype)+strlen(".local")+1);
+ char *extendedregtype = malloc(strlen(config.regtype) + strlen(".local") + 1);
- if (extendedregtype==NULL)
+ if (extendedregtype == NULL)
die("tinysvcmdns: could not allocated memory to request a Zeroconf service");
-
- strcpy(extendedregtype,config.regtype);
- strcat(extendedregtype,".local");
- struct mdns_service *svc = mdnsd_register_svc(svr, apname, extendedregtype, port, NULL,
+ strcpy(extendedregtype, config.regtype);
+ strcat(extendedregtype, ".local");
+
+ struct mdns_service *svc =
+ mdnsd_register_svc(svr, apname, extendedregtype, port, NULL,
(const char **)txt); // TTL should be 75 minutes, i.e. 4500 seconds
mdns_service_destroy(svc);
-
+
free(extendedregtype);
return 0;
* OTHER DEALINGS IN THE SOFTWARE.
*/
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <math.h>
+#include <pthread.h>
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
-#include <unistd.h>
+#include <stdlib.h>
#include <string.h>
-#include <sys/types.h>
-#include <pthread.h>
-#include <math.h>
#include <sys/stat.h>
-#include <signal.h>
#include <sys/syslog.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <limits.h>
-#include <inttypes.h>
+#include <sys/types.h>
+#include <unistd.h>
#include "config.h"
#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 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_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)
static aes_context dctx;
#endif
-//static pthread_t player_thread = NULL;
+// 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 int
+ connection_state_to_output; // if true, then play incoming stuff; if false drop everything
static alac_file *decoder_info;
// make timestamps and seqnos definitely monotonic
-// add an epoch to the timestamp. The monotonic timestamp guaranteed to start between 2^32 and 2^33 frames and continue up to 2^63-1 frames
+// add an epoch to the timestamp. The monotonic timestamp guaranteed to start between 2^32 and 2^33
+// frames and continue up to 2^63-1 frames
// if should never get into the negative range
-// which is about 2*10^8 * 1,000 seconds at 384,000 frames per second -- about 2 trillion seconds or over 50,000 years.
-// also, it won't reach zero until then, if ever, so we can safely say that a null monotonic timestamp can mean something special
+// which is about 2*10^8 * 1,000 seconds at 384,000 frames per second -- about 2 trillion seconds or
+// over 50,000 years.
+// also, it won't reach zero until then, if ever, so we can safely say that a null monotonic
+// timestamp can mean something special
int64_t monotonic_timestamp(uint32_t timestamp) {
int64_t previous_value;
int64_t return_value;
- if (timestamp_epoch==0) {
- if (timestamp>maximum_timestamp_interval)
- timestamp_epoch=1;
+ if (timestamp_epoch == 0) {
+ if (timestamp > maximum_timestamp_interval)
+ timestamp_epoch = 1;
else
- timestamp_epoch=2;
+ timestamp_epoch = 2;
previous_value = timestamp_epoch;
- previous_value<<=32;
- previous_value+=timestamp;
+ previous_value <<= 32;
+ previous_value += timestamp;
} else {
previous_value = timestamp_epoch;
- previous_value<<=32;
- previous_value+=last_timestamp;
- if (timestamp<last_timestamp) {
+ previous_value <<= 32;
+ previous_value += last_timestamp;
+ if (timestamp < last_timestamp) {
// the incoming timestamp is less than the last one.
// if the difference is more than a minute, assume it's really from the next epoch
- if ((last_timestamp-timestamp)>maximum_timestamp_interval)
- timestamp_epoch++;
+ if ((last_timestamp - timestamp) > maximum_timestamp_interval)
+ timestamp_epoch++;
} else {
// the incoming timestamp is greater than the last one.
// if the difference is more than a minute, assume it's really from the previous epoch
- if ((timestamp-last_timestamp)>maximum_timestamp_interval)
+ if ((timestamp - last_timestamp) > maximum_timestamp_interval)
timestamp_epoch--;
}
}
- last_timestamp=timestamp;
+ last_timestamp = timestamp;
return_value = timestamp_epoch;
- return_value<<=32;
- return_value+=timestamp;
- if (previous_value>return_value) {
- if ((previous_value-return_value)>maximum_timestamp_interval)
- debug(1,"interval between successive rtptimes greater than allowed!");
+ return_value <<= 32;
+ return_value += timestamp;
+ if (previous_value > return_value) {
+ if ((previous_value - return_value) > maximum_timestamp_interval)
+ debug(1, "interval between successive rtptimes greater than allowed!");
} else {
- if ((return_value-previous_value)>maximum_timestamp_interval)
- debug(1,"interval between successive rtptimes greater than allowed!");
+ if ((return_value - previous_value) > maximum_timestamp_interval)
+ debug(1, "interval between successive rtptimes greater than allowed!");
}
- if (return_value<0)
- debug(1,"monotonic rtptime is negative!");
+ if (return_value < 0)
+ debug(1, "monotonic rtptime is negative!");
return return_value;
}
// add an epoch to the seq_no. Uses the accompanying timestamp to determine the correct epoch
-uint64_t monotonic_seqno(uint16_t seq_no) {
-}
+uint64_t monotonic_seqno(uint16_t seq_no) {}
static void ab_resync(void) {
int i;
// anything with ORDINATE in it must be proctected by the ab_mutex
static inline int32_t ORDINATE(seq_t x) {
- int32_t p = x; // int32_t from seq_t, i.e. uint16_t, so okay
+ int32_t p = x; // int32_t from seq_t, i.e. uint16_t, so okay
int32_t q = ab_read; // int32_t from seq_t, i.e. uint16_t, so okay
int32_t t = (p + 0x10000 - q) & 0xffff;
// we definitely will get a positive number in t at this point, but it might be a
// 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);
+
+ 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);
- int reply = 0; //everything okay
- int outsize=input_bytes_per_frame*(*destlen); // the size the output should be, in bytes
+ int reply = 0; // everything okay
+ int outsize = input_bytes_per_frame * (*destlen); // the size the output should be, in bytes
int toutsize = outsize;
if (encrypted) {
memcpy(packet + aeslen, buf + aeslen, len - aeslen);
#ifdef HAVE_APPLE_ALAC
if (config.use_apple_decoder) {
- if (decoder_in_use!=1<<decoder_apple_alac) {
- debug(1,"Apple ALAC Decoder used on encrypted audio.");
- decoder_in_use=1<<decoder_apple_alac;
+ if (decoder_in_use != 1 << decoder_apple_alac) {
+ debug(1, "Apple ALAC Decoder used on encrypted audio.");
+ decoder_in_use = 1 << decoder_apple_alac;
}
- apple_alac_decode_frame(packet, len, (unsigned char *) dest, &outsize);
- outsize=outsize*4; // bring the size to bytes
+ apple_alac_decode_frame(packet, len, (unsigned char *)dest, &outsize);
+ outsize = outsize * 4; // bring the size to bytes
} else
#endif
{
- if (decoder_in_use!=1<<decoder_hammerton) {
- debug(1,"Hammerton Decoder used on encrypted audio.");
- decoder_in_use=1<<decoder_hammerton;
+ if (decoder_in_use != 1 << decoder_hammerton) {
+ debug(1, "Hammerton Decoder used on encrypted audio.");
+ decoder_in_use = 1 << decoder_hammerton;
}
- alac_decode_frame(decoder_info, packet, (unsigned char *) dest, &outsize);
+ alac_decode_frame(decoder_info, packet, (unsigned char *)dest, &outsize);
}
} else {
- // not encrypted
+// not encrypted
#ifdef HAVE_APPLE_ALAC
if (config.use_apple_decoder) {
- if (decoder_in_use!=1<<decoder_apple_alac) {
- debug(1,"Apple ALAC Decoder used on unencrypted audio.");
- decoder_in_use=1<<decoder_apple_alac;
+ if (decoder_in_use != 1 << decoder_apple_alac) {
+ debug(1, "Apple ALAC Decoder used on unencrypted audio.");
+ decoder_in_use = 1 << decoder_apple_alac;
}
- apple_alac_decode_frame(buf, len, (unsigned char *) dest, &outsize);
- outsize=outsize*4; // bring the size to bytes
+ apple_alac_decode_frame(buf, len, (unsigned char *)dest, &outsize);
+ outsize = outsize * 4; // bring the size to bytes
} else
#endif
{
- if (decoder_in_use!=1<<decoder_hammerton) {
- debug(1,"Hammerton Decoder used on unencrypted audio.");
- decoder_in_use=1<<decoder_hammerton;
+ if (decoder_in_use != 1 << decoder_hammerton) {
+ debug(1, "Hammerton Decoder used on unencrypted audio.");
+ decoder_in_use = 1 << decoder_hammerton;
}
alac_decode_frame(decoder_info, buf, dest, &outsize);
}
}
- 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);
+ 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 / input_bytes_per_frame;
- if ((outsize % input_bytes_per_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,input_bytes_per_frame);
+ if ((outsize % input_bytes_per_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, input_bytes_per_frame);
return reply;
}
static int init_decoder(int32_t fmtp[12]) {
-// This is a guess, but the format of the fmtp looks identical to the format of an ALACSpecificCOnfig
-// which is detailed in the file ALACMagicCookieDescription.txt in the Apple ALAC sample implementation
-// Here it is:
-
-/*
- struct ALACSpecificConfig (defined in ALACAudioTypes.h)
- abstract This struct is used to describe codec provided information about the encoded Apple Lossless bitstream.
- It must accompany the encoded stream in the containing audio file and be provided to the decoder.
-
- field frameLength uint32_t indicating the frames per packet when no explicit frames per packet setting is
- present in the packet header. The encoder frames per packet can be explicitly set
- but for maximum compatibility, the default encoder setting of 4096 should be used.
-
- field compatibleVersion uint8_t indicating compatible version,
- value must be set to 0
-
- field bitDepth uint8_t describes the bit depth of the source PCM data (maximum value = 32)
-
- field pb uint8_t currently unused tuning parametetbugr.
- value should be set to 40
-
- field mb uint8_t currently unused tuning parameter.
- value should be set to 14
-
- field kb uint8_t currently unused tuning parameter.
- value should be set to 10
-
- field numChannels uint8_t describes the channel count (1 = mono, 2 = stereo, etc...)
- when channel layout info is not provided in the 'magic cookie', a channel count > 2
- describes a set of discreet channels with no specific ordering
-
- field maxRun uint16_t currently unused.
- value should be set to 255
-
- field maxFrameBytes uint32_t the maximum size of an Apple Lossless packet within the encoded stream.
- value of 0 indicates unknown
-
- field avgBitRate uint32_t the average bit rate in bits per second of the Apple Lossless stream.
- value of 0 indicates unknown
-
- field sampleRate uint32_t sample rate of the encoded stream
- */
-
-// We are going to go on that basis
-
-
+ // This is a guess, but the format of the fmtp looks identical to the format of an
+ // ALACSpecificCOnfig
+ // which is detailed in the file ALACMagicCookieDescription.txt in the Apple ALAC sample
+ // implementation
+ // Here it is:
+
+ /*
+ struct ALACSpecificConfig (defined in ALACAudioTypes.h)
+ abstract This struct is used to describe codec provided information about the encoded
+ Apple Lossless bitstream.
+ It must accompany the encoded stream in the containing audio file and be provided
+ to the decoder.
+
+ field frameLength uint32_t indicating the frames per packet
+ when
+ no
+ explicit
+ frames per packet setting is
+ present in the packet header. The
+ encoder frames per packet can be explicitly set
+ but for maximum compatibility, the
+ default encoder setting of 4096 should be used.
+
+ field compatibleVersion uint8_t indicating compatible version,
+ value must be set to 0
+
+ field bitDepth uint8_t describes the bit depth of the source
+ PCM
+ data
+ (maximum
+ value = 32)
+
+ field pb uint8_t currently unused tuning
+ parametetbugr.
+ value should be set to 40
+
+ field mb uint8_t currently unused tuning parameter.
+ value should be set to 14
+
+ field kb uint8_t currently unused tuning parameter.
+ value should be set to 10
+
+ field numChannels uint8_t describes the channel count (1 = mono,
+ 2
+ =
+ stereo,
+ etc...)
+ when channel layout info is not provided
+ in the 'magic cookie', a channel count > 2
+ describes a set of discreet channels
+ with no specific ordering
+
+ field maxRun uint16_t currently unused.
+ value should be set to 255
+
+ field maxFrameBytes uint32_t the maximum size of an Apple
+ Lossless
+ packet
+ within
+ the encoded stream.
+ value of 0 indicates unknown
+
+ field avgBitRate uint32_t the average bit rate in bits per second
+ of
+ the
+ Apple
+ Lossless stream.
+ value of 0 indicates unknown
+
+ field sampleRate uint32_t sample rate of the encoded stream
+ */
+
+ // We are going to go on that basis
alac_file *alac;
input_rate = fmtp[11];
input_num_channels = fmtp[7];
input_bit_depth = fmtp[3];
-
- input_bytes_per_frame = input_num_channels*((input_bit_depth+7)/8);
+
+ input_bytes_per_frame = input_num_channels * ((input_bit_depth + 7) / 8);
alac = alac_create(input_bit_depth, input_num_channels);
if (!alac)
static void init_buffer(void) {
int i;
for (i = 0; i < BUFFER_FRAMES; i++)
- audio_buffer[i].data = malloc(input_bytes_per_frame*(max_frames_per_packet+max_frame_size_change));
+ audio_buffer[i].data =
+ malloc(input_bytes_per_frame * (max_frames_per_packet + max_frame_size_change));
ab_resync();
}
}
void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len) {
-
- // all timestamps are done at the output rate
-
- int64_t ltimestamp = timestamp*output_sample_ratio;
+
+ // all timestamps are done at the output rate
+
+ int64_t ltimestamp = timestamp * output_sample_ratio;
// ignore a request to flush that has been made before the first packet...
- if (packet_count==0) {
+ if (packet_count == 0) {
pthread_mutex_lock(&flush_mutex);
flush_requested = 0;
flush_rtp_timestamp = 0;
pthread_mutex_unlock(&flush_mutex);
}
-
+
pthread_mutex_lock(&ab_mutex);
packet_count++;
time_of_last_audio_packet = get_absolute_time_in_fp();
if (connection_state_to_output) { // if we are supposed to be processing these packets
-// if (flush_rtp_timestamp != 0)
-// debug(1,"Flush_rtp_timestamp is %u",flush_rtp_timestamp);
+ // if (flush_rtp_timestamp != 0)
+ // debug(1,"Flush_rtp_timestamp is %u",flush_rtp_timestamp);
- if ((flush_rtp_timestamp != 0) &&
- (ltimestamp <= flush_rtp_timestamp)) {
- debug(3, "Dropping flushed packet in player_put_packet, seqno %u, timestamp %lld, flushing to "
- "timestamp: %lld.",
+ if ((flush_rtp_timestamp != 0) && (ltimestamp <= flush_rtp_timestamp)) {
+ debug(3,
+ "Dropping flushed packet in player_put_packet, seqno %u, timestamp %lld, flushing to "
+ "timestamp: %lld.",
seqno, ltimestamp, flush_rtp_timestamp);
} else {
if ((flush_rtp_timestamp != 0x0) &&
- (ltimestamp>flush_rtp_timestamp)) // if we have gone past the flush boundary time
+ (ltimestamp > flush_rtp_timestamp)) // if we have gone past the flush boundary time
flush_rtp_timestamp = 0x0;
abuf_t *abuf = 0;
}
// debug(1,"N %d s %u.",seq_diff(ab_write,PREDECESSOR(seqno))+1,ab_write);
abuf = audio_buffer + BUFIDX(seqno);
-// rtp_request_resend(ab_write, gap);
-// resend_requests++;
+ // rtp_request_resend(ab_write, gap);
+ // resend_requests++;
ab_write = SUCCESSOR(seqno);
} else if (seq_order(ab_read, seqno)) { // late but not yet played
late_packets++;
if (abuf) {
int datalen = max_frames_per_packet;
- if (alac_decode(abuf->data, &datalen, data, len)==0) {
- abuf->ready = 1;
- abuf->length = datalen;
- abuf->timestamp = ltimestamp;
- abuf->sequence_number = seqno;
+ if (alac_decode(abuf->data, &datalen, data, len) == 0) {
+ abuf->ready = 1;
+ abuf->length = datalen;
+ abuf->timestamp = ltimestamp;
+ abuf->sequence_number = seqno;
} else {
- debug(1,"Bad audio packet detected and discarded.");
- abuf->ready = 0;
- abuf->timestamp = 0;
- abuf->sequence_number = 0;
+ debug(1, "Bad audio packet detected and discarded.");
+ abuf->ready = 0;
+ abuf->timestamp = 0;
+ abuf->sequence_number = 0;
}
}
int32_t rand_in_range(int32_t exclusive_range_limit) {
static uint32_t lcg_prev = 12345;
- // returns a pseudo random integer in the range 0 to (exclusive_range_limit-1) inclusive
- int64_t sp = lcg_prev;
- int64_t rl = exclusive_range_limit;
- lcg_prev = lcg_prev * 69069 + 3; // crappy psrg
- sp = sp*rl; // 64 bit calculation. INtersting part if above the 32 rightmost bits;
- return sp >> 32;
+ // returns a pseudo random integer in the range 0 to (exclusive_range_limit-1) inclusive
+ int64_t sp = lcg_prev;
+ int64_t rl = exclusive_range_limit;
+ lcg_prev = lcg_prev * 69069 + 3; // crappy psrg
+ sp = sp * rl; // 64 bit calculation. INtersting part if above the 32 rightmost bits;
+ return sp >> 32;
}
-static inline void process_sample(int32_t sample,char**outp,enum sps_format_t format,int volume,int dither) {
+static inline void process_sample(int32_t sample, char **outp, enum sps_format_t format, int volume,
+ int dither) {
int64_t hyper_sample = sample;
int result;
// first, modify volume, if necessary
- if (volume==0x10000)
- hyper_sample<<=32;
+ if (volume == 0x10000)
+ hyper_sample <<= 32;
else
- hyper_sample*=(volume<<16);
-
+ hyper_sample *= (volume << 16); // this is 32*32 -> 64 bit bit multiplication -- we may need to
+ // dither it down to its
+ // target resolution
+
// next, do dither, if necessary
if (dither) {
+
+ // add a TPDF dither -- see
+ // http://www.users.qwest.net/%7Evolt42/cadenzarecording/DitherExplained.pdf
+ // and the discussion around https://www.hydrogenaud.io/forums/index.php?showtopic=16963&st=25
+
+ // I think, for a 32 --> 16 bits, the range of
+ // random numbers needs to be from -2^16 to 2^16, i.e. from -65536 to 65536 inclusive, not from
+ // -32768 to +32767
+
+ // See the original paper at
+ // http://www.ece.rochester.edu/courses/ECE472/resources/Papers/Lipshitz_1992.pdf
+ // by Lipshitz, Wannamaker and Vanderkooy, 1992.
+
int64_t dither_mask;
switch (format) {
- case SPS_FORMAT_S32_LE:
- dither_mask = (int64_t)1<<(64+1-32);
- break;
- case SPS_FORMAT_S24_LE:
- dither_mask = (int64_t)1<<(64+1-24);
- break;
- case SPS_FORMAT_S16_LE:
- dither_mask = (int64_t)1<<(64+1-16);
- break;
- case SPS_FORMAT_S8:
- case SPS_FORMAT_U8:
- dither_mask = (int64_t)1<<(64+1-24);
- break;
+ case SPS_FORMAT_S32_LE:
+ dither_mask = (int64_t)1 << (64 + 1 - 32);
+ break;
+ case SPS_FORMAT_S24_LE:
+ dither_mask = (int64_t)1 << (64 + 1 - 24);
+ break;
+ case SPS_FORMAT_S16_LE:
+ dither_mask = (int64_t)1 << (64 + 1 - 16);
+ break;
+ case SPS_FORMAT_S8:
+ case SPS_FORMAT_U8:
+ dither_mask = (int64_t)1 << (64 + 1 - 24);
+ break;
}
- dither_mask-=1;
+ dither_mask -= 1;
int64_t r = r64i();
- int64_t tpdf = (r&dither_mask)-(previous_random_number&dither_mask);
- previous_random_number=r;
+ int64_t tpdf = (r & dither_mask) - (previous_random_number & dither_mask);
+ previous_random_number = r;
// add dither, allowing for clipping
- if (tpdf>=0) {
- if (INT64_MAX-tpdf>=hyper_sample)
+ if (tpdf >= 0) {
+ if (INT64_MAX - tpdf >= hyper_sample)
hyper_sample += tpdf;
else
hyper_sample = INT64_MAX;
} else {
- if (INT64_MIN-tpdf<=hyper_sample)
+ if (INT64_MIN - tpdf <= hyper_sample)
hyper_sample += tpdf;
else
hyper_sample = INT64_MIN;
}
// dither is complete here
}
-
+
// move the result to the desired position in the int64_t
char *op = *outp;
switch (format) {
- case SPS_FORMAT_S32_LE:
- hyper_sample>>=(64-32);
- *(int32_t*)op = hyper_sample;
- result=4;
- break;
- case SPS_FORMAT_S24_LE:
- hyper_sample>>=(64-24);
- *(int32_t*)op = hyper_sample;
- result=4;
- break;
- case SPS_FORMAT_S16_LE:
- hyper_sample>>=(64-16);
- *(int16_t*)op = hyper_sample;
- result=2;
- break;
- case SPS_FORMAT_S8:
- hyper_sample>>=(64-8);
- *op = hyper_sample;
- result=1;
- break;
- case SPS_FORMAT_U8:
- hyper_sample>>=(64-8);
- hyper_sample+=128; // this is just a guess!
- *op = hyper_sample;
- result=1;
- break;
+ case SPS_FORMAT_S32_LE:
+ hyper_sample >>= (64 - 32);
+ *(int32_t *)op = hyper_sample;
+ result = 4;
+ break;
+ case SPS_FORMAT_S24_LE:
+ hyper_sample >>= (64 - 24);
+ *(int32_t *)op = hyper_sample;
+ result = 4;
+ break;
+ case SPS_FORMAT_S16_LE:
+ hyper_sample >>= (64 - 16);
+ *(int16_t *)op = hyper_sample;
+ result = 2;
+ break;
+ case SPS_FORMAT_S8:
+ hyper_sample >>= (64 - 8);
+ *op = hyper_sample;
+ result = 1;
+ break;
+ case SPS_FORMAT_U8:
+ hyper_sample >>= (64 - 8);
+ hyper_sample += 128; // this is just a guess!
+ *op = hyper_sample;
+ result = 1;
+ break;
}
-
- *outp+=result;
-}
+ *outp += result;
+}
static inline int32_t dithered_vol_32(int32_t sample, int output_precision) {
- if ((fix_volume==0x1000) && (output_precision==32)) {
+ if ((fix_volume == 0x1000) && (output_precision == 32)) {
return sample;
} else {
- int64_t s = sample; // 64 bit signed
+ int64_t s = sample; // 64 bit signed
int64_t v = fix_volume & 0x1FFFF; // 17 bit unsigned made a 33 bit unsigned
- v<<=16;
- s = s*v; // 32 bit multiplication -- we need to dither it down to its target resolution
+ v <<= 16;
+ s = s * v; // this is 32*32 -> 64 bit bit multiplication -- we may need to dither it down to its
+ // target resolution
+
+ // add a TPDF dither -- see
+ // http://www.users.qwest.net/%7Evolt42/cadenzarecording/DitherExplained.pdf
+ // and the discussion around https://www.hydrogenaud.io/forums/index.php?showtopic=16963&st=25
+
+ // I think, for a 32 --> 16 bits, the range of
+ // random numbers needs to be from -2^16 to 2^16, i.e. from -65536 to 65536 inclusive, not from
+ // -32768 to +32767
+
+ // See the original paper at
+ // http://www.ece.rochester.edu/courses/ECE472/resources/Papers/Lipshitz_1992.pdf
+ // by Lipshitz, Wannamaker and Vanderkooy, 1992.
int64_t r = r64i();
- int64_t mask = (int64_t)1<<(64+1-output_precision);
- mask -=1;
- int64_t tpdf = (r&mask); //-(previous_random_number&((1<<(64+1-output_precision))-1));
-// debug(1,"output precision is %d, m is %llx, r is %llx, tpdf is %llx",output_precision,mask,r,tpdf);
- previous_random_number=r;
-
- // Check there's no clipping -- if there is,
- if (tpdf>=0) {
- if (INT64_MAX-tpdf>=s)
+ int64_t mask = (int64_t)1 << (64 + 1 - output_precision);
+ mask -= 1;
+ int64_t tpdf = (r & mask) - (previous_random_number & mask);
+
+ previous_random_number = r;
+
+ // Check there's no clipping -- if there is, use INT64_MAX or INT64_MIN
+
+ if (tpdf >= 0) {
+ if (INT64_MAX - tpdf >= s)
s += tpdf;
else
s = INT64_MAX;
} else {
- if (INT64_MIN-tpdf<=s)
+ if (INT64_MIN - tpdf <= s)
s += tpdf;
else
s = INT64_MIN;
}
- s>>=(64-output_precision);
+ s >>= (64 - output_precision);
return s;
}
}
out = (long)sample * fix_volume;
if (fix_volume < 0x10000) {
-
- // add a TPDF dither -- see http://www.users.qwest.net/%7Evolt42/cadenzarecording/DitherExplained.pdf
- // and the discussion around https://www.hydrogenaud.io/forums/index.php?showtopic=16963&st=25
-
- // I think, for a 32 --> 16 bits, the range of
- // random numbers needs to be from -2^16 to 2^16, i.e. from -65536 to 65536 inclusive, not from -32768 to +32767
-
- // See the original paper at http://www.ece.rochester.edu/courses/ECE472/resources/Papers/Lipshitz_1992.pdf
- // by Lipshitz, Wannamaker and Vanderkooy, 1992.
-
- long tpdf = rand_in_range(65536+1) - rand_in_range(65536+1);
- // Check there's no clipping -- if there is,
- if (tpdf>=0) {
- if (LONG_MAX-tpdf>=out)
- out += tpdf;
- else
- out = LONG_MAX;
+
+ // add a TPDF dither -- see
+ // http://www.users.qwest.net/%7Evolt42/cadenzarecording/DitherExplained.pdf
+ // and the discussion around https://www.hydrogenaud.io/forums/index.php?showtopic=16963&st=25
+
+ // I think, for a 32 --> 16 bits, the range of
+ // random numbers needs to be from -2^16 to 2^16, i.e. from -65536 to 65536 inclusive, not from
+ // -32768 to +32767
+
+ // See the original paper at
+ // http://www.ece.rochester.edu/courses/ECE472/resources/Papers/Lipshitz_1992.pdf
+ // by Lipshitz, Wannamaker and Vanderkooy, 1992.
+
+ long tpdf = rand_in_range(65536 + 1) - rand_in_range(65536 + 1);
+ // Check there's no clipping -- if there is,
+ if (tpdf >= 0) {
+ if (LONG_MAX - tpdf >= out)
+ out += tpdf;
+ else
+ out = LONG_MAX;
} else {
- if (LONG_MIN-tpdf<=out)
- out += tpdf;
- else
- out = LONG_MIN;
+ if (LONG_MIN - tpdf <= out)
+ out += tpdf;
+ else
+ out = LONG_MIN;
}
}
return out >> 16;
pthread_mutex_lock(&ab_mutex);
int wait;
- long dac_delay = 0; // long because alsa returns a long
+ long dac_delay = 0; // long because alsa returns a long
do {
// get the time
local_time_now = get_absolute_time_in_fp(); // type okay
flush_requested = 0;
}
pthread_mutex_unlock(&flush_mutex);
-
+
uint32_t flush_limit = 0;
if (ab_synced) {
do {
curframe = audio_buffer + BUFIDX(ab_read);
- if ((ab_read!=ab_write) && (curframe->ready)) { // it could be synced and empty, under exceptional circumstances, with the frame unused, thus apparently 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.
}
}
- if ((flush_rtp_timestamp != 0) &&
- (curframe->timestamp <= flush_rtp_timestamp)) {
+ if ((flush_rtp_timestamp != 0) && (curframe->timestamp <= flush_rtp_timestamp)) {
debug(1, "Dropping flushed packet seqno %u, timestamp %lld", curframe->sequence_number,
curframe->timestamp);
curframe->ready = 0;
flush_limit++;
ab_read = SUCCESSOR(ab_read);
}
- if (curframe->timestamp>flush_rtp_timestamp)
+ if (curframe->timestamp > flush_rtp_timestamp)
flush_rtp_timestamp = 0;
}
} while ((flush_rtp_timestamp != 0) && (flush_limit <= 8820) && (curframe->ready == 0));
curframe = audio_buffer + BUFIDX(ab_read);
if (curframe->ready) {
- notified_buffer_empty=0; // at least one buffer now -- diagnostic only.
+ notified_buffer_empty = 0; // at least one buffer now -- diagnostic only.
if (ab_buffering) { // if we are getting packets but not yet forwarding them to the player
- int have_sent_prefiller_silence; // set true when we have sent some silent frames to the DAC
+ int have_sent_prefiller_silence; // set true when we have sent some silent frames to the
+ // DAC
int64_t reference_timestamp;
- uint64_t reference_timestamp_time,remote_reference_timestamp_time;
- get_reference_timestamp_stuff(&reference_timestamp, &reference_timestamp_time, &remote_reference_timestamp_time);
- reference_timestamp*=output_sample_ratio;
+ uint64_t reference_timestamp_time, remote_reference_timestamp_time;
+ get_reference_timestamp_stuff(&reference_timestamp, &reference_timestamp_time,
+ &remote_reference_timestamp_time);
+ reference_timestamp *= output_sample_ratio;
if (first_packet_timestamp == 0) { // if this is the very first packet
// debug(1,"First frame seen, time %u, with %d
// frames...",curframe->timestamp,seq_diff(ab_read, ab_write));
// if would be in sync. To do this, we would give it a latency offset of -100 ms, i.e.
// -4410 frames.
-debug(1,"Output sample ratio is %d",output_sample_ratio);
+ debug(1, "Output sample ratio is %d", output_sample_ratio);
+
+ int64_t delta = (first_packet_timestamp - reference_timestamp) +
+ config.latency * output_sample_ratio +
+ config.audio_backend_latency_offset * config.output_rate;
- int64_t delta = (first_packet_timestamp - reference_timestamp)+config.latency*output_sample_ratio+config.audio_backend_latency_offset*config.output_rate;
-
- if (delta>=0) {
- int64_t delta_fp_sec = (delta << 32) / config.output_rate; // int64_t which is positive
- first_packet_time_to_play=reference_timestamp_time+delta_fp_sec;
+ if (delta >= 0) {
+ int64_t delta_fp_sec =
+ (delta << 32) / config.output_rate; // int64_t which is positive
+ first_packet_time_to_play = reference_timestamp_time + delta_fp_sec;
} else {
int64_t abs_delta = -delta;
- int64_t delta_fp_sec = (abs_delta << 32) / config.output_rate; // int64_t which is positive
- first_packet_time_to_play=reference_timestamp_time-delta_fp_sec;
+ int64_t delta_fp_sec =
+ (abs_delta << 32) / config.output_rate; // int64_t which is positive
+ first_packet_time_to_play = reference_timestamp_time - delta_fp_sec;
}
if (local_time_now >= first_packet_time_to_play) {
debug(
1,
"First packet is late! It should have played before now. Flushing 0.1 seconds");
- player_flush(first_packet_timestamp + 4410*output_sample_ratio);
+ player_flush(first_packet_timestamp + 4410 * output_sample_ratio);
}
}
}
if (first_packet_time_to_play != 0) {
// recalculate first_packet_time_to_play -- the latency might change
- int64_t delta = (first_packet_timestamp - reference_timestamp)+config.latency*output_sample_ratio+config.audio_backend_latency_offset*config.output_rate;
-
- if (delta>=0) {
- int64_t delta_fp_sec = (delta << 32) / config.output_rate; // int64_t which is positive
- first_packet_time_to_play=reference_timestamp_time+delta_fp_sec;
+ int64_t delta = (first_packet_timestamp - reference_timestamp) +
+ config.latency * output_sample_ratio +
+ config.audio_backend_latency_offset * config.output_rate;
+
+ if (delta >= 0) {
+ int64_t delta_fp_sec =
+ (delta << 32) / config.output_rate; // int64_t which is positive
+ first_packet_time_to_play = reference_timestamp_time + delta_fp_sec;
} else {
int64_t abs_delta = -delta;
- int64_t delta_fp_sec = (abs_delta << 32) / config.output_rate; // int64_t which is positive
- first_packet_time_to_play=reference_timestamp_time-delta_fp_sec;
+ int64_t delta_fp_sec =
+ (abs_delta << 32) / config.output_rate; // int64_t which is positive
+ first_packet_time_to_play = reference_timestamp_time - delta_fp_sec;
}
- int64_t max_dac_delay = config.output_rate/10;
+ int64_t max_dac_delay = config.output_rate / 10;
int64_t filler_size = max_dac_delay; // 0.1 second -- the maximum we'll add to the DAC
if (local_time_now >= first_packet_time_to_play) {
} else {
// first_packet_time_to_play is definitely later than local_time_now
if ((config.output->delay) && (have_sent_prefiller_silence != 0)) {
- int resp = config.output->delay(&dac_delay);
+ int resp = config.output->delay(&dac_delay);
if (resp != 0) {
- debug(1, "Error %d getting dac_delay in buffer_get_frame.",resp);
+ debug(1, "Error %d getting dac_delay in buffer_get_frame.", resp);
dac_delay = 0;
- }
+ }
} else
dac_delay = 0;
int64_t gross_frame_gap =
int64_t fs = filler_size;
if (fs > (max_dac_delay - dac_delay))
fs = max_dac_delay - dac_delay;
- if (fs<0) {
- debug(2,"frame size (fs) < 0 with max_dac_delay of %lld and dac_delay of %ld",max_dac_delay, dac_delay);
- fs=0;
+ if (fs < 0) {
+ debug(2, "frame size (fs) < 0 with max_dac_delay of %lld and dac_delay of %ld",
+ max_dac_delay, dac_delay);
+ fs = 0;
}
if ((exact_frame_gap <= fs) || (exact_frame_gap <= max_frames_per_packet * 2)) {
fs = exact_frame_gap;
ab_buffering = 0;
}
signed short *silence;
- //if (fs==0)
- // 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(output_bytes_per_frame*fs);
- if (silence==NULL)
- debug(1,"Failed to allocate %d byte silence buffer.",fs);
+ // if (fs==0)
+ // 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(output_bytes_per_frame * fs);
+ if (silence == NULL)
+ debug(1, "Failed to allocate %d byte silence buffer.", fs);
else {
- memset(silence, 0, output_bytes_per_frame*fs);
+ memset(silence, 0, output_bytes_per_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 (ab_buffering == 0) {
// not the time of the playing of the first frame
uint64_t reference_timestamp_time; // don't need this...
- get_reference_timestamp_stuff(&play_segment_reference_frame, &reference_timestamp_time, &play_segment_reference_frame_remote_time);
- play_segment_reference_frame*=output_sample_ratio;
+ get_reference_timestamp_stuff(&play_segment_reference_frame, &reference_timestamp_time,
+ &play_segment_reference_frame_remote_time);
+ play_segment_reference_frame *= output_sample_ratio;
#ifdef CONFIG_METADATA
- send_ssnc_metadata('prsm', NULL, 0, 0); // "resume", but don't wait if the queue is locked
+ send_ssnc_metadata('prsm', NULL, 0,
+ 0); // "resume", but don't wait if the queue is locked
#endif
- }
+ }
}
}
}
int do_wait = 0; // don't wait unless we can really prove we must
if ((ab_synced) && (curframe) && (curframe->ready) && (curframe->timestamp)) {
- do_wait = 1; // if the current frame exists and is ready, then wait unless it's time to let it go...
+ do_wait =
+ 1; // if the current frame exists and is ready, then wait unless it's time to let it go...
int64_t reference_timestamp;
- uint64_t reference_timestamp_time,remote_reference_timestamp_time;
- get_reference_timestamp_stuff(&reference_timestamp, &reference_timestamp_time, &remote_reference_timestamp_time); // all types okay
- reference_timestamp*=output_sample_ratio;
- if (reference_timestamp) { // if we have a reference time
+ uint64_t reference_timestamp_time, remote_reference_timestamp_time;
+ get_reference_timestamp_stuff(&reference_timestamp, &reference_timestamp_time,
+ &remote_reference_timestamp_time); // all types okay
+ reference_timestamp *= output_sample_ratio;
+ if (reference_timestamp) { // if we have a reference time
int64_t packet_timestamp = curframe->timestamp; // types okay
int64_t delta = packet_timestamp - reference_timestamp;
- int64_t offset = config.latency*output_sample_ratio + config.audio_backend_latency_offset*config.output_rate -
- config.audio_backend_buffer_desired_length*config.output_rate; // all arguments are int32_t, so expression promotion okay
- int64_t net_offset = delta + offset; // okay
+ int64_t offset =
+ config.latency * output_sample_ratio +
+ config.audio_backend_latency_offset * config.output_rate -
+ config.audio_backend_buffer_desired_length *
+ config.output_rate; // all arguments are int32_t, so expression promotion okay
+ int64_t net_offset = delta + offset; // okay
uint64_t time_to_play = reference_timestamp_time; // type okay
if (net_offset >= 0) {
- uint64_t net_offset_fp_sec = (net_offset << 32) / config.output_rate; // int64_t which is positive
- time_to_play += net_offset_fp_sec; // using the latency requested...
+ uint64_t net_offset_fp_sec =
+ (net_offset << 32) / config.output_rate; // int64_t which is positive
+ time_to_play += net_offset_fp_sec; // using the latency requested...
// debug(2,"Net Offset: %lld, adjusted: %lld.",net_offset,net_offset_fp_sec);
} else {
int64_t abs_net_offset = -net_offset;
- uint64_t net_offset_fp_sec = (abs_net_offset << 32) / config.output_rate; // int64_t which is positive
+ uint64_t net_offset_fp_sec =
+ (abs_net_offset << 32) / config.output_rate; // int64_t which is positive
time_to_play -= net_offset_fp_sec;
// debug(2,"Net Offset: %lld, adjusted: -%lld.",net_offset,net_offset_fp_sec);
}
}
}
}
- if (do_wait==0)
- if ((ab_synced!=0) && (ab_read==ab_write)) { // the buffer is empty!
- if (notified_buffer_empty==0) {
- debug(1,"Buffers exhausted.");
- notified_buffer_empty=1;
+ if (do_wait == 0)
+ if ((ab_synced != 0) && (ab_read == ab_write)) { // the buffer is empty!
+ if (notified_buffer_empty == 0) {
+ debug(1, "Buffers exhausted.");
+ notified_buffer_empty = 1;
}
- do_wait=1;
+ do_wait = 1;
}
wait = (ab_buffering || (do_wait != 0) || (!ab_synced)) && (!please_stop);
if (wait) {
uint64_t time_to_wait_for_wakeup_fp =
- ((uint64_t)1 << 32) / input_rate; // this is time period of one frame
+ ((uint64_t)1 << 32) / input_rate; // this is time period of one frame
time_to_wait_for_wakeup_fp *= 4 * 352; // four full 352-frame packets
- time_to_wait_for_wakeup_fp /= 3; // four thirds of a packet time
+ time_to_wait_for_wakeup_fp /= 3; // four thirds of a packet time
#ifdef COMPILE_FOR_LINUX_AND_FREEBSD_AND_CYGWIN
uint64_t time_of_wakeup_fp = local_time_now + time_to_wait_for_wakeup_fp;
}
}
-
if (!curframe->ready) {
// debug(1, "Supplying a silent frame for frame %u", read);
missing_packets++;
- memset(curframe->data, 0, input_bytes_per_frame*max_frames_per_packet);
+ memset(curframe->data, 0, input_bytes_per_frame * max_frames_per_packet);
curframe->timestamp = 0;
}
curframe->ready = 0;
return r;
}
-// this takes an array of signed 32-bit integers and (a) removes or inserts a frame as specified in stuff,
+// this takes an array of signed 32-bit integers and (a) removes or inserts a 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 endinan 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, char *outptr, int stuff, int dither) {
+static int stuff_buffer_basic_32(int32_t *inptr, int length, enum sps_format_t l_output_format,
+ char *outptr, int stuff, int dither) {
int tstuff = stuff;
char *l_outptr = outptr;
- if ((stuff > 1) || (stuff < -1) || (length <100)) {
+ 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/
}
-
+
int i;
int stuffsamp = length;
if (tstuff)
pthread_mutex_lock(&vol_mutex);
for (i = 0; i < stuffsamp; i++) { // the whole frame, if no stuffing
- process_sample(*inptr++,&l_outptr,l_output_format,fix_volume,dither);
- process_sample(*inptr++,&l_outptr,l_output_format,fix_volume,dither);
+ process_sample(*inptr++, &l_outptr, l_output_format, fix_volume, dither);
+ process_sample(*inptr++, &l_outptr, l_output_format, fix_volume, dither);
};
if (tstuff) {
if (tstuff == 1) {
// debug(3, "+++++++++");
// interpolate one sample
- process_sample(mean_32(inptr[-2], inptr[0]),&l_outptr,l_output_format,fix_volume,dither);
- process_sample(mean_32(inptr[-1], inptr[1]),&l_outptr,l_output_format,fix_volume,dither);
+ process_sample(mean_32(inptr[-2], inptr[0]), &l_outptr, l_output_format, fix_volume, dither);
+ process_sample(mean_32(inptr[-1], inptr[1]), &l_outptr, l_output_format, fix_volume, dither);
} else if (stuff == -1) {
// debug(3, "---------");
inptr++;
inptr++;
}
-
- // if you're removing, i.e. stuff < 0, copy that much less over. If you're adding, do all the rest.
+
+ // if you're removing, i.e. stuff < 0, copy that much less over. If you're adding, do all the
+ // rest.
int remainder = length;
- if (tstuff<0)
- remainder = remainder+tstuff; // don't run over the correct end of the output buffer
+ if (tstuff < 0)
+ remainder = remainder + tstuff; // don't run over the correct end of the output buffer
for (i = stuffsamp; i < remainder; i++) {
- process_sample(*inptr++,&l_outptr,l_output_format,fix_volume,dither);
- process_sample(*inptr++,&l_outptr,l_output_format,fix_volume,dither);
+ process_sample(*inptr++, &l_outptr, l_output_format, fix_volume, dither);
+ process_sample(*inptr++, &l_outptr, l_output_format, fix_volume, dither);
}
}
pthread_mutex_unlock(&vol_mutex);
-
+
return length + tstuff;
}
static int stuff_buffer_basic(short *inptr, int length, short *outptr, int stuff) {
int tstuff = stuff;
- if ((stuff > 1) || (stuff < -1) || (length <100)) {
+ 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/
}
inptr++;
inptr++;
}
-
- // if you're removing, i.e. stuff < 0, copy that much less over. If you're adding, do all the rest.
+
+ // if you're removing, i.e. stuff < 0, copy that much less over. If you're adding, do all the
+ // rest.
int remainder = length;
- if (tstuff<0)
- remainder = remainder+tstuff; // don't run over the correct end of the output buffer
+ if (tstuff < 0)
+ remainder = remainder + tstuff; // don't run over the correct end of the output buffer
for (i = stuffsamp; i < remainder; i++) {
*outptr++ = dithered_vol(*inptr++);
}
#ifdef HAVE_LIBSOXR
-static int stuff_buffer_soxr_32(int32_t *inptr, int length, int32_t *outptr, int stuff, int l_output_bit_depth) {
+static int stuff_buffer_soxr_32(int32_t *inptr, int length, int32_t *outptr, int stuff,
+ int l_output_bit_depth) {
return length;
}
// 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) {
int tstuff = stuff;
- if ((stuff > 1) || (stuff < -1) || (length <100)) {
+ 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/
}
size_t odone;
- soxr_error_t error = soxr_oneshot(length, length + tstuff, 2, /* Rates and # of chans. */
- inptr, length, NULL, /* Input. */
+ soxr_error_t error = soxr_oneshot(length, length + tstuff, 2, /* Rates and # of chans. */
+ inptr, length, NULL, /* Input. */
outptr, length + tstuff, &odone, /* Output. */
&io_spec, /* Input, output and transfer spec. */
NULL, NULL); /* Default configuration.*/
} stats_t;
static void *player_thread_func(void *arg) {
- struct inter_threads_record itr;
- itr.please_stop = 0;
- timestamp_epoch = 0; // indicate that the next timestamp will be the first one.
- maximum_timestamp_interval = input_rate * 60; // actually there shouldn't be more than about 13v seconds of a gap between successive rtptimes, at worst
-
- output_sample_ratio = config.output_rate/input_rate;
-
- debug(1,"Output sample ratio is %d.",output_sample_ratio);
-
- max_frame_size_change = 1*output_sample_ratio; // we add or subtract one frame at the nominal rate, multiply it by the frame ratio.
-
- output_bytes_per_frame = 4;
- switch (config.output_format) {
- case SPS_FORMAT_S24_LE:
- output_bytes_per_frame=8;
- break;
- case SPS_FORMAT_S32_LE:
- output_bytes_per_frame=8;
- break;
- }
-
- debug(1,"Output frame bytes is %d.",output_bytes_per_frame);
-
- // create and start the timing, control and audio receiver threads
- pthread_t rtp_audio_thread, rtp_control_thread, rtp_timing_thread;
- pthread_create(&rtp_audio_thread, NULL, &rtp_audio_receiver, (void *)&itr);
+ struct inter_threads_record itr;
+ itr.please_stop = 0;
+ timestamp_epoch = 0; // indicate that the next timestamp will be the first one.
+ maximum_timestamp_interval = input_rate * 60; // actually there shouldn't be more than about 13v
+ // seconds of a gap between successive rtptimes, at
+ // worst
+
+ output_sample_ratio = config.output_rate / input_rate;
+
+ debug(1, "Output sample ratio is %d.", output_sample_ratio);
+
+ max_frame_size_change = 1 * output_sample_ratio; // we add or subtract one frame at the nominal
+ // rate, multiply it by the frame ratio.
+
+ output_bytes_per_frame = 4;
+ switch (config.output_format) {
+ case SPS_FORMAT_S24_LE:
+ output_bytes_per_frame = 8;
+ break;
+ case SPS_FORMAT_S32_LE:
+ output_bytes_per_frame = 8;
+ break;
+ }
+
+ debug(1, "Output frame bytes is %d.", output_bytes_per_frame);
+
+ // create and start the timing, control and audio receiver threads
+ pthread_t rtp_audio_thread, rtp_control_thread, rtp_timing_thread;
+ pthread_create(&rtp_audio_thread, NULL, &rtp_audio_receiver, (void *)&itr);
pthread_create(&rtp_control_thread, NULL, &rtp_control_receiver, (void *)&itr);
pthread_create(&rtp_timing_thread, NULL, &rtp_timing_receiver, (void *)&itr);
- session_corrections = 0;
- play_segment_reference_frame = 0; // zero signals that we are not in a play segment
+ session_corrections = 0;
+ play_segment_reference_frame = 0; // zero signals that we are not in a play segment
+ // check that there are enough buffers to accommodate the desired latency and the latency offset
- // check that there are enough buffers to accommodate the desired latency and the latency offset
-
- int maximum_latency = config.latency+config.audio_backend_latency_offset*input_rate;
- if ((maximum_latency+(352-1))/352 + 10 > BUFFER_FRAMES)
- die("Not enough buffers available for a total latency of %d frames. A maximum of %d 352-frame packets may be accommodated.",maximum_latency,BUFFER_FRAMES);
+ int maximum_latency = config.latency + config.audio_backend_latency_offset * input_rate;
+ if ((maximum_latency + (352 - 1)) / 352 + 10 > BUFFER_FRAMES)
+ die("Not enough buffers available for a total latency of %d frames. A maximum of %d 352-frame "
+ "packets may be accommodated.",
+ maximum_latency, BUFFER_FRAMES);
connection_state_to_output = get_requested_connection_state_to_output();
// this is about half a minute
#define trend_interval 3758
signed short *inbuf, *tbuf, *silence;
char *outbuf;
-
+
int inbuflength;
-
+
int output_bit_depth = 16; // default;
-
+
switch (config.output_format) {
- case SPS_FORMAT_S16_LE:
- output_bit_depth = 16;
- break;
- case SPS_FORMAT_S24_LE:
- output_bit_depth = 24;
- break;
- case SPS_FORMAT_S32_LE:
- output_bit_depth = 32;
- break;
+ case SPS_FORMAT_S16_LE:
+ output_bit_depth = 16;
+ break;
+ case SPS_FORMAT_S24_LE:
+ output_bit_depth = 24;
+ break;
+ case SPS_FORMAT_S32_LE:
+ output_bit_depth = 32;
+ break;
}
-
-
- debug(1,"Output bit depth is %d.",output_bit_depth);
- // if we are changing any of the parameters of the input, like sample rate or sample depth, then we
+ debug(1, "Output bit depth is %d.", output_bit_depth);
+
+ // if we are changing any of the parameters of the input, like sample rate or sample depth, then
+ // we
// need an intermediate "transition" buffer
-
+
if (1) {
- //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*(max_frames_per_packet*output_sample_ratio+max_frame_size_change));
- if (tbuf==NULL)
- debug(1,"Failed to allocate 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 *
+ (max_frames_per_packet * output_sample_ratio + max_frame_size_change));
+ if (tbuf == NULL)
+ debug(1, "Failed to allocate memory for the transition buffer.");
} else {
tbuf = 0;
- }
-
+ }
+
// 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));
- if (outbuf==NULL)
- debug(1,"Failed to allocate memory for an output buffer.");
- silence = malloc(output_bytes_per_frame*max_frames_per_packet*output_sample_ratio);
- if (silence==NULL)
- debug(1,"Failed to allocate memory for a silence buffer.");
- memset(silence, 0, output_bytes_per_frame*max_frames_per_packet*output_sample_ratio);
+ // 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));
+ if (outbuf == NULL)
+ debug(1, "Failed to allocate memory for an output buffer.");
+ silence = malloc(output_bytes_per_frame * max_frames_per_packet * output_sample_ratio);
+ if (silence == NULL)
+ debug(1, "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
// 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
+ int sync_error_out_of_bounds =
+ 0; // number of times in a row that there's been a serious sync error
if (config.statistics_requested) {
if ((config.output->delay)) {
- if (config.no_sync==0) {
+ if (config.no_sync == 0) {
inform("sync error in milliseconds, "
"net correction in ppm, "
"corrections in ppm, "
// 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 (inbuf == NULL)
+ debug(1, "NULL inbuf to play -- skipping it.");
else {
- if (inbuflength==0)
- debug(1,"empty frame to play -- skipping it (1).");
+ if (inbuflength == 0)
+ debug(1, "empty frame to play -- skipping it (1).");
else
config.output->play(inbuf, inbuflength);
}
} else {
-
-// int enable_dither = 0;
- int enable_dither = !((fix_volume==0x10000)&&(input_bit_depth==output_bit_depth)); // avoid dither on audio being sent through without alteration
-
+
+ // int enable_dither = 0;
+ int enable_dither =
+ !((fix_volume == 0x10000) &&
+ (input_bit_depth ==
+ output_bit_depth)); // avoid dither on audio being sent through without alteration
+
// here, let's transform the frame of data, if necessary
-
- if (tbuf!=NULL) { //this will be null if no changes are needed
+
+ if (tbuf != NULL) { // this will be null if no changes are needed
switch (input_bit_depth) {
- case 16: {
- int i,j;
- int16_t ls,rs;
- int16_t *inps=inbuf;
- int16_t *outps=tbuf;
- int32_t *outpl=(int32_t*)tbuf;
- for (i=0;i<inbuflength;i++) {
- ls=*inps++;
- rs=*inps++;
-
- // here, do the mode stuff -- mono / reverse stereo / leftonly / rightonly
-
- switch (config.playback_mode) {
- case ST_mono: {
- int both = ls+rs;
- // Note -- this is assuming 16 bit signed.
- if (both > INT16_MAX) {
- both = INT16_MAX;
- } else if (both < INT16_MIN) {
- both = INT16_MIN;
- }
- int16_t sboth = (int16_t)both;
- ls = sboth;
- rs = sboth;
- } break;
- case ST_reverse_stereo: {
- int16_t t = ls;
- ls = rs;
- rs = t;
- } break;
- case ST_left_only:
- rs = ls;
- break;
- case ST_right_only:
- ls = rs;
- break;
- }
-
- // here, replicate the samples if you're upsampling
-
- for (j=0;j<output_sample_ratio;j++) {
- // raise the 16-bit sample to 32 bits.
- int32_t t = ls<<16;
- *outpl++=t;
- int32_t u = rs<<16;
- *outpl++=u;
-
- /*
- switch (output_bit_depth) {
- case 16:
- *outps++=ls;
- *outps++=rs;
- break;
- case 24: {
- int32_t t = ls<<8;
- *outpl++=t;
- int32_t u = rs<<8;
- *outpl++=u;
- } break;
- case 32: {
- int32_t t = ls<<16;
- *outpl++=t;
- int32_t u = rs<<16;
- *outpl++=u;
- } break;
- }
- */
- }
+ case 16: {
+ int i, j;
+ int16_t ls, rs;
+ int16_t *inps = inbuf;
+ int16_t *outps = tbuf;
+ int32_t *outpl = (int32_t *)tbuf;
+ for (i = 0; i < inbuflength; i++) {
+ ls = *inps++;
+ rs = *inps++;
+
+ // here, do the mode stuff -- mono / reverse stereo / leftonly / rightonly
+
+ switch (config.playback_mode) {
+ case ST_mono: {
+ int both = ls + rs;
+ // Note -- this is assuming 16 bit signed.
+ if (both > INT16_MAX) {
+ both = INT16_MAX;
+ } else if (both < INT16_MIN) {
+ both = INT16_MIN;
}
+ int16_t sboth = (int16_t)both;
+ ls = sboth;
+ rs = sboth;
+ } break;
+ case ST_reverse_stereo: {
+ int16_t t = ls;
+ ls = rs;
+ rs = t;
+ } break;
+ case ST_left_only:
+ rs = ls;
+ break;
+ case ST_right_only:
+ ls = rs;
+ break;
+ }
+ // here, replicate the samples if you're upsampling
+
+ for (j = 0; j < output_sample_ratio; j++) {
+ // raise the 16-bit sample to 32 bits.
+ int32_t t = ls << 16;
+ *outpl++ = t;
+ int32_t u = rs << 16;
+ *outpl++ = u;
+
+ /*
+ switch (output_bit_depth) {
+ case 16:
+ *outps++=ls;
+ *outps++=rs;
+ break;
+ case 24: {
+ int32_t t = ls<<8;
+ *outpl++=t;
+ int32_t u = rs<<8;
+ *outpl++=u;
+ } break;
+ case 32: {
+ int32_t t = ls<<16;
+ *outpl++=t;
+ int32_t u = rs<<16;
+ *outpl++=u;
+ } break;
+ }
+ */
}
- break;
- default:
- die("Shairport Sync only supports 16 bit input");
+ }
+
+ } break;
+ default:
+ die("Shairport Sync only supports 16 bit input");
}
-
+
// inbuf = tbuf;
- inbuflength*=output_sample_ratio;
+ inbuflength *= 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.
at_least_one_frame_seen = 1;
int64_t reference_timestamp;
- uint64_t reference_timestamp_time,remote_reference_timestamp_time;
- get_reference_timestamp_stuff(&reference_timestamp, &reference_timestamp_time, &remote_reference_timestamp_time); // types okay
- reference_timestamp*=output_sample_ratio;
+ uint64_t reference_timestamp_time, remote_reference_timestamp_time;
+ get_reference_timestamp_stuff(&reference_timestamp, &reference_timestamp_time,
+ &remote_reference_timestamp_time); // types okay
+ reference_timestamp *= output_sample_ratio;
int64_t rt, nt;
rt = reference_timestamp; // uint32_t to int64_t
- nt = inframe->timestamp; // uint32_t to int64_t
+ nt = inframe->timestamp; // uint32_t to int64_t
uint64_t local_time_now = get_absolute_time_in_fp(); // types okay
// struct timespec tn;
int64_t td = 0;
int64_t td_in_frames = 0;
if (local_time_now >= reference_timestamp_time) {
- // debug(1,"td is %lld.",td);
- td = local_time_now - reference_timestamp_time; // this is the positive value. Conversion is positive uint64_t to int64_t, thus okay
+ // debug(1,"td is %lld.",td);
+ td = local_time_now - reference_timestamp_time; // this is the positive value.
+ // Conversion is positive uint64_t to
+ // int64_t, thus okay
td_in_frames = (td * config.output_rate) >> 32;
} else {
- td = reference_timestamp_time - local_time_now; // this is the absolute value, which should be negated. Conversion is positive uint64_t to int64_t, thus okay.
- td_in_frames = (td * config.output_rate) >> 32; //use the absolute td value for the present. Types okay
+ td = reference_timestamp_time - local_time_now; // this is the absolute value, which
+ // should be negated. Conversion is
+ // positive uint64_t to int64_t, thus
+ // okay.
+ td_in_frames = (td * config.output_rate) >>
+ 32; // use the absolute td value for the present. Types okay
td_in_frames = -td_in_frames;
td = -td; // should be okay, as the range of values should be very small w.r.t 64 bits
}
// check sequencing
if (last_seqno_read == -1)
- last_seqno_read = inframe->sequence_number; //int32_t from seq_t, i.e. uint16_t, so okay.
+ last_seqno_read =
+ inframe->sequence_number; // int32_t from seq_t, i.e. uint16_t, so okay.
else {
- last_seqno_read = SUCCESSOR(last_seqno_read); // int32_t from seq_t, i.e. uint16_t, so okay.
- if (inframe->sequence_number != last_seqno_read) { //seq_t, ei.e. uint16_t and int32_t, so okay
- debug(
- 1,
- "Player: packets out of sequence: expected: %u, got: %u, with ab_read: %u and ab_write: %u.",
- last_seqno_read, inframe->sequence_number,ab_read,ab_write);
+ last_seqno_read =
+ SUCCESSOR(last_seqno_read); // int32_t from seq_t, i.e. uint16_t, so okay.
+ if (inframe->sequence_number !=
+ last_seqno_read) { // seq_t, ei.e. uint16_t and int32_t, so okay
+ debug(1, "Player: packets out of sequence: expected: %u, got: %u, with ab_read: %u "
+ "and ab_write: %u.",
+ last_seqno_read, inframe->sequence_number, ab_read, ab_write);
last_seqno_read = inframe->sequence_number; // reset warning...
}
}
- buffer_occupancy = seq_diff(ab_read, ab_write); // int32_t from int32
+ buffer_occupancy = seq_diff(ab_read, ab_write); // int32_t from int32
- if (buffer_occupancy < minimum_buffer_occupancy)
- minimum_buffer_occupancy = buffer_occupancy;
+ if (buffer_occupancy < minimum_buffer_occupancy)
+ minimum_buffer_occupancy = buffer_occupancy;
- if (buffer_occupancy > maximum_buffer_occupancy)
- maximum_buffer_occupancy = buffer_occupancy;
+ 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, (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
+ int resp = -1; // use this as a flag -- if negative, we can't rely on a real known delay
current_delay = -1; // use this as a failure flag
-
- if (config.output->delay) {
- long l_delay;
- resp = config.output->delay(&l_delay);
- current_delay = l_delay;
- if (resp==0) { // no error
- if (current_delay<0) {
- debug(1,"Underrun of %d frames reported, but ignored.",current_delay);
- current_delay=0; // could get a negative value if there was underrun, but ignore it.
- }
- if (current_delay < minimum_dac_queue_size) {
- minimum_dac_queue_size = current_delay; // update for display later
- }
- } else {
- debug(2, "Delay error %d when checking running latency.",resp);
- }
- }
+
+ if (config.output->delay) {
+ long l_delay;
+ resp = config.output->delay(&l_delay);
+ current_delay = l_delay;
+ if (resp == 0) { // no error
+ if (current_delay < 0) {
+ debug(1, "Underrun of %d frames reported, but ignored.", current_delay);
+ current_delay =
+ 0; // could get a negative value if there was underrun, but ignore it.
+ }
+ if (current_delay < minimum_dac_queue_size) {
+ minimum_dac_queue_size = current_delay; // update for display later
+ }
+ } else {
+ debug(2, "Delay error %d when checking running latency.", resp);
+ }
+ }
if (resp >= 0) {
// this is the actual delay, including the latency we actually want, which will
// fluctuate a good bit about a potentially rising or falling trend.
int64_t delay = td_in_frames + rt - (nt - current_delay); // all int64_t
-
// This is the timing error for the next audio frame in the DAC.
- sync_error = delay - config.latency*output_sample_ratio; // int64_t from int64_t - int32_t, so okay
+ sync_error =
+ delay -
+ config.latency * output_sample_ratio; // int64_t from int64_t - int32_t, so okay
// if (llabs(sync_error)>352*512)
// debug(1,"Very large sync error: %lld",sync_error);
// before we finally commit to this frame, check its sequencing and timing
// require a certain error before bothering to fix it...
- if (sync_error > config.tolerance*config.output_rate) { // int64_t > int, okay
+ if (sync_error > config.tolerance * config.output_rate) { // int64_t > int, okay
amount_to_stuff = -1;
}
- if (sync_error < -config.tolerance*config.output_rate) {
+ if (sync_error < -config.tolerance * config.output_rate) {
amount_to_stuff = 1;
}
}
// try to keep the corrections definitely below 1 in 1000 audio frames
-
+
// calculate the time elapsed since the play session started.
-
+
if (amount_to_stuff) {
- if ((local_time_now) && (first_packet_time_to_play) && (local_time_now >= first_packet_time_to_play)) {
+ if ((local_time_now) && (first_packet_time_to_play) &&
+ (local_time_now >= first_packet_time_to_play)) {
+
+ int64_t tp = (local_time_now - first_packet_time_to_play) >>
+ 32; // seconds int64_t from uint64_t which is always positive, so ok
- int64_t tp = (local_time_now - first_packet_time_to_play)>>32; // seconds int64_t from uint64_t which is always positive, so ok
-
- if (tp<5)
+ if (tp < 5)
amount_to_stuff = 0; // wait at least five seconds
- else if (tp<30) {
- if ((random() % 1000) > 352) // keep it to about 1:1000 for the first thirty seconds
+ else if (tp < 30) {
+ if ((random() % 1000) >
+ 352) // keep it to about 1:1000 for the first thirty seconds
amount_to_stuff = 0;
}
}
}
-
- if (config.no_sync!=0)
- amount_to_stuff = 0 ; // no stuffing if it's been disabled
-
+
+ if (config.no_sync != 0)
+ amount_to_stuff = 0; // no stuffing if it's been disabled
#ifdef HAVE_LIBSOXR
switch (config.packet_stuffing) {
case ST_basic:
// if (amount_to_stuff) debug(1,"Basic stuff...");
if (tbuf) {
- play_samples = stuff_buffer_basic_32((int32_t*)tbuf, inbuflength, config.output_format, outbuf, amount_to_stuff, enable_dither);
- }
- else
- play_samples = stuff_buffer_basic(inbuf, inbuflength, (short *)outbuf, amount_to_stuff);
+ play_samples =
+ stuff_buffer_basic_32((int32_t *)tbuf, inbuflength, config.output_format,
+ outbuf, amount_to_stuff, enable_dither);
+ } else
+ play_samples =
+ stuff_buffer_basic(inbuf, inbuflength, (short *)outbuf, amount_to_stuff);
break;
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, inbuflength, (int32_t *)outbuf,
+ amount_to_stuff, output_bit_depth);
else
- play_samples = stuff_buffer_soxr(inbuf, inbuflength, (short *)outbuf, amount_to_stuff);
+ play_samples =
+ stuff_buffer_soxr(inbuf, inbuflength, (short *)outbuf, amount_to_stuff);
break;
}
#else
// if (amount_to_stuff) debug(1,"Standard stuff...");
if (tbuf)
- play_samples = stuff_buffer_basic_32((int32_t*)tbuf, inbuflength, config.output_format, outbuf, amount_to_stuff, enable_dither);
+ play_samples =
+ stuff_buffer_basic_32((int32_t *)tbuf, inbuflength, config.output_format, outbuf,
+ amount_to_stuff, enable_dither);
else
- play_samples = stuff_buffer_basic(inbuf, inbuflength, (short *)outbuf, amount_to_stuff);
+ play_samples =
+ stuff_buffer_basic(inbuf, inbuflength, (short *)outbuf, amount_to_stuff);
#endif
/*
debug(1,"Silence!");
}
*/
-
-
- if (outbuf==NULL)
- debug(1,"NULL outbuf to play -- skipping it.");
+
+ if (outbuf == NULL)
+ debug(1, "NULL outbuf to play -- skipping it.");
else {
- if (play_samples==0)
- debug(1,"play_samples==0 skipping it (1).");
+ if (play_samples == 0)
+ debug(1, "play_samples==0 skipping it (1).");
else
- config.output->play((short*)outbuf, play_samples); // remove the (short*)!
+ config.output->play((short *)outbuf, play_samples); // remove the (short*)!
}
-
+
// check for loss of sync
// timestamp of zero means an inserted silent frame in place of a missing frame
-
+
// not too sure if abs() is implemented for int64_t, so we'll do it manually
int64_t abs_sync_error = sync_error;
- if (abs_sync_error<0)
+ if (abs_sync_error < 0)
abs_sync_error = -abs_sync_error;
-
- if ((config.no_sync==0) && (inframe->timestamp != 0) && (!please_stop) && (config.resyncthreshold > 0.0) &&
- (abs_sync_error > config.resyncthreshold*config.output_rate)) {
+
+ if ((config.no_sync == 0) && (inframe->timestamp != 0) && (!please_stop) &&
+ (config.resyncthreshold > 0.0) &&
+ (abs_sync_error > config.resyncthreshold * config.output_rate)) {
sync_error_out_of_bounds++;
// debug(1,"Sync error out of bounds: Error: %lld; previous error: %lld; DAC: %lld;
// timestamp: %llx, time now
sync_error_out_of_bounds = 0;
}
} else {
- // if there is no delay procedure, or it's not working or not allowed, there can be no synchronising
-
+ // if there is no delay procedure, or it's not working or not allowed, there can be no
+ // synchronising
+
if (fix_volume == 0x10000)
-
- if (inbuf==NULL)
- debug(1,"NULL inbuf to play -- skipping it.");
+
+ if (inbuf == NULL)
+ debug(1, "NULL inbuf to play -- skipping it.");
else {
- if (inbuflength==0)
- debug(1,"empty frame to play -- skipping it (3).");
+ if (inbuflength == 0)
+ debug(1, "empty frame to play -- skipping it (3).");
else
config.output->play(inbuf, inbuflength);
}
else {
if (tbuf)
- play_samples = stuff_buffer_basic_32((int32_t*)tbuf, inbuflength, config.output_format, outbuf, 0, enable_dither);
+ play_samples = stuff_buffer_basic_32(
+ (int32_t *)tbuf, inbuflength, config.output_format, outbuf, 0, enable_dither);
else
- play_samples = stuff_buffer_basic(inbuf, inbuflength, (short *)outbuf, 0); // no stuffing, but volume adjustment
+ play_samples = stuff_buffer_basic(inbuf, inbuflength, (short *)outbuf,
+ 0); // no stuffing, but volume adjustment
- if (outbuf==NULL)
- debug(1,"NULL outbuf to play -- skipping it.");
+ if (outbuf == NULL)
+ debug(1, "NULL outbuf to play -- skipping it.");
else {
- if (inbuf==0)
- debug(1,"empty frame to play -- skipping it (4).");
+ if (inbuf == 0)
+ debug(1, "empty frame to play -- skipping it (4).");
else
- config.output->play((short*)outbuf, play_samples); // remove the (short*)!
+ config.output->play((short *)outbuf, play_samples); // remove the (short*)!
}
}
}
// new stats calculation. We want a running average of sync error, drift, adjustment,
// number of additions+subtractions
-
- // this is a misleading hack -- the statistics should include some data on the number of valid samples and the number of times sync wasn't checked due to non availability of a delay figure.
+
+ // this is a misleading hack -- the statistics should include some data on the number of
+ // valid samples and the number of times sync wasn't checked due to non availability of a
+ // delay figure.
// for the present, stats are only updated when sync has been checked
- if (sync_error!=-1) {
+ if (sync_error != -1) {
if (number_of_statistics == trend_interval) {
// here we remove the oldest statistical data and take it from the summaries as well
tsum_of_sync_errors -= statistics[oldest_statistic].sync_error;
tsum_of_corrections += amount_to_stuff;
session_corrections += amount_to_stuff;
-
newest_statistic = (newest_statistic + 1) % trend_interval;
number_of_statistics++;
- }
+ }
}
if (play_number % print_interval == 0) {
// we can now calculate running averages for sync error (frames), corrections (ppm),
// if ((play_number/print_interval)%20==0)
if (config.statistics_requested) {
if (at_least_one_frame_seen) {
- if ((config.output->delay)) {
- if (config.no_sync==0) {
- inform("%*.1f," /* Sync error in milliseconds */
- "%*.1f," /* net correction in ppm */
- "%*.1f," /* corrections in ppm */
- "%*d," /* total packets */
- "%*llu," /* missing packets */
- "%*llu," /* late packets */
- "%*llu," /* too late packets */
- "%*llu," /* resend requests */
- "%*lli," /* min DAC queue size */
- "%*d," /* min buffer occupancy */
- "%*d", /* max buffer occupancy */
- 10, 1000*moving_average_sync_error/config.output_rate,
- 10, moving_average_correction * 1000000 / (352*output_sample_ratio),
- 10, moving_average_insertions_plus_deletions * 1000000 / (352*output_sample_ratio),
- 12, play_number,
- 7, missing_packets,
- 7, late_packets,
- 7, too_late_packets,
- 7, resend_requests,
- 7, minimum_dac_queue_size,
- 5, minimum_buffer_occupancy,
+ if ((config.output->delay)) {
+ if (config.no_sync == 0) {
+ inform("%*.1f," /* Sync error in milliseconds */
+ "%*.1f," /* net correction in ppm */
+ "%*.1f," /* corrections in ppm */
+ "%*d," /* total packets */
+ "%*llu," /* missing packets */
+ "%*llu," /* late packets */
+ "%*llu," /* too late packets */
+ "%*llu," /* resend requests */
+ "%*lli," /* min DAC queue size */
+ "%*d," /* min buffer occupancy */
+ "%*d", /* max buffer occupancy */
+ 10,
+ 1000 * moving_average_sync_error / config.output_rate, 10,
+ moving_average_correction * 1000000 / (352 * output_sample_ratio), 10,
+ moving_average_insertions_plus_deletions * 1000000 /
+ (352 * output_sample_ratio),
+ 12, play_number, 7, missing_packets, 7, late_packets, 7, too_late_packets,
+ 7, resend_requests, 7, minimum_dac_queue_size, 5, minimum_buffer_occupancy,
5, maximum_buffer_occupancy);
} else {
- inform("%*.1f," /* Sync error in milliseconds */
- "%*d," /* total packets */
- "%*llu," /* missing packets */
- "%*llu," /* late packets */
- "%*llu," /* too late packets */
- "%*llu," /* resend requests */
- "%*lli," /* min DAC queue size */
- "%*d," /* min buffer occupancy */
- "%*d", /* max buffer occupancy */
- 10, 1000*moving_average_sync_error/config.output_rate,
- 12, play_number,
- 7, missing_packets,
- 7, late_packets,
- 7, too_late_packets,
- 7, resend_requests,
- 7, minimum_dac_queue_size,
- 5, minimum_buffer_occupancy,
- 5, maximum_buffer_occupancy);
- }
+ inform("%*.1f," /* Sync error in milliseconds */
+ "%*d," /* total packets */
+ "%*llu," /* missing packets */
+ "%*llu," /* late packets */
+ "%*llu," /* too late packets */
+ "%*llu," /* resend requests */
+ "%*lli," /* min DAC queue size */
+ "%*d," /* min buffer occupancy */
+ "%*d", /* max buffer occupancy */
+ 10,
+ 1000 * moving_average_sync_error / config.output_rate, 12, play_number, 7,
+ missing_packets, 7, late_packets, 7, too_late_packets, 7, resend_requests,
+ 7, minimum_dac_queue_size, 5, minimum_buffer_occupancy, 5,
+ maximum_buffer_occupancy);
+ }
} else {
- inform("%*.1f," /* Sync error in milliseconds */
- "%*d," /* total packets */
- "%*llu," /* missing packets */
- "%*llu," /* late packets */
- "%*llu," /* too late packets */
- "%*llu," /* resend requests */
- "%*d," /* min buffer occupancy */
- "%*d", /* max buffer occupancy */
- 10, 1000*moving_average_sync_error/config.output_rate,
- 12, play_number,
- 7, missing_packets,
- 7, late_packets,
- 7, too_late_packets,
- 7, resend_requests,
- 5, minimum_buffer_occupancy,
- 5, maximum_buffer_occupancy);
+ inform("%*.1f," /* Sync error in milliseconds */
+ "%*d," /* total packets */
+ "%*llu," /* missing packets */
+ "%*llu," /* late packets */
+ "%*llu," /* too late packets */
+ "%*llu," /* resend requests */
+ "%*d," /* min buffer occupancy */
+ "%*d", /* max buffer occupancy */
+ 10,
+ 1000 * moving_average_sync_error / config.output_rate, 12, play_number, 7,
+ missing_packets, 7, late_packets, 7, too_late_packets, 7, resend_requests, 5,
+ minimum_buffer_occupancy, 5, maximum_buffer_occupancy);
}
} else {
inform("No frames received in the last sampling interval.");
}
if (config.statistics_requested) {
- int rawSeconds = (int) difftime( time( NULL ), playstart );
- int elapsedHours = rawSeconds / 3600;
- int elapsedMin = (rawSeconds / 60) % 60;
- int elapsedSec = rawSeconds % 60;
- inform( "Playback Stopped. Total playing time %02d:%02d:%02d\n", elapsedHours, elapsedMin, elapsedSec );
+ int rawSeconds = (int)difftime(time(NULL), playstart);
+ int elapsedHours = rawSeconds / 3600;
+ int elapsedMin = (rawSeconds / 60) % 60;
+ int elapsedSec = rawSeconds % 60;
+ inform("Playback Stopped. Total playing time %02d:%02d:%02d\n", elapsedHours, elapsedMin,
+ elapsedSec);
}
if (config.output->stop)
- config.output->stop();
- usleep(100000); // allow this time to (?) allow the alsa subsystem to finish cleaning up after itself. 50 ms seems too short
+ config.output->stop();
+ usleep(100000); // allow this time to (?) allow the alsa subsystem to finish cleaning up after
+ // itself. 50 ms seems too short
free(outbuf);
free(silence);
if (tbuf)
free(tbuf);
- debug(1,"Shut down audio, control and timing threads");
+ debug(1, "Shut down audio, control and timing threads");
itr.please_stop = 1;
pthread_kill(rtp_audio_thread, SIGUSR1);
pthread_kill(rtp_control_thread, SIGUSR1);
pthread_kill(rtp_timing_thread, SIGUSR1);
pthread_join(rtp_timing_thread, NULL);
- debug(1,"timing thread joined");
+ debug(1, "timing thread joined");
pthread_join(rtp_audio_thread, NULL);
- debug(1,"audio thread joined");
+ debug(1, "audio thread joined");
pthread_join(rtp_control_thread, NULL);
- debug(1,"control thread joined");
- debug(1,"Player thread exit");
+ debug(1, "control thread joined");
+ debug(1, "Player thread exit");
return 0;
}
// By examination, the -30 -- 0 range is linear on the slider; i.e. the slider is calibrated in 30
// equal increments. Since the human ear's response is roughly logarithmic, we imagine these to
// be power dB, i.e. from -30dB to 0dB.
-
+
// We may have a hardware mixer, and if so, we will give it priority.
// If a desired volume range is given, then we will try to accommodate it from
// the top of the hardware mixer's range downwards.
-
- // If no desired volume range is given, we will use the native resolution of the hardware mixer, if any,
- // or failing that, the software mixer. The software mixer has a range of from -96.3 dB up to 0 dB,
+
+ // If no desired volume range is given, we will use the native resolution of the hardware mixer,
+ // if any,
+ // or failing that, the software mixer. The software mixer has a range of from -96.3 dB up to 0
+ // dB,
// corresponding to a multiplier of 1 to 65535.
-
- // Otherwise, we will accommodate the desired volume range in the combination of the software and hardware mixer
+
+ // Otherwise, we will accommodate the desired volume range in the combination of the software and
+ // hardware mixer
// Intuitively (!), it seems best to give the hardware mixer as big a role as possible, so
// we will use its full range and then accommodate the rest of the attenuation in software.
// A problem is that we don't know whether the lowest hardware volume actually mutes the output
- // so we must assume that it does, and for this reason, the volume control goes at the "bottom" of the adjustment range
-
+ // so we must assume that it does, and for this reason, the volume control goes at the "bottom" of
+ // the adjustment range
+
// The dB range of a value from 1 to 65536 is about 96.3 dB (log10 of 65536 is 4.8164).
// Since the levels correspond with amplitude, they correspond to voltage, hence voltage dB,
// 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.
-
- int32_t hw_min_db, hw_max_db, hw_range_db, range_to_use, min_db, max_db; // hw_range_db is a flag; if 0 means no mixer
-
+
+ int32_t hw_min_db, hw_max_db, hw_range_db, range_to_use, min_db,
+ max_db; // hw_range_db is a flag; if 0 means no mixer
+
int32_t sw_min_db = -9630;
int32_t sw_max_db = 0;
int32_t sw_range_db = sw_max_db - sw_min_db;
int32_t desired_range_db; // this is used as a flag; if 0 means no desired range
-
+
if (config.volume_range_db)
- desired_range_db = (int32_t)trunc(config.volume_range_db*100);
+ desired_range_db = (int32_t)trunc(config.volume_range_db * 100);
else
desired_range_db = 0;
-
+
if (config.output->parameters) {
// have a hardware mixer
config.output->parameters(&audio_information);
hw_max_db = audio_information.maximum_volume_dB;
hw_min_db = audio_information.minimum_volume_dB;
- hw_range_db = hw_max_db-hw_min_db;
+ hw_range_db = hw_max_db - hw_min_db;
} else {
// don't have a hardware mixer
hw_max_db = hw_min_db = hw_range_db = 0;
}
-
+
if (desired_range_db) {
// debug(1,"An attenuation range of %d is requested.",desired_range_db);
// we have a desired volume range.
if (hw_range_db) {
- // we have a hardware mixer
- if (hw_range_db>=desired_range_db) {
+ // we have a hardware mixer
+ if (hw_range_db >= desired_range_db) {
// the hardware mixer can accommodate the desired range
max_db = hw_max_db;
min_db = max_db - desired_range_db;
} else {
- if ((hw_range_db+sw_range_db)<desired_range_db) {
- inform("The volume attenuation range %f is greater than can be accommodated by the hardware and software -- set to %f.",config.volume_range_db,hw_range_db+sw_range_db);
- desired_range_db=hw_range_db+sw_range_db;
+ if ((hw_range_db + sw_range_db) < desired_range_db) {
+ inform("The volume attenuation range %f is greater than can be accommodated by the "
+ "hardware and software -- set to %f.",
+ config.volume_range_db, hw_range_db + sw_range_db);
+ desired_range_db = hw_range_db + sw_range_db;
}
min_db = hw_min_db;
max_db = min_db + desired_range_db;
}
} else {
// we have a desired volume range and no hardware mixer
- if (sw_range_db<desired_range_db) {
- inform("The volume attenuation range %f is greater than can be accommodated by the software -- set to %f.",config.volume_range_db,sw_range_db);
- desired_range_db=sw_range_db;
+ if (sw_range_db < desired_range_db) {
+ inform("The volume attenuation range %f is greater than can be accommodated by the "
+ "software -- set to %f.",
+ config.volume_range_db, sw_range_db);
+ desired_range_db = sw_range_db;
}
max_db = sw_max_db;
min_db = max_db - desired_range_db;
max_db = sw_max_db;
}
}
-
+
double hardware_attenuation, software_attenuation;
- double scaled_attenuation = hw_min_db+sw_min_db;
-
+ double scaled_attenuation = hw_min_db + sw_min_db;
+
// now, we can map the input to the desired output volume
- if (airplay_volume==-144.0) {
- // do a mute
+ if (airplay_volume == -144.0) {
+ // do a mute
// needed even with hardware mute, as when sound is unmuted it might otherwise be very loud.
- hardware_attenuation = hw_min_db;
- software_attenuation = sw_min_db;
- if (config.output->mute)
- config.output->mute(1); // use real mute if it's there
-
+ hardware_attenuation = hw_min_db;
+ software_attenuation = sw_min_db;
+ if (config.output->mute)
+ config.output->mute(1); // use real mute if it's there
+
} else {
- if (config.output->mute)
- config.output->mute(0); // unmute mute if it's there
+ if (config.output->mute)
+ config.output->mute(0); // unmute mute if it's there
scaled_attenuation = vol2attn(airplay_volume, max_db, min_db);
if (hw_range_db) {
// if there is a hardware mixer
- if (scaled_attenuation<=hw_max_db) {
+ if (scaled_attenuation <= hw_max_db) {
// the attenuation is so low that's it's in the hardware mixer's range
// debug(1,"Attenuation all taken care of by the hardware mixer.");
hardware_attenuation = scaled_attenuation;
- software_attenuation = sw_max_db - (max_db-hw_max_db); // e.g. if the hw_max_db is +4 and the max is +40, this will be -36 (all by 100, of course)
+ software_attenuation = sw_max_db - (max_db - hw_max_db); // e.g. if the hw_max_db is +4 and
+ // the max is +40, this will be -36
+ // (all by 100, of course)
} else {
// debug(1,"Attenuation taken care of by hardware and software mixer.");
hardware_attenuation = hw_max_db; // the hardware mixer is turned up full
- software_attenuation = sw_max_db - (max_db-scaled_attenuation);
+ software_attenuation = sw_max_db - (max_db - scaled_attenuation);
}
} else {
// if there is no hardware mixer, the scaled_volume is the software volume
software_attenuation = scaled_attenuation;
}
}
-
+
if ((config.output->volume) && (hw_range_db)) {
- config.output->volume(hardware_attenuation); // otherwise set the output to the lowest value
- //debug(1,"Hardware attenuation set to %f for airplay volume of %f.",hardware_attenuation,airplay_volume);
+ config.output->volume(hardware_attenuation); // otherwise set the output to the lowest value
+ // debug(1,"Hardware attenuation set to %f for airplay volume of
+ // %f.",hardware_attenuation,airplay_volume);
}
double temp_fix_volume = 65536.0 * pow(10, software_attenuation / 2000);
- // 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);
-
+ // 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);
char *dv = malloc(128); // will be freed in the metadata thread
if (dv) {
memset(dv, 0, 128);
- snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume,
- scaled_attenuation / 100.0,
- min_db / 100.0,
- max_db / 100.0);
+ snprintf(dv, 127, "%.2f,%.2f,%.2f,%.2f", airplay_volume, scaled_attenuation / 100.0,
+ min_db / 100.0, max_db / 100.0);
send_ssnc_metadata('pvol', dv, strlen(dv), 1);
}
#endif
}
void player_flush(int64_t timestamp) {
- debug(3,"Flush requested up to %u. It seems as if 0 is special.",timestamp);
+ debug(3, "Flush requested up to %u. It seems as if 0 is special.", timestamp);
pthread_mutex_lock(&flush_mutex);
flush_requested = 1;
// if (timestamp!=0)
}
int player_play(stream_cfg *stream, pthread_t *player_thread) {
- //if (*player_thread!=NULL)
- // die("Trying to create a second player thread for this RTSP session");
+ // if (*player_thread!=NULL)
+ // die("Trying to create a second player thread for this RTSP session");
packet_count = 0;
encrypted = stream->encrypted;
if (config.buffer_start_fill > BUFFER_FRAMES)
#endif
if (rc)
debug(1, "Error initialising condition variable.");
- config.output->start(config.output_rate,config.output_format);
+ config.output->start(config.output_rate, config.output_format);
size_t size = (PTHREAD_STACK_MIN + 256 * 1024);
pthread_attr_t tattr;
pthread_attr_init(&tattr);
}
void player_stop(pthread_t *player_thread) {
- //if (*thread==NULL)
- // debug(1,"Trying to stop a non-existent player thread");
- // else {
- please_stop = 1;
- pthread_cond_signal(&flowcontrol); // tell it to give up
- pthread_join(*player_thread, NULL);
- #ifdef CONFIG_METADATA
- send_ssnc_metadata('pend', NULL, 0, 1);
- #endif
- command_stop();
- free_buffer();
- terminate_decoders();
- int rc = pthread_cond_destroy(&flowcontrol);
- if (rc)
- debug(1, "Error destroying condition variable.");
- // }
+ // if (*thread==NULL)
+ // debug(1,"Trying to stop a non-existent player thread");
+ // else {
+ please_stop = 1;
+ pthread_cond_signal(&flowcontrol); // tell it to give up
+ pthread_join(*player_thread, NULL);
+#ifdef CONFIG_METADATA
+ send_ssnc_metadata('pend', NULL, 0, 1);
+#endif
+ command_stop();
+ free_buffer();
+ terminate_decoders();
+ int rc = pthread_cond_destroy(&flowcontrol);
+ if (rc)
+ debug(1, "Error destroying condition variable.");
+ // }
}
void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len);
-int64_t monotonic_timestamp(uint32_t timestamp); // add an epoch to the timestamp. The monotonic timestamp guaranteed to start between 2^32 2^33 frames and continue up to 2^64 frames
+int64_t monotonic_timestamp(uint32_t timestamp); // add an epoch to the timestamp. The monotonic
+ // timestamp guaranteed to start between 2^32 2^33
+ // frames and continue up to 2^64 frames
// which is about 2*10^8 * 1,000 seconds at 384,000 frames per second -- about 2 trillion seconds.
-// assumes, without checking, that successive timestamps in a series always span an interval of less than one minute.
+// assumes, without checking, that successive timestamps in a series always span an interval of less
+// than one minute.
-uint64_t monotonic_seqno(uint16_t seq_no); // add an epoch to the seq_no. Uses the accompanying timstamp to detemine the correct epoch
+uint64_t monotonic_seqno(uint16_t seq_no); // add an epoch to the seq_no. Uses the accompanying
+ // timstamp to detemine the correct epoch
#endif //_PLAYER_H
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <time.h>
-#include <pthread.h>
-#include <signal.h>
-#include <unistd.h>
-#include <memory.h>
-#include <math.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
#include <arpa/inet.h>
+#include <errno.h>
+#include <math.h>
+#include <memory.h>
#include <netdb.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <signal.h>
#include <stdio.h>
-#include <errno.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
#include "common.h"
#include "player.h"
static int running = 0;
static char client_ip_string[INET6_ADDRSTRLEN]; // the ip string pointing to the client
-static char self_ip_string[INET6_ADDRSTRLEN]; // the ip string being used by this program -- it could be one of many, so we need to know it
-static uint32_t self_scope_id; // if it's an ipv6 connection, this will be its scope
-static short connection_ip_family; // AF_INET / AF_INET6
-static uint32_t client_active_remote; // used when you want to control the client...
+static char self_ip_string[INET6_ADDRSTRLEN]; // the ip string being used by this program -- it
+ // could be one of many, so we need to know it
+static uint32_t self_scope_id; // if it's an ipv6 connection, this will be its scope
+static short connection_ip_family; // AF_INET / AF_INET6
+static uint32_t client_active_remote; // used when you want to control the client...
static SOCKADDR rtp_client_control_socket; // a socket pointing to the control port of the client
static SOCKADDR rtp_client_timing_socket; // a socket pointing to the timing port of the client
static int audio_socket; // our local [server] audio socket
static int control_socket; // our local [server] control socket
static int timing_socket; // local timing socket
-//static pthread_t rtp_audio_thread, rtp_control_thread, rtp_timing_thread;
+// static pthread_t rtp_audio_thread, rtp_control_thread, rtp_timing_thread;
static int64_t reference_timestamp;
static uint64_t reference_timestamp_time;
uint64_t time_of_previous_packet_fp = 0;
float longest_packet_time_interval_us = 0.0;
-
- // mean and variance calculations from "online_variance" algorithm at https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Online_algorithm
-
+
+ // mean and variance calculations from "online_variance" algorithm at
+ // https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Online_algorithm
+
int32_t stat_n = 0;
float stat_mean = 0.0;
float stat_M2 = 0.0;
-
+
ssize_t nread;
- while (itr->please_stop==0) {
+ while (itr->please_stop == 0) {
nread = recv(audio_socket, packet, sizeof(packet), 0);
-
+
uint64_t local_time_now_fp = get_absolute_time_in_fp();
if (time_of_previous_packet_fp) {
- float time_interval_us = (((local_time_now_fp - time_of_previous_packet_fp)*1000000)>>32)*1.0;
+ float time_interval_us =
+ (((local_time_now_fp - time_of_previous_packet_fp) * 1000000) >> 32) * 1.0;
time_of_previous_packet_fp = local_time_now_fp;
- if (time_interval_us>longest_packet_time_interval_us)
- longest_packet_time_interval_us=time_interval_us;
- stat_n+=1;
+ if (time_interval_us > longest_packet_time_interval_us)
+ longest_packet_time_interval_us = time_interval_us;
+ stat_n += 1;
float stat_delta = time_interval_us - stat_mean;
- stat_mean += stat_delta/stat_n;
- stat_M2 += stat_delta*(time_interval_us - stat_mean);
+ stat_mean += stat_delta / stat_n;
+ stat_M2 += stat_delta * (time_interval_us - stat_mean);
if (stat_n % 2500 == 0) {
- debug(2,"Packet reception interval stats: mean, standard deviation and max for the last 2,500 packets in microseconds: %10.1f, %10.1f, %10.1f.",stat_mean, sqrtf(stat_M2 / (stat_n-1)),longest_packet_time_interval_us);
+ debug(2, "Packet reception interval stats: mean, standard deviation and max for the last "
+ "2,500 packets in microseconds: %10.1f, %10.1f, %10.1f.",
+ stat_mean, sqrtf(stat_M2 / (stat_n - 1)), longest_packet_time_interval_us);
stat_n = 0;
stat_mean = 0.0;
stat_M2 = 0.0;
last_seqno = seqno;
else {
last_seqno = (last_seqno + 1) & 0xffff;
- //if (seqno != last_seqno)
+ // if (seqno != last_seqno)
// debug(3, "RTP: Packets out of sequence: expected: %d, got %d.", last_seqno, seqno);
last_seqno = seqno; // reset warning...
}
uint64_t remote_time_of_sync, local_time_now, remote_time_now;
int64_t sync_rtp_timestamp, rtp_timestamp_less_latency;
ssize_t nread;
- while (itr->please_stop==0) {
+ while (itr->please_stop == 0) {
nread = recv(control_socket, packet, sizeof(packet), 0);
local_time_now = get_absolute_time_in_fp();
// clock_gettime(CLOCK_MONOTONIC,&tn);
rtp_timestamp_less_latency = monotonic_timestamp(ntohl(*((uint32_t *)&packet[4])));
sync_rtp_timestamp = monotonic_timestamp(ntohl(*((uint32_t *)&packet[16])));
-
+
if (config.use_negotiated_latencies) {
- int64_t la = sync_rtp_timestamp-rtp_timestamp_less_latency+11025;
- if (la!=config.latency) {
+ int64_t la = sync_rtp_timestamp - rtp_timestamp_less_latency + 11025;
+ if (la != config.latency) {
config.latency = la;
// debug(1,"Using negotiated latency of %u frames.",config.latency);
}
}
-
+
if (packet[0] & 0x10) {
// if it's a packet right after a flush or resume
sync_rtp_timestamp += 352; // add frame_size -- can't see a reference to this anywhere,
}
} else if (packet[1] == 0xd6) { // resent audio data in the control path -- whaale only?
// debug(1, "Control Port -- Retransmitted Audio Data Packet received.");
- pktp = packet+4;
+ pktp = packet + 4;
plen -= 4;
seq_t seqno = ntohs(*(unsigned short *)(pktp + 2));
void *rtp_timing_sender(void *arg) {
debug(2, "Timing sender thread starting.");
- int *stop = arg; // the parameter points to this request to stop thing
+ int *stop = arg; // the parameter points to this request to stop thing
struct timing_request {
char leader;
char type;
time_ping_count = 0;
// we inherit the signal mask (SIGUSR1)
- while (*stop==0) {
- // debug(1,"Send a timing request");
+ while (*stop == 0) {
+ // debug(1,"Send a timing request");
if (!running)
die("rtp_timing_sender called without active stream!");
debug(2, "Timing receiver -- Server RTP thread starting.");
// we inherit the signal mask (SIGUSR1)
- struct inter_threads_record *itr = arg;
+ struct inter_threads_record *itr = arg;
uint8_t packet[2048], *pktp;
ssize_t nread;
local_to_remote_time_jitters_count = 0;
uint64_t first_remote_time = 0;
uint64_t first_local_time = 0;
-
+
uint64_t first_local_to_remote_time_difference = 0;
uint64_t first_local_to_remote_time_difference_time;
uint64_t l2rtd = 0;
- while (itr->please_stop==0) {
+ while (itr->please_stop == 0) {
nread = recv(timing_socket, packet, sizeof(packet), 0);
arrival_time = get_absolute_time_in_fp();
// clock_gettime(CLOCK_MONOTONIC,&att);
// these are for diagnostics only -- not used
time_pings[0].local_time = arrival_time;
time_pings[0].remote_time = distant_transmit_time;
-
+
time_pings[0].local_to_remote_difference = local_time_by_remote_clock - arrival_time;
time_pings[0].dispersion = return_time;
if (time_ping_count < time_ping_history)
time_ping_count++;
-
- uint64_t local_time_chosen = arrival_time;;
+
+ uint64_t local_time_chosen = arrival_time;
+ ;
uint64_t remote_time_chosen = distant_transmit_time;
// now pick the timestamp with the lowest dispersion
uint64_t l2rtd = time_pings[0].local_to_remote_difference;
// with dispersion of %lld us with delta of %lld us",rtus,ji);
local_to_remote_time_difference = l2rtd;
- if (first_local_to_remote_time_difference==0) {
+ if (first_local_to_remote_time_difference == 0) {
first_local_to_remote_time_difference = local_to_remote_time_difference;
first_local_to_remote_time_difference_time = get_absolute_time_in_fp();
}
-
+
int64_t clock_drift, clock_drift_in_usec;
- if (first_local_time==0) {
+ if (first_local_time == 0) {
first_local_time = local_time_chosen;
first_remote_time = remote_time_chosen;
uint64_t clock_drift = 0;
} else {
uint64_t local_time_change = local_time_chosen - first_local_time;
uint64_t remote_time_change = remote_time_chosen - first_remote_time;
-
if (remote_time_change >= local_time_change)
clock_drift = remote_time_change - local_time_change;
else
clock_drift = -(local_time_change - remote_time_change);
}
- if (clock_drift>=0)
- clock_drift_in_usec = (clock_drift * 1000000)>>32;
- else
- clock_drift_in_usec = -(((-clock_drift) * 1000000)>>32);
-
-
-
- int64_t source_drift_usec;
- if (play_segment_reference_frame!=0) {
- int64_t reference_timestamp;
- uint64_t reference_timestamp_time,remote_reference_timestamp_time;
- get_reference_timestamp_stuff(&reference_timestamp, &reference_timestamp_time, &remote_reference_timestamp_time);
- uint64_t frame_difference = 0;
- if (reference_timestamp>=play_segment_reference_frame)
- frame_difference = (uint64_t)reference_timestamp-(uint64_t)play_segment_reference_frame;
- else // rollover
- frame_difference = (uint64_t)reference_timestamp+0x100000000-(uint64_t)play_segment_reference_frame;
- uint64_t frame_time_difference_calculated = (((uint64_t)frame_difference<<32)/44100);
- uint64_t frame_time_difference_actual = remote_reference_timestamp_time-play_segment_reference_frame_remote_time; // this is all done by reference to the sources' system clock
- // debug(1,"%llu frames since play started, %llu usec calculated, %llu usec actual",frame_difference, (frame_time_difference_calculated*1000000)>>32, (frame_time_difference_actual*1000000)>>32);
- if (frame_time_difference_calculated>=frame_time_difference_actual) // i.e. if the time it should have taken to send the packets is greater than the actual time difference measured on the source clock
- // then the source DAC's clock is running fast relative to the source system clock
- source_drift_usec = frame_time_difference_calculated-frame_time_difference_actual;
+ if (clock_drift >= 0)
+ clock_drift_in_usec = (clock_drift * 1000000) >> 32;
else
- // otherwise the source DAC's clock is running slow relative to the source system clock
- source_drift_usec = -(frame_time_difference_actual-frame_time_difference_calculated);
- } else
- source_drift_usec = 0;
- source_drift_usec = (source_drift_usec*1000000)>>32; // turn it to microseconds
-
- //long current_delay = 0;
- //if (config.output->delay) {
- // config.output->delay(¤t_delay);
- //}
- // Useful for troubleshooting:
- // clock_drift between source and local clock -- +ve means source is faster
- // session_corrections -- the amount of correction done, in microseconds. +ve means frames added
- // current_delay = delay in DAC buffer in frames
- // source_drift_usec = how much faster (+ve) or slower the source DAC is running relative to the source clock
- // buffer_occupancy = the number of buffers occupied. Crude, but should show no long term trend if source and device are in sync.
- // return_time = the time from soliciting a timing packet to getting it back. It should be short ( < 5 ms) and pretty consistent.
- // debug(1, "%lld\t%lld\t%ld\t%lld\t%u\t%llu", clock_drift_in_usec,(session_corrections*1000000)/44100,current_delay,source_drift_usec,buffer_occupancy,(return_time*1000000)>>32);
-
+ clock_drift_in_usec = -(((-clock_drift) * 1000000) >> 32);
+
+ int64_t source_drift_usec;
+ if (play_segment_reference_frame != 0) {
+ int64_t reference_timestamp;
+ uint64_t reference_timestamp_time, remote_reference_timestamp_time;
+ get_reference_timestamp_stuff(&reference_timestamp, &reference_timestamp_time,
+ &remote_reference_timestamp_time);
+ uint64_t frame_difference = 0;
+ if (reference_timestamp >= play_segment_reference_frame)
+ frame_difference = (uint64_t)reference_timestamp - (uint64_t)play_segment_reference_frame;
+ else // rollover
+ frame_difference =
+ (uint64_t)reference_timestamp + 0x100000000 - (uint64_t)play_segment_reference_frame;
+ uint64_t frame_time_difference_calculated = (((uint64_t)frame_difference << 32) / 44100);
+ uint64_t frame_time_difference_actual =
+ remote_reference_timestamp_time -
+ play_segment_reference_frame_remote_time; // this is all done by reference to the
+ // sources' system clock
+ // debug(1,"%llu frames since play started, %llu usec calculated, %llu usec
+ // actual",frame_difference, (frame_time_difference_calculated*1000000)>>32,
+ // (frame_time_difference_actual*1000000)>>32);
+ if (frame_time_difference_calculated >=
+ frame_time_difference_actual) // i.e. if the time it should have taken to send the
+ // packets is greater than the actual time difference
+ // measured on the source clock
+ // then the source DAC's clock is running fast relative to the source system clock
+ source_drift_usec = frame_time_difference_calculated - frame_time_difference_actual;
+ else
+ // otherwise the source DAC's clock is running slow relative to the source system clock
+ source_drift_usec = -(frame_time_difference_actual - frame_time_difference_calculated);
+ } else
+ source_drift_usec = 0;
+ source_drift_usec = (source_drift_usec * 1000000) >> 32; // turn it to microseconds
+
+ // long current_delay = 0;
+ // if (config.output->delay) {
+ // config.output->delay(¤t_delay);
+ //}
+ // Useful for troubleshooting:
+ // clock_drift between source and local clock -- +ve means source is faster
+ // session_corrections -- the amount of correction done, in microseconds. +ve means frames
+ // added
+ // current_delay = delay in DAC buffer in frames
+ // source_drift_usec = how much faster (+ve) or slower the source DAC is running relative
+ // to the source clock
+ // buffer_occupancy = the number of buffers occupied. Crude, but should show no long term
+ // trend if source and device are in sync.
+ // return_time = the time from soliciting a timing packet to getting it back. It should be
+ // short ( < 5 ms) and pretty consistent.
+ // debug(1, "%lld\t%lld\t%ld\t%lld\t%u\t%llu",
+ // clock_drift_in_usec,(session_corrections*1000000)/44100,current_delay,source_drift_usec,buffer_occupancy,(return_time*1000000)>>32);
+
} else {
debug(1, "Timing port -- Unknown RTP packet of type 0x%02X length %d.", packet[1], nread);
}
return NULL;
}
-static int bind_port(int ip_family,const char *self_ip_address,uint32_t scope_id,int *sock) {
+static int bind_port(int ip_family, const char *self_ip_address, uint32_t scope_id, int *sock) {
// look for a port in the range, if any was specified.
int desired_port = config.udp_port_base;
int ret;
-
+
int local_socket = socket(ip_family, SOCK_DGRAM, IPPROTO_UDP);
- if (local_socket== -1)
+ if (local_socket == -1)
die("Could not allocate a socket.");
SOCKADDR myaddr;
do {
- memset(&myaddr,0,sizeof(myaddr));
- if (ip_family==AF_INET) {
+ memset(&myaddr, 0, sizeof(myaddr));
+ if (ip_family == AF_INET) {
struct sockaddr_in *sa = (struct sockaddr_in *)&myaddr;
sa->sin_family = AF_INET;
sa->sin_port = ntohs(desired_port);
- inet_pton(AF_INET,self_ip_address,&(sa->sin_addr));
- ret = bind(local_socket,(struct sockaddr*)sa, sizeof(struct sockaddr_in));
+ inet_pton(AF_INET, self_ip_address, &(sa->sin_addr));
+ ret = bind(local_socket, (struct sockaddr *)sa, sizeof(struct sockaddr_in));
}
#ifdef AF_INET6
- if (ip_family==AF_INET6) {
+ if (ip_family == AF_INET6) {
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&myaddr;
sa6->sin6_family = AF_INET6;
sa6->sin6_port = ntohs(desired_port);
- inet_pton(AF_INET6,self_ip_address,&(sa6->sin6_addr));
- sa6->sin6_scope_id=scope_id;
- ret = bind(local_socket,(struct sockaddr*)sa6, sizeof(struct sockaddr_in6));
+ inet_pton(AF_INET6, self_ip_address, &(sa6->sin6_addr));
+ sa6->sin6_scope_id = scope_id;
+ ret = bind(local_socket, (struct sockaddr *)sa6, sizeof(struct sockaddr_in6));
}
-#endif
-
- } while ((ret<0) && (errno==EADDRINUSE) && (desired_port!=0) && (desired_port++ < config.udp_port_base+config.udp_port_range));
-
+#endif
+
+ } while ((ret < 0) && (errno == EADDRINUSE) && (desired_port != 0) &&
+ (desired_port++ < config.udp_port_base + config.udp_port_range));
+
// debug(1,"UDP port chosen: %d.",desired_port);
-
+
if (ret < 0) {
- close(local_socket);
- die("error: could not bind a UDP port!");
+ close(local_socket);
+ die("error: could not bind a UDP port!");
}
-
+
int sport;
SOCKADDR local;
socklen_t local_len = sizeof(local);
struct sockaddr_in *sa = (struct sockaddr_in *)&local;
sport = ntohs(sa->sin_port);
}
-
+
*sock = local_socket;
return sport;
}
-void rtp_setup(SOCKADDR *local, SOCKADDR *remote, int cport, int tport, uint32_t active_remote, int *lsport,
- int *lcport, int *ltport) {
-
+void rtp_setup(SOCKADDR *local, SOCKADDR *remote, int cport, int tport, uint32_t active_remote,
+ int *lsport, int *lcport, int *ltport) {
+
// this gets the local and remote ip numbers (and ports used for the TCD stuff)
// we use the local stuff to specify the address we are coming from and
// we use the remote stuff to specify where we're goint to
-
+
if (running)
die("rtp_setup called with active stream!");
client_active_remote = active_remote;
// print out what we know about the client
- void *client_addr,*self_addr;
- int client_port,self_port;
+ void *client_addr, *self_addr;
+ int client_port, self_port;
char client_port_str[64];
char self_addr_str[64];
-
+
connection_ip_family = remote->SAFAMILY; // keep information about the kind of ip of the client
-
+
#ifdef AF_INET6
if (connection_ip_family == AF_INET6) {
struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)remote;
self_port = ntohs(sa4->sin_port);
}
- inet_ntop(connection_ip_family, client_addr, client_ip_string,
- sizeof(client_ip_string));
- inet_ntop(connection_ip_family, self_addr, self_ip_string,
- sizeof(self_ip_string));
-
- debug(1, "Set up play connection from %s to self at %s.", client_ip_string,self_ip_string);
+ inet_ntop(connection_ip_family, client_addr, client_ip_string, sizeof(client_ip_string));
+ inet_ntop(connection_ip_family, self_addr, self_ip_string, sizeof(self_ip_string));
+ debug(1, "Set up play connection from %s to self at %s.", client_ip_string, self_ip_string);
// set up a the record of the remote's control socket
struct addrinfo hints;
// now, we open three sockets -- one for the audio stream, one for the timing and one for the
// control
- *lsport = bind_port(connection_ip_family,self_ip_string,self_scope_id,&audio_socket);
- *lcport = bind_port(connection_ip_family,self_ip_string,self_scope_id,&control_socket);
- *ltport = bind_port(connection_ip_family,self_ip_string,self_scope_id,&timing_socket);
+ *lsport = bind_port(connection_ip_family, self_ip_string, self_scope_id, &audio_socket);
+ *lcport = bind_port(connection_ip_family, self_ip_string, self_scope_id, &control_socket);
+ *ltport = bind_port(connection_ip_family, self_ip_string, self_scope_id, &timing_socket);
debug(2, "listening for audio, control and timing on ports %d, %d, %d.", *lsport, *lcport,
*ltport);
reference_timestamp = 0;
- //pthread_create(&rtp_audio_thread, NULL, &rtp_audio_receiver, NULL);
- //pthread_create(&rtp_control_thread, NULL, &rtp_control_receiver, NULL);
- //pthread_create(&rtp_timing_thread, NULL, &rtp_timing_receiver, NULL);
+ // pthread_create(&rtp_audio_thread, NULL, &rtp_audio_receiver, NULL);
+ // pthread_create(&rtp_control_thread, NULL, &rtp_control_receiver, NULL);
+ // pthread_create(&rtp_timing_thread, NULL, &rtp_timing_receiver, NULL);
running = 1;
request_sent = 0;
}
-void get_reference_timestamp_stuff(int64_t *timestamp, uint64_t *timestamp_time, uint64_t *remote_timestamp_time) {
+void get_reference_timestamp_stuff(int64_t *timestamp, uint64_t *timestamp_time,
+ uint64_t *remote_timestamp_time) {
// types okay
pthread_mutex_lock(&reference_time_mutex);
*timestamp = reference_timestamp;
void rtp_shutdown(void) {
if (!running)
- debug(1,"rtp_shutdown called without active stream!");
+ debug(1, "rtp_shutdown called without active stream!");
debug(2, "shutting down RTP thread");
clear_reference_timestamp();
-// debug(1,"Shut down audio, control and timing threads");
-// usleep(3000000); // hack
-// pthread_kill(rtp_audio_thread, SIGUSR1);
-// pthread_kill(rtp_control_thread, SIGUSR1);
-// pthread_kill(rtp_timing_thread, SIGUSR1);
-// pthread_join(rtp_audio_thread, &retval);
-// pthread_join(rtp_control_thread, &retval);
-// pthread_join(rtp_timing_thread, &retval);
+ // debug(1,"Shut down audio, control and timing threads");
+ // usleep(3000000); // hack
+ // pthread_kill(rtp_audio_thread, SIGUSR1);
+ // pthread_kill(rtp_control_thread, SIGUSR1);
+ // pthread_kill(rtp_timing_thread, SIGUSR1);
+ // pthread_join(rtp_audio_thread, &retval);
+ // pthread_join(rtp_control_thread, &retval);
+ // pthread_join(rtp_timing_thread, &retval);
running = 0;
}
void rtp_request_resend(seq_t first, uint32_t count) {
if (running) {
- //if (!request_sent) {
- debug(3, "requesting resend of %d packets starting at %u.", count, first);
+ // if (!request_sent) {
+ debug(3, "requesting resend of %d packets starting at %u.", count, first);
// request_sent = 1;
//}
perror("Error sendto-ing to audio socket");
}
} else {
- //if (!request_sent) {
- debug(2, "rtp_request_resend called without active stream!");
+ // if (!request_sent) {
+ debug(2, "rtp_request_resend called without active stream!");
// request_sent = 1;
//}
}
#include "player.h"
-typedef struct inter_threads_record {
- uint32_t please_stop;
-} inter_threads_record;
+typedef struct inter_threads_record { uint32_t please_stop; } inter_threads_record;
void *rtp_audio_receiver(void *arg);
void *rtp_control_receiver(void *arg);
void *rtp_timing_receiver(void *arg);
-void rtp_setup(SOCKADDR *local, SOCKADDR *remote, int controlport, int timingport, uint32_t active_remote,
- int *local_server_port, int *local_control_port, int *local_timing_port);
+void rtp_setup(SOCKADDR *local, SOCKADDR *remote, int controlport, int timingport,
+ uint32_t active_remote, int *local_server_port, int *local_control_port,
+ int *local_timing_port);
void rtp_shutdown(void);
void rtp_request_resend(seq_t first, uint32_t count);
void rtp_request_client_pause(void); // ask the client to pause
-void get_reference_timestamp_stuff(int64_t *timestamp, uint64_t *timestamp_time, uint64_t *remote_timestamp_time);
+void get_reference_timestamp_stuff(int64_t *timestamp, uint64_t *timestamp_time,
+ uint64_t *remote_timestamp_time);
void clear_reference_timestamp(void);
uint64_t static local_to_remote_time_jitters;
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <memory.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
#include <arpa/inet.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <memory.h>
#include <netdb.h>
-#include <sys/select.h>
+#include <netinet/in.h>
+#include <poll.h>
+#include <pthread.h>
#include <signal.h>
#include <stdio.h>
-#include <string.h>
#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <poll.h>
+#include <string.h>
+#include <sys/select.h>
+#include <sys/socket.h>
#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
#include "config.h"
#endif
#include "common.h"
+#include "mdns.h"
#include "player.h"
#include "rtp.h"
-#include "mdns.h"
#ifdef AF_INET6
#define INETx_ADDRSTRLEN INET6_ADDRSTRLEN
// only one thread is allowed to use the player at once.
// it monitors the request variable (at least when interrupted)
-//static pthread_mutex_t playing_mutex = PTHREAD_MUTEX_INITIALIZER;
+// static pthread_mutex_t playing_mutex = PTHREAD_MUTEX_INITIALIZER;
// static int please_shutdown = 0;
// static pthread_t playing_thread = 0;
int fd;
int authorized; // set is a password is required and has been supplied
stream_cfg stream;
- SOCKADDR remote,local;
+ SOCKADDR remote, local;
int stop;
int running;
pthread_t thread;
pthread_t player_thread;
} rtsp_conn_info;
-static rtsp_conn_info *playing_conn = NULL; // the data structure representing the connection that has the player.
+static rtsp_conn_info *playing_conn =
+ NULL; // the data structure representing the connection that has the player.
static rtsp_conn_info **conns = NULL;
void memory_barrier() {
rtsp_message *carrier;
} metadata_package;
-void pc_queue_init(pc_queue *the_queue, char *items, size_t item_size,
- uint32_t number_of_items) {
+void pc_queue_init(pc_queue *the_queue, char *items, size_t item_size, uint32_t number_of_items) {
pthread_mutex_init(&the_queue->pc_queue_lock, NULL);
pthread_cond_init(&the_queue->pc_queue_item_added_signal, NULL);
pthread_cond_init(&the_queue->pc_queue_item_removed_signal, NULL);
the_queue->eoq = 0;
}
-int send_metadata(uint32_t type, uint32_t code, char *data, uint32_t length,
- rtsp_message *carrier, int block);
+int send_metadata(uint32_t type, uint32_t code, char *data, uint32_t length, rtsp_message *carrier,
+ int block);
int send_ssnc_metadata(uint32_t code, char *data, uint32_t length, int block) {
return send_metadata('ssnc', code, data, length, NULL, block);
if (rc)
debug(1, "Error locking for pc_queue_add_item");
while (the_queue->count == the_queue->capacity) {
- rc = pthread_cond_wait(&the_queue->pc_queue_item_removed_signal,
- &the_queue->pc_queue_lock);
+ rc = pthread_cond_wait(&the_queue->pc_queue_item_removed_signal, &the_queue->pc_queue_lock);
if (rc)
debug(1, "Error waiting for item to be removed");
}
if (rc)
debug(1, "Error locking for pc_queue_get_item");
while (the_queue->count == 0) {
- rc = pthread_cond_wait(&the_queue->pc_queue_item_added_signal,
- &the_queue->pc_queue_lock);
+ rc = pthread_cond_wait(&the_queue->pc_queue_item_added_signal, &the_queue->pc_queue_lock);
if (rc)
debug(1, "Error waiting for item to be added");
}
void rtsp_request_shutdown_stream(void) {
debug(1, "Request to shut down all rtsp conversation threads");
- ask_other_rtsp_conversation_threads_to_stop(
- 0); // i.e. ask all playing threads to stop
+ ask_other_rtsp_conversation_threads_to_stop(0); // i.e. ask all playing threads to stop
}
-//static void rtsp_take_player(void) {
+// static void rtsp_take_player(void) {
// if (rtsp_playing())
// return;
int i;
debug(2, "asking playing threads to stop");
for (i = 0; i < nconns; i++) {
- if (((except_this_thread == 0) ||
- (pthread_equal(conns[i]->thread, except_this_thread) == 0)) &&
+ if (((except_this_thread == 0) || (pthread_equal(conns[i]->thread, except_this_thread) == 0)) &&
(conns[i]->running != 0)) {
conns[i]->stop = 1;
pthread_kill(conns[i]->thread, SIGUSR1);
static rtsp_message *msg_init(void) {
rtsp_message *msg = malloc(sizeof(rtsp_message));
memset(msg, 0, sizeof(rtsp_message));
- msg->referenceCount =
- 1; // from now on, any access to this must be protected with the lock
+ msg->referenceCount = 1; // from now on, any access to this must be protected with the lock
return msg;
}
msg->referenceCount--;
rc = pthread_mutex_unlock(&reference_counter_lock);
if (rc)
- debug(1, "Error %d unlocking reference counter lock during msg_free()",
- rc);
+ debug(1, "Error %d unlocking reference counter lock during msg_free()", rc);
if (msg->referenceCount == 0) {
int i;
for (i = 0; i < msg->nheaders; i++) {
return 0;
}
-static enum rtsp_read_request_response
-rtsp_read_request(rtsp_conn_info *conn, rtsp_message **the_packet) {
+static enum rtsp_read_request_response rtsp_read_request(rtsp_conn_info *conn,
+ rtsp_message **the_packet) {
enum rtsp_read_request_response reply = rtsp_read_request_response_ok;
ssize_t buflen = 512;
char *buf = malloc(buflen + 1);
goto shutdown;
}
nread = read(conn->fd, buf + inbuf, buflen - inbuf);
-
- if (nread==0) {
+
+ if (nread == 0) {
// a blocking read that returns zero means eof -- implies connection closed
debug(3, "RTSP connection closed.");
reply = rtsp_read_request_response_shutdown_requested;
buflen = msg_size;
}
- uint64_t threshold_time = get_absolute_time_in_fp() +
- ((uint64_t)5 << 32); // i.e. five seconds from now
+ uint64_t threshold_time =
+ get_absolute_time_in_fp() + ((uint64_t)5 << 32); // i.e. five seconds from now
int warning_message_sent = 0;
const size_t max_read_chunk = 50000;
int ignore = write(fd, pkt, p - pkt + 2);
}
-static void handle_record(rtsp_conn_info *conn, rtsp_message *req,
- rtsp_message *resp) {
+static void handle_record(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
// debug(1,"Handle Record");
resp->respcode = 200;
// I think this is for telling the client what the absolute minimum latency
}
}
-static void handle_options(rtsp_conn_info *conn, rtsp_message *req,
- rtsp_message *resp) {
+static void handle_options(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
resp->respcode = 200;
msg_add_header(resp, "Public", "ANNOUNCE, SETUP, RECORD, "
"PAUSE, FLUSH, TEARDOWN, "
"OPTIONS, GET_PARAMETER, SET_PARAMETER");
}
-static void handle_teardown(rtsp_conn_info *conn, rtsp_message *req,
- rtsp_message *resp) {
+static void handle_teardown(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
if (!rtsp_playing())
debug(1, "This RTSP conversation thread doesn't think it's playing, but "
"it's sending a response to teardown anyway");
conn->stop = 1;
}
-static void handle_flush(rtsp_conn_info *conn, rtsp_message *req,
- rtsp_message *resp) {
+static void handle_flush(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
if (!rtsp_playing())
debug(1, "This RTSP conversation thread doesn't think it's playing, but "
"it's sending a response to flush anyway");
resp->respcode = 200;
}
-static void handle_setup(rtsp_conn_info *conn, rtsp_message *req,
- rtsp_message *resp) {
+static void handle_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
// debug(1,"Handle Setup");
int cport, tport;
int lsport, lcport, ltport;
config.latency = config.iTunesLatency;
}
} else if (strstr(ua, "AirPlay") == ua) {
- debug(
- 2,
- "User-Agent is AirPlay; selecting the AirPlay latency of %d frames.",
- config.AirPlayLatency);
+ debug(2, "User-Agent is AirPlay; selecting the AirPlay latency of %d frames.",
+ config.AirPlayLatency);
config.latency = config.AirPlayLatency;
} else if (strstr(ua, "forked-daapd") == ua) {
debug(2, "User-Agent is forked-daapd; selecting the forked-daapd latency "
config.ForkedDaapdLatency);
config.latency = config.ForkedDaapdLatency;
} else {
- debug(2, "Unrecognised User-Agent. Using latency of %d frames.",
- config.latency);
+ debug(2, "Unrecognised User-Agent. Using latency of %d frames.", config.latency);
}
}
p = strchr(p, '=') + 1;
tport = atoi(p);
-// rtsp_take_player();
- rtp_setup(&conn->local, &conn->remote, cport, tport, active_remote, &lsport, &lcport,
- <port);
+ // rtsp_take_player();
+ rtp_setup(&conn->local, &conn->remote, cport, tport, active_remote, &lsport, &lcport, <port);
if (!lsport)
goto error;
char *q;
resp->respcode = 451; // invalid arguments
}
-static void handle_ignore(rtsp_conn_info *conn, rtsp_message *req,
- rtsp_message *resp) {
+static void handle_ignore(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
resp->respcode = 200;
}
-static void handle_set_parameter_parameter(rtsp_conn_info *conn,
- rtsp_message *req,
+static void handle_set_parameter_parameter(rtsp_conn_info *conn, rtsp_message *req,
rtsp_message *resp) {
char *cp = req->content;
int cp_left = req->contentlength;
#ifdef CONFIG_METADATA
if (!strncmp(cp, "progress: ", 10)) {
char *progress = cp + 10;
- //debug(2, "progress: \"%s\"\n",
+ // debug(2, "progress: \"%s\"\n",
// progress); // rtpstampstart/rtpstampnow/rtpstampend 44100 per second
send_ssnc_metadata('prgr', strdup(progress), strlen(progress), 1);
} else
// add _so to end of name to avoid confusion with polarssl's implementation
-static char encoding_table[] = {
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
- 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
- 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
+static char encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
+ 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
+ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
static int mod_table[] = {0, 2, 1};
// containing its maximum length
// the actual length will be returned.
-char *base64_encode_so(const unsigned char *data, size_t input_length,
- char *encoded_data, size_t *output_length) {
+char *base64_encode_so(const unsigned char *data, size_t input_length, char *encoded_data,
+ size_t *output_length) {
size_t calculated_output_length = 4 * ((input_length + 2) / 3);
if (calculated_output_length > *output_length)
fd = -1;
}
-void metadata_process(uint32_t type, uint32_t code, char *data,
- uint32_t length) {
+void metadata_process(uint32_t type, uint32_t code, char *data, uint32_t length) {
// debug(2, "Process metadata with type %x, code %x and length %u.", type, code, length);
int ret;
memcpy(ptr, &v, 4);
ptr += 4;
memcpy(ptr, data, length);
- sendto(metadata_sock, metadata_sockmsg, length + 8, 0, (struct sockaddr *)&metadata_sockaddr, sizeof(metadata_sockaddr));
+ sendto(metadata_sock, metadata_sockmsg, length + 8, 0, (struct sockaddr *)&metadata_sockaddr,
+ sizeof(metadata_sockaddr));
}
// readers may go away and come back
if (fd < 0)
return;
char thestring[1024];
- snprintf(thestring, 1024,
- "<item><type>%x</type><code>%x</code><length>%u</length>", type,
- code, length);
+ snprintf(thestring, 1024, "<item><type>%x</type><code>%x</code><length>%u</length>", type, code,
+ length);
ret = non_blocking_write(fd, thestring, strlen(thestring));
if (ret < 0) {
// debug(1,"metadata_process error %d exit 1",ret);
size_t towrite_count = remaining_count;
if (towrite_count > 57)
towrite_count = 57;
- size_t outbuf_size =
- 76; // size of output buffer on entry, length of result on exit
- if (base64_encode_so((unsigned char *)remaining_data, towrite_count,
- outbuf, &outbuf_size) == NULL)
+ size_t outbuf_size = 76; // size of output buffer on entry, length of result on exit
+ if (base64_encode_so((unsigned char *)remaining_data, towrite_count, outbuf, &outbuf_size) ==
+ NULL)
debug(1, "Error encoding base64 data.");
// debug(1,"Remaining count: %d ret: %d, outbuf_size:
// %d.",remaining_count,ret,outbuf_size);
void metadata_init(void) {
// create a pc_queue for passing information to a threaded metadata handler
- pc_queue_init(&metadata_queue, (char *)&metadata_queue_items,
- sizeof(metadata_package), metadata_queue_size);
- int ret =
- pthread_create(&metadata_thread, NULL, metadata_thread_function, NULL);
+ pc_queue_init(&metadata_queue, (char *)&metadata_queue_items, sizeof(metadata_package),
+ metadata_queue_size);
+ int ret = pthread_create(&metadata_thread, NULL, metadata_thread_function, NULL);
if (ret)
debug(1, "Failed to create metadata thread!");
}
-int send_metadata(uint32_t type, uint32_t code, char *data, uint32_t length,
- rtsp_message *carrier, int block) {
+int send_metadata(uint32_t type, uint32_t code, char *data, uint32_t length, rtsp_message *carrier,
+ int block) {
// parameters: type, code, pointer to data or NULL, length of data or NULL,
// the rtsp_message or
if ((rc == EBUSY) && (carrier))
msg_free(carrier);
if (rc == EBUSY)
- warn(
- "Metadata queue is busy, dropping message of type 0x%08X, code 0x%08X.",
- type, code);
+ warn("Metadata queue is busy, dropping message of type 0x%08X, code 0x%08X.", type, code);
return rc;
}
-static void handle_set_parameter_metadata(rtsp_conn_info *conn,
- rtsp_message *req,
+static void handle_set_parameter_metadata(rtsp_conn_info *conn, rtsp_message *req,
rtsp_message *resp) {
char *cp = req->content;
int cl = req->contentlength;
uint32_t itag, vl;
while (off < cl) {
// pick up the metadata tag as an unsigned longint
- memcpy(&itag, (uint32_t *)(cp + off),
- sizeof(uint32_t)); /* can be misaligned, thus memcpy */
+ memcpy(&itag, (uint32_t *)(cp + off), sizeof(uint32_t)); /* can be misaligned, thus memcpy */
itag = ntohl(itag);
off += sizeof(uint32_t);
// pick up the length of the data
- memcpy(&vl, (uint32_t *)(cp + off),
- sizeof(uint32_t)); /* can be misaligned, thus memcpy */
+ memcpy(&vl, (uint32_t *)(cp + off), sizeof(uint32_t)); /* can be misaligned, thus memcpy */
vl = ntohl(vl);
off += sizeof(uint32_t);
#endif
-static void handle_get_parameter(rtsp_conn_info *conn, rtsp_message *req,
- rtsp_message *resp) {
+static void handle_get_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
debug(1, "received GET_PARAMETER request.");
resp->respcode = 200;
}
-static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req,
- rtsp_message *resp) {
+static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
// if (!req->contentlength)
// debug(1, "received empty SET_PARAMETER request.");
char *ct = msg_get_header(req, "Content-Type");
if (ct) {
- // debug(2, "SET_PARAMETER Content-Type:\"%s\".", ct);
+// debug(2, "SET_PARAMETER Content-Type:\"%s\".", ct);
#ifdef CONFIG_METADATA
// It seems that the rtptime of the message is used as a kind of an ID that
if (p == NULL)
debug(1, "Missing RTP-Time info for metadata");
if (p)
- send_metadata('ssnc', 'mdst', p + 1, strlen(p + 1), req,
- 1); // metadata starting
+ send_metadata('ssnc', 'mdst', p + 1, strlen(p + 1), req, 1); // metadata starting
else
send_metadata('ssnc', 'mdst', NULL, 0, NULL,
0); // metadata starting, if rtptime is not available
handle_set_parameter_metadata(conn, req, resp);
if (p)
- send_metadata('ssnc', 'mden', p + 1, strlen(p + 1), req,
- 1); // metadata ending
+ send_metadata('ssnc', 'mden', p + 1, strlen(p + 1), req, 1); // metadata ending
else
send_metadata('ssnc', 'mden', NULL, 0, NULL,
0); // metadata starting, if rtptime is not available
if (p == NULL)
debug(1, "Missing RTP-Time info for picture item");
if (p)
- send_metadata('ssnc', 'pcst', p + 1, strlen(p + 1), req,
- 1); // picture starting
+ send_metadata('ssnc', 'pcst', p + 1, strlen(p + 1), req, 1); // picture starting
else
send_metadata('ssnc', 'pcst', NULL, 0, NULL,
0); // picture starting, if rtptime is not available
send_metadata('ssnc', 'PICT', req->content, req->contentlength, req, 1);
if (p)
- send_metadata('ssnc', 'pcen', p + 1, strlen(p + 1), req,
- 1); // picture ending
+ send_metadata('ssnc', 'pcen', p + 1, strlen(p + 1), req, 1); // picture ending
else
send_metadata('ssnc', 'pcen', NULL, 0, NULL,
0); // picture ending, if rtptime is not available
#endif
if (!strncmp(ct, "text/parameters", 15)) {
// debug(2, "received parameters in SET_PARAMETER request.");
- handle_set_parameter_parameter(conn, req,
- resp); // this could be volume or progress
+ handle_set_parameter_parameter(conn, req, resp); // this could be volume or progress
} else {
- debug(1, "received unknown Content-Type \"%s\" in SET_PARAMETER request.",
- ct);
+ debug(1, "received unknown Content-Type \"%s\" in SET_PARAMETER request.", ct);
}
} else {
debug(1, "missing Content-Type header in SET_PARAMETER request.");
resp->respcode = 200;
}
-static void handle_announce(rtsp_conn_info *conn, rtsp_message *req,
- rtsp_message *resp) {
+static void handle_announce(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) {
int have_the_player = 0;
// interrupt session if permitted
die("Non existent the_playing_conn with play_lock enabled.");
}
usleep(1000000); // here, it is possible for other connections to come in and nab the player.
- debug(1,"Try to get the player now");
- //pthread_mutex_lock(&play_lock);
+ debug(1, "Try to get the player now");
+ // pthread_mutex_lock(&play_lock);
if (pthread_mutex_trylock(&play_lock) == 0)
have_the_player = 1;
}
}
-
- if (have_the_player) {
- playing_conn = conn; // the present connection is now playing
+
+ if (have_the_player) {
+ playing_conn = conn; // the present connection is now playing
resp->respcode = 456; // 456 - Header Field Not Valid for Resource
char *paesiv = NULL;
char *prsaaeskey = NULL;
free(aeskey);
}
int i;
- for (i = 0; i < sizeof(conn->stream.fmtp) / sizeof(conn->stream.fmtp[0]);
- i++)
+ for (i = 0; i < sizeof(conn->stream.fmtp) / sizeof(conn->stream.fmtp[0]); i++)
conn->stream.fmtp[i] = atoi(strsep(&pfmtp, " \t"));
char *hdr = msg_get_header(req, "X-Apple-Client-Name");
md5_update(&tctx, (unsigned char *)":", 1);
md5_update(&tctx, (const unsigned char *)realm, strlen(realm));
md5_update(&tctx, (unsigned char *)":", 1);
- md5_update(&tctx, (const unsigned char *)config.password,
- strlen(config.password));
+ md5_update(&tctx, (const unsigned char *)config.password, strlen(config.password));
md5_finish(&tctx, digest_urp);
md5_starts(&tctx);
md5_update(&tctx, (const unsigned char *)req->method, strlen(req->method));
do {
reply = rtsp_read_request(conn, &req);
if (reply == rtsp_read_request_response_ok) {
- debug(3,"RTSP Packet received of type \"%s\":",req->method),
- debug_print_msg_headers(3,req);
+ debug(3, "RTSP Packet received of type \"%s\":", req->method),
+ debug_print_msg_headers(3, req);
resp = msg_init();
resp->respcode = 400;
hdr = msg_get_header(req, "CSeq");
if (hdr)
msg_add_header(resp, "CSeq", hdr);
-// msg_add_header(resp, "Audio-Jack-Status", "connected; type=analog");
+ // msg_add_header(resp, "Audio-Jack-Status", "connected; type=analog");
msg_add_header(resp, "Server", "AirTunes/105.1");
-
- if ((conn->authorized==1) || (rtsp_auth(&auth_nonce, req, resp))==0) {
- conn->authorized=1; // it must have been authorized or didn't need a password
- struct method_handler *mh;
- int method_selected = 0;
- for (mh = method_handlers; mh->method; mh++) {
- if (!strcmp(mh->method, req->method)) {
- method_selected = 1;
- mh->handler(conn, req, resp);
- break;
- }
- }
- if (method_selected == 0)
- debug(1, "Unrecognised and unhandled rtsp request \"%s\".",
- req->method);
- }
- debug(3,"RTSP Response:");
- debug_print_msg_headers(3,resp);
+
+ if ((conn->authorized == 1) || (rtsp_auth(&auth_nonce, req, resp)) == 0) {
+ conn->authorized = 1; // it must have been authorized or didn't need a password
+ struct method_handler *mh;
+ int method_selected = 0;
+ for (mh = method_handlers; mh->method; mh++) {
+ if (!strcmp(mh->method, req->method)) {
+ method_selected = 1;
+ mh->handler(conn, req, resp);
+ break;
+ }
+ }
+ if (method_selected == 0)
+ debug(1, "Unrecognised and unhandled rtsp request \"%s\".", req->method);
+ }
+ debug(3, "RTSP Response:");
+ debug_print_msg_headers(3, resp);
msg_write_response(conn->fd, resp);
msg_free(req);
msg_free(resp);
close(conn->fd);
if (auth_nonce)
free(auth_nonce);
-// pthread_mutex_unlock(&playing_mutex);
- // usleep(1000000);
-// } // else {
- //debug(1, "This RTSP conversation thread doesn't think it's playing for a "
- // "close RTSP connection.");
+ // pthread_mutex_unlock(&playing_mutex);
+ // usleep(1000000);
+ // } // else {
+ // debug(1, "This RTSP conversation thread doesn't think it's playing for a "
+ // "close RTSP connection.");
// }
debug(2, "RTSP conversation thread terminated.");
// please_shutdown = 0;
}
for (p = info; p; p = p->ai_next) {
- ret = 0;
+ ret = 0;
int fd = socket(p->ai_family, p->ai_socktype, IPPROTO_TCP);
int yes = 1;
// report its availability. do not complain.
if (ret) {
- char *family;
+ char *family;
#ifdef AF_INET6
- if (p->ai_family == AF_INET6) {
- family = "IPv6";
- } else
+ if (p->ai_family == AF_INET6) {
+ family = "IPv6";
+ } else
#endif
- family = "IPv4";
- debug(1, "Unable to listen on %s port %d. The error is: \"%s\".", family, config.port,strerror(errno));
+ family = "IPv4";
+ debug(1, "Unable to listen on %s port %d. The error is: \"%s\".", family, config.port,
+ strerror(errno));
continue;
}
freeaddrinfo(info);
if (!nsock)
- die("Could not establish a service on port %d -- program terminating. Is another instance of Shairport Sync running on this device?",config.port);
+ die("Could not establish a service on port %d -- program terminating. Is another instance of "
+ "Shairport Sync running on this device?",
+ config.port);
int maxfd = -1;
fd_set fds;
perror("failed to accept connection");
free(conn);
} else {
- SOCKADDR *local_info = (SOCKADDR*)&conn->local;
+ SOCKADDR *local_info = (SOCKADDR *)&conn->local;
socklen_t size_of_reply = sizeof(*local_info);
- memset(local_info,0,sizeof(SOCKADDR));
- if (getsockname(conn->fd, (struct sockaddr*)local_info, &size_of_reply)==0) {
-
+ memset(local_info, 0, sizeof(SOCKADDR));
+ if (getsockname(conn->fd, (struct sockaddr *)local_info, &size_of_reply) == 0) {
+
// IPv4:
- if (local_info->SAFAMILY==AF_INET) {
- char ip4[INET_ADDRSTRLEN]; // space to hold the IPv4 string
- char remote_ip4[INET_ADDRSTRLEN]; // space to hold the IPv4 string
- struct sockaddr_in *sa = (struct sockaddr_in*)local_info;
+ if (local_info->SAFAMILY == AF_INET) {
+ char ip4[INET_ADDRSTRLEN]; // space to hold the IPv4 string
+ char remote_ip4[INET_ADDRSTRLEN]; // space to hold the IPv4 string
+ struct sockaddr_in *sa = (struct sockaddr_in *)local_info;
inet_ntop(AF_INET, &(sa->sin_addr), ip4, INET_ADDRSTRLEN);
unsigned short int tport = ntohs(sa->sin_port);
- sa = (struct sockaddr_in*)&conn->remote;
+ sa = (struct sockaddr_in *)&conn->remote;
inet_ntop(AF_INET, &(sa->sin_addr), remote_ip4, INET_ADDRSTRLEN);
unsigned short int rport = ntohs(sa->sin_port);
- debug(1,"New RTSP connection from %s:%u to self at %s:%u.",remote_ip4,rport,ip4,tport);
+ debug(1, "New RTSP connection from %s:%u to self at %s:%u.", remote_ip4, rport, ip4,
+ tport);
}
#ifdef AF_INET6
- if (local_info->SAFAMILY==AF_INET6) {
+ if (local_info->SAFAMILY == AF_INET6) {
// IPv6:
- char ip6[INET6_ADDRSTRLEN]; // space to hold the IPv6 string
+ char ip6[INET6_ADDRSTRLEN]; // space to hold the IPv6 string
char remote_ip6[INET6_ADDRSTRLEN]; // space to hold the IPv6 string
- struct sockaddr_in6 *sa6 = (struct sockaddr_in6*)local_info; // pretend this is loaded with something
+ struct sockaddr_in6 *sa6 =
+ (struct sockaddr_in6 *)local_info; // pretend this is loaded with something
inet_ntop(AF_INET6, &(sa6->sin6_addr), ip6, INET6_ADDRSTRLEN);
u_int16_t tport = ntohs(sa6->sin6_port);
-
- sa6 = (struct sockaddr_in6*)&conn->remote; // pretend this is loaded with something
+
+ sa6 = (struct sockaddr_in6 *)&conn->remote; // pretend this is loaded with something
inet_ntop(AF_INET6, &(sa6->sin6_addr), remote_ip6, INET6_ADDRSTRLEN);
u_int16_t rport = ntohs(sa6->sin6_port);
- debug(1,"New RTSP connection from [%s]:%u to self at [%s]:%u.",remote_ip6,rport,ip6,tport);
+ debug(1, "New RTSP connection from [%s]:%u to self at [%s]:%u.", remote_ip6, rport, ip6,
+ tport);
}
- #endif
-
+#endif
+
} else {
- debug(1,"Error figuring out Shairport Sync's own IP number.");
+ debug(1, "Error figuring out Shairport Sync's own IP number.");
}
usleep(500000);
pthread_t rtsp_conversation_thread;
- ret = pthread_create(&rtsp_conversation_thread, NULL,
- rtsp_conversation_thread_func, conn);
+ ret = pthread_create(&rtsp_conversation_thread, NULL, rtsp_conversation_thread_func, conn);
if (ret)
die("Failed to create RTSP receiver thread!");
// void rtsp_shutdown_stream(void);
void rtsp_request_shutdown_stream(void);
-
// initialise the metadata stuff
void metadata_init(void);
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <sys/types.h>
-#include <signal.h>
#include <errno.h>
-#include <unistd.h>
-#include <sys/stat.h>
#include <fcntl.h>
-#include <memory.h>
-#include <sys/wait.h>
#include <getopt.h>
+#include <libconfig.h>
+#include <libgen.h>
+#include <memory.h>
+#include <popt.h>
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
-#include <popt.h>
-#include <libgen.h>
-#include <libconfig.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
#include "config.h"
#endif
#include "common.h"
-#include "rtsp.h"
-#include "rtp.h"
#include "mdns.h"
+#include "rtp.h"
+#include "rtsp.h"
+#include <libdaemon/dexec.h>
#include <libdaemon/dfork.h>
-#include <libdaemon/dsignal.h>
#include <libdaemon/dlog.h>
#include <libdaemon/dpid.h>
-#include <libdaemon/dexec.h>
+#include <libdaemon/dsignal.h>
static int shutting_down = 0;
static char *appName = NULL;
-char configuration_file_path[4096+1];
-char actual_configuration_file_path[4096+1];
+char configuration_file_path[4096 + 1];
+char actual_configuration_file_path[4096 + 1];
void shairport_shutdown() {
if (shutting_down)
static void sig_shutdown(int foo, siginfo_t *bar, void *baz) {
debug(1, "shutdown requested...");
shairport_shutdown();
-// daemon_log(LOG_NOTICE, "exit...");
+ // daemon_log(LOG_NOTICE, "exit...");
daemon_retval_send(255);
daemon_pid_file_remove();
exit(0);
set_requested_connection_state_to_output(1);
}
-char* get_version_string() {
- char* version_string = malloc(200);
+char *get_version_string() {
+ char *version_string = malloc(200);
if (version_string) {
strcpy(version_string, PACKAGE_VERSION);
- #ifdef HAVE_LIBPOLARSSL
+#ifdef HAVE_LIBPOLARSSL
strcat(version_string, "-PolarSSL");
- #endif
- #ifdef HAVE_LIBSSL
+#endif
+#ifdef HAVE_LIBSSL
strcat(version_string, "-OpenSSL");
- #endif
- #ifdef CONFIG_TINYSVCMDNS
+#endif
+#ifdef CONFIG_TINYSVCMDNS
strcat(version_string, "-tinysvcmdns");
- #endif
- #ifdef CONFIG_AVAHI
+#endif
+#ifdef CONFIG_AVAHI
strcat(version_string, "-Avahi");
- #endif
- #ifdef CONFIG_DNS_SD
+#endif
+#ifdef CONFIG_DNS_SD
strcat(version_string, "-dns_sd");
- #endif
- #ifdef CONFIG_ALSA
+#endif
+#ifdef CONFIG_ALSA
strcat(version_string, "-ALSA");
- #endif
- #ifdef CONFIG_SNDIO
+#endif
+#ifdef CONFIG_SNDIO
strcat(version_string, "-sndio");
- #endif
- #ifdef CONFIG_AO
+#endif
+#ifdef CONFIG_AO
strcat(version_string, "-ao");
- #endif
- #ifdef CONFIG_PULSE
+#endif
+#ifdef CONFIG_PULSE
strcat(version_string, "-pulse");
- #endif
- #ifdef CONFIG_DUMMY
+#endif
+#ifdef CONFIG_DUMMY
strcat(version_string, "-dummy");
- #endif
- #ifdef CONFIG_STDOUT
+#endif
+#ifdef CONFIG_STDOUT
strcat(version_string, "-stdout");
- #endif
- #ifdef CONFIG_PIPE
+#endif
+#ifdef CONFIG_PIPE
strcat(version_string, "-pipe");
- #endif
- #ifdef HAVE_LIBSOXR
+#endif
+#ifdef HAVE_LIBSOXR
strcat(version_string, "-soxr");
- #endif
- #ifdef CONFIG_METADATA
+#endif
+#ifdef CONFIG_METADATA
strcat(version_string, "-metadata");
- #endif
+#endif
strcat(version_string, "-sysconfdir:");
strcat(version_string, SYSCONFDIR);
}
}
void print_version(void) {
- char* version_string = get_version_string();
+ char *version_string = get_version_string();
if (version_string) {
printf("%s\n", version_string);
free(version_string);
} else {
- debug(1,"Can't print version string!");
+ debug(1, "Can't print version string!");
}
}
"/etc/shairport-sync.conf.\n");
printf("\n");
- printf("The following general options are for backward compatability. These and all new options have settings in the configuration file, by default /etc/shairport-sync.conf:\n");
+ printf("The following general options are for backward compatability. These and all new options "
+ "have settings in the configuration file, by default /etc/shairport-sync.conf:\n");
printf(" -v, --verbose -v print debug information; -vv more; -vvv lots.\n");
printf(" -p, --port=PORT set RTSP listening port.\n");
printf(" -a, --name=NAME set advertised name.\n");
- printf(
- " -A, --AirPlayLatency=FRAMES [Deprecated] Set the latency for audio sent from an AirPlay device.\n");
+ printf(" -A, --AirPlayLatency=FRAMES [Deprecated] Set the latency for audio sent from an "
+ "AirPlay device.\n");
printf(" The default is to set it automatically.\n");
- printf(
- " -i, --iTunesLatency=FRAMES [Deprecated] Set the latency for audio sent from iTunes 10 or later.\n");
+ printf(" -i, --iTunesLatency=FRAMES [Deprecated] Set the latency for audio sent from iTunes "
+ "10 or later.\n");
printf(" The default is to set it automatically.\n");
- printf(" -L, --latency=FRAMES [Deprecated] Set the latency for audio sent from an unknown device.\n");
+ printf(" -L, --latency=FRAMES [Deprecated] Set the latency for audio sent from an unknown "
+ "device.\n");
printf(" The default is to set it automatically.\n");
- printf(" --forkedDaapdLatency=FRAMES [Deprecated] Set the latency for audio sent from forked-daapd.\n");
+ printf(" --forkedDaapdLatency=FRAMES [Deprecated] Set the latency for audio sent from "
+ "forked-daapd.\n");
printf(" The default is to set it automatically.\n");
- printf(" -S, --stuffing=MODE set how to adjust current latency to match desired latency, where \n");
+ printf(" -S, --stuffing=MODE set how to adjust current latency to match desired latency, "
+ "where \n");
printf(" \"basic\" (default) inserts or deletes audio frames from "
"packet frames with low processor overhead, and \n");
printf(" \"soxr\" uses libsoxr to minimally resample packet frames -- "
"e.g. /usr/bin/logger.\n");
printf(" Executable scripts work, but must have #!/bin/sh (or "
"whatever) in the headline.\n");
- printf(" -w, --wait-cmd wait until the -B or -E programs finish before continuing.\n");
+ printf(
+ " -w, --wait-cmd wait until the -B or -E programs finish before continuing.\n");
printf(" -o, --output=BACKEND select audio output method.\n");
printf(" -m, --mdns=BACKEND force the use of BACKEND to advertize the service.\n");
printf(" if no mdns provider is specified,\n");
printf(" shairport tries them all until one works.\n");
- printf(" -r, --resync=THRESHOLD resync if timing error exceeds this number of seconds. Set to 0 to "
+ printf(" -r, --resync=THRESHOLD resync if timing error exceeds this number of seconds. Set "
+ "to 0 to "
"stop resyncing.\n");
printf(" -t, --timeout=SECONDS go back to idle mode from play mode after a break in "
"communications of this many seconds (default 120). Set to 0 never to exit play mode.\n");
}
int parse_options(int argc, char **argv) {
- // there are potential memory leaks here -- it's called a second time, previously allocated strings will dangle.
+ // there are potential memory leaks here -- it's called a second time, previously allocated
+ // strings will dangle.
char *raw_service_name = NULL; /* Used to pick up the service name before possibly expanding it */
- char *stuffing = NULL; /* used for picking up the stuffing option */
- signed char c; /* used for argument parsing */
- int i = 0; /* used for tracking options */
- poptContext optCon; /* context for parsing command-line options */
+ char *stuffing = NULL; /* used for picking up the stuffing option */
+ signed char c; /* used for argument parsing */
+ int i = 0; /* used for tracking options */
+ poptContext optCon; /* context for parsing command-line options */
struct poptOption optionsTable[] = {
{"verbose", 'v', POPT_ARG_NONE, NULL, 'v', NULL},
{"disconnectFromOutput", 'D', POPT_ARG_NONE, NULL, 0, NULL},
{"metadata-pipename", 'M', POPT_ARG_STRING, &config.metadata_pipename, 'M', NULL},
{"get-coverart", 'g', POPT_ARG_NONE, &config.get_coverart, 'g', NULL},
#endif
- POPT_AUTOHELP
- {NULL, 0, 0, NULL, 0}};
+ POPT_AUTOHELP{NULL, 0, 0, NULL, 0}};
-// we have to parse the command line arguments to look for a config file
+ // we have to parse the command line arguments to look for a config file
int optind;
optind = argc;
int j;
optCon = poptGetContext(NULL, optind, (const char **)argv, optionsTable, 0);
poptSetOtherOptionHelp(optCon, "[OPTIONS]* ");
-
- /* Now do options processing just to get a debug level */
+
+ /* Now do options processing just to get a debug level */
debuglev = 0;
while ((c = poptGetNextOpt(optCon)) >= 0) {
switch (c) {
}
config_setting_t *setting;
- const char *str=0;
- int value=0;
+ const char *str = 0;
+ int value = 0;
double dvalue = 0.0;
-
- debug(1,"Looking for the configuration file \"%s\".",config.configfile);
-
+
+ debug(1, "Looking for the configuration file \"%s\".", config.configfile);
+
config_init(&config_file_stuff);
-
+
char *config_file_real_path = realpath(config.configfile, NULL);
- if (config_file_real_path==NULL) {
- debug(2,"Can't resolve the configuration file \"%s\".",config.configfile);
+ if (config_file_real_path == NULL) {
+ debug(2, "Can't resolve the configuration file \"%s\".", config.configfile);
} else {
debug(2, "Looking for configuration file at full path \"%s\"", config_file_real_path);
/* Read the file. If there is an error, report it and exit. */
config.udp_port_base = value;
}
- /* Get the udp port range setting. This is number of ports that will be tried for free ports , starting at the port base. Only three ports are needed. */
+ /* Get the udp port range setting. This is number of ports that will be tried for free ports ,
+ * starting at the port base. Only three ports are needed. */
if (config_lookup_int(config.cfg, "general.udp_port_range", &value)) {
if ((value < 0) || (value > 65535))
die("Invalid port range \"%sd\". It should be between 0 and 65535, default is 100",
}
/* Get the playback_mode setting */
- if (config_lookup_string(config.cfg, "general.playback_mode", &str)) {
+ if (config_lookup_string(config.cfg, "general.playback_mode", &str)) {
if (strcasecmp(str, "stereo") == 0)
config.playback_mode = ST_stereo;
else if (strcasecmp(str, "mono") == 0)
die("Invalid playback_mode choice \"%s\". It should be \"stereo\" (default) or \"mono\"");
}
- /* Get the regtype -- the service type and protocol, separated by a dot. Default is "_raop._tcp" */
+ /* Get the regtype -- the service type and protocol, separated by a dot. Default is
+ * "_raop._tcp" */
if (config_lookup_string(config.cfg, "general.regtype", &str))
config.regtype = strdup(str);
-
- /* Get the volume range, in dB, that should be used If not set, it means you just use the range set by the mixer. */
+ /* Get the volume range, in dB, that should be used If not set, it means you just use the
+ * range set by the mixer. */
if (config_lookup_int(config.cfg, "general.volume_range_db", &value)) {
if ((value < 30) || (value > 150))
- die("Invalid volume range \"%sd\". It should be between 30 and 150 dB. Zero means use the mixer's native range",
+ die("Invalid volume range \"%sd\". It should be between 30 and 150 dB. Zero means use "
+ "the mixer's native range",
value);
else
config.volume_range_db = value;
if (strcasecmp(str, "hammerton") == 0)
config.use_apple_decoder = 0;
else if (strcasecmp(str, "apple") == 0) {
- if ((config.decoders_supported & 1<<decoder_apple_alac)!=0)
+ if ((config.decoders_supported & 1 << decoder_apple_alac) != 0)
config.use_apple_decoder = 1;
else
- inform("Support for the Apple ALAC decoder has not been compiled into this version of Shairport Sync. The default decoder will be used.");
+ inform("Support for the Apple ALAC decoder has not been compiled into this version of "
+ "Shairport Sync. The default decoder will be used.");
} else
die("Invalid alac_decoder option choice \"%s\". It should be \"hammerton\" or \"apple\"");
}
-/* Get the default latency. Deprecated! */
+ /* Get the default latency. Deprecated! */
if (config_lookup_int(config.cfg, "latencies.default", &value))
config.userSuppliedLatency = value;
if (config_lookup_int(config.cfg, "latencies.forkedDaapd", &value))
config.ForkedDaapdLatency = value;
- #ifdef CONFIG_METADATA
+#ifdef CONFIG_METADATA
/* Get the metadata setting. */
if (config_lookup_string(config.cfg, "metadata.enabled", &str)) {
if (strcasecmp(str, "no") == 0)
config.metadata_sockmsglength = value < 500 ? 500 : value > 65000 ? 65000 : value;
}
- #endif
+#endif
if (config_lookup_string(config.cfg, "sessioncontrol.run_this_before_play_begins", &str)) {
config.cmd_start = (char *)str;
else if (strcasecmp(str, "yes") == 0)
config.allow_session_interruption = 1;
else
- die("Invalid session control allow_interruption option choice \"%s\". It should be \"yes\" "
+ die("Invalid session control allow_interruption option choice \"%s\". It should be "
+ "\"yes\" "
"or \"no\"");
}
free(config_file_real_path);
}
-// now, do the command line options again, but this time do them fully -- it's a unix convention that command line
-// arguments have precedence over configuration file settings.
+ // now, do the command line options again, but this time do them fully -- it's a unix convention
+ // that command line
+ // arguments have precedence over configuration file settings.
optind = argc;
for (j = 0; j < argc; j++)
if (c < -1) {
die("%s: %s", poptBadOption(optCon, POPT_BADOPTION_NOALIAS), poptStrerror(c));
}
-
+
#ifdef CONFIG_METADATA
if ((config.metadata_enabled == 1) && (config.metadata_pipename == NULL))
- config.metadata_pipename=strdup("/tmp/shairport-sync-metadata");
+ config.metadata_pipename = strdup("/tmp/shairport-sync-metadata");
#endif
-/* if the regtype hasn't been set, do it now */
- if (config.regtype==NULL)
+ /* if the regtype hasn't been set, do it now */
+ if (config.regtype == NULL)
config.regtype = strdup("_raop._tcp");
-
- if (tdebuglev!=0)
+
+ if (tdebuglev != 0)
debuglev = tdebuglev;
-/* if the Service Name wasn't specified, do it now */
+ /* if the Service Name wasn't specified, do it now */
- if (raw_service_name==NULL)
+ if (raw_service_name == NULL)
raw_service_name = strdup("%H");
-
-// now, do the substitutions in the service name
+
+ // now, do the substitutions in the service name
char hostname[100];
gethostname(hostname, 100);
- char *i1 = str_replace(raw_service_name,"%h",hostname);
- if ((hostname[0]>='a') && (hostname[0]<='z'))
- hostname[0] = hostname[0]-0x20; // convert a lowercase first letter into a capital letter
- char *i2 = str_replace(i1,"%H",hostname);
- char *i3 = str_replace(i2,"%v",PACKAGE_VERSION);
+ char *i1 = str_replace(raw_service_name, "%h", hostname);
+ if ((hostname[0] >= 'a') && (hostname[0] <= 'z'))
+ hostname[0] = hostname[0] - 0x20; // convert a lowercase first letter into a capital letter
+ char *i2 = str_replace(i1, "%H", hostname);
+ char *i3 = str_replace(i2, "%v", PACKAGE_VERSION);
char *vs = get_version_string();
- config.service_name = str_replace(i3,"%V",vs);
+ config.service_name = str_replace(i3, "%V", vs);
free(i1);
free(i2);
free(i3);
free(basec);
// set defaults
-
-
+
// get thje endianness
union {
- uint32_t u32;
- uint8_t arr[4];
+ uint32_t u32;
+ uint8_t arr[4];
} xn;
- xn.arr[0] = 0x44; /* Lowest-address byte */
+ xn.arr[0] = 0x44; /* Lowest-address byte */
xn.arr[1] = 0x33;
xn.arr[2] = 0x22;
- xn.arr[3] = 0x11; /* Highest-address byte */
-
- if (xn.u32==0x11223344)
+ xn.arr[3] = 0x11; /* Highest-address byte */
+
+ if (xn.u32 == 0x11223344)
endianness = SS_LITTLE_ENDIAN;
- else if (xn.u32==0x33441122)
+ else if (xn.u32 == 0x33441122)
endianness = SS_PDP_ENDIAN;
- else if (xn.u32==0x44332211)
+ else if (xn.u32 == 0x44332211)
endianness = SS_BIG_ENDIAN;
- else die("Can not recognise the endianness of the processor.");
-
+ else
+ die("Can not recognise the endianness of the processor.");
+
strcpy(configuration_file_path, SYSCONFDIR);
strcat(configuration_file_path, "/");
strcat(configuration_file_path, appName);
config.configfile = configuration_file_path;
config.statistics_requested = 0; // don't print stats in the log
- config.latency = -1; // -1 means not set. 88200 works well. This is also reset in rtsp.c when play is about to start
- config.userSuppliedLatency = 0; // zero means none supplied
- config.iTunesLatency = -1; // -1 means not supplied. 99400 seems to work pretty well for iTunes from Version 10 (?)
- // upwards-- two left-ear headphones, one from the iMac jack, one
- // from an NSLU2 running a cheap "3D Sound" USB Soundcard
- config.AirPlayLatency = -1; // -1 means not set. 88200 seems to work well for AirPlay -- Syncs sound and
- // vision on AppleTV, but also used for iPhone/iPod/iPad sources
- config.ForkedDaapdLatency = -1; // -1 means not set. 99400 seems to be right
- config.resyncthreshold = 0.05; // 50 ms
+ config.latency = -1; // -1 means not set. 88200 works well. This is also reset in rtsp.c when play
+ // is about to start
+ config.userSuppliedLatency = 0; // zero means none supplied
+ config.iTunesLatency =
+ -1; // -1 means not supplied. 99400 seems to work pretty well for iTunes from Version 10 (?)
+ // upwards-- two left-ear headphones, one from the iMac jack, one
+ // from an NSLU2 running a cheap "3D Sound" USB Soundcard
+ config.AirPlayLatency =
+ -1; // -1 means not set. 88200 seems to work well for AirPlay -- Syncs sound and
+ // vision on AppleTV, but also used for iPhone/iPod/iPad sources
+ config.ForkedDaapdLatency = -1; // -1 means not set. 99400 seems to be right
+ config.resyncthreshold = 0.05; // 50 ms
config.timeout = 120; // this number of seconds to wait for [more] audio before switching to idle.
- config.tolerance = 0.002; // this number of seconds of timing error before attempting to correct it.
+ config.tolerance =
+ 0.002; // this number of seconds of timing error before attempting to correct it.
config.buffer_start_fill = 220;
config.port = 5000;
config.packet_stuffing = ST_basic; // simple interpolation or deletion
- //char hostname[100];
- //gethostname(hostname, 100);
- //config.service_name = malloc(20 + 100);
- //snprintf(config.service_name, 20 + 100, "Shairport Sync on %s", hostname);
- set_requested_connection_state_to_output(1); // we expect to be able to connect to the output device
+ // char hostname[100];
+ // gethostname(hostname, 100);
+ // config.service_name = malloc(20 + 100);
+ // snprintf(config.service_name, 20 + 100, "Shairport Sync on %s", hostname);
+ set_requested_connection_state_to_output(
+ 1); // we expect to be able to connect to the output device
config.audio_backend_buffer_desired_length = 6615; // 0.15 seconds.
config.udp_port_base = 6001;
config.udp_port_range = 100;
config.output_format = SPS_FORMAT_S16_LE; // default
- config.output_rate = 44100; // default
- config.decoders_supported = 1<<decoder_hammerton; // David Hammerton's decoder supported by default
- #ifdef HAVE_APPLE_ALAC
- config.decoders_supported += 1<<decoder_apple_alac;
- #endif
-
- // initialise random number generator
-
- r64init(0);
+ config.output_rate = 44100; // default
+ config.decoders_supported =
+ 1 << decoder_hammerton; // David Hammerton's decoder supported by default
+#ifdef HAVE_APPLE_ALAC
+ config.decoders_supported += 1 << decoder_apple_alac;
+#endif
+
+ // initialise random number generator
+
+ r64init(0);
/* Check if we are called with -V or --version parameter */
if (argc >= 2 && ((strcmp(argv[1], "-V") == 0) || (strcmp(argv[1], "--version") == 0))) {
// mDNS supports maximum of 63-character names (we append 13).
if (strlen(config.service_name) > 50) {
warn("Supplied name too long (max 50 characters)");
- config.service_name[50] = '\0'; //truncate it and carry on...
+ config.service_name[50] = '\0'; // truncate it and carry on...
}
/* here, daemonise with libdaemon */
config.output->init(argc - audio_arg, argv + audio_arg);
// daemon_log(LOG_NOTICE, "startup");
-
+
switch (endianness) {
- case SS_LITTLE_ENDIAN:
- debug(2,"The processor is running little-endian.");
- break;
- case SS_BIG_ENDIAN:
- debug(2,"The processor is running big-endian.");
- break;
- case SS_PDP_ENDIAN:
- debug(2,"The processor is running pdp-endian.");
- break;
+ case SS_LITTLE_ENDIAN:
+ debug(2, "The processor is running little-endian.");
+ break;
+ case SS_BIG_ENDIAN:
+ debug(2, "The processor is running big-endian.");
+ break;
+ case SS_PDP_ENDIAN:
+ debug(2, "The processor is running pdp-endian.");
+ break;
}
-
+
/* Mess around with the latency options */
- // Basically, we used to rely on static latencies -- 99400 for iTunes 10 or later and forkedDaapd, 88200 for everything else
- // Nowadays we allow the source to set the latency, which works out at 99651 for iTunes 10 and forkedDaapd and 88220 for everything else
- // What we want to do here is allow the source to set the latency unless the user has specified an non-standard latency.
+ // Basically, we used to rely on static latencies -- 99400 for iTunes 10 or later and forkedDaapd,
+ // 88200 for everything else
+ // Nowadays we allow the source to set the latency, which works out at 99651 for iTunes 10 and
+ // forkedDaapd and 88220 for everything else
+ // What we want to do here is allow the source to set the latency unless the user has specified an
+ // non-standard latency.
// If the user has specified a standard latency, we suggest to them to stop doing it.
- // If they specify a non-standard latency, we suggest the user to use the audio_backend_latency_offset instead.
-
- if (config.AirPlayLatency!=-1) {
- if (config.AirPlayLatency==88200) {
- inform("It is not necessary to set the AirPlay latency to 88200 -- you should remove this setting or configuration option, as it is deprecated.");
- config.AirPlayLatency= -1;
+ // If they specify a non-standard latency, we suggest the user to use the
+ // audio_backend_latency_offset instead.
+
+ if (config.AirPlayLatency != -1) {
+ if (config.AirPlayLatency == 88200) {
+ inform("It is not necessary to set the AirPlay latency to 88200 -- you should remove this "
+ "setting or configuration option, as it is deprecated.");
+ config.AirPlayLatency = -1;
} else {
- inform("The AirPlay latency setting is deprecated, as Shairport Sync can now get the correct latency from the source.");
- inform("Please remove this setting and use the relevant audio_backend_latency_offset setting, if necessary, to compensate for delays elsewhere.");
+ inform("The AirPlay latency setting is deprecated, as Shairport Sync can now get the correct "
+ "latency from the source.");
+ inform("Please remove this setting and use the relevant audio_backend_latency_offset "
+ "setting, if necessary, to compensate for delays elsewhere.");
}
}
-
- if (config.iTunesLatency!=-1) {
- if (config.iTunesLatency==99400) {
- inform("It is not necessary to set the iTunes latency to 99400 -- you should remove this setting or configuration option, as it is deprecated and ignored.");
- config.iTunesLatency= -1;
+
+ if (config.iTunesLatency != -1) {
+ if (config.iTunesLatency == 99400) {
+ inform("It is not necessary to set the iTunes latency to 99400 -- you should remove this "
+ "setting or configuration option, as it is deprecated and ignored.");
+ config.iTunesLatency = -1;
} else {
- inform("The iTunes latency setting is deprecated, as Shairport Sync can now get the correct latency from the source.");
- inform("Please remove this setting and use the relevant audio_backend_latency_offset setting, if necessary, to compensate for delays elsewhere.");
+ inform("The iTunes latency setting is deprecated, as Shairport Sync can now get the correct "
+ "latency from the source.");
+ inform("Please remove this setting and use the relevant audio_backend_latency_offset "
+ "setting, if necessary, to compensate for delays elsewhere.");
}
}
-
- if (config.ForkedDaapdLatency!=-1) {
- if (config.ForkedDaapdLatency==99400) {
- inform("It is not necessary to set the forkedDaapd latency to 99400 -- you should remove this setting or configuration option, as it is deprecated and ignored.");
- config.ForkedDaapdLatency= -1;
+
+ if (config.ForkedDaapdLatency != -1) {
+ if (config.ForkedDaapdLatency == 99400) {
+ inform("It is not necessary to set the forkedDaapd latency to 99400 -- you should remove "
+ "this setting or configuration option, as it is deprecated and ignored.");
+ config.ForkedDaapdLatency = -1;
} else {
- inform("The forkedDaapd latency setting is deprecated, as Shairport Sync can now get the correct latency from the source.");
- inform("Please remove this setting and use the relevant audio_backend_latency_offset setting, if necessary, to compensate for delays elsewhere.");
+ inform("The forkedDaapd latency setting is deprecated, as Shairport Sync can now get the "
+ "correct latency from the source.");
+ inform("Please remove this setting and use the relevant audio_backend_latency_offset "
+ "setting, if necessary, to compensate for delays elsewhere.");
}
}
if (config.userSuppliedLatency) {
- inform("The default latency setting is deprecated, as Shairport Sync can now get the correct latency from the source.");
- inform("Please remove this setting and use the relevant audio_backend_latency_offset setting, if necessary, to compensate for delays elsewhere.");
+ inform("The default latency setting is deprecated, as Shairport Sync can now get the correct "
+ "latency from the source.");
+ inform("Please remove this setting and use the relevant audio_backend_latency_offset setting, "
+ "if necessary, to compensate for delays elsewhere.");
}
-
+
/* print out version */
-
- char* version_dbs = get_version_string();
+
+ char *version_dbs = get_version_string();
if (version_dbs) {
- debug(1,"Version: \"%s\"",version_dbs);
+ debug(1, "Version: \"%s\"", version_dbs);
free(version_dbs);
} else {
- debug(1,"Can't print the version information!");
+ debug(1, "Can't print the version information!");
}
/* Print out options */
debug(1, "audio backend desired buffer length is %f seconds.",
config.audio_backend_buffer_desired_length);
debug(1, "audio backend latency offset is %f seconds.", config.audio_backend_latency_offset);
- debug(1, "volume range in dB (zero means use the range specified by the mixer): %u.", config.volume_range_db);
+ debug(1, "volume range in dB (zero means use the range specified by the mixer): %u.",
+ config.volume_range_db);
debug(1, "zeroconf regtype is \"%s\".", config.regtype);
debug(1, "decoders_supported field is %d.", config.decoders_supported);
debug(1, "use_apple_decoder is %d.", config.use_apple_decoder);
-
- char *realConfigPath = realpath(config.configfile,NULL);
+
+ char *realConfigPath = realpath(config.configfile, NULL);
if (realConfigPath) {
- debug(1, "configuration file name \"%s\" resolves to \"%s\".", config.configfile,realConfigPath);
+ debug(1, "configuration file name \"%s\" resolves to \"%s\".", config.configfile,
+ realConfigPath);
free(realConfigPath);
} else {
- debug(1, "configuration file name \"%s\" can not be resolved.", config.configfile);
- }
+ debug(1, "configuration file name \"%s\" can not be resolved.", config.configfile);
+ }
#ifdef CONFIG_METADATA
debug(1, "metdata enabled is %d.", config.metadata_enabled);
debug(1, "metadata pipename is \"%s\".", config.metadata_pipename);
- debug(1, "metadata socket address is \"%s\" port %d.", config.metadata_sockaddr, config.metadata_sockport);
+ debug(1, "metadata socket address is \"%s\" port %d.", config.metadata_sockaddr,
+ config.metadata_sockport);
debug(1, "metadata socket packet size is \"%d\".", config.metadata_sockmsglength);
debug(1, "get-coverart is %d.", config.get_coverart);
#endif
#ifdef CONFIG_METADATA
metadata_init(); // create the metadata pipe if necessary
#endif
- daemon_log(LOG_INFO,"Successful Startup");
+ daemon_log(LOG_INFO, "Successful Startup");
rtsp_listen_loop();
// should not reach this...
//******************************************************//
// mdns.c //
//******************************************************//
+#include <assert.h>
#include <stdint.h>
-#include <stdlib.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
-#include <assert.h>
#ifdef _WIN32
-#include <winsock.h>
#include <in6addr.h>
+#include <winsock.h>
#else
#include <netinet/in.h>
#endif
#include <ws2tcpip.h>
#define LOG_ERR 3
#else
-#include <sys/select.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
+#include <netinet/in.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <sys/socket.h>
#include <syslog.h>
#endif
-#include <sys/types.h>
-#include <sys/stat.h>
+#include <assert.h>
#include <fcntl.h>
+#include <pthread.h>
#include <signal.h>
-#include <string.h>
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
-#include <stdarg.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
-#include <assert.h>
-#include <pthread.h>
/*
* Define a proper IP socket level if not already done.