diff --git a/README.md b/README.md index 32133aa6f..306fd8831 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,11 @@ An example:: comment= +Additionally, a fifo named `position` will also be created and will be updated +roughly once a second with the position and the total duration of the +currently playing track, space-separated. + + Thanks ------ Big thanks to David Hammerton for releasing an ALAC decoder, which is reproduced here in full. @@ -100,7 +105,7 @@ Contributors to version 1.x * [Peter Körner](http://mazdermind.de) * [Muffinman](http://github.com/therealmuffin) * [Skaman](http://github.com/skaman) -* [Weston](http://github.com/wnielson) +* [Weston Nielson](http://github.com/wnielson) * [allesblinkt](http://github.com/allesblinkt) Contributors to version 0.x @@ -128,4 +133,4 @@ Known Ports and Tools * [shairport4w](http://sf.net/projects/shairport4w) * OS X: * [ShairportMenu](https://github.com/rcarlsen/ShairPortMenu), a GUI wrapper as a menu widget - * [MacShairport](https://github.com/joshaber/MacShairport) + * [MacShairport](https://github.com/joshaber/MacShairport) \ No newline at end of file diff --git a/metadata.c b/metadata.c index 5054ba0d7..e9708e34f 100644 --- a/metadata.c +++ b/metadata.c @@ -41,6 +41,7 @@ metadata player_meta; static int fd = -1; static int dirty = 0; +static int fdp = -1; void metadata_set(char** field, const char* value) { if (*field) { @@ -77,6 +78,31 @@ static void metadata_close(void) { fd = -1; } +void metadata_position_open(void) { + if (!config.meta_dir) + return; + + const char fn[] = "position"; + size_t pl = strlen(config.meta_dir) + 1 + strlen(fn); + + char* path = malloc(pl+1); + snprintf(path, pl+1, "%s/%s", config.meta_dir, fn); + + if (mkfifo(path, 0644) && errno != EEXIST) + die("Could not create metadata FIFO %s", path); + + fdp = open(path, O_WRONLY | O_NONBLOCK); + if (fdp < 0) + debug(1, "Could not open metadata position FIFO %s. Will try again later.", path); + + free(path); +} + +static void metadata_position_close(void) { + close(fdp); + fdp = -1; +} + static void print_one(const char *name, const char *value) { write_unchecked(fd, name, strlen(name)); write_unchecked(fd, "=", 1); @@ -114,6 +140,43 @@ void metadata_write(void) { metadata_close(); } +void metadata_position_write(void) { + int ret; + + if (player_meta.paused) + return; + + // readers may go away and come back + if (fdp < 0) + metadata_position_open(); + if (fdp < 0) + return; + + char number[10]; + int chars; + + // + // XXX: The sample rate is always 44100 Hertz, right? + // + unsigned int position = (player_meta.position-player_meta.start)/44100; + unsigned int length = (player_meta.end-player_meta.start)/44100; + + if (length == 0 || position > length) + return; + + chars = sprintf(number, "%d", position); + write_unchecked(fdp, number, chars); + + write_unchecked(fdp, " ", 1); + + chars = sprintf(number, "%d", length); + write_unchecked(fdp, number, chars); + + ret = write(fdp, "\n", 1); + if (ret < 1) // no reader + metadata_position_close(); +} + void metadata_cover_image(const char *buf, int len, const char *ext) { if (!config.meta_dir) return; diff --git a/metadata.h b/metadata.h index 3ca5595cb..ea01d8966 100644 --- a/metadata.h +++ b/metadata.h @@ -10,12 +10,19 @@ typedef struct { char *artwork; char *comment; char *genre; + + unsigned int paused; + unsigned int position; + unsigned int start; + unsigned int curr; + unsigned int end; } metadata; void metadata_set(char** field, const char* value); void metadata_open(void); void metadata_write(void); void metadata_cover_image(const char *buf, int len, const char *ext); +void metadata_position_write(void); extern metadata player_meta; diff --git a/player.c b/player.c index bc569c338..9b6229ca4 100644 --- a/player.c +++ b/player.c @@ -476,6 +476,7 @@ static void *player_thread_func(void *arg) { #endif play_samples = stuff_buffer(bf_playback_rate, inbuf, outbuf); + player_meta.paused = 0; config.output->play(outbuf, play_samples); } @@ -496,6 +497,7 @@ void player_volume(double f) { } } void player_flush(void) { + player_meta.paused = 1; pthread_mutex_lock(&ab_mutex); ab_resync(); pthread_mutex_unlock(&ab_mutex); diff --git a/rtp.c b/rtp.c index 51b846d5d..5cd1e7f87 100644 --- a/rtp.c +++ b/rtp.c @@ -34,6 +34,7 @@ #include #include "common.h" #include "player.h" +#include "metadata.h" // only one RTP session can be active at a time. static int running = 0; @@ -57,8 +58,14 @@ static void *rtp_receiver(void *arg) { ssize_t plen = nread; uint8_t type = packet[1] & ~0x80; - if (type == 0x54) // sync + if (type == 0x54) { // sync + player_meta.position = (packet[4] << 24) | + (packet[5] << 16) | + (packet[6] << 8) | + (packet[7]); + metadata_position_write(); continue; + } if (type == 0x60 || type == 0x56) { // audio data / resend pktp = packet; if (type==0x56) { diff --git a/rtsp.c b/rtsp.c index 41c8d87cf..67b7fb21c 100644 --- a/rtsp.c +++ b/rtsp.c @@ -410,7 +410,7 @@ static void handle_setup(rtsp_conn_info *conn, int sport = rtp_setup(&conn->remote, cport, tport); if (!sport) return; - + player_play(&conn->stream); char resphdr[100]; @@ -445,6 +445,12 @@ static void handle_set_parameter_parameter(rtsp_conn_info *conn, } else if(!strncmp(cp, "progress: ", 10)) { char *progress = cp + 10; debug(1, "progress: %s\n", progress); + + if (sscanf(progress, "%u/%u/%u", &(player_meta.start), &(player_meta.curr), &(player_meta.end)) != 3) + { + player_meta.position = 0; + } + } else { debug(1, "unrecognised parameter: >>%s<< (%d)\n", cp, strlen(cp)); }