diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/playback.c | 102 |
1 files changed, 52 insertions, 50 deletions
diff --git a/apps/playback.c b/apps/playback.c index c61fd9d399..ad7075eaf9 100644 --- a/apps/playback.c +++ b/apps/playback.c | |||
@@ -202,6 +202,7 @@ static enum filling_state | |||
202 | STATE_FINISHED, /* all remaining tracks are fully buffered */ | 202 | STATE_FINISHED, /* all remaining tracks are fully buffered */ |
203 | STATE_ENDING, /* audio playback is ending */ | 203 | STATE_ENDING, /* audio playback is ending */ |
204 | STATE_ENDED, /* audio playback is done */ | 204 | STATE_ENDED, /* audio playback is done */ |
205 | STATE_STOPPED, /* buffering is stopped explicitly */ | ||
205 | } filling = STATE_IDLE; | 206 | } filling = STATE_IDLE; |
206 | 207 | ||
207 | /* Track info - holds information about each track in the buffer */ | 208 | /* Track info - holds information about each track in the buffer */ |
@@ -349,7 +350,6 @@ enum audio_start_playback_flags | |||
349 | { | 350 | { |
350 | AUDIO_START_RESTART = 0x1, /* "Restart" playback (flush _all_ tracks) */ | 351 | AUDIO_START_RESTART = 0x1, /* "Restart" playback (flush _all_ tracks) */ |
351 | AUDIO_START_NEWBUF = 0x2, /* Mark the audiobuffer as invalid */ | 352 | AUDIO_START_NEWBUF = 0x2, /* Mark the audiobuffer as invalid */ |
352 | AUDIO_START_REFRESH = 0x80 | ||
353 | }; | 353 | }; |
354 | 354 | ||
355 | static void audio_start_playback(const struct audio_resume_info *resume_info, | 355 | static void audio_start_playback(const struct audio_resume_info *resume_info, |
@@ -2055,6 +2055,10 @@ static int audio_load_track(void) | |||
2055 | return LOAD_TRACK_OK; | 2055 | return LOAD_TRACK_OK; |
2056 | } | 2056 | } |
2057 | 2057 | ||
2058 | #ifdef HAVE_PLAY_FREQ | ||
2059 | static bool audio_auto_change_frequency(struct mp3entry *id3, bool play); | ||
2060 | #endif | ||
2061 | |||
2058 | /* Second part of the track loading: We now have the metadata available, so we | 2062 | /* Second part of the track loading: We now have the metadata available, so we |
2059 | can load the codec, the album art and finally the audio data. | 2063 | can load the codec, the album art and finally the audio data. |
2060 | This is called on the audio thread after the buffering thread calls the | 2064 | This is called on the audio thread after the buffering thread calls the |
@@ -2087,6 +2091,24 @@ static int audio_finish_load_track(struct track_info *infop) | |||
2087 | goto audio_finish_load_track_exit; | 2091 | goto audio_finish_load_track_exit; |
2088 | } | 2092 | } |
2089 | 2093 | ||
2094 | struct track_info user_cur; | ||
2095 | |||
2096 | #ifdef HAVE_PLAY_FREQ | ||
2097 | track_list_user_current(0, &user_cur); | ||
2098 | bool is_current_user = infop->self_hid == user_cur.self_hid; | ||
2099 | if (audio_auto_change_frequency(track_id3, is_current_user)) | ||
2100 | { | ||
2101 | // frequency switch requires full re-buffering, so stop buffering | ||
2102 | filling = STATE_STOPPED; | ||
2103 | logf("buffering stopped (current_track: %b, current_user: %b)", infop->self_hid == cur_info.self_hid, is_current_user); | ||
2104 | if (is_current_user) | ||
2105 | // audio_finish_load_track_exit not needed as playback restart is already initiated | ||
2106 | return trackstat; | ||
2107 | |||
2108 | goto audio_finish_load_track_exit; | ||
2109 | } | ||
2110 | #endif | ||
2111 | |||
2090 | /* Try to load a cuesheet for the track */ | 2112 | /* Try to load a cuesheet for the track */ |
2091 | if (!audio_load_cuesheet(infop, track_id3)) | 2113 | if (!audio_load_cuesheet(infop, track_id3)) |
2092 | { | 2114 | { |
@@ -2113,7 +2135,6 @@ static int audio_finish_load_track(struct track_info *infop) | |||
2113 | /* All handles available to external routines are ready - audio and codec | 2135 | /* All handles available to external routines are ready - audio and codec |
2114 | information is private */ | 2136 | information is private */ |
2115 | 2137 | ||
2116 | struct track_info user_cur; | ||
2117 | track_list_user_current(0, &user_cur); | 2138 | track_list_user_current(0, &user_cur); |
2118 | if (infop->self_hid == user_cur.self_hid) | 2139 | if (infop->self_hid == user_cur.self_hid) |
2119 | { | 2140 | { |
@@ -2241,7 +2262,7 @@ audio_finish_load_track_exit: | |||
2241 | playlist_peek_offset--; | 2262 | playlist_peek_offset--; |
2242 | } | 2263 | } |
2243 | 2264 | ||
2244 | if (filling != STATE_FULL) | 2265 | if (filling != STATE_FULL && filling != STATE_STOPPED) |
2245 | { | 2266 | { |
2246 | /* Load next track - error or not */ | 2267 | /* Load next track - error or not */ |
2247 | track_list.in_progress_hid = 0; | 2268 | track_list.in_progress_hid = 0; |
@@ -2566,6 +2587,11 @@ static void audio_finalise_track_change(void) | |||
2566 | id3_mutex_unlock(); | 2587 | id3_mutex_unlock(); |
2567 | 2588 | ||
2568 | audio_playlist_track_change(); | 2589 | audio_playlist_track_change(); |
2590 | |||
2591 | #ifdef HAVE_PLAY_FREQ | ||
2592 | if (filling == STATE_STOPPED) | ||
2593 | audio_auto_change_frequency(track_id3, true); | ||
2594 | #endif | ||
2569 | } | 2595 | } |
2570 | 2596 | ||
2571 | /* Actually begin a transition and take care of the codec change - may complete | 2597 | /* Actually begin a transition and take care of the codec change - may complete |
@@ -2667,7 +2693,7 @@ static void audio_on_codec_complete(int status) | |||
2667 | struct track_info info; | 2693 | struct track_info info; |
2668 | bool have_track = track_list_advance_current(1, &info); | 2694 | bool have_track = track_list_advance_current(1, &info); |
2669 | 2695 | ||
2670 | if (!have_track || info.audio_hid < 0) | 2696 | if (!have_track || (info.audio_hid < 0 && filling != STATE_STOPPED)) |
2671 | { | 2697 | { |
2672 | bool end_of_playlist = false; | 2698 | bool end_of_playlist = false; |
2673 | 2699 | ||
@@ -2764,18 +2790,15 @@ static void audio_start_playback(const struct audio_resume_info *resume_info, | |||
2764 | static struct audio_resume_info resume = { 0, 0 }; | 2790 | static struct audio_resume_info resume = { 0, 0 }; |
2765 | enum play_status old_status = play_status; | 2791 | enum play_status old_status = play_status; |
2766 | 2792 | ||
2767 | if (!(flags & AUDIO_START_REFRESH)) | 2793 | if (resume_info) |
2768 | { | 2794 | { |
2769 | if (resume_info) | 2795 | resume.elapsed = resume_info->elapsed; |
2770 | { | 2796 | resume.offset = resume_info->offset; |
2771 | resume.elapsed = resume_info->elapsed; | 2797 | } |
2772 | resume.offset = resume_info->offset; | 2798 | else |
2773 | } | 2799 | { |
2774 | else | 2800 | resume.elapsed = 0; |
2775 | { | 2801 | resume.offset = 0; |
2776 | resume.elapsed = 0; | ||
2777 | resume.offset = 0; | ||
2778 | } | ||
2779 | } | 2802 | } |
2780 | 2803 | ||
2781 | if (flags & AUDIO_START_NEWBUF) | 2804 | if (flags & AUDIO_START_NEWBUF) |
@@ -2802,11 +2825,8 @@ static void audio_start_playback(const struct audio_resume_info *resume_info, | |||
2802 | left off */ | 2825 | left off */ |
2803 | pcmbuf_play_stop(); | 2826 | pcmbuf_play_stop(); |
2804 | 2827 | ||
2805 | if (!(flags & AUDIO_START_REFRESH)) | 2828 | resume.elapsed = id3_get(PLAYING_ID3)->elapsed; |
2806 | { | 2829 | resume.offset = id3_get(PLAYING_ID3)->offset; |
2807 | resume.elapsed = id3_get(PLAYING_ID3)->elapsed; | ||
2808 | resume.offset = id3_get(PLAYING_ID3)->offset; | ||
2809 | } | ||
2810 | 2830 | ||
2811 | track_list_clear(TRACK_LIST_CLEAR_ALL); | 2831 | track_list_clear(TRACK_LIST_CLEAR_ALL); |
2812 | pcmbuf_update_frequency(); | 2832 | pcmbuf_update_frequency(); |
@@ -3425,7 +3445,7 @@ void audio_playback_handler(struct queue_event *ev) | |||
3425 | case Q_AUDIO_REMAKE_AUDIO_BUFFER: | 3445 | case Q_AUDIO_REMAKE_AUDIO_BUFFER: |
3426 | /* buffer needs to be reinitialized */ | 3446 | /* buffer needs to be reinitialized */ |
3427 | LOGFQUEUE("playback < Q_AUDIO_REMAKE_AUDIO_BUFFER"); | 3447 | LOGFQUEUE("playback < Q_AUDIO_REMAKE_AUDIO_BUFFER"); |
3428 | audio_start_playback(NULL, AUDIO_START_RESTART | AUDIO_START_NEWBUF | (ev->data ? AUDIO_START_REFRESH : 0)); | 3448 | audio_start_playback(NULL, AUDIO_START_RESTART | AUDIO_START_NEWBUF); |
3429 | if (play_status == PLAY_STOPPED) | 3449 | if (play_status == PLAY_STOPPED) |
3430 | return; /* just need to change buffer state */ | 3450 | return; /* just need to change buffer state */ |
3431 | break; | 3451 | break; |
@@ -3465,6 +3485,7 @@ void audio_playback_handler(struct queue_event *ev) | |||
3465 | } | 3485 | } |
3466 | /* Fall-through */ | 3486 | /* Fall-through */ |
3467 | case STATE_FINISHED: | 3487 | case STATE_FINISHED: |
3488 | case STATE_STOPPED: | ||
3468 | /* All data was buffered */ | 3489 | /* All data was buffered */ |
3469 | cancel_cpu_boost(); | 3490 | cancel_cpu_boost(); |
3470 | /* Fall-through */ | 3491 | /* Fall-through */ |
@@ -4029,37 +4050,22 @@ static unsigned long audio_guess_frequency(struct mp3entry *id3) | |||
4029 | } | 4050 | } |
4030 | } | 4051 | } |
4031 | 4052 | ||
4032 | static void audio_change_frequency_callback(unsigned short id, void *data) | 4053 | static bool audio_auto_change_frequency(struct mp3entry *id3, bool play) |
4033 | { | 4054 | { |
4034 | static bool starting_playback = false; | 4055 | unsigned long guessed_frequency = global_settings.play_frequency == 0 ? audio_guess_frequency(id3) : 0; |
4035 | struct mp3entry *id3; | 4056 | if (guessed_frequency && mixer_get_frequency() != guessed_frequency) |
4036 | |||
4037 | switch (id) | ||
4038 | { | 4057 | { |
4039 | case PLAYBACK_EVENT_START_PLAYBACK: | 4058 | if (!play) |
4040 | starting_playback = true; | 4059 | return true; |
4041 | break; | ||
4042 | 4060 | ||
4043 | case PLAYBACK_EVENT_TRACK_CHANGE: | ||
4044 | id3 = ((struct track_event *)data)->id3; | ||
4045 | if (id3 && !global_settings.play_frequency) | ||
4046 | { | ||
4047 | unsigned long guessed_frequency = audio_guess_frequency(id3); | ||
4048 | if (mixer_get_frequency() != guessed_frequency) | ||
4049 | { | ||
4050 | #ifdef PLAYBACK_VOICE | 4061 | #ifdef PLAYBACK_VOICE |
4051 | voice_stop(); | 4062 | voice_stop(); |
4052 | #endif | 4063 | #endif |
4053 | mixer_set_frequency(guessed_frequency); | 4064 | mixer_set_frequency(guessed_frequency); |
4054 | audio_queue_post(Q_AUDIO_REMAKE_AUDIO_BUFFER, starting_playback); | 4065 | audio_queue_post(Q_AUDIO_REMAKE_AUDIO_BUFFER, 0); |
4055 | } | 4066 | return true; |
4056 | } | ||
4057 | starting_playback = false; | ||
4058 | break; | ||
4059 | |||
4060 | default: | ||
4061 | break; | ||
4062 | } | 4067 | } |
4068 | return false; | ||
4063 | } | 4069 | } |
4064 | 4070 | ||
4065 | void audio_set_playback_frequency(unsigned int sample_rate_hz) | 4071 | void audio_set_playback_frequency(unsigned int sample_rate_hz) |
@@ -4124,10 +4130,6 @@ void INIT_ATTR playback_init(void) | |||
4124 | track_list_init(); | 4130 | track_list_init(); |
4125 | buffering_init(); | 4131 | buffering_init(); |
4126 | pcmbuf_update_frequency(); | 4132 | pcmbuf_update_frequency(); |
4127 | #ifdef HAVE_PLAY_FREQ | ||
4128 | add_event(PLAYBACK_EVENT_TRACK_CHANGE, audio_change_frequency_callback); | ||
4129 | add_event(PLAYBACK_EVENT_START_PLAYBACK, audio_change_frequency_callback); | ||
4130 | #endif | ||
4131 | #ifdef HAVE_CROSSFADE | 4133 | #ifdef HAVE_CROSSFADE |
4132 | /* Set crossfade setting for next buffer init which should be about... */ | 4134 | /* Set crossfade setting for next buffer init which should be about... */ |
4133 | pcmbuf_request_crossfade_enable(global_settings.crossfade); | 4135 | pcmbuf_request_crossfade_enable(global_settings.crossfade); |