Windows NT 4.0 source code leak
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.

3497 lines
97 KiB

4 years ago
  1. //--------------------------------------------------------------------------;
  2. //
  3. // File: DSoundHW.c
  4. //
  5. // Copyright (c) 1995 Microsoft Corporation. All Rights Reserved.
  6. //
  7. // Abstract:
  8. //
  9. //
  10. // Contents:
  11. // IDSHWQueryInterface()
  12. // IDSHWAddRef()
  13. // IDSHWRelease()
  14. // IDSHWCreateSoundBuffer()
  15. // IDSHWEnumSoundBuffers()
  16. // IDSHWGetCaps()
  17. // IDSHWDuplicateSoundBuffer()
  18. // IDSHWSetCooperativeLevel()
  19. // IDSHWCompact();
  20. // IDSHWGetSpeakerConfig()
  21. // IDSHWSetSpeakerConfig()
  22. // IDSHWInitialize()
  23. // DSHWCreateTable()
  24. // GetTopUnownedWindow() added by angusm on 11/27/95
  25. // CreateFocusThread() added by angusm on 12/1/95
  26. // cSoundObjects() added by angusm on 11/30/95
  27. //
  28. // History:
  29. // Date By Reason
  30. // ==== == ======
  31. // 3/5/96 angusm Added use of fInitialized
  32. // 03/20/06 angusm Added support for Sticky Focus
  33. //
  34. //--------------------------------------------------------------------------;
  35. #include "dsoundpr.h"
  36. #ifndef DSBLD_EMULONLY
  37. #include <pbt.h>
  38. #endif
  39. #include "grace.h"
  40. #include "flocks.h"
  41. /* Global Constansts */
  42. #define POLL_INTERVAL 250 /* number of miliseconds between polls
  43. * for active window */
  44. #define WAKEFOCUSTHREAD "DSWakeFocusThread" /* event name for Focus Thread
  45. * event. */
  46. #define FOCUSSTARTUPEVENT "DSFocusStartupEvent" /* event name for handshake
  47. * after Focus Thread
  48. * startup code */
  49. /* Function Prototypes */
  50. HWND GetTopUnownedWindow (HWND hWindow);
  51. BOOL IsValidDSApp (DWORD dwTid);
  52. void EndFocusThread();
  53. DWORD WINAPI FocusTracker (LPVOID lpvPollInterval);
  54. __inline void DseUpdateActivationState (LPDSOUNDEXTERNAL pdse);
  55. __inline void DsbeDeactivateIfNecessary (LPDSBUFFEREXTERNAL);
  56. __inline void ActivateFocusWindow (void);
  57. // From DirectDraw - for subclassing
  58. extern HRESULT _stdcall DSoundHelp( HWND hWnd,WNDPROC lpWndProc,DWORD dwPID );
  59. LRESULT CALLBACK SubclassWndProc( HWND hWnd, UINT uMessage, WPARAM wParam, LPARAM lParam );
  60. LPDSOUNDINFO gpdsinfo;
  61. //--------------------------------------------------------------------------;
  62. //
  63. // HRESULT DseVerifyValidFormat
  64. //
  65. // Description:
  66. // This function returns DS_OK if the specified format is valid for
  67. // this sound device.
  68. //
  69. //--------------------------------------------------------------------------;
  70. HRESULT DseVerifyValidFormat
  71. (
  72. LPDSOUNDEXTERNAL pdse,
  73. LPWAVEFORMATEX pwfx
  74. )
  75. {
  76. DSCAPS dsc;
  77. HRESULT hr;
  78. ZeroMemory(&dsc, sizeof(dsc));
  79. dsc.dwSize = sizeof(dsc);
  80. hr = DsGetCaps (pdse->pds, &dsc);
  81. if (DS_OK != hr) {
  82. return hr;
  83. }
  84. if (WAVE_FORMAT_PCM != pwfx->wFormatTag) return DSERR_BADFORMAT;
  85. if( ( (pwfx->nChannels == 1) &&
  86. !(dsc.dwFlags & DSCAPS_PRIMARYMONO) ) ||
  87. ( (pwfx->nChannels == 2) &&
  88. !(dsc.dwFlags & DSCAPS_PRIMARYSTEREO) ) ||
  89. ( (pwfx->wBitsPerSample == 8) &&
  90. !(dsc.dwFlags & DSCAPS_PRIMARY8BIT) ) ||
  91. ( (pwfx->wBitsPerSample == 16) &&
  92. !(dsc.dwFlags & DSCAPS_PRIMARY16BIT) ) ) {
  93. return DSERR_BADFORMAT;
  94. }
  95. return DS_OK;
  96. }
  97. //--------------------------------------------------------------------------;
  98. //
  99. // HRESULT DseSaveAppFormat
  100. //
  101. // Description:
  102. // This function saves the specified format as the app format in the
  103. // specified dse object.
  104. //
  105. //--------------------------------------------------------------------------;
  106. HRESULT DseSaveAppFormat(LPDSOUNDEXTERNAL pdse, LPWAVEFORMATEX pwfxAppCaller)
  107. {
  108. LPWAVEFORMATEX pwfxApp;
  109. int cbFormat;
  110. cbFormat = SIZEOF_WAVEFORMATEX(pwfxAppCaller);
  111. pwfxApp = (LPWAVEFORMATEX)MemAlloc(cbFormat);
  112. if (NULL == pwfxApp) {
  113. DPF(0, "DseSaveAppFormat: error: Out of memory saving app's format");
  114. return DSERR_OUTOFMEMORY;
  115. }
  116. CopyMemory(pwfxApp, pwfxAppCaller, cbFormat);
  117. if (NULL != pdse->pwfxApp) {
  118. DPF(1, "Freeing previous app format");
  119. MemFree(pdse->pwfxApp);
  120. }
  121. pdse->pwfxApp = pwfxApp;
  122. return DS_OK;
  123. }
  124. //--------------------------------------------------------------------------;
  125. //
  126. // HRESULT IDSHWQueryInterface
  127. //
  128. //--------------------------------------------------------------------------;
  129. HRESULT FAR PASCAL IDSHWQueryInterface
  130. (
  131. LPDIRECTSOUND pids,
  132. REFIID riid,
  133. LPVOID FAR* ppvObj
  134. )
  135. {
  136. LPDSOUNDEXTERNAL pdse;
  137. if( !VALID_DSOUNDE_PTR(pids) ) {
  138. RPF("IDirectSound::QueryInterface - Invalid Object or ref count");
  139. return DSERR_INVALIDPARAM;
  140. }
  141. pdse = (LPDSOUNDEXTERNAL)pids;
  142. if( 0 == pdse->uRefCount ) {
  143. RPF("IDirectSound::QueryInterface - Invalid ref count");
  144. return DSERR_INVALIDPARAM;
  145. }
  146. if (IDSHWINITIALIZEF_INITIALIZED == pdse->fInitialized) {
  147. ASSERT(VALID_DSOUND_PTR(pdse->pds));
  148. }
  149. if( riid == NULL ) {
  150. RPF("IDirectSound::QueryInterface - NULL riid");
  151. return DSERR_INVALIDPARAM;
  152. }
  153. if( ppvObj == NULL ) {
  154. RPF("IDirectSound::QueryInterface - NULL ppvObj");
  155. return DSERR_INVALIDPARAM;
  156. }
  157. ENTER_DLL_CSECT();
  158. if( IsEqualGUID(riid,&IID_IDirectSound) ||
  159. IsEqualGUID(riid,&IID_IUnknown) ) {
  160. *ppvObj = pdse;
  161. pdse->lpVtbl->AddRef((LPDIRECTSOUND)pdse);
  162. LEAVE_DLL_CSECT();
  163. return DS_OK;
  164. }
  165. else
  166. {
  167. LEAVE_DLL_CSECT();
  168. return DSERR_NOINTERFACE;
  169. }
  170. LEAVE_DLL_CSECT();
  171. return DSERR_GENERIC;
  172. } // IDSHWQueryInterface()
  173. //--------------------------------------------------------------------------;
  174. //
  175. // IDSHWAddRef
  176. //
  177. // Description:
  178. // This function implements the standard IUnknown::AddRef()
  179. //
  180. // Arguments:
  181. // pids "this" pointer
  182. //
  183. // Return (ULONG):
  184. // Estimate of the value of the reference count.
  185. //
  186. // History:
  187. // 02/11/96 angusm Removed need to have (uRefCount != 0)
  188. //
  189. //--------------------------------------------------------------------------;
  190. LONG DsAddRef(LPDSOUND pds)
  191. {
  192. pds->uRefCount++;
  193. return (int)pds->uRefCount;
  194. }
  195. ULONG FAR PASCAL IDSHWAddRef
  196. (
  197. LPDIRECTSOUND pids
  198. )
  199. {
  200. LPDSOUNDEXTERNAL pdse;
  201. if( !VALID_DSOUNDE_PTR(pids) ) {
  202. RPF("IDirectSound::AddRef - Invalid Object");
  203. return 0;
  204. }
  205. pdse = (LPDSOUNDEXTERNAL)pids;
  206. if( 0 == pdse->uRefCount) {
  207. RPF("IDirectSound::AddRef - Invalid Object or ref count");
  208. return 0;
  209. }
  210. ENTER_DLL_CSECT();
  211. pdse->uRefCount++;
  212. LEAVE_DLL_CSECT();
  213. return pdse->uRefCount;
  214. } // IDSHWAddRef()
  215. LONG DsRelease(LPDSOUND pds)
  216. {
  217. LPDSOUND pdsList;
  218. LPDSOUND pdsPrev;
  219. HANDLE hMixThread;
  220. if (0 != --pds->uRefCount) {
  221. DPF(3,"DsRelease done, ref count now %X", pds->uRefCount );
  222. ASSERT((LONG)pds->uRefCount > 0);
  223. return pds->uRefCount;
  224. }
  225. DPF(2,"Destroying DirectSound object");
  226. // Free the primary we created
  227. if( pds->pdsbePrimary != NULL ) {
  228. IDirectSoundBuffer_Release((LPDIRECTSOUNDBUFFER)(pds->pdsbePrimary));
  229. }
  230. pds->pdsbePrimary = NULL;
  231. //
  232. if (!(DS_INTERNALF_WAVEEMULATED & pds->fdwInternal)) {
  233. hMixThread = mxTerminate(pds);
  234. } else {
  235. hMixThread = NULL;
  236. }
  237. // Remove it from the list
  238. pdsList = gpdsinfo->pDSoundObj;
  239. pdsPrev = NULL;
  240. while( pdsList != NULL ) {
  241. if( pds == pdsList ) {
  242. if( pdsPrev ) {
  243. // Previous element in list remove it
  244. pdsPrev->pNext = pdsList->pNext;
  245. } else {
  246. // Head of list - remove
  247. gpdsinfo->pDSoundObj = pdsList->pNext;
  248. }
  249. pdsList = NULL;
  250. } else {
  251. pdsPrev = pdsList;
  252. pdsList = pdsList->pNext;
  253. }
  254. }
  255. pds->pNext = NULL;
  256. // If we allocated a heap manager for the driver
  257. if (DSDHEAP_CREATEHEAP == pds->dwHeapType) {
  258. VidMemFini(pds->pDriverHeap);
  259. pds->pDriverHeap = NULL;
  260. }
  261. // Free the Wave Blit structure we use on eumlation
  262. MemFree( pds->pdswb );
  263. // FINI layer to VxD
  264. if( pds->hHal) {
  265. DPF(3,"Close HAL layer %X", pds->hHal );
  266. vxdDrvClose( pds->hHal );
  267. DPF(3,"Finished Close HAL layer" );
  268. }
  269. pds->hHal = INVALID_HANDLE_VALUE;
  270. // Close mmsystem wave handle if we opened one for this driver
  271. if (pds->hwo) {
  272. // ASSERT(DSDDESC_DOMMSYSTEMOPEN & pds->dsDrvDesc.dwFlags);
  273. HelperWaveClose( (DWORD)(pds->hwo) );
  274. pds->hwo = NULL;
  275. }
  276. #ifdef DEBUG
  277. // Validity checking
  278. if(!(pds->fdwInternal & DS_INTERNALF_ALLOCATED)) {
  279. DPF(0,"******* Already Freed dsound HW object ********");
  280. }
  281. if( pds->pdsb != NULL ) {
  282. DPF(0,"******* PDSB != NULL ********");
  283. }
  284. if( pds->pdsbPrimary != NULL ) {
  285. DPF(0,"******* PDSBPrimary != NULL ********");
  286. }
  287. if( pds->hPlaybackThread != NULL ) {
  288. DPF(0,"******* Playback thread != NULL ********");
  289. }
  290. if( pds->hwo != NULL ) {
  291. DPF(0,"******* HWO != NULL ********");
  292. }
  293. if( pds->dwBuffersPlaying != 0 ) {
  294. DPF(0,"******* BuffersPlaying != NULL ********");
  295. }
  296. #endif
  297. pds->dwSig = 0xdeaddead;
  298. MemFree( pds );
  299. DPF(3,"Release done %X ref count now 0", pds);
  300. //
  301. // Wait for mixer thread to die
  302. //
  303. if (NULL != hMixThread) {
  304. DWORD dwResult;
  305. HANDLE hHelper;
  306. HANDLE hMixThreadOurs;
  307. DPF(3, "IDSHWRelease: note: waiting for mixer thread to terminate");
  308. hHelper = OpenProcess(PROCESS_DUP_HANDLE, FALSE, gpdsinfo->pidHelper);
  309. if (hHelper)
  310. {
  311. if (DuplicateHandle(hHelper, hMixThread, GetCurrentProcess(),
  312. &hMixThreadOurs, SYNCHRONIZE | THREAD_TERMINATE,
  313. FALSE, DUPLICATE_CLOSE_SOURCE))
  314. {
  315. dwResult = WaitForSingleObjectEx(hMixThreadOurs, INFINITE, FALSE);
  316. ASSERT(WAIT_OBJECT_0 == dwResult);
  317. dwResult = CloseHandle(hMixThreadOurs);
  318. ASSERT(dwResult);
  319. }
  320. dwResult = CloseHandle(hHelper);
  321. ASSERT(dwResult);
  322. }
  323. }
  324. return 0;
  325. } // DsRelease()
  326. void DseTerminate(LPDSOUNDEXTERNAL pdse)
  327. {
  328. LPDSOUNDEXTERNAL pdseList;
  329. LPDSOUNDEXTERNAL pdsePrev;
  330. HANDLE hFocusLock;
  331. // Now release any buffers this process may have accessed.
  332. // Release all buffers for this process for this object
  333. FreeBuffersForProcess( pdse );
  334. // We use DSoundHelp to give us APM window notifications. If we are
  335. // building only for emulation mode then we don't need APM notifications
  336. // since APM will be handled entirely by the WAVE drivers that we are
  337. // using for emulation.
  338. #ifndef DSBLD_EMULONLY
  339. // Remove the window from the subclass list
  340. // Window is stored by PID
  341. DSoundHelp( NULL, SubclassWndProc, HackGetCurrentProcessId() );
  342. #endif
  343. // Remove it from the list
  344. if (FALSE == GetFocusLock(&hFocusLock)) {
  345. DPF (3, "Could not get Focus Lock");
  346. }
  347. pdseList = gpdsinfo->pDSoundExternalObj;
  348. pdsePrev = NULL;
  349. while( pdseList != NULL ) {
  350. if( pdse == pdseList ) {
  351. if( pdsePrev ) {
  352. // Previous element in list remove it
  353. pdsePrev->pNext = pdseList->pNext;
  354. } else {
  355. // Head of list - remove
  356. gpdsinfo->pDSoundExternalObj = pdseList->pNext;
  357. }
  358. pdseList = NULL;
  359. } else {
  360. pdsePrev = pdseList;
  361. pdseList = pdseList->pNext;
  362. }
  363. }
  364. pdse->pNext = NULL;
  365. if (FALSE == ReleaseFocusLock(hFocusLock)) {
  366. DPF (3, "Could not release Focus Lock.");
  367. }
  368. // If an app wave format was allocated for this, then free it.
  369. if (pdse->pwfxApp) MemFree(pdse->pwfxApp);
  370. pdse->pwfxApp = NULL;
  371. //
  372. DsRelease(pdse->pds);
  373. }
  374. ULONG FAR PASCAL IDSHWRelease(LPDIRECTSOUND pIDs)
  375. {
  376. LPDSOUNDEXTERNAL pdse;
  377. ULONG cRef;
  378. pdse = (LPDSOUNDEXTERNAL)pIDs;
  379. ENTER_DLL_CSECT();
  380. cRef = --pdse->uRefCount;
  381. if (0 == cRef) {
  382. // Check to see if the object is initialized
  383. if (IDSHWINITIALIZEF_UNINITIALIZED != pdse->fInitialized) {
  384. DPF(1, "DseRelease: deleting object %08Xh", pdse);
  385. /* End Focus Thread */
  386. if (1 == cSoundObjects()) EndFocusThread();
  387. DseTerminate(pdse);
  388. pdse->fInitialized = IDSHWINITIALIZEF_UNINITIALIZED;
  389. }
  390. DPF(0, "Freeing pdse %08Xh", pdse);
  391. MemFree( pdse );
  392. }
  393. LEAVE_DLL_CSECT();
  394. return cRef;
  395. }
  396. //--------------------------------------------------------------------------;
  397. //
  398. // HRESULT DseCreateDsbe
  399. //
  400. // Description:
  401. // This function operates on a Dse object to create a Dsb object
  402. //
  403. // Arguments:
  404. //
  405. // Return (HRESULT):
  406. //
  407. //--------------------------------------------------------------------------;
  408. HRESULT DseCreateDsbe
  409. (
  410. LPDSOUNDEXTERNAL pdse,
  411. LPDSBUFFERDESC pdsbd,
  412. LPDSBUFFEREXTERNAL *ppdsbe
  413. )
  414. {
  415. LPDSBUFFER pdsb;
  416. LPDSBUFFEREXTERNAL pdsbe;
  417. LPDSBUFFER pdsb1;
  418. LPDSBUFFEREXTERNAL pdsbe1;
  419. UINT uDevID;
  420. LPDSOUND pds;
  421. DWORD cbMixBufferSize;
  422. DWORD cbFormatSize;
  423. DWORD dw;
  424. DWORD dwForce;
  425. LPDSPROCESS pDSPID;
  426. DSCAPS dsc;
  427. BOOL fTryHardware, fTrySoftware;
  428. HRESULT hr;
  429. HRESULT hrReturn;
  430. DSBUFFERDESC dsbdTemp;
  431. HRESULT hrTemp;
  432. DPF(3,"DseCreateDsbe()");
  433. pds = pdse->pds;
  434. if( !VALID_DSOUND_PTR(pds) || (0 == pdse->uRefCount)) {
  435. RPF("IDirectSound::CreateSoundBuffer - Invalid Object or ref count");
  436. return DSERR_INVALIDPARAM;
  437. }
  438. hrReturn = DS_OK;
  439. *ppdsbe = NULL;
  440. dwForce = 0;
  441. uDevID = pds->uDeviceID;
  442. _fmemcpy( &dsbdTemp, pdsbd, sizeof(DSBUFFERDESC));
  443. // If the user wants a primary then it must be Hardware
  444. // If they're trying to force a software primary, fail them
  445. // Set the hardware flag otherwise
  446. // Also set that this buffer can be blt to
  447. // If it's not a request for a primary, then set our internal force flag
  448. if( (dsbdTemp.dwFlags & DSBCAPS_PRIMARYBUFFER) ) {
  449. if( (dsbdTemp.dwFlags & DSBCAPS_LOCSOFTWARE) ) {
  450. RPF("IDirectSound::CreateSoundBuffer - Invalid attempt to force a software primary buffer!");
  451. return DSERR_INVALIDPARAM;
  452. }
  453. dsbdTemp.dwFlags |= DSBCAPS_LOCHARDWARE;
  454. dsbdTemp.dwFlags |= DSBCAPS_CTRLWAVEBLTDST;
  455. // Caller mustn't specify primary specify buffer size.
  456. if ( (0 != dsbdTemp.dwBufferBytes) ) {
  457. RPF("IDirectSound::CreateSoundBuffer - Primary buffers must be created with dwBufferBytes = 0");
  458. return DSERR_INVALIDPARAM;
  459. }
  460. else {
  461. dsbdTemp.dwBufferBytes = DEFAULT_PRIMARY_SIZE;
  462. }
  463. // We don't allow any apps to specify a format for primary buffers.
  464. if (NULL != dsbdTemp.lpwfxFormat) {
  465. RPF("IDirectSound::CreateSoundBuffer - error: app must not specify primary buffer format");
  466. return DSERR_INVALIDCALL;
  467. }
  468. } else {
  469. // NOTE: There is a conflict of motives with these flags: the user is
  470. // telling us what they want to do, but we use them internally to tell
  471. // ourselves what to do, so save off the user's intentions into dwForce
  472. // and then tell them what they actually got at the end of the create
  473. if( (dsbdTemp.dwFlags & DSBCAPS_LOCSOFTWARE) ) {
  474. dsbdTemp.dwFlags &= (~DSBCAPS_LOCSOFTWARE);
  475. dwForce = DSBCAPS_LOCSOFTWARE;
  476. }
  477. else if( (dsbdTemp.dwFlags & DSBCAPS_LOCHARDWARE) ) {
  478. dsbdTemp.dwFlags &= (~DSBCAPS_LOCHARDWARE);
  479. dwForce = DSBCAPS_LOCHARDWARE;
  480. }
  481. }
  482. // Check that buffer has a real size...
  483. if( dsbdTemp.dwBufferBytes <= 4 ) {
  484. RPF("IDirectSound::CreateSoundBuffer - Buffer size too small");
  485. return DSERR_INVALIDPARAM;
  486. }
  487. if( dsbdTemp.dwBufferBytes >= 0x10000000 ) {
  488. RPF("IDirectSound::CreateSoundBuffer - Buffer size too large");
  489. return DSERR_INVALIDPARAM;
  490. }
  491. //
  492. // If the app is creating a primary, and a primary already exists for
  493. // the app, then return the app's existing primary buffer object.
  494. //
  495. if (DSBCAPS_PRIMARYBUFFER & dsbdTemp.dwFlags) {
  496. pdsbe = pdse->pdsbe;
  497. while (NULL != pdsbe) {
  498. if (DSB_INTERNALF_PRIMARY & pdsbe->pdsb->fdwDsbI) break;
  499. pdsbe = pdsbe->pNext;
  500. }
  501. if (NULL != pdsbe) {
  502. //
  503. // If they requested vol control, specify that this pdsbe is allowed.
  504. //
  505. if( dsbdTemp.dwFlags & DSBCAPS_CTRLVOLUME ) {
  506. pdsbe->fdwDsbeI |= DSBE_INTERNALF_CTRLVOLUMEPRIMARY;
  507. }
  508. //
  509. // If they requested pan control, specify that this pdsbe is allowed.
  510. //
  511. if( dsbdTemp.dwFlags & DSBCAPS_CTRLPAN ) {
  512. pdsbe->fdwDsbeI |= DSBE_INTERNALF_CTRLPANPRIMARY;
  513. }
  514. // Addref and return pointer to existing buffer
  515. pdsbe->lpVtbl->AddRef((LPDIRECTSOUNDBUFFER)pdsbe);
  516. *ppdsbe = pdsbe;
  517. return DS_OK;
  518. }
  519. }
  520. // Allocate the dsbe object
  521. pdsbe = (LPDSBUFFEREXTERNAL)MemAlloc(sizeof(DSBUFFEREXTERNAL));
  522. if(NULL == pdsbe) {
  523. DPF(0,"CreateSoundBuffer object (External) alloc fail");
  524. goto CREATE_ERROR_LAST;
  525. }
  526. pdsbe->lpVtbl = gpdsinfo->lpVtblDSb;
  527. pdsbe->pdse = pdse;
  528. pdsbe->uRefCount = 1;
  529. pdsbe->dwPID = GetCurrentProcessId();
  530. pdsbe->dwPriority = pdse->dwPriority;
  531. pdsbe->pNext = pdse->pdsbe;
  532. pdse->pdsbe = pdsbe;
  533. // HACK HACK Multiple Primaries
  534. // Check to see if primary buffer is already allocated.
  535. if( (dsbdTemp.dwFlags & DSBCAPS_PRIMARYBUFFER ) && (pds->pdsbPrimary) ) {
  536. // We are asking for another primary buffer...
  537. DPF(3,"Primary Object already allocated" );
  538. ASSERT( VALID_DSBUFFER_PTR(pds->pdsbPrimary) );
  539. ASSERT( DSBUFFSIG == pds->pdsbPrimary->dwSig );
  540. // Point external object to this primary
  541. pdsb = pds->pdsbPrimary;
  542. pdsbe->pdsb = pds->pdsbPrimary;
  543. // If this is not waveemulated, create an alias pointer to the data
  544. // buffer. Note that this only reserves linear address space.
  545. // Physical memory is committed on Lock.
  546. if (!(pdsb->pds->fdwInternal & DS_INTERNALF_WAVEEMULATED)) {
  547. pdsbe->pDSBufferAlias = vxdMemReserveAlias(pdsb->pDSBuffer, pdsb->cbBufferSize);
  548. } else {
  549. pdsbe->pDSBufferAlias = NULL;
  550. }
  551. //
  552. // If they requested vol control, specify that this pdsbe is allowed.
  553. //
  554. if( dsbdTemp.dwFlags & DSBCAPS_CTRLVOLUME ) {
  555. pdsbe->fdwDsbeI |= DSBE_INTERNALF_CTRLVOLUMEPRIMARY;
  556. }
  557. //
  558. // If they requested pan control, specify that this pdsbe is allowed.
  559. //
  560. if( dsbdTemp.dwFlags & DSBCAPS_CTRLPAN ) {
  561. pdsbe->fdwDsbeI |= DSBE_INTERNALF_CTRLPANPRIMARY;
  562. }
  563. // Addref existing object and return pointer to it
  564. pdsbe->lpVtbl->AddRef((LPDIRECTSOUNDBUFFER)pdsbe);
  565. // The refcount on this external primary should be 1 for the create
  566. // But it is now 2 since addref needs a + refcount to work
  567. // So reset it to 1
  568. pdsbe->uRefCount = 1;
  569. DPF(2, "Return buffer ext %X, core %X mem ptr %X size %X",
  570. pdsbe, pdsb, pdsb->pDSBuffer ,pdsb->cbBufferSize );
  571. // If the pdse is in focus and it is WRITEPRIMARY, then the
  572. // primary dsbe for this app should be stopped and so must be
  573. // the internal primary dsb.
  574. //
  575. // We also need to set the internal primary format, even when
  576. // not WRITEPRIMARY.
  577. //
  578. if (pdse->tidSound == gpdsinfo->tidSoundFocus || pdse->tidSound == gpdsinfo->tidStuckFocus) {
  579. HRESULT hr;
  580. if (pdse->dwPriority >= DSSCL_WRITEPRIMARY) {
  581. IDsbStopI(pds->pdsbPrimary, FALSE);
  582. }
  583. if (NULL != pdse->pwfxApp) {
  584. hr = IDsbSetFormatI( pds->pdsbPrimary, pdse->pwfxApp, 0 );
  585. } else {
  586. hr = IDsbSetFormatI( pds->pdsbPrimary, &pds->wfxDefault, 0 );
  587. }
  588. if( DS_OK != hr )
  589. {
  590. RPF("IDirectSound::CreateSoundBuffer - Couldn't set primary format when creating primary buffer.");
  591. }
  592. }
  593. DsbeDeactivateIfNecessary (pdsbe);
  594. // Return pointer to new buffer
  595. *ppdsbe = pdsbe;
  596. return DS_OK;
  597. }
  598. // Allocate the dsb object
  599. pdsb = (LPDSBUFFER)MemAlloc(sizeof(DSBUFFER));
  600. if(NULL == pdsb) {
  601. DPF(0,"CreateSoundBuffer object alloc fail");
  602. goto CREATE_ERROR_BUFFEREXTERNAL;
  603. }
  604. pdsb->dwSig = DSBUFFSIG;
  605. DPF(1, "Allocating DSBUFFER obj 0x%8x",pdsb);
  606. // Point external object to this
  607. pdsbe->pdsb = pdsb;
  608. pdsb->fdwBufferDesc = dsbdTemp.dwFlags;
  609. pdsb->dwPrimaryNumber = dsbdTemp.dwReserved; // The reserved field is dwPrimaryNumber
  610. pdsb->cbBufferSize = dsbdTemp.dwBufferBytes;
  611. pdsb->pdsb3d = NULL;
  612. pdsb->pds = pds;
  613. pdsb->fdwDsbI = DSB_INTERNALF_STOP;
  614. pdsb->uRefCount = 1;
  615. pdsb->pNext = pds->pdsb;
  616. pds->pdsb = pdsb;
  617. pdsb->pdsbDuplicateNext = pdsb;
  618. pdsb->pdsbDuplicatePrev = pdsb;
  619. // Set up hack internal use external objct
  620. // This will be used by the mixer for calling
  621. // methods like stop
  622. // It will never be used for addref or release
  623. pdsb->dsbe.lpVtbl = gpdsinfo->lpVtblDSb;
  624. pdsb->dsbe.pdse = pdse;
  625. pdsb->dsbe.uRefCount = 1;
  626. pdsb->dsbe.dwPID = DWBUFFER_INTERNAL_PID;
  627. pdsb->dsbe.pNext = NULL;
  628. pdsb->dsbe.pdsb = pdsb;
  629. pdsb->dsbe.dwPriority = pdse->dwPriority;
  630. // If we are allocating the primary and this is the first primary
  631. // then initialize the ds obj to show the primary
  632. // The DSEPrimary will only be used internally
  633. if( dsbdTemp.dwFlags & DSBCAPS_PRIMARYBUFFER ) {
  634. pds->pdsbPrimary = pdsb;
  635. pdsb->fdwDsbI |= DSB_INTERNALF_PRIMARY;
  636. }
  637. // Alloc Process ID list
  638. pDSPID = (LPDSPROCESS)MemAlloc(sizeof(DSPROCESS));
  639. if(NULL == pDSPID) {
  640. DPF(1,"IDSCreateSoundBuffer process alloc fail");
  641. goto CREATE_ERROR_BUFFER;
  642. }
  643. pDSPID->dwPID = HackGetCurrentProcessId();
  644. pDSPID->dwProcessRefCount = 1;
  645. pDSPID->pNext = NULL;
  646. pdsb->plProcess = pDSPID;
  647. // Get the ds object's caps
  648. dsc.dwSize = sizeof( DSCAPS );
  649. hrTemp = DsGetCaps(pdse->pds, &dsc);
  650. ASSERT (DS_OK == hrTemp);
  651. DPF(3,"Caps Flags from Driver %X free buffers %X",
  652. dsc.dwFlags, dsc.dwFreeHwMixingAllBuffers );
  653. // Allocate a buffer to hold the format
  654. // First get max format size
  655. // HACK HACK - NO Need to bring in ACM just for this...
  656. // Assume size will be reasonable
  657. // If we have a format use that size
  658. // Add on 16 bytes of slop space
  659. // Format may be changed to a larger one
  660. if( dsbdTemp.lpwfxFormat != NULL ) {
  661. dw = SIZEOF_WAVEFORMATEX( dsbdTemp.lpwfxFormat );
  662. cbFormatSize = dw + 16;
  663. } else {
  664. cbFormatSize = SIZEOF_WAVEFORMATEX(&pds->wfxDefault);
  665. }
  666. // Now allocate memory
  667. pdsb->pwfx = (LPWAVEFORMATEX)MemAlloc(cbFormatSize);
  668. if(NULL == pdsb->pwfx) {
  669. DPF(1,"IDSHWCreateSoundBuffer object alloc fail");
  670. goto CREATE_ERROR_PROCESS;
  671. }
  672. // Now copy the format
  673. if( dsbdTemp.lpwfxFormat != NULL ) {
  674. // We have a real format given
  675. DPF(3,"Format Given %X", dsbdTemp.lpwfxFormat );
  676. if( !ValidPCMFormat( dsbdTemp.lpwfxFormat ) ) {
  677. RPF("IDirectSound::CreateSoundBuffer - Not a valid PCM format");
  678. // Note that later on we should handle non pcm formats
  679. hrReturn = DSERR_BADFORMAT;
  680. goto CREATE_ERROR_FORMAT;
  681. }
  682. dw = SIZEOF_WAVEFORMATEX( dsbdTemp.lpwfxFormat );
  683. CopyMemory( pdsb->pwfx, dsbdTemp.lpwfxFormat, dw );
  684. } else {
  685. // Not a real format - set to default for now
  686. // Note this is only possible in the primary case.
  687. DPF(3,"No format create default." );
  688. CopyMemory(pdsb->pwfx, &pds->wfxDefault, SIZEOF_WAVEFORMATEX(&pds->wfxDefault));
  689. }
  690. //Set the helInfo stuff
  691. pdsb->helInfo.dwSampleRate = 0;
  692. pdsb->helInfo.hfFormat = 0;
  693. pdsb->helInfo.lVolume = 0;
  694. pdsb->helInfo.lPan = 0;
  695. pdsb->helInfo.dwLVolume = 0xffff;
  696. pdsb->helInfo.dwRVolume = 0xffff;
  697. pdsb->helInfo.dwMVolume = 0xffff;
  698. // IF there is a format to set
  699. if( pdsb->pwfx->wFormatTag == WAVE_FORMAT_PCM ) {
  700. pdsb->helInfo.dwSampleRate = pdsb->pwfx->nSamplesPerSec;
  701. pdsb->helInfo.hfFormat = 0;
  702. if( pdsb->pwfx->wBitsPerSample == 8 ) {
  703. pdsb->helInfo.hfFormat |= (H_8_BITS | H_UNSIGNED);
  704. } else {
  705. pdsb->helInfo.hfFormat |= (H_16_BITS | H_SIGNED);
  706. }
  707. if( pdsb->pwfx->nChannels == 2 ) {
  708. pdsb->helInfo.hfFormat |= (H_STEREO | H_ORDER_LR);
  709. } else {
  710. pdsb->helInfo.hfFormat |= H_MONO;
  711. }
  712. } else {
  713. DPF(0, "****************** set NON PCM format ******************" );
  714. // Note that later on we should handle non pcm formats
  715. hrReturn = DSERR_BADFORMAT;
  716. goto CREATE_ERROR_FORMAT;
  717. }
  718. pdsb->helInfo.hfFormat |= H_LOOP;
  719. pdsb->fdwDsbI |= DSB_INTERNALF_LOOPING;
  720. // If this buffer is emulated on the WAVE APIs
  721. // then create and use that buffer
  722. if( pds->fdwInternal & DS_INTERNALF_WAVEEMULATED ) {
  723. if( dwForce & DSBCAPS_LOCHARDWARE )
  724. {
  725. RPF("IDirectSound::CreateSoundBuffer - Can't create a hardware buffer when using wave emulation.");
  726. hrReturn = DSERR_INVALIDCALL;
  727. goto CREATE_ERROR_FORMAT;
  728. }
  729. // If the WAVEBLTDST flag is not set, you are not allowed
  730. // to WaveBlt into this buffer!
  731. if(!( dsbdTemp.dwFlags & DSBCAPS_CTRLWAVEBLTDST )) {
  732. // We will not need a mix buffer
  733. pdsb->pMixBuffer = NULL;
  734. } else {
  735. // Buffer will have stuff mixed into it....
  736. // Default mix buffer size of 32 K.
  737. cbMixBufferSize = 0x00008000;
  738. pdsb->cbMixBufferSize = cbMixBufferSize;
  739. pdsb->pMixBuffer = (LPBYTE)MemAlloc(cbMixBufferSize);
  740. if(NULL == pdsb->pMixBuffer) {
  741. DPF(1,"IDSHWCreateSoundBuffer mix buffer alloc fail");
  742. goto CREATE_ERROR_FORMAT;
  743. }
  744. }
  745. hr = WaveEmulateCreateSoundBuffer( pds, pdsb, &dsbdTemp );
  746. // Set the grace mixer info
  747. pdsb->cSamples = pdsb->cbBufferSize / pdsb->pwfx->nBlockAlign;
  748. switch (pdsb->pwfx->nBlockAlign) {
  749. case 1:
  750. pdsb->uBlockAlignShift = 0;
  751. break;
  752. case 2:
  753. pdsb->uBlockAlignShift = 1;
  754. break;
  755. case 4:
  756. pdsb->uBlockAlignShift = 2;
  757. break;
  758. default:
  759. // Unsupported block align
  760. ASSERT(FALSE);
  761. }
  762. // For emulated primary buffers, we don't use an alias,
  763. // we use the real thing
  764. pdsbe->pDSBufferAlias = NULL;
  765. DsbeDeactivateIfNecessary (pdsbe);
  766. *ppdsbe = pdsbe;
  767. if( hr == DS_OK ) {
  768. return DS_OK;
  769. } else {
  770. hrReturn = hr;
  771. goto CREATE_ERROR_MIX;
  772. }
  773. }
  774. DPF(3," Check for try HW buffers %ld ", dsc.dwFreeHwMixingAllBuffers );
  775. if (!(DSBCAPS_LOCSOFTWARE & dwForce)) {
  776. // if it's static, see if there are _any_ free HwMixingBuffers,
  777. // otherwise see if there are any free _streaming_ buffers
  778. if ( ((DSBCAPS_STATIC & dsbdTemp.dwFlags) && (dsc.dwFreeHwMixingAllBuffers > 0)) ||
  779. (dsc.dwFreeHwMixingStreamingBuffers > 0) )
  780. {
  781. DPF(3," Check for try HW FLAGS %X ", dsc.dwFlags );
  782. DPF(3," Check for try HW format chann %d ", pdsb->pwfx->nChannels);
  783. DPF(3," Check for try HW format bits %d ",pdsb->pwfx->wBitsPerSample);
  784. // Card has secondary buffers in HW
  785. if( ( ( (pdsb->pwfx->nChannels == 1) &&
  786. (dsc.dwFlags & DSCAPS_SECONDARYMONO) ) ||
  787. ( (pdsb->pwfx->nChannels == 2) &&
  788. (dsc.dwFlags & DSCAPS_SECONDARYSTEREO) ) ) &&
  789. ( ( (pdsb->pwfx->wBitsPerSample == 8) &&
  790. (dsc.dwFlags & DSCAPS_SECONDARY8BIT) ) ||
  791. ( (pdsb->pwfx->wBitsPerSample == 16) &&
  792. (dsc.dwFlags & DSCAPS_SECONDARY16BIT) ) ) )
  793. {
  794. // Card can support mono/stereo format requested
  795. // Card can support 8/16 bit format requested
  796. DPF(3," Try a hardware buffer" );
  797. // If it was a primary this flag was already set
  798. dsbdTemp.dwFlags |= DSBCAPS_LOCHARDWARE;
  799. }
  800. }
  801. }
  802. //
  803. // Check whether this is a primary or HW buffer. If
  804. // so then try to use the HAL code
  805. //
  806. fTryHardware = (0 != (dsbdTemp.dwFlags & DSBCAPS_LOCHARDWARE));
  807. fTrySoftware = !(DSBCAPS_PRIMARYBUFFER & dsbdTemp.dwFlags) &&
  808. !(DSBCAPS_LOCHARDWARE & dwForce);
  809. if (!fTryHardware && !fTrySoftware) {
  810. hrReturn = DSERR_INVALIDCALL;
  811. goto CREATE_ERROR_FORMAT;
  812. }
  813. if (fTryHardware) {
  814. // in order to implement sound focus with secondary hardware
  815. // buffers, we need CTRLVOLUME on them.
  816. if (0 == (DSBCAPS_PRIMARYBUFFER & dsbdTemp.dwFlags)) {
  817. dsbdTemp.dwFlags |= DSBCAPS_CTRLVOLUME;
  818. }
  819. hrReturn = DsCreateHardwareBuffer(pds, pdsb, &dsbdTemp, &fTrySoftware);
  820. if (DS_OK == hrReturn) fTrySoftware = FALSE;
  821. }
  822. if (fTrySoftware) hrReturn = DsCreateSoftwareBuffer(pds, pdsb, &dsbdTemp);
  823. if (DS_OK != hrReturn) goto CREATE_ERROR_FORMAT;
  824. //
  825. // If the creating app doesn't have sound focus then we need to
  826. // immediately deactivate the new buffer
  827. //
  828. DsbeDeactivateIfNecessary (pdsbe);
  829. //
  830. //
  831. //
  832. DsbFillSilence( pdsb );
  833. // If the WAVEBLTDST flag is not set, you are not allowed
  834. // to WaveBlt into this buffer!
  835. if(!( dsbdTemp.dwFlags & DSBCAPS_CTRLWAVEBLTDST )) {
  836. // We will not need a mix buffer
  837. pdsb->pMixBuffer = NULL;
  838. } else {
  839. // Buffer will have stuff mixed into it....
  840. // If we've just created the hardware primary buffer, then let's
  841. // allocate a mixer buffer that is certainly large enough
  842. if (DSB_INTERNALF_PRIMARY & pdsb->fdwDsbI) {
  843. // May need up to 4X the buffer size
  844. cbMixBufferSize = pdsb->cbBufferSize * 4;
  845. } else {
  846. // Default mix buffer size of 32 K.
  847. cbMixBufferSize = 0x00008000;
  848. }
  849. pdsb->cbMixBufferSize = cbMixBufferSize;
  850. pdsb->pMixBuffer = (LPBYTE)MemAlloc(cbMixBufferSize);
  851. if(NULL == pdsb->pMixBuffer) {
  852. DPF(1,"IDSHWCreateSoundBuffer mix buffer alloc fail");
  853. goto CREATE_ERROR_MIX;
  854. }
  855. }
  856. // Set the grace mixer info
  857. pdsb->cSamples = pdsb->cbBufferSize / pdsb->pwfx->nBlockAlign;
  858. switch (pdsb->pwfx->nBlockAlign) {
  859. case 1:
  860. pdsb->uBlockAlignShift = 0;
  861. break;
  862. case 2:
  863. pdsb->uBlockAlignShift = 1;
  864. break;
  865. case 4:
  866. pdsb->uBlockAlignShift = 2;
  867. break;
  868. default:
  869. // Unsupported block align
  870. ASSERT(FALSE);
  871. }
  872. // If this is the first buffer for this app, and it wasn't a
  873. // primary buffer, and this app has focus, then we need to set
  874. // the format of the primary buffer.
  875. if ((NULL == pdsbe->pNext) && (!(DSB_INTERNALF_PRIMARY & pdsbe->pdsb->fdwDsbI)))
  876. {
  877. if( pdse->tidSound == gpdsinfo->tidSoundFocus || pdse->tidSound == gpdsinfo->tidStuckFocus ) {
  878. HRESULT hr;
  879. if (NULL != pdse->pwfxApp) {
  880. hr = IDsbSetFormatI( pds->pdsbPrimary, pdse->pwfxApp, 0 );
  881. } else {
  882. hr = IDsbSetFormatI( pds->pdsbPrimary, &pds->wfxDefault, 0 );
  883. }
  884. if( DS_OK != hr )
  885. {
  886. DPF( 0, "Couldn't set primary format when creating primary buffer.");
  887. }
  888. }
  889. }
  890. // If this is a primary buffer, then create an alias pointer to the data
  891. // buffer. Note that this only reserves linear address space. Physical
  892. // memory is not commited. For secondary buffers, we use the internal
  893. // buffer ptr.
  894. ASSERT(!(pds->fdwInternal & DS_INTERNALF_WAVEEMULATED));
  895. if (DSB_INTERNALF_PRIMARY & pdsb->fdwDsbI) {
  896. pdsbe->pDSBufferAlias = vxdMemReserveAlias(pdsb->pDSBuffer, pdsb->cbBufferSize);
  897. } else {
  898. pdsbe->pDSBufferAlias = NULL;
  899. }
  900. DPF(2, "Return buffer ext %X, core %X mem ptr %X size %X",
  901. pdsbe, pdsb, pdsb->pDSBuffer ,pdsb->cbBufferSize );
  902. // Return pointer to new buffer
  903. *ppdsbe = pdsbe;
  904. DPF(3,"IDSHWCreateSoundBuffer Exit");
  905. return DS_OK;
  906. CREATE_ERROR_MIX:
  907. if( pdsb->pMixBuffer != NULL ) {
  908. MemFree(pdsb->pMixBuffer);
  909. }
  910. CREATE_ERROR_FORMAT:
  911. MemFree(pdsb->pwfx);
  912. CREATE_ERROR_PROCESS:
  913. MemFree(pdsb->plProcess);
  914. CREATE_ERROR_BUFFER:
  915. // if this buffer was added to the pDS obj list, remove it
  916. if(pds->pdsb == pdsb)
  917. {
  918. pds->pdsb = pdsb->pNext;
  919. } else {
  920. for(pdsb1 = pds->pdsb; pdsb1 != NULL; pdsb1 = pdsb1->pNext)
  921. {
  922. if(pdsb1->pNext == pdsb) {
  923. pdsb1->pNext = pdsb->pNext;
  924. pdsb->pNext = NULL;
  925. break;
  926. }
  927. }
  928. }
  929. DPF(1, "Freeing DSBUFFER obj 0x%8x",pdsb);
  930. pdsb->dwSig = 0xdeaddead;
  931. MemFree(pdsb);
  932. CREATE_ERROR_BUFFEREXTERNAL:
  933. if( pdsbe == pds->pdsbePrimary ) {
  934. // This is the original alloc of the primary
  935. // clean up DS obj
  936. pds->pdsbPrimary = NULL;
  937. pds->pdsbePrimary = NULL;
  938. }
  939. // If this buffer was added to the pDSE list, remove it
  940. if(pdse->pdsbe == pdsbe)
  941. {
  942. pdse->pdsbe = pdsbe->pNext;
  943. } else {
  944. for(pdsbe1 = pdse->pdsbe; pdsbe1 != NULL; pdsbe1 = pdsbe1->pNext)
  945. {
  946. if(pdsbe1->pNext == pdsbe) {
  947. pdsbe1->pNext = pdsbe->pNext;
  948. pdsbe->pNext = NULL;
  949. break;
  950. }
  951. }
  952. }
  953. // If we allocated a wave format, free it.
  954. if (NULL != pdse->pwfxApp) MemFree(pdse->pwfxApp);
  955. //
  956. MemFree(pdsbe);
  957. CREATE_ERROR_LAST:
  958. if( hrReturn != DS_OK ) {
  959. return hrReturn;
  960. } else {
  961. return DSERR_OUTOFMEMORY;
  962. }
  963. }
  964. //--------------------------------------------------------------------------;
  965. //
  966. // LPDIRECTSOUNDBUFFER IDSHWCreateSoundBuffer
  967. //
  968. // Description:
  969. // This function is the member function for CreateSoundBuffer.
  970. //
  971. // Arguments:
  972. // LPDIRECTSOUND pids: Pointer to Direct Sound Object.
  973. //
  974. // LPDSBUFFERCREATE pdsbc: Pointer to a DSBufferCreate structure.
  975. //
  976. // Return (LPDSBUFFER):
  977. // Pointer to a DSBUFFER structure.
  978. // Return (HRESULT):
  979. // DSERR_UNINITIALIZED if object has not be initialized
  980. //
  981. // History:
  982. // 02/01/95 Fwong Making sense out of non-sense.
  983. // 11/30/95 angusm Added creation of Focus Thread.
  984. // 02/11/96 angusm Added check for initialization
  985. //
  986. //--------------------------------------------------------------------------;
  987. HRESULT FAR PASCAL IDSHWCreateSoundBuffer
  988. (
  989. LPDIRECTSOUND pids,
  990. LPDSBUFFERDESC pdsbd,
  991. LPLPDIRECTSOUNDBUFFER lplpDirectSoundBuffer,
  992. IUnknown FAR *pUnkOuter
  993. )
  994. {
  995. LPDSBUFFEREXTERNAL pdsbe;
  996. LPDSOUNDEXTERNAL pdse;
  997. HRESULT hrReturn;
  998. DPF(3,"IDSHWCreateSoundBuffer");
  999. if( !VALID_DWORD_PTR(lplpDirectSoundBuffer) ) {
  1000. RPF("IDirectSound::CreateSoundBuffer - Invalid lplpDirectSoundBuffer");
  1001. return DSERR_INVALIDPARAM;
  1002. }
  1003. *lplpDirectSoundBuffer = NULL;
  1004. if( !VALID_DSOUNDE_PTR(pids) ) {
  1005. RPF("IDirectSound::CreateSoundBuffer - Invalid Object or ref count");
  1006. return DSERR_INVALIDPARAM;
  1007. }
  1008. pdse = (LPDSOUNDEXTERNAL)pids;
  1009. /* Check to see if the object is initialized */
  1010. if (IDSHWINITIALIZEF_UNINITIALIZED == pdse->fInitialized) {
  1011. RPF("Direct Sound Object is uninitialized.");
  1012. return DSERR_UNINITIALIZED;
  1013. }
  1014. if( !VALID_DSOUND_PTR(pdse->pds) || (0 == pdse->uRefCount)) {
  1015. RPF("IDirectSound::CreateSoundBuffer - Invalid Object or ref count");
  1016. return DSERR_INVALIDPARAM;
  1017. }
  1018. if( !VALID_DSBUFFERDESC_PTR(pdsbd) ) {
  1019. RPF("IDirectSound::CreateSoundBuffer - Invalid Buffer Description or dwSize member.");
  1020. return DSERR_INVALIDPARAM;
  1021. }
  1022. if( 0 != pdsbd->dwReserved ) {
  1023. RPF("IDirectSound::CreateSoundBuffer - DSBUFFERDESC.dwReserved must be zero.");
  1024. return DSERR_INVALIDPARAM;
  1025. }
  1026. if( pdsbd->dwFlags & (~DSBCAPS_VALIDFLAGS)) {
  1027. RPF("IDirectSound::CreateSoundBuffer - Invalid CAPS flags sent to CreateSoundBuffer");
  1028. return DSERR_INVALIDPARAM;
  1029. }
  1030. if( (DSBCAPS_LOCHARDWARE | DSBCAPS_LOCSOFTWARE) ==
  1031. (pdsbd->dwFlags & (DSBCAPS_LOCHARDWARE | DSBCAPS_LOCSOFTWARE)) ) {
  1032. RPF("IDirectSound::CreateSoundBuffer - Both DSBCAPS_LOCHARDWARE and DSBCAPS_LOCSOFTWARE flags were specified: failing");
  1033. return DSERR_INVALIDPARAM;
  1034. }
  1035. if( pUnkOuter != NULL ) {
  1036. RPF("IDirectSound::CreateSoundBuffer - pUnkOuter must be NULL for this rev!");
  1037. return DSERR_NOAGGREGATION;
  1038. }
  1039. // If this is not a primary then format must be set
  1040. if( !(pdsbd->dwFlags & DSBCAPS_PRIMARYBUFFER) ) {
  1041. if( !VALID_WAVEFORMATEX_PTR((pdsbd->lpwfxFormat)) ) {
  1042. RPF("IDirectSound::CreateSoundBuffer - Invalid Format pointer");
  1043. return DSERR_BADFORMAT;
  1044. }
  1045. }
  1046. //
  1047. // If this is a primary, then we only allow DSBCAPS_CTRLVOLUME and
  1048. // DSBCAPS_CTRLPAN controls on it. In fact, we should really mask off
  1049. // this flag before we call down to the driver to create the buffer
  1050. // (just in case the call were to fail), but in fact the primary will be
  1051. // created by DirectSoundCreate without that control, and subsequent
  1052. // creations will simply create a new external object, so we're OK for
  1053. // now. REMIND HACKHACK BUGBUG fix this.
  1054. //
  1055. if( pdsbd->dwFlags & DSBCAPS_PRIMARYBUFFER )
  1056. {
  1057. if( pdsbd->dwFlags & DSBCAPS_CTRLFREQUENCY ) {
  1058. RPF("IDirectSound::CreateSoundBuffer - Primary buffers don't support frequency control.");
  1059. return DSERR_CONTROLUNAVAIL;
  1060. }
  1061. if( pdsbd->dwFlags & DSBCAPS_STATIC ) {
  1062. RPF("IDirectSound::CreateSoundBuffer - Primary buffers can't be static!");
  1063. return DSERR_INVALIDPARAM;
  1064. }
  1065. }
  1066. ENTER_DLL_CSECT();
  1067. hrReturn = DseCreateDsbe(pdse, pdsbd, &pdsbe);
  1068. LEAVE_DLL_CSECT();
  1069. *lplpDirectSoundBuffer = (LPDIRECTSOUNDBUFFER)pdsbe;
  1070. return hrReturn;
  1071. } // IDSHWCreateSoundBuffer()
  1072. //--------------------------------------------------------------------------;
  1073. //
  1074. // LPDSBUFFER IDuplicateSoundBuffer
  1075. //
  1076. // Description:
  1077. // This function is the member function for DuplicateSoundBuffer.
  1078. //
  1079. // Arguments:
  1080. // LPDIRECTSOUND pids: Pointer to Direct Sound Object.
  1081. //
  1082. // LPDSBUFFERCREATE pdsbc: Pointer to a DSBufferCreate structure.
  1083. //
  1084. // Return (LPDSBUFFER):
  1085. // Pointer to a DSBUFFER structure.
  1086. // Return (HRESULT):
  1087. // DSERR_UNINITIALIZED if object has not be initialized
  1088. //
  1089. // History:
  1090. // 02/01/95 Fwong Making sense out of non-sense.
  1091. // 02/11/96 angusm Added check for initialization
  1092. //
  1093. //--------------------------------------------------------------------------;
  1094. HRESULT FAR PASCAL IDSHWDuplicateSoundBuffer
  1095. (
  1096. LPDIRECTSOUND pids,
  1097. LPDIRECTSOUNDBUFFER pidsbCurrent,
  1098. LPLPDIRECTSOUNDBUFFER ppidsbD
  1099. )
  1100. {
  1101. LPDSBUFFER pdsbCurrent;
  1102. LPDSBUFFEREXTERNAL pdsbeCurrent;
  1103. LPDSBUFFER pdsbNew;
  1104. LPDSBUFFEREXTERNAL pdsbeNew;
  1105. LPDSOUND pds;
  1106. LPDSOUNDEXTERNAL pdse;
  1107. DWORD cbMixBufferSize;
  1108. DWORD cbFormatSize;
  1109. DWORD dw;
  1110. LPDSPROCESS pDSPID;
  1111. DSCAPS dsc;
  1112. HRESULT hrReturn;
  1113. HRESULT hr;
  1114. DPF(3,"IDSHWDuplicateSoundBuffer");
  1115. if( !VALID_DSOUNDE_PTR(pids) ) {
  1116. RPF("IDirectSound::DuplicateSoundBuffer - Invalid Object or ref count");
  1117. return DSERR_INVALIDPARAM;
  1118. }
  1119. pdse = (LPDSOUNDEXTERNAL)pids;
  1120. /* Check to see if the object is initialized */
  1121. if (IDSHWINITIALIZEF_UNINITIALIZED == pdse->fInitialized) {
  1122. RPF("Direct Sound Object is uninitialized.");
  1123. return DSERR_UNINITIALIZED;
  1124. }
  1125. pds = pdse->pds;
  1126. if( !VALID_DSOUND_PTR(pds) || (0 == pdse->uRefCount)) {
  1127. RPF("IDirectSound::DuplicateSoundBuffer - Invalid Object or ref count");
  1128. return DSERR_INVALIDPARAM;
  1129. }
  1130. if( !VALID_DSBUFFERE_PTR(pidsbCurrent) ) {
  1131. RPF("IDirectSound::DuplicateSoundBuffer - Invalid Object or ref count");
  1132. return DSERR_INVALIDPARAM;
  1133. }
  1134. pdsbeCurrent = (LPDSBUFFEREXTERNAL)pidsbCurrent;
  1135. pdsbCurrent = pdsbeCurrent->pdsb;
  1136. if( !VALID_DSBUFFER_PTR(pdsbCurrent) || (0 == pdsbeCurrent->uRefCount)) {
  1137. RPF("IDirectSound::DuplicateSoundBuffer - Invalid Object or ref count");
  1138. return DSERR_INVALIDPARAM;
  1139. }
  1140. ASSERT( DSBUFFSIG == pdsbCurrent->dwSig );
  1141. // If this is a primary then return failure
  1142. if( pdsbCurrent == pds->pdsbPrimary ) {
  1143. RPF("IDirectSound::DuplicateSoundBuffer - Can not duplicate primary");
  1144. return DSERR_INVALIDCALL;
  1145. }
  1146. hrReturn = DS_OK;
  1147. *ppidsbD = NULL;
  1148. ENTER_DLL_CSECT();
  1149. cbMixBufferSize = pdsbCurrent->cbMixBufferSize;
  1150. // Allocate the external dsb object
  1151. pdsbeNew = (LPDSBUFFEREXTERNAL)MemAlloc(sizeof(DSBUFFEREXTERNAL));
  1152. if(NULL == pdsbeNew) {
  1153. DPF(0,"DuplicateSoundBuffer object (External) alloc fail");
  1154. goto DUPLICATE_ERROR_LAST;
  1155. }
  1156. pdsbeNew->lpVtbl = gpdsinfo->lpVtblDSb;
  1157. pdsbeNew->pdse = pdse;
  1158. pdsbeNew->uRefCount = 1;
  1159. pdsbeNew->dwPID = GetCurrentProcessId();
  1160. pdsbeNew->dwPriority = pdsbeCurrent->dwPriority;
  1161. pdsbeNew->pNext = pdse->pdsbe;
  1162. pdse->pdsbe = pdsbeNew;
  1163. // We are not going to dup primaryies no need to mess
  1164. // Allocate the dsb object
  1165. pdsbNew = (LPDSBUFFER)MemAlloc(sizeof(DSBUFFER));
  1166. if(NULL == pdsbNew) {
  1167. DPF(0,"DuplicateSoundBuffer object alloc fail");
  1168. goto DUPLICATE_ERROR_BUFFEREXTERNAL;
  1169. }
  1170. pdsbNew->dwSig = DSBUFFSIG;
  1171. DPF(1, "Allocating DSBUFFER obj 0x%8x",pdsbNew);
  1172. // Point external object to this
  1173. pdsbeNew->pdsb = pdsbNew;
  1174. pdsbNew->fdwBufferDesc = pdsbCurrent->fdwBufferDesc;
  1175. pdsbNew->dwPrimaryNumber = pdsbCurrent->dwPrimaryNumber;
  1176. pdsbNew->pDSBuffer = pdsbCurrent->pDSBuffer;
  1177. pdsbNew->cbBufferSize = pdsbCurrent->cbBufferSize;
  1178. pdsbNew->dwCardAddress = pdsbCurrent->dwCardAddress;
  1179. pdsbNew->pdsb3d = NULL;
  1180. pdsbNew->pds = pds;
  1181. pdsbNew->fdwDsbI = pdsbCurrent->fdwDsbI;
  1182. pdsbNew->fdwDsbI |= DSB_INTERNALF_STOP;
  1183. pdsbNew->fdwDsbI &= ~DSB_INTERNALF_LOOPING;
  1184. pdsbNew->uRefCount = 1;
  1185. pdsbNew->pNext = pds->pdsb;
  1186. pds->pdsb = pdsbNew;
  1187. pdsbNew->pdsbDuplicateNext = pdsbCurrent;
  1188. pdsbNew->pdsbDuplicatePrev = pdsbCurrent->pdsbDuplicatePrev;
  1189. pdsbCurrent->pdsbDuplicatePrev->pdsbDuplicateNext = pdsbNew;
  1190. pdsbCurrent->pdsbDuplicatePrev = pdsbNew;
  1191. // Set up hack internal use external objct
  1192. // This will be used by the mixer for calling
  1193. // methods like stop
  1194. // It will never be used for addref or release
  1195. pdsbNew->dsbe.lpVtbl = gpdsinfo->lpVtblDSb;
  1196. pdsbNew->dsbe.pdse = pdse;
  1197. pdsbNew->dsbe.uRefCount = 1;
  1198. pdsbNew->dsbe.dwPID = DWBUFFER_INTERNAL_PID;
  1199. pdsbNew->dsbe.pNext = NULL;
  1200. pdsbNew->dsbe.pdsb = pdsbNew;
  1201. pdsbNew->dsbe.dwPriority = pdsbeCurrent->dwPriority;
  1202. //Allocate the mix buffer
  1203. pdsbNew->cbMixBufferSize = cbMixBufferSize;
  1204. pdsbNew->pMixBuffer = NULL;
  1205. if( cbMixBufferSize != 0 ) {
  1206. pdsbNew->pMixBuffer = (LPBYTE)MemAlloc(cbMixBufferSize);
  1207. if(NULL == pdsbNew->pMixBuffer) {
  1208. DPF(1,"IDSHWDuplicateSoundBuffer mix buffer alloc fail");
  1209. goto DUPLICATE_ERROR_BUFFER;
  1210. }
  1211. }
  1212. // Alloc Process ID list
  1213. pDSPID = (LPDSPROCESS)MemAlloc(sizeof(DSPROCESS));
  1214. if(NULL == pDSPID) {
  1215. DPF(1,"IDSDuplicateSoundBuffer process alloc fail");
  1216. goto DUPLICATE_ERROR_MIX;
  1217. }
  1218. pDSPID->dwPID = HackGetCurrentProcessId();
  1219. pDSPID->dwProcessRefCount = 1;
  1220. pDSPID->pNext = NULL;
  1221. pdsbNew->plProcess = pDSPID;
  1222. // Allocate a buffer to hold the format
  1223. dw = SIZEOF_WAVEFORMATEX( pdsbCurrent->pwfx );
  1224. cbFormatSize = dw + 16;
  1225. // Now allocate memory
  1226. pdsbNew->pwfx = NULL;
  1227. pdsbNew->pwfx = (LPWAVEFORMATEX)MemAlloc(cbFormatSize);
  1228. if(NULL == pdsbNew->pwfx) {
  1229. DPF(1,"IDSHWDuplicateSoundBuffer object alloc fail");
  1230. goto DUPLICATE_ERROR_PROCESS;
  1231. }
  1232. dw = SIZEOF_WAVEFORMATEX( pdsbCurrent->pwfx );
  1233. CopyMemory( pdsbNew->pwfx, pdsbCurrent->pwfx, dw );
  1234. //Set the helInfo stuff
  1235. pdsbNew->helInfo.dwSampleRate = pdsbNew->pwfx->nSamplesPerSec;
  1236. pdsbNew->helInfo.hfFormat = pdsbCurrent->helInfo.hfFormat;
  1237. pdsbNew->helInfo.lVolume = pdsbCurrent->helInfo.lVolume;
  1238. pdsbNew->helInfo.lPan = pdsbCurrent->helInfo.lPan;
  1239. pdsbNew->helInfo.dwLVolume = pdsbCurrent->helInfo.dwLVolume;
  1240. pdsbNew->helInfo.dwRVolume = pdsbCurrent->helInfo.dwRVolume;
  1241. pdsbNew->helInfo.dwMVolume = pdsbCurrent->helInfo.dwMVolume;
  1242. // No need to handle Wave Emulated separatly since primary
  1243. // is the same and emulated are the same as other emulated
  1244. // If the other buffer is HW then see if we can make this one.
  1245. if (DSB_INTERNALF_HARDWARE & pdsbCurrent->fdwDsbI) {
  1246. // Check to see if we can make this a HW buffer
  1247. // Get the caps and see if we have it free....
  1248. dsc.dwSize = sizeof( DSCAPS );
  1249. hr = DsGetCaps(pdse->pds, &dsc);
  1250. ASSERT (DS_OK == hr);
  1251. if( (dsc.dwFreeHwMixingAllBuffers > 0 ) ) {
  1252. DPF(3," Check for try HW FLAGS %X ", dsc.dwFlags );
  1253. DPF(3," Check for try HW format chann %d ",
  1254. pdsbNew->pwfx->nChannels);
  1255. DPF(3," Check for try HW format bits %d ",
  1256. pdsbNew->pwfx->wBitsPerSample);
  1257. // Card has secondary buffers in HW
  1258. // We are OK
  1259. } else {
  1260. // Other buffer is in HW and we can not make this one in HW
  1261. // Fail call.
  1262. RPF("IDirectSound::DuplicateSoundBuffer - HW does not have resources to duplicate");
  1263. hrReturn = DSERR_ALLOCATED;
  1264. goto DUPLICATE_ERROR_FORMAT;
  1265. }
  1266. }
  1267. // Check to see if this is a primary or HW buffer
  1268. // If so then use the HAL code
  1269. if (DSB_INTERNALF_HARDWARE & pdsbCurrent->fdwDsbI) {
  1270. // We are asking for a HW buffer...
  1271. DPF(3,"HW Duplicate HW buffer");
  1272. DPF(3,"HW Duplicate - sample rate %d", pdsbNew->helInfo.dwSampleRate );
  1273. DPF(3,"HW Duplicate - hfForamt %X", pdsbNew->helInfo.hfFormat );
  1274. hrReturn = vxdDrvDuplicateSoundBuffer( pds->hHal,
  1275. pdsbCurrent->hBuffer,
  1276. &pdsbNew->hBuffer );
  1277. if (DS_OK != hrReturn) {
  1278. DPF(1,"IDSHWDuplicateSoundBuffer buffer alloc fail");
  1279. goto DUPLICATE_ERROR_FORMAT;
  1280. }
  1281. ASSERT(NULL != pdsbNew->hBuffer);
  1282. DPF(3,"IDSHWDuplicateSoundBuffer buffer alloc OK");
  1283. } else {
  1284. DPF(3,"HW Duplicate Emulated secondary buffer");
  1285. }
  1286. // Should be using same snd data buffer
  1287. ASSERT(pdsbNew->pDSBuffer == pdsbCurrent->pDSBuffer);
  1288. ASSERT(pdsbNew->cbBufferSize == pdsbCurrent->cbBufferSize);
  1289. DPF(3,"--------Dup data for Emulated obj %X buff %X len %X",
  1290. pdsbNew, pdsbNew->pDSBuffer, pdsbNew->cbBufferSize );
  1291. //
  1292. // If the creating app doesn't have sound focus then we need to
  1293. // immediately deactivate the new buffer
  1294. //
  1295. DsbeDeactivateIfNecessary (pdsbeNew);
  1296. // Set the grace info
  1297. pdsbNew->cSamples = pdsbNew->cbBufferSize / pdsbNew->pwfx->nBlockAlign;
  1298. switch (pdsbNew->pwfx->nBlockAlign) {
  1299. case 1:
  1300. pdsbNew->uBlockAlignShift = 0;
  1301. break;
  1302. case 2:
  1303. pdsbNew->uBlockAlignShift = 1;
  1304. break;
  1305. case 4:
  1306. pdsbNew->uBlockAlignShift = 2;
  1307. break;
  1308. default:
  1309. ASSERT(FALSE);
  1310. }
  1311. *ppidsbD = (LPDIRECTSOUNDBUFFER)pdsbeNew;
  1312. DPF(3,"IDSHWDuplicateSoundBuffer Exit");
  1313. LEAVE_DLL_CSECT( );
  1314. return DS_OK;
  1315. //DUPLICATE_ERROR_DATA:
  1316. // Do not free since we are duplicating
  1317. DUPLICATE_ERROR_FORMAT:
  1318. MemFree(pdsbNew->pwfx);
  1319. DUPLICATE_ERROR_PROCESS:
  1320. MemFree(pdsbNew->plProcess);
  1321. DUPLICATE_ERROR_MIX:
  1322. if( pdsbNew->pMixBuffer != NULL ) {
  1323. MemFree(pdsbNew->pMixBuffer);
  1324. }
  1325. DUPLICATE_ERROR_BUFFER:
  1326. // Remove it from duplicate list
  1327. pdsbNew->pdsbDuplicateNext->pdsbDuplicatePrev = pdsbNew->pdsbDuplicatePrev;
  1328. pdsbNew->pdsbDuplicatePrev->pdsbDuplicateNext = pdsbNew->pdsbDuplicateNext;
  1329. // Remove from buffer list (inserted at head)
  1330. //
  1331. ASSERT(pds->pdsb == pdsbNew);
  1332. pds->pdsb = pds->pdsb->pNext;
  1333. DPF(1, "Freeing DSBUFFER obj 0x%8x",pdsbNew);
  1334. pdsbNew->dwSig = 0xdeaddead;
  1335. MemFree(pdsbNew);
  1336. DUPLICATE_ERROR_BUFFEREXTERNAL:
  1337. // Unlink pdsbNew from external list (inserted at head)
  1338. //
  1339. ASSERT(pdse->pdsbe == pdsbeNew);
  1340. pdse->pdsbe = pdse->pdsbe->pNext;
  1341. MemFree(pdsbeNew);
  1342. DUPLICATE_ERROR_LAST:
  1343. LEAVE_DLL_CSECT( );
  1344. if( hrReturn != DS_OK ) {
  1345. return hrReturn;
  1346. } else {
  1347. return DSERR_OUTOFMEMORY;
  1348. }
  1349. } // IDSHWDuplicateSoundBuffer()
  1350. #if 0
  1351. //--------------------------------------------------------------------------;
  1352. //
  1353. // IDSHWEnumSoundBuffers
  1354. //
  1355. // Description:
  1356. //
  1357. // Arguments:
  1358. //
  1359. // Return (HRESULT):
  1360. // DSERR_UNINITIALIZED if object has not be initialized
  1361. //
  1362. // History:
  1363. // 02/11/96 angusm Added check for initialization
  1364. //
  1365. //--------------------------------------------------------------------------;
  1366. HRESULT FAR PASCAL IDSHWEnumSoundBuffers
  1367. (
  1368. LPDIRECTSOUND pids,
  1369. LPDSENUMBUFFERSCALLBACK pfnEnumCB,
  1370. LPVOID lpContext
  1371. )
  1372. {
  1373. LPDSOUND pds;
  1374. LPDSOUNDEXTERNAL pdse;
  1375. LPDSBUFFEREXTERNAL pdsbeSearch;
  1376. LPDSBUFFERDESC lpdsbd;
  1377. LPWAVEFORMATEX pwfx;
  1378. DWORD dw;
  1379. BOOL fRet;
  1380. if( !VALID_DSOUNDE_PTR(pids) ) {
  1381. RPF("IDirectSound::EnumSoundBuffers - Invalid Object or ref count");
  1382. return DSERR_INVALIDPARAM;
  1383. }
  1384. pdse = (LPDSOUNDEXTERNAL)pids;
  1385. /* Check to see if the object is initialized */
  1386. if (IDSHWINITIALIZEF_UNINITIALIZED == pdse->fInitialized) {
  1387. RPF("Direct Sound Object is uninitialized.");
  1388. return DSERR_UNINITIALIZED;
  1389. }
  1390. pds = pdse->pds;
  1391. if( !VALID_DSOUND_PTR(pds) || (0 == pdse->uRefCount)) {
  1392. RPF("IDirectSound::EnumSoundBuffers - Invalid Object or ref count");
  1393. return DSERR_INVALIDPARAM;
  1394. }
  1395. DPF(0,"Entering EnumSoundBuffers method");
  1396. ENTER_DLL_CSECT();
  1397. if(( lpdsbd = MemAlloc( sizeof(DSBUFFERDESC) )) == NULL ) {
  1398. RPF("IDirectSound::EnumSoundBuffers - Couldn't allocate DSBUFFERDESC structure!");
  1399. LEAVE_DLL_CSECT();
  1400. DPF(0,"Leaving EnumSoundBuffers method");
  1401. return DSERR_OUTOFMEMORY;
  1402. }
  1403. pdsbeSearch = pdse->pdsbe;
  1404. while( pdsbeSearch != NULL ) {
  1405. _fmemset( lpdsbd, 0, sizeof(DSBUFFERDESC));
  1406. // In case we want to use non-PCM format structures, we can do so,
  1407. // because we're allowing for
  1408. dw = SIZEOF_WAVEFORMATEX( pdsbeSearch->pdsb->pwfx ) + 16;
  1409. if(( pwfx = MemAlloc( dw )) == NULL ) {
  1410. RPF("IDirectSound::EnumSoundBuffers - Couldn't allocate WAVEFORMATEX structure!");
  1411. MemFree( lpdsbd );
  1412. LEAVE_DLL_CSECT();
  1413. DPF(0,"Leaving EnumSoundBuffers method");
  1414. return DSERR_OUTOFMEMORY;
  1415. }
  1416. dw = SIZEOF_WAVEFORMATEX( pdsbeSearch->pdsb->pwfx );
  1417. CopyMemory( pwfx, pdsbeSearch->pdsb->pwfx, dw );
  1418. lpdsbd->dwSize = sizeof(DSBUFFERDESC);
  1419. lpdsbd->cbBuffer = pdsbeSearch->pdsb->cbBufferSize;
  1420. lpdsbd->lpwfxFormat = pwfx;
  1421. lpdsbd->dwFlags = pdsbeSearch->pdsb->fdwBufferDesc;
  1422. lpdsbd->dwReserved = pdsbeSearch->pdsb->dwPrimaryNumber;
  1423. lpdsbd->lpDirectSoundBuffer = (LPDIRECTSOUNDBUFFER)pdsbeSearch;
  1424. pdsbeSearch->lpVtbl->AddRef((LPDIRECTSOUNDBUFFER)pdsbeSearch );
  1425. DPF(1,"EnumSoundBuffers: Calling enumeration callback");
  1426. fRet = pfnEnumCB( lpdsbd, lpContext );
  1427. MemFree( pwfx );
  1428. // Break out early if they told us not to continue...
  1429. if( fRet != TRUE ) {
  1430. DPF(1,"Ending enumeration prematurely");
  1431. break;
  1432. }
  1433. pdsbeSearch = pdsbeSearch->pNext;
  1434. }
  1435. MemFree( lpdsbd );
  1436. LEAVE_DLL_CSECT();
  1437. DPF(0,"Leaving EnumSoundBuffers method");
  1438. return DS_OK;
  1439. }
  1440. #endif // 0
  1441. //--------------------------------------------------------------------------;
  1442. //
  1443. // DsGetCapsNative
  1444. //
  1445. // Description: This sets capabilty flags for supported hardware
  1446. //
  1447. // Arguments: pDSCaps pointer to capabilities structure to be filled
  1448. // pds pointer to direct sound object
  1449. //
  1450. // Concurrency: sequential
  1451. //
  1452. // Assumptions: pds->hHal, pds->dwHeapType, pds->DriverHeap
  1453. // are initialized
  1454. //
  1455. // Return (HRESULT): DS_OK Success
  1456. // DS_xxxxx on failure
  1457. //
  1458. //--------------------------------------------------------------------------;
  1459. HRESULT DsGetCapsNative
  1460. (
  1461. LPDSCAPS pDSCaps,
  1462. LPDSOUND pds
  1463. )
  1464. {
  1465. DSDRIVERCAPS drvCaps;
  1466. HRESULT hr;
  1467. DPF (2, "DsGetCapsNative: Enter Function");
  1468. DPF (2, "DsGetCapsNative: pDSCaps = %x", pDSCaps);
  1469. DPF (2, "DsGetCapsNative: pds = %x", pds);
  1470. ZeroMemory(&drvCaps, sizeof(drvCaps));
  1471. hr = vxdDrvGetCaps(pds->hHal, &drvCaps);
  1472. if (DS_OK != hr) {
  1473. DPF(0, "DsGetCapsNative: vxdDrvGetCaps failure");
  1474. return hr;
  1475. }
  1476. // Check flags returned from driver to see if they are all
  1477. // valid flags for a driver
  1478. if (drvCaps.dwFlags & (~DSCAPS_VALIDDRIVERFLAGS)) {
  1479. RPF ("Sound Device Driver may be broken. Returned non-valid"
  1480. "flags to Direct Sound: %x", drvCaps.dwFlags);
  1481. ASSERT (0);
  1482. }
  1483. pDSCaps->dwFlags = drvCaps.dwFlags & DSCAPS_VALIDDRIVERFLAGS;
  1484. pDSCaps->dwMinSecondarySampleRate = drvCaps.dwMinSecondarySampleRate;
  1485. pDSCaps->dwMaxSecondarySampleRate = drvCaps.dwMaxSecondarySampleRate;
  1486. pDSCaps->dwPrimaryBuffers = drvCaps.dwPrimaryBuffers;
  1487. pDSCaps->dwMaxHwMixingAllBuffers = drvCaps.dwMaxHwMixingAllBuffers;
  1488. pDSCaps->dwMaxHwMixingStaticBuffers = drvCaps.dwMaxHwMixingStaticBuffers;
  1489. pDSCaps->dwMaxHwMixingStreamingBuffers = drvCaps.dwMaxHwMixingStreamingBuffers;
  1490. pDSCaps->dwFreeHwMixingAllBuffers = drvCaps.dwFreeHwMixingAllBuffers;
  1491. pDSCaps->dwFreeHwMixingStaticBuffers = drvCaps.dwFreeHwMixingStaticBuffers;
  1492. pDSCaps->dwFreeHwMixingStreamingBuffers = drvCaps.dwFreeHwMixingStreamingBuffers;
  1493. pDSCaps->dwMaxHw3DAllBuffers = drvCaps.dwMaxHw3DAllBuffers;
  1494. pDSCaps->dwMaxHw3DStaticBuffers = drvCaps.dwMaxHw3DStaticBuffers;
  1495. pDSCaps->dwMaxHw3DStreamingBuffers = drvCaps.dwMaxHw3DStreamingBuffers;
  1496. pDSCaps->dwFreeHw3DAllBuffers = drvCaps.dwFreeHw3DAllBuffers;
  1497. pDSCaps->dwFreeHw3DStaticBuffers = drvCaps.dwFreeHw3DStaticBuffers;
  1498. pDSCaps->dwFreeHw3DStreamingBuffers = drvCaps.dwFreeHw3DStreamingBuffers;
  1499. pDSCaps->dwTotalHwMemBytes = drvCaps.dwTotalHwMemBytes;
  1500. pDSCaps->dwFreeHwMemBytes = drvCaps.dwFreeHwMemBytes;
  1501. pDSCaps->dwMaxContigFreeHwMemBytes = drvCaps.dwMaxContigFreeHwMemBytes;
  1502. //
  1503. // If we're using vmemmgr to manage the hw memory...
  1504. //
  1505. if ((DSDHEAP_CREATEHEAP == pds->dwHeapType) ||
  1506. (DSDHEAP_USEDIRECTDRAWHEAP == pds->dwHeapType))
  1507. {
  1508. ASSERT(pds->pDriverHeap);
  1509. pDSCaps->dwFreeHwMemBytes = VidMemAmountFree(pds->pDriverHeap);
  1510. pDSCaps->dwMaxContigFreeHwMemBytes = VidMemLargestFree(pds->pDriverHeap);
  1511. }
  1512. // REMIND what about these?
  1513. pDSCaps->dwUnlockTransferRateHwBuffers = 0;
  1514. pDSCaps->dwPlayCpuOverheadSwBuffers = 0;
  1515. DPF (2, "DsGetCapsNative: Leave Function");
  1516. return DS_OK;
  1517. }
  1518. //--------------------------------------------------------------------------;
  1519. //
  1520. // DsGetCapsEmulated
  1521. //
  1522. // Description: This sets capability flags for emulated hardware
  1523. //
  1524. // Arguments: pDSCaps pointer to capabilities structure to be filled
  1525. // pds pointer to Direct Sound Object
  1526. //
  1527. // Concurrency: sequential
  1528. //
  1529. // Assumptions: pds->uDeviceID is initialized
  1530. //
  1531. // Return (HRESULT): DS_OK Success
  1532. // DSERR_GENERIC Error getting capabilities wave
  1533. // out device
  1534. // DS_xxxxx on failure
  1535. //
  1536. //--------------------------------------------------------------------------;
  1537. HRESULT DsGetCapsEmulated
  1538. (
  1539. LPDSCAPS pDSCaps,
  1540. LPDSOUND pds
  1541. )
  1542. {
  1543. WAVEOUTCAPS woc;
  1544. MMRESULT mmr;
  1545. DPF (2, "DsGetCapsEmulated: Enter Function");
  1546. DPF (2, "DsGetCapsEmulated: pDSCaps = %x", pDSCaps);
  1547. DPF (2, "DsGetCapsEmulated: pds = %x", pds);
  1548. mmr = waveOutGetDevCaps( pds->uDeviceID, &woc, sizeof(woc) );
  1549. if( mmr != MMSYSERR_NOERROR ) {
  1550. DPF (0, "DsGetCapsEmulated: WaveOutGetCaps failed");
  1551. return DSERR_GENERIC;
  1552. }
  1553. pDSCaps->dwFlags = 0;
  1554. if( woc.dwFormats & WAVE_FORMAT_1M08 ) {
  1555. pDSCaps->dwFlags |= DSCAPS_PRIMARYMONO;
  1556. pDSCaps->dwFlags |= DSCAPS_PRIMARY8BIT;
  1557. }
  1558. if( woc.dwFormats & WAVE_FORMAT_2M08 ) {
  1559. pDSCaps->dwFlags |= DSCAPS_PRIMARYMONO;
  1560. pDSCaps->dwFlags |= DSCAPS_PRIMARY8BIT;
  1561. }
  1562. if( woc.dwFormats & WAVE_FORMAT_4M08 ) {
  1563. pDSCaps->dwFlags |= DSCAPS_PRIMARYMONO;
  1564. pDSCaps->dwFlags |= DSCAPS_PRIMARY8BIT;
  1565. }
  1566. if( woc.dwFormats & WAVE_FORMAT_1S08 ) {
  1567. pDSCaps->dwFlags |= DSCAPS_PRIMARYSTEREO;
  1568. pDSCaps->dwFlags |= DSCAPS_PRIMARY8BIT;
  1569. }
  1570. if( woc.dwFormats & WAVE_FORMAT_2S08 ) {
  1571. pDSCaps->dwFlags |= DSCAPS_PRIMARYSTEREO;
  1572. pDSCaps->dwFlags |= DSCAPS_PRIMARY8BIT;
  1573. }
  1574. if( woc.dwFormats & WAVE_FORMAT_4S08 ) {
  1575. pDSCaps->dwFlags |= DSCAPS_PRIMARYSTEREO;
  1576. pDSCaps->dwFlags |= DSCAPS_PRIMARY8BIT;
  1577. }
  1578. if( woc.dwFormats & WAVE_FORMAT_1M16 ) {
  1579. pDSCaps->dwFlags |= DSCAPS_PRIMARYMONO;
  1580. pDSCaps->dwFlags |= DSCAPS_PRIMARY16BIT;
  1581. }
  1582. if( woc.dwFormats & WAVE_FORMAT_2M16 ) {
  1583. pDSCaps->dwFlags |= DSCAPS_PRIMARYMONO;
  1584. pDSCaps->dwFlags |= DSCAPS_PRIMARY16BIT;
  1585. }
  1586. if( woc.dwFormats & WAVE_FORMAT_4M16 ) {
  1587. pDSCaps->dwFlags |= DSCAPS_PRIMARYMONO;
  1588. pDSCaps->dwFlags |= DSCAPS_PRIMARY16BIT;
  1589. }
  1590. if( woc.dwFormats & WAVE_FORMAT_1S16 ) {
  1591. pDSCaps->dwFlags |= DSCAPS_PRIMARYSTEREO;
  1592. pDSCaps->dwFlags |= DSCAPS_PRIMARY16BIT;
  1593. }
  1594. if( woc.dwFormats & WAVE_FORMAT_2S16 ) {
  1595. pDSCaps->dwFlags |= DSCAPS_PRIMARYSTEREO;
  1596. pDSCaps->dwFlags |= DSCAPS_PRIMARY16BIT;
  1597. }
  1598. if( woc.dwFormats & WAVE_FORMAT_4S16 ) {
  1599. pDSCaps->dwFlags |= DSCAPS_PRIMARYSTEREO;
  1600. pDSCaps->dwFlags |= DSCAPS_PRIMARY16BIT;
  1601. }
  1602. if( woc.dwFormats & WAVE_FORMAT_1S16 ) {
  1603. pDSCaps->dwFlags |= DSCAPS_PRIMARYSTEREO;
  1604. pDSCaps->dwFlags |= DSCAPS_PRIMARY16BIT;
  1605. }
  1606. pDSCaps->dwFlags |= DSCAPS_EMULDRIVER;
  1607. pDSCaps->dwMinSecondarySampleRate = 100;
  1608. pDSCaps->dwMaxSecondarySampleRate = 100000;
  1609. pDSCaps->dwPrimaryBuffers = 1;
  1610. pDSCaps->dwMaxHwMixingAllBuffers = 0;
  1611. pDSCaps->dwMaxHwMixingStaticBuffers = 0;
  1612. pDSCaps->dwMaxHwMixingStreamingBuffers = 0;
  1613. pDSCaps->dwFreeHwMixingAllBuffers = 0;
  1614. pDSCaps->dwFreeHwMixingStaticBuffers = 0;
  1615. pDSCaps->dwFreeHwMixingStreamingBuffers = 0;
  1616. pDSCaps->dwMaxHw3DAllBuffers = 0;
  1617. pDSCaps->dwMaxHw3DStaticBuffers = 0;
  1618. pDSCaps->dwMaxHw3DStreamingBuffers = 0;
  1619. pDSCaps->dwFreeHw3DAllBuffers = 0;
  1620. pDSCaps->dwFreeHw3DStaticBuffers = 0;
  1621. pDSCaps->dwFreeHw3DStreamingBuffers = 0;
  1622. pDSCaps->dwTotalHwMemBytes = 0;
  1623. pDSCaps->dwFreeHwMemBytes = 0;
  1624. pDSCaps->dwMaxContigFreeHwMemBytes = 0;
  1625. // REMIND what about these?
  1626. pDSCaps->dwUnlockTransferRateHwBuffers = 0;
  1627. pDSCaps->dwPlayCpuOverheadSwBuffers = 0;
  1628. DPF (2, "DsGetCapsEmulated: Leave Function");
  1629. return DS_OK;
  1630. }
  1631. //--------------------------------------------------------------------------;
  1632. //
  1633. // DsGetCaps
  1634. //
  1635. // Description: This function gets the capabilty flags for the given
  1636. // device.
  1637. //
  1638. // Arguments: pds pointer to direct sound object to retrieve
  1639. // capabilities on.
  1640. // pDSCaps pointer to capabilities structure to be filled
  1641. //
  1642. // Concurrency: synchronous
  1643. //
  1644. // Return (HRESULT): DS_OK on Success
  1645. // refer to DsGetCapsNative or DsGetCapsEmulated
  1646. // error codes
  1647. //
  1648. //--------------------------------------------------------------------------;
  1649. HRESULT DsGetCaps
  1650. (
  1651. LPDSOUND pds,
  1652. LPDSCAPS pDSCaps
  1653. )
  1654. {
  1655. HRESULT hr;
  1656. DPF (2, "DsGetCaps: Enter Function");
  1657. DPF (2, "DsGetCaps: pds = %x", pds);
  1658. DPF (2, "DsGetCaps: pDSCaps = %x", pDSCaps);
  1659. ENTER_DLL_CSECT();
  1660. if( pds->fdwInternal & DS_INTERNALF_WAVEEMULATED ) {
  1661. DPF (3, "DsGetCaps: getting emulated capabilities");
  1662. hr = DsGetCapsEmulated (pDSCaps, pds);
  1663. } else {
  1664. DPF (3, "DsGetCaps: getting native capabilities");
  1665. hr = DsGetCapsNative (pDSCaps, pds);
  1666. }
  1667. if (DS_OK == hr) {
  1668. // Set driver version, as calculated on pds object creation.
  1669. pDSCaps->dwReserved1 = pds->dwDriverVersionMinor;
  1670. pDSCaps->dwReserved2 = pds->dwDriverVersionMajor;
  1671. // Set certified bit.
  1672. if( pds->fdwInternal & DS_INTERNALF_CERTIFIED ) {
  1673. pDSCaps->dwFlags |= DSCAPS_CERTIFIED;
  1674. }
  1675. DPF (3, "DsGetCaps: version information:");
  1676. DPF (3, "DsGetCaps: dwDriverVersionMinor = %d", pDSCaps->dwReserved1);
  1677. DPF (3, "DsGetCaps: dwDriverVersionMajor = %d", pDSCaps->dwReserved2);
  1678. DPF (3, "DsGetCaps: Certified? = %d",
  1679. pDSCaps->dwFlags & DSCAPS_CERTIFIED);
  1680. }
  1681. else {
  1682. DPF (1, "DsGetCaps: error getting capabilities (%d)", hr);
  1683. }
  1684. LEAVE_DLL_CSECT();
  1685. DPF (2, "DsGetCaps: Leave Function");
  1686. return hr;
  1687. }
  1688. //--------------------------------------------------------------------------;
  1689. //
  1690. // IDSHWGetCaps
  1691. //
  1692. // Description: Direct Sound Object member to determine hardware
  1693. // capabilities.
  1694. //
  1695. // Arguments: pids pointer to Direct Sound Object
  1696. // pDSCaps pointer to DS Capabilities structures
  1697. //
  1698. // Return (HRESULT):
  1699. // DS_OK Success
  1700. // DSERR_UNINITIALIZED if object has not be initialized
  1701. // DSERR_INVALIDPARAM a parameter could not be validated
  1702. // DSERR_GENERIC any error getting Capabilities
  1703. //
  1704. //--------------------------------------------------------------------------;
  1705. HRESULT FAR PASCAL IDSHWGetCaps
  1706. (
  1707. LPDIRECTSOUND pids,
  1708. LPDSCAPS pDSCaps
  1709. )
  1710. {
  1711. LPDSOUND pds;
  1712. LPDSOUNDEXTERNAL pdse;
  1713. HRESULT hr;
  1714. // Validation Code
  1715. if( !VALID_DSOUNDE_PTR(pids) ) {
  1716. RPF("IDirectSound::GetCaps - Invalid Object or ref count");
  1717. return DSERR_INVALIDPARAM;
  1718. }
  1719. pdse = (LPDSOUNDEXTERNAL)pids;
  1720. /* Check to see if object has been initialized */
  1721. if (IDSHWINITIALIZEF_UNINITIALIZED == pdse->fInitialized) {
  1722. RPF("Direct Sound Object is uninitialized.");
  1723. return DSERR_UNINITIALIZED;
  1724. }
  1725. pds = pdse->pds;
  1726. if( !VALID_DSOUND_PTR(pds) || (0 == pdse->uRefCount)) {
  1727. RPF("IDirectSound::GetCaps - Invalid Object or ref count");
  1728. return DSERR_INVALIDPARAM;
  1729. }
  1730. if( !VALID_DSCAPS_PTR(pDSCaps) ) {
  1731. RPF("IDirectSound::GetCaps - Invalid DSCAPS structure or dwSize member.");
  1732. return DSERR_INVALIDPARAM;
  1733. }
  1734. hr = DsGetCaps (pdse->pds, pDSCaps);
  1735. return hr;
  1736. }
  1737. //--------------------------------------------------------------------------;
  1738. //
  1739. // DSDeactivateApp
  1740. //
  1741. // In: hWnd Handle of application to deactivate
  1742. // bSticky DSDEACTIVATEAPPF_NONSTICKY will deactivate only
  1743. // non-sticky buffers
  1744. // DSDEACTIVATEAPPF_ALL will deactivate all buffers
  1745. //--------------------------------------------------------------------------;
  1746. void DSDeactivateApp(DWORD tid, enum DSDeactivateAppF bSticky)
  1747. {
  1748. LPDSOUNDEXTERNAL pdse;
  1749. LPDSBUFFEREXTERNAL pdsbe;
  1750. DPF(0,"###### Deactivate tid %X ######", tid);
  1751. for (pdse = gpdsinfo->pDSoundExternalObj; NULL != pdse; pdse = pdse->pNext)
  1752. {
  1753. if (tid == pdse->tidSound) {
  1754. for (pdsbe = pdse->pdsbe; NULL != pdsbe; pdsbe = pdsbe->pNext)
  1755. {
  1756. if ((DSDEACTIVATEAPPF_ALL == bSticky) ||
  1757. (FALSE == (DSBCAPS_STICKYFOCUS & pdsbe->pdsb->fdwBufferDesc)))
  1758. {
  1759. DSBufferDeactivate(pdsbe);
  1760. }
  1761. }
  1762. if (!(pdse->pds->fdwInternal & DS_INTERNALF_WAVEEMULATED)) {
  1763. mxSignalRemix(pdse->pds, 0);
  1764. }
  1765. }
  1766. }
  1767. }
  1768. //--------------------------------------------------------------------------;
  1769. //
  1770. // DSActivateApp
  1771. //
  1772. //--------------------------------------------------------------------------;
  1773. void DSActivateApp(DWORD tid)
  1774. {
  1775. LPDSOUND pds;
  1776. LPDSBUFFER pdsb;
  1777. LPDSOUNDEXTERNAL pdse;
  1778. LPDSBUFFEREXTERNAL pdsbe;
  1779. DWORD dwActivePrio;
  1780. BOOL fWritePrimary;
  1781. //
  1782. // Find the highest priority setting of all pdse under this hwnd
  1783. //
  1784. dwActivePrio = DSSCL_NORMAL;
  1785. for (pdse = gpdsinfo->pDSoundExternalObj; pdse; pdse = pdse->pNext) {
  1786. if (tid == pdse->tidSound && pdse->dwPriority > dwActivePrio) {
  1787. dwActivePrio = pdse->dwPriority;
  1788. }
  1789. }
  1790. DPF(0,"##### Activate tid %X Active Prio %X #####", tid, dwActivePrio);
  1791. fWritePrimary = (dwActivePrio >= DSSCL_WRITEPRIMARY);
  1792. //
  1793. // For all of the app's ds objects, set the format of the internal
  1794. // primary buffer to the app's format. Also play or stop the internal
  1795. // primary buffer as appropriate for the app we are activating.
  1796. //
  1797. // If we're WRITEPRIMARY, mark everyone else's external buffers as
  1798. // lost
  1799. //
  1800. for (pdse = gpdsinfo->pDSoundExternalObj; pdse; pdse = pdse->pNext) {
  1801. DPF(2, "Activating pdse %08Xh", pdse);
  1802. if (tid == pdse->tidSound) {
  1803. ASSERT(NULL != pdse->pds->pdsbPrimary);
  1804. if (NULL == pdse->pwfxApp) {
  1805. ASSERT(0 != pdse->pds->wfxDefault.wFormatTag);
  1806. IDsbSetFormatI(pdse->pds->pdsbPrimary, &pdse->pds->wfxDefault, 0);
  1807. } else {
  1808. IDsbSetFormatI(pdse->pds->pdsbPrimary, pdse->pwfxApp, 0);
  1809. }
  1810. //
  1811. // If we're not WRITEPRIMARY, then Play/Stop the primary per the
  1812. // the count of playing buffers
  1813. //
  1814. // We must be sure to call Play/Stop on the internal primary dsb's
  1815. // contained dsbe object so that Play/Stop doesn't operate on the
  1816. // app's primary dsbe object.
  1817. //
  1818. for (pdsbe = pdse->pdsbe; pdsbe; pdsbe = pdsbe->pNext) {
  1819. pdsb = pdsbe->pdsb;
  1820. pds = pdsb->pds;
  1821. if (pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY) {
  1822. ASSERT(pdsb == pds->pdsbPrimary);
  1823. // If the external primary has been played, then cPlayPrimary must be >0.
  1824. ASSERT( !( (pdsbe->fdwDsbeI&DSBE_INTERNALF_PLAYING) && (0==pds->cPlayPrimary) ) );
  1825. if( (!fWritePrimary) &&
  1826. ( (pds->cPlayPrimary > 0) ||
  1827. (pds->dwBuffersPlaying > 0) ) )
  1828. {
  1829. DPF(3, "DSActivateApp: playing primary dsb %08Xh, pdsb");
  1830. IDirectSoundBuffer_Play((LPDIRECTSOUNDBUFFER)pds->pdsbePrimary,
  1831. 0, 0, DSBPLAY_LOOPING);
  1832. } else {
  1833. DPF(3, "DSActivateApp: stopping primary dsb %08Xh, pdsb");
  1834. IDsbStopI(pdsb, FALSE);
  1835. }
  1836. }
  1837. }
  1838. } else if (fWritePrimary) {
  1839. for (pdsbe = pdse->pdsbe; pdsbe; pdsbe = pdsbe->pNext) {
  1840. //
  1841. // Stop all playing buffers
  1842. //
  1843. if( !(pdsbe->pdsb->fdwDsbI & DSB_INTERNALF_STOP) ) {
  1844. IDsbStopI(pdsbe->pdsb, FALSE);
  1845. }
  1846. //
  1847. // Lose all secondary buffers.
  1848. //
  1849. if( !(pdsbe->pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY) ) {
  1850. pdsbe->fdwDsbeI |= DSBE_INTERNALF_LOST;
  1851. }
  1852. //
  1853. // WRITEPRIMARY primaries should already be lost.
  1854. //
  1855. ASSERT( !(pdsbe->pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY ) ||
  1856. ( pdsbe->dwPriority < DSSCL_WRITEPRIMARY ) ||
  1857. ( pdsbe->fdwDsbeI & DSBE_INTERNALF_LOST ) );
  1858. }
  1859. }
  1860. }
  1861. //
  1862. // For every pdse that are in focus, we activate all its pdsbe.
  1863. // We also signal the mixer to remix for the pdse's pds.
  1864. //
  1865. for (pdse = gpdsinfo->pDSoundExternalObj; pdse; pdse = pdse->pNext) {
  1866. if (tid == pdse->tidSound) {
  1867. for (pdsbe = pdse->pdsbe; pdsbe; pdsbe = pdsbe->pNext) {
  1868. DSBufferActivate(pdsbe);
  1869. }
  1870. if (!(pdse->pds->fdwInternal & DS_INTERNALF_WAVEEMULATED)) {
  1871. mxSignalRemix(pdse->pds, 0);
  1872. }
  1873. }
  1874. }
  1875. }
  1876. //--------------------------------------------------------------------------;
  1877. //
  1878. // void apmResume
  1879. //
  1880. // Description:
  1881. //
  1882. // Arguments:
  1883. // none
  1884. //
  1885. // Return (void):
  1886. //
  1887. // History:
  1888. // 09/11/95 FrankYe Created
  1889. //
  1890. //--------------------------------------------------------------------------;
  1891. void apmResume(void)
  1892. {
  1893. LPDSOUND pds;
  1894. ENTER_DLL_CSECT();
  1895. if (gpdsinfo->fApmSuspended) {
  1896. gpdsinfo->fApmSuspended = FALSE;
  1897. for (pds = gpdsinfo->pDSoundObj; pds; pds = pds->pNext) {
  1898. IDsbSetFormatI( pds->pdsbPrimary, &pds->wfxDefault, IDSBSETFORMATIF_ALWAYS );
  1899. }
  1900. }
  1901. /* Update Focus and Stuck handles */
  1902. ActivateFocusWindow();
  1903. LEAVE_DLL_CSECT();
  1904. }
  1905. //--------------------------------------------------------------------------;
  1906. //
  1907. // void apmSuspend
  1908. //
  1909. // Description:
  1910. //
  1911. // Arguments:
  1912. // none
  1913. //
  1914. // Return (void):
  1915. //
  1916. // History:
  1917. // 09/11/95 FrankYe Created
  1918. //
  1919. //--------------------------------------------------------------------------;
  1920. void apmSuspend(void)
  1921. {
  1922. LPDSOUNDEXTERNAL pdse;
  1923. LPDSBUFFEREXTERNAL pdsbe;
  1924. ENTER_DLL_CSECT();
  1925. DSDeactivateApp(gpdsinfo->tidSoundFocus, DSDEACTIVATEAPPF_ALL);
  1926. for (pdse = gpdsinfo->pDSoundExternalObj; pdse; pdse = pdse->pNext) {
  1927. for (pdsbe = pdse->pdsbe; pdsbe; pdsbe = pdsbe->pNext) {
  1928. if( !(pdsbe->pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY) ) {
  1929. //
  1930. // Stop all playing buffers
  1931. //
  1932. if( !(pdsbe->pdsb->fdwDsbI & DSB_INTERNALF_STOP) ) {
  1933. IDsbStopI(pdsbe->pdsb, FALSE);
  1934. }
  1935. //
  1936. // Lose all secondary buffers.
  1937. //
  1938. pdsbe->fdwDsbeI |= DSBE_INTERNALF_LOST;
  1939. }
  1940. }
  1941. for (pdsbe = pdse->pdsbe; pdsbe; pdsbe = pdsbe->pNext) {
  1942. if (pdsbe->pdsb->fdwDsbI & DSB_INTERNALF_PRIMARY) {
  1943. if( !(pdsbe->pdsb->fdwDsbI & DSB_INTERNALF_STOP) ) {
  1944. IDsbStopI(pdsbe->pdsb, FALSE);
  1945. }
  1946. //
  1947. // WRITEPRIMARY primaries should already be lost.
  1948. //
  1949. ASSERT( ( pdsbe->dwPriority < DSSCL_WRITEPRIMARY ) ||
  1950. ( pdsbe->fdwDsbeI & DSBE_INTERNALF_LOST ) );
  1951. }
  1952. }
  1953. }
  1954. gpdsinfo->fApmSuspended = TRUE;
  1955. LEAVE_DLL_CSECT();
  1956. }
  1957. //--------------------------------------------------------------------------;
  1958. //
  1959. // SubclassWndProc
  1960. //
  1961. // We use APM notifications to help use get the native DS drivers
  1962. // into a state proper for suspending. If we are compiling for
  1963. // emulation mode only, then we don't need to catch these APM
  1964. // notifications.
  1965. //
  1966. //--------------------------------------------------------------------------;
  1967. #ifndef DSBLD_EMULONLY
  1968. LRESULT CALLBACK SubclassWndProc
  1969. (
  1970. HWND hWnd,
  1971. UINT uMessage,
  1972. WPARAM wParam,
  1973. LPARAM lParam
  1974. )
  1975. {
  1976. DPF(9,"Sublcass Window %X Message %X wParam %X, lParam %X ",
  1977. (DWORD)hWnd, (DWORD)uMessage, (DWORD)wParam, (DWORD)lParam );
  1978. switch(uMessage)
  1979. {
  1980. case WM_POWERBROADCAST:
  1981. switch (wParam) {
  1982. case PBT_APMSUSPEND:
  1983. apmSuspend();
  1984. return TRUE;
  1985. case PBT_APMRESUMESUSPEND:
  1986. apmResume();
  1987. return TRUE;
  1988. }
  1989. }
  1990. return 0;
  1991. } // SubclassWndProc()
  1992. #endif
  1993. //--------------------------------------------------------------------------;
  1994. //
  1995. // IDSHWSetCooperativeLevel
  1996. //
  1997. // Description:
  1998. //
  1999. // Arguments:
  2000. //
  2001. // Return (HRESULT):
  2002. // DSERR_UNINITIALIZED if object has not be initialized
  2003. //
  2004. // History:
  2005. // 02/11/96 angusm Added check for initialization
  2006. //
  2007. //--------------------------------------------------------------------------;
  2008. HRESULT FAR PASCAL IDSHWSetCooperativeLevel
  2009. (
  2010. LPDIRECTSOUND pids,
  2011. HWND hwnd,
  2012. DWORD dwPriority
  2013. )
  2014. {
  2015. LPDSOUND pds;
  2016. LPDSOUNDEXTERNAL pdse;
  2017. LPDSBUFFEREXTERNAL pdsbeSearch;
  2018. DWORD dwProcessIdCaller;
  2019. DWORD tid;
  2020. if( !VALID_DSOUNDE_PTR(pids) ) {
  2021. RPF("IDirectSound::SetCooperativeLevel - Invalid Object or ref count");
  2022. return DSERR_INVALIDPARAM;
  2023. }
  2024. pdse = (LPDSOUNDEXTERNAL)pids;
  2025. /* Check to see if the object is initialized */
  2026. if (IDSHWINITIALIZEF_UNINITIALIZED == pdse->fInitialized) {
  2027. RPF("Direct Sound Object is uninitialized.");
  2028. return DSERR_UNINITIALIZED;
  2029. }
  2030. pds = pdse->pds;
  2031. if( !VALID_DSOUND_PTR(pds) || (0 == pdse->uRefCount)) {
  2032. RPF("IDirectSound::SetCooperativeLevel - Invalid Object or ref count");
  2033. return DSERR_INVALIDPARAM;
  2034. }
  2035. if( !VALID_HWND(hwnd) ) {
  2036. RPF("IDirectSound::SetCooperativeLevel - Invalid hwnd");
  2037. return DSERR_INVALIDPARAM;
  2038. }
  2039. if((dwPriority < DSSCL_FIRST) || (dwPriority > DSSCL_LAST)) {
  2040. RPF("IDirectSound::SetCooperativeLevel - Invalid DSSCL_* passed to SetCooperativeLevel");
  2041. return DSERR_INVALIDPARAM;
  2042. }
  2043. //
  2044. // Due to bugs in the wave emulation code, we don't allow writeprimary
  2045. // level on unsupported cards. This should be fixed. BUGBUG REMIND
  2046. //
  2047. if( ( pds->fdwInternal & DS_INTERNALF_WAVEEMULATED ) &&
  2048. ( dwPriority >= DSSCL_WRITEPRIMARY ) )
  2049. {
  2050. RPF("IDirectSound::SetCooperativeLevel - DSSCL_WRITEPRIMARY level not available on emulated drivers.");
  2051. return DSERR_INVALIDCALL;
  2052. }
  2053. /* set the actual window handle that sound */
  2054. /* focus is tracked on to be the top unowned */
  2055. /* window. */
  2056. hwnd = GetTopUnownedWindow (hwnd);
  2057. tid = GetWindowThreadProcessId(hwnd, NULL);
  2058. DPF(3,"=== Enter SetCooperativeLevel ===");
  2059. ENTER_DLL_CSECT();
  2060. dwProcessIdCaller = GetCurrentProcessId();
  2061. // We use DSoundHelp to give us APM window notifications. If we are
  2062. // building only for emulation mode then we don't need APM notifications
  2063. // since APM will be handled entirely by the WAVE drivers that we are
  2064. // using for emulation.
  2065. #ifndef DSBLD_EMULONLY
  2066. // The first time this is called, register the window
  2067. if( pdse->hwndCooperative == 0 ) {
  2068. DSoundHelp( hwnd, SubclassWndProc, dwProcessIdCaller );
  2069. } else {
  2070. // If we are given a new window, then release old window and add new
  2071. if( pdse->hwndCooperative != hwnd ) {
  2072. DSoundHelp( NULL, SubclassWndProc, dwProcessIdCaller );
  2073. DSoundHelp( hwnd, SubclassWndProc, dwProcessIdCaller );
  2074. }
  2075. }
  2076. #endif
  2077. pdse->tidSound = tid;
  2078. pdse->hwndCooperative = hwnd;
  2079. pdse->dwPriority = dwPriority;
  2080. // Update all buffers under this object to reflect the new priority level
  2081. pdsbeSearch = pdse->pdsbe;
  2082. while( pdsbeSearch != NULL ) {
  2083. pdsbeSearch->dwPriority = dwPriority;
  2084. pdsbeSearch = pdsbeSearch->pNext;
  2085. }
  2086. DseUpdateActivationState(pdse);
  2087. LEAVE_DLL_CSECT();
  2088. DPF(3,"=== Exit SetCooperativeLevel ===");
  2089. return DS_OK;
  2090. }
  2091. //--------------------------------------------------------------------------;
  2092. //
  2093. // IDSHWCompact
  2094. //
  2095. // Description:
  2096. //
  2097. // Arguments:
  2098. //
  2099. // Return (HRESULT):
  2100. // DSERR_UNINITIALIZED if object has not be initialized
  2101. //
  2102. // History:
  2103. // 02/11/96 angusm Added check for initialization
  2104. //
  2105. //--------------------------------------------------------------------------;
  2106. HRESULT FAR PASCAL IDSHWCompact
  2107. (
  2108. LPDIRECTSOUND pids
  2109. )
  2110. {
  2111. LPDSOUND pds;
  2112. LPDSOUNDEXTERNAL pdse;
  2113. if( !VALID_DSOUNDE_PTR(pids) ) {
  2114. RPF("IDirectSound::Compact - Invalid Object or ref count");
  2115. return DSERR_INVALIDPARAM;
  2116. }
  2117. pdse = (LPDSOUNDEXTERNAL)pids;
  2118. /* Check to see if the object is initialized */
  2119. if (IDSHWINITIALIZEF_UNINITIALIZED == pdse->fInitialized) {
  2120. RPF("Direct Sound Object is uninitialized.");
  2121. return DSERR_UNINITIALIZED;
  2122. }
  2123. pds = pdse->pds;
  2124. if( !VALID_DSOUND_PTR(pds) || (0 == pdse->uRefCount)) {
  2125. RPF("IDirectSound::Compact - Invalid Object or ref count");
  2126. return DSERR_INVALIDPARAM;
  2127. }
  2128. if (DSSCL_NORMAL == pdse->dwPriority) {
  2129. RPF("IDirectSound::Compact - Compact with priority DSSCL_NORMAL");
  2130. return DSERR_PRIOLEVELNEEDED;
  2131. }
  2132. return DS_OK;
  2133. }
  2134. //--------------------------------------------------------------------------;
  2135. //
  2136. // IDSHWGetSpeakerConfig
  2137. //
  2138. // Description:
  2139. //
  2140. // Arguments:
  2141. //
  2142. // Return (HRESULT):
  2143. // DSERR_UNINITIALIZED if object has not be initialized
  2144. //
  2145. // History:
  2146. // 02/11/96 angusm Added check for initialization
  2147. //
  2148. //--------------------------------------------------------------------------;
  2149. HRESULT FAR PASCAL IDSHWGetSpeakerConfig
  2150. (
  2151. LPDIRECTSOUND pids,
  2152. LPDWORD pdwConfig
  2153. )
  2154. {
  2155. LPDSOUND pds;
  2156. LPDSOUNDEXTERNAL pdse;
  2157. if( !VALID_DSOUNDE_PTR(pids) ) {
  2158. RPF("IDirectSound::GetSpeakerConfig - Invalid Object or ref count");
  2159. return DSERR_INVALIDPARAM;
  2160. }
  2161. pdse = (LPDSOUNDEXTERNAL)pids;
  2162. /* Check to see if the object is initialized */
  2163. if (IDSHWINITIALIZEF_UNINITIALIZED == pdse->fInitialized) {
  2164. RPF("Direct Sound Object is uninitialized.");
  2165. return DSERR_UNINITIALIZED;
  2166. }
  2167. pds = pdse->pds;
  2168. if( !VALID_DSOUND_PTR(pds) || (0 == pdse->uRefCount)) {
  2169. RPF("IDirectSound::GetSpeakerConfig - Invalid Object or ref count");
  2170. return DSERR_INVALIDPARAM;
  2171. }
  2172. if( !VALID_DWORD_PTR(pdwConfig)) {
  2173. RPF("IDirectSound::GetSpeakerConfig - Invalid pointer passed to GetSpeakerConfig()");
  2174. return DSERR_INVALIDPARAM;
  2175. }
  2176. ENTER_DLL_CSECT();
  2177. *pdwConfig = pdse->dwSpeakerConfig;
  2178. LEAVE_DLL_CSECT();
  2179. return DS_OK;
  2180. }
  2181. //--------------------------------------------------------------------------;
  2182. //
  2183. // IDSHWSetSpeakerConfig
  2184. //
  2185. // Description:
  2186. //
  2187. // Arguments:
  2188. //
  2189. // Return (HRESULT):
  2190. // DSERR_UNINITIALIZED if object has not be initialized
  2191. //
  2192. // History:
  2193. // 02/11/96 angusm Added check for initialization
  2194. //
  2195. //--------------------------------------------------------------------------;
  2196. HRESULT FAR PASCAL IDSHWSetSpeakerConfig
  2197. (
  2198. LPDIRECTSOUND pids,
  2199. DWORD dwConfig
  2200. )
  2201. {
  2202. LPDSOUND pds;
  2203. LPDSOUNDEXTERNAL pdse;
  2204. if( !VALID_DSOUNDE_PTR(pids) ) {
  2205. RPF("IDirectSound::SetSpeakerConfig - Invalid Object or ref count");
  2206. return DSERR_INVALIDPARAM;
  2207. }
  2208. pdse = (LPDSOUNDEXTERNAL)pids;
  2209. /* Check to see if the object is initialized */
  2210. if (IDSHWINITIALIZEF_UNINITIALIZED == pdse->fInitialized) {
  2211. RPF("Direct Sound Object is uninitialized.");
  2212. return DSERR_UNINITIALIZED;
  2213. }
  2214. pds = pdse->pds;
  2215. if( !VALID_DSOUND_PTR(pds) || (0 == pdse->uRefCount)) {
  2216. RPF("IDirectSound::SetSpeakerConfig - Invalid Object or ref count");
  2217. return DSERR_INVALIDPARAM;
  2218. }
  2219. if(( dwConfig < DSSPEAKER_FIRST ) || ( dwConfig > DSSPEAKER_LAST )) {
  2220. RPF("IDirectSound::SetSpeakerConfig - Invalid Config value");
  2221. return DSERR_INVALIDPARAM;
  2222. }
  2223. ENTER_DLL_CSECT();
  2224. // We're not doing a darn thing with this other than saving away the
  2225. // value until we get 3D sound...
  2226. pdse->dwSpeakerConfig = dwConfig;
  2227. LEAVE_DLL_CSECT();
  2228. return DS_OK;
  2229. }
  2230. //--------------------------------------------------------------------------;
  2231. //
  2232. // IDSHWInitialize
  2233. //
  2234. // Description:
  2235. //
  2236. // Arguments:
  2237. //
  2238. // Return ():
  2239. //
  2240. // History:
  2241. // 02/11/96 angusm Added init code from DirectSoundCreate
  2242. //
  2243. //--------------------------------------------------------------------------;
  2244. HRESULT FAR PASCAL IDSHWInitialize
  2245. (
  2246. LPDIRECTSOUND pids,
  2247. GUID FAR *lpGUID
  2248. )
  2249. {
  2250. LPDSOUNDEXTERNAL pdse;
  2251. GUID guid, guidLast;
  2252. DSDRIVERDESC dsDrvDesc;
  2253. UINT cWaves;
  2254. UINT uPreferredWaveId;
  2255. UINT uWaveId;
  2256. BOOL fPreferredOnly;
  2257. HRESULT hr;
  2258. HRESULT hrClient;
  2259. if( !VALID_DSOUNDE_PTR(pids) ) {
  2260. RPF("IDirectSound::Initialize - Invalid Object or ref count");
  2261. return DSERR_INVALIDPARAM;
  2262. }
  2263. pdse = (LPDSOUNDEXTERNAL)pids;
  2264. /* Check to see if the object is initialized */
  2265. if (IDSHWINITIALIZEF_INITIALIZED == pdse->fInitialized) {
  2266. return DSERR_ALREADYINITIALIZED;
  2267. }
  2268. cWaves = waveOutGetNumDevs();
  2269. cWaves = min(cWaves, LIMIT_WAVE_DEVICES-1);
  2270. if (0 == cWaves) return DSERR_NODRIVER;
  2271. if (!wavGetPreferredId(&uPreferredWaveId, &fPreferredOnly)) {
  2272. return DSERR_NODRIVER;
  2273. }
  2274. ENTER_DLL_CSECT();
  2275. if (NULL == lpGUID) {
  2276. hrClient = DSERR_NODRIVER;
  2277. #if defined(RDEBUG) || defined(DEBUG)
  2278. if (!gpdsinfo->fEnumOnlyWaveDevs)
  2279. #endif
  2280. {
  2281. hr = wavGetDrvGuidFromId(uPreferredWaveId, &guid);
  2282. if (DS_OK == hr) {
  2283. hr = hrClient = DseInitializeFromGuid(pdse, &guid);
  2284. }
  2285. if ((DS_OK != hr) && !fPreferredOnly) {
  2286. ZeroMemory(&dsDrvDesc, sizeof(dsDrvDesc));
  2287. hr = vxdDrvGetNextDriverDesc(NULL, &guid, &dsDrvDesc);
  2288. while (DS_OK == hr) {
  2289. if ((DS_OK == wavGetIdFromDrvGuid(&guid, &uWaveId)) &&
  2290. wavIsMappable(uWaveId))
  2291. {
  2292. hr = hrClient = DseInitializeFromGuid(pdse, &guid);
  2293. if (DS_OK == hr) break;
  2294. }
  2295. guidLast = guid;
  2296. ZeroMemory(&dsDrvDesc, sizeof(dsDrvDesc));
  2297. hr = vxdDrvGetNextDriverDesc(&guidLast, &guid, &dsDrvDesc);
  2298. }
  2299. }
  2300. }
  2301. if ((DS_OK != hrClient) && (uPreferredWaveId < cWaves)) {
  2302. guid = gpdsinfo->aguidWave[uPreferredWaveId];
  2303. hr = hrClient = DseInitializeFromGuid(pdse, &guid);
  2304. }
  2305. if ((DS_OK != hrClient) && !fPreferredOnly) {
  2306. uWaveId = 0;
  2307. while (uWaveId < cWaves) {
  2308. guid = gpdsinfo->aguidWave[uWaveId];
  2309. if (wavIsMappable(uWaveId)) {
  2310. hr = hrClient = DseInitializeFromGuid(pdse, &guid);
  2311. if (DS_OK == hr) break;
  2312. }
  2313. uWaveId++;
  2314. }
  2315. }
  2316. } else {
  2317. // NULL != lpGUID
  2318. hrClient = DseInitializeFromGuid(pdse, lpGUID);
  2319. }
  2320. /* Check to see if this is the first buffer */
  2321. /* created, and start Focus Thread. */
  2322. if ((DS_OK == hrClient) && (1 == cSoundObjects())) {
  2323. if (!CreateFocusThread()) {
  2324. hrClient = DSERR_GENERIC;
  2325. DseTerminate(pdse);
  2326. }
  2327. }
  2328. if (DS_OK == hrClient) {
  2329. pdse->fInitialized = IDSHWINITIALIZEF_INITIALIZED;
  2330. }
  2331. LEAVE_DLL_CSECT();
  2332. return hrClient;
  2333. } // IDSHWInitialize()
  2334. // This code is disabled for now...
  2335. #ifdef ENABLE_EXCLUSIVEMODE_STUFF
  2336. //--------------------------------------------------------------------------;
  2337. //
  2338. // IDSHWGetExclusiveModeOwner
  2339. //
  2340. // Description:
  2341. //
  2342. // Arguments:
  2343. //
  2344. // Return (HRESULT):
  2345. // DSERR_UNINITIALIZED if object has not be initialized
  2346. //
  2347. // History:
  2348. // 02/11/96 angusm Added check for initialization
  2349. //
  2350. //--------------------------------------------------------------------------;
  2351. HRESULT FAR PASCAL IDSHWGetExclusiveModeOwner
  2352. (
  2353. LPDIRECTSOUND pids,
  2354. LPHANDLE phProcess
  2355. )
  2356. {
  2357. LPDSOUND pds;
  2358. LPDSOUNDEXTERNAL pdse;
  2359. if( !VALID_DSOUNDE_PTR(pids) ) {
  2360. DPF(0,"Invalid Object or ref count");
  2361. return DSERR_INVALIDPARAM;
  2362. }
  2363. pdse = (LPDSOUNDEXTERNAL)pids;
  2364. /* Check to see if the object is initialized */
  2365. if (IDSHWINITIALIZEF_UNINITIALIZED == pdse->fInitialized) {
  2366. RPF("Direct Sound Object is uninitialized.");
  2367. return DSERR_UNINITIALIZED;
  2368. }
  2369. pds = pdse->pds;
  2370. if( !VALID_DSOUND_PTR(pds) || (0 == pdse->uRefCount)) {
  2371. DPF(0,"Invalid Object or ref count");
  2372. return DSERR_INVALIDPARAM;
  2373. }
  2374. ENTER_DLL_CSECT();
  2375. *phProcess = pds->hExclusiveOwner;
  2376. LEAVE_DLL_CSECT();
  2377. return DS_OK;
  2378. }
  2379. //--------------------------------------------------------------------------;
  2380. //
  2381. // IDSHWSetExclusiveModeOwner
  2382. //
  2383. // Description:
  2384. //
  2385. // Arguments:
  2386. //
  2387. // Return (HRESULT):
  2388. // DSERR_UNINITIALIZED if object has not be initialized
  2389. //
  2390. // History:
  2391. // 02/11/96 angusm Added check for initialization
  2392. //
  2393. //--------------------------------------------------------------------------;
  2394. HRESULT FAR PASCAL IDSHWSetExclusiveModeOwner
  2395. (
  2396. LPDIRECTSOUND pids,
  2397. DWORD fdwFlags
  2398. )
  2399. {
  2400. LPDSOUND pds;
  2401. LPDSOUNDEXTERNAL pdse;
  2402. if( !VALID_DSOUNDE_PTR(pids) ) {
  2403. DPF(0,"Invalid Object or ref count");
  2404. return DSERR_INVALIDPARAM;
  2405. }
  2406. pdse = (LPDSOUNDEXTERNAL)pids;
  2407. /* Check to see if the object is initialized */
  2408. if (IDSHWINITIALIZEF_UNINITIALIZED == pdse->fInitialized) {
  2409. RPF("Direct Sound Object is uninitialized.");
  2410. return DSERR_UNINITIALIZED;
  2411. }
  2412. pds = pdse->pds;
  2413. if( !VALID_DSOUND_PTR(pds) || (0 == pdse->uRefCount)) {
  2414. DPF(0,"Invalid Object or ref count");
  2415. return DSERR_INVALIDPARAM;
  2416. }
  2417. ENTER_DLL_CSECT();
  2418. if( (pds->hExclusiveOwner != NULL) &&
  2419. (pds->hExclusiveOwner != (HANDLE)GetCurrentProcessId()) ) {
  2420. DPF(0,"Exclusive mode already set");
  2421. LEAVE_DLL_CSECT();
  2422. return DSERR_GENERIC;
  2423. }
  2424. if( fdwFlags & DS_EXCLUSIVEF_NONEXCLUSIVE ) {
  2425. pds->fdwExclusive = 0;
  2426. pds->hExclusiveOwner = 0;
  2427. } else {
  2428. pds->fdwExclusive = fdwFlags;
  2429. pds->hExclusiveOwner = (HANDLE)GetCurrentProcessId();
  2430. }
  2431. LEAVE_DLL_CSECT();
  2432. return DSERR_OK;
  2433. }
  2434. #endif
  2435. void FNGLOBAL DSHWCreateTable
  2436. (
  2437. LPDSOUNDCALLBACKS lpVtbl
  2438. )
  2439. {
  2440. lpVtbl->QueryInterface = IDSHWQueryInterface;
  2441. lpVtbl->AddRef = IDSHWAddRef;
  2442. lpVtbl->Release = IDSHWRelease;
  2443. lpVtbl->CreateSoundBuffer = IDSHWCreateSoundBuffer;
  2444. lpVtbl->GetCaps = IDSHWGetCaps;
  2445. lpVtbl->DuplicateSoundBuffer
  2446. = IDSHWDuplicateSoundBuffer;
  2447. lpVtbl->SetCooperativeLevel = IDSHWSetCooperativeLevel;
  2448. lpVtbl->Compact = IDSHWCompact;
  2449. lpVtbl->GetSpeakerConfig = IDSHWGetSpeakerConfig;
  2450. lpVtbl->SetSpeakerConfig = IDSHWSetSpeakerConfig;
  2451. lpVtbl->Initialize = IDSHWInitialize;
  2452. } // DSHWCreateTable()
  2453. /* GetTopUnownedWindow
  2454. * This function finds the top-most unowned window ancesting for the
  2455. * given window handle.
  2456. *
  2457. * IN: a valid Window handle
  2458. * OUT: the top-most unowned window ancesting from hWindow
  2459. * SIDE EFFECTS: none
  2460. * NOTES: This function must be called in a Dll Critical Section
  2461. *
  2462. * REVISION HISTORY:
  2463. * 11/27/95 angusm Initial Version
  2464. * 12/06/95 angusm Removed supurpholous call to GetWindow( , GW_OWNER)
  2465. * 12/10/95 angusm Code style cleanup
  2466. */
  2467. HWND GetTopUnownedWindow (HWND hWindow)
  2468. {
  2469. HWND hTempWindow = hWindow;
  2470. while (NULL != hTempWindow)
  2471. {
  2472. hWindow = hTempWindow;
  2473. ASSERT (hWindow);
  2474. hTempWindow = GetParent (hWindow); /* This call will return the owner,
  2475. if on exists, for top level
  2476. windows. */
  2477. }
  2478. return hWindow;
  2479. }
  2480. /* FocusTracker
  2481. * This function is a thread that runs in the process space of DDHelp,
  2482. * and polls to see which window is the top unowned window. If the window
  2483. * has changed the sound focus changes.
  2484. *
  2485. * IN: the number of miliseconds to wait between polls
  2486. * OUT: none
  2487. * SIDE EFFECTS: The sound focus will change
  2488. * NOTES: 1. The hwndStuckSoundFocus, and validity of the current Focus handle may
  2489. * change outside of this thread. (In apmResume and SetCooperativeL.
  2490. *
  2491. * REVISION HISTORY:
  2492. * 11/27/95 angusm Initial Version
  2493. * 12/10/95 angusm added FocusLock creation
  2494. * 12/10/95 angusm Code style cleanup
  2495. * 03/20/96 angusm Added Sticky focus logic
  2496. */
  2497. DWORD WINAPI FocusTracker (LPVOID lpvPollInterval)
  2498. {
  2499. HWND hNewWindowFocus;
  2500. BOOL fIsNewWindowValid;
  2501. BOOL fIsNewWindowMinimized;
  2502. HWND hOldWindowFocus = NULL;
  2503. DWORD tidOldWindowFocus = 0;
  2504. BOOL fIsOldWindowValid = FALSE;
  2505. BOOL fIsOldWindowMinimized = FALSE;
  2506. HANDLE hWaitEvent;
  2507. HANDLE hFocusLock;
  2508. HANDLE hStartupEvent;
  2509. DWORD nRetVal;
  2510. WINDOWPLACEMENT wndplPlacement;
  2511. DWORD tid;
  2512. DPF (2, "FocusTracker: Enter Function (lpvPollInterval = %x)",
  2513. lpvPollInterval);
  2514. /* Create "Wait" Event */
  2515. hWaitEvent = CreateEvent (NULL, /* No security attribs */
  2516. TRUE, /* manual-reset */
  2517. FALSE, /* nonsignaled */
  2518. WAKEFOCUSTHREAD); /* event name */
  2519. if (NULL == hWaitEvent) { /* On Error ... */
  2520. DPF(0, "FocusTracker: Could not create DSWakeFocusThread "
  2521. "event; exiting" );
  2522. ExitThread (0);
  2523. }
  2524. /* Grab Focus Lock */
  2525. if (FALSE == CreateFocusLock (&hFocusLock)) {
  2526. DPF(1, "FocusTracker: Could not create Focus Lock" );
  2527. }
  2528. /* Open Focus Thread startup
  2529. startup verification event */
  2530. hStartupEvent = OpenEvent (EVENT_MODIFY_STATE, /* only allowed to pulse */
  2531. FALSE, /* non inheritable */
  2532. FOCUSSTARTUPEVENT);
  2533. if (NULL == hStartupEvent) { /* On Error ... */
  2534. DPF(0, "FocusTracker: Could not open Startup Event; exiting" );
  2535. if (FALSE == DestroyFocusLock (hFocusLock)) {
  2536. DPF (1, "FocusTracker: Could not destroy focus lock.");
  2537. }
  2538. if (FALSE == CloseHandle (hWaitEvent)) ASSERT (0);
  2539. ExitThread (0);
  2540. }
  2541. /* Handle Cleanup */
  2542. if (FALSE == SetEvent (hStartupEvent)) ASSERT (0);
  2543. if (FALSE == CloseHandle (hStartupEvent)) ASSERT (0);
  2544. wndplPlacement.length = sizeof(WINDOWPLACEMENT);
  2545. while (1) /* Focus Tracking Loop */
  2546. {
  2547. DWORD dwWaitResult;
  2548. hNewWindowFocus = GetTopUnownedWindow (GetForegroundWindow());
  2549. if (hOldWindowFocus != hNewWindowFocus)
  2550. {
  2551. DWORD tidNewFocus;
  2552. DPF(3, "FocusTracker: New Focus = %x Old Focus = %x",
  2553. hNewWindowFocus, hOldWindowFocus);
  2554. tidNewFocus = hNewWindowFocus ? GetWindowThreadProcessId(hNewWindowFocus, NULL) : 0;
  2555. fIsNewWindowValid = IsValidDSApp(tidNewFocus);
  2556. nRetVal = ENTER_DLL_CSECT_OR_EVENT (hWaitEvent);
  2557. if (WAIT_OBJECT_0 == nRetVal) { /* If Wait Event is signaled */
  2558. DPF (3, "FocusTracker: breaking on Wait Event");
  2559. break;
  2560. } /* Else we have taken the DLL_CSECT */
  2561. if (hNewWindowFocus) {
  2562. GetWindowPlacement (hNewWindowFocus, &wndplPlacement);
  2563. fIsNewWindowMinimized = (SW_SHOWMINIMIZED == wndplPlacement.showCmd);
  2564. } else {
  2565. fIsNewWindowMinimized = FALSE;
  2566. }
  2567. if (fIsNewWindowValid && !fIsNewWindowMinimized)
  2568. /* New window uses Direct Sound and is not minimized */
  2569. {
  2570. DPF (3, "FocusTracker: switching to DS app"
  2571. " gpdsinfo->tidStuckFocus = %x, "
  2572. "tidNewFocus = %x",
  2573. gpdsinfo->tidStuckFocus, tidNewFocus);
  2574. // If focus is switching back to the hwnd that was stuck
  2575. // then we don't need to deactivate the stuck hwnd.
  2576. if (gpdsinfo->tidStuckFocus != tidNewFocus) {
  2577. DSDeactivateApp (gpdsinfo->tidStuckFocus,
  2578. DSDEACTIVATEAPPF_ALL);
  2579. gpdsinfo->tidStuckFocus = tidNewFocus;
  2580. }
  2581. DSActivateApp (tidNewFocus);
  2582. gpdsinfo->tidSoundFocus = tidNewFocus;
  2583. gpdsinfo->hwndSoundFocus = hNewWindowFocus;
  2584. }
  2585. else /* New window is not associated with a Direct Sound object,
  2586. or the application is minimized */
  2587. {
  2588. DPF (3, "FocusTracker: switching away from DS app"
  2589. " hOldWindowFocus = %x", hOldWindowFocus);
  2590. fIsOldWindowValid = IsValidDSApp (tidOldWindowFocus);
  2591. if (fIsOldWindowValid && gpdsinfo->hwndSoundFocus) {
  2592. DSDeactivateApp (gpdsinfo->tidSoundFocus,
  2593. DSDEACTIVATEAPPF_NONSTICKY);
  2594. }
  2595. if (fIsNewWindowMinimized && fIsNewWindowValid)
  2596. /* there is a minimized ds app */
  2597. {
  2598. gpdsinfo->tidSoundFocus = 0;
  2599. gpdsinfo->hwndSoundFocus = NULL;
  2600. }
  2601. else
  2602. {
  2603. gpdsinfo->tidSoundFocus = tidNewFocus;
  2604. gpdsinfo->hwndSoundFocus = hNewWindowFocus;
  2605. }
  2606. }
  2607. hOldWindowFocus = hNewWindowFocus;
  2608. tidOldWindowFocus = tidNewFocus;
  2609. fIsOldWindowValid = fIsNewWindowValid;
  2610. fIsOldWindowMinimized = fIsNewWindowMinimized;
  2611. LEAVE_DLL_CSECT();
  2612. } else if (fIsOldWindowValid && fIsOldWindowMinimized)
  2613. {
  2614. DPF (3, "FocusTracker: switching DS from minimization"
  2615. " hOldWindowFocus = %x", hOldWindowFocus);
  2616. ASSERT (hOldWindowFocus);
  2617. GetWindowPlacement (hOldWindowFocus, &wndplPlacement);
  2618. fIsNewWindowMinimized = (SW_SHOWMINIMIZED == wndplPlacement.showCmd);
  2619. /* Old window is a DS app but has been maximized */
  2620. if (!fIsNewWindowMinimized)
  2621. {
  2622. nRetVal = ENTER_DLL_CSECT_OR_EVENT (hWaitEvent);
  2623. if (WAIT_OBJECT_0 == nRetVal) { /* If Wait Event is signaled */
  2624. DPF (3, "FocusTracker: breaking on Wait Event");
  2625. break;
  2626. } /* Else we have taken the DLL_CSECT */
  2627. tid = GetWindowThreadProcessId(hOldWindowFocus, NULL);
  2628. if (gpdsinfo->tidStuckFocus != tid) {
  2629. DSDeactivateApp (gpdsinfo->tidStuckFocus, DSDEACTIVATEAPPF_ALL);
  2630. gpdsinfo->tidStuckFocus = tid;
  2631. }
  2632. DSActivateApp(tid);
  2633. gpdsinfo->tidSoundFocus = tid;
  2634. gpdsinfo->hwndSoundFocus = hOldWindowFocus;
  2635. fIsOldWindowMinimized = fIsNewWindowMinimized;
  2636. LEAVE_DLL_CSECT();
  2637. }
  2638. }
  2639. dwWaitResult = WaitForSingleObjectEx(hWaitEvent, (DWORD)lpvPollInterval, FALSE);
  2640. if (WAIT_OBJECT_0 == dwWaitResult) break;
  2641. ASSERT(WAIT_TIMEOUT == dwWaitResult);
  2642. } /* while (1) */
  2643. /* Free Focus Lock */
  2644. if (FALSE == DestroyFocusLock (hFocusLock)) {
  2645. DPF (1, "Could not destroy focus lock.");
  2646. }
  2647. /* Cleanup Handles */
  2648. if (FALSE == CloseHandle (hWaitEvent)) ASSERT (0);
  2649. if (FALSE == CloseHandle (gpdsinfo->hFocusTracker)) ASSERT (0);
  2650. DPF (2, "FocusTracker: Exit Function");
  2651. ExitThread (0);
  2652. return 0; /* This should never be reached. */
  2653. }
  2654. /* IsValidDSApp
  2655. * This function walks the external Direct Sound structures to see if the
  2656. * given tid is a valid direct sound thread.
  2657. *
  2658. * IN: any tid
  2659. * OUT: TRUE if it is a Direct Sound thread, FALSE otherwise
  2660. * SIDE EFFECTS: none
  2661. * NOTES: This function must be called in a Dll Critical Section if you
  2662. * need the returned value to be correct. Otherwise, the returned value
  2663. * may be a false answer.
  2664. *
  2665. * REVISION HISTORY:
  2666. * 11/27/95 angusm Initial Version
  2667. * 12/06/95 angusm appended to NOTES:
  2668. * 12/10/95 angusm Added FocusLock calls
  2669. * 12/10/95 angusm Code style cleanup
  2670. */
  2671. BOOL IsValidDSApp (DWORD dwTid)
  2672. {
  2673. LPDSOUNDEXTERNAL pdse = gpdsinfo->pDSoundExternalObj;
  2674. BOOL fReturnValue = FALSE;
  2675. HANDLE hFocusLock;
  2676. if (FALSE == GetFocusLock (&hFocusLock)) {
  2677. DPF(2, "Dsound: IsValidDSApp: Error getting Focus Lock.");
  2678. return FALSE;
  2679. }
  2680. while (NULL != pdse) {
  2681. if (dwTid == (pdse->tidSound)) {
  2682. ASSERT (0 != pdse->tidSound);
  2683. fReturnValue = TRUE;
  2684. break;
  2685. }
  2686. pdse = pdse->pNext;
  2687. }
  2688. if (FALSE == ReleaseFocusLock(hFocusLock)) {
  2689. DPF (2, "Dsound: IsValidDSApp: Could not release Focus Lock.");
  2690. ASSERT (0);
  2691. }
  2692. return fReturnValue;
  2693. }
  2694. /* cSoundObjects
  2695. * This function walks the external Direct Sound structures to count them.
  2696. *
  2697. * IN: none
  2698. * OUT: The number of external structures if 0 or 1, or 2 for 2 or more
  2699. * structures.
  2700. * SIDE EFFECTS: none
  2701. * NOTES: This function must be called in a Dll Critical Section
  2702. *
  2703. * REVISION HISTORY:
  2704. * 12/1/95 angusm Initial Version
  2705. * 12/10/95 angusm Code style cleanup
  2706. */
  2707. int cSoundObjects ()
  2708. {
  2709. LPDSOUNDEXTERNAL pdse;
  2710. int cNumObjects = 0;
  2711. pdse = gpdsinfo->pDSoundExternalObj;
  2712. while ((NULL != pdse) && (2 >= cNumObjects))
  2713. {
  2714. pdse = pdse->pNext;
  2715. cNumObjects++;
  2716. }
  2717. return cNumObjects;
  2718. }
  2719. /* CreateFocusThread
  2720. * This function creates the Focus Thread.
  2721. *
  2722. * IN: none
  2723. * OUT: TRUE if Thread was created, or FALSE otherwise
  2724. * SIDE EFFECTS: a Focus Thread is created, and hWakeFocusThread, and
  2725. * hFocusThread handles are created.
  2726. * NOTES: This function must be called in a Dll Critical Section
  2727. *
  2728. * REVISION HISTORY:
  2729. * 12/1/95 angusm Initial Version
  2730. * 12/10/95 angusm Code style cleanup
  2731. */
  2732. BOOL CreateFocusThread ()
  2733. {
  2734. HANDLE hFocusStartupEvent;
  2735. DWORD dwResult;
  2736. hFocusStartupEvent = CreateEvent (NULL, /* no security attribs */
  2737. FALSE, /* auto-reset */
  2738. FALSE, /* non signaled */
  2739. FOCUSSTARTUPEVENT);
  2740. if (NULL == hFocusStartupEvent) {
  2741. DPF (1, "Dsound: CreateFocusThread: Could not create "
  2742. "Focus Startup Event");
  2743. return FALSE;
  2744. }
  2745. gpdsinfo->hFocusTracker = HelperCreateDSFocusThread
  2746. ((LPTHREAD_START_ROUTINE) FocusTracker, /* thread function */
  2747. (LPVOID) POLL_INTERVAL, /* parameter */
  2748. 0, /* normal creation flags */
  2749. NULL); /* unwanted threadid */
  2750. if (NULL == gpdsinfo->hFocusTracker) {
  2751. DPF(1, "Could not start Focus Tracker thread in helper; exiting" );
  2752. if (FALSE == CloseHandle (hFocusStartupEvent)) ASSERT (0);
  2753. return FALSE;
  2754. }
  2755. dwResult = WaitForSingleObjectEx(hFocusStartupEvent, INFINITE, FALSE);
  2756. ASSERT(WAIT_OBJECT_0 == dwResult);
  2757. if (FALSE == CloseHandle (hFocusStartupEvent)) ASSERT (0);
  2758. return TRUE;
  2759. }
  2760. /* EndFocusThread
  2761. * This function will send an event to the Focus Thread running in DDHelp,
  2762. * and wait to see if it terminates. If it does not, the thread will be
  2763. * terminated.
  2764. *
  2765. * IN: none
  2766. * OUT: none
  2767. * SIDE EFFECTS: 1. Focus Thread will be killed.
  2768. * 2. hWakeFocusThread handle will be closed.
  2769. * 3. hFocusTracker hadnle will be closed.
  2770. * NOTES: This function must be called in a Dll Critical Section
  2771. *
  2772. * REVISION HISTORY:
  2773. * 11/30/95 angusm Initial Version
  2774. * 12/10/95 angusm Code style cleanup
  2775. */
  2776. void EndFocusThread ()
  2777. {
  2778. HANDLE hWaitEvent, hHelper, hOurFocusTracker;
  2779. DWORD dwResult;
  2780. hWaitEvent = CreateEvent (NULL,
  2781. FALSE, /* auto-reset */
  2782. TRUE, /* if event object does not
  2783. already exists, create one
  2784. signaled */
  2785. WAKEFOCUSTHREAD); /* event name */
  2786. if (NULL == hWaitEvent)
  2787. {
  2788. DPF (1, "Dsound: EndFocusThread: Could not create "
  2789. "wait event");
  2790. return;
  2791. }
  2792. hHelper = OpenProcess (PROCESS_DUP_HANDLE,
  2793. FALSE, /* no inheritance */
  2794. gpdsinfo->pidHelper); /* Helper PID */
  2795. if (NULL == hHelper)
  2796. {
  2797. DPF (1, "Dsound: EndFocusThread: Could not open process");
  2798. if (FALSE == CloseHandle (hWaitEvent)) ASSERT (0);
  2799. return;
  2800. }
  2801. if (FALSE ==
  2802. DuplicateHandle (hHelper, /* source process */
  2803. gpdsinfo->hFocusTracker, /* source handle */
  2804. GetCurrentProcess(), /* our process */
  2805. &hOurFocusTracker, /* our new handle */
  2806. SYNCHRONIZE | THREAD_TERMINATE, /* access flags */
  2807. FALSE, /* no inheritance */
  2808. 0)) /* no options */
  2809. { /* On Error ... */
  2810. DPF (1, "Dsound: EndFocusThread: Could not duplicate handle");
  2811. if (FALSE == CloseHandle (hHelper)) ASSERT (0);
  2812. if (FALSE == CloseHandle (hWaitEvent)) ASSERT (0);
  2813. return;
  2814. }
  2815. if (FALSE == SetEvent (hWaitEvent)) ASSERT (0);
  2816. if (FALSE == CloseHandle (hWaitEvent)) ASSERT (0);
  2817. dwResult = WaitForSingleObjectEx(hOurFocusTracker, INFINITE, FALSE);
  2818. ASSERT(WAIT_OBJECT_0 == dwResult);
  2819. if (FALSE == CloseHandle (hHelper)) ASSERT (0);
  2820. if (FALSE == CloseHandle (hOurFocusTracker)) ASSERT (0);
  2821. return;
  2822. }
  2823. /*
  2824. * DseUpdateActivationState
  2825. *
  2826. * Given the current tidSoundFocus and tidSticky, this function activates
  2827. * or deactivates all dsbe for a dse
  2828. */
  2829. __inline void DseUpdateActivationState(LPDSOUNDEXTERNAL pdse)
  2830. {
  2831. LPDSBUFFEREXTERNAL pdsbe;
  2832. WINDOWPLACEMENT wndplPlacement;
  2833. BOOL fIsMinimized;
  2834. wndplPlacement.length = sizeof(WINDOWPLACEMENT);
  2835. ASSERT (pdse->hwndCooperative);
  2836. if (NULL != gpdsinfo->hwndSoundFocus) {
  2837. GetWindowPlacement (gpdsinfo->hwndSoundFocus, &wndplPlacement);
  2838. fIsMinimized = (SW_SHOWMINIMIZED == wndplPlacement.showCmd);
  2839. }
  2840. else fIsMinimized = FALSE;
  2841. if ((gpdsinfo->tidSoundFocus == pdse->tidSound) && !fIsMinimized) {
  2842. if (gpdsinfo->tidStuckFocus != pdse->tidSound) {
  2843. DSDeactivateApp (gpdsinfo->tidStuckFocus, DSDEACTIVATEAPPF_ALL);
  2844. }
  2845. gpdsinfo->tidStuckFocus = gpdsinfo->tidSoundFocus;
  2846. }
  2847. for (pdsbe = pdse->pdsbe; pdsbe; pdsbe = pdsbe->pNext)
  2848. {
  2849. if ((gpdsinfo->tidSoundFocus != pdsbe->pdse->tidSound) &&
  2850. !((gpdsinfo->tidStuckFocus == pdsbe->pdse->tidSound) &&
  2851. (DSBCAPS_STICKYFOCUS & pdsbe->pdsb->fdwBufferDesc)))
  2852. {
  2853. DSBufferDeactivate (pdsbe);
  2854. }
  2855. else
  2856. {
  2857. DSBufferActivate (pdsbe);
  2858. }
  2859. }
  2860. return;
  2861. }
  2862. /* DsbeDeactivateIfNecessary
  2863. *
  2864. * This function deactivates a buffer only if the buffer is current in focus.
  2865. */
  2866. __inline void DsbeDeactivateIfNecessary (LPDSBUFFEREXTERNAL pdsbe)
  2867. {
  2868. DPF (2, "DsbeDeactivateIfNecessary: entered pdsbe = %x", pdsbe);
  2869. if ((gpdsinfo->tidSoundFocus != pdsbe->pdse->tidSound) &&
  2870. !((gpdsinfo->tidStuckFocus == pdsbe->pdse->tidSound) &&
  2871. (DSBCAPS_STICKYFOCUS & pdsbe->pdsb->fdwBufferDesc)))
  2872. {
  2873. DSBufferDeactivate (pdsbe);
  2874. }
  2875. return;
  2876. }
  2877. /* ActivateFocusWindow
  2878. *
  2879. * This function will set the gpdsinfo->hwndSticky handle properly. In addition
  2880. * it will Deactivate the current sticky hwnd and activate the the in focus
  2881. * hwnd.
  2882. *
  2883. * NOTE: This function must be called within a CSECT
  2884. */
  2885. __inline void ActivateFocusWindow (void) {
  2886. if (gpdsinfo->tidSoundFocus != gpdsinfo->tidStuckFocus) {
  2887. DSDeactivateApp (gpdsinfo->tidStuckFocus, DSDEACTIVATEAPPF_ALL);
  2888. gpdsinfo->tidStuckFocus = gpdsinfo->tidSoundFocus;
  2889. }
  2890. DSActivateApp (gpdsinfo->tidSoundFocus);
  2891. }