From: Mike Brady Date: Sun, 11 Sep 2016 09:35:53 +0000 (+0100) Subject: Tidy up with a clang-format X-Git-Tag: 3.0.d18~38 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=064bd293c560d0706d9c1cdf97613174afd93419;p=thirdparty%2Fshairport-sync.git Tidy up with a clang-format --- diff --git a/alac.c b/alac.c index cf72781a..c814ee3f 100644 --- a/alac.c +++ b/alac.c @@ -35,59 +35,60 @@ static const int host_bigendian = 0; #include #include #ifdef _WIN32 - #include "stdint_win.h" +#include "stdint_win.h" #else - #include +#include #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 */ @@ -97,122 +98,114 @@ void alac_set_info(alac_file *alac, char *inputbuffer) 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: @@ -240,247 +233,220 @@ static int count_leading_zeros(int32_t input) /* 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 @@ -499,657 +465,545 @@ static void predictor_decompress_fir_adapt(int32_t *error_buffer, } #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; } - diff --git a/alac.h b/alac.h index 09666a1d..a56c29f1 100644 --- a/alac.h +++ b/alac.h @@ -6,52 +6,43 @@ 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 */ - diff --git a/apple_alac.cpp b/apple_alac.cpp index 3996cfe3..0ee30290 100644 --- a/apple_alac.cpp +++ b/apple_alac.cpp @@ -1,12 +1,12 @@ #include // these are headers for the ALAC decoder, utilities and endian utilities -#include #include +#include #include -#include "config.h" #include "apple_alac.h" +#include "config.h" typedef struct magicCookie { ALACSpecificConfig config; @@ -14,43 +14,42 @@ typedef struct magicCookie { } 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); } diff --git a/apple_alac.h b/apple_alac.h index 11ed4ded..eb8bcf6c 100644 --- a/apple_alac.h +++ b/apple_alac.h @@ -1,21 +1,20 @@ #ifndef __APPLE_ALAC_H #define __APPLE_ALAC_H -#include #include "config.h" +#include #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 */ - diff --git a/audio.c b/audio.c index 6c2c6fce..e40006c4 100644 --- a/audio.c +++ b/audio.c @@ -24,10 +24,10 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include -#include #include "audio.h" #include "config.h" +#include +#include #ifdef CONFIG_SNDIO extern audio_output audio_sndio; @@ -67,7 +67,7 @@ static audio_output *outputs[] = { #ifdef CONFIG_DUMMY &audio_dummy, #endif -#ifdef CONFIG_PIPE +#ifdef CONFIG_PIPE &audio_pipe, #endif #ifdef CONFIG_STDOUT diff --git a/audio.h b/audio.h index b93e48b5..31fa1069 100644 --- a/audio.h +++ b/audio.h @@ -1,8 +1,8 @@ #ifndef _AUDIO_H #define _AUDIO_H -#include #include +#include typedef struct { double current_volume_dB; @@ -32,17 +32,17 @@ typedef struct { // 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); diff --git a/audio_alsa.c b/audio_alsa.c index 348a0d1f..3319a7cf 100644 --- a/audio_alsa.c +++ b/audio_alsa.c @@ -26,14 +26,14 @@ #define ALSA_PCM_NEW_HW_PARAMS_API -#include -#include -#include +#include "audio.h" +#include "common.h" +#include #include +#include #include -#include -#include "common.h" -#include "audio.h" +#include +#include static void help(void); static int init(int argc, char **argv); @@ -42,7 +42,7 @@ static void start(int i_sample_rate, int i_sample_format); 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); @@ -50,20 +50,18 @@ static void mute(int do_mute); 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; @@ -87,15 +85,15 @@ static int alsa_mix_index = 0; 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" @@ -138,9 +136,9 @@ static int init(int argc, char **argv) { 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; @@ -149,8 +147,7 @@ static int init(int argc, char **argv) { 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 " @@ -162,8 +159,7 @@ static int init(int argc, char **argv) { } /* 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", @@ -195,7 +191,7 @@ static int init(int argc, char **argv) { 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) @@ -205,7 +201,7 @@ static int init(int argc, char **argv) { 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) @@ -219,26 +215,26 @@ static int init(int argc, char **argv) { 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) @@ -249,10 +245,9 @@ static int init(int argc, char **argv) { 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.", @@ -262,10 +257,9 @@ static int init(int argc, char **argv) { } /* 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.", @@ -274,8 +268,6 @@ static int init(int argc, char **argv) { 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() @@ -316,7 +308,7 @@ static int init(int argc, char **argv) { debug(1, "Output device name is \"%s\".", alsa_out_dev); if (hardware_mixer) { - + if (alsa_mix_dev == NULL) alsa_mix_dev = alsa_out_dev; @@ -324,25 +316,24 @@ static int init(int argc, char **argv) { 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 " @@ -357,16 +348,12 @@ static int init(int argc, char **argv) { 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); } /* @@ -386,14 +373,13 @@ static int init(int argc, char **argv) { } } 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; @@ -408,7 +394,7 @@ static void deinit(void) { } 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 @@ -436,77 +422,83 @@ int open_alsa_device(void) { 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) { @@ -515,12 +507,11 @@ int open_alsa_device(void) { 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 = @@ -543,153 +534,158 @@ int open_alsa_device(void) { 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; @@ -709,12 +705,11 @@ int delay(long* the_delay) { 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); @@ -723,8 +718,8 @@ int delay(long* the_delay) { } 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; } } @@ -736,7 +731,7 @@ static void play(short buf[], int samples) { 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); @@ -747,17 +742,17 @@ static void play(short buf[], int samples) { 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.", @@ -795,8 +790,7 @@ static void flush(void) { */ 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); @@ -822,7 +816,7 @@ static void parameters(audio_parameters *info) { 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) { @@ -830,17 +824,17 @@ static void volume(double vol) { 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) { @@ -860,8 +854,7 @@ static void linear_volume(double vol) { 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) diff --git a/audio_ao.c b/audio_ao.c index 62c0729f..69867caa 100644 --- a/audio_ao.c +++ b/audio_ao.c @@ -24,12 +24,12 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#include "audio.h" +#include "common.h" +#include +#include #include #include -#include -#include -#include "common.h" -#include "audio.h" ao_device *dev = NULL; @@ -50,13 +50,12 @@ static int init(int argc, char **argv) { 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 " @@ -68,8 +67,7 @@ static int init(int argc, char **argv) { } /* 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", diff --git a/audio_dummy.c b/audio_dummy.c index 3f24dadd..98d14efb 100644 --- a/audio_dummy.c +++ b/audio_dummy.c @@ -28,11 +28,11 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#include "audio.h" +#include "common.h" #include -#include #include -#include "common.h" -#include "audio.h" +#include int Fs; long long starttime, samples_played; diff --git a/audio_pipe.c b/audio_pipe.c index 155e9b07..550893dd 100644 --- a/audio_pipe.c +++ b/audio_pipe.c @@ -28,16 +28,16 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include -#include +#include "audio.h" +#include "common.h" +#include #include #include +#include #include -#include -#include #include -#include "common.h" -#include "audio.h" +#include +#include static int fd = -1; @@ -51,7 +51,7 @@ static void start(int sample_rate, int sample_format) { 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) { @@ -60,9 +60,9 @@ static void play(short buf[], int samples) { } 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) { @@ -80,13 +80,12 @@ 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 " @@ -98,8 +97,7 @@ static int init(int argc, char **argv) { } /* 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", @@ -113,8 +111,7 @@ static int init(int argc, char **argv) { 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); @@ -125,13 +122,11 @@ static int init(int argc, char **argv) { } 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, diff --git a/audio_pulse.c b/audio_pulse.c index e4118259..083f863b 100644 --- a/audio_pulse.c +++ b/audio_pulse.c @@ -28,14 +28,14 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include -#include +#include "audio.h" +#include "common.h" #include -#include -#include #include -#include "common.h" -#include "audio.h" +#include +#include +#include +#include static pa_simple *pa_dev = NULL; diff --git a/audio_sndio.c b/audio_sndio.c index 1d2e1532..357e405b 100644 --- a/audio_sndio.c +++ b/audio_sndio.c @@ -19,10 +19,10 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "audio.h" +#include #include #include -#include -#include "audio.h" static struct sio_hdl *sio; static struct sio_par par; @@ -88,4 +88,4 @@ audio_output audio_sndio = {.name = "sndio", .play = &play, .volume = &volume, .parameters = NULL, - .mute= NULL}; + .mute = NULL}; diff --git a/audio_stdout.c b/audio_stdout.c index b24e0da1..fff9c654 100644 --- a/audio_stdout.c +++ b/audio_stdout.c @@ -27,24 +27,20 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include -#include +#include "audio.h" +#include "common.h" +#include #include #include +#include #include -#include -#include "common.h" -#include "audio.h" +#include 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 @@ -60,8 +56,7 @@ static int init(int argc, char **argv) { 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 " @@ -73,8 +68,7 @@ static int init(int argc, char **argv) { } /* 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", @@ -90,19 +84,17 @@ static void deinit(void) { // 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}; diff --git a/common.c b/common.c index c1eb58e2..3389e5f9 100644 --- a/common.c +++ b/common.c @@ -25,20 +25,20 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include -#include -#include -#include #include -#include -#include -#include +#include #include +#include +#include +#include +#include #include #include +#include +#include -#include #include "common.h" +#include #ifdef COMPILE_FOR_OSX #include @@ -47,20 +47,20 @@ #endif #ifdef HAVE_LIBSSL -#include -#include -#include #include #include +#include +#include +#include #endif #ifdef HAVE_LIBPOLARSSL -#include +#include "polarssl/ctr_drbg.h" +#include "polarssl/entropy.h" #include -#include #include -#include "polarssl/entropy.h" -#include "polarssl/ctr_drbg.h" +#include +#include #if POLARSSL_VERSION_NUMBER >= 0x01030000 #include "polarssl/compat-1.2.h" @@ -478,7 +478,8 @@ uint64_t get_absolute_time_in_fp() { 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; @@ -513,13 +514,13 @@ uint64_t get_absolute_time_in_fp() { } 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) { @@ -527,51 +528,55 @@ ssize_t non_blocking_write(int fd, const void *buf, size_t count) { } 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; } @@ -579,36 +584,35 @@ char *str_replace ( const char *string, const char *substr, const char *replacem /* 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); } diff --git a/common.h b/common.h index d146ab3a..64b9b44f 100644 --- a/common.h +++ b/common.h @@ -1,12 +1,12 @@ #ifndef _COMMON_H #define _COMMON_H +#include #include #include -#include -#include "config.h" #include "audio.h" +#include "config.h" #include "mdns.h" #if defined(__APPLE__) && defined(__MACH__) @@ -58,28 +58,72 @@ enum decoders_supported_type { // 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; @@ -93,9 +137,10 @@ typedef struct { 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 @@ -110,26 +155,30 @@ typedef struct { 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; @@ -142,9 +191,10 @@ void set_requested_connection_state_to_output(int v); 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 @@ -152,7 +202,6 @@ void r64init(uint64_t seed); uint64_t r64u(); int64_t r64i(); - int debuglev; void die(char *format, ...); void warn(char *format, ...); diff --git a/mdns.c b/mdns.c index fa5bfb91..ad8d8775 100644 --- a/mdns.c +++ b/mdns.c @@ -24,13 +24,13 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#include "mdns.h" +#include "common.h" +#include "config.h" #include -#include #include #include -#include "config.h" -#include "common.h" -#include "mdns.h" +#include #ifdef CONFIG_AVAHI extern mdns_backend mdns_avahi; @@ -46,10 +46,12 @@ extern mdns_backend mdns_tinysvcmdns; 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, diff --git a/mdns.h b/mdns.h index 4c1cf247..c4fe4bc6 100644 --- a/mdns.h +++ b/mdns.h @@ -23,9 +23,10 @@ typedef struct { // "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 @@ -33,11 +34,9 @@ typedef struct { // "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 - - - diff --git a/mdns_avahi.c b/mdns_avahi.c index 065322d7..12df0505 100644 --- a/mdns_avahi.c +++ b/mdns_avahi.c @@ -27,15 +27,15 @@ #include -#include #include "common.h" #include "mdns.h" +#include #include #include -#include -#include #include +#include +#include #include #include @@ -48,157 +48,148 @@ static AvahiThreadedPoll *tpoll = NULL; 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) { @@ -213,30 +204,30 @@ 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"); } } } @@ -244,30 +235,30 @@ static void register_service(AvahiClient *c) { 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; } } @@ -286,13 +277,13 @@ static int avahi_register(char *srvname, int srvport) { 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"); diff --git a/mdns_dns_sd.c b/mdns_dns_sd.c index fb9424a2..b4b7e4ac 100644 --- a/mdns_dns_sd.c +++ b/mdns_dns_sd.c @@ -24,12 +24,12 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include -#include -#include -#include #include "mdns.h" #include "common.h" +#include +#include +#include +#include static DNSServiceRef service; diff --git a/mdns_external.c b/mdns_external.c index c3b5dc1b..fcd3a323 100644 --- a/mdns_external.c +++ b/mdns_external.c @@ -24,14 +24,14 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include -#include -#include -#include +#include "mdns.h" +#include "common.h" #include +#include +#include #include -#include "common.h" -#include "mdns.h" +#include +#include int mdns_pid = 0; @@ -87,8 +87,8 @@ static int mdns_external_avahi_register(char *apname, int port) { 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}; @@ -126,8 +126,8 @@ static int mdns_external_dns_sd_register(char *apname, int port) { 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, diff --git a/mdns_tinysvcmdns.c b/mdns_tinysvcmdns.c index 049737b4..8d51d4bf 100644 --- a/mdns_tinysvcmdns.c +++ b/mdns_tinysvcmdns.c @@ -24,15 +24,15 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#include "mdns.h" +#include "common.h" +#include +#include +#include #include -#include #include -#include -#include +#include #include -#include -#include "common.h" -#include "mdns.h" #include "tinysvcmdns.h" @@ -124,22 +124,23 @@ static int mdns_tinysvcmdns_register(char *apname, int port) { #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; diff --git a/player.c b/player.c index 96d3ac27..0e226c1c 100644 --- a/player.c +++ b/player.c @@ -28,22 +28,22 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#include +#include +#include +#include +#include +#include +#include +#include #include #include -#include +#include #include -#include -#include -#include #include -#include #include -#include -#include -#include -#include -#include -#include +#include +#include #include "config.h" @@ -76,9 +76,9 @@ static AES_KEY aes; #endif static int input_rate, input_bit_depth, input_num_channels, max_frames_per_packet; -static uint32_t timestamp_epoch, last_timestamp, maximum_timestamp_interval;// timestamp_epoch of zero means not initialised, could start at 2 or 1. - - +static 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; @@ -86,7 +86,6 @@ static int output_sample_ratio; static int output_rate; static int64_t previous_random_number = 0; - // The maximum frame size change there can be is +/- 1; static int max_frame_size_change; // #define FRAME_BYTES(max_frames_per_packet) (4 * max_frames_per_packet) @@ -97,11 +96,12 @@ static int max_frame_size_change; 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; @@ -156,56 +156,58 @@ static uint64_t missing_packets, late_packets, too_late_packets, resend_requests // 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 (timestampmaximum_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; @@ -239,7 +241,7 @@ static inline seq_t PREDECESSOR(seq_t x) { // 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 @@ -296,16 +298,17 @@ static int alac_decode(short *dest, int *destlen, uint8_t *buf, int len) { // parameters: where the decoded stuff goes, its length in samples, // the incoming packet, the length of the incoming packet in bytes // destlen should contain the allowed max number of samples on entry - - if (len>MAX_PACKET) { - warn("Incoming audio packet size is too large at %d; it should not exceed %d.",len,MAX_PACKET); + + 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) { @@ -321,101 +324,132 @@ static int alac_decode(short *dest, int *destlen, uint8_t *buf, int len) { memcpy(packet + aeslen, buf + aeslen, len - aeslen); #ifdef HAVE_APPLE_ALAC if (config.use_apple_decoder) { - if (decoder_in_use!=1<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; @@ -424,8 +458,8 @@ static int init_decoder(int32_t fmtp[12]) { 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) @@ -462,7 +496,8 @@ static void terminate_decoders(void) { 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(); } @@ -473,35 +508,35 @@ static void free_buffer(void) { } 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; @@ -531,8 +566,8 @@ void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len) { } // 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++; @@ -551,16 +586,16 @@ void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len) { 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; } } @@ -575,125 +610,154 @@ void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len) { 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; } } @@ -703,28 +767,31 @@ static inline short dithered_vol(short sample) { 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; @@ -742,7 +809,7 @@ static abuf_t *buffer_get_frame(void) { 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 @@ -785,12 +852,14 @@ static abuf_t *buffer_get_frame(void) { 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. @@ -805,15 +874,14 @@ static abuf_t *buffer_get_frame(void) { } } - 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)); @@ -826,13 +894,15 @@ static abuf_t *buffer_get_frame(void) { 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)); @@ -865,42 +935,50 @@ static abuf_t *buffer_get_frame(void) { // 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) { @@ -919,11 +997,11 @@ debug(1,"Output sample ratio is %d",output_sample_ratio); } 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 = @@ -944,9 +1022,10 @@ debug(1,"Output sample ratio is %d",output_sample_ratio); 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; @@ -957,15 +1036,18 @@ debug(1,"Output sample ratio is %d",output_sample_ratio); 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); @@ -979,12 +1061,14 @@ debug(1,"Output sample ratio is %d",output_sample_ratio); 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 - } + } } } } @@ -1003,25 +1087,32 @@ debug(1,"Output sample ratio is %d",output_sample_ratio); 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); } @@ -1031,21 +1122,21 @@ debug(1,"Output sample ratio is %d",output_sample_ratio); } } } - 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; @@ -1094,11 +1185,10 @@ debug(1,"Output sample ratio is %d",output_sample_ratio); } } - 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; @@ -1127,21 +1217,23 @@ static inline int32_t mean_32(int32_t a, int32_t b) { 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) @@ -1151,39 +1243,40 @@ static int stuff_buffer_basic_32(int32_t *inptr, int length, enum sps_format_t l 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/ } @@ -1212,11 +1305,12 @@ static int stuff_buffer_basic(short *inptr, int length, short *outptr, int stuff 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++); @@ -1229,13 +1323,14 @@ static int stuff_buffer_basic(short *inptr, int length, short *outptr, int stuff } #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/ } @@ -1255,8 +1350,8 @@ static int stuff_buffer_soxr(short *inptr, int length, short *outptr, int stuff) 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.*/ @@ -1314,44 +1409,48 @@ typedef struct stats { // statistics for running averages } 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 @@ -1387,58 +1486,63 @@ static void *player_thread_func(void *arg) { 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, " @@ -1486,103 +1590,105 @@ static void *player_thread_func(void *arg) { // 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 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 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. @@ -1593,12 +1699,13 @@ static void *player_thread_func(void *arg) { 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; @@ -1609,12 +1716,18 @@ static void *player_thread_func(void *arg) { 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 } @@ -1626,60 +1739,64 @@ static void *player_thread_func(void *arg) { // 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); @@ -1687,10 +1804,10 @@ static void *player_thread_func(void *arg) { // 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; } @@ -1701,51 +1818,60 @@ static void *player_thread_func(void *arg) { } // 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 /* @@ -1762,27 +1888,27 @@ static void *player_thread_func(void *arg) { 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 @@ -1798,31 +1924,34 @@ static void *player_thread_func(void *arg) { 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*)! } } } @@ -1835,10 +1964,12 @@ static void *player_thread_func(void *arg) { // 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; @@ -1874,10 +2005,9 @@ static void *player_thread_func(void *arg) { 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), @@ -1890,67 +2020,56 @@ static void *player_thread_func(void *arg) { // 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."); @@ -1966,32 +2085,34 @@ static void *player_thread_func(void *arg) { } 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; } @@ -2003,72 +2124,81 @@ void player_volume(double airplay_volume) { // 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)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 @@ -2119,14 +2251,16 @@ void player_volume(double airplay_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); @@ -2135,17 +2269,15 @@ void player_volume(double airplay_volume) { 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) @@ -2158,8 +2290,8 @@ void player_flush(int64_t timestamp) { } 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) @@ -2197,7 +2329,7 @@ int player_play(stream_cfg *stream, pthread_t *player_thread) { #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); @@ -2210,20 +2342,20 @@ int player_play(stream_cfg *stream, pthread_t *player_thread) { } 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."); + // } } diff --git a/player.h b/player.h index bd14acd2..eba97e8e 100644 --- a/player.h +++ b/player.h @@ -22,10 +22,14 @@ void player_flush(int64_t timestamp); 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 diff --git a/rtp.c b/rtp.c index cbef773d..aad447fb 100644 --- a/rtp.c +++ b/rtp.c @@ -24,19 +24,19 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include #include +#include +#include +#include #include -#include +#include +#include +#include +#include #include "common.h" #include "player.h" @@ -59,17 +59,18 @@ typedef struct time_ping_record { 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; @@ -104,29 +105,33 @@ void *rtp_audio_receiver(void *arg) { 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; @@ -155,7 +160,7 @@ void *rtp_audio_receiver(void *arg) { 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... } @@ -200,7 +205,7 @@ void *rtp_control_receiver(void *arg) { 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); @@ -231,15 +236,15 @@ void *rtp_control_receiver(void *arg) { 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, @@ -265,7 +270,7 @@ void *rtp_control_receiver(void *arg) { } } 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)); @@ -293,7 +298,7 @@ void *rtp_control_receiver(void *arg) { 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; @@ -314,8 +319,8 @@ void *rtp_timing_sender(void *arg) { 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!"); @@ -351,7 +356,7 @@ void *rtp_timing_receiver(void *arg) { 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; @@ -365,11 +370,11 @@ void *rtp_timing_receiver(void *arg) { 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); @@ -428,13 +433,14 @@ void *rtp_timing_receiver(void *arg) { // 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; @@ -465,69 +471,81 @@ void *rtp_timing_receiver(void *arg) { // 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); } @@ -545,44 +563,45 @@ void *rtp_timing_receiver(void *arg) { 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); @@ -597,18 +616,18 @@ static int bind_port(int ip_family,const char *self_ip_address,uint32_t scope_id 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!"); @@ -617,13 +636,13 @@ void rtp_setup(SOCKADDR *local, SOCKADDR *remote, int cport, int tport, uint32_t 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; @@ -644,13 +663,10 @@ void rtp_setup(SOCKADDR *local, SOCKADDR *remote, int cport, int tport, uint32_t 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; @@ -692,23 +708,24 @@ void rtp_setup(SOCKADDR *local, SOCKADDR *remote, int cport, int tport, uint32_t // 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; @@ -726,25 +743,25 @@ void clear_reference_timestamp(void) { 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; //} @@ -765,8 +782,8 @@ void rtp_request_resend(seq_t first, uint32_t count) { 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; //} } diff --git a/rtp.h b/rtp.h index 195f6738..f4c8ab0b 100644 --- a/rtp.h +++ b/rtp.h @@ -5,21 +5,21 @@ #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; diff --git a/rtsp.c b/rtsp.c index 3f6d9646..e8dfe35b 100644 --- a/rtsp.c +++ b/rtsp.c @@ -26,23 +26,23 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include -#include -#include -#include #include +#include +#include +#include #include -#include +#include +#include +#include #include #include -#include #include -#include -#include -#include -#include -#include +#include +#include +#include #include +#include +#include #include "config.h" @@ -55,9 +55,9 @@ #endif #include "common.h" +#include "mdns.h" #include "player.h" #include "rtp.h" -#include "mdns.h" #ifdef AF_INET6 #define INETx_ADDRSTRLEN INET6_ADDRSTRLEN @@ -82,7 +82,7 @@ static pthread_mutex_t reference_counter_lock = PTHREAD_MUTEX_INITIALIZER; // 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; @@ -90,14 +90,15 @@ typedef struct { 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() { @@ -144,8 +145,7 @@ typedef struct { 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); @@ -157,8 +157,8 @@ void pc_queue_init(pc_queue *the_queue, char *items, size_t item_size, 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); @@ -176,8 +176,7 @@ int pc_queue_add_item(pc_queue *the_queue, const void *the_stuff, int 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"); } @@ -214,8 +213,7 @@ int pc_queue_get_item(pc_queue *the_queue, void *the_stuff) { 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"); } @@ -263,11 +261,10 @@ static inline int rtsp_playing(void) { 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; @@ -314,8 +311,7 @@ void ask_other_rtsp_conversation_threads_to_stop(pthread_t except_this_thread) { 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); @@ -363,8 +359,7 @@ static void msg_retain(rtsp_message *msg) { 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; } @@ -405,8 +400,7 @@ static void msg_free(rtsp_message *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++) { @@ -479,8 +473,8 @@ fail: 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); @@ -499,8 +493,8 @@ rtsp_read_request(rtsp_conn_info *conn, rtsp_message **the_packet) { 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; @@ -542,8 +536,8 @@ rtsp_read_request(rtsp_conn_info *conn, rtsp_message **the_packet) { 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; @@ -628,8 +622,7 @@ static void msg_write_response(int fd, rtsp_message *resp) { 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 @@ -663,16 +656,14 @@ static void handle_record(rtsp_conn_info *conn, rtsp_message *req, } } -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"); @@ -681,8 +672,7 @@ static void handle_teardown(rtsp_conn_info *conn, rtsp_message *req, 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"); @@ -705,8 +695,7 @@ static void handle_flush(rtsp_conn_info *conn, rtsp_message *req, 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; @@ -768,10 +757,8 @@ static void handle_setup(rtsp_conn_info *conn, rtsp_message *req, 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 " @@ -779,8 +766,7 @@ static void handle_setup(rtsp_conn_info *conn, rtsp_message *req, 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); } } @@ -809,9 +795,8 @@ static void handle_setup(rtsp_conn_info *conn, rtsp_message *req, 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; @@ -853,13 +838,11 @@ error: 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; @@ -888,7 +871,7 @@ static void handle_set_parameter_parameter(rtsp_conn_info *conn, #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 @@ -978,12 +961,11 @@ static void handle_set_parameter_parameter(rtsp_conn_info *conn, // 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}; @@ -992,8 +974,8 @@ 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) @@ -1090,8 +1072,7 @@ static void metadata_close(void) { 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; @@ -1105,7 +1086,8 @@ void metadata_process(uint32_t type, uint32_t code, char *data, 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 @@ -1114,9 +1096,8 @@ void metadata_process(uint32_t type, uint32_t code, char *data, if (fd < 0) return; char thestring[1024]; - snprintf(thestring, 1024, - "%x%x%u", type, - code, length); + snprintf(thestring, 1024, "%x%x%u", type, code, + length); ret = non_blocking_write(fd, thestring, strlen(thestring)); if (ret < 0) { // debug(1,"metadata_process error %d exit 1",ret); @@ -1141,10 +1122,9 @@ void metadata_process(uint32_t type, uint32_t code, char *data, 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); @@ -1188,16 +1168,15 @@ void *metadata_thread_function(void *ignore) { 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 @@ -1237,14 +1216,11 @@ int send_metadata(uint32_t type, uint32_t code, char *data, uint32_t length, 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; @@ -1254,14 +1230,12 @@ static void handle_set_parameter_metadata(rtsp_conn_info *conn, 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); @@ -1278,14 +1252,12 @@ static void handle_set_parameter_metadata(rtsp_conn_info *conn, #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."); @@ -1294,7 +1266,7 @@ static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, 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 @@ -1322,8 +1294,7 @@ static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, 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 @@ -1331,8 +1302,7 @@ static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, 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 @@ -1348,8 +1318,7 @@ static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, 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 @@ -1357,8 +1326,7 @@ static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, 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 @@ -1369,11 +1337,9 @@ static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, #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."); @@ -1382,8 +1348,7 @@ static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, 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 @@ -1400,15 +1365,15 @@ static void handle_announce(rtsp_conn_info *conn, rtsp_message *req, 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; @@ -1479,8 +1444,7 @@ static void handle_announce(rtsp_conn_info *conn, rtsp_message *req, 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"); @@ -1655,8 +1619,7 @@ static int rtsp_auth(char **nonce, rtsp_message *req, rtsp_message *resp) { 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)); @@ -1728,8 +1691,8 @@ static void *rtsp_conversation_thread_func(void *pconn) { 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; @@ -1737,26 +1700,25 @@ static void *rtsp_conversation_thread_func(void *pconn) { 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); @@ -1778,11 +1740,11 @@ static void *rtsp_conversation_thread_func(void *pconn) { 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; @@ -1828,7 +1790,7 @@ void rtsp_listen_loop(void) { } 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; @@ -1862,14 +1824,15 @@ void rtsp_listen_loop(void) { // 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; } @@ -1882,7 +1845,9 @@ void rtsp_listen_loop(void) { 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; @@ -1935,49 +1900,51 @@ void rtsp_listen_loop(void) { 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!"); diff --git a/rtsp.h b/rtsp.h index a2f6a952..5058c9a1 100644 --- a/rtsp.h +++ b/rtsp.h @@ -5,7 +5,6 @@ void rtsp_listen_loop(void); // void rtsp_shutdown_stream(void); void rtsp_request_shutdown_stream(void); - // initialise the metadata stuff void metadata_init(void); diff --git a/shairport.c b/shairport.c index 538f418e..e8326233 100644 --- a/shairport.c +++ b/shairport.c @@ -25,20 +25,20 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include -#include #include -#include -#include #include -#include -#include #include +#include +#include +#include +#include +#include #include #include -#include -#include -#include +#include +#include +#include +#include #include "config.h" @@ -51,20 +51,20 @@ #endif #include "common.h" -#include "rtsp.h" -#include "rtp.h" #include "mdns.h" +#include "rtp.h" +#include "rtsp.h" +#include #include -#include #include #include -#include +#include 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) @@ -80,7 +80,7 @@ static void sig_ignore(int foo, siginfo_t *bar, void *baz) {} 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); @@ -105,52 +105,52 @@ static void sig_connect_audio_output(int foo, siginfo_t *bar, void *baz) { 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); } @@ -158,12 +158,12 @@ char* get_version_string() { } 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!"); } } @@ -182,21 +182,25 @@ void usage(char *progname) { "/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 -- " @@ -209,12 +213,14 @@ void usage(char *progname) { "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"); @@ -237,12 +243,13 @@ void usage(char *progname) { } 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}, @@ -272,10 +279,9 @@ int parse_options(int argc, char **argv) { {"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; @@ -285,8 +291,8 @@ int parse_options(int argc, char **argv) { 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) { @@ -300,17 +306,17 @@ int parse_options(int argc, char **argv) { } 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. */ @@ -358,7 +364,8 @@ int parse_options(int argc, char **argv) { 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", @@ -419,7 +426,7 @@ int parse_options(int argc, char **argv) { } /* 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) @@ -428,15 +435,17 @@ int parse_options(int argc, char **argv) { 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; @@ -447,15 +456,16 @@ int parse_options(int argc, char **argv) { if (strcasecmp(str, "hammerton") == 0) config.use_apple_decoder = 0; else if (strcasecmp(str, "apple") == 0) { - if ((config.decoders_supported & 1< 65000 ? 65000 : value; } - #endif +#endif if (config_lookup_string(config.cfg, "sessioncontrol.run_this_before_play_begins", &str)) { config.cmd_start = (char *)str; @@ -534,7 +544,8 @@ int parse_options(int argc, char **argv) { 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\""); } @@ -555,8 +566,9 @@ int parse_options(int argc, char **argv) { 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++) @@ -609,34 +621,34 @@ int parse_options(int argc, char **argv) { 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); @@ -724,27 +736,27 @@ int main(int argc, char **argv) { 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); @@ -752,38 +764,44 @@ int main(int argc, char **argv) { 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<= 2 && ((strcmp(argv[1], "-V") == 0) || (strcmp(argv[1], "--version") == 0))) { @@ -878,7 +896,7 @@ int main(int argc, char **argv) { // 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 */ @@ -948,69 +966,84 @@ int main(int argc, char **argv) { 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 */ @@ -1045,22 +1078,25 @@ int main(int argc, char **argv) { 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 @@ -1084,7 +1120,7 @@ int main(int argc, char **argv) { #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... diff --git a/tinysvcmdns.c b/tinysvcmdns.c index cadea483..bf261891 100644 --- a/tinysvcmdns.c +++ b/tinysvcmdns.c @@ -48,15 +48,15 @@ //******************************************************// // mdns.c // //******************************************************// +#include #include -#include #include +#include #include -#include #ifdef _WIN32 -#include #include +#include #else #include #endif @@ -1029,26 +1029,26 @@ size_t mdns_encode_pkt(struct mdns_pkt *answer, uint8_t *pkt_buf, size_t pkt_len #include #define LOG_ERR 3 #else -#include -#include -#include -#include #include #include +#include +#include +#include +#include #include #endif -#include -#include +#include #include +#include #include -#include +#include #include #include -#include +#include +#include +#include #include -#include -#include /* * Define a proper IP socket level if not already done.