不同的转发类型定义如下

对于IPV4

实现转发的类RTPUDPv4Transmitter

对于IPV6

实现转发的类RTPUDPv6Transmitter

对于TCP转发

实现转发的类RTPTCPTransmitter


RTPSession::SendPacket构建RTP数据发送

/** Sends the RTP packet with payload \c data which has length \c len.
	 *  Sends the RTP packet with payload \c data which has length \c len.
	 *  The used payload type, marker and timestamp increment will be those that have been set 
	 *  using the \c SetDefault member functions.
	 */
	int SendPacket(const void *data,size_t len);

	/** Sends the RTP packet with payload \c data which has length \c len.
	 *  It will use payload type \c pt, marker \c mark and after the packet has been built, the 
	 *  timestamp will be incremented by \c timestampinc.
	 */
	int SendPacket(const void *data,size_t len,
	                uint8_t pt,bool mark,uint32_t timestampinc);

RTP数据的构建
int RTPPacket::BuildPacket(uint8_t payloadtype,const void *payloaddata,size_t payloadlen,uint16_t seqnr,
		  uint32_t timestamp,uint32_t ssrc,bool gotmarker,uint8_t numcsrcs,const uint32_t *csrcs,
		  bool gotextension,uint16_t extensionid,uint16_t extensionlen_numwords,const void *extensiondata,
		  void *buffer,size_t maxsize)
{
	if (numcsrcs > RTP_MAXCSRCS)
		return ERR_RTP_PACKET_TOOMANYCSRCS;

	if (payloadtype > 127) // high bit should not be used
		return ERR_RTP_PACKET_BADPAYLOADTYPE;
	if (payloadtype == 72 || payloadtype == 73) // could cause confusion with rtcp types
		return ERR_RTP_PACKET_BADPAYLOADTYPE;
	
	packetlength = sizeof(RTPHeader);
	packetlength += sizeof(uint32_t)*((size_t)numcsrcs);
	if (gotextension)
	{
		packetlength += sizeof(RTPExtensionHeader);
		packetlength += sizeof(uint32_t)*((size_t)extensionlen_numwords);
	}
	packetlength += payloadlen;

	if (maxsize > 0 && packetlength > maxsize)
	{
		packetlength = 0;
		return ERR_RTP_PACKET_DATAEXCEEDSMAXSIZE;
	}

	// Ok, now we'll just fill in...
	
	RTPHeader *rtphdr;
	
	if (buffer == 0)
	{
		packet = RTPNew(GetMemoryManager(),RTPMEM_TYPE_BUFFER_RTPPACKET) uint8_t [packetlength];
		if (packet == 0)
		{
			packetlength = 0;
			return ERR_RTP_OUTOFMEM;
		}
		externalbuffer = false;
	}
	else
	{
		packet = (uint8_t *)buffer;
		externalbuffer = true;
	}
	
	RTPPacket::hasmarker = gotmarker;
	RTPPacket::hasextension = gotextension;
	RTPPacket::numcsrcs = numcsrcs;
	RTPPacket::payloadtype = payloadtype;
	RTPPacket::extseqnr = (uint32_t)seqnr;
	RTPPacket::timestamp = timestamp;
	RTPPacket::ssrc = ssrc;
	RTPPacket::payloadlength = payloadlen;
	RTPPacket::extid = extensionid;
	RTPPacket::extensionlength = ((size_t)extensionlen_numwords)*sizeof(uint32_t);
	
	rtphdr = (RTPHeader *)packet;
	rtphdr->version = RTP_VERSION;
	rtphdr->padding = 0;
	if (gotmarker)
		rtphdr->marker = 1;
	else
		rtphdr->marker = 0;
	if (gotextension)
		rtphdr->extension = 1;
	else
		rtphdr->extension = 0;
	rtphdr->csrccount = numcsrcs;
	rtphdr->payloadtype = payloadtype&127; // make sure high bit isn't set
	rtphdr->sequencenumber = htons(seqnr);
	rtphdr->timestamp = htonl(timestamp);
	rtphdr->ssrc = htonl(ssrc);
	
	uint32_t *curcsrc;
	int i;

	curcsrc = (uint32_t *)(packet+sizeof(RTPHeader));
	for (i = 0 ; i < numcsrcs ; i++,curcsrc++)
		*curcsrc = htonl(csrcs[i]);

	payload = packet+sizeof(RTPHeader)+((size_t)numcsrcs)*sizeof(uint32_t); 
	if (gotextension)
	{
		RTPExtensionHeader *rtpexthdr = (RTPExtensionHeader *)payload;

		rtpexthdr->extid = htons(extensionid);
		rtpexthdr->length = htons((uint16_t)extensionlen_numwords);
		
		payload += sizeof(RTPExtensionHeader);
		memcpy(payload,extensiondata,RTPPacket::extensionlength);
		
		payload += RTPPacket::extensionlength;
	}
	memcpy(payload,payloaddata,payloadlen);
	return 0;
}

当RTP会话成功建立起来之后,接下来就可以开始进行流媒体数据的实时传输了。

首先需要设置好数据发送的目标地址,RTP协议允许同一会话存在多个目标地址,这可以通过调用RTPSession类的AddDestination()、DeleteDestination()和ClearDestinations()方法来完成。目标地址全部指定之后,接着就可以调用RTPSession类的SendPacket()方法,向所有的目标地址发送流媒体数据。

SendPacket()最典型的用法是类似于下面的语句,其中第一个参数是要被发送的数据,而第二个参数则指明将要发送数据的长度,再往后依次是RTP负载类型、标识和时戳增量。 sess.SendPacket(buffer, 5, 0, false, 10); 对于同一个RTP会话来讲,负载类型、标识和时戳增量通常来讲都是相同的,JRTPLIB允许将它们设置为会话的默认参数,这是通过调用 RTPSession类的SetDefaultPayloadType()、SetDefaultMark()和 SetDefaultTimeStampIncrement()方法来完成的。为RTP会话设置这些默认参数的好处是可以简化数据的发送,

例如,如果为 RTP会话设置了默认参数: sess.SetDefaultPayloadType(0); sess.SetDefaultMark(false); sess.SetDefaultTimeStampIncrement(10); 之后在进行数据发送时只需指明要发送的数据及其长度就可以了: sess.SendPacket(buffer, 5);

RTPSession::SendRawData发送RTP数据

int RTPSession::SendRawData(const void *data, size_t len, bool usertpchannel)
{
	if (!created)
		return ERR_RTP_SESSION_NOTCREATED;

	int status;

	if (usertpchannel)
		status = rtptrans->SendRTPData(data, len);
	else
		status = rtptrans->SendRTCPData(data, len);
	return status;
}

SendRawData会调用对应的发送实例,其中usertpchannel用来区分是RTP数据包还是RTCP数据包

RTPUDPv4Transmitter::SendRTPData为例子剖析

int RTPUDPv4Transmitter::SendRTPData(const void *data,size_t len)	
{
	if (!init)
		return ERR_RTP_UDPV4TRANS_NOTINIT;

	MAINMUTEX_LOCK
	
	if (!created)
	{
		MAINMUTEX_UNLOCK
		return ERR_RTP_UDPV4TRANS_NOTCREATED;
	}
	if (len > maxpacksize)
	{
		MAINMUTEX_UNLOCK
		return ERR_RTP_UDPV4TRANS_SPECIFIEDSIZETOOBIG;
	}
  //循环从目的地址中获取每一个要转发的地址,然后
  //将数据包发送出去
	
	destinations.GotoFirstElement();
	while (destinations.HasCurrentElement())
	{
		sendto(rtpsock,(const char *)data,len,0,(const struct sockaddr *)destinations.GetCurrentElement().GetRTPSockAddr(),sizeof(struct sockaddr_in));
		destinations.GotoNextElement();
	}
	
	MAINMUTEX_UNLOCK
	return 0;
}

转发代码

当OnRTPPacket产生回调接收到RTP数据,调用RTPSession::SendRawData(pack->GetPacketData(), pack->GetPacketLength()

true),进行数据转发