Tidy up with a clang-format

This commit is contained in:
Mike Brady
2016-09-11 10:35:53 +01:00
parent 6bf0a1d483
commit 064bd293c5
29 changed files with 2907 additions and 2885 deletions
+756 -902
View File
File diff suppressed because it is too large Load Diff
+26 -35
View File
@@ -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
View File
@@ -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
View File
@@ -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 */
+3 -3
View File
@@ -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
+4 -4
View File
@@ -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
View File
@@ -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 = &parameters
};
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 = &parameters};
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 = &parameters; // 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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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};
+80 -76
View File
@@ -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); }
+82 -33
View File
@@ -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, ...);
+8 -6
View File
@@ -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,
+8 -9
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+838 -706
View File
File diff suppressed because it is too large Load Diff
+7 -3
View File
@@ -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
+161 -144
View File
@@ -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(&current_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(&current_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;
//}
}
+6 -6
View File
@@ -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;
+146 -179
View File
@@ -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,
&ltport);
// rtsp_take_player();
rtp_setup(&conn->local, &conn->remote, cport, tport, active_remote, &lsport, &lcport, &ltport);
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!");
-1
View File
@@ -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
View File
@@ -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
View File
@@ -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.