1
#include "tfm/TestRtp.hxx"
2
#include "tfm/RtpEvent.hxx"
4
#include "rutil/Logger.hxx"
5
#include "rutil/Data.hxx"
6
#include "rutil/Socket.hxx"
7
#include "rutil/DnsUtil.hxx"
8
#include "resip/stack/SipMessage.hxx"
11
#include "CommonAction.hxx"
13
#include <boost/bind.hpp>
14
#include <boost/function.hpp>
18
#define RESIPROCATE_SUBSYSTEM resip::Subsystem::TEST
21
using namespace resip;
32
#define ETHERNET_HEADER_SIZE 14
33
#define IP_HEADER_SIZE 20
34
#define UDP_HEADER_SIZE 8
35
#define RTP_HEADER_SIZE 12
36
#define RTCP_HEADER_SIZE 8
37
#define OVERHEAD_SIZE (ETHERNET_HEADER_SIZE + IP_HEADER_SIZE + UDP_HEADER_SIZE)
39
#define SDP_USER "tfm"
40
#define SDP_SESSION_ID 1000
41
#define SDP_INITIAL_VERSION 1
42
#define SDP_SESSION_NAME "tfm call"
51
#define RTP_INTERVAL 20
52
// RTCP interval in seconds
53
#define RTCP_INTERVAL 1
55
// .bwc. Not used. Do we plan on ever uncommenting the code that uses this?
57
//timeval_subtract(timeval *result, timeval* x, timeval*y)
59
// /* Perform the carry for the later subtraction by updating y. */
60
// if (x->tv_usec < y->tv_usec) {
61
// int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
62
// y->tv_usec -= 1000000 * nsec;
65
// if (x->tv_usec - y->tv_usec > 1000000) {
66
// int nsec = (x->tv_usec - y->tv_usec) / 1000000;
67
// y->tv_usec += 1000000 * nsec;
71
// /* Compute the time remaining to wait.
72
// tv_usec is certainly positive. */
73
// result->tv_sec = x->tv_sec - y->tv_sec;
74
// result->tv_usec = x->tv_usec - y->tv_usec;
76
// /* Return 1 if result is negative. */
77
// return x->tv_sec < y->tv_sec;
80
PacketSenderStatistics::PacketSenderStatistics() :
86
PacketSenderStatistics::clear()
91
PacketReceiverStatistics::PacketReceiverStatistics() :
99
PacketReceiverStatistics::clear()
106
///////////////////////////////////////////////////////////////////////////////
108
mFdRtp(INVALID_SOCKET),
109
mFdRtcp(INVALID_SOCKET),
110
mFdVideoRtp(INVALID_SOCKET),
111
mFdVideoRtcp(INVALID_SOCKET),
112
mLocalAddrRtp("127.0.0.1", 8000, V4, UDP),
113
mLocalAddrRtcp("127.0.0.1", 8001, V4, UDP),
114
mLocalAddrVideoRtp("127.0.0.1", 8002, V4, UDP),
115
mLocalAddrVideoRtcp("127.0.0.1", 8003, V4, UDP),
116
mRemoteAddrRtp("0.0.0.0", 0, V4, UDP),
117
mRemoteAddrRtcp("0.0.0.0", 0, V4, UDP),
121
mReceiverStatistics(),
123
mDescribeWellKnownCodec(true),
130
mLocalSsrc = random();
133
srand((unsigned int) time(NULL));
134
mLocalSsrc = rand() % 64000;
144
// ----------------------------------------------------------------------------
148
mLocalSdp = boost::shared_ptr<SdpContents>(new SdpContents());
149
mLocalSdp->session().name() = SDP_SESSION_NAME;
150
mLocalSdp->session().version() = 0;
151
mLocalSdp->session().origin()
152
= SdpContents::Session::Origin(SDP_USER, SDP_SESSION_ID, SDP_INITIAL_VERSION, SdpContents::IP4, Data::Empty);
156
mDescribeWellKnownCodec = true;
157
mSendPackets = false;
159
addBasicAudioCodecs();
162
// ----------------------------------------------------------------------------
164
TestRtp::addBasicAudioCodecs()
166
const Codec & codec1 = SdpContents::Session::Codec::ULaw_8000;
167
const Codec & codec2 = SdpContents::Session::Codec::TelephoneEvent;
169
addAudioCodec(codec1.getName(), codec1.payloadType(), codec1.getRate(), codec1.parameters());
170
addAudioCodec(codec2.getName(), codec2.payloadType(), codec2.getRate(), codec2.parameters());
174
TestRtp::openSocket(TransportType type)
180
fd = ::socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
186
InfoLog(<< "Unsupported transport type");
187
return INVALID_SOCKET;
190
if( INVALID_SOCKET == fd )
193
InfoLog(<< "Failed to create socket: " << strerror(e));
202
mFdRtp = openSocket(mLocalAddrRtp.getType());
203
mFdRtcp = openSocket(mLocalAddrRtcp.getType());
205
DebugLog(<< "Create RTP/RTCP socket fd: " << (unsigned int) mFdRtp << "/" << (unsigned int) mFdRtcp);
207
mFdVideoRtp = openSocket(mLocalAddrVideoRtp.getType());
208
mFdVideoRtcp = openSocket(mLocalAddrVideoRtcp.getType());
215
closeSocket(mFdRtcp);
216
closeSocket(mFdVideoRtp);
217
closeSocket(mFdVideoRtcp);
221
TestRtp::getName() const
225
DataStream strm(buffer);
226
strm << "RTP end point " << mLocalAddrRtp;
232
TestRtp::isRtpPacket(const Data& packet, UInt32 ssrc) const
234
if( packet.size() < RTP_HEADER_SIZE )
237
RtpHeader& header = *((RtpHeader*)(packet.data()));
239
if( ntohl(header.mSsrc) != ssrc )
246
TestRtp::isRtcpPacket(const Data& packet, UInt32 ssrc) const
248
if( packet.size() < RTCP_HEADER_SIZE )
251
RtcpHeader& header = *((RtcpHeader*)(packet.data()));
253
if( ntohl(header.mSsrc) != ssrc )
256
switch( header.mPayloadType )
270
TestRtp::getSeqNo(const Packet& packet)
272
RtpHeader& header = *((RtpHeader*)(packet.mData.data()));
273
return ntohs(header.mSequenceNumber);
277
TestRtp::RtpPacketInfo()
279
UInt16 first = getSeqNo(mPacketsRtp.front());
280
UInt16 last = getSeqNo(mPacketsRtp.back());
282
int received = (int) mPacketsRtp.size();
283
InfoLog(<< "Received packates: " << received);
284
InfoLog( << "First: " << first << ", Last: " << last);
289
int expected = (last - first + 1 + 65536) % 65536;
290
InfoLog(<< "Expected packets: " << expected);
291
InfoLog(<< "Loss rate: " << 100.0f * (expected - received)/(float)expected << "%");
294
struct timeval firstTime = mPacketsRtp.front().mTimeStamp;
296
list<Packet>::iterator it;
298
for( it = mPacketsRtp.begin(); it != mPacketsRtp.end(); it++ )
300
timeval_subtract(&diff, &it->mTimeStamp, &firstTime);
301
InfoLog(<< "Packet: " << i++ << ", Time: " << diff.tv_sec << "." << diff.tv_usec);
307
TestRtp::loadStream(const Data& file, UInt32 ssrc)
310
char errbuff[PCAP_ERRBUF_SIZE];
312
pcap_t* p = pcap_open_offline(file.c_str(), errbuff);
316
InfoLog(<< "Error reading PCAP file " << file << ": " << errbuff);
322
struct pcap_pkthdr h;
323
const u_char* pkt = pcap_next(p, &h);
330
if( len < OVERHEAD_SIZE )
333
Packet packet(h.ts, Data(pkt + OVERHEAD_SIZE, len - OVERHEAD_SIZE));
335
if( isRtpPacket(packet.mData, ssrc) )
336
mPacketsRtp.push_back(packet);
337
else if( isRtcpPacket(packet.mData, ssrc) )
338
mPacketsRtcp.push_back(packet);
343
InfoLog( << "RTP/RTCP packets read: " << mPacketsRtp.size() << "/" << mPacketsRtcp.size());
348
InfoLog(<< "Reading pcap files disabled");
354
TestRtp::bindSocket(resip::Socket fd, Tuple& addr)
356
if( ::bind( fd, &addr.getMutableSockaddr(), addr.length()) == SOCKET_ERROR )
359
if ( e == EADDRINUSE )
360
ErrLog (<< "Address already in use " << addr);
362
ErrLog (<< "Could not bind socket to " << addr);
367
bool ok = makeSocketNonBlocking(fd);
370
ErrLog (<< "Could not make socket non-blocking ");
380
bindSocket(mFdRtp, mLocalAddrRtp);
381
bindSocket(mFdRtcp, mLocalAddrRtcp);
383
DebugLog(<< "Binding RTP socket to " << mLocalAddrRtp);
384
DebugLog(<< "Binding RTCP socket to " << mLocalAddrRtcp);
386
bindSocket(mFdVideoRtp, mLocalAddrVideoRtp);
387
bindSocket(mFdVideoRtcp, mLocalAddrVideoRtcp);
389
DebugLog(<< "Binding RTP socket to " << mLocalAddrVideoRtp);
390
DebugLog(<< "Binding RTCP socket to " << mLocalAddrVideoRtcp);
394
TestRtp::recvPacket(resip::Socket fd, Tuple& addr)
396
char* buffer = new char[MaxBufferSize];
397
socklen_t slen = addr.length();
398
int len = recvfrom(fd, buffer, MaxBufferSize, 0, &addr.getMutableSockaddr(), &slen);
399
if ( len == SOCKET_ERROR )
402
InfoLog(<< "Socket read error: " << strerror(e));
405
if (len == 0 || len == SOCKET_ERROR)
412
return Data(Data::Take, buffer, len);
416
TestRtp::parsePacket(const Data& data)
418
if( data.size() < RTP_HEADER_SIZE )
420
InfoLog(<< "Invalid RTP message received of size: " << (unsigned int) data.size());
424
// !jv! for now, assume that RTP header is 12 bytes
425
const RtpHeader& header = *((const RtpHeader*)data.data());
427
UInt8 remoteCodec = header.mPayloadType & 0x7f;
428
bool matchAudio = false;
429
bool matchVideo = false;
431
// simple matching of payload type. Given the incoming RTP packet payload type, search our local codecs in SDP
432
// to see if there's a match and whether it's for audio or video.
434
for (list<Medium>::iterator it = mLocalSdp->session().media().begin(); it != mLocalSdp->session().media().end(); it++)
436
for( list<Codec>::const_iterator j = it->codecs().begin(); j != it->codecs().end(); j++ )
438
if (remoteCodec == j->payloadType())
440
if (it->name() == SdpHelper::AudioMediaType)
442
else if (it->name() == SdpHelper::VideoMediaType)
448
if( !(matchAudio || matchVideo) )
450
InfoLog(<< "Invalid payload type received: " << remoteCodec << " of size " << (unsigned int) data.size());
454
UInt32 remoteSsrc = ntohl(header.mSsrc);
455
if( 0 == mRemoteSsrc )
457
InfoLog(<< "TestRtp::parsePacket(): RTP strem started");
458
// handleEvent(new RtpEvent(this, Rtp_StreamStarted));
459
mRemoteSsrc = remoteSsrc;
460
mRemoteCodec = remoteCodec;
463
if( remoteSsrc != mRemoteSsrc )
465
InfoLog(<< "TestRtp::parsePacket(): SSRC changed to " << remoteSsrc);
466
// handleEvent(new RtpEvent(this, Rtp_SsrcChanged));
467
mRemoteSsrc = remoteSsrc;
470
if( mRemoteCodec != remoteCodec )
472
// handleEvent(new RtpEvent(this, Rtp_CodecChanged));
473
mRemoteCodec = remoteCodec;
476
mReceiverStatistics.mReceived++;
482
TestRtp::overrideSsrc(Data& packet)
484
RtpHeader& header = *((RtpHeader*)packet.data());
485
header.mSsrc = htonl(mLocalSsrc);
489
TestRtp::sendPacket(resip::Socket fd, Tuple& dest, const Data& data)
491
size_t count = sendto(fd, data.data(), (int) data.size(), 0, &dest.getSockaddr(), dest.length());
493
if( count == (size_t)SOCKET_ERROR )
496
ErrLog(<< "Failed to send packet to " << dest << ": " << strerror(e));
500
if( count != data.size() )
501
ErrLog(<< "Buffer overflow while sending packet to " << dest);
504
mSenderStatistics.mSent++;
507
// ----------------------------------------------------------------------------
508
boost::shared_ptr<SdpContents>
509
TestRtp::getLocalSdp() const
511
return getLocalSdp(MEDIA_ACTIVE, MEDIA_ACTIVE);
514
// ----------------------------------------------------------------------------
515
boost::shared_ptr<SdpContents>
516
TestRtp::getLocalSdp(unsigned long audioAttr, unsigned long videoAttr) const
518
SdpContents * contents = dynamic_cast<SdpContents*>(mLocalSdp->clone());
519
mLocalSdp->session().origin().getVersion() += 1;
520
if (! mSessionName.empty())
521
mLocalSdp->session().name() = mSessionName;
522
boost::shared_ptr<SdpContents> sdp = boost::shared_ptr<SdpContents>(contents);
524
SdpContents::AddrType addrType = mLocalAddrRtp.ipVersion() == V4 ? SdpContents::IP4 : SdpContents::IP6;
525
Data addr = Tuple::inet_ntop(mLocalAddrRtp);
526
sdp->session().origin().setAddress(addr, addrType);
528
SdpContents::Session::Connection connection(addrType, addr);
529
if (mHold2543 && (audioAttr & MEDIA_HOLD))
530
connection.setAddress("0.0.0.0");
531
sdp->session().connection() = connection;
533
int audioPort = mLocalAddrRtp.getPort();
536
// for each m-line in the session, set here:
540
for (list<Medium>::iterator it = sdp->session().media().begin(); it != sdp->session().media().end(); it++)
542
Medium & mline = *it;
543
unsigned long mediaAttr = MEDIA_NONE;
544
if (mline.name() == SdpHelper::AudioMediaType)
545
mediaAttr = audioAttr;
546
else if (mline.name() == SdpHelper::VideoMediaType)
547
mediaAttr = videoAttr;
552
if ((mediaAttr & MEDIA_DISABLE))
558
mline.port() = audioPort + offset;
565
if ((mediaAttr & MEDIA_HOLD))
566
mline.addAttribute("sendonly");
567
else if ((mediaAttr & MEDIA_ACTIVE))
568
mline.addAttribute("sendrecv");
569
else if ((mediaAttr & MEDIA_INACTIVE))
570
mline.addAttribute("inactive");
571
else if ((mediaAttr & MEDIA_HOLD_PEER))
572
mline.addAttribute("recvonly");
575
if (mPtime && (mline.name() == SdpHelper::AudioMediaType))
576
mline.addAttribute("ptime:" + Data(mPtime));
583
TestRtp::setLocalAddr(const Uri& addr)
585
int port = addr.port();
586
Tuple t(addr.host(), port, (DnsUtil::isIpV6Address(addr.host()) ? V6 : V4), UDP);
591
mLocalAddrVideoRtp = t;
593
mLocalAddrVideoRtcp = t;
597
TestRtp::setLocalAddr(const Data& addr)
599
int port = mLocalAddrRtp.getPort();
600
Tuple t(addr, port, (DnsUtil::isIpV6Address(addr) ? V6 : V4), UDP);
605
mLocalAddrVideoRtp = t;
607
mLocalAddrVideoRtcp = t;
612
const resip::Data& mediaName,
613
const resip::Data& codecName,
616
const resip::Data& parameters,
620
if (mediaName.empty())
624
mLocalSdp = boost::shared_ptr<SdpContents>(new SdpContents());
627
// find the m-line based on media-type: 'audio'/'video', etc. in the REVERSE direction.
628
for (list<Medium>::reverse_iterator it = mLocalSdp->session().media().rbegin(); it != mLocalSdp->session().media().rend(); it++)
630
if (it->name() == mediaName)
636
// doesn't exist, add medium and codec
637
Medium tmpMedium(mediaName, port, 0, (proto ? proto : SdpHelper::RtpAvpProtocol));
638
mLocalSdp->session().addMedium(tmpMedium);
639
medium = &mLocalSdp->session().media().back();
642
if (mDescribeWellKnownCodec)
644
Codec codec(codecName, payload, rate);
645
codec.parameters() = parameters;
646
medium->codecs().push_back(codec);
650
Data strPayload = Data::from(payload);
651
medium->addFormat(strPayload);
652
// describe telephone-event anyhow
653
if (codecName == "telephone-event")
657
DataStream s(strRTPMap);
658
s <<strPayload <<' ' <<codecName <<'/' <<rate;
660
medium->addAttribute("rtpmap", strRTPMap);
661
if (! parameters.empty())
662
medium->addAttribute("fmtp", (strPayload + " " + parameters));
669
TestRtp::addControlMLine()
671
Medium medium(SdpHelper::ControlMediaType, 0, 0, SdpHelper::TcpMcProtocol);
672
mLocalSdp->session().addMedium(medium);
676
TestRtp::removeCodecs(const resip::Data& mediaName)
680
if (mediaName.empty())
682
mLocalSdp->session().media().clear();
686
for (list<Medium>::iterator it = mLocalSdp->session().media().begin(); it != mLocalSdp->session().media().end();)
688
list<Medium>::iterator prev = it++;
689
if (prev->name() == mediaName)
690
mLocalSdp->session().media().erase(prev);
697
TestRtp::setRemoteAddr(const Tuple& addr)
699
mRemoteAddrRtp = addr;
700
mRemoteAddrRtcp = addr;
701
int port = mRemoteAddrRtp.getPort();
702
mRemoteAddrRtcp.setPort(port + 1);
706
TestRtp::enableSendingDelegate(bool enable)
708
DebugLog(<< "enableSendingDelegate()");
709
mSendPackets = enable;
713
///////////////////////////////////////////////////////////////////////////////
714
///////////////////////////////////////////////////////////////////////////////
716
resip::Data SdpHelper::AudioMediaType = "audio";
717
resip::Data SdpHelper::VideoMediaType = "video";
718
resip::Data SdpHelper::ControlMediaType = "control";
720
resip::Data SdpHelper::RtpAvpProtocol = "RTP/AVP";
721
resip::Data SdpHelper::TcpMcProtocol = "tcp mc";
723
SdpHelper::MediaDirection
724
SdpHelper::getMediaDirectionFromString(const char * szMediaName)
728
Data dir(Data::Share, szMediaName);
729
if (dir == "sendonly") return MD_SendOnly;
730
else if (dir == "recvonly") return MD_RecvOnly;
731
else if (dir == "sendrecv") return MD_SendRecv;
732
else if (dir == "inactive") return MD_Inactive;
737
SdpHelper::MediaDirection
738
SdpHelper::getMediaDirection(boost::shared_ptr<resip::SipMessage> msg, const char * szMediaName)
740
SdpContents* sdp = dynamic_cast<SdpContents*>(msg->getContents());
741
if (!sdp || !szMediaName)
743
for (list<Medium>::const_iterator it = sdp->session().media().begin(); it != sdp->session().media().end(); it++)
745
if (it->name() == szMediaName)
747
if (it->exists(Data(Data::Share, "inactive"))) return MD_Inactive;
748
else if (it->exists(Data(Data::Share, "recvonly"))) return MD_RecvOnly;
749
else if (it->exists(Data(Data::Share, "sendonly"))) return MD_SendOnly;
750
else if (it->exists(Data(Data::Share, "sendrecv"))) return MD_SendRecv;
758
SdpHelper::hasIce(boost::shared_ptr<SipMessage> msg)
760
SdpContents* sdp = dynamic_cast<SdpContents*>(msg->getContents());
764
list<SdpContents::Session::Medium> media = sdp->session().media();
765
// only consider first media
766
list<SdpContents::Session::Medium>::const_iterator it = media.begin();
767
if( it == media.end() )
770
if( it->exists("alt") )
773
if( it->exists("candidate") )
780
SdpHelper::getConnectionAddr(boost::shared_ptr<resip::SipMessage> msg)
782
SdpContents* sdp = dynamic_cast<SdpContents*>(msg->getContents());
788
return sdp->session().connection().getAddress();
792
SdpHelper::getPort(boost::shared_ptr<resip::SipMessage> msg, unsigned int index)
794
SdpContents* sdp = dynamic_cast<SdpContents*>(msg->getContents());
800
list<SdpContents::Session::Medium> media = sdp->session().media();
801
if( media.size() < index + 1 )
804
list<SdpContents::Session::Medium>::iterator it = media.begin();
805
for( unsigned int i = 0; i < index; it++, i++ );
811
SdpHelper::getPort(boost::shared_ptr<resip::SipMessage> msg, const char * szMediaName)
813
SdpContents* sdp = dynamic_cast<SdpContents*>(msg->getContents());
814
if (!sdp || !szMediaName)
816
for (list<Medium>::const_iterator it = sdp->session().media().begin(); it != sdp->session().media().end(); it++)
818
if (it->name() == szMediaName)
825
SdpHelper::setPort(boost::shared_ptr<resip::SdpContents> sdp, const char * szMediaName, unsigned long port)
827
if (!sdp || !szMediaName)
829
for (list<Medium>::iterator it = sdp->session().media().begin(); it != sdp->session().media().end(); it++)
831
if (it->name() == szMediaName)
839
void SdpHelper::addAttr(
840
boost::shared_ptr<resip::SdpContents> sdp,
841
const char * szMediaName,
842
const char* szAttrField,
843
const char* szAttrValue)
845
if (!sdp || !szMediaName || !szAttrField || !szAttrValue)
847
for (list<Medium>::iterator it = sdp->session().media().begin(); it != sdp->session().media().end(); it++)
849
if (it->name() == szMediaName)
851
it->addAttribute(szAttrField, szAttrValue);
858
SdpHelper::isMediaInactive(boost::shared_ptr<SipMessage> msg)
860
SdpContents* sdp = dynamic_cast<SdpContents*>(msg->getContents());
864
list<SdpContents::Session::Medium> media = sdp->session().media();
865
// only consider first media
866
list<SdpContents::Session::Medium>::const_iterator it = media.begin();
867
if( it == media.end() )
870
if( it->exists("inactive") )
877
SdpHelper::isMediaSendOnly(boost::shared_ptr<SipMessage> msg)
879
SdpContents* sdp = dynamic_cast<SdpContents*>(msg->getContents());
883
list<SdpContents::Session::Medium> media = sdp->session().media();
884
// only consider first media
885
list<SdpContents::Session::Medium>::const_iterator it = media.begin();
886
if( it == media.end() )
889
if( it->exists("sendonly") )
896
SdpHelper::isMediaRecvOnly(boost::shared_ptr<SipMessage> msg)
898
SdpContents* sdp = dynamic_cast<SdpContents*>(msg->getContents());
902
list<SdpContents::Session::Medium> media = sdp->session().media();
903
// only consider first media
904
list<SdpContents::Session::Medium>::const_iterator it = media.begin();
905
if( it == media.end() )
908
if( it->exists("recvonly") )
915
SdpHelper::getMediaCount(boost::shared_ptr<resip::SipMessage> msg)
917
SdpContents* sdp = dynamic_cast<SdpContents*>(msg->getContents());
920
return (unsigned int) sdp->session().media().size();
925
SdpHelper::getMLineCount(boost::shared_ptr<resip::SipMessage> msg, const char * szMediaName)
927
unsigned int ret = 0;
928
SdpContents* sdp = dynamic_cast<SdpContents*>(msg->getContents());
931
for (list<Medium>::const_iterator it = sdp->session().media().begin(); it != sdp->session().media().end(); it++)
933
if (it->name() == szMediaName)
940
SdpHelper::getCodecsCount(boost::shared_ptr<resip::SipMessage> msg, const char * szMediaName)
942
SdpContents* sdp = dynamic_cast<SdpContents*>(msg->getContents());
945
for (list<Medium>::const_iterator it = sdp->session().media().begin(); it != sdp->session().media().end(); it++)
947
if (it->name() == szMediaName)
948
return (unsigned int) it->codecs().size();
954
SdpHelper::hasPayloadNumber(boost::shared_ptr<resip::SipMessage> msg, int payloadNumber)
956
SdpContents* sdp = dynamic_cast<SdpContents*>(msg->getContents());
959
for (list<Medium>::const_iterator it = sdp->session().media().begin(); it != sdp->session().media().end(); it++)
961
for( list<Codec>::const_iterator jIt = it->codecs().begin(); jIt != it->codecs().end(); jIt++ )
963
if (jIt->payloadType() == payloadNumber)
971
SdpHelper::isHold2543(boost::shared_ptr<SipMessage> msg)
973
SdpContents* sdp = dynamic_cast<SdpContents*>(msg->getContents());
977
SdpContents::Session::Connection connection = sdp->session().connection();
978
Data addr = connection.getAddress();
979
return addr == "0.0.0.0";
985
// Three types of modes:
986
// 1. Return each packet to sender with modified SSRC
987
// 2. When a packets comes in from sender, send a packet from file
988
// 3. Send packet from file in regular interval. Currently, this method
989
// sends packets out according to timestamp found in Ethereal.
990
// The current solution consumes all CPU since it spins and checks
991
// the time periodically
993
// time_t lastRtcp = time(NULL);
994
struct timeval lastPacketTime;
995
if( !mPacketsRtp.empty() )
996
lastPacketTime = mPacketsRtp.front().mTimeStamp;
998
double lastSendingTime = XsLib::XsGetClockTickUs();
999
#elif !defined(WIN32)
1000
struct timeval lastSendingTime;
1001
gettimeofday(&lastSendingTime, 0);
1004
while( !isShutdown() )
1007
fdSet.setRead(mFdRtp);
1008
fdSet.setRead(mFdRtcp);
1010
/*int ready = */fdSet.selectMilliSeconds(RTP_INTERVAL);
1012
if( fdSet.readyToRead(mFdRtp) )
1015
Data data = recvPacket(mFdRtp, from);
1016
if( 0 == mRemoteAddrRtp.getPort() )
1018
InfoLog(<< "Updating RTP address changed to " << from);
1019
mRemoteAddrRtp = from;
1021
if( parsePacket(data) )
1023
// overrideSsrc(data);
1024
// sendPacket(mFdRtp, mRemoteAddrRtp, data);
1026
if( mSendPackets && !mPacketsRtp.empty() )
1028
Packet packet = mPacketsRtp.front();
1029
mPacketsRtp.pop_front();
1030
sendPacket(mFdRtp, mRemoteAddrRtp, packet.mData);
1031
if( 0 == (mPacketsRtp.size() % 100) )
1032
InfoLog(<< (unsigned int) mPacketsRtp.size() << " more packets to send");
1039
if( fdSet.readyToRead(mFdRtcp) )
1042
Data data = recvPacket(mFdRtcp, from);
1043
if( !(mRemoteAddrRtcp == from) )
1045
InfoLog(<< "Remote RTCP address changed to " << from);
1046
mRemoteAddrRtcp = from;
1054
if( !mPacketsRtp.empty() )
1056
// DebugLog(<< "Checking time to send RTP packet");
1060
double currentTime = XsLib::XsGetClockTickUs();
1061
double elapsedTime = currentTime - lastSendingTime;
1063
struct timeval currentTime;
1064
gettimeofday(¤tTime, 0);
1065
struct timeval elapsedTime;
1066
timeval_subtract(&elapsedTime, ¤tTime, &lastSendingTime);
1069
struct timeval currentPacketTime = mPacketsRtp.front().mTimeStamp;
1070
struct timeval packetDiffTime;
1071
timeval_subtract(&packetDiffTime, ¤tPacketTime, &lastPacketTime);
1073
// InfoLog( << "Packet diff: " << packetDiffTime.tv_sec << "." << packetDiffTime.tv_usec);
1076
// InfoLog(<< elapsedTime);
1077
bool send = (packetDiffTime.tv_sec * 1000000 + packetDiffTime.tv_usec) >= elapsedTime;
1079
struct timeval diff;
1080
bool send = (timeval_subtract(&diff, &elapsedTime, &packetDiffTime) == 0);
1081
// InfoLog( << "Elapsed: " << elapsedTime.tv_sec << "." << elapsedTime.tv_usec);
1087
// DebugLog(<< "Sending RTP packet");
1089
Packet packet = mPacketsRtp.front();
1090
mPacketsRtp.pop_front();
1091
sendPacket(mFdRtp, mRemoteAddrRtp, packet.mData);
1094
lastPacketTime = currentPacketTime;
1095
lastSendingTime = currentTime;
1103
Sleep(RTP_INTERVAL);
1105
usleep(RTP_INTERVAL * 1000);
1110
if( !mPacketsRtcp.empty() )
1112
if( time(NULL) > lastRtcp + RTCP_INTERVAL )
1114
DebugLog(<< "Sending RTCP packet");
1115
Packet packet = mPacketsRtcp.front();
1116
mPacketsRtcp.pop_front();
1117
sendPacket(mFdRtcp, mRemoteAddrRtcp, packet.mData);
1118
lastRtcp = time(NULL);
1127
TestEndPoint::ExpectBase*
1128
TestRtp::expect(RtpEvent::Type type,
1130
ActionBase* expectAction)
1132
InfoLog( << "TestRtp::expect()");
1133
return new Expect(*this,
1134
new EventMatcherSpecific<RtpEvent>(type),
1140
TestRtp::enableSending(bool enable)
1142
DebugLog(<< "TestRtp::enableSending()");
1143
return new CommonAction(this,
1145
boost::bind(&TestRtp::enableSendingDelegate, this, enable));