/* Handle Q_CODEC_LOAD */ static void load_codec(const struct codec_load_info *ev_data) { int status = CODEC_ERROR; /* Save a local copy so we can let the audio thread go ASAP */ struct codec_load_info data = *ev_data; bool const encoder = type_is_encoder(data.afmt); if (codec_type != AFMT_UNKNOWN) { /* Must have unloaded it first */ logf("a codec is already loaded"); if (data.hid >= 0) bufclose(data.hid); return; } trigger_cpu_boost(); if (!encoder) { /* Do this now because codec may set some things up at load time */ dsp_configure(ci.dsp, DSP_RESET, 0); } if (data.hid >= 0) { /* First try buffer load */ status = codec_load_buf(data.hid, &ci); bufclose(data.hid); } if (status < 0) { /* Either not a valid handle or the buffer method failed */ const char *codec_fn = get_codec_filename(data.afmt); if (codec_fn) { #ifdef HAVE_IO_PRIORITY buf_back_off_storage(true); #endif status = codec_load_file(codec_fn, &ci); #ifdef HAVE_IO_PRIORITY buf_back_off_storage(false); #endif } } if (status >= 0) { codec_type = data.afmt; codec_queue_ack(Q_CODEC_LOAD); return; } /* Failed - get rid of it */ unload_codec(); }
/** CODEC THREAD */ static void codec_thread(void) { struct queue_event ev; int status; while (1) { status = 0; #ifdef HAVE_CROSSFADE if (!pcmbuf_is_crossfade_active()) #endif { cancel_cpu_boost(); } queue_wait(&codec_queue, &ev); codec_requested_stop = false; 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); 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); break; case Q_CODEC_DO_CALLBACK: LOGFQUEUE("codec < Q_CODEC_DO_CALLBACK"); queue_reply(&codec_queue, 1); if ((void*)ev.data != NULL) { cpucache_invalidate(); ((void (*)(void))ev.data)(); cpucache_flush(); } 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"); break; #endif /* AUDIO_HAVE_RECORDING */ default: LOGFQUEUE("codec < default"); } if (audio_codec_loaded) { if (ci.stop_codec) { status = CODEC_OK; if (!(audio_status() & AUDIO_STATUS_PLAY)) pcmbuf_play_stop(); } audio_codec_loaded = false; } 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; break; #endif /* AUDIO_HAVE_RECORDING */ default: LOGFQUEUE("codec < default"); } /* end switch */ } }