From 33a62e8a8ebe8039101a2333e71bc2c2de8e5225 Mon Sep 17 00:00:00 2001 From: Brandon Low Date: Wed, 5 Apr 2006 04:27:16 +0000 Subject: [PATCH] More work on swcodec. No significant pcmbuf functions are called from the audio thread now. Do not be surprised if seek or skip behavior gets weird after this, but it Works for Me (TM), and is a significant step in the right direction. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@9510 a1c6a512-1295-4272-9138-f99709370657 --- apps/abrepeat.c | 6 ++--- apps/pcmbuf.c | 13 ----------- apps/playback.c | 52 ++++++++++++++++++++--------------------- firmware/export/audio.h | 1 - firmware/pcm_playback.c | 2 +- 5 files changed, 29 insertions(+), 45 deletions(-) diff --git a/apps/abrepeat.c b/apps/abrepeat.c index b83a7b6aa3..fc1913d37b 100644 --- a/apps/abrepeat.c +++ b/apps/abrepeat.c @@ -111,13 +111,13 @@ reasonable amount of time for the typical user to react */ void ab_jump_to_A_marker(void) { -#if (CONFIG_CODEC == SWCODEC) - audio_seamless_seek(ab_A_marker); -#else +#if (CONFIG_CODEC != SWCODEC) bool paused = (audio_status() & AUDIO_STATUS_PAUSE) != 0; if ( ! paused ) audio_pause(); +#endif audio_ff_rewind(ab_A_marker); +#if (CONFIG_CODEC != SWCODEC) if ( ! paused ) audio_resume(); #endif diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c index c0791987ce..7a261fecbe 100644 --- a/apps/pcmbuf.c +++ b/apps/pcmbuf.c @@ -61,8 +61,6 @@ static bool crossfade_init IDATA_ATTR; static size_t crossfade_pos IDATA_ATTR; static size_t crossfade_rem IDATA_ATTR; -static struct mutex pcmbuf_mutex IDATA_ATTR; - /* Crossfade modes. If CFM_CROSSFADE is selected, normal * crossfader will activate. Selecting CFM_FLUSH is a special * operation that only overwrites the pcm buffer without crossfading. @@ -297,7 +295,6 @@ bool pcmbuf_crossfade_init(bool manual_skip) void pcmbuf_play_stop(void) { - mutex_lock(&pcmbuf_mutex); /** Prevent a very tiny pop from happening by muting audio * until dma has been initialized. */ pcm_mute(true); @@ -320,7 +317,6 @@ void pcmbuf_play_stop(void) pcmbuf_set_boost_mode(false); pcmbuf_boost(false); - mutex_unlock(&pcmbuf_mutex); } int pcmbuf_used_descs(void) { @@ -356,7 +352,6 @@ static void pcmbuf_init_pcmbuffers(void) { * ...CODECBUFFER|---------PCMBUF---------|GUARDBUF|DESCS| */ void pcmbuf_init(size_t bufsize) { - mutex_init(&pcmbuf_mutex); pcmbuf_size = bufsize; pcmbuf_descsize = pcmbuf_descs()*sizeof(struct pcmbufdesc); audiobuffer = (char *)&audiobuf[(audiobufend - audiobuf) - @@ -401,8 +396,6 @@ void pcmbuf_pause(bool pause) { /* Force playback. */ void pcmbuf_play_start(void) { - mutex_lock(&pcmbuf_mutex); - if (!pcm_is_playing() && pcmbuf_unplayed_bytes) { /** Prevent a very tiny pop from happening by muting audio @@ -417,8 +410,6 @@ void pcmbuf_play_start(void) /* Now unmute the audio. */ pcm_mute(false); } - - mutex_unlock(&pcmbuf_mutex); } /** @@ -426,8 +417,6 @@ void pcmbuf_play_start(void) */ static void pcmbuf_flush_fillpos(void) { - mutex_lock(&pcmbuf_mutex); - if (audiobuffer_fillpos) { /* Never use the last buffer descriptor */ while (pcmbuf_write == pcmbuf_write_end) { @@ -444,8 +433,6 @@ static void pcmbuf_flush_fillpos(void) } pcmbuf_add_chunk(); } - - mutex_unlock(&pcmbuf_mutex); } /** diff --git a/apps/playback.c b/apps/playback.c index 9f8fc5a71b..aa48dd9bae 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -70,6 +70,7 @@ static volatile bool audio_codec_loaded; static volatile bool voice_codec_loaded; static volatile bool playing; +static volatile bool seeking; #define CODEC_VORBIS "/.rockbox/codecs/vorbis.codec" #define CODEC_MPA_L3 "/.rockbox/codecs/mpa.codec" @@ -102,7 +103,6 @@ enum { Q_AUDIO_TRACK_CHANGED, Q_AUDIO_DIR_NEXT, Q_AUDIO_DIR_PREV, - Q_AUDIO_SEAMLESS_SEEK, Q_AUDIO_POSTINIT, Q_CODEC_LOAD, @@ -679,7 +679,12 @@ off_t codec_mp3_get_filepos_callback(int newtime) void codec_seek_complete_callback(void) { /* assume we're called from non-voice codec, as they shouldn't seek */ + if (pcm_is_paused()) { + /* If this is not a seamless seek, clear the buffer */ + pcmbuf_play_stop(); + } ci.seek_time = 0; + seeking = false; } bool codec_seek_buffer_callback(size_t newpos) @@ -1329,10 +1334,10 @@ static void audio_clear_track_entries(bool buffered_only) static void stop_codec_flush(void) { ci.stop_codec = true; - pcmbuf_play_stop(); + pcmbuf_pause(true); while (audio_codec_loaded) yield(); - pcmbuf_play_stop(); + pcmbuf_pause(false); } static void audio_stop_playback(bool resume) @@ -1343,7 +1348,6 @@ static void audio_stop_playback(bool resume) playing = false; filling = false; stop_codec_flush(); - pcmbuf_pause(false); if (current_fd >= 0) { close(current_fd); current_fd = -1; @@ -1768,11 +1772,11 @@ static void initiate_track_change(int peek_index) { /* Detect if disk is spinning or already loading. */ if (filling || ci.reload_codec || !audio_codec_loaded) { - if (pcmbuf_is_crossfade_enabled()) + if (pcmbuf_is_crossfade_enabled()) { pcmbuf_crossfade_init(true); - else - pcmbuf_play_stop(); - ci.stop_codec = true; + ci.stop_codec = true; + } else + stop_codec_flush(); queue_post(&audio_queue, Q_AUDIO_PLAY, 0); } else { new_track = peek_index; @@ -1836,10 +1840,6 @@ void audio_thread(void) play_pending = false; last_tick = current_tick; - /* Do not start crossfading if audio is paused. */ - if (pcm_is_paused()) - pcmbuf_play_stop(); - #ifdef CONFIG_TUNER /* check if radio is playing */ if (get_radio_status() != FMRADIO_OFF) { @@ -1848,6 +1848,7 @@ void audio_thread(void) #endif logf("starting..."); + playing = true; ci.stop_codec = true; ci.reload_codec = false; @@ -1896,13 +1897,6 @@ void audio_thread(void) break; case Q_AUDIO_FF_REWIND: - if (!playing) - break ; - pcmbuf_play_stop(); - ci.seek_time = (long)ev.data+1; - break ; - - case Q_AUDIO_SEAMLESS_SEEK: if (!playing) break ; ci.seek_time = (long)ev.data+1; @@ -1911,6 +1905,7 @@ void audio_thread(void) case Q_AUDIO_DIR_NEXT: logf("audio_dir_next"); playlist_end = false; + /* pcmbuf_beep may or may not be safe on audio thread */ if (global_settings.beep) pcmbuf_beep(5000, 100, 2500*global_settings.beep); initiate_dir_change(1); @@ -1919,6 +1914,7 @@ void audio_thread(void) case Q_AUDIO_DIR_PREV: logf("audio_dir_prev"); playlist_end = false; + /* pcmbuf_beep may or may not be safe on audio thread */ if (global_settings.beep) pcmbuf_beep(5000, 100, 2500*global_settings.beep); initiate_dir_change(-1); @@ -2010,6 +2006,9 @@ void codec_thread(void) #endif } + if (ci.stop_codec && pcm_is_paused()) + pcmbuf_play_stop(); + audio_codec_loaded = false; switch (ev.id) { @@ -2191,7 +2190,6 @@ void audio_play(long offset) else { stop_codec_flush(); - pcmbuf_play_stop(); } queue_post(&audio_queue, Q_AUDIO_PLAY, (void *)offset); @@ -2268,14 +2266,14 @@ void audio_prev_dir(void) void audio_ff_rewind(long newpos) { - logf("rewind: %d", newpos); + logf("ff/rewind: %d", newpos); + seeking = true; queue_post(&audio_queue, Q_AUDIO_FF_REWIND, (int *)newpos); -} - -void audio_seamless_seek(long newpos) -{ - logf("seamless_seek: %d", newpos); - queue_post(&audio_queue, Q_AUDIO_SEAMLESS_SEEK, (int *)newpos); + /* This is a hack, the correct solution is to report back to + * the caller when the seek is complete. */ + while (seeking) { + yield(); + } } void audio_flush_and_reload_tracks(void) diff --git a/firmware/export/audio.h b/firmware/export/audio.h index 62dec73078..d1421ce9a3 100644 --- a/firmware/export/audio.h +++ b/firmware/export/audio.h @@ -71,7 +71,6 @@ void audio_next(void); void audio_prev(void); int audio_status(void); void audio_ff_rewind(long newtime); -void audio_seamless_seek(long newtime); void audio_flush_and_reload_tracks(void); struct mp3entry* audio_current_track(void); struct mp3entry* audio_next_track(void); diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c index d6dc41cdde..8210276c48 100644 --- a/firmware/pcm_playback.c +++ b/firmware/pcm_playback.c @@ -638,7 +638,7 @@ void pcm_play_pause(bool play) /* nothing yet */ #endif } - } + } /* pcm_playing && needs_change */ } bool pcm_is_playing(void) {