Now serving...

This commit is contained in:
Ron Pedde 2003-11-12 02:59:45 +00:00
parent 20e564ed18
commit c38085474e
7 changed files with 241 additions and 170 deletions

View File

@ -123,10 +123,6 @@ DAAP_ITEMS taglist[] = {
};
/* Forwards */
DAAP_BLOCK *daap_response_songlist(void);
DAAP_BLOCK *daap_response_playlists(void);
DAAP_BLOCK *daap_response_dbinfo(void);
DAAP_BLOCK *daap_response_playlist_items(int playlist);
int daap_add_mdcl(DAAP_BLOCK *root, char *tag, char *name, short int number) {
DAAP_BLOCK *mdcl;
@ -242,7 +238,8 @@ DAAP_BLOCK *daap_response_songlist(void) {
g = g && daap_add_string(mlit,"asar",current->artist);
// g = g && daap_add_short(mlit,"asbt",0); /* bpm */
// g = g && daap_add_short(mlit,"asbr",128); /* bitrate!! */
if(current->bitrate)
g = g && daap_add_short(mlit,"asbr",current->bitrate); /* bitrate!! */
if(current->comment)
g = g && daap_add_string(mlit,"ascm",current->comment); /* comment */
@ -254,7 +251,6 @@ DAAP_BLOCK *daap_response_songlist(void) {
// g = g && daap_add_short(mlit,"asdc",0); /* # of discs */
// g = g && daap_add_short(mlit,"asdn",0); /* disc number */
// g = g && daap_add_char(mlit,"asdk",0); /* song datakind? */
// g = g && daap_add_string(mlit,"asfm","mp3"); /* song format */
// aseq - null string!
if(current->genre)
@ -262,6 +258,8 @@ DAAP_BLOCK *daap_response_songlist(void) {
g = g && daap_add_int(mlit,"miid",current->id); /* id */
/* these quite go hand in hand */
g = g && daap_add_string(mlit,"asfm","mp3"); /* song format */
g = g && daap_add_string(mlit,"asdt","MPEG audio file"); /* descr */
if(current->title)
@ -272,11 +270,18 @@ DAAP_BLOCK *daap_response_songlist(void) {
// mper (long)
// g = g && daap_add_char(mlit,"asdb",0); /* disabled */
// g = g && daap_add_char(mlit,"asrv",0); /* rel vol */
// g = g && daap_add_int(mlit,"assr",44100); /* sample rate */
// g = g && daap_add_int(mlit,"assz",1024); /* FIXME: Song size! */
// g = g && daap_add_int(mlit,"asst",0); /* song start time? */
// g = g && daap_add_int(mlit,"assp",0); /* songstoptime */
// g = g && daap_add_int(mlit,"astm",3600); /* song time */
if(current->samplerate)
g = g && daap_add_int(mlit,"assr",current->samplerate); /* samp rate */
if(current->file_size)
g = g && daap_add_int(mlit,"assz",current->file_size); /* Size! */
g = g && daap_add_int(mlit,"asst",0); /* song start time? */
g = g && daap_add_int(mlit,"assp",0); /* songstoptime */
if(current->song_length)
g = g && daap_add_int(mlit,"astm",current->song_length*1000); /* song time */
// g = g && daap_add_short(mlit,"astc",0); /* track count */
// g = g && daap_add_short(mlit,"astn",0); /* track number */
// g = g && daap_add_char(mlit,"asur",3); /* rating */
@ -326,99 +331,6 @@ DAAP_BLOCK *daap_response_update(int clientver) {
return root;
}
/*
* daap_response_databases
*
* handle the daap block for the /databases URI
*/
DAAP_BLOCK *daap_response_databases(char *path) {
char *uri;
int db_index;
int playlist_index;
char *first, *last;
if(strcmp(path,"/databases")==0) {
return daap_response_dbinfo();
}
uri = strdup(path);
first=(char*)&uri[11];
last=first;
while((*last) && (*last != '/')) {
last++;
}
if(*last != '/') {
return NULL;
}
*last='\0';
db_index=atoi(first);
/* now we have the db id. Next, we have to figure out
* if it's a container request or a
* items request
*
* note we generally don't care about the DB index, since we only
* support 1 db.
*/
/* the /databases/ uri will either be
*
* /databases, which returns an AVDB,
* /databases/id/items, which returns items in a db
* /databases/id/containers, which returns a container
* /databases/id/containers/id/items, which returns playlist elements
* /databases/id/items/id.mp3, to spool an mp3
*/
last++;
if(strncasecmp(last,"items/",6)==0) {
/* streaming */
free(uri);
return NULL;
}
if(strncasecmp(last,"items",5)==0) {
/* songlist */
free(uri);
return daap_response_songlist();
}
if(strncasecmp(last,"containers/",11)==0) {
/* playlist elements */
first=last + 11;
last=first;
while((*last) && (*last != '/')) {
last++;
}
if(*last != '/') {
return NULL;
}
*last='\0';
playlist_index=atoi(first);
free(uri);
return daap_response_playlist_items(playlist_index);
}
if(strncasecmp(last,"containers",10)==0) {
/* list of playlists */
free(uri);
return daap_response_playlists();
return NULL;
}
free(uri);
return NULL;
}
/*
* daap_response_playlists
@ -587,3 +499,5 @@ DAAP_BLOCK *daap_response_playlist_items(int playlist) {
return root;
}

View File

@ -27,7 +27,10 @@ DAAP_BLOCK *daap_response_server_info(void);
DAAP_BLOCK *daap_response_content_codes(void);
DAAP_BLOCK *daap_response_login(void);
DAAP_BLOCK *daap_response_update(int clientver);
DAAP_BLOCK *daap_response_databases(char *path);
DAAP_BLOCK *daap_response_songlist(void);
DAAP_BLOCK *daap_response_playlists(void);
DAAP_BLOCK *daap_response_dbinfo(void);
DAAP_BLOCK *daap_response_playlist_items(int playlist);
#endif /* _DAAP_H_ */

View File

@ -52,7 +52,6 @@
*/
CONFIG config;
/*
* daap_handler
*
@ -65,8 +64,20 @@ void daap_handler(WS_CONNINFO *pwsc) {
int compress=0;
int clientrev;
/* for the /databases URI */
char *uri;
int db_index;
int playlist_index;
int item;
char *first, *last;
int streaming=0;
MP3FILE *pmp3;
int file_fd;
close=pwsc->close;
pwsc->close=1;
pwsc->close=1; /* in case we have any errors */
root=NULL;
ws_addresponseheader(pwsc,"Accept-Ranges","bytes");
ws_addresponseheader(pwsc,"DAAP-Server","iTunes/4.1 (Mac OS X)");
@ -86,28 +97,81 @@ void daap_handler(WS_CONNINFO *pwsc) {
clientrev=atoi(ws_getvar(pwsc,"delta"));
}
root=daap_response_update(clientrev);
} else if (!strcasecmp(pwsc->uri,"/databases")) {
root=daap_response_databases(pwsc->uri);
} else if (!strcasecmp(pwsc->uri,"/logout")) {
ws_returnerror(pwsc,204,"Logout Successful");
return;
} else if (!strncasecmp(pwsc->uri,"/databases/",11)) {
root=daap_response_databases(pwsc->uri);
} else {
DPRINTF(ERR_WARN,"Bad handler! Can't find uri handler for %s\n",
pwsc->uri);
return;
} else if(strcmp(pwsc->uri,"/databases")==0) {
root=daap_response_dbinfo();
} else if(strncmp(pwsc->uri,"/databases/",11) == 0) {
/* the /databases/ uri will either be:
*
* /databases/id/items, which returns items in a db
* /databases/id/containers, which returns a container
* /databases/id/containers/id/items, which returns playlist elements
* /databases/id/items/id.mp3, to spool an mp3
*/
uri = strdup(pwsc->uri);
first=(char*)&uri[11];
last=first;
while((*last) && (*last != '/')) {
last++;
}
if(!root) {
if(*last) {
*last='\0';
db_index=atoi(first);
last++;
if(strncasecmp(last,"items/",6)==0) {
/* streaming */
first=last+6;
while((*last) && (*last != '.'))
last++;
if(*last == '.') {
*last='\0';
item=atoi(first);
streaming=1;
}
free(uri);
} else if (strncasecmp(last,"items",5)==0) {
/* songlist */
free(uri);
root=daap_response_songlist();
} else if (strncasecmp(last,"containers/",11)==0) {
/* playlist elements */
first=last + 11;
last=first;
while((*last) && (*last != '/')) {
last++;
}
if(*last) {
*last='\0';
playlist_index=atoi(first);
root=daap_response_playlist_items(playlist_index);
}
free(uri);
} else if (strncasecmp(last,"containers",10)==0) {
/* list of playlists */
free(uri);
root=daap_response_playlists();
}
}
}
if((!root)&&(!streaming)) {
ws_returnerror(pwsc,400,"Invalid Request");
return;
}
pwsc->close=close;
if(!streaming) {
ws_addresponseheader(pwsc,"Content-Length","%d",root->reported_size + 8);
ws_writefd(pwsc,"HTTP/1.1 200 OK\r\n");
ws_emitheaders(pwsc);
@ -120,6 +184,31 @@ void daap_handler(WS_CONNINFO *pwsc) {
daap_serialize(root,pwsc->fd,0);
daap_free(root);
} else {
/* stream out the song */
pwsc->close=1;
pmp3=db_find(item);
if(!pmp3) {
ws_returnerror(pwsc,404,"File Not Found");
} else {
/* got the file, let's open and serve it */
file_fd=r_open2(pmp3->path,O_RDONLY);
if(file_fd == -1) {
pwsc->error=errno;
DPRINTF(ERR_WARN,"Thread %d: Error opening %s: %s\n",
pwsc->threadno,pmp3->path,strerror(errno));
ws_returnerror(pwsc,404,"Not found");
} else {
ws_writefd(pwsc,"HTTP/1.1 200 OK\r\n");
ws_addresponseheader(pwsc,"Connection","Close");
ws_emitheaders(pwsc);
copyfile(file_fd,pwsc->fd);
r_close(file_fd);
}
}
}
return;
}
@ -168,7 +257,7 @@ void config_handler(WS_CONNINFO *pwsc) {
return;
}
file_fd=open(resolved_path,O_RDONLY);
file_fd=r_open2(resolved_path,O_RDONLY);
if(file_fd == -1) {
pwsc->error=errno;
DPRINTF(ERR_WARN,"Thread %d: Error opening %s: %s\n",
@ -230,7 +319,7 @@ void config_handler(WS_CONNINFO *pwsc) {
}
}
close(file_fd);
r_close(file_fd);
DPRINTF(ERR_DEBUG,"Thread %d: Served successfully\n",pwsc->threadno);
return;
}

View File

@ -1,40 +0,0 @@
#include <stdlib.h>
#include <string.h>
int makeargv(const char *s, const char *delimiters, char ***argvp) {
int i;
int numtokens;
const char *snew;
char *t;
if ((s == NULL) || (delimiters == NULL) || (argvp == NULL))
return -1;
*argvp = NULL;
snew = s + strspn(s, delimiters); /* snew is real start of string */
if ((t = malloc(strlen(snew) + 1)) == NULL)
return -1;
/* count the number of tokens in s */
strcpy(t, snew);
numtokens = 0;
if (strtok(t, delimiters) != NULL)
for (numtokens = 1; strtok(NULL, delimiters) != NULL; numtokens++) ;
/* create argument array for ptrs to the tokens */
if ((*argvp = malloc((numtokens + 1)*sizeof(char *))) == NULL) {
free(t);
return -1;
}
/* insert pointers to tokens into the argument array */
if (numtokens == 0)
free(t);
else {
strcpy(t, snew);
**argvp = strtok(t, delimiters);
for (i = 1; i < numtokens; i++)
*((*argvp) + i) = strtok(NULL, delimiters);
}
/* put in the final NULL pointer and return */
*((*argvp) + numtokens) = NULL;
return numtokens;
}

View File

@ -36,13 +36,30 @@
/*
* Typedefs
*/
typedef struct tag_scan_id3header {
unsigned char id[3];
unsigned char version[2];
unsigned char flags;
unsigned char size[4];
} SCAN_ID3HEADER;
#define MAYBEFREE(a) { if((a)) free((a)); };
/*
* Globals
*/
int scan_br_table[] = {
0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0
};
/*
* Forwards
*/
int scan_foreground(char *path);
int scan_gettags(char *file, MP3FILE *pmp3);
int scan_getfileinfo(char *file, MP3FILE *pmp3);
int scan_freetags(MP3FILE *pmp3);
/*
@ -133,6 +150,7 @@ int scan_foreground(char *path) {
/* Do the tag lookup here */
scan_gettags(mp3file.path,&mp3file);
scan_getfileinfo(mp3file.path,&mp3file);
db_add(&mp3file);
@ -230,3 +248,84 @@ int scan_freetags(MP3FILE *pmp3) {
return 0;
}
/*
* scan_getfileinfo
*
* Get information from the file headers itself -- like
* song length, bit rate, etc.
*/
int scan_getfileinfo(char *file, MP3FILE *pmp3) {
FILE *infile;
SCAN_ID3HEADER *pid3;
unsigned int size=0;
fpos_t fp_size=0;
fpos_t file_size;
unsigned char buffer[256];
int time_seconds;
int ver=0;
int layer=0;
int bitrate=0;
int samplerate=0;
if(!(infile=fopen(file,"rb"))) {
DPRINTF(ERR_WARN,"Could not open %s for reading\n",file);
return -1;
}
fread(buffer,1,sizeof(buffer),infile);
pid3=(SCAN_ID3HEADER*)buffer;
if(strncmp(pid3->id,"ID3",3)==0) {
/* found an ID3 header... */
size = (pid3->size[0] << 21 | pid3->size[1] << 14 |
pid3->size[2] << 7 | pid3->size[3]);
fp_size=size + sizeof(SCAN_ID3HEADER);
}
fseek(infile,0,SEEK_END);
file_size=ftell(infile);
file_size -= fp_size;
fsetpos(infile,&fp_size);
fread(buffer,1,sizeof(buffer),infile);
if((buffer[0] == 0xFF)&&(buffer[1] >= 224)) {
printf("Found sync frame\n");
ver=(buffer[1] & 0x18) >> 3;
layer=(buffer[1] & 0x6) >> 1;
if((ver==3) && (layer==1)) { /* MPEG1, Layer 3 */
bitrate=(buffer[2] & 0xF0) >> 4;
bitrate=scan_br_table[bitrate];
samplerate=(buffer[2] & 0x0C) >> 2;
switch(samplerate) {
case 0:
samplerate=44100;
break;
case 1:
samplerate=48000;
break;
case 2:
samplerate=32000;
break;
}
pmp3->bitrate=bitrate;
pmp3->samplerate=samplerate;
}
/* guesstimate the file length */
time_seconds = ((int)(file_size * 8)) / (bitrate * 1024);
pmp3->song_length=time_seconds;
pmp3->file_size=file_size;
} else {
/* should really scan forward to next sync frame */
fclose(infile);
return -1;
}
fclose(infile);
return 0;
}

View File

@ -30,6 +30,12 @@ typedef struct tag_mp3file {
char *album;
char *genre;
char *comment;
int bitrate;
int samplerate;
int song_length;
int file_size;
int got_id3;
int id;
} MP3FILE;

View File

@ -1,4 +1,4 @@
web_root ../admin-root
port 3689
admin_password secret
mp3_dir mp3
mp3_dir mp3/Type O Negative