Coverage Report

Created: 2024-04-23 06:04

/src/resiprocate/resip/stack/SdpContents.cxx
Line
Count
Source (jump to first uncovered line)
1
#if defined(HAVE_CONFIG_H)
2
#include "config.h"
3
#endif
4
5
#include <algorithm>
6
7
#include "resip/stack/SdpContents.hxx"
8
#include "resip/stack/TrickleIceContents.hxx"
9
#include "resip/stack/Helper.hxx"
10
#include "rutil/ParseBuffer.hxx"
11
#include "rutil/DataStream.hxx"
12
#include "resip/stack/Symbols.hxx"
13
#include "rutil/Logger.hxx"
14
#include "rutil/WinLeakCheck.hxx"
15
16
#define RESIPROCATE_SUBSYSTEM resip::Subsystem::SDP
17
18
using namespace resip;
19
using namespace std;
20
21
const SdpContents::Session::Direction SdpContents::Session::Direction::INACTIVE("inactive", false, false);
22
const SdpContents::Session::Direction SdpContents::Session::Direction::SENDONLY("sendonly", true, false);
23
const SdpContents::Session::Direction SdpContents::Session::Direction::RECVONLY("recvonly", false, true);
24
const SdpContents::Session::Direction SdpContents::Session::Direction::SENDRECV("sendrecv", true, true);
25
26
const std::map<Data, std::reference_wrapper<const SdpContents::Session::Direction>> SdpContents::Session::Direction::directions = {
27
                           SdpContents::Session::Direction::INACTIVE.tuple(),
28
                           SdpContents::Session::Direction::SENDONLY.tuple(),
29
                           SdpContents::Session::Direction::RECVONLY.tuple(),
30
                           SdpContents::Session::Direction::SENDRECV.tuple()
31
                  };
32
33
const SdpContents SdpContents::Empty;
34
35
bool
36
SdpContents::init()
37
14
{
38
14
   static ContentsFactory<SdpContents> factory;
39
14
   (void)factory;
40
14
   return true;
41
14
}
42
43
const char* NetworkType[] = {"???", "IP4", "IP6"};
44
45
static const Data rtpmap("rtpmap");
46
static const Data fmtp("fmtp");
47
48
// RFC2327 6. page 9
49
// "parsers should be tolerant and accept records terminated with a single
50
// newline character"
51
void
52
resip::skipEol(ParseBuffer& pb)
53
207k
{
54
208k
   while(!pb.eof() && (*pb.position() == Symbols::SPACE[0] ||
55
207k
                       *pb.position() == Symbols::TAB[0]))
56
598
   {
57
598
      pb.skipChar();
58
598
   }
59
   
60
207k
   if (*pb.position() == Symbols::LF[0])
61
203k
   {
62
203k
      pb.skipChar();
63
203k
   }
64
4.03k
   else
65
4.03k
   {
66
      // allow extra 0x0d bytes.
67
7.12k
      while(*pb.position() == Symbols::CR[0])
68
3.09k
      {
69
3.09k
         pb.skipChar();
70
3.09k
      } 
71
4.03k
      pb.skipChar(Symbols::LF[0]);
72
4.03k
   }
73
   
74
207k
}
75
76
AttributeHelper::AttributeHelper(const AttributeHelper& rhs)
77
   : mAttributeList(rhs.mAttributeList),
78
     mAttributes(rhs.mAttributes)
79
9.89k
{
80
9.89k
}
81
82
AttributeHelper::AttributeHelper()
83
16.3k
{
84
16.3k
}
85
86
AttributeHelper&
87
AttributeHelper::operator=(const AttributeHelper& rhs)
88
0
{
89
0
   if (this != &rhs)
90
0
   {
91
0
      mAttributeList = rhs.mAttributeList;
92
0
      mAttributes = rhs.mAttributes;
93
0
   }
94
0
   return *this;
95
0
}
96
97
bool
98
AttributeHelper::exists(const Data& key) const
99
0
{
100
0
   return mAttributes.find(key) != mAttributes.end();
101
0
}
102
103
const list<Data>&
104
AttributeHelper::getValues(const Data& key) const
105
0
{
106
0
   if (!exists(key))
107
0
   {
108
0
      static const list<Data> emptyList;
109
0
      return emptyList;
110
0
   }
111
0
   return mAttributes.find(key)->second;
112
0
}
113
114
EncodeStream&
115
AttributeHelper::encode(EncodeStream& s) const
116
0
{
117
0
   for (std::list<std::pair<Data, Data> >::const_iterator i = mAttributeList.begin();
118
0
        i != mAttributeList.end(); ++i)
119
0
   {
120
0
      s << "a=" << i->first;
121
0
      if (!i->second.empty())
122
0
      {
123
0
         s << Symbols::COLON[0] << i->second;
124
0
      }
125
0
      s << Symbols::CRLF;
126
0
   }  
127
0
   return s;
128
0
}
129
130
void
131
AttributeHelper::parse(ParseBuffer& pb)
132
10.7k
{
133
176k
   while (!pb.eof() && *pb.position() == 'a')
134
165k
   {
135
165k
      Data key;
136
165k
      Data value;
137
138
165k
      pb.skipChar('a');
139
165k
      const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
140
165k
      pb.skipToOneOf(Symbols::COLON, Symbols::CRLF);
141
165k
      pb.data(key, anchor);
142
165k
      if (!pb.eof() && *pb.position() == Symbols::COLON[0])
143
3.56k
      {
144
3.56k
         anchor = pb.skipChar(Symbols::COLON[0]);
145
3.56k
         pb.skipToOneOf(Symbols::CRLF);
146
3.56k
         pb.data(value, anchor);
147
3.56k
      }
148
149
165k
      if(!pb.eof()) skipEol(pb);
150
151
165k
      mAttributeList.push_back(std::make_pair(key, value));
152
165k
      mAttributes[key].push_back(value);
153
165k
   }
154
10.7k
}
155
156
void
157
AttributeHelper::addAttribute(const Data& key, const Data& value)
158
0
{
159
0
   mAttributeList.push_back(std::make_pair(key, value));
160
0
   mAttributes[key].push_back(value);
161
0
}
162
163
void
164
AttributeHelper::clearAttribute(const Data& key)
165
0
{
166
0
   for (std::list<std::pair<Data, Data> >::iterator i = mAttributeList.begin();
167
0
        i != mAttributeList.end(); )
168
0
   {
169
0
      std::list<std::pair<Data, Data> >::iterator j = i++;
170
0
      if (j->first == key)
171
0
      {
172
0
         mAttributeList.erase(j);
173
0
      }
174
0
   }
175
0
   mAttributes.erase(key);
176
0
}
177
178
SdpContents::SdpContents() : Contents(getStaticType())
179
2
{
180
2
}
181
182
SdpContents::SdpContents(const HeaderFieldValue& hfv, const Mime& contentTypes)
183
   : Contents(hfv, contentTypes)
184
6.45k
{
185
6.45k
}
186
187
//SdpContents::SdpContents(const SdpContents& rhs)
188
//   : Contents(rhs),
189
//     mSession(rhs.mSession)
190
//{
191
//}
192
193
SdpContents::~SdpContents()
194
6.45k
{
195
6.45k
}
196
197
198
SdpContents&
199
SdpContents::operator=(const SdpContents& rhs)
200
0
{
201
0
   if (this != &rhs)
202
0
   {
203
0
      Contents::operator=(rhs);
204
0
      mSession = rhs.mSession;
205
0
   }
206
0
   return *this;
207
0
}
208
209
Contents*
210
SdpContents::clone() const
211
0
{
212
0
   return new SdpContents(*this);
213
0
}
214
215
void
216
SdpContents::parse(ParseBuffer& pb)
217
6.45k
{
218
6.45k
   mSession.parse(pb);
219
6.45k
}
220
221
EncodeStream&
222
SdpContents::encodeParsed(EncodeStream& s) const
223
0
{
224
0
   mSession.encode(s);
225
0
   return s;
226
0
}
227
228
const Mime&
229
SdpContents::getStaticType()
230
4
{
231
4
   static Mime type("application", "sdp");
232
4
   return type;
233
4
}
234
235
static Data nullOrigin("0.0.0.0");
236
237
SdpContents::Session::Origin::Origin()
238
   : mUser(),
239
     mSessionId(0),
240
     mVersion(0),
241
     mAddrType(IP4),
242
     mAddress(nullOrigin)
243
6.45k
{}
244
245
SdpContents::Session::Origin::Origin(const Origin& rhs)
246
   : mUser(rhs.mUser),
247
     mSessionId(rhs.mSessionId),
248
     mVersion(rhs.mVersion),
249
     mAddrType(rhs.mAddrType),
250
     mAddress(rhs.mAddress)
251
0
{
252
0
}
253
254
SdpContents::Session::Origin&
255
SdpContents::Session::Origin::operator=(const Origin& rhs)
256
0
{
257
0
   if (this != &rhs)
258
0
   {
259
0
      mUser = rhs.mUser;
260
0
      mSessionId = rhs.mSessionId;
261
0
      mVersion = rhs.mVersion;
262
0
      mAddrType = rhs.mAddrType;
263
0
      mAddress = rhs.mAddress;
264
0
   }
265
0
   return *this;
266
0
}
267
268
269
SdpContents::Session::Origin::Origin(const Data& user,
270
                                     const uint64_t& sessionId,
271
                                     const uint64_t& version,
272
                                     AddrType addr,
273
                                     const Data& address)
274
   : mUser(user),
275
     mSessionId(sessionId),
276
     mVersion(version),
277
     mAddrType(addr),
278
     mAddress(address)
279
0
{}
280
281
EncodeStream&
282
SdpContents::Session::Origin::encode(EncodeStream& s) const
283
0
{
284
0
   s << "o="
285
0
     << mUser << Symbols::SPACE[0]
286
0
     << mSessionId << Symbols::SPACE[0]
287
0
     << mVersion << Symbols::SPACE[0]
288
0
     << "IN "
289
0
     << NetworkType[mAddrType] << Symbols::SPACE[0]
290
0
     << mAddress << Symbols::CRLF;
291
0
   return s;
292
0
}
293
294
void
295
SdpContents::Session::Origin::setAddress(const Data& host, AddrType addr)
296
0
{
297
0
    mAddress = host;
298
0
    mAddrType = addr;
299
0
}
300
301
void
302
SdpContents::Session::Origin::parse(ParseBuffer& pb)
303
2.60k
{
304
2.60k
   pb.skipChar('o');
305
2.60k
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
306
307
2.60k
   pb.skipToChar(Symbols::SPACE[0]);
308
2.60k
   pb.data(mUser, anchor);
309
310
2.60k
   anchor = pb.skipChar(Symbols::SPACE[0]);
311
2.60k
   try
312
2.60k
   {
313
2.60k
      mSessionId = pb.uInt64();
314
2.60k
   }
315
2.60k
   catch(ParseException& e)
316
2.60k
   {
317
2.50k
       WarningLog(<< "Exception parsing origin sessionid: " << e);
318
2.50k
   }
319
2.60k
   pb.skipToChar(Symbols::SPACE[0]);
320
321
2.60k
   anchor = pb.skipChar(Symbols::SPACE[0]);
322
2.60k
   try
323
2.60k
   {
324
2.60k
      mVersion = pb.uInt64();
325
2.60k
   }
326
2.60k
   catch(ParseException& e)
327
2.60k
   {
328
2.46k
       WarningLog(<< "Exception parsing origin version: " << e);
329
2.46k
   }
330
2.60k
   pb.skipToChar(Symbols::SPACE[0]);
331
332
2.49k
   pb.skipChar(Symbols::SPACE[0]);
333
2.49k
   pb.skipChar('I');
334
2.49k
   pb.skipChar('N');
335
336
2.49k
   anchor = pb.skipChar(Symbols::SPACE[0]);
337
2.49k
   pb.skipToChar(Symbols::SPACE[0]);
338
2.49k
   Data addrType;
339
2.49k
   pb.data(addrType, anchor);
340
2.49k
   if (addrType == NetworkType[IP4])
341
1
   {
342
1
      mAddrType = IP4;
343
1
   }
344
2.49k
   else if (addrType == NetworkType[IP6])
345
1
   {
346
1
      mAddrType = IP6;
347
1
   }
348
2.49k
   else
349
2.49k
   {
350
2.49k
      mAddrType = static_cast<AddrType>(0);
351
2.49k
   }
352
353
2.49k
   anchor = pb.skipChar(Symbols::SPACE[0]);
354
2.49k
   pb.skipToOneOf(Symbols::CRLF);
355
2.49k
   pb.data(mAddress, anchor);
356
357
2.49k
   skipEol(pb);
358
2.49k
}
359
360
SdpContents::Session::Email::Email(const Data& address,
361
                                   const Data& freeText)
362
   : mAddress(address),
363
     mFreeText(freeText)
364
0
{}
365
366
SdpContents::Session::Email::Email(const Email& rhs)
367
   : mAddress(rhs.mAddress),
368
     mFreeText(rhs.mFreeText)
369
1.83k
{}
370
371
SdpContents::Session::Email&
372
SdpContents::Session::Email::operator=(const Email& rhs)
373
0
{
374
0
   if (this != &rhs)
375
0
   {
376
0
      mAddress = rhs.mAddress;
377
0
      mFreeText = rhs.mFreeText;
378
0
   }
379
0
   return *this;
380
0
}
381
382
EncodeStream&
383
SdpContents::Session::Email::encode(EncodeStream& s) const
384
0
{
385
0
   s << "e=" << mAddress;
386
0
   if (!mFreeText.empty())
387
0
   {
388
0
      s << Symbols::SPACE[0];
389
0
      s << Symbols::LPAREN[0] << mFreeText << Symbols::RPAREN[0];
390
0
   }
391
0
   s << Symbols::CRLF;
392
393
0
   return s;
394
0
}
395
396
// helper to parse email and phone numbers with display name
397
void parseEorP(ParseBuffer& pb, Data& eOrp, Data& freeText)
398
3.78k
{
399
   // =mjh@isi.edu (Mark Handley)
400
   // =mjh@isi.edu
401
   // =Mark Handley <mjh@isi.edu>
402
   // =<mjh@isi.edu>
403
404
3.78k
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
405
406
3.78k
   pb.skipToOneOf("<(\n\r");  // find a left angle bracket "<", a left paren "(", or a CR 
407
3.78k
   switch (*pb.position())
408
3.78k
   {
409
2.98k
      case '\n':          // Symbols::CR[0]
410
3.35k
      case '\r':          // Symbols::LF[0]
411
         // mjh@isi.edu
412
         //            ^
413
3.35k
         pb.data(eOrp, anchor);
414
3.35k
         break;
415
416
194
      case '<':         // Symbols::LA_QUOTE[0]
417
         // Mark Handley <mjh@isi.edu>
418
         //              ^
419
         // <mjh@isi.edu>
420
         // ^
421
        
422
194
         pb.data(freeText, anchor);
423
194
         anchor = pb.skipChar();
424
194
         pb.skipToEndQuote(Symbols::RA_QUOTE[0]);
425
194
         pb.data(eOrp, anchor);
426
194
         pb.skipChar(Symbols::RA_QUOTE[0]);
427
194
         break;
428
        
429
194
      case '(':         // Symbols::LPAREN[0]
430
         // mjh@isi.edu (Mark Handley)
431
         //             ^
432
        
433
194
         pb.data(eOrp, anchor);
434
194
         anchor = pb.skipChar();
435
194
         pb.skipToEndQuote(Symbols::RPAREN[0]);
436
194
         pb.data(freeText, anchor);
437
194
         pb.skipChar(Symbols::RPAREN[0]);
438
194
         break;
439
0
      default:
440
0
         resip_assert(0);
441
3.78k
   }
442
3.78k
}
443
444
void
445
SdpContents::Session::Email::parse(ParseBuffer& pb)
446
1.83k
{
447
1.83k
   pb.skipChar('e');
448
1.83k
   parseEorP(pb, mAddress, mFreeText);
449
1.83k
   skipEol(pb);
450
1.83k
}
451
452
SdpContents::Session::Phone::Phone(const Data& number,
453
                                   const Data& freeText)
454
   : mNumber(number),
455
     mFreeText(freeText)
456
0
{}
457
458
SdpContents::Session::Phone::Phone(const Phone& rhs)
459
   : mNumber(rhs.mNumber),
460
     mFreeText(rhs.mFreeText)
461
1.95k
{}
462
463
SdpContents::Session::Phone&
464
SdpContents::Session::Phone::operator=(const Phone& rhs)
465
0
{
466
0
   if (this != &rhs)
467
0
   {
468
0
      mNumber = rhs.mNumber;
469
0
      mFreeText = rhs.mFreeText;
470
0
   }
471
0
   return *this;
472
0
}
473
474
EncodeStream&
475
SdpContents::Session::Phone::encode(EncodeStream& s) const
476
0
{
477
0
  s << "p=" << mNumber;
478
0
   if (!mFreeText.empty())
479
0
   {
480
0
      s << Symbols::SPACE[0];
481
0
      s << Symbols::LPAREN[0] << mFreeText << Symbols::RPAREN[0];
482
0
   }
483
0
   s << Symbols::CRLF;
484
485
0
   return s;
486
0
}
487
488
void
489
SdpContents::Session::Phone::parse(ParseBuffer& pb)
490
1.95k
{
491
1.95k
   pb.skipChar('p');
492
1.95k
   parseEorP(pb, mNumber, mFreeText);
493
1.95k
   skipEol(pb);
494
1.95k
}
495
496
SdpContents::Session::Connection::Connection(AddrType addType,
497
                                             const Data& address,
498
                                             unsigned long ttl)
499
   : mAddrType(addType),
500
     mAddress(address),
501
     mTTL(ttl)
502
0
{}
503
504
SdpContents::Session::Connection::Connection()
505
   : mAddrType(IP4),
506
     mAddress(),
507
     mTTL(0)
508
21.4k
{}
509
510
SdpContents::Session::Connection::Connection(const Connection& rhs)
511
   : mAddrType(rhs.mAddrType),
512
     mAddress(rhs.mAddress),
513
     mTTL(rhs.mTTL)
514
130k
{
515
130k
}
516
517
SdpContents::Session::Connection&
518
SdpContents::Session::Connection::operator=(const Connection& rhs)
519
0
{
520
0
   if (this != &rhs)
521
0
   {
522
0
      mAddrType = rhs.mAddrType;
523
0
      mAddress = rhs.mAddress;
524
0
      mTTL = rhs.mTTL;
525
0
   }
526
0
   return *this;
527
0
}
528
529
EncodeStream&
530
SdpContents::Session::Connection::encode(EncodeStream& s) const
531
0
{
532
0
   s << "c=IN "
533
0
     << NetworkType[mAddrType] << Symbols::SPACE[0] << mAddress;
534
535
0
   if (mTTL)
536
0
   {
537
0
      s << Symbols::SLASH[0] << mTTL;
538
0
   }
539
0
   s << Symbols::CRLF;
540
0
   return s;
541
0
}
542
543
void
544
SdpContents::Session::Connection::setAddress(const Data& host, AddrType addr)
545
0
{
546
0
    mAddress = host;
547
0
    mAddrType = addr;
548
0
}
549
550
void
551
SdpContents::Session::Connection::parse(ParseBuffer& pb)
552
15.0k
{
553
15.0k
   pb.skipChar('c');
554
15.0k
   pb.skipChar(Symbols::EQUALS[0]);
555
15.0k
   pb.skipChar('I');
556
15.0k
   pb.skipChar('N');
557
558
15.0k
   const char* anchor = pb.skipChar(Symbols::SPACE[0]);
559
15.0k
   pb.skipToChar(Symbols::SPACE[0]);
560
15.0k
   Data addrType;
561
15.0k
   pb.data(addrType, anchor);
562
15.0k
   if (addrType == NetworkType[IP4])
563
448
   {
564
448
      mAddrType = IP4;
565
448
   }
566
14.6k
   else if (addrType == NetworkType[IP6])
567
195
   {
568
195
      mAddrType = IP6;
569
195
   }
570
14.4k
   else
571
14.4k
   {
572
14.4k
      mAddrType = static_cast<AddrType>(0);
573
14.4k
   }
574
575
15.0k
   anchor = pb.skipChar();
576
15.0k
   pb.skipToOneOf(Symbols::SLASH, Symbols::CRLF);
577
15.0k
   pb.data(mAddress, anchor);
578
579
15.0k
   mTTL = 0;
580
15.0k
   if (mAddrType == IP4 && !pb.eof() && *pb.position() == Symbols::SLASH[0])
581
243
   {
582
243
      pb.skipChar();
583
243
      mTTL = pb.integer();
584
243
   }
585
586
   // multicast dealt with above this parser
587
15.0k
   if (!pb.eof() && *pb.position() != Symbols::SLASH[0])
588
2.64k
   {
589
2.64k
      skipEol(pb);
590
2.64k
   }
591
15.0k
}
592
593
SdpContents::Session::Bandwidth::Bandwidth(const Data& modifier,
594
                                           unsigned long kbPerSecond)
595
   : mModifier(modifier),
596
     mKbPerSecond(kbPerSecond)
597
0
{}
598
599
SdpContents::Session::Bandwidth::Bandwidth(const Bandwidth& rhs)
600
   : mModifier(rhs.mModifier),
601
     mKbPerSecond(rhs.mKbPerSecond)
602
1.78k
{}
603
604
SdpContents::Session::Bandwidth&
605
SdpContents::Session::Bandwidth::operator=(const Bandwidth& rhs)
606
0
{
607
0
   if (this != &rhs)
608
0
   {
609
0
      mModifier = rhs.mModifier;
610
0
      mKbPerSecond = rhs.mKbPerSecond;
611
0
   }
612
0
   return *this;
613
0
}
614
615
EncodeStream&
616
SdpContents::Session::Bandwidth::encode(EncodeStream& s) const
617
0
{
618
0
   s << "b="
619
0
     << mModifier
620
0
     << Symbols::COLON[0] << mKbPerSecond
621
0
     << Symbols::CRLF;
622
0
   return s;
623
0
}
624
625
void
626
SdpContents::Session::Bandwidth::parse(ParseBuffer& pb)
627
1.78k
{
628
1.78k
   pb.skipChar('b');
629
1.78k
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
630
631
1.78k
   pb.skipToOneOf(Symbols::COLON, Symbols::CRLF);
632
1.78k
   if (*pb.position() == Symbols::COLON[0])
633
1.74k
   {
634
1.74k
      pb.data(mModifier, anchor);
635
636
1.74k
      anchor = pb.skipChar(Symbols::COLON[0]);
637
1.74k
      mKbPerSecond = pb.integer();
638
639
1.74k
      skipEol(pb);
640
1.74k
   }
641
44
   else
642
44
   {
643
44
      pb.fail(__FILE__, __LINE__);
644
44
   }
645
1.78k
}
646
647
SdpContents::Session::Time::Time(unsigned long start,
648
                                 unsigned long stop)
649
   : mStart(start),
650
     mStop(stop)
651
0
{}
652
653
SdpContents::Session::Time::Time(const Time& rhs)
654
   : mStart(rhs.mStart),
655
     mStop(rhs.mStop)
656
1.30k
{}
657
658
SdpContents::Session::Time&
659
SdpContents::Session::Time::operator=(const Time& rhs)
660
0
{
661
0
   if (this != &rhs)
662
0
   {
663
0
      mStart = rhs.mStart;
664
0
      mStop = rhs.mStop;
665
0
      mRepeats = rhs.mRepeats;
666
0
   }
667
0
   return *this;
668
0
}
669
670
EncodeStream&
671
SdpContents::Session::Time::encode(EncodeStream& s) const
672
0
{
673
0
   s << "t=" << mStart << Symbols::SPACE[0]
674
0
     << mStop
675
0
     << Symbols::CRLF;
676
677
0
   for (list<Repeat>::const_iterator i = mRepeats.begin();
678
0
        i != mRepeats.end(); ++i)
679
0
   {
680
0
      i->encode(s);
681
0
   }
682
0
   return s;
683
0
}
684
685
void
686
SdpContents::Session::Time::parse(ParseBuffer& pb)
687
1.30k
{
688
1.30k
   pb.skipChar('t');
689
1.30k
   pb.skipChar(Symbols::EQUALS[0]);
690
691
1.30k
   mStart = pb.uInt32();
692
1.30k
   pb.skipChar(Symbols::SPACE[0]);
693
1.30k
   mStop = pb.uInt32();
694
695
1.30k
   skipEol(pb);
696
697
3.07k
   while (!pb.eof() && *pb.position() == 'r')
698
1.76k
   {
699
1.76k
      addRepeat(Repeat());
700
1.76k
      mRepeats.back().parse(pb);
701
1.76k
   }
702
1.30k
}
703
704
void
705
SdpContents::Session::Time::addRepeat(const Repeat& repeat)
706
1.76k
{
707
1.76k
   mRepeats.push_back(repeat);
708
1.76k
}
709
710
SdpContents::Session::Time::Repeat::Repeat(unsigned long interval,
711
                                           unsigned long duration,
712
                                           list<int> offsets)
713
   : mInterval(interval),
714
     mDuration(duration),
715
     mOffsets(offsets)
716
0
{}
717
718
EncodeStream&
719
SdpContents::Session::Time::Repeat::encode(EncodeStream& s) const
720
0
{
721
0
   s << "r="
722
0
     << mInterval << Symbols::SPACE[0]
723
0
     << mDuration << 's';
724
0
   for (list<int>::const_iterator i = mOffsets.begin();
725
0
        i != mOffsets.end(); ++i)
726
0
   {
727
0
      s << Symbols::SPACE[0] << *i << 's';
728
0
   }
729
730
0
   s << Symbols::CRLF;
731
0
   return s;
732
0
}
733
734
int
735
parseTypedTime(ParseBuffer& pb)
736
82.5k
{
737
82.5k
   int v = pb.integer();
738
82.5k
   if (!pb.eof())
739
82.4k
   {
740
82.4k
      switch (*pb.position())
741
82.4k
      {
742
250
    case 's' :
743
250
       pb.skipChar();
744
250
       break;
745
1.11k
    case 'm' :
746
1.11k
       v *= 60;
747
1.11k
       pb.skipChar();
748
1.11k
       break;
749
209
    case 'h' :
750
209
       v *= 3600;
751
209
       pb.skipChar();
752
209
       break;
753
262
    case 'd' :
754
262
       v *= 3600*24;
755
262
       pb.skipChar();
756
82.4k
      }
757
82.4k
   }
758
82.5k
   return v;
759
82.5k
}
760
761
void
762
SdpContents::Session::Time::Repeat::parse(ParseBuffer& pb)
763
1.76k
{
764
1.76k
   pb.skipChar('r');
765
1.76k
   pb.skipChar(Symbols::EQUALS[0]);
766
767
1.76k
   mInterval = parseTypedTime(pb);
768
1.76k
   pb.skipChar(Symbols::SPACE[0]);
769
770
1.76k
   mDuration = parseTypedTime(pb);
771
772
52.3k
   while (!pb.eof() && *pb.position() != Symbols::CR[0])
773
50.6k
   {
774
50.6k
      pb.skipChar(Symbols::SPACE[0]);
775
776
50.6k
      mOffsets.push_back(parseTypedTime(pb));
777
50.6k
   }
778
779
1.76k
   skipEol(pb);
780
1.76k
}
781
782
SdpContents::Session::Timezones::Adjustment::Adjustment(unsigned long _time,
783
                                                        int _offset)
784
   : time(_time),
785
     offset(_offset)
786
28.4k
{}
787
788
SdpContents::Session::Timezones::Adjustment::Adjustment(const Adjustment& rhs)
789
   : time(rhs.time),
790
     offset(rhs.offset)
791
28.4k
{}
792
793
SdpContents::Session::Timezones::Adjustment&
794
SdpContents::Session::Timezones::Adjustment::operator=(const Adjustment& rhs)
795
0
{
796
0
   if (this != &rhs)
797
0
   {
798
0
      time = rhs.time;
799
0
      offset = rhs.offset;
800
0
   }
801
0
   return *this;
802
0
}
803
804
SdpContents::Session::Timezones::Timezones()
805
   : mAdjustments()
806
6.45k
{}
807
808
SdpContents::Session::Timezones::Timezones(const Timezones& rhs)
809
   : mAdjustments(rhs.mAdjustments)
810
0
{}
811
812
SdpContents::Session::Timezones&
813
SdpContents::Session::Timezones::operator=(const Timezones& rhs)
814
0
{
815
0
   if (this != &rhs)
816
0
   {
817
0
      mAdjustments = rhs.mAdjustments;
818
0
   }
819
0
   return *this;
820
0
}
821
822
EncodeStream&
823
SdpContents::Session::Timezones::encode(EncodeStream& s) const
824
0
{
825
0
   if (!mAdjustments.empty())
826
0
   {
827
0
      s << "z=";
828
0
      bool first = true;
829
0
      for (list<Adjustment>::const_iterator i = mAdjustments.begin();
830
0
           i != mAdjustments.end(); ++i)
831
0
      {
832
0
         if (!first)
833
0
         {
834
0
            s << Symbols::SPACE[0];
835
0
         }
836
0
         first = false;
837
0
         s << i->time << Symbols::SPACE[0]
838
0
           << i->offset << 's';
839
0
      }
840
841
0
      s << Symbols::CRLF;
842
0
   }
843
0
   return s;
844
0
}
845
846
void
847
SdpContents::Session::Timezones::parse(ParseBuffer& pb)
848
81
{
849
81
   pb.skipChar('z');
850
81
   pb.skipChar(Symbols::EQUALS[0]);
851
852
28.5k
   while (!pb.eof() && *pb.position() != Symbols::CR[0])
853
28.4k
   {
854
28.4k
      Adjustment adj(0, 0);
855
28.4k
      adj.time = pb.integer();
856
28.4k
      pb.skipChar(Symbols::SPACE[0]);
857
28.4k
      adj.offset = parseTypedTime(pb);
858
28.4k
      addAdjustment(adj);
859
860
28.4k
      if (!pb.eof() && *pb.position() == Symbols::SPACE[0])
861
26.5k
      {
862
26.5k
         pb.skipChar();
863
26.5k
      }
864
28.4k
   }
865
866
81
   skipEol(pb);
867
81
}
868
869
void
870
SdpContents::Session::Timezones::addAdjustment(const Adjustment& adjust)
871
28.4k
{
872
28.4k
   mAdjustments.push_back(adjust);
873
28.4k
}
874
875
SdpContents::Session::Encryption::Encryption()
876
   : mMethod(NoEncryption),
877
     mKey()
878
16.3k
{}
879
880
SdpContents::Session::Encryption::Encryption(const KeyType& method,
881
                                             const Data& key)
882
   : mMethod(method),
883
     mKey(key)
884
0
{}
885
886
SdpContents::Session::Encryption::Encryption(const Encryption& rhs)
887
   : mMethod(rhs.mMethod),
888
     mKey(rhs.mKey)
889
9.89k
{}
890
891
SdpContents::Session::Encryption&
892
SdpContents::Session::Encryption::operator=(const Encryption& rhs)
893
0
{
894
0
   if (this != &rhs)
895
0
   {
896
0
      mMethod = rhs.mMethod;
897
0
      mKey = rhs.mKey;
898
0
   }
899
0
   return *this;
900
0
}
901
902
const char* KeyTypes[] = {"????", "prompt", "clear", "base64", "uri"};
903
904
EncodeStream&
905
SdpContents::Session::Encryption::encode(EncodeStream& s) const
906
0
{
907
0
   s << "k="
908
0
     << KeyTypes[mMethod];
909
0
   if (mMethod != Prompt)
910
0
   {
911
0
      s << Symbols::COLON[0] << mKey;
912
0
   }
913
0
   s << Symbols::CRLF;
914
915
0
   return s;
916
0
}
917
918
void
919
SdpContents::Session::Encryption::parse(ParseBuffer& pb)
920
1.63k
{
921
1.63k
   pb.skipChar('k');
922
1.63k
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
923
924
1.63k
   pb.skipToChar(Symbols::COLON[0]);
925
1.63k
   if (!pb.eof())
926
957
   {
927
957
      Data p;
928
957
      pb.data(p, anchor);
929
957
      if (p == KeyTypes[Clear])
930
194
      {
931
194
         mMethod = Clear;
932
194
      }
933
763
      else if (p == KeyTypes[Base64])
934
194
      {
935
194
         mMethod = Base64;
936
194
      }
937
569
      else if (p == KeyTypes[UriKey])
938
194
      {
939
194
         mMethod = UriKey;
940
194
      }
941
942
957
      anchor = pb.skipChar(Symbols::COLON[0]);
943
957
      pb.skipToOneOf(Symbols::CRLF);
944
957
      pb.data(mKey, anchor);
945
957
   }
946
678
   else
947
678
   {
948
678
      pb.reset(anchor);
949
678
      pb.skipToOneOf(Symbols::CRLF);
950
951
678
      Data p;
952
678
      pb.data(p, anchor);
953
678
      if (p == KeyTypes[Prompt])
954
322
      {
955
322
         mMethod = Prompt;
956
322
      }
957
678
   }
958
959
1.63k
   skipEol(pb);
960
1.63k
}
961
962
SdpContents::Session::Session(int version,
963
                              const Origin& origin,
964
                              const Data& name)
965
   : mVersion(version),
966
     mOrigin(origin),
967
     mName(name)
968
0
{}
969
970
SdpContents::Session::Session(const Session& rhs)
971
0
{
972
0
   *this = rhs;
973
0
}
974
975
SdpContents::Session&
976
SdpContents::Session::operator=(const Session& rhs)
977
0
{
978
0
   if (this != &rhs)
979
0
   {
980
0
      mVersion = rhs.mVersion;
981
0
      mOrigin = rhs.mOrigin;
982
0
      mName = rhs.mName;
983
0
      mMedia = rhs.mMedia;
984
0
      mInformation = rhs.mInformation;
985
0
      mUri = rhs.mUri;
986
0
      mEmails = rhs.mEmails;
987
0
      mPhones = rhs.mPhones;
988
0
      mConnection = rhs.mConnection;
989
0
      mBandwidths = rhs.mBandwidths;
990
0
      mTimes = rhs.mTimes;
991
0
      mTimezones = rhs.mTimezones;
992
0
      mEncryption = rhs.mEncryption;
993
0
      mAttributeHelper = rhs.mAttributeHelper;
994
995
0
      for (MediumContainer::iterator i=mMedia.begin(); i != mMedia.end(); ++i)
996
0
      {
997
0
         i->setSession(this);
998
0
      }
999
0
   }
1000
0
   return *this;
1001
0
}
1002
1003
void
1004
SdpContents::Session::parse(ParseBuffer& pb)
1005
6.45k
{
1006
6.45k
   pb.skipChar('v');
1007
6.45k
   pb.skipChar(Symbols::EQUALS[0]);
1008
6.45k
   mVersion = pb.integer();
1009
6.45k
   skipEol(pb);
1010
1011
6.45k
   mOrigin.parse(pb);
1012
1013
6.45k
   pb.skipChar('s');
1014
6.45k
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
1015
6.45k
   pb.skipToOneOf(Symbols::CRLF);
1016
6.45k
   pb.data(mName, anchor);
1017
6.45k
   skipEol(pb);
1018
1019
6.45k
   if (!pb.eof() && *pb.position() == 'i')
1020
9
   {
1021
9
      pb.skipChar('i');
1022
9
      const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
1023
9
      pb.skipToOneOf(Symbols::CRLF);
1024
9
      pb.data(mInformation, anchor);
1025
9
      skipEol(pb);
1026
9
   }
1027
1028
6.45k
   if (!pb.eof() && *pb.position() == 'u')
1029
73
   {
1030
73
      pb.skipChar('u');
1031
73
      pb.skipChar(Symbols::EQUALS[0]);
1032
73
      mUri.parse(pb);
1033
73
      skipEol(pb);
1034
73
   }
1035
1036
8.28k
   while (!pb.eof() && *pb.position() == 'e')
1037
1.83k
   {
1038
1.83k
      addEmail(Email());
1039
1.83k
      mEmails.back().parse(pb);
1040
1.83k
   }
1041
1042
8.40k
   while (!pb.eof() && *pb.position() == 'p')
1043
1.95k
   {
1044
1.95k
      addPhone(Phone());
1045
1.95k
      mPhones.back().parse(pb);
1046
1.95k
   }
1047
1048
6.45k
   if (!pb.eof() && *pb.position() == 'c')
1049
37
   {
1050
37
      mConnection.parse(pb);
1051
37
   }
1052
1053
7.15k
   while (!pb.eof() && *pb.position() == 'b')
1054
701
   {
1055
701
      addBandwidth(Bandwidth());
1056
701
      mBandwidths.back().parse(pb);
1057
701
   }
1058
1059
7.76k
   while (!pb.eof() && *pb.position() == 't')
1060
1.30k
   {
1061
1.30k
      addTime(Time());
1062
1.30k
      mTimes.back().parse(pb);
1063
1.30k
   }
1064
1065
6.45k
   if (!pb.eof() && *pb.position() == 'z')
1066
81
   {
1067
81
      mTimezones.parse(pb);
1068
81
   }
1069
1070
6.45k
   if (!pb.eof() && *pb.position() == 'k')
1071
92
   {
1072
92
      mEncryption.parse(pb);
1073
92
   }
1074
1075
6.45k
   mAttributeHelper.parse(pb);
1076
1077
16.3k
   while (!pb.eof() && *pb.position() == 'm')
1078
9.89k
   {
1079
9.89k
      addMedium(Medium());
1080
9.89k
      mMedia.back().parse(pb);
1081
9.89k
   }
1082
6.45k
}
1083
1084
EncodeStream&
1085
SdpContents::Session::encode(EncodeStream& s) const
1086
0
{
1087
0
   s << "v=" << mVersion << Symbols::CRLF;
1088
0
   mOrigin.encode(s);
1089
0
   s << "s=" << mName << Symbols::CRLF;
1090
1091
0
   if (!mInformation.empty())
1092
0
   {
1093
0
      s << "i=" << mInformation << Symbols::CRLF;
1094
0
   }
1095
1096
0
   if (!mUri.host().empty())
1097
0
   {
1098
0
      s << "u=";
1099
0
      mUri.encode(s);
1100
0
      s << Symbols::CRLF;
1101
0
   }
1102
1103
0
   for (list<Email>::const_iterator i = mEmails.begin();
1104
0
        i != mEmails.end(); ++i)
1105
0
   {
1106
0
      i->encode(s);
1107
0
   }
1108
1109
0
   for (list<Phone>::const_iterator i = mPhones.begin();
1110
0
        i != mPhones.end(); ++i)
1111
0
   {
1112
0
      i->encode(s);
1113
0
   }
1114
1115
0
   if (!mConnection.getAddress().empty())
1116
0
   {
1117
0
      mConnection.encode(s);
1118
0
   }
1119
1120
0
   for (list<Bandwidth>::const_iterator i = mBandwidths.begin();
1121
0
        i != mBandwidths.end(); ++i)
1122
0
   {
1123
0
      i->encode(s);
1124
0
   }
1125
1126
0
   if (mTimes.empty())
1127
0
   {
1128
0
      s << "t=0 0" << Symbols::CRLF;
1129
0
   }
1130
0
   else
1131
0
   {
1132
0
      for (list<Time>::const_iterator i = mTimes.begin();
1133
0
           i != mTimes.end(); ++i)
1134
0
      {
1135
0
         i->encode(s);
1136
0
      }
1137
0
   }
1138
1139
0
   mTimezones.encode(s);
1140
1141
0
   if (mEncryption.getMethod() != Encryption::NoEncryption)
1142
0
   {
1143
0
      mEncryption.encode(s);
1144
0
   }
1145
1146
0
   mAttributeHelper.encode(s);
1147
1148
0
   for (MediumContainer::const_iterator i = mMedia.begin();
1149
0
        i != mMedia.end(); ++i)
1150
0
   {
1151
0
      i->encode(s);
1152
0
   }
1153
1154
0
   return s;
1155
0
}
1156
1157
std::list<std::reference_wrapper<SdpContents::Session::Medium>>
1158
SdpContents::Session::getMediaByType(const Data& type)
1159
0
{
1160
0
   std::list<std::reference_wrapper<SdpContents::Session::Medium>> r;
1161
0
   std::for_each(mMedia.begin(), mMedia.end(), [&r, &type](SdpContents::Session::Medium& m){
1162
0
      if(m.name() == type)
1163
0
      {
1164
0
         r.push_back(std::ref(m));
1165
0
      }
1166
0
   });
1167
0
   return r;
1168
0
}
1169
1170
void
1171
SdpContents::Session::addEmail(const Email& email)
1172
1.83k
{
1173
1.83k
   mEmails.push_back(email);
1174
1.83k
}
1175
1176
void
1177
SdpContents::Session::addTime(const Time& t)
1178
1.30k
{
1179
1.30k
   mTimes.push_back(t);
1180
1.30k
}
1181
1182
void
1183
SdpContents::Session::addPhone(const Phone& phone)
1184
1.95k
{
1185
1.95k
   mPhones.push_back(phone);
1186
1.95k
}
1187
1188
void
1189
SdpContents::Session::addBandwidth(const Bandwidth& bandwidth)
1190
701
{
1191
701
   mBandwidths.push_back(bandwidth);
1192
701
}
1193
1194
void
1195
SdpContents::Session::addMedium(const Medium& medium)
1196
9.89k
{
1197
9.89k
   mMedia.push_back(medium);
1198
9.89k
   mMedia.back().setSession(this);
1199
9.89k
}
1200
1201
void
1202
SdpContents::Session::addAttribute(const Data& key, const Data& value)
1203
0
{
1204
0
   mAttributeHelper.addAttribute(key, value);
1205
1206
0
   if (key == rtpmap)
1207
0
   {
1208
0
      for (MediumContainer::iterator i = mMedia.begin();
1209
0
           i != mMedia.end(); ++i)
1210
0
      {
1211
0
         i->mRtpMapDone = false;
1212
0
      }
1213
0
   }
1214
0
}
1215
1216
void
1217
SdpContents::Session::clearAttribute(const Data& key)
1218
0
{
1219
0
   mAttributeHelper.clearAttribute(key);
1220
1221
0
   if (key == rtpmap)
1222
0
   {
1223
0
      for (MediumContainer::iterator i = mMedia.begin();
1224
0
           i != mMedia.end(); ++i)
1225
0
      {
1226
0
         i->mRtpMapDone = false;
1227
0
      }
1228
0
   }
1229
0
}
1230
1231
bool
1232
SdpContents::Session::exists(const Data& key) const
1233
0
{
1234
0
   return mAttributeHelper.exists(key);
1235
0
}
1236
1237
const list<Data>&
1238
SdpContents::Session::getValues(const Data& key) const
1239
0
{
1240
0
   return mAttributeHelper.getValues(key);
1241
0
}
1242
1243
const SdpContents::Session::Direction&
1244
SdpContents::Session::getDirection() const
1245
0
{
1246
0
   for(const Direction& k : Direction::ordered())
1247
0
   {
1248
0
      if(exists(k.name()))
1249
0
      {
1250
0
         return k;
1251
0
      }
1252
0
   }
1253
1254
0
   return Direction::SENDRECV;
1255
0
}
1256
1257
const SdpContents::Session::Direction&
1258
SdpContents::Session::Medium::getDirection() const
1259
0
{
1260
0
   for(const Direction& k : Direction::ordered())
1261
0
   {
1262
0
      if(exists(k.name()))
1263
0
      {
1264
0
         return k;
1265
0
      }
1266
0
   }
1267
1268
0
   if(mSession)
1269
0
   {
1270
0
      return mSession->getDirection();
1271
0
   }
1272
0
   else
1273
0
   {
1274
0
      return Direction::SENDRECV;
1275
0
   }
1276
0
}
1277
1278
1279
const SdpContents::Session::Direction&
1280
SdpContents::Session::Medium::getDirection(const Direction& sessionDefault) const
1281
0
{
1282
0
   for(const Direction& k : Direction::ordered())
1283
0
   {
1284
0
      if(exists(k.name()))
1285
0
      {
1286
0
         return k;
1287
0
      }
1288
0
   }
1289
1290
0
   return sessionDefault;
1291
0
}
1292
1293
SdpContents::Session::DirectionList
1294
SdpContents::Session::getDirections() const
1295
0
{
1296
0
   SdpContents::Session::DirectionList directions;
1297
0
   const Direction& sessionDefault = getDirection();
1298
1299
0
   for(auto& m : mMedia)
1300
0
   {
1301
0
      directions.push_back(m.getDirection(sessionDefault).cref);
1302
0
   }
1303
1304
0
   return directions;
1305
0
}
1306
1307
SdpContents::Session::DirectionList
1308
SdpContents::Session::getNetDirections(const SdpContents& remote) const
1309
0
{
1310
0
   SdpContents::Session::DirectionList localDirections = getDirections();
1311
0
   SdpContents::Session::DirectionList remoteDirections = remote.session().getDirections();
1312
1313
0
   if(localDirections.size() != remoteDirections.size())
1314
0
   {
1315
0
      WarningLog(<<"SDP media count mismatch: local = " << localDirections.size()
1316
0
               << " and remote = " << remoteDirections.size());
1317
0
   }
1318
1319
0
   SdpContents::Session::DirectionList result;
1320
0
   auto iLocal = localDirections.cbegin();
1321
0
   auto iRemote = remoteDirections.cbegin();
1322
0
   while(iLocal != localDirections.cend() && iRemote != remoteDirections.cend())
1323
0
   {
1324
0
      const Direction& _iLocal = *iLocal;
1325
0
      const Direction& _iRemote = *iRemote;
1326
0
      if(_iLocal == Direction::INACTIVE || _iRemote == Direction::INACTIVE)
1327
0
      {
1328
0
         result.push_back(Direction::INACTIVE.cref);
1329
0
      }
1330
0
      else if(_iLocal == Direction::SENDONLY)
1331
0
      {
1332
0
         result.push_back(Direction::SENDONLY.cref);
1333
0
      }
1334
0
      else if(_iLocal == Direction::RECVONLY || _iRemote == Direction::SENDONLY)
1335
0
      {
1336
0
         result.push_back(Direction::RECVONLY.cref);
1337
0
      }
1338
0
      else if(_iRemote == Direction::RECVONLY)
1339
0
      {
1340
0
         result.push_back(Direction::SENDONLY.cref);
1341
0
      }
1342
0
      else
1343
0
      {
1344
0
         result.push_back(Direction::SENDRECV.cref);
1345
0
      }
1346
1347
0
      iLocal++;
1348
0
      iRemote++;
1349
0
   }
1350
1351
0
   return result;
1352
0
}
1353
1354
const SdpContents::Session::Direction&
1355
SdpContents::Session::getDirection(const std::set<Data> types,
1356
               const std::set<Data> protocolTypes) const
1357
0
{
1358
0
   const Direction& sessionDefault = getDirection();
1359
1360
0
   std::set<Data> directions;
1361
0
   for(const auto& m : mMedia)
1362
0
   {
1363
0
      if((types.empty() || types.find(m.name())!=types.end()) &&
1364
0
         (protocolTypes.empty() || protocolTypes.find(m.protocol())!=protocolTypes.end()) &&
1365
0
         m.getConnections().size() > 0 &&
1366
0
         m.port() != 0)
1367
0
      {
1368
0
         directions.insert(m.getDirection(sessionDefault).name());
1369
0
      }
1370
0
   }
1371
1372
   // Identify the strongest direction attribute in the result set
1373
0
   for(const Direction& k : Direction::ordered())
1374
0
   {
1375
0
      if(directions.find(k.name()) != directions.end())
1376
0
      {
1377
0
         return k;
1378
0
      }
1379
0
   }
1380
0
   return sessionDefault;
1381
0
}
1382
1383
std::set<Data>
1384
SdpContents::Session::getMediaStreamLabels() const
1385
0
{
1386
0
   std::set<Data> labels;
1387
0
   for (std::list<resip::SdpContents::Session::Medium>::const_iterator it = mMedia.cbegin(); it != mMedia.cend(); it++)
1388
0
   {
1389
0
      const resip::SdpContents::Session::Medium& m = *it;
1390
0
      if(m.name().caseInsensitiveTokenCompare("video") && m.exists("label"))
1391
0
      {
1392
0
         const std::list<Data>& _labels = m.getValues("label");
1393
0
         labels.insert(_labels.begin(), _labels.end());
1394
0
      }
1395
0
   }
1396
0
   return labels;
1397
0
}
1398
1399
bool
1400
SdpContents::Session::isWebRTC() const
1401
0
{
1402
0
   std::set<resip::Data> mediumTransports;
1403
0
   for(SdpContents::Session::MediumContainer::const_iterator it = mMedia.cbegin();
1404
0
         it != mMedia.cend();
1405
0
         it++)
1406
0
   {
1407
0
      const SdpContents::Session::Medium& m = *it;
1408
0
      mediumTransports.insert(m.protocol());
1409
0
   }
1410
0
   return std::find(mediumTransports.cbegin(),
1411
0
      mediumTransports.end(),
1412
0
      "RTP/SAVPF") != mediumTransports.end();
1413
0
}
1414
1415
bool
1416
SdpContents::Session::isTrickleIceSupported() const
1417
0
{
1418
0
   if(!exists("ice-options"))
1419
0
   {
1420
0
      return false;
1421
0
   }
1422
0
   auto opts = getValues("ice-options");
1423
0
   for(auto opt = opts.cbegin(); opt != opts.cend(); opt++)
1424
0
   {
1425
0
      if(*opt == "trickle")
1426
0
      {
1427
0
         return true;
1428
0
      }
1429
0
   }
1430
0
   return false;
1431
0
}
1432
1433
void
1434
SdpContents::Session::transformCOMedia(const Data& setupDirection, const Data& cOMediaAttribute)
1435
0
{
1436
0
   for(SdpContents::Session::MediumContainer::iterator it = mMedia.begin();
1437
0
         it != mMedia.end();
1438
0
         it++)
1439
0
   {
1440
0
      SdpContents::Session::Medium& m = *it;
1441
0
      m.port() = 9;
1442
0
      m.addAttribute(cOMediaAttribute, setupDirection);
1443
0
   }
1444
0
}
1445
1446
void
1447
SdpContents::Session::transformLocalHold(bool holding)
1448
0
{
1449
0
   SdpContents::Session::MediumContainer::iterator it = mMedia.begin();
1450
0
   for(;it != mMedia.end(); it++)
1451
0
   {
1452
0
      SdpContents::Session::Medium& m = *it;
1453
0
      if(holding)
1454
0
      {
1455
0
         if(m.exists("sendrecv"))
1456
0
         {
1457
0
            m.clearAttribute("sendrecv");
1458
0
            m.addAttribute("sendonly");
1459
0
         }
1460
0
         if(m.exists("recvonly"))
1461
0
         {
1462
0
            m.clearAttribute("recvonly");
1463
0
            m.addAttribute("inactive");
1464
0
         }
1465
0
      }
1466
0
      else
1467
0
      {
1468
0
         if(m.exists("sendonly"))
1469
0
         {
1470
0
            m.clearAttribute("sendonly");
1471
0
            m.addAttribute("sendrecv");
1472
0
         }
1473
0
         if(m.exists("inactive"))
1474
0
         {
1475
0
            m.clearAttribute("inactive");
1476
0
            m.addAttribute("recvonly");
1477
0
         }
1478
0
      }
1479
0
   }
1480
0
}
1481
1482
const SdpContents::Session::Medium*
1483
SdpContents::Session::getMediumByMid(const Data& mid) const
1484
0
{
1485
0
   for(auto _m = mMedia.cbegin(); _m != mMedia.end(); _m++)
1486
0
   {
1487
0
      if(_m->exists("mid") && _m->getValues("mid").front() == mid)
1488
0
      {
1489
0
         return &(*_m);
1490
0
      }
1491
0
   }
1492
0
   return nullptr;
1493
0
}
1494
1495
std::shared_ptr<TrickleIceContents>
1496
SdpContents::Session::makeIceFragment(const Data& fragment,
1497
               unsigned int lineIndex, const Data& mid)
1498
0
{
1499
0
   std::shared_ptr<TrickleIceContents> ret;
1500
0
   const Medium* m = getMediumByMid(mid);
1501
0
   if(m && m->exists("ice-ufrag") && m->exists("ice-pwd"))
1502
0
   {
1503
0
      ret = std::make_shared<TrickleIceContents>();
1504
0
      ret->addAttribute(Data("ice-ufrag"), m->getValues("ice-ufrag").front());
1505
0
      ret->addAttribute(Data("ice-pwd"), m->getValues("ice-pwd").front());
1506
0
      Medium _m(m->name(), m->port(), m->multicast(), m->protocol());
1507
0
      _m.addAttribute("candidate", fragment.substr(strlen("candidate:")));
1508
0
      ret->addMedium(_m);
1509
0
   }
1510
0
   return ret;
1511
0
}
1512
1513
SdpContents::Session::Medium::Medium(const Data& name,
1514
                                     unsigned long port,
1515
                                     unsigned long multicast,
1516
                                     const Data& protocol)
1517
   : mSession(0),
1518
     mName(name),
1519
     mPort(port),
1520
     mMulticast(multicast),
1521
     mProtocol(protocol),
1522
     mRtpMapDone(false)
1523
0
{}
1524
1525
SdpContents::Session::Medium::Medium()
1526
   : mSession(0),
1527
     mPort(0),
1528
     mMulticast(1),
1529
     mRtpMapDone(false)
1530
9.89k
{}
1531
1532
SdpContents::Session::Medium::Medium(const Medium& rhs)
1533
   : mSession(0),
1534
     mName(rhs.mName),
1535
     mPort(rhs.mPort),
1536
     mMulticast(rhs.mMulticast),
1537
     mProtocol(rhs.mProtocol),
1538
     mFormats(rhs.mFormats),
1539
     mCodecs(rhs.mCodecs),
1540
     mTransport(rhs.mTransport),
1541
     mInformation(rhs.mInformation),
1542
     mConnections(rhs.mConnections),
1543
     mBandwidths(rhs.mBandwidths),
1544
     mEncryption(rhs.mEncryption),
1545
     mAttributeHelper(rhs.mAttributeHelper),
1546
     mRtpMapDone(rhs.mRtpMapDone),
1547
     mRtpMap(rhs.mRtpMap)
1548
9.89k
{
1549
9.89k
}
1550
1551
1552
SdpContents::Session::Medium&
1553
SdpContents::Session::Medium::operator=(const Medium& rhs)
1554
0
{
1555
0
   if (this != &rhs)
1556
0
   {
1557
0
      mSession = 0;
1558
0
      mName = rhs.mName;
1559
0
      mPort = rhs.mPort;
1560
0
      mMulticast = rhs.mMulticast;
1561
0
      mProtocol = rhs.mProtocol;
1562
0
      mFormats = rhs.mFormats;
1563
0
      mCodecs = rhs.mCodecs;
1564
0
      mTransport = rhs.mTransport;
1565
0
      mInformation = rhs.mInformation;
1566
0
      mConnections = rhs.mConnections;
1567
0
      mBandwidths = rhs.mBandwidths;
1568
0
      mEncryption = rhs.mEncryption;
1569
0
      mAttributeHelper = rhs.mAttributeHelper;
1570
0
      mRtpMapDone = rhs.mRtpMapDone;
1571
0
      mRtpMap = rhs.mRtpMap;
1572
0
   }
1573
0
   return *this;
1574
0
}
1575
1576
void
1577
SdpContents::Session::Medium::setPort(int port)
1578
0
{
1579
0
   mPort = port;
1580
0
}
1581
1582
void
1583
SdpContents::Session::Medium::setSession(Session* session)
1584
9.89k
{
1585
9.89k
   mSession = session;
1586
9.89k
}
1587
1588
void
1589
SdpContents::Session::Medium::parse(ParseBuffer& pb)
1590
9.89k
{
1591
9.89k
   pb.skipChar('m');
1592
9.89k
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
1593
1594
9.89k
   pb.skipToChar(Symbols::SPACE[0]);
1595
9.89k
   pb.data(mName, anchor);
1596
9.89k
   pb.skipChar(Symbols::SPACE[0]);
1597
1598
9.89k
   mPort = pb.integer();
1599
1600
9.89k
   if (*pb.position() == Symbols::SLASH[0])
1601
307
   {
1602
307
      pb.skipChar();
1603
307
      mMulticast = pb.integer();
1604
307
   }
1605
1606
9.89k
   anchor = pb.skipChar(Symbols::SPACE[0]);
1607
9.89k
   pb.skipToOneOf(Symbols::SPACE, Symbols::CRLF);
1608
9.89k
   pb.data(mProtocol, anchor);
1609
1610
78.2k
   while (*pb.position() != Symbols::CR[0] &&
1611
78.2k
          *pb.position() != Symbols::LF[0])
1612
68.3k
   {
1613
68.3k
      anchor = pb.skipChar(Symbols::SPACE[0]);
1614
68.3k
      pb.skipToOneOf(Symbols::SPACE, Symbols::CRLF);
1615
68.3k
     if(pb.position() != anchor)
1616
67.3k
     {
1617
67.3k
      Data format;
1618
67.3k
      pb.data(format, anchor);
1619
67.3k
      addFormat(format);
1620
67.3k
     }
1621
68.3k
   }
1622
1623
9.89k
   skipEol(pb);
1624
1625
9.89k
   if (!pb.eof() && *pb.position() == 'i')
1626
194
   {
1627
194
      pb.skipChar('i');
1628
194
      anchor = pb.skipChar(Symbols::EQUALS[0]);
1629
194
      pb.skipToOneOf(Symbols::CRLF);
1630
194
      pb.data(mInformation, anchor);
1631
1632
194
      skipEol(pb);
1633
194
   }
1634
1635
24.9k
   while (!pb.eof() && *pb.position() == 'c')
1636
15.0k
   {
1637
15.0k
      addConnection(Connection());
1638
15.0k
      mConnections.back().parse(pb);
1639
15.0k
      if (!pb.eof() && *pb.position() == Symbols::SLASH[0])
1640
12.3k
      {
1641
         // Note:  we only get here if there was a /<number of addresses> 
1642
         //        parameter following the connection address. 
1643
12.3k
         pb.skipChar();
1644
12.3k
         int num = pb.integer();
1645
1646
12.3k
         if (num > 255)
1647
7
         {
1648
7
            pb.fail(__FILE__, __LINE__, "Too many connection addresses");
1649
7
         }
1650
1651
12.3k
         Connection& con = mConnections.back();
1652
12.3k
         const Data& addr = con.getAddress();
1653
12.3k
         if (addr.empty())
1654
37
         {
1655
37
            pb.fail(__FILE__, __LINE__, "IP address expected");
1656
37
         }
1657
12.3k
         size_t i = addr.size() - 1;
1658
1.88M
         for (; i; i--)
1659
1.87M
         {
1660
1.87M
            if (addr[i] == '.' || addr[i] == ':') // ipv4 or ipv6
1661
1.94k
            {
1662
1.94k
               break;
1663
1.94k
            }
1664
1.87M
         }
1665
1666
12.3k
         if (addr[i] == '.')  // add a number of ipv4 connections
1667
2.81k
         {
1668
2.81k
            Data before(addr.data(), i+1);
1669
2.81k
            ParseBuffer subpb(addr.data()+i+1, addr.size()-i-1);
1670
2.81k
            int after = subpb.integer();
1671
1672
10.1k
            for (int i = 1; i < num; i++)
1673
7.32k
            {
1674
7.32k
               addConnection(con);
1675
7.32k
               mConnections.back().mAddress = before + Data(after+i);
1676
7.32k
            }
1677
2.81k
         }
1678
12.3k
         if (addr[i] == ':') // add a number of ipv6 connections
1679
9.30k
         {
1680
9.30k
            Data before(addr.data(), i+1);
1681
9.30k
            int after = Helper::hex2integer(addr.data()+i+1);
1682
9.30k
            char hexstring[9];
1683
1684
117k
            for (int i = 1; i < num; i++)
1685
108k
            {
1686
108k
               addConnection(con);
1687
108k
               memset(hexstring, 0, sizeof(hexstring));
1688
108k
               Helper::integer2hex(hexstring, after+i, false /* supress leading zeros */);
1689
108k
               mConnections.back().mAddress = before + Data(hexstring);
1690
108k
            }
1691
9.30k
         }
1692
1693
12.3k
         skipEol(pb);
1694
12.3k
      }
1695
15.0k
   }
1696
1697
10.9k
   while (!pb.eof() && *pb.position() == 'b')
1698
1.08k
   {
1699
1.08k
      addBandwidth(Bandwidth());
1700
1.08k
      mBandwidths.back().parse(pb);
1701
1.08k
   }
1702
1703
9.89k
   if (!pb.eof() && *pb.position() == 'k')
1704
1.54k
   {
1705
1.54k
      mEncryption.parse(pb);
1706
1.54k
   }
1707
1708
9.89k
   mAttributeHelper.parse(pb);
1709
9.89k
}
1710
1711
EncodeStream&
1712
SdpContents::Session::Medium::encode(EncodeStream& s) const
1713
0
{
1714
0
   s << "m="
1715
0
     << mName << Symbols::SPACE[0]
1716
0
     << mPort;
1717
0
   if (mMulticast > 1)
1718
0
   {
1719
0
      s << Symbols::SLASH[0] << mMulticast;
1720
0
   }
1721
0
   s << Symbols::SPACE[0]
1722
0
     << mProtocol;
1723
1724
0
   for (list<Data>::const_iterator i = mFormats.begin();
1725
0
        i != mFormats.end(); ++i)
1726
0
   {
1727
0
      s << Symbols::SPACE[0] << *i;
1728
0
   }
1729
1730
0
   if (!mCodecs.empty())
1731
0
   {
1732
0
      for (CodecContainer::const_iterator i = mCodecs.begin();
1733
0
           i != mCodecs.end(); ++i)
1734
0
      {
1735
0
         s << Symbols::SPACE[0] << i->payloadType();
1736
0
      }
1737
0
   }
1738
1739
0
   s << Symbols::CRLF;
1740
1741
0
   if (!mInformation.empty())
1742
0
   {
1743
0
      s << "i=" << mInformation << Symbols::CRLF;
1744
0
   }
1745
1746
0
   for (list<Connection>::const_iterator i = mConnections.begin();
1747
0
        i != mConnections.end(); ++i)
1748
0
   {
1749
0
      i->encode(s);
1750
0
   }
1751
1752
0
   for (list<Bandwidth>::const_iterator i = mBandwidths.begin();
1753
0
        i != mBandwidths.end(); ++i)
1754
0
   {
1755
0
      i->encode(s);
1756
0
   }
1757
1758
0
   if (mEncryption.getMethod() != Encryption::NoEncryption)
1759
0
   {
1760
0
      mEncryption.encode(s);
1761
0
   }
1762
1763
0
   if (!mCodecs.empty())
1764
0
   {
1765
      // add codecs to information and attributes
1766
0
      for (CodecContainer::const_iterator i = mCodecs.begin();
1767
0
           i != mCodecs.end(); ++i)
1768
0
      {
1769
          // If codec is static (defined in RFC 3551) we probably shouldn't
1770
          // add attributes for it. But some UAs do include them.
1771
          //Codec::CodecMap& staticCodecs = Codec::getStaticCodecs();
1772
          //if (staticCodecs.find(i->payloadType()) != staticCodecs.end())
1773
          //{
1774
          //    continue;
1775
          //}
1776
1777
0
         s << "a=rtpmap:"
1778
0
           << i->payloadType() << Symbols::SPACE[0] << *i
1779
0
           << Symbols::CRLF;
1780
0
         if (!i->parameters().empty())
1781
0
         {
1782
0
            s << "a=fmtp:"
1783
0
              << i->payloadType() << Symbols::SPACE[0] << i->parameters()
1784
0
              << Symbols::CRLF;
1785
0
         }
1786
0
      }
1787
0
   }
1788
1789
0
   mAttributeHelper.encode(s);
1790
1791
0
   return s;
1792
0
}
1793
1794
void
1795
SdpContents::Session::Medium::addFormat(const Data& format)
1796
67.3k
{
1797
67.3k
   mFormats.push_back(format);
1798
67.3k
}
1799
1800
void
1801
SdpContents::Session::Medium::setConnection(const Connection& connection)
1802
0
{
1803
0
   mConnections.clear();
1804
0
   addConnection(connection);
1805
0
}
1806
1807
void
1808
SdpContents::Session::Medium::addConnection(const Connection& connection)
1809
130k
{
1810
130k
   mConnections.push_back(connection);
1811
130k
}
1812
1813
void
1814
SdpContents::Session::Medium::setBandwidth(const Bandwidth& bandwidth)
1815
0
{
1816
0
   mBandwidths.clear();
1817
0
   addBandwidth(bandwidth);
1818
0
}
1819
1820
void
1821
SdpContents::Session::Medium::addBandwidth(const Bandwidth& bandwidth)
1822
1.08k
{
1823
1.08k
   mBandwidths.push_back(bandwidth);
1824
1.08k
}
1825
1826
void
1827
SdpContents::Session::Medium::addAttribute(const Data& key, const Data& value)
1828
0
{
1829
0
   mAttributeHelper.addAttribute(key, value);
1830
0
   if (key == rtpmap)
1831
0
   {
1832
0
      mRtpMapDone = false;
1833
0
   }
1834
0
}
1835
1836
const list<SdpContents::Session::Connection>
1837
SdpContents::Session::Medium::getConnections() const
1838
0
{
1839
0
   list<Connection> connections = const_cast<Medium*>(this)->getMediumConnections();
1840
   // If there are connections specified at the medium level, then check if a session level
1841
   // connection is present - if so then return it
1842
0
   if (connections.empty() && mSession && !mSession->connection().getAddress().empty())
1843
0
   {
1844
0
      connections.push_back(mSession->connection());
1845
0
   }
1846
1847
0
   return connections;
1848
0
}
1849
1850
bool
1851
SdpContents::Session::Medium::exists(const Data& key) const
1852
0
{
1853
0
   if (mAttributeHelper.exists(key))
1854
0
   {
1855
0
      return true;
1856
0
   }
1857
0
   return mSession && mSession->exists(key);
1858
0
}
1859
1860
const list<Data>&
1861
SdpContents::Session::Medium::getValues(const Data& key) const
1862
0
{
1863
0
   if (mAttributeHelper.exists(key))
1864
0
   {
1865
0
      return mAttributeHelper.getValues(key);
1866
0
   }
1867
0
   if (!mSession)
1868
0
   {
1869
0
      resip_assert(false);
1870
0
      static list<Data> error;
1871
0
      return error;
1872
0
   }
1873
0
   return mSession->getValues(key);
1874
0
}
1875
1876
void
1877
SdpContents::Session::Medium::clearAttribute(const Data& key)
1878
0
{
1879
0
   mAttributeHelper.clearAttribute(key);
1880
0
   if (key == rtpmap)
1881
0
   {
1882
0
      mRtpMapDone = false;
1883
0
   }
1884
0
}
1885
1886
void
1887
SdpContents::Session::Medium::clearCodecs()
1888
0
{
1889
0
   mFormats.clear();
1890
0
   clearAttribute(rtpmap);
1891
0
   clearAttribute(fmtp);
1892
0
   mCodecs.clear();
1893
0
}
1894
1895
void
1896
SdpContents::Session::Medium::addCodec(const Codec& codec)
1897
0
{
1898
0
   codecs();
1899
0
   mCodecs.push_back(codec);
1900
0
}
1901
1902
1903
const SdpContents::Session::Medium::CodecContainer&
1904
SdpContents::Session::Medium::codecs() const
1905
0
{
1906
0
   return const_cast<Medium*>(this)->codecs();
1907
0
}
1908
1909
SdpContents::Session::Medium::CodecContainer&
1910
SdpContents::Session::Medium::codecs()
1911
0
{
1912
#if defined(WIN32) && defined(_MSC_VER) && (_MSC_VER < 1310)  // CJ TODO fix 
1913
   resip_assert(0);
1914
#else 
1915
0
   if (!mRtpMapDone)
1916
0
   {
1917
      // prevent recursion
1918
0
      mRtpMapDone = true;
1919
1920
0
      if (exists(rtpmap))
1921
0
      {
1922
0
         for (list<Data>::const_iterator i = getValues(rtpmap).begin();
1923
0
              i != getValues(rtpmap).end(); ++i)
1924
0
         {
1925
            //DebugLog(<< "SdpContents::Session::Medium::getCodec(" << *i << ")");
1926
0
            ParseBuffer pb(i->data(), i->size());
1927
0
            int format = pb.integer();
1928
            // pass to codec constructor for parsing
1929
            // pass this for other codec attributes
1930
0
            try
1931
0
            {
1932
0
               mRtpMap[format].parse(pb, *this, format);
1933
0
            }
1934
0
            catch (ParseException& e)
1935
0
            {
1936
0
               ErrLog(<<"Caught exception: "<< e);
1937
0
               mRtpMap.erase(format);
1938
0
            }
1939
0
         }
1940
0
      }
1941
1942
0
      for (list<Data>::const_iterator i = mFormats.begin();
1943
0
           i != mFormats.end(); ++i)
1944
0
      {
1945
0
         int mapKey = i->convertInt();
1946
0
         RtpMap::const_iterator ri = mRtpMap.find(mapKey);
1947
0
         if (ri != mRtpMap.end())
1948
0
         {
1949
            //DebugLog(<< "SdpContents::Session::Medium::getCodec[](" << ri->second << ")");
1950
0
            mCodecs.push_back(ri->second);
1951
0
         }
1952
0
         else
1953
0
         {
1954
             // !kk! Is it a static format?
1955
0
             Codec::CodecMap& staticCodecs = Codec::getStaticCodecs();
1956
0
             Codec::CodecMap::const_iterator ri = staticCodecs.find(mapKey);
1957
0
             if (ri != staticCodecs.end())
1958
0
             {
1959
                //DebugLog(<< "Found static codec for format: " << mapKey);
1960
0
                Codec codec(ri->second);
1961
1962
                // Look for format parameters, and assign
1963
0
                codec.assignFormatParameters(*this);
1964
1965
0
                mCodecs.push_back(codec);
1966
0
             }
1967
0
         }
1968
0
      }
1969
1970
      // don't store twice
1971
0
      mFormats.clear();
1972
0
      mAttributeHelper.clearAttribute(rtpmap);
1973
0
      mAttributeHelper.clearAttribute(fmtp);  // parsed out in codec.parse
1974
0
   }
1975
0
#endif
1976
1977
0
   return mCodecs;
1978
0
}
1979
1980
static Codec emptyCodec;
1981
const Codec& 
1982
SdpContents::Session::Medium::findFirstMatchingCodecs(const CodecContainer& codecList, Codec* pMatchingCodec) const
1983
0
{
1984
0
   const CodecContainer& internalCodecList = codecs();
1985
0
   resip::SdpContents::Session::Medium::CodecContainer::const_iterator sIter;
1986
0
   resip::SdpContents::Session::Medium::CodecContainer::const_iterator sEnd = internalCodecList.end();
1987
0
   resip::SdpContents::Session::Medium::CodecContainer::const_iterator eIter;
1988
0
   resip::SdpContents::Session::Medium::CodecContainer::const_iterator eEnd = codecList.end();
1989
0
   for (eIter = codecList.begin(); eIter != eEnd ; ++eIter)
1990
0
   {
1991
0
      for (sIter = internalCodecList.begin(); sIter != sEnd; ++sIter)
1992
0
      {
1993
0
         if (*sIter == *eIter)
1994
0
         {
1995
0
            if (pMatchingCodec) 
1996
0
            {
1997
0
               *pMatchingCodec = *eIter;
1998
0
            }
1999
0
            return *sIter;
2000
0
         }
2001
0
      }
2002
0
   }
2003
0
   return emptyCodec;
2004
0
}
2005
2006
const Codec& 
2007
SdpContents::Session::Medium::findFirstMatchingCodecs(const Medium& medium, Codec* pMatchingCodec) const
2008
0
{
2009
0
   if (&medium == this)
2010
0
   {
2011
0
      return codecs().front();
2012
0
   }
2013
0
   else
2014
0
   {
2015
0
      return findFirstMatchingCodecs(medium.codecs(), pMatchingCodec);
2016
0
   }
2017
0
}
2018
2019
const Codec& 
2020
SdpContents::Session::Medium::findTelephoneEventPayloadCodec() const
2021
0
{
2022
0
   const CodecContainer& codecList = codecs();
2023
0
   for (CodecContainer::const_iterator i = codecList.begin(); i != codecList.end(); i++)
2024
0
   {
2025
0
      if (i->getName() == SdpContents::Session::Codec::TelephoneEvent.getName())
2026
0
      {
2027
0
         return *i;
2028
0
      }
2029
0
   }
2030
0
   return emptyCodec;
2031
0
}
2032
2033
int
2034
SdpContents::Session::Medium::findTelephoneEventPayloadType() const
2035
0
{
2036
0
   const Codec& telephoneEventCodec = findTelephoneEventPayloadCodec();
2037
0
   if (!(telephoneEventCodec == emptyCodec))
2038
0
   {
2039
0
      return telephoneEventCodec.payloadType();
2040
0
   }
2041
0
   return -1;
2042
0
}
2043
2044
Codec::Codec(const Data& name,
2045
             unsigned long rate,
2046
             const Data& parameters,
2047
             const Data& encodingParameters)
2048
   : mName(name),
2049
     mRate(rate),
2050
     mPayloadType(-1),
2051
     mParameters(parameters),
2052
     mEncodingParameters(encodingParameters)
2053
0
{
2054
0
}
2055
2056
Codec::Codec(const Codec& rhs)
2057
   : mName(rhs.mName),
2058
     mRate(rhs.mRate),
2059
     mPayloadType(rhs.mPayloadType),
2060
     mParameters(rhs.mParameters),
2061
     mEncodingParameters(rhs.mEncodingParameters)
2062
0
{
2063
0
}
2064
2065
Codec::Codec(const Data& name, int payloadType, int rate)
2066
   : mName(name),
2067
     mRate(rate),
2068
     mPayloadType(payloadType)
2069
20
{
2070
20
}
2071
2072
Codec&
2073
Codec::operator=(const Codec& rhs)
2074
0
{
2075
0
   if (this != &rhs)
2076
0
   {
2077
0
      mName = rhs.mName;
2078
0
      mRate = rhs.mRate;
2079
0
      mPayloadType = rhs.mPayloadType;
2080
0
      mParameters = rhs.mParameters;
2081
0
      mEncodingParameters = rhs.mEncodingParameters;
2082
0
   }
2083
0
   return *this;
2084
0
}
2085
2086
void
2087
Codec::parse(ParseBuffer& pb,
2088
             const SdpContents::Session::Medium& medium,
2089
             int payloadType)
2090
0
{
2091
0
   const char* anchor = pb.skipWhitespace();
2092
0
   pb.skipToChar(Symbols::SLASH[0]);
2093
0
   mName = pb.data(anchor);
2094
0
   if(!pb.eof())
2095
0
   {
2096
0
      pb.skipChar(Symbols::SLASH[0]);
2097
0
      mRate = pb.integer();
2098
0
      pb.skipToChar(Symbols::SLASH[0]);
2099
0
   }
2100
0
   if(!pb.eof() && *pb.position() == Symbols::SLASH[0])
2101
0
   {
2102
0
      anchor = pb.skipChar(Symbols::SLASH[0]);
2103
0
      pb.skipToEnd();
2104
0
      mEncodingParameters = pb.data(anchor);
2105
0
   }
2106
0
   mPayloadType = payloadType;
2107
2108
0
   assignFormatParameters(medium); 
2109
0
}
2110
2111
void
2112
Codec::assignFormatParameters(const SdpContents::Session::Medium& medium)
2113
0
{
2114
   // get parameters if they exist
2115
0
   if (medium.exists(fmtp))
2116
0
   {
2117
0
      for (list<Data>::const_iterator i = medium.getValues(fmtp).begin();
2118
0
           i != medium.getValues(fmtp).end(); ++i)
2119
0
      {
2120
0
         try
2121
0
         {
2122
0
            ParseBuffer pb(i->data(), i->size());
2123
0
            int payload = pb.integer();
2124
0
            if (payload == mPayloadType)
2125
0
            {
2126
0
               const char* anchor = pb.skipWhitespace();
2127
0
               pb.skipToEnd();
2128
0
               mParameters = pb.data(anchor);
2129
0
               break;
2130
0
            }
2131
0
         }
2132
0
         catch (ParseException &pe)
2133
0
         {
2134
0
            InfoLog(<<"Caught exception when parsing a=fmtp: "<< pe);
2135
0
         }
2136
0
      }
2137
0
   }
2138
0
}
2139
2140
const Data&
2141
Codec::getName() const
2142
0
{
2143
0
   return mName;
2144
0
}
2145
2146
int
2147
Codec::getRate() const
2148
0
{
2149
0
   return mRate;
2150
0
}
2151
2152
Codec::CodecMap& Codec::getStaticCodecs()
2153
0
{
2154
0
   if (! sStaticCodecsCreated)
2155
0
   {
2156
      //
2157
      // Build map of static codecs as defined in RFC 3551
2158
      //
2159
0
      sStaticCodecs = std::unique_ptr<CodecMap>(new CodecMap);
2160
2161
      // Audio codecs
2162
0
      sStaticCodecs->insert(make_pair(0,Codec("PCMU",0,8000)));
2163
0
      sStaticCodecs->insert(make_pair(3,Codec("GSM",3,8000)));
2164
0
      sStaticCodecs->insert(make_pair(4,Codec("G723",4,8000)));
2165
0
      sStaticCodecs->insert(make_pair(5,Codec("DVI4",5,8000)));
2166
0
      sStaticCodecs->insert(make_pair(6,Codec("DVI4",6,16000)));
2167
0
      sStaticCodecs->insert(make_pair(7,Codec("LPC",7,8000)));
2168
0
      sStaticCodecs->insert(make_pair(8,Codec("PCMA",8,8000)));
2169
0
      sStaticCodecs->insert(make_pair(9,Codec("G722",9,8000)));
2170
0
      sStaticCodecs->insert(make_pair(10,Codec("L16-2",10,44100)));
2171
0
      sStaticCodecs->insert(make_pair(11,Codec("L16-1",11,44100)));
2172
0
      sStaticCodecs->insert(make_pair(12,Codec("QCELP",12,8000)));
2173
0
      sStaticCodecs->insert(make_pair(13,Codec("CN",13,8000)));
2174
0
      sStaticCodecs->insert(make_pair(14,Codec("MPA",14,90000)));
2175
0
      sStaticCodecs->insert(make_pair(15,Codec("G728",15,8000)));
2176
0
      sStaticCodecs->insert(make_pair(16,Codec("DVI4",16,11025)));
2177
0
      sStaticCodecs->insert(make_pair(17,Codec("DVI4",17,22050)));
2178
0
      sStaticCodecs->insert(make_pair(18,Codec("G729",18,8000)));
2179
2180
      // Video or audio/video codecs
2181
0
      sStaticCodecs->insert(make_pair(25,Codec("CelB",25,90000)));
2182
0
      sStaticCodecs->insert(make_pair(26,Codec("JPEG",26,90000)));
2183
0
      sStaticCodecs->insert(make_pair(28,Codec("nv",28,90000)));
2184
0
      sStaticCodecs->insert(make_pair(31,Codec("H261",31,90000)));
2185
0
      sStaticCodecs->insert(make_pair(32,Codec("MPV",32,90000)));
2186
0
      sStaticCodecs->insert(make_pair(33,Codec("MP2T",33,90000)));
2187
0
      sStaticCodecs->insert(make_pair(34,Codec("H263",34,90000)));
2188
2189
0
      sStaticCodecsCreated = true;
2190
0
   }
2191
0
   return *(sStaticCodecs.get());
2192
0
}
2193
2194
bool
2195
resip::operator==(const Codec& lhs, const Codec& rhs)
2196
0
{
2197
0
   static Data defaultEncodingParameters(Data("1"));  // Default for audio streams (1-Channel)
2198
0
   return (isEqualNoCase(lhs.mName, rhs.mName) && lhs.mRate == rhs.mRate && 
2199
0
           (lhs.mEncodingParameters == rhs.mEncodingParameters ||
2200
0
            (lhs.mEncodingParameters.empty() && rhs.mEncodingParameters == defaultEncodingParameters) ||
2201
0
            (lhs.mEncodingParameters == defaultEncodingParameters && rhs.mEncodingParameters.empty())));
2202
0
}
2203
2204
bool
2205
resip::operator!=(const Codec& lhs, const Codec& rhs)
2206
0
{
2207
0
   return !operator==(lhs, rhs);
2208
0
}
2209
2210
EncodeStream&
2211
resip::operator<<(EncodeStream& str, const Codec& codec)
2212
0
{
2213
0
   str << codec.mName;
2214
0
   str << Symbols::SLASH[0];
2215
0
   str << codec.mRate;
2216
0
   if(!codec.mEncodingParameters.empty())
2217
0
   {
2218
0
      str << Symbols::SLASH[0];
2219
0
      str << codec.mEncodingParameters;
2220
0
   }
2221
0
   return str;
2222
0
}
2223
2224
const Codec Codec::ULaw_8000("PCMU", 0, 8000);
2225
const Codec Codec::GSM_8000("GSM",   3, 8000);
2226
const Codec Codec::G723_8000("G723", 4, 8000);
2227
const Codec Codec::ALaw_8000("PCMA", 8, 8000);
2228
const Codec Codec::G722_8000("G722", 9, 8000);
2229
const Codec Codec::CN("CN",          13, 8000);
2230
const Codec Codec::G729_8000("G729", 18, 8000);
2231
const Codec Codec::H263("H263",      34, 90000);
2232
2233
const Codec Codec::TelephoneEvent("telephone-event", 101, 8000);
2234
const Codec Codec::FrfDialedDigit("frf-dialed-event",102, 8000);
2235
2236
bool Codec::sStaticCodecsCreated = false;
2237
std::unique_ptr<Codec::CodecMap> Codec::sStaticCodecs;
2238
2239
/* ====================================================================
2240
 * The Vovida Software License, Version 1.0
2241
 *
2242
 * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
2243
 *
2244
 * Redistribution and use in source and binary forms, with or without
2245
 * modification, are permitted provided that the following conditions
2246
 * are met:
2247
 *
2248
 * 1. Redistributions of source code must retain the above copyright
2249
 *    notice, this list of conditions and the following disclaimer.
2250
 *
2251
 * 2. Redistributions in binary form must reproduce the above copyright
2252
 *    notice, this list of conditions and the following disclaimer in
2253
 *    the documentation and/or other materials provided with the
2254
 *    distribution.
2255
 *
2256
 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
2257
 *    and "Vovida Open Communication Application Library (VOCAL)" must
2258
 *    not be used to endorse or promote products derived from this
2259
 *    software without prior written permission. For written
2260
 *    permission, please contact vocal@vovida.org.
2261
 *
2262
 * 4. Products derived from this software may not be called "VOCAL", nor
2263
 *    may "VOCAL" appear in their name, without prior written
2264
 *    permission of Vovida Networks, Inc.
2265
 *
2266
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
2267
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2268
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
2269
 * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
2270
 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
2271
 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
2272
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2273
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
2274
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
2275
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2276
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
2277
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
2278
 * DAMAGE.
2279
 *
2280
 * ====================================================================
2281
 *
2282
 * This software consists of voluntary contributions made by Vovida
2283
 * Networks, Inc. and many individuals on behalf of Vovida Networks,
2284
 * Inc.  For more information on Vovida Networks, Inc., please see
2285
 * <http://www.vovida.org/>.
2286
 *
2287
 */