summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2013-10-27 07:44:53 -0600
committerGregory Nutt <gnutt@nuttx.org>2013-10-27 07:44:53 -0600
commit66bc3094e689ff4a96c9ac2755335d45b8765aa1 (patch)
treea25e3cf4f1a61bcd727587fefc2725316c82ee05
parent6dc974b4b0d8423cc9073e425a2e3a4370160df6 (diff)
downloadpx4-nuttx-66bc3094e689ff4a96c9ac2755335d45b8765aa1.tar.gz
px4-nuttx-66bc3094e689ff4a96c9ac2755335d45b8765aa1.tar.bz2
px4-nuttx-66bc3094e689ff4a96c9ac2755335d45b8765aa1.zip
Updated audio subsystem from Ken Pettit
-rw-r--r--nuttx/audio/Kconfig150
-rw-r--r--nuttx/audio/Makefile12
-rw-r--r--nuttx/audio/README.txt125
-rw-r--r--nuttx/audio/audio.c570
-rw-r--r--nuttx/audio/buffer.c59
-rw-r--r--nuttx/include/nuttx/audio/audio.h376
6 files changed, 1061 insertions, 231 deletions
diff --git a/nuttx/audio/Kconfig b/nuttx/audio/Kconfig
index 7ce503aaf..ef4bfe779 100644
--- a/nuttx/audio/Kconfig
+++ b/nuttx/audio/Kconfig
@@ -11,53 +11,64 @@ 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_CUSTOM_DEV_PATH
- bool "Use custom device path"
- default n
+config AUDIO_NUM_BUFFERS
+ int "Number of buffers for audio processing"
+ default 2
---help---
- By default, all audio devices on the target are are registered in the
- /dev/audio directory. Select this option to change the default location
- for the device registration.
-
-if AUDIO_CUSTOM_DEV_PATH
+ 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_DEV_ROOT
- bool "Place audio devices in /dev"
+config AUDIO_DRIVER_SPECIFIC_BUFFERS
+ bool "Support for Driver specified buffer sizes"
default n
---help---
- This option causes all device entries to appear in /dev with all the
- other device entries. This option generates the smallest code and
- RAM footprint.
+ 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.
-if !AUDIO_DEV_ROOT
+menu "Supported Audio Formats"
-config AUDIO_DEV_PATH
- string "Base path for Audio devices"
- default "/dev/audio"
+config AUDIO_FORMAT_AC3
+ bool "AC3 Format"
+ default n
---help---
- The path on the target where audio devices are registered. The default
- is to place all audio devices in the /dev/audio/ directory.
+ Build in support for AC3 (Dolby Digital) Audio format.
-endif
-endif
-
-menu "Supported Audio Formats"
+config AUDIO_FORMAT_DTS
+ bool "DTS Format"
+ default n
+ ---help---
+ Add in support for DTS format.
config AUDIO_FORMAT_PCM
bool "PCM Audio"
@@ -67,10 +78,16 @@ config AUDIO_FORMAT_PCM
config AUDIO_FORMAT_MP3
bool "MPEG 3 Layer 1"
- default n
+ 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
@@ -85,6 +102,79 @@ config AUDIO_FORMAT_OGG_VORBIS
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
+ ---help---
+ By default, all audio devices on the target are are registered in the
+ /dev/audio directory. Select this option to change the default location
+ for the device registration.
+
+if AUDIO_CUSTOM_DEV_PATH
+
+config AUDIO_DEV_ROOT
+ bool "Place audio devices in /dev"
+ default n
+ ---help---
+ This option causes all device entries to appear in /dev with all the
+ other device entries. This option generates the smallest code and
+ RAM footprint.
+
+if !AUDIO_DEV_ROOT
+
+config AUDIO_DEV_PATH
+ string "Base path for Audio devices"
+ default "/dev/audio"
+ ---help---
+ The path on the target where audio devices are registered. The default
+ is to place all audio devices in the /dev/audio/ directory.
+
+endif
+endif
+
+
# These are here as placeholders of what could be added
if CONFIG_AUDIO_PLANNED
diff --git a/nuttx/audio/Makefile b/nuttx/audio/Makefile
index b6c111621..7b34de1ae 100644
--- a/nuttx/audio/Makefile
+++ b/nuttx/audio/Makefile
@@ -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))
diff --git a/nuttx/audio/README.txt b/nuttx/audio/README.txt
new file mode 100644
index 000000000..80178865d
--- /dev/null
+++ b/nuttx/audio/README.txt
@@ -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.
+
diff --git a/nuttx/audio/audio.c b/nuttx/audio/audio.c
index 444412c97..351ed8ad9 100644
--- a/nuttx/audio/audio.c
+++ b/nuttx/audio/audio.c
@@ -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 */
@@ -420,6 +659,182 @@ static int audio_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
}
/****************************************************************************
+ * 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
- audvdbg("Registering %s\n", path);
- return register_driver(path, &g_audioops, 0666, upper);
-}
+ /* Give the lower-half a context to the upper half */
-/****************************************************************************
- * 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;
+ dev->upper = audio_callback;
+ dev->priv = upper;
- default:
- {
- auddbg("Unknown callback reason code %d\n", reason);
- break;
- }
- }
+ audvdbg("Registering %s\n", path);
+ return register_driver(path, &g_audioops, 0666, upper);
}
#endif /* CONFIG_AUDIO */
diff --git a/nuttx/audio/buffer.c b/nuttx/audio/buffer.c
index 3906891f6..b0b5c6c36 100644
--- a/nuttx/audio/buffer.c
+++ b/nuttx/audio/buffer.c
@@ -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 */
diff --git a/nuttx/include/nuttx/audio/audio.h b/nuttx/include/nuttx/audio/audio.h
index 6234ac0db..be03cc71e 100644
--- a/nuttx/include/nuttx/audio/audio.h
+++ b/nuttx/include/nuttx/audio/audio.h
@@ -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
+
+ /* 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);
- /* 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
+ /* 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