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