Coverage Report

Created: 2026-08-13 06:19

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
314k
{
54
315k
   while(!pb.eof() && (*pb.position() == Symbols::SPACE[0] ||
55
314k
                       *pb.position() == Symbols::TAB[0]))
56
584
   {
57
584
      pb.skipChar();
58
584
   }
59
   
60
314k
   if (*pb.position() == Symbols::LF[0])
61
311k
   {
62
311k
      pb.skipChar();
63
311k
   }
64
2.95k
   else
65
2.95k
   {
66
      // allow extra 0x0d bytes.
67
5.27k
      while(*pb.position() == Symbols::CR[0])
68
2.32k
      {
69
2.32k
         pb.skipChar();
70
2.32k
      } 
71
2.95k
      pb.skipChar(Symbols::LF[0]);
72
2.95k
   }
73
   
74
314k
}
75
76
AttributeHelper::AttributeHelper(const AttributeHelper& rhs)
77
17.8k
   : mAttributeList(rhs.mAttributeList),
78
17.8k
     mAttributes(rhs.mAttributes)
79
17.8k
{
80
17.8k
}
81
82
AttributeHelper::AttributeHelper()
83
24.3k
{
84
24.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
18.4k
{
133
284k
   while (!pb.eof() && *pb.position() == 'a')
134
266k
   {
135
266k
      Data key;
136
266k
      Data value;
137
138
266k
      pb.skipChar('a');
139
266k
      const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
140
266k
      pb.skipToOneOf(Symbols::COLON, Symbols::CRLF);
141
266k
      pb.data(key, anchor);
142
266k
      if (!pb.eof() && *pb.position() == Symbols::COLON[0])
143
466
      {
144
466
         anchor = pb.skipChar(Symbols::COLON[0]);
145
466
         pb.skipToOneOf(Symbols::CRLF);
146
466
         pb.data(value, anchor);
147
466
      }
148
149
266k
      if(!pb.eof()) skipEol(pb);
150
151
266k
      mAttributeList.push_back(std::make_pair(key, value));
152
266k
      mAttributes[key].push_back(value);
153
266k
   }
154
18.4k
}
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.52k
   : Contents(hfv, contentTypes)
184
6.52k
{
185
6.52k
}
186
187
//SdpContents::SdpContents(const SdpContents& rhs)
188
//   : Contents(rhs),
189
//     mSession(rhs.mSession)
190
//{
191
//}
192
193
SdpContents::~SdpContents()
194
6.52k
{
195
6.52k
}
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.52k
{
218
6.52k
   mSession.parse(pb);
219
6.52k
}
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.52k
   : mUser(),
239
6.52k
     mSessionId(0),
240
6.52k
     mVersion(0),
241
6.52k
     mAddrType(IP4),
242
6.52k
     mAddress(nullOrigin)
243
6.52k
{}
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.02k
{
304
2.02k
   pb.skipChar('o');
305
2.02k
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
306
307
2.02k
   pb.skipToChar(Symbols::SPACE[0]);
308
2.02k
   pb.data(mUser, anchor);
309
310
2.02k
   anchor = pb.skipChar(Symbols::SPACE[0]);
311
2.02k
   try
312
2.02k
   {
313
2.02k
      mSessionId = pb.uInt64();
314
2.02k
   }
315
2.02k
   catch(ParseException& e)
316
2.02k
   {
317
1.92k
       WarningLog(<< "Exception parsing origin sessionid: " << e);
318
1.92k
   }
319
2.02k
   pb.skipToChar(Symbols::SPACE[0]);
320
321
2.02k
   anchor = pb.skipChar(Symbols::SPACE[0]);
322
2.02k
   try
323
2.02k
   {
324
2.02k
      mVersion = pb.uInt64();
325
2.02k
   }
326
2.02k
   catch(ParseException& e)
327
2.02k
   {
328
1.91k
       WarningLog(<< "Exception parsing origin version: " << e);
329
1.91k
   }
330
2.02k
   pb.skipToChar(Symbols::SPACE[0]);
331
332
1.93k
   pb.skipChar(Symbols::SPACE[0]);
333
1.93k
   pb.skipChar('I');
334
1.93k
   pb.skipChar('N');
335
336
1.93k
   anchor = pb.skipChar(Symbols::SPACE[0]);
337
1.93k
   pb.skipToChar(Symbols::SPACE[0]);
338
1.93k
   Data addrType;
339
1.93k
   pb.data(addrType, anchor);
340
1.93k
   if (addrType == NetworkType[IP4])
341
1
   {
342
1
      mAddrType = IP4;
343
1
   }
344
1.93k
   else if (addrType == NetworkType[IP6])
345
1
   {
346
1
      mAddrType = IP6;
347
1
   }
348
1.93k
   else
349
1.93k
   {
350
1.93k
      mAddrType = static_cast<AddrType>(0);
351
1.93k
   }
352
353
1.93k
   anchor = pb.skipChar(Symbols::SPACE[0]);
354
1.93k
   pb.skipToOneOf(Symbols::CRLF);
355
1.93k
   pb.data(mAddress, anchor);
356
357
1.93k
   skipEol(pb);
358
1.93k
}
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.80k
   : mAddress(rhs.mAddress),
368
2.80k
     mFreeText(rhs.mFreeText)
369
2.80k
{}
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
9.06k
{
399
   // =mjh@isi.edu (Mark Handley)
400
   // =mjh@isi.edu
401
   // =Mark Handley <mjh@isi.edu>
402
   // =<mjh@isi.edu>
403
404
9.06k
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
405
406
9.06k
   pb.skipToOneOf("<(\n\r");  // find a left angle bracket "<", a left paren "(", or a CR 
407
9.06k
   switch (*pb.position())
408
9.06k
   {
409
8.26k
      case '\n':          // Symbols::CR[0]
410
8.64k
      case '\r':          // Symbols::LF[0]
411
         // mjh@isi.edu
412
         //            ^
413
8.64k
         pb.data(eOrp, anchor);
414
8.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
9.06k
   }
442
9.06k
}
443
444
void
445
SdpContents::Session::Email::parse(ParseBuffer& pb)
446
2.80k
{
447
2.80k
   pb.skipChar('e');
448
2.80k
   parseEorP(pb, mAddress, mFreeText);
449
2.80k
   skipEol(pb);
450
2.80k
}
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
6.26k
   : mNumber(rhs.mNumber),
460
6.26k
     mFreeText(rhs.mFreeText)
461
6.26k
{}
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
6.26k
{
491
6.26k
   pb.skipChar('p');
492
6.26k
   parseEorP(pb, mNumber, mFreeText);
493
6.26k
   skipEol(pb);
494
6.26k
}
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
12.7k
   : mAddrType(IP4),
506
12.7k
     mAddress(),
507
12.7k
     mTTL(0)
508
12.7k
{}
509
510
SdpContents::Session::Connection::Connection(const Connection& rhs)
511
33.7k
   : mAddrType(rhs.mAddrType),
512
33.7k
     mAddress(rhs.mAddress),
513
33.7k
     mTTL(rhs.mTTL)
514
33.7k
{
515
33.7k
}
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
6.26k
{
553
6.26k
   pb.skipChar('c');
554
6.26k
   pb.skipChar(Symbols::EQUALS[0]);
555
6.26k
   pb.skipChar('I');
556
6.26k
   pb.skipChar('N');
557
558
6.26k
   const char* anchor = pb.skipChar(Symbols::SPACE[0]);
559
6.26k
   pb.skipToChar(Symbols::SPACE[0]);
560
6.26k
   Data addrType;
561
6.26k
   pb.data(addrType, anchor);
562
6.26k
   if (addrType == NetworkType[IP4])
563
425
   {
564
425
      mAddrType = IP4;
565
425
   }
566
5.83k
   else if (addrType == NetworkType[IP6])
567
195
   {
568
195
      mAddrType = IP6;
569
195
   }
570
5.64k
   else
571
5.64k
   {
572
5.64k
      mAddrType = static_cast<AddrType>(0);
573
5.64k
   }
574
575
6.26k
   anchor = pb.skipChar();
576
6.26k
   pb.skipToOneOf(Symbols::SLASH, Symbols::CRLF);
577
6.26k
   pb.data(mAddress, anchor);
578
579
6.26k
   mTTL = 0;
580
6.26k
   if (mAddrType == IP4 && !pb.eof() && *pb.position() == Symbols::SLASH[0])
581
210
   {
582
210
      pb.skipChar();
583
210
      mTTL = pb.integer();
584
210
   }
585
586
   // multicast dealt with above this parser
587
6.26k
   if (!pb.eof() && *pb.position() != Symbols::SLASH[0])
588
1.33k
   {
589
1.33k
      skipEol(pb);
590
1.33k
   }
591
6.26k
}
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
6.14k
   : mModifier(rhs.mModifier),
601
6.14k
     mKbPerSecond(rhs.mKbPerSecond)
602
6.14k
{}
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
6.14k
{
628
6.14k
   pb.skipChar('b');
629
6.14k
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
630
631
6.14k
   pb.skipToOneOf(Symbols::COLON, Symbols::CRLF);
632
6.14k
   if (*pb.position() == Symbols::COLON[0])
633
6.10k
   {
634
6.10k
      pb.data(mModifier, anchor);
635
636
6.10k
      anchor = pb.skipChar(Symbols::COLON[0]);
637
6.10k
      mKbPerSecond = pb.integer();
638
639
6.10k
      skipEol(pb);
640
6.10k
   }
641
43
   else
642
43
   {
643
43
      pb.fail(__FILE__, __LINE__);
644
43
   }
645
6.14k
}
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
870
   : mStart(rhs.mStart),
655
870
     mStop(rhs.mStop)
656
870
{}
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
870
{
688
870
   pb.skipChar('t');
689
870
   pb.skipChar(Symbols::EQUALS[0]);
690
691
870
   mStart = pb.uInt32();
692
870
   pb.skipChar(Symbols::SPACE[0]);
693
870
   mStop = pb.uInt32();
694
695
870
   skipEol(pb);
696
697
2.10k
   while (!pb.eof() && *pb.position() == 'r')
698
1.23k
   {
699
1.23k
      addRepeat(Repeat());
700
1.23k
      mRepeats.back().parse(pb);
701
1.23k
   }
702
870
}
703
704
void
705
SdpContents::Session::Time::addRepeat(const Repeat& repeat)
706
1.23k
{
707
1.23k
   mRepeats.push_back(repeat);
708
1.23k
}
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.32k
{
737
8.32k
   int v = pb.integer();
738
8.32k
   if (!pb.eof())
739
8.27k
   {
740
8.27k
      switch (*pb.position())
741
8.27k
      {
742
212
    case 's' :
743
212
       pb.skipChar();
744
212
       break;
745
1.21k
    case 'm' :
746
1.21k
       v *= 60;
747
1.21k
       pb.skipChar();
748
1.21k
       break;
749
203
    case 'h' :
750
203
       v *= 3600;
751
203
       pb.skipChar();
752
203
       break;
753
241
    case 'd' :
754
241
       v *= 3600*24;
755
241
       pb.skipChar();
756
8.27k
      }
757
8.27k
   }
758
8.32k
   return v;
759
8.32k
}
760
761
void
762
SdpContents::Session::Time::Repeat::parse(ParseBuffer& pb)
763
1.23k
{
764
1.23k
   pb.skipChar('r');
765
1.23k
   pb.skipChar(Symbols::EQUALS[0]);
766
767
1.23k
   mInterval = parseTypedTime(pb);
768
1.23k
   pb.skipChar(Symbols::SPACE[0]);
769
770
1.23k
   mDuration = parseTypedTime(pb);
771
772
4.24k
   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.23k
   skipEol(pb);
780
1.23k
}
781
782
SdpContents::Session::Timezones::Adjustment::Adjustment(unsigned long _time,
783
                                                        int _offset)
784
2.92k
   : time(_time),
785
2.92k
     offset(_offset)
786
2.92k
{}
787
788
SdpContents::Session::Timezones::Adjustment::Adjustment(const Adjustment& rhs)
789
2.90k
   : time(rhs.time),
790
2.90k
     offset(rhs.offset)
791
2.90k
{}
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.52k
   : mAdjustments()
806
6.52k
{}
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.92k
   {
854
2.92k
      Adjustment adj(0, 0);
855
2.92k
      adj.time = pb.integer();
856
2.92k
      pb.skipChar(Symbols::SPACE[0]);
857
2.92k
      adj.offset = parseTypedTime(pb);
858
2.92k
      addAdjustment(adj);
859
860
2.92k
      if (!pb.eof() && *pb.position() == Symbols::SPACE[0])
861
1.01k
      {
862
1.01k
         pb.skipChar();
863
1.01k
      }
864
2.92k
   }
865
866
73
   skipEol(pb);
867
73
}
868
869
void
870
SdpContents::Session::Timezones::addAdjustment(const Adjustment& adjust)
871
2.90k
{
872
2.90k
   mAdjustments.push_back(adjust);
873
2.90k
}
874
875
SdpContents::Session::Encryption::Encryption()
876
24.3k
   : mMethod(NoEncryption),
877
24.3k
     mKey()
878
24.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
17.8k
   : mMethod(rhs.mMethod),
888
17.8k
     mKey(rhs.mKey)
889
17.8k
{}
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.71k
{
921
1.71k
   pb.skipChar('k');
922
1.71k
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
923
924
1.71k
   pb.skipToChar(Symbols::COLON[0]);
925
1.71k
   if (!pb.eof())
926
1.06k
   {
927
1.06k
      Data p;
928
1.06k
      pb.data(p, anchor);
929
1.06k
      if (p == KeyTypes[Clear])
930
194
      {
931
194
         mMethod = Clear;
932
194
      }
933
872
      else if (p == KeyTypes[Base64])
934
194
      {
935
194
         mMethod = Base64;
936
194
      }
937
678
      else if (p == KeyTypes[UriKey])
938
194
      {
939
194
         mMethod = UriKey;
940
194
      }
941
942
1.06k
      anchor = pb.skipChar(Symbols::COLON[0]);
943
1.06k
      pb.skipToOneOf(Symbols::CRLF);
944
1.06k
      pb.data(mKey, anchor);
945
1.06k
   }
946
647
   else
947
647
   {
948
647
      pb.reset(anchor);
949
647
      pb.skipToOneOf(Symbols::CRLF);
950
951
647
      Data p;
952
647
      pb.data(p, anchor);
953
647
      if (p == KeyTypes[Prompt])
954
310
      {
955
310
         mMethod = Prompt;
956
310
      }
957
647
   }
958
959
1.71k
   skipEol(pb);
960
1.71k
}
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.52k
{
1006
6.52k
   pb.skipChar('v');
1007
6.52k
   pb.skipChar(Symbols::EQUALS[0]);
1008
6.52k
   mVersion = pb.integer();
1009
6.52k
   skipEol(pb);
1010
1011
6.52k
   mOrigin.parse(pb);
1012
1013
6.52k
   pb.skipChar('s');
1014
6.52k
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
1015
6.52k
   pb.skipToOneOf(Symbols::CRLF);
1016
6.52k
   pb.data(mName, anchor);
1017
6.52k
   skipEol(pb);
1018
1019
6.52k
   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.52k
   if (!pb.eof() && *pb.position() == 'u')
1029
61
   {
1030
61
      pb.skipChar('u');
1031
61
      pb.skipChar(Symbols::EQUALS[0]);
1032
61
      mUri.parse(pb);
1033
61
      skipEol(pb);
1034
61
   }
1035
1036
9.32k
   while (!pb.eof() && *pb.position() == 'e')
1037
2.80k
   {
1038
2.80k
      addEmail(Email());
1039
2.80k
      mEmails.back().parse(pb);
1040
2.80k
   }
1041
1042
12.7k
   while (!pb.eof() && *pb.position() == 'p')
1043
6.26k
   {
1044
6.26k
      addPhone(Phone());
1045
6.26k
      mPhones.back().parse(pb);
1046
6.26k
   }
1047
1048
6.52k
   if (!pb.eof() && *pb.position() == 'c')
1049
29
   {
1050
29
      mConnection.parse(pb);
1051
29
   }
1052
1053
6.97k
   while (!pb.eof() && *pb.position() == 'b')
1054
456
   {
1055
456
      addBandwidth(Bandwidth());
1056
456
      mBandwidths.back().parse(pb);
1057
456
   }
1058
1059
7.39k
   while (!pb.eof() && *pb.position() == 't')
1060
870
   {
1061
870
      addTime(Time());
1062
870
      mTimes.back().parse(pb);
1063
870
   }
1064
1065
6.52k
   if (!pb.eof() && *pb.position() == 'z')
1066
73
   {
1067
73
      mTimezones.parse(pb);
1068
73
   }
1069
1070
6.52k
   if (!pb.eof() && *pb.position() == 'k')
1071
92
   {
1072
92
      mEncryption.parse(pb);
1073
92
   }
1074
1075
6.52k
   mAttributeHelper.parse(pb);
1076
1077
24.3k
   while (!pb.eof() && *pb.position() == 'm')
1078
17.8k
   {
1079
17.8k
      addMedium(Medium());
1080
17.8k
      mMedia.back().parse(pb);
1081
17.8k
   }
1082
6.52k
}
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.80k
{
1173
2.80k
   mEmails.push_back(email);
1174
2.80k
}
1175
1176
void
1177
SdpContents::Session::addTime(const Time& t)
1178
870
{
1179
870
   mTimes.push_back(t);
1180
870
}
1181
1182
void
1183
SdpContents::Session::addPhone(const Phone& phone)
1184
6.26k
{
1185
6.26k
   mPhones.push_back(phone);
1186
6.26k
}
1187
1188
void
1189
SdpContents::Session::addBandwidth(const Bandwidth& bandwidth)
1190
456
{
1191
456
   mBandwidths.push_back(bandwidth);
1192
456
}
1193
1194
void
1195
SdpContents::Session::addMedium(const Medium& medium)
1196
17.8k
{
1197
17.8k
   mMedia.push_back(medium);
1198
17.8k
   mMedia.back().setSession(this);
1199
17.8k
}
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
17.8k
   : mSession(0),
1527
17.8k
     mPort(0),
1528
17.8k
     mMulticast(1),
1529
17.8k
     mRtpMapDone(false)
1530
17.8k
{}
1531
1532
SdpContents::Session::Medium::Medium(const Medium& rhs)
1533
17.8k
   : mSession(0),
1534
17.8k
     mName(rhs.mName),
1535
17.8k
     mPort(rhs.mPort),
1536
17.8k
     mMulticast(rhs.mMulticast),
1537
17.8k
     mProtocol(rhs.mProtocol),
1538
17.8k
     mFormats(rhs.mFormats),
1539
17.8k
     mCodecs(rhs.mCodecs),
1540
17.8k
     mTransport(rhs.mTransport),
1541
17.8k
     mInformation(rhs.mInformation),
1542
17.8k
     mConnections(rhs.mConnections),
1543
17.8k
     mBandwidths(rhs.mBandwidths),
1544
17.8k
     mEncryption(rhs.mEncryption),
1545
17.8k
     mAttributeHelper(rhs.mAttributeHelper),
1546
17.8k
     mRtpMapDone(rhs.mRtpMapDone),
1547
17.8k
     mRtpMap(rhs.mRtpMap)
1548
17.8k
{
1549
17.8k
}
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
17.8k
{
1585
17.8k
   mSession = session;
1586
17.8k
}
1587
1588
void
1589
SdpContents::Session::Medium::parse(ParseBuffer& pb)
1590
17.8k
{
1591
17.8k
   pb.skipChar('m');
1592
17.8k
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
1593
1594
17.8k
   pb.skipToChar(Symbols::SPACE[0]);
1595
17.8k
   pb.data(mName, anchor);
1596
17.8k
   pb.skipChar(Symbols::SPACE[0]);
1597
1598
17.8k
   mPort = pb.integer();
1599
1600
17.8k
   if (*pb.position() == Symbols::SLASH[0])
1601
10.3k
   {
1602
10.3k
      pb.skipChar();
1603
10.3k
      mMulticast = pb.integer();
1604
10.3k
   }
1605
1606
17.8k
   anchor = pb.skipChar(Symbols::SPACE[0]);
1607
17.8k
   pb.skipToOneOf(Symbols::SPACE, Symbols::CRLF);
1608
17.8k
   pb.data(mProtocol, anchor);
1609
1610
262k
   while (*pb.position() != Symbols::CR[0] &&
1611
261k
          *pb.position() != Symbols::LF[0])
1612
244k
   {
1613
244k
      anchor = pb.skipChar(Symbols::SPACE[0]);
1614
244k
      pb.skipToOneOf(Symbols::SPACE, Symbols::CRLF);
1615
244k
     if(pb.position() != anchor)
1616
234k
     {
1617
234k
      Data format;
1618
234k
      pb.data(format, anchor);
1619
234k
      addFormat(format);
1620
234k
     }
1621
244k
   }
1622
1623
17.8k
   skipEol(pb);
1624
1625
17.8k
   if (!pb.eof() && *pb.position() == 'i')
1626
195
   {
1627
195
      pb.skipChar('i');
1628
195
      anchor = pb.skipChar(Symbols::EQUALS[0]);
1629
195
      pb.skipToOneOf(Symbols::CRLF);
1630
195
      pb.data(mInformation, anchor);
1631
1632
195
      skipEol(pb);
1633
195
   }
1634
1635
24.0k
   while (!pb.eof() && *pb.position() == 'c')
1636
6.23k
   {
1637
6.23k
      addConnection(Connection());
1638
6.23k
      mConnections.back().parse(pb);
1639
6.23k
      if (!pb.eof() && *pb.position() == Symbols::SLASH[0])
1640
4.86k
      {
1641
         // Note:  we only get here if there was a /<number of addresses> 
1642
         //        parameter following the connection address. 
1643
4.86k
         pb.skipChar();
1644
4.86k
         int num = pb.integer();
1645
1646
4.86k
         if (num > 255)
1647
8
         {
1648
8
            pb.fail(__FILE__, __LINE__, "Too many connection addresses");
1649
8
         }
1650
1651
4.86k
         Connection& con = mConnections.back();
1652
4.86k
         const Data& addr = con.getAddress();
1653
4.86k
         if (addr.empty())
1654
48
         {
1655
48
            pb.fail(__FILE__, __LINE__, "IP address expected");
1656
48
         }
1657
4.86k
         Data::size_type i = addr.size() - 1;
1658
1.05M
         for (; i; i--)
1659
1.05M
         {
1660
1.05M
            if (addr[i] == '.' || addr[i] == ':') // ipv4 or ipv6
1661
900
            {
1662
900
               break;
1663
900
            }
1664
1.05M
         }
1665
1666
4.86k
         if (addr[i] == '.')  // add a number of ipv4 connections
1667
2.71k
         {
1668
2.71k
            Data before(addr.data(), i+1);
1669
2.71k
            ParseBuffer subpb(addr.data()+i+1, addr.size()-i-1);
1670
2.71k
            int after = subpb.integer();
1671
1672
9.26k
            for (int i = 1; i < num; i++)
1673
6.54k
            {
1674
6.54k
               addConnection(con);
1675
6.54k
               mConnections.back().mAddress = before + Data(after+i);
1676
6.54k
            }
1677
2.71k
         }
1678
4.86k
         if (addr[i] == ':') // add a number of ipv6 connections
1679
2.04k
         {
1680
2.04k
            Data before(addr.data(), i+1);
1681
2.04k
            int after = Helper::hex2integer(addr.data()+i+1);
1682
2.04k
            char hexstring[9];
1683
1684
23.0k
            for (int i = 1; i < num; i++)
1685
21.0k
            {
1686
21.0k
               addConnection(con);
1687
21.0k
               memset(hexstring, 0, sizeof(hexstring));
1688
21.0k
               Helper::integer2hex(hexstring, after+i, false /* supress leading zeros */);
1689
21.0k
               mConnections.back().mAddress = before + Data(hexstring);
1690
21.0k
            }
1691
2.04k
         }
1692
1693
4.86k
         skipEol(pb);
1694
4.86k
      }
1695
6.23k
   }
1696
1697
23.5k
   while (!pb.eof() && *pb.position() == 'b')
1698
5.68k
   {
1699
5.68k
      addBandwidth(Bandwidth());
1700
5.68k
      mBandwidths.back().parse(pb);
1701
5.68k
   }
1702
1703
17.8k
   if (!pb.eof() && *pb.position() == 'k')
1704
1.62k
   {
1705
1.62k
      mEncryption.parse(pb);
1706
1.62k
   }
1707
1708
17.8k
   mAttributeHelper.parse(pb);
1709
17.8k
}
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
234k
{
1797
234k
   mFormats.push_back(format);
1798
234k
}
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
33.7k
{
1810
33.7k
   mConnections.push_back(connection);
1811
33.7k
}
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
5.68k
{
1823
5.68k
   mBandwidths.push_back(bandwidth);
1824
5.68k
}
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
 */