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.

289 lines
7.4 KiB

  1. // Copyright (c) 1997 Microsoft Corporation. All Rights Reserved.
  2. #include <windows.h>
  3. #include <mmsystem.h>
  4. #include <amstream.h>
  5. #include <stdio.h>
  6. /********************************************************************
  7. Trivial wave player stuff
  8. ********************************************************************/
  9. class CWaveBuffer;
  10. class CWaveBuffer {
  11. public:
  12. CWaveBuffer();
  13. ~CWaveBuffer();
  14. BOOL Init(HWAVEOUT hWave, int Size);
  15. void Done();
  16. BOOL Write(PBYTE pData, int nBytes, int& BytesWritten);
  17. void Flush();
  18. private:
  19. WAVEHDR m_Hdr;
  20. HWAVEOUT m_hWave;
  21. int m_nBytes;
  22. };
  23. class CWaveOut {
  24. public:
  25. CWaveOut(LPCWAVEFORMATEX Format, int nBuffers, int BufferSize);
  26. ~CWaveOut();
  27. void Write(PBYTE Data, int nBytes);
  28. void Flush();
  29. void Wait();
  30. void Reset();
  31. private:
  32. const HANDLE m_hSem;
  33. const int m_nBuffers;
  34. int m_CurrentBuffer;
  35. BOOL m_NoBuffer;
  36. CWaveBuffer *m_Hdrs;
  37. HWAVEOUT m_hWave;
  38. };
  39. /*
  40. CWaveBuffer
  41. */
  42. CWaveBuffer::CWaveBuffer()
  43. {
  44. }
  45. BOOL CWaveBuffer::Init(HWAVEOUT hWave, int Size)
  46. {
  47. m_hWave = hWave;
  48. m_nBytes = 0;
  49. /* Allocate a buffer and initialize the header */
  50. m_Hdr.lpData = (LPSTR)LocalAlloc(LMEM_FIXED, Size);
  51. if (m_Hdr.lpData == NULL) {
  52. return FALSE;
  53. }
  54. m_Hdr.dwBufferLength = Size;
  55. m_Hdr.dwBytesRecorded = 0;
  56. m_Hdr.dwUser = 0;
  57. m_Hdr.dwFlags = 0;
  58. m_Hdr.dwLoops = 0;
  59. m_Hdr.lpNext = 0;
  60. m_Hdr.reserved = 0;
  61. /* Prepare it */
  62. waveOutPrepareHeader(hWave, &m_Hdr, sizeof(WAVEHDR));
  63. return TRUE;
  64. }
  65. CWaveBuffer::~CWaveBuffer() {
  66. if (m_Hdr.lpData) {
  67. waveOutUnprepareHeader(m_hWave, &m_Hdr, sizeof(WAVEHDR));
  68. LocalFree(m_Hdr.lpData);
  69. }
  70. }
  71. void CWaveBuffer::Flush()
  72. {
  73. //ASSERT(m_nBytes != 0);
  74. m_nBytes = 0;
  75. waveOutWrite(m_hWave, &m_Hdr, sizeof(WAVEHDR));
  76. }
  77. BOOL CWaveBuffer::Write(PBYTE pData, int nBytes, int& BytesWritten)
  78. {
  79. //ASSERT((DWORD)m_nBytes != m_Hdr.dwBufferLength);
  80. BytesWritten = min((int)m_Hdr.dwBufferLength - m_nBytes, nBytes);
  81. CopyMemory((PVOID)(m_Hdr.lpData + m_nBytes), (PVOID)pData, BytesWritten);
  82. m_nBytes += BytesWritten;
  83. if (m_nBytes == (int)m_Hdr.dwBufferLength) {
  84. /* Write it! */
  85. m_nBytes = 0;
  86. waveOutWrite(m_hWave, &m_Hdr, sizeof(WAVEHDR));
  87. return TRUE;
  88. }
  89. return FALSE;
  90. }
  91. void CALLBACK WaveCallback(HWAVEOUT hWave, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
  92. {
  93. if (uMsg == WOM_DONE) {
  94. ReleaseSemaphore((HANDLE)dwUser, 1, NULL);
  95. }
  96. }
  97. /*
  98. CWaveOut
  99. */
  100. CWaveOut::CWaveOut(LPCWAVEFORMATEX Format, int nBuffers, int BufferSize) :
  101. m_nBuffers(nBuffers),
  102. m_CurrentBuffer(0),
  103. m_NoBuffer(TRUE),
  104. m_hSem(CreateSemaphore(NULL, nBuffers, nBuffers, NULL)),
  105. m_Hdrs(new CWaveBuffer[nBuffers]),
  106. m_hWave(NULL)
  107. {
  108. /* Create wave device */
  109. waveOutOpen(&m_hWave,
  110. WAVE_MAPPER,
  111. Format,
  112. (DWORD)WaveCallback,
  113. (DWORD)m_hSem,
  114. CALLBACK_FUNCTION);
  115. /* Initialize the wave buffers */
  116. for (int i = 0; i < nBuffers; i++) {
  117. m_Hdrs[i].Init(m_hWave, BufferSize);
  118. }
  119. }
  120. CWaveOut::~CWaveOut()
  121. {
  122. /* First get our buffers back */
  123. waveOutReset(m_hWave);
  124. /* Free the buffers */
  125. delete [] m_Hdrs;
  126. /* Close the wave device */
  127. waveOutClose(m_hWave);
  128. /* Free our semaphore */
  129. CloseHandle(m_hSem);
  130. }
  131. void CWaveOut::Flush()
  132. {
  133. if (!m_NoBuffer) {
  134. m_Hdrs[m_CurrentBuffer].Flush();
  135. m_NoBuffer = TRUE;
  136. m_CurrentBuffer = (m_CurrentBuffer + 1) % m_nBuffers;
  137. }
  138. }
  139. void CWaveOut::Reset()
  140. {
  141. waveOutReset(m_hWave);
  142. }
  143. void CWaveOut::Write(PBYTE pData, int nBytes)
  144. {
  145. while (nBytes != 0) {
  146. /* Get a buffer if necessary */
  147. if (m_NoBuffer) {
  148. WaitForSingleObject(m_hSem, INFINITE);
  149. m_NoBuffer = FALSE;
  150. }
  151. /* Write into a buffer */
  152. int nWritten;
  153. if (m_Hdrs[m_CurrentBuffer].Write(pData, nBytes, nWritten)) {
  154. m_NoBuffer = TRUE;
  155. m_CurrentBuffer = (m_CurrentBuffer + 1) % m_nBuffers;
  156. nBytes -= nWritten;
  157. pData += nWritten;
  158. } else {
  159. //ASSERT(nWritten == nBytes);
  160. break;
  161. }
  162. }
  163. }
  164. void CWaveOut::Wait()
  165. {
  166. /* Send any remaining buffers */
  167. Flush();
  168. /* Wait for our buffers back */
  169. for (int i = 0; i < m_nBuffers; i++) {
  170. WaitForSingleObject(m_hSem, INFINITE);
  171. }
  172. LONG lPrevCount;
  173. ReleaseSemaphore(m_hSem, m_nBuffers, &lPrevCount);
  174. }
  175. /**************************************************************************
  176. End of wave player stuff
  177. **************************************************************************/
  178. HRESULT RenderStreamToDevice(IMultiMediaStream *pMMStream)
  179. {
  180. WAVEFORMATEX wfx;
  181. #define DATA_SIZE 5000
  182. PBYTE pBuffer = (PBYTE)LocalAlloc(LMEM_FIXED, DATA_SIZE);
  183. IMediaStream *pStream;
  184. IAudioStreamSample *pSample;
  185. IAudioMediaStream *pAudioStream;
  186. IAudioData *pAudioData;
  187. pMMStream->GetMediaStream(MSPID_PrimaryAudio, &pStream);
  188. pStream->QueryInterface(IID_IAudioMediaStream, (void **)&pAudioStream);
  189. pAudioStream->GetFormat(&wfx);
  190. CoCreateInstance(CLSID_AMAudioData, NULL, CLSCTX_INPROC_SERVER,
  191. IID_IAudioData, (void **)&pAudioData);
  192. pAudioData->SetBuffer(DATA_SIZE, pBuffer, 0);
  193. pAudioData->SetFormat(&wfx);
  194. pAudioStream->CreateSample(pAudioData, 0, &pSample);
  195. HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  196. CWaveOut WaveOut(&wfx, 4, 2048);
  197. int iTimes;
  198. DWORD dwLength = 0;
  199. for (iTimes = 0; iTimes < 3; iTimes++) {
  200. for (; ; ) {
  201. HRESULT hr = pSample->Update(0, hEvent, NULL, 0);
  202. WaitForSingleObject(hEvent, INFINITE);
  203. pAudioData->GetInfo(NULL, NULL, &dwLength);
  204. printf("%d bytes in buffer\n", dwLength);
  205. WaveOut.Write(pBuffer, dwLength);
  206. hr = pSample->CompletionStatus(0, 0);
  207. if (hr != S_OK) {
  208. printf("Completion status %8.8x\n", hr);
  209. break;
  210. }
  211. }
  212. HANDLE hComplete;
  213. pMMStream->GetEndOfStreamEventHandle(&hComplete);
  214. WaitForSingleObject(hComplete, INFINITE);
  215. pMMStream->Seek(0);
  216. }
  217. pAudioData->Release();
  218. pSample->Release();
  219. pStream->Release();
  220. pAudioStream->Release();
  221. LocalFree((HLOCAL)pBuffer);
  222. return S_OK;
  223. }
  224. HRESULT RenderFileToMMStream(WCHAR * pszFileName, IMultiMediaStream **ppMMStream)
  225. {
  226. IAMMultiMediaStream *pAMStream;
  227. CoCreateInstance(CLSID_AMMultiMediaStream, NULL, CLSCTX_INPROC_SERVER,
  228. IID_IAMMultiMediaStream, (void **)&pAMStream);
  229. pAMStream->Initialize(STREAMTYPE_READ, AMMSF_NOGRAPHTHREAD, NULL);
  230. pAMStream->AddMediaStream(NULL, &MSPID_PrimaryAudio, 0, NULL);
  231. pAMStream->OpenFile(pszFileName, AMMSF_RUN);
  232. *ppMMStream = pAMStream;
  233. return S_OK;
  234. }
  235. int _CRTAPI1 main(int argc, char *argv[])
  236. {
  237. IMultiMediaStream *pMMStream;
  238. CoInitialize(NULL);
  239. WCHAR wszName[1000];
  240. MultiByteToWideChar(CP_ACP, 0, argv[1], -1, wszName,
  241. sizeof(wszName) / sizeof(wszName[0]));
  242. RenderFileToMMStream(wszName, &pMMStream);
  243. RenderStreamToDevice(pMMStream);
  244. pMMStream->Release();
  245. CoUninitialize();
  246. return 0;
  247. }