📄 sound_directsound.cxx
字号:
/*
* sound_directsound.cxx
*
* DirectX Sound driver implementation.
*
* Portable Windows Library
*
* Copyright (c) 2006-2007 Novacom, a division of IT-Optics
*
* 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 DirectSound Code is
* Vincent Luba <vincent.luba@novacom.be>
*
* Contributor(s): /
*
* $Revision: 19307 $
* $Author: rjongbloed $
* $Date: 2008-01-22 11:59:32 +0000 (Tue, 22 Jan 2008) $
*/
#pragma implementation "sound_directsound.h"
#include <ptlib.h>
#if defined(P_DIRECTSOUND) && ! defined(P_DIRECTSOUND_WINCE)
#include <ptlib/msos/ptlib/sound_directsound.h>
#include <math.h>
//#include <dxerr9.h> Doesn't seem to exist for me!
#define DXGetErrorString9(r) r
#pragma comment(lib, P_DIRECTSOUND_LIBRARY)
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
#define SAFE_DELETE_ARRAY(p) { if (p) { delete[] (p); (p)=NULL; } }
/* Instantiate the PWLIBsound plugin*/
PCREATE_SOUND_PLUGIN(DirectSound, PSoundChannelDirectSound)
/* Callback function used to collect data from enumerated DirectX devices */
INT_PTR CALLBACK DSoundEnumCallback( GUID* pGUID, LPSTR strDesc, LPSTR strDrvName,
VOID* devices );
///////////////////////////////////////////////////////////////////////////////
/*
* DESC : Default Constructor
* BEHAVIOUR :
* RETURN :
*/
PSoundChannelDirectSound::PSoundChannelDirectSound()
{
Construct();
}
/*
* DESC : PSoundChannelDirectSound Constructor. Creates the object and Initialise the device
* BEHAVIOUR :
* RETURN :
*/
PSoundChannelDirectSound::PSoundChannelDirectSound (const PString &device,
Directions dir,
unsigned numChannels,
unsigned sampleRate,
unsigned bitsPerSample)
{
Construct();
Open (device, dir, numChannels, sampleRate, bitsPerSample);
}
/*
* DESC : DirectSound Object destructor
* BEHAVIOUR : Close any opened channels
* RETURN :
*/
PSoundChannelDirectSound::~PSoundChannelDirectSound()
{
PTRACE (4, "dsound\t (" << ((mDirection == Player) ? "Playback" : "Recording") << " ~PSoundChannelDirectSound");
Close();
}
/*
* DESC : Initialize Object variable
* BEHAVIOUR : Every member set to NULL
* RETURN :
*/
void
PSoundChannelDirectSound::Construct()
{
mAudioPlaybackBuffer = NULL;
mAudioPrimaryPlaybackBuffer = NULL;
sAudioPlaybackDevice = NULL;
sAudioCaptureDevice = NULL;
mAudioCaptureBuffer = NULL;
mDXBufferSize = 0;
mStreaming = true;
mOutburst = 0;
mVolume = 0;
}
/*
* DESC : Opens a device with format specifications
* BEHAVIOUR : Fetch the requested device GUID, then initialize the Device.
* RETURN :
*/
PBoolean
PSoundChannelDirectSound::Open (const PString & _device,
Directions _dir,
unsigned _numChannels,
unsigned _sampleRate,
unsigned _bitsPerSample)
{
mDirection = _dir;
mNumChannels = _numChannels;
mSampleRate = _sampleRate;
mBitsPerSample = _bitsPerSample;
GUID deviceGUID;
if (!GetDeviceID (_device, &deviceGUID))
return false;
PTRACE (4, "dsound\tOpen " << ((mDirection == Player) ? "Playback" : "Recording") << " Channel\n"
<< " --> mNumChannels " << mNumChannels << '\n'
<< " --> mSampleRate" << mSampleRate << '\n'
<< " --> mBitsPerSample" << mBitsPerSample);
Close();
SetFormat (_numChannels,
_sampleRate,
_bitsPerSample);
PBoolean result = (mDirection == Recorder) ?
InitCaptureDevice (&deviceGUID) :
InitPlaybackDevice (&deviceGUID);
if (!result) {
PTRACE(4, "dsound\tCould not open device " << ((mDirection == Player) ? "Playback" : "Recording") << " failed");
}
return result;
}
/*
* DESC : Provides Default device names
* BEHAVIOUR : Defines 'Default' as the default interface's name
* RETURN : PString
*/
PString
PSoundChannelDirectSound::GetDefaultDevice (Directions /*dir*/)
{
return PString ("Default");
}
/*
* DESC :
* BEHAVIOUR :
* RETURN :
*/
DirectSoundDevices
PSoundChannelDirectSound::DevicesEnumerators (Directions dir)
{
DirectSoundDevices devices;
if (dir == Recorder)
DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK)DSoundEnumCallback,
(void*) &devices);
else
DirectSoundEnumerate( (LPDSENUMCALLBACK)DSoundEnumCallback,
(void*) &devices);
if (devices.names.GetSize () > 1)
{
GUID pTemp = (dir == Player) ? DSDEVID_DefaultPlayback : DSDEVID_DefaultCapture;
devices.guids [devices.names.GetSize ()] = pTemp;
devices.names += "Default";
}
return devices;
}
/*
* DESC :
* BEHAVIOUR :
* RETURN :
*/
PBoolean
PSoundChannelDirectSound::GetDeviceID (PString deviceName, GUID *pGUID)
{
PTRACE (4, "dsound\tGet " << ((mDirection == Player) ? "Playback" : "Recording") << " Device ID for " << deviceName);
*pGUID = (mDirection == Player) ? DSDEVID_DefaultPlayback : DSDEVID_DefaultCapture;
DirectSoundDevices devices = DevicesEnumerators (mDirection);
PINDEX idx = devices.names.GetStringsIndex (deviceName);
if (idx != P_MAX_INDEX)
*pGUID = devices.guids[idx];
return true;
}
/*
* DESC : Provides a list of detected devices human readable names
* BEHAVIOUR : Returns the names array of enumerated devices
* RETURN : Names as PStringArray
*/
PStringArray
PSoundChannelDirectSound::GetDeviceNames (Directions dir)
{
PTRACE (4, "dsound\tGetDeviceNames " << ((dir == Player) ? "Playback" : "Recording") << " device Name");
DirectSoundDevices devices = DevicesEnumerators (dir);
return devices.names;
}
/*
* DESC :
* BEHAVIOUR :
* RETURN :
*/
INT_PTR CALLBACK
DSoundEnumCallback( GUID* pGUID, LPSTR strDesc, LPSTR /*strDrvName*/,
void* device)
{
DirectSoundDevices* devices_array = (DirectSoundDevices *) device;
if( pGUID )
{
if (devices_array->names.GetSize () < 20)
{
GUID *pTemp = & (*devices_array).guids [devices_array->names.GetSize ()];
memcpy( pTemp, pGUID, sizeof(GUID) );
devices_array->names += strDesc;
PTRACE (4, "dsound\tDevice --> " << strDesc );
} else
return PTrue;
}
return PTrue;
}
/*
* DESC :
* BEHAVIOUR :
* RETURN :
*/
PBoolean
PSoundChannelDirectSound::InitPlaybackDevice(GUID *pGUID) {
HRESULT hr;
PTRACE (4, "dsound\t" << ((mDirection == Player) ? "Playback" : "Recording") << " InitPlaybackDevice");
hr = DirectSoundCreate8 (pGUID,
&sAudioPlaybackDevice,
NULL);
if (FAILED (hr))
{
PTRACE (4, "dsound\tCould not create playback device " << DXGetErrorString9 (hr));
return false;
}
HWND hWnd = GetForegroundWindow();
if (hWnd == NULL)
hWnd = GetDesktopWindow();
hr = sAudioPlaybackDevice->SetCooperativeLevel (hWnd,
DSSCL_PRIORITY);
if (FAILED (hr))
{
PTRACE (4, "dsound\tCould not set cooperative level " << DXGetErrorString9 (hr));
return false;
}
DSBUFFERDESC dsbd;
ZeroMemory(&dsbd, sizeof(dsbd));
dsbd.dwSize = sizeof(DSBUFFERDESC);
dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
dsbd.dwBufferBytes = 0;
dsbd.lpwfxFormat = NULL;
if ( FAILED(sAudioPlaybackDevice->CreateSoundBuffer(&dsbd,
&mAudioPrimaryPlaybackBuffer,
NULL)) )
{
PTRACE (4, "dsound\tCould not create primary buffer " << DXGetErrorString9 (hr));
return false;
}
return PTrue;
}
/*
* DESC :
* BEHAVIOUR :
* RETURN :
*/
PBoolean
PSoundChannelDirectSound::InitCaptureDevice(GUID *pGUID) {
HRESULT hr;
hr = DirectSoundCaptureCreate8 (pGUID,
&sAudioCaptureDevice,
NULL);
if (FAILED (hr))
{
PTRACE (4, "dsound\tCould not create Capture device " << DXGetErrorString9 (hr));
return false;
}
return PTrue;
}
/*
* DESC :
* BEHAVIOUR :
* RETURN :
*/
PBoolean
PSoundChannelDirectSound::Setup()
{
PTRACE (4, "dsound\t" << ((mDirection == Player) ? "Playback" : "Recording") << " Setup");
PBoolean no_error = PTrue;
return no_error;
}
/*
* DESC :
* BEHAVIOUR :
* RETURN :
*/
PBoolean
PSoundChannelDirectSound::Close()
{
PTRACE (4, "dsound\tClosing " << ((mDirection == Player) ? "Playback" : "Recording") << ") Channel");
PWaitAndSignal mutex(bufferMutex);
switch (mDirection)
{
case Player:
if (mAudioPlaybackBuffer)
mAudioPlaybackBuffer->Stop ();
SAFE_RELEASE(mAudioPlaybackBuffer);
SAFE_RELEASE(mAudioPrimaryPlaybackBuffer);
SAFE_RELEASE(sAudioPlaybackDevice);
break;
case Recorder:
if (mAudioCaptureBuffer)
mAudioCaptureBuffer->Stop ();
SAFE_RELEASE(mAudioCaptureBuffer);
SAFE_RELEASE(sAudioCaptureDevice);
break;
}
isInitialised = false;
return PTrue;
}
/*
* DESC : Compute the freeSpace in a DirectX Circular Buffer
* BEHAVIOUR :
* RETURN : the size
*/
DWORD
PSoundChannelDirectSound::GetDXBufferFreeSpace ()
{
DWORD dwCursor = 0;
PINDEX freeSpace;
if (mDirection == Player)
mAudioPlaybackBuffer->GetCurrentPosition (&dwCursor, NULL);
else
mAudioCaptureBuffer->GetCurrentPosition (&dwCursor, NULL);
freeSpace = mDXBufferSize - (mDXOffset - dwCursor);
if (freeSpace > mDXBufferSize)
freeSpace -= mDXBufferSize; // write_offset < play_offset
return freeSpace;
}
/*
* DESC : Write Method is called by the playback device
* BEHAVIOUR: It writes (len) bytes of input data (*buf) into the device circular buffer.
* In case data to write are bigger than the free space left in the buffer, it writes them than sleep while directx cursor move forward to leave
* RETURN : PTrue if successful and PFalse otherwise.
*/
PBoolean
PSoundChannelDirectSound::Write (const void *buf,
PINDEX len)
{
PINDEX to_write = len, written = 0;
BYTE * input_buffer = (BYTE*) buf;
if (!isInitialised)
{
PTRACE (4, "dsound\tWrite Failed: Device not initialised :");
return false;
}
//Wait for Mutex signal
PWaitAndSignal mutex(bufferMutex);
lastWriteCount = 0;
while (to_write > mOutburst)
{
/*
//Adjust to blockalign
if (mOutburst != 0)
write_in_cycle = (write_in_cycle / mOutburst ) * mOutburst;
*/
/* Write data from buf to circular buffer */
written = WriteToDXBuffer (input_buffer,
PMIN ((PINDEX)GetDXBufferFreeSpace (), to_write));
if (HasPlayCompleted ())
{
mAudioPlaybackBuffer->Play (0,
0,
mStreaming ? DSBPLAY_LOOPING : 0L);
}
//Move the cursor into the data buffer
input_buffer += written;
//Update the written buffer count for PWLIB usage
lastWriteCount += written;
//Set the count of buffers left to write
to_write -= written;
/* Wait as buffer is played */
FlushBuffer ();
}
return true;
}
/*
* DESC : Read Method is called by the recording device
* BEHAVIOUR: It reads (len) bytes from the device circular buffer to an input data (*buf).
* RETURN : PTrue if successful and PFalse otherwise.
*/
PBoolean
PSoundChannelDirectSound::Read (void * buf, PINDEX len)
{
PINDEX read = 0, to_read = len;
BYTE * output_buffer = (BYTE*) buf;
PWaitAndSignal mutex(bufferMutex);
if (!isInitialised)
{
PTRACE (4, "dsound\tRead : Device not initialised ");
return false;
}
lastReadCount = 0;
while (to_read > mOutburst)
{
/* Will read from device buffer minimum between the data left to read, and the available space */
read = ReadFromDXBuffer (output_buffer,
PMIN ((PINDEX)GetDXBufferFreeSpace (), to_read));
to_read -= read;
lastReadCount += read;
output_buffer += read; /* Increment the buffer pointer */
/* Wait as buffer is being played */
FlushBuffer ();
}
return true;
}
/*
* DESC: Writes (len) bytes from the buffer (*buf) to DirectX sound device buffer
* BEHAVIOUR : Locks the buffer on the requested size; In case buffer was lost, tries to restore it.
* Copies the data into the buffer
* Unlock the buffer
* RETURN : Returns the size actually written
*/
PINDEX
PSoundChannelDirectSound::WriteToDXBuffer (const void *buf,
PINDEX len)
{
HRESULT hr;
LPVOID lpvWrite1, lpvWrite2;
DWORD dwLength1, dwLength2;
PINDEX written = 0;
/*** Lock the buffer ***/
hr = mAudioPlaybackBuffer->Lock (mDXOffset,
len,
&lpvWrite1,
&dwLength1,
&lpvWrite2,
&dwLength2,
0L);
if (hr == DSERR_BUFFERLOST)
{
//Buffer was lost, need to restore it
PTRACE (4, "dsound\tPlayback buffer was lost, Need to restore.");
mAudioPlaybackBuffer->Restore ();
hr = mAudioPlaybackBuffer->Lock (mDXOffset,
len,
&lpvWrite1,
&dwLength1,
&lpvWrite2,
&dwLength2,
0L);
}
if (!FAILED (hr))
{
/*** Copy memory into buffer ***/
memcpy (lpvWrite1, buf, dwLength1);
if (lpvWrite2 != NULL)
memcpy (lpvWrite2, (BYTE *) buf + dwLength1, dwLength2);
written = dwLength1 + dwLength2;
/*** Unlock the buffer ***/
mAudioPlaybackBuffer->Unlock (lpvWrite1,
dwLength1,
lpvWrite2,
dwLength2);
//Move write cursor
mDXOffset += written;
mDXOffset %= mDXBufferSize;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -