DWORD StreamContext::Reset() { AddRef(); // Stop stream for now. Stop(); m_lpWaveHdrCurrent = NULL; m_lpCurrData = NULL; m_lpCurrDataEnd = NULL; m_dwByteCount = 0; m_dwLoopCount = 0; LPWAVEHDR lpHdr; while (m_lpWaveHdrHead) { lpHdr = m_lpWaveHdrHead; m_lpWaveHdrHead = lpHdr->lpNext; if (m_lpWaveHdrHead==NULL) { m_lpWaveHdrTail=NULL; } ReturnBuffer(lpHdr); } Release(); return MMSYSERR_NOERROR; }
DWORD StreamContext::BreakLoop() { AddRef(); if (m_dwLoopCount>0) { m_dwLoopCount = 0; LPWAVEHDR lpHdr; while (m_lpWaveHdrHead!=m_lpWaveHdrCurrent) { lpHdr = m_lpWaveHdrHead; m_lpWaveHdrHead = lpHdr->lpNext; if (m_lpWaveHdrHead==NULL) { m_lpWaveHdrTail=NULL; } ReturnBuffer(lpHdr); } } Release(); return MMSYSERR_NOERROR; }
// Read data from the audio Buffer. // Called at interrupt time to get the good data from the audiobuffer object. // BOOL WAVESTREAM::_vReadAudioBuf(void) { PSTREAMBUFFER pTemp = (PSTREAMBUFFER)qhInProcess.Head(); ULONG pdataBuf; ULONG Buff_left, bytesread; if(!pTemp) return FALSE; // get the buffer pointer and amount of data remaining pdataBuf = (ULONG)pTemp->pBuffptr + pTemp->ulBuffpos; Buff_left = pTemp->ulBuffsz - pTemp->ulBuffpos; // write the audio buffer bytesread = OSS16_StreamAddBuffer(this, pdataBuf, Buff_left); if(bytesread == 0) { return FALSE; //no more data } dprintf4(("_vReadAudioBuf %lx size %d, bytes read %d", pdataBuf, Buff_left, bytesread)); // update the buffer pos counter pTemp->ulBuffpos += bytesread; _ulBytesProcessed += bytesread; if(pTemp->ulBuffpos == pTemp->ulBuffsz) { qhDone.PushOnTail(qhInProcess.PopHead()); ReturnBuffer(); dprintf4(("_vReadAudioBuf return buffer %lx size %ld, bytes read %ld", (ULONG)pTemp->pBuffptr, pTemp->ulBuffsz, bytesread)); } return TRUE; }
void STREAM::ReturnBuffers(void) { while (uHead != uTail) { ReturnBuffer(uHead); uHead = (uHead+1) & (MAX_BUFFERS-1); } uBufIdx=0; }
// called by the irq function in the hardware object when we get an interrupt // first call _vUpdateProcessed() to update the dma amd audio buffer related // stuff. Next if we have buffers on the primary queue try to read/write them // to the audiobuffer. Look at the buffers on the done queue and see if they // can be returned and finally process any events pending. void WAVESTREAM::Process(void) { PSTREAMBUFFER ptemp; ULONG ulCurBytesProcessed = 0; ULONG bytesinc; switch (ulStreamType & STREAM_WRITE) { case STREAM_WRITE: { OSS16_StreamGetPos(this, &ulCurBytesProcessed); if(ulCurBytesProcessed == 0) { //shouldn't happen DebugInt3(); return; } bytesinc = ulCurBytesProcessed - _ulBytesProcessed; dprintf4(("Process: %lx %x", ulCurBytesProcessed, (USHORT)bytesinc)); if(ulCurBytesProcessed < _ulBytesProcessed) { dprintf(("WARNING: Process: Current pos %ld incr %d", ulCurBytesProcessed, (USHORT)bytesinc)); } _ulBytesProcessed = ulCurBytesProcessed; while(bytesinc) { if(qhDone.IsElements()) { // if there are buffers that have been // completly written to the audio buffer // check the first one on the done queue // if it's data has been consumed by // the hardware return it ptemp = (PSTREAMBUFFER)qhDone.Head(); ptemp->ulDonepos += bytesinc; bytesinc = 0; if(ptemp->ulDonepos >= ptemp->ulBuffsz) { //calc position in next buffer bytesinc = ptemp->ulDonepos - ptemp->ulBuffsz; dprintf3(("Process: Return buffer %lx size %d", ptemp->pBuffptr, ptemp->ulBuffsz)); ReturnBuffer(); } } else break; //shouldn't happen } AddBuffers(FALSE); break; } case STREAM_READ: while(_vReadAudioBuf()); break; default: break; } /* endswitch */ ProcessEvents(); }
void CMMALVideo::ReleaseBuffer(CMMALVideoBuffer *buffer) { // remove from busy list pthread_mutex_lock(&m_output_mutex); assert(m_output_busy > 0); m_output_busy--; pthread_mutex_unlock(&m_output_mutex); ReturnBuffer(buffer); bool done = false; pthread_mutex_lock(&m_output_mutex); if (m_finished && !m_output_busy) done = true; pthread_mutex_unlock(&m_output_mutex); if (done) m_myself.reset(); if (g_advancedSettings.CanLogComponent(LOGVIDEO)) CLog::Log(LOGDEBUG, "%s::%s %p (%p) dts_queue(%d) ready_queue(%d) busy_queue(%d) done:%d", CLASSNAME, __func__, buffer, buffer->mmal_buffer, m_dts_queue.size(), m_output_ready.size(), m_output_busy, done); delete buffer; }
// Assumes lock is taken PBYTE StreamContext::GetNextBuffer() { LPWAVEHDR lpOldHdr; LPWAVEHDR lpNewHdr; LPSTR pNewBuf=NULL; // Get a pointer to the current buffer which is now done being processed lpOldHdr=m_lpWaveHdrCurrent; if (!lpOldHdr) { return NULL; } // Are we in a loop // Note: a loopcount of 1 means we're not really in a loop if (m_dwLoopCount>1) { // We're in a loop! if (lpOldHdr->dwFlags & WHDR_ENDLOOP) { // In loop, last buffer // If dwLoopCount was set to INFINITE, loop forever // (Note: this is not explicitly in the wave driver API spec) if (m_dwLoopCount!=INFINITE) { m_dwLoopCount--; // decrement loop count } lpNewHdr=m_lpWaveHdrHead; // go back to start of loop } else { // In loop, intermediate buffer lpNewHdr=lpOldHdr->lpNext; // just go to next buffer in loop block } lpOldHdr=NULL; } else { // Not in a loop; return old buffer and get new buffer lpNewHdr=lpOldHdr->lpNext; m_lpWaveHdrHead = lpNewHdr; // reset list head if (!lpNewHdr) { m_lpWaveHdrTail=NULL; // no new buffer, reset tail to NULL } else if (lpNewHdr->dwFlags & WHDR_BEGINLOOP) // if new buffer is start of a loop block { m_dwLoopCount=lpNewHdr->dwLoops; // save # of loops } } m_lpWaveHdrCurrent=lpNewHdr; // save current buffer pointer if (lpNewHdr) { m_lpCurrData = (PBYTE)lpNewHdr->lpData; // reinitialize data pointer m_lpCurrDataEnd = m_lpCurrData + lpNewHdr->dwBufferLength; } else { m_lpCurrData = NULL; m_lpCurrDataEnd = NULL; } // Return the old buffer // This may cause the stream to be destroyed, so make sure that any calls to this function // are within an AddRef/Release block if (lpOldHdr) { ReturnBuffer(lpOldHdr); } return m_lpCurrData; }
// // _vRealignPausedBuffers(void) // when a stream is paused we need to "realign" the data in the audio buffer // with reality. On playback, not all the data in the audio buffer has been // consumed. Likewise on a capture, not all the good data in the audio buffer // has been copied out. After receiving the DDCMDCONTROL Pause we will call // this function to line the MMPM buffers back up. // there are 2 cases here: first one is the case of a capture stream. // for a capture stream we simply read any data that is still in the audio // buffer into a MMPM buffer. // for a playback stream things are not so straight forward. // first check the STREAMBUFFER on pHead to see if any of it's data is in the // audio buffer and not consumed, if yes back up the ulBuffpos in the // STREAMBUFFER. Next check any STREAMBUFFERS on pdone starting with the last // one. (the one on the tail of the queue) If necessary back up the ulBuffpos // and put the STREAMBUFFER on the Head queue. // void WAVESTREAM::_vRealignPausedBuffers(ULONG endpos) { PSTREAMBUFFER ptempbuff; switch (ulStreamType & STREAM_WRITE) { case STREAM_READ: //SvL: Don't get the lastest recording data as a read command // would now restart recording (as it's stopped) // Just return what we've got or push the buffer on the inprocess queue ptempbuff = (PSTREAMBUFFER)qhDone.Head(); if(ptempbuff) { if(ptempbuff->ulBuffpos) {//if we recorded anything into this buffer, then return it now ReturnBuffer(); return; } ptempbuff->ulBuffpos = 0; ptempbuff->ulDonepos = 0; qhInProcess.PushOnHead(qhDone.PopHead()); } break; case STREAM_WRITE: { PQUEUEHEAD pTempHead = new QUEUEHEAD; ULONG bytesinc; USHORT usRC; bytesinc = endpos - _ulBytesProcessed; bytesinc &= 0xFFFFFFFC; //keep it on a dword boundary // if there are bufferes on the done queue, pop them off the head and // push them on the head of qhTempHead. This will reorder them so // that the more recently used ones will be in the front of the queue. // Pass them all to _vRealignBuffer. If the rc from _vRealignBuffer is // 0 then there is no unprocessed data in the buffer (it is ready to // be returned) so put it on the Tail of the done queue. // If the rc is 1 then put it on the head of the InProcess queue. while (qhDone.IsElements()) { pTempHead->PushOnTail(qhDone.PopHead()); } /* endwhile */ while (qhInProcess.IsElements()) { pTempHead->PushOnTail(qhInProcess.PopHead()); } /* endwhile */ while(pTempHead->IsElements()) { usRC = _vRealignBuffer(&bytesinc, (PSTREAMBUFFER)pTempHead->Head()); if (usRC) { qhInProcess.PushOnTail(pTempHead->PopHead()); } else { qhDone.PushOnTail(pTempHead->PopHead()); } } /* endwhile */ if(qhDone.IsElements()) ReturnBuffer(); delete pTempHead; // free the memory this ain't no Java here !! break; } default: break; } /* endswitch */ }