Rockbox open source high quality audio player as a Music Player Daemon
mpris rockbox mpd libadwaita audio rust zig deno
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

Update software recording engine to latest codec interface.

Basically, just give it a good rewrite.

Software codec recording can be implemented in a more straightforward
and simple manner and made more robust through the better codec
control now available.

Encoded audio buffer uses a packed format instead of fixed-size
chunks and uses smaller data headers leading to more efficient usage.
The greatest benefit is with a VBR format like wavpack which needs
to request a maximum size but only actually ends up committing part
of that request.

No guard buffers are used for either PCM or encoded audio. PCM is
read into the codec's provided buffer and mono conversion done at
that time in the core if required. Any highly-specialized sample
conversion is still done within the codec itself, such as 32-bit
(wavpack) or interleaved mono (mp3).

There is no longer a separate filename array. All metadata goes
onto the main encoded audio buffer, eliminating any predermined
file limit on the buffer as well as not wasting the space for
unused path queue slots.

The core and codec interface is less awkward and a bit more sensible.
Some less useful interface features were removed. Threads are kept
on narrow code paths ie. the audio thread never calls encoding
functions and the codec thread never calls file functions as before.

Codecs no longer call file functions directly. Writes are buffered
in the core and data written to storage in larger chunks to speed up
flushing of data. In fact, codecs are no longer aware of the stream
being a file at all and have no access to the fd.

SPDIF frequency detection no longer requires a restart of recording
or plugging the source before entering the screen. It will poll
for changes and update when stopped or prerecording (which does
discard now-invalid prerecorded data).

I've seen to it that writing a proper header on full disk works
when the format makes it reasonably practical to do so. Other cases
may have incorrect data sizes but sample info will be in tact. File
left that way may play anyway.

mp3_enc.codec acquires the ability to write 'Info' headers with LAME
tags to make it gapless (bonus).

Change-Id: I670685166d5eb32ef58ef317f50b8af766ceb653
Reviewed-on: http://gerrit.rockbox.org/493
Reviewed-by: Michael Sevakis <jethead71@rockbox.org>
Tested-by: Michael Sevakis <jethead71@rockbox.org>

+2640 -2768
+13 -1
apps/audio_thread.c
··· 108 108 } 109 109 } 110 110 111 + void audio_queue_post(long id, intptr_t data) 112 + { 113 + queue_post(&audio_queue, id, data); 114 + } 115 + 116 + intptr_t audio_queue_send(long id, intptr_t data) 117 + { 118 + return queue_send(&audio_queue, id, data); 119 + } 120 + 111 121 /* Return the playback and recording status */ 112 122 int audio_status(void) 113 123 { ··· 156 166 audio_thread_id); 157 167 158 168 playback_init(); 159 - /* Recording doesn't need init call */ 169 + #ifdef AUDIO_HAVE_RECORDING 170 + recording_init(); 171 + #endif 160 172 161 173 /* ...now...audio_reset_buffer must know the size of voicefile buffer so 162 174 init talk first which will init the buffers */
+8 -1
apps/audio_thread.h
··· 74 74 Q_AUDIO_CLOSE_RECORDING, 75 75 Q_AUDIO_RECORDING_OPTIONS, 76 76 Q_AUDIO_RECORD, 77 - Q_AUDIO_RESUME, 77 + Q_AUDIO_RECORD_STOP, 78 + Q_AUDIO_RECORD_PAUSE, 79 + Q_AUDIO_RECORD_RESUME, 80 + Q_AUDIO_RECORD_FLUSH, 78 81 #endif 79 82 80 83 /*- settings -*/ ··· 98 101 #ifdef AUDIO_HAVE_RECORDING 99 102 void audio_recording_handler(struct queue_event *ev); 100 103 #endif 104 + 105 + /** --- audio_queue helpers --- **/ 106 + void audio_queue_post(long id, intptr_t data); 107 + intptr_t audio_queue_send(long id, intptr_t data); 101 108 102 109 #endif /* AUDIO_THREAD_H */
+52 -7
apps/codec_thread.c
··· 249 249 return; /* No input remains and DSP purged */ 250 250 } 251 251 } 252 - } 252 + } 253 253 } 254 254 255 255 /* helper function, not a callback */ ··· 365 365 366 366 queue_peek(&codec_queue, &ev); /* Find out what it is */ 367 367 368 - long id = ev.id; 368 + intptr_t id = ev.id; 369 369 370 370 switch (id) 371 371 { 372 + case Q_NULL: 373 + LOGFQUEUE("codec < Q_NULL"); 374 + break; 375 + 372 376 case Q_CODEC_RUN: /* Already running */ 373 377 LOGFQUEUE("codec < Q_CODEC_RUN"); 374 378 break; ··· 388 392 break; 389 393 390 394 case Q_CODEC_STOP: /* Must only return 0 in main loop */ 391 - LOGFQUEUE("codec < Q_CODEC_STOP"); 392 - dsp_configure(ci.dsp, DSP_FLUSH, 0); /* Discontinuity */ 395 + LOGFQUEUE("codec < Q_CODEC_STOP: %ld", ev.data); 396 + #ifdef HAVE_RECORDING 397 + if (type_is_encoder(codec_type)) 398 + { 399 + /* Stream finish request (soft stop)? */ 400 + if (ev.data && param) 401 + { 402 + /* ev.data is pointer to size */ 403 + *param = ev.data; 404 + action = CODEC_ACTION_STREAM_FINISH; 405 + break; 406 + } 407 + } 408 + else 409 + #endif /* HAVE_RECORDING */ 410 + { 411 + dsp_configure(ci.dsp, DSP_FLUSH, 0); /* Discontinuity */ 412 + } 413 + 393 414 return CODEC_ACTION_HALT; /* Leave in queue */ 394 415 395 416 default: /* This is in error in this context. */ ··· 459 480 } 460 481 } 461 482 462 - if (status >= 0) 483 + /* Types must agree */ 484 + if (status >= 0 && encoder == !!codec_get_enc_callback()) 463 485 { 464 486 codec_type = data.afmt; 465 487 codec_queue_ack(Q_CODEC_LOAD); ··· 558 580 { 559 581 struct queue_event ev; 560 582 561 - while (1) 583 + while (1) 562 584 { 563 585 cancel_cpu_boost(); 564 586 ··· 685 707 void codec_stop(void) 686 708 { 687 709 /* Wait until it's in the main loop */ 688 - LOGFQUEUE("audio >| codec Q_CODEC_STOP"); 710 + LOGFQUEUE("audio >| codec Q_CODEC_STOP: 0"); 689 711 while (codec_queue_send(Q_CODEC_STOP, 0) != Q_NULL); 690 712 } 713 + 714 + #ifdef HAVE_RECORDING 715 + /* Tells codec to take final encoding step and then exit - 716 + Returns minimum buffer size required or 0 if complete */ 717 + size_t codec_finish_stream(void) 718 + { 719 + size_t size = 0; 720 + 721 + LOGFQUEUE("audio >| codec Q_CODEC_STOP: &size"); 722 + if (codec_queue_send(Q_CODEC_STOP, (intptr_t)&size) != Q_NULL) 723 + { 724 + /* Sync to keep size in scope and get response */ 725 + LOGFQUEUE("audio >| codec Q_NULL"); 726 + codec_queue_send(Q_NULL, 0); 727 + 728 + if (size == 0) 729 + codec_stop(); /* Replied with 0 size */ 730 + } 731 + /* else thread running in the main loop */ 732 + 733 + return size; 734 + } 735 + #endif /* HAVE_RECORDING */ 691 736 692 737 /* Call the codec's exit routine and close all references */ 693 738 void codec_unload(void)
+3
apps/codec_thread.h
··· 46 46 bool codec_pause(void); 47 47 void codec_seek(long time); 48 48 void codec_stop(void); 49 + #ifdef HAVE_RECORDING 50 + size_t codec_finish_stream(void); 51 + #endif 49 52 void codec_unload(void); 50 53 int codec_loaded(void); 51 54
+21 -22
apps/codecs.c
··· 73 73 74 74 extern void* plugin_get_audio_buffer(size_t *buffer_size); 75 75 76 - #if (CONFIG_PLATFORM & PLATFORM_NATIVE) && defined(HAVE_RECORDING) 77 - #undef open 78 - static int open(const char* pathname, int flags, ...) 79 - { 80 - return file_open(pathname, flags); 81 - } 82 - #endif 83 76 struct codec_api ci = { 84 77 85 78 0, /* filesize */ ··· 99 92 NULL, /* configure */ 100 93 NULL, /* get_command */ 101 94 NULL, /* loop_track */ 102 - 95 + 103 96 /* kernel/ system */ 104 97 #if defined(CPU_ARM) && CONFIG_PLATFORM & PLATFORM_NATIVE 105 98 __div0, ··· 147 140 #endif 148 141 149 142 #ifdef HAVE_RECORDING 150 - enc_get_inputs, 151 - enc_set_parameters, 152 - enc_get_chunk, 153 - enc_finish_chunk, 154 - enc_get_pcm_data, 155 - enc_unget_pcm_data, 156 - 157 - /* file */ 158 - (open_func)PREFIX(open), 159 - PREFIX(close), 160 - (read_func)PREFIX(read), 161 - PREFIX(lseek), 162 - (write_func)PREFIX(write), 143 + NULL, /* enc_pcmbuf_read */ 144 + NULL, /* enc_pcmbuf_advance */ 145 + NULL, /* enc_encbuf_get_buffer */ 146 + NULL, /* enc_encbuf_finish_buffer */ 147 + NULL, /* enc_stream_read */ 148 + NULL, /* enc_stream_lseek */ 149 + NULL, /* enc_stream_write */ 163 150 round_value_to_list32, 164 - 165 151 #endif /* HAVE_RECORDING */ 166 152 167 153 /* new stuff at the end, sort into place next time ··· 299 285 300 286 return status; 301 287 } 288 + 289 + #ifdef HAVE_RECORDING 290 + enc_callback_t codec_get_enc_callback(void) 291 + { 292 + if (curr_handle == NULL || 293 + c_hdr->lc_hdr.magic != CODEC_ENC_MAGIC) { 294 + logf("Codec: not an encoder"); 295 + return NULL; 296 + } 297 + 298 + return c_hdr->rec_extension[0]; 299 + } 300 + #endif /* HAVE_RECORDING */
-12
apps/playback.c
··· 351 351 pcmbuf_soft_mode(*(bool *)data); 352 352 } 353 353 354 - /** --- audio_queue helpers --- **/ 355 - static void audio_queue_post(long id, intptr_t data) 356 - { 357 - queue_post(&audio_queue, id, data); 358 - } 359 - 360 - static intptr_t audio_queue_send(long id, intptr_t data) 361 - { 362 - return queue_send(&audio_queue, id, data); 363 - } 364 - 365 - 366 354 /** --- MP3Entry --- **/ 367 355 368 356 /* Does the mp3entry have enough info for us to use it? */
+1560 -1342
apps/recorder/pcm_record.c
··· 7 7 * \/ \/ \/ \/ \/ 8 8 * $Id$ 9 9 * 10 - * Copyright (C) 2005 by Linus Nielsen Feltzing 10 + * Copyright (C) 2005 Linus Nielsen Feltzing 11 + * Copyright (C) 2006 Antonius Hellmann 12 + * Copyright (C) 2006-2013 Michael Sevakis 13 + * 11 14 * 12 15 * This program is free software; you can redistribute it and/or 13 16 * modify it under the terms of the GNU General Public License ··· 18 21 * KIND, either express or implied. 19 22 * 20 23 ****************************************************************************/ 21 - 22 24 #include "config.h" 23 - #include "gcc_extensions.h" 24 - #include "pcm_record.h" 25 25 #include "system.h" 26 26 #include "kernel.h" 27 + #include "pcm_record.h" 28 + #include "codecs.h" 27 29 #include "logf.h" 28 30 #include "thread.h" 29 - #include "string-extra.h" 30 31 #include "storage.h" 31 - #include "usb.h" 32 32 #include "general.h" 33 33 #include "codec_thread.h" 34 34 #include "audio.h" ··· 40 40 #endif 41 41 #include "audio_thread.h" 42 42 43 - /***************************************************************************/ 43 + /* Macros to enable logf for queues 44 + logging on SYS_TIMEOUT can be disabled */ 45 + #ifdef SIMULATOR 46 + /* Define this for logf output of all queuing except SYS_TIMEOUT */ 47 + #define PCMREC_LOGQUEUES 48 + /* Define this to logf SYS_TIMEOUT messages */ 49 + /*#define PCMREC_LOGQUEUES_SYS_TIMEOUT*/ 50 + #endif /* SIMULATOR */ 51 + 52 + #ifdef PCMREC_LOGQUEUES 53 + #define LOGFQUEUE logf 54 + #else 55 + #define LOGFQUEUE(...) 56 + #endif 57 + 58 + #ifdef PCMREC_LOGQUEUES_SYS_TIMEOUT 59 + #define LOGFQUEUE_SYS_TIMEOUT logf 60 + #else 61 + #define LOGFQUEUE_SYS_TIMEOUT(...) 62 + #endif 63 + 64 + /** Target-related configuration **/ 65 + 66 + /** 67 + * PCM_NUM_CHUNKS: Number of PCM chunks 68 + * PCM_CHUNK_SAMP: Number of samples in a PCM chunk 69 + * PCM_BOOST_SECONDS: PCM level at which to boost CPU 70 + * PANIC_SECONDS: Flood watermark time until full 71 + * FLUSH_SECONDS: Flush watermark time until full 72 + * STREAM_BUF_SIZE: Size of stream write buffer 73 + * PRIO_SECONDS: Max flush time before prio boost 74 + * 75 + * Total PCM buffer size should be mem aligned 76 + * 77 + * Fractions should be left without parentheses so the multiplier is 78 + * multiplied by the numerator first. 79 + */ 80 + #if MEMORYSIZE <= 2 81 + #define PCM_NUM_CHUNKS 56 82 + #define PCM_CHUNK_SAMP 1024 83 + #define PCM_BOOST_SECONDS 1/2 84 + #define PANIC_SECONDS 1/2 85 + #define FLUSH_SECONDS 1 86 + #define FLUSH_MON_INTERVAL 1/6 87 + #define STREAM_BUF_SIZE 32768 88 + #elif MEMORYSIZE <= 16 89 + #define PANIC_SECONDS 5 90 + #define FLUSH_SECONDS 7 91 + #else /* MEMORYSIZE > 16 */ 92 + #define PANIC_SECONDS 8 93 + #define FLUSH_SECONDS 10 94 + #endif /* MEMORYSIZE */ 44 95 45 - extern struct event_queue audio_queue; 96 + /* Default values if not overridden above */ 97 + #ifndef PCM_NUM_CHUNKS 98 + #define PCM_NUM_CHUNKS 256 99 + #endif 100 + #ifndef PCM_CHUNK_SAMP 101 + #define PCM_CHUNK_SAMP 2048 102 + #endif 103 + #ifndef PCM_BOOST_SECONDS 104 + #define PCM_BOOST_SECONDS 1 105 + #endif 106 + #ifndef FLUSH_MON_INTERVAL 107 + #define FLUSH_MON_INTERVAL 1/4 108 + #endif 109 + #ifndef STREAM_BUF_SIZE 110 + #define STREAM_BUF_SIZE 65536 111 + #endif 112 + #ifndef PRIO_SECONDS 113 + #define PRIO_SECONDS 10 114 + #endif 115 + 116 + /* FAT limit for filesize. Recording will accept no further data from the 117 + * codec if this limit is reached in order to preserve its own data 118 + * integrity. A split should have made by the higher-ups long before this 119 + * point. 120 + * 121 + * Leave a generous 64k margin for metadata being added to file. */ 122 + #define MAX_NUM_REC_BYTES ((size_t)0x7fff0000u) 123 + 124 + /***************************************************************************/ 125 + extern struct codec_api ci; /* in codec_thread.c */ 126 + extern struct event_queue audio_queue; /* in audio_thread.c */ 127 + extern unsigned int audio_thread_id; /* in audio_thread.c */ 46 128 47 129 /** General recording state **/ 48 - static bool is_recording; /* We are recording */ 49 - static bool is_paused; /* We have paused */ 50 - static unsigned long errors; /* An error has occured */ 51 - static unsigned long warnings; /* Warning */ 52 - static int flush_interrupts = 0; /* Number of messages queued that 53 - should interrupt a flush in 54 - progress - 55 - for a safety net and a prompt 56 - response to stop, split and pause 57 - requests - 58 - only interrupts a flush initiated 59 - by pcmrec_flush(0) */ 60 130 61 - /* Utility functions for setting/clearing flushing interrupt flag */ 62 - static inline void flush_interrupt(void) 131 + /* Recording action being performed */ 132 + static enum record_status 63 133 { 64 - flush_interrupts++; 65 - logf("flush int: %d", flush_interrupts); 66 - } 134 + RECORD_STOPPED = 0, 135 + RECORD_PRERECORDING = AUDIO_STATUS_PRERECORD, 136 + RECORD_RECORDING = AUDIO_STATUS_RECORD, 137 + RECORD_PAUSED = (AUDIO_STATUS_RECORD | AUDIO_STATUS_PAUSE), 138 + } record_status = RECORD_STOPPED; 67 139 68 - static inline void clear_flush_interrupt(void) 140 + /* State of engine operations */ 141 + static enum record_state 69 142 { 70 - if (--flush_interrupts < 0) 71 - flush_interrupts = 0; 72 - } 143 + REC_STATE_IDLE, /* Stopped or prerecording */ 144 + REC_STATE_MONITOR, /* Monitoring buffer status */ 145 + REC_STATE_FLUSH, /* Flushing buffer */ 146 + } record_state = REC_STATE_IDLE; 73 147 74 - /** Stats on encoded data for current file **/ 75 - static size_t num_rec_bytes; /* Num bytes recorded */ 76 - static unsigned long num_rec_samples; /* Number of PCM samples recorded */ 148 + static uint32_t errors; /* An error has occured (bitmask) */ 149 + static uint32_t warnings; /* Non-fatal warnings (bitmask) */ 77 150 78 - /** Stats on encoded data for all files from start to stop **/ 79 - #if 0 80 - static unsigned long long accum_rec_bytes; /* total size written to chunks */ 81 - static unsigned long long accum_pcm_samples; /* total pcm count processed */ 82 - #endif 151 + static uint32_t rec_errors; /* Mirror of errors but private to 152 + * avoid race with controlling 153 + * thread. Engine uses this 154 + * internally. */ 83 155 84 - /* Keeps data about current file and is sent as event data for codec */ 85 - static struct enc_file_event_data rec_fdata IDATA_ATTR = 86 - { 87 - .chunk = NULL, 88 - .new_enc_size = 0, 89 - .new_num_pcm = 0, 90 - .rec_file = -1, 91 - .num_pcm_samples = 0 92 - }; 156 + /** Stats on encoded data for current file **/ 157 + static int rec_fd = -1; /* Currently open file descriptor */ 158 + static size_t num_rec_bytes; /* Number of bytes recorded */ 159 + static uint64_t num_rec_samples; /* Number of PCM samples recorded */ 160 + static uint64_t encbuf_rec_count; /* Count of slots written to buffer 161 + for current file */ 93 162 94 163 /** These apply to current settings **/ 95 - static int rec_source; /* current rec_source setting */ 96 - static int rec_frequency; /* current frequency setting */ 97 - static unsigned long sample_rate; /* Sample rate in HZ */ 164 + static int rec_source; /* Current rec_source setting */ 165 + static unsigned long sample_rate; /* Samplerate setting in HZ */ 98 166 static int num_channels; /* Current number of channels */ 99 - static int rec_mono_mode; /* how mono is created */ 100 167 static struct encoder_config enc_config; /* Current encoder configuration */ 101 - static unsigned long pre_record_ticks; /* pre-record time in ticks */ 168 + static unsigned int pre_record_seconds; /* Pre-record time in seconds */ 102 169 103 170 /**************************************************************************** 104 - use 2 circular buffers: 171 + Use 2 circular buffers: 105 172 pcm_buffer=DMA output buffer: chunks (8192 Bytes) of raw pcm audio data 106 173 enc_buffer=encoded audio buffer: storage for encoder output data 107 174 108 175 Flow: 109 - 1. when entering recording_screen DMA feeds the ringbuffer pcm_buffer 110 - 2. if enough pcm data are available the encoder codec does encoding of pcm 176 + 1. When entering recording_screen DMA feeds the ringbuffer pcm_buffer 177 + 2. If enough pcm data are available the encoder codec does encoding of pcm 111 178 chunks (4-8192 Bytes) into ringbuffer enc_buffer in codec_thread 112 179 3. pcmrec_callback detects enc_buffer 'near full' and writes data to disk 113 180 114 181 Functions calls (basic encoder steps): 115 - 1.main: audio_load_encoder(); start the encoder 116 - 2.encoder: enc_get_inputs(); get encoder recording settings 117 - 3.encoder: enc_set_parameters(); set the encoder parameters 118 - 4.encoder: enc_get_pcm_data(); get n bytes of unprocessed pcm data 119 - 5.encoder: enc_unget_pcm_data(); put n bytes of data back (optional) 120 - 6.encoder: enc_get_chunk(); get a ptr to next enc chunk 121 - 7.encoder: <process enc chunk> compress and store data to enc chunk 122 - 8.encoder: enc_finish_chunk(); inform main about chunk processed and 123 - is available to be written to a file. 124 - Encoder can place any number of chunks 125 - of PCM data in a single output chunk 126 - but must stay within its output chunk 127 - size 128 - 9.encoder: repeat 4. to 8. 129 - A.pcmrec: enc_events_callback(); called for certain events 182 + 1.audio: codec_load(); load the encoder 183 + 2.encoder: enc_init_parameters(); set the encoder parameters (at load) 184 + 3.audio: enc_callback(); configure encoder recording settings 185 + 4.audio: codec_go(); start encoding the new stream 186 + 5.encoder: enc_encbuf_get_buffer(); obtain an output buffer of size n 187 + 6.encoder: enc_pcmbuf_read(); read n bytes of unprocessed pcm data 188 + 7.encoder: enc_encbuf_finish_buffer(); add the obtained buffer to output 189 + 8.encoder: enc_pcmbuf_advance(); advance pcm by n samples 190 + 9.encoder: while more PCM available, repeat 5. to 9. 191 + 10.audio: codec_finish_stream(); finish the output for current stream 130 192 131 - (*) Optional step 193 + Function calls (basic stream flushing steps through enc_callback()): 194 + 1.audio: flush_stream_start(); stream flush destination is opening 195 + 2.audio: flush_stream_data(); flush encoded audio to stream 196 + 3.audio: while encoded data available, repeat 2. 197 + 4.audio: flush_stream_end(); stream flush destination is closing 198 + 132 199 ****************************************************************************/ 133 200 134 - /** buffer parameters where incoming PCM data is placed **/ 135 - #if MEMORYSIZE <= 2 136 - #define PCM_NUM_CHUNKS 16 /* Power of 2 */ 137 - #else 138 - #define PCM_NUM_CHUNKS 256 /* Power of 2 */ 139 - #endif 140 - #define PCM_CHUNK_SIZE 8192 /* Power of 2 */ 141 - #define PCM_CHUNK_MASK (PCM_NUM_CHUNKS*PCM_CHUNK_SIZE - 1) 201 + /** Buffer parameters where incoming PCM data is placed **/ 202 + #define PCM_DEPTH_BYTES (sizeof (int16_t)) 203 + #define PCM_SAMP_SIZE (2*PCM_DEPTH_BYTES) 204 + #define PCM_CHUNK_SIZE (PCM_CHUNK_SAMP*PCM_SAMP_SIZE) 205 + #define PCM_BUF_SIZE (PCM_NUM_CHUNKS*PCM_CHUNK_SIZE) 206 + 207 + /* Convert byte sizes into buffer slot counts */ 208 + #define CHUNK_SIZE_COUNT(size) \ 209 + (((size) + ENC_HDR_SIZE - 1) / ENC_HDR_SIZE) 210 + #define CHUNK_FILE_COUNT(size) \ 211 + ({ typeof (size) __size = (size); \ 212 + CHUNK_SIZE_COUNT(MIN(__size, MAX_PATH) + ENC_HDR_SIZE); }) 213 + #define CHUNK_FILE_COUNT_PATH(path) \ 214 + CHUNK_FILE_COUNT(strlen(path) + 1) 215 + #define CHUNK_DATA_COUNT(size) \ 216 + CHUNK_SIZE_COUNT((size) + sizeof (struct enc_chunk_data)) 217 + 218 + /* Min margin to write stream split headers without overwrap risk */ 219 + #define ENCBUF_MIN_SPLIT_MARGIN \ 220 + (2*(1 + CHUNK_FILE_COUNT(MAX_PATH)) - 1) 221 + 222 + static void *rec_buffer; /* Root rec buffer pointer */ 223 + static size_t rec_buffer_size; /* Root rec buffer size */ 224 + 225 + static void *pcm_buffer; /* Circular buffer for PCM samples */ 226 + static volatile bool pcm_pause; /* Freeze DMA write position */ 227 + static volatile size_t pcm_widx; /* Current DMA write position */ 228 + static volatile size_t pcm_ridx; /* Current PCM read position */ 229 + 230 + static union enc_chunk_hdr *enc_buffer; /* Circular encoding buffer */ 231 + static size_t enc_widx; /* Encoder chunk write index */ 232 + static size_t enc_ridx; /* Encoder chunk read index */ 233 + static size_t enc_buflen; /* Length of buffer in slots */ 234 + 235 + static unsigned char *stream_buffer; /* Stream-to-disk write buffer */ 236 + static ssize_t stream_buf_used; /* Stream write buffer occupancy */ 237 + 238 + static struct enc_chunk_file *fname_buf;/* Buffer with next file to create */ 142 239 143 - #define GET_PCM_CHUNK(offset) ((long *)(pcm_buffer + (offset))) 144 - #define GET_ENC_CHUNK(index) ENC_CHUNK_HDR(enc_buffer + enc_chunk_size*(index)) 145 - #define INC_ENC_INDEX(index) \ 146 - { if (++index >= enc_num_chunks) index = 0; } 147 - #define DEC_ENC_INDEX(index) \ 148 - { if (--index < 0) index = enc_num_chunks - 1; } 240 + static unsigned long enc_sample_rate; /* Samplerate used by encoder */ 241 + static bool pcm_buffer_empty; /* All PCM chunks processed? */ 149 242 150 - static size_t rec_buffer_size; /* size of available buffer */ 151 - static unsigned char *pcm_buffer; /* circular recording buffer */ 152 - static unsigned char *enc_buffer; /* circular encoding buffer */ 153 - #ifdef DEBUG 154 - static unsigned long *wrap_id_p; /* magic at wrap position - a debugging 155 - aid to check if the encoder data 156 - spilled out of its chunk */ 157 - #endif /* DEBUG */ 158 - static volatile int dma_wr_pos; /* current DMA write pos */ 159 - static int pcm_rd_pos; /* current PCM read pos */ 160 - static int pcm_enc_pos; /* position encoder is processing */ 161 - static volatile bool dma_lock; /* lock DMA write position */ 162 - static int enc_wr_index; /* encoder chunk write index */ 163 - static int enc_rd_index; /* encoder chunk read index */ 164 - static int enc_num_chunks; /* number of chunks in ringbuffer */ 165 - static size_t enc_chunk_size; /* maximum encoder chunk size */ 166 - static unsigned long enc_sample_rate; /* sample rate used by encoder */ 167 - static bool pcmrec_context = false; /* called by pcmrec thread? */ 168 - static bool pcm_buffer_empty; /* all pcm chunks processed? */ 243 + static typeof (memcpy) *pcm_copyfn; /* PCM memcpy or copy_buffer_mono */ 244 + static enc_callback_t enc_cb; /* Encoder's recording callback */ 169 245 170 - /** file flushing **/ 171 - static int low_watermark; /* Low watermark to stop flush */ 172 - static int high_watermark; /* max chunk limit for data flush */ 173 - static unsigned long spinup_time = 35*HZ/10; /* Fudged spinup time */ 174 - static int last_storage_spinup_time = -1;/* previous spin time used */ 175 - #ifdef HAVE_PRIORITY_SCHEDULING 176 - static int flood_watermark; /* boost thread priority when here */ 246 + /** File flushing **/ 247 + static unsigned long encbuf_datarate; /* Rate of data per second */ 248 + #if (CONFIG_STORAGE & STORAGE_ATA) 249 + static int spinup_time; /* Last spinup time */ 177 250 #endif 251 + static size_t high_watermark; /* Max limit for data flush */ 178 252 179 - /* Constants that control watermarks */ 180 - #define MINI_CHUNKS 10 /* chunk count for mini flush */ 181 253 #ifdef HAVE_PRIORITY_SCHEDULING 182 - #define PRIO_SECONDS 10 /* max flush time before priority boost */ 254 + static size_t flood_watermark; /* Max limit for thread prio boost */ 255 + static bool prio_boosted; 183 256 #endif 184 - #if MEMORYSIZE <= 2 185 - /* fractions must be integer fractions of 4 because they are evaluated with 186 - * X*4*XXX_SECONDS, that way we avoid float calculation */ 187 - #define LOW_SECONDS 1/4 /* low watermark time till empty */ 188 - #define PANIC_SECONDS 1/2 /* flood watermark time until full */ 189 - #define FLUSH_SECONDS 1 /* flush watermark time until full */ 190 - #elif MEMORYSIZE <= 16 191 - #define LOW_SECONDS 1 /* low watermark time till empty */ 192 - #define PANIC_SECONDS 5 /* flood watermark time until full */ 193 - #define FLUSH_SECONDS 7 /* flush watermark time until full */ 194 - #else 195 - #define LOW_SECONDS 1 /* low watermark time till empty */ 196 - #define PANIC_SECONDS 8 197 - #define FLUSH_SECONDS 10 198 - #endif /* MEMORYSIZE */ 199 257 200 - /** encoder events **/ 201 - static void (*enc_events_callback)(enum enc_events event, void *data); 202 - 203 - /** Path queue for files to write **/ 204 - #define FNQ_MIN_NUM_PATHS 16 /* minimum number of paths to hold */ 205 - #define FNQ_MAX_NUM_PATHS 64 /* maximum number of paths to hold */ 206 - static unsigned char *fn_queue; /* pointer to first filename */ 207 - static ssize_t fnq_size; /* capacity of queue in bytes */ 208 - static int fnq_rd_pos; /* current read position */ 209 - static int fnq_wr_pos; /* current write position */ 210 - #define FNQ_NEXT(pos) \ 211 - ({ int p = (pos) + MAX_PATH; \ 212 - if (p >= fnq_size) \ 213 - p = 0; \ 214 - p; }) 215 - #define FNQ_PREV(pos) \ 216 - ({ int p = (pos) - MAX_PATH; \ 217 - if (p < 0) \ 218 - p = fnq_size - MAX_PATH; \ 219 - p; }) 220 - 221 - enum 258 + /** Stream marking **/ 259 + enum mark_stream_action 222 260 { 223 - PCMREC_FLUSH_INTERRUPTABLE = 0x8000000, /* Flush can be interrupted by 224 - incoming messages - combine 225 - with other constants */ 226 - PCMREC_FLUSH_ALL = 0x7ffffff, /* Flush all files */ 227 - PCMREC_FLUSH_MINI = 0x7fffffe, /* Flush a small number of 228 - chunks */ 229 - PCMREC_FLUSH_IF_HIGH = 0x0000000, /* Flush if high watermark 230 - reached */ 261 + MARK_STREAM_END = 0x1, /* Mark end current stream */ 262 + MARK_STREAM_START = 0x2, /* Mark start of new stream */ 263 + MARK_STREAM_SPLIT = 0x3, /* Insert split; orr of above values */ 264 + MARK_STREAM_PRE = 0x4, /* Do prerecord data tally */ 265 + MARK_STREAM_START_PRE = MARK_STREAM_PRE | MARK_STREAM_START, 231 266 }; 267 + 232 268 233 269 /***************************************************************************/ 234 270 235 - enum 271 + /* Buffer pointer (p) to PCM sample memory address */ 272 + static inline void * pcmbuf_ptr(size_t p) 236 273 { 237 - PCMREC_NULL = 0, 238 - PCMREC_INIT, /* enable recording */ 239 - PCMREC_CLOSE, /* close recording */ 240 - PCMREC_OPTIONS, /* set recording options */ 241 - PCMREC_RECORD, /* record a new file */ 242 - PCMREC_STOP, /* stop the current recording */ 243 - PCMREC_PAUSE, /* pause the current recording */ 244 - PCMREC_RESUME, /* resume the current recording */ 245 - }; 274 + return pcm_buffer + p; 275 + } 246 276 247 - /*******************************************************************/ 248 - /* Functions that are not executing in the audio thread first */ 249 - /*******************************************************************/ 277 + /* Buffer pointer (p) plus value (v), wrapped if necessary */ 278 + static size_t pcmbuf_add(size_t p, size_t v) 279 + { 280 + size_t res = p + v; 281 + 282 + if (res >= PCM_BUF_SIZE) 283 + res -= PCM_BUF_SIZE; 284 + 285 + return res; 286 + } 250 287 251 - static void pcmrec_raise_error_status(unsigned long e) 288 + /* Size of data in PCM buffer */ 289 + size_t pcmbuf_used(void) 252 290 { 253 - pcm_rec_lock(); /* DMA sets this too */ 254 - errors |= e; 255 - pcm_rec_unlock(); 291 + size_t p1 = pcm_ridx; 292 + size_t p2 = pcm_widx; 293 + 294 + if (p1 > p2) 295 + p2 += PCM_BUF_SIZE; 296 + 297 + return p2 - p1; 256 298 } 257 299 258 - static void pcmrec_raise_warning_status(unsigned long w) 300 + /* Buffer pointer (p) to memory address of header */ 301 + static inline union enc_chunk_hdr * encbuf_ptr(size_t p) 259 302 { 260 - warnings |= w; 303 + return enc_buffer + p; 261 304 } 262 305 263 - /* Callback for when more data is ready - called in interrupt context */ 264 - static void pcm_rec_have_more(void **start, size_t *size) 306 + /* Buffer pointer (p) plus value (v), wrapped if necessary */ 307 + static size_t encbuf_add(size_t p, size_t v) 265 308 { 266 - if (!dma_lock) 267 - { 268 - /* advance write position */ 269 - int next_pos = (dma_wr_pos + PCM_CHUNK_SIZE) & PCM_CHUNK_MASK; 309 + size_t res = p + v; 270 310 271 - /* set pcm ovf if processing start position is inside current 272 - write chunk */ 273 - if ((unsigned)(pcm_enc_pos - next_pos) < PCM_CHUNK_SIZE) 274 - pcmrec_raise_warning_status(PCMREC_W_PCM_BUFFER_OVF); 311 + if (res >= enc_buflen) 312 + res -= enc_buflen; 275 313 276 - dma_wr_pos = next_pos; 277 - } 314 + return res; 315 + } 278 316 279 - *start = GET_PCM_CHUNK(dma_wr_pos); 280 - *size = PCM_CHUNK_SIZE; 281 - } /* pcm_rec_have_more */ 317 + /* Number of free buffer slots */ 318 + static size_t encbuf_free(void) 319 + { 320 + size_t p1 = enc_ridx; 321 + size_t p2 = enc_widx; 282 322 283 - static enum pcm_dma_status pcm_rec_status_callback(enum pcm_dma_status status) 284 - { 285 - if (status < PCM_DMAST_OK) 286 - { 287 - /* some error condition */ 288 - if (status == PCM_DMAST_ERR_DMA) 289 - { 290 - /* Flush recorded data to disk and stop recording */ 291 - errors |= PCMREC_E_DMA; 292 - return status; 293 - } 294 - /* else try again next transmission - frame is invalid */ 295 - } 323 + if (p2 >= p1) 324 + p1 += enc_buflen; 296 325 297 - return PCM_DMAST_OK; 298 - } /* pcm_rec_status_callback */ 326 + return p1 - p2; 327 + } 299 328 300 - static void reset_hardware(void) 329 + /* Number of used buffer slots */ 330 + static size_t encbuf_used(void) 301 331 { 302 - /* reset pcm to defaults */ 303 - pcm_set_frequency(HW_SAMPR_RESET | SAMPR_TYPE_REC); 304 - audio_set_output_source(AUDIO_SRC_PLAYBACK); 305 - pcm_apply_settings(); 332 + size_t p1 = enc_ridx; 333 + size_t p2 = enc_widx; 334 + 335 + if (p1 > p2) 336 + p2 += enc_buflen; 337 + 338 + return p2 - p1; 306 339 } 307 340 308 - /** pcm_rec_* group **/ 341 + /* Is the encoder buffer empty? */ 342 + static bool encbuf_empty(void) 343 + { 344 + return enc_ridx == enc_widx; 345 + } 309 346 310 - /** 311 - * Clear all errors and warnings 312 - */ 313 - void pcm_rec_error_clear(void) 347 + /* Buffer pointer (p) plus size (v), written to enc_widx, new widx 348 + * zero-initialized */ 349 + static void encbuf_widx_advance(size_t widx, size_t v) 314 350 { 315 - errors = warnings = 0; 316 - } /* pcm_rec_error_clear */ 351 + widx = encbuf_add(widx, v); 352 + encbuf_ptr(widx)->zero = 0; 353 + enc_widx = widx; 354 + } 317 355 318 - /** 319 - * Check mode, errors and warnings 320 - */ 321 - unsigned int pcm_rec_status(void) 356 + /* Buffer pointer (p) plus size of chunk at (p), wrapped to (0) if 357 + * necessary. 358 + * 359 + * pout points to variable to receive increment result 360 + * 361 + * Returns NULL if it was a wrap marker */ 362 + static void * encbuf_read_ptr_incr(size_t p, size_t *pout) 322 363 { 323 - unsigned int ret = 0; 364 + union enc_chunk_hdr *hdr = encbuf_ptr(p); 365 + size_t v; 324 366 325 - if (is_recording) 326 - ret |= AUDIO_STATUS_RECORD; 327 - else if (pre_record_ticks) 328 - ret |= AUDIO_STATUS_PRERECORD; 367 + switch (hdr->type) 368 + { 369 + case CHUNK_T_DATA: 370 + v = CHUNK_DATA_COUNT(hdr->size); 371 + break; 372 + case CHUNK_T_STREAM_START: 373 + v = hdr->size; 374 + break; 375 + case CHUNK_T_STREAM_END: 376 + default: 377 + v = 1; 378 + break; 379 + case CHUNK_T_WRAP: 380 + /* Wrap markers are not returned but caller may have to know that 381 + the index was changed since it impacts available space */ 382 + *pout = 0; 383 + return NULL; 384 + } 329 385 330 - if (is_paused) 331 - ret |= AUDIO_STATUS_PAUSE; 386 + *pout = encbuf_add(p, v); 387 + return hdr; 388 + } 332 389 333 - if (errors) 334 - ret |= AUDIO_STATUS_ERROR; 390 + /* Buffer pointer (p) of contiguous free space (v), wrapped to (0) if 391 + * necessary. 392 + * 393 + * pout points to variable to receive possible-adjusted p 394 + * 395 + * Returns header at (p) or wrapped header at (0) if wrap was 396 + * required in order to provide contiguous space. Header is zero- 397 + * initialized. 398 + * 399 + * Marks the wrap point if a wrap is required to make the allocation. */ 400 + static void * encbuf_get_write_ptr(size_t p, size_t v, size_t *pout) 401 + { 402 + union enc_chunk_hdr *hdr = encbuf_ptr(p); 335 403 336 - if (warnings) 337 - ret |= AUDIO_STATUS_WARNING; 404 + if (p + v > enc_buflen) 405 + { 406 + hdr->type = CHUNK_T_WRAP; /* All other fields ignored */ 407 + p = 0; 408 + hdr = encbuf_ptr(0); 409 + } 338 410 339 - return ret; 340 - } /* pcm_rec_status */ 411 + *pout = p; 412 + hdr->zero = 0; 413 + return hdr; 414 + } 341 415 342 - /** 343 - * Return warnings that have occured since recording started 344 - */ 345 - unsigned long pcm_rec_get_warnings(void) 416 + /* Post a flush request to audio thread, if none is currently queued */ 417 + static void encbuf_request_flush(void) 346 418 { 347 - return warnings; 419 + if (!queue_peek_ex(&audio_queue, NULL, 0, 420 + &(const long [2]){ Q_AUDIO_RECORD_FLUSH, 421 + Q_AUDIO_RECORD_FLUSH })) 422 + queue_post(&audio_queue, Q_AUDIO_RECORD_FLUSH, 0); 348 423 } 349 424 350 - #if 0 351 - int pcm_rec_current_bitrate(void) 425 + /* Set the error bits in (e): no lock */ 426 + static inline void set_error_bits(uint32_t e) 352 427 { 353 - if (accum_pcm_samples == 0) 354 - return 0; 428 + errors |= e; 429 + rec_errors |= e; 430 + } 355 431 356 - return (int)(8*accum_rec_bytes*enc_sample_rate / (1000*accum_pcm_samples)); 357 - } /* pcm_rec_current_bitrate */ 358 - #endif 432 + /* Clear the error bits in (e): no lock */ 433 + static inline void clear_error_bits(uint32_t e) 434 + { 435 + errors &= ~e; 436 + } 359 437 360 - #if 0 361 - int pcm_rec_encoder_afmt(void) 438 + /* Set the error bits in (e) */ 439 + static void raise_error_status(uint32_t e) 362 440 { 363 - return enc_config.afmt; 364 - } /* pcm_rec_encoder_afmt */ 365 - #endif 441 + pcm_rec_lock(); 442 + set_error_bits(e); 443 + pcm_rec_unlock(); 444 + } 366 445 367 - #if 0 368 - int pcm_rec_rec_format(void) 446 + /* Clear the error bits in (e) */ 447 + static void clear_error_status(uint32_t e) 369 448 { 370 - return afmt_rec_format[enc_config.afmt]; 371 - } /* pcm_rec_rec_format */ 372 - #endif 449 + pcm_rec_lock(); 450 + clear_error_bits(e); 451 + pcm_rec_unlock(); 452 + } 373 453 374 - #ifdef HAVE_SPDIF_IN 375 - unsigned long pcm_rec_sample_rate(void) 454 + /* Set the warning bits in (w): no lock */ 455 + static inline void set_warning_bits(uint32_t w) 376 456 { 377 - /* Which is better ?? */ 378 - #if 0 379 - return enc_sample_rate; 380 - #endif 381 - return sample_rate; 382 - } /* audio_get_sample_rate */ 383 - #endif 457 + warnings |= w; 458 + } 384 459 385 - /** audio_* group **/ 460 + /* Clear the warning bits in (w): no lock */ 461 + static inline void clear_warning_bits(uint32_t w) 462 + { 463 + warnings &= ~w; 464 + } 386 465 387 - /** 388 - * Initializes recording - call before calling any other recording function 389 - */ 390 - void audio_init_recording(void) 466 + /* Set the warning bits in (w) */ 467 + static void raise_warning_status(uint32_t w) 391 468 { 392 - logf("audio_init_recording"); 393 - queue_send(&audio_queue, Q_AUDIO_INIT_RECORDING, 1); 394 - logf("audio_init_recording done"); 395 - } /* audio_init_recording */ 469 + pcm_rec_lock(); 470 + set_warning_bits(w); 471 + pcm_rec_unlock(); 472 + } 396 473 397 - /** 398 - * Closes recording - call audio_stop_recording first 399 - */ 400 - void audio_close_recording(void) 474 + /* Clear the warning bits in (w) */ 475 + static void clear_warning_status(uint32_t w) 401 476 { 402 - logf("audio_close_recording"); 403 - queue_send(&audio_queue, Q_AUDIO_CLOSE_RECORDING, 0); 404 - logf("audio_close_recording done"); 405 - } /* audio_close_recording */ 477 + pcm_rec_lock(); 478 + clear_warning_bits(w); 479 + pcm_rec_unlock(); 480 + } 406 481 407 - /** 408 - * Sets recording parameters 409 - */ 410 - void audio_set_recording_options(struct audio_recording_options *options) 482 + /* Callback for when more data is ready - called by DMA ISR */ 483 + static void pcm_rec_have_more(void **start, size_t *size) 411 484 { 412 - logf("audio_set_recording_options"); 413 - queue_send(&audio_queue, Q_AUDIO_RECORDING_OPTIONS, (intptr_t)options); 414 - logf("audio_set_recording_options done"); 415 - } /* audio_set_recording_options */ 485 + size_t next_idx = pcm_widx; 486 + 487 + if (!pcm_pause) 488 + { 489 + /* One empty chunk must remain after widx is advanced */ 490 + if (pcmbuf_used() <= PCM_BUF_SIZE - 2*PCM_CHUNK_SIZE) 491 + next_idx = pcmbuf_add(next_idx, PCM_CHUNK_SIZE); 492 + else 493 + set_warning_bits(PCMREC_W_PCM_BUFFER_OVF); 494 + } 495 + 496 + *start = pcmbuf_ptr(next_idx); 497 + *size = PCM_CHUNK_SIZE; 416 498 417 - /** 418 - * Start recording if not recording or else split 419 - */ 420 - void audio_record(const char *filename) 499 + pcm_widx = next_idx; 500 + } 501 + 502 + static enum pcm_dma_status pcm_rec_status_callback(enum pcm_dma_status status) 421 503 { 422 - logf("audio_record: %s", filename); 423 - flush_interrupt(); 424 - queue_send(&audio_queue, Q_AUDIO_RECORD, (intptr_t)filename); 425 - logf("audio_record_done"); 426 - } /* audio_record */ 504 + if (status < PCM_DMAST_OK) 505 + { 506 + /* Some error condition */ 507 + if (status == PCM_DMAST_ERR_DMA) 508 + { 509 + set_error_bits(PCMREC_E_DMA); 510 + return status; 511 + } 512 + else 513 + { 514 + /* Try again next transmission - frame is invalid */ 515 + set_warning_bits(PCMREC_W_DMA); 516 + } 517 + } 427 518 428 - /** 429 - * audio_record wrapper for API compatibility with HW codec 430 - */ 431 - void audio_new_file(const char *filename) 519 + return PCM_DMAST_OK; 520 + } 521 + 522 + /* Start DMA transfer */ 523 + static void pcm_start_recording(void) 432 524 { 433 - audio_record(filename); 434 - } /* audio_new_file */ 525 + pcm_record_data(pcm_rec_have_more, pcm_rec_status_callback, 526 + pcmbuf_ptr(pcm_widx), PCM_CHUNK_SIZE); 527 + } 435 528 436 - /** 437 - * Stop current recording if recording 438 - */ 439 - void audio_stop_recording(void) 529 + /* Initialize the various recording buffers */ 530 + static void init_rec_buffers(void) 440 531 { 441 - logf("audio_stop_recording"); 442 - flush_interrupt(); 443 - queue_post(&audio_queue, Q_AUDIO_STOP, 0); 444 - logf("audio_stop_recording done"); 445 - } /* audio_stop_recording */ 532 + /* Layout of recording buffer: |PCMBUF|STREAMBUF|FILENAME|ENCBUF| */ 533 + void *buf = rec_buffer; 534 + size_t size = rec_buffer_size; 446 535 447 - /** 448 - * Pause current recording 449 - */ 450 - void audio_pause_recording(void) 451 - { 452 - logf("audio_pause_recording"); 453 - flush_interrupt(); 454 - queue_post(&audio_queue, Q_AUDIO_PAUSE, 0); 455 - logf("audio_pause_recording done"); 456 - } /* audio_pause_recording */ 536 + /* PCMBUF */ 537 + pcm_buffer = CACHEALIGN_UP(buf); /* Line align */ 538 + size -= pcm_buffer + PCM_BUF_SIZE - buf; 539 + buf = pcm_buffer + PCM_BUF_SIZE; 457 540 458 - /** 459 - * Resume current recording if paused 460 - */ 461 - void audio_resume_recording(void) 462 - { 463 - logf("audio_resume_recording"); 464 - queue_post(&audio_queue, Q_AUDIO_RESUME, 0); 465 - logf("audio_resume_recording done"); 466 - } /* audio_resume_recording */ 541 + /* STREAMBUF */ 542 + stream_buffer = buf; /* Also line-aligned */ 543 + buf += STREAM_BUF_SIZE; 544 + size -= STREAM_BUF_SIZE; 467 545 468 - /** 469 - * Note that microphone is mono, only left value is used 470 - * See audiohw_set_recvol() for exact ranges. 471 - * 472 - * @param type AUDIO_GAIN_MIC, AUDIO_GAIN_LINEIN 473 - * 474 - */ 475 - void audio_set_recording_gain(int left, int right, int type) 476 - { 477 - //logf("rcmrec: t=%d l=%d r=%d", type, left, right); 478 - audiohw_set_recvol(left, right, type); 479 - } /* audio_set_recording_gain */ 546 + /* FILENAME */ 547 + fname_buf = buf; 548 + buf += CHUNK_FILE_COUNT(MAX_PATH)*ENC_HDR_SIZE; 549 + size -= CHUNK_FILE_COUNT(MAX_PATH)*ENC_HDR_SIZE; 550 + fname_buf->hdr.zero = 0; 480 551 481 - /** Information about current state **/ 552 + /* ENCBUF */ 553 + enc_buffer = buf; 554 + enc_buflen = size; 555 + ALIGN_BUFFER(enc_buffer, enc_buflen, ENC_HDR_SIZE); 556 + enc_buflen = CHUNK_SIZE_COUNT(enc_buflen); 557 + } 482 558 483 - /** 484 - * Return current recorded time in ticks (playback eqivalent time) 485 - */ 486 - unsigned long audio_recorded_time(void) 559 + /* Reset the circular buffers */ 560 + static void reset_fifos(bool hard) 487 561 { 488 - if (!is_recording || enc_sample_rate == 0) 489 - return 0; 562 + /* PCM FIFO */ 563 + pcm_pause = true; 490 564 491 - /* return actual recorded time a la encoded data even if encoder rate 492 - doesn't match the pcm rate */ 493 - return (long)(HZ*(unsigned long long)num_rec_samples / enc_sample_rate); 494 - } /* audio_recorded_time */ 565 + if (hard) 566 + pcm_widx = 0; /* Don't just empty but reset it */ 495 567 496 - /** 497 - * Return number of bytes encoded to output 498 - */ 499 - unsigned long audio_num_recorded_bytes(void) 500 - { 501 - if (!is_recording) 502 - return 0; 568 + pcm_ridx = pcm_widx; 503 569 504 - return num_rec_bytes; 505 - } /* audio_num_recorded_bytes */ 570 + /* Encoder FIFO */ 571 + encbuf_widx_advance(0, 0); 572 + enc_ridx = 0; 506 573 507 - /***************************************************************************/ 508 - /* */ 509 - /* Functions that execute in the context of audio thread */ 510 - /* */ 511 - /***************************************************************************/ 574 + /* No overflow-related warnings now */ 575 + clear_warning_status(PCMREC_W_PCM_BUFFER_OVF | PCMREC_W_ENC_BUFFER_OVF); 576 + } 512 577 513 - static void pcmrec_init_state(void) 578 + /* Initialize file statistics */ 579 + static void reset_rec_stats(void) 514 580 { 515 - flush_interrupts = 0; 516 - 517 - /* warings and errors */ 518 - warnings = 519 - errors = 0; 581 + num_rec_bytes = 0; 582 + num_rec_samples = 0; 583 + encbuf_rec_count = 0; 584 + clear_warning_status(PCMREC_W_FILE_SIZE); 585 + } 520 586 521 - /* pcm FIFO */ 522 - dma_lock = true; 523 - pcm_rd_pos = 0; 524 - dma_wr_pos = 0; 525 - pcm_enc_pos = 0; 587 + /* Boost or unboost recording threads' priorities */ 588 + static void do_prio_boost(bool boost) 589 + { 590 + #ifdef HAVE_PRIORITY_SCHEDULING 591 + prio_boosted = boost; 526 592 527 - /* encoder FIFO */ 528 - enc_wr_index = 0; 529 - enc_rd_index = 0; 593 + int prio = PRIORITY_RECORDING; 530 594 531 - /* filename queue */ 532 - fnq_rd_pos = 0; 533 - fnq_wr_pos = 0; 595 + if (boost) 596 + prio -= 4; 534 597 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; 598 + codec_thread_set_priority(prio); 599 + thread_set_priority(audio_thread_id, prio); 541 600 #endif 601 + (void)boost; 602 + } 542 603 543 - pre_record_ticks = 0; 604 + /* Reset all relevant state */ 605 + static void init_state(void) 606 + { 607 + reset_fifos(true); 608 + reset_rec_stats(); 609 + do_prio_boost(false); 610 + cancel_cpu_boost(); 611 + record_state = REC_STATE_IDLE; 612 + record_status = RECORD_STOPPED; 613 + } 614 + 615 + /* Set hardware samplerate and save it */ 616 + static void update_samplerate_config(unsigned long sampr) 617 + { 618 + /* PCM samplerate is either the same as the setting or the nearest 619 + one hardware supports if using S/PDIF */ 620 + unsigned long pcm_sampr = sampr; 544 621 545 - is_recording = false; 546 - is_paused = false; 547 - } /* pcmrec_init_state */ 622 + #ifdef HAVE_SPDIF_IN 623 + if (rec_source == AUDIO_SRC_SPDIF) 624 + { 625 + int index = round_value_to_list32(sampr, hw_freq_sampr, 626 + HW_NUM_FREQ, false); 627 + pcm_sampr = hw_freq_sampr[index]; 628 + } 629 + #endif /* HAVE_SPDIF_IN */ 548 630 549 - /** Filename Queue **/ 631 + pcm_set_frequency(pcm_sampr | SAMPR_TYPE_REC); 632 + sample_rate = sampr; 633 + } 550 634 551 - /* returns true if the queue is empty */ 552 - static inline bool pcmrec_fnq_is_empty(void) 635 + /* Calculate the average data rate */ 636 + static unsigned long get_encbuf_datarate(void) 553 637 { 554 - return fnq_rd_pos == fnq_wr_pos; 555 - } /* pcmrec_fnq_is_empty */ 638 + /* If not yet calculable, start with uncompressed PCM byterate */ 639 + if (num_rec_samples && sample_rate && encbuf_rec_count) 640 + { 641 + return (encbuf_rec_count*sample_rate + num_rec_samples - 1) 642 + / num_rec_samples; 643 + } 644 + else 645 + { 646 + return CHUNK_SIZE_COUNT(sample_rate*num_channels*PCM_DEPTH_BYTES); 647 + } 648 + } 556 649 557 - /* empties the filename queue */ 558 - static inline void pcmrec_fnq_set_empty(void) 650 + /* Returns true if the watermarks should be updated due to data rate 651 + change */ 652 + static bool monitor_encbuf_datarate(void) 559 653 { 560 - fnq_rd_pos = fnq_wr_pos; 561 - } /* pcmrec_fnq_set_empty */ 654 + unsigned long rate = get_encbuf_datarate(); 655 + long diff = rate - encbuf_datarate; 656 + /* Off by more than 1/2 FLUSH_MON_INTERVAL? */ 657 + return 2*(unsigned long)abs(diff) > encbuf_datarate*FLUSH_MON_INTERVAL; 658 + } 562 659 563 - /* returns true if the queue is full */ 564 - static bool pcmrec_fnq_is_full(void) 660 + /* Get adjusted spinup time */ 661 + static int get_spinup_time(void) 565 662 { 566 - ssize_t size = fnq_wr_pos - fnq_rd_pos; 567 - if (size < 0) 568 - size += fnq_size; 663 + int spin = storage_spinup_time(); 569 664 570 - return size >= fnq_size - MAX_PATH; 571 - } /* pcmrec_fnq_is_full */ 665 + #if (CONFIG_STORAGE & STORAGE_ATA) 666 + /* Write at FLUSH_SECONDS + st remaining in enc_buffer - range fs+2s to 667 + fs+10s total - default to 3.5s spinup. */ 668 + if (spin == 0) 669 + spin = 35*HZ/10; /* default - cozy */ 670 + else if (spin < 2*HZ) 671 + spin = 2*HZ; /* ludicrous - ramdisk? */ 672 + else if (spin > 10*HZ) 673 + spin = 10*HZ; /* do you have a functioning HD? */ 674 + #endif /* (CONFIG_STORAGE & STORAGE_ATA) */ 572 675 573 - /* queue another filename - will overwrite oldest one if full */ 574 - static bool pcmrec_fnq_add_filename(const char *filename) 676 + return spin; 677 + } 678 + 679 + /* Returns true if the watermarks should be updated due to spinup time 680 + change */ 681 + static inline bool monitor_spinup_time(void) 682 + { 683 + #if (CONFIG_STORAGE & STORAGE_ATA) 684 + return get_spinup_time() != spinup_time; 685 + #else 686 + return false; 687 + #endif 688 + } 689 + 690 + /* Update buffer watermarks with spinup time compensation */ 691 + static void refresh_watermarks(void) 575 692 { 576 - strlcpy(fn_queue + fnq_wr_pos, filename, MAX_PATH); 577 - fnq_wr_pos = FNQ_NEXT(fnq_wr_pos); 693 + int spin = get_spinup_time(); 694 + #if (CONFIG_STORAGE & STORAGE_ATA) 695 + logf("ata spinup: %d", spin); 696 + spinup_time = spin; 697 + #endif 578 698 579 - if (fnq_rd_pos != fnq_wr_pos) 580 - return true; 699 + unsigned long rate = get_encbuf_datarate(); 700 + logf("byterate: %lu", rate * ENC_HDR_SIZE); 701 + encbuf_datarate = rate; 702 + 703 + /* Try to start writing with FLUSH_SECONDS remaining after disk spinup */ 704 + high_watermark = (uint64_t)rate*(FLUSH_SECONDS*HZ + spin) / HZ; 705 + 706 + if (high_watermark > enc_buflen) 707 + high_watermark = enc_buflen; 581 708 582 - /* queue full */ 583 - fnq_rd_pos = FNQ_NEXT(fnq_rd_pos); 584 - return true; 585 - } /* pcmrec_fnq_add_filename */ 709 + high_watermark = enc_buflen - high_watermark; 586 710 587 - /* replace the last filename added */ 588 - static bool pcmrec_fnq_replace_tail(const char *filename) 589 - { 590 - int pos; 711 + logf("high wm: %lu", (unsigned long)high_watermark); 591 712 592 - if (pcmrec_fnq_is_empty()) 593 - return false; 713 + #ifdef HAVE_PRIORITY_SCHEDULING 714 + /* Boost thread priority if enough ground is lost since flushing started 715 + or is taking an unreasonably long time */ 716 + flood_watermark = rate*PANIC_SECONDS; 594 717 595 - pos = FNQ_PREV(fnq_wr_pos); 718 + if (flood_watermark > enc_buflen) 719 + flood_watermark = enc_buflen; 596 720 597 - strlcpy(fn_queue + pos, filename, MAX_PATH); 721 + flood_watermark = enc_buflen - flood_watermark; 598 722 599 - return true; 600 - } /* pcmrec_fnq_replace_tail */ 723 + logf("flood wm: %lu", (unsigned long)flood_watermark); 724 + #endif /* HAVE_PRIORITY_SCHEDULING */ 725 + } 601 726 602 - /* pulls the next filename from the queue */ 603 - static bool pcmrec_fnq_get_filename(char *filename) 727 + /* Tell encoder the stream parameters and get information back */ 728 + static bool configure_encoder_stream(void) 604 729 { 605 - if (pcmrec_fnq_is_empty()) 730 + struct enc_inputs inputs; 731 + inputs.sample_rate = sample_rate; 732 + inputs.num_channels = num_channels; 733 + inputs.config = &enc_config; 734 + 735 + /* encoder can change these - init with defaults */ 736 + inputs.enc_sample_rate = sample_rate; 737 + 738 + if (enc_cb(ENC_CB_INPUTS, &inputs) < 0) 739 + { 740 + raise_error_status(PCMREC_E_ENC_SETUP); 606 741 return false; 742 + } 607 743 608 - if (filename) 609 - strlcpy(filename, fn_queue + fnq_rd_pos, MAX_PATH); 744 + enc_sample_rate = inputs.enc_sample_rate; 745 + 746 + if (enc_sample_rate != sample_rate) 747 + { 748 + /* Codec doesn't want to/can't use the setting and has chosen a 749 + different sample rate */ 750 + raise_warning_status(PCMREC_W_SAMPR_MISMATCH); 751 + logf("enc sampr:%lu", enc_sample_rate); 752 + } 753 + else 754 + { 755 + clear_warning_status(PCMREC_W_SAMPR_MISMATCH); 756 + } 610 757 611 - fnq_rd_pos = FNQ_NEXT(fnq_rd_pos); 758 + refresh_watermarks(); 612 759 return true; 613 - } /* pcmrec_fnq_get_filename */ 760 + } 614 761 615 - /* close the file number pointed to by fd_p */ 616 - static void pcmrec_close_file(int *fd_p) 762 + #ifdef HAVE_SPDIF_IN 763 + /* Return the S/PDIF sample rate closest to a value in the master list */ 764 + static unsigned long get_spdif_samplerate(void) 617 765 { 618 - if (*fd_p < 0) 619 - return; /* preserve error */ 766 + unsigned long sr = spdif_measure_frequency(); 767 + int index = round_value_to_list32(sr, audio_master_sampr_list, 768 + SAMPR_NUM_FREQ, false); 769 + return audio_master_sampr_list[index]; 770 + } 620 771 621 - if (close(*fd_p) != 0) 622 - pcmrec_raise_error_status(PCMREC_E_IO); 772 + /* Check the S/PDIF rate and compare to current setting. Apply the new 773 + * rate if it changed. */ 774 + static void check_spdif_samplerate(void) 775 + { 776 + unsigned long sampr = get_spdif_samplerate(); 623 777 624 - *fd_p = -1; 625 - } /* pcmrec_close_file */ 778 + if (sampr == sample_rate) 779 + return; 780 + 781 + codec_stop(); 782 + pcm_stop_recording(); 783 + reset_fifos(true); 784 + reset_rec_stats(); 785 + update_samplerate_config(sampr); 786 + pcm_apply_settings(); 626 787 627 - /** Data Flushing **/ 788 + if (!configure_encoder_stream() || rec_errors) 789 + return; 628 790 629 - /** 630 - * called after callback to update sizes if codec changed the amount of data 631 - * a chunk represents 632 - */ 633 - static inline void pcmrec_update_sizes_inl(size_t prev_enc_size, 634 - unsigned long prev_num_pcm) 635 - { 636 - if (rec_fdata.new_enc_size != prev_enc_size) 637 - { 638 - ssize_t size_diff = rec_fdata.new_enc_size - prev_enc_size; 639 - num_rec_bytes += size_diff; 640 - #if 0 641 - accum_rec_bytes += size_diff; 642 - #endif 643 - } 791 + pcm_start_recording(); 644 792 645 - if (rec_fdata.new_num_pcm != prev_num_pcm) 793 + if (record_status == RECORD_PRERECORDING) 646 794 { 647 - unsigned long pcm_diff = rec_fdata.new_num_pcm - prev_num_pcm; 648 - num_rec_samples += pcm_diff; 649 - #if 0 650 - accum_pcm_samples += pcm_diff; 651 - #endif 795 + codec_go(); 796 + pcm_pause = false; 652 797 } 653 - } /* pcmrec_update_sizes_inl */ 798 + } 799 + #endif /* HAVE_SPDIF_IN */ 654 800 655 - /* don't need to inline every instance */ 656 - static void pcmrec_update_sizes(size_t prev_enc_size, 657 - unsigned long prev_num_pcm) 801 + /* Discard the stream buffer contents */ 802 + static inline void stream_discard_buf(void) 658 803 { 659 - pcmrec_update_sizes_inl(prev_enc_size, prev_num_pcm); 660 - } /* pcmrec_update_sizes */ 804 + stream_buf_used = 0; 805 + } 661 806 662 - static void pcmrec_start_file(void) 807 + /* Flush stream buffer to disk */ 808 + static bool stream_flush_buf(void) 663 809 { 664 - size_t enc_size = rec_fdata.new_enc_size; 665 - unsigned long num_pcm = rec_fdata.new_num_pcm; 666 - int curr_rec_file = rec_fdata.rec_file; 667 - char filename[MAX_PATH]; 810 + if (stream_buf_used == 0) 811 + return true; 668 812 669 - /* must always pull the filename that matches with this queue */ 670 - if (!pcmrec_fnq_get_filename(filename)) 813 + ssize_t rc = write(rec_fd, stream_buffer, stream_buf_used); 814 + 815 + if (LIKELY(rc == stream_buf_used)) 671 816 { 672 - logf("start file: fnq empty"); 673 - *filename = '\0'; 674 - pcmrec_raise_error_status(PCMREC_E_FNQ_DESYNC); 817 + stream_discard_buf(); 818 + return true; 675 819 } 676 - else if (errors != 0) 820 + 821 + if (rc > 0) 677 822 { 678 - logf("start file: error already"); 823 + /* Some was written; keep in sync */ 824 + stream_buf_used -= rc; 825 + memmove(stream_buffer, stream_buffer + rc, stream_buf_used); 679 826 } 680 - else if (curr_rec_file >= 0) 681 - { 682 - /* Any previous file should have been closed */ 683 - logf("start file: file already open"); 684 - pcmrec_raise_error_status(PCMREC_E_FNQ_DESYNC); 685 - } 827 + 828 + return false; 829 + } 830 + 831 + /* Close the output file */ 832 + static void close_rec_file(void) 833 + { 834 + if (rec_fd < 0) 835 + return; 686 836 687 - if (errors != 0) 688 - rec_fdata.chunk->flags |= CHUNKF_ERROR; 837 + bool ok = stream_flush_buf(); 838 + 839 + if (close(rec_fd) != 0 || !ok) 840 + raise_error_status(PCMREC_E_IO); 689 841 690 - /* encoder can set error flag here and should increase 691 - enc_new_size and pcm_new_size to reflect additional 692 - data written if any */ 693 - rec_fdata.filename = filename; 694 - enc_events_callback(ENC_START_FILE, &rec_fdata); 842 + rec_fd = -1; 843 + } 695 844 696 - if (errors == 0 && (rec_fdata.chunk->flags & CHUNKF_ERROR)) 845 + /* Creates or opens the current path */ 846 + static bool open_rec_file(bool create) 847 + { 848 + if (rec_fd >= 0) 697 849 { 698 - logf("start file: enc error"); 699 - pcmrec_raise_error_status(PCMREC_E_ENCODER); 850 + /* Any previous file should have been closed */ 851 + logf("open file: file already open"); 852 + close_rec_file(); 700 853 } 701 854 702 - if (errors != 0) 703 - { 704 - pcmrec_close_file(&curr_rec_file); 705 - /* Write no more to this file */ 706 - rec_fdata.chunk->flags |= CHUNKF_END_FILE; 707 - } 708 - else 855 + stream_discard_buf(); 856 + int oflags = create ? O_CREAT|O_TRUNC : 0; 857 + rec_fd = open(fname_buf->path, O_RDWR|oflags, 0666); 858 + 859 + if (rec_fd < 0) 709 860 { 710 - pcmrec_update_sizes(enc_size, num_pcm); 861 + raise_error_status(PCMREC_E_IO); 862 + return false; 711 863 } 712 864 713 - rec_fdata.chunk->flags &= ~CHUNKF_START_FILE; 714 - } /* pcmrec_start_file */ 865 + return true; 866 + } 715 867 716 - static inline void pcmrec_write_chunk(void) 868 + /* Copy with mono conversion - output 1/2 size of input */ 869 + static void * ICODE_ATTR 870 + copy_buffer_mono_lr(void *dst, const void *src, size_t src_size) 717 871 { 718 - size_t enc_size = rec_fdata.new_enc_size; 719 - unsigned long num_pcm = rec_fdata.new_num_pcm; 872 + int16_t *d = dst; 873 + int16_t const *s = src; 874 + 875 + /* mono = (L + R) / 2 */ 876 + do 877 + *d++ = ((int32_t){ *s++ } + *s++ + 1) >> 1; 878 + while (src_size -= PCM_SAMP_SIZE); 720 879 721 - if (errors != 0) 722 - rec_fdata.chunk->flags |= CHUNKF_ERROR; 880 + return dst; 881 + } 723 882 724 - enc_events_callback(ENC_WRITE_CHUNK, &rec_fdata); 883 + /* Copy with mono conversion - output 1/2 size of input */ 884 + static void * ICODE_ATTR 885 + copy_buffer_mono_l(void *dst, const void *src, size_t src_size) 886 + { 887 + int16_t *d = dst; 888 + int16_t const *s = (int16_t *)src - 2; 725 889 726 - if ((long)rec_fdata.chunk->flags >= 0) 727 - { 728 - pcmrec_update_sizes_inl(enc_size, num_pcm); 729 - } 730 - else if (errors == 0) 731 - { 732 - logf("wr chk enc error %lu %lu", 733 - rec_fdata.chunk->enc_size, rec_fdata.chunk->num_pcm); 734 - pcmrec_raise_error_status(PCMREC_E_ENCODER); 735 - } 736 - } /* pcmrec_write_chunk */ 890 + /* mono = L */ 891 + do 892 + *d++ = *(s += 2); 893 + while (src_size -= PCM_SAMP_SIZE); 737 894 738 - static void pcmrec_end_file(void) 895 + return dst; 896 + } 897 + 898 + /* Copy with mono conversion - output 1/2 size of input */ 899 + static void * ICODE_ATTR 900 + copy_buffer_mono_r(void *dst, const void *src, size_t src_size) 739 901 { 740 - /* all data in output buffer for current file will have been 741 - written and encoder can now do any nescessary steps to 742 - finalize the written file */ 743 - size_t enc_size = rec_fdata.new_enc_size; 744 - unsigned long num_pcm = rec_fdata.new_num_pcm; 902 + int16_t *d = dst; 903 + int16_t const *s = (int16_t *)src - 1; 745 904 746 - enc_events_callback(ENC_END_FILE, &rec_fdata); 905 + /* mono = R */ 906 + do 907 + *d++ = *(s += 2); 908 + while (src_size -= PCM_SAMP_SIZE); 747 909 748 - if (errors == 0) 749 - { 750 - if (rec_fdata.chunk->flags & CHUNKF_ERROR) 751 - { 752 - logf("end file: enc error"); 753 - pcmrec_raise_error_status(PCMREC_E_ENCODER); 754 - } 755 - else 756 - { 757 - pcmrec_update_sizes(enc_size, num_pcm); 758 - } 759 - } 910 + return dst; 911 + } 760 912 761 - /* Force file close if error */ 762 - if (errors != 0) 763 - pcmrec_close_file(&rec_fdata.rec_file); 764 913 765 - rec_fdata.chunk->flags &= ~CHUNKF_END_FILE; 766 - } /* pcmrec_end_file */ 914 + /** pcm_rec_* group **/ 767 915 768 - /** 769 - * Update buffer watermarks with spinup time compensation 770 - * 771 - * All this assumes reasonable data rates, chunk sizes and sufficient 772 - * memory for the most part. Some dumb checks are included but perhaps 773 - * are pointless since this all will break down at extreme limits that 774 - * are currently not applicable to any supported device. 775 - */ 776 - static void pcmrec_refresh_watermarks(void) 916 + /* Clear all errors and warnings */ 917 + void pcm_rec_error_clear(void) 777 918 { 778 - logf("ata spinup: %d", storage_spinup_time()); 919 + clear_error_status(PCMREC_E_ALL); 920 + clear_warning_status(PCMREC_W_ALL); 921 + } 779 922 780 - /* set the low mark for when flushing stops if automatic */ 781 - /* don't change the order in this expression, LOW_SECONDS can be an 782 - * integer fraction of 4 */ 783 - low_watermark = (sample_rate*4*LOW_SECONDS + (enc_chunk_size-1)) 784 - / enc_chunk_size; 785 - logf("low wmk: %d", low_watermark); 923 + /* Check mode, errors and warnings */ 924 + unsigned int pcm_rec_status(void) 925 + { 926 + unsigned int ret = record_status; 786 927 787 - #ifdef HAVE_PRIORITY_SCHEDULING 788 - /* panic boost thread priority if 2 seconds of ground is lost - 789 - this allows encoder to boost with just under a second of 790 - pcm data (if not yet full enough to boost itself) 791 - and not falsely trip the alarm. */ 792 - /* don't change the order in this expression, PANIC_SECONDS can be an 793 - * integer fraction of 4 */ 794 - flood_watermark = enc_num_chunks - 795 - (sample_rate*4*PANIC_SECONDS + (enc_chunk_size-1)) 796 - / enc_chunk_size; 928 + if (errors) 929 + ret |= AUDIO_STATUS_ERROR; 930 + 931 + if (warnings) 932 + ret |= AUDIO_STATUS_WARNING; 933 + 934 + return ret; 935 + } 797 936 798 - if (flood_watermark < low_watermark) 799 - { 800 - logf("warning: panic < low"); 801 - flood_watermark = low_watermark; 802 - } 937 + /* Return warnings that have occured since recording started */ 938 + uint32_t pcm_rec_get_warnings(void) 939 + { 940 + return warnings; 941 + } 803 942 804 - logf("flood at: %d", flood_watermark); 943 + #ifdef HAVE_SPDIF_IN 944 + /* Return the currently-configured sample rate */ 945 + unsigned long pcm_rec_sample_rate(void) 946 + { 947 + return sample_rate; 948 + } 805 949 #endif 806 - spinup_time = last_storage_spinup_time = storage_spinup_time(); 807 - #if (CONFIG_STORAGE & STORAGE_ATA) 808 - /* write at 8s + st remaining in enc_buffer - range 12s to 809 - 20s total - default to 3.5s spinup. */ 810 - if (spinup_time == 0) 811 - spinup_time = 35*HZ/10; /* default - cozy */ 812 - else if (spinup_time < 2*HZ) 813 - spinup_time = 2*HZ; /* ludicrous - ramdisk? */ 814 - else if (spinup_time > 10*HZ) 815 - spinup_time = 10*HZ; /* do you have a functioning HD? */ 816 - #endif 950 + 951 + 952 + /** audio_* group **/ 953 + 954 + /* Initializes recording - call before calling any other recording function */ 955 + void audio_init_recording(void) 956 + { 957 + LOGFQUEUE("audio >| pcmrec Q_AUDIO_INIT_RECORDING"); 958 + audio_queue_send(Q_AUDIO_INIT_RECORDING, 1); 959 + } 960 + 961 + /* Closes recording - call audio_stop_recording first or risk data loss */ 962 + void audio_close_recording(void) 963 + { 964 + LOGFQUEUE("audio >| pcmrec Q_AUDIO_CLOSE_RECORDING"); 965 + audio_queue_send(Q_AUDIO_CLOSE_RECORDING, 0); 966 + } 967 + 968 + /* Sets recording parameters */ 969 + void audio_set_recording_options(struct audio_recording_options *options) 970 + { 971 + LOGFQUEUE("audio >| pcmrec Q_AUDIO_RECORDING_OPTIONS"); 972 + audio_queue_send(Q_AUDIO_RECORDING_OPTIONS, (intptr_t)options); 973 + } 974 + 975 + /* Start recording if not recording or else split */ 976 + void audio_record(const char *filename) 977 + { 978 + LOGFQUEUE("audio >| pcmrec Q_AUDIO_RECORD: %s", filename); 979 + audio_queue_send(Q_AUDIO_RECORD, (intptr_t)filename); 980 + } 981 + 982 + /* audio_record alias for API compatibility with HW codec */ 983 + void audio_new_file(const char *filename) 984 + __attribute__((alias("audio_record"))); 817 985 818 - /* try to start writing with 10s remaining after disk spinup */ 819 - high_watermark = enc_num_chunks - 820 - ((FLUSH_SECONDS*HZ + spinup_time)*4*sample_rate + 821 - (enc_chunk_size-1)*HZ) / (enc_chunk_size*HZ); 986 + /* Stop current recording if recording */ 987 + void audio_stop_recording(void) 988 + { 989 + LOGFQUEUE("audio > pcmrec Q_AUDIO_RECORD_STOP"); 990 + audio_queue_post(Q_AUDIO_RECORD_STOP, 0); 991 + } 822 992 823 - if (high_watermark < low_watermark) 824 - { 825 - logf("warning: low 'write at' (%d)", high_watermark); 826 - high_watermark = low_watermark; 827 - low_watermark /= 2; 828 - } 993 + /* Pause current recording */ 994 + void audio_pause_recording(void) 995 + { 996 + LOGFQUEUE("audio > pcmrec Q_AUDIO_RECORD_PAUSE"); 997 + audio_queue_post(Q_AUDIO_RECORD_PAUSE, 0); 998 + } 829 999 830 - logf("write at: %d", high_watermark); 831 - } /* pcmrec_refresh_watermarks */ 1000 + /* Resume current recording if paused */ 1001 + void audio_resume_recording(void) 1002 + { 1003 + LOGFQUEUE("audio > pcmrec Q_AUDIO_RECORD_RESUME"); 1004 + audio_queue_post(Q_AUDIO_RECORD_RESUME, 0); 1005 + } 832 1006 833 - /** 834 - * Process the chunks 835 - * 836 - * This function is called when queue_get_w_tmo times out. 837 - * 838 - * Set flush_num to the number of files to flush to disk or to 839 - * a PCMREC_FLUSH_* constant. 840 - */ 841 - static void pcmrec_flush(unsigned flush_num) 1007 + /* Set the input source gain. For mono sources, only left gain is used */ 1008 + void audio_set_recording_gain(int left, int right, int type) 842 1009 { 843 - #ifdef HAVE_PRIORITY_SCHEDULING 844 - static unsigned long last_flush_tick; /* tick when function returned */ 845 - unsigned long start_tick; /* When flush started */ 846 - unsigned long prio_tick; /* Timeout for auto boost */ 847 - int prio_pcmrec; /* Current thread priority for pcmrec */ 848 - int prio_codec; /* Current thread priority for codec */ 1010 + #if 0 1011 + logf("pcmrec: t=%d l=%d r=%d", type, left, right); 849 1012 #endif 850 - int num_ready; /* Number of chunks ready at start */ 851 - unsigned remaining; /* Number of file starts remaining */ 852 - unsigned chunks_flushed; /* Chunks flushed (for mini flush only) */ 853 - bool interruptable; /* Flush can be interupted */ 1013 + audiohw_set_recvol(left, right, type); 1014 + } 1015 + 1016 + 1017 + /** Information about current state **/ 1018 + 1019 + /* Return sample clock in HZ */ 1020 + static unsigned long get_samples_time(void) 1021 + { 1022 + if (enc_sample_rate == 0) 1023 + return 0; 1024 + 1025 + return (unsigned long)(HZ*num_rec_samples / enc_sample_rate); 1026 + } 854 1027 855 - num_ready = enc_wr_index - enc_rd_index; 856 - if (num_ready < 0) 857 - num_ready += enc_num_chunks; 1028 + /* Return current prerecorded time in ticks (playback equivalent time) */ 1029 + unsigned long audio_prerecorded_time(void) 1030 + { 1031 + if (record_status != RECORD_PRERECORDING) 1032 + return 0; 858 1033 859 - /* save interruptable flag and remove it to get the actual count */ 860 - interruptable = (flush_num & PCMREC_FLUSH_INTERRUPTABLE) != 0; 861 - flush_num &= ~PCMREC_FLUSH_INTERRUPTABLE; 1034 + unsigned long t = get_samples_time(); 1035 + return MIN(t, pre_record_seconds*HZ); 1036 + } 862 1037 863 - if (flush_num == 0) 1038 + /* Return current recorded time in ticks (playback equivalent time) */ 1039 + unsigned long audio_recorded_time(void) 1040 + { 1041 + if (record_state == REC_STATE_IDLE) 1042 + return 0; 1043 + 1044 + return get_samples_time(); 1045 + } 1046 + 1047 + /* Return number of bytes encoded to output */ 1048 + unsigned long audio_num_recorded_bytes(void) 1049 + { 1050 + if (record_state == REC_STATE_IDLE) 1051 + return 0; 1052 + 1053 + return num_rec_bytes; 1054 + } 1055 + 1056 + 1057 + /** Data Flushing **/ 1058 + 1059 + /* Stream start chunk with path was encountered */ 1060 + static void flush_stream_start(struct enc_chunk_file *file) 1061 + { 1062 + /* Save filename; don't open file here which avoids creating files 1063 + with no audio content. Splitting while paused can create those 1064 + in large numbers. */ 1065 + fname_buf->hdr = file->hdr; 1066 + /* Correct size if this was wrap-padded */ 1067 + fname_buf->hdr.size = CHUNK_FILE_COUNT( 1068 + strlcpy(fname_buf->path, file->path, MAX_PATH) + 1); 1069 + } 1070 + 1071 + /* Data chunk was encountered */ 1072 + static bool flush_stream_data(struct enc_chunk_data *data) 1073 + { 1074 + if (fname_buf->hdr.zero) 864 1075 { 865 - if (!is_recording) 866 - return; 1076 + /* First data chunk; create the file */ 1077 + if (open_rec_file(true)) 1078 + { 1079 + /* Inherit some flags from initial data chunk */ 1080 + fname_buf->hdr.err = data->hdr.err; 1081 + fname_buf->hdr.pre = data->hdr.pre; 1082 + fname_buf->hdr.aux0 = data->hdr.aux0; 1083 + 1084 + if (enc_cb(ENC_CB_STREAM, fname_buf) < 0) 1085 + raise_error_status(PCMREC_E_ENCODER_STREAM); 1086 + } 867 1087 868 - if (storage_spinup_time() != last_storage_spinup_time) 869 - pcmrec_refresh_watermarks(); 1088 + fname_buf->hdr.zero = 0; 870 1089 871 - /* enough available? no? then leave */ 872 - if (num_ready < high_watermark) 873 - return; 874 - } /* endif (flush_num == 0) */ 1090 + if (rec_errors) 1091 + return false; 1092 + } 875 1093 876 - #ifdef HAVE_PRIORITY_SCHEDULING 877 - start_tick = current_tick; 878 - prio_tick = start_tick + PRIO_SECONDS*HZ + spinup_time; 1094 + if (rec_fd < 0) 1095 + return true; /* Just keep discarding */ 879 1096 880 - if (flush_num == 0 && TIME_BEFORE(current_tick, last_flush_tick + HZ/2)) 1097 + if (enc_cb(ENC_CB_STREAM, data) < 0) 881 1098 { 882 - /* if we're getting called too much and this isn't forced, 883 - boost stat by expiring timeout in advance */ 884 - logf("too frequent flush"); 885 - prio_tick = current_tick - 1; 1099 + raise_error_status(PCMREC_E_ENCODER_STREAM); 1100 + return false; 886 1101 } 887 1102 888 - prio_pcmrec = -1; 889 - prio_codec = -1; /* GCC is too stoopid to figure out it doesn't 890 - need init */ 891 - #endif 1103 + return true; 1104 + } 892 1105 893 - logf("writing:%d(%d):%s%s", num_ready, flush_num, 894 - interruptable ? "i" : "", 895 - flush_num == PCMREC_FLUSH_MINI ? "m" : ""); 1106 + /* Stream end chunk was encountered */ 1107 + static bool flush_stream_end(union enc_chunk_hdr *hdr) 1108 + { 1109 + if (rec_fd < 0) 1110 + return true; 896 1111 897 - cpu_boost(true); 1112 + if (enc_cb(ENC_CB_STREAM, hdr) < 0) 1113 + { 1114 + raise_error_status(PCMREC_E_ENCODER_STREAM); 1115 + return false; 1116 + } 898 1117 899 - remaining = flush_num; 900 - chunks_flushed = 0; 1118 + close_rec_file(); 1119 + return true; 1120 + } 901 1121 902 - while (num_ready > 0) 1122 + /* Discard remainder of stream in encoder buffer */ 1123 + static void discard_stream(void) 1124 + { 1125 + /* Discard everything up until the next non-data chunk */ 1126 + while (!encbuf_empty()) 903 1127 { 904 - /* check current number of encoder chunks */ 905 - int num = enc_wr_index - enc_rd_index; 906 - if (num < 0) 907 - num += enc_num_chunks; 1128 + size_t ridx; 1129 + union enc_chunk_hdr *hdr = encbuf_read_ptr_incr(enc_ridx, &ridx); 908 1130 909 - if (num <= low_watermark && 910 - (flush_num == PCMREC_FLUSH_IF_HIGH || num <= 0)) 1131 + if (hdr && hdr->type != CHUNK_T_DATA) 911 1132 { 912 - logf("low data: %d", num); 913 - break; /* data remaining is below threshold */ 1133 + if (hdr->type != CHUNK_T_STREAM_START) 1134 + enc_ridx = ridx; 1135 + break; 914 1136 } 915 1137 916 - if (interruptable && flush_interrupts > 0) 917 - { 918 - logf("int at: %d", num); 919 - break; /* interrupted */ 920 - } 1138 + enc_ridx = ridx; 1139 + } 1140 + 1141 + /* Try to finish header by closing and reopening the file. A seek or 1142 + other operation will likely fail because buffers will need to be 1143 + flushed (here and in file code). That will likely fail but a close 1144 + will just close the fd and discard everything. We reopen with what 1145 + actually made it to disk. Modifying existing file contents will 1146 + more than likely succeed even on a full disk. The result might not 1147 + be entirely correct as far as the headers' sizes and counts unless 1148 + the codec can correct that but the sample format information 1149 + should be. */ 1150 + if (rec_fd >= 0 && open_rec_file(false)) 1151 + { 1152 + /* Synthesize a special end chunk here */ 1153 + union enc_chunk_hdr end; 1154 + end.zero = 0; 1155 + end.err = 1; /* Codec should try to correct anything that's off */ 1156 + end.type = CHUNK_T_STREAM_END; 1157 + if (!flush_stream_end(&end)) 1158 + close_rec_file(); 1159 + } 1160 + } 921 1161 1162 + /* Flush a chunk to disk 1163 + * 1164 + * Transitions state from REC_STATE_MONITOR to REC_STATE_FLUSH when buffer 1165 + * is filling. 'margin' is fullness threshold that transitions to flush state. 1166 + * 1167 + * Call with REC_STATE_IDLE to indicate a forced flush which flushes buffer 1168 + * to less than 'margin'. 1169 + */ 1170 + static enum record_state flush_chunk(enum record_state state, size_t margin) 1171 + { 922 1172 #ifdef HAVE_PRIORITY_SCHEDULING 923 - if (prio_pcmrec == -1 && (num >= flood_watermark || 924 - TIME_AFTER(current_tick, prio_tick))) 925 - { 926 - /* losing ground or holding without progress - boost 927 - priority until finished */ 928 - logf("pcmrec: boost (%s)", 929 - num >= flood_watermark ? "num" : "time"); 930 - prio_pcmrec = thread_set_priority(thread_self(), 931 - thread_get_priority(thread_self()) - 4); 932 - prio_codec = codec_thread_set_priority( 933 - codec_thread_get_priority() - 4); 934 - } 1173 + static unsigned long prio_tick; /* Timeout for auto boost */ 935 1174 #endif 936 1175 937 - rec_fdata.chunk = GET_ENC_CHUNK(enc_rd_index); 938 - rec_fdata.new_enc_size = rec_fdata.chunk->enc_size; 939 - rec_fdata.new_num_pcm = rec_fdata.chunk->num_pcm; 1176 + size_t used = encbuf_used(); 940 1177 941 - if (rec_fdata.chunk->flags & CHUNKF_START_FILE) 942 - { 943 - pcmrec_start_file(); 944 - if (--remaining == 0) 945 - num_ready = 0; /* stop on next loop - must write this 946 - chunk if it has data */ 947 - } 1178 + switch (state) 1179 + { 1180 + case REC_STATE_MONITOR: 1181 + if (monitor_encbuf_datarate() || monitor_spinup_time()) 1182 + refresh_watermarks(); 948 1183 949 - pcmrec_write_chunk(); 1184 + if (used < margin) 1185 + return REC_STATE_MONITOR; 950 1186 951 - if (rec_fdata.chunk->flags & CHUNKF_END_FILE) 952 - pcmrec_end_file(); 1187 + state = REC_STATE_FLUSH; 1188 + trigger_cpu_boost(); 953 1189 954 - INC_ENC_INDEX(enc_rd_index); 1190 + #ifdef HAVE_PRIORITY_SCHEDULING 1191 + prio_tick = current_tick + PRIO_SECONDS*HZ; 1192 + #if (CONFIG_STORAGE & STORAGE_ATA) 1193 + prio_tick += spinup_time; 1194 + #endif 1195 + #endif /* HAVE_PRIORITY_SCHEDULING */ 955 1196 956 - if (errors != 0) 957 - { 958 - pcmrec_end_file(); 1197 + /* Fall-through */ 1198 + case REC_STATE_IDLE: /* As a hint for "forced" */ 1199 + if (used < margin) 959 1200 break; 960 - } 961 1201 962 - if (flush_num == PCMREC_FLUSH_MINI && 963 - ++chunks_flushed >= MINI_CHUNKS) 1202 + /* Fall-through */ 1203 + case REC_STATE_FLUSH: 1204 + #ifdef HAVE_PRIORITY_SCHEDULING 1205 + if (!prio_boosted && state != REC_STATE_IDLE && 1206 + (used >= flood_watermark || TIME_AFTER(current_tick, prio_tick))) 1207 + do_prio_boost(true); 1208 + #endif /* HAVE_PRIORITY_SCHEDULING */ 1209 + 1210 + while (used) 964 1211 { 965 - logf("mini flush break"); 1212 + union enc_chunk_hdr *hdr = encbuf_ptr(enc_ridx); 1213 + size_t count = 0; 1214 + 1215 + switch (hdr->type) 1216 + { 1217 + case CHUNK_T_DATA: 1218 + if (flush_stream_data(ENC_DATA_HDR(hdr))) 1219 + count = CHUNK_DATA_COUNT(hdr->size); 1220 + break; 1221 + 1222 + case CHUNK_T_STREAM_START: 1223 + /* Doesn't do stream writes */ 1224 + flush_stream_start(ENC_FILE_HDR(hdr)); 1225 + count = hdr->size; 1226 + break; 1227 + 1228 + case CHUNK_T_STREAM_END: 1229 + if (flush_stream_end(hdr)) 1230 + count = 1; 1231 + break; 1232 + 1233 + case CHUNK_T_WRAP: 1234 + enc_ridx = 0; 1235 + used = encbuf_used(); 1236 + continue; 1237 + } 1238 + 1239 + if (count) 1240 + enc_ridx = encbuf_add(enc_ridx, count); 1241 + else 1242 + discard_stream(); 1243 + 966 1244 break; 967 1245 } 968 - /* no yielding; the file apis called in the codecs do that 969 - sufficiently */ 970 - } /* end while */ 971 1246 972 - /* sync file */ 973 - if (rec_fdata.rec_file >= 0 && fsync(rec_fdata.rec_file) != 0) 974 - pcmrec_raise_error_status(PCMREC_E_IO); 1247 + if (!encbuf_empty()) 1248 + return state; 975 1249 976 - cpu_boost(false); 1250 + break; 1251 + } 977 1252 978 - #ifdef HAVE_PRIORITY_SCHEDULING 979 - if (prio_pcmrec != -1) 1253 + if (encbuf_empty()) 980 1254 { 981 - /* return to original priorities */ 982 - logf("pcmrec: unboost priority"); 983 - thread_set_priority(thread_self(), prio_pcmrec); 984 - codec_thread_set_priority(prio_codec); 1255 + do_prio_boost(false); 1256 + cancel_cpu_boost(); 985 1257 } 986 1258 987 - last_flush_tick = current_tick; /* save tick when we left */ 988 - #endif 1259 + return REC_STATE_MONITOR; 1260 + } 989 1261 990 - logf("done"); 991 - } /* pcmrec_flush */ 992 - 993 - /** 994 - * Marks a new stream in the buffer and gives the encoder a chance for special 995 - * handling of transition from one to the next. The encoder may change the 996 - * chunk that ends the old stream by requesting more chunks and similiarly for 997 - * the new but must always advance the position though the interface. It can 998 - * later reject any data it cares to when writing the file but should mark the 999 - * chunk so it can recognize this. ENC_WRITE_CHUNK event must be able to accept 1000 - * a NULL data pointer without error as well. 1001 - */ 1002 - static int pcmrec_get_chunk_index(struct enc_chunk_hdr *chunk) 1262 + /* Monitor buffer and finish stream, freeing-up space at the same time */ 1263 + static void finish_stream(bool stopping) 1003 1264 { 1004 - return ((char *)chunk - (char *)enc_buffer) / enc_chunk_size; 1005 - } /* pcmrec_get_chunk_index */ 1265 + size_t threshold = stopping ? 1 : enc_buflen - ENCBUF_MIN_SPLIT_MARGIN; 1266 + enum record_state state = REC_STATE_MONITOR; 1267 + size_t need = 1; 1006 1268 1007 - static struct enc_chunk_hdr * pcmrec_get_prev_chunk(int index) 1008 - { 1009 - DEC_ENC_INDEX(index); 1010 - return GET_ENC_CHUNK(index); 1011 - } /* pcmrec_get_prev_chunk */ 1269 + while (1) 1270 + { 1271 + switch (state) 1272 + { 1273 + case REC_STATE_IDLE: 1274 + state = flush_chunk(state, threshold); 1275 + continue; 1012 1276 1013 - static void pcmrec_new_stream(const char *filename, /* next file name */ 1014 - unsigned long flags, /* CHUNKF_* flags */ 1015 - int pre_index) /* index for prerecorded data */ 1016 - { 1017 - logf("pcmrec_new_stream"); 1018 - char path[MAX_PATH]; /* place to copy filename so sender can be released */ 1277 + default: 1278 + if (!need) 1279 + break; 1019 1280 1020 - struct enc_buffer_event_data data; 1021 - bool (*fnq_add_fn)(const char *) = NULL; /* function to use to add 1022 - new filename */ 1023 - struct enc_chunk_hdr *start = NULL; /* pointer to starting chunk of 1024 - stream */ 1025 - bool did_flush = false; /* did a flush occurr? */ 1281 + if (!stopping || pcm_buffer_empty) 1282 + { 1283 + need = codec_finish_stream(); 1026 1284 1027 - if (filename) 1028 - strlcpy(path, filename, MAX_PATH); 1029 - queue_reply(&audio_queue, 0); /* We have all we need */ 1285 + if (need) 1286 + { 1287 + need = 2*CHUNK_DATA_COUNT(need) - 1; 1030 1288 1031 - data.pre_chunk = NULL; 1032 - data.chunk = GET_ENC_CHUNK(enc_wr_index); 1289 + if (need >= enc_buflen) 1290 + { 1291 + need = 0; 1292 + codec_stop(); 1293 + threshold = 1; 1294 + } 1295 + else if (threshold > enc_buflen - need) 1296 + { 1297 + threshold = enc_buflen - need; 1298 + } 1299 + } 1300 + } 1033 1301 1034 - /* end chunk */ 1035 - if (flags & CHUNKF_END_FILE) 1036 - { 1037 - data.chunk->flags &= CHUNKF_START_FILE | CHUNKF_END_FILE; 1302 + if (!need || encbuf_used() >= threshold) 1303 + state = REC_STATE_IDLE; /* Start flush */ 1304 + else 1305 + sleep(HZ/10); /* Don't flood with pings */ 1038 1306 1039 - if (data.chunk->flags & CHUNKF_START_FILE) 1040 - { 1041 - /* cannot start and end on same unprocessed chunk */ 1042 - logf("file end on start"); 1043 - flags &= ~CHUNKF_END_FILE; 1044 - } 1045 - else if (enc_rd_index == enc_wr_index) 1046 - { 1047 - /* all data flushed but file not ended - chunk will be left 1048 - empty */ 1049 - logf("end on dead end"); 1050 - data.chunk->flags = 0; 1051 - data.chunk->enc_size = 0; 1052 - data.chunk->num_pcm = 0; 1053 - data.chunk->enc_data = NULL; 1054 - INC_ENC_INDEX(enc_wr_index); 1055 - data.chunk = GET_ENC_CHUNK(enc_wr_index); 1307 + continue; 1056 1308 } 1057 - else 1058 - { 1059 - struct enc_chunk_hdr *last = pcmrec_get_prev_chunk(enc_wr_index); 1060 1309 1061 - if (last->flags & CHUNKF_END_FILE) 1062 - { 1063 - /* end already processed and marked - can't end twice */ 1064 - logf("file end again"); 1065 - flags &= ~CHUNKF_END_FILE; 1066 - } 1067 - } 1310 + break; 1068 1311 } 1312 + } 1069 1313 1070 - /* start chunk */ 1071 - if (flags & CHUNKF_START_FILE) 1314 + /* Start a new stream, transistion to a new one or end the current one */ 1315 + static void mark_stream(const char *path, enum mark_stream_action action) 1316 + { 1317 + if (action & MARK_STREAM_END) 1072 1318 { 1073 - bool pre = flags & CHUNKF_PRERECORD; 1319 + size_t widx; 1320 + union enc_chunk_hdr *hdr = encbuf_get_write_ptr(enc_widx, 1, &widx); 1321 + hdr->type = CHUNK_T_STREAM_END; 1322 + encbuf_widx_advance(widx, 1); 1323 + } 1324 + 1325 + if (action & MARK_STREAM_START) 1326 + { 1327 + size_t count = CHUNK_FILE_COUNT_PATH(path); 1328 + struct enc_chunk_file *file; 1329 + size_t widx; 1074 1330 1075 - if (pre) 1331 + if (action & MARK_STREAM_PRE) 1076 1332 { 1077 - logf("stream prerecord start"); 1078 - start = data.pre_chunk = GET_ENC_CHUNK(pre_index); 1079 - start->flags &= CHUNKF_START_FILE | CHUNKF_PRERECORD; 1080 - } 1081 - else 1082 - { 1083 - logf("stream normal start"); 1084 - start = data.chunk; 1085 - start->flags &= CHUNKF_START_FILE; 1086 - } 1333 + /* Prerecord: START marker goes first or before existing data */ 1334 + if (enc_ridx < count) 1335 + { 1336 + /* Adjust to occupy end of buffer and pad accordingly */ 1337 + count += enc_ridx; 1338 + enc_ridx += enc_buflen; 1339 + } 1340 + 1341 + enc_ridx -= count; 1087 1342 1088 - /* if encoder hasn't yet processed the last start - abort the start 1089 - of the previous file queued or else it will be empty and invalid */ 1090 - if (start->flags & CHUNKF_START_FILE) 1091 - { 1092 - logf("replacing fnq tail: %s", filename); 1093 - fnq_add_fn = pcmrec_fnq_replace_tail; 1343 + /* Won't adjust p since enc_ridx is already set as non-wrapping */ 1344 + file = encbuf_get_write_ptr(enc_ridx, count, &widx); 1094 1345 } 1095 1346 else 1096 1347 { 1097 - logf("adding filename: %s", filename); 1098 - fnq_add_fn = pcmrec_fnq_add_filename; 1348 + /* The usual: START marker goes first or after existing data */ 1349 + file = encbuf_get_write_ptr(enc_widx, count, &widx); 1350 + encbuf_widx_advance(widx, count); 1099 1351 } 1100 - } 1101 1352 1102 - data.flags = flags; 1103 - pcmrec_context = true; /* switch encoder context */ 1104 - enc_events_callback(ENC_REC_NEW_STREAM, &data); 1105 - pcmrec_context = false; /* switch back */ 1106 - 1107 - if (flags & CHUNKF_END_FILE) 1108 - { 1109 - int i = pcmrec_get_chunk_index(data.chunk); 1110 - pcmrec_get_prev_chunk(i)->flags |= CHUNKF_END_FILE; 1353 + file->hdr.type = CHUNK_T_STREAM_START; 1354 + file->hdr.size = count; 1355 + strlcpy(file->path, path, MAX_PATH); 1111 1356 } 1357 + } 1112 1358 1113 - if (start) 1114 - { 1115 - if (!(flags & CHUNKF_PRERECORD)) 1116 - { 1117 - /* get stats on data added to start - sort of a prerecord 1118 - operation */ 1119 - int i = pcmrec_get_chunk_index(data.chunk); 1120 - struct enc_chunk_hdr *chunk = data.chunk; 1359 + /* Tally-up and keep the required amount of prerecord data. 1360 + * Updates record stats accordingly. */ 1361 + static void tally_prerecord_data(void) 1362 + { 1363 + unsigned long count = 0; 1364 + size_t bytes = 0; 1365 + unsigned long samples = 0; 1121 1366 1122 - logf("start data: %d %d", i, enc_wr_index); 1367 + /* Find out how much is there */ 1368 + for (size_t idx = enc_ridx; idx != enc_widx;) 1369 + { 1370 + struct enc_chunk_data *data = encbuf_read_ptr_incr(idx, &idx); 1123 1371 1124 - num_rec_bytes = 0; 1125 - num_rec_samples = 0; 1372 + if (!data) 1373 + continue; 1126 1374 1127 - while (i != enc_wr_index) 1128 - { 1129 - num_rec_bytes += chunk->enc_size; 1130 - num_rec_samples += chunk->num_pcm; 1131 - INC_ENC_INDEX(i); 1132 - chunk = GET_ENC_CHUNK(i); 1133 - } 1375 + count += CHUNK_DATA_COUNT(data->hdr.size); 1376 + bytes += data->hdr.size; 1377 + samples += data->pcm_count; 1378 + } 1134 1379 1135 - start->flags &= ~CHUNKF_START_FILE; 1136 - start = data.chunk; 1137 - } 1380 + /* Have too much? Discard oldest data. */ 1381 + unsigned long pre_samples = enc_sample_rate*pre_record_seconds; 1138 1382 1139 - start->flags |= CHUNKF_START_FILE; 1383 + while (samples > pre_samples) 1384 + { 1385 + struct enc_chunk_data *data = 1386 + encbuf_read_ptr_incr(enc_ridx, &enc_ridx); 1140 1387 1141 - /* flush all pending files out if full and adding */ 1142 - if (fnq_add_fn == pcmrec_fnq_add_filename && pcmrec_fnq_is_full()) 1143 - { 1144 - logf("fnq full"); 1145 - pcmrec_flush(PCMREC_FLUSH_ALL); 1146 - did_flush = true; 1147 - } 1388 + if (!data) 1389 + continue; 1148 1390 1149 - fnq_add_fn(path); 1391 + count -= CHUNK_DATA_COUNT(data->hdr.size); 1392 + bytes -= data->hdr.size; 1393 + samples -= data->pcm_count; 1150 1394 } 1151 1395 1152 - /* Make sure to complete any interrupted high watermark */ 1153 - if (!did_flush) 1154 - pcmrec_flush(PCMREC_FLUSH_IF_HIGH); 1155 - } /* pcmrec_new_stream */ 1396 + encbuf_rec_count = count; 1397 + num_rec_bytes = bytes; 1398 + num_rec_samples = samples; 1399 + } 1156 1400 1157 1401 1158 - /** event handlers for pcmrec thread */ 1402 + /** Event handlers for recording thread **/ 1159 1403 1160 - /* PCMREC_INIT */ 1161 - static void pcmrec_init(void) 1404 + /* Q_AUDIO_INIT_RECORDING */ 1405 + static void on_init_recording(void) 1162 1406 { 1163 1407 send_event(RECORDING_EVENT_START, NULL); 1164 - pcmrec_close_file(&rec_fdata.rec_file); 1165 - 1166 - pcmrec_init_state(); 1167 - 1168 - unsigned char *buffer = audio_get_buffer(true, &rec_buffer_size); 1169 - 1170 - /* Line align pcm_buffer 2^5=32 bytes */ 1171 - pcm_buffer = (unsigned char *)ALIGN_UP_P2((uintptr_t)buffer, 5); 1172 - enc_buffer = pcm_buffer + ALIGN_UP_P2(PCM_NUM_CHUNKS*PCM_CHUNK_SIZE + 1173 - PCM_MAX_FEED_SIZE, 2); 1174 - /* Adjust available buffer for possible align advancement */ 1175 - rec_buffer_size -= pcm_buffer - buffer; 1176 - 1408 + rec_buffer = audio_get_buffer(true, &rec_buffer_size); 1409 + init_rec_buffers(); 1410 + init_state(); 1177 1411 pcm_init_recording(); 1178 - } /* pcmrec_init */ 1412 + } 1179 1413 1180 - /* PCMREC_CLOSE */ 1181 - static void pcmrec_close(void) 1414 + /* Q_AUDIO_CLOSE_RECORDING */ 1415 + static void on_close_recording(void) 1182 1416 { 1183 - dma_lock = true; 1184 - pre_record_ticks = 0; /* Can't be prerecording any more */ 1185 - warnings = 0; 1417 + /* Simply shut down the recording system. Whatever wasn't saved is 1418 + lost. */ 1186 1419 codec_unload(); 1187 1420 pcm_close_recording(); 1188 - reset_hardware(); 1421 + close_rec_file(); 1422 + init_state(); 1423 + 1424 + rec_errors = 0; 1425 + pcm_rec_error_clear(); 1426 + 1427 + /* Reset PCM to defaults */ 1428 + pcm_set_frequency(HW_SAMPR_RESET | SAMPR_TYPE_REC); 1429 + audio_set_output_source(AUDIO_SRC_PLAYBACK); 1430 + pcm_apply_settings(); 1431 + 1189 1432 send_event(RECORDING_EVENT_STOP, NULL); 1190 - } /* pcmrec_close */ 1433 + } 1191 1434 1192 - /* PCMREC_OPTIONS */ 1193 - static void pcmrec_set_recording_options( 1194 - struct audio_recording_options *options) 1435 + /* Q_AUDIO_RECORDING_OPTIONS */ 1436 + static void on_recording_options(struct audio_recording_options *options) 1195 1437 { 1196 - /* stop everything */ 1197 - dma_lock = true; 1198 - codec_unload(); 1438 + if (!options) 1439 + { 1440 + logf("options: option NULL!"); 1441 + return; 1442 + } 1443 + 1444 + if (record_state != REC_STATE_IDLE) 1445 + { 1446 + /* This would ruin things */ 1447 + logf("options: still recording!"); 1448 + return; 1449 + } 1450 + 1451 + /* Stop everything else that might be running */ 1199 1452 pcm_stop_recording(); 1200 - pcmrec_init_state(); 1453 + 1454 + int afmt = rec_format_afmt[options->enc_config.rec_format]; 1455 + bool enc_load = true; 1456 + 1457 + if (codec_loaded() != AFMT_UNKNOWN) 1458 + { 1459 + if (get_audio_base_codec_type(enc_config.afmt) != 1460 + get_audio_base_codec_type(afmt)) 1461 + { 1462 + /* New format, new encoder; unload this one */ 1463 + codec_unload(); 1464 + } 1465 + else 1466 + { 1467 + /* Keep current encoder */ 1468 + codec_stop(); 1469 + enc_load = false; 1470 + } 1471 + } 1472 + 1473 + init_state(); 1201 1474 1202 - rec_frequency = options->rec_frequency; 1475 + /* Read recording options, remember the ones used elsewhere */ 1476 + unsigned frequency = options->rec_frequency; 1203 1477 rec_source = options->rec_source; 1204 1478 num_channels = options->rec_channels == 1 ? 1 : 2; 1205 - rec_mono_mode = options->rec_mono_mode; 1206 - pre_record_ticks = options->rec_prerecord_time * HZ; 1479 + unsigned mono_mode = options->rec_mono_mode; 1480 + pre_record_seconds = options->rec_prerecord_time; 1207 1481 enc_config = options->enc_config; 1208 - enc_config.afmt = rec_format_afmt[enc_config.rec_format]; 1482 + enc_config.afmt = afmt; 1483 + 1484 + queue_reply(&audio_queue, 0); /* Let caller go */ 1485 + 1486 + /* Pick appropriate PCM copy routine */ 1487 + pcm_copyfn = memcpy; 1488 + 1489 + if (num_channels == 1) 1490 + { 1491 + static typeof (memcpy) * const copy_buffer_mono[] = 1492 + { 1493 + copy_buffer_mono_lr, 1494 + copy_buffer_mono_l, 1495 + copy_buffer_mono_r 1496 + }; 1497 + 1498 + if (mono_mode >= ARRAYLEN(copy_buffer_mono)) 1499 + mono_mode = 0; 1500 + 1501 + pcm_copyfn = copy_buffer_mono[mono_mode]; 1502 + } 1503 + 1504 + /* Get the hardware samplerate to be used */ 1505 + unsigned long sampr; 1209 1506 1210 1507 #ifdef HAVE_SPDIF_IN 1211 1508 if (rec_source == AUDIO_SRC_SPDIF) 1212 - { 1213 - /* must measure SPDIF sample rate before configuring codecs */ 1214 - unsigned long sr = spdif_measure_frequency(); 1215 - /* round to master list for SPDIF rate */ 1216 - int index = round_value_to_list32(sr, audio_master_sampr_list, 1217 - SAMPR_NUM_FREQ, false); 1218 - sample_rate = audio_master_sampr_list[index]; 1219 - /* round to HW playback rates for monitoring */ 1220 - index = round_value_to_list32(sr, hw_freq_sampr, 1221 - HW_NUM_FREQ, false); 1222 - pcm_set_frequency(hw_freq_sampr[index] | SAMPR_TYPE_REC); 1223 - /* encoders with a limited number of rates do their own rounding */ 1224 - } 1509 + sampr = get_spdif_samplerate(); /* Determined by source */ 1225 1510 else 1226 - #endif 1227 - { 1228 - /* set sample rate from frequency selection */ 1229 - sample_rate = rec_freq_sampr[rec_frequency]; 1230 - pcm_set_frequency(sample_rate | SAMPR_TYPE_REC); 1231 - } 1511 + #endif /* HAVE_SPDIF_IN */ 1512 + sampr = rec_freq_sampr[frequency]; 1513 + 1514 + update_samplerate_config(sampr); 1232 1515 1233 - /* set monitoring */ 1516 + /* Set monitoring */ 1234 1517 audio_set_output_source(rec_source); 1235 1518 1236 - /* apply hardware setting to start monitoring now */ 1519 + /* Apply hardware setting to start monitoring now */ 1237 1520 pcm_apply_settings(); 1238 1521 1239 - queue_reply(&audio_queue, 0); /* Release sender */ 1240 - 1241 - if (codec_load(-1, enc_config.afmt | CODEC_TYPE_ENCODER)) 1522 + if (!enc_load || codec_load(-1, afmt | CODEC_TYPE_ENCODER)) 1242 1523 { 1524 + enc_cb = codec_get_enc_callback(); 1243 1525 1244 - /* run immediately */ 1245 - codec_go(); 1526 + if (!enc_cb || !configure_encoder_stream()) 1527 + { 1528 + codec_unload(); 1529 + return; 1530 + } 1246 1531 1247 - /* start DMA transfer */ 1248 - dma_lock = pre_record_ticks == 0; 1249 - pcm_record_data(pcm_rec_have_more, pcm_rec_status_callback, 1250 - GET_PCM_CHUNK(dma_wr_pos), PCM_CHUNK_SIZE); 1532 + if (pre_record_seconds != 0) 1533 + { 1534 + record_status = RECORD_PRERECORDING; 1535 + codec_go(); 1536 + pcm_pause = false; 1537 + } 1538 + 1539 + pcm_start_recording(); 1251 1540 } 1252 1541 else 1253 1542 { 1254 1543 logf("set rec opt: enc load failed"); 1255 - pcmrec_raise_error_status(PCMREC_E_LOAD_ENCODER); 1544 + raise_error_status(PCMREC_E_LOAD_ENCODER); 1256 1545 } 1257 - } /* pcmrec_set_recording_options */ 1546 + } 1258 1547 1259 - /* PCMREC_RECORD - start recording (not gapless) 1260 - or split stream (gapless) */ 1261 - static void pcmrec_record(const char *filename) 1548 + /* Q_AUDIO_RECORD - start recording (not gapless) 1549 + or split stream (gapless) */ 1550 + static void on_record(const char *filename) 1262 1551 { 1263 - unsigned long pre_sample_ticks; 1264 - int rd_start; 1265 - unsigned long flags; 1266 - int pre_index; 1552 + if (rec_errors) 1553 + { 1554 + logf("on_record: errors not cleared"); 1555 + return; 1556 + } 1267 1557 1268 - logf("pcmrec_record: %s", filename); 1269 - 1270 - /* reset stats */ 1271 - num_rec_bytes = 0; 1272 - num_rec_samples = 0; 1558 + if (!filename) 1559 + { 1560 + logf("on_record: No filename"); 1561 + return; 1562 + } 1273 1563 1274 - if (!is_recording) 1564 + if (codec_loaded() == AFMT_UNKNOWN) 1275 1565 { 1276 - #if 0 1277 - accum_rec_bytes = 0; 1278 - accum_pcm_samples = 0; 1279 - #endif 1280 - warnings = 0; /* reset warnings */ 1566 + logf("on_record: Recording options not set"); 1567 + return; 1568 + } 1281 1569 1282 - rd_start = enc_wr_index; 1283 - pre_sample_ticks = 0; 1284 - 1285 - pcmrec_refresh_watermarks(); 1286 - 1287 - if (pre_record_ticks) 1288 - { 1289 - int i = rd_start; 1290 - /* calculate number of available chunks */ 1291 - unsigned long avail_pre_chunks = (enc_wr_index - enc_rd_index + 1292 - enc_num_chunks) % enc_num_chunks; 1293 - /* overflow at 974 seconds of prerecording at 44.1kHz */ 1294 - unsigned long pre_record_sample_ticks = 1295 - enc_sample_rate*pre_record_ticks; 1296 - int pre_chunks = 0; /* Counter to limit prerecorded time to 1297 - prevent flood state at outset */ 1298 - 1299 - logf("pre-st: %ld", pre_record_sample_ticks); 1300 - 1301 - /* Get exact measure of recorded data as number of samples aren't 1302 - nescessarily going to be the max for each chunk */ 1303 - for (; avail_pre_chunks-- > 0;) 1304 - { 1305 - struct enc_chunk_hdr *chunk; 1306 - unsigned long chunk_sample_ticks; 1570 + logf("on_record: new file '%s'", filename); 1307 1571 1308 - DEC_ENC_INDEX(i); 1572 + /* Copy path and let caller go */ 1573 + char path[MAX_PATH]; 1574 + strlcpy(path, filename, MAX_PATH); 1309 1575 1310 - chunk = GET_ENC_CHUNK(i); 1576 + queue_reply(&audio_queue, 0); 1311 1577 1312 - /* must have data to be counted */ 1313 - if (chunk->enc_data == NULL) 1314 - continue; 1578 + enum mark_stream_action mark_action; 1315 1579 1316 - chunk_sample_ticks = chunk->num_pcm*HZ; 1580 + if (record_state == REC_STATE_IDLE) 1581 + { 1582 + mark_action = MARK_STREAM_START; 1317 1583 1318 - rd_start = i; 1319 - pre_sample_ticks += chunk_sample_ticks; 1320 - num_rec_bytes += chunk->enc_size; 1321 - num_rec_samples += chunk->num_pcm; 1322 - pre_chunks++; 1323 - 1324 - /* stop here if enough already */ 1325 - if (pre_chunks >= high_watermark || 1326 - pre_sample_ticks >= pre_record_sample_ticks) 1327 - { 1328 - logf("pre-chks: %d", pre_chunks); 1329 - break; 1330 - } 1331 - } 1332 - 1333 - #if 0 1334 - accum_rec_bytes = num_rec_bytes; 1335 - accum_pcm_samples = num_rec_samples; 1336 - #endif 1337 - } 1338 - 1339 - enc_rd_index = rd_start; 1340 - 1341 - /* filename queue should be empty */ 1342 - if (!pcmrec_fnq_is_empty()) 1584 + if (pre_record_seconds) 1343 1585 { 1344 - logf("fnq: not empty!"); 1345 - pcmrec_fnq_set_empty(); 1586 + codec_pause(); 1587 + tally_prerecord_data(); 1588 + mark_action = MARK_STREAM_START_PRE; 1346 1589 } 1347 1590 1348 - flags = CHUNKF_START_FILE; 1349 - if (pre_sample_ticks > 0) 1350 - flags |= CHUNKF_PRERECORD; 1351 - 1352 - pre_index = enc_rd_index; 1353 - 1354 - dma_lock = false; 1355 - is_paused = false; 1356 - is_recording = true; 1591 + clear_warning_status(PCMREC_W_ALL & 1592 + ~(PCMREC_W_SAMPR_MISMATCH|PCMREC_W_DMA)); 1593 + record_state = REC_STATE_MONITOR; 1594 + record_status = RECORD_RECORDING; 1357 1595 } 1358 1596 else 1359 1597 { 1360 - /* already recording, just split the stream */ 1598 + /* Already recording, just split the stream */ 1361 1599 logf("inserting split"); 1362 - flags = CHUNKF_START_FILE | CHUNKF_END_FILE; 1363 - pre_index = 0; 1600 + mark_action = MARK_STREAM_SPLIT; 1601 + finish_stream(false); 1602 + reset_rec_stats(); 1364 1603 } 1365 1604 1366 - pcmrec_new_stream(filename, flags, pre_index); 1367 - logf("pcmrec_record done"); 1368 - } /* pcmrec_record */ 1369 - 1370 - /* PCMREC_STOP */ 1371 - static void pcmrec_stop(void) 1372 - { 1373 - logf("pcmrec_stop"); 1374 - 1375 - if (is_recording) 1605 + if (rec_errors) 1376 1606 { 1377 - dma_lock = true; /* lock dma write position */ 1607 + pcm_pause = true; 1608 + codec_stop(); 1609 + reset_fifos(false); 1610 + return; 1611 + } 1378 1612 1379 - /* flush all available data first to avoid overflow while waiting 1380 - for encoding to finish */ 1381 - pcmrec_flush(PCMREC_FLUSH_ALL); 1613 + mark_stream(path, mark_action); 1382 1614 1383 - /* wait for encoder to finish remaining data */ 1384 - while (errors == 0 && !pcm_buffer_empty) 1385 - yield(); 1615 + codec_go(); 1616 + pcm_pause = record_status != RECORD_RECORDING; 1617 + } 1386 1618 1387 - /* end stream at last data */ 1388 - pcmrec_new_stream(NULL, CHUNKF_END_FILE, 0); 1619 + /* Q_AUDIO_RECORD_STOP */ 1620 + static void on_record_stop(void) 1621 + { 1622 + if (record_state == REC_STATE_IDLE) 1623 + return; 1389 1624 1390 - /* flush anything else encoder added */ 1391 - pcmrec_flush(PCMREC_FLUSH_ALL); 1625 + /* Drain encoder and PCM buffers */ 1626 + pcm_pause = true; 1627 + finish_stream(true); 1392 1628 1393 - /* remove any pending file start not yet processed - should be at 1394 - most one at enc_wr_index */ 1395 - pcmrec_fnq_get_filename(NULL); 1396 - /* encoder should abort any chunk it was in midst of processing */ 1397 - GET_ENC_CHUNK(enc_wr_index)->flags = CHUNKF_ABORT; 1629 + /* End stream at last data and flush end marker */ 1630 + mark_stream(NULL, MARK_STREAM_END); 1631 + while (flush_chunk(REC_STATE_IDLE, 1) == REC_STATE_IDLE); 1398 1632 1399 - /* filename queue should be empty */ 1400 - if (!pcmrec_fnq_is_empty()) 1401 - { 1402 - logf("fnq: not empty!"); 1403 - pcmrec_fnq_set_empty(); 1404 - } 1633 + reset_fifos(false); 1405 1634 1406 - /* be absolutely sure the file is closed */ 1407 - if (errors != 0) 1408 - pcmrec_close_file(&rec_fdata.rec_file); 1409 - rec_fdata.rec_file = -1; 1635 + bool prerecord = pre_record_seconds != 0; 1410 1636 1411 - is_recording = false; 1412 - is_paused = false; 1413 - dma_lock = pre_record_ticks == 0; 1414 - } 1415 - else 1637 + if (rec_errors) 1416 1638 { 1417 - logf("not recording"); 1639 + codec_stop(); 1640 + prerecord = false; 1418 1641 } 1419 1642 1420 - logf("pcmrec_stop done"); 1421 - } /* pcmrec_stop */ 1643 + close_rec_file(); 1644 + rec_errors = 0; 1422 1645 1423 - /* PCMREC_PAUSE */ 1424 - static void pcmrec_pause(void) 1425 - { 1426 - logf("pcmrec_pause"); 1646 + record_state = REC_STATE_IDLE; 1647 + record_status = prerecord ? RECORD_PRERECORDING : RECORD_STOPPED; 1648 + reset_rec_stats(); 1427 1649 1428 - if (!is_recording) 1650 + if (prerecord) 1429 1651 { 1430 - logf("not recording"); 1652 + codec_go(); 1653 + pcm_pause = false; 1431 1654 } 1432 - else if (is_paused) 1433 - { 1434 - logf("already paused"); 1435 - } 1436 - else 1437 - { 1438 - dma_lock = true; 1439 - is_paused = true; 1440 - } 1655 + } 1656 + 1657 + /* Q_AUDIO_RECORD_PAUSE */ 1658 + static void on_record_pause(void) 1659 + { 1660 + if (record_status != RECORD_RECORDING) 1661 + return; 1441 1662 1442 - logf("pcmrec_pause done"); 1443 - } /* pcmrec_pause */ 1663 + pcm_pause = true; 1664 + record_status = RECORD_PAUSED; 1665 + } 1444 1666 1445 - /* PCMREC_RESUME */ 1446 - static void pcmrec_resume(void) 1667 + /* Q_AUDIO_RECORD_RESUME */ 1668 + static void on_record_resume(void) 1447 1669 { 1448 - logf("pcmrec_resume"); 1449 - 1450 - if (!is_recording) 1451 - { 1452 - logf("not recording"); 1453 - } 1454 - else if (!is_paused) 1455 - { 1456 - logf("not paused"); 1457 - } 1458 - else 1459 - { 1460 - is_paused = false; 1461 - is_recording = true; 1462 - dma_lock = false; 1463 - } 1670 + if (record_status != RECORD_PAUSED) 1671 + return; 1464 1672 1465 - logf("pcmrec_resume done"); 1466 - } /* pcmrec_resume */ 1673 + record_status = RECORD_RECORDING; 1674 + pcm_pause = !!rec_errors; 1675 + } 1467 1676 1468 1677 /* Called by audio thread when recording is initialized */ 1469 1678 void audio_recording_handler(struct queue_event *ev) 1470 1679 { 1471 - logf("audio recording start"); 1680 + #ifdef HAVE_PRIORITY_SCHEDULING 1681 + /* Get current priorities since they get changed */ 1682 + int old_prio = thread_get_priority(audio_thread_id); 1683 + int old_cod_prio = codec_thread_get_priority(); 1684 + #endif 1685 + 1686 + LOGFQUEUE("record < Q_AUDIO_INIT_RECORDING"); 1687 + on_init_recording(); 1472 1688 1473 1689 while (1) 1474 1690 { 1691 + int watermark = high_watermark; 1692 + 1475 1693 switch (ev->id) 1476 1694 { 1477 - case Q_AUDIO_INIT_RECORDING: 1478 - pcmrec_init(); 1479 - break; 1480 - 1481 - case SYS_USB_CONNECTED: 1482 - if (is_recording) 1483 - break; 1484 - /* Fall-through */ 1485 1695 case Q_AUDIO_CLOSE_RECORDING: 1486 - pcmrec_close(); 1487 - return; /* no more recording */ 1696 + LOGFQUEUE("record < Q_AUDIO_CLOSE_RECORDING"); 1697 + goto recording_done; 1488 1698 1489 1699 case Q_AUDIO_RECORDING_OPTIONS: 1490 - pcmrec_set_recording_options( 1491 - (struct audio_recording_options *)ev->data); 1700 + LOGFQUEUE("record < Q_AUDIO_RECORDING_OPTIONS"); 1701 + on_recording_options((struct audio_recording_options *)ev->data); 1492 1702 break; 1493 1703 1494 1704 case Q_AUDIO_RECORD: 1495 - clear_flush_interrupt(); 1496 - pcmrec_record((const char *)ev->data); 1705 + LOGFQUEUE("record < Q_AUDIO_RECORD: %s", (const char *)ev->data); 1706 + on_record((const char *)ev->data); 1497 1707 break; 1498 1708 1499 - case Q_AUDIO_STOP: 1500 - clear_flush_interrupt(); 1501 - pcmrec_stop(); 1709 + case Q_AUDIO_RECORD_STOP: 1710 + LOGFQUEUE("record < Q_AUDIO_RECORD_STOP"); 1711 + on_record_stop(); 1502 1712 break; 1503 1713 1504 - case Q_AUDIO_PAUSE: 1505 - clear_flush_interrupt(); 1506 - pcmrec_pause(); 1714 + case Q_AUDIO_RECORD_PAUSE: 1715 + LOGFQUEUE("record < Q_AUDIO_RECORD_PAUSE"); 1716 + on_record_pause(); 1507 1717 break; 1508 1718 1509 - case Q_AUDIO_RESUME: 1510 - pcmrec_resume(); 1719 + case Q_AUDIO_RECORD_RESUME: 1720 + LOGFQUEUE("record < Q_AUDIO_RECORD_RESUME"); 1721 + on_record_resume(); 1511 1722 break; 1512 1723 1513 - case SYS_TIMEOUT: 1514 - /* Messages that interrupt this will complete it */ 1515 - pcmrec_flush(PCMREC_FLUSH_IF_HIGH | 1516 - PCMREC_FLUSH_INTERRUPTABLE); 1517 - 1518 - if (errors & PCMREC_E_DMA) 1519 - queue_post(&audio_queue, Q_AUDIO_STOP, 0); 1724 + case Q_AUDIO_RECORD_FLUSH: 1725 + watermark = 1; 1520 1726 break; 1521 - } /* end switch */ 1522 1727 1523 - queue_wait_w_tmo(&audio_queue, ev, 1524 - is_recording ? HZ/5 : TIMEOUT_BLOCK); 1525 - } /* end while */ 1526 - } /* audio_recording_handler */ 1728 + case SYS_USB_CONNECTED: 1729 + LOGFQUEUE("record < SYS_USB_CONNECTED"); 1730 + if (record_state != REC_STATE_IDLE) 1731 + { 1732 + LOGFQUEUE(" still recording"); 1733 + break; 1734 + } 1527 1735 1528 - /****************************************************************************/ 1529 - /* */ 1530 - /* following functions will be called by the encoder codec */ 1531 - /* in a free-threaded manner */ 1532 - /* */ 1533 - /****************************************************************************/ 1736 + goto recording_done; 1737 + } /* switch */ 1534 1738 1535 - /* pass the encoder settings to the encoder */ 1536 - void enc_get_inputs(struct enc_inputs *inputs) 1537 - { 1538 - inputs->sample_rate = sample_rate; 1539 - inputs->num_channels = num_channels; 1540 - inputs->rec_mono_mode = rec_mono_mode; 1541 - inputs->config = &enc_config; 1542 - } /* enc_get_inputs */ 1739 + int timeout; 1543 1740 1544 - /* set the encoder dimensions (called by encoder codec at initialization and 1545 - termination) */ 1546 - void enc_set_parameters(struct enc_parameters *params) 1547 - { 1548 - size_t bufsize, resbytes; 1741 + switch (record_state) 1742 + { 1743 + case REC_STATE_FLUSH: 1744 + case REC_STATE_MONITOR: 1745 + do 1746 + record_state = flush_chunk(record_state, watermark); 1747 + while (record_state == REC_STATE_FLUSH && 1748 + queue_empty(&audio_queue)); 1549 1749 1550 - logf("enc_set_parameters"); 1750 + timeout = record_state == REC_STATE_FLUSH ? 1751 + HZ*0 : HZ*FLUSH_MON_INTERVAL; 1752 + break; 1753 + case REC_STATE_IDLE: 1754 + #ifdef HAVE_SPDIF_IN 1755 + if (rec_source == AUDIO_SRC_SPDIF) 1756 + { 1757 + check_spdif_samplerate(); 1758 + timeout = HZ/2; 1759 + break; 1760 + } 1761 + #endif /* HAVE_SPDIF_IN */ 1762 + default: 1763 + timeout = TIMEOUT_BLOCK; 1764 + break; 1765 + } 1551 1766 1552 - if (!params) 1553 - { 1554 - logf("reset"); 1555 - /* Encoder is terminating */ 1556 - memset(&enc_config, 0, sizeof (enc_config)); 1557 - enc_sample_rate = 0; 1558 - cancel_cpu_boost(); /* Make sure no boost remains */ 1559 - return; 1560 - } 1767 + queue_wait_w_tmo(&audio_queue, ev, timeout); 1768 + } /* while */ 1561 1769 1562 - enc_sample_rate = params->enc_sample_rate; 1563 - logf("enc sampr:%lu", enc_sample_rate); 1770 + recording_done: 1771 + on_close_recording(); 1772 + #ifdef HAVE_PRIORITY_SCHEDULING 1773 + /* Restore normal thread priorities */ 1774 + thread_set_priority(audio_thread_id, old_prio); 1775 + codec_thread_set_priority(old_cod_prio); 1776 + #endif 1777 + } 1564 1778 1565 - pcm_rd_pos = dma_wr_pos; 1566 - pcm_enc_pos = pcm_rd_pos; 1567 1779 1568 - enc_config.afmt = params->afmt; 1569 - /* addition of the header is always implied - chunk size 4-byte aligned */ 1570 - enc_chunk_size = 1571 - ALIGN_UP_P2(ENC_CHUNK_HDR_SIZE + params->chunk_size, 2); 1572 - enc_events_callback = params->events_callback; 1780 + /** Encoder callbacks **/ 1573 1781 1574 - logf("chunk size:%lu", enc_chunk_size); 1782 + /* Read a block of unprocessed PCM data, with mono conversion if 1783 + * num_channels == 1 1784 + * 1785 + * NOTE: Request must be less than the PCM buffer length in samples in order 1786 + * to progress. 1787 + * (ie. count <= PCM_NUM_CHUNKS*PCM_CHUNK_SAMP) 1788 + */ 1789 + static int enc_pcmbuf_read(void *buffer, int count) 1790 + { 1791 + size_t avail = pcmbuf_used(); 1792 + size_t size = count*PCM_SAMP_SIZE; 1575 1793 1576 - /*** Configure the buffers ***/ 1794 + if (count > 0 && avail >= size) 1795 + { 1796 + size_t endidx = pcm_ridx + size; 1577 1797 1578 - /* Layout of recording buffer: 1579 - * [ax] = possible alignment x multiple 1580 - * [sx] = possible size alignment of x multiple 1581 - * |[a16]|[s4]:PCM Buffer+PCM Guard|[s4 each]:Encoder Chunks|-> 1582 - * |[[s4]:Reserved Bytes]|Filename Queue->|[space]| 1583 - */ 1584 - resbytes = ALIGN_UP_P2(params->reserve_bytes, 2); 1585 - logf("resbytes:%lu", resbytes); 1798 + if (endidx > PCM_BUF_SIZE) 1799 + { 1800 + size_t wrap = endidx - PCM_BUF_SIZE; 1801 + size_t offset = size -= wrap; 1586 1802 1587 - bufsize = rec_buffer_size - (enc_buffer - pcm_buffer) - 1588 - resbytes - FNQ_MIN_NUM_PATHS*MAX_PATH 1589 - #ifdef DEBUG 1590 - - sizeof (*wrap_id_p) 1591 - #endif 1592 - ; 1803 + if (num_channels == 1) 1804 + offset /= 2; /* src offset -> dst offset */ 1593 1805 1594 - enc_num_chunks = bufsize / enc_chunk_size; 1595 - logf("num chunks:%d", enc_num_chunks); 1806 + pcm_copyfn(buffer + offset, pcmbuf_ptr(0), wrap); 1807 + } 1596 1808 1597 - /* get real amount used by encoder chunks */ 1598 - bufsize = enc_num_chunks*enc_chunk_size; 1599 - logf("enc size:%lu", bufsize); 1809 + pcm_copyfn(buffer, pcmbuf_ptr(pcm_ridx), size); 1600 1810 1601 - #ifdef DEBUG 1602 - /* add magic at wraparound for spillover checks */ 1603 - wrap_id_p = SKIPBYTES((unsigned long *)enc_buffer, bufsize); 1604 - bufsize += sizeof (*wrap_id_p); 1605 - *wrap_id_p = ENC_CHUNK_MAGIC; 1606 - #endif 1811 + if (avail >= sample_rate*PCM_SAMP_SIZE*PCM_BOOST_SECONDS || 1812 + avail >= PCM_BUF_SIZE*1/2) 1813 + { 1814 + /* Filling up - boost threshold data available or more or 1/2 full 1815 + or more - boost codec */ 1816 + trigger_cpu_boost(); 1817 + } 1607 1818 1608 - /** set OUT parameters **/ 1609 - params->enc_buffer = enc_buffer; 1610 - params->buf_chunk_size = enc_chunk_size; 1611 - params->num_chunks = enc_num_chunks; 1819 + pcm_buffer_empty = false; 1612 1820 1613 - /* calculate reserve buffer start and return pointer to encoder */ 1614 - params->reserve_buffer = NULL; 1615 - if (resbytes > 0) 1616 - { 1617 - params->reserve_buffer = enc_buffer + bufsize; 1618 - bufsize += resbytes; 1821 + return count; 1619 1822 } 1620 1823 1621 - /* place filename queue at end of buffer using up whatever remains */ 1622 - fnq_rd_pos = 0; /* reset */ 1623 - fnq_wr_pos = 0; /* reset */ 1624 - fn_queue = enc_buffer + bufsize; 1625 - fnq_size = pcm_buffer + rec_buffer_size - fn_queue; 1626 - fnq_size /= MAX_PATH; 1627 - if (fnq_size > FNQ_MAX_NUM_PATHS) 1628 - fnq_size = FNQ_MAX_NUM_PATHS; 1629 - fnq_size *= MAX_PATH; 1630 - logf("fnq files:%ld", fnq_size / MAX_PATH); 1824 + /* Not enough data available - encoder should idle */ 1825 + pcm_buffer_empty = true; 1631 1826 1632 - #if defined(DEBUG) 1633 - logf("pcm:%08lX", (uintptr_t)pcm_buffer); 1634 - logf("enc:%08lX", (uintptr_t)enc_buffer); 1635 - logf("res:%08lX", (uintptr_t)params->reserve_buffer); 1636 - logf("wip:%08lX", (uintptr_t)wrap_id_p); 1637 - logf("fnq:%08lX", (uintptr_t)fn_queue); 1638 - logf("end:%08lX", (uintptr_t)fn_queue + fnq_size); 1639 - #endif 1827 + cancel_cpu_boost(); 1640 1828 1641 - /* init all chunk headers and reset indexes */ 1642 - enc_rd_index = 0; 1643 - for (enc_wr_index = enc_num_chunks; enc_wr_index > 0; ) 1644 - { 1645 - struct enc_chunk_hdr *chunk = GET_ENC_CHUNK(--enc_wr_index); 1646 - #ifdef DEBUG 1647 - chunk->id = ENC_CHUNK_MAGIC; 1648 - #endif 1649 - chunk->flags = 0; 1650 - } 1829 + /* Sleep a little bit */ 1830 + sleep(0); 1651 1831 1652 - logf("enc_set_parameters done"); 1653 - } /* enc_set_parameters */ 1832 + return 0; 1833 + } 1654 1834 1655 - /* return encoder chunk at current write position - 1656 - NOTE: can be called by pcmrec thread when splitting streams */ 1657 - struct enc_chunk_hdr * enc_get_chunk(void) 1835 + /* Advance PCM buffer by count samples */ 1836 + static int enc_pcmbuf_advance(int count) 1658 1837 { 1659 - struct enc_chunk_hdr *chunk = GET_ENC_CHUNK(enc_wr_index); 1838 + if (count <= 0) 1839 + return 0; 1840 + 1841 + size_t avail = pcmbuf_used(); 1842 + size_t size = count*PCM_SAMP_SIZE; 1660 1843 1661 - #ifdef DEBUG 1662 - if (chunk->id != ENC_CHUNK_MAGIC || *wrap_id_p != ENC_CHUNK_MAGIC) 1844 + if (avail < size) 1663 1845 { 1664 - pcmrec_raise_error_status(PCMREC_E_CHUNK_OVF); 1665 - logf("finish chk ovf: %d", enc_wr_index); 1846 + size = avail; 1847 + count = size / PCM_SAMP_SIZE; 1666 1848 } 1667 - #endif 1668 1849 1669 - chunk->flags &= CHUNKF_START_FILE; 1670 - 1671 - if (!is_recording) 1672 - chunk->flags |= CHUNKF_PRERECORD; 1850 + pcm_ridx = pcmbuf_add(pcm_ridx, size); 1673 1851 1674 - return chunk; 1675 - } /* enc_get_chunk */ 1852 + return count; 1853 + } 1676 1854 1677 - /* releases the current chunk into the available chunks - 1678 - NOTE: can be called by pcmrec thread when splitting streams */ 1679 - void enc_finish_chunk(void) 1855 + /* Return encoder chunk at current write position, wrapping to 0 if 1856 + * requested size demands it. 1857 + * 1858 + * NOTE: No request should be more than 1/2 the buffer length, all elements 1859 + * included, or progress will not be guaranteed. 1860 + * (ie. CHUNK_DATA_COUNT(need) <= enc_buflen / 2) 1861 + */ 1862 + static struct enc_chunk_data * enc_encbuf_get_buffer(size_t need) 1680 1863 { 1681 - struct enc_chunk_hdr *chunk = GET_ENC_CHUNK(enc_wr_index); 1864 + /* Convert to buffer slot count, including the header */ 1865 + need = CHUNK_DATA_COUNT(need); 1866 + 1867 + enum record_state state = record_state; 1868 + size_t avail = encbuf_free(); 1682 1869 1683 - if ((long)chunk->flags < 0) 1870 + /* Must have the split margin as well but it does not have to be 1871 + continuous with the request */ 1872 + while (avail <= need + ENCBUF_MIN_SPLIT_MARGIN || 1873 + (enc_widx + need > enc_buflen && 1874 + enc_ridx <= need + ENCBUF_MIN_SPLIT_MARGIN)) 1684 1875 { 1685 - /* encoder set error flag */ 1686 - pcmrec_raise_error_status(PCMREC_E_ENCODER); 1687 - logf("finish chk enc error"); 1688 - } 1876 + if (UNLIKELY(state == REC_STATE_IDLE)) 1877 + { 1878 + /* Prerecording - delete some old data */ 1879 + size_t ridx; 1880 + struct enc_chunk_data *data = 1881 + encbuf_read_ptr_incr(enc_ridx, &ridx); 1689 1882 1690 - /* advance enc_wr_index to the next encoder chunk */ 1691 - INC_ENC_INDEX(enc_wr_index); 1883 + if (data) 1884 + { 1885 + encbuf_rec_count -= CHUNK_DATA_COUNT(data->hdr.size); 1886 + num_rec_bytes -= data->hdr.size; 1887 + num_rec_samples -= data->pcm_count; 1888 + } 1692 1889 1693 - if (enc_rd_index != enc_wr_index) 1694 - { 1695 - num_rec_bytes += chunk->enc_size; 1696 - num_rec_samples += chunk->num_pcm; 1697 - #if 0 1698 - accum_rec_bytes += chunk->enc_size; 1699 - accum_pcm_samples += chunk->num_pcm; 1700 - #endif 1701 - } 1702 - else if (is_recording) /* buffer full */ 1703 - { 1704 - /* keep current position and put up warning flag */ 1705 - pcmrec_raise_warning_status(PCMREC_W_ENC_BUFFER_OVF); 1706 - logf("enc_buffer ovf"); 1707 - DEC_ENC_INDEX(enc_wr_index); 1708 - if (pcmrec_context) 1890 + enc_ridx = ridx; 1891 + avail = encbuf_free(); 1892 + continue; 1893 + } 1894 + else if (avail == enc_buflen) 1709 1895 { 1710 - /* if stream splitting, keep this out of circulation and 1711 - flush a small number, then readd - cannot risk losing 1712 - stream markers */ 1713 - logf("mini flush"); 1714 - pcmrec_flush(PCMREC_FLUSH_MINI); 1715 - INC_ENC_INDEX(enc_wr_index); 1896 + /* Empty but request larger than any possible space */ 1897 + raise_warning_status(PCMREC_W_ENC_BUFFER_OVF); 1716 1898 } 1899 + else if (state != REC_STATE_FLUSH && encbuf_used() < high_watermark) 1900 + { 1901 + /* Not yet even at high watermark but what's needed won't fit */ 1902 + encbuf_request_flush(); 1903 + } 1904 + 1905 + sleep(0); 1906 + return NULL; 1717 1907 } 1718 - else 1719 - { 1720 - /* advance enc_rd_index for prerecording */ 1721 - INC_ENC_INDEX(enc_rd_index); 1722 - } 1723 - } /* enc_finish_chunk */ 1908 + 1909 + struct enc_chunk_data *data = 1910 + encbuf_get_write_ptr(enc_widx, need, &enc_widx); 1911 + 1912 + if (state == REC_STATE_IDLE) 1913 + data->hdr.pre = 1; 1914 + 1915 + return data; 1916 + } 1724 1917 1725 - /* passes a pointer to next chunk of unprocessed wav data */ 1726 - /* TODO: this really should give the actual size returned */ 1727 - unsigned char * enc_get_pcm_data(size_t size) 1918 + /* Releases the current buffer into the available chunks */ 1919 + static void enc_encbuf_finish_buffer(void) 1728 1920 { 1729 - int wp = dma_wr_pos; 1730 - size_t avail = (wp - pcm_rd_pos) & PCM_CHUNK_MASK; 1921 + struct enc_chunk_data *data = ENC_DATA_HDR(encbuf_ptr(enc_widx)); 1731 1922 1732 - /* limit the requested pcm data size */ 1733 - if (size > PCM_MAX_FEED_SIZE) 1734 - size = PCM_MAX_FEED_SIZE; 1923 + if (data->hdr.err) 1924 + { 1925 + /* Encoder set error flag */ 1926 + raise_error_status(PCMREC_E_ENCODER); 1927 + return; 1928 + } 1735 1929 1736 - if (avail >= size) 1737 - { 1738 - unsigned char *ptr = pcm_buffer + pcm_rd_pos; 1739 - int next_pos = (pcm_rd_pos + size) & PCM_CHUNK_MASK; 1930 + size_t data_size = data->hdr.size; 1740 1931 1741 - pcm_enc_pos = pcm_rd_pos; 1742 - pcm_rd_pos = next_pos; 1932 + if (data_size == 0) 1933 + return; /* Claims nothing was written */ 1743 1934 1744 - /* ptr must point to continous data at wraparound position */ 1745 - if ((size_t)pcm_rd_pos < size) 1746 - { 1747 - memcpy(pcm_buffer + PCM_NUM_CHUNKS*PCM_CHUNK_SIZE, 1748 - pcm_buffer, pcm_rd_pos); 1749 - } 1935 + size_t count = CHUNK_DATA_COUNT(data_size); 1936 + size_t avail = encbuf_free(); 1750 1937 1751 - if (avail >= (sample_rate << 2) || 1752 - avail >= 3*(PCM_NUM_CHUNKS*PCM_CHUNK_SIZE) / 4) 1753 - { 1754 - /* Filling up - 1s data available or more or 3/4 full or more - 1755 - boost codec */ 1756 - trigger_cpu_boost(); 1757 - } 1938 + if (avail <= count || enc_widx + count > enc_buflen) 1939 + { 1940 + /* Claims it wrote too much? */ 1941 + raise_warning_status(PCMREC_W_ENC_BUFFER_OVF); 1942 + return; 1943 + } 1758 1944 1759 - pcm_buffer_empty = false; 1760 - return ptr; 1945 + if (num_rec_bytes + data_size > MAX_NUM_REC_BYTES) 1946 + { 1947 + /* Would exceed filesize limit; should have split sooner. 1948 + This chunk will be dropped. :'( */ 1949 + raise_warning_status(PCMREC_W_FILE_SIZE); 1950 + return; 1761 1951 } 1762 1952 1763 - /* not enough data available - encoder should idle */ 1764 - pcm_buffer_empty = true; 1953 + encbuf_widx_advance(enc_widx, count); 1765 1954 1766 - cancel_cpu_boost(); 1955 + encbuf_rec_count += count; 1956 + num_rec_bytes += data_size; 1957 + num_rec_samples += data->pcm_count; 1958 + } 1767 1959 1768 - /* Sleep long enough to allow one frame on average */ 1769 - sleep(0); 1960 + /* Read from the output stream */ 1961 + static ssize_t enc_stream_read(void *buf, size_t count) 1962 + { 1963 + if (!stream_flush_buf()) 1964 + return -1; 1770 1965 1771 - return NULL; 1772 - } /* enc_get_pcm_data */ 1966 + return read(rec_fd, buf, count); 1967 + } 1773 1968 1774 - /* puts some pcm data back in the queue */ 1775 - size_t enc_unget_pcm_data(size_t size) 1969 + /* Seek the output steam */ 1970 + static off_t enc_stream_lseek(off_t offset, int whence) 1776 1971 { 1777 - int wp = dma_wr_pos; 1778 - size_t old_avail = ((pcm_rd_pos - wp) & PCM_CHUNK_MASK) - 1779 - 2*PCM_CHUNK_SIZE; 1972 + if (!stream_flush_buf()) 1973 + return -1; 1780 1974 1781 - /* allow one interrupt to occur during this call and not have the 1782 - new read position inside the DMA destination chunk */ 1783 - if ((ssize_t)old_avail > 0) 1975 + return lseek(rec_fd, offset, whence); 1976 + } 1977 + 1978 + /* Write to the output stream */ 1979 + static ssize_t enc_stream_write(const void *buf, size_t count) 1980 + { 1981 + if (UNLIKELY(count >= STREAM_BUF_SIZE)) 1784 1982 { 1785 - /* limit size to amount of old data remaining */ 1786 - if (size > old_avail) 1787 - size = old_avail; 1983 + /* Too big to buffer */ 1984 + if (stream_flush_buf()) 1985 + return write(rec_fd, buf, count); 1986 + } 1788 1987 1789 - pcm_enc_pos = (pcm_rd_pos - size) & PCM_CHUNK_MASK; 1790 - pcm_rd_pos = pcm_enc_pos; 1988 + if (!count) 1989 + return 0; 1791 1990 1792 - return size; 1991 + if (stream_buf_used + count > STREAM_BUF_SIZE) 1992 + { 1993 + if (!stream_flush_buf() && stream_buf_used + count > STREAM_BUF_SIZE) 1994 + count = STREAM_BUF_SIZE - stream_buf_used; 1793 1995 } 1794 1996 1795 - return 0; 1796 - } /* enc_unget_pcm_data */ 1997 + memcpy(stream_buffer + stream_buf_used, buf, count); 1998 + stream_buf_used += count; 1999 + 2000 + return count; 2001 + } 2002 + 2003 + /* One-time init at startup */ 2004 + void INIT_ATTR recording_init(void) 2005 + { 2006 + /* Init API */ 2007 + ci.enc_pcmbuf_read = enc_pcmbuf_read; 2008 + ci.enc_pcmbuf_advance = enc_pcmbuf_advance; 2009 + ci.enc_encbuf_get_buffer = enc_encbuf_get_buffer; 2010 + ci.enc_encbuf_finish_buffer = enc_encbuf_finish_buffer; 2011 + ci.enc_stream_read = enc_stream_read; 2012 + ci.enc_stream_lseek = enc_stream_lseek; 2013 + ci.enc_stream_write = enc_stream_write; 2014 + }
+46 -28
apps/recorder/pcm_record.h
··· 8 8 * $Id$ 9 9 * 10 10 * Copyright (C) 2005 by Linus Nielsen Feltzing 11 + * Copyright (C) 2006-2013 by Michael Sevakis 11 12 * 12 13 * This program is free software; you can redistribute it and/or 13 14 * modify it under the terms of the GNU General Public License ··· 18 19 * KIND, either express or implied. 19 20 * 20 21 ****************************************************************************/ 21 - 22 22 #ifndef PCM_RECORD_H 23 23 #define PCM_RECORD_H 24 24 25 - #include "config.h" 25 + /** Warnings (recording may continue with possible data loss) 26 + ** Reset of recording clears, otherwise see notes below 27 + */ 26 28 27 - /** Warnings **/ 28 - /* pcm (dma) buffer has overflowed */ 29 + /* PCM buffer has overflowed; PCM samples were dropped */ 30 + /* persists until: stop, new file, clear */ 29 31 #define PCMREC_W_PCM_BUFFER_OVF 0x00000001 30 - /* encoder output buffer has overflowed */ 32 + /* encoder output buffer has overflowed; encoded data was dropped */ 33 + /* persists until: stop, new file, clear */ 31 34 #define PCMREC_W_ENC_BUFFER_OVF 0x00000002 32 - /** Errors **/ 35 + /* encoder and set/detected sample rates do not match */ 36 + /* persists until: rates match, clear */ 37 + #define PCMREC_W_SAMPR_MISMATCH 0x00000004 38 + /* PCM frame skipped because of recoverable DMA error */ 39 + /* persists until: clear */ 40 + #define PCMREC_W_DMA 0x00000008 41 + /* internal file size limit was reached; encoded data was dropped */ 42 + /* persists until: stop, new file, clear */ 43 + #define PCMREC_W_FILE_SIZE 0x00000010 44 + 45 + /* all warning flags */ 46 + #define PCMREC_W_ALL 0x0000001f 47 + 48 + /** Errors (recording should be reset) 49 + ** 50 + ** Stopping recording if recording clears internally and externally visible 51 + ** status must be cleared with audio_error_clear() 52 + ** reset of recording clears 53 + */ 54 + 55 + /* DMA callback has reported an error */ 56 + #define PCMREC_E_DMA 0x80010000 33 57 /* failed to load encoder */ 34 - #define PCMREC_E_LOAD_ENCODER 0x80001000 58 + #define PCMREC_E_LOAD_ENCODER 0x80020000 35 59 /* error originating in encoder */ 36 - #define PCMREC_E_ENCODER 0x80002000 37 - /* filename queue has desynced from stream markers */ 38 - #define PCMREC_E_FNQ_DESYNC 0x80004000 60 + #define PCMREC_E_ENCODER 0x80040000 61 + /* error from encoder setup of stream parameters */ 62 + #define PCMREC_E_ENC_SETUP 0x80080000 63 + /* error writing to output stream */ 64 + #define PCMREC_E_ENCODER_STREAM 0x80100000 39 65 /* I/O error has occurred */ 40 - #define PCMREC_E_IO 0x80008000 41 - #ifdef DEBUG 42 - /* encoder has written past end of allocated space */ 43 - #define PCMREC_E_CHUNK_OVF 0x80010000 44 - #endif /* DEBUG */ 45 - /* DMA callback has reported an error */ 46 - #define PCMREC_E_DMA 0x80020000 66 + #define PCMREC_E_IO 0x80200000 67 + 68 + /* all error flags */ 69 + #define PCMREC_E_ALL 0x803f0000 47 70 48 - /** General functions for high level codec recording **/ 49 - /* pcm_rec_error_clear is deprecated for general use. audio_error_clear 50 - should be used */ 71 + /* Functions called by audio_thread.c */ 51 72 void pcm_rec_error_clear(void); 52 - /* pcm_rec_status is deprecated for general use. audio_status merges the 53 - results for consistency with the hardware codec version */ 54 73 unsigned int pcm_rec_status(void); 55 - unsigned long pcm_rec_get_warnings(void); 56 - void pcm_rec_init(void) INIT_ATTR; 57 - int pcm_rec_current_bitrate(void); 58 - int pcm_rec_encoder_afmt(void); /* AFMT_* value, AFMT_UNKNOWN if none */ 59 - int pcm_rec_rec_format(void); /* Format index or -1 otherwise */ 74 + uint32_t pcm_rec_get_warnings(void); 75 + #ifdef HAVE_SPDIF_IN 60 76 unsigned long pcm_rec_sample_rate(void); 61 - int pcm_get_num_unprocessed(void); 77 + #endif 78 + 79 + void recording_init(void); 62 80 63 81 /* audio.h contains audio_* recording functions */ 64 82
+10 -3
apps/recorder/recording.c
··· 1730 1730 /* Don't use language string unless agreed upon to make this 1731 1731 method permanent - could do something in the statusbar */ 1732 1732 snprintf(buf, sizeof(buf), "Warning: %08lX", 1733 - pcm_rec_get_warnings()); 1733 + (unsigned long)pcm_rec_get_warnings()); 1734 1734 } 1735 1735 else 1736 1736 #endif /* CONFIG_CODEC == SWCODEC */ ··· 1755 1755 1756 1756 if(audio_stat & AUDIO_STATUS_PRERECORD) 1757 1757 { 1758 + #if CONFIG_CODEC == SWCODEC 1759 + /* Tracks amount of prerecorded data in buffer */ 1760 + snprintf(buf, sizeof(buf), "%s (%lu/%ds)...", 1761 + str(LANG_RECORD_PRERECORD), 1762 + audio_prerecorded_time() / HZ, 1763 + global_settings.rec_prerecord_time); 1764 + #else /* !SWCODEC */ 1758 1765 snprintf(buf, sizeof(buf), "%s...", 1759 1766 str(LANG_RECORD_PRERECORD)); 1767 + #endif /* CONFIG_CODEC == SWCODEC */ 1760 1768 } 1761 1769 else 1762 1770 { ··· 1915 1923 screens[i].update(); 1916 1924 1917 1925 #if CONFIG_CODEC == SWCODEC 1918 - /* stop recording - some players like H10 freeze otherwise 1919 - TO DO: find out why it freezes and fix properly */ 1926 + /* stop recording first and try to finish saving whatever it can */ 1920 1927 rec_command(RECORDING_CMD_STOP); 1921 1928 audio_close_recording(); 1922 1929 #endif
+1 -4
firmware/export/audio.h
··· 212 212 213 213 #if CONFIG_CODEC == SWCODEC 214 214 /* SWCODEC recording functions */ 215 - /* playback.c */ 216 - bool audio_load_encoder(int afmt); 217 - void audio_remove_encoder(void); 218 - unsigned char *audio_get_recording_buffer(size_t *buffer_size); 215 + unsigned long audio_prerecorded_time(void); 219 216 #endif /* CONFIG_CODEC == SWCODEC */ 220 217 221 218 #endif /* HAVE_RECORDING */
+71 -131
firmware/export/enc_base.h
··· 9 9 * 10 10 * Base declarations for working with software encoders 11 11 * 12 - * Copyright (C) 2006 Michael Sevakis 12 + * Copyright (C) 2006-2013 Michael Sevakis 13 13 * 14 14 * This program is free software; you can redistribute it and/or 15 15 * modify it under the terms of the GNU General Public License ··· 24 24 #ifndef ENC_BASE_H 25 25 #define ENC_BASE_H 26 26 27 - /** encoder config structures **/ 27 + #include <sys/types.h> 28 + 29 + /** Encoder config structures **/ 28 30 29 31 /** aiff_enc.codec **/ 30 32 struct aiff_enc_config ··· 57 59 58 60 /* MPEG 1 */ 59 61 #define MPEG1_SAMPR_CAPS (SAMPR_CAP_32 | SAMPR_CAP_48 | SAMPR_CAP_44) 60 - #define MPEG1_BITR_CAPS (MP3_BITR_CAP_32 | MP3_BITR_CAP_40 | MP3_BITR_CAP_48 | \ 61 - MP3_BITR_CAP_56 | MP3_BITR_CAP_64 | MP3_BITR_CAP_80 | \ 62 - MP3_BITR_CAP_96 | MP3_BITR_CAP_112 | MP3_BITR_CAP_128 | \ 63 - MP3_BITR_CAP_160 | MP3_BITR_CAP_192 | MP3_BITR_CAP_224 | \ 62 + #define MPEG1_BITR_CAPS (MP3_BITR_CAP_32 | MP3_BITR_CAP_40 | \ 63 + MP3_BITR_CAP_48 | MP3_BITR_CAP_56 | \ 64 + MP3_BITR_CAP_64 | MP3_BITR_CAP_80 | \ 65 + MP3_BITR_CAP_96 | MP3_BITR_CAP_112 | \ 66 + MP3_BITR_CAP_128 | MP3_BITR_CAP_160 | \ 67 + MP3_BITR_CAP_192 | MP3_BITR_CAP_224 | \ 64 68 MP3_BITR_CAP_256 | MP3_BITR_CAP_320) 65 69 66 70 /* MPEG 2 */ 67 71 #define MPEG2_SAMPR_CAPS (SAMPR_CAP_22 | SAMPR_CAP_24 | SAMPR_CAP_16) 68 - #define MPEG2_BITR_CAPS (MP3_BITR_CAP_8 | MP3_BITR_CAP_16 | MP3_BITR_CAP_24 | \ 69 - MP3_BITR_CAP_32 | MP3_BITR_CAP_40 | MP3_BITR_CAP_48 | \ 70 - MP3_BITR_CAP_56 | MP3_BITR_CAP_64 | MP3_BITR_CAP_80 | \ 71 - MP3_BITR_CAP_96 | MP3_BITR_CAP_112 | MP3_BITR_CAP_128 | \ 72 + #define MPEG2_BITR_CAPS (MP3_BITR_CAP_8 | MP3_BITR_CAP_16 | \ 73 + MP3_BITR_CAP_24 | MP3_BITR_CAP_32 | \ 74 + MP3_BITR_CAP_40 | MP3_BITR_CAP_48 | \ 75 + MP3_BITR_CAP_56 | MP3_BITR_CAP_64 | \ 76 + MP3_BITR_CAP_80 | MP3_BITR_CAP_96 | \ 77 + MP3_BITR_CAP_112 | MP3_BITR_CAP_128 | \ 72 78 MP3_BITR_CAP_144 | MP3_BITR_CAP_160) 73 79 74 80 #if 0 ··· 131 137 #endif 132 138 }; 133 139 140 + /* General config information about any encoder */ 134 141 struct encoder_config 135 142 { 136 143 union ··· 149 156 }; 150 157 151 158 /** Encoder chunk macros and definitions **/ 152 - #define CHUNKF_START_FILE 0x0001ul /* This chunk starts a new file */ 153 - #define CHUNKF_END_FILE 0x0002ul /* This chunk ends the current file */ 154 - #define CHUNKF_PRERECORD 0x0010ul /* This chunk is prerecord data, 155 - a new file could start anytime */ 156 - #define CHUNKF_ABORT 0x0020ul /* Encoder should not finish this 157 - chunk */ 158 - #define CHUNKF_ERROR (~0ul ^ (~0ul >> 1)) /* An error has occured 159 - (passed to/from encoder). Use the 160 - sign bit to check (long)flags < 0. */ 161 - #define CHUNKF_ALLFLAGS (0x0033ul | CHUNKF_ERROR) 162 159 163 - /* Header at the beginning of every encoder chunk */ 164 - #ifdef DEBUG 165 - #define H_TO_BE32 htobe32 166 - #define ENC_CHUNK_MAGIC H_TO_BE32(('P' << 24) | ('T' << 16) | ('Y' << 8) | 'R') 167 - #endif 168 - struct enc_chunk_hdr 160 + /* What sort of data does the header describe? */ 161 + enum CHUNK_T 169 162 { 170 - #ifdef DEBUG 171 - unsigned long id; /* overflow detection - 'PTYR' - acronym for 172 - "PTYR Tells You Right" ;) */ 173 - #endif 174 - unsigned long flags; /* in/out: flags used by encoder and file 175 - writing */ 176 - size_t enc_size; /* out: amount of encoder data written to 177 - chunk */ 178 - unsigned long num_pcm; /* out: number of PCM samples eaten during 179 - processing 180 - (<= size of allocated buffer) */ 181 - unsigned char *enc_data; /* out: pointer to enc_size_written bytes 182 - of encoded audio data in chunk */ 183 - /* Encoder defined data follows header. Can be audio data + any other 184 - stuff the encoder needs to handle on a per chunk basis */ 163 + CHUNK_T_DATA = 0x0, /* Encoded audio data */ 164 + CHUNK_T_STREAM_START = 0x1, /* Stream start marker */ 165 + CHUNK_T_STREAM_END = 0x2, /* Stream end marker */ 166 + CHUNK_T_WRAP = 0x3 /* Buffer early wrap marker */ 185 167 }; 186 168 187 - /* Paranoia: be sure header size is 4-byte aligned */ 188 - #define ENC_CHUNK_HDR_SIZE \ 189 - ALIGN_UP_P2(sizeof (struct enc_chunk_hdr), 2) 190 - /* Skip the chunk header and return data */ 191 - #define ENC_CHUNK_SKIP_HDR(t, hdr) \ 192 - ((typeof (t))((char *)hdr + ENC_CHUNK_HDR_SIZE)) 193 - /* Cast p to struct enc_chunk_hdr * */ 194 - #define ENC_CHUNK_HDR(p) \ 195 - ((struct enc_chunk_hdr *)(p)) 196 - 197 - enum enc_events 169 + /* Header for every buffer slot and chunk */ 170 + union enc_chunk_hdr 198 171 { 199 - /* File writing events - data points to enc_file_event_data */ 200 - ENC_START_FILE = 0, /* a new file has been opened and no data has yet 201 - been written */ 202 - ENC_WRITE_CHUNK, /* write the current chunk to disk */ 203 - ENC_END_FILE, /* current file about to be closed and all valid 204 - data has been written */ 205 - /* Encoder buffer events - data points to enc_buffer_event_data */ 206 - ENC_REC_NEW_STREAM, /* Take steps to finish current stream and start 207 - new */ 208 - }; 172 + struct 173 + { 174 + uint32_t type : 2; /* Chunk type (CHUNK_T_*) */ 175 + uint32_t err : 1; /* Encoder error */ 176 + uint32_t pre : 1; /* Chunk is prerecorded data */ 177 + uint32_t aux0 : 1; /* Aux flag 0 - for encoder */ 178 + uint32_t unused : 3; /* */ 179 + uint32_t size : 24; /* size of data */ 180 + }; 181 + uint32_t zero; /* Zero-out struct access */ 182 + intptr_t reserved1; /* Want it at least pointer-sized */ 183 + } __attribute__((__may_alias__)); 209 184 210 - /** 211 - * encoder can write extra data to the file such as headers or more encoded 212 - * samples and must update sizes and samples accordingly. 213 - */ 214 - struct enc_file_event_data 185 + #define ENC_HDR_SIZE (sizeof (union enc_chunk_hdr)) 186 + 187 + /* When hdr.type is CHUNK_T_STREAM_START */ 188 + struct enc_chunk_file 215 189 { 216 - struct enc_chunk_hdr *chunk; /* Current chunk */ 217 - size_t new_enc_size; /* New size of chunk */ 218 - unsigned long new_num_pcm; /* New number of pcm in chunk */ 219 - const char *filename; /* filename to open if ENC_START_FILE */ 220 - int rec_file; /* Current file or < 0 if none */ 221 - unsigned long num_pcm_samples; /* Current pcm sample count written to 222 - file so far. */ 223 - }; 190 + union enc_chunk_hdr hdr; /* This chunk's header */ 191 + /* hdr.size = slot count of chunk */ 192 + char path[]; /* NULL-terminated path of file */ 193 + } __attribute__((__may_alias__)); 194 + 195 + /* If flags = CHUNK_T_STREAM_END, just the header exists */ 224 196 225 - /** 226 - * encoder may add some data to the end of the last and start of the next 227 - * but must never yield when called so any encoding done should be absolutely 228 - * minimal. 229 - */ 230 - struct enc_buffer_event_data 197 + /* When hdr.type is CHUNK_T_DATA */ 198 + struct enc_chunk_data 231 199 { 232 - unsigned long flags; /* in: One or more of: 233 - * CHUNKF_PRERECORD 234 - * CHUNKF_END_FILE 235 - * CHUNKF_START_FILE 236 - */ 237 - struct enc_chunk_hdr *pre_chunk; /* in: pointer to first prerecord 238 - * chunk 239 - */ 240 - struct enc_chunk_hdr *chunk; /* in,out: chunk were split occurs - 241 - * first chunk of start 242 - */ 243 - }; 200 + union enc_chunk_hdr hdr; /* IN,OUT: This chunk's header */ 201 + /* hdr.size = total size of data[] */ 202 + uint32_t pcm_count; /* OUT: number of PCM samples encoded */ 203 + uint8_t data[]; /* OUT: encoded audio data */ 204 + } __attribute__((__may_alias__)); 205 + 206 + /* CHUNK_T_STREAM_END and CHUNK_T_WRAP consist of only the header */ 244 207 245 - /** Callbacks called by encoder codec **/ 208 + #define ENC_FILE_HDR(hdr) ((struct enc_chunk_file *)(hdr)) 209 + #define ENC_DATA_HDR(hdr) ((struct enc_chunk_data *)(hdr)) 246 210 247 - /* parameters passed to encoder by enc_get_inputs */ 211 + /* Audio and encoder stream parameters */ 248 212 struct enc_inputs 249 213 { 250 - unsigned long sample_rate; /* out - pcm frequency */ 251 - int num_channels; /* out - number of audio channels */ 252 - int rec_mono_mode; /* out - how to create mono */ 253 - struct encoder_config *config; /* out - encoder settings */ 214 + /* IN parameters */ 215 + unsigned long sample_rate; /* PCM samplerate setting */ 216 + int num_channels; /* Number of audio channels */ 217 + struct encoder_config *config; /* Encoder settings */ 218 + 219 + /* IN,OUT parameters */ 220 + unsigned long enc_sample_rate; /* Actual sample rate accepted by encoder 221 + (for recorded time calculation) */ 254 222 }; 255 223 256 - void enc_get_inputs(struct enc_inputs *inputs); 257 - 258 - /* parameters pass from encoder to enc_set_parameters */ 259 - struct enc_parameters 224 + enum enc_callback_reason 260 225 { 261 - /* IN parameters */ 262 - int afmt; /* AFMT_* id - sanity checker */ 263 - size_t chunk_size; /* max chunk size required */ 264 - unsigned long enc_sample_rate; /* actual sample rate used by encoder 265 - (for recorded time calculation) */ 266 - size_t reserve_bytes; /* number of bytes to reserve immediately 267 - following chunks */ 268 - void (*events_callback)(enum enc_events event, 269 - void *data); /* pointer to events callback */ 270 - /* OUT parameters */ 271 - unsigned char *enc_buffer; /* pointer to enc_buffer */ 272 - size_t buf_chunk_size; /* size of chunks in enc_buffer */ 273 - int num_chunks; /* number of chunks allotted to encoder */ 274 - unsigned char *reserve_buffer; /* pointer to reserve_bytes bytes */ 226 + ENC_CB_INPUTS, /* 'params' is struct enc_inputs * */ 227 + ENC_CB_STREAM, /* 'params' is union enc_chunk_hdr * */ 275 228 }; 276 229 277 - /* set the encoder dimensions - called by encoder codec at initialization 278 - and termination */ 279 - void enc_set_parameters(struct enc_parameters *params); 280 - /* returns pointer to next write chunk in circular buffer */ 281 - struct enc_chunk_hdr * enc_get_chunk(void); 282 - /* releases the current chunk into the available chunks */ 283 - void enc_finish_chunk(void); 284 - 285 - #define PCM_MAX_FEED_SIZE 20000 /* max pcm size passed to encoder */ 286 - 287 - /* passes a pointer to next chunk of unprocessed wav data */ 288 - unsigned char * enc_get_pcm_data(size_t size); 289 - /* puts some pcm data back in the queue */ 290 - size_t enc_unget_pcm_data(size_t size); 230 + typedef int (* enc_callback_t)(enum enc_callback_reason reason, void *params); 291 231 292 232 #endif /* ENC_BASE_H */
+129 -266
lib/rbcodec/codecs/aiff_enc.c
··· 8 8 * $Id$ 9 9 * 10 10 * Copyright (C) 2006 Antonius Hellmann 11 + * Copyright (C) 2006-2013 Michael Sevakis 11 12 * 12 13 * This program is free software; you can redistribute it and/or 13 14 * modify it under the terms of the GNU General Public License ··· 47 48 #define PCM_DEPTH_BYTES 2 48 49 #define PCM_DEPTH_BITS 16 49 50 #define PCM_SAMP_PER_CHUNK 2048 50 - #define PCM_CHUNK_SIZE (PCM_SAMP_PER_CHUNK*4) 51 + 52 + static int num_channels; 53 + static uint32_t sample_rate; 54 + static size_t frame_size; 55 + static size_t pcm_size; 56 + static uint32_t num_sample_frames; 51 57 52 58 /* Template headers */ 53 - struct aiff_header aiff_header = 59 + static const struct aiff_header aiff_template_header = 54 60 { 55 61 { 'F', 'O', 'R', 'M' }, /* form_id */ 56 62 0, /* form_size (*) */ ··· 65 71 0, /* ssnd_size (*) */ 66 72 htobe32(0), /* offset */ 67 73 htobe32(0), /* block_size */ 74 + /* (*) updated when finalizing stream */ 68 75 }; 69 76 70 - /* (*) updated when finalizing file */ 71 - 72 - static int num_channels IBSS_ATTR; 73 - static int rec_mono_mode IBSS_ATTR; 74 - static uint32_t sample_rate; 75 - static uint32_t enc_size; 76 - static int32_t err IBSS_ATTR; 77 + static inline void frame_htobe(uint32_t *p, size_t size) 78 + { 79 + #ifdef ROCKBOX_LITTLE_ENDIAN 80 + /* Byte-swap samples, stereo or mono */ 81 + do 82 + { 83 + uint32_t t; 84 + t = swap_odd_even32(*p); *p++ = t; 85 + t = swap_odd_even32(*p); *p++ = t; 86 + t = swap_odd_even32(*p); *p++ = t; 87 + t = swap_odd_even32(*p); *p++ = t; 88 + t = swap_odd_even32(*p); *p++ = t; 89 + t = swap_odd_even32(*p); *p++ = t; 90 + t = swap_odd_even32(*p); *p++ = t; 91 + t = swap_odd_even32(*p); *p++ = t; 92 + } 93 + while (size -= 8 * 2 * PCM_DEPTH_BYTES); 94 + #endif /* ROCKBOX_LITTLE_ENDIAN */ 95 + (void)p; (void)size; 96 + } 77 97 78 98 /* convert unsigned 32 bit value to 80-bit floating point number */ 79 99 static void uint32_h_to_ieee754_extended_be(uint8_t f[10], uint32_t l) 80 - ICODE_ATTR; 81 - static void uint32_h_to_ieee754_extended_be(uint8_t f[10], uint32_t l) 82 100 { 83 - int32_t exp; 84 - 85 101 ci->memset(f, 0, 10); 86 102 87 103 if (l == 0) 88 104 return; 89 105 90 - for (exp = 30; (l & (1ul << 31)) == 0; exp--) 91 - l <<= 1; 106 + int shift = __builtin_clz(l); 92 107 93 108 /* sign always zero - bit 79 */ 94 - /* exponent is 0-31 (normalized: 31 - shift + 16383) - bits 64-78 */ 109 + /* exponent is 0-31 (normalized: 30 - shift + 16383) - bits 64-78 */ 95 110 f[0] = 0x40; 96 - f[1] = (uint8_t)exp; 111 + f[1] = (uint8_t)(30 - shift); 97 112 /* mantissa is value left justified with most significant non-zero 98 113 bit stored in bit 63 - bits 0-63 */ 114 + l <<= shift; 99 115 f[2] = (uint8_t)(l >> 24); 100 116 f[3] = (uint8_t)(l >> 16); 101 117 f[4] = (uint8_t)(l >> 8); 102 118 f[5] = (uint8_t)(l >> 0); 103 - } /* uint32_h_to_ieee754_extended_be */ 119 + } 104 120 105 - /* called version often - inline */ 106 - static inline bool is_file_data_ok(struct enc_file_event_data *data) ICODE_ATTR; 107 - static inline bool is_file_data_ok(struct enc_file_event_data *data) 121 + static int on_stream_data(struct enc_chunk_data *data) 108 122 { 109 - return data->rec_file >= 0 && (long)data->chunk->flags >= 0; 110 - } /* is_file_data_ok */ 123 + size_t size = data->hdr.size; 111 124 112 - /* called version often - inline */ 113 - static inline bool on_write_chunk(struct enc_file_event_data *data) ICODE_ATTR; 114 - static inline bool on_write_chunk(struct enc_file_event_data *data) 115 - { 116 - if (!is_file_data_ok(data)) 117 - return false; 125 + if (ci->enc_stream_write(data->data, size) != (ssize_t)size) 126 + return -1; 118 127 119 - if (data->chunk->enc_data == NULL) 120 - { 121 - #ifdef ROCKBOX_HAS_LOGF 122 - ci->logf("aiff enc: NULL data"); 123 - #endif 124 - return true; 125 - } 128 + pcm_size += size; 129 + num_sample_frames += data->pcm_count; 126 130 127 - if (ci->write(data->rec_file, data->chunk->enc_data, 128 - data->chunk->enc_size) != (ssize_t)data->chunk->enc_size) 129 - return false; 130 - 131 - data->num_pcm_samples += data->chunk->num_pcm; 132 - return true; 133 - } /* on_write_chunk */ 131 + return 0; 132 + } 134 133 135 - static bool on_start_file(struct enc_file_event_data *data) 134 + static int on_stream_start(void) 136 135 { 137 - if ((data->chunk->flags & CHUNKF_ERROR) || *data->filename == '\0') 138 - return false; 139 - 140 - data->rec_file = ci->open(data->filename, O_RDWR|O_CREAT|O_TRUNC, 0666); 141 - 142 - if (data->rec_file < 0) 143 - return false; 144 - 145 136 /* reset sample count */ 146 - data->num_pcm_samples = 0; 137 + pcm_size = 0; 138 + num_sample_frames = 0; 147 139 148 - /* write template headers */ 149 - if (ci->write(data->rec_file, &aiff_header, sizeof (aiff_header)) 150 - != sizeof (aiff_header)) 151 - { 152 - return false; 153 - } 140 + /* write template header */ 141 + if (ci->enc_stream_write(&aiff_template_header, 142 + sizeof (struct aiff_header)) 143 + != sizeof (struct aiff_header)) 144 + return -1; 154 145 155 - data->new_enc_size += sizeof(aiff_header); 156 - return true; 157 - } /* on_start_file */ 146 + return 0; 147 + } 158 148 159 - static bool on_end_file(struct enc_file_event_data *data) 149 + static int on_stream_end(union enc_chunk_hdr *hdr) 160 150 { 161 - /* update template headers */ 162 - struct aiff_header hdr; 163 - uint32_t data_size; 164 - 165 - if (!is_file_data_ok(data)) 166 - return false; 151 + /* update template header */ 152 + struct aiff_header aiff; 167 153 168 - if (ci->lseek(data->rec_file, 0, SEEK_SET) != 0 || 169 - ci->read(data->rec_file, &hdr, sizeof (hdr)) != sizeof (hdr)) 154 + if (hdr->err) 170 155 { 171 - return false; 156 + /* Called for stream error; get correct data size */ 157 + ssize_t size = ci->enc_stream_lseek(0, SEEK_END); 158 + 159 + if (size > (ssize_t)sizeof (aiff)) 160 + { 161 + pcm_size = size - sizeof (aiff); 162 + num_sample_frames = pcm_size / (PCM_DEPTH_BYTES*num_channels); 163 + } 172 164 } 173 165 174 - data_size = data->num_pcm_samples*num_channels*PCM_DEPTH_BYTES; 166 + if (ci->enc_stream_lseek(0, SEEK_SET) != 0) 167 + return -1; 168 + 169 + if (ci->enc_stream_read(&aiff, sizeof (aiff)) != sizeof (aiff)) 170 + return -2; 175 171 176 172 /* 'FORM' chunk */ 177 - hdr.form_size = htobe32(data_size + sizeof (hdr) - 8); 173 + aiff.form_size = htobe32(pcm_size + sizeof (aiff) - 8); 178 174 179 175 /* 'COMM' chunk */ 180 - hdr.num_channels = htobe16(num_channels); 181 - hdr.num_sample_frames = htobe32(data->num_pcm_samples); 182 - uint32_h_to_ieee754_extended_be(hdr.sample_rate, sample_rate); 176 + aiff.num_channels = htobe16(num_channels); 177 + aiff.num_sample_frames = htobe32(num_sample_frames); 178 + uint32_h_to_ieee754_extended_be(aiff.sample_rate, sample_rate); 183 179 184 180 /* 'SSND' chunk */ 185 - hdr.ssnd_size = htobe32(data_size + 8); 181 + aiff.ssnd_size = htobe32(pcm_size + 8); 186 182 187 - if (ci->lseek(data->rec_file, 0, SEEK_SET) != 0 || 188 - ci->write(data->rec_file, &hdr, sizeof (hdr)) != sizeof (hdr) || 189 - ci->close(data->rec_file) != 0) 190 - { 191 - return false; 192 - } 183 + if (ci->enc_stream_lseek(0, SEEK_SET) != 0) 184 + return -3; 193 185 194 - data->rec_file = -1; 186 + if (ci->enc_stream_write(&aiff, sizeof (aiff)) != sizeof (aiff)) 187 + return -4; 195 188 196 - return true; 197 - } /* on_end_file */ 189 + return 0; 190 + } 198 191 199 - static void enc_events_callback(enum enc_events event, void *data) 200 - ICODE_ATTR; 201 - static void enc_events_callback(enum enc_events event, void *data) 192 + /* this is the codec entry point */ 193 + enum codec_status codec_main(enum codec_entry_call_reason reason) 202 194 { 203 - switch (event) 204 - { 205 - case ENC_WRITE_CHUNK: 206 - if (on_write_chunk((struct enc_file_event_data *)data)) 207 - return; 208 - 209 - break; 210 - 211 - case ENC_START_FILE: 212 - if (on_start_file((struct enc_file_event_data *)data)) 213 - return; 214 - 215 - break; 216 - 217 - case ENC_END_FILE: 218 - if (on_end_file((struct enc_file_event_data *)data)) 219 - return; 220 - 221 - break; 195 + return CODEC_OK; 196 + (void)reason; 197 + } 222 198 223 - default: 224 - return; 225 - } 226 - 227 - /* Something failed above. Signal error back to core. */ 228 - ((struct enc_file_event_data *)data)->chunk->flags |= CHUNKF_ERROR; 229 - } /* enc_events_callback */ 230 - 231 - /* convert native pcm samples to aiff format samples */ 232 - static inline void sample_to_mono(uint32_t **src, uint32_t **dst) 199 + /* this is called for each file to process */ 200 + enum codec_status ICODE_ATTR codec_run(void) 233 201 { 234 - int32_t lr1, lr2; 202 + enum { GETBUF_ENC, GETBUF_PCM } getbuf = GETBUF_ENC; 203 + struct enc_chunk_data *data = NULL; 235 204 236 - switch(rec_mono_mode) 205 + /* main encoding loop */ 206 + while (1) 237 207 { 238 - case 1: 239 - /* mono = L */ 240 - lr1 = *(*src)++; 241 - lr1 = lr1 >> 16; 242 - lr2 = *(*src)++; 243 - lr2 = lr2 >> 16; 244 - break; 245 - case 2: 246 - /* mono = R */ 247 - lr1 = *(*src)++; 248 - lr1 = (int16_t)lr1; 249 - lr2 = *(*src)++; 250 - lr2 = (int16_t)lr2; 251 - break; 252 - case 0: 253 - default: 254 - /* mono = (L+R)/2 */ 255 - lr1 = *(*src)++; 256 - lr1 = (int16_t)lr1 + (lr1 >> 16) + err; 257 - err = lr1 & 1; 258 - lr1 >>= 1; 208 + enum codec_command_action action = ci->get_command(NULL); 259 209 260 - lr2 = *(*src)++; 261 - lr2 = (int16_t)lr2 + (lr2 >> 16) + err; 262 - err = lr2 & 1; 263 - lr2 >>= 1; 210 + if (action != CODEC_ACTION_NULL) 264 211 break; 265 - } 266 - *(*dst)++ = htobe32((lr1 << 16) | (uint16_t)lr2); 267 - } /* sample_to_mono */ 268 212 269 - static void chunk_to_aiff_format(uint32_t *src, uint32_t *dst) ICODE_ATTR; 270 - static void chunk_to_aiff_format(uint32_t *src, uint32_t *dst) 271 - { 272 - if (num_channels == 1) 273 - { 274 - /* On big endian: 275 - * |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| 276 - * |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| => 277 - * |MMMMMMMMmmmmmmmm|MMMMMMMMmmmmmmmm| 278 - * 279 - * On little endian: 280 - * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| 281 - * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| => 282 - * |MMMMMMMMmmmmmmmm|MMMMMMMMmmmmmmmm| 283 - */ 284 - uint32_t *src_end = src + PCM_SAMP_PER_CHUNK; 285 - 286 - do 213 + /* First obtain output buffer; when available, get PCM data */ 214 + switch (getbuf) 287 215 { 288 - sample_to_mono(&src, &dst); 289 - sample_to_mono(&src, &dst); 290 - sample_to_mono(&src, &dst); 291 - sample_to_mono(&src, &dst); 292 - sample_to_mono(&src, &dst); 293 - sample_to_mono(&src, &dst); 294 - sample_to_mono(&src, &dst); 295 - sample_to_mono(&src, &dst); 216 + case GETBUF_ENC: 217 + if (!(data = ci->enc_encbuf_get_buffer(frame_size))) 218 + continue; 219 + getbuf = GETBUF_PCM; 220 + case GETBUF_PCM: 221 + if (!ci->enc_pcmbuf_read(data->data, PCM_SAMP_PER_CHUNK)) 222 + continue; 223 + getbuf = GETBUF_ENC; 296 224 } 297 - while (src < src_end); 298 - } 299 - else 300 - { 301 - #ifdef ROCKBOX_BIG_ENDIAN 302 - /* |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| => 303 - * |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| 304 - */ 305 - ci->memcpy(dst, src, PCM_CHUNK_SIZE); 306 - #else 307 - /* |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| => 308 - * |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| 309 - */ 310 - uint32_t *src_end = src + PCM_SAMP_PER_CHUNK; 311 225 312 - do 313 - { 314 - *dst++ = swap_odd_even32(*src++); 315 - *dst++ = swap_odd_even32(*src++); 316 - *dst++ = swap_odd_even32(*src++); 317 - *dst++ = swap_odd_even32(*src++); 318 - *dst++ = swap_odd_even32(*src++); 319 - *dst++ = swap_odd_even32(*src++); 320 - *dst++ = swap_odd_even32(*src++); 321 - *dst++ = swap_odd_even32(*src++); 322 - } 323 - while (src < src_end); 324 - #endif 325 - } 326 - } /* chunk_to_aiff_format */ 226 + data->hdr.size = frame_size; 227 + data->pcm_count = PCM_SAMP_PER_CHUNK; 327 228 328 - static bool init_encoder(void) 329 - { 330 - struct enc_inputs inputs; 331 - struct enc_parameters params; 229 + frame_htobe((uint32_t *)data->data, frame_size); 332 230 333 - if (ci->enc_get_inputs == NULL || 334 - ci->enc_set_parameters == NULL || 335 - ci->enc_get_chunk == NULL || 336 - ci->enc_finish_chunk == NULL || 337 - ci->enc_get_pcm_data == NULL ) 338 - return false; 339 - 340 - ci->enc_get_inputs(&inputs); 341 - 342 - if (inputs.config->afmt != AFMT_AIFF) 343 - return false; 344 - 345 - sample_rate = inputs.sample_rate; 346 - num_channels = inputs.num_channels; 347 - rec_mono_mode = inputs.rec_mono_mode; 348 - err = 0; 349 - 350 - /* configure the buffer system */ 351 - params.afmt = AFMT_AIFF; 352 - enc_size = PCM_CHUNK_SIZE*inputs.num_channels / 2; 353 - params.chunk_size = enc_size; 354 - params.enc_sample_rate = sample_rate; 355 - params.reserve_bytes = 0; 356 - params.events_callback = enc_events_callback; 357 - ci->enc_set_parameters(&params); 358 - 359 - return true; 360 - } /* init_encoder */ 361 - 362 - /* this is the codec entry point */ 363 - enum codec_status codec_main(enum codec_entry_call_reason reason) 364 - { 365 - if (reason == CODEC_LOAD) { 366 - if (!init_encoder()) 367 - return CODEC_ERROR; 368 - } 369 - else if (reason == CODEC_UNLOAD) { 370 - /* reset parameters to initial state */ 371 - ci->enc_set_parameters(NULL); 231 + ci->enc_pcmbuf_advance(PCM_SAMP_PER_CHUNK); 232 + ci->enc_encbuf_finish_buffer(); 372 233 } 373 234 374 235 return CODEC_OK; 375 236 } 376 237 377 - /* this is called for each file to process */ 378 - enum codec_status codec_run(void) 238 + /* this is called by recording system */ 239 + int ICODE_ATTR enc_callback(enum enc_callback_reason reason, 240 + void *params) 379 241 { 380 - /* main encoding loop */ 381 - while (ci->get_command(NULL) != CODEC_ACTION_HALT) 242 + if (LIKELY(reason == ENC_CB_STREAM)) 243 + { 244 + switch (((union enc_chunk_hdr *)params)->type) 245 + { 246 + case CHUNK_T_DATA: 247 + return on_stream_data(params); 248 + case CHUNK_T_STREAM_START: 249 + return on_stream_start(); 250 + case CHUNK_T_STREAM_END: 251 + return on_stream_end(params); 252 + } 253 + } 254 + else if (reason == ENC_CB_INPUTS) 382 255 { 383 - uint32_t *src = (uint32_t *)ci->enc_get_pcm_data(PCM_CHUNK_SIZE); 384 - struct enc_chunk_hdr *chunk; 385 - 386 - if (src == NULL) 387 - continue; 388 - 389 - chunk = ci->enc_get_chunk(); 390 - chunk->enc_size = enc_size; 391 - chunk->num_pcm = PCM_SAMP_PER_CHUNK; 392 - chunk->enc_data = ENC_CHUNK_SKIP_HDR(chunk->enc_data, chunk); 393 - 394 - chunk_to_aiff_format(src, (uint32_t *)chunk->enc_data); 395 - 396 - ci->enc_finish_chunk(); 256 + struct enc_inputs *inputs = params; 257 + sample_rate = inputs->sample_rate; 258 + num_channels = inputs->num_channels; 259 + frame_size = PCM_SAMP_PER_CHUNK*PCM_DEPTH_BYTES*num_channels; 397 260 } 398 261 399 - return CODEC_OK; 262 + return 0; 400 263 }
+25 -20
lib/rbcodec/codecs/codecs.h
··· 36 36 #endif 37 37 #if (CONFIG_CODEC == SWCODEC) 38 38 #ifdef HAVE_RECORDING 39 - #include "pcm_record.h" 39 + #include "enc_base.h" 40 40 #endif 41 41 #include "dsp_core.h" 42 42 #include "dsp_misc.h" ··· 72 72 #define CODEC_ENC_MAGIC 0x52454E43 /* RENC */ 73 73 74 74 /* increase this every time the api struct changes */ 75 - #define CODEC_API_VERSION 45 75 + #define CODEC_API_VERSION 46 76 76 77 77 /* update this to latest version if a change to the api struct breaks 78 78 backwards compatibility (and please take the opportunity to sort in any 79 79 new function which are "waiting" at the end of the function table) */ 80 - #define CODEC_MIN_API_VERSION 45 80 + #define CODEC_MIN_API_VERSION 46 81 81 82 82 /* reasons for calling codec main entrypoint */ 83 83 enum codec_entry_call_reason { ··· 96 96 CODEC_ACTION_HALT = -1, 97 97 CODEC_ACTION_NULL = 0, 98 98 CODEC_ACTION_SEEK_TIME = 1, 99 + #ifdef HAVE_RECORDING 100 + CODEC_ACTION_STREAM_FINISH = 2, 101 + #endif 99 102 }; 100 103 101 104 /* NOTE: To support backwards compatibility, only add new functions at ··· 200 203 #endif 201 204 202 205 #ifdef HAVE_RECORDING 203 - void (*enc_get_inputs)(struct enc_inputs *inputs); 204 - void (*enc_set_parameters)(struct enc_parameters *params); 205 - struct enc_chunk_hdr * (*enc_get_chunk)(void); 206 - void (*enc_finish_chunk)(void); 207 - unsigned char * (*enc_get_pcm_data)(size_t size); 208 - size_t (*enc_unget_pcm_data)(size_t size); 209 - 210 - /* file */ 211 - int (*open)(const char* pathname, int flags, ...); 212 - int (*close)(int fd); 213 - ssize_t (*read)(int fd, void* buf, size_t count); 214 - off_t (*lseek)(int fd, off_t offset, int whence); 215 - ssize_t (*write)(int fd, const void* buf, size_t count); 206 + int (*enc_pcmbuf_read)(void *buf, int count); 207 + int (*enc_pcmbuf_advance)(int count); 208 + struct enc_chunk_data * (*enc_encbuf_get_buffer)(size_t need); 209 + void (*enc_encbuf_finish_buffer)(void); 210 + ssize_t (*enc_stream_read)(void *buf, size_t count); 211 + off_t (*enc_stream_lseek)(off_t offset, int whence); 212 + ssize_t (*enc_stream_write)(const void *buf, size_t count); 216 213 int (*round_value_to_list32)(unsigned long value, 217 214 const unsigned long list[], 218 215 int count, 219 216 bool signd); 220 - #endif 217 + #endif /* HAVE_RECORDING */ 221 218 222 219 /* new stuff at the end, sort into place next time 223 220 the API gets incompatible */ ··· 229 226 enum codec_status(*entry_point)(enum codec_entry_call_reason reason); 230 227 enum codec_status(*run_proc)(void); 231 228 struct codec_api **api; 229 + void * rec_extension[]; /* extension for encoders */ 232 230 }; 233 231 234 232 #ifdef CODEC ··· 249 247 __attribute__ ((section (".header")))= { \ 250 248 { CODEC_ENC_MAGIC, TARGET_ID, CODEC_API_VERSION, \ 251 249 plugin_start_addr, plugin_end_addr }, codec_start, \ 252 - codec_run, &ci }; 250 + codec_run, &ci, { enc_callback } }; 253 251 254 252 #else /* def SIMULATOR */ 255 253 /* decoders */ ··· 262 260 #define CODEC_ENC_HEADER \ 263 261 const struct codec_header __header = { \ 264 262 { CODEC_ENC_MAGIC, TARGET_ID, CODEC_API_VERSION, NULL, NULL }, \ 265 - codec_start, codec_run, &ci }; 263 + codec_start, codec_run, &ci, { enc_callback } }; 266 264 #endif /* SIMULATOR */ 267 265 #endif /* CODEC */ 268 266 ··· 277 275 int codec_load_buf(int hid, struct codec_api *api); 278 276 int codec_load_file(const char* codec, struct codec_api *api); 279 277 int codec_run_proc(void); 280 - int codec_halt(void); 281 278 int codec_close(void); 279 + #if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) 280 + enc_callback_t codec_get_enc_callback(void); 281 + #else 282 + #define codec_get_enc_callback() NULL 283 + #endif 282 284 283 285 /* defined by the codec */ 284 286 enum codec_status codec_start(enum codec_entry_call_reason reason); 285 287 enum codec_status codec_main(enum codec_entry_call_reason reason); 286 288 enum codec_status codec_run(void); 289 + #if CONFIG_CODEC == SWCODEC && defined(HAVE_RECORDING) 290 + int enc_callback(enum enc_callback_reason reason, void *params); 291 + #endif 287 292 288 293 #endif /* _CODECS_H_ */
+428 -379
lib/rbcodec/codecs/mp3_enc.c
··· 8 8 * $Id$ 9 9 * 10 10 * Copyright (C) 2006 Antonius Hellmann 11 + * Copyright (C) 2006-2013 Michael Sevakis 11 12 * 12 13 * This program is free software; you can redistribute it and/or 13 14 * modify it under the terms of the GNU General Public License ··· 37 38 38 39 CODEC_ENC_HEADER 39 40 40 - #define ENC_PADDING_FRAMES1 2 41 - #define ENC_PADDING_FRAMES2 4 42 - #define ENC_DELAY_SAMP 576 43 - #define ENC_DELAY_SIZE (ENC_DELAY_SAMP*4) 44 - #define SAMP_PER_FRAME1 1152 45 - #define SAMP_PER_FRAME2 576 46 - #define PCM_CHUNK_SIZE1 (SAMP_PER_FRAME1*4) 47 - #define PCM_CHUNK_SIZE2 (SAMP_PER_FRAME2*4) 48 - #define SAMPL2 576 49 - #define SBLIMIT 32 50 - #define HTN 16 41 + #define SAMPL2 576 42 + #define SBLIMIT 32 43 + #define HTN 16 51 44 #define memcpy ci->memcpy 52 45 #define memset ci->memset 53 46 #define putlong(c, s) if(s+sz <= 32) { cc = (cc << s) | c; sz+= s; } \ ··· 79 72 } side_info_t; 80 73 81 74 typedef struct { 82 - side_info_t cod_info[2][2]; 83 - mpeg_t mpg; 84 - long frac_per_frame; 85 - long byte_per_frame; 86 - long slot_lag; 87 - int sideinfo_len; 88 - int mean_bits; 89 - int ResvSize; 90 - int channels; 91 - int rec_mono_mode; 92 - int granules; 93 - long samplerate; 75 + side_info_t cod_info[2][2]; 76 + mpeg_t mpg; 77 + long frac_per_frame; 78 + long byte_per_frame; 79 + long req_byte_per_frame; 80 + long slot_lag; 81 + int sideinfo_len; 82 + int mean_bits; 83 + int ResvSize; 84 + int channels; 85 + int granules; 86 + long src_samplerate; 87 + long samplerate; 88 + short *samp_buffer; 89 + unsigned samp_per_frame; 90 + int flush_frames; 91 + int delay; 92 + int padding; 94 93 } config_t; 95 94 96 95 typedef struct { ··· 118 117 #define shft_n(x,n) ((x) >> n) 119 118 #define SQRT 724 /* sqrt(2) * 512 */ 120 119 121 - static short mfbuf [2*(1152+512)] IBSS_ATTR; /* 3328 Bytes */ 120 + static short mfbuf [2*(1152+512)] IBSS_ATTR 121 + /* for memcpy and 32-bit access */ MEM_ALIGN_ATTR; /* 3328 Bytes */ 122 122 static int sb_data [2][2][18][SBLIMIT] IBSS_ATTR; /* 13824 Bytes */ 123 123 static int mdct_freq [SAMPL2] IBSS_ATTR; /* 2304 Bytes */ 124 124 static char mdct_sign [SAMPL2] IBSS_ATTR; /* 576 Bytes */ ··· 171 171 static uint8_t t24l [256] IBSS_ATTR; 172 172 static struct huffcodetab ht [HTN] IBSS_ATTR; 173 173 174 - static unsigned pcm_chunk_size IBSS_ATTR; 175 - static unsigned samp_per_frame IBSS_ATTR; 176 - 177 174 static config_t cfg IBSS_ATTR; 178 - static char *res_buffer; 179 - static int32_t err IBSS_ATTR; 180 175 static uint8_t band_scale_f[22]; 181 176 182 177 static const uint8_t ht_count_const[2][2][16] = ··· 848 843 static int count_bigv ( short *ix, uint32_t start, uint32_t end, int table0, int table1, 849 844 int *bits); 850 845 846 + static inline uint32_t encodeHeader( int padding, long bitr_id ) 847 + { 848 + /* 849 + * MPEG header layout: 850 + * AAAAAAAA AAABBCCD EEEEFFGH IIJJKLMM 851 + * A (31-21) = frame sync 852 + * B (20-19) = MPEG type 853 + * C (18-17) = MPEG layer 854 + * D (16) = protection bit 855 + * E (15-12) = bitrate index 856 + * F (11-10) = samplerate index 857 + * G (9) = padding bit 858 + * H (8) = private bit 859 + * I (7-6) = channel mode 860 + * J (5-4) = mode extension (jstereo only) 861 + * K (3) = copyright bit 862 + * L (2) = original 863 + * M (1-0) = emphasis 864 + */ 865 + return (0xffe00000 ) /* frame sync (AAAAAAAAA AAA) */ 866 + | (0x2 << 19) /* mp3 type (upper): 1 (BB) */ 867 + | (cfg.mpg.type << 19) 868 + | (0x1 << 17) /* mp3 layer: 01 (CC) */ 869 + | (0x1 << 16) /* mp3 crc: 1 (D) */ 870 + | (bitr_id << 12) 871 + | (cfg.mpg.smpl_id << 10) 872 + | (padding << 9) 873 + | (cfg.mpg.mode << 6) 874 + | (0x1 << 2); /* mp3 org: 1 (L) */ 875 + /* no emphasis (bits 0-1) */ 876 + } 851 877 878 + static long calcFrameSize(int bitr_id, long *frac) 879 + { 880 + unsigned long v = bitr_index[cfg.mpg.type][bitr_id]; 881 + v = SAMPL2 * 16000 * v / (2 - cfg.mpg.type); 882 + v /= cfg.samplerate; 883 + 884 + if (frac) 885 + *frac = v % 64; 886 + 887 + return v / 64; 888 + 889 + } 852 890 static void encodeSideInfo( side_info_t si[2][2] ) 853 891 { 854 - int gr, ch, header; 892 + int gr, ch; 855 893 uint32_t cc=0, sz=0; 856 894 857 - /* 858 - * MPEG header layout: 859 - * AAAAAAAA AAABBCCD EEEEFFGH IIJJKLMM 860 - * A (31-21) = frame sync 861 - * B (20-19) = MPEG type 862 - * C (18-17) = MPEG layer 863 - * D (16) = protection bit 864 - * E (15-12) = bitrate index 865 - * F (11-10) = samplerate index 866 - * G (9) = padding bit 867 - * H (8) = private bit 868 - * I (7-6) = channel mode 869 - * J (5-4) = mode extension (jstereo only) 870 - * K (3) = copyright bit 871 - * L (2) = original 872 - * M (1-0) = emphasis 873 - */ 874 - 875 - header = (0xfff00000) | /* frame sync (AAAAAAAAA AAA) 876 - mp3 type (upper): 1 (B) */ 877 - (0x01 << 17) | /* mp3 layer: 01 (CC) */ 878 - ( 0x1 << 16) | /* mp3 crc: 1 (D) */ 879 - ( 0x1 << 2); /* mp3 org: 1 (L) */ 880 - header |= cfg.mpg.type << 19; 881 - header |= cfg.mpg.bitr_id << 12; 882 - header |= cfg.mpg.smpl_id << 10; 883 - header |= cfg.mpg.padding << 9; 884 - header |= cfg.mpg.mode << 6; 885 - /* no emphasis (bits 0-1) */ 886 - putbits( header, 32 ); 895 + putbits( encodeHeader( cfg.mpg.padding, cfg.mpg.bitr_id ), 32 ); 887 896 888 897 if(cfg.mpg.type == 1) 889 898 { /* MPEG1 */ ··· 1501 1510 1502 1511 1503 1512 /* returns sum_j=0^31 a[j]*cos(PI*j*(k+1/2)/32), 0<=k<32 */ 1504 - void window_subband1(short *wk, int sb0[SBLIMIT], int sb1[SBLIMIT]) ICODE_ATTR; 1505 - void window_subband1(short *wk, int sb0[SBLIMIT], int sb1[SBLIMIT]) 1513 + static void ICODE_ATTR window_subband1(short *wk, int sb0[SBLIMIT], 1514 + int sb1[SBLIMIT]) 1506 1515 { 1507 1516 int k, i, u, v; 1508 1517 short *wp, *x1, *x2; ··· 1761 1770 #endif 1762 1771 } 1763 1772 1764 - void window_subband2(short *x1, int a[SBLIMIT]) ICODE_ATTR; 1765 - void window_subband2(short *x1, int a[SBLIMIT]) 1773 + static void ICODE_ATTR window_subband2(short *x1, int a[SBLIMIT]) 1766 1774 { 1767 1775 int xr; 1768 1776 short *wp = enwindow; ··· 1879 1887 xr = a[29]; a[29] += a[ 2]; a[ 2] -= xr; 1880 1888 } 1881 1889 1882 - void mdct_long(int *out, int *in) ICODE_ATTR; 1883 - void mdct_long(int *out, int *in) 1890 + static void ICODE_ATTR mdct_long(int *out, int *in) 1884 1891 { 1885 1892 int ct,st; 1886 1893 int tc1, tc2, tc3, tc4, ts5, ts6, ts7, ts8; ··· 1969 1976 return i; 1970 1977 } 1971 1978 1972 - static bool init_mp3_encoder_engine(int sample_rate, 1973 - int num_channels, 1974 - int rec_mono_mode, 1975 - struct encoder_config *enc_cfg) 1979 + static void mp3_encoder_reset(void) 1980 + { 1981 + memset(&cfg.cod_info, 0, sizeof(cfg.cod_info)); 1982 + memset(mfbuf , 0, sizeof(mfbuf )); 1983 + memset(mdct_freq , 0, sizeof(mdct_freq )); 1984 + memset(enc_data , 0, sizeof(enc_data )); 1985 + memset(sb_data , 0, sizeof(sb_data )); 1986 + memset(&CodedData , 0, sizeof(CodedData )); 1987 + cfg.slot_lag = 0; 1988 + } 1989 + 1990 + static void mp3_encoder_init(unsigned long sample_rate, int num_channels, 1991 + unsigned long bitrate) 1976 1992 { 1977 - const bool stereo = num_channels > 1; 1978 - uint32_t avg_byte_per_frame; 1993 + mp3_encoder_reset(); 1979 1994 1980 - cfg.channels = stereo ? 2 : 1; 1981 - cfg.rec_mono_mode = rec_mono_mode; 1982 - cfg.mpg.mode = stereo ? 0 : 3; /* 0=stereo, 3=mono */ 1983 - cfg.mpg.smpl_id = find_samplerate_index(sample_rate, &cfg.mpg.type); 1984 - cfg.samplerate = sampr_index[cfg.mpg.type][cfg.mpg.smpl_id]; 1985 - cfg.mpg.bitr_id = find_bitrate_index(cfg.mpg.type, 1986 - enc_cfg->mp3_enc.bitrate, 1987 - stereo); 1988 - cfg.mpg.bitrate = bitr_index[cfg.mpg.type][cfg.mpg.bitr_id]; 1989 - cfg.mpg.num_bands = num_bands[stereo ? cfg.mpg.type : 2][cfg.mpg.bitr_id]; 1995 + const bool stereo = num_channels > 1; 1996 + cfg.channels = stereo ? 2 : 1; 1997 + cfg.mpg.mode = stereo ? 0 : 3; /* 0=stereo, 3=mono */ 1998 + cfg.mpg.smpl_id = find_samplerate_index(sample_rate, &cfg.mpg.type); 1999 + cfg.samplerate = sampr_index[cfg.mpg.type][cfg.mpg.smpl_id]; 2000 + cfg.src_samplerate = sample_rate; 2001 + cfg.mpg.bitr_id = find_bitrate_index(cfg.mpg.type, bitrate, stereo); 2002 + cfg.mpg.bitrate = bitr_index[cfg.mpg.type][cfg.mpg.bitr_id]; 2003 + cfg.mpg.num_bands = num_bands[stereo ? cfg.mpg.type : 2][cfg.mpg.bitr_id]; 1990 2004 1991 2005 if (cfg.mpg.type == 1) 1992 2006 { 1993 - cfg.granules = 2; 1994 - pcm_chunk_size = PCM_CHUNK_SIZE1; 1995 - samp_per_frame = SAMP_PER_FRAME1; 2007 + cfg.granules = 2; 2008 + cfg.samp_per_frame = 1152; 2009 + cfg.flush_frames = 2; 1996 2010 } 1997 2011 else 1998 2012 { 1999 - cfg.granules = 1; 2000 - pcm_chunk_size = PCM_CHUNK_SIZE2; 2001 - samp_per_frame = SAMP_PER_FRAME2; 2013 + cfg.granules = 1; 2014 + cfg.samp_per_frame = 576; 2015 + cfg.flush_frames = 3; 2002 2016 } 2003 2017 2018 + cfg.delay = 576-16; 2019 + cfg.padding = 3*576+16; 2020 + 2021 + cfg.samp_buffer = mfbuf + 2*512; 2022 + 2004 2023 memcpy(scalefac, sfBand[cfg.mpg.smpl_id + 3*cfg.mpg.type], sizeof(scalefac)); 2005 - memset(mfbuf , 0 , sizeof(mfbuf )); 2006 - memset(mdct_freq , 0 , sizeof(mdct_freq )); 2007 - memset(enc_data , 0 , sizeof(enc_data )); 2008 - memset(sb_data , 0 , sizeof(sb_data )); 2009 - memset(&CodedData, 0 , sizeof(CodedData )); 2010 2024 memcpy(ca , ca_const , sizeof(ca )); 2011 2025 memcpy(cs , cs_const , sizeof(cs )); 2012 2026 memcpy(cx , cx_const , sizeof(cx )); ··· 2052 2066 memcpy(t16l , t16l_const , sizeof(t16l )); 2053 2067 memcpy(t24l , t24l_const , sizeof(t24l )); 2054 2068 memcpy(ht , ht_const , sizeof(ht )); 2069 + memset(band_scale_f, 0 , sizeof(band_scale_f)); 2055 2070 2056 2071 ht[ 0].table = NULL; ht[ 0].hlen = NULL; /* Apparently not used */ 2057 2072 ht[ 1].table = t1HB; ht[ 1].hlen = t1l; ··· 2071 2086 ht[15].table = t15HB; ht[15].hlen = t15l; 2072 2087 2073 2088 /* Figure average number of 'bytes' per frame */ 2074 - avg_byte_per_frame = SAMPL2 * 16000 * cfg.mpg.bitrate / (2 - cfg.mpg.type); 2075 - avg_byte_per_frame = avg_byte_per_frame / cfg.samplerate; 2076 - cfg.byte_per_frame = avg_byte_per_frame / 64; 2077 - cfg.frac_per_frame = avg_byte_per_frame & 63; 2078 - cfg.slot_lag = 0; 2089 + cfg.byte_per_frame = calcFrameSize(cfg.mpg.bitr_id, &cfg.frac_per_frame); 2079 2090 cfg.sideinfo_len = 32 + (cfg.mpg.type ? (cfg.channels == 1 ? 136 : 256) 2080 2091 : (cfg.channels == 1 ? 72 : 136)); 2081 2092 2082 - return true; 2093 + cfg.req_byte_per_frame = ALIGN_UP(cfg.byte_per_frame + 1, 2094 + sizeof (uint32_t)); 2083 2095 } 2084 2096 2085 - static inline void to_mono(uint16_t **samp) 2086 - { 2087 - int16_t l = **samp; 2088 - int16_t r = *(*samp+1); 2089 - int32_t m; 2090 - 2091 - switch(cfg.rec_mono_mode) 2092 - { 2093 - case 1: 2094 - /* mono = L */ 2095 - m = l; 2096 - break; 2097 - case 2: 2098 - /* mono = R */ 2099 - m = r; 2100 - break; 2101 - case 0: 2102 - default: 2103 - /* mono = (L+R)/2 */ 2104 - m = l + r + err; 2105 - err = m & 1; 2106 - m >>= 1; 2107 - break; 2108 - } 2109 - *(*samp)++ = (uint16_t)m; 2110 - *(*samp)++ = (uint16_t)m; 2111 - } /* to_mono */ 2112 - 2113 - static void to_mono_mm(void) ICODE_ATTR; 2114 - static void to_mono_mm(void) 2115 - { 2116 - /* |llllllllllllllll|rrrrrrrrrrrrrrrr| => 2117 - * |mmmmmmmmmmmmmmmm|mmmmmmmmmmmmmmmm| 2118 - */ 2119 - uint16_t *samp = &mfbuf[2*512]; 2120 - uint16_t *samp_end = samp + 2*samp_per_frame; 2121 - 2122 - do 2123 - { 2124 - to_mono(&samp); 2125 - to_mono(&samp); 2126 - to_mono(&samp); 2127 - to_mono(&samp); 2128 - to_mono(&samp); 2129 - to_mono(&samp); 2130 - to_mono(&samp); 2131 - to_mono(&samp); 2132 - } 2133 - while (samp < samp_end); 2134 - } /* to_mono_mm */ 2135 - 2136 - #ifdef ROCKBOX_LITTLE_ENDIAN 2137 - /* Swaps a frame to big endian */ 2138 - static inline void byte_swap_frame32(uint32_t *dst, uint32_t *src, 2139 - size_t size) 2140 - { 2141 - uint32_t *src_end = SKIPBYTES(src, size); 2142 - 2143 - do 2144 - { 2145 - *dst++ = swap32(*src++); 2146 - *dst++ = swap32(*src++); 2147 - *dst++ = swap32(*src++); 2148 - *dst++ = swap32(*src++); 2149 - *dst++ = swap32(*src++); 2150 - *dst++ = swap32(*src++); 2151 - *dst++ = swap32(*src++); 2152 - *dst++ = swap32(*src++); 2153 - } 2154 - while(src < src_end); 2155 - } /* byte_swap_frame32 */ 2156 - #endif /* ROCKBOX_LITTLE_ENDIAN */ 2157 - 2158 2097 static void set_scale_facs(int *mdct_freq) 2159 2098 { 2160 2099 unsigned int i, is, ie, k, s; ··· 2188 2127 } 2189 2128 } 2190 2129 2191 - static void encode_frame(char *buffer, struct enc_chunk_hdr *chunk) 2192 - ICODE_ATTR; 2193 - static void encode_frame(char *buffer, struct enc_chunk_hdr *chunk) 2130 + static size_t ICODE_ATTR mp3_encoder_encode_frame(uint8_t *outbuf) 2194 2131 { 2195 - int gr, gr_cnt; 2196 - uint32_t max; 2132 + int gr, gr_cnt; 2133 + uint32_t max; 2197 2134 2198 2135 /* encode one mp3 frame in this loop */ 2199 2136 CodedData.bitpos = 0; ··· 2211 2148 - cfg.sideinfo_len) / cfg.granules / cfg.channels 2212 2149 - 42; // reserved for scale_facs 2213 2150 2214 - /* shift out old samples */ 2215 - memcpy(mfbuf, mfbuf + 2*cfg.granules*576, 4*512); 2216 - 2217 - if (chunk->flags & CHUNKF_START_FILE) 2218 - { 2219 - /* prefix silent samples for encoder delay */ 2220 - memset(mfbuf + 2*512, 0, ENC_DELAY_SIZE); 2221 - /* read new samples to iram for further processing */ 2222 - memcpy(mfbuf + 2*512 + ENC_DELAY_SIZE/2, 2223 - buffer, pcm_chunk_size - ENC_DELAY_SIZE); 2224 - chunk->num_pcm = samp_per_frame - ENC_DELAY_SAMP; 2225 - } 2226 - else 2227 - { 2228 - /* read new samples to iram for further processing */ 2229 - memcpy(mfbuf + 2*512, buffer, pcm_chunk_size); 2230 - chunk->num_pcm = samp_per_frame; 2231 - } 2232 - 2233 - if (cfg.channels == 1) 2234 - to_mono_mm(); 2235 - 2236 2151 cfg.ResvSize = 0; 2237 2152 gr_cnt = cfg.granules * cfg.channels; 2238 2153 CodedData.bitpos = cfg.sideinfo_len; /* leave space for mp3 header */ ··· 2366 2281 } 2367 2282 } 2368 2283 2369 - chunk->enc_size = cfg.byte_per_frame + cfg.mpg.padding; 2284 + /* shift out old samples */ 2285 + memmove(mfbuf, mfbuf + 2*cfg.granules*576, 4*512); 2370 2286 2371 2287 /* finish this chunk by adding sideinfo header data */ 2372 2288 CodedData.bitpos = 0; 2373 2289 encodeSideInfo( cfg.cod_info ); 2374 2290 2375 - #ifdef ROCKBOX_BIG_ENDIAN 2376 - /* copy chunk to enc_buffer */ 2377 - memcpy(chunk->enc_data, CodedData.bbuf, chunk->enc_size); 2291 + long size = cfg.byte_per_frame + cfg.mpg.padding; 2292 + 2293 + #ifdef ROCKBOX_LITTLE_ENDIAN 2294 + /* convert frame to big endian */ 2295 + const uint32_t *src = CodedData.bbuf; 2296 + uint32_t *dst = (uint32_t *)outbuf; 2297 + 2298 + for(long i = 0; i < size; i += sizeof(uint32_t)) 2299 + *dst++ = swap32(*src++); 2378 2300 #else 2379 - /* swap frame to big endian */ 2380 - byte_swap_frame32((uint32_t *)chunk->enc_data, CodedData.bbuf, chunk->enc_size); 2381 - #endif 2382 - } /* encode_frame */ 2301 + memcpy(outbuf, CodedData.bbuf, size); 2302 + #endif /* ROCKBOX_LITTLE_ENDIAN */ 2383 2303 2384 - /* called very often - inline */ 2385 - static inline bool is_file_data_ok(struct enc_file_event_data *filed) 2304 + return size; 2305 + } 2306 + 2307 + 2308 + /*======== Codec section ========*/ 2309 + 2310 + /* CRC code lovingly ripped from: 2311 + * github.com/CFR-maniac/lame/blob/master/libmp3lame/VbrTag.c */ 2312 + 2313 + /* Lookup table for fast CRC computation 2314 + * See 'crc_update_lookup' 2315 + * Uses the polynomial x^16+x^15+x^2+1 */ 2316 + static const uint16_t crc16_lookup[256] ICONST_ATTR = 2386 2317 { 2387 - return filed->rec_file >= 0 && (long)filed->chunk->flags >= 0; 2388 - } /* is_event_ok */ 2318 + 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 2319 + 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, 2320 + 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 2321 + 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, 2322 + 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, 2323 + 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 2324 + 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, 2325 + 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, 2326 + 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, 2327 + 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, 2328 + 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, 2329 + 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, 2330 + 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, 2331 + 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, 2332 + 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, 2333 + 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, 2334 + 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, 2335 + 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, 2336 + 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 2337 + 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, 2338 + 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 2339 + 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, 2340 + 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, 2341 + 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, 2342 + 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, 2343 + 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, 2344 + 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 2345 + 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, 2346 + 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, 2347 + 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, 2348 + 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, 2349 + 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 2350 + }; 2389 2351 2390 - static unsigned char mp3_data[16384] __attribute__((aligned(4))); 2391 - static unsigned int mp3_data_len; /* current data size in buffer */ 2352 + static ssize_t header_size; 2353 + static unsigned int mp3_crc16; 2392 2354 2393 - /* called very often - inline */ 2394 - static inline bool on_write_chunk(struct enc_file_event_data *data) 2355 + /* fast CRC-16 computation - uses table crc16_lookup 8*/ 2356 + static inline unsigned int crc_update_lookup(unsigned int value, 2357 + unsigned int crc) 2395 2358 { 2396 - if (!is_file_data_ok(data)) 2397 - return false; 2359 + unsigned int tmp = crc ^ value; 2360 + crc = (crc >> 8) ^ crc16_lookup[tmp & 0xff]; 2361 + return crc & 0xffff; 2362 + } 2398 2363 2399 - if (data->chunk->enc_data == NULL) 2400 - { 2401 - #ifdef ROCKBOX_HAS_LOGF 2402 - ci->logf("mp3 enc: NULL data"); 2403 - #endif 2404 - return true; 2405 - } 2364 + /* Calculate position of 'Info' header */ 2365 + static int get_info_offset(uint32_t header) 2366 + { 2367 + uint32_t type = (header & (0x3 << 19)) >> 19; 2368 + uint32_t mode = (header & (0x3 << 6)) >> 6; 2406 2369 2407 - /* if current chunk doesn't fit => write collected data */ 2408 - if (mp3_data_len + data->chunk->enc_size > sizeof(mp3_data)) 2409 - { 2410 - if (ci->write(data->rec_file, mp3_data, 2411 - mp3_data_len) != (ssize_t)mp3_data_len) 2412 - return false; 2370 + return type == 3 ? (mode == 3 ? 21 : 36) : (mode == 3 ? 13 : 21); 2371 + } 2413 2372 2414 - mp3_data_len = 0; 2415 - } 2373 + /* Write very basic 'Info' header with delay, padding and a bit of 2374 + * miscellaneous info. */ 2375 + static bool write_info_header(bool first_encode) 2376 + { 2377 + ssize_t size = cfg.byte_per_frame; 2416 2378 2417 - memcpy(mp3_data+mp3_data_len, data->chunk->enc_data, 2418 - data->chunk->enc_size); 2379 + /* By default the MP3 frame header for the info frame is the same as 2380 + unpadded audio frames */ 2381 + uint32_t header = encodeHeader(0, cfg.mpg.bitr_id); 2419 2382 2420 - mp3_data_len += data->chunk->enc_size; 2383 + int i = get_info_offset(header); 2421 2384 2422 - data->num_pcm_samples += data->chunk->num_pcm; 2423 - return true; 2424 - } /* on_write_chunk */ 2385 + if (i + 8 + 36 > size) 2386 + { 2387 + /* The default frame size too small so find the smallest one that 2388 + may accomodate it by increasing the bit rate for this empty 2389 + MP3 frame */ 2390 + int j; 2391 + for (j = cfg.mpg.bitr_id + 1; j < 15; j++) 2392 + { 2393 + size = calcFrameSize(j, NULL); 2425 2394 2426 - static bool on_start_file(struct enc_file_event_data *data) 2427 - { 2428 - if ((data->chunk->flags & CHUNKF_ERROR) || *data->filename == '\0') 2429 - return false; 2395 + if (size >= i + 8 + 36) 2396 + break; 2397 + } 2430 2398 2431 - data->rec_file = ci->open(data->filename, O_RDWR|O_CREAT|O_TRUNC, 0666); 2399 + if (j >= 15) 2400 + { 2401 + /* Shouldn't really happen but... */ 2402 + header_size = -1; 2403 + return true; 2404 + } 2432 2405 2433 - if (data->rec_file < 0) 2434 - return false; 2406 + header = encodeHeader(0, j); 2407 + /* Info offset won't change */ 2408 + } 2435 2409 2436 - /* reset sample count */ 2437 - data->num_pcm_samples = 0; 2410 + uint8_t frame[size]; 2411 + memset(frame, 0, size); 2438 2412 2439 - /* reset buffer write position */ 2440 - mp3_data_len = 0; 2413 + frame[0] = header >> 24; 2414 + frame[1] = header >> 16; 2415 + frame[2] = header >> 8; 2416 + frame[3] = header >> 0; 2441 2417 2442 - return true; 2443 - } /* on_start_file */ 2418 + /* 'Info' header (CBR 'Xing') */ 2419 + memcpy(&frame[i], "Info", 4); 2444 2420 2445 - static bool on_end_file(struct enc_file_event_data *data) 2446 - { 2447 - if (data->rec_file < 0) 2448 - return false; /* file already closed, nothing more we can do */ 2421 + /* flags = 0; Info contains no other sections and is 8 bytes */ 2449 2422 2450 - /* write the remaining mp3_data */ 2451 - if (ci->write(data->rec_file, mp3_data, mp3_data_len) 2452 - != (ssize_t)mp3_data_len) 2453 - return false; 2423 + /* Just mark the LAMEness to indicate header presence; we're not 2424 + actually _the_ LAME so 'rbshn' is the version we give */ 2425 + memcpy(&frame[i + 8], "LAMErbshn", 9); 2454 2426 2455 - /* reset buffer write position */ 2456 - mp3_data_len = 0; 2427 + /* Fill-in some info about us 2428 + * reference: http://gabriel.mp3-tech.org/mp3infotag.html 2429 + */ 2457 2430 2458 - /* always _try_ to write the file header, even on error */ 2459 - if (ci->close(data->rec_file) != 0) 2460 - return false; 2431 + /* Revision + VBR method: 2432 + * [7:4] = Revision (0 ??) 2433 + * [3:0] = VBR method (CBR) 2434 + */ 2435 + frame[i + 17] = (0 << 4) | (1 << 0); 2461 2436 2462 - data->rec_file = -1; 2437 + /* If first frame since encoder reset is long gone (not unlikely in 2438 + prerecording), then the delay is long passed and no trimming done 2439 + at the start */ 2440 + unsigned int delay = first_encode ? cfg.delay : 0; 2441 + unsigned int padding = cfg.padding; 2463 2442 2464 - return true; 2465 - } /* on_end_file */ 2443 + /* Delay and padding: 2444 + * [23:12] = delay 2445 + * [11: 0] = padding 2446 + */ 2447 + frame[i + 29] = delay >> 4; 2448 + frame[i + 30] = (delay << 4) | (padding >> 8); 2449 + frame[i + 31] = padding; 2466 2450 2467 - static void on_rec_new_stream(struct enc_buffer_event_data *data) 2468 - { 2469 - int num_frames = cfg.mpg.type == 1 ? 2470 - ENC_PADDING_FRAMES1 : ENC_PADDING_FRAMES2; 2451 + /* Misc: 2452 + * [7:6] = source frequency 2453 + * [ 5] = unwise settings (of course not :) 2454 + * [4:2] = stereo mode (mono or stereo) 2455 + * [1:0] = noise shaping (who knows, 0) 2456 + */ 2457 + uint8_t misc; 2471 2458 2472 - if (data->flags & CHUNKF_END_FILE) 2473 - { 2474 - /* add silent frames to end - encoder will also be flushed for start 2475 - of next file if any */ 2476 - memset(res_buffer, 0, pcm_chunk_size); 2459 + if (cfg.src_samplerate <= 32000) 2460 + misc = (0 << 6); 2461 + else if (cfg.src_samplerate <= 44100) 2462 + misc = (1 << 6); 2463 + else if (cfg.src_samplerate <= 48000) 2464 + misc = (2 << 6); 2465 + else /* > 48000 */ 2466 + misc = (3 << 6); 2477 2467 2478 - /* the initial chunk given for the end is at enc_wr_index */ 2479 - while (num_frames-- > 0) 2480 - { 2481 - data->chunk->enc_data = ENC_CHUNK_SKIP_HDR(data->chunk->enc_data, 2482 - data->chunk); 2468 + if (cfg.channels > 1) 2469 + misc |= (1 << 2); /* Stereo */ 2483 2470 2484 - encode_frame(res_buffer, data->chunk); 2485 - data->chunk->num_pcm = samp_per_frame; 2471 + frame[i + 32] = misc; 2486 2472 2487 - ci->enc_finish_chunk(); 2488 - data->chunk = ci->enc_get_chunk(); 2489 - } 2490 - } 2491 - else if (data->flags & CHUNKF_PRERECORD) 2473 + if (ci->enc_stream_write(frame, size) != size) 2492 2474 { 2493 - /* nothing to add and we cannot change prerecorded data */ 2475 + ci->enc_stream_lseek(0, SEEK_SET); 2476 + header_size = -1; 2477 + return false; 2494 2478 } 2495 - else if (data->flags & CHUNKF_START_FILE) 2496 - { 2497 - /* starting fresh ... be sure to flush encoder first */ 2498 - struct enc_chunk_hdr *chunk = ENC_CHUNK_HDR(res_buffer); 2499 2479 2500 - chunk->flags = 0; 2501 - chunk->enc_data = ENC_CHUNK_SKIP_HDR(chunk->enc_data, chunk); 2480 + header_size = size; 2481 + return true; 2482 + } 2502 2483 2503 - while (num_frames-- > 0) 2504 - { 2505 - memset(chunk->enc_data, 0, pcm_chunk_size); 2506 - encode_frame(chunk->enc_data, chunk); 2507 - } 2508 - } 2509 - } /* on_rec_new_stream */ 2510 - 2511 - static void enc_events_callback(enum enc_events event, void *data) 2484 + static inline int on_stream_data(struct enc_chunk_data *data) 2512 2485 { 2513 - switch (event) 2486 + ssize_t size = data->hdr.size; 2487 + 2488 + if (header_size > 0) 2514 2489 { 2515 - case ENC_WRITE_CHUNK: 2516 - if (on_write_chunk((struct enc_file_event_data *)data)) 2517 - return; 2490 + /* Header is layed-down; keep running CRC of audio data */ 2491 + uint8_t *p = data->data; 2492 + uint8_t *p_end = p + size; 2518 2493 2519 - break; 2494 + while (p < p_end) 2495 + mp3_crc16 = crc_update_lookup(*p++, mp3_crc16); 2496 + } 2520 2497 2521 - case ENC_START_FILE: 2522 - if (on_start_file((struct enc_file_event_data *)data)) 2523 - return; 2498 + if (ci->enc_stream_write(data->data, size) != size) 2499 + return -1; 2524 2500 2525 - break; 2501 + return 0; 2502 + } 2526 2503 2527 - case ENC_END_FILE: 2528 - if (on_end_file((struct enc_file_event_data *)data)) 2529 - return; 2504 + static int on_stream_start(struct enc_chunk_file *file) 2505 + { 2506 + mp3_crc16 = 0x0000; 2530 2507 2531 - break; 2508 + if (!write_info_header(file->hdr.aux0)) 2509 + return -1; 2532 2510 2533 - case ENC_REC_NEW_STREAM: 2534 - on_rec_new_stream((struct enc_buffer_event_data *)data); 2535 - return; 2511 + return 0; 2512 + } 2536 2513 2537 - default: 2538 - return; 2539 - } 2514 + static int on_stream_end(union enc_chunk_hdr *hdr) 2515 + { 2516 + ssize_t size = header_size; 2540 2517 2541 - /* Something failed above. Signal error back to core. */ 2542 - ((struct enc_file_event_data *)data)->chunk->flags |= CHUNKF_ERROR; 2543 - } /* enc_events_callback */ 2518 + if (size <= 0) 2519 + return 0; /* No header possible/none yet written */ 2544 2520 2545 - static bool enc_init(void) 2546 - { 2547 - struct enc_inputs inputs; 2548 - struct enc_parameters params; 2521 + /* Update audio CRC and header CRC */ 2522 + uint8_t frame[size]; 2549 2523 2550 - if (ci->enc_get_inputs == NULL || 2551 - ci->enc_set_parameters == NULL || 2552 - ci->enc_get_chunk == NULL || 2553 - ci->enc_finish_chunk == NULL || 2554 - ci->enc_get_pcm_data == NULL || 2555 - ci->enc_unget_pcm_data == NULL ) 2556 - return false; 2524 + /* Won't fail this since it could still be useable if some decoder 2525 + plays loose with the CRC info (like Rockbox :) */ 2526 + if (ci->enc_stream_lseek(0, SEEK_SET) != 0 || 2527 + ci->enc_stream_read(frame, size) != size) 2528 + return 0; 2557 2529 2558 - ci->enc_get_inputs(&inputs); 2530 + uint32_t header = (frame[0] << 24) | (frame[1] << 16) | 2531 + (frame[2] << 8) | (frame[3] << 0); 2532 + int i = get_info_offset(header); /* Get 'Info' header */ 2559 2533 2560 - if (inputs.config->afmt != AFMT_MPA_L3) 2561 - return false; 2534 + /* 'Info' header = 8 bytes */ 2562 2535 2563 - init_mp3_encoder_engine(inputs.sample_rate, inputs.num_channels, 2564 - inputs.rec_mono_mode, inputs.config); 2536 + /* Fill-in audio data CRC16 */ 2565 2537 2566 - err = 0; 2538 + /* On error, fixing data CRC would require scanning file since it 2539 + has probably dropped something we tried to write and the likely 2540 + reason is that the disk filled; just leave it 0 in that case. */ 2541 + if (!hdr->err) 2542 + { 2543 + frame[i + 40] = mp3_crc16 >> 8; 2544 + frame[i + 41] = mp3_crc16; 2545 + } 2567 2546 2568 - /* configure the buffer system */ 2569 - params.afmt = AFMT_MPA_L3; 2570 - params.chunk_size = cfg.byte_per_frame + 1; 2571 - params.enc_sample_rate = cfg.samplerate; 2572 - /* need enough reserved bytes to hold one frame of pcm samples + hdr 2573 - for padding and flushing */ 2574 - params.reserve_bytes = ENC_CHUNK_HDR_SIZE + pcm_chunk_size; 2575 - params.events_callback = enc_events_callback; 2576 - ci->enc_set_parameters(&params); 2547 + /* Fill-in header CRC16 */ 2548 + unsigned int hdr_crc16 = 0x0000; 2549 + for (int j = 0; j < i + 42; j++) 2550 + hdr_crc16 = crc_update_lookup(frame[j], hdr_crc16); 2577 2551 2578 - res_buffer = params.reserve_buffer; 2552 + frame[i + 42] = hdr_crc16 >> 8; 2553 + frame[i + 43] = hdr_crc16; 2579 2554 2580 - #ifdef CPU_COLDFIRE 2581 - asm volatile ("move.l #0, %macsr"); /* integer mode */ 2582 - #endif 2555 + /* Update file */ 2556 + if (ci->enc_stream_lseek(0, SEEK_SET) == 0) 2557 + ci->enc_stream_write(frame, size); 2583 2558 2584 - return true; 2585 - } /* enc_init */ 2559 + return 0; 2560 + } 2586 2561 2587 2562 /* this is the codec entry point */ 2588 2563 enum codec_status codec_main(enum codec_entry_call_reason reason) 2589 2564 { 2590 - if (reason == CODEC_LOAD) { 2591 - if (!enc_init()) 2592 - return CODEC_ERROR; 2593 - } 2594 - else if (reason == CODEC_UNLOAD) { 2595 - /* reset parameters to initial state */ 2596 - ci->enc_set_parameters(NULL); 2597 - } 2598 - 2565 + #ifdef CPU_COLDFIRE 2566 + if (reason == CODEC_LOAD) 2567 + asm volatile ("move.l #0, %macsr"); /* integer mode */ 2568 + #endif 2599 2569 return CODEC_OK; 2570 + (void)reason; 2600 2571 } 2601 2572 2602 2573 /* this is called for each file to process */ 2603 2574 enum codec_status codec_run(void) 2604 2575 { 2576 + mp3_encoder_reset(); 2577 + uint32_t first = 1; 2578 + 2579 + /* Needs to do stream finishing steps to flush-out all samples */ 2580 + int frames_rem = -1; /* -1 = indeterminate */ 2581 + 2582 + enum { GETBUF_ENC, GETBUF_PCM } getbuf = GETBUF_ENC; 2583 + struct enc_chunk_data *data = NULL; 2584 + 2605 2585 /* main encoding loop */ 2606 - while(ci->get_command(NULL) != CODEC_ACTION_HALT) 2586 + while (frames_rem) 2607 2587 { 2608 - char *buffer = buffer = ci->enc_get_pcm_data(pcm_chunk_size); 2609 - struct enc_chunk_hdr *chunk; 2588 + intptr_t param; 2589 + enum codec_command_action action = ci->get_command(&param); 2610 2590 2611 - if(buffer == NULL) 2612 - continue; 2591 + if (action != CODEC_ACTION_NULL) 2592 + { 2593 + if (action != CODEC_ACTION_STREAM_FINISH) 2594 + break; 2613 2595 2614 - chunk = ci->enc_get_chunk(); 2615 - chunk->enc_data = ENC_CHUNK_SKIP_HDR(chunk->enc_data, chunk); 2596 + if (frames_rem < 0) 2597 + frames_rem = cfg.flush_frames; 2616 2598 2617 - encode_frame(buffer, chunk); 2599 + /* Reply with required space */ 2600 + *(size_t *)param = cfg.req_byte_per_frame*frames_rem; 2601 + } 2618 2602 2619 - if (chunk->num_pcm < samp_per_frame) 2603 + /* First obtain output buffer; when available, get PCM data */ 2604 + switch (getbuf) 2620 2605 { 2621 - ci->enc_unget_pcm_data(pcm_chunk_size - chunk->num_pcm*4); 2622 - chunk->num_pcm = samp_per_frame; 2606 + case GETBUF_ENC: 2607 + if (!(data = ci->enc_encbuf_get_buffer(cfg.req_byte_per_frame))) 2608 + continue; 2609 + getbuf = GETBUF_PCM; 2610 + case GETBUF_PCM: 2611 + if (LIKELY(frames_rem < 0)) 2612 + { 2613 + /* Encoding audio */ 2614 + int count = cfg.samp_per_frame; 2615 + if (!ci->enc_pcmbuf_read(cfg.samp_buffer, count)) 2616 + continue; 2617 + 2618 + ci->enc_pcmbuf_advance(cfg.samp_per_frame); 2619 + 2620 + if (cfg.channels == 1) 2621 + { 2622 + /* Interleave the mono samples to stereo as required by 2623 + encoder */ 2624 + uint16_t *src = cfg.samp_buffer + count; 2625 + uint32_t *dst = (uint32_t *)(src + count); 2626 + 2627 + for (int i = count; i > 0; i--) 2628 + { uint32_t s = *--src; *--dst = s | (s << 16); } 2629 + } 2630 + } 2631 + else 2632 + { 2633 + /* Flushing encoder */ 2634 + memset(cfg.samp_buffer, 0, cfg.samp_per_frame*4); 2635 + frames_rem--; 2636 + } 2637 + getbuf = GETBUF_ENC; 2623 2638 } 2624 2639 2625 - ci->enc_finish_chunk(); 2640 + data->hdr.aux0 = first; 2641 + first = 0; 2642 + data->hdr.size = mp3_encoder_encode_frame(data->data); 2643 + data->pcm_count = cfg.samp_per_frame; 2644 + ci->enc_encbuf_finish_buffer(); 2626 2645 } 2627 2646 2628 2647 return CODEC_OK; 2629 2648 } 2649 + 2650 + /* this is called by recording system */ 2651 + int ICODE_ATTR enc_callback(enum enc_callback_reason reason, 2652 + void *params) 2653 + { 2654 + if (LIKELY(reason == ENC_CB_STREAM)) 2655 + { 2656 + switch (((union enc_chunk_hdr *)params)->type) 2657 + { 2658 + case CHUNK_T_DATA: 2659 + return on_stream_data(params); 2660 + case CHUNK_T_STREAM_START: 2661 + return on_stream_start(params); 2662 + case CHUNK_T_STREAM_END: 2663 + return on_stream_end(params); 2664 + } 2665 + } 2666 + else if (reason == ENC_CB_INPUTS) 2667 + { 2668 + struct enc_inputs *inputs = params; 2669 + 2670 + mp3_encoder_init(inputs->sample_rate, inputs->num_channels, 2671 + inputs->config->mp3_enc.bitrate); 2672 + 2673 + /* Return the actual configuration */ 2674 + inputs->enc_sample_rate = cfg.samplerate; 2675 + } 2676 + 2677 + return 0; 2678 + }
+116 -258
lib/rbcodec/codecs/wav_enc.c
··· 8 8 * $Id$ 9 9 * 10 10 * Copyright (C) 2006 Antonius Hellmann 11 + * Copyright (C) 2006-2013 Michael Sevakis 11 12 * 12 13 * This program is free software; you can redistribute it and/or 13 14 * modify it under the terms of the GNU General Public License ··· 40 41 uint16_t block_align; /* 20h - num_channels*bits_per_samples/8 */ 41 42 uint16_t bits_per_sample; /* 22h - 8=8 bits, 16=16 bits, etc. */ 42 43 /* Not for audio_format=1 (PCM) */ 43 - /* unsigned short extra_param_size; 24h - size of extra data */ 44 - /* unsigned char *extra_params; */ 44 + /* uint16_t extra_param_size; 24h - size of extra data */ 45 + /* uint8_t extra_params[extra_param_size]; */ 45 46 /* data header */ 46 47 uint8_t data_id[4]; /* 24h - "data" */ 47 48 uint32_t data_size; /* 28h - num_samples*num_channels*bits_per_sample/8 */ 48 - /* unsigned char *data; 2ch - actual sound data */ 49 + /* uint8_t data[data_size]; 2Ch - actual sound data */ 49 50 } __attribute__((packed)); 50 51 51 52 #define RIFF_FMT_HEADER_SIZE 12 /* format -> format_size */ ··· 55 56 #define PCM_DEPTH_BYTES 2 56 57 #define PCM_DEPTH_BITS 16 57 58 #define PCM_SAMP_PER_CHUNK 2048 58 - #define PCM_CHUNK_SIZE (PCM_SAMP_PER_CHUNK*4) 59 59 60 - static int num_channels IBSS_ATTR; 61 - static int rec_mono_mode IBSS_ATTR; 60 + static int num_channels; 62 61 static uint32_t sample_rate; 63 - static uint32_t enc_size; 64 - static int32_t err IBSS_ATTR; 62 + static size_t frame_size; 63 + static size_t data_size; 65 64 66 - static const struct riff_header riff_header = 65 + static const struct riff_header riff_template_header = 67 66 { 68 67 /* "RIFF" header */ 69 68 { 'R', 'I', 'F', 'F' }, /* riff_id */ 70 - 0, /* riff_size (*) */ 69 + 0, /* riff_size (*) */ 71 70 /* format header */ 72 71 { 'W', 'A', 'V', 'E' }, /* format */ 73 72 { 'f', 'm', 't', ' ' }, /* format_id */ ··· 82 81 /* data header */ 83 82 { 'd', 'a', 't', 'a' }, /* data_id */ 84 83 0 /* data_size (*) */ 85 - /* (*) updated during ENC_END_FILE event */ 84 + /* (*) updated when finalizing stream */ 86 85 }; 87 86 88 - /* called version often - inline */ 89 - static inline bool is_file_data_ok(struct enc_file_event_data *data) ICODE_ATTR; 90 - static inline bool is_file_data_ok(struct enc_file_event_data *data) 87 + static inline void frame_htole(uint32_t *p, size_t size) 91 88 { 92 - return data->rec_file >= 0 && (long)data->chunk->flags >= 0; 93 - } /* is_file_data_ok */ 94 - 95 - /* called version often - inline */ 96 - static inline bool on_write_chunk(struct enc_file_event_data *data) ICODE_ATTR; 97 - static inline bool on_write_chunk(struct enc_file_event_data *data) 98 - { 99 - if (!is_file_data_ok(data)) 100 - return false; 101 - 102 - if (data->chunk->enc_data == NULL) 89 + #ifdef ROCKBOX_BIG_ENDIAN 90 + /* Byte-swap samples, stereo or mono */ 91 + do 103 92 { 104 - #ifdef ROCKBOX_HAS_LOGF 105 - ci->logf("wav enc: NULL data"); 106 - #endif 107 - return true; 93 + uint32_t t; 94 + t = swap_odd_even32(*p); *p++ = t; 95 + t = swap_odd_even32(*p); *p++ = t; 96 + t = swap_odd_even32(*p); *p++ = t; 97 + t = swap_odd_even32(*p); *p++ = t; 98 + t = swap_odd_even32(*p); *p++ = t; 99 + t = swap_odd_even32(*p); *p++ = t; 100 + t = swap_odd_even32(*p); *p++ = t; 101 + t = swap_odd_even32(*p); *p++ = t; 108 102 } 103 + while (size -= 8 * 2 * PCM_DEPTH_BYTES); 104 + #endif /* ROCKBOX_BIG_ENDIAN */ 105 + (void)p; (void)size; 106 + } 109 107 110 - if (ci->write(data->rec_file, data->chunk->enc_data, 111 - data->chunk->enc_size) != (ssize_t)data->chunk->enc_size) 112 - return false; 108 + static int on_stream_data(struct enc_chunk_data *data) 109 + { 110 + size_t size = data->hdr.size; 113 111 114 - data->num_pcm_samples += data->chunk->num_pcm; 115 - return true; 116 - } /* on_write_chunk */ 112 + if (ci->enc_stream_write(data->data, size) != (ssize_t)size) 113 + return -1; 117 114 118 - static bool on_start_file(struct enc_file_event_data *data) 119 - { 120 - if ((data->chunk->flags & CHUNKF_ERROR) || *data->filename == '\0') 121 - return false; 122 - 123 - data->rec_file = ci->open(data->filename, O_RDWR|O_CREAT|O_TRUNC, 0666); 115 + data_size += size; 124 116 125 - if (data->rec_file < 0) 126 - return false; 117 + return 0; 118 + } 127 119 120 + static int on_stream_start(void) 121 + { 128 122 /* reset sample count */ 129 - data->num_pcm_samples = 0; 123 + data_size = 0; 130 124 131 125 /* write template header */ 132 - if (ci->write(data->rec_file, &riff_header, sizeof (riff_header)) 133 - != sizeof (riff_header)) 134 - { 135 - return false; 136 - } 126 + if (ci->enc_stream_write(&riff_template_header, sizeof (struct riff_header)) 127 + != sizeof (struct riff_header)) 128 + return -1; 137 129 138 - data->new_enc_size += sizeof (riff_header); 139 - return true; 140 - } /* on_start_file */ 130 + return 0; 131 + } 141 132 142 - static bool on_end_file(struct enc_file_event_data *data) 133 + static int on_stream_end(union enc_chunk_hdr *hdr) 143 134 { 144 135 /* update template header */ 145 - struct riff_header hdr; 146 - uint32_t data_size; 147 - 148 - if (data->rec_file < 0) 149 - return false; /* file already closed, nothing more we can do */ 136 + struct riff_header riff; 150 137 151 - /* always _try_ to write the file header, even on error */ 152 - if ((ci->lseek(data->rec_file, 0, SEEK_SET)) || 153 - (ci->read(data->rec_file, &hdr, sizeof (hdr)) != sizeof (hdr))) 138 + if (hdr->err) 154 139 { 155 - return false; 140 + /* Called for stream error; get correct data size */ 141 + ssize_t size = ci->enc_stream_lseek(0, SEEK_END); 142 + 143 + if (size > (ssize_t)sizeof (riff)) 144 + data_size = size - sizeof (riff); 156 145 } 157 146 158 - data_size = data->num_pcm_samples*num_channels*PCM_DEPTH_BYTES; 147 + if (ci->enc_stream_lseek(0, SEEK_SET) || 148 + ci->enc_stream_read(&riff, sizeof (riff)) != sizeof (riff)) 149 + return -1; 159 150 160 151 /* "RIFF" header */ 161 - hdr.riff_size = htole32(RIFF_FMT_HEADER_SIZE + RIFF_FMT_DATA_SIZE 162 - + RIFF_DATA_HEADER_SIZE + data_size); 152 + riff.riff_size = htole32(RIFF_FMT_HEADER_SIZE + RIFF_FMT_DATA_SIZE 153 + + RIFF_DATA_HEADER_SIZE + data_size); 163 154 164 155 /* format data */ 165 - hdr.num_channels = htole16(num_channels); 166 - hdr.sample_rate = htole32(sample_rate); 167 - hdr.byte_rate = htole32(sample_rate*num_channels* PCM_DEPTH_BYTES); 168 - hdr.block_align = htole16(num_channels*PCM_DEPTH_BYTES); 156 + riff.num_channels = htole16(num_channels); 157 + riff.sample_rate = htole32(sample_rate); 158 + riff.byte_rate = htole32(sample_rate*num_channels*PCM_DEPTH_BYTES); 159 + riff.block_align = htole16(num_channels*PCM_DEPTH_BYTES); 169 160 170 161 /* data header */ 171 - hdr.data_size = htole32(data_size); 162 + riff.data_size = htole32(data_size); 172 163 173 - if (ci->lseek(data->rec_file, 0, SEEK_SET) != 0 || 174 - ci->write(data->rec_file, &hdr, sizeof (hdr)) != sizeof (hdr) || 175 - ci->close(data->rec_file) != 0) 176 - { 177 - return false; 178 - } 164 + if (ci->enc_stream_lseek(0, SEEK_SET) != 0) 165 + return -2; 179 166 180 - data->rec_file = -1; 167 + if (ci->enc_stream_write(&riff, sizeof (riff)) != sizeof (riff)) 168 + return -3; 181 169 182 - return true; 183 - } /* on_end_file */ 170 + return 0; 171 + } 184 172 185 - static void enc_events_callback(enum enc_events event, void *data) 186 - ICODE_ATTR; 187 - static void enc_events_callback(enum enc_events event, void *data) 173 + /* this is the codec entry point */ 174 + enum codec_status codec_main(enum codec_entry_call_reason reason) 188 175 { 189 - switch (event) 190 - { 191 - case ENC_WRITE_CHUNK: 192 - if (on_write_chunk((struct enc_file_event_data *)data)) 193 - return; 194 - 195 - break; 196 - 197 - case ENC_START_FILE: 198 - if (on_start_file((struct enc_file_event_data *)data)) 199 - return; 200 - 201 - break; 202 - 203 - case ENC_END_FILE: 204 - if (on_end_file((struct enc_file_event_data *)data)) 205 - return; 206 - 207 - break; 176 + return CODEC_OK; 177 + (void)reason; 178 + } 208 179 209 - default: 210 - return; 211 - } 212 - 213 - /* Something failed above. Signal error back to core. */ 214 - ((struct enc_file_event_data *)data)->chunk->flags |= CHUNKF_ERROR; 215 - } /* enc_events_callback */ 216 - 217 - /* convert native pcm samples to wav format samples */ 218 - static inline void sample_to_mono(uint32_t **src, uint32_t **dst) 180 + /* this is called for each file to process */ 181 + enum codec_status ICODE_ATTR codec_run(void) 219 182 { 220 - int32_t lr1, lr2; 183 + enum { GETBUF_ENC, GETBUF_PCM } getbuf = GETBUF_ENC; 184 + struct enc_chunk_data *data = NULL; 221 185 222 - switch(rec_mono_mode) 186 + /* main encoding loop */ 187 + while (1) 223 188 { 224 - case 1: 225 - /* mono = L */ 226 - lr1 = *(*src)++; 227 - lr1 = lr1 >> 16; 228 - lr2 = *(*src)++; 229 - lr2 = lr2 >> 16; 230 - break; 231 - case 2: 232 - /* mono = R */ 233 - lr1 = *(*src)++; 234 - lr1 = (uint16_t)lr1; 235 - lr2 = *(*src)++; 236 - lr2 = (uint16_t)lr2; 237 - break; 238 - case 0: 239 - default: 240 - /* mono = (L+R)/2 */ 241 - lr1 = *(*src)++; 242 - lr1 = (int16_t)lr1 + (lr1 >> 16) + err; 243 - err = lr1 & 1; 244 - lr1 >>= 1; 189 + enum codec_command_action action = ci->get_command(NULL); 245 190 246 - lr2 = *(*src)++; 247 - lr2 = (int16_t)lr2 + (lr2 >> 16) + err; 248 - err = lr2 & 1; 249 - lr2 >>= 1; 191 + if (action != CODEC_ACTION_NULL) 250 192 break; 251 - } 252 - *(*dst)++ = htole32((lr2 << 16) | (uint16_t)lr1); 253 - } /* sample_to_mono */ 254 193 255 - static void chunk_to_wav_format(uint32_t *src, uint32_t *dst) ICODE_ATTR; 256 - static void chunk_to_wav_format(uint32_t *src, uint32_t *dst) 257 - { 258 - if (num_channels == 1) 259 - { 260 - /* On big endian: 261 - * |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| 262 - * |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| => 263 - * |mmmmmmmmMMMMMMMM|mmmmmmmmMMMMMMMM| 264 - * 265 - * On little endian: 266 - * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| 267 - * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| => 268 - * |mmmmmmmmMMMMMMMM|mmmmmmmmMMMMMMMM| 269 - */ 270 - uint32_t *src_end = src + PCM_SAMP_PER_CHUNK; 271 - 272 - do 194 + /* First obtain output buffer; when available, get PCM data */ 195 + switch (getbuf) 273 196 { 274 - sample_to_mono(&src, &dst); 275 - sample_to_mono(&src, &dst); 276 - sample_to_mono(&src, &dst); 277 - sample_to_mono(&src, &dst); 278 - sample_to_mono(&src, &dst); 279 - sample_to_mono(&src, &dst); 280 - sample_to_mono(&src, &dst); 281 - sample_to_mono(&src, &dst); 197 + case GETBUF_ENC: 198 + if (!(data = ci->enc_encbuf_get_buffer(frame_size))) 199 + continue; 200 + getbuf = GETBUF_PCM; 201 + case GETBUF_PCM: 202 + if (!ci->enc_pcmbuf_read(data->data, PCM_SAMP_PER_CHUNK)) 203 + continue; 204 + getbuf = GETBUF_ENC; 282 205 } 283 - while (src < src_end); 284 - } 285 - else 286 - { 287 - #ifdef ROCKBOX_BIG_ENDIAN 288 - /* |LLLLLLLLllllllll|RRRRRRRRrrrrrrrr| => 289 - * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| 290 - */ 291 - uint32_t *src_end = src + PCM_SAMP_PER_CHUNK; 292 206 293 - do 294 - { 295 - *dst++ = swap_odd_even32(*src++); 296 - *dst++ = swap_odd_even32(*src++); 297 - *dst++ = swap_odd_even32(*src++); 298 - *dst++ = swap_odd_even32(*src++); 299 - *dst++ = swap_odd_even32(*src++); 300 - *dst++ = swap_odd_even32(*src++); 301 - *dst++ = swap_odd_even32(*src++); 302 - *dst++ = swap_odd_even32(*src++); 303 - } 304 - while (src < src_end); 305 - #else 306 - /* |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| => 307 - * |llllllllLLLLLLLL|rrrrrrrrRRRRRRRR| 308 - */ 309 - ci->memcpy(dst, src, PCM_CHUNK_SIZE); 310 - #endif 311 - } 312 - } /* chunk_to_wav_format */ 313 - 314 - static bool init_encoder(void) 315 - { 316 - struct enc_inputs inputs; 317 - struct enc_parameters params; 207 + data->hdr.size = frame_size; 208 + data->pcm_count = PCM_SAMP_PER_CHUNK; 318 209 319 - if (ci->enc_get_inputs == NULL || 320 - ci->enc_set_parameters == NULL || 321 - ci->enc_get_chunk == NULL || 322 - ci->enc_finish_chunk == NULL || 323 - ci->enc_get_pcm_data == NULL ) 324 - return false; 325 - 326 - ci->enc_get_inputs(&inputs); 210 + frame_htole((uint32_t *)data->data, frame_size); 327 211 328 - if (inputs.config->afmt != AFMT_PCM_WAV) 329 - return false; 330 - 331 - sample_rate = inputs.sample_rate; 332 - num_channels = inputs.num_channels; 333 - rec_mono_mode = inputs.rec_mono_mode; 334 - err = 0; 335 - 336 - /* configure the buffer system */ 337 - params.afmt = AFMT_PCM_WAV; 338 - enc_size = PCM_CHUNK_SIZE*inputs.num_channels / 2; 339 - params.chunk_size = enc_size; 340 - params.enc_sample_rate = sample_rate; 341 - params.reserve_bytes = 0; 342 - params.events_callback = enc_events_callback; 343 - ci->enc_set_parameters(&params); 344 - 345 - return true; 346 - } /* init_encoder */ 347 - 348 - /* this is the codec entry point */ 349 - enum codec_status codec_main(enum codec_entry_call_reason reason) 350 - { 351 - if (reason == CODEC_LOAD) { 352 - if (!init_encoder()) 353 - return CODEC_ERROR; 354 - } 355 - else if (reason == CODEC_UNLOAD) { 356 - /* reset parameters to initial state */ 357 - ci->enc_set_parameters(NULL); 212 + ci->enc_pcmbuf_advance(PCM_SAMP_PER_CHUNK); 213 + ci->enc_encbuf_finish_buffer(); 358 214 } 359 215 360 216 return CODEC_OK; 361 217 } 362 218 363 - /* this is called for each file to process */ 364 - enum codec_status codec_run(void) 219 + /* this is called by recording system */ 220 + int ICODE_ATTR enc_callback(enum enc_callback_reason reason, 221 + void *params) 365 222 { 366 - /* main encoding loop */ 367 - while(ci->get_command(NULL) != CODEC_ACTION_HALT) 223 + if (LIKELY(reason == ENC_CB_STREAM)) 368 224 { 369 - uint32_t *src = (uint32_t *)ci->enc_get_pcm_data(PCM_CHUNK_SIZE); 370 - struct enc_chunk_hdr *chunk; 371 - 372 - if(src == NULL) 373 - continue; 374 - 375 - chunk = ci->enc_get_chunk(); 376 - chunk->enc_size = enc_size; 377 - chunk->num_pcm = PCM_SAMP_PER_CHUNK; 378 - chunk->enc_data = ENC_CHUNK_SKIP_HDR(chunk->enc_data, chunk); 379 - 380 - chunk_to_wav_format(src, (uint32_t *)chunk->enc_data); 381 - 382 - ci->enc_finish_chunk(); 225 + switch (((union enc_chunk_hdr *)params)->type) 226 + { 227 + case CHUNK_T_DATA: 228 + return on_stream_data(params); 229 + case CHUNK_T_STREAM_START: 230 + return on_stream_start(); 231 + case CHUNK_T_STREAM_END: 232 + return on_stream_end(params); 233 + } 234 + } 235 + else if (reason == ENC_CB_INPUTS) 236 + { 237 + struct enc_inputs *inputs = params; 238 + sample_rate = inputs->sample_rate; 239 + num_channels = inputs->num_channels; 240 + frame_size = PCM_SAMP_PER_CHUNK*PCM_DEPTH_BYTES*num_channels; 383 241 } 384 242 385 - return CODEC_OK; 243 + return 0; 386 244 }
+157 -294
lib/rbcodec/codecs/wavpack_enc.c
··· 8 8 * $Id$ 9 9 * 10 10 * Copyright (C) 2006 Antonius Hellmann 11 + * Copyright (C) 2006-2013 Michael Sevakis 11 12 * 12 13 * This program is free software; you can redistribute it and/or 13 14 * modify it under the terms of the GNU General Public License ··· 47 48 uint16_t block_align; /* 20h - num_channels*bits_per_samples/8 */ 48 49 uint16_t bits_per_sample; /* 22h - 8=8 bits, 16=16 bits, etc. */ 49 50 /* Not for audio_format=1 (PCM) */ 50 - /* unsigned short extra_param_size; 24h - size of extra data */ 51 - /* unsigned char *extra_params; */ 51 + /* uint16_t extra_param_size; 24h - size of extra data */ 52 + /* uint8_t extra_params[extra_param_size]; */ 52 53 /* data header */ 53 54 uint8_t data_id[4]; /* 24h - "data" */ 54 55 uint32_t data_size; /* 28h - num_samples*num_channels*bits_per_sample/8 */ 55 - /* unsigned char *data; 2ch - actual sound data */ 56 + /* uint8_t data[data_size]; 2Ch - actual sound data */ 56 57 } __attribute__((packed)); 57 58 58 59 #define RIFF_FMT_HEADER_SIZE 12 /* format -> format_size */ 59 60 #define RIFF_FMT_DATA_SIZE 16 /* audio_format -> bits_per_sample */ 60 61 #define RIFF_DATA_HEADER_SIZE 8 /* data_id -> data_size */ 61 62 63 + struct wvpk_chunk_data 64 + { 65 + struct enc_chunk_data ckhdr; /* The base data chunk header */ 66 + WavpackHeader wphdr; /* The block wavpack info */ 67 + uint8_t data[]; /* Encoded audio data */ 68 + }; 69 + 62 70 #define PCM_DEPTH_BITS 16 63 71 #define PCM_DEPTH_BYTES 2 64 72 #define PCM_SAMP_PER_CHUNK 5000 65 - #define PCM_CHUNK_SIZE (4*PCM_SAMP_PER_CHUNK) 66 73 67 74 /** Data **/ 68 - static int8_t input_buffer[PCM_CHUNK_SIZE*2] IBSS_ATTR; 69 - static WavpackConfig config IBSS_ATTR; 75 + static int32_t input_buffer[PCM_SAMP_PER_CHUNK*2] IBSS_ATTR; 76 + 77 + static WavpackConfig config IBSS_ATTR; 70 78 static WavpackContext *wpc; 71 - static int32_t data_size, input_size, input_step IBSS_ATTR; 72 - static int32_t err IBSS_ATTR; 79 + static uint32_t sample_rate; 80 + static int num_channels; 81 + static uint32_t total_samples; 82 + static size_t out_reqsize; 83 + static size_t frame_size; 73 84 74 85 static const WavpackMetadataHeader wvpk_mdh = 75 86 { ··· 77 88 sizeof (struct riff_header) / sizeof (uint16_t), 78 89 }; 79 90 80 - static const struct riff_header riff_header = 91 + static const struct riff_header riff_template_header = 81 92 { 82 93 /* "RIFF" header */ 83 94 { 'R', 'I', 'F', 'F' }, /* riff_id */ ··· 96 107 /* data header */ 97 108 { 'd', 'a', 't', 'a' }, /* data_id */ 98 109 0 /* data_size (*) */ 99 - /* (*) updated during ENC_END_FILE event */ 110 + /* (*) updated when finalizing stream */ 100 111 }; 101 112 102 - static inline void sample_to_int32_mono(int32_t **src, int32_t **dst) 103 - { 104 - int32_t t = *(*src)++; 105 - /* endianness irrelevant */ 106 - t = (int16_t)t + (t >> 16) + err; 107 - err = t & 1; 108 - *(*dst)++ = t >> 1; 109 - } /* sample_to_int32_mono */ 110 - 111 - static inline void sample_to_int32_stereo(int32_t **src, int32_t **dst) 113 + static inline void sample_to_int32(int32_t **dst, int32_t **src) 112 114 { 113 - int32_t t = *(*src)++; 115 + uint32_t t = *(*src)++; 114 116 #ifdef ROCKBOX_BIG_ENDIAN 115 - *(*dst)++ = t >> 16, *(*dst)++ = (int16_t)t; 117 + *(*dst)++ = (int32_t)t >> 16; 118 + *(*dst)++ = (int16_t)t; 116 119 #else 117 - *(*dst)++ = (int16_t)t, *(*dst)++ = t >> 16; 120 + *(*dst)++ = (int16_t)t; 121 + *(*dst)++ = (int32_t)t >> 16; 118 122 #endif 119 - } /* sample_to_int32_stereo */ 123 + } 120 124 121 - static void chunk_to_int32(int32_t *src) ICODE_ATTR; 122 - static void chunk_to_int32(int32_t *src) 125 + static void ICODE_ATTR input_buffer_to_int32(size_t size) 123 126 { 124 - int32_t *src_end, *dst; 125 - #ifdef USE_IRAM 126 - /* copy to IRAM before converting data */ 127 - dst = (int32_t *)input_buffer + PCM_SAMP_PER_CHUNK; 128 - src_end = dst + PCM_SAMP_PER_CHUNK; 127 + int32_t *dst = input_buffer; 128 + int32_t *src = input_buffer + PCM_SAMP_PER_CHUNK; 129 129 130 - memcpy(dst, src, PCM_CHUNK_SIZE); 131 - 132 - src = dst; 133 - #else 134 - src_end = src + PCM_SAMP_PER_CHUNK; 135 - #endif 136 - 137 - dst = (int32_t *)input_buffer; 138 - 139 - if (config.num_channels == 1) 140 - { 141 - /* 142 - * |llllllllllllllll|rrrrrrrrrrrrrrrr| => 143 - * |mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm| 144 - */ 145 - do 146 - { 147 - /* read 10 longs and write 10 longs */ 148 - sample_to_int32_mono(&src, &dst); 149 - sample_to_int32_mono(&src, &dst); 150 - sample_to_int32_mono(&src, &dst); 151 - sample_to_int32_mono(&src, &dst); 152 - sample_to_int32_mono(&src, &dst); 153 - sample_to_int32_mono(&src, &dst); 154 - sample_to_int32_mono(&src, &dst); 155 - sample_to_int32_mono(&src, &dst); 156 - sample_to_int32_mono(&src, &dst); 157 - sample_to_int32_mono(&src, &dst); 158 - } 159 - while(src < src_end); 160 - 161 - return; 162 - } 163 - else 130 + do 164 131 { 165 - /* 166 - * |llllllllllllllll|rrrrrrrrrrrrrrrr| => 167 - * |llllllllllllllllllllllllllllllll|rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr| 168 - */ 169 - do 170 - { 171 - /* read 10 longs and write 20 longs */ 172 - sample_to_int32_stereo(&src, &dst); 173 - sample_to_int32_stereo(&src, &dst); 174 - sample_to_int32_stereo(&src, &dst); 175 - sample_to_int32_stereo(&src, &dst); 176 - sample_to_int32_stereo(&src, &dst); 177 - sample_to_int32_stereo(&src, &dst); 178 - sample_to_int32_stereo(&src, &dst); 179 - sample_to_int32_stereo(&src, &dst); 180 - sample_to_int32_stereo(&src, &dst); 181 - sample_to_int32_stereo(&src, &dst); 182 - } 183 - while (src < src_end); 184 - 185 - return; 132 + sample_to_int32(&dst, &src); 133 + sample_to_int32(&dst, &src); 134 + sample_to_int32(&dst, &src); 135 + sample_to_int32(&dst, &src); 136 + sample_to_int32(&dst, &src); 137 + sample_to_int32(&dst, &src); 138 + sample_to_int32(&dst, &src); 139 + sample_to_int32(&dst, &src); 140 + sample_to_int32(&dst, &src); 141 + sample_to_int32(&dst, &src); 186 142 } 187 - } /* chunk_to_int32 */ 143 + while (size -= 10 * 2 * PCM_DEPTH_BYTES); 144 + } 188 145 189 - /* called very often - inline */ 190 - static inline bool is_file_data_ok(struct enc_file_event_data *data) ICODE_ATTR; 191 - static inline bool is_file_data_ok(struct enc_file_event_data *data) 146 + static int on_stream_data(struct wvpk_chunk_data *wpdata) 192 147 { 193 - return data->rec_file >= 0 && (long)data->chunk->flags >= 0; 194 - } /* is_file_data_ok */ 148 + /* update timestamp (block_index) */ 149 + wpdata->wphdr.block_index = htole32(total_samples); 195 150 196 - /* called very often - inline */ 197 - static inline bool on_write_chunk(struct enc_file_event_data *data) ICODE_ATTR; 198 - static inline bool on_write_chunk(struct enc_file_event_data *data) 199 - { 200 - if (!is_file_data_ok(data)) 201 - return false; 202 - 203 - if (data->chunk->enc_data == NULL) 204 - { 205 - #ifdef ROCKBOX_HAS_LOGF 206 - ci->logf("wvpk enc: NULL data"); 207 - #endif 208 - return true; 209 - } 151 + size_t size = wpdata->ckhdr.hdr.size; 152 + if (ci->enc_stream_write(wpdata->ckhdr.data, size) != (ssize_t)size) 153 + return -1; 210 154 211 - /* update timestamp (block_index) */ 212 - ((WavpackHeader *)data->chunk->enc_data)->block_index = 213 - htole32(data->num_pcm_samples); 214 - 215 - if (ci->write(data->rec_file, data->chunk->enc_data, 216 - data->chunk->enc_size) != (ssize_t)data->chunk->enc_size) 217 - return false; 155 + total_samples += wpdata->ckhdr.pcm_count; 218 156 219 - data->num_pcm_samples += data->chunk->num_pcm; 220 - return true; 221 - } /* on_write_chunk */ 157 + return 0; 158 + } 222 159 223 - static bool on_start_file(struct enc_file_event_data *data) 160 + static int on_stream_start(void) 224 161 { 225 - if ((data->chunk->flags & CHUNKF_ERROR) || *data->filename == '\0') 226 - return false; 227 - 228 - data->rec_file = ci->open(data->filename, O_RDWR|O_CREAT|O_TRUNC, 0666); 229 - 230 - if (data->rec_file < 0) 231 - return false; 232 - 233 162 /* reset sample count */ 234 - data->num_pcm_samples = 0; 163 + total_samples = 0; 235 164 236 165 /* write template headers */ 237 - if (ci->write(data->rec_file, &wvpk_mdh, sizeof (wvpk_mdh)) 238 - != sizeof (wvpk_mdh) || 239 - ci->write(data->rec_file, &riff_header, sizeof (riff_header)) 240 - != sizeof (riff_header)) 241 - { 242 - return false; 243 - } 166 + if (ci->enc_stream_write(&wvpk_mdh, sizeof (wvpk_mdh)) 167 + != sizeof (wvpk_mdh)) 168 + return -1; 244 169 245 - data->new_enc_size += sizeof(wvpk_mdh) + sizeof(riff_header); 246 - return true; 247 - } /* on_start_file */ 170 + if (ci->enc_stream_write(&riff_template_header, 171 + sizeof (riff_template_header)) 172 + != sizeof (riff_template_header)) 173 + return -2; 248 174 249 - static bool on_end_file(struct enc_file_event_data *data) 175 + return 0; 176 + } 177 + 178 + static int on_stream_end(void) 250 179 { 251 180 struct 252 181 { ··· 255 184 WavpackHeader wph; 256 185 } __attribute__ ((packed)) h; 257 186 258 - uint32_t data_size; 259 - 260 - if (data->rec_file < 0) 261 - return false; /* file already closed, nothing more we can do */ 262 - 263 - /* always _try_ to write the file header, even on error */ 187 + /* Correcting sizes on error is a bit of a pain */ 264 188 265 189 /* read template headers at start */ 266 - if (ci->lseek(data->rec_file, 0, SEEK_SET) != 0 || 267 - ci->read(data->rec_file, &h, sizeof (h)) != sizeof (h)) 268 - return false; 190 + if (ci->enc_stream_lseek(0, SEEK_SET) != 0) 191 + return -1; 269 192 270 - data_size = data->num_pcm_samples*config.num_channels*PCM_DEPTH_BYTES; 193 + if (ci->enc_stream_read(&h, sizeof (h)) != sizeof (h)) 194 + return -2; 195 + 196 + size_t data_size = total_samples*config.num_channels*PCM_DEPTH_BYTES; 271 197 272 198 /** "RIFF" header **/ 273 199 h.rhdr.riff_size = htole32(RIFF_FMT_HEADER_SIZE + ··· 286 212 /** Wavpack header **/ 287 213 h.wph.ckSize = htole32(letoh32(h.wph.ckSize) + sizeof (h.wpmdh) 288 214 + sizeof (h.rhdr)); 289 - h.wph.total_samples = htole32(data->num_pcm_samples); 215 + h.wph.total_samples = htole32(total_samples); 290 216 291 217 /* MDH|RIFF|WVPK => WVPK|MDH|RIFF */ 292 - if (ci->lseek(data->rec_file, 0, SEEK_SET) 293 - != 0 || 294 - ci->write(data->rec_file, &h.wph, sizeof (h.wph)) 295 - != sizeof (h.wph) || 296 - ci->write(data->rec_file, &h.wpmdh, sizeof (h.wpmdh)) 297 - != sizeof (h.wpmdh) || 298 - ci->write(data->rec_file, &h.rhdr, sizeof (h.rhdr)) 299 - != sizeof (h.rhdr) || 300 - ci->close(data->rec_file) != 0 ) 301 - { 302 - return false; 303 - } 218 + if (ci->enc_stream_lseek(0, SEEK_SET) != 0) 219 + return -3; 304 220 305 - data->rec_file = -1; 221 + if (ci->enc_stream_write(&h.wph, sizeof (h.wph)) != sizeof (h.wph)) 222 + return -4; 306 223 307 - return true; 308 - } /* on_end_file */ 224 + if (ci->enc_stream_write(&h.wpmdh, sizeof (h.wpmdh)) != sizeof (h.wpmdh)) 225 + return -5; 309 226 310 - static void enc_events_callback(enum enc_events event, void *data) 311 - ICODE_ATTR; 312 - static void enc_events_callback(enum enc_events event, void *data) 313 - { 314 - switch (event) 315 - { 316 - case ENC_WRITE_CHUNK: 317 - if (on_write_chunk((struct enc_file_event_data *)data)) 318 - return; 227 + if (ci->enc_stream_write(&h.rhdr, sizeof (h.rhdr)) != sizeof (h.rhdr)) 228 + return -6; 319 229 320 - break; 321 - 322 - case ENC_START_FILE: 323 - /* write metadata header and RIFF header */ 324 - if (on_start_file((struct enc_file_event_data *)data)) 325 - return; 326 - 327 - break; 328 - 329 - case ENC_END_FILE: 330 - if (on_end_file((struct enc_file_event_data *)data)) 331 - return; 332 - 333 - break; 334 - 335 - default: 336 - return; 337 - } 338 - 339 - /* Something failed above. Signal error back to core. */ 340 - ((struct enc_file_event_data *)data)->chunk->flags |= CHUNKF_ERROR; 341 - } /* enc_events_callback */ 342 - 343 - static bool init_encoder(void) 344 - { 345 - struct enc_inputs inputs; 346 - struct enc_parameters params; 347 - 348 - codec_init(); 349 - 350 - if (ci->enc_get_inputs == NULL || 351 - ci->enc_set_parameters == NULL || 352 - ci->enc_get_chunk == NULL || 353 - ci->enc_finish_chunk == NULL || 354 - ci->enc_get_pcm_data == NULL || 355 - ci->enc_unget_pcm_data == NULL ) 356 - return false; 357 - 358 - ci->enc_get_inputs(&inputs); 359 - 360 - if (inputs.config->afmt != AFMT_WAVPACK) 361 - return false; 362 - 363 - memset(&config, 0, sizeof (config)); 364 - config.bits_per_sample = PCM_DEPTH_BITS; 365 - config.bytes_per_sample = PCM_DEPTH_BYTES; 366 - config.sample_rate = inputs.sample_rate; 367 - config.num_channels = inputs.num_channels; 368 - 369 - wpc = WavpackOpenFileOutput (); 370 - 371 - if (!WavpackSetConfiguration(wpc, &config, -1)) 372 - return false; 373 - 374 - err = 0; 375 - 376 - /* configure the buffer system */ 377 - params.afmt = AFMT_WAVPACK; 378 - input_size = PCM_CHUNK_SIZE*inputs.num_channels / 2; 379 - data_size = 105*input_size / 100; 380 - input_size *= 2; 381 - input_step = input_size / 4; 382 - params.chunk_size = data_size; 383 - params.enc_sample_rate = inputs.sample_rate; 384 - params.reserve_bytes = 0; 385 - params.events_callback = enc_events_callback; 386 - 387 - ci->enc_set_parameters(&params); 388 - 389 - return true; 390 - } /* init_encoder */ 230 + return 0; 231 + } 391 232 392 233 /* this is the codec entry point */ 393 234 enum codec_status codec_main(enum codec_entry_call_reason reason) 394 235 { 395 - if (reason == CODEC_LOAD) { 396 - /* initialize params and config */ 397 - if (!init_encoder()) 398 - return CODEC_ERROR; 399 - } 400 - else if (reason == CODEC_UNLOAD) { 401 - /* reset parameters to initial state */ 402 - ci->enc_set_parameters(NULL); 403 - } 236 + if (reason == CODEC_LOAD) 237 + codec_init(); 404 238 405 239 return CODEC_OK; 406 240 } ··· 408 242 /* this is called for each file to process */ 409 243 enum codec_status codec_run(void) 410 244 { 245 + enum { GETBUF_ENC, GETBUF_PCM } getbuf = GETBUF_ENC; 246 + struct enc_chunk_data *data = NULL; 247 + 411 248 /* main encoding loop */ 412 - while(ci->get_command(NULL) != CODEC_ACTION_HALT) 249 + while (1) 413 250 { 414 - uint8_t *src = (uint8_t *)ci->enc_get_pcm_data(PCM_CHUNK_SIZE); 415 - struct enc_chunk_hdr *chunk; 416 - bool abort_chunk; 417 - uint8_t *dst; 418 - uint8_t *src_end; 251 + enum codec_command_action action = ci->get_command(NULL); 419 252 420 - if(src == NULL) 421 - continue; 253 + if (action != CODEC_ACTION_NULL) 254 + break; 422 255 423 - chunk = ci->enc_get_chunk(); 256 + /* First obtain output buffer; when available, get PCM data */ 257 + switch (getbuf) 258 + { 259 + case GETBUF_ENC: 260 + if (!(data = ci->enc_encbuf_get_buffer(out_reqsize))) 261 + continue; 262 + getbuf = GETBUF_PCM; 263 + case GETBUF_PCM: 264 + if (!ci->enc_pcmbuf_read(input_buffer + PCM_SAMP_PER_CHUNK, 265 + PCM_SAMP_PER_CHUNK)) 266 + continue; 267 + getbuf = GETBUF_ENC; 268 + } 424 269 425 - /* reset counts and pointer */ 426 - chunk->enc_size = 0; 427 - chunk->num_pcm = 0; 428 - chunk->enc_data = NULL; 270 + input_buffer_to_int32(frame_size); 429 271 430 - dst = ENC_CHUNK_SKIP_HDR(dst, chunk); 272 + if (WavpackStartBlock(wpc, data->data, data->data + out_reqsize) && 273 + WavpackPackSamples(wpc, input_buffer, PCM_SAMP_PER_CHUNK)) 274 + { 275 + /* finish the chunk and store chunk size info */ 276 + data->hdr.size = WavpackFinishBlock(wpc); 277 + data->pcm_count = PCM_SAMP_PER_CHUNK; 278 + } 279 + else 280 + { 281 + data->hdr.err = 1; 282 + } 431 283 432 - WavpackStartBlock(wpc, dst, dst + data_size); 284 + ci->enc_pcmbuf_advance(PCM_SAMP_PER_CHUNK); 285 + ci->enc_encbuf_finish_buffer(); 286 + } 433 287 434 - chunk_to_int32((uint32_t*)src); 435 - src = input_buffer; 436 - src_end = src + input_size; 288 + return CODEC_OK; 289 + } 437 290 438 - /* encode chunk in four steps yielding between each */ 439 - do 291 + /* this is called by recording system */ 292 + int ICODE_ATTR enc_callback(enum enc_callback_reason reason, 293 + void *params) 294 + { 295 + if (LIKELY(reason == ENC_CB_STREAM)) 296 + { 297 + switch (((union enc_chunk_hdr *)params)->type) 440 298 { 441 - abort_chunk = true; 442 - if (WavpackPackSamples(wpc, (int32_t *)src, 443 - PCM_SAMP_PER_CHUNK/4)) 444 - { 445 - chunk->num_pcm += PCM_SAMP_PER_CHUNK/4; 446 - ci->yield(); 447 - /* could've been stopped in some way */ 448 - abort_chunk = chunk->flags & CHUNKF_ABORT; 449 - } 450 - 451 - src += input_step; 299 + case CHUNK_T_DATA: 300 + return on_stream_data(params); 301 + case CHUNK_T_STREAM_START: 302 + return on_stream_start(); 303 + case CHUNK_T_STREAM_END: 304 + return on_stream_end(); 452 305 } 453 - while (!abort_chunk && src < src_end); 306 + } 307 + else if (reason == ENC_CB_INPUTS) 308 + { 309 + /* Save parameters */ 310 + struct enc_inputs *inputs = params; 311 + sample_rate = inputs->sample_rate; 312 + num_channels = inputs->num_channels; 313 + frame_size = PCM_SAMP_PER_CHUNK*PCM_DEPTH_BYTES*num_channels; 314 + out_reqsize = frame_size*110 / 100; /* Add 10% */ 454 315 455 - if (!abort_chunk) 456 - { 457 - chunk->enc_data = dst; 458 - if (chunk->num_pcm < PCM_SAMP_PER_CHUNK) 459 - ci->enc_unget_pcm_data(PCM_CHUNK_SIZE - chunk->num_pcm*4); 460 - /* finish the chunk and store chunk size info */ 461 - chunk->enc_size = WavpackFinishBlock(wpc); 462 - ci->enc_finish_chunk(); 463 - } 316 + /* Setup Wavpack encoder */ 317 + memset(&config, 0, sizeof (config)); 318 + config.bits_per_sample = PCM_DEPTH_BITS; 319 + config.bytes_per_sample = PCM_DEPTH_BYTES; 320 + config.sample_rate = sample_rate; 321 + config.num_channels = num_channels; 322 + 323 + wpc = WavpackOpenFileOutput(); 324 + 325 + if (!WavpackSetConfiguration(wpc, &config, -1)) 326 + return -1; 464 327 } 465 328 466 - return CODEC_OK; 329 + return 0; 467 330 }