不同的转发类型定义如下
对于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),进行数据转发