📄 soundcardpmo.cpp
字号:
void SoundCardPMO::Clear(void)
{
if (m_initialized)
{
int i;
waveOutReset(m_hwo);
g_pHeaderMutex->Acquire();
for (i = 0; i < m_num_headers; i++)
{
m_wavehdr_array[i].dwBufferLength = m_data_size;
m_wavehdr_array[i].dwBytesRecorded = 0;
m_wavehdr_array[i].dwUser = 0;
m_wavehdr_array[i].dwLoops = 0;
m_wavehdr_array[i].dwFlags = NULL;
}
m_iOffset = 0;
m_iHead = m_iTail = 0;
g_pHeaderMutex->Release();
}
PhysicalMediaOutput::Clear();
}
Error SoundCardPMO::Reset(bool user_stop)
{
waveOutPause(m_hwo);
return kError_NoErr;
}
Error SoundCardPMO::Write(void *pBuffer, uint32 uSize)
{
Error result = kError_NoErr;
WAVEHDR *wavhdr = NULL;
wavhdr = NextHeader();
if (!wavhdr)
{
return kError_Interrupt;
}
if (pBase == NULL)
pBase = (char *)pBuffer;
if ((((char *)pBuffer) + uSize)- pBase > m_pInputBuffer->GetBufferSize())
{
//Debug_v("Diff: %d Size: %u",
// ((((char *)pBuffer) + uSize) - pBase), m_pInputBuffer->GetBufferSize());
assert(0);
}
wavhdr->dwBufferLength = uSize;
wavhdr->lpData = (char *)pBuffer;
// Prepare & write newest header
waveOutPrepareHeader(m_hwo, wavhdr, m_hdr_size);
waveOutWrite(m_hwo, wavhdr, m_hdr_size);
return result;
}
Error SoundCardPMO::AllocHeader(void *&pBuffer, uint32 &uSize)
{
Error eRet;
unsigned iRead, uMaxBytes;
int iNumBlocks;
uMaxBytes = m_pInputBuffer->GetBufferSize() -
(m_pInputBuffer->GetReadIndex() + m_iOffset);
iNumBlocks = iFramesPerHeader;
if (iNumBlocks * m_data_size >= uMaxBytes && uMaxBytes != 0)
{
iNumBlocks = uMaxBytes / m_data_size;
assert(uMaxBytes % m_data_size == 0);
}
while(iNumBlocks > 0)
{
uSize = m_data_size * iNumBlocks;
iRead = m_iOffset + uSize;
eRet = ((EventBuffer *)m_pInputBuffer)->BeginRead(pBuffer, iRead);
if (eRet == kError_NoDataAvail)
{
iNumBlocks >>= 1;
continue;
}
if (eRet != kError_NoErr)
return eRet;
else
break;
}
if (iNumBlocks == 0)
return kError_NoDataAvail;
eRet = ((EventBuffer *)m_pInputBuffer)->EndRead(0);
if (eRet != kError_NoErr)
return eRet;
pBuffer = (char *)pBuffer + m_iOffset;
((EventBuffer *)m_pInputBuffer)->WrapPointer(pBuffer);
m_iOffset += uSize;
((EventBuffer *)m_pInputBuffer)->SetBytesInUse(m_iOffset);
return kError_NoErr;
}
Error SoundCardPMO::FreeHeader(uint32 uSize)
{
Error eRet;
void *pBuffer;
unsigned iRead;
iRead = uSize;
eRet = ((EventBuffer *)m_pInputBuffer)->BeginRead(pBuffer, iRead);
if (eRet != kError_NoErr)
return eRet;
eRet = ((EventBuffer *)m_pInputBuffer)->EndRead(iRead);
if (eRet != kError_NoErr)
return eRet;
m_iOffset -= uSize;
((EventBuffer *)m_pInputBuffer)->SetBytesInUse(m_iOffset);
return kError_NoErr;
}
WAVEHDR *SoundCardPMO::NextHeader(bool bFreeHeadersOnly)
{
WAVEHDR *result = NULL;
unsigned iLoop;
Error eRet;
assert(m_initialized);
for(; !m_bExit;)
{
g_pHeaderMutex->Acquire();
for(iLoop = 0; iLoop < m_num_headers; iLoop++)
{
if ((int)m_wavehdr_array[iLoop].dwUser < 0 &&
(-(int)m_wavehdr_array[iLoop].dwUser) == m_iTail + 1)
{
waveOutUnprepareHeader(m_hwo, &m_wavehdr_array[iLoop], sizeof(WAVEHDR));
eRet = FreeHeader(m_wavehdr_array[iLoop].dwBufferLength);
if (IsError(eRet))
{
g_pHeaderMutex->Release();
return NULL;
}
m_wavehdr_array[iLoop].dwUser = 0;
m_iTail++;
}
if (!bFreeHeadersOnly && !m_wavehdr_array[iLoop].dwUser)
{
result = &m_wavehdr_array[iLoop];
result->dwUser = ++m_iHead;
g_pHeaderMutex->Release();
return result;
}
}
g_pHeaderMutex->Release();
if (bFreeHeadersOnly)
return NULL;
// Toss out frames that have been consumed
NextHeader(true);
if (m_iHead == m_iTail)
m_iBaseTime = MAXINT32;
CheckForBufferUp();
usleep(10000);
}
return NULL;
}
void SoundCardPMO::StartWorkerThread(void *pVoidBuffer)
{
((SoundCardPMO*)pVoidBuffer)->WorkerThread();
}
void SoundCardPMO::WorkerThread(void)
{
void *pBuffer;
Error eErr;
Event *pEvent;
int iValue;
uint32 uSize;
// Don't do anything until resume is called.
m_pPauseSem->Wait();
// Wait for prebuffer period
PreBuffer();
m_pContext->prefs->GetPrefInt32(kDecoderThreadPriorityPref, &iValue);
m_pBufferThread->SetPriority(iValue);
for(; !m_bExit;)
{
if (m_bPause)
{
m_pPauseSem->Wait();
continue;
}
// Loop until we get an Init event from the LMC
if (!m_initialized)
{
pEvent = ((EventBuffer *)m_pInputBuffer)->GetEvent();
if (pEvent == NULL)
{
m_pLmc->Wake();
WasteTime();
continue;
}
if (pEvent->Type() == PMO_Init)
{
if (IsError(Init(((PMOInitEvent *)pEvent)->GetInfo())))
{
delete pEvent;
break;
}
}
delete pEvent;
continue;
}
// Set up reading a block from the buffer. If not enough bytes are
// available, sleep for a little while and try again.
for(;;)
{
if (m_bPause || m_bExit)
break;
eErr = AllocHeader(pBuffer, uSize);
if (eErr == kError_EndOfStream || eErr == kError_Interrupt)
break;
if (eErr == kError_NoDataAvail)
{
m_pLmc->Wake();
// Calling NextHeader with a true arguments just
// cleans up the pending headers so the bytes in use
// value is correct.
NextHeader(true);
HandleTimeInfoEvent(NULL);
if (m_iHead == m_iTail)
m_iBaseTime = MAXINT32;
WasteTime();
CheckForBufferUp();
continue;
}
// Is there an event pending that we need to take care of
// before we play this block of samples?
if (eErr == kError_EventPending)
{
pEvent = ((EventBuffer *)m_pInputBuffer)->PeekEvent();
if (pEvent == NULL)
continue;
if (pEvent->Type() == PMO_Quit &&
((EventBuffer *)m_pInputBuffer)->GetBytesInUse() > 0)
{
if (WaitForDrain())
{
m_pTarget->AcceptEvent(new Event(INFO_DoneOutputting));
return;
}
continue;
}
pEvent = ((EventBuffer *)m_pInputBuffer)->GetEvent();
if (pEvent == NULL)
continue;
if (pEvent->Type() == PMO_Init)
{
Init(((PMOInitEvent *)pEvent)->GetInfo());
}
if (pEvent->Type() == PMO_Reset)
Reset(true);
if (pEvent->Type() == PMO_Info)
HandleTimeInfoEvent((PMOTimeInfoEvent *)pEvent);
if (pEvent->Type() == PMO_Quit)
{
m_pTarget->AcceptEvent(new Event(INFO_DoneOutputting));
delete pEvent;
return;
}
delete pEvent;
continue;
}
if (IsError(eErr))
{
ReportError("Internal error occured.");
m_pContext->log->Error("Cannot read from buffer in PMO "
"worker tread: %d\n", eErr);
return;
}
break;
}
if (m_bPause || m_bExit)
continue;
Write(pBuffer, uSize);
m_pLmc->Wake();
UpdateBufferStatus();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -