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

📄 dsoundcardpmo.cpp

📁 vc++ mp3 源码下载 使用vc写的mp3 播放器
💻 CPP
📖 第 1 页 / 共 2 页
字号:
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->GetDecoderThreadPriority(&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();
    
              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 + -