diff options
-rw-r--r-- | apps/database.c | 17 | ||||
-rw-r--r-- | firmware/export/mpeg.h | 7 | ||||
-rw-r--r-- | firmware/mpeg.c | 125 |
3 files changed, 132 insertions, 17 deletions
diff --git a/apps/database.c b/apps/database.c index 1691e2221b..90cdc37f2c 100644 --- a/apps/database.c +++ b/apps/database.c | |||
@@ -43,7 +43,13 @@ | |||
43 | #include "keyboard.h" | 43 | #include "keyboard.h" |
44 | #include "database.h" | 44 | #include "database.h" |
45 | #include "autoconf.h" | 45 | #include "autoconf.h" |
46 | |||
47 | #if CONFIG_HWCODEC == MASNONE | ||
46 | #include "playback.h" | 48 | #include "playback.h" |
49 | #else | ||
50 | #include "mpeg.h" | ||
51 | #endif | ||
52 | |||
47 | #include "logf.h" | 53 | #include "logf.h" |
48 | 54 | ||
49 | /* internal functions */ | 55 | /* internal functions */ |
@@ -328,9 +334,6 @@ void rundb_buffer_track(struct mp3entry *id, bool last_track) { | |||
328 | 334 | ||
329 | int rundb_init(void) | 335 | int rundb_init(void) |
330 | { | 336 | { |
331 | #if CONFIG_HWCODEC != MASNONE | ||
332 | return -1; | ||
333 | #else | ||
334 | unsigned char* ptr = (char*)&rundbheader.version; | 337 | unsigned char* ptr = (char*)&rundbheader.version; |
335 | #ifdef ROCKBOX_LITTLE_ENDIAN | 338 | #ifdef ROCKBOX_LITTLE_ENDIAN |
336 | int i, *p; | 339 | int i, *p; |
@@ -376,17 +379,13 @@ int rundb_init(void) | |||
376 | } | 379 | } |
377 | 380 | ||
378 | rundb_initialized = 1; | 381 | rundb_initialized = 1; |
379 | /* hooks disabled for archos, rendering the runtime database not working, | ||
380 | * re enable when these callbacks are implemented in mpeg.c */ | ||
381 | #if CONFIG_HWCODEC == MASNONE | ||
382 | audio_set_track_buffer_event(&rundb_buffer_track); | 382 | audio_set_track_buffer_event(&rundb_buffer_track); |
383 | audio_set_track_changed_event(&rundb_track_change); | 383 | audio_set_track_changed_event(&rundb_track_change); |
384 | audio_set_track_unbuffer_event(&rundb_unbuffer_track); | 384 | audio_set_track_unbuffer_event(&rundb_unbuffer_track); |
385 | logf("rundb inited."); | 385 | logf("rundb inited."); |
386 | #endif | 386 | |
387 | rundbsize=lseek(rundb_fd,0,SEEK_END); | 387 | rundbsize=lseek(rundb_fd,0,SEEK_END); |
388 | return 0; | 388 | return 0; |
389 | #endif | ||
390 | } | 389 | } |
391 | 390 | ||
392 | void rundb_shutdown(void) | 391 | void rundb_shutdown(void) |
@@ -394,11 +393,9 @@ void rundb_shutdown(void) | |||
394 | if (rundb_fd >= 0) | 393 | if (rundb_fd >= 0) |
395 | close(rundb_fd); | 394 | close(rundb_fd); |
396 | rundb_initialized = 0; | 395 | rundb_initialized = 0; |
397 | #if CONFIG_HWCODEC == MASNONE | ||
398 | audio_set_track_buffer_event(NULL); | 396 | audio_set_track_buffer_event(NULL); |
399 | audio_set_track_unbuffer_event(NULL); | 397 | audio_set_track_unbuffer_event(NULL); |
400 | audio_set_track_changed_event(NULL); | 398 | audio_set_track_changed_event(NULL); |
401 | #endif | ||
402 | } | 399 | } |
403 | 400 | ||
404 | void writerundbheader(void) | 401 | void writerundbheader(void) |
diff --git a/firmware/export/mpeg.h b/firmware/export/mpeg.h index 71e61a08c9..d8dea3d143 100644 --- a/firmware/export/mpeg.h +++ b/firmware/export/mpeg.h | |||
@@ -20,6 +20,7 @@ | |||
20 | #define _MPEG_H_ | 20 | #define _MPEG_H_ |
21 | 21 | ||
22 | #include <stdbool.h> | 22 | #include <stdbool.h> |
23 | #include "id3.h" | ||
23 | 24 | ||
24 | #define MPEG_SWAP_CHUNKSIZE 0x2000 | 25 | #define MPEG_SWAP_CHUNKSIZE 0x2000 |
25 | #define MPEG_HIGH_WATER 2 /* We leave 2 bytes empty because otherwise we | 26 | #define MPEG_HIGH_WATER 2 /* We leave 2 bytes empty because otherwise we |
@@ -65,4 +66,10 @@ void rec_tick(void); | |||
65 | void playback_tick(void); /* FixMe: get rid of this, use mp3_get_playtime() */ | 66 | void playback_tick(void); /* FixMe: get rid of this, use mp3_get_playtime() */ |
66 | void mpeg_id3_options(bool _v1first); | 67 | void mpeg_id3_options(bool _v1first); |
67 | 68 | ||
69 | void audio_set_track_changed_event(void (*handler)(struct mp3entry *id3)); | ||
70 | void audio_set_track_buffer_event(void (*handler)(struct mp3entry *id3, | ||
71 | bool last_track)); | ||
72 | void audio_set_track_unbuffer_event(void (*handler)(struct mp3entry *id3, | ||
73 | bool last_track)); | ||
74 | |||
68 | #endif | 75 | #endif |
diff --git a/firmware/mpeg.c b/firmware/mpeg.c index 0406376e00..575ba29fe3 100644 --- a/firmware/mpeg.c +++ b/firmware/mpeg.c | |||
@@ -84,6 +84,9 @@ extern int playlist_update_resume_info(const struct mp3entry* id3); | |||
84 | #define MPEG_SAVE_DATA 102 | 84 | #define MPEG_SAVE_DATA 102 |
85 | #define MPEG_STOP_DONE 103 | 85 | #define MPEG_STOP_DONE 103 |
86 | 86 | ||
87 | /* indicator for MPEG_NEED_DATA */ | ||
88 | #define GENERATE_UNBUFFER_EVENTS ((void*)1) | ||
89 | |||
87 | /* list of tracks in memory */ | 90 | /* list of tracks in memory */ |
88 | #define MAX_TRACK_ENTRIES (1<<4) /* Must be power of 2 */ | 91 | #define MAX_TRACK_ENTRIES (1<<4) /* Must be power of 2 */ |
89 | #define MAX_TRACK_ENTRIES_MASK (MAX_TRACK_ENTRIES - 1) | 92 | #define MAX_TRACK_ENTRIES_MASK (MAX_TRACK_ENTRIES - 1) |
@@ -93,6 +96,7 @@ struct trackdata | |||
93 | struct mp3entry id3; | 96 | struct mp3entry id3; |
94 | int mempos; | 97 | int mempos; |
95 | int load_ahead_index; | 98 | int load_ahead_index; |
99 | bool event_sent; | ||
96 | }; | 100 | }; |
97 | 101 | ||
98 | static struct trackdata trackdata[MAX_TRACK_ENTRIES]; | 102 | static struct trackdata trackdata[MAX_TRACK_ENTRIES]; |
@@ -105,6 +109,11 @@ static int track_read_idx = 0; | |||
105 | static int track_write_idx = 0; | 109 | static int track_write_idx = 0; |
106 | #endif /* !SIMULATOR */ | 110 | #endif /* !SIMULATOR */ |
107 | 111 | ||
112 | /* Callback function to call when current track has really changed. */ | ||
113 | void (*track_changed_callback)(struct mp3entry *id3); | ||
114 | void (*track_buffer_callback)(struct mp3entry *id3, bool last_track); | ||
115 | void (*track_unbuffer_callback)(struct mp3entry *id3, bool last_track); | ||
116 | |||
108 | static const char mpeg_thread_name[] = "mpeg"; | 117 | static const char mpeg_thread_name[] = "mpeg"; |
109 | static unsigned int mpeg_errno; | 118 | static unsigned int mpeg_errno; |
110 | 119 | ||
@@ -400,8 +409,89 @@ unsigned long mpeg_get_last_header(void) | |||
400 | #endif /* !SIMULATOR */ | 409 | #endif /* !SIMULATOR */ |
401 | } | 410 | } |
402 | 411 | ||
412 | void audio_set_track_buffer_event(void (*handler)(struct mp3entry *id3, | ||
413 | bool last_track)) | ||
414 | { | ||
415 | track_buffer_callback = handler; | ||
416 | } | ||
417 | |||
418 | void audio_set_track_unbuffer_event(void (*handler)(struct mp3entry *id3, | ||
419 | bool last_track)) | ||
420 | { | ||
421 | track_unbuffer_callback = handler; | ||
422 | } | ||
423 | |||
424 | void audio_set_track_changed_event(void (*handler)(struct mp3entry *id3)) | ||
425 | { | ||
426 | track_changed_callback = handler; | ||
427 | } | ||
403 | 428 | ||
404 | #ifndef SIMULATOR | 429 | #ifndef SIMULATOR |
430 | /* Send callback events to notify about removing old tracks. */ | ||
431 | static void generate_unbuffer_events(void) | ||
432 | { | ||
433 | int i; | ||
434 | int event_count = 0; | ||
435 | int numentries = MAX_TRACK_ENTRIES - num_tracks_in_memory(); | ||
436 | int cur_idx = track_write_idx; | ||
437 | |||
438 | for (i = 0; i < numentries; i++) | ||
439 | { | ||
440 | if (trackdata[cur_idx].event_sent) | ||
441 | event_count++; | ||
442 | |||
443 | cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK; | ||
444 | } | ||
445 | |||
446 | cur_idx = track_write_idx; | ||
447 | |||
448 | for (i = 0; i < numentries; i++) | ||
449 | { | ||
450 | /* Send an event to notify that track has finished. */ | ||
451 | if (trackdata[cur_idx].event_sent) | ||
452 | { | ||
453 | event_count--; | ||
454 | if (track_unbuffer_callback) | ||
455 | track_unbuffer_callback(&trackdata[cur_idx].id3, | ||
456 | event_count == 0); | ||
457 | trackdata[cur_idx].event_sent = false; | ||
458 | } | ||
459 | cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK; | ||
460 | } | ||
461 | } | ||
462 | |||
463 | /* Send callback events to notify about new tracks. */ | ||
464 | static void generate_postbuffer_events(void) | ||
465 | { | ||
466 | int i; | ||
467 | int event_count = 0; | ||
468 | int numentries = num_tracks_in_memory(); | ||
469 | int cur_idx = track_read_idx; | ||
470 | |||
471 | for (i = 0; i < numentries; i++) | ||
472 | { | ||
473 | if (!trackdata[cur_idx].event_sent) | ||
474 | event_count++; | ||
475 | |||
476 | cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK; | ||
477 | } | ||
478 | |||
479 | cur_idx = track_read_idx; | ||
480 | |||
481 | for (i = 0; i < numentries; i++) | ||
482 | { | ||
483 | if (!trackdata[cur_idx].event_sent) | ||
484 | { | ||
485 | event_count--; | ||
486 | if (track_buffer_callback) | ||
487 | track_buffer_callback(&trackdata[cur_idx].id3, | ||
488 | event_count == 0); | ||
489 | trackdata[cur_idx].event_sent = true; | ||
490 | } | ||
491 | cur_idx = (cur_idx + 1) & MAX_TRACK_ENTRIES_MASK; | ||
492 | } | ||
493 | } | ||
494 | |||
405 | static void recalculate_watermark(int bitrate) | 495 | static void recalculate_watermark(int bitrate) |
406 | { | 496 | { |
407 | int bytes_per_sec; | 497 | int bytes_per_sec; |
@@ -684,7 +774,7 @@ static void transfer_end(unsigned char** ppbuf, int* psize) | |||
684 | if(!filling && unplayed_space_left < low_watermark) | 774 | if(!filling && unplayed_space_left < low_watermark) |
685 | { | 775 | { |
686 | filling = true; | 776 | filling = true; |
687 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | 777 | queue_post(&mpeg_queue, MPEG_NEED_DATA, GENERATE_UNBUFFER_EVENTS); |
688 | } | 778 | } |
689 | 779 | ||
690 | if(unplayed_space_left) | 780 | if(unplayed_space_left) |
@@ -862,6 +952,7 @@ static void stop_playing(void) | |||
862 | close(mpeg_file); | 952 | close(mpeg_file); |
863 | mpeg_file = -1; | 953 | mpeg_file = -1; |
864 | remove_all_tags(); | 954 | remove_all_tags(); |
955 | generate_unbuffer_events(); | ||
865 | reset_mp3_buffer(); | 956 | reset_mp3_buffer(); |
866 | } | 957 | } |
867 | 958 | ||
@@ -894,6 +985,8 @@ static void track_change(void) | |||
894 | if (num_tracks_in_memory() > 0) | 985 | if (num_tracks_in_memory() > 0) |
895 | { | 986 | { |
896 | remove_current_tag(); | 987 | remove_current_tag(); |
988 | if (track_changed_callback) | ||
989 | track_changed_callback(audio_current_track()); | ||
897 | update_playlist(); | 990 | update_playlist(); |
898 | } | 991 | } |
899 | 992 | ||
@@ -935,9 +1028,15 @@ static void start_playback_if_ready(void) | |||
935 | !filling || dma_underrun) | 1028 | !filling || dma_underrun) |
936 | { | 1029 | { |
937 | DEBUGF("P\n"); | 1030 | DEBUGF("P\n"); |
938 | play_pending = false; | 1031 | if (play_pending) /* don't do this when recovering from DMA underrun */ |
1032 | { | ||
1033 | generate_postbuffer_events(); /* signal first track as buffered */ | ||
1034 | if (track_changed_callback) | ||
1035 | track_changed_callback(audio_current_track()); | ||
1036 | play_pending = false; | ||
1037 | } | ||
939 | playing = true; | 1038 | playing = true; |
940 | 1039 | ||
941 | last_dma_chunk_size = MIN(0x2000, get_unplayed_space_current_song()); | 1040 | last_dma_chunk_size = MIN(0x2000, get_unplayed_space_current_song()); |
942 | mp3_play_data(audiobuf + audiobuf_read, last_dma_chunk_size, transfer_end); | 1041 | mp3_play_data(audiobuf + audiobuf_read, last_dma_chunk_size, transfer_end); |
943 | dma_underrun = false; | 1042 | dma_underrun = false; |
@@ -1066,6 +1165,7 @@ static void mpeg_thread(void) | |||
1066 | 1165 | ||
1067 | reset_mp3_buffer(); | 1166 | reset_mp3_buffer(); |
1068 | remove_all_tags(); | 1167 | remove_all_tags(); |
1168 | generate_unbuffer_events(); | ||
1069 | 1169 | ||
1070 | if(mpeg_file >= 0) | 1170 | if(mpeg_file >= 0) |
1071 | close(mpeg_file); | 1171 | close(mpeg_file); |
@@ -1170,7 +1270,7 @@ static void mpeg_thread(void) | |||
1170 | /* should we start reading more data? */ | 1270 | /* should we start reading more data? */ |
1171 | if(!filling && (unplayed_space_left < low_watermark)) { | 1271 | if(!filling && (unplayed_space_left < low_watermark)) { |
1172 | filling = true; | 1272 | filling = true; |
1173 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | 1273 | queue_post(&mpeg_queue, MPEG_NEED_DATA, GENERATE_UNBUFFER_EVENTS); |
1174 | play_pending = true; | 1274 | play_pending = true; |
1175 | } else if(unswapped_space_left && | 1275 | } else if(unswapped_space_left && |
1176 | unswapped_space_left > unplayed_space_left) { | 1276 | unswapped_space_left > unplayed_space_left) { |
@@ -1194,6 +1294,7 @@ static void mpeg_thread(void) | |||
1194 | 1294 | ||
1195 | reset_mp3_buffer(); | 1295 | reset_mp3_buffer(); |
1196 | remove_all_tags(); | 1296 | remove_all_tags(); |
1297 | generate_unbuffer_events(); | ||
1197 | 1298 | ||
1198 | /* Open the next file */ | 1299 | /* Open the next file */ |
1199 | if (mpeg_file >= 0) | 1300 | if (mpeg_file >= 0) |
@@ -1233,6 +1334,7 @@ static void mpeg_thread(void) | |||
1233 | 1334 | ||
1234 | reset_mp3_buffer(); | 1335 | reset_mp3_buffer(); |
1235 | remove_all_tags(); | 1336 | remove_all_tags(); |
1337 | generate_unbuffer_events(); | ||
1236 | 1338 | ||
1237 | /* Open the next file */ | 1339 | /* Open the next file */ |
1238 | if (mpeg_file >= 0) | 1340 | if (mpeg_file >= 0) |
@@ -1324,7 +1426,7 @@ static void mpeg_thread(void) | |||
1324 | { | 1426 | { |
1325 | /* We need to load more data before starting */ | 1427 | /* We need to load more data before starting */ |
1326 | filling = true; | 1428 | filling = true; |
1327 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | 1429 | queue_post(&mpeg_queue, MPEG_NEED_DATA, GENERATE_UNBUFFER_EVENTS); |
1328 | play_pending = true; | 1430 | play_pending = true; |
1329 | } | 1431 | } |
1330 | else | 1432 | else |
@@ -1348,6 +1450,7 @@ static void mpeg_thread(void) | |||
1348 | /* We have to reload the current track */ | 1450 | /* We have to reload the current track */ |
1349 | close(mpeg_file); | 1451 | close(mpeg_file); |
1350 | remove_all_non_current_tags(); | 1452 | remove_all_non_current_tags(); |
1453 | generate_unbuffer_events(); | ||
1351 | mpeg_file = -1; | 1454 | mpeg_file = -1; |
1352 | } | 1455 | } |
1353 | 1456 | ||
@@ -1396,6 +1499,7 @@ static void mpeg_thread(void) | |||
1396 | 1499 | ||
1397 | close(mpeg_file); | 1500 | close(mpeg_file); |
1398 | remove_all_non_current_tags(); | 1501 | remove_all_non_current_tags(); |
1502 | generate_unbuffer_events(); | ||
1399 | mpeg_file = -1; | 1503 | mpeg_file = -1; |
1400 | reload_track = true; | 1504 | reload_track = true; |
1401 | } | 1505 | } |
@@ -1407,8 +1511,8 @@ static void mpeg_thread(void) | |||
1407 | if(reload_track && new_file(1) >= 0) | 1511 | if(reload_track && new_file(1) >= 0) |
1408 | { | 1512 | { |
1409 | /* Tell ourselves that we want more data */ | 1513 | /* Tell ourselves that we want more data */ |
1410 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | ||
1411 | filling = true; | 1514 | filling = true; |
1515 | queue_post(&mpeg_queue, MPEG_NEED_DATA, 0); | ||
1412 | } | 1516 | } |
1413 | 1517 | ||
1414 | break; | 1518 | break; |
@@ -1425,12 +1529,16 @@ static void mpeg_thread(void) | |||
1425 | 1529 | ||
1426 | /* Make sure that we don't fill the entire buffer */ | 1530 | /* Make sure that we don't fill the entire buffer */ |
1427 | free_space_left -= MPEG_HIGH_WATER; | 1531 | free_space_left -= MPEG_HIGH_WATER; |
1532 | |||
1533 | if (ev.data == GENERATE_UNBUFFER_EVENTS) | ||
1534 | generate_unbuffer_events(); | ||
1428 | 1535 | ||
1429 | /* do we have any more buffer space to fill? */ | 1536 | /* do we have any more buffer space to fill? */ |
1430 | if(free_space_left <= 0) | 1537 | if(free_space_left <= 0) |
1431 | { | 1538 | { |
1432 | DEBUGF("0\n"); | 1539 | DEBUGF("0\n"); |
1433 | filling = false; | 1540 | filling = false; |
1541 | generate_postbuffer_events(); | ||
1434 | ata_sleep(); | 1542 | ata_sleep(); |
1435 | break; | 1543 | break; |
1436 | } | 1544 | } |
@@ -1575,7 +1683,7 @@ static void mpeg_thread(void) | |||
1575 | if (playing) | 1683 | if (playing) |
1576 | playlist_update_resume_info(audio_current_track()); | 1684 | playlist_update_resume_info(audio_current_track()); |
1577 | break; | 1685 | break; |
1578 | } | 1686 | } |
1579 | #if CONFIG_HWCODEC == MAS3587F | 1687 | #if CONFIG_HWCODEC == MAS3587F |
1580 | } | 1688 | } |
1581 | else | 1689 | else |
@@ -2673,6 +2781,9 @@ static void mpeg_thread(void) | |||
2673 | void audio_init(void) | 2781 | void audio_init(void) |
2674 | { | 2782 | { |
2675 | mpeg_errno = 0; | 2783 | mpeg_errno = 0; |
2784 | track_buffer_callback = NULL; | ||
2785 | track_unbuffer_callback = NULL; | ||
2786 | track_changed_callback = NULL; | ||
2676 | 2787 | ||
2677 | #ifndef SIMULATOR | 2788 | #ifndef SIMULATOR |
2678 | audiobuflen = audiobufend - audiobuf; | 2789 | audiobuflen = audiobufend - audiobuf; |