blob: b5de670c0dac6cdde2c429a55a7f07b51ba5c1b5 [file] [log] [blame]
Andye5d08722005-06-19 03:05:53 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
Michael Sevakis48881312013-06-22 16:41:16 -040010 * Copyright (C) 2005 Linus Nielsen Feltzing
11 * Copyright (C) 2006 Antonius Hellmann
12 * Copyright (C) 2006-2013 Michael Sevakis
13 *
Andye5d08722005-06-19 03:05:53 +000014 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000015 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
Andye5d08722005-06-19 03:05:53 +000019 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
Thomas Martitz0e2286f2010-08-12 13:38:25 +000024#include "config.h"
Michael Sevakis0f5cb942006-11-06 18:07:30 +000025#include "system.h"
26#include "kernel.h"
Thomas Martitz22e802e2013-05-30 11:24:16 +020027#include "panic.h"
Michael Sevakis59abdb52013-06-29 19:27:21 -040028#include "string-extra.h"
Michael Sevakis48881312013-06-22 16:41:16 -040029#include "pcm_record.h"
30#include "codecs.h"
Michael Sevakis0f5cb942006-11-06 18:07:30 +000031#include "logf.h"
Andye5d08722005-06-19 03:05:53 +000032#include "thread.h"
Frank Gevaerts2f8a0082008-11-01 16:14:28 +000033#include "storage.h"
Michael Sevakis36c94052006-12-17 11:03:19 +000034#include "general.h"
Michael Sevakis65109732011-02-23 14:31:13 +000035#include "codec_thread.h"
Andye5d08722005-06-19 03:05:53 +000036#include "audio.h"
Michael Sevakis4fc717a2006-08-28 22:38:41 +000037#include "sound.h"
Björn Stenberg51b45d52008-10-15 06:38:51 +000038#include "metadata.h"
Jonathan Gordon7d5e0d72010-05-16 11:13:42 +000039#include "appevents.h"
Michael Sevakiscc50c142006-11-13 23:21:54 +000040#ifdef HAVE_SPDIF_IN
41#include "spdif.h"
42#endif
Michael Sevakis5857c442013-05-31 02:41:02 -040043#include "audio_thread.h"
Thomas Martitz22e802e2013-05-30 11:24:16 +020044#include "core_alloc.h"
45#include "talk.h"
Andye5d08722005-06-19 03:05:53 +000046
Michael Sevakis48881312013-06-22 16:41:16 -040047/* Macros to enable logf for queues
48 logging on SYS_TIMEOUT can be disabled */
49#ifdef SIMULATOR
50/* Define this for logf output of all queuing except SYS_TIMEOUT */
51#define PCMREC_LOGQUEUES
52/* Define this to logf SYS_TIMEOUT messages */
53/*#define PCMREC_LOGQUEUES_SYS_TIMEOUT*/
54#endif /* SIMULATOR */
Andye5d08722005-06-19 03:05:53 +000055
Michael Sevakis48881312013-06-22 16:41:16 -040056#ifdef PCMREC_LOGQUEUES
57#define LOGFQUEUE logf
58#else
59#define LOGFQUEUE(...)
Michael Sevakis7d00f972006-11-29 14:23:24 +000060#endif
Andye5d08722005-06-19 03:05:53 +000061
Michael Sevakis48881312013-06-22 16:41:16 -040062#ifdef PCMREC_LOGQUEUES_SYS_TIMEOUT
63#define LOGFQUEUE_SYS_TIMEOUT logf
64#else
65#define LOGFQUEUE_SYS_TIMEOUT(...)
66#endif
67
68/** Target-related configuration **/
69
70/**
71 * PCM_NUM_CHUNKS: Number of PCM chunks
72 * PCM_CHUNK_SAMP: Number of samples in a PCM chunk
73 * PCM_BOOST_SECONDS: PCM level at which to boost CPU
74 * PANIC_SECONDS: Flood watermark time until full
75 * FLUSH_SECONDS: Flush watermark time until full
76 * STREAM_BUF_SIZE: Size of stream write buffer
77 * PRIO_SECONDS: Max flush time before prio boost
78 *
79 * Total PCM buffer size should be mem aligned
80 *
81 * Fractions should be left without parentheses so the multiplier is
82 * multiplied by the numerator first.
83 */
84#if MEMORYSIZE <= 2
85#define PCM_NUM_CHUNKS 56
86#define PCM_CHUNK_SAMP 1024
87#define PCM_BOOST_SECONDS 1/2
88#define PANIC_SECONDS 1/2
89#define FLUSH_SECONDS 1
90#define FLUSH_MON_INTERVAL 1/6
91#define STREAM_BUF_SIZE 32768
92#elif MEMORYSIZE <= 16
93#define PANIC_SECONDS 5
94#define FLUSH_SECONDS 7
95#else /* MEMORYSIZE > 16 */
96#define PANIC_SECONDS 8
97#define FLUSH_SECONDS 10
98#endif /* MEMORYSIZE */
99
100/* Default values if not overridden above */
101#ifndef PCM_NUM_CHUNKS
102#define PCM_NUM_CHUNKS 256
103#endif
104#ifndef PCM_CHUNK_SAMP
105#define PCM_CHUNK_SAMP 2048
106#endif
107#ifndef PCM_BOOST_SECONDS
108#define PCM_BOOST_SECONDS 1
109#endif
110#ifndef FLUSH_MON_INTERVAL
111#define FLUSH_MON_INTERVAL 1/4
112#endif
113#ifndef STREAM_BUF_SIZE
114#define STREAM_BUF_SIZE 65536
115#endif
116#ifndef PRIO_SECONDS
117#define PRIO_SECONDS 10
118#endif
119
120/* FAT limit for filesize. Recording will accept no further data from the
121 * codec if this limit is reached in order to preserve its own data
122 * integrity. A split should have made by the higher-ups long before this
123 * point.
124 *
125 * Leave a generous 64k margin for metadata being added to file. */
126#define MAX_NUM_REC_BYTES ((size_t)0x7fff0000u)
127
128/***************************************************************************/
129extern struct codec_api ci; /* in codec_thread.c */
130extern struct event_queue audio_queue; /* in audio_thread.c */
131extern unsigned int audio_thread_id; /* in audio_thread.c */
132
133/** General recording state **/
134
135/* Recording action being performed */
136static enum record_status
Michael Sevakis0f5cb942006-11-06 18:07:30 +0000137{
Michael Sevakis48881312013-06-22 16:41:16 -0400138 RECORD_STOPPED = 0,
139 RECORD_PRERECORDING = AUDIO_STATUS_PRERECORD,
140 RECORD_RECORDING = AUDIO_STATUS_RECORD,
141 RECORD_PAUSED = (AUDIO_STATUS_RECORD | AUDIO_STATUS_PAUSE),
142} record_status = RECORD_STOPPED;
143
144/* State of engine operations */
145static enum record_state
146{
147 REC_STATE_IDLE, /* Stopped or prerecording */
148 REC_STATE_MONITOR, /* Monitoring buffer status */
149 REC_STATE_FLUSH, /* Flushing buffer */
150} record_state = REC_STATE_IDLE;
151
152static uint32_t errors; /* An error has occured (bitmask) */
153static uint32_t warnings; /* Non-fatal warnings (bitmask) */
154
155static uint32_t rec_errors; /* Mirror of errors but private to
156 * avoid race with controlling
157 * thread. Engine uses this
158 * internally. */
159
160/** Stats on encoded data for current file **/
161static int rec_fd = -1; /* Currently open file descriptor */
162static size_t num_rec_bytes; /* Number of bytes recorded */
163static uint64_t num_rec_samples; /* Number of PCM samples recorded */
164static uint64_t encbuf_rec_count; /* Count of slots written to buffer
165 for current file */
Andye5d08722005-06-19 03:05:53 +0000166
Michael Sevakis0f5cb942006-11-06 18:07:30 +0000167/** These apply to current settings **/
Michael Sevakis48881312013-06-22 16:41:16 -0400168static int rec_source; /* Current rec_source setting */
169static unsigned long sample_rate; /* Samplerate setting in HZ */
Michael Sevakis0f5cb942006-11-06 18:07:30 +0000170static int num_channels; /* Current number of channels */
171static struct encoder_config enc_config; /* Current encoder configuration */
Michael Sevakis48881312013-06-22 16:41:16 -0400172static unsigned int pre_record_seconds; /* Pre-record time in seconds */
Michael Sevakisa9ea1a42013-06-22 16:39:40 -0400173
Michael Sevakis4fc717a2006-08-28 22:38:41 +0000174/****************************************************************************
Michael Sevakis48881312013-06-22 16:41:16 -0400175 Use 2 circular buffers:
Michael Sevakis0f5cb942006-11-06 18:07:30 +0000176 pcm_buffer=DMA output buffer: chunks (8192 Bytes) of raw pcm audio data
Michael Sevakis4fc717a2006-08-28 22:38:41 +0000177 enc_buffer=encoded audio buffer: storage for encoder output data
Andye5d08722005-06-19 03:05:53 +0000178
Michael Sevakis4fc717a2006-08-28 22:38:41 +0000179 Flow:
Michael Sevakis48881312013-06-22 16:41:16 -0400180 1. When entering recording_screen DMA feeds the ringbuffer pcm_buffer
181 2. If enough pcm data are available the encoder codec does encoding of pcm
Michael Sevakis4fc717a2006-08-28 22:38:41 +0000182 chunks (4-8192 Bytes) into ringbuffer enc_buffer in codec_thread
183 3. pcmrec_callback detects enc_buffer 'near full' and writes data to disk
184
Michael Sevakis0f5cb942006-11-06 18:07:30 +0000185 Functions calls (basic encoder steps):
Michael Sevakis48881312013-06-22 16:41:16 -0400186 1.audio: codec_load(); load the encoder
187 2.encoder: enc_init_parameters(); set the encoder parameters (at load)
188 3.audio: enc_callback(); configure encoder recording settings
189 4.audio: codec_go(); start encoding the new stream
190 5.encoder: enc_encbuf_get_buffer(); obtain an output buffer of size n
191 6.encoder: enc_pcmbuf_read(); read n bytes of unprocessed pcm data
192 7.encoder: enc_encbuf_finish_buffer(); add the obtained buffer to output
193 8.encoder: enc_pcmbuf_advance(); advance pcm by n samples
194 9.encoder: while more PCM available, repeat 5. to 9.
195 10.audio: codec_finish_stream(); finish the output for current stream
Michael Sevakiseca9f7f2006-12-10 14:21:31 +0000196
Michael Sevakis48881312013-06-22 16:41:16 -0400197 Function calls (basic stream flushing steps through enc_callback()):
198 1.audio: flush_stream_start(); stream flush destination is opening
199 2.audio: flush_stream_data(); flush encoded audio to stream
200 3.audio: while encoded data available, repeat 2.
201 4.audio: flush_stream_end(); stream flush destination is closing
202
Michael Sevakis4fc717a2006-08-28 22:38:41 +0000203****************************************************************************/
Michael Sevakis4fc717a2006-08-28 22:38:41 +0000204
Michael Sevakis48881312013-06-22 16:41:16 -0400205/** Buffer parameters where incoming PCM data is placed **/
206#define PCM_DEPTH_BYTES (sizeof (int16_t))
207#define PCM_SAMP_SIZE (2*PCM_DEPTH_BYTES)
208#define PCM_CHUNK_SIZE (PCM_CHUNK_SAMP*PCM_SAMP_SIZE)
209#define PCM_BUF_SIZE (PCM_NUM_CHUNKS*PCM_CHUNK_SIZE)
210
211/* Convert byte sizes into buffer slot counts */
212#define CHUNK_SIZE_COUNT(size) \
213 (((size) + ENC_HDR_SIZE - 1) / ENC_HDR_SIZE)
214#define CHUNK_FILE_COUNT(size) \
215 ({ typeof (size) __size = (size); \
216 CHUNK_SIZE_COUNT(MIN(__size, MAX_PATH) + ENC_HDR_SIZE); })
217#define CHUNK_FILE_COUNT_PATH(path) \
218 CHUNK_FILE_COUNT(strlen(path) + 1)
219#define CHUNK_DATA_COUNT(size) \
220 CHUNK_SIZE_COUNT((size) + sizeof (struct enc_chunk_data))
221
222/* Min margin to write stream split headers without overwrap risk */
223#define ENCBUF_MIN_SPLIT_MARGIN \
224 (2*(1 + CHUNK_FILE_COUNT(MAX_PATH)) - 1)
225
226static void *rec_buffer; /* Root rec buffer pointer */
227static size_t rec_buffer_size; /* Root rec buffer size */
228
229static void *pcm_buffer; /* Circular buffer for PCM samples */
230static volatile bool pcm_pause; /* Freeze DMA write position */
231static volatile size_t pcm_widx; /* Current DMA write position */
232static volatile size_t pcm_ridx; /* Current PCM read position */
233
234static union enc_chunk_hdr *enc_buffer; /* Circular encoding buffer */
235static size_t enc_widx; /* Encoder chunk write index */
236static size_t enc_ridx; /* Encoder chunk read index */
237static size_t enc_buflen; /* Length of buffer in slots */
238
239static unsigned char *stream_buffer; /* Stream-to-disk write buffer */
240static ssize_t stream_buf_used; /* Stream write buffer occupancy */
241
242static struct enc_chunk_file *fname_buf;/* Buffer with next file to create */
243
244static unsigned long enc_sample_rate; /* Samplerate used by encoder */
245static bool pcm_buffer_empty; /* All PCM chunks processed? */
246
247static typeof (memcpy) *pcm_copyfn; /* PCM memcpy or copy_buffer_mono */
248static enc_callback_t enc_cb; /* Encoder's recording callback */
249
250/** File flushing **/
251static unsigned long encbuf_datarate; /* Rate of data per second */
252#if (CONFIG_STORAGE & STORAGE_ATA)
253static int spinup_time; /* Last spinup time */
Rafaël Carré020dddf2010-05-14 11:08:15 +0000254#endif
Michael Sevakis48881312013-06-22 16:41:16 -0400255static size_t high_watermark; /* Max limit for data flush */
Michael Sevakis0f5cb942006-11-06 18:07:30 +0000256
Michael Sevakis0d094bd2007-01-31 06:43:31 +0000257#ifdef HAVE_PRIORITY_SCHEDULING
Michael Sevakis48881312013-06-22 16:41:16 -0400258static size_t flood_watermark; /* Max limit for thread prio boost */
259static bool prio_boosted;
Michael Sevakis0d094bd2007-01-31 06:43:31 +0000260#endif
Michael Sevakis0f5cb942006-11-06 18:07:30 +0000261
Michael Sevakis48881312013-06-22 16:41:16 -0400262/** Stream marking **/
263enum mark_stream_action
Michael Sevakisec1f4822007-02-16 08:52:06 +0000264{
Michael Sevakis48881312013-06-22 16:41:16 -0400265 MARK_STREAM_END = 0x1, /* Mark end current stream */
266 MARK_STREAM_START = 0x2, /* Mark start of new stream */
267 MARK_STREAM_SPLIT = 0x3, /* Insert split; orr of above values */
268 MARK_STREAM_PRE = 0x4, /* Do prerecord data tally */
269 MARK_STREAM_START_PRE = MARK_STREAM_PRE | MARK_STREAM_START,
Michael Sevakisec1f4822007-02-16 08:52:06 +0000270};
271
Michael Sevakis48881312013-06-22 16:41:16 -0400272
Andye5d08722005-06-19 03:05:53 +0000273/***************************************************************************/
274
Michael Sevakis48881312013-06-22 16:41:16 -0400275/* Buffer pointer (p) to PCM sample memory address */
276static inline void * pcmbuf_ptr(size_t p)
Michael Sevakis0f5cb942006-11-06 18:07:30 +0000277{
Michael Sevakis48881312013-06-22 16:41:16 -0400278 return pcm_buffer + p;
279}
Michael Sevakis0f5cb942006-11-06 18:07:30 +0000280
Michael Sevakis48881312013-06-22 16:41:16 -0400281/* Buffer pointer (p) plus value (v), wrapped if necessary */
282static size_t pcmbuf_add(size_t p, size_t v)
Michael Sevakis5857c442013-05-31 02:41:02 -0400283{
Michael Sevakis48881312013-06-22 16:41:16 -0400284 size_t res = p + v;
285
286 if (res >= PCM_BUF_SIZE)
287 res -= PCM_BUF_SIZE;
288
289 return res;
290}
291
292/* Size of data in PCM buffer */
293size_t pcmbuf_used(void)
294{
295 size_t p1 = pcm_ridx;
296 size_t p2 = pcm_widx;
297
298 if (p1 > p2)
299 p2 += PCM_BUF_SIZE;
300
301 return p2 - p1;
302}
303
304/* Buffer pointer (p) to memory address of header */
305static inline union enc_chunk_hdr * encbuf_ptr(size_t p)
306{
307 return enc_buffer + p;
308}
309
310/* Buffer pointer (p) plus value (v), wrapped if necessary */
311static size_t encbuf_add(size_t p, size_t v)
312{
313 size_t res = p + v;
314
315 if (res >= enc_buflen)
316 res -= enc_buflen;
317
318 return res;
319}
320
321/* Number of free buffer slots */
322static size_t encbuf_free(void)
323{
324 size_t p1 = enc_ridx;
325 size_t p2 = enc_widx;
326
327 if (p2 >= p1)
328 p1 += enc_buflen;
329
330 return p1 - p2;
331}
332
333/* Number of used buffer slots */
334static size_t encbuf_used(void)
335{
336 size_t p1 = enc_ridx;
337 size_t p2 = enc_widx;
338
339 if (p1 > p2)
340 p2 += enc_buflen;
341
342 return p2 - p1;
343}
344
345/* Is the encoder buffer empty? */
346static bool encbuf_empty(void)
347{
348 return enc_ridx == enc_widx;
349}
350
351/* Buffer pointer (p) plus size (v), written to enc_widx, new widx
352 * zero-initialized */
353static void encbuf_widx_advance(size_t widx, size_t v)
354{
355 widx = encbuf_add(widx, v);
356 encbuf_ptr(widx)->zero = 0;
357 enc_widx = widx;
358}
359
360/* Buffer pointer (p) plus size of chunk at (p), wrapped to (0) if
361 * necessary.
362 *
363 * pout points to variable to receive increment result
364 *
365 * Returns NULL if it was a wrap marker */
366static void * encbuf_read_ptr_incr(size_t p, size_t *pout)
367{
368 union enc_chunk_hdr *hdr = encbuf_ptr(p);
369 size_t v;
370
371 switch (hdr->type)
372 {
373 case CHUNK_T_DATA:
374 v = CHUNK_DATA_COUNT(hdr->size);
375 break;
376 case CHUNK_T_STREAM_START:
377 v = hdr->size;
378 break;
379 case CHUNK_T_STREAM_END:
380 default:
381 v = 1;
382 break;
383 case CHUNK_T_WRAP:
384 /* Wrap markers are not returned but caller may have to know that
385 the index was changed since it impacts available space */
386 *pout = 0;
387 return NULL;
388 }
389
390 *pout = encbuf_add(p, v);
391 return hdr;
392}
393
394/* Buffer pointer (p) of contiguous free space (v), wrapped to (0) if
395 * necessary.
396 *
397 * pout points to variable to receive possible-adjusted p
398 *
399 * Returns header at (p) or wrapped header at (0) if wrap was
400 * required in order to provide contiguous space. Header is zero-
401 * initialized.
402 *
403 * Marks the wrap point if a wrap is required to make the allocation. */
404static void * encbuf_get_write_ptr(size_t p, size_t v, size_t *pout)
405{
406 union enc_chunk_hdr *hdr = encbuf_ptr(p);
407
408 if (p + v > enc_buflen)
409 {
410 hdr->type = CHUNK_T_WRAP; /* All other fields ignored */
411 p = 0;
412 hdr = encbuf_ptr(0);
413 }
414
415 *pout = p;
416 hdr->zero = 0;
417 return hdr;
418}
419
420/* Post a flush request to audio thread, if none is currently queued */
421static void encbuf_request_flush(void)
422{
423 if (!queue_peek_ex(&audio_queue, NULL, 0,
424 &(const long [2]){ Q_AUDIO_RECORD_FLUSH,
425 Q_AUDIO_RECORD_FLUSH }))
426 queue_post(&audio_queue, Q_AUDIO_RECORD_FLUSH, 0);
427}
428
429/* Set the error bits in (e): no lock */
430static inline void set_error_bits(uint32_t e)
431{
Michael Sevakis5857c442013-05-31 02:41:02 -0400432 errors |= e;
Michael Sevakis48881312013-06-22 16:41:16 -0400433 rec_errors |= e;
434}
435
436/* Clear the error bits in (e): no lock */
437static inline void clear_error_bits(uint32_t e)
438{
439 errors &= ~e;
440}
441
442/* Set the error bits in (e) */
443static void raise_error_status(uint32_t e)
444{
445 pcm_rec_lock();
446 set_error_bits(e);
Michael Sevakis5857c442013-05-31 02:41:02 -0400447 pcm_rec_unlock();
448}
449
Michael Sevakis48881312013-06-22 16:41:16 -0400450/* Clear the error bits in (e) */
451static void clear_error_status(uint32_t e)
452{
453 pcm_rec_lock();
454 clear_error_bits(e);
455 pcm_rec_unlock();
456}
457
458/* Set the warning bits in (w): no lock */
459static inline void set_warning_bits(uint32_t w)
Michael Sevakis5857c442013-05-31 02:41:02 -0400460{
461 warnings |= w;
462}
Michael Sevakisa9ea1a42013-06-22 16:39:40 -0400463
Michael Sevakis48881312013-06-22 16:41:16 -0400464/* Clear the warning bits in (w): no lock */
465static inline void clear_warning_bits(uint32_t w)
466{
467 warnings &= ~w;
468}
469
470/* Set the warning bits in (w) */
471static void raise_warning_status(uint32_t w)
472{
473 pcm_rec_lock();
474 set_warning_bits(w);
475 pcm_rec_unlock();
476}
477
478/* Clear the warning bits in (w) */
479static void clear_warning_status(uint32_t w)
480{
481 pcm_rec_lock();
482 clear_warning_bits(w);
483 pcm_rec_unlock();
484}
485
486/* Callback for when more data is ready - called by DMA ISR */
Michael Sevakis286a4c52012-02-23 08:14:46 -0500487static void pcm_rec_have_more(void **start, size_t *size)
Andye5d08722005-06-19 03:05:53 +0000488{
Michael Sevakis48881312013-06-22 16:41:16 -0400489 size_t next_idx = pcm_widx;
490
491 if (!pcm_pause)
Michael Sevakis0f5cb942006-11-06 18:07:30 +0000492 {
Michael Sevakis48881312013-06-22 16:41:16 -0400493 /* One empty chunk must remain after widx is advanced */
494 if (pcmbuf_used() <= PCM_BUF_SIZE - 2*PCM_CHUNK_SIZE)
495 next_idx = pcmbuf_add(next_idx, PCM_CHUNK_SIZE);
496 else
497 set_warning_bits(PCMREC_W_PCM_BUFFER_OVF);
Michael Sevakis0f5cb942006-11-06 18:07:30 +0000498 }
Michael Sevakis51189b42006-12-06 08:34:55 +0000499
Michael Sevakis48881312013-06-22 16:41:16 -0400500 *start = pcmbuf_ptr(next_idx);
Michael Sevakisd5699982010-05-24 16:42:32 +0000501 *size = PCM_CHUNK_SIZE;
Michael Sevakis48881312013-06-22 16:41:16 -0400502
503 pcm_widx = next_idx;
504}
Michael Sevakis4fc717a2006-08-28 22:38:41 +0000505
Michael Sevakis286a4c52012-02-23 08:14:46 -0500506static enum pcm_dma_status pcm_rec_status_callback(enum pcm_dma_status status)
507{
508 if (status < PCM_DMAST_OK)
509 {
Michael Sevakis48881312013-06-22 16:41:16 -0400510 /* Some error condition */
Michael Sevakis286a4c52012-02-23 08:14:46 -0500511 if (status == PCM_DMAST_ERR_DMA)
512 {
Michael Sevakis48881312013-06-22 16:41:16 -0400513 set_error_bits(PCMREC_E_DMA);
Michael Sevakis286a4c52012-02-23 08:14:46 -0500514 return status;
515 }
Michael Sevakis48881312013-06-22 16:41:16 -0400516 else
517 {
518 /* Try again next transmission - frame is invalid */
519 set_warning_bits(PCMREC_W_DMA);
520 }
Michael Sevakis286a4c52012-02-23 08:14:46 -0500521 }
522
523 return PCM_DMAST_OK;
Michael Sevakis0d768a32006-12-07 19:34:26 +0000524}
525
Michael Sevakis48881312013-06-22 16:41:16 -0400526/* Start DMA transfer */
527static void pcm_start_recording(void)
528{
529 pcm_record_data(pcm_rec_have_more, pcm_rec_status_callback,
530 pcmbuf_ptr(pcm_widx), PCM_CHUNK_SIZE);
531}
532
533/* Initialize the various recording buffers */
534static void init_rec_buffers(void)
535{
536 /* Layout of recording buffer: |PCMBUF|STREAMBUF|FILENAME|ENCBUF| */
537 void *buf = rec_buffer;
538 size_t size = rec_buffer_size;
539
540 /* PCMBUF */
541 pcm_buffer = CACHEALIGN_UP(buf); /* Line align */
542 size -= pcm_buffer + PCM_BUF_SIZE - buf;
543 buf = pcm_buffer + PCM_BUF_SIZE;
544
545 /* STREAMBUF */
546 stream_buffer = buf; /* Also line-aligned */
547 buf += STREAM_BUF_SIZE;
548 size -= STREAM_BUF_SIZE;
549
550 /* FILENAME */
551 fname_buf = buf;
552 buf += CHUNK_FILE_COUNT(MAX_PATH)*ENC_HDR_SIZE;
553 size -= CHUNK_FILE_COUNT(MAX_PATH)*ENC_HDR_SIZE;
554 fname_buf->hdr.zero = 0;
555
556 /* ENCBUF */
557 enc_buffer = buf;
558 enc_buflen = size;
559 ALIGN_BUFFER(enc_buffer, enc_buflen, ENC_HDR_SIZE);
560 enc_buflen = CHUNK_SIZE_COUNT(enc_buflen);
561}
562
563/* Reset the circular buffers */
564static void reset_fifos(bool hard)
565{
566 /* PCM FIFO */
567 pcm_pause = true;
568
569 if (hard)
570 pcm_widx = 0; /* Don't just empty but reset it */
571
572 pcm_ridx = pcm_widx;
573
574 /* Encoder FIFO */
575 encbuf_widx_advance(0, 0);
576 enc_ridx = 0;
577
578 /* No overflow-related warnings now */
579 clear_warning_status(PCMREC_W_PCM_BUFFER_OVF | PCMREC_W_ENC_BUFFER_OVF);
580}
581
582/* Initialize file statistics */
583static void reset_rec_stats(void)
584{
585 num_rec_bytes = 0;
586 num_rec_samples = 0;
587 encbuf_rec_count = 0;
588 clear_warning_status(PCMREC_W_FILE_SIZE);
589}
590
591/* Boost or unboost recording threads' priorities */
592static void do_prio_boost(bool boost)
593{
594#ifdef HAVE_PRIORITY_SCHEDULING
595 prio_boosted = boost;
596
597 int prio = PRIORITY_RECORDING;
598
599 if (boost)
600 prio -= 4;
601
602 codec_thread_set_priority(prio);
603 thread_set_priority(audio_thread_id, prio);
604#endif
605 (void)boost;
606}
607
608/* Reset all relevant state */
609static void init_state(void)
610{
611 reset_fifos(true);
612 reset_rec_stats();
613 do_prio_boost(false);
614 cancel_cpu_boost();
615 record_state = REC_STATE_IDLE;
616 record_status = RECORD_STOPPED;
617}
618
619/* Set hardware samplerate and save it */
620static void update_samplerate_config(unsigned long sampr)
621{
622 /* PCM samplerate is either the same as the setting or the nearest
623 one hardware supports if using S/PDIF */
624 unsigned long pcm_sampr = sampr;
625
626#ifdef HAVE_SPDIF_IN
627 if (rec_source == AUDIO_SRC_SPDIF)
628 {
629 int index = round_value_to_list32(sampr, hw_freq_sampr,
630 HW_NUM_FREQ, false);
631 pcm_sampr = hw_freq_sampr[index];
632 }
633#endif /* HAVE_SPDIF_IN */
634
635 pcm_set_frequency(pcm_sampr | SAMPR_TYPE_REC);
636 sample_rate = sampr;
637}
638
639/* Calculate the average data rate */
640static unsigned long get_encbuf_datarate(void)
641{
642 /* If not yet calculable, start with uncompressed PCM byterate */
643 if (num_rec_samples && sample_rate && encbuf_rec_count)
644 {
645 return (encbuf_rec_count*sample_rate + num_rec_samples - 1)
646 / num_rec_samples;
647 }
648 else
649 {
650 return CHUNK_SIZE_COUNT(sample_rate*num_channels*PCM_DEPTH_BYTES);
651 }
652}
653
654/* Returns true if the watermarks should be updated due to data rate
655 change */
656static bool monitor_encbuf_datarate(void)
657{
658 unsigned long rate = get_encbuf_datarate();
659 long diff = rate - encbuf_datarate;
660 /* Off by more than 1/2 FLUSH_MON_INTERVAL? */
661 return 2*(unsigned long)abs(diff) > encbuf_datarate*FLUSH_MON_INTERVAL;
662}
663
664/* Get adjusted spinup time */
665static int get_spinup_time(void)
666{
667 int spin = storage_spinup_time();
668
669#if (CONFIG_STORAGE & STORAGE_ATA)
670 /* Write at FLUSH_SECONDS + st remaining in enc_buffer - range fs+2s to
671 fs+10s total - default to 3.5s spinup. */
672 if (spin == 0)
673 spin = 35*HZ/10; /* default - cozy */
674 else if (spin < 2*HZ)
675 spin = 2*HZ; /* ludicrous - ramdisk? */
676 else if (spin > 10*HZ)
677 spin = 10*HZ; /* do you have a functioning HD? */
678#endif /* (CONFIG_STORAGE & STORAGE_ATA) */
679
680 return spin;
681}
682
683/* Returns true if the watermarks should be updated due to spinup time
684 change */
685static inline bool monitor_spinup_time(void)
686{
687#if (CONFIG_STORAGE & STORAGE_ATA)
688 return get_spinup_time() != spinup_time;
689#else
690 return false;
691#endif
692}
693
694/* Update buffer watermarks with spinup time compensation */
695static void refresh_watermarks(void)
696{
697 int spin = get_spinup_time();
698#if (CONFIG_STORAGE & STORAGE_ATA)
699 logf("ata spinup: %d", spin);
700 spinup_time = spin;
701#endif
702
703 unsigned long rate = get_encbuf_datarate();
704 logf("byterate: %lu", rate * ENC_HDR_SIZE);
705 encbuf_datarate = rate;
706
707 /* Try to start writing with FLUSH_SECONDS remaining after disk spinup */
708 high_watermark = (uint64_t)rate*(FLUSH_SECONDS*HZ + spin) / HZ;
709
710 if (high_watermark > enc_buflen)
711 high_watermark = enc_buflen;
712
713 high_watermark = enc_buflen - high_watermark;
714
715 logf("high wm: %lu", (unsigned long)high_watermark);
716
717#ifdef HAVE_PRIORITY_SCHEDULING
718 /* Boost thread priority if enough ground is lost since flushing started
719 or is taking an unreasonably long time */
720 flood_watermark = rate*PANIC_SECONDS;
721
722 if (flood_watermark > enc_buflen)
723 flood_watermark = enc_buflen;
724
725 flood_watermark = enc_buflen - flood_watermark;
726
727 logf("flood wm: %lu", (unsigned long)flood_watermark);
728#endif /* HAVE_PRIORITY_SCHEDULING */
729}
730
731/* Tell encoder the stream parameters and get information back */
732static bool configure_encoder_stream(void)
733{
734 struct enc_inputs inputs;
735 inputs.sample_rate = sample_rate;
736 inputs.num_channels = num_channels;
737 inputs.config = &enc_config;
738
739 /* encoder can change these - init with defaults */
740 inputs.enc_sample_rate = sample_rate;
741
742 if (enc_cb(ENC_CB_INPUTS, &inputs) < 0)
743 {
744 raise_error_status(PCMREC_E_ENC_SETUP);
745 return false;
746 }
747
748 enc_sample_rate = inputs.enc_sample_rate;
749
750 if (enc_sample_rate != sample_rate)
751 {
752 /* Codec doesn't want to/can't use the setting and has chosen a
753 different sample rate */
754 raise_warning_status(PCMREC_W_SAMPR_MISMATCH);
755 logf("enc sampr:%lu", enc_sample_rate);
756 }
757 else
758 {
759 clear_warning_status(PCMREC_W_SAMPR_MISMATCH);
760 }
761
762 refresh_watermarks();
763 return true;
764}
765
766#ifdef HAVE_SPDIF_IN
767/* Return the S/PDIF sample rate closest to a value in the master list */
768static unsigned long get_spdif_samplerate(void)
769{
770 unsigned long sr = spdif_measure_frequency();
771 int index = round_value_to_list32(sr, audio_master_sampr_list,
772 SAMPR_NUM_FREQ, false);
773 return audio_master_sampr_list[index];
774}
775
776/* Check the S/PDIF rate and compare to current setting. Apply the new
777 * rate if it changed. */
778static void check_spdif_samplerate(void)
779{
780 unsigned long sampr = get_spdif_samplerate();
781
782 if (sampr == sample_rate)
783 return;
784
785 codec_stop();
786 pcm_stop_recording();
787 reset_fifos(true);
788 reset_rec_stats();
789 update_samplerate_config(sampr);
790 pcm_apply_settings();
791
792 if (!configure_encoder_stream() || rec_errors)
793 return;
794
795 pcm_start_recording();
796
797 if (record_status == RECORD_PRERECORDING)
798 {
799 codec_go();
800 pcm_pause = false;
801 }
802}
803#endif /* HAVE_SPDIF_IN */
804
805/* Discard the stream buffer contents */
806static inline void stream_discard_buf(void)
807{
808 stream_buf_used = 0;
809}
810
811/* Flush stream buffer to disk */
812static bool stream_flush_buf(void)
813{
814 if (stream_buf_used == 0)
815 return true;
816
817 ssize_t rc = write(rec_fd, stream_buffer, stream_buf_used);
818
819 if (LIKELY(rc == stream_buf_used))
820 {
821 stream_discard_buf();
822 return true;
823 }
824
825 if (rc > 0)
826 {
827 /* Some was written; keep in sync */
828 stream_buf_used -= rc;
829 memmove(stream_buffer, stream_buffer + rc, stream_buf_used);
830 }
831
832 return false;
833}
834
835/* Close the output file */
836static void close_rec_file(void)
837{
838 if (rec_fd < 0)
839 return;
840
841 bool ok = stream_flush_buf();
842
843 if (close(rec_fd) != 0 || !ok)
844 raise_error_status(PCMREC_E_IO);
845
846 rec_fd = -1;
847}
848
849/* Creates or opens the current path */
850static bool open_rec_file(bool create)
851{
852 if (rec_fd >= 0)
853 {
854 /* Any previous file should have been closed */
855 logf("open file: file already open");
856 close_rec_file();
857 }
858
859 stream_discard_buf();
860 int oflags = create ? O_CREAT|O_TRUNC : 0;
861 rec_fd = open(fname_buf->path, O_RDWR|oflags, 0666);
862
863 if (rec_fd < 0)
864 {
865 raise_error_status(PCMREC_E_IO);
866 return false;
867 }
868
869 return true;
870}
871
872/* Copy with mono conversion - output 1/2 size of input */
873static void * ICODE_ATTR
874copy_buffer_mono_lr(void *dst, const void *src, size_t src_size)
875{
876 int16_t *d = dst;
877 int16_t const *s = src;
878
879 /* mono = (L + R) / 2 */
880 do
881 *d++ = ((int32_t){ *s++ } + *s++ + 1) >> 1;
882 while (src_size -= PCM_SAMP_SIZE);
883
884 return dst;
885}
886
887/* Copy with mono conversion - output 1/2 size of input */
888static void * ICODE_ATTR
889copy_buffer_mono_l(void *dst, const void *src, size_t src_size)
890{
891 int16_t *d = dst;
892 int16_t const *s = (int16_t *)src - 2;
893
894 /* mono = L */
895 do
896 *d++ = *(s += 2);
897 while (src_size -= PCM_SAMP_SIZE);
898
899 return dst;
900}
901
902/* Copy with mono conversion - output 1/2 size of input */
903static void * ICODE_ATTR
904copy_buffer_mono_r(void *dst, const void *src, size_t src_size)
905{
906 int16_t *d = dst;
907 int16_t const *s = (int16_t *)src - 1;
908
909 /* mono = R */
910 do
911 *d++ = *(s += 2);
912 while (src_size -= PCM_SAMP_SIZE);
913
914 return dst;
915}
916
917
Michael Sevakis0f5cb942006-11-06 18:07:30 +0000918/** pcm_rec_* group **/
Michael Sevakiseca9f7f2006-12-10 14:21:31 +0000919
Michael Sevakis48881312013-06-22 16:41:16 -0400920/* Clear all errors and warnings */
Michael Sevakis0f5cb942006-11-06 18:07:30 +0000921void pcm_rec_error_clear(void)
922{
Michael Sevakis48881312013-06-22 16:41:16 -0400923 clear_error_status(PCMREC_E_ALL);
924 clear_warning_status(PCMREC_W_ALL);
925}
Andye5d08722005-06-19 03:05:53 +0000926
Michael Sevakis48881312013-06-22 16:41:16 -0400927/* Check mode, errors and warnings */
Michael Sevakis5857c442013-05-31 02:41:02 -0400928unsigned int pcm_rec_status(void)
Andye5d08722005-06-19 03:05:53 +0000929{
Michael Sevakis48881312013-06-22 16:41:16 -0400930 unsigned int ret = record_status;
Michael Sevakis0f5cb942006-11-06 18:07:30 +0000931
Michael Sevakiseca9f7f2006-12-10 14:21:31 +0000932 if (errors)
Andye6e54962005-11-12 04:00:56 +0000933 ret |= AUDIO_STATUS_ERROR;
Michael Sevakis0f5cb942006-11-06 18:07:30 +0000934
Michael Sevakiseca9f7f2006-12-10 14:21:31 +0000935 if (warnings)
936 ret |= AUDIO_STATUS_WARNING;
Christian Gmeiner14e80672005-08-06 10:12:19 +0000937
Andye5d08722005-06-19 03:05:53 +0000938 return ret;
Michael Sevakis48881312013-06-22 16:41:16 -0400939}
Andye5d08722005-06-19 03:05:53 +0000940
Michael Sevakis48881312013-06-22 16:41:16 -0400941/* Return warnings that have occured since recording started */
942uint32_t pcm_rec_get_warnings(void)
Michael Sevakiseca9f7f2006-12-10 14:21:31 +0000943{
944 return warnings;
945}
946
Michael Sevakis7d00f972006-11-29 14:23:24 +0000947#ifdef HAVE_SPDIF_IN
Michael Sevakis48881312013-06-22 16:41:16 -0400948/* Return the currently-configured sample rate */
Michael Sevakis0f5cb942006-11-06 18:07:30 +0000949unsigned long pcm_rec_sample_rate(void)
950{
Michael Sevakis0f5cb942006-11-06 18:07:30 +0000951 return sample_rate;
Michael Sevakis48881312013-06-22 16:41:16 -0400952}
Michael Sevakis7d00f972006-11-29 14:23:24 +0000953#endif
Michael Sevakis0f5cb942006-11-06 18:07:30 +0000954
Michael Sevakis48881312013-06-22 16:41:16 -0400955
Michael Sevakis0f5cb942006-11-06 18:07:30 +0000956/** audio_* group **/
957
Michael Sevakis48881312013-06-22 16:41:16 -0400958/* Initializes recording - call before calling any other recording function */
Thomas Martitz8a701e52011-08-14 15:37:05 +0000959void audio_init_recording(void)
Michael Sevakis0f5cb942006-11-06 18:07:30 +0000960{
Michael Sevakis48881312013-06-22 16:41:16 -0400961 LOGFQUEUE("audio >| pcmrec Q_AUDIO_INIT_RECORDING");
962 audio_queue_send(Q_AUDIO_INIT_RECORDING, 1);
963}
Michael Sevakis0f5cb942006-11-06 18:07:30 +0000964
Michael Sevakis48881312013-06-22 16:41:16 -0400965/* Closes recording - call audio_stop_recording first or risk data loss */
Michael Sevakis0f5cb942006-11-06 18:07:30 +0000966void audio_close_recording(void)
967{
Michael Sevakis48881312013-06-22 16:41:16 -0400968 LOGFQUEUE("audio >| pcmrec Q_AUDIO_CLOSE_RECORDING");
969 audio_queue_send(Q_AUDIO_CLOSE_RECORDING, 0);
970}
Michael Sevakis4fc717a2006-08-28 22:38:41 +0000971
Michael Sevakis48881312013-06-22 16:41:16 -0400972/* Sets recording parameters */
Michael Sevakiseca9f7f2006-12-10 14:21:31 +0000973void audio_set_recording_options(struct audio_recording_options *options)
974{
Michael Sevakis48881312013-06-22 16:41:16 -0400975 LOGFQUEUE("audio >| pcmrec Q_AUDIO_RECORDING_OPTIONS");
976 audio_queue_send(Q_AUDIO_RECORDING_OPTIONS, (intptr_t)options);
977}
Michael Sevakiseca9f7f2006-12-10 14:21:31 +0000978
Michael Sevakis48881312013-06-22 16:41:16 -0400979/* Start recording if not recording or else split */
Michael Sevakiseca9f7f2006-12-10 14:21:31 +0000980void audio_record(const char *filename)
981{
Michael Sevakis48881312013-06-22 16:41:16 -0400982 LOGFQUEUE("audio >| pcmrec Q_AUDIO_RECORD: %s", filename);
983 audio_queue_send(Q_AUDIO_RECORD, (intptr_t)filename);
984}
Michael Sevakiseca9f7f2006-12-10 14:21:31 +0000985
Michael Sevakis48881312013-06-22 16:41:16 -0400986/* audio_record alias for API compatibility with HW codec */
Michael Sevakis2d48d0f2007-06-08 23:42:04 +0000987void audio_new_file(const char *filename)
Michael Sevakis48881312013-06-22 16:41:16 -0400988 __attribute__((alias("audio_record")));
Michael Sevakis2d48d0f2007-06-08 23:42:04 +0000989
Michael Sevakis48881312013-06-22 16:41:16 -0400990/* Stop current recording if recording */
Michael Sevakiseca9f7f2006-12-10 14:21:31 +0000991void audio_stop_recording(void)
992{
Michael Sevakis48881312013-06-22 16:41:16 -0400993 LOGFQUEUE("audio > pcmrec Q_AUDIO_RECORD_STOP");
994 audio_queue_post(Q_AUDIO_RECORD_STOP, 0);
995}
Michael Sevakiseca9f7f2006-12-10 14:21:31 +0000996
Michael Sevakis48881312013-06-22 16:41:16 -0400997/* Pause current recording */
Michael Sevakiseca9f7f2006-12-10 14:21:31 +0000998void audio_pause_recording(void)
999{
Michael Sevakis48881312013-06-22 16:41:16 -04001000 LOGFQUEUE("audio > pcmrec Q_AUDIO_RECORD_PAUSE");
1001 audio_queue_post(Q_AUDIO_RECORD_PAUSE, 0);
1002}
Michael Sevakiseca9f7f2006-12-10 14:21:31 +00001003
Michael Sevakis48881312013-06-22 16:41:16 -04001004/* Resume current recording if paused */
Michael Sevakiseca9f7f2006-12-10 14:21:31 +00001005void audio_resume_recording(void)
1006{
Michael Sevakis48881312013-06-22 16:41:16 -04001007 LOGFQUEUE("audio > pcmrec Q_AUDIO_RECORD_RESUME");
1008 audio_queue_post(Q_AUDIO_RECORD_RESUME, 0);
1009}
Michael Sevakiseca9f7f2006-12-10 14:21:31 +00001010
Michael Sevakis48881312013-06-22 16:41:16 -04001011/* Set the input source gain. For mono sources, only left gain is used */
Michael Sevakis36c94052006-12-17 11:03:19 +00001012void audio_set_recording_gain(int left, int right, int type)
1013{
Michael Sevakis48881312013-06-22 16:41:16 -04001014#if 0
1015 logf("pcmrec: t=%d l=%d r=%d", type, left, right);
1016#endif
Michael Sevakis36c94052006-12-17 11:03:19 +00001017 audiohw_set_recvol(left, right, type);
Michael Sevakis48881312013-06-22 16:41:16 -04001018}
1019
Michael Sevakis36c94052006-12-17 11:03:19 +00001020
Michael Sevakiseca9f7f2006-12-10 14:21:31 +00001021/** Information about current state **/
1022
Michael Sevakis48881312013-06-22 16:41:16 -04001023/* Return sample clock in HZ */
1024static unsigned long get_samples_time(void)
Andye5d08722005-06-19 03:05:53 +00001025{
Michael Sevakis48881312013-06-22 16:41:16 -04001026 if (enc_sample_rate == 0)
Michael Sevakis7d00f972006-11-29 14:23:24 +00001027 return 0;
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001028
Michael Sevakis48881312013-06-22 16:41:16 -04001029 return (unsigned long)(HZ*num_rec_samples / enc_sample_rate);
1030}
Andye5d08722005-06-19 03:05:53 +00001031
Michael Sevakis48881312013-06-22 16:41:16 -04001032/* Return current prerecorded time in ticks (playback equivalent time) */
1033unsigned long audio_prerecorded_time(void)
1034{
1035 if (record_status != RECORD_PRERECORDING)
1036 return 0;
1037
1038 unsigned long t = get_samples_time();
1039 return MIN(t, pre_record_seconds*HZ);
1040}
1041
1042/* Return current recorded time in ticks (playback equivalent time) */
1043unsigned long audio_recorded_time(void)
1044{
1045 if (record_state == REC_STATE_IDLE)
1046 return 0;
1047
1048 return get_samples_time();
1049}
1050
1051/* Return number of bytes encoded to output */
Andye6e54962005-11-12 04:00:56 +00001052unsigned long audio_num_recorded_bytes(void)
Andye5d08722005-06-19 03:05:53 +00001053{
Michael Sevakis48881312013-06-22 16:41:16 -04001054 if (record_state == REC_STATE_IDLE)
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001055 return 0;
Andye5d08722005-06-19 03:05:53 +00001056
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001057 return num_rec_bytes;
Michael Sevakis48881312013-06-22 16:41:16 -04001058}
Michael Sevakisa9ea1a42013-06-22 16:39:40 -04001059
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001060
1061/** Data Flushing **/
1062
Michael Sevakis48881312013-06-22 16:41:16 -04001063/* Stream start chunk with path was encountered */
1064static void flush_stream_start(struct enc_chunk_file *file)
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001065{
Michael Sevakis48881312013-06-22 16:41:16 -04001066 /* Save filename; don't open file here which avoids creating files
1067 with no audio content. Splitting while paused can create those
1068 in large numbers. */
1069 fname_buf->hdr = file->hdr;
1070 /* Correct size if this was wrap-padded */
1071 fname_buf->hdr.size = CHUNK_FILE_COUNT(
1072 strlcpy(fname_buf->path, file->path, MAX_PATH) + 1);
1073}
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001074
Michael Sevakis48881312013-06-22 16:41:16 -04001075/* Data chunk was encountered */
1076static bool flush_stream_data(struct enc_chunk_data *data)
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001077{
Michael Sevakis48881312013-06-22 16:41:16 -04001078 if (fname_buf->hdr.zero)
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001079 {
Michael Sevakis48881312013-06-22 16:41:16 -04001080 /* First data chunk; create the file */
1081 if (open_rec_file(true))
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001082 {
Michael Sevakis48881312013-06-22 16:41:16 -04001083 /* Inherit some flags from initial data chunk */
1084 fname_buf->hdr.err = data->hdr.err;
1085 fname_buf->hdr.pre = data->hdr.pre;
1086 fname_buf->hdr.aux0 = data->hdr.aux0;
1087
1088 if (enc_cb(ENC_CB_STREAM, fname_buf) < 0)
1089 raise_error_status(PCMREC_E_ENCODER_STREAM);
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001090 }
Michael Sevakis48881312013-06-22 16:41:16 -04001091
1092 fname_buf->hdr.zero = 0;
1093
1094 if (rec_errors)
1095 return false;
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001096 }
1097
Michael Sevakis48881312013-06-22 16:41:16 -04001098 if (rec_fd < 0)
1099 return true; /* Just keep discarding */
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001100
Michael Sevakis48881312013-06-22 16:41:16 -04001101 if (enc_cb(ENC_CB_STREAM, data) < 0)
1102 {
1103 raise_error_status(PCMREC_E_ENCODER_STREAM);
1104 return false;
1105 }
Andye5d08722005-06-19 03:05:53 +00001106
Michael Sevakis48881312013-06-22 16:41:16 -04001107 return true;
1108}
1109
1110/* Stream end chunk was encountered */
1111static bool flush_stream_end(union enc_chunk_hdr *hdr)
1112{
1113 if (rec_fd < 0)
1114 return true;
1115
1116 if (enc_cb(ENC_CB_STREAM, hdr) < 0)
1117 {
1118 raise_error_status(PCMREC_E_ENCODER_STREAM);
1119 return false;
1120 }
1121
1122 close_rec_file();
1123 return true;
1124}
1125
1126/* Discard remainder of stream in encoder buffer */
1127static void discard_stream(void)
1128{
1129 /* Discard everything up until the next non-data chunk */
1130 while (!encbuf_empty())
1131 {
1132 size_t ridx;
1133 union enc_chunk_hdr *hdr = encbuf_read_ptr_incr(enc_ridx, &ridx);
1134
1135 if (hdr && hdr->type != CHUNK_T_DATA)
1136 {
1137 if (hdr->type != CHUNK_T_STREAM_START)
1138 enc_ridx = ridx;
1139 break;
1140 }
1141
1142 enc_ridx = ridx;
1143 }
1144
1145 /* Try to finish header by closing and reopening the file. A seek or
1146 other operation will likely fail because buffers will need to be
1147 flushed (here and in file code). That will likely fail but a close
1148 will just close the fd and discard everything. We reopen with what
1149 actually made it to disk. Modifying existing file contents will
1150 more than likely succeed even on a full disk. The result might not
1151 be entirely correct as far as the headers' sizes and counts unless
1152 the codec can correct that but the sample format information
1153 should be. */
1154 if (rec_fd >= 0 && open_rec_file(false))
1155 {
1156 /* Synthesize a special end chunk here */
1157 union enc_chunk_hdr end;
1158 end.zero = 0;
1159 end.err = 1; /* Codec should try to correct anything that's off */
1160 end.type = CHUNK_T_STREAM_END;
1161 if (!flush_stream_end(&end))
1162 close_rec_file();
1163 }
1164}
1165
1166/* Flush a chunk to disk
Michael Sevakisec1f4822007-02-16 08:52:06 +00001167 *
Michael Sevakis48881312013-06-22 16:41:16 -04001168 * Transitions state from REC_STATE_MONITOR to REC_STATE_FLUSH when buffer
1169 * is filling. 'margin' is fullness threshold that transitions to flush state.
1170 *
1171 * Call with REC_STATE_IDLE to indicate a forced flush which flushes buffer
1172 * to less than 'margin'.
Michael Sevakisec1f4822007-02-16 08:52:06 +00001173 */
Michael Sevakis48881312013-06-22 16:41:16 -04001174static enum record_state flush_chunk(enum record_state state, size_t margin)
Michael Sevakisec1f4822007-02-16 08:52:06 +00001175{
Michael Sevakis48881312013-06-22 16:41:16 -04001176#ifdef HAVE_PRIORITY_SCHEDULING
1177 static unsigned long prio_tick; /* Timeout for auto boost */
1178#endif
Michael Sevakisec1f4822007-02-16 08:52:06 +00001179
Michael Sevakis48881312013-06-22 16:41:16 -04001180 size_t used = encbuf_used();
1181
1182 switch (state)
1183 {
1184 case REC_STATE_MONITOR:
1185 if (monitor_encbuf_datarate() || monitor_spinup_time())
1186 refresh_watermarks();
1187
1188 if (used < margin)
1189 return REC_STATE_MONITOR;
1190
1191 state = REC_STATE_FLUSH;
1192 trigger_cpu_boost();
Michael Sevakisec1f4822007-02-16 08:52:06 +00001193
1194#ifdef HAVE_PRIORITY_SCHEDULING
Michael Sevakis48881312013-06-22 16:41:16 -04001195 prio_tick = current_tick + PRIO_SECONDS*HZ;
Rafaël Carré020dddf2010-05-14 11:08:15 +00001196#if (CONFIG_STORAGE & STORAGE_ATA)
Michael Sevakis48881312013-06-22 16:41:16 -04001197 prio_tick += spinup_time;
Rafaël Carré020dddf2010-05-14 11:08:15 +00001198#endif
Michael Sevakis48881312013-06-22 16:41:16 -04001199#endif /* HAVE_PRIORITY_SCHEDULING */
Michael Sevakisec1f4822007-02-16 08:52:06 +00001200
Michael Sevakis48881312013-06-22 16:41:16 -04001201 /* Fall-through */
1202 case REC_STATE_IDLE: /* As a hint for "forced" */
1203 if (used < margin)
1204 break;
Michael Sevakisec1f4822007-02-16 08:52:06 +00001205
Michael Sevakis48881312013-06-22 16:41:16 -04001206 /* Fall-through */
1207 case REC_STATE_FLUSH:
Michael Sevakis0d094bd2007-01-31 06:43:31 +00001208#ifdef HAVE_PRIORITY_SCHEDULING
Michael Sevakis48881312013-06-22 16:41:16 -04001209 if (!prio_boosted && state != REC_STATE_IDLE &&
1210 (used >= flood_watermark || TIME_AFTER(current_tick, prio_tick)))
1211 do_prio_boost(true);
1212#endif /* HAVE_PRIORITY_SCHEDULING */
Peter D'Hoye9ace16f2006-02-24 22:28:57 +00001213
Michael Sevakis48881312013-06-22 16:41:16 -04001214 while (used)
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001215 {
Michael Sevakis48881312013-06-22 16:41:16 -04001216 union enc_chunk_hdr *hdr = encbuf_ptr(enc_ridx);
1217 size_t count = 0;
Michael Sevakisec1f4822007-02-16 08:52:06 +00001218
Michael Sevakis48881312013-06-22 16:41:16 -04001219 switch (hdr->type)
1220 {
1221 case CHUNK_T_DATA:
1222 if (flush_stream_data(ENC_DATA_HDR(hdr)))
1223 count = CHUNK_DATA_COUNT(hdr->size);
1224 break;
Michael Sevakisec1f4822007-02-16 08:52:06 +00001225
Michael Sevakis48881312013-06-22 16:41:16 -04001226 case CHUNK_T_STREAM_START:
1227 /* Doesn't do stream writes */
1228 flush_stream_start(ENC_FILE_HDR(hdr));
1229 count = hdr->size;
1230 break;
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001231
Michael Sevakis48881312013-06-22 16:41:16 -04001232 case CHUNK_T_STREAM_END:
1233 if (flush_stream_end(hdr))
1234 count = 1;
1235 break;
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001236
Michael Sevakis48881312013-06-22 16:41:16 -04001237 case CHUNK_T_WRAP:
1238 enc_ridx = 0;
1239 used = encbuf_used();
1240 continue;
1241 }
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001242
Michael Sevakis48881312013-06-22 16:41:16 -04001243 if (count)
1244 enc_ridx = encbuf_add(enc_ridx, count);
1245 else
1246 discard_stream();
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001247
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001248 break;
Peter D'Hoye85058f52007-10-10 23:26:17 +00001249 }
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001250
Michael Sevakis48881312013-06-22 16:41:16 -04001251 if (!encbuf_empty())
1252 return state;
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001253
Michael Sevakis48881312013-06-22 16:41:16 -04001254 break;
Andye5d08722005-06-19 03:05:53 +00001255 }
Andye5d08722005-06-19 03:05:53 +00001256
Michael Sevakis48881312013-06-22 16:41:16 -04001257 if (encbuf_empty())
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001258 {
Michael Sevakis48881312013-06-22 16:41:16 -04001259 do_prio_boost(false);
1260 cancel_cpu_boost();
1261 }
Michael Sevakis4fc717a2006-08-28 22:38:41 +00001262
Michael Sevakis48881312013-06-22 16:41:16 -04001263 return REC_STATE_MONITOR;
1264}
Christian Gmeiner14e80672005-08-06 10:12:19 +00001265
Michael Sevakis48881312013-06-22 16:41:16 -04001266/* Monitor buffer and finish stream, freeing-up space at the same time */
1267static void finish_stream(bool stopping)
1268{
1269 size_t threshold = stopping ? 1 : enc_buflen - ENCBUF_MIN_SPLIT_MARGIN;
1270 enum record_state state = REC_STATE_MONITOR;
1271 size_t need = 1;
1272
1273 while (1)
1274 {
1275 switch (state)
1276 {
1277 case REC_STATE_IDLE:
1278 state = flush_chunk(state, threshold);
1279 continue;
1280
1281 default:
1282 if (!need)
1283 break;
1284
1285 if (!stopping || pcm_buffer_empty)
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001286 {
Michael Sevakis48881312013-06-22 16:41:16 -04001287 need = codec_finish_stream();
Christian Gmeiner14e80672005-08-06 10:12:19 +00001288
Michael Sevakis48881312013-06-22 16:41:16 -04001289 if (need)
1290 {
1291 need = 2*CHUNK_DATA_COUNT(need) - 1;
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001292
Michael Sevakis48881312013-06-22 16:41:16 -04001293 if (need >= enc_buflen)
1294 {
1295 need = 0;
1296 codec_stop();
1297 threshold = 1;
1298 }
1299 else if (threshold > enc_buflen - need)
1300 {
1301 threshold = enc_buflen - need;
1302 }
1303 }
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001304 }
1305
Michael Sevakis48881312013-06-22 16:41:16 -04001306 if (!need || encbuf_used() >= threshold)
1307 state = REC_STATE_IDLE; /* Start flush */
1308 else
1309 sleep(HZ/10); /* Don't flood with pings */
1310
1311 continue;
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001312 }
1313
Michael Sevakis48881312013-06-22 16:41:16 -04001314 break;
1315 }
1316}
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001317
Michael Sevakis48881312013-06-22 16:41:16 -04001318/* Start a new stream, transistion to a new one or end the current one */
1319static void mark_stream(const char *path, enum mark_stream_action action)
1320{
1321 if (action & MARK_STREAM_END)
1322 {
1323 size_t widx;
1324 union enc_chunk_hdr *hdr = encbuf_get_write_ptr(enc_widx, 1, &widx);
1325 hdr->type = CHUNK_T_STREAM_END;
1326 encbuf_widx_advance(widx, 1);
Andye5d08722005-06-19 03:05:53 +00001327 }
Michael Sevakisec1f4822007-02-16 08:52:06 +00001328
Michael Sevakis48881312013-06-22 16:41:16 -04001329 if (action & MARK_STREAM_START)
1330 {
1331 size_t count = CHUNK_FILE_COUNT_PATH(path);
1332 struct enc_chunk_file *file;
1333 size_t widx;
1334
1335 if (action & MARK_STREAM_PRE)
1336 {
1337 /* Prerecord: START marker goes first or before existing data */
1338 if (enc_ridx < count)
1339 {
1340 /* Adjust to occupy end of buffer and pad accordingly */
1341 count += enc_ridx;
1342 enc_ridx += enc_buflen;
1343 }
1344
1345 enc_ridx -= count;
1346
1347 /* Won't adjust p since enc_ridx is already set as non-wrapping */
1348 file = encbuf_get_write_ptr(enc_ridx, count, &widx);
1349 }
1350 else
1351 {
1352 /* The usual: START marker goes first or after existing data */
1353 file = encbuf_get_write_ptr(enc_widx, count, &widx);
1354 encbuf_widx_advance(widx, count);
1355 }
1356
1357 file->hdr.type = CHUNK_T_STREAM_START;
1358 file->hdr.size = count;
1359 strlcpy(file->path, path, MAX_PATH);
1360 }
1361}
1362
1363/* Tally-up and keep the required amount of prerecord data.
1364 * Updates record stats accordingly. */
1365static void tally_prerecord_data(void)
1366{
1367 unsigned long count = 0;
1368 size_t bytes = 0;
1369 unsigned long samples = 0;
1370
1371 /* Find out how much is there */
1372 for (size_t idx = enc_ridx; idx != enc_widx;)
1373 {
1374 struct enc_chunk_data *data = encbuf_read_ptr_incr(idx, &idx);
1375
1376 if (!data)
1377 continue;
1378
1379 count += CHUNK_DATA_COUNT(data->hdr.size);
1380 bytes += data->hdr.size;
1381 samples += data->pcm_count;
1382 }
1383
1384 /* Have too much? Discard oldest data. */
1385 unsigned long pre_samples = enc_sample_rate*pre_record_seconds;
1386
1387 while (samples > pre_samples)
1388 {
1389 struct enc_chunk_data *data =
1390 encbuf_read_ptr_incr(enc_ridx, &enc_ridx);
1391
1392 if (!data)
1393 continue;
1394
1395 count -= CHUNK_DATA_COUNT(data->hdr.size);
1396 bytes -= data->hdr.size;
1397 samples -= data->pcm_count;
1398 }
1399
1400 encbuf_rec_count = count;
1401 num_rec_bytes = bytes;
1402 num_rec_samples = samples;
1403}
Christian Gmeiner14e80672005-08-06 10:12:19 +00001404
Michael Sevakis5857c442013-05-31 02:41:02 -04001405
Michael Sevakis48881312013-06-22 16:41:16 -04001406/** Event handlers for recording thread **/
Andye5d08722005-06-19 03:05:53 +00001407
Thomas Martitz22e802e2013-05-30 11:24:16 +02001408static int pcmrec_handle;
Michael Sevakis48881312013-06-22 16:41:16 -04001409/* Q_AUDIO_INIT_RECORDING */
1410static void on_init_recording(void)
Andye5d08722005-06-19 03:05:53 +00001411{
Jonathan Gordon7d5e0d72010-05-16 11:13:42 +00001412 send_event(RECORDING_EVENT_START, NULL);
Thomas Martitz22e802e2013-05-30 11:24:16 +02001413 /* dummy ops with no callbacks, needed because by
1414 * default buflib buffers can be moved around which must be avoided
1415 * FIXME: This buffer should play nicer and be shrinkable/movable */
1416 static struct buflib_callbacks dummy_ops;
1417 talk_buffer_set_policy(TALK_BUFFER_LOOSE);
1418 pcmrec_handle = core_alloc_maximum("pcmrec", &rec_buffer_size, &dummy_ops);
Thomas Martitza56837b2013-12-24 10:20:13 +01001419 if (pcmrec_handle <= 0)
Thomas Martitz22e802e2013-05-30 11:24:16 +02001420 /* someone is abusing core_alloc_maximum(). Fix this evil guy instead of
1421 * trying to handle OOM without hope */
1422 panicf("%s(): OOM\n", __func__);
1423 rec_buffer = core_get_data(pcmrec_handle);
Michael Sevakis48881312013-06-22 16:41:16 -04001424 init_rec_buffers();
1425 init_state();
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001426 pcm_init_recording();
Michael Sevakis48881312013-06-22 16:41:16 -04001427}
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001428
Michael Sevakis48881312013-06-22 16:41:16 -04001429/* Q_AUDIO_CLOSE_RECORDING */
1430static void on_close_recording(void)
Andye5d08722005-06-19 03:05:53 +00001431{
Michael Sevakis48881312013-06-22 16:41:16 -04001432 /* Simply shut down the recording system. Whatever wasn't saved is
1433 lost. */
Michael Sevakis5857c442013-05-31 02:41:02 -04001434 codec_unload();
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001435 pcm_close_recording();
Michael Sevakis48881312013-06-22 16:41:16 -04001436 close_rec_file();
1437 init_state();
1438
1439 rec_errors = 0;
1440 pcm_rec_error_clear();
1441
1442 /* Reset PCM to defaults */
1443 pcm_set_frequency(HW_SAMPR_RESET | SAMPR_TYPE_REC);
1444 audio_set_output_source(AUDIO_SRC_PLAYBACK);
1445 pcm_apply_settings();
1446
Thomas Martitz22e802e2013-05-30 11:24:16 +02001447 if (pcmrec_handle > 0)
1448 pcmrec_handle = core_free(pcmrec_handle);
1449 talk_buffer_set_policy(TALK_BUFFER_DEFAULT);
1450
Jonathan Gordon7d5e0d72010-05-16 11:13:42 +00001451 send_event(RECORDING_EVENT_STOP, NULL);
Michael Sevakis48881312013-06-22 16:41:16 -04001452}
Miika Pekkarinen482a2422005-12-23 21:43:05 +00001453
Michael Sevakis48881312013-06-22 16:41:16 -04001454/* Q_AUDIO_RECORDING_OPTIONS */
1455static void on_recording_options(struct audio_recording_options *options)
Michael Sevakiseca9f7f2006-12-10 14:21:31 +00001456{
Michael Sevakis48881312013-06-22 16:41:16 -04001457 if (!options)
1458 {
1459 logf("options: option NULL!");
1460 return;
1461 }
Michael Sevakiseca9f7f2006-12-10 14:21:31 +00001462
Michael Sevakis48881312013-06-22 16:41:16 -04001463 if (record_state != REC_STATE_IDLE)
1464 {
1465 /* This would ruin things */
1466 logf("options: still recording!");
1467 return;
1468 }
1469
1470 /* Stop everything else that might be running */
1471 pcm_stop_recording();
1472
1473 int afmt = rec_format_afmt[options->enc_config.rec_format];
1474 bool enc_load = true;
1475
1476 if (codec_loaded() != AFMT_UNKNOWN)
1477 {
1478 if (get_audio_base_codec_type(enc_config.afmt) !=
1479 get_audio_base_codec_type(afmt))
1480 {
1481 /* New format, new encoder; unload this one */
1482 codec_unload();
1483 }
1484 else
1485 {
1486 /* Keep current encoder */
1487 codec_stop();
1488 enc_load = false;
1489 }
1490 }
1491
1492 init_state();
1493
1494 /* Read recording options, remember the ones used elsewhere */
1495 unsigned frequency = options->rec_frequency;
Michael Sevakiseca9f7f2006-12-10 14:21:31 +00001496 rec_source = options->rec_source;
1497 num_channels = options->rec_channels == 1 ? 1 : 2;
Michael Sevakis48881312013-06-22 16:41:16 -04001498 unsigned mono_mode = options->rec_mono_mode;
1499 pre_record_seconds = options->rec_prerecord_time;
Michael Sevakiseca9f7f2006-12-10 14:21:31 +00001500 enc_config = options->enc_config;
Michael Sevakis48881312013-06-22 16:41:16 -04001501 enc_config.afmt = afmt;
1502
1503 queue_reply(&audio_queue, 0); /* Let caller go */
1504
1505 /* Pick appropriate PCM copy routine */
1506 pcm_copyfn = memcpy;
1507
1508 if (num_channels == 1)
1509 {
1510 static typeof (memcpy) * const copy_buffer_mono[] =
1511 {
1512 copy_buffer_mono_lr,
1513 copy_buffer_mono_l,
1514 copy_buffer_mono_r
1515 };
1516
1517 if (mono_mode >= ARRAYLEN(copy_buffer_mono))
1518 mono_mode = 0;
1519
1520 pcm_copyfn = copy_buffer_mono[mono_mode];
1521 }
1522
1523 /* Get the hardware samplerate to be used */
1524 unsigned long sampr;
Michael Sevakiseca9f7f2006-12-10 14:21:31 +00001525
1526#ifdef HAVE_SPDIF_IN
1527 if (rec_source == AUDIO_SRC_SPDIF)
Michael Sevakis48881312013-06-22 16:41:16 -04001528 sampr = get_spdif_samplerate(); /* Determined by source */
Michael Sevakiseca9f7f2006-12-10 14:21:31 +00001529 else
Michael Sevakis48881312013-06-22 16:41:16 -04001530#endif /* HAVE_SPDIF_IN */
1531 sampr = rec_freq_sampr[frequency];
Michael Sevakiseca9f7f2006-12-10 14:21:31 +00001532
Michael Sevakis48881312013-06-22 16:41:16 -04001533 update_samplerate_config(sampr);
1534
1535 /* Set monitoring */
Michael Sevakiseca9f7f2006-12-10 14:21:31 +00001536 audio_set_output_source(rec_source);
1537
Michael Sevakis48881312013-06-22 16:41:16 -04001538 /* Apply hardware setting to start monitoring now */
Michael Sevakis8867d002007-03-05 08:14:27 +00001539 pcm_apply_settings();
Michael Sevakiseca9f7f2006-12-10 14:21:31 +00001540
Michael Sevakis48881312013-06-22 16:41:16 -04001541 if (!enc_load || codec_load(-1, afmt | CODEC_TYPE_ENCODER))
Michael Sevakiseca9f7f2006-12-10 14:21:31 +00001542 {
Michael Sevakis48881312013-06-22 16:41:16 -04001543 enc_cb = codec_get_enc_callback();
Michael Sevakis5857c442013-05-31 02:41:02 -04001544
Michael Sevakis48881312013-06-22 16:41:16 -04001545 if (!enc_cb || !configure_encoder_stream())
1546 {
1547 codec_unload();
1548 return;
1549 }
Michael Sevakis5857c442013-05-31 02:41:02 -04001550
Michael Sevakis48881312013-06-22 16:41:16 -04001551 if (pre_record_seconds != 0)
1552 {
1553 record_status = RECORD_PRERECORDING;
1554 codec_go();
1555 pcm_pause = false;
1556 }
1557
1558 pcm_start_recording();
Michael Sevakiseca9f7f2006-12-10 14:21:31 +00001559 }
1560 else
1561 {
1562 logf("set rec opt: enc load failed");
Michael Sevakis48881312013-06-22 16:41:16 -04001563 raise_error_status(PCMREC_E_LOAD_ENCODER);
Michael Sevakiseca9f7f2006-12-10 14:21:31 +00001564 }
Michael Sevakis48881312013-06-22 16:41:16 -04001565}
Michael Sevakiseca9f7f2006-12-10 14:21:31 +00001566
Michael Sevakis48881312013-06-22 16:41:16 -04001567/* Q_AUDIO_RECORD - start recording (not gapless)
1568 or split stream (gapless) */
1569static void on_record(const char *filename)
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001570{
Michael Sevakis48881312013-06-22 16:41:16 -04001571 if (rec_errors)
Michael Sevakisec1f4822007-02-16 08:52:06 +00001572 {
Michael Sevakis48881312013-06-22 16:41:16 -04001573 logf("on_record: errors not cleared");
1574 return;
1575 }
Michael Sevakisec1f4822007-02-16 08:52:06 +00001576
Michael Sevakis48881312013-06-22 16:41:16 -04001577 if (!filename)
1578 {
1579 logf("on_record: No filename");
1580 return;
1581 }
Michael Sevakisec1f4822007-02-16 08:52:06 +00001582
Michael Sevakis48881312013-06-22 16:41:16 -04001583 if (codec_loaded() == AFMT_UNKNOWN)
1584 {
1585 logf("on_record: Recording options not set");
1586 return;
1587 }
Michael Sevakisec1f4822007-02-16 08:52:06 +00001588
Michael Sevakis48881312013-06-22 16:41:16 -04001589 logf("on_record: new file '%s'", filename);
1590
1591 /* Copy path and let caller go */
1592 char path[MAX_PATH];
1593 strlcpy(path, filename, MAX_PATH);
1594
1595 queue_reply(&audio_queue, 0);
1596
1597 enum mark_stream_action mark_action;
1598
1599 if (record_state == REC_STATE_IDLE)
1600 {
1601 mark_action = MARK_STREAM_START;
1602
1603 if (pre_record_seconds)
Michael Sevakisec1f4822007-02-16 08:52:06 +00001604 {
Michael Sevakis48881312013-06-22 16:41:16 -04001605 codec_pause();
1606 tally_prerecord_data();
1607 mark_action = MARK_STREAM_START_PRE;
Michael Sevakisec1f4822007-02-16 08:52:06 +00001608 }
1609
Michael Sevakis48881312013-06-22 16:41:16 -04001610 clear_warning_status(PCMREC_W_ALL &
1611 ~(PCMREC_W_SAMPR_MISMATCH|PCMREC_W_DMA));
1612 record_state = REC_STATE_MONITOR;
1613 record_status = RECORD_RECORDING;
Michael Sevakisec1f4822007-02-16 08:52:06 +00001614 }
1615 else
Michael Sevakiseca9f7f2006-12-10 14:21:31 +00001616 {
Michael Sevakis48881312013-06-22 16:41:16 -04001617 /* Already recording, just split the stream */
Michael Sevakiseca9f7f2006-12-10 14:21:31 +00001618 logf("inserting split");
Michael Sevakis48881312013-06-22 16:41:16 -04001619 mark_action = MARK_STREAM_SPLIT;
1620 finish_stream(false);
1621 reset_rec_stats();
Michael Sevakiseca9f7f2006-12-10 14:21:31 +00001622 }
1623
Michael Sevakis48881312013-06-22 16:41:16 -04001624 if (rec_errors)
1625 {
1626 pcm_pause = true;
1627 codec_stop();
1628 reset_fifos(false);
1629 return;
1630 }
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001631
Michael Sevakis48881312013-06-22 16:41:16 -04001632 mark_stream(path, mark_action);
1633
1634 codec_go();
1635 pcm_pause = record_status != RECORD_RECORDING;
1636}
1637
1638/* Q_AUDIO_RECORD_STOP */
1639static void on_record_stop(void)
Andye5d08722005-06-19 03:05:53 +00001640{
Michael Sevakis48881312013-06-22 16:41:16 -04001641 if (record_state == REC_STATE_IDLE)
1642 return;
Michael Sevakisa9ea1a42013-06-22 16:39:40 -04001643
Michael Sevakis5f0692b2013-07-09 07:36:22 -04001644 trigger_cpu_boost();
1645
Michael Sevakis48881312013-06-22 16:41:16 -04001646 /* Drain encoder and PCM buffers */
1647 pcm_pause = true;
1648 finish_stream(true);
1649
1650 /* End stream at last data and flush end marker */
1651 mark_stream(NULL, MARK_STREAM_END);
1652 while (flush_chunk(REC_STATE_IDLE, 1) == REC_STATE_IDLE);
1653
1654 reset_fifos(false);
1655
1656 bool prerecord = pre_record_seconds != 0;
1657
1658 if (rec_errors)
Michael Sevakisec1f4822007-02-16 08:52:06 +00001659 {
Michael Sevakis48881312013-06-22 16:41:16 -04001660 codec_stop();
1661 prerecord = false;
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001662 }
1663
Michael Sevakis48881312013-06-22 16:41:16 -04001664 close_rec_file();
1665 rec_errors = 0;
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001666
Michael Sevakis48881312013-06-22 16:41:16 -04001667 record_state = REC_STATE_IDLE;
1668 record_status = prerecord ? RECORD_PRERECORDING : RECORD_STOPPED;
1669 reset_rec_stats();
1670
1671 if (prerecord)
1672 {
1673 codec_go();
1674 pcm_pause = false;
1675 }
1676}
1677
1678/* Q_AUDIO_RECORD_PAUSE */
1679static void on_record_pause(void)
Andye6e54962005-11-12 04:00:56 +00001680{
Michael Sevakis48881312013-06-22 16:41:16 -04001681 if (record_status != RECORD_RECORDING)
1682 return;
Andye6e54962005-11-12 04:00:56 +00001683
Michael Sevakis48881312013-06-22 16:41:16 -04001684 pcm_pause = true;
1685 record_status = RECORD_PAUSED;
1686}
Michael Sevakisec1f4822007-02-16 08:52:06 +00001687
Michael Sevakis48881312013-06-22 16:41:16 -04001688/* Q_AUDIO_RECORD_RESUME */
1689static void on_record_resume(void)
Andye6e54962005-11-12 04:00:56 +00001690{
Michael Sevakis48881312013-06-22 16:41:16 -04001691 if (record_status != RECORD_PAUSED)
1692 return;
Michael Sevakisa9ea1a42013-06-22 16:39:40 -04001693
Michael Sevakis48881312013-06-22 16:41:16 -04001694 record_status = RECORD_RECORDING;
1695 pcm_pause = !!rec_errors;
1696}
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001697
Michael Sevakis5857c442013-05-31 02:41:02 -04001698/* Called by audio thread when recording is initialized */
1699void audio_recording_handler(struct queue_event *ev)
Andye5d08722005-06-19 03:05:53 +00001700{
Michael Sevakis48881312013-06-22 16:41:16 -04001701#ifdef HAVE_PRIORITY_SCHEDULING
1702 /* Get current priorities since they get changed */
1703 int old_prio = thread_get_priority(audio_thread_id);
1704 int old_cod_prio = codec_thread_get_priority();
1705#endif
1706
1707 LOGFQUEUE("record < Q_AUDIO_INIT_RECORDING");
1708 on_init_recording();
Christian Gmeiner14e80672005-08-06 10:12:19 +00001709
Michael Sevakis5857c442013-05-31 02:41:02 -04001710 while (1)
Andye5d08722005-06-19 03:05:53 +00001711 {
Michael Sevakis48881312013-06-22 16:41:16 -04001712 int watermark = high_watermark;
1713
Michael Sevakis5857c442013-05-31 02:41:02 -04001714 switch (ev->id)
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001715 {
Michael Sevakis5857c442013-05-31 02:41:02 -04001716 case Q_AUDIO_CLOSE_RECORDING:
Michael Sevakis48881312013-06-22 16:41:16 -04001717 LOGFQUEUE("record < Q_AUDIO_CLOSE_RECORDING");
1718 goto recording_done;
Christian Gmeiner14e80672005-08-06 10:12:19 +00001719
Michael Sevakis5857c442013-05-31 02:41:02 -04001720 case Q_AUDIO_RECORDING_OPTIONS:
Michael Sevakis48881312013-06-22 16:41:16 -04001721 LOGFQUEUE("record < Q_AUDIO_RECORDING_OPTIONS");
1722 on_recording_options((struct audio_recording_options *)ev->data);
Michael Sevakis5857c442013-05-31 02:41:02 -04001723 break;
Christian Gmeiner14e80672005-08-06 10:12:19 +00001724
Michael Sevakis5857c442013-05-31 02:41:02 -04001725 case Q_AUDIO_RECORD:
Michael Sevakis48881312013-06-22 16:41:16 -04001726 LOGFQUEUE("record < Q_AUDIO_RECORD: %s", (const char *)ev->data);
1727 on_record((const char *)ev->data);
Michael Sevakis5857c442013-05-31 02:41:02 -04001728 break;
Christian Gmeiner14e80672005-08-06 10:12:19 +00001729
Michael Sevakis48881312013-06-22 16:41:16 -04001730 case Q_AUDIO_RECORD_STOP:
1731 LOGFQUEUE("record < Q_AUDIO_RECORD_STOP");
1732 on_record_stop();
Michael Sevakis5857c442013-05-31 02:41:02 -04001733 break;
Michael Sevakiseca9f7f2006-12-10 14:21:31 +00001734
Michael Sevakis48881312013-06-22 16:41:16 -04001735 case Q_AUDIO_RECORD_PAUSE:
1736 LOGFQUEUE("record < Q_AUDIO_RECORD_PAUSE");
1737 on_record_pause();
Michael Sevakis5857c442013-05-31 02:41:02 -04001738 break;
Christian Gmeiner14e80672005-08-06 10:12:19 +00001739
Michael Sevakis48881312013-06-22 16:41:16 -04001740 case Q_AUDIO_RECORD_RESUME:
1741 LOGFQUEUE("record < Q_AUDIO_RECORD_RESUME");
1742 on_record_resume();
Michael Sevakis5857c442013-05-31 02:41:02 -04001743 break;
Christian Gmeiner14e80672005-08-06 10:12:19 +00001744
Michael Sevakis48881312013-06-22 16:41:16 -04001745 case Q_AUDIO_RECORD_FLUSH:
1746 watermark = 1;
Michael Sevakis5857c442013-05-31 02:41:02 -04001747 break;
Michael Sevakis5857c442013-05-31 02:41:02 -04001748
Michael Sevakis48881312013-06-22 16:41:16 -04001749 case SYS_USB_CONNECTED:
1750 LOGFQUEUE("record < SYS_USB_CONNECTED");
1751 if (record_state != REC_STATE_IDLE)
1752 {
1753 LOGFQUEUE(" still recording");
1754 break;
1755 }
Michael Sevakis4fc717a2006-08-28 22:38:41 +00001756
Michael Sevakis48881312013-06-22 16:41:16 -04001757 goto recording_done;
1758 } /* switch */
Michael Sevakis4fc717a2006-08-28 22:38:41 +00001759
Michael Sevakis48881312013-06-22 16:41:16 -04001760 int timeout;
Peter D'Hoye528fe442008-10-08 22:18:16 +00001761
Michael Sevakis48881312013-06-22 16:41:16 -04001762 switch (record_state)
Michael Sevakisec1f4822007-02-16 08:52:06 +00001763 {
Michael Sevakis48881312013-06-22 16:41:16 -04001764 case REC_STATE_FLUSH:
1765 case REC_STATE_MONITOR:
1766 do
1767 record_state = flush_chunk(record_state, watermark);
1768 while (record_state == REC_STATE_FLUSH &&
1769 queue_empty(&audio_queue));
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001770
Michael Sevakis48881312013-06-22 16:41:16 -04001771 timeout = record_state == REC_STATE_FLUSH ?
1772 HZ*0 : HZ*FLUSH_MON_INTERVAL;
1773 break;
1774 case REC_STATE_IDLE:
1775#ifdef HAVE_SPDIF_IN
1776 if (rec_source == AUDIO_SRC_SPDIF)
1777 {
1778 check_spdif_samplerate();
1779 timeout = HZ/2;
1780 break;
1781 }
1782#endif /* HAVE_SPDIF_IN */
1783 default:
1784 timeout = TIMEOUT_BLOCK;
1785 break;
Michael Sevakis5be56742007-09-30 15:55:34 +00001786 }
Michael Sevakis4fc717a2006-08-28 22:38:41 +00001787
Michael Sevakis48881312013-06-22 16:41:16 -04001788 queue_wait_w_tmo(&audio_queue, ev, timeout);
1789 } /* while */
1790
1791recording_done:
1792 on_close_recording();
1793#ifdef HAVE_PRIORITY_SCHEDULING
1794 /* Restore normal thread priorities */
1795 thread_set_priority(audio_thread_id, old_prio);
1796 codec_thread_set_priority(old_cod_prio);
1797#endif
1798}
1799
1800
1801/** Encoder callbacks **/
1802
1803/* Read a block of unprocessed PCM data, with mono conversion if
1804 * num_channels == 1
1805 *
1806 * NOTE: Request must be less than the PCM buffer length in samples in order
1807 * to progress.
1808 * (ie. count <= PCM_NUM_CHUNKS*PCM_CHUNK_SAMP)
1809 */
1810static int enc_pcmbuf_read(void *buffer, int count)
1811{
1812 size_t avail = pcmbuf_used();
1813 size_t size = count*PCM_SAMP_SIZE;
1814
1815 if (count > 0 && avail >= size)
1816 {
1817 size_t endidx = pcm_ridx + size;
1818
1819 if (endidx > PCM_BUF_SIZE)
Michael Sevakis5323fe92007-11-30 05:16:56 +00001820 {
Michael Sevakis48881312013-06-22 16:41:16 -04001821 size_t wrap = endidx - PCM_BUF_SIZE;
1822 size_t offset = size -= wrap;
1823
1824 if (num_channels == 1)
1825 offset /= 2; /* src offset -> dst offset */
1826
1827 pcm_copyfn(buffer + offset, pcmbuf_ptr(0), wrap);
1828 }
1829
1830 pcm_copyfn(buffer, pcmbuf_ptr(pcm_ridx), size);
1831
1832 if (avail >= sample_rate*PCM_SAMP_SIZE*PCM_BOOST_SECONDS ||
1833 avail >= PCM_BUF_SIZE*1/2)
1834 {
1835 /* Filling up - boost threshold data available or more or 1/2 full
1836 or more - boost codec */
Michael Sevakis5323fe92007-11-30 05:16:56 +00001837 trigger_cpu_boost();
1838 }
1839
Michael Sevakisec1f4822007-02-16 08:52:06 +00001840 pcm_buffer_empty = false;
Michael Sevakis48881312013-06-22 16:41:16 -04001841
1842 return count;
Michael Sevakis4fc717a2006-08-28 22:38:41 +00001843 }
1844
Michael Sevakis48881312013-06-22 16:41:16 -04001845 /* Not enough data available - encoder should idle */
Michael Sevakisec1f4822007-02-16 08:52:06 +00001846 pcm_buffer_empty = true;
Michael Sevakis5323fe92007-11-30 05:16:56 +00001847
1848 cancel_cpu_boost();
1849
Michael Sevakis48881312013-06-22 16:41:16 -04001850 /* Sleep a little bit */
Michael Sevakis5323fe92007-11-30 05:16:56 +00001851 sleep(0);
1852
Michael Sevakis48881312013-06-22 16:41:16 -04001853 return 0;
1854}
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001855
Michael Sevakis48881312013-06-22 16:41:16 -04001856/* Advance PCM buffer by count samples */
1857static int enc_pcmbuf_advance(int count)
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001858{
Michael Sevakis48881312013-06-22 16:41:16 -04001859 if (count <= 0)
1860 return 0;
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001861
Michael Sevakis48881312013-06-22 16:41:16 -04001862 size_t avail = pcmbuf_used();
1863 size_t size = count*PCM_SAMP_SIZE;
1864
1865 if (avail < size)
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001866 {
Michael Sevakis48881312013-06-22 16:41:16 -04001867 size = avail;
1868 count = size / PCM_SAMP_SIZE;
Michael Sevakis0f5cb942006-11-06 18:07:30 +00001869 }
1870
Michael Sevakis48881312013-06-22 16:41:16 -04001871 pcm_ridx = pcmbuf_add(pcm_ridx, size);
1872
1873 return count;
1874}
1875
1876/* Return encoder chunk at current write position, wrapping to 0 if
1877 * requested size demands it.
1878 *
1879 * NOTE: No request should be more than 1/2 the buffer length, all elements
1880 * included, or progress will not be guaranteed.
1881 * (ie. CHUNK_DATA_COUNT(need) <= enc_buflen / 2)
1882 */
1883static struct enc_chunk_data * enc_encbuf_get_buffer(size_t need)
1884{
1885 /* Convert to buffer slot count, including the header */
1886 need = CHUNK_DATA_COUNT(need);
1887
1888 enum record_state state = record_state;
1889 size_t avail = encbuf_free();
1890
1891 /* Must have the split margin as well but it does not have to be
1892 continuous with the request */
1893 while (avail <= need + ENCBUF_MIN_SPLIT_MARGIN ||
1894 (enc_widx + need > enc_buflen &&
1895 enc_ridx <= need + ENCBUF_MIN_SPLIT_MARGIN))
1896 {
1897 if (UNLIKELY(state == REC_STATE_IDLE))
1898 {
1899 /* Prerecording - delete some old data */
1900 size_t ridx;
1901 struct enc_chunk_data *data =
1902 encbuf_read_ptr_incr(enc_ridx, &ridx);
1903
1904 if (data)
1905 {
1906 encbuf_rec_count -= CHUNK_DATA_COUNT(data->hdr.size);
1907 num_rec_bytes -= data->hdr.size;
1908 num_rec_samples -= data->pcm_count;
1909 }
1910
1911 enc_ridx = ridx;
1912 avail = encbuf_free();
1913 continue;
1914 }
1915 else if (avail == enc_buflen)
1916 {
1917 /* Empty but request larger than any possible space */
1918 raise_warning_status(PCMREC_W_ENC_BUFFER_OVF);
1919 }
1920 else if (state != REC_STATE_FLUSH && encbuf_used() < high_watermark)
1921 {
1922 /* Not yet even at high watermark but what's needed won't fit */
1923 encbuf_request_flush();
1924 }
1925
1926 sleep(0);
1927 return NULL;
1928 }
1929
1930 struct enc_chunk_data *data =
1931 encbuf_get_write_ptr(enc_widx, need, &enc_widx);
1932
1933 if (state == REC_STATE_IDLE)
1934 data->hdr.pre = 1;
1935
1936 return data;
1937}
1938
1939/* Releases the current buffer into the available chunks */
1940static void enc_encbuf_finish_buffer(void)
1941{
1942 struct enc_chunk_data *data = ENC_DATA_HDR(encbuf_ptr(enc_widx));
1943
1944 if (data->hdr.err)
1945 {
1946 /* Encoder set error flag */
1947 raise_error_status(PCMREC_E_ENCODER);
1948 return;
1949 }
1950
1951 size_t data_size = data->hdr.size;
1952
1953 if (data_size == 0)
1954 return; /* Claims nothing was written */
1955
1956 size_t count = CHUNK_DATA_COUNT(data_size);
1957 size_t avail = encbuf_free();
1958
1959 if (avail <= count || enc_widx + count > enc_buflen)
1960 {
1961 /* Claims it wrote too much? */
1962 raise_warning_status(PCMREC_W_ENC_BUFFER_OVF);
1963 return;
1964 }
1965
1966 if (num_rec_bytes + data_size > MAX_NUM_REC_BYTES)
1967 {
1968 /* Would exceed filesize limit; should have split sooner.
1969 This chunk will be dropped. :'( */
1970 raise_warning_status(PCMREC_W_FILE_SIZE);
1971 return;
1972 }
1973
1974 encbuf_widx_advance(enc_widx, count);
1975
1976 encbuf_rec_count += count;
1977 num_rec_bytes += data_size;
1978 num_rec_samples += data->pcm_count;
1979}
1980
1981/* Read from the output stream */
1982static ssize_t enc_stream_read(void *buf, size_t count)
1983{
1984 if (!stream_flush_buf())
1985 return -1;
1986
1987 return read(rec_fd, buf, count);
1988}
1989
1990/* Seek the output steam */
1991static off_t enc_stream_lseek(off_t offset, int whence)
1992{
1993 if (!stream_flush_buf())
1994 return -1;
1995
1996 return lseek(rec_fd, offset, whence);
1997}
1998
1999/* Write to the output stream */
2000static ssize_t enc_stream_write(const void *buf, size_t count)
2001{
2002 if (UNLIKELY(count >= STREAM_BUF_SIZE))
2003 {
2004 /* Too big to buffer */
2005 if (stream_flush_buf())
2006 return write(rec_fd, buf, count);
2007 }
2008
2009 if (!count)
2010 return 0;
2011
2012 if (stream_buf_used + count > STREAM_BUF_SIZE)
2013 {
2014 if (!stream_flush_buf() && stream_buf_used + count > STREAM_BUF_SIZE)
2015 count = STREAM_BUF_SIZE - stream_buf_used;
2016 }
2017
2018 memcpy(stream_buffer + stream_buf_used, buf, count);
2019 stream_buf_used += count;
2020
2021 return count;
2022}
2023
2024/* One-time init at startup */
2025void INIT_ATTR recording_init(void)
2026{
2027 /* Init API */
2028 ci.enc_pcmbuf_read = enc_pcmbuf_read;
2029 ci.enc_pcmbuf_advance = enc_pcmbuf_advance;
2030 ci.enc_encbuf_get_buffer = enc_encbuf_get_buffer;
2031 ci.enc_encbuf_finish_buffer = enc_encbuf_finish_buffer;
2032 ci.enc_stream_read = enc_stream_read;
2033 ci.enc_stream_lseek = enc_stream_lseek;
2034 ci.enc_stream_write = enc_stream_write;
2035}