Fix an issue that a browser seek is requested after decoder draining is interrupted.
[chromium-blink-merge.git] / remoting / protocol / content_description.cc
blob0308fda219fc358c95df74eb16c96361e1c753b7
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 kControlTag[] = "control";
29 const char kEventTag[] = "event";
30 const char kVideoTag[] = "video";
31 const char kAudioTag[] = "audio";
32 const char kDeprecatedResolutionTag[] = "initial-resolution";
34 const char kTransportAttr[] = "transport";
35 const char kVersionAttr[] = "version";
36 const char kCodecAttr[] = "codec";
37 const char kDeprecatedWidthAttr[] = "width";
38 const char kDeprecatedHeightAttr[] = "height";
40 const NameMapElement<ChannelConfig::TransportType> kTransports[] = {
41 { ChannelConfig::TRANSPORT_STREAM, "stream" },
42 { ChannelConfig::TRANSPORT_MUX_STREAM, "mux-stream" },
43 { ChannelConfig::TRANSPORT_DATAGRAM, "datagram" },
44 { ChannelConfig::TRANSPORT_NONE, "none" },
47 const NameMapElement<ChannelConfig::Codec> kCodecs[] = {
48 { ChannelConfig::CODEC_VERBATIM, "verbatim" },
49 { ChannelConfig::CODEC_VP8, "vp8" },
50 { ChannelConfig::CODEC_VP9, "vp9" },
51 { ChannelConfig::CODEC_ZIP, "zip" },
52 { ChannelConfig::CODEC_OPUS, "opus" },
53 { ChannelConfig::CODEC_SPEEX, "speex" },
56 // Format a channel configuration tag for chromotocol session description,
57 // e.g. for video channel:
58 // <video transport="stream" version="1" codec="vp8" />
59 XmlElement* FormatChannelConfig(const ChannelConfig& config,
60 const std::string& tag_name) {
61 XmlElement* result = new XmlElement(
62 QName(kChromotingXmlNamespace, tag_name));
64 result->AddAttr(QName(kDefaultNs, kTransportAttr),
65 ValueToName(kTransports, config.transport));
67 if (config.transport != ChannelConfig::TRANSPORT_NONE) {
68 result->AddAttr(QName(kDefaultNs, kVersionAttr),
69 base::IntToString(config.version));
71 if (config.codec != ChannelConfig::CODEC_UNDEFINED) {
72 result->AddAttr(QName(kDefaultNs, kCodecAttr),
73 ValueToName(kCodecs, config.codec));
77 return result;
80 // Returns false if the element is invalid.
81 bool ParseChannelConfig(const XmlElement* element, bool codec_required,
82 ChannelConfig* config) {
83 if (!NameToValue(
84 kTransports, element->Attr(QName(kDefaultNs, kTransportAttr)),
85 &config->transport)) {
86 return false;
89 // Version is not required when transport="none".
90 if (config->transport != ChannelConfig::TRANSPORT_NONE) {
91 if (!base::StringToInt(element->Attr(QName(kDefaultNs, kVersionAttr)),
92 &config->version)) {
93 return false;
96 // Codec is not required when transport="none".
97 if (codec_required) {
98 if (!NameToValue(kCodecs, element->Attr(QName(kDefaultNs, kCodecAttr)),
99 &config->codec)) {
100 return false;
102 } else {
103 config->codec = ChannelConfig::CODEC_UNDEFINED;
105 } else {
106 config->version = 0;
107 config->codec = ChannelConfig::CODEC_UNDEFINED;
110 return true;
113 } // namespace
115 ContentDescription::ContentDescription(
116 scoped_ptr<CandidateSessionConfig> config,
117 scoped_ptr<buzz::XmlElement> authenticator_message)
118 : candidate_config_(config.Pass()),
119 authenticator_message_(authenticator_message.Pass()) {
122 ContentDescription::~ContentDescription() { }
124 ContentDescription* ContentDescription::Copy() const {
125 if (!candidate_config_.get() || !authenticator_message_.get()) {
126 return NULL;
128 scoped_ptr<XmlElement> message(new XmlElement(*authenticator_message_));
129 return new ContentDescription(candidate_config_->Clone(), message.Pass());
132 // ToXml() creates content description for chromoting session. The
133 // description looks as follows:
134 // <description xmlns="google:remoting">
135 // <control transport="stream" version="1" />
136 // <event transport="datagram" version="1" />
137 // <video transport="stream" codec="vp8" version="1" />
138 // <audio transport="stream" codec="opus" version="1" />
139 // <authentication>
140 // Message created by Authenticator implementation.
141 // </authentication>
142 // </description>
144 XmlElement* ContentDescription::ToXml() const {
145 XmlElement* root = new XmlElement(
146 QName(kChromotingXmlNamespace, kDescriptionTag), true);
148 std::list<ChannelConfig>::const_iterator it;
150 for (it = config()->control_configs().begin();
151 it != config()->control_configs().end(); ++it) {
152 root->AddElement(FormatChannelConfig(*it, kControlTag));
155 for (it = config()->event_configs().begin();
156 it != config()->event_configs().end(); ++it) {
157 root->AddElement(FormatChannelConfig(*it, kEventTag));
160 for (it = config()->video_configs().begin();
161 it != config()->video_configs().end(); ++it) {
162 root->AddElement(FormatChannelConfig(*it, kVideoTag));
165 for (it = config()->audio_configs().begin();
166 it != config()->audio_configs().end(); ++it) {
167 ChannelConfig config = *it;
168 root->AddElement(FormatChannelConfig(config, kAudioTag));
171 // Older endpoints require an initial-resolution tag, but otherwise ignore it.
172 XmlElement* resolution_tag = new XmlElement(
173 QName(kChromotingXmlNamespace, kDeprecatedResolutionTag));
174 resolution_tag->AddAttr(QName(kDefaultNs, kDeprecatedWidthAttr), "640");
175 resolution_tag->AddAttr(QName(kDefaultNs, kDeprecatedHeightAttr), "480");
176 root->AddElement(resolution_tag);
178 if (authenticator_message_.get()) {
179 DCHECK(Authenticator::IsAuthenticatorMessage(authenticator_message_.get()));
180 root->AddElement(new XmlElement(*authenticator_message_));
183 return root;
186 // static
187 // Adds the channel configs corresponding to |tag_name|,
188 // found in |element|, to |configs|.
189 bool ContentDescription::ParseChannelConfigs(
190 const XmlElement* const element,
191 const char tag_name[],
192 bool codec_required,
193 bool optional,
194 std::list<ChannelConfig>* const configs) {
196 QName tag(kChromotingXmlNamespace, tag_name);
197 const XmlElement* child = element->FirstNamed(tag);
198 while (child) {
199 ChannelConfig channel_config;
200 if (ParseChannelConfig(child, codec_required, &channel_config)) {
201 configs->push_back(channel_config);
203 child = child->NextNamed(tag);
205 if (optional && configs->empty()) {
206 // If there's no mention of the tag, implicitly assume disabled channel.
207 configs->push_back(ChannelConfig::None());
209 return true;
212 // static
213 scoped_ptr<ContentDescription> ContentDescription::ParseXml(
214 const XmlElement* element) {
215 if (element->Name() != QName(kChromotingXmlNamespace, kDescriptionTag)) {
216 LOG(ERROR) << "Invalid description: " << element->Str();
217 return nullptr;
219 scoped_ptr<CandidateSessionConfig> config(
220 CandidateSessionConfig::CreateEmpty());
221 if (!ParseChannelConfigs(element, kControlTag, false, false,
222 config->mutable_control_configs()) ||
223 !ParseChannelConfigs(element, kEventTag, false, false,
224 config->mutable_event_configs()) ||
225 !ParseChannelConfigs(element, kVideoTag, true, false,
226 config->mutable_video_configs()) ||
227 !ParseChannelConfigs(element, kAudioTag, true, true,
228 config->mutable_audio_configs())) {
229 return nullptr;
232 scoped_ptr<XmlElement> authenticator_message;
233 const XmlElement* child = Authenticator::FindAuthenticatorMessage(element);
234 if (child)
235 authenticator_message.reset(new XmlElement(*child));
237 return make_scoped_ptr(
238 new ContentDescription(config.Pass(), authenticator_message.Pass()));
241 } // namespace protocol
242 } // namespace remoting