diff options
Diffstat (limited to 'apps/playlist.c')
-rw-r--r-- | apps/playlist.c | 216 |
1 files changed, 198 insertions, 18 deletions
diff --git a/apps/playlist.c b/apps/playlist.c index a2f46cf99f..ee09eecf40 100644 --- a/apps/playlist.c +++ b/apps/playlist.c | |||
@@ -86,6 +86,9 @@ | |||
86 | #include "button.h" | 86 | #include "button.h" |
87 | #include "filetree.h" | 87 | #include "filetree.h" |
88 | #include "abrepeat.h" | 88 | #include "abrepeat.h" |
89 | #include "dircache.h" | ||
90 | #include "thread.h" | ||
91 | #include "usb.h" | ||
89 | #ifdef HAVE_LCD_BITMAP | 92 | #ifdef HAVE_LCD_BITMAP |
90 | #include "icons.h" | 93 | #include "icons.h" |
91 | #include "widgets.h" | 94 | #include "widgets.h" |
@@ -162,7 +165,7 @@ static int get_next_index(const struct playlist_info* playlist, int steps, | |||
162 | static void find_and_set_playlist_index(struct playlist_info* playlist, | 165 | static void find_and_set_playlist_index(struct playlist_info* playlist, |
163 | unsigned int seek); | 166 | unsigned int seek); |
164 | static int compare(const void* p1, const void* p2); | 167 | static int compare(const void* p1, const void* p2); |
165 | static int get_filename(struct playlist_info* playlist, int seek, | 168 | static int get_filename(struct playlist_info* playlist, int index, int seek, |
166 | bool control_file, char *buf, int buf_length); | 169 | bool control_file, char *buf, int buf_length); |
167 | static int get_next_directory(char *dir); | 170 | static int get_next_directory(char *dir); |
168 | static int get_next_dir(char *dir, bool is_forward, bool recursion); | 171 | static int get_next_dir(char *dir, bool is_forward, bool recursion); |
@@ -175,6 +178,14 @@ static void display_buffer_full(void); | |||
175 | static int flush_pending_control(struct playlist_info* playlist); | 178 | static int flush_pending_control(struct playlist_info* playlist); |
176 | static int rotate_index(const struct playlist_info* playlist, int index); | 179 | static int rotate_index(const struct playlist_info* playlist, int index); |
177 | 180 | ||
181 | #ifdef HAVE_DIRCACHE | ||
182 | #define PLAYLIST_LOAD_POINTERS 1 | ||
183 | |||
184 | static struct event_queue playlist_queue; | ||
185 | static long playlist_stack[(DEFAULT_STACK_SIZE + 0x400)/sizeof(long)]; | ||
186 | static const char playlist_thread_name[] = "playlist cachectrl"; | ||
187 | #endif | ||
188 | |||
178 | /* | 189 | /* |
179 | * remove any files and indices associated with the playlist | 190 | * remove any files and indices associated with the playlist |
180 | */ | 191 | */ |
@@ -394,11 +405,15 @@ static int add_indices_to_playlist(struct playlist_info* playlist, | |||
394 | { | 405 | { |
395 | /* Store a new entry */ | 406 | /* Store a new entry */ |
396 | playlist->indices[ playlist->amount ] = i+count; | 407 | playlist->indices[ playlist->amount ] = i+count; |
397 | playlist->amount++; | 408 | #ifdef HAVE_DIRCACHE |
409 | if (playlist->filenames) | ||
410 | playlist->filenames[ playlist->amount ] = NULL; | ||
411 | #endif | ||
398 | if ( playlist->amount >= playlist->max_playlist_size ) { | 412 | if ( playlist->amount >= playlist->max_playlist_size ) { |
399 | display_buffer_full(); | 413 | display_buffer_full(); |
400 | return -1; | 414 | return -1; |
401 | } | 415 | } |
416 | playlist->amount++; | ||
402 | } | 417 | } |
403 | } | 418 | } |
404 | } | 419 | } |
@@ -406,6 +421,10 @@ static int add_indices_to_playlist(struct playlist_info* playlist, | |||
406 | i+= count; | 421 | i+= count; |
407 | } | 422 | } |
408 | 423 | ||
424 | #ifdef HAVE_DIRCACHE | ||
425 | queue_post(&playlist_queue, PLAYLIST_LOAD_POINTERS, 0); | ||
426 | #endif | ||
427 | |||
409 | return 0; | 428 | return 0; |
410 | } | 429 | } |
411 | 430 | ||
@@ -499,8 +518,14 @@ static int add_track_to_playlist(struct playlist_info* playlist, | |||
499 | 518 | ||
500 | /* shift indices so that track can be added */ | 519 | /* shift indices so that track can be added */ |
501 | for (i=playlist->amount; i>insert_position; i--) | 520 | for (i=playlist->amount; i>insert_position; i--) |
521 | { | ||
502 | playlist->indices[i] = playlist->indices[i-1]; | 522 | playlist->indices[i] = playlist->indices[i-1]; |
503 | 523 | #ifdef HAVE_DIRCACHE | |
524 | if (playlist->filenames) | ||
525 | playlist->filenames[i] = playlist->filenames[i-1]; | ||
526 | #endif | ||
527 | } | ||
528 | |||
504 | /* update stored indices if needed */ | 529 | /* update stored indices if needed */ |
505 | if (playlist->amount > 0 && insert_position <= playlist->index) | 530 | if (playlist->amount > 0 && insert_position <= playlist->index) |
506 | playlist->index++; | 531 | playlist->index++; |
@@ -554,6 +579,12 @@ static int add_track_to_playlist(struct playlist_info* playlist, | |||
554 | 579 | ||
555 | playlist->indices[insert_position] = flags | seek_pos; | 580 | playlist->indices[insert_position] = flags | seek_pos; |
556 | 581 | ||
582 | #ifdef HAVE_DIRCACHE | ||
583 | if (playlist->filenames) | ||
584 | playlist->filenames[insert_position] = NULL; | ||
585 | queue_post(&playlist_queue, PLAYLIST_LOAD_POINTERS, 0); | ||
586 | #endif | ||
587 | |||
557 | playlist->amount++; | 588 | playlist->amount++; |
558 | playlist->num_inserted_tracks++; | 589 | playlist->num_inserted_tracks++; |
559 | 590 | ||
@@ -693,7 +724,13 @@ static int remove_track_from_playlist(struct playlist_info* playlist, | |||
693 | 724 | ||
694 | /* shift indices now that track has been removed */ | 725 | /* shift indices now that track has been removed */ |
695 | for (i=position; i<playlist->amount; i++) | 726 | for (i=position; i<playlist->amount; i++) |
727 | { | ||
696 | playlist->indices[i] = playlist->indices[i+1]; | 728 | playlist->indices[i] = playlist->indices[i+1]; |
729 | #ifdef HAVE_DIRCACHE | ||
730 | if (playlist->filenames) | ||
731 | playlist->filenames[i] = playlist->filenames[i+1]; | ||
732 | #endif | ||
733 | } | ||
697 | 734 | ||
698 | playlist->amount--; | 735 | playlist->amount--; |
699 | 736 | ||
@@ -780,6 +817,14 @@ static int randomise_playlist(struct playlist_info* playlist, | |||
780 | store = playlist->indices[candidate]; | 817 | store = playlist->indices[candidate]; |
781 | playlist->indices[candidate] = playlist->indices[count]; | 818 | playlist->indices[candidate] = playlist->indices[count]; |
782 | playlist->indices[count] = store; | 819 | playlist->indices[count] = store; |
820 | #ifdef HAVE_DIRCACHE | ||
821 | if (playlist->filenames) | ||
822 | { | ||
823 | store = (int)playlist->filenames[candidate]; | ||
824 | playlist->filenames[candidate] = playlist->filenames[count]; | ||
825 | playlist->filenames[count] = (struct dircache_entry *)store; | ||
826 | } | ||
827 | #endif | ||
783 | } | 828 | } |
784 | 829 | ||
785 | if (start_current) | 830 | if (start_current) |
@@ -817,6 +862,13 @@ static int sort_playlist(struct playlist_info* playlist, bool start_current, | |||
817 | qsort(playlist->indices, playlist->amount, | 862 | qsort(playlist->indices, playlist->amount, |
818 | sizeof(playlist->indices[0]), compare); | 863 | sizeof(playlist->indices[0]), compare); |
819 | 864 | ||
865 | #ifdef HAVE_DIRCACHE | ||
866 | /** We need to re-check the song names from disk because qsort can't | ||
867 | * sort two arrays at once :/ | ||
868 | * FIXME: Please implement a better way to do this. */ | ||
869 | queue_post(&playlist_queue, PLAYLIST_LOAD_POINTERS, 0); | ||
870 | #endif | ||
871 | |||
820 | if (start_current) | 872 | if (start_current) |
821 | find_and_set_playlist_index(playlist, current); | 873 | find_and_set_playlist_index(playlist, current); |
822 | 874 | ||
@@ -1040,10 +1092,88 @@ static int compare(const void* p1, const void* p2) | |||
1040 | return *e1 - *e2; | 1092 | return *e1 - *e2; |
1041 | } | 1093 | } |
1042 | 1094 | ||
1095 | #ifdef HAVE_DIRCACHE | ||
1096 | /** | ||
1097 | * Thread to update filename pointers to dircache on background | ||
1098 | * without affecting playlist load up performance. | ||
1099 | */ | ||
1100 | static void playlist_thread(void) | ||
1101 | { | ||
1102 | struct event ev; | ||
1103 | bool dirty_pointers = false; | ||
1104 | static char tmp[MAX_PATH+1]; | ||
1105 | |||
1106 | struct playlist_info *playlist; | ||
1107 | int index; | ||
1108 | int seek; | ||
1109 | bool control_file; | ||
1110 | |||
1111 | while (1) | ||
1112 | { | ||
1113 | queue_wait_w_tmo(&playlist_queue, &ev, HZ*5); | ||
1114 | |||
1115 | switch (ev.id) | ||
1116 | { | ||
1117 | case PLAYLIST_LOAD_POINTERS: | ||
1118 | dirty_pointers = true; | ||
1119 | break ; | ||
1120 | |||
1121 | /* Start the background scanning after 5s. */ | ||
1122 | case SYS_TIMEOUT: | ||
1123 | if (!dirty_pointers) | ||
1124 | break ; | ||
1125 | |||
1126 | playlist = ¤t_playlist; | ||
1127 | if (!dircache_is_enabled() || !playlist->filenames | ||
1128 | || playlist->amount <= 0) | ||
1129 | break ; | ||
1130 | |||
1131 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | ||
1132 | cpu_boost(true); | ||
1133 | #endif | ||
1134 | for (index = 0; index < playlist->amount | ||
1135 | && queue_empty(&playlist_queue); index++) | ||
1136 | { | ||
1137 | /* Process only pointers that are not already loaded. */ | ||
1138 | if (playlist->filenames[index]) | ||
1139 | continue ; | ||
1140 | |||
1141 | control_file = playlist->indices[index] & PLAYLIST_INSERT_TYPE_MASK; | ||
1142 | seek = playlist->indices[index] & PLAYLIST_SEEK_MASK; | ||
1143 | |||
1144 | /* Load the filename from playlist file. */ | ||
1145 | if (get_filename(playlist, index, seek, control_file, tmp, | ||
1146 | sizeof(tmp)) < 0) | ||
1147 | break ; | ||
1148 | |||
1149 | /* Set the dircache entry pointer. */ | ||
1150 | playlist->filenames[index] = dircache_get_entry_ptr(tmp); | ||
1151 | |||
1152 | /* And be on background so user doesn't notice any delays. */ | ||
1153 | yield(); | ||
1154 | } | ||
1155 | |||
1156 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | ||
1157 | cpu_boost(false); | ||
1158 | #endif | ||
1159 | dirty_pointers = false; | ||
1160 | break ; | ||
1161 | |||
1162 | #ifndef SIMULATOR | ||
1163 | case SYS_USB_CONNECTED: | ||
1164 | usb_acknowledge(SYS_USB_CONNECTED_ACK); | ||
1165 | usb_wait_for_disconnect(&playlist_queue); | ||
1166 | break ; | ||
1167 | #endif | ||
1168 | } | ||
1169 | } | ||
1170 | } | ||
1171 | #endif | ||
1172 | |||
1043 | /* | 1173 | /* |
1044 | * gets pathname for track at seek index | 1174 | * gets pathname for track at seek index |
1045 | */ | 1175 | */ |
1046 | static int get_filename(struct playlist_info* playlist, int seek, | 1176 | static int get_filename(struct playlist_info* playlist, int index, int seek, |
1047 | bool control_file, char *buf, int buf_length) | 1177 | bool control_file, char *buf, int buf_length) |
1048 | { | 1178 | { |
1049 | int fd; | 1179 | int fd; |
@@ -1054,13 +1184,26 @@ static int get_filename(struct playlist_info* playlist, int seek, | |||
1054 | if (buf_length > MAX_PATH+1) | 1184 | if (buf_length > MAX_PATH+1) |
1055 | buf_length = MAX_PATH+1; | 1185 | buf_length = MAX_PATH+1; |
1056 | 1186 | ||
1057 | if (playlist->in_ram && !control_file) | 1187 | #ifdef HAVE_DIRCACHE |
1188 | if (dircache_is_enabled() && playlist->filenames) | ||
1189 | { | ||
1190 | if (playlist->filenames[index] != NULL) | ||
1191 | { | ||
1192 | dircache_copy_path(playlist->filenames[index], tmp_buf, sizeof(tmp_buf)-1); | ||
1193 | max = strlen(tmp_buf) + 1; | ||
1194 | } | ||
1195 | } | ||
1196 | #else | ||
1197 | (void)index; | ||
1198 | #endif | ||
1199 | |||
1200 | if (playlist->in_ram && !control_file && max < 0) | ||
1058 | { | 1201 | { |
1059 | strncpy(tmp_buf, &playlist->buffer[seek], sizeof(tmp_buf)); | 1202 | strncpy(tmp_buf, &playlist->buffer[seek], sizeof(tmp_buf)); |
1060 | tmp_buf[MAX_PATH] = '\0'; | 1203 | tmp_buf[MAX_PATH] = '\0'; |
1061 | max = strlen(tmp_buf) + 1; | 1204 | max = strlen(tmp_buf) + 1; |
1062 | } | 1205 | } |
1063 | else | 1206 | else if (max < 0) |
1064 | { | 1207 | { |
1065 | if (control_file) | 1208 | if (control_file) |
1066 | fd = playlist->control_fd; | 1209 | fd = playlist->control_fd; |
@@ -1482,6 +1625,16 @@ void playlist_init(void) | |||
1482 | playlist->buffer = buffer_alloc(playlist->buffer_size); | 1625 | playlist->buffer = buffer_alloc(playlist->buffer_size); |
1483 | mutex_init(&playlist->control_mutex); | 1626 | mutex_init(&playlist->control_mutex); |
1484 | empty_playlist(playlist, true); | 1627 | empty_playlist(playlist, true); |
1628 | |||
1629 | #ifdef HAVE_DIRCACHE | ||
1630 | playlist->filenames = buffer_alloc( | ||
1631 | playlist->max_playlist_size * sizeof(int)); | ||
1632 | memset(playlist->filenames, 0, | ||
1633 | playlist->max_playlist_size * sizeof(int)); | ||
1634 | create_thread(playlist_thread, playlist_stack, sizeof(playlist_stack), | ||
1635 | playlist_thread_name); | ||
1636 | queue_init(&playlist_queue); | ||
1637 | #endif | ||
1485 | } | 1638 | } |
1486 | 1639 | ||
1487 | /* | 1640 | /* |
@@ -1906,8 +2059,9 @@ int playlist_add(const char *filename) | |||
1906 | return -1; | 2059 | return -1; |
1907 | } | 2060 | } |
1908 | 2061 | ||
1909 | playlist->indices[playlist->amount++] = playlist->buffer_end_pos; | 2062 | playlist->indices[playlist->amount] = playlist->buffer_end_pos; |
1910 | 2063 | playlist->amount++; | |
2064 | |||
1911 | strcpy(&playlist->buffer[playlist->buffer_end_pos], filename); | 2065 | strcpy(&playlist->buffer[playlist->buffer_end_pos], filename); |
1912 | playlist->buffer_end_pos += len; | 2066 | playlist->buffer_end_pos += len; |
1913 | playlist->buffer[playlist->buffer_end_pos++] = '\0'; | 2067 | playlist->buffer[playlist->buffer_end_pos++] = '\0'; |
@@ -1991,7 +2145,7 @@ char* playlist_peek(int steps) | |||
1991 | control_file = playlist->indices[index] & PLAYLIST_INSERT_TYPE_MASK; | 2145 | control_file = playlist->indices[index] & PLAYLIST_INSERT_TYPE_MASK; |
1992 | seek = playlist->indices[index] & PLAYLIST_SEEK_MASK; | 2146 | seek = playlist->indices[index] & PLAYLIST_SEEK_MASK; |
1993 | 2147 | ||
1994 | if (get_filename(playlist, seek, control_file, now_playing, | 2148 | if (get_filename(playlist, index, seek, control_file, now_playing, |
1995 | MAX_PATH+1) < 0) | 2149 | MAX_PATH+1) < 0) |
1996 | return NULL; | 2150 | return NULL; |
1997 | 2151 | ||
@@ -2003,11 +2157,21 @@ char* playlist_peek(int steps) | |||
2003 | (workaround for buggy playlist creation tools) */ | 2157 | (workaround for buggy playlist creation tools) */ |
2004 | while (temp_ptr) | 2158 | while (temp_ptr) |
2005 | { | 2159 | { |
2006 | fd = open(temp_ptr, O_RDONLY); | 2160 | #ifdef HAVE_DIRCACHE |
2007 | if (fd >= 0) | 2161 | if (dircache_is_enabled()) |
2008 | { | 2162 | { |
2009 | close(fd); | 2163 | if (dircache_get_entry_ptr(temp_ptr)) |
2010 | break; | 2164 | break; |
2165 | } | ||
2166 | else | ||
2167 | #endif | ||
2168 | { | ||
2169 | fd = open(temp_ptr, O_RDONLY); | ||
2170 | if (fd >= 0) | ||
2171 | { | ||
2172 | close(fd); | ||
2173 | break; | ||
2174 | } | ||
2011 | } | 2175 | } |
2012 | 2176 | ||
2013 | temp_ptr = strchr(temp_ptr+1, '/'); | 2177 | temp_ptr = strchr(temp_ptr+1, '/'); |
@@ -2278,16 +2442,26 @@ int playlist_create_ex(struct playlist_info* playlist, | |||
2278 | { | 2442 | { |
2279 | int num_indices = index_buffer_size / sizeof(int); | 2443 | int num_indices = index_buffer_size / sizeof(int); |
2280 | 2444 | ||
2445 | #ifdef HAVE_DIRCACHE | ||
2446 | num_indices /= 2; | ||
2447 | #endif | ||
2281 | if (num_indices > global_settings.max_files_in_playlist) | 2448 | if (num_indices > global_settings.max_files_in_playlist) |
2282 | num_indices = global_settings.max_files_in_playlist; | 2449 | num_indices = global_settings.max_files_in_playlist; |
2283 | 2450 | ||
2284 | playlist->max_playlist_size = num_indices; | 2451 | playlist->max_playlist_size = num_indices; |
2285 | playlist->indices = index_buffer; | 2452 | playlist->indices = index_buffer; |
2453 | #ifdef HAVE_DIRCACHE | ||
2454 | playlist->filenames = (const struct dircache_entry **) | ||
2455 | &playlist->indices[num_indices]; | ||
2456 | #endif | ||
2286 | } | 2457 | } |
2287 | else | 2458 | else |
2288 | { | 2459 | { |
2289 | playlist->max_playlist_size = current_playlist.max_playlist_size; | 2460 | playlist->max_playlist_size = current_playlist.max_playlist_size; |
2290 | playlist->indices = current_playlist.indices; | 2461 | playlist->indices = current_playlist.indices; |
2462 | #ifdef HAVE_DIRCACHE | ||
2463 | playlist->filenames = current_playlist.filenames; | ||
2464 | #endif | ||
2291 | } | 2465 | } |
2292 | 2466 | ||
2293 | playlist->buffer_size = 0; | 2467 | playlist->buffer_size = 0; |
@@ -2336,9 +2510,15 @@ int playlist_set_current(struct playlist_info* playlist) | |||
2336 | current_playlist.dirlen = playlist->dirlen; | 2510 | current_playlist.dirlen = playlist->dirlen; |
2337 | 2511 | ||
2338 | if (playlist->indices && playlist->indices != current_playlist.indices) | 2512 | if (playlist->indices && playlist->indices != current_playlist.indices) |
2513 | { | ||
2339 | memcpy(current_playlist.indices, playlist->indices, | 2514 | memcpy(current_playlist.indices, playlist->indices, |
2340 | playlist->max_playlist_size*sizeof(int)); | 2515 | playlist->max_playlist_size*sizeof(int)); |
2341 | 2516 | #ifdef HAVE_DIRCACHE | |
2517 | memcpy(current_playlist.filenames, playlist->filenames, | ||
2518 | playlist->max_playlist_size*sizeof(int)); | ||
2519 | #endif | ||
2520 | } | ||
2521 | |||
2342 | current_playlist.first_index = playlist->first_index; | 2522 | current_playlist.first_index = playlist->first_index; |
2343 | current_playlist.amount = playlist->amount; | 2523 | current_playlist.amount = playlist->amount; |
2344 | current_playlist.last_insert_pos = playlist->last_insert_pos; | 2524 | current_playlist.last_insert_pos = playlist->last_insert_pos; |
@@ -2620,7 +2800,7 @@ int playlist_move(struct playlist_info* playlist, int index, int new_index) | |||
2620 | queue = playlist->indices[index] & PLAYLIST_QUEUE_MASK; | 2800 | queue = playlist->indices[index] & PLAYLIST_QUEUE_MASK; |
2621 | seek = playlist->indices[index] & PLAYLIST_SEEK_MASK; | 2801 | seek = playlist->indices[index] & PLAYLIST_SEEK_MASK; |
2622 | 2802 | ||
2623 | if (get_filename(playlist, seek, control_file, filename, | 2803 | if (get_filename(playlist, index, seek, control_file, filename, |
2624 | sizeof(filename)) < 0) | 2804 | sizeof(filename)) < 0) |
2625 | return -1; | 2805 | return -1; |
2626 | 2806 | ||
@@ -2812,7 +2992,7 @@ int playlist_get_track_info(struct playlist_info* playlist, int index, | |||
2812 | control_file = playlist->indices[index] & PLAYLIST_INSERT_TYPE_MASK; | 2992 | control_file = playlist->indices[index] & PLAYLIST_INSERT_TYPE_MASK; |
2813 | seek = playlist->indices[index] & PLAYLIST_SEEK_MASK; | 2993 | seek = playlist->indices[index] & PLAYLIST_SEEK_MASK; |
2814 | 2994 | ||
2815 | if (get_filename(playlist, seek, control_file, info->filename, | 2995 | if (get_filename(playlist, index, seek, control_file, info->filename, |
2816 | sizeof(info->filename)) < 0) | 2996 | sizeof(info->filename)) < 0) |
2817 | return -1; | 2997 | return -1; |
2818 | 2998 | ||
@@ -2883,7 +3063,7 @@ int playlist_save(struct playlist_info* playlist, char *filename) | |||
2883 | /* Don't save queued files */ | 3063 | /* Don't save queued files */ |
2884 | if (!queue) | 3064 | if (!queue) |
2885 | { | 3065 | { |
2886 | if (get_filename(playlist, seek, control_file, tmp_buf, | 3066 | if (get_filename(playlist, index, seek, control_file, tmp_buf, |
2887 | MAX_PATH+1) < 0) | 3067 | MAX_PATH+1) < 0) |
2888 | { | 3068 | { |
2889 | result = -1; | 3069 | result = -1; |