| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright 2013 The WebRTC project authors. All Rights Reserved. | |
| 3 * | |
| 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 | |
| 6 * tree. An additional intellectual property rights grant can be found | |
| 7 * in the file PATENTS. All contributing project authors may | |
| 8 * be found in the AUTHORS file in the root of the source tree. | |
| 9 */ | |
| 10 | |
| 11 #include "webrtc/api/webrtcsessiondescriptionfactory.h" | |
| 12 | |
| 13 #include <utility> | |
| 14 | |
| 15 #include "webrtc/api/jsep.h" | |
| 16 #include "webrtc/api/jsepsessiondescription.h" | |
| 17 #include "webrtc/api/mediaconstraintsinterface.h" | |
| 18 #include "webrtc/api/webrtcsession.h" | |
| 19 #include "webrtc/base/checks.h" | |
| 20 #include "webrtc/base/sslidentity.h" | |
| 21 | |
| 22 using cricket::MediaSessionOptions; | |
| 23 | |
| 24 namespace webrtc { | |
| 25 namespace { | |
| 26 static const char kFailedDueToIdentityFailed[] = | |
| 27 " failed because DTLS identity request failed"; | |
| 28 static const char kFailedDueToSessionShutdown[] = | |
| 29 " failed because the session was shut down"; | |
| 30 | |
| 31 static const uint64_t kInitSessionVersion = 2; | |
| 32 | |
| 33 static bool CompareStream(const MediaSessionOptions::Stream& stream1, | |
| 34 const MediaSessionOptions::Stream& stream2) { | |
| 35 return stream1.id < stream2.id; | |
| 36 } | |
| 37 | |
| 38 static bool SameId(const MediaSessionOptions::Stream& stream1, | |
| 39 const MediaSessionOptions::Stream& stream2) { | |
| 40 return stream1.id == stream2.id; | |
| 41 } | |
| 42 | |
| 43 // Checks if each Stream within the |streams| has unique id. | |
| 44 static bool ValidStreams(const MediaSessionOptions::Streams& streams) { | |
| 45 MediaSessionOptions::Streams sorted_streams = streams; | |
| 46 std::sort(sorted_streams.begin(), sorted_streams.end(), CompareStream); | |
| 47 MediaSessionOptions::Streams::iterator it = | |
| 48 std::adjacent_find(sorted_streams.begin(), sorted_streams.end(), | |
| 49 SameId); | |
| 50 return it == sorted_streams.end(); | |
| 51 } | |
| 52 | |
| 53 enum { | |
| 54 MSG_CREATE_SESSIONDESCRIPTION_SUCCESS, | |
| 55 MSG_CREATE_SESSIONDESCRIPTION_FAILED, | |
| 56 MSG_USE_CONSTRUCTOR_CERTIFICATE | |
| 57 }; | |
| 58 | |
| 59 struct CreateSessionDescriptionMsg : public rtc::MessageData { | |
| 60 explicit CreateSessionDescriptionMsg( | |
| 61 webrtc::CreateSessionDescriptionObserver* observer) | |
| 62 : observer(observer) { | |
| 63 } | |
| 64 | |
| 65 rtc::scoped_refptr<webrtc::CreateSessionDescriptionObserver> observer; | |
| 66 std::string error; | |
| 67 std::unique_ptr<webrtc::SessionDescriptionInterface> description; | |
| 68 }; | |
| 69 } // namespace | |
| 70 | |
| 71 void WebRtcCertificateGeneratorCallback::OnFailure() { | |
| 72 SignalRequestFailed(); | |
| 73 } | |
| 74 | |
| 75 void WebRtcCertificateGeneratorCallback::OnSuccess( | |
| 76 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) { | |
| 77 SignalCertificateReady(certificate); | |
| 78 } | |
| 79 | |
| 80 // static | |
| 81 void WebRtcSessionDescriptionFactory::CopyCandidatesFromSessionDescription( | |
| 82 const SessionDescriptionInterface* source_desc, | |
| 83 const std::string& content_name, | |
| 84 SessionDescriptionInterface* dest_desc) { | |
| 85 if (!source_desc) { | |
| 86 return; | |
| 87 } | |
| 88 const cricket::ContentInfos& contents = | |
| 89 source_desc->description()->contents(); | |
| 90 const cricket::ContentInfo* cinfo = | |
| 91 source_desc->description()->GetContentByName(content_name); | |
| 92 if (!cinfo) { | |
| 93 return; | |
| 94 } | |
| 95 size_t mediasection_index = static_cast<int>(cinfo - &contents[0]); | |
| 96 const IceCandidateCollection* source_candidates = | |
| 97 source_desc->candidates(mediasection_index); | |
| 98 const IceCandidateCollection* dest_candidates = | |
| 99 dest_desc->candidates(mediasection_index); | |
| 100 if (!source_candidates || !dest_candidates) { | |
| 101 return; | |
| 102 } | |
| 103 for (size_t n = 0; n < source_candidates->count(); ++n) { | |
| 104 const IceCandidateInterface* new_candidate = source_candidates->at(n); | |
| 105 if (!dest_candidates->HasCandidate(new_candidate)) { | |
| 106 dest_desc->AddCandidate(source_candidates->at(n)); | |
| 107 } | |
| 108 } | |
| 109 } | |
| 110 | |
| 111 // Private constructor called by other constructors. | |
| 112 WebRtcSessionDescriptionFactory::WebRtcSessionDescriptionFactory( | |
| 113 rtc::Thread* signaling_thread, | |
| 114 cricket::ChannelManager* channel_manager, | |
| 115 WebRtcSession* session, | |
| 116 const std::string& session_id, | |
| 117 std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator, | |
| 118 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) | |
| 119 : signaling_thread_(signaling_thread), | |
| 120 session_desc_factory_(channel_manager, &transport_desc_factory_), | |
| 121 // RFC 4566 suggested a Network Time Protocol (NTP) format timestamp | |
| 122 // as the session id and session version. To simplify, it should be fine | |
| 123 // to just use a random number as session id and start version from | |
| 124 // |kInitSessionVersion|. | |
| 125 session_version_(kInitSessionVersion), | |
| 126 cert_generator_(std::move(cert_generator)), | |
| 127 session_(session), | |
| 128 session_id_(session_id), | |
| 129 certificate_request_state_(CERTIFICATE_NOT_NEEDED) { | |
| 130 RTC_DCHECK(signaling_thread_); | |
| 131 session_desc_factory_.set_add_legacy_streams(false); | |
| 132 bool dtls_enabled = cert_generator_ || certificate; | |
| 133 // SRTP-SDES is disabled if DTLS is on. | |
| 134 SetSdesPolicy(dtls_enabled ? cricket::SEC_DISABLED : cricket::SEC_REQUIRED); | |
| 135 if (!dtls_enabled) { | |
| 136 LOG(LS_VERBOSE) << "DTLS-SRTP disabled."; | |
| 137 return; | |
| 138 } | |
| 139 | |
| 140 if (certificate) { | |
| 141 // Use |certificate|. | |
| 142 certificate_request_state_ = CERTIFICATE_WAITING; | |
| 143 | |
| 144 LOG(LS_VERBOSE) << "DTLS-SRTP enabled; has certificate parameter."; | |
| 145 // We already have a certificate but we wait to do |SetIdentity|; if we do | |
| 146 // it in the constructor then the caller has not had a chance to connect to | |
| 147 // |SignalCertificateReady|. | |
| 148 signaling_thread_->Post( | |
| 149 RTC_FROM_HERE, this, MSG_USE_CONSTRUCTOR_CERTIFICATE, | |
| 150 new rtc::ScopedRefMessageData<rtc::RTCCertificate>(certificate)); | |
| 151 } else { | |
| 152 // Generate certificate. | |
| 153 certificate_request_state_ = CERTIFICATE_WAITING; | |
| 154 | |
| 155 rtc::scoped_refptr<WebRtcCertificateGeneratorCallback> callback( | |
| 156 new rtc::RefCountedObject<WebRtcCertificateGeneratorCallback>()); | |
| 157 callback->SignalRequestFailed.connect( | |
| 158 this, &WebRtcSessionDescriptionFactory::OnCertificateRequestFailed); | |
| 159 callback->SignalCertificateReady.connect( | |
| 160 this, &WebRtcSessionDescriptionFactory::SetCertificate); | |
| 161 | |
| 162 rtc::KeyParams key_params = rtc::KeyParams(); | |
| 163 LOG(LS_VERBOSE) << "DTLS-SRTP enabled; sending DTLS identity request (key " | |
| 164 << "type: " << key_params.type() << ")."; | |
| 165 | |
| 166 // Request certificate. This happens asynchronously, so that the caller gets | |
| 167 // a chance to connect to |SignalCertificateReady|. | |
| 168 cert_generator_->GenerateCertificateAsync( | |
| 169 key_params, rtc::Optional<uint64_t>(), callback); | |
| 170 } | |
| 171 } | |
| 172 | |
| 173 WebRtcSessionDescriptionFactory::WebRtcSessionDescriptionFactory( | |
| 174 rtc::Thread* signaling_thread, | |
| 175 cricket::ChannelManager* channel_manager, | |
| 176 WebRtcSession* session, | |
| 177 const std::string& session_id, | |
| 178 std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator) | |
| 179 : WebRtcSessionDescriptionFactory( | |
| 180 signaling_thread, | |
| 181 channel_manager, | |
| 182 session, | |
| 183 session_id, | |
| 184 std::move(cert_generator), | |
| 185 nullptr) { | |
| 186 } | |
| 187 | |
| 188 WebRtcSessionDescriptionFactory::WebRtcSessionDescriptionFactory( | |
| 189 rtc::Thread* signaling_thread, | |
| 190 cricket::ChannelManager* channel_manager, | |
| 191 WebRtcSession* session, | |
| 192 const std::string& session_id, | |
| 193 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) | |
| 194 : WebRtcSessionDescriptionFactory(signaling_thread, | |
| 195 channel_manager, | |
| 196 session, | |
| 197 session_id, | |
| 198 nullptr, | |
| 199 certificate) { | |
| 200 RTC_DCHECK(certificate); | |
| 201 } | |
| 202 | |
| 203 WebRtcSessionDescriptionFactory::~WebRtcSessionDescriptionFactory() { | |
| 204 RTC_DCHECK(signaling_thread_->IsCurrent()); | |
| 205 | |
| 206 // Fail any requests that were asked for before identity generation completed. | |
| 207 FailPendingRequests(kFailedDueToSessionShutdown); | |
| 208 | |
| 209 // Process all pending notifications in the message queue. If we don't do | |
| 210 // this, requests will linger and not know they succeeded or failed. | |
| 211 rtc::MessageList list; | |
| 212 signaling_thread_->Clear(this, rtc::MQID_ANY, &list); | |
| 213 for (auto& msg : list) { | |
| 214 if (msg.message_id != MSG_USE_CONSTRUCTOR_CERTIFICATE) { | |
| 215 OnMessage(&msg); | |
| 216 } else { | |
| 217 // Skip MSG_USE_CONSTRUCTOR_CERTIFICATE because we don't want to trigger | |
| 218 // SetIdentity-related callbacks in the destructor. This can be a problem | |
| 219 // when WebRtcSession listens to the callback but it was the WebRtcSession | |
| 220 // destructor that caused WebRtcSessionDescriptionFactory's destruction. | |
| 221 // The callback is then ignored, leaking memory allocated by OnMessage for | |
| 222 // MSG_USE_CONSTRUCTOR_CERTIFICATE. | |
| 223 delete msg.pdata; | |
| 224 } | |
| 225 } | |
| 226 } | |
| 227 | |
| 228 void WebRtcSessionDescriptionFactory::CreateOffer( | |
| 229 CreateSessionDescriptionObserver* observer, | |
| 230 const PeerConnectionInterface::RTCOfferAnswerOptions& options, | |
| 231 const cricket::MediaSessionOptions& session_options) { | |
| 232 std::string error = "CreateOffer"; | |
| 233 if (certificate_request_state_ == CERTIFICATE_FAILED) { | |
| 234 error += kFailedDueToIdentityFailed; | |
| 235 LOG(LS_ERROR) << error; | |
| 236 PostCreateSessionDescriptionFailed(observer, error); | |
| 237 return; | |
| 238 } | |
| 239 | |
| 240 if (!ValidStreams(session_options.streams)) { | |
| 241 error += " called with invalid media streams."; | |
| 242 LOG(LS_ERROR) << error; | |
| 243 PostCreateSessionDescriptionFailed(observer, error); | |
| 244 return; | |
| 245 } | |
| 246 | |
| 247 CreateSessionDescriptionRequest request( | |
| 248 CreateSessionDescriptionRequest::kOffer, observer, session_options); | |
| 249 if (certificate_request_state_ == CERTIFICATE_WAITING) { | |
| 250 create_session_description_requests_.push(request); | |
| 251 } else { | |
| 252 RTC_DCHECK(certificate_request_state_ == CERTIFICATE_SUCCEEDED || | |
| 253 certificate_request_state_ == CERTIFICATE_NOT_NEEDED); | |
| 254 InternalCreateOffer(request); | |
| 255 } | |
| 256 } | |
| 257 | |
| 258 void WebRtcSessionDescriptionFactory::CreateAnswer( | |
| 259 CreateSessionDescriptionObserver* observer, | |
| 260 const cricket::MediaSessionOptions& session_options) { | |
| 261 std::string error = "CreateAnswer"; | |
| 262 if (certificate_request_state_ == CERTIFICATE_FAILED) { | |
| 263 error += kFailedDueToIdentityFailed; | |
| 264 LOG(LS_ERROR) << error; | |
| 265 PostCreateSessionDescriptionFailed(observer, error); | |
| 266 return; | |
| 267 } | |
| 268 if (!session_->remote_description()) { | |
| 269 error += " can't be called before SetRemoteDescription."; | |
| 270 LOG(LS_ERROR) << error; | |
| 271 PostCreateSessionDescriptionFailed(observer, error); | |
| 272 return; | |
| 273 } | |
| 274 if (session_->remote_description()->type() != | |
| 275 JsepSessionDescription::kOffer) { | |
| 276 error += " failed because remote_description is not an offer."; | |
| 277 LOG(LS_ERROR) << error; | |
| 278 PostCreateSessionDescriptionFailed(observer, error); | |
| 279 return; | |
| 280 } | |
| 281 | |
| 282 if (!ValidStreams(session_options.streams)) { | |
| 283 error += " called with invalid media streams."; | |
| 284 LOG(LS_ERROR) << error; | |
| 285 PostCreateSessionDescriptionFailed(observer, error); | |
| 286 return; | |
| 287 } | |
| 288 | |
| 289 CreateSessionDescriptionRequest request( | |
| 290 CreateSessionDescriptionRequest::kAnswer, observer, session_options); | |
| 291 if (certificate_request_state_ == CERTIFICATE_WAITING) { | |
| 292 create_session_description_requests_.push(request); | |
| 293 } else { | |
| 294 RTC_DCHECK(certificate_request_state_ == CERTIFICATE_SUCCEEDED || | |
| 295 certificate_request_state_ == CERTIFICATE_NOT_NEEDED); | |
| 296 InternalCreateAnswer(request); | |
| 297 } | |
| 298 } | |
| 299 | |
| 300 void WebRtcSessionDescriptionFactory::SetSdesPolicy( | |
| 301 cricket::SecurePolicy secure_policy) { | |
| 302 session_desc_factory_.set_secure(secure_policy); | |
| 303 } | |
| 304 | |
| 305 cricket::SecurePolicy WebRtcSessionDescriptionFactory::SdesPolicy() const { | |
| 306 return session_desc_factory_.secure(); | |
| 307 } | |
| 308 | |
| 309 void WebRtcSessionDescriptionFactory::OnMessage(rtc::Message* msg) { | |
| 310 switch (msg->message_id) { | |
| 311 case MSG_CREATE_SESSIONDESCRIPTION_SUCCESS: { | |
| 312 CreateSessionDescriptionMsg* param = | |
| 313 static_cast<CreateSessionDescriptionMsg*>(msg->pdata); | |
| 314 param->observer->OnSuccess(param->description.release()); | |
| 315 delete param; | |
| 316 break; | |
| 317 } | |
| 318 case MSG_CREATE_SESSIONDESCRIPTION_FAILED: { | |
| 319 CreateSessionDescriptionMsg* param = | |
| 320 static_cast<CreateSessionDescriptionMsg*>(msg->pdata); | |
| 321 param->observer->OnFailure(param->error); | |
| 322 delete param; | |
| 323 break; | |
| 324 } | |
| 325 case MSG_USE_CONSTRUCTOR_CERTIFICATE: { | |
| 326 rtc::ScopedRefMessageData<rtc::RTCCertificate>* param = | |
| 327 static_cast<rtc::ScopedRefMessageData<rtc::RTCCertificate>*>( | |
| 328 msg->pdata); | |
| 329 LOG(LS_INFO) << "Using certificate supplied to the constructor."; | |
| 330 SetCertificate(param->data()); | |
| 331 delete param; | |
| 332 break; | |
| 333 } | |
| 334 default: | |
| 335 RTC_NOTREACHED(); | |
| 336 break; | |
| 337 } | |
| 338 } | |
| 339 | |
| 340 void WebRtcSessionDescriptionFactory::InternalCreateOffer( | |
| 341 CreateSessionDescriptionRequest request) { | |
| 342 if (session_->local_description()) { | |
| 343 for (const cricket::TransportInfo& transport : | |
| 344 session_->local_description()->description()->transport_infos()) { | |
| 345 // If the needs-ice-restart flag is set as described by JSEP, we should | |
| 346 // generate an offer with a new ufrag/password to trigger an ICE restart. | |
| 347 if (session_->NeedsIceRestart(transport.content_name)) { | |
| 348 request.options.transport_options[transport.content_name].ice_restart = | |
| 349 true; | |
| 350 } | |
| 351 } | |
| 352 } | |
| 353 | |
| 354 cricket::SessionDescription* desc(session_desc_factory_.CreateOffer( | |
| 355 request.options, session_->local_description() | |
| 356 ? session_->local_description()->description() | |
| 357 : nullptr)); | |
| 358 // RFC 3264 | |
| 359 // When issuing an offer that modifies the session, | |
| 360 // the "o=" line of the new SDP MUST be identical to that in the | |
| 361 // previous SDP, except that the version in the origin field MUST | |
| 362 // increment by one from the previous SDP. | |
| 363 | |
| 364 // Just increase the version number by one each time when a new offer | |
| 365 // is created regardless if it's identical to the previous one or not. | |
| 366 // The |session_version_| is a uint64_t, the wrap around should not happen. | |
| 367 RTC_DCHECK(session_version_ + 1 > session_version_); | |
| 368 JsepSessionDescription* offer(new JsepSessionDescription( | |
| 369 JsepSessionDescription::kOffer)); | |
| 370 if (!offer->Initialize(desc, session_id_, | |
| 371 rtc::ToString(session_version_++))) { | |
| 372 delete offer; | |
| 373 PostCreateSessionDescriptionFailed(request.observer, | |
| 374 "Failed to initialize the offer."); | |
| 375 return; | |
| 376 } | |
| 377 if (session_->local_description()) { | |
| 378 for (const cricket::ContentInfo& content : | |
| 379 session_->local_description()->description()->contents()) { | |
| 380 // Include all local ICE candidates in the SessionDescription unless | |
| 381 // the remote peer has requested an ICE restart. | |
| 382 if (!request.options.transport_options[content.name].ice_restart) { | |
| 383 CopyCandidatesFromSessionDescription(session_->local_description(), | |
| 384 content.name, offer); | |
| 385 } | |
| 386 } | |
| 387 } | |
| 388 PostCreateSessionDescriptionSucceeded(request.observer, offer); | |
| 389 } | |
| 390 | |
| 391 void WebRtcSessionDescriptionFactory::InternalCreateAnswer( | |
| 392 CreateSessionDescriptionRequest request) { | |
| 393 if (session_->remote_description()) { | |
| 394 for (const cricket::ContentInfo& content : | |
| 395 session_->remote_description()->description()->contents()) { | |
| 396 // According to http://tools.ietf.org/html/rfc5245#section-9.2.1.1 | |
| 397 // an answer should also contain new ICE ufrag and password if an offer | |
| 398 // has been received with new ufrag and password. | |
| 399 request.options.transport_options[content.name].ice_restart = | |
| 400 session_->IceRestartPending(content.name); | |
| 401 // We should pass the current SSL role to the transport description | |
| 402 // factory, if there is already an existing ongoing session. | |
| 403 rtc::SSLRole ssl_role; | |
| 404 if (session_->GetSslRole(content.name, &ssl_role)) { | |
| 405 request.options.transport_options[content.name].prefer_passive_role = | |
| 406 (rtc::SSL_SERVER == ssl_role); | |
| 407 } | |
| 408 } | |
| 409 } | |
| 410 | |
| 411 cricket::SessionDescription* desc(session_desc_factory_.CreateAnswer( | |
| 412 session_->remote_description() | |
| 413 ? session_->remote_description()->description() | |
| 414 : nullptr, | |
| 415 request.options, session_->local_description() | |
| 416 ? session_->local_description()->description() | |
| 417 : nullptr)); | |
| 418 // RFC 3264 | |
| 419 // If the answer is different from the offer in any way (different IP | |
| 420 // addresses, ports, etc.), the origin line MUST be different in the answer. | |
| 421 // In that case, the version number in the "o=" line of the answer is | |
| 422 // unrelated to the version number in the o line of the offer. | |
| 423 // Get a new version number by increasing the |session_version_answer_|. | |
| 424 // The |session_version_| is a uint64_t, the wrap around should not happen. | |
| 425 RTC_DCHECK(session_version_ + 1 > session_version_); | |
| 426 JsepSessionDescription* answer(new JsepSessionDescription( | |
| 427 JsepSessionDescription::kAnswer)); | |
| 428 if (!answer->Initialize(desc, session_id_, | |
| 429 rtc::ToString(session_version_++))) { | |
| 430 delete answer; | |
| 431 PostCreateSessionDescriptionFailed(request.observer, | |
| 432 "Failed to initialize the answer."); | |
| 433 return; | |
| 434 } | |
| 435 if (session_->local_description()) { | |
| 436 for (const cricket::ContentInfo& content : | |
| 437 session_->local_description()->description()->contents()) { | |
| 438 // Include all local ICE candidates in the SessionDescription unless | |
| 439 // the remote peer has requested an ICE restart. | |
| 440 if (!request.options.transport_options[content.name].ice_restart) { | |
| 441 CopyCandidatesFromSessionDescription(session_->local_description(), | |
| 442 content.name, answer); | |
| 443 } | |
| 444 } | |
| 445 } | |
| 446 PostCreateSessionDescriptionSucceeded(request.observer, answer); | |
| 447 } | |
| 448 | |
| 449 void WebRtcSessionDescriptionFactory::FailPendingRequests( | |
| 450 const std::string& reason) { | |
| 451 RTC_DCHECK(signaling_thread_->IsCurrent()); | |
| 452 while (!create_session_description_requests_.empty()) { | |
| 453 const CreateSessionDescriptionRequest& request = | |
| 454 create_session_description_requests_.front(); | |
| 455 PostCreateSessionDescriptionFailed(request.observer, | |
| 456 ((request.type == CreateSessionDescriptionRequest::kOffer) ? | |
| 457 "CreateOffer" : "CreateAnswer") + reason); | |
| 458 create_session_description_requests_.pop(); | |
| 459 } | |
| 460 } | |
| 461 | |
| 462 void WebRtcSessionDescriptionFactory::PostCreateSessionDescriptionFailed( | |
| 463 CreateSessionDescriptionObserver* observer, const std::string& error) { | |
| 464 CreateSessionDescriptionMsg* msg = new CreateSessionDescriptionMsg(observer); | |
| 465 msg->error = error; | |
| 466 signaling_thread_->Post(RTC_FROM_HERE, this, | |
| 467 MSG_CREATE_SESSIONDESCRIPTION_FAILED, msg); | |
| 468 LOG(LS_ERROR) << "Create SDP failed: " << error; | |
| 469 } | |
| 470 | |
| 471 void WebRtcSessionDescriptionFactory::PostCreateSessionDescriptionSucceeded( | |
| 472 CreateSessionDescriptionObserver* observer, | |
| 473 SessionDescriptionInterface* description) { | |
| 474 CreateSessionDescriptionMsg* msg = new CreateSessionDescriptionMsg(observer); | |
| 475 msg->description.reset(description); | |
| 476 signaling_thread_->Post(RTC_FROM_HERE, this, | |
| 477 MSG_CREATE_SESSIONDESCRIPTION_SUCCESS, msg); | |
| 478 } | |
| 479 | |
| 480 void WebRtcSessionDescriptionFactory::OnCertificateRequestFailed() { | |
| 481 RTC_DCHECK(signaling_thread_->IsCurrent()); | |
| 482 | |
| 483 LOG(LS_ERROR) << "Asynchronous certificate generation request failed."; | |
| 484 certificate_request_state_ = CERTIFICATE_FAILED; | |
| 485 | |
| 486 FailPendingRequests(kFailedDueToIdentityFailed); | |
| 487 } | |
| 488 | |
| 489 void WebRtcSessionDescriptionFactory::SetCertificate( | |
| 490 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) { | |
| 491 RTC_DCHECK(certificate); | |
| 492 LOG(LS_VERBOSE) << "Setting new certificate."; | |
| 493 | |
| 494 certificate_request_state_ = CERTIFICATE_SUCCEEDED; | |
| 495 SignalCertificateReady(certificate); | |
| 496 | |
| 497 transport_desc_factory_.set_certificate(certificate); | |
| 498 transport_desc_factory_.set_secure(cricket::SEC_ENABLED); | |
| 499 | |
| 500 while (!create_session_description_requests_.empty()) { | |
| 501 if (create_session_description_requests_.front().type == | |
| 502 CreateSessionDescriptionRequest::kOffer) { | |
| 503 InternalCreateOffer(create_session_description_requests_.front()); | |
| 504 } else { | |
| 505 InternalCreateAnswer(create_session_description_requests_.front()); | |
| 506 } | |
| 507 create_session_description_requests_.pop(); | |
| 508 } | |
| 509 } | |
| 510 } // namespace webrtc | |
| OLD | NEW |