Audio: Change how the end of the audio stream is detected by the leaf audio component. This used by be done by looking for the first partial buffer. That does not work with the in-place sub-sampling performed by the PCM decoder: That always reduces the size of the buffer so that all buffers only partially filled by the time they get to the leaf. Now, a flag is set in the audio buffer flags set to indicate the final buffer in the stream.

This commit is contained in:
Gregory Nutt 2014-07-31 16:36:09 -06:00
parent 319d07dc69
commit e214382264
5 changed files with 160 additions and 79 deletions

View File

@ -650,6 +650,7 @@ static int null_enqueuebuffer(FAR struct audio_lowerhalf_s *dev,
FAR struct ap_buffer_s *apb) FAR struct ap_buffer_s *apb)
{ {
FAR struct null_dev_s *priv = (FAR struct null_dev_s *)dev; FAR struct null_dev_s *priv = (FAR struct null_dev_s *)dev;
bool final;
audvdbg("apb=%p curbyte=%d nbytes=%d\n", apb, apb->curbyte, apb->nbytes); audvdbg("apb=%p curbyte=%d nbytes=%d\n", apb, apb->curbyte, apb->nbytes);
@ -657,6 +658,10 @@ static int null_enqueuebuffer(FAR struct audio_lowerhalf_s *dev,
apb->curbyte = apb->nbytes; apb->curbyte = apb->nbytes;
/* Check if this was the last buffer in the stream */
done = ((apb->flags & AUDIO_APB_FINAL) != 0);
/* And return the buffer to the upper level */ /* And return the buffer to the upper level */
DEBUGASSERT(priv && apb && priv->dev.upper); DEBUGASSERT(priv && apb && priv->dev.upper);
@ -671,6 +676,17 @@ static int null_enqueuebuffer(FAR struct audio_lowerhalf_s *dev,
priv->dev.upper(priv->dev.priv, AUDIO_CALLBACK_DEQUEUE, apb, OK); priv->dev.upper(priv->dev.priv, AUDIO_CALLBACK_DEQUEUE, apb, OK);
#endif #endif
/* Say we are done playing if this was the last buffer in the stream */
if (done)
{
#ifdef CONFIG_AUDIO_MULTI_SESSION
priv->dev.upper(priv->dev.priv, AUDIO_CALLBACK_COMPLETE, NULL, OK, NULL);
#else
priv->dev.upper(priv->dev.priv, AUDIO_CALLBACK_COMPLETE, NULL, OK);
#endif
}
audvdbg("Return OK\n"); audvdbg("Return OK\n");
return OK; return OK;
} }

View File

@ -43,7 +43,9 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <fcntl.h> #include <fcntl.h>
#include <string.h> #include <string.h>
@ -111,7 +113,7 @@ struct vs1053_struct_s
const FAR struct vs1053_lower_s *hw_lower;/* Pointer to the hardware lower functions */ const FAR struct vs1053_lower_s *hw_lower;/* Pointer to the hardware lower functions */
FAR struct spi_dev_s *spi; /* Pointer to the SPI bus */ FAR struct spi_dev_s *spi; /* Pointer to the SPI bus */
FAR struct ap_buffer_s *pBuf; /* Pointer to the buffer we are processing */ FAR struct ap_buffer_s *apb; /* Pointer to the buffer we are processing */
struct dq_queue_s apbq; /* Our queue for enqueued buffers */ struct dq_queue_s apbq; /* Our queue for enqueued buffers */
unsigned long spi_freq; /* Frequency to run the SPI bus at. */ unsigned long spi_freq; /* Frequency to run the SPI bus at. */
unsigned long chip_freq; /* Current chip frequency */ unsigned long chip_freq; /* Current chip frequency */
@ -131,13 +133,13 @@ struct vs1053_struct_s
#endif #endif
uint16_t endfillbytes; uint16_t endfillbytes;
uint8_t endfillchar; /* Fill char to send when no more data */ uint8_t endfillchar; /* Fill char to send when no more data */
uint8_t running; bool running;
uint8_t paused; bool paused;
uint8_t endmode; bool endmode;
#ifndef CONFIG_AUDIO_EXCLUDE_STOP #ifndef CONFIG_AUDIO_EXCLUDE_STOP
uint8_t cancelmode; bool cancelmode;
#endif #endif
uint8_t busy; /* Set true when device reserved */ bool busy; /* Set true when device reserved */
}; };
/**************************************************************************** /****************************************************************************
@ -511,7 +513,7 @@ static void vs1053_setvolume(FAR struct vs1053_struct_s *dev)
leftreg = vs1053_logapprox(leftlevel / 10); leftreg = vs1053_logapprox(leftlevel / 10);
rightreg = vs1053_logapprox(rightlevel / 10); rightreg = vs1053_logapprox(rightlevel / 10);
/* Lock the SPI bus to get exclsive access to the chip. */ /* Lock the SPI bus to get exclusive access to the chip. */
vs1053_spi_lock(spi, dev->spi_freq); vs1053_spi_lock(spi, dev->spi_freq);
vs1053_writereg(dev, VS1053_SCI_VOL, (leftreg << 8) | rightreg); vs1053_writereg(dev, VS1053_SCI_VOL, (leftreg << 8) | rightreg);
@ -941,7 +943,7 @@ static void vs1053_feeddata(FAR struct vs1053_struct_s *dev)
int ret; int ret;
uint8_t *pSamp = NULL; uint8_t *pSamp = NULL;
uint16_t reg; uint16_t reg;
struct ap_buffer_s *pBuf; struct ap_buffer_s *apb;
FAR struct spi_dev_s *spi = dev->spi; FAR struct spi_dev_s *spi = dev->spi;
/* Check for false interrupt caused by an SCI transaction */ /* Check for false interrupt caused by an SCI transaction */
@ -960,14 +962,14 @@ static void vs1053_feeddata(FAR struct vs1053_struct_s *dev)
/* Local stack copy of our active buffer */ /* Local stack copy of our active buffer */
pBuf = dev->pBuf; apb = dev->apb;
//auddbg("Entry pBuf=%p, Bytes left=%d\n", pBuf, pBuf->nbytes - pBuf->curbyte); //auddbg("Entry apb=%p, Bytes left=%d\n", apb, apb->nbytes - apb->curbyte);
/* Setup pointer to the next sample in the buffer */ /* Setup pointer to the next sample in the buffer */
if (pBuf) if (apb)
{ {
pSamp = &pBuf->samp[pBuf->curbyte]; pSamp = &apb->samp[apb->curbyte];
} }
else if (!dev->endmode) else if (!dev->endmode)
{ {
@ -1018,14 +1020,14 @@ static void vs1053_feeddata(FAR struct vs1053_struct_s *dev)
/* Do a hard reset and terminate */ /* Do a hard reset and terminate */
vs1053_hardreset(dev); vs1053_hardreset(dev);
dev->running = FALSE; dev->running = false;
dev->endmode = FALSE; dev->endmode = false;
break; break;
} }
else if (dev->endfillbytes > 32*65) else if (dev->endfillbytes > 32*65)
{ {
/* After each 32 byte of endfillchar, check the status /* After each 32 byte of endfillchar, check the status
* register to see if SM_CANCEL has been cleard. If * register to see if SM_CANCEL has been cleared. If
* it has been cleared, then we're done. * it has been cleared, then we're done.
*/ */
@ -1041,8 +1043,9 @@ static void vs1053_feeddata(FAR struct vs1053_struct_s *dev)
auddbg("EndFillChar: 0x%0X\n", dev->endfillchar); auddbg("EndFillChar: 0x%0X\n", dev->endfillchar);
reg = vs1053_readreg(dev, VS1053_SCI_MODE); reg = vs1053_readreg(dev, VS1053_SCI_MODE);
vs1053_writereg(dev, VS1053_SCI_MODE, reg | VS1053_SM_RESET); vs1053_writereg(dev, VS1053_SCI_MODE, reg | VS1053_SM_RESET);
dev->running = FALSE;
dev->endmode = FALSE; dev->running = false;
dev->endmode = false;
break; break;
} }
} }
@ -1055,7 +1058,7 @@ static void vs1053_feeddata(FAR struct vs1053_struct_s *dev)
* will recheck the DREQ line again. * will recheck the DREQ line again.
*/ */
bytecount = pBuf->nbytes - pBuf->curbyte; bytecount = apb->nbytes - apb->curbyte;
if (bytecount > 32) if (bytecount > 32)
{ {
bytecount = 32; bytecount = 32;
@ -1073,7 +1076,7 @@ static void vs1053_feeddata(FAR struct vs1053_struct_s *dev)
pSamp++; pSamp++;
} }
#endif #endif
pBuf->curbyte += bytecount; apb->curbyte += bytecount;
/* Test if we are in cancel mode. If we are, then we need /* Test if we are in cancel mode. If we are, then we need
* to continue sending file data and check for the SM_CANCEL * to continue sending file data and check for the SM_CANCEL
@ -1097,16 +1100,19 @@ static void vs1053_feeddata(FAR struct vs1053_struct_s *dev)
{ {
/* Cancel has begun. Switch to endmode */ /* Cancel has begun. Switch to endmode */
pBuf->curbyte = pBuf->nbytes = 0; apb->nbytes = 0;
apb->curbyte = 0;
} }
} }
#endif /* CONFIG_AUDIO_EXCLUDE_STOP */ #endif /* CONFIG_AUDIO_EXCLUDE_STOP */
/* Test if we are at the end of the buffer */ /* Test if we are at the end of the buffer */
if (pBuf->curbyte >= pBuf->nbytes) if (apb->curbyte >= apb->nbytes)
{ {
if (pBuf->nbytes != pBuf->nmaxbytes) /* Check if this was the final buffer in stream */
if ((apb->flags & AUDIO_APB_FINAL) != 0)
{ {
/* This is the final buffer. Get the VS1053 endfillchar */ /* This is the final buffer. Get the VS1053 endfillchar */
@ -1119,7 +1125,8 @@ static void vs1053_feeddata(FAR struct vs1053_struct_s *dev)
/* Mark the device as endmode */ /* Mark the device as endmode */
dev->endmode = TRUE; dev->endmode = true;
#ifndef CONFIG_AUDIO_EXCLUDE_STOP #ifndef CONFIG_AUDIO_EXCLUDE_STOP
if (dev->cancelmode) if (dev->cancelmode)
{ {
@ -1140,13 +1147,13 @@ static void vs1053_feeddata(FAR struct vs1053_struct_s *dev)
/* We referenced the buffer so we must free it */ /* We referenced the buffer so we must free it */
apb_free(pBuf); apb_free(apb);
#ifdef CONFIG_AUDIO_MULTI_SESSION #ifdef CONFIG_AUDIO_MULTI_SESSION
dev->lower.upper(dev->lower.priv, AUDIO_CALLBACK_DEQUEUE, dev->lower.upper(dev->lower.priv, AUDIO_CALLBACK_DEQUEUE,
pBuf, OK, NULL); apb, OK, NULL);
#else #else
dev->lower.upper(dev->lower.priv, AUDIO_CALLBACK_DEQUEUE, dev->lower.upper(dev->lower.priv, AUDIO_CALLBACK_DEQUEUE,
pBuf, OK); apb, OK);
#endif #endif
/* Lock the buffer queue to pop the next buffer */ /* Lock the buffer queue to pop the next buffer */
@ -1167,18 +1174,18 @@ static void vs1053_feeddata(FAR struct vs1053_struct_s *dev)
/* Pop the next entry */ /* Pop the next entry */
pBuf = (struct ap_buffer_s *) dq_remfirst(&dev->apbq); apb = (struct ap_buffer_s *) dq_remfirst(&dev->apbq);
dev->pBuf = pBuf; dev->apb = apb;
//auddbg("Next Buffer = %p, bytes = %d\n", pBuf, pBuf ? pBuf->nbytes : 0); //auddbg("Next Buffer = %p, bytes = %d\n", apb, apb ? apb->nbytes : 0);
if (pBuf == NULL) if (apb == NULL)
{ {
sem_post(&dev->apbq_sem); sem_post(&dev->apbq_sem);
break; break;
} }
pSamp = &pBuf->samp[pBuf->curbyte]; pSamp = &apb->samp[apb->curbyte];
apb_reference(pBuf); /* Add our buffer reference */ apb_reference(apb); /* Add our buffer reference */
sem_post(&dev->apbq_sem); sem_post(&dev->apbq_sem);
} }
} }
@ -1254,7 +1261,7 @@ static void *vs1053_workerthread(pthread_addr_t pvarg)
{ {
FAR struct vs1053_struct_s *dev = (struct vs1053_struct_s *) pvarg; FAR struct vs1053_struct_s *dev = (struct vs1053_struct_s *) pvarg;
struct audio_msg_s msg; struct audio_msg_s msg;
FAR struct ap_buffer_s *pBuf; FAR struct ap_buffer_s *apb;
int size; int size;
int prio; int prio;
#ifndef CONFIG_AUDIO_EXCLUDE_STOP #ifndef CONFIG_AUDIO_EXCLUDE_STOP
@ -1265,9 +1272,10 @@ static void *vs1053_workerthread(pthread_addr_t pvarg)
auddbg("Entry\n"); auddbg("Entry\n");
#ifndef CONFIG_AUDIO_EXCLUDE_STOP #ifndef CONFIG_AUDIO_EXCLUDE_STOP
dev->cancelmode = 0; dev->cancelmode = false;
#endif #endif
dev->endmode = dev->endfillbytes = 0; dev->endmode = false;
dev->endfillbytes = 0;
/* Fill the VS1053 FIFO with initial data. */ /* Fill the VS1053 FIFO with initial data. */
@ -1284,7 +1292,7 @@ static void *vs1053_workerthread(pthread_addr_t pvarg)
/* Loop as long as we are supposed to be running */ /* Loop as long as we are supposed to be running */
dev->running = TRUE; dev->running = true;
dev->hw_lower->enable(dev->hw_lower); /* Enable the DREQ interrupt */ dev->hw_lower->enable(dev->hw_lower); /* Enable the DREQ interrupt */
while (dev->running || dev->endmode) while (dev->running || dev->endmode)
{ {
@ -1303,7 +1311,7 @@ static void *vs1053_workerthread(pthread_addr_t pvarg)
{ {
/* Should we just stop running? */ /* Should we just stop running? */
dev->running = FALSE; dev->running = false;
break; break;
} }
@ -1338,7 +1346,7 @@ static void *vs1053_workerthread(pthread_addr_t pvarg)
/* Set cancelmode */ /* Set cancelmode */
dev->cancelmode = TRUE; dev->cancelmode = true;
break; break;
#endif #endif
@ -1363,7 +1371,7 @@ static void *vs1053_workerthread(pthread_addr_t pvarg)
{ {
/* Get the next buffer from the queue */ /* Get the next buffer from the queue */
while ((pBuf = (FAR struct ap_buffer_s *) dq_remfirst(&dev->apbq)) != NULL) while ((apb = (FAR struct ap_buffer_s *) dq_remfirst(&dev->apbq)) != NULL)
; ;
} }
@ -1371,10 +1379,10 @@ static void *vs1053_workerthread(pthread_addr_t pvarg)
/* Free the active buffer */ /* Free the active buffer */
if (dev->pBuf != NULL) if (dev->apb != NULL)
{ {
apb_free(dev->pBuf); apb_free(dev->apb);
dev->pBuf = NULL; dev->apb = NULL;
} }
/* Close the message queue */ /* Close the message queue */
@ -1458,8 +1466,8 @@ static int vs1053_start(FAR struct audio_lowerhalf_s *lower)
if ((ret = sem_wait(&dev->apbq_sem)) == OK) if ((ret = sem_wait(&dev->apbq_sem)) == OK)
{ {
dev->pBuf = (FAR struct ap_buffer_s *) dq_remfirst(&dev->apbq); dev->apb = (FAR struct ap_buffer_s *) dq_remfirst(&dev->apbq);
apb_reference(dev->pBuf); /* Add our buffer reference */ apb_reference(dev->apb); /* Add our buffer reference */
sem_post(&dev->apbq_sem); sem_post(&dev->apbq_sem);
} }
else else
@ -1560,11 +1568,13 @@ static int vs1053_pause(FAR struct audio_lowerhalf_s *lower)
FAR struct vs1053_struct_s *dev = (struct vs1053_struct_s *) lower; FAR struct vs1053_struct_s *dev = (struct vs1053_struct_s *) lower;
if (!dev->running) if (!dev->running)
return OK; {
return OK;
}
/* Disable interrupts to prevent us from suppling any more data */ /* Disable interrupts to prevent us from supplying any more data */
dev->paused = TRUE; dev->paused = true;
dev->hw_lower->disable(dev->hw_lower); /* Disable the DREQ interrupt */ dev->hw_lower->disable(dev->hw_lower); /* Disable the DREQ interrupt */
return OK; return OK;
} }
@ -1587,11 +1597,13 @@ static int vs1053_resume(FAR struct audio_lowerhalf_s *lower)
FAR struct vs1053_struct_s *dev = (struct vs1053_struct_s *) lower; FAR struct vs1053_struct_s *dev = (struct vs1053_struct_s *) lower;
if (!dev->running) if (!dev->running)
return OK; {
return OK;
}
/* Enable interrupts to allow suppling data */ /* Enable interrupts to allow suppling data */
dev->paused = FALSE; dev->paused = false;
vs1053_feeddata(dev); vs1053_feeddata(dev);
dev->hw_lower->enable(dev->hw_lower); /* Enable the DREQ interrupt */ dev->hw_lower->enable(dev->hw_lower); /* Enable the DREQ interrupt */
return OK; return OK;
@ -1621,7 +1633,7 @@ static int vs1053_enqueuebuffer(FAR struct audio_lowerhalf_s *lower,
/* We can now safely add the buffer to the queue */ /* We can now safely add the buffer to the queue */
apb->curbyte = 0; apb->curbyte = 0;
apb->flags = AUDIO_APB_OUTPUT_ENQUEUED; apb->flags |= AUDIO_APB_OUTPUT_ENQUEUED;
dq_addlast(&apb->dq_entry, &dev->apbq); dq_addlast(&apb->dq_entry, &dev->apbq);
sem_post(&dev->apbq_sem); sem_post(&dev->apbq_sem);
@ -1730,9 +1742,9 @@ static int vs1053_reserve(FAR struct audio_lowerhalf_s *lower)
#ifdef CONFIG_AUDIO_MULTI_SESSION #ifdef CONFIG_AUDIO_MULTI_SESSION
*psession = NULL; *psession = NULL;
#endif #endif
dev->busy = TRUE; dev->busy = true;
dev->running = FALSE; dev->running = false;
dev->paused = FALSE; dev->paused = false;
} }
sem_post(&dev->apbq_sem); sem_post(&dev->apbq_sem);
@ -1774,7 +1786,7 @@ static int vs1053_release(FAR struct audio_lowerhalf_s *lower)
/* Really we should free any queued buffers here */ /* Really we should free any queued buffers here */
dev->busy = 0; dev->busy = false;
sem_post(&dev->apbq_sem); sem_post(&dev->apbq_sem);
return OK; return OK;
@ -1825,9 +1837,9 @@ struct audio_lowerhalf_s *vs1053_initialize(FAR struct spi_dev_s *spi,
dev->spi_freq = CONFIG_VS1053_XTALI / 7; dev->spi_freq = CONFIG_VS1053_XTALI / 7;
dev->spi = spi; dev->spi = spi;
dev->mq = NULL; dev->mq = NULL;
dev->busy = FALSE; dev->busy = false;
dev->threadid = 0; dev->threadid = 0;
dev->running = 0; dev->running = false;
#ifndef CONFIG_AUDIO_EXCLUDE_VOLUME #ifndef CONFIG_AUDIO_EXCLUDE_VOLUME
dev->volume = 250; /* 25% volume as default */ dev->volume = 250; /* 25% volume as default */

View File

@ -451,6 +451,8 @@ static void wm8904_setvolume(FAR struct wm8904_dev_s *priv, uint16_t volume,
uint32_t rightlevel; uint32_t rightlevel;
uint16_t regval; uint16_t regval;
audvdbg("volume=%u mute=%u\n", volume, mute);
#ifndef CONFIG_AUDIO_EXCLUDE_BALANCE #ifndef CONFIG_AUDIO_EXCLUDE_BALANCE
/* Calculate the left channel volume level {0..1000} */ /* Calculate the left channel volume level {0..1000} */
@ -524,6 +526,7 @@ static void wm8904_setvolume(FAR struct wm8904_dev_s *priv, uint16_t volume,
#ifndef CONFIG_AUDIO_EXCLUDE_TONE #ifndef CONFIG_AUDIO_EXCLUDE_TONE
static void wm8904_setbass(FAR struct wm8904_dev_s *priv, uint8_t bass) static void wm8904_setbass(FAR struct wm8904_dev_s *priv, uint8_t bass)
{ {
audvdbg("bass=%u\n", bass);
#warning Missing logic #warning Missing logic
} }
#endif /* CONFIG_AUDIO_EXCLUDE_TONE */ #endif /* CONFIG_AUDIO_EXCLUDE_TONE */
@ -541,6 +544,7 @@ static void wm8904_setbass(FAR struct wm8904_dev_s *priv, uint8_t bass)
#ifndef CONFIG_AUDIO_EXCLUDE_TONE #ifndef CONFIG_AUDIO_EXCLUDE_TONE
static void wm8904_settreble(FAR struct wm8904_dev_s *priv, uint8_t treble) static void wm8904_settreble(FAR struct wm8904_dev_s *priv, uint8_t treble)
{ {
audvdbg("treble=%u\n", treble);
#warning Missing logic #warning Missing logic
} }
#endif /* CONFIG_AUDIO_EXCLUDE_TONE */ #endif /* CONFIG_AUDIO_EXCLUDE_TONE */
@ -555,11 +559,10 @@ static void wm8904_settreble(FAR struct wm8904_dev_s *priv, uint8_t treble)
static int wm8904_getcaps(FAR struct audio_lowerhalf_s *dev, int type, static int wm8904_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
FAR struct audio_caps_s *caps) FAR struct audio_caps_s *caps)
{ {
audvdbg("Entry\n");
/* Validate the structure */ /* Validate the structure */
DEBUGASSERT(caps->ac_len >= sizeof(struct audio_caps_s)); DEBUGASSERT(caps && caps->ac_len >= sizeof(struct audio_caps_s));
audvdbg("type=%d ac_type=%d\n", type, caps->ac_type);
/* Fill in the caller's structure based on requested info */ /* Fill in the caller's structure based on requested info */
@ -726,6 +729,7 @@ static int wm8904_configure(FAR struct audio_lowerhalf_s *dev,
#endif #endif
int ret = OK; int ret = OK;
DEBUGASSERT(priv && caps);
audvdbg("ac_type: %d\n", caps->ac_type); audvdbg("ac_type: %d\n", caps->ac_type);
/* Process the configure operation */ /* Process the configure operation */
@ -858,6 +862,7 @@ static int wm8904_shutdown(FAR struct audio_lowerhalf_s *dev)
{ {
FAR struct wm8904_dev_s *priv = (FAR struct wm8904_dev_s *)dev; FAR struct wm8904_dev_s *priv = (FAR struct wm8904_dev_s *)dev;
DEBUGASSERT(priv);
wm8904_reset(priv); wm8904_reset(priv);
return OK; return OK;
} }
@ -881,6 +886,7 @@ static void wm8904_senddone(FAR struct i2s_dev_s *i2s,
int ret; int ret;
DEBUGASSERT(i2s && priv && priv->running && apb); DEBUGASSERT(i2s && priv && priv->running && apb);
audvdbg("apb=%p inflight=%d\n", apb, priv->inflight);
/* We do not place any restriction on the context in which this function /* We do not place any restriction on the context in which this function
* is called. It may be called from an interrupt handler. Therefore, the * is called. It may be called from an interrupt handler. Therefore, the
@ -933,7 +939,7 @@ static void wm8904_senddone(FAR struct i2s_dev_s *i2s,
static void wm8904_returnbuffers(FAR struct wm8904_dev_s *priv) static void wm8904_returnbuffers(FAR struct wm8904_dev_s *priv)
{ {
FAR struct ap_buffer_s *apb; FAR struct ap_buffer_s *apb;
irqstate_t flags; irqstate_t flags;
/* The doneq and in-flight values might be accessed from the interrupt /* The doneq and in-flight values might be accessed from the interrupt
* level in some implementations. Not the best design. But we will * level in some implementations. Not the best design. But we will
@ -943,14 +949,43 @@ static void wm8904_returnbuffers(FAR struct wm8904_dev_s *priv)
flags = irqsave(); flags = irqsave();
while (dq_peek(&priv->doneq) != NULL) while (dq_peek(&priv->doneq) != NULL)
{ {
/* Take next buffer from the queue of completed transfers */ /* Take the next buffer from the queue of completed transfers */
apb = (FAR struct ap_buffer_s *)dq_remfirst(&priv->doneq); apb = (FAR struct ap_buffer_s *)dq_remfirst(&priv->doneq);
irqrestore(flags); irqrestore(flags);
audvdbg("Returning apb=%p flags=%04x\n", apb, apb->flags);
/* Are we returning the final buffer in the stream? */
if ((apb->flags & AUDIO_APB_FINAL) != 0)
{
/* Both the pending and the done queues should be empty and there
* should be no buffers in-flight.
*/
DEBUGASSERT(dq_empty(&priv->doneq) && dq_empty(&priv->pendq) &&
priv->inflight == 0);
/* Set the terminating flag. This will, eventually, cause the
* worker thread to exit (if it is not already terminating).
*/
audvdbg("Terminating\n");
priv->terminating = true;
}
/* Release our reference to the audio buffer */ /* Release our reference to the audio buffer */
apb_free(apb); apb_free(apb);
/* Send the buffer back up to the previous level. */
#ifdef CONFIG_AUDIO_MULTI_SESSION
priv->dev.upper(priv->dev.priv, AUDIO_CALLBACK_DEQUEUE, apb, OK, NULL);
#else
priv->dev.upper(priv->dev.priv, AUDIO_CALLBACK_DEQUEUE, apb, OK);
#endif
flags = irqsave(); flags = irqsave();
} }
@ -993,7 +1028,8 @@ static int wm8904_sendbuffer(FAR struct wm8904_dev_s *priv)
/* Take next buffer from the queue of pending transfers */ /* Take next buffer from the queue of pending transfers */
apb = (FAR struct ap_buffer_s *)dq_remfirst(&priv->pendq); apb = (FAR struct ap_buffer_s *)dq_remfirst(&priv->pendq);
audvdbg("Sending apb=%p, size=%d\n", apb, apb->nbytes); audvdbg("Sending apb=%p, size=%d inflight=%d\n",
apb, apb->nbytes, priv->inflight);
/* Increment the number of buffers in-flight before sending in order /* Increment the number of buffers in-flight before sending in order
* to avoid a possible race condition. * to avoid a possible race condition.
@ -1082,7 +1118,9 @@ static void *wm8904_workerthread(pthread_addr_t pvarg)
WM8904_ENABLE(priv->lower); WM8904_ENABLE(priv->lower);
wm8904_setvolume(priv, priv->volume, false); wm8904_setvolume(priv, priv->volume, false);
/* Loop as long as we are supposed to be running */ /* Loop as long as we are supposed to be running and as long as we have
* buffers in-flight.
*/
while (priv->running || priv->inflight > 0) while (priv->running || priv->inflight > 0)
{ {
@ -1125,7 +1163,7 @@ static void *wm8904_workerthread(pthread_addr_t pvarg)
*/ */
case AUDIO_MSG_DATA_REQUEST: case AUDIO_MSG_DATA_REQUEST:
/* REVISIT this */ audvdbg("AUDIO_MSG_DATA_REQUEST\n");
break; break;
/* Stop the playback */ /* Stop the playback */
@ -1134,6 +1172,7 @@ static void *wm8904_workerthread(pthread_addr_t pvarg)
case AUDIO_MSG_STOP: case AUDIO_MSG_STOP:
/* Indicate that we are terminating */ /* Indicate that we are terminating */
audvdbg("AUDIO_MSG_STOP: Terminating\n");
priv->terminating = true; priv->terminating = true;
break; break;
#endif #endif
@ -1143,11 +1182,13 @@ static void *wm8904_workerthread(pthread_addr_t pvarg)
*/ */
case AUDIO_MSG_ENQUEUE: case AUDIO_MSG_ENQUEUE:
audvdbg("AUDIO_MSG_ENQUEUE\n");
break; break;
/* We will wake up from the I2S callback with this message */ /* We will wake up from the I2S callback with this message */
case AUDIO_MSG_COMPLETE: case AUDIO_MSG_COMPLETE:
audvdbg("AUDIO_MSG_COMPLETE\n");
wm8904_returnbuffers(priv); wm8904_returnbuffers(priv);
break; break;
@ -1170,6 +1211,14 @@ static void *wm8904_workerthread(pthread_addr_t pvarg)
/* Release our reference to the buffer */ /* Release our reference to the buffer */
apb_free(apb); apb_free(apb);
/* Send the buffer back up to the previous level. */
#ifdef CONFIG_AUDIO_MULTI_SESSION
priv->dev.upper(priv->dev.priv, AUDIO_CALLBACK_DEQUEUE, apb, OK, NULL);
#else
priv->dev.upper(priv->dev.priv, AUDIO_CALLBACK_DEQUEUE, apb, OK);
#endif
} }
wm8904_givesem(&priv->pendsem); wm8904_givesem(&priv->pendsem);
@ -1386,7 +1435,7 @@ static int wm8904_enqueuebuffer(FAR struct audio_lowerhalf_s *dev,
struct audio_msg_s term_msg; struct audio_msg_s term_msg;
int ret = -EAGAIN; int ret = -EAGAIN;
audvdbg("Entry\n"); audvdbg("apb=%p\n", apb);
/* Take a reference on the new audio buffer */ /* Take a reference on the new audio buffer */
@ -1395,7 +1444,7 @@ static int wm8904_enqueuebuffer(FAR struct audio_lowerhalf_s *dev,
/* Add the new buffer to the tail of pending audio buffers */ /* Add the new buffer to the tail of pending audio buffers */
wm8904_takesem(&priv->pendsem); wm8904_takesem(&priv->pendsem);
apb->flags = AUDIO_APB_OUTPUT_ENQUEUED; apb->flags |= AUDIO_APB_OUTPUT_ENQUEUED;
dq_addlast(&apb->dq_entry, &priv->pendq); dq_addlast(&apb->dq_entry, &priv->pendq);
wm8904_givesem(&priv->pendsem); wm8904_givesem(&priv->pendsem);
@ -1434,6 +1483,7 @@ static int wm8904_enqueuebuffer(FAR struct audio_lowerhalf_s *dev,
static int wm8904_cancelbuffer(FAR struct audio_lowerhalf_s *dev, static int wm8904_cancelbuffer(FAR struct audio_lowerhalf_s *dev,
FAR struct ap_buffer_s *apb) FAR struct ap_buffer_s *apb)
{ {
audvdbg("apb=%p\n", apb);
return OK; return OK;
} }

View File

@ -289,9 +289,10 @@
/* Audio Pipeline Buffer flags */ /* Audio Pipeline Buffer flags */
#define AUDIO_APB_OUTPUT_ENQUEUED 0x0001; #define AUDIO_APB_OUTPUT_ENQUEUED (1 << 0)
#define AUDIO_APB_OUTPUT_PROCESS 0x0002; #define AUDIO_APB_OUTPUT_PROCESS (1 << 1)
#define AUDIO_APB_DEQUEUED 0x0004; #define AUDIO_APB_DEQUEUED (1 << 2)
#define AUDIO_APB_FINAL (1 << 3) /* Last buffer in the stream */
/**************************************************************************** /****************************************************************************
* Public Types * Public Types

View File

@ -118,15 +118,15 @@ int apb_alloc(FAR struct audio_buf_desc_s *bufdesc)
{ {
uint32_t bufsize; uint32_t bufsize;
int ret; int ret;
struct ap_buffer_s *pBuf; struct ap_buffer_s *apb;
DEBUGASSERT(bufdesc->u.ppBuffer != NULL); DEBUGASSERT(bufdesc->u.ppBuffer != NULL);
/* Perform a user mode allocation */ /* Perform a user mode allocation */
bufsize = sizeof(struct ap_buffer_s) + bufdesc->numbytes; bufsize = sizeof(struct ap_buffer_s) + bufdesc->numbytes;
pBuf = lib_umalloc(bufsize); apb = lib_umalloc(bufsize);
*bufdesc->u.ppBuffer = pBuf; *bufdesc->u.ppBuffer = apb;
/* Test if the allocation was successful or not */ /* Test if the allocation was successful or not */
@ -138,15 +138,17 @@ int apb_alloc(FAR struct audio_buf_desc_s *bufdesc)
{ {
/* Populate the buffer contents */ /* Populate the buffer contents */
memset(pBuf, 0, bufsize); memset(apb, 0, bufsize);
pBuf->i.channels = 1; apb->i.channels = 1;
pBuf->crefs = 1; apb->crefs = 1;
pBuf->nmaxbytes = bufdesc->numbytes; apb->nmaxbytes = bufdesc->numbytes;
pBuf->nbytes = 0; apb->nbytes = 0;
apb->flags = 0;
#ifdef CONFIG_AUDIO_MULTI_SESSION #ifdef CONFIG_AUDIO_MULTI_SESSION
pBuf->session = bufdesc->session; apb->session = bufdesc->session;
#endif #endif
sem_init(&pBuf->sem, 0, 1);
sem_init(&apb->sem, 0, 1);
ret = sizeof(struct audio_buf_desc_s); ret = sizeof(struct audio_buf_desc_s);
} }