summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/appevents.h1
-rw-r--r--apps/buffering.c288
-rw-r--r--apps/buffering.h25
-rw-r--r--apps/codec_thread.c679
-rw-r--r--apps/codec_thread.h7
-rw-r--r--apps/codecs.c96
-rw-r--r--apps/codecs.h67
-rw-r--r--apps/codecs/a52.c53
-rw-r--r--apps/codecs/a52_rm.c77
-rw-r--r--apps/codecs/aac.c62
-rw-r--r--apps/codecs/adx.c40
-rw-r--r--apps/codecs/aiff.c108
-rw-r--r--apps/codecs/aiff_enc.c54
-rw-r--r--apps/codecs/alac.c188
-rw-r--r--apps/codecs/ape.c54
-rw-r--r--apps/codecs/asap.c32
-rw-r--r--apps/codecs/atrac3_oma.c136
-rw-r--r--apps/codecs/atrac3_rm.c67
-rw-r--r--apps/codecs/au.c80
-rw-r--r--apps/codecs/codec_crt0.c50
-rw-r--r--apps/codecs/cook.c63
-rw-r--r--apps/codecs/flac.c62
-rw-r--r--apps/codecs/lib/codeclib.c25
-rw-r--r--apps/codecs/lib/codeclib.h3
-rw-r--r--apps/codecs/mod.c67
-rw-r--r--apps/codecs/mp3_enc.c59
-rw-r--r--apps/codecs/mpa.c76
-rw-r--r--apps/codecs/mpc.c76
-rw-r--r--apps/codecs/nsf.c82
-rw-r--r--apps/codecs/raac.c98
-rw-r--r--apps/codecs/shorten.c40
-rw-r--r--apps/codecs/sid.c72
-rw-r--r--apps/codecs/smaf.c82
-rw-r--r--apps/codecs/spc.c128
-rw-r--r--apps/codecs/speex.c61
-rw-r--r--apps/codecs/tta.c61
-rw-r--r--apps/codecs/vorbis.c74
-rw-r--r--apps/codecs/vox.c78
-rw-r--r--apps/codecs/wav.c106
-rw-r--r--apps/codecs/wav64.c113
-rw-r--r--apps/codecs/wav_enc.c54
-rw-r--r--apps/codecs/wavpack.c78
-rw-r--r--apps/codecs/wavpack_enc.c112
-rw-r--r--apps/codecs/wma.c77
-rw-r--r--apps/codecs/wmapro.c68
-rw-r--r--apps/codecs/wmavoice.c68
-rw-r--r--apps/gui/wps.c40
-rw-r--r--apps/menus/playback_menu.c4
-rw-r--r--apps/metadata.c130
-rw-r--r--apps/metadata.h7
-rw-r--r--apps/metadata/nsf.c3
-rw-r--r--apps/pcmbuf.c55
-rw-r--r--apps/pcmbuf.h10
-rw-r--r--apps/playback.c4590
-rw-r--r--apps/playback.h78
-rw-r--r--apps/playlist.c43
-rw-r--r--apps/playlist.h3
-rw-r--r--apps/plugin.c2
-rw-r--r--apps/plugin.h10
-rw-r--r--apps/plugins/test_codec.c45
60 files changed, 5376 insertions, 3691 deletions
diff --git a/apps/appevents.h b/apps/appevents.h
index fd578b90a2..a303491ae9 100644
--- a/apps/appevents.h
+++ b/apps/appevents.h
@@ -35,6 +35,7 @@ enum {
35 PLAYBACK_EVENT_TRACK_BUFFER, 35 PLAYBACK_EVENT_TRACK_BUFFER,
36 PLAYBACK_EVENT_TRACK_FINISH, 36 PLAYBACK_EVENT_TRACK_FINISH,
37 PLAYBACK_EVENT_TRACK_CHANGE, 37 PLAYBACK_EVENT_TRACK_CHANGE,
38 PLAYBACK_EVENT_TRACK_SKIP,
38 PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, 39 PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE,
39}; 40};
40 41
diff --git a/apps/buffering.c b/apps/buffering.c
index 578f0f261a..a130a787ff 100644
--- a/apps/buffering.c
+++ b/apps/buffering.c
@@ -58,7 +58,7 @@
58#define GUARD_BUFSIZE (32*1024) 58#define GUARD_BUFSIZE (32*1024)
59 59
60/* Define LOGF_ENABLE to enable logf output in this file */ 60/* Define LOGF_ENABLE to enable logf output in this file */
61/*#define LOGF_ENABLE*/ 61/* #define LOGF_ENABLE */
62#include "logf.h" 62#include "logf.h"
63 63
64/* macros to enable logf for queues 64/* macros to enable logf for queues
@@ -82,8 +82,6 @@
82#define LOGFQUEUE_SYS_TIMEOUT(...) 82#define LOGFQUEUE_SYS_TIMEOUT(...)
83#endif 83#endif
84 84
85/* default point to start buffer refill */
86#define BUFFERING_DEFAULT_WATERMARK (1024*128)
87/* amount of data to read in one read() call */ 85/* amount of data to read in one read() call */
88#define BUFFERING_DEFAULT_FILECHUNK (1024*32) 86#define BUFFERING_DEFAULT_FILECHUNK (1024*32)
89 87
@@ -94,6 +92,8 @@
94struct memory_handle { 92struct memory_handle {
95 int id; /* A unique ID for the handle */ 93 int id; /* A unique ID for the handle */
96 enum data_type type; /* Type of data buffered with this handle */ 94 enum data_type type; /* Type of data buffered with this handle */
95 int8_t pinned; /* Count of references */
96 int8_t signaled; /* Stop any attempt at waiting to get the data */
97 char path[MAX_PATH]; /* Path if data originated in a file */ 97 char path[MAX_PATH]; /* Path if data originated in a file */
98 int fd; /* File descriptor to path (-1 if closed) */ 98 int fd; /* File descriptor to path (-1 if closed) */
99 size_t data; /* Start index of the handle's data buffer */ 99 size_t data; /* Start index of the handle's data buffer */
@@ -125,9 +125,7 @@ static volatile size_t buf_ridx; /* current reading position */
125 125
126/* Configuration */ 126/* Configuration */
127static size_t conf_watermark = 0; /* Level to trigger filebuf fill */ 127static size_t conf_watermark = 0; /* Level to trigger filebuf fill */
128#if MEMORYSIZE > 8
129static size_t high_watermark = 0; /* High watermark for rebuffer */ 128static size_t high_watermark = 0; /* High watermark for rebuffer */
130#endif
131 129
132/* current memory handle in the linked list. NULL when the list is empty. */ 130/* current memory handle in the linked list. NULL when the list is empty. */
133static struct memory_handle *cur_handle; 131static struct memory_handle *cur_handle;
@@ -162,7 +160,6 @@ enum
162 Q_REBUFFER_HANDLE, /* Request reset and rebuffering of a handle at a new 160 Q_REBUFFER_HANDLE, /* Request reset and rebuffering of a handle at a new
163 file starting position. */ 161 file starting position. */
164 Q_CLOSE_HANDLE, /* Request closing a handle */ 162 Q_CLOSE_HANDLE, /* Request closing a handle */
165 Q_BASE_HANDLE, /* Set the reference handle for buf_useful_data */
166 163
167 /* Configuration: */ 164 /* Configuration: */
168 Q_START_FILL, /* Request that the buffering thread initiate a buffer 165 Q_START_FILL, /* Request that the buffering thread initiate a buffer
@@ -222,6 +219,9 @@ static inline ssize_t ringbuf_add_cross(uintptr_t p1, size_t v, uintptr_t p2)
222/* Bytes available in the buffer */ 219/* Bytes available in the buffer */
223#define BUF_USED ringbuf_sub(buf_widx, buf_ridx) 220#define BUF_USED ringbuf_sub(buf_widx, buf_ridx)
224 221
222/* Real buffer watermark */
223#define BUF_WATERMARK MIN(conf_watermark, high_watermark)
224
225/* 225/*
226LINKED LIST MANAGEMENT 226LINKED LIST MANAGEMENT
227====================== 227======================
@@ -313,6 +313,12 @@ static struct memory_handle *add_handle(size_t data_size, bool can_wrap,
313 /* Prevent buffering thread from looking at it */ 313 /* Prevent buffering thread from looking at it */
314 new_handle->filerem = 0; 314 new_handle->filerem = 0;
315 315
316 /* Handle can be moved by default */
317 new_handle->pinned = 0;
318
319 /* Handle data can be waited for by default */
320 new_handle->signaled = 0;
321
316 /* only advance the buffer write index of the size of the struct */ 322 /* only advance the buffer write index of the size of the struct */
317 buf_widx = ringbuf_add(buf_widx, sizeof(struct memory_handle)); 323 buf_widx = ringbuf_add(buf_widx, sizeof(struct memory_handle));
318 324
@@ -364,6 +370,9 @@ static bool rm_handle(const struct memory_handle *h)
364 buf_widx = cur_handle->widx; 370 buf_widx = cur_handle->widx;
365 } 371 }
366 } else { 372 } else {
373 /* If we don't find ourselves, this is a seriously incoherent
374 state with a corrupted list and severe action is needed! */
375 panicf("rm_handle fail: %d", h->id);
367 return false; 376 return false;
368 } 377 }
369 } 378 }
@@ -385,8 +394,7 @@ static struct memory_handle *find_handle(int handle_id)
385 394
386 /* simple caching because most of the time the requested handle 395 /* simple caching because most of the time the requested handle
387 will either be the same as the last, or the one after the last */ 396 will either be the same as the last, or the one after the last */
388 if (cached_handle) 397 if (cached_handle) {
389 {
390 if (cached_handle->id == handle_id) { 398 if (cached_handle->id == handle_id) {
391 return cached_handle; 399 return cached_handle;
392 } else if (cached_handle->next && 400 } else if (cached_handle->next &&
@@ -618,20 +626,22 @@ static void update_data_counters(struct data_counters *dc)
618static inline bool buffer_is_low(void) 626static inline bool buffer_is_low(void)
619{ 627{
620 update_data_counters(NULL); 628 update_data_counters(NULL);
621 return data_counters.useful < (conf_watermark / 2); 629 return data_counters.useful < BUF_WATERMARK / 2;
622} 630}
623 631
624/* Q_BUFFER_HANDLE event and buffer data for the given handle. 632/* Q_BUFFER_HANDLE event and buffer data for the given handle.
625 Return whether or not the buffering should continue explicitly. */ 633 Return whether or not the buffering should continue explicitly. */
626static bool buffer_handle(int handle_id, size_t to_buffer) 634static bool buffer_handle(int handle_id, size_t to_buffer)
627{ 635{
628 logf("buffer_handle(%d)", handle_id); 636 logf("buffer_handle(%d, %lu)", handle_id, (unsigned long)to_buffer);
629 struct memory_handle *h = find_handle(handle_id); 637 struct memory_handle *h = find_handle(handle_id);
630 bool stop = false; 638 bool stop = false;
631 639
632 if (!h) 640 if (!h)
633 return true; 641 return true;
634 642
643 logf(" type: %d", (int)h->type);
644
635 if (h->filerem == 0) { 645 if (h->filerem == 0) {
636 /* nothing left to buffer */ 646 /* nothing left to buffer */
637 return true; 647 return true;
@@ -659,13 +669,13 @@ static bool buffer_handle(int handle_id, size_t to_buffer)
659 if (!get_metadata((struct mp3entry *)(buffer + h->data), 669 if (!get_metadata((struct mp3entry *)(buffer + h->data),
660 h->fd, h->path)) { 670 h->fd, h->path)) {
661 /* metadata parsing failed: clear the buffer. */ 671 /* metadata parsing failed: clear the buffer. */
662 memset(buffer + h->data, 0, sizeof(struct mp3entry)); 672 wipe_mp3entry((struct mp3entry *)(buffer + h->data));
663 } 673 }
664 close(h->fd); 674 close(h->fd);
665 h->fd = -1; 675 h->fd = -1;
666 h->filerem = 0; 676 h->filerem = 0;
667 h->available = sizeof(struct mp3entry); 677 h->available = sizeof(struct mp3entry);
668 h->widx += sizeof(struct mp3entry); 678 h->widx = ringbuf_add(h->widx, sizeof(struct mp3entry));
669 send_event(BUFFER_EVENT_FINISHED, &handle_id); 679 send_event(BUFFER_EVENT_FINISHED, &handle_id);
670 return true; 680 return true;
671 } 681 }
@@ -698,7 +708,7 @@ static bool buffer_handle(int handle_id, size_t to_buffer)
698 break; 708 break;
699 } 709 }
700 710
701 DEBUGF("File ended %ld bytes early\n", (long)h->filerem); 711 logf("File ended %ld bytes early\n", (long)h->filerem);
702 h->filesize -= h->filerem; 712 h->filesize -= h->filerem;
703 h->filerem = 0; 713 h->filerem = 0;
704 break; 714 break;
@@ -770,22 +780,31 @@ static bool close_handle(int handle_id)
770 part of its data buffer or by moving all the data. */ 780 part of its data buffer or by moving all the data. */
771static void shrink_handle(struct memory_handle *h) 781static void shrink_handle(struct memory_handle *h)
772{ 782{
773 size_t delta;
774
775 if (!h) 783 if (!h)
776 return; 784 return;
777 785
778 if (h->type == TYPE_ID3 || h->type == TYPE_CUESHEET || 786 if (h->type == TYPE_PACKET_AUDIO) {
779 h->type == TYPE_BITMAP || h->type == TYPE_CODEC || 787 /* only move the handle struct */
780 h->type == TYPE_ATOMIC_AUDIO) 788 /* data is pinned by default - if we start moving packet audio,
781 { 789 the semantics will determine whether or not data is movable
790 but the handle will remain movable in either case */
791 size_t delta = ringbuf_sub(h->ridx, h->data);
792
793 /* The value of delta might change for alignment reasons */
794 if (!move_handle(&h, &delta, 0, true))
795 return;
796
797 h->data = ringbuf_add(h->data, delta);
798 h->available -= delta;
799 h->offset += delta;
800 } else {
782 /* metadata handle: we can move all of it */ 801 /* metadata handle: we can move all of it */
783 if (!h->next || h->filerem != 0) 802 if (h->pinned || !h->next || h->filerem != 0)
784 return; /* Last handle or not finished loading */ 803 return; /* Pinned, last handle or not finished loading */
785 804
786 uintptr_t handle_distance = 805 uintptr_t handle_distance =
787 ringbuf_sub(ringbuf_offset(h->next), h->data); 806 ringbuf_sub(ringbuf_offset(h->next), h->data);
788 delta = handle_distance - h->available; 807 size_t delta = handle_distance - h->available;
789 808
790 /* The value of delta might change for alignment reasons */ 809 /* The value of delta might change for alignment reasons */
791 if (!move_handle(&h, &delta, h->available, h->type==TYPE_CODEC)) 810 if (!move_handle(&h, &delta, h->available, h->type==TYPE_CODEC))
@@ -806,15 +825,6 @@ static void shrink_handle(struct memory_handle *h)
806 struct bitmap *bmp = (struct bitmap *)&buffer[h->data]; 825 struct bitmap *bmp = (struct bitmap *)&buffer[h->data];
807 bmp->data = &buffer[h->data + sizeof(struct bitmap)]; 826 bmp->data = &buffer[h->data + sizeof(struct bitmap)];
808 } 827 }
809 } else {
810 /* only move the handle struct */
811 delta = ringbuf_sub(h->ridx, h->data);
812 if (!move_handle(&h, &delta, 0, true))
813 return;
814
815 h->data = ringbuf_add(h->data, delta);
816 h->available -= delta;
817 h->offset += delta;
818 } 828 }
819} 829}
820 830
@@ -962,6 +972,8 @@ int bufopen(const char *file, size_t offset, enum data_type type,
962 mutex_unlock(&llist_mutex); 972 mutex_unlock(&llist_mutex);
963 return handle_id; 973 return handle_id;
964 } 974 }
975 else if (type == TYPE_UNKNOWN)
976 return ERR_UNSUPPORTED_TYPE;
965#ifdef APPLICATION 977#ifdef APPLICATION
966 /* loading code from memory is not supported in application builds */ 978 /* loading code from memory is not supported in application builds */
967 else if (type == TYPE_CODEC) 979 else if (type == TYPE_CODEC)
@@ -1083,7 +1095,12 @@ int bufopen(const char *file, size_t offset, enum data_type type,
1083*/ 1095*/
1084int bufalloc(const void *src, size_t size, enum data_type type) 1096int bufalloc(const void *src, size_t size, enum data_type type)
1085{ 1097{
1086 int handle_id = ERR_BUFFER_FULL; 1098 int handle_id;
1099
1100 if (type == TYPE_UNKNOWN)
1101 return ERR_UNSUPPORTED_TYPE;
1102
1103 handle_id = ERR_BUFFER_FULL;
1087 1104
1088 mutex_lock(&llist_mutex); 1105 mutex_lock(&llist_mutex);
1089 1106
@@ -1124,7 +1141,14 @@ int bufalloc(const void *src, size_t size, enum data_type type)
1124bool bufclose(int handle_id) 1141bool bufclose(int handle_id)
1125{ 1142{
1126 logf("bufclose(%d)", handle_id); 1143 logf("bufclose(%d)", handle_id);
1127 1144#if 0
1145 /* Don't interrupt the buffering thread if the handle is already
1146 stale */
1147 if (!find_handle(handle_id)) {
1148 logf(" handle already closed");
1149 return true;
1150 }
1151#endif
1128 LOGFQUEUE("buffering >| Q_CLOSE_HANDLE %d", handle_id); 1152 LOGFQUEUE("buffering >| Q_CLOSE_HANDLE %d", handle_id);
1129 return queue_send(&buffering_queue, Q_CLOSE_HANDLE, handle_id); 1153 return queue_send(&buffering_queue, Q_CLOSE_HANDLE, handle_id);
1130} 1154}
@@ -1236,9 +1260,10 @@ static int seek_handle(struct memory_handle *h, size_t newpos)
1236 1260
1237/* Set reading index in handle (relatively to the start of the file). 1261/* Set reading index in handle (relatively to the start of the file).
1238 Access before the available data will trigger a rebuffer. 1262 Access before the available data will trigger a rebuffer.
1239 Return 0 for success and < 0 for failure: 1263 Return 0 for success and for failure:
1240 -1 if the handle wasn't found 1264 ERR_HANDLE_NOT_FOUND if the handle wasn't found
1241 -2 if the new requested position was beyond the end of the file 1265 ERR_INVALID_VALUE if the new requested position was beyond the end of
1266 the file
1242*/ 1267*/
1243int bufseek(int handle_id, size_t newpos) 1268int bufseek(int handle_id, size_t newpos)
1244{ 1269{
@@ -1250,7 +1275,11 @@ int bufseek(int handle_id, size_t newpos)
1250} 1275}
1251 1276
1252/* Advance the reading index in a handle (relatively to its current position). 1277/* Advance the reading index in a handle (relatively to its current position).
1253 Return 0 for success and < 0 for failure */ 1278 Return 0 for success and for failure:
1279 ERR_HANDLE_NOT_FOUND if the handle wasn't found
1280 ERR_INVALID_VALUE if the new requested position was beyond the end of
1281 the file
1282 */
1254int bufadvance(int handle_id, off_t offset) 1283int bufadvance(int handle_id, off_t offset)
1255{ 1284{
1256 struct memory_handle *h = find_handle(handle_id); 1285 struct memory_handle *h = find_handle(handle_id);
@@ -1261,6 +1290,18 @@ int bufadvance(int handle_id, off_t offset)
1261 return seek_handle(h, newpos); 1290 return seek_handle(h, newpos);
1262} 1291}
1263 1292
1293/* Get the read position from the start of the file
1294 Returns the offset from byte 0 of the file and for failure:
1295 ERR_HANDLE_NOT_FOUND if the handle wasn't found
1296 */
1297off_t bufftell(int handle_id)
1298{
1299 const struct memory_handle *h = find_handle(handle_id);
1300 if (!h)
1301 return ERR_HANDLE_NOT_FOUND;
1302 return h->offset + ringbuf_sub(h->ridx, h->data);
1303}
1304
1264/* Used by bufread and bufgetdata to prepare the buffer and retrieve the 1305/* Used by bufread and bufgetdata to prepare the buffer and retrieve the
1265 * actual amount of data available for reading. This function explicitly 1306 * actual amount of data available for reading. This function explicitly
1266 * does not check the validity of the input handle. It does do range checks 1307 * does not check the validity of the input handle. It does do range checks
@@ -1306,7 +1347,7 @@ static struct memory_handle *prep_bufdata(int handle_id, size_t *size,
1306 /* it is not safe for a non-buffering thread to sleep while 1347 /* it is not safe for a non-buffering thread to sleep while
1307 * holding a handle */ 1348 * holding a handle */
1308 h = find_handle(handle_id); 1349 h = find_handle(handle_id);
1309 if (!h) 1350 if (!h || h->signaled != 0)
1310 return NULL; 1351 return NULL;
1311 avail = handle_size_available(h); 1352 avail = handle_size_available(h);
1312 } 1353 }
@@ -1447,9 +1488,14 @@ SECONDARY EXPORTED FUNCTIONS
1447buf_handle_offset 1488buf_handle_offset
1448buf_request_buffer_handle 1489buf_request_buffer_handle
1449buf_set_base_handle 1490buf_set_base_handle
1491buf_handle_data_type
1492buf_is_handle
1493buf_pin_handle
1494buf_signal_handle
1495buf_length
1450buf_used 1496buf_used
1451register_buffering_callback 1497buf_set_watermark
1452unregister_buffering_callback 1498buf_get_watermark
1453 1499
1454These functions are exported, to allow interaction with the buffer. 1500These functions are exported, to allow interaction with the buffer.
1455They take care of the content of the structs, and rely on the linked list 1501They take care of the content of the structs, and rely on the linked list
@@ -1472,8 +1518,61 @@ void buf_request_buffer_handle(int handle_id)
1472 1518
1473void buf_set_base_handle(int handle_id) 1519void buf_set_base_handle(int handle_id)
1474{ 1520{
1475 LOGFQUEUE("buffering > Q_BASE_HANDLE %d", handle_id); 1521 mutex_lock(&llist_mutex);
1476 queue_post(&buffering_queue, Q_BASE_HANDLE, handle_id); 1522 base_handle_id = handle_id;
1523 mutex_unlock(&llist_mutex);
1524}
1525
1526enum data_type buf_handle_data_type(int handle_id)
1527{
1528 const struct memory_handle *h = find_handle(handle_id);
1529 if (!h)
1530 return TYPE_UNKNOWN;
1531 return h->type;
1532}
1533
1534ssize_t buf_handle_remaining(int handle_id)
1535{
1536 const struct memory_handle *h = find_handle(handle_id);
1537 if (!h)
1538 return ERR_HANDLE_NOT_FOUND;
1539 return h->filerem;
1540}
1541
1542bool buf_is_handle(int handle_id)
1543{
1544 return find_handle(handle_id) != NULL;
1545}
1546
1547bool buf_pin_handle(int handle_id, bool pin)
1548{
1549 struct memory_handle *h = find_handle(handle_id);
1550 if (!h)
1551 return false;
1552
1553 if (pin) {
1554 h->pinned++;
1555 } else if (h->pinned > 0) {
1556 h->pinned--;
1557 }
1558
1559 return true;
1560}
1561
1562bool buf_signal_handle(int handle_id, bool signal)
1563{
1564 struct memory_handle *h = find_handle(handle_id);
1565 if (!h)
1566 return false;
1567
1568 h->signaled = signal ? 1 : 0;
1569 return true;
1570}
1571
1572/* Return the size of the ringbuffer */
1573size_t buf_length(void)
1574{
1575 return buffer_len;
1477} 1576}
1478 1577
1479/* Return the amount of buffer space used */ 1578/* Return the amount of buffer space used */
@@ -1487,6 +1586,21 @@ void buf_set_watermark(size_t bytes)
1487 conf_watermark = bytes; 1586 conf_watermark = bytes;
1488} 1587}
1489 1588
1589size_t buf_get_watermark(void)
1590{
1591 return BUF_WATERMARK;
1592}
1593
1594#ifdef HAVE_IO_PRIORITY
1595void buf_back_off_storage(bool back_off)
1596{
1597 int priority = back_off ?
1598 IO_PRIORITY_BACKGROUND : IO_PRIORITY_IMMEDIATE;
1599 thread_set_io_priority(buffering_thread_id, priority);
1600}
1601#endif
1602
1603/** -- buffer thread helpers -- **/
1490static void shrink_buffer_inner(struct memory_handle *h) 1604static void shrink_buffer_inner(struct memory_handle *h)
1491{ 1605{
1492 if (h == NULL) 1606 if (h == NULL)
@@ -1503,7 +1617,7 @@ static void shrink_buffer(void)
1503 shrink_buffer_inner(first_handle); 1617 shrink_buffer_inner(first_handle);
1504} 1618}
1505 1619
1506void buffering_thread(void) 1620static void NORETURN_ATTR buffering_thread(void)
1507{ 1621{
1508 bool filling = false; 1622 bool filling = false;
1509 struct queue_event ev; 1623 struct queue_event ev;
@@ -1511,19 +1625,21 @@ void buffering_thread(void)
1511 1625
1512 while (true) 1626 while (true)
1513 { 1627 {
1514 if (!filling) { 1628 if (num_handles > 0) {
1629 if (!filling) {
1630 cancel_cpu_boost();
1631 }
1632 queue_wait_w_tmo(&buffering_queue, &ev, filling ? 1 : HZ/2);
1633 } else {
1634 filling = false;
1515 cancel_cpu_boost(); 1635 cancel_cpu_boost();
1636 queue_wait(&buffering_queue, &ev);
1516 } 1637 }
1517 1638
1518 queue_wait_w_tmo(&buffering_queue, &ev, filling ? 5 : HZ/2);
1519
1520 switch (ev.id) 1639 switch (ev.id)
1521 { 1640 {
1522 case Q_START_FILL: 1641 case Q_START_FILL:
1523 LOGFQUEUE("buffering < Q_START_FILL %d", (int)ev.data); 1642 LOGFQUEUE("buffering < Q_START_FILL %d", (int)ev.data);
1524 /* Call buffer callbacks here because this is one of two ways
1525 * to begin a full buffer fill */
1526 send_event(BUFFER_EVENT_BUFFER_LOW, 0);
1527 shrink_buffer(); 1643 shrink_buffer();
1528 queue_reply(&buffering_queue, 1); 1644 queue_reply(&buffering_queue, 1);
1529 filling |= buffer_handle((int)ev.data, 0); 1645 filling |= buffer_handle((int)ev.data, 0);
@@ -1553,36 +1669,21 @@ void buffering_thread(void)
1553 filling = true; 1669 filling = true;
1554 break; 1670 break;
1555 1671
1556 case Q_BASE_HANDLE:
1557 LOGFQUEUE("buffering < Q_BASE_HANDLE %d", (int)ev.data);
1558 base_handle_id = (int)ev.data;
1559 break;
1560
1561#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
1562 case SYS_USB_CONNECTED:
1563 LOGFQUEUE("buffering < SYS_USB_CONNECTED");
1564 usb_acknowledge(SYS_USB_CONNECTED_ACK);
1565 usb_wait_for_disconnect(&buffering_queue);
1566 break;
1567#endif
1568
1569 case SYS_TIMEOUT: 1672 case SYS_TIMEOUT:
1570 LOGFQUEUE_SYS_TIMEOUT("buffering < SYS_TIMEOUT"); 1673 LOGFQUEUE_SYS_TIMEOUT("buffering < SYS_TIMEOUT");
1571 break; 1674 break;
1572 } 1675 }
1573 1676
1574 update_data_counters(NULL); 1677 if (num_handles == 0 || !queue_empty(&buffering_queue))
1575 1678 continue;
1576 /* If the buffer is low, call the callbacks to get new data */
1577 if (num_handles > 0 && data_counters.useful <= conf_watermark)
1578 send_event(BUFFER_EVENT_BUFFER_LOW, 0);
1579 1679
1680 update_data_counters(NULL);
1580#if 0 1681#if 0
1581 /* TODO: This needs to be fixed to use the idle callback, disable it 1682 /* TODO: This needs to be fixed to use the idle callback, disable it
1582 * for simplicity until its done right */ 1683 * for simplicity until its done right */
1583#if MEMORYSIZE > 8 1684#if MEMORYSIZE > 8
1584 /* If the disk is spinning, take advantage by filling the buffer */ 1685 /* If the disk is spinning, take advantage by filling the buffer */
1585 else if (storage_disk_is_active() && queue_empty(&buffering_queue)) { 1686 else if (storage_disk_is_active()) {
1586 if (num_handles > 0 && data_counters.useful <= high_watermark) 1687 if (num_handles > 0 && data_counters.useful <= high_watermark)
1587 send_event(BUFFER_EVENT_BUFFER_LOW, 0); 1688 send_event(BUFFER_EVENT_BUFFER_LOW, 0);
1588 1689
@@ -1597,15 +1698,23 @@ void buffering_thread(void)
1597#endif 1698#endif
1598#endif 1699#endif
1599 1700
1600 if (queue_empty(&buffering_queue)) { 1701 if (filling) {
1601 if (filling) { 1702 if (data_counters.remaining > 0 && BUF_USED < buffer_len) {
1602 if (data_counters.remaining > 0 && BUF_USED < buffer_len) 1703 filling = fill_buffer();
1603 filling = fill_buffer(); 1704 }
1604 else if (data_counters.remaining == 0) 1705 else if (data_counters.remaining == 0) {
1605 filling = false; 1706 filling = false;
1606 } else if (ev.id == SYS_TIMEOUT) { 1707 }
1607 if (data_counters.remaining > 0 && 1708 } else if (ev.id == SYS_TIMEOUT) {
1608 data_counters.useful <= conf_watermark) { 1709 if (data_counters.useful < BUF_WATERMARK) {
1710 /* The buffer is low and we're idle, just watching the levels
1711 - call the callbacks to get new data */
1712 send_event(BUFFER_EVENT_BUFFER_LOW, NULL);
1713
1714 /* Continue anything else we haven't finished - it might
1715 get booted off or stop early because the receiver hasn't
1716 had a chance to clear anything yet */
1717 if (data_counters.remaining > 0) {
1609 shrink_buffer(); 1718 shrink_buffer();
1610 filling = fill_buffer(); 1719 filling = fill_buffer();
1611 } 1720 }
@@ -1618,9 +1727,14 @@ void buffering_init(void)
1618{ 1727{
1619 mutex_init(&llist_mutex); 1728 mutex_init(&llist_mutex);
1620 1729
1621 conf_watermark = BUFFERING_DEFAULT_WATERMARK; 1730 /* Thread should absolutely not respond to USB because if it waits first,
1622 1731 then it cannot properly service the handles and leaks will happen -
1623 queue_init(&buffering_queue, true); 1732 this is a worker thread and shouldn't need to care about any system
1733 notifications.
1734 ***
1735 Whoever is using buffering should be responsible enough to clear all
1736 the handles at the right time. */
1737 queue_init(&buffering_queue, false);
1624 buffering_thread_id = create_thread( buffering_thread, buffering_stack, 1738 buffering_thread_id = create_thread( buffering_thread, buffering_stack,
1625 sizeof(buffering_stack), CREATE_THREAD_FROZEN, 1739 sizeof(buffering_stack), CREATE_THREAD_FROZEN,
1626 buffering_thread_name IF_PRIO(, PRIORITY_BUFFERING) 1740 buffering_thread_name IF_PRIO(, PRIORITY_BUFFERING)
@@ -1636,6 +1750,9 @@ bool buffering_reset(char *buf, size_t buflen)
1636 /* Wraps of storage-aligned data must also be storage aligned, 1750 /* Wraps of storage-aligned data must also be storage aligned,
1637 thus buf and buflen must be a aligned to an integer multiple of 1751 thus buf and buflen must be a aligned to an integer multiple of
1638 the storage alignment */ 1752 the storage alignment */
1753
1754 buflen -= GUARD_BUFSIZE;
1755
1639 STORAGE_ALIGN_BUFFER(buf, buflen); 1756 STORAGE_ALIGN_BUFFER(buf, buflen);
1640 1757
1641 if (!buf || !buflen) 1758 if (!buf || !buflen)
@@ -1654,10 +1771,13 @@ bool buffering_reset(char *buf, size_t buflen)
1654 num_handles = 0; 1771 num_handles = 0;
1655 base_handle_id = -1; 1772 base_handle_id = -1;
1656 1773
1657 /* Set the high watermark as 75% full...or 25% empty :) */ 1774 /* Set the high watermark as 75% full...or 25% empty :)
1658#if MEMORYSIZE > 8 1775 This is the greatest fullness that will trigger low-buffer events
1776 no matter what the setting because high-bitrate files can have
1777 ludicrous margins that even exceed the buffer size - most common
1778 with a huge anti-skip buffer but even without that setting,
1779 staying constantly active in buffering is pointless */
1659 high_watermark = 3*buflen / 4; 1780 high_watermark = 3*buflen / 4;
1660#endif
1661 1781
1662 thread_thaw(buffering_thread_id); 1782 thread_thaw(buffering_thread_id);
1663 1783
@@ -1673,5 +1793,5 @@ void buffering_get_debugdata(struct buffering_debug *dbgdata)
1673 dbgdata->wasted_space = dc.wasted; 1793 dbgdata->wasted_space = dc.wasted;
1674 dbgdata->buffered_data = dc.buffered; 1794 dbgdata->buffered_data = dc.buffered;
1675 dbgdata->useful_data = dc.useful; 1795 dbgdata->useful_data = dc.useful;
1676 dbgdata->watermark = conf_watermark; 1796 dbgdata->watermark = BUF_WATERMARK;
1677} 1797}
diff --git a/apps/buffering.h b/apps/buffering.h
index 34d6d641c7..2e4cfd3968 100644
--- a/apps/buffering.h
+++ b/apps/buffering.h
@@ -28,14 +28,13 @@
28 28
29 29
30enum data_type { 30enum data_type {
31 TYPE_UNKNOWN = 0, /* invalid type indicator */
32 TYPE_ID3,
31 TYPE_CODEC, 33 TYPE_CODEC,
32 TYPE_PACKET_AUDIO, 34 TYPE_PACKET_AUDIO,
33 TYPE_ATOMIC_AUDIO, 35 TYPE_ATOMIC_AUDIO,
34 TYPE_ID3,
35 TYPE_CUESHEET, 36 TYPE_CUESHEET,
36 TYPE_BITMAP, 37 TYPE_BITMAP,
37 TYPE_BUFFER,
38 TYPE_UNKNOWN,
39}; 38};
40 39
41/* Error return values */ 40/* Error return values */
@@ -63,6 +62,7 @@ bool buffering_reset(char *buf, size_t buflen);
63 * bufclose : Close an open handle 62 * bufclose : Close an open handle
64 * bufseek : Set handle reading index, relatively to the start of the file 63 * bufseek : Set handle reading index, relatively to the start of the file
65 * bufadvance: Move handle reading index, relatively to current position 64 * bufadvance: Move handle reading index, relatively to current position
65 * bufftell : Return the handle's file read position
66 * bufread : Copy data from a handle to a buffer 66 * bufread : Copy data from a handle to a buffer
67 * bufgetdata: Obtain a pointer for linear access to a "size" amount of data 67 * bufgetdata: Obtain a pointer for linear access to a "size" amount of data
68 * bufgettail: Out-of-band get the last size bytes of a handle. 68 * bufgettail: Out-of-band get the last size bytes of a handle.
@@ -81,28 +81,40 @@ int bufalloc(const void *src, size_t size, enum data_type type);
81bool bufclose(int handle_id); 81bool bufclose(int handle_id);
82int bufseek(int handle_id, size_t newpos); 82int bufseek(int handle_id, size_t newpos);
83int bufadvance(int handle_id, off_t offset); 83int bufadvance(int handle_id, off_t offset);
84off_t bufftell(int handle_id);
84ssize_t bufread(int handle_id, size_t size, void *dest); 85ssize_t bufread(int handle_id, size_t size, void *dest);
85ssize_t bufgetdata(int handle_id, size_t size, void **data); 86ssize_t bufgetdata(int handle_id, size_t size, void **data);
86ssize_t bufgettail(int handle_id, size_t size, void **data); 87ssize_t bufgettail(int handle_id, size_t size, void **data);
87ssize_t bufcuttail(int handle_id, size_t size); 88ssize_t bufcuttail(int handle_id, size_t size);
88 89
89
90/*************************************************************************** 90/***************************************************************************
91 * SECONDARY FUNCTIONS 91 * SECONDARY FUNCTIONS
92 * =================== 92 * ===================
93 * 93 *
94 * buf_handle_data_type: return the handle's data type
95 * buf_is_handle: is the handle valid?
96 * buf_pin_handle: Disallow/allow handle movement. Handle may still be removed.
94 * buf_handle_offset: Get the offset of the first buffered byte from the file 97 * buf_handle_offset: Get the offset of the first buffered byte from the file
95 * buf_request_buffer_handle: Request buffering of a handle 98 * buf_request_buffer_handle: Request buffering of a handle
96 * buf_set_base_handle: Tell the buffering thread which handle is currently read 99 * buf_set_base_handle: Tell the buffering thread which handle is currently read
100 * buf_length: Total size of ringbuffer
97 * buf_used: Total amount of buffer space used (including allocated space) 101 * buf_used: Total amount of buffer space used (including allocated space)
102 * buf_back_off_storage: tell buffering thread to take it easy
98 ****************************************************************************/ 103 ****************************************************************************/
99 104
105enum data_type buf_handle_data_type(int handle_id);
106ssize_t buf_handle_remaining(int handle_id);
107bool buf_is_handle(int handle_id);
100ssize_t buf_handle_offset(int handle_id); 108ssize_t buf_handle_offset(int handle_id);
101void buf_request_buffer_handle(int handle_id); 109void buf_request_buffer_handle(int handle_id);
102void buf_set_base_handle(int handle_id); 110void buf_set_base_handle(int handle_id);
111size_t buf_length(void);
103size_t buf_used(void); 112size_t buf_used(void);
104 113bool buf_pin_handle(int handle_id, bool pin);
105 114bool buf_signal_handle(int handle_id, bool signal);
115#ifdef HAVE_IO_PRIORITY
116void buf_back_off_storage(bool back_off);
117#endif
106 118
107/* Settings */ 119/* Settings */
108enum { 120enum {
@@ -110,6 +122,7 @@ enum {
110 BUFFERING_SET_CHUNKSIZE, 122 BUFFERING_SET_CHUNKSIZE,
111}; 123};
112void buf_set_watermark(size_t bytes); 124void buf_set_watermark(size_t bytes);
125size_t buf_get_watermark(void);
113 126
114/* Debugging */ 127/* Debugging */
115struct buffering_debug { 128struct buffering_debug {
diff --git a/apps/codec_thread.c b/apps/codec_thread.c
index 65a7ebc7d5..7cf45c3490 100644
--- a/apps/codec_thread.c
+++ b/apps/codec_thread.c
@@ -9,6 +9,7 @@
9 * 9 *
10 * Copyright (C) 2005-2007 Miika Pekkarinen 10 * Copyright (C) 2005-2007 Miika Pekkarinen
11 * Copyright (C) 2007-2008 Nicolas Pennequin 11 * Copyright (C) 2007-2008 Nicolas Pennequin
12 * Copyright (C) 2011 Michael Sevakis
12 * 13 *
13 * This program is free software; you can redistribute it and/or 14 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License 15 * modify it under the terms of the GNU General Public License
@@ -21,16 +22,14 @@
21 ****************************************************************************/ 22 ****************************************************************************/
22#include "config.h" 23#include "config.h"
23#include "system.h" 24#include "system.h"
24#include "playback.h"
25#include "codec_thread.h"
26#include "kernel.h" 25#include "kernel.h"
27#include "codecs.h" 26#include "codecs.h"
28#include "buffering.h" 27#include "codec_thread.h"
29#include "pcmbuf.h" 28#include "pcmbuf.h"
29#include "playback.h"
30#include "buffering.h"
30#include "dsp.h" 31#include "dsp.h"
31#include "abrepeat.h"
32#include "metadata.h" 32#include "metadata.h"
33#include "splash.h"
34 33
35/* Define LOGF_ENABLE to enable logf output in this file */ 34/* Define LOGF_ENABLE to enable logf output in this file */
36/*#define LOGF_ENABLE*/ 35/*#define LOGF_ENABLE*/
@@ -57,38 +56,45 @@
57#define LOGFQUEUE_SYS_TIMEOUT(...) 56#define LOGFQUEUE_SYS_TIMEOUT(...)
58#endif 57#endif
59 58
60
61/* Variables are commented with the threads that use them: 59/* Variables are commented with the threads that use them:
62 * A=audio, C=codec, V=voice. A suffix of - indicates that 60 * A=audio, C=codec
63 * the variable is read but not updated on that thread. 61 * - = reads only
64 62 *
65 * Unless otherwise noted, the extern variables are located 63 * Unless otherwise noted, the extern variables are located
66 * in playback.c. 64 * in playback.c.
67 */ 65 */
68 66
69/* Main state control */ 67/* Q_LOAD_CODEC parameter data */
70 68struct codec_load_info
71/* Type of codec loaded? (C/A) */ 69{
72static int current_codectype SHAREDBSS_ATTR = AFMT_UNKNOWN; 70 int hid; /* audio handle id (specify < 0 to use afmt) */
71 int afmt; /* codec specification (AFMT_*) */
72};
73 73
74extern struct mp3entry *thistrack_id3, /* the currently playing track */
75 *othertrack_id3; /* prev track during track-change-transition, or end of playlist,
76 * next track otherwise */
77 74
78/* Track change controls */ 75/** --- Main state control --- **/
79extern struct event_queue audio_queue SHAREDBSS_ATTR;
80 76
77static int codec_type = AFMT_UNKNOWN; /* Codec type (C,A-) */
81 78
79/* Private interfaces to main playback control */
80extern void audio_codec_update_elapsed(unsigned long value);
81extern void audio_codec_update_offset(size_t value);
82extern void audio_queue_post(long id, intptr_t data);
82extern struct codec_api ci; /* from codecs.c */ 83extern struct codec_api ci; /* from codecs.c */
83 84
84/* Codec thread */ 85/* Codec thread */
85static unsigned int codec_thread_id; /* For modifying thread priority later */ 86static unsigned int codec_thread_id; /* For modifying thread priority later */
86static struct event_queue codec_queue SHAREDBSS_ATTR; 87static struct event_queue codec_queue SHAREDBSS_ATTR;
87static struct queue_sender_list codec_queue_sender_list SHAREDBSS_ATTR; 88static struct queue_sender_list codec_queue_sender_list SHAREDBSS_ATTR;
88static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)] 89static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)] IBSS_ATTR;
89 IBSS_ATTR;
90static const char codec_thread_name[] = "codec"; 90static const char codec_thread_name[] = "codec";
91 91
92static void unload_codec(void);
93
94/* Messages are only ever sent one at a time to the codec from the audio
95 thread. This is important for correct operation unless playback is
96 stopped. */
97
92/* static routines */ 98/* static routines */
93static void codec_queue_ack(intptr_t ackme) 99static void codec_queue_ack(intptr_t ackme)
94{ 100{
@@ -100,52 +106,63 @@ static intptr_t codec_queue_send(long id, intptr_t data)
100 return queue_send(&codec_queue, id, data); 106 return queue_send(&codec_queue, id, data);
101} 107}
102 108
103/**************************************/ 109/* Poll the state of the codec queue. Returns < 0 if the message is urgent
110 and any state should exit, > 0 if it's a run message (and it was
111 scrubbed), 0 if message was ignored. */
112static int codec_check_queue__have_msg(void)
113{
114 struct queue_event ev;
104 115
105/** misc external functions */ 116 queue_peek(&codec_queue, &ev);
106 117
107/* Used to check whether a new codec must be loaded. See array audio_formats[] 118 /* Seek, pause or stop? Just peek and return if so. Codec
108 * in metadata.c */ 119 must handle the command after returing. Inserts will not
109int get_codec_base_type(int type) 120 be allowed until it complies. */
110{ 121 switch (ev.id)
111 int base_type = type; 122 {
112 switch (type) { 123 case Q_CODEC_SEEK:
113 case AFMT_MPA_L1: 124 LOGFQUEUE("codec - Q_CODEC_SEEK", ev.id);
114 case AFMT_MPA_L2: 125 return -1;
115 case AFMT_MPA_L3: 126 case Q_CODEC_PAUSE:
116 base_type = AFMT_MPA_L3; 127 LOGFQUEUE("codec - Q_CODEC_PAUSE", ev.id);
117 break; 128 return -1;
118 case AFMT_MPC_SV7: 129 case Q_CODEC_STOP:
119 case AFMT_MPC_SV8: 130 LOGFQUEUE("codec - Q_CODEC_STOP", ev.id);
120 base_type = AFMT_MPC_SV7; 131 return -1;
121 break;
122 case AFMT_MP4_AAC:
123 case AFMT_MP4_AAC_HE:
124 base_type = AFMT_MP4_AAC;
125 break;
126 case AFMT_SAP:
127 case AFMT_CMC:
128 case AFMT_CM3:
129 case AFMT_CMR:
130 case AFMT_CMS:
131 case AFMT_DMC:
132 case AFMT_DLT:
133 case AFMT_MPT:
134 case AFMT_MPD:
135 case AFMT_RMT:
136 case AFMT_TMC:
137 case AFMT_TM8:
138 case AFMT_TM2:
139 base_type = AFMT_SAP;
140 break;
141 default:
142 break;
143 } 132 }
144 133
145 return base_type; 134 /* This is in error in this context unless it's "go, go, go!" */
135 queue_wait(&codec_queue, &ev);
136
137 if (ev.id == Q_CODEC_RUN)
138 {
139 logf("codec < Q_CODEC_RUN: already running!");
140 codec_queue_ack(Q_CODEC_RUN);
141 return 1;
142 }
143
144 /* Ignore it */
145 logf("codec < bad req %ld (%s)", ev.id, __func__);
146 codec_queue_ack(Q_NULL);
147 return 0;
148}
149
150/* Does the audio format type equal CODEC_TYPE_ENCODER? */
151static inline bool type_is_encoder(int afmt)
152{
153#ifdef AUDIO_HAVE_RECORDING
154 return (afmt & CODEC_TYPE_MASK) == CODEC_TYPE_ENCODER;
155#else
156 return false;
157 (void)afmt;
158#endif
146} 159}
147 160
148const char *get_codec_filename(int cod_spec) 161/**************************************/
162
163
164/** --- Miscellaneous external functions --- **/
165const char * get_codec_filename(int cod_spec)
149{ 166{
150 const char *fname; 167 const char *fname;
151 168
@@ -173,7 +190,7 @@ const char *get_codec_filename(int cod_spec)
173#endif /* HAVE_RECORDING */ 190#endif /* HAVE_RECORDING */
174 191
175 return fname; 192 return fname;
176} /* get_codec_filename */ 193}
177 194
178/* Borrow the codec thread and return the ID */ 195/* Borrow the codec thread and return the ID */
179void codec_thread_do_callback(void (*fn)(void), unsigned int *id) 196void codec_thread_do_callback(void (*fn)(void), unsigned int *id)
@@ -189,9 +206,9 @@ void codec_thread_do_callback(void (*fn)(void), unsigned int *id)
189} 206}
190 207
191 208
192/** codec API callbacks */ 209/** --- codec API callbacks --- **/
193 210
194static void* codec_get_buffer(size_t *size) 211static void * codec_get_buffer(size_t *size)
195{ 212{
196 ssize_t s = CODEC_SIZE - codec_size; 213 ssize_t s = CODEC_SIZE - codec_size;
197 void *buf = &codecbuf[codec_size]; 214 void *buf = &codecbuf[codec_size];
@@ -215,15 +232,19 @@ static void codec_pcmbuf_insert_callback(
215 int inp_count; 232 int inp_count;
216 char *dest; 233 char *dest;
217 234
218 /* Prevent audio from a previous track from playing */ 235 while (1)
219 if (ci.new_track || ci.stop_codec)
220 return;
221
222 while ((dest = pcmbuf_request_buffer(&out_count)) == NULL)
223 { 236 {
237 if ((dest = pcmbuf_request_buffer(&out_count)) != NULL)
238 break;
239
224 cancel_cpu_boost(); 240 cancel_cpu_boost();
225 sleep(1); 241
226 if (ci.seek_time || ci.new_track || ci.stop_codec) 242 /* It will be awhile before space is available but we want
243 "instant" response to any message */
244 queue_wait_w_tmo(&codec_queue, NULL, HZ/20);
245
246 if (!queue_empty(&codec_queue) &&
247 codec_check_queue__have_msg() < 0)
227 return; 248 return;
228 } 249 }
229 250
@@ -247,62 +268,28 @@ static void codec_pcmbuf_insert_callback(
247 268
248 count -= inp_count; 269 count -= inp_count;
249 } 270 }
250} /* codec_pcmbuf_insert_callback */ 271}
251 272
252static void codec_set_elapsed_callback(unsigned long value) 273/* helper function, not a callback */
274static bool codec_advance_buffer_counters(size_t amount)
253{ 275{
254 if (ci.seek_time) 276 if (bufadvance(ci.audio_hid, amount) < 0)
255 return;
256
257#ifdef AB_REPEAT_ENABLE
258 ab_position_report(value);
259#endif
260
261 unsigned long latency = pcmbuf_get_latency();
262 if (value < latency)
263 thistrack_id3->elapsed = 0;
264 else
265 { 277 {
266 unsigned long elapsed = value - latency; 278 ci.curpos = ci.filesize;
267 if (elapsed > thistrack_id3->elapsed || 279 return false;
268 elapsed < thistrack_id3->elapsed - 2)
269 {
270 thistrack_id3->elapsed = elapsed;
271 }
272 } 280 }
273}
274
275static void codec_set_offset_callback(size_t value)
276{
277 if (ci.seek_time)
278 return;
279 281
280 unsigned long latency = pcmbuf_get_latency() * thistrack_id3->bitrate / 8;
281 if (value < latency)
282 thistrack_id3->offset = 0;
283 else
284 thistrack_id3->offset = value - latency;
285}
286
287/* helper function, not a callback */
288static void codec_advance_buffer_counters(size_t amount)
289{
290 bufadvance(get_audio_hid(), amount);
291 ci.curpos += amount; 282 ci.curpos += amount;
283 return true;
292} 284}
293 285
294/* copy up-to size bytes into ptr and return the actual size copied */ 286/* copy up-to size bytes into ptr and return the actual size copied */
295static size_t codec_filebuf_callback(void *ptr, size_t size) 287static size_t codec_filebuf_callback(void *ptr, size_t size)
296{ 288{
297 ssize_t copy_n; 289 ssize_t copy_n = bufread(ci.audio_hid, size, ptr);
298
299 if (ci.stop_codec)
300 return 0;
301
302 copy_n = bufread(get_audio_hid(), size, ptr);
303 290
304 /* Nothing requested OR nothing left */ 291 /* Nothing requested OR nothing left */
305 if (copy_n == 0) 292 if (copy_n <= 0)
306 return 0; 293 return 0;
307 294
308 /* Update read and other position pointers */ 295 /* Update read and other position pointers */
@@ -310,15 +297,15 @@ static size_t codec_filebuf_callback(void *ptr, size_t size)
310 297
311 /* Return the actual amount of data copied to the buffer */ 298 /* Return the actual amount of data copied to the buffer */
312 return copy_n; 299 return copy_n;
313} /* codec_filebuf_callback */ 300}
314 301
315static void* codec_request_buffer_callback(size_t *realsize, size_t reqsize) 302static void * codec_request_buffer_callback(size_t *realsize, size_t reqsize)
316{ 303{
317 size_t copy_n = reqsize; 304 size_t copy_n = reqsize;
318 ssize_t ret; 305 ssize_t ret;
319 void *ptr; 306 void *ptr;
320 307
321 ret = bufgetdata(get_audio_hid(), reqsize, &ptr); 308 ret = bufgetdata(ci.audio_hid, reqsize, &ptr);
322 if (ret >= 0) 309 if (ret >= 0)
323 copy_n = MIN((size_t)ret, reqsize); 310 copy_n = MIN((size_t)ret, reqsize);
324 else 311 else
@@ -329,101 +316,103 @@ static void* codec_request_buffer_callback(size_t *realsize, size_t reqsize)
329 316
330 *realsize = copy_n; 317 *realsize = copy_n;
331 return ptr; 318 return ptr;
332} /* codec_request_buffer_callback */ 319}
333 320
334static void codec_advance_buffer_callback(size_t amount) 321static void codec_advance_buffer_callback(size_t amount)
335{ 322{
336 codec_advance_buffer_counters(amount); 323 if (!codec_advance_buffer_counters(amount))
337 codec_set_offset_callback(ci.curpos); 324 return;
325
326 audio_codec_update_offset(ci.curpos);
338} 327}
339 328
340static bool codec_seek_buffer_callback(size_t newpos) 329static bool codec_seek_buffer_callback(size_t newpos)
341{ 330{
342 logf("codec_seek_buffer_callback"); 331 logf("codec_seek_buffer_callback");
343 332
344 int ret = bufseek(get_audio_hid(), newpos); 333 int ret = bufseek(ci.audio_hid, newpos);
345 if (ret == 0) { 334 if (ret == 0)
335 {
346 ci.curpos = newpos; 336 ci.curpos = newpos;
347 return true; 337 return true;
348 } 338 }
349 else { 339
350 return false; 340 return false;
351 }
352} 341}
353 342
354static void codec_seek_complete_callback(void) 343static void codec_seek_complete_callback(void)
355{ 344{
356 struct queue_event ev;
357
358 logf("seek_complete"); 345 logf("seek_complete");
359 346
360 /* Clear DSP */ 347 /* Clear DSP */
361 dsp_configure(ci.dsp, DSP_FLUSH, 0); 348 dsp_configure(ci.dsp, DSP_FLUSH, 0);
362 349
363 /* Post notification to audio thread */ 350 /* Post notification to audio thread */
364 LOGFQUEUE("audio > Q_AUDIO_SEEK_COMPLETE"); 351 LOGFQUEUE("audio > Q_AUDIO_CODEC_SEEK_COMPLETE");
365 queue_post(&audio_queue, Q_AUDIO_SEEK_COMPLETE, 0); 352 audio_queue_post(Q_AUDIO_CODEC_SEEK_COMPLETE, 0);
366
367 /* Wait for ACK */
368 queue_wait(&codec_queue, &ev);
369 353
370 /* ACK back in context */ 354 /* Wait for urgent or go message */
371 codec_queue_ack(Q_AUDIO_SEEK_COMPLETE); 355 do
356 {
357 queue_wait(&codec_queue, NULL);
358 }
359 while (codec_check_queue__have_msg() == 0);
372} 360}
373 361
374static bool codec_request_next_track_callback(void) 362static void codec_configure_callback(int setting, intptr_t value)
375{ 363{
376 struct queue_event ev; 364 if (!dsp_configure(ci.dsp, setting, value))
377 365 {
378 logf("Request new track"); 366 logf("Illegal key: %d", setting);
367 }
368}
379 369
380 audio_set_prev_elapsed(thistrack_id3->elapsed); 370static enum codec_command_action
371 codec_get_command_callback(intptr_t *param)
372{
373 yield();
381 374
382#ifdef AB_REPEAT_ENABLE 375 if (LIKELY(queue_empty(&codec_queue)))
383 ab_end_of_track_report(); 376 return CODEC_ACTION_NULL; /* As you were */
384#endif
385 377
386 if (ci.stop_codec) 378 /* Process the message - return requested action and data (if any should
379 be expected) */
380 while (1)
387 { 381 {
388 /* Handle ACK in outer loop */ 382 enum codec_command_action action = CODEC_ACTION_NULL;
389 LOGFQUEUE("codec: already stopping"); 383 struct queue_event ev;
390 return false; 384 queue_wait(&codec_queue, &ev);
391 }
392 385
393 trigger_cpu_boost(); 386 switch (ev.id)
387 {
388 case Q_CODEC_RUN: /* Already running */
389 LOGFQUEUE("codec < Q_CODEC_RUN");
390 break;
394 391
395 /* Post request to audio thread */ 392 case Q_CODEC_PAUSE: /* Stay here and wait */
396 LOGFQUEUE("codec > audio Q_AUDIO_CHECK_NEW_TRACK"); 393 LOGFQUEUE("codec < Q_CODEC_PAUSE");
397 queue_post(&audio_queue, Q_AUDIO_CHECK_NEW_TRACK, 0); 394 codec_queue_ack(Q_CODEC_PAUSE);
395 continue;
398 396
399 /* Wait for ACK */ 397 case Q_CODEC_SEEK: /* Audio wants codec to seek */
400 queue_wait(&codec_queue, &ev); 398 LOGFQUEUE("codec < Q_CODEC_SEEK %ld", ev.data);
399 *param = ev.data;
400 action = CODEC_ACTION_SEEK_TIME;
401 break;
401 402
402 if (ev.data == Q_CODEC_REQUEST_COMPLETE) 403 case Q_CODEC_STOP: /* Must only return 0 in main loop */
403 { 404 LOGFQUEUE("codec < Q_CODEC_STOP");
404 /* Seek to the beginning of the new track because if the struct 405 action = CODEC_ACTION_HALT;
405 mp3entry was buffered, "elapsed" might not be zero (if the track has 406 break;
406 been played already but not unbuffered) */
407 codec_seek_buffer_callback(thistrack_id3->first_frame_offset);
408 }
409 407
410 /* ACK back in context */ 408 default: /* This is in error in this context. */
411 codec_queue_ack(Q_AUDIO_CHECK_NEW_TRACK); 409 ev.id = Q_NULL;
410 logf("codec bad req %ld (%s)", ev.id, __func__);
411 }
412 412
413 if (ev.data != Q_CODEC_REQUEST_COMPLETE || ci.stop_codec) 413 codec_queue_ack(ev.id);
414 { 414 return action;
415 LOGFQUEUE("codec <= request failed (%d)", ev.data);
416 return false;
417 } 415 }
418
419 LOGFQUEUE("codec <= Q_CODEC_REQEST_COMPLETE");
420 return true;
421}
422
423static void codec_configure_callback(int setting, intptr_t value)
424{
425 if (!dsp_configure(ci.dsp, setting, value))
426 { logf("Illegal key:%d", setting); }
427} 416}
428 417
429/* Initialize codec API */ 418/* Initialize codec API */
@@ -433,119 +422,215 @@ void codec_init_codec_api(void)
433 CODEC_IDX_AUDIO); 422 CODEC_IDX_AUDIO);
434 ci.codec_get_buffer = codec_get_buffer; 423 ci.codec_get_buffer = codec_get_buffer;
435 ci.pcmbuf_insert = codec_pcmbuf_insert_callback; 424 ci.pcmbuf_insert = codec_pcmbuf_insert_callback;
436 ci.set_elapsed = codec_set_elapsed_callback; 425 ci.set_elapsed = audio_codec_update_elapsed;
437 ci.read_filebuf = codec_filebuf_callback; 426 ci.read_filebuf = codec_filebuf_callback;
438 ci.request_buffer = codec_request_buffer_callback; 427 ci.request_buffer = codec_request_buffer_callback;
439 ci.advance_buffer = codec_advance_buffer_callback; 428 ci.advance_buffer = codec_advance_buffer_callback;
440 ci.seek_buffer = codec_seek_buffer_callback; 429 ci.seek_buffer = codec_seek_buffer_callback;
441 ci.seek_complete = codec_seek_complete_callback; 430 ci.seek_complete = codec_seek_complete_callback;
442 ci.request_next_track = codec_request_next_track_callback; 431 ci.set_offset = audio_codec_update_offset;
443 ci.set_offset = codec_set_offset_callback;
444 ci.configure = codec_configure_callback; 432 ci.configure = codec_configure_callback;
433 ci.get_command = codec_get_command_callback;
445} 434}
446 435
447 436
448/* track change */ 437/** --- CODEC THREAD --- **/
449 438
450/** CODEC THREAD */ 439/* Handle Q_CODEC_LOAD */
451static void codec_thread(void) 440static void load_codec(const struct codec_load_info *ev_data)
452{ 441{
453 struct queue_event ev; 442 int status = CODEC_ERROR;
443 /* Save a local copy so we can let the audio thread go ASAP */
444 struct codec_load_info data = *ev_data;
445 bool const encoder = type_is_encoder(data.afmt);
454 446
447 if (codec_type != AFMT_UNKNOWN)
448 {
449 /* Must have unloaded it first */
450 logf("a codec is already loaded");
451 if (data.hid >= 0)
452 bufclose(data.hid);
453 return;
454 }
455 455
456 while (1) 456 trigger_cpu_boost();
457
458 if (!encoder)
457 { 459 {
458 int status = CODEC_OK; 460 /* Do this now because codec may set some things up at load time */
459 void *handle = NULL; 461 dsp_configure(ci.dsp, DSP_RESET, 0);
460 int hid; 462 }
461 const char *codec_fn; 463
462 464 if (data.hid >= 0)
463#ifdef HAVE_CROSSFADE 465 {
464 if (!pcmbuf_is_crossfade_active()) 466 /* First try buffer load */
465#endif 467 status = codec_load_buf(data.hid, &ci);
468 bufclose(data.hid);
469 }
470
471 if (status < 0)
472 {
473 /* Either not a valid handle or the buffer method failed */
474 const char *codec_fn = get_codec_filename(data.afmt);
475 if (codec_fn)
466 { 476 {
467 cancel_cpu_boost(); 477#ifdef HAVE_IO_PRIORITY
478 buf_back_off_storage(true);
479#endif
480 status = codec_load_file(codec_fn, &ci);
481#ifdef HAVE_IO_PRIORITY
482 buf_back_off_storage(false);
483#endif
468 } 484 }
485 }
486
487 if (status >= 0)
488 {
489 codec_type = data.afmt;
490 codec_queue_ack(Q_CODEC_LOAD);
491 return;
492 }
493
494 /* Failed - get rid of it */
495 unload_codec();
496}
497
498/* Handle Q_CODEC_RUN */
499static void run_codec(void)
500{
501 bool const encoder = type_is_encoder(codec_type);
502 int status;
503
504 if (codec_type == AFMT_UNKNOWN)
505 {
506 logf("no codec to run");
507 return;
508 }
509
510 codec_queue_ack(Q_CODEC_RUN);
511
512 trigger_cpu_boost();
513
514 if (!encoder)
515 {
516 /* This will be either the initial buffered offset or where it left off
517 if it remained buffered and we're skipping back to it and it is best
518 to have ci.curpos in sync with the handle's read position - it's the
519 codec's responsibility to ensure it has the correct positions -
520 playback is sorta dumb and only has a vague idea about what to
521 buffer based upon what metadata has to say */
522 ci.curpos = bufftell(ci.audio_hid);
523
524 /* Pin the codec's audio data in place */
525 buf_pin_handle(ci.audio_hid, true);
526 }
527
528 status = codec_run_proc();
529
530 if (!encoder)
531 {
532 /* Codec is done with it - let it move */
533 buf_pin_handle(ci.audio_hid, false);
534
535 /* Notify audio that we're done for better or worse - advise of the
536 status */
537 LOGFQUEUE("codec > audio Q_AUDIO_CODEC_COMPLETE: %d", status);
538 audio_queue_post(Q_AUDIO_CODEC_COMPLETE, status);
539 }
540}
541
542/* Handle Q_CODEC_SEEK */
543static void seek_codec(unsigned long time)
544{
545 if (codec_type == AFMT_UNKNOWN)
546 {
547 logf("no codec to seek");
548 codec_queue_ack(Q_CODEC_SEEK);
549 codec_seek_complete_callback();
550 return;
551 }
552
553 /* Post it up one level */
554 queue_post(&codec_queue, Q_CODEC_SEEK, time);
555 codec_queue_ack(Q_CODEC_SEEK);
556
557 /* Have to run it again */
558 run_codec();
559}
560
561/* Handle Q_CODEC_UNLOAD */
562static void unload_codec(void)
563{
564 /* Tell codec to clean up */
565 codec_type = AFMT_UNKNOWN;
566 codec_close();
567}
568
569/* Handle Q_CODEC_DO_CALLBACK */
570static void do_callback(void (* callback)(void))
571{
572 codec_queue_ack(Q_CODEC_DO_CALLBACK);
573
574 if (callback)
575 {
576 cpucache_commit_discard();
577 callback();
578 cpucache_commit();
579 }
580}
581
582/* Codec thread function */
583static void NORETURN_ATTR codec_thread(void)
584{
585 struct queue_event ev;
586
587 while (1)
588 {
589 cancel_cpu_boost();
469 590
470 queue_wait(&codec_queue, &ev); 591 queue_wait(&codec_queue, &ev);
471 592
472 switch (ev.id) 593 switch (ev.id)
473 { 594 {
474 case Q_CODEC_LOAD_DISK: 595 case Q_CODEC_LOAD:
475 LOGFQUEUE("codec < Q_CODEC_LOAD_DISK"); 596 LOGFQUEUE("codec < Q_CODEC_LOAD");
476 codec_fn = get_codec_filename(ev.data); 597 load_codec((const struct codec_load_info *)ev.data);
477 if (!codec_fn) 598 break;
478 break;
479#ifdef AUDIO_HAVE_RECORDING
480 if (ev.data & CODEC_TYPE_ENCODER)
481 {
482 ev.id = Q_ENCODER_LOAD_DISK;
483 handle = codec_load_file(codec_fn, &ci);
484 if (handle)
485 codec_queue_ack(Q_ENCODER_LOAD_DISK);
486 }
487 else
488#endif
489 {
490 codec_queue_ack(Q_CODEC_LOAD_DISK);
491 handle = codec_load_file(codec_fn, &ci);
492 }
493 break;
494 599
495 case Q_CODEC_LOAD: 600 case Q_CODEC_RUN:
496 LOGFQUEUE("codec < Q_CODEC_LOAD"); 601 LOGFQUEUE("codec < Q_CODEC_RUN");
497 codec_queue_ack(Q_CODEC_LOAD); 602 run_codec();
498 hid = (int)ev.data; 603 break;
499 handle = codec_load_buf(hid, &ci);
500 bufclose(hid);
501 break;
502 604
503 case Q_CODEC_DO_CALLBACK: 605 case Q_CODEC_PAUSE:
504 LOGFQUEUE("codec < Q_CODEC_DO_CALLBACK"); 606 LOGFQUEUE("codec < Q_CODEC_PAUSE");
505 codec_queue_ack(Q_CODEC_DO_CALLBACK); 607 break;
506 if ((void*)ev.data != NULL)
507 {
508 cpucache_commit_discard();
509 ((void (*)(void))ev.data)();
510 cpucache_commit();
511 }
512 break;
513 608
514 default: 609 case Q_CODEC_SEEK:
515 LOGFQUEUE("codec < default : %ld", ev.id); 610 LOGFQUEUE("codec < Q_CODEC_SEEK: %lu", (unsigned long)ev.data);
516 } 611 seek_codec(ev.data);
612 break;
517 613
518 if (handle) 614 case Q_CODEC_UNLOAD:
519 { 615 LOGFQUEUE("codec < Q_CODEC_UNLOAD");
520 /* Codec loaded - call the entrypoint */ 616 unload_codec();
521 yield(); 617 break;
522 logf("codec running");
523 status = codec_begin(handle);
524 logf("codec stopped");
525 codec_close(handle);
526 current_codectype = AFMT_UNKNOWN;
527
528 if (ci.stop_codec)
529 status = CODEC_OK;
530 }
531 618
532 switch (ev.id) 619 case Q_CODEC_DO_CALLBACK:
533 { 620 LOGFQUEUE("codec < Q_CODEC_DO_CALLBACK");
534#ifdef AUDIO_HAVE_RECORDING 621 do_callback((void (*)(void))ev.data);
535 case Q_ENCODER_LOAD_DISK: 622 break;
536#endif 623
537 case Q_CODEC_LOAD_DISK: 624 default:
538 case Q_CODEC_LOAD: 625 LOGFQUEUE("codec < default : %ld", ev.id);
539 /* Notify about the status */
540 if (!handle)
541 status = CODEC_ERROR;
542 LOGFQUEUE("codec > audio notify status: %d", status);
543 queue_post(&audio_queue, ev.id, status);
544 break;
545 } 626 }
546 } 627 }
547} 628}
548 629
630
631/** --- Miscellaneous external interfaces -- **/
632
633/* Create the codec thread and init kernel objects */
549void make_codec_thread(void) 634void make_codec_thread(void)
550{ 635{
551 queue_init(&codec_queue, false); 636 queue_init(&codec_queue, false);
@@ -558,78 +643,86 @@ void make_codec_thread(void)
558 codec_thread_id); 643 codec_thread_id);
559} 644}
560 645
646/* Unfreeze the codec thread */
561void codec_thread_resume(void) 647void codec_thread_resume(void)
562{ 648{
563 thread_thaw(codec_thread_id); 649 thread_thaw(codec_thread_id);
564} 650}
565 651
652/* Is the current thread the codec thread? */
566bool is_codec_thread(void) 653bool is_codec_thread(void)
567{ 654{
568 return thread_self() == codec_thread_id; 655 return thread_self() == codec_thread_id;
569} 656}
570 657
571#ifdef HAVE_PRIORITY_SCHEDULING 658#ifdef HAVE_PRIORITY_SCHEDULING
659/* Obtain codec thread's current priority */
572int codec_thread_get_priority(void) 660int codec_thread_get_priority(void)
573{ 661{
574 return thread_get_priority(codec_thread_id); 662 return thread_get_priority(codec_thread_id);
575} 663}
576 664
665/* Set the codec thread's priority and return the old value */
577int codec_thread_set_priority(int priority) 666int codec_thread_set_priority(int priority)
578{ 667{
579 return thread_set_priority(codec_thread_id, priority); 668 return thread_set_priority(codec_thread_id, priority);
580} 669}
581#endif /* HAVE_PRIORITY_SCHEDULING */ 670#endif /* HAVE_PRIORITY_SCHEDULING */
582 671
583/* functions for audio thread use */
584intptr_t codec_ack_msg(intptr_t data, bool stop_codec)
585{
586 intptr_t resp;
587 LOGFQUEUE("codec >| Q_CODEC_ACK: %d", data);
588 if (stop_codec)
589 ci.stop_codec = true;
590 resp = codec_queue_send(Q_CODEC_ACK, data);
591 if (stop_codec)
592 codec_stop();
593 LOGFQUEUE(" ack: %ld", resp);
594 return resp;
595}
596 672
673/** --- Functions for audio thread use --- **/
674
675/* Load a decoder or encoder and set the format type */
597bool codec_load(int hid, int cod_spec) 676bool codec_load(int hid, int cod_spec)
598{ 677{
599 bool retval = false; 678 struct codec_load_info parm = { hid, cod_spec };
600 679
601 ci.stop_codec = false; 680 LOGFQUEUE("audio >| codec Q_CODEC_LOAD: %d, %d", hid, cod_spec);
602 current_codectype = cod_spec; 681 return codec_queue_send(Q_CODEC_LOAD, (intptr_t)&parm) != 0;
682}
603 683
604 if (hid >= 0) 684/* Begin decoding the current file */
605 { 685void codec_go(void)
606 LOGFQUEUE("audio >| codec Q_CODEC_LOAD: %d", hid); 686{
607 retval = codec_queue_send(Q_CODEC_LOAD, hid) != Q_NULL; 687 LOGFQUEUE("audio >| codec Q_CODEC_RUN");
608 } 688 codec_queue_send(Q_CODEC_RUN, 0);
609 else 689}
610 {
611 LOGFQUEUE("audio >| codec Q_CODEC_LOAD_DISK: %d", cod_spec);
612 retval = codec_queue_send(Q_CODEC_LOAD_DISK, cod_spec) != Q_NULL;
613 }
614 690
615 if (!retval) 691/* Instruct the codec to seek to the specified time (should be properly
616 { 692 paused or stopped first to avoid possible buffering deadlock) */
617 ci.stop_codec = true; 693void codec_seek(long time)
618 current_codectype = AFMT_UNKNOWN; 694{
619 } 695 LOGFQUEUE("audio > codec Q_CODEC_SEEK: %ld", time);
696 codec_queue_send(Q_CODEC_SEEK, time);
697}
620 698
621 return retval; 699/* Pause the codec and make it wait for further instructions inside the
700 command callback */
701bool codec_pause(void)
702{
703 LOGFQUEUE("audio >| codec Q_CODEC_PAUSE");
704 return codec_queue_send(Q_CODEC_PAUSE, 0) != Q_NULL;
622} 705}
623 706
707/* Stop codec if running - codec stays resident if loaded */
624void codec_stop(void) 708void codec_stop(void)
625{ 709{
626 ci.stop_codec = true;
627 /* Wait until it's in the main loop */ 710 /* Wait until it's in the main loop */
628 while (codec_ack_msg(0, false) != Q_NULL); 711 LOGFQUEUE("audio >| codec Q_CODEC_STOP");
629 current_codectype = AFMT_UNKNOWN; 712 while (codec_queue_send(Q_CODEC_STOP, 0) != Q_NULL);
713}
714
715/* Call the codec's exit routine and close all references */
716void codec_unload(void)
717{
718 codec_stop();
719 LOGFQUEUE("audio >| codec Q_CODEC_UNLOAD");
720 codec_queue_send(Q_CODEC_UNLOAD, 0);
630} 721}
631 722
723/* Return the afmt type of the loaded codec - sticks until calling
724 codec_unload unless initial load failed */
632int codec_loaded(void) 725int codec_loaded(void)
633{ 726{
634 return current_codectype; 727 return codec_type;
635} 728}
diff --git a/apps/codec_thread.h b/apps/codec_thread.h
index 7056e2cdf5..acd7e556e2 100644
--- a/apps/codec_thread.h
+++ b/apps/codec_thread.h
@@ -25,7 +25,6 @@
25#include <stdbool.h> 25#include <stdbool.h>
26 26
27/* codec identity */ 27/* codec identity */
28int get_codec_base_type(int type);
29const char *get_codec_filename(int cod_spec); 28const char *get_codec_filename(int cod_spec);
30 29
31/* codec thread */ 30/* codec thread */
@@ -44,10 +43,14 @@ int codec_thread_set_priority(int priority);
44#endif 43#endif
45 44
46/* codec commands - on audio thread only! */ 45/* codec commands - on audio thread only! */
47intptr_t codec_ack_msg(intptr_t data, bool stop_codec);
48bool codec_load(int hid, int cod_spec); 46bool codec_load(int hid, int cod_spec);
47void codec_go(void);
48bool codec_pause(void);
49void codec_seek(long time);
49void codec_stop(void); 50void codec_stop(void);
51void codec_unload(void);
50int codec_loaded(void); 52int codec_loaded(void);
53
51/* */ 54/* */
52 55
53#endif /* _CODEC_THREAD_H */ 56#endif /* _CODEC_THREAD_H */
diff --git a/apps/codecs.c b/apps/codecs.c
index 28e8c2a1c0..25ace4969b 100644
--- a/apps/codecs.c
+++ b/apps/codecs.c
@@ -79,13 +79,10 @@ static int open(const char* pathname, int flags, ...)
79#endif 79#endif
80struct codec_api ci = { 80struct codec_api ci = {
81 81
82 0, /* filesize */ 82 0, /* filesize */
83 0, /* curpos */ 83 0, /* curpos */
84 NULL, /* id3 */ 84 NULL, /* id3 */
85 NULL, /* taginfo_ready */ 85 ERR_HANDLE_NOT_FOUND, /* audio_hid */
86 false, /* stop_codec */
87 0, /* new_track */
88 0, /* seek_time */
89 NULL, /* struct dsp_config *dsp */ 86 NULL, /* struct dsp_config *dsp */
90 NULL, /* codec_get_buffer */ 87 NULL, /* codec_get_buffer */
91 NULL, /* pcmbuf_insert */ 88 NULL, /* pcmbuf_insert */
@@ -95,9 +92,9 @@ struct codec_api ci = {
95 NULL, /* advance_buffer */ 92 NULL, /* advance_buffer */
96 NULL, /* seek_buffer */ 93 NULL, /* seek_buffer */
97 NULL, /* seek_complete */ 94 NULL, /* seek_complete */
98 NULL, /* request_next_track */
99 NULL, /* set_offset */ 95 NULL, /* set_offset */
100 NULL, /* configure */ 96 NULL, /* configure */
97 NULL, /* get_command */
101 98
102 /* kernel/ system */ 99 /* kernel/ system */
103#if defined(CPU_ARM) && CONFIG_PLATFORM & PLATFORM_NATIVE 100#if defined(CPU_ARM) && CONFIG_PLATFORM & PLATFORM_NATIVE
@@ -174,10 +171,16 @@ void codec_get_full_path(char *path, const char *codec_root_fn)
174 CODECS_DIR, codec_root_fn); 171 CODECS_DIR, codec_root_fn);
175} 172}
176 173
177static void * codec_load_ram(void *handle, struct codec_api *api) 174/** codec loading and call interface **/
175static void *curr_handle = NULL;
176static struct codec_header *c_hdr = NULL;
177
178static int codec_load_ram(struct codec_api *api)
178{ 179{
179 struct codec_header *c_hdr = lc_get_header(handle); 180 struct lc_header *hdr;
180 struct lc_header *hdr = c_hdr ? &c_hdr->lc_hdr : NULL; 181
182 c_hdr = lc_get_header(curr_handle);
183 hdr = c_hdr ? &c_hdr->lc_hdr : NULL;
181 184
182 if (hdr == NULL 185 if (hdr == NULL
183 || (hdr->magic != CODEC_MAGIC 186 || (hdr->magic != CODEC_MAGIC
@@ -193,15 +196,17 @@ static void * codec_load_ram(void *handle, struct codec_api *api)
193 ) 196 )
194 { 197 {
195 logf("codec header error"); 198 logf("codec header error");
196 lc_close(handle); 199 lc_close(curr_handle);
197 return NULL; 200 curr_handle = NULL;
201 return CODEC_ERROR;
198 } 202 }
199 203
200 if (hdr->api_version > CODEC_API_VERSION 204 if (hdr->api_version > CODEC_API_VERSION
201 || hdr->api_version < CODEC_MIN_API_VERSION) { 205 || hdr->api_version < CODEC_MIN_API_VERSION) {
202 logf("codec api version error"); 206 logf("codec api version error");
203 lc_close(handle); 207 lc_close(curr_handle);
204 return NULL; 208 curr_handle = NULL;
209 return CODEC_ERROR;
205 } 210 }
206 211
207#if (CONFIG_PLATFORM & PLATFORM_NATIVE) 212#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
@@ -212,63 +217,66 @@ static void * codec_load_ram(void *handle, struct codec_api *api)
212 217
213 *(c_hdr->api) = api; 218 *(c_hdr->api) = api;
214 219
215 return handle; 220 logf("Codec: calling entrypoint");
221 return c_hdr->entry_point(CODEC_LOAD);
216} 222}
217 223
218void * codec_load_buf(int hid, struct codec_api *api) 224int codec_load_buf(int hid, struct codec_api *api)
219{ 225{
220 int rc; 226 int rc = bufread(hid, CODEC_SIZE, codecbuf);
221 void *handle; 227
222 rc = bufread(hid, CODEC_SIZE, codecbuf);
223 if (rc < 0) { 228 if (rc < 0) {
224 logf("Codec: cannot read buf handle"); 229 logf("Codec: cannot read buf handle");
225 return NULL; 230 return CODEC_ERROR;
226 } 231 }
227 232
228 handle = lc_open_from_mem(codecbuf, rc); 233 curr_handle = lc_open_from_mem(codecbuf, rc);
229 234
230 if (handle == NULL) { 235 if (curr_handle == NULL) {
231 logf("error loading codec"); 236 logf("Codec: load error");
232 return NULL; 237 return CODEC_ERROR;
233 } 238 }
234 239
235 return codec_load_ram(handle, api); 240 return codec_load_ram(api);
236} 241}
237 242
238void * codec_load_file(const char *plugin, struct codec_api *api) 243int codec_load_file(const char *plugin, struct codec_api *api)
239{ 244{
240 char path[MAX_PATH]; 245 char path[MAX_PATH];
241 void *handle;
242 246
243 codec_get_full_path(path, plugin); 247 codec_get_full_path(path, plugin);
244 248
245 handle = lc_open(path, codecbuf, CODEC_SIZE); 249 curr_handle = lc_open(path, codecbuf, CODEC_SIZE);
246 250
247 if (handle == NULL) { 251 if (curr_handle == NULL) {
248 logf("Codec: cannot read file"); 252 logf("Codec: cannot read file");
249 return NULL; 253 return CODEC_ERROR;
250 } 254 }
251 255
252 return codec_load_ram(handle, api); 256 return codec_load_ram(api);
253} 257}
254 258
255int codec_begin(void *handle) 259int codec_run_proc(void)
256{ 260{
257 int status = CODEC_ERROR; 261 if (curr_handle == NULL) {
258 struct codec_header *c_hdr; 262 logf("Codec: no codec to run");
259 263 return CODEC_ERROR;
260 c_hdr = lc_get_header(handle);
261
262 if (c_hdr != NULL) {
263 logf("Codec: calling entry_point");
264 status = c_hdr->entry_point();
265 } 264 }
266 265
267 return status; 266 logf("Codec: entering run state");
267 return c_hdr->run_proc();
268} 268}
269 269
270void codec_close(void *handle) 270int codec_close(void)
271{ 271{
272 if (handle) 272 int status = CODEC_OK;
273 lc_close(handle); 273
274 if (curr_handle != NULL) {
275 logf("Codec: cleaning up");
276 status = c_hdr->entry_point(CODEC_UNLOAD);
277 lc_close(curr_handle);
278 curr_handle = NULL;
279 }
280
281 return status;
274} 282}
diff --git a/apps/codecs.h b/apps/codecs.h
index d96b2a7c9a..5c50116038 100644
--- a/apps/codecs.h
+++ b/apps/codecs.h
@@ -75,12 +75,18 @@
75#define CODEC_ENC_MAGIC 0x52454E43 /* RENC */ 75#define CODEC_ENC_MAGIC 0x52454E43 /* RENC */
76 76
77/* increase this every time the api struct changes */ 77/* increase this every time the api struct changes */
78#define CODEC_API_VERSION 41 78#define CODEC_API_VERSION 42
79 79
80/* update this to latest version if a change to the api struct breaks 80/* update this to latest version if a change to the api struct breaks
81 backwards compatibility (and please take the opportunity to sort in any 81 backwards compatibility (and please take the opportunity to sort in any
82 new function which are "waiting" at the end of the function table) */ 82 new function which are "waiting" at the end of the function table) */
83#define CODEC_MIN_API_VERSION 41 83#define CODEC_MIN_API_VERSION 42
84
85/* reasons for calling codec main entrypoint */
86enum codec_entry_call_reason {
87 CODEC_LOAD = 0,
88 CODEC_UNLOAD
89};
84 90
85/* codec return codes */ 91/* codec return codes */
86enum codec_status { 92enum codec_status {
@@ -88,6 +94,13 @@ enum codec_status {
88 CODEC_ERROR = -1, 94 CODEC_ERROR = -1,
89}; 95};
90 96
97/* codec command action codes */
98enum codec_command_action {
99 CODEC_ACTION_HALT = -1,
100 CODEC_ACTION_NULL = 0,
101 CODEC_ACTION_SEEK_TIME = 1,
102};
103
91/* NOTE: To support backwards compatibility, only add new functions at 104/* NOTE: To support backwards compatibility, only add new functions at
92 the end of the structure. Every time you add a new function, 105 the end of the structure. Every time you add a new function,
93 remember to increase CODEC_API_VERSION. If you make changes to the 106 remember to increase CODEC_API_VERSION. If you make changes to the
@@ -95,24 +108,12 @@ enum codec_status {
95 version 108 version
96 */ 109 */
97struct codec_api { 110struct codec_api {
98
99 off_t filesize; /* Total file length */ 111 off_t filesize; /* Total file length */
100 off_t curpos; /* Current buffer position */ 112 off_t curpos; /* Current buffer position */
101 113
102 /* For gapless mp3 */
103 struct mp3entry *id3; /* TAG metadata pointer */ 114 struct mp3entry *id3; /* TAG metadata pointer */
104 bool *taginfo_ready; /* Is metadata read */ 115 int audio_hid; /* Current audio handle */
105 116
106 /* Codec should periodically check if stop_codec is set to true.
107 In case it is, codec must return immediately */
108 volatile bool stop_codec;
109 /* Codec should periodically check if new_track is non zero.
110 When it is, the codec should request a new track. */
111 volatile int new_track;
112 /* If seek_time != 0, codec should seek to that song position (in ms)
113 if codec supports seeking. */
114 volatile long seek_time;
115
116 /* The dsp instance to be used for audio output */ 117 /* The dsp instance to be used for audio output */
117 struct dsp_config *dsp; 118 struct dsp_config *dsp;
118 119
@@ -138,14 +139,12 @@ struct codec_api {
138 bool (*seek_buffer)(size_t newpos); 139 bool (*seek_buffer)(size_t newpos);
139 /* Codec should call this function when it has done the seeking. */ 140 /* Codec should call this function when it has done the seeking. */
140 void (*seek_complete)(void); 141 void (*seek_complete)(void);
141 /* Request file change from file buffer. Returns true is next 142 /* Update the current position */
142 track is available and changed. If return value is false,
143 codec should exit immediately with PLUGIN_OK status. */
144 bool (*request_next_track)(void);
145
146 void (*set_offset)(size_t value); 143 void (*set_offset)(size_t value);
147 /* Configure different codec buffer parameters. */ 144 /* Configure different codec buffer parameters. */
148 void (*configure)(int setting, intptr_t value); 145 void (*configure)(int setting, intptr_t value);
146 /* Obtain command action on what to do next */
147 enum codec_command_action (*get_command)(intptr_t *param);
149 148
150 /* kernel/ system */ 149 /* kernel/ system */
151#if defined(CPU_ARM) && CONFIG_PLATFORM & PLATFORM_NATIVE 150#if defined(CPU_ARM) && CONFIG_PLATFORM & PLATFORM_NATIVE
@@ -231,7 +230,8 @@ struct codec_api {
231/* codec header */ 230/* codec header */
232struct codec_header { 231struct codec_header {
233 struct lc_header lc_hdr; /* must be first */ 232 struct lc_header lc_hdr; /* must be first */
234 enum codec_status(*entry_point)(void); 233 enum codec_status(*entry_point)(enum codec_entry_call_reason reason);
234 enum codec_status(*run_proc)(void);
235 struct codec_api **api; 235 struct codec_api **api;
236}; 236};
237 237
@@ -248,13 +248,15 @@ extern unsigned char plugin_end_addr[];
248 const struct codec_header __header \ 248 const struct codec_header __header \
249 __attribute__ ((section (".header")))= { \ 249 __attribute__ ((section (".header")))= { \
250 { CODEC_MAGIC, TARGET_ID, CODEC_API_VERSION, \ 250 { CODEC_MAGIC, TARGET_ID, CODEC_API_VERSION, \
251 plugin_start_addr, plugin_end_addr }, codec_start, &ci }; 251 plugin_start_addr, plugin_end_addr }, codec_start, \
252 codec_run, &ci };
252/* encoders */ 253/* encoders */
253#define CODEC_ENC_HEADER \ 254#define CODEC_ENC_HEADER \
254 const struct codec_header __header \ 255 const struct codec_header __header \
255 __attribute__ ((section (".header")))= { \ 256 __attribute__ ((section (".header")))= { \
256 { CODEC_ENC_MAGIC, TARGET_ID, CODEC_API_VERSION, \ 257 { CODEC_ENC_MAGIC, TARGET_ID, CODEC_API_VERSION, \
257 plugin_start_addr, plugin_end_addr }, codec_start, &ci }; 258 plugin_start_addr, plugin_end_addr }, codec_start, \
259 codec_run, &ci };
258 260
259#else /* def SIMULATOR */ 261#else /* def SIMULATOR */
260/* decoders */ 262/* decoders */
@@ -262,12 +264,12 @@ extern unsigned char plugin_end_addr[];
262 const struct codec_header __header \ 264 const struct codec_header __header \
263 __attribute__((visibility("default"))) = { \ 265 __attribute__((visibility("default"))) = { \
264 { CODEC_MAGIC, TARGET_ID, CODEC_API_VERSION, NULL, NULL }, \ 266 { CODEC_MAGIC, TARGET_ID, CODEC_API_VERSION, NULL, NULL }, \
265 codec_start, &ci }; 267 codec_start, codec_run, &ci };
266/* encoders */ 268/* encoders */
267#define CODEC_ENC_HEADER \ 269#define CODEC_ENC_HEADER \
268 const struct codec_header __header = { \ 270 const struct codec_header __header = { \
269 { CODEC_ENC_MAGIC, TARGET_ID, CODEC_API_VERSION, NULL, NULL }, \ 271 { CODEC_ENC_MAGIC, TARGET_ID, CODEC_API_VERSION, NULL, NULL }, \
270 codec_start, &ci }; 272 codec_start, codec_run, &ci };
271#endif /* SIMULATOR */ 273#endif /* SIMULATOR */
272#endif /* CODEC */ 274#endif /* CODEC */
273 275
@@ -276,13 +278,14 @@ extern unsigned char plugin_end_addr[];
276void codec_get_full_path(char *path, const char *codec_root_fn); 278void codec_get_full_path(char *path, const char *codec_root_fn);
277 279
278/* defined by the codec loader (codec.c) */ 280/* defined by the codec loader (codec.c) */
279void * codec_load_buf(int hid, struct codec_api *api); 281int codec_load_buf(int hid, struct codec_api *api);
280void * codec_load_file(const char* codec, struct codec_api *api); 282int codec_load_file(const char* codec, struct codec_api *api);
281int codec_begin(void *handle); 283int codec_run_proc(void);
282void codec_close(void *handle); 284int codec_halt(void);
285int codec_close(void);
283 286
284/* defined by the codec */ 287/* defined by the codec */
285enum codec_status codec_start(void); 288enum codec_status codec_start(enum codec_entry_call_reason reason);
286enum codec_status codec_main(void); 289enum codec_status codec_run(void);
287 290
288#endif 291#endif /* _CODECS_H_ */
diff --git a/apps/codecs/a52.c b/apps/codecs/a52.c
index 00fdeea309..4cd293e37f 100644
--- a/apps/codecs/a52.c
+++ b/apps/codecs/a52.c
@@ -116,27 +116,31 @@ static void a52_decode_data(uint8_t *start, uint8_t *end)
116} 116}
117 117
118/* this is the codec entry point */ 118/* this is the codec entry point */
119enum codec_status codec_main(void) 119enum codec_status codec_main(enum codec_entry_call_reason reason)
120{
121 if (reason == CODEC_LOAD) {
122 /* Generic codec initialisation */
123 ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
124 ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
125 }
126 else if (reason == CODEC_UNLOAD) {
127 if (state)
128 a52_free(state);
129 }
130
131 return CODEC_OK;
132}
133
134/* this is called for each file to process */
135enum codec_status codec_run(void)
120{ 136{
121 size_t n; 137 size_t n;
122 unsigned char *filebuf; 138 unsigned char *filebuf;
123 int sample_loc; 139 int sample_loc;
124 int retval; 140 intptr_t param;
125 141
126 /* Generic codec initialisation */ 142 if (codec_init())
127 ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED); 143 return CODEC_ERROR;
128 ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
129
130next_track:
131 retval = CODEC_OK;
132
133 if (codec_init()) {
134 retval = CODEC_ERROR;
135 goto exit;
136 }
137
138 if (codec_wait_taginfo() != 0)
139 goto request_next_track;
140 144
141 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); 145 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
142 codec_set_replaygain(ci->id3); 146 codec_set_replaygain(ci->id3);
@@ -153,15 +157,18 @@ next_track:
153 } 157 }
154 } 158 }
155 else { 159 else {
160 ci->seek_buffer(ci->id3->first_frame_offset);
156 samplesdone = 0; 161 samplesdone = 0;
157 } 162 }
158 163
159 while (1) { 164 while (1) {
160 if (ci->stop_codec || ci->new_track) 165 enum codec_command_action action = ci->get_command(&param);
166
167 if (action == CODEC_ACTION_HALT)
161 break; 168 break;
162 169
163 if (ci->seek_time) { 170 if (action == CODEC_ACTION_SEEK_TIME) {
164 sample_loc = (ci->seek_time - 1)/1000 * ci->id3->frequency; 171 sample_loc = param/1000 * ci->id3->frequency;
165 172
166 if (ci->seek_buffer((sample_loc/A52_SAMPLESPERFRAME)*ci->id3->bytesperframe)) { 173 if (ci->seek_buffer((sample_loc/A52_SAMPLESPERFRAME)*ci->id3->bytesperframe)) {
167 samplesdone = sample_loc; 174 samplesdone = sample_loc;
@@ -179,11 +186,5 @@ next_track:
179 ci->advance_buffer(n); 186 ci->advance_buffer(n);
180 } 187 }
181 188
182request_next_track: 189 return CODEC_OK;
183 if (ci->request_next_track())
184 goto next_track;
185
186exit:
187 a52_free(state);
188 return retval;
189} 190}
diff --git a/apps/codecs/a52_rm.c b/apps/codecs/a52_rm.c
index f5e4923292..c1930aa7b4 100644
--- a/apps/codecs/a52_rm.c
+++ b/apps/codecs/a52_rm.c
@@ -124,36 +124,44 @@ static void a52_decode_data(uint8_t *start, uint8_t *end)
124 } 124 }
125} 125}
126 126
127
128/* this is the codec entry point */ 127/* this is the codec entry point */
129enum codec_status codec_main(void) 128enum codec_status codec_main(enum codec_entry_call_reason reason)
129{
130 if (reason == CODEC_LOAD) {
131 /* Generic codec initialisation */
132 ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
133 ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
134 }
135 else if (reason == CODEC_UNLOAD) {
136 if (state)
137 a52_free(state);
138 }
139
140 return CODEC_OK;
141}
142
143/* this is called for each file to process */
144enum codec_status codec_run(void)
130{ 145{
131 size_t n; 146 size_t n;
132 uint8_t *filebuf; 147 uint8_t *filebuf;
133 int retval, consumed, packet_offset; 148 int consumed, packet_offset;
134 int playback_on = -1; 149 int playback_on = -1;
135 size_t resume_offset; 150 size_t resume_offset;
136 151 intptr_t param;
137 /* Generic codec initialisation */ 152 enum codec_command_action action = CODEC_ACTION_NULL;
138 ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
139 ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
140
141next_track:
142 retval = CODEC_OK;
143 153
144 if (codec_init()) { 154 if (codec_init()) {
145 retval = CODEC_ERROR; 155 return CODEC_ERROR;
146 goto exit;
147 } 156 }
148 157
149 if (codec_wait_taginfo() != 0)
150 goto request_next_track;
151
152 resume_offset = ci->id3->offset; 158 resume_offset = ci->id3->offset;
153 159
154 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); 160 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
155 codec_set_replaygain(ci->id3); 161 codec_set_replaygain(ci->id3);
156 162
163 ci->seek_buffer(ci->id3->first_frame_offset);
164
157 /* Intializations */ 165 /* Intializations */
158 state = a52_init(0); 166 state = a52_init(0);
159 ci->memset(&rmctx,0,sizeof(RMContext)); 167 ci->memset(&rmctx,0,sizeof(RMContext));
@@ -165,26 +173,34 @@ next_track:
165 resume_offset -= rmctx.data_offset + DATA_HEADER_SIZE; 173 resume_offset -= rmctx.data_offset + DATA_HEADER_SIZE;
166 /* put number of subpackets to skip in resume_offset */ 174 /* put number of subpackets to skip in resume_offset */
167 resume_offset /= (rmctx.block_align + PACKET_HEADER_SIZE); 175 resume_offset /= (rmctx.block_align + PACKET_HEADER_SIZE);
168 ci->seek_time = (int)resume_offset * ((rmctx.block_align * 8 * 1000)/rmctx.bit_rate); 176 param = (int)resume_offset * ((rmctx.block_align * 8 * 1000)/rmctx.bit_rate);
177 action = CODEC_ACTION_SEEK_TIME;
178 }
179 else {
180 /* Seek to the first packet */
181 ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE );
169 } 182 }
170
171 /* Seek to the first packet */
172 ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE );
173 183
174 /* The main decoding loop */ 184 /* The main decoding loop */
175 while((unsigned)rmctx.audio_pkt_cnt < rmctx.nb_packets) { 185 while((unsigned)rmctx.audio_pkt_cnt < rmctx.nb_packets) {
176 ci->yield(); 186 if (action == CODEC_ACTION_NULL)
177 if (ci->stop_codec || ci->new_track) 187 action = ci->get_command(&param);
188
189 if (action == CODEC_ACTION_HALT)
178 break; 190 break;
179 191
180 if (ci->seek_time) { 192 if (action == CODEC_ACTION_SEEK_TIME) {
181 packet_offset = ci->seek_time / ((rmctx.block_align*8*1000)/rmctx.bit_rate); 193 packet_offset = param / ((rmctx.block_align*8*1000)/rmctx.bit_rate);
182 ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + packet_offset*(rmctx.block_align + PACKET_HEADER_SIZE)); 194 ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE +
195 packet_offset*(rmctx.block_align + PACKET_HEADER_SIZE));
183 rmctx.audio_pkt_cnt = packet_offset; 196 rmctx.audio_pkt_cnt = packet_offset;
184 samplesdone = (rmctx.sample_rate/1000 * ci->seek_time); 197 samplesdone = (rmctx.sample_rate/1000 * param);
198 ci->set_elapsed(samplesdone/(frequency/1000));
185 ci->seek_complete(); 199 ci->seek_complete();
186 } 200 }
187 201
202 action = CODEC_ACTION_NULL;
203
188 filebuf = ci->request_buffer(&n, rmctx.block_align + PACKET_HEADER_SIZE); 204 filebuf = ci->request_buffer(&n, rmctx.block_align + PACKET_HEADER_SIZE);
189 consumed = rm_get_packet(&filebuf, &rmctx, &pkt); 205 consumed = rm_get_packet(&filebuf, &rmctx, &pkt);
190 206
@@ -195,8 +211,7 @@ next_track:
195 return CODEC_ERROR; 211 return CODEC_ERROR;
196 } 212 }
197 else { 213 else {
198 retval = CODEC_OK; 214 break;
199 goto exit;
200 } 215 }
201 } 216 }
202 217
@@ -205,11 +220,5 @@ next_track:
205 ci->advance_buffer(pkt.length); 220 ci->advance_buffer(pkt.length);
206 } 221 }
207 222
208request_next_track: 223 return CODEC_OK;
209 if (ci->request_next_track())
210 goto next_track;
211
212exit:
213 a52_free(state);
214 return retval;
215} 224}
diff --git a/apps/codecs/aac.c b/apps/codecs/aac.c
index 5638dc49a9..90cf0438ce 100644
--- a/apps/codecs/aac.c
+++ b/apps/codecs/aac.c
@@ -33,7 +33,19 @@ CODEC_HEADER
33#define FAAD_BYTE_BUFFER_SIZE (2048-12) 33#define FAAD_BYTE_BUFFER_SIZE (2048-12)
34 34
35/* this is the codec entry point */ 35/* this is the codec entry point */
36enum codec_status codec_main(void) 36enum codec_status codec_main(enum codec_entry_call_reason reason)
37{
38 if (reason == CODEC_LOAD) {
39 /* Generic codec initialisation */
40 ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
41 ci->configure(DSP_SET_SAMPLE_DEPTH, 29);
42 }
43
44 return CODEC_OK;
45}
46
47/* this is called for each file to process */
48enum codec_status codec_run(void)
37{ 49{
38 /* Note that when dealing with QuickTime/MPEG4 files, terminology is 50 /* Note that when dealing with QuickTime/MPEG4 files, terminology is
39 * a bit confusing. Files with sound are split up in chunks, where 51 * a bit confusing. Files with sound are split up in chunks, where
@@ -59,25 +71,15 @@ enum codec_status codec_main(void)
59 uint32_t sbr_fac = 1; 71 uint32_t sbr_fac = 1;
60 unsigned char c = 0; 72 unsigned char c = 0;
61 void *ret; 73 void *ret;
62 74 intptr_t param;
63 /* Generic codec initialisation */
64 ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
65 ci->configure(DSP_SET_SAMPLE_DEPTH, 29);
66
67next_track:
68 err = CODEC_OK;
69 75
70 /* Clean and initialize decoder structures */ 76 /* Clean and initialize decoder structures */
71 memset(&demux_res , 0, sizeof(demux_res)); 77 memset(&demux_res , 0, sizeof(demux_res));
72 if (codec_init()) { 78 if (codec_init()) {
73 LOGF("FAAD: Codec init error\n"); 79 LOGF("FAAD: Codec init error\n");
74 err = CODEC_ERROR; 80 return CODEC_ERROR;
75 goto exit;
76 } 81 }
77 82
78 if (codec_wait_taginfo() != 0)
79 goto done;
80
81 file_offset = ci->id3->offset; 83 file_offset = ci->id3->offset;
82 84
83 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); 85 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
@@ -85,12 +87,13 @@ next_track:
85 87
86 stream_create(&input_stream,ci); 88 stream_create(&input_stream,ci);
87 89
90 ci->seek_buffer(ci->id3->first_frame_offset);
91
88 /* if qtmovie_read returns successfully, the stream is up to 92 /* if qtmovie_read returns successfully, the stream is up to
89 * the movie data, which can be used directly by the decoder */ 93 * the movie data, which can be used directly by the decoder */
90 if (!qtmovie_read(&input_stream, &demux_res)) { 94 if (!qtmovie_read(&input_stream, &demux_res)) {
91 LOGF("FAAD: File init error\n"); 95 LOGF("FAAD: File init error\n");
92 err = CODEC_ERROR; 96 return CODEC_ERROR;
93 goto done;
94 } 97 }
95 98
96 /* initialise the sound converter */ 99 /* initialise the sound converter */
@@ -98,8 +101,7 @@ next_track:
98 101
99 if (!decoder) { 102 if (!decoder) {
100 LOGF("FAAD: Decode open error\n"); 103 LOGF("FAAD: Decode open error\n");
101 err = CODEC_ERROR; 104 return CODEC_ERROR;
102 goto done;
103 } 105 }
104 106
105 NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(decoder); 107 NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(decoder);
@@ -109,8 +111,7 @@ next_track:
109 err = NeAACDecInit2(decoder, demux_res.codecdata, demux_res.codecdata_len, &s, &c); 111 err = NeAACDecInit2(decoder, demux_res.codecdata, demux_res.codecdata_len, &s, &c);
110 if (err) { 112 if (err) {
111 LOGF("FAAD: DecInit: %d, %d\n", err, decoder->object_type); 113 LOGF("FAAD: DecInit: %d, %d\n", err, decoder->object_type);
112 err = CODEC_ERROR; 114 return CODEC_ERROR;
113 goto done;
114 } 115 }
115 116
116#ifdef SBR_DEC 117#ifdef SBR_DEC
@@ -150,20 +151,19 @@ next_track:
150 151
151 /* The main decoding loop */ 152 /* The main decoding loop */
152 while (i < demux_res.num_sample_byte_sizes) { 153 while (i < demux_res.num_sample_byte_sizes) {
153 ci->yield(); 154 enum codec_command_action action = ci->get_command(&param);
154 155
155 if (ci->stop_codec || ci->new_track) { 156 if (action == CODEC_ACTION_HALT)
156 break; 157 break;
157 }
158 158
159 /* Deal with any pending seek requests */ 159 /* Deal with any pending seek requests */
160 if (ci->seek_time) { 160 if (action == CODEC_ACTION_SEEK_TIME) {
161 /* Seek to the desired time position. Important: When seeking in SBR 161 /* Seek to the desired time position. Important: When seeking in SBR
162 * upsampling files the seek_time must be divided by 2 when calling 162 * upsampling files the seek_time must be divided by 2 when calling
163 * m4a_seek and the resulting sound_samples_done must be expanded 163 * m4a_seek and the resulting sound_samples_done must be expanded
164 * by a factor 2. This is done via using sbr_fac. */ 164 * by a factor 2. This is done via using sbr_fac. */
165 if (m4a_seek(&demux_res, &input_stream, 165 if (m4a_seek(&demux_res, &input_stream,
166 ((ci->seek_time-1)/10/sbr_fac)*(ci->id3->frequency/100), 166 (param/10/sbr_fac)*(ci->id3->frequency/100),
167 &sound_samples_done, (int*) &i)) { 167 &sound_samples_done, (int*) &i)) {
168 sound_samples_done *= sbr_fac; 168 sound_samples_done *= sbr_fac;
169 elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100); 169 elapsed_time = (sound_samples_done * 10) / (ci->id3->frequency / 100);
@@ -194,8 +194,7 @@ next_track:
194 else if (file_offset == 0) 194 else if (file_offset == 0)
195 { 195 {
196 LOGF("AAC: get_sample_offset error\n"); 196 LOGF("AAC: get_sample_offset error\n");
197 err = CODEC_ERROR; 197 return CODEC_ERROR;
198 goto done;
199 } 198 }
200 199
201 /* Request the required number of bytes from the input buffer */ 200 /* Request the required number of bytes from the input buffer */
@@ -207,8 +206,7 @@ next_track:
207 /* NeAACDecDecode may sometimes return NULL without setting error. */ 206 /* NeAACDecDecode may sometimes return NULL without setting error. */
208 if (ret == NULL || frame_info.error > 0) { 207 if (ret == NULL || frame_info.error > 0) {
209 LOGF("FAAD: decode error '%s'\n", NeAACDecGetErrorMessage(frame_info.error)); 208 LOGF("FAAD: decode error '%s'\n", NeAACDecGetErrorMessage(frame_info.error));
210 err = CODEC_ERROR; 209 return CODEC_ERROR;
211 goto done;
212 } 210 }
213 211
214 /* Advance codec buffer (no need to call set_offset because of this) */ 212 /* Advance codec buffer (no need to call set_offset because of this) */
@@ -251,12 +249,6 @@ next_track:
251 i++; 249 i++;
252 } 250 }
253 251
254done:
255 LOGF("AAC: Decoded %lu samples\n", (unsigned long)sound_samples_done); 252 LOGF("AAC: Decoded %lu samples\n", (unsigned long)sound_samples_done);
256 253 return CODEC_OK;
257 if (ci->request_next_track())
258 goto next_track;
259
260exit:
261 return err;
262} 254}
diff --git a/apps/codecs/adx.c b/apps/codecs/adx.c
index 832b94797b..a1b57fce58 100644
--- a/apps/codecs/adx.c
+++ b/apps/codecs/adx.c
@@ -45,7 +45,19 @@ static const long cutoff = 500;
45static int16_t samples[WAV_CHUNK_SIZE] IBSS_ATTR; 45static int16_t samples[WAV_CHUNK_SIZE] IBSS_ATTR;
46 46
47/* this is the codec entry point */ 47/* this is the codec entry point */
48enum codec_status codec_main(void) 48enum codec_status codec_main(enum codec_entry_call_reason reason)
49{
50 if (reason == CODEC_LOAD) {
51 /* Generic codec initialisation */
52 /* we only render 16 bits */
53 ci->configure(DSP_SET_SAMPLE_DEPTH, 16);
54 }
55
56 return CODEC_OK;
57}
58
59/* this is called for each file to process */
60enum codec_status codec_run(void)
49{ 61{
50 int channels; 62 int channels;
51 int sampleswritten, i; 63 int sampleswritten, i;
@@ -62,12 +74,8 @@ enum codec_status codec_main(void)
62 off_t chanstart, bufoff; 74 off_t chanstart, bufoff;
63 /*long coef1=0x7298L,coef2=-0x3350L;*/ 75 /*long coef1=0x7298L,coef2=-0x3350L;*/
64 long coef1, coef2; 76 long coef1, coef2;
77 intptr_t param;
65 78
66 /* Generic codec initialisation */
67 /* we only render 16 bits */
68 ci->configure(DSP_SET_SAMPLE_DEPTH, 16);
69
70next_track:
71 DEBUGF("ADX: next_track\n"); 79 DEBUGF("ADX: next_track\n");
72 if (codec_init()) { 80 if (codec_init()) {
73 return CODEC_ERROR; 81 return CODEC_ERROR;
@@ -77,10 +85,6 @@ next_track:
77 /* init history */ 85 /* init history */
78 ch1_1=ch1_2=ch2_1=ch2_2=0; 86 ch1_1=ch1_2=ch2_1=ch2_2=0;
79 87
80 /* wait for track info to load */
81 if (codec_wait_taginfo() != 0)
82 goto request_next_track;
83
84 codec_set_replaygain(ci->id3); 88 codec_set_replaygain(ci->id3);
85 89
86 /* Get header */ 90 /* Get header */
@@ -226,10 +230,10 @@ next_track:
226 /* The main decoder loop */ 230 /* The main decoder loop */
227 231
228 while (!endofstream) { 232 while (!endofstream) {
229 ci->yield(); 233 enum codec_command_action action = ci->get_command(&param);
230 if (ci->stop_codec || ci->new_track) { 234
235 if (action == CODEC_ACTION_HALT)
231 break; 236 break;
232 }
233 237
234 /* do we need to loop? */ 238 /* do we need to loop? */
235 if (bufoff > end_adr-18*channels && looping) { 239 if (bufoff > end_adr-18*channels && looping) {
@@ -254,17 +258,17 @@ next_track:
254 } 258 }
255 259
256 /* do we need to seek? */ 260 /* do we need to seek? */
257 if (ci->seek_time) { 261 if (action == CODEC_ACTION_SEEK_TIME) {
258 uint32_t newpos; 262 uint32_t newpos;
259 263
260 DEBUGF("ADX: seek to %ldms\n",ci->seek_time); 264 DEBUGF("ADX: seek to %ldms\n", (long)param);
261 265
262 endofstream = 0; 266 endofstream = 0;
263 loop_count = 0; 267 loop_count = 0;
264 fade_count = -1; /* disable fade */ 268 fade_count = -1; /* disable fade */
265 fade_frames = 1; 269 fade_frames = 1;
266 270
267 newpos = (((uint64_t)avgbytespersec*(ci->seek_time - 1)) 271 newpos = (((uint64_t)avgbytespersec*param)
268 / (1000LL*18*channels))*(18*channels); 272 / (1000LL*18*channels))*(18*channels);
269 bufoff = chanstart + newpos; 273 bufoff = chanstart + newpos;
270 while (bufoff > end_adr-18*channels) { 274 while (bufoff > end_adr-18*channels) {
@@ -385,9 +389,5 @@ next_track:
385 1000LL/avgbytespersec); 389 1000LL/avgbytespersec);
386 } 390 }
387 391
388request_next_track:
389 if (ci->request_next_track())
390 goto next_track;
391
392 return CODEC_OK; 392 return CODEC_OK;
393} 393}
diff --git a/apps/codecs/aiff.c b/apps/codecs/aiff.c
index d4cf8660dd..3fc137eaeb 100644
--- a/apps/codecs/aiff.c
+++ b/apps/codecs/aiff.c
@@ -61,9 +61,20 @@ static const struct pcm_codec *get_codec(uint32_t formattag)
61 return NULL; 61 return NULL;
62} 62}
63 63
64enum codec_status codec_main(void) 64/* this is the codec entry point */
65enum codec_status codec_main(enum codec_entry_call_reason reason)
66{
67 if (reason == CODEC_LOAD) {
68 /* Generic codec initialisation */
69 ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1);
70 }
71
72 return CODEC_OK;
73}
74
75/* this is called for each file to process */
76enum codec_status codec_run(void)
65{ 77{
66 int status;
67 struct pcm_format format; 78 struct pcm_format format;
68 uint32_t bytesdone, decodedsamples; 79 uint32_t bytesdone, decodedsamples;
69 uint32_t num_sample_frames = 0; 80 uint32_t num_sample_frames = 0;
@@ -77,38 +88,28 @@ enum codec_status codec_main(void)
77 bool is_aifc = false; 88 bool is_aifc = false;
78 const struct pcm_codec *codec; 89 const struct pcm_codec *codec;
79 uint32_t size; 90 uint32_t size;
80 91 intptr_t param;
81 /* Generic codec initialisation */
82 ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1);
83
84next_track:
85 status = CODEC_OK;
86 92
87 if (codec_init()) { 93 if (codec_init()) {
88 status = CODEC_ERROR; 94 return CODEC_ERROR;
89 goto exit;
90 } 95 }
91 96
92 if (codec_wait_taginfo() != 0)
93 goto done;
94
95 codec_set_replaygain(ci->id3); 97 codec_set_replaygain(ci->id3);
96 98
97 /* Need to save offset for later use (cleared indirectly by advance_buffer) */ 99 /* Need to save offset for later use (cleared indirectly by advance_buffer) */
98 bytesdone = ci->id3->offset; 100 bytesdone = ci->id3->offset;
99 101
100 /* assume the AIFF header is less than 1024 bytes */ 102 /* assume the AIFF header is less than 1024 bytes */
103 ci->seek_buffer(0);
101 buf = ci->request_buffer(&n, 1024); 104 buf = ci->request_buffer(&n, 1024);
102 if (n < 54) { 105 if (n < 54) {
103 status = CODEC_ERROR; 106 return CODEC_ERROR;
104 goto done;
105 } 107 }
106 108
107 if (memcmp(buf, "FORM", 4) != 0) 109 if (memcmp(buf, "FORM", 4) != 0)
108 { 110 {
109 DEBUGF("CODEC_ERROR: does not aiff format %4.4s\n", (char*)&buf[0]); 111 DEBUGF("CODEC_ERROR: does not aiff format %4.4s\n", (char*)&buf[0]);
110 status = CODEC_ERROR; 112 return CODEC_ERROR;
111 goto done;
112 } 113 }
113 if (memcmp(&buf[8], "AIFF", 4) == 0) 114 if (memcmp(&buf[8], "AIFF", 4) == 0)
114 is_aifc = false; 115 is_aifc = false;
@@ -117,8 +118,7 @@ next_track:
117 else 118 else
118 { 119 {
119 DEBUGF("CODEC_ERROR: does not aiff format %4.4s\n", (char*)&buf[8]); 120 DEBUGF("CODEC_ERROR: does not aiff format %4.4s\n", (char*)&buf[8]);
120 status = CODEC_ERROR; 121 return CODEC_ERROR;
121 goto done;
122 } 122 }
123 123
124 buf += 12; 124 buf += 12;
@@ -141,8 +141,7 @@ next_track:
141 { 141 {
142 DEBUGF("CODEC_ERROR: 'COMM' chunk size=%lu < %d\n", 142 DEBUGF("CODEC_ERROR: 'COMM' chunk size=%lu < %d\n",
143 (unsigned long)size, (is_aifc)?22:18); 143 (unsigned long)size, (is_aifc)?22:18);
144 status = CODEC_ERROR; 144 return CODEC_ERROR;
145 goto done;
146 } 145 }
147 /* num_channels */ 146 /* num_channels */
148 format.channels = ((buf[8]<<8)|buf[9]); 147 format.channels = ((buf[8]<<8)|buf[9]);
@@ -154,8 +153,7 @@ next_track:
154 /* sample_rate (don't use last 4 bytes, only integer fs) */ 153 /* sample_rate (don't use last 4 bytes, only integer fs) */
155 if (buf[16] != 0x40) { 154 if (buf[16] != 0x40) {
156 DEBUGF("CODEC_ERROR: weird sampling rate (no @)\n"); 155 DEBUGF("CODEC_ERROR: weird sampling rate (no @)\n");
157 status = CODEC_ERROR; 156 return CODEC_ERROR;
158 goto done;
159 } 157 }
160 format.samplespersec = ((buf[18]<<24)|(buf[19]<<16)|(buf[20]<<8)|buf[21])+1; 158 format.samplespersec = ((buf[18]<<24)|(buf[19]<<16)|(buf[20]<<8)|buf[21])+1;
161 format.samplespersec >>= (16 + 14 - buf[17]); 159 format.samplespersec >>= (16 + 14 - buf[17]);
@@ -181,8 +179,7 @@ next_track:
181 } else if (memcmp(buf, "SSND", 4)==0) { 179 } else if (memcmp(buf, "SSND", 4)==0) {
182 if (format.bitspersample == 0) { 180 if (format.bitspersample == 0) {
183 DEBUGF("CODEC_ERROR: unsupported chunk order\n"); 181 DEBUGF("CODEC_ERROR: unsupported chunk order\n");
184 status = CODEC_ERROR; 182 return CODEC_ERROR;
185 goto done;
186 } 183 }
187 /* offset2snd */ 184 /* offset2snd */
188 offset2snd = (buf[8]<<24)|(buf[9]<<16)|(buf[10]<<8)|buf[11]; 185 offset2snd = (buf[8]<<24)|(buf[9]<<16)|(buf[10]<<8)|buf[11];
@@ -205,21 +202,18 @@ next_track:
205 buf += size; 202 buf += size;
206 if (n < size) { 203 if (n < size) {
207 DEBUGF("CODEC_ERROR: AIFF header size > 1024\n"); 204 DEBUGF("CODEC_ERROR: AIFF header size > 1024\n");
208 status = CODEC_ERROR; 205 return CODEC_ERROR;
209 goto done;
210 } 206 }
211 n -= size; 207 n -= size;
212 } /* while 'SSND' */ 208 } /* while 'SSND' */
213 209
214 if (format.channels == 0) { 210 if (format.channels == 0) {
215 DEBUGF("CODEC_ERROR: 'COMM' chunk not found or 0-channels file\n"); 211 DEBUGF("CODEC_ERROR: 'COMM' chunk not found or 0-channels file\n");
216 status = CODEC_ERROR; 212 return CODEC_ERROR;
217 goto done;
218 } 213 }
219 if (format.numbytes == 0) { 214 if (format.numbytes == 0) {
220 DEBUGF("CODEC_ERROR: 'SSND' chunk not found or has zero length\n"); 215 DEBUGF("CODEC_ERROR: 'SSND' chunk not found or has zero length\n");
221 status = CODEC_ERROR; 216 return CODEC_ERROR;
222 goto done;
223 } 217 }
224 218
225 codec = get_codec(format.formattag); 219 codec = get_codec(format.formattag);
@@ -227,14 +221,12 @@ next_track:
227 { 221 {
228 DEBUGF("CODEC_ERROR: AIFC does not support compressionType: 0x%x\n", 222 DEBUGF("CODEC_ERROR: AIFC does not support compressionType: 0x%x\n",
229 (unsigned int)format.formattag); 223 (unsigned int)format.formattag);
230 status = CODEC_ERROR; 224 return CODEC_ERROR;
231 goto done;
232 } 225 }
233 226
234 if (!codec->set_format(&format)) 227 if (!codec->set_format(&format))
235 { 228 {
236 status = CODEC_ERROR; 229 return CODEC_ERROR;
237 goto done;
238 } 230 }
239 231
240 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); 232 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
@@ -245,21 +237,18 @@ next_track:
245 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); 237 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
246 } else { 238 } else {
247 DEBUGF("CODEC_ERROR: more than 2 channels unsupported\n"); 239 DEBUGF("CODEC_ERROR: more than 2 channels unsupported\n");
248 status = CODEC_ERROR; 240 return CODEC_ERROR;
249 goto done;
250 } 241 }
251 242
252 if (format.samplesperblock == 0) 243 if (format.samplesperblock == 0)
253 { 244 {
254 DEBUGF("CODEC_ERROR: samplesperblock is 0\n"); 245 DEBUGF("CODEC_ERROR: samplesperblock is 0\n");
255 status = CODEC_ERROR; 246 return CODEC_ERROR;
256 goto done;
257 } 247 }
258 if (format.blockalign == 0) 248 if (format.blockalign == 0)
259 { 249 {
260 DEBUGF("CODEC_ERROR: blockalign is 0\n"); 250 DEBUGF("CODEC_ERROR: blockalign is 0\n");
261 status = CODEC_ERROR; 251 return CODEC_ERROR;
262 goto done;
263 } 252 }
264 253
265 /* check chunksize */ 254 /* check chunksize */
@@ -269,8 +258,7 @@ next_track:
269 if (format.chunksize == 0) 258 if (format.chunksize == 0)
270 { 259 {
271 DEBUGF("CODEC_ERROR: chunksize is 0\n"); 260 DEBUGF("CODEC_ERROR: chunksize is 0\n");
272 status = CODEC_ERROR; 261 return CODEC_ERROR;
273 goto done;
274 } 262 }
275 263
276 firstblockposn = 1024 - n; 264 firstblockposn = 1024 - n;
@@ -283,13 +271,13 @@ next_track:
283 PCM_SEEK_POS, NULL); 271 PCM_SEEK_POS, NULL);
284 272
285 if (newpos->pos > format.numbytes) 273 if (newpos->pos > format.numbytes)
286 goto done; 274 return CODEC_OK;
275
287 if (ci->seek_buffer(firstblockposn + newpos->pos)) 276 if (ci->seek_buffer(firstblockposn + newpos->pos))
288 { 277 {
289 bytesdone = newpos->pos; 278 bytesdone = newpos->pos;
290 decodedsamples = newpos->samples; 279 decodedsamples = newpos->samples;
291 } 280 }
292 ci->seek_complete();
293 } else { 281 } else {
294 /* already where we need to be */ 282 /* already where we need to be */
295 bytesdone = 0; 283 bytesdone = 0;
@@ -299,21 +287,29 @@ next_track:
299 endofstream = 0; 287 endofstream = 0;
300 288
301 while (!endofstream) { 289 while (!endofstream) {
302 ci->yield(); 290 enum codec_command_action action = ci->get_command(&param);
303 if (ci->stop_codec || ci->new_track) 291
292 if (action == CODEC_ACTION_HALT)
304 break; 293 break;
305 294
306 if (ci->seek_time) { 295 if (action == CODEC_ACTION_SEEK_TIME) {
307 /* 3rd args(read_buffer) is unnecessary in the format which AIFF supports. */ 296 /* 3rd args(read_buffer) is unnecessary in the format which AIFF supports. */
308 struct pcm_pos *newpos = codec->get_seek_pos(ci->seek_time, PCM_SEEK_TIME, NULL); 297 struct pcm_pos *newpos = codec->get_seek_pos(param, PCM_SEEK_TIME, NULL);
309 298
310 if (newpos->pos > format.numbytes) 299 if (newpos->pos > format.numbytes)
300 {
301 ci->set_elapsed(ci->id3->length);
302 ci->seek_complete();
311 break; 303 break;
304 }
305
312 if (ci->seek_buffer(firstblockposn + newpos->pos)) 306 if (ci->seek_buffer(firstblockposn + newpos->pos))
313 { 307 {
314 bytesdone = newpos->pos; 308 bytesdone = newpos->pos;
315 decodedsamples = newpos->samples; 309 decodedsamples = newpos->samples;
316 } 310 }
311
312 ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
317 ci->seek_complete(); 313 ci->seek_complete();
318 } 314 }
319 aifbuf = (uint8_t *)ci->request_buffer(&n, format.chunksize); 315 aifbuf = (uint8_t *)ci->request_buffer(&n, format.chunksize);
@@ -326,11 +322,10 @@ next_track:
326 endofstream = 1; 322 endofstream = 1;
327 } 323 }
328 324
329 status = codec->decode(aifbuf, n, samples, &bufcount); 325 if (codec->decode(aifbuf, n, samples, &bufcount) == CODEC_ERROR)
330 if (status == CODEC_ERROR)
331 { 326 {
332 DEBUGF("codec error\n"); 327 DEBUGF("codec error\n");
333 goto done; 328 return CODEC_ERROR;
334 } 329 }
335 330
336 ci->pcmbuf_insert(samples, NULL, bufcount); 331 ci->pcmbuf_insert(samples, NULL, bufcount);
@@ -343,13 +338,6 @@ next_track:
343 338
344 ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency); 339 ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
345 } 340 }
346 status = CODEC_OK;
347
348done:
349 if (ci->request_next_track())
350 goto next_track;
351 341
352exit: 342 return CODEC_OK;
353 return status;
354} 343}
355
diff --git a/apps/codecs/aiff_enc.c b/apps/codecs/aiff_enc.c
index 69496f70ac..fc44196eb0 100644
--- a/apps/codecs/aiff_enc.c
+++ b/apps/codecs/aiff_enc.c
@@ -359,40 +359,42 @@ static bool init_encoder(void)
359 return true; 359 return true;
360} /* init_encoder */ 360} /* init_encoder */
361 361
362/* main codec entry point */ 362/* this is the codec entry point */
363enum codec_status codec_main(void) 363enum codec_status codec_main(enum codec_entry_call_reason reason)
364{ 364{
365 if (!init_encoder()) 365 if (reason == CODEC_LOAD) {
366 return CODEC_ERROR; 366 if (!init_encoder())
367 return CODEC_ERROR;
368 }
369 else if (reason == CODEC_UNLOAD) {
370 /* reset parameters to initial state */
371 ci->enc_set_parameters(NULL);
372 }
367 373
374 return CODEC_OK;
375}
376
377/* this is called for each file to process */
378enum codec_status codec_run(void)
379{
368 /* main encoding loop */ 380 /* main encoding loop */
369 while(!ci->stop_codec) 381 while (ci->get_command(NULL) != CODEC_ACTION_HALT)
370 { 382 {
371 uint32_t *src; 383 uint32_t *src = (uint32_t *)ci->enc_get_pcm_data(PCM_CHUNK_SIZE);
384 struct enc_chunk_hdr *chunk;
372 385
373 while ((src = (uint32_t *)ci->enc_get_pcm_data(PCM_CHUNK_SIZE)) != NULL) 386 if (src == NULL)
374 { 387 continue;
375 struct enc_chunk_hdr *chunk;
376
377 if (ci->stop_codec)
378 break;
379 388
380 chunk = ci->enc_get_chunk(); 389 chunk = ci->enc_get_chunk();
381 chunk->enc_size = enc_size; 390 chunk->enc_size = enc_size;
382 chunk->num_pcm = PCM_SAMP_PER_CHUNK; 391 chunk->num_pcm = PCM_SAMP_PER_CHUNK;
383 chunk->enc_data = ENC_CHUNK_SKIP_HDR(chunk->enc_data, chunk); 392 chunk->enc_data = ENC_CHUNK_SKIP_HDR(chunk->enc_data, chunk);
384 393
385 chunk_to_aiff_format(src, (uint32_t *)chunk->enc_data); 394 chunk_to_aiff_format(src, (uint32_t *)chunk->enc_data);
386
387 ci->enc_finish_chunk();
388 ci->yield();
389 }
390 395
391 ci->yield(); 396 ci->enc_finish_chunk();
392 } 397 }
393 398
394 /* reset parameters to initial state */
395 ci->enc_set_parameters(NULL);
396
397 return CODEC_OK; 399 return CODEC_OK;
398} /* codec_start */ 400}
diff --git a/apps/codecs/alac.c b/apps/codecs/alac.c
index cd9129a278..82bda264c3 100644
--- a/apps/codecs/alac.c
+++ b/apps/codecs/alac.c
@@ -32,116 +32,114 @@ CODEC_HEADER
32static int32_t outputbuffer[ALAC_MAX_CHANNELS][ALAC_BLOCKSIZE] IBSS_ATTR; 32static int32_t outputbuffer[ALAC_MAX_CHANNELS][ALAC_BLOCKSIZE] IBSS_ATTR;
33 33
34/* this is the codec entry point */ 34/* this is the codec entry point */
35enum codec_status codec_main(void) 35enum codec_status codec_main(enum codec_entry_call_reason reason)
36{ 36{
37 size_t n; 37 if (reason == CODEC_LOAD) {
38 demux_res_t demux_res; 38 /* Generic codec initialisation */
39 stream_t input_stream; 39 ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
40 uint32_t samplesdone; 40 ci->configure(DSP_SET_SAMPLE_DEPTH, ALAC_OUTPUT_DEPTH-1);
41 uint32_t elapsedtime; 41 }
42 int samplesdecoded;
43 unsigned int i;
44 unsigned char* buffer;
45 alac_file alac;
46 int retval;
47
48 /* Generic codec initialisation */
49 ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
50 ci->configure(DSP_SET_SAMPLE_DEPTH, ALAC_OUTPUT_DEPTH-1);
51
52 next_track:
53 retval = CODEC_OK;
54
55 /* Clean and initialize decoder structures */
56 memset(&demux_res , 0, sizeof(demux_res));
57 if (codec_init()) {
58 LOGF("ALAC: Error initialising codec\n");
59 retval = CODEC_ERROR;
60 goto exit;
61 }
62
63 if (codec_wait_taginfo() != 0)
64 goto done;
65
66 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
67 codec_set_replaygain(ci->id3);
68 42
69 stream_create(&input_stream,ci); 43 return CODEC_OK;
44}
70 45
71 /* Read from ci->id3->offset before calling qtmovie_read. */ 46/* this is called for each file to process */
72 samplesdone = (uint32_t)(((uint64_t)(ci->id3->offset) * ci->id3->frequency) / 47enum codec_status codec_run(void)
73 (ci->id3->bitrate*128)); 48{
74 49 size_t n;
75 /* if qtmovie_read returns successfully, the stream is up to 50 demux_res_t demux_res;
76 * the movie data, which can be used directly by the decoder */ 51 stream_t input_stream;
77 if (!qtmovie_read(&input_stream, &demux_res)) { 52 uint32_t samplesdone;
78 LOGF("ALAC: Error initialising file\n"); 53 uint32_t elapsedtime = 0;
79 retval = CODEC_ERROR; 54 int samplesdecoded;
80 goto done; 55 unsigned int i;
81 } 56 unsigned char* buffer;
82 57 alac_file alac;
83 /* initialise the sound converter */ 58 intptr_t param;
84 create_alac(demux_res.sound_sample_size, demux_res.num_channels,&alac); 59
85 alac_set_info(&alac, demux_res.codecdata); 60 /* Clean and initialize decoder structures */
86 61 memset(&demux_res , 0, sizeof(demux_res));
87 /* Set i for first frame, seek to desired sample position for resuming. */ 62 if (codec_init()) {
88 i=0; 63 LOGF("ALAC: Error initialising codec\n");
89 if (samplesdone > 0) { 64 return CODEC_ERROR;
90 if (m4a_seek(&demux_res, &input_stream, samplesdone,
91 &samplesdone, (int*) &i)) {
92 elapsedtime = (samplesdone * 10) / (ci->id3->frequency / 100);
93 ci->set_elapsed(elapsedtime);
94 } else {
95 samplesdone = 0;
96 } 65 }
97 }
98 66
99 /* The main decoding loop */ 67 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
100 while (i < demux_res.num_sample_byte_sizes) { 68 codec_set_replaygain(ci->id3);
101 ci->yield(); 69
102 if (ci->stop_codec || ci->new_track) { 70 ci->seek_buffer(0);
103 break; 71
72 stream_create(&input_stream,ci);
73
74 /* Read from ci->id3->offset before calling qtmovie_read. */
75 samplesdone = (uint32_t)(((uint64_t)(ci->id3->offset) * ci->id3->frequency) /
76 (ci->id3->bitrate*128));
77
78 /* if qtmovie_read returns successfully, the stream is up to
79 * the movie data, which can be used directly by the decoder */
80 if (!qtmovie_read(&input_stream, &demux_res)) {
81 LOGF("ALAC: Error initialising file\n");
82 return CODEC_ERROR;
104 } 83 }
105 84
106 /* Deal with any pending seek requests */ 85 /* initialise the sound converter */
107 if (ci->seek_time) { 86 create_alac(demux_res.sound_sample_size, demux_res.num_channels,&alac);
108 if (m4a_seek(&demux_res, &input_stream, 87 alac_set_info(&alac, demux_res.codecdata);
109 ((ci->seek_time-1)/10) * (ci->id3->frequency/100), 88
110 &samplesdone, (int *)&i)) { 89 /* Set i for first frame, seek to desired sample position for resuming. */
111 elapsedtime=(samplesdone*10)/(ci->id3->frequency/100); 90 i=0;
112 ci->set_elapsed(elapsedtime); 91 if (samplesdone > 0) {
113 } 92 if (m4a_seek(&demux_res, &input_stream, samplesdone,
114 ci->seek_complete(); 93 &samplesdone, (int*) &i)) {
94 elapsedtime = (samplesdone * 10) / (ci->id3->frequency / 100);
95 ci->set_elapsed(elapsedtime);
96 } else {
97 samplesdone = 0;
98 }
115 } 99 }
116 100
117 /* Request the required number of bytes from the input buffer */ 101 /* The main decoding loop */
118 buffer=ci->request_buffer(&n, ALAC_BYTE_BUFFER_SIZE); 102 while (i < demux_res.num_sample_byte_sizes) {
103 enum codec_command_action action = ci->get_command(&param);
104
105 if (action == CODEC_ACTION_HALT)
106 break;
119 107
120 /* Decode one block - returned samples will be host-endian */ 108 /* Request the required number of bytes from the input buffer */
121 ci->yield(); 109 buffer=ci->request_buffer(&n, ALAC_BYTE_BUFFER_SIZE);
122 samplesdecoded=alac_decode_frame(&alac, buffer, outputbuffer, ci->yield);
123 110
124 /* Advance codec buffer by amount of consumed bytes */ 111 /* Deal with any pending seek requests */
125 ci->advance_buffer(alac.bytes_consumed); 112 if (action == CODEC_ACTION_SEEK_TIME) {
113 if (m4a_seek(&demux_res, &input_stream,
114 (param/10) * (ci->id3->frequency/100),
115 &samplesdone, (int *)&i)) {
116 elapsedtime=(samplesdone*10)/(ci->id3->frequency/100);
117 }
118 ci->set_elapsed(elapsedtime);
119 ci->seek_complete();
120 }
126 121
127 /* Output the audio */ 122 /* Request the required number of bytes from the input buffer */
128 ci->yield(); 123 buffer=ci->request_buffer(&n, ALAC_BYTE_BUFFER_SIZE);
129 ci->pcmbuf_insert(outputbuffer[0], outputbuffer[1], samplesdecoded);
130 124
131 /* Update the elapsed-time indicator */ 125 /* Decode one block - returned samples will be host-endian */
132 samplesdone+=samplesdecoded; 126 samplesdecoded=alac_decode_frame(&alac, buffer, outputbuffer, ci->yield);
133 elapsedtime=(samplesdone*10)/(ci->id3->frequency/100); 127 ci->yield();
134 ci->set_elapsed(elapsedtime);
135 128
136 i++; 129 /* Advance codec buffer by amount of consumed bytes */
137 } 130 ci->advance_buffer(alac.bytes_consumed);
138 131
139done: 132 /* Output the audio */
140 LOGF("ALAC: Decoded %lu samples\n",(unsigned long)samplesdone); 133 ci->pcmbuf_insert(outputbuffer[0], outputbuffer[1], samplesdecoded);
141 134
142 if (ci->request_next_track()) 135 /* Update the elapsed-time indicator */
143 goto next_track; 136 samplesdone+=samplesdecoded;
137 elapsedtime=(samplesdone*10)/(ci->id3->frequency/100);
138 ci->set_elapsed(elapsedtime);
139
140 i++;
141 }
144 142
145exit: 143 LOGF("ALAC: Decoded %lu samples\n",(unsigned long)samplesdone);
146 return retval; 144 return CODEC_OK;
147} 145}
diff --git a/apps/codecs/ape.c b/apps/codecs/ape.c
index 11d973ab26..8f95a01ec7 100644
--- a/apps/codecs/ape.c
+++ b/apps/codecs/ape.c
@@ -127,13 +127,23 @@ static void ape_resume(struct ape_ctx_t* ape_ctx, size_t resume_offset,
127} 127}
128 128
129/* this is the codec entry point */ 129/* this is the codec entry point */
130enum codec_status codec_main(void) 130enum codec_status codec_main(enum codec_entry_call_reason reason)
131{
132 if (reason == CODEC_LOAD) {
133 /* Generic codec initialisation */
134 ci->configure(DSP_SET_SAMPLE_DEPTH, APE_OUTPUT_DEPTH-1);
135 }
136
137 return CODEC_OK;
138}
139
140/* this is called for each file to process */
141enum codec_status codec_run(void)
131{ 142{
132 struct ape_ctx_t ape_ctx; 143 struct ape_ctx_t ape_ctx;
133 uint32_t samplesdone; 144 uint32_t samplesdone;
134 uint32_t elapsedtime; 145 uint32_t elapsedtime;
135 size_t bytesleft; 146 size_t bytesleft;
136 int retval;
137 147
138 uint32_t currentframe; 148 uint32_t currentframe;
139 uint32_t newfilepos; 149 uint32_t newfilepos;
@@ -145,33 +155,24 @@ enum codec_status codec_main(void)
145 int res; 155 int res;
146 int firstbyte; 156 int firstbyte;
147 size_t resume_offset; 157 size_t resume_offset;
148 158 intptr_t param;
149 /* Generic codec initialisation */
150 ci->configure(DSP_SET_SAMPLE_DEPTH, APE_OUTPUT_DEPTH-1);
151
152next_track:
153 retval = CODEC_OK;
154 159
155 if (codec_init()) { 160 if (codec_init()) {
156 LOGF("APE: Error initialising codec\n"); 161 LOGF("APE: Error initialising codec\n");
157 retval = CODEC_ERROR; 162 return CODEC_ERROR;
158 goto exit;
159 } 163 }
160 164
161 if (codec_wait_taginfo() != 0)
162 goto done;
163
164 /* Remember the resume position - when the codec is opened, the 165 /* Remember the resume position - when the codec is opened, the
165 playback engine will reset it. */ 166 playback engine will reset it. */
166 resume_offset = ci->id3->offset; 167 resume_offset = ci->id3->offset;
167 168
169 ci->seek_buffer(0);
168 inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE); 170 inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
169 171
170 /* Read the file headers to populate the ape_ctx struct */ 172 /* Read the file headers to populate the ape_ctx struct */
171 if (ape_parseheaderbuf(inbuffer,&ape_ctx) < 0) { 173 if (ape_parseheaderbuf(inbuffer,&ape_ctx) < 0) {
172 LOGF("APE: Error reading header\n"); 174 LOGF("APE: Error reading header\n");
173 retval = CODEC_ERROR; 175 return CODEC_ERROR;
174 goto exit;
175 } 176 }
176 177
177 /* Initialise the seektable for this file */ 178 /* Initialise the seektable for this file */
@@ -243,16 +244,16 @@ frame_start:
243 /* Decode the frame a chunk at a time */ 244 /* Decode the frame a chunk at a time */
244 while (nblocks > 0) 245 while (nblocks > 0)
245 { 246 {
246 ci->yield(); 247 enum codec_command_action action = ci->get_command(&param);
247 if (ci->stop_codec || ci->new_track) { 248
249 if (action == CODEC_ACTION_HALT)
248 goto done; 250 goto done;
249 }
250 251
251 /* Deal with any pending seek requests */ 252 /* Deal with any pending seek requests */
252 if (ci->seek_time) 253 if (action == CODEC_ACTION_SEEK_TIME)
253 { 254 {
254 if (ape_calc_seekpos(&ape_ctx, 255 if (ape_calc_seekpos(&ape_ctx,
255 ((ci->seek_time-1)/10) * (ci->id3->frequency/100), 256 (param/10) * (ci->id3->frequency/100),
256 &currentframe, 257 &currentframe,
257 &newfilepos, 258 &newfilepos,
258 &samplestoskip)) 259 &samplestoskip))
@@ -266,9 +267,12 @@ frame_start:
266 ci->seek_buffer(newfilepos); 267 ci->seek_buffer(newfilepos);
267 inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE); 268 inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE);
268 269
270 elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100);
271 ci->set_elapsed(elapsedtime);
269 ci->seek_complete(); 272 ci->seek_complete();
270 goto frame_start; /* Sorry... */ 273 goto frame_start; /* Sorry... */
271 } 274 }
275
272 ci->seek_complete(); 276 ci->seek_complete();
273 } 277 }
274 278
@@ -281,8 +285,7 @@ frame_start:
281 { 285 {
282 /* Frame decoding error, abort */ 286 /* Frame decoding error, abort */
283 LOGF("APE: Frame %lu, error %d\n",(unsigned long)currentframe,res); 287 LOGF("APE: Frame %lu, error %d\n",(unsigned long)currentframe,res);
284 retval = CODEC_ERROR; 288 return CODEC_ERROR;
285 goto done;
286 } 289 }
287 290
288 ci->yield(); 291 ci->yield();
@@ -320,10 +323,5 @@ frame_start:
320 323
321done: 324done:
322 LOGF("APE: Decoded %lu samples\n",(unsigned long)samplesdone); 325 LOGF("APE: Decoded %lu samples\n",(unsigned long)samplesdone);
323 326 return CODEC_OK;
324 if (ci->request_next_track())
325 goto next_track;
326
327exit:
328 return retval;
329} 327}
diff --git a/apps/codecs/asap.c b/apps/codecs/asap.c
index 9447c738d2..f12dc6a0c5 100644
--- a/apps/codecs/asap.c
+++ b/apps/codecs/asap.c
@@ -29,24 +29,21 @@ CODEC_HEADER
29static byte samples[CHUNK_SIZE] IBSS_ATTR; /* The sample buffer */ 29static byte samples[CHUNK_SIZE] IBSS_ATTR; /* The sample buffer */
30static ASAP_State asap; /* asap codec state */ 30static ASAP_State asap; /* asap codec state */
31 31
32/* this is the codec entry point */ 32/* this is called for each file to process */
33enum codec_status codec_main(void) 33enum codec_status codec_run(void)
34{ 34{
35 int n_bytes; 35 int n_bytes;
36 int song; 36 int song;
37 int duration; 37 int duration;
38 char* module; 38 char* module;
39 int bytesPerSample =2; 39 int bytesPerSample =2;
40 intptr_t param;
40 41
41next_track:
42 if (codec_init()) { 42 if (codec_init()) {
43 DEBUGF("codec init failed\n"); 43 DEBUGF("codec init failed\n");
44 return CODEC_ERROR; 44 return CODEC_ERROR;
45 } 45 }
46 46
47 if (codec_wait_taginfo() != 0)
48 goto request_next_track;
49
50 codec_set_replaygain(ci->id3); 47 codec_set_replaygain(ci->id3);
51 48
52 int bytes_done =0; 49 int bytes_done =0;
@@ -97,19 +94,20 @@ next_track:
97 94
98 /* The main decoder loop */ 95 /* The main decoder loop */
99 while (1) { 96 while (1) {
100 ci->yield(); 97 enum codec_command_action action = ci->get_command(&param);
101 if (ci->stop_codec || ci->new_track) 98
99 if (action == CODEC_ACTION_HALT)
102 break; 100 break;
103 101
104 if (ci->seek_time) { 102 if (action == CODEC_ACTION_SEEK_TIME) {
105 /* New time is ready in ci->seek_time */ 103 /* New time is ready in param */
106 104
107 /* seek to pos */ 105 /* seek to pos */
108 ASAP_Seek(&asap,ci->seek_time); 106 ASAP_Seek(&asap,param);
109 /* update elapsed */
110 ci->set_elapsed(ci->seek_time);
111 /* update bytes_done */ 107 /* update bytes_done */
112 bytes_done = ci->seek_time*44.1*2; 108 bytes_done = param*44.1*2;
109 /* update elapsed */
110 ci->set_elapsed((bytes_done / 2) / 44.1);
113 /* seek ready */ 111 /* seek ready */
114 ci->seek_complete(); 112 ci->seek_complete();
115 } 113 }
@@ -129,10 +127,6 @@ next_track:
129 if(n_bytes != sizeof(samples)) 127 if(n_bytes != sizeof(samples))
130 break; 128 break;
131 } 129 }
132
133request_next_track:
134 if (ci->request_next_track())
135 goto next_track;
136 130
137 return CODEC_OK; 131 return CODEC_OK;
138} 132}
diff --git a/apps/codecs/atrac3_oma.c b/apps/codecs/atrac3_oma.c
index 73f3ad29fd..ab24783368 100644
--- a/apps/codecs/atrac3_oma.c
+++ b/apps/codecs/atrac3_oma.c
@@ -33,24 +33,22 @@ CODEC_HEADER
33 33
34static ATRAC3Context q IBSS_ATTR; 34static ATRAC3Context q IBSS_ATTR;
35 35
36/* this is the codec entry point */ 36/* this is called for each file to process */
37enum codec_status codec_main(void) 37enum codec_status codec_run(void)
38{ 38{
39 static size_t buff_size; 39 static size_t buff_size;
40 int datasize, res, frame_counter, total_frames, seek_frame_offset; 40 int datasize, res, frame_counter, total_frames, seek_frame_offset;
41 uint8_t *bit_buffer; 41 uint8_t *bit_buffer;
42 int elapsed = 0; 42 int elapsed = 0;
43 size_t resume_offset; 43 size_t resume_offset;
44 intptr_t param;
45 enum codec_command_action action = CODEC_ACTION_NULL;
44 46
45next_track:
46 if (codec_init()) { 47 if (codec_init()) {
47 DEBUGF("codec init failed\n"); 48 DEBUGF("codec init failed\n");
48 return CODEC_ERROR; 49 return CODEC_ERROR;
49 } 50 }
50 51
51 if (codec_wait_taginfo() != 0)
52 goto done;
53
54 resume_offset = ci->id3->offset; 52 resume_offset = ci->id3->offset;
55 53
56 codec_set_replaygain(ci->id3); 54 codec_set_replaygain(ci->id3);
@@ -60,84 +58,88 @@ next_track:
60 ci->configure(DSP_SET_SAMPLE_DEPTH, 17); /* Remark: atrac3 uses s15.0 by default, s15.2 was hacked. */ 58 ci->configure(DSP_SET_SAMPLE_DEPTH, 17); /* Remark: atrac3 uses s15.0 by default, s15.2 was hacked. */
61 ci->configure(DSP_SET_STEREO_MODE, ci->id3->channels == 1 ? 59 ci->configure(DSP_SET_STEREO_MODE, ci->id3->channels == 1 ?
62 STEREO_MONO : STEREO_NONINTERLEAVED); 60 STEREO_MONO : STEREO_NONINTERLEAVED);
63 61
64 res =atrac3_decode_init(&q, ci->id3); 62 ci->seek_buffer(0);
63
64 res = atrac3_decode_init(&q, ci->id3);
65 if(res < 0) { 65 if(res < 0) {
66 DEBUGF("failed to initialize OMA atrac decoder\n"); 66 DEBUGF("failed to initialize OMA atrac decoder\n");
67 return CODEC_ERROR; 67 return CODEC_ERROR;
68 } 68 }
69 69
70 total_frames = (ci->id3->filesize - ci->id3->first_frame_offset) / FRAMESIZE;
71 frame_counter = 0;
72
70 /* check for a mid-track resume and force a seek time accordingly */ 73 /* check for a mid-track resume and force a seek time accordingly */
71 if(resume_offset > ci->id3->first_frame_offset) { 74 if(resume_offset > ci->id3->first_frame_offset) {
72 resume_offset -= ci->id3->first_frame_offset; 75 resume_offset -= ci->id3->first_frame_offset;
73 /* calculate resume_offset in frames */ 76 /* calculate resume_offset in frames */
74 resume_offset = (int)resume_offset / FRAMESIZE; 77 resume_offset = (int)resume_offset / FRAMESIZE;
75 ci->seek_time = (int)resume_offset * ((FRAMESIZE * 8)/BITRATE); 78 param = (int)resume_offset * ((FRAMESIZE * 8)/BITRATE);
79 action = CODEC_ACTION_SEEK_TIME;
80 }
81 else {
82 ci->set_elapsed(0);
83 ci->seek_buffer(ci->id3->first_frame_offset);
76 } 84 }
77 total_frames = (ci->id3->filesize - ci->id3->first_frame_offset) / FRAMESIZE;
78 frame_counter = 0;
79
80 ci->set_elapsed(0);
81 ci->seek_buffer(0);
82 ci->advance_buffer(ci->id3->first_frame_offset);
83 85
84 /* The main decoder loop */ 86 /* The main decoder loop */
85seek_start :
86 while(frame_counter < total_frames) 87 while(frame_counter < total_frames)
87 { 88 {
89 if (action == CODEC_ACTION_NULL)
90 action = ci->get_command(&param);
91
92 if (action == CODEC_ACTION_HALT)
93 break;
94
88 bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, FRAMESIZE); 95 bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, FRAMESIZE);
89 96
90 ci->yield(); 97 if (action == CODEC_ACTION_SEEK_TIME) {
91 if (ci->stop_codec || ci->new_track) 98 /* Do not allow seeking beyond the file's length */
92 goto done; 99 if ((unsigned) param > ci->id3->length) {
93 100 ci->set_elapsed(ci->id3->length);
94 if (ci->seek_time) { 101 ci->seek_complete();
95 ci->set_elapsed(ci->seek_time); 102 break;
96 103 }
97 /* Do not allow seeking beyond the file's length */ 104
98 if ((unsigned) ci->seek_time > ci->id3->length) { 105 /* Seek to the start of the track */
99 ci->seek_complete(); 106 if (param == 0) {
100 goto done; 107 elapsed = 0;
101 } 108 ci->set_elapsed(0);
102 109 ci->seek_buffer(ci->id3->first_frame_offset);
103 /* Seek to the start of the track */ 110 ci->seek_complete();
104 if (ci->seek_time == 1) { 111 action = CODEC_ACTION_NULL;
105 ci->set_elapsed(0); 112 continue;
106 ci->seek_complete(); 113 }
107 ci->seek_buffer(ci->id3->first_frame_offset); 114
108 elapsed = 0; 115 seek_frame_offset = (param * BITRATE) / (8 * FRAMESIZE);
109 goto seek_start; 116 frame_counter = seek_frame_offset;
110 } 117 ci->seek_buffer(ci->id3->first_frame_offset + seek_frame_offset* FRAMESIZE);
111 seek_frame_offset = (ci->seek_time * BITRATE) / (8 * FRAMESIZE); 118 bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, FRAMESIZE);
112 frame_counter = seek_frame_offset; 119 elapsed = param;
113 ci->seek_buffer(ci->id3->first_frame_offset + seek_frame_offset* FRAMESIZE);
114 bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, FRAMESIZE);
115 elapsed = ci->seek_time;
116
117 ci->set_elapsed(elapsed);
118 ci->seek_complete();
119 }
120
121 res = atrac3_decode_frame(FRAMESIZE, &q, &datasize, bit_buffer, FRAMESIZE);
122
123 if(res != (int)FRAMESIZE) {
124 DEBUGF("codec error\n");
125 return CODEC_ERROR;
126 }
127
128 if(datasize)
129 ci->pcmbuf_insert(q.outSamples, q.outSamples + 1024, q.samples_per_frame / ci->id3->channels);
130
131 elapsed += (FRAMESIZE * 8) / BITRATE;
132 ci->set_elapsed(elapsed); 120 ci->set_elapsed(elapsed);
133 121 ci->seek_complete();
134 ci->advance_buffer(FRAMESIZE); 122 }
135 frame_counter++; 123
136 } 124 action = CODEC_ACTION_NULL;
137 125
138 done: 126 res = atrac3_decode_frame(FRAMESIZE, &q, &datasize, bit_buffer, FRAMESIZE);
139 if (ci->request_next_track()) 127
140 goto next_track; 128 if(res != (int)FRAMESIZE) {
129 DEBUGF("codec error\n");
130 return CODEC_ERROR;
131 }
132
133 if(datasize)
134 ci->pcmbuf_insert(q.outSamples, q.outSamples + 1024,
135 q.samples_per_frame / ci->id3->channels);
136
137 elapsed += (FRAMESIZE * 8) / BITRATE;
138 ci->set_elapsed(elapsed);
139
140 ci->advance_buffer(FRAMESIZE);
141 frame_counter++;
142 }
141 143
142 return CODEC_OK; 144 return CODEC_OK;
143} 145}
diff --git a/apps/codecs/atrac3_rm.c b/apps/codecs/atrac3_rm.c
index 6a77d24283..1322e917ed 100644
--- a/apps/codecs/atrac3_rm.c
+++ b/apps/codecs/atrac3_rm.c
@@ -41,9 +41,9 @@ static void init_rm(RMContext *rmctx)
41 memcpy(ci->id3->id3v2buf, (char*)rmctx->codec_extradata, rmctx->extradata_size*sizeof(char)); 41 memcpy(ci->id3->id3v2buf, (char*)rmctx->codec_extradata, rmctx->extradata_size*sizeof(char));
42} 42}
43 43
44/* this is the codec entry point */ 44/* this is called for each file to process */
45enum codec_status codec_main(void) 45enum codec_status codec_run(void)
46{ 46{
47 static size_t buff_size; 47 static size_t buff_size;
48 int datasize, res, consumed, i, time_offset; 48 int datasize, res, consumed, i, time_offset;
49 uint8_t *bit_buffer; 49 uint8_t *bit_buffer;
@@ -52,16 +52,14 @@ enum codec_status codec_main(void)
52 int scrambling_unit_size, num_units, elapsed = 0; 52 int scrambling_unit_size, num_units, elapsed = 0;
53 int playback_on = -1; 53 int playback_on = -1;
54 size_t resume_offset; 54 size_t resume_offset;
55 intptr_t param;
56 enum codec_command_action action = CODEC_ACTION_NULL;
55 57
56next_track:
57 if (codec_init()) { 58 if (codec_init()) {
58 DEBUGF("codec init failed\n"); 59 DEBUGF("codec init failed\n");
59 return CODEC_ERROR; 60 return CODEC_ERROR;
60 } 61 }
61 62
62 if (codec_wait_taginfo() != 0)
63 goto done;
64
65 resume_offset = ci->id3->offset; 63 resume_offset = ci->id3->offset;
66 64
67 codec_set_replaygain(ci->id3); 65 codec_set_replaygain(ci->id3);
@@ -69,6 +67,7 @@ next_track:
69 ci->memset(&pkt,0,sizeof(RMPacket)); 67 ci->memset(&pkt,0,sizeof(RMPacket));
70 ci->memset(&q,0,sizeof(ATRAC3Context)); 68 ci->memset(&q,0,sizeof(ATRAC3Context));
71 69
70 ci->seek_buffer(0);
72 init_rm(&rmctx); 71 init_rm(&rmctx);
73 72
74 ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency); 73 ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency);
@@ -84,22 +83,25 @@ next_track:
84 h = rmctx.sub_packet_h; 83 h = rmctx.sub_packet_h;
85 scrambling_unit_size = h*fs; 84 scrambling_unit_size = h*fs;
86 85
87 res =atrac3_decode_init(&q, ci->id3); 86 res = atrac3_decode_init(&q, ci->id3);
88 if(res < 0) { 87 if(res < 0) {
89 DEBUGF("failed to initialize RM atrac decoder\n"); 88 DEBUGF("failed to initialize RM atrac decoder\n");
90 return CODEC_ERROR; 89 return CODEC_ERROR;
91 } 90 }
92 91
93 /* check for a mid-track resume and force a seek time accordingly */ 92 /* check for a mid-track resume and force a seek time accordingly */
94 if(resume_offset > rmctx.data_offset + DATA_HEADER_SIZE) { 93 if(resume_offset > rmctx.data_offset + DATA_HEADER_SIZE) {
95 resume_offset -= rmctx.data_offset + DATA_HEADER_SIZE; 94 resume_offset -= rmctx.data_offset + DATA_HEADER_SIZE;
96 num_units = (int)resume_offset / scrambling_unit_size; 95 num_units = (int)resume_offset / scrambling_unit_size;
97 /* put number of subpackets to skip in resume_offset */ 96 /* put number of subpackets to skip in resume_offset */
98 resume_offset /= (sps + PACKET_HEADER_SIZE); 97 resume_offset /= (sps + PACKET_HEADER_SIZE);
99 ci->seek_time = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate); 98 param = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate);
99 action = CODEC_ACTION_SEEK_TIME;
100 } 100 }
101 101 else {
102 ci->set_elapsed(0); 102 ci->set_elapsed(0);
103 }
104
103 ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE); 105 ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE);
104 106
105 /* The main decoder loop */ 107 /* The main decoder loop */
@@ -115,22 +117,23 @@ seek_start :
115 return CODEC_ERROR; 117 return CODEC_ERROR;
116 } 118 }
117 else 119 else
118 goto done; 120 return CODEC_OK;
119 } 121 }
120 122
121 for(i = 0; i < rmctx.audio_pkt_cnt*(fs/sps) ; i++) 123 for(i = 0; i < rmctx.audio_pkt_cnt*(fs/sps) ; i++)
122 { 124 {
123 ci->yield(); 125 if (action == CODEC_ACTION_NULL)
124 if (ci->stop_codec || ci->new_track) 126 action = ci->get_command(&param);
125 goto done;
126 127
127 if (ci->seek_time) { 128 if (action == CODEC_ACTION_HALT)
128 ci->set_elapsed(ci->seek_time); 129 return CODEC_OK;
129 130
131 if (action == CODEC_ACTION_SEEK_TIME) {
130 /* Do not allow seeking beyond the file's length */ 132 /* Do not allow seeking beyond the file's length */
131 if ((unsigned) ci->seek_time > ci->id3->length) { 133 if ((unsigned) param > ci->id3->length) {
134 ci->set_elapsed(ci->id3->length);
132 ci->seek_complete(); 135 ci->seek_complete();
133 goto done; 136 return CODEC_OK;
134 } 137 }
135 138
136 ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE); 139 ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE);
@@ -139,12 +142,13 @@ seek_start :
139 rmctx.frame_number = 0; 142 rmctx.frame_number = 0;
140 143
141 /* Seek to the start of the track */ 144 /* Seek to the start of the track */
142 if (ci->seek_time == 1) { 145 if (param == 0) {
143 ci->set_elapsed(0); 146 ci->set_elapsed(0);
144 ci->seek_complete(); 147 ci->seek_complete();
148 action = CODEC_ACTION_NULL;
145 goto seek_start; 149 goto seek_start;
146 } 150 }
147 num_units = ((ci->seek_time)/(sps*1000*8/rmctx.bit_rate))/(h*(fs/sps)); 151 num_units = (param/(sps*1000*8/rmctx.bit_rate))/(h*(fs/sps));
148 ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + consumed * num_units); 152 ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + consumed * num_units);
149 bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size); 153 bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size);
150 consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt); 154 consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt);
@@ -155,12 +159,12 @@ seek_start :
155 return CODEC_ERROR; 159 return CODEC_ERROR;
156 } 160 }
157 else 161 else
158 goto done; 162 return CODEC_OK;
159 } 163 }
160 164
161 packet_count = rmctx.nb_packets - rmctx.audio_pkt_cnt * num_units; 165 packet_count = rmctx.nb_packets - rmctx.audio_pkt_cnt * num_units;
162 rmctx.frame_number = ((ci->seek_time)/(sps*1000*8/rmctx.bit_rate)); 166 rmctx.frame_number = (param/(sps*1000*8/rmctx.bit_rate));
163 while(rmctx.audiotimestamp > (unsigned) ci->seek_time) { 167 while(rmctx.audiotimestamp > (unsigned) param) {
164 rmctx.audio_pkt_cnt = 0; 168 rmctx.audio_pkt_cnt = 0;
165 ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + consumed * (num_units-1)); 169 ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + consumed * (num_units-1));
166 bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size); 170 bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size);
@@ -168,16 +172,19 @@ seek_start :
168 packet_count += rmctx.audio_pkt_cnt; 172 packet_count += rmctx.audio_pkt_cnt;
169 num_units--; 173 num_units--;
170 } 174 }
171 time_offset = ci->seek_time - rmctx.audiotimestamp; 175 time_offset = param - rmctx.audiotimestamp;
172 i = (time_offset/((sps * 8 * 1000)/rmctx.bit_rate)); 176 i = (time_offset/((sps * 8 * 1000)/rmctx.bit_rate));
173 elapsed = rmctx.audiotimestamp+(1000*8*sps/rmctx.bit_rate)*i; 177 elapsed = rmctx.audiotimestamp+(1000*8*sps/rmctx.bit_rate)*i;
174 ci->set_elapsed(elapsed); 178 ci->set_elapsed(elapsed);
175 ci->seek_complete(); 179 ci->seek_complete();
176 } 180 }
181
182 action = CODEC_ACTION_NULL;
183
177 if(pkt.length) 184 if(pkt.length)
178 res = atrac3_decode_frame(rmctx.block_align, &q, &datasize, pkt.frames[i], rmctx.block_align); 185 res = atrac3_decode_frame(rmctx.block_align, &q, &datasize, pkt.frames[i], rmctx.block_align);
179 else /* indicates that there are no remaining frames */ 186 else /* indicates that there are no remaining frames */
180 goto done; 187 return CODEC_OK;
181 188
182 if(res != rmctx.block_align) { 189 if(res != rmctx.block_align) {
183 DEBUGF("codec error\n"); 190 DEBUGF("codec error\n");
@@ -196,9 +203,5 @@ seek_start :
196 ci->advance_buffer(consumed); 203 ci->advance_buffer(consumed);
197 } 204 }
198 205
199 done : 206 return CODEC_OK;
200 if (ci->request_next_track())
201 goto next_track;
202
203 return CODEC_OK;
204} 207}
diff --git a/apps/codecs/au.c b/apps/codecs/au.c
index 3f9436c9e7..e06f931cf9 100644
--- a/apps/codecs/au.c
+++ b/apps/codecs/au.c
@@ -106,9 +106,19 @@ static int convert_au_format(unsigned int encoding, struct pcm_format *fmt)
106} 106}
107 107
108/* this is the codec entry point */ 108/* this is the codec entry point */
109enum codec_status codec_main(void) 109enum codec_status codec_main(enum codec_entry_call_reason reason)
110{
111 if (reason == CODEC_LOAD) {
112 /* Generic codec initialisation */
113 ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1);
114 }
115
116 return CODEC_OK;
117}
118
119/* this is called for each file to process */
120enum codec_status codec_run(void)
110{ 121{
111 int status;
112 struct pcm_format format; 122 struct pcm_format format;
113 uint32_t bytesdone, decodedsamples; 123 uint32_t bytesdone, decodedsamples;
114 size_t n; 124 size_t n;
@@ -119,22 +129,13 @@ enum codec_status codec_main(void)
119 off_t firstblockposn; /* position of the first block in file */ 129 off_t firstblockposn; /* position of the first block in file */
120 const struct pcm_codec *codec; 130 const struct pcm_codec *codec;
121 int offset = 0; 131 int offset = 0;
122 132 intptr_t param;
123 /* Generic codec initialisation */ 133
124 ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1);
125
126next_track:
127 status = CODEC_OK;
128
129 if (codec_init()) { 134 if (codec_init()) {
130 DEBUGF("codec_init() error\n"); 135 DEBUGF("codec_init() error\n");
131 status = CODEC_ERROR; 136 return CODEC_ERROR;
132 goto exit;
133 } 137 }
134 138
135 if (codec_wait_taginfo() != 0)
136 goto done;
137
138 codec_set_replaygain(ci->id3); 139 codec_set_replaygain(ci->id3);
139 140
140 /* Need to save offset for later use (cleared indirectly by advance_buffer) */ 141 /* Need to save offset for later use (cleared indirectly by advance_buffer) */
@@ -145,6 +146,7 @@ next_track:
145 format.is_little_endian = false; 146 format.is_little_endian = false;
146 147
147 /* set format */ 148 /* set format */
149 ci->seek_buffer(0);
148 buf = ci->request_buffer(&n, 24); 150 buf = ci->request_buffer(&n, 24);
149 if (n < 24 || (memcmp(buf, ".snd", 4) != 0)) 151 if (n < 24 || (memcmp(buf, ".snd", 4) != 0))
150 { 152 {
@@ -170,8 +172,7 @@ next_track:
170 if (offset < 24) 172 if (offset < 24)
171 { 173 {
172 DEBUGF("CODEC_ERROR: sun audio offset size is small: %d\n", offset); 174 DEBUGF("CODEC_ERROR: sun audio offset size is small: %d\n", offset);
173 status = CODEC_ERROR; 175 return CODEC_ERROR;
174 goto done;
175 } 176 }
176 /* data size */ 177 /* data size */
177 format.numbytes = get_be32(buf + 8); 178 format.numbytes = get_be32(buf + 8);
@@ -182,8 +183,7 @@ next_track:
182 if (format.formattag == AU_FORMAT_UNSUPPORT) 183 if (format.formattag == AU_FORMAT_UNSUPPORT)
183 { 184 {
184 DEBUGF("CODEC_ERROR: sun audio unsupport format: %d\n", get_be32(buf + 12)); 185 DEBUGF("CODEC_ERROR: sun audio unsupport format: %d\n", get_be32(buf + 12));
185 status = CODEC_ERROR; 186 return CODEC_ERROR;
186 goto done;
187 } 187 }
188 /* skip sample rate */ 188 /* skip sample rate */
189 format.channels = get_be32(buf + 20); 189 format.channels = get_be32(buf + 20);
@@ -202,20 +202,17 @@ next_track:
202 if (!codec) 202 if (!codec)
203 { 203 {
204 DEBUGF("CODEC_ERROR: unsupport sun audio format: %x\n", (int)format.formattag); 204 DEBUGF("CODEC_ERROR: unsupport sun audio format: %x\n", (int)format.formattag);
205 status = CODEC_ERROR; 205 return CODEC_ERROR;
206 goto done;
207 } 206 }
208 207
209 if (!codec->set_format(&format)) 208 if (!codec->set_format(&format))
210 { 209 {
211 status = CODEC_ERROR; 210 return CODEC_ERROR;
212 goto done;
213 } 211 }
214 212
215 if (format.numbytes == 0) { 213 if (format.numbytes == 0) {
216 DEBUGF("CODEC_ERROR: data size is 0\n"); 214 DEBUGF("CODEC_ERROR: data size is 0\n");
217 status = CODEC_ERROR; 215 return CODEC_ERROR;
218 goto done;
219 } 216 }
220 217
221 /* check chunksize */ 218 /* check chunksize */
@@ -225,8 +222,7 @@ next_track:
225 if (format.chunksize == 0) 222 if (format.chunksize == 0)
226 { 223 {
227 DEBUGF("CODEC_ERROR: chunksize is 0\n"); 224 DEBUGF("CODEC_ERROR: chunksize is 0\n");
228 status = CODEC_ERROR; 225 return CODEC_ERROR;
229 goto done;
230 } 226 }
231 227
232 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); 228 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
@@ -236,8 +232,7 @@ next_track:
236 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); 232 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
237 } else { 233 } else {
238 DEBUGF("CODEC_ERROR: more than 2 channels\n"); 234 DEBUGF("CODEC_ERROR: more than 2 channels\n");
239 status = CODEC_ERROR; 235 return CODEC_ERROR;
240 goto done;
241 } 236 }
242 237
243 /* make sure we're at the correct offset */ 238 /* make sure we're at the correct offset */
@@ -253,7 +248,6 @@ next_track:
253 bytesdone = newpos->pos; 248 bytesdone = newpos->pos;
254 decodedsamples = newpos->samples; 249 decodedsamples = newpos->samples;
255 } 250 }
256 ci->seek_complete();
257 } else { 251 } else {
258 /* already where we need to be */ 252 /* already where we need to be */
259 bytesdone = 0; 253 bytesdone = 0;
@@ -263,22 +257,29 @@ next_track:
263 endofstream = 0; 257 endofstream = 0;
264 258
265 while (!endofstream) { 259 while (!endofstream) {
266 ci->yield(); 260 enum codec_command_action action = ci->get_command(&param);
267 if (ci->stop_codec || ci->new_track) { 261
262 if (action == CODEC_ACTION_HALT)
268 break; 263 break;
269 }
270 264
271 if (ci->seek_time) { 265 if (action == CODEC_ACTION_SEEK_TIME) {
272 /* 3rd args(read_buffer) is unnecessary in the format which Sun Audio supports. */ 266 /* 3rd args(read_buffer) is unnecessary in the format which Sun Audio supports. */
273 struct pcm_pos *newpos = codec->get_seek_pos(ci->seek_time, PCM_SEEK_TIME, NULL); 267 struct pcm_pos *newpos = codec->get_seek_pos(param, PCM_SEEK_TIME, NULL);
274 268
275 if (newpos->pos > format.numbytes) 269 if (newpos->pos > format.numbytes)
270 {
271 ci->set_elapsed(ci->id3->length);
272 ci->seek_complete();
276 break; 273 break;
274 }
275
277 if (ci->seek_buffer(firstblockposn + newpos->pos)) 276 if (ci->seek_buffer(firstblockposn + newpos->pos))
278 { 277 {
279 bytesdone = newpos->pos; 278 bytesdone = newpos->pos;
280 decodedsamples = newpos->samples; 279 decodedsamples = newpos->samples;
281 } 280 }
281
282 ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
282 ci->seek_complete(); 283 ci->seek_complete();
283 } 284 }
284 285
@@ -290,11 +291,10 @@ next_track:
290 endofstream = 1; 291 endofstream = 1;
291 } 292 }
292 293
293 status = codec->decode(aubuf, n, samples, &bufcount); 294 if (codec->decode(aubuf, n, samples, &bufcount) == CODEC_ERROR)
294 if (status == CODEC_ERROR)
295 { 295 {
296 DEBUGF("codec error\n"); 296 DEBUGF("codec error\n");
297 goto done; 297 return CODEC_ERROR;
298 } 298 }
299 299
300 ci->pcmbuf_insert(samples, NULL, bufcount); 300 ci->pcmbuf_insert(samples, NULL, bufcount);
@@ -308,9 +308,5 @@ next_track:
308 } 308 }
309 309
310done: 310done:
311 if (ci->request_next_track()) 311 return CODEC_OK;
312 goto next_track;
313
314exit:
315 return status;
316} 312}
diff --git a/apps/codecs/codec_crt0.c b/apps/codecs/codec_crt0.c
index cf14e460ec..33876272c6 100644
--- a/apps/codecs/codec_crt0.c
+++ b/apps/codecs/codec_crt0.c
@@ -27,39 +27,45 @@ struct codec_api *ci DATA_ATTR;
27extern unsigned char plugin_bss_start[]; 27extern unsigned char plugin_bss_start[];
28extern unsigned char plugin_end_addr[]; 28extern unsigned char plugin_end_addr[];
29 29
30extern enum codec_status codec_main(void); 30extern enum codec_status codec_main(enum codec_entry_call_reason reason);
31 31
32/* stub, the entry point is called via its reference in __header to 32/* stub, the entry point is called via its reference in __header to
33 * avoid warning with certain compilers */ 33 * avoid warning with certain compilers */
34int _start(void) {return 0;} 34int _start(void) {return 0;}
35 35
36enum codec_status codec_start(void) 36enum codec_status codec_start(enum codec_entry_call_reason reason)
37{ 37{
38#if (CONFIG_PLATFORM & PLATFORM_NATIVE) 38#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
39#ifdef USE_IRAM 39 if (reason == CODEC_LOAD)
40 extern char iramcopy[], iramstart[], iramend[], iedata[], iend[];
41 size_t iram_size = iramend - iramstart;
42 size_t ibss_size = iend - iedata;
43 if (iram_size > 0 || ibss_size > 0)
44 { 40 {
45 ci->memcpy(iramstart, iramcopy, iram_size); 41#ifdef USE_IRAM
46 ci->memset(iedata, 0, ibss_size); 42 extern char iramcopy[], iramstart[], iramend[], iedata[], iend[];
47 /* make the icache (if it exists) up to date with the new code */ 43 size_t iram_size = iramend - iramstart;
44 size_t ibss_size = iend - iedata;
45 if (iram_size > 0 || ibss_size > 0)
46 {
47 ci->memcpy(iramstart, iramcopy, iram_size);
48 ci->memset(iedata, 0, ibss_size);
49 /* make the icache (if it exists) up to date with the new code */
50 ci->cpucache_invalidate();
51 /* barrier to prevent reordering iram copy and BSS clearing,
52 * because the BSS segment alias the IRAM copy.
53 */
54 asm volatile ("" ::: "memory");
55 }
56#endif /* PLUGIN_USE_IRAM */
57 ci->memset(plugin_bss_start, 0, plugin_end_addr - plugin_bss_start);
58 /* Some parts of bss may be used via a no-cache alias (at least
59 * portalplayer has this). If we don't clear the cache, those aliases
60 * may read garbage */
48 ci->cpucache_invalidate(); 61 ci->cpucache_invalidate();
49 /* barrier to prevent reordering iram copy and BSS clearing,
50 * because the BSS segment alias the IRAM copy.
51 */
52 asm volatile ("" ::: "memory");
53 } 62 }
54#endif /* PLUGIN_USE_IRAM */ 63#endif /* CONFIG_PLATFORM */
55 ci->memset(plugin_bss_start, 0, plugin_end_addr - plugin_bss_start);
56 /* Some parts of bss may be used via a no-cache alias (at least
57 * portalplayer has this). If we don't clear the cache, those aliases
58 * may read garbage */
59 ci->cpucache_invalidate();
60#endif
61 64
62 return codec_main(); 65 /* Note: If for any reason codec_main would not be called with CODEC_LOAD
66 * because the above code failed then it must not be ever be called with
67 * any other value and some strategy to avoid doing so must be conceived */
68 return codec_main(reason);
63} 69}
64 70
65#if defined(CPU_ARM) && (CONFIG_PLATFORM & PLATFORM_NATIVE) 71#if defined(CPU_ARM) && (CONFIG_PLATFORM & PLATFORM_NATIVE)
diff --git a/apps/codecs/cook.c b/apps/codecs/cook.c
index 015618986c..a6b4a1153e 100644
--- a/apps/codecs/cook.c
+++ b/apps/codecs/cook.c
@@ -38,9 +38,9 @@ static void init_rm(RMContext *rmctx)
38 memcpy(rmctx, (void*)(( (intptr_t)ci->id3->id3v2buf + 3 ) &~ 3), sizeof(RMContext)); 38 memcpy(rmctx, (void*)(( (intptr_t)ci->id3->id3v2buf + 3 ) &~ 3), sizeof(RMContext));
39} 39}
40 40
41/* this is the codec entry point */ 41/* this is called for each file to process */
42enum codec_status codec_main(void) 42enum codec_status codec_run(void)
43{ 43{
44 static size_t buff_size; 44 static size_t buff_size;
45 int datasize, res, consumed, i, time_offset; 45 int datasize, res, consumed, i, time_offset;
46 uint8_t *bit_buffer; 46 uint8_t *bit_buffer;
@@ -48,16 +48,14 @@ enum codec_status codec_main(void)
48 uint32_t packet_count; 48 uint32_t packet_count;
49 int scrambling_unit_size, num_units; 49 int scrambling_unit_size, num_units;
50 size_t resume_offset; 50 size_t resume_offset;
51 intptr_t param = 0;
52 enum codec_command_action action = CODEC_ACTION_NULL;
51 53
52next_track:
53 if (codec_init()) { 54 if (codec_init()) {
54 DEBUGF("codec init failed\n"); 55 DEBUGF("codec init failed\n");
55 return CODEC_ERROR; 56 return CODEC_ERROR;
56 } 57 }
57 58
58 if (codec_wait_taginfo() != 0)
59 goto done;
60
61 resume_offset = ci->id3->offset; 59 resume_offset = ci->id3->offset;
62 60
63 codec_set_replaygain(ci->id3); 61 codec_set_replaygain(ci->id3);
@@ -65,6 +63,8 @@ next_track:
65 ci->memset(&pkt,0,sizeof(RMPacket)); 63 ci->memset(&pkt,0,sizeof(RMPacket));
66 ci->memset(&q,0,sizeof(COOKContext)); 64 ci->memset(&q,0,sizeof(COOKContext));
67 65
66 ci->seek_buffer(0);
67
68 init_rm(&rmctx); 68 init_rm(&rmctx);
69 69
70 ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency); 70 ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency);
@@ -87,20 +87,21 @@ next_track:
87 DEBUGF("failed to initialize cook decoder\n"); 87 DEBUGF("failed to initialize cook decoder\n");
88 return CODEC_ERROR; 88 return CODEC_ERROR;
89 } 89 }
90 90
91 /* check for a mid-track resume and force a seek time accordingly */ 91 /* check for a mid-track resume and force a seek time accordingly */
92 if(resume_offset > rmctx.data_offset + DATA_HEADER_SIZE) { 92 if(resume_offset > rmctx.data_offset + DATA_HEADER_SIZE) {
93 resume_offset -= rmctx.data_offset + DATA_HEADER_SIZE; 93 resume_offset -= rmctx.data_offset + DATA_HEADER_SIZE;
94 num_units = (int)resume_offset / scrambling_unit_size; 94 num_units = (int)resume_offset / scrambling_unit_size;
95 /* put number of subpackets to skip in resume_offset */ 95 /* put number of subpackets to skip in resume_offset */
96 resume_offset /= (sps + PACKET_HEADER_SIZE); 96 resume_offset /= (sps + PACKET_HEADER_SIZE);
97 ci->seek_time = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate); 97 param = (int)resume_offset * ((sps * 8 * 1000)/rmctx.bit_rate);
98 action = CODEC_ACTION_SEEK_TIME;
98 } 99 }
99 100
100 ci->set_elapsed(0); 101 ci->set_elapsed(0);
101 ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE); 102 ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE);
102 103
103 /* The main decoder loop */ 104 /* The main decoder loop */
104seek_start : 105seek_start :
105 while(packet_count) 106 while(packet_count)
106 { 107 {
@@ -112,18 +113,19 @@ seek_start :
112 } 113 }
113 114
114 for(i = 0; i < rmctx.audio_pkt_cnt*(fs/sps) ; i++) 115 for(i = 0; i < rmctx.audio_pkt_cnt*(fs/sps) ; i++)
115 { 116 {
116 ci->yield(); 117 if (action == CODEC_ACTION_NULL)
117 if (ci->stop_codec || ci->new_track) 118 action = ci->get_command(&param);
118 goto done;
119 119
120 if (ci->seek_time) { 120 if (action == CODEC_ACTION_HALT)
121 ci->set_elapsed(ci->seek_time); 121 return CODEC_OK;
122 122
123 if (action == CODEC_ACTION_SEEK_TIME) {
123 /* Do not allow seeking beyond the file's length */ 124 /* Do not allow seeking beyond the file's length */
124 if ((unsigned) ci->seek_time > ci->id3->length) { 125 if ((unsigned) param > ci->id3->length) {
126 ci->set_elapsed(ci->id3->length);
125 ci->seek_complete(); 127 ci->seek_complete();
126 goto done; 128 return CODEC_OK;
127 } 129 }
128 130
129 ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE); 131 ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE);
@@ -132,22 +134,24 @@ seek_start :
132 rmctx.frame_number = 0; 134 rmctx.frame_number = 0;
133 135
134 /* Seek to the start of the track */ 136 /* Seek to the start of the track */
135 if (ci->seek_time == 1) { 137 if (param == 0) {
136 ci->set_elapsed(0); 138 ci->set_elapsed(0);
137 ci->seek_complete(); 139 ci->seek_complete();
140 action = CODEC_ACTION_NULL;
138 goto seek_start; 141 goto seek_start;
139 } 142 }
140 num_units = ((ci->seek_time)/(sps*1000*8/rmctx.bit_rate))/(h*(fs/sps)); 143 num_units = (param/(sps*1000*8/rmctx.bit_rate))/(h*(fs/sps));
141 ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + consumed * num_units); 144 ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + consumed * num_units);
142 bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size); 145 bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size);
143 consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt); 146 consumed = rm_get_packet(&bit_buffer, &rmctx, &pkt);
144 if(consumed < 0) { 147 if(consumed < 0) {
145 DEBUGF("rm_get_packet failed\n"); 148 DEBUGF("rm_get_packet failed\n");
146 return CODEC_ERROR; 149 ci->seek_complete();
150 return CODEC_ERROR;
147 } 151 }
148 packet_count = rmctx.nb_packets - rmctx.audio_pkt_cnt * num_units; 152 packet_count = rmctx.nb_packets - rmctx.audio_pkt_cnt * num_units;
149 rmctx.frame_number = ((ci->seek_time)/(sps*1000*8/rmctx.bit_rate)); 153 rmctx.frame_number = (param/(sps*1000*8/rmctx.bit_rate));
150 while(rmctx.audiotimestamp > (unsigned) ci->seek_time) { 154 while(rmctx.audiotimestamp > (unsigned) param) {
151 rmctx.audio_pkt_cnt = 0; 155 rmctx.audio_pkt_cnt = 0;
152 ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + consumed * (num_units-1)); 156 ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE + consumed * (num_units-1));
153 bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size); 157 bit_buffer = (uint8_t *) ci->request_buffer(&buff_size, scrambling_unit_size);
@@ -155,11 +159,14 @@ seek_start :
155 packet_count += rmctx.audio_pkt_cnt; 159 packet_count += rmctx.audio_pkt_cnt;
156 num_units--; 160 num_units--;
157 } 161 }
158 time_offset = ci->seek_time - rmctx.audiotimestamp; 162 time_offset = param - rmctx.audiotimestamp;
159 i = (time_offset/((sps * 8 * 1000)/rmctx.bit_rate)); 163 i = (time_offset/((sps * 8 * 1000)/rmctx.bit_rate));
160 ci->set_elapsed(rmctx.audiotimestamp+(1000*8*sps/rmctx.bit_rate)*i); 164 ci->set_elapsed(rmctx.audiotimestamp+(1000*8*sps/rmctx.bit_rate)*i);
161 ci->seek_complete(); 165 ci->seek_complete();
162 } 166 }
167
168 action = CODEC_ACTION_NULL;
169
163 res = cook_decode_frame(&rmctx,&q, rm_outbuf, &datasize, pkt.frames[i], rmctx.block_align); 170 res = cook_decode_frame(&rmctx,&q, rm_outbuf, &datasize, pkt.frames[i], rmctx.block_align);
164 rmctx.frame_number++; 171 rmctx.frame_number++;
165 172
@@ -181,9 +188,5 @@ seek_start :
181 ci->advance_buffer(consumed); 188 ci->advance_buffer(consumed);
182 } 189 }
183 190
184 done : 191 return CODEC_OK;
185 if (ci->request_next_track())
186 goto next_track;
187
188 return CODEC_OK;
189} 192}
diff --git a/apps/codecs/flac.c b/apps/codecs/flac.c
index 89d14b98a7..a5521b584f 100644
--- a/apps/codecs/flac.c
+++ b/apps/codecs/flac.c
@@ -418,40 +418,40 @@ static bool flac_seek_offset(FLACContext* fc, uint32_t offset) {
418} 418}
419 419
420/* this is the codec entry point */ 420/* this is the codec entry point */
421enum codec_status codec_main(void) 421enum codec_status codec_main(enum codec_entry_call_reason reason)
422{
423 if (reason == CODEC_LOAD) {
424 /* Generic codec initialisation */
425 ci->configure(DSP_SET_SAMPLE_DEPTH, FLAC_OUTPUT_DEPTH-1);
426 }
427
428 return CODEC_OK;
429}
430
431/* this is called for each file to process */
432enum codec_status codec_run(void)
422{ 433{
423 int8_t *buf; 434 int8_t *buf;
424 FLACContext fc; 435 FLACContext fc;
425 uint32_t samplesdone = 0; 436 uint32_t samplesdone;
426 uint32_t elapsedtime; 437 uint32_t elapsedtime;
427 size_t bytesleft; 438 size_t bytesleft;
428 int consumed; 439 int consumed;
429 int res; 440 int res;
430 int frame; 441 int frame;
431 int retval; 442 intptr_t param;
432
433 /* Generic codec initialisation */
434 ci->configure(DSP_SET_SAMPLE_DEPTH, FLAC_OUTPUT_DEPTH-1);
435 443
436next_track:
437 retval = CODEC_OK;
438
439 if (codec_init()) { 444 if (codec_init()) {
440 LOGF("FLAC: Error initialising codec\n"); 445 LOGF("FLAC: Error initialising codec\n");
441 retval = CODEC_ERROR; 446 return CODEC_ERROR;
442 goto exit;
443 } 447 }
444 448
445 if (codec_wait_taginfo() != 0)
446 goto done;
447
448 /* Need to save offset for later use (cleared indirectly by flac_init) */ 449 /* Need to save offset for later use (cleared indirectly by flac_init) */
449 samplesdone = ci->id3->offset; 450 samplesdone = ci->id3->offset;
450 451
451 if (!flac_init(&fc,ci->id3->first_frame_offset)) { 452 if (!flac_init(&fc,ci->id3->first_frame_offset)) {
452 LOGF("FLAC: Error initialising codec\n"); 453 LOGF("FLAC: Error initialising codec\n");
453 retval = CODEC_ERROR; 454 return CODEC_ERROR;
454 goto done;
455 } 455 }
456 456
457 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); 457 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
@@ -459,35 +459,34 @@ next_track:
459 STEREO_MONO : STEREO_NONINTERLEAVED); 459 STEREO_MONO : STEREO_NONINTERLEAVED);
460 codec_set_replaygain(ci->id3); 460 codec_set_replaygain(ci->id3);
461 461
462 if (samplesdone) { 462 flac_seek_offset(&fc, samplesdone);
463 flac_seek_offset(&fc, samplesdone); 463 samplesdone=0;
464 samplesdone=0;
465 }
466 464
467 /* The main decoding loop */ 465 /* The main decoding loop */
468 frame=0; 466 frame=0;
469 buf = ci->request_buffer(&bytesleft, MAX_FRAMESIZE); 467 buf = ci->request_buffer(&bytesleft, MAX_FRAMESIZE);
470 while (bytesleft) { 468 while (bytesleft) {
471 ci->yield(); 469 enum codec_command_action action = ci->get_command(&param);
472 if (ci->stop_codec || ci->new_track) { 470
471 if (action == CODEC_ACTION_HALT)
473 break; 472 break;
474 }
475 473
476 /* Deal with any pending seek requests */ 474 /* Deal with any pending seek requests */
477 if (ci->seek_time) { 475 if (action == CODEC_ACTION_SEEK_TIME) {
478 if (flac_seek(&fc,(uint32_t)(((uint64_t)(ci->seek_time-1) 476 if (flac_seek(&fc,(uint32_t)(((uint64_t)param
479 *ci->id3->frequency)/1000))) { 477 *ci->id3->frequency)/1000))) {
480 /* Refill the input buffer */ 478 /* Refill the input buffer */
481 buf = ci->request_buffer(&bytesleft, MAX_FRAMESIZE); 479 buf = ci->request_buffer(&bytesleft, MAX_FRAMESIZE);
482 } 480 }
481
482 ci->set_elapsed(param);
483 ci->seek_complete(); 483 ci->seek_complete();
484 } 484 }
485 485
486 if((res=flac_decode_frame(&fc,decoded0,decoded1,buf, 486 if((res=flac_decode_frame(&fc,decoded0,decoded1,buf,
487 bytesleft,ci->yield)) < 0) { 487 bytesleft,ci->yield)) < 0) {
488 LOGF("FLAC: Frame %d, error %d\n",frame,res); 488 LOGF("FLAC: Frame %d, error %d\n",frame,res);
489 retval = CODEC_ERROR; 489 return CODEC_ERROR;
490 goto done;
491 } 490 }
492 consumed=fc.gb.index/8; 491 consumed=fc.gb.index/8;
493 frame++; 492 frame++;
@@ -507,14 +506,7 @@ next_track:
507 506
508 buf = ci->request_buffer(&bytesleft, MAX_FRAMESIZE); 507 buf = ci->request_buffer(&bytesleft, MAX_FRAMESIZE);
509 } 508 }
510 retval = CODEC_OK;
511 509
512done:
513 LOGF("FLAC: Decoded %lu samples\n",(unsigned long)samplesdone); 510 LOGF("FLAC: Decoded %lu samples\n",(unsigned long)samplesdone);
514 511 return CODEC_OK;
515 if (ci->request_next_track())
516 goto next_track;
517
518exit:
519 return retval;
520} 512}
diff --git a/apps/codecs/lib/codeclib.c b/apps/codecs/lib/codeclib.c
index af0894c498..443c0bbdcf 100644
--- a/apps/codecs/lib/codeclib.c
+++ b/apps/codecs/lib/codeclib.c
@@ -33,6 +33,16 @@ unsigned char* mp3buf; // The actual MP3 buffer from Rockbox
33unsigned char* mallocbuf; // 512K from the start of MP3 buffer 33unsigned char* mallocbuf; // 512K from the start of MP3 buffer
34unsigned char* filebuf; // The rest of the MP3 buffer 34unsigned char* filebuf; // The rest of the MP3 buffer
35 35
36/* this is the default codec entry point for when nothing needs to be done
37 on load or unload */
38enum codec_status __attribute__((weak))
39codec_main(enum codec_entry_call_reason reason)
40{
41 /* Nothing to do */
42 return CODEC_OK;
43 (void)reason;
44}
45
36int codec_init(void) 46int codec_init(void)
37{ 47{
38 mem_ptr = 0; 48 mem_ptr = 0;
@@ -41,7 +51,7 @@ int codec_init(void)
41 return 0; 51 return 0;
42} 52}
43 53
44void codec_set_replaygain(struct mp3entry* id3) 54void codec_set_replaygain(const struct mp3entry *id3)
45{ 55{
46 ci->configure(DSP_SET_TRACK_GAIN, id3->track_gain); 56 ci->configure(DSP_SET_TRACK_GAIN, id3->track_gain);
47 ci->configure(DSP_SET_ALBUM_GAIN, id3->album_gain); 57 ci->configure(DSP_SET_ALBUM_GAIN, id3->album_gain);
@@ -49,19 +59,6 @@ void codec_set_replaygain(struct mp3entry* id3)
49 ci->configure(DSP_SET_ALBUM_PEAK, id3->album_peak); 59 ci->configure(DSP_SET_ALBUM_PEAK, id3->album_peak);
50} 60}
51 61
52/* Note: codec really needs its own private metdata copy for the current
53 track being processed in order to be stable. */
54int codec_wait_taginfo(void)
55{
56 while (!*ci->taginfo_ready && !ci->stop_codec && !ci->new_track)
57 ci->sleep(0);
58 if (ci->stop_codec)
59 return -1;
60 if (ci->new_track)
61 return 1;
62 return 0;
63}
64
65/* Various "helper functions" common to all the xxx2wav decoder plugins */ 62/* Various "helper functions" common to all the xxx2wav decoder plugins */
66 63
67 64
diff --git a/apps/codecs/lib/codeclib.h b/apps/codecs/lib/codeclib.h
index 41b466ed1f..30091c5333 100644
--- a/apps/codecs/lib/codeclib.h
+++ b/apps/codecs/lib/codeclib.h
@@ -156,8 +156,7 @@ static inline unsigned int bs_generic(unsigned int v, int mode)
156/* Various codec helper functions */ 156/* Various codec helper functions */
157 157
158int codec_init(void); 158int codec_init(void);
159void codec_set_replaygain(struct mp3entry* id3); 159void codec_set_replaygain(const struct mp3entry *id3);
160int codec_wait_taginfo(void); /* 0 = success */
161 160
162#ifdef RB_PROFILE 161#ifdef RB_PROFILE
163void __cyg_profile_func_enter(void *this_fn, void *call_site) 162void __cyg_profile_func_enter(void *this_fn, void *call_site)
diff --git a/apps/codecs/mod.c b/apps/codecs/mod.c
index 4ace721a1e..3dfaac663f 100644
--- a/apps/codecs/mod.c
+++ b/apps/codecs/mod.c
@@ -1218,47 +1218,37 @@ void synthrender(int32_t *renderbuffer, int samplecount)
1218 } 1218 }
1219} 1219}
1220 1220
1221/* this is the codec entry point */
1222enum codec_status codec_main(enum codec_entry_call_reason reason)
1223{
1224 if (reason == CODEC_LOAD) {
1225 /* Make use of 44.1khz */
1226 ci->configure(DSP_SET_FREQUENCY, 44100);
1227 /* Sample depth is 28 bit host endian */
1228 ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
1229 /* Stereo output */
1230 ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED);
1231 }
1232
1233 return CODEC_OK;
1234}
1221 1235
1222enum codec_status codec_main(void) 1236/* this is called for each file to process */
1237enum codec_status codec_run(void)
1223{ 1238{
1224 size_t n; 1239 size_t n;
1225 unsigned char *modfile; 1240 unsigned char *modfile;
1226 int old_patterntableposition; 1241 int old_patterntableposition;
1227
1228 int bytesdone; 1242 int bytesdone;
1243 intptr_t param;
1229 1244
1230next_track:
1231 if (codec_init()) { 1245 if (codec_init()) {
1232 return CODEC_ERROR; 1246 return CODEC_ERROR;
1233 } 1247 }
1234 1248
1235 if (codec_wait_taginfo() != 0)
1236 goto request_next_track;
1237
1238 codec_set_replaygain(ci->id3); 1249 codec_set_replaygain(ci->id3);
1239 1250
1240 /* Load MOD file */ 1251 /* Load MOD file */
1241 /*
1242 * This is the save way
1243
1244 size_t bytesfree;
1245 unsigned int filesize;
1246
1247 p = modfile;
1248 bytesfree=sizeof(modfile);
1249 while ((n = ci->read_filebuf(p, bytesfree)) > 0) {
1250 p += n;
1251 bytesfree -= n;
1252 if (bytesfree == 0)
1253 return CODEC_ERROR;
1254 }
1255 filesize = p-modfile;
1256
1257 if (filesize == 0)
1258 return CODEC_ERROR;
1259 */
1260
1261 /* Directly use mod in buffer */
1262 ci->seek_buffer(0); 1252 ci->seek_buffer(0);
1263 modfile = ci->request_buffer(&n, ci->filesize); 1253 modfile = ci->request_buffer(&n, ci->filesize);
1264 if (!modfile || n < (size_t)ci->filesize) { 1254 if (!modfile || n < (size_t)ci->filesize) {
@@ -1268,27 +1258,22 @@ next_track:
1268 initmodplayer(); 1258 initmodplayer();
1269 loadmod(modfile); 1259 loadmod(modfile);
1270 1260
1271 /* Make use of 44.1khz */
1272 ci->configure(DSP_SET_FREQUENCY, 44100);
1273 /* Sample depth is 28 bit host endian */
1274 ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
1275 /* Stereo output */
1276 ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED);
1277
1278 /* The main decoder loop */ 1261 /* The main decoder loop */
1279 ci->set_elapsed(0); 1262 ci->set_elapsed(0);
1280 bytesdone = 0; 1263 bytesdone = 0;
1281 old_patterntableposition = 0; 1264 old_patterntableposition = 0;
1282 1265
1283 while (1) { 1266 while (1) {
1284 ci->yield(); 1267 enum codec_command_action action = ci->get_command(&param);
1285 if (ci->stop_codec || ci->new_track) 1268
1269 if (action == CODEC_ACTION_HALT)
1286 break; 1270 break;
1287 1271
1288 if (ci->seek_time) { 1272 if (action == CODEC_ACTION_SEEK_TIME) {
1289 /* New time is ready in ci->seek_time */ 1273 /* New time is ready in param */
1290 modplayer.patterntableposition = ci->seek_time/1000; 1274 modplayer.patterntableposition = param/1000;
1291 modplayer.currentline = 0; 1275 modplayer.currentline = 0;
1276 ci->set_elapsed(modplayer.patterntableposition*1000+500);
1292 ci->seek_complete(); 1277 ci->seek_complete();
1293 } 1278 }
1294 1279
@@ -1305,9 +1290,5 @@ next_track:
1305 1290
1306 } 1291 }
1307 1292
1308request_next_track:
1309 if (ci->request_next_track())
1310 goto next_track;
1311
1312 return CODEC_OK; 1293 return CODEC_OK;
1313} 1294}
diff --git a/apps/codecs/mp3_enc.c b/apps/codecs/mp3_enc.c
index e7893fd14a..2f5528f74c 100644
--- a/apps/codecs/mp3_enc.c
+++ b/apps/codecs/mp3_enc.c
@@ -2584,45 +2584,46 @@ static bool enc_init(void)
2584 return true; 2584 return true;
2585} /* enc_init */ 2585} /* enc_init */
2586 2586
2587enum codec_status codec_main(void) 2587/* this is the codec entry point */
2588enum codec_status codec_main(enum codec_entry_call_reason reason)
2588{ 2589{
2589 /* Generic codec initialisation */ 2590 if (reason == CODEC_LOAD) {
2590 if (!enc_init()) 2591 if (!enc_init())
2591 return CODEC_ERROR; 2592 return CODEC_ERROR;
2593 }
2594 else if (reason == CODEC_UNLOAD) {
2595 /* reset parameters to initial state */
2596 ci->enc_set_parameters(NULL);
2597 }
2598
2599 return CODEC_OK;
2600}
2592 2601
2602/* this is called for each file to process */
2603enum codec_status codec_run(void)
2604{
2593 /* main encoding loop */ 2605 /* main encoding loop */
2594 while (!ci->stop_codec) 2606 while(ci->get_command(NULL) != CODEC_ACTION_HALT)
2595 { 2607 {
2596 char *buffer; 2608 char *buffer = buffer = ci->enc_get_pcm_data(pcm_chunk_size);
2597 2609 struct enc_chunk_hdr *chunk;
2598 while ((buffer = ci->enc_get_pcm_data(pcm_chunk_size)) != NULL)
2599 {
2600 struct enc_chunk_hdr *chunk;
2601
2602 if (ci->stop_codec)
2603 break;
2604 2610
2605 chunk = ci->enc_get_chunk(); 2611 if(buffer == NULL)
2606 chunk->enc_data = ENC_CHUNK_SKIP_HDR(chunk->enc_data, chunk); 2612 continue;
2607 2613
2608 encode_frame(buffer, chunk); 2614 chunk = ci->enc_get_chunk();
2615 chunk->enc_data = ENC_CHUNK_SKIP_HDR(chunk->enc_data, chunk);
2609 2616
2610 if (chunk->num_pcm < samp_per_frame) 2617 encode_frame(buffer, chunk);
2611 {
2612 ci->enc_unget_pcm_data(pcm_chunk_size - chunk->num_pcm*4);
2613 chunk->num_pcm = samp_per_frame;
2614 }
2615 2618
2616 ci->enc_finish_chunk(); 2619 if (chunk->num_pcm < samp_per_frame)
2617 2620 {
2618 ci->yield(); 2621 ci->enc_unget_pcm_data(pcm_chunk_size - chunk->num_pcm*4);
2622 chunk->num_pcm = samp_per_frame;
2619 } 2623 }
2620 2624
2621 ci->yield(); 2625 ci->enc_finish_chunk();
2622 } 2626 }
2623 2627
2624 /* reset parameters to initial state */
2625 ci->enc_set_parameters(NULL);
2626
2627 return CODEC_OK; 2628 return CODEC_OK;
2628} /* codec_start */ 2629}
diff --git a/apps/codecs/mpa.c b/apps/codecs/mpa.c
index 4b49775029..c9e2131450 100644
--- a/apps/codecs/mpa.c
+++ b/apps/codecs/mpa.c
@@ -268,8 +268,8 @@ static bool mad_synth_thread_create(void)
268 268
269static void mad_synth_thread_quit(void) 269static void mad_synth_thread_quit(void)
270{ 270{
271 /*mop up COP thread*/ 271 /* mop up COP thread */
272 die=1; 272 die = 1;
273 ci->semaphore_release(&synth_pending_sem); 273 ci->semaphore_release(&synth_pending_sem);
274 ci->thread_wait(mad_synth_thread_id); 274 ci->thread_wait(mad_synth_thread_id);
275 ci->cpucache_invalidate(); 275 ci->cpucache_invalidate();
@@ -299,9 +299,30 @@ static inline void mad_synth_thread_unwait_pcm(void)
299#endif /* MPA_SYNTH_ON_COP */ 299#endif /* MPA_SYNTH_ON_COP */
300 300
301/* this is the codec entry point */ 301/* this is the codec entry point */
302enum codec_status codec_main(void) 302enum codec_status codec_main(enum codec_entry_call_reason reason)
303{
304 if (reason == CODEC_LOAD) {
305 /* Create a decoder instance */
306 if (codec_init())
307 return CODEC_ERROR;
308
309 ci->configure(DSP_SET_SAMPLE_DEPTH, MAD_F_FRACBITS);
310
311 /* does nothing on 1 processor systems except return true */
312 if(!mad_synth_thread_create())
313 return CODEC_ERROR;
314 }
315 else if (reason == CODEC_UNLOAD) {
316 /* mop up COP thread - MT only */
317 mad_synth_thread_quit();
318 }
319
320 return CODEC_OK;
321}
322
323/* this is called for each file to process */
324enum codec_status codec_run(void)
303{ 325{
304 int status;
305 size_t size; 326 size_t size;
306 int file_end; 327 int file_end;
307 int samples_to_skip; /* samples to skip in total for this file (at start) */ 328 int samples_to_skip; /* samples to skip in total for this file (at start) */
@@ -312,27 +333,12 @@ enum codec_status codec_main(void)
312 unsigned long current_frequency = 0; 333 unsigned long current_frequency = 0;
313 int framelength; 334 int framelength;
314 int padding = MAD_BUFFER_GUARD; /* to help mad decode the last frame */ 335 int padding = MAD_BUFFER_GUARD; /* to help mad decode the last frame */
315 336 intptr_t param;
316 if (codec_init())
317 return CODEC_ERROR;
318
319 /* Create a decoder instance */
320
321 ci->configure(DSP_SET_SAMPLE_DEPTH, MAD_F_FRACBITS);
322
323 /*does nothing on 1 processor systems except return true*/
324 if(!mad_synth_thread_create())
325 return CODEC_ERROR;
326
327next_track:
328 status = CODEC_OK;
329 337
330 /* Reinitializing seems to be necessary to avoid playback quircks when seeking. */ 338 /* Reinitializing seems to be necessary to avoid playback quircks when seeking. */
331 init_mad(); 339 init_mad();
332 340
333 file_end = 0; 341 file_end = 0;
334 if (codec_wait_taginfo() != 0)
335 goto request_next_track;
336 342
337 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); 343 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
338 current_frequency = ci->id3->frequency; 344 current_frequency = ci->id3->frequency;
@@ -379,29 +385,35 @@ next_track:
379 385
380 /* This is the decoding loop. */ 386 /* This is the decoding loop. */
381 while (1) { 387 while (1) {
382 ci->yield(); 388 enum codec_command_action action = ci->get_command(&param);
383 if (ci->stop_codec || ci->new_track) 389
390 if (action == CODEC_ACTION_HALT)
384 break; 391 break;
385 392
386 if (ci->seek_time) { 393 if (action == CODEC_ACTION_SEEK_TIME) {
387 int newpos; 394 int newpos;
388 395
389 /*make sure the synth thread is idle before seeking - MT only*/ 396 /*make sure the synth thread is idle before seeking - MT only*/
390 mad_synth_thread_wait_pcm(); 397 mad_synth_thread_wait_pcm();
391 mad_synth_thread_unwait_pcm(); 398 mad_synth_thread_unwait_pcm();
392 399
393 samplesdone = ((int64_t)(ci->seek_time-1))*current_frequency/1000; 400 samplesdone = ((int64_t)param)*current_frequency/1000;
394 401
395 if (ci->seek_time-1 == 0) { 402 if (param == 0) {
396 newpos = ci->id3->first_frame_offset; 403 newpos = ci->id3->first_frame_offset;
397 samples_to_skip = start_skip; 404 samples_to_skip = start_skip;
398 } else { 405 } else {
399 newpos = get_file_pos(ci->seek_time-1); 406 newpos = get_file_pos(param);
400 samples_to_skip = 0; 407 samples_to_skip = 0;
401 } 408 }
402 409
403 if (!ci->seek_buffer(newpos)) 410 if (!ci->seek_buffer(newpos))
411 {
412 ci->seek_complete();
404 break; 413 break;
414 }
415
416 ci->set_elapsed((samplesdone * 1000) / current_frequency);
405 ci->seek_complete(); 417 ci->seek_complete();
406 init_mad(); 418 init_mad();
407 framelength = 0; 419 framelength = 0;
@@ -435,8 +447,7 @@ next_track:
435 continue; 447 continue;
436 } else { 448 } else {
437 /* Some other unrecoverable error */ 449 /* Some other unrecoverable error */
438 status = CODEC_ERROR; 450 return CODEC_ERROR;
439 break;
440 } 451 }
441 } 452 }
442 453
@@ -504,12 +515,5 @@ next_track:
504 framelength - stop_skip); 515 framelength - stop_skip);
505 } 516 }
506 517
507request_next_track: 518 return CODEC_OK;
508 if (ci->request_next_track())
509 goto next_track;
510
511 /*mop up COP thread - MT only*/
512 mad_synth_thread_quit();
513
514 return status;
515} 519}
diff --git a/apps/codecs/mpc.c b/apps/codecs/mpc.c
index 187c37e597..bbe2d9943b 100644
--- a/apps/codecs/mpc.c
+++ b/apps/codecs/mpc.c
@@ -52,8 +52,20 @@ static mpc_int32_t get_size_impl(mpc_reader *reader)
52 return ci->filesize; 52 return ci->filesize;
53} 53}
54 54
55/* This is the codec entry point. */ 55/* this is the codec entry point */
56enum codec_status codec_main(void) 56enum codec_status codec_main(enum codec_entry_call_reason reason)
57{
58 if (reason == CODEC_LOAD) {
59 /* musepack's sample representation is 18.14
60 * DSP_SET_SAMPLE_DEPTH = 14 (FRACT) + 16 (NATIVE) - 1 (SIGN) = 29 */
61 ci->configure(DSP_SET_SAMPLE_DEPTH, 29);
62 }
63
64 return CODEC_OK;
65}
66
67/* this is called for each file to process */
68enum codec_status codec_run(void)
57{ 69{
58 mpc_int64_t samplesdone; 70 mpc_int64_t samplesdone;
59 uint32_t frequency; /* 0.1 kHz accuracy */ 71 uint32_t frequency; /* 0.1 kHz accuracy */
@@ -64,39 +76,27 @@ enum codec_status codec_main(void)
64 mpc_streaminfo info; 76 mpc_streaminfo info;
65 mpc_frame_info frame; 77 mpc_frame_info frame;
66 mpc_demux *demux = NULL; 78 mpc_demux *demux = NULL;
67 int retval; 79 intptr_t param;
68 80
69 frame.buffer = sample_buffer; 81 frame.buffer = sample_buffer;
70 82
71 /* musepack's sample representation is 18.14
72 * DSP_SET_SAMPLE_DEPTH = 14 (FRACT) + 16 (NATIVE) - 1 (SIGN) = 29 */
73 ci->configure(DSP_SET_SAMPLE_DEPTH, 29);
74
75 /* Create a decoder instance */ 83 /* Create a decoder instance */
76 reader.read = read_impl; 84 reader.read = read_impl;
77 reader.seek = seek_impl; 85 reader.seek = seek_impl;
78 reader.tell = tell_impl; 86 reader.tell = tell_impl;
79 reader.get_size = get_size_impl; 87 reader.get_size = get_size_impl;
80 88
81next_track:
82 retval = CODEC_OK;
83
84 if (codec_init()) 89 if (codec_init())
85 { 90 return CODEC_ERROR;
86 retval = CODEC_ERROR;
87 goto exit;
88 }
89 91
90 if (codec_wait_taginfo() != 0) 92 /* Prep position */
91 goto done; 93 ci->seek_buffer(0);
92 94
93 /* Initialize demux/decoder. */ 95 /* Initialize demux/decoder. */
94 demux = mpc_demux_init(&reader); 96 demux = mpc_demux_init(&reader);
95 if (NULL == demux) 97 if (NULL == demux)
96 { 98 return CODEC_ERROR;
97 retval = CODEC_ERROR; 99
98 goto done;
99 }
100 /* Read file's streaminfo data. */ 100 /* Read file's streaminfo data. */
101 mpc_demux_get_info(demux, &info); 101 mpc_demux_get_info(demux, &info);
102 102
@@ -117,11 +117,8 @@ next_track:
117 ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED); 117 ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
118 else if (info.channels == 1) 118 else if (info.channels == 1)
119 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); 119 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
120 else 120 else
121 { 121 return CODEC_ERROR;
122 retval = CODEC_ERROR;
123 goto done;
124 }
125 122
126 codec_set_replaygain(ci->id3); 123 codec_set_replaygain(ci->id3);
127 124
@@ -142,21 +139,24 @@ next_track:
142 /* This is the decoding loop. */ 139 /* This is the decoding loop. */
143 do 140 do
144 { 141 {
142 enum codec_command_action action = ci->get_command(&param);
143
144 if (action == CODEC_ACTION_HALT)
145 return CODEC_OK;
146
145 /* Complete seek handler. */ 147 /* Complete seek handler. */
146 if (ci->seek_time) 148 if (action == CODEC_ACTION_SEEK_TIME)
147 { 149 {
148 mpc_int64_t new_offset = ((ci->seek_time - 1)/10)*frequency; 150 mpc_int64_t new_offset = (param/10)*frequency;
149 if (mpc_demux_seek_sample(demux, new_offset) == MPC_STATUS_OK) 151 if (mpc_demux_seek_sample(demux, new_offset) == MPC_STATUS_OK)
150 { 152 {
151 samplesdone = new_offset; 153 samplesdone = new_offset;
152 ci->set_elapsed(ci->seek_time);
153 } 154 }
155
156 elapsed_time = (samplesdone*10)/frequency;
157 ci->set_elapsed(elapsed_time);
154 ci->seek_complete(); 158 ci->seek_complete();
155 } 159 }
156
157 /* Stop or skip occured, exit decoding loop. */
158 if (ci->stop_codec || ci->new_track)
159 break;
160 160
161 /* Decode one frame. */ 161 /* Decode one frame. */
162 status = mpc_demux_decode(demux, &frame); 162 status = mpc_demux_decode(demux, &frame);
@@ -164,8 +164,7 @@ next_track:
164 if (frame.bits == -1) 164 if (frame.bits == -1)
165 { 165 {
166 /* Decoding error, exit decoding loop. */ 166 /* Decoding error, exit decoding loop. */
167 retval = (status == MPC_STATUS_OK) ? CODEC_OK : CODEC_ERROR; 167 return (status == MPC_STATUS_OK) ? CODEC_OK : CODEC_ERROR;
168 goto done;
169 } 168 }
170 else 169 else
171 { 170 {
@@ -181,11 +180,4 @@ next_track:
181 ci->set_offset( (samplesdone * byterate)/(frequency*100) ); 180 ci->set_offset( (samplesdone * byterate)/(frequency*100) );
182 } 181 }
183 } while (true); 182 } while (true);
184
185done:
186 if (ci->request_next_track())
187 goto next_track;
188
189exit:
190 return retval;
191} 183}
diff --git a/apps/codecs/nsf.c b/apps/codecs/nsf.c
index 2f37da81d2..72f6974214 100644
--- a/apps/codecs/nsf.c
+++ b/apps/codecs/nsf.c
@@ -4307,46 +4307,44 @@ static void set_codec_track(int t, int d) {
4307 nSilenceTrackMS=5000; 4307 nSilenceTrackMS=5000;
4308 SetFadeTime(track,track+fade, fNSFPlaybackSpeed,def); 4308 SetFadeTime(track,track+fade, fNSFPlaybackSpeed,def);
4309 } 4309 }
4310 ci->id3->elapsed=d*1000; /* d is track no to display */ 4310 ci->set_elapsed(d*1000); /* d is track no to display */
4311} 4311}
4312 4312
4313/** Operational info **/
4314static int track = 0;
4315static char last_path[MAX_PATH];
4316static int dontresettrack = 0;
4317
4313/* this is the codec entry point */ 4318/* this is the codec entry point */
4314enum codec_status codec_main(void) 4319enum codec_status codec_main(enum codec_entry_call_reason reason)
4320{
4321 if (reason == CODEC_LOAD) {
4322 /* we only render 16 bits, 44.1KHz, Stereo */
4323 ci->configure(DSP_SET_SAMPLE_DEPTH, 16);
4324 ci->configure(DSP_SET_FREQUENCY, 44100);
4325 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
4326
4327 RebuildOutputTables();
4328 }
4329
4330 return CODEC_OK;
4331}
4332
4333/* this is called for each file to process */
4334enum codec_status codec_run(void)
4315{ 4335{
4316 int written; 4336 int written;
4317 uint8_t *buf; 4337 uint8_t *buf;
4318 size_t n; 4338 size_t n;
4319 int endofstream; /* end of stream flag */ 4339 int endofstream; /* end of stream flag */
4320 int track; 4340 int usingplaylist = 0;
4321 int dontresettrack;
4322 char last_path[MAX_PATH];
4323 int usingplaylist;
4324
4325 /* we only render 16 bits */
4326 ci->configure(DSP_SET_SAMPLE_DEPTH, 16);
4327
4328 ci->configure(DSP_SET_FREQUENCY, 44100);
4329 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
4330
4331 RebuildOutputTables();
4332
4333 dontresettrack=0;
4334 last_path[0]='\0';
4335 track=0;
4336 4341
4337next_track:
4338 usingplaylist=0;
4339 DEBUGF("NSF: next_track\n"); 4342 DEBUGF("NSF: next_track\n");
4340 if (codec_init()) { 4343 if (codec_init()) {
4341 return CODEC_ERROR; 4344 return CODEC_ERROR;
4342 } 4345 }
4343 DEBUGF("NSF: after init\n"); 4346 DEBUGF("NSF: after init\n");
4344 4347
4345
4346 /* wait for track info to load */
4347 if (codec_wait_taginfo() != 0)
4348 goto request_next_track;
4349
4350 codec_set_replaygain(ci->id3); 4348 codec_set_replaygain(ci->id3);
4351 4349
4352 /* Read the entire file */ 4350 /* Read the entire file */
@@ -4408,22 +4406,27 @@ init_nsf:
4408 reset_profile_timers(); 4406 reset_profile_timers();
4409 4407
4410 while (!endofstream) { 4408 while (!endofstream) {
4409 intptr_t param;
4410 enum codec_command_action action = ci->get_command(&param);
4411 4411
4412 ci->yield(); 4412 if (action == CODEC_ACTION_HALT)
4413 if (ci->stop_codec || ci->new_track) {
4414 break; 4413 break;
4415 }
4416 4414
4417 if (ci->seek_time >0) { 4415 if (action == CODEC_ACTION_SEEK_TIME) {
4418 track=ci->seek_time/1000; 4416 if (param > 0) {
4419 if (usingplaylist) { 4417 track=param/1000;
4420 if (track>=nPlaylistSize) break; 4418 if (usingplaylist) {
4421 } else { 4419 if (track>=nPlaylistSize) break;
4422 if (track>=nTrackCount) break; 4420 } else {
4421 if (track>=nTrackCount) break;
4422 }
4423 dontresettrack=1;
4424 ci->seek_complete();
4425 goto init_nsf;
4426 }
4427 else {
4428 ci->seek_complete();
4423 } 4429 }
4424 ci->seek_complete();
4425 dontresettrack=1;
4426 goto init_nsf;
4427 } 4430 }
4428 4431
4429 ENTER_TIMER(total); 4432 ENTER_TIMER(total);
@@ -4449,22 +4452,17 @@ init_nsf:
4449 4452
4450 print_timers(last_path,track); 4453 print_timers(last_path,track);
4451 4454
4452request_next_track:
4453 if (ci->request_next_track()) {
4454 if (ci->global_settings->repeat_mode==REPEAT_ONE) { 4455 if (ci->global_settings->repeat_mode==REPEAT_ONE) {
4455 /* in repeat one mode just advance to the next track */ 4456 /* in repeat one mode just advance to the next track */
4456 track++; 4457 track++;
4457 if (track>=nTrackCount) track=0; 4458 if (track>=nTrackCount) track=0;
4458 dontresettrack=1; 4459 dontresettrack=1;
4459 /* at this point we can't tell if another file has been selected */ 4460 /* at this point we can't tell if another file has been selected */
4460 goto next_track;
4461 } else { 4461 } else {
4462 /* otherwise do a proper load of the next file */ 4462 /* otherwise do a proper load of the next file */
4463 dontresettrack=0; 4463 dontresettrack=0;
4464 last_path[0]='\0'; 4464 last_path[0]='\0';
4465 } 4465 }
4466 goto next_track; /* when we fall through here we'll reload the file */
4467 }
4468 4466
4469 return CODEC_OK; 4467 return CODEC_OK;
4470} 4468}
diff --git a/apps/codecs/raac.c b/apps/codecs/raac.c
index b322ae7df3..4b73f41462 100644
--- a/apps/codecs/raac.c
+++ b/apps/codecs/raac.c
@@ -35,8 +35,21 @@ static void init_rm(RMContext *rmctx)
35 35
36static RMContext rmctx; 36static RMContext rmctx;
37static RMPacket pkt; 37static RMPacket pkt;
38
38/* this is the codec entry point */ 39/* this is the codec entry point */
39enum codec_status codec_main(void) 40enum codec_status codec_main(enum codec_entry_call_reason reason)
41{
42 if (reason == CODEC_LOAD) {
43 /* Generic codec initialisation */
44 ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
45 ci->configure(DSP_SET_SAMPLE_DEPTH, 29);
46 }
47
48 return CODEC_OK;
49}
50
51/* this is called for each file to process */
52enum codec_status codec_run(void)
40{ 53{
41 static NeAACDecFrameInfo frame_info; 54 static NeAACDecFrameInfo frame_info;
42 NeAACDecHandle decoder; 55 NeAACDecHandle decoder;
@@ -49,26 +62,21 @@ enum codec_status codec_main(void)
49 unsigned char c = 0; /* channels */ 62 unsigned char c = 0; /* channels */
50 int playback_on = -1; 63 int playback_on = -1;
51 size_t resume_offset; 64 size_t resume_offset;
52 65 intptr_t param;
53 /* Generic codec initialisation */ 66 enum codec_command_action action = CODEC_ACTION_NULL;
54 ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
55 ci->configure(DSP_SET_SAMPLE_DEPTH, 29);
56
57next_track:
58 err = CODEC_OK;
59 67
60 if (codec_init()) { 68 if (codec_init()) {
61 DEBUGF("FAAD: Codec init error\n"); 69 DEBUGF("FAAD: Codec init error\n");
62 return CODEC_ERROR; 70 return CODEC_ERROR;
63 } 71 }
64 72
65 if (codec_wait_taginfo() != 0)
66 goto done;
67
68 resume_offset = ci->id3->offset; 73 resume_offset = ci->id3->offset;
69 74
70 ci->memset(&rmctx,0,sizeof(RMContext)); 75 ci->memset(&rmctx,0,sizeof(RMContext));
71 ci->memset(&pkt,0,sizeof(RMPacket)); 76 ci->memset(&pkt,0,sizeof(RMPacket));
77
78 ci->seek_buffer(0);
79
72 init_rm(&rmctx); 80 init_rm(&rmctx);
73 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); 81 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
74 codec_set_replaygain(ci->id3); 82 codec_set_replaygain(ci->id3);
@@ -78,9 +86,9 @@ next_track:
78 86
79 if (!decoder) { 87 if (!decoder) {
80 DEBUGF("FAAD: Decode open error\n"); 88 DEBUGF("FAAD: Decode open error\n");
81 err = CODEC_ERROR; 89 return CODEC_ERROR;
82 goto done; 90 }
83 } 91
84 NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(decoder); 92 NeAACDecConfigurationPtr conf = NeAACDecGetCurrentConfiguration(decoder);
85 conf->outputFormat = FAAD_FMT_16BIT; /* irrelevant, we don't convert */ 93 conf->outputFormat = FAAD_FMT_16BIT; /* irrelevant, we don't convert */
86 NeAACDecSetConfiguration(decoder, conf); 94 NeAACDecSetConfiguration(decoder, conf);
@@ -91,8 +99,7 @@ next_track:
91 99
92 if (err) { 100 if (err) {
93 DEBUGF("FAAD: DecInit: %d, %d\n", err, decoder->object_type); 101 DEBUGF("FAAD: DecInit: %d, %d\n", err, decoder->object_type);
94 err = CODEC_ERROR; 102 return CODEC_ERROR;
95 goto done;
96 } 103 }
97 104
98 /* check for a mid-track resume and force a seek time accordingly */ 105 /* check for a mid-track resume and force a seek time accordingly */
@@ -100,36 +107,38 @@ next_track:
100 resume_offset -= rmctx.data_offset + DATA_HEADER_SIZE; 107 resume_offset -= rmctx.data_offset + DATA_HEADER_SIZE;
101 /* put number of subpackets to skip in resume_offset */ 108 /* put number of subpackets to skip in resume_offset */
102 resume_offset /= (rmctx.block_align + PACKET_HEADER_SIZE); 109 resume_offset /= (rmctx.block_align + PACKET_HEADER_SIZE);
103 ci->seek_time = (int)resume_offset * ((rmctx.block_align * 8 * 1000)/rmctx.bit_rate); 110 param = (int)resume_offset * ((rmctx.block_align * 8 * 1000)/rmctx.bit_rate);
111 action = CODEC_ACTION_SEEK_TIME;
104 } 112 }
105 113
106 ci->id3->frequency = s; 114 ci->id3->frequency = s; /* FIXME: Won't get it to the UI */
107 ci->set_elapsed(0); 115 ci->set_elapsed(0);
108 ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE); 116 ci->advance_buffer(rmctx.data_offset + DATA_HEADER_SIZE);
109 117
110 /* The main decoding loop */ 118 /* The main decoding loop */
111seek_start:
112 while (1) { 119 while (1) {
113 ci->yield(); 120 if (action == CODEC_ACTION_NULL)
114 if (ci->stop_codec || ci->new_track) { 121 action = ci->get_command(&param);
122
123 if (action == CODEC_ACTION_HALT)
115 break; 124 break;
116 }
117 125
118 if (ci->seek_time) { 126 if (action == CODEC_ACTION_SEEK_TIME) {
119
120 /* Do not allow seeking beyond the file's length */ 127 /* Do not allow seeking beyond the file's length */
121 if ((unsigned) ci->seek_time > ci->id3->length) { 128 if ((unsigned) param > ci->id3->length) {
129 ci->set_elapsed(ci->id3->length);
122 ci->seek_complete(); 130 ci->seek_complete();
123 goto done; 131 break;
124 } 132 }
125 133
126 ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE); 134 ci->seek_buffer(rmctx.data_offset + DATA_HEADER_SIZE);
127 135
128 /* Seek to the start of the track */ 136 /* Seek to the start of the track */
129 if (ci->seek_time == 1) { 137 if (param == 0) {
130 ci->set_elapsed(0); 138 ci->set_elapsed(0);
131 ci->seek_complete(); 139 ci->seek_complete();
132 goto seek_start; 140 action = CODEC_ACTION_NULL;
141 continue;
133 } 142 }
134 143
135 skipped = 0; 144 skipped = 0;
@@ -141,21 +150,30 @@ seek_start:
141 if(playback_on == -1) { 150 if(playback_on == -1) {
142 /* Error only if packet-parsing failed and playback hadn't started */ 151 /* Error only if packet-parsing failed and playback hadn't started */
143 DEBUGF("rm_get_packet failed\n"); 152 DEBUGF("rm_get_packet failed\n");
153 ci->seek_complete();
144 return CODEC_ERROR; 154 return CODEC_ERROR;
145 } 155 }
146 else 156 else {
147 goto done; 157 ci->seek_complete();
158 return CODEC_OK;
159 }
148 } 160 }
149 skipped += pkt.length; 161 skipped += pkt.length;
150 if(pkt.timestamp > (unsigned)ci->seek_time) break; 162
163 if(pkt.timestamp > (unsigned)param)
164 break;
165
151 ci->advance_buffer(pkt.length); 166 ci->advance_buffer(pkt.length);
152 } 167 }
153 ci->seek_buffer(pkt_offset + rmctx.data_offset + DATA_HEADER_SIZE); 168 ci->seek_buffer(pkt_offset + rmctx.data_offset + DATA_HEADER_SIZE);
154 buffer = ci->request_buffer(&n,rmctx.audio_framesize + 1000); 169 buffer = ci->request_buffer(&n,rmctx.audio_framesize + 1000);
155 NeAACDecPostSeekReset(decoder, decoder->frame); 170 NeAACDecPostSeekReset(decoder, decoder->frame);
171 ci->set_elapsed(pkt.timestamp);
156 ci->seek_complete(); 172 ci->seek_complete();
157 } 173 }
158 174
175 action = CODEC_ACTION_NULL;
176
159 /* Request the required number of bytes from the input buffer */ 177 /* Request the required number of bytes from the input buffer */
160 buffer=ci->request_buffer(&n,rmctx.audio_framesize + 1000); 178 buffer=ci->request_buffer(&n,rmctx.audio_framesize + 1000);
161 consumed = rm_get_packet(&buffer, &rmctx, &pkt); 179 consumed = rm_get_packet(&buffer, &rmctx, &pkt);
@@ -167,20 +185,20 @@ seek_start:
167 return CODEC_ERROR; 185 return CODEC_ERROR;
168 } 186 }
169 else 187 else
170 goto done; 188 break;
171 } 189 }
172 190
173 playback_on = 1; 191 playback_on = 1;
174 if (pkt.timestamp >= ci->id3->length) 192 if (pkt.timestamp >= ci->id3->length)
175 goto done; 193 break;
194
176 /* Decode one block - returned samples will be host-endian */ 195 /* Decode one block - returned samples will be host-endian */
177 for(i = 0; i < rmctx.sub_packet_cnt; i++) { 196 for(i = 0; i < rmctx.sub_packet_cnt; i++) {
178 ret = NeAACDecDecode(decoder, &frame_info, buffer, rmctx.sub_packet_lengths[i]); 197 ret = NeAACDecDecode(decoder, &frame_info, buffer, rmctx.sub_packet_lengths[i]);
179 buffer += rmctx.sub_packet_lengths[i]; 198 buffer += rmctx.sub_packet_lengths[i];
180 if (frame_info.error > 0) { 199 if (frame_info.error > 0) {
181 DEBUGF("FAAD: decode error '%s'\n", NeAACDecGetErrorMessage(frame_info.error)); 200 DEBUGF("FAAD: decode error '%s'\n", NeAACDecGetErrorMessage(frame_info.error));
182 err = CODEC_ERROR; 201 return CODEC_ERROR;
183 goto exit;
184 } 202 }
185 ci->pcmbuf_insert(decoder->time_out[0], 203 ci->pcmbuf_insert(decoder->time_out[0],
186 decoder->time_out[1], 204 decoder->time_out[1],
@@ -191,11 +209,5 @@ seek_start:
191 ci->advance_buffer(pkt.length); 209 ci->advance_buffer(pkt.length);
192 } 210 }
193 211
194done: 212 return CODEC_OK;
195 if (ci->request_next_track())
196 goto next_track;
197
198exit:
199 return err;
200} 213}
201
diff --git a/apps/codecs/shorten.c b/apps/codecs/shorten.c
index 83a9c34da8..db66991679 100644
--- a/apps/codecs/shorten.c
+++ b/apps/codecs/shorten.c
@@ -37,7 +37,19 @@ static int32_t offset1[MAX_OFFSET_SIZE] IBSS_ATTR;
37static int8_t ibuf[MAX_BUFFER_SIZE] IBSS_ATTR; 37static int8_t ibuf[MAX_BUFFER_SIZE] IBSS_ATTR;
38 38
39/* this is the codec entry point */ 39/* this is the codec entry point */
40enum codec_status codec_main(void) 40enum codec_status codec_main(enum codec_entry_call_reason reason)
41{
42 if (reason == CODEC_LOAD) {
43 /* Generic codec initialisation */
44 ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
45 ci->configure(DSP_SET_SAMPLE_DEPTH, SHN_OUTPUT_DEPTH-1);
46 }
47
48 return CODEC_OK;
49}
50
51/* this is called for each file to process */
52enum codec_status codec_run(void)
41{ 53{
42 ShortenContext sc; 54 ShortenContext sc;
43 uint32_t samplesdone; 55 uint32_t samplesdone;
@@ -45,21 +57,14 @@ enum codec_status codec_main(void)
45 int8_t *buf; 57 int8_t *buf;
46 int consumed, res, nsamples; 58 int consumed, res, nsamples;
47 size_t bytesleft; 59 size_t bytesleft;
60 intptr_t param;
48 61
49 /* Generic codec initialisation */
50 ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
51 ci->configure(DSP_SET_SAMPLE_DEPTH, SHN_OUTPUT_DEPTH-1);
52
53next_track:
54 /* Codec initialization */ 62 /* Codec initialization */
55 if (codec_init()) { 63 if (codec_init()) {
56 LOGF("Shorten: codec_init error\n"); 64 LOGF("Shorten: codec_init error\n");
57 return CODEC_ERROR; 65 return CODEC_ERROR;
58 } 66 }
59 67
60 if (codec_wait_taginfo() != 0)
61 goto request_next_track;
62
63 codec_set_replaygain(ci->id3); 68 codec_set_replaygain(ci->id3);
64 69
65 /* Shorten decoder initialization */ 70 /* Shorten decoder initialization */
@@ -103,14 +108,15 @@ seek_start:
103 samplesdone = 0; 108 samplesdone = 0;
104 buf = ci->request_buffer(&bytesleft, MAX_BUFFER_SIZE); 109 buf = ci->request_buffer(&bytesleft, MAX_BUFFER_SIZE);
105 while (bytesleft) { 110 while (bytesleft) {
106 ci->yield(); 111 enum codec_command_action action = ci->get_command(&param);
107 if (ci->stop_codec || ci->new_track) { 112
113 if (action == CODEC_ACTION_HALT)
108 break; 114 break;
109 }
110 115
111 /* Seek to start of track */ 116 /* Seek to start of track */
112 if (ci->seek_time == 1) { 117 if (action == CODEC_ACTION_SEEK_TIME) {
113 if (ci->seek_buffer(sc.header_bits/8 + ci->id3->first_frame_offset)) { 118 if (param == 0 &&
119 ci->seek_buffer(sc.header_bits/8 + ci->id3->first_frame_offset)) {
114 sc.bitindex = sc.header_bits - 8*(sc.header_bits/8); 120 sc.bitindex = sc.header_bits - 8*(sc.header_bits/8);
115 ci->set_elapsed(0); 121 ci->set_elapsed(0);
116 ci->seek_complete(); 122 ci->seek_complete();
@@ -128,7 +134,7 @@ seek_start:
128 if (res == FN_ERROR) { 134 if (res == FN_ERROR) {
129 LOGF("Shorten: shorten_decode_frames error (%lu)\n", 135 LOGF("Shorten: shorten_decode_frames error (%lu)\n",
130 (unsigned long)samplesdone); 136 (unsigned long)samplesdone);
131 break; 137 return CODEC_ERROR;
132 } else { 138 } else {
133 /* Insert decoded samples in pcmbuf */ 139 /* Insert decoded samples in pcmbuf */
134 if (nsamples) { 140 if (nsamples) {
@@ -153,9 +159,5 @@ seek_start:
153 sc.bitindex = sc.gb.index - 8*consumed; 159 sc.bitindex = sc.gb.index - 8*consumed;
154 } 160 }
155 161
156request_next_track:
157 if (ci->request_next_track())
158 goto next_track;
159
160 return CODEC_OK; 162 return CODEC_OK;
161} 163}
diff --git a/apps/codecs/sid.c b/apps/codecs/sid.c
index 52c1289fff..0edbabe0b6 100644
--- a/apps/codecs/sid.c
+++ b/apps/codecs/sid.c
@@ -1203,34 +1203,47 @@ unsigned short LoadSIDFromMemory(void *pSidData, unsigned short *load_addr,
1203 return *load_addr; 1203 return *load_addr;
1204} 1204}
1205 1205
1206static int nSamplesRendered = 0;
1207static int nSamplesPerCall = 882; /* This is PAL SID single speed (44100/50Hz) */
1208static int nSamplesToRender = 0;
1206 1209
1207enum codec_status codec_main(void) 1210/* this is the codec entry point */
1211enum codec_status codec_main(enum codec_entry_call_reason reason)
1208{ 1212{
1209 unsigned int filesize; 1213 if (reason == CODEC_LOAD) {
1214 /* Make use of 44.1khz */
1215 ci->configure(DSP_SWITCH_FREQUENCY, 44100);
1216 /* Sample depth is 28 bit host endian */
1217 ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
1218 /* Mono output */
1219 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
1220 }
1221
1222 return CODEC_OK;
1223}
1210 1224
1225/* this is called for each file to process */
1226enum codec_status codec_run(void)
1227{
1228 unsigned int filesize;
1211 unsigned short load_addr, init_addr, play_addr; 1229 unsigned short load_addr, init_addr, play_addr;
1212 unsigned char subSongsMax, subSong, song_speed; 1230 unsigned char subSongsMax, subSong, song_speed;
1231 intptr_t param;
1213 1232
1214 int nSamplesRendered = 0;
1215 int nSamplesPerCall = 882; /* This is PAL SID single speed (44100/50Hz) */
1216 int nSamplesToRender = 0;
1217
1218next_track:
1219 if (codec_init()) { 1233 if (codec_init()) {
1220 return CODEC_ERROR; 1234 return CODEC_ERROR;
1221 } 1235 }
1222 1236
1223 if (codec_wait_taginfo() != 0)
1224 goto request_next_track;
1225
1226 codec_set_replaygain(ci->id3); 1237 codec_set_replaygain(ci->id3);
1227 1238
1228 /* Load SID file the read_filebuf callback will return the full requested 1239 /* Load SID file the read_filebuf callback will return the full requested
1229 * size if at all possible, so there is no need to loop */ 1240 * size if at all possible, so there is no need to loop */
1241 ci->seek_buffer(0);
1230 filesize = ci->read_filebuf(sidfile, sizeof(sidfile)); 1242 filesize = ci->read_filebuf(sidfile, sizeof(sidfile));
1231 1243
1232 if (filesize == 0) 1244 if (filesize == 0) {
1233 return CODEC_ERROR; 1245 return CODEC_ERROR;
1246 }
1234 1247
1235 c64Init(44100); 1248 c64Init(44100);
1236 LoadSIDFromMemory(sidfile, &load_addr, &init_addr, &play_addr, 1249 LoadSIDFromMemory(sidfile, &load_addr, &init_addr, &play_addr,
@@ -1239,37 +1252,30 @@ next_track:
1239 cpuJSR(init_addr, subSong); /* Start the song initialize */ 1252 cpuJSR(init_addr, subSong); /* Start the song initialize */
1240 1253
1241 1254
1242 /* Make use of 44.1khz */
1243 ci->configure(DSP_SWITCH_FREQUENCY, 44100);
1244 /* Sample depth is 28 bit host endian */
1245 ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
1246 /* Mono output */
1247 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
1248
1249
1250 /* Set the elapsed time to the current subsong (in seconds) */ 1255 /* Set the elapsed time to the current subsong (in seconds) */
1251 ci->set_elapsed(subSong*1000); 1256 ci->set_elapsed(subSong*1000);
1252 1257
1253 /* The main decoder loop */ 1258 /* The main decoder loop */
1254 while (1) { 1259 while (1) {
1255 ci->yield(); 1260 enum codec_command_action action = ci->get_command(&param);
1256 if (ci->stop_codec || ci->new_track) 1261
1262 if (action == CODEC_ACTION_HALT)
1257 break; 1263 break;
1258 1264
1259 if (ci->seek_time) { 1265 if (action == CODEC_ACTION_SEEK_TIME) {
1260 /* New time is ready in ci->seek_time */ 1266 /* New time is ready in param */
1261 1267
1262 /* Start playing from scratch */ 1268 /* Start playing from scratch */
1263 c64Init(44100); 1269 c64Init(44100);
1264 LoadSIDFromMemory(sidfile, &load_addr, &init_addr, &play_addr, &subSongsMax, &subSong, &song_speed, filesize); 1270 LoadSIDFromMemory(sidfile, &load_addr, &init_addr, &play_addr,
1265 sidPoke(24, 15); /* Turn on full volume */ 1271 &subSongsMax, &subSong, &song_speed, filesize);
1266 subSong = ci->seek_time / 1000; /* Now use the current seek time in seconds as subsong */ 1272 sidPoke(24, 15); /* Turn on full volume */
1267 cpuJSR(init_addr, subSong); /* Start the song initialize */ 1273 subSong = param / 1000; /* Now use the current seek time in seconds as subsong */
1268 nSamplesToRender = 0; /* Start the rendering from scratch */ 1274 cpuJSR(init_addr, subSong); /* Start the song initialize */
1269 1275 nSamplesToRender = 0; /* Start the rendering from scratch */
1270 ci->seek_complete();
1271 1276
1272 /* Set the elapsed time to the current subsong (in seconds) */ 1277 /* Set the elapsed time to the current subsong (in seconds) */
1278 ci->seek_complete();
1273 ci->set_elapsed(subSong*1000); 1279 ci->set_elapsed(subSong*1000);
1274 } 1280 }
1275 1281
@@ -1306,9 +1312,5 @@ next_track:
1306 ci->pcmbuf_insert(samples, NULL, CHUNK_SIZE); 1312 ci->pcmbuf_insert(samples, NULL, CHUNK_SIZE);
1307 } 1313 }
1308 1314
1309request_next_track:
1310 if (ci->request_next_track())
1311 goto next_track;
1312
1313 return CODEC_OK; 1315 return CODEC_OK;
1314} 1316}
diff --git a/apps/codecs/smaf.c b/apps/codecs/smaf.c
index 3e8a41387d..9211daa9aa 100644
--- a/apps/codecs/smaf.c
+++ b/apps/codecs/smaf.c
@@ -332,9 +332,20 @@ static uint8_t *read_buffer(size_t *realsize)
332 return buffer; 332 return buffer;
333} 333}
334 334
335enum codec_status codec_main(void) 335/* this is the codec entry point */
336enum codec_status codec_main(enum codec_entry_call_reason reason)
337{
338 if (reason == CODEC_LOAD) {
339 /* Generic codec initialisation */
340 ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1);
341 }
342
343 return CODEC_OK;
344}
345
346/* this is called for each file to process */
347enum codec_status codec_run(void)
336{ 348{
337 int status;
338 uint32_t decodedsamples; 349 uint32_t decodedsamples;
339 size_t n; 350 size_t n;
340 int bufcount; 351 int bufcount;
@@ -342,20 +353,10 @@ enum codec_status codec_main(void)
342 uint8_t *smafbuf; 353 uint8_t *smafbuf;
343 off_t firstblockposn; /* position of the first block in file */ 354 off_t firstblockposn; /* position of the first block in file */
344 const struct pcm_codec *codec; 355 const struct pcm_codec *codec;
345 356 intptr_t param;
346 /* Generic codec initialisation */
347 ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1);
348 357
349next_track: 358 if (codec_init())
350 status = CODEC_OK; 359 return CODEC_ERROR;
351
352 if (codec_init()) {
353 status = CODEC_ERROR;
354 goto exit;
355 }
356
357 if (codec_wait_taginfo() != 0)
358 goto done;
359 360
360 codec_set_replaygain(ci->id3); 361 codec_set_replaygain(ci->id3);
361 362
@@ -365,24 +366,22 @@ next_track:
365 decodedsamples = 0; 366 decodedsamples = 0;
366 codec = 0; 367 codec = 0;
367 368
369 ci->seek_buffer(0);
368 if (!parse_header(&format, &firstblockposn)) 370 if (!parse_header(&format, &firstblockposn))
369 { 371 {
370 status = CODEC_ERROR; 372 return CODEC_ERROR;
371 goto done;
372 } 373 }
373 374
374 codec = get_codec(format.formattag); 375 codec = get_codec(format.formattag);
375 if (codec == 0) 376 if (codec == 0)
376 { 377 {
377 DEBUGF("CODEC_ERROR: unsupport audio format: 0x%x\n", (int)format.formattag); 378 DEBUGF("CODEC_ERROR: unsupport audio format: 0x%x\n", (int)format.formattag);
378 status = CODEC_ERROR; 379 return CODEC_ERROR;
379 goto done;
380 } 380 }
381 381
382 if (!codec->set_format(&format)) 382 if (!codec->set_format(&format))
383 { 383 {
384 status = CODEC_ERROR; 384 return CODEC_ERROR;
385 goto done;
386 } 385 }
387 386
388 /* check chunksize */ 387 /* check chunksize */
@@ -392,8 +391,7 @@ next_track:
392 if (format.chunksize == 0) 391 if (format.chunksize == 0)
393 { 392 {
394 DEBUGF("CODEC_ERROR: chunksize is 0\n"); 393 DEBUGF("CODEC_ERROR: chunksize is 0\n");
395 status = CODEC_ERROR; 394 return CODEC_ERROR;
396 goto done;
397 } 395 }
398 396
399 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); 397 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
@@ -404,12 +402,10 @@ next_track:
404 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); 402 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
405 } else { 403 } else {
406 DEBUGF("CODEC_ERROR: more than 2 channels unsupported\n"); 404 DEBUGF("CODEC_ERROR: more than 2 channels unsupported\n");
407 status = CODEC_ERROR; 405 return CODEC_ERROR;
408 goto done;
409 } 406 }
410 407
411 ci->seek_buffer(firstblockposn); 408 ci->seek_buffer(firstblockposn);
412 ci->seek_complete();
413 409
414 /* make sure we're at the correct offset */ 410 /* make sure we're at the correct offset */
415 if (bytesdone > (uint32_t) firstblockposn) 411 if (bytesdone > (uint32_t) firstblockposn)
@@ -419,13 +415,13 @@ next_track:
419 PCM_SEEK_POS, &read_buffer); 415 PCM_SEEK_POS, &read_buffer);
420 416
421 if (newpos->pos > format.numbytes) 417 if (newpos->pos > format.numbytes)
422 goto done; 418 return CODEC_OK;
419
423 if (ci->seek_buffer(firstblockposn + newpos->pos)) 420 if (ci->seek_buffer(firstblockposn + newpos->pos))
424 { 421 {
425 bytesdone = newpos->pos; 422 bytesdone = newpos->pos;
426 decodedsamples = newpos->samples; 423 decodedsamples = newpos->samples;
427 } 424 }
428 ci->seek_complete();
429 } 425 }
430 else 426 else
431 { 427 {
@@ -437,23 +433,32 @@ next_track:
437 endofstream = 0; 433 endofstream = 0;
438 434
439 while (!endofstream) { 435 while (!endofstream) {
440 ci->yield(); 436 enum codec_command_action action = ci->get_command(&param);
441 if (ci->stop_codec || ci->new_track) 437
438 if (action == CODEC_ACTION_HALT)
442 break; 439 break;
443 440
444 if (ci->seek_time) { 441 if (action == CODEC_ACTION_SEEK_TIME) {
445 struct pcm_pos *newpos = codec->get_seek_pos(ci->seek_time, PCM_SEEK_TIME, 442 struct pcm_pos *newpos = codec->get_seek_pos(param, PCM_SEEK_TIME,
446 &read_buffer); 443 &read_buffer);
447 444
448 if (newpos->pos > format.numbytes) 445 if (newpos->pos > format.numbytes)
446 {
447 ci->set_elapsed(ci->id3->length);
448 ci->seek_complete();
449 break; 449 break;
450 }
451
450 if (ci->seek_buffer(firstblockposn + newpos->pos)) 452 if (ci->seek_buffer(firstblockposn + newpos->pos))
451 { 453 {
452 bytesdone = newpos->pos; 454 bytesdone = newpos->pos;
453 decodedsamples = newpos->samples; 455 decodedsamples = newpos->samples;
454 } 456 }
457
458 ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
455 ci->seek_complete(); 459 ci->seek_complete();
456 } 460 }
461
457 smafbuf = (uint8_t *)ci->request_buffer(&n, format.chunksize); 462 smafbuf = (uint8_t *)ci->request_buffer(&n, format.chunksize);
458 463
459 if (n == 0) 464 if (n == 0)
@@ -464,11 +469,10 @@ next_track:
464 endofstream = 1; 469 endofstream = 1;
465 } 470 }
466 471
467 status = codec->decode(smafbuf, n, samples, &bufcount); 472 if (codec->decode(smafbuf, n, samples, &bufcount) == CODEC_ERROR)
468 if (status == CODEC_ERROR)
469 { 473 {
470 DEBUGF("codec error\n"); 474 DEBUGF("codec error\n");
471 goto done; 475 return CODEC_ERROR;
472 } 476 }
473 477
474 ci->pcmbuf_insert(samples, NULL, bufcount); 478 ci->pcmbuf_insert(samples, NULL, bufcount);
@@ -482,11 +486,5 @@ next_track:
482 ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency); 486 ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
483 } 487 }
484 488
485done: 489 return CODEC_OK;
486 if (ci->request_next_track())
487 goto next_track;
488
489exit:
490 return status;
491} 490}
492
diff --git a/apps/codecs/spc.c b/apps/codecs/spc.c
index 4db2878964..1b49761810 100644
--- a/apps/codecs/spc.c
+++ b/apps/codecs/spc.c
@@ -260,14 +260,6 @@ static inline void samples_release_rdbuf(void)
260static inline int32_t * samples_get_rdbuf(void) 260static inline int32_t * samples_get_rdbuf(void)
261{ 261{
262 ci->semaphore_wait(&sample_queue.emu_sem_head, TIMEOUT_BLOCK); 262 ci->semaphore_wait(&sample_queue.emu_sem_head, TIMEOUT_BLOCK);
263
264 if (ci->stop_codec || ci->new_track)
265 {
266 /* Told to stop. Buffer must be released. */
267 samples_release_rdbuf();
268 return NULL;
269 }
270
271 return sample_queue.wav_chunk[sample_queue.head & WAV_CHUNK_MASK].audio; 263 return sample_queue.wav_chunk[sample_queue.head & WAV_CHUNK_MASK].audio;
272} 264}
273 265
@@ -390,11 +382,10 @@ static inline void spc_emu_quit(void)
390 } 382 }
391} 383}
392 384
393static inline bool spc_play_get_samples(int32_t **samples) 385static inline int32_t * spc_play_get_samples(void)
394{ 386{
395 /* obtain filled samples buffer */ 387 /* obtain filled samples buffer */
396 *samples = samples_get_rdbuf(); 388 return samples_get_rdbuf();
397 return *samples != NULL;
398} 389}
399 390
400static inline void spc_play_send_samples(int32_t *samples) 391static inline void spc_play_send_samples(int32_t *samples)
@@ -433,15 +424,14 @@ static inline void spc_play_send_samples(int32_t *samples)
433#define spc_emu_quit() 424#define spc_emu_quit()
434#define samples_release_rdbuf() 425#define samples_release_rdbuf()
435 426
436static inline bool spc_play_get_samples(int32_t **samples) 427static inline int32_t * spc_play_get_samples(void)
437{ 428{
438 ENTER_TIMER(render); 429 ENTER_TIMER(render);
439 /* fill samples buffer */ 430 /* fill samples buffer */
440 if ( SPC_play(&spc_emu,WAV_CHUNK_SIZE*2,wav_chunk) ) 431 if ( SPC_play(&spc_emu,WAV_CHUNK_SIZE*2,wav_chunk) )
441 assert( false ); 432 assert( false );
442 EXIT_TIMER(render); 433 EXIT_TIMER(render);
443 *samples = wav_chunk; 434 return wav_chunk;
444 return true;
445} 435}
446#endif /* SPC_DUAL_CORE */ 436#endif /* SPC_DUAL_CORE */
447 437
@@ -454,6 +444,7 @@ static int play_track( void )
454 unsigned long fadeendsample = (ID666.length+ID666.fade)*(long long) SAMPLE_RATE/1000; 444 unsigned long fadeendsample = (ID666.length+ID666.fade)*(long long) SAMPLE_RATE/1000;
455 int fadedec = 0; 445 int fadedec = 0;
456 int fadevol = 0x7fffffffl; 446 int fadevol = 0x7fffffffl;
447 intptr_t param;
457 448
458 if (fadeendsample>fadestartsample) 449 if (fadeendsample>fadestartsample)
459 fadedec=0x7fffffffl/(fadeendsample-fadestartsample)+1; 450 fadedec=0x7fffffffl/(fadeendsample-fadestartsample)+1;
@@ -462,25 +453,26 @@ static int play_track( void )
462 453
463 while ( 1 ) 454 while ( 1 )
464 { 455 {
465 ci->yield(); 456 enum codec_command_action action = ci->get_command(&param);
466 if (ci->stop_codec || ci->new_track) { 457
458 if (action == CODEC_ACTION_HALT)
467 break; 459 break;
468 }
469 460
470 if (ci->seek_time) { 461 if (action == CODEC_ACTION_SEEK_TIME) {
471 int curtime = sampleswritten*1000LL/SAMPLE_RATE; 462 int curtime = sampleswritten*1000LL/SAMPLE_RATE;
472 DEBUGF("seek to %ld\ncurrently at %d\n",ci->seek_time,curtime); 463 DEBUGF("seek to %ld\ncurrently at %d\n", (long)param, curtime);
473 if (ci->seek_time < curtime) { 464 if (param < curtime) {
474 DEBUGF("seek backwards = reset\n"); 465 DEBUGF("seek backwards = reset\n");
466 ci->set_elapsed(0);
475 ci->seek_complete(); 467 ci->seek_complete();
476 return 1; 468 return 1;
477 } 469 }
470
471 ci->set_elapsed(curtime);
478 ci->seek_complete(); 472 ci->seek_complete();
479 } 473 }
480 474
481 int32_t *samples; 475 int32_t *samples = spc_play_get_samples();
482 if (!spc_play_get_samples(&samples))
483 break;
484 476
485 sampleswritten += WAV_CHUNK_SIZE; 477 sampleswritten += WAV_CHUNK_SIZE;
486 478
@@ -532,67 +524,61 @@ static int play_track( void )
532} 524}
533 525
534/* this is the codec entry point */ 526/* this is the codec entry point */
535enum codec_status codec_main(void) 527enum codec_status codec_main(enum codec_entry_call_reason reason)
536{ 528{
537 enum codec_status stat = CODEC_ERROR; 529 if (reason == CODEC_LOAD) {
538 530 if (!spc_emu_start())
539 if (!spc_emu_start()) 531 return CODEC_ERROR;
540 goto codec_quit;
541
542 do
543 {
544 DEBUGF("SPC: next_track\n");
545 if (codec_init()) {
546 goto codec_quit;
547 }
548 DEBUGF("SPC: after init\n");
549 532
550 ci->configure(DSP_SET_SAMPLE_DEPTH, 24); 533 ci->configure(DSP_SET_SAMPLE_DEPTH, 24);
551 ci->configure(DSP_SET_FREQUENCY, SAMPLE_RATE); 534 ci->configure(DSP_SET_FREQUENCY, SAMPLE_RATE);
552 ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED); 535 ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
536 }
537 else if (reason == CODEC_UNLOAD) {
538 spc_emu_quit();
539 }
553 540
554 /* wait for track info to load */ 541 return CODEC_OK;
555 if (codec_wait_taginfo() != 0) 542}
556 continue;
557
558 codec_set_replaygain(ci->id3);
559 543
560 /* Read the entire file */ 544/* this is called for each file to process */
561 DEBUGF("SPC: request initial buffer\n"); 545enum codec_status codec_run(void)
562 ci->seek_buffer(0); 546{
563 size_t buffersize; 547 DEBUGF("SPC: next_track\n");
564 uint8_t* buffer = ci->request_buffer(&buffersize, ci->filesize); 548 if (codec_init())
565 if (!buffer) { 549 return CODEC_ERROR;
566 goto codec_quit; 550 DEBUGF("SPC: after init\n");
551
552 codec_set_replaygain(ci->id3);
553
554 /* Read the entire file */
555 DEBUGF("SPC: request initial buffer\n");
556 ci->seek_buffer(0);
557 size_t buffersize;
558 uint8_t* buffer = ci->request_buffer(&buffersize, ci->filesize);
559 if (!buffer)
560 return CODEC_ERROR;
561
562 DEBUGF("SPC: read size = 0x%lx\n",(unsigned long)buffersize);
563 do
564 {
565 if (load_spc_buffer(buffer, buffersize)) {
566 DEBUGF("SPC load failure\n");
567 return CODEC_ERROR;
567 } 568 }
568 569
569 DEBUGF("SPC: read size = 0x%lx\n",(unsigned long)buffersize); 570 LoadID666(buffer+0x2e);
570 do
571 {
572 if (load_spc_buffer(buffer, buffersize)) {
573 DEBUGF("SPC load failure\n");
574 goto codec_quit;
575 }
576
577 LoadID666(buffer+0x2e);
578 571
579 if (ci->global_settings->repeat_mode!=REPEAT_ONE && ID666.length==0) { 572 if (ci->global_settings->repeat_mode!=REPEAT_ONE && ID666.length==0) {
580 ID666.length=3*60*1000; /* 3 minutes */ 573 ID666.length=3*60*1000; /* 3 minutes */
581 ID666.fade=5*1000; /* 5 seconds */ 574 ID666.fade=5*1000; /* 5 seconds */
582 }
583
584 reset_profile_timers();
585 } 575 }
586 while ( play_track() );
587 576
588 print_timers(ci->id3->path); 577 reset_profile_timers();
589 } 578 }
590 while ( ci->request_next_track() ); 579 while ( play_track() );
591 580
592 stat = CODEC_OK; 581 print_timers(ci->id3->path);
593 582
594codec_quit: 583 return CODEC_OK;
595 spc_emu_quit();
596
597 return stat;
598} 584}
diff --git a/apps/codecs/speex.c b/apps/codecs/speex.c
index 7a1efa9753..e394efc3d5 100644
--- a/apps/codecs/speex.c
+++ b/apps/codecs/speex.c
@@ -367,11 +367,12 @@ static void *process_header(spx_ogg_packet *op,
367 return st; 367 return st;
368} 368}
369 369
370/* this is the codec entry point */ 370/* this is called for each file to process */
371enum codec_status codec_main(void) 371enum codec_status codec_run(void)
372{ 372{
373 int error = CODEC_ERROR;
374
373 SpeexBits bits; 375 SpeexBits bits;
374 int error;
375 int eof = 0; 376 int eof = 0;
376 spx_ogg_sync_state oy; 377 spx_ogg_sync_state oy;
377 spx_ogg_page og; 378 spx_ogg_page og;
@@ -383,7 +384,7 @@ enum codec_status codec_main(void)
383 int eos = 0; 384 int eos = 0;
384 SpeexStereoState *stereo; 385 SpeexStereoState *stereo;
385 int channels = -1; 386 int channels = -1;
386 int rate = 0, samplerate = 0; 387 int samplerate = 0;
387 int extra_headers = 0; 388 int extra_headers = 0;
388 int stream_init = 0; 389 int stream_init = 0;
389 int page_nb_packets, frame_size, packet_count = 0; 390 int page_nb_packets, frame_size, packet_count = 0;
@@ -392,26 +393,22 @@ enum codec_status codec_main(void)
392 unsigned long strtoffset = 0; 393 unsigned long strtoffset = 0;
393 void *st = NULL; 394 void *st = NULL;
394 int j = 0; 395 int j = 0;
396 intptr_t param;
395 397
396 memset(&bits, 0, sizeof(bits)); 398 memset(&bits, 0, sizeof(bits));
397 memset(&oy, 0, sizeof(oy)); 399 memset(&oy, 0, sizeof(oy));
398 400
399 /* Ogg handling still uses mallocs, so reset the malloc buffer per track */ 401 /* Ogg handling still uses mallocs, so reset the malloc buffer per track */
400next_track:
401 error = CODEC_OK;
402
403 if (codec_init()) { 402 if (codec_init()) {
404 error = CODEC_ERROR;
405 goto exit; 403 goto exit;
406 } 404 }
407 405
406 ci->seek_buffer(0);
407
408 stereo = speex_stereo_state_init(); 408 stereo = speex_stereo_state_init();
409 spx_ogg_sync_init(&oy); 409 spx_ogg_sync_init(&oy);
410 spx_ogg_alloc_buffer(&oy,2*CHUNKSIZE); 410 spx_ogg_alloc_buffer(&oy,2*CHUNKSIZE);
411 411
412 if (codec_wait_taginfo() != 0)
413 goto done;
414
415 strtoffset = ci->id3->offset; 412 strtoffset = ci->id3->offset;
416 413
417 samplerate = ci->id3->frequency; 414 samplerate = ci->id3->frequency;
@@ -419,30 +416,32 @@ next_track:
419 416
420 eof = 0; 417 eof = 0;
421 while (!eof) { 418 while (!eof) {
422 ci->yield(); 419 enum codec_command_action action = ci->get_command(&param);
423 if (ci->stop_codec || ci->new_track) 420
421 if (action == CODEC_ACTION_HALT)
424 break; 422 break;
425 423
426 /*seek (seeks to the page before the position) */ 424 /*seek (seeks to the page before the position) */
427 if (ci->seek_time) { 425 if (action == CODEC_ACTION_SEEK_TIME) {
428 if(samplerate!=0&&packet_count>1){ 426 if(samplerate!=0&&packet_count>1){
429 LOGF("Speex seek page:%lld,%lld,%ld,%lld,%d\n", 427 LOGF("Speex seek page:%lld,%lld,%ld,%lld,%d\n",
430 ((spx_int64_t)ci->seek_time/1000) * 428 ((spx_int64_t)param/1000) *
431 (spx_int64_t)samplerate, 429 (spx_int64_t)samplerate,
432 page_granule, ci->seek_time, 430 page_granule, param,
433 (page_granule/samplerate)*1000, samplerate); 431 (page_granule/samplerate)*1000, samplerate);
434 432
435 speex_seek_page_granule(((spx_int64_t)ci->seek_time/1000) * 433 speex_seek_page_granule(((spx_int64_t)param/1000) *
436 (spx_int64_t)samplerate, 434 (spx_int64_t)samplerate,
437 page_granule, &oy, headerssize); 435 page_granule, &oy, headerssize);
438 ci->seek_complete();
439 } 436 }
437
438 ci->set_elapsed(param);
439 ci->seek_complete();
440 } 440 }
441 441
442next_page: 442next_page:
443 /*Get the ogg buffer for writing*/ 443 /*Get the ogg buffer for writing*/
444 if(get_more_data(&oy)<1){/*read error*/ 444 if(get_more_data(&oy)<1){/*read error*/
445 error=CODEC_ERROR;
446 goto done; 445 goto done;
447 } 446 }
448 447
@@ -477,8 +476,7 @@ next_page:
477 nframes=1; 476 nframes=1;
478 477
479 if (!st){ 478 if (!st){
480 error=CODEC_ERROR; 479 goto done;
481 goto exit;
482 } 480 }
483 481
484 ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency); 482 ci->configure(DSP_SET_FREQUENCY, ci->id3->frequency);
@@ -557,31 +555,18 @@ next_page:
557 } 555 }
558 556
559done: 557done:
560 if (ci->request_next_track()) { 558 /* Clean things up for the next track */
561 559 speex_bits_destroy(&bits);
562 /* Clean things up for the next track */
563 560
561 if (st)
564 if (st) 562 if (st)
565 speex_decoder_destroy(st); 563 speex_decoder_destroy(st);
566 564
567 if (stream_init == 1)
568 spx_ogg_stream_reset(&os);
569
570 spx_ogg_sync_reset(&oy);
571
572 cur_granule = stream_init = rate = samplerate = headerssize
573 = packet_count = eos = 0;
574
575 goto next_track;
576 }
577
578exit:
579 speex_bits_destroy(&bits);
580
581 if (stream_init) 565 if (stream_init)
582 spx_ogg_stream_destroy(&os); 566 spx_ogg_stream_destroy(&os);
583 567
584 spx_ogg_sync_destroy(&oy); 568 spx_ogg_sync_destroy(&oy);
585 569
570exit:
586 return error; 571 return error;
587} 572}
diff --git a/apps/codecs/tta.c b/apps/codecs/tta.c
index 1d0846ea61..c75f2b0a57 100644
--- a/apps/codecs/tta.c
+++ b/apps/codecs/tta.c
@@ -34,36 +34,36 @@ CODEC_HEADER
34static int32_t samples[PCM_BUFFER_LENGTH * 2] IBSS_ATTR; 34static int32_t samples[PCM_BUFFER_LENGTH * 2] IBSS_ATTR;
35 35
36/* this is the codec entry point */ 36/* this is the codec entry point */
37enum codec_status codec_main(void) 37enum codec_status codec_main(enum codec_entry_call_reason reason)
38{
39 if (reason == CODEC_LOAD) {
40 /* Generic codec initialisation */
41 ci->configure(DSP_SET_SAMPLE_DEPTH, TTA_OUTPUT_DEPTH - 1);
42 }
43
44 return CODEC_OK;
45}
46
47/* this is called for each file to process */
48enum codec_status codec_run(void)
38{ 49{
39 tta_info info; 50 tta_info info;
40 int status;
41 unsigned int decodedsamples; 51 unsigned int decodedsamples;
42 int endofstream; 52 int endofstream;
43 int new_pos = 0; 53 int new_pos = 0;
44 int sample_count; 54 int sample_count;
45 55 intptr_t param;
46 /* Generic codec initialisation */
47 ci->configure(DSP_SET_SAMPLE_DEPTH, TTA_OUTPUT_DEPTH - 1);
48 56
49next_track:
50 status = CODEC_OK;
51
52 if (codec_init()) 57 if (codec_init())
53 { 58 {
54 DEBUGF("codec_init() error\n"); 59 DEBUGF("codec_init() error\n");
55 status = CODEC_ERROR; 60 return CODEC_ERROR;
56 goto exit;
57 } 61 }
58 62
59 if (codec_wait_taginfo() != 0) 63 ci->seek_buffer(0);
60 goto done;
61 64
62 if (set_tta_info(&info) < 0 || player_init(&info) < 0) 65 if (set_tta_info(&info) < 0 || player_init(&info) < 0)
63 { 66 return CODEC_ERROR;
64 status = CODEC_ERROR;
65 goto exit;
66 }
67 67
68 codec_set_replaygain(ci->id3); 68 codec_set_replaygain(ci->id3);
69 69
@@ -74,8 +74,8 @@ next_track:
74 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); 74 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
75 } else { 75 } else {
76 DEBUGF("CODEC_ERROR: more than 2 channels\n"); 76 DEBUGF("CODEC_ERROR: more than 2 channels\n");
77 status = CODEC_ERROR; 77 player_stop();
78 goto done; 78 return CODEC_ERROR;
79 } 79 }
80 80
81 /* The main decoder loop */ 81 /* The main decoder loop */
@@ -88,31 +88,31 @@ next_track:
88 new_pos = set_position(ci->id3->offset, TTA_SEEK_POS); 88 new_pos = set_position(ci->id3->offset, TTA_SEEK_POS);
89 if (new_pos >= 0) 89 if (new_pos >= 0)
90 decodedsamples = new_pos; 90 decodedsamples = new_pos;
91 ci->seek_complete();
92 } 91 }
93 92
94 while (!endofstream) 93 while (!endofstream)
95 { 94 {
96 ci->yield(); 95 enum codec_command_action action = ci->get_command(&param);
97 if (ci->stop_codec || ci->new_track) 96
97 if (action == CODEC_ACTION_HALT)
98 break; 98 break;
99 99
100 if (ci->seek_time) 100 if (action == CODEC_ACTION_SEEK_TIME)
101 { 101 {
102 new_pos = set_position(ci->seek_time / SEEK_STEP, TTA_SEEK_TIME); 102 new_pos = set_position(param / SEEK_STEP, TTA_SEEK_TIME);
103 if (new_pos >= 0) 103 if (new_pos >= 0)
104 { 104 {
105 decodedsamples = new_pos; 105 decodedsamples = new_pos;
106 ci->seek_complete();
107 } 106 }
107
108 ci->set_elapsed((uint64_t)info.LENGTH * 1000 * decodedsamples / info.DATALENGTH);
109 ci->seek_complete();
108 } 110 }
109 111
110 sample_count = get_samples(samples); 112 sample_count = get_samples(samples);
111 if (sample_count < 0) 113 if (sample_count < 0)
112 {
113 status = CODEC_ERROR;
114 break; 114 break;
115 } 115
116 ci->pcmbuf_insert(samples, NULL, sample_count); 116 ci->pcmbuf_insert(samples, NULL, sample_count);
117 decodedsamples += sample_count; 117 decodedsamples += sample_count;
118 if (decodedsamples >= info.DATALENGTH) 118 if (decodedsamples >= info.DATALENGTH)
@@ -120,11 +120,6 @@ next_track:
120 ci->set_elapsed((uint64_t)info.LENGTH * 1000 * decodedsamples / info.DATALENGTH); 120 ci->set_elapsed((uint64_t)info.LENGTH * 1000 * decodedsamples / info.DATALENGTH);
121 } 121 }
122 122
123done:
124 player_stop(); 123 player_stop();
125 if (ci->request_next_track()) 124 return CODEC_OK;
126 goto next_track;
127
128exit:
129 return status;
130} 125}
diff --git a/apps/codecs/vorbis.c b/apps/codecs/vorbis.c
index 0a36a37c8b..e02d459262 100644
--- a/apps/codecs/vorbis.c
+++ b/apps/codecs/vorbis.c
@@ -104,14 +104,25 @@ static bool vorbis_set_codec_parameters(OggVorbis_File *vf)
104} 104}
105 105
106/* this is the codec entry point */ 106/* this is the codec entry point */
107enum codec_status codec_main(void) 107enum codec_status codec_main(enum codec_entry_call_reason reason)
108{
109 if (reason == CODEC_LOAD) {
110 if (codec_init())
111 return CODEC_ERROR;
112 ci->configure(DSP_SET_SAMPLE_DEPTH, 24);
113 }
114
115 return CODEC_OK;
116}
117
118/* this is called for each file to process */
119enum codec_status codec_run(void)
108{ 120{
109 ov_callbacks callbacks; 121 ov_callbacks callbacks;
110 OggVorbis_File vf; 122 OggVorbis_File vf;
111 ogg_int32_t **pcm; 123 ogg_int32_t **pcm;
112 124
113 bool initialized = false; /* First init done? */ 125 int error = CODEC_ERROR;
114 int error;
115 long n; 126 long n;
116 int current_section; 127 int current_section;
117 int previous_section; 128 int previous_section;
@@ -120,36 +131,24 @@ enum codec_status codec_main(void)
120 ogg_int64_t vf_dataoffsets; 131 ogg_int64_t vf_dataoffsets;
121 ogg_uint32_t vf_serialnos; 132 ogg_uint32_t vf_serialnos;
122 ogg_int64_t vf_pcmlengths[2]; 133 ogg_int64_t vf_pcmlengths[2];
123 134 intptr_t param;
124 ci->configure(DSP_SET_SAMPLE_DEPTH, 24);
125
126 if (codec_init()) {
127 error = CODEC_ERROR;
128 goto exit;
129 }
130 135
131#if defined(CPU_ARM) || defined(CPU_COLDFIRE) || defined(CPU_MIPS) 136#if defined(CPU_ARM) || defined(CPU_COLDFIRE) || defined(CPU_MIPS)
132 if (setjmp(rb_jump_buf) != 0) { 137 if (setjmp(rb_jump_buf) != 0) {
133 /* malloc failed; skip to next track */ 138 /* malloc failed; finish with this track */
134 error = CODEC_ERROR;
135 goto done; 139 goto done;
136 } 140 }
137#endif 141#endif
138
139next_track:
140 error = CODEC_OK;
141
142 ogg_malloc_init(); 142 ogg_malloc_init();
143 143
144 if (codec_wait_taginfo() != 0)
145 goto done;
146
147 /* Create a decoder instance */ 144 /* Create a decoder instance */
148 callbacks.read_func = read_handler; 145 callbacks.read_func = read_handler;
149 callbacks.seek_func = initial_seek_handler; 146 callbacks.seek_func = initial_seek_handler;
150 callbacks.tell_func = tell_handler; 147 callbacks.tell_func = tell_handler;
151 callbacks.close_func = close_handler; 148 callbacks.close_func = close_handler;
152 149
150 ci->seek_buffer(0);
151
153 /* Open a non-seekable stream */ 152 /* Open a non-seekable stream */
154 error = ov_open_callbacks(ci, &vf, NULL, 0, callbacks); 153 error = ov_open_callbacks(ci, &vf, NULL, 0, callbacks);
155 154
@@ -186,15 +185,13 @@ next_track:
186 vf.end = ci->id3->filesize; 185 vf.end = ci->id3->filesize;
187 vf.ready_state = OPENED; 186 vf.ready_state = OPENED;
188 vf.links = 1; 187 vf.links = 1;
189 initialized = true;
190 } else { 188 } else {
191 DEBUGF("Vorbis: ov_open failed: %d\n", error); 189 DEBUGF("Vorbis: ov_open failed: %d\n", error);
192 error = CODEC_ERROR;
193 goto done; 190 goto done;
194 } 191 }
195 192
196 if (ci->id3->offset) { 193 if (ci->id3->offset) {
197 ci->advance_buffer(ci->id3->offset); 194 ci->seek_buffer(ci->id3->offset);
198 ov_raw_seek(&vf, ci->id3->offset); 195 ov_raw_seek(&vf, ci->id3->offset);
199 ci->set_elapsed(ov_time_tell(&vf)); 196 ci->set_elapsed(ov_time_tell(&vf));
200 ci->set_offset(ov_raw_tell(&vf)); 197 ci->set_offset(ov_raw_tell(&vf));
@@ -203,14 +200,17 @@ next_track:
203 previous_section = -1; 200 previous_section = -1;
204 eof = 0; 201 eof = 0;
205 while (!eof) { 202 while (!eof) {
206 ci->yield(); 203 enum codec_command_action action = ci->get_command(&param);
207 if (ci->stop_codec || ci->new_track) 204
205 if (action == CODEC_ACTION_HALT)
208 break; 206 break;
209 207
210 if (ci->seek_time) { 208 if (action == CODEC_ACTION_SEEK_TIME) {
211 if (ov_time_seek(&vf, ci->seek_time - 1)) { 209 if (ov_time_seek(&vf, param)) {
212 //ci->logf("ov_time_seek failed"); 210 //ci->logf("ov_time_seek failed");
213 } 211 }
212
213 ci->set_elapsed(ov_time_tell(&vf));
214 ci->seek_complete(); 214 ci->seek_complete();
215 } 215 }
216 216
@@ -220,7 +220,6 @@ next_track:
220 /* Change DSP and buffer settings for this bitstream */ 220 /* Change DSP and buffer settings for this bitstream */
221 if (current_section != previous_section) { 221 if (current_section != previous_section) {
222 if (!vorbis_set_codec_parameters(&vf)) { 222 if (!vorbis_set_codec_parameters(&vf)) {
223 error = CODEC_ERROR;
224 goto done; 223 goto done;
225 } else { 224 } else {
226 previous_section = current_section; 225 previous_section = current_section;
@@ -238,6 +237,7 @@ next_track:
238 } 237 }
239 } 238 }
240 239
240 error = CODEC_OK;
241done: 241done:
242#if 0 /* defined(SIMULATOR) */ 242#if 0 /* defined(SIMULATOR) */
243 { 243 {
@@ -249,18 +249,12 @@ done:
249#endif 249#endif
250 ogg_malloc_destroy(); 250 ogg_malloc_destroy();
251 251
252 if (ci->request_next_track()) { 252 /* Clean things up for the next track */
253 if (!initialized) 253 vf.dataoffsets = NULL;
254 goto next_track; 254 vf.offsets = NULL;
255 /* Clean things up for the next track */ 255 vf.serialnos = NULL;
256 vf.dataoffsets = NULL; 256 vf.pcmlengths = NULL;
257 vf.offsets = NULL; 257 ov_clear(&vf);
258 vf.serialnos = NULL; 258
259 vf.pcmlengths = NULL;
260 ov_clear(&vf);
261 goto next_track;
262 }
263
264exit:
265 return error; 259 return error;
266} 260}
diff --git a/apps/codecs/vox.c b/apps/codecs/vox.c
index c7f39342c3..bf274c6917 100644
--- a/apps/codecs/vox.c
+++ b/apps/codecs/vox.c
@@ -44,9 +44,19 @@ static uint8_t *read_buffer(size_t *realsize)
44} 44}
45 45
46/* this is the codec entry point */ 46/* this is the codec entry point */
47enum codec_status codec_main(void) 47enum codec_status codec_main(enum codec_entry_call_reason reason)
48{
49 if (reason == CODEC_LOAD) {
50 /* Generic codec initialisation */
51 ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1);
52 }
53
54 return CODEC_OK;
55}
56
57/* this is called for each file to process */
58enum codec_status codec_run(void)
48{ 59{
49 int status;
50 uint32_t decodedsamples; 60 uint32_t decodedsamples;
51 size_t n; 61 size_t n;
52 int bufcount; 62 int bufcount;
@@ -54,26 +64,18 @@ enum codec_status codec_main(void)
54 uint8_t *voxbuf; 64 uint8_t *voxbuf;
55 off_t firstblockposn = 0; /* position of the first block in file */ 65 off_t firstblockposn = 0; /* position of the first block in file */
56 const struct pcm_codec *codec; 66 const struct pcm_codec *codec;
57 67 intptr_t param;
58 /* Generic codec initialisation */
59 ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1);
60
61next_track:
62 status = CODEC_OK;
63 68
64 if (codec_init()) { 69 if (codec_init()) {
65 DEBUGF("codec_init() error\n"); 70 DEBUGF("codec_init() error\n");
66 status = CODEC_ERROR; 71 return CODEC_ERROR;
67 goto exit;
68 } 72 }
69 73
70 if (codec_wait_taginfo() != 0)
71 goto done;
72
73 codec_set_replaygain(ci->id3); 74 codec_set_replaygain(ci->id3);
74 75
75 /* Need to save offset for later use (cleared indirectly by advance_buffer) */ 76 /* Need to save offset for later use (cleared indirectly by advance_buffer) */
76 bytesdone = ci->id3->offset; 77 bytesdone = ci->id3->offset;
78 ci->seek_buffer(0);
77 79
78 ci->memset(&format, 0, sizeof(struct pcm_format)); 80 ci->memset(&format, 0, sizeof(struct pcm_format));
79 81
@@ -96,20 +98,16 @@ next_track:
96 if (!codec) 98 if (!codec)
97 { 99 {
98 DEBUGF("CODEC_ERROR: dialogic oki adpcm codec does not load.\n"); 100 DEBUGF("CODEC_ERROR: dialogic oki adpcm codec does not load.\n");
99 status = CODEC_ERROR; 101 return CODEC_ERROR;
100 goto done;
101 } 102 }
102 103
103 if (!codec->set_format(&format)) 104 if (!codec->set_format(&format)) {
104 { 105 return CODEC_ERROR;
105 status = CODEC_ERROR;
106 goto done;
107 } 106 }
108 107
109 if (format.numbytes == 0) { 108 if (format.numbytes == 0) {
110 DEBUGF("CODEC_ERROR: data size is 0\n"); 109 DEBUGF("CODEC_ERROR: data size is 0\n");
111 status = CODEC_ERROR; 110 return CODEC_ERROR;
112 goto done;
113 } 111 }
114 112
115 /* check chunksize */ 113 /* check chunksize */
@@ -118,8 +116,7 @@ next_track:
118 if (format.chunksize == 0) 116 if (format.chunksize == 0)
119 { 117 {
120 DEBUGF("CODEC_ERROR: chunksize is 0\n"); 118 DEBUGF("CODEC_ERROR: chunksize is 0\n");
121 status = CODEC_ERROR; 119 return CODEC_ERROR;
122 goto done;
123 } 120 }
124 121
125 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); 122 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
@@ -131,14 +128,14 @@ next_track:
131 struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn, 128 struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn,
132 PCM_SEEK_POS, &read_buffer); 129 PCM_SEEK_POS, &read_buffer);
133 130
134 if (newpos->pos > format.numbytes) 131 if (newpos->pos > format.numbytes) {
135 goto done; 132 return CODEC_OK;
133 }
136 if (ci->seek_buffer(firstblockposn + newpos->pos)) 134 if (ci->seek_buffer(firstblockposn + newpos->pos))
137 { 135 {
138 bytesdone = newpos->pos; 136 bytesdone = newpos->pos;
139 decodedsamples = newpos->samples; 137 decodedsamples = newpos->samples;
140 } 138 }
141 ci->seek_complete();
142 } else { 139 } else {
143 /* already where we need to be */ 140 /* already where we need to be */
144 bytesdone = 0; 141 bytesdone = 0;
@@ -148,22 +145,29 @@ next_track:
148 endofstream = 0; 145 endofstream = 0;
149 146
150 while (!endofstream) { 147 while (!endofstream) {
151 ci->yield(); 148 enum codec_command_action action = ci->get_command(&param);
152 if (ci->stop_codec || ci->new_track) { 149
150 if (action == CODEC_ACTION_HALT)
153 break; 151 break;
154 }
155 152
156 if (ci->seek_time) { 153 if (action == CODEC_ACTION_SEEK_TIME) {
157 struct pcm_pos *newpos = codec->get_seek_pos(ci->seek_time, PCM_SEEK_TIME, 154 struct pcm_pos *newpos = codec->get_seek_pos(param, PCM_SEEK_TIME,
158 &read_buffer); 155 &read_buffer);
159 156
160 if (newpos->pos > format.numbytes) 157 if (newpos->pos > format.numbytes)
158 {
159 ci->set_elapsed(ci->id3->length);
160 ci->seek_complete();
161 break; 161 break;
162 }
163
162 if (ci->seek_buffer(firstblockposn + newpos->pos)) 164 if (ci->seek_buffer(firstblockposn + newpos->pos))
163 { 165 {
164 bytesdone = newpos->pos; 166 bytesdone = newpos->pos;
165 decodedsamples = newpos->samples; 167 decodedsamples = newpos->samples;
166 } 168 }
169
170 ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
167 ci->seek_complete(); 171 ci->seek_complete();
168 } 172 }
169 173
@@ -175,11 +179,10 @@ next_track:
175 endofstream = 1; 179 endofstream = 1;
176 } 180 }
177 181
178 status = codec->decode(voxbuf, n, samples, &bufcount); 182 if (codec->decode(voxbuf, n, samples, &bufcount) == CODEC_ERROR)
179 if (status == CODEC_ERROR)
180 { 183 {
181 DEBUGF("codec error\n"); 184 DEBUGF("codec error\n");
182 goto done; 185 return CODEC_ERROR;
183 } 186 }
184 187
185 ci->pcmbuf_insert(samples, NULL, bufcount); 188 ci->pcmbuf_insert(samples, NULL, bufcount);
@@ -192,10 +195,5 @@ next_track:
192 ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency); 195 ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
193 } 196 }
194 197
195done: 198 return CODEC_OK;
196 if (ci->request_next_track())
197 goto next_track;
198
199exit:
200 return status;
201} 199}
diff --git a/apps/codecs/wav.c b/apps/codecs/wav.c
index e179470f27..42bcc7081f 100644
--- a/apps/codecs/wav.c
+++ b/apps/codecs/wav.c
@@ -151,9 +151,19 @@ static uint8_t *read_buffer(size_t *realsize)
151} 151}
152 152
153/* this is the codec entry point */ 153/* this is the codec entry point */
154enum codec_status codec_main(void) 154enum codec_status codec_main(enum codec_entry_call_reason reason)
155{
156 if (reason == CODEC_LOAD) {
157 /* Generic codec initialisation */
158 ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1);
159 }
160
161 return CODEC_OK;
162}
163
164/* this is called for each file to process */
165enum codec_status codec_run(void)
155{ 166{
156 int status;
157 uint32_t decodedsamples; 167 uint32_t decodedsamples;
158 size_t n; 168 size_t n;
159 int bufcount; 169 int bufcount;
@@ -163,38 +173,28 @@ enum codec_status codec_main(void)
163 off_t firstblockposn; /* position of the first block in file */ 173 off_t firstblockposn; /* position of the first block in file */
164 const struct pcm_codec *codec; 174 const struct pcm_codec *codec;
165 uint32_t size; 175 uint32_t size;
166 176 intptr_t param;
167 /* Generic codec initialisation */
168 ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1);
169
170next_track:
171 status = CODEC_OK;
172 177
173 if (codec_init()) { 178 if (codec_init()) {
174 DEBUGF("codec_init() error\n"); 179 DEBUGF("codec_init() error\n");
175 status = CODEC_ERROR; 180 return CODEC_ERROR;
176 goto exit;
177 } 181 }
178 182
179 if (codec_wait_taginfo() != 0)
180 goto done;
181
182 codec_set_replaygain(ci->id3); 183 codec_set_replaygain(ci->id3);
183 184
184 /* Need to save offset for later use (cleared indirectly by advance_buffer) */ 185 /* Need to save offset for later use (cleared indirectly by advance_buffer) */
185 bytesdone = ci->id3->offset; 186 bytesdone = ci->id3->offset;
186 187
187 /* get RIFF chunk header */ 188 /* get RIFF chunk header */
189 ci->seek_buffer(0);
188 buf = ci->request_buffer(&n, 12); 190 buf = ci->request_buffer(&n, 12);
189 if (n < 12) { 191 if (n < 12) {
190 DEBUGF("request_buffer error\n"); 192 DEBUGF("request_buffer error\n");
191 status = CODEC_ERROR; 193 return CODEC_ERROR;
192 goto done;
193 } 194 }
194 if ((memcmp(buf, "RIFF", 4) != 0) || (memcmp(&buf[8], "WAVE", 4) != 0)) { 195 if ((memcmp(buf, "RIFF", 4) != 0) || (memcmp(&buf[8], "WAVE", 4) != 0)) {
195 DEBUGF("CODEC_ERROR: missing riff header\n"); 196 DEBUGF("CODEC_ERROR: missing riff header\n");
196 status = CODEC_ERROR; 197 return CODEC_ERROR;
197 goto done;
198 } 198 }
199 199
200 /* advance to first WAVE chunk */ 200 /* advance to first WAVE chunk */
@@ -215,8 +215,7 @@ next_track:
215 if (n < 8) { 215 if (n < 8) {
216 DEBUGF("data chunk request_buffer error\n"); 216 DEBUGF("data chunk request_buffer error\n");
217 /* no more chunks, 'data' chunk must not have been found */ 217 /* no more chunks, 'data' chunk must not have been found */
218 status = CODEC_ERROR; 218 return CODEC_ERROR;
219 goto done;
220 } 219 }
221 220
222 /* chunkSize */ 221 /* chunkSize */
@@ -225,8 +224,7 @@ next_track:
225 if (size < 16) { 224 if (size < 16) {
226 DEBUGF("CODEC_ERROR: 'fmt ' chunk size=%lu < 16\n", 225 DEBUGF("CODEC_ERROR: 'fmt ' chunk size=%lu < 16\n",
227 (unsigned long)size); 226 (unsigned long)size);
228 status = CODEC_ERROR; 227 return CODEC_ERROR;
229 goto done;
230 } 228 }
231 /* wFormatTag */ 229 /* wFormatTag */
232 format.formattag=buf[8]|(buf[9]<<8); 230 format.formattag=buf[8]|(buf[9]<<8);
@@ -256,8 +254,7 @@ next_track:
256 if (format.size < 22) { 254 if (format.size < 22) {
257 DEBUGF("CODEC_ERROR: WAVE_FORMAT_EXTENSIBLE is " 255 DEBUGF("CODEC_ERROR: WAVE_FORMAT_EXTENSIBLE is "
258 "missing extension\n"); 256 "missing extension\n");
259 status = CODEC_ERROR; 257 return CODEC_ERROR;
260 goto done;
261 } 258 }
262 /* wValidBitsPerSample */ 259 /* wValidBitsPerSample */
263 format.bitspersample = buf[26]|(buf[27]<<8); 260 format.bitspersample = buf[26]|(buf[27]<<8);
@@ -273,8 +270,7 @@ next_track:
273 { 270 {
274 if (!set_msadpcm_coeffs(buf)) 271 if (!set_msadpcm_coeffs(buf))
275 { 272 {
276 status = CODEC_ERROR; 273 return CODEC_ERROR;
277 goto done;
278 } 274 }
279 } 275 }
280 276
@@ -284,8 +280,7 @@ next_track:
284 { 280 {
285 DEBUGF("CODEC_ERROR: unsupported wave format 0x%x\n", 281 DEBUGF("CODEC_ERROR: unsupported wave format 0x%x\n",
286 (unsigned int) format.formattag); 282 (unsigned int) format.formattag);
287 status = CODEC_ERROR; 283 return CODEC_ERROR;
288 goto done;
289 } 284 }
290 285
291 /* riff 8bit linear pcm is unsigned */ 286 /* riff 8bit linear pcm is unsigned */
@@ -295,8 +290,7 @@ next_track:
295 /* set format, parse codec specific tag, check format, and calculate chunk size */ 290 /* set format, parse codec specific tag, check format, and calculate chunk size */
296 if (!codec->set_format(&format)) 291 if (!codec->set_format(&format))
297 { 292 {
298 status = CODEC_ERROR; 293 return CODEC_ERROR;
299 goto done;
300 } 294 }
301 } else if (memcmp(buf, "data", 4) == 0) { 295 } else if (memcmp(buf, "data", 4) == 0) {
302 format.numbytes = size; 296 format.numbytes = size;
@@ -324,31 +318,26 @@ next_track:
324 if (!codec) 318 if (!codec)
325 { 319 {
326 DEBUGF("CODEC_ERROR: 'fmt ' chunk not found\n"); 320 DEBUGF("CODEC_ERROR: 'fmt ' chunk not found\n");
327 status = CODEC_ERROR; 321 return CODEC_ERROR;
328 goto done;
329 } 322 }
330 323
331 /* common format check */ 324 /* common format check */
332 if (format.channels == 0) { 325 if (format.channels == 0) {
333 DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-channels file\n"); 326 DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-channels file\n");
334 status = CODEC_ERROR; 327 return CODEC_ERROR;
335 goto done;
336 } 328 }
337 if (format.samplesperblock == 0) { 329 if (format.samplesperblock == 0) {
338 DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-wSamplesPerBlock file\n"); 330 DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-wSamplesPerBlock file\n");
339 status = CODEC_ERROR; 331 return CODEC_ERROR;
340 goto done;
341 } 332 }
342 if (format.blockalign == 0) 333 if (format.blockalign == 0)
343 { 334 {
344 DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-blockalign file\n"); 335 DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-blockalign file\n");
345 status = CODEC_ERROR; 336 return CODEC_ERROR;
346 goto done;
347 } 337 }
348 if (format.numbytes == 0) { 338 if (format.numbytes == 0) {
349 DEBUGF("CODEC_ERROR: 'data' chunk not found or has zero-length\n"); 339 DEBUGF("CODEC_ERROR: 'data' chunk not found or has zero-length\n");
350 status = CODEC_ERROR; 340 return CODEC_ERROR;
351 goto done;
352 } 341 }
353 342
354 /* check chunksize */ 343 /* check chunksize */
@@ -358,8 +347,7 @@ next_track:
358 if (format.chunksize == 0) 347 if (format.chunksize == 0)
359 { 348 {
360 DEBUGF("CODEC_ERROR: chunksize is 0\n"); 349 DEBUGF("CODEC_ERROR: chunksize is 0\n");
361 status = CODEC_ERROR; 350 return CODEC_ERROR;
362 goto done;
363 } 351 }
364 352
365 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); 353 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
@@ -369,8 +357,7 @@ next_track:
369 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); 357 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
370 } else { 358 } else {
371 DEBUGF("CODEC_ERROR: more than 2 channels\n"); 359 DEBUGF("CODEC_ERROR: more than 2 channels\n");
372 status = CODEC_ERROR; 360 return CODEC_ERROR;
373 goto done;
374 } 361 }
375 362
376 /* make sure we're at the correct offset */ 363 /* make sure we're at the correct offset */
@@ -380,13 +367,12 @@ next_track:
380 PCM_SEEK_POS, &read_buffer); 367 PCM_SEEK_POS, &read_buffer);
381 368
382 if (newpos->pos > format.numbytes) 369 if (newpos->pos > format.numbytes)
383 goto done; 370 return CODEC_OK;
384 if (ci->seek_buffer(firstblockposn + newpos->pos)) 371 if (ci->seek_buffer(firstblockposn + newpos->pos))
385 { 372 {
386 bytesdone = newpos->pos; 373 bytesdone = newpos->pos;
387 decodedsamples = newpos->samples; 374 decodedsamples = newpos->samples;
388 } 375 }
389 ci->seek_complete();
390 } else { 376 } else {
391 /* already where we need to be */ 377 /* already where we need to be */
392 bytesdone = 0; 378 bytesdone = 0;
@@ -396,22 +382,28 @@ next_track:
396 endofstream = 0; 382 endofstream = 0;
397 383
398 while (!endofstream) { 384 while (!endofstream) {
399 ci->yield(); 385 enum codec_command_action action = ci->get_command(&param);
400 if (ci->stop_codec || ci->new_track) { 386
387 if (action == CODEC_ACTION_HALT)
401 break; 388 break;
402 }
403 389
404 if (ci->seek_time) { 390 if (action == CODEC_ACTION_SEEK_TIME) {
405 struct pcm_pos *newpos = codec->get_seek_pos(ci->seek_time, PCM_SEEK_TIME, 391 struct pcm_pos *newpos = codec->get_seek_pos(param, PCM_SEEK_TIME,
406 &read_buffer); 392 &read_buffer);
407
408 if (newpos->pos > format.numbytes) 393 if (newpos->pos > format.numbytes)
394 {
395 ci->set_elapsed(ci->id3->length);
396 ci->seek_complete();
409 break; 397 break;
398 }
399
410 if (ci->seek_buffer(firstblockposn + newpos->pos)) 400 if (ci->seek_buffer(firstblockposn + newpos->pos))
411 { 401 {
412 bytesdone = newpos->pos; 402 bytesdone = newpos->pos;
413 decodedsamples = newpos->samples; 403 decodedsamples = newpos->samples;
414 } 404 }
405
406 ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
415 ci->seek_complete(); 407 ci->seek_complete();
416 } 408 }
417 409
@@ -423,11 +415,10 @@ next_track:
423 endofstream = 1; 415 endofstream = 1;
424 } 416 }
425 417
426 status = codec->decode(wavbuf, n, samples, &bufcount); 418 if (codec->decode(wavbuf, n, samples, &bufcount) == CODEC_ERROR)
427 if (status == CODEC_ERROR)
428 { 419 {
429 DEBUGF("codec error\n"); 420 DEBUGF("codec error\n");
430 goto done; 421 return CODEC_ERROR;
431 } 422 }
432 423
433 ci->pcmbuf_insert(samples, NULL, bufcount); 424 ci->pcmbuf_insert(samples, NULL, bufcount);
@@ -440,10 +431,5 @@ next_track:
440 ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency); 431 ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
441 } 432 }
442 433
443done: 434 return CODEC_OK;
444 if (ci->request_next_track())
445 goto next_track;
446
447exit:
448 return status;
449} 435}
diff --git a/apps/codecs/wav64.c b/apps/codecs/wav64.c
index 9dbdab8368..c763e6f7f0 100644
--- a/apps/codecs/wav64.c
+++ b/apps/codecs/wav64.c
@@ -159,9 +159,19 @@ static uint8_t *read_buffer(size_t *realsize)
159} 159}
160 160
161/* this is the codec entry point */ 161/* this is the codec entry point */
162enum codec_status codec_main(void) 162enum codec_status codec_main(enum codec_entry_call_reason reason)
163{
164 if (reason == CODEC_LOAD) {
165 /* Generic codec initialisation */
166 ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1);
167 }
168
169 return CODEC_OK;
170}
171
172/* this is called for each file to process */
173enum codec_status codec_run(void)
163{ 174{
164 int status;
165 uint32_t decodedsamples; 175 uint32_t decodedsamples;
166 size_t n; 176 size_t n;
167 int bufcount; 177 int bufcount;
@@ -171,39 +181,29 @@ enum codec_status codec_main(void)
171 off_t firstblockposn; /* position of the first block in file */ 181 off_t firstblockposn; /* position of the first block in file */
172 const struct pcm_codec *codec; 182 const struct pcm_codec *codec;
173 uint64_t size; 183 uint64_t size;
174 184 intptr_t param;
175 /* Generic codec initialisation */
176 ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1);
177
178next_track:
179 status = CODEC_OK;
180 185
181 if (codec_init()) { 186 if (codec_init()) {
182 DEBUGF("codec_init() error\n"); 187 DEBUGF("codec_init() error\n");
183 status = CODEC_ERROR; 188 return CODEC_ERROR;
184 goto exit;
185 } 189 }
186 190
187 if (codec_wait_taginfo() != 0)
188 goto done;
189
190 codec_set_replaygain(ci->id3); 191 codec_set_replaygain(ci->id3);
191 192
192 /* Need to save offset for later use (cleared indirectly by advance_buffer) */ 193 /* Need to save offset for later use (cleared indirectly by advance_buffer) */
193 bytesdone = ci->id3->offset; 194 bytesdone = ci->id3->offset;
194 195
195 /* get RIFF chunk header */ 196 /* get RIFF chunk header */
197 ci->seek_buffer(0);
196 buf = ci->request_buffer(&n, 40); 198 buf = ci->request_buffer(&n, 40);
197 if (n < 40) { 199 if (n < 40) {
198 DEBUGF("request_buffer error\n"); 200 DEBUGF("request_buffer error\n");
199 status = CODEC_ERROR; 201 return CODEC_ERROR;
200 goto done;
201 } 202 }
202 if ((memcmp(buf , WAVE64_GUID_RIFF, 16) != 0) || 203 if ((memcmp(buf , WAVE64_GUID_RIFF, 16) != 0) ||
203 (memcmp(buf+24, WAVE64_GUID_WAVE, 16) != 0)) 204 (memcmp(buf+24, WAVE64_GUID_WAVE, 16) != 0))
204 { 205 {
205 status = CODEC_ERROR; 206 return CODEC_ERROR;
206 goto done;
207 } 207 }
208 208
209 /* advance to first WAVE chunk */ 209 /* advance to first WAVE chunk */
@@ -224,8 +224,7 @@ next_track:
224 if (n < 8) { 224 if (n < 8) {
225 DEBUGF("data chunk request_buffer error\n"); 225 DEBUGF("data chunk request_buffer error\n");
226 /* no more chunks, 'data' chunk must not have been found */ 226 /* no more chunks, 'data' chunk must not have been found */
227 status = CODEC_ERROR; 227 return CODEC_ERROR;
228 goto done;
229 } 228 }
230 229
231 /* chunkSize */ 230 /* chunkSize */
@@ -233,8 +232,7 @@ next_track:
233 if (memcmp(buf, WAVE64_GUID_FMT, 16) == 0) { 232 if (memcmp(buf, WAVE64_GUID_FMT, 16) == 0) {
234 if (size < 16) { 233 if (size < 16) {
235 DEBUGF("CODEC_ERROR: 'fmt ' chunk size=%d < 16\n", (int)size); 234 DEBUGF("CODEC_ERROR: 'fmt ' chunk size=%d < 16\n", (int)size);
236 status = CODEC_ERROR; 235 return CODEC_ERROR;
237 goto done;
238 } 236 }
239 /* wFormatTag */ 237 /* wFormatTag */
240 format.formattag=buf[24]|(buf[25]<<8); 238 format.formattag=buf[24]|(buf[25]<<8);
@@ -263,8 +261,7 @@ next_track:
263 if (format.size < 22) { 261 if (format.size < 22) {
264 DEBUGF("CODEC_ERROR: WAVE_FORMAT_EXTENSIBLE is " 262 DEBUGF("CODEC_ERROR: WAVE_FORMAT_EXTENSIBLE is "
265 "missing extension\n"); 263 "missing extension\n");
266 status = CODEC_ERROR; 264 return CODEC_ERROR;
267 goto done;
268 } 265 }
269 /* wValidBitsPerSample */ 266 /* wValidBitsPerSample */
270 format.bitspersample = buf[42]|(buf[43]<<8); 267 format.bitspersample = buf[42]|(buf[43]<<8);
@@ -279,10 +276,7 @@ next_track:
279 if (format.formattag == WAVE_FORMAT_ADPCM) 276 if (format.formattag == WAVE_FORMAT_ADPCM)
280 { 277 {
281 if (!set_msadpcm_coeffs(buf)) 278 if (!set_msadpcm_coeffs(buf))
282 { 279 return CODEC_ERROR;
283 status = CODEC_ERROR;
284 goto done;
285 }
286 } 280 }
287 281
288 /* get codec */ 282 /* get codec */
@@ -291,8 +285,7 @@ next_track:
291 { 285 {
292 DEBUGF("CODEC_ERROR: unsupported wave format 0x%x\n", 286 DEBUGF("CODEC_ERROR: unsupported wave format 0x%x\n",
293 (unsigned int) format.formattag); 287 (unsigned int) format.formattag);
294 status = CODEC_ERROR; 288 return CODEC_ERROR;
295 goto done;
296 } 289 }
297 290
298 /* riff 8bit linear pcm is unsigned */ 291 /* riff 8bit linear pcm is unsigned */
@@ -301,10 +294,7 @@ next_track:
301 294
302 /* check format, and calculate chunk size */ 295 /* check format, and calculate chunk size */
303 if (!codec->set_format(&format)) 296 if (!codec->set_format(&format))
304 { 297 return CODEC_ERROR;
305 status = CODEC_ERROR;
306 goto done;
307 }
308 } else if (memcmp(buf, WAVE64_GUID_DATA, 16) == 0) { 298 } else if (memcmp(buf, WAVE64_GUID_DATA, 16) == 0) {
309 format.numbytes = size; 299 format.numbytes = size;
310 /* advance to start of data */ 300 /* advance to start of data */
@@ -330,31 +320,26 @@ next_track:
330 if (!codec) 320 if (!codec)
331 { 321 {
332 DEBUGF("CODEC_ERROR: 'fmt ' chunk not found\n"); 322 DEBUGF("CODEC_ERROR: 'fmt ' chunk not found\n");
333 status = CODEC_ERROR; 323 return CODEC_ERROR;
334 goto done;
335 } 324 }
336 325
337 /* common format check */ 326 /* common format check */
338 if (format.channels == 0) { 327 if (format.channels == 0) {
339 DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-channels file\n"); 328 DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-channels file\n");
340 status = CODEC_ERROR; 329 return CODEC_ERROR;
341 goto done;
342 } 330 }
343 if (format.samplesperblock == 0) { 331 if (format.samplesperblock == 0) {
344 DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-wSamplesPerBlock file\n"); 332 DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-wSamplesPerBlock file\n");
345 status = CODEC_ERROR; 333 return CODEC_ERROR;
346 goto done;
347 } 334 }
348 if (format.blockalign == 0) 335 if (format.blockalign == 0)
349 { 336 {
350 DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-blockalign file\n"); 337 DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-blockalign file\n");
351 status = CODEC_ERROR; 338 return CODEC_ERROR;
352 goto done;
353 } 339 }
354 if (format.numbytes == 0) { 340 if (format.numbytes == 0) {
355 DEBUGF("CODEC_ERROR: 'data' chunk not found or has zero-length\n"); 341 DEBUGF("CODEC_ERROR: 'data' chunk not found or has zero-length\n");
356 status = CODEC_ERROR; 342 return CODEC_ERROR;
357 goto done;
358 } 343 }
359 344
360 /* check chunksize */ 345 /* check chunksize */
@@ -364,8 +349,7 @@ next_track:
364 if (format.chunksize == 0) 349 if (format.chunksize == 0)
365 { 350 {
366 DEBUGF("CODEC_ERROR: chunksize is 0\n"); 351 DEBUGF("CODEC_ERROR: chunksize is 0\n");
367 status = CODEC_ERROR; 352 return CODEC_ERROR;
368 goto done;
369 } 353 }
370 354
371 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); 355 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
@@ -375,8 +359,7 @@ next_track:
375 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); 359 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
376 } else { 360 } else {
377 DEBUGF("CODEC_ERROR: more than 2 channels\n"); 361 DEBUGF("CODEC_ERROR: more than 2 channels\n");
378 status = CODEC_ERROR; 362 return CODEC_ERROR;
379 goto done;
380 } 363 }
381 364
382 /* make sure we're at the correct offset */ 365 /* make sure we're at the correct offset */
@@ -385,14 +368,14 @@ next_track:
385 struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn, 368 struct pcm_pos *newpos = codec->get_seek_pos(bytesdone - firstblockposn,
386 PCM_SEEK_POS, &read_buffer); 369 PCM_SEEK_POS, &read_buffer);
387 370
388 if (newpos->pos > format.numbytes) 371 if (newpos->pos > format.numbytes) {
389 goto done; 372 return CODEC_OK;
373 }
390 if (ci->seek_buffer(firstblockposn + newpos->pos)) 374 if (ci->seek_buffer(firstblockposn + newpos->pos))
391 { 375 {
392 bytesdone = newpos->pos; 376 bytesdone = newpos->pos;
393 decodedsamples = newpos->samples; 377 decodedsamples = newpos->samples;
394 } 378 }
395 ci->seek_complete();
396 } else { 379 } else {
397 /* already where we need to be */ 380 /* already where we need to be */
398 bytesdone = 0; 381 bytesdone = 0;
@@ -402,22 +385,29 @@ next_track:
402 endofstream = 0; 385 endofstream = 0;
403 386
404 while (!endofstream) { 387 while (!endofstream) {
405 ci->yield(); 388 enum codec_command_action action = ci->get_command(&param);
406 if (ci->stop_codec || ci->new_track) { 389
390 if (action == CODEC_ACTION_HALT)
407 break; 391 break;
408 }
409 392
410 if (ci->seek_time) { 393 if (action == CODEC_ACTION_SEEK_TIME) {
411 struct pcm_pos *newpos = codec->get_seek_pos(ci->seek_time, PCM_SEEK_TIME, 394 struct pcm_pos *newpos = codec->get_seek_pos(param, PCM_SEEK_TIME,
412 &read_buffer); 395 &read_buffer);
413 396
414 if (newpos->pos > format.numbytes) 397 if (newpos->pos > format.numbytes)
398 {
399 ci->set_elapsed(ci->id3->length);
400 ci->seek_complete();
415 break; 401 break;
402 }
403
416 if (ci->seek_buffer(firstblockposn + newpos->pos)) 404 if (ci->seek_buffer(firstblockposn + newpos->pos))
417 { 405 {
418 bytesdone = newpos->pos; 406 bytesdone = newpos->pos;
419 decodedsamples = newpos->samples; 407 decodedsamples = newpos->samples;
420 } 408 }
409
410 ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
421 ci->seek_complete(); 411 ci->seek_complete();
422 } 412 }
423 413
@@ -429,11 +419,10 @@ next_track:
429 endofstream = 1; 419 endofstream = 1;
430 } 420 }
431 421
432 status = codec->decode(wavbuf, n, samples, &bufcount); 422 if (codec->decode(wavbuf, n, samples, &bufcount) == CODEC_ERROR)
433 if (status == CODEC_ERROR)
434 { 423 {
435 DEBUGF("codec error\n"); 424 DEBUGF("codec error\n");
436 goto done; 425 return CODEC_ERROR;
437 } 426 }
438 427
439 ci->pcmbuf_insert(samples, NULL, bufcount); 428 ci->pcmbuf_insert(samples, NULL, bufcount);
@@ -445,12 +434,6 @@ next_track:
445 endofstream = 1; 434 endofstream = 1;
446 ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency); 435 ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
447 } 436 }
448 status = CODEC_OK;
449
450done:
451 if (ci->request_next_track())
452 goto next_track;
453 437
454exit: 438 return CODEC_OK;
455 return status;
456} 439}
diff --git a/apps/codecs/wav_enc.c b/apps/codecs/wav_enc.c
index ef1a88ec23..e4afeaf93c 100644
--- a/apps/codecs/wav_enc.c
+++ b/apps/codecs/wav_enc.c
@@ -345,40 +345,42 @@ static bool init_encoder(void)
345 return true; 345 return true;
346} /* init_encoder */ 346} /* init_encoder */
347 347
348/* main codec entry point */ 348/* this is the codec entry point */
349enum codec_status codec_main(void) 349enum codec_status codec_main(enum codec_entry_call_reason reason)
350{ 350{
351 if (!init_encoder()) 351 if (reason == CODEC_LOAD) {
352 return CODEC_ERROR; 352 if (!init_encoder())
353 return CODEC_ERROR;
354 }
355 else if (reason == CODEC_UNLOAD) {
356 /* reset parameters to initial state */
357 ci->enc_set_parameters(NULL);
358 }
353 359
360 return CODEC_OK;
361}
362
363/* this is called for each file to process */
364enum codec_status codec_run(void)
365{
354 /* main encoding loop */ 366 /* main encoding loop */
355 while(!ci->stop_codec) 367 while(ci->get_command(NULL) != CODEC_ACTION_HALT)
356 { 368 {
357 uint32_t *src; 369 uint32_t *src = (uint32_t *)ci->enc_get_pcm_data(PCM_CHUNK_SIZE);
370 struct enc_chunk_hdr *chunk;
358 371
359 while ((src = (uint32_t *)ci->enc_get_pcm_data(PCM_CHUNK_SIZE)) != NULL) 372 if(src == NULL)
360 { 373 continue;
361 struct enc_chunk_hdr *chunk;
362
363 if (ci->stop_codec)
364 break;
365 374
366 chunk = ci->enc_get_chunk(); 375 chunk = ci->enc_get_chunk();
367 chunk->enc_size = enc_size; 376 chunk->enc_size = enc_size;
368 chunk->num_pcm = PCM_SAMP_PER_CHUNK; 377 chunk->num_pcm = PCM_SAMP_PER_CHUNK;
369 chunk->enc_data = ENC_CHUNK_SKIP_HDR(chunk->enc_data, chunk); 378 chunk->enc_data = ENC_CHUNK_SKIP_HDR(chunk->enc_data, chunk);
370 379
371 chunk_to_wav_format(src, (uint32_t *)chunk->enc_data); 380 chunk_to_wav_format(src, (uint32_t *)chunk->enc_data);
372 381
373 ci->enc_finish_chunk(); 382 ci->enc_finish_chunk();
374 ci->yield();
375 }
376
377 ci->yield();
378 } 383 }
379 384
380 /* reset parameters to initial state */
381 ci->enc_set_parameters(NULL);
382
383 return CODEC_OK; 385 return CODEC_OK;
384} /* codec_start */ 386}
diff --git a/apps/codecs/wavpack.c b/apps/codecs/wavpack.c
index d27a9fb621..ccb9f41190 100644
--- a/apps/codecs/wavpack.c
+++ b/apps/codecs/wavpack.c
@@ -31,39 +31,39 @@ static int32_t temp_buffer [BUFFER_SIZE] IBSS_ATTR;
31static int32_t read_callback (void *buffer, int32_t bytes) 31static int32_t read_callback (void *buffer, int32_t bytes)
32{ 32{
33 int32_t retval = ci->read_filebuf (buffer, bytes); 33 int32_t retval = ci->read_filebuf (buffer, bytes);
34 ci->id3->offset = ci->curpos; 34 ci->set_offset(ci->curpos);
35 return retval; 35 return retval;
36} 36}
37 37
38/* this is the codec entry point */ 38/* this is the codec entry point */
39enum codec_status codec_main(void) 39enum codec_status codec_main(enum codec_entry_call_reason reason)
40{
41 if (reason == CODEC_LOAD) {
42 /* Generic codec initialisation */
43 ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
44 }
45
46 return CODEC_OK;
47}
48
49/* this is called for each file to process */
50enum codec_status codec_run(void)
40{ 51{
41 WavpackContext *wpc; 52 WavpackContext *wpc;
42 char error [80]; 53 char error [80];
43 int bps, nchans, sr_100; 54 int bps, nchans, sr_100;
44 int retval; 55 intptr_t param;
45 56
46 /* Generic codec initialisation */ 57 if (codec_init())
47 ci->configure(DSP_SET_SAMPLE_DEPTH, 28); 58 return CODEC_ERROR;
48 59
49next_track: 60 ci->seek_buffer (ci->id3->offset);
50 retval = CODEC_OK;
51 61
52 if (codec_init()) {
53 retval = CODEC_ERROR;
54 goto exit;
55 }
56
57 if (codec_wait_taginfo() != 0)
58 goto done;
59
60 /* Create a decoder instance */ 62 /* Create a decoder instance */
61 wpc = WavpackOpenFileInput (read_callback, error); 63 wpc = WavpackOpenFileInput (read_callback, error);
62 64
63 if (!wpc) { 65 if (!wpc)
64 retval = CODEC_ERROR; 66 return CODEC_ERROR;
65 goto done;
66 }
67 67
68 ci->configure(DSP_SWITCH_FREQUENCY, WavpackGetSampleRate (wpc)); 68 ci->configure(DSP_SWITCH_FREQUENCY, WavpackGetSampleRate (wpc));
69 codec_set_replaygain(ci->id3); 69 codec_set_replaygain(ci->id3);
@@ -77,56 +77,48 @@ next_track:
77 /* The main decoder loop */ 77 /* The main decoder loop */
78 78
79 while (1) { 79 while (1) {
80 int32_t nsamples; 80 int32_t nsamples;
81 enum codec_command_action action = ci->get_command(&param);
82
83 if (action == CODEC_ACTION_HALT)
84 break;
81 85
82 if (ci->seek_time && ci->taginfo_ready && ci->id3->length) { 86 if (action == CODEC_ACTION_SEEK_TIME) {
83 ci->seek_time--;
84 int curpos_ms = WavpackGetSampleIndex (wpc) / sr_100 * 10; 87 int curpos_ms = WavpackGetSampleIndex (wpc) / sr_100 * 10;
85 int n, d, skip; 88 int n, d, skip;
86 89
87 if (ci->seek_time > curpos_ms) { 90 if (param > curpos_ms) {
88 n = ci->seek_time - curpos_ms; 91 n = param - curpos_ms;
89 d = ci->id3->length - curpos_ms; 92 d = ci->id3->length - curpos_ms;
90 skip = (int)((int64_t)(ci->filesize - ci->curpos) * n / d); 93 skip = (int)((int64_t)(ci->filesize - ci->curpos) * n / d);
91 ci->seek_buffer (ci->curpos + skip); 94 ci->seek_buffer (ci->curpos + skip);
92 } 95 }
93 else { 96 else if (curpos_ms != 0) {
94 n = curpos_ms - ci->seek_time; 97 n = curpos_ms - param;
95 d = curpos_ms; 98 d = curpos_ms;
96 skip = (int)((int64_t) ci->curpos * n / d); 99 skip = (int)((int64_t) ci->curpos * n / d);
97 ci->seek_buffer (ci->curpos - skip); 100 ci->seek_buffer (ci->curpos - skip);
98 } 101 }
99 102
100 wpc = WavpackOpenFileInput (read_callback, error); 103 wpc = WavpackOpenFileInput (read_callback, error);
101 ci->seek_complete();
102
103 if (!wpc) 104 if (!wpc)
105 {
106 ci->seek_complete();
104 break; 107 break;
108 }
105 109
106 ci->set_elapsed (WavpackGetSampleIndex (wpc) / sr_100 * 10); 110 ci->set_elapsed (WavpackGetSampleIndex (wpc) / sr_100 * 10);
107 ci->yield (); 111 ci->seek_complete();
108 } 112 }
109 113
110 nsamples = WavpackUnpackSamples (wpc, temp_buffer, BUFFER_SIZE / nchans); 114 nsamples = WavpackUnpackSamples (wpc, temp_buffer, BUFFER_SIZE / nchans);
111 115
112 if (!nsamples || ci->stop_codec || ci->new_track) 116 if (!nsamples)
113 break;
114
115 ci->yield ();
116
117 if (ci->stop_codec || ci->new_track)
118 break; 117 break;
119 118
120 ci->pcmbuf_insert (temp_buffer, NULL, nsamples); 119 ci->pcmbuf_insert (temp_buffer, NULL, nsamples);
121
122 ci->set_elapsed (WavpackGetSampleIndex (wpc) / sr_100 * 10); 120 ci->set_elapsed (WavpackGetSampleIndex (wpc) / sr_100 * 10);
123 ci->yield ();
124 } 121 }
125 122
126done: 123 return CODEC_OK;
127 if (ci->request_next_track())
128 goto next_track;
129
130exit:
131 return retval;
132} 124}
diff --git a/apps/codecs/wavpack_enc.c b/apps/codecs/wavpack_enc.c
index d908e284be..730cf0734b 100644
--- a/apps/codecs/wavpack_enc.c
+++ b/apps/codecs/wavpack_enc.c
@@ -389,77 +389,79 @@ static bool init_encoder(void)
389 return true; 389 return true;
390} /* init_encoder */ 390} /* init_encoder */
391 391
392enum codec_status codec_main(void) 392/* this is the codec entry point */
393enum codec_status codec_main(enum codec_entry_call_reason reason)
393{ 394{
394 /* initialize params and config */ 395 if (reason == CODEC_LOAD) {
395 if (!init_encoder()) 396 /* initialize params and config */
396 return CODEC_ERROR; 397 if (!init_encoder())
398 return CODEC_ERROR;
399 }
400 else if (reason == CODEC_UNLOAD) {
401 /* reset parameters to initial state */
402 ci->enc_set_parameters(NULL);
403 }
397 404
405 return CODEC_OK;
406}
407
408/* this is called for each file to process */
409enum codec_status codec_run(void)
410{
398 /* main encoding loop */ 411 /* main encoding loop */
399 while(!ci->stop_codec) 412 while(ci->get_command(NULL) != CODEC_ACTION_HALT)
400 { 413 {
401 uint8_t *src; 414 uint8_t *src = (uint8_t *)ci->enc_get_pcm_data(PCM_CHUNK_SIZE);
415 struct enc_chunk_hdr *chunk;
416 bool abort_chunk;
417 uint8_t *dst;
418 uint8_t *src_end;
402 419
403 while ((src = ci->enc_get_pcm_data(PCM_CHUNK_SIZE)) != NULL) 420 if(src == NULL)
404 { 421 continue;
405 struct enc_chunk_hdr *chunk;
406 bool abort_chunk;
407 uint8_t *dst;
408 uint8_t *src_end;
409
410 if(ci->stop_codec)
411 break;
412
413 abort_chunk = true;
414 422
415 chunk = ci->enc_get_chunk(); 423 chunk = ci->enc_get_chunk();
416 424
417 /* reset counts and pointer */ 425 /* reset counts and pointer */
418 chunk->enc_size = 0; 426 chunk->enc_size = 0;
419 chunk->num_pcm = 0; 427 chunk->num_pcm = 0;
420 chunk->enc_data = NULL; 428 chunk->enc_data = NULL;
421 429
422 dst = ENC_CHUNK_SKIP_HDR(dst, chunk); 430 dst = ENC_CHUNK_SKIP_HDR(dst, chunk);
423 431
424 WavpackStartBlock(wpc, dst, dst + data_size); 432 WavpackStartBlock(wpc, dst, dst + data_size);
425 433
426 chunk_to_int32((uint32_t*)src); 434 chunk_to_int32((uint32_t*)src);
427 src = input_buffer; 435 src = input_buffer;
428 src_end = src + input_size; 436 src_end = src + input_size;
429 437
430 /* encode chunk in four steps yielding between each */ 438 /* encode chunk in four steps yielding between each */
431 do 439 do
440 {
441 abort_chunk = true;
442 if (WavpackPackSamples(wpc, (int32_t *)src,
443 PCM_SAMP_PER_CHUNK/4))
432 { 444 {
433 if (WavpackPackSamples(wpc, (int32_t *)src, 445 chunk->num_pcm += PCM_SAMP_PER_CHUNK/4;
434 PCM_SAMP_PER_CHUNK/4)) 446 ci->yield();
435 { 447 /* could've been stopped in some way */
436 chunk->num_pcm += PCM_SAMP_PER_CHUNK/4; 448 abort_chunk = chunk->flags & CHUNKF_ABORT;
437 ci->yield();
438 /* could've been stopped in some way */
439 abort_chunk = ci->stop_codec ||
440 (chunk->flags & CHUNKF_ABORT);
441 }
442
443 src += input_step;
444 } 449 }
445 while (!abort_chunk && src < src_end);
446 450
447 if (!abort_chunk) 451 src += input_step;
448 {
449 chunk->enc_data = dst;
450 if (chunk->num_pcm < PCM_SAMP_PER_CHUNK)
451 ci->enc_unget_pcm_data(PCM_CHUNK_SIZE - chunk->num_pcm*4);
452 /* finish the chunk and store chunk size info */
453 chunk->enc_size = WavpackFinishBlock(wpc);
454 ci->enc_finish_chunk();
455 }
456 } 452 }
453 while (!abort_chunk && src < src_end);
457 454
458 ci->yield(); 455 if (!abort_chunk)
456 {
457 chunk->enc_data = dst;
458 if (chunk->num_pcm < PCM_SAMP_PER_CHUNK)
459 ci->enc_unget_pcm_data(PCM_CHUNK_SIZE - chunk->num_pcm*4);
460 /* finish the chunk and store chunk size info */
461 chunk->enc_size = WavpackFinishBlock(wpc);
462 ci->enc_finish_chunk();
463 }
459 } 464 }
460 465
461 /* reset parameters to initial state */
462 ci->enc_set_parameters(NULL);
463
464 return CODEC_OK; 466 return CODEC_OK;
465} /* codec_start */ 467}
diff --git a/apps/codecs/wma.c b/apps/codecs/wma.c
index 1b46813444..c327fafb5a 100644
--- a/apps/codecs/wma.c
+++ b/apps/codecs/wma.c
@@ -29,53 +29,52 @@ CODEC_HEADER
29static WMADecodeContext wmadec; 29static WMADecodeContext wmadec;
30 30
31/* this is the codec entry point */ 31/* this is the codec entry point */
32enum codec_status codec_main(void) 32enum codec_status codec_main(enum codec_entry_call_reason reason)
33{
34 if (reason == CODEC_LOAD) {
35 /* Generic codec initialisation */
36 ci->configure(DSP_SET_SAMPLE_DEPTH, 29);
37 }
38
39 return CODEC_OK;
40}
41
42/* this is called for each file to process */
43enum codec_status codec_run(void)
33{ 44{
34 uint32_t elapsedtime; 45 uint32_t elapsedtime;
35 int retval;
36 asf_waveformatex_t wfx; 46 asf_waveformatex_t wfx;
37 size_t resume_offset; 47 size_t resume_offset;
38 int i; 48 int i;
39 int wmares, res; 49 int wmares;
50 int res = 0;
40 uint8_t* audiobuf; 51 uint8_t* audiobuf;
41 int audiobufsize; 52 int audiobufsize;
42 int packetlength = 0; 53 int packetlength = 0;
43 int errcount = 0; 54 int errcount = 0;
44 55 intptr_t param;
45 /* Generic codec initialisation */
46 ci->configure(DSP_SET_SAMPLE_DEPTH, 29);
47
48next_track:
49 retval = CODEC_OK;
50 56
51 /* Proper reset of the decoder context. */ 57 /* Proper reset of the decoder context. */
52 memset(&wmadec, 0, sizeof(wmadec)); 58 memset(&wmadec, 0, sizeof(wmadec));
53 59
54 /* Wait for the metadata to be read */
55 if (codec_wait_taginfo() != 0)
56 goto done;
57
58 /* Remember the resume position - when the codec is opened, the 60 /* Remember the resume position - when the codec is opened, the
59 playback engine will reset it. */ 61 playback engine will reset it. */
60 resume_offset = ci->id3->offset; 62 resume_offset = ci->id3->offset;
61 63
62restart_track: 64restart_track:
63 retval = CODEC_OK;
64
65 if (codec_init()) { 65 if (codec_init()) {
66 LOGF("WMA: Error initialising codec\n"); 66 LOGF("WMA: Error initialising codec\n");
67 retval = CODEC_ERROR; 67 return CODEC_ERROR;
68 goto exit;
69 } 68 }
70 69
71 /* Copy the format metadata we've stored in the id3 TOC field. This 70 /* Copy the format metadata we've stored in the id3 TOC field. This
72 saves us from parsing it again here. */ 71 saves us from parsing it again here. */
73 memcpy(&wfx, ci->id3->toc, sizeof(wfx)); 72 memcpy(&wfx, ci->id3->toc, sizeof(wfx));
74 73
74 ci->seek_buffer(ci->id3->first_frame_offset);
75 if (wma_decode_init(&wmadec,&wfx) < 0) { 75 if (wma_decode_init(&wmadec,&wfx) < 0) {
76 LOGF("WMA: Unsupported or corrupt file\n"); 76 LOGF("WMA: Unsupported or corrupt file\n");
77 retval = CODEC_ERROR; 77 return CODEC_ERROR;
78 goto exit;
79 } 78 }
80 79
81 if (resume_offset > ci->id3->first_frame_offset) 80 if (resume_offset > ci->id3->first_frame_offset)
@@ -101,34 +100,35 @@ restart_track:
101 codec_set_replaygain(ci->id3); 100 codec_set_replaygain(ci->id3);
102 101
103 /* The main decoding loop */ 102 /* The main decoding loop */
104
105 res = 1;
106 while (res >= 0) 103 while (res >= 0)
107 { 104 {
108 ci->yield(); 105 enum codec_command_action action = ci->get_command(&param);
109 if (ci->stop_codec || ci->new_track) { 106
110 goto done; 107 if (action == CODEC_ACTION_HALT)
111 } 108 break;
112 109
113 /* Deal with any pending seek requests */ 110 /* Deal with any pending seek requests */
114 if (ci->seek_time){ 111 if (action == CODEC_ACTION_SEEK_TIME) {
115 112
116 if (ci->seek_time == 1) { 113 if (param == 0) {
114 ci->set_elapsed(0);
117 ci->seek_complete(); 115 ci->seek_complete();
118 goto restart_track; /* Pretend you never saw this... */ 116 goto restart_track; /* Pretend you never saw this... */
119 } 117 }
120 118
121 elapsedtime = asf_seek(ci->seek_time, &wfx); 119 elapsedtime = asf_seek(param, &wfx);
122 if (elapsedtime < 1){ 120 if (elapsedtime < 1){
121 ci->set_elapsed(0);
123 ci->seek_complete(); 122 ci->seek_complete();
124 goto next_track; 123 break;
125 } 124 }
126 /*DEBUGF("Seek returned %d\n", (int)elapsedtime);*/ 125 /*DEBUGF("Seek returned %d\n", (int)elapsedtime);*/
127 ci->set_elapsed(elapsedtime);
128 126
129 /*flush the wma decoder state*/ 127 /*flush the wma decoder state*/
130 wmadec.last_superframe_len = 0; 128 wmadec.last_superframe_len = 0;
131 wmadec.last_bitoffset = 0; 129 wmadec.last_bitoffset = 0;
130
131 ci->set_elapsed(elapsedtime);
132 ci->seek_complete(); 132 ci->seek_complete();
133 } 133 }
134 errcount = 0; 134 errcount = 0;
@@ -140,10 +140,15 @@ new_packet:
140 * times. If we succeed, the error counter will be reset. 140 * times. If we succeed, the error counter will be reset.
141 */ 141 */
142 142
143 if (res == ASF_ERROR_EOF) {
144 /* File ended - not an error */
145 break;
146 }
147
143 errcount++; 148 errcount++;
144 DEBUGF("read_packet error %d, errcount %d\n",wmares, errcount); 149 DEBUGF("read_packet error %d, errcount %d\n",wmares, errcount);
145 if (errcount > 5) { 150 if (errcount > 5) {
146 goto done; 151 return CODEC_ERROR;
147 } else { 152 } else {
148 ci->advance_buffer(packetlength); 153 ci->advance_buffer(packetlength);
149 goto new_packet; 154 goto new_packet;
@@ -163,7 +168,7 @@ new_packet:
163 errcount++; 168 errcount++;
164 DEBUGF("WMA decode error %d, errcount %d\n",wmares, errcount); 169 DEBUGF("WMA decode error %d, errcount %d\n",wmares, errcount);
165 if (errcount > 5) { 170 if (errcount > 5) {
166 goto done; 171 return CODEC_ERROR;
167 } else { 172 } else {
168 ci->advance_buffer(packetlength); 173 ci->advance_buffer(packetlength);
169 goto new_packet; 174 goto new_packet;
@@ -173,18 +178,12 @@ new_packet:
173 elapsedtime += (wmares*10)/(wfx.rate/100); 178 elapsedtime += (wmares*10)/(wfx.rate/100);
174 ci->set_elapsed(elapsedtime); 179 ci->set_elapsed(elapsedtime);
175 } 180 }
176 ci->yield();
177 } 181 }
178 } 182 }
179 183
180 ci->advance_buffer(packetlength); 184 ci->advance_buffer(packetlength);
181 } 185 }
182 186
183done:
184 /*LOGF("WMA: Decoded %ld samples\n",elapsedtime*wfx.rate/1000);*/ 187 /*LOGF("WMA: Decoded %ld samples\n",elapsedtime*wfx.rate/1000);*/
185 188 return CODEC_OK;
186 if (ci->request_next_track())
187 goto next_track;
188exit:
189 return retval;
190} 189}
diff --git a/apps/codecs/wmapro.c b/apps/codecs/wmapro.c
index c02dddeeb3..b6a8e47f25 100644
--- a/apps/codecs/wmapro.c
+++ b/apps/codecs/wmapro.c
@@ -27,11 +27,22 @@ CODEC_HEADER
27 27
28int32_t *dec[2]; /* pointers to the output buffers in WMAProDecodeCtx in wmaprodec.c */ 28int32_t *dec[2]; /* pointers to the output buffers in WMAProDecodeCtx in wmaprodec.c */
29 29
30
30/* this is the codec entry point */ 31/* this is the codec entry point */
31enum codec_status codec_main(void) 32enum codec_status codec_main(enum codec_entry_call_reason reason)
33{
34 if (reason == CODEC_LOAD) {
35 /* Generic codec initialisation */
36 ci->configure(DSP_SET_SAMPLE_DEPTH, WMAPRO_DSP_SAMPLE_DEPTH);
37 }
38
39 return CODEC_OK;
40}
41
42/* this is called for each file to process */
43enum codec_status codec_run(void)
32{ 44{
33 uint32_t elapsedtime; 45 uint32_t elapsedtime;
34 int retval;
35 asf_waveformatex_t wfx; /* Holds the stream properties */ 46 asf_waveformatex_t wfx; /* Holds the stream properties */
36 size_t resume_offset; 47 size_t resume_offset;
37 int res; /* Return values from asf_read_packet() and decode_packet() */ 48 int res; /* Return values from asf_read_packet() and decode_packet() */
@@ -42,28 +53,15 @@ enum codec_status codec_main(void)
42 int pktcnt = 0; /* Count of the packets played */ 53 int pktcnt = 0; /* Count of the packets played */
43 uint8_t *data; /* Pointer to decoder input buffer */ 54 uint8_t *data; /* Pointer to decoder input buffer */
44 int size; /* Size of the input frame to the decoder */ 55 int size; /* Size of the input frame to the decoder */
45 56 intptr_t param;
46 /* Generic codec initialisation */
47 ci->configure(DSP_SET_SAMPLE_DEPTH, WMAPRO_DSP_SAMPLE_DEPTH);
48
49
50next_track:
51 retval = CODEC_OK;
52
53 /* Wait for the metadata to be read */
54 if (codec_wait_taginfo() != 0)
55 goto done;
56 57
57 /* Remember the resume position */ 58 /* Remember the resume position */
58 resume_offset = ci->id3->offset; 59 resume_offset = ci->id3->offset;
59 60
60restart_track: 61restart_track:
61 retval = CODEC_OK;
62
63 if (codec_init()) { 62 if (codec_init()) {
64 LOGF("(WMA PRO) Error: Error initialising codec\n"); 63 LOGF("(WMA PRO) Error: Error initialising codec\n");
65 retval = CODEC_ERROR; 64 return CODEC_ERROR;
66 goto done;
67 } 65 }
68 66
69 /* Copy the format metadata we've stored in the id3 TOC field. This 67 /* Copy the format metadata we've stored in the id3 TOC field. This
@@ -77,8 +75,7 @@ restart_track:
77 75
78 if (decode_init(&wfx) < 0) { 76 if (decode_init(&wfx) < 0) {
79 LOGF("(WMA PRO) Error: Unsupported or corrupt file\n"); 77 LOGF("(WMA PRO) Error: Unsupported or corrupt file\n");
80 retval = CODEC_ERROR; 78 return CODEC_ERROR;
81 goto done;
82 } 79 }
83 80
84 /* Now advance the file position to the first frame */ 81 /* Now advance the file position to the first frame */
@@ -91,23 +88,24 @@ restart_track:
91 88
92 while (pktcnt < wfx.numpackets) 89 while (pktcnt < wfx.numpackets)
93 { 90 {
94 ci->yield(); 91 enum codec_command_action action = ci->get_command(&param);
95 if (ci->stop_codec || ci->new_track) { 92
96 goto done; 93 if (action == CODEC_ACTION_HALT)
97 } 94 break;
98
99 /* Deal with any pending seek requests */
100 if (ci->seek_time){
101 95
102 if (ci->seek_time == 1) { 96 /* Deal with any pending seek requests */
97 if (action == CODEC_ACTION_SEEK_TIME) {
98 if (param == 0) {
99 ci->set_elapsed(0);
103 ci->seek_complete(); 100 ci->seek_complete();
104 goto restart_track; /* Pretend you never saw this... */ 101 goto restart_track; /* Pretend you never saw this... */
105 } 102 }
106 103
107 elapsedtime = asf_seek(ci->seek_time, &wfx); 104 elapsedtime = asf_seek(param, &wfx);
108 if (elapsedtime < 1){ 105 if (elapsedtime < 1){
106 ci->set_elapsed(0);
109 ci->seek_complete(); 107 ci->seek_complete();
110 goto next_track; 108 break;
111 } 109 }
112 110
113 ci->set_elapsed(elapsedtime); 111 ci->set_elapsed(elapsedtime);
@@ -117,8 +115,8 @@ restart_track:
117 res = asf_read_packet(&audiobuf, &audiobufsize, &packetlength, &wfx); 115 res = asf_read_packet(&audiobuf, &audiobufsize, &packetlength, &wfx);
118 116
119 if (res < 0) { 117 if (res < 0) {
120 LOGF("(WMA PRO) Warning: asf_read_packet returned %d", res); 118 LOGF("(WMA PRO) Warning: asf_read_packet returned %d", res);
121 goto done; 119 return CODEC_ERROR;
122 } else { 120 } else {
123 data = audiobuf; 121 data = audiobuf;
124 size = audiobufsize; 122 size = audiobufsize;
@@ -132,7 +130,7 @@ restart_track:
132 res = decode_packet(&wfx, dec, &outlen, data, size); 130 res = decode_packet(&wfx, dec, &outlen, data, size);
133 if(res < 0) { 131 if(res < 0) {
134 LOGF("(WMA PRO) Error: decode_packet returned %d", res); 132 LOGF("(WMA PRO) Error: decode_packet returned %d", res);
135 goto done; 133 return CODEC_ERROR;
136 } 134 }
137 data += res; 135 data += res;
138 size -= res; 136 size -= res;
@@ -152,10 +150,6 @@ restart_track:
152 ci->advance_buffer(packetlength); 150 ci->advance_buffer(packetlength);
153 } 151 }
154 152
155done: 153 return CODEC_OK;
156 if (ci->request_next_track())
157 goto next_track;
158
159 return retval;
160} 154}
161 155
diff --git a/apps/codecs/wmavoice.c b/apps/codecs/wmavoice.c
index ddf66828f1..64c8cd1692 100644
--- a/apps/codecs/wmavoice.c
+++ b/apps/codecs/wmavoice.c
@@ -52,10 +52,20 @@ static void init_codec_ctx(AVCodecContext *avctx, asf_waveformatex_t *wfx)
52} 52}
53 53
54/* this is the codec entry point */ 54/* this is the codec entry point */
55enum codec_status codec_main(void) 55enum codec_status codec_main(enum codec_entry_call_reason reason)
56{
57 if (reason == CODEC_LOAD) {
58 /* Generic codec initialisation */
59 ci->configure(DSP_SET_SAMPLE_DEPTH, 31);
60 }
61
62 return CODEC_OK;
63}
64
65/* this is called for each file to process */
66enum codec_status codec_run(void)
56{ 67{
57 uint32_t elapsedtime; 68 uint32_t elapsedtime;
58 int retval;
59 asf_waveformatex_t wfx; /* Holds the stream properties */ 69 asf_waveformatex_t wfx; /* Holds the stream properties */
60 size_t resume_offset; 70 size_t resume_offset;
61 int res; /* Return values from asf_read_packet() and decode_packet() */ 71 int res; /* Return values from asf_read_packet() and decode_packet() */
@@ -64,27 +74,14 @@ enum codec_status codec_main(void)
64 int packetlength = 0; /* Logical packet size (minus the header size) */ 74 int packetlength = 0; /* Logical packet size (minus the header size) */
65 int outlen = 0; /* Number of bytes written to the output buffer */ 75 int outlen = 0; /* Number of bytes written to the output buffer */
66 int pktcnt = 0; /* Count of the packets played */ 76 int pktcnt = 0; /* Count of the packets played */
67 77 intptr_t param;
68 /* Generic codec initialisation */
69 ci->configure(DSP_SET_SAMPLE_DEPTH, 31);
70
71
72next_track:
73 retval = CODEC_OK;
74
75 /* Wait for the metadata to be read */
76 if (codec_wait_taginfo() != 0)
77 goto done;
78 78
79 /* Remember the resume position */ 79 /* Remember the resume position */
80 resume_offset = ci->id3->offset; 80 resume_offset = ci->id3->offset;
81restart_track: 81restart_track:
82 retval = CODEC_OK;
83
84 if (codec_init()) { 82 if (codec_init()) {
85 LOGF("(WMA Voice) Error: Error initialising codec\n"); 83 LOGF("(WMA Voice) Error: Error initialising codec\n");
86 retval = CODEC_ERROR; 84 return CODEC_ERROR;
87 goto done;
88 } 85 }
89 86
90 /* Copy the format metadata we've stored in the id3 TOC field. This 87 /* Copy the format metadata we've stored in the id3 TOC field. This
@@ -97,14 +94,15 @@ restart_track:
97 ci->configure(DSP_SET_STEREO_MODE, wfx.channels == 1 ? 94 ci->configure(DSP_SET_STEREO_MODE, wfx.channels == 1 ?
98 STEREO_MONO : STEREO_INTERLEAVED); 95 STEREO_MONO : STEREO_INTERLEAVED);
99 codec_set_replaygain(ci->id3); 96 codec_set_replaygain(ci->id3);
97
98 ci->seek_buffer(0);
100 99
101 /* Initialise the AVCodecContext */ 100 /* Initialise the AVCodecContext */
102 init_codec_ctx(&avctx, &wfx); 101 init_codec_ctx(&avctx, &wfx);
103 102
104 if (wmavoice_decode_init(&avctx) < 0) { 103 if (wmavoice_decode_init(&avctx) < 0) {
105 LOGF("(WMA Voice) Error: Unsupported or corrupt file\n"); 104 LOGF("(WMA Voice) Error: Unsupported or corrupt file\n");
106 retval = CODEC_ERROR; 105 return CODEC_ERROR;
107 goto done;
108 } 106 }
109 107
110 /* Now advance the file position to the first frame */ 108 /* Now advance the file position to the first frame */
@@ -117,21 +115,24 @@ restart_track:
117 115
118 while (pktcnt < wfx.numpackets) 116 while (pktcnt < wfx.numpackets)
119 { 117 {
120 ci->yield(); 118 enum codec_command_action action = ci->get_command(&param);
121 if (ci->stop_codec || ci->new_track) { 119
122 goto done; 120 if (action == CODEC_ACTION_HALT)
123 } 121 break;
124 122
125 /* Deal with any pending seek requests */ 123 /* Deal with any pending seek requests */
126 if (ci->seek_time){ 124 if (action == CODEC_ACTION_SEEK_TIME) {
125 ci->set_elapsed(param);
127 126
128 if (ci->seek_time == 1) { 127 if (param == 0) {
128 ci->set_elapsed(0);
129 ci->seek_complete(); 129 ci->seek_complete();
130 goto restart_track; /* Pretend you never saw this... */ 130 goto restart_track; /* Pretend you never saw this... */
131 } 131 }
132 132
133 elapsedtime = asf_seek(ci->seek_time, &wfx); 133 elapsedtime = asf_seek(param, &wfx);
134 if (elapsedtime < 1){ 134 if (elapsedtime < 1){
135 ci->set_elapsed(0);
135 ci->seek_complete(); 136 ci->seek_complete();
136 goto next_track; 137 goto next_track;
137 } 138 }
@@ -145,7 +146,7 @@ new_packet:
145 146
146 if (res < 0) { 147 if (res < 0) {
147 LOGF("(WMA Voice) read_packet error %d\n",res); 148 LOGF("(WMA Voice) read_packet error %d\n",res);
148 goto done; 149 return CODEC_ERROR;
149 } else { 150 } else {
150 avpkt.data = audiobuf; 151 avpkt.data = audiobuf;
151 avpkt.size = audiobufsize; 152 avpkt.size = audiobufsize;
@@ -165,8 +166,9 @@ new_packet:
165 ci->advance_buffer(packetlength); 166 ci->advance_buffer(packetlength);
166 goto new_packet; 167 goto new_packet;
167 } 168 }
168 else 169 else {
169 goto done; 170 return CODEC_ERROR;
171 }
170 } 172 }
171 avpkt.data += res; 173 avpkt.data += res;
172 avpkt.size -= res; 174 avpkt.size -= res;
@@ -186,10 +188,6 @@ new_packet:
186 ci->advance_buffer(packetlength); 188 ci->advance_buffer(packetlength);
187 } 189 }
188 190
189done: 191 return CODEC_OK;
190 if (ci->request_next_track())
191 goto next_track;
192
193 return retval;
194} 192}
195 193
diff --git a/apps/gui/wps.c b/apps/gui/wps.c
index c33268e6bd..069df09c36 100644
--- a/apps/gui/wps.c
+++ b/apps/gui/wps.c
@@ -219,10 +219,10 @@ static int skintouch_to_wps(struct wps_data *data)
219#endif 219#endif
220 case ACTION_TOUCH_SCROLLBAR: 220 case ACTION_TOUCH_SCROLLBAR:
221 skin_get_global_state()->id3->elapsed = skin_get_global_state()->id3->length*offset/100; 221 skin_get_global_state()->id3->elapsed = skin_get_global_state()->id3->length*offset/100;
222 if (!skin_get_global_state()->paused)
223#if (CONFIG_CODEC == SWCODEC) 222#if (CONFIG_CODEC == SWCODEC)
224 audio_pre_ff_rewind(); 223 audio_pre_ff_rewind();
225#else 224#else
225 if (!skin_get_global_state()->paused)
226 audio_pause(); 226 audio_pause();
227#endif 227#endif
228 audio_ff_rewind(skin_get_global_state()->id3->elapsed); 228 audio_ff_rewind(skin_get_global_state()->id3->elapsed);
@@ -300,10 +300,10 @@ bool ffwd_rew(int button)
300 if ( (audio_status() & AUDIO_STATUS_PLAY) && 300 if ( (audio_status() & AUDIO_STATUS_PLAY) &&
301 skin_get_global_state()->id3 && skin_get_global_state()->id3->length ) 301 skin_get_global_state()->id3 && skin_get_global_state()->id3->length )
302 { 302 {
303 if (!skin_get_global_state()->paused)
304#if (CONFIG_CODEC == SWCODEC) 303#if (CONFIG_CODEC == SWCODEC)
305 audio_pre_ff_rewind(); 304 audio_pre_ff_rewind();
306#else 305#else
306 if (!skin_get_global_state()->paused)
307 audio_pause(); 307 audio_pause();
308#endif 308#endif
309#if CONFIG_KEYPAD == PLAYER_PAD 309#if CONFIG_KEYPAD == PLAYER_PAD
@@ -472,10 +472,10 @@ static void prev_track(unsigned long skip_thresh)
472 return; 472 return;
473 } 473 }
474 474
475 if (!state->paused)
476#if (CONFIG_CODEC == SWCODEC) 475#if (CONFIG_CODEC == SWCODEC)
477 audio_pre_ff_rewind(); 476 audio_pre_ff_rewind();
478#else 477#else
478 if (!state->paused)
479 audio_pause(); 479 audio_pause();
480#endif 480#endif
481 481
@@ -554,16 +554,20 @@ static void play_hop(int direction)
554 { 554 {
555 elapsed += step * direction; 555 elapsed += step * direction;
556 } 556 }
557 if((audio_status() & AUDIO_STATUS_PLAY) && !state->paused) 557 if(audio_status() & AUDIO_STATUS_PLAY)
558 { 558 {
559#if (CONFIG_CODEC == SWCODEC) 559#if (CONFIG_CODEC == SWCODEC)
560 audio_pre_ff_rewind(); 560 audio_pre_ff_rewind();
561#else 561#else
562 audio_pause(); 562 if (!state->paused)
563 audio_pause();
563#endif 564#endif
564 } 565 }
566
567#if (CONFIG_CODEC == SWCODEC)
568 audio_ff_rewind(elapsed);
569#else
565 audio_ff_rewind(state->id3->elapsed = elapsed); 570 audio_ff_rewind(state->id3->elapsed = elapsed);
566#if (CONFIG_CODEC != SWCODEC)
567 if (!state->paused) 571 if (!state->paused)
568 audio_resume(); 572 audio_resume();
569#endif 573#endif
@@ -849,10 +853,10 @@ long gui_wps_show(void)
849 { 853 {
850 if (state->id3->cuesheet) 854 if (state->id3->cuesheet)
851 { 855 {
852 if (!state->paused)
853#if (CONFIG_CODEC == SWCODEC) 856#if (CONFIG_CODEC == SWCODEC)
854 audio_pre_ff_rewind(); 857 audio_pre_ff_rewind();
855#else 858#else
859 if (!state->paused)
856 audio_pause(); 860 audio_pause();
857#endif 861#endif
858 audio_ff_rewind(0); 862 audio_ff_rewind(0);
@@ -1146,6 +1150,17 @@ static void nextid3available_callback(void* param)
1146 skin_request_full_update(WPS); 1150 skin_request_full_update(WPS);
1147} 1151}
1148 1152
1153#ifdef AUDIO_FAST_SKIP_PREVIEW
1154/* this is called on the audio_skip caller thread */
1155static void track_skip_callback(void *param)
1156{
1157 struct wps_state *state = skin_get_global_state();
1158 state->id3 = audio_current_track();
1159 state->nid3 = audio_next_track();
1160 skin_request_full_update(WPS);
1161 (void)param;
1162}
1163#endif /* AUDIO_FAST_SKIP_PREVIEW */
1149 1164
1150static void wps_state_init(void) 1165static void wps_state_init(void)
1151{ 1166{
@@ -1167,6 +1182,9 @@ static void wps_state_init(void)
1167 /* add the WPS track event callbacks */ 1182 /* add the WPS track event callbacks */
1168 add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, track_changed_callback); 1183 add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, track_changed_callback);
1169 add_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, false, nextid3available_callback); 1184 add_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, false, nextid3available_callback);
1185#ifdef AUDIO_FAST_SKIP_PREVIEW
1186 add_event(PLAYBACK_EVENT_TRACK_SKIP, false, track_skip_callback);
1187#endif
1170} 1188}
1171 1189
1172 1190
diff --git a/apps/menus/playback_menu.c b/apps/menus/playback_menu.c
index 9ed0bc5651..4153c1c776 100644
--- a/apps/menus/playback_menu.c
+++ b/apps/menus/playback_menu.c
@@ -159,9 +159,13 @@ static int cuesheet_callback(int action,const struct menu_item_ex *this_item)
159 switch (action) 159 switch (action)
160 { 160 {
161 case ACTION_EXIT_MENUITEM: /* on exit */ 161 case ACTION_EXIT_MENUITEM: /* on exit */
162#if CONFIG_CODEC == SWCODEC
163 audio_set_cuesheet(global_settings.cuesheet);
164#else
162 if (global_settings.cuesheet) 165 if (global_settings.cuesheet)
163 splash(HZ*2, ID2P(LANG_PLEASE_REBOOT)); 166 splash(HZ*2, ID2P(LANG_PLEASE_REBOOT));
164 break; 167 break;
168#endif
165 } 169 }
166 return action; 170 return action;
167} 171}
diff --git a/apps/metadata.c b/apps/metadata.c
index 46b9482bc7..e88603721b 100644
--- a/apps/metadata.c
+++ b/apps/metadata.c
@@ -33,7 +33,7 @@
33 33
34#if CONFIG_CODEC == SWCODEC 34#if CONFIG_CODEC == SWCODEC
35 35
36/* For trailing tag stripping */ 36/* For trailing tag stripping and base audio data types */
37#include "buffering.h" 37#include "buffering.h"
38 38
39#include "metadata/metadata_common.h" 39#include "metadata/metadata_common.h"
@@ -239,6 +239,94 @@ const int afmt_rec_format[AFMT_NUM_CODECS] =
239}; 239};
240#endif /* CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) */ 240#endif /* CONFIG_CODEC == SWCODEC && defined (HAVE_RECORDING) */
241 241
242#if CONFIG_CODEC == SWCODEC
243/* Get the canonical AFMT type */
244int get_audio_base_codec_type(int type)
245{
246 int base_type = type;
247 switch (type) {
248 case AFMT_MPA_L1:
249 case AFMT_MPA_L2:
250 case AFMT_MPA_L3:
251 base_type = AFMT_MPA_L3;
252 break;
253 case AFMT_MPC_SV7:
254 case AFMT_MPC_SV8:
255 base_type = AFMT_MPC_SV7;
256 break;
257 case AFMT_MP4_AAC:
258 case AFMT_MP4_AAC_HE:
259 base_type = AFMT_MP4_AAC;
260 break;
261 case AFMT_SAP:
262 case AFMT_CMC:
263 case AFMT_CM3:
264 case AFMT_CMR:
265 case AFMT_CMS:
266 case AFMT_DMC:
267 case AFMT_DLT:
268 case AFMT_MPT:
269 case AFMT_MPD:
270 case AFMT_RMT:
271 case AFMT_TMC:
272 case AFMT_TM8:
273 case AFMT_TM2:
274 base_type = AFMT_SAP;
275 break;
276 default:
277 break;
278 }
279
280 return base_type;
281}
282
283/* Get the basic audio type */
284enum data_type get_audio_base_data_type(int afmt)
285{
286 if ((unsigned)afmt >= AFMT_NUM_CODECS)
287 return TYPE_UNKNOWN;
288
289 switch (get_audio_base_codec_type(afmt))
290 {
291 case AFMT_NSF:
292 case AFMT_SPC:
293 case AFMT_SID:
294 case AFMT_MOD:
295 case AFMT_SAP:
296 /* Type must be allocated and loaded in its entirety onto
297 the buffer */
298 return TYPE_ATOMIC_AUDIO;
299
300 default:
301 /* Assume type may be loaded and discarded incrementally */
302 return TYPE_PACKET_AUDIO;
303
304 case AFMT_UNKNOWN:
305 /* Have no idea at all */
306 return TYPE_UNKNOWN;
307 }
308}
309
310/* Is the format allowed to buffer starting at some offset other than 0
311 or first frame only for resume purposes? */
312bool format_buffers_with_offset(int afmt)
313{
314 switch (afmt)
315 {
316 case AFMT_MPA_L1:
317 case AFMT_MPA_L2:
318 case AFMT_MPA_L3:
319 case AFMT_WAVPACK:
320 /* Format may be loaded at the first needed frame */
321 return true;
322 default:
323 /* Format must be loaded from the beginning of the file
324 (does not imply 'atomic', while 'atomic' implies 'no offset') */
325 return false;
326 }
327}
328#endif /* CONFIG_CODEC == SWCODEC */
329
242 330
243/* Simple file type probing by looking at the filename extension. */ 331/* Simple file type probing by looking at the filename extension. */
244unsigned int probe_file_format(const char *filename) 332unsigned int probe_file_format(const char *filename)
@@ -313,7 +401,7 @@ bool get_metadata(struct mp3entry* id3, int fd, const char* trackname)
313 } 401 }
314 402
315 /* Clear the mp3entry to avoid having bogus pointers appear */ 403 /* Clear the mp3entry to avoid having bogus pointers appear */
316 memset(id3, 0, sizeof(struct mp3entry)); 404 wipe_mp3entry(id3);
317 405
318 /* Take our best guess at the codec type based on file extension */ 406 /* Take our best guess at the codec type based on file extension */
319 id3->codectype = probe_file_format(trackname); 407 id3->codectype = probe_file_format(trackname);
@@ -414,6 +502,44 @@ void copy_mp3entry(struct mp3entry *dest, const struct mp3entry *orig)
414 adjust_mp3entry(dest, dest, orig); 502 adjust_mp3entry(dest, dest, orig);
415} 503}
416 504
505/* A shortcut to simplify the common task of clearing the struct */
506void wipe_mp3entry(struct mp3entry *id3)
507{
508 memset(id3, 0, sizeof (struct mp3entry));
509}
510
511#if CONFIG_CODEC == SWCODEC
512/* Glean what is possible from the filename alone - does not parse metadata */
513void fill_metadata_from_path(struct mp3entry *id3, const char *trackname)
514{
515 char *p;
516
517 /* Clear the mp3entry to avoid having bogus pointers appear */
518 wipe_mp3entry(id3);
519
520 /* Find the filename portion of the path */
521 p = strrchr(trackname, '/');
522 strlcpy(id3->id3v2buf, p ? ++p : id3->path, ID3V2_BUF_SIZE);
523
524 /* Get the format from the extension and trim it off */
525 p = strrchr(id3->id3v2buf, '.');
526 if (p)
527 {
528 /* Might be wrong for container formats - should we bother? */
529 id3->codectype = probe_file_format(p);
530
531 if (id3->codectype != AFMT_UNKNOWN)
532 *p = '\0';
533 }
534
535 /* Set the filename as the title */
536 id3->title = id3->id3v2buf;
537
538 /* Copy the path info */
539 strlcpy(id3->path, trackname, sizeof (id3->path));
540}
541#endif /* CONFIG_CODEC == SWCODEC */
542
417#ifndef __PCTOOL__ 543#ifndef __PCTOOL__
418#ifdef HAVE_TAGCACHE 544#ifdef HAVE_TAGCACHE
419#if CONFIG_CODEC == SWCODEC 545#if CONFIG_CODEC == SWCODEC
diff --git a/apps/metadata.h b/apps/metadata.h
index c22c1b3ecf..b268a3d474 100644
--- a/apps/metadata.h
+++ b/apps/metadata.h
@@ -266,9 +266,7 @@ struct mp3entry {
266 266
267 /* resume related */ 267 /* resume related */
268 unsigned long offset; /* bytes played */ 268 unsigned long offset; /* bytes played */
269#if CONFIG_CODEC != SWCODEC
270 int index; /* playlist index */ 269 int index; /* playlist index */
271#endif
272 270
273#ifdef HAVE_TAGCACHE 271#ifdef HAVE_TAGCACHE
274 unsigned char autoresumable; /* caches result of autoresumable() */ 272 unsigned char autoresumable; /* caches result of autoresumable() */
@@ -309,9 +307,14 @@ bool get_metadata(struct mp3entry* id3, int fd, const char* trackname);
309bool mp3info(struct mp3entry *entry, const char *filename); 307bool mp3info(struct mp3entry *entry, const char *filename);
310void adjust_mp3entry(struct mp3entry *entry, void *dest, const void *orig); 308void adjust_mp3entry(struct mp3entry *entry, void *dest, const void *orig);
311void copy_mp3entry(struct mp3entry *dest, const struct mp3entry *orig); 309void copy_mp3entry(struct mp3entry *dest, const struct mp3entry *orig);
310void wipe_mp3entry(struct mp3entry *id3);
312 311
313#if CONFIG_CODEC == SWCODEC 312#if CONFIG_CODEC == SWCODEC
313void fill_metadata_from_path(struct mp3entry *id3, const char *trackname);
314int get_audio_base_codec_type(int type);
314void strip_tags(int handle_id); 315void strip_tags(int handle_id);
316enum data_type get_audio_base_data_type(int afmt);
317bool format_buffers_with_offset(int afmt);
315#endif 318#endif
316 319
317#ifdef HAVE_TAGCACHE 320#ifdef HAVE_TAGCACHE
diff --git a/apps/metadata/nsf.c b/apps/metadata/nsf.c
index abb4e6fd80..9207a14048 100644
--- a/apps/metadata/nsf.c
+++ b/apps/metadata/nsf.c
@@ -40,6 +40,9 @@ bool get_nsf_metadata(int fd, struct mp3entry* id3)
40 40
41 p = id3->id3v2buf; 41 p = id3->id3v2buf;
42 42
43 /* Length */
44 id3->length = buf[6]*1000;
45
43 /* Title */ 46 /* Title */
44 memcpy(p, &buf[14], 32); 47 memcpy(p, &buf[14], 32);
45 id3->title = p; 48 id3->title = p;
diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c
index f548b156b3..c7baad08e4 100644
--- a/apps/pcmbuf.c
+++ b/apps/pcmbuf.c
@@ -86,6 +86,8 @@ static size_t pcmbuffer_pos IDATA_ATTR;
86/* Amount pcmbuffer_pos will be increased.*/ 86/* Amount pcmbuffer_pos will be increased.*/
87static size_t pcmbuffer_fillpos IDATA_ATTR; 87static size_t pcmbuffer_fillpos IDATA_ATTR;
88 88
89static struct chunkdesc *first_desc;
90
89/* Gapless playback */ 91/* Gapless playback */
90static bool track_transition IDATA_ATTR; 92static bool track_transition IDATA_ATTR;
91 93
@@ -144,6 +146,11 @@ static void write_to_crossfade(size_t length);
144static void pcmbuf_finish_crossfade_enable(void); 146static void pcmbuf_finish_crossfade_enable(void);
145#endif 147#endif
146 148
149/* Callbacks into playback.c */
150extern void audio_pcmbuf_position_callback(unsigned int time);
151extern void audio_pcmbuf_track_change(bool pcmbuf);
152extern bool audio_pcmbuf_may_play(void);
153
147 154
148/**************************************/ 155/**************************************/
149 156
@@ -153,9 +160,8 @@ static void pcmbuf_finish_crossfade_enable(void);
153#ifndef SIMULATOR 160#ifndef SIMULATOR
154#undef DESC_DEBUG 161#undef DESC_DEBUG
155#endif 162#endif
163
156#ifdef DESC_DEBUG 164#ifdef DESC_DEBUG
157static struct chunkdesc *first_desc;
158static bool show_desc_in_use = false;
159#define DISPLAY_DESC(caller) while(!show_desc(caller)) 165#define DISPLAY_DESC(caller) while(!show_desc(caller))
160#define DESC_IDX(desc) (desc ? desc - first_desc : -1) 166#define DESC_IDX(desc) (desc ? desc - first_desc : -1)
161#define SHOW_DESC(desc) if(DESC_IDX(desc)==-1) DEBUGF("--"); \ 167#define SHOW_DESC(desc) if(DESC_IDX(desc)==-1) DEBUGF("--"); \
@@ -231,6 +237,7 @@ static void commit_chunk(bool flush_next_time)
231 /* Flush! Discard all data after the currently playing chunk, 237 /* Flush! Discard all data after the currently playing chunk,
232 and make the current chunk play next */ 238 and make the current chunk play next */
233 logf("commit_chunk: flush"); 239 logf("commit_chunk: flush");
240 pcm_play_lock();
234 write_end_chunk->link = read_chunk->link; 241 write_end_chunk->link = read_chunk->link;
235 read_chunk->link = pcmbuf_current; 242 read_chunk->link = pcmbuf_current;
236 while (write_end_chunk->link) 243 while (write_end_chunk->link)
@@ -238,6 +245,9 @@ static void commit_chunk(bool flush_next_time)
238 write_end_chunk = write_end_chunk->link; 245 write_end_chunk = write_end_chunk->link;
239 pcmbuf_unplayed_bytes -= write_end_chunk->size; 246 pcmbuf_unplayed_bytes -= write_end_chunk->size;
240 } 247 }
248
249 read_chunk->end_of_track = track_transition;
250 pcm_play_unlock();
241 } 251 }
242 /* If there is already a read buffer setup, add to it */ 252 /* If there is already a read buffer setup, add to it */
243 else 253 else
@@ -248,7 +258,7 @@ static void commit_chunk(bool flush_next_time)
248 /* Otherwise create the buffer */ 258 /* Otherwise create the buffer */
249 read_chunk = pcmbuf_current; 259 read_chunk = pcmbuf_current;
250 } 260 }
251 261
252 /* If flush_next_time is true, then the current chunk will be thrown out 262 /* If flush_next_time is true, then the current chunk will be thrown out
253 * and the next chunk to be committed will be the next to be played. 263 * and the next chunk to be committed will be the next to be played.
254 * This is used to empty the PCM buffer for a track change. */ 264 * This is used to empty the PCM buffer for a track change. */
@@ -354,7 +364,7 @@ static bool prepare_insert(size_t length)
354#endif 364#endif
355 { 365 {
356 logf("pcm starting"); 366 logf("pcm starting");
357 if (!(audio_status() & AUDIO_STATUS_PAUSE)) 367 if (audio_pcmbuf_may_play())
358 pcmbuf_play_start(); 368 pcmbuf_play_start();
359 } 369 }
360 } 370 }
@@ -373,8 +383,12 @@ void *pcmbuf_request_buffer(int *count)
373 /* crossfade has begun, put the new track samples in fadebuf */ 383 /* crossfade has begun, put the new track samples in fadebuf */
374 if (crossfade_active) 384 if (crossfade_active)
375 { 385 {
376 *count = MIN(*count, CROSSFADE_BUFSIZE/4); 386 int cnt = MIN(*count, CROSSFADE_BUFSIZE/4);
377 return fadebuf; 387 if (prepare_insert(cnt << 2))
388 {
389 *count = cnt;
390 return fadebuf;
391 }
378 } 392 }
379 else 393 else
380#endif 394#endif
@@ -421,9 +435,7 @@ void pcmbuf_write_complete(int count)
421 435
422static inline void init_pcmbuffers(void) 436static inline void init_pcmbuffers(void)
423{ 437{
424#ifdef DESC_DEBUG
425 first_desc = write_chunk; 438 first_desc = write_chunk;
426#endif
427 struct chunkdesc *next = write_chunk; 439 struct chunkdesc *next = write_chunk;
428 next++; 440 next++;
429 write_end_chunk = write_chunk; 441 write_end_chunk = write_chunk;
@@ -494,19 +506,27 @@ void pcmbuf_monitor_track_change(bool monitor)
494 currently playing chunk. If not, cancel notification. */ 506 currently playing chunk. If not, cancel notification. */
495 track_transition = monitor; 507 track_transition = monitor;
496 read_end_chunk->end_of_track = monitor; 508 read_end_chunk->end_of_track = monitor;
509 if (!monitor)
510 {
511 /* Clear all notifications */
512 struct chunkdesc *desc = first_desc;
513 struct chunkdesc *end = desc + pcmbuf_descs();
514 while (desc < end)
515 desc++->end_of_track = false;
516 }
497 } 517 }
498 else 518 else
499 { 519 {
500 /* Post now if PCM stopped and last buffer was sent. */ 520 /* Post now if PCM stopped and last buffer was sent. */
501 track_transition = false; 521 track_transition = false;
502 if (monitor) 522 if (monitor)
503 audio_post_track_change(false); 523 audio_pcmbuf_track_change(false);
504 } 524 }
505 525
506 pcm_play_unlock(); 526 pcm_play_unlock();
507} 527}
508 528
509void pcmbuf_start_track_change(bool auto_skip) 529bool pcmbuf_start_track_change(bool auto_skip)
510{ 530{
511 bool crossfade = false; 531 bool crossfade = false;
512#ifdef HAVE_CROSSFADE 532#ifdef HAVE_CROSSFADE
@@ -546,9 +566,6 @@ void pcmbuf_start_track_change(bool auto_skip)
546 566
547 /* Cancel any pending automatic gapless transition */ 567 /* Cancel any pending automatic gapless transition */
548 pcmbuf_monitor_track_change(false); 568 pcmbuf_monitor_track_change(false);
549
550 /* Notify the wps that the track change starts now */
551 audio_post_track_change(false);
552 569
553 /* Can't do two crossfades at once and, no fade if pcm is off now */ 570 /* Can't do two crossfades at once and, no fade if pcm is off now */
554 if ( 571 if (
@@ -559,7 +576,8 @@ void pcmbuf_start_track_change(bool auto_skip)
559 { 576 {
560 pcmbuf_play_stop(); 577 pcmbuf_play_stop();
561 pcm_play_unlock(); 578 pcm_play_unlock();
562 return; 579 /* Notify playback that the track change starts now */
580 return true;
563 } 581 }
564 582
565 /* Not enough data, or not crossfading, flush the old data instead */ 583 /* Not enough data, or not crossfading, flush the old data instead */
@@ -584,6 +602,9 @@ void pcmbuf_start_track_change(bool auto_skip)
584 /* Keep trigger outside the play lock or HW FIFO underruns can happen 602 /* Keep trigger outside the play lock or HW FIFO underruns can happen
585 since frequency scaling is *not* always fast */ 603 since frequency scaling is *not* always fast */
586 trigger_cpu_boost(); 604 trigger_cpu_boost();
605
606 /* Notify playback that the track change starts now */
607 return true;
587 } 608 }
588 else /* automatic and not crossfading, so do gapless track change */ 609 else /* automatic and not crossfading, so do gapless track change */
589 { 610 {
@@ -593,6 +614,7 @@ void pcmbuf_start_track_change(bool auto_skip)
593 * as the last one in the track. */ 614 * as the last one in the track. */
594 logf(" gapless track change"); 615 logf(" gapless track change");
595 pcmbuf_monitor_track_change(true); 616 pcmbuf_monitor_track_change(true);
617 return false;
596 } 618 }
597} 619}
598 620
@@ -623,7 +645,7 @@ static void pcmbuf_pcm_callback(unsigned char** start, size_t* size)
623 if (pcmbuf_current->end_of_track) 645 if (pcmbuf_current->end_of_track)
624 { 646 {
625 track_transition = false; 647 track_transition = false;
626 audio_post_track_change(true); 648 audio_pcmbuf_track_change(true);
627 } 649 }
628 650
629 /* Put the finished chunk back into circulation */ 651 /* Put the finished chunk back into circulation */
@@ -955,9 +977,6 @@ static void write_to_crossfade(size_t length)
955 return; 977 return;
956 } 978 }
957 979
958 /* Commit samples to the buffer */
959 while (!prepare_insert(length))
960 sleep(1);
961 while (length > 0) 980 while (length > 0)
962 { 981 {
963 COMMIT_IF_NEEDED; 982 COMMIT_IF_NEEDED;
diff --git a/apps/pcmbuf.h b/apps/pcmbuf.h
index 618b1babad..b7bf8c2b16 100644
--- a/apps/pcmbuf.h
+++ b/apps/pcmbuf.h
@@ -33,13 +33,21 @@ void pcmbuf_play_start(void);
33void pcmbuf_play_stop(void); 33void pcmbuf_play_stop(void);
34void pcmbuf_pause(bool pause); 34void pcmbuf_pause(bool pause);
35void pcmbuf_monitor_track_change(bool monitor); 35void pcmbuf_monitor_track_change(bool monitor);
36void pcmbuf_start_track_change(bool manual_skip); 36bool pcmbuf_start_track_change(bool manual_skip);
37 37
38/* Crossfade */ 38/* Crossfade */
39#ifdef HAVE_CROSSFADE 39#ifdef HAVE_CROSSFADE
40bool pcmbuf_is_crossfade_active(void); 40bool pcmbuf_is_crossfade_active(void);
41void pcmbuf_request_crossfade_enable(bool on_off); 41void pcmbuf_request_crossfade_enable(bool on_off);
42bool pcmbuf_is_same_size(void); 42bool pcmbuf_is_same_size(void);
43#else
44/* Dummy functions with sensible returns */
45static inline bool pcmbuf_is_crossfade_active(void)
46 { return false; }
47static inline void pcmbuf_request_crossfade_enable(bool on_off)
48 { return; (void)on_off; }
49static inline bool pcmbuf_is_same_size(void)
50 { return true; }
43#endif 51#endif
44 52
45/* Voice */ 53/* Voice */
diff --git a/apps/playback.c b/apps/playback.c
index 632fd05d3d..a369d15715 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -9,6 +9,7 @@
9 * 9 *
10 * Copyright (C) 2005-2007 Miika Pekkarinen 10 * Copyright (C) 2005-2007 Miika Pekkarinen
11 * Copyright (C) 2007-2008 Nicolas Pennequin 11 * Copyright (C) 2007-2008 Nicolas Pennequin
12 * Copyright (C) 2011 Michael Sevakis
12 * 13 *
13 * This program is free software; you can redistribute it and/or 14 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License 15 * modify it under the terms of the GNU General Public License
@@ -19,53 +20,61 @@
19 * KIND, either express or implied. 20 * KIND, either express or implied.
20 * 21 *
21 ****************************************************************************/ 22 ****************************************************************************/
22
23/* TODO: Pause should be handled in here, rather than PCMBUF so that voice can
24 * play whilst audio is paused */
25#include "config.h" 23#include "config.h"
26#include "system.h" 24#include "system.h"
27#include <string.h>
28#include "playback.h"
29#include "codec_thread.h"
30#include "kernel.h" 25#include "kernel.h"
26#include "panic.h"
27#include "buffer.h"
28#include "sound.h"
29#include "ata.h"
30#include "usb.h"
31#include "codecs.h" 31#include "codecs.h"
32#include "buffering.h" 32#include "codec_thread.h"
33#include "voice_thread.h" 33#include "voice_thread.h"
34#include "usb.h" 34#include "metadata.h"
35#include "ata.h" 35#include "cuesheet.h"
36#include "buffering.h"
37#include "talk.h"
36#include "playlist.h" 38#include "playlist.h"
39#include "abrepeat.h"
37#include "pcmbuf.h" 40#include "pcmbuf.h"
38#include "buffer.h" 41#include "playback.h"
39#include "cuesheet.h" 42
40#ifdef HAVE_TAGCACHE 43#ifdef HAVE_TAGCACHE
41#include "tagcache.h" 44#include "tagcache.h"
42#endif 45#endif
46
47#ifdef AUDIO_HAVE_RECORDING
48#include "pcm_record.h"
49#endif
50
43#ifdef HAVE_LCD_BITMAP 51#ifdef HAVE_LCD_BITMAP
44#ifdef HAVE_ALBUMART 52#ifdef HAVE_ALBUMART
45#include "albumart.h" 53#include "albumart.h"
46#endif 54#endif
47#endif 55#endif
48#include "sound.h"
49#include "metadata.h"
50#include "splash.h"
51#include "talk.h"
52#include "panic.h"
53 56
54#ifdef HAVE_RECORDING 57/* TODO: The audio thread really is doing multitasking of acting like a
55#include "pcm_record.h" 58 consumer and producer of tracks. It may be advantageous to better
56#endif 59 logically separate the two functions. I won't go that far just yet. */
57 60
61/* Internal support for voice playback */
58#define PLAYBACK_VOICE 62#define PLAYBACK_VOICE
59 63
60/* amount of guess-space to allow for codecs that must hunt and peck 64#if CONFIG_PLATFORM & PLATFORM_NATIVE
61 * for their correct seeek target, 32k seems a good size */ 65/* Application builds don't support direct code loading */
66#define HAVE_CODEC_BUFFERING
67#endif
68
69/* Amount of guess-space to allow for codecs that must hunt and peck
70 * for their correct seek target, 32k seems a good size */
62#define AUDIO_REBUFFER_GUESS_SIZE (1024*32) 71#define AUDIO_REBUFFER_GUESS_SIZE (1024*32)
63 72
64/* Define LOGF_ENABLE to enable logf output in this file */ 73/* Define LOGF_ENABLE to enable logf output in this file */
65/*#define LOGF_ENABLE*/ 74/* #define LOGF_ENABLE */
66#include "logf.h" 75#include "logf.h"
67 76
68/* macros to enable logf for queues 77/* Macros to enable logf for queues
69 logging on SYS_TIMEOUT can be disabled */ 78 logging on SYS_TIMEOUT can be disabled */
70#ifdef SIMULATOR 79#ifdef SIMULATOR
71/* Define this for logf output of all queuing except SYS_TIMEOUT */ 80/* Define this for logf output of all queuing except SYS_TIMEOUT */
@@ -86,202 +95,292 @@
86#define LOGFQUEUE_SYS_TIMEOUT(...) 95#define LOGFQUEUE_SYS_TIMEOUT(...)
87#endif 96#endif
88 97
98/* Variables are commented with the threads that use them:
99 * A=audio, C=codec, O=other. A suffix of "-" indicates that the variable is
100 * read but not updated on that thread. Audio is the only user unless otherwise
101 * specified.
102 */
89 103
90static enum filling_state { 104/** Miscellaneous **/
91 STATE_IDLE, /* audio is stopped: nothing to do */ 105bool audio_is_initialized = false; /* (A,O-) */
92 STATE_FILLING, /* adding tracks to the buffer */ 106extern struct codec_api ci; /* (A,C) */
93 STATE_FULL, /* can't add any more tracks */ 107
94 STATE_END_OF_PLAYLIST, /* all remaining tracks have been added */ 108/** Possible arrangements of the main buffer **/
95 STATE_FINISHED, /* all remaining tracks are fully buffered */ 109static enum audio_buffer_state
96 STATE_ENDING, /* audio playback is ending */ 110{
97#if (CONFIG_PLATFORM & PLATFORM_NATIVE) 111 AUDIOBUF_STATE_TRASHED = -1, /* trashed; must be reset */
98 STATE_USB, /* USB mode, ignore most messages */ 112 AUDIOBUF_STATE_INITIALIZED = 0, /* voice+audio OR audio-only */
113 AUDIOBUF_STATE_VOICED_ONLY = 1, /* voice-only */
114} buffer_state = AUDIOBUF_STATE_TRASHED; /* (A,O) */
115
116/** Main state control **/
117static bool ff_rw_mode SHAREDBSS_ATTR = false; /* Pre-ff-rewind mode (A,O-) */
118
119enum play_status
120{
121 PLAY_STOPPED = 0,
122 PLAY_PLAYING = AUDIO_STATUS_PLAY,
123 PLAY_PAUSED = AUDIO_STATUS_PLAY | AUDIO_STATUS_PAUSE,
124} play_status = PLAY_STOPPED;
125
126/* Sizeable things that only need exist during playback and not when stopped */
127static struct audio_scratch_memory
128{
129 struct mp3entry codec_id3; /* (A,C) */
130 struct mp3entry unbuffered_id3;
131 struct cuesheet *curr_cue; /* Will follow this structure */
132} * audio_scratch_memory = NULL;
133
134/* These are used to store the current, next and optionally the peek-ahead
135 * mp3entry's - this guarentees that the pointer returned by audio_current/
136 * next_track will be valid for the full duration of the currently playing
137 * track */
138enum audio_id3_types
139{
140 /* These are allocated statically */
141 PLAYING_ID3 = 0,
142 NEXTTRACK_ID3,
143#ifdef AUDIO_FAST_SKIP_PREVIEW
144 /* The real playing metadata must has to be protected since it contains
145 critical info for other features */
146 PLAYING_PEEK_ID3,
99#endif 147#endif
100} filling; 148 ID3_TYPE_NUM_STATIC,
101 149 /* These go in the scratch memory */
102/* As defined in plugins/lib/xxx2wav.h */ 150 UNBUFFERED_ID3 = ID3_TYPE_NUM_STATIC,
103#define GUARD_BUFSIZE (32*1024) 151 CODEC_ID3,
104 152};
105bool audio_is_initialized = false; 153static struct mp3entry static_id3_entries[ID3_TYPE_NUM_STATIC]; /* (A,O) */
106static bool audio_thread_ready SHAREDBSS_ATTR = false;
107 154
108/* Variables are commented with the threads that use them: * 155/* Peeking functions can yield and mess us up */
109 * A=audio, C=codec, V=voice. A suffix of - indicates that * 156static struct mutex id3_mutex SHAREDBSS_ATTR; /* (A,0)*/
110 * the variable is read but not updated on that thread. */
111/* TBD: Split out "audio" and "playback" (ie. calling) threads */
112 157
113/* Main state control */
114static volatile bool playing SHAREDBSS_ATTR = false;/* Is audio playing? (A) */
115static volatile bool paused SHAREDBSS_ATTR = false; /* Is audio paused? (A/C-) */
116 158
117/* Ring buffer where compressed audio and codecs are loaded */ 159/** For Scrobbler support **/
118static unsigned char *filebuf = NULL; /* Start of buffer (A/C-) */
119static size_t filebuflen = 0; /* Size of buffer (A/C-) */
120/* FIXME: make buf_ridx (C/A-) */
121 160
122/* Possible arrangements of the buffer */ 161/* Previous track elapsed time */
123enum audio_buffer_state 162static unsigned long prev_track_elapsed = 0; /* (A,O-) */
124{
125 AUDIOBUF_STATE_TRASHED = -1, /* trashed; must be reset */
126 AUDIOBUF_STATE_INITIALIZED = 0, /* voice+audio OR audio-only */
127 AUDIOBUF_STATE_VOICED_ONLY = 1, /* voice-only */
128};
129static int buffer_state = AUDIOBUF_STATE_TRASHED; /* Buffer state */
130
131/* These are used to store the current and next (or prev if the current is the last)
132 * mp3entry's in a round-robin system. This guarentees that the pointer returned
133 * by audio_current/next_track will be valid for the full duration of the
134 * currently playing track */
135static struct mp3entry mp3entry_buf[2];
136struct mp3entry *thistrack_id3, /* the currently playing track */
137 *othertrack_id3; /* prev track during track-change-transition, or end of playlist,
138 * next track otherwise */
139static struct mp3entry unbuffered_id3; /* the id3 for the first unbuffered track */
140
141/* for cuesheet support */
142static struct cuesheet *curr_cue = NULL;
143 163
144 164
165/** For album art support **/
145#define MAX_MULTIPLE_AA SKINNABLE_SCREENS_COUNT 166#define MAX_MULTIPLE_AA SKINNABLE_SCREENS_COUNT
146
147#ifdef HAVE_ALBUMART 167#ifdef HAVE_ALBUMART
148 168
149static struct albumart_slot { 169static struct albumart_slot
150 struct dim dim; /* holds width, height of the albumart */ 170{
151 int used; /* counter, increments if something uses it */ 171 struct dim dim; /* Holds width, height of the albumart */
152} albumart_slots[MAX_MULTIPLE_AA]; 172 int used; /* Counter; increments if something uses it */
173} albumart_slots[MAX_MULTIPLE_AA]; /* (A,O) */
153 174
154#define FOREACH_ALBUMART(i) for(i = 0;i < MAX_MULTIPLE_AA; i++) 175#define FOREACH_ALBUMART(i) for(i = 0;i < MAX_MULTIPLE_AA; i++)
155#endif 176#endif /* HAVE_ALBUMART */
156 177
157 178
158#define MAX_TRACK 128 179/** Information used for tracking buffer fills **/
159#define MAX_TRACK_MASK (MAX_TRACK-1)
160 180
161/* Track info structure about songs in the file buffer (A/C-) */ 181/* Buffer and thread state tracking */
162static struct track_info { 182static enum filling_state
163 int audio_hid; /* The ID for the track's buffer handle */ 183{
164 int id3_hid; /* The ID for the track's metadata handle */ 184 STATE_BOOT = 0, /* audio thread is not ready yet */
165 int codec_hid; /* The ID for the track's codec handle */ 185 STATE_IDLE, /* audio is stopped: nothing to do */
166#ifdef HAVE_ALBUMART 186 STATE_FILLING, /* adding tracks to the buffer */
167 int aa_hid[MAX_MULTIPLE_AA];/* The ID for the track's album art handle */ 187 STATE_FULL, /* can't add any more tracks */
188 STATE_END_OF_PLAYLIST, /* all remaining tracks have been added */
189 STATE_FINISHED, /* all remaining tracks are fully buffered */
190 STATE_ENDING, /* audio playback is ending */
191 STATE_ENDED, /* audio playback is done */
192#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
193 STATE_USB, /* USB mode, ignore most messages */
168#endif 194#endif
169 int cuesheet_hid; /* The ID for the track's parsed cueesheet handle */ 195} filling = STATE_BOOT;
170 196
171 size_t filesize; /* File total length */ 197/* Track info - holds information about each track in the buffer */
198struct track_info
199{
200 /* In per-track allocated order: */
201 int id3_hid; /* Metadata handle ID */
202 int cuesheet_hid; /* Parsed cueesheet handle ID */
203#ifdef HAVE_ALBUMART
204 int aa_hid[MAX_MULTIPLE_AA];/* Album art handle IDs */
205#endif
206#ifdef HAVE_CODEC_BUFFERING
207 int codec_hid; /* Buffered codec handle ID */
208#endif
209 int audio_hid; /* Main audio data handle ID */
210 size_t filesize; /* File total length on disk
211 TODO: This should be stored
212 in the handle or the
213 id3 and would use less
214 ram */
215};
172 216
173 bool taginfo_ready; /* Is metadata read */ 217/* Track list - holds info about all buffered tracks */
174 218#if MEMORYSIZE >= 32
175} tracks[MAX_TRACK]; 219#define TRACK_LIST_LEN 128 /* Must be 2^int(+n) */
220#elif MEMORYSIZE >= 16
221#define TRACK_LIST_LEN 64
222#elif MEMORYSIZE >= 8
223#define TRACK_LIST_LEN 32
224#else
225#define TRACK_LIST_LEN 16
226#endif
176 227
177static volatile int track_ridx = 0; /* Track being decoded (A/C-) */ 228#define TRACK_LIST_MASK (TRACK_LIST_LEN-1)
178static int track_widx = 0; /* Track being buffered (A) */
179#define CUR_TI (&tracks[track_ridx]) /* Playing track info pointer (A/C-) */
180 229
181static struct track_info *prev_ti = NULL; /* Pointer to the previously played 230static struct
182 track */ 231{
232 /* read, write and current are maintained unwrapped, limited only by the
233 unsigned int range and wrap-safe comparisons are used */
183 234
184/* Information used only for filling the buffer */ 235 /* NOTE: there appears to be a bug in arm-elf-eabi-gcc 4.4.4 for ARMv4 where
185/* Playlist steps from playing track to next track to be buffered (A) */ 236 if 'end' follows 'start' in this structure, track_list_count performs
186static int last_peek_offset = 0; 237 'start - end' rather than 'end - start', giving negative count values...
238 so leave it this way for now! */
239 unsigned int end; /* Next open position */
240 unsigned int start; /* First track in list */
241 unsigned int current; /* Currently decoding track */
242 struct track_info tracks[TRACK_LIST_LEN]; /* Buffered track information */
243} track_list; /* (A, O-) */
187 244
188/* Scrobbler support */
189static unsigned long prev_track_elapsed = 0; /* Previous track elapsed time (C/A-)*/
190 245
191/* Track change controls */ 246/* Playlist steps from playlist position to next track to be buffered */
192static bool automatic_skip = false; /* Who initiated in-progress skip? (A) */ 247static int playlist_peek_offset = 0;
193extern bool track_transition; /* Are we in a track transition? */
194static bool dir_skip = false; /* Is a directory skip pending? (A) */
195static bool new_playlist = false; /* Are we starting a new playlist? (A) */
196static int wps_offset = 0; /* Pending track change offset, to keep WPS responsive (A) */
197static bool skipped_during_pause = false; /* Do we need to clear the PCM buffer when playback resumes (A) */
198 248
199static bool start_play_g = false; /* Used by audio_load_track to notify 249/* Metadata handle of track load in progress (meaning all handles have not
200 audio_finish_load_track about start_play */ 250 yet been opened for the track, id3 always exists or the track does not)
201 251
202/* True when a track load is in progress, i.e. audio_load_track() has returned 252 Tracks are keyed by their metadata handles if track list pointers are
203 * but audio_finish_load_track() hasn't been called yet. Used to avoid allowing 253 insufficient to make comparisons */
204 * audio_load_track() to get called twice in a row, which would cause problems. 254static int in_progress_id3_hid = ERR_HANDLE_NOT_FOUND;
205 */
206static bool track_load_started = false;
207 255
208#ifdef HAVE_DISK_STORAGE 256#ifdef HAVE_DISK_STORAGE
209static size_t buffer_margin = 5; /* Buffer margin aka anti-skip buffer (A/C-) */ 257/* Buffer margin A.K.A. anti-skip buffer (in seconds) */
258static size_t buffer_margin = 5;
210#endif 259#endif
211 260
212/* Event queues */ 261/* Values returned for track loading */
213struct event_queue audio_queue SHAREDBSS_ATTR; 262enum track_load_status
214static struct event_queue pcmbuf_queue SHAREDBSS_ATTR; 263{
264 LOAD_TRACK_ERR_START_CODEC = -6,
265 LOAD_TRACK_ERR_FINISH_FAILED = -5,
266 LOAD_TRACK_ERR_FINISH_FULL = -4,
267 LOAD_TRACK_ERR_BUSY = -3,
268 LOAD_TRACK_ERR_NO_MORE = -2,
269 LOAD_TRACK_ERR_FAILED = -1,
270 LOAD_TRACK_OK = 0,
271 LOAD_TRACK_READY = 1,
272};
215 273
216extern struct codec_api ci; 274/** Track change controls **/
217extern unsigned int codec_thread_id; 275
276/* What sort of skip is pending globally? */
277enum track_skip_type
278{
279 /* Relative to what user is intended to see: */
280 /* Codec: +0, Track List: +0, Playlist: +0 */
281 TRACK_SKIP_NONE = 0, /* no track skip */
282 /* Codec: +1, Track List: +1, Playlist: +0 */
283 TRACK_SKIP_AUTO, /* codec-initiated skip */
284 /* Codec: +1, Track List: +1, Playlist: +1 */
285 TRACK_SKIP_AUTO_NEW_PLAYLIST, /* codec-initiated skip is new playlist */
286 /* Codec: xx, Track List: +0, Playlist: +0 */
287 TRACK_SKIP_AUTO_END_PLAYLIST, /* codec-initiated end of playlist */
288 /* Manual skip: Never pends */
289 TRACK_SKIP_MANUAL, /* manual track skip */
290 /* Manual skip: Never pends */
291 TRACK_SKIP_DIR_CHANGE, /* manual directory skip */
292} skip_pending = TRACK_SKIP_NONE;
293
294/* Note about TRACK_SKIP_AUTO_NEW_PLAYLIST:
295 Fixing playlist code to be able to peek into the first song of
296 the next playlist would fix any issues and this wouldn't need
297 to be a special case since pre-advancing the playlist would be
298 unneeded - it could be much more like TRACK_SKIP_AUTO and all
299 actions that require reversal during an in-progress transition
300 would work as expected */
301
302/* Used to indicate status for the events. Must be separate to satisfy all
303 clients so the correct metadata is read when sending the change events
304 and also so that it is read correctly outside the events. */
305static bool automatic_skip = false; /* (A, O-) */
306
307/* Pending manual track skip offset */
308static int skip_offset = 0; /* (A, O) */
309
310/* Track change notification */
311static struct
312{
313 unsigned int in; /* Number of pcmbuf posts (audio isr) */
314 unsigned int out; /* Number of times audio has read the difference */
315} track_change = { 0, 0 };
316
317/** Codec status **/
318/* Did the codec notify us it finished while we were paused or while still
319 in an automatic transition?
320
321 If paused, it is necessary to defer a codec-initiated skip until resuming
322 or else the track will move forward while not playing audio!
323
324 If in-progress, skips should not build-up ahead of where the WPS is when
325 really short tracks finish decoding.
326
327 If it is forgotten, it will be missed altogether and playback will just sit
328 there looking stupid and comatose until the user does something */
329static bool codec_skip_pending = false;
330static int codec_skip_status;
331static bool codec_seeking = false; /* Codec seeking ack expected? */
218 332
219/* Multiple threads */ 333
220/* Set the watermark to trigger buffer fill (A/C) */ 334/* Event queues */
221static void set_filebuf_watermark(void); 335static struct event_queue audio_queue SHAREDBSS_ATTR;
222 336
223/* Audio thread */ 337/* Audio thread */
224static struct queue_sender_list audio_queue_sender_list SHAREDBSS_ATTR; 338static struct queue_sender_list audio_queue_sender_list SHAREDBSS_ATTR;
225static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)]; 339static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)];
226static const char audio_thread_name[] = "audio"; 340static const char audio_thread_name[] = "audio";
341static unsigned int audio_thread_id = 0;
342
343/* Forward declarations */
344enum audio_start_playback_flags
345{
346 AUDIO_START_RESTART = 0x1, /* "Restart" playback (flush _all_ tracks) */
347 AUDIO_START_NEWBUF = 0x2, /* Mark the audiobuffer as invalid */
348};
227 349
228static void audio_thread(void); 350static void audio_start_playback(size_t offset, unsigned int flags);
229static void audio_initiate_track_change(long direction);
230static bool audio_have_tracks(void);
231static void audio_reset_buffer(void);
232static void audio_stop_playback(void); 351static void audio_stop_playback(void);
352static void buffer_event_buffer_low_callback(void *data);
353static void buffer_event_rebuffer_callback(void *data);
354static void buffer_event_finished_callback(void *data);
355
233 356
234/**************************************/ 357/**************************************/
235 358
236/** Pcmbuf callbacks */ 359/** --- audio_queue helpers --- **/
237 360
238/* Between the codec and PCM track change, we need to keep updating the 361/* codec thread needs access */
239 * "elapsed" value of the previous (to the codec, but current to the 362void audio_queue_post(long id, intptr_t data)
240 * user/PCM/WPS) track, so that the progressbar reaches the end.
241 * During that transition, the WPS will display othertrack_id3. */
242void audio_pcmbuf_position_callback(unsigned int time)
243{ 363{
244 time += othertrack_id3->elapsed; 364 queue_post(&audio_queue, id, data);
245 othertrack_id3->elapsed = (time >= othertrack_id3->length)
246 ? othertrack_id3->length : time;
247} 365}
248 366
249/* Post message from pcmbuf that the end of the previous track 367static intptr_t audio_queue_send(long id, intptr_t data)
250 * has just been played. */
251void audio_post_track_change(bool pcmbuf)
252{ 368{
253 if (pcmbuf) 369 return queue_send(&audio_queue, id, data);
254 {
255 LOGFQUEUE("pcmbuf > pcmbuf Q_AUDIO_TRACK_CHANGED");
256 queue_post(&pcmbuf_queue, Q_AUDIO_TRACK_CHANGED, 0);
257 }
258 else
259 {
260 LOGFQUEUE("pcmbuf > audio Q_AUDIO_TRACK_CHANGED");
261 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
262 }
263} 370}
264 371
265/* Scan the pcmbuf queue and return true if a message pulled */
266static bool pcmbuf_queue_scan(struct queue_event *ev)
267{
268 if (!queue_empty(&pcmbuf_queue))
269 {
270 /* Transfer message to audio queue */
271 pcm_play_lock();
272 /* Pull message - never, ever any blocking call! */
273 queue_wait_w_tmo(&pcmbuf_queue, ev, 0);
274 pcm_play_unlock();
275 return true;
276 }
277
278 return false;
279}
280 372
373/** --- MP3Entry --- **/
281 374
282/** Helper functions */ 375/* Does the mp3entry have enough info for us to use it? */
376static struct mp3entry * valid_mp3entry(const struct mp3entry *id3)
377{
378 return id3 && (id3->length != 0 || id3->filesize != 0) &&
379 id3->codectype != AFMT_UNKNOWN ? (struct mp3entry *)id3 : NULL;
380}
283 381
284static struct mp3entry *bufgetid3(int handle_id) 382/* Return a pointer to an mp3entry on the buffer, as it is */
383static struct mp3entry * bufgetid3(int handle_id)
285{ 384{
286 if (handle_id < 0) 385 if (handle_id < 0)
287 return NULL; 386 return NULL;
@@ -295,6 +394,7 @@ static struct mp3entry *bufgetid3(int handle_id)
295 return id3; 394 return id3;
296} 395}
297 396
397/* Read an mp3entry from the buffer, adjusted */
298static bool bufreadid3(int handle_id, struct mp3entry *id3out) 398static bool bufreadid3(int handle_id, struct mp3entry *id3out)
299{ 399{
300 struct mp3entry *id3 = bufgetid3(handle_id); 400 struct mp3entry *id3 = bufgetid3(handle_id);
@@ -308,1200 +408,1441 @@ static bool bufreadid3(int handle_id, struct mp3entry *id3out)
308 return false; 408 return false;
309} 409}
310 410
311static bool clear_track_info(struct track_info *track) 411/* Lock the id3 mutex */
412static void id3_mutex_lock(void)
312{ 413{
313 /* bufclose returns true if the handle is not found, or if it is closed 414 mutex_lock(&id3_mutex);
314 * successfully, so these checks are safe on non-existant handles */
315 if (!track)
316 return false;
317
318 if (track->codec_hid >= 0) {
319 if (bufclose(track->codec_hid))
320 track->codec_hid = -1;
321 else
322 return false;
323 }
324
325 if (track->id3_hid >= 0) {
326 if (bufclose(track->id3_hid))
327 track->id3_hid = -1;
328 else
329 return false;
330 }
331
332 if (track->audio_hid >= 0) {
333 if (bufclose(track->audio_hid))
334 track->audio_hid = -1;
335 else
336 return false;
337 }
338
339#ifdef HAVE_ALBUMART
340 {
341 int i;
342 FOREACH_ALBUMART(i)
343 {
344 if (track->aa_hid[i] >= 0) {
345 if (bufclose(track->aa_hid[i]))
346 track->aa_hid[i] = -1;
347 else
348 return false;
349 }
350 }
351 }
352#endif
353
354 if (track->cuesheet_hid >= 0) {
355 if (bufclose(track->cuesheet_hid))
356 track->cuesheet_hid = -1;
357 else
358 return false;
359 }
360
361 track->filesize = 0;
362 track->taginfo_ready = false;
363
364 return true;
365} 415}
366 416
367/* --- External interfaces --- */ 417/* Unlock the id3 mutex */
368 418static void id3_mutex_unlock(void)
369/* This sends a stop message and the audio thread will dump all it's
370 subsequenct messages */
371void audio_hard_stop(void)
372{ 419{
373 /* Stop playback */ 420 mutex_unlock(&id3_mutex);
374 LOGFQUEUE("audio >| audio Q_AUDIO_STOP: 1");
375 queue_send(&audio_queue, Q_AUDIO_STOP, 1);
376#ifdef PLAYBACK_VOICE
377 voice_stop();
378#endif
379} 421}
380 422
381bool audio_restore_playback(int type) 423/* Return one of the collection of mp3entry pointers - collect them all here */
424static inline struct mp3entry * id3_get(enum audio_id3_types id3_num)
382{ 425{
383 switch (type) 426 switch (id3_num)
384 { 427 {
385 case AUDIO_WANT_PLAYBACK: 428 case UNBUFFERED_ID3:
386 if (buffer_state != AUDIOBUF_STATE_INITIALIZED) 429 return &audio_scratch_memory->unbuffered_id3;
387 audio_reset_buffer(); 430 case CODEC_ID3:
388 return true; 431 return &audio_scratch_memory->codec_id3;
389 case AUDIO_WANT_VOICE:
390 if (buffer_state == AUDIOBUF_STATE_TRASHED)
391 audio_reset_buffer();
392 return true;
393 default: 432 default:
394 return false; 433 return &static_id3_entries[id3_num];
395 } 434 }
396} 435}
397 436
398unsigned char *audio_get_buffer(bool talk_buf, size_t *buffer_size) 437/* Copy an mp3entry into one of the mp3 entries */
438static void id3_write(enum audio_id3_types id3_num,
439 const struct mp3entry *id3_src)
399{ 440{
400 unsigned char *buf, *end; 441 struct mp3entry *dest_id3 = id3_get(id3_num);
401
402 if (audio_is_initialized)
403 {
404 audio_hard_stop();
405 }
406 /* else buffer_state will be AUDIOBUF_STATE_TRASHED at this point */
407
408 /* Reset the buffering thread so that it doesn't try to use the data */
409 buffering_reset(filebuf, filebuflen);
410
411 if (buffer_size == NULL)
412 {
413 /* Special case for talk_init to use since it already knows it's
414 trashed */
415 buffer_state = AUDIOBUF_STATE_TRASHED;
416 return NULL;
417 }
418 442
419 if (talk_buf || buffer_state == AUDIOBUF_STATE_TRASHED 443 if (id3_src)
420 || !talk_voice_required()) 444 copy_mp3entry(dest_id3, id3_src);
421 {
422 logf("get buffer: talk, audio");
423 /* Ok to use everything from audiobuf to audiobufend - voice is loaded,
424 the talk buffer is not needed because voice isn't being used, or
425 could be AUDIOBUF_STATE_TRASHED already. If state is
426 AUDIOBUF_STATE_VOICED_ONLY, no problem as long as memory isn't written
427 without the caller knowing what's going on. Changing certain settings
428 may move it to a worse condition but the memory in use by something
429 else will remain undisturbed.
430 */
431 if (buffer_state != AUDIOBUF_STATE_TRASHED)
432 {
433 talk_buffer_steal();
434 buffer_state = AUDIOBUF_STATE_TRASHED;
435 }
436
437 buf = audiobuf;
438 end = audiobufend;
439 }
440 else 445 else
441 { 446 wipe_mp3entry(dest_id3);
442 /* Safe to just return this if already AUDIOBUF_STATE_VOICED_ONLY or
443 still AUDIOBUF_STATE_INITIALIZED */
444 /* Skip talk buffer and move pcm buffer to end to maximize available
445 contiguous memory - no audio running means voice will not need the
446 swap space */
447 logf("get buffer: audio");
448 buf = audiobuf + talk_get_bufsize();
449 end = audiobufend - pcmbuf_init(audiobufend);
450 buffer_state = AUDIOBUF_STATE_VOICED_ONLY;
451 }
452
453 *buffer_size = end - buf;
454
455 return buf;
456} 447}
457 448
458bool audio_buffer_state_trashed(void) 449/* Call id3_write "safely" because peek aheads can yield, even if the fast
450 preview isn't enabled */
451static void id3_write_locked(enum audio_id3_types id3_num,
452 const struct mp3entry *id3_src)
459{ 453{
460 return buffer_state == AUDIOBUF_STATE_TRASHED; 454 id3_mutex_lock();
455 id3_write(id3_num, id3_src);
456 id3_mutex_unlock();
461} 457}
462 458
463#ifdef HAVE_RECORDING 459
464unsigned char *audio_get_recording_buffer(size_t *buffer_size) 460/** --- Track info --- **/
461
462/* Close a handle and mark it invalid */
463static void track_info_close_handle(int *hid_p)
465{ 464{
466 /* Stop audio, voice and obtain all available buffer space */ 465 int hid = *hid_p;
467 audio_hard_stop();
468 talk_buffer_steal();
469 466
470 unsigned char *end = audiobufend; 467 /* bufclose returns true if the handle is not found, or if it is closed
471 buffer_state = AUDIOBUF_STATE_TRASHED; 468 * successfully, so these checks are safe on non-existant handles */
472 *buffer_size = end - audiobuf; 469 if (hid >= 0)
470 bufclose(hid);
473 471
474 return (unsigned char *)audiobuf; 472 /* Always reset to "no handle" in case it was something else */
473 *hid_p = ERR_HANDLE_NOT_FOUND;
475} 474}
476 475
477bool audio_load_encoder(int afmt) 476/* Close all handles in a struct track_info and clear it */
477static void track_info_close(struct track_info *info)
478{ 478{
479#if (CONFIG_PLATFORM & PLATFORM_NATIVE) 479 /* Close them in the order they are allocated on the buffer to speed up
480 LOGFQUEUE("audio >| Q_AUDIO_LOAD_ENCODER: %d", afmt); 480 the handle searching */
481 return queue_send(&audio_queue, Q_AUDIO_LOAD_ENCODER, afmt) > 0; 481 track_info_close_handle(&info->id3_hid);
482#else 482 track_info_close_handle(&info->cuesheet_hid);
483 (void)afmt; 483#ifdef HAVE_ALBUMART
484 return true; 484 int i;
485 FOREACH_ALBUMART(i)
486 track_info_close_handle(&info->aa_hid[i]);
485#endif 487#endif
486} /* audio_load_encoder */ 488#ifdef HAVE_CODEC_BUFFERING
489 track_info_close_handle(&info->codec_hid);
490#endif
491 track_info_close_handle(&info->audio_hid);
492 info->filesize = 0;
493}
487 494
488void audio_remove_encoder(void) 495/* Invalidate all members to initial values - does not close handles */
496static void track_info_wipe(struct track_info * info)
489{ 497{
490#if (CONFIG_PLATFORM & PLATFORM_NATIVE) 498 info->id3_hid = ERR_HANDLE_NOT_FOUND;
491 LOGFQUEUE("audio >| Q_AUDIO_LOAD_ENCODER: NULL"); 499 info->cuesheet_hid = ERR_HANDLE_NOT_FOUND;
492 queue_send(&audio_queue, Q_AUDIO_LOAD_ENCODER, AFMT_UNKNOWN); 500#ifdef HAVE_ALBUMART
501 int i;
502 FOREACH_ALBUMART(i)
503 info->aa_hid[i] = ERR_HANDLE_NOT_FOUND;
504#endif
505#ifdef HAVE_CODEC_BUFFERING
506 info->codec_hid = ERR_HANDLE_NOT_FOUND;
493#endif 507#endif
494} /* audio_remove_encoder */ 508 info->audio_hid = ERR_HANDLE_NOT_FOUND;
509 info->filesize = 0;
510}
495 511
496#endif /* HAVE_RECORDING */
497 512
513/** --- Track list --- **/
498 514
499struct mp3entry* audio_current_track(void) 515/* Initialize the track list */
516static void track_list_init(void)
500{ 517{
501 const char *filename; 518 int i;
502 struct playlist_track_info trackinfo; 519 for (i = 0; i < TRACK_LIST_LEN; i++)
503 int cur_idx; 520 track_info_wipe(&track_list.tracks[i]);
504 int offset = ci.new_track + wps_offset;
505 struct mp3entry *write_id3;
506
507 cur_idx = (track_ridx + offset) & MAX_TRACK_MASK;
508 521
509 if (cur_idx == track_ridx && *thistrack_id3->path) 522 track_list.start = track_list.end = track_list.current;
510 { 523}
511 /* The usual case */
512 if (tracks[cur_idx].cuesheet_hid >= 0 && !thistrack_id3->cuesheet)
513 {
514 bufread(tracks[cur_idx].cuesheet_hid, sizeof(struct cuesheet), curr_cue);
515 thistrack_id3->cuesheet = curr_cue;
516 }
517 return thistrack_id3;
518 }
519 else if (automatic_skip && offset == -1 && *othertrack_id3->path)
520 {
521 /* We're in a track transition. The codec has moved on to the next track,
522 but the audio being played is still the same (now previous) track.
523 othertrack_id3.elapsed is being updated in an ISR by
524 codec_pcmbuf_position_callback */
525 if (tracks[cur_idx].cuesheet_hid >= 0 && !thistrack_id3->cuesheet)
526 {
527 bufread(tracks[cur_idx].cuesheet_hid, sizeof(struct cuesheet), curr_cue);
528 othertrack_id3->cuesheet = curr_cue;
529 }
530 return othertrack_id3;
531 }
532 524
533 if (offset != 0) 525/* Return number of items allocated in the list */
534 { 526static unsigned int track_list_count(void)
535 /* Codec may be using thistrack_id3, so it must not be overwritten. 527{
536 If this is a manual skip, othertrack_id3 will become 528 return track_list.end - track_list.start;
537 thistrack_id3 in audio_check_new_track(). 529}
538 FIXME: If this is an automatic skip, it probably means multiple
539 short tracks fit in the PCM buffer. Overwriting othertrack_id3
540 can lead to an incorrect value later.
541 Note that othertrack_id3 may also be used for next track.
542 */
543 write_id3 = othertrack_id3;
544 }
545 else
546 {
547 write_id3 = thistrack_id3;
548 }
549 530
550 if (tracks[cur_idx].id3_hid >= 0) 531/* Return true if the list is empty */
551 { 532static inline bool track_list_empty(void)
552 /* The current track's info has been buffered but not read yet, so get it */ 533{
553 if (bufreadid3(tracks[cur_idx].id3_hid, write_id3)) 534 return track_list.end == track_list.start;
554 return write_id3; 535}
555 }
556 536
557 /* We didn't find the ID3 metadata, so we fill temp_id3 with the little info 537/* Returns true if the list is holding the maximum number of items */
558 we have and return that. */ 538static bool track_list_full(void)
539{
540 return track_list.end - track_list.start >= TRACK_LIST_LEN;
541}
559 542
560 memset(write_id3, 0, sizeof(struct mp3entry)); 543/* Test if the index is within the allocated range */
544static bool track_list_in_range(int pos)
545{
546 return (int)(pos - track_list.start) >= 0 &&
547 (int)(pos - track_list.end) < 0;
548}
561 549
562 playlist_get_track_info(NULL, playlist_next(0)+wps_offset, &trackinfo); 550static struct track_info * track_list_entry(int pos)
563 filename = trackinfo.filename; 551{
564 if (!filename) 552 return &track_list.tracks[pos & TRACK_LIST_MASK];
565 filename = "No file!"; 553}
566 554
567#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) 555/* Return the info of the last allocation plus an offset, NULL if result is
568 if (tagcache_fill_tags(write_id3, filename)) 556 out of bounds */
569 return write_id3; 557static struct track_info * track_list_last(int offset)
570#endif 558{
559 /* Last is before the end since the end isn't inclusive */
560 unsigned int pos = track_list.end + offset - 1;
571 561
572 strlcpy(write_id3->path, filename, sizeof(write_id3->path)); 562 if (!track_list_in_range(pos))
573 write_id3->title = strrchr(write_id3->path, '/'); 563 return NULL;
574 if (!write_id3->title)
575 write_id3->title = &write_id3->path[0];
576 else
577 write_id3->title++;
578 564
579 return write_id3; 565 return track_list_entry(pos);
580} 566}
581 567
582struct mp3entry* audio_next_track(void) 568/* Allocate space at the end for another track if not full */
569static struct track_info * track_list_alloc_track(void)
583{ 570{
584 int next_idx; 571 if (track_list_full())
585 int offset = ci.new_track + wps_offset;
586
587 if (!audio_have_tracks())
588 return NULL; 572 return NULL;
589 573
590 if (wps_offset == -1 && *thistrack_id3->path) 574 return track_list_entry(track_list.end++);
591 { 575}
592 /* We're in a track transition. The next track for the WPS is the one
593 currently being decoded. */
594 return thistrack_id3;
595 }
596 576
597 next_idx = (track_ridx + offset + 1) & MAX_TRACK_MASK; 577/* Remove the last track entry allocated in order to support backing out
578 of a track load */
579static void track_list_unalloc_track(void)
580{
581 if (track_list_empty())
582 return;
598 583
599 if (tracks[next_idx].id3_hid >= 0) 584 track_list.end--;
600 {
601 if (bufreadid3(tracks[next_idx].id3_hid, othertrack_id3))
602 return othertrack_id3;
603 else
604 return NULL;
605 }
606 585
607 if (next_idx == track_widx) 586 if (track_list.current == track_list.end &&
587 track_list.current != track_list.start)
608 { 588 {
609 /* The next track hasn't been buffered yet, so we return the static 589 /* Current _must_ remain within bounds */
610 version of its metadata. */ 590 track_list.current--;
611 return &unbuffered_id3;
612 } 591 }
613
614 return NULL;
615} 592}
616 593
617/* gets a copy of the id3 data */ 594/* Return current track plus an offset, NULL if result is out of bounds */
618bool audio_peek_track(struct mp3entry* id3, int offset) 595static struct track_info * track_list_current(int offset)
619{ 596{
620 int next_idx; 597 unsigned int pos = track_list.current + offset;
621 int new_offset = ci.new_track + wps_offset + offset;
622
623 if (!audio_have_tracks())
624 return false;
625 next_idx = (track_ridx + new_offset) & MAX_TRACK_MASK;
626 598
627 if (tracks[next_idx].id3_hid >= 0) 599 if (!track_list_in_range(pos))
628 return bufreadid3(tracks[next_idx].id3_hid, id3); 600 return NULL;
629
630 return false;
631}
632
633#ifdef HAVE_ALBUMART
634
635int playback_current_aa_hid(int slot)
636{
637 if (slot < 0)
638 return -1;
639 int cur_idx;
640 int offset = ci.new_track + wps_offset;
641 601
642 cur_idx = track_ridx + offset; 602 return track_list_entry(pos);
643 cur_idx &= MAX_TRACK_MASK;
644 return tracks[cur_idx].aa_hid[slot];
645} 603}
646 604
647int playback_claim_aa_slot(struct dim *dim) 605/* Return current based upon what's intended that the user sees - not
606 necessarily where decoding is taking place */
607static struct track_info * track_list_user_current(int offset)
648{ 608{
649 int i; 609 if (skip_pending == TRACK_SKIP_AUTO ||
650 610 skip_pending == TRACK_SKIP_AUTO_NEW_PLAYLIST)
651 /* first try to find a slot already having the size to reuse it
652 * since we don't want albumart of the same size buffered multiple times */
653 FOREACH_ALBUMART(i)
654 {
655 struct albumart_slot *slot = &albumart_slots[i];
656 if (slot->dim.width == dim->width
657 && slot->dim.height == dim->height)
658 {
659 slot->used++;
660 return i;
661 }
662 }
663 /* size is new, find a free slot */
664 FOREACH_ALBUMART(i)
665 { 611 {
666 if (!albumart_slots[i].used) 612 offset--;
667 {
668 albumart_slots[i].used++;
669 albumart_slots[i].dim = *dim;
670 return i;
671 }
672 } 613 }
673 /* sorry, no free slot */
674 return -1;
675}
676 614
677void playback_release_aa_slot(int slot) 615 return track_list_current(offset);
678{
679 /* invalidate the albumart_slot */
680 struct albumart_slot *aa_slot = &albumart_slots[slot];
681
682 if (aa_slot->used > 0)
683 aa_slot->used--;
684} 616}
685 617
686#endif 618/* Advance current track by an offset, return false if result is out of
687void audio_play(long offset) 619 bounds */
620static struct track_info * track_list_advance_current(int offset)
688{ 621{
689 logf("audio_play"); 622 unsigned int pos = track_list.current + offset;
690 623
691#ifdef PLAYBACK_VOICE 624 if (!track_list_in_range(pos))
692 /* Truncate any existing voice output so we don't have spelling 625 return NULL;
693 * etc. over the first part of the played track */
694 talk_force_shutup();
695#endif
696 626
697 /* Start playback */ 627 track_list.current = pos;
698 LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %ld", offset); 628 return track_list_entry(pos);
699 /* Don't return until playback has actually started */
700 queue_send(&audio_queue, Q_AUDIO_PLAY, offset);
701} 629}
702 630
703void audio_stop(void) 631/* Clear tracks in the list, optionally preserving the current track -
632 returns 'false' if the operation was changed */
633enum track_clear_action
704{ 634{
705 /* Stop playback */ 635 TRACK_LIST_CLEAR_ALL = 0, /* Clear all tracks */
706 LOGFQUEUE("audio >| audio Q_AUDIO_STOP"); 636 TRACK_LIST_KEEP_CURRENT, /* Keep current only; clear before + after */
707 /* Don't return until playback has actually stopped */ 637 TRACK_LIST_KEEP_NEW /* Keep current and those that follow */
708 queue_send(&audio_queue, Q_AUDIO_STOP, 0); 638};
709}
710 639
711void audio_pause(void) 640static void track_list_clear(enum track_clear_action action)
712{ 641{
713 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE"); 642 logf("%s(%d)", __func__, (int)action);
714 /* Don't return until playback has actually paused */
715 queue_send(&audio_queue, Q_AUDIO_PAUSE, true);
716}
717 643
718void audio_resume(void) 644 /* Don't care now since rebuffering is imminent */
719{ 645 buf_set_watermark(0);
720 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE resume");
721 /* Don't return until playback has actually resumed */
722 queue_send(&audio_queue, Q_AUDIO_PAUSE, false);
723}
724 646
725void audio_skip(int direction) 647 if (action != TRACK_LIST_CLEAR_ALL)
726{
727 if (playlist_check(ci.new_track + wps_offset + direction))
728 { 648 {
729 if (global_settings.beep) 649 struct track_info *cur = track_list_current(0);
730 pcmbuf_beep(2000, 100, 2500*global_settings.beep);
731 650
732 LOGFQUEUE("audio > audio Q_AUDIO_SKIP %d", direction); 651 if (!cur || cur->id3_hid < 0)
733 queue_post(&audio_queue, Q_AUDIO_SKIP, direction); 652 action = TRACK_LIST_CLEAR_ALL; /* Nothing worthwhile keeping */
734 /* Update wps while our message travels inside deep playback queues. */
735 wps_offset += direction;
736 } 653 }
737 else 654
655 /* Noone should see this progressing */
656 int start = track_list.start;
657 int current = track_list.current;
658 int end = track_list.end;
659
660 track_list.start = current;
661
662 switch (action)
738 { 663 {
739 /* No more tracks. */ 664 case TRACK_LIST_CLEAR_ALL:
740 if (global_settings.beep) 665 /* Result: .start = .current, .end = .current */
741 pcmbuf_beep(1000, 100, 1500*global_settings.beep); 666 track_list.end = current;
667 break;
668
669 case TRACK_LIST_KEEP_CURRENT:
670 /* Result: .start = .current, .end = .current + 1 */
671 track_list.end = current + 1;
672 break;
673
674 case TRACK_LIST_KEEP_NEW:
675 /* Result: .start = .current, .end = .end */
676 end = current;
677 break;
742 } 678 }
743}
744 679
745void audio_next(void) 680 /* Close all open handles in the range except the for the current track
746{ 681 if preserving that */
747 audio_skip(1); 682 while (start != end)
748} 683 {
684 if (action != TRACK_LIST_KEEP_CURRENT || start != current)
685 {
686 struct track_info *info =
687 &track_list.tracks[start & TRACK_LIST_MASK];
749 688
750void audio_prev(void) 689 /* If this is the in-progress load, abort it */
751{ 690 if (in_progress_id3_hid >= 0 &&
752 audio_skip(-1); 691 info->id3_hid == in_progress_id3_hid)
753} 692 {
693 in_progress_id3_hid = ERR_HANDLE_NOT_FOUND;
694 }
754 695
755void audio_next_dir(void) 696 track_info_close(info);
756{ 697 }
757 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
758 queue_post(&audio_queue, Q_AUDIO_DIR_SKIP, 1);
759}
760 698
761void audio_prev_dir(void) 699 start++;
762{ 700 }
763 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
764 queue_post(&audio_queue, Q_AUDIO_DIR_SKIP, -1);
765} 701}
766 702
767void audio_pre_ff_rewind(void)
768{
769 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
770 queue_post(&audio_queue, Q_AUDIO_PRE_FF_REWIND, 0);
771}
772 703
773void audio_ff_rewind(long newpos) 704/** --- Audio buffer -- **/
774{
775 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
776 queue_post(&audio_queue, Q_AUDIO_FF_REWIND, newpos);
777}
778 705
779void audio_flush_and_reload_tracks(void) 706/* What size is needed for the scratch buffer? */
707static size_t scratch_mem_size(void)
780{ 708{
781 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH"); 709 size_t size = sizeof (struct audio_scratch_memory);
782 queue_post(&audio_queue, Q_AUDIO_FLUSH, 0); 710
711 if (global_settings.cuesheet)
712 size += sizeof (struct cuesheet);
713
714 return size;
783} 715}
784 716
785void audio_error_clear(void) 717/* Initialize the memory area where data is stored that is only used when
718 playing audio and anything depending upon it */
719static void scratch_mem_init(void *mem)
786{ 720{
787#ifdef AUDIO_HAVE_RECORDING 721 audio_scratch_memory = (struct audio_scratch_memory *)mem;
788 pcm_rec_error_clear(); 722 id3_write_locked(UNBUFFERED_ID3, NULL);
789#endif 723 id3_write(CODEC_ID3, NULL);
724 ci.id3 = id3_get(CODEC_ID3);
725 audio_scratch_memory->curr_cue = NULL;
726
727 if (global_settings.cuesheet)
728 {
729 audio_scratch_memory->curr_cue =
730 SKIPBYTES((struct cuesheet *)audio_scratch_memory,
731 sizeof (struct audio_scratch_memory));
732 }
790} 733}
791 734
792int audio_status(void) 735/* Set up the audio buffer for playback */
736static void audio_reset_buffer(void)
793{ 737{
794 int ret = 0; 738 /*
739 * Layout audio buffer as follows:
740 * [[|TALK]|SCRATCH|BUFFERING|PCM|]
741 */
795 742
796 if (playing) 743 /* see audio_get_recording_buffer if this is modified */
797 ret |= AUDIO_STATUS_PLAY; 744 logf("%s()", __func__);
798 745
799 if (paused) 746 /* If the setup of anything allocated before the file buffer is
800 ret |= AUDIO_STATUS_PAUSE; 747 changed, do check the adjustments after the buffer_alloc call
748 as it will likely be affected and need sliding over */
801 749
802#ifdef HAVE_RECORDING 750 /* Initially set up file buffer as all space available */
803 /* Do this here for constitency with mpeg.c version */ 751 unsigned char *filebuf = audiobuf + talk_get_bufsize();
804 /* FIXME: pcm_rec_status() is deprecated */ 752 size_t filebuflen = audiobufend - filebuf;
805 ret |= pcm_rec_status(); 753 size_t allocsize;
806#endif
807 754
808 return ret; 755 ALIGN_BUFFER(filebuf, filebuflen, sizeof (intptr_t));
809}
810 756
811bool audio_automatic_skip(void) 757 /* Subtract whatever the pcm buffer says it used plus the guard buffer */
812{ 758 allocsize = pcmbuf_init(filebuf + filebuflen);
813 return automatic_skip;
814}
815 759
816int audio_get_file_pos(void) 760 /* Make sure filebuflen is a pointer sized multiple after adjustment */
817{ 761 allocsize = ALIGN_UP(allocsize, sizeof (intptr_t));
818 return 0; 762 if (allocsize > filebuflen)
819} 763 goto bufpanic;
820 764
821#ifdef HAVE_DISK_STORAGE 765 filebuflen -= allocsize;
822void audio_set_buffer_margin(int setting)
823{
824 static const unsigned short lookup[] = {5, 15, 30, 60, 120, 180, 300, 600};
825 buffer_margin = lookup[setting];
826 logf("buffer margin: %ld", (long)buffer_margin);
827 set_filebuf_watermark();
828}
829#endif
830 766
831#ifdef HAVE_CROSSFADE 767 /* Scratch memory */
832/* Take necessary steps to enable or disable the crossfade setting */ 768 allocsize = scratch_mem_size();
833void audio_set_crossfade(int enable) 769 if (allocsize > filebuflen)
834{ 770 goto bufpanic;
835 size_t offset;
836 bool was_playing;
837 size_t size;
838 771
839 /* Tell it the next setting to use */ 772 scratch_mem_init(filebuf);
840 pcmbuf_request_crossfade_enable(enable); 773 filebuf += allocsize;
774 filebuflen -= allocsize;
841 775
842 /* Return if size hasn't changed or this is too early to determine 776 buffering_reset(filebuf, filebuflen);
843 which in the second case there's no way we could be playing
844 anything at all */
845 if (pcmbuf_is_same_size()) return;
846 777
847 offset = 0; 778 /* Clear any references to the file buffer */
848 was_playing = playing; 779 buffer_state = AUDIOBUF_STATE_INITIALIZED;
849 780
850 /* Playback has to be stopped before changing the buffer size */ 781#if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE)
851 if (was_playing) 782 /* Make sure everything adds up - yes, some info is a bit redundant but
783 aids viewing and the sumation of certain variables should add up to
784 the location of others. */
852 { 785 {
853 /* Store the track resume position */ 786 size_t pcmbufsize;
854 offset = thistrack_id3->offset; 787 const unsigned char *pcmbuf = pcmbuf_get_meminfo(&pcmbufsize);
788 logf("fbuf: %08X", (unsigned)filebuf);
789 logf("fbufe: %08X", (unsigned)(filebuf + filebuflen));
790 logf("sbuf: %08X", (unsigned)audio_scratch_memory);
791 logf("sbufe: %08X", (unsigned)(audio_scratch_memory + allocsize));
792 logf("pcmb: %08X", (unsigned)pcmbuf);
793 logf("pcmbe: %08X", (unsigned)(pcmbuf + pcmbufsize));
855 } 794 }
795#endif
856 796
857 /* Blast it - audio buffer will have to be setup again next time 797 return;
858 something plays */
859 audio_get_buffer(true, &size);
860 798
861 /* Restart playback if audio was running previously */ 799bufpanic:
862 if (was_playing) 800 panicf("%s(): EOM (%zu > %zu)", __func__, allocsize, filebuflen);
863 audio_play(offset);
864} 801}
865#endif
866
867/* --- Routines called from multiple threads --- */
868 802
869static void set_filebuf_watermark(void) 803/* Set the buffer margin to begin rebuffering when 'seconds' from empty */
804static void audio_update_filebuf_watermark(int seconds)
870{ 805{
871 if (!filebuf) 806 size_t bytes = 0;
872 return; /* Audio buffers not yet set up */
873 807
874#ifdef HAVE_DISK_STORAGE 808#ifdef HAVE_DISK_STORAGE
875 int seconds;
876 int spinup = ata_spinup_time(); 809 int spinup = ata_spinup_time();
810
811 if (seconds == 0)
812 {
813 /* By current setting */
814 seconds = buffer_margin;
815 }
816 else
817 {
818 /* New setting */
819 buffer_margin = seconds;
820
821 if (buf_get_watermark() == 0)
822 {
823 /* Write a watermark only if the audio thread already did so for
824 itself or it will fail to set the event and the watermark - if
825 it hasn't yet, it will use the new setting when it does */
826 return;
827 }
828 }
829
877 if (spinup) 830 if (spinup)
878 seconds = (spinup / HZ) + 1; 831 seconds += (spinup / HZ) + 1;
879 else 832 else
880 seconds = 5; 833 seconds += 5;
881 834
882 seconds += buffer_margin; 835 seconds += buffer_margin;
883#else 836#else
884 /* flash storage */ 837 /* flash storage */
885 int seconds = 1; 838 seconds = 1;
886#endif 839#endif
887 840
888 /* bitrate of last track in buffer dictates watermark */ 841 /* Watermark is a function of the bitrate of the last track in the buffer */
889 struct mp3entry* id3 = NULL; 842 struct mp3entry *id3 = NULL;
890 if (tracks[track_widx].taginfo_ready) 843 struct track_info *info = track_list_last(0);
891 id3 = bufgetid3(tracks[track_widx].id3_hid); 844
845 if (info)
846 id3 = valid_mp3entry(bufgetid3(info->id3_hid));
847
848 if (id3)
849 {
850 if (get_audio_base_data_type(id3->codectype) == TYPE_PACKET_AUDIO)
851 {
852 bytes = id3->bitrate * (1000/8) * seconds;
853 }
854 else
855 {
856 /* Bitrate has no meaning to buffering margin for atomic audio -
857 rebuffer when it's the only track left unless it's the only
858 track that fits, in which case we should avoid constant buffer
859 low events */
860 if (track_list_count() > 1)
861 bytes = info->filesize + 1;
862 }
863 }
892 else 864 else
893 id3 = bufgetid3(tracks[track_widx-1].id3_hid); 865 {
894 if (!id3) { 866 /* Then set the minimum - this should not occur anyway */
895 logf("fwmark: No id3 for last track (r%d/w%d), aborting!", track_ridx, track_widx); 867 logf("fwmark: No id3 for last track (s%u/c%u/e%u)",
896 return; 868 track_list.start, track_list.current, track_list.end);
897 } 869 }
898 size_t bytes = id3->bitrate * (1000/8) * seconds; 870
899 buf_set_watermark(bytes); 871 /* Actually setting zero disables the notification and we use that
900 logf("fwmark: %d", bytes); 872 to detect that it has been reset */
873 buf_set_watermark(MAX(bytes, 1));
874 logf("fwmark: %lu", (unsigned long)bytes);
901} 875}
902 876
903/* --- Buffering callbacks --- */
904 877
905static void buffering_low_buffer_callback(void *data) 878/** -- Track change notification -- **/
879
880/* Check the pcmbuf track changes and return write the message into the event
881 if there are any */
882static inline bool audio_pcmbuf_track_change_scan(void)
906{ 883{
907 (void)data; 884 if (track_change.out != track_change.in)
908 logf("low buffer callback"); 885 {
886 track_change.out++;
887 return true;
888 }
889
890 return false;
891}
892
893/* Clear outstanding track change posts */
894static inline void audio_pcmbuf_track_change_clear(void)
895{
896 track_change.out = track_change.in;
897}
898
899/* Post a track change notification - called by audio ISR */
900static inline void audio_pcmbuf_track_change_post(void)
901{
902 track_change.in++;
903}
909 904
910 if (filling == STATE_FULL || filling == STATE_END_OF_PLAYLIST) { 905
911 /* force a refill */ 906/** --- Helper functions --- **/
912 LOGFQUEUE("buffering > audio Q_AUDIO_FILL_BUFFER"); 907
913 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0); 908/* Removes messages that might end up in the queue before or while processing
909 a manual track change. Responding to them would be harmful since they
910 belong to a previous track's playback period. Anything that would generate
911 the stale messages must first be put into a state where it will not do so.
912 */
913static void audio_clear_track_notifications(void)
914{
915 static const long filter_list[][2] =
916 {
917 /* codec messages */
918 { Q_AUDIO_CODEC_SEEK_COMPLETE, Q_AUDIO_CODEC_COMPLETE },
919 /* track change messages */
920 { Q_AUDIO_TRACK_CHANGED, Q_AUDIO_TRACK_CHANGED },
921 };
922
923 const int filter_count = ARRAYLEN(filter_list) - 1;
924
925 /* Remove any pcmbuf notifications */
926 pcmbuf_monitor_track_change(false);
927 audio_pcmbuf_track_change_clear();
928
929 /* Scrub the audio queue of the old mold */
930 while (queue_peek_ex(&audio_queue, NULL,
931 filter_count | QPEEK_REMOVE_EVENTS,
932 filter_list))
933 {
934 yield(); /* Not strictly needed, per se, ad infinitum, ra, ra */
914 } 935 }
915} 936}
916 937
917static void buffering_handle_rebuffer_callback(void *data) 938/* Takes actions based upon track load status codes */
939static void audio_handle_track_load_status(int trackstat)
918{ 940{
919 (void)data; 941 switch (trackstat)
920 LOGFQUEUE("audio >| audio Q_AUDIO_FLUSH"); 942 {
921 queue_post(&audio_queue, Q_AUDIO_FLUSH, 0); 943 case LOAD_TRACK_ERR_NO_MORE:
944 if (track_list_count() > 0)
945 break;
946
947 case LOAD_TRACK_ERR_START_CODEC:
948 audio_queue_post(Q_AUDIO_CODEC_COMPLETE, CODEC_ERROR);
949 break;
950
951 default:
952 break;
953 }
922} 954}
923 955
924static void buffering_handle_finished_callback(void *data) 956/* Announce the end of playing the current track */
957static void audio_playlist_track_finish(void)
925{ 958{
926 logf("handle %d finished buffering", *(int*)data); 959 struct mp3entry *id3 = valid_mp3entry(id3_get(PLAYING_ID3));
927 int hid = (*(int*)data);
928 960
929 if (hid == tracks[track_widx].id3_hid) 961 playlist_update_resume_info(filling == STATE_ENDED ? NULL : id3);
962
963 if (id3)
930 { 964 {
931 int offset = ci.new_track + wps_offset; 965 send_event(PLAYBACK_EVENT_TRACK_FINISH, id3);
932 int next_idx = (track_ridx + offset + 1) & MAX_TRACK_MASK; 966 prev_track_elapsed = id3->elapsed;
933 /* The metadata handle for the last loaded track has been buffered.
934 We can ask the audio thread to load the rest of the track's data. */
935 LOGFQUEUE("audio > audio Q_AUDIO_FINISH_LOAD");
936 queue_post(&audio_queue, Q_AUDIO_FINISH_LOAD, 0);
937 if (tracks[next_idx].id3_hid == hid)
938 send_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, NULL);
939 } 967 }
940 else 968 else
941 { 969 {
942 /* This is most likely an audio handle, so we strip the useless 970 prev_track_elapsed = 0;
943 trailing tags that are left. */
944 strip_tags(hid);
945
946 if (hid == tracks[track_widx-1].audio_hid
947 && filling == STATE_END_OF_PLAYLIST)
948 {
949 /* This was the last track in the playlist.
950 We now have all the data we need. */
951 logf("last track finished buffering");
952 filling = STATE_FINISHED;
953 }
954 } 971 }
955} 972}
956 973
974/* Announce the beginning of the new track */
975static void audio_playlist_track_change(void)
976{
977 struct mp3entry *id3 = valid_mp3entry(id3_get(PLAYING_ID3));
978
979 if (id3)
980 send_event(PLAYBACK_EVENT_TRACK_CHANGE, id3);
957 981
958/* --- Audio thread --- */ 982 playlist_update_resume_info(id3);
983}
959 984
960static bool audio_have_tracks(void) 985/* Change the data for the next track and send the event */
986static void audio_update_and_announce_next_track(const struct mp3entry *id3_next)
961{ 987{
962 return (audio_track_count() != 0); 988 id3_write_locked(NEXTTRACK_ID3, id3_next);
989 send_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE,
990 id3_get(NEXTTRACK_ID3));
963} 991}
964 992
965static int audio_free_track_count(void) 993/* Bring the user current mp3entry up to date and set a new offset for the
994 buffered metadata */
995static void playing_id3_sync(struct track_info *user_info, size_t offset)
966{ 996{
967 /* Used tracks + free tracks adds up to MAX_TRACK - 1 */ 997 id3_mutex_lock();
968 return MAX_TRACK - 1 - audio_track_count(); 998
999 struct mp3entry *id3 = bufgetid3(user_info->id3_hid);
1000
1001 if (offset == (size_t)-1)
1002 {
1003 struct mp3entry *ply_id3 = id3_get(PLAYING_ID3);
1004 size_t play_offset = ply_id3->offset;
1005 long play_elapsed = ply_id3->elapsed;
1006 id3_write(PLAYING_ID3, id3);
1007 ply_id3->offset = play_offset;
1008 ply_id3->elapsed = play_elapsed;
1009 offset = 0;
1010 }
1011 else
1012 {
1013 id3_write(PLAYING_ID3, id3);
1014 }
1015
1016 if (id3)
1017 id3->offset = offset;
1018
1019 id3_mutex_unlock();
969} 1020}
970 1021
971int audio_track_count(void) 1022/* Wipe-out track metadata - current is optional */
1023static void wipe_track_metadata(bool current)
972{ 1024{
973 /* Calculate difference from track_ridx to track_widx 1025 id3_mutex_lock();
974 * taking into account a possible wrap-around. */ 1026
975 return (MAX_TRACK + track_widx - track_ridx) & MAX_TRACK_MASK; 1027 if (current)
1028 id3_write(PLAYING_ID3, NULL);
1029
1030 id3_write(NEXTTRACK_ID3, NULL);
1031 id3_write(UNBUFFERED_ID3, NULL);
1032
1033 id3_mutex_unlock();
976} 1034}
977 1035
978long audio_filebufused(void) 1036/* Called when buffering is completed on the last track handle */
1037static void filling_is_finished(void)
979{ 1038{
980 return (long) buf_used(); 1039 logf("last track finished buffering");
1040
1041 /* There's no more to load or watch for */
1042 buf_set_watermark(0);
1043 filling = STATE_FINISHED;
981} 1044}
982 1045
983/* Update track info after successful a codec track change */ 1046/* Stop the codec decoding or waiting for its data to be ready - returns
984static void audio_update_trackinfo(void) 1047 'false' if the codec ended up stopped */
1048static bool halt_decoding_track(bool stop)
985{ 1049{
986 bool resume = false; 1050 /* If it was waiting for us to clear the buffer to make a rebuffer
1051 happen, it should cease otherwise codec_stop could deadlock waiting
1052 for the codec to go to its main loop - codec's request will now
1053 force-fail */
1054 bool retval = false;
987 1055
988 /* Load the curent track's metadata into curtrack_id3 */ 1056 buf_signal_handle(ci.audio_hid, true);
989 if (CUR_TI->id3_hid >= 0)
990 bufreadid3(CUR_TI->id3_hid, thistrack_id3);
991 1057
992 /* Reset current position */ 1058 if (stop)
993 thistrack_id3->elapsed = 0; 1059 codec_stop();
1060 else
1061 retval = codec_pause();
994 1062
995#ifdef HAVE_TAGCACHE 1063 audio_clear_track_notifications();
996 /* Ignoring resume position for automatic track change if so configured */
997 resume = global_settings.autoresume_enable &&
998 (!automatic_skip /* Resume all manually selected tracks */
999 || global_settings.autoresume_automatic == AUTORESUME_NEXTTRACK_ALWAYS
1000 || (global_settings.autoresume_automatic != AUTORESUME_NEXTTRACK_NEVER
1001 /* Not never resume? */
1002 && autoresumable(thistrack_id3))); /* Pass Resume filter? */
1003#endif
1004 1064
1005 if (!resume) 1065 /* We now know it's idle and not waiting for buffered data */
1006 { 1066 buf_signal_handle(ci.audio_hid, false);
1007 thistrack_id3->offset = 0;
1008 }
1009 1067
1010 logf("audio_update_trackinfo: Set offset for %s to %lX\n", 1068 codec_skip_pending = false;
1011 thistrack_id3->title, thistrack_id3->offset); 1069 codec_seeking = false;
1012 1070
1013 /* Update the codec API */ 1071 return retval;
1014 ci.filesize = CUR_TI->filesize;
1015 ci.id3 = thistrack_id3;
1016 ci.curpos = 0;
1017 ci.taginfo_ready = &CUR_TI->taginfo_ready;
1018} 1072}
1019 1073
1020/* Clear tracks between write and read, non inclusive */ 1074/* Clear the PCM on a manual skip */
1021static void audio_clear_track_entries(void) 1075static void audio_clear_paused_pcm(void)
1022{ 1076{
1023 int cur_idx = track_widx; 1077 if (play_status == PLAY_PAUSED && !pcmbuf_is_crossfade_active())
1024 1078 pcmbuf_play_stop();
1025 logf("Clearing tracks: r%d/w%d", track_ridx, track_widx); 1079}
1026 1080
1027 /* Loop over all tracks from write-to-read */ 1081/* End the ff/rw mode */
1028 while (1) 1082static void audio_ff_rewind_end(void)
1083{
1084 /* A seamless seek (not calling audio_pre_ff_rewind) skips this
1085 section */
1086 if (ff_rw_mode)
1029 { 1087 {
1030 cur_idx = (cur_idx + 1) & MAX_TRACK_MASK; 1088 ff_rw_mode = false;
1031 1089
1032 if (cur_idx == track_ridx) 1090 if (codec_seeking)
1033 break; 1091 {
1092 /* Clear the buffer */
1093 pcmbuf_play_stop();
1094 }
1034 1095
1035 clear_track_info(&tracks[cur_idx]); 1096 if (play_status != PLAY_PAUSED)
1097 {
1098 /* Seeking-while-playing, resume PCM playback */
1099 pcmbuf_pause(false);
1100 }
1036 } 1101 }
1037} 1102}
1038 1103
1039/* Clear all tracks */ 1104/* Complete the codec seek */
1040static bool audio_release_tracks(void) 1105static void audio_complete_codec_seek(void)
1041{ 1106{
1042 int i, cur_idx; 1107 /* If a seek completed while paused, 'paused' is true.
1043 1108 * If seeking from seek mode, 'ff_rw_mode' is true. */
1044 logf("releasing all tracks"); 1109 if (codec_seeking)
1045
1046 for(i = 0; i < MAX_TRACK; i++)
1047 { 1110 {
1048 cur_idx = (track_ridx + i) & MAX_TRACK_MASK; 1111 audio_ff_rewind_end();
1049 if (!clear_track_info(&tracks[cur_idx])) 1112 codec_seeking = false; /* set _after_ the call! */
1050 return false;
1051 } 1113 }
1114 /* else it's waiting and we must repond */
1115}
1052 1116
1053 return true; 1117/* Get the current cuesheet pointer */
1118static inline struct cuesheet * get_current_cuesheet(void)
1119{
1120 return audio_scratch_memory->curr_cue;
1054} 1121}
1055 1122
1056static bool audio_loadcodec(bool start_play) 1123/* Read the cuesheet from the buffer */
1124static void buf_read_cuesheet(int handle_id)
1057{ 1125{
1058 int prev_track, hid; 1126 struct cuesheet *cue = get_current_cuesheet();
1059 char codec_path[MAX_PATH]; /* Full path to codec */
1060 const struct mp3entry *id3, *prev_id3;
1061 1127
1062 if (tracks[track_widx].id3_hid < 0) { 1128 if (!cue || handle_id < 0)
1063 return false; 1129 return;
1064 }
1065 1130
1066 id3 = bufgetid3(tracks[track_widx].id3_hid); 1131 bufread(handle_id, sizeof (struct cuesheet), cue);
1067 if (!id3) 1132}
1068 return false;
1069 1133
1070 const char *codec_fn = get_codec_filename(id3->codectype); 1134/* Backend to peek/current/next track metadata interface functions -
1071 if (codec_fn == NULL) 1135 fill in the mp3entry with as much information as we may obtain about
1136 the track at the specified offset from the user current track -
1137 returns false if no information exists with us */
1138static bool audio_get_track_metadata(int offset, struct mp3entry *id3)
1139{
1140 if (play_status == PLAY_STOPPED)
1072 return false; 1141 return false;
1073 1142
1074 tracks[track_widx].codec_hid = -1; 1143 if (id3->path[0] != '\0')
1144 return true; /* Already filled */
1145
1146 struct track_info *info = track_list_user_current(offset);
1075 1147
1076 if (start_play) 1148 if (!info)
1077 { 1149 {
1078 /* Load the codec directly from disk and save some memory. */ 1150 struct mp3entry *ub_id3 = id3_get(UNBUFFERED_ID3);
1079 track_ridx = track_widx; 1151
1080 ci.filesize = CUR_TI->filesize; 1152 if (offset > 0 && track_list_user_current(offset - 1))
1081 ci.id3 = thistrack_id3; 1153 {
1082 ci.taginfo_ready = &CUR_TI->taginfo_ready; 1154 /* Try the unbuffered id3 since we're moving forward */
1083 ci.curpos = 0; 1155 if (ub_id3->path[0] != '\0')
1084 return codec_load(-1, id3->codectype); 1156 {
1157 copy_mp3entry(id3, ub_id3);
1158 return true;
1159 }
1160 }
1085 } 1161 }
1086 else 1162 else if (bufreadid3(info->id3_hid, id3))
1087 { 1163 {
1088 /* If we already have another track than this one buffered */ 1164 return true;
1089 if (track_widx != track_ridx) 1165 }
1090 {
1091 prev_track = (track_widx - 1) & MAX_TRACK_MASK;
1092
1093 id3 = bufgetid3(tracks[track_widx].id3_hid);
1094 prev_id3 = bufgetid3(tracks[prev_track].id3_hid);
1095 1166
1096 /* If the previous codec is the same as this one and the current 1167 /* We didn't find the ID3 metadata, so we fill it with the little info we
1097 * one is the correct one, there is no need to put another copy of 1168 have and return that */
1098 * it on the file buffer */
1099 if (id3 && prev_id3)
1100 {
1101 int codt = get_codec_base_type(id3->codectype);
1102 int prev_codt = get_codec_base_type(prev_id3->codectype);
1103 int cod_loaded = get_codec_base_type(codec_loaded());
1104 1169
1105 if (codt == prev_codt && codt == cod_loaded) 1170 char path[MAX_PATH+1];
1106 { 1171 if (playlist_peek(offset, path, sizeof (path)))
1107 logf("Reusing prev. codec"); 1172 {
1108 return true; 1173#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
1109 } 1174 /* Try to get it from the database */
1110 } 1175 if (!tagcache_fill_tags(id3, path))
1176#endif
1177 {
1178 /* By now, filename is the only source of info */
1179 fill_metadata_from_path(id3, path);
1111 } 1180 }
1181
1182 return true;
1112 } 1183 }
1113 1184
1114 codec_get_full_path(codec_path, codec_fn); 1185 wipe_mp3entry(id3);
1115 1186
1116 hid = tracks[track_widx].codec_hid = bufopen(codec_path, 0, TYPE_CODEC, NULL); 1187 return false;
1188}
1117 1189
1118 /* not an error if codec load it supported, will load it from disk 1190/* Get a resume rewind adjusted offset from the ID3 */
1119 * application builds don't support it 1191unsigned long resume_rewind_adjusted_offset(const struct mp3entry *id3)
1120 */ 1192{
1121 if (hid < 0 && hid != ERR_UNSUPPORTED_TYPE) 1193 unsigned long offset = id3->offset;
1122 return false; 1194 size_t resume_rewind = global_settings.resume_rewind *
1195 id3->bitrate * (1000/8);
1123 1196
1124 if (hid >= 0) 1197 if (offset < resume_rewind)
1125 logf("Loaded codec"); 1198 offset = 0;
1126 else 1199 else
1127 logf("Buffering codec unsupported, load later from disk"); 1200 offset -= resume_rewind;
1128 1201
1129 return true; 1202 return offset;
1130} 1203}
1131 1204
1132/* Load metadata for the next track (with bufopen). The rest of the track 1205/* Get the codec into ram and initialize it - keep it if it's ready */
1133 loading will be handled by audio_finish_load_track once the metadata has been 1206static bool audio_init_codec(struct track_info *track_info,
1134 actually loaded by the buffering thread. */ 1207 struct mp3entry *track_id3)
1135static bool audio_load_track(size_t offset, bool start_play)
1136{ 1208{
1137 char name_buf[MAX_PATH + 1]; 1209 int codt_loaded = get_audio_base_codec_type(codec_loaded());
1138 const char *trackname; 1210 int hid = ERR_HANDLE_NOT_FOUND;
1139 int fd = -1;
1140 1211
1141 if (track_load_started) { 1212 if (codt_loaded != AFMT_UNKNOWN)
1142 /* There is already a track load in progress, so track_widx hasn't been 1213 {
1143 incremented yet. Loading another track would overwrite the one that 1214 int codt = get_audio_base_codec_type(track_id3->codectype);
1144 hasn't finished loading. */ 1215
1145 logf("audio_load_track(): a track load is already in progress"); 1216 if (codt == codt_loaded)
1146 return false; 1217 {
1218 /* Codec is the same base type */
1219 logf("Reusing prev. codec: %d", track_id3->codectype);
1220#ifdef HAVE_CODEC_BUFFERING
1221 /* Close any buffered codec (we could have skipped directly to a
1222 format transistion that is the same format as the current track
1223 and the buffered one is no longer needed) */
1224 track_info_close_handle(&track_info->codec_hid);
1225#endif
1226 return true;
1227 }
1228 else
1229 {
1230 /* New codec - first make sure the old one's gone */
1231 logf("Removing prev. codec: %d", codt_loaded);
1232 codec_unload();
1233 }
1147 } 1234 }
1148 1235
1149 start_play_g = start_play; /* will be read by audio_finish_load_track */ 1236 logf("New codec: %d/%d", track_id3->codectype, codec_loaded());
1150 1237
1151 /* Stop buffer filling if there is no free track entries. 1238#ifdef HAVE_CODEC_BUFFERING
1152 Don't fill up the last track entry (we wan't to store next track 1239 /* Codec thread will close the handle even if it fails and will load from
1153 metadata there). */ 1240 storage if hid is not valid or the buffer load fails */
1154 if (!audio_free_track_count()) 1241 hid = track_info->codec_hid;
1155 { 1242 track_info->codec_hid = ERR_HANDLE_NOT_FOUND;
1156 logf("No free tracks"); 1243#endif
1244
1245 return codec_load(hid, track_id3->codectype);
1246 (void)track_info; /* When codec buffering isn't supported */
1247}
1248
1249/* Start the codec for the current track scheduled to be decoded */
1250static bool audio_start_codec(bool auto_skip)
1251{
1252 struct track_info *info = track_list_current(0);
1253 struct mp3entry *cur_id3 = valid_mp3entry(bufgetid3(info->id3_hid));
1254
1255 if (!cur_id3)
1157 return false; 1256 return false;
1158 }
1159 1257
1160 last_peek_offset++; 1258 buf_pin_handle(info->id3_hid, true);
1161 tracks[track_widx].taginfo_ready = false;
1162 1259
1163 logf("Buffering track: r%d/w%d", track_ridx, track_widx); 1260 if (!audio_init_codec(info, cur_id3))
1164 /* Get track name from current playlist read position. */
1165 while ((trackname = playlist_peek(last_peek_offset, name_buf,
1166 sizeof(name_buf))) != NULL)
1167 { 1261 {
1168 /* Handle broken playlists. */ 1262 buf_pin_handle(info->id3_hid, false);
1169 fd = open(trackname, O_RDONLY); 1263 return false;
1170 if (fd < 0)
1171 {
1172 logf("Open failed");
1173 /* Skip invalid entry from playlist. */
1174 playlist_skip_entry(NULL, last_peek_offset);
1175 }
1176 else
1177 break;
1178 } 1264 }
1179 1265
1180 if (!trackname) 1266#ifdef HAVE_TAGCACHE
1267 bool autoresume_enable = global_settings.autoresume_enable;
1268
1269 if (autoresume_enable && !cur_id3->offset)
1181 { 1270 {
1182 logf("End-of-playlist"); 1271 /* Resume all manually selected tracks */
1183 memset(&unbuffered_id3, 0, sizeof(struct mp3entry)); 1272 bool resume = !auto_skip;
1184 filling = STATE_END_OF_PLAYLIST; 1273
1274 /* Send the "buffer" event to obtain the resume position for the codec */
1275 send_event(PLAYBACK_EVENT_TRACK_BUFFER, cur_id3);
1185 1276
1186 if (thistrack_id3->length == 0 && thistrack_id3->filesize == 0) 1277 if (!resume)
1187 { 1278 {
1188 /* Stop playback if no valid track was found. */ 1279 /* Automatic skip - do further tests to see if we should just
1189 audio_stop_playback(); 1280 ignore any autoresume position */
1281 int autoresume_automatic = global_settings.autoresume_automatic;
1282
1283 switch (autoresume_automatic)
1284 {
1285 case AUTORESUME_NEXTTRACK_ALWAYS:
1286 /* Just resume unconditionally */
1287 resume = true;
1288 break;
1289 case AUTORESUME_NEXTTRACK_NEVER:
1290 /* Force-rewind it */
1291 break;
1292 default:
1293 /* Not "never resume" - pass resume filter? */
1294 resume = autoresumable(cur_id3);
1295 }
1190 } 1296 }
1191 1297
1192 return false; 1298 if (!resume)
1299 cur_id3->offset = 0;
1300
1301 logf("%s: Set offset for %s to %lX\n", __func__,
1302 cur_id3->title, cur_id3->offset);
1193 } 1303 }
1304#endif /* HAVE_TAGCACHE */
1194 1305
1195 tracks[track_widx].filesize = filesize(fd); 1306 /* Rewind the required amount - if an autoresume was done, this also rewinds
1307 that by the setting's amount
1196 1308
1197 if (offset > tracks[track_widx].filesize) 1309 It would be best to have bookkeeping about whether or not the track
1198 offset = 0; 1310 sounded or not since skipping to it or else skipping to it while paused
1311 and back again will cause accumulation of silent rewinds - that's not
1312 our job to track directly nor could it be in any reasonable way
1313 */
1314 cur_id3->offset = resume_rewind_adjusted_offset(cur_id3);
1315
1316 /* Update the codec API with the metadata and track info */
1317 id3_write(CODEC_ID3, cur_id3);
1199 1318
1200 /* Set default values */ 1319 ci.audio_hid = info->audio_hid;
1201 if (start_play) 1320 ci.filesize = info->filesize;
1321 buf_set_base_handle(info->audio_hid);
1322
1323 /* All required data is now available for the codec */
1324 codec_go();
1325
1326#ifdef HAVE_TAGCACHE
1327 if (!autoresume_enable || cur_id3->offset)
1328#endif
1202 { 1329 {
1203 buf_set_watermark(filebuflen/2); 1330 /* Send the "buffer" event now */
1204 dsp_configure(ci.dsp, DSP_RESET, 0); 1331 send_event(PLAYBACK_EVENT_TRACK_BUFFER, cur_id3);
1205 playlist_update_resume_info(audio_current_track());
1206 } 1332 }
1207 1333
1208 /* Get track metadata if we don't already have it. */ 1334 buf_pin_handle(info->id3_hid, false);
1209 if (tracks[track_widx].id3_hid < 0) 1335 return true;
1336
1337 (void)auto_skip; /* ifndef HAVE_TAGCACHE */
1338}
1339
1340
1341/** --- Audio thread --- **/
1342
1343/* Load and parse a cuesheet for the file - returns false if the buffer
1344 is full */
1345static bool audio_load_cuesheet(struct track_info *info,
1346 struct mp3entry *track_id3)
1347{
1348 struct cuesheet *cue = get_current_cuesheet();
1349 track_id3->cuesheet = NULL;
1350
1351 if (cue && info->cuesheet_hid == ERR_HANDLE_NOT_FOUND)
1210 { 1352 {
1211 tracks[track_widx].id3_hid = bufopen(trackname, 0, TYPE_ID3, NULL); 1353 /* If error other than a full buffer, then mark it "unsupported" to
1354 avoid reloading attempt */
1355 int hid = ERR_UNSUPPORTED_TYPE;
1356 char cuepath[MAX_PATH];
1212 1357
1213 if (tracks[track_widx].id3_hid < 0) 1358#ifdef HAVE_IO_PRIORITY
1359 buf_back_off_storage(true);
1360#endif
1361 if (look_for_cuesheet_file(track_id3->path, cuepath))
1214 { 1362 {
1215 /* Buffer is full. */ 1363 hid = bufalloc(NULL, sizeof (struct cuesheet), TYPE_CUESHEET);
1216 get_metadata(&unbuffered_id3, fd, trackname);
1217 last_peek_offset--;
1218 close(fd);
1219 logf("buffer is full for now (get metadata)");
1220 filling = STATE_FULL;
1221 return false;
1222 }
1223 1364
1224 if (track_widx == track_ridx) 1365 if (hid >= 0)
1225 { 1366 {
1226 /* TODO: Superfluos buffering call? */ 1367 void *cuesheet = NULL;
1227 buf_request_buffer_handle(tracks[track_widx].id3_hid); 1368 bufgetdata(hid, sizeof (struct cuesheet), &cuesheet);
1228 if (bufreadid3(tracks[track_widx].id3_hid, thistrack_id3)) 1369
1229 { 1370 if (parse_cuesheet(cuepath, (struct cuesheet *)cuesheet))
1230 thistrack_id3->offset = offset; 1371 {
1231 logf("audio_load_track: set offset for %s to %lX\n", 1372 /* Indicate cuesheet is present (while track remains
1232 thistrack_id3->title, 1373 buffered) */
1233 offset); 1374 track_id3->cuesheet = cue;
1375 }
1376 else
1377 {
1378 bufclose(hid);
1379 hid = ERR_UNSUPPORTED_TYPE;
1380 }
1234 } 1381 }
1235 else
1236 memset(thistrack_id3, 0, sizeof(struct mp3entry));
1237 } 1382 }
1238 1383
1239 if (start_play) 1384#ifdef HAVE_IO_PRIORITY
1385 buf_back_off_storage(false);
1386#endif
1387 if (hid == ERR_BUFFER_FULL)
1240 { 1388 {
1241 playlist_update_resume_info(audio_current_track()); 1389 logf("buffer is full for now (%s)", __func__);
1390 return false;
1391 }
1392 else
1393 {
1394 if (hid < 0)
1395 logf("Cuesheet loading failed");
1396
1397 info->cuesheet_hid = hid;
1242 } 1398 }
1243 } 1399 }
1244 1400
1245 close(fd);
1246 track_load_started = true; /* Remember that we've started loading a track */
1247 return true; 1401 return true;
1248} 1402}
1249 1403
1250#ifdef HAVE_ALBUMART 1404#ifdef HAVE_ALBUMART
1251/* Load any album art for the file */ 1405/* Load any album art for the file - returns false if the buffer is full */
1252static void audio_load_albumart(struct mp3entry *track_id3) 1406static bool audio_load_albumart(struct track_info *info,
1407 struct mp3entry *track_id3)
1253{ 1408{
1254 int i; 1409 int i;
1255
1256 FOREACH_ALBUMART(i) 1410 FOREACH_ALBUMART(i)
1257 { 1411 {
1258 struct bufopen_bitmap_data user_data; 1412 struct bufopen_bitmap_data user_data;
1259 int hid = ERR_HANDLE_NOT_FOUND; 1413 int *aa_hid = &info->aa_hid[i];
1414 int hid = ERR_UNSUPPORTED_TYPE;
1260 1415
1261 /* albumart_slots may change during a yield of bufopen, 1416 /* albumart_slots may change during a yield of bufopen,
1262 * but that's no problem */ 1417 * but that's no problem */
1263 if (tracks[track_widx].aa_hid[i] >= 0 || !albumart_slots[i].used) 1418 if (*aa_hid >= 0 || *aa_hid == ERR_UNSUPPORTED_TYPE ||
1419 !albumart_slots[i].used)
1264 continue; 1420 continue;
1265 1421
1266 memset(&user_data, 0, sizeof(user_data)); 1422 memset(&user_data, 0, sizeof(user_data));
1267 user_data.dim = &(albumart_slots[i].dim); 1423 user_data.dim = &albumart_slots[i].dim;
1268 1424
1269 /* we can only decode jpeg for embedded AA */ 1425#ifdef HAVE_IO_PRIORITY
1426 buf_back_off_storage(true);
1427#endif
1428
1429 /* We can only decode jpeg for embedded AA */
1270 if (track_id3->embed_albumart && track_id3->albumart.type == AA_TYPE_JPG) 1430 if (track_id3->embed_albumart && track_id3->albumart.type == AA_TYPE_JPG)
1271 { 1431 {
1272 user_data.embedded_albumart = &(track_id3->albumart); 1432 user_data.embedded_albumart = &track_id3->albumart;
1273 hid = bufopen(track_id3->path, 0, TYPE_BITMAP, &user_data); 1433 hid = bufopen(track_id3->path, 0, TYPE_BITMAP, &user_data);
1274 } 1434 }
1275 1435
1276 if (hid < 0 && hid != ERR_BUFFER_FULL) 1436 if (hid < 0 && hid != ERR_BUFFER_FULL)
1277 { 1437 {
1278 /* no embedded AA or it couldn't be loaded, try other sources */ 1438 /* No embedded AA or it couldn't be loaded - try other sources */
1279 char path[MAX_PATH]; 1439 char path[MAX_PATH];
1280 1440
1281 if (find_albumart(track_id3, path, sizeof(path), 1441 if (find_albumart(track_id3, path, sizeof(path),
1282 &(albumart_slots[i].dim))) 1442 &albumart_slots[i].dim))
1283 { 1443 {
1284 user_data.embedded_albumart = NULL; 1444 user_data.embedded_albumart = NULL;
1285 hid = bufopen(path, 0, TYPE_BITMAP, &user_data); 1445 hid = bufopen(path, 0, TYPE_BITMAP, &user_data);
1286 } 1446 }
1287 } 1447 }
1288 1448
1449#ifdef HAVE_IO_PRIORITY
1450 buf_back_off_storage(false);
1451#endif
1289 if (hid == ERR_BUFFER_FULL) 1452 if (hid == ERR_BUFFER_FULL)
1290 { 1453 {
1291 filling = STATE_FULL; 1454 logf("buffer is full for now (%s)", __func__);
1292 logf("buffer is full for now (get album art)"); 1455 return false;
1293 } 1456 }
1294 else if (hid < 0) 1457 else
1295 { 1458 {
1296 logf("Album art loading failed"); 1459 /* If error other than a full buffer, then mark it "unsupported"
1297 } 1460 to avoid reloading attempt */
1461 if (hid < 0)
1462 {
1463 logf("Album art loading failed");
1464 hid = ERR_UNSUPPORTED_TYPE;
1465 }
1298 1466
1299 tracks[track_widx].aa_hid[i] = hid; 1467 *aa_hid = hid;
1468 }
1300 } 1469 }
1470
1471 return true;
1301} 1472}
1302#endif 1473#endif /* HAVE_ALBUMART */
1303 1474
1304/* Second part of the track loading: We now have the metadata available, so we 1475#ifdef HAVE_CODEC_BUFFERING
1305 can load the codec, the album art and finally the audio data. 1476/* Load a codec for the file onto the buffer - assumes we're working from the
1306 This is called on the audio thread after the buffering thread calls the 1477 currently loading track - not called for the current track */
1307 buffering_handle_finished_callback callback. */ 1478static bool audio_buffer_codec(struct track_info *track_info,
1308static void audio_finish_load_track(void) 1479 struct mp3entry *track_id3)
1309{ 1480{
1310 size_t file_offset = 0; 1481 /* This will not be the current track -> it cannot be the first and the
1311 size_t offset = 0; 1482 current track cannot be ahead of buffering -> there is a previous
1312 bool start_play = start_play_g; 1483 track entry which is either current or ahead of the current */
1484 struct track_info *prev_info = track_list_last(-1);
1485 struct mp3entry *prev_id3 = bufgetid3(prev_info->id3_hid);
1313 1486
1314 track_load_started = false; 1487 /* If the previous codec is the same as this one, there is no need to
1488 put another copy of it on the file buffer (in other words, only
1489 buffer codecs at format transitions) */
1490 if (prev_id3)
1491 {
1492 int codt = get_audio_base_codec_type(track_id3->codectype);
1493 int prev_codt = get_audio_base_codec_type(prev_id3->codectype);
1315 1494
1316 if (tracks[track_widx].id3_hid < 0) { 1495 if (codt == prev_codt)
1317 logf("No metadata"); 1496 {
1318 return; 1497 logf("Reusing prev. codec: %d", prev_id3->codectype);
1498 return true;
1499 }
1319 } 1500 }
1501 /* else just load it (harmless) */
1320 1502
1321 struct mp3entry *track_id3; 1503 /* Load the codec onto the buffer if possible */
1504 const char *codec_fn = get_codec_filename(track_id3->codectype);
1505 if (!codec_fn)
1506 return false;
1322 1507
1323 if (track_widx == track_ridx) 1508 char codec_path[MAX_PATH+1]; /* Full path to codec */
1324 track_id3 = thistrack_id3; 1509 codec_get_full_path(codec_path, codec_fn);
1325 else 1510
1326 track_id3 = bufgetid3(tracks[track_widx].id3_hid); 1511 track_info->codec_hid = bufopen(codec_path, 0, TYPE_CODEC, NULL);
1327 1512
1328 if (track_id3->length == 0 && track_id3->filesize == 0) 1513 if (track_info->codec_hid >= 0)
1329 { 1514 {
1330 logf("audio_finish_load_track: invalid metadata"); 1515 logf("Buffered codec: %d", afmt);
1516 return true;
1517 }
1331 1518
1332 /* Invalid metadata */ 1519 return false;
1333 bufclose(tracks[track_widx].id3_hid); 1520}
1334 tracks[track_widx].id3_hid = -1; 1521#endif /* HAVE_CODEC_BUFFERING */
1335 1522
1336 /* Skip invalid entry from playlist. */ 1523/* Load metadata for the next track (with bufopen). The rest of the track
1337 playlist_skip_entry(NULL, last_peek_offset--); 1524 loading will be handled by audio_finish_load_track once the metadata has
1525 been actually loaded by the buffering thread.
1338 1526
1339 /* load next track */ 1527 Each track is arranged in the buffer as follows:
1340 LOGFQUEUE("audio > audio Q_AUDIO_FILL_BUFFER %d", (int)start_play); 1528 <id3|[cuesheet|][album art|][codec|]audio>
1341 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, start_play);
1342 1529
1343 return; 1530 The next will not be loaded until the previous succeeds if the buffer was
1344 } 1531 full at the time. To put any metadata after audio would make those handles
1345 /* Try to load a cuesheet for the track */ 1532 unmovable.
1346 if (curr_cue) 1533*/
1534static int audio_load_track(void)
1535{
1536 if (in_progress_id3_hid >= 0)
1347 { 1537 {
1348 char cuepath[MAX_PATH]; 1538 /* There must be an info pointer if the in-progress id3 is even there */
1349 if (look_for_cuesheet_file(track_id3->path, cuepath)) 1539 struct track_info *info = track_list_last(0);
1540
1541 if (info->id3_hid == in_progress_id3_hid)
1350 { 1542 {
1351 void *temp; 1543 if (filling == STATE_FILLING)
1352 tracks[track_widx].cuesheet_hid =
1353 bufalloc(NULL, sizeof(struct cuesheet), TYPE_CUESHEET);
1354 if (tracks[track_widx].cuesheet_hid >= 0)
1355 { 1544 {
1356 bufgetdata(tracks[track_widx].cuesheet_hid, 1545 /* Haven't finished the metadata but the notification is
1357 sizeof(struct cuesheet), &temp); 1546 anticipated to come soon */
1358 struct cuesheet *cuesheet = (struct cuesheet*)temp; 1547 logf("%s(): in progress ok: %d". __func__, info->id3_hid);
1359 if (!parse_cuesheet(cuepath, cuesheet)) 1548 return LOAD_TRACK_OK;
1360 { 1549 }
1361 bufclose(tracks[track_widx].cuesheet_hid); 1550 else if (filling == STATE_FULL)
1362 track_id3->cuesheet = NULL; 1551 {
1363 } 1552 /* Buffer was full trying to complete the load after the
1553 metadata finished, so attempt to continue - older handles
1554 should have been cleared already */
1555 logf("%s(): finishing load: %d". __func__, info->id3_hid);
1556 filling = STATE_FILLING;
1557 buffer_event_finished_callback(&info->id3_hid);
1558 return LOAD_TRACK_OK;
1364 } 1559 }
1365 } 1560 }
1561
1562 /* Some old, stray buffering message */
1563 logf("%s(): already in progress: %d". __func__, info->id3_hid);
1564 return LOAD_TRACK_ERR_BUSY;
1366 } 1565 }
1367 1566
1368#ifdef HAVE_ALBUMART 1567 filling = STATE_FILLING;
1369 audio_load_albumart(track_id3); 1568
1370#endif 1569 struct track_info *info = track_list_alloc_track();
1570 if (info == NULL)
1571 {
1572 /* List is full so stop buffering tracks - however, attempt to obtain
1573 metadata as the unbuffered id3 */
1574 logf("No free tracks");
1575 filling = STATE_FULL;
1576 }
1577
1578 playlist_peek_offset++;
1579
1580 logf("Buffering track: s%u/c%u/e%u/p%d",
1581 track_list.start, track_list.current, track_list.end,
1582 playlist_peek_offset);
1583
1584 /* Get track name from current playlist read position */
1585 int fd = -1;
1586 char name_buf[MAX_PATH + 1];
1587 const char *trackname;
1371 1588
1372 /* Load the codec. */ 1589 while (1)
1373 if (!audio_loadcodec(start_play))
1374 { 1590 {
1375 if (tracks[track_widx].codec_hid == ERR_BUFFER_FULL) 1591
1592 trackname = playlist_peek(playlist_peek_offset, name_buf,
1593 sizeof (name_buf));
1594
1595 if (!trackname)
1596 break;
1597
1598 /* Test for broken playlists by probing for the files */
1599 fd = open(trackname, O_RDONLY);
1600 if (fd >= 0)
1601 break;
1602
1603 logf("Open failed");
1604 /* Skip invalid entry from playlist */
1605 playlist_skip_entry(NULL, playlist_peek_offset);
1606
1607 /* Sync the playlist if it isn't finished */
1608 if (playlist_peek(playlist_peek_offset, NULL, 0))
1609 playlist_next(0);
1610 }
1611
1612 if (!trackname)
1613 {
1614 /* No track - exhausted the playlist entries */
1615 logf("End-of-playlist");
1616 id3_write_locked(UNBUFFERED_ID3, NULL);
1617
1618 if (filling != STATE_FULL)
1619 track_list_unalloc_track(); /* Free this entry */
1620
1621 playlist_peek_offset--; /* Maintain at last index */
1622
1623 /* We can end up here after the real last track signals its completion
1624 and miss the transition to STATE_FINISHED esp. if dropping the last
1625 songs of a playlist late in their load (2nd stage) */
1626 info = track_list_last(0);
1627
1628 if (info && buf_handle_remaining(info->audio_hid) == 0)
1629 filling_is_finished();
1630 else
1631 filling = STATE_END_OF_PLAYLIST;
1632
1633 return LOAD_TRACK_ERR_NO_MORE;
1634 }
1635
1636 /* Successfully opened the file - get track metadata */
1637 if (filling == STATE_FULL ||
1638 (info->id3_hid = bufopen(trackname, 0, TYPE_ID3, NULL)) < 0)
1639 {
1640 /* Buffer or track list is full */
1641 struct mp3entry *ub_id3;
1642
1643 playlist_peek_offset--;
1644
1645 /* Load the metadata for the first unbuffered track */
1646 ub_id3 = id3_get(UNBUFFERED_ID3);
1647 id3_mutex_lock();
1648 get_metadata(ub_id3, fd, trackname);
1649 id3_mutex_unlock();
1650
1651 if (filling != STATE_FULL)
1376 { 1652 {
1377 /* No space for codec on buffer, not an error */ 1653 track_list_unalloc_track();
1378 filling = STATE_FULL; 1654 filling = STATE_FULL;
1379 return;
1380 } 1655 }
1381 1656
1382 /* This is an error condition, either no codec was found, or reading 1657 logf("%s: buffer is full for now (%u tracks)", __func__,
1383 * the codec file failed part way through, either way, skip the track */ 1658 track_list_count());
1384 /* FIXME: We should not use splashf from audio thread! */ 1659 }
1385 splashf(HZ*2, "No codec for: %s", track_id3->path); 1660 else
1386 /* Skip invalid entry from playlist. */ 1661 {
1387 playlist_skip_entry(NULL, last_peek_offset); 1662 /* Successful load initiation */
1388 return; 1663 info->filesize = filesize(fd);
1664 in_progress_id3_hid = info->id3_hid; /* Remember what's in-progress */
1389 } 1665 }
1390 1666
1391 track_id3->elapsed = 0; 1667 close(fd);
1392 offset = track_id3->offset; 1668 return LOAD_TRACK_OK;
1393 size_t resume_rewind = (global_settings.resume_rewind * 1669}
1394 track_id3->bitrate * 1000) / 8;
1395 1670
1396 if (offset < resume_rewind) 1671/* Second part of the track loading: We now have the metadata available, so we
1672 can load the codec, the album art and finally the audio data.
1673 This is called on the audio thread after the buffering thread calls the
1674 buffering_handle_finished_callback callback. */
1675static int audio_finish_load_track(struct track_info *info)
1676{
1677 int trackstat = LOAD_TRACK_OK;
1678
1679 if (info->id3_hid != in_progress_id3_hid)
1397 { 1680 {
1398 offset = 0; 1681 /* We must not be here if not! */
1682 logf("%s: wrong track %d/%d", __func__, info->id3_hid,
1683 in_progress_id3_hid);
1684 return LOAD_TRACK_ERR_BUSY;
1399 } 1685 }
1400 else 1686
1687 /* The current track for decoding (there is always one if the list is
1688 populated) */
1689 struct track_info *cur_info = track_list_current(0);
1690 struct mp3entry *track_id3 = valid_mp3entry(bufgetid3(info->id3_hid));
1691
1692 if (!track_id3)
1401 { 1693 {
1402 offset -= resume_rewind; 1694 /* This is an error condition. Track cannot be played without valid
1695 metadata; skip the track. */
1696 logf("No metadata for: %s", track_id3->path);
1697 trackstat = LOAD_TRACK_ERR_FINISH_FAILED;
1698 goto audio_finish_load_track_exit;
1699 }
1700
1701 /* Try to load a cuesheet for the track */
1702 if (!audio_load_cuesheet(info, track_id3))
1703 {
1704 /* No space for cuesheet on buffer, not an error */
1705 filling = STATE_FULL;
1706 goto audio_finish_load_track_exit;
1403 } 1707 }
1404 1708
1405 enum data_type type = TYPE_PACKET_AUDIO; 1709#ifdef HAVE_ALBUMART
1710 /* Try to load album art for the track */
1711 if (!audio_load_albumart(info, track_id3))
1712 {
1713 /* No space for album art on buffer, not an error */
1714 filling = STATE_FULL;
1715 goto audio_finish_load_track_exit;
1716 }
1717#endif
1406 1718
1407 switch (track_id3->codectype) { 1719#ifdef HAVE_CODEC_BUFFERING
1408 case AFMT_MPA_L1: 1720 /* Try to buffer a codec for the track */
1409 case AFMT_MPA_L2: 1721 if (info != cur_info && !audio_buffer_codec(info, track_id3))
1410 case AFMT_MPA_L3: 1722 {
1411 if (offset > 0) { 1723 if (info->codec_hid == ERR_BUFFER_FULL)
1412 file_offset = offset; 1724 {
1725 /* No space for codec on buffer, not an error */
1726 filling = STATE_FULL;
1727 logf("buffer is full for now (%s)", __func__);
1413 } 1728 }
1414 break; 1729 else
1415 1730 {
1416 case AFMT_WAVPACK: 1731 /* This is an error condition, either no codec was found, or
1417 if (offset > 0) { 1732 reading the codec file failed part way through, either way,
1418 file_offset = offset; 1733 skip the track */
1419 track_id3->elapsed = track_id3->length / 2; 1734 logf("No codec for: %s", track_id3->path);
1735 trackstat = LOAD_TRACK_ERR_FINISH_FAILED;
1420 } 1736 }
1421 break;
1422 1737
1423 case AFMT_NSF: 1738 goto audio_finish_load_track_exit;
1424 case AFMT_SPC:
1425 case AFMT_SID:
1426 logf("Loading atomic %d",track_id3->codectype);
1427 type = TYPE_ATOMIC_AUDIO;
1428 break;
1429
1430 default:
1431 /* no special treatment needed */
1432 break;
1433 } 1739 }
1740#endif /* HAVE_CODEC_BUFFERING */
1434 1741
1435 track_id3->offset = offset; 1742 /** Finally, load the audio **/
1743 size_t file_offset = 0;
1744 track_id3->elapsed = 0;
1745
1746 if (track_id3->offset >= info->filesize)
1747 track_id3->offset = 0;
1748
1749 logf("%s: set offset for %s to %lu\n", __func__,
1750 id3->title, (unsigned long)offset);
1751
1752 /* Adjust for resume rewind so we know what to buffer - starting the codec
1753 calls it again, so we don't save it (and they shouldn't accumulate) */
1754 size_t offset = resume_rewind_adjusted_offset(track_id3);
1755
1756 enum data_type audiotype = get_audio_base_data_type(track_id3->codectype);
1757
1758 if (audiotype == TYPE_ATOMIC_AUDIO)
1759 logf("Loading atomic %d", track_id3->codectype);
1760
1761 if (format_buffers_with_offset(track_id3->codectype))
1762 {
1763 /* This format can begin buffering from any point */
1764 file_offset = offset;
1765 }
1436 1766
1437 logf("load track: %s", track_id3->path); 1767 logf("load track: %s", track_id3->path);
1438 1768
1439 if (file_offset > AUDIO_REBUFFER_GUESS_SIZE) 1769 if (file_offset > AUDIO_REBUFFER_GUESS_SIZE)
1770 {
1771 /* We can buffer later in the file, adjust the hunt-and-peck margin */
1440 file_offset -= AUDIO_REBUFFER_GUESS_SIZE; 1772 file_offset -= AUDIO_REBUFFER_GUESS_SIZE;
1441 else if (track_id3->first_frame_offset) 1773 }
1442 file_offset = track_id3->first_frame_offset;
1443 else 1774 else
1444 file_offset = 0; 1775 {
1776 /* No offset given or it is very minimal - begin at the first frame
1777 according to the metadata */
1778 file_offset = track_id3->first_frame_offset;
1779 }
1445 1780
1446 tracks[track_widx].audio_hid = bufopen(track_id3->path, file_offset, type, 1781 int hid = bufopen(track_id3->path, file_offset, audiotype, NULL);
1447 NULL);
1448 1782
1449 /* No space left, not an error */ 1783 if (hid >= 0)
1450 if (tracks[track_widx].audio_hid == ERR_BUFFER_FULL)
1451 { 1784 {
1452 filling = STATE_FULL; 1785 info->audio_hid = hid;
1453 logf("buffer is full for now (load audio)"); 1786
1454 return; 1787 if (info == cur_info)
1788 {
1789 /* This is the current track to decode - should be started now */
1790 trackstat = LOAD_TRACK_READY;
1791 }
1455 } 1792 }
1456 else if (tracks[track_widx].audio_hid < 0) 1793 else
1457 { 1794 {
1458 /* another error, do not continue either */ 1795 /* Buffer could be full but not properly so if this is the only
1459 logf("Could not add audio data handle"); 1796 track! */
1460 return; 1797 if (hid == ERR_BUFFER_FULL && audio_track_count() > 1)
1798 {
1799 filling = STATE_FULL;
1800 logf("Buffer is full for now (%s)", __func__);
1801 }
1802 else
1803 {
1804 /* Nothing to play if no audio handle - skip this */
1805 logf("Could not add audio data handle");
1806 trackstat = LOAD_TRACK_ERR_FINISH_FAILED;
1807 }
1461 } 1808 }
1462 1809
1463 /* All required data is now available for the codec -- unless the 1810audio_finish_load_track_exit:
1464 autoresume feature is in effect. In the latter case, the codec 1811 if (trackstat < LOAD_TRACK_OK)
1465 must wait until after PLAYBACK_EVENT_TRACK_BUFFER, which may
1466 generate a resume position. */
1467#ifdef HAVE_TAGCACHE
1468 if (!global_settings.autoresume_enable || offset)
1469#endif
1470 tracks[track_widx].taginfo_ready = true;
1471
1472 if (start_play)
1473 { 1812 {
1474 ci.curpos=file_offset; 1813 playlist_skip_entry(NULL, playlist_peek_offset);
1475 buf_request_buffer_handle(tracks[track_widx].audio_hid); 1814 track_info_close(info);
1476 } 1815 track_list_unalloc_track();
1477 1816
1478 send_event(PLAYBACK_EVENT_TRACK_BUFFER, track_id3); 1817 if (playlist_peek(playlist_peek_offset, NULL, 0))
1818 playlist_next(0);
1479 1819
1480#ifdef HAVE_TAGCACHE 1820 playlist_peek_offset--;
1481 /* In case the autoresume feature has been enabled, finally all 1821 }
1482 required data is available for the codec. */
1483 if (global_settings.autoresume_enable && !offset)
1484 tracks[track_widx].taginfo_ready = true;
1485#endif
1486
1487 track_widx = (track_widx + 1) & MAX_TRACK_MASK;
1488 1822
1489 /* load next track */ 1823 if (filling != STATE_FULL)
1490 LOGFQUEUE("audio > audio Q_AUDIO_FILL_BUFFER"); 1824 {
1491 queue_post(&audio_queue, Q_AUDIO_FILL_BUFFER, 0); 1825 /* Load next track - error or not */
1826 in_progress_id3_hid = ERR_HANDLE_NOT_FOUND;
1827 LOGFQUEUE("audio > audio Q_AUDIO_FILL_BUFFER");
1828 audio_queue_post(Q_AUDIO_FILL_BUFFER, 0);
1829 }
1830 else
1831 {
1832 /* Full */
1833 trackstat = LOAD_TRACK_ERR_FINISH_FULL;
1834 }
1492 1835
1493 return; 1836 return trackstat;
1494} 1837}
1495 1838
1496static void audio_fill_file_buffer(bool start_play, size_t offset) 1839/* Start a new track load */
1840static int audio_fill_file_buffer(void)
1497{ 1841{
1498 trigger_cpu_boost(); 1842 if (play_status == PLAY_STOPPED)
1843 return LOAD_TRACK_ERR_FAILED;
1499 1844
1500 /* No need to rebuffer if there are track skips pending, 1845 trigger_cpu_boost();
1501 * however don't cancel buffering on skipping while filling. */
1502 if (ci.new_track != 0 && filling != STATE_FILLING)
1503 return;
1504 filling = STATE_FILLING;
1505 1846
1506 /* Must reset the buffer before use if trashed or voice only - voice 1847 /* Must reset the buffer before use if trashed or voice only - voice
1507 file size shouldn't have changed so we can go straight from 1848 file size shouldn't have changed so we can go straight from
@@ -1511,772 +1852,1848 @@ static void audio_fill_file_buffer(bool start_play, size_t offset)
1511 1852
1512 logf("Starting buffer fill"); 1853 logf("Starting buffer fill");
1513 1854
1514 if (!start_play) 1855 int trackstat = audio_load_track();
1515 audio_clear_track_entries();
1516 1856
1517 /* Save the current resume position once. */ 1857 if (trackstat >= LOAD_TRACK_OK)
1518 playlist_update_resume_info(audio_current_track()); 1858 {
1859 if (track_list_current(0) == track_list_user_current(0))
1860 playlist_next(0);
1519 1861
1520 audio_load_track(offset, start_play); 1862 if (filling == STATE_FULL && !track_list_user_current(1))
1863 {
1864 /* There are no user tracks on the buffer after this therefore
1865 this is the next track */
1866 audio_update_and_announce_next_track(id3_get(UNBUFFERED_ID3));
1867 }
1868 }
1869
1870 return trackstat;
1521} 1871}
1522 1872
1523static void audio_rebuffer(void) 1873/* Discard unwanted tracks and start refill from after the specified playlist
1874 offset */
1875static int audio_reset_and_rebuffer(
1876 enum track_clear_action action, int peek_offset)
1524{ 1877{
1525 logf("Forcing rebuffer"); 1878 logf("Forcing rebuffer: 0x%X, %d", flags, peek_offset);
1526 1879
1527 clear_track_info(CUR_TI); 1880 id3_write_locked(UNBUFFERED_ID3, NULL);
1528 1881
1529 /* Reset track pointers */ 1882 /* Remove unwanted tracks - caller must have ensured codec isn't using
1530 track_widx = track_ridx; 1883 any */
1531 audio_clear_track_entries(); 1884 track_list_clear(action);
1532 1885
1533 /* Reset a possibly interrupted track load */ 1886 /* Refill at specified position (-1 starts at index offset 0) */
1534 track_load_started = false; 1887 playlist_peek_offset = peek_offset;
1535 1888
1536 /* Fill the buffer */ 1889 /* Fill the buffer */
1537 last_peek_offset = -1; 1890 return audio_fill_file_buffer();
1538 ci.curpos = 0; 1891}
1539 1892
1540 if (!CUR_TI->taginfo_ready) 1893/* Handle buffering events
1541 memset(thistrack_id3, 0, sizeof(struct mp3entry)); 1894 (Q_AUDIO_BUFFERING) */
1895static void audio_on_buffering(int event)
1896{
1897 enum track_clear_action action;
1898 int peek_offset;
1899
1900 if (track_list_empty())
1901 return;
1902
1903 switch (event)
1904 {
1905 case BUFFER_EVENT_BUFFER_LOW:
1906 if (filling != STATE_FULL && filling != STATE_END_OF_PLAYLIST)
1907 return; /* Should be nothing left to fill */
1908
1909 /* Clear old tracks and continue buffering where it left off */
1910 action = TRACK_LIST_KEEP_NEW;
1911 peek_offset = playlist_peek_offset;
1912 break;
1542 1913
1543 audio_fill_file_buffer(false, 0); 1914 case BUFFER_EVENT_REBUFFER:
1915 /* Remove all but the currently decoding track and redo buffering
1916 after that */
1917 action = TRACK_LIST_KEEP_CURRENT;
1918 peek_offset = (skip_pending == TRACK_SKIP_AUTO) ? 1 : 0;
1919 break;
1920
1921 default:
1922 return;
1923 }
1924
1925 switch (skip_pending)
1926 {
1927 case TRACK_SKIP_NONE:
1928 case TRACK_SKIP_AUTO:
1929 case TRACK_SKIP_AUTO_NEW_PLAYLIST:
1930 audio_reset_and_rebuffer(action, peek_offset);
1931 break;
1932
1933 case TRACK_SKIP_AUTO_END_PLAYLIST:
1934 /* Already finished */
1935 break;
1936
1937 default:
1938 /* Invalid */
1939 logf("Buffering call, inv. state: %d", (int)skip_pending);
1940 }
1544} 1941}
1545 1942
1546/* Called on request from the codec to get a new track. This is the codec part 1943/* Handle starting the next track load
1547 of the track transition. */ 1944 (Q_AUDIO_FILL_BUFFER) */
1548static void audio_last_track(bool automatic) 1945static void audio_on_fill_buffer(void)
1549{ 1946{
1550 if (automatic) 1947 audio_handle_track_load_status(audio_fill_file_buffer());
1948}
1949
1950/* Handle posted load track finish event
1951 (Q_AUDIO_FINISH_LOAD_TRACK) */
1952static void audio_on_finish_load_track(int id3_hid)
1953{
1954 struct track_info *info = track_list_last(0);
1955
1956 if (!info || !buf_is_handle(id3_hid))
1957 return;
1958
1959 if (info == track_list_user_current(1))
1551 { 1960 {
1552 ci.new_track = 0; 1961 /* Just loaded the metadata right after the current position */
1553 automatic_skip = false; 1962 audio_update_and_announce_next_track(bufgetid3(info->id3_hid));
1963 }
1554 1964
1555 if (filling != STATE_ENDING) 1965 if (audio_finish_load_track(info) != LOAD_TRACK_READY)
1966 return; /* Not current track */
1967
1968 bool is_user_current = info == track_list_user_current(0);
1969
1970 if (is_user_current)
1971 {
1972 /* Copy cuesheet */
1973 buf_read_cuesheet(info->cuesheet_hid);
1974 }
1975
1976 if (audio_start_codec(automatic_skip))
1977 {
1978 if (is_user_current)
1556 { 1979 {
1557 /* Monitor remaining PCM before stopping */ 1980 /* Be sure all tagtree info is synchronized; it will be needed for the
1558 filling = STATE_ENDING; 1981 track finish event - the sync will happen when finalizing a track
1559 pcmbuf_monitor_track_change(true); 1982 change otherwise */
1560 } 1983 bool was_valid = valid_mp3entry(id3_get(PLAYING_ID3));
1561 1984
1562 codec_stop(); 1985 playing_id3_sync(info, -1);
1986
1987 if (!was_valid)
1988 {
1989 /* Playing id3 hadn't been updated yet because no valid track
1990 was yet available - treat like the first track */
1991 audio_playlist_track_change();
1992 }
1993 }
1563 } 1994 }
1564 else 1995 else
1565 { 1996 {
1997 audio_handle_track_load_status(LOAD_TRACK_ERR_START_CODEC);
1998 }
1999}
2000
2001/* Called when handles other than metadata handles have finished buffering
2002 (Q_AUDIO_HANDLE_FINISHED) */
2003static void audio_on_handle_finished(int hid)
2004{
2005 /* Right now, only audio handles should end up calling this */
2006 if (filling == STATE_END_OF_PLAYLIST)
2007 {
2008 struct track_info *info = track_list_last(0);
2009
2010 /* Really we don't know which order the handles will actually complete
2011 to zero bytes remaining since another thread is doing it - be sure
2012 it's the right one */
2013 if (info && info->audio_hid == hid)
2014 {
2015 /* This was the last track in the playlist and we now have all the
2016 data we need */
2017 filling_is_finished();
2018 }
2019 }
2020}
2021
2022/* Called to make an outstanding track skip the current track and to send the
2023 transition events */
2024static void audio_finalise_track_change(bool delayed)
2025{
2026 switch (skip_pending)
2027 {
2028 case TRACK_SKIP_NONE: /* Manual skip */
2029 break;
2030
2031 case TRACK_SKIP_AUTO:
2032 case TRACK_SKIP_AUTO_NEW_PLAYLIST:
2033 {
2034 int playlist_delta = skip_pending == TRACK_SKIP_AUTO ? 1 : 0;
2035 audio_playlist_track_finish();
2036
2037 if (!playlist_peek(playlist_delta, NULL, 0))
2038 {
2039 /* Track ended up rejected - push things ahead like the codec blew
2040 it (because it was never started and now we're here where it
2041 should have been decoding the next track by now) - next, a
2042 directory change or end of playback will most likely happen */
2043 skip_pending = TRACK_SKIP_NONE;
2044 audio_handle_track_load_status(LOAD_TRACK_ERR_START_CODEC);
2045 return;
2046 }
2047
2048 if (!playlist_delta)
2049 break;
2050
2051 playlist_peek_offset -= playlist_delta;
2052 if (playlist_next(playlist_delta) >= 0)
2053 break;
2054 /* What!? Disappear? Hopeless bleak despair */
2055 }
2056 /* Fallthrough */
2057 case TRACK_SKIP_AUTO_END_PLAYLIST:
2058 default: /* Invalid */
2059 filling = STATE_ENDED;
1566 audio_stop_playback(); 2060 audio_stop_playback();
2061 return;
2062 }
2063
2064 struct track_info *info = track_list_current(0);
2065 struct mp3entry *track_id3 = NULL;
2066
2067 id3_mutex_lock();
2068
2069 /* Update the current cuesheet if any and enabled */
2070 if (info)
2071 {
2072 buf_read_cuesheet(info->cuesheet_hid);
2073 track_id3 = bufgetid3(info->id3_hid);
2074 }
2075
2076 id3_write(PLAYING_ID3, track_id3);
2077
2078 if (delayed)
2079 {
2080 /* Delayed skip where codec is ahead of user's current track */
2081 struct mp3entry *ci_id3 = id3_get(CODEC_ID3);
2082 struct mp3entry *ply_id3 = id3_get(PLAYING_ID3);
2083 ply_id3->elapsed = ci_id3->elapsed;
2084 ply_id3->offset = ci_id3->offset;
1567 } 2085 }
2086
2087 /* The skip is technically over */
2088 skip_pending = TRACK_SKIP_NONE;
2089
2090 /* Sync the next track information */
2091 info = track_list_current(1);
2092
2093 id3_write(NEXTTRACK_ID3, info ? bufgetid3(info->id3_hid) :
2094 id3_get(UNBUFFERED_ID3));
2095
2096 id3_mutex_unlock();
2097
2098 audio_playlist_track_change();
1568} 2099}
1569 2100
1570static void audio_check_new_track(void) 2101/* Actually begin a transition and take care of the codec change - may complete
2102 it now or ask pcmbuf for notification depending on the type and what pcmbuf
2103 has to say */
2104static void audio_begin_track_change(bool auto_skip, int trackstat)
1571{ 2105{
1572 int track_count; 2106 /* Even if the new track is bad, the old track must be finished off */
1573 int old_track_ridx; 2107 bool finalised = pcmbuf_start_track_change(auto_skip);
1574 int i, idx;
1575 bool forward;
1576 struct mp3entry *temp;
1577 2108
1578 if (ci.new_track == 0) 2109 if (finalised)
1579 { 2110 {
1580 ci.new_track++; 2111 /* pcmbuf says that the transition happens now - complete it */
1581 automatic_skip = true; 2112 audio_finalise_track_change(false);
2113
2114 if (play_status == PLAY_STOPPED)
2115 return; /* Stopped us */
2116 }
2117
2118 if (!auto_skip)
2119 audio_clear_paused_pcm();
2120
2121 if (trackstat >= LOAD_TRACK_OK)
2122 {
2123 struct track_info *info = track_list_current(0);
2124
2125 if (info->audio_hid < 0)
2126 return;
2127
2128 /* Everything needed for the codec is ready - start it */
2129 if (audio_start_codec(auto_skip))
2130 {
2131 if (finalised)
2132 playing_id3_sync(info, -1);
2133 return;
2134 }
2135
2136 trackstat = LOAD_TRACK_ERR_START_CODEC;
1582 } 2137 }
1583 2138
1584 track_count = audio_track_count(); 2139 audio_handle_track_load_status(trackstat);
1585 old_track_ridx = track_ridx; 2140}
2141
2142/* Transition to end-of-playlist state and begin wait for PCM to finish */
2143static void audio_monitor_end_of_playlist(void)
2144{
2145 skip_pending = TRACK_SKIP_AUTO_END_PLAYLIST;
2146 filling = STATE_ENDING;
2147 pcmbuf_monitor_track_change(true);
2148}
2149
2150/* Codec has completed decoding the track
2151 (usually Q_AUDIO_CODEC_COMPLETE) */
2152static void audio_on_codec_complete(int status)
2153{
2154 logf("%s(%d)", __func__, status);
1586 2155
1587 /* Now it's good time to send track finish events. */ 2156 if (play_status == PLAY_STOPPED)
1588 send_event(PLAYBACK_EVENT_TRACK_FINISH, thistrack_id3); 2157 return;
1589 /* swap the mp3entry pointers */
1590 temp = thistrack_id3;
1591 thistrack_id3 = othertrack_id3;
1592 othertrack_id3 = temp;
1593 ci.id3 = thistrack_id3;
1594 memset(thistrack_id3, 0, sizeof(struct mp3entry));
1595 2158
1596 if (dir_skip) 2159 /* If it didn't notify us first, don't expect "seek complete" message
2160 since the codec can't post it now - do things like it would have
2161 done */
2162 audio_complete_codec_seek();
2163
2164 if (play_status == PLAY_PAUSED || skip_pending != TRACK_SKIP_NONE)
1597 { 2165 {
1598 dir_skip = false; 2166 /* Old-hay on the ip-skay - codec has completed decoding
1599 /* regardless of the return value we need to rebuffer. 2167
1600 if it fails the old playlist will resume, else the 2168 Paused: We're not sounding it, so just remember that it happened
1601 next dir will start playing */ 2169 and the resume will begin the transition
1602 playlist_next_dir(ci.new_track); 2170
1603 ci.new_track = 0; 2171 Skipping: There was already a skip in progress, remember it and
1604 audio_rebuffer(); 2172 allow no further progress until the PCM from the previous
1605 goto skip_done; 2173 song has finished
2174 */
2175 codec_skip_pending = true;
2176 codec_skip_status = status;
2177 return;
1606 } 2178 }
1607 2179
1608 if (new_playlist) 2180 codec_skip_pending = false;
1609 ci.new_track = 0;
1610 2181
1611 /* If the playlist isn't that big */ 2182 if (status >= 0)
1612 if (automatic_skip)
1613 { 2183 {
1614 while (!playlist_check(ci.new_track)) 2184 /* Normal automatic skip */
2185 ab_end_of_track_report();
2186 }
2187
2188 int trackstat = LOAD_TRACK_OK;
2189
2190 automatic_skip = true;
2191 skip_pending = TRACK_SKIP_AUTO;
2192
2193 /* Does this track have an entry allocated? */
2194 struct track_info *info = track_list_advance_current(1);
2195
2196 if (!info || info->audio_hid < 0)
2197 {
2198 bool end_of_playlist = false;
2199
2200 if (info)
1615 { 2201 {
1616 if (ci.new_track >= 0) 2202 /* Track load is not complete - it might have stopped on a
2203 full buffer without reaching the audio handle or we just
2204 arrived at it early
2205
2206 If this type is atomic and we couldn't get the audio,
2207 perhaps it would need to wrap to make the allocation and
2208 handles are in the way - to maximize the liklihood it can
2209 be allocated, clear all handles to reset the buffer and
2210 its indexes to 0 - for packet audio, this should not be an
2211 issue and a pointless full reload of all the track's
2212 metadata may be avoided */
2213
2214 struct mp3entry *track_id3 = bufgetid3(info->id3_hid);
2215
2216 if (track_id3 &&
2217 get_audio_base_data_type(track_id3->codectype)
2218 == TYPE_PACKET_AUDIO)
1617 { 2219 {
1618 audio_last_track(true); 2220 /* Continue filling after this track */
2221 audio_reset_and_rebuffer(TRACK_LIST_KEEP_CURRENT, 1);
2222 audio_begin_track_change(true, trackstat);
1619 return; 2223 return;
1620 } 2224 }
1621 ci.new_track++; 2225 /* else rebuffer at this track; status applies to the track we
2226 want */
2227 }
2228 else if (!playlist_peek(1, NULL, 0))
2229 {
2230 /* Play sequence is complete - directory change or other playlist
2231 resequencing - the playlist must now be advanced in order to
2232 continue since a peek ahead to the next track is not possible */
2233 skip_pending = TRACK_SKIP_AUTO_NEW_PLAYLIST;
2234 end_of_playlist = playlist_next(1) < 0;
2235 }
2236
2237 if (!end_of_playlist)
2238 {
2239 trackstat = audio_reset_and_rebuffer(TRACK_LIST_CLEAR_ALL,
2240 skip_pending == TRACK_SKIP_AUTO ? 0 : -1);
2241
2242 if (trackstat == LOAD_TRACK_ERR_NO_MORE)
2243 {
2244 /* Failed to find anything afterall - do playlist switchover
2245 instead */
2246 skip_pending = TRACK_SKIP_AUTO_NEW_PLAYLIST;
2247 end_of_playlist = playlist_next(1) < 0;
2248 }
2249 }
2250
2251 if (end_of_playlist)
2252 {
2253 audio_monitor_end_of_playlist();
2254 return;
2255 }
2256 }
2257
2258 audio_begin_track_change(true, trackstat);
2259}
2260
2261/* Called when codec completes seek operation
2262 (usually Q_AUDIO_CODEC_SEEK_COMPLETE) */
2263static void audio_on_codec_seek_complete(void)
2264{
2265 logf("%s()", __func__);
2266 audio_complete_codec_seek();
2267 codec_go();
2268}
2269
2270/* Called when PCM track change has completed
2271 (Q_AUDIO_TRACK_CHANGED) */
2272static void audio_on_track_changed(void)
2273{
2274 /* Finish whatever is pending so that the WPS is in sync */
2275 audio_finalise_track_change(true);
2276
2277 if (codec_skip_pending)
2278 {
2279 /* Codec got ahead completing a short track - complete the
2280 codec's skip and begin the next */
2281 codec_skip_pending = false;
2282 audio_on_codec_complete(codec_skip_status);
2283 }
2284}
2285
2286/* Begin playback from an idle state, transition to a new playlist or
2287 invalidate the buffer and resume (if playing).
2288 (usually Q_AUDIO_PLAY, Q_AUDIO_REMAKE_AUDIO_BUFFER) */
2289static void audio_start_playback(size_t offset, unsigned int flags)
2290{
2291 enum play_status old_status = play_status;
2292
2293 if (flags & AUDIO_START_NEWBUF)
2294 {
2295 /* Mark the buffer dirty - if not playing, it will be reset next
2296 time */
2297 if (buffer_state == AUDIOBUF_STATE_INITIALIZED)
2298 buffer_state = AUDIOBUF_STATE_VOICED_ONLY;
2299 }
2300
2301 if (old_status != PLAY_STOPPED)
2302 {
2303 logf("%s(%lu): skipping", __func__, (unsigned long)offset);
2304
2305 halt_decoding_track(true);
2306
2307 automatic_skip = false;
2308 ff_rw_mode = false;
2309
2310 if (flags & AUDIO_START_RESTART)
2311 {
2312 /* Clear out some stuff to resume the current track where it
2313 left off */
2314 pcmbuf_play_stop();
2315 offset = id3_get(PLAYING_ID3)->offset;
2316 track_list_clear(TRACK_LIST_CLEAR_ALL);
2317 }
2318 else
2319 {
2320 /* This is more-or-less treated as manual track transition */
2321 /* Save resume information for current track */
2322 audio_playlist_track_finish();
2323 track_list_clear(TRACK_LIST_CLEAR_ALL);
2324
2325 /* Indicate manual track change */
2326 pcmbuf_start_track_change(false);
2327 audio_clear_paused_pcm();
2328 wipe_track_metadata(true);
1622 } 2329 }
2330
2331 /* Set after track finish event in case skip was in progress */
2332 skip_pending = TRACK_SKIP_NONE;
2333 }
2334 else
2335 {
2336 if (flags & AUDIO_START_RESTART)
2337 return; /* Must already be playing */
2338
2339 /* Cold playback start from a stopped state */
2340 logf("%s(%lu): starting", __func__, offset);
2341
2342 /* Set audio parameters */
2343#if INPUT_SRC_CAPS != 0
2344 audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
2345 audio_set_output_source(AUDIO_SRC_PLAYBACK);
2346#endif
2347#ifndef PLATFORM_HAS_VOLUME_CHANGE
2348 sound_set_volume(global_settings.volume);
2349#endif
2350 /* Update our state */
2351 play_status = PLAY_PLAYING;
2352 }
2353
2354 /* Start fill from beginning of playlist */
2355 playlist_peek_offset = -1;
2356 buf_set_base_handle(-1);
2357
2358 /* Officially playing */
2359 queue_reply(&audio_queue, 1);
2360
2361 /* Add these now - finish event for the first id3 will most likely be sent
2362 immediately */
2363 add_event(BUFFER_EVENT_REBUFFER, false, buffer_event_rebuffer_callback);
2364 add_event(BUFFER_EVENT_FINISHED, false, buffer_event_finished_callback);
2365
2366 if (old_status == PLAY_STOPPED)
2367 {
2368 /* Send coldstart event */
2369 send_event(PLAYBACK_EVENT_START_PLAYBACK, NULL);
1623 } 2370 }
1624 2371
1625 /* Update the playlist */ 2372 /* Fill the buffer */
1626 last_peek_offset -= ci.new_track; 2373 int trackstat = audio_fill_file_buffer();
2374
2375 if (trackstat >= LOAD_TRACK_OK)
2376 {
2377 /* This is the currently playing track - get metadata, stat */
2378 playing_id3_sync(track_list_current(0), offset);
1627 2379
1628 if (playlist_next(ci.new_track) < 0) 2380 if (valid_mp3entry(id3_get(PLAYING_ID3)))
2381 {
2382 /* Only if actually changing tracks... */
2383 if (!(flags & AUDIO_START_RESTART))
2384 audio_playlist_track_change();
2385 }
2386 }
2387 else
1629 { 2388 {
1630 /* End of list */ 2389 /* Found nothing playable */
1631 audio_last_track(automatic_skip); 2390 audio_handle_track_load_status(trackstat);
2391 }
2392}
2393
2394/* Stop playback and enter an idle state
2395 (usually Q_AUDIO_STOP) */
2396static void audio_stop_playback(void)
2397{
2398 logf("%s()", __func__);
2399
2400 if (play_status == PLAY_STOPPED)
2401 return;
2402
2403 /* Stop the codec and unload it */
2404 halt_decoding_track(true);
2405 pcmbuf_play_stop();
2406 codec_unload();
2407
2408 /* Save resume information - "filling" might have been set to
2409 "STATE_ENDED" by caller in order to facilitate end of playlist */
2410 audio_playlist_track_finish();
2411
2412 skip_pending = TRACK_SKIP_NONE;
2413 automatic_skip = false;
2414
2415 /* Close all tracks and mark them NULL */
2416 remove_event(BUFFER_EVENT_REBUFFER, buffer_event_rebuffer_callback);
2417 remove_event(BUFFER_EVENT_FINISHED, buffer_event_finished_callback);
2418 remove_event(BUFFER_EVENT_BUFFER_LOW, buffer_event_buffer_low_callback);
2419
2420 track_list_clear(TRACK_LIST_CLEAR_ALL);
2421
2422 /* Update our state */
2423 ff_rw_mode = false;
2424 play_status = PLAY_STOPPED;
2425
2426 wipe_track_metadata(true);
2427
2428 /* Go idle */
2429 filling = STATE_IDLE;
2430 cancel_cpu_boost();
2431}
2432
2433/* Pause the playback of the current track
2434 (Q_AUDIO_PAUSE) */
2435static void audio_on_pause(bool pause)
2436{
2437 logf("%s(%s)", __func__, pause ? "true" : "false");
2438
2439 if (play_status == PLAY_STOPPED || pause == (play_status == PLAY_PAUSED))
1632 return; 2440 return;
2441
2442 if (!ff_rw_mode)
2443 {
2444 /* Not in ff/rw mode - may set the state (otherwise this could make
2445 old data play because seek hasn't completed and cleared it) */
2446 pcmbuf_pause(pause);
1633 } 2447 }
1634 2448
1635 if (new_playlist) 2449 play_status = pause ? PLAY_PAUSED : PLAY_PLAYING;
2450
2451 if (!pause && codec_skip_pending)
1636 { 2452 {
1637 ci.new_track = 1; 2453 /* Actually do the skip that is due - resets the status flag */
1638 new_playlist = false; 2454 audio_on_codec_complete(codec_skip_status);
1639 } 2455 }
2456}
2457
2458/* Skip a certain number of tracks forwards or backwards
2459 (Q_AUDIO_SKIP) */
2460static void audio_on_skip(void)
2461{
2462 id3_mutex_lock();
2463
2464 /* Eat the delta to keep it synced, even if not playing */
2465 int toskip = skip_offset;
2466 skip_offset = 0;
1640 2467
1641 /* Save a pointer to the old track to allow later clearing */ 2468 logf("%s(): %d", __func__, toskip);
1642 prev_ti = CUR_TI; 2469
2470 id3_mutex_unlock();
2471
2472 if (play_status == PLAY_STOPPED)
2473 return;
1643 2474
1644 for (i = 0; i < ci.new_track; i++) 2475 /* Force codec to abort this track */
2476 halt_decoding_track(true);
2477
2478 /* Kill the ff/rw halt */
2479 ff_rw_mode = false;
2480
2481 /* Manual skip */
2482 automatic_skip = false;
2483
2484 /* If there was an auto skip in progress, there will be residual
2485 advancement of the playlist and/or track list so compensation will be
2486 required in order to end up in the right spot */
2487 int track_list_delta = toskip;
2488 int playlist_delta = toskip;
2489
2490 if (skip_pending != TRACK_SKIP_NONE)
1645 { 2491 {
1646 idx = (track_ridx + i) & MAX_TRACK_MASK; 2492 if (skip_pending != TRACK_SKIP_AUTO_END_PLAYLIST)
1647 struct mp3entry *id3 = bufgetid3(tracks[idx].id3_hid); 2493 track_list_delta--;
1648 ssize_t offset = buf_handle_offset(tracks[idx].audio_hid); 2494
1649 if (!id3 || offset < 0 || (unsigned)offset > id3->first_frame_offset) 2495 if (skip_pending == TRACK_SKIP_AUTO_NEW_PLAYLIST)
2496 playlist_delta--;
2497 }
2498
2499 audio_playlist_track_finish();
2500 skip_pending = TRACK_SKIP_NONE;
2501
2502 /* Update the playlist current track now */
2503 while (playlist_next(playlist_delta) < 0)
2504 {
2505 /* Manual skip out of range (because the playlist wasn't updated
2506 yet by us and so the check in audio_skip returned 'ok') - bring
2507 back into range */
2508 int d = toskip < 0 ? 1 : -1;
2509
2510 while (!playlist_check(playlist_delta))
1650 { 2511 {
1651 /* We don't have all the audio data for that track, so clear it, 2512 if (playlist_delta == d)
1652 but keep the metadata. */
1653 if (tracks[idx].audio_hid >= 0 && bufclose(tracks[idx].audio_hid))
1654 { 2513 {
1655 tracks[idx].audio_hid = -1; 2514 /* Had to move the opposite direction to correct, which is
1656 tracks[idx].filesize = 0; 2515 wrong - this is the end */
2516 filling = STATE_ENDED;
2517 audio_stop_playback();
2518 return;
1657 } 2519 }
2520
2521 playlist_delta += d;
2522 track_list_delta += d;
1658 } 2523 }
1659 } 2524 }
1660 2525
1661 /* Move to the new track */ 2526 /* Adjust things by how much the playlist was manually moved */
1662 track_ridx = (track_ridx + ci.new_track) & MAX_TRACK_MASK; 2527 playlist_peek_offset -= playlist_delta;
1663 buf_set_base_handle(CUR_TI->audio_hid);
1664 2528
1665 if (automatic_skip) 2529 struct track_info *info = track_list_advance_current(track_list_delta);
1666 { 2530 int trackstat = LOAD_TRACK_OK;
1667 wps_offset = -ci.new_track;
1668 }
1669 2531
1670 /* If it is not safe to even skip this many track entries */ 2532 if (!info || info->audio_hid < 0)
1671 if (ci.new_track >= track_count || ci.new_track <= track_count - MAX_TRACK)
1672 { 2533 {
1673 ci.new_track = 0; 2534 /* We don't know the next track thus we know we don't have it */
1674 audio_rebuffer(); 2535 trackstat = audio_reset_and_rebuffer(TRACK_LIST_CLEAR_ALL, -1);
1675 goto skip_done;
1676 } 2536 }
1677 2537
1678 forward = ci.new_track > 0; 2538 audio_begin_track_change(false, trackstat);
1679 ci.new_track = 0; 2539}
2540
2541/* Skip to the next/previous directory
2542 (Q_AUDIO_DIR_SKIP) */
2543static void audio_on_dir_skip(int direction)
2544{
2545 logf("%s(%d)", __func__, direction);
2546
2547 id3_mutex_lock();
2548 skip_offset = 0;
2549 id3_mutex_unlock();
2550
2551 if (play_status == PLAY_STOPPED)
2552 return;
2553
2554 /* Force codec to abort this track */
2555 halt_decoding_track(true);
2556
2557 /* Kill the ff/rw halt */
2558 ff_rw_mode = false;
2559
2560 /* Manual skip */
2561 automatic_skip = false;
2562
2563 audio_playlist_track_finish();
2564
2565 /* Unless automatic and gapless, skips do not pend */
2566 skip_pending = TRACK_SKIP_NONE;
2567
2568 /* Regardless of the return value we need to rebuffer. If it fails the old
2569 playlist will resume, else the next dir will start playing. */
2570 playlist_next_dir(direction);
2571
2572 wipe_track_metadata(false);
1680 2573
1681 /* If the target track is clearly not in memory */ 2574 int trackstat = audio_reset_and_rebuffer(TRACK_LIST_CLEAR_ALL, -1);
1682 if (CUR_TI->filesize == 0 || !CUR_TI->taginfo_ready) 2575
2576 if (trackstat == LOAD_TRACK_ERR_NO_MORE)
1683 { 2577 {
1684 audio_rebuffer(); 2578 /* The day the music died - finish-off whatever is playing and call it
1685 goto skip_done; 2579 quits */
2580 audio_monitor_end_of_playlist();
2581 return;
1686 } 2582 }
1687 2583
1688 /* When skipping backwards, it is possible that we've found a track that's 2584 audio_begin_track_change(false, trackstat);
1689 * buffered, but which is around the track-wrap and therefore not the track 2585}
1690 * we are looking for */ 2586
1691 if (!forward) 2587/* Enter seek mode in order to start a seek
2588 (Q_AUDIO_PRE_FF_REWIND) */
2589static void audio_on_pre_ff_rewind(void)
2590{
2591 logf("%s()", __func__);
2592
2593 if (play_status == PLAY_STOPPED || ff_rw_mode)
2594 return;
2595
2596 ff_rw_mode = true;
2597
2598 if (play_status == PLAY_PAUSED)
2599 return;
2600
2601 pcmbuf_pause(true);
2602}
2603
2604/* Seek the playback of the current track to the specified time
2605 (Q_AUDIO_FF_REWIND) */
2606static void audio_on_ff_rewind(long time)
2607{
2608 logf("%s(%ld)", __func__, time);
2609
2610 if (play_status == PLAY_STOPPED)
2611 return;
2612
2613 enum track_skip_type pending = skip_pending;
2614
2615 switch (pending)
2616 {
2617 case TRACK_SKIP_NONE: /* The usual case */
2618 case TRACK_SKIP_AUTO: /* Have to back it out (fun!) */
2619 case TRACK_SKIP_AUTO_END_PLAYLIST: /* Still have the last codec used */
1692 { 2620 {
1693 int cur_idx = track_ridx; 2621 struct mp3entry *id3 = id3_get(PLAYING_ID3);
1694 bool taginfo_ready = true; 2622 struct mp3entry *ci_id3 = id3_get(CODEC_ID3);
1695 /* We've wrapped the buffer backwards if new > old */ 2623
1696 bool wrap = track_ridx > old_track_ridx; 2624 automatic_skip = false;
2625
2626 /* Send event before clobbering the time */
2627 /* FIXME: Nasty, but the tagtree expects this so that rewinding and
2628 then skipping back to this track resumes properly. Something else
2629 should be sent. We're not _really_ finishing the track are we? */
2630 if (time == 0)
2631 send_event(PLAYBACK_EVENT_TRACK_FINISH, id3);
2632
2633 /* Prevent user codec time update - coerce to something that is
2634 innocuous concerning lookaheads */
2635 if (pending == TRACK_SKIP_NONE)
2636 skip_pending = TRACK_SKIP_AUTO_END_PLAYLIST;
2637
2638 id3->elapsed = time;
2639 queue_reply(&audio_queue, 1);
2640
2641 bool haltres = halt_decoding_track(pending == TRACK_SKIP_AUTO);
2642
2643 /* Need this set in case ff/rw mode + error but _after_ the codec
2644 halt that will reset it */
2645 codec_seeking = true;
1697 2646
1698 while (1) 2647 if (pending == TRACK_SKIP_AUTO)
1699 { 2648 {
1700 cur_idx = (cur_idx + 1) & MAX_TRACK_MASK; 2649 if (!track_list_advance_current(-1))
2650 {
2651 /* Not in list - must rebuffer at the current playlist index */
2652 if (audio_reset_and_rebuffer(TRACK_LIST_CLEAR_ALL, -1)
2653 < LOAD_TRACK_OK)
2654 {
2655 /* Codec is stopped */
2656 break;
2657 }
2658 }
2659 }
1701 2660
1702 /* if we've advanced past the wrap when cur_idx is zeroed */ 2661 /* Set after audio_fill_file_buffer to disable playing id3 clobber if
1703 if (!cur_idx) 2662 rebuffer is needed */
1704 wrap = false; 2663 skip_pending = TRACK_SKIP_NONE;
2664 struct track_info *cur_info = track_list_current(0);
1705 2665
1706 /* if we aren't still on the wrap and we've caught the old track */ 2666 /* Track must complete the loading _now_ since a codec and audio
1707 if (!(wrap || cur_idx < old_track_ridx)) 2667 handle are needed in order to do the seek */
1708 break; 2668 if (cur_info->audio_hid < 0 &&
2669 audio_finish_load_track(cur_info) != LOAD_TRACK_READY)
2670 {
2671 /* Call above should push any load sequence - no need for
2672 halt_decoding_track here if no skip was pending here because
2673 there would not be a codec started if no audio handle was yet
2674 opened */
2675 break;
2676 }
1709 2677
1710 /* If we hit a track in between without valid tag info, bail */ 2678 if (pending == TRACK_SKIP_AUTO)
1711 if (!tracks[cur_idx].taginfo_ready) 2679 {
2680 if (!bufreadid3(cur_info->id3_hid, ci_id3) ||
2681 !audio_init_codec(cur_info, ci_id3))
1712 { 2682 {
1713 taginfo_ready = false; 2683 /* We should have still been able to get it - skip it and move
2684 onto the next one - like it or not this track is borken */
1714 break; 2685 break;
1715 } 2686 }
2687
2688 /* Set the codec API to the correct metadata and track info */
2689 ci.audio_hid = cur_info->audio_hid;
2690 ci.filesize = cur_info->filesize;
2691 buf_set_base_handle(cur_info->audio_hid);
1716 } 2692 }
1717 if (!taginfo_ready) 2693
2694 if (!haltres)
1718 { 2695 {
1719 audio_rebuffer(); 2696 /* If codec must be (re)started, reset the offset */
2697 ci_id3->offset = 0;
1720 } 2698 }
1721 }
1722 2699
1723skip_done: 2700 codec_seek(time);
1724 audio_update_trackinfo(); 2701 return;
1725 pcmbuf_start_track_change(automatic_skip); 2702 }
1726 2703
1727 if (get_codec_base_type(codec_loaded()) == 2704 case TRACK_SKIP_AUTO_NEW_PLAYLIST:
1728 get_codec_base_type(thistrack_id3->codectype))
1729 { 2705 {
1730 /* codec is the same base type */ 2706 /* We cannot do this because the playlist must be reversed by one
1731 logf("New track loaded"); 2707 and it doesn't always return the same song when going backwards
1732 codec_ack_msg(Q_CODEC_REQUEST_COMPLETE, false); 2708 across boundaries as forwards (either because of randomization
2709 or inconsistency in deciding what the previous track should be),
2710 therefore the whole operation would often end up as nonsense -
2711 lock out seeking for a couple seconds */
2712
2713 /* Sure as heck cancel seek mode too! */
2714 audio_ff_rewind_end();
2715 return;
2716 }
2717
2718 default:
2719 /* Won't see this */
2720 return;
1733 } 2721 }
1734 else 2722
2723 if (play_status == PLAY_STOPPED)
1735 { 2724 {
1736 /* a codec change is required */ 2725 /* Playback ended because of an error completing a track load */
1737 logf("New codec: %d/%d", thistrack_id3->codectype, codec_loaded()); 2726 return;
1738 codec_ack_msg(Q_CODEC_REQUEST_COMPLETE, true);
1739 codec_load(tracks[track_ridx].codec_hid, thistrack_id3->codectype);
1740 tracks[track_ridx].codec_hid = -1; /* Codec thread will close it */
1741 } 2727 }
2728
2729 /* Always fake it as a codec start error which will handle mode
2730 cancellations and skip to the next track */
2731 audio_handle_track_load_status(LOAD_TRACK_ERR_START_CODEC);
1742} 2732}
1743 2733
1744unsigned long audio_prev_elapsed(void) 2734/* Invalidates all but currently playing track
2735 (Q_AUDIO_FLUSH) */
2736static void audio_on_audio_flush(void)
1745{ 2737{
1746 return prev_track_elapsed; 2738 logf("%s", __func__);
2739
2740 if (track_list_empty())
2741 return; /* Nothing to flush out */
2742
2743 switch (skip_pending)
2744 {
2745 case TRACK_SKIP_NONE:
2746 case TRACK_SKIP_AUTO_END_PLAYLIST:
2747 /* Remove all but the currently playing track from the list and
2748 refill after that */
2749 track_list_clear(TRACK_LIST_KEEP_CURRENT);
2750 playlist_peek_offset = 0;
2751 id3_write_locked(UNBUFFERED_ID3, NULL);
2752 audio_update_and_announce_next_track(NULL);
2753
2754 /* Ignore return since it's about the next track, not this one */
2755 audio_fill_file_buffer();
2756
2757 if (skip_pending == TRACK_SKIP_NONE)
2758 break;
2759
2760 /* There's now a track after this one now - convert to auto skip -
2761 no skip should pend right now because multiple flush messages can
2762 be fired which would cause a restart in the below cases */
2763 skip_pending = TRACK_SKIP_NONE;
2764 audio_clear_track_notifications();
2765 audio_queue_post(Q_AUDIO_CODEC_COMPLETE, CODEC_OK);
2766 break;
2767
2768 case TRACK_SKIP_AUTO:
2769 case TRACK_SKIP_AUTO_NEW_PLAYLIST:
2770 /* Precisely removing what it already decoded for the next track is
2771 not possible so a restart is required in order to continue the
2772 currently playing track without the now invalid future track
2773 playing */
2774 audio_start_playback(0, AUDIO_START_RESTART);
2775 break;
2776
2777 default: /* Nothing else is a state */
2778 break;
2779 }
1747} 2780}
1748 2781
1749void audio_set_prev_elapsed(unsigned long setting) 2782#ifdef AUDIO_HAVE_RECORDING
2783/* Load the requested encoder type
2784 (Q_AUDIO_LOAD_ENCODER) */
2785static void audio_on_load_encoder(int afmt)
1750{ 2786{
1751 prev_track_elapsed = setting; 2787 bool res = true;
2788
2789 if (play_status != PLAY_STOPPED)
2790 audio_stop_playback(); /* Can't load both types at once */
2791 else
2792 codec_unload(); /* Encoder still loaded, stop and unload it */
2793
2794 if (afmt != AFMT_UNKNOWN)
2795 {
2796 res = codec_load(-1, afmt | CODEC_TYPE_ENCODER);
2797 if (res)
2798 codec_go(); /* These are run immediately */
2799 }
2800
2801 queue_reply(&audio_queue, res);
1752} 2802}
2803#endif /* AUDIO_HAVE_RECORDING */
1753 2804
1754/* Stop the codec and reset the PCM buffer */ 2805static void audio_thread(void)
1755static void audio_stop_codec_flush(void)
1756{ 2806{
1757 bool pcm_playing; 2807 struct queue_event ev;
1758 2808
1759 pcmbuf_pause(true); 2809 pcm_postinit();
1760 2810
1761 codec_stop(); 2811 filling = STATE_IDLE;
1762 2812
1763 pcm_play_lock(); 2813 while (1)
2814 {
2815 switch (filling)
2816 {
2817 /* Active states */
2818 case STATE_FULL:
2819 case STATE_END_OF_PLAYLIST:
2820 if (buf_get_watermark() == 0)
2821 {
2822 /* End of buffering for now, let's calculate the watermark,
2823 register for a low buffer event and unboost */
2824 audio_update_filebuf_watermark(0);
2825 add_event(BUFFER_EVENT_BUFFER_LOW, true,
2826 buffer_event_buffer_low_callback);
2827 }
2828 /* Fall-through */
2829 case STATE_FINISHED:
2830 /* All data was buffered */
2831 cancel_cpu_boost();
2832 /* Fall-through */
2833 case STATE_FILLING:
2834 case STATE_ENDING:
2835 if (audio_pcmbuf_track_change_scan())
2836 {
2837 /* Transfer notification to audio queue event */
2838 ev.id = Q_AUDIO_TRACK_CHANGED;
2839 ev.data = 1;
2840 }
2841 else
2842 {
2843 /* If doing auto skip, poll pcmbuf track notifications a bit
2844 faster to promply detect the transition */
2845 queue_wait_w_tmo(&audio_queue, &ev,
2846 skip_pending == TRACK_SKIP_NONE ?
2847 HZ/2 : HZ/10);
2848 }
2849 break;
1764 2850
1765 pcm_playing = pcm_is_playing(); 2851 /* Idle states */
2852 default:
2853 queue_wait(&audio_queue, &ev);
1766 2854
1767 pcmbuf_play_stop(); 2855#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
1768 queue_clear(&pcmbuf_queue); 2856 switch (ev.id)
2857 {
2858#ifdef AUDIO_HAVE_RECORDING
2859 /* Must monitor the encoder message for recording so it can remove
2860 it if we process the insertion before it does. It cannot simply
2861 be removed from under recording however. */
2862 case Q_AUDIO_LOAD_ENCODER:
2863 break;
2864#endif
2865 case SYS_USB_DISCONNECTED:
2866 filling = STATE_IDLE;
2867 break;
2868
2869 default:
2870 if (filling == STATE_USB)
2871 continue;
2872 }
2873#endif /* CONFIG_PLATFORM */
2874 }
2875
2876 switch (ev.id)
2877 {
2878 /** Codec and track change messages **/
2879 case Q_AUDIO_CODEC_COMPLETE:
2880 /* Codec is done processing track and has gone idle */
2881 LOGFQUEUE("audio < Q_AUDIO_CODEC_COMPLETE: %ld", (long)ev.data);
2882 audio_on_codec_complete(ev.data);
2883 break;
2884
2885 case Q_AUDIO_CODEC_SEEK_COMPLETE:
2886 /* Codec is done seeking */
2887 LOGFQUEUE("audio < Q_AUDIO_SEEK_COMPLETE");
2888 audio_on_codec_seek_complete();
2889 break;
2890
2891 case Q_AUDIO_TRACK_CHANGED:
2892 /* PCM track change done */
2893 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED");
2894 audio_on_track_changed();
2895 break;
2896
2897 /** Control messages **/
2898 case Q_AUDIO_PLAY:
2899 LOGFQUEUE("audio < Q_AUDIO_PLAY");
2900 audio_start_playback(ev.data, 0);
2901 break;
2902
2903 case Q_AUDIO_STOP:
2904 LOGFQUEUE("audio < Q_AUDIO_STOP");
2905 audio_stop_playback();
2906 if (ev.data != 0)
2907 queue_clear(&audio_queue);
2908 break;
2909
2910 case Q_AUDIO_PAUSE:
2911 LOGFQUEUE("audio < Q_AUDIO_PAUSE");
2912 audio_on_pause(ev.data);
2913 break;
2914
2915 case Q_AUDIO_SKIP:
2916 LOGFQUEUE("audio < Q_AUDIO_SKIP");
2917 audio_on_skip();
2918 break;
1769 2919
1770 if (pcm_playing) 2920 case Q_AUDIO_DIR_SKIP:
1771 pcmbuf_pause(paused); 2921 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
2922 audio_on_dir_skip(ev.data);
2923 break;
2924
2925 case Q_AUDIO_PRE_FF_REWIND:
2926 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND");
2927 audio_on_pre_ff_rewind();
2928 break;
2929
2930 case Q_AUDIO_FF_REWIND:
2931 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND");
2932 audio_on_ff_rewind(ev.data);
2933 break;
2934
2935 case Q_AUDIO_FLUSH:
2936 LOGFQUEUE("audio < Q_AUDIO_FLUSH: %d", (int)ev.data);
2937 audio_on_audio_flush();
2938 break;
1772 2939
1773 pcm_play_unlock(); 2940 /** Buffering messages **/
2941 case Q_AUDIO_BUFFERING:
2942 /* some buffering event */
2943 LOGFQUEUE("audio < Q_AUDIO_BUFFERING: %d", (int)ev.data);
2944 audio_on_buffering(ev.data);
2945 break;
2946
2947 case Q_AUDIO_FILL_BUFFER:
2948 /* continue buffering next track */
2949 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER");
2950 audio_on_fill_buffer();
2951 break;
2952
2953 case Q_AUDIO_FINISH_LOAD_TRACK:
2954 /* metadata is buffered */
2955 LOGFQUEUE("audio < Q_AUDIO_FINISH_LOAD_TRACK");
2956 audio_on_finish_load_track(ev.data);
2957 break;
2958
2959 case Q_AUDIO_HANDLE_FINISHED:
2960 /* some other type is buffered */
2961 LOGFQUEUE("audio < Q_AUDIO_HANDLE_FINISHED");
2962 audio_on_handle_finished(ev.data);
2963 break;
2964
2965 /** Miscellaneous messages **/
2966 case Q_AUDIO_REMAKE_AUDIO_BUFFER:
2967 /* buffer needs to be reinitialized */
2968 LOGFQUEUE("audio < Q_AUDIO_REMAKE_AUDIO_BUFFER");
2969 audio_start_playback(0, AUDIO_START_RESTART | AUDIO_START_NEWBUF);
2970 break;
2971
2972#ifdef HAVE_DISK_STORAGE
2973 case Q_AUDIO_UPDATE_WATERMARK:
2974 /* buffering watermark needs updating */
2975 LOGFQUEUE("audio < Q_AUDIO_UPDATE_WATERMARK: %d", (int)ev.data);
2976 audio_update_filebuf_watermark(ev.data);
2977 break;
2978#endif /* HAVE_DISK_STORAGE */
2979
2980#ifdef AUDIO_HAVE_RECORDING
2981 case Q_AUDIO_LOAD_ENCODER:
2982 /* load an encoder for recording */
2983 LOGFQUEUE("audio < Q_AUDIO_LOAD_ENCODER: %d", (int)ev.data);
2984 audio_on_load_encoder(ev.data);
2985 break;
2986#endif /* AUDIO_HAVE_RECORDING */
2987
2988#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
2989 case SYS_USB_CONNECTED:
2990 LOGFQUEUE("audio < SYS_USB_CONNECTED");
2991 audio_stop_playback();
2992#ifdef PLAYBACK_VOICE
2993 voice_stop();
2994#endif
2995 filling = STATE_USB;
2996 usb_acknowledge(SYS_USB_CONNECTED_ACK);
2997 break;
2998#endif /* (CONFIG_PLATFORM & PLATFORM_NATIVE) */
2999
3000 case SYS_TIMEOUT:
3001 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
3002 break;
3003
3004 default:
3005 /* LOGFQUEUE("audio < default : %08lX", ev.id); */
3006 break;
3007 } /* end switch */
3008 } /* end while */
1774} 3009}
1775 3010
1776static void audio_stop_playback(void) 3011
3012/* --- Buffering callbacks --- */
3013
3014/* Called when fullness is below the watermark level */
3015static void buffer_event_buffer_low_callback(void *data)
1777{ 3016{
1778 if (playing) 3017 logf("low buffer callback");
1779 { 3018 LOGFQUEUE("buffering > audio Q_AUDIO_BUFFERING: buffer low");
1780 /* If we were playing, save resume information */ 3019 audio_queue_post(Q_AUDIO_BUFFERING, BUFFER_EVENT_BUFFER_LOW);
1781 struct mp3entry *id3 = NULL; 3020 (void)data;
3021}
1782 3022
1783 if (!ci.stop_codec) 3023/* Called when handles must be discarded in order to buffer new data */
1784 id3 = audio_current_track(); 3024static void buffer_event_rebuffer_callback(void *data)
3025{
3026 logf("rebuffer callback");
3027 LOGFQUEUE("buffering > audio Q_AUDIO_BUFFERING: rebuffer");
3028 audio_queue_post(Q_AUDIO_BUFFERING, BUFFER_EVENT_REBUFFER);
3029 (void)data;
3030}
1785 3031
1786 /* Save the current playing spot, or NULL if the playlist has ended */ 3032/* A handle has completed buffering and all required data is available */
1787 playlist_update_resume_info(id3); 3033static void buffer_event_finished_callback(void *data)
3034{
3035 int hid = *(const int *)data;
3036 const enum data_type htype = buf_handle_data_type(hid);
1788 3037
1789 /* Now it's good time to send track finish events. Do this 3038 logf("handle %d finished buffering (type:%u)", hid, (unsigned)htype);
1790 only if this hasn't been done already as part of a track
1791 switch. */
1792 if (id3 == thistrack_id3)
1793 send_event(PLAYBACK_EVENT_TRACK_FINISH, thistrack_id3);
1794 3039
1795 /* TODO: Create auto bookmark too? */ 3040 /* Limit queue traffic */
3041 switch (htype)
3042 {
3043 case TYPE_ID3:
3044 /* The metadata handle for the last loaded track has been buffered.
3045 We can ask the audio thread to load the rest of the track's data. */
3046 LOGFQUEUE("buffering > audio Q_AUDIO_FINISH_LOAD_TRACK: %d", hid);
3047 audio_queue_post(Q_AUDIO_FINISH_LOAD_TRACK, hid);
3048 break;
1796 3049
1797 prev_track_elapsed = othertrack_id3->elapsed; 3050 case TYPE_PACKET_AUDIO:
3051 /* Strip any useless trailing tags that are left. */
3052 strip_tags(hid);
3053 /* Fall-through */
3054 case TYPE_ATOMIC_AUDIO:
3055 LOGFQUEUE("buffering > audio Q_AUDIO_HANDLE_FINISHED: %d", hid);
3056 audio_queue_post(Q_AUDIO_HANDLE_FINISHED, hid);
3057 break;
1798 3058
1799 remove_event(BUFFER_EVENT_BUFFER_LOW, buffering_low_buffer_callback); 3059 default:
3060 /* Don't care to know about these */
3061 break;
1800 } 3062 }
3063}
1801 3064
1802 audio_stop_codec_flush();
1803 paused = false;
1804 playing = false;
1805 track_load_started = false;
1806 3065
1807 filling = STATE_IDLE; 3066/** -- Codec callbacks -- **/
3067
3068/* Update elapsed times with latency-adjusted values */
3069void audio_codec_update_elapsed(unsigned long value)
3070{
3071#ifdef AB_REPEAT_ENABLE
3072 ab_position_report(value);
3073#endif
3074
3075 unsigned long latency = pcmbuf_get_latency();
3076
3077 if (LIKELY(value >= latency))
3078 {
3079 unsigned long elapsed = value - latency;
3080
3081 if (elapsed > value || elapsed < value - 2)
3082 value = elapsed;
3083 }
3084 else
3085 {
3086 value = 0;
3087 }
1808 3088
1809 /* Mark all entries null. */ 3089 /* Track codec: used later when updating the playing at the user
1810 audio_clear_track_entries(); 3090 transition */
3091 id3_get(CODEC_ID3)->elapsed = value;
1811 3092
1812 /* Close all tracks */ 3093 /* If a skip is pending, the PCM buffer is updating the time on the
1813 audio_release_tracks(); 3094 previous song */
3095 if (LIKELY(skip_pending == TRACK_SKIP_NONE))
3096 id3_get(PLAYING_ID3)->elapsed = value;
1814} 3097}
1815 3098
1816static void audio_play_start(size_t offset) 3099/* Update offsets with latency-adjusted values */
3100void audio_codec_update_offset(size_t value)
1817{ 3101{
1818 int i; 3102 struct mp3entry *ci_id3 = id3_get(CODEC_ID3);
3103 unsigned long latency = pcmbuf_get_latency() * ci_id3->bitrate / 8;
1819 3104
1820 send_event(PLAYBACK_EVENT_START_PLAYBACK, NULL); 3105 if (LIKELY(value >= latency))
1821#if INPUT_SRC_CAPS != 0 3106 {
1822 audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK); 3107 value -= latency;
1823 audio_set_output_source(AUDIO_SRC_PLAYBACK); 3108 }
1824#endif 3109 else
3110 {
3111 value = 0;
3112 }
1825 3113
1826 paused = false; 3114 /* Track codec: used later when updating the playing id3 at the user
1827 audio_stop_codec_flush(); 3115 transition */
3116 ci_id3->offset = value;
1828 3117
1829 playing = true; 3118 /* If a skip is pending, the PCM buffer is updating the time on the
1830 track_load_started = false; 3119 previous song */
3120 if (LIKELY(skip_pending == TRACK_SKIP_NONE))
3121 id3_get(PLAYING_ID3)->offset = value;
3122}
1831 3123
1832 ci.new_track = 0;
1833 ci.seek_time = 0;
1834 wps_offset = 0;
1835 3124
1836#ifndef PLATFORM_HAS_VOLUME_CHANGE 3125/** --- Pcmbuf callbacks --- **/
1837 sound_set_volume(global_settings.volume);
1838#endif
1839 track_widx = track_ridx = 0;
1840 buf_set_base_handle(-1);
1841 3126
1842 /* Clear all track entries. */ 3127/* Between the codec and PCM track change, we need to keep updating the
1843 for (i = 0; i < MAX_TRACK; i++) { 3128 * "elapsed" value of the previous (to the codec, but current to the
1844 clear_track_info(&tracks[i]); 3129 * user/PCM/WPS) track, so that the progressbar reaches the end. */
3130void audio_pcmbuf_position_callback(unsigned int time)
3131{
3132 struct mp3entry *id3 = id3_get(PLAYING_ID3);
3133
3134 time += id3->elapsed;
3135
3136 id3->elapsed = MIN(time, id3->length);
3137}
3138
3139/* Post message from pcmbuf that the end of the previous track has just
3140 * been played */
3141void audio_pcmbuf_track_change(bool pcmbuf)
3142{
3143 if (pcmbuf)
3144 {
3145 /* Notify of the change in special-purpose semaphore object */
3146 LOGFQUEUE("pcmbuf > pcmbuf Q_AUDIO_TRACK_CHANGED");
3147 audio_pcmbuf_track_change_post();
1845 } 3148 }
3149 else
3150 {
3151 /* Safe to post directly to the queue */
3152 LOGFQUEUE("pcmbuf > audio Q_AUDIO_TRACK_CHANGED");
3153 audio_queue_post(Q_AUDIO_TRACK_CHANGED, 0);
3154 }
3155}
1846 3156
1847 last_peek_offset = -1; 3157/* May pcmbuf start PCM playback when the buffer is full enough? */
3158bool audio_pcmbuf_may_play(void)
3159{
3160 return play_status == PLAY_PLAYING && !ff_rw_mode;
3161}
1848 3162
1849 /* Officially playing */
1850 queue_reply(&audio_queue, 1);
1851 3163
1852 audio_fill_file_buffer(true, offset); 3164/** -- External interfaces -- **/
1853 3165
1854 add_event(BUFFER_EVENT_BUFFER_LOW, false, buffering_low_buffer_callback); 3166/* Return the playback and recording status */
3167int audio_status(void)
3168{
3169 unsigned int ret = play_status;
3170
3171#ifdef AUDIO_HAVE_RECORDING
3172 /* Do this here for constitency with mpeg.c version */
3173 ret |= pcm_rec_status();
3174#endif
1855 3175
1856 LOGFQUEUE("audio > audio Q_AUDIO_TRACK_CHANGED"); 3176 return (int)ret;
1857 queue_post(&audio_queue, Q_AUDIO_TRACK_CHANGED, 0);
1858} 3177}
1859 3178
3179/* Clear all accumulated audio errors for playback and recording */
3180void audio_error_clear(void)
3181{
3182#ifdef AUDIO_HAVE_RECORDING
3183 pcm_rec_error_clear();
3184#endif
3185}
1860 3186
1861/* Invalidates all but currently playing track. */ 3187/* Get a copy of the id3 data for the for current track + offset + skip delta */
1862static void audio_invalidate_tracks(void) 3188bool audio_peek_track(struct mp3entry *id3, int offset)
1863{ 3189{
1864 if (audio_have_tracks()) 3190 bool retval = false;
3191
3192 id3_mutex_lock();
3193
3194 if (play_status != PLAY_STOPPED)
1865 { 3195 {
1866 last_peek_offset = 0; 3196 id3->path[0] = '\0'; /* Null path means it should be filled now */
1867 track_widx = track_ridx; 3197 retval = audio_get_track_metadata(offset + skip_offset, id3) &&
3198 id3->path[0] != '\0';
3199 }
1868 3200
1869 /* Mark all other entries null (also buffered wrong metadata). */ 3201 id3_mutex_unlock();
1870 audio_clear_track_entries();
1871 3202
1872 track_widx = (track_widx + 1) & MAX_TRACK_MASK; 3203 return retval;
3204}
3205
3206/* Return the mp3entry for the currently playing track */
3207struct mp3entry * audio_current_track(void)
3208{
3209 struct mp3entry *id3;
1873 3210
1874 audio_fill_file_buffer(false, 0); 3211 id3_mutex_lock();
1875 send_event(PLAYBACK_EVENT_TRACK_CHANGE, thistrack_id3); 3212
3213#ifdef AUDIO_FAST_SKIP_PREVIEW
3214 if (skip_offset != 0)
3215 {
3216 /* This is a peekahead */
3217 id3 = id3_get(PLAYING_PEEK_ID3);
3218 audio_peek_track(id3, 0);
1876 } 3219 }
3220 else
3221#endif
3222 {
3223 /* Normal case */
3224 id3 = id3_get(PLAYING_ID3);
3225 audio_get_track_metadata(0, id3);
3226 }
3227
3228 id3_mutex_unlock();
3229
3230 return id3;
1877} 3231}
1878 3232
1879static void audio_new_playlist(void) 3233/* Obtains the mp3entry for the next track from the current */
3234struct mp3entry * audio_next_track(void)
1880{ 3235{
1881 /* Prepare to start a new fill from the beginning of the playlist */ 3236 struct mp3entry *id3 = id3_get(NEXTTRACK_ID3);
1882 last_peek_offset = -1;
1883 3237
1884 /* Signal the codec to initiate a track change forward */ 3238 id3_mutex_lock();
1885 new_playlist = true;
1886 ci.new_track = 1;
1887 3239
1888 if (audio_have_tracks()) 3240#ifdef AUDIO_FAST_SKIP_PREVIEW
3241 if (skip_offset != 0)
3242 {
3243 /* This is a peekahead */
3244 if (!audio_peek_track(id3, 1))
3245 id3 = NULL;
3246 }
3247 else
3248#endif
1889 { 3249 {
1890 if (paused) 3250 /* Normal case */
1891 skipped_during_pause = true; 3251 if (!audio_get_track_metadata(1, id3))
1892 track_widx = track_ridx; 3252 id3 = NULL;
1893 audio_clear_track_entries(); 3253 }
1894 3254
1895 track_widx = (track_widx + 1) & MAX_TRACK_MASK; 3255 id3_mutex_unlock();
1896 3256
1897 /* Mark the current track as invalid to prevent skipping back to it */ 3257 return id3;
1898 CUR_TI->taginfo_ready = false; 3258}
1899 }
1900 3259
1901 /* Officially playing */ 3260/* Start playback at the specified offset */
1902 queue_reply(&audio_queue, 1); 3261void audio_play(long offset)
3262{
3263 logf("audio_play");
1903 3264
1904 audio_fill_file_buffer(false, 0); 3265#ifdef PLAYBACK_VOICE
3266 /* Truncate any existing voice output so we don't have spelling
3267 * etc. over the first part of the played track */
3268 talk_force_shutup();
3269#endif
3270
3271 LOGFQUEUE("audio >| audio Q_AUDIO_PLAY: %ld", offset);
3272 audio_queue_send(Q_AUDIO_PLAY, offset);
1905} 3273}
1906 3274
1907/* Called on manual track skip */ 3275/* Stop playback if playing */
1908static void audio_initiate_track_change(long direction) 3276void audio_stop(void)
1909{ 3277{
1910 logf("audio_initiate_track_change(%ld)", direction); 3278 LOGFQUEUE("audio >| audio Q_AUDIO_STOP");
3279 audio_queue_send(Q_AUDIO_STOP, 0);
3280}
1911 3281
1912 ci.new_track += direction; 3282/* Pause playback if playing */
1913 wps_offset -= direction; 3283void audio_pause(void)
1914 if (paused) 3284{
1915 skipped_during_pause = true; 3285 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE");
3286 audio_queue_send(Q_AUDIO_PAUSE, true);
3287}
3288
3289/* This sends a stop message and the audio thread will dump all its
3290 subsequent messages */
3291void audio_hard_stop(void)
3292{
3293 /* Stop playback */
3294 LOGFQUEUE("audio >| audio Q_AUDIO_STOP: 1");
3295 audio_queue_send(Q_AUDIO_STOP, 1);
3296#ifdef PLAYBACK_VOICE
3297 voice_stop();
3298#endif
1916} 3299}
1917 3300
1918/* Called on manual dir skip */ 3301/* Resume playback if paused */
1919static void audio_initiate_dir_change(long direction) 3302void audio_resume(void)
1920{ 3303{
1921 dir_skip = true; 3304 LOGFQUEUE("audio >| audio Q_AUDIO_PAUSE resume");
1922 ci.new_track = direction; 3305 audio_queue_send(Q_AUDIO_PAUSE, false);
1923 if (paused)
1924 skipped_during_pause = true;
1925} 3306}
1926 3307
1927/* Called when PCM track change is complete */ 3308/* Skip the specified number of tracks forward or backward from the current */
1928static void audio_finalise_track_change(void) 3309void audio_skip(int offset)
1929{ 3310{
1930 logf("audio_finalise_track_change"); 3311 id3_mutex_lock();
3312
3313 /* If offset has to be backed-out to stay in range, no skip is done */
3314 int accum = skip_offset + offset;
1931 3315
1932 if (automatic_skip) 3316 while (offset != 0 && !playlist_check(accum))
1933 { 3317 {
1934 wps_offset = 0; 3318 offset += offset < 0 ? 1 : -1;
1935 automatic_skip = false; 3319 accum = skip_offset + offset;
3320 }
1936 3321
1937 /* Invalidate prevtrack_id3 */ 3322 if (offset != 0)
1938 memset(othertrack_id3, 0, sizeof(struct mp3entry)); 3323 {
3324 /* Accumulate net manual skip count since the audio thread last
3325 processed one */
3326 skip_offset = accum;
1939 3327
1940 if (prev_ti && prev_ti->audio_hid < 0) 3328 if (global_settings.beep)
1941 { 3329 pcmbuf_beep(2000, 100, 2500*global_settings.beep);
1942 /* No audio left so we clear all the track info. */ 3330
1943 clear_track_info(prev_ti); 3331 LOGFQUEUE("audio > audio Q_AUDIO_SKIP %d", offset);
1944 } 3332
3333#ifdef AUDIO_FAST_SKIP_PREVIEW
3334 /* Do this before posting so that the audio thread can correct us
3335 when things settle down - additionally, if audio gets a message
3336 and the delta is zero, the Q_AUDIO_SKIP handler (audio_on_skip)
3337 handler a skip event with the correct info but doesn't skip */
3338 send_event(PLAYBACK_EVENT_TRACK_SKIP, NULL);
3339#endif /* AUDIO_FAST_SKIP_PREVIEW */
3340
3341 /* Playback only needs the final state even if more than one is
3342 processed because it wasn't removed in time */
3343 queue_remove_from_head(&audio_queue, Q_AUDIO_SKIP);
3344 audio_queue_post(Q_AUDIO_SKIP, 0);
1945 } 3345 }
1946 send_event(PLAYBACK_EVENT_TRACK_CHANGE, thistrack_id3); 3346 else
1947 playlist_update_resume_info(audio_current_track()); 3347 {
3348 /* No more tracks */
3349 if (global_settings.beep)
3350 pcmbuf_beep(1000, 100, 1500*global_settings.beep);
3351 }
3352
3353 id3_mutex_unlock();
1948} 3354}
1949 3355
1950static void audio_seek_complete(void) 3356/* Skip one track forward from the current */
3357void audio_next(void)
1951{ 3358{
1952 logf("audio_seek_complete"); 3359 audio_skip(1);
3360}
1953 3361
1954 if (!playing) 3362/* Skip one track backward from the current */
1955 return; 3363void audio_prev(void)
3364{
3365 audio_skip(-1);
3366}
1956 3367
1957 /* If seeking-while-playing, pcm_is_paused() is true. 3368/* Move one directory forward */
1958 * If seeking-while-paused, audio_status PAUSE is true. 3369void audio_next_dir(void)
1959 * A seamless seek skips this section. */ 3370{
1960 ci.seek_time = 0; 3371 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP 1");
3372 audio_queue_post(Q_AUDIO_DIR_SKIP, 1);
3373}
1961 3374
1962 pcm_play_lock(); 3375/* Move one directory backward */
3376void audio_prev_dir(void)
3377{
3378 LOGFQUEUE("audio > audio Q_AUDIO_DIR_SKIP -1");
3379 audio_queue_post(Q_AUDIO_DIR_SKIP, -1);
3380}
1963 3381
1964 if (pcm_is_paused() || paused) 3382/* Pause playback in order to start a seek that flushes the old audio */
1965 { 3383void audio_pre_ff_rewind(void)
1966 /* Clear the buffer */ 3384{
1967 pcmbuf_play_stop(); 3385 LOGFQUEUE("audio > audio Q_AUDIO_PRE_FF_REWIND");
3386 audio_queue_post(Q_AUDIO_PRE_FF_REWIND, 0);
3387}
1968 3388
1969 /* If seeking-while-playing, resume PCM playback */ 3389/* Seek to the new time in the current track */
1970 if (!paused) 3390void audio_ff_rewind(long time)
1971 pcmbuf_pause(false); 3391{
1972 } 3392 LOGFQUEUE("audio > audio Q_AUDIO_FF_REWIND");
3393 audio_queue_post(Q_AUDIO_FF_REWIND, time);
3394}
1973 3395
1974 pcm_play_unlock(); 3396/* Clear all but the currently playing track then rebuffer */
3397void audio_flush_and_reload_tracks(void)
3398{
3399 LOGFQUEUE("audio > audio Q_AUDIO_FLUSH");
3400 audio_queue_post(Q_AUDIO_FLUSH, 0);
1975} 3401}
1976 3402
1977static void audio_codec_status_message(long reason, int status) 3403/* Return the pointer to the main audio buffer, optionally preserving
3404 voicing */
3405unsigned char * audio_get_buffer(bool talk_buf, size_t *buffer_size)
1978{ 3406{
1979 /* TODO: Push the errors up to the normal UI somewhere */ 3407 unsigned char *buf, *end;
1980 switch (reason) 3408
3409 if (audio_is_initialized)
1981 { 3410 {
1982 case Q_CODEC_LOAD_DISK: 3411 audio_hard_stop();
1983 case Q_CODEC_LOAD: 3412 }
1984 if (!playing) 3413 /* else buffer_state will be AUDIOBUF_STATE_TRASHED at this point */
1985 return;
1986 3414
1987 if (status < 0) 3415 if (buffer_size == NULL)
3416 {
3417 /* Special case for talk_init to use since it already knows it's
3418 trashed */
3419 buffer_state = AUDIOBUF_STATE_TRASHED;
3420 return NULL;
3421 }
3422
3423 if (talk_buf || buffer_state == AUDIOBUF_STATE_TRASHED
3424 || !talk_voice_required())
3425 {
3426 logf("get buffer: talk, audio");
3427 /* Ok to use everything from audiobuf to audiobufend - voice is loaded,
3428 the talk buffer is not needed because voice isn't being used, or
3429 could be AUDIOBUF_STATE_TRASHED already. If state is
3430 AUDIOBUF_STATE_VOICED_ONLY, no problem as long as memory isn't written
3431 without the caller knowing what's going on. Changing certain settings
3432 may move it to a worse condition but the memory in use by something
3433 else will remain undisturbed.
3434 */
3435 if (buffer_state != AUDIOBUF_STATE_TRASHED)
1988 { 3436 {
1989 splash(HZ*2, "Codec failure"); 3437 talk_buffer_steal();
1990 audio_check_new_track(); 3438 buffer_state = AUDIOBUF_STATE_TRASHED;
1991 } 3439 }
1992 break;
1993 3440
1994#ifdef AUDIO_HAVE_RECORDING 3441 buf = audiobuf;
1995 case Q_ENCODER_LOAD_DISK: 3442 end = audiobufend;
1996 if (status < 0)
1997 splash(HZ*2, "Encoder failure");
1998 break;
1999#endif /* AUDIO_HAVE_RECORDING */
2000 } 3443 }
3444 else
3445 {
3446 /* Safe to just return this if already AUDIOBUF_STATE_VOICED_ONLY or
3447 still AUDIOBUF_STATE_INITIALIZED */
3448 /* Skip talk buffer and move pcm buffer to end to maximize available
3449 contiguous memory - no audio running means voice will not need the
3450 swap space */
3451 logf("get buffer: audio");
3452 buf = audiobuf + talk_get_bufsize();
3453 end = audiobufend - pcmbuf_init(audiobufend);
3454 buffer_state = AUDIOBUF_STATE_VOICED_ONLY;
3455 }
3456
3457 *buffer_size = end - buf;
3458
3459 return buf;
2001} 3460}
2002 3461
2003/* 3462#ifdef HAVE_RECORDING
2004 * Layout audio buffer as follows - iram buffer depends on target: 3463/* Stop audio, voice and obtain all available buffer space */
2005 * [|SWAP:iram][|TALK]|FILE|GUARD|PCM|[SWAP:dram[|iram]|] 3464unsigned char * audio_get_recording_buffer(size_t *buffer_size)
2006 */
2007static void audio_reset_buffer(void)
2008{ 3465{
2009 /* see audio_get_recording_buffer if this is modified */ 3466 audio_hard_stop();
2010 logf("audio_reset_buffer"); 3467 talk_buffer_steal();
2011 3468
2012 /* If the setup of anything allocated before the file buffer is 3469 unsigned char *end = audiobufend;
2013 changed, do check the adjustments after the buffer_alloc call 3470 buffer_state = AUDIOBUF_STATE_TRASHED;
2014 as it will likely be affected and need sliding over */ 3471 *buffer_size = end - audiobuf;
2015 3472
2016 /* Initially set up file buffer as all space available */ 3473 return (unsigned char *)audiobuf;
2017 filebuf = audiobuf + talk_get_bufsize(); 3474}
2018 filebuflen = audiobufend - filebuf; 3475#endif /* HAVE_RECORDING */
2019 3476
2020 ALIGN_BUFFER(filebuf, filebuflen, sizeof (intptr_t)); 3477/* Restore audio buffer to a particular state (one more valid than the current
3478 state) */
3479bool audio_restore_playback(int type)
3480{
3481 switch (type)
3482 {
3483 case AUDIO_WANT_PLAYBACK:
3484 if (buffer_state != AUDIOBUF_STATE_INITIALIZED)
3485 audio_reset_buffer();
3486 return true;
3487 case AUDIO_WANT_VOICE:
3488 if (buffer_state == AUDIOBUF_STATE_TRASHED)
3489 audio_reset_buffer();
3490 return true;
3491 default:
3492 return false;
3493 }
3494}
2021 3495
2022 /* Subtract whatever the pcm buffer says it used plus the guard buffer */ 3496/* Has the playback buffer been completely claimed? */
2023 size_t pcmbuf_size = pcmbuf_init(filebuf + filebuflen) + GUARD_BUFSIZE; 3497bool audio_buffer_state_trashed(void)
3498{
3499 return buffer_state == AUDIOBUF_STATE_TRASHED;
3500}
2024 3501
2025 /* Make sure filebuflen is a pointer sized multiple after adjustment */
2026 pcmbuf_size = ALIGN_UP(pcmbuf_size, sizeof (intptr_t));
2027 3502
2028 if(pcmbuf_size > filebuflen) 3503/** --- Miscellaneous public interfaces --- **/
2029 panicf("%s(): EOM (%zu > %zu)", __func__, pcmbuf_size, filebuflen);
2030 3504
2031 filebuflen -= pcmbuf_size; 3505#ifdef HAVE_ALBUMART
2032 buffering_reset(filebuf, filebuflen); 3506/* Return which album art handle is current for the user in the given slot */
3507int playback_current_aa_hid(int slot)
3508{
3509 if ((unsigned)slot < MAX_MULTIPLE_AA)
3510 {
3511 struct track_info *info = track_list_user_current(skip_offset);
2033 3512
2034 /* Clear any references to the file buffer */ 3513 if (!info && abs(skip_offset) <= 1)
2035 buffer_state = AUDIOBUF_STATE_INITIALIZED; 3514 {
3515 /* Give the actual position a go */
3516 info = track_list_user_current(0);
3517 }
2036 3518
2037#if defined(ROCKBOX_HAS_LOGF) && defined(LOGF_ENABLE) 3519 if (info)
2038 /* Make sure everything adds up - yes, some info is a bit redundant but 3520 return info->aa_hid[slot];
2039 aids viewing and the sumation of certain variables should add up to
2040 the location of others. */
2041 {
2042 size_t pcmbufsize;
2043 const unsigned char *pcmbuf = pcmbuf_get_meminfo(&pcmbufsize);
2044 logf("fbuf: %08X", (unsigned)filebuf);
2045 logf("fbufe: %08X", (unsigned)(filebuf + filebuflen));
2046 logf("gbuf: %08X", (unsigned)(filebuf + filebuflen));
2047 logf("gbufe: %08X", (unsigned)(filebuf + filebuflen + GUARD_BUFSIZE));
2048 logf("pcmb: %08X", (unsigned)pcmbuf);
2049 logf("pcmbe: %08X", (unsigned)(pcmbuf + pcmbufsize));
2050 } 3521 }
2051#endif 3522
3523 return ERR_HANDLE_NOT_FOUND;
2052} 3524}
2053 3525
2054static void audio_thread(void) 3526/* Find an album art slot that doesn't match the dimensions of another that
3527 is already claimed - increment the use count if it is */
3528int playback_claim_aa_slot(struct dim *dim)
2055{ 3529{
2056 struct queue_event ev; 3530 int i;
2057
2058 pcm_postinit();
2059
2060 audio_thread_ready = true;
2061 3531
2062 while (1) 3532 /* First try to find a slot already having the size to reuse it since we
3533 don't want albumart of the same size buffered multiple times */
3534 FOREACH_ALBUMART(i)
2063 { 3535 {
2064 switch (filling) { 3536 struct albumart_slot *slot = &albumart_slots[i];
2065 case STATE_IDLE:
2066 queue_wait(&audio_queue, &ev);
2067 break;
2068 3537
2069#if (CONFIG_PLATFORM & PLATFORM_NATIVE) 3538 if (slot->dim.width == dim->width &&
2070 case STATE_USB: 3539 slot->dim.height == dim->height)
2071 queue_wait(&audio_queue, &ev); 3540 {
2072 switch (ev.id) { 3541 slot->used++;
2073#ifdef AUDIO_HAVE_RECORDING 3542 return i;
2074 /* Must monitor the encoder message for recording so it can 3543 }
2075 remove it if we process the insertion before it does. It 3544 }
2076 cannot simply be removed from under recording however. */
2077 case Q_AUDIO_LOAD_ENCODER:
2078 break;
2079#endif
2080 case SYS_USB_DISCONNECTED:
2081 filling = STATE_IDLE;
2082 default:
2083 continue;
2084 }
2085 break;
2086#endif /* CONFIG_PLATFORM */
2087 3545
2088 default: 3546 /* Size is new, find a free slot */
2089 /* End of buffering, let's calculate the watermark and 3547 FOREACH_ALBUMART(i)
2090 unboost */ 3548 {
2091 set_filebuf_watermark(); 3549 if (!albumart_slots[i].used)
2092 cancel_cpu_boost(); 3550 {
2093 /* Fall-through */ 3551 albumart_slots[i].used++;
2094 case STATE_FILLING: 3552 albumart_slots[i].dim = *dim;
2095 case STATE_ENDING: 3553 return i;
2096 if (!pcmbuf_queue_scan(&ev))
2097 queue_wait_w_tmo(&audio_queue, &ev, HZ/2);
2098 break;
2099 } 3554 }
3555 }
2100 3556
2101 switch (ev.id) { 3557 /* Sorry, no free slot */
3558 return -1;
3559}
2102 3560
2103 case Q_AUDIO_FILL_BUFFER: 3561/* Invalidate the albumart_slot - decrement the use count if > 0 */
2104 LOGFQUEUE("audio < Q_AUDIO_FILL_BUFFER %d", (int)ev.data); 3562void playback_release_aa_slot(int slot)
2105 audio_fill_file_buffer((bool)ev.data, 0); 3563{
2106 break; 3564 if ((unsigned)slot < MAX_MULTIPLE_AA)
3565 {
3566 struct albumart_slot *aa_slot = &albumart_slots[slot];
2107 3567
2108 case Q_AUDIO_FINISH_LOAD: 3568 if (aa_slot->used > 0)
2109 LOGFQUEUE("audio < Q_AUDIO_FINISH_LOAD"); 3569 aa_slot->used--;
2110 audio_finish_load_track(); 3570 }
2111 buf_set_base_handle(CUR_TI->audio_hid); 3571}
2112 break; 3572#endif /* HAVE_ALBUMART */
2113 3573
2114 case Q_AUDIO_PLAY:
2115 LOGFQUEUE("audio < Q_AUDIO_PLAY");
2116 if (playing && ev.data <= 0)
2117 audio_new_playlist();
2118 else
2119 {
2120 audio_stop_playback();
2121 audio_play_start((size_t)ev.data);
2122 }
2123 break;
2124 3574
2125 case Q_AUDIO_STOP: 3575#ifdef HAVE_RECORDING
2126 LOGFQUEUE("audio < Q_AUDIO_STOP"); 3576/* Load an encoder and run it */
2127 if (playing) 3577bool audio_load_encoder(int afmt)
2128 audio_stop_playback(); 3578{
2129 if (ev.data != 0) 3579#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
2130 queue_clear(&audio_queue); 3580 LOGFQUEUE("audio >| Q_AUDIO_LOAD_ENCODER: %d", afmt);
2131 break; 3581 return audio_queue_send(Q_AUDIO_LOAD_ENCODER, afmt) != 0;
3582#else
3583 (void)afmt;
3584 return true;
3585#endif
3586}
2132 3587
2133 case Q_AUDIO_PAUSE: 3588/* Stop an encoder and unload it */
2134 LOGFQUEUE("audio < Q_AUDIO_PAUSE"); 3589void audio_remove_encoder(void)
2135 if (!(bool) ev.data && skipped_during_pause 3590{
2136#ifdef HAVE_CROSSFADE 3591#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
2137 && !pcmbuf_is_crossfade_active() 3592 LOGFQUEUE("audio >| Q_AUDIO_LOAD_ENCODER: NULL");
3593 audio_queue_send(Q_AUDIO_LOAD_ENCODER, AFMT_UNKNOWN);
2138#endif 3594#endif
2139 ) 3595}
2140 pcmbuf_play_stop(); /* Flush old track on resume after skip */ 3596#endif /* HAVE_RECORDING */
2141 skipped_during_pause = false;
2142 if (!playing)
2143 break;
2144 pcmbuf_pause((bool)ev.data);
2145 paused = (bool)ev.data;
2146 break;
2147 3597
2148 case Q_AUDIO_SKIP: 3598/* Is an automatic skip in progress? If called outside transistion callbacks,
2149 LOGFQUEUE("audio < Q_AUDIO_SKIP"); 3599 indicates the last skip type at the time it was processed and isn't very
2150 audio_initiate_track_change((long)ev.data); 3600 meaningful. */
2151 break; 3601bool audio_automatic_skip(void)
3602{
3603 return automatic_skip;
3604}
2152 3605
2153 case Q_AUDIO_PRE_FF_REWIND: 3606/* Would normally calculate byte offset from an elapsed time but is not
2154 LOGFQUEUE("audio < Q_AUDIO_PRE_FF_REWIND"); 3607 used on SWCODEC */
2155 if (!playing) 3608int audio_get_file_pos(void)
2156 break; 3609{
2157 pcmbuf_pause(true); 3610 return 0;
2158 break; 3611}
2159 3612
2160 case Q_AUDIO_FF_REWIND: 3613/* Return the elasped time of the track previous to the current */
2161 LOGFQUEUE("audio < Q_AUDIO_FF_REWIND"); 3614unsigned long audio_prev_elapsed(void)
2162 if (!playing) 3615{
2163 break; 3616 return prev_track_elapsed;
3617}
2164 3618
2165 if (filling == STATE_ENDING) 3619/* Is the audio thread ready to accept commands? */
2166 { 3620bool audio_is_thread_ready(void)
2167 /* Temp workaround: There is no codec available */ 3621{
2168 if (!paused) 3622 return filling != STATE_BOOT;
2169 pcmbuf_pause(false); 3623}
2170 break;
2171 }
2172 3624
2173 if ((long)ev.data == 0) 3625/* Return total file buffer length after accounting for the talk buf */
2174 { 3626size_t audio_get_filebuflen(void)
2175 /* About to restart the track - send track finish 3627{
2176 events if not already done. */ 3628 return buf_length();
2177 if (thistrack_id3 == audio_current_track()) 3629}
2178 send_event(PLAYBACK_EVENT_TRACK_FINISH, thistrack_id3);
2179 }
2180 3630
2181 if (automatic_skip) 3631/* How many tracks exist on the buffer - full or partial */
2182 { 3632int audio_track_count(void)
2183 /* An automatic track skip is in progress. Finalize it, 3633 __attribute__((alias("track_list_count")));
2184 then go back to the previous track */
2185 audio_finalise_track_change();
2186 ci.new_track = -1;
2187 }
2188 ci.seek_time = (long)ev.data+1;
2189 break;
2190 3634
2191 case Q_AUDIO_CHECK_NEW_TRACK: 3635/* Return total ringbuffer space occupied - ridx to widx */
2192 LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK"); 3636long audio_filebufused(void)
2193 audio_check_new_track(); 3637{
2194 break; 3638 return buf_used();
3639}
2195 3640
2196 case Q_AUDIO_DIR_SKIP:
2197 LOGFQUEUE("audio < Q_AUDIO_DIR_SKIP");
2198 audio_initiate_dir_change(ev.data);
2199 break;
2200 3641
2201 case Q_AUDIO_FLUSH: 3642/** -- Settings -- **/
2202 LOGFQUEUE("audio < Q_AUDIO_FLUSH");
2203 audio_invalidate_tracks();
2204 break;
2205 3643
2206 case Q_AUDIO_TRACK_CHANGED: 3644/* Enable or disable cuesheet support and allocate/don't allocate the
2207 /* PCM track change done */ 3645 extra associated resources */
2208 LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED"); 3646void audio_set_cuesheet(int enable)
2209 /* Set new playlist position for resuming. */ 3647{
2210 playlist_update_resume_index(); 3648 if (play_status == PLAY_STOPPED || !enable != !get_current_cuesheet())
2211 if (filling != STATE_ENDING) 3649 {
2212 audio_finalise_track_change(); 3650 LOGFQUEUE("audio >| audio Q_AUDIO_REMAKE_AUDIO_BUFFER");
2213 else if (playing) 3651 audio_queue_send(Q_AUDIO_REMAKE_AUDIO_BUFFER, 0);
2214 audio_stop_playback(); 3652 }
2215 break; 3653}
2216 3654
2217 case Q_AUDIO_SEEK_COMPLETE: 3655#ifdef HAVE_DISK_STORAGE
2218 /* Codec seek done */ 3656/* Set the audio antiskip buffer margin by index */
2219 LOGFQUEUE("audio < Q_AUDIO_SEEK_COMPLETE"); 3657void audio_set_buffer_margin(int setting)
2220 audio_seek_complete(); 3658{
2221 codec_ack_msg(Q_AUDIO_SEEK_COMPLETE, false); 3659 static const unsigned short lookup[] =
2222 break; 3660 { 5, 15, 30, 60, 120, 180, 300, 600 };
2223 3661
2224 case Q_CODEC_LOAD: 3662 if ((unsigned)setting >= ARRAYLEN(lookup))
2225 case Q_CODEC_LOAD_DISK: 3663 setting = 0;
2226#ifdef AUDIO_HAVE_RECORDING
2227 case Q_ENCODER_LOAD_DISK:
2228#endif
2229 /* These are received when a codec has finished normally or
2230 upon a codec error */
2231 audio_codec_status_message(ev.id, ev.data);
2232 break;
2233 3664
2234#if (CONFIG_PLATFORM & PLATFORM_NATIVE) 3665 logf("buffer margin: %u", (unsigned)lookup[setting]);
2235 case SYS_USB_CONNECTED:
2236 LOGFQUEUE("audio < SYS_USB_CONNECTED");
2237 if (playing)
2238 audio_stop_playback();
2239#ifdef PLAYBACK_VOICE
2240 voice_stop();
2241#endif
2242 filling = STATE_USB;
2243 usb_acknowledge(SYS_USB_CONNECTED_ACK);
2244 break;
2245#endif
2246 3666
2247#ifdef AUDIO_HAVE_RECORDING 3667 LOGFQUEUE("audio > audio Q_AUDIO_UPDATE_WATERMARK: %u",
2248 case Q_AUDIO_LOAD_ENCODER: 3668 (unsigned)lookup[setting]);
2249 if (playing) 3669 audio_queue_post(Q_AUDIO_UPDATE_WATERMARK, lookup[setting]);
2250 audio_stop_playback(); 3670}
2251 else 3671#endif /* HAVE_DISK_STORAGE */
2252 codec_stop(); /* If encoder still loaded, stop it */
2253 3672
2254 if (ev.data == AFMT_UNKNOWN) 3673#ifdef HAVE_CROSSFADE
2255 break; 3674/* Take necessary steps to enable or disable the crossfade setting */
3675void audio_set_crossfade(int enable)
3676{
3677 /* Tell it the next setting to use */
3678 pcmbuf_request_crossfade_enable(enable);
2256 3679
2257 queue_reply(&audio_queue, 3680 /* Return if size hasn't changed or this is too early to determine
2258 codec_load(-1, ev.data | CODEC_TYPE_ENCODER)); 3681 which in the second case there's no way we could be playing
2259 break; 3682 anything at all */
2260#endif /* AUDIO_HAVE_RECORDING */ 3683 if (!pcmbuf_is_same_size())
3684 {
3685 LOGFQUEUE("audio >| audio Q_AUDIO_REMAKE_AUDIO_BUFFER");
3686 audio_queue_send(Q_AUDIO_REMAKE_AUDIO_BUFFER, 0);
3687 }
3688}
3689#endif /* HAVE_CROSSFADE */
2261 3690
2262 case SYS_TIMEOUT:
2263 LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT");
2264 break;
2265 3691
2266 default: 3692/** -- Startup -- **/
2267 /* LOGFQUEUE("audio < default : %08lX", ev.id); */
2268 break;
2269 } /* end switch */
2270 } /* end while */
2271}
2272 3693
2273/* Initialize the audio system - called from init() in main.c. 3694/* Initialize the audio system - called from init() in main.c */
2274 * Last function because of all the references to internal symbols
2275 */
2276void audio_init(void) 3695void audio_init(void)
2277{ 3696{
2278 unsigned int audio_thread_id;
2279
2280 /* Can never do this twice */ 3697 /* Can never do this twice */
2281 if (audio_is_initialized) 3698 if (audio_is_initialized)
2282 { 3699 {
@@ -2290,31 +3707,20 @@ void audio_init(void)
2290 to send messages. Thread creation will be delayed however so nothing 3707 to send messages. Thread creation will be delayed however so nothing
2291 starts running until ready if something yields such as talk_init. */ 3708 starts running until ready if something yields such as talk_init. */
2292 queue_init(&audio_queue, true); 3709 queue_init(&audio_queue, true);
2293 queue_init(&pcmbuf_queue, false); 3710
3711 mutex_init(&id3_mutex);
2294 3712
2295 pcm_init(); 3713 pcm_init();
2296 3714
2297 codec_init_codec_api(); 3715 codec_init_codec_api();
2298 3716
2299 thistrack_id3 = &mp3entry_buf[0];
2300 othertrack_id3 = &mp3entry_buf[1];
2301
2302 /* cuesheet support */
2303 if (global_settings.cuesheet)
2304 curr_cue = (struct cuesheet*)buffer_alloc(sizeof(struct cuesheet));
2305
2306 /* initialize the buffer */
2307 filebuf = audiobuf;
2308
2309 /* audio_reset_buffer must to know the size of voice buffer so init
2310 talk first */
2311 talk_init();
2312
2313 make_codec_thread(); 3717 make_codec_thread();
2314 3718
3719 /* This thread does buffer, so match its priority */
2315 audio_thread_id = create_thread(audio_thread, audio_stack, 3720 audio_thread_id = create_thread(audio_thread, audio_stack,
2316 sizeof(audio_stack), CREATE_THREAD_FROZEN, 3721 sizeof(audio_stack), CREATE_THREAD_FROZEN,
2317 audio_thread_name IF_PRIO(, PRIORITY_USER_INTERFACE) 3722 audio_thread_name
3723 IF_PRIO(, MIN(PRIORITY_BUFFERING, PRIORITY_USER_INTERFACE))
2318 IF_COP(, CPU)); 3724 IF_COP(, CPU));
2319 3725
2320 queue_enable_queue_send(&audio_queue, &audio_queue_sender_list, 3726 queue_enable_queue_send(&audio_queue, &audio_queue_sender_list,
@@ -2324,39 +3730,21 @@ void audio_init(void)
2324 voice_thread_init(); 3730 voice_thread_init();
2325#endif 3731#endif
2326 3732
3733 /* audio_reset_buffer must to know the size of voice buffer so init
3734 talk first */
3735 talk_init();
3736
2327#ifdef HAVE_CROSSFADE 3737#ifdef HAVE_CROSSFADE
2328 /* Set crossfade setting for next buffer init which should be about... */ 3738 /* Set crossfade setting for next buffer init which should be about... */
2329 pcmbuf_request_crossfade_enable(global_settings.crossfade); 3739 pcmbuf_request_crossfade_enable(global_settings.crossfade);
2330#endif 3740#endif
2331 3741
2332 /* initialize the buffering system */ 3742 /* Initialize the buffering system */
2333 3743 track_list_init();
2334 buffering_init(); 3744 buffering_init();
2335 /* ...now! Set up the buffers */ 3745 /* ...now! Set up the buffers */
2336 audio_reset_buffer(); 3746 audio_reset_buffer();
2337 3747
2338 int i;
2339 for(i = 0; i < MAX_TRACK; i++)
2340 {
2341 tracks[i].audio_hid = -1;
2342 tracks[i].id3_hid = -1;
2343 tracks[i].codec_hid = -1;
2344 tracks[i].cuesheet_hid = -1;
2345 }
2346#ifdef HAVE_ALBUMART
2347 FOREACH_ALBUMART(i)
2348 {
2349 int j;
2350 for (j = 0; j < MAX_TRACK; j++)
2351 {
2352 tracks[j].aa_hid[i] = -1;
2353 }
2354 }
2355#endif
2356
2357 add_event(BUFFER_EVENT_REBUFFER, false, buffering_handle_rebuffer_callback);
2358 add_event(BUFFER_EVENT_FINISHED, false, buffering_handle_finished_callback);
2359
2360 /* Probably safe to say */ 3748 /* Probably safe to say */
2361 audio_is_initialized = true; 3749 audio_is_initialized = true;
2362 3750
@@ -2365,26 +3753,10 @@ void audio_init(void)
2365 audio_set_buffer_margin(global_settings.buffer_margin); 3753 audio_set_buffer_margin(global_settings.buffer_margin);
2366#endif 3754#endif
2367 3755
2368 /* it's safe to let the threads run now */ 3756 /* It's safe to let the threads run now */
2369#ifdef PLAYBACK_VOICE 3757#ifdef PLAYBACK_VOICE
2370 voice_thread_resume(); 3758 voice_thread_resume();
2371#endif 3759#endif
2372 codec_thread_resume(); 3760 codec_thread_resume();
2373 thread_thaw(audio_thread_id); 3761 thread_thaw(audio_thread_id);
2374
2375} /* audio_init */
2376
2377bool audio_is_thread_ready(void)
2378{
2379 return audio_thread_ready;
2380}
2381
2382size_t audio_get_filebuflen(void)
2383{
2384 return filebuflen;
2385}
2386
2387int get_audio_hid()
2388{
2389 return CUR_TI->audio_hid;
2390} 3762}
diff --git a/apps/playback.h b/apps/playback.h
index 76c394603f..225946cfaf 100644
--- a/apps/playback.h
+++ b/apps/playback.h
@@ -26,6 +26,16 @@
26#include <stdlib.h> 26#include <stdlib.h>
27#include "config.h" 27#include "config.h"
28 28
29#if CONFIG_CODEC == SWCODEC
30/* Including the code for fast previews is entirely optional since it
31 does add two more mp3entry's - for certain targets it may be less
32 beneficial such as flash-only storage */
33#if MEMORYSIZE > 2
34#define AUDIO_FAST_SKIP_PREVIEW
35#endif
36
37#endif /* CONFIG_CODEC == SWCODEC */
38
29#ifdef HAVE_ALBUMART 39#ifdef HAVE_ALBUMART
30 40
31#include "bmp.h" 41#include "bmp.h"
@@ -67,6 +77,8 @@ long audio_filebufused(void);
67void audio_pre_ff_rewind(void); 77void audio_pre_ff_rewind(void);
68void audio_skip(int direction); 78void audio_skip(int direction);
69void audio_hard_stop(void); /* Stops audio from serving playback */ 79void audio_hard_stop(void); /* Stops audio from serving playback */
80
81void audio_set_cuesheet(int enable);
70#ifdef HAVE_CROSSFADE 82#ifdef HAVE_CROSSFADE
71void audio_set_crossfade(int enable); 83void audio_set_crossfade(int enable);
72#endif 84#endif
@@ -78,11 +90,10 @@ enum
78}; 90};
79bool audio_restore_playback(int type); /* Restores the audio buffer to handle the requested playback */ 91bool audio_restore_playback(int type); /* Restores the audio buffer to handle the requested playback */
80size_t audio_get_filebuflen(void); 92size_t audio_get_filebuflen(void);
81void audio_pcmbuf_position_callback(unsigned int time) ICODE_ATTR;
82void audio_post_track_change(bool pcmbuf);
83int get_audio_hid(void);
84void audio_set_prev_elapsed(unsigned long setting);
85bool audio_buffer_state_trashed(void); 93bool audio_buffer_state_trashed(void);
94
95/* Automatic transition? Only valid to call during the track change events,
96 otherwise the result is undefined. */
86bool audio_automatic_skip(void); 97bool audio_automatic_skip(void);
87 98
88/* Define one constant that includes recording related functionality */ 99/* Define one constant that includes recording related functionality */
@@ -91,35 +102,62 @@ bool audio_automatic_skip(void);
91#endif 102#endif
92 103
93enum { 104enum {
94 Q_NULL = 0, 105 Q_NULL = 0, /* reserved */
106
107 /* -> audio */
95 Q_AUDIO_PLAY = 1, 108 Q_AUDIO_PLAY = 1,
96 Q_AUDIO_STOP, 109 Q_AUDIO_STOP,
97 Q_AUDIO_PAUSE, 110 Q_AUDIO_PAUSE,
98 Q_AUDIO_SKIP, 111 Q_AUDIO_SKIP,
99 Q_AUDIO_PRE_FF_REWIND, 112 Q_AUDIO_PRE_FF_REWIND,
100 Q_AUDIO_FF_REWIND, 113 Q_AUDIO_FF_REWIND,
101 Q_AUDIO_CHECK_NEW_TRACK,
102 Q_AUDIO_FLUSH, 114 Q_AUDIO_FLUSH,
103 Q_AUDIO_TRACK_CHANGED,
104 Q_AUDIO_SEEK_COMPLETE,
105 Q_AUDIO_DIR_SKIP, 115 Q_AUDIO_DIR_SKIP,
106 Q_AUDIO_POSTINIT,
107 Q_AUDIO_FILL_BUFFER,
108 Q_AUDIO_FINISH_LOAD,
109 Q_CODEC_REQUEST_COMPLETE,
110 Q_CODEC_REQUEST_FAILED,
111 116
117 /* pcmbuf -> audio */
118 Q_AUDIO_TRACK_CHANGED,
119
120 /* audio -> audio */
121 Q_AUDIO_FILL_BUFFER, /* continue buffering next track */
122
123 /* buffering -> audio */
124 Q_AUDIO_BUFFERING, /* some buffer event */
125 Q_AUDIO_FINISH_LOAD_TRACK, /* metadata is buffered */
126 Q_AUDIO_HANDLE_FINISHED, /* some other type is buffered */
127
128 /* codec -> audio (*) */
129 Q_AUDIO_CODEC_SEEK_COMPLETE,
130 Q_AUDIO_CODEC_COMPLETE,
131
132 /* audio -> codec */
112 Q_CODEC_LOAD, 133 Q_CODEC_LOAD,
113 Q_CODEC_LOAD_DISK, 134 Q_CODEC_RUN,
135 Q_CODEC_PAUSE,
136 Q_CODEC_SEEK,
137 Q_CODEC_STOP,
138 Q_CODEC_UNLOAD,
139
114 140
141 /*- miscellanous -*/
115#ifdef AUDIO_HAVE_RECORDING 142#ifdef AUDIO_HAVE_RECORDING
116 Q_AUDIO_LOAD_ENCODER, 143 /* -> codec */
117 Q_ENCODER_LOAD_DISK, 144 Q_AUDIO_LOAD_ENCODER, /* load an encoder for recording */
118 Q_ENCODER_RECORD,
119#endif 145#endif
120 146 /* -> codec */
121 Q_CODEC_DO_CALLBACK, 147 Q_CODEC_DO_CALLBACK,
122 Q_CODEC_ACK,
123};
124 148
149
150 /*- settings -*/
151
152#ifdef HAVE_DISK_STORAGE
153 /* -> audio */
154 Q_AUDIO_UPDATE_WATERMARK, /* buffering watermark needs updating */
125#endif 155#endif
156 /* -> audio */
157 Q_AUDIO_REMAKE_AUDIO_BUFFER, /* buffer needs to be reinitialized */
158};
159
160/* (*) If you change these, you must check audio_clear_track_notifications
161 in playback.c for correctness */
162
163#endif /* _PLAYBACK_H */
diff --git a/apps/playlist.c b/apps/playlist.c
index 14ebb7a198..d17bf230a5 100644
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -822,9 +822,6 @@ static int add_track_to_playlist(struct playlist_info* playlist,
822 playlist->amount++; 822 playlist->amount++;
823 playlist->num_inserted_tracks++; 823 playlist->num_inserted_tracks++;
824 824
825 /* Update index for resume. */
826 playlist_update_resume_index();
827
828 return insert_position; 825 return insert_position;
829} 826}
830 827
@@ -925,9 +922,6 @@ static int remove_track_from_playlist(struct playlist_info* playlist,
925 sync_control(playlist, false); 922 sync_control(playlist, false);
926 } 923 }
927 924
928 /* Update index for resume. */
929 playlist_update_resume_index();
930
931 return 0; 925 return 0;
932} 926}
933 927
@@ -987,9 +981,6 @@ static int randomise_playlist(struct playlist_info* playlist,
987 playlist->first_index, NULL, NULL, NULL); 981 playlist->first_index, NULL, NULL, NULL);
988 } 982 }
989 983
990 /* Update index for resume. */
991 playlist_update_resume_index();
992
993 return 0; 984 return 0;
994} 985}
995 986
@@ -1030,9 +1021,6 @@ static int sort_playlist(struct playlist_info* playlist, bool start_current,
1030 playlist->first_index, -1, NULL, NULL, NULL); 1021 playlist->first_index, -1, NULL, NULL, NULL);
1031 } 1022 }
1032 1023
1033 /* Update index for resume. */
1034 playlist_update_resume_index();
1035
1036 return 0; 1024 return 0;
1037} 1025}
1038 1026
@@ -1205,9 +1193,6 @@ static void find_and_set_playlist_index(struct playlist_info* playlist,
1205 break; 1193 break;
1206 } 1194 }
1207 } 1195 }
1208
1209 /* Update index for resume. */
1210 playlist_update_resume_index();
1211} 1196}
1212 1197
1213/* 1198/*
@@ -2486,6 +2471,12 @@ const char* playlist_peek(int steps, char* buf, size_t buf_size)
2486 if (index < 0) 2471 if (index < 0)
2487 return NULL; 2472 return NULL;
2488 2473
2474#if CONFIG_CODEC == SWCODEC
2475 /* Just testing - don't care about the file name */
2476 if (!buf || !buf_size)
2477 return "";
2478#endif
2479
2489 control_file = playlist->indices[index] & PLAYLIST_INSERT_TYPE_MASK; 2480 control_file = playlist->indices[index] & PLAYLIST_INSERT_TYPE_MASK;
2490 seek = playlist->indices[index] & PLAYLIST_SEEK_MASK; 2481 seek = playlist->indices[index] & PLAYLIST_SEEK_MASK;
2491 2482
@@ -2632,30 +2623,17 @@ int playlist_get_resume_info(int *resume_index)
2632 return 0; 2623 return 0;
2633} 2624}
2634 2625
2635/* Get current playlist index. */
2636int playlist_get_index(void)
2637{
2638 return current_playlist.index;
2639}
2640
2641/* Update resume index within playlist_info structure. */
2642void playlist_update_resume_index(void)
2643{
2644 struct playlist_info* playlist = &current_playlist;
2645 playlist->resume_index = playlist->index;
2646}
2647
2648/* Update resume info for current playing song. Returns -1 on error. */ 2626/* Update resume info for current playing song. Returns -1 on error. */
2649int playlist_update_resume_info(const struct mp3entry* id3) 2627int playlist_update_resume_info(const struct mp3entry* id3)
2650{ 2628{
2651 struct playlist_info* playlist = &current_playlist; 2629 struct playlist_info* playlist = &current_playlist;
2652 2630
2653 if (id3) 2631 if (id3)
2654 { 2632 {
2655 if (global_status.resume_index != playlist->resume_index || 2633 if (global_status.resume_index != playlist->index ||
2656 global_status.resume_offset != id3->offset) 2634 global_status.resume_offset != id3->offset)
2657 { 2635 {
2658 global_status.resume_index = playlist->resume_index; 2636 global_status.resume_index = playlist->index;
2659 global_status.resume_offset = id3->offset; 2637 global_status.resume_offset = id3->offset;
2660 status_save(); 2638 status_save();
2661 } 2639 }
@@ -3203,9 +3181,6 @@ int playlist_move(struct playlist_info* playlist, int index, int new_index)
3203 queue_post(&playlist_queue, PLAYLIST_LOAD_POINTERS, 0); 3181 queue_post(&playlist_queue, PLAYLIST_LOAD_POINTERS, 0);
3204#endif 3182#endif
3205 3183
3206 /* Update index for resume. */
3207 playlist_update_resume_index();
3208
3209 return result; 3184 return result;
3210} 3185}
3211 3186
diff --git a/apps/playlist.h b/apps/playlist.h
index a0e3b579f7..9c45769981 100644
--- a/apps/playlist.h
+++ b/apps/playlist.h
@@ -90,7 +90,6 @@ struct playlist_info
90 int buffer_end_pos; /* last position where buffer was written */ 90 int buffer_end_pos; /* last position where buffer was written */
91 int index; /* index of current playing track */ 91 int index; /* index of current playing track */
92 int first_index; /* index of first song in playlist */ 92 int first_index; /* index of first song in playlist */
93 int resume_index; /* index of playing track to resume */
94 int amount; /* number of tracks in the index */ 93 int amount; /* number of tracks in the index */
95 int last_insert_pos; /* last position we inserted a track */ 94 int last_insert_pos; /* last position we inserted a track */
96 int seed; /* shuffle seed */ 95 int seed; /* shuffle seed */
@@ -132,7 +131,6 @@ const char *playlist_peek(int steps, char* buf, size_t buf_size);
132int playlist_next(int steps); 131int playlist_next(int steps);
133bool playlist_next_dir(int direction); 132bool playlist_next_dir(int direction);
134int playlist_get_resume_info(int *resume_index); 133int playlist_get_resume_info(int *resume_index);
135int playlist_get_index(void);
136int playlist_update_resume_info(const struct mp3entry* id3); 134int playlist_update_resume_info(const struct mp3entry* id3);
137int playlist_get_display_index(void); 135int playlist_get_display_index(void);
138int playlist_amount(void); 136int playlist_amount(void);
@@ -176,6 +174,5 @@ int playlist_directory_tracksearch(const char* dirname, bool recurse,
176 int (*callback)(char*, void*), 174 int (*callback)(char*, void*),
177 void* context); 175 void* context);
178int playlist_remove_all_tracks(struct playlist_info *playlist); 176int playlist_remove_all_tracks(struct playlist_info *playlist);
179void playlist_update_resume_index(void);
180 177
181#endif /* __PLAYLIST_H__ */ 178#endif /* __PLAYLIST_H__ */
diff --git a/apps/plugin.c b/apps/plugin.c
index ea290c89a7..bb326d937b 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -692,7 +692,7 @@ static const struct plugin_api rockbox_api = {
692#if CONFIG_CODEC == SWCODEC 692#if CONFIG_CODEC == SWCODEC
693 codec_thread_do_callback, 693 codec_thread_do_callback,
694 codec_load_file, 694 codec_load_file,
695 codec_begin, 695 codec_run_proc,
696 codec_close, 696 codec_close,
697 get_codec_filename, 697 get_codec_filename,
698 find_array_ptr, 698 find_array_ptr,
diff --git a/apps/plugin.h b/apps/plugin.h
index 4537c6670b..cdf34e28b1 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -145,12 +145,12 @@ void* plugin_get_buffer(size_t *buffer_size);
145#define PLUGIN_MAGIC 0x526F634B /* RocK */ 145#define PLUGIN_MAGIC 0x526F634B /* RocK */
146 146
147/* increase this every time the api struct changes */ 147/* increase this every time the api struct changes */
148#define PLUGIN_API_VERSION 203 148#define PLUGIN_API_VERSION 204
149 149
150/* update this to latest version if a change to the api struct breaks 150/* update this to latest version if a change to the api struct breaks
151 backwards compatibility (and please take the opportunity to sort in any 151 backwards compatibility (and please take the opportunity to sort in any
152 new function which are "waiting" at the end of the function table) */ 152 new function which are "waiting" at the end of the function table) */
153#define PLUGIN_MIN_API_VERSION 203 153#define PLUGIN_MIN_API_VERSION 204
154 154
155/* plugin return codes */ 155/* plugin return codes */
156/* internal returns start at 0x100 to make exit(1..255) work */ 156/* internal returns start at 0x100 to make exit(1..255) work */
@@ -799,9 +799,9 @@ struct plugin_api {
799#if CONFIG_CODEC == SWCODEC 799#if CONFIG_CODEC == SWCODEC
800 void (*codec_thread_do_callback)(void (*fn)(void), 800 void (*codec_thread_do_callback)(void (*fn)(void),
801 unsigned int *audio_thread_id); 801 unsigned int *audio_thread_id);
802 void * (*codec_load_file)(const char* codec, struct codec_api *api); 802 int (*codec_load_file)(const char* codec, struct codec_api *api);
803 int (*codec_begin)(void *handle); 803 int (*codec_run_proc)(void);
804 void (*codec_close)(void *handle); 804 int (*codec_close)(void);
805 const char *(*get_codec_filename)(int cod_spec); 805 const char *(*get_codec_filename)(int cod_spec);
806 void ** (*find_array_ptr)(void **arr, void *ptr); 806 void ** (*find_array_ptr)(void **arr, void *ptr);
807 int (*remove_array_ptr)(void **arr, void *ptr); 807 int (*remove_array_ptr)(void **arr, void *ptr);
diff --git a/apps/plugins/test_codec.c b/apps/plugins/test_codec.c
index 855503a0ec..4bde1ba39d 100644
--- a/apps/plugins/test_codec.c
+++ b/apps/plugins/test_codec.c
@@ -127,7 +127,6 @@ struct test_track_info {
127}; 127};
128 128
129static struct test_track_info track; 129static struct test_track_info track;
130static bool taginfo_ready = true;
131 130
132static bool use_dsp; 131static bool use_dsp;
133 132
@@ -433,6 +432,7 @@ static void pcmbuf_insert_wav_checksum(const void *ch1, const void *ch2, int cou
433static void set_elapsed(unsigned long value) 432static void set_elapsed(unsigned long value)
434{ 433{
435 elapsed = value; 434 elapsed = value;
435 ci.id3->elapsed = value;
436} 436}
437 437
438 438
@@ -482,6 +482,7 @@ static void* request_buffer(size_t *realsize, size_t reqsize)
482static void advance_buffer(size_t amount) 482static void advance_buffer(size_t amount)
483{ 483{
484 ci.curpos += amount; 484 ci.curpos += amount;
485 ci.id3->offset = ci.curpos;
485} 486}
486 487
487 488
@@ -499,20 +500,17 @@ static void seek_complete(void)
499 /* Do nothing */ 500 /* Do nothing */
500} 501}
501 502
502/* Request file change from file buffer. Returns true is next 503/* Codec calls this to know what it should do next. */
503 track is available and changed. If return value is false, 504static enum codec_command_action get_command(intptr_t *param)
504 codec should exit immediately with PLUGIN_OK status. */
505static bool request_next_track(void)
506{ 505{
507 /* We are only decoding a single track */ 506 rb->yield();
508 return false; 507 return CODEC_ACTION_NULL; /* just continue processing */
508 (void)param;
509} 509}
510 510
511
512static void set_offset(size_t value) 511static void set_offset(size_t value)
513{ 512{
514 /* ??? */ 513 ci.id3->offset = value;
515 (void)value;
516} 514}
517 515
518 516
@@ -546,6 +544,9 @@ static void init_ci(void)
546{ 544{
547 /* --- Our "fake" implementations of the codec API functions. --- */ 545 /* --- Our "fake" implementations of the codec API functions. --- */
548 546
547 ci.dsp = (struct dsp_config *)rb->dsp_configure(NULL, DSP_MYDSP,
548 CODEC_IDX_AUDIO);
549
549 ci.codec_get_buffer = codec_get_buffer; 550 ci.codec_get_buffer = codec_get_buffer;
550 551
551 if (wavinfo.fd >= 0 || checksum) { 552 if (wavinfo.fd >= 0 || checksum) {
@@ -560,11 +561,9 @@ static void init_ci(void)
560 ci.advance_buffer = advance_buffer; 561 ci.advance_buffer = advance_buffer;
561 ci.seek_buffer = seek_buffer; 562 ci.seek_buffer = seek_buffer;
562 ci.seek_complete = seek_complete; 563 ci.seek_complete = seek_complete;
563 ci.request_next_track = request_next_track;
564 ci.set_offset = set_offset; 564 ci.set_offset = set_offset;
565 ci.configure = configure; 565 ci.configure = configure;
566 ci.dsp = (struct dsp_config *)rb->dsp_configure(NULL, DSP_MYDSP, 566 ci.get_command = get_command;
567 CODEC_IDX_AUDIO);
568 567
569 /* --- "Core" functions --- */ 568 /* --- "Core" functions --- */
570 569
@@ -620,20 +619,22 @@ static void init_ci(void)
620static void codec_thread(void) 619static void codec_thread(void)
621{ 620{
622 const char* codecname; 621 const char* codecname;
623 void *handle; 622 int res;
624 int res = CODEC_ERROR;
625 623
626 codecname = rb->get_codec_filename(track.id3.codectype); 624 codecname = rb->get_codec_filename(track.id3.codectype);
627 625
628 /* Load the codec and start decoding. */ 626 /* Load the codec */
629 handle = rb->codec_load_file(codecname,&ci); 627 res = rb->codec_load_file(codecname, &ci);
630 628
631 if (handle != NULL) 629 if (res >= 0)
632 { 630 {
633 res = rb->codec_begin(handle); 631 /* Decode the file */
634 rb->codec_close(handle); 632 res = rb->codec_run_proc();
635 } 633 }
636 634
635 /* Clean up */
636 rb->codec_close();
637
637 /* Signal to the main thread that we are done */ 638 /* Signal to the main thread that we are done */
638 endtick = *rb->current_tick - rebuffertick; 639 endtick = *rb->current_tick - rebuffertick;
639 codec_playing = false; 640 codec_playing = false;
@@ -705,11 +706,7 @@ static enum plugin_status test_track(const char* filename)
705 /* Prepare the codec struct for playing the whole file */ 706 /* Prepare the codec struct for playing the whole file */
706 ci.filesize = track.filesize; 707 ci.filesize = track.filesize;
707 ci.id3 = &track.id3; 708 ci.id3 = &track.id3;
708 ci.taginfo_ready = &taginfo_ready;
709 ci.curpos = 0; 709 ci.curpos = 0;
710 ci.stop_codec = false;
711 ci.new_track = 0;
712 ci.seek_time = 0;
713 710
714 if (use_dsp) 711 if (use_dsp)
715 rb->dsp_configure(ci.dsp, DSP_RESET, 0); 712 rb->dsp_configure(ci.dsp, DSP_RESET, 0);