diff --git a/common.h b/common.h index 62dd2e18..9a35d187 100644 --- a/common.h +++ b/common.h @@ -41,8 +41,10 @@ enum stuffing_type { typedef struct { char *password; char *apname; +#ifdef CONFIG_METADATA char *meta_dir; int get_coverart; +#endif uint8_t hw_addr[6]; int port; int resyncthreshold; // if it get's out of whack my more than this, resync. Zero means never resync. diff --git a/configure.ac b/configure.ac index f8243023..779baa1a 100644 --- a/configure.ac +++ b/configure.ac @@ -74,6 +74,13 @@ AC_ARG_WITH(soxr, [ --with-soxr = choose libsoxr for high-quality interpolation AC_MSG_RESULT(>>Including support for soxr-based interpolation) AC_CHECK_LIB([soxr],[soxr_create], , AC_MSG_ERROR(soxr support requested but libsoxr not found!))], ) +# Look for metadata flag -- set flag for conditional compilation +AC_ARG_WITH(metadata, [ --with-metadata = include support for a metadata feed], [ + AC_MSG_RESULT(>>Including metadata support) + HAS_METADATA=1 + AC_DEFINE([CONFIG_METADATA], 1, [Needed by the compiler.])], ) +AM_CONDITIONAL([USE_METADATA], [test "x$HAS_METADATA" = "x1"]) + # What follows is a bit messy, because if the relevant library is requested, a compiler flag is defined, a file is included in the compilation # and the relevant link files are added. diff --git a/mdns.h b/mdns.h index a5dc88a4..247b9a68 100644 --- a/mdns.h +++ b/mdns.h @@ -1,6 +1,8 @@ #ifndef _MDNS_H #define _MDNS_H +#include "config.h" + extern int mdns_pid; void mdns_unregister(void); @@ -15,11 +17,14 @@ typedef struct { // text and progress only -- picture feed really buggy from iTunes +#ifdef CONFIG_METADATA + #define METADATA_EXPRESSION config.get_coverart ? "md=0,1,2" : "md=0,2" #define MDNS_RECORD_WITH_METADATA "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" +#endif #define MDNS_RECORD_WITHOUT_METADATA "tp=UDP", "sm=false", "ek=1", "et=0,1", "cn=0,1", "ch=2", \ "ss=16", "sr=44100", "vn=3", "txtvers=1", \ diff --git a/mdns_avahi.c b/mdns_avahi.c index f1db7c68..6b073115 100644 --- a/mdns_avahi.c +++ b/mdns_avahi.c @@ -62,6 +62,7 @@ static void register_service(AvahiClient *c) { return; int ret; +#ifdef CONFIG_METADATA if (config.meta_dir) { debug(1,"Avahi with metadata"); ret = avahi_entry_group_add_service(group, @@ -77,6 +78,7 @@ static void register_service(AvahiClient *c) { NULL); } else { +#endif debug(1,"Avahi without metadata"); ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, @@ -89,7 +91,9 @@ static void register_service(AvahiClient *c) { port, MDNS_RECORD_WITHOUT_METADATA, NULL); +#ifdef CONFIG_METADATA } +#endif if (ret < 0) die("avahi_entry_group_add_service failed"); diff --git a/mdns_dns_sd.c b/mdns_dns_sd.c index 1a458ea3..4f586b93 100644 --- a/mdns_dns_sd.c +++ b/mdns_dns_sd.c @@ -33,12 +33,15 @@ static DNSServiceRef service; static int mdns_dns_sd_register(char *apname, int port) { const char *recordwithoutmetadata[] = { MDNS_RECORD_WITHOUT_METADATA, NULL }; +#ifdef CONFIG_METADATA const char *recordwithmetadata[] = { MDNS_RECORD_WITH_METADATA, NULL }; - +#endif char **record; +#ifdef CONFIG_METADATA if (config.meta_dir) record = recordwithmetadata; else +#endif record = recordwithoutmetadata; uint16_t length = 0; diff --git a/mdns_external.c b/mdns_external.c index 912dfec1..832d8e06 100644 --- a/mdns_external.c +++ b/mdns_external.c @@ -92,15 +92,18 @@ static int mdns_external_avahi_register(char *apname, int port) { char *argvwithoutmetadata[] = { NULL, apname, "_raop._tcp", mdns_port, MDNS_RECORD_WITHOUT_METADATA, NULL }; - +#ifdef CONFIG_METADATA char *argvwithmetadata[] = { NULL, apname, "_raop._tcp", mdns_port, MDNS_RECORD_WITH_METADATA, NULL }; - +#endif char **argv; + +#ifdef CONFIG_METADATA if (config.meta_dir) argv=argvwithmetadata; else +#endif argv=argvwithoutmetadata; argv[0] = "avahi-publish-service"; @@ -135,14 +138,19 @@ static int mdns_external_dns_sd_register(char *apname, int port) { NULL, apname, "_raop._tcp", mdns_port, MDNS_RECORD_WITHOUT_METADATA, NULL }; +#ifdef CONFIG_METADATA char *argvwithmetadata[] = { NULL, apname, "_raop._tcp", mdns_port, MDNS_RECORD_WITH_METADATA, NULL }; - +#endif + char **argv; +#ifdef CONFIG_METADATA if (config.meta_dir) argv=argvwithmetadata; else +#endif + argv=argvwithoutmetadata; int pid = fork_execvp(argv[0], argv); diff --git a/mdns_tinysvcmdns.c b/mdns_tinysvcmdns.c index fa258e54..8b79d49c 100644 --- a/mdns_tinysvcmdns.c +++ b/mdns_tinysvcmdns.c @@ -123,13 +123,17 @@ static int mdns_tinysvcmdns_register(char *apname, int port) { freeifaddrs(ifa); char *txtwithoutmetadata[] = { MDNS_RECORD_WITHOUT_METADATA, NULL }; +#ifdef CONFIG_METADATA char *txtwithmetadata[] = { MDNS_RECORD_WITH_METADATA, NULL }; - +#endif char **txt; - + +#ifdef CONFIG_METADATA if (config.meta_dir) txt = txtwithmetadata; else +#endif + txt = txtwithoutmetadata; diff --git a/player.c b/player.c index a002db5b..5be04439 100644 --- a/player.c +++ b/player.c @@ -564,9 +564,11 @@ static abuf_t *buffer_get_frame(void) { // debug(1,"Exact frame gap is %llu; play %d frames of silence. Dac_delay is %d, with %d packets.",exact_frame_gap,fs,dac_delay,seq_diff(ab_read, ab_write)); config.output->play(silence, fs); free(silence); +#ifdef CONFIG_METADATA if (ab_buffering==0) { send_ssnc_metadata('prsm',NULL,0,0); // "resume", but don't wait if the queue is locked } +#endif } } } @@ -1061,14 +1063,14 @@ void player_volume(double f) { software_mixer_volume = linear_volume; fix_volume = 65536.0 * software_mixer_volume; pthread_mutex_unlock(&vol_mutex); - +#ifdef CONFIG_METADATA char *dv = malloc(64); // will be freed in the metadata thread if (dv) { memset(dv,0,64); snprintf(dv,63,"%.2f,%.2f,%.2f,%.2f",audio_information.airplay_volume,audio_information.current_volume_dB/100.0,audio_information.minimum_volume_dB/100.0,audio_information.maximum_volume_dB/100.0); send_ssnc_metadata('pvol',dv,strlen(dv),1); } - +#endif } @@ -1079,7 +1081,9 @@ void player_flush(uint32_t timestamp) { //if (timestamp!=0) flush_rtp_timestamp=timestamp; // flush all packets up to (and including?) this pthread_mutex_unlock(&flush_mutex); +#ifdef CONFIG_METADATA send_ssnc_metadata('pfls',NULL,0,1); +#endif } int player_play(stream_cfg *stream) { @@ -1103,7 +1107,9 @@ int player_play(stream_cfg *stream) { init_buffer(); please_stop = 0; command_start(); +#ifdef CONFIG_METADATA send_ssnc_metadata('pbeg',NULL,0,1); +#endif // set the flowcontrol condition variable to wait on a monotonic clock #ifdef COMPILE_FOR_LINUX @@ -1127,7 +1133,9 @@ void player_stop(void) { please_stop = 1; pthread_cond_signal(&flowcontrol); // tell it to give up pthread_join(player_thread, NULL); +#ifdef CONFIG_METADATA send_ssnc_metadata('pend',NULL,0,1); +#endif config.output->stop(); command_stop(); free_buffer(); diff --git a/player.h b/player.h index 5188ac07..0a9f82a5 100644 --- a/player.h +++ b/player.h @@ -18,11 +18,6 @@ void player_stop(void); void player_volume(double f); void player_flush(uint32_t timestamp); -void player_resync(void); - -void player_metadata(); -void player_cover_image(char *buf, int len, char *ext); -void player_cover_clear(); void player_put_packet(seq_t seqno,uint32_t timestamp, uint8_t *data, int len); diff --git a/rtsp.c b/rtsp.c index a4561c49..91e0728e 100644 --- a/rtsp.c +++ b/rtsp.c @@ -91,7 +91,7 @@ typedef struct { pthread_t thread; } rtsp_conn_info; - +#ifdef CONFIG_METADATA typedef struct { pthread_mutex_t pc_queue_lock; pthread_cond_t pc_queue_item_added_signal; @@ -103,6 +103,7 @@ typedef struct { uint32_t eoq; // free space at end of queue void *items; // a pointer to where the items are actually stored } pc_queue; // producer-consumer queue +#endif typedef struct { uint32_t referenceCount; // we might start using this... @@ -120,6 +121,7 @@ typedef struct { int respcode; } rtsp_message; +#ifdef CONFIG_METADATA typedef struct { uint32_t type; uint32_t code; @@ -143,49 +145,6 @@ int send_ssnc_metadata(uint32_t code,char *data,uint32_t length,int block) { return send_metadata('ssnc',code,data,length,NULL,block); } - -/* -pc_queue* pc_queue_create(size_t new_item_size, uint32_t number_of_items) { - debug(1,"Creating pc_queue"); - pc_queue* the_queue = malloc(sizeof(pc_queue)+number_of_items*new_item_size-sizeof(void*)); - if (the_queue) { - int rc = pthread_mutex_init(&the_queue->pc_queue_lock,NULL); - if (rc) - debug(1,"Error %d creating pc_queue lock",rc); - rc = pthread_cond_init(&the_queue->pc_queue_item_added_signal,NULL); - if (rc) - debug(1,"Error %d creating pc_queue add cond",rc); - rc = pthread_cond_init(&the_queue->pc_queue_item_removed_signal,NULL); - if (rc) - debug(1,"Error %d creating pc_queue remove cond",rc); - the_queue->item_size = new_item_size; - the_queue->count = 0; - the_queue->capacity = number_of_items; - the_queue->toq = 0; - the_queue->eoq = 0; - } - return the_queue; -} - -int pc_queue_delete(pc_queue* the_queue) { - if (the_queue) { - int rc = pthread_mutex_destroy(&the_queue->pc_queue_lock); - if (rc) - debug(1,"Error %d deleting pc_queue lock",rc); - rc = pthread_cond_destroy(&the_queue->pc_queue_item_added_signal); - if (rc) - debug(1,"Error %d deleting pc_queue add cond",rc); - rc = pthread_cond_destroy(&the_queue->pc_queue_item_removed_signal); - if (rc) - debug(1,"Error %d deleting pc_queue remove cond",rc); - free(the_queue); - } else { - debug(1,"Attempting to delete a NULL pc_queue!"); - } - return 0; -} -*/ - int pc_queue_add_item(pc_queue* the_queue,const void* the_stuff, int block) { int rc; if (the_queue) { @@ -263,6 +222,7 @@ int pc_queue_get_item(pc_queue* the_queue,void* the_stuff) { return 0; } +#endif // determine if we are the currently playing thread static inline int rtsp_playing(void) { @@ -551,7 +511,9 @@ static enum rtsp_read_request_response rtsp_read_request(int fd, rtsp_message** uint64_t time_now = get_absolute_time_in_fp(); if (time_now>threshold_time) { // it's taking too long debug(1,"Error receiving metadata from source -- transmission seems to be stalled."); +#ifdef CONFIG_METADATA send_ssnc_metadata('stal',NULL,0,1); +#endif warning_message_sent = 1; } } @@ -785,11 +747,15 @@ static void handle_set_parameter_parameter(rtsp_conn_info *conn, float volume = atof(cp + 8); debug(2, "volume: %f\n", volume); player_volume(volume); - } else if(!strncmp(cp, "progress: ", 10)) { + } else +#ifdef CONFIG_METADATA + if(!strncmp(cp, "progress: ", 10)) { char *progress = cp + 10; debug(2, "progress: \"%s\"\n", progress); // rtpstampstart/rtpstampnow/rtpstampend 44100 per second send_ssnc_metadata('prgr',strdup(progress),strlen(progress),1); - } else { + } else +#endif + { debug(1, "unrecognised parameter: \"%s\" (%d)\n", cp, strlen(cp)); } cp = next; @@ -797,7 +763,7 @@ static void handle_set_parameter_parameter(rtsp_conn_info *conn, } - +#ifdef CONFIG_METADATA // Metadata is not used by shairport-sync. // Instead we send all metadata to a fifo pipe, so that other apps can listen to the pipe and use the metadata. @@ -1095,6 +1061,8 @@ static void handle_set_parameter_metadata(rtsp_conn_info *conn, send_metadata('ssnc','sndr',strdup(sender_name),strlen(sender_name),NULL,1); } +#endif + static void handle_set_parameter(rtsp_conn_info *conn, rtsp_message *req, rtsp_message *resp) { //if (!req->contentlength) @@ -1104,7 +1072,7 @@ static void handle_set_parameter(rtsp_conn_info *conn, if (ct) { debug(2, "SET_PARAMETER Content-Type:\"%s\".", ct); - +#ifdef CONFIG_METADATA if (!strncmp(ct, "application/x-dmap-tagged", 25)) { debug(2, "received metadata tags in SET_PARAMETER request."); handle_set_parameter_metadata(conn, req, resp); @@ -1113,7 +1081,9 @@ static void handle_set_parameter(rtsp_conn_info *conn, // note: the image/type tag isn't reliable, so it's not being sent // -- best look at the first few bytes of the image send_metadata('ssnc','PICT',req->content,req->contentlength,req,1); - } else if (!strncmp(ct, "text/parameters", 15)) { + } else +#endif + if (!strncmp(ct, "text/parameters", 15)) { debug(2, "received parameters in SET_PARAMETER request."); handle_set_parameter_parameter(conn, req, resp); } else { diff --git a/shairport.c b/shairport.c index e4d2f534..565ced69 100644 --- a/shairport.c +++ b/shairport.c @@ -133,6 +133,9 @@ void print_version(void) { #endif #ifdef HAVE_LIBSOXR strcat(version_string,"-soxr"); +#endif +#ifdef CONFIG_METADATA + strcat(version_string,"-metadata"); #endif printf("%s\n",version_string); } @@ -180,8 +183,10 @@ void usage(char *progname) { printf(" --statistics print some interesting statistics -- output to the logfile if running as a daemon.\n"); printf(" --tolerance=TOLERANCE allow a synchronization error of TOLERANCE frames (default 88) before trying to correct it.\n"); printf(" --password=PASSWORD require PASSWORD to connect. Default is not to require a password.\n"); +#ifdef CONFIG_METADATA printf(" --meta-dir=DIR get metadata from the source and pipe it to DIR/shairport-sync-metadata, e.g. --meta-dir=/tmp.\n"); printf(" --get-coverart get cover art from the source and pipe it to DIR/shairport-sync-metadata, e.g. --meta-dir=/tmp.\n"); +#endif printf("\n"); mdns_ls_backends(); printf("\n"); @@ -217,8 +222,10 @@ int parse_options(int argc, char **argv) { { "timeout", 't', POPT_ARG_INT, &config.timeout, 0, NULL } , { "password", 0, POPT_ARG_STRING, &config.password, 0, NULL } , { "tolerance", 0, POPT_ARG_INT, &config.tolerance, 0, NULL } , +#ifdef CONFIG_METADATA { "meta-dir", 'M', POPT_ARG_STRING, &config.meta_dir, 0, NULL } , - { "get-coverart", 'g', POPT_ARG_NONE, &config.get_coverart, 0, NULL }, + { "get-coverart", 'g', POPT_ARG_NONE, &config.get_coverart, 0, NULL } , +#endif POPT_AUTOHELP { NULL, 0, 0, NULL, 0 } }; @@ -238,10 +245,12 @@ int parse_options(int argc, char **argv) { case 'v': debuglev++; break; +#ifdef CONFIG_METADATA case 'g': if (config.meta_dir==0) die("If you want to get cover art, you must also select the --meta-dir option."); break; +#endif case 'S': if (strcmp(stuffing,"basic")==0) config.packet_stuffing = ST_basic; @@ -279,8 +288,10 @@ int parse_options(int argc, char **argv) { debug(2,"busy timeout time is %d.",config.timeout); debug(2,"tolerance is %d frames.",config.tolerance); debug(2,"password is \"%s\".",config.password); +#ifdef CONFIG_METADATA debug(2,"metadata directory is \"%s\".",config.meta_dir); debug(2,"get-coverart is %d.",config.get_coverart); +#endif return optind+1; } @@ -538,7 +549,9 @@ int main(int argc, char **argv) { md5_finish(&tctx, ap_md5); #endif memcpy(config.hw_addr, ap_md5, sizeof(config.hw_addr)); +#ifdef CONFIG_METADATA metadata_init() ; // create the metadata pipe if necessary +#endif rtsp_listen_loop();