⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 soundcardpmo.cpp

📁 FreeAMP(MP3播放)程序源代码-用来研究MP3解码
💻 CPP
📖 第 1 页 / 共 2 页
字号:

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 + -