/* Handle STREAM_PAUSE */ static void stream_on_pause(void) { int status = stream_mgr.status; stream_mgr_lock(); /* Reply with previous state */ stream_mgr_reply_msg(status); if (status == STREAM_PLAYING) { /* Pause the clock */ pcm_output_play_pause(false); /* Pause each active stream */ actl_stream_broadcast(STREAM_PAUSE, 0); /* Pause the disk buffer - buffer may continue filling */ disk_buf_send_msg(STREAM_PAUSE, false); /* Unboost the CPU */ cancel_cpu_boost(); /* Offically paused */ stream_mgr.status = STREAM_PAUSED; } stream_mgr_unlock(); }
/* Handle STREAM_OPEN */ void stream_on_open(const char *filename) { int err = STREAM_ERROR; stream_mgr_lock(); trigger_cpu_boost(); /* Open the video file */ if (disk_buf_open(filename) >= 0) { /* Initialize the parser */ err = parser_init_stream(); if (err >= STREAM_OK) { /* File ok - save the opened filename */ stream_mgr.filename = filename; } } /* If error - cleanup */ if (err < STREAM_OK) stream_on_close(); cancel_cpu_boost(); stream_mgr_unlock(); stream_mgr_reply_msg(err); }
bool create_playlist(void) { char filename[MAX_PATH]; snprintf(filename, sizeof filename, "%s.m3u8", tc.currdir[1] ? tc.currdir : "/root"); splashf(0, "%s %s", str(LANG_CREATING), filename); trigger_cpu_boost(); catalog_add_to_a_playlist(tc.currdir, ATTR_DIRECTORY, true, filename); cancel_cpu_boost(); return true; }
static void codec_pcmbuf_insert_callback( const void *ch1, const void *ch2, int count) { const char *src[2] = { ch1, ch2 }; while (count > 0) { int out_count = dsp_output_count(ci.dsp, count); int inp_count; char *dest; while (1) { if ((dest = pcmbuf_request_buffer(&out_count)) != NULL) break; cancel_cpu_boost(); /* It will be awhile before space is available but we want "instant" response to any message */ queue_wait_w_tmo(&codec_queue, NULL, HZ/20); if (!queue_empty(&codec_queue) && codec_check_queue__have_msg() < 0) return; } /* Get the real input_size for output_size bytes, guarding * against resampling buffer overflows. */ inp_count = dsp_input_count(ci.dsp, out_count); if (inp_count <= 0) return; /* Input size has grown, no error, just don't write more than length */ if (inp_count > count) inp_count = count; out_count = dsp_process(ci.dsp, dest, src, inp_count); if (out_count <= 0) return; pcmbuf_write_complete(out_count); count -= inp_count; } }
/* Codec thread function */ static void NORETURN_ATTR codec_thread(void) { struct queue_event ev; while (1) { cancel_cpu_boost(); queue_wait(&codec_queue, &ev); switch (ev.id) { case Q_CODEC_LOAD: LOGFQUEUE("codec < Q_CODEC_LOAD"); load_codec((const struct codec_load_info *)ev.data); break; case Q_CODEC_RUN: LOGFQUEUE("codec < Q_CODEC_RUN"); run_codec(); break; case Q_CODEC_PAUSE: LOGFQUEUE("codec < Q_CODEC_PAUSE"); break; case Q_CODEC_SEEK: LOGFQUEUE("codec < Q_CODEC_SEEK: %lu", (unsigned long)ev.data); seek_codec(ev.data); break; case Q_CODEC_UNLOAD: LOGFQUEUE("codec < Q_CODEC_UNLOAD"); unload_codec(); break; case Q_CODEC_DO_CALLBACK: LOGFQUEUE("codec < Q_CODEC_DO_CALLBACK"); do_callback((void (*)(void))ev.data); break; default: LOGFQUEUE("codec < default : %ld", ev.id); } } }
static void codec_pcmbuf_insert_callback( const void *ch1, const void *ch2, int count) { const char *src[2] = { ch1, ch2 }; while (count > 0) { int out_count = dsp_output_count(ci.dsp, count); int inp_count; char *dest; /* Prevent audio from a previous track from playing */ if (ci.new_track || ci.stop_codec) return; while ((dest = pcmbuf_request_buffer(&out_count)) == NULL) { cancel_cpu_boost(); sleep(1); if (ci.seek_time || ci.new_track || ci.stop_codec) return; } /* Get the real input_size for output_size bytes, guarding * against resampling buffer overflows. */ inp_count = dsp_input_count(ci.dsp, out_count); if (inp_count <= 0) return; /* Input size has grown, no error, just don't write more than length */ if (inp_count > count) inp_count = count; out_count = dsp_process(ci.dsp, dest, src, inp_count); if (out_count <= 0) return; pcmbuf_write_complete(out_count); count -= inp_count; } } /* codec_pcmbuf_insert_callback */
bool create_playlist(void) { char filename[MAX_PATH]; if (tc.currdir[1]) snprintf(filename, sizeof filename, "%s.m3u8", tc.currdir); else snprintf(filename, sizeof filename, "%s/all.m3u8", catalog_get_directory()); if (kbd_input(filename, MAX_PATH)) return false; splashf(0, "%s %s", str(LANG_CREATING), filename); trigger_cpu_boost(); catalog_add_to_a_playlist(tc.currdir, ATTR_DIRECTORY, true, filename); cancel_cpu_boost(); return true; }
/* Handle STREAM_STOP */ static void stream_on_stop(bool reply) { int status = stream_mgr.status; stream_mgr_lock(); if (reply) stream_mgr_reply_msg(status); if (status != STREAM_STOPPED) { /* Pause the clock */ pcm_output_play_pause(false); /* Update the resume time info */ stream_remember_resume_time(); /* Not stopped = paused or playing */ stream_mgr.seeked = false; /* Stop buffering */ disk_buf_send_msg(STREAM_STOP, 0); /* Clear any still-active streams and remove from actl */ actl_stream_broadcast(STREAM_STOP, 1); /* Stop PCM output (and clock) */ pcm_output_stop(); /* Cancel our processor boost */ cancel_cpu_boost(); stream_mgr.status = STREAM_STOPPED; } stream_mgr_unlock(); }
/* inline since branch is chosen at compile time */ static inline void usb_slave_mode(bool on) { #ifdef USE_ROCKBOX_USB int rc; if (on) { trigger_cpu_boost(); #ifdef HAVE_PRIORITY_SCHEDULING thread_set_priority(THREAD_ID_CURRENT, PRIORITY_REALTIME); #endif usb_attach(); } else /* usb_state == USB_INSERTED (only!) */ { #ifndef USB_DETECT_BY_DRV usb_enable(false); #endif #ifdef HAVE_PRIORITY_SCHEDULING thread_set_priority(THREAD_ID_CURRENT, PRIORITY_SYSTEM); #endif /* Entered exclusive mode */ rc = disk_mount_all(); if (rc <= 0) /* no partition */ panicf("mount: %d",rc); cancel_cpu_boost(); } #else /* !USE_ROCKBOX_USB */ if (on) { /* until we have native mass-storage mode, we want to reboot on usb host connect */ try_reboot(); } #endif /* USE_ROCKBOX_USB */ }
void radio_screen(void) { bool done = false; int button; bool stereo = false, last_stereo = false; int update_type = 0; bool screen_freeze = false; bool keep_playing = false; bool talk = false; #ifdef FM_RECORD_DBLPRE int lastbutton = BUTTON_NONE; unsigned long rec_lastclick = 0; #endif #if CONFIG_CODEC != SWCODEC int timeout = current_tick + HZ/10; #if !defined(SIMULATOR) unsigned int last_seconds = 0; unsigned int seconds = 0; struct audio_recording_options rec_options; #endif /* SIMULATOR */ #endif /* CONFIG_CODEC != SWCODEC */ #ifndef HAVE_NOISY_IDLE_MODE int button_timeout = current_tick + (2*HZ); #endif /* change status to "in screen" */ push_current_activity(ACTIVITY_FM); in_screen = true; if(radio_preset_count() <= 0) { radio_load_presets(global_settings.fmr_file); } skin_get_global_state()->id3 = NULL; #ifdef HAVE_ALBUMART radioart_init(true); #endif if(radio_status == FMRADIO_OFF) audio_stop(); fms_fix_displays(FMS_ENTER); #ifndef SIMULATOR #if CONFIG_CODEC != SWCODEC rec_create_directory(); audio_init_recording(); sound_settings_apply(); /* Yes, we use the D/A for monitoring */ peak_meter_playback(true); peak_meter_enable(true); rec_init_recording_options(&rec_options); rec_options.rec_source = AUDIO_SRC_LINEIN; rec_set_recording_options(&rec_options); audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN), sound_default(SOUND_RIGHT_GAIN), AUDIO_GAIN_LINEIN); #endif /* CONFIG_CODEC != SWCODEC */ #endif /* ndef SIMULATOR */ /* turn on radio */ #if CONFIG_CODEC == SWCODEC /* This should be done before touching audio settings */ while (!pcm_is_initialized()) sleep(0); audio_set_input_source(AUDIO_SRC_FMRADIO, (radio_status == FMRADIO_PAUSED) ? SRCF_FMRADIO_PAUSED : SRCF_FMRADIO_PLAYING); #else if (radio_status == FMRADIO_OFF) radio_start(); #endif if(radio_preset_count() < 1 && yesno_pop(ID2P(LANG_FM_FIRST_AUTOSCAN))) presets_scan(NULL); preset_set_current(preset_find(curr_freq)); if(radio_current_preset() != -1) radio_mode = RADIO_PRESET_MODE; /* Load/update the skin at last, when fully initialzed, so that it can * display the right content from the beginning */ FOR_NB_SCREENS(i) skin_update(FM_SCREEN, i, SKIN_REFRESH_ALL); #ifndef HAVE_NOISY_IDLE_MODE cpu_idle_mode(true); #endif while(!done) { if(search_dir != 0) { curr_freq = step_freq(curr_freq, search_dir); update_type = SKIN_REFRESH_ALL; if(tuner_set(RADIO_SCAN_FREQUENCY, curr_freq)) { preset_set_current(preset_find(curr_freq)); remember_frequency(); end_search(); talk = true; } trigger_cpu_boost(); } if (!update_type) { cancel_cpu_boost(); } button = fms_do_button_loop(update_type>0); #ifndef HAVE_NOISY_IDLE_MODE if (button != ACTION_NONE) { cpu_idle_mode(false); button_timeout = current_tick + (2*HZ); } #endif switch(button) { case ACTION_FM_STOP: #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR) if(audio_status() == AUDIO_STATUS_RECORD) { audio_stop(); } else #endif { done = true; if(presets_have_changed()) { if(yesno_pop(ID2P(LANG_SAVE_CHANGES))) { presets_save(); } } } update_type = SKIN_REFRESH_NON_STATIC; break; #ifdef FM_RECORD case ACTION_FM_RECORD: #ifdef FM_RECORD_DBLPRE if (lastbutton != ACTION_FM_RECORD_DBLPRE) { rec_lastclick = 0; break; } if (current_tick - rec_lastclick > HZ/2) { rec_lastclick = current_tick; break; } #endif /* FM_RECORD_DBLPRE */ #ifndef SIMULATOR if(audio_status() == AUDIO_STATUS_RECORD) { rec_command(RECORDING_CMD_START_NEWFILE); update_type = SKIN_REFRESH_ALL; } else { rec_command(RECORDING_CMD_START); update_type = SKIN_REFRESH_ALL; } #if CONFIG_CODEC != SWCODEC last_seconds = 0; #endif #endif /* SIMULATOR */ break; #endif /* #ifdef FM_RECORD */ case ACTION_FM_EXIT: #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR) if(audio_status() == AUDIO_STATUS_RECORD) audio_stop(); #endif keep_playing = true; done = true; if(presets_have_changed()) { if(yesno_pop(ID2P(LANG_SAVE_CHANGES))) { presets_save(); } } break; case ACTION_STD_PREV: case ACTION_STD_NEXT: next_station(button == ACTION_STD_PREV ? -1 : 1); end_search(); update_type = SKIN_REFRESH_ALL; talk = true; break; case ACTION_STD_PREVREPEAT: case ACTION_STD_NEXTREPEAT: { int dir = search_dir; search_dir = button == ACTION_STD_PREVREPEAT ? -1 : 1; if (radio_mode != RADIO_SCAN_MODE) { preset_next(search_dir); end_search(); talk = true; } else if (dir == 0) { /* Starting auto scan */ tuner_set(RADIO_MUTE, 1); } update_type = SKIN_REFRESH_ALL; break; } case ACTION_SETTINGS_INC: case ACTION_SETTINGS_INCREPEAT: global_settings.volume++; setvol(); update_type = SKIN_REFRESH_NON_STATIC; break; case ACTION_SETTINGS_DEC: case ACTION_SETTINGS_DECREPEAT: global_settings.volume--; setvol(); update_type = SKIN_REFRESH_NON_STATIC; break; case ACTION_FM_PLAY: if (radio_status == FMRADIO_PLAYING) radio_pause(); else radio_start(); update_type = SKIN_REFRESH_NON_STATIC; talk = false; talk_shutup(); break; case ACTION_FM_MENU: fms_fix_displays(FMS_EXIT); do_menu(&radio_settings_menu, NULL, NULL, false); preset_set_current(preset_find(curr_freq)); fms_fix_displays(FMS_ENTER); update_type = SKIN_REFRESH_ALL; break; #ifdef FM_PRESET case ACTION_FM_PRESET: if(radio_preset_count() < 1) { splash(HZ, ID2P(LANG_FM_NO_PRESETS)); update_type = SKIN_REFRESH_ALL; break; } fms_fix_displays(FMS_EXIT); handle_radio_presets(); fms_fix_displays(FMS_ENTER); update_type = SKIN_REFRESH_ALL; break; #endif /* FM_PRESET */ #ifdef FM_FREEZE case ACTION_FM_FREEZE: if(!screen_freeze) { splash(HZ, str(LANG_FM_FREEZE)); screen_freeze = true; } else { update_type = SKIN_REFRESH_ALL; screen_freeze = false; } break; #endif /* FM_FREEZE */ case SYS_USB_CONNECTED: #if CONFIG_CODEC != SWCODEC /* Only accept USB connection when not recording */ if(audio_status() != AUDIO_STATUS_RECORD) #endif { default_event_handler(SYS_USB_CONNECTED); screen_freeze = true; /* Cosmetic: makes sure the radio screen doesn't redraw */ done = true; } break; #ifdef FM_MODE case ACTION_FM_MODE: if(radio_mode == RADIO_SCAN_MODE) { /* Force scan mode if there are no presets. */ if(radio_preset_count() > 0) radio_mode = RADIO_PRESET_MODE; } else radio_mode = RADIO_SCAN_MODE; update_type = SKIN_REFRESH_ALL; cond_talk_ids_fq(radio_mode ? LANG_PRESET : LANG_RADIO_SCAN_MODE); talk = true; break; #endif /* FM_MODE */ #ifdef FM_NEXT_PRESET case ACTION_FM_NEXT_PRESET: preset_next(1); end_search(); update_type = SKIN_REFRESH_ALL; talk = true; break; #endif #ifdef FM_PREV_PRESET case ACTION_FM_PREV_PRESET: preset_next(-1); end_search(); update_type = SKIN_REFRESH_ALL; talk = true; break; #endif case ACTION_NONE: update_type = SKIN_REFRESH_NON_STATIC; break; /* this case is used by the softlock feature * it requests a full update here */ case ACTION_REDRAW: skin_request_full_update(FM_SCREEN); break; default: default_event_handler(button); #ifdef HAVE_RDS_CAP if (tuner_get(RADIO_EVENT)) update_type = SKIN_REFRESH_ALL; #endif if (!tuner_get(RADIO_PRESENT)) { #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR) if(audio_status() == AUDIO_STATUS_RECORD) audio_stop(); #endif keep_playing = false; done = true; if(presets_have_changed()) { if(yesno_pop(ID2P(LANG_SAVE_CHANGES))) { radio_save_presets(); } } /* Clear the preset list on exit. */ preset_list_clear(); } break; } /*switch(button)*/ #ifdef FM_RECORD_DBLPRE if (button != ACTION_NONE) lastbutton = button; #endif #if CONFIG_CODEC != SWCODEC peak_meter_peek(); #endif if(!screen_freeze) { /* Only display the peak meter when not recording */ #if CONFIG_CODEC != SWCODEC if(TIME_AFTER(current_tick, timeout)) { timeout = current_tick + HZ; #else /* SWCODEC */ { #endif /* CONFIG_CODEC == SWCODEC */ /* keep "mono" from always being displayed when paused */ if (radio_status != FMRADIO_PAUSED) { stereo = tuner_get(RADIO_STEREO) && !global_settings.fm_force_mono; if(stereo != last_stereo) { update_type = SKIN_REFRESH_ALL; last_stereo = stereo; } } } #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR) seconds = audio_recorded_time() / HZ; if (update_type || seconds > last_seconds) { last_seconds = seconds; #else if (update_type) { #endif FOR_NB_SCREENS(i) skin_update(FM_SCREEN, i, update_type); if (update_type == (int)SKIN_REFRESH_ALL) skin_request_full_update(CUSTOM_STATUSBAR); } } update_type = 0; if (global_settings.talk_file && talk && radio_status == FMRADIO_PAUSED) { talk = false; bool enqueue = false; if (radio_mode == RADIO_SCAN_MODE) { talk_value_decimal(curr_freq, UNIT_INT, 6, enqueue); enqueue = true; } if (radio_current_preset() >= 0) preset_talk(radio_current_preset(), radio_mode == RADIO_PRESET_MODE, enqueue); } #if CONFIG_CODEC != SWCODEC if(audio_status() & AUDIO_STATUS_ERROR) { done = true; } #endif #ifndef HAVE_NOISY_IDLE_MODE if (TIME_AFTER(current_tick, button_timeout)) { cpu_idle_mode(true); } #endif } /*while(!done)*/ #ifndef SIMULATOR #if CONFIG_CODEC != SWCODEC if(audio_status() & AUDIO_STATUS_ERROR) { splash(0, str(LANG_DISK_FULL)); audio_error_clear(); while(1) { button = get_action(CONTEXT_FM|ALLOW_SOFTLOCK, TIMEOUT_BLOCK); if(button == ACTION_FM_STOP) break; } } audio_init_playback(); #endif /* CONFIG_CODEC != SWCODEC */ sound_settings_apply(); #endif /* SIMULATOR */ if(keep_playing) { /* Catch FMRADIO_PLAYING status for the sim. */ #ifndef SIMULATOR #if CONFIG_CODEC != SWCODEC /* Enable the Left and right A/D Converter */ audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN), sound_default(SOUND_RIGHT_GAIN), AUDIO_GAIN_LINEIN); mas_codec_writereg(6, 0x4000); #endif end_search(); #endif /* SIMULATOR */ } else { #if CONFIG_CODEC == SWCODEC audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK); #else radio_stop(); #endif } #ifndef HAVE_NOISY_IDLE_MODE cpu_idle_mode(false); #endif fms_fix_displays(FMS_EXIT); pop_current_activity(); in_screen = false; } /* radio_screen */ void toggle_mono_mode(bool mono) { tuner_set(RADIO_FORCE_MONO, mono); } void set_radio_region(int region) { #ifdef HAVE_RADIO_REGION tuner_set(RADIO_REGION, region); #endif next_station(0); remember_frequency(); (void)region; }
/* Voice thread message processing */ static enum voice_state voice_message(struct voice_thread_data *td) { if (quiet_counter > 0) queue_wait_w_tmo(&voice_queue, &td->ev, HZ/10); else queue_wait(&voice_queue, &td->ev); switch (td->ev.id) { case Q_VOICE_PLAY: LOGFQUEUE("voice < Q_VOICE_PLAY"); if (quiet_counter == 0) { /* Boost CPU now */ trigger_cpu_boost(); } else { /* Stop any clip still playing */ voice_stop_playback(); } quiet_counter = QUIET_COUNT; /* Copy the clip info */ td->vi = *(struct voice_info *)td->ev.data; /* Be sure audio buffer is initialized */ audio_restore_playback(AUDIO_WANT_VOICE); /* We need nothing more from the sending thread - let it run */ queue_reply(&voice_queue, 1); /* Make audio play more softly and set delay to return to normal playback level */ pcmbuf_soft_mode(true); /* Clean-start the decoder */ td->st = speex_decoder_init(&speex_wb_mode); /* Make bit buffer use our own buffer */ speex_bits_set_bit_buffer(&td->bits, td->vi.start, td->vi.size); speex_decoder_ctl(td->st, SPEEX_GET_LOOKAHEAD, &td->lookahead); return VOICE_STATE_DECODE; case SYS_TIMEOUT: if (voice_unplayed_frames()) { /* Waiting for PCM to finish */ break; } /* Drop through and stop the first time after clip runs out */ if (quiet_counter-- != QUIET_COUNT) { if (quiet_counter <= 0) pcmbuf_soft_mode(false); break; } /* Fall-through */ case Q_VOICE_STOP: LOGFQUEUE("voice < Q_VOICE_STOP"); cancel_cpu_boost(); voice_stop_playback(); break; /* No default: no other message ids are sent */ } return VOICE_STATE_MESSAGE; }
/** 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 */ } }
void buffering_thread(void) { bool filling = false; struct queue_event ev; while (true) { if (!filling) { cancel_cpu_boost(); } queue_wait_w_tmo(&buffering_queue, &ev, filling ? 5 : HZ/2); switch (ev.id) { case Q_START_FILL: LOGFQUEUE("buffering < Q_START_FILL %d", (int)ev.data); /* Call buffer callbacks here because this is one of two ways * to begin a full buffer fill */ send_event(BUFFER_EVENT_BUFFER_LOW, 0); shrink_buffer(); queue_reply(&buffering_queue, 1); filling |= buffer_handle((int)ev.data); break; case Q_BUFFER_HANDLE: LOGFQUEUE("buffering < Q_BUFFER_HANDLE %d", (int)ev.data); queue_reply(&buffering_queue, 1); buffer_handle((int)ev.data); break; case Q_RESET_HANDLE: LOGFQUEUE("buffering < Q_RESET_HANDLE %d", (int)ev.data); queue_reply(&buffering_queue, 1); reset_handle((int)ev.data); break; case Q_CLOSE_HANDLE: LOGFQUEUE("buffering < Q_CLOSE_HANDLE %d", (int)ev.data); queue_reply(&buffering_queue, close_handle((int)ev.data)); break; case Q_HANDLE_ADDED: LOGFQUEUE("buffering < Q_HANDLE_ADDED %d", (int)ev.data); /* A handle was added: the disk is spinning, so we can fill */ filling = true; break; case Q_BASE_HANDLE: LOGFQUEUE("buffering < Q_BASE_HANDLE %d", (int)ev.data); base_handle_id = (int)ev.data; break; #ifndef SIMULATOR case SYS_USB_CONNECTED: LOGFQUEUE("buffering < SYS_USB_CONNECTED"); usb_acknowledge(SYS_USB_CONNECTED_ACK); usb_wait_for_disconnect(&buffering_queue); break; #endif case SYS_TIMEOUT: LOGFQUEUE_SYS_TIMEOUT("buffering < SYS_TIMEOUT"); break; } update_data_counters(); /* If the buffer is low, call the callbacks to get new data */ if (num_handles > 0 && data_counters.useful <= conf_watermark) send_event(BUFFER_EVENT_BUFFER_LOW, 0); #if 0 /* TODO: This needs to be fixed to use the idle callback, disable it * for simplicity until its done right */ #if MEM > 8 /* If the disk is spinning, take advantage by filling the buffer */ else if (storage_disk_is_active() && queue_empty(&buffering_queue)) { if (num_handles > 0 && data_counters.useful <= high_watermark) send_event(BUFFER_EVENT_BUFFER_LOW, 0); if (data_counters.remaining > 0 && BUF_USED <= high_watermark) { /* This is a new fill, shrink the buffer up first */ if (!filling) shrink_buffer(); filling = fill_buffer(); update_data_counters(); } } #endif #endif if (queue_empty(&buffering_queue)) { if (filling) { if (data_counters.remaining > 0 && BUF_USED < buffer_len) filling = fill_buffer(); else if (data_counters.remaining == 0) filling = false; } else if (ev.id == SYS_TIMEOUT) { if (data_counters.remaining > 0 && data_counters.useful <= conf_watermark) { shrink_buffer(); filling = fill_buffer(); } } } } }
/* Voice thread message processing */ static void voice_message(struct voice_thread_data *td) { while (1) { switch (td->ev.id) { case Q_VOICE_PLAY: LOGFQUEUE("voice < Q_VOICE_PLAY"); /* Put up a block for completion signal */ voice_done = false; /* Copy the clip info */ td->vi = *(struct voice_info *)td->ev.data; /* Be sure audio buffer is initialized */ audio_restore_playback(AUDIO_WANT_VOICE); /* We need nothing more from the sending thread - let it run */ queue_reply(&voice_queue, 1); if (td->state == TSTATE_STOPPED) { /* Boost CPU now */ trigger_cpu_boost(); } else if (!playback_is_playing()) { /* Just voice, stop any clip still playing */ pcmbuf_play_stop(); } /* Clean-start the decoder */ td->st = speex_decoder_init(&speex_wb_mode); /* Make bit buffer use our own buffer */ speex_bits_set_bit_buffer(&td->bits, td->vi.start, td->vi.size); speex_decoder_ctl(td->st, SPEEX_GET_LOOKAHEAD, &td->lookahead); td->state = TSTATE_DECODE; return; case Q_VOICE_STOP: LOGFQUEUE("voice < Q_VOICE_STOP: %ld", td->ev.data); if (td->ev.data != 0 && !playback_is_playing()) { /* If not playing, it's just voice so stop pcm playback */ pcmbuf_play_stop(); } /* Cancel boost */ cancel_cpu_boost(); td->state = TSTATE_STOPPED; voice_done = true; break; case Q_VOICE_STATE: LOGFQUEUE("voice < Q_VOICE_STATE"); queue_reply(&voice_queue, td->state); if (td->state == TSTATE_STOPPED) break; /* Not in a playback state */ return; default: /* Default messages get a reply and thread continues with no * state transition */ LOGFQUEUE("voice < default"); if (td->state == TSTATE_STOPPED) break; /* Not in playback state */ queue_reply(&voice_queue, 0); return; } queue_wait(&voice_queue, &td->ev); } }