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
SerializeServers(const std::vector<webrtc::PeerConnectionInterface::IceServer> & servers)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
GetNativeMediaConstraints(const blink::WebMediaConstraints & constraints)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
SerializeMediaConstraints(const RTCMediaConstraints & constraints)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
SerializeMediaStreamComponent(const blink::WebMediaStreamTrack component)91 static string SerializeMediaStreamComponent(
92 const blink::WebMediaStreamTrack component) {
93 string id = base::UTF16ToUTF8(component.source().id());
94 return id;
95 }
96
SerializeMediaDescriptor(const blink::WebMediaStream & stream)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
SerializeIceTransportType(webrtc::PeerConnectionInterface::IceTransportsType type)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
GetSignalingStateString(WebRTCPeerConnectionHandlerClient::SignalingState state)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
GetIceConnectionStateString(WebRTCPeerConnectionHandlerClient::ICEConnectionState state)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
GetIceGatheringStateString(WebRTCPeerConnectionHandlerClient::ICEGatheringState state)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.
GetDictValueStats(const webrtc::StatsReport & report)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.
GetDictValue(const webrtc::StatsReport & report)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:
InternalStatsObserver(int lid)246 InternalStatsObserver(int lid)
247 : lid_(lid){}
248
OnComplete(const std::vector<webrtc::StatsReport> & reports)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:
~InternalStatsObserver()265 virtual ~InternalStatsObserver() {}
266
267 private:
268 int lid_;
269 };
270
PeerConnectionTracker()271 PeerConnectionTracker::PeerConnectionTracker() : next_lid_(1) {
272 }
273
~PeerConnectionTracker()274 PeerConnectionTracker::~PeerConnectionTracker() {
275 }
276
OnControlMessageReceived(const IPC::Message & message)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
OnGetAllStats()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
OnSuspend()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
RegisterPeerConnection(RTCPeerConnectionHandler * pc_handler,const webrtc::PeerConnectionInterface::RTCConfiguration & config,const RTCMediaConstraints & constraints,const blink::WebFrame * frame)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
UnregisterPeerConnection(RTCPeerConnectionHandler * pc_handler)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
TrackCreateOffer(RTCPeerConnectionHandler * pc_handler,const RTCMediaConstraints & constraints)351 void PeerConnectionTracker::TrackCreateOffer(
352 RTCPeerConnectionHandler* pc_handler,
353 const RTCMediaConstraints& constraints) {
354 SendPeerConnectionUpdate(
355 pc_handler, "createOffer",
356 "constraints: {" + SerializeMediaConstraints(constraints) + "}");
357 }
358
TrackCreateAnswer(RTCPeerConnectionHandler * pc_handler,const RTCMediaConstraints & constraints)359 void PeerConnectionTracker::TrackCreateAnswer(
360 RTCPeerConnectionHandler* pc_handler,
361 const RTCMediaConstraints& constraints) {
362 SendPeerConnectionUpdate(
363 pc_handler, "createAnswer",
364 "constraints: {" + SerializeMediaConstraints(constraints) + "}");
365 }
366
TrackSetSessionDescription(RTCPeerConnectionHandler * pc_handler,const blink::WebRTCSessionDescription & desc,Source source)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
TrackUpdateIce(RTCPeerConnectionHandler * pc_handler,const webrtc::PeerConnectionInterface::RTCConfiguration & config,const RTCMediaConstraints & options)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
TrackAddIceCandidate(RTCPeerConnectionHandler * pc_handler,const blink::WebRTCICECandidate & candidate,Source source,bool succeeded)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
TrackAddStream(RTCPeerConnectionHandler * pc_handler,const blink::WebMediaStream & stream,Source source)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
TrackRemoveStream(RTCPeerConnectionHandler * pc_handler,const blink::WebMediaStream & stream,Source source)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
TrackCreateDataChannel(RTCPeerConnectionHandler * pc_handler,const webrtc::DataChannelInterface * data_channel,Source source)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
TrackStop(RTCPeerConnectionHandler * pc_handler)450 void PeerConnectionTracker::TrackStop(RTCPeerConnectionHandler* pc_handler) {
451 SendPeerConnectionUpdate(pc_handler, "stop", std::string());
452 }
453
TrackSignalingStateChange(RTCPeerConnectionHandler * pc_handler,WebRTCPeerConnectionHandlerClient::SignalingState state)454 void PeerConnectionTracker::TrackSignalingStateChange(
455 RTCPeerConnectionHandler* pc_handler,
456 WebRTCPeerConnectionHandlerClient::SignalingState state) {
457 SendPeerConnectionUpdate(
458 pc_handler, "signalingStateChange", GetSignalingStateString(state));
459 }
460
TrackIceConnectionStateChange(RTCPeerConnectionHandler * pc_handler,WebRTCPeerConnectionHandlerClient::ICEConnectionState state)461 void PeerConnectionTracker::TrackIceConnectionStateChange(
462 RTCPeerConnectionHandler* pc_handler,
463 WebRTCPeerConnectionHandlerClient::ICEConnectionState state) {
464 SendPeerConnectionUpdate(
465 pc_handler, "iceConnectionStateChange",
466 GetIceConnectionStateString(state));
467 }
468
TrackIceGatheringStateChange(RTCPeerConnectionHandler * pc_handler,WebRTCPeerConnectionHandlerClient::ICEGatheringState state)469 void PeerConnectionTracker::TrackIceGatheringStateChange(
470 RTCPeerConnectionHandler* pc_handler,
471 WebRTCPeerConnectionHandlerClient::ICEGatheringState state) {
472 SendPeerConnectionUpdate(
473 pc_handler, "iceGatheringStateChange",
474 GetIceGatheringStateString(state));
475 }
476
TrackSessionDescriptionCallback(RTCPeerConnectionHandler * pc_handler,Action action,const string & callback_type,const string & value)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
TrackOnRenegotiationNeeded(RTCPeerConnectionHandler * pc_handler)503 void PeerConnectionTracker::TrackOnRenegotiationNeeded(
504 RTCPeerConnectionHandler* pc_handler) {
505 SendPeerConnectionUpdate(pc_handler, "onRenegotiationNeeded", std::string());
506 }
507
TrackCreateDTMFSender(RTCPeerConnectionHandler * pc_handler,const blink::WebMediaStreamTrack & track)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
TrackGetUserMedia(const blink::WebUserMediaRequest & user_media_request)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
GetNextLocalID()530 int PeerConnectionTracker::GetNextLocalID() {
531 return next_lid_++;
532 }
533
SendPeerConnectionUpdate(RTCPeerConnectionHandler * pc_handler,const std::string & type,const std::string & value)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