1 // Copyright (c) 2013 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 #include "content/renderer/media/peer_connection_tracker.h" 5 6 #include "base/strings/string_number_conversions.h" 7 #include "base/strings/utf_string_conversions.h" 8 #include "content/common/media/peer_connection_tracker_messages.h" 9 #include "content/renderer/media/rtc_media_constraints.h" 10 #include "content/renderer/media/rtc_peer_connection_handler.h" 11 #include "content/renderer/render_thread_impl.h" 12 #include "third_party/WebKit/public/platform/WebMediaConstraints.h" 13 #include "third_party/WebKit/public/platform/WebMediaStream.h" 14 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h" 15 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h" 16 #include "third_party/WebKit/public/platform/WebRTCICECandidate.h" 17 #include "third_party/WebKit/public/platform/WebRTCPeerConnectionHandlerClient.h" 18 #include "third_party/WebKit/public/web/WebDocument.h" 19 #include "third_party/WebKit/public/web/WebFrame.h" 20 #include "third_party/WebKit/public/web/WebUserMediaRequest.h" 21 22 using std::string; 23 using webrtc::MediaConstraintsInterface; 24 using blink::WebRTCPeerConnectionHandlerClient; 25 26 namespace content { 27 28 static string SerializeServers( 29 const std::vector<webrtc::PeerConnectionInterface::IceServer>& servers) { 30 string result = "["; 31 for (size_t i = 0; i < servers.size(); ++i) { 32 result += servers[i].uri; 33 if (i != servers.size() - 1) 34 result += ", "; 35 } 36 result += "]"; 37 return result; 38 } 39 40 static RTCMediaConstraints GetNativeMediaConstraints( 41 const blink::WebMediaConstraints& constraints) { 42 RTCMediaConstraints native_constraints; 43 44 if (constraints.isNull()) 45 return native_constraints; 46 47 blink::WebVector<blink::WebMediaConstraint> mandatory; 48 constraints.getMandatoryConstraints(mandatory); 49 for (size_t i = 0; i < mandatory.size(); ++i) { 50 native_constraints.AddMandatory( 51 mandatory[i].m_name.utf8(), mandatory[i].m_value.utf8(), false); 52 } 53 54 blink::WebVector<blink::WebMediaConstraint> optional; 55 constraints.getOptionalConstraints(optional); 56 for (size_t i = 0; i < optional.size(); ++i) { 57 native_constraints.AddOptional( 58 optional[i].m_name.utf8(), optional[i].m_value.utf8(), false); 59 } 60 return native_constraints; 61 } 62 63 static string SerializeMediaConstraints( 64 const RTCMediaConstraints& constraints) { 65 string result; 66 MediaConstraintsInterface::Constraints mandatory = constraints.GetMandatory(); 67 if (!mandatory.empty()) { 68 result += "mandatory: {"; 69 for (size_t i = 0; i < mandatory.size(); ++i) { 70 result += mandatory[i].key + ":" + mandatory[i].value; 71 if (i != mandatory.size() - 1) 72 result += ", "; 73 } 74 result += "}"; 75 } 76 MediaConstraintsInterface::Constraints optional = constraints.GetOptional(); 77 if (!optional.empty()) { 78 if (!result.empty()) 79 result += ", "; 80 result += "optional: {"; 81 for (size_t i = 0; i < optional.size(); ++i) { 82 result += optional[i].key + ":" + optional[i].value; 83 if (i != optional.size() - 1) 84 result += ", "; 85 } 86 result += "}"; 87 } 88 return result; 89 } 90 91 static string SerializeMediaStreamComponent( 92 const blink::WebMediaStreamTrack component) { 93 string id = base::UTF16ToUTF8(component.source().id()); 94 return id; 95 } 96 97 static string SerializeMediaDescriptor( 98 const blink::WebMediaStream& stream) { 99 string label = base::UTF16ToUTF8(stream.id()); 100 string result = "label: " + label; 101 blink::WebVector<blink::WebMediaStreamTrack> tracks; 102 stream.audioTracks(tracks); 103 if (!tracks.isEmpty()) { 104 result += ", audio: ["; 105 for (size_t i = 0; i < tracks.size(); ++i) { 106 result += SerializeMediaStreamComponent(tracks[i]); 107 if (i != tracks.size() - 1) 108 result += ", "; 109 } 110 result += "]"; 111 } 112 stream.videoTracks(tracks); 113 if (!tracks.isEmpty()) { 114 result += ", video: ["; 115 for (size_t i = 0; i < tracks.size(); ++i) { 116 result += SerializeMediaStreamComponent(tracks[i]); 117 if (i != tracks.size() - 1) 118 result += ", "; 119 } 120 result += "]"; 121 } 122 return result; 123 } 124 125 static std::string SerializeIceTransportType( 126 webrtc::PeerConnectionInterface::IceTransportsType type) { 127 string transport_type; 128 switch (type) { 129 case webrtc::PeerConnectionInterface::kNone: 130 transport_type = "none"; 131 break; 132 case webrtc::PeerConnectionInterface::kRelay: 133 transport_type = "relay"; 134 break; 135 case webrtc::PeerConnectionInterface::kAll: 136 transport_type = "all"; 137 break; 138 case webrtc::PeerConnectionInterface::kNoHost: 139 transport_type = "noHost"; 140 break; 141 default: 142 NOTREACHED(); 143 }; 144 return transport_type; 145 } 146 147 #define GET_STRING_OF_STATE(state) \ 148 case WebRTCPeerConnectionHandlerClient::state: \ 149 result = #state; \ 150 break; 151 152 static string GetSignalingStateString( 153 WebRTCPeerConnectionHandlerClient::SignalingState state) { 154 string result; 155 switch (state) { 156 GET_STRING_OF_STATE(SignalingStateStable) 157 GET_STRING_OF_STATE(SignalingStateHaveLocalOffer) 158 GET_STRING_OF_STATE(SignalingStateHaveRemoteOffer) 159 GET_STRING_OF_STATE(SignalingStateHaveLocalPrAnswer) 160 GET_STRING_OF_STATE(SignalingStateHaveRemotePrAnswer) 161 GET_STRING_OF_STATE(SignalingStateClosed) 162 default: 163 NOTREACHED(); 164 break; 165 } 166 return result; 167 } 168 169 static string GetIceConnectionStateString( 170 WebRTCPeerConnectionHandlerClient::ICEConnectionState state) { 171 string result; 172 switch (state) { 173 GET_STRING_OF_STATE(ICEConnectionStateStarting) 174 GET_STRING_OF_STATE(ICEConnectionStateChecking) 175 GET_STRING_OF_STATE(ICEConnectionStateConnected) 176 GET_STRING_OF_STATE(ICEConnectionStateCompleted) 177 GET_STRING_OF_STATE(ICEConnectionStateFailed) 178 GET_STRING_OF_STATE(ICEConnectionStateDisconnected) 179 GET_STRING_OF_STATE(ICEConnectionStateClosed) 180 default: 181 NOTREACHED(); 182 break; 183 } 184 return result; 185 } 186 187 static string GetIceGatheringStateString( 188 WebRTCPeerConnectionHandlerClient::ICEGatheringState state) { 189 string result; 190 switch (state) { 191 GET_STRING_OF_STATE(ICEGatheringStateNew) 192 GET_STRING_OF_STATE(ICEGatheringStateGathering) 193 GET_STRING_OF_STATE(ICEGatheringStateComplete) 194 default: 195 NOTREACHED(); 196 break; 197 } 198 return result; 199 } 200 201 // Builds a DictionaryValue from the StatsReport. 202 // The caller takes the ownership of the returned value. 203 // Note: 204 // The format must be consistent with what webrtc_internals.js expects. 205 // If you change it here, you must change webrtc_internals.js as well. 206 static base::DictionaryValue* GetDictValueStats( 207 const webrtc::StatsReport& report) { 208 if (report.values.empty()) 209 return NULL; 210 211 base::DictionaryValue* dict = new base::DictionaryValue(); 212 dict->SetDouble("timestamp", report.timestamp); 213 214 base::ListValue* values = new base::ListValue(); 215 dict->Set("values", values); 216 217 for (size_t i = 0; i < report.values.size(); ++i) { 218 values->AppendString(report.values[i].display_name()); 219 values->AppendString(report.values[i].value); 220 } 221 return dict; 222 } 223 224 // Builds a DictionaryValue from the StatsReport. 225 // The caller takes the ownership of the returned value. 226 static base::DictionaryValue* GetDictValue(const webrtc::StatsReport& report) { 227 scoped_ptr<base::DictionaryValue> stats, result; 228 229 stats.reset(GetDictValueStats(report)); 230 if (!stats) 231 return NULL; 232 233 result.reset(new base::DictionaryValue()); 234 // Note: 235 // The format must be consistent with what webrtc_internals.js expects. 236 // If you change it here, you must change webrtc_internals.js as well. 237 result->Set("stats", stats.release()); 238 result->SetString("id", report.id); 239 result->SetString("type", report.type); 240 241 return result.release(); 242 } 243 244 class InternalStatsObserver : public webrtc::StatsObserver { 245 public: 246 InternalStatsObserver(int lid) 247 : lid_(lid){} 248 249 virtual void OnComplete( 250 const std::vector<webrtc::StatsReport>& reports) OVERRIDE { 251 base::ListValue list; 252 253 for (size_t i = 0; i < reports.size(); ++i) { 254 base::DictionaryValue* report = GetDictValue(reports[i]); 255 if (report) 256 list.Append(report); 257 } 258 259 if (!list.empty()) 260 RenderThreadImpl::current()->Send( 261 new PeerConnectionTrackerHost_AddStats(lid_, list)); 262 } 263 264 protected: 265 virtual ~InternalStatsObserver() {} 266 267 private: 268 int lid_; 269 }; 270 271 PeerConnectionTracker::PeerConnectionTracker() : next_lid_(1) { 272 } 273 274 PeerConnectionTracker::~PeerConnectionTracker() { 275 } 276 277 bool PeerConnectionTracker::OnControlMessageReceived( 278 const IPC::Message& message) { 279 bool handled = true; 280 IPC_BEGIN_MESSAGE_MAP(PeerConnectionTracker, message) 281 IPC_MESSAGE_HANDLER(PeerConnectionTracker_GetAllStats, OnGetAllStats) 282 IPC_MESSAGE_HANDLER(PeerConnectionTracker_OnSuspend, OnSuspend) 283 IPC_MESSAGE_UNHANDLED(handled = false) 284 IPC_END_MESSAGE_MAP() 285 return handled; 286 } 287 288 void PeerConnectionTracker::OnGetAllStats() { 289 for (PeerConnectionIdMap::iterator it = peer_connection_id_map_.begin(); 290 it != peer_connection_id_map_.end(); ++it) { 291 292 rtc::scoped_refptr<InternalStatsObserver> observer( 293 new rtc::RefCountedObject<InternalStatsObserver>(it->second)); 294 295 it->first->GetStats( 296 observer, 297 NULL, 298 webrtc::PeerConnectionInterface::kStatsOutputLevelDebug); 299 } 300 } 301 302 void PeerConnectionTracker::OnSuspend() { 303 for (PeerConnectionIdMap::iterator it = peer_connection_id_map_.begin(); 304 it != peer_connection_id_map_.end(); ++it) { 305 it->first->CloseClientPeerConnection(); 306 } 307 } 308 309 void PeerConnectionTracker::RegisterPeerConnection( 310 RTCPeerConnectionHandler* pc_handler, 311 const webrtc::PeerConnectionInterface::RTCConfiguration& config, 312 const RTCMediaConstraints& constraints, 313 const blink::WebFrame* frame) { 314 DVLOG(1) << "PeerConnectionTracker::RegisterPeerConnection()"; 315 PeerConnectionInfo info; 316 317 info.lid = GetNextLocalID(); 318 info.rtc_configuration = 319 "{ servers: " + SerializeServers(config.servers) + ", " + 320 "iceTransportType: " + SerializeIceTransportType(config.type) + " }"; 321 322 info.constraints = SerializeMediaConstraints(constraints); 323 info.url = frame->document().url().spec(); 324 RenderThreadImpl::current()->Send( 325 new PeerConnectionTrackerHost_AddPeerConnection(info)); 326 327 DCHECK(peer_connection_id_map_.find(pc_handler) == 328 peer_connection_id_map_.end()); 329 peer_connection_id_map_[pc_handler] = info.lid; 330 } 331 332 void PeerConnectionTracker::UnregisterPeerConnection( 333 RTCPeerConnectionHandler* pc_handler) { 334 DVLOG(1) << "PeerConnectionTracker::UnregisterPeerConnection()"; 335 336 std::map<RTCPeerConnectionHandler*, int>::iterator it = 337 peer_connection_id_map_.find(pc_handler); 338 339 if (it == peer_connection_id_map_.end()) { 340 // The PeerConnection might not have been registered if its initilization 341 // failed. 342 return; 343 } 344 345 RenderThreadImpl::current()->Send( 346 new PeerConnectionTrackerHost_RemovePeerConnection(it->second)); 347 348 peer_connection_id_map_.erase(it); 349 } 350 351 void PeerConnectionTracker::TrackCreateOffer( 352 RTCPeerConnectionHandler* pc_handler, 353 const RTCMediaConstraints& constraints) { 354 SendPeerConnectionUpdate( 355 pc_handler, "createOffer", 356 "constraints: {" + SerializeMediaConstraints(constraints) + "}"); 357 } 358 359 void PeerConnectionTracker::TrackCreateAnswer( 360 RTCPeerConnectionHandler* pc_handler, 361 const RTCMediaConstraints& constraints) { 362 SendPeerConnectionUpdate( 363 pc_handler, "createAnswer", 364 "constraints: {" + SerializeMediaConstraints(constraints) + "}"); 365 } 366 367 void PeerConnectionTracker::TrackSetSessionDescription( 368 RTCPeerConnectionHandler* pc_handler, 369 const blink::WebRTCSessionDescription& desc, 370 Source source) { 371 string sdp = base::UTF16ToUTF8(desc.sdp()); 372 string type = base::UTF16ToUTF8(desc.type()); 373 374 string value = "type: " + type + ", sdp: " + sdp; 375 SendPeerConnectionUpdate( 376 pc_handler, 377 source == SOURCE_LOCAL ? "setLocalDescription" : "setRemoteDescription", 378 value); 379 } 380 381 void PeerConnectionTracker::TrackUpdateIce( 382 RTCPeerConnectionHandler* pc_handler, 383 const webrtc::PeerConnectionInterface::RTCConfiguration& config, 384 const RTCMediaConstraints& options) { 385 string servers_string = "servers: " + SerializeServers(config.servers); 386 387 string transport_type = 388 "iceTransportType: " + SerializeIceTransportType(config.type); 389 390 string constraints = 391 "constraints: {" + SerializeMediaConstraints(options) + "}"; 392 393 SendPeerConnectionUpdate( 394 pc_handler, 395 "updateIce", 396 servers_string + ", " + transport_type + ", " + constraints); 397 } 398 399 void PeerConnectionTracker::TrackAddIceCandidate( 400 RTCPeerConnectionHandler* pc_handler, 401 const blink::WebRTCICECandidate& candidate, 402 Source source, 403 bool succeeded) { 404 string value = 405 "sdpMid: " + base::UTF16ToUTF8(candidate.sdpMid()) + ", " + 406 "sdpMLineIndex: " + base::IntToString(candidate.sdpMLineIndex()) + ", " + 407 "candidate: " + base::UTF16ToUTF8(candidate.candidate()); 408 409 // OnIceCandidate always succeeds as it's a callback from the browser. 410 DCHECK(source != SOURCE_LOCAL || succeeded); 411 412 string event = 413 (source == SOURCE_LOCAL) ? "onIceCandidate" 414 : (succeeded ? "addIceCandidate" 415 : "addIceCandidateFailed"); 416 417 SendPeerConnectionUpdate(pc_handler, event, value); 418 } 419 420 void PeerConnectionTracker::TrackAddStream( 421 RTCPeerConnectionHandler* pc_handler, 422 const blink::WebMediaStream& stream, 423 Source source){ 424 SendPeerConnectionUpdate( 425 pc_handler, source == SOURCE_LOCAL ? "addStream" : "onAddStream", 426 SerializeMediaDescriptor(stream)); 427 } 428 429 void PeerConnectionTracker::TrackRemoveStream( 430 RTCPeerConnectionHandler* pc_handler, 431 const blink::WebMediaStream& stream, 432 Source source){ 433 SendPeerConnectionUpdate( 434 pc_handler, source == SOURCE_LOCAL ? "removeStream" : "onRemoveStream", 435 SerializeMediaDescriptor(stream)); 436 } 437 438 void PeerConnectionTracker::TrackCreateDataChannel( 439 RTCPeerConnectionHandler* pc_handler, 440 const webrtc::DataChannelInterface* data_channel, 441 Source source) { 442 string value = "label: " + data_channel->label() + 443 ", reliable: " + (data_channel->reliable() ? "true" : "false"); 444 SendPeerConnectionUpdate( 445 pc_handler, 446 source == SOURCE_LOCAL ? "createLocalDataChannel" : "onRemoteDataChannel", 447 value); 448 } 449 450 void PeerConnectionTracker::TrackStop(RTCPeerConnectionHandler* pc_handler) { 451 SendPeerConnectionUpdate(pc_handler, "stop", std::string()); 452 } 453 454 void PeerConnectionTracker::TrackSignalingStateChange( 455 RTCPeerConnectionHandler* pc_handler, 456 WebRTCPeerConnectionHandlerClient::SignalingState state) { 457 SendPeerConnectionUpdate( 458 pc_handler, "signalingStateChange", GetSignalingStateString(state)); 459 } 460 461 void PeerConnectionTracker::TrackIceConnectionStateChange( 462 RTCPeerConnectionHandler* pc_handler, 463 WebRTCPeerConnectionHandlerClient::ICEConnectionState state) { 464 SendPeerConnectionUpdate( 465 pc_handler, "iceConnectionStateChange", 466 GetIceConnectionStateString(state)); 467 } 468 469 void PeerConnectionTracker::TrackIceGatheringStateChange( 470 RTCPeerConnectionHandler* pc_handler, 471 WebRTCPeerConnectionHandlerClient::ICEGatheringState state) { 472 SendPeerConnectionUpdate( 473 pc_handler, "iceGatheringStateChange", 474 GetIceGatheringStateString(state)); 475 } 476 477 void PeerConnectionTracker::TrackSessionDescriptionCallback( 478 RTCPeerConnectionHandler* pc_handler, Action action, 479 const string& callback_type, const string& value) { 480 string update_type; 481 switch (action) { 482 case ACTION_SET_LOCAL_DESCRIPTION: 483 update_type = "setLocalDescription"; 484 break; 485 case ACTION_SET_REMOTE_DESCRIPTION: 486 update_type = "setRemoteDescription"; 487 break; 488 case ACTION_CREATE_OFFER: 489 update_type = "createOffer"; 490 break; 491 case ACTION_CREATE_ANSWER: 492 update_type = "createAnswer"; 493 break; 494 default: 495 NOTREACHED(); 496 break; 497 } 498 update_type += callback_type; 499 500 SendPeerConnectionUpdate(pc_handler, update_type, value); 501 } 502 503 void PeerConnectionTracker::TrackOnRenegotiationNeeded( 504 RTCPeerConnectionHandler* pc_handler) { 505 SendPeerConnectionUpdate(pc_handler, "onRenegotiationNeeded", std::string()); 506 } 507 508 void PeerConnectionTracker::TrackCreateDTMFSender( 509 RTCPeerConnectionHandler* pc_handler, 510 const blink::WebMediaStreamTrack& track) { 511 SendPeerConnectionUpdate(pc_handler, "createDTMFSender", 512 base::UTF16ToUTF8(track.id())); 513 } 514 515 void PeerConnectionTracker::TrackGetUserMedia( 516 const blink::WebUserMediaRequest& user_media_request) { 517 RTCMediaConstraints audio_constraints( 518 GetNativeMediaConstraints(user_media_request.audioConstraints())); 519 RTCMediaConstraints video_constraints( 520 GetNativeMediaConstraints(user_media_request.videoConstraints())); 521 522 RenderThreadImpl::current()->Send(new PeerConnectionTrackerHost_GetUserMedia( 523 user_media_request.securityOrigin().toString().utf8(), 524 user_media_request.audio(), 525 user_media_request.video(), 526 SerializeMediaConstraints(audio_constraints), 527 SerializeMediaConstraints(video_constraints))); 528 } 529 530 int PeerConnectionTracker::GetNextLocalID() { 531 return next_lid_++; 532 } 533 534 void PeerConnectionTracker::SendPeerConnectionUpdate( 535 RTCPeerConnectionHandler* pc_handler, 536 const std::string& type, 537 const std::string& value) { 538 if (peer_connection_id_map_.find(pc_handler) == peer_connection_id_map_.end()) 539 return; 540 541 RenderThreadImpl::current()->Send( 542 new PeerConnectionTrackerHost_UpdatePeerConnection( 543 peer_connection_id_map_[pc_handler], type, value)); 544 } 545 546 } // namespace content 547