10e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org/*
20e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * libjingle
30e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Copyright 2004 Google Inc.
40e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
50e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * Redistribution and use in source and binary forms, with or without
60e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * modification, are permitted provided that the following conditions are met:
70e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
80e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *  1. Redistributions of source code must retain the above copyright notice,
90e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *     this list of conditions and the following disclaimer.
100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *  2. Redistributions in binary form must reproduce the above copyright notice,
110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *     this list of conditions and the following disclaimer in the documentation
120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *     and/or other materials provided with the distribution.
130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *  3. The name of the author may not be used to endorse or promote products
140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *     derived from this software without specific prior written permission.
150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org *
160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org */
270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include <string>
290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/session/media/mediasessionclient.h"
310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/base/helpers.h"
330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/base/logging.h"
340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/base/stringencode.h"
350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/base/stringutils.h"
360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/media/base/cryptoparams.h"
370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/media/base/capturemanager.h"
38391247d05a663265807c400947ab6eb01ae3d690mallinath@webrtc.org#include "talk/media/sctp/sctpdataengine.h"
390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/p2p/base/constants.h"
400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/p2p/base/parsing.h"
410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/session/media/mediamessages.h"
420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/session/media/srtpfilter.h"
430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/xmllite/qname.h"
440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/xmllite/xmlconstants.h"
450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#include "talk/xmpp/constants.h"
460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgnamespace cricket {
480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#if !defined(DISABLE_MEDIA_ENGINE_FACTORY)
500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgMediaSessionClient::MediaSessionClient(
510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    const buzz::Jid& jid, SessionManager *manager)
520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    : jid_(jid),
530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      session_manager_(manager),
540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      focus_call_(NULL),
550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      channel_manager_(new ChannelManager(session_manager_->worker_thread())),
560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      desc_factory_(channel_manager_,
577162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org          session_manager_->transport_desc_factory()),
587162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org      multisession_enabled_(false) {
590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  Construct();
600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org#endif
620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgMediaSessionClient::MediaSessionClient(
640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    const buzz::Jid& jid, SessionManager *manager,
650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    MediaEngineInterface* media_engine,
660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    DataEngineInterface* data_media_engine,
670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    DeviceManagerInterface* device_manager)
680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    : jid_(jid),
690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      session_manager_(manager),
700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      focus_call_(NULL),
710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      channel_manager_(new ChannelManager(
720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          media_engine, data_media_engine,
730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          device_manager, new CaptureManager(),
740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          session_manager_->worker_thread())),
750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      desc_factory_(channel_manager_,
767162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org                    session_manager_->transport_desc_factory()),
777162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org      multisession_enabled_(false) {
780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  Construct();
790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid MediaSessionClient::Construct() {
820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Register ourselves as the handler of audio and video sessions.
830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  session_manager_->AddClient(NS_JINGLE_RTP, this);
840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Forward device notifications.
850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  SignalDevicesChange.repeat(channel_manager_->SignalDevicesChange);
860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Bring up the channel manager.
870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // In previous versions of ChannelManager, this was done automatically
880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // in the constructor.
890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  channel_manager_->Init();
900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgMediaSessionClient::~MediaSessionClient() {
930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Destroy all calls
940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  std::map<uint32, Call *>::iterator it;
950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  while (calls_.begin() != calls_.end()) {
960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    std::map<uint32, Call *>::iterator it = calls_.begin();
970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    DestroyCall((*it).second);
980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Delete channel manager. This will wait for the channels to exit
1010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  delete channel_manager_;
1020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Remove ourselves from the client map.
1040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  session_manager_->RemoveClient(NS_JINGLE_RTP);
1050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgCall *MediaSessionClient::CreateCall() {
1080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  Call *call = new Call(this);
1090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  calls_[call->id()] = call;
1100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  SignalCallCreate(call);
1110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return call;
1120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid MediaSessionClient::OnSessionCreate(Session *session,
1150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                         bool received_initiate) {
1160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (received_initiate) {
1170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    session->SignalState.connect(this, &MediaSessionClient::OnSessionState);
1180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
1190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid MediaSessionClient::OnSessionState(BaseSession* base_session,
1220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                        BaseSession::State state) {
1230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // MediaSessionClient can only be used with a Session*, so it's
1240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // safe to cast here.
1250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  Session* session = static_cast<Session*>(base_session);
1260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (state == Session::STATE_RECEIVEDINITIATE) {
1280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // The creation of the call must happen after the session has
1290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // processed the initiate message because we need the
1300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // remote_description to know what content names to use in the
1310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // call.
1320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // If our accept would have no codecs, then we must reject this call.
1340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    const SessionDescription* offer = session->remote_description();
1350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    const SessionDescription* accept = CreateAnswer(offer, CallOptions());
1360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    const ContentInfo* audio_content = GetFirstAudioContent(accept);
1370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    bool audio_rejected = (!audio_content) ? true : audio_content->rejected;
1380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    const AudioContentDescription* audio_desc = (!audio_content) ? NULL :
1390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        static_cast<const AudioContentDescription*>(audio_content->description);
1400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // For some reason, we need a call even if we reject. So, either find a
1420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // matching call or create a new one.
1430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // The matching of existing calls is used to support the multi-session mode
1440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // required for p2p handoffs: ie. once a MUC call is established, a new
1450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // session may be established for the same call but is direct between the
1460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // clients. To indicate that this is the case, the initiator of the incoming
1470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // session is set to be the same as the remote name of the MUC for the
1480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // existing session, thus the client can know that this is a new session for
1490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // the existing call, rather than a whole new call.
1500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    Call* call = NULL;
1510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (multisession_enabled_) {
1520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      call = FindCallByRemoteName(session->initiator_name());
1530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
1540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (call == NULL) {
1560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      // Could not find a matching call, so create a new one.
1570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      call = CreateCall();
1580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
1590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    session_map_[session->id()] = call;
1610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    call->IncomingSession(session, offer);
1620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (audio_rejected || !audio_desc || audio_desc->codecs().size() == 0) {
1640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      session->Reject(STR_TERMINATE_INCOMPATIBLE_PARAMETERS);
1650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
1660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    delete accept;
1670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
1680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid MediaSessionClient::DestroyCall(Call *call) {
1710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Change focus away, signal destruction
1720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (call == focus_call_)
1740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    SetFocus(NULL);
1750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  SignalCallDestroy(call);
1760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Remove it from calls_ map and delete
1780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  std::map<uint32, Call *>::iterator it = calls_.find(call->id());
1800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (it != calls_.end())
1810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    calls_.erase(it);
1820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  delete call;
1840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid MediaSessionClient::OnSessionDestroy(Session *session) {
1870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Find the call this session is in, remove it
1880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  SessionMap::iterator it = session_map_.find(session->id());
1890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ASSERT(it != session_map_.end());
1900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (it != session_map_.end()) {
1910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    Call *call = (*it).second;
1920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    session_map_.erase(it);
1930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    call->RemoveSession(session);
1940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
1950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
1960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
1970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgCall *MediaSessionClient::GetFocus() {
1980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return focus_call_;
1990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
2000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid MediaSessionClient::SetFocus(Call *call) {
2020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  Call *old_focus_call = focus_call_;
2030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (focus_call_ != call) {
2040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (focus_call_ != NULL)
2050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      focus_call_->EnableChannels(false);
2060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    focus_call_ = call;
2070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (focus_call_ != NULL)
2080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      focus_call_->EnableChannels(true);
2090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    SignalFocus(focus_call_, old_focus_call);
2100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
2110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
2120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid MediaSessionClient::JoinCalls(Call *call_to_join, Call *call) {
2140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // Move all sessions from call to call_to_join, delete call.
2150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  // If call_to_join has focus, added sessions should have enabled channels.
2160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (focus_call_ == call)
2180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    SetFocus(NULL);
2190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  call_to_join->Join(call, focus_call_ == call_to_join);
2200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  DestroyCall(call);
2210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
2220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgSession *MediaSessionClient::CreateSession(Call *call) {
224f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  std::string id;
225f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  return CreateSession(id, call);
226f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org}
227f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org
228f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.orgSession *MediaSessionClient::CreateSession(const std::string& id, Call* call) {
2290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  const std::string& type = NS_JINGLE_RTP;
230f99f1011aa4cd22bd86ba2e4f7d239ea1b766ec8wu@webrtc.org  Session *session = session_manager_->CreateSession(id, jid().Str(), type);
2310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  session_map_[session->id()] = call;
2320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return session;
2330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
2340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgCall *MediaSessionClient::FindCallByRemoteName(const std::string &remote_name) {
2360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  SessionMap::const_iterator call;
2370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (call = session_map_.begin(); call != session_map_.end(); ++call) {
2380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    std::vector<Session *> sessions = call->second->sessions();
2390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    std::vector<Session *>::const_iterator session;
2400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    for (session = sessions.begin(); session != sessions.end(); ++session) {
2410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      if (remote_name == (*session)->remote_name()) {
2420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        return call->second;
2430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
2440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
2450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
2460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return NULL;
2480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
2490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// TODO(pthatcher): Move all of the parsing and writing functions into
2510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// mediamessages.cc, with unit tests.
2520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool ParseGingleAudioCodec(const buzz::XmlElement* element, AudioCodec* out) {
2530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int id = GetXmlAttr(element, QN_ID, -1);
2540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (id < 0)
2550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
2560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  std::string name = GetXmlAttr(element, QN_NAME, buzz::STR_EMPTY);
2580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int clockrate = GetXmlAttr(element, QN_CLOCKRATE, 0);
2590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int bitrate = GetXmlAttr(element, QN_BITRATE, 0);
2600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int channels = GetXmlAttr(element, QN_CHANNELS, 1);
2610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  *out = AudioCodec(id, name, clockrate, bitrate, channels, 0);
2620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
2630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
2640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool ParseGingleVideoCodec(const buzz::XmlElement* element, VideoCodec* out) {
2660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int id = GetXmlAttr(element, QN_ID, -1);
2670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (id < 0)
2680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
2690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  std::string name = GetXmlAttr(element, QN_NAME, buzz::STR_EMPTY);
2710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int width = GetXmlAttr(element, QN_WIDTH, 0);
2720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int height = GetXmlAttr(element, QN_HEIGHT, 0);
2730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int framerate = GetXmlAttr(element, QN_FRAMERATE, 0);
2740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  *out = VideoCodec(id, name, width, height, framerate, 0);
2760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
2770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
2780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Parses an ssrc string as a legacy stream.  If it fails, returns
2800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// false and fills an error message.
2810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool ParseSsrcAsLegacyStream(const std::string& ssrc_str,
2820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                             std::vector<StreamParams>* streams,
2830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                             ParseError* error) {
2840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!ssrc_str.empty()) {
2850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    uint32 ssrc;
2860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (!talk_base::FromString(ssrc_str, &ssrc)) {
2870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return BadParse("Missing or invalid ssrc.", error);
2880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
2890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    streams->push_back(StreamParams::CreateLegacy(ssrc));
2910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
2920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
2930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
2940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
2950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid ParseGingleSsrc(const buzz::XmlElement* parent_elem,
2960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                     const buzz::QName& name,
2970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                     MediaContentDescription* media) {
2980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  const buzz::XmlElement* ssrc_elem = parent_elem->FirstNamed(name);
2990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (ssrc_elem) {
3000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    ParseError error;
3010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    ParseSsrcAsLegacyStream(
3020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        ssrc_elem->BodyText(), &(media->mutable_streams()), &error);
3030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
3040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
3050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool ParseCryptoParams(const buzz::XmlElement* element,
3070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                       CryptoParams* out,
3080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                       ParseError* error) {
3090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!element->HasAttr(QN_CRYPTO_SUITE)) {
3100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return BadParse("crypto: crypto-suite attribute missing ", error);
3110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else if (!element->HasAttr(QN_CRYPTO_KEY_PARAMS)) {
3120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return BadParse("crypto: key-params attribute missing ", error);
3130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else if (!element->HasAttr(QN_CRYPTO_TAG)) {
3140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return BadParse("crypto: tag attribute missing ", error);
3150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
3160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  const std::string& crypto_suite = element->Attr(QN_CRYPTO_SUITE);
3180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  const std::string& key_params = element->Attr(QN_CRYPTO_KEY_PARAMS);
3190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  const int tag = GetXmlAttr(element, QN_CRYPTO_TAG, 0);
3200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  const std::string& session_params =
3210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      element->Attr(QN_CRYPTO_SESSION_PARAMS);  // Optional.
3220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  *out = CryptoParams(tag, crypto_suite, key_params, session_params);
3240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
3250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
3260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Parse the first encryption element found with a matching 'usage'
3290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// element.
3300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// <usage/> is specific to Gingle. In Jingle, <crypto/> is already
3310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// scoped to a content.
3320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Return false if there was an encryption element and it could not be
3330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// parsed.
3340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool ParseGingleEncryption(const buzz::XmlElement* desc,
3350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                           const buzz::QName& usage,
3360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                           MediaContentDescription* media,
3370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                           ParseError* error) {
3380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (const buzz::XmlElement* encryption = desc->FirstNamed(QN_ENCRYPTION);
3390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org       encryption != NULL;
3400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org       encryption = encryption->NextNamed(QN_ENCRYPTION)) {
3410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (encryption->FirstNamed(usage) != NULL) {
342ac5a3e5f1e59174797dc60641cba617c1bf0c279henrike@webrtc.org      if (GetXmlAttr(encryption, QN_ENCRYPTION_REQUIRED, false)) {
343ac5a3e5f1e59174797dc60641cba617c1bf0c279henrike@webrtc.org        media->set_crypto_required(CT_SDES);
344ac5a3e5f1e59174797dc60641cba617c1bf0c279henrike@webrtc.org      }
3450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      for (const buzz::XmlElement* crypto = encryption->FirstNamed(QN_CRYPTO);
3460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org           crypto != NULL;
3470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org           crypto = crypto->NextNamed(QN_CRYPTO)) {
3480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        CryptoParams params;
3490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        if (!ParseCryptoParams(crypto, &params, error)) {
3500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          return false;
3510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        }
3520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        media->AddCrypto(params);
3530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
3540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      break;
3550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
3560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
3570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
3580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
3590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid ParseBandwidth(const buzz::XmlElement* parent_elem,
3610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                    MediaContentDescription* media) {
3620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  const buzz::XmlElement* bw_elem = GetXmlChild(parent_elem, LN_BANDWIDTH);
3630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int bandwidth_kbps = -1;
3640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (bw_elem && talk_base::FromString(bw_elem->BodyText(), &bandwidth_kbps)) {
3650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (bandwidth_kbps >= 0) {
3660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      media->set_bandwidth(bandwidth_kbps * 1000);
3670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
3680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
3690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
3700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool ParseGingleAudioContent(const buzz::XmlElement* content_elem,
3720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                             ContentDescription** content,
3730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                             ParseError* error) {
3740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  AudioContentDescription* audio = new AudioContentDescription();
3750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (content_elem->FirstElement()) {
3770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    for (const buzz::XmlElement* codec_elem =
3780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org             content_elem->FirstNamed(QN_GINGLE_AUDIO_PAYLOADTYPE);
3790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org         codec_elem != NULL;
3800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org         codec_elem = codec_elem->NextNamed(QN_GINGLE_AUDIO_PAYLOADTYPE)) {
3810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      AudioCodec codec;
3820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      if (ParseGingleAudioCodec(codec_elem, &codec)) {
3830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        audio->AddCodec(codec);
3840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      }
3850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
3860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else {
3870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // For backward compatibility, we can assume the other client is
3880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // an old version of Talk if it has no audio payload types at all.
3890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    audio->AddCodec(AudioCodec(103, "ISAC", 16000, -1, 1, 1));
3900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    audio->AddCodec(AudioCodec(0, "PCMU", 8000, 64000, 1, 0));
3910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
3920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ParseGingleSsrc(content_elem, QN_GINGLE_AUDIO_SRCID, audio);
3940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
3950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!ParseGingleEncryption(content_elem, QN_GINGLE_AUDIO_CRYPTO_USAGE,
3960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                             audio, error)) {
3970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
3980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
3990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
4000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  *content = audio;
4010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
4020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
4030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
4040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool ParseGingleVideoContent(const buzz::XmlElement* content_elem,
4050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                             ContentDescription** content,
4060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                             ParseError* error) {
4070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  VideoContentDescription* video = new VideoContentDescription();
4080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
4090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (const buzz::XmlElement* codec_elem =
4100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org           content_elem->FirstNamed(QN_GINGLE_VIDEO_PAYLOADTYPE);
4110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org       codec_elem != NULL;
4120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org       codec_elem = codec_elem->NextNamed(QN_GINGLE_VIDEO_PAYLOADTYPE)) {
4130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    VideoCodec codec;
4140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (ParseGingleVideoCodec(codec_elem, &codec)) {
4150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      video->AddCodec(codec);
4160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
4170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
4180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
4190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ParseGingleSsrc(content_elem, QN_GINGLE_VIDEO_SRCID, video);
4200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ParseBandwidth(content_elem, video);
4210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
4220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!ParseGingleEncryption(content_elem, QN_GINGLE_VIDEO_CRYPTO_USAGE,
4230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                             video, error)) {
4240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
4250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
4260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
4270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  *content = video;
4280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
4290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
4300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
4310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid ParsePayloadTypeParameters(const buzz::XmlElement* element,
4320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                std::map<std::string, std::string>* paramap) {
4330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (const buzz::XmlElement* param = element->FirstNamed(QN_PARAMETER);
4340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org       param != NULL; param = param->NextNamed(QN_PARAMETER)) {
4350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    std::string name  = GetXmlAttr(param, QN_PAYLOADTYPE_PARAMETER_NAME,
4360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                   buzz::STR_EMPTY);
4370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    std::string value = GetXmlAttr(param, QN_PAYLOADTYPE_PARAMETER_VALUE,
4380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                   buzz::STR_EMPTY);
4390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (!name.empty() && !value.empty()) {
4400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      paramap->insert(make_pair(name, value));
4410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
4420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
4430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
4440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
4455aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.orgvoid ParseFeedbackParams(const buzz::XmlElement* element,
4465aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org                         FeedbackParams* params) {
4475aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org  for (const buzz::XmlElement* param = element->FirstNamed(QN_JINGLE_RTCP_FB);
4485aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org       param != NULL; param = param->NextNamed(QN_JINGLE_RTCP_FB)) {
4495aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org    std::string type = GetXmlAttr(param, QN_TYPE, buzz::STR_EMPTY);
4505aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org    std::string subtype = GetXmlAttr(param, QN_SUBTYPE, buzz::STR_EMPTY);
4515aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org    if (!type.empty()) {
4525aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org      params->Add(FeedbackParam(type, subtype));
4535aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org    }
4545aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org  }
4555aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org}
4565aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org
4575aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.orgvoid AddFeedbackParams(const FeedbackParams& additional_params,
4585aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org                       FeedbackParams* params) {
4595aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org  for (size_t i = 0; i < additional_params.params().size(); ++i) {
4605aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org    params->Add(additional_params.params()[i]);
4615aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org  }
4625aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org}
4635aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org
4640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgint FindWithDefault(const std::map<std::string, std::string>& map,
4650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                    const std::string& key, const int def) {
4660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  std::map<std::string, std::string>::const_iterator iter = map.find(key);
4670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return (iter == map.end()) ? def : atoi(iter->second.c_str());
4680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
4690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
4700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
4710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Parse the first encryption element found.
4720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// Return false if there was an encryption element and it could not be
4730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// parsed.
4740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool ParseJingleEncryption(const buzz::XmlElement* content_elem,
4750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                           MediaContentDescription* media,
4760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                           ParseError* error) {
4770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  const buzz::XmlElement* encryption =
4780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org          content_elem->FirstNamed(QN_ENCRYPTION);
4790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (encryption == NULL) {
4800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return true;
4810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
4820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
483ac5a3e5f1e59174797dc60641cba617c1bf0c279henrike@webrtc.org  if (GetXmlAttr(encryption, QN_ENCRYPTION_REQUIRED, false)) {
484ac5a3e5f1e59174797dc60641cba617c1bf0c279henrike@webrtc.org    media->set_crypto_required(CT_SDES);
485ac5a3e5f1e59174797dc60641cba617c1bf0c279henrike@webrtc.org  }
4860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
4870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (const buzz::XmlElement* crypto = encryption->FirstNamed(QN_CRYPTO);
4880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org       crypto != NULL;
4890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org       crypto = crypto->NextNamed(QN_CRYPTO)) {
4900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    CryptoParams params;
4910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (!ParseCryptoParams(crypto, &params, error)) {
4920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
4930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
4940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    media->AddCrypto(params);
4950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
4960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
4970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
4980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
4990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool ParseJingleAudioCodec(const buzz::XmlElement* elem, AudioCodec* codec) {
5000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int id = GetXmlAttr(elem, QN_ID, -1);
5010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (id < 0)
5020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
5030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
5040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  std::string name = GetXmlAttr(elem, QN_NAME, buzz::STR_EMPTY);
5050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int clockrate = GetXmlAttr(elem, QN_CLOCKRATE, 0);
5060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int channels = GetXmlAttr(elem, QN_CHANNELS, 1);
5070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
5080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  std::map<std::string, std::string> paramap;
5090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ParsePayloadTypeParameters(elem, &paramap);
5100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int bitrate = FindWithDefault(paramap, PAYLOADTYPE_PARAMETER_BITRATE, 0);
5110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
5120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  *codec = AudioCodec(id, name, clockrate, bitrate, channels, 0);
5135aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org  ParseFeedbackParams(elem, &codec->feedback_params);
5140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
5150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
5160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
5170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool ParseJingleVideoCodec(const buzz::XmlElement* elem, VideoCodec* codec) {
5180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int id = GetXmlAttr(elem, QN_ID, -1);
5190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (id < 0)
5200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
5210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
5220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  std::string name = GetXmlAttr(elem, QN_NAME, buzz::STR_EMPTY);
5230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
5240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  std::map<std::string, std::string> paramap;
5250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ParsePayloadTypeParameters(elem, &paramap);
5260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int width = FindWithDefault(paramap, PAYLOADTYPE_PARAMETER_WIDTH, 0);
5270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int height = FindWithDefault(paramap, PAYLOADTYPE_PARAMETER_HEIGHT, 0);
5280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int framerate = FindWithDefault(paramap, PAYLOADTYPE_PARAMETER_FRAMERATE, 0);
5290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
5300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  *codec = VideoCodec(id, name, width, height, framerate, 0);
5310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  codec->params = paramap;
5325aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org  ParseFeedbackParams(elem, &codec->feedback_params);
5330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
5340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
5350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
5360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool ParseJingleDataCodec(const buzz::XmlElement* elem, DataCodec* codec) {
5370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int id = GetXmlAttr(elem, QN_ID, -1);
5380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (id < 0)
5390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
5400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
5410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  std::string name = GetXmlAttr(elem, QN_NAME, buzz::STR_EMPTY);
5420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
5430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  *codec = DataCodec(id, name, 0);
5445aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org  ParseFeedbackParams(elem, &codec->feedback_params);
5450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
5460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
5470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
5480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool ParseJingleStreamsOrLegacySsrc(const buzz::XmlElement* desc_elem,
5490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                    MediaContentDescription* media,
5500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                    ParseError* error) {
5510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (HasJingleStreams(desc_elem)) {
5520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (!ParseJingleStreams(desc_elem, &(media->mutable_streams()), error)) {
5530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
5540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
5550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else {
5560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    const std::string ssrc_str = desc_elem->Attr(QN_SSRC);
5570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (!ParseSsrcAsLegacyStream(
5580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org            ssrc_str, &(media->mutable_streams()), error)) {
5590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
5600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
5610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
5620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
5630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
5640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
5650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool ParseJingleAudioContent(const buzz::XmlElement* content_elem,
5660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                             ContentDescription** content,
5670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                             ParseError* error) {
5687162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  talk_base::scoped_ptr<AudioContentDescription> audio(
5697162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org      new AudioContentDescription());
5700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
5715aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org  FeedbackParams content_feedback_params;
5725aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org  ParseFeedbackParams(content_elem, &content_feedback_params);
5735aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org
5740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (const buzz::XmlElement* payload_elem =
5750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org           content_elem->FirstNamed(QN_JINGLE_RTP_PAYLOADTYPE);
5760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      payload_elem != NULL;
5770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      payload_elem = payload_elem->NextNamed(QN_JINGLE_RTP_PAYLOADTYPE)) {
5780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    AudioCodec codec;
5790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (ParseJingleAudioCodec(payload_elem, &codec)) {
5805aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org      AddFeedbackParams(content_feedback_params, &codec.feedback_params);
5810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      audio->AddCodec(codec);
5820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
5830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
5840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
5857162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  if (!ParseJingleStreamsOrLegacySsrc(content_elem, audio.get(), error)) {
5860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
5870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
5880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
5897162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  if (!ParseJingleEncryption(content_elem, audio.get(), error)) {
5900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
5910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
5920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
5930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  audio->set_rtcp_mux(content_elem->FirstNamed(QN_JINGLE_RTCP_MUX) != NULL);
5940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
5950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  RtpHeaderExtensions hdrexts;
5960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!ParseJingleRtpHeaderExtensions(content_elem, &hdrexts, error)) {
5970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
5980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
5990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  audio->set_rtp_header_extensions(hdrexts);
6000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
6017162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  *content = audio.release();
6020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
6030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
6040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
6050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool ParseJingleVideoContent(const buzz::XmlElement* content_elem,
6060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                             ContentDescription** content,
6070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                             ParseError* error) {
6087162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  talk_base::scoped_ptr<VideoContentDescription> video(
6097162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org      new VideoContentDescription());
6100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
6115aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org  FeedbackParams content_feedback_params;
6125aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org  ParseFeedbackParams(content_elem, &content_feedback_params);
6135aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org
6140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (const buzz::XmlElement* payload_elem =
6150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org           content_elem->FirstNamed(QN_JINGLE_RTP_PAYLOADTYPE);
6160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      payload_elem != NULL;
6170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      payload_elem = payload_elem->NextNamed(QN_JINGLE_RTP_PAYLOADTYPE)) {
6180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    VideoCodec codec;
6190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (ParseJingleVideoCodec(payload_elem, &codec)) {
6205aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org      AddFeedbackParams(content_feedback_params, &codec.feedback_params);
6210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      video->AddCodec(codec);
6220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
6230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
6240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
6257162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  if (!ParseJingleStreamsOrLegacySsrc(content_elem, video.get(), error)) {
6260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
6270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
6287162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  ParseBandwidth(content_elem, video.get());
6290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
6307162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  if (!ParseJingleEncryption(content_elem, video.get(), error)) {
6310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
6320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
6330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
6340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  video->set_rtcp_mux(content_elem->FirstNamed(QN_JINGLE_RTCP_MUX) != NULL);
6350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
6360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  RtpHeaderExtensions hdrexts;
6370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!ParseJingleRtpHeaderExtensions(content_elem, &hdrexts, error)) {
6380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
6390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
6400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  video->set_rtp_header_extensions(hdrexts);
6410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
6427162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  *content = video.release();
6430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
6440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
6450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
6460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool ParseJingleSctpDataContent(const buzz::XmlElement* content_elem,
6470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                ContentDescription** content,
6480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                ParseError* error) {
6497162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  talk_base::scoped_ptr<DataContentDescription> data(
6507162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org      new DataContentDescription());
6510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  data->set_protocol(kMediaProtocolSctp);
6520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
6530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (const buzz::XmlElement* stream_elem =
6540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org           content_elem->FirstNamed(QN_JINGLE_DRAFT_SCTP_STREAM);
6550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org       stream_elem != NULL;
6560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org       stream_elem = stream_elem->NextNamed(QN_JINGLE_DRAFT_SCTP_STREAM)) {
6570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    StreamParams stream;
6580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    stream.groupid = stream_elem->Attr(QN_NICK);
6590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    stream.id = stream_elem->Attr(QN_NAME);
6600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    uint32 sid;
6610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (!talk_base::FromString(stream_elem->Attr(QN_SID), &sid)) {
6620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return BadParse("Missing or invalid sid.", error);
6630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
6640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (sid > kMaxSctpSid) {
6650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return BadParse("SID is greater than max value.", error);
6660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
6670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
6680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    stream.ssrcs.push_back(sid);
6690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    data->mutable_streams().push_back(stream);
6700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
6710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
6727162d28d68ad58802a5a52eca0df59150ee7b9d4henrike@webrtc.org  *content = data.release();
6730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
6740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
6750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
6760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool ParseJingleRtpDataContent(const buzz::XmlElement* content_elem,
6770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                               ContentDescription** content,
6780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                               ParseError* error) {
6790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  DataContentDescription* data = new DataContentDescription();
6800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
6815aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org  FeedbackParams content_feedback_params;
6825aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org  ParseFeedbackParams(content_elem, &content_feedback_params);
6835aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org
6840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (const buzz::XmlElement* payload_elem =
6850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org           content_elem->FirstNamed(QN_JINGLE_RTP_PAYLOADTYPE);
6860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      payload_elem != NULL;
6870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      payload_elem = payload_elem->NextNamed(QN_JINGLE_RTP_PAYLOADTYPE)) {
6880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    DataCodec codec;
6890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (ParseJingleDataCodec(payload_elem, &codec)) {
6905aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org      AddFeedbackParams(content_feedback_params, &codec.feedback_params);
6910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      data->AddCodec(codec);
6920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
6930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
6940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
6950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!ParseJingleStreamsOrLegacySsrc(content_elem, data, error)) {
6960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
6970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
6980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  ParseBandwidth(content_elem, data);
6990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
7000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!ParseJingleEncryption(content_elem, data, error)) {
7010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
7020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
7030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
7040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  data->set_rtcp_mux(content_elem->FirstNamed(QN_JINGLE_RTCP_MUX) != NULL);
7050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
7060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  *content = data;
7070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
7080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
7090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
7100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool MediaSessionClient::ParseContent(SignalingProtocol protocol,
7110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                      const buzz::XmlElement* content_elem,
7120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                      ContentDescription** content,
7130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                      ParseError* error) {
7140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (protocol == PROTOCOL_GINGLE) {
7150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    const std::string& content_type = content_elem->Name().Namespace();
7160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (NS_GINGLE_AUDIO == content_type) {
7170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return ParseGingleAudioContent(content_elem, content, error);
7180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    } else if (NS_GINGLE_VIDEO == content_type) {
7190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return ParseGingleVideoContent(content_elem, content, error);
7200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    } else {
7210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return BadParse("Unknown content type: " + content_type, error);
7220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
7230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else {
7240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    const std::string& content_type = content_elem->Name().Namespace();
7250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // We use the XMLNS of the <description> element to determine if
7260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    // it's RTP or SCTP.
7270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (content_type == NS_JINGLE_DRAFT_SCTP) {
7280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return ParseJingleSctpDataContent(content_elem, content, error);
7290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
7300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
7310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    std::string media;
7320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (!RequireXmlAttr(content_elem, QN_JINGLE_CONTENT_MEDIA, &media, error))
7330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return false;
7340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
7350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (media == JINGLE_CONTENT_MEDIA_AUDIO) {
7360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return ParseJingleAudioContent(content_elem, content, error);
7370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    } else if (media == JINGLE_CONTENT_MEDIA_VIDEO) {
7380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return ParseJingleVideoContent(content_elem, content, error);
7390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    } else if (media == JINGLE_CONTENT_MEDIA_DATA) {
7400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return ParseJingleRtpDataContent(content_elem, content, error);
7410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    } else {
7420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return BadParse("Unknown media: " + media, error);
7430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
7440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
7450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
7460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
7470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbuzz::XmlElement* CreateGingleAudioCodecElem(const AudioCodec& codec) {
7480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  buzz::XmlElement* payload_type =
7490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      new buzz::XmlElement(QN_GINGLE_AUDIO_PAYLOADTYPE, true);
7500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  AddXmlAttr(payload_type, QN_ID, codec.id);
7510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  payload_type->AddAttr(QN_NAME, codec.name);
7520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (codec.clockrate > 0)
7530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    AddXmlAttr(payload_type, QN_CLOCKRATE, codec.clockrate);
7540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (codec.bitrate > 0)
7550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    AddXmlAttr(payload_type, QN_BITRATE, codec.bitrate);
7560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (codec.channels > 1)
7570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    AddXmlAttr(payload_type, QN_CHANNELS, codec.channels);
7580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return payload_type;
7590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
7600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
7610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbuzz::XmlElement* CreateGingleVideoCodecElem(const VideoCodec& codec) {
7620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  buzz::XmlElement* payload_type =
7630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      new buzz::XmlElement(QN_GINGLE_VIDEO_PAYLOADTYPE, true);
7640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  AddXmlAttr(payload_type, QN_ID, codec.id);
7650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  payload_type->AddAttr(QN_NAME, codec.name);
7660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  AddXmlAttr(payload_type, QN_WIDTH, codec.width);
7670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  AddXmlAttr(payload_type, QN_HEIGHT, codec.height);
7680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  AddXmlAttr(payload_type, QN_FRAMERATE, codec.framerate);
7690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return payload_type;
7700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
7710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
7720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbuzz::XmlElement* CreateGingleSsrcElem(const buzz::QName& name, uint32 ssrc) {
7730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  buzz::XmlElement* elem = new buzz::XmlElement(name, true);
7740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (ssrc) {
7750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    SetXmlBody(elem, ssrc);
7760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
7770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return elem;
7780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
7790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
7800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbuzz::XmlElement* CreateBandwidthElem(const buzz::QName& name, int bps) {
7810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  int kbps = bps / 1000;
7820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  buzz::XmlElement* elem = new buzz::XmlElement(name);
7830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  elem->AddAttr(buzz::QN_TYPE, "AS");
7840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  SetXmlBody(elem, kbps);
7850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return elem;
7860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
7870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
7880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org// For Jingle, usage_qname is empty.
7890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbuzz::XmlElement* CreateJingleEncryptionElem(const CryptoParamsVec& cryptos,
7900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                             bool required) {
7910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  buzz::XmlElement* encryption_elem = new buzz::XmlElement(QN_ENCRYPTION);
7920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
7930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (required) {
7940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    encryption_elem->SetAttr(QN_ENCRYPTION_REQUIRED, "true");
7950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
7960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
7970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (CryptoParamsVec::const_iterator i = cryptos.begin();
7980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org       i != cryptos.end();
7990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org       ++i) {
8000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    buzz::XmlElement* crypto_elem = new buzz::XmlElement(QN_CRYPTO);
8010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
8020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    AddXmlAttr(crypto_elem, QN_CRYPTO_TAG, i->tag);
8030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    crypto_elem->AddAttr(QN_CRYPTO_SUITE, i->cipher_suite);
8040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    crypto_elem->AddAttr(QN_CRYPTO_KEY_PARAMS, i->key_params);
8050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (!i->session_params.empty()) {
8060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      crypto_elem->AddAttr(QN_CRYPTO_SESSION_PARAMS, i->session_params);
8070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
8080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    encryption_elem->AddElement(crypto_elem);
8090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
8100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return encryption_elem;
8110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
8120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
8130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbuzz::XmlElement* CreateGingleEncryptionElem(const CryptoParamsVec& cryptos,
8140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                             const buzz::QName& usage_qname,
8150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                             bool required) {
8160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  buzz::XmlElement* encryption_elem =
8170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      CreateJingleEncryptionElem(cryptos, required);
8180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
8190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (required) {
8200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    encryption_elem->SetAttr(QN_ENCRYPTION_REQUIRED, "true");
8210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
8220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
8230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  buzz::XmlElement* usage_elem = new buzz::XmlElement(usage_qname);
8240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  encryption_elem->AddElement(usage_elem);
8250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
8260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return encryption_elem;
8270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
8280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
8290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbuzz::XmlElement* CreateGingleAudioContentElem(
8300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    const AudioContentDescription* audio,
8310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    bool crypto_required) {
8320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  buzz::XmlElement* elem =
8330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      new buzz::XmlElement(QN_GINGLE_AUDIO_CONTENT, true);
8340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
8350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (AudioCodecs::const_iterator codec = audio->codecs().begin();
8360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org       codec != audio->codecs().end(); ++codec) {
8370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    elem->AddElement(CreateGingleAudioCodecElem(*codec));
8380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
8390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (audio->has_ssrcs()) {
8400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    elem->AddElement(CreateGingleSsrcElem(
8410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        QN_GINGLE_AUDIO_SRCID, audio->first_ssrc()));
8420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
8430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
8440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  const CryptoParamsVec& cryptos = audio->cryptos();
8450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!cryptos.empty()) {
8460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    elem->AddElement(CreateGingleEncryptionElem(cryptos,
8470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                                QN_GINGLE_AUDIO_CRYPTO_USAGE,
8480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                                crypto_required));
8490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
8500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return elem;
8510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
8520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
8530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbuzz::XmlElement* CreateGingleVideoContentElem(
8540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    const VideoContentDescription* video,
8550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    bool crypto_required) {
8560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  buzz::XmlElement* elem =
8570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      new buzz::XmlElement(QN_GINGLE_VIDEO_CONTENT, true);
8580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
8590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (VideoCodecs::const_iterator codec = video->codecs().begin();
8600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org       codec != video->codecs().end(); ++codec) {
8610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    elem->AddElement(CreateGingleVideoCodecElem(*codec));
8620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
8630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (video->has_ssrcs()) {
8640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    elem->AddElement(CreateGingleSsrcElem(
8650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        QN_GINGLE_VIDEO_SRCID, video->first_ssrc()));
8660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
8670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (video->bandwidth() != kAutoBandwidth) {
8680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    elem->AddElement(CreateBandwidthElem(QN_GINGLE_VIDEO_BANDWIDTH,
8690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                         video->bandwidth()));
8700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
8710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
8720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  const CryptoParamsVec& cryptos = video->cryptos();
8730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!cryptos.empty()) {
8740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    elem->AddElement(CreateGingleEncryptionElem(cryptos,
8750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                                QN_GINGLE_VIDEO_CRYPTO_USAGE,
8760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                                crypto_required));
8770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
8780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
8790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return elem;
8800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
8810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
8820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgtemplate <class T>
8830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbuzz::XmlElement* CreatePayloadTypeParameterElem(
8840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    const std::string& name, T value) {
8850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  buzz::XmlElement* elem = new buzz::XmlElement(QN_PARAMETER);
8860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
8870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  elem->AddAttr(QN_PAYLOADTYPE_PARAMETER_NAME, name);
8880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  AddXmlAttr(elem, QN_PAYLOADTYPE_PARAMETER_VALUE, value);
8890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
8900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return elem;
8910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
8920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
8935aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.orgvoid AddRtcpFeedbackElem(buzz::XmlElement* elem,
8945aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org                      const FeedbackParams& feedback_params) {
8955aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org  std::vector<FeedbackParam>::const_iterator it;
8965aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org  for (it = feedback_params.params().begin();
8975aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org       it != feedback_params.params().end(); ++it) {
8985aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org    buzz::XmlElement* fb_elem = new buzz::XmlElement(QN_JINGLE_RTCP_FB);
8995aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org    fb_elem->AddAttr(QN_TYPE, it->id());
9005aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org    fb_elem->AddAttr(QN_SUBTYPE, it->param());
9015aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org    elem->AddElement(fb_elem);
9025aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org  }
9035aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org}
9045aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org
9050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbuzz::XmlElement* CreateJingleAudioCodecElem(const AudioCodec& codec) {
9060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  buzz::XmlElement* elem = new buzz::XmlElement(QN_JINGLE_RTP_PAYLOADTYPE);
9070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
9080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  AddXmlAttr(elem, QN_ID, codec.id);
9090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  elem->AddAttr(QN_NAME, codec.name);
9100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (codec.clockrate > 0) {
9110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    AddXmlAttr(elem, QN_CLOCKRATE, codec.clockrate);
9120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
9130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (codec.bitrate > 0) {
9140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    elem->AddElement(CreatePayloadTypeParameterElem(
9150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        PAYLOADTYPE_PARAMETER_BITRATE, codec.bitrate));
9160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
9170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (codec.channels > 1) {
9180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    AddXmlAttr(elem, QN_CHANNELS, codec.channels);
9190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
9200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
9215aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org  AddRtcpFeedbackElem(elem, codec.feedback_params);
9225aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org
9230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return elem;
9240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
9250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
9260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbuzz::XmlElement* CreateJingleVideoCodecElem(const VideoCodec& codec) {
9270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  buzz::XmlElement* elem = new buzz::XmlElement(QN_JINGLE_RTP_PAYLOADTYPE);
9280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
9290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  AddXmlAttr(elem, QN_ID, codec.id);
9300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  elem->AddAttr(QN_NAME, codec.name);
9310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  elem->AddElement(CreatePayloadTypeParameterElem(
9320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      PAYLOADTYPE_PARAMETER_WIDTH, codec.width));
9330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  elem->AddElement(CreatePayloadTypeParameterElem(
9340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      PAYLOADTYPE_PARAMETER_HEIGHT, codec.height));
9350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  elem->AddElement(CreatePayloadTypeParameterElem(
9360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      PAYLOADTYPE_PARAMETER_FRAMERATE, codec.framerate));
9375aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org
9385aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org  AddRtcpFeedbackElem(elem, codec.feedback_params);
9395aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org
9400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  CodecParameterMap::const_iterator param_iter;
9410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (param_iter = codec.params.begin(); param_iter != codec.params.end();
9420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org       ++param_iter) {
9430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    elem->AddElement(CreatePayloadTypeParameterElem(param_iter->first,
9440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                                    param_iter->second));
9450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
9460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
9470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return elem;
9480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
9490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
9500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbuzz::XmlElement* CreateJingleDataCodecElem(const DataCodec& codec) {
9510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  buzz::XmlElement* elem = new buzz::XmlElement(QN_JINGLE_RTP_PAYLOADTYPE);
9520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
9530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  AddXmlAttr(elem, QN_ID, codec.id);
9540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  elem->AddAttr(QN_NAME, codec.name);
9550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
9565aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org  AddRtcpFeedbackElem(elem, codec.feedback_params);
9575aed3bb9fb287faecd773b88bb68732c31579590wu@webrtc.org
9580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return elem;
9590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
9600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
9610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid WriteLegacyJingleSsrc(const MediaContentDescription* media,
9620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                           buzz::XmlElement* elem) {
9630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (media->has_ssrcs()) {
9640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    AddXmlAttr(elem, QN_SSRC, media->first_ssrc());
9650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
9660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
9670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
9680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgvoid WriteJingleStreamsOrLegacySsrc(const MediaContentDescription* media,
9690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                    buzz::XmlElement* desc_elem) {
9700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!media->multistream()) {
9710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    WriteLegacyJingleSsrc(media, desc_elem);
9720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else {
9730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    WriteJingleStreams(media->streams(), desc_elem);
9740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
9750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
9760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
9770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbuzz::XmlElement* CreateJingleAudioContentElem(
9780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    const AudioContentDescription* audio, bool crypto_required) {
9790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  buzz::XmlElement* elem =
9800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      new buzz::XmlElement(QN_JINGLE_RTP_CONTENT, true);
9810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
9820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  elem->SetAttr(QN_JINGLE_CONTENT_MEDIA, JINGLE_CONTENT_MEDIA_AUDIO);
9830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  WriteJingleStreamsOrLegacySsrc(audio, elem);
9840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
9850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (AudioCodecs::const_iterator codec = audio->codecs().begin();
9860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org       codec != audio->codecs().end(); ++codec) {
9870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    elem->AddElement(CreateJingleAudioCodecElem(*codec));
9880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
9890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
9900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  const CryptoParamsVec& cryptos = audio->cryptos();
9910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!cryptos.empty()) {
9920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    elem->AddElement(CreateJingleEncryptionElem(cryptos, crypto_required));
9930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
9940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
9950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (audio->rtcp_mux()) {
9960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    elem->AddElement(new buzz::XmlElement(QN_JINGLE_RTCP_MUX));
9970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
9980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
9990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  WriteJingleRtpHeaderExtensions(audio->rtp_header_extensions(), elem);
10000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
10010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return elem;
10020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
10030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
10040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbuzz::XmlElement* CreateJingleVideoContentElem(
10050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    const VideoContentDescription* video, bool crypto_required) {
10060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  buzz::XmlElement* elem =
10070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      new buzz::XmlElement(QN_JINGLE_RTP_CONTENT, true);
10080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
10090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  elem->SetAttr(QN_JINGLE_CONTENT_MEDIA, JINGLE_CONTENT_MEDIA_VIDEO);
10100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  WriteJingleStreamsOrLegacySsrc(video, elem);
10110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
10120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (VideoCodecs::const_iterator codec = video->codecs().begin();
10130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org       codec != video->codecs().end(); ++codec) {
10140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    elem->AddElement(CreateJingleVideoCodecElem(*codec));
10150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
10160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
10170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  const CryptoParamsVec& cryptos = video->cryptos();
10180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!cryptos.empty()) {
10190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    elem->AddElement(CreateJingleEncryptionElem(cryptos, crypto_required));
10200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
10210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
10220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (video->rtcp_mux()) {
10230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    elem->AddElement(new buzz::XmlElement(QN_JINGLE_RTCP_MUX));
10240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
10250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
10260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (video->bandwidth() != kAutoBandwidth) {
10270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    elem->AddElement(CreateBandwidthElem(QN_JINGLE_RTP_BANDWIDTH,
10280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                         video->bandwidth()));
10290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
10300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
10310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  WriteJingleRtpHeaderExtensions(video->rtp_header_extensions(), elem);
10320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
10330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return elem;
10340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
10350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
10360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbuzz::XmlElement* CreateJingleSctpDataContentElem(
10370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    const DataContentDescription* data) {
10380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  buzz::XmlElement* content_elem =
10390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      new buzz::XmlElement(QN_JINGLE_DRAFT_SCTP_CONTENT, true);
10400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (std::vector<StreamParams>::const_iterator
10410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org           stream = data->streams().begin();
10420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org       stream != data->streams().end(); ++stream) {
10430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    buzz::XmlElement* stream_elem =
10440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      new buzz::XmlElement(QN_JINGLE_DRAFT_SCTP_STREAM, false);
10450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    AddXmlAttrIfNonEmpty(stream_elem, QN_NICK, stream->groupid);
10460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    AddXmlAttrIfNonEmpty(stream_elem, QN_NAME, stream->id);
10470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (!stream->ssrcs.empty()) {
10480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      AddXmlAttr(stream_elem, QN_SID, stream->ssrcs[0]);
10490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
10500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    content_elem->AddElement(stream_elem);
10510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
10520e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return content_elem;;
10530e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
10540e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
10550e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbuzz::XmlElement* CreateJingleRtpDataContentElem(
10560e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    const DataContentDescription* data, bool crypto_required) {
10570e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
10580e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  buzz::XmlElement* elem =
10590e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      new buzz::XmlElement(QN_JINGLE_RTP_CONTENT, true);
10600e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
10610e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  elem->SetAttr(QN_JINGLE_CONTENT_MEDIA, JINGLE_CONTENT_MEDIA_DATA);
10620e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  WriteJingleStreamsOrLegacySsrc(data, elem);
10630e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
10640e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  for (DataCodecs::const_iterator codec = data->codecs().begin();
10650e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org       codec != data->codecs().end(); ++codec) {
10660e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    elem->AddElement(CreateJingleDataCodecElem(*codec));
10670e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
10680e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
10690e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  const CryptoParamsVec& cryptos = data->cryptos();
10700e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (!cryptos.empty()) {
10710e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    elem->AddElement(CreateJingleEncryptionElem(cryptos, crypto_required));
10720e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
10730e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
10740e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (data->rtcp_mux()) {
10750e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    elem->AddElement(new buzz::XmlElement(QN_JINGLE_RTCP_MUX));
10760e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
10770e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
10780e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (data->bandwidth() != kAutoBandwidth) {
10790e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    elem->AddElement(CreateBandwidthElem(QN_JINGLE_RTP_BANDWIDTH,
10800e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                         data->bandwidth()));
10810e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
10820e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
10830e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return elem;
10840e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
10850e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
10860e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool IsSctp(const DataContentDescription* data) {
10870e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return (data->protocol() == kMediaProtocolSctp ||
10880e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    data->protocol() == kMediaProtocolDtlsSctp);
10890e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
10900e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
10910e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbuzz::XmlElement* CreateJingleDataContentElem(
10920e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    const DataContentDescription* data, bool crypto_required) {
10930e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (IsSctp(data)) {
10940e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return CreateJingleSctpDataContentElem(data);
10950e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else {
10960e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return CreateJingleRtpDataContentElem(data, crypto_required);
10970e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
10980e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
10990e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
11000e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool MediaSessionClient::IsWritable(SignalingProtocol protocol,
11010e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                    const ContentDescription* content) {
11020e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  const MediaContentDescription* media =
11030e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      static_cast<const MediaContentDescription*>(content);
11040e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (protocol == PROTOCOL_GINGLE &&
11050e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      media->type() == MEDIA_TYPE_DATA) {
11060e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return false;
11070e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
11080e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
11090e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
11100e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
11110e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.orgbool MediaSessionClient::WriteContent(SignalingProtocol protocol,
11120e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                      const ContentDescription* content,
11130e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                      buzz::XmlElement** elem,
11140e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                                      WriteError* error) {
11150e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  const MediaContentDescription* media =
11160e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      static_cast<const MediaContentDescription*>(content);
11170e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  bool crypto_required = secure() == SEC_REQUIRED;
11180e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
11190e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  if (media->type() == MEDIA_TYPE_AUDIO) {
11200e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    const AudioContentDescription* audio =
11210e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        static_cast<const AudioContentDescription*>(media);
11220e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (protocol == PROTOCOL_GINGLE) {
11230e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      *elem = CreateGingleAudioContentElem(audio, crypto_required);
11240e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    } else {
11250e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      *elem = CreateJingleAudioContentElem(audio, crypto_required);
11260e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
11270e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else if (media->type() == MEDIA_TYPE_VIDEO) {
11280e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    const VideoContentDescription* video =
11290e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        static_cast<const VideoContentDescription*>(media);
11300e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (protocol == PROTOCOL_GINGLE) {
11310e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      *elem = CreateGingleVideoContentElem(video, crypto_required);
11320e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    } else {
11330e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      *elem = CreateJingleVideoContentElem(video, crypto_required);
11340e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
11350e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else if (media->type() == MEDIA_TYPE_DATA) {
11360e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    const DataContentDescription* data =
11370e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org        static_cast<const DataContentDescription*>(media);
11380e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    if (protocol == PROTOCOL_GINGLE) {
11390e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      return BadWrite("Data channel not supported with Gingle.", error);
11400e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    } else {
11410e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org      *elem = CreateJingleDataContentElem(data, crypto_required);
11420e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    }
11430e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  } else {
11440e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org    return BadWrite("Unknown content type: " +
11450e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org                    talk_base::ToString<int>(media->type()), error);
11460e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  }
11470e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
11480e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org  return true;
11490e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}
11500e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org
11510e118e7129884fbea117e78d6f2068139a414dbhenrike@webrtc.org}  // namespace cricket
1152