1f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch/*
2f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * libjingle
3f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * Copyright 2004--2005, Google Inc.
4f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *
5f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * Redistribution and use in source and binary forms, with or without
6f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * modification, are permitted provided that the following conditions are met:
7f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *
8f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *  1. Redistributions of source code must retain the above copyright notice,
9f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *     this list of conditions and the following disclaimer.
10f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *  2. Redistributions in binary form must reproduce the above copyright notice,
11f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *     this list of conditions and the following disclaimer in the documentation
12f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *     and/or other materials provided with the distribution.
13f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *  3. The name of the author may not be used to endorse or promote products
14f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *     derived from this software without specific prior written permission.
15f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch *
16f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch */
27f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
284a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include <string>
294a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
30f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/session/phone/mediasessionclient.h"
31f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
324a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "talk/base/helpers.h"
33f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/logging.h"
34f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/base/stringutils.h"
354a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "talk/base/stringencode.h"
36f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/p2p/base/constants.h"
37f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/p2p/base/parsing.h"
384a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "talk/session/phone/cryptoparams.h"
394a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "talk/session/phone/srtpfilter.h"
40f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/xmpp/constants.h"
41f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch#include "talk/xmllite/qname.h"
424a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "talk/xmllite/xmlconstants.h"
43f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
44f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochusing namespace talk_base;
45f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
464a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochnamespace {
474a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochconst std::string kInline = "inline:";
484a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
494a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
50f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochnamespace cricket {
51f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
524a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochtypedef std::vector<CryptoParams> CryptoParamsVec;
534a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
54f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochMediaSessionClient::MediaSessionClient(
55f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    const buzz::Jid& jid, SessionManager *manager)
56f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    : jid_(jid), session_manager_(manager), focus_call_(NULL),
574a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      channel_manager_(new ChannelManager(session_manager_->worker_thread())),
584a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      secure_(SEC_DISABLED) {
59f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  Construct();
60f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
61f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
62f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochMediaSessionClient::MediaSessionClient(
63f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    const buzz::Jid& jid, SessionManager *manager,
64f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    MediaEngine* media_engine, DeviceManager* device_manager)
65f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    : jid_(jid), session_manager_(manager), focus_call_(NULL),
66f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      channel_manager_(new ChannelManager(
674a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch          media_engine, device_manager, session_manager_->worker_thread())),
684a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      secure_(SEC_DISABLED) {
69f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  Construct();
70f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
71f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
72f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
73f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid MediaSessionClient::Construct() {
74f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Register ourselves as the handler of phone and video sessions.
75731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  session_manager_->AddClient(NS_JINGLE_RTP, this);
76f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Forward device notifications.
77f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  SignalDevicesChange.repeat(channel_manager_->SignalDevicesChange);
783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Bring up the channel manager.
793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // In previous versions of ChannelManager, this was done automatically
803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // in the constructor.
813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  channel_manager_->Init();
82f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
83f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
84f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochMediaSessionClient::~MediaSessionClient() {
85f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Destroy all calls
86f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  std::map<uint32, Call *>::iterator it;
87f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  while (calls_.begin() != calls_.end()) {
88f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    std::map<uint32, Call *>::iterator it = calls_.begin();
89f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    DestroyCall((*it).second);
90f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
91f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
92f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Delete channel manager. This will wait for the channels to exit
93f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  delete channel_manager_;
94f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
95f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Remove ourselves from the client map.
96731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  session_manager_->RemoveClient(NS_JINGLE_RTP);
97f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
98f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
994a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochbool CreateCryptoParams(int tag, const std::string& cipher, CryptoParams *out) {
1004a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  std::string key;
1014a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  key.reserve(SRTP_MASTER_KEY_BASE64_LEN);
1024a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
1034a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (!CreateRandomString(SRTP_MASTER_KEY_BASE64_LEN, &key)) {
1044a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    return false;
1054a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
1064a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  out->tag = tag;
1074a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  out->cipher_suite = cipher;
1084a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  out->key_params = kInline + key;
1094a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  return true;
1104a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
1114a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
1124a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochbool AddCryptoParams(const std::string& cipher_suite, CryptoParamsVec *out) {
1134a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  int size = out->size();
1144a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
1154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  out->resize(size + 1);
1164a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  return CreateCryptoParams(size, cipher_suite, &out->at(size));
1174a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
1184a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
1194a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// For audio, HMAC 32 is prefered because of the low overhead.
1204a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochbool GetSupportedAudioCryptos(CryptoParamsVec* cryptos) {
1214a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#ifdef HAVE_SRTP
1224a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  return AddCryptoParams(CS_AES_CM_128_HMAC_SHA1_32, cryptos) &&
1234a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      AddCryptoParams(CS_AES_CM_128_HMAC_SHA1_80, cryptos);
1244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#else
1254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  return false;
1264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#endif
1274a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
1284a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
1294a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochbool GetSupportedVideoCryptos(CryptoParamsVec* cryptos) {
1304a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#ifdef HAVE_SRTP
1314a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  return AddCryptoParams(CS_AES_CM_128_HMAC_SHA1_80, cryptos);
1324a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#else
1334a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  return false;
1344a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#endif
1354a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
1364a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
1374a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben MurdochSessionDescription* MediaSessionClient::CreateOffer(
1384a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    const CallOptions& options) {
1393345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  SessionDescription* offer = new SessionDescription();
1403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  AudioContentDescription* audio = new AudioContentDescription();
141f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
142f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
1433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  AudioCodecs audio_codecs;
1443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  channel_manager_->GetSupportedAudioCodecs(&audio_codecs);
1453345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  for (AudioCodecs::const_iterator codec = audio_codecs.begin();
146731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick       codec != audio_codecs.end(); ++codec) {
1473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    audio->AddCodec(*codec);
1483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1494a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (options.is_muc) {
1503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    audio->set_ssrc(0);
1513345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  audio->SortCodecs();
1534a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
1544a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (secure() != SEC_DISABLED) {
1554a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    CryptoParamsVec audio_cryptos;
1564a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    if (GetSupportedAudioCryptos(&audio_cryptos)) {
1574a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      for (CryptoParamsVec::const_iterator crypto = audio_cryptos.begin();
1584a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch           crypto != audio_cryptos.end(); ++crypto) {
1594a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        audio->AddCrypto(*crypto);
1604a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      }
1614a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    }
1624a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    if (secure() == SEC_REQUIRED) {
1634a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      if (audio->cryptos().empty()) {
1644a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        return NULL;  // Abort, crypto required but none found.
1654a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      }
1664a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      audio->set_crypto_required(true);
1674a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    }
1684a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
1694a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
170731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  offer->AddContent(CN_AUDIO, NS_JINGLE_RTP, audio);
171f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
172f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // add video codecs, if this is a video call
1734a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (options.is_video) {
1743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    VideoContentDescription* video = new VideoContentDescription();
1753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    VideoCodecs video_codecs;
176f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    channel_manager_->GetSupportedVideoCodecs(&video_codecs);
1773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    for (VideoCodecs::const_iterator codec = video_codecs.begin();
178731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick         codec != video_codecs.end(); ++codec) {
1793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      video->AddCodec(*codec);
1803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
1814a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    if (options.is_muc) {
1823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      video->set_ssrc(0);
1833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
1844a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    video->set_bandwidth(options.video_bandwidth);
1853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    video->SortCodecs();
1864a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
1874a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    if (secure() != SEC_DISABLED) {
1884a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      CryptoParamsVec video_cryptos;
1894a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      if (GetSupportedVideoCryptos(&video_cryptos)) {
1904a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        for (CryptoParamsVec::const_iterator crypto = video_cryptos.begin();
1914a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch             crypto != video_cryptos.end(); ++crypto) {
1924a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch          video->AddCrypto(*crypto);
1934a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        }
1944a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      }
1954a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      if (secure() == SEC_REQUIRED) {
1964a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        if (video->cryptos().empty()) {
1974a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch          return NULL;  // Abort, crypto required but none found.
1984a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        }
1994a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        video->set_crypto_required(true);
2004a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      }
2014a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    }
2024a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
203731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    offer->AddContent(CN_VIDEO, NS_JINGLE_RTP, video);
204f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
205f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
2063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return offer;
2073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst ContentInfo* GetFirstMediaContent(const SessionDescription* sdesc,
210731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                        MediaType media_type) {
2113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (sdesc == NULL)
2123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return NULL;
2133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
214731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  const ContentInfos& contents = sdesc->contents();
215731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  for (ContentInfos::const_iterator content = contents.begin();
216731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick       content != contents.end(); content++) {
217731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (content->type == NS_JINGLE_RTP) {
218731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      const MediaContentDescription* media =
219731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          static_cast<const MediaContentDescription*>(content->description);
220731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      if (media->type() == media_type) {
221731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        return &*content;
222731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      }
223731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    }
224731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
225731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return NULL;
226f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
227f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
2283345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc) {
229731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return GetFirstMediaContent(sdesc, MEDIA_TYPE_AUDIO);
2303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickconst ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc) {
233731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return GetFirstMediaContent(sdesc, MEDIA_TYPE_VIDEO);
2343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick}
2353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2364a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// For video support only 80-bit SHA1 HMAC. For audio 32-bit HMAC is
2374a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// tolerated because it is low overhead. Pick the crypto in the list
2384a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// that is supported.
2394a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochbool SelectCrypto(const MediaContentDescription* offer, CryptoParams *crypto) {
2404a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  bool audio = offer->type() == MEDIA_TYPE_AUDIO;
2414a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  const CryptoParamsVec& cryptos = offer->cryptos();
2424a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
2434a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  for (CryptoParamsVec::const_iterator i = cryptos.begin();
2444a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch       i != cryptos.end(); ++i) {
2454a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    if (CS_AES_CM_128_HMAC_SHA1_80 == i->cipher_suite ||
2464a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        (CS_AES_CM_128_HMAC_SHA1_32 == i->cipher_suite && audio)) {
2474a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      return CreateCryptoParams(i->tag, i->cipher_suite, crypto);
2484a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    }
2494a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
2504a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  return false;
2514a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
2524a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
2533345a6884c488ff3a535c2c9acdd33d74b37e311Iain MerrickSessionDescription* MediaSessionClient::CreateAnswer(
2544a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    const SessionDescription* offer, const CallOptions& options) {
255731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // The answer contains the intersection of the codecs in the offer with the
256731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // codecs we support, ordered by our local preference. As indicated by
257731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // XEP-0167, we retain the same payload ids from the offer in the answer.
2583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  SessionDescription* accept = new SessionDescription();
2593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
2603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  const ContentInfo* audio_content = GetFirstAudioContent(offer);
2613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (audio_content) {
2623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const AudioContentDescription* audio_offer =
2633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        static_cast<const AudioContentDescription*>(audio_content->description);
2643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    AudioContentDescription* audio_accept = new AudioContentDescription();
265731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    AudioCodecs audio_codecs;
266731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    channel_manager_->GetSupportedAudioCodecs(&audio_codecs);
267731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    for (AudioCodecs::const_iterator ours = audio_codecs.begin();
268731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        ours != audio_codecs.end(); ++ours) {
269731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      for (AudioCodecs::const_iterator theirs = audio_offer->codecs().begin();
270731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          theirs != audio_offer->codecs().end(); ++theirs) {
271731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        if (ours->Matches(*theirs)) {
272731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          AudioCodec negotiated(*ours);
273731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          negotiated.id = theirs->id;
274731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          audio_accept->AddCodec(negotiated);
275731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        }
2763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      }
2773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
278731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
2793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    audio_accept->SortCodecs();
2804a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
2814a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    if (secure() != SEC_DISABLED) {
2824a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      CryptoParams crypto;
2834a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
2844a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      if (SelectCrypto(audio_offer, &crypto)) {
2854a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        audio_accept->AddCrypto(crypto);
2864a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      }
2874a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    }
2884a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
2894a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    if (audio_accept->cryptos().empty() &&
2904a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        (audio_offer->crypto_required() || secure() == SEC_REQUIRED)) {
2914a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      return NULL;  // Fails the session setup.
2924a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    }
2933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    accept->AddContent(audio_content->name, audio_content->type, audio_accept);
294f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
295f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
2963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  const ContentInfo* video_content = GetFirstVideoContent(offer);
2973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (video_content) {
2983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const VideoContentDescription* video_offer =
2993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        static_cast<const VideoContentDescription*>(video_content->description);
3003345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    VideoContentDescription* video_accept = new VideoContentDescription();
301731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    VideoCodecs video_codecs;
302731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    channel_manager_->GetSupportedVideoCodecs(&video_codecs);
303731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    for (VideoCodecs::const_iterator ours = video_codecs.begin();
304731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        ours != video_codecs.end(); ++ours) {
305731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      for (VideoCodecs::const_iterator theirs = video_offer->codecs().begin();
306731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          theirs != video_offer->codecs().end(); ++theirs) {
307731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        if (ours->Matches(*theirs)) {
308731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          VideoCodec negotiated(*ours);
309731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          negotiated.id = theirs->id;
310731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick          video_accept->AddCodec(negotiated);
311731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        }
3123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      }
313f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
314731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
3154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    video_accept->set_bandwidth(options.video_bandwidth);
3163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    video_accept->SortCodecs();
3174a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
3184a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    if (secure() != SEC_DISABLED) {
3194a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      CryptoParams crypto;
3204a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
3214a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      if (SelectCrypto(video_offer, &crypto)) {
3224a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        video_accept->AddCrypto(crypto);
3234a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      }
3244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    }
3254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
3264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    if (video_accept->cryptos().empty() &&
3274a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        (video_offer->crypto_required() || secure() == SEC_REQUIRED)) {
3284a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      return NULL;  // Fails the session setup.
3294a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    }
3303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    accept->AddContent(video_content->name, video_content->type, video_accept);
331f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
332f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
3333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return accept;
334f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
335f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
3364a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben MurdochCall *MediaSessionClient::CreateCall() {
3374a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  Call *call = new Call(this);
338f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  calls_[call->id()] = call;
339f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  SignalCallCreate(call);
340f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return call;
341f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
342f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
343f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid MediaSessionClient::OnSessionCreate(Session *session,
344f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                                         bool received_initiate) {
345f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (received_initiate) {
346f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    session->SignalState.connect(this, &MediaSessionClient::OnSessionState);
347f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
348f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
349f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
350731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid MediaSessionClient::OnSessionState(BaseSession* base_session,
351f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch                                        BaseSession::State state) {
352731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // MediaSessionClient can only be used with a Session*, so it's
353731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // safe to cast here.
354731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  Session* session = static_cast<Session*>(base_session);
355731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
356f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (state == Session::STATE_RECEIVEDINITIATE) {
357731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // The creation of the call must happen after the session has
358731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // processed the initiate message because we need the
359731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // remote_description to know what content names to use in the
360731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // call.
361731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
362f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    // If our accept would have no codecs, then we must reject this call.
363731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const SessionDescription* offer = session->remote_description();
3644a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    const SessionDescription* accept = CreateAnswer(offer, CallOptions());
3653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const ContentInfo* audio_content = GetFirstAudioContent(accept);
3663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const AudioContentDescription* audio_accept = (!audio_content) ? NULL :
3673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        static_cast<const AudioContentDescription*>(audio_content->description);
3683345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
369731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // For some reason, we need to create the call even when we
370731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // reject.
3714a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    Call *call = CreateCall();
372731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    session_map_[session->id()] = call;
373731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    call->IncomingSession(session, offer);
374731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
3753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (!audio_accept || audio_accept->codecs().size() == 0) {
376731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      session->Reject(STR_TERMINATE_INCOMPATIBLE_PARAMETERS);
377f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
3783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    delete accept;
379f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
380f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
381f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
382f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid MediaSessionClient::DestroyCall(Call *call) {
383f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Change focus away, signal destruction
384f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
385f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (call == focus_call_)
386f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    SetFocus(NULL);
387f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  SignalCallDestroy(call);
388f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
389f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Remove it from calls_ map and delete
390f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
391f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  std::map<uint32, Call *>::iterator it = calls_.find(call->id());
392f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (it != calls_.end())
393f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    calls_.erase(it);
394f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
395f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  delete call;
396f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
397f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
398f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid MediaSessionClient::OnSessionDestroy(Session *session) {
399f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Find the call this session is in, remove it
400f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
401731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  std::map<std::string, Call *>::iterator it = session_map_.find(session->id());
4023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  ASSERT(it != session_map_.end());
403f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (it != session_map_.end()) {
404f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    Call *call = (*it).second;
405f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    session_map_.erase(it);
406f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    call->RemoveSession(session);
407f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
408f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
409f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
410f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochCall *MediaSessionClient::GetFocus() {
411f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return focus_call_;
412f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
413f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
414f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid MediaSessionClient::SetFocus(Call *call) {
415f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  Call *old_focus_call = focus_call_;
416f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (focus_call_ != call) {
417f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (focus_call_ != NULL)
418f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      focus_call_->EnableChannels(false);
419f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    focus_call_ = call;
420f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    if (focus_call_ != NULL)
421f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      focus_call_->EnableChannels(true);
422f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    SignalFocus(focus_call_, old_focus_call);
423f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
424f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
425f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
426f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdochvoid MediaSessionClient::JoinCalls(Call *call_to_join, Call *call) {
427f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // Move all sessions from call to call_to_join, delete call.
428f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  // If call_to_join has focus, added sessions should have enabled channels.
429f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
430f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (focus_call_ == call)
431f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    SetFocus(NULL);
432f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  call_to_join->Join(call, focus_call_ == call_to_join);
433f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  DestroyCall(call);
434f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
435f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
436f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen MurdochSession *MediaSessionClient::CreateSession(Call *call) {
437731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  const std::string& type = NS_JINGLE_RTP;
438f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  Session *session = session_manager_->CreateSession(jid().Str(), type);
439f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  session_map_[session->id()] = call;
440f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return session;
441f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
442f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
443731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ParseGingleAudioCodec(const buzz::XmlElement* element, AudioCodec* out) {
444f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int id = GetXmlAttr(element, QN_ID, -1);
445f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (id < 0)
446f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
447f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
448f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  std::string name = GetXmlAttr(element, QN_NAME, buzz::STR_EMPTY);
449f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int clockrate = GetXmlAttr(element, QN_CLOCKRATE, 0);
450f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int bitrate = GetXmlAttr(element, QN_BITRATE, 0);
451f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int channels = GetXmlAttr(element, QN_CHANNELS, 1);
4523345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  *out = AudioCodec(id, name, clockrate, bitrate, channels, 0);
453f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return true;
454f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
455f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
456731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ParseGingleVideoCodec(const buzz::XmlElement* element, VideoCodec* out) {
457f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int id = GetXmlAttr(element, QN_ID, -1);
458f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (id < 0)
459f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    return false;
460f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
461f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  std::string name = GetXmlAttr(element, QN_NAME, buzz::STR_EMPTY);
462f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int width = GetXmlAttr(element, QN_WIDTH, 0);
463f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int height = GetXmlAttr(element, QN_HEIGHT, 0);
464f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  int framerate = GetXmlAttr(element, QN_FRAMERATE, 0);
465731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
466f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  *out = VideoCodec(id, name, width, height, framerate, 0);
467f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return true;
468f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
469f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
470731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid ParseGingleSsrc(const buzz::XmlElement* parent_elem,
471731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                     const buzz::QName& name,
472731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                     MediaContentDescription* content) {
473731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  const buzz::XmlElement* ssrc_elem = parent_elem->FirstNamed(name);
474731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (ssrc_elem) {
475731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    content->set_ssrc(strtoul(ssrc_elem->BodyText().c_str(), NULL, 10));
476731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
477731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
478731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
4794a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochbool ParseCryptoParams(const buzz::XmlElement* element,
4804a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                       CryptoParams* out,
4814a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                       ParseError* error) {
4824a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (!element->HasAttr(QN_CRYPTO_SUITE)) {
4834a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    return BadParse("crypto: crypto-suite attribute missing ", error);
4844a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  } else if (!element->HasAttr(QN_CRYPTO_KEY_PARAMS)) {
4854a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    return BadParse("crypto: key-params attribute missing ", error);
4864a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  } else if (!element->HasAttr(QN_CRYPTO_TAG)) {
4874a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    return BadParse("crypto: tag attribute missing ", error);
4884a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
4894a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
4904a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  const std::string& crypto_suite = element->Attr(QN_CRYPTO_SUITE);
4914a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  const std::string& key_params = element->Attr(QN_CRYPTO_KEY_PARAMS);
4924a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  const int tag = GetXmlAttr(element, QN_CRYPTO_TAG, 0);
4934a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  const std::string& session_params =
4944a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      element->Attr(QN_CRYPTO_SESSION_PARAMS);  // Optional.
4954a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
4964a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  *out = CryptoParams(tag, crypto_suite, key_params, session_params);
4974a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  return true;
4984a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
4994a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
5004a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
5014a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// Parse the first encryption element found with a matching 'usage'
5024a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// element.
5034a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// <usage/> is specific to Gingle. In Jingle, <crypto/> is already
5044a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// scoped to a content.
5054a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// Return false if there was an encryption element and it could not be
5064a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// parsed.
5074a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochbool ParseGingleEncryption(const buzz::XmlElement* desc,
5084a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                           const buzz::QName& usage,
5094a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                           MediaContentDescription* media,
5104a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                           ParseError* error) {
5114a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  for (const buzz::XmlElement* encryption = desc->FirstNamed(QN_ENCRYPTION);
5124a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch       encryption != NULL;
5134a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch       encryption = encryption->NextNamed(QN_ENCRYPTION)) {
5144a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    if (encryption->FirstNamed(usage) != NULL) {
5154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      media->set_crypto_required(
5164a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch          GetXmlAttr(encryption, QN_ENCRYPTION_REQUIRED, false));
5174a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      for (const buzz::XmlElement* crypto = encryption->FirstNamed(QN_CRYPTO);
5184a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch           crypto != NULL;
5194a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch           crypto = crypto->NextNamed(QN_CRYPTO)) {
5204a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        CryptoParams params;
5214a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        if (!ParseCryptoParams(crypto, &params, error)) {
5224a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch          return false;
5234a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        }
5244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch        media->AddCrypto(params);
5254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      }
5264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      break;
5274a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    }
5284a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
5294a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  return true;
5304a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
5314a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
5324a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochvoid ParseBandwidth(const buzz::XmlElement* parent_elem,
5334a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                    MediaContentDescription* media) {
5344a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  const buzz::XmlElement* bw_elem = GetXmlChild(parent_elem, LN_BANDWIDTH);
5354a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  int bandwidth_kbps;
5364a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (bw_elem && FromString(bw_elem->BodyText(), &bandwidth_kbps)) {
5374a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    if (bandwidth_kbps >= 0) {
5384a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      media->set_bandwidth(bandwidth_kbps * 1000);
5394a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    }
5404a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
5414a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
5424a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
543731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ParseGingleAudioContent(const buzz::XmlElement* content_elem,
544731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                             const ContentDescription** content,
545731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                             ParseError* error) {
546731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  AudioContentDescription* audio = new AudioContentDescription();
547731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
548731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (content_elem->FirstElement()) {
549731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    for (const buzz::XmlElement* codec_elem =
550731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick             content_elem->FirstNamed(QN_GINGLE_AUDIO_PAYLOADTYPE);
551731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick         codec_elem != NULL;
552731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick         codec_elem = codec_elem->NextNamed(QN_GINGLE_AUDIO_PAYLOADTYPE)) {
553731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      AudioCodec codec;
554731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      if (ParseGingleAudioCodec(codec_elem, &codec)) {
555731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        audio->AddCodec(codec);
556f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      }
557f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
558731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  } else {
559731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // For backward compatibility, we can assume the other client is
560731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    // an old version of Talk if it has no audio payload types at all.
561731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    audio->AddCodec(AudioCodec(103, "ISAC", 16000, -1, 1, 1));
562731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    audio->AddCodec(AudioCodec(0, "PCMU", 8000, 64000, 1, 0));
563731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
564731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
565dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  ParseGingleSsrc(content_elem, QN_GINGLE_AUDIO_SRCID, audio);
566731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
5674a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (!ParseGingleEncryption(content_elem, QN_GINGLE_AUDIO_CRYPTO_USAGE,
5684a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                             audio, error)) {
5694a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    return false;
5704a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
5714a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
572731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  *content = audio;
573731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return true;
574731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
575731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
576731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ParseGingleVideoContent(const buzz::XmlElement* content_elem,
577731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                             const ContentDescription** content,
578731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                             ParseError* error) {
579731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  VideoContentDescription* video = new VideoContentDescription();
580731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
581731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  for (const buzz::XmlElement* codec_elem =
582731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick           content_elem->FirstNamed(QN_GINGLE_VIDEO_PAYLOADTYPE);
583731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick       codec_elem != NULL;
584731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick       codec_elem = codec_elem->NextNamed(QN_GINGLE_VIDEO_PAYLOADTYPE)) {
585731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    VideoCodec codec;
586731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (ParseGingleVideoCodec(codec_elem, &codec)) {
587731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      video->AddCodec(codec);
5883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
589731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
590f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
591731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  ParseGingleSsrc(content_elem, QN_GINGLE_VIDEO_SRCID, video);
5924a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  ParseBandwidth(content_elem, video);
5934a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
5944a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (!ParseGingleEncryption(content_elem, QN_GINGLE_VIDEO_CRYPTO_USAGE,
5954a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                             video, error)) {
5964a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    return false;
5974a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
5983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
599731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  *content = video;
600731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return true;
601731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
602731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
603731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid ParsePayloadTypeParameters(const buzz::XmlElement* element,
604731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                std::map<std::string, std::string>* paramap) {
605731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  for (const buzz::XmlElement* param = element->FirstNamed(QN_PARAMETER);
606731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick       param != NULL; param = param->NextNamed(QN_PARAMETER)) {
6074a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    std::string name  = GetXmlAttr(param, QN_PAYLOADTYPE_PARAMETER_NAME,
6084a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                   buzz::STR_EMPTY);
6094a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    std::string value = GetXmlAttr(param, QN_PAYLOADTYPE_PARAMETER_VALUE,
6104a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                   buzz::STR_EMPTY);
611731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!name.empty() && !value.empty()) {
612731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      paramap->insert(make_pair(name, value));
6133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
614731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
615731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
6163345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
617731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickint FindWithDefault(const std::map<std::string, std::string>& map,
618731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                    const std::string& key, const int def) {
619731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  std::map<std::string, std::string>::const_iterator iter = map.find(key);
620731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return (iter == map.end()) ? def : atoi(iter->second.c_str());
621731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
622731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
6234a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
6244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// Parse the first encryption element found.
6254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// Return false if there was an encryption element and it could not be
6264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// parsed.
6274a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochbool ParseJingleEncryption(const buzz::XmlElement* content_elem,
6284a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                           MediaContentDescription* media,
6294a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                           ParseError* error) {
6304a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  const buzz::XmlElement* encryption =
6314a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch          content_elem->FirstNamed(QN_ENCRYPTION);
6324a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (encryption == NULL) {
6334a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      return true;
6344a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
6354a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
6364a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  media->set_crypto_required(
6374a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      GetXmlAttr(encryption, QN_ENCRYPTION_REQUIRED, false));
6384a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
6394a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  for (const buzz::XmlElement* crypto = encryption->FirstNamed(QN_CRYPTO);
6404a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch       crypto != NULL;
6414a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch       crypto = crypto->NextNamed(QN_CRYPTO)) {
6424a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    CryptoParams params;
6434a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    if (!ParseCryptoParams(crypto, &params, error)) {
6444a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      return false;
6454a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    }
6464a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    media->AddCrypto(params);
6474a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
6484a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  return true;
6494a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
6504a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
651731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ParseJingleAudioCodec(const buzz::XmlElement* elem, AudioCodec* codec) {
652731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  int id = GetXmlAttr(elem, QN_ID, -1);
653731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (id < 0)
654731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return false;
655731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
6564a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  std::string name = GetXmlAttr(elem, QN_NAME, buzz::STR_EMPTY);
657731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  int clockrate = GetXmlAttr(elem, QN_CLOCKRATE, 0);
658731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  int channels = GetXmlAttr(elem, QN_CHANNELS, 1);
659731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
660731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  std::map<std::string, std::string> paramap;
661731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  ParsePayloadTypeParameters(elem, &paramap);
662731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  int bitrate = FindWithDefault(paramap, PAYLOADTYPE_PARAMETER_BITRATE, 0);
663731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
664731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  *codec = AudioCodec(id, name, clockrate, bitrate, channels, 0);
665731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return true;
666731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
667731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
668731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ParseJingleVideoCodec(const buzz::XmlElement* elem, VideoCodec* codec) {
669731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  int id = GetXmlAttr(elem, QN_ID, -1);
670731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (id < 0)
671731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return false;
672731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
6734a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  std::string name = GetXmlAttr(elem, QN_NAME, buzz::STR_EMPTY);
674731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
675731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  std::map<std::string, std::string> paramap;
676731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  ParsePayloadTypeParameters(elem, &paramap);
677731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  int width = FindWithDefault(paramap, PAYLOADTYPE_PARAMETER_WIDTH, 0);
678731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  int height = FindWithDefault(paramap, PAYLOADTYPE_PARAMETER_HEIGHT, 0);
679731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  int framerate = FindWithDefault(paramap, PAYLOADTYPE_PARAMETER_FRAMERATE, 0);
680731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
681731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  *codec = VideoCodec(id, name, width, height, framerate, 0);
682731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return true;
683731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
684731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
685731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ParseJingleAudioContent(const buzz::XmlElement* content_elem,
686731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                             const ContentDescription** content,
687731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                             ParseError* error) {
688731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  AudioContentDescription* audio = new AudioContentDescription();
689731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
690731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  for (const buzz::XmlElement* payload_elem =
691731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick           content_elem->FirstNamed(QN_JINGLE_RTP_PAYLOADTYPE);
692731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      payload_elem != NULL;
693731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      payload_elem = payload_elem->NextNamed(QN_JINGLE_RTP_PAYLOADTYPE)) {
694731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    AudioCodec codec;
695731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (ParseJingleAudioCodec(payload_elem, &codec)) {
696731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      audio->AddCodec(codec);
6973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
698731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
6993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
7004a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (!ParseJingleEncryption(content_elem, audio, error)) {
7014a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    return false;
7024a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
703731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // TODO: Figure out how to integrate SSRC into Jingle.
704731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  *content = audio;
705731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return true;
706731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
707731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
708731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool ParseJingleVideoContent(const buzz::XmlElement* content_elem,
709731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                             const ContentDescription** content,
710731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                             ParseError* error) {
711731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  VideoContentDescription* video = new VideoContentDescription();
712731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
713731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  for (const buzz::XmlElement* payload_elem =
714731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick           content_elem->FirstNamed(QN_JINGLE_RTP_PAYLOADTYPE);
715731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      payload_elem != NULL;
716731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      payload_elem = payload_elem->NextNamed(QN_JINGLE_RTP_PAYLOADTYPE)) {
717731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    VideoCodec codec;
718731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (ParseJingleVideoCodec(payload_elem, &codec)) {
719731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      video->AddCodec(codec);
720731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    }
721f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  }
722f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
7234a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  ParseBandwidth(content_elem, video);
7244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
7254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (!ParseJingleEncryption(content_elem, video, error)) {
7264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    return false;
7274a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
728731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // TODO: Figure out how to integrate SSRC into Jingle.
729731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  *content = video;
7303345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return true;
731f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
732f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
733731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool MediaSessionClient::ParseContent(SignalingProtocol protocol,
734731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                     const buzz::XmlElement* content_elem,
735731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                     const ContentDescription** content,
736731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                     ParseError* error) {
737731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (protocol == PROTOCOL_GINGLE) {
738731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const std::string& content_type = content_elem->Name().Namespace();
739731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (NS_GINGLE_AUDIO == content_type) {
740731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return ParseGingleAudioContent(content_elem, content, error);
741731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    } else if (NS_GINGLE_VIDEO == content_type) {
742731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return ParseGingleVideoContent(content_elem, content, error);
743731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    } else {
744731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return BadParse("Unknown content type: " + content_type, error);
745731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    }
746731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  } else {
747731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    std::string media;
748731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (!RequireXmlAttr(content_elem, QN_JINGLE_CONTENT_MEDIA, &media, error))
749731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return false;
750731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
751731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (media == JINGLE_CONTENT_MEDIA_AUDIO) {
752731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return ParseJingleAudioContent(content_elem, content, error);
753731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    } else if (media == JINGLE_CONTENT_MEDIA_VIDEO) {
754731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return ParseJingleVideoContent(content_elem, content, error);
755731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    } else {
756731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      return BadParse("Unknown media: " + media, error);
757731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    }
758731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
759731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
760731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
761731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbuzz::XmlElement* CreateGingleAudioCodecElem(const AudioCodec& codec) {
762f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  buzz::XmlElement* payload_type =
763f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      new buzz::XmlElement(QN_GINGLE_AUDIO_PAYLOADTYPE, true);
764f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  AddXmlAttr(payload_type, QN_ID, codec.id);
765f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  payload_type->AddAttr(QN_NAME, codec.name);
766f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (codec.clockrate > 0)
767f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    AddXmlAttr(payload_type, QN_CLOCKRATE, codec.clockrate);
768f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (codec.bitrate > 0)
769f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    AddXmlAttr(payload_type, QN_BITRATE, codec.bitrate);
770f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  if (codec.channels > 1)
771f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    AddXmlAttr(payload_type, QN_CHANNELS, codec.channels);
772f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return payload_type;
773f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
774f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
775731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbuzz::XmlElement* CreateGingleVideoCodecElem(const VideoCodec& codec) {
776f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  buzz::XmlElement* payload_type =
777f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch      new buzz::XmlElement(QN_GINGLE_VIDEO_PAYLOADTYPE, true);
778f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  AddXmlAttr(payload_type, QN_ID, codec.id);
779f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  payload_type->AddAttr(QN_NAME, codec.name);
780f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  AddXmlAttr(payload_type, QN_WIDTH, codec.width);
781f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  AddXmlAttr(payload_type, QN_HEIGHT, codec.height);
782f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  AddXmlAttr(payload_type, QN_FRAMERATE, codec.framerate);
783f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch  return payload_type;
784f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
785f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
786731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbuzz::XmlElement* CreateGingleSsrcElem(const buzz::QName& name, uint32 ssrc) {
787731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  buzz::XmlElement* elem = new buzz::XmlElement(name, true);
788731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (ssrc) {
789731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    SetXmlBody(elem, ssrc);
790731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
791731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return elem;
792731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
793731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
7944a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochbuzz::XmlElement* CreateBandwidthElem(const buzz::QName& name, int bps) {
7954a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  int kbps = bps / 1000;
7964a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  buzz::XmlElement* elem = new buzz::XmlElement(name);
7974a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  elem->AddAttr(buzz::QN_TYPE, "AS");
7984a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  SetXmlBody(elem, kbps);
7994a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  return elem;
8004a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
8014a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
8024a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// For Jingle, usage_qname is empty.
8034a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochbuzz::XmlElement* CreateJingleEncryptionElem(const CryptoParamsVec& cryptos,
8044a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                             bool required) {
8054a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  buzz::XmlElement* encryption_elem = new buzz::XmlElement(QN_ENCRYPTION);
8064a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
8074a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (required) {
8084a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    encryption_elem->SetAttr(QN_ENCRYPTION_REQUIRED, "true");
8094a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
8104a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
8114a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  for (CryptoParamsVec::const_iterator i = cryptos.begin();
8124a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch       i != cryptos.end();
8134a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch       ++i) {
8144a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    buzz::XmlElement* crypto_elem = new buzz::XmlElement(QN_CRYPTO);
8154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
8164a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    AddXmlAttr(crypto_elem, QN_CRYPTO_TAG, i->tag);
8174a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    crypto_elem->AddAttr(QN_CRYPTO_SUITE, i->cipher_suite);
8184a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    crypto_elem->AddAttr(QN_CRYPTO_KEY_PARAMS, i->key_params);
8194a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    if (!i->session_params.empty()) {
8204a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      crypto_elem->AddAttr(QN_CRYPTO_SESSION_PARAMS, i->session_params);
8214a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    }
8224a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    encryption_elem->AddElement(crypto_elem);
8234a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
8244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  return encryption_elem;
8254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
8264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
8274a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochbuzz::XmlElement* CreateGingleEncryptionElem(const CryptoParamsVec& cryptos,
8284a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                             const buzz::QName& usage_qname,
8294a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                             bool required) {
8304a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  buzz::XmlElement* encryption_elem =
8314a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      CreateJingleEncryptionElem(cryptos, required);
8324a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
8334a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (required) {
8344a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    encryption_elem->SetAttr(QN_ENCRYPTION_REQUIRED, "true");
8354a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
8364a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
8374a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  buzz::XmlElement* usage_elem = new buzz::XmlElement(usage_qname);
8384a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  encryption_elem->AddElement(usage_elem);
8394a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
8404a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  return encryption_elem;
8414a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}
8424a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
843731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbuzz::XmlElement* CreateGingleAudioContentElem(
8444a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    const AudioContentDescription* audio,
8454a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    bool crypto_required) {
846731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  buzz::XmlElement* elem =
847731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      new buzz::XmlElement(QN_GINGLE_AUDIO_CONTENT, true);
848731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
849731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  for (AudioCodecs::const_iterator codec = audio->codecs().begin();
850731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick       codec != audio->codecs().end(); ++codec) {
851731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    elem->AddElement(CreateGingleAudioCodecElem(*codec));
852731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
853731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (audio->ssrc_set()) {
854731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    elem->AddElement(CreateGingleSsrcElem(
855731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        QN_GINGLE_AUDIO_SRCID, audio->ssrc()));
856731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
857731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
8584a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  const CryptoParamsVec& cryptos = audio->cryptos();
8594a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (!cryptos.empty()) {
8604a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    elem->AddElement(CreateGingleEncryptionElem(cryptos,
8614a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                                QN_GINGLE_AUDIO_CRYPTO_USAGE,
8624a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                                crypto_required));
8634a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
8644a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
865731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
866731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return elem;
867731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
868731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
869731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbuzz::XmlElement* CreateGingleVideoContentElem(
8704a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    const VideoContentDescription* video,
8714a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    bool crypto_required) {
872731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  buzz::XmlElement* elem =
873731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      new buzz::XmlElement(QN_GINGLE_VIDEO_CONTENT, true);
874731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
875731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  for (VideoCodecs::const_iterator codec = video->codecs().begin();
876731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick       codec != video->codecs().end(); ++codec) {
877731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    elem->AddElement(CreateGingleVideoCodecElem(*codec));
878731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
879731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (video->ssrc_set()) {
880731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    elem->AddElement(CreateGingleSsrcElem(
881731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        QN_GINGLE_VIDEO_SRCID, video->ssrc()));
882731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
8834a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (video->bandwidth() != kAutoBandwidth) {
8844a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    elem->AddElement(CreateBandwidthElem(QN_GINGLE_VIDEO_BANDWIDTH,
8854a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                         video->bandwidth()));
8864a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
8874a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
8884a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  const CryptoParamsVec& cryptos = video->cryptos();
8894a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (!cryptos.empty()) {
8904a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    elem->AddElement(CreateGingleEncryptionElem(cryptos,
8914a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                                QN_GINGLE_VIDEO_CRYPTO_USAGE,
8924a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                                crypto_required));
8934a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
894731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
895731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return elem;
896731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
897731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
898731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbuzz::XmlElement* CreatePayloadTypeParameterElem(
899731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    const std::string& name, int value) {
900731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  buzz::XmlElement* elem = new buzz::XmlElement(QN_PARAMETER);
901731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
902731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  elem->AddAttr(QN_PAYLOADTYPE_PARAMETER_NAME, name);
903731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  AddXmlAttr(elem, QN_PAYLOADTYPE_PARAMETER_VALUE, value);
904731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
905731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return elem;
906731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
907731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
908731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbuzz::XmlElement* CreateJingleAudioCodecElem(const AudioCodec& codec) {
909731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  buzz::XmlElement* elem = new buzz::XmlElement(QN_JINGLE_RTP_PAYLOADTYPE);
910731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
911731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  AddXmlAttr(elem, QN_ID, codec.id);
912731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  elem->AddAttr(QN_NAME, codec.name);
913731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (codec.clockrate > 0) {
914731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    AddXmlAttr(elem, QN_CLOCKRATE, codec.clockrate);
915731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
916731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (codec.bitrate > 0) {
917731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    elem->AddElement(CreatePayloadTypeParameterElem(
918731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        PAYLOADTYPE_PARAMETER_BITRATE, codec.bitrate));
919731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
920731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (codec.channels > 1) {
921731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    AddXmlAttr(elem, QN_CHANNELS, codec.channels);
922731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
923731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
924731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return elem;
925731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
926731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
927731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbuzz::XmlElement* CreateJingleVideoCodecElem(const VideoCodec& codec) {
928731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  buzz::XmlElement* elem = new buzz::XmlElement(QN_JINGLE_RTP_PAYLOADTYPE);
929731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
930731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  AddXmlAttr(elem, QN_ID, codec.id);
931731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  elem->AddAttr(QN_NAME, codec.name);
932731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  elem->AddElement(CreatePayloadTypeParameterElem(
933731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      PAYLOADTYPE_PARAMETER_WIDTH, codec.width));
934731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  elem->AddElement(CreatePayloadTypeParameterElem(
935731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      PAYLOADTYPE_PARAMETER_HEIGHT, codec.height));
936731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  elem->AddElement(CreatePayloadTypeParameterElem(
937731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      PAYLOADTYPE_PARAMETER_FRAMERATE, codec.framerate));
938731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
939731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return elem;
940731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
941731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
942731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbuzz::XmlElement* CreateJingleAudioContentElem(
9434a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    const AudioContentDescription* audio, bool crypto_required) {
944731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  buzz::XmlElement* elem =
945731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      new buzz::XmlElement(QN_JINGLE_RTP_CONTENT, true);
946731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
947731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  elem->SetAttr(QN_JINGLE_CONTENT_MEDIA, JINGLE_CONTENT_MEDIA_AUDIO);
948731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
949731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  for (AudioCodecs::const_iterator codec = audio->codecs().begin();
950731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick       codec != audio->codecs().end(); ++codec) {
951731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    elem->AddElement(CreateJingleAudioCodecElem(*codec));
952731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
953731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
9544a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  const CryptoParamsVec& cryptos = audio->cryptos();
9554a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (!cryptos.empty()) {
9564a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    elem->AddElement(CreateJingleEncryptionElem(cryptos, crypto_required));
9574a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
9584a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
959731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // TODO: Figure out how to integrate SSRC into Jingle.
960731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return elem;
961731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
962731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
963731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbuzz::XmlElement* CreateJingleVideoContentElem(
9644a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    const VideoContentDescription* video, bool crypto_required) {
965731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  buzz::XmlElement* elem =
966731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      new buzz::XmlElement(QN_JINGLE_RTP_CONTENT, true);
967731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
968731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  elem->SetAttr(QN_JINGLE_CONTENT_MEDIA, JINGLE_CONTENT_MEDIA_VIDEO);
969731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
970731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  for (VideoCodecs::const_iterator codec = video->codecs().begin();
971731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick       codec != video->codecs().end(); ++codec) {
972731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    elem->AddElement(CreateJingleVideoCodecElem(*codec));
973731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  }
974731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
9754a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  const CryptoParamsVec& cryptos = video->cryptos();
9764a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (!cryptos.empty()) {
9774a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    elem->AddElement(CreateJingleEncryptionElem(cryptos, crypto_required));
9784a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
9794a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
9804a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  if (video->bandwidth() != kAutoBandwidth) {
9814a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch    elem->AddElement(CreateBandwidthElem(QN_JINGLE_RTP_BANDWIDTH,
9824a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch                                         video->bandwidth()));
9834a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  }
9844a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch
985731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  // TODO: Figure out how to integrate SSRC into Jingle.
986731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  return elem;
987731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
988731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
989731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool MediaSessionClient::WriteContent(SignalingProtocol protocol,
990731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                      const ContentDescription* content,
9913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                      buzz::XmlElement** elem,
9923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                      WriteError* error) {
9933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  const MediaContentDescription* media =
994731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      static_cast<const MediaContentDescription*>(content);
9954a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch  bool crypto_required = secure() == SEC_REQUIRED;
9963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
9973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (media->type() == MEDIA_TYPE_AUDIO) {
9983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const AudioContentDescription* audio =
999731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        static_cast<const AudioContentDescription*>(media);
1000731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (protocol == PROTOCOL_GINGLE) {
10014a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      *elem = CreateGingleAudioContentElem(audio, crypto_required);
1002731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    } else {
10034a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      *elem = CreateJingleAudioContentElem(audio, crypto_required);
10043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    }
10053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  } else if (media->type() == MEDIA_TYPE_VIDEO) {
10063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    const VideoContentDescription* video =
1007731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        static_cast<const VideoContentDescription*>(media);
1008731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    if (protocol == PROTOCOL_GINGLE) {
10094a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      *elem = CreateGingleVideoContentElem(video, crypto_required);
1010731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    } else {
10114a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch      *elem = CreateJingleVideoContentElem(video, crypto_required);
1012f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch    }
1013731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  } else {
1014731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    return BadWrite("Unknown content type: " + media->type(), error);
10153345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
1016731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
10173345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  return true;
1018f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}
1019f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch
1020f74420b3285b9fe04a7e00aa3b8c0ab07ea344bcBen Murdoch}  // namespace cricket
1021