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