~ubuntu-branches/debian/experimental/kopete/experimental

« back to all changes in this revision

Viewing changes to protocols/jabber/libjingle/talk/session/phone/mediasessionclient.cc

  • Committer: Package Import Robot
  • Author(s): Maximiliano Curia
  • Date: 2015-02-24 11:32:57 UTC
  • mfrom: (1.1.41 vivid)
  • Revision ID: package-import@ubuntu.com-20150224113257-gnupg4v7lzz18ij0
Tags: 4:14.12.2-1
* New upstream release (14.12.2).
* Bump Standards-Version to 3.9.6, no changes needed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * libjingle
 
3
 * Copyright 2004--2005, Google Inc.
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions are met:
 
7
 *
 
8
 *  1. Redistributions of source code must retain the above copyright notice,
 
9
 *     this list of conditions and the following disclaimer.
 
10
 *  2. Redistributions in binary form must reproduce the above copyright notice,
 
11
 *     this list of conditions and the following disclaimer in the documentation
 
12
 *     and/or other materials provided with the distribution.
 
13
 *  3. The name of the author may not be used to endorse or promote products
 
14
 *     derived from this software without specific prior written permission.
 
15
 *
 
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 
17
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 
18
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 
19
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
20
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
21
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 
22
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 
23
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 
24
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 
25
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
26
 */
 
27
 
 
28
#include <string>
 
29
 
 
30
#include "talk/session/phone/mediasessionclient.h"
 
31
 
 
32
#include "talk/base/helpers.h"
 
33
#include "talk/base/logging.h"
 
34
#include "talk/base/stringutils.h"
 
35
#include "talk/base/stringencode.h"
 
36
#include "talk/p2p/base/constants.h"
 
37
#include "talk/p2p/base/parsing.h"
 
38
#include "talk/session/phone/cryptoparams.h"
 
39
#include "talk/session/phone/mediamessages.h"
 
40
#include "talk/session/phone/srtpfilter.h"
 
41
#include "talk/xmpp/constants.h"
 
42
#include "talk/xmllite/qname.h"
 
43
#include "talk/xmllite/xmlconstants.h"
 
44
 
 
45
namespace cricket {
 
46
 
 
47
MediaSessionClient::MediaSessionClient(
 
48
    const buzz::Jid& jid, SessionManager *manager)
 
49
    : jid_(jid),
 
50
      session_manager_(manager),
 
51
      focus_call_(NULL),
 
52
      channel_manager_(new ChannelManager(session_manager_->worker_thread())),
 
53
      desc_factory_(channel_manager_) {
 
54
  Construct();
 
55
}
 
56
 
 
57
MediaSessionClient::MediaSessionClient(
 
58
    const buzz::Jid& jid, SessionManager *manager,
 
59
    MediaEngineInterface* media_engine,
 
60
    DataEngineInterface* data_media_engine,
 
61
    DeviceManagerInterface* device_manager)
 
62
    : jid_(jid),
 
63
      session_manager_(manager),
 
64
      focus_call_(NULL),
 
65
      channel_manager_(new ChannelManager(
 
66
          media_engine, data_media_engine,
 
67
          device_manager, session_manager_->worker_thread())),
 
68
      desc_factory_(channel_manager_) {
 
69
  Construct();
 
70
}
 
71
 
 
72
void MediaSessionClient::Construct() {
 
73
  // Register ourselves as the handler of audio and video sessions.
 
74
  session_manager_->AddClient(NS_JINGLE_RTP, this);
 
75
  // Forward device notifications.
 
76
  SignalDevicesChange.repeat(channel_manager_->SignalDevicesChange);
 
77
  // Bring up the channel manager.
 
78
  // In previous versions of ChannelManager, this was done automatically
 
79
  // in the constructor.
 
80
  channel_manager_->Init();
 
81
}
 
82
 
 
83
MediaSessionClient::~MediaSessionClient() {
 
84
  // Destroy all calls
 
85
  std::map<uint32, Call *>::iterator it;
 
86
  while (calls_.begin() != calls_.end()) {
 
87
    std::map<uint32, Call *>::iterator it = calls_.begin();
 
88
    DestroyCall((*it).second);
 
89
  }
 
90
 
 
91
  // Delete channel manager. This will wait for the channels to exit
 
92
  delete channel_manager_;
 
93
 
 
94
  // Remove ourselves from the client map.
 
95
  session_manager_->RemoveClient(NS_JINGLE_RTP);
 
96
}
 
97
 
 
98
Call *MediaSessionClient::CreateCall() {
 
99
  Call *call = new Call(this);
 
100
  calls_[call->id()] = call;
 
101
  SignalCallCreate(call);
 
102
  return call;
 
103
}
 
104
 
 
105
void MediaSessionClient::OnSessionCreate(Session *session,
 
106
                                         bool received_initiate) {
 
107
  if (received_initiate) {
 
108
    session->SignalState.connect(this, &MediaSessionClient::OnSessionState);
 
109
  }
 
110
}
 
111
 
 
112
void MediaSessionClient::OnSessionState(BaseSession* base_session,
 
113
                                        BaseSession::State state) {
 
114
  // MediaSessionClient can only be used with a Session*, so it's
 
115
  // safe to cast here.
 
116
  Session* session = static_cast<Session*>(base_session);
 
117
 
 
118
  if (state == Session::STATE_RECEIVEDINITIATE) {
 
119
    // The creation of the call must happen after the session has
 
120
    // processed the initiate message because we need the
 
121
    // remote_description to know what content names to use in the
 
122
    // call.
 
123
 
 
124
    // If our accept would have no codecs, then we must reject this call.
 
125
    const SessionDescription* offer = session->remote_description();
 
126
    const SessionDescription* accept = CreateAnswer(offer, CallOptions());
 
127
    const ContentInfo* audio_content = GetFirstAudioContent(accept);
 
128
    const AudioContentDescription* audio_accept = (!audio_content) ? NULL :
 
129
        static_cast<const AudioContentDescription*>(audio_content->description);
 
130
 
 
131
    // For some reason, we need to create the call even when we
 
132
    // reject.
 
133
    Call *call = CreateCall();
 
134
    session_map_[session->id()] = call;
 
135
    call->IncomingSession(session, offer);
 
136
 
 
137
    if (!audio_accept || audio_accept->codecs().size() == 0) {
 
138
      session->Reject(STR_TERMINATE_INCOMPATIBLE_PARAMETERS);
 
139
    }
 
140
    delete accept;
 
141
  }
 
142
}
 
143
 
 
144
void MediaSessionClient::DestroyCall(Call *call) {
 
145
  // Change focus away, signal destruction
 
146
 
 
147
  if (call == focus_call_)
 
148
    SetFocus(NULL);
 
149
  SignalCallDestroy(call);
 
150
 
 
151
  // Remove it from calls_ map and delete
 
152
 
 
153
  std::map<uint32, Call *>::iterator it = calls_.find(call->id());
 
154
  if (it != calls_.end())
 
155
    calls_.erase(it);
 
156
 
 
157
  delete call;
 
158
}
 
159
 
 
160
void MediaSessionClient::OnSessionDestroy(Session *session) {
 
161
  // Find the call this session is in, remove it
 
162
 
 
163
  std::map<std::string, Call *>::iterator it = session_map_.find(session->id());
 
164
  ASSERT(it != session_map_.end());
 
165
  if (it != session_map_.end()) {
 
166
    Call *call = (*it).second;
 
167
    session_map_.erase(it);
 
168
    call->RemoveSession(session);
 
169
  }
 
170
}
 
171
 
 
172
Call *MediaSessionClient::GetFocus() {
 
173
  return focus_call_;
 
174
}
 
175
 
 
176
void MediaSessionClient::SetFocus(Call *call) {
 
177
  Call *old_focus_call = focus_call_;
 
178
  if (focus_call_ != call) {
 
179
    if (focus_call_ != NULL)
 
180
      focus_call_->EnableChannels(false);
 
181
    focus_call_ = call;
 
182
    if (focus_call_ != NULL)
 
183
      focus_call_->EnableChannels(true);
 
184
    SignalFocus(focus_call_, old_focus_call);
 
185
  }
 
186
}
 
187
 
 
188
void MediaSessionClient::JoinCalls(Call *call_to_join, Call *call) {
 
189
  // Move all sessions from call to call_to_join, delete call.
 
190
  // If call_to_join has focus, added sessions should have enabled channels.
 
191
 
 
192
  if (focus_call_ == call)
 
193
    SetFocus(NULL);
 
194
  call_to_join->Join(call, focus_call_ == call_to_join);
 
195
  DestroyCall(call);
 
196
}
 
197
 
 
198
Session *MediaSessionClient::CreateSession(Call *call) {
 
199
  const std::string& type = NS_JINGLE_RTP;
 
200
  Session *session = session_manager_->CreateSession(jid().Str(), type);
 
201
  session_map_[session->id()] = call;
 
202
  return session;
 
203
}
 
204
 
 
205
// TODO: Move all of the parsing and writing functions into
 
206
// mediamessages.cc, with unit tests.
 
207
bool ParseGingleAudioCodec(const buzz::XmlElement* element, AudioCodec* out) {
 
208
  int id = GetXmlAttr(element, QN_ID, -1);
 
209
  if (id < 0)
 
210
    return false;
 
211
 
 
212
  std::string name = GetXmlAttr(element, QN_NAME, buzz::STR_EMPTY);
 
213
  int clockrate = GetXmlAttr(element, QN_CLOCKRATE, 0);
 
214
  int bitrate = GetXmlAttr(element, QN_BITRATE, 0);
 
215
  int channels = GetXmlAttr(element, QN_CHANNELS, 1);
 
216
  *out = AudioCodec(id, name, clockrate, bitrate, channels, 0);
 
217
  return true;
 
218
}
 
219
 
 
220
bool ParseGingleVideoCodec(const buzz::XmlElement* element, VideoCodec* out) {
 
221
  int id = GetXmlAttr(element, QN_ID, -1);
 
222
  if (id < 0)
 
223
    return false;
 
224
 
 
225
  std::string name = GetXmlAttr(element, QN_NAME, buzz::STR_EMPTY);
 
226
  int width = GetXmlAttr(element, QN_WIDTH, 0);
 
227
  int height = GetXmlAttr(element, QN_HEIGHT, 0);
 
228
  int framerate = GetXmlAttr(element, QN_FRAMERATE, 0);
 
229
 
 
230
  *out = VideoCodec(id, name, width, height, framerate, 0);
 
231
  return true;
 
232
}
 
233
 
 
234
// Parses an ssrc string as a legacy stream.  If it fails, returns
 
235
// false and fills an error message.
 
236
bool ParseSsrcAsLegacyStream(const std::string& ssrc_str,
 
237
                             std::vector<StreamParams>* streams,
 
238
                             ParseError* error) {
 
239
  if (!ssrc_str.empty()) {
 
240
    uint32 ssrc;
 
241
    if (!talk_base::FromString(ssrc_str, &ssrc)) {
 
242
      return BadParse("Missing or invalid ssrc.", error);
 
243
    }
 
244
 
 
245
    streams->push_back(StreamParams::CreateLegacy(ssrc));
 
246
  }
 
247
  return true;
 
248
}
 
249
 
 
250
void ParseGingleSsrc(const buzz::XmlElement* parent_elem,
 
251
                     const buzz::QName& name,
 
252
                     MediaContentDescription* media) {
 
253
  const buzz::XmlElement* ssrc_elem = parent_elem->FirstNamed(name);
 
254
  if (ssrc_elem) {
 
255
    ParseError error;
 
256
    ParseSsrcAsLegacyStream(
 
257
        ssrc_elem->BodyText(), &(media->mutable_streams()), &error);
 
258
  }
 
259
}
 
260
 
 
261
bool ParseCryptoParams(const buzz::XmlElement* element,
 
262
                       CryptoParams* out,
 
263
                       ParseError* error) {
 
264
  if (!element->HasAttr(QN_CRYPTO_SUITE)) {
 
265
    return BadParse("crypto: crypto-suite attribute missing ", error);
 
266
  } else if (!element->HasAttr(QN_CRYPTO_KEY_PARAMS)) {
 
267
    return BadParse("crypto: key-params attribute missing ", error);
 
268
  } else if (!element->HasAttr(QN_CRYPTO_TAG)) {
 
269
    return BadParse("crypto: tag attribute missing ", error);
 
270
  }
 
271
 
 
272
  const std::string& crypto_suite = element->Attr(QN_CRYPTO_SUITE);
 
273
  const std::string& key_params = element->Attr(QN_CRYPTO_KEY_PARAMS);
 
274
  const int tag = GetXmlAttr(element, QN_CRYPTO_TAG, 0);
 
275
  const std::string& session_params =
 
276
      element->Attr(QN_CRYPTO_SESSION_PARAMS);  // Optional.
 
277
 
 
278
  *out = CryptoParams(tag, crypto_suite, key_params, session_params);
 
279
  return true;
 
280
}
 
281
 
 
282
 
 
283
// Parse the first encryption element found with a matching 'usage'
 
284
// element.
 
285
// <usage/> is specific to Gingle. In Jingle, <crypto/> is already
 
286
// scoped to a content.
 
287
// Return false if there was an encryption element and it could not be
 
288
// parsed.
 
289
bool ParseGingleEncryption(const buzz::XmlElement* desc,
 
290
                           const buzz::QName& usage,
 
291
                           MediaContentDescription* media,
 
292
                           ParseError* error) {
 
293
  for (const buzz::XmlElement* encryption = desc->FirstNamed(QN_ENCRYPTION);
 
294
       encryption != NULL;
 
295
       encryption = encryption->NextNamed(QN_ENCRYPTION)) {
 
296
    if (encryption->FirstNamed(usage) != NULL) {
 
297
      media->set_crypto_required(
 
298
          GetXmlAttr(encryption, QN_ENCRYPTION_REQUIRED, false));
 
299
      for (const buzz::XmlElement* crypto = encryption->FirstNamed(QN_CRYPTO);
 
300
           crypto != NULL;
 
301
           crypto = crypto->NextNamed(QN_CRYPTO)) {
 
302
        CryptoParams params;
 
303
        if (!ParseCryptoParams(crypto, &params, error)) {
 
304
          return false;
 
305
        }
 
306
        media->AddCrypto(params);
 
307
      }
 
308
      break;
 
309
    }
 
310
  }
 
311
  return true;
 
312
}
 
313
 
 
314
void ParseBandwidth(const buzz::XmlElement* parent_elem,
 
315
                    MediaContentDescription* media) {
 
316
  const buzz::XmlElement* bw_elem = GetXmlChild(parent_elem, LN_BANDWIDTH);
 
317
  int bandwidth_kbps = -1;
 
318
  if (bw_elem && talk_base::FromString(bw_elem->BodyText(), &bandwidth_kbps)) {
 
319
    if (bandwidth_kbps >= 0) {
 
320
      media->set_bandwidth(bandwidth_kbps * 1000);
 
321
    }
 
322
  }
 
323
}
 
324
 
 
325
bool ParseGingleAudioContent(const buzz::XmlElement* content_elem,
 
326
                             const ContentDescription** content,
 
327
                             ParseError* error) {
 
328
  AudioContentDescription* audio = new AudioContentDescription();
 
329
 
 
330
  if (content_elem->FirstElement()) {
 
331
    for (const buzz::XmlElement* codec_elem =
 
332
             content_elem->FirstNamed(QN_GINGLE_AUDIO_PAYLOADTYPE);
 
333
         codec_elem != NULL;
 
334
         codec_elem = codec_elem->NextNamed(QN_GINGLE_AUDIO_PAYLOADTYPE)) {
 
335
      AudioCodec codec;
 
336
      if (ParseGingleAudioCodec(codec_elem, &codec)) {
 
337
        audio->AddCodec(codec);
 
338
      }
 
339
    }
 
340
  } else {
 
341
    // For backward compatibility, we can assume the other client is
 
342
    // an old version of Talk if it has no audio payload types at all.
 
343
    audio->AddCodec(AudioCodec(103, "ISAC", 16000, -1, 1, 1));
 
344
    audio->AddCodec(AudioCodec(0, "PCMU", 8000, 64000, 1, 0));
 
345
  }
 
346
 
 
347
  ParseGingleSsrc(content_elem, QN_GINGLE_AUDIO_SRCID, audio);
 
348
 
 
349
  if (!ParseGingleEncryption(content_elem, QN_GINGLE_AUDIO_CRYPTO_USAGE,
 
350
                             audio, error)) {
 
351
    return false;
 
352
  }
 
353
 
 
354
  *content = audio;
 
355
  return true;
 
356
}
 
357
 
 
358
bool ParseGingleVideoContent(const buzz::XmlElement* content_elem,
 
359
                             const ContentDescription** content,
 
360
                             ParseError* error) {
 
361
  VideoContentDescription* video = new VideoContentDescription();
 
362
 
 
363
  for (const buzz::XmlElement* codec_elem =
 
364
           content_elem->FirstNamed(QN_GINGLE_VIDEO_PAYLOADTYPE);
 
365
       codec_elem != NULL;
 
366
       codec_elem = codec_elem->NextNamed(QN_GINGLE_VIDEO_PAYLOADTYPE)) {
 
367
    VideoCodec codec;
 
368
    if (ParseGingleVideoCodec(codec_elem, &codec)) {
 
369
      video->AddCodec(codec);
 
370
    }
 
371
  }
 
372
 
 
373
  ParseGingleSsrc(content_elem, QN_GINGLE_VIDEO_SRCID, video);
 
374
  ParseBandwidth(content_elem, video);
 
375
 
 
376
  if (!ParseGingleEncryption(content_elem, QN_GINGLE_VIDEO_CRYPTO_USAGE,
 
377
                             video, error)) {
 
378
    return false;
 
379
  }
 
380
 
 
381
  *content = video;
 
382
  return true;
 
383
}
 
384
 
 
385
void ParsePayloadTypeParameters(const buzz::XmlElement* element,
 
386
                                std::map<std::string, std::string>* paramap) {
 
387
  for (const buzz::XmlElement* param = element->FirstNamed(QN_PARAMETER);
 
388
       param != NULL; param = param->NextNamed(QN_PARAMETER)) {
 
389
    std::string name  = GetXmlAttr(param, QN_PAYLOADTYPE_PARAMETER_NAME,
 
390
                                   buzz::STR_EMPTY);
 
391
    std::string value = GetXmlAttr(param, QN_PAYLOADTYPE_PARAMETER_VALUE,
 
392
                                   buzz::STR_EMPTY);
 
393
    if (!name.empty() && !value.empty()) {
 
394
      paramap->insert(make_pair(name, value));
 
395
    }
 
396
  }
 
397
}
 
398
 
 
399
int FindWithDefault(const std::map<std::string, std::string>& map,
 
400
                    const std::string& key, const int def) {
 
401
  std::map<std::string, std::string>::const_iterator iter = map.find(key);
 
402
  return (iter == map.end()) ? def : atoi(iter->second.c_str());
 
403
}
 
404
 
 
405
 
 
406
// Parse the first encryption element found.
 
407
// Return false if there was an encryption element and it could not be
 
408
// parsed.
 
409
bool ParseJingleEncryption(const buzz::XmlElement* content_elem,
 
410
                           MediaContentDescription* media,
 
411
                           ParseError* error) {
 
412
  const buzz::XmlElement* encryption =
 
413
          content_elem->FirstNamed(QN_ENCRYPTION);
 
414
  if (encryption == NULL) {
 
415
      return true;
 
416
  }
 
417
 
 
418
  media->set_crypto_required(
 
419
      GetXmlAttr(encryption, QN_ENCRYPTION_REQUIRED, false));
 
420
 
 
421
  for (const buzz::XmlElement* crypto = encryption->FirstNamed(QN_CRYPTO);
 
422
       crypto != NULL;
 
423
       crypto = crypto->NextNamed(QN_CRYPTO)) {
 
424
    CryptoParams params;
 
425
    if (!ParseCryptoParams(crypto, &params, error)) {
 
426
      return false;
 
427
    }
 
428
    media->AddCrypto(params);
 
429
  }
 
430
  return true;
 
431
}
 
432
 
 
433
bool ParseJingleAudioCodec(const buzz::XmlElement* elem, AudioCodec* codec) {
 
434
  int id = GetXmlAttr(elem, QN_ID, -1);
 
435
  if (id < 0)
 
436
    return false;
 
437
 
 
438
  std::string name = GetXmlAttr(elem, QN_NAME, buzz::STR_EMPTY);
 
439
  int clockrate = GetXmlAttr(elem, QN_CLOCKRATE, 0);
 
440
  int channels = GetXmlAttr(elem, QN_CHANNELS, 1);
 
441
 
 
442
  std::map<std::string, std::string> paramap;
 
443
  ParsePayloadTypeParameters(elem, &paramap);
 
444
  int bitrate = FindWithDefault(paramap, PAYLOADTYPE_PARAMETER_BITRATE, 0);
 
445
 
 
446
  *codec = AudioCodec(id, name, clockrate, bitrate, channels, 0);
 
447
  return true;
 
448
}
 
449
 
 
450
bool ParseJingleVideoCodec(const buzz::XmlElement* elem, VideoCodec* codec) {
 
451
  int id = GetXmlAttr(elem, QN_ID, -1);
 
452
  if (id < 0)
 
453
    return false;
 
454
 
 
455
  std::string name = GetXmlAttr(elem, QN_NAME, buzz::STR_EMPTY);
 
456
 
 
457
  std::map<std::string, std::string> paramap;
 
458
  ParsePayloadTypeParameters(elem, &paramap);
 
459
  int width = FindWithDefault(paramap, PAYLOADTYPE_PARAMETER_WIDTH, 0);
 
460
  int height = FindWithDefault(paramap, PAYLOADTYPE_PARAMETER_HEIGHT, 0);
 
461
  int framerate = FindWithDefault(paramap, PAYLOADTYPE_PARAMETER_FRAMERATE, 0);
 
462
 
 
463
  *codec = VideoCodec(id, name, width, height, framerate, 0);
 
464
  return true;
 
465
}
 
466
 
 
467
bool ParseJingleDataCodec(const buzz::XmlElement* elem, DataCodec* codec) {
 
468
  int id = GetXmlAttr(elem, QN_ID, -1);
 
469
  if (id < 0)
 
470
    return false;
 
471
 
 
472
  std::string name = GetXmlAttr(elem, QN_NAME, buzz::STR_EMPTY);
 
473
 
 
474
  *codec = DataCodec(id, name, 0);
 
475
  return true;
 
476
}
 
477
 
 
478
bool ParseJingleStreamsOrLegacySsrc(const buzz::XmlElement* desc_elem,
 
479
                                    MediaContentDescription* media,
 
480
                                    ParseError* error) {
 
481
  if (HasJingleStreams(desc_elem)) {
 
482
    if (!ParseJingleStreams(desc_elem, &(media->mutable_streams()), error)) {
 
483
      return false;
 
484
    }
 
485
  } else {
 
486
    const std::string ssrc_str = desc_elem->Attr(QN_SSRC);
 
487
    if (!ParseSsrcAsLegacyStream(
 
488
            ssrc_str, &(media->mutable_streams()), error)) {
 
489
      return false;
 
490
    }
 
491
  }
 
492
  return true;
 
493
}
 
494
 
 
495
bool ParseJingleAudioContent(const buzz::XmlElement* content_elem,
 
496
                             const ContentDescription** content,
 
497
                             ParseError* error) {
 
498
  AudioContentDescription* audio = new AudioContentDescription();
 
499
 
 
500
  for (const buzz::XmlElement* payload_elem =
 
501
           content_elem->FirstNamed(QN_JINGLE_RTP_PAYLOADTYPE);
 
502
      payload_elem != NULL;
 
503
      payload_elem = payload_elem->NextNamed(QN_JINGLE_RTP_PAYLOADTYPE)) {
 
504
    AudioCodec codec;
 
505
    if (ParseJingleAudioCodec(payload_elem, &codec)) {
 
506
      audio->AddCodec(codec);
 
507
    }
 
508
  }
 
509
 
 
510
  if (!ParseJingleStreamsOrLegacySsrc(content_elem, audio, error)) {
 
511
    return false;
 
512
  }
 
513
 
 
514
  if (!ParseJingleEncryption(content_elem, audio, error)) {
 
515
    return false;
 
516
  }
 
517
 
 
518
  audio->set_rtcp_mux(content_elem->FirstNamed(QN_JINGLE_RTCP_MUX) != NULL);
 
519
 
 
520
  *content = audio;
 
521
  return true;
 
522
}
 
523
 
 
524
bool ParseJingleVideoContent(const buzz::XmlElement* content_elem,
 
525
                             const ContentDescription** content,
 
526
                             ParseError* error) {
 
527
  VideoContentDescription* video = new VideoContentDescription();
 
528
 
 
529
  for (const buzz::XmlElement* payload_elem =
 
530
           content_elem->FirstNamed(QN_JINGLE_RTP_PAYLOADTYPE);
 
531
      payload_elem != NULL;
 
532
      payload_elem = payload_elem->NextNamed(QN_JINGLE_RTP_PAYLOADTYPE)) {
 
533
    VideoCodec codec;
 
534
    if (ParseJingleVideoCodec(payload_elem, &codec)) {
 
535
      video->AddCodec(codec);
 
536
    }
 
537
  }
 
538
 
 
539
  if (!ParseJingleStreamsOrLegacySsrc(content_elem, video, error)) {
 
540
    return false;
 
541
  }
 
542
  ParseBandwidth(content_elem, video);
 
543
 
 
544
  if (!ParseJingleEncryption(content_elem, video, error)) {
 
545
    return false;
 
546
  }
 
547
 
 
548
  video->set_rtcp_mux(content_elem->FirstNamed(QN_JINGLE_RTCP_MUX) != NULL);
 
549
 
 
550
  *content = video;
 
551
  return true;
 
552
}
 
553
 
 
554
bool ParseJingleDataContent(const buzz::XmlElement* content_elem,
 
555
                            const ContentDescription** content,
 
556
                            ParseError* error) {
 
557
  DataContentDescription* data = new DataContentDescription();
 
558
 
 
559
  for (const buzz::XmlElement* payload_elem =
 
560
           content_elem->FirstNamed(QN_JINGLE_RTP_PAYLOADTYPE);
 
561
      payload_elem != NULL;
 
562
      payload_elem = payload_elem->NextNamed(QN_JINGLE_RTP_PAYLOADTYPE)) {
 
563
    DataCodec codec;
 
564
    if (ParseJingleDataCodec(payload_elem, &codec)) {
 
565
      data->AddCodec(codec);
 
566
    }
 
567
  }
 
568
 
 
569
  if (!ParseJingleStreamsOrLegacySsrc(content_elem, data, error)) {
 
570
    return false;
 
571
  }
 
572
  ParseBandwidth(content_elem, data);
 
573
 
 
574
  if (!ParseJingleEncryption(content_elem, data, error)) {
 
575
    return false;
 
576
  }
 
577
 
 
578
  data->set_rtcp_mux(content_elem->FirstNamed(QN_JINGLE_RTCP_MUX) != NULL);
 
579
 
 
580
  *content = data;
 
581
  return true;
 
582
}
 
583
 
 
584
bool MediaSessionClient::ParseContent(SignalingProtocol protocol,
 
585
                                     const buzz::XmlElement* content_elem,
 
586
                                     const ContentDescription** content,
 
587
                                     ParseError* error) {
 
588
  if (protocol == PROTOCOL_GINGLE) {
 
589
    const std::string& content_type = content_elem->Name().Namespace();
 
590
    if (NS_GINGLE_AUDIO == content_type) {
 
591
      return ParseGingleAudioContent(content_elem, content, error);
 
592
    } else if (NS_GINGLE_VIDEO == content_type) {
 
593
      return ParseGingleVideoContent(content_elem, content, error);
 
594
    } else {
 
595
      return BadParse("Unknown content type: " + content_type, error);
 
596
    }
 
597
  } else {
 
598
    std::string media;
 
599
    if (!RequireXmlAttr(content_elem, QN_JINGLE_CONTENT_MEDIA, &media, error))
 
600
      return false;
 
601
 
 
602
    if (media == JINGLE_CONTENT_MEDIA_AUDIO) {
 
603
      return ParseJingleAudioContent(content_elem, content, error);
 
604
    } else if (media == JINGLE_CONTENT_MEDIA_VIDEO) {
 
605
      return ParseJingleVideoContent(content_elem, content, error);
 
606
    } else if (media == JINGLE_CONTENT_MEDIA_DATA) {
 
607
      return ParseJingleDataContent(content_elem, content, error);
 
608
    } else {
 
609
      return BadParse("Unknown media: " + media, error);
 
610
    }
 
611
  }
 
612
}
 
613
 
 
614
buzz::XmlElement* CreateGingleAudioCodecElem(const AudioCodec& codec) {
 
615
  buzz::XmlElement* payload_type =
 
616
      new buzz::XmlElement(QN_GINGLE_AUDIO_PAYLOADTYPE, true);
 
617
  AddXmlAttr(payload_type, QN_ID, codec.id);
 
618
  payload_type->AddAttr(QN_NAME, codec.name);
 
619
  if (codec.clockrate > 0)
 
620
    AddXmlAttr(payload_type, QN_CLOCKRATE, codec.clockrate);
 
621
  if (codec.bitrate > 0)
 
622
    AddXmlAttr(payload_type, QN_BITRATE, codec.bitrate);
 
623
  if (codec.channels > 1)
 
624
    AddXmlAttr(payload_type, QN_CHANNELS, codec.channels);
 
625
  return payload_type;
 
626
}
 
627
 
 
628
buzz::XmlElement* CreateGingleVideoCodecElem(const VideoCodec& codec) {
 
629
  buzz::XmlElement* payload_type =
 
630
      new buzz::XmlElement(QN_GINGLE_VIDEO_PAYLOADTYPE, true);
 
631
  AddXmlAttr(payload_type, QN_ID, codec.id);
 
632
  payload_type->AddAttr(QN_NAME, codec.name);
 
633
  AddXmlAttr(payload_type, QN_WIDTH, codec.width);
 
634
  AddXmlAttr(payload_type, QN_HEIGHT, codec.height);
 
635
  AddXmlAttr(payload_type, QN_FRAMERATE, codec.framerate);
 
636
  return payload_type;
 
637
}
 
638
 
 
639
buzz::XmlElement* CreateGingleSsrcElem(const buzz::QName& name, uint32 ssrc) {
 
640
  buzz::XmlElement* elem = new buzz::XmlElement(name, true);
 
641
  if (ssrc) {
 
642
    SetXmlBody(elem, ssrc);
 
643
  }
 
644
  return elem;
 
645
}
 
646
 
 
647
buzz::XmlElement* CreateBandwidthElem(const buzz::QName& name, int bps) {
 
648
  int kbps = bps / 1000;
 
649
  buzz::XmlElement* elem = new buzz::XmlElement(name);
 
650
  elem->AddAttr(buzz::QN_TYPE, "AS");
 
651
  SetXmlBody(elem, kbps);
 
652
  return elem;
 
653
}
 
654
 
 
655
// For Jingle, usage_qname is empty.
 
656
buzz::XmlElement* CreateJingleEncryptionElem(const CryptoParamsVec& cryptos,
 
657
                                             bool required) {
 
658
  buzz::XmlElement* encryption_elem = new buzz::XmlElement(QN_ENCRYPTION);
 
659
 
 
660
  if (required) {
 
661
    encryption_elem->SetAttr(QN_ENCRYPTION_REQUIRED, "true");
 
662
  }
 
663
 
 
664
  for (CryptoParamsVec::const_iterator i = cryptos.begin();
 
665
       i != cryptos.end();
 
666
       ++i) {
 
667
    buzz::XmlElement* crypto_elem = new buzz::XmlElement(QN_CRYPTO);
 
668
 
 
669
    AddXmlAttr(crypto_elem, QN_CRYPTO_TAG, i->tag);
 
670
    crypto_elem->AddAttr(QN_CRYPTO_SUITE, i->cipher_suite);
 
671
    crypto_elem->AddAttr(QN_CRYPTO_KEY_PARAMS, i->key_params);
 
672
    if (!i->session_params.empty()) {
 
673
      crypto_elem->AddAttr(QN_CRYPTO_SESSION_PARAMS, i->session_params);
 
674
    }
 
675
    encryption_elem->AddElement(crypto_elem);
 
676
  }
 
677
  return encryption_elem;
 
678
}
 
679
 
 
680
buzz::XmlElement* CreateGingleEncryptionElem(const CryptoParamsVec& cryptos,
 
681
                                             const buzz::QName& usage_qname,
 
682
                                             bool required) {
 
683
  buzz::XmlElement* encryption_elem =
 
684
      CreateJingleEncryptionElem(cryptos, required);
 
685
 
 
686
  if (required) {
 
687
    encryption_elem->SetAttr(QN_ENCRYPTION_REQUIRED, "true");
 
688
  }
 
689
 
 
690
  buzz::XmlElement* usage_elem = new buzz::XmlElement(usage_qname);
 
691
  encryption_elem->AddElement(usage_elem);
 
692
 
 
693
  return encryption_elem;
 
694
}
 
695
 
 
696
buzz::XmlElement* CreateGingleAudioContentElem(
 
697
    const AudioContentDescription* audio,
 
698
    bool crypto_required) {
 
699
  buzz::XmlElement* elem =
 
700
      new buzz::XmlElement(QN_GINGLE_AUDIO_CONTENT, true);
 
701
 
 
702
  for (AudioCodecs::const_iterator codec = audio->codecs().begin();
 
703
       codec != audio->codecs().end(); ++codec) {
 
704
    elem->AddElement(CreateGingleAudioCodecElem(*codec));
 
705
  }
 
706
  if (audio->has_ssrcs()) {
 
707
    elem->AddElement(CreateGingleSsrcElem(
 
708
        QN_GINGLE_AUDIO_SRCID, audio->first_ssrc()));
 
709
  }
 
710
 
 
711
  const CryptoParamsVec& cryptos = audio->cryptos();
 
712
  if (!cryptos.empty()) {
 
713
    elem->AddElement(CreateGingleEncryptionElem(cryptos,
 
714
                                                QN_GINGLE_AUDIO_CRYPTO_USAGE,
 
715
                                                crypto_required));
 
716
  }
 
717
  return elem;
 
718
}
 
719
 
 
720
buzz::XmlElement* CreateGingleVideoContentElem(
 
721
    const VideoContentDescription* video,
 
722
    bool crypto_required) {
 
723
  buzz::XmlElement* elem =
 
724
      new buzz::XmlElement(QN_GINGLE_VIDEO_CONTENT, true);
 
725
 
 
726
  for (VideoCodecs::const_iterator codec = video->codecs().begin();
 
727
       codec != video->codecs().end(); ++codec) {
 
728
    elem->AddElement(CreateGingleVideoCodecElem(*codec));
 
729
  }
 
730
  if (video->has_ssrcs()) {
 
731
    elem->AddElement(CreateGingleSsrcElem(
 
732
        QN_GINGLE_VIDEO_SRCID, video->first_ssrc()));
 
733
  }
 
734
  if (video->bandwidth() != kAutoBandwidth) {
 
735
    elem->AddElement(CreateBandwidthElem(QN_GINGLE_VIDEO_BANDWIDTH,
 
736
                                         video->bandwidth()));
 
737
  }
 
738
 
 
739
  const CryptoParamsVec& cryptos = video->cryptos();
 
740
  if (!cryptos.empty()) {
 
741
    elem->AddElement(CreateGingleEncryptionElem(cryptos,
 
742
                                                QN_GINGLE_VIDEO_CRYPTO_USAGE,
 
743
                                                crypto_required));
 
744
  }
 
745
 
 
746
  return elem;
 
747
}
 
748
 
 
749
buzz::XmlElement* CreatePayloadTypeParameterElem(
 
750
    const std::string& name, int value) {
 
751
  buzz::XmlElement* elem = new buzz::XmlElement(QN_PARAMETER);
 
752
 
 
753
  elem->AddAttr(QN_PAYLOADTYPE_PARAMETER_NAME, name);
 
754
  AddXmlAttr(elem, QN_PAYLOADTYPE_PARAMETER_VALUE, value);
 
755
 
 
756
  return elem;
 
757
}
 
758
 
 
759
buzz::XmlElement* CreateJingleAudioCodecElem(const AudioCodec& codec) {
 
760
  buzz::XmlElement* elem = new buzz::XmlElement(QN_JINGLE_RTP_PAYLOADTYPE);
 
761
 
 
762
  AddXmlAttr(elem, QN_ID, codec.id);
 
763
  elem->AddAttr(QN_NAME, codec.name);
 
764
  if (codec.clockrate > 0) {
 
765
    AddXmlAttr(elem, QN_CLOCKRATE, codec.clockrate);
 
766
  }
 
767
  if (codec.bitrate > 0) {
 
768
    elem->AddElement(CreatePayloadTypeParameterElem(
 
769
        PAYLOADTYPE_PARAMETER_BITRATE, codec.bitrate));
 
770
  }
 
771
  if (codec.channels > 1) {
 
772
    AddXmlAttr(elem, QN_CHANNELS, codec.channels);
 
773
  }
 
774
 
 
775
  return elem;
 
776
}
 
777
 
 
778
buzz::XmlElement* CreateJingleVideoCodecElem(const VideoCodec& codec) {
 
779
  buzz::XmlElement* elem = new buzz::XmlElement(QN_JINGLE_RTP_PAYLOADTYPE);
 
780
 
 
781
  AddXmlAttr(elem, QN_ID, codec.id);
 
782
  elem->AddAttr(QN_NAME, codec.name);
 
783
  elem->AddElement(CreatePayloadTypeParameterElem(
 
784
      PAYLOADTYPE_PARAMETER_WIDTH, codec.width));
 
785
  elem->AddElement(CreatePayloadTypeParameterElem(
 
786
      PAYLOADTYPE_PARAMETER_HEIGHT, codec.height));
 
787
  elem->AddElement(CreatePayloadTypeParameterElem(
 
788
      PAYLOADTYPE_PARAMETER_FRAMERATE, codec.framerate));
 
789
 
 
790
  return elem;
 
791
}
 
792
 
 
793
buzz::XmlElement* CreateJingleDataCodecElem(const DataCodec& codec) {
 
794
  buzz::XmlElement* elem = new buzz::XmlElement(QN_JINGLE_RTP_PAYLOADTYPE);
 
795
 
 
796
  AddXmlAttr(elem, QN_ID, codec.id);
 
797
  elem->AddAttr(QN_NAME, codec.name);
 
798
 
 
799
  return elem;
 
800
}
 
801
 
 
802
void WriteLegacyJingleSsrc(const MediaContentDescription* media,
 
803
                           buzz::XmlElement* elem) {
 
804
  if (media->has_ssrcs()) {
 
805
    AddXmlAttr(elem, QN_SSRC, media->first_ssrc());
 
806
  }
 
807
}
 
808
 
 
809
void WriteJingleStreamsOrLegacySsrc(const MediaContentDescription* media,
 
810
                                    buzz::XmlElement* desc_elem) {
 
811
  if (!media->multistream()) {
 
812
    WriteLegacyJingleSsrc(media, desc_elem);
 
813
  } else {
 
814
    WriteJingleStreams(media->streams(), desc_elem);
 
815
  }
 
816
}
 
817
 
 
818
buzz::XmlElement* CreateJingleAudioContentElem(
 
819
    const AudioContentDescription* audio, bool crypto_required) {
 
820
  buzz::XmlElement* elem =
 
821
      new buzz::XmlElement(QN_JINGLE_RTP_CONTENT, true);
 
822
 
 
823
  elem->SetAttr(QN_JINGLE_CONTENT_MEDIA, JINGLE_CONTENT_MEDIA_AUDIO);
 
824
  WriteJingleStreamsOrLegacySsrc(audio, elem);
 
825
 
 
826
  for (AudioCodecs::const_iterator codec = audio->codecs().begin();
 
827
       codec != audio->codecs().end(); ++codec) {
 
828
    elem->AddElement(CreateJingleAudioCodecElem(*codec));
 
829
  }
 
830
 
 
831
  const CryptoParamsVec& cryptos = audio->cryptos();
 
832
  if (!cryptos.empty()) {
 
833
    elem->AddElement(CreateJingleEncryptionElem(cryptos, crypto_required));
 
834
  }
 
835
 
 
836
  if (audio->rtcp_mux()) {
 
837
    elem->AddElement(new buzz::XmlElement(QN_JINGLE_RTCP_MUX));
 
838
  }
 
839
 
 
840
  return elem;
 
841
}
 
842
 
 
843
buzz::XmlElement* CreateJingleVideoContentElem(
 
844
    const VideoContentDescription* video, bool crypto_required) {
 
845
  buzz::XmlElement* elem =
 
846
      new buzz::XmlElement(QN_JINGLE_RTP_CONTENT, true);
 
847
 
 
848
  elem->SetAttr(QN_JINGLE_CONTENT_MEDIA, JINGLE_CONTENT_MEDIA_VIDEO);
 
849
  WriteJingleStreamsOrLegacySsrc(video, elem);
 
850
 
 
851
  for (VideoCodecs::const_iterator codec = video->codecs().begin();
 
852
       codec != video->codecs().end(); ++codec) {
 
853
    elem->AddElement(CreateJingleVideoCodecElem(*codec));
 
854
  }
 
855
 
 
856
  const CryptoParamsVec& cryptos = video->cryptos();
 
857
  if (!cryptos.empty()) {
 
858
    elem->AddElement(CreateJingleEncryptionElem(cryptos, crypto_required));
 
859
  }
 
860
 
 
861
  if (video->rtcp_mux()) {
 
862
    elem->AddElement(new buzz::XmlElement(QN_JINGLE_RTCP_MUX));
 
863
  }
 
864
 
 
865
  if (video->bandwidth() != kAutoBandwidth) {
 
866
    elem->AddElement(CreateBandwidthElem(QN_JINGLE_RTP_BANDWIDTH,
 
867
                                         video->bandwidth()));
 
868
  }
 
869
 
 
870
  return elem;
 
871
}
 
872
 
 
873
buzz::XmlElement* CreateJingleDataContentElem(
 
874
    const DataContentDescription* data, bool crypto_required) {
 
875
  buzz::XmlElement* elem =
 
876
      new buzz::XmlElement(QN_JINGLE_RTP_CONTENT, true);
 
877
 
 
878
  elem->SetAttr(QN_JINGLE_CONTENT_MEDIA, JINGLE_CONTENT_MEDIA_DATA);
 
879
  WriteJingleStreamsOrLegacySsrc(data, elem);
 
880
 
 
881
  for (DataCodecs::const_iterator codec = data->codecs().begin();
 
882
       codec != data->codecs().end(); ++codec) {
 
883
    elem->AddElement(CreateJingleDataCodecElem(*codec));
 
884
  }
 
885
 
 
886
  const CryptoParamsVec& cryptos = data->cryptos();
 
887
  if (!cryptos.empty()) {
 
888
    elem->AddElement(CreateJingleEncryptionElem(cryptos, crypto_required));
 
889
  }
 
890
 
 
891
  if (data->rtcp_mux()) {
 
892
    elem->AddElement(new buzz::XmlElement(QN_JINGLE_RTCP_MUX));
 
893
  }
 
894
 
 
895
  if (data->bandwidth() != kAutoBandwidth) {
 
896
    elem->AddElement(CreateBandwidthElem(QN_JINGLE_RTP_BANDWIDTH,
 
897
                                         data->bandwidth()));
 
898
  }
 
899
 
 
900
  return elem;
 
901
}
 
902
 
 
903
bool MediaSessionClient::IsWritable(SignalingProtocol protocol,
 
904
                                    const ContentDescription* content) {
 
905
  const MediaContentDescription* media =
 
906
      static_cast<const MediaContentDescription*>(content);
 
907
  if (protocol == PROTOCOL_GINGLE &&
 
908
      media->type() == MEDIA_TYPE_DATA) {
 
909
    return false;
 
910
  }
 
911
  return true;
 
912
}
 
913
 
 
914
bool MediaSessionClient::WriteContent(SignalingProtocol protocol,
 
915
                                      const ContentDescription* content,
 
916
                                      buzz::XmlElement** elem,
 
917
                                      WriteError* error) {
 
918
  const MediaContentDescription* media =
 
919
      static_cast<const MediaContentDescription*>(content);
 
920
  bool crypto_required = secure() == SEC_REQUIRED;
 
921
 
 
922
  if (media->type() == MEDIA_TYPE_AUDIO) {
 
923
    const AudioContentDescription* audio =
 
924
        static_cast<const AudioContentDescription*>(media);
 
925
    if (protocol == PROTOCOL_GINGLE) {
 
926
      *elem = CreateGingleAudioContentElem(audio, crypto_required);
 
927
    } else {
 
928
      *elem = CreateJingleAudioContentElem(audio, crypto_required);
 
929
    }
 
930
  } else if (media->type() == MEDIA_TYPE_VIDEO) {
 
931
    const VideoContentDescription* video =
 
932
        static_cast<const VideoContentDescription*>(media);
 
933
    if (protocol == PROTOCOL_GINGLE) {
 
934
      *elem = CreateGingleVideoContentElem(video, crypto_required);
 
935
    } else {
 
936
      *elem = CreateJingleVideoContentElem(video, crypto_required);
 
937
    }
 
938
  } else if (media->type() == MEDIA_TYPE_DATA) {
 
939
    const DataContentDescription* data =
 
940
        static_cast<const DataContentDescription*>(media);
 
941
    if (protocol == PROTOCOL_GINGLE) {
 
942
      return BadWrite("Data channel not supported with Gingle.", error);
 
943
    } else {
 
944
      *elem = CreateJingleDataContentElem(data, crypto_required);
 
945
    }
 
946
  } else {
 
947
    return BadWrite("Unknown content type: " +
 
948
                    talk_base::ToString<int>(media->type()), error);
 
949
  }
 
950
 
 
951
  return true;
 
952
}
 
953
 
 
954
}  // namespace cricket