rockbox/apps/audio_thread.c

182 lines
5 KiB
C
Raw Normal View History

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2005-2007 Miika Pekkarinen
* Copyright (C) 2007-2008 Nicolas Pennequin
* Copyright (C) 2011-2013 Michael Sevakis
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "config.h"
#include "system.h"
#include "kernel.h"
#include "logf.h"
#include "usb.h"
#include "pcm.h"
#include "sound.h"
#include "audio_thread.h"
#ifdef AUDIO_HAVE_RECORDING
#include "pcm_record.h"
#endif
#include "codec_thread.h"
#include "voice_thread.h"
#include "talk.h"
#include "settings.h"
/* Macros to enable logf for queues
logging on SYS_TIMEOUT can be disabled */
#ifdef SIMULATOR
/* Define this for logf output of all queuing except SYS_TIMEOUT */
#define AUDIO_LOGQUEUES
/* Define this to logf SYS_TIMEOUT messages */
/*#define AUDIO_LOGQUEUES_SYS_TIMEOUT*/
#endif
#ifdef AUDIO_LOGQUEUES
#define LOGFQUEUE logf
#else
#define LOGFQUEUE(...)
#endif
bool audio_is_initialized = false;
/* Event queues */
struct event_queue audio_queue SHAREDBSS_ATTR;
static struct queue_sender_list audio_queue_sender_list SHAREDBSS_ATTR;
/* Audio thread */
static long audio_stack[(DEFAULT_STACK_SIZE + 0x1000)/sizeof(long)];
static const char audio_thread_name[] = "audio";
unsigned int audio_thread_id = 0;
static void NORETURN_ATTR audio_thread(void)
{
struct queue_event ev;
ev.id = Q_NULL; /* something not in switch below */
pcm_postinit();
while (1)
{
switch (ev.id)
{
/* Starts the playback engine branch */
case Q_AUDIO_PLAY:
LOGFQUEUE("audio < Q_AUDIO_PLAY");
audio_playback_handler(&ev);
continue;
/* Playback has to handle these, even if not playing */
case Q_AUDIO_REMAKE_AUDIO_BUFFER:
#ifdef HAVE_DISK_STORAGE
case Q_AUDIO_UPDATE_WATERMARK:
#endif
audio_playback_handler(&ev);
break;
#ifdef AUDIO_HAVE_RECORDING
/* Starts the recording engine branch */
case Q_AUDIO_INIT_RECORDING:
LOGFQUEUE("audio < Q_AUDIO_INIT_RECORDING");
audio_recording_handler(&ev);
continue;
#endif
/* All return upon USB */
case SYS_USB_CONNECTED:
LOGFQUEUE("audio < SYS_USB_CONNECTED");
voice_stop();
usb_acknowledge(SYS_USB_CONNECTED_ACK);
usb_wait_for_disconnect(&audio_queue);
break;
}
queue_wait(&audio_queue, &ev);
}
}
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>
2013-06-22 20:41:16 +00:00
void audio_queue_post(long id, intptr_t data)
{
queue_post(&audio_queue, id, data);
}
intptr_t audio_queue_send(long id, intptr_t data)
{
return queue_send(&audio_queue, id, data);
}
/* Return the playback and recording status */
int audio_status(void)
{
return playback_status()
#ifdef AUDIO_HAVE_RECORDING
| pcm_rec_status()
#endif
;
}
/* Clear all accumulated audio errors for playback and recording */
void audio_error_clear(void)
{
#ifdef AUDIO_HAVE_RECORDING
pcm_rec_error_clear();
#endif
}
/** -- Startup -- **/
/* Initialize the audio system - called from init() in main.c */
void audio_init(void)
{
/* Can never do this twice */
if (audio_is_initialized)
{
logf("audio: already initialized");
return;
}
logf("audio: initializing");
/* Initialize queues before giving control elsewhere in case it likes
to send messages. Thread creation will be delayed however so nothing
starts running until ready if something yields such as talk_init. */
queue_init(&audio_queue, true);
codec_thread_init();
/* This thread does buffer, so match its priority */
audio_thread_id = create_thread(audio_thread, audio_stack,
sizeof(audio_stack), 0, audio_thread_name
IF_PRIO(, MIN(PRIORITY_BUFFERING, PRIORITY_USER_INTERFACE))
IF_COP(, CPU));
queue_enable_queue_send(&audio_queue, &audio_queue_sender_list,
audio_thread_id);
playback_init();
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>
2013-06-22 20:41:16 +00:00
#ifdef AUDIO_HAVE_RECORDING
recording_init();
#endif
/* ...now...audio_reset_buffer must know the size of voicefile buffer so
init talk first which will init the buffers */
talk_init();
/* Probably safe to say */
audio_is_initialized = true;
sound_settings_apply();
}