/****************************************************************************
 * include/nuttx/audio/audio.h
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.  The
 * ASF licenses this file to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the
 * License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations
 * under the License.
 *
 ****************************************************************************/

#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
 * 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 common Audio
 *    interface to application level code, and
 * 2) A "lower half", platform-specific driver that implements the
 *    low-level controls to configure and communicate with the audio
 *    device(s).
 */

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/config.h>
#include <nuttx/compiler.h>

#include <nuttx/fs/ioctl.h>
#include <nuttx/mutex.h>
#include <nuttx/spi/spi.h>
#include <nuttx/queue.h>

#ifdef CONFIG_AUDIO

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

/* Configuration ************************************************************/

/* CONFIG_AUDIO - Enables Audio driver support
 * CONFIG_DEBUG_AUDIO - If enabled (with CONFIG_DEBUG_FEATURES and,
 *   optionally, CONFIG_DEBUG_INFO), 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
 * interface, such as sampling rate, volume, data format, etc.
 * The Audio ioctl commands are listed below:
 *
 * AUDIOIOC_GETCAPS - Get the Audio Device Capabilities
 *
 *   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
 *                    AUDIO_TYPE_QUERY, otherwise specify any type that was
 *                    reported by the device during the QUERY.
 *
 * AUDIOIOC_CONFIGURE - Configure device for the specified mode
 *
 *   ioctl argument:  Pointer to the audio_caps_s structure which identifies
 *                    the capabilities to configure for.
 *
 * AUDIOIOC_SHUTDOWN - Shutdown the device.
 *
 *   ioctl argument:  None
 *
 * AUDIOIOC_START - Start Audio streaming
 *
 *   ioctl argument:  None
 *
 * AUDIOIOC_STOP - Stop Audio streaming
 *
 *   ioctl argument:  None
 */

#define AUDIOIOC_GETCAPS            _AUDIOIOC(1)
#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)
#define AUDIOIOC_SETBUFFERINFO      _AUDIOIOC(17)
#define AUDIOIOC_SETPARAMTER        _AUDIOIOC(18)
#define AUDIOIOC_GETLATENCY         _AUDIOIOC(19)
#define AUDIOIOC_FLUSH              _AUDIOIOC(20)
#define AUDIOIOC_GETPOSITION        _AUDIOIOC(21)
#define AUDIOIOC_GETAUDIOINFO       _AUDIOIOC(22)
#define AUDIOIOC_GETSTATUS          _AUDIOIOC(23)
#define AUDIOIOC_RESETSTATUS        _AUDIOIOC(24)

/* Audio Device Types *******************************************************/

/* The NuttX audio interface support different types of audio devices for
 * input, output, synthesis, and manipulation of audio data.  A given driver/
 * device could support a combination of these device type.  The following
 * is a list of bit-field definitions for defining the device type.
 */

#define AUDIO_TYPE_QUERY            0x00
#define AUDIO_TYPE_INPUT            0x01
#define AUDIO_TYPE_OUTPUT           0x02
#define AUDIO_TYPE_MIXER            0x04
#define AUDIO_TYPE_SELECTOR         0x08
#define AUDIO_TYPE_FEATURE          0x10
#define AUDIO_TYPE_EFFECT           0x20
#define AUDIO_TYPE_PROCESSING       0x40
#define AUDIO_TYPE_EXTENSION        0x80

/* Audio Format Types *******************************************************/

/* The following defines the audio data format types in NuttX.  During a
 * format query, these will be converted to bit positions within the
 * ac_format field, meaning we currently only support up to 16 formats. To
 * support more than that, we will use the FMT_OTHER entry, and the
 * interfacing software can perform a second query to get the other formats.
 */

#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_WAV               0x07
#define AUDIO_FMT_MP3               0x08
#define AUDIO_FMT_MIDI              0x09
#define AUDIO_FMT_OGG_VORBIS        0x0a
#define AUDIO_FMT_FLAC              0x0b
#define AUDIO_FMT_SBC               0x0c
#define AUDIO_FMT_AAC               0x0d
#define AUDIO_FMT_MSBC              0x0e
#define AUDIO_FMT_CVSD              0x0f
#define AUDIO_FMT_AMR               0x10
#define AUDIO_FMT_AMRWB             0x11
#define AUDIO_FMT_AMRWBPLUS         0x12
#define AUDIO_FMT_OPUS              0x13
#define AUDIO_FMT_REAL              0x14
#define AUDIO_FMT_IEC61937          0x15
#define AUDIO_FMT_G723_1            0x16
#define AUDIO_FMT_G729              0x17
#define AUDIO_FMT_ALAC              0x18
#define AUDIO_FMT_APE               0x19

#define AUDIO_SUBFMT_END            0x00

#define AUDIO_PROFILE_PCM                  0x01

#define AUDIO_SUBFMT_PCM_MP1               0x01
#define AUDIO_SUBFMT_PCM_MP2               0x02
#define AUDIO_SUBFMT_PCM_MP3               0x03
#define AUDIO_SUBFMT_PCM_MU_LAW            0x04
#define AUDIO_SUBFMT_PCM_A_LAW             0x05
#define AUDIO_SUBFMT_PCM_U8                0x06
#define AUDIO_SUBFMT_PCM_S8                0x07
#define AUDIO_SUBFMT_PCM_U16_LE            0x08
#define AUDIO_SUBFMT_PCM_S16_BE            0x09
#define AUDIO_SUBFMT_PCM_S16_LE            0x0a
#define AUDIO_SUBFMT_PCM_U16_BE            0x0b
#define AUDIO_SUBFMT_PCM_U24_LE            0x0c
#define AUDIO_SUBFMT_PCM_S24_BE            0x0d
#define AUDIO_SUBFMT_PCM_S24_LE            0x0e
#define AUDIO_SUBFMT_PCM_U24_BE            0x0f
#define AUDIO_SUBFMT_PCM_U32_LE            0x10
#define AUDIO_SUBFMT_PCM_U32_BE            0x11
#define AUDIO_SUBFMT_PCM_S32_LE            0x12
#define AUDIO_SUBFMT_PCM_S32_BE            0x13
#define AUDIO_SUBFMT_PCM_FLOAT_LE          0x14
#define AUDIO_SUBFMT_PCM_FLOAT_BE          0x15

#define AUDIO_SUBFMT_MIDI_0                0x01
#define AUDIO_SUBFMT_MIDI_1                0x02
#define AUDIO_SUBFMT_MIDI_2                0x03

#define AUDIO_CHANMODE_MP3_MONO            0x01
#define AUDIO_CHANMODE_MP3_STEREO          0x02
#define AUDIO_CHANMODE_MP3_JOINTSTEREO     0x03
#define AUDIO_CHANMODE_MP3_DUAL            0x04

#define AUDIO_PROFILE_AMR                  0x01

#define AUDIO_SUBFMT_AMR_DTX_OFF           0x01
#define AUDIO_SUBFMT_AMR_VAD1              0x02
#define AUDIO_SUBFMT_AMR_VAD2              0x03

#define AUDIO_STREAMFORMAT_UNDEF           0x01
#define AUDIO_STREAMFORMAT_CONFORMANCE     0x02
#define AUDIO_STREAMFORMAT_IF1             0x03
#define AUDIO_STREAMFORMAT_IF2             0x04
#define AUDIO_STREAMFORMAT_FSF             0x05
#define AUDIO_STREAMFORMAT_RTPPAYLOAD      0x06
#define AUDIO_STREAMFORMAT_ITU             0x07

#define AUDIO_PROFILE_AMRWB                0x01

#define AUDIO_SUBFMT_AMRWB_DTX_OFF         0x01
#define AUDIO_SUBFMT_AMRWB_VAD1            0x02
#define AUDIO_SUBFMT_AMRWB_VAD2            0x03

#define AUDIO_PROFILE_AMRWBPLUS            0x01

#define AUDIO_PROFILE_AAC                  0x01

#define AUDIO_SUBFMT_AAC_MAIN              0x01
#define AUDIO_SUBFMT_AAC_LC                0x02
#define AUDIO_SUBFMT_AAC_SSR               0x03
#define AUDIO_SUBFMT_AAC_LTP               0x04
#define AUDIO_SUBFMT_AAC_HE                0x05
#define AUDIO_SUBFMT_AAC_SCALABLE          0x06
#define AUDIO_SUBFMT_AAC_ERLC              0x07
#define AUDIO_SUBFMT_AAC_LD                0x08
#define AUDIO_SUBFMT_AAC_HE_PS             0x09
#define AUDIO_SUBFMT_AAC_HE_MPS            0x0a

#define AUDIO_STREAMFORMAT_MP2ADTS         0x01
#define AUDIO_STREAMFORMAT_MP4ADTS         0x02
#define AUDIO_STREAMFORMAT_MP4LOAS         0x03
#define AUDIO_STREAMFORMAT_MP4LATM         0x04
#define AUDIO_STREAMFORMAT_ADIF            0x05
#define AUDIO_STREAMFORMAT_MP4FF           0x06
#define AUDIO_STREAMFORMAT_RAW             0x07
#define AUDIO_STREAMFORMAT_LATM            0x08

#define AUDIO_PROFILE_WMA7                 0x01
#define AUDIO_PROFILE_WMA8                 0x02
#define AUDIO_PROFILE_WMA9                 0x03
#define AUDIO_PROFILE_WMA10                0x04
#define AUDIO_PROFILE_WMA9_PRO             0x05
#define AUDIO_PROFILE_WMA9_LOSSLESS        0x06
#define AUDIO_PROFILE_WMA10_LOSSLESS       0x07

#define AUDIO_SUBFMT_WMA_LEVEL1            0x01
#define AUDIO_SUBFMT_WMA_LEVEL2            0x02
#define AUDIO_SUBFMT_WMA_LEVEL3            0x03
#define AUDIO_SUBFMT_WMA_LEVEL4            0x04
#define AUDIO_SUBFMT_WMAPRO_LEVELM0        0x05
#define AUDIO_SUBFMT_WMAPRO_LEVELM1        0x06
#define AUDIO_SUBFMT_WMAPRO_LEVELM2        0x07
#define AUDIO_SUBFMT_WMAPRO_LEVELM3        0x08

#define AUDIO_STREAMFORMAT_WMA_ASF         0x01
#define AUDIO_STREAMFORMAT_WMA_NOASF_HDR   0x02

#define AUDIO_PROFILE_SBC                  0x01

#define AUDIO_SUBFMT_SBC                   0x01

#define AUDIO_STREAMFORMAT_SBC_PACKED      0x01 /* SBC data with MTU packed */

#define AUDIO_PROFILE_REALAUDIO            0x01

#define AUDIO_SUBFMT_REALAUDIO_G2          0x01
#define AUDIO_SUBFMT_REALAUDIO_8           0x02
#define AUDIO_SUBFMT_REALAUDIO_10          0x03
#define AUDIO_SUBFMT_REALAUDIO_SURROUND    0x04

#define AUDIO_PROFILE_VORBIS               0x01

#define AUDIO_SUBFMT_VORBIS                0x01

#define AUDIO_PROFILE_FLAC                 0x01

#define AUDIO_SUBFMT_FLAC_LEVEL0           0x01
#define AUDIO_SUBFMT_FLAC_LEVEL1           0x02
#define AUDIO_SUBFMT_FLAC_LEVEL2           0x03
#define AUDIO_SUBFMT_FLAC_LEVEL3           0x04
#define AUDIO_SUBFMT_FLAC_LEVEL4           0x05
#define AUDIO_SUBFMT_FLAC_LEVEL5           0x06
#define AUDIO_SUBFMT_FLAC_LEVEL6           0x07
#define AUDIO_SUBFMT_FLAC_LEVEL7           0x08
#define AUDIO_SUBFMT_FLAC_LEVEL8           0x09

#define AUDIO_STREAMFORMAT_FLAC            0x01
#define AUDIO_STREAMFORMAT_FLAC_OGG        0x02

#define AUDIO_PROFILE_IEC61937             0x01
#define AUDIO_PROFILE_IEC61937_SPDIF       0x02

#define AUDIO_SUBFMT_IEC_REF_STREAM_HEADER 0x01
#define AUDIO_SUBFMT_IEC_LPCM              0x02
#define AUDIO_SUBFMT_IEC_AC3               0x03
#define AUDIO_SUBFMT_IEC_MPEG1             0x04
#define AUDIO_SUBFMT_IEC_MP3               0x05
#define AUDIO_SUBFMT_IEC_MPEG2             0x06
#define AUDIO_SUBFMT_IEC_AACLC             0x07
#define AUDIO_SUBFMT_IEC_DTS               0x08
#define AUDIO_SUBFMT_IEC_ATRAC             0x09
#define AUDIO_SUBFMT_IEC_SACD              0x0a
#define AUDIO_SUBFMT_IEC_EAC3              0x0b
#define AUDIO_SUBFMT_IEC_DTS_HD            0x0c
#define AUDIO_SUBFMT_IEC_MLP               0x0d
#define AUDIO_SUBFMT_IEC_DST               0x0e
#define AUDIO_SUBFMT_IEC_WMAPRO            0x0f
#define AUDIO_SUBFMT_IEC_REF_CXT           0x10
#define AUDIO_SUBFMT_IEC_HE_AAC            0x11
#define AUDIO_SUBFMT_IEC_HE_AAC2           0x12
#define AUDIO_SUBFMT_IEC_MPEG_SURROUND     0x13

#define AUDIO_PROFILE_G723_1               0x01

#define AUDIO_SUBFMT_G723_1_ANNEX_A        0x01
#define AUDIO_SUBFMT_G723_1_ANNEX_B        0x02
#define AUDIO_SUBFMT_G723_1_ANNEX_C        0x03

#define AUDIO_PROFILE_G729                 0x01

#define AUDIO_SUBFMT_G729_ANNEX_A          0x01
#define AUDIO_SUBFMT_G729_ANNEX_B          0x02

#define AUDIO_RATECONTROL_CONSTANT         0x01
#define AUDIO_RATECONTROL_VARIABLE         0x02

/* Audio Hardware-Format Types **********************************************/

#define AUDIO_HWFMT_I2S             (1 << 0)
#define AUDIO_HWFMT_RIGHT_J         (2 << 0)
#define AUDIO_HWFMT_LEFT_J          (3 << 0)
#define AUDIO_HWFMT_DSP_A           (4 << 0)
#define AUDIO_HWFMT_DSP_B           (5 << 0)
#define AUDIO_HWFMT_AC97            (6 << 0)
#define AUDIO_HWFMT_PDM             (7 << 0)

#define AUDIO_HWFMT_NB_NF           (0 << 8)
#define AUDIO_HWFMT_NB_IF           (2 << 8)
#define AUDIO_HWFMT_IB_NF           (3 << 8)
#define AUDIO_HWFMT_IB_IF           (4 << 8)

#define AUDIO_HWFMT_CBM_CFM         (1 << 12)
#define AUDIO_HWFMT_CBS_CFM         (2 << 12)
#define AUDIO_HWFMT_CBM_CFS         (3 << 12)
#define AUDIO_HWFMT_CBS_CFS         (4 << 12)

#define AUDIO_HWFMT_FORMAT_MASK     0x000f
#define AUDIO_HWFMT_CLOCK_MASK      0x00f0
#define AUDIO_HWFMT_INV_MASK        0x0f00
#define AUDIO_HWFMT_MASTER_MASK     0xf000

/* Supported Sampling Rates *************************************************/

#define AUDIO_SAMP_RATE_8K          0x0001
#define AUDIO_SAMP_RATE_11K         0x0002
#define AUDIO_SAMP_RATE_12K         0x0004
#define AUDIO_SAMP_RATE_16K         0x0008
#define AUDIO_SAMP_RATE_22K         0x0010
#define AUDIO_SAMP_RATE_24K         0x0020
#define AUDIO_SAMP_RATE_32K         0x0040
#define AUDIO_SAMP_RATE_44K         0x0080
#define AUDIO_SAMP_RATE_48K         0x0100
#define AUDIO_SAMP_RATE_88K         0x0200
#define AUDIO_SAMP_RATE_96K         0x0400
#define AUDIO_SAMP_RATE_128K        0x0800
#define AUDIO_SAMP_RATE_160K        0x1000
#define AUDIO_SAMP_RATE_172K        0x2000
#define AUDIO_SAMP_RATE_192K        0x4000
#define AUDIO_SAMP_RATE_DEF_ALL    (AUDIO_SAMP_RATE_8K   | AUDIO_SAMP_RATE_11K | \
                                    AUDIO_SAMP_RATE_12K  | AUDIO_SAMP_RATE_16K | \
                                    AUDIO_SAMP_RATE_22K  | AUDIO_SAMP_RATE_24K | \
                                    AUDIO_SAMP_RATE_32K  | AUDIO_SAMP_RATE_44K | \
                                    AUDIO_SAMP_RATE_48K  | AUDIO_SAMP_RATE_88K | \
                                    AUDIO_SAMP_RATE_96K  | AUDIO_SAMP_RATE_128K | \
                                    AUDIO_SAMP_RATE_160K | AUDIO_SAMP_RATE_172K | \
                                    AUDIO_SAMP_RATE_192K)
/* Audio Sub-sampling Ratios  ***********************************************/

#define AUDIO_SUBSAMPLE_NONE        0
#define AUDIO_SUBSAMPLE_2X          2
#define AUDIO_SUBSAMPLE_4X          4
#define AUDIO_SUBSAMPLE_8X          8
#define AUDIO_SUBSAMPLE_16X         16

#define AUDIO_SUBSAMPLE_MIN         AUDIO_SUBSAMPLE_2X
#define AUDIO_SUBSAMPLE_MAX         AUDIO_SUBSAMPLE_16X

/* 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

/* Audio Volume Limits ******************************************************/

/* As nxplayer passes a value in the range (0..1000) to the ioctl, all audio
 * drivers that implement volume expect a value from 0 to 1000 from the ioctl
 */

#define AUDIO_VOLUME_MAX            1000
#define AUDIO_VOLUME_MIN            0

/* Audio Balance Limits *****************************************************/

/* As nxplayer passes a value in the range (0..1000) to the ioctl, all audio
 * drivers that implement balance expect a value from 0 to 1000 from the
 * ioctl
 */

#define AUDIO_BALANCE_RIGHT          1000
#define AUDIO_BALANCE_CENTER         500
#define AUDIO_BALANCE_LEFT           0

/* 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
#define AUDIO_PU_SUBSAMPLE_FORWARD  0x04
#define AUDIO_PU_SUBSAMPLE_REWIND   0x05

/* 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

/* Extension Unit controls **************************************************/

#define AUDIO_EU_HW_FORMAT          0x0001
#define AUDIO_EU_LOAD_MODULE        0x0002

/* Audio Callback Reasons ***************************************************/

#define AUDIO_CALLBACK_UNDEF        0x00
#define AUDIO_CALLBACK_DEQUEUE      0x01
#define AUDIO_CALLBACK_IOERR        0x02
#define AUDIO_CALLBACK_COMPLETE     0x03
#define AUDIO_CALLBACK_MESSAGE      0x04
#define AUDIO_CALLBACK_UNDERRUN     0x05

/* Audio Pipeline Buffer (AP Buffer) flags **********************************/

#define AUDIO_ABP_ALIGNMENT         0x000f  /* Mask to define buffer alignment */
#define AUDIO_ABP_CANDMA            0x0010  /* Set if the data is DMA'able */
#define AUDIO_ABP_STATIC            0x0020  /* Set if statically allocated */
#define AUDIO_ABP_ACTIVE            0x0040  /* Set if this buffer is still active.
                                             *   A buffer could become inactive
                                             *   if it is processed by an output
                                             *   device or a processing device
                                             *   that replaces it with an alternate
                                             *   buffer as a result of some DSP
                                             *   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_WAKEUP            9
#define AUDIO_MSG_COMMAND          10
#define AUDIO_MSG_SLIENCE          11
#define AUDIO_MSG_UNDERRUN         12
#define AUDIO_MSG_IOERR            13
#define AUDIO_MSG_USER             64

/* Audio Pipeline Buffer flags */

#define AUDIO_APB_OUTPUT_ENQUEUED   (1 << 0)
#define AUDIO_APB_OUTPUT_PROCESS    (1 << 1)
#define AUDIO_APB_DEQUEUED          (1 << 2)
#define AUDIO_APB_FINAL             (1 << 3) /* Last buffer in the stream */

/* Audio channels range wrapper macro */

#define AUDIO_CHANNELS_RANGE(min, max) ((uint8_t)(((min) << 4) | ((max) & 0xf)))

/* State of appl and lower driver, higher value = higher priority */

#define AUDIO_STATE_OPEN           0
#define AUDIO_STATE_PREPARED       1
#define AUDIO_STATE_PAUSED         2
#define AUDIO_STATE_XRUN           3
#define AUDIO_STATE_DRAINING       4
#define AUDIO_STATE_RUNNING        5

/****************************************************************************
 * Public Types
 ****************************************************************************/

/* Define the size of AP Buffer sample count base on CONFIG */

#ifdef CONFIG_AUDIO_LARGE_BUFFERS
typedef uint32_t apb_samp_t;
#else
typedef uint16_t apb_samp_t;
#endif

/* This structure describes the lower driver status */

struct audio_status_s
{
  volatile int state;
  volatile unsigned long head;
  volatile unsigned long tail;
};

/* This structure is used to describe the audio device capabilities */

struct audio_enc_wma_s
{
  uint32_t super_block_align;
};

struct audio_enc_vorbis_s
{
  int32_t  quality;
  uint32_t managed;
  uint32_t max_bit_rate;
  uint32_t min_bit_rate;
  uint32_t downmix;
};

struct audio_enc_real_s
{
  uint32_t quant_bits;
  uint32_t start_region;
  uint32_t num_regions;
};

struct audio_enc_flac_s
{
  uint32_t num;
  uint32_t gain;
};

struct audio_enc_sbc_s
{
  uint8_t blocks;
  uint8_t subbands;
  uint8_t alloc_method;
  uint8_t bitpool;
};

struct audio_enc_lc3_s
{
  float frame_duration;
};

struct audio_enc_generic_s
{
  uint32_t bw;
  int32_t  reserved[15];
};

struct audio_dec_flac_s
{
  uint16_t sample_size;
  uint16_t min_blk_size;
  uint16_t max_blk_size;
  uint16_t min_frame_size;
  uint16_t max_frame_size;
  uint16_t reserved;
};

struct audio_dec_wma_s
{
  uint32_t encoder_option;
  uint32_t adv_encoder_option;
  uint32_t adv_encoder_option2;
  uint32_t reserved;
};

struct audio_dec_alac_s
{
  uint32_t frame_length;
  uint8_t  compatible_version;
  uint8_t  pb;
  uint8_t  mb;
  uint8_t  kb;
  uint32_t max_run;
  uint32_t max_frame_bytes;
};

struct audio_dec_ape_s
{
  uint16_t compatible_version;
  uint16_t compression_level;
  uint32_t format_flags;
  uint32_t blocks_per_frame;
  uint32_t final_frame_blocks;
  uint32_t total_frames;
  uint32_t seek_table_present;
};

struct audio_dec_lc3_s
{
  float frame_duration;
};

union audio_codec_options_u
{
  struct audio_enc_wma_s wma;
  struct audio_enc_vorbis_s vorbis;
  struct audio_enc_real_s real;
  struct audio_enc_flac_s flac;
  struct audio_enc_sbc_s sbc;
  struct audio_enc_lc3_s lc3;
  struct audio_enc_generic_s generic;
  struct audio_dec_flac_s flac_d;
  struct audio_dec_wma_s wma_d;
  struct audio_dec_alac_s alac_d;
  struct audio_dec_ape_s ape_d;
  struct audio_dec_lc3_s lc3_d;
};

struct audio_codec_s
{
  uint32_t bit_rate;
  uint32_t rate_control;
  uint32_t profile;
  uint32_t level;
  uint32_t ch_mode;
  uint32_t format;
  uint32_t align;
  union audio_codec_options_u options;
};

struct audio_caps_s
{
  uint8_t ac_len;           /* Length of the structure */
  uint8_t ac_type;          /* Capabilities (device) type */
  uint8_t ac_subtype;       /* Capabilities sub-type, if needed */
  uint8_t ac_channels;      /* Number of channels (1, 2, 3, ... 15) upper 4 bits for minimum channels,
                             * lower 4 bits for maximum channels */
  uint8_t ac_chmap;         /* Channel map, each ch for each bit,
                             * zero means don't care */
  uint8_t reserved;         /* Reserved for future use */

  /* Audio data format(s) for this device */

  union
  {
    uint8_t  b[2];
    uint16_t hw;
  } ac_format;

  /* Specific controls for AUDIO_DEVICE_QUERY
   *   this field reports the device type supported
   *   by this lower-half driver.
   */

  union
  {
    uint8_t  b[4];
    uint16_t hw[2];
    uint32_t w;
#ifdef CONFIG_HAVE_LONG_LONG
    uint64_t qw;
#endif
  } ac_controls;

  /* Codec info */

  struct audio_codec_s ac_codec;
};

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
{
  uint32_t              samplerate; /* Sample Rate of the audio data */
  uint8_t               channels;   /* Number of channels (1, 2, 5, 7) */
  uint8_t               format;     /* Audio data format */
  uint8_t               subformat;  /* Audio subformat */
  uint8_t               type;       /* device type */
  struct audio_codec_s  codec;      /* Codec extra params */
};

/* 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.
 */

struct ap_buffer_info_s
{
  apb_samp_t  nbuffers;     /* Preferred qty of buffers */
  apb_samp_t  buffer_size;  /* Preferred size of the buffers */
};

/* 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 */
#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 */
  apb_samp_t            nsamples;   /* The number of samples in the buffer */
  mutex_t               lock;       /* Reference locking mutex */
  uint16_t              flags;      /* Buffer flags */
  uint16_t              crefs;      /* Number of reference counts */
  FAR uint8_t           *samp;      /* Offset of the first sample */
};

/* 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            msg_id;       /* Message ID */
  union
  {
    FAR void         *ptr;          /* Buffer being dequeued */
    uint32_t          data;         /* Message data */
  } u;
};

/* Structure defining the built-in sounds */

#ifdef CONFIG_AUDIO_BUILTIN_SOUNDS
struct audio_sound_s
{
  FAR 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 */
  FAR const uint8_t  *data;         /* Pointer to the data */
};

#endif

/* Structure for allocating, freeing and enqueueing 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
  apb_samp_t          numbytes;           /* Number of bytes to allocate */
  union
  {
    FAR struct ap_buffer_s  *buffer;     /* Buffer to free / enqueue */
    FAR struct ap_buffer_s  **pbuffer;   /* Pointer to receive allocated 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
 * supports the low-level functionality.
 */

struct audio_lowerhalf_s;
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 of that device type
   * (such as MP3 encoder, WMA encoder, PCM output, etc.).
   */

  CODE int (*getcaps)(FAR struct audio_lowerhalf_s *dev, int type,
                      FAR struct audio_caps_s *caps);

  /* 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,
   * however, process any audio data until the start method is called.
   */

#ifdef CONFIG_AUDIO_MULTI_SESSION
  CODE int (*configure)(FAR struct audio_lowerhalf_s *dev,
                        FAR void *session,
                        FAR const struct audio_caps_s *caps);
#else
  CODE int (*configure)(FAR struct audio_lowerhalf_s *dev,
                        FAR const struct audio_caps_s *caps);
#endif

  /* This method is called when the driver is closed.  The lower half driver
   * should stop processing audio data, including terminating any active
   * output generation.  It should also disable the audio hardware and put
   * it into the lowest possible power usage state.
   *
   * Any enqueued Audio Pipeline Buffers that have not been
   * processed / dequeued should be dequeued by this function.
   */

  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 Audio Pipeline 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 kumm_malloc 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.
   */

  CODE int (*enqueuebuffer)(FAR struct audio_lowerhalf_s *dev,
                            FAR struct ap_buffer_s *apb);

  /* Cancel a previously enqueued buffer. */

  CODE int (*cancelbuffer)(FAR struct audio_lowerhalf_s *dev,
                           FAR struct ap_buffer_s *apb);

  /* Lower-half logic may support platform-specific ioctl commands */

  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
 * Audio driver.  This state structure is passed to the Audio driver when the
 * driver is initialized.  Then, on subsequent callbacks into the lower half
 * Audio logic, this structure is provided so that the Audio logic can
 * 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
 * fields of the following generic Audio state structure.
 */

struct audio_lowerhalf_s
{
  /* The first field of this state structure must be a pointer to the Audio
   * callback structure:
   */

  FAR const struct audio_ops_s *ops;

  /* The bind data to the upper-half driver used for callbacks of dequeuing
   * buffer, reporting asynchronous event, reporting errors, etc.
   */

  audio_callback_t upper;

  /* The private opaque pointer to be passed to upper-layer during
   * callbacks
   */

  FAR void *priv;

  /* The custom Audio device state structure may include additional fields
   * after the pointer to the Audio callback structure.
   */
};

/****************************************************************************
 * Public Data
 ****************************************************************************/

/****************************************************************************
 * Public Function Prototypes
 ****************************************************************************/

#ifdef __cplusplus
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif

/****************************************************************************
 * "Upper-Half" Audio Driver Interfaces
 ****************************************************************************/

/****************************************************************************
 * Name: audio_register
 *
 * Description:
 *   This function binds an instance of a "lower half" Audio driver with the
 *   "upper half" Audio device and registers that device so that can be used
 *   by application code.
 *
 *   When this function is called, the "lower half" driver should be in the
 *   reset state (as if the shutdown() method had already been called).
 *
 * Input Parameters:
 *   name - The name of the audio device.  This name will be used to generate
 *     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", "/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
 *     persists.
 *
 * Returned Value:
 *   Zero on success; a negated errno value on failure.
 *
 ****************************************************************************/

int audio_register(FAR const char *name, FAR struct audio_lowerhalf_s *dev);

/****************************************************************************
 * Name: abp_alloc
 *
 * Description:
 *   Allocated an AP Buffer and prepares it for use.
 *   This allocates a dynamically allocated buffer that has no special
 *    DMA capabilities.
 *
 * Input Parameters:
 *   bufdesc:   Pointer to a buffer descriptor
 *
 * Returned Value:
 *   Pointer to the allocated buffer or NULL if no memory.
 *
 ****************************************************************************/

int apb_alloc(FAR struct audio_buf_desc_s *bufdesc);

/****************************************************************************
 * Name: apb_free
 *
 * Free's a previously allocated or referenced Audio Pipeline Buffer
 *
 ****************************************************************************/

void apb_free(FAR struct ap_buffer_s *apb);

/****************************************************************************
 * Name: apb_reference
 *
 * Claim a reference to an Audio Pipeline Buffer.  Each call to apb_reference
 * will increment the reference count and must have a matching apb_free
 * call.  When the refcount decrements to zero, the buffer will be freed.
 *
 ****************************************************************************/

void apb_reference(FAR struct ap_buffer_s *apb);

/****************************************************************************
 * Platform-Dependent "Lower-Half" Audio Driver Interfaces
 ****************************************************************************/

#undef EXTERN
#ifdef __cplusplus
}
#endif

#endif /* CONFIG_AUDIO */
#endif /* __INCLUDE_NUTTX_AUDIO_AUDIO_H */
