summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorHardeep Sidhu <dyp@pobox.com>2006-02-05 18:17:41 +0000
committerHardeep Sidhu <dyp@pobox.com>2006-02-05 18:17:41 +0000
commit75a60fbf69fb7d7be5839b35efc8253d682a1c7d (patch)
tree219ce4485e7128232090e3cbcdd357addbf09481 /apps
parent987879b958f87a9af7ef9edcf6ae417fe56db788 (diff)
downloadrockbox-75a60fbf69fb7d7be5839b35efc8253d682a1c7d.tar.gz
rockbox-75a60fbf69fb7d7be5839b35efc8253d682a1c7d.zip
Added a cache for playlist control commands. On non-dircache systems, behaviour should be the same as before (all commands except shuffle flushed immediately). On dircache systems, commands are only flushed when disk is accessed or during shutdown. This especially reduces disk accesses when playing queued files and should fix the problem with gapless playback.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8584 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps')
-rw-r--r--apps/playlist.c402
-rw-r--r--apps/playlist.h66
-rw-r--r--apps/tree.c1
3 files changed, 281 insertions, 188 deletions
diff --git a/apps/playlist.c b/apps/playlist.c
index d760b2450d..25939bb3ee 100644
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -175,7 +175,11 @@ static int format_track_path(char *dest, char *src, int buf_length, int max,
175 char *dir); 175 char *dir);
176static void display_playlist_count(int count, const unsigned char *fmt); 176static void display_playlist_count(int count, const unsigned char *fmt);
177static void display_buffer_full(void); 177static void display_buffer_full(void);
178static int flush_pending_control(struct playlist_info* playlist); 178static int flush_cached_control(struct playlist_info* playlist);
179static int update_control(struct playlist_info* playlist,
180 enum playlist_command command, int i1, int i2,
181 const char* s1, const char* s2, void* data);
182static void sync_control(struct playlist_info* playlist, bool force);
179static int rotate_index(const struct playlist_info* playlist, int index); 183static int rotate_index(const struct playlist_info* playlist, int index);
180 184
181#ifdef HAVE_DIRCACHE 185#ifdef HAVE_DIRCACHE
@@ -218,7 +222,9 @@ static void empty_playlist(struct playlist_info* playlist, bool resume)
218 playlist->shuffle_modified = false; 222 playlist->shuffle_modified = false;
219 playlist->deleted = false; 223 playlist->deleted = false;
220 playlist->num_inserted_tracks = 0; 224 playlist->num_inserted_tracks = 0;
221 playlist->shuffle_flush = false; 225
226 playlist->num_cached = 0;
227 playlist->pending_control_sync = false;
222 228
223 if (!resume && playlist->current) 229 if (!resume && playlist->current)
224 { 230 {
@@ -255,11 +261,9 @@ static void new_playlist(struct playlist_info* playlist, const char *dir,
255 261
256 if (playlist->control_fd >= 0) 262 if (playlist->control_fd >= 0)
257 { 263 {
258 if (fdprintf(playlist->control_fd, "P:%d:%s:%s\n", 264 update_control(playlist, PLAYLIST_COMMAND_PLAYLIST,
259 PLAYLIST_CONTROL_FILE_VERSION, dir, file) > 0) 265 PLAYLIST_CONTROL_FILE_VERSION, -1, dir, file, NULL);
260 fsync(playlist->control_fd); 266 sync_control(playlist, false);
261 else
262 gui_syncsplash(HZ*2, true, str(LANG_PLAYLIST_CONTROL_UPDATE_ERROR));
263 } 267 }
264} 268}
265 269
@@ -304,12 +308,9 @@ static int check_control(struct playlist_info* playlist)
304 308
305 playlist->filename[playlist->dirlen-1] = '\0'; 309 playlist->filename[playlist->dirlen-1] = '\0';
306 310
307 if (fdprintf(playlist->control_fd, "P:%d:%s:%s\n", 311 update_control(playlist, PLAYLIST_COMMAND_PLAYLIST,
308 PLAYLIST_CONTROL_FILE_VERSION, dir, file) > 0) 312 PLAYLIST_CONTROL_FILE_VERSION, -1, dir, file, NULL);
309 fsync(playlist->control_fd); 313 sync_control(playlist, false);
310 else
311 gui_syncsplash(HZ*2, true, str(LANG_PLAYLIST_CONTROL_UPDATE_ERROR));
312
313 playlist->filename[playlist->dirlen-1] = c; 314 playlist->filename[playlist->dirlen-1] = c;
314 } 315 }
315 } 316 }
@@ -548,33 +549,12 @@ static int add_track_to_playlist(struct playlist_info* playlist,
548 549
549 if (seek_pos < 0 && playlist->control_fd >= 0) 550 if (seek_pos < 0 && playlist->control_fd >= 0)
550 { 551 {
551 int result = -1; 552 int result = update_control(playlist,
552 553 (queue?PLAYLIST_COMMAND_QUEUE:PLAYLIST_COMMAND_ADD), position,
553 if (flush_pending_control(playlist) < 0) 554 playlist->last_insert_pos, filename, NULL, &seek_pos);
554 return -1;
555
556 mutex_lock(&playlist->control_mutex);
557
558 if (lseek(playlist->control_fd, 0, SEEK_END) >= 0)
559 {
560 if (fdprintf(playlist->control_fd, "%c:%d:%d:", (queue?'Q':'A'),
561 position, playlist->last_insert_pos) > 0)
562 {
563 /* save the position in file where track name is written */
564 seek_pos = lseek(playlist->control_fd, 0, SEEK_CUR);
565
566 if (fdprintf(playlist->control_fd, "%s\n", filename) > 0)
567 result = 0;
568 }
569 }
570
571 mutex_unlock(&playlist->control_mutex);
572 555
573 if (result < 0) 556 if (result < 0)
574 {
575 gui_syncsplash(HZ*2, true, str(LANG_PLAYLIST_CONTROL_UPDATE_ERROR));
576 return result; 557 return result;
577 }
578 } 558 }
579 559
580 playlist->indices[insert_position] = flags | seek_pos; 560 playlist->indices[insert_position] = flags | seek_pos;
@@ -758,29 +738,13 @@ static int remove_track_from_playlist(struct playlist_info* playlist,
758 738
759 if (write && playlist->control_fd >= 0) 739 if (write && playlist->control_fd >= 0)
760 { 740 {
761 int result = -1; 741 int result = update_control(playlist, PLAYLIST_COMMAND_DELETE,
762 742 position, -1, NULL, NULL, NULL);
763 if (flush_pending_control(playlist) < 0)
764 return -1;
765
766 mutex_lock(&playlist->control_mutex);
767
768 if (lseek(playlist->control_fd, 0, SEEK_END) >= 0)
769 {
770 if (fdprintf(playlist->control_fd, "D:%d\n", position) > 0)
771 {
772 fsync(playlist->control_fd);
773 result = 0;
774 }
775 }
776
777 mutex_unlock(&playlist->control_mutex);
778 743
779 if (result < 0) 744 if (result < 0)
780 {
781 gui_syncsplash(HZ*2, true, str(LANG_PLAYLIST_CONTROL_UPDATE_ERROR));
782 return result; 745 return result;
783 } 746
747 sync_control(playlist, false);
784 } 748 }
785 749
786 return 0; 750 return 0;
@@ -838,9 +802,8 @@ static int randomise_playlist(struct playlist_info* playlist,
838 802
839 if (write) 803 if (write)
840 { 804 {
841 /* Don't write to disk immediately. Instead, save in settings and 805 update_control(playlist, PLAYLIST_COMMAND_SHUFFLE, seed,
842 only flush if playlist is modified (insertion/deletion) */ 806 playlist->first_index, NULL, NULL, NULL);
843 playlist->shuffle_flush = true;
844 global_settings.resume_seed = seed; 807 global_settings.resume_seed = seed;
845 settings_save(); 808 settings_save();
846 } 809 }
@@ -878,9 +841,8 @@ static int sort_playlist(struct playlist_info* playlist, bool start_current,
878 playlist->shuffle_modified = false; 841 playlist->shuffle_modified = false;
879 if (write && playlist->control_fd >= 0) 842 if (write && playlist->control_fd >= 0)
880 { 843 {
881 /* Don't write to disk immediately. Instead, save in settings and 844 update_control(playlist, PLAYLIST_COMMAND_UNSHUFFLE,
882 only flush if playlist is modified (insertion/deletion) */ 845 playlist->first_index, -1, NULL, NULL, NULL);
883 playlist->shuffle_flush = true;
884 global_settings.resume_seed = 0; 846 global_settings.resume_seed = 0;
885 settings_save(); 847 settings_save();
886 } 848 }
@@ -1094,7 +1056,8 @@ static int compare(const void* p1, const void* p2)
1094#ifdef HAVE_DIRCACHE 1056#ifdef HAVE_DIRCACHE
1095/** 1057/**
1096 * Thread to update filename pointers to dircache on background 1058 * Thread to update filename pointers to dircache on background
1097 * without affecting playlist load up performance. 1059 * without affecting playlist load up performance. This thread also flushes
1060 * any pending control commands when the disk spins up.
1098 */ 1061 */
1099static void playlist_thread(void) 1062static void playlist_thread(void)
1100{ 1063{
@@ -1107,9 +1070,15 @@ static void playlist_thread(void)
1107 int seek; 1070 int seek;
1108 bool control_file; 1071 bool control_file;
1109 1072
1073 int sleep_time = 5;
1074
1075 if (global_settings.disk_spindown > 1 &&
1076 global_settings.disk_spindown <= 5)
1077 sleep_time = global_settings.disk_spindown - 1;
1078
1110 while (1) 1079 while (1)
1111 { 1080 {
1112 queue_wait_w_tmo(&playlist_queue, &ev, HZ*5); 1081 queue_wait_w_tmo(&playlist_queue, &ev, HZ*sleep_time);
1113 1082
1114 switch (ev.id) 1083 switch (ev.id)
1115 { 1084 {
@@ -1117,12 +1086,22 @@ static void playlist_thread(void)
1117 dirty_pointers = true; 1086 dirty_pointers = true;
1118 break ; 1087 break ;
1119 1088
1120 /* Start the background scanning after 5s. */ 1089 /* Start the background scanning after either the disk spindown
1090 timeout or 5s, whichever is less */
1121 case SYS_TIMEOUT: 1091 case SYS_TIMEOUT:
1092 playlist = &current_playlist;
1093
1094 if (playlist->control_fd >= 0 && ata_disk_is_active())
1095 {
1096 if (playlist->num_cached > 0)
1097 flush_cached_control(playlist);
1098
1099 sync_control(playlist, true);
1100 }
1101
1122 if (!dirty_pointers) 1102 if (!dirty_pointers)
1123 break ; 1103 break ;
1124 1104
1125 playlist = &current_playlist;
1126 if (!dircache_is_enabled() || !playlist->filenames 1105 if (!dircache_is_enabled() || !playlist->filenames
1127 || playlist->amount <= 0) 1106 || playlist->amount <= 0)
1128 break ; 1107 break ;
@@ -1543,56 +1522,157 @@ static void display_buffer_full(void)
1543} 1522}
1544 1523
1545/* 1524/*
1546 * Flush any pending control commands to disk. Called when playlist is being 1525 * Flush any cached control commands to disk. Called when playlist is being
1547 * modified. Returns 0 on success and -1 on failure. 1526 * modified. Returns 0 on success and -1 on failure.
1548 */ 1527 */
1549static int flush_pending_control(struct playlist_info* playlist) 1528static int flush_cached_control(struct playlist_info* playlist)
1550{ 1529{
1551 int result = 0; 1530 int result = 0;
1552 1531 int i;
1553 if (playlist->shuffle_flush && global_settings.resume_seed >= 0) 1532
1533 lseek(playlist->control_fd, 0, SEEK_END);
1534
1535 for (i=0; i<playlist->num_cached; i++)
1554 { 1536 {
1555 /* pending shuffle */ 1537 struct playlist_control_cache* cache =
1556 mutex_lock(&playlist->control_mutex); 1538 &(playlist->control_cache[i]);
1557 1539
1558 if (lseek(playlist->control_fd, 0, SEEK_END) >= 0) 1540 switch (cache->command)
1559 { 1541 {
1560 if (global_settings.resume_seed == 0) 1542 case PLAYLIST_COMMAND_PLAYLIST:
1561 result = fdprintf(playlist->control_fd, "U:%d\n", 1543 result = fdprintf(playlist->control_fd, "P:%d:%s:%s\n",
1562 playlist->first_index); 1544 cache->i1, cache->s1, cache->s2);
1563 else 1545 break;
1546 case PLAYLIST_COMMAND_ADD:
1547 case PLAYLIST_COMMAND_QUEUE:
1548 result = fdprintf(playlist->control_fd, "%c:%d:%d:",
1549 (cache->command == PLAYLIST_COMMAND_ADD)?'A':'Q',
1550 cache->i1, cache->i2);
1551 if (result > 0)
1552 {
1553 /* save the position in file where name is written */
1554 int* seek_pos = (int *)cache->data;
1555 *seek_pos = lseek(playlist->control_fd, 0, SEEK_CUR);
1556 result = fdprintf(playlist->control_fd, "%s\n",
1557 cache->s1);
1558 }
1559 break;
1560 case PLAYLIST_COMMAND_DELETE:
1561 result = fdprintf(playlist->control_fd, "D:%d\n", cache->i1);
1562 break;
1563 case PLAYLIST_COMMAND_SHUFFLE:
1564 result = fdprintf(playlist->control_fd, "S:%d:%d\n", 1564 result = fdprintf(playlist->control_fd, "S:%d:%d\n",
1565 global_settings.resume_seed, playlist->first_index); 1565 cache->i1, cache->i2);
1566 1566 break;
1567 if (result > 0) 1567 case PLAYLIST_COMMAND_UNSHUFFLE:
1568 { 1568 result = fdprintf(playlist->control_fd, "U:%d\n", cache->i1);
1569 fsync(playlist->control_fd); 1569 break;
1570 case PLAYLIST_COMMAND_RESET:
1571 result = fdprintf(playlist->control_fd, "R\n");
1572 break;
1573 default:
1574 break;
1575 }
1570 1576
1571 playlist->shuffle_flush = false; 1577 if (result <= 0)
1572 global_settings.resume_seed = -1; 1578 break;
1573 settings_save(); 1579 }
1574 1580
1575 result = 0; 1581 if (result > 0)
1576 } 1582 {
1577 else 1583 if (global_settings.resume_seed >= 0)
1578 result = -1;
1579 }
1580 else
1581 result = -1;
1582
1583 mutex_unlock(&playlist->control_mutex);
1584
1585 if (result < 0)
1586 { 1584 {
1587 gui_syncsplash(HZ*2, true, str(LANG_PLAYLIST_CONTROL_UPDATE_ERROR)); 1585 global_settings.resume_seed = -1;
1588 return result; 1586 settings_save();
1589 } 1587 }
1588
1589 playlist->num_cached = 0;
1590 playlist->pending_control_sync = true;
1591
1592 result = 0;
1593 }
1594 else
1595 result = -1;
1596
1597 if (result < 0)
1598 {
1599 gui_syncsplash(HZ*2, true, str(LANG_PLAYLIST_CONTROL_UPDATE_ERROR));
1600 return result;
1590 } 1601 }
1591 1602
1592 return result; 1603 return result;
1593} 1604}
1594 1605
1595/* 1606/*
1607 * Update control data with new command. Depending on the command, it may be
1608 * cached or flushed to disk.
1609 */
1610static int update_control(struct playlist_info* playlist,
1611 enum playlist_command command, int i1, int i2,
1612 const char* s1, const char* s2, void* data)
1613{
1614 int result = 0;
1615 struct playlist_control_cache* cache;
1616 bool flush = false;
1617
1618 mutex_lock(&playlist->control_mutex);
1619
1620 cache = &(playlist->control_cache[playlist->num_cached++]);
1621
1622 cache->command = command;
1623 cache->i1 = i1;
1624 cache->i2 = i2;
1625 cache->s1 = s1;
1626 cache->s2 = s2;
1627 cache->data = data;
1628
1629 switch (command)
1630 {
1631 case PLAYLIST_COMMAND_PLAYLIST:
1632 case PLAYLIST_COMMAND_ADD:
1633 case PLAYLIST_COMMAND_QUEUE:
1634#ifndef HAVE_DIRCACHE
1635 case PLAYLIST_COMMAND_DELETE:
1636 case PLAYLIST_COMMAND_RESET:
1637#endif
1638 flush = true;
1639 break;
1640 case PLAYLIST_COMMAND_SHUFFLE:
1641 case PLAYLIST_COMMAND_UNSHUFFLE:
1642 default:
1643 /* only flush when needed */
1644 break;
1645 }
1646
1647 if (flush || playlist->num_cached == PLAYLIST_MAX_CACHE)
1648 result = flush_cached_control(playlist);
1649
1650 mutex_unlock(&playlist->control_mutex);
1651
1652 return result;
1653}
1654
1655/*
1656 * sync control file to disk
1657 */
1658static void sync_control(struct playlist_info* playlist, bool force)
1659{
1660 (void) force;
1661#ifdef HAVE_DIRCACHE
1662 if (force)
1663#endif
1664 {
1665 if (playlist->pending_control_sync)
1666 {
1667 mutex_lock(&playlist->control_mutex);
1668 fsync(playlist->control_fd);
1669 playlist->pending_control_sync = false;
1670 mutex_unlock(&playlist->control_mutex);
1671 }
1672 }
1673}
1674
1675/*
1596 * Rotate indices such that first_index is index 0 1676 * Rotate indices such that first_index is index 0
1597 */ 1677 */
1598static int rotate_index(const struct playlist_info* playlist, int index) 1678static int rotate_index(const struct playlist_info* playlist, int index)
@@ -1637,6 +1717,26 @@ void playlist_init(void)
1637} 1717}
1638 1718
1639/* 1719/*
1720 * Clean playlist at shutdown
1721 */
1722void playlist_shutdown(void)
1723{
1724 struct playlist_info* playlist = &current_playlist;
1725
1726 if (playlist->control_fd >= 0)
1727 {
1728 mutex_lock(&playlist->control_mutex);
1729
1730 if (playlist->num_cached > 0)
1731 flush_cached_control(playlist);
1732
1733 close(playlist->control_fd);
1734
1735 mutex_unlock(&playlist->control_mutex);
1736 }
1737}
1738
1739/*
1640 * Create new playlist 1740 * Create new playlist
1641 */ 1741 */
1642int playlist_create(const char *dir, const char *file) 1742int playlist_create(const char *dir, const char *file)
@@ -1669,17 +1769,6 @@ int playlist_resume(void)
1669 bool first = true; 1769 bool first = true;
1670 bool sorted = true; 1770 bool sorted = true;
1671 1771
1672 enum {
1673 resume_playlist,
1674 resume_add,
1675 resume_queue,
1676 resume_delete,
1677 resume_shuffle,
1678 resume_unshuffle,
1679 resume_reset,
1680 resume_comment
1681 };
1682
1683 /* use mp3 buffer for maximum load speed */ 1772 /* use mp3 buffer for maximum load speed */
1684#if CONFIG_CODEC != SWCODEC 1773#if CONFIG_CODEC != SWCODEC
1685 talk_buffer_steal(); /* we use the mp3 buffer, need to tell */ 1774 talk_buffer_steal(); /* we use the mp3 buffer, need to tell */
@@ -1721,7 +1810,7 @@ int playlist_resume(void)
1721 { 1810 {
1722 int result = 0; 1811 int result = 0;
1723 int count; 1812 int count;
1724 int current_command = resume_comment; 1813 enum playlist_command current_command = PLAYLIST_COMMAND_COMMENT;
1725 int last_newline = 0; 1814 int last_newline = 0;
1726 int str_count = -1; 1815 int str_count = -1;
1727 bool newline = true; 1816 bool newline = true;
@@ -1743,7 +1832,7 @@ int playlist_resume(void)
1743 1832
1744 switch (current_command) 1833 switch (current_command)
1745 { 1834 {
1746 case resume_playlist: 1835 case PLAYLIST_COMMAND_PLAYLIST:
1747 { 1836 {
1748 /* str1=version str2=dir str3=file */ 1837 /* str1=version str2=dir str3=file */
1749 int version; 1838 int version;
@@ -1787,8 +1876,8 @@ int playlist_resume(void)
1787 1876
1788 break; 1877 break;
1789 } 1878 }
1790 case resume_add: 1879 case PLAYLIST_COMMAND_ADD:
1791 case resume_queue: 1880 case PLAYLIST_COMMAND_QUEUE:
1792 { 1881 {
1793 /* str1=position str2=last_position str3=file */ 1882 /* str1=position str2=last_position str3=file */
1794 int position, last_position; 1883 int position, last_position;
@@ -1804,7 +1893,8 @@ int playlist_resume(void)
1804 position = atoi(str1); 1893 position = atoi(str1);
1805 last_position = atoi(str2); 1894 last_position = atoi(str2);
1806 1895
1807 queue = (current_command == resume_add)?false:true; 1896 queue = (current_command == PLAYLIST_COMMAND_ADD)?
1897 false:true;
1808 1898
1809 /* seek position is based on str3's position in 1899 /* seek position is based on str3's position in
1810 buffer */ 1900 buffer */
@@ -1816,7 +1906,7 @@ int playlist_resume(void)
1816 1906
1817 break; 1907 break;
1818 } 1908 }
1819 case resume_delete: 1909 case PLAYLIST_COMMAND_DELETE:
1820 { 1910 {
1821 /* str1=position */ 1911 /* str1=position */
1822 int position; 1912 int position;
@@ -1836,7 +1926,7 @@ int playlist_resume(void)
1836 1926
1837 break; 1927 break;
1838 } 1928 }
1839 case resume_shuffle: 1929 case PLAYLIST_COMMAND_SHUFFLE:
1840 { 1930 {
1841 /* str1=seed str2=first_index */ 1931 /* str1=seed str2=first_index */
1842 int seed; 1932 int seed;
@@ -1864,7 +1954,7 @@ int playlist_resume(void)
1864 sorted = false; 1954 sorted = false;
1865 break; 1955 break;
1866 } 1956 }
1867 case resume_unshuffle: 1957 case PLAYLIST_COMMAND_UNSHUFFLE:
1868 { 1958 {
1869 /* str1=first_index */ 1959 /* str1=first_index */
1870 if (!str1) 1960 if (!str1)
@@ -1882,12 +1972,12 @@ int playlist_resume(void)
1882 sorted = true; 1972 sorted = true;
1883 break; 1973 break;
1884 } 1974 }
1885 case resume_reset: 1975 case PLAYLIST_COMMAND_RESET:
1886 { 1976 {
1887 playlist->last_insert_pos = -1; 1977 playlist->last_insert_pos = -1;
1888 break; 1978 break;
1889 } 1979 }
1890 case resume_comment: 1980 case PLAYLIST_COMMAND_COMMENT:
1891 default: 1981 default:
1892 break; 1982 break;
1893 } 1983 }
@@ -1895,7 +1985,7 @@ int playlist_resume(void)
1895 newline = true; 1985 newline = true;
1896 1986
1897 /* to ignore any extra newlines */ 1987 /* to ignore any extra newlines */
1898 current_command = resume_comment; 1988 current_command = PLAYLIST_COMMAND_COMMENT;
1899 } 1989 }
1900 else if(newline) 1990 else if(newline)
1901 { 1991 {
@@ -1920,28 +2010,28 @@ int playlist_resume(void)
1920 break; 2010 break;
1921 } 2011 }
1922 2012
1923 current_command = resume_playlist; 2013 current_command = PLAYLIST_COMMAND_PLAYLIST;
1924 break; 2014 break;
1925 case 'A': 2015 case 'A':
1926 current_command = resume_add; 2016 current_command = PLAYLIST_COMMAND_ADD;
1927 break; 2017 break;
1928 case 'Q': 2018 case 'Q':
1929 current_command = resume_queue; 2019 current_command = PLAYLIST_COMMAND_QUEUE;
1930 break; 2020 break;
1931 case 'D': 2021 case 'D':
1932 current_command = resume_delete; 2022 current_command = PLAYLIST_COMMAND_DELETE;
1933 break; 2023 break;
1934 case 'S': 2024 case 'S':
1935 current_command = resume_shuffle; 2025 current_command = PLAYLIST_COMMAND_SHUFFLE;
1936 break; 2026 break;
1937 case 'U': 2027 case 'U':
1938 current_command = resume_unshuffle; 2028 current_command = PLAYLIST_COMMAND_UNSHUFFLE;
1939 break; 2029 break;
1940 case 'R': 2030 case 'R':
1941 current_command = resume_reset; 2031 current_command = PLAYLIST_COMMAND_RESET;
1942 break; 2032 break;
1943 case '#': 2033 case '#':
1944 current_command = resume_comment; 2034 current_command = PLAYLIST_COMMAND_COMMENT;
1945 break; 2035 break;
1946 default: 2036 default:
1947 result = -1; 2037 result = -1;
@@ -1954,7 +2044,7 @@ int playlist_resume(void)
1954 str2 = NULL; 2044 str2 = NULL;
1955 str3 = NULL; 2045 str3 = NULL;
1956 } 2046 }
1957 else if(current_command != resume_comment) 2047 else if(current_command != PLAYLIST_COMMAND_COMMENT)
1958 { 2048 {
1959 /* all control file strings are separated with a colon. 2049 /* all control file strings are separated with a colon.
1960 Replace the colon with 0 to get proper strings that can be 2050 Replace the colon with 0 to get proper strings that can be
@@ -2097,9 +2187,6 @@ int playlist_shuffle(int random_seed, int start_index)
2097 2187
2098 randomise_playlist(playlist, random_seed, start_current, true); 2188 randomise_playlist(playlist, random_seed, start_current, true);
2099 2189
2100 /* Flush shuffle command to disk */
2101 flush_pending_control(playlist);
2102
2103 return playlist->index; 2190 return playlist->index;
2104} 2191}
2105 2192
@@ -2300,27 +2387,13 @@ int playlist_next(int steps)
2300 2387
2301 if (playlist->control_fd >= 0) 2388 if (playlist->control_fd >= 0)
2302 { 2389 {
2303 int result = -1; 2390 int result = update_control(playlist, PLAYLIST_COMMAND_RESET,
2304 2391 -1, -1, NULL, NULL, NULL);
2305 mutex_lock(&playlist->control_mutex);
2306
2307 if (lseek(playlist->control_fd, 0, SEEK_END) >= 0)
2308 {
2309 if (fdprintf(playlist->control_fd, "R\n") > 0)
2310 {
2311 fsync(playlist->control_fd);
2312 result = 0;
2313 }
2314 }
2315
2316 mutex_unlock(&playlist->control_mutex);
2317 2392
2318 if (result < 0) 2393 if (result < 0)
2319 {
2320 gui_syncsplash(HZ*2, true,
2321 str(LANG_PLAYLIST_CONTROL_UPDATE_ERROR));
2322 return result; 2394 return result;
2323 } 2395
2396 sync_control(playlist, false);
2324 } 2397 }
2325 } 2398 }
2326 } 2399 }
@@ -2536,8 +2609,12 @@ int playlist_set_current(struct playlist_info* playlist)
2536 current_playlist.shuffle_modified = playlist->shuffle_modified; 2609 current_playlist.shuffle_modified = playlist->shuffle_modified;
2537 current_playlist.deleted = playlist->deleted; 2610 current_playlist.deleted = playlist->deleted;
2538 current_playlist.num_inserted_tracks = playlist->num_inserted_tracks; 2611 current_playlist.num_inserted_tracks = playlist->num_inserted_tracks;
2539 current_playlist.shuffle_flush = playlist->shuffle_flush;
2540 2612
2613 memcpy(current_playlist.control_cache, playlist->control_cache,
2614 sizeof(current_playlist.control_cache));
2615 current_playlist.num_cached = playlist->num_cached;
2616 current_playlist.pending_control_sync = playlist->pending_control_sync;
2617
2541 return 0; 2618 return 0;
2542} 2619}
2543 2620
@@ -2581,10 +2658,7 @@ int playlist_insert_track(struct playlist_info* playlist,
2581 2658
2582 if (result != -1) 2659 if (result != -1)
2583 { 2660 {
2584 mutex_lock(&playlist->control_mutex); 2661 sync_control(playlist, false);
2585 fsync(playlist->control_fd);
2586 mutex_unlock(&playlist->control_mutex);
2587
2588 if (audio_status() & AUDIO_STATUS_PLAY) 2662 if (audio_status() & AUDIO_STATUS_PLAY)
2589 audio_flush_and_reload_tracks(); 2663 audio_flush_and_reload_tracks();
2590 } 2664 }
@@ -2626,9 +2700,7 @@ int playlist_insert_directory(struct playlist_info* playlist,
2626 result = add_directory_to_playlist(playlist, dirname, &position, queue, 2700 result = add_directory_to_playlist(playlist, dirname, &position, queue,
2627 &count, recurse); 2701 &count, recurse);
2628 2702
2629 mutex_lock(&playlist->control_mutex); 2703 sync_control(playlist, false);
2630 fsync(playlist->control_fd);
2631 mutex_unlock(&playlist->control_mutex);
2632 2704
2633 display_playlist_count(count, count_str); 2705 display_playlist_count(count, count_str);
2634 2706
@@ -2741,13 +2813,11 @@ int playlist_insert_playlist(struct playlist_info* playlist, char *filename,
2741 2813
2742 close(fd); 2814 close(fd);
2743 2815
2744 mutex_lock(&playlist->control_mutex);
2745 fsync(playlist->control_fd);
2746 mutex_unlock(&playlist->control_mutex);
2747
2748 if (temp_ptr) 2816 if (temp_ptr)
2749 *temp_ptr = '/'; 2817 *temp_ptr = '/';
2750 2818
2819 sync_control(playlist, false);
2820
2751 display_playlist_count(count, count_str); 2821 display_playlist_count(count, count_str);
2752 2822
2753 if (audio_status() & AUDIO_STATUS_PLAY) 2823 if (audio_status() & AUDIO_STATUS_PLAY)
@@ -2870,10 +2940,6 @@ int playlist_move(struct playlist_info* playlist, int index, int new_index)
2870 } 2940 }
2871 } 2941 }
2872 2942
2873 mutex_lock(&playlist->control_mutex);
2874 fsync(playlist->control_fd);
2875 mutex_unlock(&playlist->control_mutex);
2876
2877 if (audio_status() & AUDIO_STATUS_PLAY) 2943 if (audio_status() & AUDIO_STATUS_PLAY)
2878 audio_flush_and_reload_tracks(); 2944 audio_flush_and_reload_tracks();
2879 } 2945 }
diff --git a/apps/playlist.h b/apps/playlist.h
index 286823e0cf..3aa5406a51 100644
--- a/apps/playlist.h
+++ b/apps/playlist.h
@@ -25,7 +25,44 @@
25#include "kernel.h" 25#include "kernel.h"
26#include "id3.h" 26#include "id3.h"
27 27
28/* playlist data */ 28#define PLAYLIST_ATTR_QUEUED 0x01
29#define PLAYLIST_ATTR_INSERTED 0x02
30#define PLAYLIST_ATTR_SKIPPED 0x04
31#define PLAYLIST_MAX_CACHE 16
32
33#define DEFAULT_DYNAMIC_PLAYLIST_NAME "/dynamic.m3u"
34
35enum playlist_command {
36 PLAYLIST_COMMAND_PLAYLIST,
37 PLAYLIST_COMMAND_ADD,
38 PLAYLIST_COMMAND_QUEUE,
39 PLAYLIST_COMMAND_DELETE,
40 PLAYLIST_COMMAND_SHUFFLE,
41 PLAYLIST_COMMAND_UNSHUFFLE,
42 PLAYLIST_COMMAND_RESET,
43 PLAYLIST_COMMAND_COMMENT
44};
45
46enum {
47 PLAYLIST_PREPEND = -1,
48 PLAYLIST_INSERT = -2,
49 PLAYLIST_INSERT_LAST = -3,
50 PLAYLIST_INSERT_FIRST = -4,
51 PLAYLIST_INSERT_SHUFFLED = -5
52};
53
54enum {
55 PLAYLIST_DELETE_CURRENT = -1
56};
57
58struct playlist_control_cache {
59 enum playlist_command command;
60 int i1;
61 int i2;
62 const char* s1;
63 const char* s2;
64 void* data;
65};
29 66
30struct playlist_info 67struct playlist_info
31{ 68{
@@ -53,15 +90,15 @@ struct playlist_info
53 inserted tracks? */ 90 inserted tracks? */
54 bool deleted; /* have any tracks been deleted? */ 91 bool deleted; /* have any tracks been deleted? */
55 int num_inserted_tracks; /* number of tracks inserted */ 92 int num_inserted_tracks; /* number of tracks inserted */
56 bool shuffle_flush; /* does shuffle value need to be flushed? */
57 struct mutex control_mutex; /* mutex for control file access */
58};
59 93
60#define PLAYLIST_ATTR_QUEUED 0x01 94 /* cache of playlist control commands waiting to be flushed to
61#define PLAYLIST_ATTR_INSERTED 0x02 95 to disk */
62#define PLAYLIST_ATTR_SKIPPED 0x04 96 struct playlist_control_cache control_cache[PLAYLIST_MAX_CACHE];
97 int num_cached; /* number of cached entries */
98 bool pending_control_sync; /* control file needs to be synced */
63 99
64#define DEFAULT_DYNAMIC_PLAYLIST_NAME "/dynamic.m3u" 100 struct mutex control_mutex; /* mutex for control file access */
101};
65 102
66struct playlist_track_info 103struct playlist_track_info
67{ 104{
@@ -73,6 +110,7 @@ struct playlist_track_info
73 110
74/* Exported functions only for current playlist. */ 111/* Exported functions only for current playlist. */
75void playlist_init(void); 112void playlist_init(void);
113void playlist_shutdown(void);
76int playlist_create(const char *dir, const char *file); 114int playlist_create(const char *dir, const char *file);
77int playlist_resume(void); 115int playlist_resume(void);
78int playlist_add(const char *filename); 116int playlist_add(const char *filename);
@@ -120,16 +158,4 @@ int playlist_get_track_info(struct playlist_info* playlist, int index,
120 struct playlist_track_info* info); 158 struct playlist_track_info* info);
121int playlist_save(struct playlist_info* playlist, char *filename); 159int playlist_save(struct playlist_info* playlist, char *filename);
122 160
123enum {
124 PLAYLIST_PREPEND = -1,
125 PLAYLIST_INSERT = -2,
126 PLAYLIST_INSERT_LAST = -3,
127 PLAYLIST_INSERT_FIRST = -4,
128 PLAYLIST_INSERT_SHUFFLED = -5
129};
130
131enum {
132 PLAYLIST_DELETE_CURRENT = -1
133};
134
135#endif /* __PLAYLIST_H__ */ 161#endif /* __PLAYLIST_H__ */
diff --git a/apps/tree.c b/apps/tree.c
index e91eb4b16f..d69217e5b2 100644
--- a/apps/tree.c
+++ b/apps/tree.c
@@ -1325,6 +1325,7 @@ void tree_flush(void)
1325{ 1325{
1326 rundb_shutdown(); 1326 rundb_shutdown();
1327 tagdb_shutdown(); 1327 tagdb_shutdown();
1328 playlist_shutdown();
1328#ifdef HAVE_DIRCACHE 1329#ifdef HAVE_DIRCACHE
1329 if (global_settings.dircache) 1330 if (global_settings.dircache)
1330 { 1331 {