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

📄 wavethread.cpp

📁 ppciaxclient softphone
💻 CPP
📖 第 1 页 / 共 2 页
字号:
   m_pWaveHeaderArray         = NULL;
   m_dwActiveThreadPriority   = THREAD_PRIORITY_NORMAL;
   m_wBufferCount             = 0;
   m_dwSingleBufferSize       = 0;
   m_dwBufferSize             = 0;
   m_dwCopyBufferBytes        = 0;
   m_pCopyBufferPos           = NULL;
   m_bPause                   = FALSE;
   m_dwUsedWaveOutBuffers     = 0;
   m_wNextCopyBuffer          = 0;

   ZeroMemory(&m_wfx, sizeof(m_wfx));

   InitializeCriticalSection(&m_critSecRtp);

   m_hEventKill = CreateEvent(NULL, FALSE, FALSE, NULL);
}


CWaveOutThread::~CWaveOutThread()
{
   // Stop the thread processing
   StopThread();

   // Delete the critical section
	DeleteCriticalSection(&m_critSecRtp);

   // Destroy events
   CloseHandle(m_hEventKill);
}


// Output initialization
BOOL CWaveOutThread::Init(cbWaveOut pcbWaveOut,          // Callback function for event notifications, NULL = No callback!
                          DWORD dwActiveThreadPriority,  // Thread Priority for this thread, if OUTPUT is active
                          WORD wBufferCount,             // Count of buffers to use
                          DWORD dwSingleBufferSize,      // Size of a single buffer in bytes (eg. 44100Hz Mono 16bit: 10ms = 882bytes)
                          WORD wChannels,                // Mono = 1; Stereo = 2
                          DWORD dwSamplesPerSec,         // 8000Hz/11025Hz/22050Hz/44100Hz
                          WORD wBitsPerSample)           // 8bit/16bit
{
   if (
       ( m_bInitialized
       ) ||
       ( dwActiveThreadPriority > THREAD_PRIORITY_IDLE
       ) ||
       ( wBufferCount < INTERNAL_WAVEOUT_BUFFER_COUNT
       ) ||
       ( dwSingleBufferSize < 80
       ) ||
       ( wChannels < 1
       ) ||
       ( wChannels > 2
       ) ||
       ( 
        ( wBitsPerSample != 8
        ) && 
        ( wBitsPerSample != 16
        )
       ) ||
       ( 
        ( dwSamplesPerSec != 8000
        ) && 
        ( dwSamplesPerSec != 11025
        ) && 
        ( dwSamplesPerSec != 22050  
        ) && 
        ( dwSamplesPerSec != 44100
        )
       )
      )
   {
      return FALSE;
   }

   m_pcbWaveOut               = pcbWaveOut;
   m_dwActiveThreadPriority   = dwActiveThreadPriority;
   m_wBufferCount             = wBufferCount;
   m_dwSingleBufferSize       = dwSingleBufferSize;

   m_wfx.cbSize               = 0;
   m_wfx.wFormatTag           = WAVE_FORMAT_PCM;
   m_wfx.nChannels            = wChannels;
   m_wfx.nSamplesPerSec       = dwSamplesPerSec;
   m_wfx.nBlockAlign          = (wBitsPerSample * wChannels) / 8;
   m_wfx.nAvgBytesPerSec      = dwSamplesPerSec * m_wfx.nBlockAlign;
   m_wfx.wBitsPerSample       = wBitsPerSample;

   m_dwBufferSize = wBufferCount * dwSingleBufferSize;

   m_bInitialized = TRUE;

   return TRUE;
}


// Start sound output
BOOL CWaveOutThread::StartThread()
{
   UINT           id;
   WORD           i;

   if ((m_thread) || (!m_bInitialized))
   {
      return FALSE;
   }

   m_dwUsedWaveOutBuffers  = 0;
   m_wNextCopyBuffer       = 0;

   // Start the thread
   m_thread = CreateThread(NULL, 
                           0, 
                           ThreadProc, 
                           (void*)this,
                           0, 
                           &m_threadId);

   if (m_thread)
   {
      DWORD dwExitCode;
      
      if (GetExitCodeThread(m_thread, &dwExitCode))
      {
         if (dwExitCode != STILL_ACTIVE)
         {
            return FALSE;
         }
      }

      if (m_hWaveOut == NULL)
      {
         m_pWaveOutBuffer = new unsigned char[m_dwSingleBufferSize * INTERNAL_WAVEOUT_BUFFER_COUNT];

         if (m_pWaveOutBuffer)
         {
            ZeroMemory(m_pWaveOutBuffer, m_dwSingleBufferSize * INTERNAL_WAVEOUT_BUFFER_COUNT);

            m_pWaveCopyBuffer = new unsigned char[m_dwBufferSize];

            if (m_pWaveCopyBuffer)
            {
               ZeroMemory(m_pWaveCopyBuffer, m_dwBufferSize);

               m_pWaveHeaderArray = new WAVEHDR[INTERNAL_WAVEOUT_BUFFER_COUNT];

               if (m_pWaveHeaderArray)
               {
                  ZeroMemory(m_pWaveHeaderArray, INTERNAL_WAVEOUT_BUFFER_COUNT * sizeof(WAVEHDR));

                  for (id = 0; id < waveOutGetNumDevs(); id++) 
                  {
	                  if (waveOutOpen(&m_hWaveOut, id, &m_wfx, m_threadId, (DWORD)this, CALLBACK_THREAD) == MMSYSERR_NOERROR) 
                     {
                        waveOutPause(m_hWaveOut);

                        for (i=0 ; i<INTERNAL_WAVEOUT_BUFFER_COUNT ; i++)
                        {
                           m_dwUsedWaveOutBuffers |= (1 << i);
                        }

                        ResetBuffer();

                        m_bPause = TRUE;

                        return TRUE;
	                  }
                  }
               }

               delete m_pWaveCopyBuffer;
               m_pWaveCopyBuffer = NULL;
            }

            delete m_pWaveOutBuffer;
            m_pWaveOutBuffer = NULL;
         }
      }
   }

   StopThread();

   return FALSE;
}


// Stop sound output
BOOL CWaveOutThread::StopThread()
{
   WORD i;

   if (m_thread == NULL)
   {
      return FALSE;
   }

   SetThreadPriority(m_thread, THREAD_PRIORITY_NORMAL);

   SetEvent(m_hEventKill);

   if (m_hWaveOut)
   {
      waveOutPause(m_hWaveOut);
   }

   // This is ugly, wait for 10 seconds, then kill the thread
   DWORD res = WaitForSingleObject(m_thread, 10000);

   if (res == WAIT_TIMEOUT)
   {
      if (m_thread)
      {
         // OK, do it the hard way
         TerminateThread(m_thread, 0);

         CloseHandle(m_thread);

         m_thread = NULL;
      }
   }

   if (m_hWaveOut)
   {
      waveOutReset(m_hWaveOut);

      if (m_pWaveHeaderArray)
      {
         for (i=0 ; i<m_wBufferCount ; i++)
         {
            waveOutUnprepareHeader(m_hWaveOut, &m_pWaveHeaderArray[i], sizeof(WAVEHDR));
         }
      }

      waveOutClose(m_hWaveOut);
      m_hWaveOut = NULL;
   }

   if (m_pWaveOutBuffer)
   {
      delete m_pWaveOutBuffer;
      m_pWaveOutBuffer = NULL;
   }

   if (m_pWaveCopyBuffer)
   {
      delete m_pWaveCopyBuffer;
      m_pWaveCopyBuffer = NULL;
   }

   if (m_pWaveHeaderArray)
   {
      delete m_pWaveHeaderArray;
      m_pWaveHeaderArray = NULL;
   }

   return TRUE;
}


// Clear the buffer
void CWaveOutThread::ResetBuffer()
{
   EnterCriticalSection(&m_critSecRtp);

   m_pCopyBufferPos     = m_pWaveCopyBuffer;
   m_dwCopyBufferBytes  = 0;
   m_wNextCopyBuffer    = 0;

   LeaveCriticalSection(&m_critSecRtp);
}


// Get the size of the needed buffer for one second of data
DWORD CWaveOutThread::GetBytesPerSecond()
{
   if (m_bInitialized)
   {
      return m_wfx.nAvgBytesPerSec;
   }

   return 0;
}


// Get the current length of data in the buffer
DWORD CWaveOutThread::GetDataLen()
{
   DWORD dwBytes;
   
   EnterCriticalSection(&m_critSecRtp);

   dwBytes = m_dwCopyBufferBytes;
   
   LeaveCriticalSection(&m_critSecRtp);

   return dwBytes;
}


// Play sound data
BOOL CWaveOutThread::WriteData(unsigned char* pBuffer, // Data will be copied from this buffer
                               DWORD dwCount)          // Count of bytes to copy
{
   int i, iLastIndex;

   EnterCriticalSection(&m_critSecRtp);

   if (
       ( pBuffer == NULL
       ) || 
       ( m_dwCopyBufferBytes + dwCount > m_dwBufferSize
       )
      )
   {
      LeaveCriticalSection(&m_critSecRtp);

      return FALSE;
   }

   if (m_pCopyBufferPos + dwCount > m_pWaveCopyBuffer + m_dwBufferSize)
   {
      memcpy(m_pCopyBufferPos,
             pBuffer, 
             m_pWaveCopyBuffer + m_dwBufferSize - m_pCopyBufferPos);
      pBuffer += m_pWaveCopyBuffer + m_dwBufferSize - m_pCopyBufferPos;
      memcpy(m_pWaveCopyBuffer, 
             pBuffer, 
             m_pCopyBufferPos + dwCount - (m_pWaveCopyBuffer + m_dwBufferSize));
      m_pCopyBufferPos = m_pWaveCopyBuffer + ((m_pCopyBufferPos + dwCount) - (m_pWaveCopyBuffer + m_dwBufferSize));
   }
   else
   {
      memcpy(m_pCopyBufferPos, pBuffer, dwCount);
      m_pCopyBufferPos += dwCount;
   }

   m_dwCopyBufferBytes += dwCount;

   while (m_dwCopyBufferBytes >= m_dwSingleBufferSize)
   {
      iLastIndex = -1;

      for (i=INTERNAL_WAVEOUT_BUFFER_COUNT-1 ; i>=0; i--)
      {
         if (m_dwUsedWaveOutBuffers & (1 << i))
         {
            iLastIndex = i;
         }
         else
         {
            if (iLastIndex != -1)
            {
               break;
            }
         }
      }

      if (iLastIndex != -1)
      {
         memcpy(m_pWaveOutBuffer + iLastIndex * m_dwSingleBufferSize,
                m_pWaveCopyBuffer + m_wNextCopyBuffer * m_dwSingleBufferSize,
                m_dwSingleBufferSize);
         
         m_pWaveHeaderArray[iLastIndex].dwBufferLength = m_dwSingleBufferSize;
         m_pWaveHeaderArray[iLastIndex].lpData = (char*)m_pWaveOutBuffer + iLastIndex * m_dwSingleBufferSize;
         m_pWaveHeaderArray[iLastIndex].dwUser = iLastIndex;

         waveOutPrepareHeader(m_hWaveOut, &m_pWaveHeaderArray[iLastIndex], sizeof(WAVEHDR));

         waveOutWrite(m_hWaveOut, &m_pWaveHeaderArray[iLastIndex], sizeof(WAVEHDR));

         m_dwCopyBufferBytes     -= m_dwSingleBufferSize;
         m_wNextCopyBuffer++;
         m_wNextCopyBuffer       %= m_wBufferCount;
         m_dwUsedWaveOutBuffers  ^= (1 << iLastIndex);

         if ((m_bPause) && (m_dwUsedWaveOutBuffers == 0))
         {
            SetThreadPriority(m_thread, m_dwActiveThreadPriority);

            waveOutRestart(m_hWaveOut);

            m_bPause = FALSE;
         }
      }
      else
      {
         break;
      }
   }

   LeaveCriticalSection(&m_critSecRtp);

   return TRUE;
}


// Handles MM-API for sound output
DWORD WINAPI CWaveOutThread::ThreadProc(LPVOID lpParameter)
{
   CWaveOutThread* pWaveOut   = (CWaveOutThread*)lpParameter;
   MSG            msg;
   DWORD          dwWait      = 0;
   DWORD          dwUser      = 0;
   WAVEHDR        *pWaveHdr   = NULL;
   WAVE_OUT_EVENT event;

   if (pWaveOut == NULL)
   {
      return -1;
   }

	while ((dwWait = WaitForSingleObject(pWaveOut->m_hEventKill, 5)) != 0)
   {
      // Handle MMAPI wave capturing thread messages
      while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
      {
         switch (msg.message)
         {
            case MM_WOM_DONE:
         	   EnterCriticalSection(&pWaveOut->m_critSecRtp);

               event = WAVE_OUT_EVENT_BUFFER_PLAYED;

               pWaveHdr = (WAVEHDR*)msg.lParam;

               // Unprepare header, initialize with the next buffer position, prepare the header 
               //  again and add it to the wave capture device.
               if (pWaveHdr)
               {
                  waveOutUnprepareHeader(pWaveOut->m_hWaveOut, pWaveHdr, sizeof(WAVEHDR));

                  dwUser = pWaveHdr->dwUser;

                  ZeroMemory(pWaveHdr, sizeof(WAVEHDR));

                  if (pWaveOut->m_dwCopyBufferBytes >= pWaveOut->m_dwBufferSize)
                  {
                     memcpy(pWaveOut->m_pWaveOutBuffer + dwUser * pWaveOut->m_dwSingleBufferSize,
                            pWaveOut->m_pWaveCopyBuffer + pWaveOut->m_wNextCopyBuffer * pWaveOut->m_dwSingleBufferSize,
                            pWaveOut->m_dwSingleBufferSize);
         
                     pWaveOut->m_pWaveHeaderArray[dwUser].dwBufferLength = pWaveOut->m_dwSingleBufferSize;
                     pWaveOut->m_pWaveHeaderArray[dwUser].lpData = (char*)pWaveOut->m_pWaveOutBuffer + dwUser * pWaveOut->m_dwSingleBufferSize;
                     pWaveOut->m_pWaveHeaderArray[dwUser].dwUser = dwUser;

                     waveOutPrepareHeader(pWaveOut->m_hWaveOut, &pWaveOut->m_pWaveHeaderArray[dwUser], sizeof(WAVEHDR));

                     waveOutWrite(pWaveOut->m_hWaveOut, &pWaveOut->m_pWaveHeaderArray[dwUser], sizeof(WAVEHDR));

                     pWaveOut->m_dwCopyBufferBytes    -= pWaveOut->m_dwSingleBufferSize;
                     pWaveOut->m_wNextCopyBuffer++;
                     pWaveOut->m_wNextCopyBuffer      %= pWaveOut->m_wBufferCount;
                  }
                  else
                  {
                     pWaveOut->m_dwUsedWaveOutBuffers |= (1 << dwUser);

                     if (0xffffffff >> (32 - INTERNAL_WAVEOUT_BUFFER_COUNT) == pWaveOut->m_dwUsedWaveOutBuffers)
                     {
                        SetThreadPriority(pWaveOut->m_thread, THREAD_PRIORITY_NORMAL);

                        waveOutPause(pWaveOut->m_hWaveOut);

                        pWaveOut->m_bPause = TRUE;

                        event = WAVE_OUT_EVENT_BUFFER_EMPTY;
                     }
                  }
               }

         	   LeaveCriticalSection(&pWaveOut->m_critSecRtp);

               if ((pWaveOut->m_pcbWaveOut != NULL) && (event != WAVE_OUT_EVENT_NONE))
               {
                  (pWaveOut->m_pcbWaveOut)(event);
               }
               break;
            default:
               break;
         }
      }
   }

   CloseHandle(pWaveOut->m_thread);
   pWaveOut->m_thread = NULL;

   return 0;
}


⌨️ 快捷键说明

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