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.

421 lines
12 KiB

  1. /*----------------------------------------------------------------------------
  2. * File: RTCPIO.C
  3. * Product: RTP/RTCP implementation
  4. * Description: Provides the RTCP network I/O.
  5. *
  6. * INTEL Corporation Proprietary Information
  7. * This listing is supplied under the terms of a license agreement with
  8. * Intel Corporation and may not be copied nor disclosed except in
  9. * accordance with the terms of that agreement.
  10. * Copyright (c) 1995 Intel Corporation.
  11. *--------------------------------------------------------------------------*/
  12. #include "rrcm.h"
  13. /*---------------------------------------------------------------------------
  14. / External Variables
  15. /--------------------------------------------------------------------------*/
  16. extern PRTCP_CONTEXT pRTCPContext;
  17. extern RRCM_WS RRCMws;
  18. #ifdef _DEBUG
  19. extern char debug_string[];
  20. #endif
  21. #if (defined(_DEBUG) || defined(PCS_COMPLIANCE))
  22. //INTEROP
  23. extern LPInteropLogger RTPLogger;
  24. #endif
  25. /*----------------------------------------------------------------------------
  26. * Function : RTCPThread
  27. * Description: RTCP thread
  28. *
  29. * Input : pRTCPctxt: -> to RTCP context
  30. *
  31. * Return: None.
  32. ---------------------------------------------------------------------------*/
  33. void RTCPThread (PRTCP_CONTEXT pRTCPctxt)
  34. {
  35. PSSRC_ENTRY pSSRC;
  36. PSSRC_ENTRY pRecvSSRC;
  37. PRTCP_SESSION pRTCP;
  38. long timerPeriod;
  39. long minTimeInterval;
  40. long prvTimeoutChkTime = 0;
  41. DWORD initTime;
  42. long deltaTime;
  43. int dwStatus;
  44. DWORD curTime;
  45. DWORD dwNumBytesXfr;
  46. HANDLE bfrHandle[2];
  47. DWORD dwHandleCnt;
  48. RRCM_DBG_MSG ("RTCP: RTCP thread running ...", 0, NULL, 0, DBG_NOTIFY);
  49. // setup buffer Events
  50. bfrHandle[0] = pRTCPctxt->hTerminateRtcpEvent;
  51. bfrHandle[1] = pRTCPctxt->hRtcpRptRequestEvent;
  52. dwHandleCnt = 2;
  53. // loop as long as there are sessions in the RTCP session list
  54. //
  55. while (1)
  56. {
  57. //LOOK: Claim global critical section?
  58. // walk through the RTCP session list from the tail and check which
  59. // SSRC entry timed out if any
  60. curTime = timeGetTime();
  61. minTimeInterval = TIMEOUT_CHK_FREQ; // 30 seconds
  62. for (pRTCP = (PRTCP_SESSION)pRTCPctxt->RTCPSession.prev;
  63. pRTCP;
  64. pRTCP = (PRTCP_SESSION)(pRTCP->RTCPList.next))
  65. {
  66. // if RTCP is disabled or shutdown is in progress, ignore
  67. // this session and move on.
  68. if (!(pRTCP->dwSessionStatus & RTCP_ON)
  69. || (pRTCP->dwSessionStatus & SHUTDOWN_IN_PROGRESS))
  70. continue;
  71. // lock out access to this RTCP session
  72. EnterCriticalSection (&pRTCP->critSect);
  73. // NOTE: this assumes only one SSRC in the transmit list but
  74. // that assumption has been made elsewhere too
  75. pSSRC = (PSSRC_ENTRY)pRTCP->XmtSSRCList.prev;
  76. // if its a new session, post RECVs
  77. if (pRTCP->dwSessionStatus & NEW_RTCP_SESSION)
  78. {
  79. // post RTCP receive buffers
  80. dwStatus = RTCPrcvInit(pSSRC);
  81. #ifdef _DEBUG
  82. if (dwStatus == FALSE)
  83. {
  84. RRCM_DBG_MSG ("RTCP: Couldn't initialize RTCP receive", 0,
  85. __FILE__, __LINE__, DBG_TRACE);
  86. }
  87. #endif
  88. // get initial transmit time
  89. timerPeriod = (long)RTCPxmitInterval (1, 0,
  90. pSSRC->xmtInfo.dwRtcpStreamMinBW,
  91. 0, 100,
  92. &pRTCP->avgRTCPpktSizeRcvd,
  93. 1);
  94. pSSRC->dwNextReportSendTime = curTime + timerPeriod;
  95. pRTCP->dwSessionStatus &= ~NEW_RTCP_SESSION;
  96. }
  97. // check if it has any expired SSRCs
  98. if ((curTime - prvTimeoutChkTime) > TIMEOUT_CHK_FREQ)
  99. {
  100. while (pRecvSSRC = SSRCTimeoutCheck (pRTCP, curTime))
  101. {
  102. // notify application if interested
  103. // NOTE: may be do this outside the loop?
  104. RRCMnotification (RRCM_TIMEOUT_EVENT, pRecvSSRC,
  105. pRecvSSRC->SSRC, 0);
  106. // remove this entry from the list
  107. deleteSSRCEntry (pRecvSSRC->SSRC, pRTCP);
  108. }
  109. prvTimeoutChkTime = curTime;
  110. }
  111. if ( ! (pRTCP->dwSessionStatus & RTCP_DEST_LEARNED))
  112. {
  113. // cant send yet because we dont know who to
  114. // send to. Delay for 3 seconds
  115. pSSRC->dwNextReportSendTime = curTime + 3000;
  116. }
  117. // if its time to send RTCP reports on this session
  118. // then break out of the loop and send it (cannot
  119. // send with the global critsect held)
  120. //
  121. timerPeriod = (pSSRC->dwNextReportSendTime - curTime);
  122. if (timerPeriod <= RTCP_TIMEOUT_WITHIN_RANGE
  123. && FormatRTCPReport(pRTCP, pSSRC, curTime))
  124. {
  125. // increment Xmt count in anticipation. This will prevent
  126. // the session from being deleted while the send is in progress.
  127. InterlockedIncrement ((long *)&pSSRC->dwNumXmtIoPending);
  128. InterlockedIncrement ((long *)&pSSRC->dwNumRptSent);
  129. LeaveCriticalSection(&pRTCP->critSect);
  130. break;
  131. }
  132. // if not then check how long before the next scheduled
  133. // transmission and save the minimum. We will sleep
  134. // for this much time and then start again.
  135. if (minTimeInterval > timerPeriod)
  136. minTimeInterval = timerPeriod;
  137. LeaveCriticalSection(&pRTCP->critSect);
  138. }
  139. if (pRTCP)
  140. {
  141. #if (defined(_DEBUG) || defined(PCS_COMPLIANCE))
  142. if (RTPLogger)
  143. {
  144. //INTEROP
  145. InteropOutput (RTPLogger,
  146. (BYTE FAR*)(pRTCP->XmtBfr.buf),
  147. (int)pRTCP->XmtBfr.len,
  148. RTPLOG_SENT_PDU | RTCP_PDU);
  149. }
  150. #endif
  151. // send the RTCP packet
  152. dwStatus = RRCMws.sendTo (pSSRC->RTCPsd,
  153. &pRTCP->XmtBfr,
  154. 1,
  155. &dwNumBytesXfr,
  156. 0,
  157. (PSOCKADDR)pRTCP->toBfr,
  158. pRTCP->toLen,
  159. NULL,
  160. NULL);
  161. // check SendTo status
  162. if (dwStatus == SOCKET_ERROR)
  163. {
  164. RRCM_DBG_MSG ("RTCP: ERROR - WSASendTo()", dwStatus,
  165. __FILE__, __LINE__, DBG_ERROR);
  166. //If dwStatus is WSAENOTSOCK (or worse, a fault)
  167. //We're likely shutting down, and the RTCP session
  168. //is going away, don't touch it and let the normal
  169. //shutdown code take over
  170. if (dwStatus != WSAENOTSOCK && dwStatus != WSAEFAULT) {
  171. // notify application if interested
  172. RRCMnotification (RRCM_RTCP_WS_XMT_ERROR, pSSRC,
  173. pSSRC->SSRC, dwStatus);
  174. InterlockedDecrement ((long *)&pSSRC->dwNumRptSent);
  175. }
  176. }
  177. InterlockedDecrement ((long *)&pSSRC->dwNumXmtIoPending);
  178. // run through the session list again
  179. continue;
  180. }
  181. // grab an initial timestamp so we can reset WaitForSingleObjectEx
  182. initTime = timeGetTime();
  183. // now we've gone through all the RTCP sessions and
  184. // verified that none have pending reports to be sent
  185. // We also know the earliest scheduled timeout so
  186. // lets sleep till then.
  187. while (1)
  188. {
  189. dwStatus = WaitForMultipleObjectsEx (dwHandleCnt,
  190. bfrHandle,
  191. FALSE,
  192. (DWORD)minTimeInterval,
  193. TRUE);
  194. if (dwStatus == WAIT_OBJECT_0)
  195. {
  196. // Exit event was signalled
  197. #ifdef _DEBUG
  198. wsprintf(debug_string,
  199. "RTCP: Exit RTCP thread - Handle: x%p - ID: x%lX",
  200. pRTCPctxt->hRtcpThread, pRTCPctxt->dwRtcpThreadID);
  201. RRCM_DBG_MSG (debug_string, 0, NULL, 0, DBG_TRACE);
  202. #endif
  203. ExitThread (0);
  204. }
  205. else if (dwStatus == WAIT_OBJECT_0+1)
  206. {
  207. // the application requested a non-periodic control
  208. // of the RTCP report frequency
  209. break;
  210. }
  211. else if (dwStatus == WAIT_IO_COMPLETION)
  212. {
  213. // decrement the timerPeriod so the WaitForSingleObjectEx
  214. // can continue but if we're less than 250 milliseconds from
  215. // the original timeout go ahead and call it close enough.
  216. curTime = timeGetTime();
  217. deltaTime = curTime - initTime;
  218. if (deltaTime < 0)
  219. break;
  220. else
  221. {
  222. if (minTimeInterval >
  223. (deltaTime + (RTCP_TIMEOUT_WITHIN_RANGE * 2)))
  224. {
  225. minTimeInterval -= deltaTime;
  226. }
  227. else
  228. break;
  229. }
  230. }
  231. else if (dwStatus == WAIT_TIMEOUT)
  232. {
  233. // the expected completion status
  234. break;
  235. }
  236. else if (dwStatus == WAIT_FAILED)
  237. {
  238. RRCM_DBG_MSG ("RTCP: Wait() Error", GetLastError(),
  239. __FILE__, __LINE__, DBG_ERROR);
  240. break;
  241. }
  242. }
  243. }
  244. }
  245. /*----------------------------------------------------------------------------
  246. * Function : RTCPThreadCtrl
  247. * Description: RTCP thread ON / OFF
  248. *
  249. * Input : dwState: ON / OFF
  250. *
  251. * Return: 0 (success) / 0xFFFFFFFF (failure)
  252. ---------------------------------------------------------------------------*/
  253. DWORD WINAPI RTCPThreadCtrl (DWORD dwState)
  254. {
  255. IN_OUT_STR ("RTCP : Enter RTCPThreadCtrl()\n");
  256. DWORD dwStatus = RRCM_NoError;
  257. DWORD dwSuspendCnt;
  258. DWORD idx;
  259. if (pRTCPContext->hRtcpThread == 0)
  260. {
  261. IN_OUT_STR ("RTCP : Exit RTCPThreadCtrl()\n");
  262. return dwStatus;
  263. }
  264. if (dwState == RTCP_ON)
  265. {
  266. idx = MAXIMUM_SUSPEND_COUNT;
  267. while (idx--)
  268. {
  269. dwSuspendCnt = ResumeThread (pRTCPContext->hRtcpThread);
  270. if (dwSuspendCnt <= 1)
  271. {
  272. break;
  273. }
  274. else if (dwSuspendCnt == 0xFFFFFFFF)
  275. {
  276. dwStatus = RRCM_NoError;
  277. break;
  278. }
  279. }
  280. }
  281. else if (dwState == RTCP_OFF)
  282. {
  283. if (SuspendThread (pRTCPContext->hRtcpThread) == 0xFFFFFFFF)
  284. {
  285. RRCM_DBG_MSG ("RTCP: SuspendThread() Error", GetLastError(),
  286. __FILE__, __LINE__, DBG_ERROR);
  287. }
  288. }
  289. IN_OUT_STR ("RTCP : Exit RTCPThreadCtrl()\n");
  290. return dwStatus;
  291. }
  292. /*----------------------------------------------------------------------------
  293. * Function : RTCPSendSessionCtrl
  294. * Description: Gives RTCP control to the application if the application
  295. * desire to do so. The application is now responsible to comply
  296. * with the RTP specification.
  297. *
  298. * Input : hRtpSession: Handle of the RTP session
  299. * dwTimeout: RTCP send message timeout
  300. * 0x0 -> RRCM control
  301. * 0x7FFFFFFF -> RTCP xmt disabled
  302. * value -> selected timeout
  303. * (periodic or not)
  304. *
  305. * Return: 0 (success) / 0xFFFFFFFF (failure)
  306. ---------------------------------------------------------------------------*/
  307. HRESULT WINAPI RTCPSendSessionCtrl (DWORD_PTR RTPSession,
  308. DWORD dwTimeOut)
  309. {
  310. IN_OUT_STR ("RTCP : Enter RTCPSendSessionCtrl()\n");
  311. PRTP_SESSION pSession;
  312. PSSRC_ENTRY pSSRC;
  313. DWORD dwStatus = RRCM_NoError;
  314. // Cast Session ID to obtain the session pointer.
  315. pSession = (PRTP_SESSION)RTPSession;
  316. if (pSession == NULL)
  317. {
  318. RRCM_DBG_MSG ("RTCP : ERROR - Invalid RTP session", 0,
  319. __FILE__, __LINE__, DBG_ERROR);
  320. IN_OUT_STR ("RTP : Exit RTCPSendSessionCtrl()\n");
  321. return (MAKE_RRCM_ERROR (RRCMError_RTPSessResources));
  322. }
  323. // Get this RTP session's transmit SSRC
  324. pSSRC = (PSSRC_ENTRY)pSession->pRTCPSession->XmtSSRCList.prev;
  325. if (pSSRC == NULL)
  326. {
  327. RRCM_DBG_MSG ("RTP : ERROR - No SSRC entry on the Xmt list", 0,
  328. __FILE__, __LINE__, DBG_ERROR);
  329. IN_OUT_STR ("RTCP : Exit RTCPSendSessionCtrl()\n");
  330. return (MAKE_RRCM_ERROR (RRCMError_RTCPInvalidSSRCentry));
  331. }
  332. // set the new RTCP control timeout value
  333. if (dwTimeOut == RRCM_CTRL_RTCP)
  334. pSSRC->dwSSRCStatus &= ~RTCP_XMT_USER_CTRL;
  335. else if (dwTimeOut & RTCP_ONE_SEND_ONLY)
  336. {
  337. pSSRC->dwNextReportSendTime = RTCP_TIMEOUT_WITHIN_RANGE;
  338. // report are then turned off
  339. pSSRC->dwUserXmtTimeoutCtrl = RTCP_XMT_OFF;
  340. // signal the thread to terminate
  341. SetEvent (pRTCPContext->hRtcpRptRequestEvent);
  342. }
  343. else
  344. {
  345. if (dwTimeOut < RTCP_XMT_MINTIME)
  346. dwTimeOut = RTCP_XMT_MINTIME;
  347. pSSRC->dwUserXmtTimeoutCtrl = dwTimeOut;
  348. pSSRC->dwSSRCStatus |= RTCP_XMT_USER_CTRL;
  349. }
  350. IN_OUT_STR ("RTCP : Exit RTCPSendSessionCtrl()\n");
  351. return dwStatus;
  352. }
  353. // [EOF]