summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 {