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"
6 #include "base/strings/string_number_conversions.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "base/thread_task_runner_handle.h"
9 #include "content/common/media/peer_connection_tracker_messages.h"
10 #include "content/renderer/media/rtc_media_constraints.h"
11 #include "content/renderer/media/rtc_peer_connection_handler.h"
12 #include "content/renderer/render_thread_impl.h"
13 #include "third_party/WebKit/public/platform/WebMediaConstraints.h"
14 #include "third_party/WebKit/public/platform/WebMediaStream.h"
15 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
16 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
17 #include "third_party/WebKit/public/platform/WebRTCICECandidate.h"
18 #include "third_party/WebKit/public/platform/WebRTCPeerConnectionHandlerClient.h"
19 #include "third_party/WebKit/public/web/WebDocument.h"
20 #include "third_party/WebKit/public/web/WebFrame.h"
21 #include "third_party/WebKit/public/web/WebUserMediaRequest.h"
24 using webrtc::MediaConstraintsInterface
;
25 using blink::WebRTCPeerConnectionHandlerClient
;
29 static string
SerializeServers(
30 const std::vector
<webrtc::PeerConnectionInterface::IceServer
>& servers
) {
32 for (size_t i
= 0; i
< servers
.size(); ++i
) {
33 result
+= servers
[i
].uri
;
34 if (i
!= servers
.size() - 1)
41 static RTCMediaConstraints
GetNativeMediaConstraints(
42 const blink::WebMediaConstraints
& constraints
) {
43 RTCMediaConstraints native_constraints
;
45 if (constraints
.isNull())
46 return native_constraints
;
48 blink::WebVector
<blink::WebMediaConstraint
> mandatory
;
49 constraints
.getMandatoryConstraints(mandatory
);
50 for (size_t i
= 0; i
< mandatory
.size(); ++i
) {
51 native_constraints
.AddMandatory(
52 mandatory
[i
].m_name
.utf8(), mandatory
[i
].m_value
.utf8(), false);
55 blink::WebVector
<blink::WebMediaConstraint
> optional
;
56 constraints
.getOptionalConstraints(optional
);
57 for (size_t i
= 0; i
< optional
.size(); ++i
) {
58 native_constraints
.AddOptional(
59 optional
[i
].m_name
.utf8(), optional
[i
].m_value
.utf8(), false);
61 return native_constraints
;
64 static string
SerializeMediaConstraints(
65 const RTCMediaConstraints
& constraints
) {
67 MediaConstraintsInterface::Constraints mandatory
= constraints
.GetMandatory();
68 if (!mandatory
.empty()) {
69 result
+= "mandatory: {";
70 for (size_t i
= 0; i
< mandatory
.size(); ++i
) {
71 result
+= mandatory
[i
].key
+ ":" + mandatory
[i
].value
;
72 if (i
!= mandatory
.size() - 1)
77 MediaConstraintsInterface::Constraints optional
= constraints
.GetOptional();
78 if (!optional
.empty()) {
81 result
+= "optional: {";
82 for (size_t i
= 0; i
< optional
.size(); ++i
) {
83 result
+= optional
[i
].key
+ ":" + optional
[i
].value
;
84 if (i
!= optional
.size() - 1)
92 static string
SerializeMediaStreamComponent(
93 const blink::WebMediaStreamTrack component
) {
94 string id
= base::UTF16ToUTF8(component
.source().id());
98 static string
SerializeMediaDescriptor(
99 const blink::WebMediaStream
& stream
) {
100 string label
= base::UTF16ToUTF8(stream
.id());
101 string result
= "label: " + label
;
102 blink::WebVector
<blink::WebMediaStreamTrack
> tracks
;
103 stream
.audioTracks(tracks
);
104 if (!tracks
.isEmpty()) {
105 result
+= ", audio: [";
106 for (size_t i
= 0; i
< tracks
.size(); ++i
) {
107 result
+= SerializeMediaStreamComponent(tracks
[i
]);
108 if (i
!= tracks
.size() - 1)
113 stream
.videoTracks(tracks
);
114 if (!tracks
.isEmpty()) {
115 result
+= ", video: [";
116 for (size_t i
= 0; i
< tracks
.size(); ++i
) {
117 result
+= SerializeMediaStreamComponent(tracks
[i
]);
118 if (i
!= tracks
.size() - 1)
126 static std::string
SerializeIceTransportType(
127 webrtc::PeerConnectionInterface::IceTransportsType type
) {
128 string transport_type
;
130 case webrtc::PeerConnectionInterface::kNone
:
131 transport_type
= "none";
133 case webrtc::PeerConnectionInterface::kRelay
:
134 transport_type
= "relay";
136 case webrtc::PeerConnectionInterface::kAll
:
137 transport_type
= "all";
139 case webrtc::PeerConnectionInterface::kNoHost
:
140 transport_type
= "noHost";
145 return transport_type
;
148 #define GET_STRING_OF_STATE(state) \
149 case WebRTCPeerConnectionHandlerClient::state: \
153 static string
GetSignalingStateString(
154 WebRTCPeerConnectionHandlerClient::SignalingState state
) {
157 GET_STRING_OF_STATE(SignalingStateStable
)
158 GET_STRING_OF_STATE(SignalingStateHaveLocalOffer
)
159 GET_STRING_OF_STATE(SignalingStateHaveRemoteOffer
)
160 GET_STRING_OF_STATE(SignalingStateHaveLocalPrAnswer
)
161 GET_STRING_OF_STATE(SignalingStateHaveRemotePrAnswer
)
162 GET_STRING_OF_STATE(SignalingStateClosed
)
170 static string
GetIceConnectionStateString(
171 WebRTCPeerConnectionHandlerClient::ICEConnectionState state
) {
174 GET_STRING_OF_STATE(ICEConnectionStateStarting
)
175 GET_STRING_OF_STATE(ICEConnectionStateChecking
)
176 GET_STRING_OF_STATE(ICEConnectionStateConnected
)
177 GET_STRING_OF_STATE(ICEConnectionStateCompleted
)
178 GET_STRING_OF_STATE(ICEConnectionStateFailed
)
179 GET_STRING_OF_STATE(ICEConnectionStateDisconnected
)
180 GET_STRING_OF_STATE(ICEConnectionStateClosed
)
188 static string
GetIceGatheringStateString(
189 WebRTCPeerConnectionHandlerClient::ICEGatheringState state
) {
192 GET_STRING_OF_STATE(ICEGatheringStateNew
)
193 GET_STRING_OF_STATE(ICEGatheringStateGathering
)
194 GET_STRING_OF_STATE(ICEGatheringStateComplete
)
202 // Builds a DictionaryValue from the StatsReport.
203 // The caller takes the ownership of the returned value.
205 // The format must be consistent with what webrtc_internals.js expects.
206 // If you change it here, you must change webrtc_internals.js as well.
207 static base::DictionaryValue
* GetDictValueStats(
208 const webrtc::StatsReport
& report
) {
209 if (report
.values().empty())
212 base::DictionaryValue
* dict
= new base::DictionaryValue();
213 dict
->SetDouble("timestamp", report
.timestamp());
215 base::ListValue
* values
= new base::ListValue();
216 dict
->Set("values", values
);
218 for (const auto& v
: report
.values()) {
219 values
->AppendString(v
->display_name());
220 values
->AppendString(v
->value
);
226 // Builds a DictionaryValue from the StatsReport.
227 // The caller takes the ownership of the returned value.
228 static base::DictionaryValue
* GetDictValue(const webrtc::StatsReport
& report
) {
229 scoped_ptr
<base::DictionaryValue
> stats
, result
;
231 stats
.reset(GetDictValueStats(report
));
235 result
.reset(new base::DictionaryValue());
237 // The format must be consistent with what webrtc_internals.js expects.
238 // If you change it here, you must change webrtc_internals.js as well.
239 result
->Set("stats", stats
.release());
240 result
->SetString("id", report
.id().ToString());
241 result
->SetString("type", report
.TypeToString());
243 return result
.release();
246 class InternalStatsObserver
: public webrtc::StatsObserver
{
248 InternalStatsObserver(int lid
)
249 : lid_(lid
), main_thread_(base::ThreadTaskRunnerHandle::Get()) {}
251 void OnComplete(const webrtc::StatsReports
& reports
) override
{
252 scoped_ptr
<base::ListValue
> list(new base::ListValue());
254 for (const auto* r
: reports
) {
255 base::DictionaryValue
* report
= GetDictValue(*r
);
257 list
->Append(report
);
260 if (!list
->empty()) {
261 main_thread_
->PostTask(FROM_HERE
,
262 base::Bind(&InternalStatsObserver::OnCompleteImpl
,
263 base::Passed(&list
), lid_
));
268 ~InternalStatsObserver() override
{
269 // Will be destructed on libjingle's signaling thread.
270 // The signaling thread is where libjingle's objects live and from where
271 // libjingle makes callbacks. This may or may not be the same thread as
276 // Static since |this| will most likely have been deleted by the time we
278 static void OnCompleteImpl(scoped_ptr
<base::ListValue
> list
, int lid
) {
279 DCHECK(!list
->empty());
280 RenderThreadImpl::current()->Send(
281 new PeerConnectionTrackerHost_AddStats(lid
, *list
.get()));
285 const scoped_refptr
<base::SingleThreadTaskRunner
> main_thread_
;
288 PeerConnectionTracker::PeerConnectionTracker() : next_lid_(1) {
291 PeerConnectionTracker::~PeerConnectionTracker() {
294 bool PeerConnectionTracker::OnControlMessageReceived(
295 const IPC::Message
& message
) {
297 IPC_BEGIN_MESSAGE_MAP(PeerConnectionTracker
, message
)
298 IPC_MESSAGE_HANDLER(PeerConnectionTracker_GetAllStats
, OnGetAllStats
)
299 IPC_MESSAGE_HANDLER(PeerConnectionTracker_OnSuspend
, OnSuspend
)
300 IPC_MESSAGE_UNHANDLED(handled
= false)
301 IPC_END_MESSAGE_MAP()
305 void PeerConnectionTracker::OnGetAllStats() {
306 DCHECK(main_thread_
.CalledOnValidThread());
308 const std::string empty_track_id
;
309 for (PeerConnectionIdMap::iterator it
= peer_connection_id_map_
.begin();
310 it
!= peer_connection_id_map_
.end(); ++it
) {
311 rtc::scoped_refptr
<InternalStatsObserver
> observer(
312 new rtc::RefCountedObject
<InternalStatsObserver
>(it
->second
));
314 // The last type parameter is ignored when the track id is empty.
317 webrtc::PeerConnectionInterface::kStatsOutputLevelDebug
,
318 empty_track_id
, blink::WebMediaStreamSource::TypeAudio
);
322 void PeerConnectionTracker::OnSuspend() {
323 DCHECK(main_thread_
.CalledOnValidThread());
324 for (PeerConnectionIdMap::iterator it
= peer_connection_id_map_
.begin();
325 it
!= peer_connection_id_map_
.end(); ++it
) {
326 it
->first
->CloseClientPeerConnection();
330 void PeerConnectionTracker::RegisterPeerConnection(
331 RTCPeerConnectionHandler
* pc_handler
,
332 const webrtc::PeerConnectionInterface::RTCConfiguration
& config
,
333 const RTCMediaConstraints
& constraints
,
334 const blink::WebFrame
* frame
) {
335 DCHECK(main_thread_
.CalledOnValidThread());
336 DVLOG(1) << "PeerConnectionTracker::RegisterPeerConnection()";
337 PeerConnectionInfo info
;
339 info
.lid
= GetNextLocalID();
340 info
.rtc_configuration
=
341 "{ servers: " + SerializeServers(config
.servers
) + ", " +
342 "iceTransportType: " + SerializeIceTransportType(config
.type
) + " }";
344 info
.constraints
= SerializeMediaConstraints(constraints
);
345 info
.url
= frame
->document().url().spec();
346 RenderThreadImpl::current()->Send(
347 new PeerConnectionTrackerHost_AddPeerConnection(info
));
349 DCHECK(peer_connection_id_map_
.find(pc_handler
) ==
350 peer_connection_id_map_
.end());
351 peer_connection_id_map_
[pc_handler
] = info
.lid
;
354 void PeerConnectionTracker::UnregisterPeerConnection(
355 RTCPeerConnectionHandler
* pc_handler
) {
356 DCHECK(main_thread_
.CalledOnValidThread());
357 DVLOG(1) << "PeerConnectionTracker::UnregisterPeerConnection()";
359 std::map
<RTCPeerConnectionHandler
*, int>::iterator it
=
360 peer_connection_id_map_
.find(pc_handler
);
362 if (it
== peer_connection_id_map_
.end()) {
363 // The PeerConnection might not have been registered if its initilization
368 RenderThreadImpl::current()->Send(
369 new PeerConnectionTrackerHost_RemovePeerConnection(it
->second
));
371 peer_connection_id_map_
.erase(it
);
374 void PeerConnectionTracker::TrackCreateOffer(
375 RTCPeerConnectionHandler
* pc_handler
,
376 const RTCMediaConstraints
& constraints
) {
377 DCHECK(main_thread_
.CalledOnValidThread());
378 SendPeerConnectionUpdate(
379 pc_handler
, "createOffer",
380 "constraints: {" + SerializeMediaConstraints(constraints
) + "}");
383 void PeerConnectionTracker::TrackCreateAnswer(
384 RTCPeerConnectionHandler
* pc_handler
,
385 const RTCMediaConstraints
& constraints
) {
386 DCHECK(main_thread_
.CalledOnValidThread());
387 SendPeerConnectionUpdate(
388 pc_handler
, "createAnswer",
389 "constraints: {" + SerializeMediaConstraints(constraints
) + "}");
392 void PeerConnectionTracker::TrackSetSessionDescription(
393 RTCPeerConnectionHandler
* pc_handler
,
394 const std::string
& sdp
, const std::string
& type
, Source source
) {
395 DCHECK(main_thread_
.CalledOnValidThread());
396 string value
= "type: " + type
+ ", sdp: " + sdp
;
397 SendPeerConnectionUpdate(
399 source
== SOURCE_LOCAL
? "setLocalDescription" : "setRemoteDescription",
403 void PeerConnectionTracker::TrackUpdateIce(
404 RTCPeerConnectionHandler
* pc_handler
,
405 const webrtc::PeerConnectionInterface::RTCConfiguration
& config
,
406 const RTCMediaConstraints
& options
) {
407 DCHECK(main_thread_
.CalledOnValidThread());
408 string servers_string
= "servers: " + SerializeServers(config
.servers
);
410 string transport_type
=
411 "iceTransportType: " + SerializeIceTransportType(config
.type
);
414 "constraints: {" + SerializeMediaConstraints(options
) + "}";
416 SendPeerConnectionUpdate(
419 servers_string
+ ", " + transport_type
+ ", " + constraints
);
422 void PeerConnectionTracker::TrackAddIceCandidate(
423 RTCPeerConnectionHandler
* pc_handler
,
424 const blink::WebRTCICECandidate
& candidate
,
427 DCHECK(main_thread_
.CalledOnValidThread());
429 "sdpMid: " + base::UTF16ToUTF8(candidate
.sdpMid()) + ", " +
430 "sdpMLineIndex: " + base::IntToString(candidate
.sdpMLineIndex()) + ", " +
431 "candidate: " + base::UTF16ToUTF8(candidate
.candidate());
433 // OnIceCandidate always succeeds as it's a callback from the browser.
434 DCHECK(source
!= SOURCE_LOCAL
|| succeeded
);
437 (source
== SOURCE_LOCAL
) ? "onIceCandidate"
438 : (succeeded
? "addIceCandidate"
439 : "addIceCandidateFailed");
441 SendPeerConnectionUpdate(pc_handler
, event
, value
);
444 void PeerConnectionTracker::TrackAddStream(
445 RTCPeerConnectionHandler
* pc_handler
,
446 const blink::WebMediaStream
& stream
,
448 DCHECK(main_thread_
.CalledOnValidThread());
449 SendPeerConnectionUpdate(
450 pc_handler
, source
== SOURCE_LOCAL
? "addStream" : "onAddStream",
451 SerializeMediaDescriptor(stream
));
454 void PeerConnectionTracker::TrackRemoveStream(
455 RTCPeerConnectionHandler
* pc_handler
,
456 const blink::WebMediaStream
& stream
,
458 DCHECK(main_thread_
.CalledOnValidThread());
459 SendPeerConnectionUpdate(
460 pc_handler
, source
== SOURCE_LOCAL
? "removeStream" : "onRemoveStream",
461 SerializeMediaDescriptor(stream
));
464 void PeerConnectionTracker::TrackCreateDataChannel(
465 RTCPeerConnectionHandler
* pc_handler
,
466 const webrtc::DataChannelInterface
* data_channel
,
468 DCHECK(main_thread_
.CalledOnValidThread());
469 string value
= "label: " + data_channel
->label() +
470 ", reliable: " + (data_channel
->reliable() ? "true" : "false");
471 SendPeerConnectionUpdate(
473 source
== SOURCE_LOCAL
? "createLocalDataChannel" : "onRemoteDataChannel",
477 void PeerConnectionTracker::TrackStop(RTCPeerConnectionHandler
* pc_handler
) {
478 DCHECK(main_thread_
.CalledOnValidThread());
479 SendPeerConnectionUpdate(pc_handler
, "stop", std::string());
482 void PeerConnectionTracker::TrackSignalingStateChange(
483 RTCPeerConnectionHandler
* pc_handler
,
484 WebRTCPeerConnectionHandlerClient::SignalingState state
) {
485 DCHECK(main_thread_
.CalledOnValidThread());
486 SendPeerConnectionUpdate(
487 pc_handler
, "signalingStateChange", GetSignalingStateString(state
));
490 void PeerConnectionTracker::TrackIceConnectionStateChange(
491 RTCPeerConnectionHandler
* pc_handler
,
492 WebRTCPeerConnectionHandlerClient::ICEConnectionState state
) {
493 DCHECK(main_thread_
.CalledOnValidThread());
494 SendPeerConnectionUpdate(
495 pc_handler
, "iceConnectionStateChange",
496 GetIceConnectionStateString(state
));
499 void PeerConnectionTracker::TrackIceGatheringStateChange(
500 RTCPeerConnectionHandler
* pc_handler
,
501 WebRTCPeerConnectionHandlerClient::ICEGatheringState state
) {
502 DCHECK(main_thread_
.CalledOnValidThread());
503 SendPeerConnectionUpdate(
504 pc_handler
, "iceGatheringStateChange",
505 GetIceGatheringStateString(state
));
508 void PeerConnectionTracker::TrackSessionDescriptionCallback(
509 RTCPeerConnectionHandler
* pc_handler
, Action action
,
510 const string
& callback_type
, const string
& value
) {
511 DCHECK(main_thread_
.CalledOnValidThread());
514 case ACTION_SET_LOCAL_DESCRIPTION
:
515 update_type
= "setLocalDescription";
517 case ACTION_SET_REMOTE_DESCRIPTION
:
518 update_type
= "setRemoteDescription";
520 case ACTION_CREATE_OFFER
:
521 update_type
= "createOffer";
523 case ACTION_CREATE_ANSWER
:
524 update_type
= "createAnswer";
530 update_type
+= callback_type
;
532 SendPeerConnectionUpdate(pc_handler
, update_type
, value
);
535 void PeerConnectionTracker::TrackOnRenegotiationNeeded(
536 RTCPeerConnectionHandler
* pc_handler
) {
537 DCHECK(main_thread_
.CalledOnValidThread());
538 SendPeerConnectionUpdate(pc_handler
, "onRenegotiationNeeded", std::string());
541 void PeerConnectionTracker::TrackCreateDTMFSender(
542 RTCPeerConnectionHandler
* pc_handler
,
543 const blink::WebMediaStreamTrack
& track
) {
544 DCHECK(main_thread_
.CalledOnValidThread());
545 SendPeerConnectionUpdate(pc_handler
, "createDTMFSender",
546 base::UTF16ToUTF8(track
.id()));
549 void PeerConnectionTracker::TrackGetUserMedia(
550 const blink::WebUserMediaRequest
& user_media_request
) {
551 DCHECK(main_thread_
.CalledOnValidThread());
552 RTCMediaConstraints
audio_constraints(
553 GetNativeMediaConstraints(user_media_request
.audioConstraints()));
554 RTCMediaConstraints
video_constraints(
555 GetNativeMediaConstraints(user_media_request
.videoConstraints()));
557 RenderThreadImpl::current()->Send(new PeerConnectionTrackerHost_GetUserMedia(
558 user_media_request
.securityOrigin().toString().utf8(),
559 user_media_request
.audio(),
560 user_media_request
.video(),
561 SerializeMediaConstraints(audio_constraints
),
562 SerializeMediaConstraints(video_constraints
)));
565 int PeerConnectionTracker::GetNextLocalID() {
566 DCHECK(main_thread_
.CalledOnValidThread());
570 void PeerConnectionTracker::SendPeerConnectionUpdate(
571 RTCPeerConnectionHandler
* pc_handler
,
572 const std::string
& type
,
573 const std::string
& value
) {
574 DCHECK(main_thread_
.CalledOnValidThread());
575 if (peer_connection_id_map_
.find(pc_handler
) == peer_connection_id_map_
.end())
578 RenderThreadImpl::current()->Send(
579 new PeerConnectionTrackerHost_UpdatePeerConnection(
580 peer_connection_id_map_
[pc_handler
], type
, value
));
583 } // namespace content