Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

987 lines
29 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1999-2002 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: sndutils.cpp
  6. * Content:
  7. * This module contains the implementation of sound related utility
  8. * functions. Functions in this module manipulate WAVEFORMATEX
  9. * structures and provide full duplex initialization / testing
  10. * facilities.
  11. *
  12. * This module also contains the routines used to measure peak
  13. * of an audio buffer and for voice activation.
  14. *
  15. * History:
  16. * Date By Reason
  17. * ==== == ======
  18. * 07/16/99 rodtoll Created
  19. * 07/30/99 rodtoll Updated util functions to take GUIDs and allow for
  20. * users to pre-create capture/playback devices and
  21. * pass them into InitXXXXDuplex
  22. * 08/25/99 rodtoll General Cleanup/Modifications to support new
  23. * compression sub-system.
  24. * 08/30/99 rodtoll Added new playback format param to sound init
  25. * 09/03/99 rodtoll Fixed return codes on InitFullDuplex
  26. * 09/20/99 rodtoll Now checks for invalid GUIDs for playback/record
  27. * 10/05/99 rodtoll Added DPF_MODNAMEs
  28. * 10/29/99 rodtoll Bug #113726 - Fixed memory leak when full duplex
  29. * fails caused by architecture update.
  30. * 11/12/99 rodtoll Updated full duplex test to use new abstracted recording
  31. * and playback systems.
  32. * rodtoll Updated to allow passing of sounddeviceconfig flags in dwflags
  33. * parameter to init is effected by the flags specified by user
  34. * rodtoll Sound buffers (rec and playback) are now set to silence before
  35. * recording/playback is started.
  36. * 11/22/99 rodtoll Removed unnessessary set of recording buffer to silence.
  37. * 12/01/99 rodtoll Bug #115783 - Will always adjust volume of default device
  38. * Updated for new parameters added by above bug.
  39. * 12/08/99 rodtoll Bug #121054 - Support for capture focus and removed flags
  40. * from buffer, allow dsound to manage buffer location.
  41. * 01/21/2000 pnewson Fixed error cleanup code in InitHalfDuplex
  42. * 01/27/2000 rodtoll Updated tests to accept buffer descriptions and play flags/priority
  43. * 02/10/2000 rodtoll Removed more capture focus
  44. * 02/23/2000 rodtoll Fix to allow to run on dsound7.
  45. * 05/19/2000 rodtoll Bug #35395 - Unable to run two copies of DPVHELP on same system without
  46. * DirectX 8 installed.
  47. * 06/21/2000 rodtoll Bug #35767 - Must implement ability to use effects processing on voice buffers
  48. * Updated sound initialization routines to handle buffers being passed in.
  49. * 07/12/2000 rodtoll Bug #31468 - Add diagnostic spew to logfile to show what is failing the HW Wizard
  50. * 10/04/2000 rodtoll Bug #43510 - DPVOICE: Apps receive a DVMSGID_SESSIONLOST w/DVERR_LOCKEDBUFFER
  51. * 01/04/2001 rodtoll WinBug #94200 - Remove stray comments
  52. * 01/26/2001 rodtoll WINBUG #293197 - DPVOICE: [STRESS} Stress applications cannot tell difference between out of memory and internal errors.
  53. * Remap DSERR_OUTOFMEMORY to DVERR_OUTOFMEMORY instead of DVERR_SOUNDINITFAILURE.
  54. * Remap DSERR_ALLOCATED to DVERR_PLAYBACKSYSTEMERROR instead of DVERR_SOUNDINITFAILURE.
  55. * 04/12/2001 kareemc WINBUG #360971 - Wizard Memory Leaks
  56. *
  57. ***************************************************************************/
  58. #include "dxvutilspch.h"
  59. #undef DPF_SUBCOMP
  60. #define DPF_SUBCOMP DN_SUBCOMP_VOICE
  61. #define DSERRBREAK_NAME "DSASSERT"
  62. DNCRITICAL_SECTION g_csDSDebug;
  63. CHAR g_szLastDirectSoundAPI[100] = "";
  64. HRESULT g_hrLastDirectSoundResult = DS_OK;
  65. BOOL g_fDSErrorBreak = FALSE;
  66. void DSERTRACK_Update( const char *szAPICall, HRESULT hrResult )
  67. {
  68. DNEnterCriticalSection( &g_csDSDebug );
  69. if( SUCCEEDED( g_hrLastDirectSoundResult ) )
  70. {
  71. g_hrLastDirectSoundResult = hrResult;
  72. strcpy( g_szLastDirectSoundAPI , szAPICall );
  73. }
  74. DNLeaveCriticalSection( &g_csDSDebug );
  75. }
  76. void DSERRTRACK_Reset()
  77. {
  78. DNEnterCriticalSection( &g_csDSDebug );
  79. g_hrLastDirectSoundResult = DS_OK;
  80. g_szLastDirectSoundAPI[0] = 0;
  81. DNLeaveCriticalSection( &g_csDSDebug );
  82. }
  83. BOOL DSERRTRACK_Init()
  84. {
  85. if (!DNInitializeCriticalSection( &g_csDSDebug ))
  86. {
  87. return FALSE;
  88. }
  89. // Load the setting for the directsound assert
  90. g_fDSErrorBreak = GetProfileIntA( "DirectPlay8", DSERRBREAK_NAME, FALSE );
  91. return TRUE;
  92. }
  93. void DSERRTRACK_UnInit()
  94. {
  95. DNDeleteCriticalSection( &g_csDSDebug );
  96. }
  97. #undef DPF_MODNAME
  98. #define DPF_MODNAME "DV_SetupBufferDesc"
  99. void DV_SetupBufferDesc( LPDSBUFFERDESC lpdsBufferDesc, LPDSBUFFERDESC lpdsBufferSource, LPWAVEFORMATEX lpwfxFormat, DWORD dwBufferSize )
  100. {
  101. // Confirm specified buffer description is valid
  102. if( lpdsBufferSource != NULL )
  103. {
  104. if( lpdsBufferSource->dwSize == sizeof( DSBUFFERDESC1 ) )
  105. {
  106. memcpy( lpdsBufferDesc, lpdsBufferSource, sizeof( DSBUFFERDESC1 ) );
  107. }
  108. else
  109. {
  110. memcpy( lpdsBufferDesc, lpdsBufferSource, sizeof( DSBUFFERDESC ) );
  111. }
  112. // We require the following flags, at a minimum so they should always be set
  113. lpdsBufferDesc->dwFlags |= DSBCAPS_CTRL3D | DSBCAPS_CTRLVOLUME | DSBCAPS_GETCURRENTPOSITION2;
  114. }
  115. // User did not specify a buffer description, let's use our own!
  116. else
  117. {
  118. lpdsBufferDesc->dwSize = sizeof( DSBUFFERDESC );
  119. lpdsBufferDesc->dwFlags = DSBCAPS_CTRL3D | DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2;
  120. lpdsBufferDesc->dwBufferBytes = 0;
  121. lpdsBufferDesc->dwReserved = 0;
  122. lpdsBufferDesc->lpwfxFormat = NULL;
  123. lpdsBufferDesc->guid3DAlgorithm = DS3DALG_DEFAULT;
  124. }
  125. lpdsBufferDesc->lpwfxFormat = lpwfxFormat;
  126. lpdsBufferDesc->dwBufferBytes = dwBufferSize;
  127. }
  128. #undef DPF_MODNAME
  129. #define DPF_MODNAME "SetRecordBufferToSilence"
  130. HRESULT SetPlaybackBufferToSilence( CAudioPlaybackBuffer *pRecBuffer, const WAVEFORMATEX* lpwfxFormat )
  131. {
  132. HRESULT hr;
  133. LPVOID pBufferPtr1, pBufferPtr2;
  134. DWORD dwBufferSize1, dwBufferSize2;
  135. hr = pRecBuffer->Lock( 0, 0, &pBufferPtr1, &dwBufferSize1, &pBufferPtr2, &dwBufferSize2, DSBLOCK_ENTIREBUFFER );
  136. DSERTRACK_Update( "Lock", hr );
  137. if( FAILED( hr ) )
  138. {
  139. Diagnostics_Write( DVF_ERRORLEVEL, "Lock() failed during silence write hr=0x%x", hr );
  140. return hr;
  141. }
  142. memset( pBufferPtr1, (lpwfxFormat->wBitsPerSample==8) ? 0x80 : 0x00, dwBufferSize1 );
  143. hr = pRecBuffer->UnLock( pBufferPtr1, dwBufferSize1, pBufferPtr2, dwBufferSize2 );
  144. DSERTRACK_Update( "UnLock", hr );
  145. if( FAILED( hr ) )
  146. {
  147. Diagnostics_Write( DVF_ERRORLEVEL, "Unlock() failed uffer unlock failed hr=0x%x", hr );
  148. return hr;
  149. }
  150. return DV_OK;
  151. }
  152. #undef DPF_MODNAME
  153. #define DPF_MODNAME "InitHalfDuplex"
  154. // InitHalfDuplex
  155. //
  156. // This function initializes the playback system for the
  157. // specified compression type and the specified playback
  158. // format. This function is used to initialize
  159. // the AudioPlaybackDevice and AudioPlaybackBuffer.
  160. //
  161. // It also starts the audio buffer which is used for voice
  162. // output playing. (In looping mode).
  163. //
  164. // Parameters:
  165. // HWND hwnd -
  166. // Window handle for the window where the output will
  167. // be associated
  168. // ARDID playbackDeviceID -
  169. // The deviceID for the device which will be used for
  170. // playback
  171. // CAudioPlaybackDevice ** -
  172. // A pointer to a pointer which will contain a pointer
  173. // to a newly created CAudioPlaybackDevice which will
  174. // represent the playback device on success.
  175. // CAudioPlaybackBuffer ** -
  176. // A pointer to a pointer which will contain a pointer
  177. // to a newly created CAudioPlaybacKbuffer which will
  178. // be used for voice audio output on success.
  179. // CompressionType ct -
  180. // The type of compression which will be in use. Used
  181. // to determine buffer sizes etc.
  182. // WAVEFORMATEX *primaryFormat -
  183. // Pointer to a WAVEFORMATEX structure describing the
  184. // format of the voice output. (This will also be used
  185. // to set the primary format of the output device if
  186. // normal is set to false).
  187. // bool normal -
  188. // Specifies if normal mode should be used or not.
  189. // (Only used when using the DirectSound playback
  190. // system. Set to true for normal cooperative mode,
  191. // false for priority mode).
  192. //
  193. // Returns:
  194. // bool -
  195. // Returns true if playback was initializes succesfully,
  196. // false if initialization fails.
  197. //
  198. HRESULT InitHalfDuplex(
  199. HWND hwnd,
  200. const GUID &guidPlayback,
  201. CAudioPlaybackDevice **audioPlaybackDevice,
  202. LPDSBUFFERDESC lpdsBufferDesc,
  203. CAudioPlaybackBuffer **audioPlaybackBuffer,
  204. const GUID &guidCT,
  205. WAVEFORMATEX *primaryFormat,
  206. WAVEFORMATEX *lpwfxPlayFormat,
  207. DWORD dwPlayPriority,
  208. DWORD dwPlayFlags,
  209. DWORD dwFlags
  210. )
  211. {
  212. DWORD frameSize;
  213. HRESULT hr;
  214. DWORD dwBufferSize;
  215. BOOL fPriorityMode;
  216. DSBUFFERDESC dsBufferDesc;
  217. BOOL fPlaybackDeviceAllocated = FALSE;
  218. BOOL fPlaybackBufferAllocated = FALSE;
  219. fPriorityMode = !( dwFlags & DVSOUNDCONFIG_NORMALMODE );
  220. // *audioPlaybackBuffer = NULL;
  221. DPFX(DPFPREP, DVF_INFOLEVEL, "HALFDUPLEX INIT: Begin ==========" );
  222. LPDVFULLCOMPRESSIONINFO lpdvfInfo;
  223. hr = DVCDB_GetCompressionInfo( guidCT, &lpdvfInfo );
  224. if( FAILED( hr ) )
  225. {
  226. Diagnostics_Write( DVF_ERRORLEVEL, "Error loading compression type: hr = 0x%x", hr );
  227. goto INIT_EXIT_ERROR2;
  228. }
  229. if( (*audioPlaybackDevice) == NULL )
  230. {
  231. #ifdef __WAVESUBSYSTEM
  232. if( !(dwFlags & DVSOUNDCONFIG_FORCEWAVEOUT) )
  233. {
  234. #endif
  235. // Create the object to represent the device using the playback subsystem's
  236. // CreateDevice function
  237. (*audioPlaybackDevice) = new CDirectSoundPlaybackDevice();
  238. fPlaybackDeviceAllocated = TRUE;
  239. if( *audioPlaybackDevice == NULL )
  240. {
  241. Diagnostics_Write( DVF_ERRORLEVEL, "> Out of memory" );
  242. hr = DVERR_OUTOFMEMORY;
  243. goto INIT_EXIT_ERROR2;
  244. }
  245. hr = (*audioPlaybackDevice)->Initialize( guidPlayback, hwnd, primaryFormat, fPriorityMode );
  246. #ifndef __WAVESUBSYSTEM
  247. if( FAILED( hr ) )
  248. {
  249. Diagnostics_Write( DVF_ERRORLEVEL, "Unable to initialize playback. hr=0x%x", hr );
  250. goto INIT_EXIT_ERROR2;
  251. }
  252. #endif
  253. #ifdef __WAVESUBSYSTEM
  254. }
  255. if( dwFlags & DVSOUNDCONFIG_FORCEWAVEOUT ||
  256. ((dwFlags & DVSOUNDCONFIG_ALLOWWAVEOUT) && FAILED( hr ))
  257. )
  258. {
  259. Diagnostics_Write( DVF_ERRORLEVEL, "Could not initialize directsound, defaulting to waveout hr=0x%x", hr );
  260. delete (*audioPlaybackDevice);
  261. (*audioPlaybackDevice) = new CWaveOutPlaybackDevice( );
  262. fPlaybackDeviceAllocated = TRUE;
  263. if( (*audioPlaybackDevice) == NULL )
  264. {
  265. Diagnostics_Write( DVF_ERRORLEVEL, "> Out of memory" );
  266. hr = DVERR_OUTOFMEMORY;
  267. goto INIT_EXIT_ERROR2;
  268. }
  269. hr = (*audioPlaybackDevice)->Initialize( guidPlayback, hwnd, primaryFormat, fPriorityMode );
  270. if( FAILED( hr ) )
  271. {
  272. Diagnostics_Write( DVF_ERRORLEVEL, "Could not initalize waveOut. Init failed hr=0x%x", hr );
  273. goto INIT_EXIT_ERROR2;
  274. }
  275. }
  276. else if( FAILED( hr ) )
  277. {
  278. Diagnostics_Write( DVF_ERRORLEVEL, "Unable to initialize playback. hr=0x%x", hr );
  279. goto INIT_EXIT_ERROR2;
  280. }
  281. #endif
  282. // At this point we should have a valid device, waveOut or DirectSound
  283. }
  284. DPFX(DPFPREP, DVF_INFOLEVEL, "> Play init" );
  285. // Create a buffer if the user didn't specify one
  286. if( !(*audioPlaybackBuffer) )
  287. {
  288. frameSize = DVCDB_CalcUnCompressedFrameSize( lpdvfInfo, lpwfxPlayFormat );
  289. dwBufferSize = lpdvfInfo->dwFramesPerBuffer * frameSize;
  290. DV_SetupBufferDesc( &dsBufferDesc, lpdsBufferDesc, lpwfxPlayFormat, dwBufferSize );
  291. // Create the audio buffer which will be used for output
  292. hr = (*audioPlaybackDevice)->CreateBuffer( &dsBufferDesc, frameSize, audioPlaybackBuffer);
  293. fPlaybackBufferAllocated = TRUE;
  294. if( FAILED( hr ) )
  295. {
  296. Diagnostics_Write( DVF_ERRORLEVEL, "Unable to create sound buffer. hr=0x%x", hr );
  297. goto INIT_EXIT_ERROR2;
  298. }
  299. }
  300. DPFX(DPFPREP, DVF_INFOLEVEL, "> Play init 2" );
  301. hr = SetPlaybackBufferToSilence( *audioPlaybackBuffer, lpwfxPlayFormat );
  302. if( FAILED( hr ) )
  303. {
  304. Diagnostics_Write( DVF_ERRORLEVEL, "> Unable to set playback to silence" );
  305. goto INIT_EXIT_ERROR2;
  306. }
  307. DPFX(DPFPREP, DVF_INFOLEVEL, "> Play init 3" );
  308. // Start the audio playback buffer playing
  309. hr = (*audioPlaybackBuffer)->Play( dwPlayPriority, dwPlayFlags );
  310. if( FAILED( hr ) )
  311. {
  312. DPFX(DPFPREP, DVF_ERRORLEVEL, "> Can't play" );
  313. goto INIT_EXIT_ERROR2;
  314. }
  315. Diagnostics_Write( DVF_INFOLEVEL, "Half Duplex Init Result = DV_OK " );
  316. return DV_OK;
  317. // Handle errors
  318. INIT_EXIT_ERROR2:
  319. if( fPlaybackBufferAllocated && *audioPlaybackBuffer != NULL )
  320. {
  321. delete *audioPlaybackBuffer;
  322. *audioPlaybackBuffer = NULL;
  323. }
  324. if( fPlaybackDeviceAllocated && *audioPlaybackDevice != NULL )
  325. {
  326. delete *audioPlaybackDevice;
  327. *audioPlaybackDevice = NULL;
  328. }
  329. Diagnostics_Write( DVF_ERRORLEVEL, "Half Duplex Init Result = 0x%x", hr );
  330. return hr;
  331. }
  332. #undef DPF_MODNAME
  333. #define DPF_MODNAME "InitializeRecordBuffer"
  334. HRESULT InitializeRecordBuffer( HWND hwnd, const DVFULLCOMPRESSIONINFO* lpdvfInfo, CAudioRecordDevice *parecDevice, CAudioRecordBuffer **pparecBuffer, DWORD dwFlags )
  335. {
  336. WAVEFORMATEX *lpwfxRecordFormat;
  337. DSCBUFFERDESC1 dscdesc;
  338. DWORD dwFrameSize;
  339. HRESULT hr;
  340. for( DWORD dwIndex = 0; dwIndex < GetNumRecordFormats(); dwIndex++ )
  341. {
  342. lpwfxRecordFormat = GetRecordFormat( dwIndex );
  343. dwFrameSize = DVCDB_CalcUnCompressedFrameSize( lpdvfInfo, lpwfxRecordFormat );
  344. memset( &dscdesc, 0x00, sizeof( DSCBUFFERDESC1 ) );
  345. dscdesc.dwSize = sizeof( DSCBUFFERDESC1 );
  346. dscdesc.dwFlags = 0;
  347. dscdesc.lpwfxFormat = lpwfxRecordFormat;
  348. dscdesc.dwBufferBytes = dwFrameSize*lpdvfInfo->dwFramesPerBuffer;
  349. if( !(dwFlags & DVSOUNDCONFIG_NOFOCUS) )
  350. {
  351. dscdesc.dwFlags |= DSCBCAPS_FOCUSAWARE;
  352. if( dwFlags & DVSOUNDCONFIG_STRICTFOCUS )
  353. {
  354. dscdesc.dwFlags |= DSCBCAPS_STRICTFOCUS;
  355. }
  356. }
  357. hr = parecDevice->CreateBuffer( (DSCBUFFERDESC *) &dscdesc, hwnd, dwFrameSize, pparecBuffer );
  358. if( FAILED( hr ) )
  359. {
  360. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Could not initialize %d hz, %d bits, %s (hr=0x%x)", lpwfxRecordFormat->nSamplesPerSec,
  361. lpwfxRecordFormat->wBitsPerSample, (lpwfxRecordFormat->nChannels==1) ? _T("Mono") : _T("Stereo"), hr );
  362. continue;
  363. }
  364. else
  365. {
  366. Diagnostics_Write( DVF_INFOLEVEL, "Recording Initialized. Format=" );
  367. Diagnositcs_WriteWAVEFORMATEX( DVF_INFOLEVEL, lpwfxRecordFormat );
  368. }
  369. hr = (*pparecBuffer)->Record(TRUE);
  370. if( FAILED( hr ) )
  371. {
  372. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Could not start rec at %d hz, %d bits, %s (hr=0x%x)", lpwfxRecordFormat->nSamplesPerSec,
  373. lpwfxRecordFormat->wBitsPerSample, (lpwfxRecordFormat->nChannels==1) ? _T("Mono") : _T("Stereo"), hr );
  374. delete (*pparecBuffer);
  375. (*pparecBuffer) = NULL;
  376. continue;
  377. }
  378. else
  379. {
  380. Diagnostics_Write( DVF_INFOLEVEL, "Recording Started. Format=" );
  381. Diagnositcs_WriteWAVEFORMATEX( DVF_INFOLEVEL, lpwfxRecordFormat );
  382. // Reset the directsound erros as we expect errors in this part and if we suceed we handled
  383. // them.
  384. return DV_OK;
  385. }
  386. }
  387. return DVERR_RECORDSYSTEMERROR;
  388. }
  389. #undef DPF_MODNAME
  390. #define DPF_MODNAME "InitFullDuplex"
  391. // InitFullDuplex
  392. //
  393. // The tricky part.
  394. //
  395. // This function is responsible for initializing the system into full duplex
  396. // mode using the specified parameters. This function will create and
  397. // initialize the playback and record devices as well as start the
  398. // playback device playing and the recording device recording. (On success).
  399. // This is neccessary because the order of Play and Record and device
  400. // creation is important.
  401. //
  402. // Parameters:
  403. // HWND hwnd -
  404. // Window handle for the window where the output will
  405. // be associated
  406. // ARDID playbackDeviceID -
  407. // The deviceID for the device which will be used for
  408. // playback
  409. // CAudioPlaybackDevice ** -
  410. // A pointer to a pointer which will contain a pointer
  411. // to a newly created CAudioPlaybackDevice which will
  412. // represent the playback device on success.
  413. // CAudioPlaybackBuffer ** -
  414. // A pointer to a pointer which will contain a pointer
  415. // to a newly created CAudioPlaybacKbuffer which will
  416. // be used for voice audio output on success.
  417. // ARDID recordDeviceID -
  418. // The ARDID for the device which will be used for recording.
  419. // CAudioRecordSubSystem *recordSubSystem -
  420. // This parameter is a pointer to the object representing
  421. // the subsystem which will be used for recording.
  422. // CAudioRecordDevice ** -
  423. // A pointer to a pointer which will contain a newly
  424. // create CAudioRecordDevice for voice recording on
  425. // success.
  426. // CompressionType ct -
  427. // The type of compression which will be in use. Used
  428. // to determine buffer sizes etc.
  429. // WAVEFORMATEX *primaryFormat -
  430. // Pointer to a WAVEFORMATEX structure describing the
  431. // format of the voice output. (This will also be used
  432. // to set the primary format of the output device if
  433. // normal is set to false).
  434. // bool aso -
  435. // This parameter controls the ASO option. The ASO
  436. // option controls the "Startup Order". Enabling
  437. // this option allows full duplex to be initialized
  438. // on some troublesome cards.
  439. // bool normal -
  440. // Specifies if normal mode should be used or not.
  441. // (Only used when using the DirectSound playback
  442. // system. Set to true for normal cooperative mode,
  443. // false for priority mode).
  444. //
  445. // Returns:
  446. // bool - true on successful full duplex initialization,
  447. // false on failure.
  448. //
  449. HRESULT InitFullDuplex(
  450. HWND hwnd,
  451. const GUID &guidPlayback,
  452. CAudioPlaybackDevice **audioPlaybackDevice,
  453. LPDSBUFFERDESC lpdsBufferDesc,
  454. CAudioPlaybackBuffer **audioPlaybackBuffer,
  455. const GUID &guidRecord,
  456. CAudioRecordDevice **audioRecordDevice,
  457. CAudioRecordBuffer **audioRecordBuffer,
  458. const GUID &guidCT,
  459. WAVEFORMATEX *primaryFormat,
  460. WAVEFORMATEX *lpwfxPlayFormat,
  461. BOOL aso,
  462. DWORD dwPlayPriority,
  463. DWORD dwPlayFlags,
  464. DWORD dwFlags
  465. )
  466. {
  467. DWORD frameSize;
  468. DWORD dwBufferSize;
  469. HRESULT hr;
  470. DSBUFFERDESC dsbdesc;
  471. BOOL fPriorityMode;
  472. BOOL fPlaybackDeviceAllocated = FALSE;
  473. BOOL fPlaybackBufferAllocated = FALSE;
  474. BOOL fRecordDeviceAllocated = FALSE;
  475. fPriorityMode = !(dwFlags & DVSOUNDCONFIG_NORMALMODE);
  476. // *audioPlaybackBuffer = NULL;
  477. *audioRecordBuffer = NULL;
  478. DPFX(DPFPREP, DVF_INFOLEVEL, "FULLDUPLEX INIT: Begin ==========" );
  479. LPDVFULLCOMPRESSIONINFO lpdvfInfo;
  480. hr = DVCDB_GetCompressionInfo( guidCT, &lpdvfInfo );
  481. if( FAILED( hr ) )
  482. {
  483. Diagnostics_Write( DVF_ERRORLEVEL, "Error loading compression type: hr = 0x%x", hr );
  484. goto INIT_EXIT_ERROR;
  485. }
  486. if( (*audioPlaybackDevice) == NULL )
  487. {
  488. #ifdef __WAVESUBSYSTEM
  489. if( !(dwFlags & DVSOUNDCONFIG_FORCEWAVEOUT) )
  490. {
  491. #endif
  492. // Create the object to represent the device using the playback subsystem's
  493. // CreateDevice function
  494. (*audioPlaybackDevice) = new CDirectSoundPlaybackDevice();
  495. fPlaybackDeviceAllocated = TRUE;
  496. if( *audioPlaybackDevice == NULL )
  497. {
  498. Diagnostics_Write( DVF_ERRORLEVEL, "> Out of memory" );
  499. hr = DVERR_OUTOFMEMORY;
  500. goto INIT_EXIT_ERROR;
  501. }
  502. hr = (*audioPlaybackDevice)->Initialize( guidPlayback, hwnd, primaryFormat, fPriorityMode );
  503. #ifndef __WAVESUBSYSTEM
  504. if( FAILED( hr ) )
  505. {
  506. Diagnostics_Write( DVF_ERRORLEVEL, "Unable to initialize playback. hr=0x%x", hr );
  507. goto INIT_EXIT_ERROR;
  508. }
  509. #endif
  510. #ifdef __WAVESUBSYSTEM
  511. }
  512. if( dwFlags & DVSOUNDCONFIG_FORCEWAVEOUT ||
  513. ((dwFlags & DVSOUNDCONFIG_ALLOWWAVEOUT) && FAILED( hr )) )
  514. {
  515. Diagnostics_Write( DVF_ERRORLEVEL, "Could not initialize directsound, defaulting to waveout hr=0x%x", hr );
  516. delete (*audioPlaybackDevice);
  517. (*audioPlaybackDevice) = new CWaveOutPlaybackDevice();
  518. fPlaybackDeviceAllocated = TRUE;
  519. if( (*audioPlaybackDevice) == NULL )
  520. {
  521. Diagnostics_Write( DVF_ERRORLEVEL, "> Out of memory" );
  522. hr = DVERR_OUTOFMEMORY;
  523. goto INIT_EXIT_ERROR;
  524. }
  525. hr = (*audioPlaybackDevice)->Initialize( guidPlayback, hwnd, primaryFormat, fPriorityMode );
  526. if( FAILED( hr ) )
  527. {
  528. Diagnostics_Write( DVF_ERRORLEVEL, "Could not initalize waveOut. Init failed hr=0x%x", hr );
  529. goto INIT_EXIT_ERROR;
  530. }
  531. }
  532. else if( FAILED( hr ) )
  533. {
  534. Diagnostics_Write( DVF_ERRORLEVEL, "Unable to initialize playback. hr=0x%x", hr );
  535. goto INIT_EXIT_ERROR;
  536. }
  537. #endif
  538. }
  539. DPFX(DPFPREP, DVF_INFOLEVEL, "> Play init" );
  540. frameSize = DVCDB_CalcUnCompressedFrameSize( lpdvfInfo, lpwfxPlayFormat );
  541. DPFX(DPFPREP, DVF_INFOLEVEL, "> Play init" );
  542. dwBufferSize = lpdvfInfo->dwFramesPerBuffer * frameSize;
  543. if( !(*audioPlaybackBuffer) )
  544. {
  545. DV_SetupBufferDesc( &dsbdesc, lpdsBufferDesc, lpwfxPlayFormat, dwBufferSize );
  546. // Create the audio buffer which will be used for output
  547. hr = (*audioPlaybackDevice)->CreateBuffer( &dsbdesc, frameSize, audioPlaybackBuffer);
  548. fPlaybackBufferAllocated = TRUE;
  549. if( FAILED( hr ) )
  550. {
  551. Diagnostics_Write( DVF_ERRORLEVEL, "Unable to create sound buffer. hr=0x%x", hr );
  552. goto INIT_EXIT_ERROR;
  553. }
  554. }
  555. DPFX(DPFPREP, DVF_INFOLEVEL, "> Play init 2" );
  556. DPFX(DPFPREP, DVF_INFOLEVEL, "> Initing Recording" );
  557. // We're creating the device..
  558. if( (*audioRecordDevice) == NULL )
  559. {
  560. #ifdef __WAVESUBSYSTEM
  561. if( !(dwFlags & DVSOUNDCONFIG_FORCEWAVEIN) )
  562. {
  563. #endif
  564. (*audioRecordDevice) = new CDirectSoundCaptureRecordDevice();
  565. fRecordDeviceAllocated = TRUE;
  566. if( *audioRecordDevice == NULL )
  567. {
  568. Diagnostics_Write( DVF_ERRORLEVEL, "> Out of memory" );
  569. hr = DVERR_OUTOFMEMORY;
  570. goto INIT_EXIT_ERROR;
  571. }
  572. hr = (*audioRecordDevice)->Initialize( guidRecord );
  573. // DSC Init passed, try getting a buffer
  574. if( SUCCEEDED( hr ) )
  575. {
  576. hr = InitializeRecordBuffer( hwnd, lpdvfInfo, *audioRecordDevice, audioRecordBuffer, dwFlags );
  577. if( FAILED( hr ) )
  578. {
  579. Diagnostics_Write( DVF_ERRORLEVEL, "Unable to initialize dsc buffer hr=0x%x", hr );
  580. #ifndef __WAVESUBSYSTEM
  581. Diagnostics_Write( DVF_ERRORLEVEL, "Unable to initialize record. hr=0x%x", hr );
  582. goto INIT_EXIT_ERROR;
  583. #endif
  584. }
  585. else
  586. {
  587. // Need to reset because we expect errors during initialization.
  588. DSERRTRACK_Reset();
  589. }
  590. }
  591. #ifndef __WAVESUBSYSTEM
  592. else
  593. {
  594. Diagnostics_Write( DVF_ERRORLEVEL, "Unable to initialize record. hr=0x%x", hr );
  595. goto INIT_EXIT_ERROR;
  596. }
  597. #endif
  598. #ifdef __WAVESUBSYSTEM
  599. }
  600. // DSC Init failed, try and get a waveIn device
  601. if( dwFlags & DVSOUNDCONFIG_FORCEWAVEIN ||
  602. ((dwFlags & DVSOUNDCONFIG_ALLOWWAVEIN) && FAILED( hr )))
  603. {
  604. Diagnostics_Write( DVF_ERRORLEVEL, "Could not initialize directsoundcapture, defaulting to wavein hr=0x%x", hr );
  605. delete (*audioRecordDevice);
  606. (*audioRecordDevice) = new CWaveInRecordDevice();
  607. fRecordDeviceAllocated = TRUE;
  608. if( (*audioRecordDevice) == NULL )
  609. {
  610. Diagnostics_Write( DVF_ERRORLEVEL, "> Out of memory" );
  611. hr = DVERR_OUTOFMEMORY;
  612. goto INIT_EXIT_ERROR;
  613. }
  614. hr = (*audioRecordDevice)->Initialize( guidPlayback );
  615. if( FAILED( hr ) )
  616. {
  617. Diagnostics_Write( DVF_ERRORLEVEL, "Could not initalize waveIn. Init failed hr=0x%x", hr );
  618. goto INIT_EXIT_ERROR;
  619. }
  620. hr = InitializeRecordBuffer( hwnd, lpdvfInfo, *audioRecordDevice, audioRecordBuffer, dwFlags );
  621. if( FAILED( hr ) )
  622. {
  623. Diagnostics_Write( DVF_ERRORLEVEL, "Unable to initialize waveIn buffer hr=0x%x", hr );
  624. goto INIT_EXIT_ERROR;
  625. }
  626. }
  627. else if( FAILED( hr ) )
  628. {
  629. Diagnostics_Write( DVF_ERRORLEVEL, "Unable to initialize record. hr=0x%x", hr );
  630. goto INIT_EXIT_ERROR;
  631. }
  632. #endif
  633. }
  634. // Use specified device, just try and create the buffer
  635. else
  636. {
  637. hr = InitializeRecordBuffer( hwnd, lpdvfInfo, *audioRecordDevice, audioRecordBuffer, dwFlags );
  638. if( FAILED( hr ) )
  639. {
  640. Diagnostics_Write( DVF_ERRORLEVEL, "Unable to initialize dsc buffer hr=0x%x", hr );
  641. goto INIT_EXIT_ERROR;
  642. }
  643. }
  644. DPFX(DPFPREP, DVF_INFOLEVEL, "> Rec Init 2" );
  645. hr = SetPlaybackBufferToSilence( *audioPlaybackBuffer, lpwfxPlayFormat );
  646. if( FAILED( hr ) )
  647. {
  648. Diagnostics_Write( DVF_ERRORLEVEL, "> Unable to set playback to silence" );
  649. goto INIT_EXIT_ERROR;
  650. }
  651. DPFX(DPFPREP, DVF_INFOLEVEL, "> Rec Init 3" );
  652. // Depending on the ASO parameter start the playback buffer
  653. // playing and the recording buffer recording.
  654. if( aso )
  655. {
  656. DPFX(DPFPREP, DVF_INFOLEVEL, "> ASO " );
  657. hr = (*audioPlaybackBuffer)->Play( dwPlayPriority, dwPlayFlags );
  658. if( FAILED( hr ) )
  659. {
  660. Diagnostics_Write( DVF_ERRORLEVEL, "> Can't play" );
  661. goto INIT_EXIT_ERROR;
  662. }
  663. hr = (*audioRecordBuffer)->Record(TRUE);
  664. if( FAILED( hr ) )
  665. {
  666. Diagnostics_Write( DVF_ERRORLEVEL, "> Can't start recording" );
  667. goto INIT_EXIT_ERROR;
  668. }
  669. }
  670. else
  671. {
  672. DPFX(DPFPREP, DVF_INFOLEVEL, "> !ASO " );
  673. /* hr = (*audioRecordBuffer)->Record(TRUE);
  674. if( FAILED( hr ) )
  675. {
  676. Diagnostics_Write( DVF_ERRORLEVEL, "> Can't start recording" );
  677. goto INIT_EXIT_ERROR;
  678. } */
  679. hr = (*audioPlaybackBuffer)->Play( dwPlayPriority, dwPlayFlags );
  680. if( FAILED( hr ) )
  681. {
  682. Diagnostics_Write( DVF_ERRORLEVEL, "> Can't play" );
  683. goto INIT_EXIT_ERROR;
  684. }
  685. }
  686. DPFX(DPFPREP, DVF_INFOLEVEL, "FULL DUPLEX INIT: End ==========" );
  687. Diagnostics_Write( DVF_INFOLEVEL, "Full Duplex Init Result = DV_OK" );
  688. return DV_OK;
  689. INIT_EXIT_ERROR:
  690. if( *audioRecordBuffer != NULL )
  691. {
  692. delete *audioRecordBuffer;
  693. *audioRecordBuffer = NULL;
  694. }
  695. // Only delete on error if we allocated
  696. if( fRecordDeviceAllocated && *audioRecordDevice != NULL )
  697. {
  698. delete *audioRecordDevice;
  699. *audioRecordDevice = NULL;
  700. }
  701. // Only delete on error if we allocated
  702. if( fPlaybackBufferAllocated && *audioPlaybackBuffer != NULL )
  703. {
  704. delete *audioPlaybackBuffer;
  705. *audioPlaybackBuffer = NULL;
  706. }
  707. // Only delete on error if we allocated
  708. if( fPlaybackDeviceAllocated && *audioPlaybackDevice != NULL )
  709. {
  710. delete *audioPlaybackDevice;
  711. *audioPlaybackDevice = NULL;
  712. }
  713. Diagnostics_Write( DVF_ERRORLEVEL, "Full Duplex Init Result = 0x%x", hr );
  714. return hr;
  715. }
  716. #undef DPF_MODNAME
  717. #define DPF_MODNAME "FindPeak8Bit"
  718. // FindPeak8Bit
  719. //
  720. // This function determines what the peak for a buffer
  721. // of 8 bit audio is. Peak is defined as the loudest
  722. // sample in a set of audio data rated on a scale of
  723. // between 0 and 100.
  724. //
  725. // Parameters:
  726. // BYTE *data -
  727. // Pointer to the buffer containing the audio data
  728. // to find the peak of.
  729. // DWORD frameSize -
  730. // The size in bytes of the audio data we are
  731. // checking.
  732. //
  733. // Returns:
  734. // BYTE -
  735. // The peak of the audio buffer, a value between 0 and 100.
  736. //
  737. BYTE FindPeak8Bit( const BYTE *data, DWORD frameSize )
  738. {
  739. BYTE peak = 0;
  740. int tmpData;
  741. for( int index = 0; index < frameSize; index++ )
  742. {
  743. tmpData = data[index];
  744. tmpData -= 0x80;
  745. if( tmpData < 0 )
  746. tmpData *= -1;
  747. if( tmpData > peak )
  748. {
  749. peak = (unsigned char) tmpData;
  750. }
  751. }
  752. tmpData = peak * 100 / 0x7F;
  753. return (BYTE) tmpData;
  754. }
  755. #undef DPF_MODNAME
  756. #define DPF_MODNAME "FindPeak16Bit"
  757. // FindPeak16Bit
  758. //
  759. // This function determines what the peak for a buffer
  760. // of 16 bit audio is. Peak is defined as the loudest
  761. // sample in a set of audio data rated on a scale of
  762. // between 0 and 100.
  763. //
  764. // Parameters:
  765. // BYTE *data -
  766. // Pointer to the buffer containing the audio data
  767. // to find the peak of.
  768. // DWORD frameSize -
  769. // The size in bytes of the audio data we are
  770. // checking.
  771. //
  772. // Returns:
  773. // BYTE -
  774. // The peak of the audio buffer, a value between 0 and 100.
  775. //
  776. BYTE FindPeak16Bit( const short *data, DWORD frameSize )
  777. {
  778. int peak,
  779. tmpData;
  780. frameSize /= 2;
  781. peak = 0;
  782. for( int index = 0; index < frameSize; index++ )
  783. {
  784. tmpData = data[index];
  785. if( tmpData < 0 )
  786. {
  787. tmpData *= -1;
  788. }
  789. if( tmpData > peak )
  790. {
  791. peak = tmpData;
  792. }
  793. }
  794. tmpData = (peak * 100) / 0x7FFF;
  795. return (BYTE) tmpData;
  796. }
  797. #undef DPF_MODNAME
  798. #define DPF_MODNAME "FindPeak"
  799. // FindPeak
  800. //
  801. // This function determines what the peak for a buffer
  802. // of 8 or 16 bit audio is. Peak is defined as the loudest
  803. // sample in a set of audio data rated on a scale of
  804. // between 0 and 100.
  805. //
  806. // Parameters:
  807. // BYTE *data -
  808. // Pointer to the buffer containing the audio data
  809. // to find the peak of.
  810. // DWORD frameSize -
  811. // The size in bytes of the audio data we are
  812. // checking.
  813. // BOOL eightBit -
  814. // Determins if the buffer is 8 bit or not. Set to
  815. // TRUE for 8 bit data, FALSE for 16 bit data.
  816. //
  817. // Returns:
  818. // BYTE -
  819. // The peak of the audio buffer, a value between 0 and 100.
  820. //
  821. BYTE FindPeak( BYTE *data, DWORD frameSize, BOOL eightBit )
  822. {
  823. if( eightBit )
  824. {
  825. return FindPeak8Bit( data, frameSize );
  826. }
  827. else
  828. {
  829. return FindPeak16Bit( (signed short *) data, frameSize );
  830. }
  831. }