9
0
Fork 0

Updated audio subsystem from Ken Pettit

This commit is contained in:
Gregory Nutt 2013-10-27 07:44:53 -06:00
parent 6dc974b4b0
commit 66bc3094e6
6 changed files with 1064 additions and 234 deletions

View File

@ -11,22 +11,139 @@ config AUDIO
if AUDIO
config AUDIO_NCHANNELS
int "Number of Audio Channels"
default 2
config AUDIO_MULTI_SESSION
bool "Support multiple sessions"
default n
---help---
Stereo channel support is standard, but some systems may support 5 or 7
channel capability.
Some audio devices, such as USB attached sound cards, may support more
than one streaming session at a time (each with one or more audio channels).
Selecting this feature adds support for tracking multiple concurrent
sessions with the lower-level audio devices.
config AUDIO_LARGE_BUFFERS
bool "Support Audio Buffers with greater than 65K samples"
default n
---help---
By default, the Audio Pipeline Buffer uses a 16-bit max sample count, limiting
By default, the Audio Pipeline Buffers use a 16-bit max sample count, limiting
the number of samples per buffer to 65K. Enable this option to specify a
32-bit max sample count for increased samples / buffer capability.
channel capability.
config AUDIO_NUM_BUFFERS
int "Number of buffers for audio processing"
default 2
---help---
Specifies the number of buffers to allocate for audio processing.
If Driver Specified buffer sizes is enabled (below), then the
low-level drivers will have the opportunity to override this
value.
config AUDIO_BUFFER_NUMBYTES
int "Size of each audio buffer for audio processing"
default 8192
---help---
Specifies the allocation size for each audio buffer
If Driver Specified buffer sizes is enabled (below), then the
low-level drivers will have the opportunity to override this
value.
config AUDIO_DRIVER_SPECIFIC_BUFFERS
bool "Support for Driver specified buffer sizes"
default n
---help---
By default, the Audio system uses the same size and number of buffers
regardless of the specific audio device in use. Specifying 'y' here
adds extra code which allows the lower-level audio device to specify
a partucular size and number of buffers.
menu "Supported Audio Formats"
config AUDIO_FORMAT_AC3
bool "AC3 Format"
default n
---help---
Build in support for AC3 (Dolby Digital) Audio format.
config AUDIO_FORMAT_DTS
bool "DTS Format"
default n
---help---
Add in support for DTS format.
config AUDIO_FORMAT_PCM
bool "PCM Audio"
default y
---help---
Build in support for PCM Audio format.
config AUDIO_FORMAT_MP3
bool "MPEG 3 Layer 1"
default y
---help---
Build in support for MP3 Audio format.
config AUDIO_FORMAT_MIDI
bool "Midi Format"
default n
---help---
Add in support for MIDI format.
config AUDIO_FORMAT_WMA
bool "WMA Format (see copyright notice)"
default n
---help---
Add in support for Microsoft Windows Media format.
config AUDIO_FORMAT_OGG_VORBIS
bool "Ogg Vorbis format"
default n
---help---
Build in support for the Open Source Ogg Vorbis format.
endmenu
menu "Exclude Specific Audio Features"
config AUDIO_EXCLUDE_VOLUME
bool "Exclude volume controls"
default n
---help---
Exclude building support for changing the playback volume.
config AUDIO_EXCLUDE_BALANCE
bool "Exclude balance controls"
default n
---help---
Exclude building support for changing the balance.
config AUDIO_EXCLUDE_TONE
bool "Exclude tone (bass and treble) controls"
default n
---help---
Exclude building support for changing the bass and treble.
config AUDIO_EXCLUDE_PAUSE_RESUME
bool "Exclude pause and resume controls"
default n
---help---
Exclude building support for pausing and resuming audio files
once they are submitted. If the sound system is being used to play
short system notification or error type sounds that typicaly only
last a second or two, then there is no need (or chance) to pause or
resume sound playback once it has started.
config AUDIO_EXCLUDE_STOP
bool "Exclude stop playback controls"
default n
---help---
Exclude building support for stopping audio files once they are
submitted. If the sound system is being used to play short ssytem
notification or error type sounds that typicaly only last a second
or two, then there is no need (or chance) to stop the sound
playback once it has started.
endmenu
config AUDIO_CUSTOM_DEV_PATH
bool "Use custom device path"
default n
@ -57,33 +174,6 @@ config AUDIO_DEV_PATH
endif
endif
menu "Supported Audio Formats"
config AUDIO_FORMAT_PCM
bool "PCM Audio"
default y
---help---
Build in support for PCM Audio format.
config AUDIO_FORMAT_MP3
bool "MPEG 3 Layer 1"
default n
---help---
Build in support for MP3 Audio format.
config AUDIO_FORMAT_WMA
bool "WMA Format (see copyright notice)"
default n
---help---
Add in support for Microsoft Windows Media format.
config AUDIO_FORMAT_OGG_VORBIS
bool "Ogg Vorbis format"
default n
---help---
Build in support for the Open Source Ogg Vorbis format.
endmenu
# These are here as placeholders of what could be added

View File

@ -53,18 +53,6 @@ ifeq ($(CONFIG_AUDIO_FORMAT_PCM),y)
CSRCS += pcm.c
endif
ifeq ($(CONFIG_AUDIO_MIXER),y)
CSRCS += mixer.c
endif
ifeq ($(CONFIG_AUDIO_MIDI_SYNTH),y)
CSRCS += midisynth.c
endif
ifeq ($(CONFIG_AUDIO_FONT),y)
CSRCS += audio_font.c
endif
AOBJS = $(ASRCS:.S=$(OBJEXT))
COBJS = $(CSRCS:.c=$(OBJEXT))

125
nuttx/audio/README.txt Normal file
View File

@ -0,0 +1,125 @@
README
^^^^^^
This directory contains the audio subsytem support for NuttX. The contents of this
directory are only built if CONFIG_AUDIO is defined in the NuttX configuration file.
Contents
^^^^^^^^
- Files in this directory
- Related Header Files
- Related directories
Files in this directory
^^^^^^^^^^^^^^^^^^^^^^^
This directory holds the NuttX audio subsystem upper-half. The upper-half provides
a common interface for applications to interface with and also defines a bind
layer for specific lower-half audio device drivers.
audio.c - The upper-half driver that binds to a lower-half driver from the
drivers/audio subdirectory. For each attached audio device, there
will be an instance of this upper-half driver bound to the
instance of the lower half driver context.
buffer.c - Routines to manage creattion and destruction of audio pipeline buffers
(apb) used in the audio subsystem. Audio pipeline buffers are passed
between user applications and the audio drivers to deliver audio
content for playback (or possibly recording in the future).
pcm.c - Routines to manage PCM / WAV type data. Currently just a placeholder.
README - This file!
Related Header Files
^^^^^^^^^^^^^^^^^^^^
include/nuttx/audio/audio.h -- Top level include file defining the audio interface
include/nuttx/audio/vs1053.h -- Specific driver initialization prototypes
Configuration Settings
^^^^^^^^^^^^^^^^^^^^^^
General Audio Settings
----------------------
CONFIG_AUDIO
Enables overall support for audio subsystem
CONFIG_AUDIO_MULTI_SESSION
Enables support for the audio subystem to track mutliple open sessions
with lower-level audio devices.
CONFIG_AUDIO_LARGE_BUFFERS
Specifies that buffer size variables should be 32-bit vs. the normal 16-bit
size. This allows buffers to be larger than 64K bytes on systems with
an abundance of RAM.
CONFIG_AUDIO_NUM_BUFFERS
Sets the number of audio buffers to use for audio operations. If the
configuration has set CONFIG_AUDIO_DRIVER_SPECIFIC_BUFFERS, and an audio
device does not support the operation, then this becomes the default number
of buffers to use.
CONFIG_AUDIO_BUFFER_SIZE
Sets the size of the audio buffers to use for audio operations. If the
configuration has set CONFIG_AUDIO_DRIVER_SPECIFIC_BUFFERS, and an audio
device does not support the operation, then this becomes the default size
of buffers to use.
CONFIG_AUDIO_DRIVER_SPECIFIC_BUFFERS
Enables support for lower-level audio drivers to specify the number and size
of buffers that should be allocated for best performance while interacting
with that driver.
CONFIG_AUDIO_CUSTOM_DEV_PATH
Specifies that all audio devices should be registered in the filesystem at
a location other than the standard /dev/audio directory.
CONFIG_AUDIO_DEV_ROOT
Specifies that all audio devices should be registered in the /dev directory.
Saves a tiny bit of code and RAM space since an additional directory isn't needed,
but at the expense of execution speed when searching for audio devices since all
entries in /dev must be opened and tested if they provide audio support.
Available only if CONFIG_AUDIO_CUSTOM_DEV_PATH is selected.
CONFIG_AUDIO_DEV_PATH
Specifies a custom directory where audio devices will be registered.
Available if CONFIG_AUDIO_CUSTOM_DEV_PATH is selected and CONFIG_AUDIO_DEV_ROOT
is not selected.
Audio Format Support Selections
-------------------------------
CONFIG_AUDIO_FORMAT_AC3
Specifies that AC3 support should be enabled if available by a lower-half driver.
CONFIG_AUDIO_FORMAT_DTS
Specifies that DTS support should be enabled if available by a lower-half driver.
CONFIG_AUDIO_FORMAT_PCM
Specifies that PCM support should be enabled if available by a lower-half driver.
CONFIG_AUDIO_FORMAT_MP3
Specifies that MP3 support should be enabled if available by a lower-half driver.
CONFIG_AUDIO_FORMAT_MIDI
Specifies that MIDI support should be enabled if available by a lower-half driver.
CONFIG_AUDIO_FORMAT_WMA
Specifies that WMA support should be enabled if available by a lower-half driver.
CONFIG_AUDIO_FORMAT_OGG_VORBIS
Specifies that Ogg Vorbis support should be enabled if available by a lower-half driver.
Audio feature exclusion Selections
----------------------------------
CONFIG_AUDIO_EXCLUDE_VOLUME
Disables support in all libraries and drivers for setting the playback volume. In
this case, the device volume will depend on the default level defined by the
lower-level driver, typically via a config setting.
CONFIG_AUDIO_EXCLUDE_BALANCE
Disables support in all libraries and drivers for setting the playback balance.
Also, the volume support must not be excluded for balance to work or make sense.
CONFIG_AUDIO_EXCLUDE_TONE
Disables support for setting bass and treble.
CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
Disables support in all libraries and drivers for pausing and resuming playback.
CONFIG_AUDIO_EXCLUDE_STOP
Disables support in all libraries and drivers for stopping an audio playback
once it has started. Typically selected if only short notification audio sounds
are needed (vs. media playing type applications).
Related Subdirectories
^^^^^^^^^^^^^^^^^^^^^^
drivers/audio -- Contains the lower-level device specific drivers.
apps/system/nxplayer -- User-mode audio subsystem interface library.

View File

@ -60,6 +60,7 @@
#include <nuttx/fs/fs.h>
#include <nuttx/arch.h>
#include <nuttx/audio/audio.h>
#include <mqueue.h>
#include <arch/irq.h>
@ -75,6 +76,10 @@
# define AUDIO_MAX_DEVICE_PATH 32
#endif
#ifndef CONFIG_AUDIO_BUFFER_DEQUEUE_PRIO
# define CONFIG_AUDIO_BUFFER_DEQUEUE_PRIO 1
#endif
/****************************************************************************
* Private Type Definitions
****************************************************************************/
@ -84,10 +89,10 @@
struct audio_upperhalf_s
{
uint8_t crefs; /* The number of times the device has been opened */
volatile bool started; /* True: pulsed output is being generated */
volatile bool started; /* True: playback is active */
sem_t exclsem; /* Supports mutual exclusion */
struct audio_info_s info; /* Pulsed output characteristics */
FAR struct audio_lowerhalf_s *dev; /* lower-half state */
mqd_t usermq; /* User mode app's message queue */
};
/****************************************************************************
@ -98,10 +103,16 @@ static int audio_open(FAR struct file *filep);
static int audio_close(FAR struct file *filep);
static ssize_t audio_read(FAR struct file *filep, FAR char *buffer, size_t buflen);
static ssize_t audio_write(FAR struct file *filep, FAR const char *buffer, size_t buflen);
static int audio_start(FAR struct audio_upperhalf_s *upper, unsigned int oflags);
static int audio_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
#ifdef CONFIG_AUDIO_MULTI_SESSION
static int audio_start(FAR struct audio_upperhalf_s *upper, FAR void *session);
static void audio_callback(FAR void *priv, uint16_t reason,
FAR struct ap_buffer_s *apb, uint16_t status, FAR void *session);
#else
static int audio_start(FAR struct audio_upperhalf_s *upper);
static void audio_callback(FAR void *priv, uint16_t reason,
FAR struct ap_buffer_s *apb, uint16_t status);
#endif /* CONFIG_AUDIO_MULTI_SESSION */
/****************************************************************************
* Private Data
@ -113,10 +124,10 @@ static const struct file_operations g_audioops =
audio_close, /* close */
audio_read, /* read */
audio_write, /* write */
0, /* seek */
0, /* seek */
audio_ioctl /* ioctl */
#ifndef CONFIG_DISABLE_POLL
, 0 /* poll */
, 0 /* poll */
#endif
};
@ -134,10 +145,10 @@ static const struct file_operations g_audioops =
static int audio_open(FAR struct file *filep)
{
FAR struct inode *inode = filep->f_inode;
FAR struct inode *inode = filep->f_inode;
FAR struct audio_upperhalf_s *upper = inode->i_private;
uint8_t tmp;
int ret;
uint8_t tmp;
int ret;
audvdbg("crefs: %d\n", upper->crefs);
@ -167,6 +178,7 @@ static int audio_open(FAR struct file *filep)
/* Save the new open count on success */
upper->crefs = tmp;
upper->usermq = NULL;
ret = OK;
errout_with_sem:
@ -186,9 +198,9 @@ errout:
static int audio_close(FAR struct file *filep)
{
FAR struct inode *inode = filep->f_inode;
FAR struct inode *inode = filep->f_inode;
FAR struct audio_upperhalf_s *upper = inode->i_private;
int ret;
int ret;
audvdbg("crefs: %d\n", upper->crefs);
@ -243,7 +255,18 @@ errout:
static ssize_t audio_read(FAR struct file *filep, FAR char *buffer, size_t buflen)
{
/* Return zero -- usually meaning end-of-file */
FAR struct inode *inode = filep->f_inode;
FAR struct audio_upperhalf_s *upper = inode->i_private;
FAR struct audio_lowerhalf_s *lower = upper->dev;
/* TODO: Should we check permissions here? */
/* Audio read operations get passed directly to the lower-level */
if (lower->ops->read != NULL)
{
return lower->ops->read(lower, buffer, buflen);
}
return 0;
}
@ -258,6 +281,19 @@ static ssize_t audio_read(FAR struct file *filep, FAR char *buffer, size_t bufle
static ssize_t audio_write(FAR struct file *filep, FAR const char *buffer, size_t buflen)
{
FAR struct inode *inode = filep->f_inode;
FAR struct audio_upperhalf_s *upper = inode->i_private;
FAR struct audio_lowerhalf_s *lower = upper->dev;
/* TODO: Should we check permissions here? */
/* Audio write operations get passed directly to the lower-level */
if (lower->ops->write != NULL)
{
return lower->ops->write(lower, buffer, buflen);
}
return 0;
}
@ -269,7 +305,11 @@ static ssize_t audio_write(FAR struct file *filep, FAR const char *buffer, size_
*
************************************************************************************/
static int audio_start(FAR struct audio_upperhalf_s *upper, unsigned int oflags)
#ifdef CONFIG_AUDIO_MULTI_SESSION
static int audio_start(FAR struct audio_upperhalf_s *upper, FAR void *session)
#else
static int audio_start(FAR struct audio_upperhalf_s *upper)
#endif
{
FAR struct audio_lowerhalf_s *lower = upper->dev;
int ret = OK;
@ -280,17 +320,21 @@ static int audio_start(FAR struct audio_upperhalf_s *upper, unsigned int oflags)
if (!upper->started)
{
/* Invoke the bottom half method to start the pulse train */
/* Invoke the bottom half method to start the audio stream */
#ifdef CONFIG_AUDIO_MULTI_SESSION
ret = lower->ops->start(lower, session);
#else
ret = lower->ops->start(lower);
#endif
/* A return value of zero means that the pulse train was started
/* A return value of zero means that the audio stream was started
* successfully.
*/
if (ret == OK)
{
/* Indicate that the pulse train has started */
/* Indicate that the audio stream has started */
upper->started = true;
}
@ -309,10 +353,14 @@ static int audio_start(FAR struct audio_upperhalf_s *upper, unsigned int oflags)
static int audio_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
{
FAR struct inode *inode = filep->f_inode;
FAR struct inode *inode = filep->f_inode;
FAR struct audio_upperhalf_s *upper = inode->i_private;
FAR struct audio_lowerhalf_s *lower = upper->dev;
int ret;
FAR struct audio_buf_desc_s *bufdesc;
#ifdef CONFIG_AUDIO_MULTI_SESSION
FAR void *session;
#endif
int ret;
audvdbg("cmd: %d arg: %ld\n", cmd, arg);
@ -347,14 +395,19 @@ static int audio_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
case AUDIOIOC_CONFIGURE:
{
FAR const struct audio_caps_s *caps = (FAR const struct audio_caps_s*)((uintptr_t)arg);
FAR const struct audio_caps_desc_s *caps =
(FAR const struct audio_caps_desc_s*)((uintptr_t)arg);
DEBUGASSERT(lower->ops->configure != NULL);
audvdbg("AUDIOIOC_INITIALIZE: Device=%d", caps->ac_type);
audvdbg("AUDIOIOC_INITIALIZE: Device=%d", caps->caps.ac_type);
/* Call the lower-half driver configure handler */
ret = lower->ops->configure(lower, caps, &audio_callback, upper);
#ifdef CONFIG_AUDIO_MULTI_SESSION
ret = lower->ops->configure(lower, caps->session, &caps->caps);
#else
ret = lower->ops->configure(lower, &caps->caps);
#endif
}
break;
@ -369,10 +422,10 @@ static int audio_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
}
break;
/* AUDIOIOC_START - Start the pulsed output. The AUDIOIOC_SETCHARACTERISTICS
/* AUDIOIOC_START - Start the audio stream. The AUDIOIOC_SETCHARACTERISTICS
* command must have previously been sent.
*
* ioctl argument: None
* ioctl argument: Audio session
*/
case AUDIOIOC_START:
@ -380,17 +433,23 @@ static int audio_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
audvdbg("AUDIOIOC_START\n");
DEBUGASSERT(lower->ops->start != NULL);
/* Start the pulse train */
/* Start the audio stream */
ret = audio_start(upper, filep->f_oflags);
#ifdef CONFIG_AUDIO_MULTI_SESSION
session = (FAR void *) arg;
ret = audio_start(upper, session);
#else
ret = audio_start(upper);
#endif
}
break;
/* AUDIOIOC_STOP - Stop the pulsed output.
/* AUDIOIOC_STOP - Stop the audio stream.
*
* ioctl argument: None
* ioctl argument: Audio session
*/
#ifndef CONFIG_AUDIO_EXCLUDE_STOP
case AUDIOIOC_STOP:
{
audvdbg("AUDIOIOC_STOP\n");
@ -398,11 +457,191 @@ static int audio_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
if (upper->started)
{
#ifdef CONFIG_AUDIO_MULTI_SESSION
session = (FAR void *) arg;
ret = lower->ops->stop(lower, session);
#else
ret = lower->ops->stop(lower);
#endif
upper->started = false;
}
}
break;
#endif /* CONFIG_AUDIO_EXCLUDE_STOP */
/* AUDIOIOC_PAUSE - Pause the audio stream.
*
* ioctl argument: Audio session
*/
#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
case AUDIOIOC_PAUSE:
{
audvdbg("AUDIOIOC_PAUSE\n");
DEBUGASSERT(lower->ops->pause != NULL);
if (upper->started)
{
#ifdef CONFIG_AUDIO_MULTI_SESSION
session = (FAR void *) arg;
ret = lower->ops->pause(lower, session);
#else
ret = lower->ops->pause(lower);
#endif
}
}
break;
/* AUDIOIOC_RESUME - Resume the audio stream.
*
* ioctl argument: Audio session
*/
case AUDIOIOC_RESUME:
{
audvdbg("AUDIOIOC_RESUME\n");
DEBUGASSERT(lower->ops->resume != NULL);
if (upper->started)
{
#ifdef CONFIG_AUDIO_MULTI_SESSION
session = (FAR void *) arg;
ret = lower->ops->resume(lower, session);
#else
ret = lower->ops->resume(lower);
#endif
}
}
break;
#endif /* CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME */
/* AUDIOIOC_ALLOCBUFFER - Allocate an audio buffer
*
* ioctl argument: pointer to an audio_buf_desc_s structure
*/
case AUDIOIOC_ALLOCBUFFER:
{
audvdbg("AUDIOIOC_ALLOCBUFFER\n");
bufdesc = (FAR struct audio_buf_desc_s *) arg;
if (lower->ops->allocbuffer)
{
ret = lower->ops->allocbuffer(lower, bufdesc);
}
else
{
/* Perform a simple kumalloc operation assuming 1 session */
ret = apb_alloc(bufdesc);
}
}
break;
/* AUDIOIOC_FREEBUFFER - Free an audio buffer
*
* ioctl argument: pointer to an audio_buf_desc_s structure
*/
case AUDIOIOC_FREEBUFFER:
{
audvdbg("AUDIOIOC_FREEBUFFER\n");
bufdesc = (FAR struct audio_buf_desc_s *) arg;
if (lower->ops->freebuffer)
{
ret = lower->ops->freebuffer(lower, bufdesc);
}
else
{
/* Perform a simple kufree operation */
DEBUGASSERT(bufdesc->u.pBuffer != NULL);
apb_free(bufdesc->u.pBuffer);
ret = sizeof(struct audio_buf_desc_s);
}
}
break;
/* AUDIOIOC_ENQUEUEBUFFER - Enqueue an audio buffer
*
* ioctl argument: pointer to an audio_buf_desc_s structure
*/
case AUDIOIOC_ENQUEUEBUFFER:
{
audvdbg("AUDIOIOC_ENQUEUEBUFFER\n");
DEBUGASSERT(lower->ops->enqueuebuffer != NULL);
bufdesc = (FAR struct audio_buf_desc_s *) arg;
ret = lower->ops->enqueuebuffer(lower, bufdesc->u.pBuffer);
}
break;
/* AUDIOIOC_REGISTERMQ - Register a client Message Queue
*
* TODO: This needs to have multi session support.
*/
case AUDIOIOC_REGISTERMQ:
{
upper->usermq = (mqd_t) arg;
ret = OK;
}
break;
/* AUDIOIOC_UNREGISTERMQ - Register a client Message Queue
*
* TODO: This needs to have multi session support.
*/
case AUDIOIOC_UNREGISTERMQ:
{
upper->usermq = NULL;
ret = OK;
}
break;
/* AUDIOIOC_RESERVE - Reserve a session with the driver
*
* ioctl argument - pointer to receive the session context
*/
case AUDIOIOC_RESERVE:
{
DEBUGASSERT(lower->ops->reserve != NULL);
/* Call lower-half to perform the reservation */
#ifdef CONFIG_AUDIO_MULTI_SESSION
ret = lower->ops->reserve(lower, (FAR void **) arg);
#else
ret = lower->ops->reserve(lower);
#endif
}
break;
/* AUDIOIOC_RESERVE - Reserve a session with the driver
*
* ioctl argument - pointer to receive the session context
*/
case AUDIOIOC_RELEASE:
{
DEBUGASSERT(lower->ops->release != NULL);
/* Call lower-half to perform the release */
#ifdef CONFIG_AUDIO_MULTI_SESSION
ret = lower->ops->release(lower, (FAR void *) arg);
#else
ret = lower->ops->release(lower);
#endif
}
break;
/* Any unrecognized IOCTL commands might be platform-specific ioctl commands */
@ -419,6 +658,182 @@ static int audio_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
return ret;
}
/****************************************************************************
* Name: audio_dequeuebuffer
*
* Description:
* Dequeues a previously enqueued Audio Pipeline Buffer.
*
* 1. The upper half driver calls the enqueuebuffer method, providing the
* lower half driver with the ab_buffer to process.
* 2. The lower half driver's enqueuebuffer will either processes the
* buffer directly, or more likely add it to a queue for processing
* by a background thread or worker task.
* 3. When the lower half driver has completed processing of the enqueued
* ab_buffer, it will call this routine to indicate processing of the
* buffer is complete.
* 4. When this routine is called, it will check if any threads are waiting
* to enqueue additional buffers and "wake them up" for further
* processing.
*
* Input parameters:
* handle - This is the handle that was provided to the lower-half
* start() method.
* apb - A pointer to the previsously enqueued ap_buffer_s
* status - Status of the dequeue operation
*
* Returned Value:
* None
*
* Assumptions:
* This function may be called from an interrupt handler.
*
****************************************************************************/
#ifdef CONFIG_AUDIO_MULTI_SESSION
static inline void audio_dequeuebuffer(FAR struct audio_upperhalf_s *upper,
FAR struct ap_buffer_s *apb, uint16_t status,
FAR void *session)
#else
static inline void audio_dequeuebuffer(FAR struct audio_upperhalf_s *upper,
FAR struct ap_buffer_s *apb, uint16_t status)
#endif
{
struct audio_msg_s msg;
audllvdbg("Entry\n");
/* Send a dequeue message to the user if a message queue is registered */
if (upper->usermq != NULL)
{
msg.msgId = AUDIO_MSG_DEQUEUE;
msg.u.pPtr = apb;
#ifdef CONFIG_AUDIO_MULTI_SESSION
msg.session = session;
#endif
apb->flags |= AUDIO_APB_DEQUEUED;
mq_send(upper->usermq, &msg, sizeof(msg), CONFIG_AUDIO_BUFFER_DEQUEUE_PRIO);
}
}
/****************************************************************************
* Name: audio_complete
*
* Description:
* Send an AUDIO_MSG_COMPLETE message to the client to indicate that the
* active playback has completed. The lower-half driver initiates this
* call via its callback pointer to our upper-half driver.
*
****************************************************************************/
#ifdef CONFIG_AUDIO_MULTI_SESSION
static inline void audio_complete(FAR struct audio_upperhalf_s *upper,
FAR struct ap_buffer_s *apb, uint16_t status,
FAR void *session)
#else
static inline void audio_complete(FAR struct audio_upperhalf_s *upper,
FAR struct ap_buffer_s *apb, uint16_t status)
#endif
{
struct audio_msg_s msg;
audllvdbg("Entry\n");
/* Send a dequeue message to the user if a message queue is registered */
upper->started = false;
if (upper->usermq != NULL)
{
msg.msgId = AUDIO_MSG_COMPLETE;
msg.u.pPtr = NULL;
#ifdef CONFIG_AUDIO_MULTI_SESSION
msg.session = session;
#endif
mq_send(upper->usermq, &msg, sizeof(msg),
CONFIG_AUDIO_BUFFER_DEQUEUE_PRIO);
}
}
/****************************************************************************
* Name: audio_callback
*
* Description:
* Provides a callback interface for lower-half drivers to call to the
* upper-half for buffer dequeueing, error reporting, etc.
*
* Input parameters:
* priv - Private context data owned by the upper-half
* reason - The reason code for the callback
* apb - A pointer to the previsously enqueued ap_buffer_s
* status - Status information associated with the callback
*
* Returned Value:
* None
*
* Assumptions:
* This function may be called from an interrupt handler.
*
****************************************************************************/
#ifdef CONFIG_AUDIO_MULTI_SESSION
static void audio_callback(FAR void *handle, uint16_t reason,
FAR struct ap_buffer_s *apb, uint16_t status,
FAR void *session)
#else
static void audio_callback(FAR void *handle, uint16_t reason,
FAR struct ap_buffer_s *apb, uint16_t status)
#endif
{
FAR struct audio_upperhalf_s *upper = (FAR struct audio_upperhalf_s *)handle;
audllvdbg("Entry\n");
/* Perform operation based on reason code */
switch (reason)
{
case AUDIO_CALLBACK_DEQUEUE:
{
/* Call the dequeue routine */
#ifdef CONFIG_AUDIO_MULTI_SESSION
audio_dequeuebuffer(upper, apb, status, session);
#else
audio_dequeuebuffer(upper, apb, status);
#endif
break;
}
/* Lower-half I/O error occurred */
case AUDIO_CALLBACK_IOERR:
{
}
break;
/* Lower-half driver has completed a playback */
case AUDIO_CALLBACK_COMPLETE:
{
/* Send a complete message to the user if a message queue is registered */
#ifdef CONFIG_AUDIO_MULTI_SESSION
audio_complete(upper, apb, status, session);
#else
audio_complete(upper, apb, status);
#endif
}
break;
default:
{
auddbg("Unknown callback reason code %d\n", reason);
break;
}
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -451,14 +866,14 @@ static int audio_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
int audio_register(FAR const char *name, FAR struct audio_lowerhalf_s *dev)
{
FAR struct audio_upperhalf_s *upper;
char path[AUDIO_MAX_DEVICE_PATH];
char path[AUDIO_MAX_DEVICE_PATH];
static bool dev_audio_created = false;
#ifndef CONFIG_AUDIO_CUSTOM_DEV_PATH
const char* devname = "/dev/audio";
#elif !defined(CONFIG_AUDIO_DEV_ROOT)
const char* devname = CONFIG_AUDIO_DEV_PATH;
const char* ptr;
char* pathptr;
char* pathptr;
#endif
/* Allocate the upper-half data structure */
@ -570,102 +985,13 @@ int audio_register(FAR const char *name, FAR struct audio_lowerhalf_s *dev)
strncat(path, name, AUDIO_MAX_DEVICE_PATH - 11);
#endif
/* Give the lower-half a context to the upper half */
dev->upper = audio_callback;
dev->priv = upper;
audvdbg("Registering %s\n", path);
return register_driver(path, &g_audioops, 0666, upper);
}
/****************************************************************************
* Name: audio_dequeuebuffer
*
* Description:
* Dequeues a previously enqueued Audio Pipeline Buffer.
*
* 1. The upper half driver calls the enqueuebuffer method, providing the
* lower half driver with the ab_buffer to process.
* 2. The lower half driver's enqueuebuffer will either processes the
* buffer directly, or more likely add it to a queue for processing
* by a background thread or worker task.
* 3. When the lower half driver has completed processing of the enqueued
* ab_buffer, it will call this routine to indicated processing of the
* buffer is complete.
* 4. When this routine is called, it will check if any threads are waiting
* to enqueue additional buffers and "wake them up" for further
* processing.
*
* Input parameters:
* handle - This is the handle that was provided to the lower-half
* start() method.
* apb - A pointer to the previsously enqueued ap_buffer_s
* status - Status of the dequeue operation
*
* Returned Value:
* None
*
* Assumptions:
* This function may be called from an interrupt handler.
*
****************************************************************************/
static inline void audio_dequeuebuffer(FAR struct audio_upperhalf_s *upper,
FAR struct ap_buffer_s *apb, uint16_t status)
{
audllvdbg("Entry\n");
/* TODO: Implement the logic */
}
/****************************************************************************
* Name: audio_callback
*
* Description:
* Provides a callback interface for lower-half drivers to call to the
* upper-half for buffer dequeueing, error reporting, etc.
*
* Input parameters:
* priv - Private context data owned by the upper-half
* reason - The reason code for the callback
* apb - A pointer to the previsously enqueued ap_buffer_s
* status - Status information associated with the callback
*
* Returned Value:
* None
*
* Assumptions:
* This function may be called from an interrupt handler.
*
****************************************************************************/
static void audio_callback(FAR void *handle, uint16_t reason,
FAR struct ap_buffer_s *apb, uint16_t status)
{
FAR struct audio_upperhalf_s *upper = (FAR struct audio_upperhalf_s *)handle;
audllvdbg("Entry\n");
/* Perform operation based on reason code */
switch (reason)
{
case AUDIO_CALLBACK_DEQUEUE:
{
/* Call the dequeue routine */
audio_dequeuebuffer(upper, apb, status);
break;
}
case AUDIO_CALLBACK_IOERR:
{
}
break;
default:
{
auddbg("Unknown callback reason code %d\n", reason);
break;
}
}
}
#endif /* CONFIG_AUDIO */

View File

@ -84,11 +84,11 @@
*
****************************************************************************/
static void apb_semtake(sem_t *sem)
static void apb_semtake(FAR struct ap_buffer_s *apb)
{
/* Take the semaphore (perhaps waiting) */
while (sem_wait(sem) != 0)
while (sem_wait(&apb->sem) != 0)
{
/* The only case that an error should occr here is if
* the wait was awakened by a signal.
@ -102,7 +102,7 @@ static void apb_semtake(sem_t *sem)
* Name: apb_semgive
****************************************************************************/
#define apb_semgive(s) sem_post(s)
#define apb_semgive(b) sem_post(&b->sem)
/****************************************************************************
* Name: apb_alloc
@ -113,11 +113,41 @@ static void apb_semtake(sem_t *sem)
*
****************************************************************************/
FAR struct ap_buffer_s *apb_alloc(int type, int sampleCount)
int apb_alloc(FAR struct audio_buf_desc_s * bufdesc)
{
/* TODO: Implement the alloc logic */
uint32_t bufsize;
int ret;
struct ap_buffer_s *pBuf;
return NULL;
DEBUGASSERT(bufdesc->u.ppBuffer != NULL);
/* Perform a user mode allocation */
bufsize = sizeof(struct ap_buffer_s) + bufdesc->numbytes;
pBuf = kumalloc(bufsize);
*bufdesc->u.ppBuffer = pBuf;
/* Test if the allocation was successful or not */
if (*bufdesc->u.ppBuffer == NULL)
ret = -ENOMEM;
else
{
/* Populate the buffer contents */
memset(pBuf, bufsize, 0);
pBuf->i.channels = 1;
pBuf->crefs = 1;
pBuf->nmaxbytes = bufdesc->numbytes;
pBuf->nbytes = 0;
#ifdef CONFIG_AUDIO_MULTI_SESSION
pBuf->session = bufdesc->session;
#endif
sem_init(&pBuf->sem, 0, 1);
ret = sizeof(struct audio_buf_desc_s);
}
return ret;
}
/****************************************************************************
@ -143,8 +173,19 @@ void apb_prepare(FAR struct ap_buffer_s *apb, int8_t allocmode, uint8_t format,
void apb_free(FAR struct ap_buffer_s *apb)
{
int refcount;
/* Perform a reference count decrement and possibly release the memory */
apb_semtake(apb);
refcount = apb->crefs--;
apb_semgive(apb);
if (refcount == 1)
{
auddbg("Freeing %p\n", apb);
kufree(apb);
}
}
/****************************************************************************
@ -158,7 +199,11 @@ void apb_free(FAR struct ap_buffer_s *apb)
void apb_reference(FAR struct ap_buffer_s *apb)
{
/* TODO: Implement the reference logic */
/* Do we need any thread protection here? Almost certaily... */
apb_semtake(apb);
apb->crefs++;
apb_semgive(apb);
}
#endif /* CONFIG_AUDIO */

View File

@ -36,10 +36,10 @@
#ifndef __INCLUDE_NUTTX_AUDIO_AUDIO_H
#define __INCLUDE_NUTTX_AUDIO_AUDIO_H
/* For the purposes of this driver, an Audio device is any device that
/* For the purposes of this driver, an Audio device is any device that
* generates, records, mixes, or otherwise modifies audio data in any format,
* such as PCM, MP3, AAC, etc.
*
*
* The Audio driver is split into two parts:
*
* 1) An "upper half", generic driver that provides the comman Audio interface
@ -57,6 +57,8 @@
#include <nuttx/fs/ioctl.h>
#include <nuttx/spi/spi.h>
#include <queue.h>
#include <semaphore.h>
#ifdef CONFIG_AUDIO
@ -69,10 +71,10 @@
* CONFIG_DEBUG_VERBOSE), this will generate output that can be used to
* debug Audio drivers.
*/
/* IOCTL Commands ***********************************************************/
/* The Audio module uses a standard character driver framework. However, a
* lot of the Audio driver functionality is configured via a device control
* lot of the Audio driver functionality is configured via a device control
* interface, such as sampling rate, volume, data format, etc.
* The Audio ioctl commands are lised below:
*
@ -81,7 +83,7 @@
* ioctl argument: Pointer to the audio_caps_s structure to receive the
* capabilities info. The "len" and "type" fields should
* be filled in prior to calling this ioctl. To get
* overall capabilities, specify the type as
* overall capabilities, specify the type as
* AUDIO_TYPE_QUERY, otherwise specify any type that was
* reported by the device during the QUERY.
*
@ -104,10 +106,21 @@
*/
#define AUDIOIOC_GETCAPS _AUDIOIOC(1)
#define AUDIOIOC_CONFIGURE _AUDIOIOC(2)
#define AUDIOIOC_SHUTDOWN _AUDIOIOC(3)
#define AUDIOIOC_START _AUDIOIOC(4)
#define AUDIOIOC_STOP _AUDIOIOC(5)
#define AUDIOIOC_RESERVE _AUDIOIOC(2)
#define AUDIOIOC_RELEASE _AUDIOIOC(3)
#define AUDIOIOC_CONFIGURE _AUDIOIOC(4)
#define AUDIOIOC_SHUTDOWN _AUDIOIOC(5)
#define AUDIOIOC_START _AUDIOIOC(6)
#define AUDIOIOC_STOP _AUDIOIOC(7)
#define AUDIOIOC_PAUSE _AUDIOIOC(8)
#define AUDIOIOC_RESUME _AUDIOIOC(9)
#define AUDIOIOC_GETBUFFERINFO _AUDIOIOC(10)
#define AUDIOIOC_ALLOCBUFFER _AUDIOIOC(11)
#define AUDIOIOC_FREEBUFFER _AUDIOIOC(12)
#define AUDIOIOC_ENQUEUEBUFFER _AUDIOIOC(13)
#define AUDIOIOC_REGISTERMQ _AUDIOIOC(14)
#define AUDIOIOC_UNREGISTERMQ _AUDIOIOC(15)
#define AUDIOIOC_HWRESET _AUDIOIOC(16)
/* Audio Device Types *******************************************************/
/* The NuttX audio interface support different types of audio devices for
@ -129,16 +142,17 @@
/* Audio Format Types *******************************************************/
/* The following defines the audio data format types in NuttX. */
#define AUDIO_FMT_UNDEF 0x00
#define AUDIO_FMT_OTHER 0x01
#define AUDIO_FMT_MPEG 0x02
#define AUDIO_FMT_AC3 0x03
#define AUDIO_FMT_WMA 0x04
#define AUDIO_FMT_DTS 0x05
#define AUDIO_FMT_PCM 0x06
#define AUDIO_FMT_MP3 0x07
#define AUDIO_FMT_MIDI 0x08
#define AUDIO_FMT_OGG_VORBIS 0x09
#define AUDIO_FMT_UNDEF 0x000
#define AUDIO_FMT_OTHER 0x001
#define AUDIO_FMT_MPEG 0x002
#define AUDIO_FMT_AC3 0x004
#define AUDIO_FMT_WMA 0x008
#define AUDIO_FMT_DTS 0x010
#define AUDIO_FMT_PCM 0x020
#define AUDIO_FMT_WAV 0x020
#define AUDIO_FMT_MP3 0x040
#define AUDIO_FMT_MIDI 0x080
#define AUDIO_FMT_OGG_VORBIS 0x100
/* Audio Sub-Format Types ***************************************************/
@ -156,21 +170,72 @@
/* Supported Sampling Rates *************************************************/
#define AUDIO_RATE_22K 0x01
#define AUDIO_RATE_44K 0x02
#define AUDIO_RATE_48K 0x03
#define AUDIO_RATE_96K 0x04
#define AUDIO_RATE_128K 0x05
#define AUDIO_RATE_160K 0x06
#define AUDIO_RATE_172K 0x07
#define AUDIO_RATE_192K 0x08
#define AUDIO_RATE_320K 0x09
#define AUDIO_SAMP_RATE_8K 0x0001
#define AUDIO_SAMP_RATE_11K 0x0002
#define AUDIO_SAMP_RATE_16K 0x0004
#define AUDIO_SAMP_RATE_22K 0x0008
#define AUDIO_SAMP_RATE_32K 0x0010
#define AUDIO_SAMP_RATE_44K 0x0020
#define AUDIO_SAMP_RATE_48K 0x0040
#define AUDIO_SAMP_RATE_96K 0x0080
#define AUDIO_SAMP_RATE_128K 0x0100
#define AUDIO_SAMP_RATE_160K 0x0200
#define AUDIO_SAMP_RATE_172K 0x0400
#define AUDIO_SAMP_RATE_192K 0x0800
/* Supported Bit Rates *************************************************/
#define AUDIO_BIT_RATE_22K 0x01
#define AUDIO_BIT_RATE_44K 0x02
#define AUDIO_BIT_RATE_48K 0x04
#define AUDIO_BIT_RATE_96K 0x08
#define AUDIO_BIT_RATE_128K 0x10
#define AUDIO_BIT_RATE_160K 0x20
#define AUDIO_BIT_RATE_172K 0x40
#define AUDIO_BIT_RATE_192K 0x80
/* Supported Feature Units controls *****************************************/
#define AUDIO_FU_UNDEF 0x0000
#define AUDIO_FU_MUTE 0x0001
#define AUDIO_FU_VOLUME 0x0002
#define AUDIO_FU_BASS 0x0004
#define AUDIO_FU_MID 0x0008
#define AUDIO_FU_TREBLE 0x0010
#define AUDIO_FU_EQUALIZER 0x0020
#define AUDIO_FU_AGC 0x0040
#define AUDIO_FU_DELAY 0x0080
#define AUDIO_FU_BASS_BOOST 0x0100
#define AUDIO_FU_LOUDNESS 0x0200
#define AUDIO_FU_INP_GAIN 0x0400
#define AUDIO_FU_BALANCE 0x0800
#define AUDIO_FU_PHASE_INVERT 0x1000
#define AUDIO_FU_UNDERFLOW 0x2000
#define AUDIO_FU_OVERFLOW 0x4000
#define AUDIO_FU_LATENCY 0x8000
/* Processing Unit controls *************************************************/
#define AUDIO_PU_UNDEF 0x00
#define AUDIO_PU_UPDOWNMIX 0x01
#define AUDIO_PU_DOLBY_PROLOGIC 0x02
#define AUDIO_PU_STEREO_EXTENDER 0x03
/* Stereo Extender PU Controls **********************************************/
#define AUDIO_STEXT_UNDEF 0x00
#define AUDIO_STEXT_ENABLE 0x01
#define AUDIO_STEXT_WIDTH 0x02
#define AUDIO_STEXT_UNDERFLOW 0x03
#define AUDIO_STEXT_OVERFLOW 0x04
#define AUDIO_STEXT_LATENCY 0x05
/* Audio Callback Reasons ***************************************************/
#define AUDIO_CALLBACK_UNDEF 0x00
#define AUDIO_CALLBACK_DEQUEUE 0x01
#define AUDIO_CALLBACK_IOERR 0x02
#define AUDIO_CALLBACK_COMPLETE 0x03
/* Audio Pipeline Buffer (AP Buffer) flags **********************************/
@ -186,6 +251,25 @@
* operation, etc.
*/
/* Standard Audio Message Queue message IDs */
#define AUDIO_MSG_NONE 0
#define AUDIO_MSG_DEQUEUE 1
#define AUDIO_MSG_START 2
#define AUDIO_MSG_STOP 3
#define AUDIO_MSG_PAUSE 4
#define AUDIO_MSG_RESUME 5
#define AUDIO_MSG_DATA_REQUEST 6
#define AUDIO_MSG_ENQUEUE 7
#define AUDIO_MSG_COMPLETE 8
#define AUDIO_MSG_USER 64
/* Audio Pipeline Buffer flags */
#define AUDIO_APB_OUTPUT_ENQUEUED 0x0001;
#define AUDIO_APB_OUTPUT_PROCESS 0x0002;
#define AUDIO_APB_DEQUEUED 0x0004;
/****************************************************************************
* Public Types
****************************************************************************/
@ -212,6 +296,14 @@ struct audio_caps_s
* by this lower-half driver. */
};
struct audio_caps_desc_s
{
#ifdef CONFIG_AUDIO_MULTI_SESSION
FAR void *session; /* Associated session */
#endif
struct audio_caps_s caps; /* The capabilities struct */
};
/* This structure describes the characteristics of the Audio samples */
struct audio_info_s
@ -222,21 +314,99 @@ struct audio_info_s
uint8_t subformat; /* Audio subformat (maybe should be combined with format? */
};
/* This structure describes the preferred number and size of
* audio pipeline buffers for the audio device. Each device
* may have unique needs regarding size and qty of buffers,
* so this info is queried from the lower-half driver.
*/
#ifdef CONFIG_AUDIO_DRIVER_SPECIFIC_BUFFERS
struct ap_buffer_info_s
{
apb_samp_t nbuffers; /* Preferred qty of buffers */
apb_samp_t buffer_size; /* Preferred size of the buffers */
};
#endif
/* This structure describes an Audio Pipeline Buffer */
struct ap_buffer_s
{
struct dq_entry_s dq_entry; /* Double linked queue entry */
struct audio_info_s i; /* The info for samples in this buffer */
apb_samp_t nmaxsamples;/* The maximum number of samples */
apb_samp_t nsamples; /* The number of samples used */
#ifdef CONFIG_AUDIO_MULTI_SESSION
FAR void *session; /* Associated session */
#endif
apb_samp_t nmaxbytes; /* The maximum number of bytes */
apb_samp_t nbytes; /* The number of bytes used */
apb_samp_t curbyte; /* Next byte to be processed */
sem_t sem; /* Reference locking semaphore */
uint16_t flags; /* Buffer flags */
uint16_t crefs; /* Number of reference counts */
uint8_t samp[0]; /* Offset of the first sample */
} packed_struct;
/* Structure defining the messages passed to a listening audio thread
* for dequeuing buffers and other operations. Also used to allocate
* and enqueue buffers via the AUDIOIOC_ALLOCBUFFER, AUDIOIOC_FREEBUFFER,
* and AUDIOIOC_ENQUEUEBUFFER ioctls.
*/
struct audio_msg_s
{
#ifdef CONFIG_AUDIO_MULTI_SESSION
FAR void *session; /* Associated channel */
#endif
uint16_t msgId; /* Message ID */
union
{
FAR void * pPtr; /* Buffer being dequeued */
uint32_t data; /* Message data */
} u;
};
/* Strucure defining the built-in sounds */
#ifdef CONFIG_AUDIO_BUILTIN_SOUNDS
struct audio_sound_s
{
const char *name; /* Name of the sound */
uint32_t id; /* ID of the sound */
uint32_t type; /* Type of sound */
uint32_t size; /* Number of bytes in the sound */
const uint8_t *data; /* Pointer to the data */
};
#endif
/* Structure for allocating, freeing and enqueuing audio pipeline
* buffers via the AUDIOIOC_ALLOCBUFFER, AUDIOIOC_FREEBUFFER,
* and AUDIOIOC_ENQUEUEBUFFER ioctls.
*/
struct audio_buf_desc_s
{
#ifdef CONFIG_AUDIO_MULTI_SESSION
FAR void *session; /* Associated channel */
#endif
uint16_t numbytes; /* Number of bytes to allocate */
union
{
FAR struct ap_buffer_s *pBuffer; /* Buffer to free / enqueue */
FAR struct ap_buffer_s **ppBuffer; /* Pointer to receive alloced buffer */
} u;
};
/* Typedef for lower-level to upper-level callback for buffer dequeuing */
#ifdef CONFIG_AUDIO_MULTI_SESSION
typedef CODE void (*audio_callback_t)(FAR void *priv, uint16_t reason,
FAR struct ap_buffer_s *apb, uint16_t status, FAR void *session);
#else
typedef CODE void (*audio_callback_t)(FAR void *priv, uint16_t reason,
FAR struct ap_buffer_s *apb, uint16_t status);
#endif
/* This structure is a set a callback functions used to call from the upper-
* half, generic Audo driver into lower-half, platform-specific logic that
@ -249,25 +419,29 @@ struct audio_ops_s
/* This method is called to retrieve the lower-half device capabilities.
* It will be called with device type AUDIO_TYPE_QUERY to request the
* overall capabilities, such as to determine the types of devices supported
* audio formats supported, etc. Then it may be called once or more with
* reported supported device types to determine the specific capabilities
* audio formats supported, etc. Then it may be called once or more with
* reported supported device types to determine the specific capabilities
* of that device type (such as MP3 encoder, WMA encoder, PCM output, etc.).
*/
CODE int (*getcaps)(FAR struct audio_lowerhalf_s *dev, int type,
CODE int (*getcaps)(FAR struct audio_lowerhalf_s *dev, int type,
FAR struct audio_caps_s *pCaps);
/* This method is called to bind the lower-level driver to the upper-level
* driver and to configure the driver for a specific mode of
* operation defined by the parameters selected in supplied device caps
* structure. The lower-level device should perform any initialization
* needed to prepare for operations in the specified mode. It should not,
* structure. The lower-level device should perform any initialization
* needed to prepare for operations in the specified mode. It should not,
* however, process any audio data until the start method is called.
*/
CODE int (*configure)(FAR struct audio_lowerhalf_s *dev,
FAR const struct audio_caps_s *pCaps,
audio_callback_t upper, FAR void *priv);
#ifdef CONFIG_AUDIO_MULTI_SESSION
CODE int (*configure)(FAR struct audio_lowerhalf_s *dev,
FAR void *session, FAR const struct audio_caps_s *pCaps);
#else
CODE int (*configure)(FAR struct audio_lowerhalf_s *dev,
FAR const struct audio_caps_s *pCaps);
#endif
/* This method is called when the driver is closed. The lower half driver
* should stop processing audio data, including terminating any active
@ -280,26 +454,75 @@ struct audio_ops_s
CODE int (*shutdown)(FAR struct audio_lowerhalf_s *dev);
/* Start audio streaming in the configured mode. For input and synthesis
* devices, this means it should begin sending streaming audio data. For output
* or processing type device, it means it should begin processing of any enqueued
/* Start audio streaming in the configured mode. For input and synthesis
* devices, this means it should begin sending streaming audio data. For output
* or processing type device, it means it should begin processing of any enqueued
* Audio Pipline Buffers.
*/
#ifdef CONFIG_AUDIO_MULTI_SESSION
CODE int (*start)(FAR struct audio_lowerhalf_s *dev, FAR void *session);
#else
CODE int (*start)(FAR struct audio_lowerhalf_s *dev);
#endif
/* Stop audio streaming and/or processing of enqueued Audio Pipeline Buffers */
#ifndef CONFIG_AUDIO_EXCLUDE_STOP
#ifdef CONFIG_AUDIO_MULTI_SESSION
CODE int (*stop)(FAR struct audio_lowerhalf_s *dev, FAR void *session);
#else
CODE int (*stop)(FAR struct audio_lowerhalf_s *dev);
#endif
#endif
/* Enqueue a buffer for processing. This is a non-blocking enqueue operation.
* If the lower-half driver's buffer queue is full, then it should return an
j* error code of -ENOMEM, and the upper-half driver can decide to either block
* the calling thread or deal with it in a non-blocking manner.
* For each call to enqueuebuffer, the lower-half driver must call
* audio_dequeuebuffer when it is finished processing the bufferr, passing the
* previously enqueued apb and a dequeue status so that the upper-half driver
/* Pause the audio stream. Should keep current playback context active
* in case a resume is issued. Could be called and then followed by a stop.
*/
#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
#ifdef CONFIG_AUDIO_MULTI_SESSION
CODE int (*pause)(FAR struct audio_lowerhalf_s *dev, FAR void *session);
#else
CODE int (*pause)(FAR struct audio_lowerhalf_s *dev);
#endif
/* Resumes audio streaming after a pause */
#ifdef CONFIG_AUDIO_MULTI_SESSION
CODE int (*resume)(FAR struct audio_lowerhalf_s *dev, FAR void *session);
#else
CODE int (*resume)(FAR struct audio_lowerhalf_s *dev);
#endif
#endif /* CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME */
/* Allocate an audio pipeline buffer. This routine provides the
* lower-half driver with the opportunity to perform special buffer
* allocation if needed, such as allocating from a specific memory
* region (DMA-able, etc.). If not supplied, then the top-half
* driver will perform a standard kumalloc using normal user-space
* memory region.
*/
CODE int (*allocbuffer)(FAR struct audio_lowerhalf_s *dev,
FAR struct audio_buf_desc_s *apb);
/* Free an audio pipeline buffer. If the lower-level driver
* provides an allocbuffer routine, it should also provide the
* freebuffer routine to perform the free operation.
*/
CODE int (*freebuffer)(FAR struct audio_lowerhalf_s *dev,
FAR struct audio_buf_desc_s *apb);
/* Enqueue a buffer for processing. This is a non-blocking enqueue operation.
* If the lower-half driver's buffer queue is full, then it should return an
* error code of -ENOMEM, and the upper-half driver can decide to either block
* the calling thread or deal with it in a non-blocking manner.
* For each call to enqueuebuffer, the lower-half driver must call
* audio_dequeuebuffer when it is finished processing the bufferr, passing the
* previously enqueued apb and a dequeue status so that the upper-half driver
* can decide if a waiting thread needs to be release, if the dequeued buffer
* should be passed to the next block in the Audio Pipeline, etc.
*/
@ -316,6 +539,37 @@ struct audio_ops_s
CODE int (*ioctl)(FAR struct audio_lowerhalf_s *dev,
int cmd, unsigned long arg);
/* Lower-half logic may support platform-specific read commands */
CODE int (*read)(FAR struct audio_lowerhalf_s *dev,
FAR char *buffer, size_t buflen);
/* Lower-half logic may support platform-specific write commands */
CODE int (*write)(FAR struct audio_lowerhalf_s *dev,
FAR const char *buffer, size_t buflen);
/* Reserve a session (may only be one per device or may be multiple) for
* use by a client. Client software can open audio devices and issue
* AUDIOIOC_GETCAPS calls freely, but other operations require a
* reservation. A session reservation will assign a context that must
* be passed with
*/
#ifdef CONFIG_AUDIO_MULTI_SESSION
CODE int (*reserve)(FAR struct audio_lowerhalf_s *dev, FAR void **psession );
#else
CODE int (*reserve)(FAR struct audio_lowerhalf_s *dev);
#endif
/* Release a session. */
#ifdef CONFIG_AUDIO_MULTI_SESSION
CODE int (*release)(FAR struct audio_lowerhalf_s *dev, FAR void *session );
#else
CODE int (*release)(FAR struct audio_lowerhalf_s *dev);
#endif
};
/* This structure is the generic form of state structure used by lower half
@ -325,8 +579,8 @@ struct audio_ops_s
* maintain state information.
*
* Normally that Audio logic will have its own, custom state structure
* that is simply cast to struct audio_lowerhalf_s. In order to perform such
* casts, the initial fields of the custom state structure match the initial
* that is simply cast to struct audio_lowerhalf_s. In order to perform such
* casts, the initial fields of the custom state structure match the initial
* fields of the following generic Audio state structure.
*/
@ -348,7 +602,7 @@ struct audio_lowerhalf_s
FAR void *priv;
/* The custom Audio device state structure may include additional fields
/* The custom Audio device state structure may include additional fields
* after the pointer to the Audio callback structure.
*/
};
@ -363,7 +617,8 @@ struct audio_lowerhalf_s
#ifdef __cplusplus
#define EXTERN extern "C"
extern "C" {
extern "C"
{
#else
#define EXTERN extern
#endif
@ -387,7 +642,7 @@ extern "C" {
* a full path to the driver in the format "/dev/audio/[name]" in the NuttX
* filesystem (i.e. the path "/dev/audio" will be prepended to the supplied
* device name. The recommended convention is to name Audio drivers
* based on the type of functionality they provide, such as "/dev/audio/pcm0",
* based on the type of functionality they provide, such as "/dev/audio/pcm0",
* "/dev/audio/midi0", "/dev/audio/mp30, etc.
* dev - A pointer to an instance of lower half audio driver. This instance
* is bound to the Audio driver and must persists as long as the driver
@ -398,7 +653,7 @@ extern "C" {
*
****************************************************************************/
EXTERN int audio_register(FAR const char *name, FAR struct audio_lowerhalf_s *dev);
int audio_register(FAR const char *name, FAR struct audio_lowerhalf_s *dev);
/****************************************************************************
* Name: abp_alloc
@ -410,13 +665,14 @@ EXTERN int audio_register(FAR const char *name, FAR struct audio_lowerhalf_s *de
* and then call apb_prepare, passing it the allocated memory.
*
* Input parameters:
* bufdesc: Pointer to a buffer descriptor
*
* Returned Value:
* Pointer to the allocated buffer or NULL if no memory.
*
****************************************************************************/
FAR struct ap_buffer_s *apb_alloc(int type, int sampleCount);
int apb_alloc(FAR struct audio_buf_desc_s *bufdesc);
/****************************************************************************
* Name: abp_prepare
@ -437,8 +693,8 @@ FAR struct ap_buffer_s *apb_alloc(int type, int sampleCount);
*
****************************************************************************/
EXTERN void apb_prepare(struct ap_buffer_s *apb, int8_t allocmode, uint8_t format,
uint8_t subformat, apb_samp_t maxsamples);
void apb_prepare(struct ap_buffer_s *apb, int8_t allocmode, uint8_t format,
uint8_t subformat, apb_samp_t maxsamples);
/****************************************************************************
* Name: apb_free
@ -447,7 +703,7 @@ EXTERN void apb_prepare(struct ap_buffer_s *apb, int8_t allocmode, uint8_t forma
*
****************************************************************************/
EXTERN void apb_free(FAR struct ap_buffer_s *apb);
void apb_free(FAR struct ap_buffer_s *apb);
/****************************************************************************
* Name: apb_reference
@ -458,7 +714,7 @@ EXTERN void apb_free(FAR struct ap_buffer_s *apb);
*
****************************************************************************/
EXTERN void apb_reference(FAR struct ap_buffer_s *apb);
void apb_reference(FAR struct ap_buffer_s *apb);
/****************************************************************************
* Platform-Dependent "Lower-Half" Audio Driver Interfaces