summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorroman.artiukhin <bahusdrive@gmail.com>2023-10-02 19:19:09 +0300
committerAidan MacDonald <amachronic@protonmail.com>2023-10-28 15:11:07 -0400
commit831faa3b82a8c3bfb3241e60641bf783adba4d4a (patch)
tree622e87637e0ef3fab652e053b22b1f8fd7f20fa7
parent90e35716e312b9446515263f75e9e7cb66483c2c (diff)
downloadrockbox-831faa3b82a8c3bfb3241e60641bf783adba4d4a.tar.gz
rockbox-831faa3b82a8c3bfb3241e60641bf783adba4d4a.zip
Rework auto playback frequency switch
Moved logic outside playback events to be executed early. Stops buffering when frequency change is detected (additional STATE_STOPPED state is introduced) Removed no longer used AUDIO_START_REFRESH flag Change-Id: Icfae61725a4d8ffb47380f561a011bda4841457b
-rw-r--r--apps/playback.c102
-rw-r--r--firmware/pcm.c4
2 files changed, 54 insertions, 52 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
355static void audio_start_playback(const struct audio_resume_info *resume_info, 355static 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
2059static 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
4032static void audio_change_frequency_callback(unsigned short id, void *data) 4053static 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
4065void audio_set_playback_frequency(unsigned int sample_rate_hz) 4071void 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);
diff --git a/firmware/pcm.c b/firmware/pcm.c
index 6fc0b626f7..de01af484f 100644
--- a/firmware/pcm.c
+++ b/firmware/pcm.c
@@ -23,7 +23,7 @@
23#include "kernel.h" 23#include "kernel.h"
24 24
25/* Define LOGF_ENABLE to enable logf output in this file */ 25/* Define LOGF_ENABLE to enable logf output in this file */
26/*#define LOGF_ENABLE*/ 26//#define LOGF_ENABLE
27#include "logf.h" 27#include "logf.h"
28#include "audio.h" 28#include "audio.h"
29#include "sound.h" 29#include "sound.h"
@@ -314,7 +314,7 @@ void pcm_play_stop(void)
314 * what pcm_apply_settings will set */ 314 * what pcm_apply_settings will set */
315void pcm_set_frequency(unsigned int samplerate) 315void pcm_set_frequency(unsigned int samplerate)
316{ 316{
317 logf("pcm_set_frequency"); 317 logf("pcm_set_frequency %u", samplerate);
318 318
319 int index; 319 int index;
320 320