diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2013-05-31 02:41:02 -0400 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2013-05-31 03:20:35 -0400 |
commit | 5857c44017a1641fce7f00da7f16c143daacbaf6 (patch) | |
tree | b8a7ff134977ee8dd6b25b5591f4eb81172f74ab /apps/recorder/pcm_record.c | |
parent | df6e1bcce5071e02b5cd46736bff87ca0dcceffe (diff) | |
download | rockbox-5857c44017a1641fce7f00da7f16c143daacbaf6.tar.gz rockbox-5857c44017a1641fce7f00da7f16c143daacbaf6.zip |
Refactor audio thread to run both recording and playback.
Eliminates the pcmrec thread and keeps playback and recording engine
operation mutually-exclusive.
audio_thread.c contains the audio thread which branches to the
correct engine depending upon the request. It also handles the main
audio initialization.
Moves pcm_init into main.c just before dsp_init because I don't want
that one in audio_init in the new file.
(Also makes revision df6e1bc pointless ;)
Change-Id: Ifc1db24404e6d8dd9ac42d9f4dfbc207aa9a26e1
Diffstat (limited to 'apps/recorder/pcm_record.c')
-rw-r--r-- | apps/recorder/pcm_record.c | 305 |
1 files changed, 135 insertions, 170 deletions
diff --git a/apps/recorder/pcm_record.c b/apps/recorder/pcm_record.c index fe7a54a565..a45dcc2d11 100644 --- a/apps/recorder/pcm_record.c +++ b/apps/recorder/pcm_record.c | |||
@@ -38,11 +38,13 @@ | |||
38 | #ifdef HAVE_SPDIF_IN | 38 | #ifdef HAVE_SPDIF_IN |
39 | #include "spdif.h" | 39 | #include "spdif.h" |
40 | #endif | 40 | #endif |
41 | #include "audio_thread.h" | ||
41 | 42 | ||
42 | /***************************************************************************/ | 43 | /***************************************************************************/ |
43 | 44 | ||
45 | extern struct event_queue audio_queue; | ||
46 | |||
44 | /** General recording state **/ | 47 | /** General recording state **/ |
45 | static bool is_initialized = false; /* Subsystem ready? */ | ||
46 | static bool is_recording; /* We are recording */ | 48 | static bool is_recording; /* We are recording */ |
47 | static bool is_paused; /* We have paused */ | 49 | static bool is_paused; /* We have paused */ |
48 | static unsigned long errors; /* An error has occured */ | 50 | static unsigned long errors; /* An error has occured */ |
@@ -230,14 +232,6 @@ enum | |||
230 | 232 | ||
231 | /***************************************************************************/ | 233 | /***************************************************************************/ |
232 | 234 | ||
233 | static struct event_queue pcmrec_queue SHAREDBSS_ATTR; | ||
234 | static struct queue_sender_list pcmrec_queue_send SHAREDBSS_ATTR; | ||
235 | static long pcmrec_stack[3*DEFAULT_STACK_SIZE/sizeof(long)]; | ||
236 | static const char pcmrec_thread_name[] = "pcmrec"; | ||
237 | static unsigned int pcmrec_thread_id = 0; | ||
238 | |||
239 | static void pcmrec_thread(void); | ||
240 | |||
241 | enum | 235 | enum |
242 | { | 236 | { |
243 | PCMREC_NULL = 0, | 237 | PCMREC_NULL = 0, |
@@ -248,14 +242,23 @@ enum | |||
248 | PCMREC_STOP, /* stop the current recording */ | 242 | PCMREC_STOP, /* stop the current recording */ |
249 | PCMREC_PAUSE, /* pause the current recording */ | 243 | PCMREC_PAUSE, /* pause the current recording */ |
250 | PCMREC_RESUME, /* resume the current recording */ | 244 | PCMREC_RESUME, /* resume the current recording */ |
251 | #if 0 | ||
252 | PCMREC_FLUSH_NUM, /* flush a number of files out */ | ||
253 | #endif | ||
254 | }; | 245 | }; |
255 | 246 | ||
256 | /*******************************************************************/ | 247 | /*******************************************************************/ |
257 | /* Functions that are not executing in the pcmrec_thread first */ | 248 | /* Functions that are not executing in the audio thread first */ |
258 | /*******************************************************************/ | 249 | /*******************************************************************/ |
250 | |||
251 | static void pcmrec_raise_error_status(unsigned long e) | ||
252 | { | ||
253 | pcm_rec_lock(); /* DMA sets this too */ | ||
254 | errors |= e; | ||
255 | pcm_rec_unlock(); | ||
256 | } | ||
257 | |||
258 | static void pcmrec_raise_warning_status(unsigned long w) | ||
259 | { | ||
260 | warnings |= w; | ||
261 | } | ||
259 | 262 | ||
260 | /* Callback for when more data is ready - called in interrupt context */ | 263 | /* Callback for when more data is ready - called in interrupt context */ |
261 | static void pcm_rec_have_more(void **start, size_t *size) | 264 | static void pcm_rec_have_more(void **start, size_t *size) |
@@ -268,7 +271,7 @@ static void pcm_rec_have_more(void **start, size_t *size) | |||
268 | /* set pcm ovf if processing start position is inside current | 271 | /* set pcm ovf if processing start position is inside current |
269 | write chunk */ | 272 | write chunk */ |
270 | if ((unsigned)(pcm_enc_pos - next_pos) < PCM_CHUNK_SIZE) | 273 | if ((unsigned)(pcm_enc_pos - next_pos) < PCM_CHUNK_SIZE) |
271 | warnings |= PCMREC_W_PCM_BUFFER_OVF; | 274 | pcmrec_raise_warning_status(PCMREC_W_PCM_BUFFER_OVF); |
272 | 275 | ||
273 | dma_wr_pos = next_pos; | 276 | dma_wr_pos = next_pos; |
274 | } | 277 | } |
@@ -285,7 +288,7 @@ static enum pcm_dma_status pcm_rec_status_callback(enum pcm_dma_status status) | |||
285 | if (status == PCM_DMAST_ERR_DMA) | 288 | if (status == PCM_DMAST_ERR_DMA) |
286 | { | 289 | { |
287 | /* Flush recorded data to disk and stop recording */ | 290 | /* Flush recorded data to disk and stop recording */ |
288 | queue_post(&pcmrec_queue, PCMREC_STOP, 0); | 291 | errors |= PCMREC_E_DMA; |
289 | return status; | 292 | return status; |
290 | } | 293 | } |
291 | /* else try again next transmission - frame is invalid */ | 294 | /* else try again next transmission - frame is invalid */ |
@@ -315,9 +318,9 @@ void pcm_rec_error_clear(void) | |||
315 | /** | 318 | /** |
316 | * Check mode, errors and warnings | 319 | * Check mode, errors and warnings |
317 | */ | 320 | */ |
318 | unsigned long pcm_rec_status(void) | 321 | unsigned int pcm_rec_status(void) |
319 | { | 322 | { |
320 | unsigned long ret = 0; | 323 | unsigned int ret = 0; |
321 | 324 | ||
322 | if (is_recording) | 325 | if (is_recording) |
323 | ret |= AUDIO_STATUS_RECORD; | 326 | ret |= AUDIO_STATUS_RECORD; |
@@ -379,20 +382,6 @@ unsigned long pcm_rec_sample_rate(void) | |||
379 | } /* audio_get_sample_rate */ | 382 | } /* audio_get_sample_rate */ |
380 | #endif | 383 | #endif |
381 | 384 | ||
382 | /** | ||
383 | * Creates pcmrec_thread | ||
384 | */ | ||
385 | void pcm_rec_init(void) | ||
386 | { | ||
387 | queue_init(&pcmrec_queue, true); | ||
388 | pcmrec_thread_id = | ||
389 | create_thread(pcmrec_thread, pcmrec_stack, sizeof(pcmrec_stack), | ||
390 | 0, pcmrec_thread_name IF_PRIO(, PRIORITY_RECORDING) | ||
391 | IF_COP(, CPU)); | ||
392 | queue_enable_queue_send(&pcmrec_queue, &pcmrec_queue_send, | ||
393 | pcmrec_thread_id); | ||
394 | } /* pcm_rec_init */ | ||
395 | |||
396 | /** audio_* group **/ | 385 | /** audio_* group **/ |
397 | 386 | ||
398 | /** | 387 | /** |
@@ -401,7 +390,7 @@ void pcm_rec_init(void) | |||
401 | void audio_init_recording(void) | 390 | void audio_init_recording(void) |
402 | { | 391 | { |
403 | logf("audio_init_recording"); | 392 | logf("audio_init_recording"); |
404 | queue_send(&pcmrec_queue, PCMREC_INIT, 0); | 393 | queue_send(&audio_queue, Q_AUDIO_INIT_RECORDING, 1); |
405 | logf("audio_init_recording done"); | 394 | logf("audio_init_recording done"); |
406 | } /* audio_init_recording */ | 395 | } /* audio_init_recording */ |
407 | 396 | ||
@@ -411,7 +400,7 @@ void audio_init_recording(void) | |||
411 | void audio_close_recording(void) | 400 | void audio_close_recording(void) |
412 | { | 401 | { |
413 | logf("audio_close_recording"); | 402 | logf("audio_close_recording"); |
414 | queue_send(&pcmrec_queue, PCMREC_CLOSE, 0); | 403 | queue_send(&audio_queue, Q_AUDIO_CLOSE_RECORDING, 0); |
415 | logf("audio_close_recording done"); | 404 | logf("audio_close_recording done"); |
416 | } /* audio_close_recording */ | 405 | } /* audio_close_recording */ |
417 | 406 | ||
@@ -421,7 +410,7 @@ void audio_close_recording(void) | |||
421 | void audio_set_recording_options(struct audio_recording_options *options) | 410 | void audio_set_recording_options(struct audio_recording_options *options) |
422 | { | 411 | { |
423 | logf("audio_set_recording_options"); | 412 | logf("audio_set_recording_options"); |
424 | queue_send(&pcmrec_queue, PCMREC_OPTIONS, (intptr_t)options); | 413 | queue_send(&audio_queue, Q_AUDIO_RECORDING_OPTIONS, (intptr_t)options); |
425 | logf("audio_set_recording_options done"); | 414 | logf("audio_set_recording_options done"); |
426 | } /* audio_set_recording_options */ | 415 | } /* audio_set_recording_options */ |
427 | 416 | ||
@@ -432,7 +421,7 @@ void audio_record(const char *filename) | |||
432 | { | 421 | { |
433 | logf("audio_record: %s", filename); | 422 | logf("audio_record: %s", filename); |
434 | flush_interrupt(); | 423 | flush_interrupt(); |
435 | queue_send(&pcmrec_queue, PCMREC_RECORD, (intptr_t)filename); | 424 | queue_send(&audio_queue, Q_AUDIO_RECORD, (intptr_t)filename); |
436 | logf("audio_record_done"); | 425 | logf("audio_record_done"); |
437 | } /* audio_record */ | 426 | } /* audio_record */ |
438 | 427 | ||
@@ -451,7 +440,7 @@ void audio_stop_recording(void) | |||
451 | { | 440 | { |
452 | logf("audio_stop_recording"); | 441 | logf("audio_stop_recording"); |
453 | flush_interrupt(); | 442 | flush_interrupt(); |
454 | queue_post(&pcmrec_queue, PCMREC_STOP, 0); | 443 | queue_post(&audio_queue, Q_AUDIO_STOP, 0); |
455 | logf("audio_stop_recording done"); | 444 | logf("audio_stop_recording done"); |
456 | } /* audio_stop_recording */ | 445 | } /* audio_stop_recording */ |
457 | 446 | ||
@@ -462,7 +451,7 @@ void audio_pause_recording(void) | |||
462 | { | 451 | { |
463 | logf("audio_pause_recording"); | 452 | logf("audio_pause_recording"); |
464 | flush_interrupt(); | 453 | flush_interrupt(); |
465 | queue_post(&pcmrec_queue, PCMREC_PAUSE, 0); | 454 | queue_post(&audio_queue, Q_AUDIO_PAUSE, 0); |
466 | logf("audio_pause_recording done"); | 455 | logf("audio_pause_recording done"); |
467 | } /* audio_pause_recording */ | 456 | } /* audio_pause_recording */ |
468 | 457 | ||
@@ -472,7 +461,7 @@ void audio_pause_recording(void) | |||
472 | void audio_resume_recording(void) | 461 | void audio_resume_recording(void) |
473 | { | 462 | { |
474 | logf("audio_resume_recording"); | 463 | logf("audio_resume_recording"); |
475 | queue_post(&pcmrec_queue, PCMREC_RESUME, 0); | 464 | queue_post(&audio_queue, Q_AUDIO_RESUME, 0); |
476 | logf("audio_resume_recording done"); | 465 | logf("audio_resume_recording done"); |
477 | } /* audio_resume_recording */ | 466 | } /* audio_resume_recording */ |
478 | 467 | ||
@@ -517,10 +506,46 @@ unsigned long audio_num_recorded_bytes(void) | |||
517 | 506 | ||
518 | /***************************************************************************/ | 507 | /***************************************************************************/ |
519 | /* */ | 508 | /* */ |
520 | /* Functions that execute in the context of pcmrec_thread */ | 509 | /* Functions that execute in the context of audio thread */ |
521 | /* */ | 510 | /* */ |
522 | /***************************************************************************/ | 511 | /***************************************************************************/ |
523 | 512 | ||
513 | static void pcmrec_init_state(void) | ||
514 | { | ||
515 | flush_interrupts = 0; | ||
516 | |||
517 | /* warings and errors */ | ||
518 | warnings = | ||
519 | errors = 0; | ||
520 | |||
521 | /* pcm FIFO */ | ||
522 | dma_lock = true; | ||
523 | pcm_rd_pos = 0; | ||
524 | dma_wr_pos = 0; | ||
525 | pcm_enc_pos = 0; | ||
526 | |||
527 | /* encoder FIFO */ | ||
528 | enc_wr_index = 0; | ||
529 | enc_rd_index = 0; | ||
530 | |||
531 | /* filename queue */ | ||
532 | fnq_rd_pos = 0; | ||
533 | fnq_wr_pos = 0; | ||
534 | |||
535 | /* stats */ | ||
536 | num_rec_bytes = 0; | ||
537 | num_rec_samples = 0; | ||
538 | #if 0 | ||
539 | accum_rec_bytes = 0; | ||
540 | accum_pcm_samples = 0; | ||
541 | #endif | ||
542 | |||
543 | pre_record_ticks = 0; | ||
544 | |||
545 | is_recording = false; | ||
546 | is_paused = false; | ||
547 | } /* pcmrec_init_state */ | ||
548 | |||
524 | /** Filename Queue **/ | 549 | /** Filename Queue **/ |
525 | 550 | ||
526 | /* returns true if the queue is empty */ | 551 | /* returns true if the queue is empty */ |
@@ -594,7 +619,7 @@ static void pcmrec_close_file(int *fd_p) | |||
594 | return; /* preserve error */ | 619 | return; /* preserve error */ |
595 | 620 | ||
596 | if (close(*fd_p) != 0) | 621 | if (close(*fd_p) != 0) |
597 | errors |= PCMREC_E_IO; | 622 | pcmrec_raise_error_status(PCMREC_E_IO); |
598 | 623 | ||
599 | *fd_p = -1; | 624 | *fd_p = -1; |
600 | } /* pcmrec_close_file */ | 625 | } /* pcmrec_close_file */ |
@@ -646,7 +671,7 @@ static void pcmrec_start_file(void) | |||
646 | { | 671 | { |
647 | logf("start file: fnq empty"); | 672 | logf("start file: fnq empty"); |
648 | *filename = '\0'; | 673 | *filename = '\0'; |
649 | errors |= PCMREC_E_FNQ_DESYNC; | 674 | pcmrec_raise_error_status(PCMREC_E_FNQ_DESYNC); |
650 | } | 675 | } |
651 | else if (errors != 0) | 676 | else if (errors != 0) |
652 | { | 677 | { |
@@ -656,7 +681,7 @@ static void pcmrec_start_file(void) | |||
656 | { | 681 | { |
657 | /* Any previous file should have been closed */ | 682 | /* Any previous file should have been closed */ |
658 | logf("start file: file already open"); | 683 | logf("start file: file already open"); |
659 | errors |= PCMREC_E_FNQ_DESYNC; | 684 | pcmrec_raise_error_status(PCMREC_E_FNQ_DESYNC); |
660 | } | 685 | } |
661 | 686 | ||
662 | if (errors != 0) | 687 | if (errors != 0) |
@@ -671,7 +696,7 @@ static void pcmrec_start_file(void) | |||
671 | if (errors == 0 && (rec_fdata.chunk->flags & CHUNKF_ERROR)) | 696 | if (errors == 0 && (rec_fdata.chunk->flags & CHUNKF_ERROR)) |
672 | { | 697 | { |
673 | logf("start file: enc error"); | 698 | logf("start file: enc error"); |
674 | errors |= PCMREC_E_ENCODER; | 699 | pcmrec_raise_error_status(PCMREC_E_ENCODER); |
675 | } | 700 | } |
676 | 701 | ||
677 | if (errors != 0) | 702 | if (errors != 0) |
@@ -706,7 +731,7 @@ static inline void pcmrec_write_chunk(void) | |||
706 | { | 731 | { |
707 | logf("wr chk enc error %lu %lu", | 732 | logf("wr chk enc error %lu %lu", |
708 | rec_fdata.chunk->enc_size, rec_fdata.chunk->num_pcm); | 733 | rec_fdata.chunk->enc_size, rec_fdata.chunk->num_pcm); |
709 | errors |= PCMREC_E_ENCODER; | 734 | pcmrec_raise_error_status(PCMREC_E_ENCODER); |
710 | } | 735 | } |
711 | } /* pcmrec_write_chunk */ | 736 | } /* pcmrec_write_chunk */ |
712 | 737 | ||
@@ -725,7 +750,7 @@ static void pcmrec_end_file(void) | |||
725 | if (rec_fdata.chunk->flags & CHUNKF_ERROR) | 750 | if (rec_fdata.chunk->flags & CHUNKF_ERROR) |
726 | { | 751 | { |
727 | logf("end file: enc error"); | 752 | logf("end file: enc error"); |
728 | errors |= PCMREC_E_ENCODER; | 753 | pcmrec_raise_error_status(PCMREC_E_ENCODER); |
729 | } | 754 | } |
730 | else | 755 | else |
731 | { | 756 | { |
@@ -946,7 +971,7 @@ static void pcmrec_flush(unsigned flush_num) | |||
946 | 971 | ||
947 | /* sync file */ | 972 | /* sync file */ |
948 | if (rec_fdata.rec_file >= 0 && fsync(rec_fdata.rec_file) != 0) | 973 | if (rec_fdata.rec_file >= 0 && fsync(rec_fdata.rec_file) != 0) |
949 | errors |= PCMREC_E_IO; | 974 | pcmrec_raise_error_status(PCMREC_E_IO); |
950 | 975 | ||
951 | cpu_boost(false); | 976 | cpu_boost(false); |
952 | 977 | ||
@@ -1001,7 +1026,7 @@ static void pcmrec_new_stream(const char *filename, /* next file name */ | |||
1001 | 1026 | ||
1002 | if (filename) | 1027 | if (filename) |
1003 | strlcpy(path, filename, MAX_PATH); | 1028 | strlcpy(path, filename, MAX_PATH); |
1004 | queue_reply(&pcmrec_queue, 0); /* We have all we need */ | 1029 | queue_reply(&audio_queue, 0); /* We have all we need */ |
1005 | 1030 | ||
1006 | data.pre_chunk = NULL; | 1031 | data.pre_chunk = NULL; |
1007 | data.chunk = GET_ENC_CHUNK(enc_wr_index); | 1032 | data.chunk = GET_ENC_CHUNK(enc_wr_index); |
@@ -1129,51 +1154,18 @@ static void pcmrec_new_stream(const char *filename, /* next file name */ | |||
1129 | pcmrec_flush(PCMREC_FLUSH_IF_HIGH); | 1154 | pcmrec_flush(PCMREC_FLUSH_IF_HIGH); |
1130 | } /* pcmrec_new_stream */ | 1155 | } /* pcmrec_new_stream */ |
1131 | 1156 | ||
1157 | |||
1132 | /** event handlers for pcmrec thread */ | 1158 | /** event handlers for pcmrec thread */ |
1133 | 1159 | ||
1134 | /* PCMREC_INIT */ | 1160 | /* PCMREC_INIT */ |
1135 | static void pcmrec_init(void) | 1161 | static void pcmrec_init(void) |
1136 | { | 1162 | { |
1137 | is_initialized = true; | ||
1138 | |||
1139 | unsigned char *buffer; | ||
1140 | send_event(RECORDING_EVENT_START, NULL); | 1163 | send_event(RECORDING_EVENT_START, NULL); |
1141 | |||
1142 | /* warings and errors */ | ||
1143 | warnings = | ||
1144 | errors = 0; | ||
1145 | |||
1146 | pcmrec_close_file(&rec_fdata.rec_file); | 1164 | pcmrec_close_file(&rec_fdata.rec_file); |
1147 | rec_fdata.rec_file = -1; | ||
1148 | 1165 | ||
1149 | /* pcm FIFO */ | 1166 | pcmrec_init_state(); |
1150 | dma_lock = true; | ||
1151 | pcm_rd_pos = 0; | ||
1152 | dma_wr_pos = 0; | ||
1153 | pcm_enc_pos = 0; | ||
1154 | 1167 | ||
1155 | /* encoder FIFO */ | 1168 | unsigned char *buffer = audio_get_buffer(true, &rec_buffer_size); |
1156 | enc_wr_index = 0; | ||
1157 | enc_rd_index = 0; | ||
1158 | |||
1159 | /* filename queue */ | ||
1160 | fnq_rd_pos = 0; | ||
1161 | fnq_wr_pos = 0; | ||
1162 | |||
1163 | /* stats */ | ||
1164 | num_rec_bytes = 0; | ||
1165 | num_rec_samples = 0; | ||
1166 | #if 0 | ||
1167 | accum_rec_bytes = 0; | ||
1168 | accum_pcm_samples = 0; | ||
1169 | #endif | ||
1170 | |||
1171 | pre_record_ticks = 0; | ||
1172 | |||
1173 | is_recording = false; | ||
1174 | is_paused = false; | ||
1175 | |||
1176 | buffer = audio_get_recording_buffer(&rec_buffer_size); | ||
1177 | 1169 | ||
1178 | /* Line align pcm_buffer 2^5=32 bytes */ | 1170 | /* Line align pcm_buffer 2^5=32 bytes */ |
1179 | pcm_buffer = (unsigned char *)ALIGN_UP_P2((uintptr_t)buffer, 5); | 1171 | pcm_buffer = (unsigned char *)ALIGN_UP_P2((uintptr_t)buffer, 5); |
@@ -1188,23 +1180,25 @@ static void pcmrec_init(void) | |||
1188 | /* PCMREC_CLOSE */ | 1180 | /* PCMREC_CLOSE */ |
1189 | static void pcmrec_close(void) | 1181 | static void pcmrec_close(void) |
1190 | { | 1182 | { |
1191 | is_initialized = false; | ||
1192 | dma_lock = true; | 1183 | dma_lock = true; |
1193 | pre_record_ticks = 0; /* Can't be prerecording any more */ | 1184 | pre_record_ticks = 0; /* Can't be prerecording any more */ |
1194 | warnings = 0; | 1185 | warnings = 0; |
1186 | codec_unload(); | ||
1195 | pcm_close_recording(); | 1187 | pcm_close_recording(); |
1196 | reset_hardware(); | 1188 | reset_hardware(); |
1197 | audio_remove_encoder(); | ||
1198 | send_event(RECORDING_EVENT_STOP, NULL); | 1189 | send_event(RECORDING_EVENT_STOP, NULL); |
1199 | } /* pcmrec_close */ | 1190 | } /* pcmrec_close */ |
1200 | 1191 | ||
1201 | /* PCMREC_OPTIONS */ | 1192 | /* PCMREC_OPTIONS */ |
1202 | static void pcmrec_set_recording_options( | 1193 | static void pcmrec_set_recording_options( |
1194 | struct event_queue *q, | ||
1203 | struct audio_recording_options *options) | 1195 | struct audio_recording_options *options) |
1204 | { | 1196 | { |
1205 | /* stop DMA transfer */ | 1197 | /* stop everything */ |
1206 | dma_lock = true; | 1198 | dma_lock = true; |
1199 | codec_unload(); | ||
1207 | pcm_stop_recording(); | 1200 | pcm_stop_recording(); |
1201 | pcmrec_init_state(); | ||
1208 | 1202 | ||
1209 | rec_frequency = options->rec_frequency; | 1203 | rec_frequency = options->rec_frequency; |
1210 | rec_source = options->rec_source; | 1204 | rec_source = options->rec_source; |
@@ -1243,10 +1237,13 @@ static void pcmrec_set_recording_options( | |||
1243 | /* apply hardware setting to start monitoring now */ | 1237 | /* apply hardware setting to start monitoring now */ |
1244 | pcm_apply_settings(); | 1238 | pcm_apply_settings(); |
1245 | 1239 | ||
1246 | queue_reply(&pcmrec_queue, 0); /* Release sender */ | 1240 | if (codec_load(-1, enc_config.afmt | CODEC_TYPE_ENCODER)) |
1247 | |||
1248 | if (audio_load_encoder(enc_config.afmt)) | ||
1249 | { | 1241 | { |
1242 | queue_reply(q, true); | ||
1243 | |||
1244 | /* run immediately */ | ||
1245 | codec_go(); | ||
1246 | |||
1250 | /* start DMA transfer */ | 1247 | /* start DMA transfer */ |
1251 | dma_lock = pre_record_ticks == 0; | 1248 | dma_lock = pre_record_ticks == 0; |
1252 | pcm_record_data(pcm_rec_have_more, pcm_rec_status_callback, | 1249 | pcm_record_data(pcm_rec_have_more, pcm_rec_status_callback, |
@@ -1255,7 +1252,7 @@ static void pcmrec_set_recording_options( | |||
1255 | else | 1252 | else |
1256 | { | 1253 | { |
1257 | logf("set rec opt: enc load failed"); | 1254 | logf("set rec opt: enc load failed"); |
1258 | errors |= PCMREC_E_LOAD_ENCODER; | 1255 | pcmrec_raise_error_status(PCMREC_E_LOAD_ENCODER); |
1259 | } | 1256 | } |
1260 | } /* pcmrec_set_recording_options */ | 1257 | } /* pcmrec_set_recording_options */ |
1261 | 1258 | ||
@@ -1468,97 +1465,65 @@ static void pcmrec_resume(void) | |||
1468 | logf("pcmrec_resume done"); | 1465 | logf("pcmrec_resume done"); |
1469 | } /* pcmrec_resume */ | 1466 | } /* pcmrec_resume */ |
1470 | 1467 | ||
1471 | static void pcmrec_thread(void) NORETURN_ATTR; | 1468 | /* Called by audio thread when recording is initialized */ |
1472 | static void pcmrec_thread(void) | 1469 | void audio_recording_handler(struct queue_event *ev) |
1473 | { | 1470 | { |
1474 | struct queue_event ev; | 1471 | logf("audio recording start"); |
1475 | |||
1476 | logf("thread pcmrec start"); | ||
1477 | 1472 | ||
1478 | while(1) | 1473 | while (1) |
1479 | { | 1474 | { |
1480 | if (is_recording) | 1475 | switch (ev->id) |
1481 | { | 1476 | { |
1482 | /* Poll periodically to flush data */ | 1477 | case Q_AUDIO_INIT_RECORDING: |
1483 | queue_wait_w_tmo(&pcmrec_queue, &ev, HZ/5); | 1478 | pcmrec_init(); |
1484 | 1479 | break; | |
1485 | if (ev.id == SYS_TIMEOUT) | ||
1486 | { | ||
1487 | /* Messages that interrupt this will complete it */ | ||
1488 | pcmrec_flush(PCMREC_FLUSH_IF_HIGH | | ||
1489 | PCMREC_FLUSH_INTERRUPTABLE); | ||
1490 | continue; | ||
1491 | } | ||
1492 | } | ||
1493 | else | ||
1494 | { | ||
1495 | /* Not doing anything - sit and wait for commands */ | ||
1496 | queue_wait(&pcmrec_queue, &ev); | ||
1497 | |||
1498 | /* Some messages must be handled even if not initialized */ | ||
1499 | switch (ev.id) | ||
1500 | { | ||
1501 | case PCMREC_INIT: | ||
1502 | case SYS_USB_CONNECTED: | ||
1503 | break; | ||
1504 | default: | ||
1505 | if (!is_initialized) | ||
1506 | continue; | ||
1507 | } | ||
1508 | } | ||
1509 | |||
1510 | switch (ev.id) | ||
1511 | { | ||
1512 | case PCMREC_INIT: | ||
1513 | pcmrec_init(); | ||
1514 | break; | ||
1515 | |||
1516 | case PCMREC_CLOSE: | ||
1517 | pcmrec_close(); | ||
1518 | break; | ||
1519 | 1480 | ||
1520 | case PCMREC_OPTIONS: | 1481 | case SYS_USB_CONNECTED: |
1521 | pcmrec_set_recording_options( | 1482 | if (is_recording) |
1522 | (struct audio_recording_options *)ev.data); | ||
1523 | break; | 1483 | break; |
1484 | /* Fall-through */ | ||
1485 | case Q_AUDIO_CLOSE_RECORDING: | ||
1486 | pcmrec_close(); | ||
1487 | return; /* no more recording */ | ||
1488 | |||
1489 | case Q_AUDIO_RECORDING_OPTIONS: | ||
1490 | pcmrec_set_recording_options(&audio_queue, | ||
1491 | (struct audio_recording_options *)ev->data); | ||
1492 | break; | ||
1524 | 1493 | ||
1525 | case PCMREC_RECORD: | 1494 | case Q_AUDIO_RECORD: |
1526 | clear_flush_interrupt(); | 1495 | clear_flush_interrupt(); |
1527 | pcmrec_record((const char *)ev.data); | 1496 | pcmrec_record((const char *)ev->data); |
1528 | break; | 1497 | break; |
1529 | 1498 | ||
1530 | case PCMREC_STOP: | 1499 | case Q_AUDIO_STOP: |
1531 | clear_flush_interrupt(); | 1500 | clear_flush_interrupt(); |
1532 | pcmrec_stop(); | 1501 | pcmrec_stop(); |
1533 | break; | 1502 | break; |
1534 | 1503 | ||
1535 | case PCMREC_PAUSE: | 1504 | case Q_AUDIO_PAUSE: |
1536 | clear_flush_interrupt(); | 1505 | clear_flush_interrupt(); |
1537 | pcmrec_pause(); | 1506 | pcmrec_pause(); |
1538 | break; | 1507 | break; |
1539 | 1508 | ||
1540 | case PCMREC_RESUME: | 1509 | case Q_AUDIO_RESUME: |
1541 | pcmrec_resume(); | 1510 | pcmrec_resume(); |
1542 | break; | 1511 | break; |
1543 | #if 0 | ||
1544 | case PCMREC_FLUSH_NUM: | ||
1545 | pcmrec_flush((unsigned)ev.data); | ||
1546 | break; | ||
1547 | #endif | ||
1548 | case SYS_USB_CONNECTED: | ||
1549 | if (is_recording) | ||
1550 | break; | ||
1551 | 1512 | ||
1552 | if (is_initialized) | 1513 | case SYS_TIMEOUT: |
1553 | pcmrec_close(); | 1514 | /* Messages that interrupt this will complete it */ |
1515 | pcmrec_flush(PCMREC_FLUSH_IF_HIGH | | ||
1516 | PCMREC_FLUSH_INTERRUPTABLE); | ||
1554 | 1517 | ||
1555 | usb_acknowledge(SYS_USB_CONNECTED_ACK); | 1518 | if (errors & PCMREC_E_DMA) |
1556 | usb_wait_for_disconnect(&pcmrec_queue); | 1519 | queue_post(&audio_queue, Q_AUDIO_STOP, 0); |
1557 | flush_interrupts = 0; | 1520 | break; |
1558 | break; | ||
1559 | } /* end switch */ | 1521 | } /* end switch */ |
1522 | |||
1523 | queue_wait_w_tmo(&audio_queue, ev, | ||
1524 | is_recording ? HZ/5 : TIMEOUT_BLOCK); | ||
1560 | } /* end while */ | 1525 | } /* end while */ |
1561 | } /* pcmrec_thread */ | 1526 | } /* audio_recording_handler */ |
1562 | 1527 | ||
1563 | /****************************************************************************/ | 1528 | /****************************************************************************/ |
1564 | /* */ | 1529 | /* */ |
@@ -1696,7 +1661,7 @@ struct enc_chunk_hdr * enc_get_chunk(void) | |||
1696 | #ifdef DEBUG | 1661 | #ifdef DEBUG |
1697 | if (chunk->id != ENC_CHUNK_MAGIC || *wrap_id_p != ENC_CHUNK_MAGIC) | 1662 | if (chunk->id != ENC_CHUNK_MAGIC || *wrap_id_p != ENC_CHUNK_MAGIC) |
1698 | { | 1663 | { |
1699 | errors |= PCMREC_E_CHUNK_OVF; | 1664 | pcmrec_raise_error_status(PCMREC_E_CHUNK_OVF); |
1700 | logf("finish chk ovf: %d", enc_wr_index); | 1665 | logf("finish chk ovf: %d", enc_wr_index); |
1701 | } | 1666 | } |
1702 | #endif | 1667 | #endif |
@@ -1718,7 +1683,7 @@ void enc_finish_chunk(void) | |||
1718 | if ((long)chunk->flags < 0) | 1683 | if ((long)chunk->flags < 0) |
1719 | { | 1684 | { |
1720 | /* encoder set error flag */ | 1685 | /* encoder set error flag */ |
1721 | errors |= PCMREC_E_ENCODER; | 1686 | pcmrec_raise_error_status(PCMREC_E_ENCODER); |
1722 | logf("finish chk enc error"); | 1687 | logf("finish chk enc error"); |
1723 | } | 1688 | } |
1724 | 1689 | ||
@@ -1737,7 +1702,7 @@ void enc_finish_chunk(void) | |||
1737 | else if (is_recording) /* buffer full */ | 1702 | else if (is_recording) /* buffer full */ |
1738 | { | 1703 | { |
1739 | /* keep current position and put up warning flag */ | 1704 | /* keep current position and put up warning flag */ |
1740 | warnings |= PCMREC_W_ENC_BUFFER_OVF; | 1705 | pcmrec_raise_warning_status(PCMREC_W_ENC_BUFFER_OVF); |
1741 | logf("enc_buffer ovf"); | 1706 | logf("enc_buffer ovf"); |
1742 | DEC_ENC_INDEX(enc_wr_index); | 1707 | DEC_ENC_INDEX(enc_wr_index); |
1743 | if (pcmrec_context) | 1708 | if (pcmrec_context) |