Merge support of apple's ALAC decoder

This commit is contained in:
Mike Brady
2016-08-28 21:38:24 +01:00
parent a1519f2abe
commit 945483d9c3
10 changed files with 194 additions and 19 deletions
+5
View File
@@ -4,6 +4,11 @@ bin_PROGRAMS = shairport-sync
shairport_sync_SOURCES = shairport.c rtsp.c mdns.c mdns_external.c common.c rtp.c player.c alac.c audio.c
AM_CFLAGS = -Wno-multichar -DSYSCONFDIR=\"$(sysconfdir)\"
AM_CPPFLAGS = -Wno-multichar -DSYSCONFDIR=\"$(sysconfdir)\"
if USE_APPLE_ALAC
shairport_sync_SOURCES += apple_alac.cpp
endif
if USE_CUSTOMPIDDIR
AM_CFLAGS+= \
+58
View File
@@ -0,0 +1,58 @@
#include <string.h>
// these are headers for the ALAC decoder, utilities and endian utilities
#include <alac/ALACDecoder.h>
#include <alac/ALACBitUtilities.h>
#include <alac/EndianPortable.h>
#include "config.h"
#include "apple_alac.h"
typedef struct magicCookie {
ALACSpecificConfig config;
ALACAudioChannelLayout channelLayoutInfo; // seems to be unused
} magicCookie;
magicCookie cookie;
ALACDecoder * theDecoder;
extern "C" int apple_alac_init(int frame_size,int sample_size,int sample_rate) {
memset(&cookie,0,sizeof(magicCookie));
#define CHANNELS_PER_FRAME 2
//create a magic cookie for the decoder
cookie.config.frameLength = Swap32NtoB(frame_size);
cookie.config.compatibleVersion = 0;
cookie.config.bitDepth = sample_size;
cookie.config.pb = 40;
cookie.config.mb = 10;
cookie.config.kb = 14;
cookie.config.numChannels = CHANNELS_PER_FRAME;
cookie.config.maxRun = Swap16NtoB(255);
cookie.config.maxFrameBytes = 0;
cookie.config.avgBitRate = 0;
cookie.config.sampleRate = Swap32NtoB(sample_rate);
theDecoder = new ALACDecoder;
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)
{
uint32_t numFrames = 0;
BitBuffer theInputBuffer;
BitBufferInit(&theInputBuffer, sampleBuffer, bufferLength);
theDecoder->Decode(&theInputBuffer, dest, Swap32BtoN(cookie.config.frameLength), CHANNELS_PER_FRAME, &numFrames);
*outsize = numFrames;
return 0;
}
extern "C" int apple_alac_terminate() {
delete(theDecoder);
}
+21
View File
@@ -0,0 +1,21 @@
#ifndef __APPLE_ALAC_H
#define __APPLE_ALAC_H
#include <stdint.h>
#include "config.h"
#ifdef __cplusplus
#define EXTERNC extern "C"
#else
#define EXTERNC
#endif
EXTERNC int apple_alac_init(int frame_size,int sample_size,int sample_rate);
EXTERNC int apple_alac_terminate();
EXTERNC int apple_alac_decode_frame(unsigned char *sampleBuffer, uint32_t bufferLength, unsigned char *dest, int *outsize);
#undef EXTERNC
#endif /* __APPLE_ALAC_H */
-1
View File
@@ -67,7 +67,6 @@
#endif
#endif
#include "common.h"
#include <libdaemon/dlog.h>
// true if Shairport Sync is supposed to be sending output to the output device, false otherwise
+9
View File
@@ -46,8 +46,15 @@ enum stuffing_type {
enum playback_mode_type {
ST_stereo = 0,
ST_mono,
ST_reverse_stereo,
ST_left_only,
ST_right_only,
} playback_mode_type;
enum decoders_supported_type {
decoder_hammerton = 0,
decoder_apple_alac,
} decoders_supported_type;
// the following enum must _exactly match the snd_pcm_format_t definition in the alsa pcm.h file.
@@ -112,6 +119,8 @@ typedef struct {
int cmd_blocking;
int 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
char *pidfile;
// char *logfile;
// char *errfile;
+18 -1
View File
@@ -2,7 +2,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.50])
AC_INIT([shairport-sync], [3.0PB1], [mikebrady@eircom.net])
AC_INIT([shairport-sync], [3.0PB2], [mikebrady@eircom.net])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([shairport.c])
AC_CONFIG_HEADERS([config.h])
@@ -20,6 +20,7 @@ with_os_type=`echo ${with_os_type} | tr '[[:upper:]]' '[[:lower:]]' `
# Checks for programs.
AC_PROG_CC
AC_PROG_CXX
AC_PROG_INSTALL
PKG_PROG_PKG_CONFIG([0.9.0])
@@ -93,6 +94,22 @@ AC_ARG_WITH([configfiles],
[ --with-configfiles = install configuration files during a make install ], ,[with_configfiles=yes])
AM_CONDITIONAL([INSTALL_CONFIG_FILES], [test "x$with_configfiles" = "xyes"])
# Look for Apple ALAC flag
AC_ARG_WITH(apple-alac, [ --with-apple-alac = include support for the Apple ALAC decoder],
[AC_MSG_RESULT(>>Including the Apple ALAC Decoder)
HAS_APPLE_ALAC=1
AM_CONDITIONAL([USE_APPLE_ALAC], [test 0])
AC_DEFINE([CONFIG_APPLE_ALAC], 1, [Needed by the compiler.])
if test "x${with_pkg_config}" = xyes ; then
PKG_CHECK_MODULES(
[ALAC], [alac],
[LIBS="${ALAC_LIBS} ${LIBS}"
AC_DEFINE([HAVE_APPLE_ALAC],[1],[Define to 1 if you are using the Apple ALAC Decoder])])
else
AC_CHECK_LIB([alac], [BitBufferInit], , AC_MSG_ERROR(Apple ALAC Decoder support requires the alac library!))
AC_DEFINE([HAVE_APPLE_ALAC],[1],[Define to 1 if you have the Apple ALAC library])
fi ])
AM_CONDITIONAL([USE_APPLE_ALAC], [test "x$HAS_APPLE_ALAC" = "x1"])
# Look for piddir flag
AC_ARG_WITH(piddir, [ --with-piddir=<pathname> Specify a pathname to a directory in which to write the PID file.], [
+62 -16
View File
@@ -67,6 +67,8 @@
#include "alac.h"
#include "apple_alac.h"
// parameters from the source
static unsigned char *aesiv;
#ifdef HAVE_LIBSSL
@@ -100,6 +102,7 @@ static alac_file *decoder_info;
static int late_packet_message_sent;
static uint64_t packet_count = 0;
static int32_t last_seqno_read;
static int decoder_in_use = 0;
// interthread variables
static int fix_volume = 0x10000;
@@ -240,7 +243,7 @@ static int alac_decode(short *dest, int *destlen, uint8_t *buf, int len) {
}
unsigned char packet[MAX_PACKET];
unsigned char packetp[MAX_PACKET];
// assert(len <= MAX_PACKET);
assert(len <= MAX_PACKET);
int reply = 0; //everything okay
int outsize=bytes_per_audio_frame*(*destlen); // the size the output should be, in bytes
int toutsize = outsize;
@@ -256,15 +259,49 @@ static int alac_decode(short *dest, int *destlen, uint8_t *buf, int len) {
AES_cbc_encrypt(buf, packet, aeslen, &aes, iv, AES_DECRYPT);
#endif
memcpy(packet + aeslen, buf + aeslen, len - aeslen);
alac_decode_frame(decoder_info, packet, dest, &outsize);
#ifdef HAVE_APPLE_ALAC
if (config.use_apple_decoder) {
if (decoder_in_use!=1<<decoder_apple_alac) {
debug(1,"Apple ALAC Decoder used on encrypted audio.");
decoder_in_use=1<<decoder_apple_alac;
}
apple_alac_decode_frame(packet, len, (unsigned char *) dest, &outsize);
outsize=outsize*4; // bring the size to bytes
} else
#endif
{
if (decoder_in_use!=1<<decoder_hammerton) {
debug(1,"Hammerton Decoder used on encrypted audio.");
decoder_in_use=1<<decoder_hammerton;
}
alac_decode_frame(decoder_info, packet, (unsigned char *) dest, &outsize);
}
} else {
alac_decode_frame(decoder_info, buf, dest, &outsize);
// not encrypted
#ifdef HAVE_APPLE_ALAC
if (config.use_apple_decoder) {
if (decoder_in_use!=1<<decoder_apple_alac) {
debug(1,"Apple ALAC Decoder used on unencrypted audio.");
decoder_in_use=1<<decoder_apple_alac;
}
apple_alac_decode_frame(buf, len, (unsigned char *) dest, &outsize);
outsize=outsize*4; // bring the size to bytes
} else
#endif
{
if (decoder_in_use!=1<<decoder_hammerton) {
debug(1,"Hammerton Decoder used on unencrypted audio.");
decoder_in_use=1<<decoder_hammerton;
}
alac_decode_frame(decoder_info, buf, dest, &outsize);
}
}
if(outsize>toutsize) {
debug(2,"Output from alac_decode larger (%d bytes, not frames) than expected (%d bytes) -- truncated, but buffer overflow possible! Encrypted = %d.",outsize, toutsize, encrypted);
reply = -1; // output packet is the wrong size
}
}
*destlen = outsize / bytes_per_audio_frame;
if ((outsize % bytes_per_audio_frame)!=0)
debug(1,"Number of audio frames (%d) does not correspond exactly to the number of bytes (%d) and the audio frame size (%d).",*destlen,outsize,bytes_per_audio_frame);
@@ -298,10 +335,20 @@ static int init_decoder(int32_t fmtp[12]) {
alac->setinfo_86 = fmtp[10];
alac->setinfo_8a_rate = fmtp[11];
alac_allocate_buffers(alac);
#ifdef HAVE_APPLE_ALAC
apple_alac_init(frame_size,sample_size,sampling_rate);
#endif
return 0;
}
static void free_decoder(void) { alac_free(decoder_info); }
static void terminate_decoders(void) {
alac_free(decoder_info);
#ifdef HAVE_APPLE_ALAC
apple_alac_terminate();
#endif
}
static void init_buffer(void) {
int i;
@@ -506,7 +553,6 @@ static abuf_t *buffer_get_frame(void) {
shutdown_requested = 1;
}
}
int rco = get_requested_connection_state_to_output();
if (connection_state_to_output != rco) {
@@ -530,7 +576,6 @@ static abuf_t *buffer_get_frame(void) {
flush_requested = 0;
}
pthread_mutex_unlock(&flush_mutex);
uint32_t flush_limit = 0;
if (ab_synced) {
do {
@@ -1000,7 +1045,7 @@ static void *player_thread_func(void *arg) {
session_corrections = 0;
play_segment_reference_frame = 0; // zero signals that we are not in a play segment
int output_sample_ratio = 1;
if (config.output_rate!=0)
output_sample_ratio = config.output_rate/44100;
@@ -1112,20 +1157,21 @@ static void *player_thread_func(void *arg) {
while (!please_stop) {
abuf_t *inframe = buffer_get_frame();
if (inframe) {
if (inframe->data) {
inbuf = inframe->data;
if (inbuf) {
play_number++;
// if it's a supplied silent frame, let us know...
if (inframe->timestamp == 0) {
// debug(1,"Player has a supplied silent frame.");
last_seqno_read =
(SUCCESSOR(last_seqno_read) & 0xffff); // manage the packet out of sequence minder
if (inframe->data==NULL)
debug(1,"NULL inframe->data to play -- skipping it.");
if (inbuf==NULL)
debug(1,"NULL inbuf to play -- skipping it.");
else {
if (inframe->length==0)
debug(1,"empty frame to play -- skipping it.");
debug(1,"empty frame to play -- skipping it (1).");
else
config.output->play(inframe->data, inframe->length);
config.output->play(inbuf, inframe->length);
}
} else {
// We have a frame of data. We need to see if we want to add or remove a frame from it to
@@ -1279,8 +1325,8 @@ static void *player_thread_func(void *arg) {
config.output->play(inframe->data, inframe->length);
}
} else {
#ifdef HAVE_LIBSOXR
switch (config.packet_stuffing) {
case ST_basic:
@@ -1766,7 +1812,7 @@ void player_stop(pthread_t *player_thread) {
#endif
command_stop();
free_buffer();
free_decoder();
terminate_decoders();
int rc = pthread_cond_destroy(&flowcontrol);
if (rc)
debug(1, "Error destroying condition variable.");
+1 -1
View File
@@ -1882,7 +1882,7 @@ void rtsp_listen_loop(void) {
freeaddrinfo(info);
if (!nsock)
die("Could not establish a service on port %d -- program terminating. Is another 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;
+1
View File
@@ -62,6 +62,7 @@ alsa =
// audio_backend_buffer_desired_length = 6615; // If set too small, buffer underflow occurs on low-powered machines. Too long and the response times with software mixer become annoying.
// disable_synchronization = "no"; // Set to "yes" to disable synchronization. Default is "no".
// period_size = <number>; // Use this optional advanced setting to set the alsa period size near to this value
// buffer_size = <number>; // Use this optional advanced setting to set the alsa buffer size near to this value
// use_mmap_if_available = "yes"; // Use this optional advanced setting to control whether MMAP-based output is used to communicate with the DAC. Default is "yes"
};
+19
View File
@@ -441,6 +441,19 @@ int parse_options(int argc, char **argv) {
config.volume_range_db = value;
}
/* Get the use_apple_decoder setting. */
if (config_lookup_string(config.cfg, "general.use_apple_decoder", &str)) {
if (strcasecmp(str, "no") == 0)
config.use_apple_decoder = 0;
else if (strcasecmp(str, "yes") == 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 comiled into this version of Shairport Sync. The default decoder will be used.");
} else
die("Invalid use_apple_decoder option choice \"%s\". It should be \"yes\" or \"no\"");
}
/* Get the default latency. Deprecated! */
if (config_lookup_int(config.cfg, "latencies.default", &value))
config.userSuppliedLatency = value;
@@ -760,6 +773,10 @@ int main(int argc, char **argv) {
config.audio_backend_buffer_desired_length = 6615; // 0.15 seconds.
config.udp_port_base = 6001;
config.udp_port_range = 100;
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
/* Check if we are called with -V or --version parameter */
if (argc >= 2 && ((strcmp(argv[1], "-V") == 0) || (strcmp(argv[1], "--version") == 0))) {
@@ -1023,6 +1040,8 @@ int main(int argc, char **argv) {
debug(1, "audio backend latency offset is %d.", 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, "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);
if (realConfigPath) {