summaryrefslogtreecommitdiff
path: root/firmware/pcm_record.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/pcm_record.c')
-rw-r--r--firmware/pcm_record.c651
1 files changed, 405 insertions, 246 deletions
diff --git a/firmware/pcm_record.c b/firmware/pcm_record.c
index 98473a3870..85ab7caafc 100644
--- a/firmware/pcm_record.c
+++ b/firmware/pcm_record.c
@@ -46,6 +46,7 @@
46 46
47/** These items may be implemented target specifically or need to 47/** These items may be implemented target specifically or need to
48 be shared semi-privately **/ 48 be shared semi-privately **/
49extern struct thread_entry *codec_thread_p;
49 50
50/* the registered callback function for when more data is available */ 51/* the registered callback function for when more data is available */
51volatile pcm_more_callback_type2 pcm_callback_more_ready = NULL; 52volatile pcm_more_callback_type2 pcm_callback_more_ready = NULL;
@@ -57,6 +58,14 @@ static bool is_recording; /* We are recording */
57static bool is_paused; /* We have paused */ 58static bool is_paused; /* We have paused */
58static unsigned long errors; /* An error has occured */ 59static unsigned long errors; /* An error has occured */
59static unsigned long warnings; /* Warning */ 60static unsigned long warnings; /* Warning */
61static int flush_interrupts = 0; /* Number of messages queued that
62 should interrupt a flush in
63 progress -
64 for a safety net and a prompt
65 response to stop, split and pause
66 requests -
67 only interrupts a flush initiated
68 by pcmrec_flush(0) */
60 69
61/** Stats on encoded data for current file **/ 70/** Stats on encoded data for current file **/
62static size_t num_rec_bytes; /* Num bytes recorded */ 71static size_t num_rec_bytes; /* Num bytes recorded */
@@ -179,31 +188,62 @@ static unsigned char *pcm_buffer; /* circular recording buffer */
179static unsigned char *enc_buffer; /* circular encoding buffer */ 188static unsigned char *enc_buffer; /* circular encoding buffer */
180static volatile int dma_wr_pos; /* current DMA write pos */ 189static volatile int dma_wr_pos; /* current DMA write pos */
181static int pcm_rd_pos; /* current PCM read pos */ 190static int pcm_rd_pos; /* current PCM read pos */
191static int pcm_enc_pos; /* position encoder is processing */
182static volatile bool dma_lock; /* lock DMA write position */ 192static volatile bool dma_lock; /* lock DMA write position */
183static int enc_wr_index; /* encoder chunk write index */ 193static int enc_wr_index; /* encoder chunk write index */
184static int enc_rd_index; /* encoder chunk read index */ 194static int enc_rd_index; /* encoder chunk read index */
185static int enc_num_chunks; /* number of chunks in ringbuffer */ 195static int enc_num_chunks; /* number of chunks in ringbuffer */
186static size_t enc_chunk_size; /* maximum encoder chunk size */ 196static size_t enc_chunk_size; /* maximum encoder chunk size */
187static unsigned long enc_sample_rate; /* sample rate used by encoder */ 197static unsigned long enc_sample_rate; /* sample rate used by encoder */
188static bool wav_queue_empty; /* all wav chunks processed? */ 198static bool pcmrec_context = false; /* called by pcmrec thread? */
199static bool pcm_buffer_empty; /* all pcm chunks processed? */
189 200
190/** file flushing **/ 201/** file flushing **/
191static int write_threshold; /* max chunk limit for data flush */ 202static int low_watermark; /* Low watermark to stop flush */
192static int spinup_time = -1;/* last ata_spinup_time */ 203static int high_watermark; /* max chunk limit for data flush */
204static unsigned long spinup_time = 35*HZ/10; /* Fudged spinup time */
205static int last_ata_spinup_time = -1;/* previous spin time used */
193#ifdef HAVE_PRIORITY_SCHEDULING 206#ifdef HAVE_PRIORITY_SCHEDULING
194static int panic_threshold; /* boost thread prio when here */ 207static int flood_watermark; /* boost thread priority when here */
195#endif 208#endif
196 209
210/* Constants that control watermarks */
211#define LOW_SECONDS 1 /* low watermark time till empty */
212#define MINI_CHUNKS 10 /* chunk count for mini flush */
213#ifdef HAVE_PRIORITY_SCHEDULING
214#define PRIO_SECONDS 10 /* max flush time before priority boost */
215#endif
216#if MEM <= 16
217#define PANIC_SECONDS 5 /* flood watermark time until full */
218#define FLUSH_SECONDS 7 /* flush watermark time until full */
219#else
220#define PANIC_SECONDS 8
221#define FLUSH_SECONDS 10
222#endif /* MEM */
223
197/** encoder events **/ 224/** encoder events **/
198static void (*enc_events_callback)(enum enc_events event, void *data); 225static void (*enc_events_callback)(enum enc_events event, void *data);
199 226
200/** Path queue for files to write **/ 227/** Path queue for files to write **/
201#define FNQ_MIN_NUM_PATHS 16 /* minimum number of paths to hold */ 228#define FNQ_MIN_NUM_PATHS 16 /* minimum number of paths to hold */
229#define FNQ_MAX_NUM_PATHS 64 /* maximum number of paths to hold */
202static unsigned char *fn_queue; /* pointer to first filename */ 230static unsigned char *fn_queue; /* pointer to first filename */
203static ssize_t fnq_size; /* capacity of queue in bytes */ 231static ssize_t fnq_size; /* capacity of queue in bytes */
204static int fnq_rd_pos; /* current read position */ 232static int fnq_rd_pos; /* current read position */
205static int fnq_wr_pos; /* current write position */ 233static int fnq_wr_pos; /* current write position */
206 234
235enum
236{
237 PCMREC_FLUSH_INTERRUPTABLE = 0x8000000, /* Flush can be interrupted by
238 incoming messages - combine
239 with other constants */
240 PCMREC_FLUSH_ALL = 0x7ffffff, /* Flush all files */
241 PCMREC_FLUSH_MINI = 0x7fffffe, /* Flush a small number of
242 chunks */
243 PCMREC_FLUSH_IF_HIGH = 0x0000000, /* Flush if high watermark
244 reached */
245};
246
207/** extra debugging info positioned away from other vars **/ 247/** extra debugging info positioned away from other vars **/
208#ifdef PCMREC_PARANOID 248#ifdef PCMREC_PARANOID
209static unsigned long *wrap_id_p; /* magic at end of encoding buffer */ 249static unsigned long *wrap_id_p; /* magic at end of encoding buffer */
@@ -220,6 +260,7 @@ static struct event_queue pcmrec_queue;
220static struct queue_sender_list pcmrec_queue_send; 260static struct queue_sender_list pcmrec_queue_send;
221static long pcmrec_stack[3*DEFAULT_STACK_SIZE/sizeof(long)]; 261static long pcmrec_stack[3*DEFAULT_STACK_SIZE/sizeof(long)];
222static const char pcmrec_thread_name[] = "pcmrec"; 262static const char pcmrec_thread_name[] = "pcmrec";
263static struct thread_entry *pcmrec_thread_p;
223 264
224static void pcmrec_thread(void); 265static void pcmrec_thread(void);
225 266
@@ -261,8 +302,9 @@ static int pcm_rec_have_more(int status)
261 /* advance write position */ 302 /* advance write position */
262 int next_pos = (dma_wr_pos + PCM_CHUNK_SIZE) & PCM_CHUNK_MASK; 303 int next_pos = (dma_wr_pos + PCM_CHUNK_SIZE) & PCM_CHUNK_MASK;
263 304
264 /* set pcm ovf if read position is inside current write chunk */ 305 /* set pcm ovf if processing start position is inside current
265 if ((unsigned)(pcm_rd_pos - next_pos) < PCM_CHUNK_SIZE) 306 write chunk */
307 if ((unsigned)(pcm_enc_pos - next_pos) < PCM_CHUNK_SIZE)
266 warnings |= PCMREC_W_PCM_BUFFER_OVF; 308 warnings |= PCMREC_W_PCM_BUFFER_OVF;
267 309
268#ifdef PCMREC_PARANOID 310#ifdef PCMREC_PARANOID
@@ -374,16 +416,13 @@ void pcm_rec_init(void)
374{ 416{
375 queue_init(&pcmrec_queue, true); 417 queue_init(&pcmrec_queue, true);
376 queue_enable_queue_send(&pcmrec_queue, &pcmrec_queue_send); 418 queue_enable_queue_send(&pcmrec_queue, &pcmrec_queue_send);
377 create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack), 419 pcmrec_thread_p =
378 pcmrec_thread_name IF_PRIO(, PRIORITY_RECORDING)); 420 create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack),
421 pcmrec_thread_name IF_PRIO(, PRIORITY_RECORDING));
379} /* pcm_rec_init */ 422} /* pcm_rec_init */
380 423
381/** audio_* group **/ 424/** audio_* group **/
382 425
383/* NOTE: The following posting functions are really only single-thread safe
384 at the moment since a response to a particular message at a particular
385 position in the queue can't be distinguished */
386
387/** 426/**
388 * Initializes recording - call before calling any other recording function 427 * Initializes recording - call before calling any other recording function
389 */ 428 */
@@ -421,6 +460,8 @@ void audio_set_recording_options(struct audio_recording_options *options)
421void audio_record(const char *filename) 460void audio_record(const char *filename)
422{ 461{
423 logf("audio_record: %s", filename); 462 logf("audio_record: %s", filename);
463 flush_interrupts++;
464 logf("flush int: %d", flush_interrupts);
424 queue_send(&pcmrec_queue, PCMREC_RECORD, (intptr_t)filename); 465 queue_send(&pcmrec_queue, PCMREC_RECORD, (intptr_t)filename);
425 logf("audio_record_done"); 466 logf("audio_record_done");
426} /* audio_record */ 467} /* audio_record */
@@ -431,6 +472,8 @@ void audio_record(const char *filename)
431void audio_stop_recording(void) 472void audio_stop_recording(void)
432{ 473{
433 logf("audio_stop_recording"); 474 logf("audio_stop_recording");
475 flush_interrupts++;
476 logf("flush int: %d", flush_interrupts);
434 queue_send(&pcmrec_queue, PCMREC_STOP, 0); 477 queue_send(&pcmrec_queue, PCMREC_STOP, 0);
435 logf("audio_stop_recording done"); 478 logf("audio_stop_recording done");
436} /* audio_stop_recording */ 479} /* audio_stop_recording */
@@ -441,6 +484,8 @@ void audio_stop_recording(void)
441void audio_pause_recording(void) 484void audio_pause_recording(void)
442{ 485{
443 logf("audio_pause_recording"); 486 logf("audio_pause_recording");
487 flush_interrupts++;
488 logf("flush int: %d", flush_interrupts);
444 queue_send(&pcmrec_queue, PCMREC_PAUSE, 0); 489 queue_send(&pcmrec_queue, PCMREC_PAUSE, 0);
445 logf("audio_pause_recording done"); 490 logf("audio_pause_recording done");
446} /* audio_pause_recording */ 491} /* audio_pause_recording */
@@ -787,95 +832,166 @@ static void pcmrec_end_file(void)
787} /* pcmrec_end_file */ 832} /* pcmrec_end_file */
788 833
789/** 834/**
835 * Update buffer watermarks with spinup time compensation
836 *
837 * All this assumes reasonable data rates, chunk sizes and sufficient
838 * memory for the most part. Some dumb checks are included but perhaps
839 * are pointless since this all will break down at extreme limits that
840 * are currently not applicable to any supported device.
841 */
842static void pcmrec_refresh_watermarks(void)
843{
844 logf("ata spinup: %d", ata_spinup_time);
845
846 /* set the low mark for when flushing stops if automatic */
847 low_watermark = (LOW_SECONDS*4*sample_rate + (enc_chunk_size-1))
848 / enc_chunk_size;
849 logf("low wmk: %d", low_watermark);
850
851#ifdef HAVE_PRIORITY_SCHEDULING
852 /* panic boost thread priority if 2 seconds of ground is lost -
853 this allows encoder to boost with just under a second of
854 pcm data (if not yet full enough to boost itself)
855 and not falsely trip the alarm. */
856 flood_watermark = enc_num_chunks -
857 (PANIC_SECONDS*4*sample_rate + (enc_chunk_size-1))
858 / enc_chunk_size;
859
860 if (flood_watermark < low_watermark)
861 {
862 logf("warning: panic < low");
863 flood_watermark = low_watermark;
864 }
865
866 logf("flood at: %d", flood_watermark);
867#endif
868 spinup_time = last_ata_spinup_time = ata_spinup_time;
869
870 /* write at 8s + st remaining in enc_buffer - range 12s to
871 20s total - default to 3.5s spinup. */
872 if (spinup_time == 0)
873 spinup_time = 35*HZ/10; /* default - cozy */
874 else if (spinup_time < 2*HZ)
875 spinup_time = 2*HZ; /* ludicrous - ramdisk? */
876 else if (spinup_time > 10*HZ)
877 spinup_time = 10*HZ; /* do you have a functioning HD? */
878
879 /* try to start writing with 10s remaining after disk spinup */
880 high_watermark = enc_num_chunks -
881 ((FLUSH_SECONDS*HZ + spinup_time)*4*sample_rate +
882 (enc_chunk_size-1)*HZ) / (enc_chunk_size*HZ);
883
884 if (high_watermark < low_watermark)
885 {
886 high_watermark = low_watermark;
887 low_watermark /= 2;
888 logf("warning: low 'write at'");
889 }
890
891 logf("write at: %d", high_watermark);
892} /* pcmrec_refresh_watermarks */
893
894/**
790 * Process the chunks 895 * Process the chunks
791 * 896 *
792 * This function is called when queue_get_w_tmo times out. 897 * This function is called when queue_get_w_tmo times out.
793 * 898 *
794 * Set flush_num to the number of files to flush to disk. 899 * Set flush_num to the number of files to flush to disk or to
795 * flush_num = -1 to flush all available chunks to disk. 900 * a PCMREC_FLUSH_* constant.
796 * flush_num = 0 normal write thresholding
797 * flush_num = 1 or greater - all available chunks of current file plus
798 * flush_num file starts if first chunk has been processed.
799 *
800 */ 901 */
801static void pcmrec_flush(unsigned flush_num) 902static void pcmrec_flush(unsigned flush_num)
802{ 903{
803#ifdef HAVE_PRIORITY_SCHEDULING 904#ifdef HAVE_PRIORITY_SCHEDULING
804 static unsigned long last_flush_tick = 0; 905 static unsigned long last_flush_tick; /* tick when function returned */
805 unsigned long start_tick; 906 unsigned long start_tick; /* When flush started */
806 int num; 907 unsigned long prio_tick; /* Timeout for auto boost */
807 int prio; 908 int prio_pcmrec; /* Current thread priority for pcmrec */
909 int prio_codec; /* Current thread priority for codec */
808#endif 910#endif
809 int num_ready; 911 int num_ready; /* Number of chunks ready at start */
810 int i; 912 unsigned remaining; /* Number of file starts remaining */
913 unsigned chunks_flushed; /* Chunks flushed (for mini flush only) */
914 bool interruptable; /* Flush can be interupted */
811 915
812 num_ready = enc_wr_index - enc_rd_index; 916 num_ready = enc_wr_index - enc_rd_index;
813 if (num_ready < 0) 917 if (num_ready < 0)
814 num_ready += enc_num_chunks; 918 num_ready += enc_num_chunks;
815 919
816#ifdef HAVE_PRIORITY_SCHEDULING 920 /* save interruptable flag and remove it to get the actual count */
817 num = num_ready; 921 interruptable = (flush_num & PCMREC_FLUSH_INTERRUPTABLE) != 0;
818#endif 922 flush_num &= ~PCMREC_FLUSH_INTERRUPTABLE;
819 923
820 if (flush_num == 0) 924 if (flush_num == 0)
821 { 925 {
822 if (!is_recording) 926 if (!is_recording)
823 return; 927 return;
824 928
825 if (ata_spinup_time != spinup_time) 929 if (ata_spinup_time != last_ata_spinup_time)
826 { 930 pcmrec_refresh_watermarks();
827 /* spinup time has changed, calculate new write threshold */
828 logf("new t spinup : %d", ata_spinup_time);
829 unsigned long st = spinup_time = ata_spinup_time;
830
831 /* write at 5s + st remaining in enc_buffer */
832 if (st < 2*HZ)
833 st = 2*HZ; /* my drive is usually < 250 ticks :) */
834 else if (st > 10*HZ)
835 st = 10*HZ;
836
837 write_threshold = enc_num_chunks -
838 (int)(((5ull*HZ + st)*4ull*sample_rate + (enc_chunk_size-1)) /
839 (enc_chunk_size*HZ));
840
841 if (write_threshold < 0)
842 write_threshold = 0;
843#ifdef HAVE_PRIORITY_SCHEDULING
844 else if (write_threshold > panic_threshold)
845 write_threshold = panic_threshold;
846#endif
847 logf("new wr thresh: %d", write_threshold);
848 }
849 931
850 if (num_ready < write_threshold) 932 /* enough available? no? then leave */
933 if (num_ready < high_watermark)
851 return; 934 return;
935 } /* endif (flush_num == 0) */
852 936
853#ifdef HAVE_PRIORITY_SCHEDULING 937#ifdef HAVE_PRIORITY_SCHEDULING
938 start_tick = current_tick;
939 prio_tick = start_tick + PRIO_SECONDS*HZ + spinup_time;
940
941 if (flush_num == 0 && TIME_BEFORE(current_tick, last_flush_tick + HZ/2))
942 {
854 /* if we're getting called too much and this isn't forced, 943 /* if we're getting called too much and this isn't forced,
855 boost stat */ 944 boost stat by expiring timeout in advance */
856 if (current_tick - last_flush_tick < HZ/2) 945 logf("too frequent flush");
857 num = panic_threshold; 946 prio_tick = current_tick - 1;
858#endif
859 } 947 }
860 948
861#ifdef HAVE_PRIORITY_SCHEDULING 949 prio_pcmrec = -1;
862 start_tick = current_tick; 950 prio_codec = -1; /* GCC is too stoopid to figure out it doesn't
863 prio = -1; 951 need init */
864#endif 952#endif
865 953
866 logf("writing: %d (%d)", num_ready, flush_num); 954 logf("writing:%d(%d):%s%s", num_ready, flush_num,
955 interruptable ? "i" : "",
956 flush_num == PCMREC_FLUSH_MINI ? "m" : "");
867 957
868 cpu_boost(true); 958 cpu_boost(true);
869 959
870 for (i = 0; i < num_ready; i++) 960 remaining = flush_num;
961 chunks_flushed = 0;
962
963 while (num_ready > 0)
871 { 964 {
965 /* check current number of encoder chunks */
966 int num = enc_wr_index - enc_rd_index;
967 if (num < 0)
968 num += enc_num_chunks;
969
970 if (num <= low_watermark &&
971 (flush_num == PCMREC_FLUSH_IF_HIGH || num <= 0))
972 {
973 logf("low data: %d", num);
974 break; /* data remaining is below threshold */
975 }
976
977 if (interruptable && flush_interrupts > 0)
978 {
979 logf("int at: %d", num);
980 break; /* interrupted */
981 }
982
872#ifdef HAVE_PRIORITY_SCHEDULING 983#ifdef HAVE_PRIORITY_SCHEDULING
873 if (prio == -1 && (num >= panic_threshold || 984 if (prio_pcmrec == -1 && (num >= flood_watermark ||
874 current_tick - start_tick > 10*HZ)) 985 TIME_AFTER(current_tick, prio_tick)))
875 { 986 {
876 /* losing ground - boost priority until finished */ 987 /* losing ground or holding without progress - boost
877 logf("pcmrec: boost priority"); 988 priority until finished */
878 prio = thread_set_priority(NULL, thread_get_priority(NULL)-1); 989 logf("pcmrec: boost (%s)",
990 num >= flood_watermark ? "num" : "time");
991 prio_pcmrec = thread_set_priority(NULL,
992 thread_get_priority(NULL) - 1);
993 prio_codec = thread_set_priority(codec_thread_p,
994 thread_get_priority(codec_thread_p) - 1);
879 } 995 }
880#endif 996#endif
881 997
@@ -888,8 +1004,8 @@ static void pcmrec_flush(unsigned flush_num)
888 if (rec_fdata.chunk->flags & CHUNKF_START_FILE) 1004 if (rec_fdata.chunk->flags & CHUNKF_START_FILE)
889 { 1005 {
890 pcmrec_start_file(); 1006 pcmrec_start_file();
891 if (--flush_num == 0) 1007 if (--remaining == 0)
892 i = num_ready; /* stop on next loop - must write this 1008 num_ready = 0; /* stop on next loop - must write this
893 chunk if it has data */ 1009 chunk if it has data */
894 } 1010 }
895 1011
@@ -903,16 +1019,15 @@ static void pcmrec_flush(unsigned flush_num)
903 if (errors != 0) 1019 if (errors != 0)
904 break; 1020 break;
905 1021
906#ifdef HAVE_PRIORITY_SCHEDULING 1022 if (flush_num == PCMREC_FLUSH_MINI &&
907 if (prio == -1) 1023 ++chunks_flushed >= MINI_CHUNKS)
908 { 1024 {
909 num = enc_wr_index - enc_rd_index; 1025 logf("mini flush break");
910 if (num < 0) 1026 break;
911 num += enc_num_chunks;
912 } 1027 }
913#endif 1028 /* no yielding; the file apis called in the codecs do that
914 /* no yielding, the file apis called in the codecs do that */ 1029 sufficiently */
915 } /* end for */ 1030 } /* end while */
916 1031
917 /* sync file */ 1032 /* sync file */
918 if (rec_fdata.rec_file >= 0) 1033 if (rec_fdata.rec_file >= 0)
@@ -921,11 +1036,12 @@ static void pcmrec_flush(unsigned flush_num)
921 cpu_boost(false); 1036 cpu_boost(false);
922 1037
923#ifdef HAVE_PRIORITY_SCHEDULING 1038#ifdef HAVE_PRIORITY_SCHEDULING
924 if (prio != -1) 1039 if (prio_pcmrec != -1)
925 { 1040 {
926 /* return to original priority */ 1041 /* return to original priorities */
927 logf("pcmrec: unboost priority"); 1042 logf("pcmrec: unboost priority");
928 thread_set_priority(NULL, prio); 1043 thread_set_priority(NULL, prio_pcmrec);
1044 thread_set_priority(codec_thread_p, prio_codec);
929 } 1045 }
930 1046
931 last_flush_tick = current_tick; /* save tick when we left */ 1047 last_flush_tick = current_tick; /* save tick when we left */
@@ -948,10 +1064,14 @@ static void pcmrec_new_stream(const char *filename, /* next file name */
948 int pre_index) /* index for prerecorded data */ 1064 int pre_index) /* index for prerecorded data */
949{ 1065{
950 logf("pcmrec_new_stream"); 1066 logf("pcmrec_new_stream");
1067 char path[MAX_PATH]; /* place to copy filename so sender can be released */
951 1068
952 struct enc_buffer_event_data data; 1069 struct enc_buffer_event_data data;
953 bool (*fnq_add_fn)(const char *) = NULL; 1070 bool (*fnq_add_fn)(const char *) = NULL; /* function to use to add
954 struct enc_chunk_hdr *start = NULL; 1071 new filename */
1072 struct enc_chunk_hdr *start = NULL; /* pointer to starting chunk of
1073 stream */
1074 bool did_flush = false; /* did a flush occurr? */
955 1075
956 int get_chunk_index(struct enc_chunk_hdr *chunk) 1076 int get_chunk_index(struct enc_chunk_hdr *chunk)
957 { 1077 {
@@ -967,6 +1087,10 @@ static void pcmrec_new_stream(const char *filename, /* next file name */
967 return GET_ENC_CHUNK(index); 1087 return GET_ENC_CHUNK(index);
968 } 1088 }
969 1089
1090 if (filename)
1091 strncpy(path, filename, MAX_PATH);
1092 queue_reply(&pcmrec_queue, 0); /* We have all we need */
1093
970 data.pre_chunk = NULL; 1094 data.pre_chunk = NULL;
971 data.chunk = GET_ENC_CHUNK(enc_wr_index); 1095 data.chunk = GET_ENC_CHUNK(enc_wr_index);
972 1096
@@ -1039,7 +1163,9 @@ static void pcmrec_new_stream(const char *filename, /* next file name */
1039 } 1163 }
1040 1164
1041 data.flags = flags; 1165 data.flags = flags;
1166 pcmrec_context = true; /* switch encoder context */
1042 enc_events_callback(ENC_REC_NEW_STREAM, &data); 1167 enc_events_callback(ENC_REC_NEW_STREAM, &data);
1168 pcmrec_context = false; /* switch back */
1043 1169
1044 if (flags & CHUNKF_END_FILE) 1170 if (flags & CHUNKF_END_FILE)
1045 { 1171 {
@@ -1049,11 +1175,10 @@ static void pcmrec_new_stream(const char *filename, /* next file name */
1049 1175
1050 if (start) 1176 if (start)
1051 { 1177 {
1052 char buf[MAX_PATH]; /* place to copy in case we're full */
1053
1054 if (!(flags & CHUNKF_PRERECORD)) 1178 if (!(flags & CHUNKF_PRERECORD))
1055 { 1179 {
1056 /* get stats on data added to start - sort of a prerecord operation */ 1180 /* get stats on data added to start - sort of a prerecord
1181 operation */
1057 int i = get_chunk_index(data.chunk); 1182 int i = get_chunk_index(data.chunk);
1058#ifdef PCMREC_PARANOID 1183#ifdef PCMREC_PARANOID
1059 int i_last = i; 1184 int i_last = i;
@@ -1083,16 +1208,16 @@ static void pcmrec_new_stream(const char *filename, /* next file name */
1083 if (fnq_add_fn == pcmrec_fnq_add_filename && pcmrec_fnq_is_full()) 1208 if (fnq_add_fn == pcmrec_fnq_add_filename && pcmrec_fnq_is_full())
1084 { 1209 {
1085 logf("fnq full"); 1210 logf("fnq full");
1086 /* make a local copy of filename and let sender go as this 1211 pcmrec_flush(PCMREC_FLUSH_ALL);
1087 flush will hang the screen for a bit otherwise */ 1212 did_flush = true;
1088 strncpy(buf, filename, MAX_PATH);
1089 filename = buf;
1090 queue_reply(&pcmrec_queue, 0);
1091 pcmrec_flush(-1);
1092 } 1213 }
1093 1214
1094 fnq_add_fn(filename); 1215 fnq_add_fn(path);
1095 } 1216 }
1217
1218 /* Make sure to complete any interrupted high watermark */
1219 if (!did_flush)
1220 pcmrec_flush(PCMREC_FLUSH_IF_HIGH);
1096} /* pcmrec_new_stream */ 1221} /* pcmrec_new_stream */
1097 1222
1098/** event handlers for pcmrec thread */ 1223/** event handlers for pcmrec thread */
@@ -1102,6 +1227,7 @@ static void pcmrec_init(void)
1102{ 1227{
1103 unsigned char *buffer; 1228 unsigned char *buffer;
1104 1229
1230 pcmrec_close_file(&rec_fdata.rec_file);
1105 rec_fdata.rec_file = -1; 1231 rec_fdata.rec_file = -1;
1106 1232
1107 /* warings and errors */ 1233 /* warings and errors */
@@ -1112,6 +1238,7 @@ static void pcmrec_init(void)
1112 dma_lock = true; 1238 dma_lock = true;
1113 SET_PCM_POS(pcm_rd_pos, 0); 1239 SET_PCM_POS(pcm_rd_pos, 0);
1114 SET_PCM_POS(dma_wr_pos, 0); 1240 SET_PCM_POS(dma_wr_pos, 0);
1241 pcm_enc_pos = 0;
1115 1242
1116 /* encoder FIFO */ 1243 /* encoder FIFO */
1117 SET_ENC_INDEX(enc_wr_index, 0); 1244 SET_ENC_INDEX(enc_wr_index, 0);
@@ -1137,7 +1264,7 @@ static void pcmrec_init(void)
1137 buffer = audio_get_recording_buffer(&rec_buffer_size); 1264 buffer = audio_get_recording_buffer(&rec_buffer_size);
1138 1265
1139 /* Line align pcm_buffer 2^4=16 bytes */ 1266 /* Line align pcm_buffer 2^4=16 bytes */
1140 pcm_buffer = (unsigned char *)ALIGN_UP_P2((unsigned long)buffer, 4); 1267 pcm_buffer = (unsigned char *)ALIGN_UP_P2((uintptr_t)buffer, 4);
1141 enc_buffer = pcm_buffer + ALIGN_UP_P2(PCM_NUM_CHUNKS*PCM_CHUNK_SIZE + 1268 enc_buffer = pcm_buffer + ALIGN_UP_P2(PCM_NUM_CHUNKS*PCM_CHUNK_SIZE +
1142 PCM_MAX_FEED_SIZE, 2); 1269 PCM_MAX_FEED_SIZE, 2);
1143 /* Adjust available buffer for possible align advancement */ 1270 /* Adjust available buffer for possible align advancement */
@@ -1158,7 +1285,8 @@ static void pcmrec_close(void)
1158} /* pcmrec_close */ 1285} /* pcmrec_close */
1159 1286
1160/* PCMREC_OPTIONS */ 1287/* PCMREC_OPTIONS */
1161static void pcmrec_set_recording_options(struct audio_recording_options *options) 1288static void pcmrec_set_recording_options(
1289 struct audio_recording_options *options)
1162{ 1290{
1163 /* stop DMA transfer */ 1291 /* stop DMA transfer */
1164 dma_lock = true; 1292 dma_lock = true;
@@ -1222,97 +1350,111 @@ static void pcmrec_record(const char *filename)
1222{ 1350{
1223 unsigned long pre_sample_ticks; 1351 unsigned long pre_sample_ticks;
1224 int rd_start; 1352 int rd_start;
1353 unsigned long flags;
1354 int pre_index;
1225 1355
1226 logf("pcmrec_record: %s", filename); 1356 logf("pcmrec_record: %s", filename);
1227 1357
1228 /* reset stats */ 1358 /* reset stats */
1229 num_rec_bytes = 0; 1359 num_rec_bytes = 0;
1230 num_rec_samples = 0; 1360 num_rec_samples = 0;
1231 1361
1232 if (is_recording) 1362 if (!is_recording)
1233 { 1363 {
1234 /* already recording, just split the stream */
1235 logf("inserting split");
1236 pcmrec_new_stream(filename,
1237 CHUNKF_START_FILE | CHUNKF_END_FILE,
1238 0);
1239 goto record_done;
1240 }
1241
1242#if 0 1364#if 0
1243 accum_rec_bytes = 0; 1365 accum_rec_bytes = 0;
1244 accum_pcm_samples = 0; 1366 accum_pcm_samples = 0;
1245#endif 1367#endif
1246 spinup_time = -1; 1368 warnings = 0; /* reset warnings */
1247 warnings = 0; /* reset warnings */
1248 1369
1249 rd_start = enc_wr_index; 1370 rd_start = enc_wr_index;
1250 pre_sample_ticks = 0; 1371 pre_sample_ticks = 0;
1251 1372
1252 if (pre_record_ticks) 1373 pcmrec_refresh_watermarks();
1253 { 1374
1254 int i = rd_start; 1375 if (pre_record_ticks)
1376 {
1377 int i = rd_start;
1255#ifdef PCMREC_PARANOID 1378#ifdef PCMREC_PARANOID
1256 int i_last = i; 1379 int i_last = i;
1257#endif 1380#endif
1258 /* calculate number of available chunks */ 1381 /* calculate number of available chunks */
1259 unsigned long avail_pre_chunks = (enc_wr_index - enc_rd_index + 1382 unsigned long avail_pre_chunks = (enc_wr_index - enc_rd_index +
1260 enc_num_chunks) % enc_num_chunks; 1383 enc_num_chunks) % enc_num_chunks;
1261 /* overflow at 974 seconds of prerecording at 44.1kHz */ 1384 /* overflow at 974 seconds of prerecording at 44.1kHz */
1262 unsigned long pre_record_sample_ticks = enc_sample_rate*pre_record_ticks; 1385 unsigned long pre_record_sample_ticks =
1263 1386 enc_sample_rate*pre_record_ticks;
1264 /* Get exact measure of recorded data as number of samples aren't 1387 int pre_chunks = 0; /* Counter to limit prerecorded time to
1265 nescessarily going to be the max for each chunk */ 1388 prevent flood state at outset */
1266 for (; avail_pre_chunks-- > 0;) 1389
1267 { 1390 logf("pre-st: %ld", pre_record_sample_ticks);
1268 struct enc_chunk_hdr *chunk; 1391
1269 unsigned long chunk_sample_ticks; 1392 /* Get exact measure of recorded data as number of samples aren't
1393 nescessarily going to be the max for each chunk */
1394 for (; avail_pre_chunks-- > 0;)
1395 {
1396 struct enc_chunk_hdr *chunk;
1397 unsigned long chunk_sample_ticks;
1270 1398
1271 DEC_ENC_INDEX(i); 1399 DEC_ENC_INDEX(i);
1272 1400
1273 chunk = GET_ENC_CHUNK(i); 1401 chunk = GET_ENC_CHUNK(i);
1274 1402
1275 /* must have data to be counted */ 1403 /* must have data to be counted */
1276 if (chunk->enc_data == NULL) 1404 if (chunk->enc_data == NULL)
1277 continue; 1405 continue;
1278 1406
1279 chunk_sample_ticks = chunk->num_pcm*HZ; 1407 chunk_sample_ticks = chunk->num_pcm*HZ;
1280 1408
1281 rd_start = i; 1409 rd_start = i;
1282 pre_sample_ticks += chunk_sample_ticks; 1410 pre_sample_ticks += chunk_sample_ticks;
1283 num_rec_bytes += chunk->enc_size; 1411 num_rec_bytes += chunk->enc_size;
1284 num_rec_samples += chunk->num_pcm; 1412 num_rec_samples += chunk->num_pcm;
1413 pre_chunks++;
1285 1414
1286 /* stop here if enough already */ 1415 /* stop here if enough already */
1287 if (pre_sample_ticks >= pre_record_sample_ticks) 1416 if (pre_chunks >= high_watermark ||
1288 break; 1417 pre_sample_ticks >= pre_record_sample_ticks)
1289 } 1418 {
1419 logf("pre-chks: %d", pre_chunks);
1420 break;
1421 }
1422 }
1290 1423
1291#if 0 1424#if 0
1292 accum_rec_bytes = num_rec_bytes; 1425 accum_rec_bytes = num_rec_bytes;
1293 accum_pcm_samples = num_rec_samples; 1426 accum_pcm_samples = num_rec_samples;
1294#endif 1427#endif
1295 } 1428 }
1429
1430 SET_ENC_INDEX(enc_rd_index, rd_start);
1431
1432 /* filename queue should be empty */
1433 if (!pcmrec_fnq_is_empty())
1434 {
1435 logf("fnq: not empty!");
1436 pcmrec_fnq_set_empty();
1437 }
1438
1439 flags = CHUNKF_START_FILE;
1440 if (pre_sample_ticks > 0)
1441 flags |= CHUNKF_PRERECORD;
1296 1442
1297 SET_ENC_INDEX(enc_rd_index, rd_start); 1443 pre_index = enc_rd_index;
1298 1444
1299 /* filename queue should be empty */ 1445 dma_lock = false;
1300 if (!pcmrec_fnq_is_empty()) 1446 is_paused = false;
1447 is_recording = true;
1448 }
1449 else
1301 { 1450 {
1302 logf("fnq: not empty!"); 1451 /* already recording, just split the stream */
1303 pcmrec_fnq_set_empty(); 1452 logf("inserting split");
1453 flags = CHUNKF_START_FILE | CHUNKF_END_FILE;
1454 pre_index = 0;
1304 } 1455 }
1305
1306 dma_lock = false;
1307 is_paused = false;
1308 is_recording = true;
1309 1456
1310 pcmrec_new_stream(filename, 1457 pcmrec_new_stream(filename, flags, pre_index);
1311 CHUNKF_START_FILE |
1312 (pre_sample_ticks > 0 ? CHUNKF_PRERECORD : 0),
1313 enc_rd_index);
1314
1315record_done:
1316 logf("pcmrec_record done"); 1458 logf("pcmrec_record done");
1317} /* pcmrec_record */ 1459} /* pcmrec_record */
1318 1460
@@ -1321,52 +1463,52 @@ static void pcmrec_stop(void)
1321{ 1463{
1322 logf("pcmrec_stop"); 1464 logf("pcmrec_stop");
1323 1465
1324 if (!is_recording) 1466 if (is_recording)
1325 { 1467 {
1326 logf("not recording"); 1468 dma_lock = true; /* lock dma write position */
1327 goto not_recording; 1469 queue_reply(&pcmrec_queue, 0);
1328 }
1329 1470
1330 dma_lock = true; /* lock dma write position */ 1471 /* flush all available data first to avoid overflow while waiting
1331 queue_reply(&pcmrec_queue, 0); 1472 for encoding to finish */
1473 pcmrec_flush(PCMREC_FLUSH_ALL);
1332 1474
1333 /* flush all available data first to avoid overflow while waiting 1475 /* wait for encoder to finish remaining data */
1334 for encoding to finish */ 1476 while (errors == 0 && !pcm_buffer_empty)
1335 pcmrec_flush(-1); 1477 yield();
1336
1337 /* wait for encoder to finish remaining data */
1338 while (errors == 0 && !wav_queue_empty)
1339 yield();
1340
1341 /* end stream at last data */
1342 pcmrec_new_stream(NULL, CHUNKF_END_FILE, 0);
1343
1344 /* flush anything else encoder added */
1345 pcmrec_flush(-1);
1346
1347 /* remove any pending file start not yet processed - should be at
1348 most one at enc_wr_index */
1349 pcmrec_fnq_get_filename(NULL);
1350 /* encoder should abort any chunk it was in midst of processing */
1351 GET_ENC_CHUNK(enc_wr_index)->flags = CHUNKF_ABORT;
1352
1353 /* filename queue should be empty */
1354 if (!pcmrec_fnq_is_empty())
1355 {
1356 logf("fnq: not empty!");
1357 pcmrec_fnq_set_empty();
1358 }
1359 1478
1360 /* be absolutely sure the file is closed */ 1479 /* end stream at last data */
1361 if (errors != 0) 1480 pcmrec_new_stream(NULL, CHUNKF_END_FILE, 0);
1362 pcmrec_close_file(&rec_fdata.rec_file); 1481
1363 rec_fdata.rec_file = -1; 1482 /* flush anything else encoder added */
1483 pcmrec_flush(PCMREC_FLUSH_ALL);
1364 1484
1365 is_recording = false; 1485 /* remove any pending file start not yet processed - should be at
1366 is_paused = false; 1486 most one at enc_wr_index */
1367 dma_lock = pre_record_ticks == 0; 1487 pcmrec_fnq_get_filename(NULL);
1488 /* encoder should abort any chunk it was in midst of processing */
1489 GET_ENC_CHUNK(enc_wr_index)->flags = CHUNKF_ABORT;
1490
1491 /* filename queue should be empty */
1492 if (!pcmrec_fnq_is_empty())
1493 {
1494 logf("fnq: not empty!");
1495 pcmrec_fnq_set_empty();
1496 }
1497
1498 /* be absolutely sure the file is closed */
1499 if (errors != 0)
1500 pcmrec_close_file(&rec_fdata.rec_file);
1501 rec_fdata.rec_file = -1;
1502
1503 is_recording = false;
1504 is_paused = false;
1505 dma_lock = pre_record_ticks == 0;
1506 }
1507 else
1508 {
1509 logf("not recording");
1510 }
1368 1511
1369not_recording:
1370 logf("pcmrec_stop done"); 1512 logf("pcmrec_stop done");
1371} /* pcmrec_stop */ 1513} /* pcmrec_stop */
1372 1514
@@ -1378,18 +1520,17 @@ static void pcmrec_pause(void)
1378 if (!is_recording) 1520 if (!is_recording)
1379 { 1521 {
1380 logf("not recording"); 1522 logf("not recording");
1381 goto not_recording_or_paused;
1382 } 1523 }
1383 else if (is_paused) 1524 else if (is_paused)
1384 { 1525 {
1385 logf("already paused"); 1526 logf("already paused");
1386 goto not_recording_or_paused;
1387 } 1527 }
1388 1528 else
1389 dma_lock = true; /* fix DMA write pointer at current position */ 1529 {
1390 is_paused = true; 1530 dma_lock = true;
1391 1531 is_paused = true;
1392not_recording_or_paused: 1532 }
1533
1393 logf("pcmrec_pause done"); 1534 logf("pcmrec_pause done");
1394} /* pcmrec_pause */ 1535} /* pcmrec_pause */
1395 1536
@@ -1401,19 +1542,18 @@ static void pcmrec_resume(void)
1401 if (!is_recording) 1542 if (!is_recording)
1402 { 1543 {
1403 logf("not recording"); 1544 logf("not recording");
1404 goto not_recording_or_not_paused;
1405 } 1545 }
1406 else if (!is_paused) 1546 else if (!is_paused)
1407 { 1547 {
1408 logf("not paused"); 1548 logf("not paused");
1409 goto not_recording_or_not_paused;
1410 } 1549 }
1411 1550 else
1412 is_paused = false; 1551 {
1413 is_recording = true; 1552 is_paused = false;
1414 dma_lock = false; 1553 is_recording = true;
1415 1554 dma_lock = false;
1416not_recording_or_not_paused: 1555 }
1556
1417 logf("pcmrec_resume done"); 1557 logf("pcmrec_resume done");
1418} /* pcmrec_resume */ 1558} /* pcmrec_resume */
1419 1559
@@ -1424,6 +1564,12 @@ static void pcmrec_thread(void)
1424 1564
1425 logf("thread pcmrec start"); 1565 logf("thread pcmrec start");
1426 1566
1567 static void clear_flush_interrupt(void)
1568 {
1569 if (--flush_interrupts < 0)
1570 flush_interrupts = 0;
1571 }
1572
1427 while(1) 1573 while(1)
1428 { 1574 {
1429 if (is_recording) 1575 if (is_recording)
@@ -1433,7 +1579,9 @@ static void pcmrec_thread(void)
1433 1579
1434 if (ev.id == SYS_TIMEOUT) 1580 if (ev.id == SYS_TIMEOUT)
1435 { 1581 {
1436 pcmrec_flush(0); /* flush if getting full */ 1582 /* Messages that interrupt this will complete it */
1583 pcmrec_flush(PCMREC_FLUSH_IF_HIGH |
1584 PCMREC_FLUSH_INTERRUPTABLE);
1437 continue; 1585 continue;
1438 } 1586 }
1439 } 1587 }
@@ -1459,14 +1607,17 @@ static void pcmrec_thread(void)
1459 break; 1607 break;
1460 1608
1461 case PCMREC_RECORD: 1609 case PCMREC_RECORD:
1610 clear_flush_interrupt();
1462 pcmrec_record((const char *)ev.data); 1611 pcmrec_record((const char *)ev.data);
1463 break; 1612 break;
1464 1613
1465 case PCMREC_STOP: 1614 case PCMREC_STOP:
1615 clear_flush_interrupt();
1466 pcmrec_stop(); 1616 pcmrec_stop();
1467 break; 1617 break;
1468 1618
1469 case PCMREC_PAUSE: 1619 case PCMREC_PAUSE:
1620 clear_flush_interrupt();
1470 pcmrec_pause(); 1621 pcmrec_pause();
1471 break; 1622 break;
1472 1623
@@ -1483,6 +1634,9 @@ static void pcmrec_thread(void)
1483 break; 1634 break;
1484 pcmrec_close(); 1635 pcmrec_close();
1485 reset_hardware(); 1636 reset_hardware();
1637 /* Be sure other threads are released if waiting */
1638 queue_clear(&pcmrec_queue);
1639 flush_interrupts = 0;
1486 usb_acknowledge(SYS_USB_CONNECTED_ACK); 1640 usb_acknowledge(SYS_USB_CONNECTED_ACK);
1487 usb_wait_for_disconnect(&pcmrec_queue); 1641 usb_wait_for_disconnect(&pcmrec_queue);
1488 break; 1642 break;
@@ -1495,6 +1649,7 @@ static void pcmrec_thread(void)
1495/****************************************************************************/ 1649/****************************************************************************/
1496/* */ 1650/* */
1497/* following functions will be called by the encoder codec */ 1651/* following functions will be called by the encoder codec */
1652/* in a free-threaded manner */
1498/* */ 1653/* */
1499/****************************************************************************/ 1654/****************************************************************************/
1500 1655
@@ -1527,6 +1682,7 @@ void enc_set_parameters(struct enc_parameters *params)
1527 logf("enc sampr:%d", enc_sample_rate); 1682 logf("enc sampr:%d", enc_sample_rate);
1528 1683
1529 SET_PCM_POS(pcm_rd_pos, dma_wr_pos); 1684 SET_PCM_POS(pcm_rd_pos, dma_wr_pos);
1685 pcm_enc_pos = pcm_rd_pos;
1530 1686
1531 enc_config.afmt = params->afmt; 1687 enc_config.afmt = params->afmt;
1532 /* addition of the header is always implied - chunk size 4-byte aligned */ 1688 /* addition of the header is always implied - chunk size 4-byte aligned */
@@ -1568,16 +1724,6 @@ void enc_set_parameters(struct enc_parameters *params)
1568 *wrap_id_p = ENC_CHUNK_MAGIC; 1724 *wrap_id_p = ENC_CHUNK_MAGIC;
1569#endif /* PCMREC_PARANOID */ 1725#endif /* PCMREC_PARANOID */
1570 1726
1571#ifdef HAVE_PRIORITY_SCHEDULING
1572 /* panic boost thread priority at 1 second remaining */
1573 panic_threshold = enc_num_chunks -
1574 (4*sample_rate + (enc_chunk_size-1)) / enc_chunk_size;
1575 if (panic_threshold < 0)
1576 panic_threshold = 0;
1577
1578 logf("panic thr:%d", panic_threshold);
1579#endif
1580
1581 /** set OUT parameters **/ 1727 /** set OUT parameters **/
1582 params->enc_buffer = enc_buffer; 1728 params->enc_buffer = enc_buffer;
1583 params->buf_chunk_size = enc_chunk_size; 1729 params->buf_chunk_size = enc_chunk_size;
@@ -1596,7 +1742,10 @@ void enc_set_parameters(struct enc_parameters *params)
1596 fnq_wr_pos = 0; /* reset */ 1742 fnq_wr_pos = 0; /* reset */
1597 fn_queue = enc_buffer + bufsize; 1743 fn_queue = enc_buffer + bufsize;
1598 fnq_size = pcm_buffer + rec_buffer_size - fn_queue; 1744 fnq_size = pcm_buffer + rec_buffer_size - fn_queue;
1599 fnq_size = ALIGN_DOWN(fnq_size, MAX_PATH); 1745 fnq_size /= MAX_PATH;
1746 if (fnq_size > FNQ_MAX_NUM_PATHS)
1747 fnq_size = FNQ_MAX_NUM_PATHS;
1748 fnq_size *= MAX_PATH;
1600 logf("fnq files: %d", fnq_size / MAX_PATH); 1749 logf("fnq files: %d", fnq_size / MAX_PATH);
1601 1750
1602#if 0 1751#if 0
@@ -1626,7 +1775,8 @@ void enc_set_parameters(struct enc_parameters *params)
1626 logf("enc_set_parameters done"); 1775 logf("enc_set_parameters done");
1627} /* enc_set_parameters */ 1776} /* enc_set_parameters */
1628 1777
1629/* return encoder chunk at current write position */ 1778/* return encoder chunk at current write position -
1779 NOTE: can be called by pcmrec thread when splitting streams */
1630struct enc_chunk_hdr * enc_get_chunk(void) 1780struct enc_chunk_hdr * enc_get_chunk(void)
1631{ 1781{
1632 struct enc_chunk_hdr *chunk = GET_ENC_CHUNK(enc_wr_index); 1782 struct enc_chunk_hdr *chunk = GET_ENC_CHUNK(enc_wr_index);
@@ -1647,7 +1797,8 @@ struct enc_chunk_hdr * enc_get_chunk(void)
1647 return chunk; 1797 return chunk;
1648} /* enc_get_chunk */ 1798} /* enc_get_chunk */
1649 1799
1650/* releases the current chunk into the available chunks */ 1800/* releases the current chunk into the available chunks -
1801 NOTE: can be called by pcmrec thread when splitting streams */
1651void enc_finish_chunk(void) 1802void enc_finish_chunk(void)
1652{ 1803{
1653 struct enc_chunk_hdr *chunk = GET_ENC_CHUNK(enc_wr_index); 1804 struct enc_chunk_hdr *chunk = GET_ENC_CHUNK(enc_wr_index);
@@ -1675,10 +1826,19 @@ void enc_finish_chunk(void)
1675 } 1826 }
1676 else if (is_recording) /* buffer full */ 1827 else if (is_recording) /* buffer full */
1677 { 1828 {
1678 /* keep current position - but put up warning flag */ 1829 /* keep current position and put up warning flag */
1679 warnings |= PCMREC_W_ENC_BUFFER_OVF; 1830 warnings |= PCMREC_W_ENC_BUFFER_OVF;
1680 logf("enc_buffer ovf"); 1831 logf("enc_buffer ovf");
1681 DEC_ENC_INDEX(enc_wr_index); 1832 DEC_ENC_INDEX(enc_wr_index);
1833 if (pcmrec_context)
1834 {
1835 /* if stream splitting, keep this out of circulation and
1836 flush a small number, then readd - cannot risk losing
1837 stream markers */
1838 logf("mini flush");
1839 pcmrec_flush(PCMREC_FLUSH_MINI);
1840 INC_ENC_INDEX(enc_wr_index);
1841 }
1682 } 1842 }
1683 else 1843 else
1684 { 1844 {
@@ -1691,7 +1851,7 @@ void enc_finish_chunk(void)
1691int enc_pcm_buf_near_empty(void) 1851int enc_pcm_buf_near_empty(void)
1692{ 1852{
1693 /* less than 1sec raw data? => unboost encoder */ 1853 /* less than 1sec raw data? => unboost encoder */
1694 int wp = dma_wr_pos; 1854 int wp = dma_wr_pos;
1695 size_t avail = (wp - pcm_rd_pos) & PCM_CHUNK_MASK; 1855 size_t avail = (wp - pcm_rd_pos) & PCM_CHUNK_MASK;
1696 return avail < (sample_rate << 2) ? 1 : 0; 1856 return avail < (sample_rate << 2) ? 1 : 0;
1697} /* enc_pcm_buf_near_empty */ 1857} /* enc_pcm_buf_near_empty */
@@ -1700,7 +1860,7 @@ int enc_pcm_buf_near_empty(void)
1700/* TODO: this really should give the actual size returned */ 1860/* TODO: this really should give the actual size returned */
1701unsigned char * enc_get_pcm_data(size_t size) 1861unsigned char * enc_get_pcm_data(size_t size)
1702{ 1862{
1703 int wp = dma_wr_pos; 1863 int wp = dma_wr_pos;
1704 size_t avail = (wp - pcm_rd_pos) & PCM_CHUNK_MASK; 1864 size_t avail = (wp - pcm_rd_pos) & PCM_CHUNK_MASK;
1705 1865
1706 /* limit the requested pcm data size */ 1866 /* limit the requested pcm data size */
@@ -1712,47 +1872,46 @@ unsigned char * enc_get_pcm_data(size_t size)
1712 unsigned char *ptr = pcm_buffer + pcm_rd_pos; 1872 unsigned char *ptr = pcm_buffer + pcm_rd_pos;
1713 int next_pos = (pcm_rd_pos + size) & PCM_CHUNK_MASK; 1873 int next_pos = (pcm_rd_pos + size) & PCM_CHUNK_MASK;
1714 1874
1875 pcm_enc_pos = pcm_rd_pos;
1876
1715 SET_PCM_POS(pcm_rd_pos, next_pos); 1877 SET_PCM_POS(pcm_rd_pos, next_pos);
1716 pcm_rd_pos = next_pos;
1717 1878
1718 /* ptr must point to continous data at wraparound position */ 1879 /* ptr must point to continous data at wraparound position */
1719 if ((size_t)pcm_rd_pos < size) 1880 if ((size_t)pcm_rd_pos < size)
1720 memcpy(pcm_buffer + PCM_NUM_CHUNKS*PCM_CHUNK_SIZE, 1881 memcpy(pcm_buffer + PCM_NUM_CHUNKS*PCM_CHUNK_SIZE,
1721 pcm_buffer, pcm_rd_pos); 1882 pcm_buffer, pcm_rd_pos);
1722 1883
1723 wav_queue_empty = false; 1884 pcm_buffer_empty = false;
1724 return ptr; 1885 return ptr;
1725 } 1886 }
1726 1887
1727 /* not enough data available - encoder should idle */ 1888 /* not enough data available - encoder should idle */
1728 wav_queue_empty = true; 1889 pcm_buffer_empty = true;
1729 return NULL; 1890 return NULL;
1730} /* enc_get_pcm_data */ 1891} /* enc_get_pcm_data */
1731 1892
1732/* puts some pcm data back in the queue */ 1893/* puts some pcm data back in the queue */
1733size_t enc_unget_pcm_data(size_t size) 1894size_t enc_unget_pcm_data(size_t size)
1734{ 1895{
1735 /* can't let DMA advance write position when doing this */ 1896 int wp = dma_wr_pos;
1736 int level = set_irq_level(HIGHEST_IRQ_LEVEL); 1897 size_t old_avail = ((pcm_rd_pos - wp) & PCM_CHUNK_MASK) -
1898 2*PCM_CHUNK_SIZE;
1737 1899
1738 if (pcm_rd_pos != dma_wr_pos) 1900 /* allow one interrupt to occur during this call and not have the
1901 new read position inside the DMA destination chunk */
1902 if ((ssize_t)old_avail > 0)
1739 { 1903 {
1740 /* disallow backing up into current DMA write chunk */
1741 size_t old_avail = (pcm_rd_pos - dma_wr_pos - PCM_CHUNK_SIZE)
1742 & PCM_CHUNK_MASK;
1743 int next_pos;
1744
1745 /* limit size to amount of old data remaining */ 1904 /* limit size to amount of old data remaining */
1746 if (size > old_avail) 1905 if (size > old_avail)
1747 size = old_avail; 1906 size = old_avail;
1748 1907
1749 next_pos = (pcm_rd_pos - size) & PCM_CHUNK_MASK; 1908 pcm_enc_pos = (pcm_rd_pos - size) & PCM_CHUNK_MASK;
1750 SET_PCM_POS(pcm_rd_pos, next_pos); 1909 SET_PCM_POS(pcm_rd_pos, pcm_enc_pos);
1751 }
1752 1910
1753 set_irq_level(level); 1911 return size;
1912 }
1754 1913
1755 return size; 1914 return 0;
1756} /* enc_unget_pcm_data */ 1915} /* enc_unget_pcm_data */
1757 1916
1758/** Low level pcm recording apis **/ 1917/** Low level pcm recording apis **/