mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-10-14 02:27:39 -04:00
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
This commit is contained in:
parent
90e35716e3
commit
831faa3b82
2 changed files with 54 additions and 52 deletions
102
apps/playback.c
102
apps/playback.c
|
@ -202,6 +202,7 @@ static enum filling_state
|
||||||
STATE_FINISHED, /* all remaining tracks are fully buffered */
|
STATE_FINISHED, /* all remaining tracks are fully buffered */
|
||||||
STATE_ENDING, /* audio playback is ending */
|
STATE_ENDING, /* audio playback is ending */
|
||||||
STATE_ENDED, /* audio playback is done */
|
STATE_ENDED, /* audio playback is done */
|
||||||
|
STATE_STOPPED, /* buffering is stopped explicitly */
|
||||||
} filling = STATE_IDLE;
|
} filling = STATE_IDLE;
|
||||||
|
|
||||||
/* Track info - holds information about each track in the buffer */
|
/* Track info - holds information about each track in the buffer */
|
||||||
|
@ -349,7 +350,6 @@ enum audio_start_playback_flags
|
||||||
{
|
{
|
||||||
AUDIO_START_RESTART = 0x1, /* "Restart" playback (flush _all_ tracks) */
|
AUDIO_START_RESTART = 0x1, /* "Restart" playback (flush _all_ tracks) */
|
||||||
AUDIO_START_NEWBUF = 0x2, /* Mark the audiobuffer as invalid */
|
AUDIO_START_NEWBUF = 0x2, /* Mark the audiobuffer as invalid */
|
||||||
AUDIO_START_REFRESH = 0x80
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void audio_start_playback(const struct audio_resume_info *resume_info,
|
static void audio_start_playback(const struct audio_resume_info *resume_info,
|
||||||
|
@ -2055,6 +2055,10 @@ static int audio_load_track(void)
|
||||||
return LOAD_TRACK_OK;
|
return LOAD_TRACK_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_PLAY_FREQ
|
||||||
|
static bool audio_auto_change_frequency(struct mp3entry *id3, bool play);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Second part of the track loading: We now have the metadata available, so we
|
/* Second part of the track loading: We now have the metadata available, so we
|
||||||
can load the codec, the album art and finally the audio data.
|
can load the codec, the album art and finally the audio data.
|
||||||
This is called on the audio thread after the buffering thread calls the
|
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)
|
||||||
goto audio_finish_load_track_exit;
|
goto audio_finish_load_track_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct track_info user_cur;
|
||||||
|
|
||||||
|
#ifdef HAVE_PLAY_FREQ
|
||||||
|
track_list_user_current(0, &user_cur);
|
||||||
|
bool is_current_user = infop->self_hid == user_cur.self_hid;
|
||||||
|
if (audio_auto_change_frequency(track_id3, is_current_user))
|
||||||
|
{
|
||||||
|
// frequency switch requires full re-buffering, so stop buffering
|
||||||
|
filling = STATE_STOPPED;
|
||||||
|
logf("buffering stopped (current_track: %b, current_user: %b)", infop->self_hid == cur_info.self_hid, is_current_user);
|
||||||
|
if (is_current_user)
|
||||||
|
// audio_finish_load_track_exit not needed as playback restart is already initiated
|
||||||
|
return trackstat;
|
||||||
|
|
||||||
|
goto audio_finish_load_track_exit;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Try to load a cuesheet for the track */
|
/* Try to load a cuesheet for the track */
|
||||||
if (!audio_load_cuesheet(infop, track_id3))
|
if (!audio_load_cuesheet(infop, track_id3))
|
||||||
{
|
{
|
||||||
|
@ -2113,7 +2135,6 @@ static int audio_finish_load_track(struct track_info *infop)
|
||||||
/* All handles available to external routines are ready - audio and codec
|
/* All handles available to external routines are ready - audio and codec
|
||||||
information is private */
|
information is private */
|
||||||
|
|
||||||
struct track_info user_cur;
|
|
||||||
track_list_user_current(0, &user_cur);
|
track_list_user_current(0, &user_cur);
|
||||||
if (infop->self_hid == user_cur.self_hid)
|
if (infop->self_hid == user_cur.self_hid)
|
||||||
{
|
{
|
||||||
|
@ -2241,7 +2262,7 @@ audio_finish_load_track_exit:
|
||||||
playlist_peek_offset--;
|
playlist_peek_offset--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filling != STATE_FULL)
|
if (filling != STATE_FULL && filling != STATE_STOPPED)
|
||||||
{
|
{
|
||||||
/* Load next track - error or not */
|
/* Load next track - error or not */
|
||||||
track_list.in_progress_hid = 0;
|
track_list.in_progress_hid = 0;
|
||||||
|
@ -2566,6 +2587,11 @@ static void audio_finalise_track_change(void)
|
||||||
id3_mutex_unlock();
|
id3_mutex_unlock();
|
||||||
|
|
||||||
audio_playlist_track_change();
|
audio_playlist_track_change();
|
||||||
|
|
||||||
|
#ifdef HAVE_PLAY_FREQ
|
||||||
|
if (filling == STATE_STOPPED)
|
||||||
|
audio_auto_change_frequency(track_id3, true);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Actually begin a transition and take care of the codec change - may complete
|
/* 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)
|
||||||
struct track_info info;
|
struct track_info info;
|
||||||
bool have_track = track_list_advance_current(1, &info);
|
bool have_track = track_list_advance_current(1, &info);
|
||||||
|
|
||||||
if (!have_track || info.audio_hid < 0)
|
if (!have_track || (info.audio_hid < 0 && filling != STATE_STOPPED))
|
||||||
{
|
{
|
||||||
bool end_of_playlist = false;
|
bool end_of_playlist = false;
|
||||||
|
|
||||||
|
@ -2764,18 +2790,15 @@ static void audio_start_playback(const struct audio_resume_info *resume_info,
|
||||||
static struct audio_resume_info resume = { 0, 0 };
|
static struct audio_resume_info resume = { 0, 0 };
|
||||||
enum play_status old_status = play_status;
|
enum play_status old_status = play_status;
|
||||||
|
|
||||||
if (!(flags & AUDIO_START_REFRESH))
|
if (resume_info)
|
||||||
{
|
{
|
||||||
if (resume_info)
|
resume.elapsed = resume_info->elapsed;
|
||||||
{
|
resume.offset = resume_info->offset;
|
||||||
resume.elapsed = resume_info->elapsed;
|
}
|
||||||
resume.offset = resume_info->offset;
|
else
|
||||||
}
|
{
|
||||||
else
|
resume.elapsed = 0;
|
||||||
{
|
resume.offset = 0;
|
||||||
resume.elapsed = 0;
|
|
||||||
resume.offset = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & AUDIO_START_NEWBUF)
|
if (flags & AUDIO_START_NEWBUF)
|
||||||
|
@ -2802,11 +2825,8 @@ static void audio_start_playback(const struct audio_resume_info *resume_info,
|
||||||
left off */
|
left off */
|
||||||
pcmbuf_play_stop();
|
pcmbuf_play_stop();
|
||||||
|
|
||||||
if (!(flags & AUDIO_START_REFRESH))
|
resume.elapsed = id3_get(PLAYING_ID3)->elapsed;
|
||||||
{
|
resume.offset = id3_get(PLAYING_ID3)->offset;
|
||||||
resume.elapsed = id3_get(PLAYING_ID3)->elapsed;
|
|
||||||
resume.offset = id3_get(PLAYING_ID3)->offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
track_list_clear(TRACK_LIST_CLEAR_ALL);
|
track_list_clear(TRACK_LIST_CLEAR_ALL);
|
||||||
pcmbuf_update_frequency();
|
pcmbuf_update_frequency();
|
||||||
|
@ -3425,7 +3445,7 @@ void audio_playback_handler(struct queue_event *ev)
|
||||||
case Q_AUDIO_REMAKE_AUDIO_BUFFER:
|
case Q_AUDIO_REMAKE_AUDIO_BUFFER:
|
||||||
/* buffer needs to be reinitialized */
|
/* buffer needs to be reinitialized */
|
||||||
LOGFQUEUE("playback < Q_AUDIO_REMAKE_AUDIO_BUFFER");
|
LOGFQUEUE("playback < Q_AUDIO_REMAKE_AUDIO_BUFFER");
|
||||||
audio_start_playback(NULL, AUDIO_START_RESTART | AUDIO_START_NEWBUF | (ev->data ? AUDIO_START_REFRESH : 0));
|
audio_start_playback(NULL, AUDIO_START_RESTART | AUDIO_START_NEWBUF);
|
||||||
if (play_status == PLAY_STOPPED)
|
if (play_status == PLAY_STOPPED)
|
||||||
return; /* just need to change buffer state */
|
return; /* just need to change buffer state */
|
||||||
break;
|
break;
|
||||||
|
@ -3465,6 +3485,7 @@ void audio_playback_handler(struct queue_event *ev)
|
||||||
}
|
}
|
||||||
/* Fall-through */
|
/* Fall-through */
|
||||||
case STATE_FINISHED:
|
case STATE_FINISHED:
|
||||||
|
case STATE_STOPPED:
|
||||||
/* All data was buffered */
|
/* All data was buffered */
|
||||||
cancel_cpu_boost();
|
cancel_cpu_boost();
|
||||||
/* Fall-through */
|
/* Fall-through */
|
||||||
|
@ -4029,37 +4050,22 @@ static unsigned long audio_guess_frequency(struct mp3entry *id3)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void audio_change_frequency_callback(unsigned short id, void *data)
|
static bool audio_auto_change_frequency(struct mp3entry *id3, bool play)
|
||||||
{
|
{
|
||||||
static bool starting_playback = false;
|
unsigned long guessed_frequency = global_settings.play_frequency == 0 ? audio_guess_frequency(id3) : 0;
|
||||||
struct mp3entry *id3;
|
if (guessed_frequency && mixer_get_frequency() != guessed_frequency)
|
||||||
|
|
||||||
switch (id)
|
|
||||||
{
|
{
|
||||||
case PLAYBACK_EVENT_START_PLAYBACK:
|
if (!play)
|
||||||
starting_playback = true;
|
return true;
|
||||||
break;
|
|
||||||
|
|
||||||
case PLAYBACK_EVENT_TRACK_CHANGE:
|
|
||||||
id3 = ((struct track_event *)data)->id3;
|
|
||||||
if (id3 && !global_settings.play_frequency)
|
|
||||||
{
|
|
||||||
unsigned long guessed_frequency = audio_guess_frequency(id3);
|
|
||||||
if (mixer_get_frequency() != guessed_frequency)
|
|
||||||
{
|
|
||||||
#ifdef PLAYBACK_VOICE
|
#ifdef PLAYBACK_VOICE
|
||||||
voice_stop();
|
voice_stop();
|
||||||
#endif
|
#endif
|
||||||
mixer_set_frequency(guessed_frequency);
|
mixer_set_frequency(guessed_frequency);
|
||||||
audio_queue_post(Q_AUDIO_REMAKE_AUDIO_BUFFER, starting_playback);
|
audio_queue_post(Q_AUDIO_REMAKE_AUDIO_BUFFER, 0);
|
||||||
}
|
return true;
|
||||||
}
|
|
||||||
starting_playback = false;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_set_playback_frequency(unsigned int sample_rate_hz)
|
void audio_set_playback_frequency(unsigned int sample_rate_hz)
|
||||||
|
@ -4124,10 +4130,6 @@ void INIT_ATTR playback_init(void)
|
||||||
track_list_init();
|
track_list_init();
|
||||||
buffering_init();
|
buffering_init();
|
||||||
pcmbuf_update_frequency();
|
pcmbuf_update_frequency();
|
||||||
#ifdef HAVE_PLAY_FREQ
|
|
||||||
add_event(PLAYBACK_EVENT_TRACK_CHANGE, audio_change_frequency_callback);
|
|
||||||
add_event(PLAYBACK_EVENT_START_PLAYBACK, audio_change_frequency_callback);
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_CROSSFADE
|
#ifdef HAVE_CROSSFADE
|
||||||
/* Set crossfade setting for next buffer init which should be about... */
|
/* Set crossfade setting for next buffer init which should be about... */
|
||||||
pcmbuf_request_crossfade_enable(global_settings.crossfade);
|
pcmbuf_request_crossfade_enable(global_settings.crossfade);
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
|
|
||||||
/* Define LOGF_ENABLE to enable logf output in this file */
|
/* Define LOGF_ENABLE to enable logf output in this file */
|
||||||
/*#define LOGF_ENABLE*/
|
//#define LOGF_ENABLE
|
||||||
#include "logf.h"
|
#include "logf.h"
|
||||||
#include "audio.h"
|
#include "audio.h"
|
||||||
#include "sound.h"
|
#include "sound.h"
|
||||||
|
@ -314,7 +314,7 @@ void pcm_play_stop(void)
|
||||||
* what pcm_apply_settings will set */
|
* what pcm_apply_settings will set */
|
||||||
void pcm_set_frequency(unsigned int samplerate)
|
void pcm_set_frequency(unsigned int samplerate)
|
||||||
{
|
{
|
||||||
logf("pcm_set_frequency");
|
logf("pcm_set_frequency %u", samplerate);
|
||||||
|
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue