| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2013 The WebRTC project authors. All Rights Reserved. | 2 * Copyright 2013 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 | 23 |
| 24 namespace webrtc { | 24 namespace webrtc { |
| 25 namespace { | 25 namespace { |
| 26 static const char kFailedDueToIdentityFailed[] = | 26 static const char kFailedDueToIdentityFailed[] = |
| 27 " failed because DTLS identity request failed"; | 27 " failed because DTLS identity request failed"; |
| 28 static const char kFailedDueToSessionShutdown[] = | 28 static const char kFailedDueToSessionShutdown[] = |
| 29 " failed because the session was shut down"; | 29 " failed because the session was shut down"; |
| 30 | 30 |
| 31 static const uint64_t kInitSessionVersion = 2; | 31 static const uint64_t kInitSessionVersion = 2; |
| 32 | 32 |
| 33 static bool CompareSenderOptions(const cricket::SenderOptions& sender1, | 33 static bool CompareStream(const MediaSessionOptions::Stream& stream1, |
| 34 const cricket::SenderOptions& sender2) { | 34 const MediaSessionOptions::Stream& stream2) { |
| 35 return sender1.track_id < sender2.track_id; | 35 return stream1.id < stream2.id; |
| 36 } | 36 } |
| 37 | 37 |
| 38 static bool SameId(const cricket::SenderOptions& sender1, | 38 static bool SameId(const MediaSessionOptions::Stream& stream1, |
| 39 const cricket::SenderOptions& sender2) { | 39 const MediaSessionOptions::Stream& stream2) { |
| 40 return sender1.track_id == sender2.track_id; | 40 return stream1.id == stream2.id; |
| 41 } | 41 } |
| 42 | 42 |
| 43 // Check that each sender has a unique ID. | 43 // Checks if each Stream within the |streams| has unique id. |
| 44 static bool ValidMediaSessionOptions( | 44 static bool ValidStreams(const MediaSessionOptions::Streams& streams) { |
| 45 const cricket::MediaSessionOptions& session_options) { | 45 MediaSessionOptions::Streams sorted_streams = streams; |
| 46 std::vector<cricket::SenderOptions> sorted_senders; | 46 std::sort(sorted_streams.begin(), sorted_streams.end(), CompareStream); |
| 47 for (const cricket::MediaDescriptionOptions& media_description_options : | 47 MediaSessionOptions::Streams::iterator it = |
| 48 session_options.media_description_options) { | 48 std::adjacent_find(sorted_streams.begin(), sorted_streams.end(), |
| 49 sorted_senders.insert(sorted_senders.end(), | 49 SameId); |
| 50 media_description_options.sender_options.begin(), | 50 return it == sorted_streams.end(); |
| 51 media_description_options.sender_options.end()); | |
| 52 } | |
| 53 std::sort(sorted_senders.begin(), sorted_senders.end(), CompareSenderOptions); | |
| 54 std::vector<cricket::SenderOptions>::iterator it = | |
| 55 std::adjacent_find(sorted_senders.begin(), sorted_senders.end(), SameId); | |
| 56 return it == sorted_senders.end(); | |
| 57 } | 51 } |
| 58 | 52 |
| 59 enum { | 53 enum { |
| 60 MSG_CREATE_SESSIONDESCRIPTION_SUCCESS, | 54 MSG_CREATE_SESSIONDESCRIPTION_SUCCESS, |
| 61 MSG_CREATE_SESSIONDESCRIPTION_FAILED, | 55 MSG_CREATE_SESSIONDESCRIPTION_FAILED, |
| 62 MSG_USE_CONSTRUCTOR_CERTIFICATE | 56 MSG_USE_CONSTRUCTOR_CERTIFICATE |
| 63 }; | 57 }; |
| 64 | 58 |
| 65 struct CreateSessionDescriptionMsg : public rtc::MessageData { | 59 struct CreateSessionDescriptionMsg : public rtc::MessageData { |
| 66 explicit CreateSessionDescriptionMsg( | 60 explicit CreateSessionDescriptionMsg( |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 127 // RFC 4566 suggested a Network Time Protocol (NTP) format timestamp | 121 // RFC 4566 suggested a Network Time Protocol (NTP) format timestamp |
| 128 // as the session id and session version. To simplify, it should be fine | 122 // as the session id and session version. To simplify, it should be fine |
| 129 // to just use a random number as session id and start version from | 123 // to just use a random number as session id and start version from |
| 130 // |kInitSessionVersion|. | 124 // |kInitSessionVersion|. |
| 131 session_version_(kInitSessionVersion), | 125 session_version_(kInitSessionVersion), |
| 132 cert_generator_(std::move(cert_generator)), | 126 cert_generator_(std::move(cert_generator)), |
| 133 session_(session), | 127 session_(session), |
| 134 session_id_(session_id), | 128 session_id_(session_id), |
| 135 certificate_request_state_(CERTIFICATE_NOT_NEEDED) { | 129 certificate_request_state_(CERTIFICATE_NOT_NEEDED) { |
| 136 RTC_DCHECK(signaling_thread_); | 130 RTC_DCHECK(signaling_thread_); |
| 131 session_desc_factory_.set_add_legacy_streams(false); |
| 137 bool dtls_enabled = cert_generator_ || certificate; | 132 bool dtls_enabled = cert_generator_ || certificate; |
| 138 // SRTP-SDES is disabled if DTLS is on. | 133 // SRTP-SDES is disabled if DTLS is on. |
| 139 SetSdesPolicy(dtls_enabled ? cricket::SEC_DISABLED : cricket::SEC_REQUIRED); | 134 SetSdesPolicy(dtls_enabled ? cricket::SEC_DISABLED : cricket::SEC_REQUIRED); |
| 140 if (!dtls_enabled) { | 135 if (!dtls_enabled) { |
| 141 LOG(LS_VERBOSE) << "DTLS-SRTP disabled."; | 136 LOG(LS_VERBOSE) << "DTLS-SRTP disabled."; |
| 142 return; | 137 return; |
| 143 } | 138 } |
| 144 | 139 |
| 145 if (certificate) { | 140 if (certificate) { |
| 146 // Use |certificate|. | 141 // Use |certificate|. |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 235 const PeerConnectionInterface::RTCOfferAnswerOptions& options, | 230 const PeerConnectionInterface::RTCOfferAnswerOptions& options, |
| 236 const cricket::MediaSessionOptions& session_options) { | 231 const cricket::MediaSessionOptions& session_options) { |
| 237 std::string error = "CreateOffer"; | 232 std::string error = "CreateOffer"; |
| 238 if (certificate_request_state_ == CERTIFICATE_FAILED) { | 233 if (certificate_request_state_ == CERTIFICATE_FAILED) { |
| 239 error += kFailedDueToIdentityFailed; | 234 error += kFailedDueToIdentityFailed; |
| 240 LOG(LS_ERROR) << error; | 235 LOG(LS_ERROR) << error; |
| 241 PostCreateSessionDescriptionFailed(observer, error); | 236 PostCreateSessionDescriptionFailed(observer, error); |
| 242 return; | 237 return; |
| 243 } | 238 } |
| 244 | 239 |
| 245 if (!ValidMediaSessionOptions(session_options)) { | 240 if (!ValidStreams(session_options.streams)) { |
| 246 error += " called with invalid session options"; | 241 error += " called with invalid media streams."; |
| 247 LOG(LS_ERROR) << error; | 242 LOG(LS_ERROR) << error; |
| 248 PostCreateSessionDescriptionFailed(observer, error); | 243 PostCreateSessionDescriptionFailed(observer, error); |
| 249 return; | 244 return; |
| 250 } | 245 } |
| 251 | 246 |
| 252 CreateSessionDescriptionRequest request( | 247 CreateSessionDescriptionRequest request( |
| 253 CreateSessionDescriptionRequest::kOffer, observer, session_options); | 248 CreateSessionDescriptionRequest::kOffer, observer, session_options); |
| 254 if (certificate_request_state_ == CERTIFICATE_WAITING) { | 249 if (certificate_request_state_ == CERTIFICATE_WAITING) { |
| 255 create_session_description_requests_.push(request); | 250 create_session_description_requests_.push(request); |
| 256 } else { | 251 } else { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 277 return; | 272 return; |
| 278 } | 273 } |
| 279 if (session_->remote_description()->type() != | 274 if (session_->remote_description()->type() != |
| 280 JsepSessionDescription::kOffer) { | 275 JsepSessionDescription::kOffer) { |
| 281 error += " failed because remote_description is not an offer."; | 276 error += " failed because remote_description is not an offer."; |
| 282 LOG(LS_ERROR) << error; | 277 LOG(LS_ERROR) << error; |
| 283 PostCreateSessionDescriptionFailed(observer, error); | 278 PostCreateSessionDescriptionFailed(observer, error); |
| 284 return; | 279 return; |
| 285 } | 280 } |
| 286 | 281 |
| 287 if (!ValidMediaSessionOptions(session_options)) { | 282 if (!ValidStreams(session_options.streams)) { |
| 288 error += " called with invalid session options."; | 283 error += " called with invalid media streams."; |
| 289 LOG(LS_ERROR) << error; | 284 LOG(LS_ERROR) << error; |
| 290 PostCreateSessionDescriptionFailed(observer, error); | 285 PostCreateSessionDescriptionFailed(observer, error); |
| 291 return; | 286 return; |
| 292 } | 287 } |
| 293 | 288 |
| 294 CreateSessionDescriptionRequest request( | 289 CreateSessionDescriptionRequest request( |
| 295 CreateSessionDescriptionRequest::kAnswer, observer, session_options); | 290 CreateSessionDescriptionRequest::kAnswer, observer, session_options); |
| 296 if (certificate_request_state_ == CERTIFICATE_WAITING) { | 291 if (certificate_request_state_ == CERTIFICATE_WAITING) { |
| 297 create_session_description_requests_.push(request); | 292 create_session_description_requests_.push(request); |
| 298 } else { | 293 } else { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 338 } | 333 } |
| 339 default: | 334 default: |
| 340 RTC_NOTREACHED(); | 335 RTC_NOTREACHED(); |
| 341 break; | 336 break; |
| 342 } | 337 } |
| 343 } | 338 } |
| 344 | 339 |
| 345 void WebRtcSessionDescriptionFactory::InternalCreateOffer( | 340 void WebRtcSessionDescriptionFactory::InternalCreateOffer( |
| 346 CreateSessionDescriptionRequest request) { | 341 CreateSessionDescriptionRequest request) { |
| 347 if (session_->local_description()) { | 342 if (session_->local_description()) { |
| 348 // If the needs-ice-restart flag is set as described by JSEP, we should | 343 for (const cricket::TransportInfo& transport : |
| 349 // generate an offer with a new ufrag/password to trigger an ICE restart. | 344 session_->local_description()->description()->transport_infos()) { |
| 350 for (cricket::MediaDescriptionOptions& options : | 345 // If the needs-ice-restart flag is set as described by JSEP, we should |
| 351 request.options.media_description_options) { | 346 // generate an offer with a new ufrag/password to trigger an ICE restart. |
| 352 if (session_->NeedsIceRestart(options.mid)) { | 347 if (session_->NeedsIceRestart(transport.content_name)) { |
| 353 options.transport_options.ice_restart = true; | 348 request.options.transport_options[transport.content_name].ice_restart = |
| 349 true; |
| 354 } | 350 } |
| 355 } | 351 } |
| 356 } | 352 } |
| 357 | 353 |
| 358 cricket::SessionDescription* desc(session_desc_factory_.CreateOffer( | 354 cricket::SessionDescription* desc(session_desc_factory_.CreateOffer( |
| 359 request.options, session_->local_description() | 355 request.options, session_->local_description() |
| 360 ? session_->local_description()->description() | 356 ? session_->local_description()->description() |
| 361 : nullptr)); | 357 : nullptr)); |
| 362 // RFC 3264 | 358 // RFC 3264 |
| 363 // When issuing an offer that modifies the session, | 359 // When issuing an offer that modifies the session, |
| 364 // the "o=" line of the new SDP MUST be identical to that in the | 360 // the "o=" line of the new SDP MUST be identical to that in the |
| 365 // previous SDP, except that the version in the origin field MUST | 361 // previous SDP, except that the version in the origin field MUST |
| 366 // increment by one from the previous SDP. | 362 // increment by one from the previous SDP. |
| 367 | 363 |
| 368 // Just increase the version number by one each time when a new offer | 364 // Just increase the version number by one each time when a new offer |
| 369 // is created regardless if it's identical to the previous one or not. | 365 // is created regardless if it's identical to the previous one or not. |
| 370 // The |session_version_| is a uint64_t, the wrap around should not happen. | 366 // The |session_version_| is a uint64_t, the wrap around should not happen. |
| 371 RTC_DCHECK(session_version_ + 1 > session_version_); | 367 RTC_DCHECK(session_version_ + 1 > session_version_); |
| 372 JsepSessionDescription* offer(new JsepSessionDescription( | 368 JsepSessionDescription* offer(new JsepSessionDescription( |
| 373 JsepSessionDescription::kOffer)); | 369 JsepSessionDescription::kOffer)); |
| 374 if (!offer->Initialize(desc, session_id_, | 370 if (!offer->Initialize(desc, session_id_, |
| 375 rtc::ToString(session_version_++))) { | 371 rtc::ToString(session_version_++))) { |
| 376 delete offer; | 372 delete offer; |
| 377 PostCreateSessionDescriptionFailed(request.observer, | 373 PostCreateSessionDescriptionFailed(request.observer, |
| 378 "Failed to initialize the offer."); | 374 "Failed to initialize the offer."); |
| 379 return; | 375 return; |
| 380 } | 376 } |
| 381 if (session_->local_description()) { | 377 if (session_->local_description()) { |
| 382 for (const cricket::MediaDescriptionOptions& options : | 378 for (const cricket::ContentInfo& content : |
| 383 request.options.media_description_options) { | 379 session_->local_description()->description()->contents()) { |
| 384 if (!options.transport_options.ice_restart) { | 380 // Include all local ICE candidates in the SessionDescription unless |
| 381 // an ICE restart was requested. |
| 382 if (!request.options.transport_options[content.name].ice_restart) { |
| 385 CopyCandidatesFromSessionDescription(session_->local_description(), | 383 CopyCandidatesFromSessionDescription(session_->local_description(), |
| 386 options.mid, offer); | 384 content.name, offer); |
| 387 } | 385 } |
| 388 } | 386 } |
| 389 } | 387 } |
| 390 PostCreateSessionDescriptionSucceeded(request.observer, offer); | 388 PostCreateSessionDescriptionSucceeded(request.observer, offer); |
| 391 } | 389 } |
| 392 | 390 |
| 393 void WebRtcSessionDescriptionFactory::InternalCreateAnswer( | 391 void WebRtcSessionDescriptionFactory::InternalCreateAnswer( |
| 394 CreateSessionDescriptionRequest request) { | 392 CreateSessionDescriptionRequest request) { |
| 395 if (session_->remote_description()) { | 393 if (session_->remote_description()) { |
| 396 for (cricket::MediaDescriptionOptions& options : | 394 for (const cricket::ContentInfo& content : |
| 397 request.options.media_description_options) { | 395 session_->remote_description()->description()->contents()) { |
| 398 // According to http://tools.ietf.org/html/rfc5245#section-9.2.1.1 | 396 // According to http://tools.ietf.org/html/rfc5245#section-9.2.1.1 |
| 399 // an answer should also contain new ICE ufrag and password if an offer | 397 // an answer should also contain new ICE ufrag and password if an offer |
| 400 // has been received with new ufrag and password. | 398 // has been received with new ufrag and password. |
| 401 options.transport_options.ice_restart = | 399 request.options.transport_options[content.name].ice_restart = |
| 402 session_->IceRestartPending(options.mid); | 400 session_->IceRestartPending(content.name); |
| 403 // We should pass the current SSL role to the transport description | 401 // We should pass the current SSL role to the transport description |
| 404 // factory, if there is already an existing ongoing session. | 402 // factory, if there is already an existing ongoing session. |
| 405 rtc::SSLRole ssl_role; | 403 rtc::SSLRole ssl_role; |
| 406 if (session_->GetSslRole(options.mid, &ssl_role)) { | 404 if (session_->GetSslRole(content.name, &ssl_role)) { |
| 407 options.transport_options.prefer_passive_role = | 405 request.options.transport_options[content.name].prefer_passive_role = |
| 408 (rtc::SSL_SERVER == ssl_role); | 406 (rtc::SSL_SERVER == ssl_role); |
| 409 } | 407 } |
| 410 } | 408 } |
| 411 } | 409 } |
| 412 | 410 |
| 413 cricket::SessionDescription* desc(session_desc_factory_.CreateAnswer( | 411 cricket::SessionDescription* desc(session_desc_factory_.CreateAnswer( |
| 414 session_->remote_description() | 412 session_->remote_description() |
| 415 ? session_->remote_description()->description() | 413 ? session_->remote_description()->description() |
| 416 : nullptr, | 414 : nullptr, |
| 417 request.options, session_->local_description() | 415 request.options, session_->local_description() |
| (...skipping 10 matching lines...) Expand all Loading... |
| 428 JsepSessionDescription* answer(new JsepSessionDescription( | 426 JsepSessionDescription* answer(new JsepSessionDescription( |
| 429 JsepSessionDescription::kAnswer)); | 427 JsepSessionDescription::kAnswer)); |
| 430 if (!answer->Initialize(desc, session_id_, | 428 if (!answer->Initialize(desc, session_id_, |
| 431 rtc::ToString(session_version_++))) { | 429 rtc::ToString(session_version_++))) { |
| 432 delete answer; | 430 delete answer; |
| 433 PostCreateSessionDescriptionFailed(request.observer, | 431 PostCreateSessionDescriptionFailed(request.observer, |
| 434 "Failed to initialize the answer."); | 432 "Failed to initialize the answer."); |
| 435 return; | 433 return; |
| 436 } | 434 } |
| 437 if (session_->local_description()) { | 435 if (session_->local_description()) { |
| 438 // Include all local ICE candidates in the SessionDescription unless | 436 for (const cricket::ContentInfo& content : |
| 439 // the remote peer has requested an ICE restart. | 437 session_->local_description()->description()->contents()) { |
| 440 for (const cricket::MediaDescriptionOptions& options : | 438 // Include all local ICE candidates in the SessionDescription unless |
| 441 request.options.media_description_options) { | 439 // the remote peer has requested an ICE restart. |
| 442 if (!options.transport_options.ice_restart) { | 440 if (!request.options.transport_options[content.name].ice_restart) { |
| 443 CopyCandidatesFromSessionDescription(session_->local_description(), | 441 CopyCandidatesFromSessionDescription(session_->local_description(), |
| 444 options.mid, answer); | 442 content.name, answer); |
| 445 } | 443 } |
| 446 } | 444 } |
| 447 } | 445 } |
| 448 PostCreateSessionDescriptionSucceeded(request.observer, answer); | 446 PostCreateSessionDescriptionSucceeded(request.observer, answer); |
| 449 } | 447 } |
| 450 | 448 |
| 451 void WebRtcSessionDescriptionFactory::FailPendingRequests( | 449 void WebRtcSessionDescriptionFactory::FailPendingRequests( |
| 452 const std::string& reason) { | 450 const std::string& reason) { |
| 453 RTC_DCHECK(signaling_thread_->IsCurrent()); | 451 RTC_DCHECK(signaling_thread_->IsCurrent()); |
| 454 while (!create_session_description_requests_.empty()) { | 452 while (!create_session_description_requests_.empty()) { |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 503 if (create_session_description_requests_.front().type == | 501 if (create_session_description_requests_.front().type == |
| 504 CreateSessionDescriptionRequest::kOffer) { | 502 CreateSessionDescriptionRequest::kOffer) { |
| 505 InternalCreateOffer(create_session_description_requests_.front()); | 503 InternalCreateOffer(create_session_description_requests_.front()); |
| 506 } else { | 504 } else { |
| 507 InternalCreateAnswer(create_session_description_requests_.front()); | 505 InternalCreateAnswer(create_session_description_requests_.front()); |
| 508 } | 506 } |
| 509 create_session_description_requests_.pop(); | 507 create_session_description_requests_.pop(); |
| 510 } | 508 } |
| 511 } | 509 } |
| 512 } // namespace webrtc | 510 } // namespace webrtc |
| OLD | NEW |