void Audio_Queue::enqueueCachedData() { AQ_ASSERT(!m_waitingOnBuffer); AQ_ASSERT(!m_bufferInUse[m_fillBufferIndex]); /* Queue up as many packets as possible into the buffers */ queued_packet_t *cur = m_queuedHead; while (cur) { int ret = handlePacket(cur->data, &cur->desc); if (ret == 0) { break; } queued_packet_t *next = cur->next; free(cur); cur = next; } m_queuedHead = cur; /* If we finished queueing all our saved packets, we can re-schedule the * stream to run */ if (cur == NULL) { m_queuedTail = NULL; if (m_delegate) { m_delegate->audioQueueUnderflow(); } } }
void Audio_Queue::enqueueBuffer() { AQ_ASSERT(!m_bufferInUse[m_fillBufferIndex]); Stream_Configuration *config = Stream_Configuration::configuration(); AQ_TRACE("%s: enter\n", __PRETTY_FUNCTION__); pthread_mutex_lock(&m_bufferInUseMutex); m_bufferInUse[m_fillBufferIndex] = true; m_buffersUsed++; // enqueue buffer AudioQueueBufferRef fillBuf = m_audioQueueBuffer[m_fillBufferIndex]; fillBuf->mAudioDataByteSize = m_bytesFilled; pthread_mutex_unlock(&m_bufferInUseMutex); AQ_ASSERT(m_packetsFilled > 0); OSStatus err = AudioQueueEnqueueBuffer(m_outAQ, fillBuf, m_packetsFilled, m_packetDescs); if (!err) { m_lastError = noErr; start(); } else { /* If we get an error here, it very likely means that the audio queue is no longer running */ AQ_TRACE("%s: error in AudioQueueEnqueueBuffer\n", __PRETTY_FUNCTION__); m_lastError = err; return; } pthread_mutex_lock(&m_bufferInUseMutex); // go to next buffer if (++m_fillBufferIndex >= config->bufferCount) { m_fillBufferIndex = 0; } // reset bytes filled m_bytesFilled = 0; // reset packets filled m_packetsFilled = 0; // wait until next buffer is not in use while (m_bufferInUse[m_fillBufferIndex]) { AQ_TRACE("waiting for buffer %u\n", (unsigned int)m_fillBufferIndex); pthread_cond_wait(&m_bufferFreeCondition, &m_bufferInUseMutex); } pthread_mutex_unlock(&m_bufferInUseMutex); }
// this is called by the audio queue when it has finished decoding our data. // The buffer is now free to be reused. void Audio_Queue::audioQueueOutputCallback(void *inClientData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) { Audio_Queue *audioQueue = static_cast<Audio_Queue*>(inClientData); Stream_Configuration *config = Stream_Configuration::configuration(); int bufIndex = -1; for (unsigned int i = 0; i < config->bufferCount; ++i) { if (inBuffer == audioQueue->m_audioQueueBuffer[i]) { AQ_TRACE("findQueueBuffer %i\n", i); bufIndex = i; break; } } if (bufIndex == -1) { return; } pthread_mutex_lock(&audioQueue->m_bufferInUseMutex); AQ_ASSERT(audioQueue->m_bufferInUse[bufIndex]); audioQueue->m_bufferInUse[bufIndex] = false; audioQueue->m_buffersUsed--; AQ_TRACE("signaling buffer free for inuse %i....\n", bufIndex); pthread_cond_signal(&audioQueue->m_bufferFreeCondition); AQ_TRACE("signal sent!\n"); if (audioQueue->m_buffersUsed == 0 && audioQueue->m_delegate) { AQ_LOCK_TRACE("audioQueueOutputCallback: unlock 2\n"); pthread_mutex_unlock(&audioQueue->m_bufferInUseMutex); if (audioQueue->m_delegate) { audioQueue->m_delegate->audioQueueBuffersEmpty(); } } else { pthread_mutex_unlock(&audioQueue->m_bufferInUseMutex); if (audioQueue->m_delegate) { audioQueue->m_delegate->audioQueueFinishedPlayingPacket(); } } AQ_LOCK_TRACE("audioQueueOutputCallback: unlock\n"); }
// this is called by the audio queue when it has finished decoding our data. // The buffer is now free to be reused. void Audio_Queue::audioQueueOutputCallback(void *inClientData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) { Audio_Queue *audioQueue = static_cast<Audio_Queue*>(inClientData); unsigned int bufIndex = audioQueue->findQueueBuffer(inBuffer); AQ_ASSERT(audioQueue->m_bufferInUse[bufIndex]); audioQueue->m_bufferInUse[bufIndex] = false; audioQueue->m_buffersUsed--; if (audioQueue->m_buffersUsed == 0 && !audioQueue->m_queuedHead && audioQueue->m_delegate) { audioQueue->m_delegate->audioQueueBuffersEmpty(); } else if (audioQueue->m_waitingOnBuffer) { audioQueue->m_waitingOnBuffer = false; audioQueue->enqueueCachedData(); } }