1 /* 2 * libjingle 3 * Copyright 2004 Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <string> 29 30 #include "talk/session/media/mediasessionclient.h" 31 32 #include "talk/media/base/capturemanager.h" 33 #include "talk/media/base/cryptoparams.h" 34 #include "talk/media/sctp/sctpdataengine.h" 35 #include "talk/p2p/base/constants.h" 36 #include "talk/p2p/base/parsing.h" 37 #include "talk/session/media/mediamessages.h" 38 #include "talk/session/media/srtpfilter.h" 39 #include "webrtc/libjingle/xmllite/qname.h" 40 #include "webrtc/libjingle/xmllite/xmlconstants.h" 41 #include "talk/xmpp/constants.h" 42 #include "webrtc/base/helpers.h" 43 #include "webrtc/base/logging.h" 44 #include "webrtc/base/stringencode.h" 45 #include "webrtc/base/stringutils.h" 46 47 namespace cricket { 48 49 #if !defined(DISABLE_MEDIA_ENGINE_FACTORY) 50 MediaSessionClient::MediaSessionClient( 51 const buzz::Jid& jid, SessionManager *manager) 52 : jid_(jid), 53 session_manager_(manager), 54 focus_call_(NULL), 55 channel_manager_(new ChannelManager(session_manager_->worker_thread())), 56 desc_factory_(channel_manager_, 57 session_manager_->transport_desc_factory()), 58 multisession_enabled_(false) { 59 Construct(); 60 } 61 #endif 62 63 MediaSessionClient::MediaSessionClient( 64 const buzz::Jid& jid, SessionManager *manager, 65 MediaEngineInterface* media_engine, 66 DataEngineInterface* data_media_engine, 67 DeviceManagerInterface* device_manager) 68 : jid_(jid), 69 session_manager_(manager), 70 focus_call_(NULL), 71 channel_manager_(new ChannelManager( 72 media_engine, data_media_engine, 73 device_manager, new CaptureManager(), 74 session_manager_->worker_thread())), 75 desc_factory_(channel_manager_, 76 session_manager_->transport_desc_factory()), 77 multisession_enabled_(false) { 78 Construct(); 79 } 80 81 void MediaSessionClient::Construct() { 82 // Register ourselves as the handler of audio and video sessions. 83 session_manager_->AddClient(NS_JINGLE_RTP, this); 84 // Forward device notifications. 85 SignalDevicesChange.repeat(channel_manager_->SignalDevicesChange); 86 // Bring up the channel manager. 87 // In previous versions of ChannelManager, this was done automatically 88 // in the constructor. 89 channel_manager_->Init(); 90 } 91 92 MediaSessionClient::~MediaSessionClient() { 93 // Destroy all calls 94 std::map<uint32, Call *>::iterator it; 95 while (calls_.begin() != calls_.end()) { 96 std::map<uint32, Call *>::iterator it = calls_.begin(); 97 DestroyCall((*it).second); 98 } 99 100 // Delete channel manager. This will wait for the channels to exit 101 delete channel_manager_; 102 103 // Remove ourselves from the client map. 104 session_manager_->RemoveClient(NS_JINGLE_RTP); 105 } 106 107 Call *MediaSessionClient::CreateCall() { 108 Call *call = new Call(this); 109 calls_[call->id()] = call; 110 SignalCallCreate(call); 111 return call; 112 } 113 114 void MediaSessionClient::OnSessionCreate(Session *session, 115 bool received_initiate) { 116 if (received_initiate) { 117 session->SignalState.connect(this, &MediaSessionClient::OnSessionState); 118 } 119 } 120 121 void MediaSessionClient::OnSessionState(BaseSession* base_session, 122 BaseSession::State state) { 123 // MediaSessionClient can only be used with a Session*, so it's 124 // safe to cast here. 125 Session* session = static_cast<Session*>(base_session); 126 127 if (state == Session::STATE_RECEIVEDINITIATE) { 128 // The creation of the call must happen after the session has 129 // processed the initiate message because we need the 130 // remote_description to know what content names to use in the 131 // call. 132 133 // If our accept would have no codecs, then we must reject this call. 134 const SessionDescription* offer = session->remote_description(); 135 const SessionDescription* accept = CreateAnswer(offer, CallOptions()); 136 const ContentInfo* audio_content = GetFirstAudioContent(accept); 137 bool audio_rejected = (!audio_content) ? true : audio_content->rejected; 138 const AudioContentDescription* audio_desc = (!audio_content) ? NULL : 139 static_cast<const AudioContentDescription*>(audio_content->description); 140 141 // For some reason, we need a call even if we reject. So, either find a 142 // matching call or create a new one. 143 // The matching of existing calls is used to support the multi-session mode 144 // required for p2p handoffs: ie. once a MUC call is established, a new 145 // session may be established for the same call but is direct between the 146 // clients. To indicate that this is the case, the initiator of the incoming 147 // session is set to be the same as the remote name of the MUC for the 148 // existing session, thus the client can know that this is a new session for 149 // the existing call, rather than a whole new call. 150 Call* call = NULL; 151 if (multisession_enabled_) { 152 call = FindCallByRemoteName(session->initiator_name()); 153 } 154 155 if (call == NULL) { 156 // Could not find a matching call, so create a new one. 157 call = CreateCall(); 158 } 159 160 session_map_[session->id()] = call; 161 call->IncomingSession(session, offer); 162 163 if (audio_rejected || !audio_desc || audio_desc->codecs().size() == 0) { 164 session->Reject(STR_TERMINATE_INCOMPATIBLE_PARAMETERS); 165 } 166 delete accept; 167 } 168 } 169 170 void MediaSessionClient::DestroyCall(Call *call) { 171 // Change focus away, signal destruction 172 173 if (call == focus_call_) 174 SetFocus(NULL); 175 SignalCallDestroy(call); 176 177 // Remove it from calls_ map and delete 178 179 std::map<uint32, Call *>::iterator it = calls_.find(call->id()); 180 if (it != calls_.end()) 181 calls_.erase(it); 182 183 delete call; 184 } 185 186 void MediaSessionClient::OnSessionDestroy(Session *session) { 187 // Find the call this session is in, remove it 188 SessionMap::iterator it = session_map_.find(session->id()); 189 ASSERT(it != session_map_.end()); 190 if (it != session_map_.end()) { 191 Call *call = (*it).second; 192 session_map_.erase(it); 193 call->RemoveSession(session); 194 } 195 } 196 197 Call *MediaSessionClient::GetFocus() { 198 return focus_call_; 199 } 200 201 void MediaSessionClient::SetFocus(Call *call) { 202 Call *old_focus_call = focus_call_; 203 if (focus_call_ != call) { 204 if (focus_call_ != NULL) 205 focus_call_->EnableChannels(false); 206 focus_call_ = call; 207 if (focus_call_ != NULL) 208 focus_call_->EnableChannels(true); 209 SignalFocus(focus_call_, old_focus_call); 210 } 211 } 212 213 void MediaSessionClient::JoinCalls(Call *call_to_join, Call *call) { 214 // Move all sessions from call to call_to_join, delete call. 215 // If call_to_join has focus, added sessions should have enabled channels. 216 217 if (focus_call_ == call) 218 SetFocus(NULL); 219 call_to_join->Join(call, focus_call_ == call_to_join); 220 DestroyCall(call); 221 } 222 223 Session *MediaSessionClient::CreateSession(Call *call) { 224 std::string id; 225 return CreateSession(id, call); 226 } 227 228 Session *MediaSessionClient::CreateSession(const std::string& id, Call* call) { 229 const std::string& type = NS_JINGLE_RTP; 230 Session *session = session_manager_->CreateSession(id, jid().Str(), type); 231 session_map_[session->id()] = call; 232 return session; 233 } 234 235 Call *MediaSessionClient::FindCallByRemoteName(const std::string &remote_name) { 236 SessionMap::const_iterator call; 237 for (call = session_map_.begin(); call != session_map_.end(); ++call) { 238 std::vector<Session *> sessions = call->second->sessions(); 239 std::vector<Session *>::const_iterator session; 240 for (session = sessions.begin(); session != sessions.end(); ++session) { 241 if (remote_name == (*session)->remote_name()) { 242 return call->second; 243 } 244 } 245 } 246 247 return NULL; 248 } 249 250 // TODO(pthatcher): Move all of the parsing and writing functions into 251 // mediamessages.cc, with unit tests. 252 bool ParseGingleAudioCodec(const buzz::XmlElement* element, AudioCodec* out) { 253 int id = GetXmlAttr(element, QN_ID, -1); 254 if (id < 0) 255 return false; 256 257 std::string name = GetXmlAttr(element, QN_NAME, buzz::STR_EMPTY); 258 int clockrate = GetXmlAttr(element, QN_CLOCKRATE, 0); 259 int bitrate = GetXmlAttr(element, QN_BITRATE, 0); 260 int channels = GetXmlAttr(element, QN_CHANNELS, 1); 261 *out = AudioCodec(id, name, clockrate, bitrate, channels, 0); 262 return true; 263 } 264 265 bool ParseGingleVideoCodec(const buzz::XmlElement* element, VideoCodec* out) { 266 int id = GetXmlAttr(element, QN_ID, -1); 267 if (id < 0) 268 return false; 269 270 std::string name = GetXmlAttr(element, QN_NAME, buzz::STR_EMPTY); 271 int width = GetXmlAttr(element, QN_WIDTH, 0); 272 int height = GetXmlAttr(element, QN_HEIGHT, 0); 273 int framerate = GetXmlAttr(element, QN_FRAMERATE, 0); 274 275 *out = VideoCodec(id, name, width, height, framerate, 0); 276 return true; 277 } 278 279 // Parses an ssrc string as a legacy stream. If it fails, returns 280 // false and fills an error message. 281 bool ParseSsrcAsLegacyStream(const std::string& ssrc_str, 282 std::vector<StreamParams>* streams, 283 ParseError* error) { 284 if (!ssrc_str.empty()) { 285 uint32 ssrc; 286 if (!rtc::FromString(ssrc_str, &ssrc)) { 287 return BadParse("Missing or invalid ssrc.", error); 288 } 289 290 streams->push_back(StreamParams::CreateLegacy(ssrc)); 291 } 292 return true; 293 } 294 295 void ParseGingleSsrc(const buzz::XmlElement* parent_elem, 296 const buzz::QName& name, 297 MediaContentDescription* media) { 298 const buzz::XmlElement* ssrc_elem = parent_elem->FirstNamed(name); 299 if (ssrc_elem) { 300 ParseError error; 301 ParseSsrcAsLegacyStream( 302 ssrc_elem->BodyText(), &(media->mutable_streams()), &error); 303 } 304 } 305 306 bool ParseCryptoParams(const buzz::XmlElement* element, 307 CryptoParams* out, 308 ParseError* error) { 309 if (!element->HasAttr(QN_CRYPTO_SUITE)) { 310 return BadParse("crypto: crypto-suite attribute missing ", error); 311 } else if (!element->HasAttr(QN_CRYPTO_KEY_PARAMS)) { 312 return BadParse("crypto: key-params attribute missing ", error); 313 } else if (!element->HasAttr(QN_CRYPTO_TAG)) { 314 return BadParse("crypto: tag attribute missing ", error); 315 } 316 317 const std::string& crypto_suite = element->Attr(QN_CRYPTO_SUITE); 318 const std::string& key_params = element->Attr(QN_CRYPTO_KEY_PARAMS); 319 const int tag = GetXmlAttr(element, QN_CRYPTO_TAG, 0); 320 const std::string& session_params = 321 element->Attr(QN_CRYPTO_SESSION_PARAMS); // Optional. 322 323 *out = CryptoParams(tag, crypto_suite, key_params, session_params); 324 return true; 325 } 326 327 328 // Parse the first encryption element found with a matching 'usage' 329 // element. 330 // <usage/> is specific to Gingle. In Jingle, <crypto/> is already 331 // scoped to a content. 332 // Return false if there was an encryption element and it could not be 333 // parsed. 334 bool ParseGingleEncryption(const buzz::XmlElement* desc, 335 const buzz::QName& usage, 336 MediaContentDescription* media, 337 ParseError* error) { 338 for (const buzz::XmlElement* encryption = desc->FirstNamed(QN_ENCRYPTION); 339 encryption != NULL; 340 encryption = encryption->NextNamed(QN_ENCRYPTION)) { 341 if (encryption->FirstNamed(usage) != NULL) { 342 if (GetXmlAttr(encryption, QN_ENCRYPTION_REQUIRED, false)) { 343 media->set_crypto_required(CT_SDES); 344 } 345 for (const buzz::XmlElement* crypto = encryption->FirstNamed(QN_CRYPTO); 346 crypto != NULL; 347 crypto = crypto->NextNamed(QN_CRYPTO)) { 348 CryptoParams params; 349 if (!ParseCryptoParams(crypto, ¶ms, error)) { 350 return false; 351 } 352 media->AddCrypto(params); 353 } 354 break; 355 } 356 } 357 return true; 358 } 359 360 void ParseBandwidth(const buzz::XmlElement* parent_elem, 361 MediaContentDescription* media) { 362 const buzz::XmlElement* bw_elem = GetXmlChild(parent_elem, LN_BANDWIDTH); 363 int bandwidth_kbps = -1; 364 if (bw_elem && rtc::FromString(bw_elem->BodyText(), &bandwidth_kbps)) { 365 if (bandwidth_kbps >= 0) { 366 media->set_bandwidth(bandwidth_kbps * 1000); 367 } 368 } 369 } 370 371 bool ParseGingleAudioContent(const buzz::XmlElement* content_elem, 372 ContentDescription** content, 373 ParseError* error) { 374 AudioContentDescription* audio = new AudioContentDescription(); 375 376 int preference = kMaxPayloadId; 377 if (content_elem->FirstElement()) { 378 for (const buzz::XmlElement* codec_elem = 379 content_elem->FirstNamed(QN_GINGLE_AUDIO_PAYLOADTYPE); 380 codec_elem != NULL; 381 codec_elem = codec_elem->NextNamed(QN_GINGLE_AUDIO_PAYLOADTYPE)) { 382 AudioCodec codec; 383 if (ParseGingleAudioCodec(codec_elem, &codec)) { 384 codec.preference = preference--; 385 audio->AddCodec(codec); 386 } 387 } 388 } else { 389 // For backward compatibility, we can assume the other client is 390 // an old version of Talk if it has no audio payload types at all. 391 audio->AddCodec(AudioCodec(103, "ISAC", 16000, -1, 1, 1)); 392 audio->AddCodec(AudioCodec(0, "PCMU", 8000, 64000, 1, 0)); 393 } 394 395 ParseGingleSsrc(content_elem, QN_GINGLE_AUDIO_SRCID, audio); 396 397 if (!ParseGingleEncryption(content_elem, QN_GINGLE_AUDIO_CRYPTO_USAGE, 398 audio, error)) { 399 return false; 400 } 401 402 *content = audio; 403 return true; 404 } 405 406 bool ParseGingleVideoContent(const buzz::XmlElement* content_elem, 407 ContentDescription** content, 408 ParseError* error) { 409 VideoContentDescription* video = new VideoContentDescription(); 410 411 int preference = kMaxPayloadId; 412 for (const buzz::XmlElement* codec_elem = 413 content_elem->FirstNamed(QN_GINGLE_VIDEO_PAYLOADTYPE); 414 codec_elem != NULL; 415 codec_elem = codec_elem->NextNamed(QN_GINGLE_VIDEO_PAYLOADTYPE)) { 416 VideoCodec codec; 417 if (ParseGingleVideoCodec(codec_elem, &codec)) { 418 codec.preference = preference--; 419 video->AddCodec(codec); 420 } 421 } 422 423 ParseGingleSsrc(content_elem, QN_GINGLE_VIDEO_SRCID, video); 424 ParseBandwidth(content_elem, video); 425 426 if (!ParseGingleEncryption(content_elem, QN_GINGLE_VIDEO_CRYPTO_USAGE, 427 video, error)) { 428 return false; 429 } 430 431 *content = video; 432 return true; 433 } 434 435 void ParsePayloadTypeParameters(const buzz::XmlElement* element, 436 std::map<std::string, std::string>* paramap) { 437 for (const buzz::XmlElement* param = element->FirstNamed(QN_PARAMETER); 438 param != NULL; param = param->NextNamed(QN_PARAMETER)) { 439 std::string name = GetXmlAttr(param, QN_PAYLOADTYPE_PARAMETER_NAME, 440 buzz::STR_EMPTY); 441 std::string value = GetXmlAttr(param, QN_PAYLOADTYPE_PARAMETER_VALUE, 442 buzz::STR_EMPTY); 443 if (!name.empty() && !value.empty()) { 444 paramap->insert(make_pair(name, value)); 445 } 446 } 447 } 448 449 void ParseFeedbackParams(const buzz::XmlElement* element, 450 FeedbackParams* params) { 451 for (const buzz::XmlElement* param = element->FirstNamed(QN_JINGLE_RTCP_FB); 452 param != NULL; param = param->NextNamed(QN_JINGLE_RTCP_FB)) { 453 std::string type = GetXmlAttr(param, QN_TYPE, buzz::STR_EMPTY); 454 std::string subtype = GetXmlAttr(param, QN_SUBTYPE, buzz::STR_EMPTY); 455 if (!type.empty()) { 456 params->Add(FeedbackParam(type, subtype)); 457 } 458 } 459 } 460 461 void AddFeedbackParams(const FeedbackParams& additional_params, 462 FeedbackParams* params) { 463 for (size_t i = 0; i < additional_params.params().size(); ++i) { 464 params->Add(additional_params.params()[i]); 465 } 466 } 467 468 int FindWithDefault(const std::map<std::string, std::string>& map, 469 const std::string& key, const int def) { 470 std::map<std::string, std::string>::const_iterator iter = map.find(key); 471 return (iter == map.end()) ? def : atoi(iter->second.c_str()); 472 } 473 474 475 // Parse the first encryption element found. 476 // Return false if there was an encryption element and it could not be 477 // parsed. 478 bool ParseJingleEncryption(const buzz::XmlElement* content_elem, 479 MediaContentDescription* media, 480 ParseError* error) { 481 const buzz::XmlElement* encryption = 482 content_elem->FirstNamed(QN_ENCRYPTION); 483 if (encryption == NULL) { 484 return true; 485 } 486 487 if (GetXmlAttr(encryption, QN_ENCRYPTION_REQUIRED, false)) { 488 media->set_crypto_required(CT_SDES); 489 } 490 491 for (const buzz::XmlElement* crypto = encryption->FirstNamed(QN_CRYPTO); 492 crypto != NULL; 493 crypto = crypto->NextNamed(QN_CRYPTO)) { 494 CryptoParams params; 495 if (!ParseCryptoParams(crypto, ¶ms, error)) { 496 return false; 497 } 498 media->AddCrypto(params); 499 } 500 return true; 501 } 502 503 bool ParseJingleAudioCodec(const buzz::XmlElement* elem, AudioCodec* codec) { 504 int id = GetXmlAttr(elem, QN_ID, -1); 505 if (id < 0) 506 return false; 507 508 std::string name = GetXmlAttr(elem, QN_NAME, buzz::STR_EMPTY); 509 int clockrate = GetXmlAttr(elem, QN_CLOCKRATE, 0); 510 int channels = GetXmlAttr(elem, QN_CHANNELS, 1); 511 512 std::map<std::string, std::string> paramap; 513 ParsePayloadTypeParameters(elem, ¶map); 514 int bitrate = FindWithDefault(paramap, PAYLOADTYPE_PARAMETER_BITRATE, 0); 515 516 *codec = AudioCodec(id, name, clockrate, bitrate, channels, 0); 517 ParseFeedbackParams(elem, &codec->feedback_params); 518 return true; 519 } 520 521 bool ParseJingleVideoCodec(const buzz::XmlElement* elem, VideoCodec* codec) { 522 int id = GetXmlAttr(elem, QN_ID, -1); 523 if (id < 0) 524 return false; 525 526 std::string name = GetXmlAttr(elem, QN_NAME, buzz::STR_EMPTY); 527 528 std::map<std::string, std::string> paramap; 529 ParsePayloadTypeParameters(elem, ¶map); 530 int width = FindWithDefault(paramap, PAYLOADTYPE_PARAMETER_WIDTH, 0); 531 int height = FindWithDefault(paramap, PAYLOADTYPE_PARAMETER_HEIGHT, 0); 532 int framerate = FindWithDefault(paramap, PAYLOADTYPE_PARAMETER_FRAMERATE, 0); 533 534 *codec = VideoCodec(id, name, width, height, framerate, 0); 535 codec->params = paramap; 536 ParseFeedbackParams(elem, &codec->feedback_params); 537 return true; 538 } 539 540 bool ParseJingleDataCodec(const buzz::XmlElement* elem, DataCodec* codec) { 541 int id = GetXmlAttr(elem, QN_ID, -1); 542 if (id < 0) 543 return false; 544 545 std::string name = GetXmlAttr(elem, QN_NAME, buzz::STR_EMPTY); 546 547 *codec = DataCodec(id, name, 0); 548 ParseFeedbackParams(elem, &codec->feedback_params); 549 return true; 550 } 551 552 bool ParseJingleStreamsOrLegacySsrc(const buzz::XmlElement* desc_elem, 553 MediaContentDescription* media, 554 ParseError* error) { 555 if (HasJingleStreams(desc_elem)) { 556 if (!ParseJingleStreams(desc_elem, &(media->mutable_streams()), error)) { 557 return false; 558 } 559 } else { 560 const std::string ssrc_str = desc_elem->Attr(QN_SSRC); 561 if (!ParseSsrcAsLegacyStream( 562 ssrc_str, &(media->mutable_streams()), error)) { 563 return false; 564 } 565 } 566 return true; 567 } 568 569 bool ParseJingleAudioContent(const buzz::XmlElement* content_elem, 570 ContentDescription** content, 571 ParseError* error) { 572 rtc::scoped_ptr<AudioContentDescription> audio( 573 new AudioContentDescription()); 574 575 FeedbackParams content_feedback_params; 576 ParseFeedbackParams(content_elem, &content_feedback_params); 577 578 int preference = kMaxPayloadId; 579 for (const buzz::XmlElement* payload_elem = 580 content_elem->FirstNamed(QN_JINGLE_RTP_PAYLOADTYPE); 581 payload_elem != NULL; 582 payload_elem = payload_elem->NextNamed(QN_JINGLE_RTP_PAYLOADTYPE)) { 583 AudioCodec codec; 584 if (ParseJingleAudioCodec(payload_elem, &codec)) { 585 AddFeedbackParams(content_feedback_params, &codec.feedback_params); 586 codec.preference = preference--; 587 audio->AddCodec(codec); 588 } 589 } 590 591 if (!ParseJingleStreamsOrLegacySsrc(content_elem, audio.get(), error)) { 592 return false; 593 } 594 595 if (!ParseJingleEncryption(content_elem, audio.get(), error)) { 596 return false; 597 } 598 599 audio->set_rtcp_mux(content_elem->FirstNamed(QN_JINGLE_RTCP_MUX) != NULL); 600 601 RtpHeaderExtensions hdrexts; 602 if (!ParseJingleRtpHeaderExtensions(content_elem, &hdrexts, error)) { 603 return false; 604 } 605 audio->set_rtp_header_extensions(hdrexts); 606 607 *content = audio.release(); 608 return true; 609 } 610 611 bool ParseJingleVideoContent(const buzz::XmlElement* content_elem, 612 ContentDescription** content, 613 ParseError* error) { 614 rtc::scoped_ptr<VideoContentDescription> video( 615 new VideoContentDescription()); 616 617 FeedbackParams content_feedback_params; 618 ParseFeedbackParams(content_elem, &content_feedback_params); 619 620 int preference = kMaxPayloadId; 621 for (const buzz::XmlElement* payload_elem = 622 content_elem->FirstNamed(QN_JINGLE_RTP_PAYLOADTYPE); 623 payload_elem != NULL; 624 payload_elem = payload_elem->NextNamed(QN_JINGLE_RTP_PAYLOADTYPE)) { 625 VideoCodec codec; 626 if (ParseJingleVideoCodec(payload_elem, &codec)) { 627 AddFeedbackParams(content_feedback_params, &codec.feedback_params); 628 codec.preference = preference--; 629 video->AddCodec(codec); 630 } 631 } 632 633 if (!ParseJingleStreamsOrLegacySsrc(content_elem, video.get(), error)) { 634 return false; 635 } 636 ParseBandwidth(content_elem, video.get()); 637 638 if (!ParseJingleEncryption(content_elem, video.get(), error)) { 639 return false; 640 } 641 642 video->set_rtcp_mux(content_elem->FirstNamed(QN_JINGLE_RTCP_MUX) != NULL); 643 644 RtpHeaderExtensions hdrexts; 645 if (!ParseJingleRtpHeaderExtensions(content_elem, &hdrexts, error)) { 646 return false; 647 } 648 video->set_rtp_header_extensions(hdrexts); 649 650 *content = video.release(); 651 return true; 652 } 653 654 bool ParseJingleSctpDataContent(const buzz::XmlElement* content_elem, 655 ContentDescription** content, 656 ParseError* error) { 657 rtc::scoped_ptr<DataContentDescription> data( 658 new DataContentDescription()); 659 data->set_protocol(kMediaProtocolSctp); 660 661 for (const buzz::XmlElement* stream_elem = 662 content_elem->FirstNamed(QN_JINGLE_DRAFT_SCTP_STREAM); 663 stream_elem != NULL; 664 stream_elem = stream_elem->NextNamed(QN_JINGLE_DRAFT_SCTP_STREAM)) { 665 StreamParams stream; 666 stream.groupid = stream_elem->Attr(QN_NICK); 667 stream.id = stream_elem->Attr(QN_NAME); 668 uint32 sid; 669 if (!rtc::FromString(stream_elem->Attr(QN_SID), &sid)) { 670 return BadParse("Missing or invalid sid.", error); 671 } 672 if (sid > kMaxSctpSid) { 673 return BadParse("SID is greater than max value.", error); 674 } 675 676 stream.ssrcs.push_back(sid); 677 data->mutable_streams().push_back(stream); 678 } 679 680 *content = data.release(); 681 return true; 682 } 683 684 bool ParseJingleRtpDataContent(const buzz::XmlElement* content_elem, 685 ContentDescription** content, 686 ParseError* error) { 687 DataContentDescription* data = new DataContentDescription(); 688 689 FeedbackParams content_feedback_params; 690 ParseFeedbackParams(content_elem, &content_feedback_params); 691 692 int preference = kMaxPayloadId; 693 for (const buzz::XmlElement* payload_elem = 694 content_elem->FirstNamed(QN_JINGLE_RTP_PAYLOADTYPE); 695 payload_elem != NULL; 696 payload_elem = payload_elem->NextNamed(QN_JINGLE_RTP_PAYLOADTYPE)) { 697 DataCodec codec; 698 if (ParseJingleDataCodec(payload_elem, &codec)) { 699 AddFeedbackParams(content_feedback_params, &codec.feedback_params); 700 codec.preference = preference--; 701 data->AddCodec(codec); 702 } 703 } 704 705 if (!ParseJingleStreamsOrLegacySsrc(content_elem, data, error)) { 706 return false; 707 } 708 ParseBandwidth(content_elem, data); 709 710 if (!ParseJingleEncryption(content_elem, data, error)) { 711 return false; 712 } 713 714 data->set_rtcp_mux(content_elem->FirstNamed(QN_JINGLE_RTCP_MUX) != NULL); 715 716 *content = data; 717 return true; 718 } 719 720 bool MediaSessionClient::ParseContent(SignalingProtocol protocol, 721 const buzz::XmlElement* content_elem, 722 ContentDescription** content, 723 ParseError* error) { 724 if (protocol == PROTOCOL_GINGLE) { 725 const std::string& content_type = content_elem->Name().Namespace(); 726 if (NS_GINGLE_AUDIO == content_type) { 727 return ParseGingleAudioContent(content_elem, content, error); 728 } else if (NS_GINGLE_VIDEO == content_type) { 729 return ParseGingleVideoContent(content_elem, content, error); 730 } else { 731 return BadParse("Unknown content type: " + content_type, error); 732 } 733 } else { 734 const std::string& content_type = content_elem->Name().Namespace(); 735 // We use the XMLNS of the <description> element to determine if 736 // it's RTP or SCTP. 737 if (content_type == NS_JINGLE_DRAFT_SCTP) { 738 return ParseJingleSctpDataContent(content_elem, content, error); 739 } 740 741 std::string media; 742 if (!RequireXmlAttr(content_elem, QN_JINGLE_CONTENT_MEDIA, &media, error)) 743 return false; 744 745 if (media == JINGLE_CONTENT_MEDIA_AUDIO) { 746 return ParseJingleAudioContent(content_elem, content, error); 747 } else if (media == JINGLE_CONTENT_MEDIA_VIDEO) { 748 return ParseJingleVideoContent(content_elem, content, error); 749 } else if (media == JINGLE_CONTENT_MEDIA_DATA) { 750 return ParseJingleRtpDataContent(content_elem, content, error); 751 } else { 752 return BadParse("Unknown media: " + media, error); 753 } 754 } 755 } 756 757 buzz::XmlElement* CreateGingleAudioCodecElem(const AudioCodec& codec) { 758 buzz::XmlElement* payload_type = 759 new buzz::XmlElement(QN_GINGLE_AUDIO_PAYLOADTYPE, true); 760 AddXmlAttr(payload_type, QN_ID, codec.id); 761 payload_type->AddAttr(QN_NAME, codec.name); 762 if (codec.clockrate > 0) 763 AddXmlAttr(payload_type, QN_CLOCKRATE, codec.clockrate); 764 if (codec.bitrate > 0) 765 AddXmlAttr(payload_type, QN_BITRATE, codec.bitrate); 766 if (codec.channels > 1) 767 AddXmlAttr(payload_type, QN_CHANNELS, codec.channels); 768 return payload_type; 769 } 770 771 buzz::XmlElement* CreateGingleVideoCodecElem(const VideoCodec& codec) { 772 buzz::XmlElement* payload_type = 773 new buzz::XmlElement(QN_GINGLE_VIDEO_PAYLOADTYPE, true); 774 AddXmlAttr(payload_type, QN_ID, codec.id); 775 payload_type->AddAttr(QN_NAME, codec.name); 776 AddXmlAttr(payload_type, QN_WIDTH, codec.width); 777 AddXmlAttr(payload_type, QN_HEIGHT, codec.height); 778 AddXmlAttr(payload_type, QN_FRAMERATE, codec.framerate); 779 return payload_type; 780 } 781 782 buzz::XmlElement* CreateGingleSsrcElem(const buzz::QName& name, uint32 ssrc) { 783 buzz::XmlElement* elem = new buzz::XmlElement(name, true); 784 if (ssrc) { 785 SetXmlBody(elem, ssrc); 786 } 787 return elem; 788 } 789 790 buzz::XmlElement* CreateBandwidthElem(const buzz::QName& name, int bps) { 791 int kbps = bps / 1000; 792 buzz::XmlElement* elem = new buzz::XmlElement(name); 793 elem->AddAttr(buzz::QN_TYPE, "AS"); 794 SetXmlBody(elem, kbps); 795 return elem; 796 } 797 798 // For Jingle, usage_qname is empty. 799 buzz::XmlElement* CreateJingleEncryptionElem(const CryptoParamsVec& cryptos, 800 bool required) { 801 buzz::XmlElement* encryption_elem = new buzz::XmlElement(QN_ENCRYPTION); 802 803 if (required) { 804 encryption_elem->SetAttr(QN_ENCRYPTION_REQUIRED, "true"); 805 } 806 807 for (CryptoParamsVec::const_iterator i = cryptos.begin(); 808 i != cryptos.end(); 809 ++i) { 810 buzz::XmlElement* crypto_elem = new buzz::XmlElement(QN_CRYPTO); 811 812 AddXmlAttr(crypto_elem, QN_CRYPTO_TAG, i->tag); 813 crypto_elem->AddAttr(QN_CRYPTO_SUITE, i->cipher_suite); 814 crypto_elem->AddAttr(QN_CRYPTO_KEY_PARAMS, i->key_params); 815 if (!i->session_params.empty()) { 816 crypto_elem->AddAttr(QN_CRYPTO_SESSION_PARAMS, i->session_params); 817 } 818 encryption_elem->AddElement(crypto_elem); 819 } 820 return encryption_elem; 821 } 822 823 buzz::XmlElement* CreateGingleEncryptionElem(const CryptoParamsVec& cryptos, 824 const buzz::QName& usage_qname, 825 bool required) { 826 buzz::XmlElement* encryption_elem = 827 CreateJingleEncryptionElem(cryptos, required); 828 829 if (required) { 830 encryption_elem->SetAttr(QN_ENCRYPTION_REQUIRED, "true"); 831 } 832 833 buzz::XmlElement* usage_elem = new buzz::XmlElement(usage_qname); 834 encryption_elem->AddElement(usage_elem); 835 836 return encryption_elem; 837 } 838 839 buzz::XmlElement* CreateGingleAudioContentElem( 840 const AudioContentDescription* audio, 841 bool crypto_required) { 842 buzz::XmlElement* elem = 843 new buzz::XmlElement(QN_GINGLE_AUDIO_CONTENT, true); 844 845 for (AudioCodecs::const_iterator codec = audio->codecs().begin(); 846 codec != audio->codecs().end(); ++codec) { 847 elem->AddElement(CreateGingleAudioCodecElem(*codec)); 848 } 849 if (audio->has_ssrcs()) { 850 elem->AddElement(CreateGingleSsrcElem( 851 QN_GINGLE_AUDIO_SRCID, audio->first_ssrc())); 852 } 853 854 const CryptoParamsVec& cryptos = audio->cryptos(); 855 if (!cryptos.empty()) { 856 elem->AddElement(CreateGingleEncryptionElem(cryptos, 857 QN_GINGLE_AUDIO_CRYPTO_USAGE, 858 crypto_required)); 859 } 860 return elem; 861 } 862 863 buzz::XmlElement* CreateGingleVideoContentElem( 864 const VideoContentDescription* video, 865 bool crypto_required) { 866 buzz::XmlElement* elem = 867 new buzz::XmlElement(QN_GINGLE_VIDEO_CONTENT, true); 868 869 for (VideoCodecs::const_iterator codec = video->codecs().begin(); 870 codec != video->codecs().end(); ++codec) { 871 elem->AddElement(CreateGingleVideoCodecElem(*codec)); 872 } 873 if (video->has_ssrcs()) { 874 elem->AddElement(CreateGingleSsrcElem( 875 QN_GINGLE_VIDEO_SRCID, video->first_ssrc())); 876 } 877 if (video->bandwidth() != kAutoBandwidth) { 878 elem->AddElement(CreateBandwidthElem(QN_GINGLE_VIDEO_BANDWIDTH, 879 video->bandwidth())); 880 } 881 882 const CryptoParamsVec& cryptos = video->cryptos(); 883 if (!cryptos.empty()) { 884 elem->AddElement(CreateGingleEncryptionElem(cryptos, 885 QN_GINGLE_VIDEO_CRYPTO_USAGE, 886 crypto_required)); 887 } 888 889 return elem; 890 } 891 892 template <class T> 893 buzz::XmlElement* CreatePayloadTypeParameterElem( 894 const std::string& name, T value) { 895 buzz::XmlElement* elem = new buzz::XmlElement(QN_PARAMETER); 896 897 elem->AddAttr(QN_PAYLOADTYPE_PARAMETER_NAME, name); 898 AddXmlAttr(elem, QN_PAYLOADTYPE_PARAMETER_VALUE, value); 899 900 return elem; 901 } 902 903 void AddRtcpFeedbackElem(buzz::XmlElement* elem, 904 const FeedbackParams& feedback_params) { 905 std::vector<FeedbackParam>::const_iterator it; 906 for (it = feedback_params.params().begin(); 907 it != feedback_params.params().end(); ++it) { 908 buzz::XmlElement* fb_elem = new buzz::XmlElement(QN_JINGLE_RTCP_FB); 909 fb_elem->AddAttr(QN_TYPE, it->id()); 910 fb_elem->AddAttr(QN_SUBTYPE, it->param()); 911 elem->AddElement(fb_elem); 912 } 913 } 914 915 buzz::XmlElement* CreateJingleAudioCodecElem(const AudioCodec& codec) { 916 buzz::XmlElement* elem = new buzz::XmlElement(QN_JINGLE_RTP_PAYLOADTYPE); 917 918 AddXmlAttr(elem, QN_ID, codec.id); 919 elem->AddAttr(QN_NAME, codec.name); 920 if (codec.clockrate > 0) { 921 AddXmlAttr(elem, QN_CLOCKRATE, codec.clockrate); 922 } 923 if (codec.bitrate > 0) { 924 elem->AddElement(CreatePayloadTypeParameterElem( 925 PAYLOADTYPE_PARAMETER_BITRATE, codec.bitrate)); 926 } 927 if (codec.channels > 1) { 928 AddXmlAttr(elem, QN_CHANNELS, codec.channels); 929 } 930 931 AddRtcpFeedbackElem(elem, codec.feedback_params); 932 933 return elem; 934 } 935 936 buzz::XmlElement* CreateJingleVideoCodecElem(const VideoCodec& codec) { 937 buzz::XmlElement* elem = new buzz::XmlElement(QN_JINGLE_RTP_PAYLOADTYPE); 938 939 AddXmlAttr(elem, QN_ID, codec.id); 940 elem->AddAttr(QN_NAME, codec.name); 941 elem->AddElement(CreatePayloadTypeParameterElem( 942 PAYLOADTYPE_PARAMETER_WIDTH, codec.width)); 943 elem->AddElement(CreatePayloadTypeParameterElem( 944 PAYLOADTYPE_PARAMETER_HEIGHT, codec.height)); 945 elem->AddElement(CreatePayloadTypeParameterElem( 946 PAYLOADTYPE_PARAMETER_FRAMERATE, codec.framerate)); 947 948 AddRtcpFeedbackElem(elem, codec.feedback_params); 949 950 CodecParameterMap::const_iterator param_iter; 951 for (param_iter = codec.params.begin(); param_iter != codec.params.end(); 952 ++param_iter) { 953 elem->AddElement(CreatePayloadTypeParameterElem(param_iter->first, 954 param_iter->second)); 955 } 956 957 return elem; 958 } 959 960 buzz::XmlElement* CreateJingleDataCodecElem(const DataCodec& codec) { 961 buzz::XmlElement* elem = new buzz::XmlElement(QN_JINGLE_RTP_PAYLOADTYPE); 962 963 AddXmlAttr(elem, QN_ID, codec.id); 964 elem->AddAttr(QN_NAME, codec.name); 965 966 AddRtcpFeedbackElem(elem, codec.feedback_params); 967 968 return elem; 969 } 970 971 void WriteLegacyJingleSsrc(const MediaContentDescription* media, 972 buzz::XmlElement* elem) { 973 if (media->has_ssrcs()) { 974 AddXmlAttr(elem, QN_SSRC, media->first_ssrc()); 975 } 976 } 977 978 void WriteJingleStreamsOrLegacySsrc(const MediaContentDescription* media, 979 buzz::XmlElement* desc_elem) { 980 if (!media->multistream()) { 981 WriteLegacyJingleSsrc(media, desc_elem); 982 } else { 983 WriteJingleStreams(media->streams(), desc_elem); 984 } 985 } 986 987 buzz::XmlElement* CreateJingleAudioContentElem( 988 const AudioContentDescription* audio, bool crypto_required) { 989 buzz::XmlElement* elem = 990 new buzz::XmlElement(QN_JINGLE_RTP_CONTENT, true); 991 992 elem->SetAttr(QN_JINGLE_CONTENT_MEDIA, JINGLE_CONTENT_MEDIA_AUDIO); 993 WriteJingleStreamsOrLegacySsrc(audio, elem); 994 995 for (AudioCodecs::const_iterator codec = audio->codecs().begin(); 996 codec != audio->codecs().end(); ++codec) { 997 elem->AddElement(CreateJingleAudioCodecElem(*codec)); 998 } 999 1000 const CryptoParamsVec& cryptos = audio->cryptos(); 1001 if (!cryptos.empty()) { 1002 elem->AddElement(CreateJingleEncryptionElem(cryptos, crypto_required)); 1003 } 1004 1005 if (audio->rtcp_mux()) { 1006 elem->AddElement(new buzz::XmlElement(QN_JINGLE_RTCP_MUX)); 1007 } 1008 1009 WriteJingleRtpHeaderExtensions(audio->rtp_header_extensions(), elem); 1010 1011 return elem; 1012 } 1013 1014 buzz::XmlElement* CreateJingleVideoContentElem( 1015 const VideoContentDescription* video, bool crypto_required) { 1016 buzz::XmlElement* elem = 1017 new buzz::XmlElement(QN_JINGLE_RTP_CONTENT, true); 1018 1019 elem->SetAttr(QN_JINGLE_CONTENT_MEDIA, JINGLE_CONTENT_MEDIA_VIDEO); 1020 WriteJingleStreamsOrLegacySsrc(video, elem); 1021 1022 for (VideoCodecs::const_iterator codec = video->codecs().begin(); 1023 codec != video->codecs().end(); ++codec) { 1024 elem->AddElement(CreateJingleVideoCodecElem(*codec)); 1025 } 1026 1027 const CryptoParamsVec& cryptos = video->cryptos(); 1028 if (!cryptos.empty()) { 1029 elem->AddElement(CreateJingleEncryptionElem(cryptos, crypto_required)); 1030 } 1031 1032 if (video->rtcp_mux()) { 1033 elem->AddElement(new buzz::XmlElement(QN_JINGLE_RTCP_MUX)); 1034 } 1035 1036 if (video->bandwidth() != kAutoBandwidth) { 1037 elem->AddElement(CreateBandwidthElem(QN_JINGLE_RTP_BANDWIDTH, 1038 video->bandwidth())); 1039 } 1040 1041 WriteJingleRtpHeaderExtensions(video->rtp_header_extensions(), elem); 1042 1043 return elem; 1044 } 1045 1046 buzz::XmlElement* CreateJingleSctpDataContentElem( 1047 const DataContentDescription* data) { 1048 buzz::XmlElement* content_elem = 1049 new buzz::XmlElement(QN_JINGLE_DRAFT_SCTP_CONTENT, true); 1050 for (std::vector<StreamParams>::const_iterator 1051 stream = data->streams().begin(); 1052 stream != data->streams().end(); ++stream) { 1053 buzz::XmlElement* stream_elem = 1054 new buzz::XmlElement(QN_JINGLE_DRAFT_SCTP_STREAM, false); 1055 AddXmlAttrIfNonEmpty(stream_elem, QN_NICK, stream->groupid); 1056 AddXmlAttrIfNonEmpty(stream_elem, QN_NAME, stream->id); 1057 if (!stream->ssrcs.empty()) { 1058 AddXmlAttr(stream_elem, QN_SID, stream->ssrcs[0]); 1059 } 1060 content_elem->AddElement(stream_elem); 1061 } 1062 return content_elem;; 1063 } 1064 1065 buzz::XmlElement* CreateJingleRtpDataContentElem( 1066 const DataContentDescription* data, bool crypto_required) { 1067 1068 buzz::XmlElement* elem = 1069 new buzz::XmlElement(QN_JINGLE_RTP_CONTENT, true); 1070 1071 elem->SetAttr(QN_JINGLE_CONTENT_MEDIA, JINGLE_CONTENT_MEDIA_DATA); 1072 WriteJingleStreamsOrLegacySsrc(data, elem); 1073 1074 for (DataCodecs::const_iterator codec = data->codecs().begin(); 1075 codec != data->codecs().end(); ++codec) { 1076 elem->AddElement(CreateJingleDataCodecElem(*codec)); 1077 } 1078 1079 const CryptoParamsVec& cryptos = data->cryptos(); 1080 if (!cryptos.empty()) { 1081 elem->AddElement(CreateJingleEncryptionElem(cryptos, crypto_required)); 1082 } 1083 1084 if (data->rtcp_mux()) { 1085 elem->AddElement(new buzz::XmlElement(QN_JINGLE_RTCP_MUX)); 1086 } 1087 1088 if (data->bandwidth() != kAutoBandwidth) { 1089 elem->AddElement(CreateBandwidthElem(QN_JINGLE_RTP_BANDWIDTH, 1090 data->bandwidth())); 1091 } 1092 1093 return elem; 1094 } 1095 1096 bool IsSctp(const DataContentDescription* data) { 1097 return (data->protocol() == kMediaProtocolSctp || 1098 data->protocol() == kMediaProtocolDtlsSctp); 1099 } 1100 1101 buzz::XmlElement* CreateJingleDataContentElem( 1102 const DataContentDescription* data, bool crypto_required) { 1103 if (IsSctp(data)) { 1104 return CreateJingleSctpDataContentElem(data); 1105 } else { 1106 return CreateJingleRtpDataContentElem(data, crypto_required); 1107 } 1108 } 1109 1110 bool MediaSessionClient::IsWritable(SignalingProtocol protocol, 1111 const ContentDescription* content) { 1112 const MediaContentDescription* media = 1113 static_cast<const MediaContentDescription*>(content); 1114 if (protocol == PROTOCOL_GINGLE && 1115 media->type() == MEDIA_TYPE_DATA) { 1116 return false; 1117 } 1118 return true; 1119 } 1120 1121 bool MediaSessionClient::WriteContent(SignalingProtocol protocol, 1122 const ContentDescription* content, 1123 buzz::XmlElement** elem, 1124 WriteError* error) { 1125 const MediaContentDescription* media = 1126 static_cast<const MediaContentDescription*>(content); 1127 bool crypto_required = secure() == SEC_REQUIRED; 1128 1129 if (media->type() == MEDIA_TYPE_AUDIO) { 1130 const AudioContentDescription* audio = 1131 static_cast<const AudioContentDescription*>(media); 1132 if (protocol == PROTOCOL_GINGLE) { 1133 *elem = CreateGingleAudioContentElem(audio, crypto_required); 1134 } else { 1135 *elem = CreateJingleAudioContentElem(audio, crypto_required); 1136 } 1137 } else if (media->type() == MEDIA_TYPE_VIDEO) { 1138 const VideoContentDescription* video = 1139 static_cast<const VideoContentDescription*>(media); 1140 if (protocol == PROTOCOL_GINGLE) { 1141 *elem = CreateGingleVideoContentElem(video, crypto_required); 1142 } else { 1143 *elem = CreateJingleVideoContentElem(video, crypto_required); 1144 } 1145 } else if (media->type() == MEDIA_TYPE_DATA) { 1146 const DataContentDescription* data = 1147 static_cast<const DataContentDescription*>(media); 1148 if (protocol == PROTOCOL_GINGLE) { 1149 return BadWrite("Data channel not supported with Gingle.", error); 1150 } else { 1151 *elem = CreateJingleDataContentElem(data, crypto_required); 1152 } 1153 } else { 1154 return BadWrite("Unknown content type: " + 1155 rtc::ToString<int>(media->type()), error); 1156 } 1157 1158 return true; 1159 } 1160 1161 } // namespace cricket 1162