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.

313 lines
8.4 KiB

  1. // Copyright (c) 1997 - 1998 Microsoft Corporation. All Rights Reserved.
  2. // austrm.cpp : Implementation of CAudioStream
  3. #include "stdafx.h"
  4. #include "project.h"
  5. #include "austrm.h"
  6. // Helper
  7. void SetWaveFormatEx(
  8. LPWAVEFORMATEX pFormat,
  9. int nChannels,
  10. int nBitsPerSample,
  11. int nSamplesPerSecond
  12. )
  13. {
  14. pFormat->wFormatTag = WAVE_FORMAT_PCM;
  15. pFormat->nChannels = (WORD)nChannels;
  16. pFormat->nSamplesPerSec = (DWORD)nSamplesPerSecond;
  17. pFormat->nBlockAlign = (WORD)((nBitsPerSample * nChannels) / 8);
  18. pFormat->nAvgBytesPerSec = (DWORD)(nSamplesPerSecond * pFormat->nBlockAlign);
  19. pFormat->wBitsPerSample = (WORD)nBitsPerSample;
  20. pFormat->cbSize = 0;
  21. }
  22. HRESULT ConvertWAVEFORMATEXToMediaType(
  23. const WAVEFORMATEX *pFormat,
  24. AM_MEDIA_TYPE **ppmt
  25. )
  26. {
  27. AM_MEDIA_TYPE *pmt;
  28. pmt = (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(*pmt));
  29. if (pmt == NULL) {
  30. return E_OUTOFMEMORY;
  31. }
  32. _ASSERTE(pFormat->wFormatTag == WAVE_FORMAT_PCM);
  33. ZeroMemory(pmt, sizeof(*pmt));
  34. pmt->majortype = MEDIATYPE_Audio;
  35. pmt->formattype = FORMAT_WaveFormatEx;
  36. pmt->bFixedSizeSamples = TRUE;
  37. pmt->lSampleSize = pFormat->nBlockAlign;
  38. pmt->cbFormat = sizeof(*pFormat);
  39. pmt->pbFormat = (PBYTE)CoTaskMemAlloc(sizeof(*pFormat));
  40. if (pmt->pbFormat == NULL) {
  41. CoTaskMemFree(pmt);
  42. return E_OUTOFMEMORY;
  43. }
  44. CopyMemory(pmt->pbFormat, pFormat, sizeof(*pFormat));
  45. *ppmt = pmt;
  46. return S_OK;
  47. }
  48. /////////////////////////////////////////////////////////////////////////////
  49. // CAudioStream
  50. CAudioStream::CAudioStream() :
  51. m_fForceFormat(false)
  52. {
  53. // Set to mono 16bit PCM 11025Hz
  54. SetWaveFormatEx(&m_Format, 1, 16, 11025);
  55. }
  56. STDMETHODIMP
  57. CAudioStream::ReceiveConnection(
  58. IPin * pConnector,
  59. const AM_MEDIA_TYPE *pmt
  60. )
  61. {
  62. AUTO_CRIT_LOCK;
  63. //
  64. // This helper function in CStream checks basic parameters for the Pin such as
  65. // the connecting pin's direction (we need to check this -- Sometimes the filter
  66. // graph will try to connect us to ourselves!) and other errors like already being
  67. // connected, etc.
  68. //
  69. HRESULT hr = CheckReceiveConnectionPin(pConnector);
  70. if (hr == NOERROR) {
  71. /* Accept only the format we've been given. If we
  72. haven't been given a format accept PCM only
  73. */
  74. if (pmt->majortype != MEDIATYPE_Audio ||
  75. pmt->formattype != FORMAT_WaveFormatEx ||
  76. pmt->cbFormat < sizeof(WAVEFORMATEX)) {
  77. hr = VFW_E_TYPE_NOT_ACCEPTED;
  78. } else {
  79. hr = InternalSetFormat((LPWAVEFORMATEX)pmt->pbFormat, true);
  80. if (SUCCEEDED(hr)) {
  81. CopyMediaType(&m_ConnectedMediaType, pmt);
  82. m_pConnectedPin = pConnector;
  83. }
  84. }
  85. }
  86. return hr;
  87. }
  88. STDMETHODIMP CAudioStream::SetSameFormat(IMediaStream *pStream, DWORD dwFlags)
  89. {
  90. CComQIPtr<IAudioMediaStream, &IID_IAudioMediaStream> pSource(pStream);
  91. if (!pSource) {
  92. return MS_E_INCOMPATIBLE;
  93. }
  94. WAVEFORMATEX wfx;
  95. HRESULT hr = pSource->GetFormat(&wfx);
  96. if (SUCCEEDED(hr)) {
  97. hr = SetFormat(&wfx);
  98. }
  99. return hr;
  100. }
  101. STDMETHODIMP CAudioStream::AllocateSample(DWORD dwFlags, IStreamSample **ppNewSample)
  102. {
  103. IAudioStreamSample *pSample = NULL;
  104. IAudioData *pAudioData;
  105. HRESULT hr = CoCreateInstance(CLSID_AMAudioData, NULL, CLSCTX_INPROC_SERVER,
  106. IID_IAudioData, (void **)&pAudioData);
  107. if (SUCCEEDED(hr)) {
  108. // Pick a sensible buffer size - 1/10 second
  109. DWORD dwBufferSize = m_Format.nAvgBytesPerSec / 10 +
  110. m_Format.nBlockAlign - 1;
  111. dwBufferSize -= dwBufferSize % m_Format.nBlockAlign;
  112. pAudioData->SetBuffer(dwBufferSize, NULL, 0);
  113. pAudioData->SetFormat(&m_Format);
  114. hr = CreateSample(pAudioData, 0, &pSample);
  115. }
  116. *ppNewSample = pSample;
  117. return hr;
  118. }
  119. STDMETHODIMP CAudioStream::CreateSharedSample(
  120. /* [in] */ IStreamSample *pExistingSample,
  121. DWORD dwFlags,
  122. /* [out] */ IStreamSample **ppNewSample
  123. )
  124. {
  125. AUTO_CRIT_LOCK;
  126. // See if we can get the information we need from the existing
  127. // sample
  128. IAudioStreamSample *pAudioSample;
  129. HRESULT hr = pExistingSample->QueryInterface(
  130. IID_IAudioStreamSample,
  131. (void **)&pAudioSample);
  132. if (FAILED(hr)) {
  133. return hr;
  134. }
  135. IAudioData *pAudioData;
  136. hr = pAudioSample->GetAudioData(&pAudioData);
  137. pAudioSample->Release();
  138. if (FAILED(hr)) {
  139. return hr;
  140. }
  141. IAudioStreamSample *pNewSample;
  142. hr = CreateSample(pAudioData, 0, &pNewSample);
  143. pAudioData->Release();
  144. if (FAILED(hr)) {
  145. return hr;
  146. }
  147. hr = pNewSample->QueryInterface(IID_IStreamSample, (void**)ppNewSample);
  148. pNewSample->Release();
  149. return hr;
  150. }
  151. STDMETHODIMP CAudioStream::SetFormat(const WAVEFORMATEX *pFormat)
  152. {
  153. if (pFormat == NULL) {
  154. return E_POINTER;
  155. }
  156. AUTO_CRIT_LOCK;
  157. return InternalSetFormat(pFormat, false);
  158. }
  159. STDMETHODIMP CAudioStream::GetFormat(LPWAVEFORMATEX pFormat)
  160. {
  161. if (pFormat == NULL) {
  162. return E_POINTER;
  163. }
  164. if (!m_pConnectedPin) {
  165. return MS_E_NOSTREAM;
  166. }
  167. *pFormat = m_Format;
  168. return S_OK;
  169. }
  170. STDMETHODIMP CAudioStream::CreateSample(
  171. /* [in] */ IAudioData *pAudioData,
  172. /* [in] */ DWORD dwFlags,
  173. /* [out] */ IAudioStreamSample **ppSample
  174. )
  175. {
  176. if (dwFlags != 0) {
  177. return E_INVALIDARG;
  178. }
  179. if (pAudioData == NULL || ppSample == NULL) {
  180. return E_POINTER;
  181. }
  182. AUTO_CRIT_LOCK;
  183. // Check the format
  184. WAVEFORMATEX wfx;
  185. HRESULT hr = pAudioData->GetFormat(&wfx);
  186. if (FAILED(hr)) {
  187. return hr;
  188. }
  189. hr = CheckFormat(&wfx);
  190. if (FAILED(hr)) {
  191. return hr;
  192. }
  193. typedef CComObject<CAudioStreamSample> _AudioSample;
  194. _AudioSample *pSample = new _AudioSample;
  195. if (pSample == NULL) {
  196. return E_OUTOFMEMORY;
  197. }
  198. hr = pSample->Init(pAudioData);
  199. if (FAILED(hr)) {
  200. return hr;
  201. }
  202. pSample->InitSample(this, false);
  203. return pSample->GetControllingUnknown()->QueryInterface(
  204. IID_IAudioStreamSample, (void **)ppSample
  205. );
  206. }
  207. HRESULT CAudioStream::CheckFormat(const WAVEFORMATEX *lpFormat, bool bForceFormat)
  208. {
  209. if (lpFormat->wFormatTag != WAVE_FORMAT_PCM ||
  210. lpFormat->nBlockAlign == 0) {
  211. return E_INVALIDARG;
  212. }
  213. if ((m_pConnectedPin || bForceFormat) &&
  214. 0 != memcmp(lpFormat, &m_Format, sizeof(m_Format)))
  215. {
  216. // Try reconnection!
  217. return E_INVALIDARG;
  218. }
  219. return S_OK;
  220. }
  221. HRESULT CAudioStream::InternalSetFormat(const WAVEFORMATEX *lpFormat, bool bFromPin)
  222. {
  223. HRESULT hr = CheckFormat(lpFormat, m_fForceFormat);
  224. if (FAILED(hr)) {
  225. return hr;
  226. }
  227. m_Format = *lpFormat;
  228. m_lBytesPerSecond = m_Format.nAvgBytesPerSec;
  229. if(!bFromPin) {
  230. m_fForceFormat = true;
  231. }
  232. return S_OK;
  233. }
  234. //
  235. // Special CStream methods
  236. //
  237. HRESULT CAudioStream::GetMediaType(ULONG Index, AM_MEDIA_TYPE **ppMediaType)
  238. {
  239. if (Index != 0) {
  240. return S_FALSE;
  241. }
  242. return ConvertWAVEFORMATEXToMediaType(&m_Format, ppMediaType);
  243. }
  244. //////////////////////////////////////////////////////////////////////
  245. // CAudioData
  246. CAudioData::CAudioData() :
  247. m_cbSize(0),
  248. m_pbData(0),
  249. m_cbData(0),
  250. m_bWeAllocatedData(false)
  251. {
  252. // Set to mono 16bit PCM 11025Hz
  253. SetWaveFormatEx(&m_Format, 1, 16, 11025);
  254. }
  255. CAudioData::~CAudioData()
  256. {
  257. if (m_bWeAllocatedData) {
  258. CoTaskMemFree(m_pbData);
  259. }
  260. }
  261. STDMETHODIMP CAudioStream::GetProperties(ALLOCATOR_PROPERTIES* pProps)
  262. {
  263. AUTO_CRIT_LOCK;
  264. // NB TAPI relies on this number as a max for now when
  265. // we're connected to the AVI Mux which uses this size to
  266. // create its own samples
  267. pProps->cbBuffer = CAudioStream::GetChopSize();
  268. // Default to 5 buffers (half a second at our default buffer size)
  269. pProps->cBuffers = m_lRequestedBufferCount ? m_lRequestedBufferCount : 5;
  270. pProps->cbAlign = 1;
  271. pProps->cbPrefix = 0;
  272. return NOERROR;
  273. }
  274. STDMETHODIMP CAudioStream::SetProperties(ALLOCATOR_PROPERTIES* pRequest, ALLOCATOR_PROPERTIES* pActual)
  275. {
  276. HRESULT hr;
  277. AUTO_CRIT_LOCK;
  278. ZeroMemory(pActual, sizeof(*pActual));
  279. if (pRequest->cbAlign == 0) {
  280. hr = VFW_E_BADALIGN;
  281. } else {
  282. if (m_bCommitted == TRUE) {
  283. hr = VFW_E_ALREADY_COMMITTED;
  284. } else {
  285. m_lRequestedBufferCount = pRequest->cBuffers;
  286. hr = GetProperties(pActual);
  287. }
  288. }
  289. return hr;
  290. }