988 lines
28 KiB
C++
988 lines
28 KiB
C++
/*==========================================================================
|
|
*
|
|
* Copyright (C) 1999 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: sndutils.cpp
|
|
* Content:
|
|
* This module contains the implementation of sound related utility
|
|
* functions. Functions in this module manipulate WAVEFORMATEX
|
|
* structures and provide full duplex initialization / testing
|
|
* facilities.
|
|
*
|
|
* This module also contains the routines used to measure peak
|
|
* of an audio buffer and for voice activation.
|
|
*
|
|
* History:
|
|
* Date By Reason
|
|
* ==== == ======
|
|
* 07/16/99 rodtoll Created
|
|
* 07/30/99 rodtoll Updated util functions to take GUIDs and allow for
|
|
* users to pre-create capture/playback devices and
|
|
* pass them into InitXXXXDuplex
|
|
* 08/25/99 rodtoll General Cleanup/Modifications to support new
|
|
* compression sub-system.
|
|
* 08/30/99 rodtoll Added new playback format param to sound init
|
|
* 09/03/99 rodtoll Fixed return codes on InitFullDuplex
|
|
* 09/20/99 rodtoll Now checks for invalid GUIDs for playback/record
|
|
* 10/05/99 rodtoll Added DPF_MODNAMEs
|
|
* 10/29/99 rodtoll Bug #113726 - Fixed memory leak when full duplex
|
|
* fails caused by architecture update.
|
|
* 11/12/99 rodtoll Updated full duplex test to use new abstracted recording
|
|
* and playback systems.
|
|
* rodtoll Updated to allow passing of sounddeviceconfig flags in dwflags
|
|
* parameter to init is effected by the flags specified by user
|
|
* rodtoll Sound buffers (rec and playback) are now set to silence before
|
|
* recording/playback is started.
|
|
* 11/22/99 rodtoll Removed unnessessary set of recording buffer to silence.
|
|
* 12/01/99 rodtoll Bug #115783 - Will always adjust volume of default device
|
|
* Updated for new parameters added by above bug.
|
|
* 12/08/99 rodtoll Bug #121054 - Support for capture focus and removed flags
|
|
* from buffer, allow dsound to manage buffer location.
|
|
* 01/21/2000 pnewson Fixed error cleanup code in InitHalfDuplex
|
|
* 01/27/2000 rodtoll Updated tests to accept buffer descriptions and play flags/priority
|
|
* 02/10/2000 rodtoll Removed more capture focus
|
|
* 02/23/2000 rodtoll Fix to allow to run on dsound7.
|
|
* 05/19/2000 rodtoll Bug #35395 - Unable to run two copies of DPVHELP on same system without
|
|
* DirectX 8 installed.
|
|
* 06/21/2000 rodtoll Bug #35767 - Must implement ability to use effects processing on voice buffers
|
|
* Updated sound initialization routines to handle buffers being passed in.
|
|
* 07/12/2000 rodtoll Bug #31468 - Add diagnostic spew to logfile to show what is failing the HW Wizard
|
|
* 10/04/2000 rodtoll Bug #43510 - DPVOICE: Apps receive a DVMSGID_SESSIONLOST w/DVERR_LOCKEDBUFFER
|
|
* 01/04/2001 rodtoll WinBug #94200 - Remove stray comments
|
|
* 01/26/2001 rodtoll WINBUG #293197 - DPVOICE: [STRESS} Stress applications cannot tell difference between out of memory and internal errors.
|
|
* Remap DSERR_OUTOFMEMORY to DVERR_OUTOFMEMORY instead of DVERR_SOUNDINITFAILURE.
|
|
* Remap DSERR_ALLOCATED to DVERR_PLAYBACKSYSTEMERROR instead of DVERR_SOUNDINITFAILURE.
|
|
* 04/12/2001 kareemc WINBUG #360971 - Wizard Memory Leaks
|
|
*
|
|
***************************************************************************/
|
|
|
|
#include "dxvutilspch.h"
|
|
|
|
|
|
#undef DPF_SUBCOMP
|
|
#define DPF_SUBCOMP DN_SUBCOMP_VOICE
|
|
|
|
#define DSERRBREAK_NAME "DSASSERT"
|
|
|
|
DNCRITICAL_SECTION g_csDSDebug;
|
|
|
|
CHAR g_szLastDirectSoundAPI[100] = "";
|
|
HRESULT g_hrLastDirectSoundResult = DS_OK;
|
|
BOOL g_fDSErrorBreak = FALSE;
|
|
|
|
void DSERTRACK_Update( const char *szAPICall, HRESULT hrResult )
|
|
{
|
|
DNEnterCriticalSection( &g_csDSDebug );
|
|
if( SUCCEEDED( g_hrLastDirectSoundResult ) )
|
|
{
|
|
g_hrLastDirectSoundResult = hrResult;
|
|
strcpy( g_szLastDirectSoundAPI , szAPICall );
|
|
}
|
|
DNLeaveCriticalSection( &g_csDSDebug );
|
|
}
|
|
|
|
void DSERRTRACK_Reset()
|
|
{
|
|
DNEnterCriticalSection( &g_csDSDebug );
|
|
g_hrLastDirectSoundResult = DS_OK;
|
|
g_szLastDirectSoundAPI[0] = 0;
|
|
DNLeaveCriticalSection( &g_csDSDebug );
|
|
}
|
|
|
|
BOOL DSERRTRACK_Init()
|
|
{
|
|
if (!DNInitializeCriticalSection( &g_csDSDebug ))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
// Load the setting for the directsound assert
|
|
g_fDSErrorBreak = GetProfileIntA( "DirectPlay8", DSERRBREAK_NAME, FALSE );
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void DSERRTRACK_UnInit()
|
|
{
|
|
DNDeleteCriticalSection( &g_csDSDebug );
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "DV_SetupBufferDesc"
|
|
void DV_SetupBufferDesc( LPDSBUFFERDESC lpdsBufferDesc, LPDSBUFFERDESC lpdsBufferSource, LPWAVEFORMATEX lpwfxFormat, DWORD dwBufferSize )
|
|
{
|
|
// Confirm specified buffer description is valid
|
|
if( lpdsBufferSource != NULL )
|
|
{
|
|
if( lpdsBufferSource->dwSize == sizeof( DSBUFFERDESC1 ) )
|
|
{
|
|
memcpy( lpdsBufferDesc, lpdsBufferSource, sizeof( DSBUFFERDESC1 ) );
|
|
}
|
|
else
|
|
{
|
|
memcpy( lpdsBufferDesc, lpdsBufferSource, sizeof( DSBUFFERDESC ) );
|
|
}
|
|
|
|
// We require the following flags, at a minimum so they should always be set
|
|
lpdsBufferDesc->dwFlags |= DSBCAPS_CTRL3D | DSBCAPS_CTRLVOLUME | DSBCAPS_GETCURRENTPOSITION2;
|
|
}
|
|
// User did not specify a buffer description, let's use our own!
|
|
else
|
|
{
|
|
lpdsBufferDesc->dwSize = sizeof( DSBUFFERDESC );
|
|
lpdsBufferDesc->dwFlags = DSBCAPS_CTRL3D | DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2;
|
|
lpdsBufferDesc->dwBufferBytes = 0;
|
|
lpdsBufferDesc->dwReserved = 0;
|
|
lpdsBufferDesc->lpwfxFormat = NULL;
|
|
lpdsBufferDesc->guid3DAlgorithm = DS3DALG_DEFAULT;
|
|
}
|
|
|
|
lpdsBufferDesc->lpwfxFormat = lpwfxFormat;
|
|
lpdsBufferDesc->dwBufferBytes = dwBufferSize;
|
|
|
|
}
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "SetRecordBufferToSilence"
|
|
HRESULT SetPlaybackBufferToSilence( CAudioPlaybackBuffer *pRecBuffer, LPWAVEFORMATEX lpwfxFormat )
|
|
{
|
|
HRESULT hr;
|
|
LPVOID pBufferPtr1, pBufferPtr2;
|
|
DWORD dwBufferSize1, dwBufferSize2;
|
|
|
|
hr = pRecBuffer->Lock( 0, 0, &pBufferPtr1, &dwBufferSize1, &pBufferPtr2, &dwBufferSize2, DSBLOCK_ENTIREBUFFER );
|
|
|
|
DSERTRACK_Update( "Lock", hr );
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "Lock() failed during silence write hr=0x%x", hr );
|
|
return hr;
|
|
}
|
|
|
|
memset( pBufferPtr1, (lpwfxFormat->wBitsPerSample==8) ? 0x80 : 0x00, dwBufferSize1 );
|
|
|
|
hr = pRecBuffer->UnLock( pBufferPtr1, dwBufferSize1, pBufferPtr2, dwBufferSize2 );
|
|
|
|
DSERTRACK_Update( "UnLock", hr );
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "Unlock() failed uffer unlock failed hr=0x%x", hr );
|
|
return hr;
|
|
}
|
|
|
|
return DV_OK;
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "InitHalfDuplex"
|
|
// InitHalfDuplex
|
|
//
|
|
// This function initializes the playback system for the
|
|
// specified compression type and the specified playback
|
|
// format. This function is used to initialize
|
|
// the AudioPlaybackDevice and AudioPlaybackBuffer.
|
|
//
|
|
// It also starts the audio buffer which is used for voice
|
|
// output playing. (In looping mode).
|
|
//
|
|
// Parameters:
|
|
// HWND hwnd -
|
|
// Window handle for the window where the output will
|
|
// be associated
|
|
// ARDID playbackDeviceID -
|
|
// The deviceID for the device which will be used for
|
|
// playback
|
|
// CAudioPlaybackDevice ** -
|
|
// A pointer to a pointer which will contain a pointer
|
|
// to a newly created CAudioPlaybackDevice which will
|
|
// represent the playback device on success.
|
|
// CAudioPlaybackBuffer ** -
|
|
// A pointer to a pointer which will contain a pointer
|
|
// to a newly created CAudioPlaybacKbuffer which will
|
|
// be used for voice audio output on success.
|
|
// CompressionType ct -
|
|
// The type of compression which will be in use. Used
|
|
// to determine buffer sizes etc.
|
|
// WAVEFORMATEX *primaryFormat -
|
|
// Pointer to a WAVEFORMATEX structure describing the
|
|
// format of the voice output. (This will also be used
|
|
// to set the primary format of the output device if
|
|
// normal is set to false).
|
|
// bool normal -
|
|
// Specifies if normal mode should be used or not.
|
|
// (Only used when using the DirectSound playback
|
|
// system. Set to true for normal cooperative mode,
|
|
// false for priority mode).
|
|
//
|
|
// Returns:
|
|
// bool -
|
|
// Returns true if playback was initializes succesfully,
|
|
// false if initialization fails.
|
|
//
|
|
HRESULT InitHalfDuplex(
|
|
HWND hwnd,
|
|
const GUID &guidPlayback,
|
|
CAudioPlaybackDevice **audioPlaybackDevice,
|
|
LPDSBUFFERDESC lpdsBufferDesc,
|
|
CAudioPlaybackBuffer **audioPlaybackBuffer,
|
|
GUID guidCT,
|
|
WAVEFORMATEX *primaryFormat,
|
|
WAVEFORMATEX *lpwfxPlayFormat,
|
|
DWORD dwPlayPriority,
|
|
DWORD dwPlayFlags,
|
|
DWORD dwFlags
|
|
)
|
|
{
|
|
DWORD frameSize;
|
|
HRESULT hr;
|
|
DWORD dwBufferSize;
|
|
BOOL fPriorityMode;
|
|
DSBUFFERDESC dsBufferDesc;
|
|
BOOL fPlaybackDeviceAllocated = FALSE;
|
|
BOOL fPlaybackBufferAllocated = FALSE;
|
|
|
|
fPriorityMode = !( dwFlags & DVSOUNDCONFIG_NORMALMODE );
|
|
|
|
// *audioPlaybackBuffer = NULL;
|
|
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "HALFDUPLEX INIT: Begin ==========" );
|
|
|
|
LPDVFULLCOMPRESSIONINFO lpdvfInfo;
|
|
|
|
hr = DVCDB_GetCompressionInfo( guidCT, &lpdvfInfo );
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "Error loading compression type: hr = 0x%x", hr );
|
|
goto INIT_EXIT_ERROR2;
|
|
}
|
|
|
|
if( (*audioPlaybackDevice) == NULL )
|
|
{
|
|
#ifdef __WAVESUBSYSTEM
|
|
if( !(dwFlags & DVSOUNDCONFIG_FORCEWAVEOUT) )
|
|
{
|
|
#endif
|
|
// Create the object to represent the device using the playback subsystem's
|
|
// CreateDevice function
|
|
(*audioPlaybackDevice) = new CDirectSoundPlaybackDevice();
|
|
fPlaybackDeviceAllocated = TRUE;
|
|
|
|
if( *audioPlaybackDevice == NULL )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "> Out of memory" );
|
|
hr = DVERR_OUTOFMEMORY;
|
|
goto INIT_EXIT_ERROR2;
|
|
}
|
|
|
|
hr = (*audioPlaybackDevice)->Initialize( guidPlayback, hwnd, primaryFormat, fPriorityMode );
|
|
|
|
#ifndef __WAVESUBSYSTEM
|
|
if( FAILED( hr ) )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "Unable to initialize playback. hr=0x%x", hr );
|
|
goto INIT_EXIT_ERROR2;
|
|
}
|
|
#endif
|
|
|
|
#ifdef __WAVESUBSYSTEM
|
|
}
|
|
|
|
if( dwFlags & DVSOUNDCONFIG_FORCEWAVEOUT ||
|
|
((dwFlags & DVSOUNDCONFIG_ALLOWWAVEOUT) && FAILED( hr ))
|
|
)
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "Could not initialize directsound, defaulting to waveout hr=0x%x", hr );
|
|
delete (*audioPlaybackDevice);
|
|
|
|
(*audioPlaybackDevice) = new CWaveOutPlaybackDevice( );
|
|
fPlaybackDeviceAllocated = TRUE;
|
|
|
|
if( (*audioPlaybackDevice) == NULL )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "> Out of memory" );
|
|
hr = DVERR_OUTOFMEMORY;
|
|
goto INIT_EXIT_ERROR2;
|
|
}
|
|
|
|
hr = (*audioPlaybackDevice)->Initialize( guidPlayback, hwnd, primaryFormat, fPriorityMode );
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "Could not initalize waveOut. Init failed hr=0x%x", hr );
|
|
goto INIT_EXIT_ERROR2;
|
|
}
|
|
}
|
|
else if( FAILED( hr ) )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "Unable to initialize playback. hr=0x%x", hr );
|
|
goto INIT_EXIT_ERROR2;
|
|
}
|
|
#endif
|
|
// At this point we should have a valid device, waveOut or DirectSound
|
|
}
|
|
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "> Play init" );
|
|
|
|
// Create a buffer if the user didn't specify one
|
|
if( !(*audioPlaybackBuffer) )
|
|
{
|
|
frameSize = DVCDB_CalcUnCompressedFrameSize( lpdvfInfo, lpwfxPlayFormat );
|
|
dwBufferSize = lpdvfInfo->dwFramesPerBuffer * frameSize;
|
|
|
|
DV_SetupBufferDesc( &dsBufferDesc, lpdsBufferDesc, lpwfxPlayFormat, dwBufferSize );
|
|
|
|
// Create the audio buffer which will be used for output
|
|
hr = (*audioPlaybackDevice)->CreateBuffer( &dsBufferDesc, frameSize, audioPlaybackBuffer);
|
|
fPlaybackBufferAllocated = TRUE;
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "Unable to create sound buffer. hr=0x%x", hr );
|
|
goto INIT_EXIT_ERROR2;
|
|
}
|
|
}
|
|
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "> Play init 2" );
|
|
|
|
hr = SetPlaybackBufferToSilence( *audioPlaybackBuffer, lpwfxPlayFormat );
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "> Unable to set playback to silence" );
|
|
goto INIT_EXIT_ERROR2;
|
|
}
|
|
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "> Play init 3" );
|
|
|
|
// Start the audio playback buffer playing
|
|
hr = (*audioPlaybackBuffer)->Play( dwPlayPriority, dwPlayFlags );
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
DPFX(DPFPREP, DVF_ERRORLEVEL, "> Can't play" );
|
|
goto INIT_EXIT_ERROR2;
|
|
}
|
|
|
|
Diagnostics_Write( DVF_INFOLEVEL, "Half Duplex Init Result = DV_OK " );
|
|
|
|
return DV_OK;
|
|
|
|
// Handle errors
|
|
INIT_EXIT_ERROR2:
|
|
|
|
if( fPlaybackBufferAllocated && *audioPlaybackBuffer != NULL )
|
|
{
|
|
delete *audioPlaybackBuffer;
|
|
*audioPlaybackBuffer = NULL;
|
|
}
|
|
|
|
if( fPlaybackDeviceAllocated && *audioPlaybackDevice != NULL )
|
|
{
|
|
delete *audioPlaybackDevice;
|
|
*audioPlaybackDevice = NULL;
|
|
}
|
|
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "Half Duplex Init Result = 0x%x", hr );
|
|
|
|
return hr;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "InitializeRecordBuffer"
|
|
HRESULT InitializeRecordBuffer( HWND hwnd, LPDVFULLCOMPRESSIONINFO lpdvfInfo, CAudioRecordDevice *parecDevice, CAudioRecordBuffer **pparecBuffer, DWORD dwFlags )
|
|
{
|
|
WAVEFORMATEX *lpwfxRecordFormat;
|
|
DSCBUFFERDESC1 dscdesc;
|
|
DWORD dwFrameSize;
|
|
HRESULT hr;
|
|
|
|
for( DWORD dwIndex = 0; dwIndex < GetNumRecordFormats(); dwIndex++ )
|
|
{
|
|
lpwfxRecordFormat = GetRecordFormat( dwIndex );
|
|
|
|
dwFrameSize = DVCDB_CalcUnCompressedFrameSize( lpdvfInfo, lpwfxRecordFormat );
|
|
|
|
memset( &dscdesc, 0x00, sizeof( DSCBUFFERDESC1 ) );
|
|
dscdesc.dwSize = sizeof( DSCBUFFERDESC1 );
|
|
dscdesc.dwFlags = 0;
|
|
dscdesc.lpwfxFormat = lpwfxRecordFormat;
|
|
dscdesc.dwBufferBytes = dwFrameSize*lpdvfInfo->dwFramesPerBuffer;
|
|
|
|
if( !(dwFlags & DVSOUNDCONFIG_NOFOCUS) )
|
|
{
|
|
dscdesc.dwFlags |= DSCBCAPS_FOCUSAWARE;
|
|
|
|
if( dwFlags & DVSOUNDCONFIG_STRICTFOCUS )
|
|
{
|
|
dscdesc.dwFlags |= DSCBCAPS_STRICTFOCUS;
|
|
}
|
|
}
|
|
|
|
hr = parecDevice->CreateBuffer( (DSCBUFFERDESC *) &dscdesc, hwnd, dwFrameSize, pparecBuffer );
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
DPFX(DPFPREP, DVF_WARNINGLEVEL, "Could not initialize %d hz, %d bits, %s (hr=0x%x)", lpwfxRecordFormat->nSamplesPerSec,
|
|
lpwfxRecordFormat->wBitsPerSample, (lpwfxRecordFormat->nChannels==1) ? "Mono" : "Stereo", hr );
|
|
continue;
|
|
|
|
}
|
|
else
|
|
{
|
|
Diagnostics_Write( DVF_INFOLEVEL, "Recording Initialized. Format=" );
|
|
Diagnositcs_WriteWAVEFORMATEX( DVF_INFOLEVEL, lpwfxRecordFormat );
|
|
}
|
|
|
|
hr = (*pparecBuffer)->Record(TRUE);
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
DPFX(DPFPREP, DVF_WARNINGLEVEL, "Could not start rec at %d hz, %d bits, %s (hr=0x%x)", lpwfxRecordFormat->nSamplesPerSec,
|
|
lpwfxRecordFormat->wBitsPerSample, (lpwfxRecordFormat->nChannels==1) ? "Mono" : "Stereo", hr );
|
|
delete (*pparecBuffer);
|
|
(*pparecBuffer) = NULL;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
Diagnostics_Write( DVF_INFOLEVEL, "Recording Started. Format=" );
|
|
Diagnositcs_WriteWAVEFORMATEX( DVF_INFOLEVEL, lpwfxRecordFormat );
|
|
// Reset the directsound erros as we expect errors in this part and if we suceed we handled
|
|
// them.
|
|
return DV_OK;
|
|
}
|
|
|
|
}
|
|
|
|
return DVERR_RECORDSYSTEMERROR;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "InitFullDuplex"
|
|
// InitFullDuplex
|
|
//
|
|
// The tricky part.
|
|
//
|
|
// This function is responsible for initializing the system into full duplex
|
|
// mode using the specified parameters. This function will create and
|
|
// initialize the playback and record devices as well as start the
|
|
// playback device playing and the recording device recording. (On success).
|
|
// This is neccessary because the order of Play and Record and device
|
|
// creation is important.
|
|
//
|
|
// Parameters:
|
|
// HWND hwnd -
|
|
// Window handle for the window where the output will
|
|
// be associated
|
|
// ARDID playbackDeviceID -
|
|
// The deviceID for the device which will be used for
|
|
// playback
|
|
// CAudioPlaybackDevice ** -
|
|
// A pointer to a pointer which will contain a pointer
|
|
// to a newly created CAudioPlaybackDevice which will
|
|
// represent the playback device on success.
|
|
// CAudioPlaybackBuffer ** -
|
|
// A pointer to a pointer which will contain a pointer
|
|
// to a newly created CAudioPlaybacKbuffer which will
|
|
// be used for voice audio output on success.
|
|
// ARDID recordDeviceID -
|
|
// The ARDID for the device which will be used for recording.
|
|
// CAudioRecordSubSystem *recordSubSystem -
|
|
// This parameter is a pointer to the object representing
|
|
// the subsystem which will be used for recording.
|
|
// CAudioRecordDevice ** -
|
|
// A pointer to a pointer which will contain a newly
|
|
// create CAudioRecordDevice for voice recording on
|
|
// success.
|
|
// CompressionType ct -
|
|
// The type of compression which will be in use. Used
|
|
// to determine buffer sizes etc.
|
|
// WAVEFORMATEX *primaryFormat -
|
|
// Pointer to a WAVEFORMATEX structure describing the
|
|
// format of the voice output. (This will also be used
|
|
// to set the primary format of the output device if
|
|
// normal is set to false).
|
|
// bool aso -
|
|
// This parameter controls the ASO option. The ASO
|
|
// option controls the "Startup Order". Enabling
|
|
// this option allows full duplex to be initialized
|
|
// on some troublesome cards.
|
|
// bool normal -
|
|
// Specifies if normal mode should be used or not.
|
|
// (Only used when using the DirectSound playback
|
|
// system. Set to true for normal cooperative mode,
|
|
// false for priority mode).
|
|
//
|
|
// Returns:
|
|
// bool - true on successful full duplex initialization,
|
|
// false on failure.
|
|
//
|
|
HRESULT InitFullDuplex(
|
|
HWND hwnd,
|
|
const GUID &guidPlayback,
|
|
CAudioPlaybackDevice **audioPlaybackDevice,
|
|
LPDSBUFFERDESC lpdsBufferDesc,
|
|
CAudioPlaybackBuffer **audioPlaybackBuffer,
|
|
const GUID &guidRecord,
|
|
CAudioRecordDevice **audioRecordDevice,
|
|
CAudioRecordBuffer **audioRecordBuffer,
|
|
GUID guidCT,
|
|
WAVEFORMATEX *primaryFormat,
|
|
WAVEFORMATEX *lpwfxPlayFormat,
|
|
BOOL aso,
|
|
DWORD dwPlayPriority,
|
|
DWORD dwPlayFlags,
|
|
DWORD dwFlags
|
|
)
|
|
{
|
|
DWORD frameSize;
|
|
DWORD dwBufferSize;
|
|
HRESULT hr;
|
|
DSBUFFERDESC dsbdesc;
|
|
BOOL fPriorityMode;
|
|
BOOL fPlaybackDeviceAllocated = FALSE;
|
|
BOOL fPlaybackBufferAllocated = FALSE;
|
|
BOOL fRecordDeviceAllocated = FALSE;
|
|
|
|
fPriorityMode = !(dwFlags & DVSOUNDCONFIG_NORMALMODE);
|
|
|
|
// *audioPlaybackBuffer = NULL;
|
|
*audioRecordBuffer = NULL;
|
|
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "FULLDUPLEX INIT: Begin ==========" );
|
|
|
|
LPDVFULLCOMPRESSIONINFO lpdvfInfo;
|
|
|
|
hr = DVCDB_GetCompressionInfo( guidCT, &lpdvfInfo );
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "Error loading compression type: hr = 0x%x", hr );
|
|
goto INIT_EXIT_ERROR;
|
|
}
|
|
|
|
if( (*audioPlaybackDevice) == NULL )
|
|
{
|
|
#ifdef __WAVESUBSYSTEM
|
|
if( !(dwFlags & DVSOUNDCONFIG_FORCEWAVEOUT) )
|
|
{
|
|
#endif
|
|
// Create the object to represent the device using the playback subsystem's
|
|
// CreateDevice function
|
|
(*audioPlaybackDevice) = new CDirectSoundPlaybackDevice();
|
|
fPlaybackDeviceAllocated = TRUE;
|
|
|
|
if( *audioPlaybackDevice == NULL )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "> Out of memory" );
|
|
hr = DVERR_OUTOFMEMORY;
|
|
goto INIT_EXIT_ERROR;
|
|
}
|
|
|
|
hr = (*audioPlaybackDevice)->Initialize( guidPlayback, hwnd, primaryFormat, fPriorityMode );
|
|
|
|
#ifndef __WAVESUBSYSTEM
|
|
if( FAILED( hr ) )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "Unable to initialize playback. hr=0x%x", hr );
|
|
goto INIT_EXIT_ERROR;
|
|
}
|
|
#endif
|
|
|
|
#ifdef __WAVESUBSYSTEM
|
|
}
|
|
|
|
if( dwFlags & DVSOUNDCONFIG_FORCEWAVEOUT ||
|
|
((dwFlags & DVSOUNDCONFIG_ALLOWWAVEOUT) && FAILED( hr )) )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "Could not initialize directsound, defaulting to waveout hr=0x%x", hr );
|
|
delete (*audioPlaybackDevice);
|
|
|
|
(*audioPlaybackDevice) = new CWaveOutPlaybackDevice();
|
|
fPlaybackDeviceAllocated = TRUE;
|
|
|
|
if( (*audioPlaybackDevice) == NULL )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "> Out of memory" );
|
|
hr = DVERR_OUTOFMEMORY;
|
|
goto INIT_EXIT_ERROR;
|
|
}
|
|
|
|
hr = (*audioPlaybackDevice)->Initialize( guidPlayback, hwnd, primaryFormat, fPriorityMode );
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "Could not initalize waveOut. Init failed hr=0x%x", hr );
|
|
goto INIT_EXIT_ERROR;
|
|
}
|
|
}
|
|
else if( FAILED( hr ) )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "Unable to initialize playback. hr=0x%x", hr );
|
|
goto INIT_EXIT_ERROR;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "> Play init" );
|
|
|
|
frameSize = DVCDB_CalcUnCompressedFrameSize( lpdvfInfo, lpwfxPlayFormat );
|
|
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "> Play init" );
|
|
|
|
dwBufferSize = lpdvfInfo->dwFramesPerBuffer * frameSize;
|
|
|
|
if( !(*audioPlaybackBuffer) )
|
|
{
|
|
DV_SetupBufferDesc( &dsbdesc, lpdsBufferDesc, lpwfxPlayFormat, dwBufferSize );
|
|
|
|
// Create the audio buffer which will be used for output
|
|
hr = (*audioPlaybackDevice)->CreateBuffer( &dsbdesc, frameSize, audioPlaybackBuffer);
|
|
fPlaybackBufferAllocated = TRUE;
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "Unable to create sound buffer. hr=0x%x", hr );
|
|
goto INIT_EXIT_ERROR;
|
|
}
|
|
}
|
|
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "> Play init 2" );
|
|
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "> Initing Recording" );
|
|
|
|
// We're creating the device..
|
|
if( (*audioRecordDevice) == NULL )
|
|
{
|
|
#ifdef __WAVESUBSYSTEM
|
|
if( !(dwFlags & DVSOUNDCONFIG_FORCEWAVEIN) )
|
|
{
|
|
#endif
|
|
(*audioRecordDevice) = new CDirectSoundCaptureRecordDevice();
|
|
fRecordDeviceAllocated = TRUE;
|
|
|
|
if( *audioRecordDevice == NULL )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "> Out of memory" );
|
|
hr = DVERR_OUTOFMEMORY;
|
|
goto INIT_EXIT_ERROR;
|
|
}
|
|
|
|
hr = (*audioRecordDevice)->Initialize( guidRecord );
|
|
|
|
// DSC Init passed, try getting a buffer
|
|
if( SUCCEEDED( hr ) )
|
|
{
|
|
hr = InitializeRecordBuffer( hwnd, lpdvfInfo, *audioRecordDevice, audioRecordBuffer, dwFlags );
|
|
if( FAILED( hr ) )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "Unable to initialize dsc buffer hr=0x%x", hr );
|
|
#ifndef __WAVESUBSYSTEM
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "Unable to initialize record. hr=0x%x", hr );
|
|
goto INIT_EXIT_ERROR;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
// Need to reset because we expect errors during initialization.
|
|
DSERRTRACK_Reset();
|
|
}
|
|
}
|
|
#ifndef __WAVESUBSYSTEM
|
|
else
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "Unable to initialize record. hr=0x%x", hr );
|
|
goto INIT_EXIT_ERROR;
|
|
}
|
|
#endif
|
|
#ifdef __WAVESUBSYSTEM
|
|
}
|
|
|
|
// DSC Init failed, try and get a waveIn device
|
|
if( dwFlags & DVSOUNDCONFIG_FORCEWAVEIN ||
|
|
((dwFlags & DVSOUNDCONFIG_ALLOWWAVEIN) && FAILED( hr )))
|
|
{
|
|
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "Could not initialize directsoundcapture, defaulting to wavein hr=0x%x", hr );
|
|
delete (*audioRecordDevice);
|
|
|
|
(*audioRecordDevice) = new CWaveInRecordDevice();
|
|
fRecordDeviceAllocated = TRUE;
|
|
|
|
if( (*audioRecordDevice) == NULL )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "> Out of memory" );
|
|
hr = DVERR_OUTOFMEMORY;
|
|
goto INIT_EXIT_ERROR;
|
|
}
|
|
|
|
hr = (*audioRecordDevice)->Initialize( guidPlayback );
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "Could not initalize waveIn. Init failed hr=0x%x", hr );
|
|
goto INIT_EXIT_ERROR;
|
|
}
|
|
|
|
hr = InitializeRecordBuffer( hwnd, lpdvfInfo, *audioRecordDevice, audioRecordBuffer, dwFlags );
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "Unable to initialize waveIn buffer hr=0x%x", hr );
|
|
goto INIT_EXIT_ERROR;
|
|
}
|
|
}
|
|
else if( FAILED( hr ) )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "Unable to initialize record. hr=0x%x", hr );
|
|
goto INIT_EXIT_ERROR;
|
|
}
|
|
#endif
|
|
}
|
|
// Use specified device, just try and create the buffer
|
|
else
|
|
{
|
|
hr = InitializeRecordBuffer( hwnd, lpdvfInfo, *audioRecordDevice, audioRecordBuffer, dwFlags );
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "Unable to initialize dsc buffer hr=0x%x", hr );
|
|
goto INIT_EXIT_ERROR;
|
|
}
|
|
}
|
|
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "> Rec Init 2" );
|
|
|
|
hr = SetPlaybackBufferToSilence( *audioPlaybackBuffer, lpwfxPlayFormat );
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "> Unable to set playback to silence" );
|
|
goto INIT_EXIT_ERROR;
|
|
}
|
|
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "> Rec Init 3" );
|
|
|
|
// Depending on the ASO parameter start the playback buffer
|
|
// playing and the recording buffer recording.
|
|
if( aso )
|
|
{
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "> ASO " );
|
|
|
|
hr = (*audioPlaybackBuffer)->Play( dwPlayPriority, dwPlayFlags );
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "> Can't play" );
|
|
goto INIT_EXIT_ERROR;
|
|
}
|
|
|
|
hr = (*audioRecordBuffer)->Record(TRUE);
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "> Can't start recording" );
|
|
goto INIT_EXIT_ERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "> !ASO " );
|
|
|
|
/* hr = (*audioRecordBuffer)->Record(TRUE);
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "> Can't start recording" );
|
|
goto INIT_EXIT_ERROR;
|
|
} */
|
|
|
|
hr = (*audioPlaybackBuffer)->Play( dwPlayPriority, dwPlayFlags );
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "> Can't play" );
|
|
goto INIT_EXIT_ERROR;
|
|
}
|
|
}
|
|
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "FULL DUPLEX INIT: End ==========" );
|
|
|
|
Diagnostics_Write( DVF_INFOLEVEL, "Full Duplex Init Result = DV_OK" );
|
|
|
|
return DV_OK;
|
|
|
|
INIT_EXIT_ERROR:
|
|
|
|
if( *audioRecordBuffer != NULL )
|
|
{
|
|
delete *audioRecordBuffer;
|
|
*audioRecordBuffer = NULL;
|
|
}
|
|
|
|
// Only delete on error if we allocated
|
|
if( fRecordDeviceAllocated && *audioRecordDevice != NULL )
|
|
{
|
|
delete *audioRecordDevice;
|
|
*audioRecordDevice = NULL;
|
|
}
|
|
|
|
// Only delete on error if we allocated
|
|
if( fPlaybackBufferAllocated && *audioPlaybackBuffer != NULL )
|
|
{
|
|
delete *audioPlaybackBuffer;
|
|
*audioPlaybackBuffer = NULL;
|
|
}
|
|
|
|
// Only delete on error if we allocated
|
|
if( fPlaybackDeviceAllocated && *audioPlaybackDevice != NULL )
|
|
{
|
|
delete *audioPlaybackDevice;
|
|
*audioPlaybackDevice = NULL;
|
|
}
|
|
|
|
Diagnostics_Write( DVF_ERRORLEVEL, "Full Duplex Init Result = 0x%x", hr );
|
|
|
|
return hr;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "FindPeak8Bit"
|
|
// FindPeak8Bit
|
|
//
|
|
// This function determines what the peak for a buffer
|
|
// of 8 bit audio is. Peak is defined as the loudest
|
|
// sample in a set of audio data rated on a scale of
|
|
// between 0 and 100.
|
|
//
|
|
// Parameters:
|
|
// BYTE *data -
|
|
// Pointer to the buffer containing the audio data
|
|
// to find the peak of.
|
|
// DWORD frameSize -
|
|
// The size in bytes of the audio data we are
|
|
// checking.
|
|
//
|
|
// Returns:
|
|
// BYTE -
|
|
// The peak of the audio buffer, a value between 0 and 100.
|
|
//
|
|
BYTE FindPeak8Bit( BYTE *data, DWORD frameSize )
|
|
{
|
|
BYTE peak = 0;
|
|
int tmpData;
|
|
|
|
for( int index = 0; index < frameSize; index++ )
|
|
{
|
|
tmpData = data[index];
|
|
|
|
tmpData -= 0x80;
|
|
|
|
if( tmpData < 0 )
|
|
tmpData *= -1;
|
|
|
|
if( tmpData > peak )
|
|
{
|
|
peak = (unsigned char) tmpData;
|
|
}
|
|
}
|
|
|
|
tmpData = peak * 100 / 0x7F;
|
|
|
|
return (BYTE) tmpData;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "FindPeak16Bit"
|
|
// FindPeak16Bit
|
|
//
|
|
// This function determines what the peak for a buffer
|
|
// of 16 bit audio is. Peak is defined as the loudest
|
|
// sample in a set of audio data rated on a scale of
|
|
// between 0 and 100.
|
|
//
|
|
// Parameters:
|
|
// BYTE *data -
|
|
// Pointer to the buffer containing the audio data
|
|
// to find the peak of.
|
|
// DWORD frameSize -
|
|
// The size in bytes of the audio data we are
|
|
// checking.
|
|
//
|
|
// Returns:
|
|
// BYTE -
|
|
// The peak of the audio buffer, a value between 0 and 100.
|
|
//
|
|
BYTE FindPeak16Bit( short *data, DWORD frameSize )
|
|
{
|
|
int peak,
|
|
tmpData;
|
|
|
|
frameSize /= 2;
|
|
peak = 0;
|
|
|
|
for( int index = 0; index < frameSize; index++ )
|
|
{
|
|
tmpData = data[index];
|
|
|
|
if( tmpData < 0 )
|
|
{
|
|
tmpData *= -1;
|
|
}
|
|
|
|
if( tmpData > peak )
|
|
{
|
|
peak = tmpData;
|
|
}
|
|
}
|
|
|
|
tmpData = (peak * 100) / 0x7FFF;
|
|
|
|
return (BYTE) tmpData;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "FindPeak"
|
|
// FindPeak
|
|
//
|
|
// This function determines what the peak for a buffer
|
|
// of 8 or 16 bit audio is. Peak is defined as the loudest
|
|
// sample in a set of audio data rated on a scale of
|
|
// between 0 and 100.
|
|
//
|
|
// Parameters:
|
|
// BYTE *data -
|
|
// Pointer to the buffer containing the audio data
|
|
// to find the peak of.
|
|
// DWORD frameSize -
|
|
// The size in bytes of the audio data we are
|
|
// checking.
|
|
// BOOL eightBit -
|
|
// Determins if the buffer is 8 bit or not. Set to
|
|
// TRUE for 8 bit data, FALSE for 16 bit data.
|
|
//
|
|
// Returns:
|
|
// BYTE -
|
|
// The peak of the audio buffer, a value between 0 and 100.
|
|
//
|
|
BYTE FindPeak( BYTE *data, DWORD frameSize, BOOL eightBit )
|
|
{
|
|
if( eightBit )
|
|
{
|
|
return FindPeak8Bit( data, frameSize );
|
|
}
|
|
else
|
|
{
|
|
return FindPeak16Bit( (signed short *) data, frameSize );
|
|
}
|
|
}
|
|
|
|
|