Index: firmware/pcm_record.c =================================================================== --- firmware/pcm_record.c (revision 12233) +++ firmware/pcm_record.c (working copy) @@ -46,6 +46,7 @@ /** These items may be implemented target specifically or need to be shared semi-privately **/ +extern struct thread_entry *codec_thread_p; /* the registered callback function for when more data is available */ volatile pcm_more_callback_type2 pcm_callback_more_ready = NULL; @@ -380,10 +381,6 @@ /** audio_* group **/ -/* NOTE: The following posting functions are really only single-thread safe - at the moment since a response to a particular message at a particular - position in the queue can't be distinguished */ - /** * Initializes recording - call before calling any other recording function */ @@ -801,12 +798,16 @@ static void pcmrec_flush(unsigned flush_num) { #ifdef HAVE_PRIORITY_SCHEDULING - static unsigned long last_flush_tick = 0; - unsigned long start_tick; - int num; - int prio; + static unsigned long last_flush_tick = 0; /* End time of last flush */ + static unsigned long st = 35*HZ/10; /* Fudged spinup time */ + unsigned long start_tick; /* When flush started */ + unsigned long prio_tick; /* Timeout for auto boost */ + int num; /* Current number of used encoder chunks + during write */ + int prio_pcmrec; /* Current thread priority for pcmrec */ + int prio_codec; /* Current thread priority for codec */ #endif - int num_ready; + int num_ready; /* Number of chunks ready at start */ int i; num_ready = enc_wr_index - enc_rd_index; @@ -825,42 +826,53 @@ if (ata_spinup_time != spinup_time) { /* spinup time has changed, calculate new write threshold */ - logf("new t spinup : %d", ata_spinup_time); - unsigned long st = spinup_time = ata_spinup_time; + logf("ata spinup: %d", ata_spinup_time); - /* write at 5s + st remaining in enc_buffer */ - if (st < 2*HZ) - st = 2*HZ; /* my drive is usually < 250 ticks :) */ +#ifdef HAVE_PRIORITY_SCHEDULING + /* panic boost thread priority if 1 second of ground is lost - + constant for any encoder configuration but keep the calcs + together */ + panic_threshold = enc_num_chunks - + (7*4*sample_rate + (enc_chunk_size-1)) / enc_chunk_size; + logf("panic at: %d", panic_threshold); +#endif + st = spinup_time = ata_spinup_time; + + /* write at 8s + st remaining in enc_buffer - range 10s to + 20s - default to 3.5s. */ + if (st == 0) + st = 35*HZ/10; + else if (st < 2*HZ) + st = 2*HZ; else if (st > 10*HZ) st = 10*HZ; write_threshold = enc_num_chunks - - (int)(((5ull*HZ + st)*4ull*sample_rate + (enc_chunk_size-1)) / - (enc_chunk_size*HZ)); - - if (write_threshold < 0) - write_threshold = 0; -#ifdef HAVE_PRIORITY_SCHEDULING - else if (write_threshold > panic_threshold) - write_threshold = panic_threshold; -#endif - logf("new wr thresh: %d", write_threshold); + ((8*HZ + st)*4*sample_rate + (enc_chunk_size-1)*HZ) / + (enc_chunk_size*HZ); + logf("write at: %d", write_threshold); } + /* Enough available? No? Then leave */ if (num_ready < write_threshold) return; #ifdef HAVE_PRIORITY_SCHEDULING /* if we're getting called too much and this isn't forced, boost stat */ - if (current_tick - last_flush_tick < HZ/2) + if (TIME_BEFORE(current_tick, last_flush_tick + HZ/2)) + { + logf("too frequent flush"); num = panic_threshold; + } #endif } #ifdef HAVE_PRIORITY_SCHEDULING - start_tick = current_tick; - prio = -1; + start_tick = current_tick; + prio_tick = start_tick + 8*HZ + st; + prio_pcmrec = -1; + prio_codec = -1; #endif logf("writing: %d (%d)", num_ready, flush_num); @@ -870,12 +882,17 @@ for (i = 0; i < num_ready; i++) { #ifdef HAVE_PRIORITY_SCHEDULING - if (prio == -1 && (num >= panic_threshold || - current_tick - start_tick > 10*HZ)) + if (prio_codec == -1 && (num >= panic_threshold || + TIME_AFTER(current_tick, prio_tick))) { - /* losing ground - boost priority until finished */ - logf("pcmrec: boost priority"); - prio = thread_set_priority(NULL, thread_get_priority(NULL)-1); + /* losing ground or holding without progress - boost + priority until finished */ + logf("pcmrec: boost (%s)", + num >= panic_threshold ? "num" : "time"); + prio_pcmrec = thread_set_priority(NULL, + thread_get_priority(NULL) - 1); + prio_codec = thread_set_priority(codec_thread_p, + thread_get_priority(codec_thread_p) - 1); } #endif @@ -904,14 +921,24 @@ break; #ifdef HAVE_PRIORITY_SCHEDULING - if (prio == -1) + if (prio_pcmrec == -1) { + /* Check if number of chunks is growing on us */ num = enc_wr_index - enc_rd_index; if (num < 0) num += enc_num_chunks; } +#if 0 + else + { + /* Do some yielding so as not to hog so much execution time + or else the codec could lose ground if we're not done soon */ + yield(); + } #endif - /* no yielding, the file apis called in the codecs do that */ +#endif + /* no yielding if not priority boosted, the file apis called in the + codecs do that sufficiently */ } /* end for */ /* sync file */ @@ -921,11 +948,12 @@ cpu_boost(false); #ifdef HAVE_PRIORITY_SCHEDULING - if (prio != -1) + if (prio_pcmrec != -1) { - /* return to original priority */ + /* return to original priorities */ logf("pcmrec: unboost priority"); - thread_set_priority(NULL, prio); + thread_set_priority(NULL, prio_pcmrec); + thread_set_priority(codec_thread_p, prio_codec); } last_flush_tick = current_tick; /* save tick when we left */ @@ -1137,7 +1165,7 @@ buffer = audio_get_recording_buffer(&rec_buffer_size); /* Line align pcm_buffer 2^4=16 bytes */ - pcm_buffer = (unsigned char *)ALIGN_UP_P2((unsigned long)buffer, 4); + pcm_buffer = (unsigned char *)ALIGN_UP_P2((uintptr_t)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 */ @@ -1243,8 +1271,8 @@ accum_rec_bytes = 0; accum_pcm_samples = 0; #endif - spinup_time = -1; - warnings = 0; /* reset warnings */ + spinup_time = -1; /* force recheck of spinup time */ + warnings = 0; /* reset warnings */ rd_start = enc_wr_index; pre_sample_ticks = 0; @@ -1568,16 +1596,6 @@ *wrap_id_p = ENC_CHUNK_MAGIC; #endif /* PCMREC_PARANOID */ -#ifdef HAVE_PRIORITY_SCHEDULING - /* panic boost thread priority at 1 second remaining */ - panic_threshold = enc_num_chunks - - (4*sample_rate + (enc_chunk_size-1)) / enc_chunk_size; - if (panic_threshold < 0) - panic_threshold = 0; - - logf("panic thr:%d", panic_threshold); -#endif - /** set OUT parameters **/ params->enc_buffer = enc_buffer; params->buf_chunk_size = enc_chunk_size; @@ -1691,7 +1709,7 @@ int enc_pcm_buf_near_empty(void) { /* less than 1sec raw data? => unboost encoder */ - int wp = dma_wr_pos; + 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 */ @@ -1700,7 +1718,7 @@ /* TODO: this really should give the actual size returned */ unsigned char * enc_get_pcm_data(size_t size) { - int wp = dma_wr_pos; + int wp = dma_wr_pos; size_t avail = (wp - pcm_rd_pos) & PCM_CHUNK_MASK; /* limit the requested pcm data size */ @@ -1713,7 +1731,6 @@ int next_pos = (pcm_rd_pos + size) & PCM_CHUNK_MASK; SET_PCM_POS(pcm_rd_pos, next_pos); - pcm_rd_pos = next_pos; /* ptr must point to continous data at wraparound position */ if ((size_t)pcm_rd_pos < size) @@ -1732,14 +1749,14 @@ /* puts some pcm data back in the queue */ size_t enc_unget_pcm_data(size_t size) { - /* can't let DMA advance write position when doing this */ - int level = set_irq_level(HIGHEST_IRQ_LEVEL); + int wp = dma_wr_pos; + size_t old_avail = ((pcm_rd_pos - wp) & PCM_CHUNK_MASK) - + 2*PCM_CHUNK_SIZE; - if (pcm_rd_pos != dma_wr_pos) + /* allow one interrupt to occur during this call and not have the + new read position inside the DMA destination chunk */ + if ((ssize_t)old_avail > 0) { - /* disallow backing up into current DMA write chunk */ - size_t old_avail = (pcm_rd_pos - dma_wr_pos - PCM_CHUNK_SIZE) - & PCM_CHUNK_MASK; int next_pos; /* limit size to amount of old data remaining */ @@ -1748,11 +1765,11 @@ next_pos = (pcm_rd_pos - size) & PCM_CHUNK_MASK; SET_PCM_POS(pcm_rd_pos, next_pos); + + return size; } - set_irq_level(level); - - return size; + return 0; } /* enc_unget_pcm_data */ /** Low level pcm recording apis **/