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) {