Tidy up with a clang-format
This commit is contained in:
@@ -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 */
|
||||
|
||||
|
||||
+24
-25
@@ -1,12 +1,12 @@
|
||||
#include <string.h>
|
||||
|
||||
// these are headers for the ALAC decoder, utilities and endian utilities
|
||||
#include <alac/ALACDecoder.h>
|
||||
#include <alac/ALACBitUtilities.h>
|
||||
#include <alac/ALACDecoder.h>
|
||||
#include <alac/EndianPortable.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "apple_alac.h"
|
||||
#include "config.h"
|
||||
|
||||
typedef struct magicCookie {
|
||||
ALACSpecificConfig config;
|
||||
@@ -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); }
|
||||
|
||||
+5
-6
@@ -1,21 +1,20 @@
|
||||
#ifndef __APPLE_ALAC_H
|
||||
#define __APPLE_ALAC_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "config.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define EXTERNC extern "C"
|
||||
#define EXTERNC extern "C"
|
||||
#else
|
||||
#define EXTERNC
|
||||
#define EXTERNC
|
||||
#endif
|
||||
|
||||
|
||||
EXTERNC int apple_alac_init(int32_t fmtp[12]);
|
||||
EXTERNC int apple_alac_terminate();
|
||||
EXTERNC int apple_alac_decode_frame(unsigned char *sampleBuffer, uint32_t bufferLength, unsigned char *dest, int *outsize);
|
||||
EXTERNC int apple_alac_decode_frame(unsigned char *sampleBuffer, uint32_t bufferLength,
|
||||
unsigned char *dest, int *outsize);
|
||||
|
||||
#undef EXTERNC
|
||||
|
||||
#endif /* __APPLE_ALAC_H */
|
||||
|
||||
|
||||
@@ -24,10 +24,10 @@
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "audio.h"
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef CONFIG_SNDIO
|
||||
extern audio_output audio_sndio;
|
||||
@@ -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
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#ifndef _AUDIO_H
|
||||
#define _AUDIO_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <libconfig.h>
|
||||
#include <stdint.h>
|
||||
|
||||
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);
|
||||
|
||||
+270
-277
@@ -26,14 +26,14 @@
|
||||
|
||||
#define ALSA_PCM_NEW_HW_PARAMS_API
|
||||
|
||||
#include "audio.h"
|
||||
#include "common.h"
|
||||
#include <alsa/asoundlib.h>
|
||||
#include <math.h>
|
||||
#include <memory.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <memory.h>
|
||||
#include <math.h>
|
||||
#include <pthread.h>
|
||||
#include <alsa/asoundlib.h>
|
||||
#include "common.h"
|
||||
#include "audio.h"
|
||||
|
||||
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);
|
||||
// }
|
||||
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,"alsa device parameters:");
|
||||
debug(log_level, "PCM handle name = '%s'", snd_pcm_name(alsa_handle));
|
||||
|
||||
snd_pcm_hw_params_get_access(alsa_params,&access_type);
|
||||
debug(log_level," access type = %s", snd_pcm_access_name(access_type));
|
||||
// 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);
|
||||
// }
|
||||
|
||||
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));
|
||||
debug(log_level, "alsa device parameters:");
|
||||
|
||||
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_access(alsa_params, &access_type);
|
||||
debug(log_level, " access type = %s", snd_pcm_access_name(access_type));
|
||||
|
||||
snd_pcm_hw_params_get_channels(alsa_params, &uval);
|
||||
debug(log_level," number of channels = %u", uval);
|
||||
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));
|
||||
|
||||
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;
|
||||
}
|
||||
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));
|
||||
|
||||
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_channels(alsa_params, &uval);
|
||||
debug(log_level, " number of channels = %u", uval);
|
||||
|
||||
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;
|
||||
}
|
||||
sval = snd_pcm_hw_params_get_sbits(alsa_params);
|
||||
debug(log_level, " number of significant bits = %d", sval);
|
||||
|
||||
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_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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
+7
-9
@@ -24,12 +24,12 @@
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "audio.h"
|
||||
#include "common.h"
|
||||
#include <ao/ao.h>
|
||||
#include <memory.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <memory.h>
|
||||
#include <ao/ao.h>
|
||||
#include "common.h"
|
||||
#include "audio.h"
|
||||
|
||||
ao_device *dev = NULL;
|
||||
|
||||
@@ -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",
|
||||
|
||||
+4
-4
@@ -28,11 +28,11 @@
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include "common.h"
|
||||
#include "audio.h"
|
||||
#include "common.h"
|
||||
#include <stdio.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int Fs;
|
||||
long long starttime, samples_played;
|
||||
|
||||
+16
-21
@@ -28,16 +28,16 @@
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "audio.h"
|
||||
#include "common.h"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <memory.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include "common.h"
|
||||
#include "audio.h"
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static int fd = -1;
|
||||
|
||||
@@ -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,
|
||||
|
||||
+6
-6
@@ -28,14 +28,14 @@
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "audio.h"
|
||||
#include "common.h"
|
||||
#include <memory.h>
|
||||
#include <pulse/def.h>
|
||||
#include <pulse/error.h>
|
||||
#include <pulse/simple.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <memory.h>
|
||||
#include <pulse/simple.h>
|
||||
#include <pulse/error.h>
|
||||
#include <pulse/def.h>
|
||||
#include "common.h"
|
||||
#include "audio.h"
|
||||
|
||||
static pa_simple *pa_dev = NULL;
|
||||
|
||||
|
||||
+3
-3
@@ -19,10 +19,10 @@
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "audio.h"
|
||||
#include <sndio.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sndio.h>
|
||||
#include "audio.h"
|
||||
|
||||
static struct sio_hdl *sio;
|
||||
static struct sio_par par;
|
||||
@@ -88,4 +88,4 @@ audio_output audio_sndio = {.name = "sndio",
|
||||
.play = &play,
|
||||
.volume = &volume,
|
||||
.parameters = NULL,
|
||||
.mute= NULL};
|
||||
.mute = NULL};
|
||||
|
||||
+21
-29
@@ -27,24 +27,20 @@
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include "audio.h"
|
||||
#include "common.h"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <memory.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include "common.h"
|
||||
#include "audio.h"
|
||||
#include <unistd.h>
|
||||
|
||||
static int fd = -1;
|
||||
|
||||
static void start(int sample_rate, int sample_format) {
|
||||
fd = STDOUT_FILENO;
|
||||
}
|
||||
static void start(int sample_rate, int sample_format) { fd = STDOUT_FILENO; }
|
||||
|
||||
static void play(short buf[], int samples) {
|
||||
int ignore = write(fd, buf, samples * 4);
|
||||
}
|
||||
static void play(short buf[], int samples) { int ignore = write(fd, buf, samples * 4); }
|
||||
|
||||
static void stop(void) {
|
||||
// don't close stdout
|
||||
@@ -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};
|
||||
|
||||
@@ -25,20 +25,20 @@
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <popt.h>
|
||||
#include <memory.h>
|
||||
#include <poll.h>
|
||||
#include <popt.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include "common.h"
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef COMPILE_FOR_OSX
|
||||
#include <CoreServices/CoreServices.h>
|
||||
@@ -47,20 +47,20 @@
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBSSL
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/buffer.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/rsa.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBPOLARSSL
|
||||
#include <polarssl/version.h>
|
||||
#include <polarssl/base64.h>
|
||||
#include <polarssl/x509.h>
|
||||
#include <polarssl/md.h>
|
||||
#include "polarssl/entropy.h"
|
||||
#include "polarssl/ctr_drbg.h"
|
||||
#include "polarssl/entropy.h"
|
||||
#include <polarssl/base64.h>
|
||||
#include <polarssl/md.h>
|
||||
#include <polarssl/version.h>
|
||||
#include <polarssl/x509.h>
|
||||
|
||||
#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); }
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#ifndef _COMMON_H
|
||||
#define _COMMON_H
|
||||
|
||||
#include <libconfig.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/socket.h>
|
||||
#include <libconfig.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "audio.h"
|
||||
#include "config.h"
|
||||
#include "mdns.h"
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
@@ -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, ...);
|
||||
|
||||
@@ -24,13 +24,13 @@
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "mdns.h"
|
||||
#include "common.h"
|
||||
#include "config.h"
|
||||
#include <memory.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "config.h"
|
||||
#include "common.h"
|
||||
#include "mdns.h"
|
||||
#include <string.h>
|
||||
|
||||
#ifdef CONFIG_AVAHI
|
||||
extern mdns_backend mdns_avahi;
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
+149
-158
@@ -27,15 +27,15 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <string.h>
|
||||
#include "common.h"
|
||||
#include "mdns.h"
|
||||
#include <string.h>
|
||||
|
||||
#include <avahi-client/client.h>
|
||||
#include <avahi-client/publish.h>
|
||||
#include <avahi-common/thread-watch.h>
|
||||
#include <avahi-common/malloc.h>
|
||||
#include <avahi-common/error.h>
|
||||
#include <avahi-common/malloc.h>
|
||||
#include <avahi-common/thread-watch.h>
|
||||
|
||||
#include <avahi-client/lookup.h>
|
||||
#include <avahi-common/alternative.h>
|
||||
@@ -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) {
|
||||
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);
|
||||
assert(r);
|
||||
|
||||
/* Called whenever a service has been resolved successfully or timed out */
|
||||
/* 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;
|
||||
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;
|
||||
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));
|
||||
// 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_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;
|
||||
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;
|
||||
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;
|
||||
/* 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 );
|
||||
debug(2, "avahi: service name collision, renaming service to '%s'", name);
|
||||
|
||||
/* And recreate the services */
|
||||
register_service( avahi_entry_group_get_client( g ) );
|
||||
break;
|
||||
}
|
||||
/* 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_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_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;
|
||||
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;
|
||||
}
|
||||
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_REGISTERING:
|
||||
if (group)
|
||||
avahi_entry_group_reset(group);
|
||||
break;
|
||||
|
||||
case AVAHI_CLIENT_S_RUNNING:
|
||||
register_service(c);
|
||||
break;
|
||||
case AVAHI_CLIENT_S_RUNNING:
|
||||
register_service(c);
|
||||
break;
|
||||
|
||||
case AVAHI_CLIENT_FAILURE:
|
||||
debug(1,"avahi: client failure");
|
||||
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_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;
|
||||
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;
|
||||
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");
|
||||
|
||||
+4
-4
@@ -24,12 +24,12 @@
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <dns_sd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "mdns.h"
|
||||
#include "common.h"
|
||||
#include <arpa/inet.h>
|
||||
#include <dns_sd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static DNSServiceRef service;
|
||||
|
||||
|
||||
+11
-11
@@ -24,14 +24,14 @@
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include "common.h"
|
||||
#include "mdns.h"
|
||||
#include "common.h"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
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,
|
||||
|
||||
+17
-16
@@ -24,15 +24,15 @@
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include "common.h"
|
||||
#include "mdns.h"
|
||||
#include "common.h"
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -24,19 +24,19 @@
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <time.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
#include <memory.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <memory.h>
|
||||
#include <math.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "player.h"
|
||||
@@ -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;
|
||||
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;
|
||||
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;
|
||||
//}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -26,23 +26,23 @@
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <memory.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/select.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <memory.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <poll.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
@@ -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,
|
||||
"<item><type>%x</type><code>%x</code><length>%u</length>", type,
|
||||
code, length);
|
||||
snprintf(thestring, 1024, "<item><type>%x</type><code>%x</code><length>%u</length>", type, code,
|
||||
length);
|
||||
ret = non_blocking_write(fd, thestring, strlen(thestring));
|
||||
if (ret < 0) {
|
||||
// debug(1,"metadata_process error %d exit 1",ret);
|
||||
@@ -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!");
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
+230
-194
@@ -25,20 +25,20 @@
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <memory.h>
|
||||
#include <sys/wait.h>
|
||||
#include <getopt.h>
|
||||
#include <libconfig.h>
|
||||
#include <libgen.h>
|
||||
#include <memory.h>
|
||||
#include <popt.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <popt.h>
|
||||
#include <libgen.h>
|
||||
#include <libconfig.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
@@ -51,20 +51,20 @@
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
#include "rtsp.h"
|
||||
#include "rtp.h"
|
||||
#include "mdns.h"
|
||||
#include "rtp.h"
|
||||
#include "rtsp.h"
|
||||
|
||||
#include <libdaemon/dexec.h>
|
||||
#include <libdaemon/dfork.h>
|
||||
#include <libdaemon/dsignal.h>
|
||||
#include <libdaemon/dlog.h>
|
||||
#include <libdaemon/dpid.h>
|
||||
#include <libdaemon/dexec.h>
|
||||
#include <libdaemon/dsignal.h>
|
||||
|
||||
static int shutting_down = 0;
|
||||
static char *appName = NULL;
|
||||
char configuration_file_path[4096+1];
|
||||
char actual_configuration_file_path[4096+1];
|
||||
char configuration_file_path[4096 + 1];
|
||||
char actual_configuration_file_path[4096 + 1];
|
||||
|
||||
void shairport_shutdown() {
|
||||
if (shutting_down)
|
||||
@@ -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<<decoder_apple_alac)!=0)
|
||||
if ((config.decoders_supported & 1 << decoder_apple_alac) != 0)
|
||||
config.use_apple_decoder = 1;
|
||||
else
|
||||
inform("Support for the Apple ALAC decoder has not been compiled into this version of Shairport Sync. The default decoder will be used.");
|
||||
inform("Support for the Apple ALAC decoder has not been compiled into this version of "
|
||||
"Shairport Sync. The default decoder will be used.");
|
||||
} else
|
||||
die("Invalid alac_decoder option choice \"%s\". It should be \"hammerton\" or \"apple\"");
|
||||
}
|
||||
|
||||
/* Get the default latency. Deprecated! */
|
||||
/* Get the default latency. Deprecated! */
|
||||
if (config_lookup_int(config.cfg, "latencies.default", &value))
|
||||
config.userSuppliedLatency = value;
|
||||
|
||||
@@ -471,7 +481,7 @@ int parse_options(int argc, char **argv) {
|
||||
if (config_lookup_int(config.cfg, "latencies.forkedDaapd", &value))
|
||||
config.ForkedDaapdLatency = value;
|
||||
|
||||
#ifdef CONFIG_METADATA
|
||||
#ifdef CONFIG_METADATA
|
||||
/* Get the metadata setting. */
|
||||
if (config_lookup_string(config.cfg, "metadata.enabled", &str)) {
|
||||
if (strcasecmp(str, "no") == 0)
|
||||
@@ -507,7 +517,7 @@ int parse_options(int argc, char **argv) {
|
||||
config.metadata_sockmsglength = value < 500 ? 500 : value > 65000 ? 65000 : value;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (config_lookup_string(config.cfg, "sessioncontrol.run_this_before_play_begins", &str)) {
|
||||
config.cmd_start = (char *)str;
|
||||
@@ -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<<decoder_hammerton; // David Hammerton's decoder supported by default
|
||||
#ifdef HAVE_APPLE_ALAC
|
||||
config.decoders_supported += 1<<decoder_apple_alac;
|
||||
#endif
|
||||
|
||||
// initialise random number generator
|
||||
|
||||
r64init(0);
|
||||
config.output_rate = 44100; // default
|
||||
config.decoders_supported =
|
||||
1 << decoder_hammerton; // David Hammerton's decoder supported by default
|
||||
#ifdef HAVE_APPLE_ALAC
|
||||
config.decoders_supported += 1 << decoder_apple_alac;
|
||||
#endif
|
||||
|
||||
// initialise random number generator
|
||||
|
||||
r64init(0);
|
||||
|
||||
/* Check if we are called with -V or --version parameter */
|
||||
if (argc >= 2 && ((strcmp(argv[1], "-V") == 0) || (strcmp(argv[1], "--version") == 0))) {
|
||||
@@ -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...
|
||||
|
||||
+15
-15
@@ -48,15 +48,15 @@
|
||||
//******************************************************//
|
||||
// mdns.c //
|
||||
//******************************************************//
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock.h>
|
||||
#include <in6addr.h>
|
||||
#include <winsock.h>
|
||||
#else
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
@@ -1029,26 +1029,26 @@ size_t mdns_encode_pkt(struct mdns_pkt *answer, uint8_t *pkt_buf, size_t pkt_len
|
||||
#include <ws2tcpip.h>
|
||||
#define LOG_ERR 3
|
||||
#else
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <syslog.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <pthread.h>
|
||||
|
||||
/*
|
||||
* Define a proper IP socket level if not already done.
|
||||
|
||||
Reference in New Issue
Block a user