Coverage Report

Created: 2025-11-05 06:27

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
87.6k
{
54
88.2k
   while(!pb.eof() && (*pb.position() == Symbols::SPACE[0] ||
55
87.2k
                       *pb.position() == Symbols::TAB[0]))
56
586
   {
57
586
      pb.skipChar();
58
586
   }
59
   
60
87.6k
   if (*pb.position() == Symbols::LF[0])
61
84.8k
   {
62
84.8k
      pb.skipChar();
63
84.8k
   }
64
2.88k
   else
65
2.88k
   {
66
      // allow extra 0x0d bytes.
67
5.15k
      while(*pb.position() == Symbols::CR[0])
68
2.27k
      {
69
2.27k
         pb.skipChar();
70
2.27k
      } 
71
2.88k
      pb.skipChar(Symbols::LF[0]);
72
2.88k
   }
73
   
74
87.6k
}
75
76
AttributeHelper::AttributeHelper(const AttributeHelper& rhs)
77
4.73k
   : mAttributeList(rhs.mAttributeList),
78
4.73k
     mAttributes(rhs.mAttributes)
79
4.73k
{
80
4.73k
}
81
82
AttributeHelper::AttributeHelper()
83
10.8k
{
84
10.8k
}
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
5.31k
{
133
33.7k
   while (!pb.eof() && *pb.position() == 'a')
134
28.3k
   {
135
28.3k
      Data key;
136
28.3k
      Data value;
137
138
28.3k
      pb.skipChar('a');
139
28.3k
      const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
140
28.3k
      pb.skipToOneOf(Symbols::COLON, Symbols::CRLF);
141
28.3k
      pb.data(key, anchor);
142
28.3k
      if (!pb.eof() && *pb.position() == Symbols::COLON[0])
143
752
      {
144
752
         anchor = pb.skipChar(Symbols::COLON[0]);
145
752
         pb.skipToOneOf(Symbols::CRLF);
146
752
         pb.data(value, anchor);
147
752
      }
148
149
28.3k
      if(!pb.eof()) skipEol(pb);
150
151
28.3k
      mAttributeList.push_back(std::make_pair(key, value));
152
28.3k
      mAttributes[key].push_back(value);
153
28.3k
   }
154
5.31k
}
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.07k
   : Contents(hfv, contentTypes)
184
6.07k
{
185
6.07k
}
186
187
//SdpContents::SdpContents(const SdpContents& rhs)
188
//   : Contents(rhs),
189
//     mSession(rhs.mSession)
190
//{
191
//}
192
193
SdpContents::~SdpContents()
194
6.07k
{
195
6.07k
}
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.07k
{
218
6.07k
   mSession.parse(pb);
219
6.07k
}
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.08k
   : mUser(),
239
6.08k
     mSessionId(0),
240
6.08k
     mVersion(0),
241
6.08k
     mAddrType(IP4),
242
6.08k
     mAddress(nullOrigin)
243
6.08k
{}
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
1.96k
{
304
1.96k
   pb.skipChar('o');
305
1.96k
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
306
307
1.96k
   pb.skipToChar(Symbols::SPACE[0]);
308
1.96k
   pb.data(mUser, anchor);
309
310
1.96k
   anchor = pb.skipChar(Symbols::SPACE[0]);
311
1.96k
   try
312
1.96k
   {
313
1.96k
      mSessionId = pb.uInt64();
314
1.96k
   }
315
1.96k
   catch(ParseException& e)
316
1.96k
   {
317
1.86k
       WarningLog(<< "Exception parsing origin sessionid: " << e);
318
1.86k
   }
319
1.96k
   pb.skipToChar(Symbols::SPACE[0]);
320
321
1.95k
   anchor = pb.skipChar(Symbols::SPACE[0]);
322
1.95k
   try
323
1.95k
   {
324
1.95k
      mVersion = pb.uInt64();
325
1.95k
   }
326
1.95k
   catch(ParseException& e)
327
1.95k
   {
328
1.83k
       WarningLog(<< "Exception parsing origin version: " << e);
329
1.83k
   }
330
1.95k
   pb.skipToChar(Symbols::SPACE[0]);
331
332
1.86k
   pb.skipChar(Symbols::SPACE[0]);
333
1.86k
   pb.skipChar('I');
334
1.86k
   pb.skipChar('N');
335
336
1.86k
   anchor = pb.skipChar(Symbols::SPACE[0]);
337
1.86k
   pb.skipToChar(Symbols::SPACE[0]);
338
1.86k
   Data addrType;
339
1.86k
   pb.data(addrType, anchor);
340
1.86k
   if (addrType == NetworkType[IP4])
341
1
   {
342
1
      mAddrType = IP4;
343
1
   }
344
1.86k
   else if (addrType == NetworkType[IP6])
345
1
   {
346
1
      mAddrType = IP6;
347
1
   }
348
1.86k
   else
349
1.86k
   {
350
1.86k
      mAddrType = static_cast<AddrType>(0);
351
1.86k
   }
352
353
1.86k
   anchor = pb.skipChar(Symbols::SPACE[0]);
354
1.86k
   pb.skipToOneOf(Symbols::CRLF);
355
1.86k
   pb.data(mAddress, anchor);
356
357
1.86k
   skipEol(pb);
358
1.86k
}
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
1.83k
   : mAddress(rhs.mAddress),
368
1.83k
     mFreeText(rhs.mFreeText)
369
1.83k
{}
370
371
SdpContents::Session::Email&
372
SdpContents::Session::Email::operator=(const Email& rhs)
373
0
{
374
0
   if (this != &rhs)
375
0
   {
376
0
      mAddress = rhs.mAddress;
377
0
      mFreeText = rhs.mFreeText;
378
0
   }
379
0
   return *this;
380
0
}
381
382
EncodeStream&
383
SdpContents::Session::Email::encode(EncodeStream& s) const
384
0
{
385
0
   s << "e=" << mAddress;
386
0
   if (!mFreeText.empty())
387
0
   {
388
0
      s << Symbols::SPACE[0];
389
0
      s << Symbols::LPAREN[0] << mFreeText << Symbols::RPAREN[0];
390
0
   }
391
0
   s << Symbols::CRLF;
392
393
0
   return s;
394
0
}
395
396
// helper to parse email and phone numbers with display name
397
void parseEorP(ParseBuffer& pb, Data& eOrp, Data& freeText)
398
3.09k
{
399
   // =mjh@isi.edu (Mark Handley)
400
   // =mjh@isi.edu
401
   // =Mark Handley <mjh@isi.edu>
402
   // =<mjh@isi.edu>
403
404
3.09k
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
405
406
3.09k
   pb.skipToOneOf("<(\n\r");  // find a left angle bracket "<", a left paren "(", or a CR 
407
3.09k
   switch (*pb.position())
408
3.09k
   {
409
2.30k
      case '\n':          // Symbols::CR[0]
410
2.67k
      case '\r':          // Symbols::LF[0]
411
         // mjh@isi.edu
412
         //            ^
413
2.67k
         pb.data(eOrp, anchor);
414
2.67k
         break;
415
416
194
      case '<':         // Symbols::LA_QUOTE[0]
417
         // Mark Handley <mjh@isi.edu>
418
         //              ^
419
         // <mjh@isi.edu>
420
         // ^
421
        
422
194
         pb.data(freeText, anchor);
423
194
         anchor = pb.skipChar();
424
194
         pb.skipToEndQuote(Symbols::RA_QUOTE[0]);
425
194
         pb.data(eOrp, anchor);
426
194
         pb.skipChar(Symbols::RA_QUOTE[0]);
427
194
         break;
428
        
429
194
      case '(':         // Symbols::LPAREN[0]
430
         // mjh@isi.edu (Mark Handley)
431
         //             ^
432
        
433
194
         pb.data(eOrp, anchor);
434
194
         anchor = pb.skipChar();
435
194
         pb.skipToEndQuote(Symbols::RPAREN[0]);
436
194
         pb.data(freeText, anchor);
437
194
         pb.skipChar(Symbols::RPAREN[0]);
438
194
         break;
439
0
      default:
440
0
         resip_assert(0);
441
3.09k
   }
442
3.09k
}
443
444
void
445
SdpContents::Session::Email::parse(ParseBuffer& pb)
446
1.83k
{
447
1.83k
   pb.skipChar('e');
448
1.83k
   parseEorP(pb, mAddress, mFreeText);
449
1.83k
   skipEol(pb);
450
1.83k
}
451
452
SdpContents::Session::Phone::Phone(const Data& number,
453
                                   const Data& freeText)
454
0
   : mNumber(number),
455
0
     mFreeText(freeText)
456
0
{}
457
458
SdpContents::Session::Phone::Phone(const Phone& rhs)
459
1.25k
   : mNumber(rhs.mNumber),
460
1.25k
     mFreeText(rhs.mFreeText)
461
1.25k
{}
462
463
SdpContents::Session::Phone&
464
SdpContents::Session::Phone::operator=(const Phone& rhs)
465
0
{
466
0
   if (this != &rhs)
467
0
   {
468
0
      mNumber = rhs.mNumber;
469
0
      mFreeText = rhs.mFreeText;
470
0
   }
471
0
   return *this;
472
0
}
473
474
EncodeStream&
475
SdpContents::Session::Phone::encode(EncodeStream& s) const
476
0
{
477
0
  s << "p=" << mNumber;
478
0
   if (!mFreeText.empty())
479
0
   {
480
0
      s << Symbols::SPACE[0];
481
0
      s << Symbols::LPAREN[0] << mFreeText << Symbols::RPAREN[0];
482
0
   }
483
0
   s << Symbols::CRLF;
484
485
0
   return s;
486
0
}
487
488
void
489
SdpContents::Session::Phone::parse(ParseBuffer& pb)
490
1.25k
{
491
1.25k
   pb.skipChar('p');
492
1.25k
   parseEorP(pb, mNumber, mFreeText);
493
1.25k
   skipEol(pb);
494
1.25k
}
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.2k
   : mAddrType(IP4),
506
12.2k
     mAddress(),
507
12.2k
     mTTL(0)
508
12.2k
{}
509
510
SdpContents::Session::Connection::Connection(const Connection& rhs)
511
68.0k
   : mAddrType(rhs.mAddrType),
512
68.0k
     mAddress(rhs.mAddress),
513
68.0k
     mTTL(rhs.mTTL)
514
68.0k
{
515
68.0k
}
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.20k
{
553
6.20k
   pb.skipChar('c');
554
6.20k
   pb.skipChar(Symbols::EQUALS[0]);
555
6.20k
   pb.skipChar('I');
556
6.20k
   pb.skipChar('N');
557
558
6.20k
   const char* anchor = pb.skipChar(Symbols::SPACE[0]);
559
6.20k
   pb.skipToChar(Symbols::SPACE[0]);
560
6.20k
   Data addrType;
561
6.20k
   pb.data(addrType, anchor);
562
6.20k
   if (addrType == NetworkType[IP4])
563
427
   {
564
427
      mAddrType = IP4;
565
427
   }
566
5.77k
   else if (addrType == NetworkType[IP6])
567
225
   {
568
225
      mAddrType = IP6;
569
225
   }
570
5.55k
   else
571
5.55k
   {
572
5.55k
      mAddrType = static_cast<AddrType>(0);
573
5.55k
   }
574
575
6.20k
   anchor = pb.skipChar();
576
6.20k
   pb.skipToOneOf(Symbols::SLASH, Symbols::CRLF);
577
6.20k
   pb.data(mAddress, anchor);
578
579
6.20k
   mTTL = 0;
580
6.20k
   if (mAddrType == IP4 && !pb.eof() && *pb.position() == Symbols::SLASH[0])
581
221
   {
582
221
      pb.skipChar();
583
221
      mTTL = pb.integer();
584
221
   }
585
586
   // multicast dealt with above this parser
587
6.20k
   if (!pb.eof() && *pb.position() != Symbols::SLASH[0])
588
1.32k
   {
589
1.32k
      skipEol(pb);
590
1.32k
   }
591
6.20k
}
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
1.36k
   : mModifier(rhs.mModifier),
601
1.36k
     mKbPerSecond(rhs.mKbPerSecond)
602
1.36k
{}
603
604
SdpContents::Session::Bandwidth&
605
SdpContents::Session::Bandwidth::operator=(const Bandwidth& rhs)
606
0
{
607
0
   if (this != &rhs)
608
0
   {
609
0
      mModifier = rhs.mModifier;
610
0
      mKbPerSecond = rhs.mKbPerSecond;
611
0
   }
612
0
   return *this;
613
0
}
614
615
EncodeStream&
616
SdpContents::Session::Bandwidth::encode(EncodeStream& s) const
617
0
{
618
0
   s << "b="
619
0
     << mModifier
620
0
     << Symbols::COLON[0] << mKbPerSecond
621
0
     << Symbols::CRLF;
622
0
   return s;
623
0
}
624
625
void
626
SdpContents::Session::Bandwidth::parse(ParseBuffer& pb)
627
1.36k
{
628
1.36k
   pb.skipChar('b');
629
1.36k
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
630
631
1.36k
   pb.skipToOneOf(Symbols::COLON, Symbols::CRLF);
632
1.36k
   if (*pb.position() == Symbols::COLON[0])
633
1.33k
   {
634
1.33k
      pb.data(mModifier, anchor);
635
636
1.33k
      anchor = pb.skipChar(Symbols::COLON[0]);
637
1.33k
      mKbPerSecond = pb.integer();
638
639
1.33k
      skipEol(pb);
640
1.33k
   }
641
38
   else
642
38
   {
643
38
      pb.fail(__FILE__, __LINE__);
644
38
   }
645
1.36k
}
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
36.3k
   : mStart(rhs.mStart),
655
36.3k
     mStop(rhs.mStop)
656
36.3k
{}
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
36.3k
{
688
36.3k
   pb.skipChar('t');
689
36.3k
   pb.skipChar(Symbols::EQUALS[0]);
690
691
36.3k
   mStart = pb.uInt32();
692
36.3k
   pb.skipChar(Symbols::SPACE[0]);
693
36.3k
   mStop = pb.uInt32();
694
695
36.3k
   skipEol(pb);
696
697
37.3k
   while (!pb.eof() && *pb.position() == 'r')
698
980
   {
699
980
      addRepeat(Repeat());
700
980
      mRepeats.back().parse(pb);
701
980
   }
702
36.3k
}
703
704
void
705
SdpContents::Session::Time::addRepeat(const Repeat& repeat)
706
980
{
707
980
   mRepeats.push_back(repeat);
708
980
}
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
6.97k
{
737
6.97k
   int v = pb.integer();
738
6.97k
   if (!pb.eof())
739
6.92k
   {
740
6.92k
      switch (*pb.position())
741
6.92k
      {
742
204
    case 's' :
743
204
       pb.skipChar();
744
204
       break;
745
2.24k
    case 'm' :
746
2.24k
       v *= 60;
747
2.24k
       pb.skipChar();
748
2.24k
       break;
749
254
    case 'h' :
750
254
       v *= 3600;
751
254
       pb.skipChar();
752
254
       break;
753
112
    case 'd' :
754
112
       v *= 3600*24;
755
112
       pb.skipChar();
756
6.92k
      }
757
6.92k
   }
758
6.97k
   return v;
759
6.97k
}
760
761
void
762
SdpContents::Session::Time::Repeat::parse(ParseBuffer& pb)
763
980
{
764
980
   pb.skipChar('r');
765
980
   pb.skipChar(Symbols::EQUALS[0]);
766
767
980
   mInterval = parseTypedTime(pb);
768
980
   pb.skipChar(Symbols::SPACE[0]);
769
770
980
   mDuration = parseTypedTime(pb);
771
772
2.27k
   while (!pb.eof() && *pb.position() != Symbols::CR[0])
773
1.29k
   {
774
1.29k
      pb.skipChar(Symbols::SPACE[0]);
775
776
1.29k
      mOffsets.push_back(parseTypedTime(pb));
777
1.29k
   }
778
779
980
   skipEol(pb);
780
980
}
781
782
SdpContents::Session::Timezones::Adjustment::Adjustment(unsigned long _time,
783
                                                        int _offset)
784
3.78k
   : time(_time),
785
3.78k
     offset(_offset)
786
3.78k
{}
787
788
SdpContents::Session::Timezones::Adjustment::Adjustment(const Adjustment& rhs)
789
3.76k
   : time(rhs.time),
790
3.76k
     offset(rhs.offset)
791
3.76k
{}
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.08k
   : mAdjustments()
806
6.08k
{}
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
76
{
849
76
   pb.skipChar('z');
850
76
   pb.skipChar(Symbols::EQUALS[0]);
851
852
3.86k
   while (!pb.eof() && *pb.position() != Symbols::CR[0])
853
3.78k
   {
854
3.78k
      Adjustment adj(0, 0);
855
3.78k
      adj.time = pb.integer();
856
3.78k
      pb.skipChar(Symbols::SPACE[0]);
857
3.78k
      adj.offset = parseTypedTime(pb);
858
3.78k
      addAdjustment(adj);
859
860
3.78k
      if (!pb.eof() && *pb.position() == Symbols::SPACE[0])
861
921
      {
862
921
         pb.skipChar();
863
921
      }
864
3.78k
   }
865
866
76
   skipEol(pb);
867
76
}
868
869
void
870
SdpContents::Session::Timezones::addAdjustment(const Adjustment& adjust)
871
3.76k
{
872
3.76k
   mAdjustments.push_back(adjust);
873
3.76k
}
874
875
SdpContents::Session::Encryption::Encryption()
876
10.8k
   : mMethod(NoEncryption),
877
10.8k
     mKey()
878
10.8k
{}
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
4.73k
   : mMethod(rhs.mMethod),
888
4.73k
     mKey(rhs.mKey)
889
4.73k
{}
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.33k
{
921
1.33k
   pb.skipChar('k');
922
1.33k
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
923
924
1.33k
   pb.skipToChar(Symbols::COLON[0]);
925
1.33k
   if (!pb.eof())
926
837
   {
927
837
      Data p;
928
837
      pb.data(p, anchor);
929
837
      if (p == KeyTypes[Clear])
930
226
      {
931
226
         mMethod = Clear;
932
226
      }
933
611
      else if (p == KeyTypes[Base64])
934
66
      {
935
66
         mMethod = Base64;
936
66
      }
937
545
      else if (p == KeyTypes[UriKey])
938
194
      {
939
194
         mMethod = UriKey;
940
194
      }
941
942
837
      anchor = pb.skipChar(Symbols::COLON[0]);
943
837
      pb.skipToOneOf(Symbols::CRLF);
944
837
      pb.data(mKey, anchor);
945
837
   }
946
495
   else
947
495
   {
948
495
      pb.reset(anchor);
949
495
      pb.skipToOneOf(Symbols::CRLF);
950
951
495
      Data p;
952
495
      pb.data(p, anchor);
953
495
      if (p == KeyTypes[Prompt])
954
194
      {
955
194
         mMethod = Prompt;
956
194
      }
957
495
   }
958
959
1.33k
   skipEol(pb);
960
1.33k
}
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.07k
{
1006
6.07k
   pb.skipChar('v');
1007
6.07k
   pb.skipChar(Symbols::EQUALS[0]);
1008
6.07k
   mVersion = pb.integer();
1009
6.07k
   skipEol(pb);
1010
1011
6.07k
   mOrigin.parse(pb);
1012
1013
6.07k
   pb.skipChar('s');
1014
6.07k
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
1015
6.07k
   pb.skipToOneOf(Symbols::CRLF);
1016
6.07k
   pb.data(mName, anchor);
1017
6.07k
   skipEol(pb);
1018
1019
6.07k
   if (!pb.eof() && *pb.position() == 'i')
1020
7
   {
1021
7
      pb.skipChar('i');
1022
7
      const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
1023
7
      pb.skipToOneOf(Symbols::CRLF);
1024
7
      pb.data(mInformation, anchor);
1025
7
      skipEol(pb);
1026
7
   }
1027
1028
6.07k
   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
7.91k
   while (!pb.eof() && *pb.position() == 'e')
1037
1.83k
   {
1038
1.83k
      addEmail(Email());
1039
1.83k
      mEmails.back().parse(pb);
1040
1.83k
   }
1041
1042
7.33k
   while (!pb.eof() && *pb.position() == 'p')
1043
1.25k
   {
1044
1.25k
      addPhone(Phone());
1045
1.25k
      mPhones.back().parse(pb);
1046
1.25k
   }
1047
1048
6.07k
   if (!pb.eof() && *pb.position() == 'c')
1049
25
   {
1050
25
      mConnection.parse(pb);
1051
25
   }
1052
1053
7.02k
   while (!pb.eof() && *pb.position() == 'b')
1054
946
   {
1055
946
      addBandwidth(Bandwidth());
1056
946
      mBandwidths.back().parse(pb);
1057
946
   }
1058
1059
42.4k
   while (!pb.eof() && *pb.position() == 't')
1060
36.3k
   {
1061
36.3k
      addTime(Time());
1062
36.3k
      mTimes.back().parse(pb);
1063
36.3k
   }
1064
1065
6.07k
   if (!pb.eof() && *pb.position() == 'z')
1066
76
   {
1067
76
      mTimezones.parse(pb);
1068
76
   }
1069
1070
6.07k
   if (!pb.eof() && *pb.position() == 'k')
1071
90
   {
1072
90
      mEncryption.parse(pb);
1073
90
   }
1074
1075
6.07k
   mAttributeHelper.parse(pb);
1076
1077
10.8k
   while (!pb.eof() && *pb.position() == 'm')
1078
4.73k
   {
1079
4.73k
      addMedium(Medium());
1080
4.73k
      mMedia.back().parse(pb);
1081
4.73k
   }
1082
6.07k
}
1083
1084
EncodeStream&
1085
SdpContents::Session::encode(EncodeStream& s) const
1086
0
{
1087
0
   s << "v=" << mVersion << Symbols::CRLF;
1088
0
   mOrigin.encode(s);
1089
0
   s << "s=" << mName << Symbols::CRLF;
1090
1091
0
   if (!mInformation.empty())
1092
0
   {
1093
0
      s << "i=" << mInformation << Symbols::CRLF;
1094
0
   }
1095
1096
0
   if (!mUri.host().empty())
1097
0
   {
1098
0
      s << "u=";
1099
0
      mUri.encode(s);
1100
0
      s << Symbols::CRLF;
1101
0
   }
1102
1103
0
   for (list<Email>::const_iterator i = mEmails.begin();
1104
0
        i != mEmails.end(); ++i)
1105
0
   {
1106
0
      i->encode(s);
1107
0
   }
1108
1109
0
   for (list<Phone>::const_iterator i = mPhones.begin();
1110
0
        i != mPhones.end(); ++i)
1111
0
   {
1112
0
      i->encode(s);
1113
0
   }
1114
1115
0
   if (!mConnection.getAddress().empty())
1116
0
   {
1117
0
      mConnection.encode(s);
1118
0
   }
1119
1120
0
   for (list<Bandwidth>::const_iterator i = mBandwidths.begin();
1121
0
        i != mBandwidths.end(); ++i)
1122
0
   {
1123
0
      i->encode(s);
1124
0
   }
1125
1126
0
   if (mTimes.empty())
1127
0
   {
1128
0
      s << "t=0 0" << Symbols::CRLF;
1129
0
   }
1130
0
   else
1131
0
   {
1132
0
      for (list<Time>::const_iterator i = mTimes.begin();
1133
0
           i != mTimes.end(); ++i)
1134
0
      {
1135
0
         i->encode(s);
1136
0
      }
1137
0
   }
1138
1139
0
   mTimezones.encode(s);
1140
1141
0
   if (mEncryption.getMethod() != Encryption::NoEncryption)
1142
0
   {
1143
0
      mEncryption.encode(s);
1144
0
   }
1145
1146
0
   mAttributeHelper.encode(s);
1147
1148
0
   for (MediumContainer::const_iterator i = mMedia.begin();
1149
0
        i != mMedia.end(); ++i)
1150
0
   {
1151
0
      i->encode(s);
1152
0
   }
1153
1154
0
   return s;
1155
0
}
1156
1157
std::list<std::reference_wrapper<SdpContents::Session::Medium>>
1158
SdpContents::Session::getMediaByType(const Data& type)
1159
0
{
1160
0
   std::list<std::reference_wrapper<SdpContents::Session::Medium>> r;
1161
0
   std::for_each(mMedia.begin(), mMedia.end(), [&r, &type](SdpContents::Session::Medium& m){
1162
0
      if(m.name() == type)
1163
0
      {
1164
0
         r.push_back(std::ref(m));
1165
0
      }
1166
0
   });
1167
0
   return r;
1168
0
}
1169
1170
void
1171
SdpContents::Session::addEmail(const Email& email)
1172
1.83k
{
1173
1.83k
   mEmails.push_back(email);
1174
1.83k
}
1175
1176
void
1177
SdpContents::Session::addTime(const Time& t)
1178
36.3k
{
1179
36.3k
   mTimes.push_back(t);
1180
36.3k
}
1181
1182
void
1183
SdpContents::Session::addPhone(const Phone& phone)
1184
1.25k
{
1185
1.25k
   mPhones.push_back(phone);
1186
1.25k
}
1187
1188
void
1189
SdpContents::Session::addBandwidth(const Bandwidth& bandwidth)
1190
946
{
1191
946
   mBandwidths.push_back(bandwidth);
1192
946
}
1193
1194
void
1195
SdpContents::Session::addMedium(const Medium& medium)
1196
4.73k
{
1197
4.73k
   mMedia.push_back(medium);
1198
4.73k
   mMedia.back().setSession(this);
1199
4.73k
}
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
4.73k
   : mSession(0),
1527
4.73k
     mPort(0),
1528
4.73k
     mMulticast(1),
1529
4.73k
     mRtpMapDone(false)
1530
4.73k
{}
1531
1532
SdpContents::Session::Medium::Medium(const Medium& rhs)
1533
4.73k
   : mSession(0),
1534
4.73k
     mName(rhs.mName),
1535
4.73k
     mPort(rhs.mPort),
1536
4.73k
     mMulticast(rhs.mMulticast),
1537
4.73k
     mProtocol(rhs.mProtocol),
1538
4.73k
     mFormats(rhs.mFormats),
1539
4.73k
     mCodecs(rhs.mCodecs),
1540
4.73k
     mTransport(rhs.mTransport),
1541
4.73k
     mInformation(rhs.mInformation),
1542
4.73k
     mConnections(rhs.mConnections),
1543
4.73k
     mBandwidths(rhs.mBandwidths),
1544
4.73k
     mEncryption(rhs.mEncryption),
1545
4.73k
     mAttributeHelper(rhs.mAttributeHelper),
1546
4.73k
     mRtpMapDone(rhs.mRtpMapDone),
1547
4.73k
     mRtpMap(rhs.mRtpMap)
1548
4.73k
{
1549
4.73k
}
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
4.73k
{
1585
4.73k
   mSession = session;
1586
4.73k
}
1587
1588
void
1589
SdpContents::Session::Medium::parse(ParseBuffer& pb)
1590
4.73k
{
1591
4.73k
   pb.skipChar('m');
1592
4.73k
   const char* anchor = pb.skipChar(Symbols::EQUALS[0]);
1593
1594
4.73k
   pb.skipToChar(Symbols::SPACE[0]);
1595
4.73k
   pb.data(mName, anchor);
1596
4.73k
   pb.skipChar(Symbols::SPACE[0]);
1597
1598
4.73k
   mPort = pb.integer();
1599
1600
4.73k
   if (*pb.position() == Symbols::SLASH[0])
1601
194
   {
1602
194
      pb.skipChar();
1603
194
      mMulticast = pb.integer();
1604
194
   }
1605
1606
4.73k
   anchor = pb.skipChar(Symbols::SPACE[0]);
1607
4.73k
   pb.skipToOneOf(Symbols::SPACE, Symbols::CRLF);
1608
4.73k
   pb.data(mProtocol, anchor);
1609
1610
6.65k
   while (*pb.position() != Symbols::CR[0] &&
1611
6.16k
          *pb.position() != Symbols::LF[0])
1612
1.91k
   {
1613
1.91k
      anchor = pb.skipChar(Symbols::SPACE[0]);
1614
1.91k
      pb.skipToOneOf(Symbols::SPACE, Symbols::CRLF);
1615
1.91k
     if(pb.position() != anchor)
1616
1.16k
     {
1617
1.16k
      Data format;
1618
1.16k
      pb.data(format, anchor);
1619
1.16k
      addFormat(format);
1620
1.16k
     }
1621
1.91k
   }
1622
1623
4.73k
   skipEol(pb);
1624
1625
4.73k
   if (!pb.eof() && *pb.position() == 'i')
1626
67
   {
1627
67
      pb.skipChar('i');
1628
67
      anchor = pb.skipChar(Symbols::EQUALS[0]);
1629
67
      pb.skipToOneOf(Symbols::CRLF);
1630
67
      pb.data(mInformation, anchor);
1631
1632
67
      skipEol(pb);
1633
67
   }
1634
1635
10.9k
   while (!pb.eof() && *pb.position() == 'c')
1636
6.18k
   {
1637
6.18k
      addConnection(Connection());
1638
6.18k
      mConnections.back().parse(pb);
1639
6.18k
      if (!pb.eof() && *pb.position() == Symbols::SLASH[0])
1640
4.81k
      {
1641
         // Note:  we only get here if there was a /<number of addresses> 
1642
         //        parameter following the connection address. 
1643
4.81k
         pb.skipChar();
1644
4.81k
         int num = pb.integer();
1645
1646
4.81k
         if (num > 255)
1647
10
         {
1648
10
            pb.fail(__FILE__, __LINE__, "Too many connection addresses");
1649
10
         }
1650
1651
4.81k
         Connection& con = mConnections.back();
1652
4.81k
         const Data& addr = con.getAddress();
1653
4.81k
         if (addr.empty())
1654
40
         {
1655
40
            pb.fail(__FILE__, __LINE__, "IP address expected");
1656
40
         }
1657
4.81k
         Data::size_type i = addr.size() - 1;
1658
3.43M
         for (; i; i--)
1659
3.42M
         {
1660
3.42M
            if (addr[i] == '.' || addr[i] == ':') // ipv4 or ipv6
1661
921
            {
1662
921
               break;
1663
921
            }
1664
3.42M
         }
1665
1666
4.81k
         if (addr[i] == '.')  // add a number of ipv4 connections
1667
2.55k
         {
1668
2.55k
            Data before(addr.data(), i+1);
1669
2.55k
            ParseBuffer subpb(addr.data()+i+1, addr.size()-i-1);
1670
2.55k
            int after = subpb.integer();
1671
1672
7.88k
            for (int i = 1; i < num; i++)
1673
5.33k
            {
1674
5.33k
               addConnection(con);
1675
5.33k
               mConnections.back().mAddress = before + Data(after+i);
1676
5.33k
            }
1677
2.55k
         }
1678
4.81k
         if (addr[i] == ':') // add a number of ipv6 connections
1679
2.17k
         {
1680
2.17k
            Data before(addr.data(), i+1);
1681
2.17k
            int after = Helper::hex2integer(addr.data()+i+1);
1682
2.17k
            char hexstring[9];
1683
1684
58.6k
            for (int i = 1; i < num; i++)
1685
56.5k
            {
1686
56.5k
               addConnection(con);
1687
56.5k
               memset(hexstring, 0, sizeof(hexstring));
1688
56.5k
               Helper::integer2hex(hexstring, after+i, false /* supress leading zeros */);
1689
56.5k
               mConnections.back().mAddress = before + Data(hexstring);
1690
56.5k
            }
1691
2.17k
         }
1692
1693
4.81k
         skipEol(pb);
1694
4.81k
      }
1695
6.18k
   }
1696
1697
5.15k
   while (!pb.eof() && *pb.position() == 'b')
1698
422
   {
1699
422
      addBandwidth(Bandwidth());
1700
422
      mBandwidths.back().parse(pb);
1701
422
   }
1702
1703
4.73k
   if (!pb.eof() && *pb.position() == 'k')
1704
1.24k
   {
1705
1.24k
      mEncryption.parse(pb);
1706
1.24k
   }
1707
1708
4.73k
   mAttributeHelper.parse(pb);
1709
4.73k
}
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
1.16k
{
1797
1.16k
   mFormats.push_back(format);
1798
1.16k
}
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
68.0k
{
1810
68.0k
   mConnections.push_back(connection);
1811
68.0k
}
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
422
{
1823
422
   mBandwidths.push_back(bandwidth);
1824
422
}
1825
1826
void
1827
SdpContents::Session::Medium::addAttribute(const Data& key, const Data& value)
1828
0
{
1829
0
   mAttributeHelper.addAttribute(key, value);
1830
0
   if (key == rtpmap)
1831
0
   {
1832
0
      mRtpMapDone = false;
1833
0
   }
1834
0
}
1835
1836
const list<SdpContents::Session::Connection>
1837
SdpContents::Session::Medium::getConnections() const
1838
0
{
1839
0
   list<Connection> connections = const_cast<Medium*>(this)->getMediumConnections();
1840
   // If there are connections specified at the medium level, then check if a session level
1841
   // connection is present - if so then return it
1842
0
   if (connections.empty() && mSession && !mSession->connection().getAddress().empty())
1843
0
   {
1844
0
      connections.push_back(mSession->connection());
1845
0
   }
1846
1847
0
   return connections;
1848
0
}
1849
1850
bool
1851
SdpContents::Session::Medium::exists(const Data& key) const
1852
0
{
1853
0
   if (mAttributeHelper.exists(key))
1854
0
   {
1855
0
      return true;
1856
0
   }
1857
0
   return mSession && mSession->exists(key);
1858
0
}
1859
1860
const list<Data>&
1861
SdpContents::Session::Medium::getValues(const Data& key) const
1862
0
{
1863
0
   if (mAttributeHelper.exists(key))
1864
0
   {
1865
0
      return mAttributeHelper.getValues(key);
1866
0
   }
1867
0
   if (!mSession)
1868
0
   {
1869
0
      resip_assert(false);
1870
0
      static list<Data> error;
1871
0
      return error;
1872
0
   }
1873
0
   return mSession->getValues(key);
1874
0
}
1875
1876
void
1877
SdpContents::Session::Medium::clearAttribute(const Data& key)
1878
0
{
1879
0
   mAttributeHelper.clearAttribute(key);
1880
0
   if (key == rtpmap)
1881
0
   {
1882
0
      mRtpMapDone = false;
1883
0
   }
1884
0
}
1885
1886
void
1887
SdpContents::Session::Medium::clearCodecs()
1888
0
{
1889
0
   mFormats.clear();
1890
0
   clearAttribute(rtpmap);
1891
0
   clearAttribute(fmtp);
1892
0
   mCodecs.clear();
1893
0
}
1894
1895
void
1896
SdpContents::Session::Medium::addCodec(const Codec& codec)
1897
0
{
1898
0
   codecs();
1899
0
   mCodecs.push_back(codec);
1900
0
}
1901
1902
1903
const SdpContents::Session::Medium::CodecContainer&
1904
SdpContents::Session::Medium::codecs() const
1905
0
{
1906
0
   return const_cast<Medium*>(this)->codecs();
1907
0
}
1908
1909
SdpContents::Session::Medium::CodecContainer&
1910
SdpContents::Session::Medium::codecs()
1911
0
{
1912
#if defined(WIN32) && defined(_MSC_VER) && (_MSC_VER < 1310)  // CJ TODO fix 
1913
   resip_assert(0);
1914
#else 
1915
0
   if (!mRtpMapDone)
1916
0
   {
1917
      // prevent recursion
1918
0
      mRtpMapDone = true;
1919
1920
0
      if (exists(rtpmap))
1921
0
      {
1922
0
         for (list<Data>::const_iterator i = getValues(rtpmap).begin();
1923
0
              i != getValues(rtpmap).end(); ++i)
1924
0
         {
1925
            //DebugLog(<< "SdpContents::Session::Medium::getCodec(" << *i << ")");
1926
0
            ParseBuffer pb(i->data(), i->size());
1927
0
            int format = pb.integer();
1928
            // pass to codec constructor for parsing
1929
            // pass this for other codec attributes
1930
0
            try
1931
0
            {
1932
0
               mRtpMap[format].parse(pb, *this, format);
1933
0
            }
1934
0
            catch (ParseException& e)
1935
0
            {
1936
0
               ErrLog(<<"Caught exception: "<< e);
1937
0
               mRtpMap.erase(format);
1938
0
            }
1939
0
         }
1940
0
      }
1941
1942
0
      for (list<Data>::const_iterator i = mFormats.begin();
1943
0
           i != mFormats.end(); ++i)
1944
0
      {
1945
0
         int mapKey = i->convertInt();
1946
0
         RtpMap::const_iterator ri = mRtpMap.find(mapKey);
1947
0
         if (ri != mRtpMap.end())
1948
0
         {
1949
            //DebugLog(<< "SdpContents::Session::Medium::getCodec[](" << ri->second << ")");
1950
0
            mCodecs.push_back(ri->second);
1951
0
         }
1952
0
         else
1953
0
         {
1954
             // !kk! Is it a static format?
1955
0
             Codec::CodecMap& staticCodecs = Codec::getStaticCodecs();
1956
0
             Codec::CodecMap::const_iterator ri = staticCodecs.find(mapKey);
1957
0
             if (ri != staticCodecs.end())
1958
0
             {
1959
                //DebugLog(<< "Found static codec for format: " << mapKey);
1960
0
                Codec codec(ri->second);
1961
1962
                // Look for format parameters, and assign
1963
0
                codec.assignFormatParameters(*this);
1964
1965
0
                mCodecs.push_back(codec);
1966
0
             }
1967
0
         }
1968
0
      }
1969
1970
      // don't store twice
1971
0
      mFormats.clear();
1972
0
      mAttributeHelper.clearAttribute(rtpmap);
1973
0
      mAttributeHelper.clearAttribute(fmtp);  // parsed out in codec.parse
1974
0
   }
1975
0
#endif
1976
1977
0
   return mCodecs;
1978
0
}
1979
1980
static Codec emptyCodec;
1981
const Codec& 
1982
SdpContents::Session::Medium::findFirstMatchingCodecs(const CodecContainer& codecList, Codec* pMatchingCodec) const
1983
0
{
1984
0
   const CodecContainer& internalCodecList = codecs();
1985
0
   resip::SdpContents::Session::Medium::CodecContainer::const_iterator sIter;
1986
0
   resip::SdpContents::Session::Medium::CodecContainer::const_iterator sEnd = internalCodecList.end();
1987
0
   resip::SdpContents::Session::Medium::CodecContainer::const_iterator eIter;
1988
0
   resip::SdpContents::Session::Medium::CodecContainer::const_iterator eEnd = codecList.end();
1989
0
   for (eIter = codecList.begin(); eIter != eEnd ; ++eIter)
1990
0
   {
1991
0
      for (sIter = internalCodecList.begin(); sIter != sEnd; ++sIter)
1992
0
      {
1993
0
         if (*sIter == *eIter)
1994
0
         {
1995
0
            if (pMatchingCodec) 
1996
0
            {
1997
0
               *pMatchingCodec = *eIter;
1998
0
            }
1999
0
            return *sIter;
2000
0
         }
2001
0
      }
2002
0
   }
2003
0
   return emptyCodec;
2004
0
}
2005
2006
const Codec& 
2007
SdpContents::Session::Medium::findFirstMatchingCodecs(const Medium& medium, Codec* pMatchingCodec) const
2008
0
{
2009
0
   if (&medium == this)
2010
0
   {
2011
0
      return codecs().front();
2012
0
   }
2013
0
   else
2014
0
   {
2015
0
      return findFirstMatchingCodecs(medium.codecs(), pMatchingCodec);
2016
0
   }
2017
0
}
2018
2019
const Codec& 
2020
SdpContents::Session::Medium::findTelephoneEventPayloadCodec() const
2021
0
{
2022
0
   const CodecContainer& codecList = codecs();
2023
0
   for (CodecContainer::const_iterator i = codecList.begin(); i != codecList.end(); i++)
2024
0
   {
2025
0
      if (i->getName() == SdpContents::Session::Codec::TelephoneEvent.getName())
2026
0
      {
2027
0
         return *i;
2028
0
      }
2029
0
   }
2030
0
   return emptyCodec;
2031
0
}
2032
2033
int
2034
SdpContents::Session::Medium::findTelephoneEventPayloadType() const
2035
0
{
2036
0
   const Codec& telephoneEventCodec = findTelephoneEventPayloadCodec();
2037
0
   if (!(telephoneEventCodec == emptyCodec))
2038
0
   {
2039
0
      return telephoneEventCodec.payloadType();
2040
0
   }
2041
0
   return -1;
2042
0
}
2043
2044
Codec::Codec(const Data& name,
2045
             unsigned long rate,
2046
             const Data& parameters,
2047
             const Data& encodingParameters)
2048
0
   : mName(name),
2049
0
     mRate(rate),
2050
0
     mPayloadType(-1),
2051
0
     mParameters(parameters),
2052
0
     mEncodingParameters(encodingParameters)
2053
0
{
2054
0
}
2055
2056
Codec::Codec(const Codec& rhs)
2057
0
   : mName(rhs.mName),
2058
0
     mRate(rhs.mRate),
2059
0
     mPayloadType(rhs.mPayloadType),
2060
0
     mParameters(rhs.mParameters),
2061
0
     mEncodingParameters(rhs.mEncodingParameters)
2062
0
{
2063
0
}
2064
2065
Codec::Codec(const Data& name, int payloadType, int rate)
2066
20
   : mName(name),
2067
20
     mRate(rate),
2068
20
     mPayloadType(payloadType)
2069
20
{
2070
20
}
2071
2072
Codec&
2073
Codec::operator=(const Codec& rhs)
2074
0
{
2075
0
   if (this != &rhs)
2076
0
   {
2077
0
      mName = rhs.mName;
2078
0
      mRate = rhs.mRate;
2079
0
      mPayloadType = rhs.mPayloadType;
2080
0
      mParameters = rhs.mParameters;
2081
0
      mEncodingParameters = rhs.mEncodingParameters;
2082
0
   }
2083
0
   return *this;
2084
0
}
2085
2086
void
2087
Codec::parse(ParseBuffer& pb,
2088
             const SdpContents::Session::Medium& medium,
2089
             int payloadType)
2090
0
{
2091
0
   const char* anchor = pb.skipWhitespace();
2092
0
   pb.skipToChar(Symbols::SLASH[0]);
2093
0
   mName = pb.data(anchor);
2094
0
   if(!pb.eof())
2095
0
   {
2096
0
      pb.skipChar(Symbols::SLASH[0]);
2097
0
      mRate = pb.integer();
2098
0
      pb.skipToChar(Symbols::SLASH[0]);
2099
0
   }
2100
0
   if(!pb.eof() && *pb.position() == Symbols::SLASH[0])
2101
0
   {
2102
0
      anchor = pb.skipChar(Symbols::SLASH[0]);
2103
0
      pb.skipToEnd();
2104
0
      mEncodingParameters = pb.data(anchor);
2105
0
   }
2106
0
   mPayloadType = payloadType;
2107
2108
0
   assignFormatParameters(medium); 
2109
0
}
2110
2111
void
2112
Codec::assignFormatParameters(const SdpContents::Session::Medium& medium)
2113
0
{
2114
   // get parameters if they exist
2115
0
   if (medium.exists(fmtp))
2116
0
   {
2117
0
      for (list<Data>::const_iterator i = medium.getValues(fmtp).begin();
2118
0
           i != medium.getValues(fmtp).end(); ++i)
2119
0
      {
2120
0
         try
2121
0
         {
2122
0
            ParseBuffer pb(i->data(), i->size());
2123
0
            int payload = pb.integer();
2124
0
            if (payload == mPayloadType)
2125
0
            {
2126
0
               const char* anchor = pb.skipWhitespace();
2127
0
               pb.skipToEnd();
2128
0
               mParameters = pb.data(anchor);
2129
0
               break;
2130
0
            }
2131
0
         }
2132
0
         catch (ParseException &pe)
2133
0
         {
2134
0
            InfoLog(<<"Caught exception when parsing a=fmtp: "<< pe);
2135
0
         }
2136
0
      }
2137
0
   }
2138
0
}
2139
2140
const Data&
2141
Codec::getName() const
2142
0
{
2143
0
   return mName;
2144
0
}
2145
2146
int
2147
Codec::getRate() const
2148
0
{
2149
0
   return mRate;
2150
0
}
2151
2152
Codec::CodecMap& Codec::getStaticCodecs()
2153
0
{
2154
0
   if (! sStaticCodecsCreated)
2155
0
   {
2156
      //
2157
      // Build map of static codecs as defined in RFC 3551
2158
      //
2159
0
      sStaticCodecs = std::unique_ptr<CodecMap>(new CodecMap);
2160
2161
      // Audio codecs
2162
0
      sStaticCodecs->insert(make_pair(0,Codec("PCMU",0,8000)));
2163
0
      sStaticCodecs->insert(make_pair(3,Codec("GSM",3,8000)));
2164
0
      sStaticCodecs->insert(make_pair(4,Codec("G723",4,8000)));
2165
0
      sStaticCodecs->insert(make_pair(5,Codec("DVI4",5,8000)));
2166
0
      sStaticCodecs->insert(make_pair(6,Codec("DVI4",6,16000)));
2167
0
      sStaticCodecs->insert(make_pair(7,Codec("LPC",7,8000)));
2168
0
      sStaticCodecs->insert(make_pair(8,Codec("PCMA",8,8000)));
2169
0
      sStaticCodecs->insert(make_pair(9,Codec("G722",9,8000)));
2170
0
      sStaticCodecs->insert(make_pair(10,Codec("L16-2",10,44100)));
2171
0
      sStaticCodecs->insert(make_pair(11,Codec("L16-1",11,44100)));
2172
0
      sStaticCodecs->insert(make_pair(12,Codec("QCELP",12,8000)));
2173
0
      sStaticCodecs->insert(make_pair(13,Codec("CN",13,8000)));
2174
0
      sStaticCodecs->insert(make_pair(14,Codec("MPA",14,90000)));
2175
0
      sStaticCodecs->insert(make_pair(15,Codec("G728",15,8000)));
2176
0
      sStaticCodecs->insert(make_pair(16,Codec("DVI4",16,11025)));
2177
0
      sStaticCodecs->insert(make_pair(17,Codec("DVI4",17,22050)));
2178
0
      sStaticCodecs->insert(make_pair(18,Codec("G729",18,8000)));
2179
2180
      // Video or audio/video codecs
2181
0
      sStaticCodecs->insert(make_pair(25,Codec("CelB",25,90000)));
2182
0
      sStaticCodecs->insert(make_pair(26,Codec("JPEG",26,90000)));
2183
0
      sStaticCodecs->insert(make_pair(28,Codec("nv",28,90000)));
2184
0
      sStaticCodecs->insert(make_pair(31,Codec("H261",31,90000)));
2185
0
      sStaticCodecs->insert(make_pair(32,Codec("MPV",32,90000)));
2186
0
      sStaticCodecs->insert(make_pair(33,Codec("MP2T",33,90000)));
2187
0
      sStaticCodecs->insert(make_pair(34,Codec("H263",34,90000)));
2188
2189
0
      sStaticCodecsCreated = true;
2190
0
   }
2191
0
   return *(sStaticCodecs.get());
2192
0
}
2193
2194
bool
2195
resip::operator==(const Codec& lhs, const Codec& rhs)
2196
0
{
2197
0
   static Data defaultEncodingParameters(Data("1"));  // Default for audio streams (1-Channel)
2198
0
   return (isEqualNoCase(lhs.mName, rhs.mName) && lhs.mRate == rhs.mRate && 
2199
0
           (lhs.mEncodingParameters == rhs.mEncodingParameters ||
2200
0
            (lhs.mEncodingParameters.empty() && rhs.mEncodingParameters == defaultEncodingParameters) ||
2201
0
            (lhs.mEncodingParameters == defaultEncodingParameters && rhs.mEncodingParameters.empty())));
2202
0
}
2203
2204
bool
2205
resip::operator!=(const Codec& lhs, const Codec& rhs)
2206
0
{
2207
0
   return !operator==(lhs, rhs);
2208
0
}
2209
2210
EncodeStream&
2211
resip::operator<<(EncodeStream& str, const Codec& codec)
2212
0
{
2213
0
   str << codec.mName;
2214
0
   str << Symbols::SLASH[0];
2215
0
   str << codec.mRate;
2216
0
   if(!codec.mEncodingParameters.empty())
2217
0
   {
2218
0
      str << Symbols::SLASH[0];
2219
0
      str << codec.mEncodingParameters;
2220
0
   }
2221
0
   return str;
2222
0
}
2223
2224
const Codec Codec::ULaw_8000("PCMU", 0, 8000);
2225
const Codec Codec::GSM_8000("GSM",   3, 8000);
2226
const Codec Codec::G723_8000("G723", 4, 8000);
2227
const Codec Codec::ALaw_8000("PCMA", 8, 8000);
2228
const Codec Codec::G722_8000("G722", 9, 8000);
2229
const Codec Codec::CN("CN",          13, 8000);
2230
const Codec Codec::G729_8000("G729", 18, 8000);
2231
const Codec Codec::H263("H263",      34, 90000);
2232
2233
const Codec Codec::TelephoneEvent("telephone-event", 101, 8000);
2234
const Codec Codec::FrfDialedDigit("frf-dialed-event",102, 8000);
2235
2236
bool Codec::sStaticCodecsCreated = false;
2237
std::unique_ptr<Codec::CodecMap> Codec::sStaticCodecs;
2238
2239
/* ====================================================================
2240
 * The Vovida Software License, Version 1.0
2241
 *
2242
 * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
2243
 *
2244
 * Redistribution and use in source and binary forms, with or without
2245
 * modification, are permitted provided that the following conditions
2246
 * are met:
2247
 *
2248
 * 1. Redistributions of source code must retain the above copyright
2249
 *    notice, this list of conditions and the following disclaimer.
2250
 *
2251
 * 2. Redistributions in binary form must reproduce the above copyright
2252
 *    notice, this list of conditions and the following disclaimer in
2253
 *    the documentation and/or other materials provided with the
2254
 *    distribution.
2255
 *
2256
 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
2257
 *    and "Vovida Open Communication Application Library (VOCAL)" must
2258
 *    not be used to endorse or promote products derived from this
2259
 *    software without prior written permission. For written
2260
 *    permission, please contact vocal@vovida.org.
2261
 *
2262
 * 4. Products derived from this software may not be called "VOCAL", nor
2263
 *    may "VOCAL" appear in their name, without prior written
2264
 *    permission of Vovida Networks, Inc.
2265
 *
2266
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
2267
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2268
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
2269
 * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
2270
 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
2271
 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
2272
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2273
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
2274
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
2275
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2276
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
2277
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
2278
 * DAMAGE.
2279
 *
2280
 * ====================================================================
2281
 *
2282
 * This software consists of voluntary contributions made by Vovida
2283
 * Networks, Inc. and many individuals on behalf of Vovida Networks,
2284
 * Inc.  For more information on Vovida Networks, Inc., please see
2285
 * <http://www.vovida.org/>.
2286
 *
2287
 */