123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987 |
- /****************************************************************************
- * audio/audio_comp.c
- *
- * 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.
- *
- ****************************************************************************/
- /****************************************************************************
- * Included Files
- ****************************************************************************/
- #include <stdarg.h>
- #include <nuttx/audio/audio.h>
- #include <nuttx/audio/audio_comp.h>
- #include <nuttx/kmalloc.h>
- /****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
- /****************************************************************************
- * Private Types
- ****************************************************************************/
- /* This structure describes the internal state of the audio composite */
- struct audio_comp_priv_s
- {
- /* This is is our appearance to the outside world. This *MUST* be the
- * first element of the structure so that we can freely cast between
- * types struct audio_lowerhalf and struct audio_comp_dev_s.
- */
- struct audio_lowerhalf_s export;
- /* This is the contained, low-level audio device array and count. */
- FAR struct audio_lowerhalf_s **lower;
- int count;
- };
- /****************************************************************************
- * Private Function Prototypes
- ****************************************************************************/
- static int audio_comp_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
- FAR struct audio_caps_s *caps);
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- static int audio_comp_configure(FAR struct audio_lowerhalf_s *dev,
- FAR void *session,
- FAR const struct audio_caps_s *caps);
- #else
- static int audio_comp_configure(FAR struct audio_lowerhalf_s *dev,
- FAR const struct audio_caps_s *caps);
- #endif
- static int audio_comp_shutdown(FAR struct audio_lowerhalf_s *dev);
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- static int audio_comp_start(FAR struct audio_lowerhalf_s *dev,
- FAR void *session);
- #else
- static int audio_comp_start(FAR struct audio_lowerhalf_s *dev);
- #endif
- #ifndef CONFIG_AUDIO_EXCLUDE_STOP
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- static int audio_comp_stop(FAR struct audio_lowerhalf_s *dev,
- FAR void *session);
- #else
- static int audio_comp_stop(FAR struct audio_lowerhalf_s *dev);
- #endif
- #endif
- #ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- static int audio_comp_pause(FAR struct audio_lowerhalf_s *dev,
- FAR void *session);
- static int audio_comp_resume(FAR struct audio_lowerhalf_s *dev,
- FAR void *session);
- #else
- static int audio_comp_pause(FAR struct audio_lowerhalf_s *dev);
- static int audio_comp_resume(FAR struct audio_lowerhalf_s *dev);
- #endif
- #endif
- static int audio_comp_allocbuffer(FAR struct audio_lowerhalf_s *dev,
- FAR struct audio_buf_desc_s *bufdesc);
- static int audio_comp_freebuffer(FAR struct audio_lowerhalf_s *dev,
- FAR struct audio_buf_desc_s *bufdesc);
- static int audio_comp_enqueuebuffer(FAR struct audio_lowerhalf_s *dev,
- FAR struct ap_buffer_s *apb);
- static int audio_comp_cancelbuffer(FAR struct audio_lowerhalf_s *dev,
- FAR struct ap_buffer_s *apb);
- static int audio_comp_ioctl(FAR struct audio_lowerhalf_s *dev, int cmd,
- unsigned long arg);
- static int audio_comp_read(FAR struct audio_lowerhalf_s *dev,
- FAR char *buffer, size_t buflen);
- static int audio_comp_write(FAR struct audio_lowerhalf_s *dev,
- FAR const char *buffer, size_t buflen);
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- static int audio_comp_reserve(FAR struct audio_lowerhalf_s *dev,
- FAR void **session);
- #else
- static int audio_comp_reserve(FAR struct audio_lowerhalf_s *dev);
- #endif
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- static int audio_comp_release(FAR struct audio_lowerhalf_s *dev,
- FAR void *session);
- #else
- static int audio_comp_release(FAR struct audio_lowerhalf_s *dev);
- #endif
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- static void audio_comp_callback(FAR void *arg, uint16_t reason,
- FAR struct ap_buffer_s *apb,
- uint16_t status,
- FAR void *session);
- #else
- static void audio_comp_callback(FAR void *arg, uint16_t reason,
- FAR struct ap_buffer_s *apb,
- uint16_t status);
- #endif
- /****************************************************************************
- * Private Data
- ****************************************************************************/
- static const struct audio_ops_s g_audio_comp_ops =
- {
- audio_comp_getcaps, /* getcaps */
- audio_comp_configure, /* configure */
- audio_comp_shutdown, /* shutdown */
- audio_comp_start, /* start */
- #ifndef CONFIG_AUDIO_EXCLUDE_STOP
- audio_comp_stop, /* stop */
- #endif
- #ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
- audio_comp_pause, /* pause */
- audio_comp_resume, /* resume */
- #endif
- audio_comp_allocbuffer, /* allocbuffer */
- audio_comp_freebuffer, /* freebuffer */
- audio_comp_enqueuebuffer, /* enqueue_buffer */
- audio_comp_cancelbuffer, /* cancel_buffer */
- audio_comp_ioctl, /* ioctl */
- audio_comp_read, /* read */
- audio_comp_write, /* write */
- audio_comp_reserve, /* reserve */
- audio_comp_release /* release */
- };
- /****************************************************************************
- * Private Functions
- ****************************************************************************/
- /****************************************************************************
- * Name: audio_comp_getcaps
- *
- * Description: Get the audio device capabilities
- *
- ****************************************************************************/
- static int audio_comp_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
- FAR struct audio_caps_s *caps)
- {
- FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
- FAR struct audio_lowerhalf_s **lower = priv->lower;
- int ret = -ENOTTY;
- int i;
- caps->ac_channels = 0;
- caps->ac_format.hw = 0;
- caps->ac_controls.w = 0;
- for (i = 0; i < priv->count; i++)
- {
- if (lower[i]->ops->getcaps)
- {
- FAR struct audio_caps_s dup = *caps;
- int tmp = lower[i]->ops->getcaps(lower[i], type, &dup);
- if (tmp == -ENOTTY)
- {
- continue;
- }
- ret = tmp;
- if (ret < 0)
- {
- break;
- }
- if (caps->ac_channels < dup.ac_channels)
- {
- caps->ac_channels = dup.ac_channels;
- }
- caps->ac_format.hw |= dup.ac_format.hw;
- caps->ac_controls.w |= dup.ac_controls.w;
- }
- }
- return ret;
- }
- /****************************************************************************
- * Name: audio_comp_configure
- *
- * Description:
- * Configure the audio device for the specified mode of operation.
- *
- ****************************************************************************/
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- static int audio_comp_configure(FAR struct audio_lowerhalf_s *dev,
- FAR void *session,
- FAR const struct audio_caps_s *caps)
- #else
- static int audio_comp_configure(FAR struct audio_lowerhalf_s *dev,
- FAR const struct audio_caps_s *caps)
- #endif
- {
- FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
- FAR struct audio_lowerhalf_s **lower = priv->lower;
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- FAR void **sess = session;
- #endif
- int ret = -ENOTTY;
- int i;
- for (i = 0; i < priv->count; i++)
- {
- if (lower[i]->ops->configure)
- {
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- int tmp = lower[i]->ops->configure(lower[i], sess[i], caps);
- #else
- int tmp = lower[i]->ops->configure(lower[i], caps);
- #endif
- if (tmp == -ENOTTY)
- {
- continue;
- }
- ret = tmp;
- if (ret < 0)
- {
- break;
- }
- }
- }
- return ret;
- }
- /****************************************************************************
- * Name: audio_comp_shutdown
- *
- * Description:
- * Shutdown the driver and put it in the lowest power state possible.
- *
- ****************************************************************************/
- static int audio_comp_shutdown(FAR struct audio_lowerhalf_s *dev)
- {
- FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
- FAR struct audio_lowerhalf_s **lower = priv->lower;
- int ret = -ENOTTY;
- int i;
- for (i = priv->count - 1; i >= 0; i--)
- {
- if (lower[i]->ops->shutdown)
- {
- int tmp = lower[i]->ops->shutdown(lower[i]);
- if (tmp == -ENOTTY)
- {
- continue;
- }
- if (tmp < 0 || ret == -ENOTTY || ret >= 0)
- {
- ret = tmp;
- }
- }
- }
- return ret;
- }
- /****************************************************************************
- * Name: audio_comp_start
- *
- * Description:
- * Start the configured operation (audio streaming, volume enabled, etc.).
- *
- ****************************************************************************/
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- static int audio_comp_start(FAR struct audio_lowerhalf_s *dev,
- FAR void *session)
- #else
- static int audio_comp_start(FAR struct audio_lowerhalf_s *dev)
- #endif
- {
- FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
- FAR struct audio_lowerhalf_s **lower = priv->lower;
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- FAR void **sess = session;
- #endif
- int ret = -ENOTTY;
- int i;
- for (i = 0; i < priv->count; i++)
- {
- if (lower[i]->ops->start)
- {
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- int tmp = lower[i]->ops->start(lower[i], sess[i]);
- #else
- int tmp = lower[i]->ops->start(lower[i]);
- #endif
- if (tmp == -ENOTTY)
- {
- continue;
- }
- ret = tmp;
- if (ret >= 0)
- {
- continue;
- }
- while (--i >= 0)
- {
- if (lower[i]->ops->stop)
- {
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- lower[i]->ops->stop(lower[i], sess[i]);
- #else
- lower[i]->ops->stop(lower[i]);
- #endif
- }
- }
- break;
- }
- }
- return ret;
- }
- /****************************************************************************
- * Name: audio_comp_stop
- *
- * Description: Stop the configured operation (audio streaming, volume
- * disabled, etc.).
- *
- ****************************************************************************/
- #ifndef CONFIG_AUDIO_EXCLUDE_STOP
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- static int audio_comp_stop(FAR struct audio_lowerhalf_s *dev,
- FAR void *session)
- #else
- static int audio_comp_stop(FAR struct audio_lowerhalf_s *dev)
- #endif
- {
- FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
- FAR struct audio_lowerhalf_s **lower = priv->lower;
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- FAR void **sess = session;
- #endif
- int ret = -ENOTTY;
- int i;
- for (i = priv->count - 1; i >= 0; i--)
- {
- if (lower[i]->ops->stop)
- {
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- int tmp = lower[i]->ops->stop(lower[i], sess[i]);
- #else
- int tmp = lower[i]->ops->stop(lower[i]);
- #endif
- if (tmp == -ENOTTY)
- {
- continue;
- }
- if (tmp < 0 || ret == -ENOTTY || ret >= 0)
- {
- ret = tmp;
- }
- }
- }
- return ret;
- }
- #endif
- /****************************************************************************
- * Name: audio_comp_pause
- *
- * Description: Pauses the playback.
- *
- ****************************************************************************/
- #ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- static int audio_comp_pause(FAR struct audio_lowerhalf_s *dev,
- FAR void *session)
- #else
- static int audio_comp_pause(FAR struct audio_lowerhalf_s *dev)
- #endif
- {
- FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
- FAR struct audio_lowerhalf_s **lower = priv->lower;
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- FAR void **sess = session;
- #endif
- int ret = -ENOTTY;
- int i;
- for (i = priv->count - 1; i >= 0; i--)
- {
- if (lower[i]->ops->pause)
- {
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- int tmp = lower[i]->ops->pause(lower[i], sess[i]);
- #else
- int tmp = lower[i]->ops->pause(lower[i]);
- #endif
- if (tmp == -ENOTTY)
- {
- continue;
- }
- if (tmp < 0 || ret == -ENOTTY || ret >= 0)
- {
- ret = tmp;
- }
- }
- }
- return ret;
- }
- #endif /* CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME */
- /****************************************************************************
- * Name: audio_comp_resume
- *
- * Description: Resumes the playback.
- *
- ****************************************************************************/
- #ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- static int audio_comp_resume(FAR struct audio_lowerhalf_s *dev,
- FAR void *session)
- #else
- static int audio_comp_resume(FAR struct audio_lowerhalf_s *dev)
- #endif
- {
- FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
- FAR struct audio_lowerhalf_s **lower = priv->lower;
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- FAR void **sess = session;
- #endif
- int ret = -ENOTTY;
- int i;
- for (i = 0; i < priv->count; i++)
- {
- if (lower[i]->ops->resume)
- {
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- int tmp = lower[i]->ops->resume(lower[i], sess[i]);
- #else
- int tmp = lower[i]->ops->resume(lower[i]);
- #endif
- if (tmp == -ENOTTY)
- {
- continue;
- }
- ret = tmp;
- if (ret >= 0)
- {
- continue;
- }
- while (--i >= 0)
- {
- if (lower[i]->ops->pause)
- {
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- lower[i]->ops->pause(lower[i], sess[i]);
- #else
- lower[i]->ops->pause(lower[i]);
- #endif
- }
- }
- break;
- }
- }
- return ret;
- }
- #endif /* CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME */
- /****************************************************************************
- * Name: audio_comp_allocbuffer
- *
- * Description: Allocate an audio pipeline buffer.
- *
- ****************************************************************************/
- static int audio_comp_allocbuffer(FAR struct audio_lowerhalf_s *dev,
- FAR struct audio_buf_desc_s *bufdesc)
- {
- FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
- FAR struct audio_lowerhalf_s **lower = priv->lower;
- int ret = -ENOTTY;
- int i;
- for (i = 0; i < priv->count; i++)
- {
- if (lower[i]->ops->allocbuffer)
- {
- ret = lower[i]->ops->allocbuffer(lower[i], bufdesc);
- if (ret != -ENOTTY)
- {
- break;
- }
- }
- }
- if (ret == -ENOTTY)
- {
- ret = apb_alloc(bufdesc);
- }
- return ret;
- }
- /****************************************************************************
- * Name: audio_comp_freebuffer
- *
- * Description: Free an audio pipeline buffer.
- *
- ****************************************************************************/
- static int audio_comp_freebuffer(FAR struct audio_lowerhalf_s *dev,
- FAR struct audio_buf_desc_s *bufdesc)
- {
- FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
- FAR struct audio_lowerhalf_s **lower = priv->lower;
- int ret = -ENOTTY;
- int i;
- for (i = 0; i < priv->count; i++)
- {
- if (lower[i]->ops->freebuffer)
- {
- ret = lower[i]->ops->freebuffer(lower[i], bufdesc);
- if (ret != -ENOTTY)
- {
- break;
- }
- }
- }
- if (ret == -ENOTTY)
- {
- apb_free(bufdesc->u.buffer);
- ret = sizeof(*bufdesc);
- }
- return ret;
- }
- /****************************************************************************
- * Name: audio_comp_enqueuebuffer
- *
- * Description: Enqueue an Audio Pipeline Buffer for playback/ processing.
- *
- ****************************************************************************/
- static int audio_comp_enqueuebuffer(FAR struct audio_lowerhalf_s *dev,
- FAR struct ap_buffer_s *apb)
- {
- FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
- FAR struct audio_lowerhalf_s **lower = priv->lower;
- int ret = -ENOTTY;
- int i;
- for (i = 0; i < priv->count; i++)
- {
- if (lower[i]->ops->enqueuebuffer)
- {
- ret = lower[i]->ops->enqueuebuffer(lower[i], apb);
- if (ret != -ENOTTY)
- {
- break;
- }
- }
- }
- return ret;
- }
- /****************************************************************************
- * Name: audio_comp_cancelbuffer
- *
- * Description: Called when an enqueued buffer is being cancelled.
- *
- ****************************************************************************/
- static int audio_comp_cancelbuffer(FAR struct audio_lowerhalf_s *dev,
- FAR struct ap_buffer_s *apb)
- {
- FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
- FAR struct audio_lowerhalf_s **lower = priv->lower;
- int ret = -ENOTTY;
- int i;
- for (i = 0; i < priv->count; i++)
- {
- if (lower[i]->ops->cancelbuffer)
- {
- ret = lower[i]->ops->cancelbuffer(lower[i], apb);
- if (ret != -ENOTTY)
- {
- break;
- }
- }
- }
- return ret;
- }
- /****************************************************************************
- * Name: audio_comp_ioctl
- *
- * Description: Perform a device ioctl
- *
- ****************************************************************************/
- static int audio_comp_ioctl(FAR struct audio_lowerhalf_s *dev, int cmd,
- unsigned long arg)
- {
- FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
- FAR struct audio_lowerhalf_s **lower = priv->lower;
- int ret = -ENOTTY;
- int i;
- for (i = 0; i < priv->count; i++)
- {
- if (lower[i]->ops->ioctl)
- {
- int tmp = lower[i]->ops->ioctl(lower[i], cmd, arg);
- if (tmp == -ENOTTY)
- {
- continue;
- }
- ret = tmp;
- if (ret < 0)
- {
- break;
- }
- }
- }
- return ret;
- }
- /****************************************************************************
- * Name: audio_comp_read
- *
- * Description: Lower-half logic for read commands.
- *
- ****************************************************************************/
- static int audio_comp_read(FAR struct audio_lowerhalf_s *dev,
- FAR char *buffer, size_t buflen)
- {
- FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
- FAR struct audio_lowerhalf_s **lower = priv->lower;
- int ret = -ENOTTY;
- int i;
- for (i = 0; i < priv->count; i++)
- {
- if (lower[i]->ops->read)
- {
- ret = lower[i]->ops->read(lower[i], buffer, buflen);
- if (ret != -ENOTTY)
- {
- break;
- }
- }
- }
- return ret;
- }
- /****************************************************************************
- * Name: audio_comp_write
- *
- * Description: Lower-half logic for write commands.
- *
- ****************************************************************************/
- static int audio_comp_write(FAR struct audio_lowerhalf_s *dev,
- FAR const char *buffer, size_t buflen)
- {
- FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
- FAR struct audio_lowerhalf_s **lower = priv->lower;
- int ret = -ENOTTY;
- int i;
- for (i = 0; i < priv->count; i++)
- {
- if (lower[i]->ops->write)
- {
- ret = lower[i]->ops->write(lower[i], buffer, buflen);
- if (ret != -ENOTTY)
- {
- break;
- }
- }
- }
- return ret;
- }
- /****************************************************************************
- * Name: audio_comp_reserve
- *
- * Description: Reserves a session.
- *
- ****************************************************************************/
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- static int audio_comp_reserve(FAR struct audio_lowerhalf_s *dev,
- FAR void **session)
- #else
- static int audio_comp_reserve(FAR struct audio_lowerhalf_s *dev)
- #endif
- {
- FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
- FAR struct audio_lowerhalf_s **lower = priv->lower;
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- FAR void **sess;
- #endif
- int ret = OK;
- int i;
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- sess = kmm_calloc(priv->count, sizeof(*sess));
- if (sess == NULL)
- {
- return -ENOMEM;
- }
- #endif
- for (i = 0; i < priv->count; i++)
- {
- if (lower[i]->ops->reserve)
- {
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- int tmp = lower[i]->ops->reserve(lower[i], &sess[i]);
- #else
- int tmp = lower[i]->ops->reserve(lower[i]);
- #endif
- if (tmp == -ENOTTY)
- {
- continue;
- }
- ret = tmp;
- if (ret >= 0)
- {
- continue;
- }
- while (--i >= 0)
- {
- if (lower[i]->ops->release)
- {
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- lower[i]->ops->release(lower[i], sess[i]);
- #else
- lower[i]->ops->release(lower[i]);
- #endif
- }
- }
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- kmm_free(sess);
- sess = NULL;
- #endif
- break;
- }
- }
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- *session = sess;
- #endif
- return ret;
- }
- /****************************************************************************
- * Name: audio_comp_release
- *
- * Description: Releases the session.
- *
- ****************************************************************************/
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- static int audio_comp_release(FAR struct audio_lowerhalf_s *dev,
- FAR void *session)
- #else
- static int audio_comp_release(FAR struct audio_lowerhalf_s *dev)
- #endif
- {
- FAR struct audio_comp_priv_s *priv = (FAR struct audio_comp_priv_s *)dev;
- FAR struct audio_lowerhalf_s **lower = priv->lower;
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- FAR void **sess = session;
- #endif
- int ret = OK;
- int i;
- for (i = priv->count - 1; i >= 0; i--)
- {
- if (lower[i]->ops->release)
- {
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- int tmp = lower[i]->ops->release(lower[i], sess[i]);
- #else
- int tmp = lower[i]->ops->release(lower[i]);
- #endif
- if (tmp == -ENOTTY)
- {
- continue;
- }
- if (tmp < 0 || ret >= 0)
- {
- ret = tmp;
- }
- }
- }
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- kmm_free(sess);
- #endif
- return ret;
- }
- /****************************************************************************
- * Name: audio_comp_callback
- *
- * Description:
- * Lower-to-upper level callback for buffer dequeueing.
- *
- * Input Parameters:
- * arg - The value of the 'priv' field from audio_lowerhalf_s.
- *
- * Returned Value:
- * None
- *
- ****************************************************************************/
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- static void audio_comp_callback(FAR void *arg, uint16_t reason,
- FAR struct ap_buffer_s *apb, uint16_t status,
- FAR void *session)
- #else
- static void audio_comp_callback(FAR void *arg, uint16_t reason,
- FAR struct ap_buffer_s *apb, uint16_t status)
- #endif
- {
- FAR struct audio_comp_priv_s *priv = arg;
- #ifdef CONFIG_AUDIO_MULTI_SESSION
- priv->export.upper(priv->export.priv, reason, apb, status, session);
- #else
- priv->export.upper(priv->export.priv, reason, apb, status);
- #endif
- }
- /****************************************************************************
- * Public Functions
- ****************************************************************************/
- /****************************************************************************
- * Name: audio_comp_initialize
- *
- * Description:
- * Initialize the composite audio device.
- *
- * Input Parameters:
- * name - The name of the audio device.
- * ... - The list of the lower half audio driver.
- *
- * Returned Value:
- * Zero on success; a negated errno value on failure.
- *
- * Note
- * The variable argument list must be NULL terminated.
- *
- ****************************************************************************/
- int audio_comp_initialize(FAR const char *name, ...)
- {
- FAR struct audio_comp_priv_s *priv;
- va_list ap;
- va_list cp;
- int ret = -ENOMEM;
- int i;
- va_start(ap, name);
- va_copy(cp, ap);
- priv = kmm_zalloc(sizeof(struct audio_comp_priv_s));
- if (priv == NULL)
- {
- goto end_va;
- }
- priv->export.ops = &g_audio_comp_ops;
- while (va_arg(ap, FAR struct audio_lowerhalf_s *))
- {
- priv->count++;
- }
- priv->lower = kmm_calloc(priv->count,
- sizeof(FAR struct audio_lowerhalf_s *));
- if (priv->lower == NULL)
- {
- goto free_priv;
- }
- for (i = 0; i < priv->count; i++)
- {
- FAR struct audio_lowerhalf_s *tmp;
- tmp = va_arg(cp, FAR struct audio_lowerhalf_s *);
- tmp->upper = audio_comp_callback;
- tmp->priv = priv;
- priv->lower[i] = tmp;
- }
- ret = audio_register(name, &priv->export);
- if (ret < 0)
- {
- goto free_lower;
- }
- va_end(ap);
- return OK;
- free_lower:
- kmm_free(priv->lower);
- free_priv:
- kmm_free(priv);
- end_va:
- va_end(ap);
- return ret;
- }
|