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.

490 lines
14 KiB

  1. /*++
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name:
  4. wavecall.cpp
  5. Abstract:
  6. This module contains implementation of CWaveMSPCall.
  7. Author:
  8. Zoltan Szilagyi (zoltans) September 7, 1998
  9. --*/
  10. #include "stdafx.h"
  11. ///////////////////////////////////////////////////////////////////////////////
  12. ///////////////////////////////////////////////////////////////////////////////
  13. //
  14. CWaveMSPCall::CWaveMSPCall() : CMSPCallMultiGraph()
  15. {
  16. LOG((MSP_TRACE, "CWaveMSPCall::CWaveMSPCall entered."));
  17. m_fHavePerAddressWaveIDs = FALSE;
  18. m_dwPerAddressWaveInID = 0xfeedface;
  19. m_dwPerAddressWaveOutID = 0xfeedface;
  20. LOG((MSP_TRACE, "CWaveMSPCall::CWaveMSPCall exited."));
  21. }
  22. ///////////////////////////////////////////////////////////////////////////////
  23. ///////////////////////////////////////////////////////////////////////////////
  24. //
  25. CWaveMSPCall::~CWaveMSPCall()
  26. {
  27. LOG((MSP_TRACE, "CWaveMSPCall::~CWaveMSPCall entered."));
  28. LOG((MSP_TRACE, "CWaveMSPCall::~CWaveMSPCall exited."));
  29. }
  30. ULONG CWaveMSPCall::MSPCallAddRef(void)
  31. {
  32. return MSPAddRefHelper(this);
  33. }
  34. ULONG CWaveMSPCall::MSPCallRelease(void)
  35. {
  36. return MSPReleaseHelper(this);
  37. }
  38. ///////////////////////////////////////////////////////////////////////////////
  39. ///////////////////////////////////////////////////////////////////////////////
  40. //
  41. HRESULT CWaveMSPCall::Init(
  42. IN CMSPAddress * pMSPAddress,
  43. IN MSP_HANDLE htCall,
  44. IN DWORD dwReserved,
  45. IN DWORD dwMediaType
  46. )
  47. {
  48. // No need to acquire locks on this call because it is called only
  49. // once when the object is created. No other calls can be made on
  50. // this object at this point.
  51. LOG((MSP_TRACE, "CWaveMSPCall::Init - enter"));
  52. //
  53. // First do the base class method. We are adding to the functionality,
  54. // not replacing it.
  55. //
  56. HRESULT hr;
  57. hr = CMSPCallMultiGraph::Init(pMSPAddress,
  58. htCall,
  59. dwReserved,
  60. dwMediaType);
  61. if (FAILED(hr))
  62. {
  63. LOG((MSP_ERROR, "CWaveMSPCall::Init - "
  64. "base class method failed: %x", hr));
  65. return hr;
  66. }
  67. //
  68. // Our calls always come with two streams. Create them now. Use the base class
  69. // methods, as our overriden methods (exposed to the user) purposely fail in order
  70. // to keep the user from creating or removing streams themselves.
  71. // These methods return a pointer to the ITStream. They get saved in our list of
  72. // ITStreams, and we also save them here as CWaveMSPStream pointers.
  73. //
  74. ITStream * pStream;
  75. //
  76. // Create the capture stream.
  77. //
  78. hr = InternalCreateStream (dwMediaType,
  79. TD_CAPTURE,
  80. &pStream);
  81. if (FAILED(hr))
  82. {
  83. LOG((MSP_ERROR, "CWaveMSPCall::Init - "
  84. "couldn't create capture stream: %x", hr));
  85. return hr;
  86. }
  87. m_pCaptureStream = dynamic_cast<CWaveMSPStream *> (pStream);
  88. if ( m_pCaptureStream == NULL )
  89. {
  90. LOG((MSP_ERROR, "CWaveMSPCall::Init - "
  91. "couldn't dynamic_cast capture stream - exit E_FAIL"));
  92. return E_FAIL;
  93. }
  94. pStream->Release();
  95. //
  96. // Create the render stream.
  97. //
  98. hr = InternalCreateStream (dwMediaType,
  99. TD_RENDER,
  100. &pStream);
  101. if (FAILED(hr))
  102. {
  103. LOG((MSP_ERROR, "CWaveMSPCall::Init - "
  104. "couldn't create capture stream: %x", hr));
  105. return hr;
  106. }
  107. m_pRenderStream = dynamic_cast<CWaveMSPStream *> (pStream);
  108. if ( m_pRenderStream == NULL )
  109. {
  110. LOG((MSP_ERROR, "CWaveMSPCall::Init - "
  111. "couldn't dynamic_cast render stream - exit E_FAIL"));
  112. return E_FAIL;
  113. }
  114. pStream->Release();
  115. LOG((MSP_TRACE, "CWaveMSPCall::Init - exit S_OK"));
  116. return S_OK;
  117. }
  118. //////////////////////////////////////////////////////////////////////////////
  119. //////////////////////////////////////////////////////////////////////////////
  120. //
  121. // Public method called by the address to tell us the per-address wave IDs. We
  122. // hold on to them until we know whether we have per-call waveids, and if we
  123. // don't, then we set them on the streams.
  124. //
  125. //
  126. HRESULT CWaveMSPCall::SetWaveIDs(
  127. IN DWORD dwWaveInID,
  128. IN DWORD dwWaveOutID
  129. )
  130. {
  131. LOG((MSP_TRACE, "CWaveMSPCall::SetWaveIDs - enter"));
  132. m_fHavePerAddressWaveIDs = TRUE;
  133. m_dwPerAddressWaveInID = dwWaveInID;
  134. m_dwPerAddressWaveOutID = dwWaveOutID;
  135. LOG((MSP_TRACE, "CWaveMSPCall::SetWaveIDs - exit S_OK"));
  136. return S_OK;
  137. }
  138. ///////////////////////////////////////////////////////////////////////////////
  139. ///////////////////////////////////////////////////////////////////////////////
  140. //
  141. // We override this to make sure the number of
  142. // streams we have is constant.
  143. //
  144. STDMETHODIMP CWaveMSPCall::CreateStream (
  145. IN long lMediaType,
  146. IN TERMINAL_DIRECTION Direction,
  147. IN OUT ITStream ** ppStream
  148. )
  149. {
  150. LOG((MSP_TRACE, "CWaveMSPCall::CreateStream entered."));
  151. LOG((MSP_TRACE, "CWaveMSPCall::CreateStream - "
  152. "we have a fixed set of streams - exit TAPI_E_MAXSTREAMS"));
  153. return TAPI_E_MAXSTREAMS;
  154. }
  155. ///////////////////////////////////////////////////////////////////////////////
  156. ///////////////////////////////////////////////////////////////////////////////
  157. //
  158. // We override this to make sure the number of
  159. // streams we have is constant.
  160. //
  161. STDMETHODIMP CWaveMSPCall::RemoveStream (
  162. IN ITStream * pStream
  163. )
  164. {
  165. LOG((MSP_TRACE, "CWaveMSPCall::RemoveStream entered."));
  166. LOG((MSP_TRACE, "CWaveMSPCall::RemoveStream - "
  167. "we have a fixed set of streams - exit TAPI_E_NOTSUPPORTED"));
  168. return TAPI_E_NOTSUPPORTED;
  169. }
  170. ///////////////////////////////////////////////////////////////////////////////
  171. ///////////////////////////////////////////////////////////////////////////////
  172. //
  173. // This is our override to create the right kind of stream on stream creation.
  174. // The base class checks the arguments for us.
  175. //
  176. HRESULT CWaveMSPCall::CreateStreamObject(
  177. IN DWORD dwMediaType,
  178. IN TERMINAL_DIRECTION Direction,
  179. IN IMediaEvent * pGraph,
  180. IN ITStream ** ppStream
  181. )
  182. {
  183. LOG((MSP_TRACE, "CWaveMSPCall::CreateStreamObject - enter"));
  184. HRESULT hr;
  185. CMSPComObject<CWaveMSPStream> * pStream;
  186. hr = CMSPComObject<CWaveMSPStream>::CreateInstance( &pStream );
  187. if ( FAILED(hr) )
  188. {
  189. LOG((MSP_ERROR, "CWaveMSPCall::CreateStreamObject - "
  190. "can't create stream object - 0x%08x", hr));
  191. return hr;
  192. }
  193. hr = pStream->_InternalQueryInterface( IID_ITStream,
  194. (void **) ppStream );
  195. if ( FAILED(hr) )
  196. {
  197. LOG((MSP_ERROR, "CWaveMSPCall::CreateStreamObject - "
  198. "can't get ITStream interface - 0x%08x", hr));
  199. delete pStream;
  200. return hr;
  201. }
  202. hr = pStream->Init( (MSP_HANDLE) m_pMSPAddress,
  203. this,
  204. pGraph,
  205. dwMediaType,
  206. Direction);
  207. if ( FAILED(hr) )
  208. {
  209. LOG((MSP_ERROR, "CWaveMSPCall::CreateStreamObject - "
  210. "can't Init stream object - 0x%08x", hr));
  211. (*ppStream)->Release();
  212. return hr;
  213. }
  214. LOG((MSP_TRACE, "CWaveMSPCall::CreateStreamObject - exit S_OK"));
  215. return S_OK;
  216. }
  217. ///////////////////////////////////////////////////////////////////////////////
  218. ///////////////////////////////////////////////////////////////////////////////
  219. //
  220. // First DWORD = Command Second DWORD Third DWORD
  221. // ------------- ------- ------------ -----------
  222. // 0 Set wave IDs WaveIn ID WaveOut ID
  223. // 1 Start streaming <ignored> <ignored>
  224. // 2 Stop streaming <ignored> <ignored>
  225. // 3 <per-address, not per-call>
  226. // 4 <per-address, not per-call>
  227. // 5 Suspend streaming <ignored> <ignored>
  228. // 6 Resume streaming <ignored> <ignored>
  229. // 7 Wave IDs unavailable <ignored> <ignored>
  230. //
  231. // The method returns S_OK even if an individual stream failed to
  232. // start, stop, or initialize. This is because TAPI 3.0 doesn't need to
  233. // know about streaming failures in this code path. Instead, we
  234. // generate events to note failures (in the stream code).
  235. //
  236. HRESULT CWaveMSPCall::ReceiveTSPCallData(
  237. IN PBYTE pBuffer,
  238. IN DWORD dwSize
  239. )
  240. {
  241. LOG((MSP_TRACE, "CWaveMSPCall::ReceiveTSPCallData - enter"));
  242. //
  243. // Check that the buffer is as big as advertised.
  244. //
  245. if ( IsBadWritePtr(pBuffer, sizeof(BYTE) * dwSize) )
  246. {
  247. LOG((MSP_ERROR, "CWaveMSPCall::ReceiveTSPCallData - "
  248. "bad buffer - exit E_POINTER"));
  249. return E_POINTER;
  250. }
  251. //
  252. // Check if we have a command DWORD.
  253. //
  254. if ( dwSize < sizeof(DWORD) )
  255. {
  256. LOG((MSP_ERROR, "CWaveMSPCall::ReceiveTSPCallData - "
  257. "need a DWORD for command - exit E_INVALIDARG"));
  258. return E_INVALIDARG;
  259. }
  260. //
  261. // We are going to access the streams lists -- grab the lock
  262. //
  263. CLock lock(m_lock);
  264. _ASSERTE( m_Streams.GetSize() == 2 );
  265. int i;
  266. HRESULT hr;
  267. //
  268. // Based on the command, take action:
  269. //
  270. switch ( ((DWORD *) pBuffer) [0] )
  271. {
  272. //
  273. // Notes on waveid messages:
  274. //
  275. // * The capture stream is the one with a capture terminal, and thus we
  276. // need to give it the wave out id, and we need to give the render
  277. // terminal the wave in ID.
  278. // * We do not return errors or fire events on failure. If something
  279. // fails, then the waveid will not be set for that stream, and
  280. // a failure event will be fired when streaming begins.
  281. //
  282. case 0: // set per-call wave IDs (overrides per-address waveids)
  283. {
  284. if ( dwSize < 3 * sizeof(DWORD) )
  285. {
  286. LOG((MSP_ERROR, "CWaveMSPCall::ReceiveTSPCallData - "
  287. "need 3 DWORDs for SetWaveID command - "
  288. "exit E_INVALIDARG"));
  289. return E_INVALIDARG;
  290. }
  291. LOG((MSP_INFO, "CWaveMSPCall::ReceiveTSPCallData - "
  292. "setting WaveInID=%d, WaveOutID=%d",
  293. ((DWORD *) pBuffer) [1],
  294. ((DWORD *) pBuffer) [2]));
  295. // waveout
  296. hr = m_pCaptureStream->SetWaveID( ((DWORD *) pBuffer) [2] );
  297. if ( FAILED(hr) )
  298. {
  299. LOG((MSP_ERROR, "CWaveMSPCall::ReceiveTSPCallData - "
  300. "capture stream SetWaveID (per-call) failed 0x%08x - "
  301. "continuing", hr));
  302. }
  303. // wavein
  304. hr = m_pRenderStream ->SetWaveID( ((DWORD *) pBuffer) [1] );
  305. if ( FAILED(hr) )
  306. {
  307. LOG((MSP_ERROR, "CWaveMSPCall::ReceiveTSPCallData - "
  308. "render stream SetWaveID (per-call) failed 0x%08x - "
  309. "continuing", hr));
  310. }
  311. }
  312. break;
  313. case 7: // no per-call wave IDs (use per-address waveids if available)
  314. {
  315. if ( m_fHavePerAddressWaveIDs )
  316. {
  317. hr = m_pCaptureStream->SetWaveID( m_dwPerAddressWaveOutID );
  318. if ( FAILED(hr) )
  319. {
  320. LOG((MSP_ERROR, "CWaveMSPCall::ReceiveTSPCallData - "
  321. "capture stream SetWaveID (cached per-address id) "
  322. "failed 0x%08x - continuing", hr));
  323. }
  324. hr = m_pRenderStream ->SetWaveID( m_dwPerAddressWaveInID );
  325. if ( FAILED(hr) )
  326. {
  327. LOG((MSP_ERROR, "CWaveMSPCall::ReceiveTSPCallData - "
  328. "render stream SetWaveID (cached per-address id) "
  329. "failed 0x%08x - continuing", hr));
  330. }
  331. }
  332. else
  333. {
  334. LOG((MSP_ERROR, "CWaveMSPCall::ReceiveTSPCallData - "
  335. "no per-address and no per-call wave ids - continuing"));
  336. }
  337. }
  338. break;
  339. //
  340. // Notes on streaming state control messages:
  341. //
  342. // It is crucial that the order of invocations here be
  343. // kept the same for each message that is dispatched to streams;
  344. // otherwise you may get a different stream resuming than had
  345. // originally started in the case where only one stream can
  346. // run at a time (half-duplex hardware). Also, the exact order
  347. // (capture first, render second) is important as well! We get
  348. // better error reporting -- synchronous instead of asynchronous
  349. // -- for half-duplex line devices this way.
  350. //
  351. case 1: // start streaming
  352. {
  353. hr = m_pCaptureStream ->StartStream(); // waveout
  354. hr = m_pRenderStream ->StartStream(); // wavein
  355. }
  356. break;
  357. case 2: // stop streaming
  358. {
  359. hr = m_pCaptureStream ->StopStream(); // waveout
  360. hr = m_pRenderStream ->StopStream(); // wavein
  361. }
  362. break;
  363. case 5: // suspend streaming
  364. {
  365. hr = m_pCaptureStream ->SuspendStream(); // waveout
  366. hr = m_pRenderStream ->SuspendStream(); // wavein
  367. }
  368. break;
  369. case 6: // resume streaming
  370. {
  371. hr = m_pCaptureStream ->ResumeStream(); // waveout
  372. hr = m_pRenderStream ->ResumeStream(); // wavein
  373. }
  374. break;
  375. default:
  376. LOG((MSP_ERROR, "CWaveMSPCall::ReceiveTSPCallData - "
  377. "invalid command - exit E_INVALIDARG"));
  378. return E_INVALIDARG;
  379. }
  380. LOG((MSP_TRACE, "CWaveMSPCall::ReceiveTSPCallData - exit S_OK"));
  381. return S_OK;
  382. }
  383. // eof