Source code of Windows XP (NT5)
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.

1041 lines
26 KiB

  1. #include "priv.h"
  2. #include "sccls.h"
  3. #include <mmsystem.h>
  4. #include <amstream.h>
  5. #include "power.h"
  6. #include "dsound.h"
  7. #include "Zaxxon.h"
  8. #ifndef SAFERELEASE
  9. #define SAFERELEASE(x) if (x) { x->Release(); x = NULL; }
  10. #endif
  11. #define AUDIO_MAXBUFFER 64000
  12. // Which is better?
  13. // 2Megs causes 25% cpu usage every 5 seconds
  14. // 1meg causes 15% cpu usage every 2 seconds
  15. // 100k causes a contant 6% cpu usage
  16. // 64k?
  17. #define EVENT_NONE 0x0
  18. #define EVENT_PLAY 0x1
  19. #define EVENT_STOP 0x2
  20. #define EVENT_PAUSE 0x3
  21. #define EVENT_FORWARD 0x4
  22. #define EVENT_BACKWARD 0x5
  23. #define EVENT_TERMINATE 0x6
  24. #define EVENT_ADDSONG 0x7
  25. #define EVENT_REMOVESONG 0x8
  26. #define EVENT_NEXTSONG 0x9
  27. #define EVENT_PREVSONG 0xA
  28. #define EVENT_REGISTER 0xB
  29. #define EVENT_DEREGISTER 0xC
  30. #define EVENT_CLEARPLAYLIST 0xD
  31. #define EVENT_SETSONG 0xE
  32. struct ZAXXONEVENT
  33. {
  34. ZAXXONEVENT():_dwEvent(EVENT_NONE), _pNext(NULL) { }
  35. DWORD _dwEvent;
  36. ZAXXONEVENT* _pNext;
  37. union
  38. {
  39. TCHAR szPath[MAX_PATH];
  40. UINT szSeconds;
  41. UINT iIndex;
  42. HWND hwnd;
  43. };
  44. };
  45. typedef struct
  46. {
  47. HANDLE hThread;
  48. CRITICAL_SECTION crit;
  49. HANDLE hEvents;
  50. ZAXXONEVENT* pEvents;
  51. } ZAXXON_ARG;
  52. class CNotifyList
  53. {
  54. HDSA _hdsa;
  55. public:
  56. CNotifyList()
  57. {
  58. _hdsa = DSA_Create(sizeof(HWND), 1);
  59. }
  60. ~CNotifyList()
  61. {
  62. if (_hdsa)
  63. DSA_Destroy(_hdsa);
  64. }
  65. void AddNotify(HWND hwnd)
  66. {
  67. if (_hdsa)
  68. DSA_AppendItem(_hdsa, &hwnd);
  69. }
  70. void RemoveNotify(HWND hwnd)
  71. {
  72. //
  73. }
  74. void SendNotify(UINT uMsg, WPARAM wParam, LPARAM lParam)
  75. {
  76. for (int i = 0; i < DSA_GetItemCount(_hdsa); i++)
  77. {
  78. DWORD_PTR l;
  79. HWND hwnd = *(HWND*)DSA_GetItemPtr(_hdsa, i);
  80. SendMessageTimeout(hwnd, uMsg, wParam, lParam, SMTO_ABORTIFHUNG, 100, &l);
  81. }
  82. }
  83. };
  84. class CPlayList
  85. {
  86. int iIndex;
  87. HDPA _hdpa;
  88. static BOOL CALLBACK s_DestroyPlaylist(void* pv, void* pvData)
  89. {
  90. PWSTR psz = (PWSTR)pv;
  91. if (psz)
  92. {
  93. Str_SetPtr(&psz, NULL);
  94. }
  95. return TRUE;
  96. }
  97. public:
  98. int GetIndex() { return iIndex;}
  99. CPlayList()
  100. {
  101. _hdpa = NULL;
  102. iIndex = -1;
  103. }
  104. ~CPlayList()
  105. {
  106. Empty();
  107. }
  108. BOOL AddSong(PWSTR psz)
  109. {
  110. if (!_hdpa)
  111. {
  112. _hdpa = DPA_Create(4);
  113. }
  114. if (!_hdpa)
  115. return FALSE;
  116. TCHAR* pszSet = NULL;
  117. Str_SetPtr(&pszSet, psz);
  118. return DPA_AppendPtr(_hdpa, pszSet) != -1;
  119. }
  120. BOOL RemoveSong(int i)
  121. {
  122. if (!_hdpa)
  123. return FALSE;
  124. if (i < iIndex)
  125. iIndex--;
  126. TCHAR* pszSet = (TCHAR*)DPA_DeletePtr(_hdpa, i);
  127. Str_SetPtr(&pszSet, NULL);
  128. return FALSE;
  129. }
  130. BOOL GetSong(int i, PWSTR psz, int cch)
  131. {
  132. if (!_hdpa)
  133. return FALSE;
  134. PWSTR pszSong = (PWSTR)DPA_FastGetPtr(_hdpa, i);
  135. if (pszSong)
  136. {
  137. iIndex = i;
  138. StrCpyN(psz, pszSong, cch);
  139. return TRUE;
  140. }
  141. return FALSE;
  142. }
  143. BOOL GetNextSong(PWSTR psz, int cch)
  144. {
  145. if (!_hdpa)
  146. return FALSE;
  147. if (iIndex >= DPA_GetPtrCount(_hdpa) - 1)
  148. iIndex = -1;
  149. return GetSong(++iIndex, psz, cch);
  150. }
  151. BOOL GetPrevSong(PWSTR psz, int cch)
  152. {
  153. if (!_hdpa)
  154. return FALSE;
  155. if (iIndex <= 0)
  156. iIndex = DPA_GetPtrCount(_hdpa);
  157. return GetSong(--iIndex, psz, cch);
  158. }
  159. BOOL Empty()
  160. {
  161. if (_hdpa)
  162. {
  163. DPA_DestroyCallback(_hdpa, s_DestroyPlaylist, NULL);
  164. }
  165. _hdpa = NULL;
  166. return TRUE;
  167. }
  168. };
  169. HRESULT CreateBuffer(IDirectSound* pds, WAVEFORMATEX* pwfx, DWORD dwBufferSize, IDirectSoundBuffer** ppdsb)
  170. {
  171. HRESULT hr = S_OK;
  172. IDirectSoundBuffer* psbPrimary;
  173. // Get the primary buffer
  174. DSBUFFERDESC dsbdesc;
  175. ZeroMemory(&dsbdesc, sizeof(DSBUFFERDESC));
  176. dsbdesc.dwSize = sizeof(DSBUFFERDESC);
  177. dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
  178. hr = pds->CreateSoundBuffer(&dsbdesc, &psbPrimary, NULL);
  179. if (SUCCEEDED(hr))
  180. {
  181. hr = psbPrimary->SetFormat(pwfx);
  182. if (SUCCEEDED(hr))
  183. {
  184. dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 |
  185. DSBCAPS_GLOBALFOCUS |
  186. DSBCAPS_CTRLPOSITIONNOTIFY;
  187. dsbdesc.dwBufferBytes = dwBufferSize;
  188. dsbdesc.lpwfxFormat = pwfx;
  189. hr = pds->CreateSoundBuffer(&dsbdesc, ppdsb, NULL);
  190. }
  191. psbPrimary->Release();
  192. }
  193. return hr;
  194. }
  195. HRESULT CreateDirectSound(IDirectSound** ppds)
  196. {
  197. IDirectSound* pds = NULL;
  198. HRESULT hr = CoCreateInstance(CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER,
  199. IID_IDirectSound, (void**)&pds);
  200. if (SUCCEEDED(hr))
  201. {
  202. hr = pds->Initialize(NULL); // Don't support more than one at the moment.
  203. if (SUCCEEDED(hr))
  204. {
  205. hr = pds->SetCooperativeLevel(GetDesktopWindow(), DSSCL_PRIORITY);
  206. }
  207. }
  208. if (SUCCEEDED(hr))
  209. {
  210. *ppds = pds;
  211. pds->AddRef();
  212. }
  213. SAFERELEASE(pds);
  214. return hr;
  215. }
  216. class CZaxxonPlayingSample
  217. {
  218. public:
  219. CZaxxonPlayingSample();
  220. ~CZaxxonPlayingSample();
  221. HRESULT Open(PWSTR psz);
  222. HRESULT SetBuffer(PBYTE pBuf, DWORD dwSize);
  223. HRESULT CopySampleData(PBYTE pBuffer1, DWORD dwBytesForBuffer1,
  224. PBYTE pBuffer2, DWORD dwBytesForBuffer2,
  225. DWORD* pdwBytesLeft1, DWORD* pdwBytesLeft2);
  226. HRESULT GetSampleFormat(WAVEFORMATEX* pwfx);
  227. private:
  228. void CloseOut();
  229. HRESULT _SetupMediaStream();
  230. TCHAR _szPath[MAX_PATH];
  231. IAMMultiMediaStream *_pMMStream;
  232. IMediaStream *_pStream;
  233. IAudioStreamSample *_pSample;
  234. IAudioMediaStream *_pAudioStream;
  235. IAudioData *_pAudioData;
  236. WAVEFORMATEX _wfx;
  237. HANDLE _hRenderEvent;
  238. PBYTE _pBuffer;
  239. };
  240. CZaxxonPlayingSample::CZaxxonPlayingSample():
  241. _pMMStream(NULL),
  242. _pStream(NULL),
  243. _pSample(NULL),
  244. _pAudioStream(NULL),
  245. _pAudioData(NULL),
  246. _hRenderEvent(NULL),
  247. _pBuffer(NULL)
  248. {
  249. ZeroMemory(&_wfx, sizeof(WAVEFORMATEX));
  250. }
  251. CZaxxonPlayingSample::~CZaxxonPlayingSample()
  252. {
  253. CloseOut();
  254. }
  255. void CZaxxonPlayingSample::CloseOut()
  256. {
  257. ATOMICRELEASE(_pMMStream);
  258. ATOMICRELEASE(_pAudioData);
  259. ATOMICRELEASE(_pSample);
  260. ATOMICRELEASE(_pStream);
  261. ATOMICRELEASE(_pAudioStream);
  262. if (_hRenderEvent)
  263. {
  264. CloseHandle(_hRenderEvent);
  265. _hRenderEvent = NULL;
  266. }
  267. }
  268. HRESULT CZaxxonPlayingSample::Open(PWSTR psz)
  269. {
  270. CloseOut();
  271. lstrcpy(_szPath, psz);
  272. return _SetupMediaStream();
  273. }
  274. HRESULT CZaxxonPlayingSample::SetBuffer(PBYTE pBuf, DWORD dwSize)
  275. {
  276. if (_pAudioData && _pAudioStream)
  277. {
  278. _pAudioData->SetBuffer(dwSize, pBuf, 0);
  279. _pAudioData->SetFormat(&_wfx);
  280. _pBuffer = pBuf;
  281. return _pAudioStream->CreateSample(_pAudioData, 0, &_pSample);
  282. }
  283. return E_FAIL;
  284. }
  285. HRESULT CZaxxonPlayingSample::GetSampleFormat(WAVEFORMATEX* pwfx)
  286. {
  287. CopyMemory(pwfx, &_wfx, sizeof(_wfx));
  288. return S_OK;
  289. }
  290. HRESULT CZaxxonPlayingSample::CopySampleData(PBYTE pBuffer1, DWORD dwBytesForBuffer1,
  291. PBYTE pBuffer2, DWORD dwBytesForBuffer2,
  292. DWORD* pdwBytesLeft1, DWORD* pdwBytesLeft2)
  293. {
  294. if (!_pSample)
  295. return E_FAIL;
  296. HRESULT hr = _pSample->Update(0, _hRenderEvent, NULL, 0);
  297. if (FAILED(hr) || MS_S_ENDOFSTREAM == hr)
  298. {
  299. return hr;
  300. }
  301. DWORD dwLength;
  302. WaitForSingleObject(_hRenderEvent, INFINITE);
  303. _pAudioData->GetInfo(NULL, NULL, &dwLength);
  304. *pdwBytesLeft1 = 0;
  305. *pdwBytesLeft2 = 0;
  306. // _pBuffer contains the audio data. Copy.
  307. if (dwLength < dwBytesForBuffer1)
  308. {
  309. *pdwBytesLeft2 = dwBytesForBuffer2;
  310. *pdwBytesLeft1 = dwBytesForBuffer1 - dwLength;
  311. dwBytesForBuffer1 = dwLength;
  312. dwBytesForBuffer2 = 0;
  313. }
  314. CopyMemory(pBuffer1, _pBuffer, dwBytesForBuffer1);
  315. dwLength -= dwBytesForBuffer1;
  316. if (dwBytesForBuffer2 > 0 && dwLength > 0)
  317. {
  318. CopyMemory(pBuffer2, _pBuffer + dwBytesForBuffer1, dwLength);
  319. if (dwLength < dwBytesForBuffer2)
  320. *pdwBytesLeft2 = dwBytesForBuffer2 - dwLength;
  321. }
  322. return hr;
  323. }
  324. HRESULT CZaxxonPlayingSample::_SetupMediaStream()
  325. {
  326. HRESULT hr = E_INVALIDARG;
  327. if (_szPath[0] != 0)
  328. {
  329. hr = CoCreateInstance(CLSID_AMMultiMediaStream, NULL, CLSCTX_INPROC_SERVER,
  330. IID_IAMMultiMediaStream, (void **)&_pMMStream);
  331. if (SUCCEEDED(hr))
  332. {
  333. _pMMStream->Initialize(STREAMTYPE_READ, AMMSF_NOGRAPHTHREAD, NULL);
  334. _pMMStream->AddMediaStream(NULL, &MSPID_PrimaryAudio, 0, NULL);
  335. hr = _pMMStream->OpenFile(_szPath, AMMSF_RUN);
  336. if (SUCCEEDED(hr))
  337. {
  338. hr = CoCreateInstance(CLSID_AMAudioData, NULL, CLSCTX_INPROC_SERVER,
  339. IID_IAudioData, (void **)&_pAudioData);
  340. if (SUCCEEDED(hr))
  341. {
  342. hr = _pMMStream->GetMediaStream(MSPID_PrimaryAudio, &_pStream);
  343. if (SUCCEEDED(hr))
  344. {
  345. hr = _pStream->QueryInterface(IID_IAudioMediaStream, (void **)&_pAudioStream);
  346. if (SUCCEEDED(hr))
  347. {
  348. _pAudioStream->GetFormat(&_wfx);
  349. _hRenderEvent = CreateEvent(NULL, NULL, TRUE, NULL);
  350. hr = S_OK;
  351. }
  352. }
  353. }
  354. }
  355. }
  356. }
  357. return hr;
  358. }
  359. ZAXXONEVENT* GetZaxxonEvent(ZAXXON_ARG* pza)
  360. {
  361. ZAXXONEVENT* pz = NULL;
  362. if (pza->pEvents)
  363. {
  364. EnterCriticalSection(&pza->crit);
  365. if (pza->pEvents)
  366. {
  367. pz = pza->pEvents;
  368. pza->pEvents = pza->pEvents->_pNext;
  369. }
  370. LeaveCriticalSection(&pza->crit);
  371. }
  372. return pz;
  373. }
  374. HRESULT CopySample(CZaxxonPlayingSample* pzax, IDirectSoundBuffer* pdsb, DWORD dwStart, DWORD dwNumBytes)
  375. {
  376. HRESULT hr;
  377. PBYTE pBuffer1;
  378. PBYTE pBuffer2;
  379. DWORD dwBytesToCopyToBuffer1;
  380. DWORD dwBytesToCopyToBuffer2;
  381. DWORD dwBytesLeft1;
  382. DWORD dwBytesLeft2;
  383. if (!pdsb)
  384. return E_ACCESSDENIED;
  385. hr = pdsb->Lock(dwStart, dwNumBytes, (void**)&pBuffer1, &dwBytesToCopyToBuffer1,
  386. (void**)&pBuffer2, &dwBytesToCopyToBuffer2, 0);
  387. if (SUCCEEDED(hr))
  388. {
  389. hr = pzax->CopySampleData(
  390. pBuffer1, dwBytesToCopyToBuffer1,
  391. pBuffer2, dwBytesToCopyToBuffer2,
  392. &dwBytesLeft1,
  393. &dwBytesLeft2);
  394. if (FAILED(hr) || MS_S_ENDOFSTREAM == hr)
  395. {
  396. pdsb->Stop();
  397. }
  398. else
  399. {
  400. if (dwBytesLeft1 > 0)
  401. {
  402. ZeroMemory(pBuffer1 + dwBytesToCopyToBuffer1 - dwBytesLeft1,
  403. dwBytesLeft1);
  404. }
  405. if (dwBytesLeft2 > 0)
  406. {
  407. ZeroMemory(pBuffer2 + dwBytesToCopyToBuffer2 - dwBytesLeft2,
  408. dwBytesLeft2);
  409. }
  410. }
  411. pdsb->Unlock(pBuffer1, dwBytesToCopyToBuffer1,
  412. pBuffer2, dwBytesToCopyToBuffer2);
  413. }
  414. return hr;
  415. }
  416. BOOL SetupSample(CZaxxonPlayingSample* pzaxSample, PWSTR psz, PBYTE pBuffer, DSBPOSITIONNOTIFY* rgdsbp, int cdsbpn, IDirectSound* pds, IDirectSoundBuffer** ppdsb)
  417. {
  418. if (SUCCEEDED(pzaxSample->Open(psz)))
  419. {
  420. WAVEFORMATEX wfx;
  421. pzaxSample->SetBuffer(pBuffer, AUDIO_MAXBUFFER / 2);
  422. pzaxSample->GetSampleFormat(&wfx);
  423. if (SUCCEEDED(CreateBuffer(pds, &wfx, AUDIO_MAXBUFFER, ppdsb)))
  424. {
  425. IDirectSoundNotify* pdsn;
  426. if (SUCCEEDED((*ppdsb)->QueryInterface(IID_IDirectSoundNotify, (void**)&pdsn)))
  427. {
  428. for (int i = 0; i < cdsbpn; i++)
  429. {
  430. ResetEvent(rgdsbp[i].hEventNotify);
  431. }
  432. pdsn->SetNotificationPositions(cdsbpn, rgdsbp);
  433. pdsn->Release();
  434. }
  435. if (SUCCEEDED(CopySample(pzaxSample, *ppdsb, 0, AUDIO_MAXBUFFER / 2)))
  436. {
  437. (*ppdsb)->SetCurrentPosition(0);
  438. (*ppdsb)->Play(0, 0, DSBPLAY_LOOPING);
  439. return TRUE;
  440. }
  441. else
  442. {
  443. (*ppdsb)->Release();
  444. *ppdsb = NULL;
  445. }
  446. }
  447. }
  448. return FALSE;
  449. }
  450. ULONG CALLBACK AudioRenderThread(LPVOID pvArg)
  451. {
  452. CPlayList playlist;
  453. CNotifyList notifylist;
  454. ZAXXON_ARG* pza = (ZAXXON_ARG*)pvArg;
  455. HRESULT hr = CoInitialize(NULL);
  456. PBYTE pBuffer = (PBYTE)LocalAlloc(LMEM_FIXED, AUDIO_MAXBUFFER);
  457. if (SUCCEEDED(hr) && pBuffer)
  458. {
  459. IDirectSound* pds = NULL;
  460. IDirectSoundBuffer* pdsb = NULL;
  461. HANDLE rgEvent[] =
  462. {
  463. CreateEvent(NULL, FALSE, FALSE, NULL),
  464. CreateEvent(NULL, FALSE, FALSE, NULL),
  465. pza->hEvents,
  466. };
  467. DSBPOSITIONNOTIFY rgdsbp[] =
  468. {
  469. {0, rgEvent[0]},
  470. {AUDIO_MAXBUFFER / 2, rgEvent[1]},
  471. };
  472. if (SUCCEEDED(CreateDirectSound(&pds)))
  473. {
  474. CZaxxonPlayingSample zaxSample;
  475. BOOL fPaused = FALSE;
  476. BOOL fDone = FALSE;
  477. while (!fDone)
  478. {
  479. DWORD dwEvent = WaitForMultipleObjects(ARRAYSIZE(rgEvent), rgEvent, FALSE, INFINITE);
  480. dwEvent -= WAIT_OBJECT_0;
  481. if (dwEvent < 2)
  482. {
  483. DWORD dwStartByte;
  484. if (dwEvent + 1 >= ARRAYSIZE(rgdsbp))
  485. dwStartByte = rgdsbp[0].dwOffset;
  486. else
  487. dwStartByte = rgdsbp[dwEvent + 1].dwOffset;
  488. hr = CopySample(&zaxSample, pdsb, dwStartByte, AUDIO_MAXBUFFER / 2);
  489. if (FAILED(hr) || MS_S_ENDOFSTREAM == hr)
  490. {
  491. TCHAR pszPath[MAX_PATH];
  492. if (playlist.GetNextSong(pszPath, MAX_PATH))
  493. {
  494. ATOMICRELEASE(pdsb);
  495. notifylist.SendNotify(WM_SONGCHANGE, (WPARAM)pszPath, 0);
  496. SetupSample(&zaxSample, pszPath, pBuffer, rgdsbp, ARRAYSIZE(rgdsbp), pds, &pdsb);
  497. }
  498. }
  499. }
  500. else
  501. {
  502. ZAXXONEVENT* pZaxxonEvent;
  503. while ((pZaxxonEvent = GetZaxxonEvent(pza)))
  504. {
  505. switch (pZaxxonEvent->_dwEvent)
  506. {
  507. case EVENT_STOP:
  508. if (pdsb)
  509. pdsb->Stop();
  510. notifylist.SendNotify(WM_SONGSTOP, 0, 0);
  511. fPaused = FALSE;
  512. break;
  513. case EVENT_ADDSONG:
  514. playlist.AddSong(pZaxxonEvent->szPath);
  515. break;
  516. case EVENT_REMOVESONG:
  517. if (pZaxxonEvent->iIndex == playlist.GetIndex())
  518. {
  519. fPaused = FALSE;
  520. TCHAR pszPath[MAX_PATH];
  521. if (playlist.GetNextSong(pszPath, MAX_PATH))
  522. {
  523. if (pdsb)
  524. pdsb->Stop();
  525. ATOMICRELEASE(pdsb);
  526. notifylist.SendNotify(WM_SONGCHANGE, (WPARAM)pszPath, 0);
  527. SetupSample(&zaxSample, pszPath, pBuffer, rgdsbp, ARRAYSIZE(rgdsbp), pds, &pdsb);
  528. }
  529. }
  530. playlist.RemoveSong(pZaxxonEvent->iIndex);
  531. break;
  532. case EVENT_CLEARPLAYLIST:
  533. if (pdsb)
  534. pdsb->Stop();
  535. fPaused = FALSE;
  536. notifylist.SendNotify(WM_SONGSTOP, 0, 0);
  537. playlist.Empty();
  538. break;
  539. case EVENT_REGISTER:
  540. notifylist.AddNotify(pZaxxonEvent->hwnd);
  541. break;
  542. case EVENT_DEREGISTER:
  543. notifylist.RemoveNotify(pZaxxonEvent->hwnd);
  544. break;
  545. case EVENT_PLAY:
  546. if (fPaused)
  547. {
  548. if (pdsb)
  549. pdsb->Play(0, 0, DSBPLAY_LOOPING);
  550. fPaused = FALSE;
  551. }
  552. else
  553. {
  554. fPaused = FALSE;
  555. TCHAR pszPath[MAX_PATH];
  556. if (playlist.GetNextSong(pszPath, MAX_PATH))
  557. {
  558. ATOMICRELEASE(pdsb);
  559. notifylist.SendNotify(WM_SONGCHANGE, (WPARAM)pszPath, 0);
  560. SetupSample(&zaxSample, pszPath, pBuffer, rgdsbp, ARRAYSIZE(rgdsbp), pds, &pdsb);
  561. }
  562. }
  563. break;
  564. case EVENT_NEXTSONG:
  565. {
  566. fPaused = FALSE;
  567. TCHAR pszPath[MAX_PATH];
  568. if (playlist.GetNextSong(pszPath, MAX_PATH))
  569. {
  570. if (pdsb)
  571. pdsb->Stop();
  572. ATOMICRELEASE(pdsb);
  573. notifylist.SendNotify(WM_SONGCHANGE, (WPARAM)pszPath, 0);
  574. SetupSample(&zaxSample, pszPath, pBuffer, rgdsbp, ARRAYSIZE(rgdsbp), pds, &pdsb);
  575. }
  576. }
  577. break;
  578. case EVENT_PREVSONG:
  579. {
  580. fPaused = FALSE;
  581. TCHAR pszPath[MAX_PATH];
  582. if (playlist.GetPrevSong(pszPath, MAX_PATH))
  583. {
  584. if (pdsb)
  585. pdsb->Stop();
  586. ATOMICRELEASE(pdsb);
  587. notifylist.SendNotify(WM_SONGCHANGE, (WPARAM)pszPath, 0);
  588. SetupSample(&zaxSample, pszPath, pBuffer, rgdsbp, ARRAYSIZE(rgdsbp), pds, &pdsb);
  589. }
  590. }
  591. break;
  592. case EVENT_SETSONG:
  593. {
  594. fPaused = FALSE;
  595. TCHAR pszPath[MAX_PATH];
  596. if (playlist.GetSong(pZaxxonEvent->iIndex, pszPath, MAX_PATH))
  597. {
  598. if (pdsb)
  599. pdsb->Stop();
  600. ATOMICRELEASE(pdsb);
  601. notifylist.SendNotify(WM_SONGCHANGE, (WPARAM)pszPath, 0);
  602. SetupSample(&zaxSample, pszPath, pBuffer, rgdsbp, ARRAYSIZE(rgdsbp), pds, &pdsb);
  603. }
  604. }
  605. case EVENT_PAUSE:
  606. if (pdsb)
  607. pdsb->Stop();
  608. fPaused = TRUE;
  609. break;
  610. case EVENT_TERMINATE:
  611. fDone = TRUE;
  612. break;
  613. }
  614. delete pZaxxonEvent;
  615. }
  616. ResetEvent(pza->hEvents);
  617. }
  618. }
  619. }
  620. SAFERELEASE(pdsb);
  621. SAFERELEASE(pds);
  622. if (rgEvent[0])
  623. CloseHandle(rgEvent[0]);
  624. if (rgEvent[1])
  625. CloseHandle(rgEvent[1]);
  626. CoUninitialize();
  627. }
  628. if (pBuffer)
  629. LocalFree((HLOCAL)pBuffer);
  630. return 1;
  631. }
  632. class CZaxxonPlayer : public IZaxxonPlayer
  633. {
  634. ZAXXON_ARG _za;
  635. LPTSTR _pszFile;
  636. int _cRef;
  637. HRESULT _LoadTypeLib();
  638. BOOL _AddPlayEvent(int i);
  639. BOOL _AddRemoveEvent(int i);
  640. BOOL _AddSongEvent(int iEvent, PWSTR pszFile);
  641. BOOL _AddHWNDEvent(int iEvent, HWND hwnd);
  642. BOOL _AddPositionEvent(DWORD dwEvent, UINT uSeconds);
  643. BOOL _AddEvent(DWORD dwEvent);
  644. BOOL _AddEventToList(ZAXXONEVENT* pzEvent);
  645. public:
  646. CZaxxonPlayer();
  647. virtual ~CZaxxonPlayer();
  648. STDMETHODIMP QueryInterface(REFIID riid, void** ppvObj);
  649. STDMETHODIMP_(ULONG) AddRef();
  650. STDMETHODIMP_(ULONG) Release();
  651. STDMETHODIMP Play();
  652. STDMETHODIMP Stop();
  653. STDMETHODIMP NextSong();
  654. STDMETHODIMP PrevSong();
  655. STDMETHODIMP SetSong(int i);
  656. STDMETHODIMP Forward(UINT iSeconds);
  657. STDMETHODIMP Backward(UINT iSeconds);
  658. STDMETHODIMP Pause();
  659. STDMETHODIMP AddSong(LPWSTR pszFile);
  660. STDMETHODIMP RemoveSong(int i);
  661. STDMETHODIMP Register(HWND hwnd);
  662. STDMETHODIMP DeRegister(HWND hwnd);
  663. STDMETHODIMP ClearPlaylist();
  664. };
  665. BOOL CZaxxonPlayer::_AddRemoveEvent(int i)
  666. {
  667. ZAXXONEVENT* pze = new ZAXXONEVENT;
  668. if (pze)
  669. {
  670. pze->_dwEvent = EVENT_REMOVESONG;
  671. pze->iIndex = i;
  672. return _AddEventToList(pze);
  673. }
  674. return FALSE;
  675. }
  676. BOOL CZaxxonPlayer::_AddPlayEvent(int i)
  677. {
  678. ZAXXONEVENT* pze = new ZAXXONEVENT;
  679. if (pze)
  680. {
  681. pze->_dwEvent = EVENT_SETSONG;
  682. pze->iIndex = i;
  683. return _AddEventToList(pze);
  684. }
  685. return FALSE;
  686. }
  687. BOOL CZaxxonPlayer::_AddPositionEvent(DWORD dwEvent, UINT uSeconds)
  688. {
  689. return FALSE;
  690. }
  691. BOOL CZaxxonPlayer::_AddHWNDEvent(int iEvent, HWND hwnd)
  692. {
  693. ZAXXONEVENT* pze = new ZAXXONEVENT;
  694. if (pze)
  695. {
  696. pze->_dwEvent = iEvent;
  697. pze->hwnd = hwnd;
  698. return _AddEventToList(pze);
  699. }
  700. return FALSE;
  701. }
  702. BOOL CZaxxonPlayer::_AddSongEvent(int iEvent, PWSTR pszFile)
  703. {
  704. ZAXXONEVENT* pze = new ZAXXONEVENT;
  705. if (pze)
  706. {
  707. pze->_dwEvent = iEvent;
  708. StrCpyN(pze->szPath, pszFile, ARRAYSIZE(pze->szPath));
  709. return _AddEventToList(pze);
  710. }
  711. return FALSE;
  712. }
  713. BOOL CZaxxonPlayer::_AddEvent(DWORD dwEvent)
  714. {
  715. ZAXXONEVENT* pze = new ZAXXONEVENT;
  716. if (pze)
  717. {
  718. pze->_dwEvent = dwEvent;
  719. return _AddEventToList(pze);
  720. }
  721. return FALSE;
  722. }
  723. BOOL CZaxxonPlayer::_AddEventToList(ZAXXONEVENT* pzEvent)
  724. {
  725. EnterCriticalSection(&_za.crit);
  726. BOOL fRet = FALSE;
  727. ZAXXONEVENT** ppza = &_za.pEvents;
  728. while (*ppza)
  729. {
  730. ppza = &(*ppza)->_pNext;
  731. }
  732. *ppza = pzEvent;
  733. SetEvent(_za.hEvents);
  734. LeaveCriticalSection(&_za.crit);
  735. return fRet;
  736. }
  737. CZaxxonPlayer::CZaxxonPlayer() : _cRef(1)
  738. {
  739. ZeroMemory(&_za, sizeof(_za));
  740. InitializeCriticalSection(&_za.crit);
  741. _za.hEvents = CreateEvent(NULL, TRUE, FALSE, NULL);
  742. if (_za.hEvents)
  743. {
  744. DWORD thread;
  745. _za.hThread = CreateThread(NULL, 0, AudioRenderThread, (LPVOID)&_za, 0, &thread);
  746. }
  747. }
  748. CZaxxonPlayer::~CZaxxonPlayer()
  749. {
  750. if (_za.hThread)
  751. {
  752. _AddEvent(EVENT_TERMINATE);
  753. WaitForSingleObject(_za.hThread, INFINITE);
  754. CloseHandle(_za.hThread);
  755. }
  756. CloseHandle(_za.hEvents);
  757. DeleteCriticalSection(&_za.crit);
  758. for (ZAXXONEVENT* pza = GetZaxxonEvent(&_za); pza; pza = GetZaxxonEvent(&_za))
  759. {
  760. delete pza;
  761. }
  762. }
  763. STDMETHODIMP CZaxxonPlayer::QueryInterface(REFIID riid, LPVOID * ppvObj)
  764. {
  765. static const QITAB qit[] =
  766. {
  767. QITABENT(CZaxxonPlayer, IZaxxonPlayer),
  768. { 0 },
  769. };
  770. return QISearch(this, qit, riid, ppvObj);
  771. }
  772. ULONG CZaxxonPlayer::AddRef()
  773. {
  774. _cRef++;
  775. return _cRef;
  776. }
  777. ULONG CZaxxonPlayer::Release()
  778. {
  779. ASSERT(_cRef > 0);
  780. _cRef--;
  781. if (_cRef > 0)
  782. return _cRef;
  783. delete this;
  784. return 0;
  785. }
  786. HRESULT CZaxxonPlayer::Play()
  787. {
  788. _AddEvent(EVENT_PLAY);
  789. return S_OK;
  790. }
  791. HRESULT CZaxxonPlayer::Stop()
  792. {
  793. _AddEvent(EVENT_STOP);
  794. return E_NOTIMPL;
  795. }
  796. HRESULT CZaxxonPlayer::Forward(UINT iSeconds)
  797. {
  798. return E_NOTIMPL;
  799. }
  800. HRESULT CZaxxonPlayer::Backward(UINT iSeconds)
  801. {
  802. return E_NOTIMPL;
  803. }
  804. HRESULT CZaxxonPlayer::Pause()
  805. {
  806. _AddEvent(EVENT_PAUSE);
  807. return S_OK;
  808. }
  809. HRESULT CZaxxonPlayer::AddSong(LPWSTR pszFile)
  810. {
  811. _AddSongEvent(EVENT_ADDSONG, pszFile);
  812. return S_OK;
  813. }
  814. HRESULT CZaxxonPlayer::RemoveSong(int i)
  815. {
  816. _AddRemoveEvent(i);
  817. return S_OK;
  818. }
  819. HRESULT CZaxxonPlayer::NextSong()
  820. {
  821. _AddEvent(EVENT_NEXTSONG);
  822. return S_OK;
  823. }
  824. HRESULT CZaxxonPlayer::PrevSong()
  825. {
  826. _AddEvent(EVENT_PREVSONG);
  827. return S_OK;
  828. }
  829. HRESULT CZaxxonPlayer::SetSong(int i)
  830. {
  831. _AddPlayEvent(i);
  832. return S_OK;
  833. }
  834. HRESULT CZaxxonPlayer::Register(HWND hwnd)
  835. {
  836. _AddHWNDEvent(EVENT_REGISTER, hwnd);
  837. return S_OK;
  838. }
  839. HRESULT CZaxxonPlayer::DeRegister(HWND hwnd)
  840. {
  841. _AddHWNDEvent(EVENT_REGISTER, hwnd);
  842. return S_OK;
  843. }
  844. HRESULT CZaxxonPlayer::ClearPlaylist()
  845. {
  846. _AddEvent(EVENT_CLEARPLAYLIST);
  847. return S_OK;
  848. }
  849. STDAPI CZaxxonPlayer_CreateInstance(IUnknown *punk, REFIID riid, void **ppv)
  850. {
  851. HRESULT hr;
  852. CZaxxonPlayer *pzax = new CZaxxonPlayer;
  853. if (pzax)
  854. {
  855. hr = pzax->QueryInterface(riid, ppv);
  856. pzax->Release();
  857. }
  858. else
  859. {
  860. hr = E_OUTOFMEMORY;
  861. *ppv = NULL;
  862. }
  863. return hr;
  864. }