sound.cxx
上传用户:hzhsqp
上传日期:2007-01-06
资源大小:1600k
文件大小:31k
源码类别:

IP电话/视频会议

开发平台:

Visual C++

  1. /*
  2.  * sound.cxx
  3.  *
  4.  * Implementation of sound classes for Win32
  5.  *
  6.  * Portable Windows Library
  7.  *
  8.  * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
  9.  *
  10.  * The contents of this file are subject to the Mozilla Public License
  11.  * Version 1.0 (the "License"); you may not use this file except in
  12.  * compliance with the License. You may obtain a copy of the License at
  13.  * http://www.mozilla.org/MPL/
  14.  *
  15.  * Software distributed under the License is distributed on an "AS IS"
  16.  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  17.  * the License for the specific language governing rights and limitations
  18.  * under the License.
  19.  *
  20.  * The Original Code is Portable Windows Library.
  21.  *
  22.  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
  23.  *
  24.  * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
  25.  * All Rights Reserved.
  26.  *
  27.  * Contributor(s): ______________________________________.
  28.  *
  29.  * $Log: sound.cxx,v $
  30.  * Revision 1.15  2000/07/04 04:30:47  robertj
  31.  * Fixed shutdown issues with buffers in use, again.
  32.  *
  33.  * Revision 1.14  2000/07/01 09:39:31  robertj
  34.  * Fixed shutdown issues with buffers in use.
  35.  *
  36.  * Revision 1.13  2000/06/29 00:39:29  robertj
  37.  * Fixed bug when PWaveFormat is assigned to itself.
  38.  *
  39.  * Revision 1.12  2000/05/22 07:17:50  robertj
  40.  * Fixed missing initialisation of format data block in Win32 PSound::Load().
  41.  *
  42.  * Revision 1.11  2000/05/01 05:59:11  robertj
  43.  * Added mutex to PSoundChannel buffer structure.
  44.  *
  45.  * Revision 1.10  2000/03/04 10:15:32  robertj
  46.  * Added simple play functions for sound files.
  47.  *
  48.  * Revision 1.9  2000/02/17 11:33:33  robertj
  49.  * Changed PSoundChannel::Write so blocks instead of error if no buffers available.
  50.  *
  51.  * Revision 1.8  1999/10/09 01:22:07  robertj
  52.  * Fixed error display for sound channels.
  53.  *
  54.  * Revision 1.7  1999/09/23 04:28:44  robertj
  55.  * Allowed some Win32 only access to wave format in sound channel
  56.  *
  57.  * Revision 1.6  1999/07/08 08:39:53  robertj
  58.  * Fixed bug when breaking block by closing the PSoundChannel in other thread.
  59.  *
  60.  * Revision 1.5  1999/06/24 14:01:25  robertj
  61.  * Fixed bug in not returning correct default recorder (waveIn) device.
  62.  *
  63.  * Revision 1.4  1999/06/07 01:36:28  robertj
  64.  * Fixed incorrect;ly set block alignment in sound structure.
  65.  *
  66.  * Revision 1.3  1999/05/28 14:04:51  robertj
  67.  * Added function to get default audio device.
  68.  *
  69.  * Revision 1.2  1999/02/22 10:15:15  robertj
  70.  * Sound driver interface implementation to Linux OSS specification.
  71.  *
  72.  * Revision 1.1  1999/02/16 06:02:07  robertj
  73.  * Major implementation to Linux OSS model
  74.  *
  75.  */
  76. #include <ptlib.h>
  77. #include <mmsystem.h>
  78. #include <process.h>
  79. class PMultiMediaFile
  80. {
  81.   public:
  82.     PMultiMediaFile();
  83.     ~PMultiMediaFile();
  84.     BOOL CreateWaveFile(const PFilePath & filename,
  85.                         const PWaveFormat & waveFormat,
  86.                         DWORD dataSize);
  87.     BOOL OpenWaveFile(const PFilePath & filename,
  88.                       PWaveFormat & waveFormat,
  89.                       DWORD & dataSize);
  90.     BOOL Open(const PFilePath & filename, DWORD dwOpenFlags, LPMMIOINFO lpmmioinfo = NULL);
  91.     BOOL Close(UINT wFlags = 0);
  92.     BOOL Ascend(MMCKINFO & ckinfo, UINT wFlags = 0);
  93.     BOOL Descend(UINT wFlags, MMCKINFO & ckinfo, LPMMCKINFO lpckParent = NULL);
  94.     BOOL Read(void * data, PINDEX len);
  95.     BOOL CreateChunk(MMCKINFO & ckinfo, UINT wFlags = 0);
  96.     BOOL Write(const void * data, PINDEX len);
  97.     DWORD GetLastError() const { return dwLastError; }
  98.   protected:
  99.     HMMIO hmmio;
  100.     DWORD dwLastError;
  101. };
  102. #define new PNEW
  103. ///////////////////////////////////////////////////////////////////////////////
  104. PMultiMediaFile::PMultiMediaFile()
  105. {
  106.   hmmio = NULL;
  107. }
  108. PMultiMediaFile::~PMultiMediaFile()
  109. {
  110.   Close();
  111. }
  112. BOOL PMultiMediaFile::CreateWaveFile(const PFilePath & filename,
  113.                                      const PWaveFormat & waveFormat,
  114.                                      DWORD dataSize)
  115. {
  116.   if (!Open(filename, MMIO_CREATE|MMIO_WRITE))
  117.     return FALSE;
  118.   MMCKINFO mmChunk;
  119.   mmChunk.fccType = mmioFOURCC('W', 'A', 'V', 'E');
  120.   mmChunk.cksize = 4 + // Form type
  121.                    4 + sizeof(DWORD) + waveFormat.GetSize() + // fmt chunk
  122.                    4 + sizeof(DWORD) + dataSize;              // data chunk
  123.   // Create a RIFF chunk
  124.   if (!CreateChunk(mmChunk, MMIO_CREATERIFF))
  125.     return FALSE;
  126.   // Save the format sub-chunk
  127.   mmChunk.ckid = mmioFOURCC('f', 'm', 't', ' ');
  128.   mmChunk.cksize = waveFormat.GetSize();
  129.   if (!CreateChunk(mmChunk))
  130.     return FALSE;
  131.   if (!Write(waveFormat, waveFormat.GetSize()))
  132.     return FALSE;
  133.   // Save the data sub-chunk
  134.   mmChunk.ckid = mmioFOURCC('d', 'a', 't', 'a');
  135.   mmChunk.cksize = dataSize;
  136.   return CreateChunk(mmChunk);
  137. }
  138. BOOL PMultiMediaFile::OpenWaveFile(const PFilePath & filename,
  139.                                    PWaveFormat  & waveFormat,
  140.                                    DWORD & dataSize)
  141. {
  142.   // Open wave file
  143.   if (!Open(filename, MMIO_READ | MMIO_ALLOCBUF))
  144.     return FALSE;
  145.   MMCKINFO mmParentChunk, mmSubChunk;
  146.   dwLastError = MMSYSERR_NOERROR;
  147.   // Locate a 'RIFF' chunk with a 'WAVE' form type
  148.   mmParentChunk.fccType = mmioFOURCC('W', 'A', 'V', 'E');
  149.   if (!Descend(MMIO_FINDRIFF, mmParentChunk))
  150.     return FALSE;
  151.   // Find the format chunk
  152.   mmSubChunk.ckid = mmioFOURCC('f', 'm', 't', ' ');
  153.   if (!Descend(MMIO_FINDCHUNK, mmSubChunk, &mmParentChunk))
  154.     return FALSE;
  155.   // Get the size of the format chunk, allocate memory for it
  156.   if (!waveFormat.SetSize(mmSubChunk.cksize))
  157.     return FALSE;
  158.   // Read the format chunk
  159.   if (!Read(waveFormat.GetPointer(), waveFormat.GetSize()))
  160.     return FALSE;
  161.   // Ascend out of the format subchunk
  162.   Ascend(mmSubChunk);
  163.   // Find the data subchunk
  164.   mmSubChunk.ckid = mmioFOURCC('d', 'a', 't', 'a');
  165.   if (!Descend(MMIO_FINDCHUNK, mmSubChunk, &mmParentChunk))
  166.     return FALSE;
  167.   // Get the size of the data subchunk
  168.   if (mmSubChunk.cksize == 0) {
  169.     dwLastError = MMSYSERR_INVALPARAM;
  170.     return FALSE;
  171.   }
  172.   dataSize = mmSubChunk.cksize;
  173.   return TRUE;
  174. }
  175. BOOL PMultiMediaFile::Open(const PFilePath & filename,
  176.                           DWORD dwOpenFlags,
  177.                           LPMMIOINFO lpmmioinfo)
  178. {
  179.   MMIOINFO local_mmioinfo;
  180.   if (lpmmioinfo == NULL) {
  181.     lpmmioinfo = &local_mmioinfo;
  182.     memset(lpmmioinfo, 0, sizeof(local_mmioinfo));
  183.   }
  184.   hmmio = mmioOpen((char *)(const char *)filename, lpmmioinfo, dwOpenFlags);
  185.   dwLastError = lpmmioinfo->wErrorRet;
  186.   return hmmio != NULL;
  187. }
  188. BOOL PMultiMediaFile::Close(UINT wFlags)
  189. {
  190.   if (hmmio == NULL)
  191.     return FALSE;
  192.   mmioClose(hmmio, wFlags);
  193.   hmmio = NULL;
  194.   return TRUE;
  195. }
  196. BOOL PMultiMediaFile::Ascend(MMCKINFO & ckinfo, UINT wFlags)
  197. {
  198.   dwLastError = mmioAscend(hmmio, &ckinfo, wFlags);
  199.   return dwLastError == MMSYSERR_NOERROR;
  200. }
  201. BOOL PMultiMediaFile::Descend(UINT wFlags, MMCKINFO & ckinfo, LPMMCKINFO lpckParent)
  202. {
  203.   dwLastError = mmioDescend(hmmio, &ckinfo, lpckParent, wFlags);
  204.   return dwLastError == MMSYSERR_NOERROR;
  205. }
  206. BOOL PMultiMediaFile::Read(void * data, PINDEX len)
  207. {
  208.   return mmioRead(hmmio, (char *)data, len) == len;
  209. }
  210. BOOL PMultiMediaFile::CreateChunk(MMCKINFO & ckinfo, UINT wFlags)
  211. {
  212.   dwLastError = mmioCreateChunk(hmmio, &ckinfo, wFlags);
  213.   return dwLastError == MMSYSERR_NOERROR;
  214. }
  215. BOOL PMultiMediaFile::Write(const void * data, PINDEX len)
  216. {
  217.   return mmioWrite(hmmio, (char *)data, len) == len;
  218. }
  219. ///////////////////////////////////////////////////////////////////////////////
  220. PWaveFormat::PWaveFormat()
  221. {
  222.   size = 0;
  223.   waveFormat = NULL;
  224. }
  225. PWaveFormat::~PWaveFormat()
  226. {
  227.   if (waveFormat != NULL)
  228.     free(waveFormat);
  229. }
  230. PWaveFormat::PWaveFormat(const PWaveFormat & fmt)
  231. {
  232.   size = fmt.size;
  233.   waveFormat = (WAVEFORMATEX *)malloc(size);
  234.   PAssert(waveFormat != NULL, POutOfMemory);
  235.   memcpy(waveFormat, fmt.waveFormat, size);
  236. }
  237. PWaveFormat & PWaveFormat::operator=(const PWaveFormat & fmt)
  238. {
  239.   if (this == &fmt)
  240.     return *this;
  241.   if (waveFormat != NULL)
  242.     free(waveFormat);
  243.   size = fmt.size;
  244.   waveFormat = (WAVEFORMATEX *)malloc(size);
  245.   PAssert(waveFormat != NULL, POutOfMemory);
  246.   memcpy(waveFormat, fmt.waveFormat, size);
  247.   return *this;
  248. }
  249. void PWaveFormat::PrintOn(ostream & out) const
  250. {
  251.   if (waveFormat == NULL)
  252.     out << "<null>";
  253.   else {
  254.     out << waveFormat->wFormatTag << ','
  255.         << waveFormat->nChannels << ','
  256.         << waveFormat->nSamplesPerSec << ','
  257.         << waveFormat->nAvgBytesPerSec << ','
  258.         << waveFormat->nBlockAlign << ','
  259.         << waveFormat->wBitsPerSample;
  260.     if (waveFormat->cbSize > 0) {
  261.       out << hex << setfill('0');
  262.       const BYTE * ptr = (const BYTE *)&waveFormat[1];
  263.       for (PINDEX i = 0; i < waveFormat->cbSize; i++)
  264.         out << ',' << setw(2) << (unsigned)*ptr++;
  265.       out << dec << setfill(' ');
  266.     }
  267.   }
  268. }
  269. void PWaveFormat::ReadFrom(istream &)
  270. {
  271. }
  272. void PWaveFormat::SetFormat(unsigned numChannels,
  273.                             unsigned sampleRate,
  274.                             unsigned bitsPerSample)
  275. {
  276.   PAssert(numChannels == 1 || numChannels == 2, PInvalidParameter);
  277.   PAssert(bitsPerSample == 8 || bitsPerSample == 16, PInvalidParameter);
  278.   if (waveFormat != NULL)
  279.     free(waveFormat);
  280.   size = sizeof(WAVEFORMATEX);
  281.   waveFormat = (WAVEFORMATEX *)malloc(sizeof(WAVEFORMATEX));
  282.   PAssert(waveFormat != NULL, POutOfMemory);
  283.   waveFormat->wFormatTag = WAVE_FORMAT_PCM;
  284.   waveFormat->nChannels = (WORD)numChannels;
  285.   waveFormat->nSamplesPerSec = sampleRate;
  286.   waveFormat->wBitsPerSample = (WORD)bitsPerSample;
  287.   waveFormat->nBlockAlign = (WORD)(numChannels*(bitsPerSample+7)/8);
  288.   waveFormat->nAvgBytesPerSec = waveFormat->nSamplesPerSec*waveFormat->nBlockAlign;
  289.   waveFormat->cbSize = 0;
  290. }
  291. void PWaveFormat::SetFormat(const void * data, PINDEX size)
  292. {
  293.   SetSize(size);
  294.   memcpy(waveFormat, data, size);
  295. }
  296. BOOL PWaveFormat::SetSize(PINDEX sz)
  297. {
  298.   if (waveFormat != NULL)
  299.     free(waveFormat);
  300.   size = sz;
  301.   if (sz == 0)
  302.     waveFormat = NULL;
  303.   else {
  304.     waveFormat = (WAVEFORMATEX *)calloc(sz, 1);
  305.     waveFormat->cbSize = (WORD)(sz - sizeof(WAVEFORMATEX));
  306.   }
  307.   return waveFormat != NULL;
  308. }
  309. ///////////////////////////////////////////////////////////////////////////////
  310. PSound::PSound(unsigned channels,
  311.                unsigned samplesPerSecond,
  312.                unsigned bitsPerSample,
  313.                PINDEX   bufferSize,
  314.                const BYTE * buffer)
  315. {
  316.   encoding = 0;
  317.   numChannels = channels;
  318.   sampleRate = samplesPerSecond;
  319.   sampleSize = bitsPerSample;
  320.   SetSize(bufferSize);
  321.   if (buffer != NULL)
  322.     memcpy(GetPointer(), buffer, bufferSize);
  323. }
  324. PSound::PSound(const PFilePath & filename)
  325. {
  326.   encoding = 0;
  327.   numChannels = 1;
  328.   sampleRate = 8000;
  329.   sampleSize = 16;
  330.   Load(filename);
  331. }
  332. PSound & PSound::operator=(const PBYTEArray & data)
  333. {
  334.   PBYTEArray::operator=(data);
  335.   return *this;
  336. }
  337. void PSound::SetFormat(unsigned channels,
  338.                        unsigned samplesPerSecond,
  339.                        unsigned bitsPerSample)
  340. {
  341.   encoding = 0;
  342.   numChannels = channels;
  343.   sampleRate = samplesPerSecond;
  344.   sampleSize = bitsPerSample;
  345.   formatInfo.SetSize(0);
  346. }
  347. BOOL PSound::Load(const PFilePath & filename)
  348. {
  349.   // Open wave file
  350.   PMultiMediaFile mmio;
  351.   PWaveFormat waveFormat;
  352.   DWORD dataSize;
  353.   if (!mmio.OpenWaveFile(filename, waveFormat, dataSize)) {
  354.     dwLastError = mmio.GetLastError();
  355.     return FALSE;
  356.   }
  357.   encoding = waveFormat->wFormatTag;
  358.   numChannels = waveFormat->nChannels;
  359.   sampleRate = waveFormat->nSamplesPerSec;
  360.   sampleSize = waveFormat->wBitsPerSample;
  361.   if (encoding != 0) {
  362.     PINDEX formatSize = waveFormat->cbSize + sizeof(WAVEFORMATEX);
  363.     memcpy(formatInfo.GetPointer(formatSize), waveFormat, formatSize);
  364.   }
  365.   // Allocate and lock memory for the waveform data.
  366.   if (!SetSize(dataSize)) {
  367.     dwLastError = MMSYSERR_NOMEM;
  368.     return FALSE;
  369.   }
  370.   // Read the waveform data subchunk
  371.   if (!mmio.Read(GetPointer(), GetSize())) {
  372.     dwLastError = mmio.GetLastError();
  373.     return FALSE;
  374.   }
  375.   return TRUE;
  376. }
  377. BOOL PSound::Save(const PFilePath & filename)
  378. {
  379.   PWaveFormat waveFormat;
  380.   if (encoding == 0)
  381.     waveFormat.SetFormat(numChannels, sampleRate, sampleSize);
  382.   else {
  383.     waveFormat.SetSize(GetFormatInfoSize());
  384.     memcpy(waveFormat.GetPointer(), GetFormatInfoData(), GetFormatInfoSize());
  385.   }
  386.   // Open wave file
  387.   PMultiMediaFile mmio;
  388.   if (!mmio.CreateWaveFile(filename, waveFormat, GetSize())) {
  389.     dwLastError = mmio.GetLastError();
  390.     return FALSE;
  391.   }
  392.   if (!mmio.Write(GetPointer(), GetSize())) {
  393.     dwLastError = mmio.GetLastError();
  394.     return FALSE;
  395.   }
  396.   return TRUE;
  397. }
  398. BOOL PSound::Play()
  399. {
  400.   PSoundChannel channel(PSoundChannel::GetDefaultDevice(PSoundChannel::Player),
  401.                         PSoundChannel::Player);
  402.   if (!channel.IsOpen())
  403.     return FALSE;
  404.   return channel.PlaySound(*this, TRUE);
  405. }
  406. BOOL PSound::PlayFile(const PFilePath & file, BOOL wait)
  407. {
  408.   return ::PlaySound(file, NULL, SND_FILENAME|(wait ? SND_SYNC : SND_ASYNC));
  409. }
  410. ///////////////////////////////////////////////////////////////////////////////
  411. PWaveBuffer::PWaveBuffer(PINDEX sz)
  412.  : PBYTEArray(sz)
  413. {
  414.   hWaveOut = NULL;
  415.   hWaveIn = NULL;
  416.   header.dwFlags = WHDR_DONE;
  417. }
  418. PWaveBuffer::~PWaveBuffer()
  419. {
  420.   Release();
  421. }
  422. PWaveBuffer & PWaveBuffer::operator=(const PSound & sound)
  423. {
  424.   PBYTEArray::operator=(sound);
  425.   return *this;
  426. }
  427. void PWaveBuffer::PrepareCommon(PINDEX count)
  428. {
  429.   Release();
  430.   memset(&header, 0, sizeof(header));
  431.   header.lpData = (char *)GetPointer();
  432.   header.dwBufferLength = count;
  433.   header.dwUser = (DWORD)this;
  434. }
  435. DWORD PWaveBuffer::Prepare(HWAVEOUT hOut, PINDEX & count)
  436. {
  437.   // Set up WAVEHDR structure and prepare it to be written to wave device
  438.   if (count > GetSize())
  439.     count = GetSize();
  440.   PrepareCommon(count);
  441.   hWaveOut = hOut;
  442.   return waveOutPrepareHeader(hWaveOut, &header, sizeof(header));
  443. }
  444. DWORD PWaveBuffer::Prepare(HWAVEIN hIn)
  445. {
  446.   // Set up WAVEHDR structure and prepare it to be read from wave device
  447.   PrepareCommon(GetSize());
  448.   hWaveIn = hIn;
  449.   return waveInPrepareHeader(hWaveIn, &header, sizeof(header));
  450. }
  451. DWORD PWaveBuffer::Release()
  452. {
  453.   DWORD err = MMSYSERR_NOERROR;
  454.   // There seems to be some pathalogical cases where on an Abort() call the buffers
  455.   // still are "in use", even though waveOutReset() was called. So wait until the
  456.   // sound driver has finished with the buffer before releasing it.
  457.   if (hWaveOut != NULL) {
  458.     if ((err = waveOutUnprepareHeader(hWaveOut, &header, sizeof(header))) == WAVERR_STILLPLAYING)
  459.       return err;
  460.     hWaveOut = NULL;
  461.   }
  462.   if (hWaveIn != NULL) {
  463.     if ((err = waveInUnprepareHeader(hWaveIn, &header, sizeof(header))) == WAVERR_STILLPLAYING)
  464.       return err;
  465.     hWaveIn = NULL;
  466.   }
  467.   header.dwFlags |= WHDR_DONE;
  468.   return err;
  469. }
  470. ///////////////////////////////////////////////////////////////////////////////
  471. PSoundChannel::PSoundChannel()
  472. {
  473.   Construct();
  474. }
  475. PSoundChannel::PSoundChannel(const PString & device,
  476.                              Directions dir,
  477.                              unsigned numChannels,
  478.                              unsigned sampleRate,
  479.                              unsigned bitsPerSample)
  480. {
  481.   Construct();
  482.   Open(device, dir, numChannels, sampleRate, bitsPerSample);
  483. }
  484. void PSoundChannel::Construct()
  485. {
  486.   direction = Player;
  487.   hWaveOut = NULL;
  488.   hWaveIn = NULL;
  489.   hEventDone = CreateEvent(NULL, FALSE, FALSE, NULL);
  490.   waveFormat.SetFormat(1, 8000, 16);
  491.   bufferByteOffset = P_MAX_INDEX;
  492.   SetBuffers(32768, 2);
  493. }
  494. PSoundChannel::~PSoundChannel()
  495. {
  496.   Close();
  497.   if (hEventDone != NULL)
  498.     DeleteObject(hEventDone);
  499. }
  500. PString PSoundChannel::GetName() const
  501. {
  502.   return deviceName;
  503. }
  504. PStringArray PSoundChannel::GetDeviceNames(Directions dir)
  505. {
  506.   PStringArray array;
  507.   unsigned numDevs, id;
  508.   switch (dir) {
  509.     case Player :
  510.       numDevs = waveOutGetNumDevs();
  511.       for (id = 0; id < numDevs; id++) {
  512.         WAVEOUTCAPS caps;
  513.         if (waveOutGetDevCaps(id, &caps, sizeof(caps)) == 0)
  514.           array[array.GetSize()] = caps.szPname;
  515.       }
  516.       break;
  517.     case Recorder :
  518.       numDevs = waveInGetNumDevs();
  519.       for (id = 0; id < numDevs; id++) {
  520.         WAVEINCAPS caps;
  521.         if (waveInGetDevCaps(id, &caps, sizeof(caps)) == 0)
  522.           array[array.GetSize()] = caps.szPname;
  523.       }
  524.       break;
  525.   }
  526.   return array;
  527. }
  528. PString PSoundChannel::GetDefaultDevice(Directions dir)
  529. {
  530.   RegistryKey registry("HKEY_CURRENT_USER\Software\Microsoft\Multimedia\Sound Mapper",
  531.                        RegistryKey::ReadOnly);
  532.   PString str;
  533.   if (dir == Player) {
  534.     if (!registry.QueryValue("Playback", str)) {
  535.       WAVEOUTCAPS caps;
  536.       if (waveOutGetDevCaps(0, &caps, sizeof(caps)) == 0)
  537.         str = caps.szPname;
  538.     }
  539.   }
  540.   else {
  541.     if (!registry.QueryValue("Record", str)) {
  542.       WAVEINCAPS caps;
  543.       if (waveInGetDevCaps(0, &caps, sizeof(caps)) == 0)
  544.         str = caps.szPname;
  545.     }
  546.   }
  547.   return str;
  548. }
  549. BOOL PSoundChannel::Open(const PString & device,
  550.                          Directions dir,
  551.                          unsigned numChannels,
  552.                          unsigned sampleRate,
  553.                          unsigned bitsPerSample)
  554. {
  555.   Close();
  556.   BOOL bad = TRUE;
  557.   unsigned id = 0;
  558.   if (device[0] == '#') {
  559.     id = device.Mid(1).AsUnsigned();
  560.     switch (dir) {
  561.       case Player :
  562.         if (id < waveOutGetNumDevs()) {
  563.           WAVEOUTCAPS caps;
  564.           osError = waveOutGetDevCaps(id, &caps, sizeof(caps));
  565.           if (osError == 0) {
  566.             deviceName = caps.szPname;
  567.             bad = FALSE;
  568.           }
  569.         }
  570.         break;
  571.       case Recorder :
  572.         if (id < waveInGetNumDevs()) {
  573.           WAVEINCAPS caps;
  574.           osError = waveInGetDevCaps(id, &caps, sizeof(caps));
  575.           if (osError == 0) {
  576.             deviceName = caps.szPname;
  577.             bad = FALSE;
  578.           }
  579.         }
  580.         break;
  581.     }
  582.   }
  583.   else {
  584.     switch (dir) {
  585.       case Player :
  586.         for (id = 0; id < waveOutGetNumDevs(); id++) {
  587.           WAVEOUTCAPS caps;
  588.           osError = waveOutGetDevCaps(id, &caps, sizeof(caps));
  589.           if (osError == 0 && stricmp(caps.szPname, device) == 0) {
  590.             deviceName = caps.szPname;
  591.             bad = FALSE;
  592.             break;
  593.           }
  594.         }
  595.         break;
  596.       case Recorder :
  597.         for (id = 0; id < waveInGetNumDevs(); id++) {
  598.           WAVEINCAPS caps;
  599.           osError = waveInGetDevCaps(id, &caps, sizeof(caps));
  600.           if (osError == 0 && stricmp(caps.szPname, device) == 0) {
  601.             deviceName = caps.szPname;
  602.             bad = FALSE;
  603.             break;
  604.           }
  605.         }
  606.         break;
  607.     }
  608.   }
  609.   if (bad) {
  610.     osError = MMSYSERR_BADDEVICEID;
  611.     return FALSE;
  612.   }
  613.   waveFormat.SetFormat(numChannels, sampleRate, bitsPerSample);
  614.   direction = dir;
  615.   return OpenDevice(id);
  616. }
  617. BOOL PSoundChannel::OpenDevice(unsigned id)
  618. {
  619.   Close();
  620.   PWaitAndSignal mutex(bufferMutex);
  621.   bufferByteOffset = P_MAX_INDEX;
  622.   bufferIndex = 0;
  623.   switch (direction) {
  624.     case Player :
  625.       osError = waveOutOpen(&hWaveOut, id, waveFormat,
  626.                             (DWORD)hEventDone, 0, CALLBACK_EVENT);
  627.       break;
  628.     case Recorder :
  629.       osError = waveInOpen(&hWaveIn, id, waveFormat,
  630.                            (DWORD)hEventDone, 0, CALLBACK_EVENT);
  631.       break;
  632.   }
  633.   if (osError != MMSYSERR_NOERROR)
  634.     return FALSE;
  635.   os_handle = id;
  636.   return TRUE;
  637. }
  638. BOOL PSoundChannel::SetFormat(unsigned numChannels,
  639.                               unsigned sampleRate,
  640.                               unsigned bitsPerSample)
  641. {
  642.   Abort();
  643.   waveFormat.SetFormat(numChannels, sampleRate, bitsPerSample);
  644.   return OpenDevice(os_handle);
  645. }
  646. BOOL PSoundChannel::SetFormat(const PWaveFormat & format)
  647. {
  648.   Abort();
  649.   waveFormat = format;
  650.   return OpenDevice(os_handle);
  651. }
  652. BOOL PSoundChannel::Close()
  653. {
  654.   if (!IsOpen())
  655.     return FALSE;
  656.   Abort();
  657.   if (hWaveOut != NULL) {
  658.     while ((osError = waveOutClose(hWaveOut)) == WAVERR_STILLPLAYING)
  659.       waveOutReset(hWaveOut);
  660.     hWaveOut = NULL;
  661.   }
  662.   if (hWaveIn != NULL) {
  663.     while ((osError = waveInClose(hWaveIn)) == WAVERR_STILLPLAYING)
  664.       waveInReset(hWaveIn);
  665.     hWaveIn = NULL;
  666.   }
  667.   Abort();
  668.   os_handle = -1;
  669.   return TRUE;
  670. }
  671. BOOL PSoundChannel::SetBuffers(PINDEX size, PINDEX count)
  672. {
  673.   Abort();
  674.   PAssert(size > 0 && count > 0, PInvalidParameter);
  675.   BOOL ok = TRUE;
  676.   PWaitAndSignal mutex(bufferMutex);
  677.   if (!buffers.SetSize(count))
  678.     ok = FALSE;
  679.   else {
  680.     for (PINDEX i = 0; i < count; i++) {
  681.       if (buffers.GetAt(i) == NULL)
  682.         buffers.SetAt(i, new PWaveBuffer(size));
  683.       if (!buffers[i].SetSize(size))
  684.         ok = FALSE;
  685.     }
  686.   }
  687.   bufferByteOffset = P_MAX_INDEX;
  688.   bufferIndex = 0;
  689.   return ok;
  690. }
  691. BOOL PSoundChannel::GetBuffers(PINDEX & size, PINDEX & count)
  692. {
  693.   PWaitAndSignal mutex(bufferMutex);
  694.   count = buffers.GetSize();
  695.   if (count == 0)
  696.     size = 0;
  697.   else
  698.     size = buffers[0].GetSize();
  699.   return TRUE;
  700. }
  701. BOOL PSoundChannel::Write(const void * data, PINDEX size)
  702. {
  703.   lastWriteCount = 0;
  704.   if (hWaveOut == NULL) {
  705.     osError = MMSYSERR_NOTSUPPORTED;
  706.     return FALSE;
  707.   }
  708.   const BYTE * ptr = (const BYTE *)data;
  709.   bufferMutex.Wait();
  710.   while (size > 0) {
  711.     PWaveBuffer & buffer = buffers[bufferIndex];
  712.     while ((buffer.header.dwFlags&WHDR_DONE) == 0) {
  713.       bufferMutex.Signal();
  714.       // No free buffers, so wait for one
  715.       if (WaitForSingleObject(hEventDone, INFINITE) != WAIT_OBJECT_0) {
  716.         osError = MMSYSERR_ERROR;
  717.         return FALSE; // No free buffers
  718.       }
  719.       bufferMutex.Wait();
  720.     }
  721.     // Can't write more than a buffer full
  722.     PINDEX count = size;
  723.     if ((osError = buffer.Prepare(hWaveOut, count)) != MMSYSERR_NOERROR)
  724.       break;
  725.     memcpy(buffer.GetPointer(), data, count);
  726.     if ((osError = waveOutWrite(hWaveOut, &buffer.header, sizeof(WAVEHDR))) != MMSYSERR_NOERROR)
  727.       break;
  728.     bufferIndex = (bufferIndex+1)%buffers.GetSize();
  729.     lastWriteCount += count;
  730.     size -= count;
  731.     ptr += count;
  732.   }
  733.   bufferMutex.Signal();
  734.   return size == 0;
  735. }
  736. BOOL PSoundChannel::PlaySound(const PSound & sound, BOOL wait)
  737. {
  738.   Abort();
  739.   BOOL ok = FALSE;
  740.   PINDEX bufferSize;
  741.   PINDEX bufferCount;
  742.   GetBuffers(bufferSize, bufferCount);
  743.   unsigned numChannels = waveFormat->nChannels;
  744.   unsigned sampleRate = waveFormat->nSamplesPerSec;
  745.   unsigned bitsPerSample = waveFormat->wBitsPerSample;
  746.   if (sound.GetEncoding() == 0)
  747.     ok = SetFormat(sound.GetChannels(), sound.GetSampleRate(), sound.GetSampleSize());
  748.   else {
  749.     waveFormat.SetFormat(sound.GetFormatInfoData(), sound.GetFormatInfoSize());
  750.     ok = OpenDevice(os_handle);
  751.   }
  752.   if (ok) {
  753.     bufferMutex.Wait();
  754.     // To avoid lots of copying of sound data, we fake the PSound buffer into
  755.     // the internal buffers and play directly from the PSound object.
  756.     buffers.SetSize(1);
  757.     PWaveBuffer & buffer = buffers[0];
  758.     buffer = sound;
  759.     PINDEX count = sound.GetSize();
  760.     if ((osError = buffer.Prepare(hWaveOut, count)) == MMSYSERR_NOERROR &&
  761.         (osError = waveOutWrite(hWaveOut, &buffer.header, sizeof(WAVEHDR))) == MMSYSERR_NOERROR) {
  762.       if (wait)
  763.         ok = WaitForPlayCompletion();
  764.     }
  765.     else
  766.       ok = FALSE;
  767.     bufferMutex.Signal();
  768.   }
  769.   SetFormat(numChannels, sampleRate, bitsPerSample);
  770.   SetBuffers(bufferSize, bufferCount);
  771.   return ok;
  772. }
  773. BOOL PSoundChannel::PlayFile(const PFilePath & filename, BOOL wait)
  774. {
  775.   Abort();
  776.   PMultiMediaFile mmio;
  777.   PWaveFormat fileFormat;
  778.   DWORD dataSize;
  779.   if (!mmio.OpenWaveFile(filename, fileFormat, dataSize)) {
  780.     osError = mmio.GetLastError();
  781.     return FALSE;
  782.   }
  783.   // Save old format and set to one loaded from file.
  784.   unsigned numChannels = waveFormat->nChannels;
  785.   unsigned sampleRate = waveFormat->nSamplesPerSec;
  786.   unsigned bitsPerSample = waveFormat->wBitsPerSample;
  787.   waveFormat = fileFormat;
  788.   if (!OpenDevice(os_handle)) {
  789.     SetFormat(numChannels, sampleRate, bitsPerSample);
  790.     return FALSE;
  791.   }
  792.   bufferMutex.Wait();
  793.   while (dataSize > 0) {
  794.     PWaveBuffer & buffer = buffers[bufferIndex];
  795.     while ((buffer.header.dwFlags&WHDR_DONE) == 0) {
  796.       bufferMutex.Signal();
  797.       // No free buffers, so wait for one
  798.       if (WaitForSingleObject(hEventDone, INFINITE) != WAIT_OBJECT_0) {
  799.         SetFormat(numChannels, sampleRate, bitsPerSample);
  800.         return FALSE;
  801.       }
  802.       bufferMutex.Wait();
  803.     }
  804.     // Can't write more than a buffer full
  805.     PINDEX count = dataSize;
  806.     if ((osError = buffer.Prepare(hWaveOut, count)) != MMSYSERR_NOERROR)
  807.       break;
  808.     // Read the waveform data subchunk
  809.     if (!mmio.Read(buffer.GetPointer(), count)) {
  810.       osError = mmio.GetLastError();
  811.       break;
  812.     }
  813.     if ((osError = waveOutWrite(hWaveOut, &buffer.header, sizeof(WAVEHDR))) != MMSYSERR_NOERROR)
  814.       break;
  815.     bufferIndex = (bufferIndex+1)%buffers.GetSize();
  816.     dataSize -= count;
  817.   }
  818.   bufferMutex.Signal();
  819.   if (dataSize == 0 && wait)
  820.     WaitForPlayCompletion();
  821.   SetFormat(numChannels, sampleRate, bitsPerSample);
  822.   return TRUE;
  823. }
  824. BOOL PSoundChannel::HasPlayCompleted()
  825. {
  826.   PWaitAndSignal mutex(bufferMutex);
  827.   for (PINDEX i = 0; i < buffers.GetSize(); i++) {
  828.     if ((buffers[i].header.dwFlags&WHDR_DONE) == 0)
  829.       return FALSE;
  830.   }
  831.   return TRUE;
  832. }
  833. BOOL PSoundChannel::WaitForPlayCompletion()
  834. {
  835.   while (!HasPlayCompleted()) {
  836.     if (WaitForSingleObject(hEventDone, INFINITE) != WAIT_OBJECT_0)
  837.       return FALSE;
  838.   }
  839.   return TRUE;
  840. }
  841. BOOL PSoundChannel::StartRecording()
  842. {
  843.   PWaitAndSignal mutex(bufferMutex);
  844.   // See if has started already.
  845.   if (bufferByteOffset != P_MAX_INDEX)
  846.     return TRUE;
  847.   // Start the first read, queue all the buffers
  848.   for (PINDEX i = 0; i < buffers.GetSize(); i++) {
  849.     PWaveBuffer & buffer = buffers[i];
  850.     if ((osError = buffer.Prepare(hWaveIn)) != MMSYSERR_NOERROR)
  851.       return FALSE;
  852.     if ((osError = waveInAddBuffer(hWaveIn, &buffer.header, sizeof(WAVEHDR))) != MMSYSERR_NOERROR)
  853.       return FALSE;
  854.   }
  855.   bufferByteOffset = 0;
  856.   if ((osError = waveInStart(hWaveIn)) == MMSYSERR_NOERROR) // start recording
  857.     return TRUE;
  858.   bufferByteOffset = P_MAX_INDEX;
  859.   return FALSE;
  860. }
  861. BOOL PSoundChannel::Read(void * data, PINDEX size)
  862. {
  863.   lastReadCount = 0;
  864.   if (hWaveIn == NULL) {
  865.     osError = MMSYSERR_NOTSUPPORTED;
  866.     return FALSE;
  867.   }
  868.   if (!StartRecording())  // Start the first read, queue all the buffers
  869.     return FALSE;
  870.   if (!WaitForRecordBufferFull())
  871.     return FALSE;
  872.   PWaitAndSignal mutex(bufferMutex);
  873.   PWaveBuffer & buffer = buffers[bufferIndex];
  874.   PINDEX bytesRecorded = buffer.header.dwBytesRecorded;
  875.   lastReadCount = bytesRecorded - bufferByteOffset;
  876.   if (lastReadCount > size)
  877.     lastReadCount = size;
  878.   if (lastReadCount == 0 || bufferByteOffset == P_MAX_INDEX)
  879.     return FALSE;
  880.   memcpy(data, &buffer[bufferByteOffset], lastReadCount);
  881.   bufferByteOffset += lastReadCount;
  882.   if (bufferByteOffset >= buffer.GetSize()) {
  883.     if ((osError = buffer.Prepare(hWaveIn)) != MMSYSERR_NOERROR)
  884.       return FALSE;
  885.     if ((osError = waveInAddBuffer(hWaveIn, &buffer.header, sizeof(WAVEHDR))) != MMSYSERR_NOERROR)
  886.       return FALSE;
  887.     bufferIndex = (bufferIndex+1)%buffers.GetSize();
  888.     bufferByteOffset = 0;
  889.   }
  890.   return TRUE;
  891. }
  892. BOOL PSoundChannel::RecordSound(PSound & sound)
  893. {
  894.   if (!StartRecording())  // Start the first read, queue all the buffers
  895.     return FALSE;
  896.   if (!WaitForAllRecordBuffersFull())
  897.     return FALSE;
  898.   sound.SetFormat(waveFormat->nChannels,
  899.                   waveFormat->nSamplesPerSec,
  900.                   waveFormat->wBitsPerSample);
  901.   PWaitAndSignal mutex(bufferMutex);
  902.   if (buffers.GetSize() == 1 &&
  903.           (PINDEX)buffers[0].header.dwBytesRecorded == buffers[0].GetSize())
  904.     sound = buffers[0];
  905.   else {
  906.     PINDEX totalSize = 0;
  907.     PINDEX i;
  908.     for (i = 0; i < buffers.GetSize(); i++)
  909.       totalSize += buffers[i].header.dwBytesRecorded;
  910.     if (!sound.SetSize(totalSize)) {
  911.       osError = MMSYSERR_NOMEM;
  912.       return FALSE;
  913.     }
  914.     BYTE * ptr = sound.GetPointer();
  915.     for (i = 0; i < buffers.GetSize(); i++) {
  916.       PINDEX sz = buffers[i].header.dwBytesRecorded;
  917.       memcpy(ptr, buffers[i], sz);
  918.       ptr += sz;
  919.     }
  920.   }
  921.   return TRUE;
  922. }
  923. BOOL PSoundChannel::RecordFile(const PFilePath & filename)
  924. {
  925.   if (!StartRecording())  // Start the first read, queue all the buffers
  926.     return FALSE;
  927.   if (!WaitForAllRecordBuffersFull())
  928.     return FALSE;
  929.   PWaitAndSignal mutex(bufferMutex);
  930.   PINDEX dataSize = 0;
  931.   PINDEX i;
  932.   for (i = 0; i < buffers.GetSize(); i++)
  933.     dataSize += buffers[i].header.dwBytesRecorded;
  934.   PMultiMediaFile mmio;
  935.   if (!mmio.CreateWaveFile(filename, waveFormat, dataSize)) {
  936.     osError = mmio.GetLastError();
  937.     return FALSE;
  938.   }
  939.   for (i = 0; i < buffers.GetSize(); i++) {
  940.     if (!mmio.Write(buffers[i], buffers[i].header.dwBytesRecorded)) {
  941.       osError = mmio.GetLastError();
  942.       return FALSE;
  943.     }
  944.   }
  945.   return TRUE;
  946. }
  947. BOOL PSoundChannel::IsRecordBufferFull()
  948. {
  949.   PWaitAndSignal mutex(bufferMutex);
  950.   if (bufferByteOffset == P_MAX_INDEX)
  951.     return TRUE;
  952.   return (buffers[bufferIndex].header.dwFlags&WHDR_DONE) != 0;
  953. }
  954. BOOL PSoundChannel::AreAllRecordBuffersFull()
  955. {
  956.   PWaitAndSignal mutex(bufferMutex);
  957.   if (bufferByteOffset == P_MAX_INDEX)
  958.     return TRUE;
  959.   for (PINDEX i = 0; i < buffers.GetSize(); i++) {
  960.     if ((buffers[i].header.dwFlags&WHDR_DONE) == 0)
  961.       return FALSE;
  962.   }
  963.   return TRUE;
  964. }
  965. BOOL PSoundChannel::WaitForRecordBufferFull()
  966. {
  967.   if (bufferByteOffset == P_MAX_INDEX)
  968.     return FALSE;
  969.   while (!IsRecordBufferFull()) {
  970.     if (WaitForSingleObject(hEventDone, INFINITE) != WAIT_OBJECT_0)
  971.       return FALSE;
  972.   }
  973.   return TRUE;
  974. }
  975. BOOL PSoundChannel::WaitForAllRecordBuffersFull()
  976. {
  977.   if (bufferByteOffset == P_MAX_INDEX)
  978.     return FALSE;
  979.   while (!AreAllRecordBuffersFull()) {
  980.     if (WaitForSingleObject(hEventDone, INFINITE) != WAIT_OBJECT_0)
  981.       return FALSE;
  982.   }
  983.   return TRUE;
  984. }
  985. BOOL PSoundChannel::Abort()
  986. {
  987.   if (hWaveOut != NULL)
  988.     osError = waveOutReset(hWaveOut);
  989.   if (hWaveIn != NULL)
  990.     osError = waveInReset(hWaveIn);
  991.   PWaitAndSignal mutex(bufferMutex);
  992.   for (PINDEX i = 0; i < buffers.GetSize(); i++) {
  993.     if (buffers[i].Release() == WAVERR_STILLPLAYING) {
  994.       if (hWaveOut != NULL)
  995.         waveOutReset(hWaveOut);
  996.       if (hWaveIn != NULL)
  997.         waveInReset(hWaveIn);
  998.     }
  999.   }
  1000.   bufferByteOffset = P_MAX_INDEX;
  1001.   bufferIndex = 0;
  1002.   return osError == MMSYSERR_NOERROR;
  1003. }
  1004. PString PSoundChannel::GetErrorText() const
  1005. {
  1006.   PString str;
  1007.   if (direction == Recorder) {
  1008.     if (waveInGetErrorText(osError, str.GetPointer(256), 256) != MMSYSERR_NOERROR)
  1009.       return PChannel::GetErrorText();
  1010.   }
  1011.   else {
  1012.     if (waveOutGetErrorText(osError, str.GetPointer(256), 256) != MMSYSERR_NOERROR)
  1013.       return PChannel::GetErrorText();
  1014.   }
  1015.   return str;
  1016. }
  1017. // End of File ///////////////////////////////////////////////////////////////