1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "content/renderer/media/rtc_peer_connection_handler.h" 6 7 #include <string> 8 #include <utility> 9 #include <vector> 10 11 #include "base/command_line.h" 12 #include "base/debug/trace_event.h" 13 #include "base/lazy_instance.h" 14 #include "base/logging.h" 15 #include "base/memory/scoped_ptr.h" 16 #include "base/metrics/histogram.h" 17 #include "base/stl_util.h" 18 #include "base/strings/utf_string_conversions.h" 19 #include "content/public/common/content_switches.h" 20 #include "content/renderer/media/media_stream_track.h" 21 #include "content/renderer/media/peer_connection_tracker.h" 22 #include "content/renderer/media/remote_media_stream_impl.h" 23 #include "content/renderer/media/rtc_data_channel_handler.h" 24 #include "content/renderer/media/rtc_dtmf_sender_handler.h" 25 #include "content/renderer/media/rtc_media_constraints.h" 26 #include "content/renderer/media/webrtc/peer_connection_dependency_factory.h" 27 #include "content/renderer/media/webrtc/webrtc_media_stream_adapter.h" 28 #include "content/renderer/media/webrtc_audio_capturer.h" 29 #include "content/renderer/media/webrtc_audio_device_impl.h" 30 #include "content/renderer/media/webrtc_uma_histograms.h" 31 #include "content/renderer/render_thread_impl.h" 32 #include "third_party/WebKit/public/platform/WebMediaConstraints.h" 33 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h" 34 #include "third_party/WebKit/public/platform/WebRTCConfiguration.h" 35 #include "third_party/WebKit/public/platform/WebRTCDataChannelInit.h" 36 #include "third_party/WebKit/public/platform/WebRTCICECandidate.h" 37 #include "third_party/WebKit/public/platform/WebRTCOfferOptions.h" 38 #include "third_party/WebKit/public/platform/WebRTCSessionDescription.h" 39 #include "third_party/WebKit/public/platform/WebRTCSessionDescriptionRequest.h" 40 #include "third_party/WebKit/public/platform/WebRTCVoidRequest.h" 41 #include "third_party/WebKit/public/platform/WebURL.h" 42 43 using webrtc::StatsReport; 44 using webrtc::StatsReports; 45 46 namespace content { 47 48 // Converter functions from libjingle types to WebKit types. 49 blink::WebRTCPeerConnectionHandlerClient::ICEGatheringState GetWebKitIceGatheringState(webrtc::PeerConnectionInterface::IceGatheringState state)50 GetWebKitIceGatheringState( 51 webrtc::PeerConnectionInterface::IceGatheringState state) { 52 using blink::WebRTCPeerConnectionHandlerClient; 53 switch (state) { 54 case webrtc::PeerConnectionInterface::kIceGatheringNew: 55 return WebRTCPeerConnectionHandlerClient::ICEGatheringStateNew; 56 case webrtc::PeerConnectionInterface::kIceGatheringGathering: 57 return WebRTCPeerConnectionHandlerClient::ICEGatheringStateGathering; 58 case webrtc::PeerConnectionInterface::kIceGatheringComplete: 59 return WebRTCPeerConnectionHandlerClient::ICEGatheringStateComplete; 60 default: 61 NOTREACHED(); 62 return WebRTCPeerConnectionHandlerClient::ICEGatheringStateNew; 63 } 64 } 65 66 static blink::WebRTCPeerConnectionHandlerClient::ICEConnectionState GetWebKitIceConnectionState(webrtc::PeerConnectionInterface::IceConnectionState ice_state)67 GetWebKitIceConnectionState( 68 webrtc::PeerConnectionInterface::IceConnectionState ice_state) { 69 using blink::WebRTCPeerConnectionHandlerClient; 70 switch (ice_state) { 71 case webrtc::PeerConnectionInterface::kIceConnectionNew: 72 return WebRTCPeerConnectionHandlerClient::ICEConnectionStateStarting; 73 case webrtc::PeerConnectionInterface::kIceConnectionChecking: 74 return WebRTCPeerConnectionHandlerClient::ICEConnectionStateChecking; 75 case webrtc::PeerConnectionInterface::kIceConnectionConnected: 76 return WebRTCPeerConnectionHandlerClient::ICEConnectionStateConnected; 77 case webrtc::PeerConnectionInterface::kIceConnectionCompleted: 78 return WebRTCPeerConnectionHandlerClient::ICEConnectionStateCompleted; 79 case webrtc::PeerConnectionInterface::kIceConnectionFailed: 80 return WebRTCPeerConnectionHandlerClient::ICEConnectionStateFailed; 81 case webrtc::PeerConnectionInterface::kIceConnectionDisconnected: 82 return WebRTCPeerConnectionHandlerClient::ICEConnectionStateDisconnected; 83 case webrtc::PeerConnectionInterface::kIceConnectionClosed: 84 return WebRTCPeerConnectionHandlerClient::ICEConnectionStateClosed; 85 default: 86 NOTREACHED(); 87 return WebRTCPeerConnectionHandlerClient::ICEConnectionStateClosed; 88 } 89 } 90 91 static blink::WebRTCPeerConnectionHandlerClient::SignalingState GetWebKitSignalingState(webrtc::PeerConnectionInterface::SignalingState state)92 GetWebKitSignalingState(webrtc::PeerConnectionInterface::SignalingState state) { 93 using blink::WebRTCPeerConnectionHandlerClient; 94 switch (state) { 95 case webrtc::PeerConnectionInterface::kStable: 96 return WebRTCPeerConnectionHandlerClient::SignalingStateStable; 97 case webrtc::PeerConnectionInterface::kHaveLocalOffer: 98 return WebRTCPeerConnectionHandlerClient::SignalingStateHaveLocalOffer; 99 case webrtc::PeerConnectionInterface::kHaveLocalPrAnswer: 100 return WebRTCPeerConnectionHandlerClient::SignalingStateHaveLocalPrAnswer; 101 case webrtc::PeerConnectionInterface::kHaveRemoteOffer: 102 return WebRTCPeerConnectionHandlerClient::SignalingStateHaveRemoteOffer; 103 case webrtc::PeerConnectionInterface::kHaveRemotePrAnswer: 104 return 105 WebRTCPeerConnectionHandlerClient::SignalingStateHaveRemotePrAnswer; 106 case webrtc::PeerConnectionInterface::kClosed: 107 return WebRTCPeerConnectionHandlerClient::SignalingStateClosed; 108 default: 109 NOTREACHED(); 110 return WebRTCPeerConnectionHandlerClient::SignalingStateClosed; 111 } 112 } 113 114 static blink::WebRTCSessionDescription CreateWebKitSessionDescription(const webrtc::SessionDescriptionInterface * native_desc)115 CreateWebKitSessionDescription( 116 const webrtc::SessionDescriptionInterface* native_desc) { 117 blink::WebRTCSessionDescription description; 118 if (!native_desc) { 119 LOG(ERROR) << "Native session description is null."; 120 return description; 121 } 122 123 std::string sdp; 124 if (!native_desc->ToString(&sdp)) { 125 LOG(ERROR) << "Failed to get SDP string of native session description."; 126 return description; 127 } 128 129 description.initialize(base::UTF8ToUTF16(native_desc->type()), 130 base::UTF8ToUTF16(sdp)); 131 return description; 132 } 133 134 // Converter functions from WebKit types to libjingle types. 135 GetNativeRtcConfiguration(const blink::WebRTCConfiguration & server_configuration,webrtc::PeerConnectionInterface::RTCConfiguration * config)136 static void GetNativeRtcConfiguration( 137 const blink::WebRTCConfiguration& server_configuration, 138 webrtc::PeerConnectionInterface::RTCConfiguration* config) { 139 if (server_configuration.isNull() || !config) 140 return; 141 for (size_t i = 0; i < server_configuration.numberOfServers(); ++i) { 142 webrtc::PeerConnectionInterface::IceServer server; 143 const blink::WebRTCICEServer& webkit_server = 144 server_configuration.server(i); 145 server.username = base::UTF16ToUTF8(webkit_server.username()); 146 server.password = base::UTF16ToUTF8(webkit_server.credential()); 147 server.uri = webkit_server.uri().spec(); 148 config->servers.push_back(server); 149 } 150 151 switch (server_configuration.iceTransports()) { 152 case blink::WebRTCIceTransportsNone: 153 config->type = webrtc::PeerConnectionInterface::kNone; 154 break; 155 case blink::WebRTCIceTransportsRelay: 156 config->type = webrtc::PeerConnectionInterface::kRelay; 157 break; 158 case blink::WebRTCIceTransportsAll: 159 config->type = webrtc::PeerConnectionInterface::kAll; 160 break; 161 default: 162 NOTREACHED(); 163 } 164 } 165 166 class SessionDescriptionRequestTracker { 167 public: SessionDescriptionRequestTracker(RTCPeerConnectionHandler * handler,PeerConnectionTracker::Action action)168 SessionDescriptionRequestTracker(RTCPeerConnectionHandler* handler, 169 PeerConnectionTracker::Action action) 170 : handler_(handler), action_(action) {} 171 TrackOnSuccess(const webrtc::SessionDescriptionInterface * desc)172 void TrackOnSuccess(const webrtc::SessionDescriptionInterface* desc) { 173 std::string value; 174 if (desc) { 175 desc->ToString(&value); 176 value = "type: " + desc->type() + ", sdp: " + value; 177 } 178 if (handler_->peer_connection_tracker()) 179 handler_->peer_connection_tracker()->TrackSessionDescriptionCallback( 180 handler_, action_, "OnSuccess", value); 181 } 182 TrackOnFailure(const std::string & error)183 void TrackOnFailure(const std::string& error) { 184 if (handler_->peer_connection_tracker()) 185 handler_->peer_connection_tracker()->TrackSessionDescriptionCallback( 186 handler_, action_, "OnFailure", error); 187 } 188 189 private: 190 RTCPeerConnectionHandler* handler_; 191 PeerConnectionTracker::Action action_; 192 }; 193 194 // Class mapping responses from calls to libjingle CreateOffer/Answer and 195 // the blink::WebRTCSessionDescriptionRequest. 196 class CreateSessionDescriptionRequest 197 : public webrtc::CreateSessionDescriptionObserver { 198 public: CreateSessionDescriptionRequest(const blink::WebRTCSessionDescriptionRequest & request,RTCPeerConnectionHandler * handler,PeerConnectionTracker::Action action)199 explicit CreateSessionDescriptionRequest( 200 const blink::WebRTCSessionDescriptionRequest& request, 201 RTCPeerConnectionHandler* handler, 202 PeerConnectionTracker::Action action) 203 : webkit_request_(request), tracker_(handler, action) {} 204 OnSuccess(webrtc::SessionDescriptionInterface * desc)205 virtual void OnSuccess(webrtc::SessionDescriptionInterface* desc) OVERRIDE { 206 tracker_.TrackOnSuccess(desc); 207 webkit_request_.requestSucceeded(CreateWebKitSessionDescription(desc)); 208 delete desc; 209 } OnFailure(const std::string & error)210 virtual void OnFailure(const std::string& error) OVERRIDE { 211 tracker_.TrackOnFailure(error); 212 webkit_request_.requestFailed(base::UTF8ToUTF16(error)); 213 } 214 215 protected: ~CreateSessionDescriptionRequest()216 virtual ~CreateSessionDescriptionRequest() {} 217 218 private: 219 blink::WebRTCSessionDescriptionRequest webkit_request_; 220 SessionDescriptionRequestTracker tracker_; 221 }; 222 223 // Class mapping responses from calls to libjingle 224 // SetLocalDescription/SetRemoteDescription and a blink::WebRTCVoidRequest. 225 class SetSessionDescriptionRequest 226 : public webrtc::SetSessionDescriptionObserver { 227 public: SetSessionDescriptionRequest(const blink::WebRTCVoidRequest & request,RTCPeerConnectionHandler * handler,PeerConnectionTracker::Action action)228 explicit SetSessionDescriptionRequest( 229 const blink::WebRTCVoidRequest& request, 230 RTCPeerConnectionHandler* handler, 231 PeerConnectionTracker::Action action) 232 : webkit_request_(request), tracker_(handler, action) {} 233 OnSuccess()234 virtual void OnSuccess() OVERRIDE { 235 tracker_.TrackOnSuccess(NULL); 236 webkit_request_.requestSucceeded(); 237 } OnFailure(const std::string & error)238 virtual void OnFailure(const std::string& error) OVERRIDE { 239 tracker_.TrackOnFailure(error); 240 webkit_request_.requestFailed(base::UTF8ToUTF16(error)); 241 } 242 243 protected: ~SetSessionDescriptionRequest()244 virtual ~SetSessionDescriptionRequest() {} 245 246 private: 247 blink::WebRTCVoidRequest webkit_request_; 248 SessionDescriptionRequestTracker tracker_; 249 }; 250 251 // Class mapping responses from calls to libjingle 252 // GetStats into a blink::WebRTCStatsCallback. 253 class StatsResponse : public webrtc::StatsObserver { 254 public: StatsResponse(const scoped_refptr<LocalRTCStatsRequest> & request)255 explicit StatsResponse(const scoped_refptr<LocalRTCStatsRequest>& request) 256 : request_(request.get()), response_(request_->createResponse().get()) { 257 // Measure the overall time it takes to satisfy a getStats request. 258 TRACE_EVENT_ASYNC_BEGIN0("webrtc", "getStats_Native", this); 259 } 260 OnComplete(const StatsReports & reports)261 virtual void OnComplete(const StatsReports& reports) OVERRIDE { 262 TRACE_EVENT0("webrtc", "StatsResponse::OnComplete") 263 for (StatsReports::const_iterator it = reports.begin(); 264 it != reports.end(); ++it) { 265 if ((*it)->values.size() > 0) { 266 AddReport(*(*it)); 267 } 268 } 269 270 // Record the getSync operation as done before calling into Blink so that 271 // we don't skew the perf measurements of the native code with whatever the 272 // callback might be doing. 273 TRACE_EVENT_ASYNC_END0("webrtc", "getStats_Native", this); 274 275 request_->requestSucceeded(response_); 276 } 277 278 private: AddReport(const StatsReport & report)279 void AddReport(const StatsReport& report) { 280 int idx = response_->addReport(blink::WebString::fromUTF8(report.id), 281 blink::WebString::fromUTF8(report.type), 282 report.timestamp); 283 for (StatsReport::Values::const_iterator value_it = report.values.begin(); 284 value_it != report.values.end(); ++value_it) { 285 AddStatistic(idx, value_it->display_name(), value_it->value); 286 } 287 } 288 AddStatistic(int idx,const char * name,const std::string & value)289 void AddStatistic(int idx, const char* name, const std::string& value) { 290 response_->addStatistic(idx, 291 blink::WebString::fromUTF8(name), 292 blink::WebString::fromUTF8(value)); 293 } 294 295 rtc::scoped_refptr<LocalRTCStatsRequest> request_; 296 rtc::scoped_refptr<LocalRTCStatsResponse> response_; 297 }; 298 299 // Implementation of LocalRTCStatsRequest. LocalRTCStatsRequest(blink::WebRTCStatsRequest impl)300 LocalRTCStatsRequest::LocalRTCStatsRequest(blink::WebRTCStatsRequest impl) 301 : impl_(impl), 302 response_(NULL) { 303 } 304 LocalRTCStatsRequest()305 LocalRTCStatsRequest::LocalRTCStatsRequest() {} ~LocalRTCStatsRequest()306 LocalRTCStatsRequest::~LocalRTCStatsRequest() {} 307 hasSelector() const308 bool LocalRTCStatsRequest::hasSelector() const { 309 return impl_.hasSelector(); 310 } 311 component() const312 blink::WebMediaStreamTrack LocalRTCStatsRequest::component() const { 313 return impl_.component(); 314 } 315 createResponse()316 scoped_refptr<LocalRTCStatsResponse> LocalRTCStatsRequest::createResponse() { 317 DCHECK(!response_); 318 response_ = new rtc::RefCountedObject<LocalRTCStatsResponse>( 319 impl_.createResponse()); 320 return response_.get(); 321 } 322 requestSucceeded(const LocalRTCStatsResponse * response)323 void LocalRTCStatsRequest::requestSucceeded( 324 const LocalRTCStatsResponse* response) { 325 impl_.requestSucceeded(response->webKitStatsResponse()); 326 } 327 328 // Implementation of LocalRTCStatsResponse. webKitStatsResponse() const329 blink::WebRTCStatsResponse LocalRTCStatsResponse::webKitStatsResponse() const { 330 return impl_; 331 } 332 addReport(blink::WebString type,blink::WebString id,double timestamp)333 size_t LocalRTCStatsResponse::addReport(blink::WebString type, 334 blink::WebString id, 335 double timestamp) { 336 return impl_.addReport(type, id, timestamp); 337 } 338 addStatistic(size_t report,blink::WebString name,blink::WebString value)339 void LocalRTCStatsResponse::addStatistic(size_t report, 340 blink::WebString name, 341 blink::WebString value) { 342 impl_.addStatistic(report, name, value); 343 } 344 345 namespace { 346 347 class PeerConnectionUMAObserver : public webrtc::UMAObserver { 348 public: PeerConnectionUMAObserver()349 PeerConnectionUMAObserver() {} ~PeerConnectionUMAObserver()350 virtual ~PeerConnectionUMAObserver() {} 351 IncrementCounter(webrtc::PeerConnectionUMAMetricsCounter counter)352 virtual void IncrementCounter( 353 webrtc::PeerConnectionUMAMetricsCounter counter) OVERRIDE { 354 UMA_HISTOGRAM_ENUMERATION("WebRTC.PeerConnection.IPMetrics", 355 counter, 356 webrtc::kBoundary); 357 } 358 AddHistogramSample(webrtc::PeerConnectionUMAMetricsName type,int value)359 virtual void AddHistogramSample( 360 webrtc::PeerConnectionUMAMetricsName type, int value) OVERRIDE { 361 switch (type) { 362 case webrtc::kTimeToConnect: 363 UMA_HISTOGRAM_MEDIUM_TIMES( 364 "WebRTC.PeerConnection.TimeToConnect", 365 base::TimeDelta::FromMilliseconds(value)); 366 break; 367 case webrtc::kNetworkInterfaces_IPv4: 368 UMA_HISTOGRAM_COUNTS_100("WebRTC.PeerConnection.IPv4Interfaces", 369 value); 370 break; 371 case webrtc::kNetworkInterfaces_IPv6: 372 UMA_HISTOGRAM_COUNTS_100("WebRTC.PeerConnection.IPv6Interfaces", 373 value); 374 break; 375 default: 376 NOTREACHED(); 377 } 378 } 379 }; 380 381 base::LazyInstance<std::set<RTCPeerConnectionHandler*> >::Leaky 382 g_peer_connection_handlers = LAZY_INSTANCE_INITIALIZER; 383 384 } // namespace 385 RTCPeerConnectionHandler(blink::WebRTCPeerConnectionHandlerClient * client,PeerConnectionDependencyFactory * dependency_factory)386 RTCPeerConnectionHandler::RTCPeerConnectionHandler( 387 blink::WebRTCPeerConnectionHandlerClient* client, 388 PeerConnectionDependencyFactory* dependency_factory) 389 : client_(client), 390 dependency_factory_(dependency_factory), 391 frame_(NULL), 392 peer_connection_tracker_(NULL), 393 num_data_channels_created_(0), 394 num_local_candidates_ipv4_(0), 395 num_local_candidates_ipv6_(0) { 396 g_peer_connection_handlers.Get().insert(this); 397 } 398 ~RTCPeerConnectionHandler()399 RTCPeerConnectionHandler::~RTCPeerConnectionHandler() { 400 g_peer_connection_handlers.Get().erase(this); 401 if (peer_connection_tracker_) 402 peer_connection_tracker_->UnregisterPeerConnection(this); 403 STLDeleteValues(&remote_streams_); 404 405 UMA_HISTOGRAM_COUNTS_10000( 406 "WebRTC.NumDataChannelsPerPeerConnection", num_data_channels_created_); 407 } 408 409 // static DestructAllHandlers()410 void RTCPeerConnectionHandler::DestructAllHandlers() { 411 std::set<RTCPeerConnectionHandler*> handlers( 412 g_peer_connection_handlers.Get().begin(), 413 g_peer_connection_handlers.Get().end()); 414 for (std::set<RTCPeerConnectionHandler*>::iterator handler = handlers.begin(); 415 handler != handlers.end(); 416 ++handler) { 417 (*handler)->client_->releasePeerConnectionHandler(); 418 } 419 } 420 ConvertOfferOptionsToConstraints(const blink::WebRTCOfferOptions & options,RTCMediaConstraints * output)421 void RTCPeerConnectionHandler::ConvertOfferOptionsToConstraints( 422 const blink::WebRTCOfferOptions& options, 423 RTCMediaConstraints* output) { 424 output->AddMandatory( 425 webrtc::MediaConstraintsInterface::kOfferToReceiveAudio, 426 options.offerToReceiveAudio() > 0 ? "true" : "false", 427 true); 428 429 output->AddMandatory( 430 webrtc::MediaConstraintsInterface::kOfferToReceiveVideo, 431 options.offerToReceiveVideo() > 0 ? "true" : "false", 432 true); 433 434 if (!options.voiceActivityDetection()) { 435 output->AddMandatory( 436 webrtc::MediaConstraintsInterface::kVoiceActivityDetection, 437 "false", 438 true); 439 } 440 441 if (options.iceRestart()) { 442 output->AddMandatory( 443 webrtc::MediaConstraintsInterface::kIceRestart, "true", true); 444 } 445 } 446 associateWithFrame(blink::WebFrame * frame)447 void RTCPeerConnectionHandler::associateWithFrame(blink::WebFrame* frame) { 448 DCHECK(frame); 449 frame_ = frame; 450 } 451 initialize(const blink::WebRTCConfiguration & server_configuration,const blink::WebMediaConstraints & options)452 bool RTCPeerConnectionHandler::initialize( 453 const blink::WebRTCConfiguration& server_configuration, 454 const blink::WebMediaConstraints& options) { 455 DCHECK(frame_); 456 457 peer_connection_tracker_ = 458 RenderThreadImpl::current()->peer_connection_tracker(); 459 460 webrtc::PeerConnectionInterface::RTCConfiguration config; 461 GetNativeRtcConfiguration(server_configuration, &config); 462 463 RTCMediaConstraints constraints(options); 464 465 native_peer_connection_ = 466 dependency_factory_->CreatePeerConnection( 467 config, &constraints, frame_, this); 468 469 if (!native_peer_connection_.get()) { 470 LOG(ERROR) << "Failed to initialize native PeerConnection."; 471 return false; 472 } 473 if (peer_connection_tracker_) 474 peer_connection_tracker_->RegisterPeerConnection( 475 this, config, constraints, frame_); 476 477 uma_observer_ = new rtc::RefCountedObject<PeerConnectionUMAObserver>(); 478 native_peer_connection_->RegisterUMAObserver(uma_observer_.get()); 479 return true; 480 } 481 InitializeForTest(const blink::WebRTCConfiguration & server_configuration,const blink::WebMediaConstraints & options,PeerConnectionTracker * peer_connection_tracker)482 bool RTCPeerConnectionHandler::InitializeForTest( 483 const blink::WebRTCConfiguration& server_configuration, 484 const blink::WebMediaConstraints& options, 485 PeerConnectionTracker* peer_connection_tracker) { 486 webrtc::PeerConnectionInterface::RTCConfiguration config; 487 GetNativeRtcConfiguration(server_configuration, &config); 488 489 RTCMediaConstraints constraints(options); 490 native_peer_connection_ = 491 dependency_factory_->CreatePeerConnection( 492 config, &constraints, NULL, this); 493 if (!native_peer_connection_.get()) { 494 LOG(ERROR) << "Failed to initialize native PeerConnection."; 495 return false; 496 } 497 peer_connection_tracker_ = peer_connection_tracker; 498 return true; 499 } 500 createOffer(const blink::WebRTCSessionDescriptionRequest & request,const blink::WebMediaConstraints & options)501 void RTCPeerConnectionHandler::createOffer( 502 const blink::WebRTCSessionDescriptionRequest& request, 503 const blink::WebMediaConstraints& options) { 504 scoped_refptr<CreateSessionDescriptionRequest> description_request( 505 new rtc::RefCountedObject<CreateSessionDescriptionRequest>( 506 request, this, PeerConnectionTracker::ACTION_CREATE_OFFER)); 507 RTCMediaConstraints constraints(options); 508 native_peer_connection_->CreateOffer(description_request.get(), &constraints); 509 510 if (peer_connection_tracker_) 511 peer_connection_tracker_->TrackCreateOffer(this, constraints); 512 } 513 createOffer(const blink::WebRTCSessionDescriptionRequest & request,const blink::WebRTCOfferOptions & options)514 void RTCPeerConnectionHandler::createOffer( 515 const blink::WebRTCSessionDescriptionRequest& request, 516 const blink::WebRTCOfferOptions& options) { 517 scoped_refptr<CreateSessionDescriptionRequest> description_request( 518 new rtc::RefCountedObject<CreateSessionDescriptionRequest>( 519 request, this, PeerConnectionTracker::ACTION_CREATE_OFFER)); 520 521 RTCMediaConstraints constraints; 522 ConvertOfferOptionsToConstraints(options, &constraints); 523 native_peer_connection_->CreateOffer(description_request.get(), &constraints); 524 525 if (peer_connection_tracker_) 526 peer_connection_tracker_->TrackCreateOffer(this, constraints); 527 } 528 createAnswer(const blink::WebRTCSessionDescriptionRequest & request,const blink::WebMediaConstraints & options)529 void RTCPeerConnectionHandler::createAnswer( 530 const blink::WebRTCSessionDescriptionRequest& request, 531 const blink::WebMediaConstraints& options) { 532 scoped_refptr<CreateSessionDescriptionRequest> description_request( 533 new rtc::RefCountedObject<CreateSessionDescriptionRequest>( 534 request, this, PeerConnectionTracker::ACTION_CREATE_ANSWER)); 535 RTCMediaConstraints constraints(options); 536 native_peer_connection_->CreateAnswer(description_request.get(), 537 &constraints); 538 539 if (peer_connection_tracker_) 540 peer_connection_tracker_->TrackCreateAnswer(this, constraints); 541 } 542 setLocalDescription(const blink::WebRTCVoidRequest & request,const blink::WebRTCSessionDescription & description)543 void RTCPeerConnectionHandler::setLocalDescription( 544 const blink::WebRTCVoidRequest& request, 545 const blink::WebRTCSessionDescription& description) { 546 webrtc::SdpParseError error; 547 webrtc::SessionDescriptionInterface* native_desc = 548 CreateNativeSessionDescription(description, &error); 549 if (!native_desc) { 550 std::string reason_str = "Failed to parse SessionDescription. "; 551 reason_str.append(error.line); 552 reason_str.append(" "); 553 reason_str.append(error.description); 554 LOG(ERROR) << reason_str; 555 request.requestFailed(blink::WebString::fromUTF8(reason_str)); 556 return; 557 } 558 if (peer_connection_tracker_) 559 peer_connection_tracker_->TrackSetSessionDescription( 560 this, description, PeerConnectionTracker::SOURCE_LOCAL); 561 562 scoped_refptr<SetSessionDescriptionRequest> set_request( 563 new rtc::RefCountedObject<SetSessionDescriptionRequest>( 564 request, this, PeerConnectionTracker::ACTION_SET_LOCAL_DESCRIPTION)); 565 native_peer_connection_->SetLocalDescription(set_request.get(), native_desc); 566 } 567 setRemoteDescription(const blink::WebRTCVoidRequest & request,const blink::WebRTCSessionDescription & description)568 void RTCPeerConnectionHandler::setRemoteDescription( 569 const blink::WebRTCVoidRequest& request, 570 const blink::WebRTCSessionDescription& description) { 571 webrtc::SdpParseError error; 572 webrtc::SessionDescriptionInterface* native_desc = 573 CreateNativeSessionDescription(description, &error); 574 if (!native_desc) { 575 std::string reason_str = "Failed to parse SessionDescription. "; 576 reason_str.append(error.line); 577 reason_str.append(" "); 578 reason_str.append(error.description); 579 LOG(ERROR) << reason_str; 580 request.requestFailed(blink::WebString::fromUTF8(reason_str)); 581 return; 582 } 583 if (peer_connection_tracker_) 584 peer_connection_tracker_->TrackSetSessionDescription( 585 this, description, PeerConnectionTracker::SOURCE_REMOTE); 586 587 scoped_refptr<SetSessionDescriptionRequest> set_request( 588 new rtc::RefCountedObject<SetSessionDescriptionRequest>( 589 request, this, PeerConnectionTracker::ACTION_SET_REMOTE_DESCRIPTION)); 590 native_peer_connection_->SetRemoteDescription(set_request.get(), native_desc); 591 } 592 593 blink::WebRTCSessionDescription localDescription()594 RTCPeerConnectionHandler::localDescription() { 595 const webrtc::SessionDescriptionInterface* native_desc = 596 native_peer_connection_->local_description(); 597 blink::WebRTCSessionDescription description = 598 CreateWebKitSessionDescription(native_desc); 599 return description; 600 } 601 602 blink::WebRTCSessionDescription remoteDescription()603 RTCPeerConnectionHandler::remoteDescription() { 604 const webrtc::SessionDescriptionInterface* native_desc = 605 native_peer_connection_->remote_description(); 606 blink::WebRTCSessionDescription description = 607 CreateWebKitSessionDescription(native_desc); 608 return description; 609 } 610 updateICE(const blink::WebRTCConfiguration & server_configuration,const blink::WebMediaConstraints & options)611 bool RTCPeerConnectionHandler::updateICE( 612 const blink::WebRTCConfiguration& server_configuration, 613 const blink::WebMediaConstraints& options) { 614 webrtc::PeerConnectionInterface::RTCConfiguration config; 615 GetNativeRtcConfiguration(server_configuration, &config); 616 RTCMediaConstraints constraints(options); 617 618 if (peer_connection_tracker_) 619 peer_connection_tracker_->TrackUpdateIce(this, config, constraints); 620 621 return native_peer_connection_->UpdateIce(config.servers, 622 &constraints); 623 } 624 addICECandidate(const blink::WebRTCVoidRequest & request,const blink::WebRTCICECandidate & candidate)625 bool RTCPeerConnectionHandler::addICECandidate( 626 const blink::WebRTCVoidRequest& request, 627 const blink::WebRTCICECandidate& candidate) { 628 // Libjingle currently does not accept callbacks for addICECandidate. 629 // For that reason we are going to call callbacks from here. 630 bool result = addICECandidate(candidate); 631 base::MessageLoop::current()->PostTask( 632 FROM_HERE, 633 base::Bind(&RTCPeerConnectionHandler::OnaddICECandidateResult, 634 base::Unretained(this), request, result)); 635 // On failure callback will be triggered. 636 return true; 637 } 638 addICECandidate(const blink::WebRTCICECandidate & candidate)639 bool RTCPeerConnectionHandler::addICECandidate( 640 const blink::WebRTCICECandidate& candidate) { 641 scoped_ptr<webrtc::IceCandidateInterface> native_candidate( 642 dependency_factory_->CreateIceCandidate( 643 base::UTF16ToUTF8(candidate.sdpMid()), 644 candidate.sdpMLineIndex(), 645 base::UTF16ToUTF8(candidate.candidate()))); 646 bool return_value = false; 647 648 if (native_candidate) { 649 return_value = 650 native_peer_connection_->AddIceCandidate(native_candidate.get()); 651 LOG_IF(ERROR, !return_value) << "Error processing ICE candidate."; 652 } else { 653 LOG(ERROR) << "Could not create native ICE candidate."; 654 } 655 656 if (peer_connection_tracker_) { 657 peer_connection_tracker_->TrackAddIceCandidate( 658 this, candidate, PeerConnectionTracker::SOURCE_REMOTE, return_value); 659 } 660 return return_value; 661 } 662 OnaddICECandidateResult(const blink::WebRTCVoidRequest & webkit_request,bool result)663 void RTCPeerConnectionHandler::OnaddICECandidateResult( 664 const blink::WebRTCVoidRequest& webkit_request, bool result) { 665 if (!result) { 666 // We don't have the actual error code from the libjingle, so for now 667 // using a generic error string. 668 return webkit_request.requestFailed( 669 base::UTF8ToUTF16("Error processing ICE candidate")); 670 } 671 672 return webkit_request.requestSucceeded(); 673 } 674 addStream(const blink::WebMediaStream & stream,const blink::WebMediaConstraints & options)675 bool RTCPeerConnectionHandler::addStream( 676 const blink::WebMediaStream& stream, 677 const blink::WebMediaConstraints& options) { 678 679 for (ScopedVector<WebRtcMediaStreamAdapter>::iterator adapter_it = 680 local_streams_.begin(); adapter_it != local_streams_.end(); 681 ++adapter_it) { 682 if ((*adapter_it)->IsEqual(stream)) { 683 DVLOG(1) << "RTCPeerConnectionHandler::addStream called with the same " 684 << "stream twice. id=" << stream.id().utf8(); 685 return false; 686 } 687 } 688 689 if (peer_connection_tracker_) 690 peer_connection_tracker_->TrackAddStream( 691 this, stream, PeerConnectionTracker::SOURCE_LOCAL); 692 693 PerSessionWebRTCAPIMetrics::GetInstance()->IncrementStreamCounter(); 694 695 WebRtcMediaStreamAdapter* adapter = 696 new WebRtcMediaStreamAdapter(stream, dependency_factory_); 697 local_streams_.push_back(adapter); 698 699 webrtc::MediaStreamInterface* webrtc_stream = adapter->webrtc_media_stream(); 700 track_metrics_.AddStream(MediaStreamTrackMetrics::SENT_STREAM, 701 webrtc_stream); 702 703 RTCMediaConstraints constraints(options); 704 return native_peer_connection_->AddStream(webrtc_stream, &constraints); 705 } 706 removeStream(const blink::WebMediaStream & stream)707 void RTCPeerConnectionHandler::removeStream( 708 const blink::WebMediaStream& stream) { 709 // Find the webrtc stream. 710 scoped_refptr<webrtc::MediaStreamInterface> webrtc_stream; 711 for (ScopedVector<WebRtcMediaStreamAdapter>::iterator adapter_it = 712 local_streams_.begin(); adapter_it != local_streams_.end(); 713 ++adapter_it) { 714 if ((*adapter_it)->IsEqual(stream)) { 715 webrtc_stream = (*adapter_it)->webrtc_media_stream(); 716 local_streams_.erase(adapter_it); 717 break; 718 } 719 } 720 DCHECK(webrtc_stream.get()); 721 native_peer_connection_->RemoveStream(webrtc_stream.get()); 722 723 if (peer_connection_tracker_) 724 peer_connection_tracker_->TrackRemoveStream( 725 this, stream, PeerConnectionTracker::SOURCE_LOCAL); 726 PerSessionWebRTCAPIMetrics::GetInstance()->DecrementStreamCounter(); 727 track_metrics_.RemoveStream(MediaStreamTrackMetrics::SENT_STREAM, 728 webrtc_stream.get()); 729 } 730 getStats(const blink::WebRTCStatsRequest & request)731 void RTCPeerConnectionHandler::getStats( 732 const blink::WebRTCStatsRequest& request) { 733 scoped_refptr<LocalRTCStatsRequest> inner_request( 734 new rtc::RefCountedObject<LocalRTCStatsRequest>(request)); 735 getStats(inner_request.get()); 736 } 737 getStats(LocalRTCStatsRequest * request)738 void RTCPeerConnectionHandler::getStats(LocalRTCStatsRequest* request) { 739 rtc::scoped_refptr<webrtc::StatsObserver> observer( 740 new rtc::RefCountedObject<StatsResponse>(request)); 741 webrtc::MediaStreamTrackInterface* track = NULL; 742 if (request->hasSelector()) { 743 blink::WebMediaStreamSource::Type type = 744 request->component().source().type(); 745 std::string track_id = request->component().id().utf8(); 746 if (type == blink::WebMediaStreamSource::TypeAudio) { 747 track = 748 native_peer_connection_->local_streams()->FindAudioTrack(track_id); 749 if (!track) { 750 track = 751 native_peer_connection_->remote_streams()->FindAudioTrack(track_id); 752 } 753 } else { 754 DCHECK_EQ(blink::WebMediaStreamSource::TypeVideo, type); 755 track = 756 native_peer_connection_->local_streams()->FindVideoTrack(track_id); 757 if (!track) { 758 track = 759 native_peer_connection_->remote_streams()->FindVideoTrack(track_id); 760 } 761 } 762 if (!track) { 763 DVLOG(1) << "GetStats: Track not found."; 764 // TODO(hta): Consider how to get an error back. 765 observer->OnComplete(StatsReports()); 766 return; 767 } 768 } 769 GetStats(observer, 770 track, 771 webrtc::PeerConnectionInterface::kStatsOutputLevelStandard); 772 } 773 GetStats(webrtc::StatsObserver * observer,webrtc::MediaStreamTrackInterface * track,webrtc::PeerConnectionInterface::StatsOutputLevel level)774 void RTCPeerConnectionHandler::GetStats( 775 webrtc::StatsObserver* observer, 776 webrtc::MediaStreamTrackInterface* track, 777 webrtc::PeerConnectionInterface::StatsOutputLevel level) { 778 TRACE_EVENT0("webrtc", "RTCPeerConnectionHandler::GetStats"); 779 if (!native_peer_connection_->GetStats(observer, track, level)) { 780 DVLOG(1) << "GetStats failed."; 781 // TODO(hta): Consider how to get an error back. 782 observer->OnComplete(StatsReports()); 783 return; 784 } 785 } 786 CloseClientPeerConnection()787 void RTCPeerConnectionHandler::CloseClientPeerConnection() { 788 client_->closePeerConnection(); 789 } 790 createDataChannel(const blink::WebString & label,const blink::WebRTCDataChannelInit & init)791 blink::WebRTCDataChannelHandler* RTCPeerConnectionHandler::createDataChannel( 792 const blink::WebString& label, const blink::WebRTCDataChannelInit& init) { 793 DVLOG(1) << "createDataChannel label " << base::UTF16ToUTF8(label); 794 795 webrtc::DataChannelInit config; 796 // TODO(jiayl): remove the deprecated reliable field once Libjingle is updated 797 // to handle that. 798 config.reliable = false; 799 config.id = init.id; 800 config.ordered = init.ordered; 801 config.negotiated = init.negotiated; 802 config.maxRetransmits = init.maxRetransmits; 803 config.maxRetransmitTime = init.maxRetransmitTime; 804 config.protocol = base::UTF16ToUTF8(init.protocol); 805 806 rtc::scoped_refptr<webrtc::DataChannelInterface> webrtc_channel( 807 native_peer_connection_->CreateDataChannel(base::UTF16ToUTF8(label), 808 &config)); 809 if (!webrtc_channel) { 810 DLOG(ERROR) << "Could not create native data channel."; 811 return NULL; 812 } 813 if (peer_connection_tracker_) 814 peer_connection_tracker_->TrackCreateDataChannel( 815 this, webrtc_channel.get(), PeerConnectionTracker::SOURCE_LOCAL); 816 817 ++num_data_channels_created_; 818 819 return new RtcDataChannelHandler(webrtc_channel); 820 } 821 createDTMFSender(const blink::WebMediaStreamTrack & track)822 blink::WebRTCDTMFSenderHandler* RTCPeerConnectionHandler::createDTMFSender( 823 const blink::WebMediaStreamTrack& track) { 824 DVLOG(1) << "createDTMFSender."; 825 826 MediaStreamTrack* native_track = MediaStreamTrack::GetTrack(track); 827 if (!native_track || 828 track.source().type() != blink::WebMediaStreamSource::TypeAudio) { 829 DLOG(ERROR) << "Could not create DTMF sender from a non-audio track."; 830 return NULL; 831 } 832 833 webrtc::AudioTrackInterface* audio_track = native_track->GetAudioAdapter(); 834 rtc::scoped_refptr<webrtc::DtmfSenderInterface> sender( 835 native_peer_connection_->CreateDtmfSender(audio_track)); 836 if (!sender) { 837 DLOG(ERROR) << "Could not create native DTMF sender."; 838 return NULL; 839 } 840 if (peer_connection_tracker_) 841 peer_connection_tracker_->TrackCreateDTMFSender(this, track); 842 843 return new RtcDtmfSenderHandler(sender); 844 } 845 stop()846 void RTCPeerConnectionHandler::stop() { 847 DVLOG(1) << "RTCPeerConnectionHandler::stop"; 848 849 if (peer_connection_tracker_) 850 peer_connection_tracker_->TrackStop(this); 851 native_peer_connection_->Close(); 852 } 853 OnError()854 void RTCPeerConnectionHandler::OnError() { 855 // TODO(perkj): Implement. 856 NOTIMPLEMENTED(); 857 } 858 OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState new_state)859 void RTCPeerConnectionHandler::OnSignalingChange( 860 webrtc::PeerConnectionInterface::SignalingState new_state) { 861 blink::WebRTCPeerConnectionHandlerClient::SignalingState state = 862 GetWebKitSignalingState(new_state); 863 if (peer_connection_tracker_) 864 peer_connection_tracker_->TrackSignalingStateChange(this, state); 865 client_->didChangeSignalingState(state); 866 } 867 868 // Called any time the IceConnectionState changes OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState new_state)869 void RTCPeerConnectionHandler::OnIceConnectionChange( 870 webrtc::PeerConnectionInterface::IceConnectionState new_state) { 871 if (new_state == webrtc::PeerConnectionInterface::kIceConnectionChecking) { 872 ice_connection_checking_start_ = base::TimeTicks::Now(); 873 } else if (new_state == 874 webrtc::PeerConnectionInterface::kIceConnectionConnected) { 875 // If the state becomes connected, send the time needed for PC to become 876 // connected from checking to UMA. UMA data will help to know how much 877 // time needed for PC to connect with remote peer. 878 UMA_HISTOGRAM_MEDIUM_TIMES( 879 "WebRTC.PeerConnection.TimeToConnect", 880 base::TimeTicks::Now() - ice_connection_checking_start_); 881 } 882 883 track_metrics_.IceConnectionChange(new_state); 884 blink::WebRTCPeerConnectionHandlerClient::ICEConnectionState state = 885 GetWebKitIceConnectionState(new_state); 886 if (peer_connection_tracker_) 887 peer_connection_tracker_->TrackIceConnectionStateChange(this, state); 888 client_->didChangeICEConnectionState(state); 889 } 890 891 // Called any time the IceGatheringState changes OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState new_state)892 void RTCPeerConnectionHandler::OnIceGatheringChange( 893 webrtc::PeerConnectionInterface::IceGatheringState new_state) { 894 if (new_state == webrtc::PeerConnectionInterface::kIceGatheringComplete) { 895 // If ICE gathering is completed, generate a NULL ICE candidate, 896 // to signal end of candidates. 897 blink::WebRTCICECandidate null_candidate; 898 client_->didGenerateICECandidate(null_candidate); 899 900 UMA_HISTOGRAM_COUNTS_100("WebRTC.PeerConnection.IPv4LocalCandidates", 901 num_local_candidates_ipv4_); 902 903 UMA_HISTOGRAM_COUNTS_100("WebRTC.PeerConnection.IPv6LocalCandidates", 904 num_local_candidates_ipv6_); 905 } else if (new_state == 906 webrtc::PeerConnectionInterface::kIceGatheringGathering) { 907 // ICE restarts will change gathering state back to "gathering", 908 // reset the counter. 909 num_local_candidates_ipv6_ = 0; 910 num_local_candidates_ipv4_ = 0; 911 } 912 913 blink::WebRTCPeerConnectionHandlerClient::ICEGatheringState state = 914 GetWebKitIceGatheringState(new_state); 915 if (peer_connection_tracker_) 916 peer_connection_tracker_->TrackIceGatheringStateChange(this, state); 917 client_->didChangeICEGatheringState(state); 918 } 919 OnAddStream(webrtc::MediaStreamInterface * stream_interface)920 void RTCPeerConnectionHandler::OnAddStream( 921 webrtc::MediaStreamInterface* stream_interface) { 922 DCHECK(stream_interface); 923 DCHECK(remote_streams_.find(stream_interface) == remote_streams_.end()); 924 925 RemoteMediaStreamImpl* remote_stream = 926 new RemoteMediaStreamImpl(stream_interface); 927 remote_streams_.insert( 928 std::pair<webrtc::MediaStreamInterface*, RemoteMediaStreamImpl*> ( 929 stream_interface, remote_stream)); 930 931 if (peer_connection_tracker_) 932 peer_connection_tracker_->TrackAddStream( 933 this, remote_stream->webkit_stream(), 934 PeerConnectionTracker::SOURCE_REMOTE); 935 936 PerSessionWebRTCAPIMetrics::GetInstance()->IncrementStreamCounter(); 937 938 track_metrics_.AddStream(MediaStreamTrackMetrics::RECEIVED_STREAM, 939 stream_interface); 940 941 client_->didAddRemoteStream(remote_stream->webkit_stream()); 942 } 943 OnRemoveStream(webrtc::MediaStreamInterface * stream_interface)944 void RTCPeerConnectionHandler::OnRemoveStream( 945 webrtc::MediaStreamInterface* stream_interface) { 946 DCHECK(stream_interface); 947 RemoteStreamMap::iterator it = remote_streams_.find(stream_interface); 948 if (it == remote_streams_.end()) { 949 NOTREACHED() << "Stream not found"; 950 return; 951 } 952 953 track_metrics_.RemoveStream(MediaStreamTrackMetrics::RECEIVED_STREAM, 954 stream_interface); 955 PerSessionWebRTCAPIMetrics::GetInstance()->DecrementStreamCounter(); 956 957 scoped_ptr<RemoteMediaStreamImpl> remote_stream(it->second); 958 const blink::WebMediaStream& webkit_stream = remote_stream->webkit_stream(); 959 DCHECK(!webkit_stream.isNull()); 960 remote_streams_.erase(it); 961 962 if (peer_connection_tracker_) 963 peer_connection_tracker_->TrackRemoveStream( 964 this, webkit_stream, PeerConnectionTracker::SOURCE_REMOTE); 965 966 client_->didRemoveRemoteStream(webkit_stream); 967 } 968 OnIceCandidate(const webrtc::IceCandidateInterface * candidate)969 void RTCPeerConnectionHandler::OnIceCandidate( 970 const webrtc::IceCandidateInterface* candidate) { 971 DCHECK(candidate); 972 std::string sdp; 973 if (!candidate->ToString(&sdp)) { 974 NOTREACHED() << "OnIceCandidate: Could not get SDP string."; 975 return; 976 } 977 blink::WebRTCICECandidate web_candidate; 978 web_candidate.initialize(base::UTF8ToUTF16(sdp), 979 base::UTF8ToUTF16(candidate->sdp_mid()), 980 candidate->sdp_mline_index()); 981 if (peer_connection_tracker_) 982 peer_connection_tracker_->TrackAddIceCandidate( 983 this, web_candidate, PeerConnectionTracker::SOURCE_LOCAL, true); 984 985 // Only the first m line's first component is tracked to avoid 986 // miscounting when doing BUNDLE or rtcp mux. 987 if (candidate->sdp_mline_index() == 0 && 988 candidate->candidate().component() == 1) { 989 if (candidate->candidate().address().family() == AF_INET) { 990 num_local_candidates_ipv4_++; 991 } else if (candidate->candidate().address().family() == AF_INET6) { 992 num_local_candidates_ipv6_++; 993 } else { 994 NOTREACHED(); 995 } 996 } 997 client_->didGenerateICECandidate(web_candidate); 998 } 999 OnDataChannel(webrtc::DataChannelInterface * data_channel)1000 void RTCPeerConnectionHandler::OnDataChannel( 1001 webrtc::DataChannelInterface* data_channel) { 1002 if (peer_connection_tracker_) 1003 peer_connection_tracker_->TrackCreateDataChannel( 1004 this, data_channel, PeerConnectionTracker::SOURCE_REMOTE); 1005 1006 DVLOG(1) << "RTCPeerConnectionHandler::OnDataChannel " 1007 << data_channel->label(); 1008 client_->didAddRemoteDataChannel(new RtcDataChannelHandler(data_channel)); 1009 } 1010 OnRenegotiationNeeded()1011 void RTCPeerConnectionHandler::OnRenegotiationNeeded() { 1012 if (peer_connection_tracker_) 1013 peer_connection_tracker_->TrackOnRenegotiationNeeded(this); 1014 client_->negotiationNeeded(); 1015 } 1016 peer_connection_tracker()1017 PeerConnectionTracker* RTCPeerConnectionHandler::peer_connection_tracker() { 1018 return peer_connection_tracker_; 1019 } 1020 1021 webrtc::SessionDescriptionInterface* CreateNativeSessionDescription(const blink::WebRTCSessionDescription & description,webrtc::SdpParseError * error)1022 RTCPeerConnectionHandler::CreateNativeSessionDescription( 1023 const blink::WebRTCSessionDescription& description, 1024 webrtc::SdpParseError* error) { 1025 std::string sdp = base::UTF16ToUTF8(description.sdp()); 1026 std::string type = base::UTF16ToUTF8(description.type()); 1027 webrtc::SessionDescriptionInterface* native_desc = 1028 dependency_factory_->CreateSessionDescription(type, sdp, error); 1029 1030 LOG_IF(ERROR, !native_desc) << "Failed to create native session description." 1031 << " Type: " << type << " SDP: " << sdp; 1032 1033 return native_desc; 1034 } 1035 1036 } // namespace content 1037