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

📄 sound_win32.cxx

📁 sloedgy open sip stack source code
💻 CXX
📖 第 1 页 / 共 3 页
字号:
/*
 * sound.cxx
 *
 * Implementation of sound classes for Win32
 *
 * Portable Windows Library
 *
 * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
 *
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.0 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 * the License for the specific language governing rights and limitations
 * under the License.
 *
 * The Original Code is Portable Windows Library.
 *
 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
 *
 * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
 * All Rights Reserved.
 *
 * Contributor(s): ______________________________________.
 *
 * $Log: sound_win32.cxx,v $
 * Revision 1.1  2006/06/29 04:18:40  joegenbaclor
 * *** empty log message ***
 *
 * Revision 1.16  2006/04/09 11:03:59  csoutheren
 * Remove warnings on VS.net 2005
 *
 * Revision 1.15  2005/11/30 12:47:42  csoutheren
 * Removed tabs, reformatted some code, and changed tags for Doxygen
 *
 * Revision 1.14  2005/10/06 08:14:55  csoutheren
 * Fixed race condition in sound driver when shutting down with driver that is not open
 *
 * Revision 1.13  2005/09/18 13:01:43  dominance
 * fixed pragma warnings when building with gcc.
 *
 * Revision 1.12  2005/07/03 13:48:58  shorne
 * Add the ability to play sound to specified device.
 *
 * Revision 1.11  2005/04/21 05:27:04  csoutheren
 * Prevent weird deadlocks when using record-only or play-only sound channels
 *
 * Revision 1.10  2005/01/04 07:44:04  csoutheren
 * More changes to implement the new configuration methodology, and also to
 * attack the global static problem
 *
 * Revision 1.9  2004/10/23 11:16:17  ykiryanov
 * Added ifdef _WIN32_WCE for PocketPC 2003 SDK port
 *
 * Revision 1.8  2004/08/16 06:41:00  csoutheren
 * Added adapters template to make device plugins available via the abstract factory interface
 *
 * Revision 1.7  2004/04/09 06:52:18  rjongbloed
 * Removed #pargma linker command for /delayload of DLL as documentations sais that
 *   you cannot do this.
 *
 * Revision 1.6  2004/02/23 23:52:20  csoutheren
 * Added pragmas to avoid every Windows application needing to include libs explicitly
 *
 * Revision 1.5  2004/02/15 03:59:20  rjongbloed
 * Fixed the default number of buffer to be the value determined emprirically in
 *    OpenH323, thanks Ted Szoczei
 *
 * Revision 1.4  2003/12/29 03:29:26  csoutheren
 * Allowed access to Windows sound channel declaration, just in case it is required
 *
 * Revision 1.3  2003/12/29 02:00:40  csoutheren
 * Moved some declarations to sound_win32.h to allow access
 *
 * Revision 1.2  2003/11/18 10:50:44  csoutheren
 * Changed name of Windows sound device
 *
 * Revision 1.1  2003/11/12 04:39:56  csoutheren
 * Changed to work with new plugin system
 *
 * Revision 1.37  2003/11/05 05:57:58  csoutheren
 * Added #pragma to include required libs
 *
 * Revision 1.36  2003/09/17 05:45:10  csoutheren
 * Removed recursive includes
 *
 * Revision 1.35  2003/06/05 05:20:35  rjongbloed
 * Fixed WinCE compatibility, thanks Yuri Kiryanov
 *
 * Revision 1.34  2003/05/29 08:57:38  rjongbloed
 * Futher changes to not alter balance when changing volume setting, also fixed
 *   correct return of volume level if balance not centred, thanks Diego T醨tara
 *
 * Revision 1.33  2003/05/01 00:17:40  robertj
 * Fixed setting of stereo volume levels, thanks Diego T醨tara
 *
 * Revision 1.32  2002/08/05 01:22:59  robertj
 * Fixed possible range error on SetVolume(), thanks Sonya Cooper-Hull
 *
 * Revision 1.31  2002/02/08 09:59:45  robertj
 * Slight adjustment to API and documentation for volume functions.
 * Added implementation for volume function on play, still needs recording.
 *
 * Revision 1.30  2002/02/07 20:57:21  dereks
 * add SetVolume and GetVolume methods to PSoundChannel
 *
 * Revision 1.29  2001/10/23 02:49:48  robertj
 * Fixed problem with Abort() not always breaking I/O blocked threads.
 *
 * Revision 1.28  2001/10/12 03:50:27  robertj
 * Fixed race condition on using Abort() which Reading from another thread.
 * Fixed failure to start recording if called WaitForXXXFull() functions.
 *
 * Revision 1.27  2001/10/10 03:29:34  yurik
 * Added open with format other than PCM
 *
 * Revision 1.26  2001/09/22 03:36:56  yurik
 * Put code to prevent audio channel disconnection
 *
 * Revision 1.25  2001/09/10 02:51:23  robertj
 * Major change to fix problem with error codes being corrupted in a
 *   PChannel when have simultaneous reads and writes in threads.
 *
 * Revision 1.24  2001/09/10 02:48:51  robertj
 * Removed previous change as breaks semantics of Read() function, moved test
 *   for zero buffer length to part that waits for buffer to be full.
 *
 * Revision 1.23  2001/09/09 17:37:49  yurik
 * dwBytesRecorded in WAVEHDR could return 0. We should not close the channel in this case
 *
 * Revision 1.22  2001/09/09 02:17:11  yurik
 * Returned to 1.20
 *
 * Revision 1.20  2001/07/01 02:45:01  yurik
 * WinCE compiler wants implicit cast to format
 *
 * Revision 1.19  2001/05/04 09:38:07  robertj
 * Fixed problem with some WAV files having small WAVEFORMATEX chunk.
 *
 * Revision 1.18  2001/04/10 00:51:11  robertj
 * Fixed bug in using incorrect function to delete event handle, thanks Victor H.
 *
 * Revision 1.17  2001/03/15 23:39:29  robertj
 * Fixed bug with trying to write block larger than one buffer, thanks Norbert Oertel
 *
 * Revision 1.16  2001/02/07 04:45:54  robertj
 * Added functions to get current sound channel format parameters.
 *
 * Revision 1.15  2000/07/04 04:30:47  robertj
 * Fixed shutdown issues with buffers in use, again.
 *
 * Revision 1.14  2000/07/01 09:39:31  robertj
 * Fixed shutdown issues with buffers in use.
 *
 * Revision 1.13  2000/06/29 00:39:29  robertj
 * Fixed bug when PWaveFormat is assigned to itself.
 *
 * Revision 1.12  2000/05/22 07:17:50  robertj
 * Fixed missing initialisation of format data block in Win32 PSound::Load().
 *
 * Revision 1.11  2000/05/01 05:59:11  robertj
 * Added mutex to PSoundChannel buffer structure.
 *
 * Revision 1.10  2000/03/04 10:15:32  robertj
 * Added simple play functions for sound files.
 *
 * Revision 1.9  2000/02/17 11:33:33  robertj
 * Changed PSoundChannel::Write so blocks instead of error if no buffers available.
 *
 * Revision 1.8  1999/10/09 01:22:07  robertj
 * Fixed error display for sound channels.
 *
 * Revision 1.7  1999/09/23 04:28:44  robertj
 * Allowed some Win32 only access to wave format in sound channel
 *
 * Revision 1.6  1999/07/08 08:39:53  robertj
 * Fixed bug when breaking block by closing the PSoundChannel in other thread.
 *
 * Revision 1.5  1999/06/24 14:01:25  robertj
 * Fixed bug in not returning correct default recorder (waveIn) device.
 *
 * Revision 1.4  1999/06/07 01:36:28  robertj
 * Fixed incorrect;ly set block alignment in sound structure.
 *
 * Revision 1.3  1999/05/28 14:04:51  robertj
 * Added function to get default audio device.
 *
 * Revision 1.2  1999/02/22 10:15:15  robertj
 * Sound driver interface implementation to Linux OSS specification.
 *
 * Revision 1.1  1999/02/16 06:02:07  robertj
 * Major implementation to Linux OSS model
 *
 */

#define P_FORCE_STATIC_PLUGIN

#include <ptlib.h>

#if defined(_WIN32) && !defined(P_FORCE_STATIC_PLUGIN)
#error "sound_win32.cxx must be compiled without precompiled headers"
#endif

#include <process.h>

#include <ptlib/plugin.h>
#include <ptlib/msos/ptlib/sound_win32.h>

#ifndef _WIN32_WCE
#ifdef _MSC_VER
#pragma comment(lib, "winmm.lib")
#endif
#endif

class PSound;

PCREATE_SOUND_PLUGIN(WindowsMultimedia, PSoundChannelWin32);

class PMultiMediaFile
{
  public:
    PMultiMediaFile();
    ~PMultiMediaFile();

    BOOL CreateWaveFile(const PFilePath & filename,
                        const PWaveFormat & waveFormat,
                        DWORD dataSize);
    BOOL OpenWaveFile(const PFilePath & filename,
                      PWaveFormat & waveFormat,
                      DWORD & dataSize);

    BOOL Open(const PFilePath & filename, DWORD dwOpenFlags, LPMMIOINFO lpmmioinfo = NULL);
    BOOL Close(UINT wFlags = 0);
    BOOL Ascend(MMCKINFO & ckinfo, UINT wFlags = 0);
    BOOL Descend(UINT wFlags, MMCKINFO & ckinfo, LPMMCKINFO lpckParent = NULL);
    BOOL Read(void * data, PINDEX len);
    BOOL CreateChunk(MMCKINFO & ckinfo, UINT wFlags = 0);
    BOOL Write(const void * data, PINDEX len);

    DWORD GetLastError() const { return dwLastError; }

  protected:
    HMMIO hmmio;
    DWORD dwLastError;
};


#define new PNEW


///////////////////////////////////////////////////////////////////////////////

PMultiMediaFile::PMultiMediaFile()
{
  hmmio = NULL;
}


PMultiMediaFile::~PMultiMediaFile()
{
  Close();
}


BOOL PMultiMediaFile::CreateWaveFile(const PFilePath & filename,
                                     const PWaveFormat & waveFormat,
                                     DWORD dataSize)
{
  if (!Open(filename, MMIO_CREATE|MMIO_WRITE))
    return FALSE;

  MMCKINFO mmChunk;
  mmChunk.fccType = mmioFOURCC('W', 'A', 'V', 'E');
  mmChunk.cksize = 4 + // Form type
                   4 + sizeof(DWORD) + waveFormat.GetSize() + // fmt chunk
                   4 + sizeof(DWORD) + dataSize;              // data chunk

  // Create a RIFF chunk
  if (!CreateChunk(mmChunk, MMIO_CREATERIFF))
    return FALSE;

  // Save the format sub-chunk
  mmChunk.ckid = mmioFOURCC('f', 'm', 't', ' ');
  mmChunk.cksize = waveFormat.GetSize();
  if (!CreateChunk(mmChunk))
    return FALSE;

  if (!Write(waveFormat, waveFormat.GetSize()))
    return FALSE;

  // Save the data sub-chunk
  mmChunk.ckid = mmioFOURCC('d', 'a', 't', 'a');
  mmChunk.cksize = dataSize;
  return CreateChunk(mmChunk);
}


BOOL PMultiMediaFile::OpenWaveFile(const PFilePath & filename,
                                   PWaveFormat  & waveFormat,
                                   DWORD & dataSize)
{
  // Open wave file
  if (!Open(filename, MMIO_READ | MMIO_ALLOCBUF))
    return FALSE;

  MMCKINFO mmParentChunk, mmSubChunk;
  dwLastError = MMSYSERR_NOERROR;

  // Locate a 'RIFF' chunk with a 'WAVE' form type
  mmParentChunk.fccType = mmioFOURCC('W', 'A', 'V', 'E');
  if (!Descend(MMIO_FINDRIFF, mmParentChunk))
    return FALSE;

  // Find the format chunk
  mmSubChunk.ckid = mmioFOURCC('f', 'm', 't', ' ');
  if (!Descend(MMIO_FINDCHUNK, mmSubChunk, &mmParentChunk))
    return FALSE;

  // Get the size of the format chunk, allocate memory for it
  if (!waveFormat.SetSize(mmSubChunk.cksize))
    return FALSE;

  // Read the format chunk
  if (!Read(waveFormat.GetPointer(), waveFormat.GetSize()))
    return FALSE;

  // Ascend out of the format subchunk
  Ascend(mmSubChunk);

  // Find the data subchunk
  mmSubChunk.ckid = mmioFOURCC('d', 'a', 't', 'a');
  if (!Descend(MMIO_FINDCHUNK, mmSubChunk, &mmParentChunk))
    return FALSE;

  // Get the size of the data subchunk
  if (mmSubChunk.cksize == 0) {
    dwLastError = MMSYSERR_INVALPARAM;
    return FALSE;
  }

  dataSize = mmSubChunk.cksize;
  return TRUE;
}


BOOL PMultiMediaFile::Open(const PFilePath & filename,
                          DWORD dwOpenFlags,
                          LPMMIOINFO lpmmioinfo)
{
  MMIOINFO local_mmioinfo;
  if (lpmmioinfo == NULL) {
    lpmmioinfo = &local_mmioinfo;
    memset(lpmmioinfo, 0, sizeof(local_mmioinfo));
  }

  hmmio = mmioOpen((char *)(const char *)filename, lpmmioinfo, dwOpenFlags);

  dwLastError = lpmmioinfo->wErrorRet;

  return hmmio != NULL;
}


BOOL PMultiMediaFile::Close(UINT wFlags)
{
  if (hmmio == NULL)
    return FALSE;

  mmioClose(hmmio, wFlags);
  hmmio = NULL;
  return TRUE;
}


BOOL PMultiMediaFile::Ascend(MMCKINFO & ckinfo, UINT wFlags)
{
  dwLastError = mmioAscend(hmmio, &ckinfo, wFlags);
  return dwLastError == MMSYSERR_NOERROR;
}


BOOL PMultiMediaFile::Descend(UINT wFlags, MMCKINFO & ckinfo, LPMMCKINFO lpckParent)
{
  dwLastError = mmioDescend(hmmio, &ckinfo, lpckParent, wFlags);
  return dwLastError == MMSYSERR_NOERROR;
}


BOOL PMultiMediaFile::Read(void * data, PINDEX len)
{
  return mmioRead(hmmio, (char *)data, len) == len;
}


BOOL PMultiMediaFile::CreateChunk(MMCKINFO & ckinfo, UINT wFlags)
{
  dwLastError = mmioCreateChunk(hmmio, &ckinfo, wFlags);
  return dwLastError == MMSYSERR_NOERROR;
}


BOOL PMultiMediaFile::Write(const void * data, PINDEX len)
{
  return mmioWrite(hmmio, (char *)data, len) == len;
}


///////////////////////////////////////////////////////////////////////////////

PWaveFormat::PWaveFormat()
{
  size = 0;
  waveFormat = NULL;
}


PWaveFormat::~PWaveFormat()
{
  if (waveFormat != NULL)
    free(waveFormat);
}


PWaveFormat::PWaveFormat(const PWaveFormat & fmt)
{
  size = fmt.size;
  waveFormat = (WAVEFORMATEX *)malloc(size);
  PAssert(waveFormat != NULL, POutOfMemory);

  memcpy(waveFormat, fmt.waveFormat, size);
}


PWaveFormat & PWaveFormat::operator=(const PWaveFormat & fmt)
{
  if (this == &fmt)
    return *this;

  if (waveFormat != NULL)
    free(waveFormat);

  size = fmt.size;
  waveFormat = (WAVEFORMATEX *)malloc(size);
  PAssert(waveFormat != NULL, POutOfMemory);

  memcpy(waveFormat, fmt.waveFormat, size);
  return *this;
}


void PWaveFormat::PrintOn(ostream & out) const
{
  if (waveFormat == NULL)
    out << "<null>";
  else {
    out << waveFormat->wFormatTag << ','
        << waveFormat->nChannels << ','
        << waveFormat->nSamplesPerSec << ','
        << waveFormat->nAvgBytesPerSec << ','
        << waveFormat->nBlockAlign << ','
        << waveFormat->wBitsPerSample;
    if (waveFormat->cbSize > 0) {
      out << hex << setfill('0');
      const BYTE * ptr = (const BYTE *)&waveFormat[1];
      for (PINDEX i = 0; i < waveFormat->cbSize; i++)
        out << ',' << setw(2) << (unsigned)*ptr++;
      out << dec << setfill(' ');
    }
  }
}


void PWaveFormat::ReadFrom(istream &)
{
}


void PWaveFormat::SetFormat(unsigned numChannels,
                            unsigned sampleRate,
                            unsigned bitsPerSample)
{
  PAssert(numChannels == 1 || numChannels == 2, PInvalidParameter);
  PAssert(bitsPerSample == 8 || bitsPerSample == 16, PInvalidParameter);

  if (waveFormat != NULL)
    free(waveFormat);

  size = sizeof(WAVEFORMATEX);
  waveFormat = (WAVEFORMATEX *)malloc(sizeof(WAVEFORMATEX));
  PAssert(waveFormat != NULL, POutOfMemory);

  waveFormat->wFormatTag = WAVE_FORMAT_PCM;
  waveFormat->nChannels = (WORD)numChannels;
  waveFormat->nSamplesPerSec = sampleRate;
  waveFormat->wBitsPerSample = (WORD)bitsPerSample;
  waveFormat->nBlockAlign = (WORD)(numChannels*(bitsPerSample+7)/8);
  waveFormat->nAvgBytesPerSec = waveFormat->nSamplesPerSec*waveFormat->nBlockAlign;
  waveFormat->cbSize = 0;
}


void PWaveFormat::SetFormat(const void * data, PINDEX size)
{
  SetSize(size);
  memcpy(waveFormat, data, size);
}


BOOL PWaveFormat::SetSize(PINDEX sz)
{
  if (waveFormat != NULL)
    free(waveFormat);

  size = sz;
  if (sz == 0)
    waveFormat = NULL;
  else {
    if (sz < sizeof(WAVEFORMATEX))
      sz = sizeof(WAVEFORMATEX);
    waveFormat = (WAVEFORMATEX *)calloc(sz, 1);
    waveFormat->cbSize = (WORD)(sz - sizeof(WAVEFORMATEX));
  }

  return waveFormat != NULL;
}


///////////////////////////////////////////////////////////////////////////////

PSound::PSound(unsigned channels,
               unsigned samplesPerSecond,
               unsigned bitsPerSample,
               PINDEX   bufferSize,
               const BYTE * buffer)
{
  encoding = 0;
  numChannels = channels;
  sampleRate = samplesPerSecond;
  sampleSize = bitsPerSample;
  SetSize(bufferSize);
  if (buffer != NULL)
    memcpy(GetPointer(), buffer, bufferSize);
}

⌨️ 快捷键说明

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