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

📄 dsoundcardpmo.cpp

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

  PhysicalMediaOutput::Pause();
}

void
DSoundCardPMO::
Resume()
{
  m_bLMCsaidToPlay = true;
  // If the LMC is pausing then resume manually
  // otherwise, it's a seek or a stop (DSClear has been called)
  // and we let the Monitor decide to start playing when there are data
  if ((m_DSBufferManager.pDSSecondaryBuffer) && (m_bIsBufferEmptyNow == false))
    m_DSBufferManager.pDSSecondaryBuffer->Play( 0, 0, DSBPLAY_LOOPING);

  PhysicalMediaOutput::Resume();
}

Error
DSoundCardPMO::
Reset(bool user_stop)
{
  if(user_stop)
  {
    DSReset();
    DSClear();
  }

  return kError_NoErr;
}

void 
DSoundCardPMO::
Clear()
{
    DSClear();
    PhysicalMediaOutput::Clear();
}

void
DSoundCardPMO::
HandleTimeInfoEvent(PMOTimeInfoEvent *pEvent)
{
  MediaTimeInfoEvent* pmtpi;
  int32               hours, minutes, seconds;
  int                 iTotalTime = 0;

  if (m_samples_per_second <= 0)
    return;

  // Since the Monitor modifies the m_iTotalBytesWritten, we meed exclusive access
  m_pDSBufferSem->Wait();

  if (pEvent->GetFrameNumber() != m_iLastFrame + 1)
  {
    m_iTotalBytesWritten = m_samples_per_frame * 
                           pEvent->GetFrameNumber() *  
                           m_iBytesPerSample;
  }
  m_iLastFrame = pEvent->GetFrameNumber();

  iTotalTime  = (m_iTotalBytesWritten) / (m_iBytesPerSample * m_samples_per_second);

  m_pDSBufferSem->Signal();

  hours       = iTotalTime / 3600;
  minutes     = (iTotalTime - hours) / 60;
  seconds     = iTotalTime - hours * 3600 - minutes * 60;

  if (minutes < 0 || minutes > 59 || seconds < 0 || seconds > 59)
    return;

  pmtpi = new MediaTimeInfoEvent(hours, minutes, seconds, 0,
                                (float)iTotalTime, 0);
  m_pTarget->AcceptEvent(pmtpi);
}

Error
DSoundCardPMO::
GetData(void *&pBuffer)
{
  Error     eRet;
  unsigned  iRead;

  iRead = m_data_size;
  eRet = ((EventBuffer *)m_pInputBuffer)->BeginRead(pBuffer, iRead);
  if (eRet != kError_NoErr)
    return eRet;

  eRet = ((EventBuffer *)m_pInputBuffer)->EndRead(0);
  if (eRet != kError_NoErr)
    return eRet;

  return kError_NoErr;
}

Error
DSoundCardPMO::
Write(void *pBuffer)
{
  int   nState;
  int32 wrote;

  for(; !m_bExit;)
  {
    // wait until we are in a good state to write
    nState = DSMonitorBufferState();
    if (nState == -1 || nState == OVERFLOW || nState == STOPPING)
    {
      ::Sleep(WRITESLEEPTIME);
    }
    else
      break;
  }

  if (m_bExit)
    return kError_Interrupt;

  return DSWriteToSecBuffer(wrote, pBuffer, m_data_size);
}

Error
DSoundCardPMO::
DSWriteToSecBuffer(int32& wrote, void *pBuffer, int32 length)
{
  HRESULT   hResult;
  LPVOID    ptr1;
  DWORD     dwBytes1;
  LPVOID    ptr2;
  DWORD     dwBytes2;
  Error     result  = kError_UnknownErr;
  unsigned  iRead;

  iRead = m_data_size;
  result = ((EventBuffer *)m_pInputBuffer)->BeginRead(pBuffer, iRead);
  if (result != kError_NoErr)
    return result;

  // grab the write semaphore
  m_pDSWriteSem->Wait();

  // get a lock to a memory region to write to
  hResult = m_DSBufferManager.pDSSecondaryBuffer->Lock( m_DSBufferManager.dwWritePtr,
                                                        length,
                                                        &ptr1,
                                                        &dwBytes1,
                                                        &ptr2,                                                                                                          &dwBytes2,
                                                        0);
  if (hResult == DSERR_BUFFERLOST)
  {
    hResult = m_DSBufferManager.pDSSecondaryBuffer->Restore();
    if (FAILED(hResult))
    {
      wrote = 0;
      m_pDSWriteSem->Signal();
      m_pContext->log->Log(LogOutput, "Exiting DSWriteToSecBuffer with DSound error\n");
      return result;
    }
    hResult = m_DSBufferManager.pDSSecondaryBuffer->Lock(   m_DSBufferManager.dwWritePtr,
                                                            length,
                                                            &ptr1,
                                                            &dwBytes1,
                                                            &ptr2,
                                                            &dwBytes2,
                                                            0);
  }

  if (FAILED(hResult))
  {
    wrote = 0;
    m_pDSWriteSem->Signal();
    m_pContext->log->Log(LogOutput, "Exiting DSWriteToSecBuffer with DSound error\n");
    return result;
  }

  // copy the samples
  if (pBuffer)
    memcpy(ptr1, pBuffer, dwBytes1);
  else
    memset(ptr1, 0, dwBytes1);

  m_DSBufferManager.dwWritePtr += dwBytes1;
  if (m_DSBufferManager.dwWritePtr >= m_DSBufferManager.dwBufferSize)
  {
    m_DSBufferManager.dwWritePtr = 0;
  }
  if (ptr2)
  {
    if (pBuffer)
      memcpy(ptr2, (unsigned char *)pBuffer + dwBytes1, dwBytes2);
    else
      memset(ptr2, 0, dwBytes2);
    m_DSBufferManager.dwWritePtr = dwBytes2;
  }

  // unlock the memory region
  m_DSBufferManager.pDSSecondaryBuffer->Unlock( ptr1, dwBytes1, ptr2, dwBytes2);
  if (FAILED(hResult))
  {
    wrote = 0;
    m_pDSWriteSem->Signal();
    m_pContext->log->Log(LogOutput, "Exiting DSWriteToSecBuffer with DSound error\n");
    return result;
  }

  wrote = length;
  // release the write semaphore
  m_pDSWriteSem->Signal();

  result = ((EventBuffer *)m_pInputBuffer)->EndRead(iRead);
  if (result != kError_NoErr)
    return result;

  return kError_NoErr;
}

int32
DSoundCardPMO::
DSMonitorBufferState()
{
  DWORD     dwBuffered;
  DSState   new_state;
  int32     wrote;
  DWORD     dwReadPos;
  DWORD     dwWritePos;

  if (m_DSBufferManager.pDSSecondaryBuffer == NULL)
    return -1;

  m_pDSBufferSem->Wait();

  new_state = m_DSBufferManager.state;

  m_DSBufferManager.pDSSecondaryBuffer->GetCurrentPosition( &dwReadPos,
                                                            &dwWritePos);
  if (m_DSBufferManager.dwWritePtr >= dwReadPos)
  {
    dwBuffered = m_DSBufferManager.dwWritePtr - dwReadPos;
  }
  else
  {
    dwBuffered = (m_DSBufferManager.dwBufferSize - dwReadPos) +
                  m_DSBufferManager.dwWritePtr;
  }
  if (dwReadPos >= m_DSBufferManager.dwOldReadPos)
  {
    m_iTotalBytesWritten += dwReadPos - m_DSBufferManager.dwOldReadPos;
  }
  else
  {
    m_iTotalBytesWritten +=  (m_DSBufferManager.dwBufferSize - m_DSBufferManager.dwOldReadPos) +
                              dwReadPos;
  }
  m_DSBufferManager.dwOldReadPos  = dwReadPos;

  switch(m_DSBufferManager.state)
  {
    case UNDERFLOW:
//      m_pContext->log->Log(LogOutput, "UNDERFLOW    : %d\n", dwBuffered*100/m_DSBufferManager.dwBufferSize);
      if (dwBuffered > m_DSBufferManager.dwTrigger)
      {
        if (dwBuffered >= m_DSBufferManager.dwBufferSize)
        {
          new_state = OVERFLOW;
        }
        else
        {
          new_state = NORMAL;
        }

        // restart the buffer
        if (m_bLMCsaidToPlay && m_bIsBufferEmptyNow)
        m_DSBufferManager.pDSSecondaryBuffer->Play( 0, 0, DSBPLAY_LOOPING);

        m_bIsBufferEmptyNow = false;
      }
      break;

    case NORMAL:
//      m_pContext->log->Log(LogOutput, "NORMAL       : %d\n", dwBuffered*100/m_DSBufferManager.dwBufferSize);
      if (dwBuffered < m_DSBufferManager.dwUnderflow)
      {
        new_state = STOPPING;

        DSWriteToSecBuffer(wrote, NULL, m_DSBufferManager.dwZerofill);

      }
      else if (dwBuffered >= m_DSBufferManager.dwOverflow)
      {
        new_state = OVERFLOW;
      }
      else
      {
        new_state = NORMAL;
      }
    break;

    case OVERFLOW:
//      m_pContext->log->Log(LogOutput, "OVERFLOW     : %d\n", dwBuffered*100/m_DSBufferManager.dwBufferSize);
      if (dwBuffered < m_DSBufferManager.dwUnderflow)
      {
        new_state = STOPPING;
        DSWriteToSecBuffer( wrote, NULL, m_DSBufferManager.dwZerofill);
      }
      else if (dwBuffered < m_DSBufferManager.dwOverflow)
      {
        new_state = NORMAL;
      }
      break;

    case STOPPING:
//      m_pContext->log->Log(LogOutput, "STOPPING     : %d\n", dwBuffered*100/m_DSBufferManager.dwBufferSize);
      if (dwBuffered < m_DSBufferManager.dwZerofill)
      {
        Reset(true);
        new_state = UNDERFLOW;
      }
      break;
  }

  m_DSBufferManager.state = new_state;

  m_pDSBufferSem->Signal();

  return new_state;
}

void
DSoundCardPMO::
DSReset()
{
  if (m_DSBufferManager.pDSSecondaryBuffer)
  {
    m_DSBufferManager.pDSSecondaryBuffer->Stop();
  }
}

void
DSoundCardPMO::
DSClear()
{
  HRESULT hResult;
  LPVOID  ptr;
  DWORD dwBytes;

  // grab the write semaphore
  m_pDSWriteSem->Wait();

  // init the fields
  m_DSBufferManager.dwWritePtr    = 0;
  m_DSBufferManager.dwOldReadPos  = 0;
  m_DSBufferManager.state         = UNDERFLOW;

  // reset the play cursor
  m_DSBufferManager.pDSSecondaryBuffer->SetCurrentPosition(0);

  // write zeros into secondary buffer
  hResult = m_DSBufferManager.pDSSecondaryBuffer->Lock( 0,
                                                        m_DSBufferManager.dwBufferSize,
                                                        &ptr,
                                                        &dwBytes,
                                                        NULL,
                                                        NULL,
                                                        0);
  if (SUCCEEDED(hResult))
  {
    memset(ptr, 0, m_DSBufferManager.dwBufferSize);
    m_DSBufferManager.pDSSecondaryBuffer->Unlock(   ptr,
                                                    dwBytes,
                                                    NULL,
                                                    0);
  }
  m_bIsBufferEmptyNow = true;

  // grab the write semaphore
  m_pDSWriteSem->Signal();
}

void
DSoundCardPMO::
StartWorkerThread(void *pVoidBuffer)
{
  ((DSoundCardPMO*)pVoidBuffer)->WorkerThread();
}

void
DSoundCardPMO::
WorkerThread(void)
{
   void*   pBuffer;
   Error   eErr;
   Event*  pEvent;
   int32 iValue;

   // 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 = GetData(pBuffer);
          if (eErr == kError_EndOfStream || eErr == kError_Interrupt)
             break;


          if (eErr == kError_NoDataAvail)
          {
              m_pLmc->Wake();
              CheckForBufferUp();
    
              WasteTime();
              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)->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) 
              {
                  delete pEvent;
                  m_pTarget->AcceptEvent(new Event(INFO_DoneOutputting));
                  
                  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);
      m_pLmc->Wake();
      UpdateBufferStatus();
  }

  m_pContext->log->Log(LogOutput, "PMO: Soundcard thread exiting\n");
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -