258 lines
6.8 KiB
C++
258 lines
6.8 KiB
C++
![]() |
#include "rtpexternaltransmitter.h"
|
||
|
#include "rtperrors.h"
|
||
|
#include "rtpsession.h"
|
||
|
#include "rtpsessionparams.h"
|
||
|
#include "rtpbyteaddress.h"
|
||
|
#include "rtcpcompoundpacket.h"
|
||
|
#include "rtcpsrpacket.h"
|
||
|
#include "rtcprrpacket.h"
|
||
|
#include "rtcpbyepacket.h"
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <iostream>
|
||
|
#include <vector>
|
||
|
|
||
|
using namespace std;
|
||
|
using namespace jrtplib;
|
||
|
|
||
|
void checkError(int status)
|
||
|
{
|
||
|
if (status >= 0)
|
||
|
return;
|
||
|
|
||
|
cerr << "An error occured in the RTP component: " << endl;
|
||
|
cerr << "Error description: " << RTPGetErrorString(status) << endl;
|
||
|
|
||
|
exit(-1);
|
||
|
}
|
||
|
|
||
|
class MyRTPSession : public RTPSession
|
||
|
{
|
||
|
protected:
|
||
|
void OnPollThreadStep()
|
||
|
{
|
||
|
//cerr << "OnPollThreadStep" << endl;
|
||
|
}
|
||
|
|
||
|
void OnPollThreadError(int err)
|
||
|
{
|
||
|
cerr << "POLL THREAD ERROR!" << endl;
|
||
|
checkError(err);
|
||
|
}
|
||
|
|
||
|
void OnRTCPCompoundPacket(RTCPCompoundPacket *p, const RTPTime &receivetime, const RTPAddress *senderaddress)
|
||
|
{
|
||
|
printf("%u.%06u RECEIVED\n",receivetime.GetSeconds(),receivetime.GetMicroSeconds());
|
||
|
|
||
|
DumpCompoundPacket(stdout,p);
|
||
|
}
|
||
|
|
||
|
void OnSendRTCPCompoundPacket(RTCPCompoundPacket *p)
|
||
|
{
|
||
|
RTPTime t = RTPTime::CurrentTime();
|
||
|
|
||
|
printf("%u.%06u SENDING\n",t.GetSeconds(),t.GetMicroSeconds());
|
||
|
|
||
|
DumpCompoundPacket(stdout,p);
|
||
|
}
|
||
|
|
||
|
void DumpCompoundPacket(FILE *f, RTCPCompoundPacket *p)
|
||
|
{
|
||
|
RTCPPacket *pack;
|
||
|
|
||
|
p->GotoFirstPacket();
|
||
|
while ((pack = p->GetNextPacket()) != 0)
|
||
|
{
|
||
|
if (pack->GetPacketType() == RTCPPacket::SR)
|
||
|
{
|
||
|
RTCPSRPacket *p = (RTCPSRPacket *)pack;
|
||
|
|
||
|
RTPTime t(p->GetNTPTimestamp());
|
||
|
|
||
|
fprintf(f," SR packet\n SSRC %27u\n",p->GetSenderSSRC());
|
||
|
fprintf(f," NTP timestamp: %10u.%06u\n RTP timestamp: %17u\n Packets sent: %18u\n Octets sent: %19u\n",t.GetSeconds(),t.GetMicroSeconds(),p->GetRTPTimestamp(),p->GetSenderPacketCount(),p->GetSenderOctetCount());
|
||
|
|
||
|
for (int i = 0 ; i < p->GetReceptionReportCount() ; i++)
|
||
|
fprintf(f," RR block %d\n SSRC %25u\n Fraction lost: %15d\n Packets lost: %16d\n Ext. high. seq. nr: %10u\n Jitter: %22u\n LSR: %25u\n DLSR: %24u\n",(i+1),
|
||
|
p->GetSSRC(i),(int)p->GetFractionLost(i),p->GetLostPacketCount(i),p->GetExtendedHighestSequenceNumber(i),p->GetJitter(i),p->GetLSR(i),
|
||
|
p->GetDLSR(i));
|
||
|
}
|
||
|
else if (pack->GetPacketType() == RTCPPacket::RR)
|
||
|
{
|
||
|
RTCPRRPacket *p = (RTCPRRPacket *)pack;
|
||
|
|
||
|
fprintf(f," RR packet\n SSRC %27u\n",p->GetSenderSSRC());
|
||
|
|
||
|
for (int i = 0 ; i < p->GetReceptionReportCount() ; i++)
|
||
|
fprintf(f," RR block %d\n SSRC %25u\n Fraction lost: %15d\n Packets lost: %16d\n Ext. high. seq. nr: %10u\n Jitter: %22u\n LSR: %25u\n DLSR: %24u\n",(i+1),
|
||
|
p->GetSSRC(i),(int)p->GetFractionLost(i),p->GetLostPacketCount(i),p->GetExtendedHighestSequenceNumber(i),p->GetJitter(i),p->GetLSR(i),
|
||
|
p->GetDLSR(i));
|
||
|
}
|
||
|
else if (pack->GetPacketType() == RTCPPacket::SDES)
|
||
|
{
|
||
|
RTCPSDESPacket *p = (RTCPSDESPacket *)pack;
|
||
|
char str[1024];
|
||
|
|
||
|
if (!p->GotoFirstChunk())
|
||
|
return;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
fprintf(f," SDES Chunk:\n");
|
||
|
fprintf(f," SSRC: %26u\n",p->GetChunkSSRC());
|
||
|
if (p->GotoFirstItem())
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
switch (p->GetItemType())
|
||
|
{
|
||
|
case RTCPSDESPacket::None:
|
||
|
strcpy(str,"None ");
|
||
|
break;
|
||
|
case RTCPSDESPacket::CNAME:
|
||
|
strcpy(str,"CNAME: ");
|
||
|
break;
|
||
|
case RTCPSDESPacket::NAME:
|
||
|
strcpy(str,"NAME: ");
|
||
|
break;
|
||
|
case RTCPSDESPacket::EMAIL:
|
||
|
strcpy(str,"EMAIL: ");
|
||
|
break;
|
||
|
case RTCPSDESPacket::PHONE:
|
||
|
strcpy(str,"PHONE: ");
|
||
|
break;
|
||
|
case RTCPSDESPacket::LOC:
|
||
|
strcpy(str,"LOC: ");
|
||
|
break;
|
||
|
case RTCPSDESPacket::TOOL:
|
||
|
strcpy(str,"TOOL: ");
|
||
|
break;
|
||
|
case RTCPSDESPacket::NOTE:
|
||
|
strcpy(str,"NOTE: ");
|
||
|
break;
|
||
|
case RTCPSDESPacket::PRIV:
|
||
|
strcpy(str,"PRIV: ");
|
||
|
break;
|
||
|
case RTCPSDESPacket::Unknown:
|
||
|
default:
|
||
|
strcpy(str,"Unknown ");
|
||
|
}
|
||
|
fprintf(f," %s",str);
|
||
|
|
||
|
if (p->GetItemType() != RTCPSDESPacket::PRIV)
|
||
|
{
|
||
|
char str[1024];
|
||
|
memcpy(str,p->GetItemData(),p->GetItemLength());
|
||
|
str[p->GetItemLength()] = 0;
|
||
|
fprintf(f,"%24s\n",str);
|
||
|
}
|
||
|
} while (p->GotoNextItem());
|
||
|
}
|
||
|
} while (p->GotoNextChunk());
|
||
|
}
|
||
|
else if (pack->GetPacketType() == RTCPPacket::BYE)
|
||
|
{
|
||
|
fprintf(f," BYE packet:\n");
|
||
|
|
||
|
RTCPBYEPacket *p = (RTCPBYEPacket *)pack;
|
||
|
|
||
|
int num = p->GetSSRCCount();
|
||
|
int i;
|
||
|
|
||
|
for (i = 0 ; i < num ; i++)
|
||
|
fprintf(f," SSRC: %26u\n",p->GetSSRC(i));
|
||
|
if (p->HasReasonForLeaving())
|
||
|
{
|
||
|
char str[1024];
|
||
|
memcpy(str,p->GetReasonData(),p->GetReasonLength());
|
||
|
str[p->GetReasonLength()] = 0;
|
||
|
fprintf(f," Reason: %24s\n",str);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
fprintf(f,"\n");
|
||
|
}
|
||
|
};
|
||
|
|
||
|
class DummySender : public RTPExternalSender
|
||
|
{
|
||
|
public:
|
||
|
DummySender() { }
|
||
|
bool SendRTP(const void *data, size_t len) { return true; }
|
||
|
bool SendRTCP(const void *data, size_t len) { return true; }
|
||
|
bool ComesFromThisSender(const RTPAddress *a) { return false; }
|
||
|
};
|
||
|
|
||
|
int main(void)
|
||
|
{
|
||
|
FILE *pFile = fopen("logfile.dat", "rb");
|
||
|
if (!pFile)
|
||
|
{
|
||
|
cerr << "Unable to open logfile.dat" << endl;
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
DummySender sender;
|
||
|
RTPExternalTransmitter trans(0);
|
||
|
RTPExternalTransmissionParams params(&sender, 20);
|
||
|
|
||
|
checkError(trans.Init(true));
|
||
|
checkError(trans.Create(65535, ¶ms));
|
||
|
|
||
|
RTPExternalTransmissionInfo *pTransInfo = (RTPExternalTransmissionInfo *)trans.GetTransmissionInfo();
|
||
|
RTPExternalPacketInjecter *pPacketInjecter = pTransInfo->GetPacketInjector();
|
||
|
trans.DeleteTransmissionInfo(pTransInfo);
|
||
|
|
||
|
MyRTPSession session;
|
||
|
RTPSessionParams sessParams;
|
||
|
|
||
|
sessParams.SetOwnTimestampUnit(1.0/5.0);
|
||
|
sessParams.SetProbationType(RTPSources::NoProbation);
|
||
|
|
||
|
checkError(session.Create(sessParams, &trans));
|
||
|
|
||
|
vector<uint8_t> data;
|
||
|
double fileStartTime = 0;
|
||
|
double realStartTime = 0;
|
||
|
uint8_t host[] = {1, 2, 3, 4};
|
||
|
RTPByteAddress addr(host, 4);
|
||
|
|
||
|
while (true)
|
||
|
{
|
||
|
char ident[4];
|
||
|
double t;
|
||
|
uint32_t dataLength;
|
||
|
|
||
|
if (fread(ident, 1, 4, pFile) != 4 || fread(&t, 1, sizeof(double), pFile) != sizeof(double) ||
|
||
|
fread(&dataLength, 1, sizeof(uint32_t), pFile) != sizeof(uint32_t))
|
||
|
break;
|
||
|
|
||
|
data.resize(dataLength);
|
||
|
if (fread(&data[0], 1, dataLength, pFile) != dataLength)
|
||
|
break;
|
||
|
|
||
|
if (realStartTime == 0)
|
||
|
{
|
||
|
realStartTime = RTPTime::CurrentTime().GetDouble();
|
||
|
fileStartTime = t;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Busy wait until time to inject
|
||
|
while (true)
|
||
|
{
|
||
|
double curTime = RTPTime::CurrentTime().GetDouble();
|
||
|
if (curTime - realStartTime >= t - fileStartTime)
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// if (ident[2] == 'C')
|
||
|
// cerr << "Injecting RTCP packet of length " << dataLength << endl;
|
||
|
pPacketInjecter->InjectRTPorRTCP(&data[0], dataLength, addr);
|
||
|
}
|
||
|
|
||
|
fclose(pFile);
|
||
|
return 0;
|
||
|
}
|