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

873 lines
20 KiB

  1. //--------------------------------------------------------------------------;
  2. //
  3. // File: kegrace.cpp
  4. //
  5. // Copyright (c) 1995 Microsoft Corporation. All Rights Reserved.
  6. //
  7. // Abstract:
  8. //
  9. // Contents:
  10. //
  11. // History:
  12. // 06/29/96 FrankYe Created
  13. //
  14. //--------------------------------------------------------------------------;
  15. #define NODSOUNDSERVICETABLE
  16. #include "dsoundi.h"
  17. // never premix less than this
  18. #define MIN_PREMIX 45
  19. #pragma VxD_LOCKED_CODE_SEG
  20. #pragma VxD_LOCKED_DATA_SEG
  21. extern "C" void KeGrace_GlobalTimeOutProcAsm();
  22. LONG lMixerMutex;
  23. LONG glNum;
  24. DWORDLONG gdwlTotalWasted;
  25. DWORDLONG gdwlTotal;
  26. DWORDLONG _inline GetPentiumCounter(void)
  27. {
  28. _asm _emit 0x0F
  29. _asm _emit 0x31
  30. }
  31. ULONG VXDINLINE VMM_Get_System_Time(void)
  32. {
  33. ULONG Time;
  34. Touch_Register(eax);
  35. VMMCall(Get_System_Time);
  36. _asm mov Time, eax;
  37. return Time;
  38. }
  39. VOID _VMCPD_Get_Thread_State(PTCB Thread, PVOID pCPState)
  40. {
  41. _asm mov esi, pCPState;
  42. _asm mov edi, Thread;
  43. VxDCall(VMCPD_Get_Thread_State);
  44. }
  45. VOID _VMCPD_Set_Thread_State(PTCB Thread, PVOID pCPState)
  46. {
  47. _asm mov esi, pCPState;
  48. _asm mov edi, Thread;
  49. VxDCall(VMCPD_Set_Thread_State);
  50. }
  51. LONG _InterlockedExchange(PLONG pTarget, LONG Value)
  52. {
  53. LONG OldTarget;
  54. _asm push edi;
  55. _asm mov eax, Value;
  56. _asm mov edi, pTarget;
  57. _asm xchg [edi], eax;
  58. _asm mov OldTarget, eax;
  59. _asm pop edi;
  60. return OldTarget;
  61. }
  62. // Must be in locked code
  63. LONG _InterlockedExchangeAdd(PLONG pAddend, LONG Increment)
  64. {
  65. LONG OldAddend;
  66. _asm mov esi, pAddend;
  67. _asm mov ecx, Increment;
  68. _asm mov eax, [esi]; // Read it (possibly causing a fault in)
  69. _asm add ecx, eax;
  70. _asm mov [esi], ecx;
  71. _asm mov OldAddend, eax;
  72. return OldAddend;
  73. }
  74. VOID _ZeroMemory(PVOID pDestination, DWORD cbLength)
  75. {
  76. _asm mov edi, pDestination ;
  77. _asm mov esi, cbLength ;
  78. _asm xor eax, eax ;
  79. _asm mov ecx, esi ;
  80. _asm shr ecx, 2 ;
  81. _asm rep stosd ;
  82. _asm mov ecx, esi ;
  83. _asm and ecx, 3 ;
  84. _asm rep stosb ;
  85. }
  86. // Override the global new and delete operators
  87. void * ::operator new(size_t size)
  88. {
  89. return MemAlloc(size);
  90. }
  91. void ::operator delete(void * pv)
  92. {
  93. MemFree(pv);
  94. }
  95. // Implement our own purecall
  96. int __cdecl _purecall(void)
  97. {
  98. ASSERT(FALSE);
  99. return 0;
  100. }
  101. typedef struct tEVENTPARAMS {
  102. HTIMEOUT hEvent;
  103. class CKeGrace *pThis;
  104. } EVENTPARAMS, *PEVENTPARAMS;
  105. class CKeGrace : public CGrace {
  106. public:
  107. HRESULT Initialize(CGrDest *pGrDest);
  108. void Terminate(void);
  109. void SignalRemix(void);
  110. int GetMaxRemix(void);
  111. void GlobalTimeOutProc(int dtimeTardiness);
  112. private:
  113. static const int MIXER_MINPREMIX;
  114. static const int MIXER_MAXPREMIX;
  115. LONG m_dtimePremix;
  116. LONG m_ddtimePremix;
  117. EVENTPARAMS m_EventParams;
  118. LONG m_timeBusyWaitForMutex;
  119. };
  120. const int CKeGrace::MIXER_MINPREMIX = 45;
  121. const int CKeGrace::MIXER_MAXPREMIX = 200;
  122. extern "C" void KeGrace_GlobalTimeOutProc(PVOID pKeGrace, int dtimeTardiness)
  123. {
  124. ((CKeGrace*)pKeGrace)->GlobalTimeOutProc(dtimeTardiness);
  125. }
  126. void CKeGrace::SignalRemix()
  127. {
  128. HTIMEOUT hEvent;
  129. #if 0
  130. // If you wanna run without remixing, just enable this bit of code. You
  131. // might want to lower the MIXER_MAXPREMIX constant as well.
  132. m_fdwMixerSignal &= DSMIXERSIGNAL_REMIX;
  133. return;
  134. #endif
  135. if (!(m_fdwMixerSignal & DSMIXERSIGNAL_REMIX))
  136. {
  137. m_fdwMixerSignal |= DSMIXERSIGNAL_REMIX;
  138. // Set a new time out for 2ms, and then cancel any prior pending timeout.
  139. //
  140. // Note that "2ms" is somewhat arbitrary. It just needs to be
  141. // enough time to hopefully let this thread release the mixer
  142. // mutex before the event executes.
  143. hEvent = Set_Global_Time_Out(KeGrace_GlobalTimeOutProcAsm, 2, (ULONG)&m_EventParams);
  144. hEvent = _InterlockedExchange((PLONG)&m_EventParams.hEvent, hEvent);
  145. Cancel_Time_Out(hEvent);
  146. }
  147. }
  148. void CKeGrace::GlobalTimeOutProc(int dtimeTardiness)
  149. {
  150. char CPState[108]; // Size of fp state per Intel prog. ref.
  151. LONG dtime;
  152. LONG dtimeSleep;
  153. LONG dtimeInvalid;
  154. LONG dtimeNextNotify;
  155. int cSamplesPremixMax;
  156. int cSamplesPremixed;
  157. // DPF(("CKeGrace::GlobalTimeOutProc"));
  158. if (m_dtimePremix/2 < dtimeTardiness) {
  159. DPF(("CKeGrace_GlobalTimeOutProc : warning: %dms late", dtimeTardiness));
  160. }
  161. //
  162. // We busy wait on the mutex, each iteration of the wait is longer
  163. // than the previous.
  164. //
  165. if (_InterlockedExchange(&lMixerMutex, TRUE)) {
  166. HTIMEOUT hEvent;
  167. LONG timeOut;
  168. // DPF(("CKeGrace::GlobalTimeOutProc : note: mutex already owned"));
  169. timeOut = _InterlockedExchangeAdd(&m_timeBusyWaitForMutex, 1);
  170. hEvent = Set_Global_Time_Out(KeGrace_GlobalTimeOutProcAsm, timeOut,
  171. (ULONG)&m_EventParams);
  172. hEvent = _InterlockedExchange((PLONG)&m_EventParams.hEvent, hEvent);
  173. Cancel_Time_Out(hEvent);
  174. return;
  175. }
  176. m_timeBusyWaitForMutex = 1;
  177. // Three cases:
  178. // 1) mixer is stopped
  179. // 2) mixer running and a remix is pending
  180. // 3) mixer running and no remix is pending
  181. //
  182. // Around each call to Refresh we need to save and restore the thread's
  183. // floating point state using the VMCPD Get/Set_Thread_State services.
  184. //
  185. if (MIXERSTATE_STOPPED == m_kMixerState) {
  186. dtimeSleep = 1000; // arbitrarily set for 1 second
  187. } else {
  188. // DWORDLONG dwlStartCycle;
  189. // DWORDLONG dwlT;
  190. // dwlStartCycle = dwlT = GetPentiumCounter();
  191. dtime = VMM_Get_System_Time();
  192. _ZeroMemory(&CPState, sizeof(CPState));
  193. _VMCPD_Get_Thread_State(Get_Cur_Thread_Handle(), &CPState);
  194. // gdwlTotalWasted += GetPentiumCounter() - dwlT;
  195. // glNum++;
  196. if (m_fdwMixerSignal & DSMIXERSIGNAL_REMIX) {
  197. m_dtimePremix = MIXER_MINPREMIX; // Initial premix length
  198. m_ddtimePremix = 2; // increment
  199. cSamplesPremixMax = MulDivRD(m_dtimePremix, m_pDest->m_nFrequency, 1000);
  200. Refresh(TRUE, cSamplesPremixMax, &cSamplesPremixed, &dtimeNextNotify);
  201. } else {
  202. m_dtimePremix += m_ddtimePremix;
  203. if (m_dtimePremix > MIXER_MAXPREMIX) {
  204. m_dtimePremix = MIXER_MAXPREMIX;
  205. } else {
  206. m_ddtimePremix += 2;
  207. }
  208. cSamplesPremixMax = MulDivRD(m_dtimePremix, m_pDest->m_nFrequency, 1000);
  209. Refresh(FALSE, cSamplesPremixMax, &cSamplesPremixed, &dtimeNextNotify);
  210. }
  211. // dwlT = GetPentiumCounter();
  212. _VMCPD_Set_Thread_State(Get_Cur_Thread_Handle(), &CPState);
  213. dtimeInvalid = MulDivRD(cSamplesPremixed, 1000, m_pDest->m_nFrequency);
  214. dtime = VMM_Get_System_Time() - dtime;
  215. dtimeInvalid -= 2 * dtime;
  216. dtimeSleep = min(dtimeNextNotify, dtimeInvalid/2);
  217. dtimeSleep = max(dtimeSleep, MIXER_MINPREMIX/2);
  218. // gdwlTotalWasted += GetPentiumCounter() - dwlT;
  219. // gdwlTotal += GetPentiumCounter() - dwlStartCycle;
  220. }
  221. // DPF(("CKeGrace::GlobalTimeOutProc : note: dtimeSleep=%dms", dtimeSleep));
  222. ASSERT(!m_EventParams.hEvent);
  223. m_EventParams.hEvent = Set_Global_Time_Out(KeGrace_GlobalTimeOutProcAsm, dtimeSleep, (ULONG)&m_EventParams);
  224. _InterlockedExchange(&lMixerMutex, FALSE);
  225. }
  226. HRESULT CKeGrace::Initialize(CGrDest *pDest)
  227. {
  228. HRESULT hr;
  229. hr = CGrace::Initialize(pDest);
  230. if (S_OK != hr) return hr;
  231. DPF(("CKeGrace::Initialize : note: Setting up first GlobalTimeOut"));
  232. // If we want to run the timer really fast, do this. So far I haven't seen
  233. // any empirical evidence of this helping.
  234. VTD_Begin_Min_Int_Period(5);
  235. m_dtimePremix = MIXER_MINPREMIX; // Initial premix length
  236. m_ddtimePremix = 2; // increment
  237. // REMIND do error check
  238. m_timeBusyWaitForMutex = 1;
  239. m_EventParams.pThis = this;
  240. m_EventParams.hEvent = Set_Global_Time_Out(KeGrace_GlobalTimeOutProcAsm, 1, (ULONG)&m_EventParams);
  241. gdwlTotal = 0;
  242. gdwlTotalWasted = 0;
  243. glNum = 0;
  244. return hr;
  245. }
  246. //--------------------------------------------------------------------------;
  247. //
  248. // Terminate
  249. //
  250. // This function is called to terminate the grace mixer thread for the
  251. // specified ds object. It returns the handle to the thread that is being
  252. // terminated. After releasing any critical sections that the grace mixer
  253. // thread may be waiting on, the caller should wait for the thread handle
  254. // to become signaled. For Win32 beginners: the thread handle is signalled
  255. // after the thread terminates.
  256. //
  257. //--------------------------------------------------------------------------;
  258. void CKeGrace::Terminate()
  259. {
  260. HTIMEOUT hEvent;
  261. hEvent = _InterlockedExchange((PLONG)&m_EventParams.hEvent, 0);
  262. Cancel_Time_Out(hEvent);
  263. CGrace::Terminate();
  264. if (0 != glNum) {
  265. DPF(("Wasted time = %d cycles", (int)(gdwlTotalWasted / glNum)));
  266. DPF(("Total time = %d cycles", (int)(gdwlTotal / glNum)));
  267. }
  268. }
  269. int CKeGrace::GetMaxRemix(void)
  270. {
  271. // return max number of samples we might remix
  272. return (MulDivRU(MIXER_MAXPREMIX, m_pDest->m_nFrequency, 1000));
  273. }
  274. #pragma VxD_PAGEABLE_CODE_SEG
  275. #pragma VxD_PAGEABLE_DATA_SEG
  276. class CKeGrDest : public CGrDest {
  277. public:
  278. CKeGrDest(LPNAGRDESTDATA);
  279. HRESULT Initialize(void);
  280. void Terminate(void);
  281. HRESULT SetFormat(LPWAVEFORMATEX pwfx);
  282. HRESULT AllocMixer(CMixer **ppMixer);
  283. void FreeMixer(void);
  284. HRESULT GetSamplePosition(int *pposPlay, int *pposWrite);
  285. HRESULT GetSamplePositionNoWin16(int *pposPlay, int *pposWrite);
  286. HRESULT Lock(PVOID *ppBuffer1, int *pcbBuffer1, PVOID *ppBuffer2, int *pcbBuffer2, int ibWrite, int cbWrite);
  287. HRESULT Unlock(PVOID pBuffer1, int cbBuffer1, PVOID pBuffer2, int cbBuffer2);
  288. void Play();
  289. void Stop();
  290. private:
  291. CKeGrace* m_pKeGrace;
  292. DWORD m_fdwDriverDesc;
  293. CBuf* m_pDrvBuf;
  294. // Let's only send a stop if we are currently playing
  295. BOOL m_fStopped;
  296. };
  297. CKeGrDest::CKeGrDest(LPNAGRDESTDATA pData)
  298. {
  299. m_cbBuffer = pData->cbBuffer;
  300. m_pBuffer = pData->pBuffer;
  301. m_pDrvBuf = ((CBuf*)((PIDSDRIVERBUFFER)pData->hBuffer));
  302. m_fdwDriverDesc = pData->fdwDriverDesc;
  303. m_fStopped = TRUE;
  304. }
  305. HRESULT CKeGrDest::Initialize(void)
  306. {
  307. m_cSamples = m_cbBuffer >> m_nBlockAlignShift;
  308. return DS_OK;
  309. }
  310. void CKeGrDest::Terminate(void)
  311. {
  312. return;
  313. }
  314. HRESULT CKeGrDest::AllocMixer(CMixer **ppMixer)
  315. {
  316. HRESULT hr;
  317. ASSERT(m_pBuffer);
  318. *ppMixer = NULL;
  319. m_pKeGrace = new CKeGrace;
  320. if (m_pKeGrace) {
  321. hr = m_pKeGrace->Initialize(this);
  322. if (S_OK != hr) {
  323. delete m_pKeGrace;
  324. m_pKeGrace = NULL;
  325. }
  326. } else {
  327. hr = DSERR_OUTOFMEMORY;
  328. }
  329. if (S_OK == hr) *ppMixer = m_pKeGrace;
  330. return hr;
  331. }
  332. void CKeGrDest::FreeMixer()
  333. {
  334. ASSERT(m_pKeGrace);
  335. m_pKeGrace->Terminate();
  336. delete m_pKeGrace;
  337. m_pKeGrace = NULL;
  338. }
  339. HRESULT CKeGrDest::SetFormat(LPWAVEFORMATEX pwfx)
  340. {
  341. HRESULT hr;
  342. SetFormatInfo(pwfx);
  343. hr = m_pDrvBuf->SetFormat(pwfx);
  344. return hr;
  345. }
  346. void CKeGrDest::Play()
  347. {
  348. HRESULT hr;
  349. // REMIND we're not propagating errors here!
  350. hr = m_pDrvBuf->Play(0, 0, DSBPLAY_LOOPING);
  351. if (SUCCEEDED(hr)) m_fStopped = FALSE;
  352. }
  353. void CKeGrDest::Stop()
  354. {
  355. HRESULT hr;
  356. if (m_fStopped == FALSE)
  357. {
  358. hr = m_pDrvBuf->Stop();
  359. if (SUCCEEDED(hr)) m_fStopped = TRUE;
  360. }
  361. }
  362. HRESULT CKeGrDest::Lock(PVOID *ppBuffer1, int *pcbBuffer1, PVOID *ppBuffer2, int *pcbBuffer2, int ibWrite, int cbWrite)
  363. {
  364. LOCKCIRCULARBUFFER lcb;
  365. HRESULT hr;
  366. lcb.pHwBuffer = m_pDrvBuf;
  367. lcb.pvBuffer = m_pBuffer;
  368. lcb.cbBuffer = m_cbBuffer;
  369. lcb.fPrimary = TRUE;
  370. lcb.fdwDriverDesc = m_fdwDriverDesc;
  371. lcb.ibRegion = ibWrite;
  372. lcb.cbRegion = cbWrite;
  373. hr = LockCircularBuffer(&lcb);
  374. if(SUCCEEDED(hr))
  375. {
  376. *ppBuffer1 = lcb.pvLock[0];
  377. *pcbBuffer1 = lcb.cbLock[0];
  378. if(ppBuffer2)
  379. {
  380. *ppBuffer2 = lcb.pvLock[1];
  381. }
  382. else
  383. {
  384. ASSERT(!lcb.pvLock[1]);
  385. }
  386. if(pcbBuffer2)
  387. {
  388. *pcbBuffer2 = lcb.cbLock[1];
  389. }
  390. else
  391. {
  392. ASSERT(!lcb.cbLock[1]);
  393. }
  394. }
  395. return hr;
  396. }
  397. HRESULT CKeGrDest::Unlock(PVOID pBuffer1, int cbBuffer1, PVOID pBuffer2, int cbBuffer2)
  398. {
  399. LOCKCIRCULARBUFFER lcb;
  400. lcb.pHwBuffer = m_pDrvBuf;
  401. lcb.pvBuffer = m_pBuffer;
  402. lcb.cbBuffer = m_cbBuffer;
  403. lcb.fPrimary = TRUE;
  404. lcb.fdwDriverDesc = m_fdwDriverDesc;
  405. lcb.pvLock[0] = pBuffer1;
  406. lcb.cbLock[0] = cbBuffer1;
  407. lcb.pvLock[1] = pBuffer2;
  408. lcb.cbLock[1] = cbBuffer2;
  409. return UnlockCircularBuffer(&lcb);
  410. }
  411. HRESULT CKeGrDest::GetSamplePosition(int *pposPlay, int *pposWrite)
  412. {
  413. HRESULT hr;
  414. DWORD dwPlay, dwWrite;
  415. ASSERT(pposPlay && pposWrite);
  416. hr = m_pDrvBuf->GetPosition(&dwPlay, &dwWrite);
  417. if (S_OK == hr) {
  418. *pposPlay = dwPlay >> m_nBlockAlignShift;
  419. *pposWrite = dwWrite >> m_nBlockAlignShift;
  420. // Until we write code to actually profile the performance, we'll just
  421. // pad the write position with a hard coded amount
  422. *pposWrite += m_nFrequency * HW_WRITE_CURSOR_MSEC_PAD / 1024;
  423. if (*pposWrite >= m_cSamples) *pposWrite -= m_cSamples;
  424. ASSERT(*pposWrite < m_cSamples);
  425. } else {
  426. *pposPlay = *pposWrite = 0;
  427. }
  428. return hr;
  429. }
  430. inline HRESULT CKeGrDest::GetSamplePositionNoWin16(int *pposPlay, int *pposWrite)
  431. {
  432. return GetSamplePosition(pposPlay, pposWrite);
  433. }
  434. int ioctlMixer_Run(PDIOCPARAMETERS pdiocp)
  435. {
  436. CMixer *pMixer;
  437. HRESULT hr;
  438. IOSTART(1*4);
  439. IOINPUT(pMixer, CMixer*);
  440. hr = pMixer->Run();
  441. IOOUTPUT(hr, HRESULT);
  442. IORETURN;
  443. return 0;
  444. }
  445. int ioctlMixer_Stop(PDIOCPARAMETERS pdiocp)
  446. {
  447. BOOL f;
  448. CMixer *pMixer;
  449. IOSTART(1*4);
  450. IOINPUT(pMixer, CMixer*);
  451. f = pMixer->Stop();
  452. IOOUTPUT(f, BOOL);
  453. IORETURN;
  454. return 0;
  455. }
  456. int ioctlMixer_PlayWhenIdle(PDIOCPARAMETERS pdiocp)
  457. {
  458. CMixer *pMixer;
  459. IOSTART(1*4);
  460. IOINPUT(pMixer, CMixer*);
  461. pMixer->PlayWhenIdle();
  462. IORETURN;
  463. return 0;
  464. }
  465. int ioctlMixer_StopWhenIdle(PDIOCPARAMETERS pdiocp)
  466. {
  467. CMixer *pMixer;
  468. IOSTART(1*4);
  469. IOINPUT(pMixer, CMixer*);
  470. pMixer->StopWhenIdle();
  471. IORETURN;
  472. return 0;
  473. }
  474. int ioctlMixer_MixListAdd(PDIOCPARAMETERS pdiocp)
  475. {
  476. CMixer *pMixer;
  477. CMixSource *pSource;
  478. IOSTART(2*4);
  479. IOINPUT(pMixer, CMixer*);
  480. IOINPUT(pSource, CMixSource*);
  481. pMixer->MixListAdd(pSource);
  482. IORETURN;
  483. return 0;
  484. }
  485. int ioctlMixer_MixListRemove(PDIOCPARAMETERS pdiocp)
  486. {
  487. CMixer *pMixer;
  488. CMixSource *pSource;
  489. IOSTART(2*4);
  490. IOINPUT(pMixer, CMixer*);
  491. IOINPUT(pSource, CMixSource*);
  492. pMixer->MixListRemove(pSource);
  493. IORETURN;
  494. return 0;
  495. }
  496. int ioctlMixer_FilterOn(PDIOCPARAMETERS pdiocp)
  497. {
  498. CMixer *pMixer;
  499. CMixSource *pSource;
  500. IOSTART(2*4);
  501. IOINPUT(pMixer, CMixer*);
  502. IOINPUT(pSource, CMixSource*);
  503. pMixer->FilterOn(pSource);
  504. IORETURN;
  505. return 0;
  506. }
  507. int ioctlMixer_FilterOff(PDIOCPARAMETERS pdiocp)
  508. {
  509. CMixer *pMixer;
  510. CMixSource *pSource;
  511. IOSTART(2*4);
  512. IOINPUT(pMixer, CMixer*);
  513. IOINPUT(pSource, CMixSource*);
  514. pMixer->FilterOff(pSource);
  515. IORETURN;
  516. return 0;
  517. }
  518. int ioctlMixer_GetBytePosition(PDIOCPARAMETERS pdiocp)
  519. {
  520. CMixer *pMixer;
  521. CMixSource *pSource;
  522. int *pibPlay;
  523. int *pibWrite;
  524. IOSTART(4*4);
  525. IOINPUT(pMixer, CMixer*);
  526. IOINPUT(pSource, CMixSource*);
  527. IOINPUT(pibPlay, int*);
  528. IOINPUT(pibWrite, int*);
  529. pMixer->GetBytePosition(pSource, pibPlay, pibWrite);
  530. IORETURN;
  531. return 0;
  532. }
  533. int ioctlMixer_SignalRemix(PDIOCPARAMETERS pdiocp)
  534. {
  535. CMixer *pMixer;
  536. IOSTART(1*4);
  537. IOINPUT(pMixer, CMixer*);
  538. pMixer->SignalRemix();
  539. IORETURN;
  540. return 0;
  541. }
  542. int ioctlKeDest_New(PDIOCPARAMETERS pdiocp)
  543. {
  544. LPNAGRDESTDATA pData;
  545. CKeGrDest *pKeGrDest;
  546. IOSTART(1*4);
  547. IOINPUT(pData, LPNAGRDESTDATA);
  548. pKeGrDest = new CKeGrDest(pData);
  549. IOOUTPUT(pKeGrDest, CKeGrDest*);
  550. IORETURN;
  551. return 0;
  552. }
  553. int ioctlMixDest_Delete(PDIOCPARAMETERS pdiocp)
  554. {
  555. CMixDest *pMixDest;
  556. IOSTART(1*4);
  557. IOINPUT(pMixDest, CMixDest*);
  558. delete pMixDest;
  559. IORETURN;
  560. return 0;
  561. }
  562. int ioctlMixDest_Initialize(PDIOCPARAMETERS pdiocp)
  563. {
  564. CMixDest *pMixDest;
  565. HRESULT hr;
  566. IOSTART(1*4);
  567. IOINPUT(pMixDest, CMixDest*);
  568. hr = pMixDest->Initialize();
  569. IOOUTPUT(hr, HRESULT);
  570. IORETURN;
  571. return 0;
  572. }
  573. int ioctlMixDest_Terminate(PDIOCPARAMETERS pdiocp)
  574. {
  575. CMixDest *pMixDest;
  576. IOSTART(1*4);
  577. IOINPUT(pMixDest, CMixDest*);
  578. pMixDest->Terminate();
  579. IORETURN;
  580. return 0;
  581. }
  582. int ioctlMixDest_SetFormat(PDIOCPARAMETERS pdiocp)
  583. {
  584. CMixDest *pMixDest;
  585. LPWAVEFORMATEX pwfx;
  586. HRESULT hr;
  587. IOSTART(2*4);
  588. IOINPUT(pMixDest, CMixDest*);
  589. IOINPUT(pwfx, LPWAVEFORMATEX);
  590. hr = pMixDest->SetFormat(pwfx);
  591. IOOUTPUT(hr, HRESULT);
  592. IORETURN;
  593. return 0;
  594. }
  595. int ioctlMixDest_SetFormatInfo(PDIOCPARAMETERS pdiocp)
  596. {
  597. CMixDest *pMixDest;
  598. LPWAVEFORMATEX pwfx;
  599. IOSTART(2*4);
  600. IOINPUT(pMixDest, CMixDest*);
  601. IOINPUT(pwfx, LPWAVEFORMATEX);
  602. pMixDest->SetFormatInfo(pwfx);
  603. IORETURN;
  604. return 0;
  605. }
  606. int ioctlMixDest_AllocMixer(PDIOCPARAMETERS pdiocp)
  607. {
  608. CMixDest *pMixDest;
  609. CMixer **ppMixer;
  610. HRESULT hr;
  611. IOSTART(2*4);
  612. IOINPUT(pMixDest, CMixDest*);
  613. IOINPUT(ppMixer, CMixer**);
  614. hr = pMixDest->AllocMixer(ppMixer);
  615. IOOUTPUT(hr, HRESULT);
  616. IORETURN;
  617. return 0;
  618. }
  619. int ioctlMixDest_FreeMixer(PDIOCPARAMETERS pdiocp)
  620. {
  621. CMixDest *pMixDest;
  622. IOSTART(1*4);
  623. IOINPUT(pMixDest, CMixDest*);
  624. pMixDest->FreeMixer();
  625. IORETURN;
  626. return 0;
  627. }
  628. int ioctlMixDest_Play(PDIOCPARAMETERS pdiocp)
  629. {
  630. CMixDest *pMixDest;
  631. IOSTART(1*4);
  632. IOINPUT(pMixDest, CMixDest*);
  633. pMixDest->Play();
  634. IORETURN;
  635. return 0;
  636. }
  637. int ioctlMixDest_Stop(PDIOCPARAMETERS pdiocp)
  638. {
  639. CMixDest *pMixDest;
  640. IOSTART(1*4);
  641. IOINPUT(pMixDest, CMixDest*);
  642. pMixDest->Stop();
  643. IORETURN;
  644. return 0;
  645. }
  646. int ioctlMixDest_GetFrequency(PDIOCPARAMETERS pdiocp)
  647. {
  648. CMixDest *pMixDest;
  649. int nFrequency;
  650. IOSTART(1*4);
  651. IOINPUT(pMixDest, CMixDest*);
  652. nFrequency = pMixDest->GetFrequency();
  653. IOOUTPUT(nFrequency, int);
  654. IORETURN;
  655. return 0;
  656. }
  657. int ioctlDsvxd_GetMixerMutexPtr(PDIOCPARAMETERS pdiocp)
  658. {
  659. IOSTART(0*4);
  660. IOOUTPUT(&lMixerMutex, PLONG);
  661. IORETURN;
  662. return 0;
  663. }