[PATCH 01/31] Hack to support IPhone streaming
Niv Sardi <[email protected]>
| Newsgroups | gmane.comp.audio.icecast.devel |
|---|---|
| Message-ID | <[email protected]> |
Iphone (CoreMedia) requires that we insert a Range header, create a fake one on the fly ! Signed-off-by: Niv Sardi <[email protected]> --- src/format.c | 26 ++++++++++++++++++------ src/format_mp3.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 70 insertions(+), 12 deletions(-) diff --git a/src/format.c b/src/format.c index 415391c..369dfbd 100644 --- a/src/format.c +++ b/src/format.c @@ -3,7 +3,7 @@ * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * - * Copyright 2000-2004, Jack Moffitt <[email protected], + * Copyright 2000-2004, Jack Moffitt <[email protected], * Michael Smith <[email protected]>, * oddsock <[email protected]>, * Karl Heyes <[email protected]> @@ -85,7 +85,7 @@ int format_get_plugin(format_type_t type, source_t *source) break; } if (ret < 0) - stats_event (source->mount, "content-type", + stats_event (source->mount, "content-type", source->format->contenttype); return ret; @@ -93,7 +93,7 @@ int format_get_plugin(format_type_t type, source_t *source) /* clients need to be start from somewhere in the queue so we will look for - * a refbuf which has been previously marked as a sync point. + * a refbuf which has been previously marked as a sync point. */ static void find_client_start (source_t *source, client_t *client) { @@ -248,7 +248,7 @@ int format_generic_write_to_client (client_t *client) /* This is the commonly used for source streams, here we just progress to - * the next buffer in the queue if there is no more left to be written from + * the next buffer in the queue if there is no more left to be written from * the existing buffer. */ int format_advance_queue (source_t *source, client_t *client) @@ -280,12 +280,24 @@ static int format_prepare_headers (source_t *source, client_t *client) avl_node *node; ice_config_t *config; + /* Partial hack, check for range and user agent in this function */ + const char *useragent; + const char *range; + useragent = httpp_getvar (client->parser, "user-agent"); + range = httpp_getvar (client->parser, "range"); + remaining = client->refbuf->len; ptr = client->refbuf->data; client->respcode = 200; - bytes = snprintf (ptr, remaining, "HTTP/1.0 200 OK\r\n" - "Content-Type: %s\r\n", source->format->contenttype); + + if (range && useragent && strstr(useragent, "CoreMedia")) { + bytes = snprintf (ptr, remaining, "HTTP/1.1 206 Partial Content\r\n" + "Content-Type: %s\r\n", source->format->contenttype); + } else { + bytes = snprintf (ptr, remaining, "HTTP/1.0 200 OK\r\n" + "Content-Type: %s\r\n", source->format->contenttype); + } remaining -= bytes; ptr += bytes; @@ -307,7 +319,7 @@ static int format_prepare_headers (source_t *source, client_t *client) if (bitrate_filtered == 0) brfield = strstr(var->value, "bitrate="); if (brfield && sscanf (brfield, "bitrate=%u", &bitrate)) - { + { bytes = snprintf (ptr, remaining, "icy-br:%u\r\n", bitrate); next = 0; bitrate_filtered = 1; diff --git a/src/format_mp3.c b/src/format_mp3.c index 7f08e15..2d62314 100644 --- a/src/format_mp3.c +++ b/src/format_mp3.c @@ -4,7 +4,7 @@ * This program is distributed under the GNU General Public License, version 2. * A copy of this license is included with this source. * - * Copyright 2000-2004, Jack Moffitt <[email protected], + * Copyright 2000-2004, Jack Moffitt <[email protected], * Michael Smith <[email protected]>, * oddsock <[email protected]>, * Karl Heyes <[email protected]> @@ -461,7 +461,7 @@ static void format_mp3_free_plugin(format_plugin_t *self) /* This does the actual reading, making sure the read data is packaged in * blocks of 1400 bytes (near the common MTU size). This is because many - * incoming streams come in small packets which could waste a lot of + * incoming streams come in small packets which could waste a lot of * bandwidth with many listeners due to headers and such like. */ static int complete_read (source_t *source) @@ -476,7 +476,7 @@ static int complete_read (source_t *source) if (source_mp3->read_data == NULL) { - source_mp3->read_data = refbuf_new (REFBUF_SIZE); + source_mp3->read_data = refbuf_new (REFBUF_SIZE); source_mp3->read_count = 0; } buf = source_mp3->read_data->data + source_mp3->read_count; @@ -603,7 +603,7 @@ static refbuf_t *mp3_get_filter_meta (source_t *source) source_mp3->build_metadata_offset += bytes; break; } - /* copy all bytes except the last one, that way we + /* copy all bytes except the last one, that way we * know a null byte terminates the message */ memcpy (source_mp3->build_metadata + source_mp3->build_metadata_offset, src, metadata_remaining-1); @@ -654,6 +654,42 @@ static refbuf_t *mp3_get_filter_meta (source_t *source) return refbuf; } +inline int format_mp3_insert_coremedia_header(client_t *client, char *ptr, int remaining) { + int range[2]; + char *rangestr; + int read = 0; + int bytes; + rangestr = httpp_getvar(client->parser, "range"); + + if (rangestr != NULL) { + if (sscanf(rangestr, "bytes=%d-%d", &range[0], &range[1]) != 2) + return 0; + if (range[0] < 0) + return 0; + + char currenttime[50]; + time_t now; + int strflen; + struct tm result; + time(&now); + strflen = strftime(currenttime, 50, "%a, %d-%b-%Y %X GMT", + gmtime_r(&now, &result)); + client->respcode = 206; + bytes = snprintf(ptr, remaining, "Date: %s\r\n", currenttime); + if (bytes > 0){ + remaining -= bytes; + read += bytes; + } + bytes = snprintf(ptr + read, remaining, "Content-Range: bytes %d-%d/221183499\r\n", + range[0], range[1]); + if (bytes > 0) { + remaining -= bytes; + read += bytes; + } + } + + return read; +} static int format_mp3_create_client_data(source_t *source, client_t *client) { @@ -681,7 +717,17 @@ static int format_mp3_create_client_data(source_t *source, client_t *client) /* avoid browser caching, reported via forum */ bytes = snprintf (ptr, remaining, "Expires: Mon, 26 Jul 1997 05:00:00 GMT\r\n"); remaining -= bytes; - ptr += bytes; + ptr += bytes; + } + + /* hack for iPhone OS or Simulator with CoreMedia. checks user agent then adds iPhone-specific headers */ + if (useragent && strstr(useragent, "CoreMedia")) + { + bytes = format_mp3_insert_coremedia_header(client, ptr, remaining); + if (bytes) { + ptr += bytes; + remaining -= bytes; + } } client->format_data = client_mp3; -- 1.7.1