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

📄 alsapmo.cpp

📁 FreeAMP(MP3播放)程序源代码-用来研究MP3解码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
    if (err < 0)
    {
        ReportError("Cannot initialized audio device.");
        return (Error)pmoError_DeviceOpenFailed;
    }
    err = snd_pcm_channel_prepare(m_handle, SND_PCM_CHANNEL_PLAYBACK);
    if (err < 0)
    {
        ReportError("Cannot initialized audio device.");
        return (Error)pmoError_DeviceOpenFailed;
    }

    memcpy(myInfo, info, sizeof(OutputInfo));

    snd_pcm_channel_setup_t aInfo;
    aInfo.channel = SND_PCM_CHANNEL_PLAYBACK;
    err = snd_pcm_channel_setup(m_handle,&aInfo);
    if (err < 0)
    {
        ReportError("Cannot initialized audio device.");
        return (Error)pmoError_DeviceOpenFailed;
    }

    m_iOutputBufferSize = aInfo.buf.block.frag_size * aInfo.buf.block.frags;
    m_iBytesPerSample = info->number_of_channels * (info->bits_per_sample / 8);



    m_properlyInitialized = true;
    return kError_NoErr;
}

Error AlsaPMO::Reset(bool user_stop) {

    if (user_stop) 
        snd_pcm_playback_drain(m_handle);
    else
        snd_pcm_playback_flush(m_handle);

    snd_pcm_playback_prepare(m_handle);

    return kError_NoErr;
}

void AlsaPMO::Pause(void)
{
    m_iBaseTime = -1;

    PhysicalMediaOutput::Pause();
}

bool AlsaPMO::WaitForDrain(void)
{
   snd_pcm_channel_status_t ainfo;

   for(; !m_bExit && !m_bPause; )
   {
       ainfo.channel = SND_PCM_CHANNEL_PLAYBACK;
       snd_pcm_channel_status(m_handle,&ainfo);

       if (ainfo.underrun || ainfo.status == SND_PCM_STATUS_UNDERRUN)
       {
           return true;
       }
       WasteTime();
   }

   return false;
} 

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

   if (m_iBaseTime < 0)
   {
       m_iBaseTime = (pEvent->GetFrameNumber() * 
                      myInfo->samples_per_frame) / 
                      myInfo->samples_per_second;
   }

   ainfo.channel = SND_PCM_CHANNEL_PLAYBACK;
   snd_pcm_channel_status(m_handle,&ainfo);

   iTotalTime = ainfo.scount / (m_iBytesPerSample * myInfo->samples_per_second);
   iTotalTime = (iTotalTime + m_iBaseTime) % 86400;

   hours = iTotalTime / 3600;
   minutes = (iTotalTime / 60) % 60;
   seconds = iTotalTime % 60;

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

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

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

void AlsaPMO::WorkerThread(void)
{
   void                      *pBuffer;
   Error                      eErr;
   int                        iRet = -1;
   Event                     *pEvent;
   snd_pcm_channel_status_t  ainfo;

   // Don't do anything until resume is called.
   m_pPauseSem->Wait();

   // Sleep for a pre buffer period
   PreBuffer();

   // The following should be abstracted out into the general thread
   // classes:
#ifdef __linux__
   struct sched_param sParam;

   sParam.sched_priority = sched_get_priority_max(SCHED_OTHER);
   pthread_setschedparam(pthread_self(), SCHED_OTHER, &sParam);
#endif

   ainfo.channel = SND_PCM_CHANNEL_PLAYBACK;
   for(; !m_bExit;)
   {
      if (m_bPause)
      {
          m_pPauseSem->Wait();
          continue;
      }

      // Loop until we get an Init event from the LMC
      if (!m_properlyInitialized)
      {
          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(;;)
      {
          eErr = ((EventBuffer *)m_pInputBuffer)->BeginRead(pBuffer, 
                                                             m_iDataSize);
          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)->PeekEvent();
			  if (pEvent == NULL)
				  continue;
                  
              if (pEvent->Type() == PMO_Quit && 
                  ((EventBuffer *)m_pInputBuffer)->GetNumBytesInBuffer() > 0) 
              {
                  if (WaitForDrain())
				  {
                     Reset(true);
                     m_pTarget->AcceptEvent(new Event(INFO_DoneOutputting));
                     return;
				  }
                  continue;
              }
              
              pEvent = ((EventBuffer *)m_pInputBuffer)->GetEvent();

              if (pEvent->Type() == PMO_Init)
                  Init(((PMOInitEvent *)pEvent)->GetInfo());
    
              if (pEvent->Type() == PMO_Reset)
                  Reset(false);
    
              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);
              break;
          }
          break;
      }

      // Now write the block to the audio device. If the block doesn't
      // all fit, pause and loop until the entire block has been played.
      // This loop could be written using non-blocking io...
      for(;!m_bExit && !m_bPause;)
      {
          iRet = snd_pcm_write(m_handle,pBuffer,m_iDataSize);
          if (iRet == -EAGAIN)
          {
               CheckForBufferUp();
               WasteTime();
               continue;
          }
          if (iRet == -EIO)
          {
               snd_pcm_channel_prepare(m_handle, SND_PCM_CHANNEL_PLAYBACK);
               continue;
          }
          break;
      }
      if (m_bExit)
      {
          m_pInputBuffer->EndRead(0);
          return;
      }

      if (m_bPause)
      {
         if (iRet == -EAGAIN)
             m_pInputBuffer->EndRead(0);
         else
         {
             m_pInputBuffer->EndRead(iRet);
             UpdateBufferStatus();
         }
         continue;   
      }

      if (iRet < 0)
      {
         m_pInputBuffer->EndRead(0);
         ReportError("Could not write sound data to the soundcard.");
         m_pContext->log->Error("Failed to write to the soundcard: %s\n", 
                               strerror(errno));
         break;
      }

      m_pInputBuffer->EndRead(iRet);
      m_pLmc->Wake();
      UpdateBufferStatus();
   }
}

⌨️ 快捷键说明

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