~ubuntu-branches/ubuntu/saucy/resiprocate/saucy-proposed

« back to all changes in this revision

Viewing changes to tfm/TestRtp.cxx

  • Committer: Package Import Robot
  • Author(s): Daniel Pocock
  • Date: 2012-05-17 19:29:59 UTC
  • Revision ID: package-import@ubuntu.com-20120517192959-vv00m77isztdy64q
Tags: upstream-1.8.2
ImportĀ upstreamĀ versionĀ 1.8.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "tfm/TestRtp.hxx"
 
2
#include "tfm/RtpEvent.hxx"
 
3
 
 
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"
 
9
 
 
10
#include "Expect.hxx"
 
11
#include "CommonAction.hxx"
 
12
 
 
13
#include <boost/bind.hpp>
 
14
#include <boost/function.hpp>
 
15
 
 
16
#include <time.h>
 
17
 
 
18
#define RESIPROCATE_SUBSYSTEM resip::Subsystem::TEST
 
19
 
 
20
 
 
21
using namespace resip;
 
22
using namespace std;
 
23
 
 
24
//#define USE_XS_TIME
 
25
 
 
26
//#define HAS_PCAP
 
27
 
 
28
#ifdef HAS_PCAP
 
29
#include <pcap.h>
 
30
#endif
 
31
 
 
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)
 
38
 
 
39
#define SDP_USER "tfm"
 
40
#define SDP_SESSION_ID 1000
 
41
#define SDP_INITIAL_VERSION  1
 
42
#define SDP_SESSION_NAME "tfm call"
 
43
 
 
44
#define RTCP_SR    200
 
45
#define RTCP_RR    201
 
46
#define RTCP_SDES  202
 
47
#define RTCP_BYE   203
 
48
#define RTCP_APP   204
 
49
 
 
50
// RTP interval in ms
 
51
#define RTP_INTERVAL  20
 
52
// RTCP interval in seconds
 
53
#define RTCP_INTERVAL 1
 
54
 
 
55
// .bwc. Not used. Do we plan on ever uncommenting the code that uses this?
 
56
//static int
 
57
//timeval_subtract(timeval *result, timeval* x, timeval*y)
 
58
//{
 
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;
 
63
//    y->tv_sec += nsec;
 
64
//  }
 
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;
 
68
//    y->tv_sec -= nsec;
 
69
//  }
 
70
//
 
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;
 
75
//
 
76
//  /* Return 1 if result is negative. */
 
77
//  return x->tv_sec < y->tv_sec;
 
78
//}
 
79
 
 
80
PacketSenderStatistics::PacketSenderStatistics() :
 
81
   mSent(0)
 
82
{
 
83
}
 
84
 
 
85
void
 
86
PacketSenderStatistics::clear()
 
87
{
 
88
   mSent = 0;
 
89
}
 
90
 
 
91
PacketReceiverStatistics::PacketReceiverStatistics() :
 
92
   mReceived(0),
 
93
   mLost(0)
 
94
 
 
95
{
 
96
}
 
97
 
 
98
void
 
99
PacketReceiverStatistics::clear()
 
100
{
 
101
   mReceived = 0;
 
102
   mLost = 0;
 
103
}
 
104
 
 
105
 
 
106
///////////////////////////////////////////////////////////////////////////////
 
107
TestRtp::TestRtp() :
 
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),
 
118
   mRemoteSsrc(0),
 
119
   mRemoteCodec(0),
 
120
   mSenderStatistics(),
 
121
   mReceiverStatistics(),
 
122
   mHold2543(false),
 
123
   mDescribeWellKnownCodec(true),
 
124
   mPtime(0),
 
125
   mPacketsRtp(),
 
126
   mPacketsRtcp(),
 
127
   mSendPackets(false)
 
128
{
 
129
#ifndef WIN32
 
130
   mLocalSsrc = random();
 
131
//   mLocalSsrc = 0;
 
132
#else
 
133
   srand((unsigned int) time(NULL));
 
134
   mLocalSsrc = rand() % 64000;
 
135
#endif
 
136
 
 
137
   clean();
 
138
}
 
139
 
 
140
TestRtp::~TestRtp()
 
141
{
 
142
}
 
143
 
 
144
// ----------------------------------------------------------------------------
 
145
void
 
146
TestRtp::clean()
 
147
{
 
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);
 
153
 
 
154
   mPtime = 0;
 
155
   mHold2543 = false;
 
156
   mDescribeWellKnownCodec = true;
 
157
   mSendPackets = false;
 
158
 
 
159
   addBasicAudioCodecs();
 
160
}
 
161
 
 
162
// ----------------------------------------------------------------------------
 
163
void
 
164
TestRtp::addBasicAudioCodecs()
 
165
{
 
166
   const Codec & codec1 = SdpContents::Session::Codec::ULaw_8000;
 
167
   const Codec & codec2 = SdpContents::Session::Codec::TelephoneEvent;
 
168
 
 
169
   addAudioCodec(codec1.getName(), codec1.payloadType(), codec1.getRate(), codec1.parameters());
 
170
   addAudioCodec(codec2.getName(), codec2.payloadType(), codec2.getRate(), codec2.parameters());
 
171
}
 
172
 
 
173
resip::Socket
 
174
TestRtp::openSocket(TransportType type)
 
175
{
 
176
   Socket fd;
 
177
   switch( type )
 
178
   {
 
179
      case UDP:
 
180
         fd = ::socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
 
181
         break;
 
182
 
 
183
      case TCP:
 
184
      case TLS:
 
185
      default:
 
186
         InfoLog(<< "Unsupported transport type");
 
187
         return INVALID_SOCKET;
 
188
   }
 
189
 
 
190
   if( INVALID_SOCKET == fd )
 
191
   {
 
192
      int e = getErrno();
 
193
      InfoLog(<< "Failed to create socket: " << strerror(e));
 
194
   }
 
195
 
 
196
   return fd;
 
197
}
 
198
 
 
199
void
 
200
TestRtp::open()
 
201
{
 
202
   mFdRtp = openSocket(mLocalAddrRtp.getType());
 
203
   mFdRtcp = openSocket(mLocalAddrRtcp.getType());
 
204
 
 
205
   DebugLog(<< "Create RTP/RTCP socket fd: " << (unsigned int) mFdRtp << "/" << (unsigned int) mFdRtcp);
 
206
 
 
207
   mFdVideoRtp = openSocket(mLocalAddrVideoRtp.getType());
 
208
   mFdVideoRtcp = openSocket(mLocalAddrVideoRtcp.getType());
 
209
}
 
210
 
 
211
void
 
212
TestRtp::close()
 
213
{
 
214
   closeSocket(mFdRtp);
 
215
   closeSocket(mFdRtcp);
 
216
   closeSocket(mFdVideoRtp);
 
217
   closeSocket(mFdVideoRtcp);
 
218
}
 
219
 
 
220
Data
 
221
TestRtp::getName() const
 
222
{
 
223
  Data buffer;
 
224
  {
 
225
     DataStream strm(buffer);
 
226
     strm << "RTP end point " << mLocalAddrRtp;
 
227
  }
 
228
  return buffer;
 
229
}
 
230
 
 
231
bool
 
232
TestRtp::isRtpPacket(const Data& packet, UInt32 ssrc) const
 
233
{
 
234
   if( packet.size() < RTP_HEADER_SIZE )
 
235
      return false;
 
236
 
 
237
   RtpHeader& header = *((RtpHeader*)(packet.data()));
 
238
 
 
239
   if( ntohl(header.mSsrc) != ssrc )
 
240
      return false;
 
241
 
 
242
   return true;
 
243
}
 
244
 
 
245
bool
 
246
TestRtp::isRtcpPacket(const Data& packet, UInt32 ssrc) const
 
247
{
 
248
   if( packet.size() < RTCP_HEADER_SIZE )
 
249
      return false;
 
250
 
 
251
   RtcpHeader& header = *((RtcpHeader*)(packet.data()));
 
252
 
 
253
   if( ntohl(header.mSsrc) != ssrc )
 
254
      return false;
 
255
 
 
256
   switch( header.mPayloadType )
 
257
   {
 
258
      case RTCP_SR:
 
259
      case RTCP_RR:
 
260
      case RTCP_SDES:
 
261
      case RTCP_BYE:
 
262
      case RTCP_APP:
 
263
         return true;
 
264
   }
 
265
 
 
266
   return true;
 
267
}
 
268
 
 
269
UInt16 
 
270
TestRtp::getSeqNo(const Packet& packet)
 
271
{
 
272
   RtpHeader& header = *((RtpHeader*)(packet.mData.data()));
 
273
   return ntohs(header.mSequenceNumber);
 
274
}
 
275
 
 
276
void
 
277
TestRtp::RtpPacketInfo()
 
278
{
 
279
   UInt16 first = getSeqNo(mPacketsRtp.front());
 
280
   UInt16 last = getSeqNo(mPacketsRtp.back());
 
281
 
 
282
   int received = (int) mPacketsRtp.size();
 
283
   InfoLog(<< "Received packates: " << received);
 
284
   InfoLog( << "First: " << first << ", Last: " << last);
 
285
 
 
286
   if( received <= 0 )
 
287
      return;
 
288
 
 
289
   int expected = (last - first + 1 + 65536) % 65536;
 
290
   InfoLog(<< "Expected packets: " << expected);
 
291
   InfoLog(<< "Loss rate: " << 100.0f * (expected - received)/(float)expected << "%");
 
292
 
 
293
/*
 
294
   struct timeval firstTime =  mPacketsRtp.front().mTimeStamp;
 
295
   struct timeval diff;
 
296
   list<Packet>::iterator it;
 
297
   int i = 0;
 
298
   for( it = mPacketsRtp.begin(); it != mPacketsRtp.end(); it++ )
 
299
   {
 
300
      timeval_subtract(&diff, &it->mTimeStamp, &firstTime);
 
301
      InfoLog(<< "Packet: " << i++ << ", Time: " << diff.tv_sec << "." << diff.tv_usec);
 
302
   }
 
303
*/
 
304
}
 
305
 
 
306
void
 
307
TestRtp::loadStream(const Data& file, UInt32 ssrc)
 
308
{
 
309
#ifdef HAS_PCAP
 
310
   char errbuff[PCAP_ERRBUF_SIZE];
 
311
 
 
312
   pcap_t* p = pcap_open_offline(file.c_str(), errbuff);
 
313
 
 
314
   if( !p )
 
315
   {
 
316
      InfoLog(<< "Error reading PCAP file " << file << ": " << errbuff);
 
317
      return;
 
318
   }
 
319
 
 
320
   while( 1 )
 
321
   {
 
322
      struct pcap_pkthdr h;
 
323
      const u_char* pkt = pcap_next(p, &h);
 
324
 
 
325
      if( NULL == pkt )
 
326
         break;
 
327
 
 
328
      int len = h.len;
 
329
 
 
330
      if( len < OVERHEAD_SIZE )
 
331
         continue;
 
332
 
 
333
      Packet packet(h.ts, Data(pkt + OVERHEAD_SIZE, len - OVERHEAD_SIZE));
 
334
 
 
335
      if( isRtpPacket(packet.mData, ssrc) )
 
336
         mPacketsRtp.push_back(packet);
 
337
      else if( isRtcpPacket(packet.mData, ssrc) )
 
338
         mPacketsRtcp.push_back(packet);
 
339
   };
 
340
 
 
341
   pcap_close(p);
 
342
 
 
343
   InfoLog( << "RTP/RTCP packets read: " << mPacketsRtp.size() << "/" << mPacketsRtcp.size());
 
344
 
 
345
   RtpPacketInfo();
 
346
 
 
347
#else
 
348
   InfoLog(<< "Reading pcap files disabled");
 
349
   assert(0);
 
350
#endif
 
351
}
 
352
 
 
353
int
 
354
TestRtp::bindSocket(resip::Socket fd, Tuple& addr)
 
355
{
 
356
   if( ::bind( fd, &addr.getMutableSockaddr(), addr.length()) == SOCKET_ERROR )
 
357
   {
 
358
      int e = getErrno();
 
359
      if ( e == EADDRINUSE )
 
360
         ErrLog (<< "Address already in use " << addr);
 
361
      else
 
362
         ErrLog (<< "Could not bind socket to " << addr);
 
363
 
 
364
      return -1;
 
365
   }
 
366
 
 
367
   bool ok = makeSocketNonBlocking(fd);
 
368
   if( !ok )
 
369
   {
 
370
      ErrLog (<< "Could not make socket non-blocking ");
 
371
      return -1;
 
372
   }
 
373
 
 
374
   return 0;
 
375
}
 
376
 
 
377
void
 
378
TestRtp::bind()
 
379
{
 
380
   bindSocket(mFdRtp, mLocalAddrRtp);
 
381
   bindSocket(mFdRtcp, mLocalAddrRtcp);
 
382
 
 
383
   DebugLog(<< "Binding RTP socket to " << mLocalAddrRtp);
 
384
   DebugLog(<< "Binding RTCP socket to " << mLocalAddrRtcp);
 
385
 
 
386
   bindSocket(mFdVideoRtp, mLocalAddrVideoRtp);
 
387
   bindSocket(mFdVideoRtcp, mLocalAddrVideoRtcp);
 
388
 
 
389
   DebugLog(<< "Binding RTP socket to " << mLocalAddrVideoRtp);
 
390
   DebugLog(<< "Binding RTCP socket to " << mLocalAddrVideoRtcp);
 
391
}
 
392
 
 
393
Data
 
394
TestRtp::recvPacket(resip::Socket fd, Tuple& addr)
 
395
{
 
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 )
 
400
   {
 
401
      int e = getErrno();
 
402
      InfoLog(<< "Socket read error: " << strerror(e));
 
403
   }
 
404
 
 
405
   if (len == 0 || len == SOCKET_ERROR)
 
406
   {
 
407
      delete[] buffer;
 
408
      buffer=0;
 
409
      return Data::Empty;
 
410
   }
 
411
 
 
412
   return Data(Data::Take, buffer, len);
 
413
}
 
414
 
 
415
bool
 
416
TestRtp::parsePacket(const Data& data)
 
417
{
 
418
   if( data.size() < RTP_HEADER_SIZE )
 
419
   {
 
420
      InfoLog(<< "Invalid RTP message received of size: " << (unsigned int) data.size());
 
421
      return false;
 
422
   }
 
423
 
 
424
   // !jv! for now, assume that RTP header is 12 bytes
 
425
   const RtpHeader& header = *((const RtpHeader*)data.data());
 
426
 
 
427
   UInt8 remoteCodec = header.mPayloadType & 0x7f;
 
428
   bool matchAudio = false;
 
429
   bool matchVideo = false;
 
430
 
 
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.
 
433
   //
 
434
   for (list<Medium>::iterator it = mLocalSdp->session().media().begin(); it != mLocalSdp->session().media().end(); it++)
 
435
   {
 
436
      for( list<Codec>::const_iterator j = it->codecs().begin(); j != it->codecs().end(); j++ )
 
437
      {
 
438
         if (remoteCodec == j->payloadType())
 
439
         {
 
440
            if (it->name() == SdpHelper::AudioMediaType)
 
441
               matchAudio = true;
 
442
            else if (it->name() == SdpHelper::VideoMediaType)
 
443
               matchVideo = true;
 
444
         }
 
445
      }
 
446
   }
 
447
 
 
448
   if( !(matchAudio || matchVideo) )
 
449
   {
 
450
      InfoLog(<< "Invalid payload type received: " << remoteCodec << " of size " << (unsigned int) data.size());
 
451
      return false;
 
452
   }
 
453
 
 
454
   UInt32 remoteSsrc = ntohl(header.mSsrc);
 
455
   if( 0 == mRemoteSsrc )
 
456
   {
 
457
      InfoLog(<< "TestRtp::parsePacket():  RTP strem started");
 
458
//      handleEvent(new RtpEvent(this, Rtp_StreamStarted));
 
459
      mRemoteSsrc = remoteSsrc;
 
460
      mRemoteCodec = remoteCodec;
 
461
   }
 
462
 
 
463
   if( remoteSsrc != mRemoteSsrc )
 
464
   {
 
465
      InfoLog(<< "TestRtp::parsePacket(): SSRC changed to " << remoteSsrc);
 
466
//      handleEvent(new RtpEvent(this, Rtp_SsrcChanged));
 
467
      mRemoteSsrc = remoteSsrc;
 
468
   }
 
469
 
 
470
   if( mRemoteCodec !=  remoteCodec )
 
471
   {
 
472
//      handleEvent(new RtpEvent(this, Rtp_CodecChanged));
 
473
      mRemoteCodec = remoteCodec;
 
474
   }
 
475
 
 
476
   mReceiverStatistics.mReceived++;
 
477
 
 
478
   return true;
 
479
}
 
480
 
 
481
void
 
482
TestRtp::overrideSsrc(Data& packet)
 
483
{
 
484
   RtpHeader& header = *((RtpHeader*)packet.data());
 
485
   header.mSsrc = htonl(mLocalSsrc);
 
486
}
 
487
 
 
488
void
 
489
TestRtp::sendPacket(resip::Socket fd, Tuple& dest, const Data& data)
 
490
{
 
491
   size_t count = sendto(fd, data.data(), (int) data.size(), 0, &dest.getSockaddr(), dest.length());
 
492
 
 
493
   if( count == (size_t)SOCKET_ERROR )
 
494
   {
 
495
      int e = getErrno();
 
496
      ErrLog(<< "Failed to send packet to " << dest << ": " << strerror(e));
 
497
   }
 
498
   else
 
499
   {
 
500
      if( count != data.size() )
 
501
         ErrLog(<< "Buffer overflow while sending packet to " << dest);
 
502
   }
 
503
 
 
504
   mSenderStatistics.mSent++;
 
505
}
 
506
 
 
507
// ----------------------------------------------------------------------------
 
508
boost::shared_ptr<SdpContents>
 
509
TestRtp::getLocalSdp() const
 
510
{
 
511
   return getLocalSdp(MEDIA_ACTIVE, MEDIA_ACTIVE);
 
512
}
 
513
 
 
514
// ----------------------------------------------------------------------------
 
515
boost::shared_ptr<SdpContents>
 
516
TestRtp::getLocalSdp(unsigned long audioAttr, unsigned long videoAttr) const
 
517
{
 
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);
 
523
 
 
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);
 
527
 
 
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;
 
532
 
 
533
   int audioPort = mLocalAddrRtp.getPort();
 
534
   int offset = 0;
 
535
 
 
536
   // for each m-line in the session, set here:
 
537
   // * port
 
538
   // * media-direction
 
539
   //
 
540
   for (list<Medium>::iterator it = sdp->session().media().begin(); it != sdp->session().media().end(); it++)
 
541
   {
 
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;
 
548
      else
 
549
         continue;
 
550
 
 
551
      // port
 
552
      if ((mediaAttr & MEDIA_DISABLE))
 
553
      {
 
554
         mline.port() = 0;
 
555
      }
 
556
      else
 
557
      {
 
558
         mline.port() = audioPort + offset;
 
559
         offset += 2;
 
560
      }
 
561
 
 
562
      // media-direction
 
563
      if (! mHold2543)
 
564
      {
 
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");
 
573
      }
 
574
 
 
575
      if (mPtime && (mline.name() == SdpHelper::AudioMediaType))
 
576
         mline.addAttribute("ptime:" + Data(mPtime));
 
577
   }
 
578
 
 
579
   return sdp;
 
580
}
 
581
 
 
582
void
 
583
TestRtp::setLocalAddr(const Uri& addr)
 
584
{
 
585
   int port = addr.port();
 
586
   Tuple t(addr.host(), port, (DnsUtil::isIpV6Address(addr.host()) ? V6 : V4), UDP);
 
587
   mLocalAddrRtp = t;
 
588
   t.setPort(port + 1);
 
589
   mLocalAddrRtcp = t;
 
590
   t.setPort(port + 2);
 
591
   mLocalAddrVideoRtp = t;
 
592
   t.setPort(port + 3);
 
593
   mLocalAddrVideoRtcp = t;
 
594
}
 
595
 
 
596
void
 
597
TestRtp::setLocalAddr(const Data& addr)
 
598
{
 
599
   int port =  mLocalAddrRtp.getPort();
 
600
   Tuple t(addr, port, (DnsUtil::isIpV6Address(addr) ? V6 : V4), UDP);
 
601
   mLocalAddrRtp = t;
 
602
   t.setPort(port + 1);
 
603
   mLocalAddrRtcp = t;
 
604
   t.setPort(port + 2);
 
605
   mLocalAddrVideoRtp = t;
 
606
   t.setPort(port + 3);
 
607
   mLocalAddrVideoRtcp = t;
 
608
}
 
609
 
 
610
void
 
611
TestRtp::addCodec(
 
612
   const resip::Data& mediaName,
 
613
   const resip::Data& codecName,
 
614
   int payload,
 
615
   int rate,
 
616
   const resip::Data& parameters,
 
617
   int port,
 
618
   const char * proto)
 
619
{
 
620
   if (mediaName.empty())
 
621
      return;
 
622
 
 
623
   if (! mLocalSdp)
 
624
      mLocalSdp = boost::shared_ptr<SdpContents>(new SdpContents());
 
625
 
 
626
   Medium * medium = 0;
 
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++)
 
629
   {
 
630
      if (it->name() == mediaName)
 
631
         medium = &(*it);
 
632
   }
 
633
 
 
634
   if (! medium)
 
635
   {
 
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();
 
640
   }
 
641
 
 
642
   if (mDescribeWellKnownCodec)
 
643
   {
 
644
      Codec codec(codecName, payload, rate);
 
645
      codec.parameters() = parameters;
 
646
      medium->codecs().push_back(codec);
 
647
   }
 
648
   else
 
649
   {
 
650
      Data strPayload = Data::from(payload);
 
651
      medium->addFormat(strPayload);
 
652
      // describe telephone-event anyhow
 
653
      if (codecName == "telephone-event")
 
654
      {
 
655
         Data strRTPMap;
 
656
         {
 
657
            DataStream s(strRTPMap);
 
658
            s <<strPayload <<' ' <<codecName <<'/' <<rate;
 
659
         }
 
660
         medium->addAttribute("rtpmap", strRTPMap);
 
661
         if (! parameters.empty())
 
662
            medium->addAttribute("fmtp", (strPayload + " " + parameters));
 
663
      }
 
664
   }
 
665
}
 
666
 
 
667
 
 
668
void
 
669
TestRtp::addControlMLine()
 
670
{
 
671
   Medium medium(SdpHelper::ControlMediaType, 0, 0, SdpHelper::TcpMcProtocol);
 
672
   mLocalSdp->session().addMedium(medium);
 
673
}
 
674
 
 
675
void
 
676
TestRtp::removeCodecs(const resip::Data& mediaName)
 
677
{
 
678
   if (mLocalSdp)
 
679
   {
 
680
      if (mediaName.empty())
 
681
      {
 
682
         mLocalSdp->session().media().clear();
 
683
      }
 
684
      else
 
685
      {
 
686
         for (list<Medium>::iterator it = mLocalSdp->session().media().begin(); it != mLocalSdp->session().media().end();)
 
687
         {
 
688
            list<Medium>::iterator prev = it++;
 
689
            if (prev->name() == mediaName)
 
690
               mLocalSdp->session().media().erase(prev);
 
691
         }
 
692
      }
 
693
   }
 
694
}
 
695
 
 
696
void
 
697
TestRtp::setRemoteAddr(const Tuple& addr)
 
698
{
 
699
   mRemoteAddrRtp = addr;
 
700
   mRemoteAddrRtcp = addr;
 
701
   int port = mRemoteAddrRtp.getPort();
 
702
   mRemoteAddrRtcp.setPort(port + 1);
 
703
}
 
704
 
 
705
void
 
706
TestRtp::enableSendingDelegate(bool enable)
 
707
{
 
708
   DebugLog(<< "enableSendingDelegate()");
 
709
   mSendPackets = enable;
 
710
}
 
711
 
 
712
 
 
713
///////////////////////////////////////////////////////////////////////////////
 
714
///////////////////////////////////////////////////////////////////////////////
 
715
 
 
716
resip::Data SdpHelper::AudioMediaType = "audio";
 
717
resip::Data SdpHelper::VideoMediaType = "video";
 
718
resip::Data SdpHelper::ControlMediaType = "control";
 
719
 
 
720
resip::Data SdpHelper::RtpAvpProtocol = "RTP/AVP";
 
721
resip::Data SdpHelper::TcpMcProtocol = "tcp mc";
 
722
 
 
723
SdpHelper::MediaDirection
 
724
SdpHelper::getMediaDirectionFromString(const char * szMediaName)
 
725
{
 
726
   if (szMediaName)
 
727
   {
 
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;
 
733
   }
 
734
   return MD_None;
 
735
}
 
736
 
 
737
SdpHelper::MediaDirection
 
738
SdpHelper::getMediaDirection(boost::shared_ptr<resip::SipMessage> msg, const char * szMediaName)
 
739
{
 
740
   SdpContents* sdp = dynamic_cast<SdpContents*>(msg->getContents());
 
741
   if (!sdp || !szMediaName)
 
742
      return MD_None;
 
743
   for (list<Medium>::const_iterator it = sdp->session().media().begin(); it != sdp->session().media().end(); it++)
 
744
   {
 
745
      if (it->name() == szMediaName)
 
746
      {
 
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;
 
751
      }
 
752
   }
 
753
   return MD_None;
 
754
}
 
755
 
 
756
 
 
757
bool
 
758
SdpHelper::hasIce(boost::shared_ptr<SipMessage> msg)
 
759
{
 
760
   SdpContents* sdp = dynamic_cast<SdpContents*>(msg->getContents());
 
761
   if( NULL == sdp )
 
762
      return false;
 
763
 
 
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() )
 
768
      return false;
 
769
 
 
770
   if( it->exists("alt") )
 
771
      return true;
 
772
 
 
773
   if( it->exists("candidate") )
 
774
      return true;
 
775
 
 
776
   return false;
 
777
}
 
778
 
 
779
Data 
 
780
SdpHelper::getConnectionAddr(boost::shared_ptr<resip::SipMessage> msg)
 
781
{
 
782
   SdpContents* sdp = dynamic_cast<SdpContents*>(msg->getContents());
 
783
   if( NULL == sdp )
 
784
   {
 
785
      return "0.0.0.0";
 
786
   }
 
787
 
 
788
   return sdp->session().connection().getAddress();
 
789
}
 
790
 
 
791
int
 
792
SdpHelper::getPort(boost::shared_ptr<resip::SipMessage> msg, unsigned int index)
 
793
{
 
794
   SdpContents* sdp = dynamic_cast<SdpContents*>(msg->getContents());
 
795
   if( NULL == sdp )
 
796
   {
 
797
      return -1;
 
798
   }
 
799
 
 
800
   list<SdpContents::Session::Medium> media = sdp->session().media();
 
801
   if( media.size() < index + 1 )
 
802
      return -1;
 
803
 
 
804
   list<SdpContents::Session::Medium>::iterator it = media.begin();
 
805
   for( unsigned int i = 0; i < index; it++, i++ );
 
806
   
 
807
   return it->port();
 
808
}
 
809
 
 
810
int
 
811
SdpHelper::getPort(boost::shared_ptr<resip::SipMessage> msg, const char * szMediaName)
 
812
{
 
813
   SdpContents* sdp = dynamic_cast<SdpContents*>(msg->getContents());
 
814
   if (!sdp || !szMediaName)
 
815
      return -1;
 
816
   for (list<Medium>::const_iterator it = sdp->session().media().begin(); it != sdp->session().media().end(); it++)
 
817
   {
 
818
      if (it->name() == szMediaName)
 
819
         return it->port();
 
820
   }
 
821
   return -1;
 
822
}
 
823
 
 
824
void
 
825
SdpHelper::setPort(boost::shared_ptr<resip::SdpContents> sdp, const char * szMediaName, unsigned long port)
 
826
{
 
827
   if (!sdp || !szMediaName)
 
828
      return;
 
829
   for (list<Medium>::iterator it = sdp->session().media().begin(); it != sdp->session().media().end(); it++)
 
830
   {
 
831
      if (it->name() == szMediaName)
 
832
      {
 
833
         it->port() = port;
 
834
         break;
 
835
      }
 
836
   }
 
837
}
 
838
 
 
839
void SdpHelper::addAttr(
 
840
   boost::shared_ptr<resip::SdpContents> sdp,
 
841
   const char * szMediaName,
 
842
   const char* szAttrField,
 
843
   const char* szAttrValue)
 
844
{
 
845
   if (!sdp || !szMediaName || !szAttrField || !szAttrValue)
 
846
      return;
 
847
   for (list<Medium>::iterator it = sdp->session().media().begin(); it != sdp->session().media().end(); it++)
 
848
   {
 
849
      if (it->name() == szMediaName)
 
850
      {
 
851
         it->addAttribute(szAttrField, szAttrValue);
 
852
         break;
 
853
      }
 
854
   }
 
855
}
 
856
 
 
857
bool
 
858
SdpHelper::isMediaInactive(boost::shared_ptr<SipMessage> msg)
 
859
{
 
860
   SdpContents* sdp = dynamic_cast<SdpContents*>(msg->getContents());
 
861
   if( NULL == sdp )
 
862
      return false;
 
863
 
 
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() )
 
868
      return false;
 
869
 
 
870
   if( it->exists("inactive") )
 
871
      return true;
 
872
 
 
873
   return false;
 
874
}
 
875
 
 
876
bool
 
877
SdpHelper::isMediaSendOnly(boost::shared_ptr<SipMessage> msg)
 
878
{
 
879
   SdpContents* sdp = dynamic_cast<SdpContents*>(msg->getContents());
 
880
   if( NULL == sdp )
 
881
      return false;
 
882
 
 
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() )
 
887
      return false;
 
888
 
 
889
   if( it->exists("sendonly") )
 
890
      return true;
 
891
 
 
892
   return false;
 
893
}
 
894
 
 
895
bool
 
896
SdpHelper::isMediaRecvOnly(boost::shared_ptr<SipMessage> msg)
 
897
{
 
898
   SdpContents* sdp = dynamic_cast<SdpContents*>(msg->getContents());
 
899
   if( NULL == sdp )
 
900
      return false;
 
901
 
 
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() )
 
906
      return false;
 
907
 
 
908
   if( it->exists("recvonly") )
 
909
      return true;
 
910
 
 
911
   return false;
 
912
}
 
913
 
 
914
unsigned int
 
915
SdpHelper::getMediaCount(boost::shared_ptr<resip::SipMessage> msg)
 
916
{
 
917
   SdpContents* sdp = dynamic_cast<SdpContents*>(msg->getContents());
 
918
   if (! sdp)
 
919
      return 0;
 
920
   return (unsigned int) sdp->session().media().size();
 
921
}
 
922
 
 
923
// m-line
 
924
unsigned int
 
925
SdpHelper::getMLineCount(boost::shared_ptr<resip::SipMessage> msg, const char * szMediaName)
 
926
{
 
927
   unsigned int ret = 0;
 
928
   SdpContents* sdp = dynamic_cast<SdpContents*>(msg->getContents());
 
929
   if (! sdp)
 
930
      return 0;
 
931
   for (list<Medium>::const_iterator it = sdp->session().media().begin(); it != sdp->session().media().end(); it++)
 
932
   {
 
933
      if (it->name() == szMediaName)
 
934
         ret++;
 
935
   }
 
936
   return ret;
 
937
}
 
938
 
 
939
unsigned int
 
940
SdpHelper::getCodecsCount(boost::shared_ptr<resip::SipMessage> msg, const char * szMediaName)
 
941
{
 
942
   SdpContents* sdp = dynamic_cast<SdpContents*>(msg->getContents());
 
943
   if (! sdp)
 
944
      return 0;
 
945
   for (list<Medium>::const_iterator it = sdp->session().media().begin(); it != sdp->session().media().end(); it++)
 
946
   {
 
947
      if (it->name() == szMediaName)
 
948
         return (unsigned int) it->codecs().size();
 
949
   }
 
950
   return 0;
 
951
}
 
952
 
 
953
bool
 
954
SdpHelper::hasPayloadNumber(boost::shared_ptr<resip::SipMessage> msg, int payloadNumber)
 
955
{
 
956
   SdpContents* sdp = dynamic_cast<SdpContents*>(msg->getContents());
 
957
   if (! sdp)
 
958
      return false;
 
959
   for (list<Medium>::const_iterator it = sdp->session().media().begin(); it != sdp->session().media().end(); it++)
 
960
   {
 
961
      for( list<Codec>::const_iterator jIt = it->codecs().begin(); jIt != it->codecs().end(); jIt++ )
 
962
      {
 
963
         if (jIt->payloadType() == payloadNumber)
 
964
            return true;
 
965
      }
 
966
   }
 
967
   return false;
 
968
}
 
969
 
 
970
bool
 
971
SdpHelper::isHold2543(boost::shared_ptr<SipMessage> msg)
 
972
{
 
973
   SdpContents* sdp = dynamic_cast<SdpContents*>(msg->getContents());
 
974
   if( NULL == sdp )
 
975
      return false;
 
976
 
 
977
   SdpContents::Session::Connection connection = sdp->session().connection();
 
978
   Data addr = connection.getAddress();
 
979
   return addr == "0.0.0.0";
 
980
}
 
981
 
 
982
void
 
983
TestRtp::thread()
 
984
{
 
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
 
992
 
 
993
   // time_t lastRtcp = time(NULL);
 
994
   struct timeval lastPacketTime;
 
995
   if( !mPacketsRtp.empty() )
 
996
      lastPacketTime = mPacketsRtp.front().mTimeStamp;
 
997
#ifdef USE_XS_TIME
 
998
   double lastSendingTime = XsLib::XsGetClockTickUs();
 
999
#elif !defined(WIN32)
 
1000
   struct timeval lastSendingTime;
 
1001
   gettimeofday(&lastSendingTime, 0);
 
1002
#endif
 
1003
 
 
1004
   while( !isShutdown() )
 
1005
   {
 
1006
      FdSet fdSet;
 
1007
      fdSet.setRead(mFdRtp);
 
1008
      fdSet.setRead(mFdRtcp);
 
1009
 
 
1010
      /*int ready = */fdSet.selectMilliSeconds(RTP_INTERVAL);
 
1011
 
 
1012
      if( fdSet.readyToRead(mFdRtp) )
 
1013
      {
 
1014
         Tuple from;
 
1015
         Data data = recvPacket(mFdRtp, from);
 
1016
         if( 0 == mRemoteAddrRtp.getPort() )
 
1017
         {
 
1018
            InfoLog(<< "Updating RTP address changed to " << from);
 
1019
            mRemoteAddrRtp = from;
 
1020
         }
 
1021
         if( parsePacket(data) )
 
1022
         {
 
1023
//            overrideSsrc(data);
 
1024
//            sendPacket(mFdRtp, mRemoteAddrRtp, data);
 
1025
 
 
1026
            if( mSendPackets && !mPacketsRtp.empty() )
 
1027
            {
 
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");
 
1033
            }
 
1034
         }
 
1035
      }
 
1036
 
 
1037
/*
 
1038
      // rtcp
 
1039
      if( fdSet.readyToRead(mFdRtcp) )
 
1040
      {
 
1041
         Tuple from;
 
1042
         Data data = recvPacket(mFdRtcp, from);
 
1043
         if( !(mRemoteAddrRtcp == from) )
 
1044
         {
 
1045
            InfoLog(<< "Remote RTCP address changed to " << from);
 
1046
            mRemoteAddrRtcp = from;
 
1047
         }
 
1048
      }
 
1049
*/
 
1050
 
 
1051
#if 0
 
1052
      if( mSendPackets )
 
1053
      {
 
1054
         if( !mPacketsRtp.empty() )
 
1055
         {
 
1056
//               DebugLog(<< "Checking time to send RTP packet");
 
1057
 
 
1058
/*
 
1059
#ifdef USE_XS_TIME
 
1060
               double currentTime = XsLib::XsGetClockTickUs();
 
1061
               double elapsedTime = currentTime - lastSendingTime;
 
1062
#else
 
1063
               struct timeval currentTime;
 
1064
               gettimeofday(&currentTime, 0);
 
1065
               struct timeval elapsedTime;
 
1066
               timeval_subtract(&elapsedTime, &currentTime, &lastSendingTime);
 
1067
#endif
 
1068
  
 
1069
               struct timeval currentPacketTime = mPacketsRtp.front().mTimeStamp;
 
1070
               struct timeval packetDiffTime;
 
1071
               timeval_subtract(&packetDiffTime, &currentPacketTime, &lastPacketTime);
 
1072
 
 
1073
//               InfoLog( << "Packet diff: " << packetDiffTime.tv_sec << "." << packetDiffTime.tv_usec);
 
1074
 
 
1075
#ifdef USE_XS_TIME
 
1076
//               InfoLog(<< elapsedTime);
 
1077
               bool send = (packetDiffTime.tv_sec * 1000000 + packetDiffTime.tv_usec) >= elapsedTime;
 
1078
#else
 
1079
               struct timeval diff;
 
1080
               bool send = (timeval_subtract(&diff, &elapsedTime, &packetDiffTime) == 0);
 
1081
//               InfoLog( << "Elapsed: " << elapsedTime.tv_sec << "." << elapsedTime.tv_usec);
 
1082
#endif
 
1083
*/
 
1084
               bool send = true;
 
1085
               if( send )
 
1086
               {
 
1087
//                  DebugLog(<< "Sending RTP packet");
 
1088
 
 
1089
                  Packet packet = mPacketsRtp.front();
 
1090
                  mPacketsRtp.pop_front();
 
1091
                  sendPacket(mFdRtp, mRemoteAddrRtp, packet.mData);
 
1092
 
 
1093
/*               
 
1094
                  lastPacketTime = currentPacketTime;
 
1095
                  lastSendingTime = currentTime;
 
1096
*/
 
1097
               }
 
1098
         }
 
1099
 
 
1100
/*
 
1101
         if( 0 != ready )
 
1102
#ifdef WIN32
 
1103
            Sleep(RTP_INTERVAL);
 
1104
#else
 
1105
            usleep(RTP_INTERVAL * 1000);
 
1106
#endif
 
1107
*/
 
1108
 
 
1109
/*
 
1110
         if( !mPacketsRtcp.empty() )
 
1111
         {
 
1112
            if( time(NULL) > lastRtcp + RTCP_INTERVAL )
 
1113
            {
 
1114
               DebugLog(<< "Sending RTCP packet");
 
1115
               Packet packet = mPacketsRtcp.front();
 
1116
               mPacketsRtcp.pop_front();
 
1117
               sendPacket(mFdRtcp, mRemoteAddrRtcp, packet.mData);
 
1118
               lastRtcp = time(NULL);
 
1119
            }
 
1120
         }
 
1121
*/
 
1122
      }
 
1123
#endif
 
1124
   }
 
1125
}
 
1126
 
 
1127
TestEndPoint::ExpectBase*
 
1128
TestRtp::expect(RtpEvent::Type type,
 
1129
                 int timeoutMs,
 
1130
                 ActionBase* expectAction)
 
1131
{
 
1132
   InfoLog( << "TestRtp::expect()");
 
1133
   return new Expect(*this,
 
1134
                     new EventMatcherSpecific<RtpEvent>(type),
 
1135
                     timeoutMs,
 
1136
                     expectAction);
 
1137
}
 
1138
 
 
1139
ActionBase*
 
1140
TestRtp::enableSending(bool enable)
 
1141
{
 
1142
   DebugLog(<< "TestRtp::enableSending()");
 
1143
   return new CommonAction(this,
 
1144
      "Enable sending",
 
1145
       boost::bind(&TestRtp::enableSendingDelegate, this, enable));
 
1146
}