📄 sound_win32.cxx
字号:
/* * 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.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#pragma comment(lib, "winmm.lib")#endifclass 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);}PSound::PSound(const PFilePath & filename){ encoding = 0; numChannels = 1; sampleRate = 8000; sampleSize = 16; Load(filename);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -