| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "remoting/protocol/content_description.h" | 5 #include "remoting/protocol/content_description.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/strings/string_number_conversions.h" | 8 #include "base/strings/string_number_conversions.h" |
| 9 #include "remoting/base/constants.h" | 9 #include "remoting/base/constants.h" |
| 10 #include "remoting/protocol/authenticator.h" | 10 #include "remoting/protocol/authenticator.h" |
| 11 #include "remoting/protocol/name_value_map.h" | 11 #include "remoting/protocol/name_value_map.h" |
| 12 #include "third_party/webrtc/libjingle/xmllite/xmlelement.h" | 12 #include "third_party/webrtc/libjingle/xmllite/xmlelement.h" |
| 13 | 13 |
| 14 using buzz::QName; | 14 using buzz::QName; |
| 15 using buzz::XmlElement; | 15 using buzz::XmlElement; |
| 16 | 16 |
| 17 namespace remoting { | 17 namespace remoting { |
| 18 namespace protocol { | 18 namespace protocol { |
| 19 | 19 |
| 20 const char ContentDescription::kChromotingContentName[] = "chromoting"; | 20 const char ContentDescription::kChromotingContentName[] = "chromoting"; |
| 21 | 21 |
| 22 namespace { | 22 namespace { |
| 23 | 23 |
| 24 const char kDefaultNs[] = ""; | 24 const char kDefaultNs[] = ""; |
| 25 | 25 |
| 26 // Following constants are used to format session description in XML. | 26 // Following constants are used to format session description in XML. |
| 27 const char kDescriptionTag[] = "description"; | 27 const char kDescriptionTag[] = "description"; |
| 28 const char kStandardIceTag[] = "standard-ice"; | |
| 29 const char kControlTag[] = "control"; | 28 const char kControlTag[] = "control"; |
| 30 const char kEventTag[] = "event"; | 29 const char kEventTag[] = "event"; |
| 31 const char kVideoTag[] = "video"; | 30 const char kVideoTag[] = "video"; |
| 32 const char kAudioTag[] = "audio"; | 31 const char kAudioTag[] = "audio"; |
| 33 const char kDeprecatedResolutionTag[] = "initial-resolution"; | 32 const char kDeprecatedResolutionTag[] = "initial-resolution"; |
| 34 | 33 |
| 35 const char kTransportAttr[] = "transport"; | 34 const char kTransportAttr[] = "transport"; |
| 36 const char kVersionAttr[] = "version"; | 35 const char kVersionAttr[] = "version"; |
| 37 const char kCodecAttr[] = "codec"; | 36 const char kCodecAttr[] = "codec"; |
| 38 const char kDeprecatedWidthAttr[] = "width"; | 37 const char kDeprecatedWidthAttr[] = "width"; |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 115 | 114 |
| 116 ContentDescription::ContentDescription( | 115 ContentDescription::ContentDescription( |
| 117 scoped_ptr<CandidateSessionConfig> config, | 116 scoped_ptr<CandidateSessionConfig> config, |
| 118 scoped_ptr<buzz::XmlElement> authenticator_message) | 117 scoped_ptr<buzz::XmlElement> authenticator_message) |
| 119 : candidate_config_(config.Pass()), | 118 : candidate_config_(config.Pass()), |
| 120 authenticator_message_(authenticator_message.Pass()) { | 119 authenticator_message_(authenticator_message.Pass()) { |
| 121 } | 120 } |
| 122 | 121 |
| 123 ContentDescription::~ContentDescription() { } | 122 ContentDescription::~ContentDescription() { } |
| 124 | 123 |
| 124 ContentDescription* ContentDescription::Copy() const { |
| 125 if (!candidate_config_.get() || !authenticator_message_.get()) { |
| 126 return nullptr; |
| 127 } |
| 128 scoped_ptr<XmlElement> message(new XmlElement(*authenticator_message_)); |
| 129 return new ContentDescription(candidate_config_->Clone(), message.Pass()); |
| 130 } |
| 131 |
| 125 // ToXml() creates content description for chromoting session. The | 132 // ToXml() creates content description for chromoting session. The |
| 126 // description looks as follows: | 133 // description looks as follows: |
| 127 // <description xmlns="google:remoting"> | 134 // <description xmlns="google:remoting"> |
| 128 // <standard-ice/> | |
| 129 // <control transport="stream" version="1" /> | 135 // <control transport="stream" version="1" /> |
| 130 // <event transport="datagram" version="1" /> | 136 // <event transport="datagram" version="1" /> |
| 131 // <video transport="stream" codec="vp8" version="1" /> | 137 // <video transport="stream" codec="vp8" version="1" /> |
| 132 // <audio transport="stream" codec="opus" version="1" /> | 138 // <audio transport="stream" codec="opus" version="1" /> |
| 133 // <authentication> | 139 // <authentication> |
| 134 // Message created by Authenticator implementation. | 140 // Message created by Authenticator implementation. |
| 135 // </authentication> | 141 // </authentication> |
| 136 // </description> | 142 // </description> |
| 137 // | 143 // |
| 138 XmlElement* ContentDescription::ToXml() const { | 144 XmlElement* ContentDescription::ToXml() const { |
| 139 XmlElement* root = new XmlElement( | 145 XmlElement* root = new XmlElement( |
| 140 QName(kChromotingXmlNamespace, kDescriptionTag), true); | 146 QName(kChromotingXmlNamespace, kDescriptionTag), true); |
| 141 | 147 |
| 142 if (config()->standard_ice()) { | 148 std::list<ChannelConfig>::const_iterator it; |
| 143 root->AddElement( | 149 |
| 144 new buzz::XmlElement(QName(kChromotingXmlNamespace, kStandardIceTag))); | 150 for (it = config()->control_configs().begin(); |
| 151 it != config()->control_configs().end(); ++it) { |
| 152 root->AddElement(FormatChannelConfig(*it, kControlTag)); |
| 145 } | 153 } |
| 146 | 154 |
| 147 for (const ChannelConfig& channel_config : config()->control_configs()) { | 155 for (it = config()->event_configs().begin(); |
| 148 root->AddElement(FormatChannelConfig(channel_config, kControlTag)); | 156 it != config()->event_configs().end(); ++it) { |
| 157 root->AddElement(FormatChannelConfig(*it, kEventTag)); |
| 149 } | 158 } |
| 150 | 159 |
| 151 for (const ChannelConfig& channel_config : config()->event_configs()) { | 160 for (it = config()->video_configs().begin(); |
| 152 root->AddElement(FormatChannelConfig(channel_config, kEventTag)); | 161 it != config()->video_configs().end(); ++it) { |
| 162 root->AddElement(FormatChannelConfig(*it, kVideoTag)); |
| 153 } | 163 } |
| 154 | 164 |
| 155 for (const ChannelConfig& channel_config : config()->video_configs()) { | 165 for (it = config()->audio_configs().begin(); |
| 156 root->AddElement(FormatChannelConfig(channel_config, kVideoTag)); | 166 it != config()->audio_configs().end(); ++it) { |
| 157 } | 167 ChannelConfig config = *it; |
| 158 | 168 root->AddElement(FormatChannelConfig(config, kAudioTag)); |
| 159 for (const ChannelConfig& channel_config : config()->audio_configs()) { | |
| 160 root->AddElement(FormatChannelConfig(channel_config, kAudioTag)); | |
| 161 } | 169 } |
| 162 | 170 |
| 163 // Older endpoints require an initial-resolution tag, but otherwise ignore it. | 171 // Older endpoints require an initial-resolution tag, but otherwise ignore it. |
| 164 XmlElement* resolution_tag = new XmlElement( | 172 XmlElement* resolution_tag = new XmlElement( |
| 165 QName(kChromotingXmlNamespace, kDeprecatedResolutionTag)); | 173 QName(kChromotingXmlNamespace, kDeprecatedResolutionTag)); |
| 166 resolution_tag->AddAttr(QName(kDefaultNs, kDeprecatedWidthAttr), "640"); | 174 resolution_tag->AddAttr(QName(kDefaultNs, kDeprecatedWidthAttr), "640"); |
| 167 resolution_tag->AddAttr(QName(kDefaultNs, kDeprecatedHeightAttr), "480"); | 175 resolution_tag->AddAttr(QName(kDefaultNs, kDeprecatedHeightAttr), "480"); |
| 168 root->AddElement(resolution_tag); | 176 root->AddElement(resolution_tag); |
| 169 | 177 |
| 170 if (authenticator_message_.get()) { | 178 if (authenticator_message_.get()) { |
| 171 DCHECK(Authenticator::IsAuthenticatorMessage(authenticator_message_.get())); | 179 DCHECK(Authenticator::IsAuthenticatorMessage(authenticator_message_.get())); |
| 172 root->AddElement(new XmlElement(*authenticator_message_)); | 180 root->AddElement(new XmlElement(*authenticator_message_)); |
| 173 } | 181 } |
| 174 | 182 |
| 175 return root; | 183 return root; |
| 176 } | 184 } |
| 177 | 185 |
| 178 // static | 186 // static |
| 179 // Adds the channel configs corresponding to |tag_name|, | 187 // Adds the channel configs corresponding to |tag_name|, |
| 180 // found in |element|, to |configs|. | 188 // found in |element|, to |configs|. |
| 181 bool ContentDescription::ParseChannelConfigs( | 189 bool ContentDescription::ParseChannelConfigs( |
| 182 const XmlElement* const element, | 190 const XmlElement* const element, |
| 183 const char tag_name[], | 191 const char tag_name[], |
| 184 bool codec_required, | 192 bool codec_required, |
| 185 bool optional, | 193 bool optional, |
| 186 std::list<ChannelConfig>* const configs) { | 194 std::list<ChannelConfig>* const configs) { |
| 195 |
| 187 QName tag(kChromotingXmlNamespace, tag_name); | 196 QName tag(kChromotingXmlNamespace, tag_name); |
| 188 const XmlElement* child = element->FirstNamed(tag); | 197 const XmlElement* child = element->FirstNamed(tag); |
| 189 while (child) { | 198 while (child) { |
| 190 ChannelConfig channel_config; | 199 ChannelConfig channel_config; |
| 191 if (ParseChannelConfig(child, codec_required, &channel_config)) { | 200 if (ParseChannelConfig(child, codec_required, &channel_config)) { |
| 192 configs->push_back(channel_config); | 201 configs->push_back(channel_config); |
| 193 } | 202 } |
| 194 child = child->NextNamed(tag); | 203 child = child->NextNamed(tag); |
| 195 } | 204 } |
| 196 if (optional && configs->empty()) { | 205 if (optional && configs->empty()) { |
| 197 // If there's no mention of the tag, implicitly assume disabled channel. | 206 // If there's no mention of the tag, implicitly assume disabled channel. |
| 198 configs->push_back(ChannelConfig::None()); | 207 configs->push_back(ChannelConfig::None()); |
| 199 } | 208 } |
| 200 return true; | 209 return true; |
| 201 } | 210 } |
| 202 | 211 |
| 203 // static | 212 // static |
| 204 scoped_ptr<ContentDescription> ContentDescription::ParseXml( | 213 scoped_ptr<ContentDescription> ContentDescription::ParseXml( |
| 205 const XmlElement* element) { | 214 const XmlElement* element) { |
| 206 if (element->Name() != QName(kChromotingXmlNamespace, kDescriptionTag)) { | 215 if (element->Name() != QName(kChromotingXmlNamespace, kDescriptionTag)) { |
| 207 LOG(ERROR) << "Invalid description: " << element->Str(); | 216 LOG(ERROR) << "Invalid description: " << element->Str(); |
| 208 return nullptr; | 217 return nullptr; |
| 209 } | 218 } |
| 210 scoped_ptr<CandidateSessionConfig> config( | 219 scoped_ptr<CandidateSessionConfig> config( |
| 211 CandidateSessionConfig::CreateEmpty()); | 220 CandidateSessionConfig::CreateEmpty()); |
| 212 | |
| 213 config->set_standard_ice( | |
| 214 element->FirstNamed(QName(kChromotingXmlNamespace, kStandardIceTag)) != | |
| 215 nullptr); | |
| 216 | |
| 217 if (!ParseChannelConfigs(element, kControlTag, false, false, | 221 if (!ParseChannelConfigs(element, kControlTag, false, false, |
| 218 config->mutable_control_configs()) || | 222 config->mutable_control_configs()) || |
| 219 !ParseChannelConfigs(element, kEventTag, false, false, | 223 !ParseChannelConfigs(element, kEventTag, false, false, |
| 220 config->mutable_event_configs()) || | 224 config->mutable_event_configs()) || |
| 221 !ParseChannelConfigs(element, kVideoTag, true, false, | 225 !ParseChannelConfigs(element, kVideoTag, true, false, |
| 222 config->mutable_video_configs()) || | 226 config->mutable_video_configs()) || |
| 223 !ParseChannelConfigs(element, kAudioTag, true, true, | 227 !ParseChannelConfigs(element, kAudioTag, true, true, |
| 224 config->mutable_audio_configs())) { | 228 config->mutable_audio_configs())) { |
| 225 return nullptr; | 229 return nullptr; |
| 226 } | 230 } |
| 227 | 231 |
| 228 scoped_ptr<XmlElement> authenticator_message; | 232 scoped_ptr<XmlElement> authenticator_message; |
| 229 const XmlElement* child = Authenticator::FindAuthenticatorMessage(element); | 233 const XmlElement* child = Authenticator::FindAuthenticatorMessage(element); |
| 230 if (child) | 234 if (child) |
| 231 authenticator_message.reset(new XmlElement(*child)); | 235 authenticator_message.reset(new XmlElement(*child)); |
| 232 | 236 |
| 233 return make_scoped_ptr( | 237 return make_scoped_ptr( |
| 234 new ContentDescription(config.Pass(), authenticator_message.Pass())); | 238 new ContentDescription(config.Pass(), authenticator_message.Pass())); |
| 235 } | 239 } |
| 236 | 240 |
| 237 } // namespace protocol | 241 } // namespace protocol |
| 238 } // namespace remoting | 242 } // namespace remoting |
| OLD | NEW |