Darwin流媒体服务器RTP包可以指定通过 RTSP TCP channel进行传输。
1.调用RTPStream::Write发送RTP包时,会判断是否使用TCP的方式进行传输,使用TCP传输时调用InterleavedWrite
if (fTransportType == qtssRTPTransportTypeTCP) // write out in interleave format on the RTSP TCP channel.
err = this->InterleavedWrite(thePacket->packetData, inLen, outLenWritten, fRTPChannel);
else if (fTransportType == qtssRTPTransportTypeReliableUDP)
err = this->ReliableRTPWrite(thePacket->packetData, inLen, theCurrentPacketDelay);
else if (inLen > 0)
{
(void)fSockets->GetSocketA()->SendTo(fRemoteAddr, fRemoteRTPPort, thePacket->packetData, inLen);
this->UDPMonitorWrite(thePacket->packetData, inLen, kIsRTPPacket);
}
2.RTPStream::InterleavedWrite中获取RTPStream所属的RTSPSession,并调用该类提供的InterleavedWrite方法
QTSS_Error RTPStream::InterleavedWrite(void* inBuffer, UInt32 inLen, UInt32* outLenWritten, unsigned char channel)
{
if (fSession->GetRTSPSession() == NULL) // RTSPSession required for interleaved write
{
return EAGAIN;
}
//char blahblah[2048];
QTSS_Error err = fSession->GetRTSPSession()->InterleavedWrite(inBuffer, inLen, outLenWritten, channel);
}
3.RTSPSessionInterface::InterleavedWrite 使用interleaved format进行写入,由于RTSP还要用来发送RTSP请求的响应消息(Pause,Teardown等),因此要区分发送的是RTP包还是RTSP响应消息,区分标识为RTPInterleaveHeader的结构体(4个字节:第一个字节为$,第二个字节为channel,后面两个字节代表RTP的长度),RTP包在通过RTSP发送时需要以$作为开始标识。
RTSPSessionInterface::InterleavedWrite最终调用RTSPResponseStream::WriteV进行写入。
QTSS_Error RTSPSessionInterface::InterleavedWrite(void* inBuffer, UInt32 inLen, UInt32* outLenWritten, unsigned char channel)
{
......
// DMS - this struct should be packed.
//rt todo -- is this struct more portable (byte alignment could be a problem)?
struct RTPInterleaveHeader
{
unsigned char header;
unsigned char channel;
UInt16 len;
};
if (err == QTSS_NoErr)
{
if (inLen > kTCPCoalesceDirectWriteSize)
{
struct RTPInterleaveHeader rih;
// write direct to stream
rih.header = '$';
rih.channel = channel;
rih.len = htons((UInt16)inLen);
iov[1].iov_base = (char*)&rih;
iov[1].iov_len = sizeof(rih);
iov[2].iov_base = (char*)inBuffer;
iov[2].iov_len = inLen;
err = this->GetOutputStream()->WriteV(iov, 3, inLen + sizeof(rih), outLenWritten, RTSPResponseStream::kAllOrNothing);
#if RTSP_SESSION_INTERFACE_DEBUGGING
qtss_printf("InterleavedWrite: bypass %li\n", inLen);
#endif
}
else
{
// coalesce with other small writes
fTCPCoalesceBuffer[fNumInCoalesceBuffer] = '$';
fNumInCoalesceBuffer++;;
fTCPCoalesceBuffer[fNumInCoalesceBuffer] = channel;
fNumInCoalesceBuffer++;
//*((short*)&fTCPCoalesceBuffer[fNumInCoalesceBuffer]) = htons(inLen);
// if we ever turn TCPCoalesce back on, this should be optimized
// for processors w/o alignment restrictions as above.
SInt16 pcketLen = htons((UInt16)inLen);
::memcpy(&fTCPCoalesceBuffer[fNumInCoalesceBuffer], &pcketLen, 2);
fNumInCoalesceBuffer += 2;
::memcpy(&fTCPCoalesceBuffer[fNumInCoalesceBuffer], inBuffer, inLen);
fNumInCoalesceBuffer += inLen;
#if RTSP_SESSION_INTERFACE_DEBUGGING
qtss_printf("InterleavedWrite: coalesce %li, total bufff %li\n", inLen, fNumInCoalesceBuffer);
#endif
}
}
......
}