Coverage Report

Created: 2026-06-07 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/resiprocate/resip/stack/SdpContents.cxx
Line
Count
Source
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
60.4k
{
54
60.9k
   while(!pb.eof() && (*pb.position() == Symbols::SPACE[0] ||
55
59.8k
                       *pb.position() == Symbols::TAB[0]))
56
586
   {
57
586
      pb.skipChar();
58
586
   }
59
   
60
60.4k
   if (*pb.position() == Symbols::LF[0])
61
57.2k
   {
62
57.2k
      pb.skipChar();
63
57.2k
   }
64
3.18k
   else
65
3.18k
   {
66
      // allow extra 0x0d bytes.
67
5.67k
      while(*pb.position() == Symbols::CR[0])
68
2.49k
      {
69
2.49k
         pb.skipChar();
70
2.49k
      } 
71
3.18k
      pb.skipChar(Symbols::LF[0]);
72
3.18k
   }
73
   
74
60.4k
}
75
76
AttributeHelper::AttributeHelper(const AttributeHelper& rhs)
77
5.74k
   : mAttributeList(rhs.mAttributeList),
78
5.74k
     mAttributes(rhs.mAttributes)
79
5.74k
{
80
5.74k
}
81
82
AttributeHelper::AttributeHelper()
83
12.3k
{
84
12.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
6.35k
{
133
36.9k
   while (!pb.eof() && *pb.position() == 'a')
134
30.5k
   {
135
30.5k
      Data key;
136
30.5k
      Data value;
137
138
30.5k
      pb.skipChar('a');
139
30.5k
      const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
140
30.5k
      pb.skipToOneOf(Symbols::COLON, Symbols::CRLF);
141
30.5k
      pb.data(key, anchor);
142
30.5k
      if (!pb.eof() && *pb.position() == Symbols::COLON[0])
143
593
      {
144
593
         anchor = pb.skipChar(Symbols::COLON[0]);
145
593
         pb.skipToOneOf(Symbols::CRLF);
146
593
         pb.data(value, anchor);
147
593
      }
148
149
30.5k
      if(!pb.eof()) skipEol(pb);
150
151
30.5k
      mAttributeList.push_back(std::make_pair(key, value));
152
30.5k
      mAttributes[key].push_back(value);
153
30.5k
   }
154
6.35k
}
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
2
SdpContents::SdpContents() : Contents(getStaticType())
179
2
{
180
2
}
181
182
SdpContents::SdpContents(const HeaderFieldValue& hfv, const Mime& contentTypes)
183
6.55k
   : Contents(hfv, contentTypes)
184
6.55k
{
185
6.55k
}
186
187
//SdpContents::SdpContents(const SdpContents& rhs)
188
//   : Contents(rhs),
189
//     mSession(rhs.mSession)
190
//{
191
//}
192
193
SdpContents::~SdpContents()
194
6.55k
{
195
6.55k
}
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.55k
{
218
6.55k
   mSession.parse(pb);
219
6.55k
}
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
6.55k
   : mUser(),
239
6.55k
     mSessionId(0),
240
6.55k
     mVersion(0),
241
6.55k
     mAddrType(IP4),
242
6.55k
     mAddress(nullOrigin)
243
6.55k
{}
244
245
SdpContents::Session::Origin::Origin(const Origin& rhs)
246
0
   : mUser(rhs.mUser),
247
0
     mSessionId(rhs.mSessionId),
248
0
     mVersion(rhs.mVersion),
249
0
     mAddrType(rhs.mAddrType),
250
0
     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
0
   : mUser(user),
275
0
     mSessionId(sessionId),
276
0
     mVersion(version),
277
0
     mAddrType(addr),
278
0
     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.08k
{
304
2.08k
   pb.skipChar('o');
305
2.08k
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
306
307
2.08k
   pb.skipToChar(Symbols::SPACE[0]);
308
2.08k
   pb.data(mUser, anchor);
309
310
2.08k
   anchor = pb.skipChar(Symbols::SPACE[0]);
311
2.08k
   try
312
2.08k
   {
313
2.08k
      mSessionId = pb.uInt64();
314
2.08k
   }
315
2.08k
   catch(ParseException& e)
316
2.08k
   {
317
1.98k
       WarningLog(<< "Exception parsing origin sessionid: " << e);
318
1.98k
   }
319
2.08k
   pb.skipToChar(Symbols::SPACE[0]);
320
321
2.07k
   anchor = pb.skipChar(Symbols::SPACE[0]);
322
2.07k
   try
323
2.07k
   {
324
2.07k
      mVersion = pb.uInt64();
325
2.07k
   }
326
2.07k
   catch(ParseException& e)
327
2.07k
   {
328
1.96k
       WarningLog(<< "Exception parsing origin version: " << e);
329
1.96k
   }
330
2.07k
   pb.skipToChar(Symbols::SPACE[0]);
331
332
1.99k
   pb.skipChar(Symbols::SPACE[0]);
333
1.99k
   pb.skipChar('I');
334
1.99k
   pb.skipChar('N');
335
336
1.99k
   anchor = pb.skipChar(Symbols::SPACE[0]);
337
1.99k
   pb.skipToChar(Symbols::SPACE[0]);
338
1.99k
   Data addrType;
339
1.99k
   pb.data(addrType, anchor);
340
1.99k
   if (addrType == NetworkType[IP4])
341
1
   {
342
1
      mAddrType = IP4;
343
1
   }
344
1.99k
   else if (addrType == NetworkType[IP6])
345
1
   {
346
1
      mAddrType = IP6;
347
1
   }
348
1.99k
   else
349
1.99k
   {
350
1.99k
      mAddrType = static_cast<AddrType>(0);
351
1.99k
   }
352
353
1.99k
   anchor = pb.skipChar(Symbols::SPACE[0]);
354
1.99k
   pb.skipToOneOf(Symbols::CRLF);
355
1.99k
   pb.data(mAddress, anchor);
356
357
1.99k
   skipEol(pb);
358
1.99k
}
359
360
SdpContents::Session::Email::Email(const Data& address,
361
                                   const Data& freeText)
362
0
   : mAddress(address),
363
0
     mFreeText(freeText)
364
0
{}
365
366
SdpContents::Session::Email::Email(const Email& rhs)
367
2.54k
   : mAddress(rhs.mAddress),
368
2.54k
     mFreeText(rhs.mFreeText)
369
2.54k
{}
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.06k
{
399
   // =mjh@isi.edu (Mark Handley)
400
   // =mjh@isi.edu
401
   // =Mark Handley <mjh@isi.edu>
402
   // =<mjh@isi.edu>
403
404
3.06k
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
405
406
3.06k
   pb.skipToOneOf("<(\n\r");  // find a left angle bracket "<", a left paren "(", or a CR 
407
3.06k
   switch (*pb.position())
408
3.06k
   {
409
2.26k
      case '\n':          // Symbols::CR[0]
410
2.64k
      case '\r':          // Symbols::LF[0]
411
         // mjh@isi.edu
412
         //            ^
413
2.64k
         pb.data(eOrp, anchor);
414
2.64k
         break;
415
416
195
      case '<':         // Symbols::LA_QUOTE[0]
417
         // Mark Handley <mjh@isi.edu>
418
         //              ^
419
         // <mjh@isi.edu>
420
         // ^
421
        
422
195
         pb.data(freeText, anchor);
423
195
         anchor = pb.skipChar();
424
195
         pb.skipToEndQuote(Symbols::RA_QUOTE[0]);
425
195
         pb.data(eOrp, anchor);
426
195
         pb.skipChar(Symbols::RA_QUOTE[0]);
427
195
         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.06k
   }
442
3.06k
}
443
444
void
445
SdpContents::Session::Email::parse(ParseBuffer& pb)
446
2.54k
{
447
2.54k
   pb.skipChar('e');
448
2.54k
   parseEorP(pb, mAddress, mFreeText);
449
2.54k
   skipEol(pb);
450
2.54k
}
451
452
SdpContents::Session::Phone::Phone(const Data& number,
453
                                   const Data& freeText)
454
0
   : mNumber(number),
455
0
     mFreeText(freeText)
456
0
{}
457
458
SdpContents::Session::Phone::Phone(const Phone& rhs)
459
522
   : mNumber(rhs.mNumber),
460
522
     mFreeText(rhs.mFreeText)
461
522
{}
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
522
{
491
522
   pb.skipChar('p');
492
522
   parseEorP(pb, mNumber, mFreeText);
493
522
   skipEol(pb);
494
522
}
495
496
SdpContents::Session::Connection::Connection(AddrType addType,
497
                                             const Data& address,
498
                                             unsigned long ttl)
499
0
   : mAddrType(addType),
500
0
     mAddress(address),
501
0
     mTTL(ttl)
502
0
{}
503
504
SdpContents::Session::Connection::Connection()
505
14.0k
   : mAddrType(IP4),
506
14.0k
     mAddress(),
507
14.0k
     mTTL(0)
508
14.0k
{}
509
510
SdpContents::Session::Connection::Connection(const Connection& rhs)
511
254k
   : mAddrType(rhs.mAddrType),
512
254k
     mAddress(rhs.mAddress),
513
254k
     mTTL(rhs.mTTL)
514
254k
{
515
254k
}
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
7.55k
{
553
7.55k
   pb.skipChar('c');
554
7.55k
   pb.skipChar(Symbols::EQUALS[0]);
555
7.55k
   pb.skipChar('I');
556
7.55k
   pb.skipChar('N');
557
558
7.55k
   const char* anchor = pb.skipChar(Symbols::SPACE[0]);
559
7.55k
   pb.skipToChar(Symbols::SPACE[0]);
560
7.55k
   Data addrType;
561
7.55k
   pb.data(addrType, anchor);
562
7.55k
   if (addrType == NetworkType[IP4])
563
425
   {
564
425
      mAddrType = IP4;
565
425
   }
566
7.12k
   else if (addrType == NetworkType[IP6])
567
214
   {
568
214
      mAddrType = IP6;
569
214
   }
570
6.91k
   else
571
6.91k
   {
572
6.91k
      mAddrType = static_cast<AddrType>(0);
573
6.91k
   }
574
575
7.55k
   anchor = pb.skipChar();
576
7.55k
   pb.skipToOneOf(Symbols::SLASH, Symbols::CRLF);
577
7.55k
   pb.data(mAddress, anchor);
578
579
7.55k
   mTTL = 0;
580
7.55k
   if (mAddrType == IP4 && !pb.eof() && *pb.position() == Symbols::SLASH[0])
581
212
   {
582
212
      pb.skipChar();
583
212
      mTTL = pb.integer();
584
212
   }
585
586
   // multicast dealt with above this parser
587
7.55k
   if (!pb.eof() && *pb.position() != Symbols::SLASH[0])
588
1.40k
   {
589
1.40k
      skipEol(pb);
590
1.40k
   }
591
7.55k
}
592
593
SdpContents::Session::Bandwidth::Bandwidth(const Data& modifier,
594
                                           unsigned long kbPerSecond)
595
0
   : mModifier(modifier),
596
0
     mKbPerSecond(kbPerSecond)
597
0
{}
598
599
SdpContents::Session::Bandwidth::Bandwidth(const Bandwidth& rhs)
600
4.07k
   : mModifier(rhs.mModifier),
601
4.07k
     mKbPerSecond(rhs.mKbPerSecond)
602
4.07k
{}
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
4.07k
{
628
4.07k
   pb.skipChar('b');
629
4.07k
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
630
631
4.07k
   pb.skipToOneOf(Symbols::COLON, Symbols::CRLF);
632
4.07k
   if (*pb.position() == Symbols::COLON[0])
633
4.02k
   {
634
4.02k
      pb.data(mModifier, anchor);
635
636
4.02k
      anchor = pb.skipChar(Symbols::COLON[0]);
637
4.02k
      mKbPerSecond = pb.integer();
638
639
4.02k
      skipEol(pb);
640
4.02k
   }
641
47
   else
642
47
   {
643
47
      pb.fail(__FILE__, __LINE__);
644
47
   }
645
4.07k
}
646
647
SdpContents::Session::Time::Time(unsigned long start,
648
                                 unsigned long stop)
649
0
   : mStart(start),
650
0
     mStop(stop)
651
0
{}
652
653
SdpContents::Session::Time::Time(const Time& rhs)
654
548
   : mStart(rhs.mStart),
655
548
     mStop(rhs.mStop)
656
548
{}
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
548
{
688
548
   pb.skipChar('t');
689
548
   pb.skipChar(Symbols::EQUALS[0]);
690
691
548
   mStart = pb.uInt32();
692
548
   pb.skipChar(Symbols::SPACE[0]);
693
548
   mStop = pb.uInt32();
694
695
548
   skipEol(pb);
696
697
1.91k
   while (!pb.eof() && *pb.position() == 'r')
698
1.37k
   {
699
1.37k
      addRepeat(Repeat());
700
1.37k
      mRepeats.back().parse(pb);
701
1.37k
   }
702
548
}
703
704
void
705
SdpContents::Session::Time::addRepeat(const Repeat& repeat)
706
1.37k
{
707
1.37k
   mRepeats.push_back(repeat);
708
1.37k
}
709
710
SdpContents::Session::Time::Repeat::Repeat(unsigned long interval,
711
                                           unsigned long duration,
712
                                           list<int> offsets)
713
0
   : mInterval(interval),
714
0
     mDuration(duration),
715
0
     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
8.61k
{
737
8.61k
   int v = pb.integer();
738
8.61k
   if (!pb.eof())
739
8.55k
   {
740
8.55k
      switch (*pb.position())
741
8.55k
      {
742
195
    case 's' :
743
195
       pb.skipChar();
744
195
       break;
745
1.22k
    case 'm' :
746
1.22k
       v *= 60;
747
1.22k
       pb.skipChar();
748
1.22k
       break;
749
219
    case 'h' :
750
219
       v *= 3600;
751
219
       pb.skipChar();
752
219
       break;
753
230
    case 'd' :
754
230
       v *= 3600*24;
755
230
       pb.skipChar();
756
8.55k
      }
757
8.55k
   }
758
8.61k
   return v;
759
8.61k
}
760
761
void
762
SdpContents::Session::Time::Repeat::parse(ParseBuffer& pb)
763
1.37k
{
764
1.37k
   pb.skipChar('r');
765
1.37k
   pb.skipChar(Symbols::EQUALS[0]);
766
767
1.37k
   mInterval = parseTypedTime(pb);
768
1.37k
   pb.skipChar(Symbols::SPACE[0]);
769
770
1.37k
   mDuration = parseTypedTime(pb);
771
772
4.38k
   while (!pb.eof() && *pb.position() != Symbols::CR[0])
773
3.01k
   {
774
3.01k
      pb.skipChar(Symbols::SPACE[0]);
775
776
3.01k
      mOffsets.push_back(parseTypedTime(pb));
777
3.01k
   }
778
779
1.37k
   skipEol(pb);
780
1.37k
}
781
782
SdpContents::Session::Timezones::Adjustment::Adjustment(unsigned long _time,
783
                                                        int _offset)
784
2.93k
   : time(_time),
785
2.93k
     offset(_offset)
786
2.93k
{}
787
788
SdpContents::Session::Timezones::Adjustment::Adjustment(const Adjustment& rhs)
789
2.91k
   : time(rhs.time),
790
2.91k
     offset(rhs.offset)
791
2.91k
{}
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
6.55k
   : mAdjustments()
806
6.55k
{}
807
808
SdpContents::Session::Timezones::Timezones(const Timezones& rhs)
809
0
   : 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
73
{
849
73
   pb.skipChar('z');
850
73
   pb.skipChar(Symbols::EQUALS[0]);
851
852
3.00k
   while (!pb.eof() && *pb.position() != Symbols::CR[0])
853
2.93k
   {
854
2.93k
      Adjustment adj(0, 0);
855
2.93k
      adj.time = pb.integer();
856
2.93k
      pb.skipChar(Symbols::SPACE[0]);
857
2.93k
      adj.offset = parseTypedTime(pb);
858
2.93k
      addAdjustment(adj);
859
860
2.93k
      if (!pb.eof() && *pb.position() == Symbols::SPACE[0])
861
1.01k
      {
862
1.01k
         pb.skipChar();
863
1.01k
      }
864
2.93k
   }
865
866
73
   skipEol(pb);
867
73
}
868
869
void
870
SdpContents::Session::Timezones::addAdjustment(const Adjustment& adjust)
871
2.91k
{
872
2.91k
   mAdjustments.push_back(adjust);
873
2.91k
}
874
875
SdpContents::Session::Encryption::Encryption()
876
12.3k
   : mMethod(NoEncryption),
877
12.3k
     mKey()
878
12.3k
{}
879
880
SdpContents::Session::Encryption::Encryption(const KeyType& method,
881
                                             const Data& key)
882
0
   : mMethod(method),
883
0
     mKey(key)
884
0
{}
885
886
SdpContents::Session::Encryption::Encryption(const Encryption& rhs)
887
5.74k
   : mMethod(rhs.mMethod),
888
5.74k
     mKey(rhs.mKey)
889
5.74k
{}
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.80k
{
921
1.80k
   pb.skipChar('k');
922
1.80k
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
923
924
1.80k
   pb.skipToChar(Symbols::COLON[0]);
925
1.80k
   if (!pb.eof())
926
912
   {
927
912
      Data p;
928
912
      pb.data(p, anchor);
929
912
      if (p == KeyTypes[Clear])
930
196
      {
931
196
         mMethod = Clear;
932
196
      }
933
716
      else if (p == KeyTypes[Base64])
934
194
      {
935
194
         mMethod = Base64;
936
194
      }
937
522
      else if (p == KeyTypes[UriKey])
938
194
      {
939
194
         mMethod = UriKey;
940
194
      }
941
942
912
      anchor = pb.skipChar(Symbols::COLON[0]);
943
912
      pb.skipToOneOf(Symbols::CRLF);
944
912
      pb.data(mKey, anchor);
945
912
   }
946
897
   else
947
897
   {
948
897
      pb.reset(anchor);
949
897
      pb.skipToOneOf(Symbols::CRLF);
950
951
897
      Data p;
952
897
      pb.data(p, anchor);
953
897
      if (p == KeyTypes[Prompt])
954
432
      {
955
432
         mMethod = Prompt;
956
432
      }
957
897
   }
958
959
1.80k
   skipEol(pb);
960
1.80k
}
961
962
SdpContents::Session::Session(int version,
963
                              const Origin& origin,
964
                              const Data& name)
965
0
   : mVersion(version),
966
0
     mOrigin(origin),
967
0
     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.55k
{
1006
6.55k
   pb.skipChar('v');
1007
6.55k
   pb.skipChar(Symbols::EQUALS[0]);
1008
6.55k
   mVersion = pb.integer();
1009
6.55k
   skipEol(pb);
1010
1011
6.55k
   mOrigin.parse(pb);
1012
1013
6.55k
   pb.skipChar('s');
1014
6.55k
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
1015
6.55k
   pb.skipToOneOf(Symbols::CRLF);
1016
6.55k
   pb.data(mName, anchor);
1017
6.55k
   skipEol(pb);
1018
1019
6.55k
   if (!pb.eof() && *pb.position() == 'i')
1020
10
   {
1021
10
      pb.skipChar('i');
1022
10
      const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
1023
10
      pb.skipToOneOf(Symbols::CRLF);
1024
10
      pb.data(mInformation, anchor);
1025
10
      skipEol(pb);
1026
10
   }
1027
1028
6.55k
   if (!pb.eof() && *pb.position() == 'u')
1029
59
   {
1030
59
      pb.skipChar('u');
1031
59
      pb.skipChar(Symbols::EQUALS[0]);
1032
59
      mUri.parse(pb);
1033
59
      skipEol(pb);
1034
59
   }
1035
1036
9.09k
   while (!pb.eof() && *pb.position() == 'e')
1037
2.54k
   {
1038
2.54k
      addEmail(Email());
1039
2.54k
      mEmails.back().parse(pb);
1040
2.54k
   }
1041
1042
7.07k
   while (!pb.eof() && *pb.position() == 'p')
1043
522
   {
1044
522
      addPhone(Phone());
1045
522
      mPhones.back().parse(pb);
1046
522
   }
1047
1048
6.55k
   if (!pb.eof() && *pb.position() == 'c')
1049
30
   {
1050
30
      mConnection.parse(pb);
1051
30
   }
1052
1053
9.03k
   while (!pb.eof() && *pb.position() == 'b')
1054
2.48k
   {
1055
2.48k
      addBandwidth(Bandwidth());
1056
2.48k
      mBandwidths.back().parse(pb);
1057
2.48k
   }
1058
1059
7.09k
   while (!pb.eof() && *pb.position() == 't')
1060
548
   {
1061
548
      addTime(Time());
1062
548
      mTimes.back().parse(pb);
1063
548
   }
1064
1065
6.55k
   if (!pb.eof() && *pb.position() == 'z')
1066
73
   {
1067
73
      mTimezones.parse(pb);
1068
73
   }
1069
1070
6.55k
   if (!pb.eof() && *pb.position() == 'k')
1071
93
   {
1072
93
      mEncryption.parse(pb);
1073
93
   }
1074
1075
6.55k
   mAttributeHelper.parse(pb);
1076
1077
12.2k
   while (!pb.eof() && *pb.position() == 'm')
1078
5.74k
   {
1079
5.74k
      addMedium(Medium());
1080
5.74k
      mMedia.back().parse(pb);
1081
5.74k
   }
1082
6.55k
}
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
2.54k
{
1173
2.54k
   mEmails.push_back(email);
1174
2.54k
}
1175
1176
void
1177
SdpContents::Session::addTime(const Time& t)
1178
548
{
1179
548
   mTimes.push_back(t);
1180
548
}
1181
1182
void
1183
SdpContents::Session::addPhone(const Phone& phone)
1184
522
{
1185
522
   mPhones.push_back(phone);
1186
522
}
1187
1188
void
1189
SdpContents::Session::addBandwidth(const Bandwidth& bandwidth)
1190
2.48k
{
1191
2.48k
   mBandwidths.push_back(bandwidth);
1192
2.48k
}
1193
1194
void
1195
SdpContents::Session::addMedium(const Medium& medium)
1196
5.74k
{
1197
5.74k
   mMedia.push_back(medium);
1198
5.74k
   mMedia.back().setSession(this);
1199
5.74k
}
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((Data::size_type)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
0
   : mSession(0),
1518
0
     mName(name),
1519
0
     mPort(port),
1520
0
     mMulticast(multicast),
1521
0
     mProtocol(protocol),
1522
0
     mRtpMapDone(false)
1523
0
{}
1524
1525
SdpContents::Session::Medium::Medium()
1526
5.74k
   : mSession(0),
1527
5.74k
     mPort(0),
1528
5.74k
     mMulticast(1),
1529
5.74k
     mRtpMapDone(false)
1530
5.74k
{}
1531
1532
SdpContents::Session::Medium::Medium(const Medium& rhs)
1533
5.74k
   : mSession(0),
1534
5.74k
     mName(rhs.mName),
1535
5.74k
     mPort(rhs.mPort),
1536
5.74k
     mMulticast(rhs.mMulticast),
1537
5.74k
     mProtocol(rhs.mProtocol),
1538
5.74k
     mFormats(rhs.mFormats),
1539
5.74k
     mCodecs(rhs.mCodecs),
1540
5.74k
     mTransport(rhs.mTransport),
1541
5.74k
     mInformation(rhs.mInformation),
1542
5.74k
     mConnections(rhs.mConnections),
1543
5.74k
     mBandwidths(rhs.mBandwidths),
1544
5.74k
     mEncryption(rhs.mEncryption),
1545
5.74k
     mAttributeHelper(rhs.mAttributeHelper),
1546
5.74k
     mRtpMapDone(rhs.mRtpMapDone),
1547
5.74k
     mRtpMap(rhs.mRtpMap)
1548
5.74k
{
1549
5.74k
}
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
5.74k
{
1585
5.74k
   mSession = session;
1586
5.74k
}
1587
1588
void
1589
SdpContents::Session::Medium::parse(ParseBuffer& pb)
1590
5.74k
{
1591
5.74k
   pb.skipChar('m');
1592
5.74k
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
1593
1594
5.74k
   pb.skipToChar(Symbols::SPACE[0]);
1595
5.74k
   pb.data(mName, anchor);
1596
5.74k
   pb.skipChar(Symbols::SPACE[0]);
1597
1598
5.74k
   mPort = pb.integer();
1599
1600
5.74k
   if (*pb.position() == Symbols::SLASH[0])
1601
194
   {
1602
194
      pb.skipChar();
1603
194
      mMulticast = pb.integer();
1604
194
   }
1605
1606
5.74k
   anchor = pb.skipChar(Symbols::SPACE[0]);
1607
5.74k
   pb.skipToOneOf(Symbols::SPACE, Symbols::CRLF);
1608
5.74k
   pb.data(mProtocol, anchor);
1609
1610
7.33k
   while (*pb.position() != Symbols::CR[0] &&
1611
6.84k
          *pb.position() != Symbols::LF[0])
1612
1.58k
   {
1613
1.58k
      anchor = pb.skipChar(Symbols::SPACE[0]);
1614
1.58k
      pb.skipToOneOf(Symbols::SPACE, Symbols::CRLF);
1615
1.58k
     if(pb.position() != anchor)
1616
738
     {
1617
738
      Data format;
1618
738
      pb.data(format, anchor);
1619
738
      addFormat(format);
1620
738
     }
1621
1.58k
   }
1622
1623
5.74k
   skipEol(pb);
1624
1625
5.74k
   if (!pb.eof() && *pb.position() == 'i')
1626
199
   {
1627
199
      pb.skipChar('i');
1628
199
      anchor = pb.skipChar(Symbols::EQUALS[0]);
1629
199
      pb.skipToOneOf(Symbols::CRLF);
1630
199
      pb.data(mInformation, anchor);
1631
1632
199
      skipEol(pb);
1633
199
   }
1634
1635
13.2k
   while (!pb.eof() && *pb.position() == 'c')
1636
7.52k
   {
1637
7.52k
      addConnection(Connection());
1638
7.52k
      mConnections.back().parse(pb);
1639
7.52k
      if (!pb.eof() && *pb.position() == Symbols::SLASH[0])
1640
6.06k
      {
1641
         // Note:  we only get here if there was a /<number of addresses> 
1642
         //        parameter following the connection address. 
1643
6.06k
         pb.skipChar();
1644
6.06k
         int num = pb.integer();
1645
1646
6.06k
         if (num > 255)
1647
8
         {
1648
8
            pb.fail(__FILE__, __LINE__, "Too many connection addresses");
1649
8
         }
1650
1651
6.06k
         Connection& con = mConnections.back();
1652
6.06k
         const Data& addr = con.getAddress();
1653
6.06k
         if (addr.empty())
1654
39
         {
1655
39
            pb.fail(__FILE__, __LINE__, "IP address expected");
1656
39
         }
1657
6.06k
         Data::size_type i = addr.size() - 1;
1658
1.68M
         for (; i; i--)
1659
1.67M
         {
1660
1.67M
            if (addr[i] == '.' || addr[i] == ':') // ipv4 or ipv6
1661
1.48k
            {
1662
1.48k
               break;
1663
1.48k
            }
1664
1.67M
         }
1665
1666
6.06k
         if (addr[i] == '.')  // add a number of ipv4 connections
1667
2.73k
         {
1668
2.73k
            Data before(addr.data(), i+1);
1669
2.73k
            ParseBuffer subpb(addr.data()+i+1, addr.size()-i-1);
1670
2.73k
            int after = subpb.integer();
1671
1672
9.58k
            for (int i = 1; i < num; i++)
1673
6.85k
            {
1674
6.85k
               addConnection(con);
1675
6.85k
               mConnections.back().mAddress = before + Data(after+i);
1676
6.85k
            }
1677
2.73k
         }
1678
6.06k
         if (addr[i] == ':') // add a number of ipv6 connections
1679
3.24k
         {
1680
3.24k
            Data before(addr.data(), i+1);
1681
3.24k
            int after = Helper::hex2integer(addr.data()+i+1);
1682
3.24k
            char hexstring[9];
1683
1684
243k
            for (int i = 1; i < num; i++)
1685
239k
            {
1686
239k
               addConnection(con);
1687
239k
               memset(hexstring, 0, sizeof(hexstring));
1688
239k
               Helper::integer2hex(hexstring, after+i, false /* supress leading zeros */);
1689
239k
               mConnections.back().mAddress = before + Data(hexstring);
1690
239k
            }
1691
3.24k
         }
1692
1693
6.06k
         skipEol(pb);
1694
6.06k
      }
1695
7.52k
   }
1696
1697
7.33k
   while (!pb.eof() && *pb.position() == 'b')
1698
1.58k
   {
1699
1.58k
      addBandwidth(Bandwidth());
1700
1.58k
      mBandwidths.back().parse(pb);
1701
1.58k
   }
1702
1703
5.74k
   if (!pb.eof() && *pb.position() == 'k')
1704
1.71k
   {
1705
1.71k
      mEncryption.parse(pb);
1706
1.71k
   }
1707
1708
5.74k
   mAttributeHelper.parse(pb);
1709
5.74k
}
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
738
{
1797
738
   mFormats.push_back(format);
1798
738
}
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
254k
{
1810
254k
   mConnections.push_back(connection);
1811
254k
}
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.58k
{
1823
1.58k
   mBandwidths.push_back(bandwidth);
1824
1.58k
}
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
list<Data>
1877
SdpContents::Session::Medium::getMergedValues(const Data& key) const
1878
0
{
1879
0
   const list<Data>& mediumValues = mAttributeHelper.getValues(key);
1880
0
   if (mSession && mSession->exists(key))
1881
0
   {
1882
0
      if (mediumValues.size() > 0)
1883
0
      {
1884
         // The attribute exists at both medium level and session level, merge lists for return
1885
0
         list<Data> mergedValues = mediumValues;
1886
0
         const list<Data>& sessionValues = mSession->getValues(key);
1887
0
         mergedValues.insert(mergedValues.end(), sessionValues.begin(), sessionValues.end());
1888
0
         return mergedValues;
1889
0
      }
1890
      // Attribute only exists at session level, return them
1891
0
      return mSession->getValues(key);
1892
0
   }
1893
   // Attribute only exists at medium level, return them
1894
0
   return mediumValues;
1895
0
}
1896
1897
void
1898
SdpContents::Session::Medium::clearAttribute(const Data& key)
1899
0
{
1900
0
   mAttributeHelper.clearAttribute(key);
1901
0
   if (key == rtpmap)
1902
0
   {
1903
0
      mRtpMapDone = false;
1904
0
   }
1905
0
}
1906
1907
void
1908
SdpContents::Session::Medium::clearCodecs()
1909
0
{
1910
0
   mFormats.clear();
1911
0
   clearAttribute(rtpmap);
1912
0
   clearAttribute(fmtp);
1913
0
   mCodecs.clear();
1914
0
}
1915
1916
void
1917
SdpContents::Session::Medium::addCodec(const Codec& codec)
1918
0
{
1919
0
   codecs();
1920
0
   mCodecs.push_back(codec);
1921
0
}
1922
1923
1924
const SdpContents::Session::Medium::CodecContainer&
1925
SdpContents::Session::Medium::codecs() const
1926
0
{
1927
0
   return const_cast<Medium*>(this)->codecs();
1928
0
}
1929
1930
SdpContents::Session::Medium::CodecContainer&
1931
SdpContents::Session::Medium::codecs()
1932
0
{
1933
#if defined(WIN32) && defined(_MSC_VER) && (_MSC_VER < 1310)  // CJ TODO fix 
1934
   resip_assert(0);
1935
#else 
1936
0
   if (!mRtpMapDone)
1937
0
   {
1938
      // prevent recursion
1939
0
      mRtpMapDone = true;
1940
1941
0
      if (exists(rtpmap))
1942
0
      {
1943
0
         for (list<Data>::const_iterator i = getValues(rtpmap).begin();
1944
0
              i != getValues(rtpmap).end(); ++i)
1945
0
         {
1946
            //DebugLog(<< "SdpContents::Session::Medium::getCodec(" << *i << ")");
1947
0
            ParseBuffer pb(i->data(), i->size());
1948
0
            int format = pb.integer();
1949
            // pass to codec constructor for parsing
1950
            // pass this for other codec attributes
1951
0
            try
1952
0
            {
1953
0
               mRtpMap[format].parse(pb, *this, format);
1954
0
            }
1955
0
            catch (ParseException& e)
1956
0
            {
1957
0
               ErrLog(<<"Caught exception: "<< e);
1958
0
               mRtpMap.erase(format);
1959
0
            }
1960
0
         }
1961
0
      }
1962
1963
0
      for (list<Data>::const_iterator i = mFormats.begin();
1964
0
           i != mFormats.end(); ++i)
1965
0
      {
1966
0
         int mapKey = i->convertInt();
1967
0
         RtpMap::const_iterator ri = mRtpMap.find(mapKey);
1968
0
         if (ri != mRtpMap.end())
1969
0
         {
1970
            //DebugLog(<< "SdpContents::Session::Medium::getCodec[](" << ri->second << ")");
1971
0
            mCodecs.push_back(ri->second);
1972
0
         }
1973
0
         else
1974
0
         {
1975
             // !kk! Is it a static format?
1976
0
             Codec::CodecMap& staticCodecs = Codec::getStaticCodecs();
1977
0
             Codec::CodecMap::const_iterator ri = staticCodecs.find(mapKey);
1978
0
             if (ri != staticCodecs.end())
1979
0
             {
1980
                //DebugLog(<< "Found static codec for format: " << mapKey);
1981
0
                Codec codec(ri->second);
1982
1983
                // Look for format parameters, and assign
1984
0
                codec.assignFormatParameters(*this);
1985
1986
0
                mCodecs.push_back(codec);
1987
0
             }
1988
0
         }
1989
0
      }
1990
1991
      // don't store twice
1992
0
      mFormats.clear();
1993
0
      mAttributeHelper.clearAttribute(rtpmap);
1994
0
      mAttributeHelper.clearAttribute(fmtp);  // parsed out in codec.parse
1995
0
   }
1996
0
#endif
1997
1998
0
   return mCodecs;
1999
0
}
2000
2001
static Codec emptyCodec;
2002
const Codec& 
2003
SdpContents::Session::Medium::findFirstMatchingCodecs(const CodecContainer& codecList, Codec* pMatchingCodec) const
2004
0
{
2005
0
   const CodecContainer& internalCodecList = codecs();
2006
0
   resip::SdpContents::Session::Medium::CodecContainer::const_iterator sIter;
2007
0
   resip::SdpContents::Session::Medium::CodecContainer::const_iterator sEnd = internalCodecList.end();
2008
0
   resip::SdpContents::Session::Medium::CodecContainer::const_iterator eIter;
2009
0
   resip::SdpContents::Session::Medium::CodecContainer::const_iterator eEnd = codecList.end();
2010
0
   for (eIter = codecList.begin(); eIter != eEnd ; ++eIter)
2011
0
   {
2012
0
      for (sIter = internalCodecList.begin(); sIter != sEnd; ++sIter)
2013
0
      {
2014
0
         if (*sIter == *eIter)
2015
0
         {
2016
0
            if (pMatchingCodec) 
2017
0
            {
2018
0
               *pMatchingCodec = *eIter;
2019
0
            }
2020
0
            return *sIter;
2021
0
         }
2022
0
      }
2023
0
   }
2024
0
   return emptyCodec;
2025
0
}
2026
2027
const Codec& 
2028
SdpContents::Session::Medium::findFirstMatchingCodecs(const Medium& medium, Codec* pMatchingCodec) const
2029
0
{
2030
0
   if (&medium == this)
2031
0
   {
2032
0
      return codecs().front();
2033
0
   }
2034
0
   else
2035
0
   {
2036
0
      return findFirstMatchingCodecs(medium.codecs(), pMatchingCodec);
2037
0
   }
2038
0
}
2039
2040
const Codec& 
2041
SdpContents::Session::Medium::findTelephoneEventPayloadCodec() const
2042
0
{
2043
0
   const CodecContainer& codecList = codecs();
2044
0
   for (CodecContainer::const_iterator i = codecList.begin(); i != codecList.end(); i++)
2045
0
   {
2046
0
      if (i->getName() == SdpContents::Session::Codec::TelephoneEvent.getName())
2047
0
      {
2048
0
         return *i;
2049
0
      }
2050
0
   }
2051
0
   return emptyCodec;
2052
0
}
2053
2054
int
2055
SdpContents::Session::Medium::findTelephoneEventPayloadType() const
2056
0
{
2057
0
   const Codec& telephoneEventCodec = findTelephoneEventPayloadCodec();
2058
0
   if (!(telephoneEventCodec == emptyCodec))
2059
0
   {
2060
0
      return telephoneEventCodec.payloadType();
2061
0
   }
2062
0
   return -1;
2063
0
}
2064
2065
Codec::Codec(const Data& name,
2066
             unsigned long rate,
2067
             const Data& parameters,
2068
             const Data& encodingParameters)
2069
0
   : mName(name),
2070
0
     mRate(rate),
2071
0
     mPayloadType(-1),
2072
0
     mParameters(parameters),
2073
0
     mEncodingParameters(encodingParameters)
2074
0
{
2075
0
}
2076
2077
Codec::Codec(const Codec& rhs)
2078
0
   : mName(rhs.mName),
2079
0
     mRate(rhs.mRate),
2080
0
     mPayloadType(rhs.mPayloadType),
2081
0
     mParameters(rhs.mParameters),
2082
0
     mEncodingParameters(rhs.mEncodingParameters)
2083
0
{
2084
0
}
2085
2086
Codec::Codec(const Data& name, int payloadType, int rate)
2087
20
   : mName(name),
2088
20
     mRate(rate),
2089
20
     mPayloadType(payloadType)
2090
20
{
2091
20
}
2092
2093
Codec&
2094
Codec::operator=(const Codec& rhs)
2095
0
{
2096
0
   if (this != &rhs)
2097
0
   {
2098
0
      mName = rhs.mName;
2099
0
      mRate = rhs.mRate;
2100
0
      mPayloadType = rhs.mPayloadType;
2101
0
      mParameters = rhs.mParameters;
2102
0
      mEncodingParameters = rhs.mEncodingParameters;
2103
0
   }
2104
0
   return *this;
2105
0
}
2106
2107
void
2108
Codec::parse(ParseBuffer& pb,
2109
             const SdpContents::Session::Medium& medium,
2110
             int payloadType)
2111
0
{
2112
0
   const char* anchor = pb.skipWhitespace();
2113
0
   pb.skipToChar(Symbols::SLASH[0]);
2114
0
   mName = pb.data(anchor);
2115
0
   if(!pb.eof())
2116
0
   {
2117
0
      pb.skipChar(Symbols::SLASH[0]);
2118
0
      mRate = pb.integer();
2119
0
      pb.skipToChar(Symbols::SLASH[0]);
2120
0
   }
2121
0
   if(!pb.eof() && *pb.position() == Symbols::SLASH[0])
2122
0
   {
2123
0
      anchor = pb.skipChar(Symbols::SLASH[0]);
2124
0
      pb.skipToEnd();
2125
0
      mEncodingParameters = pb.data(anchor);
2126
0
   }
2127
0
   mPayloadType = payloadType;
2128
2129
0
   assignFormatParameters(medium); 
2130
0
}
2131
2132
void
2133
Codec::assignFormatParameters(const SdpContents::Session::Medium& medium)
2134
0
{
2135
   // get parameters if they exist
2136
0
   if (medium.exists(fmtp))
2137
0
   {
2138
0
      for (list<Data>::const_iterator i = medium.getValues(fmtp).begin();
2139
0
           i != medium.getValues(fmtp).end(); ++i)
2140
0
      {
2141
0
         try
2142
0
         {
2143
0
            ParseBuffer pb(i->data(), i->size());
2144
0
            int payload = pb.integer();
2145
0
            if (payload == mPayloadType)
2146
0
            {
2147
0
               const char* anchor = pb.skipWhitespace();
2148
0
               pb.skipToEnd();
2149
0
               mParameters = pb.data(anchor);
2150
0
               break;
2151
0
            }
2152
0
         }
2153
0
         catch (ParseException &pe)
2154
0
         {
2155
0
            InfoLog(<<"Caught exception when parsing a=fmtp: "<< pe);
2156
0
         }
2157
0
      }
2158
0
   }
2159
0
}
2160
2161
const Data&
2162
Codec::getName() const
2163
0
{
2164
0
   return mName;
2165
0
}
2166
2167
int
2168
Codec::getRate() const
2169
0
{
2170
0
   return mRate;
2171
0
}
2172
2173
Codec::CodecMap& Codec::getStaticCodecs()
2174
0
{
2175
0
   if (! sStaticCodecsCreated)
2176
0
   {
2177
      //
2178
      // Build map of static codecs as defined in RFC 3551
2179
      //
2180
0
      sStaticCodecs = std::unique_ptr<CodecMap>(new CodecMap);
2181
2182
      // Audio codecs
2183
0
      sStaticCodecs->insert(make_pair(0,Codec("PCMU",0,8000)));
2184
0
      sStaticCodecs->insert(make_pair(3,Codec("GSM",3,8000)));
2185
0
      sStaticCodecs->insert(make_pair(4,Codec("G723",4,8000)));
2186
0
      sStaticCodecs->insert(make_pair(5,Codec("DVI4",5,8000)));
2187
0
      sStaticCodecs->insert(make_pair(6,Codec("DVI4",6,16000)));
2188
0
      sStaticCodecs->insert(make_pair(7,Codec("LPC",7,8000)));
2189
0
      sStaticCodecs->insert(make_pair(8,Codec("PCMA",8,8000)));
2190
0
      sStaticCodecs->insert(make_pair(9,Codec("G722",9,8000)));
2191
0
      sStaticCodecs->insert(make_pair(10,Codec("L16-2",10,44100)));
2192
0
      sStaticCodecs->insert(make_pair(11,Codec("L16-1",11,44100)));
2193
0
      sStaticCodecs->insert(make_pair(12,Codec("QCELP",12,8000)));
2194
0
      sStaticCodecs->insert(make_pair(13,Codec("CN",13,8000)));
2195
0
      sStaticCodecs->insert(make_pair(14,Codec("MPA",14,90000)));
2196
0
      sStaticCodecs->insert(make_pair(15,Codec("G728",15,8000)));
2197
0
      sStaticCodecs->insert(make_pair(16,Codec("DVI4",16,11025)));
2198
0
      sStaticCodecs->insert(make_pair(17,Codec("DVI4",17,22050)));
2199
0
      sStaticCodecs->insert(make_pair(18,Codec("G729",18,8000)));
2200
2201
      // Video or audio/video codecs
2202
0
      sStaticCodecs->insert(make_pair(25,Codec("CelB",25,90000)));
2203
0
      sStaticCodecs->insert(make_pair(26,Codec("JPEG",26,90000)));
2204
0
      sStaticCodecs->insert(make_pair(28,Codec("nv",28,90000)));
2205
0
      sStaticCodecs->insert(make_pair(31,Codec("H261",31,90000)));
2206
0
      sStaticCodecs->insert(make_pair(32,Codec("MPV",32,90000)));
2207
0
      sStaticCodecs->insert(make_pair(33,Codec("MP2T",33,90000)));
2208
0
      sStaticCodecs->insert(make_pair(34,Codec("H263",34,90000)));
2209
2210
0
      sStaticCodecsCreated = true;
2211
0
   }
2212
0
   return *(sStaticCodecs.get());
2213
0
}
2214
2215
bool
2216
resip::operator==(const Codec& lhs, const Codec& rhs)
2217
0
{
2218
0
   static Data defaultEncodingParameters(Data("1"));  // Default for audio streams (1-Channel)
2219
0
   return (isEqualNoCase(lhs.mName, rhs.mName) && lhs.mRate == rhs.mRate && 
2220
0
           (lhs.mEncodingParameters == rhs.mEncodingParameters ||
2221
0
            (lhs.mEncodingParameters.empty() && rhs.mEncodingParameters == defaultEncodingParameters) ||
2222
0
            (lhs.mEncodingParameters == defaultEncodingParameters && rhs.mEncodingParameters.empty())));
2223
0
}
2224
2225
bool
2226
resip::operator!=(const Codec& lhs, const Codec& rhs)
2227
0
{
2228
0
   return !operator==(lhs, rhs);
2229
0
}
2230
2231
EncodeStream&
2232
resip::operator<<(EncodeStream& str, const Codec& codec)
2233
0
{
2234
0
   str << codec.mName;
2235
0
   str << Symbols::SLASH[0];
2236
0
   str << codec.mRate;
2237
0
   if(!codec.mEncodingParameters.empty())
2238
0
   {
2239
0
      str << Symbols::SLASH[0];
2240
0
      str << codec.mEncodingParameters;
2241
0
   }
2242
0
   return str;
2243
0
}
2244
2245
const Codec Codec::ULaw_8000("PCMU", 0, 8000);
2246
const Codec Codec::GSM_8000("GSM",   3, 8000);
2247
const Codec Codec::G723_8000("G723", 4, 8000);
2248
const Codec Codec::ALaw_8000("PCMA", 8, 8000);
2249
const Codec Codec::G722_8000("G722", 9, 8000);
2250
const Codec Codec::CN("CN",          13, 8000);
2251
const Codec Codec::G729_8000("G729", 18, 8000);
2252
const Codec Codec::H263("H263",      34, 90000);
2253
2254
const Codec Codec::TelephoneEvent("telephone-event", 101, 8000);
2255
const Codec Codec::FrfDialedDigit("frf-dialed-event",102, 8000);
2256
2257
bool Codec::sStaticCodecsCreated = false;
2258
std::unique_ptr<Codec::CodecMap> Codec::sStaticCodecs;
2259
2260
/* ====================================================================
2261
 * The Vovida Software License, Version 1.0
2262
 *
2263
 * Copyright (c) 2026, SIP Spectrum, Inc. https://www.sipspectrum.com
2264
 * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
2265
 *
2266
 * Redistribution and use in source and binary forms, with or without
2267
 * modification, are permitted provided that the following conditions
2268
 * are met:
2269
 *
2270
 * 1. Redistributions of source code must retain the above copyright
2271
 *    notice, this list of conditions and the following disclaimer.
2272
 *
2273
 * 2. Redistributions in binary form must reproduce the above copyright
2274
 *    notice, this list of conditions and the following disclaimer in
2275
 *    the documentation and/or other materials provided with the
2276
 *    distribution.
2277
 *
2278
 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
2279
 *    and "Vovida Open Communication Application Library (VOCAL)" must
2280
 *    not be used to endorse or promote products derived from this
2281
 *    software without prior written permission. For written
2282
 *    permission, please contact vocal@vovida.org.
2283
 *
2284
 * 4. Products derived from this software may not be called "VOCAL", nor
2285
 *    may "VOCAL" appear in their name, without prior written
2286
 *    permission of Vovida Networks, Inc.
2287
 *
2288
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
2289
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2290
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
2291
 * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
2292
 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
2293
 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
2294
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2295
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
2296
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
2297
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2298
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
2299
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
2300
 * DAMAGE.
2301
 *
2302
 * ====================================================================
2303
 *
2304
 * This software consists of voluntary contributions made by Vovida
2305
 * Networks, Inc. and many individuals on behalf of Vovida Networks,
2306
 * Inc.  For more information on Vovida Networks, Inc., please see
2307
 * <http://www.vovida.org/>.
2308
 *
2309
 */