Updating XTBs based on .GRDs from branch master
[chromium-blink-merge.git] / remoting / protocol / content_description.cc
bloba86caa5fa882d589b43eaae3db2fc0e7eb4f0bd2
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "remoting/protocol/content_description.h"
7 #include "base/logging.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "remoting/base/constants.h"
10 #include "remoting/protocol/authenticator.h"
11 #include "remoting/protocol/name_value_map.h"
12 #include "third_party/webrtc/libjingle/xmllite/xmlelement.h"
14 using buzz::QName;
15 using buzz::XmlElement;
17 namespace remoting {
18 namespace protocol {
20 const char ContentDescription::kChromotingContentName[] = "chromoting";
22 namespace {
24 const char kDefaultNs[] = "";
26 // Following constants are used to format session description in XML.
27 const char kDescriptionTag[] = "description";
28 const char kStandardIceTag[] = "standard-ice";
29 const char kControlTag[] = "control";
30 const char kEventTag[] = "event";
31 const char kVideoTag[] = "video";
32 const char kAudioTag[] = "audio";
33 const char kVp9ExperimentTag[] = "vp9-experiment";
34 const char kDeprecatedResolutionTag[] = "initial-resolution";
36 const char kTransportAttr[] = "transport";
37 const char kVersionAttr[] = "version";
38 const char kCodecAttr[] = "codec";
39 const char kDeprecatedWidthAttr[] = "width";
40 const char kDeprecatedHeightAttr[] = "height";
42 const NameMapElement<ChannelConfig::TransportType> kTransports[] = {
43 { ChannelConfig::TRANSPORT_STREAM, "stream" },
44 { ChannelConfig::TRANSPORT_MUX_STREAM, "mux-stream" },
45 { ChannelConfig::TRANSPORT_DATAGRAM, "datagram" },
46 { ChannelConfig::TRANSPORT_NONE, "none" },
49 const NameMapElement<ChannelConfig::Codec> kCodecs[] = {
50 { ChannelConfig::CODEC_VERBATIM, "verbatim" },
51 { ChannelConfig::CODEC_VP8, "vp8" },
52 { ChannelConfig::CODEC_VP9, "vp9" },
53 { ChannelConfig::CODEC_ZIP, "zip" },
54 { ChannelConfig::CODEC_OPUS, "opus" },
55 { ChannelConfig::CODEC_SPEEX, "speex" },
58 // Format a channel configuration tag for chromotocol session description,
59 // e.g. for video channel:
60 // <video transport="stream" version="1" codec="vp8" />
61 XmlElement* FormatChannelConfig(const ChannelConfig& config,
62 const std::string& tag_name) {
63 XmlElement* result = new XmlElement(
64 QName(kChromotingXmlNamespace, tag_name));
66 result->AddAttr(QName(kDefaultNs, kTransportAttr),
67 ValueToName(kTransports, config.transport));
69 if (config.transport != ChannelConfig::TRANSPORT_NONE) {
70 result->AddAttr(QName(kDefaultNs, kVersionAttr),
71 base::IntToString(config.version));
73 if (config.codec != ChannelConfig::CODEC_UNDEFINED) {
74 result->AddAttr(QName(kDefaultNs, kCodecAttr),
75 ValueToName(kCodecs, config.codec));
79 return result;
82 // Returns false if the element is invalid.
83 bool ParseChannelConfig(const XmlElement* element, bool codec_required,
84 ChannelConfig* config) {
85 if (!NameToValue(
86 kTransports, element->Attr(QName(kDefaultNs, kTransportAttr)),
87 &config->transport)) {
88 return false;
91 // Version is not required when transport="none".
92 if (config->transport != ChannelConfig::TRANSPORT_NONE) {
93 if (!base::StringToInt(element->Attr(QName(kDefaultNs, kVersionAttr)),
94 &config->version)) {
95 return false;
98 // Codec is not required when transport="none".
99 if (codec_required) {
100 if (!NameToValue(kCodecs, element->Attr(QName(kDefaultNs, kCodecAttr)),
101 &config->codec)) {
102 return false;
104 } else {
105 config->codec = ChannelConfig::CODEC_UNDEFINED;
107 } else {
108 config->version = 0;
109 config->codec = ChannelConfig::CODEC_UNDEFINED;
112 return true;
115 } // namespace
117 ContentDescription::ContentDescription(
118 scoped_ptr<CandidateSessionConfig> config,
119 scoped_ptr<buzz::XmlElement> authenticator_message)
120 : candidate_config_(config.Pass()),
121 authenticator_message_(authenticator_message.Pass()) {
124 ContentDescription::~ContentDescription() { }
126 // ToXml() creates content description for chromoting session. The
127 // description looks as follows:
128 // <description xmlns="google:remoting">
129 // <standard-ice/>
130 // <control transport="stream" version="1" />
131 // <event transport="datagram" version="1" />
132 // <video transport="stream" codec="vp8" version="1" />
133 // <audio transport="stream" codec="opus" version="1" />
134 // <authentication>
135 // Message created by Authenticator implementation.
136 // </authentication>
137 // </description>
139 XmlElement* ContentDescription::ToXml() const {
140 XmlElement* root = new XmlElement(
141 QName(kChromotingXmlNamespace, kDescriptionTag), true);
143 if (config()->standard_ice()) {
144 root->AddElement(
145 new buzz::XmlElement(QName(kChromotingXmlNamespace, kStandardIceTag)));
148 for (const ChannelConfig& channel_config : config()->control_configs()) {
149 root->AddElement(FormatChannelConfig(channel_config, kControlTag));
152 for (const ChannelConfig& channel_config : config()->event_configs()) {
153 root->AddElement(FormatChannelConfig(channel_config, kEventTag));
156 for (const ChannelConfig& channel_config : config()->video_configs()) {
157 root->AddElement(FormatChannelConfig(channel_config, kVideoTag));
160 for (const ChannelConfig& channel_config : config()->audio_configs()) {
161 root->AddElement(FormatChannelConfig(channel_config, kAudioTag));
164 // Older endpoints require an initial-resolution tag, but otherwise ignore it.
165 XmlElement* resolution_tag = new XmlElement(
166 QName(kChromotingXmlNamespace, kDeprecatedResolutionTag));
167 resolution_tag->AddAttr(QName(kDefaultNs, kDeprecatedWidthAttr), "640");
168 resolution_tag->AddAttr(QName(kDefaultNs, kDeprecatedHeightAttr), "480");
169 root->AddElement(resolution_tag);
171 if (authenticator_message_.get()) {
172 DCHECK(Authenticator::IsAuthenticatorMessage(authenticator_message_.get()));
173 root->AddElement(new XmlElement(*authenticator_message_));
176 if (config()->vp9_experiment_enabled()) {
177 root->AddElement(
178 new XmlElement(QName(kChromotingXmlNamespace, kVp9ExperimentTag)));
181 return root;
184 // static
185 // Adds the channel configs corresponding to |tag_name|,
186 // found in |element|, to |configs|.
187 bool ContentDescription::ParseChannelConfigs(
188 const XmlElement* const element,
189 const char tag_name[],
190 bool codec_required,
191 bool optional,
192 std::list<ChannelConfig>* const configs) {
193 QName tag(kChromotingXmlNamespace, tag_name);
194 const XmlElement* child = element->FirstNamed(tag);
195 while (child) {
196 ChannelConfig channel_config;
197 if (ParseChannelConfig(child, codec_required, &channel_config)) {
198 configs->push_back(channel_config);
200 child = child->NextNamed(tag);
202 if (optional && configs->empty()) {
203 // If there's no mention of the tag, implicitly assume disabled channel.
204 configs->push_back(ChannelConfig::None());
206 return true;
209 // static
210 scoped_ptr<ContentDescription> ContentDescription::ParseXml(
211 const XmlElement* element) {
212 if (element->Name() != QName(kChromotingXmlNamespace, kDescriptionTag)) {
213 LOG(ERROR) << "Invalid description: " << element->Str();
214 return nullptr;
216 scoped_ptr<CandidateSessionConfig> config(
217 CandidateSessionConfig::CreateEmpty());
219 config->set_standard_ice(
220 element->FirstNamed(QName(kChromotingXmlNamespace, kStandardIceTag)) !=
221 nullptr);
223 if (!ParseChannelConfigs(element, kControlTag, false, false,
224 config->mutable_control_configs()) ||
225 !ParseChannelConfigs(element, kEventTag, false, false,
226 config->mutable_event_configs()) ||
227 !ParseChannelConfigs(element, kVideoTag, true, false,
228 config->mutable_video_configs()) ||
229 !ParseChannelConfigs(element, kAudioTag, true, true,
230 config->mutable_audio_configs())) {
231 return nullptr;
234 // Check if VP9 experiment is enabled.
235 if (element->FirstNamed(QName(kChromotingXmlNamespace, kVp9ExperimentTag))) {
236 config->set_vp9_experiment_enabled(true);
239 scoped_ptr<XmlElement> authenticator_message;
240 const XmlElement* child = Authenticator::FindAuthenticatorMessage(element);
241 if (child)
242 authenticator_message.reset(new XmlElement(*child));
244 return make_scoped_ptr(
245 new ContentDescription(config.Pass(), authenticator_message.Pass()));
248 } // namespace protocol
249 } // namespace remoting