diff --git a/common.h b/common.h index 93d12dcc..62dd2e18 100644 --- a/common.h +++ b/common.h @@ -42,6 +42,7 @@ typedef struct { char *password; char *apname; char *meta_dir; + int get_coverart; 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/mdns.h b/mdns.h index e09b5686..a5dc88a4 100644 --- a/mdns.h +++ b/mdns.h @@ -15,7 +15,9 @@ typedef struct { // text and progress only -- picture feed really buggy from iTunes -#define MDNS_RECORD_WITH_METADATA "tp=UDP", "sm=false", "ek=1", "et=0,1", "cn=0,1", "ch=2", "md=0,1,2", \ +#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" diff --git a/rtsp.c b/rtsp.c index d4c7d186..a4561c49 100644 --- a/rtsp.c +++ b/rtsp.c @@ -538,20 +538,39 @@ static enum rtsp_read_request_response rtsp_read_request(int fd, rtsp_message** buflen = msg_size; } + 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; while (inbuf < msg_size) { - nread = read(fd, buf+inbuf, msg_size-inbuf); - if (!nread) { - reply = rtsp_read_request_response_error; - goto shutdown; + + // we are going to read the stream in chunks and time how long it takes to do so. + // If it's taking too long, (and we find out about it), we will send an error message as metadata + + if (warning_message_sent==0) { + 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."); + send_ssnc_metadata('stal',NULL,0,1); + warning_message_sent = 1; } - if (nread==EINTR) - continue; - if (nread < 0) { - perror("read failure"); - reply = rtsp_read_request_response_error; - goto shutdown; - } - inbuf += nread; + } + ssize_t read_chunk = msg_size-inbuf; + if (read_chunk > max_read_chunk) + read_chunk = max_read_chunk; + nread = read(fd, buf+inbuf, read_chunk); + if (!nread) { + reply = rtsp_read_request_response_error; + goto shutdown; + } + if (nread==EINTR) + continue; + if (nread < 0) { + perror("read failure"); + reply = rtsp_read_request_response_error; + goto shutdown; + } + inbuf += nread; } msg->contentlength = inbuf; diff --git a/shairport.c b/shairport.c index f0fc8539..e4d2f534 100644 --- a/shairport.c +++ b/shairport.c @@ -180,6 +180,8 @@ 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"); + 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"); printf("\n"); mdns_ls_backends(); printf("\n"); @@ -216,6 +218,7 @@ int parse_options(int argc, char **argv) { { "password", 0, POPT_ARG_STRING, &config.password, 0, NULL } , { "tolerance", 0, POPT_ARG_INT, &config.tolerance, 0, NULL } , { "meta-dir", 'M', POPT_ARG_STRING, &config.meta_dir, 0, NULL } , + { "get-coverart", 'g', POPT_ARG_NONE, &config.get_coverart, 0, NULL }, POPT_AUTOHELP { NULL, 0, 0, NULL, 0 } }; @@ -235,6 +238,10 @@ int parse_options(int argc, char **argv) { case 'v': debuglev++; break; + case 'g': + if (config.meta_dir==0) + die("If you want to get cover art, you must also select the --meta-dir option."); + break; case 'S': if (strcmp(stuffing,"basic")==0) config.packet_stuffing = ST_basic; @@ -273,7 +280,7 @@ int parse_options(int argc, char **argv) { debug(2,"tolerance is %d frames.",config.tolerance); debug(2,"password is \"%s\".",config.password); debug(2,"metadata directory is \"%s\".",config.meta_dir); - + debug(2,"get-coverart is %d.",config.get_coverart); return optind+1; }