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.

937 lines
22 KiB

  1. #include <objbase.h>
  2. #include <windowsx.h>
  3. #include <mmsystem.h>
  4. #include <dsoundp.h>
  5. //#include "debug.h"
  6. #include "debug.h"
  7. #include "dmusicc.h"
  8. #include "dmusici.h"
  9. #include "dmusicf.h"
  10. #include "validate.h"
  11. #include "riff.h"
  12. #include "dswave.h"
  13. #include "riff.h"
  14. #include <regstr.h>
  15. #include <share.h>
  16. #include "waveutil.h"
  17. #include "dmstrm.h"
  18. // seeks to a 32-bit position in a stream.
  19. HRESULT __inline StreamSeek( LPSTREAM pStream, long lSeekTo, DWORD dwOrigin )
  20. {
  21. LARGE_INTEGER li;
  22. if( lSeekTo < 0 )
  23. {
  24. li.HighPart = -1;
  25. }
  26. else
  27. {
  28. li.HighPart = 0;
  29. }
  30. li.LowPart = lSeekTo;
  31. return pStream->Seek( li, dwOrigin, NULL );
  32. }
  33. // returns the current 32-bit position in a stream.
  34. DWORD __inline StreamTell( LPSTREAM pStream )
  35. {
  36. LARGE_INTEGER li;
  37. ULARGE_INTEGER ul;
  38. #ifdef DBG
  39. HRESULT hr;
  40. #endif
  41. li.HighPart = 0;
  42. li.LowPart = 0;
  43. #ifdef DBG
  44. hr = pStream->Seek( li, STREAM_SEEK_CUR, &ul );
  45. if( FAILED( hr ) )
  46. #else
  47. if( FAILED( pStream->Seek( li, STREAM_SEEK_CUR, &ul ) ) )
  48. #endif
  49. {
  50. return 0;
  51. }
  52. return ul.LowPart;
  53. }
  54. CWave::CWave() : m_dwDecompressedStart(0)
  55. {
  56. V_INAME(CWave::CWave);
  57. InterlockedIncrement(&g_cComponent);
  58. InitializeCriticalSection(&m_CriticalSection);
  59. m_pwfx = NULL;
  60. m_pwfxDst = NULL;
  61. m_fdwFlags = 0;
  62. m_fdwOptions = 0;
  63. m_cSamples = 0L;
  64. m_pStream = NULL;
  65. m_rtReadAheadTime = 0;
  66. m_cRef = 1;
  67. }
  68. CWave::~CWave()
  69. {
  70. V_INAME(CWave::~CWave);
  71. if (NULL != m_pwfx)
  72. {
  73. GlobalFreePtr(m_pwfx);
  74. }
  75. if (NULL != m_pwfxDst)
  76. {
  77. GlobalFreePtr(m_pwfxDst);
  78. }
  79. if (m_pStream) m_pStream->Release();
  80. DeleteCriticalSection(&m_CriticalSection);
  81. InterlockedDecrement(&g_cComponent);
  82. }
  83. STDMETHODIMP CWave::QueryInterface
  84. (
  85. const IID &iid,
  86. void **ppv
  87. )
  88. {
  89. V_INAME(CWave::QueryInterface);
  90. V_REFGUID(iid);
  91. V_PTRPTR_WRITE(ppv);
  92. if (iid == IID_IUnknown || iid == IID_IDirectSoundWave)
  93. {
  94. *ppv = static_cast<IDirectSoundWave*>(this);
  95. }
  96. else if (iid == IID_IPersistStream)
  97. {
  98. *ppv = static_cast<IPersistStream*>(this);
  99. }
  100. else if (iid == IID_IDirectMusicObject)
  101. {
  102. *ppv = static_cast<IDirectMusicObject*>(this);
  103. }
  104. else if (iid == IID_IPrivateWave)
  105. {
  106. *ppv = static_cast<IPrivateWave*>(this);
  107. }
  108. else
  109. {
  110. *ppv = NULL;
  111. Trace(4,"Warning: Request to query unknown interface on Wave Object\n");
  112. return E_NOINTERFACE;
  113. }
  114. reinterpret_cast<IUnknown*>(this)->AddRef();
  115. return S_OK;
  116. }
  117. STDMETHODIMP_(ULONG) CWave::AddRef()
  118. {
  119. V_INAME(CWave::AddRef);
  120. return InterlockedIncrement(&m_cRef);
  121. }
  122. STDMETHODIMP_(ULONG) CWave::Release()
  123. {
  124. V_INAME(CWave::Release);
  125. if (!InterlockedDecrement(&m_cRef))
  126. {
  127. delete this;
  128. return 0;
  129. }
  130. return m_cRef;
  131. }
  132. static inline HRESULT MMRESULTToHRESULT(
  133. MMRESULT mmr)
  134. {
  135. switch (mmr)
  136. {
  137. case MMSYSERR_NOERROR:
  138. return S_OK;
  139. case MMSYSERR_ALLOCATED:
  140. return DSERR_ALLOCATED;
  141. case MMSYSERR_NOMEM:
  142. return E_OUTOFMEMORY;
  143. case MMSYSERR_INVALFLAG:
  144. return E_INVALIDARG;
  145. case MMSYSERR_INVALHANDLE:
  146. return E_INVALIDARG;
  147. case MMSYSERR_INVALPARAM:
  148. return E_INVALIDARG;
  149. }
  150. return E_FAIL;
  151. }
  152. STDMETHODIMP CWave::GetFormat
  153. (
  154. LPWAVEFORMATEX pwfx,
  155. DWORD dwSizeAllocated,
  156. LPDWORD pdwSizeWritten
  157. )
  158. {
  159. DWORD cbSize;
  160. LPWAVEFORMATEX pwfxTemp = NULL;
  161. V_INAME(CWave::GetFormat);
  162. if (!pwfx && !pdwSizeWritten)
  163. {
  164. Trace(1, "ERROR: GetFormat (Wave): Must request either the format or the required size\n.");
  165. return E_INVALIDARG;
  166. }
  167. if (!m_pwfx)
  168. {
  169. return DSERR_BADFORMAT;
  170. }
  171. if (WAVE_FORMAT_PCM == m_pwfx->wFormatTag)
  172. {
  173. pwfxTemp = m_pwfx;
  174. }
  175. else
  176. {
  177. pwfxTemp = m_pwfxDst;
  178. if (!pwfxTemp)
  179. {
  180. return DSERR_BADFORMAT;
  181. }
  182. }
  183. // Note: Assuming that the wave object fills the cbSize field even
  184. // on PCM formats...
  185. if (WAVE_FORMAT_PCM == pwfxTemp->wFormatTag)
  186. {
  187. cbSize = sizeof(PCMWAVEFORMAT);
  188. }
  189. else
  190. {
  191. cbSize = sizeof(WAVEFORMATEX) + pwfxTemp->cbSize;
  192. }
  193. if (cbSize > dwSizeAllocated || !pwfx)
  194. {
  195. if (pdwSizeWritten)
  196. {
  197. *pdwSizeWritten = cbSize;
  198. return S_OK; // What to return?
  199. }
  200. else
  201. {
  202. return DSERR_INVALIDPARAM;
  203. }
  204. }
  205. // We don't validate this parameter any earlier on the off chance
  206. // that they're doing a query...
  207. V_BUFPTR_WRITE(pwfx, dwSizeAllocated);
  208. CopyMemory(pwfx, pwfxTemp, cbSize);
  209. // Set the cbSize field in destination for PCM, IF WE HAVE ROOM...
  210. if (WAVE_FORMAT_PCM == pwfxTemp->wFormatTag)
  211. {
  212. if (sizeof(WAVEFORMATEX) <= dwSizeAllocated)
  213. {
  214. pwfx->cbSize = 0;
  215. }
  216. }
  217. // Return the numbers of bytes actually writted
  218. if (pdwSizeWritten)
  219. {
  220. *pdwSizeWritten = cbSize;
  221. }
  222. return S_OK;
  223. }
  224. STDMETHODIMP CWave::CreateSource
  225. (
  226. IDirectSoundSource **ppSource,
  227. LPWAVEFORMATEX pwfx,
  228. DWORD fdwFlags
  229. )
  230. {
  231. HRESULT hr = S_OK;
  232. CWaveViewPort* pVP;
  233. CREATEVIEWPORT cvp;
  234. V_INAME(CWave::CreateSource);
  235. V_PTRPTR_WRITE(ppSource);
  236. V_PWFX_READ(pwfx);
  237. DWORD dwCreateFlags = 0;
  238. if (fdwFlags == DMUS_DOWNLOADINFO_ONESHOTWAVE)
  239. {
  240. dwCreateFlags |= DSOUND_WAVEF_ONESHOT;
  241. }
  242. if (dwCreateFlags & (~DSOUND_WAVEF_CREATEMASK))
  243. {
  244. Trace(1, "ERROR: CreateSource (Wave): Unknown flag.\n");
  245. return (E_INVALIDARG);
  246. }
  247. TraceI(5, "CWave::CreateSource [%d samples]\n", m_cSamples);
  248. pVP = new CWaveViewPort;
  249. if (!pVP)
  250. {
  251. return E_OUTOFMEMORY;
  252. }
  253. cvp.pStream = m_pStream;
  254. cvp.cSamples = m_cSamples;
  255. cvp.dwDecompressedStart = m_dwDecompressedStart;
  256. cvp.cbStream = m_cbStream;
  257. cvp.pwfxSource = m_pwfx;
  258. cvp.pwfxTarget = pwfx;
  259. cvp.fdwOptions = dwCreateFlags;
  260. hr = pVP->Create(&cvp);
  261. if (SUCCEEDED(hr))
  262. {
  263. hr = pVP->QueryInterface(IID_IDirectSoundSource, (void **)ppSource);
  264. }
  265. else
  266. {
  267. TraceI(5, "CWave::CreateSource 00\n");
  268. }
  269. if (SUCCEEDED(hr))
  270. {
  271. // The QI gave us one ref too many
  272. pVP->Release();
  273. }
  274. else
  275. {
  276. TraceI(5, "CWave::CreateSource 01\n");
  277. }
  278. return hr;
  279. }
  280. STDMETHODIMP CWave::GetStreamingParms
  281. (
  282. LPDWORD pdwFlags,
  283. LPREFERENCE_TIME prtReadAhead
  284. )
  285. {
  286. V_INAME(IDirectSoundWave::GetStreamingParms);
  287. V_PTR_WRITE(pdwFlags, DWORD);
  288. V_PTR_WRITE(prtReadAhead, REFERENCE_TIME);
  289. *pdwFlags = 0;
  290. if(!(m_fdwFlags & DSOUND_WAVEF_ONESHOT))
  291. {
  292. *pdwFlags |= DMUS_WAVEF_STREAMING;
  293. }
  294. if(m_fdwFlags & DMUS_WAVEF_NOPREROLL)
  295. {
  296. *pdwFlags |= DMUS_WAVEF_NOPREROLL;
  297. }
  298. *prtReadAhead = m_rtReadAheadTime;
  299. return S_OK;
  300. }
  301. STDMETHODIMP CWave::GetClassID
  302. (
  303. CLSID* pClsId
  304. )
  305. {
  306. V_INAME(CWave::GetClassID);
  307. V_PTR_WRITE(pClsId, CLSID);
  308. *pClsId = CLSID_DirectSoundWave;
  309. return S_OK;
  310. }
  311. STDMETHODIMP CWave::IsDirty()
  312. {
  313. V_INAME(CWave::IsDirty);
  314. return S_FALSE;
  315. }
  316. BOOL CWave::ParseHeader
  317. (
  318. IStream* pIStream,
  319. IRIFFStream* pIRiffStream,
  320. LPMMCKINFO pckMain
  321. )
  322. {
  323. MMCKINFO ck;
  324. DWORD cb = 0;
  325. DWORD dwPos = 0;
  326. MMCKINFO ckINFO;
  327. HRESULT hr;
  328. ck.ckid = 0;
  329. ck.fccType = 0;
  330. V_INAME(CWave::ParseHeader);
  331. BOOL fFormat = FALSE;
  332. BOOL fData = FALSE;
  333. BOOL fHeader = FALSE;
  334. BOOL fReadDecompressionFmt = FALSE;
  335. DWORD dwSamplesFromFact = 0;
  336. while (0 == pIRiffStream->Descend(&ck, pckMain, MMIO_FINDCHUNK))
  337. {
  338. switch (ck.ckid)
  339. {
  340. case mmioFOURCC('w','a','v','u') :
  341. {
  342. cb = 0;
  343. bool bRuntime = false;
  344. hr = pIStream->Read(&bRuntime, sizeof(bool), &cb);
  345. if(FAILED(hr) || cb != sizeof(bool))
  346. {
  347. return FALSE;
  348. }
  349. cb = 0;
  350. bool bCompressed = false;
  351. hr = pIStream->Read(&bCompressed, sizeof(bool), &cb);
  352. if(FAILED(hr) || cb != sizeof(bool))
  353. {
  354. return FALSE;
  355. }
  356. if(bRuntime && bCompressed)
  357. {
  358. // If we have already allocated m_pwfxDst, delete it first
  359. if (NULL != m_pwfxDst)
  360. {
  361. GlobalFreePtr(m_pwfxDst);
  362. }
  363. m_pwfxDst = (LPWAVEFORMATEX)GlobalAllocPtr(GHND, sizeof(WAVEFORMATEX));
  364. if (NULL == m_pwfxDst)
  365. {
  366. return FALSE;
  367. }
  368. cb = 0;
  369. hr = pIStream->Read(m_pwfxDst, sizeof(WAVEFORMATEX), &cb);
  370. if(FAILED(hr) || cb != sizeof(WAVEFORMATEX))
  371. {
  372. GlobalFreePtr(m_pwfxDst);
  373. return FALSE;
  374. }
  375. // Read the actual start for the decompressed data if available
  376. // This is very important for MP3 and WMA codecs which insert silence in the beginning
  377. if(ck.cksize > 2 + sizeof(WAVEFORMATEX))
  378. {
  379. cb = 0;
  380. hr = pIStream->Read(&m_dwDecompressedStart, sizeof(DWORD), &cb);
  381. if(FAILED(hr) || cb != sizeof(DWORD))
  382. {
  383. GlobalFreePtr(m_pwfxDst);
  384. return FALSE;
  385. }
  386. }
  387. fReadDecompressionFmt = TRUE;
  388. }
  389. break;
  390. }
  391. case DMUS_FOURCC_WAVEHEADER_CHUNK:
  392. {
  393. m_fdwFlags = 0;
  394. fHeader = TRUE;
  395. DMUS_IO_WAVE_HEADER iWaveHeader;
  396. memset(&iWaveHeader, 0, sizeof(iWaveHeader));
  397. hr = pIStream->Read(&iWaveHeader, sizeof(iWaveHeader), &cb);
  398. if (iWaveHeader.dwFlags & DMUS_WAVEF_STREAMING)
  399. {
  400. m_fdwFlags &= ~DSOUND_WAVEF_ONESHOT;
  401. m_rtReadAheadTime = iWaveHeader.rtReadAhead;
  402. }
  403. else
  404. {
  405. m_fdwFlags |= DSOUND_WAVEF_ONESHOT;
  406. m_rtReadAheadTime = 0;
  407. }
  408. if (iWaveHeader.dwFlags & DMUS_WAVEF_NOPREROLL)
  409. {
  410. m_fdwFlags |= DMUS_WAVEF_NOPREROLL;
  411. }
  412. else
  413. {
  414. m_fdwFlags &= ~DMUS_WAVEF_NOPREROLL;
  415. }
  416. break;
  417. }
  418. case DMUS_FOURCC_GUID_CHUNK:
  419. hr = pIStream->Read(&m_guid, sizeof(GUID), &cb);
  420. m_fdwOptions |= DMUS_OBJ_OBJECT;
  421. break;
  422. case DMUS_FOURCC_VERSION_CHUNK:
  423. hr = pIStream->Read( &m_vVersion, sizeof(DMUS_VERSION), &cb );
  424. m_fdwOptions |= DMUS_OBJ_VERSION;
  425. break;
  426. case FOURCC_LIST:
  427. switch(ck.fccType)
  428. {
  429. case DMUS_FOURCC_INFO_LIST:
  430. while( pIRiffStream->Descend( &ckINFO, &ck, 0 ) == 0 )
  431. {
  432. switch(ckINFO.ckid)
  433. {
  434. case mmioFOURCC('I','N','A','M'):
  435. {
  436. DWORD cbSize;
  437. cbSize = min(ckINFO.cksize, DMUS_MAX_NAME);
  438. char szName[DMUS_MAX_NAME];
  439. hr = pIStream->Read((BYTE*)szName, cbSize, &cb);
  440. if(SUCCEEDED(hr))
  441. {
  442. MultiByteToWideChar(CP_ACP, 0, szName, -1, m_wszFilename, DMUS_MAX_NAME);
  443. m_fdwOptions |= DMUS_OBJ_NAME;
  444. }
  445. break;
  446. }
  447. }
  448. pIRiffStream->Ascend( &ckINFO, 0 );
  449. }
  450. break;
  451. }
  452. break;
  453. case mmioFOURCC('f','m','t',' '):
  454. {
  455. // If we have already allocated m_pwfx, delete it first
  456. if (NULL != m_pwfx)
  457. {
  458. GlobalFreePtr(m_pwfx);
  459. }
  460. m_pwfx = (LPWAVEFORMATEX)GlobalAllocPtr(GHND, max (sizeof(WAVEFORMATEX), ck.cksize));
  461. if (NULL == m_pwfx)
  462. {
  463. return FALSE;
  464. }
  465. hr = pIStream->Read(m_pwfx, ck.cksize, &cb);
  466. if (S_OK != hr)
  467. {
  468. return FALSE;
  469. }
  470. if (m_pwfx && WAVE_FORMAT_PCM != m_pwfx->wFormatTag)
  471. {
  472. if(fReadDecompressionFmt == FALSE)
  473. {
  474. // If we have already allocated m_pwfxDst, delete it first
  475. if (NULL != m_pwfxDst)
  476. {
  477. GlobalFreePtr(m_pwfxDst);
  478. }
  479. m_pwfxDst = (LPWAVEFORMATEX)GlobalAllocPtr(GHND, sizeof(WAVEFORMATEX));
  480. if (NULL == m_pwfxDst)
  481. {
  482. return FALSE;
  483. }
  484. m_pwfxDst->wFormatTag = WAVE_FORMAT_PCM;
  485. MMRESULT mmr = acmFormatSuggest(NULL, m_pwfx, m_pwfxDst, sizeof(WAVEFORMATEX), ACM_FORMATSUGGESTF_WFORMATTAG);
  486. if(MMSYSERR_NOERROR != mmr)
  487. {
  488. GlobalFreePtr(m_pwfxDst);
  489. m_pwfxDst = NULL;
  490. return FALSE;
  491. }
  492. }
  493. }
  494. fFormat = TRUE;
  495. TraceI(5, "Format [%d:%d%c%02d]\n", m_pwfx->wFormatTag, m_pwfx->nSamplesPerSec/1000, ((2==m_pwfx->nChannels)?'S':'M'), m_pwfx->wBitsPerSample);
  496. break;
  497. }
  498. case mmioFOURCC('f','a','c','t'):
  499. hr = pIStream->Read(&dwSamplesFromFact, sizeof(DWORD), &cb);
  500. TraceI(5, "Stream is %d samples\n", dwSamplesFromFact);
  501. break;
  502. case mmioFOURCC('d','a','t','a'):
  503. TraceI(5, "Data chunk %d bytes\n", ck.cksize);
  504. m_cbStream = ck.cksize;
  505. fData = TRUE;
  506. if (!fHeader) FallbackStreamingBehavior();
  507. // save stream position so we can seek back later
  508. dwPos = StreamTell( pIStream );
  509. break;
  510. default:
  511. break;
  512. }
  513. pIRiffStream->Ascend(&ck, 0);
  514. ck.ckid = 0;
  515. ck.fccType = 0;
  516. }
  517. if (m_pwfx && WAVE_FORMAT_PCM != m_pwfx->wFormatTag && dwSamplesFromFact)
  518. {
  519. m_cSamples = dwSamplesFromFact;
  520. }
  521. if (!fHeader) FallbackStreamingBehavior();
  522. // Seek to beginning of data
  523. if (fData)
  524. {
  525. StreamSeek(pIStream, dwPos, STREAM_SEEK_SET);
  526. }
  527. return fFormat && fData;
  528. }
  529. STDMETHODIMP CWave::Load
  530. (
  531. IStream* pIStream
  532. )
  533. {
  534. IRIFFStream* pIRiffStream = NULL;
  535. HRESULT hr = S_OK;
  536. V_INAME(CWave::Load);
  537. if (NULL == pIStream)
  538. {
  539. Trace(1, "ERROR: Load (Wave): Attempt to load from null stream.\n");
  540. return E_INVALIDARG;
  541. }
  542. EnterCriticalSection( &m_CriticalSection );
  543. if (SUCCEEDED(AllocRIFFStream(pIStream, &pIRiffStream)))
  544. {
  545. MMCKINFO ckMain;
  546. ckMain.fccType = mmioFOURCC('W','A','V','E');
  547. if (0 != pIRiffStream->Descend(&ckMain, NULL, MMIO_FINDRIFF))
  548. {
  549. Trace(1, "ERROR: Load (Wave): Stream does not contain a wave chunk.\n");
  550. hr = E_INVALIDARG;
  551. goto ON_END;
  552. }
  553. // Parses the header information and seeks to the beginning
  554. // of the data in the data chunk.
  555. if (0 == ParseHeader(pIStream, pIRiffStream, &ckMain))
  556. {
  557. Trace(1, "ERROR: Load (Wave): Attempt to read wave's header information failed.\n");
  558. hr = E_INVALIDARG;
  559. goto ON_END;
  560. }
  561. if (0 == m_cSamples)
  562. {
  563. if (m_pwfx && WAVE_FORMAT_PCM == m_pwfx->wFormatTag)
  564. {
  565. m_cSamples = m_cbStream / m_pwfx->nBlockAlign;
  566. }
  567. else // wave format not supported
  568. {
  569. hr = DSERR_BADFORMAT;
  570. goto ON_END;
  571. }
  572. }
  573. }
  574. pIStream->AddRef();
  575. if (m_pStream)
  576. {
  577. m_pStream->Release();
  578. }
  579. m_pStream = pIStream;
  580. ON_END:
  581. if (pIRiffStream) pIRiffStream->Release();
  582. LeaveCriticalSection( &m_CriticalSection );
  583. TraceI(5, "CWave::Load01\n");
  584. return hr;
  585. }
  586. STDMETHODIMP CWave::Save
  587. (
  588. IStream* pIStream,
  589. BOOL fClearDirty
  590. )
  591. {
  592. V_INAME(CWave::Save);
  593. return E_NOTIMPL;
  594. }
  595. STDMETHODIMP CWave::GetSizeMax
  596. (
  597. ULARGE_INTEGER FAR* pcbSize
  598. )
  599. {
  600. V_INAME(CWave::GetSizeMax);
  601. return E_NOTIMPL;
  602. }
  603. STDMETHODIMP CWave::GetDescriptor
  604. (
  605. LPDMUS_OBJECTDESC pDesc
  606. )
  607. {
  608. // Parameter validation...
  609. V_INAME(CWave::GetDescriptor);
  610. V_STRUCTPTR_WRITE(pDesc, DMUS_OBJECTDESC)
  611. ZeroMemory(pDesc, sizeof(DMUS_OBJECTDESC));
  612. pDesc->dwSize = sizeof(DMUS_OBJECTDESC);
  613. pDesc->dwValidData = DMUS_OBJ_CLASS;
  614. pDesc->guidClass = CLSID_DirectSoundWave;
  615. if (NULL != m_pwfx)
  616. {
  617. pDesc->dwValidData |= DMUS_OBJ_LOADED;
  618. }
  619. if (m_fdwOptions & DMUS_OBJ_OBJECT)
  620. {
  621. pDesc->guidObject = m_guid;
  622. pDesc->dwValidData |= DMUS_OBJ_OBJECT;
  623. }
  624. if (m_fdwOptions & DMUS_OBJ_NAME)
  625. {
  626. memcpy( pDesc->wszName, m_wszFilename, sizeof(m_wszFilename) );
  627. pDesc->dwValidData |= DMUS_OBJ_NAME;
  628. }
  629. if (m_fdwOptions & DMUS_OBJ_VERSION)
  630. {
  631. pDesc->vVersion.dwVersionMS = m_vVersion.dwVersionMS;
  632. pDesc->vVersion.dwVersionLS = m_vVersion.dwVersionLS;
  633. pDesc->dwValidData |= DMUS_OBJ_VERSION;
  634. }
  635. return S_OK;
  636. }
  637. STDMETHODIMP CWave::SetDescriptor
  638. (
  639. LPDMUS_OBJECTDESC pDesc
  640. )
  641. {
  642. HRESULT hr = E_INVALIDARG;
  643. DWORD dw = 0;
  644. // Parameter validation...
  645. V_INAME(CWave::SetDescriptor);
  646. V_PTR_READ(pDesc, DMUS_OBJECTDESC)
  647. if (pDesc->dwSize >= sizeof(DMUS_OBJECTDESC))
  648. {
  649. if(pDesc->dwValidData & DMUS_OBJ_CLASS)
  650. {
  651. dw |= DMUS_OBJ_CLASS;
  652. }
  653. if(pDesc->dwValidData & DMUS_OBJ_LOADED)
  654. {
  655. dw |= DMUS_OBJ_LOADED;
  656. }
  657. if (pDesc->dwValidData & DMUS_OBJ_OBJECT)
  658. {
  659. m_guid = pDesc->guidObject;
  660. dw |= DMUS_OBJ_OBJECT;
  661. m_fdwOptions |= DMUS_OBJ_OBJECT;
  662. }
  663. if (pDesc->dwValidData & DMUS_OBJ_NAME)
  664. {
  665. memcpy( m_wszFilename, pDesc->wszName, sizeof(WCHAR)*DMUS_MAX_NAME );
  666. dw |= DMUS_OBJ_NAME;
  667. m_fdwOptions |= DMUS_OBJ_NAME;
  668. }
  669. if (pDesc->dwValidData & DMUS_OBJ_VERSION)
  670. {
  671. m_vVersion.dwVersionMS = pDesc->vVersion.dwVersionMS;
  672. m_vVersion.dwVersionLS = pDesc->vVersion.dwVersionLS;
  673. dw |= DMUS_OBJ_VERSION;
  674. m_fdwOptions |= DMUS_OBJ_VERSION;
  675. }
  676. if (pDesc->dwValidData & (~dw))
  677. {
  678. Trace(2, "WARNING: SetDescriptor (Wave): Descriptor contains fields that were not set.\n");
  679. hr = S_FALSE;
  680. pDesc->dwValidData = dw;
  681. }
  682. else
  683. {
  684. hr = S_OK;
  685. }
  686. }
  687. return hr;
  688. }
  689. STDMETHODIMP CWave::ParseDescriptor
  690. (
  691. LPSTREAM pStream,
  692. LPDMUS_OBJECTDESC pDesc
  693. )
  694. {
  695. V_INAME(CWave::ParseDescriptor);
  696. V_PTR_READ(pDesc, DMUS_OBJECTDESC)
  697. CRiffParser Parser(pStream);
  698. RIFFIO ckMain;
  699. RIFFIO ckNext;
  700. RIFFIO ckINFO;
  701. HRESULT hr = S_OK;
  702. Parser.EnterList(&ckMain);
  703. if (Parser.NextChunk(&hr) && (ckMain.fccType == mmioFOURCC('W','A','V','E')))
  704. {
  705. Parser.EnterList(&ckNext);
  706. while(Parser.NextChunk(&hr))
  707. {
  708. switch(ckNext.ckid)
  709. {
  710. case DMUS_FOURCC_GUID_CHUNK:
  711. hr = Parser.Read( &pDesc->guidObject, sizeof(GUID) );
  712. if( SUCCEEDED(hr) )
  713. {
  714. pDesc->dwValidData |= DMUS_OBJ_OBJECT;
  715. }
  716. break;
  717. case DMUS_FOURCC_VERSION_CHUNK:
  718. hr = Parser.Read( &pDesc->vVersion, sizeof(DMUS_VERSION) );
  719. if( SUCCEEDED(hr) )
  720. {
  721. pDesc->dwValidData |= DMUS_OBJ_VERSION;
  722. }
  723. break;
  724. case FOURCC_LIST:
  725. switch(ckNext.fccType)
  726. {
  727. case DMUS_FOURCC_INFO_LIST:
  728. Parser.EnterList(&ckINFO);
  729. while (Parser.NextChunk(&hr))
  730. {
  731. switch( ckINFO.ckid )
  732. {
  733. case mmioFOURCC('I','N','A','M'):
  734. {
  735. DWORD cbSize;
  736. cbSize = min(ckINFO.cksize, DMUS_MAX_NAME);
  737. char szName[DMUS_MAX_NAME];
  738. hr = Parser.Read(&szName, sizeof(szName));
  739. if(SUCCEEDED(hr))
  740. {
  741. MultiByteToWideChar(CP_ACP, 0, szName, -1, pDesc->wszName, DMUS_MAX_NAME);
  742. pDesc->dwValidData |= DMUS_OBJ_NAME;
  743. }
  744. break;
  745. }
  746. default:
  747. break;
  748. }
  749. }
  750. Parser.LeaveList();
  751. break;
  752. }
  753. break;
  754. default:
  755. break;
  756. }
  757. }
  758. Parser.LeaveList();
  759. }
  760. else
  761. {
  762. Trace(2, "WARNING: ParseDescriptor (Wave): The stream does not contain a Wave chunk.\n");
  763. hr = DMUS_E_CHUNKNOTFOUND;
  764. }
  765. return hr;
  766. }
  767. STDMETHODIMP CWave::GetLength(REFERENCE_TIME *prtLength)
  768. {
  769. HRESULT hr = S_OK;
  770. if (0 == m_cSamples)
  771. {
  772. if (m_pwfx && WAVE_FORMAT_PCM == m_pwfx->wFormatTag)
  773. {
  774. m_cSamples = m_cbStream / m_pwfx->nBlockAlign;
  775. }
  776. }
  777. if (m_cSamples && m_pwfx && m_pwfx->nSamplesPerSec)
  778. {
  779. if(m_dwDecompressedStart > 0)
  780. {
  781. assert(m_dwDecompressedStart < m_cSamples);
  782. *prtLength = 1000 * (REFERENCE_TIME)(m_cSamples - m_dwDecompressedStart) / m_pwfx->nSamplesPerSec;
  783. }
  784. else
  785. {
  786. *prtLength = 1000 * (REFERENCE_TIME)m_cSamples / m_pwfx->nSamplesPerSec;
  787. }
  788. }
  789. else
  790. {
  791. Trace(2, "WARNING: Couldn't get a length for a Wave.\n");
  792. hr = DMUS_E_BADWAVE;
  793. }
  794. return hr;
  795. }