diff options
author | William Wilgus <wilgus.william@gmail.com> | 2022-12-03 09:00:56 -0500 |
---|---|---|
committer | William Wilgus <me.theuser@yahoo.com> | 2022-12-06 23:40:02 -0500 |
commit | 152a2389471bb2aaf0c25acaa2f610feb1b3113c (patch) | |
tree | bdfd847734b6696d0e13505eb35a8af2e056abe6 | |
parent | a89f279fd4dfb0ecbb61d39b3e11122ebb99d94c (diff) | |
download | rockbox-152a238947.tar.gz rockbox-152a238947.zip |
playlist add mutex to public functions
mutexes are in just trying to refactor the rest and make it a smaller
and more robust system
--Done
Change-Id: If64807c3e0ee1966f7593795f26f1f538caf831b
-rw-r--r-- | apps/playlist.c | 765 | ||||
-rw-r--r-- | apps/playlist.h | 6 |
2 files changed, 431 insertions, 340 deletions
diff --git a/apps/playlist.c b/apps/playlist.c index abfefa7e8d..80685f8655 100644 --- a/apps/playlist.c +++ b/apps/playlist.c @@ -175,33 +175,65 @@ static struct playlist_info current_playlist; static struct event_queue playlist_queue SHAREDBSS_ATTR; static long playlist_stack[(DEFAULT_STACK_SIZE + 0x800)/sizeof(long)]; -static const char thread_playlist_name[] = "playlist cachectrl"; +static const char dc_thread_playlist_name[] = "playlist cachectrl"; + +static void dc_copy_filerefs(struct dircache_fileref*, + const struct dircache_fileref*, int); #endif -static struct mutex current_playlist_mutex SHAREDBSS_ATTR; -static struct mutex created_playlist_mutex SHAREDBSS_ATTR; +#if defined(PLAYLIST_DEBUG_MUTEX) +#define playlist_mutex_lock(m) {splashf(0, "%s lock", __func__); \ + mutex_lock(m);} +#define playlist_mutex_unlock(m) {splashf(0, "%s unlock", __func__); \ + mutex_unlock(m);} +#else +static void playlist_mutex_lock(struct mutex *m) { mutex_lock(m); } +static void playlist_mutex_unlock(struct mutex *m) { mutex_unlock(m); } +#endif -#ifdef HAVE_DIRCACHE -static void copy_filerefs(struct dircache_fileref *dcfto, - const struct dircache_fileref *dcffrom, - int count) +#if defined(PLAYLIST_DEBUG_ACCESS_ERRORS) +#define notify_access_error() (splashf(HZ*2, "%s %s", \ + __func__, ID2P(LANG_PLAYLIST_ACCESS_ERROR))) +#define notify_control_access_error() (splashf(HZ*2, "%s %s", \ + __func__, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR))) +#else +static void notify_access_error(void) { + splash(HZ*2, ID2P(LANG_PLAYLIST_ACCESS_ERROR)); +} +static void notify_control_access_error(void) { + splash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); +} +#endif + +/* + * Display buffer full message + */ +static void notify_buffer_full(void) { - if (!dcfto) - return; + splash(HZ*2, ID2P(LANG_PLAYLIST_BUFFER_FULL)); +} - if (dcffrom) - memmove(dcfto, dcffrom, count * sizeof (*dcfto)); - else +static void dc_load_playlist_pointers(void) +{ +#ifdef HAVE_DIRCACHE + queue_post(&playlist_queue, PLAYLIST_LOAD_POINTERS, 0); +#endif +/* No-Op for non dircache targets */ +} + +static void close_playlist_control_file(struct playlist_info *playlist) +{ + playlist_mutex_lock(&(playlist->mutex)); + if (playlist->control_fd >= 0) { - /* just initialize the destination */ - for (int i = 0; i < count; i++, dcfto++) - dircache_fileref_init(dcfto); + close(playlist->control_fd); + playlist->control_fd = -1; } + playlist_mutex_unlock(&(playlist->mutex)); } -#endif /* HAVE_DIRCACHE */ /* Check if the filename suggests M3U or M3U8 format. */ -static bool is_m3u8(const char* filename) +static bool is_m3u8_name(const char* filename) { char *dot = strrchr(filename, '.'); @@ -209,7 +241,6 @@ static bool is_m3u8(const char* filename) return (!dot || strcasecmp(dot, ".m3u") != 0); } - /* Convert a filename in an M3U playlist to UTF-8. * * buf - the filename to convert; can contain more than one line from the @@ -220,7 +251,7 @@ static bool is_m3u8(const char* filename) * * Returns the length of the converted filename. */ -static int convert_m3u(char* buf, int buf_len, int buf_max, char* temp) +static int convert_m3u_name(char* buf, int buf_len, int buf_max, char* temp) { int i = 0; char* dest; @@ -257,24 +288,21 @@ static int convert_m3u(char* buf, int buf_len, int buf_max, char* temp) /* * create control file for playlist */ -static void create_control(struct playlist_info* playlist) +static void create_control_unlocked(struct playlist_info* playlist) { playlist->control_fd = open(playlist->control_filename, O_CREAT|O_RDWR|O_TRUNC, 0666); - if (playlist->control_fd < 0) - { - if (check_rockboxdir()) - { - cond_talk_ids_fq(LANG_PLAYLIST_CONTROL_ACCESS_ERROR); - splashf(HZ*2, (unsigned char *)"%s (%d)", - str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR), - playlist->control_fd); - } - playlist->control_created = false; - } - else + + playlist->control_created = (playlist->control_fd >= 0); + + if (!playlist->control_created) { - playlist->control_created = true; + if (!check_rockboxdir()) + return; /* No RB directory exists! */ + + cond_talk_ids_fq(LANG_PLAYLIST_CONTROL_ACCESS_ERROR); + int fd = playlist->control_fd; + splashf(HZ*2, "%s (%d)", str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR), fd); } } @@ -295,20 +323,18 @@ static int rotate_index(const struct playlist_info* playlist, int index) */ static void sync_control(struct playlist_info* playlist, bool force) { -#ifdef HAVE_DIRCACHE - if (playlist->started && force) -#else - (void) force; - - if (playlist->started) +#ifndef HAVE_DIRCACHE /*non dircache targets sync every time */ + force = true; #endif + + if (playlist->started && force) { if (playlist->pending_control_sync) { - mutex_lock(playlist->control_mutex); + playlist_mutex_lock(&(playlist->mutex)); fsync(playlist->control_fd); playlist->pending_control_sync = false; - mutex_unlock(playlist->control_mutex); + playlist_mutex_unlock(&(playlist->mutex)); } } } @@ -322,15 +348,16 @@ static int flush_cached_control(struct playlist_info* playlist) int result = 0; int i; - if (!playlist->num_cached) + if (playlist->num_cached <= 0) return 0; + playlist_mutex_lock(&(playlist->mutex)); + lseek(playlist->control_fd, 0, SEEK_END); for (i=0; i<playlist->num_cached; i++) { - struct playlist_control_cache* cache = - &(playlist->control_cache[i]); + struct playlist_control_cache* cache = &(playlist->control_cache[i]); switch (cache->command) { @@ -348,8 +375,7 @@ static int flush_cached_control(struct playlist_info* playlist) /* save the position in file where name is written */ int* seek_pos = (int *)cache->data; *seek_pos = lseek(playlist->control_fd, 0, SEEK_CUR); - result = fdprintf(playlist->control_fd, "%s\n", - cache->s1); + result = fdprintf(playlist->control_fd, "%s\n", cache->s1); } break; case PLAYLIST_COMMAND_DELETE: @@ -363,7 +389,7 @@ static int flush_cached_control(struct playlist_info* playlist) result = fdprintf(playlist->control_fd, "U:%d\n", cache->i1); break; case PLAYLIST_COMMAND_RESET: - result = fdprintf(playlist->control_fd, "R\n"); + result = fdprintf(playlist->control_fd, "%s\n", "R"); break; default: break; @@ -386,6 +412,7 @@ static int flush_cached_control(struct playlist_info* playlist) splash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_UPDATE_ERROR)); } + playlist_mutex_unlock(&(playlist->mutex)); return result; } @@ -401,7 +428,7 @@ static int update_control(struct playlist_info* playlist, struct playlist_control_cache* cache; bool flush = false; - mutex_lock(playlist->control_mutex); + playlist_mutex_lock(&(playlist->mutex)); cache = &(playlist->control_cache[playlist->num_cached++]); @@ -425,15 +452,14 @@ static int update_control(struct playlist_info* playlist, break; case PLAYLIST_COMMAND_SHUFFLE: case PLAYLIST_COMMAND_UNSHUFFLE: - default: - /* only flush when needed */ + default: /* only flush when needed */ break; } if (flush || playlist->num_cached == PLAYLIST_MAX_CACHE) result = flush_cached_control(playlist); - mutex_unlock(playlist->control_mutex); + playlist_mutex_unlock(&(playlist->mutex)); return result; } @@ -441,13 +467,13 @@ static int update_control(struct playlist_info* playlist, /* * store directory and name of playlist file */ -static void update_playlist_filename(struct playlist_info* playlist, +static void update_playlist_filename_unlocked(struct playlist_info* playlist, const char *dir, const char *file) { char *sep=""; int dirlen = strlen(dir); - playlist->utf8 = is_m3u8(file); + playlist->utf8 = is_m3u8_name(file); /* If the dir does not end in trailing slash, we use a separator. Otherwise we don't. */ @@ -466,28 +492,35 @@ static void update_playlist_filename(struct playlist_info* playlist, /* * remove any files and indices associated with the playlist */ -static void empty_playlist(struct playlist_info* playlist, bool resume) +static void empty_playlist_unlocked(struct playlist_info* playlist, bool resume) { - playlist->utf8 = true; - playlist->control_created = false; - playlist->in_ram = false; if(playlist->fd >= 0) /* If there is an already open playlist, close it. */ { close(playlist->fd); } - playlist->fd = -1; if(playlist->control_fd >= 0) + { close(playlist->control_fd); - playlist->control_fd = -1; + } - playlist->num_inserted_tracks = 0; + playlist->filename[0] = '\0'; if (playlist->buffer) playlist->buffer[0] = 0; playlist->buffer_end_pos = 0; + playlist->seed = 0; + playlist->num_cached = 0; + + playlist->utf8 = true; + playlist->control_created = false; + playlist->in_ram = false; + + playlist->fd = -1; + playlist->control_fd = -1; + playlist->num_inserted_tracks = 0; playlist->index = 0; playlist->first_index = 0; @@ -499,19 +532,21 @@ static void empty_playlist(struct playlist_info* playlist, bool resume) playlist->pending_control_sync = false; playlist->shuffle_modified = false; - playlist->seed = 0; - playlist->num_cached = 0; - - playlist->filename[0] = '\0'; - if (!resume && playlist->current) { /* start with fresh playlist control file when starting new playlist */ - create_control(playlist); + create_control_unlocked(playlist); } } +/* initializes the mutex for a new playlist and sets it as empty */ +static void initalize_new_playlist(struct playlist_info* playlist, bool resume) +{ + mutex_init(&(playlist->mutex)); + empty_playlist_unlocked(playlist, resume); +} + /* * Returns absolute path of track * @@ -532,16 +567,8 @@ static void empty_playlist(struct playlist_info* playlist, bool resume) static ssize_t format_track_path(char *dest, char *src, int buf_length, const char *dir) { - size_t len = 0; - - /* Look for the end of the string */ - while (1) - { - int c = src[len]; - if (c == '\n' || c == '\r' || c == '\0') - break; - len++; - } + /* Look for the end of the string (includes NULL) */ + size_t len = strcspn(src, "\r\n");; /* Now work back killing white space */ while (len > 0) @@ -583,12 +610,13 @@ static ssize_t format_track_path(char *dest, char *src, int buf_length, * Initialize a new playlist for viewing/editing/playing. dir is the * directory where the playlist is located and file is the filename. */ -static void new_playlist(struct playlist_info* playlist, const char *dir, - const char *file) +static void new_playlist_unlocked(struct playlist_info* playlist, + const char *dir, const char *file) { const char *fileused = file; const char *dirused = dir; - empty_playlist(playlist, false); + + initalize_new_playlist(playlist, false); if (!fileused) { @@ -600,7 +628,7 @@ static void new_playlist(struct playlist_info* playlist, const char *dir, dirused = ""; /* empty playlist */ } - update_playlist_filename(playlist, dirused, fileused); + update_playlist_filename_unlocked(playlist, dirused, fileused); if (playlist->control_fd >= 0) { @@ -616,9 +644,11 @@ static void new_playlist(struct playlist_info* playlist, const char *dir, */ static int check_control(struct playlist_info* playlist) { + int ret = 0; + playlist_mutex_lock(&(playlist->mutex)); if (!playlist->control_created) { - create_control(playlist); + create_control_unlocked(playlist); if (playlist->control_fd >= 0) { @@ -636,20 +666,14 @@ static int check_control(struct playlist_info* playlist) } if (playlist->control_fd < 0) - return -1; + ret = -1; - return 0; -} + playlist_mutex_unlock(&(playlist->mutex)); - -/* - * Display buffer full message - */ -static void display_buffer_full(void) -{ - splash(HZ*2, ID2P(LANG_PLAYLIST_BUFFER_FULL)); + return ret; } + /* * Display splash message showing progress of playlist/directory insertion or * save. @@ -678,11 +702,10 @@ static void display_playlist_count(int count, const unsigned char *fmt, splashf(0, P2STR(fmt), count, str(LANG_OFF_ABORT)); } - /* * recreate the control file based on current playlist entries */ -static int recreate_control(struct playlist_info* playlist) +static int recreate_control_unlocked(struct playlist_info* playlist) { const char file_suffix[] = "_temp\0"; char temp_file[MAX_PATH + sizeof(file_suffix)]; @@ -698,8 +721,7 @@ static int recreate_control(struct playlist_info* playlist) char* file = playlist->filename+playlist->dirlen; char c = playlist->filename[playlist->dirlen-1]; - close(playlist->control_fd); - playlist->control_fd = -1; + close_playlist_control_file(playlist); snprintf(temp_file, sizeof(temp_file), "%s%s", playlist->control_filename, file_suffix); @@ -787,7 +809,6 @@ static int recreate_control(struct playlist_info* playlist) static int add_indices_to_playlist(struct playlist_info* playlist, char* buffer, size_t buflen) { - int playlist_fd; ssize_t nread; unsigned int i = 0; unsigned int count = 0; @@ -798,7 +819,7 @@ static int add_indices_to_playlist(struct playlist_info* playlist, if (!buflen) buffer = alloca((buflen = 64)); - mutex_lock(playlist->control_mutex); /* read can yield! */ + playlist_mutex_lock(&(playlist->mutex)); /* read can yield! */ if(-1 == playlist->fd) { @@ -808,26 +829,20 @@ static int add_indices_to_playlist(struct playlist_info* playlist, } if(playlist->fd < 0) + { + playlist_mutex_unlock(&(playlist->mutex)); return -1; /* failure */ - + } + /* seek to the beginning of the file get_filename leaves it elsewhere */ i = lseek(playlist->fd, playlist->utf8 ? BOM_UTF_8_SIZE : 0, SEEK_SET); - playlist_fd = playlist->fd; - playlist->fd = -2; /* DEBUGGING Remove me! */ - splash(0, ID2P(LANG_WAIT)); store_index = true; - /* invalidate playlist in case we yield */ - int amount = playlist->amount; - playlist->amount = -1; - int max_playlist_size = playlist->max_playlist_size; - playlist->max_playlist_size = 0; - while(1) { - nread = read(playlist_fd, buffer, buflen); + nread = read(playlist->fd, buffer, buflen); /* Terminate on EOF */ if(nread <= 0) break; @@ -847,18 +862,18 @@ static int add_indices_to_playlist(struct playlist_info* playlist, if(*p != '#') { - if ( amount >= max_playlist_size ) { - display_buffer_full(); + if ( playlist->amount >= playlist->max_playlist_size ) { + notify_buffer_full(); result = -1; goto exit; } /* Store a new entry */ - playlist->indices[ amount ] = i+count; + playlist->indices[ playlist->amount ] = i+count; #ifdef HAVE_DIRCACHE - copy_filerefs(&playlist->dcfrefs[amount], NULL, 1); + dc_copy_filerefs(&playlist->dcfrefs[playlist->amount], NULL, 1); #endif - amount++; + playlist->amount++; } } } @@ -867,22 +882,13 @@ static int add_indices_to_playlist(struct playlist_info* playlist, } exit: -/* v DEBUGGING Remove me! */ - if (playlist->fd != -2) - splashf(HZ, "Error playlist fd"); - playlist->fd = playlist_fd; -/* ^ DEBUGGING Remove me! */ - playlist->amount = amount; - playlist->max_playlist_size = max_playlist_size; - mutex_unlock(playlist->control_mutex); -#ifdef HAVE_DIRCACHE - queue_post(&playlist_queue, PLAYLIST_LOAD_POINTERS, 0); -#endif + + playlist_mutex_unlock(&(playlist->mutex)); + dc_load_playlist_pointers(); return result; } - /* * Checks if there are any music files in the dir or any of its * subdirectories. May be called recursively. @@ -1158,12 +1164,11 @@ static int get_previous_directory(char *dir){ return get_next_dir(dir, false); } - /* * gets pathname for track at seek index */ -static int get_filename(struct playlist_info* playlist, int index, int seek, - bool control_file, char *buf, int buf_length) +static int get_track_filename(struct playlist_info* playlist, int index, int seek, + bool control_file, char *buf, int buf_length) { int fd; int max = -1; @@ -1188,7 +1193,7 @@ static int get_filename(struct playlist_info* playlist, int index, int seek, } else if (max < 0) { - mutex_lock(playlist->control_mutex); + playlist_mutex_lock(&(playlist->mutex)); if (control_file) { @@ -1205,7 +1210,6 @@ static int get_filename(struct playlist_info* playlist, int index, int seek, if(-1 != fd) { - if (lseek(fd, seek, SEEK_SET) != seek) max = -1; else @@ -1221,21 +1225,22 @@ static int get_filename(struct playlist_info* playlist, int index, int seek, * be as large as tmp_buf. */ if (!utf8) - max = convert_m3u(tmp_buf, max, sizeof(tmp_buf), dir_buf); + max = convert_m3u_name(tmp_buf, max, + sizeof(tmp_buf), dir_buf); } } } - mutex_unlock(playlist->control_mutex); + playlist_mutex_unlock(&(playlist->mutex)); if (max < 0) { if (usb_detect() == USB_INSERTED) ; /* ignore error on usb plug */ else if (control_file) - splash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); + notify_control_access_error(); else - splash(HZ*2, ID2P(LANG_PLAYLIST_ACCESS_ERROR)); + notify_access_error(); return max; } @@ -1265,8 +1270,7 @@ static int create_and_play_dir(int direction, bool play_last) else res = get_previous_directory(dir); - if (res < 0) - /* return the error encountered */ + if (res < 0) /* return the error encountered */ return res; if (playlist_create(dir, NULL) != -1) @@ -1308,9 +1312,9 @@ static int create_and_play_dir(int direction, bool play_last) * PLAYLIST_REPLACE - Erase current playlist, Cue the current track * and inster this track at the end. */ -static int add_track_to_playlist(struct playlist_info* playlist, - const char *filename, int position, - bool queue, int seek_pos) +static int add_track_to_playlist_unlocked(struct playlist_info* playlist, + const char *filename, int position, + bool queue, int seek_pos) { int insert_position, orig_position; unsigned long flags = PLAYLIST_INSERT_TYPE_INSERT; @@ -1320,7 +1324,7 @@ static int add_track_to_playlist(struct playlist_info* playlist, if (playlist->amount >= playlist->max_playlist_size) { - display_buffer_full(); + notify_buffer_full(); return -1; } @@ -1385,15 +1389,17 @@ static int add_track_to_playlist(struct playlist_info* playlist, } case PLAYLIST_INSERT_LAST_SHUFFLED: { - position = insert_position = playlist->last_shuffled_start + - rand() % (playlist->amount - playlist->last_shuffled_start + 1); + int newpos = playlist->last_shuffled_start + + rand() % (playlist->amount - playlist->last_shuffled_start + 1); + + position = insert_position = newpos; break; } case PLAYLIST_REPLACE: if (playlist_remove_all_tracks(playlist) < 0) return -1; - - playlist->last_insert_pos = position = insert_position = playlist->index + 1; + int newpos = playlist->index + 1; + playlist->last_insert_pos = position = insert_position = newpos; break; } @@ -1440,7 +1446,7 @@ static int add_track_to_playlist(struct playlist_info* playlist, playlist->indices[insert_position] = flags | seek_pos; #ifdef HAVE_DIRCACHE - copy_filerefs(&playlist->dcfrefs[insert_position], NULL, 1); + dc_copy_filerefs(&playlist->dcfrefs[insert_position], NULL, 1); #endif playlist->amount++; @@ -1459,8 +1465,8 @@ static int directory_search_callback(char* filename, void* context) (struct directory_search_context*) context; int insert_pos; - insert_pos = add_track_to_playlist(c->playlist, filename, c->position, - c->queue, -1); + insert_pos = add_track_to_playlist_unlocked(c->playlist, filename, + c->position, c->queue, -1); if (insert_pos < 0) return -1; @@ -1499,11 +1505,13 @@ static int remove_track_from_playlist(struct playlist_info* playlist, int position, bool write) { int i; + int result = 0; bool inserted; if (playlist->amount <= 0) return -1; + playlist_mutex_lock(&(playlist->mutex)); inserted = playlist->indices[position] & PLAYLIST_INSERT_TYPE_MASK; /* shift indices now that track has been removed */ @@ -1537,24 +1545,22 @@ static int remove_track_from_playlist(struct playlist_info* playlist, if (write && playlist->control_fd >= 0) { - int result = update_control(playlist, PLAYLIST_COMMAND_DELETE, + result = update_control(playlist, PLAYLIST_COMMAND_DELETE, position, -1, NULL, NULL, NULL); - - if (result < 0) - return result; - - sync_control(playlist, false); + if (result >= 0) + sync_control(playlist, false); } - return 0; + playlist_mutex_unlock(&(playlist->mutex)); + return result; } /* * Search for the seek track and set appropriate indices. Used after shuffle * to make sure the current index is still pointing to correct track. */ -static void find_and_set_playlist_index(struct playlist_info* playlist, - unsigned int seek) +static void find_and_set_playlist_index_unlocked(struct playlist_info* playlist, + unsigned int seek) { int i; @@ -1582,6 +1588,8 @@ static int randomise_playlist(struct playlist_info* playlist, int candidate; unsigned int current = playlist->indices[playlist->index]; + playlist_mutex_lock(&(playlist->mutex)); + /* seed 0 is used to identify sorted playlist for resume purposes */ if (seed == 0) seed = 1; @@ -1610,7 +1618,7 @@ static int randomise_playlist(struct playlist_info* playlist, } if (start_current) - find_and_set_playlist_index(playlist, current); + find_and_set_playlist_index_unlocked(playlist, current); /* indices have been moved so last insert position is no longer valid */ playlist->last_insert_pos = -1; @@ -1625,6 +1633,8 @@ static int randomise_playlist(struct playlist_info* playlist, playlist->first_index, NULL, NULL, NULL); } + playlist_mutex_unlock(&(playlist->mutex)); + return 0; } @@ -1634,7 +1644,7 @@ static int randomise_playlist(struct playlist_info* playlist, * 2. Playlist/directory tracks (in playlist order) * 3. Inserted/Appended tracks (in insert order) */ -static int compare(const void* p1, const void* p2) +static int sort_compare_fn(const void* p1, const void* p2) { unsigned long* e1 = (unsigned long*) p1; unsigned long* e2 = (unsigned long*) p2; @@ -1660,25 +1670,26 @@ static int compare(const void* p1, const void* p2) * set the index to the new index of the current song. * Also while going to unshuffled mode set the first_index to 0. */ -static int sort_playlist(struct playlist_info* playlist, bool start_current, - bool write) +static int sort_playlist_unlocked(struct playlist_info* playlist, + bool start_current, bool write) { + unsigned int current = playlist->indices[playlist->index]; if (playlist->amount > 0) qsort((void*)playlist->indices, playlist->amount, - sizeof(playlist->indices[0]), compare); + sizeof(playlist->indices[0]), sort_compare_fn); #ifdef HAVE_DIRCACHE /** We need to re-check the song names from disk because qsort can't * sort two arrays at once :/ * FIXME: Please implement a better way to do this. */ - copy_filerefs(playlist->dcfrefs, NULL, playlist->max_playlist_size); - queue_post(&playlist_queue, PLAYLIST_LOAD_POINTERS, 0); + dc_copy_filerefs(playlist->dcfrefs, NULL, playlist->max_playlist_size); + dc_load_playlist_pointers(); #endif if (start_current) - find_and_set_playlist_index(playlist, current); + find_and_set_playlist_index_unlocked(playlist, current); /* indices have been moved so last insert position is no longer valid */ playlist->last_insert_pos = -1; @@ -1824,28 +1835,43 @@ static int get_next_index(const struct playlist_info* playlist, int steps, } #ifdef HAVE_DIRCACHE -/** - * Thread to update filename pointers to dircache on background - * without affecting playlist load up performance. This thread also flushes - * any pending control commands when the disk spins up. - */ -static void flush_playlist_callback(void) + +static void dc_copy_filerefs(struct dircache_fileref *dcfto, + const struct dircache_fileref *dcffrom, + int count) +{ + if (!dcfto) + return; + + if (dcffrom) + memmove(dcfto, dcffrom, count * sizeof (*dcfto)); + else + { + /* just initialize the destination */ + for (int i = 0; i < count; i++, dcfto++) + dircache_fileref_init(dcfto); + } +} + +static void dc_flush_playlist_callback(void) { struct playlist_info *playlist; playlist = ¤t_playlist; if (playlist->control_fd >= 0) { - if (playlist->num_cached > 0) - { - mutex_lock(playlist->control_mutex); - flush_cached_control(playlist); - mutex_unlock(playlist->control_mutex); - } + flush_cached_control(playlist); sync_control(playlist, true); } + else if (playlist->control_fd < 0 || playlist->num_cached <= 0) + unregister_storage_idle_func(dc_flush_playlist_callback, false); } -static void thread_playlist(void) +/** + * Thread to update filename pointers to dircache on background + * without affecting playlist load up performance. This thread also flushes + * any pending control commands when the disk spins up. + */ +static void dc_thread_playlist(void) { struct queue_event ev; bool dirty_pointers = false; @@ -1882,7 +1908,7 @@ static void thread_playlist(void) if (playlist->control_fd >= 0) { if (playlist->num_cached > 0) - register_storage_idle_func(flush_playlist_callback); + register_storage_idle_func(dc_flush_playlist_callback); } if (!playlist->dcfrefs || playlist->amount <= 0) @@ -1911,8 +1937,8 @@ static void thread_playlist(void) seek = playlist->indices[index] & PLAYLIST_SEEK_MASK; /* Load the filename from playlist file. */ - if (get_filename(playlist, index, seek, control_file, tmp, - sizeof(tmp)) < 0) + if (get_track_filename(playlist, index, seek, + control_file, tmp, sizeof(tmp)) < 0) { break ; } @@ -1999,9 +2025,6 @@ void playlist_init(void) int handle; struct playlist_info* playlist = ¤t_playlist; - mutex_init(¤t_playlist_mutex); - mutex_init(&created_playlist_mutex); - playlist->current = true; strmemccpy(playlist->control_filename, PLAYLIST_CONTROL_FILE, sizeof(playlist->control_filename)); @@ -2009,25 +2032,26 @@ void playlist_init(void) playlist->control_fd = -1; playlist->max_playlist_size = global_settings.max_files_in_playlist; handle = core_alloc_ex("playlist idx", - playlist->max_playlist_size * sizeof(*playlist->indices), &ops); + playlist->max_playlist_size * sizeof(*playlist->indices), &ops); + playlist->indices = core_get_data(handle); playlist->buffer_size = AVERAGE_FILENAME_LENGTH * global_settings.max_files_in_dir; + handle = core_alloc_ex("playlist buf", playlist->buffer_size, &ops); playlist->buffer = core_get_data(handle); playlist->buffer_handle = handle; - playlist->control_mutex = ¤t_playlist_mutex; - empty_playlist(playlist, true); + initalize_new_playlist(playlist, true); #ifdef HAVE_DIRCACHE handle = core_alloc_ex("playlist dc", playlist->max_playlist_size * sizeof(*playlist->dcfrefs), &ops); playlist->dcfrefs = core_get_data(handle); - copy_filerefs(playlist->dcfrefs, NULL, playlist->max_playlist_size); - create_thread(thread_playlist, playlist_stack, sizeof(playlist_stack), - 0, thread_playlist_name IF_PRIO(, PRIORITY_BACKGROUND) + dc_copy_filerefs(playlist->dcfrefs, NULL, playlist->max_playlist_size); + create_thread(dc_thread_playlist, playlist_stack, sizeof(playlist_stack), + 0, dc_thread_playlist_name IF_PRIO(, PRIORITY_BACKGROUND) IF_COP(, CPU)); queue_init(&playlist_queue, true); @@ -2043,15 +2067,9 @@ void playlist_shutdown(void) if (playlist->control_fd >= 0) { - mutex_lock(playlist->control_mutex); + flush_cached_control(playlist); - if (playlist->num_cached > 0) - flush_cached_control(playlist); - - close(playlist->control_fd); - playlist->control_fd = -1; - - mutex_unlock(playlist->control_mutex); + close_playlist_control_file(playlist); } } @@ -2066,13 +2084,15 @@ int playlist_add(const char *filename) if((len+1 > playlist->buffer_size - playlist->buffer_end_pos) || (playlist->amount >= playlist->max_playlist_size)) { - display_buffer_full(); + notify_buffer_full(); return -1; } + playlist_mutex_lock(&(playlist->mutex)); + playlist->indices[playlist->amount] = playlist->buffer_end_pos; #ifdef HAVE_DIRCACHE - copy_filerefs(&playlist->dcfrefs[playlist->amount], NULL, 1); + dc_copy_filerefs(&playlist->dcfrefs[playlist->amount], NULL, 1); #endif playlist->amount++; @@ -2081,6 +2101,8 @@ int playlist_add(const char *filename) playlist->buffer_end_pos += len; playlist->buffer[playlist->buffer_end_pos++] = '\0'; + playlist_mutex_unlock(&(playlist->mutex)); + return 0; } @@ -2111,7 +2133,12 @@ int playlist_create_ex(struct playlist_info* playlist, void* temp_buffer, int temp_buffer_size) { if (!playlist) + { playlist = ¤t_playlist; + playlist_mutex_lock(&(playlist->mutex)); + playlist->last_shuffled_start = playlist->amount; + playlist_mutex_unlock(&(playlist->mutex)); + } else { /* Initialize playlist structure */ @@ -2150,10 +2177,9 @@ int playlist_create_ex(struct playlist_info* playlist, playlist->buffer_size = 0; playlist->buffer_handle = -1; playlist->buffer = NULL; - playlist->control_mutex = &created_playlist_mutex; } - new_playlist(playlist, dir, file); + new_playlist_unlocked(playlist, dir, file); if (file) /* load the playlist file */ @@ -2169,7 +2195,7 @@ int playlist_create(const char *dir, const char *file) { struct playlist_info* playlist = ¤t_playlist; - new_playlist(playlist, dir, file); + new_playlist_unlocked(playlist, dir, file); if (file) { @@ -2221,17 +2247,16 @@ void playlist_close(struct playlist_info* playlist) if (!playlist) return; - if (playlist->fd >= 0) { + if (playlist->fd >= 0) + { close(playlist->fd); playlist->fd = -1; } - if (playlist->control_fd >= 0) { - close(playlist->control_fd); - playlist->control_fd = -1; - } + close_playlist_control_file(playlist); - if (playlist->control_created) { + if (playlist->control_created) + { remove(playlist->control_filename); playlist->control_created = false; } @@ -2250,7 +2275,7 @@ int playlist_delete(struct playlist_info* playlist, int index) if (check_control(playlist) < 0) { - splash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); + notify_control_access_error(); return -1; } @@ -2487,8 +2512,8 @@ int playlist_get_track_info(struct playlist_info* playlist, int index, control_file = playlist->indices[index] & PLAYLIST_INSERT_TYPE_MASK; seek = playlist->indices[index] & PLAYLIST_SEEK_MASK; - if (get_filename(playlist, index, seek, control_file, info->filename, - sizeof(info->filename)) < 0) + if (get_track_filename(playlist, index, seek, control_file, + info->filename, sizeof(info->filename)) < 0) return -1; info->attr = 0; @@ -2527,7 +2552,7 @@ int playlist_insert_directory(struct playlist_info* playlist, if (check_control(playlist) < 0) { - splash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); + notify_control_access_error(); return -1; } @@ -2565,9 +2590,7 @@ int playlist_insert_directory(struct playlist_info* playlist, if ((audio_status() & AUDIO_STATUS_PLAY) && playlist->started) audio_flush_and_reload_tracks(); -#ifdef HAVE_DIRCACHE - queue_post(&playlist_queue, PLAYLIST_LOAD_POINTERS, 0); -#endif + dc_load_playlist_pointers(); return result; } @@ -2585,23 +2608,27 @@ int playlist_insert_playlist(struct playlist_info* playlist, const char *filenam char temp_buf[MAX_PATH+1]; char trackname[MAX_PATH+1]; int count = 0; - int result = 0; - bool utf8 = is_m3u8(filename); + int result = -1; + bool utf8 = is_m3u8_name(filename); if (!playlist) playlist = ¤t_playlist; + playlist_mutex_lock(&(playlist->mutex)); + + cpu_boost(true); + if (check_control(playlist) < 0) { - splash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); - return -1; + notify_control_access_error(); + goto out; } fd = open_utf8(filename, O_RDONLY); if (fd < 0) { - splash(HZ*2, ID2P(LANG_PLAYLIST_ACCESS_ERROR)); - return -1; + notify_access_error(); + goto out; } /* we need the directory name for formatting purposes */ @@ -2622,12 +2649,10 @@ int playlist_insert_playlist(struct playlist_info* playlist, const char *filenam else { close(fd); - return -1; + goto out; } } - cpu_boost(true); - while ((max = read_line(fd, temp_buf, sizeof(temp_buf))) > 0) { /* user abort */ @@ -2643,25 +2668,22 @@ int playlist_insert_playlist(struct playlist_info* playlist, const char *filenam /* Use trackname as a temporay buffer. Note that trackname must * be as large as temp_buf. */ - max = convert_m3u(temp_buf, max, sizeof(temp_buf), trackname); + max = convert_m3u_name(temp_buf, max, sizeof(temp_buf), trackname); } /* we need to format so that relative paths are correctly handled */ - if (format_track_path(trackname, temp_buf, sizeof(trackname), - dir) < 0) + if (format_track_path(trackname, temp_buf, sizeof(trackname), dir) < 0) { - result = -1; - break; + goto out; } - insert_pos = add_track_to_playlist(playlist, trackname, position, - queue, -1); + insert_pos = add_track_to_playlist_unlocked(playlist, trackname, + position, queue, -1); if (insert_pos < 0) { - result = -1; - break; + goto out; } /* After first INSERT_FIRST switch to INSERT so that all the @@ -2678,7 +2700,9 @@ int playlist_insert_playlist(struct playlist_info* playlist, const char *filenam if (count == PLAYLIST_DISPLAY_COUNT && (audio_status() & AUDIO_STATUS_PLAY) && playlist->started) + { audio_flush_and_reload_tracks(); + } } } @@ -2690,16 +2714,18 @@ int playlist_insert_playlist(struct playlist_info* playlist, const char *filenam sync_control(playlist, false); - cpu_boost(false); - display_playlist_count(count, count_str, true); if ((audio_status() & AUDIO_STATUS_PLAY) && playlist->started) audio_flush_and_reload_tracks(); -#ifdef HAVE_DIRCACHE - queue_post(&playlist_queue, PLAYLIST_LOAD_POINTERS, 0); -#endif + dc_load_playlist_pointers(); + result = 0; + +out: + cpu_boost(false); + + playlist_mutex_unlock(&(playlist->mutex)); return result; } @@ -2716,13 +2742,16 @@ int playlist_insert_track(struct playlist_info* playlist, const char *filename, if (!playlist) playlist = ¤t_playlist; + playlist_mutex_lock(&(playlist->mutex)); + if (check_control(playlist) < 0) { - splash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); + notify_control_access_error(); return -1; } - result = add_track_to_playlist(playlist, filename, position, queue, -1); + result = add_track_to_playlist_unlocked(playlist, filename, + position, queue, -1); /* Check if we want manually sync later. For example when adding * bunch of files from tagcache, syncing after every file wouldn't be @@ -2730,10 +2759,11 @@ int playlist_insert_track(struct playlist_info* playlist, const char *filename, if (sync && result >= 0) playlist_sync(playlist); + playlist_mutex_unlock(&(playlist->mutex)); + return result; } - /* returns true if playlist has been modified */ bool playlist_modified(const struct playlist_info* playlist) { @@ -2743,7 +2773,9 @@ bool playlist_modified(const struct playlist_info* playlist) if (playlist->shuffle_modified || playlist->deleted || playlist->num_inserted_tracks > 0) + { return true; + } return false; } @@ -2754,7 +2786,7 @@ bool playlist_modified(const struct playlist_info* playlist) */ int playlist_move(struct playlist_info* playlist, int index, int new_index) { - int result; + int result = -1; int seek; bool control_file; bool queue; @@ -2770,14 +2802,16 @@ int playlist_move(struct playlist_info* playlist, int index, int new_index) if (!playlist) playlist = ¤t_playlist; + playlist_mutex_lock(&(playlist->mutex)); + if (check_control(playlist) < 0) { - splash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); - return -1; + notify_control_access_error(); + goto out;; } if (index == new_index) - return -1; + goto out; if (index == playlist->index) { @@ -2814,9 +2848,11 @@ int playlist_move(struct playlist_info* playlist, int index, int new_index) queue = playlist->indices[index] & PLAYLIST_QUEUE_MASK; seek = playlist->indices[index] & PLAYLIST_SEEK_MASK; - if (get_filename(playlist, index, seek, control_file, filename, - sizeof(filename)) < 0) - return -1; + if (get_track_filename(playlist, index, seek, + control_file, filename, sizeof(filename)) < 0) + { + goto out; + } /* We want to insert the track at the position that was specified by new_index. This may be different then new_index because of the @@ -2830,18 +2866,22 @@ int playlist_move(struct playlist_info* playlist, int index, int new_index) if (result != -1) { - if (r == 0) - /* First index */ + if (r == 0)/* First index */ + { new_index = PLAYLIST_PREPEND; + } else if (r == playlist->amount) + { /* Append */ new_index = PLAYLIST_INSERT_LAST; - else - /* Calculate index of desired position */ + } + else /* Calculate index of desired position */ + { new_index = (r+playlist->first_index)%playlist->amount; + } - result = add_track_to_playlist(playlist, filename, new_index, queue, - -1); + result = add_track_to_playlist_unlocked(playlist, filename, + new_index, queue, -1); if (result != -1) { @@ -2863,19 +2903,27 @@ int playlist_move(struct playlist_info* playlist, int index, int new_index) break; } } - else - if ((displace_current) && (new_index != PLAYLIST_PREPEND)) + else if ((displace_current) && (new_index != PLAYLIST_PREPEND)) + { /* make the index point to the currently playing track */ playlist->index++; + } + playlist_mutex_unlock(&(playlist->mutex)); if ((audio_status() & AUDIO_STATUS_PLAY) && playlist->started) audio_flush_and_reload_tracks(); } + else + { + playlist_mutex_unlock(&(playlist->mutex)); + } } -#ifdef HAVE_DIRCACHE - queue_post(&playlist_queue, PLAYLIST_LOAD_POINTERS, 0); -#endif + dc_load_playlist_pointers(); + return result; + +out: + playlist_mutex_unlock(&(playlist->mutex)); return result; } @@ -2908,6 +2956,9 @@ char *playlist_name(const struct playlist_info* playlist, char *buf, int playlist_next(int steps) { struct playlist_info* playlist = ¤t_playlist; + + playlist_mutex_lock(&(playlist->mutex)); + int index; if ( (steps > 0) @@ -2941,7 +2992,7 @@ int playlist_next(int steps) { /* Repeat shuffle mode. Re-shuffle playlist and resume play */ playlist->first_index = 0; - sort_playlist(playlist, false, false); + sort_playlist_unlocked(playlist, false, false); randomise_playlist(playlist, current_tick, false, true); playlist->started = true; @@ -2950,15 +3001,16 @@ int playlist_next(int steps) } else if (playlist->in_ram && global_settings.next_folder) { + /* we switch playlists here */ + playlist_mutex_unlock(&(playlist->mutex)); index = create_and_play_dir(steps, true); - + playlist_mutex_lock(&(playlist->mutex)); if (index >= 0) { playlist->index = index; } } - - return index; + goto out; } playlist->index = index; @@ -2973,20 +3025,24 @@ int playlist_next(int steps) { /* reset last inserted track */ playlist->last_insert_pos = -1; - if (playlist->control_fd >= 0) { int result = update_control(playlist, PLAYLIST_COMMAND_RESET, -1, -1, NULL, NULL, NULL); if (result < 0) - return result; - + { + index = result; + goto out; + } sync_control(playlist, false); } } } +out: + playlist_mutex_unlock(&(playlist->mutex)); + return index; } @@ -2997,6 +3053,9 @@ bool playlist_next_dir(int direction) if(!current_playlist.in_ram) return false; + playlist_mutex_lock(&(current_playlist.mutex)); + playlist_mutex_unlock(&(current_playlist.mutex)); + return create_and_play_dir(direction, false) >= 0; } @@ -3021,8 +3080,8 @@ const char* playlist_peek(int steps, char* buf, size_t buf_size) control_file = playlist->indices[index] & PLAYLIST_INSERT_TYPE_MASK; seek = playlist->indices[index] & PLAYLIST_SEEK_MASK; - if (get_filename(playlist, index, seek, control_file, buf, - buf_size) < 0) + if (get_track_filename(playlist, index, seek, + control_file, buf, buf_size) < 0) return NULL; temp_ptr = buf; @@ -3060,13 +3119,19 @@ int playlist_randomise(struct playlist_info* playlist, unsigned int seed, if (!playlist) playlist = ¤t_playlist; + playlist_mutex_lock(&(playlist->mutex)); + check_control(playlist); result = randomise_playlist(playlist, seed, start_current, true); if (result != -1 && (audio_status() & AUDIO_STATUS_PLAY) && playlist->started) + { audio_flush_and_reload_tracks(); + } + + playlist_mutex_unlock(&(playlist->mutex)); return result; } @@ -3103,9 +3168,9 @@ int playlist_remove_all_tracks(struct playlist_info *playlist) */ int playlist_resume(void) { - struct playlist_info* playlist = ¤t_playlist; char *buffer; size_t buflen; + size_t readsize; int handle; int nread; int total_read = 0; @@ -3115,6 +3180,10 @@ int playlist_resume(void) int result = -1; splash(0, ID2P(LANG_WAIT)); + + struct playlist_info* playlist = ¤t_playlist; + playlist_mutex_lock(&(playlist->mutex)); + if (core_allocatable() < (1 << 10)) talk_buffer_set_policy(TALK_BUFFER_LOOSE); /* back off voice buffer */ @@ -3126,7 +3195,7 @@ int playlist_resume(void) if (handle < 0) { splashf(HZ * 2, "%s(): OOM", __func__); - return -1; + goto out; } /* align buffer for faster load times */ @@ -3135,12 +3204,12 @@ int playlist_resume(void) buflen = ALIGN_DOWN(buflen, 512); /* to avoid partial sector I/O */ playlist_shutdown(); /* flush any cached control commands to disk */ - empty_playlist(playlist, true); + empty_playlist_unlocked(playlist, true); playlist->control_fd = open(playlist->control_filename, O_RDWR); if (playlist->control_fd < 0) { - splash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); + notify_control_access_error(); goto out; } playlist->control_created = true; @@ -3148,16 +3217,16 @@ int playlist_resume(void) control_file_size = filesize(playlist->control_fd); if (control_file_size <= 0) { - splash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); + notify_control_access_error(); goto out; } /* read a small amount first to get the header */ - nread = read(playlist->control_fd, buffer, - PLAYLIST_COMMAND_SIZE<buflen?PLAYLIST_COMMAND_SIZE:buflen); + readsize = (PLAYLIST_COMMAND_SIZE<buflen?PLAYLIST_COMMAND_SIZE:buflen); + nread = read(playlist->control_fd, buffer, readsize); if(nread <= 0) { - splash(HZ*2, ID2P(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); + notify_control_access_error(); goto out; } @@ -3176,11 +3245,12 @@ int playlist_resume(void) char *str1 = NULL; char *str2 = NULL; char *str3 = NULL; + unsigned long last_tick = current_tick; splash_progress_set_delay(HZ / 2); /* wait 1/2 sec before progress */ bool useraborted = false; - for(count=0; count<nread && !exit_loop && !useraborted; count++,p++) + for(count=0; count<nread && !exit_loop; count++,p++) { /* Show a splash while we are loading. */ splash_progress((total_read + count), control_file_size, @@ -3190,6 +3260,7 @@ int playlist_resume(void) if (action_userabort(TIMEOUT_NOBLOCK)) { useraborted = true; + exit_loop = true; break; } last_tick = current_tick; @@ -3199,9 +3270,6 @@ int playlist_resume(void) { *p = '\0'; - /* save last_newline in case we need to load more data */ - last_newline = count; - switch (current_command) { case PLAYLIST_COMMAND_PLAYLIST: @@ -3230,7 +3298,7 @@ int playlist_resume(void) goto out; } - update_playlist_filename(playlist, str2, str3); + update_playlist_filename_unlocked(playlist, str2, str3); if (str3[0] != '\0') { @@ -3248,7 +3316,7 @@ int playlist_resume(void) /* load the rest of the data */ first = false; exit_loop = true; - + readsize = buflen; break; } case PLAYLIST_COMMAND_ADD: @@ -3273,8 +3341,8 @@ int playlist_resume(void) /* seek position is based on str3's position in buffer */ - if (add_track_to_playlist(playlist, str3, position, - queue, total_read+(str3-buffer)) < 0) + if (add_track_to_playlist_unlocked(playlist, str3, + position, queue, total_read+(str3-buffer)) < 0) { result = -5; goto out; @@ -3322,7 +3390,7 @@ int playlist_resume(void) if (!sorted) { /* Always sort list before shuffling */ - sort_playlist(playlist, false, false); + sort_playlist_unlocked(playlist, false, false); } seed = atoi(str1); @@ -3335,6 +3403,7 @@ int playlist_resume(void) goto out; } sorted = false; + break; } case PLAYLIST_COMMAND_UNSHUFFLE: @@ -3349,7 +3418,7 @@ int playlist_resume(void) playlist->first_index = atoi(str1); - if (sort_playlist(playlist, false, false) < 0) + if (sort_playlist_unlocked(playlist, false, false) < 0) { result = -11; goto out; @@ -3368,6 +3437,8 @@ int playlist_resume(void) break; } + /* save last_newline in case we need to load more data */ + last_newline = count; newline = true; /* to ignore any extra newlines */ @@ -3377,14 +3448,6 @@ int playlist_resume(void) { newline = false; - /* first non-comment line must always specify playlist */ - if (first && *p != 'P' && *p != '#') - { - result = -12; - exit_loop = true; - break; - } - switch (*p) { case 'P': @@ -3425,6 +3488,16 @@ int playlist_resume(void) break; } + /* first non-comment line must always specify playlist */ + if (first && + (current_command != PLAYLIST_COMMAND_PLAYLIST) && + (current_command != PLAYLIST_COMMAND_COMMENT)) + { + result = -12; + exit_loop = true; + break; + } + str_count = -1; str1 = NULL; str2 = NULL; @@ -3475,6 +3548,7 @@ int playlist_resume(void) result = -1; goto out; } + if (!newline || (exit_loop && count<nread)) { if ((total_read + count) >= control_file_size) @@ -3493,12 +3567,7 @@ int playlist_resume(void) total_read += count; - if (first) - /* still looking for header */ - nread = read(playlist->control_fd, buffer, - PLAYLIST_COMMAND_SIZE<buflen?PLAYLIST_COMMAND_SIZE:buflen); - else - nread = read(playlist->control_fd, buffer, buflen); + nread = read(playlist->control_fd, buffer, readsize); /* Terminate on EOF */ if(nread <= 0) @@ -3507,11 +3576,11 @@ int playlist_resume(void) } } -#ifdef HAVE_DIRCACHE - queue_post(&playlist_queue, PLAYLIST_LOAD_POINTERS, 0); -#endif + dc_load_playlist_pointers(); out: + playlist_mutex_unlock(&(playlist->mutex)); + talk_buffer_set_policy(TALK_BUFFER_DEFAULT); core_free(handle); return result; @@ -3524,7 +3593,9 @@ void playlist_resume_track(int start_index, unsigned int crc, int i; unsigned int tmp_crc; struct playlist_info* playlist = ¤t_playlist; + tmp_crc = playlist_get_filename_crc32(playlist, start_index); + if (tmp_crc == crc) { playlist_start(start_index, elapsed, offset); @@ -3589,7 +3660,7 @@ int playlist_save(struct playlist_info* playlist, char *filename, char* old_buffer = (char*)playlist->buffer; size_t old_buffer_size = playlist->buffer_size; - if (is_m3u8(path)) + if (is_m3u8_name(path)) { fd = open_utf8(path, O_CREAT|O_WRONLY|O_TRUNC); } @@ -3598,9 +3669,10 @@ int playlist_save(struct playlist_info* playlist, char *filename, /* some applications require a BOM to read the file properly */ fd = open(path, O_CREAT|O_WRONLY|O_TRUNC, 0666); } + if (fd < 0) { - splash(HZ*2, ID2P(LANG_PLAYLIST_ACCESS_ERROR)); + notify_access_error(); result = -1; goto reset_old_buffer; } @@ -3630,8 +3702,8 @@ int playlist_save(struct playlist_info* playlist, char *filename, /* Don't save queued files */ if (!queue) { - if (get_filename(playlist, index, seek, control_file, tmp_buf, - MAX_PATH+1) < 0) + if (get_track_filename(playlist, index, seek, + control_file, tmp_buf, MAX_PATH+1) < 0) { result = -1; break; @@ -3642,7 +3714,7 @@ int playlist_save(struct playlist_info* playlist, char *filename, if (fdprintf(fd, "%s\n", tmp_buf) < 0) { - splash(HZ*2, ID2P(LANG_PLAYLIST_ACCESS_ERROR)); + notify_access_error(); result = -1; break; } @@ -3672,7 +3744,7 @@ int playlist_save(struct playlist_info* playlist, char *filename, { strmemcpy(tmp_buf, path, pathlen); /* remove "_temp" */ - mutex_lock(playlist->control_mutex); + playlist_mutex_lock(&(playlist->mutex)); if (!rename(path, tmp_buf)) { @@ -3708,11 +3780,11 @@ int playlist_save(struct playlist_info* playlist, char *filename, /* we need to recreate control because inserted tracks are now part of the playlist and shuffle has been invalidated */ - result = recreate_control(playlist); + result = recreate_control_unlocked(playlist); } } - mutex_unlock(playlist->control_mutex); + playlist_mutex_unlock(&(playlist->mutex)); } if (fd >= 0) @@ -3723,6 +3795,7 @@ int playlist_save(struct playlist_info* playlist, char *filename, reset_old_buffer: if (playlist->buffer_handle > 0) old_buffer = core_get_data(playlist->buffer_handle); + playlist->buffer = old_buffer; playlist->buffer_size = old_buffer_size; @@ -3737,10 +3810,14 @@ reset_old_buffer: */ int playlist_set_current(struct playlist_info* playlist) { + int result = -1; + if (!playlist || (check_control(playlist) < 0)) - return -1; + return result; - empty_playlist(¤t_playlist, false); + playlist_mutex_lock(&(current_playlist.mutex)); + + empty_playlist_unlocked(¤t_playlist, false); strmemccpy(current_playlist.filename, playlist->filename, sizeof(current_playlist.filename)); @@ -3748,21 +3825,22 @@ int playlist_set_current(struct playlist_info* playlist) current_playlist.utf8 = playlist->utf8; current_playlist.fd = playlist->fd; - close(playlist->control_fd); - playlist->control_fd = -1; - close(current_playlist.control_fd); - current_playlist.control_fd = -1; + close_playlist_control_file(playlist); + close_playlist_control_file(¤t_playlist); + remove(current_playlist.control_filename); current_playlist.control_created = false; - if (rename(playlist->control_filename, - current_playlist.control_filename) < 0) - return -1; + + if (rename(playlist->control_filename, current_playlist.control_filename) < 0) + goto out; + current_playlist.control_fd = open(current_playlist.control_filename, O_RDWR); + if (current_playlist.control_fd < 0) - return -1; - current_playlist.control_created = true; + goto out; + current_playlist.control_created = true; current_playlist.dirlen = playlist->dirlen; if (playlist->indices && playlist->indices != current_playlist.indices) @@ -3770,8 +3848,8 @@ int playlist_set_current(struct playlist_info* playlist) memcpy((void*)current_playlist.indices, (void*)playlist->indices, playlist->max_playlist_size*sizeof(*playlist->indices)); #ifdef HAVE_DIRCACHE - copy_filerefs(current_playlist.dcfrefs, playlist->dcfrefs, - playlist->max_playlist_size); + dc_copy_filerefs(current_playlist.dcfrefs, playlist->dcfrefs, + playlist->max_playlist_size); #endif } @@ -3785,10 +3863,15 @@ int playlist_set_current(struct playlist_info* playlist) memcpy(current_playlist.control_cache, playlist->control_cache, sizeof(current_playlist.control_cache)); + current_playlist.num_cached = playlist->num_cached; current_playlist.pending_control_sync = playlist->pending_control_sync; + result = 0; - return 0; +out: + playlist_mutex_unlock(&(current_playlist.mutex)); + + return result; } /* set playlist->last_shuffle_start to playlist->amount for @@ -3796,14 +3879,16 @@ int playlist_set_current(struct playlist_info* playlist) void playlist_set_last_shuffled_start(void) { struct playlist_info* playlist = ¤t_playlist; + playlist_mutex_lock(&(playlist->mutex)); playlist->last_shuffled_start = playlist->amount; + playlist_mutex_unlock(&(playlist->mutex)); } /* shuffle newly created playlist using random seed. */ int playlist_shuffle(int random_seed, int start_index) { struct playlist_info* playlist = ¤t_playlist; - + playlist_mutex_lock(&(playlist->mutex)); bool start_current = false; if (start_index >= 0 && global_settings.play_selected) @@ -3814,7 +3899,7 @@ int playlist_shuffle(int random_seed, int start_index) } randomise_playlist(playlist, random_seed, start_current, true); - + playlist_mutex_unlock(&(playlist->mutex)); return playlist->index; } @@ -3827,6 +3912,7 @@ void playlist_skip_entry(struct playlist_info *playlist, int steps) if (playlist == NULL) playlist = ¤t_playlist; + playlist_mutex_lock(&(playlist->mutex)); /* need to account for already skipped tracks */ steps = calculate_step_count(playlist, steps); @@ -3838,6 +3924,7 @@ void playlist_skip_entry(struct playlist_info *playlist, int steps) index -= playlist->amount; playlist->indices[index] |= PLAYLIST_SKIPPED; + playlist_mutex_unlock(&(playlist->mutex)); } /* sort currently playing playlist */ @@ -3848,14 +3935,15 @@ int playlist_sort(struct playlist_info* playlist, bool start_current) if (!playlist) playlist = ¤t_playlist; - check_control(playlist); + playlist_mutex_lock(&(playlist->mutex)); - result = sort_playlist(playlist, start_current, true); + check_control(playlist); + result = sort_playlist_unlocked(playlist, start_current, true); - if (result != -1 && (audio_status() & AUDIO_STATUS_PLAY) && - playlist->started) + if (result != -1 && (audio_status() & AUDIO_STATUS_PLAY) && playlist->started) audio_flush_and_reload_tracks(); + playlist_mutex_unlock(&(playlist->mutex)); return result; } @@ -3865,10 +3953,15 @@ void playlist_start(int start_index, unsigned long elapsed, { struct playlist_info* playlist = ¤t_playlist; - playlist->index = start_index; + playlist_mutex_lock(&(playlist->mutex)); + playlist->index = start_index; playlist->started = true; + sync_control(playlist, false); + + playlist_mutex_unlock(&(playlist->mutex)); + audio_play(elapsed, offset); audio_resume(); } @@ -3882,9 +3975,7 @@ void playlist_sync(struct playlist_info* playlist) if ((audio_status() & AUDIO_STATUS_PLAY) && playlist->started) audio_flush_and_reload_tracks(); -#ifdef HAVE_DIRCACHE - queue_post(&playlist_queue, PLAYLIST_LOAD_POINTERS, 0); -#endif + dc_load_playlist_pointers(); } /* Update resume info for current playing song. Returns -1 on error. */ @@ -3914,10 +4005,8 @@ int playlist_update_resume_info(const struct mp3entry* id3) global_status.resume_elapsed = -1; global_status.resume_offset = -1; status_save(); + return -1; } return 0; } - - - diff --git a/apps/playlist.h b/apps/playlist.h index ab2afefddd..1ab330e513 100644 --- a/apps/playlist.h +++ b/apps/playlist.h @@ -27,6 +27,7 @@ #include "file.h" #include "kernel.h" #include "metadata.h" +#include "rbpaths.h" #define PLAYLIST_ATTR_QUEUED 0x01 #define PLAYLIST_ATTR_INSERTED 0x02 @@ -103,13 +104,14 @@ struct playlist_info to disk */ struct playlist_control_cache control_cache[PLAYLIST_MAX_CACHE]; int num_cached; /* number of cached entries */ - struct mutex *control_mutex; /* mutex for control file access */ + struct mutex mutex; /* mutex for control file access */ #ifdef HAVE_DIRCACHE struct dircache_fileref *dcfrefs; /* Dircache entry shortcuts */ #endif int dirlen; /* Length of the path to the playlist file */ char filename[MAX_PATH]; /* path name of m3u playlist on disk */ - char control_filename[MAX_PATH]; /* full path of control file */ + /* full path of control file (with extra room for extensions) */ + char control_filename[sizeof(PLAYLIST_CONTROL_FILE) + 8]; }; struct playlist_track_info |