diff options
Diffstat (limited to 'apps/playback.c')
-rw-r--r-- | apps/playback.c | 215 |
1 files changed, 126 insertions, 89 deletions
diff --git a/apps/playback.c b/apps/playback.c index a37e0ad679..d4f3626f99 100644 --- a/apps/playback.c +++ b/apps/playback.c | |||
@@ -74,29 +74,18 @@ | |||
74 | #include "misc.h" | 74 | #include "misc.h" |
75 | #include "sound.h" | 75 | #include "sound.h" |
76 | #include "metadata.h" | 76 | #include "metadata.h" |
77 | #include "splash.h" | ||
77 | #include "talk.h" | 78 | #include "talk.h" |
78 | #ifdef CONFIG_TUNER | 79 | |
79 | #include "radio.h" | 80 | #ifdef HAVE_RECORDING |
81 | #include "recording.h" | ||
80 | #endif | 82 | #endif |
81 | #include "splash.h" | ||
82 | 83 | ||
83 | static volatile bool audio_codec_loaded; | 84 | static volatile bool audio_codec_loaded; |
84 | static volatile bool voice_codec_loaded; | 85 | static volatile bool voice_codec_loaded; |
85 | static volatile bool playing; | 86 | static volatile bool playing; |
86 | static volatile bool paused; | 87 | static volatile bool paused; |
87 | 88 | ||
88 | #define CODEC_VORBIS "/.rockbox/codecs/vorbis.codec" | ||
89 | #define CODEC_MPA_L3 "/.rockbox/codecs/mpa.codec" | ||
90 | #define CODEC_FLAC "/.rockbox/codecs/flac.codec" | ||
91 | #define CODEC_WAV "/.rockbox/codecs/wav.codec" | ||
92 | #define CODEC_A52 "/.rockbox/codecs/a52.codec" | ||
93 | #define CODEC_MPC "/.rockbox/codecs/mpc.codec" | ||
94 | #define CODEC_WAVPACK "/.rockbox/codecs/wavpack.codec" | ||
95 | #define CODEC_ALAC "/.rockbox/codecs/alac.codec" | ||
96 | #define CODEC_AAC "/.rockbox/codecs/aac.codec" | ||
97 | #define CODEC_SHN "/.rockbox/codecs/shorten.codec" | ||
98 | #define CODEC_AIFF "/.rockbox/codecs/aiff.codec" | ||
99 | #define CODEC_SID "/.rockbox/codecs/sid.codec" | ||
100 | 89 | ||
101 | /* default point to start buffer refill */ | 90 | /* default point to start buffer refill */ |
102 | #define AUDIO_DEFAULT_WATERMARK (1024*512) | 91 | #define AUDIO_DEFAULT_WATERMARK (1024*512) |
@@ -133,6 +122,11 @@ enum { | |||
133 | 122 | ||
134 | Q_CODEC_LOAD, | 123 | Q_CODEC_LOAD, |
135 | Q_CODEC_LOAD_DISK, | 124 | Q_CODEC_LOAD_DISK, |
125 | |||
126 | #if defined(HAVE_RECORDING) && !defined(SIMULATOR) | ||
127 | Q_ENCODER_LOAD_DISK, | ||
128 | Q_ENCODER_RECORD, | ||
129 | #endif | ||
136 | }; | 130 | }; |
137 | 131 | ||
138 | /* As defined in plugins/lib/xxx2wav.h */ | 132 | /* As defined in plugins/lib/xxx2wav.h */ |
@@ -382,7 +376,7 @@ static bool voice_pcmbuf_insert_split_callback( | |||
382 | } | 376 | } |
383 | 377 | ||
384 | return true; | 378 | return true; |
385 | } | 379 | } /* voice_pcmbuf_insert_split_callback */ |
386 | 380 | ||
387 | static bool codec_pcmbuf_insert_split_callback( | 381 | static bool codec_pcmbuf_insert_split_callback( |
388 | const void *ch1, const void *ch2, size_t length) | 382 | const void *ch1, const void *ch2, size_t length) |
@@ -444,7 +438,7 @@ static bool codec_pcmbuf_insert_split_callback( | |||
444 | } | 438 | } |
445 | 439 | ||
446 | return true; | 440 | return true; |
447 | } | 441 | } /* codec_pcmbuf_insert_split_callback */ |
448 | 442 | ||
449 | static bool voice_pcmbuf_insert_callback(const char *buf, size_t length) | 443 | static bool voice_pcmbuf_insert_callback(const char *buf, size_t length) |
450 | { | 444 | { |
@@ -649,7 +643,7 @@ static size_t codec_filebuf_callback(void *ptr, size_t size) | |||
649 | 643 | ||
650 | /* Return the actual amount of data copied to the buffer */ | 644 | /* Return the actual amount of data copied to the buffer */ |
651 | return copy_n; | 645 | return copy_n; |
652 | } | 646 | } /* codec_filebuf_callback */ |
653 | 647 | ||
654 | static void* voice_request_buffer_callback(size_t *realsize, size_t reqsize) | 648 | static void* voice_request_buffer_callback(size_t *realsize, size_t reqsize) |
655 | { | 649 | { |
@@ -664,7 +658,9 @@ static void* voice_request_buffer_callback(size_t *realsize, size_t reqsize) | |||
664 | while (1) | 658 | while (1) |
665 | { | 659 | { |
666 | if (voice_is_playing) | 660 | if (voice_is_playing) |
661 | { | ||
667 | queue_wait_w_tmo(&voice_codec_queue, &ev, 0); | 662 | queue_wait_w_tmo(&voice_codec_queue, &ev, 0); |
663 | } | ||
668 | else if (playing) | 664 | else if (playing) |
669 | { | 665 | { |
670 | queue_wait_w_tmo(&voice_codec_queue, &ev, 0); | 666 | queue_wait_w_tmo(&voice_codec_queue, &ev, 0); |
@@ -679,7 +675,11 @@ static void* voice_request_buffer_callback(size_t *realsize, size_t reqsize) | |||
679 | if (playing) | 675 | if (playing) |
680 | swap_codec(); | 676 | swap_codec(); |
681 | break; | 677 | break; |
682 | 678 | #if defined(HAVE_RECORDING) && !defined(SIMULATOR) | |
679 | case Q_ENCODER_RECORD: | ||
680 | swap_codec(); | ||
681 | break; | ||
682 | #endif | ||
683 | case Q_VOICE_STOP: | 683 | case Q_VOICE_STOP: |
684 | if (voice_is_playing) | 684 | if (voice_is_playing) |
685 | { | 685 | { |
@@ -743,7 +743,7 @@ voice_play_clip: | |||
743 | return NULL; | 743 | return NULL; |
744 | 744 | ||
745 | return voicebuf; | 745 | return voicebuf; |
746 | } | 746 | } /* voice_request_buffer_callback */ |
747 | 747 | ||
748 | static void* codec_request_buffer_callback(size_t *realsize, size_t reqsize) | 748 | static void* codec_request_buffer_callback(size_t *realsize, size_t reqsize) |
749 | { | 749 | { |
@@ -794,7 +794,7 @@ static void* codec_request_buffer_callback(size_t *realsize, size_t reqsize) | |||
794 | *realsize = copy_n; | 794 | *realsize = copy_n; |
795 | 795 | ||
796 | return (char *)&filebuf[buf_ridx]; | 796 | return (char *)&filebuf[buf_ridx]; |
797 | } | 797 | } /* codec_request_buffer_callback */ |
798 | 798 | ||
799 | static int get_codec_base_type(int type) | 799 | static int get_codec_base_type(int type) |
800 | { | 800 | { |
@@ -1531,52 +1531,24 @@ static void codec_discard_codec_callback(void) | |||
1531 | #endif | 1531 | #endif |
1532 | } | 1532 | } |
1533 | 1533 | ||
1534 | static const char *get_codec_path(int codectype) | 1534 | static const char * get_codec_filename(int enc_spec) |
1535 | { | 1535 | { |
1536 | switch (codectype) { | 1536 | const char *fname; |
1537 | case AFMT_OGG_VORBIS: | 1537 | int type = enc_spec & CODEC_TYPE_MASK; |
1538 | logf("Codec: Vorbis"); | 1538 | int afmt = enc_spec & CODEC_AFMT_MASK; |
1539 | return CODEC_VORBIS; | 1539 | |
1540 | case AFMT_MPA_L1: | 1540 | if ((unsigned)afmt >= AFMT_NUM_CODECS) |
1541 | case AFMT_MPA_L2: | 1541 | type = AFMT_UNKNOWN | (type & CODEC_TYPE_MASK); |
1542 | case AFMT_MPA_L3: | 1542 | |
1543 | logf("Codec: MPA L1/L2/L3"); | 1543 | fname = (type == CODEC_TYPE_DECODER) ? |
1544 | return CODEC_MPA_L3; | 1544 | audio_formats[afmt].codec_fn : audio_formats[afmt].codec_enc_fn; |
1545 | case AFMT_PCM_WAV: | 1545 | |
1546 | logf("Codec: PCM WAV"); | 1546 | logf("%s: %d - %s", |
1547 | return CODEC_WAV; | 1547 | (type == CODEC_TYPE_ENCODER) ? "Encoder" : "Decoder", |
1548 | case AFMT_FLAC: | 1548 | afmt, fname ? fname : "<unknown>"); |
1549 | logf("Codec: FLAC"); | 1549 | |
1550 | return CODEC_FLAC; | 1550 | return fname; |
1551 | case AFMT_A52: | 1551 | } /* get_codec_filename */ |
1552 | logf("Codec: A52"); | ||
1553 | return CODEC_A52; | ||
1554 | case AFMT_MPC: | ||
1555 | logf("Codec: Musepack"); | ||
1556 | return CODEC_MPC; | ||
1557 | case AFMT_WAVPACK: | ||
1558 | logf("Codec: WAVPACK"); | ||
1559 | return CODEC_WAVPACK; | ||
1560 | case AFMT_ALAC: | ||
1561 | logf("Codec: ALAC"); | ||
1562 | return CODEC_ALAC; | ||
1563 | case AFMT_AAC: | ||
1564 | logf("Codec: AAC"); | ||
1565 | return CODEC_AAC; | ||
1566 | case AFMT_SHN: | ||
1567 | logf("Codec: SHN"); | ||
1568 | return CODEC_SHN; | ||
1569 | case AFMT_AIFF: | ||
1570 | logf("Codec: PCM AIFF"); | ||
1571 | return CODEC_AIFF; | ||
1572 | case AFMT_SID: | ||
1573 | logf("Codec: SID"); | ||
1574 | return CODEC_SID; | ||
1575 | default: | ||
1576 | logf("Codec: Unsupported"); | ||
1577 | return NULL; | ||
1578 | } | ||
1579 | } | ||
1580 | 1552 | ||
1581 | static bool loadcodec(bool start_play) | 1553 | static bool loadcodec(bool start_play) |
1582 | { | 1554 | { |
@@ -1585,9 +1557,10 @@ static bool loadcodec(bool start_play) | |||
1585 | int rc; | 1557 | int rc; |
1586 | size_t copy_n; | 1558 | size_t copy_n; |
1587 | int prev_track; | 1559 | int prev_track; |
1560 | char codec_path[MAX_PATH]; /* Full path to codec */ | ||
1588 | 1561 | ||
1589 | const char *codec_path = get_codec_path(tracks[track_widx].id3.codectype); | 1562 | const char * codec_fn = get_codec_filename(tracks[track_widx].id3.codectype); |
1590 | if (codec_path == NULL) | 1563 | if (codec_fn == NULL) |
1591 | return false; | 1564 | return false; |
1592 | 1565 | ||
1593 | tracks[track_widx].has_codec = false; | 1566 | tracks[track_widx].has_codec = false; |
@@ -1603,7 +1576,7 @@ static bool loadcodec(bool start_play) | |||
1603 | ci.taginfo_ready = &cur_ti->taginfo_ready; | 1576 | ci.taginfo_ready = &cur_ti->taginfo_ready; |
1604 | ci.curpos = 0; | 1577 | ci.curpos = 0; |
1605 | playing = true; | 1578 | playing = true; |
1606 | queue_post(&codec_queue, Q_CODEC_LOAD_DISK, (void *)codec_path); | 1579 | queue_post(&codec_queue, Q_CODEC_LOAD_DISK, (void *)codec_fn); |
1607 | return true; | 1580 | return true; |
1608 | } | 1581 | } |
1609 | else | 1582 | else |
@@ -1625,6 +1598,8 @@ static bool loadcodec(bool start_play) | |||
1625 | } | 1598 | } |
1626 | } | 1599 | } |
1627 | 1600 | ||
1601 | codec_get_full_path(codec_path, codec_fn); | ||
1602 | |||
1628 | fd = open(codec_path, O_RDONLY); | 1603 | fd = open(codec_path, O_RDONLY); |
1629 | if (fd < 0) | 1604 | if (fd < 0) |
1630 | { | 1605 | { |
@@ -1973,11 +1948,8 @@ static void audio_stop_playback(void) | |||
1973 | (playlist_end && ci.stop_codec)?NULL:audio_current_track()); | 1948 | (playlist_end && ci.stop_codec)?NULL:audio_current_track()); |
1974 | } | 1949 | } |
1975 | 1950 | ||
1976 | if (voice_is_playing) | 1951 | while (voice_is_playing && !queue_empty(&voice_codec_queue)) |
1977 | { | 1952 | yield(); |
1978 | while (voice_is_playing && !queue_empty(&voice_codec_queue)) | ||
1979 | yield(); | ||
1980 | } | ||
1981 | 1953 | ||
1982 | filebufused = 0; | 1954 | filebufused = 0; |
1983 | playing = false; | 1955 | playing = false; |
@@ -1998,10 +1970,8 @@ static void audio_stop_playback(void) | |||
1998 | 1970 | ||
1999 | static void audio_play_start(size_t offset) | 1971 | static void audio_play_start(size_t offset) |
2000 | { | 1972 | { |
2001 | #ifdef CONFIG_TUNER | 1973 | #if defined(HAVE_RECORDING) || defined(CONFIG_TUNER) |
2002 | /* check if radio is playing */ | 1974 | rec_set_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK); |
2003 | if (get_radio_status() != FMRADIO_OFF) | ||
2004 | radio_stop(); | ||
2005 | #endif | 1975 | #endif |
2006 | 1976 | ||
2007 | /* Wait for any previously playing audio to flush - TODO: Not necessary? */ | 1977 | /* Wait for any previously playing audio to flush - TODO: Not necessary? */ |
@@ -2483,6 +2453,20 @@ static void codec_thread(void) | |||
2483 | mutex_unlock(&mutex_codecthread); | 2453 | mutex_unlock(&mutex_codecthread); |
2484 | break ; | 2454 | break ; |
2485 | 2455 | ||
2456 | #if defined(HAVE_RECORDING) && !defined(SIMULATOR) | ||
2457 | case Q_ENCODER_LOAD_DISK: | ||
2458 | logf("Encoder load disk"); | ||
2459 | audio_codec_loaded = false; | ||
2460 | if (voice_codec_loaded && current_codec == CODEC_IDX_VOICE) | ||
2461 | queue_post(&voice_codec_queue, Q_ENCODER_RECORD, NULL); | ||
2462 | mutex_lock(&mutex_codecthread); | ||
2463 | current_codec = CODEC_IDX_AUDIO; | ||
2464 | ci.stop_codec = false; | ||
2465 | status = codec_load_file((const char *)ev.data, &ci); | ||
2466 | mutex_unlock(&mutex_codecthread); | ||
2467 | break; | ||
2468 | #endif | ||
2469 | |||
2486 | #ifndef SIMULATOR | 2470 | #ifndef SIMULATOR |
2487 | case SYS_USB_CONNECTED: | 2471 | case SYS_USB_CONNECTED: |
2488 | queue_clear(&codec_queue); | 2472 | queue_clear(&codec_queue); |
@@ -2511,8 +2495,6 @@ static void codec_thread(void) | |||
2511 | case Q_CODEC_LOAD: | 2495 | case Q_CODEC_LOAD: |
2512 | if (playing) | 2496 | if (playing) |
2513 | { | 2497 | { |
2514 | const char *codec_path; | ||
2515 | |||
2516 | if (ci.new_track || status != CODEC_OK) | 2498 | if (ci.new_track || status != CODEC_OK) |
2517 | { | 2499 | { |
2518 | if (!ci.new_track) | 2500 | if (!ci.new_track) |
@@ -2523,7 +2505,8 @@ static void codec_thread(void) | |||
2523 | 2505 | ||
2524 | if (!load_next_track()) | 2506 | if (!load_next_track()) |
2525 | { | 2507 | { |
2526 | queue_post(&codec_queue, Q_AUDIO_STOP, 0); | 2508 | // queue_post(&codec_queue, Q_AUDIO_STOP, 0); |
2509 | queue_post(&audio_queue, Q_AUDIO_STOP, 0); | ||
2527 | break; | 2510 | break; |
2528 | } | 2511 | } |
2529 | } | 2512 | } |
@@ -2545,12 +2528,12 @@ static void codec_thread(void) | |||
2545 | queue_post(&codec_queue, Q_CODEC_LOAD, 0); | 2528 | queue_post(&codec_queue, Q_CODEC_LOAD, 0); |
2546 | else | 2529 | else |
2547 | { | 2530 | { |
2548 | codec_path = get_codec_path(cur_ti->id3.codectype); | 2531 | const char *codec_fn = get_codec_filename(cur_ti->id3.codectype); |
2549 | queue_post(&codec_queue, | 2532 | queue_post(&codec_queue, Q_CODEC_LOAD_DISK, |
2550 | Q_CODEC_LOAD_DISK, (void *)codec_path); | 2533 | (void *)codec_fn); |
2551 | } | 2534 | } |
2552 | } | 2535 | } |
2553 | } | 2536 | } /* end switch */ |
2554 | } | 2537 | } |
2555 | } | 2538 | } |
2556 | 2539 | ||
@@ -2596,6 +2579,37 @@ static void reset_buffer(void) | |||
2596 | filebuflen &= ~3; | 2579 | filebuflen &= ~3; |
2597 | } | 2580 | } |
2598 | 2581 | ||
2582 | void audio_load_encoder(int enc_id) | ||
2583 | { | ||
2584 | #if defined(HAVE_RECORDING) && !defined(SIMULATOR) | ||
2585 | const char *enc_fn = get_codec_filename(enc_id | CODEC_TYPE_ENCODER); | ||
2586 | if (!enc_fn) | ||
2587 | return; | ||
2588 | |||
2589 | audio_remove_encoder(); | ||
2590 | |||
2591 | queue_post(&codec_queue, Q_ENCODER_LOAD_DISK, (void *)enc_fn); | ||
2592 | |||
2593 | while (!ci.enc_codec_loaded) | ||
2594 | yield(); | ||
2595 | #endif | ||
2596 | return; | ||
2597 | (void)enc_id; | ||
2598 | } /* audio_load_encoder */ | ||
2599 | |||
2600 | void audio_remove_encoder(void) | ||
2601 | { | ||
2602 | #if defined(HAVE_RECORDING) && !defined(SIMULATOR) | ||
2603 | /* force encoder codec unload (if previously loaded) */ | ||
2604 | if (!ci.enc_codec_loaded) | ||
2605 | return; | ||
2606 | |||
2607 | ci.stop_codec = true; | ||
2608 | while (ci.enc_codec_loaded) | ||
2609 | yield(); | ||
2610 | #endif | ||
2611 | } /* audio_remove_encoder */ | ||
2612 | |||
2599 | static void voice_codec_thread(void) | 2613 | static void voice_codec_thread(void) |
2600 | { | 2614 | { |
2601 | while (1) | 2615 | while (1) |
@@ -2608,13 +2622,13 @@ static void voice_codec_thread(void) | |||
2608 | voice_remaining = 0; | 2622 | voice_remaining = 0; |
2609 | voice_getmore = NULL; | 2623 | voice_getmore = NULL; |
2610 | 2624 | ||
2611 | codec_load_file(CODEC_MPA_L3, &ci_voice); | 2625 | codec_load_file(get_codec_filename(AFMT_MPA_L3), &ci_voice); |
2612 | 2626 | ||
2613 | logf("Voice codec finished"); | 2627 | logf("Voice codec finished"); |
2614 | mutex_unlock(&mutex_codecthread); | ||
2615 | voice_codec_loaded = false; | 2628 | voice_codec_loaded = false; |
2629 | mutex_unlock(&mutex_codecthread); | ||
2616 | } | 2630 | } |
2617 | } | 2631 | } /* voice_codec_thread */ |
2618 | 2632 | ||
2619 | void voice_init(void) | 2633 | void voice_init(void) |
2620 | { | 2634 | { |
@@ -2642,7 +2656,20 @@ void voice_init(void) | |||
2642 | 2656 | ||
2643 | while (!voice_codec_loaded) | 2657 | while (!voice_codec_loaded) |
2644 | yield(); | 2658 | yield(); |
2645 | } | 2659 | } /* voice_init */ |
2660 | |||
2661 | void voice_stop(void) | ||
2662 | { | ||
2663 | /* Messages should not be posted to voice codec queue unless it is the | ||
2664 | current codec or deadlocks happen. This will be addressed globally soon. | ||
2665 | -- jhMikeS */ | ||
2666 | if (current_codec != CODEC_IDX_VOICE) | ||
2667 | return; | ||
2668 | |||
2669 | mp3_play_stop(); | ||
2670 | while (voice_is_playing && !queue_empty(&voice_codec_queue)) | ||
2671 | yield(); | ||
2672 | } /* voice_stop */ | ||
2646 | 2673 | ||
2647 | struct mp3entry* audio_current_track(void) | 2674 | struct mp3entry* audio_current_track(void) |
2648 | { | 2675 | { |
@@ -2803,9 +2830,19 @@ int audio_status(void) | |||
2803 | if (paused) | 2830 | if (paused) |
2804 | ret |= AUDIO_STATUS_PAUSE; | 2831 | ret |= AUDIO_STATUS_PAUSE; |
2805 | 2832 | ||
2833 | #ifdef HAVE_RECORDING | ||
2834 | /* Do this here for constitency with mpeg.c version */ | ||
2835 | ret |= pcm_rec_status(); | ||
2836 | #endif | ||
2837 | |||
2806 | return ret; | 2838 | return ret; |
2807 | } | 2839 | } |
2808 | 2840 | ||
2841 | bool audio_query_poweroff(void) | ||
2842 | { | ||
2843 | return !(playing && paused); | ||
2844 | } | ||
2845 | |||
2809 | int audio_get_file_pos(void) | 2846 | int audio_get_file_pos(void) |
2810 | { | 2847 | { |
2811 | return 0; | 2848 | return 0; |