summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/playlist.c257
-rw-r--r--apps/playlist.h15
2 files changed, 65 insertions, 207 deletions
diff --git a/apps/playlist.c b/apps/playlist.c
index c1d280595c..c122dac048 100644
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -387,178 +387,55 @@ static int rotate_index(const struct playlist_info* playlist, int index)
387 return index; 387 return index;
388} 388}
389 389
390/* 390static void sync_control_unlocked(struct playlist_info* playlist)
391 * sync control file to disk
392 */
393static void sync_control(struct playlist_info* playlist, bool force)
394{ 391{
395#ifndef HAVE_DIRCACHE /*non dircache targets sync every time */
396 force = true;
397#endif
398
399 if (playlist->started && force)
400 {
401 if (playlist->pending_control_sync)
402 {
403 playlist_write_lock(playlist);
404
405 fsync(playlist->control_fd);
406 playlist->pending_control_sync = false;
407
408 playlist_write_unlock(playlist);
409 }
410 }
411}
412
413static int flush_cached_control_unlocked(struct playlist_info* playlist);
414
415#if USING_STORAGE_CALLBACK
416static void flush_control_cache_idle_cb(unsigned short id, void *ev, void *ud)
417{
418 (void)id;
419 (void)ev;
420
421 struct playlist_info *playlist = ud;
422 playlist_write_lock(playlist);
423
424 if (playlist->control_fd >= 0) 392 if (playlist->control_fd >= 0)
425 flush_cached_control_unlocked(playlist); 393 fsync(playlist->control_fd);
426
427 playlist_write_unlock(playlist);
428} 394}
429#endif
430 395
431/* 396static int update_control_unlocked(struct playlist_info* playlist,
432 * Flush any cached control commands to disk. Called when playlist is being 397 enum playlist_command command, int i1, int i2,
433 * modified. Returns 0 on success and -1 on failure. 398 const char* s1, const char* s2, int *seekpos)
434 */
435static int flush_cached_control_unlocked(struct playlist_info* playlist)
436{ 399{
437 int result = 0; 400 int fd = playlist->control_fd;
438 401 int result;
439 if (playlist->num_cached <= 0)
440 return 0;
441 402
442 lseek(playlist->control_fd, 0, SEEK_END); 403 lseek(fd, 0, SEEK_END);
443 404
444 for (int i = 0; i < playlist->num_cached; i++) 405 switch (command)
445 { 406 {
446 struct playlist_control_cache* cache = &playlist->control_cache[i]; 407 case PLAYLIST_COMMAND_PLAYLIST:
447 switch (cache->command) 408 result = fdprintf(fd, "P:%d:%s:%s\n", i1, s1, s2);
409 break;
410 case PLAYLIST_COMMAND_ADD:
411 case PLAYLIST_COMMAND_QUEUE:
412 result = fdprintf(fd, "%c:%d:%d:",
413 command == PLAYLIST_COMMAND_ADD ? 'A' : 'Q', i1, i2);
414 if (result > 0)
448 { 415 {
449 case PLAYLIST_COMMAND_PLAYLIST: 416 *seekpos = lseek(fd, 0, SEEK_CUR);
450 result = fdprintf(playlist->control_fd, "P:%d:%s:%s\n", 417 result = fdprintf(fd, "%s\n", s1);
451 cache->i1, cache->s1, cache->s2);
452 break;
453 case PLAYLIST_COMMAND_ADD:
454 case PLAYLIST_COMMAND_QUEUE:
455 result = fdprintf(playlist->control_fd, "%c:%d:%d:",
456 (cache->command == PLAYLIST_COMMAND_ADD)?'A':'Q',
457 cache->i1, cache->i2);
458 if (result > 0)
459 {
460 /* save the position in file where name is written */
461 int* seek_pos = (int *)cache->data;
462 *seek_pos = lseek(playlist->control_fd, 0, SEEK_CUR);
463 result = fdprintf(playlist->control_fd, "%s\n", cache->s1);
464 }
465 break;
466 case PLAYLIST_COMMAND_DELETE:
467 result = fdprintf(playlist->control_fd, "D:%d\n", cache->i1);
468 break;
469 case PLAYLIST_COMMAND_SHUFFLE:
470 result = fdprintf(playlist->control_fd, "S:%d:%d\n",
471 cache->i1, cache->i2);
472 break;
473 case PLAYLIST_COMMAND_UNSHUFFLE:
474 result = fdprintf(playlist->control_fd, "U:%d\n", cache->i1);
475 break;
476 case PLAYLIST_COMMAND_RESET:
477 result = fdprintf(playlist->control_fd, "%s\n", "R");
478 break;
479 case PLAYLIST_COMMAND_CLEAR:
480 result = fdprintf(playlist->control_fd, "%s\n", "C");
481 break;
482 default:
483 break;
484 } 418 }
485 419 break;
486 if (result <= 0) 420 case PLAYLIST_COMMAND_DELETE:
487 break; 421 result = fdprintf(fd, "D:%d\n", i1);
488 } 422 break;
489 423 case PLAYLIST_COMMAND_SHUFFLE:
490 if (result > 0) 424 result = fdprintf(fd, "S:%d:%d\n", i1, i2);
491 { 425 break;
492 playlist->num_cached = 0; 426 case PLAYLIST_COMMAND_UNSHUFFLE:
493 playlist->pending_control_sync = true; 427 result = fdprintf(fd, "U:%d\n", i1);
494 result = 0; 428 break;
495 } 429 case PLAYLIST_COMMAND_RESET:
496 else 430 result = write(fd, "R\n", 2);
497 { 431 break;
498 /* At this point the control file is likely corrupted. We still 432 case PLAYLIST_COMMAND_CLEAR:
499 * need to clear the cache to avoid a buffer overflow from the 433 result = write(fd, "C\n", 2);
500 * next command. It's unsafe to splash() because this function 434 break;
501 * can be called off the main thread. 435 default:
502 * 436 return -1;
503 * TODO: recover from failed playlist control file writes.
504 */
505 playlist->num_cached = 0;
506 result = -1;
507 }
508
509#if USING_STORAGE_CALLBACK
510 remove_event_ex(DISK_EVENT_SPINUP, flush_control_cache_idle_cb, playlist);
511#endif
512 return result;
513}
514
515/*
516 * Update control data with new command. Depending on the command, it may be
517 * cached or flushed to disk.
518 */
519static int update_control(struct playlist_info* playlist,
520 enum playlist_command command, int i1, int i2,
521 const char* s1, const char* s2, void* data)
522{
523 int result = 0;
524 struct playlist_control_cache* cache;
525 bool flush = false;
526
527 playlist_write_lock(playlist);
528 cache = &playlist->control_cache[playlist->num_cached++];
529
530 cache->command = command;
531 cache->i1 = i1;
532 cache->i2 = i2;
533 cache->s1 = s1;
534 cache->s2 = s2;
535 cache->data = data;
536
537 switch (command)
538 {
539 case PLAYLIST_COMMAND_PLAYLIST:
540 case PLAYLIST_COMMAND_ADD:
541 case PLAYLIST_COMMAND_QUEUE:
542 /*
543 * These commands can use s1/s2, which may point to
544 * stack allocated buffers, so flush them immediately.
545 */
546 flush = true;
547 break;
548 default:
549 break;
550 }
551
552 if (flush || playlist->num_cached == PLAYLIST_MAX_CACHE)
553 result = flush_cached_control_unlocked(playlist);
554 else
555 {
556#if USING_STORAGE_CALLBACK
557 add_event_ex(DISK_EVENT_SPINUP, true, flush_control_cache_idle_cb, playlist);
558#endif
559 } 437 }
560 438
561 playlist_write_unlock(playlist);
562 return result; 439 return result;
563} 440}
564 441
@@ -602,7 +479,6 @@ static void empty_playlist_unlocked(struct playlist_info* playlist, bool resume)
602 playlist->filename[0] = '\0'; 479 playlist->filename[0] = '\0';
603 480
604 playlist->seed = 0; 481 playlist->seed = 0;
605 playlist->num_cached = 0;
606 482
607 playlist->utf8 = true; 483 playlist->utf8 = true;
608 playlist->control_created = false; 484 playlist->control_created = false;
@@ -617,7 +493,6 @@ static void empty_playlist_unlocked(struct playlist_info* playlist, bool resume)
617 playlist->last_insert_pos = -1; 493 playlist->last_insert_pos = -1;
618 494
619 playlist->started = false; 495 playlist->started = false;
620 playlist->pending_control_sync = false;
621 496
622 if (!resume && playlist == &current_playlist) 497 if (!resume && playlist == &current_playlist)
623 { 498 {
@@ -713,9 +588,9 @@ static void new_playlist_unlocked(struct playlist_info* playlist,
713 588
714 if (playlist->control_fd >= 0) 589 if (playlist->control_fd >= 0)
715 { 590 {
716 update_control(playlist, PLAYLIST_COMMAND_PLAYLIST, 591 update_control_unlocked(playlist, PLAYLIST_COMMAND_PLAYLIST,
717 PLAYLIST_CONTROL_FILE_VERSION, -1, dirused, fileused, NULL); 592 PLAYLIST_CONTROL_FILE_VERSION, -1, dirused, fileused, NULL);
718 sync_control(playlist, false); 593 sync_control_unlocked(playlist);
719 } 594 }
720} 595}
721 596
@@ -740,9 +615,9 @@ static int check_control(struct playlist_info* playlist)
740 615
741 playlist->filename[playlist->dirlen-1] = '\0'; 616 playlist->filename[playlist->dirlen-1] = '\0';
742 617
743 update_control(playlist, PLAYLIST_COMMAND_PLAYLIST, 618 update_control_unlocked(playlist, PLAYLIST_COMMAND_PLAYLIST,
744 PLAYLIST_CONTROL_FILE_VERSION, -1, dir, file, NULL); 619 PLAYLIST_CONTROL_FILE_VERSION, -1, dir, file, NULL);
745 sync_control(playlist, false); 620 sync_control_unlocked(playlist);
746 playlist->filename[playlist->dirlen-1] = c; 621 playlist->filename[playlist->dirlen-1] = c;
747 } 622 }
748 } 623 }
@@ -824,9 +699,8 @@ static int recreate_control_unlocked(struct playlist_info* playlist)
824 699
825 playlist->filename[playlist->dirlen-1] = '\0'; 700 playlist->filename[playlist->dirlen-1] = '\0';
826 701
827 /* cannot call update_control() because of mutex */ 702 update_control_unlocked(playlist, PLAYLIST_COMMAND_PLAYLIST,
828 result = fdprintf(playlist->control_fd, "P:%d:%s:%s\n", 703 PLAYLIST_CONTROL_FILE_VERSION, -1, dir, file, NULL);
829 PLAYLIST_CONTROL_FILE_VERSION, dir, file);
830 704
831 playlist->filename[playlist->dirlen-1] = c; 705 playlist->filename[playlist->dirlen-1] = c;
832 706
@@ -1381,8 +1255,9 @@ static int remove_all_tracks_unlocked(struct playlist_info *playlist, bool write
1381 1255
1382 if (write && playlist->control_fd >= 0) 1256 if (write && playlist->control_fd >= 0)
1383 { 1257 {
1384 update_control(playlist, PLAYLIST_COMMAND_CLEAR, -1, -1, NULL, NULL, NULL); 1258 update_control_unlocked(playlist, PLAYLIST_COMMAND_CLEAR,
1385 sync_control(playlist, false); 1259 -1, -1, NULL, NULL, NULL);
1260 sync_control_unlocked(playlist);
1386 } 1261 }
1387 1262
1388 return 0; 1263 return 0;
@@ -1534,7 +1409,7 @@ static int add_track_to_playlist_unlocked(struct playlist_info* playlist,
1534 1409
1535 if (seek_pos < 0 && playlist->control_fd >= 0) 1410 if (seek_pos < 0 && playlist->control_fd >= 0)
1536 { 1411 {
1537 int result = update_control(playlist, 1412 int result = update_control_unlocked(playlist,
1538 (queue?PLAYLIST_COMMAND_QUEUE:PLAYLIST_COMMAND_ADD), position, 1413 (queue?PLAYLIST_COMMAND_QUEUE:PLAYLIST_COMMAND_ADD), position,
1539 playlist->last_insert_pos, filename, NULL, &seek_pos); 1414 playlist->last_insert_pos, filename, NULL, &seek_pos);
1540 1415
@@ -1639,10 +1514,10 @@ static int remove_track_unlocked(struct playlist_info* playlist,
1639 1514
1640 if (write && playlist->control_fd >= 0) 1515 if (write && playlist->control_fd >= 0)
1641 { 1516 {
1642 result = update_control(playlist, PLAYLIST_COMMAND_DELETE, 1517 result = update_control_unlocked(playlist, PLAYLIST_COMMAND_DELETE,
1643 position, -1, NULL, NULL, NULL); 1518 position, -1, NULL, NULL, NULL);
1644 if (result >= 0) 1519 if (result >= 0)
1645 sync_control(playlist, false); 1520 sync_control_unlocked(playlist);
1646 } 1521 }
1647 1522
1648 return result; 1523 return result;
@@ -1720,7 +1595,7 @@ static int randomise_playlist_unlocked(struct playlist_info* playlist,
1720 1595
1721 if (write) 1596 if (write)
1722 { 1597 {
1723 update_control(playlist, PLAYLIST_COMMAND_SHUFFLE, seed, 1598 update_control_unlocked(playlist, PLAYLIST_COMMAND_SHUFFLE, seed,
1724 playlist->first_index, NULL, NULL, NULL); 1599 playlist->first_index, NULL, NULL, NULL);
1725 } 1600 }
1726 1601
@@ -1785,7 +1660,7 @@ static int sort_playlist_unlocked(struct playlist_info* playlist,
1785 if (write && playlist->control_fd >= 0) 1660 if (write && playlist->control_fd >= 0)
1786 { 1661 {
1787 playlist->first_index = 0; 1662 playlist->first_index = 0;
1788 update_control(playlist, PLAYLIST_COMMAND_UNSHUFFLE, 1663 update_control_unlocked(playlist, PLAYLIST_COMMAND_UNSHUFFLE,
1789 playlist->first_index, -1, NULL, NULL, NULL); 1664 playlist->first_index, -1, NULL, NULL, NULL);
1790 } 1665 }
1791 1666
@@ -2144,10 +2019,7 @@ void playlist_shutdown(void)
2144 playlist_write_lock(playlist); 2019 playlist_write_lock(playlist);
2145 2020
2146 if (playlist->control_fd >= 0) 2021 if (playlist->control_fd >= 0)
2147 {
2148 flush_cached_control_unlocked(playlist);
2149 pl_close_control(playlist); 2022 pl_close_control(playlist);
2150 }
2151 2023
2152 playlist_write_unlock(playlist); 2024 playlist_write_unlock(playlist);
2153} 2025}
@@ -2645,7 +2517,7 @@ int playlist_insert_directory(struct playlist_info* playlist,
2645 result = playlist_directory_tracksearch(dirname, recurse, 2517 result = playlist_directory_tracksearch(dirname, recurse,
2646 directory_search_callback, &context); 2518 directory_search_callback, &context);
2647 2519
2648 sync_control(playlist, false); 2520 sync_control_unlocked(playlist);
2649 2521
2650 cpu_boost(false); 2522 cpu_boost(false);
2651 2523
@@ -2779,7 +2651,7 @@ int playlist_insert_playlist(struct playlist_info* playlist, const char *filenam
2779 2651
2780 close(fd); 2652 close(fd);
2781 2653
2782 sync_control(playlist, false); 2654 sync_control_unlocked(playlist);
2783 2655
2784 display_playlist_count(count, count_str, true); 2656 display_playlist_count(count, count_str, true);
2785 2657
@@ -3092,15 +2964,16 @@ int playlist_next(int steps)
3092 playlist->last_insert_pos = -1; 2964 playlist->last_insert_pos = -1;
3093 if (playlist->control_fd >= 0) 2965 if (playlist->control_fd >= 0)
3094 { 2966 {
3095 int result = update_control(playlist, PLAYLIST_COMMAND_RESET, 2967 int result = update_control_unlocked(playlist,
3096 -1, -1, NULL, NULL, NULL); 2968 PLAYLIST_COMMAND_RESET,
3097 2969 -1, -1, NULL, NULL, NULL);
3098 if (result < 0) 2970 if (result < 0)
3099 { 2971 {
3100 index = result; 2972 index = result;
3101 goto out; 2973 goto out;
3102 } 2974 }
3103 sync_control(playlist, false); 2975
2976 sync_control_unlocked(playlist);
3104 } 2977 }
3105 } 2978 }
3106 } 2979 }
@@ -3928,11 +3801,6 @@ int playlist_set_current(struct playlist_info* playlist)
3928 current_playlist.seed = playlist->seed; 3801 current_playlist.seed = playlist->seed;
3929 current_playlist.modified = playlist->modified; 3802 current_playlist.modified = playlist->modified;
3930 3803
3931 memcpy(current_playlist.control_cache, playlist->control_cache,
3932 sizeof(current_playlist.control_cache));
3933
3934 current_playlist.num_cached = playlist->num_cached;
3935 current_playlist.pending_control_sync = playlist->pending_control_sync;
3936 result = 0; 3804 result = 0;
3937 3805
3938out: 3806out:
@@ -4034,7 +3902,7 @@ void playlist_start(int start_index, unsigned long elapsed,
4034 playlist->index = start_index; 3902 playlist->index = start_index;
4035 playlist->started = true; 3903 playlist->started = true;
4036 3904
4037 sync_control(playlist, false); 3905 sync_control_unlocked(playlist);
4038 3906
4039 playlist_write_unlock(playlist); 3907 playlist_write_unlock(playlist);
4040 3908
@@ -4047,7 +3915,12 @@ void playlist_sync(struct playlist_info* playlist)
4047 if (!playlist) 3915 if (!playlist)
4048 playlist = &current_playlist; 3916 playlist = &current_playlist;
4049 3917
4050 sync_control(playlist, false); 3918 playlist_write_lock(playlist);
3919
3920 sync_control_unlocked(playlist);
3921
3922 playlist_write_unlock(playlist);
3923
4051 if ((audio_status() & AUDIO_STATUS_PLAY) && playlist->started) 3924 if ((audio_status() & AUDIO_STATUS_PLAY) && playlist->started)
4052 audio_flush_and_reload_tracks(); 3925 audio_flush_and_reload_tracks();
4053} 3926}
diff --git a/apps/playlist.h b/apps/playlist.h
index bdc2684c18..d01100af59 100644
--- a/apps/playlist.h
+++ b/apps/playlist.h
@@ -33,7 +33,6 @@
33#define PLAYLIST_ATTR_QUEUED 0x01 33#define PLAYLIST_ATTR_QUEUED 0x01
34#define PLAYLIST_ATTR_INSERTED 0x02 34#define PLAYLIST_ATTR_INSERTED 0x02
35#define PLAYLIST_ATTR_SKIPPED 0x04 35#define PLAYLIST_ATTR_SKIPPED 0x04
36#define PLAYLIST_MAX_CACHE 16
37 36
38#define PLAYLIST_DISPLAY_COUNT 10 37#define PLAYLIST_DISPLAY_COUNT 10
39 38
@@ -61,15 +60,6 @@ enum {
61 PLAYLIST_INSERT_LAST_SHUFFLED = -7 60 PLAYLIST_INSERT_LAST_SHUFFLED = -7
62}; 61};
63 62
64struct playlist_control_cache {
65 enum playlist_command command;
66 int i1;
67 int i2;
68 const char* s1;
69 const char* s2;
70 void* data;
71};
72
73struct playlist_info 63struct playlist_info
74{ 64{
75 bool utf8; /* playlist is in .m3u8 format */ 65 bool utf8; /* playlist is in .m3u8 format */
@@ -87,14 +77,9 @@ struct playlist_info
87 int amount; /* number of tracks in the index */ 77 int amount; /* number of tracks in the index */
88 int last_insert_pos; /* last position we inserted a track */ 78 int last_insert_pos; /* last position we inserted a track */
89 bool started; /* has playlist been started? */ 79 bool started; /* has playlist been started? */
90 bool pending_control_sync; /* control file needs to be synced */
91 int last_shuffled_start; /* number of tracks when insert last 80 int last_shuffled_start; /* number of tracks when insert last
92 shuffled command start */ 81 shuffled command start */
93 int seed; /* shuffle seed */ 82 int seed; /* shuffle seed */
94 /* cache of playlist control commands waiting to be flushed to
95 to disk */
96 struct playlist_control_cache control_cache[PLAYLIST_MAX_CACHE];
97 int num_cached; /* number of cached entries */
98 struct mutex mutex; /* mutex for control file access */ 83 struct mutex mutex; /* mutex for control file access */
99#ifdef HAVE_DIRCACHE 84#ifdef HAVE_DIRCACHE
100 int dcfrefs_handle; 85 int dcfrefs_handle;