From 375521caaaf04505e7c5673b40c222870a62394e Mon Sep 17 00:00:00 2001 From: Ron Pedde Date: Tue, 2 Dec 2003 05:28:01 +0000 Subject: [PATCH] Initial playlist support --- src/daap.c | 70 +++++++++--- src/daap.h | 2 +- src/db-memory.c | 299 +++++++++++++++++++++++++++++++++++++++++++++++- src/db-memory.h | 15 +++ 4 files changed, 365 insertions(+), 21 deletions(-) diff --git a/src/daap.c b/src/daap.c index b91717f3..d76fd6c4 100644 --- a/src/daap.c +++ b/src/daap.c @@ -370,6 +370,8 @@ DAAP_BLOCK *daap_response_playlists(char *name) { DAAP_BLOCK *mlcl; DAAP_BLOCK *mlit; int g=1; + int playlistid; + ENUMHANDLE henum; DPRINTF(ERR_DEBUG,"Preparing to send playlists\n"); @@ -377,8 +379,8 @@ DAAP_BLOCK *daap_response_playlists(char *name) { if(root) { g = (int)daap_add_int(root,"mstt",200); g = g && daap_add_char(root,"muty",0); - g = g && daap_add_int(root,"mtco",1); - g = g && daap_add_int(root,"mrco",1); + g = g && daap_add_int(root,"mtco",1 + db_get_playlist_count()); + g = g && daap_add_int(root,"mrco",1 + db_get_playlist_count()); mlcl=daap_add_empty(root,"mlcl"); if(mlcl) { mlit=daap_add_empty(mlcl,"mlit"); @@ -388,10 +390,28 @@ DAAP_BLOCK *daap_response_playlists(char *name) { g = g && daap_add_string(mlit,"minm",name); g = g && daap_add_int(mlit,"mimc",db_get_song_count()); } + + g = g && mlit; + + /* add the rest of the playlists */ + henum=db_playlist_enum_begin(); + while(henum) { + playlistid=db_playlist_enum(&henum); + mlit=daap_add_empty(mlcl,"mlit"); + if(mlit) { + g = g && daap_add_int(mlit,"miid",playlistid); + g = g && daap_add_long(mlit,"mper",0,playlistid); + g = g && daap_add_string(mlit,"minm",db_get_playlist_name(playlistid)); + g = g && daap_add_int(mlit,"mimc",db_get_playlist_entry_count(playlistid)); + } + g = g && mlit; + } + db_playlist_enum_end(); } + } - g = g && mlcl && mlit; + g = g && mlcl; if(!g) { DPRINTF(ERR_INFO,"Memory problem. Bailing\n"); @@ -426,11 +446,11 @@ DAAP_BLOCK *daap_response_dbinfo(char *name) { if(mlcl) { mlit=daap_add_empty(mlcl,"mlit"); if(mlit) { - g = g && daap_add_int(mlit,"miid",0x20); + g = g && daap_add_int(mlit,"miid",1); g = g && daap_add_long(mlit,"mper",0,1); g = g && daap_add_string(mlit,"minm",name); g = g && daap_add_int(mlit,"mimc",db_get_song_count()); /* songs */ - g = g && daap_add_int(mlit,"mctc",0x1); /* playlists */ + g = g && daap_add_int(mlit,"mctc",1 + db_get_playlist_count()); /* playlists */ } } } @@ -491,17 +511,23 @@ DAAP_BLOCK *daap_response_server_info(char *name) { * * given a playlist number, return the items on the playlist */ -DAAP_BLOCK *daap_response_playlist_items(int playlist) { +DAAP_BLOCK *daap_response_playlist_items(unsigned int playlist) { DAAP_BLOCK *root; DAAP_BLOCK *mlcl; DAAP_BLOCK *mlit; ENUMHANDLE henum; MP3FILE *current; + int itemid; int g=1; DPRINTF(ERR_DEBUG,"Preparing to send playlist items for pl #%d\n",playlist); - henum=db_enum_begin(); + if(playlist == 1) { + henum=db_enum_begin(); + } else { + henum=db_playlist_items_enum_begin(playlist); + } + if(!henum) return NULL; @@ -515,18 +541,32 @@ DAAP_BLOCK *daap_response_playlist_items(int playlist) { mlcl=daap_add_empty(root,"mlcl"); if(mlcl) { - while(current=db_enum(&henum)) { - mlit=daap_add_empty(mlcl,"mlit"); - if(mlit) { - g = g && daap_add_char(mlit,"mikd",2); - g = g && daap_add_int(mlit,"miid",current->id); - g = g && daap_add_int(mlit,"mcti",0x1); /* built-in container */ - } else g=0; + if(playlist == 1) { + while(current=db_enum(&henum)) { + mlit=daap_add_empty(mlcl,"mlit"); + if(mlit) { + g = g && daap_add_char(mlit,"mikd",2); + g = g && daap_add_int(mlit,"miid",current->id); + g = g && daap_add_int(mlit,"mcti",playlist); + } else g=0; + } + } else { /* other playlist */ + while((itemid=db_playlist_items_enum(&henum)) != -1) { + mlit=daap_add_empty(mlcl,"mlit"); + if(mlit) { + g = g && daap_add_char(mlit,"mikd",2); + g = g && daap_add_int(mlit,"miid",itemid); + g = g && daap_add_int(mlit,"mcti",playlist); + } else g = 0; + } } } else g=0; } - db_enum_end(); + if(playlist == 1) + db_enum_end(); + else + db_playlist_items_enum_end(); if(!g) { daap_free(root); diff --git a/src/daap.h b/src/daap.h index 1566cc33..713e755d 100644 --- a/src/daap.h +++ b/src/daap.h @@ -30,7 +30,7 @@ DAAP_BLOCK *daap_response_update(int fd, int clientver); DAAP_BLOCK *daap_response_songlist(void); DAAP_BLOCK *daap_response_playlists(char *name); DAAP_BLOCK *daap_response_dbinfo(char *name); -DAAP_BLOCK *daap_response_playlist_items(int playlist); +DAAP_BLOCK *daap_response_playlist_items(unsigned int playlist); #endif /* _DAAP_H_ */ diff --git a/src/db-memory.c b/src/db-memory.c index e0abc4a1..b3d07af8 100644 --- a/src/db-memory.c +++ b/src/db-memory.c @@ -38,16 +38,30 @@ typedef struct tag_mp3record { struct tag_mp3record *next; } MP3RECORD; +typedef struct tag_playlistentry { + unsigned int id; + struct tag_playlistentry *next; +} DB_PLAYLISTENTRY; + +typedef struct tag_playlist { + unsigned int id; + int songs; + char *name; + struct tag_playlistentry *nodes; + struct tag_playlist *next; +} DB_PLAYLIST; + #define MAYBEFREE(a) { if((a)) free((a)); }; /* * Globals */ MP3RECORD db_root; +DB_PLAYLIST db_playlists; int db_version_no; int db_update_mode=0; int db_song_count; -int db_song_id; +int db_playlist_count=0; pthread_rwlock_t db_rwlock; /* OSX doesn't have PTHREAD_RWLOCK_INITIALIZER */ pthread_once_t db_initlock=PTHREAD_ONCE_INIT; /* @@ -61,11 +75,26 @@ int db_init(char *parameters); int db_deinit(void); int db_version(void); int db_add(MP3FILE *mp3file); +int db_add_playlist(unsigned int playlistid, char *name); +int db_add_playlist_song(unsigned int playlistid, unsigned int itemid); MP3RECORD *db_enum_begin(void); MP3FILE *db_enum(MP3RECORD **current); int db_enum_end(void); + +DB_PLAYLIST *db_playlist_enum_begin(void); +int db_playlist_enum(DB_PLAYLIST **current); +int db_playlist_enum_end(void); + +DB_PLAYLISTENTRY *db_playlist_items_enum_begin(int playlistid); +int db_playlist_items_enum(DB_PLAYLISTENTRY **current); +int db_playlist_items_enum_end(void); + int db_get_song_count(void); +int db_get_playlist_count(void); +int db_get_playlist_entry_count(int playlistid); +char *db_get_playlist_name(int playlistid); + MP3FILE *db_find(int id); void db_freerecord(MP3RECORD *mp3record); @@ -90,8 +119,7 @@ int db_init(char *parameters) { db_root.next=NULL; db_version_no=1; db_song_count=0; - db_song_id=1; - + db_playlists.next=NULL; return pthread_once(&db_initlock,db_init_once); } @@ -152,6 +180,103 @@ int db_is_empty(void) { return !db_root.next; } + +/* + * db_add_playlist + * + * Add a new playlist + */ +int db_add_playlist(unsigned int playlistid, char *name) { + int err; + DB_PLAYLIST *pnew; + + pnew=(DB_PLAYLIST*)malloc(sizeof(DB_PLAYLIST)); + if(!pnew) + return -1; + + pnew->name=strdup(name); + pnew->id=playlistid; + pnew->nodes=NULL; + pnew->songs=0; + + if(!pnew->name) { + free(pnew); + return -1; + } + + DPRINTF(ERR_DEBUG,"Adding new playlist %s\n",name); + + if(err=pthread_rwlock_wrlock(&db_rwlock)) { + DPRINTF(ERR_WARN,"cannot lock wrlock in db_add\n"); + free(pnew->name); + free(pnew); + errno=err; + return -1; + } + + db_playlist_count++; + pnew->next=db_playlists.next; + db_playlists.next=pnew; + + if(!db_update_mode) { + db_version_no++; + } + + pthread_rwlock_unlock(&db_rwlock); + DPRINTF(ERR_DEBUG,"Added playlist\n"); + return 0; +} + +/* + * db_add_playlist_song + * + * Add a song to a particular playlist + */ +int db_add_playlist_song(unsigned int playlistid, unsigned int itemid) { + DB_PLAYLIST *current; + DB_PLAYLISTENTRY *pnew; + int err; + + pnew=(DB_PLAYLISTENTRY*)malloc(sizeof(DB_PLAYLISTENTRY)); + if(!pnew) + return -1; + + pnew->id=itemid; + pnew->next=NULL; + + DPRINTF(ERR_DEBUG,"Adding new playlist item\n"); + + if(err=pthread_rwlock_wrlock(&db_rwlock)) { + DPRINTF(ERR_WARN,"cannot lock wrlock in db_add\n"); + free(pnew); + errno=err; + return -1; + } + + current=db_playlists.next; + while(current && (current->id != playlistid)) + current=current->next; + + if(!current) { + DPRINTF(ERR_WARN,"Could not find playlist attempting to add to\n"); + pthread_rwlock_unlock(&db_rwlock); + free(pnew); + return -1; + } + + current->songs++; + pnew->next = current->nodes; + current->nodes = pnew; + + if(!db_update_mode) { + db_version_no++; + } + + pthread_rwlock_unlock(&db_rwlock); + DPRINTF(ERR_DEBUG,"Added playlist item\n"); + return 0; +} + /* * db_add * @@ -207,7 +332,6 @@ int db_add(MP3FILE *mp3file) { return -1; } - pnew->mp3file.id=db_song_id++; pnew->next=db_root.next; db_root.next=pnew; @@ -250,7 +374,7 @@ void db_freerecord(MP3RECORD *mp3record) { MP3RECORD *db_enum_begin(void) { int err; - if(err=pthread_rwlock_wrlock(&db_rwlock)) { + if(err=pthread_rwlock_rdlock(&db_rwlock)) { log_err(0,"Cannot lock rwlock\n"); errno=err; return NULL; @@ -259,6 +383,49 @@ MP3RECORD *db_enum_begin(void) { return db_root.next; } +/* + * db_playlist_enum_begin + * + * Start enumerating playlists + */ +DB_PLAYLIST *db_playlist_enum_begin(void) { + int err; + + if(err=pthread_rwlock_rdlock(&db_rwlock)) { + log_err(0,"Cannot lock rwlock\n"); + errno=err; + return NULL; + } + + return db_playlists.next; +} + +/* + * db_playlist_items_enum_begin + * + * Start enumerating playlist items + */ +DB_PLAYLISTENTRY *db_playlist_items_enum_begin(int playlistid) { + DB_PLAYLIST *current; + DB_PLAYLISTENTRY *retval; + int err; + + if(err=pthread_rwlock_rdlock(&db_rwlock)) { + log_err(0,"Cannot lock rwlock\n"); + errno=err; + return NULL; + } + + current=db_playlists.next; + while(current && (current->id != playlistid)) + current++; + + if(!current) + return NULL; + + return current->nodes; +} + /* * db_enum @@ -276,6 +443,39 @@ MP3FILE *db_enum(MP3RECORD **current) { return NULL; } +/* + * db_playlist_enum + * + * walk to the next entry + */ +int db_playlist_enum(DB_PLAYLIST **current) { + int retval; + + if(*current) { + retval = (*current)->id; + *current=(*current)->next; + return retval; + } + return -1; +} + +/* + * db_playlist_items_enum + * + * walk to the next entry + */ +int db_playlist_items_enum(DB_PLAYLISTENTRY **current) { + int retval; + + if(*current) { + retval = (*current)->id; + *current=(*current)->next; + return retval; + } + + return -1; +} + /* * db_enum_end * @@ -285,6 +485,24 @@ int db_enum_end(void) { return pthread_rwlock_unlock(&db_rwlock); } +/* + * db_playlist_enum_end + * + * quit walking the database + */ +int db_playlist_enum_end(void) { + return pthread_rwlock_unlock(&db_rwlock); +} + +/* + * db_playlist_items_enum_end + * + * Quit walking the database + */ +int db_playlist_items_enum_end(void) { + return pthread_rwlock_unlock(&db_rwlock); +} + /* * db_find * @@ -302,6 +520,15 @@ MP3FILE *db_find(int id) { return ¤t->mp3file; } +/* + * db_get_playlist_count + * + * return the number of playlists + */ +int db_get_playlist_count(void) { + return db_playlist_count; +} + /* * db_get_song_count * @@ -311,3 +538,65 @@ MP3FILE *db_find(int id) { int db_get_song_count(void) { return db_song_count; } + +/* + * db_get_playlist_entry_count + * + * return the number of songs in a particular playlist + */ +int db_get_playlist_entry_count(int playlistid) { + int count; + DB_PLAYLIST *current; + int err; + + if(err=pthread_rwlock_rdlock(&db_rwlock)) { + log_err(0,"Cannot lock rwlock\n"); + errno=err; + return -1; + } + + current=db_playlists.next; + while(current && (current->id != playlistid)) + current=current->next; + + if(!current) { + count = -1; + } else { + count = current->songs; + } + + pthread_rwlock_unlock(&db_rwlock); + return count; +} + +/* + * db_get_playlist_name + * + * return the name of a playlist + * + * FIXME: Small race here + */ +char *db_get_playlist_name(int playlistid) { + char *name; + DB_PLAYLIST *current; + int err; + + if(err=pthread_rwlock_rdlock(&db_rwlock)) { + log_err(0,"Cannot lock rwlock\n"); + errno=err; + return NULL; + } + + current=db_playlists.next; + while(current && (current->id != playlistid)) + current=current->next; + + if(!current) { + name = NULL; + } else { + name = current->name; + } + + pthread_rwlock_unlock(&db_rwlock); + return name; +} diff --git a/src/db-memory.h b/src/db-memory.h index 71472503..4aca5b65 100644 --- a/src/db-memory.h +++ b/src/db-memory.h @@ -33,11 +33,26 @@ extern int db_init(char *parameters); extern int db_deinit(void); extern int db_version(void); extern int db_add(MP3FILE *mp3file); +extern int db_add_playlist(unsigned int playlistid, char *name); +extern int db_add_playlist_song(unsigned int playlistid, unsigned int itemid); + extern ENUMHANDLE db_enum_begin(void); extern MP3FILE *db_enum(ENUMHANDLE *current); extern int db_enum_end(void); extern MP3FILE *db_find(int id); extern int db_get_song_count(void); +extern int db_get_playlist_count(void); +extern int db_get_playlist_entry_count(int playlistid); + +extern ENUMHANDLE db_playlist_enum_begin(void); +extern int db_playlist_enum(ENUMHANDLE *current); +extern int db_playlist_enum_end(void); + +extern ENUMHANDLE db_playlist_items_enum_begin(int playlistid); +extern int db_playlist_items_enum(ENUMHANDLE *current); +extern int db_playlist_items_enum_end(void); + +extern char *db_get_playlist_name(int playlistid); #endif /* _DB_MEMORY_H_ */