Index: apps/codecs.c =================================================================== --- apps/codecs.c (revision 29339) +++ apps/codecs.c (working copy) @@ -97,7 +97,6 @@ NULL, /* seek_buffer */ NULL, /* seek_complete */ NULL, /* request_next_track */ - NULL, /* discard_codec */ NULL, /* set_offset */ NULL, /* configure */ @@ -149,8 +148,6 @@ #endif #ifdef HAVE_RECORDING - false, /* stop_encoder */ - 0, /* enc_codec_loaded */ enc_get_inputs, enc_set_parameters, enc_get_chunk, @@ -178,11 +175,10 @@ CODECS_DIR, codec_root_fn); } -static int codec_load_ram(void *handle, struct codec_api *api) +static void * codec_load_ram(void *handle, struct codec_api *api) { struct codec_header *c_hdr = lc_get_header(handle); struct lc_header *hdr = c_hdr ? &c_hdr->lc_hdr : NULL; - int status; if (hdr == NULL || (hdr->magic != CODEC_MAGIC @@ -199,14 +195,14 @@ { logf("codec header error"); lc_close(handle); - return CODEC_ERROR; + return NULL; } if (hdr->api_version > CODEC_API_VERSION || hdr->api_version < CODEC_MIN_API_VERSION) { logf("codec api version error"); lc_close(handle); - return CODEC_ERROR; + return NULL; } #if (CONFIG_PLATFORM & PLATFORM_NATIVE) @@ -216,34 +212,31 @@ #endif *(c_hdr->api) = api; - status = c_hdr->entry_point(); - lc_close(handle); - - return status; + return handle; } -int codec_load_buf(unsigned int hid, struct codec_api *api) +void * codec_load_buf(int hid, struct codec_api *api) { int rc; void *handle; rc = bufread(hid, CODEC_SIZE, codecbuf); if (rc < 0) { - logf("error loading codec"); - return CODEC_ERROR; + logf("Codec: cannot read buf handle"); + return NULL; } + handle = lc_open_from_mem(codecbuf, rc); - if (handle == NULL) - { + + if (handle == NULL) { logf("error loading codec"); - return CODEC_ERROR; + return NULL; } - api->discard_codec(); return codec_load_ram(handle, api); } -int codec_load_file(const char *plugin, struct codec_api *api) +void * codec_load_file(const char *plugin, struct codec_api *api) { char path[MAX_PATH]; void *handle; @@ -253,10 +246,30 @@ handle = lc_open(path, codecbuf, CODEC_SIZE); if (handle == NULL) { - logf("Codec load error"); - splashf(HZ*2, "Couldn't load codec: %s", path); - return CODEC_ERROR; + logf("Codec: cannot read file"); + return NULL; } return codec_load_ram(handle, api); } + +int codec_begin(void *handle) +{ + int status = CODEC_ERROR; + struct codec_header *c_hdr; + + c_hdr = lc_get_header(handle); + + if (c_hdr != NULL) { + logf("Codec: calling entry_point"); + status = c_hdr->entry_point(); + } + + return status; +} + +void codec_close(void *handle) +{ + if (handle) + lc_close(handle); +} Index: apps/codecs.h =================================================================== --- apps/codecs.h (revision 29339) +++ apps/codecs.h (working copy) @@ -75,17 +75,16 @@ #define CODEC_ENC_MAGIC 0x52454E43 /* RENC */ /* increase this every time the api struct changes */ -#define CODEC_API_VERSION 35 +#define CODEC_API_VERSION 36 /* update this to latest version if a change to the api struct breaks backwards compatibility (and please take the opportunity to sort in any new function which are "waiting" at the end of the function table) */ -#define CODEC_MIN_API_VERSION 35 +#define CODEC_MIN_API_VERSION 36 /* codec return codes */ enum codec_status { CODEC_OK = 0, - CODEC_USB_CONNECTED, CODEC_ERROR = -1, }; @@ -106,13 +105,13 @@ /* Codec should periodically check if stop_codec is set to true. In case it is, codec must return immediately */ - bool stop_codec; + volatile bool stop_codec; /* Codec should periodically check if new_track is non zero. When it is, the codec should request a new track. */ - int new_track; + volatile int new_track; /* If seek_time != 0, codec should seek to that song position (in ms) if codec supports seeking. */ - long seek_time; + volatile long seek_time; /* The dsp instance to be used for audio output */ struct dsp_config *dsp; @@ -145,8 +144,6 @@ track is available and changed. If return value is false, codec should exit immediately with PLUGIN_OK status. */ bool (*request_next_track)(void); - /* Free the buffer area of the current codec after its loaded */ - void (*discard_codec)(void); void (*set_offset)(size_t value); /* Configure different codec buffer parameters. */ @@ -210,8 +207,6 @@ #endif #ifdef HAVE_RECORDING - volatile bool stop_encoder; - volatile int enc_codec_loaded; /* <0=error, 0=pending, >0=ok */ void (*enc_get_inputs)(struct enc_inputs *inputs); void (*enc_set_parameters)(struct enc_parameters *params); struct enc_chunk_hdr * (*enc_get_chunk)(void); @@ -283,8 +278,10 @@ void codec_get_full_path(char *path, const char *codec_root_fn); /* defined by the codec loader (codec.c) */ -int codec_load_buf(unsigned int hid, struct codec_api *api); -int codec_load_file(const char* codec, struct codec_api *api); +void * codec_load_buf(int hid, struct codec_api *api); +void * codec_load_file(const char* codec, struct codec_api *api); +int codec_begin(void *handle); +void codec_close(void *handle); /* defined by the codec */ enum codec_status codec_start(void); Index: apps/pcmbuf.c =================================================================== --- apps/pcmbuf.c (revision 29339) +++ apps/pcmbuf.c (working copy) @@ -26,6 +26,7 @@ #include "pcmbuf.h" #include "pcm.h" #include "playback.h" +#include "codec_thread.h" /* Define LOGF_ENABLE to enable logf output in this file */ /*#define LOGF_ENABLE*/ @@ -131,8 +132,6 @@ static int codec_thread_priority = PRIORITY_PLAYBACK; #endif -extern unsigned int codec_thread_id; - /* Helpful macros for use in conditionals this assumes some of the above * static variable names */ #define COMMIT_IF_NEEDED if(pcmbuffer_fillpos > PCMBUF_TARGET_CHUNK || \ @@ -297,7 +296,7 @@ * will starve if the codec thread's priority is boosted. */ if (new_prio != codec_thread_priority) { - thread_set_priority(codec_thread_id, new_prio); + codec_thread_set_priority(new_prio); voice_thread_set_priority(new_prio); codec_thread_priority = new_prio; } @@ -327,7 +326,7 @@ /* Only codec thread initiates boost - voice boosts the cpu when playing a clip */ #ifndef SIMULATOR - if (thread_get_current() == codec_thread_id) + if (is_codec_thread()) #endif /* SIMULATOR */ { /* boost cpu if necessary */ @@ -487,7 +486,25 @@ /** Track change */ +void pcmbuf_monitor_track_change(bool check_finished) +{ + pcm_play_lock(); + if (check_finished && !pcm_is_playing()) + { + /* Post now if PCM stopped */ + audio_post_track_change(false); + } + else + { + /* Wait until this track runs out */ + track_transition = true; + end_of_track = true; + } + + pcm_play_unlock(); +} + void pcmbuf_start_track_change(bool auto_skip) { bool crossfade = false; @@ -563,8 +580,7 @@ * current track will be updated properly, and mark the current chunk * as the last one in the track. */ logf(" gapless track change"); - track_transition = true; - end_of_track = true; + pcmbuf_monitor_track_change(false); } } Index: apps/pcmbuf.h =================================================================== --- apps/pcmbuf.h (revision 29339) +++ apps/pcmbuf.h (working copy) @@ -32,6 +32,7 @@ void pcmbuf_play_start(void); void pcmbuf_play_stop(void); void pcmbuf_pause(bool pause); +void pcmbuf_monitor_track_change(bool check_finished); void pcmbuf_start_track_change(bool manual_skip); /* Crossfade */ Index: apps/recorder/pcm_record.c =================================================================== --- apps/recorder/pcm_record.c (revision 29339) +++ apps/recorder/pcm_record.c (working copy) @@ -31,6 +31,7 @@ #include "usb.h" #include "buffer.h" #include "general.h" +#include "codec_thread.h" #include "audio.h" #include "sound.h" #include "metadata.h" @@ -41,8 +42,6 @@ /***************************************************************************/ -extern unsigned int codec_thread_id; - /** General recording state **/ static bool is_recording; /* We are recording */ static bool is_paused; /* We have paused */ @@ -900,8 +899,8 @@ num >= flood_watermark ? "num" : "time"); prio_pcmrec = thread_set_priority(THREAD_ID_CURRENT, thread_get_priority(THREAD_ID_CURRENT) - 4); - prio_codec = thread_set_priority(codec_thread_id, - thread_get_priority(codec_thread_id) - 4); + prio_codec = codec_thread_set_priority( + codec_thread_get_priority() - 4); } #endif @@ -952,7 +951,7 @@ /* return to original priorities */ logf("pcmrec: unboost priority"); thread_set_priority(THREAD_ID_CURRENT, prio_pcmrec); - thread_set_priority(codec_thread_id, prio_codec); + codec_thread_set_priority(prio_codec); } last_flush_tick = current_tick; /* save tick when we left */ Index: apps/plugins/test_codec.c =================================================================== --- apps/plugins/test_codec.c (revision 29339) +++ apps/plugins/test_codec.c (working copy) @@ -516,13 +516,6 @@ } -/* Free the buffer area of the current codec after its loaded */ -static void discard_codec(void) -{ - /* ??? */ -} - - static void set_offset(size_t value) { /* ??? */ @@ -576,7 +569,6 @@ ci.seek_buffer = seek_buffer; ci.seek_complete = seek_complete; ci.request_next_track = request_next_track; - ci.discard_codec = discard_codec; ci.set_offset = set_offset; ci.configure = configure; ci.dsp = (struct dsp_config *)rb->dsp_configure(NULL, DSP_MYDSP, @@ -636,13 +628,20 @@ static void codec_thread(void) { const char* codecname; - int res; + void *handle; + int res = CODEC_ERROR; codecname = rb->get_codec_filename(track.id3.codectype); /* Load the codec and start decoding. */ - res = rb->codec_load_file(codecname,&ci); + handle = rb->codec_load_file(codecname,&ci); + if (handle != NULL) + { + res = rb->codec_begin(handle); + rb->codec_close(handle); + } + /* Signal to the main thread that we are done */ endtick = *rb->current_tick - rebuffertick; codec_playing = false; Index: apps/codec_thread.c =================================================================== --- apps/codec_thread.c (revision 29339) +++ apps/codec_thread.c (working copy) @@ -67,36 +67,52 @@ */ /* Main state control */ -volatile bool audio_codec_loaded SHAREDBSS_ATTR = false; /* Codec loaded? (C/A-) */ +/* Codes when acking audio thread in proper context */ +enum codec_queue_ack_resp +{ + CODEC_ACK_NULL = 0, /* NULL ack = default reply */ + CODEC_ACK_LOAD_DISK, + CODEC_ACK_LOAD, + CODEC_ACK_AUDIO_SEEK_COMPLETE, + CODEC_ACK_CHECK_NEW_TRACK, + CODEC_ACK_DO_CALLBACK, +#ifdef AUDIO_HAVE_RECORDING + CODEC_ACK_LOAD_ENCODER, +#endif +}; + +/* Type of codec loaded? (C/A) */ +static int current_codectype SHAREDBSS_ATTR = AFMT_UNKNOWN; + extern struct mp3entry *thistrack_id3, /* the currently playing track */ *othertrack_id3; /* prev track during track-change-transition, or end of playlist, * next track otherwise */ /* Track change controls */ -extern bool automatic_skip; /* Who initiated in-progress skip? (C/A-) */ - -/* Set to true if the codec thread should send an audio stop request - * (typically because the end of the playlist has been reached). - */ -static bool codec_requested_stop = false; - extern struct event_queue audio_queue SHAREDBSS_ATTR; -extern struct event_queue codec_queue SHAREDBSS_ATTR; + extern struct codec_api ci; /* from codecs.c */ /* Codec thread */ -unsigned int codec_thread_id; /* For modifying thread priority later. - Used by playback.c and pcmbuf.c */ +static unsigned int codec_thread_id; /* For modifying thread priority later */ +static struct event_queue codec_queue SHAREDBSS_ATTR; static struct queue_sender_list codec_queue_sender_list SHAREDBSS_ATTR; static long codec_stack[(DEFAULT_STACK_SIZE + 0x2000)/sizeof(long)] -IBSS_ATTR; + IBSS_ATTR; static const char codec_thread_name[] = "codec"; -/* function prototypes */ -static bool codec_load_next_track(void); +/* static routines */ +static void codec_queue_ack(enum codec_queue_ack_resp ackme) +{ + queue_reply(&codec_queue, ackme); +} +static intptr_t codec_queue_send(long id, intptr_t data) +{ + return queue_send(&codec_queue, id, data); +} /**************************************/ @@ -183,7 +199,7 @@ /* Codec thread will signal just before entering callback */ LOGFQUEUE("codec >| Q_CODEC_DO_CALLBACK"); - queue_send(&codec_queue, Q_CODEC_DO_CALLBACK, (intptr_t)fn); + codec_queue_send(Q_CODEC_DO_CALLBACK, (intptr_t)fn); } @@ -215,7 +231,7 @@ while ((dest = pcmbuf_request_buffer(&out_count)) == NULL) { cancel_cpu_boost(); - sleep(1); + sleep(0); if (ci.seek_time || ci.new_track || ci.stop_codec) return; } @@ -289,7 +305,7 @@ { ssize_t copy_n; - if (ci.stop_codec || !(audio_status() & AUDIO_STATUS_PLAY)) + if (ci.stop_codec) return 0; copy_n = bufread(get_audio_hid(), size, ptr); @@ -311,24 +327,16 @@ ssize_t ret; void *ptr; - if (!(audio_status() & AUDIO_STATUS_PLAY)) - { - *realsize = 0; - return NULL; - } - ret = bufgetdata(get_audio_hid(), reqsize, &ptr); if (ret >= 0) copy_n = MIN((size_t)ret, reqsize); + else + copy_n = 0; if (copy_n == 0) - { - *realsize = 0; - return NULL; - } + ptr = NULL; *realsize = copy_n; - return ptr; } /* codec_request_buffer_callback */ @@ -360,61 +368,71 @@ static void codec_seek_complete_callback(void) { + struct queue_event ev; + logf("seek_complete"); - /* If seeking-while-playing, pcm_is_paused() is true. - * If seeking-while-paused, audio_status PAUSE is true. - * A seamless seek skips this section. */ - bool audio_paused = audio_status() & AUDIO_STATUS_PAUSE; - if (pcm_is_paused() || audio_paused) - { - /* Clear the buffer */ - pcmbuf_play_stop(); - dsp_configure(ci.dsp, DSP_FLUSH, 0); - /* If seeking-while-playing, resume pcm playback */ - if (!audio_paused) - pcmbuf_pause(false); - } - ci.seek_time = 0; -} + /* Clear DSP */ + dsp_configure(ci.dsp, DSP_FLUSH, 0); -static void codec_discard_codec_callback(void) -{ - int *codec_hid = get_codec_hid(); - if (*codec_hid >= 0) - { - bufclose(*codec_hid); - *codec_hid = -1; - } + /* Post notification to audio thread */ + LOGFQUEUE("audio >| Q_AUDIO_SEEK_COMPLETE"); + queue_post(&audio_queue, Q_AUDIO_SEEK_COMPLETE, 0); + + /* Wait for ACK */ + queue_wait(&codec_queue, &ev); + + /* ACK back in context */ + codec_queue_ack(CODEC_ACK_AUDIO_SEEK_COMPLETE); } static bool codec_request_next_track_callback(void) { - int prev_codectype; + struct queue_event ev; - if (ci.stop_codec || !(audio_status() & AUDIO_STATUS_PLAY)) - return false; + logf("Request new track"); - prev_codectype = get_codec_base_type(thistrack_id3->codectype); - if (!codec_load_next_track()) + audio_set_prev_elapsed(thistrack_id3->elapsed); + +#ifdef AB_REPEAT_ENABLE + ab_end_of_track_report(); +#endif + + if (ci.stop_codec) + { + /* Handle ACK in outer loop */ + LOGFQUEUE("codec: already stopping"); return false; + } - /* Seek to the beginning of the new track because if the struct - mp3entry was buffered, "elapsed" might not be zero (if the track has - been played already but not unbuffered) */ - codec_seek_buffer_callback(thistrack_id3->first_frame_offset); - /* Check if the next codec is the same file. */ - if (prev_codectype == get_codec_base_type(thistrack_id3->codectype)) + trigger_cpu_boost(); + + /* Post request to audio thread */ + LOGFQUEUE("codec > audio Q_AUDIO_CHECK_NEW_TRACK"); + queue_post(&audio_queue, Q_AUDIO_CHECK_NEW_TRACK, 0); + + /* Wait for ACK */ + queue_wait(&codec_queue, &ev); + + if (ev.data == Q_CODEC_REQUEST_COMPLETE) { - logf("New track loaded"); - codec_discard_codec_callback(); - return true; + /* Seek to the beginning of the new track because if the struct + mp3entry was buffered, "elapsed" might not be zero (if the track has + been played already but not unbuffered) */ + codec_seek_buffer_callback(thistrack_id3->first_frame_offset); } - else + + /* ACK back in context */ + codec_queue_ack(CODEC_ACK_CHECK_NEW_TRACK); + + if (ev.data != Q_CODEC_REQUEST_COMPLETE) { - logf("New codec:%d/%d", thistrack_id3->codectype, prev_codectype); + LOGFQUEUE("codec <= request failed (%d)", ev.data); return false; } + + LOGFQUEUE("codec <= Q_CODEC_REQEST_COMPLETE"); + return true; } static void codec_configure_callback(int setting, intptr_t value) @@ -438,7 +456,6 @@ ci.seek_buffer = codec_seek_buffer_callback; ci.seek_complete = codec_seek_complete_callback; ci.request_next_track = codec_request_next_track_callback; - ci.discard_codec = codec_discard_codec_callback; ci.set_offset = codec_set_offset_callback; ci.configure = codec_configure_callback; } @@ -446,61 +463,16 @@ /* track change */ -static bool codec_load_next_track(void) -{ - intptr_t result = Q_CODEC_REQUEST_FAILED; - - audio_set_prev_elapsed(thistrack_id3->elapsed); - -#ifdef AB_REPEAT_ENABLE - ab_end_of_track_report(); -#endif - - logf("Request new track"); - - if (ci.new_track == 0) - { - ci.new_track++; - automatic_skip = true; - } - - if (!ci.stop_codec) - { - trigger_cpu_boost(); - LOGFQUEUE("codec >| audio Q_AUDIO_CHECK_NEW_TRACK"); - result = queue_send(&audio_queue, Q_AUDIO_CHECK_NEW_TRACK, 0); - } - - switch (result) - { - case Q_CODEC_REQUEST_COMPLETE: - LOGFQUEUE("codec |< Q_CODEC_REQUEST_COMPLETE"); - pcmbuf_start_track_change(automatic_skip); - return true; - - case Q_CODEC_REQUEST_FAILED: - LOGFQUEUE("codec |< Q_CODEC_REQUEST_FAILED"); - ci.new_track = 0; - ci.stop_codec = true; - codec_requested_stop = true; - return false; - - default: - LOGFQUEUE("codec |< default"); - ci.stop_codec = true; - codec_requested_stop = true; - return false; - } -} - /** CODEC THREAD */ static void codec_thread(void) { struct queue_event ev; - int status; - while (1) { - status = 0; + while (1) + { + int status = CODEC_OK; + void *handle = NULL; + int hid = -1; #ifdef HAVE_CROSSFADE if (!pcmbuf_is_crossfade_active()) @@ -508,171 +480,82 @@ { cancel_cpu_boost(); } - + queue_wait(&codec_queue, &ev); - codec_requested_stop = false; - switch (ev.id) { + switch (ev.id) + { case Q_CODEC_LOAD_DISK: LOGFQUEUE("codec < Q_CODEC_LOAD_DISK"); - queue_reply(&codec_queue, 1); - audio_codec_loaded = true; - ci.stop_codec = false; - status = codec_load_file((const char *)ev.data, &ci); - LOGFQUEUE("codec_load_file %s %d\n", (const char *)ev.data, status); + codec_queue_ack(CODEC_ACK_LOAD_DISK); + handle = codec_load_file((const char *)ev.data, &ci); break; case Q_CODEC_LOAD: LOGFQUEUE("codec < Q_CODEC_LOAD"); - if (*get_codec_hid() < 0) { - logf("Codec slot is empty!"); - /* Wait for the pcm buffer to go empty */ - while (pcm_is_playing()) - yield(); - /* This must be set to prevent an infinite loop */ - ci.stop_codec = true; - LOGFQUEUE("codec > codec Q_AUDIO_PLAY"); - queue_post(&codec_queue, Q_AUDIO_PLAY, 0); - break; - } - - audio_codec_loaded = true; - ci.stop_codec = false; - status = codec_load_buf(*get_codec_hid(), &ci); - LOGFQUEUE("codec_load_buf %d\n", status); + hid = (int)ev.data; + codec_queue_ack(CODEC_ACK_LOAD); + handle = codec_load_buf(hid, &ci); + bufclose(hid); break; case Q_CODEC_DO_CALLBACK: LOGFQUEUE("codec < Q_CODEC_DO_CALLBACK"); - queue_reply(&codec_queue, 1); + codec_queue_ack(CODEC_ACK_DO_CALLBACK); if ((void*)ev.data != NULL) { - cpucache_invalidate(); + cpucache_commit_discard(); ((void (*)(void))ev.data)(); - cpucache_flush(); + cpucache_commit(); } break; #ifdef AUDIO_HAVE_RECORDING case Q_ENCODER_LOAD_DISK: LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK"); - audio_codec_loaded = false; /* Not audio codec! */ - logf("loading encoder"); - ci.stop_encoder = false; - status = codec_load_file((const char *)ev.data, &ci); - logf("encoder stopped"); + handle = codec_load_file((const char *)ev.data, &ci); + codec_queue_ack(handle ? CODEC_ACK_LOAD_ENCODER : CODEC_ACK_NULL); break; #endif /* AUDIO_HAVE_RECORDING */ default: - LOGFQUEUE("codec < default"); + LOGFQUEUE("codec < default : %ld", ev.id); } - if (audio_codec_loaded) + if (handle) { + /* Codec loaded - call the entrypoint */ + yield(); + logf("codec running"); + status = codec_begin(handle); + logf("codec stopped"); + codec_close(handle); + current_codectype = AFMT_UNKNOWN; + if (ci.stop_codec) - { status = CODEC_OK; - if (!(audio_status() & AUDIO_STATUS_PLAY)) - pcmbuf_play_stop(); - - } - audio_codec_loaded = false; } - switch (ev.id) { + switch (ev.id) + { case Q_CODEC_LOAD_DISK: case Q_CODEC_LOAD: - LOGFQUEUE("codec < Q_CODEC_LOAD"); - if (audio_status() & AUDIO_STATUS_PLAY) - { - if (ci.new_track || status != CODEC_OK) - { - if (!ci.new_track) - { - logf("Codec failure, %d %d", ci.new_track, status); - splash(HZ*2, "Codec failure"); - } - - if (!codec_load_next_track()) - { - LOGFQUEUE("codec > audio Q_AUDIO_STOP"); - /* End of playlist */ - queue_post(&audio_queue, Q_AUDIO_STOP, 0); - break; - } - } - else - { - logf("Codec finished"); - if (ci.stop_codec) - { - /* Wait for the audio to stop playing before - * triggering the WPS exit */ - while(pcm_is_playing()) - { - /* There has been one too many struct pointer swaps by now - * so even though it says othertrack_id3, its the correct one! */ - othertrack_id3->elapsed = - othertrack_id3->length - pcmbuf_get_latency(); - sleep(1); - } - - if (codec_requested_stop) - { - LOGFQUEUE("codec > audio Q_AUDIO_STOP"); - queue_post(&audio_queue, Q_AUDIO_STOP, 0); - } - break; - } - } - - if (*get_codec_hid() >= 0) - { - LOGFQUEUE("codec > codec Q_CODEC_LOAD"); - queue_post(&codec_queue, Q_CODEC_LOAD, 0); - } - else - { - const char *codec_fn = - get_codec_filename(thistrack_id3->codectype); - if (codec_fn) - { - LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK"); - queue_post(&codec_queue, Q_CODEC_LOAD_DISK, - (intptr_t)codec_fn); - } - } - } - break; - #ifdef AUDIO_HAVE_RECORDING case Q_ENCODER_LOAD_DISK: - LOGFQUEUE("codec < Q_ENCODER_LOAD_DISK"); - - if (status == CODEC_OK) - break; - - logf("Encoder failure"); - splash(HZ*2, "Encoder failure"); - - if (ci.enc_codec_loaded < 0) - break; - - logf("Encoder failed to load"); - ci.enc_codec_loaded = -1; +#endif + /* Notify about the status */ + if (!handle) + status = CODEC_ERROR; + LOGFQUEUE("codec > audio notify status: %d", status); + queue_post(&audio_queue, ev.id, status); break; -#endif /* AUDIO_HAVE_RECORDING */ - - default: - LOGFQUEUE("codec < default"); - - } /* end switch */ + } } } void make_codec_thread(void) { + queue_init(&codec_queue, false); codec_thread_id = create_thread( codec_thread, codec_stack, sizeof(codec_stack), CREATE_THREAD_FROZEN, @@ -681,3 +564,97 @@ queue_enable_queue_send(&codec_queue, &codec_queue_sender_list, codec_thread_id); } + +void codec_thread_resume(void) +{ + thread_thaw(codec_thread_id); +} + +bool is_codec_thread(void) +{ + return thread_get_current() == codec_thread_id; +} + +#ifdef HAVE_PRIORITY_SCHEDULING +int codec_thread_get_priority(void) +{ + return thread_get_priority(codec_thread_id); +} + +int codec_thread_set_priority(int priority) +{ + return thread_set_priority(codec_thread_id, priority); +} +#endif /* HAVE_PRIORITY_SCHEDULING */ + +/* functions for audio thread use */ +intptr_t codec_ack_msg(intptr_t data) +{ + LOGFQUEUE("codec >| Q_CODEC_ACK: %d", data); + intptr_t resp = codec_queue_send(Q_CODEC_ACK, data); + LOGFQUEUE(" ack: %ld", resp); + return resp; +} + +bool codec_load(int hid, int cod_spec) +{ + bool retval = false; + + ci.stop_codec = false; + current_codectype = cod_spec; + + if (hid >= 0) + { + LOGFQUEUE("audio >| codec Q_CODEC_LOAD"); + retval = codec_queue_send(Q_CODEC_LOAD, hid) != 0; + } + else + { + const char *codec_fn = get_codec_filename(cod_spec); + + if (codec_fn) + { + LOGFQUEUE("audio >| codec Q_CODEC_LOAD_DISK"); + retval = codec_queue_send(Q_CODEC_LOAD_DISK, (intptr_t)codec_fn) != 0; + } + } + + if (!retval) + current_codectype = AFMT_UNKNOWN; + + return retval; +} + +void codec_stop(void) +{ + ci.stop_codec = true; + /* Wait until it's in the main loop */ + while (codec_ack_msg(0) != CODEC_ACK_NULL); + current_codectype = AFMT_UNKNOWN; +} + +int codec_loaded(void) +{ + return current_codectype; +} + +#ifdef AUDIO_HAVE_RECORDING +bool codec_load_encoder(int enc_spec) +{ + bool retval = false; + const char *enc_fn = get_codec_filename(enc_spec | CODEC_TYPE_ENCODER); + + if (enc_fn) + { + ci.stop_codec = false; + current_codectype = enc_spec; + LOGFQUEUE("audio >| codec Q_ENCODER_LOAD_DISK"); + retval = codec_queue_send(Q_ENCODER_LOAD_DISK, (intptr_t)enc_fn) != 0; + } + + if (!retval) + current_codectype = AFMT_UNKNOWN; + + return retval; +} +#endif /* AUDIO_HAVE_RECORDING */ Index: apps/codec_thread.h =================================================================== --- apps/codec_thread.h (revision 29339) +++ apps/codec_thread.h (working copy) @@ -24,11 +24,30 @@ #include +/* codec identity */ int get_codec_base_type(int type); const char *get_codec_filename(int cod_spec); + +/* codec thread */ void codec_thread_do_callback(void (*fn)(void), unsigned int *codec_thread_id); void codec_init_codec_api(void); void make_codec_thread(void); +void codec_thread_resume(void); +bool is_codec_thread(void); +#ifdef HAVE_PRIORITY_SCHEDULING +int codec_thread_get_priority(void); +int codec_thread_set_priority(int priority); +#endif +/* codec commands - on audio thread only! */ +intptr_t codec_ack_msg(intptr_t data); +bool codec_load(int hid, int cod_spec); +void codec_stop(void); +int codec_loaded(void); +#ifdef AUDIO_HAVE_RECORDING +bool codec_load_encoder(int enc_spec); #endif +/* */ + +#endif /* _CODEC_THREAD_H */ Index: apps/playback.c =================================================================== --- apps/playback.c (revision 29339) +++ apps/playback.c (working copy) @@ -92,6 +92,7 @@ STATE_FULL, /* can't add any more tracks */ STATE_END_OF_PLAYLIST, /* all remaining tracks have been added */ STATE_FINISHED, /* all remaining tracks are fully buffered */ + STATE_ENDING, /* audio playback is ending */ } filling; /* As defined in plugins/lib/xxx2wav.h */ @@ -108,7 +109,6 @@ /* Main state control */ static volatile bool playing SHAREDBSS_ATTR = false;/* Is audio playing? (A) */ static volatile bool paused SHAREDBSS_ATTR = false; /* Is audio paused? (A/C-) */ -extern volatile bool audio_codec_loaded; /* Codec loaded? (C/A-) */ /* Ring buffer where compressed audio and codecs are loaded */ static unsigned char *filebuf = NULL; /* Start of buffer (A/C-) */ @@ -186,7 +186,7 @@ static unsigned long prev_track_elapsed = 0; /* Previous track elapsed time (C/A-)*/ /* Track change controls */ -bool automatic_skip = false; /* Who initiated in-progress skip? (C/A-) */ +static bool automatic_skip = false; /* Who initiated in-progress skip? (A) */ extern bool track_transition; /* Are we in a track transition? */ static bool dir_skip = false; /* Is a directory skip pending? (A) */ static bool new_playlist = false; /* Are we starting a new playlist? (A) */ @@ -208,7 +208,6 @@ /* Event queues */ struct event_queue audio_queue SHAREDBSS_ATTR; -struct event_queue codec_queue SHAREDBSS_ATTR; static struct event_queue pcmbuf_queue SHAREDBSS_ATTR; extern struct codec_api ci; @@ -483,22 +482,8 @@ bool audio_load_encoder(int afmt) { #if (CONFIG_PLATFORM & PLATFORM_NATIVE) - const char *enc_fn = get_codec_filename(afmt | CODEC_TYPE_ENCODER); - if (!enc_fn) - return false; - - audio_remove_encoder(); - ci.enc_codec_loaded = 0; /* clear any previous error condition */ - - LOGFQUEUE("codec > Q_ENCODER_LOAD_DISK"); - queue_post(&codec_queue, Q_ENCODER_LOAD_DISK, (intptr_t)enc_fn); - - while (ci.enc_codec_loaded == 0) - yield(); - - logf("codec loaded: %d", ci.enc_codec_loaded); - - return ci.enc_codec_loaded > 0; + LOGFQUEUE("audio >| Q_AUDIO_LOAD_ENCODER: %d", afmt); + return queue_send(&audio_queue, Q_AUDIO_LOAD_ENCODER, afmt) > 0; #else (void)afmt; return true; @@ -508,13 +493,8 @@ void audio_remove_encoder(void) { #if (CONFIG_PLATFORM & PLATFORM_NATIVE) - /* force encoder codec unload (if currently loaded) */ - if (ci.enc_codec_loaded <= 0) - return; - - ci.stop_encoder = true; - while (ci.enc_codec_loaded > 0) - yield(); + LOGFQUEUE("audio >| Q_AUDIO_LOAD_ENCODER: NULL"); + queue_send(&audio_queue, Q_AUDIO_LOAD_ENCODER, AFMT_UNKNOWN); #endif } /* audio_remove_encoder */ @@ -833,6 +813,11 @@ return ret; } +bool audio_automatic_skip(void) +{ + return automatic_skip; +} + int audio_get_file_pos(void) { return 0; @@ -952,7 +937,7 @@ int next_idx = (track_ridx + offset + 1) & MAX_TRACK_MASK; /* The metadata handle for the last loaded track has been buffered. We can ask the audio thread to load the rest of the track's data. */ - LOGFQUEUE("audio >| audio Q_AUDIO_FINISH_LOAD"); + LOGFQUEUE("audio > audio Q_AUDIO_FINISH_LOAD"); queue_post(&audio_queue, Q_AUDIO_FINISH_LOAD, 0); if (tracks[next_idx].id3_hid == hid) send_event(PLAYBACK_EVENT_NEXTTRACKID3_AVAILABLE, NULL); @@ -1101,9 +1086,7 @@ ci.id3 = thistrack_id3; ci.taginfo_ready = &CUR_TI->taginfo_ready; ci.curpos = 0; - LOGFQUEUE("codec > codec Q_CODEC_LOAD_DISK"); - queue_post(&codec_queue, Q_CODEC_LOAD_DISK, (intptr_t)codec_fn); - return true; + return codec_load(-1, id3->codectype); } else { @@ -1120,7 +1103,7 @@ if (id3 && prev_id3 && get_codec_base_type(id3->codectype) == get_codec_base_type(prev_id3->codectype) - && audio_codec_loaded) + && (unsigned)codec_loaded() == id3->codectype) { logf("Reusing prev. codec"); return true; @@ -1138,7 +1121,7 @@ if (hid < 0 && hid != ERR_UNSUPPORTED_TYPE) return false; - if (hid > 0) + if (hid >= 0) logf("Loaded codec"); else logf("Buffering codec unsupported, load later from disk"); @@ -1562,22 +1545,51 @@ /* Called on request from the codec to get a new track. This is the codec part of the track transition. */ -static int audio_check_new_track(void) +static void audio_last_track(bool automatic_skip) { - int track_count = audio_track_count(); - int old_track_ridx = track_ridx; + if (automatic_skip) + { + if (filling != STATE_ENDING) + { + /* Monitor remaining PCM before stopping */ + filling = STATE_ENDING; + pcmbuf_monitor_track_change(true); + } + + codec_stop(); + } + else + { + audio_stop_playback(); + } +} + +static void audio_check_new_track(void) +{ + int track_count; + int old_track_ridx; int i, idx; bool forward; - struct mp3entry *temp = thistrack_id3; + struct mp3entry *temp; + if (ci.new_track == 0) + { + ci.new_track++; + automatic_skip = true; + } + + track_count = audio_track_count(); + old_track_ridx = track_ridx; + /* Now it's good time to send track finish events. */ send_event(PLAYBACK_EVENT_TRACK_FINISH, thistrack_id3); /* swap the mp3entry pointers */ + temp = thistrack_id3; thistrack_id3 = othertrack_id3; othertrack_id3 = temp; ci.id3 = thistrack_id3; memset(thistrack_id3, 0, sizeof(struct mp3entry)); - + if (dir_skip) { dir_skip = false; @@ -1600,8 +1612,9 @@ { if (ci.new_track >= 0) { - LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED"); - return Q_CODEC_REQUEST_FAILED; + ci.new_track = 0; + audio_last_track(true); + return; } ci.new_track++; } @@ -1612,8 +1625,10 @@ if (playlist_next(ci.new_track) < 0) { - LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_FAILED"); - return Q_CODEC_REQUEST_FAILED; + /* End of list */ + ci.new_track = 0; + audio_last_track(automatic_skip); + return; } if (new_playlist) @@ -1646,7 +1661,6 @@ track_ridx = (track_ridx + ci.new_track) & MAX_TRACK_MASK; buf_set_base_handle(CUR_TI->audio_hid); - if (automatic_skip) { wps_offset = -ci.new_track; @@ -1707,8 +1721,23 @@ skip_done: audio_update_trackinfo(); - LOGFQUEUE("audio >|= codec Q_CODEC_REQUEST_COMPLETE"); - return Q_CODEC_REQUEST_COMPLETE; + pcmbuf_start_track_change(automatic_skip); + + if (get_codec_base_type(codec_loaded()) == + get_codec_base_type(thistrack_id3->codectype)) + { + /* codec is the same base type */ + logf("New track loaded"); + codec_ack_msg(Q_CODEC_REQUEST_COMPLETE); + } + else + { + /* a codec change is required */ + logf("New codec: %d/%d", thistrack_id3->codectype, codec_loaded()); + codec_stop(); + codec_load(tracks[track_ridx].codec_hid, thistrack_id3->codectype); + tracks[track_ridx].codec_hid = -1; /* Codec thread will close it */ + } } unsigned long audio_prev_elapsed(void) @@ -1721,25 +1750,26 @@ prev_track_elapsed = setting; } +/* Stop the codec and reset the PCM buffer */ static void audio_stop_codec_flush(void) { - ci.stop_codec = true; + bool pcm_playing; + pcmbuf_pause(true); - while (audio_codec_loaded) - yield(); + codec_stop(); - /* If the audio codec is not loaded any more, and the audio is still - * playing, it is now and _only_ now safe to call this function from the - * audio thread */ - if (pcm_is_playing()) - { - pcmbuf_play_stop(); - pcm_play_lock(); - queue_clear(&pcmbuf_queue); - pcm_play_unlock(); - } - pcmbuf_pause(paused); + pcm_play_lock(); + + pcm_playing = pcm_is_playing(); + + pcmbuf_play_stop(); + queue_clear(&pcmbuf_queue); + + if (pcm_playing) + pcmbuf_pause(paused); + + pcm_play_unlock(); } static void audio_stop_playback(void) @@ -1750,12 +1780,7 @@ struct mp3entry *id3 = NULL; if (!ci.stop_codec) - { - /* Set this early, the outside code yields and may allow the codec - to try to wait for a reply on a buffer wait */ - ci.stop_codec = true; id3 = audio_current_track(); - } /* Save the current playing spot, or NULL if the playlist has ended */ playlist_update_resume_info(id3); @@ -1797,7 +1822,6 @@ audio_set_output_source(AUDIO_SRC_PLAYBACK); #endif - /* Wait for any previously playing audio to flush - TODO: Not necessary? */ paused = false; audio_stop_codec_flush(); @@ -1853,6 +1877,11 @@ { /* Prepare to start a new fill from the beginning of the playlist */ last_peek_offset = -1; + + /* Signal the codec to initiate a track change forward */ + new_playlist = true; + ci.new_track = 1; + if (audio_have_tracks()) { if (paused) @@ -1866,10 +1895,6 @@ CUR_TI->taginfo_ready = false; } - /* Signal the codec to initiate a track change forward */ - new_playlist = true; - ci.new_track = 1; - /* Officially playing */ queue_reply(&audio_queue, 1); @@ -1919,6 +1944,60 @@ playlist_update_resume_info(audio_current_track()); } +static void audio_seek_complete(void) +{ + logf("audio_seek_complete"); + + if (!playing) + return; + + /* If seeking-while-playing, pcm_is_paused() is true. + * If seeking-while-paused, audio_status PAUSE is true. + * A seamless seek skips this section. */ + ci.seek_time = 0; + + pcm_play_lock(); + + if (pcm_is_paused() || paused) + { + /* Clear the buffer */ + pcmbuf_play_stop(); + + /* If seeking-while-playing, resume PCM playback */ + if (!paused) + pcmbuf_pause(false); + } + + pcm_play_unlock(); +} + +static void audio_codec_status_message(long reason, int status) +{ + /* TODO: Push the errors up to the normal UI somewhere */ + if (!playing) + return; + + switch (reason) + { + case Q_CODEC_LOAD_DISK: + case Q_CODEC_LOAD: + if (status < 0) + { + splash(HZ*2, "Codec failure"); + if (!ci.stop_codec) + audio_check_new_track(); + } + break; + +#ifdef AUDIO_HAVE_RECORDING + case Q_ENCODER_LOAD_DISK: + if (status < 0) + splash(HZ*2, "Encoder failure"); + break; +#endif /* AUDIO_HAVE_RECORDING */ + } +} + /* * Layout audio buffer as follows - iram buffer depends on target: * [|SWAP:iram][|TALK]|FILE|GUARD|PCM|[SWAP:dram[|iram]|] @@ -1986,14 +2065,25 @@ while (1) { - if (filling != STATE_FILLING && filling != STATE_IDLE) { + switch (filling) + { + case STATE_FILLING: + case STATE_IDLE: + case STATE_ENDING: + break; + + default: /* End of buffering, let's calculate the watermark and unboost */ set_filebuf_watermark(); cancel_cpu_boost(); } - if (!pcmbuf_queue_scan(&ev)) - queue_wait_w_tmo(&audio_queue, &ev, HZ/2); + if (!pcmbuf_queue_scan(&ev)) { + if (filling == STATE_IDLE) + queue_wait(&audio_queue, &ev); + else + queue_wait_w_tmo(&audio_queue, &ev, HZ/2); + } switch (ev.id) { @@ -2079,7 +2169,7 @@ case Q_AUDIO_CHECK_NEW_TRACK: LOGFQUEUE("audio < Q_AUDIO_CHECK_NEW_TRACK"); - queue_reply(&audio_queue, audio_check_new_track()); + audio_check_new_track(); break; case Q_AUDIO_DIR_SKIP: @@ -2095,8 +2185,29 @@ case Q_AUDIO_TRACK_CHANGED: /* PCM track change done */ LOGFQUEUE("audio < Q_AUDIO_TRACK_CHANGED"); - audio_finalise_track_change(); + if (filling != STATE_ENDING) + audio_finalise_track_change(); + else if (playing) + audio_stop_playback(); break; + + case Q_AUDIO_SEEK_COMPLETE: + /* Codec seek done */ + LOGFQUEUE("audio < Q_AUDIO_SEEK_COMPLETE"); + audio_seek_complete(); + codec_ack_msg(Q_AUDIO_SEEK_COMPLETE); + break; + + case Q_CODEC_LOAD: + case Q_CODEC_LOAD_DISK: +#ifdef AUDIO_HAVE_RECORDING + case Q_ENCODER_LOAD_DISK: +#endif + /* These are received when a codec has finished normally or + upon a codec error */ + audio_codec_status_message(ev.id, ev.data); + break; + #if (CONFIG_PLATFORM & PLATFORM_NATIVE) case SYS_USB_CONNECTED: LOGFQUEUE("audio < SYS_USB_CONNECTED"); @@ -2116,6 +2227,18 @@ break; #endif +#ifdef AUDIO_HAVE_RECORDING + case Q_AUDIO_LOAD_ENCODER: + if (playing) + audio_stop_playback(); + else + codec_stop(); /* If encoder still loaded */ + + if (ev.data != AFMT_UNKNOWN) + queue_reply(&audio_queue, codec_load_encoder(ev.data)); + break; +#endif /* AUDIO_HAVE_RECORDING */ + case SYS_TIMEOUT: LOGFQUEUE_SYS_TIMEOUT("audio < SYS_TIMEOUT"); break; @@ -2147,7 +2270,6 @@ to send messages. Thread creation will be delayed however so nothing starts running until ready if something yields such as talk_init. */ queue_init(&audio_queue, true); - queue_init(&codec_queue, false); queue_init(&pcmbuf_queue, false); pcm_init(); @@ -2227,7 +2349,7 @@ #ifdef PLAYBACK_VOICE voice_thread_resume(); #endif - thread_thaw(codec_thread_id); + codec_thread_resume(); thread_thaw(audio_thread_id); } /* audio_init */ @@ -2246,8 +2368,3 @@ { return CUR_TI->audio_hid; } - -int *get_codec_hid() -{ - return &tracks[track_ridx].codec_hid; -} Index: apps/playback.h =================================================================== --- apps/playback.h (revision 29339) +++ apps/playback.h (working copy) @@ -81,9 +81,9 @@ void audio_pcmbuf_position_callback(unsigned int time) ICODE_ATTR; void audio_post_track_change(bool pcmbuf); int get_audio_hid(void); -int *get_codec_hid(void); void audio_set_prev_elapsed(unsigned long setting); bool audio_buffer_state_trashed(void); +bool audio_automatic_skip(void); /* Define one constant that includes recording related functionality */ #if defined(HAVE_RECORDING) && !defined(SIMULATOR) @@ -101,6 +101,7 @@ Q_AUDIO_CHECK_NEW_TRACK, Q_AUDIO_FLUSH, Q_AUDIO_TRACK_CHANGED, + Q_AUDIO_SEEK_COMPLETE, Q_AUDIO_DIR_SKIP, Q_AUDIO_POSTINIT, Q_AUDIO_FILL_BUFFER, @@ -112,11 +113,13 @@ Q_CODEC_LOAD_DISK, #ifdef AUDIO_HAVE_RECORDING + Q_AUDIO_LOAD_ENCODER, Q_ENCODER_LOAD_DISK, Q_ENCODER_RECORD, #endif Q_CODEC_DO_CALLBACK, + Q_CODEC_ACK, }; #endif Index: apps/plugin.c =================================================================== --- apps/plugin.c (revision 29339) +++ apps/plugin.c (working copy) @@ -691,6 +691,8 @@ #if CONFIG_CODEC == SWCODEC codec_thread_do_callback, codec_load_file, + codec_begin, + codec_close, get_codec_filename, find_array_ptr, remove_array_ptr, Index: apps/plugin.h =================================================================== --- apps/plugin.h (revision 29339) +++ apps/plugin.h (working copy) @@ -145,12 +145,12 @@ #define PLUGIN_MAGIC 0x526F634B /* RocK */ /* increase this every time the api struct changes */ -#define PLUGIN_API_VERSION 198 +#define PLUGIN_API_VERSION 199 /* update this to latest version if a change to the api struct breaks backwards compatibility (and please take the opportunity to sort in any new function which are "waiting" at the end of the function table) */ -#define PLUGIN_MIN_API_VERSION 198 +#define PLUGIN_MIN_API_VERSION 199 /* plugin return codes */ /* internal returns start at 0x100 to make exit(1..255) work */ @@ -798,7 +798,9 @@ #if CONFIG_CODEC == SWCODEC void (*codec_thread_do_callback)(void (*fn)(void), unsigned int *audio_thread_id); - int (*codec_load_file)(const char* codec, struct codec_api *api); + void * (*codec_load_file)(const char* codec, struct codec_api *api); + int (*codec_begin)(void *handle); + void (*codec_close)(void *handle); const char *(*get_codec_filename)(int cod_spec); void ** (*find_array_ptr)(void **arr, void *ptr); int (*remove_array_ptr)(void **arr, void *ptr); Index: apps/codecs/vorbis.c =================================================================== --- apps/codecs/vorbis.c (revision 29339) +++ apps/codecs/vorbis.c (working copy) @@ -136,10 +136,12 @@ #endif next_track: + error = CODEC_OK; + ogg_malloc_init(); - while (!*ci->taginfo_ready && !ci->stop_codec) - ci->sleep(1); + if (codec_wait_taginfo() != 0) + goto done; /* Create a decoder instance */ callbacks.read_func = read_handler; @@ -233,8 +235,7 @@ ci->set_elapsed(ov_time_tell(&vf)); } } - error = CODEC_OK; - + done: #if 0 /* defined(SIMULATOR) */ { Index: apps/codecs/au.c =================================================================== --- apps/codecs/au.c (revision 29339) +++ apps/codecs/au.c (working copy) @@ -108,7 +108,7 @@ /* this is the codec entry point */ enum codec_status codec_main(void) { - int status = CODEC_OK; + int status; struct pcm_format format; uint32_t bytesdone, decodedsamples; size_t n; @@ -124,14 +124,16 @@ ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1); next_track: + status = CODEC_OK; + if (codec_init()) { DEBUGF("codec_init() error\n"); status = CODEC_ERROR; goto exit; } - while (!*ci->taginfo_ready && !ci->stop_codec) - ci->sleep(1); + if (codec_wait_taginfo() != 0) + goto done; codec_set_replaygain(ci->id3); @@ -304,7 +306,6 @@ endofstream = 1; ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency); } - status = CODEC_OK; done: if (ci->request_next_track()) Index: apps/codecs/ape.c =================================================================== --- apps/codecs/ape.c (revision 29339) +++ apps/codecs/ape.c (working copy) @@ -149,23 +149,22 @@ /* Generic codec initialisation */ ci->configure(DSP_SET_SAMPLE_DEPTH, APE_OUTPUT_DEPTH-1); - next_track: - +next_track: retval = CODEC_OK; - /* Remember the resume position - when the codec is opened, the - playback engine will reset it. */ - resume_offset = ci->id3->offset; - if (codec_init()) { LOGF("APE: Error initialising codec\n"); retval = CODEC_ERROR; goto exit; } - while (!*ci->taginfo_ready && !ci->stop_codec) - ci->sleep(1); + if (codec_wait_taginfo() != 0) + goto done; + /* Remember the resume position - when the codec is opened, the + playback engine will reset it. */ + resume_offset = ci->id3->offset; + inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE); /* Read the file headers to populate the ape_ctx struct */ @@ -319,8 +318,6 @@ currentframe++; } - retval = CODEC_OK; - done: LOGF("APE: Decoded %lu samples\n",(unsigned long)samplesdone); Index: apps/codecs/aiff.c =================================================================== --- apps/codecs/aiff.c (revision 29339) +++ apps/codecs/aiff.c (working copy) @@ -63,7 +63,7 @@ enum codec_status codec_main(void) { - int status = CODEC_OK; + int status; struct pcm_format format; uint32_t bytesdone, decodedsamples; uint32_t num_sample_frames = 0; @@ -82,13 +82,15 @@ ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1); next_track: + status = CODEC_OK; + if (codec_init()) { status = CODEC_ERROR; goto exit; } - while (!*ci->taginfo_ready && !ci->stop_codec) - ci->sleep(1); + if (codec_wait_taginfo() != 0) + goto done; codec_set_replaygain(ci->id3); Index: apps/codecs/flac.c =================================================================== --- apps/codecs/flac.c (revision 29339) +++ apps/codecs/flac.c (working copy) @@ -433,19 +433,20 @@ /* Generic codec initialisation */ ci->configure(DSP_SET_SAMPLE_DEPTH, FLAC_OUTPUT_DEPTH-1); - next_track: +next_track: + retval = CODEC_OK; - /* Need to save offset for later use (cleared indirectly by flac_init) */ - samplesdone=ci->id3->offset; - if (codec_init()) { LOGF("FLAC: Error initialising codec\n"); retval = CODEC_ERROR; goto exit; } - while (!*ci->taginfo_ready && !ci->stop_codec) - ci->sleep(1); + if (codec_wait_taginfo() != 0) + goto done; + + /* Need to save offset for later use (cleared indirectly by flac_init) */ + samplesdone = ci->id3->offset; if (!flac_init(&fc,ci->id3->first_frame_offset)) { LOGF("FLAC: Error initialising codec\n"); Index: apps/codecs/raac.c =================================================================== --- apps/codecs/raac.c (revision 29339) +++ apps/codecs/raac.c (working copy) @@ -56,7 +56,7 @@ uint32_t s = 0; /* sample rate */ unsigned char c = 0; /* channels */ int playback_on = -1; - size_t resume_offset = ci->id3->offset; + size_t resume_offset; /* Generic codec initialisation */ ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED); @@ -70,9 +70,11 @@ return CODEC_ERROR; } - while (!*ci->taginfo_ready && !ci->stop_codec) - ci->sleep(1); + if (codec_wait_taginfo() != 0) + goto done; + resume_offset = ci->id3->offset; + ci->memset(&rmctx,0,sizeof(RMContext)); ci->memset(&pkt,0,sizeof(RMPacket)); init_rm(&rmctx); @@ -224,8 +226,6 @@ ci->advance_buffer(pkt.length); } - err = CODEC_OK; - done: if (ci->request_next_track()) goto next_track; Index: apps/codecs/atrac3_rm.c =================================================================== --- apps/codecs/atrac3_rm.c (revision 29339) +++ apps/codecs/atrac3_rm.c (working copy) @@ -51,16 +51,19 @@ uint32_t packet_count; int scrambling_unit_size, num_units, elapsed = 0; int playback_on = -1; - size_t resume_offset = ci->id3->offset; + size_t resume_offset; next_track: if (codec_init()) { DEBUGF("codec init failed\n"); return CODEC_ERROR; } - while (!*ci->taginfo_ready && !ci->stop_codec) - ci->sleep(1); + if (codec_wait_taginfo() != 0) + goto done; + + resume_offset = ci->id3->offset; + codec_set_replaygain(ci->id3); ci->memset(&rmctx,0,sizeof(RMContext)); ci->memset(&pkt,0,sizeof(RMPacket)); Index: apps/codecs/adx.c =================================================================== --- apps/codecs/adx.c (revision 29339) +++ apps/codecs/adx.c (working copy) @@ -78,8 +78,8 @@ ch1_1=ch1_2=ch2_1=ch2_2=0; /* wait for track info to load */ - while (!*ci->taginfo_ready && !ci->stop_codec) - ci->sleep(1); + if (codec_wait_taginfo() != 0) + goto request_next_track; codec_set_replaygain(ci->id3); @@ -385,6 +385,7 @@ 1000LL/avgbytespersec); } +request_next_track: if (ci->request_next_track()) goto next_track; Index: apps/codecs/vox.c =================================================================== --- apps/codecs/vox.c (revision 29339) +++ apps/codecs/vox.c (working copy) @@ -46,7 +46,7 @@ /* this is the codec entry point */ enum codec_status codec_main(void) { - int status = CODEC_OK; + int status; uint32_t decodedsamples; size_t n; int bufcount; @@ -59,14 +59,16 @@ ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1); next_track: + status = CODEC_OK; + if (codec_init()) { DEBUGF("codec_init() error\n"); status = CODEC_ERROR; goto exit; } - while (!*ci->taginfo_ready && !ci->stop_codec) - ci->sleep(1); + if (codec_wait_taginfo() != 0) + goto done; codec_set_replaygain(ci->id3); @@ -189,7 +191,6 @@ endofstream = 1; ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency); } - status = CODEC_OK; done: if (ci->request_next_track()) Index: apps/codecs/mpa.c =================================================================== --- apps/codecs/mpa.c (revision 29339) +++ apps/codecs/mpa.c (working copy) @@ -325,15 +325,14 @@ return CODEC_ERROR; next_track: - status = CODEC_OK; /* Reinitializing seems to be necessary to avoid playback quircks when seeking. */ init_mad(); file_end = 0; - while (!*ci->taginfo_ready && !ci->stop_codec) - ci->sleep(1); + if (codec_wait_taginfo() != 0) + goto request_next_track; ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); current_frequency = ci->id3->frequency; @@ -505,6 +504,7 @@ framelength - stop_skip); } +request_next_track: if (ci->request_next_track()) goto next_track; Index: apps/codecs/mpc.c =================================================================== --- apps/codecs/mpc.c (revision 29339) +++ apps/codecs/mpc.c (working copy) @@ -64,7 +64,7 @@ mpc_streaminfo info; mpc_frame_info frame; mpc_demux *demux = NULL; - int retval = CODEC_OK; + int retval; frame.buffer = sample_buffer; @@ -78,15 +78,17 @@ reader.tell = tell_impl; reader.get_size = get_size_impl; -next_track: +next_track: + retval = CODEC_OK; + if (codec_init()) { retval = CODEC_ERROR; goto exit; } - while (!*ci->taginfo_ready && !ci->stop_codec) - ci->sleep(1); + if (codec_wait_taginfo() != 0) + goto done; /* Initialize demux/decoder. */ demux = mpc_demux_init(&reader); Index: apps/codecs/speex.c =================================================================== --- apps/codecs/speex.c (revision 29339) +++ apps/codecs/speex.c (working copy) @@ -371,7 +371,7 @@ enum codec_status codec_main(void) { SpeexBits bits; - int error = 0; + int error; int eof = 0; spx_ogg_sync_state oy; spx_ogg_page og; @@ -395,17 +395,19 @@ /* Ogg handling still uses mallocs, so reset the malloc buffer per track */ next_track: + error = CODEC_OK; if (codec_init()) { error = CODEC_ERROR; goto exit; } stereo = speex_stereo_state_init(); + + if (codec_wait_taginfo() != 0) + goto done; + strtoffset = ci->id3->offset; - while (!*ci->taginfo_ready && !ci->stop_codec) - ci->sleep(1); - spx_ogg_sync_init(&oy); spx_ogg_alloc_buffer(&oy,2*CHUNKSIZE); @@ -569,8 +571,6 @@ goto next_track; } - error = CODEC_OK; - exit: speex_bits_destroy(&bits); Index: apps/codecs/mp3_enc.c =================================================================== --- apps/codecs/mp3_enc.c (revision 29339) +++ apps/codecs/mp3_enc.c (working copy) @@ -2588,16 +2588,10 @@ { /* Generic codec initialisation */ if (!enc_init()) - { - ci->enc_codec_loaded = -1; return CODEC_ERROR; - } - /* main application waits for this flag during encoder loading */ - ci->enc_codec_loaded = 1; - /* main encoding loop */ - while (!ci->stop_encoder) + while (!ci->stop_codec) { char *buffer; @@ -2605,7 +2599,7 @@ { struct enc_chunk_hdr *chunk; - if (ci->stop_encoder) + if (ci->stop_codec) break; chunk = ci->enc_get_chunk(); @@ -2630,8 +2624,5 @@ /* reset parameters to initial state */ ci->enc_set_parameters(NULL); - /* main application waits for this flag during encoder removing */ - ci->enc_codec_loaded = 0; - return CODEC_OK; } /* codec_start */ Index: apps/codecs/aac.c =================================================================== --- apps/codecs/aac.c (revision 29339) +++ apps/codecs/aac.c (working copy) @@ -78,8 +78,8 @@ goto exit; } - while (!*ci->taginfo_ready && !ci->stop_codec) - ci->sleep(1); + if (codec_wait_taginfo() != 0) + goto done; file_offset = ci->id3->offset; @@ -304,8 +304,6 @@ i++; } - err = CODEC_OK; - done: LOGF("AAC: Decoded %lu samples\n", (unsigned long)sound_samples_done); Index: apps/codecs/lib/codeclib.c =================================================================== --- apps/codecs/lib/codeclib.c (revision 29339) +++ apps/codecs/lib/codeclib.c (working copy) @@ -49,6 +49,19 @@ ci->configure(DSP_SET_ALBUM_PEAK, id3->album_peak); } +/* Note: codec really needs its own private metdata copy for the current + track being processed in order to be stable. */ +int codec_wait_taginfo(void) +{ + while (!*ci->taginfo_ready && !ci->stop_codec && !ci->new_track) + ci->sleep(0); + if (ci->stop_codec) + return -1; + if (ci->new_track) + return 1; + return 0; +} + /* Various "helper functions" common to all the xxx2wav decoder plugins */ Index: apps/codecs/lib/codeclib.h =================================================================== --- apps/codecs/lib/codeclib.h (revision 29339) +++ apps/codecs/lib/codeclib.h (working copy) @@ -157,6 +157,7 @@ int codec_init(void); void codec_set_replaygain(struct mp3entry* id3); +int codec_wait_taginfo(void); /* 0 = success */ #ifdef RB_PROFILE void __cyg_profile_func_enter(void *this_fn, void *call_site) Index: apps/codecs/spc.c =================================================================== --- apps/codecs/spc.c (revision 29339) +++ apps/codecs/spc.c (working copy) @@ -553,8 +553,8 @@ ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED); /* wait for track info to load */ - while (!*ci->taginfo_ready && !ci->stop_codec) - ci->yield(); + if (codec_wait_taginfo() != 0) + continue; codec_set_replaygain(ci->id3); Index: apps/codecs/tta.c =================================================================== --- apps/codecs/tta.c (revision 29339) +++ apps/codecs/tta.c (working copy) @@ -37,7 +37,7 @@ enum codec_status codec_main(void) { tta_info info; - int status = CODEC_OK; + int status; unsigned int decodedsamples; int endofstream; int new_pos = 0; @@ -47,6 +47,8 @@ ci->configure(DSP_SET_SAMPLE_DEPTH, TTA_OUTPUT_DEPTH - 1); next_track: + status = CODEC_OK; + if (codec_init()) { DEBUGF("codec_init() error\n"); @@ -54,8 +56,8 @@ goto exit; } - while (!*ci->taginfo_ready && !ci->stop_codec) - ci->sleep(1); + if (codec_wait_taginfo() != 0) + goto done; if (set_tta_info(&info) < 0 || player_init(&info) < 0) { @@ -72,7 +74,6 @@ ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO); } else { DEBUGF("CODEC_ERROR: more than 2 channels\n"); - status = CODEC_ERROR; goto done; } @@ -109,7 +110,7 @@ if (sample_count < 0) { status = CODEC_ERROR; - break; + goto exit; } ci->pcmbuf_insert(samples, NULL, sample_count); decodedsamples += sample_count; @@ -117,7 +118,7 @@ endofstream = 1; ci->set_elapsed((uint64_t)info.LENGTH * 1000 * decodedsamples / info.DATALENGTH); } - status = CODEC_OK; + done: player_stop(); if (ci->request_next_track()) Index: apps/codecs/alac.c =================================================================== --- apps/codecs/alac.c (revision 29339) +++ apps/codecs/alac.c (working copy) @@ -48,6 +48,7 @@ ci->configure(DSP_SET_SAMPLE_DEPTH, ALAC_OUTPUT_DEPTH-1); next_track: + retval = CODEC_OK; /* Clean and initialize decoder structures */ memset(&demux_res , 0, sizeof(demux_res)); @@ -57,8 +58,8 @@ goto exit; } - while (!*ci->taginfo_ready && !ci->stop_codec) - ci->sleep(1); + if (codec_wait_taginfo() != 0) + goto done; ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); codec_set_replaygain(ci->id3); @@ -145,7 +146,6 @@ i++; } - retval = CODEC_OK; done: LOGF("ALAC: Decoded %lu samples\n",(unsigned long)samplesdone); Index: apps/codecs/wmapro.c =================================================================== --- apps/codecs/wmapro.c (revision 29339) +++ apps/codecs/wmapro.c (working copy) @@ -48,16 +48,18 @@ next_track: + retval = CODEC_OK; /* Wait for the metadata to be read */ - while (!*ci->taginfo_ready && !ci->stop_codec) - ci->sleep(1); + if (codec_wait_taginfo() != 0) + goto done; + /* Remember the resume position */ + resume_offset = ci->id3->offset; + +restart_track: retval = CODEC_OK; - /* Remember the resume position */ - resume_offset = ci->id3->offset; - restart_track: if (codec_init()) { LOGF("(WMA PRO) Error: Error initialising codec\n"); retval = CODEC_ERROR; @@ -149,7 +151,6 @@ /* Advance to the next logical packet */ ci->advance_buffer(packetlength); } - retval = CODEC_OK; done: if (ci->request_next_track()) Index: apps/codecs/wav64.c =================================================================== --- apps/codecs/wav64.c (revision 29339) +++ apps/codecs/wav64.c (working copy) @@ -161,7 +161,7 @@ /* this is the codec entry point */ enum codec_status codec_main(void) { - int status = CODEC_OK; + int status; uint32_t decodedsamples; size_t n; int bufcount; @@ -176,14 +176,16 @@ ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1); next_track: + status = CODEC_OK; + if (codec_init()) { DEBUGF("codec_init() error\n"); status = CODEC_ERROR; goto exit; } - while (!*ci->taginfo_ready && !ci->stop_codec) - ci->sleep(1); + if (codec_wait_taginfo() != 0) + goto done; codec_set_replaygain(ci->id3); Index: apps/codecs/atrac3_oma.c =================================================================== --- apps/codecs/atrac3_oma.c (revision 29339) +++ apps/codecs/atrac3_oma.c (working copy) @@ -40,16 +40,19 @@ int datasize, res, frame_counter, total_frames, seek_frame_offset; uint8_t *bit_buffer; int elapsed = 0; - size_t resume_offset = ci->id3->offset; + size_t resume_offset; next_track: if (codec_init()) { DEBUGF("codec init failed\n"); return CODEC_ERROR; } - while (!*ci->taginfo_ready && !ci->stop_codec) - ci->sleep(1); + if (codec_wait_taginfo() != 0) + goto done; + + resume_offset = ci->id3->offset; + codec_set_replaygain(ci->id3); ci->memset(&q,0,sizeof(ATRAC3Context)); Index: apps/codecs/wmavoice.c =================================================================== --- apps/codecs/wmavoice.c (revision 29339) +++ apps/codecs/wmavoice.c (working copy) @@ -70,16 +70,17 @@ next_track: + retval = CODEC_OK; /* Wait for the metadata to be read */ - while (!*ci->taginfo_ready && !ci->stop_codec) - ci->sleep(1); + if (codec_wait_taginfo() != 0) + goto done; + /* Remember the resume position */ + resume_offset = ci->id3->offset; +restart_track: retval = CODEC_OK; - /* Remember the resume position */ - resume_offset = ci->id3->offset; - restart_track: if (codec_init()) { LOGF("(WMA Voice) Error: Error initialising codec\n"); retval = CODEC_ERROR; @@ -184,7 +185,6 @@ /* Advance to the next logical packet */ ci->advance_buffer(packetlength); } - retval = CODEC_OK; done: if (ci->request_next_track()) Index: apps/codecs/mod.c =================================================================== --- apps/codecs/mod.c (revision 29339) +++ apps/codecs/mod.c (working copy) @@ -1232,8 +1232,8 @@ return CODEC_ERROR; } - while (!*ci->taginfo_ready && !ci->stop_codec) - ci->sleep(1); + if (codec_wait_taginfo() != 0) + goto request_next_track; codec_set_replaygain(ci->id3); @@ -1305,6 +1305,7 @@ } +request_next_track: if (ci->request_next_track()) goto next_track; Index: apps/codecs/sid.c =================================================================== --- apps/codecs/sid.c (revision 29339) +++ apps/codecs/sid.c (working copy) @@ -1220,8 +1220,8 @@ return CODEC_ERROR; } - while (!*ci->taginfo_ready && !ci->stop_codec) - ci->sleep(1); + if (codec_wait_taginfo() != 0) + goto request_next_track; codec_set_replaygain(ci->id3); @@ -1306,6 +1306,7 @@ ci->pcmbuf_insert(samples, NULL, CHUNK_SIZE); } +request_next_track: if (ci->request_next_track()) goto next_track; Index: apps/codecs/wavpack_enc.c =================================================================== --- apps/codecs/wavpack_enc.c (revision 29339) +++ apps/codecs/wavpack_enc.c (working copy) @@ -393,16 +393,10 @@ { /* initialize params and config */ if (!init_encoder()) - { - ci->enc_codec_loaded = -1; return CODEC_ERROR; - } - /* main application waits for this flag during encoder loading */ - ci->enc_codec_loaded = 1; - /* main encoding loop */ - while(!ci->stop_encoder) + while(!ci->stop_codec) { uint8_t *src; @@ -413,7 +407,7 @@ uint8_t *dst; uint8_t *src_end; - if(ci->stop_encoder) + if(ci->stop_codec) break; abort_chunk = true; @@ -442,7 +436,7 @@ chunk->num_pcm += PCM_SAMP_PER_CHUNK/4; ci->yield(); /* could've been stopped in some way */ - abort_chunk = ci->stop_encoder || + abort_chunk = ci->stop_codec || (chunk->flags & CHUNKF_ABORT); } @@ -467,8 +461,5 @@ /* reset parameters to initial state */ ci->enc_set_parameters(NULL); - /* main application waits for this flag during encoder removing */ - ci->enc_codec_loaded = 0; - return CODEC_OK; } /* codec_start */ Index: apps/codecs/shorten.c =================================================================== --- apps/codecs/shorten.c (revision 29339) +++ apps/codecs/shorten.c (working copy) @@ -57,8 +57,8 @@ return CODEC_ERROR; } - while (!*ci->taginfo_ready) - ci->yield(); + if (codec_wait_taginfo() != 0) + goto request_next_track; codec_set_replaygain(ci->id3); @@ -153,6 +153,7 @@ sc.bitindex = sc.gb.index - 8*consumed; } +request_next_track: if (ci->request_next_track()) goto next_track; Index: apps/codecs/wav_enc.c =================================================================== --- apps/codecs/wav_enc.c (revision 29339) +++ apps/codecs/wav_enc.c (working copy) @@ -349,16 +349,10 @@ enum codec_status codec_main(void) { if (!init_encoder()) - { - ci->enc_codec_loaded = -1; return CODEC_ERROR; - } - /* main application waits for this flag during encoder loading */ - ci->enc_codec_loaded = 1; - /* main encoding loop */ - while(!ci->stop_encoder) + while(!ci->stop_codec) { uint32_t *src; @@ -366,7 +360,7 @@ { struct enc_chunk_hdr *chunk; - if (ci->stop_encoder) + if (ci->stop_codec) break; chunk = ci->enc_get_chunk(); @@ -386,8 +380,5 @@ /* reset parameters to initial state */ ci->enc_set_parameters(NULL); - /* main application waits for this flag during encoder removing */ - ci->enc_codec_loaded = 0; - return CODEC_OK; } /* codec_start */ Index: apps/codecs/asap.c =================================================================== --- apps/codecs/asap.c (revision 29339) +++ apps/codecs/asap.c (working copy) @@ -44,8 +44,8 @@ return CODEC_ERROR; } - while (!*ci->taginfo_ready && !ci->stop_codec) - ci->sleep(1); + if (codec_wait_taginfo() != 0) + goto request_next_track; codec_set_replaygain(ci->id3); @@ -130,6 +130,7 @@ break; } +request_next_track: if (ci->request_next_track()) goto next_track; Index: apps/codecs/wma.c =================================================================== --- apps/codecs/wma.c (revision 29339) +++ apps/codecs/wma.c (working copy) @@ -46,19 +46,22 @@ ci->configure(DSP_SET_SAMPLE_DEPTH, 29); next_track: + retval = CODEC_OK; + /* Proper reset of the decoder context. */ memset(&wmadec, 0, sizeof(wmadec)); /* Wait for the metadata to be read */ - while (!*ci->taginfo_ready && !ci->stop_codec) - ci->sleep(1); + if (codec_wait_taginfo() != 0) + goto done; - retval = CODEC_OK; - /* Remember the resume position - when the codec is opened, the playback engine will reset it. */ resume_offset = ci->id3->offset; + restart_track: + retval = CODEC_OK; + if (codec_init()) { LOGF("WMA: Error initialising codec\n"); retval = CODEC_ERROR; @@ -176,7 +179,6 @@ ci->advance_buffer(packetlength); } - retval = CODEC_OK; done: /*LOGF("WMA: Decoded %ld samples\n",elapsedtime*wfx.rate/1000);*/ Index: apps/codecs/a52_rm.c =================================================================== --- apps/codecs/a52_rm.c (revision 29339) +++ apps/codecs/a52_rm.c (working copy) @@ -132,21 +132,25 @@ uint8_t *filebuf; int retval, consumed, packet_offset; int playback_on = -1; - size_t resume_offset = ci->id3->offset; + size_t resume_offset; /* Generic codec initialisation */ ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED); ci->configure(DSP_SET_SAMPLE_DEPTH, 28); next_track: + retval = CODEC_OK; + if (codec_init()) { retval = CODEC_ERROR; goto exit; } - while (!ci->taginfo_ready) - ci->yield(); + if (codec_wait_taginfo() != 0) + goto request_next_track; + resume_offset = ci->id3->offset; + ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); codec_set_replaygain(ci->id3); @@ -201,8 +205,7 @@ ci->advance_buffer(pkt.length); } - retval = CODEC_OK; - +request_next_track: if (ci->request_next_track()) goto next_track; Index: apps/codecs/nsf.c =================================================================== --- apps/codecs/nsf.c (revision 29339) +++ apps/codecs/nsf.c (working copy) @@ -4344,9 +4344,9 @@ /* wait for track info to load */ - while (!*ci->taginfo_ready && !ci->stop_codec) - ci->sleep(1); - + if (codec_wait_taginfo() != 0) + goto request_next_track; + codec_set_replaygain(ci->id3); /* Read the entire file */ @@ -4448,7 +4448,8 @@ } print_timers(last_path,track); - + +request_next_track: if (ci->request_next_track()) { if (ci->global_settings->repeat_mode==REPEAT_ONE) { /* in repeat one mode just advance to the next track */ Index: apps/codecs/smaf.c =================================================================== --- apps/codecs/smaf.c (revision 29339) +++ apps/codecs/smaf.c (working copy) @@ -334,7 +334,7 @@ enum codec_status codec_main(void) { - int status = CODEC_OK; + int status; uint32_t decodedsamples; size_t n; int bufcount; @@ -347,13 +347,15 @@ ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1); next_track: + status = CODEC_OK; + if (codec_init()) { status = CODEC_ERROR; goto exit; } - while (!*ci->taginfo_ready && !ci->stop_codec) - ci->sleep(1); + if (codec_wait_taginfo() != 0) + goto done; codec_set_replaygain(ci->id3); @@ -479,7 +481,6 @@ ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency); } - status = CODEC_OK; done: if (ci->request_next_track()) Index: apps/codecs/a52.c =================================================================== --- apps/codecs/a52.c (revision 29339) +++ apps/codecs/a52.c (working copy) @@ -128,13 +128,15 @@ ci->configure(DSP_SET_SAMPLE_DEPTH, 28); next_track: + retval = CODEC_OK; + if (codec_init()) { retval = CODEC_ERROR; goto exit; } - while (!ci->taginfo_ready) - ci->yield(); + if (codec_wait_taginfo() != 0) + goto request_next_track; ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); codec_set_replaygain(ci->id3); @@ -176,8 +178,8 @@ a52_decode_data(filebuf, filebuf + n); ci->advance_buffer(n); } - retval = CODEC_OK; +request_next_track: if (ci->request_next_track()) goto next_track; Index: apps/codecs/aiff_enc.c =================================================================== --- apps/codecs/aiff_enc.c (revision 29339) +++ apps/codecs/aiff_enc.c (working copy) @@ -363,16 +363,10 @@ enum codec_status codec_main(void) { if (!init_encoder()) - { - ci->enc_codec_loaded = -1; return CODEC_ERROR; - } - /* main application waits for this flag during encoder loading */ - ci->enc_codec_loaded = 1; - /* main encoding loop */ - while(!ci->stop_encoder) + while(!ci->stop_codec) { uint32_t *src; @@ -380,7 +374,7 @@ { struct enc_chunk_hdr *chunk; - if (ci->stop_encoder) + if (ci->stop_codec) break; chunk = ci->enc_get_chunk(); @@ -400,8 +394,5 @@ /* reset parameters to initial state */ ci->enc_set_parameters(NULL); - /* main application waits for this flag during encoder removing */ - ci->enc_codec_loaded = 0; - return CODEC_OK; } /* codec_start */ Index: apps/codecs/cook.c =================================================================== --- apps/codecs/cook.c (revision 29339) +++ apps/codecs/cook.c (working copy) @@ -47,16 +47,19 @@ uint16_t fs,sps,h; uint32_t packet_count; int scrambling_unit_size, num_units; - size_t resume_offset = ci->id3->offset; + size_t resume_offset; next_track: if (codec_init()) { DEBUGF("codec init failed\n"); return CODEC_ERROR; } - while (!*ci->taginfo_ready && !ci->stop_codec) - ci->sleep(1); + if (codec_wait_taginfo() != 0) + goto done; + + resume_offset = ci->id3->offset; + codec_set_replaygain(ci->id3); ci->memset(&rmctx,0,sizeof(RMContext)); ci->memset(&pkt,0,sizeof(RMPacket)); Index: apps/codecs/wavpack.c =================================================================== --- apps/codecs/wavpack.c (revision 29339) +++ apps/codecs/wavpack.c (working copy) @@ -46,15 +46,16 @@ /* Generic codec initialisation */ ci->configure(DSP_SET_SAMPLE_DEPTH, 28); - next_track: +next_track: + retval = CODEC_OK; if (codec_init()) { retval = CODEC_ERROR; goto exit; } - while (!*ci->taginfo_ready && !ci->stop_codec) - ci->sleep(1); + if (codec_wait_taginfo() != 0) + goto done; /* Create a decoder instance */ wpc = WavpackOpenFileInput (read_callback, error); @@ -121,7 +122,6 @@ ci->set_elapsed (WavpackGetSampleIndex (wpc) / sr_100 * 10); ci->yield (); } - retval = CODEC_OK; done: if (ci->request_next_track()) Index: apps/codecs/wav.c =================================================================== --- apps/codecs/wav.c (revision 29339) +++ apps/codecs/wav.c (working copy) @@ -153,7 +153,7 @@ /* this is the codec entry point */ enum codec_status codec_main(void) { - int status = CODEC_OK; + int status; uint32_t decodedsamples; size_t n; int bufcount; @@ -168,14 +168,16 @@ ci->configure(DSP_SET_SAMPLE_DEPTH, PCM_OUTPUT_DEPTH-1); next_track: + status = CODEC_OK; + if (codec_init()) { DEBUGF("codec_init() error\n"); status = CODEC_ERROR; goto exit; } - while (!*ci->taginfo_ready && !ci->stop_codec) - ci->sleep(1); + if (codec_wait_taginfo() != 0) + goto done; codec_set_replaygain(ci->id3); @@ -437,7 +439,6 @@ endofstream = 1; ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency); } - status = CODEC_OK; done: if (ci->request_next_track()) Index: apps/tagtree.c =================================================================== --- apps/tagtree.c (revision 29339) +++ apps/tagtree.c (working copy) @@ -170,10 +170,6 @@ static struct tree_context *tc; -#if CONFIG_CODEC == SWCODEC -extern bool automatic_skip; /* Who initiated in-progress skip? (C/A-) */ -#endif - static int get_token_str(char *buf, int size) { /* Find the start. */ @@ -726,7 +722,7 @@ first 15 seconds. */ if (id3->elapsed == 0 #if CONFIG_CODEC == SWCODEC /* HWCODEC doesn't have automatic_skip */ - || (id3->elapsed < 15 * 1000 && !automatic_skip) + || (id3->elapsed < 15 * 1000 && !audio_automatic_skip()) #endif ) { @@ -766,7 +762,7 @@ if (global_settings.autoresume_enable) { unsigned long offset - = automatic_skip ? 0 : id3->offset; + = audio_automatic_skip() ? 0 : id3->offset; tagcache_update_numeric(tagcache_idx, tag_lastoffset, offset);