mirror of
https://github.com/tuxbox-neutrino/neutrino.git
synced 2025-08-30 17:01:15 +02:00
netfile: add chunked mode
This commit is contained in:
@@ -426,8 +426,12 @@ int request_file(URL *url)
|
|||||||
send(url->fd, str, strlen(str), 0);
|
send(url->fd, str, strlen(str), 0);
|
||||||
|
|
||||||
if( (meta_int = parse_response(url, &id3, &tmp)) < 0)
|
if( (meta_int = parse_response(url, &id3, &tmp)) < 0)
|
||||||
return meta_int;
|
{
|
||||||
|
if(meta_int == -301 || meta_int == -302)
|
||||||
|
return meta_int;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
if(meta_int)
|
if(meta_int)
|
||||||
{
|
{
|
||||||
if (slot < 0) {
|
if (slot < 0) {
|
||||||
@@ -500,7 +504,12 @@ int request_file(URL *url)
|
|||||||
send(url->fd, str, strlen(str), 0);
|
send(url->fd, str, strlen(str), 0);
|
||||||
|
|
||||||
if( (meta_int = parse_response(url, &id3, &tmp)) < 0)
|
if( (meta_int = parse_response(url, &id3, &tmp)) < 0)
|
||||||
return meta_int;
|
{
|
||||||
|
if(meta_int == -301 || meta_int == -302)
|
||||||
|
return meta_int;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if(meta_int)
|
if(meta_int)
|
||||||
{
|
{
|
||||||
@@ -658,20 +667,29 @@ int parse_response(URL *url, void * /*opt*/, CSTATE *state)
|
|||||||
if(rval >= 0)
|
if(rval >= 0)
|
||||||
return rval;
|
return rval;
|
||||||
|
|
||||||
|
/* no content length indication from the server ? Then treat it as stream */
|
||||||
|
getHeaderVal("icy-metaint:", meta_interval);
|
||||||
|
if(meta_interval < 0)
|
||||||
|
meta_interval = 0;
|
||||||
|
if (state != NULL)
|
||||||
|
state->meta_interval = meta_interval;
|
||||||
/* yet another hack: this is only implemented to be able to fetch */
|
/* yet another hack: this is only implemented to be able to fetch */
|
||||||
/* the playlists from shoutcast */
|
/* the playlists from shoutcast */
|
||||||
if(strstr(header, "Transfer-Encoding: chunked"))
|
if(strstr(header, "Transfer-Encoding: chunked"))
|
||||||
{
|
{
|
||||||
readln(fd, str);
|
readln(fd, str);
|
||||||
sscanf(str, "%x", &rval);
|
sscanf(str, "%x", &rval);
|
||||||
|
if (state != NULL)
|
||||||
|
{
|
||||||
|
int chunksize = rval;
|
||||||
|
if(chunksize < 0)
|
||||||
|
chunksize = 0;
|
||||||
|
state->chunksize = chunksize;
|
||||||
|
recv(fd, str, 1, 0);
|
||||||
|
}
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* no content length indication from the server ? Then treat it as stream */
|
|
||||||
getHeaderVal("icy-metaint:", meta_interval);
|
|
||||||
if(meta_interval < 0)
|
|
||||||
meta_interval = 0;
|
|
||||||
|
|
||||||
if (state != NULL) {
|
if (state != NULL) {
|
||||||
getHeaderStr("icy-genre:", state->genre);
|
getHeaderStr("icy-genre:", state->genre);
|
||||||
getHeaderStr("icy-name:", state->station);
|
getHeaderStr("icy-name:", state->station);
|
||||||
@@ -1601,12 +1619,55 @@ int pop(FILE *fd, char *buf, long len)
|
|||||||
|
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
static int http_read_stream_all(FILE *fd, char *buf, int size)
|
||||||
|
{
|
||||||
|
int pos = 0;
|
||||||
|
while (pos < size) {
|
||||||
|
int len = read(fileno(fd), buf + pos, size - pos);
|
||||||
|
if (len == 0)
|
||||||
|
return len;
|
||||||
|
pos += len;
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool getChunkSizeLine(FILE *fd,char *line,int size)
|
||||||
|
{
|
||||||
|
char c = 0;
|
||||||
|
int pos = 0,rn = 0,rnc = 4;
|
||||||
|
while(read(fileno(fd), &c, 1)!=0)
|
||||||
|
{
|
||||||
|
if(pos >= size)
|
||||||
|
break;
|
||||||
|
if(c == '\n' || c == '\r')
|
||||||
|
{
|
||||||
|
rn++;
|
||||||
|
if(rn == rnc)
|
||||||
|
break;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(isxdigit(c)){
|
||||||
|
line[pos++] = c;
|
||||||
|
if(!rn)
|
||||||
|
rnc = 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(c == '\n' || rn == 2)
|
||||||
|
{
|
||||||
|
line[pos++] = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void CacheFillThread(void *c)
|
void CacheFillThread(void *c)
|
||||||
{
|
{
|
||||||
char *buf;
|
|
||||||
STREAM_CACHE *scache = (STREAM_CACHE*)c;
|
STREAM_CACHE *scache = (STREAM_CACHE*)c;
|
||||||
int rval, datalen;
|
|
||||||
|
|
||||||
if(scache->closed)
|
if(scache->closed)
|
||||||
return;
|
return;
|
||||||
@@ -1614,13 +1675,24 @@ void CacheFillThread(void *c)
|
|||||||
set_threadname("netfile:cache");
|
set_threadname("netfile:cache");
|
||||||
dprintf(stderr, "CacheFillThread: thread started, using stream %p\n", scache->fd);
|
dprintf(stderr, "CacheFillThread: thread started, using stream %p\n", scache->fd);
|
||||||
|
|
||||||
buf = (char*)malloc(CACHEBTRANS);
|
int meta_interval = CACHEBTRANS;
|
||||||
|
if(scache->filter_arg && scache->filter_arg->state && scache->filter_arg->state->meta_interval)
|
||||||
|
meta_interval = scache->filter_arg->state->meta_interval;
|
||||||
|
|
||||||
|
char *buf = (char*)malloc(meta_interval);
|
||||||
if(!buf)
|
if(!buf)
|
||||||
{
|
{
|
||||||
dprintf(stderr, "CacheFillThread: fatal error ! Could not allocate memory. Terminating.\n");
|
dprintf(stderr, "CacheFillThread: fatal error ! Could not allocate memory. Terminating.\n");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
int chunkSize = 0;
|
||||||
|
if(scache->filter_arg && scache->filter_arg->state && scache->filter_arg->state->chunksize)
|
||||||
|
chunkSize = scache->filter_arg->state->chunksize;
|
||||||
|
|
||||||
|
int rest = 0;
|
||||||
|
int rval = 0;
|
||||||
|
int datalen = 0;
|
||||||
|
bool chunked = chunkSize ? true : false;
|
||||||
|
|
||||||
/* endless loop; read a block of data from the stream */
|
/* endless loop; read a block of data from the stream */
|
||||||
/* and push it into the cache */
|
/* and push it into the cache */
|
||||||
@@ -1629,7 +1701,7 @@ void CacheFillThread(void *c)
|
|||||||
struct pollfd pfd;
|
struct pollfd pfd;
|
||||||
|
|
||||||
/* has a f_close() call in an other thread already closed the cache ? */
|
/* has a f_close() call in an other thread already closed the cache ? */
|
||||||
datalen = CACHEBTRANS;
|
datalen = meta_interval;
|
||||||
|
|
||||||
pfd.fd = fileno(scache->fd);
|
pfd.fd = fileno(scache->fd);
|
||||||
pfd.events = POLLIN | POLLPRI;
|
pfd.events = POLLIN | POLLPRI;
|
||||||
@@ -1638,18 +1710,39 @@ void CacheFillThread(void *c)
|
|||||||
int ret = poll(&pfd, 1, 1000);
|
int ret = poll(&pfd, 1, 1000);
|
||||||
|
|
||||||
if (ret > 0 && (pfd.revents & POLLIN) == POLLIN) {
|
if (ret > 0 && (pfd.revents & POLLIN) == POLLIN) {
|
||||||
#if 0 //FIXME: fread blocks i/o on dead connection
|
if(chunked)
|
||||||
rval = fread(buf, 1, datalen, scache->fd);
|
{
|
||||||
if ((rval == 0) && feof(scache->fd))
|
if(chunkSize <= 0)
|
||||||
break; /* exit cache fill thread if eof and nothing to push */
|
{
|
||||||
#else
|
chunkSize = 0;
|
||||||
rval = read(fileno(scache->fd), buf, datalen);
|
char line[32];
|
||||||
|
if(getChunkSizeLine(scache->fd,line,sizeof(line)))
|
||||||
|
chunkSize = strtol(line, NULL, 16);
|
||||||
|
|
||||||
|
if(!chunkSize)
|
||||||
|
{
|
||||||
|
dprintf(stderr, "CacheFillThread: chunkSize 0\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
datalen = meta_interval;
|
||||||
|
if(chunkSize && chunkSize < datalen)
|
||||||
|
{
|
||||||
|
datalen = chunkSize ;
|
||||||
|
}
|
||||||
|
if(rest)
|
||||||
|
{
|
||||||
|
datalen = rest;
|
||||||
|
rest = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rval = http_read_stream_all(scache->fd, buf, datalen);
|
||||||
if (rval == 0)
|
if (rval == 0)
|
||||||
break; /* exit cache fill thread if eof and nothing to push */
|
break; /* exit cache fill thread if eof and nothing to push */
|
||||||
#endif
|
|
||||||
/* if there is a filter function set up for this stream, then */
|
/* if there is a filter function set up for this stream, then */
|
||||||
/* we need to call it with the propper arguments */
|
/* we need to call it with the propper arguments */
|
||||||
if(scache->filter)
|
if(!chunked && scache->filter)
|
||||||
{
|
{
|
||||||
scache->filter_arg->buf = buf;
|
scache->filter_arg->buf = buf;
|
||||||
scache->filter_arg->len = &rval;
|
scache->filter_arg->len = &rval;
|
||||||
@@ -1659,6 +1752,36 @@ void CacheFillThread(void *c)
|
|||||||
|
|
||||||
if( push(scache->fd, buf, rval) < 0)
|
if( push(scache->fd, buf, rval) < 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
if(chunked)
|
||||||
|
chunkSize -= rval;
|
||||||
|
|
||||||
|
if(enable_metadata && chunked)
|
||||||
|
{
|
||||||
|
if(chunkSize <= 0)
|
||||||
|
{
|
||||||
|
rest = meta_interval - rval;
|
||||||
|
}
|
||||||
|
if(chunkSize > 0)
|
||||||
|
{
|
||||||
|
rval = http_read_stream_all(scache->fd, buf, 1);
|
||||||
|
chunkSize -= rval;
|
||||||
|
if(rval)
|
||||||
|
{
|
||||||
|
char ch = buf[0];
|
||||||
|
if(ch > 0)
|
||||||
|
{
|
||||||
|
int len = (ch * 16);
|
||||||
|
memset(buf,0, meta_interval);
|
||||||
|
rval = http_read_stream_all(scache->fd, buf,len );
|
||||||
|
chunkSize -= rval;
|
||||||
|
ShoutCAST_ParseMetaData(buf, scache->filter_arg->state);
|
||||||
|
if(scache->filter_arg->state->cb)
|
||||||
|
scache->filter_arg->state->cb(scache->filter_arg->state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while(!scache->closed);
|
while(!scache->closed);
|
||||||
|
@@ -112,6 +112,8 @@ typedef struct
|
|||||||
int state; /* CONNECTING, BUFFERING, RUNNING */
|
int state; /* CONNECTING, BUFFERING, RUNNING */
|
||||||
int bitrate;
|
int bitrate;
|
||||||
int buffered; /* "waterlevel" in the cache; 0 ... 65535 */
|
int buffered; /* "waterlevel" in the cache; 0 ... 65535 */
|
||||||
|
int chunksize;
|
||||||
|
int meta_interval;
|
||||||
char station_url[1024]; /*station url */
|
char station_url[1024]; /*station url */
|
||||||
char station[1024]; /* station name */
|
char station[1024]; /* station name */
|
||||||
char genre[4096]; /* station genre */
|
char genre[4096]; /* station genre */
|
||||||
|
Reference in New Issue
Block a user