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.

1040 lines
26 KiB

  1. // RTPSink.cpp : Implementation of CRTPSession
  2. #include "stdafx.h"
  3. #include <qossp.h>
  4. #include "irtp.h"
  5. #include "rtp.h"
  6. #include "RTPSess.h"
  7. //#include "rtpsink.h"
  8. //#include "RTPMS.h"
  9. //#include "RTPSamp.h"
  10. #include "thread.h"
  11. #include <rrcm.h>
  12. #define DEFAULT_RTPBUF_SIZE 1500
  13. #define IPPORT_FIRST_DYNAMIC 49152
  14. #define IPPORT_FIRST_DYNAMIC_END (IPPORT_FIRST_DYNAMIC + 200)
  15. #define IPPORT_FIRST_DYNAMIC_BEGIN (IPPORT_FIRST_DYNAMIC_END + 256)
  16. // Port number allocation starts at IPPORT_FIRST_DYNAMIC_BEGIN.
  17. // Everytime a port number is allocated we decrease g_alport, until
  18. // we reach IPPORT_FIRST_DYNAMIC_END. We then reset it back to its
  19. // original value (IPPORT_FIRST_DYNAMIC_BEGIN) and start this process
  20. // all over again. This way we will avoid reusing the same port
  21. // numbers between sessions.
  22. u_short g_alport = IPPORT_FIRST_DYNAMIC_BEGIN;
  23. void __cdecl RRCMNotification(int,DWORD_PTR,DWORD_PTR,DWORD_PTR);
  24. #define IsMulticast(p) ((p->sin_addr.S_un.S_un_b.s_b1 & 0xF0) == 0xE0)
  25. BOOL CRTP::m_WSInitialized = 0;
  26. STDMETHODIMP CRTP::OpenSession(
  27. UINT sessionId, // client specified unique identifier for the session
  28. DWORD flags, // SESSIONF_SEND, SESSIONF_RECV, SESSIONF_MULTICAST etc.
  29. BYTE *localAddr,
  30. UINT cbAddr,
  31. IRTPSession **ppIRTP) // [output] pointer to RTPSession
  32. {
  33. // the session is named by the sessionId
  34. CRTPSession *pRTPSess ;
  35. HRESULT hr= E_FAIL;
  36. UINT mediaId = flags & (SESSIONF_AUDIO | SESSIONF_VIDEO);
  37. EnterCriticalSection(&g_CritSect);
  38. for (pRTPSess= CRTPSession::m_pSessFirst; pRTPSess; pRTPSess = pRTPSess->m_pSessNext ) {
  39. // check for existing session of the same media type
  40. // if the sessionId is not zero, also check for matching session id
  41. if (sessionId == pRTPSess->m_sessionId)
  42. if (mediaId == pRTPSess->m_mediaId)
  43. break;
  44. // if the local address or remote address is not NULL, search for an exising RTP session bound to
  45. // the same address
  46. // TODO
  47. }
  48. if (!pRTPSess)
  49. {
  50. if (!(flags & SESSIONF_EXISTING)) {
  51. // create the session
  52. ObjRTPSession *pObj;
  53. DEBUGMSG(ZONE_DP,("Creating new RTP session\n"));
  54. hr = ObjRTPSession::CreateInstance(&pObj);
  55. if (hr == S_OK) {
  56. pRTPSess = pObj; // pointer conversion
  57. hr = pRTPSess->Initialize(sessionId, mediaId,localAddr,cbAddr);
  58. if (hr != S_OK)
  59. delete pObj;
  60. }
  61. }
  62. else
  63. hr = E_FAIL; // matching session does not exist
  64. } else {
  65. DEBUGMSG(ZONE_DP,("Reusing RTP session\n"));
  66. hr = S_OK;
  67. }
  68. if (hr == S_OK) {
  69. hr = ((IRTPSession *)pRTPSess)->QueryInterface(IID_IRTPSession,(void **) ppIRTP);
  70. }
  71. LeaveCriticalSection(&g_CritSect);
  72. return hr;
  73. }
  74. CRTPSession *CRTPSession::m_pSessFirst = NULL;
  75. /////////////////////////////////////////////////////////////////////////////
  76. // CRTPSession
  77. CRTPSession::CRTPSession()
  78. : m_hRTPSession(NULL), m_uMaxPacketSize(1500),m_nBufsPosted(0),m_pRTPCallback(NULL),
  79. m_fSendingSync(FALSE)
  80. {
  81. ZeroMemory(&m_sOverlapped,sizeof(m_sOverlapped));
  82. ZeroMemory(&m_ss, sizeof(m_ss));
  83. ZeroMemory(&m_rs, sizeof(m_rs));
  84. m_sOverlapped.hEvent = (WSAEVENT)this;
  85. }
  86. /*
  87. HRESULT CRTPSession::GetLocalAddress(
  88. unsigned char *sockaddr,
  89. UINT *paddrlen)
  90. {
  91. if (m_pRTPSess && *paddrlen >= sizeof(SOCKADDR_IN))
  92. {
  93. *paddrlen = sizeof(SOCKADDR_IN);
  94. CopyMemory(sockaddr, m_pRTPSess->GetLocalAddress(), *paddrlen);
  95. }
  96. }
  97. */
  98. HRESULT
  99. CRTPSession::FinalRelease()
  100. {
  101. CRTPPacket1 *pRTPPacket;
  102. // remove myself from the session list
  103. EnterCriticalSection(&g_CritSect);
  104. if (m_pSessFirst == this)
  105. m_pSessFirst = m_pSessNext;
  106. else {
  107. CRTPSession *pRTPSess = m_pSessFirst;
  108. while (pRTPSess && pRTPSess->m_pSessNext != this) {
  109. pRTPSess = pRTPSess->m_pSessNext;
  110. }
  111. if (pRTPSess)
  112. pRTPSess->m_pSessNext = m_pSessNext;
  113. }
  114. LeaveCriticalSection(&g_CritSect);
  115. if (m_rtpsock) {
  116. delete m_rtpsock;
  117. m_rtpsock = NULL;
  118. }
  119. // BUGBUG: in case the buffers have not been canceled yet (an error case),
  120. // they should complete now with WSA_OPERATION_ABORTED
  121. // or WSAEINTR. This happens in the context of the RecvThread
  122. if (m_nBufsPosted != 0)
  123. Sleep(500); // time for APCs to be processed in RecvThread
  124. // close the RTP session. Also ask RRCM to close the rtcp socket if its WS2
  125. // because that is a more reliable way of cleaning up overlapped recvs than
  126. // sending loopback packets.
  127. CloseRTPSession (m_hRTPSession, NULL, TRUE );
  128. if (m_rtcpsock) {
  129. delete m_rtcpsock;
  130. m_rtcpsock = NULL;
  131. }
  132. m_hRTPSession = 0;
  133. // free receive buffers
  134. while (m_FreePkts.Get(&pRTPPacket))
  135. {
  136. delete pRTPPacket;
  137. }
  138. return S_OK;
  139. }
  140. HRESULT CRTPSession::CreateRecvRTPStream(DWORD ssrc, IRTPRecv **ppIRTPRecv)
  141. {
  142. HRESULT hr;
  143. Lock();
  144. if (ssrc != 0)
  145. return E_NOTIMPL;
  146. #if 0
  147. ObjRTPRecvSource *pRecvS;
  148. hr = ObjRTPMediaStream::CreateInstance(&pMS);
  149. if (SUCCEEDED(hr))
  150. {
  151. pMS->AddRef();
  152. pMS->Init(this, m_mediaId);
  153. hr = pMS->QueryInterface(IID_IRTPMediaStream, (void**)ppIRTPMediaStream);
  154. pMS->Release();
  155. }
  156. #else
  157. *ppIRTPRecv = this;
  158. (*ppIRTPRecv)->AddRef();
  159. hr = S_OK;
  160. #endif
  161. Unlock();
  162. return hr;
  163. }
  164. ULONG GetRandom()
  165. {
  166. return GetTickCount();
  167. }
  168. HRESULT CRTPSession::Initialize(UINT sessionId, UINT mediaId, BYTE *pLocalAddr, UINT cbAddr)
  169. {
  170. DWORD APIstatus;
  171. HRESULT hr = E_OUTOFMEMORY;
  172. char tmpBfr[MAX_COMPUTERNAME_LENGTH + 1];
  173. DWORD tmpBfrLen = sizeof(tmpBfr);
  174. SDES_DATA sdesInfo[3];
  175. ENCRYPT_INFO encryptInfo;
  176. SOCKADDR_IN *pSockAddr;
  177. m_sessionId = sessionId;
  178. m_mediaId = mediaId;
  179. m_rtpsock = new UDPSOCKET();
  180. m_rtcpsock = new UDPSOCKET();
  181. if (!m_rtpsock || !m_rtcpsock)
  182. goto ERROR_EXIT;
  183. if(!m_rtpsock->NewSock() || !m_rtcpsock->NewSock())
  184. {
  185. goto ERROR_EXIT;
  186. }
  187. // if the local address is specified do a bind on the sockets
  188. if (pLocalAddr) {
  189. // setup both channels for the current local address
  190. hr = SetLocalAddress(pLocalAddr,cbAddr);
  191. if (hr != S_OK)
  192. goto ERROR_EXIT;
  193. }
  194. /*
  195. // if the remote address is specified make a note of it
  196. SetRemoteAddresses(pChanDesc->pRemoteAddr, pChanDesc->pRemoteRTCPAddr);
  197. */
  198. // init send state
  199. memset (&m_ss.sendStats,0,sizeof(m_ss.sendStats));
  200. // init RTP send header
  201. // time stamp and marker bit have to specified per packet
  202. m_ss.hdr.p = 0; // no padding needed
  203. m_ss.hdr.x = 0; // no extensions
  204. m_ss.hdr.cc = 0; // no contributing sources
  205. m_ss.hdr.seq = (WORD)GetRandom();
  206. m_clockRate = (m_mediaId == SESSIONF_VIDEO ? 90000 : 8000); // typically 8KHz for audio
  207. m_ss.hdr.pt = 0;
  208. // Initialize list of overlapped structs
  209. // build a Cname
  210. memcpy(tmpBfr,"CName",6);
  211. GetComputerName(tmpBfr,&tmpBfrLen);
  212. // build the SDES information
  213. sdesInfo[0].dwSdesType = 1;
  214. memcpy (sdesInfo[0].sdesBfr, tmpBfr, strlen(tmpBfr)+1);
  215. sdesInfo[0].dwSdesLength = strlen(sdesInfo[0].sdesBfr);
  216. sdesInfo[0].dwSdesFrequency = 100;
  217. sdesInfo[0].dwSdesEncrypted = 0;
  218. // Build a Name
  219. tmpBfrLen = sizeof(tmpBfr);
  220. memcpy(tmpBfr,"UserName",9);
  221. GetUserName(tmpBfr,&tmpBfrLen);
  222. sdesInfo[1].dwSdesType = 2;
  223. memcpy (sdesInfo[1].sdesBfr, tmpBfr, strlen(tmpBfr)+1);
  224. sdesInfo[1].dwSdesLength = strlen(sdesInfo[1].sdesBfr);
  225. sdesInfo[1].dwSdesFrequency = 25;
  226. sdesInfo[1].dwSdesEncrypted = 0;
  227. // end of SDES list
  228. sdesInfo[2].dwSdesType = 0;
  229. pSockAddr = m_rtcpsock->GetRemoteAddress();
  230. #ifdef DEBUG
  231. if (pSockAddr->sin_addr.s_addr == INADDR_ANY)
  232. DEBUGMSG(ZONE_DP,("Null dest RTCP addr\n"));
  233. #endif
  234. // Create the RTP/RTCP session
  235. m_hRTPSession = CreateRTPSession(
  236. (m_rtpsock->GetSock()),
  237. (m_rtcpsock->GetSock()),
  238. (LPVOID)pSockAddr,
  239. (pSockAddr->sin_addr.s_addr == INADDR_ANY)? 0 : sizeof(SOCKADDR_IN),
  240. sdesInfo,
  241. (DWORD)m_clockRate,
  242. &encryptInfo,
  243. 0,
  244. (PRRCM_EVENT_CALLBACK)RRCMNotification, // callback function
  245. (DWORD_PTR) this, // callback info
  246. RTCP_ON|H323_CONFERENCE,
  247. 0, //rtp session bandwidth
  248. &APIstatus);
  249. if (m_hRTPSession == NULL)
  250. {
  251. DEBUGMSG(ZONE_DP,("Couldnt create RRCM session\n"));
  252. hr = GetLastError();
  253. goto ERROR_EXIT;
  254. }
  255. m_Qos.SendingFlowspec.ServiceType = SERVICETYPE_NOTRAFFIC;
  256. m_Qos.SendingFlowspec.TokenRate = QOS_NOT_SPECIFIED;
  257. m_Qos.SendingFlowspec.TokenBucketSize = QOS_NOT_SPECIFIED;
  258. m_Qos.SendingFlowspec.PeakBandwidth = QOS_NOT_SPECIFIED;
  259. m_Qos.SendingFlowspec.Latency = QOS_NOT_SPECIFIED;
  260. m_Qos.SendingFlowspec.DelayVariation = QOS_NOT_SPECIFIED;
  261. m_Qos.SendingFlowspec.MaxSduSize = QOS_NOT_SPECIFIED;
  262. m_Qos.ReceivingFlowspec = m_Qos.SendingFlowspec;
  263. m_Qos.ProviderSpecific.buf = NULL;
  264. m_Qos.ProviderSpecific.len = 0;
  265. // insert RTPSession in global list
  266. m_pSessNext = m_pSessFirst;
  267. m_pSessFirst = this;
  268. return S_OK;
  269. ERROR_EXIT:
  270. if (m_rtpsock)
  271. {
  272. delete m_rtpsock;
  273. m_rtpsock = NULL;
  274. }
  275. if (m_rtcpsock)
  276. {
  277. delete m_rtcpsock;
  278. m_rtcpsock = NULL;
  279. }
  280. return hr;
  281. }
  282. BOOL CRTPSession::SelectPorts()
  283. {
  284. // try port pairs in the dynamic range ( > 49152)
  285. if (g_alport <= IPPORT_FIRST_DYNAMIC_END)
  286. g_alport = IPPORT_FIRST_DYNAMIC_BEGIN;
  287. for (;g_alport >= IPPORT_FIRST_DYNAMIC;)
  288. {
  289. m_rtpsock->SetLocalPort(g_alport);
  290. if (m_rtpsock->BindMe() == 0)
  291. {
  292. /* it worked for the data, try the adjacent port for control*/
  293. ++g_alport;
  294. m_rtcpsock->SetLocalPort(g_alport);
  295. if (m_rtcpsock->BindMe() == 0)
  296. {
  297. g_alport-=3;
  298. return TRUE;
  299. }
  300. else // start over at the previous even numbered port
  301. {
  302. if( WSAGetLastError() != WSAEADDRINUSE)
  303. {
  304. DEBUGMSG(ZONE_DP,("ObjRTPSession::SelectPorts failed with error %d\n",WSAGetLastError()));
  305. goto ERROR_EXIT;
  306. }
  307. m_rtpsock->Cleanup();
  308. if(!m_rtpsock->NewSock())
  309. {
  310. ASSERT(0);
  311. return FALSE;
  312. }
  313. g_alport-=3;
  314. continue;
  315. }
  316. }
  317. if (WSAGetLastError() != WSAEADDRINUSE)
  318. {
  319. DEBUGMSG(ZONE_DP,("ObjRTPSession::SelectPorts failed with error %d\n",WSAGetLastError()));
  320. goto ERROR_EXIT;
  321. }
  322. g_alport-=2; // try the next lower even numbered port
  323. }
  324. ERROR_EXIT:
  325. m_rtcpsock->SetLocalPort(0);
  326. m_rtpsock->SetLocalPort(0);
  327. return FALSE;
  328. }
  329. STDMETHODIMP CRTPSession::SetLocalAddress(BYTE *pbAddr, UINT cbAddr)
  330. {
  331. HRESULT hr;
  332. SOCKADDR_IN *pAddr = (SOCKADDR_IN *)pbAddr;
  333. ASSERT(pbAddr);
  334. Lock();
  335. if ( IsMulticast(pAddr))
  336. hr = SetMulticastAddress(pAddr);
  337. else
  338. if (m_rtpsock->GetLocalAddress()->sin_port != 0)
  339. hr = S_OK; // already bound
  340. else
  341. {
  342. m_rtpsock->SetLocalAddress(pAddr);
  343. m_rtcpsock->SetLocalAddress(pAddr);
  344. if (pAddr->sin_port != 0)
  345. {
  346. // port already chosen
  347. m_rtcpsock->SetLocalPort(ntohs(pAddr->sin_port) + 1);
  348. if (m_rtpsock->BindMe() != 0 || m_rtcpsock->BindMe() != 0)
  349. {
  350. hr = HRESULT_FROM_WIN32(GetLastError());
  351. m_rtpsock->SetLocalPort(0);
  352. m_rtcpsock->SetLocalPort(0);
  353. }
  354. else
  355. hr = S_OK;
  356. }
  357. else
  358. {
  359. // client wants us to choose the port
  360. if (SelectPorts()) {
  361. hr = S_OK;
  362. }
  363. else
  364. hr = HRESULT_FROM_WIN32(GetLastError());
  365. }
  366. }
  367. Unlock();
  368. return hr;
  369. }
  370. HRESULT
  371. CRTPSession::SetMulticastAddress(PSOCKADDR_IN pAddr)
  372. {
  373. SOCKET s ;
  374. SOCKADDR_IN rtcpAddr = *pAddr;
  375. s = RRCMws.WSAJoinLeaf( m_rtpsock->GetSock(), (struct sockaddr *)pAddr, sizeof(SOCKADDR_IN), NULL, NULL, NULL, NULL, JL_BOTH);
  376. if (s == INVALID_SOCKET)
  377. return E_FAIL;
  378. else {
  379. rtcpAddr.sin_port = htons(ntohs(pAddr->sin_port)+1);
  380. s = RRCMws.WSAJoinLeaf( m_rtcpsock->GetSock(), (struct sockaddr *)&rtcpAddr, sizeof(SOCKADDR_IN), NULL, NULL, NULL, NULL, JL_BOTH);
  381. return S_OK;
  382. }
  383. }
  384. STDMETHODIMP
  385. CRTPSession::SetRemoteRTPAddress(BYTE *sockaddr, UINT cbAddr)
  386. {
  387. SOCKADDR_IN *pRTPAddr = (SOCKADDR_IN *)sockaddr;
  388. Lock();
  389. if (pRTPAddr) {
  390. #ifdef DEBUG
  391. if (m_rtpsock->GetRemoteAddress()->sin_addr.s_addr != INADDR_ANY
  392. && m_rtpsock->GetRemoteAddress()->sin_addr.s_addr != pRTPAddr->sin_addr.s_addr) {
  393. DEBUGMSG(ZONE_DP,("Changing RTP Session remote address (already set)!\n"));
  394. }
  395. #endif
  396. m_rtpsock->SetRemoteAddr(pRTPAddr);
  397. }
  398. Unlock();
  399. return S_OK;
  400. }
  401. STDMETHODIMP
  402. CRTPSession::SetRemoteRTCPAddress(BYTE *sockaddr, UINT cbAddr)
  403. {
  404. SOCKADDR_IN *pRTCPAddr = (SOCKADDR_IN *)sockaddr;
  405. Lock();
  406. if (pRTCPAddr) {
  407. #ifdef DEBUG
  408. if (m_rtcpsock->GetRemoteAddress()->sin_addr.s_addr != INADDR_ANY
  409. && m_rtcpsock->GetRemoteAddress()->sin_addr.s_addr != pRTCPAddr->sin_addr.s_addr) {
  410. DEBUGMSG(ZONE_DP,("Changing RTCP Session remote address (already set)!\n"));
  411. }
  412. #endif
  413. m_rtcpsock->SetRemoteAddr(pRTCPAddr);
  414. if (m_hRTPSession)
  415. updateRTCPDestinationAddress( m_hRTPSession,
  416. (SOCKADDR *)m_rtcpsock->GetRemoteAddress(), sizeof(SOCKADDR_IN));
  417. }
  418. Unlock();
  419. return S_OK;
  420. }
  421. STDMETHODIMP
  422. CRTPSession::GetLocalAddress(const BYTE **sockaddr, UINT *pcbAddr)
  423. {
  424. if (sockaddr && pcbAddr)
  425. {
  426. Lock();
  427. *sockaddr = (BYTE *)m_rtpsock->GetLocalAddress();
  428. *pcbAddr = sizeof(SOCKADDR_IN);
  429. Unlock();
  430. return S_OK;
  431. } else
  432. {
  433. return E_INVALIDARG;
  434. }
  435. }
  436. STDMETHODIMP
  437. CRTPSession::GetRemoteRTPAddress(const BYTE **sockaddr, UINT *pcbAddr)
  438. {
  439. if (sockaddr && pcbAddr )
  440. {
  441. Lock();
  442. *sockaddr = (BYTE *)m_rtpsock->GetRemoteAddress();
  443. *pcbAddr = sizeof(SOCKADDR_IN);
  444. Unlock();
  445. return S_OK;
  446. } else
  447. {
  448. return E_INVALIDARG;
  449. }
  450. }
  451. STDMETHODIMP
  452. CRTPSession::GetRemoteRTCPAddress(const BYTE **sockaddr, UINT *pcbAddr)
  453. {
  454. if (sockaddr && pcbAddr)
  455. {
  456. Lock();
  457. *sockaddr = (BYTE *)m_rtcpsock->GetRemoteAddress();
  458. *pcbAddr = sizeof(SOCKADDR_IN);
  459. Unlock();
  460. return S_OK;
  461. } else
  462. {
  463. return E_INVALIDARG;
  464. }
  465. }
  466. STDMETHODIMP
  467. CRTPSession::SetSendFlowspec(FLOWSPEC *pFlowspec)
  468. {
  469. QOS_DESTADDR qosDest;
  470. DWORD cbRet;
  471. int optval = pFlowspec->MaxSduSize;
  472. // Set the RTP socket to not buffer more than one packet
  473. // This will allow us to influence the packet scheduling.
  474. if(RRCMws.setsockopt(m_rtpsock->GetSock(),SOL_SOCKET, SO_SNDBUF,(char *)&optval,sizeof(optval)) != 0)
  475. {
  476. RRCM_DBG_MSG ("setsockopt failed ", GetLastError(),
  477. __FILE__, __LINE__, DBG_ERROR);
  478. }
  479. if (WSQOSEnabled && m_rtpsock)
  480. {
  481. m_Qos.SendingFlowspec = *pFlowspec;
  482. m_Qos.ProviderSpecific.buf = (char *)&qosDest; // NULL
  483. m_Qos.ProviderSpecific.len = sizeof (qosDest); // 0
  484. // check to see if the receive flowspec has already been
  485. // set. If it has, specify NOCHANGE for the receive service
  486. // type. If not, specify NOTRAFFIC. This is done to circumvent
  487. // a bug in the Win98 QOS/RSVP layer.
  488. if (m_Qos.ReceivingFlowspec.TokenRate == QOS_NOT_SPECIFIED)
  489. {
  490. m_Qos.ReceivingFlowspec.ServiceType = SERVICETYPE_NOTRAFFIC;
  491. }
  492. else
  493. {
  494. m_Qos.ReceivingFlowspec.ServiceType = SERVICETYPE_NOCHANGE;
  495. }
  496. qosDest.ObjectHdr.ObjectType = QOS_OBJECT_DESTADDR;
  497. qosDest.ObjectHdr.ObjectLength = sizeof(qosDest);
  498. qosDest.SocketAddress = (PSOCKADDR)m_rtpsock->GetRemoteAddress();
  499. qosDest.SocketAddressLength = sizeof(SOCKADDR_IN);
  500. if (RRCMws.WSAIoctl(m_rtpsock->GetSock(),SIO_SET_QOS, &m_Qos, sizeof(m_Qos), NULL, 0, &cbRet, NULL,NULL) == 0)
  501. return S_OK;
  502. else
  503. return GetLastError();
  504. } else
  505. return E_NOTIMPL;
  506. }
  507. STDMETHODIMP
  508. CRTPSession::SetRecvFlowspec(FLOWSPEC *pFlowspec)
  509. {
  510. SOCKADDR_IN *pAddr = NULL;
  511. DWORD cbRet;
  512. if (WSQOSEnabled && m_rtpsock)
  513. {
  514. pAddr = m_rtpsock->GetRemoteAddress();
  515. m_Qos.ReceivingFlowspec = *pFlowspec;
  516. m_Qos.ProviderSpecific.buf = NULL;
  517. m_Qos.ProviderSpecific.len = 0;
  518. // check to see if the send flowspec has already been
  519. // set. If it has, specify NOCHANGE for the receive service
  520. // type. If not, specify NOTRAFFIC. This is done to circumvent
  521. // a bug in the Win98 QOS/RSVP layer.
  522. if (m_Qos.SendingFlowspec.TokenRate == QOS_NOT_SPECIFIED)
  523. {
  524. m_Qos.SendingFlowspec.ServiceType = SERVICETYPE_NOTRAFFIC;
  525. }
  526. else
  527. {
  528. m_Qos.SendingFlowspec.ServiceType = SERVICETYPE_NOCHANGE;
  529. }
  530. if (RRCMws.WSAIoctl(m_rtpsock->GetSock(),SIO_SET_QOS, &m_Qos, sizeof(m_Qos), NULL, 0, &cbRet, NULL,NULL) == 0)
  531. return S_OK;
  532. else
  533. return GetLastError();
  534. } else
  535. return E_NOTIMPL;
  536. }
  537. // set the size used for receive packet buffers
  538. STDMETHODIMP
  539. CRTPSession::SetMaxPacketSize(UINT maxPacketSize)
  540. {
  541. m_uMaxPacketSize = maxPacketSize;
  542. return S_OK;
  543. }
  544. HRESULT CRTPSession::SetRecvNotification(
  545. PRTPRECVCALLBACK pRTPRecvCB, // pointer to callback function
  546. DWORD_PTR dwCB, // callback arg
  547. UINT nBufs // suggested number of receives to post
  548. )
  549. {
  550. CRTPPacket1 *pRTPPacket;
  551. if (!m_hRTPSession)
  552. return E_FAIL;
  553. m_pRTPCallback = pRTPRecvCB;
  554. m_dwCallback = dwCB;
  555. if (m_nBufsPosted >= nBufs)
  556. return S_OK; // packets already posted
  557. int nBufsToAllocate = nBufs - m_nBufsPosted - m_FreePkts.GetCount();
  558. // allocate packets if necessary
  559. while (nBufsToAllocate-- > 0)
  560. {
  561. if (pRTPPacket = new CRTPPacket1) {
  562. if (!SUCCEEDED(pRTPPacket->Init(m_uMaxPacketSize)))
  563. {
  564. delete pRTPPacket;
  565. break;
  566. }
  567. m_FreePkts.Put(pRTPPacket);
  568. }
  569. else
  570. break;
  571. }
  572. PostRecv();
  573. return m_nBufsPosted ? S_OK : E_OUTOFMEMORY;
  574. }
  575. HRESULT
  576. CRTPSession::CancelRecvNotification()
  577. {
  578. m_pRTPCallback = NULL;
  579. if (m_rtpsock) {
  580. struct sockaddr myaddr;
  581. int myaddrlen = sizeof(myaddr);
  582. UINT i;
  583. char buf = 0;
  584. WSABUF wsabuf;
  585. DWORD bytesSent;
  586. UINT nBufsPosted;
  587. wsabuf.buf = &buf;
  588. wsabuf.len = 0;
  589. BOOL fCanceled = FALSE;
  590. if (RRCMws.getsockname(m_rtpsock->GetSock(),&myaddr,&myaddrlen)== 0) {
  591. // send loopback packets (as many as there are recvs outstanding)
  592. // on this socket to get back our buffers.
  593. // NOTE: Winsock 2 on Win95 seems to have a bug where we get recv callbacks
  594. // within sendto() rather than in the subsequent SleepEx, so we
  595. // have to make a local copy of m_nBufsPosted
  596. for (i=0, nBufsPosted = m_nBufsPosted;i < nBufsPosted;i++) {
  597. if (RRCMws.sendTo(m_rtpsock->GetSock(),&wsabuf,1,&bytesSent,0,&myaddr, myaddrlen, NULL, NULL) < 0) {
  598. DEBUGMSG(ZONE_DP,("CancelRecv: loopback send failed\n"));
  599. break;
  600. }
  601. }
  602. fCanceled = (i > 0);
  603. } else {
  604. DEBUGMSG(ZONE_DP,("RTPState::CancelRecv: getsockname returned %d\n",GetLastError()));
  605. }
  606. if (fCanceled)
  607. while (m_nBufsPosted) {
  608. DWORD dwStatus;
  609. dwStatus = SleepEx(200,TRUE);
  610. ASSERT(dwStatus==WAIT_IO_COMPLETION);
  611. if (dwStatus !=WAIT_IO_COMPLETION)
  612. break; // timed out => bail
  613. }
  614. }
  615. return S_OK;
  616. }
  617. HRESULT
  618. CRTPSession::PostRecv()
  619. {
  620. HRESULT hr;
  621. DWORD dwError = 0;
  622. DWORD dwRcvFlag;
  623. WSAOVERLAPPED *pOverlapped;
  624. DWORD nBytesRcvd;
  625. CRTPPacket1 *pRTPPacket;
  626. if (!m_hRTPSession || !m_pRTPCallback)
  627. return E_FAIL;
  628. // post buffers in the free queue
  629. while (m_FreePkts.Get(&pRTPPacket))
  630. {
  631. pOverlapped = (WSAOVERLAPPED *)(pRTPPacket->GetOverlapped());
  632. pOverlapped->hEvent = (WSAEVENT) this;
  633. m_rcvSockAddrLen = sizeof(SOCKADDR);
  634. dwRcvFlag = 0;
  635. pRTPPacket->RestoreSize();
  636. dwError = RRCMws.recvFrom (m_rtpsock->GetSock(),
  637. pRTPPacket->GetWSABUF(),
  638. 1,
  639. &nBytesRcvd,
  640. &dwRcvFlag,
  641. &m_rcvSockAddr,
  642. &m_rcvSockAddrLen,
  643. pOverlapped,
  644. (LPWSAOVERLAPPED_COMPLETION_ROUTINE)WS2RecvCB);
  645. if (dwError == SOCKET_ERROR) {
  646. dwError = WSAGetLastError();
  647. if (dwError != WSA_IO_PENDING) {
  648. DEBUGMSG(ZONE_DP,("RTP recv error %d\n",dwError));
  649. // m_rs.rcvStats.packetErrors++;
  650. // return the buffer to the free list
  651. m_FreePkts.Put(pRTPPacket);
  652. break;
  653. }
  654. }
  655. ++m_nBufsPosted;
  656. }
  657. return m_nBufsPosted ? S_OK : S_FALSE;
  658. }
  659. HRESULT
  660. CRTPSession::FreePacket(WSABUF *pBuf)
  661. {
  662. m_FreePkts.Put(CRTPPacket1::GetRTPPacketFromWSABUF(pBuf));
  663. PostRecv();
  664. return S_OK;
  665. }
  666. /*----------------------------------------------------------------------------
  667. * Function: WS2SendCB
  668. * Description: Winsock callback provided by the application to Winsock
  669. *
  670. * Input:
  671. *
  672. * Return: None
  673. *--------------------------------------------------------------------------*/
  674. void CALLBACK WS2SendCB (DWORD dwError,
  675. DWORD cbTransferred,
  676. LPWSAOVERLAPPED lpOverlapped,
  677. DWORD dwFlags)
  678. {
  679. CRTPSession *pSess;
  680. //get the RTPSession pointer so that we can mark the
  681. //IO complete on the object
  682. pSess= (CRTPSession *)lpOverlapped->hEvent;
  683. ASSERT (&pSess->m_sOverlapped == lpOverlapped);
  684. pSess->m_lastSendError = dwError;
  685. pSess->m_fSendingSync=FALSE;
  686. }
  687. void CALLBACK WS2RecvCB (DWORD dwError,
  688. DWORD len,
  689. LPWSAOVERLAPPED lpOverlapped,
  690. DWORD dwFlags)
  691. {
  692. CRTPSession *pRTP;
  693. CRTPPacket1 *pRTPPacket;
  694. DWORD ts, ssrc;
  695. // GEORGEJ: catch Winsock 2 bug (94903) where I get a bogus callback
  696. // after WSARecv returns WSAEMSGSIZE.
  697. if (!dwError && ((int) len < 0)) {
  698. RRCM_DBG_MSG ("RTP : RCV Callback : bad cbTransferred", len,
  699. __FILE__, __LINE__, DBG_ERROR);
  700. return;
  701. }
  702. pRTP = (CRTPSession *)lpOverlapped->hEvent; // cached by PostRecv
  703. ASSERT(pRTP);
  704. ASSERT(lpOverlapped);
  705. ASSERT(pRTP->m_nBufsPosted > 0);
  706. --pRTP->m_nBufsPosted; // one recv just completed
  707. // Winsock 2 sometimes chooses to indicate a buffer-too-small
  708. // error via the dwFlags parameter.
  709. if (dwFlags & MSG_PARTIAL)
  710. dwError = WSAEMSGSIZE;
  711. pRTPPacket = CRTPPacket1::GetRTPPacketFromOverlapped(lpOverlapped);
  712. if (!dwError)
  713. {
  714. // validate RTP header and update receive stats
  715. dwError = RTPReceiveCheck(
  716. pRTP->m_hRTPSession,
  717. pRTP->m_rtpsock->GetSock(),
  718. pRTPPacket->GetWSABUF()->buf,
  719. len,
  720. &pRTP->m_rcvSockAddr,
  721. pRTP->m_rcvSockAddrLen
  722. );
  723. }
  724. if (!pRTP->m_pRTPCallback)
  725. {
  726. // we have stopped doing notifications
  727. // return the buffer to the free list
  728. pRTP->FreePacket(pRTPPacket->GetWSABUF());
  729. }
  730. else if (!dwError) {
  731. // call the callback
  732. //++pRTP->m_nBufsRecvd;
  733. // convert the RTP header fields to host order
  734. pRTPPacket->SetTimestamp(ntohl(pRTPPacket->GetTimestamp()));
  735. pRTPPacket->SetSeq(ntohs(( u_short)pRTPPacket->GetSeq()));
  736. pRTPPacket->SetActual(len);
  737. //LOG((LOGMSG_NET_RECVD,pRTPPacket->GetTimestamp(), pRTPPacket->GetSeq(), GetTickCount()));
  738. if (!pRTP->m_pRTPCallback(pRTP->m_dwCallback, pRTPPacket->GetWSABUF()))
  739. pRTP->FreePacket(pRTPPacket->GetWSABUF());
  740. } else {
  741. // packet error
  742. // repost the buffer
  743. pRTP->PostRecv();
  744. }
  745. }
  746. // the way its defined now, this Send() method is synchronous or asynchronous
  747. // depending on whether pOverlapped is NULL or not
  748. HRESULT CRTPSession::Send(
  749. WSABUF *pWsabufs,
  750. UINT nWsabufs,
  751. WSAOVERLAPPED *pOverlapped,
  752. LPWSAOVERLAPPED_COMPLETION_ROUTINE pWSAPC )
  753. {
  754. DWORD dwError;
  755. Lock();
  756. RTP_HDR_T *pHdr = (RTP_HDR_T *)pWsabufs[0].buf;
  757. // convert RTP header fields to network-order
  758. pHdr->ts = htonl (pHdr->ts);
  759. pHdr->seq = htons(pHdr->seq);
  760. //*pHdr = m_ss.hdr;
  761. pHdr->seq = htons(++m_ss.hdr.seq);
  762. // update send stats
  763. //m_ss.packetsSent++;
  764. //m_ss.bytesSent += cbBuf-sizeof(RTP_HDR_MIN_LEN);
  765. //bIOPending=TRUE; // reset when send completes
  766. dwError = RTPSendTo (
  767. m_hRTPSession,
  768. (m_rtpsock->GetSock()),
  769. pWsabufs,
  770. nWsabufs,
  771. &m_numBytesSend,
  772. 0,
  773. (LPVOID)m_rtpsock->GetRemoteAddress(),
  774. sizeof(SOCKADDR),
  775. pOverlapped,
  776. pWSAPC);
  777. if (dwError == SOCKET_ERROR) {
  778. dwError = WSAGetLastError();
  779. if (dwError != WSA_IO_PENDING) {
  780. DEBUGMSG(1, ("RTPSendTo error %d\n",dwError));
  781. m_lastSendError = dwError;
  782. m_ss.sendStats.packetErrors++;
  783. m_fSendingSync = FALSE;
  784. goto ErrorExit;
  785. }
  786. dwError = 0; // return success for ERROR_IO_PENDING
  787. }
  788. ErrorExit:
  789. Unlock();
  790. return dwError;
  791. }
  792. void CRTPSession::RTCPNotify(
  793. int rrcmEvent,
  794. DWORD_PTR dwSSRC,
  795. DWORD_PTR rtcpsock)
  796. {
  797. switch (rrcmEvent) {
  798. case RRCM_RECV_RTCP_SNDR_REPORT_EVENT:
  799. GetRTCPReport();
  800. //DispRTCPReport(rtcpsock);
  801. break;
  802. case RRCM_RECV_RTCP_RECV_REPORT_EVENT:
  803. GetRTCPReport();
  804. break;
  805. case RRCM_NEW_SOURCE_EVENT:
  806. RRCM_DBG_MSG ("RTP : New SSRC", 0,
  807. __FILE__, __LINE__, DBG_TRACE);
  808. break;
  809. default:
  810. RRCM_DBG_MSG ("RTP : RRCMNotification", rrcmEvent,
  811. __FILE__, __LINE__, DBG_TRACE);
  812. break;
  813. }
  814. }
  815. void RRCMNotification(
  816. // RRCM_EVENT_T rrcmEvent,
  817. int rrcmEvent,
  818. DWORD_PTR dwSSRC,
  819. DWORD_PTR rtcpsock,
  820. DWORD_PTR dwUser)
  821. {
  822. if (dwUser)
  823. ((CRTPSession *)dwUser)->RTCPNotify(rrcmEvent,dwSSRC,rtcpsock);
  824. }
  825. // Get the useful fields from the RTCP report and store them
  826. // Only works for unicast sessions now (one sender, one receiver)
  827. BOOL CRTPSession::GetRTCPReport()
  828. {
  829. #define MAX_RTCP_REPORT 2
  830. RTCP_REPORT rtcpReport[MAX_RTCP_REPORT];
  831. DWORD moreEntries = 0;
  832. DWORD numEntry = 0;
  833. DWORD i;
  834. ZeroMemory(rtcpReport,sizeof(rtcpReport));
  835. // Get latest RTCP report
  836. // for all SSRCs in this session
  837. if (RTCPReportRequest ( m_rtcpsock->GetSock(),
  838. 0, &numEntry,
  839. &moreEntries, MAX_RTCP_REPORT,
  840. rtcpReport,
  841. 0,NULL,0))
  842. return FALSE;
  843. for (i = 0; i < numEntry; i++)
  844. {
  845. if (rtcpReport[i].status & LOCAL_SSRC_RPT)
  846. {
  847. m_ss.sendStats.ssrc = rtcpReport[i].ssrc;
  848. m_ss.sendStats.packetsSent = rtcpReport[i].dwSrcNumPcktRealTime;
  849. m_ss.sendStats.bytesSent = rtcpReport[i].dwSrcNumByteRealTime;
  850. } else {
  851. m_rs.rcvStats.ssrc = rtcpReport[i].ssrc;
  852. m_rs.rcvStats.packetsSent = rtcpReport[i].dwSrcNumPckt;
  853. m_rs.rcvStats.bytesSent = rtcpReport[i].dwSrcNumByte;
  854. m_rs.rcvStats.packetsLost = rtcpReport[i].SrcNumLost;
  855. m_rs.rcvStats.jitter = rtcpReport[i].SrcJitter;
  856. // Get the SR timestamp information
  857. m_rs.ntpTime = ((NTP_TS)rtcpReport[i].dwSrcNtpMsw << 32) + rtcpReport[i].dwSrcNtpLsw;
  858. m_rs.rtpTime = rtcpReport[i].dwSrcRtpTs;
  859. // check if any feedback information
  860. if (rtcpReport[i].status & FEEDBACK_FOR_LOCAL_SSRC_PRESENT)
  861. {
  862. DWORD prevPacketsLost = m_ss.sendStats.packetsLost;
  863. m_ss.sendStats.packetsLost = rtcpReport[i].feedback.cumNumPcktLost;
  864. /*
  865. if (prevPacketsLost != m_ss.sendStats.packetsLost) {
  866. DEBUGMSG(ZONE_DP,("RTCP: fraction Lost=%d/256 , totalLost =%d, StreamClock=%d\n",rtcpReport[i].feedback.fractionLost,m_ss.sendStats.packetsLost,m_clockRate));
  867. }
  868. */
  869. m_ss.sendStats.jitter = rtcpReport[i].feedback.dwInterJitter;
  870. }
  871. }
  872. }
  873. m_ss.sendStats.packetsDelivered = m_ss.sendStats.packetsSent - m_ss.sendStats.packetsLost;
  874. return TRUE;
  875. }
  876. // CRTPPacket1 methods
  877. HRESULT CRTPPacket1::Init(UINT uMaxPacketSize)
  878. {
  879. m_wsabuf.buf = new char [uMaxPacketSize];
  880. if (!m_wsabuf.buf)
  881. return E_OUTOFMEMORY;
  882. m_wsabuf.len = uMaxPacketSize;
  883. m_cbSize = uMaxPacketSize;
  884. return S_OK;
  885. }
  886. CRTPPacket1::~CRTPPacket1()
  887. {
  888. if (m_wsabuf.buf)
  889. delete [] m_wsabuf.buf;
  890. }
  891.