From 0d768a37f970b40575ef2be169e670fd6b5d424a Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Thu, 7 Dec 2006 19:34:26 +0000 Subject: [PATCH] SWCODEC Recording: 1) Fix minor bug of not subtracting line aligment adjustment from buffer size. 2) Handle stop and pause better and let pcmrec thread lock the DMA as that could cause prerecording to get disabled internally 3) Make sure to snapshot DMA write index to ensure compiler doesn't perform multiple access when calculating available data (probably just paranoia on my part) 4) Handle USB connect in recording thread a little better by resetting hardware to defaults after closing 5) Make power managment stop recording properly when powering off (ie. no yield() from interrupt handler! :) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11685 a1c6a512-1295-4272-9138-f99709370657 --- apps/misc.c | 21 ++++++++++++--- firmware/pcm_record.c | 61 ++++++++++++++++++++++--------------------- firmware/powermgmt.c | 19 +++++++------- 3 files changed, 59 insertions(+), 42 deletions(-) diff --git a/apps/misc.c b/apps/misc.c index 2f3251431b..4ea8568018 100644 --- a/apps/misc.c +++ b/apps/misc.c @@ -578,6 +578,9 @@ static bool clean_shutdown(void (*callback)(void *), void *parameter) if(!charger_inserted()) #endif { + bool batt_crit = battery_level_critical(); + int audio_stat = audio_status(); + FOR_NB_SCREENS(i) screens[i].clear_display(); #ifdef X5_BACKLIGHT_SHUTDOWN @@ -604,11 +607,23 @@ static bool clean_shutdown(void (*callback)(void *), void *parameter) } if (global_settings.fade_on_stop - && (audio_status() & AUDIO_STATUS_PLAY)) + && (audio_stat & AUDIO_STATUS_PLAY)) { fade(0); } - + +#if defined(HAVE_RECORDING) && CONFIG_CODEC == SWCODEC + if (!batt_crit && (audio_stat & AUDIO_STATUS_RECORD)) + { + audio_stop_recording(); + while(audio_status() & AUDIO_STATUS_RECORD) + sleep(1); + } + + audio_close_recording(); +#endif + /* audio_stop_recording == audio_stop for HWCODEC */ + audio_stop(); while (audio_status()) sleep(1); @@ -616,7 +631,7 @@ static bool clean_shutdown(void (*callback)(void *), void *parameter) if (callback != NULL) callback(parameter); - if (!battery_level_critical()) /* do not save on critical battery */ + if (!batt_crit) /* do not save on critical battery */ system_flush(); #ifdef HAVE_EEPROM_SETTINGS if (firmware_settings.initialized) diff --git a/firmware/pcm_record.c b/firmware/pcm_record.c index a72641baa6..93a6e067b1 100644 --- a/firmware/pcm_record.c +++ b/firmware/pcm_record.c @@ -244,6 +244,14 @@ static int pcm_rec_have_more(int status) return 0; } /* pcm_rec_have_more */ +static void reset_hardware(void) +{ + /* reset pcm to defaults (playback only) */ + pcm_set_frequency(HW_SAMPR_DEFAULT); + audio_set_output_source(AUDIO_SRC_PLAYBACK); + pcm_apply_settings(true); +} + /** pcm_rec_* group **/ void pcm_rec_error_clear(void) { @@ -328,10 +336,7 @@ void audio_close_recording(void) { pcm_thread_wait_for_stop(); pcm_thread_sync_post(PCMREC_CLOSE, NULL); - /* reset pcm to defaults (playback only) */ - pcm_set_frequency(HW_SAMPR_DEFAULT); - audio_set_output_source(AUDIO_SRC_PLAYBACK); - pcm_apply_settings(true); + reset_hardware(); audio_remove_encoder(); } /* audio_close_recording */ @@ -460,10 +465,6 @@ void audio_stop_recording(void) logf("audio_stop_recording"); pcm_thread_wait_for_stop(); - - if (is_recording) - dma_lock = true; /* fix DMA write ptr at current position */ - pcm_thread_sync_post(PCMREC_STOP, NULL); logf("audio_stop_recording done"); @@ -474,11 +475,8 @@ void audio_pause_recording(void) logf("audio_pause_recording"); pcm_thread_wait_for_stop(); - - if (is_recording) - dma_lock = true; /* fix DMA write ptr at current position */ - pcm_thread_sync_post(PCMREC_PAUSE, NULL); + logf("audio_pause_recording done"); } /* audio_pause_recording */ @@ -1006,6 +1004,8 @@ static void pcmrec_new_stream(const char *filename, /* next file name */ /* PCMREC_INIT */ static void pcmrec_init(void) { + unsigned char *buffer; + rec_fdata.rec_file = -1; /* pcm FIFO */ @@ -1035,11 +1035,13 @@ static void pcmrec_init(void) is_stopping = false; is_error = false; - pcm_buffer = audio_get_recording_buffer(&rec_buffer_size); + buffer = audio_get_recording_buffer(&rec_buffer_size); /* Line align pcm_buffer 2^4=16 bytes */ - pcm_buffer = (unsigned char *)ALIGN_UP_P2((unsigned)pcm_buffer, 4); + pcm_buffer = (unsigned char *)ALIGN_UP_P2((unsigned long)buffer, 4); enc_buffer = pcm_buffer + ALIGN_UP_P2(PCM_NUM_CHUNKS*PCM_CHUNK_SIZE + PCM_MAX_FEED_SIZE, 2); + /* Adjust available buffer for possible align advancement */ + rec_buffer_size -= pcm_buffer - buffer; pcm_init_recording(); pcm_thread_signal_event(PCMREC_INIT); @@ -1132,8 +1134,8 @@ static void pcmrec_start(const char *filename) pcmrec_fnq_set_empty(); } - dma_lock = false; - is_paused = false; + dma_lock = false; + is_paused = false; is_recording = true; pcmrec_new_stream(filename, @@ -1187,11 +1189,8 @@ static void pcmrec_finish_stop(void) pcmrec_flush(-1); /* wait for encoder to finish remaining data */ - if (!is_error) - { - while (!wav_queue_empty) - yield(); - } + while (!is_error && !wav_queue_empty) + yield(); /* end stream at last data */ pcmrec_new_stream(NULL, CHUNKF_END_FILE, 0); @@ -1307,7 +1306,7 @@ static void pcmrec_thread(void) while(1) { - if (is_recording) + if (is_recording && !is_stopping) { /* Poll periodically to flush data */ queue_wait_w_tmo(&pcmrec_queue, &ev, HZ/5); @@ -1363,12 +1362,12 @@ static void pcmrec_thread(void) break; case SYS_USB_CONNECTED: - if (!is_recording) - { - pcmrec_close(); - usb_acknowledge(SYS_USB_CONNECTED_ACK); - usb_wait_for_disconnect(&pcmrec_queue); - } + if (is_recording) + break; + pcmrec_close(); + reset_hardware(); + usb_acknowledge(SYS_USB_CONNECTED_ACK); + usb_wait_for_disconnect(&pcmrec_queue); break; } /* end switch */ } /* end while */ @@ -1554,7 +1553,8 @@ void enc_finish_chunk(void) int enc_pcm_buf_near_empty(void) { /* less than 1sec raw data? => unboost encoder */ - size_t avail = (dma_wr_pos - pcm_rd_pos) & PCM_CHUNK_MASK; + int wp = dma_wr_pos; + size_t avail = (wp - pcm_rd_pos) & PCM_CHUNK_MASK; return avail < (sample_rate << 2) ? 1 : 0; } /* enc_pcm_buf_near_empty */ @@ -1562,7 +1562,8 @@ int enc_pcm_buf_near_empty(void) /* TODO: this really should give the actual size returned */ unsigned char * enc_get_pcm_data(size_t size) { - size_t avail = (dma_wr_pos - pcm_rd_pos) & PCM_CHUNK_MASK; + int wp = dma_wr_pos; + size_t avail = (wp - pcm_rd_pos) & PCM_CHUNK_MASK; /* limit the requested pcm data size */ if (size > PCM_MAX_FEED_SIZE) diff --git a/firmware/powermgmt.c b/firmware/powermgmt.c index e59e2d50b9..458745f0d9 100644 --- a/firmware/powermgmt.c +++ b/firmware/powermgmt.c @@ -1266,16 +1266,17 @@ void sys_poweroff(void) { logf("sys_poweroff()"); /* If the main thread fails to shut down the system, we will force a - power off after an 20 second timeout */ - shutdown_timeout = HZ*20; -#if defined(HAVE_RECORDING) - int audio_stat = audio_status(); - if (audio_stat & AUDIO_STATUS_RECORD) { - audio_stop_recording(); - shutdown_timeout += 8*HZ; - } + power off after an 20 second timeout - 28 seconds if recording */ +#if defined(IAUDIO_X5) && !defined (SIMULATOR) + if (shutdown_timeout == 0) + pcf50606_reset_timeout(); /* Reset timer on first attempt only */ #endif - +#ifdef HAVE_RECORDING + if (audio_status() & AUDIO_STATUS_RECORD) + shutdown_timeout += HZ*8; +#endif + + shutdown_timeout = HZ*20; queue_post(&button_queue, SYS_POWEROFF, NULL); }