15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/protocol/content_description.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
85e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/base/constants.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/protocol/authenticator.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "remoting/protocol/name_value_map.h"
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using buzz::QName;
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using buzz::XmlElement;
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace remoting {
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace protocol {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char ContentDescription::kChromotingContentName[] = "chromoting";
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kDefaultNs[] = "";
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Following constants are used to format session description in XML.
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kDescriptionTag[] = "description";
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kControlTag[] = "control";
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kEventTag[] = "event";
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kVideoTag[] = "video";
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kAudioTag[] = "audio";
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kDeprecatedResolutionTag[] = "initial-resolution";
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kTransportAttr[] = "transport";
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kVersionAttr[] = "version";
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kCodecAttr[] = "codec";
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kDeprecatedWidthAttr[] = "width";
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kDeprecatedHeightAttr[] = "height";
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const NameMapElement<ChannelConfig::TransportType> kTransports[] = {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  { ChannelConfig::TRANSPORT_STREAM, "stream" },
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  { ChannelConfig::TRANSPORT_MUX_STREAM, "mux-stream" },
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  { ChannelConfig::TRANSPORT_DATAGRAM, "datagram" },
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  { ChannelConfig::TRANSPORT_NONE, "none" },
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const NameMapElement<ChannelConfig::Codec> kCodecs[] = {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  { ChannelConfig::CODEC_VERBATIM, "verbatim" },
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  { ChannelConfig::CODEC_VP8, "vp8" },
508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)  { ChannelConfig::CODEC_VP9, "vp9" },
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  { ChannelConfig::CODEC_ZIP, "zip" },
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  { ChannelConfig::CODEC_OPUS, "opus" },
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  { ChannelConfig::CODEC_SPEEX, "speex" },
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Format a channel configuration tag for chromotocol session description,
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// e.g. for video channel:
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//    <video transport="stream" version="1" codec="vp8" />
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)XmlElement* FormatChannelConfig(const ChannelConfig& config,
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                const std::string& tag_name) {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XmlElement* result = new XmlElement(
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      QName(kChromotingXmlNamespace, tag_name));
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  result->AddAttr(QName(kDefaultNs, kTransportAttr),
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  ValueToName(kTransports, config.transport));
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (config.transport != ChannelConfig::TRANSPORT_NONE) {
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    result->AddAttr(QName(kDefaultNs, kVersionAttr),
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                    base::IntToString(config.version));
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (config.codec != ChannelConfig::CODEC_UNDEFINED) {
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      result->AddAttr(QName(kDefaultNs, kCodecAttr),
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                      ValueToName(kCodecs, config.codec));
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns false if the element is invalid.
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ParseChannelConfig(const XmlElement* element, bool codec_required,
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        ChannelConfig* config) {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!NameToValue(
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          kTransports, element->Attr(QName(kDefaultNs, kTransportAttr)),
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          &config->transport)) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Version is not required when transport="none".
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (config->transport != ChannelConfig::TRANSPORT_NONE) {
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!base::StringToInt(element->Attr(QName(kDefaultNs, kVersionAttr)),
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           &config->version)) {
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Codec is not required when transport="none".
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (codec_required) {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!NameToValue(kCodecs, element->Attr(QName(kDefaultNs, kCodecAttr)),
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       &config->codec)) {
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      config->codec = ChannelConfig::CODEC_UNDEFINED;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    config->version = 0;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    config->codec = ChannelConfig::CODEC_UNDEFINED;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ContentDescription::ContentDescription(
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<CandidateSessionConfig> config,
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_ptr<buzz::XmlElement> authenticator_message)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : candidate_config_(config.Pass()),
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      authenticator_message_(authenticator_message.Pass()) {
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ContentDescription::~ContentDescription() { }
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ContentDescription* ContentDescription::Copy() const {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!candidate_config_.get() || !authenticator_message_.get()) {
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<XmlElement> message(new XmlElement(*authenticator_message_));
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return new ContentDescription(candidate_config_->Clone(), message.Pass());
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ToXml() creates content description for chromoting session. The
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// description looks as follows:
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   <description xmlns="google:remoting">
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     <control transport="stream" version="1" />
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     <event transport="datagram" version="1" />
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     <video transport="stream" codec="vp8" version="1" />
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     <audio transport="stream" codec="opus" version="1" />
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     <authentication>
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//      Message created by Authenticator implementation.
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     </authentication>
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   </description>
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)XmlElement* ContentDescription::ToXml() const {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XmlElement* root = new XmlElement(
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      QName(kChromotingXmlNamespace, kDescriptionTag), true);
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::list<ChannelConfig>::const_iterator it;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (it = config()->control_configs().begin();
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != config()->control_configs().end(); ++it) {
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    root->AddElement(FormatChannelConfig(*it, kControlTag));
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (it = config()->event_configs().begin();
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != config()->event_configs().end(); ++it) {
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    root->AddElement(FormatChannelConfig(*it, kEventTag));
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (it = config()->video_configs().begin();
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != config()->video_configs().end(); ++it) {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    root->AddElement(FormatChannelConfig(*it, kVideoTag));
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (it = config()->audio_configs().begin();
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       it != config()->audio_configs().end(); ++it) {
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ChannelConfig config = *it;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    root->AddElement(FormatChannelConfig(config, kAudioTag));
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Older endpoints require an initial-resolution tag, but otherwise ignore it.
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  XmlElement* resolution_tag = new XmlElement(
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      QName(kChromotingXmlNamespace, kDeprecatedResolutionTag));
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resolution_tag->AddAttr(QName(kDefaultNs, kDeprecatedWidthAttr), "640");
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resolution_tag->AddAttr(QName(kDefaultNs, kDeprecatedHeightAttr), "480");
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  root->AddElement(resolution_tag);
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (authenticator_message_.get()) {
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(Authenticator::IsAuthenticatorMessage(authenticator_message_.get()));
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    root->AddElement(new XmlElement(*authenticator_message_));
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return root;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Adds the channel configs corresponding to |tag_name|,
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in |element|, to |configs|.
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ContentDescription::ParseChannelConfigs(
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const XmlElement* const element,
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char tag_name[],
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool codec_required,
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool optional,
194cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    std::list<ChannelConfig>* const configs) {
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  QName tag(kChromotingXmlNamespace, tag_name);
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const XmlElement* child = element->FirstNamed(tag);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (child) {
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ChannelConfig channel_config;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ParseChannelConfig(child, codec_required, &channel_config)) {
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      configs->push_back(channel_config);
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    child = child->NextNamed(tag);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (optional && configs->empty()) {
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If there's no mention of the tag, implicitly assume disabled channel.
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      configs->push_back(ChannelConfig::None());
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)scoped_ptr<ContentDescription> ContentDescription::ParseXml(
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const XmlElement* element) {
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (element->Name() != QName(kChromotingXmlNamespace, kDescriptionTag)) {
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Invalid description: " << element->Str();
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return scoped_ptr<ContentDescription>();
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<CandidateSessionConfig> config(
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CandidateSessionConfig::CreateEmpty());
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ParseChannelConfigs(element, kControlTag, false, false,
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           config->mutable_control_configs()) ||
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !ParseChannelConfigs(element, kEventTag, false, false,
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           config->mutable_event_configs()) ||
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !ParseChannelConfigs(element, kVideoTag, true, false,
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           config->mutable_video_configs()) ||
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      !ParseChannelConfigs(element, kAudioTag, true, true,
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           config->mutable_audio_configs())) {
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return scoped_ptr<ContentDescription>();
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<XmlElement> authenticator_message;
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const XmlElement* child = Authenticator::FindAuthenticatorMessage(element);
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (child)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    authenticator_message.reset(new XmlElement(*child));
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return scoped_ptr<ContentDescription>(
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      new ContentDescription(config.Pass(), authenticator_message.Pass()));
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace protocol
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace remoting
243