diff options
author | miwi <miwi@FreeBSD.org> | 2013-02-18 12:45:09 +0800 |
---|---|---|
committer | miwi <miwi@FreeBSD.org> | 2013-02-18 12:45:09 +0800 |
commit | 8d4b81e53f9bc5ca82d9451f01f318ba5cefb0b9 (patch) | |
tree | 2c4de2aa7c62c37628d83ce19128ddb262111ed3 /audio | |
parent | 6b5245f54e1a3fbc47e8e4bda8fec7d13a8a3290 (diff) | |
download | freebsd-ports-gnome-8d4b81e53f9bc5ca82d9451f01f318ba5cefb0b9.tar.gz freebsd-ports-gnome-8d4b81e53f9bc5ca82d9451f01f318ba5cefb0b9.tar.zst freebsd-ports-gnome-8d4b81e53f9bc5ca82d9451f01f318ba5cefb0b9.zip |
libshairport
============
Created by Team XBMC
This is a fork of ShairPort written by James Laird <jhl@mafipulation.org>. The
XBMC team decided to fork ShairPort and make it into a library.
What it is
----------
This program emulates an AirPort Express for the purpose of streaming music from
iTunes and compatible iPods. It implements a server for the Apple RAOP protocol.
ShairPort does not support AirPlay v2 (video and photo streaming).
It supports multiple simultaneous streams, if your audio output chain (as
detected by libao) does so.
WWW: https://github.com/amejia1/libshairport
PR: ports/172775
Submitted by: Manuel Creach <manuel.creach@icloud.com>
Diffstat (limited to 'audio')
-rw-r--r-- | audio/Makefile | 1 | ||||
-rw-r--r-- | audio/libshairport/Makefile | 23 | ||||
-rw-r--r-- | audio/libshairport/distinfo | 2 | ||||
-rw-r--r-- | audio/libshairport/files/patch-configure.in | 20 | ||||
-rw-r--r-- | audio/libshairport/files/patch-src-Makefile.am | 12 | ||||
-rw-r--r-- | audio/libshairport/files/patch-src-alac.c | 47 | ||||
-rw-r--r-- | audio/libshairport/files/patch-src-ao.h | 161 | ||||
-rw-r--r-- | audio/libshairport/files/patch-src-hairtunes.c | 233 | ||||
-rw-r--r-- | audio/libshairport/files/patch-src-hairtunes.h | 11 | ||||
-rw-r--r-- | audio/libshairport/files/patch-src-shairport.c | 691 | ||||
-rw-r--r-- | audio/libshairport/files/patch-src-shairport.h | 51 | ||||
-rw-r--r-- | audio/libshairport/files/patch-src-socketlib.c | 58 | ||||
-rw-r--r-- | audio/libshairport/pkg-descr | 17 | ||||
-rw-r--r-- | audio/libshairport/pkg-plist | 7 |
14 files changed, 1334 insertions, 0 deletions
diff --git a/audio/Makefile b/audio/Makefile index 2de418a702ca..503e7c732876 100644 --- a/audio/Makefile +++ b/audio/Makefile @@ -396,6 +396,7 @@ SUBDIR += liboggz SUBDIR += libopenspc SUBDIR += libsamplerate + SUBDIR += libshairport SUBDIR += libshout SUBDIR += libshout2 SUBDIR += libsidplay diff --git a/audio/libshairport/Makefile b/audio/libshairport/Makefile new file mode 100644 index 000000000000..e5de3bd27caa --- /dev/null +++ b/audio/libshairport/Makefile @@ -0,0 +1,23 @@ +# Created by: Manuel Creach <manuel.creach@icloud.com> +# $FreeBSD$ + +PORTNAME= libshairport +PORTVERSION= 1.2.0.20310 +CATEGORIES= audio +MASTER_SITES= http://mirrors.xbmc.org/build-deps/darwin-libs/ +DISTNAME= libshairport-${PORTVERSION}_lib + +MAINTAINER= manuel.creach@icloud.com +COMMENT= An Airport Extreme Emulator + +FETCH_ARGS= -pRr +USE_GMAKE= yes +USE_AUTOTOOLS= aclocal autoheader automake autoconf libtoolize +ACLOCAL_ARGS= -I. +AUTOMAKE_ARGS= --add-missing +USE_LDCONFIG= yes + +CPPFLAGS+= -isystem${LOCALBASE}/include +LDFLAGS+= -L${LOCALBASE}/lib + +.include <bsd.port.mk> diff --git a/audio/libshairport/distinfo b/audio/libshairport/distinfo new file mode 100644 index 000000000000..29b87c7e93d7 --- /dev/null +++ b/audio/libshairport/distinfo @@ -0,0 +1,2 @@ +SHA256 (libshairport-1.2.0.20310_lib.tar.gz) = 61602402d846a50e8ddf82c3fb5b81984de95ed56abfe0f1e22426d1901c564f +SIZE (libshairport-1.2.0.20310_lib.tar.gz) = 32759 diff --git a/audio/libshairport/files/patch-configure.in b/audio/libshairport/files/patch-configure.in new file mode 100644 index 000000000000..1a51ff291521 --- /dev/null +++ b/audio/libshairport/files/patch-configure.in @@ -0,0 +1,20 @@ +--- configure.in.orig 2011-09-23 22:56:46.000000000 +0200 ++++ configure.in 2012-10-09 12:09:33.000000000 +0200 +@@ -11,8 +11,9 @@ + + # Checks for libraries. + #AC_CHECK_LIB([c], [main]) +-#AC_CHECK_LIB([m], [main]) ++AC_CHECK_LIB([m], [main]) + AC_CHECK_LIB([ssl], [main],, AC_MSG_ERROR($missing_library)) ++AC_CHECK_LIB([crypto], [main],, AC_MSG_ERROR($missing_library)) + AC_CHECK_LIB([pthread], [main],, AC_MSG_ERROR($missing_library)) + + OUTPUT_FILES="Makefile" +@@ -21,4 +22,4 @@ + + AC_CONFIG_FILES([${OUTPUT_FILES}]) + AC_OUTPUT(Makefile src/Makefile) +-AC_OUTPUT +\ No newline at end of file ++AC_OUTPUT diff --git a/audio/libshairport/files/patch-src-Makefile.am b/audio/libshairport/files/patch-src-Makefile.am new file mode 100644 index 000000000000..4f1d46973aee --- /dev/null +++ b/audio/libshairport/files/patch-src-Makefile.am @@ -0,0 +1,12 @@ +--- src/Makefile.am.orig 2011-09-23 23:14:39.000000000 +0200 ++++ src/Makefile.am 2012-10-09 12:09:33.000000000 +0200 +@@ -1,7 +1,7 @@ + lib_LTLIBRARIES=libshairport.la + +-library_includedir=$(includedir) +-library_include_HEADERS = shairport.h ++library_includedir=$(includedir)/shairport ++library_include_HEADERS = shairport.h ao.h socketlib.h + + libshairport_la_SOURCES=shairport.c hairtunes.c socketlib.c alac.c + libshairport_la_LDFLAGS=-dynamiclib diff --git a/audio/libshairport/files/patch-src-alac.c b/audio/libshairport/files/patch-src-alac.c new file mode 100644 index 000000000000..8face193c68f --- /dev/null +++ b/audio/libshairport/files/patch-src-alac.c @@ -0,0 +1,47 @@ +--- src/alac.c.orig 2011-08-21 00:06:21.000000000 +0200 ++++ src/alac.c 2012-10-09 12:09:33.000000000 +0200 +@@ -804,7 +804,7 @@ + } + else + { +- fprintf(stderr, "FIXME: unhandled predicition type: %i\n", prediction_type); ++ xprintf("FIXME: unhandled predicition type: %i\n", prediction_type); + /* i think the only other prediction type (or perhaps this is just a + * boolean?) runs adaptive fir twice.. like: + * predictor_decompress_fir_adapt(predictor_error, tempout, ...) +@@ -885,7 +885,7 @@ + } + case 20: + case 32: +- fprintf(stderr, "FIXME: unimplemented sample size %i\n", alac->setinfo_sample_size); ++ xprintf("FIXME: unimplemented sample size %i\n", alac->setinfo_sample_size); + break; + default: + break; +@@ -1004,7 +1004,7 @@ + } + else + { /* see mono case */ +- fprintf(stderr, "FIXME: unhandled predicition type: %i\n", prediction_type_a); ++ xprintf("FIXME: unhandled predicition type: %i\n", prediction_type_a); + } + + /* channel 2 */ +@@ -1029,7 +1029,7 @@ + } + else + { +- fprintf(stderr, "FIXME: unhandled predicition type: %i\n", prediction_type_b); ++ xprintf("FIXME: unhandled predicition type: %i\n", prediction_type_b); + } + } + else +@@ -1106,7 +1106,7 @@ + } + case 20: + case 32: +- fprintf(stderr, "FIXME: unimplemented sample size %i\n", alac->setinfo_sample_size); ++ xprintf("FIXME: unimplemented sample size %i\n", alac->setinfo_sample_size); + break; + default: + break; diff --git a/audio/libshairport/files/patch-src-ao.h b/audio/libshairport/files/patch-src-ao.h new file mode 100644 index 000000000000..2e1ee3f78bcd --- /dev/null +++ b/audio/libshairport/files/patch-src-ao.h @@ -0,0 +1,161 @@ +--- src/ao.h.orig 2012-10-09 12:33:01.000000000 +0200 ++++ src/ao.h 2012-10-09 12:09:33.000000000 +0200 +@@ -0,0 +1,158 @@ ++/* ++ * ++ * ao.h ++ * ++ * Original Copyright (C) Aaron Holtzman - May 1999 ++ * Modifications Copyright (C) Stan Seibert - July 2000, July 2001 ++ * More Modifications Copyright (C) Jack Moffitt - October 2000 ++ * ++ * This file is part of libao, a cross-platform audio outputlibrary. See ++ * README for a history of this source code. ++ * ++ * libao is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2, or (at your option) ++ * any later version. ++ * ++ * libao is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GNU Make; see the file COPYING. If not, write to ++ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#ifndef __AO_H__ ++#define __AO_H__ ++ ++#ifdef __cplusplus ++extern "C" ++{ ++#endif /* __cplusplus */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <stdint.h> ++#include <errno.h> ++ ++/* --- Constants ---*/ ++ ++#define AO_TYPE_LIVE 1 ++#define AO_TYPE_FILE 2 ++ ++ ++#define AO_ENODRIVER 1 ++#define AO_ENOTFILE 2 ++#define AO_ENOTLIVE 3 ++#define AO_EBADOPTION 4 ++#define AO_EOPENDEVICE 5 ++#define AO_EOPENFILE 6 ++#define AO_EFILEEXISTS 7 ++#define AO_EBADFORMAT 8 ++ ++#define AO_EFAIL 100 ++ ++ ++#define AO_FMT_LITTLE 1 ++#define AO_FMT_BIG 2 ++#define AO_FMT_NATIVE 4 ++ ++/* --- Structures --- */ ++ ++typedef struct ao_info { ++ int type; /* live output or file output? */ ++ char *name; /* full name of driver */ ++ char *short_name; /* short name of driver */ ++ char *author; /* driver author */ ++ char *comment; /* driver comment */ ++ int preferred_byte_format; ++ int priority; ++ char **options; ++ int option_count; ++} ao_info; ++ ++typedef struct ao_functions ao_functions; ++typedef struct ao_device ao_device; ++ ++typedef struct ao_sample_format { ++ int bits; /* bits per sample */ ++ int rate; /* samples per second (in a single channel) */ ++ int channels; /* number of audio channels */ ++ int byte_format; /* Byte ordering in sample, see constants below */ ++ char *matrix; /* input channel location/ordering */ ++} ao_sample_format; ++ ++typedef struct ao_option { ++ char *key; ++ char *value; ++ struct ao_option *next; ++} ao_option; ++ ++#if defined(AO_BUILDING_LIBAO) ++#include "ao_private.h" ++#endif ++ ++/* --- Functions --- */ ++ ++/* library setup/teardown */ ++void ao_initialize(void); ++void ao_shutdown(void); ++ ++/* device setup/playback/teardown */ ++int ao_append_global_option(const char *key, ++ const char *value); ++int ao_append_option(ao_option **options, ++ const char *key, ++ const char *value); ++void ao_free_options(ao_option *options); ++ ++char* ao_get_option(ao_option *options, const char* key); ++ ++ao_device* ao_open_live(int driver_id, ++ ao_sample_format *format, ++ ao_option *option); ++ao_device* ao_open_file(int driver_id, ++ const char *filename, ++ int overwrite, ++ ao_sample_format *format, ++ ao_option *option); ++ ++int ao_play(ao_device *device, ++ char *output_samples, ++ uint32_t num_bytes); ++int ao_close(ao_device *device); ++ ++/* driver information */ ++int ao_driver_id(const char *short_name); ++int ao_default_driver_id(void); ++ao_info *ao_driver_info(int driver_id); ++ao_info **ao_driver_info_list(int *driver_count); ++char *ao_file_extension(int driver_id); ++ ++/* miscellaneous */ ++int ao_is_big_endian(void); ++ ++ ++#ifdef __cplusplus ++} ++#endif /* __cplusplus */ ++ ++#endif /* __AO_H__ */ ++ ++extern struct AudioOutput g_ao; ++struct AudioOutput ++ { ++ void (*ao_initialize)(void); ++ int (*ao_play)(ao_device *, char *, uint32_t); ++ int (*ao_default_driver_id)(void); ++ ao_device* (*ao_open_live)( int, ao_sample_format *, ao_option *); ++ int (*ao_close)(ao_device *); ++ /* -- Device Setup/Playback/Teardown -- */ ++ int (*ao_append_option)(ao_option **, const char *, const char *); ++ void (*ao_free_options)(ao_option *); ++ char* (*ao_get_option)(ao_option *, const char* ); ++ void (*ao_set_metadata)(const char *buffer, unsigned int size); ++ void (*ao_set_metadata_coverart)(const char *buffer, unsigned int size); ++ }; diff --git a/audio/libshairport/files/patch-src-hairtunes.c b/audio/libshairport/files/patch-src-hairtunes.c new file mode 100644 index 000000000000..b00621d1ea45 --- /dev/null +++ b/audio/libshairport/files/patch-src-hairtunes.c @@ -0,0 +1,233 @@ +--- src/hairtunes.c.orig 2011-09-23 21:55:48.000000000 +0200 ++++ src/hairtunes.c 2012-10-09 12:09:33.000000000 +0200 +@@ -25,7 +25,7 @@ + */ + + #define XBMC +-//#defined HAS_AO ++#define HAS_AO + + #include <stdio.h> + #include <stdlib.h> +@@ -45,7 +45,7 @@ + #include <sys/signal.h> + #include <fcntl.h> + #ifdef HAS_AO +-#include <ao/ao.h> ++#include "ao.h" + #endif + + #ifdef FANCY_RESAMPLING +@@ -89,7 +89,6 @@ + // maximal resampling shift - conservative + #define OUTFRAME_BYTES (4*(frame_size+3)) + +- + alac_file *decoder_info; + + #ifdef FANCY_RESAMPLING +@@ -122,8 +121,8 @@ + pthread_cond_t ab_buffer_ready; + + static void die(char *why) { +- fprintf(stderr, "FATAL: %s\n", why); +- exit(1); ++ xprintf("FATAL: %s\n", why); ++ //exit(1); + } + + static int hex2bin(unsigned char *buf, char *hex) { +@@ -246,13 +245,13 @@ + continue; + } + if (!strcmp(line, "exit\n")) { +- exit(0); ++ ;//exit(0); + } + if (!strcmp(line, "flush\n")) { + hairtunes_flush(); + } + } +- fprintf(stderr, "bye!\n"); ++ xprintf("bye!\n"); + fflush(stderr); + #endif + +@@ -263,18 +262,28 @@ + { + assert(f<=0); + if (debug) +- fprintf(stderr, "VOL: %lf\n", f); ++ xprintf("VOL: %lf\n", f); + volume = pow(10.0,0.05*f); + fix_volume = 65536.0 * volume; + } + ++void hairtunes_set_metadata(const char *buffer, unsigned int size) ++{ ++ g_ao.ao_set_metadata(buffer, size); ++} ++ ++void hairtunes_set_metadata_coverart(const char *buffer, unsigned int size) ++{ ++ g_ao.ao_set_metadata_coverart(buffer, size); ++} ++ + void hairtunes_flush(void) + { + pthread_mutex_lock(&ab_mutex); + ab_resync(); + pthread_mutex_unlock(&ab_mutex); + if (debug) +- fprintf(stderr, "FLUSH\n"); ++ xprintf("FLUSH\n"); + } + + #ifdef HAIRTUNES_STANDALONE +@@ -424,7 +433,7 @@ + } else if (seq_order(ab_read, seqno)) { // late but not yet played + abuf = audio_buffer + BUFIDX(seqno); + } else { // too late. +- fprintf(stderr, "\nlate packet %04X (%04X:%04X)\n", seqno, ab_read, ab_write); ++ xprintf("\nlate packet %04X (%04X:%04X)\n", seqno, ab_read, ab_write); + } + buf_fill = ab_write - ab_read; + pthread_mutex_unlock(&ab_mutex); +@@ -521,7 +530,7 @@ + if (seq_order(last, first)) + return; + +- fprintf(stderr, "requesting resend on %d packets (port %d)\n", last-first+1, controlport); ++ xprintf("requesting resend on %d packets (port %d)\n", last-first+1, controlport); + + char req[8]; // *not* a standard RTCP NACK + req[0] = 0x80; +@@ -605,8 +614,8 @@ + port += 3; + } + +- printf("port: %d\n", port); // let our handler know where we end up listening +- printf("cport: %d\n", port+1); ++ xprintf("port: %d\n", port); // let our handler know where we end up listening ++ xprintf("cport: %d\n", port+1); + + rtp_sockets[0] = sock; + rtp_sockets[1] = csock; +@@ -709,7 +718,7 @@ + bf_est_drift = biquad_filt(&bf_drift_lpf, CONTROL_B*(bf_est_err*CONTROL_A + err_deriv) + bf_est_drift); + + if (debug) +- fprintf(stderr, "bf %d err %f drift %f desiring %f ed %f estd %f\r", fill, bf_est_err, bf_est_drift, desired_fill, err_deriv, err_deriv + CONTROL_A*bf_est_err); ++ xprintf("bf %d err %f drift %f desiring %f ed %f estd %f\r", fill, bf_est_err, bf_est_drift, desired_fill, err_deriv, err_deriv + CONTROL_A*bf_est_err); + bf_playback_rate = 1.0 + CONTROL_A*bf_est_err + bf_est_drift; + + bf_last_err = bf_est_err; +@@ -725,7 +734,7 @@ + buf_fill = ab_write - ab_read; + if (buf_fill < 1 || !ab_synced || ab_buffering) { // init or underrun. stop and wait + if (ab_synced) +- fprintf(stderr, "\nunderrun\n"); ++ xprintf("\nunderrun\n"); + + ab_buffering = 1; + pthread_cond_wait(&ab_buffer_ready, &ab_mutex); +@@ -737,7 +746,7 @@ + return 0; + } + if (buf_fill >= BUFFER_FRAMES) { // overrunning! uh-oh. restart at a sane distance +- fprintf(stderr, "\noverrun.\n"); ++ xprintf("\noverrun.\n"); + ab_read = ab_write - START_FILL; + } + read = ab_read; +@@ -749,7 +758,7 @@ + + volatile abuf_t *curframe = audio_buffer + BUFIDX(read); + if (!curframe->ready) { +- fprintf(stderr, "\nmissing frame.\n"); ++ xprintf("\nmissing frame.\n"); + memset(curframe->data, 0, FRAME_BYTES); + } + curframe->ready = 0; +@@ -776,13 +785,13 @@ + if (stuff) { + if (stuff==1) { + if (debug) +- fprintf(stderr, "+++++++++\n"); ++ xprintf("+++++++++\n"); + // interpolate one sample + *outptr++ = dithered_vol(((long)inptr[-2] + (long)inptr[0]) >> 1); + *outptr++ = dithered_vol(((long)inptr[-1] + (long)inptr[1]) >> 1); + } else if (stuff==-1) { + if (debug) +- fprintf(stderr, "---------\n"); ++ xprintf("---------\n"); + inptr++; + inptr++; + } +@@ -849,6 +858,11 @@ + inbuf = buffer_get_frame(); + } while (!inbuf && audio_running); + ++ if(!audio_running) ++ { ++ return 0; //don't access inbuf if audio stopped ++ } ++ + #ifdef FANCY_RESAMPLING + if (fancy_resampling) { + int i; +@@ -881,7 +895,7 @@ + } + #ifdef HAS_AO + } else { +- ao_play(dev, (char *)outbuf, play_samples*4); ++ g_ao.ao_play(dev, (char *)outbuf, play_samples*4); + #endif + } + } +@@ -906,7 +920,7 @@ + ao_device *dev; + + void* init_ao() { +- ao_initialize(); ++ g_ao.ao_initialize(); + + int driver; + #ifndef XBMC +@@ -921,7 +935,7 @@ + #endif + { + // otherwise choose the default +- driver = ao_default_driver_id(); ++ driver = g_ao.ao_default_driver_id(); + } + + ao_sample_format fmt; +@@ -944,9 +958,9 @@ + } + #endif + +- ao_append_option(&ao_opts, "name", "Streaming..."); ++ g_ao.ao_append_option(&ao_opts, "name", "Streaming..."); + +- dev = ao_open_live(driver, &fmt, ao_opts); ++ dev = g_ao.ao_open_live(driver, &fmt, ao_opts); + if (dev == NULL) { + die("Could not open ao device"); + } +@@ -985,12 +999,13 @@ + audio_running = 0; + pthread_join(audio_thread, NULL); + #ifdef HAS_AO +- ao_close(dev); ++ g_ao.ao_close(dev); + #endif + } + + void hairtunes_cleanup(void) + { ++ pthread_cond_signal(&ab_buffer_ready); + clean_output(); + clean_rtp(); + clean_buffer(); diff --git a/audio/libshairport/files/patch-src-hairtunes.h b/audio/libshairport/files/patch-src-hairtunes.h new file mode 100644 index 000000000000..0dfba09d6ff6 --- /dev/null +++ b/audio/libshairport/files/patch-src-hairtunes.h @@ -0,0 +1,11 @@ +--- src/hairtunes.h.orig 2011-08-21 00:06:21.000000000 +0200 ++++ src/hairtunes.h 2012-10-09 12:09:33.000000000 +0200 +@@ -4,6 +4,8 @@ + int hairtunes_init(char *pAeskey, char *pAesiv, char *pFmtpstr, int pCtrlPort, int pTimingPort, + int pDataPort, char *pRtpHost, char*pPipeName, char *pLibaoDriver, char *pLibaoDeviceName, char *pLibaoDeviceId); + void hairtunes_setvolume(float vol); ++void hairtunes_set_metadata(const char *buffer, unsigned int size); ++void hairtunes_set_metadata_coverart(const char *buffer, unsigned int size); + void hairtunes_flush(void); + void hairtunes_cleanup(void); + diff --git a/audio/libshairport/files/patch-src-shairport.c b/audio/libshairport/files/patch-src-shairport.c new file mode 100644 index 000000000000..00fd93c92d1c --- /dev/null +++ b/audio/libshairport/files/patch-src-shairport.c @@ -0,0 +1,691 @@ +--- src/shairport.c.orig 2011-08-21 01:57:56.000000000 +0200 ++++ src/shairport.c 2012-10-09 12:09:33.000000000 +0200 +@@ -31,6 +31,27 @@ + #include "shairport.h" + #include "hairtunes.h" + ++static struct printfPtr g_printf={NULL}; ++ ++int xprintf(const char *format, ...) ++{ ++ char dbg[2048]; ++ va_list args; ++ va_start(args, format); ++ vsnprintf(dbg, sizeof(dbg), format, args); ++ va_end(args); ++ if(g_printf.extprintf) ++ { ++ g_printf.extprintf(dbg, sizeof(dbg)); ++ } ++ else ++ { ++ printf(dbg); ++ } ++ ++ return 1; ++} ++ + #ifndef TRUE + #define TRUE (-1) + #endif +@@ -92,13 +113,26 @@ + static char tPassword[56] = ""; + static char tHWID[HWID_SIZE] = {0,51,52,53,54,55}; + ++#ifdef XBMC ++struct AudioOutput g_ao; ++void shairport_set_ao(struct AudioOutput *ao) ++{ ++ g_ao=*ao; ++} ++ ++void shairport_set_printf(struct printfPtr *funcPtr) ++{ ++ g_printf = *funcPtr; ++} ++#endif ++ + #ifndef XBMC + int main(int argc, char **argv) + #else + int shairport_main(int argc, char **argv) + #endif + { +- printf("initializing shairport\n"); ++ xprintf("initializing shairport\n",NULL); + char tHWID_Hex[HWID_SIZE * 2 + 1]; + char tKnownHwid[32]; + +@@ -177,22 +211,22 @@ + } + else if(!strcmp(arg, "-h") || !strcmp(arg, "--help")) + { +- slog(LOG_INFO, "ShairPort version 0.05 C port - Airport Express emulator\n"); +- slog(LOG_INFO, "Usage:\nshairport [OPTION...]\n\nOptions:\n"); +- slog(LOG_INFO, " -a, --apname=AirPort Sets Airport name\n"); +- slog(LOG_INFO, " -p, --password=secret Sets Password (not working)\n"); +- slog(LOG_INFO, " -o, --server_port=5000 Sets Port for Avahi/dns-sd\n"); +- slog(LOG_INFO, " -b, --buffer=282 Sets Number of frames to buffer before beginning playback\n"); +- slog(LOG_INFO, " -d Daemon mode\n"); +- slog(LOG_INFO, " -q, --quiet Supresses all output.\n"); +- slog(LOG_INFO, " -v,-v2,-v3,-vv Various debugging levels\n"); +- slog(LOG_INFO, "\n"); ++ xprintf("ShairPort version 0.05 C port - Airport Express emulator\n"); ++ xprintf("Usage:\nshairport [OPTION...]\n\nOptions:\n"); ++ xprintf(" -a, --apname=AirPort Sets Airport name\n"); ++ xprintf(" -p, --password=secret Sets Password (not working)\n"); ++ xprintf(" -o, --server_port=5000 Sets Port for Avahi/dns-sd\n"); ++ xprintf(" -b, --buffer=282 Sets Number of frames to buffer before beginning playback\n"); ++ xprintf(" -d Daemon mode\n"); ++ xprintf(" -q, --quiet Supresses all output.\n"); ++ xprintf(" -v,-v2,-v3,-vv Various debugging levels\n"); ++ xprintf("\n"); + return 0; + } + } + + if ( buffer_start_fill < 30 || buffer_start_fill > BUFFER_FRAMES ) { +- fprintf(stderr, "buffer value must be > 30 and < %d\n", BUFFER_FRAMES); ++ xprintf("buffer value must be > 30 and < %d\n", BUFFER_FRAMES); + return(0); + } + +@@ -201,11 +235,11 @@ + int tPid = fork(); + if(tPid < 0) + { +- exit(1); // Error on fork ++ //exit(1); // Error on fork + } + else if(tPid > 0) + { +- exit(0); ++ //exit(0); + } + else + { +@@ -246,10 +280,10 @@ + sscanf(tHWID_Hex, "%02X%02X%02X%02X%02X%02X", &tHWID[0], &tHWID[1], &tHWID[2], &tHWID[3], &tHWID[4], &tHWID[5]); + } + +- slog(LOG_INFO, "LogLevel: %d\n", kCurrentLogLevel); +- slog(LOG_INFO, "AirName: %s\n", tServerName); +- slog(LOG_INFO, "HWID: %.*s\n", HWID_SIZE, tHWID+1); +- slog(LOG_INFO, "HWID_Hex(%d): %s\n", strlen(tHWID_Hex), tHWID_Hex); ++ xprintf("LogLevel: %d\n", kCurrentLogLevel); ++ xprintf("AirName: %s\n", tServerName); ++ xprintf("HWID: %.*s\n", HWID_SIZE, tHWID+1); ++ xprintf("HWID_Hex(%d): %s\n", strlen(tHWID_Hex), tHWID_Hex); + + if(tSimLevel >= 1) + { +@@ -263,12 +297,12 @@ + #ifndef XBMC + startAvahi(tHWID_Hex, tServerName, tPort); + #endif +- slog(LOG_DEBUG_V, "Starting connection server: specified server port: %d\n", tPort); ++ xprintf("Starting connection server: specified server port: %d\n", tPort); + tServerSock = setupListenServer(&tAddrInfo, tPort); + if(tServerSock < 0) + { + freeaddrinfo(tAddrInfo); +- slog(LOG_INFO, "Error setting up server socket on port %d, try specifying a different port\n", tPort); ++ xprintf("Error setting up server socket on port %d, try specifying a different port\n", tPort); + return 0; + } + +@@ -295,7 +329,7 @@ + + int readsock; + +- slog(LOG_DEBUG_V, "Waiting for clients to connect\n"); ++ xprintf("Waiting for clients to connect\n"); + + while(m_running) + { +@@ -327,7 +361,7 @@ + { + freeaddrinfo(tAddrInfo); + tAddrInfo = NULL; +- slog(LOG_DEBUG, "...Accepted Client Connection..\n"); ++ xprintf("...Accepted Client Connection..\n"); + close(tServerSock); + handleClient(tClientSock, tPassword, tHWID); + //close(tClientSock); +@@ -335,11 +369,11 @@ + } + else + { +- slog(LOG_DEBUG_VV, "Child now busy handling new client\n"); ++ xprintf("Child now busy handling new client\n"); + close(tClientSock); + } + #else +- slog(LOG_DEBUG, "...Accepted Client Connection..\n"); ++ xprintf("...Accepted Client Connection..\n"); + handleClient(tClientSock, tPassword, tHWID); + #endif + } +@@ -349,7 +383,7 @@ + } + } + +- slog(LOG_DEBUG_VV, "Finished\n"); ++ xprintf("Finished\n"); + if(tAddrInfo != NULL) + { + freeaddrinfo(tAddrInfo); +@@ -360,6 +394,7 @@ + void shairport_exit(void) + { + m_running = 0; ++ close(tServerSock); + } + + int shairport_is_running(void) +@@ -407,7 +442,7 @@ + + void handleClient(int pSock, char *pPassword, char *pHWADDR) + { +- slog(LOG_DEBUG_VV, "In Handle Client\n"); ++ xprintf("In Handle Client\n"); + fflush(stdout); + + socklen_t len; +@@ -426,7 +461,7 @@ + + // deal with both IPv4 and IPv6: + if (addr.ss_family == AF_INET) { +- slog(LOG_DEBUG_V, "Constructing ipv4 address\n"); ++ xprintf("Constructing ipv4 address\n"); + struct sockaddr_in *s = (struct sockaddr_in *)&addr; + port = ntohs(s->sin_port); + inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr); +@@ -446,20 +481,20 @@ + if(memcmp(&addr.bin[0], "\x00\x00\x00\x00" "\x00\x00\x00\x00" "\x00\x00\xff\xff", 12) == 0) + { + // its ipv4... +- slog(LOG_DEBUG_V, "Constructing ipv4 from ipv6 address\n"); ++ xprintf("Constructing ipv4 from ipv6 address\n"); + memcpy(ipbin, &addr.bin[12], 4); + ipbinlen = 4; + } + else + { +- slog(LOG_DEBUG_V, "Constructing ipv6 address\n"); ++ xprintf("Constructing ipv6 address\n"); + memcpy(ipbin, &s->sin6_addr, 16); + ipbinlen = 16; + } + } + +- slog(LOG_DEBUG_V, "Peer IP address: %s\n", ipstr); +- slog(LOG_DEBUG_V, "Peer port : %d\n", port); ++ xprintf("Peer IP address: %s\n", ipstr); ++ xprintf("Peer port : %d\n", port); + + int tMoreDataNeeded = 1; + struct keyring tKeys; +@@ -478,18 +513,19 @@ + while(1 == tMoreDataNeeded) + { + tError = readDataFromClient(pSock, &(tConn.recv)); +- if(!tError && strlen(tConn.recv.data) > 0) ++ //if(!tError && strlen(tConn.recv.data) > 0) ++ if(!tError && tConn.recv.current > 0) + { +- slog(LOG_DEBUG_VV, "Finished Reading some data from client\n"); ++ xprintf("Finished Reading some data from client\n"); + // parse client request + tMoreDataNeeded = parseMessage(&tConn, ipbin, ipbinlen, pHWADDR); + if(1 == tMoreDataNeeded) + { +- slog(LOG_DEBUG_VV, "\n\nNeed to read more data\n"); ++ xprintf("\n\nNeed to read more data\n"); + } + else if(-1 == tMoreDataNeeded) // Forked process down below ended. + { +- slog(LOG_DEBUG_V, "Forked Process ended...cleaning up\n"); ++ xprintf("Forked Process ended...cleaning up\n"); + cleanup(&tConn); + // pSock was already closed + return; +@@ -498,13 +534,13 @@ + } + else + { +- slog(LOG_DEBUG, "Error reading from socket, closing client\n"); ++ xprintf("Error reading from socket, closing client\n"); + // Error reading data....quit. + cleanup(&tConn); + return; + } + } +- slog(LOG_DEBUG_VV, "Writing: %d chars to socket\n", tConn.resp.current); ++ xprintf("Writing: %d chars to socket\n", tConn.resp.current); + //tConn->resp.data[tConn->resp.current-1] = '\0'; + writeDataToClient(pSock, &(tConn.resp)); + // Finished reading one message... +@@ -517,9 +553,9 @@ + + void writeDataToClient(int pSock, struct shairbuffer *pResponse) + { +- slog(LOG_DEBUG_VV, "\n----Beg Send Response Header----\n%.*s\n", pResponse->current, pResponse->data); ++ xprintf("\n----Beg Send Response Header----\n%.*s\n", pResponse->current, pResponse->data); + send(pSock, pResponse->data, pResponse->current,0); +- slog(LOG_DEBUG_VV, "----Send Response Header----\n"); ++ xprintf("----Send Response Header----\n"); + } + + int readDataFromClient(int pSock, struct shairbuffer *pClientBuffer) +@@ -532,7 +568,7 @@ + while(tRetval > 0 && tEnd < 0) + { + // Read from socket until \n\n, \r\n\r\n, or \r\r is found +- slog(LOG_DEBUG_V, "Waiting To Read...\n"); ++ xprintf("Waiting To Read...\n"); + fflush(stdout); + tRetval = read(pSock, tReadBuf, MAX_SIZE); + // if new buffer contains the end of request string, only copy partial buffer? +@@ -543,40 +579,40 @@ + { + pClientBuffer->marker = tEnd+1; // Marks start of content + } +- slog(SOCKET_LOG_LEVEL, "Found end of http request at: %d\n", tEnd); ++ xprintf("Found end of http request at: %d\n", tEnd); + fflush(stdout); + } + else + { + tEnd = MAX_SIZE; +- slog(SOCKET_LOG_LEVEL, "Read %d of data so far\n%s\n", tRetval, tReadBuf); ++ xprintf("Read %d of data so far\n%s\n", tRetval, tReadBuf); + fflush(stdout); + } + if(tRetval > 0) + { + // Copy read data into tReceive; +- slog(SOCKET_LOG_LEVEL, "Read %d data, using %d of it\n", tRetval, tEnd); ++ xprintf("Read %d data, using %d of it\n", tRetval, tEnd); + addNToShairBuffer(pClientBuffer, tReadBuf, tRetval); +- slog(LOG_DEBUG_VV, "Finished copying data\n"); ++ xprintf("Finished copying data\n"); + } + else + { +- slog(LOG_DEBUG, "Error reading data from socket, got: %d bytes", tRetval); ++ xprintf("Error reading data from socket, got: %d bytes", tRetval); + return tRetval; + } + } + if(tEnd + 1 != tRetval) + { +- slog(SOCKET_LOG_LEVEL, "Read more data after end of http request. %d instead of %d\n", tRetval, tEnd+1); ++ xprintf("Read more data after end of http request. %d instead of %d\n", tRetval, tEnd+1); + } +- slog(SOCKET_LOG_LEVEL, "Finished Reading Data:\n%s\nEndOfData\n", pClientBuffer->data); ++ xprintf("Finished Reading Data:\n%s\nEndOfData\n", pClientBuffer->data); + fflush(stdout); + return 0; + } + + char *getFromBuffer(char *pBufferPtr, const char *pField, int pLenAfterField, int *pReturnSize, char *pDelims) + { +- slog(LOG_DEBUG_V, "GettingFromBuffer: %s\n", pField); ++ xprintf("GettingFromBuffer: %s\n", pField); + char* tFound = strstr(pBufferPtr, pField); + int tSize = 0; + if(tFound != NULL) +@@ -597,7 +633,7 @@ + } + + tSize = (int) (tShortest - tFound); +- slog(LOG_DEBUG_VV, "Found %.*s length: %d\n", tSize, tFound, tSize); ++ xprintf("Found %s length: %d\n",tFound, tSize); + if(pReturnSize != NULL) + { + *pReturnSize = tSize; +@@ -605,7 +641,7 @@ + } + else + { +- slog(LOG_DEBUG_V, "Not Found\n"); ++ xprintf("Not Found\n"); + } + return tFound; + } +@@ -639,10 +675,10 @@ + { + char tTrim[tFoundSize + 2]; + getTrimmed(tFound, tFoundSize, TRUE, TRUE, tTrim); +- slog(LOG_DEBUG_VV, "HeaderChallenge: [%s] len: %d sizeFound: %d\n", tTrim, strlen(tTrim), tFoundSize); ++ xprintf("HeaderChallenge: [%s] len: %d sizeFound: %d\n", tTrim, strlen(tTrim), tFoundSize); + int tChallengeDecodeSize = 16; + char *tChallenge = decode_base64((unsigned char *)tTrim, tFoundSize, &tChallengeDecodeSize); +- slog(LOG_DEBUG_VV, "Challenge Decode size: %d expected 16\n", tChallengeDecodeSize); ++ xprintf("Challenge Decode size: %d expected 16\n", tChallengeDecodeSize); + + int tCurSize = 0; + unsigned char tChalResp[38]; +@@ -664,7 +700,7 @@ + } + + char *tTmp = encode_base64((unsigned char *)tChalResp, tCurSize); +- slog(LOG_DEBUG_VV, "Full sig: %s\n", tTmp); ++ xprintf("Full sig: %s\n", tTmp); + free(tTmp); + + // RSA Encrypt +@@ -709,15 +745,15 @@ + if(tContent != NULL) + { + int tContentSize = atoi(tContent); +- if(pConn->recv.marker == 0 || strlen(pConn->recv.data+pConn->recv.marker) != tContentSize) ++ if(pConn->recv.marker == 0 || pConn->recv.current-pConn->recv.marker != tContentSize) + { + if(isLogEnabledFor(HEADER_LOG_LEVEL)) + { +- slog(HEADER_LOG_LEVEL, "Content-Length: %s value -> %d\n", tContent, tContentSize); ++ xprintf("Content-Length: %s value -> %d\n", tContent, tContentSize); + if(pConn->recv.marker != 0) + { +- slog(HEADER_LOG_LEVEL, "ContentPtr has %d, but needs %d\n", +- strlen(pConn->recv.data+pConn->recv.marker), tContentSize); ++ xprintf("ContentPtr has %d, but needs %d\n", ++ (pConn->recv.current-pConn->recv.marker), tContentSize); + } + } + // check if value in tContent > 2nd read from client. +@@ -726,7 +762,7 @@ + } + else + { +- slog(LOG_DEBUG_VV, "No content, header only\n"); ++ xprintf("No content, header only\n"); + } + + // "Creates" a new Response Header for our response message +@@ -739,7 +775,7 @@ + { + tLen = 20; + } +- slog(LOG_INFO, "********** RECV %.*s **********\n", tLen, pConn->recv.data); ++ xprintf("********** RECV %.*s **********\n", tLen, pConn->recv.data); + } + + if(pConn->password != NULL) +@@ -749,7 +785,7 @@ + + if(buildAppleResponse(pConn, pIpBin, pIpBinLen, pHWID)) // need to free sig + { +- slog(LOG_DEBUG_V, "Added AppleResponse to Apple-Challenge request\n"); ++ xprintf("Added AppleResponse to Apple-Challenge request\n"); + } + + // Find option, then based on option, do different actions. +@@ -769,14 +805,14 @@ + int tKeySize = 0; + char tEncodedAesIV[tSize + 2]; + getTrimmed(tHeaderVal, tSize, TRUE, TRUE, tEncodedAesIV); +- slog(LOG_DEBUG_VV, "AESIV: [%.*s] Size: %d Strlen: %d\n", tSize, tEncodedAesIV, tSize, strlen(tEncodedAesIV)); ++ xprintf("AESIV: [%.*s] Size: %d Strlen: %d\n", tSize, tEncodedAesIV, tSize, strlen(tEncodedAesIV)); + char *tDecodedIV = decode_base64((unsigned char*) tEncodedAesIV, tSize, &tSize); + + // grab the key, copy it out of the receive buffer + tHeaderVal = getFromContent(tContent, "a=rsaaeskey", &tKeySize); + char tEncodedAesKey[tKeySize + 2]; // +1 for nl, +1 for \0 + getTrimmed(tHeaderVal, tKeySize, TRUE, TRUE, tEncodedAesKey); +- slog(LOG_DEBUG_VV, "AES KEY: [%s] Size: %d Strlen: %d\n", tEncodedAesKey, tKeySize, strlen(tEncodedAesKey)); ++ xprintf("AES KEY: [%s] Size: %d Strlen: %d\n", tEncodedAesKey, tKeySize, strlen(tEncodedAesKey)); + // remove base64 coding from key + char *tDecodedAesKey = decode_base64((unsigned char*) tEncodedAesKey, + tKeySize, &tKeySize); // Need to free DecodedAesKey +@@ -785,7 +821,7 @@ + int tFmtpSize = 0; + char *tFmtp = getFromContent(tContent, "a=fmtp", &tFmtpSize); // Don't need to free + tFmtp = getTrimmedMalloc(tFmtp, tFmtpSize, TRUE, FALSE); // will need to free +- slog(LOG_DEBUG_VV, "Format: %s\n", tFmtp); ++ xprintf("Format: %s\n", tFmtp); + + RSA *rsa = loadKey(); + // Decrypt the binary aes key +@@ -794,11 +830,11 @@ + if(RSA_private_decrypt(tKeySize, (unsigned char *)tDecodedAesKey, + (unsigned char*) tDecryptedKey, rsa, RSA_PKCS1_OAEP_PADDING) >= 0) + { +- slog(LOG_DEBUG, "Decrypted AES key from RSA Successfully\n"); ++ xprintf("Decrypted AES key from RSA Successfully\n"); + } + else + { +- slog(LOG_INFO, "Error Decrypting AES key from RSA\n"); ++ xprintf("Error Decrypting AES key from RSA\n"); + } + free(tDecodedAesKey); + RSA_free(rsa); +@@ -814,13 +850,13 @@ + // struct comms *tComms = pConn->hairtunes; + // if (! (pipe(tComms->in) == 0 && pipe(tComms->out) == 0)) + // { +-// slog(LOG_INFO, "Error setting up hairtunes communications...some things probably wont work very well.\n"); ++// xprintf("Error setting up hairtunes communications...some things probably wont work very well.\n"); + // } + + // Setup fork + char tPort[8] = "6000"; // get this from dup()'d stdout of child pid + +- printf("******** SETUP!!!!!\n"); ++ xprintf("******** SETUP!!!!!\n",NULL); + #ifndef XBMC + int tPid = fork(); + if(tPid == 0) +@@ -836,11 +872,11 @@ + tFound = getFromSetup(pConn->recv.data, "timing_port", &tSize); + getTrimmed(tFound, tSize, 1, 0, tTPortStr); + +- slog(LOG_DEBUG_VV, "converting %s and %s from str->int\n", tCPortStr, tTPortStr); ++ xprintf("converting %s and %s from str->int\n", tCPortStr, tTPortStr); + int tControlport = atoi(tCPortStr); + int tTimingport = atoi(tTPortStr); + +- slog(LOG_DEBUG_V, "Got %d for CPort and %d for TPort\n", tControlport, tTimingport); ++ xprintf("Got %d for CPort and %d for TPort\n", tControlport, tTimingport); + char *tRtp = NULL; + char *tPipe = NULL; + char *tAoDriver = NULL; +@@ -875,7 +911,7 @@ + tDataport, tRtp, tPipe, tAoDriver, tAoDeviceName, tAoDeviceId); + #ifndef XBMC + // Quit when finished. +- slog(LOG_DEBUG, "Returned from hairtunes init....returning -1, should close out this whole side of the fork\n"); ++ xprintf("Returned from hairtunes init....returning -1, should close out this whole side of the fork\n"); + return -1; + } + else if(tPid >0) +@@ -888,7 +924,7 @@ + int tRead = read(tComms->out[0], tFromHairtunes, 80); + if(tRead <= 0) + { +- slog(LOG_INFO, "Error reading port from hairtunes function, assuming default port: %d\n", tPort); ++ xprintf("Error reading port from hairtunes function, assuming default port: %d\n", tPort); + } + else + { +@@ -900,7 +936,7 @@ + } + else + { +- slog(LOG_INFO, "Read %d bytes, Error translating %s into a port\n", tRead, tFromHairtunes); ++ xprintf("Read %d bytes, Error translating %s into a port\n", tRead, tFromHairtunes); + } + } + +@@ -921,7 +957,7 @@ + } + else + { +- slog(LOG_INFO, "Error forking process....dere' be errors round here.\n"); ++ xprintf("Error forking process....dere' be errors round here.\n"); + return -1; + } + #endif +@@ -933,7 +969,7 @@ + propogateCSeq(pConn); + #ifndef XBMC + close(pConn->hairtunes->in[1]); +- slog(LOG_DEBUG, "Tearing down connection, closing pipes\n"); ++ xprintf("Tearing down connection, closing pipes\n"); + #else + hairtunes_cleanup(); + #endif +@@ -954,21 +990,73 @@ + { + propogateCSeq(pConn); + int tSize = 0; ++ char *buffer = NULL; ++ char *contentType = getFromHeader(pConn->recv.data, "Content-Type", &tSize); ++ char *tContent = getFromHeader(pConn->recv.data, "Content-Length", NULL); ++ int iContentSize = 0; ++ int isJpg = 0; ++ ++ if(tContent != NULL) ++ { ++ iContentSize = atoi(tContent); ++ } ++ ++ if( tSize > 1 && ++ (strncmp(contentType, "application/x-dmap-tagged", tSize) == 0) || ++ (strncmp(contentType, "image/jpeg", tSize) == 0) ) ++ { ++ if( (pConn->recv.current - pConn->recv.marker) == iContentSize && pConn->recv.marker != 0) ++ { ++ if(strncmp(contentType, "image/jpeg", tSize) == 0) ++ { ++ isJpg = 1; ++ } ++ buffer = (char *)malloc(iContentSize * sizeof(char)); ++ memcpy(buffer, pConn->recv.data + pConn->recv.marker, iContentSize); ++ } ++ else ++ { ++ iContentSize = 0; ++ } ++ } ++ else ++ { ++ iContentSize = 0; ++ } + char *tVol = getFromHeader(pConn->recv.data, "volume", &tSize); +- slog(LOG_DEBUG_VV, "About to write [vol: %.*s] data to hairtunes\n", tSize, tVol); ++ if( tVol) ++ { ++ xprintf("About to write [vol: %.*s] data to hairtunes\n", tSize, tVol); ++ } + // TBD VOLUME + #ifndef XBMC + write(pConn->hairtunes->in[1], "vol: ", 5); + write(pConn->hairtunes->in[1], tVol, tSize); + write(pConn->hairtunes->in[1], "\n", 1); + #else +- hairtunes_setvolume(atof(tVol)); ++ if(tVol) ++ { ++ hairtunes_setvolume(atof(tVol)); ++ } ++ ++ if(iContentSize) ++ { ++ if(isJpg) ++ { ++ hairtunes_set_metadata_coverart(buffer, iContentSize); ++ } ++ else ++ { ++ hairtunes_set_metadata(buffer, iContentSize); ++ } ++ free(buffer); ++ } + #endif +- slog(LOG_DEBUG_VV, "Finished writing data write data to hairtunes\n"); ++ xprintf("Finished writing data write data to hairtunes\n"); + } + else + { +- slog(LOG_DEBUG, "\n\nUn-Handled recv: %s\n", pConn->recv.data); ++ xprintf("\n\nUn-Handled recv: %s\n", pConn->recv.data); + propogateCSeq(pConn); + } + addToShairBuffer(&(pConn->resp), "\r\n"); +@@ -1047,7 +1135,7 @@ + char tName[100 + HWID_SIZE + 3]; + if(strlen(pServerName) > tMaxServerName) + { +- slog(LOG_INFO,"Hey dog, we see you like long server names, " ++ xprintf("Hey dog, we see you like long server names, " + "so we put a strncat in our command so we don't buffer overflow, while you listen to your flow.\n" + "We just used the first %d characters. Pick something shorter if you want\n", tMaxServerName); + } +@@ -1058,7 +1146,7 @@ + strcat(tName, pHWStr); + strcat(tName, "@"); + strncat(tName, pServerName, tMaxServerName); +- slog(AVAHI_LOG_LEVEL, "Avahi/DNS-SD Name: %s\n", tName); ++ xprintf("Avahi/DNS-SD Name: %s\n", tName); + + execlp("avahi-publish-service", "avahi-publish-service", tName, + "_raop._tcp", tPort, "tp=UDP","sm=false","sv=false","ek=1","et=0,1", +@@ -1070,12 +1158,12 @@ + perror("error"); + } + +- slog(LOG_INFO, "Bad error... couldn't find or failed to run: avahi-publish-service OR dns-sd\n"); +- exit(1); ++ xprintf("Bad error... couldn't find or failed to run: avahi-publish-service OR dns-sd\n"); ++ //exit(1); + } + else + { +- slog(LOG_DEBUG_VV, "Avahi/DNS-SD started on PID: %d\n", tPid); ++ xprintf("Avahi/DNS-SD started on PID: %d\n", tPid); + } + return tPid; + } +@@ -1083,7 +1171,7 @@ + + void printBufferInfo(struct shairbuffer *pBuf, int pLevel) + { +- slog(pLevel, "Buffer: [%s] size: %d maxchars:%d\n", pBuf->data, pBuf->current, pBuf->maxsize/sizeof(char)); ++ xprintf("Buffer: [%s] size: %d maxchars:%d\n", pBuf->data, pBuf->current, pBuf->maxsize/sizeof(char)); + } + + int getAvailChars(struct shairbuffer *pBuf) +@@ -1164,7 +1252,8 @@ + { + va_list argp; + va_start(argp, pFormat); +- vprintf(pFormat, argp); ++ xprintf(pFormat, argp); ++ //vprintf(pFormat, argp); + va_end(argp); + } + //#endif +@@ -1218,9 +1307,9 @@ + { + if(pBuf->data != NULL) + { +- slog(LOG_DEBUG_VV, "Hrm, buffer wasn't cleaned up....trying to free\n"); ++ xprintf("Hrm, buffer wasn't cleaned up....trying to free\n"); + free(pBuf->data); +- slog(LOG_DEBUG_VV, "Free didn't seem to seg fault....huzzah\n"); ++ xprintf("Free didn't seem to seg fault....huzzah\n"); + } + pBuf->current = 0; + pBuf->marker = 0; +@@ -1278,6 +1367,6 @@ + BIO *tBio = BIO_new_mem_buf(AIRPORT_PRIVATE_KEY, -1); + RSA *rsa = PEM_read_bio_RSAPrivateKey(tBio, NULL, NULL, NULL); //NULL, NULL, NULL); + BIO_free(tBio); +- slog(RSA_LOG_LEVEL, "RSA Key: %d\n", RSA_check_key(rsa)); ++ xprintf("RSA Key: %d\n", RSA_check_key(rsa)); + return rsa; + } diff --git a/audio/libshairport/files/patch-src-shairport.h b/audio/libshairport/files/patch-src-shairport.h new file mode 100644 index 000000000000..33337cee6792 --- /dev/null +++ b/audio/libshairport/files/patch-src-shairport.h @@ -0,0 +1,51 @@ +--- src/shairport.h.orig 2011-08-21 01:58:11.000000000 +0200 ++++ src/shairport.h 2012-10-09 12:09:33.000000000 +0200 +@@ -11,14 +11,22 @@ + #include <regex.h> + #include <sys/types.h> + #include <regex.h> ++#include "ao.h" + + + #define HWID_SIZE 6 + #define SHAIRPORT_LOG 1 +-#define LOG_INFO 1 +-#define LOG_DEBUG 5 +-#define LOG_DEBUG_V 6 +-#define LOG_DEBUG_VV 7 ++ ++#ifndef LOG_INFO ++#define LOG_INFO 5 ++#endif ++ ++#ifndef LOG_DEBUG ++#define LOG_DEBUG 6 ++#endif ++ ++#define LOG_DEBUG_V 7 ++#define LOG_DEBUG_VV 8 + + struct shairbuffer + { +@@ -58,13 +66,21 @@ + { + #endif /* __cplusplus */ + ++struct printfPtr ++{ ++ int (*extprintf)(const char* msg, size_t msgSize); ++}; ++ + int shairport_main(int argc, char **argv); + void shairport_exit(void); + int shairport_loop(void); + int shairport_is_running(void); ++void shairport_set_ao(struct AudioOutput *ao); ++void shairport_set_printf(struct printfPtr *funcPtr); + + #ifdef __cplusplus + } + #endif /* __cplusplus */ + + #endif ++ diff --git a/audio/libshairport/files/patch-src-socketlib.c b/audio/libshairport/files/patch-src-socketlib.c new file mode 100644 index 000000000000..c2b3e6c14b81 --- /dev/null +++ b/audio/libshairport/files/patch-src-socketlib.c @@ -0,0 +1,58 @@ +--- src/socketlib.c.orig 2011-09-23 22:00:48.000000000 +0200 ++++ src/socketlib.c 2012-10-09 12:09:33.000000000 +0200 +@@ -48,7 +48,7 @@ + if((tSock==-1) && (pAddrInfo->ai_family == AF_INET6) && (errno == EAFNOSUPPORT)) + { + //Fallback to ipv4 +- perror("Failed to create ipv6 socket. Trying ipv4"); ++ xprintf("Failed to create ipv6 socket. Trying ipv4"); + pAddrInfo->ai_family = AF_INET; + tSock = socket(pAddrInfo->ai_family, pAddrInfo->ai_socktype, 0); + } +@@ -82,7 +82,7 @@ + delay(RETRY_DELAY, &tRes); + } + } +- printf("%d Retry attempts exceeded\n", RETRY_COUNT); ++ xprintf("%d Retry attempts exceeded\n", RETRY_COUNT); + return ERROR; + } + +@@ -102,7 +102,7 @@ + tError = getaddrinfo(pHostname, pService, &hints, pAddrInfo); + if(tError != 0) + { +- printf("Error getting address info\n"); ++ xprintf("Error getting address info\n"); + } + return tError; + } +@@ -158,8 +158,8 @@ + sprintf(tService, "%d", pPort); // copies port to string + int tFamily = AF_INET; + #ifdef AF_INET6 +- //printf("Listening on IPv6 Socket\n"); +- //tFamily = AF_INET6; ++ xprintf("Listening on IPv6 Socket\n"); ++ tFamily = AF_INET6; + #else + //printf("Listening on IPv4 Socket"); + #endif +@@ -200,7 +200,7 @@ + else + { + // Invalid encoded data, no other cases are possible. +- printf("Unrecoverable error....base64 values are incorrectly encoded\n"); ++ xprintf("Unrecoverable error....base64 values are incorrectly encoded\n"); + return pSize; + } + } +@@ -226,7 +226,7 @@ + memset(input, 0, length); + memcpy(input, pInput, pLength); + memset(input+pLength, '=', length-pLength); +- printf("Fixed value: [%.*s]\n", length, input); ++ xprintf("Fixed value: [%.*s]\n", length, input); + } + char *buffer = (char *)malloc(length); + memset(buffer, 0, length); diff --git a/audio/libshairport/pkg-descr b/audio/libshairport/pkg-descr new file mode 100644 index 000000000000..514bc09704d3 --- /dev/null +++ b/audio/libshairport/pkg-descr @@ -0,0 +1,17 @@ +libshairport +============ +Created by Team XBMC + +This is a fork of ShairPort written by James Laird <jhl@mafipulation.org>. The +XBMC team decided to fork ShairPort and make it into a library. + +What it is +---------- +This program emulates an AirPort Express for the purpose of streaming music from +iTunes and compatible iPods. It implements a server for the Apple RAOP protocol. +ShairPort does not support AirPlay v2 (video and photo streaming). + +It supports multiple simultaneous streams, if your audio output chain (as +detected by libao) does so. + +WWW: https://github.com/amejia1/libshairport diff --git a/audio/libshairport/pkg-plist b/audio/libshairport/pkg-plist new file mode 100644 index 000000000000..1b0883c65b83 --- /dev/null +++ b/audio/libshairport/pkg-plist @@ -0,0 +1,7 @@ +lib/libshairport.la +lib/libshairport.so +lib/libshairport.so.0 +include/shairport/shairport.h +include/shairport/ao.h +include/shairport/socketlib.h +@dirrm include/shairport |