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 19using std::string; 20using webrtc::MediaConstraintsInterface; 21using WebKit::WebRTCPeerConnectionHandlerClient; 22 23namespace content { 24 25static 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 37static 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 65static string SerializeMediaStreamComponent( 66 const WebKit::WebMediaStreamTrack component) { 67 string id = UTF16ToUTF8(component.source().id()); 68 return id; 69} 70 71static string SerializeMediaDescriptor( 72 const WebKit::WebMediaStream& stream) { 73 string label = UTF16ToUTF8(stream.id()); 74 string result = "label: " + label; 75 WebKit::WebVector<WebKit::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 104static 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 121static 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 139static 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. 158static base::DictionaryValue* GetDictValueStats( 159 const webrtc::StatsReport& report) { 160 if (report.values.empty()) 161 return NULL; 162 163 DictionaryValue* dict = new base::DictionaryValue(); 164 if (!dict) 165 return NULL; 166 dict->SetDouble("timestamp", report.timestamp); 167 168 base::ListValue* values = new base::ListValue(); 169 if (!values) { 170 delete dict; 171 return NULL; 172 } 173 dict->Set("values", values); 174 175 for (size_t i = 0; i < report.values.size(); ++i) { 176 values->AppendString(report.values[i].name); 177 values->AppendString(report.values[i].value); 178 } 179 return dict; 180} 181 182// Builds a DictionaryValue from the StatsReport. 183// The caller takes the ownership of the returned value. 184static base::DictionaryValue* GetDictValue(const webrtc::StatsReport& report) { 185 scoped_ptr<base::DictionaryValue> stats, result; 186 187 stats.reset(GetDictValueStats(report)); 188 if (!stats) 189 return NULL; 190 191 result.reset(new base::DictionaryValue()); 192 if (!result) 193 return NULL; 194 195 // Note: 196 // The format must be consistent with what webrtc_internals.js expects. 197 // If you change it here, you must change webrtc_internals.js as well. 198 if (stats) 199 result->Set("stats", stats.release()); 200 result->SetString("id", report.id); 201 result->SetString("type", report.type); 202 203 return result.release(); 204} 205 206class InternalStatsObserver : public webrtc::StatsObserver { 207 public: 208 InternalStatsObserver(int lid) 209 : lid_(lid){} 210 211 virtual void OnComplete( 212 const std::vector<webrtc::StatsReport>& reports) OVERRIDE { 213 base::ListValue list; 214 215 for (size_t i = 0; i < reports.size(); ++i) { 216 base::DictionaryValue* report = GetDictValue(reports[i]); 217 if (report) 218 list.Append(report); 219 } 220 221 if (!list.empty()) 222 RenderThreadImpl::current()->Send( 223 new PeerConnectionTrackerHost_AddStats(lid_, list)); 224 } 225 226 protected: 227 virtual ~InternalStatsObserver() {} 228 229 private: 230 int lid_; 231}; 232 233PeerConnectionTracker::PeerConnectionTracker() : next_lid_(1) { 234} 235 236PeerConnectionTracker::~PeerConnectionTracker() { 237} 238 239bool PeerConnectionTracker::OnControlMessageReceived( 240 const IPC::Message& message) { 241 bool handled = true; 242 IPC_BEGIN_MESSAGE_MAP(PeerConnectionTracker, message) 243 IPC_MESSAGE_HANDLER(PeerConnectionTracker_GetAllStats, OnGetAllStats) 244 IPC_MESSAGE_UNHANDLED(handled = false) 245 IPC_END_MESSAGE_MAP() 246 return handled; 247} 248 249void PeerConnectionTracker::OnGetAllStats() { 250 for (PeerConnectionIdMap::iterator it = peer_connection_id_map_.begin(); 251 it != peer_connection_id_map_.end(); ++it) { 252 253 talk_base::scoped_refptr<InternalStatsObserver> observer( 254 new talk_base::RefCountedObject<InternalStatsObserver>(it->second)); 255 256 it->first->GetStats(observer, NULL); 257 } 258} 259 260void PeerConnectionTracker::RegisterPeerConnection( 261 RTCPeerConnectionHandler* pc_handler, 262 const std::vector<webrtc::PeerConnectionInterface::IceServer>& servers, 263 const RTCMediaConstraints& constraints, 264 const WebKit::WebFrame* frame) { 265 DVLOG(1) << "PeerConnectionTracker::RegisterPeerConnection()"; 266 PeerConnectionInfo info; 267 268 info.lid = GetNextLocalID(); 269 info.servers = SerializeServers(servers); 270 info.constraints = SerializeMediaConstraints(constraints); 271 info.url = frame->document().url().spec(); 272 RenderThreadImpl::current()->Send( 273 new PeerConnectionTrackerHost_AddPeerConnection(info)); 274 275 DCHECK(peer_connection_id_map_.find(pc_handler) == 276 peer_connection_id_map_.end()); 277 peer_connection_id_map_[pc_handler] = info.lid; 278} 279 280void PeerConnectionTracker::UnregisterPeerConnection( 281 RTCPeerConnectionHandler* pc_handler) { 282 DVLOG(1) << "PeerConnectionTracker::UnregisterPeerConnection()"; 283 284 std::map<RTCPeerConnectionHandler*, int>::iterator it = 285 peer_connection_id_map_.find(pc_handler); 286 287 if (it == peer_connection_id_map_.end()) { 288 // The PeerConnection might not have been registered if its initilization 289 // failed. 290 return; 291 } 292 293 RenderThreadImpl::current()->Send( 294 new PeerConnectionTrackerHost_RemovePeerConnection(it->second)); 295 296 peer_connection_id_map_.erase(it); 297} 298 299void PeerConnectionTracker::TrackCreateOffer( 300 RTCPeerConnectionHandler* pc_handler, 301 const RTCMediaConstraints& constraints) { 302 SendPeerConnectionUpdate( 303 pc_handler, "createOffer", 304 "constraints: {" + SerializeMediaConstraints(constraints) + "}"); 305} 306 307void PeerConnectionTracker::TrackCreateAnswer( 308 RTCPeerConnectionHandler* pc_handler, 309 const RTCMediaConstraints& constraints) { 310 SendPeerConnectionUpdate( 311 pc_handler, "createAnswer", 312 "constraints: {" + SerializeMediaConstraints(constraints) + "}"); 313} 314 315void PeerConnectionTracker::TrackSetSessionDescription( 316 RTCPeerConnectionHandler* pc_handler, 317 const WebKit::WebRTCSessionDescription& desc, 318 Source source) { 319 string sdp = UTF16ToUTF8(desc.sdp()); 320 string type = UTF16ToUTF8(desc.type()); 321 322 string value = "type: " + type + ", sdp: " + sdp; 323 SendPeerConnectionUpdate( 324 pc_handler, 325 source == SOURCE_LOCAL ? "setLocalDescription" : "setRemoteDescription", 326 value); 327} 328 329void PeerConnectionTracker::TrackUpdateIce( 330 RTCPeerConnectionHandler* pc_handler, 331 const std::vector<webrtc::PeerConnectionInterface::IceServer>& servers, 332 const RTCMediaConstraints& options) { 333 string servers_string = "servers: " + SerializeServers(servers); 334 string constraints = 335 "constraints: {" + SerializeMediaConstraints(options) + "}"; 336 337 SendPeerConnectionUpdate( 338 pc_handler, "updateIce", servers_string + ", " + constraints); 339} 340 341void PeerConnectionTracker::TrackAddIceCandidate( 342 RTCPeerConnectionHandler* pc_handler, 343 const WebKit::WebRTCICECandidate& candidate, 344 Source source) { 345 string value = "mid: " + UTF16ToUTF8(candidate.sdpMid()) + ", " + 346 "candidate: " + UTF16ToUTF8(candidate.candidate()); 347 SendPeerConnectionUpdate( 348 pc_handler, 349 source == SOURCE_LOCAL ? "onIceCandidate" : "addIceCandidate", value); 350} 351 352void PeerConnectionTracker::TrackAddStream( 353 RTCPeerConnectionHandler* pc_handler, 354 const WebKit::WebMediaStream& stream, 355 Source source){ 356 SendPeerConnectionUpdate( 357 pc_handler, source == SOURCE_LOCAL ? "addStream" : "onAddStream", 358 SerializeMediaDescriptor(stream)); 359} 360 361void PeerConnectionTracker::TrackRemoveStream( 362 RTCPeerConnectionHandler* pc_handler, 363 const WebKit::WebMediaStream& stream, 364 Source source){ 365 SendPeerConnectionUpdate( 366 pc_handler, source == SOURCE_LOCAL ? "removeStream" : "onRemoveStream", 367 SerializeMediaDescriptor(stream)); 368} 369 370void PeerConnectionTracker::TrackCreateDataChannel( 371 RTCPeerConnectionHandler* pc_handler, 372 const webrtc::DataChannelInterface* data_channel, 373 Source source) { 374 string value = "label: " + data_channel->label() + 375 ", reliable: " + (data_channel->reliable() ? "true" : "false"); 376 SendPeerConnectionUpdate( 377 pc_handler, 378 source == SOURCE_LOCAL ? "createLocalDataChannel" : "onRemoteDataChannel", 379 value); 380} 381 382void PeerConnectionTracker::TrackStop(RTCPeerConnectionHandler* pc_handler) { 383 SendPeerConnectionUpdate(pc_handler, "stop", std::string()); 384} 385 386void PeerConnectionTracker::TrackSignalingStateChange( 387 RTCPeerConnectionHandler* pc_handler, 388 WebRTCPeerConnectionHandlerClient::SignalingState state) { 389 SendPeerConnectionUpdate( 390 pc_handler, "signalingStateChange", GetSignalingStateString(state)); 391} 392 393void PeerConnectionTracker::TrackIceConnectionStateChange( 394 RTCPeerConnectionHandler* pc_handler, 395 WebRTCPeerConnectionHandlerClient::ICEConnectionState state) { 396 SendPeerConnectionUpdate( 397 pc_handler, "iceConnectionStateChange", 398 GetIceConnectionStateString(state)); 399} 400 401void PeerConnectionTracker::TrackIceGatheringStateChange( 402 RTCPeerConnectionHandler* pc_handler, 403 WebRTCPeerConnectionHandlerClient::ICEGatheringState state) { 404 SendPeerConnectionUpdate( 405 pc_handler, "iceGatheringStateChange", 406 GetIceGatheringStateString(state)); 407} 408 409void PeerConnectionTracker::TrackSessionDescriptionCallback( 410 RTCPeerConnectionHandler* pc_handler, Action action, 411 const string& callback_type, const string& value) { 412 string update_type; 413 switch (action) { 414 case ACTION_SET_LOCAL_DESCRIPTION: 415 update_type = "setLocalDescription"; 416 break; 417 case ACTION_SET_REMOTE_DESCRIPTION: 418 update_type = "setRemoteDescription"; 419 break; 420 case ACTION_CREATE_OFFER: 421 update_type = "createOffer"; 422 break; 423 case ACTION_CREATE_ANSWER: 424 update_type = "createAnswer"; 425 break; 426 default: 427 NOTREACHED(); 428 break; 429 } 430 update_type += callback_type; 431 432 SendPeerConnectionUpdate(pc_handler, update_type, value); 433} 434 435void PeerConnectionTracker::TrackOnRenegotiationNeeded( 436 RTCPeerConnectionHandler* pc_handler) { 437 SendPeerConnectionUpdate(pc_handler, "onRenegotiationNeeded", std::string()); 438} 439 440void PeerConnectionTracker::TrackCreateDTMFSender( 441 RTCPeerConnectionHandler* pc_handler, 442 const WebKit::WebMediaStreamTrack& track) { 443 SendPeerConnectionUpdate(pc_handler, "createDTMFSender", 444 UTF16ToUTF8(track.id())); 445} 446 447int PeerConnectionTracker::GetNextLocalID() { 448 return next_lid_++; 449} 450 451void PeerConnectionTracker::SendPeerConnectionUpdate( 452 RTCPeerConnectionHandler* pc_handler, 453 const std::string& type, 454 const std::string& value) { 455 if (peer_connection_id_map_.find(pc_handler) == peer_connection_id_map_.end()) 456 return; 457 458 RenderThreadImpl::current()->Send( 459 new PeerConnectionTrackerHost_UpdatePeerConnection( 460 peer_connection_id_map_[pc_handler], type, value)); 461} 462 463} // namespace content 464