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/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/WebMediaConstraints.h"
12 #include "third_party/WebKit/public/platform/WebMediaStream.h"
13 #include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
14 #include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
15 #include "third_party/WebKit/public/platform/WebRTCICECandidate.h"
16 #include "third_party/WebKit/public/platform/WebRTCPeerConnectionHandlerClient.h"
17 #include "third_party/WebKit/public/web/WebDocument.h"
18 #include "third_party/WebKit/public/web/WebFrame.h"
19 #include "third_party/WebKit/public/web/WebUserMediaRequest.h"
22 using webrtc::MediaConstraintsInterface
;
23 using blink::WebRTCPeerConnectionHandlerClient
;
27 static string
SerializeServers(
28 const std::vector
<webrtc::PeerConnectionInterface::IceServer
>& servers
) {
30 for (size_t i
= 0; i
< servers
.size(); ++i
) {
31 result
+= servers
[i
].uri
;
32 if (i
!= servers
.size() - 1)
39 static RTCMediaConstraints
GetNativeMediaConstraints(
40 const blink::WebMediaConstraints
& constraints
) {
41 RTCMediaConstraints native_constraints
;
43 if (constraints
.isNull())
44 return native_constraints
;
46 blink::WebVector
<blink::WebMediaConstraint
> mandatory
;
47 constraints
.getMandatoryConstraints(mandatory
);
48 for (size_t i
= 0; i
< mandatory
.size(); ++i
) {
49 native_constraints
.AddMandatory(
50 mandatory
[i
].m_name
.utf8(), mandatory
[i
].m_value
.utf8(), false);
53 blink::WebVector
<blink::WebMediaConstraint
> optional
;
54 constraints
.getOptionalConstraints(optional
);
55 for (size_t i
= 0; i
< optional
.size(); ++i
) {
56 native_constraints
.AddOptional(
57 optional
[i
].m_name
.utf8(), optional
[i
].m_value
.utf8(), false);
59 return native_constraints
;
62 static string
SerializeMediaConstraints(
63 const RTCMediaConstraints
& constraints
) {
65 MediaConstraintsInterface::Constraints mandatory
= constraints
.GetMandatory();
66 if (!mandatory
.empty()) {
67 result
+= "mandatory: {";
68 for (size_t i
= 0; i
< mandatory
.size(); ++i
) {
69 result
+= mandatory
[i
].key
+ ":" + mandatory
[i
].value
;
70 if (i
!= mandatory
.size() - 1)
75 MediaConstraintsInterface::Constraints optional
= constraints
.GetOptional();
76 if (!optional
.empty()) {
79 result
+= "optional: {";
80 for (size_t i
= 0; i
< optional
.size(); ++i
) {
81 result
+= optional
[i
].key
+ ":" + optional
[i
].value
;
82 if (i
!= optional
.size() - 1)
90 static string
SerializeMediaStreamComponent(
91 const blink::WebMediaStreamTrack component
) {
92 string id
= base::UTF16ToUTF8(component
.source().id());
96 static string
SerializeMediaDescriptor(
97 const blink::WebMediaStream
& stream
) {
98 string label
= base::UTF16ToUTF8(stream
.id());
99 string result
= "label: " + label
;
100 blink::WebVector
<blink::WebMediaStreamTrack
> tracks
;
101 stream
.audioTracks(tracks
);
102 if (!tracks
.isEmpty()) {
103 result
+= ", audio: [";
104 for (size_t i
= 0; i
< tracks
.size(); ++i
) {
105 result
+= SerializeMediaStreamComponent(tracks
[i
]);
106 if (i
!= tracks
.size() - 1)
111 stream
.videoTracks(tracks
);
112 if (!tracks
.isEmpty()) {
113 result
+= ", video: [";
114 for (size_t i
= 0; i
< tracks
.size(); ++i
) {
115 result
+= SerializeMediaStreamComponent(tracks
[i
]);
116 if (i
!= tracks
.size() - 1)
124 static std::string
SerializeIceTransportType(
125 webrtc::PeerConnectionInterface::IceTransportsType type
) {
126 string transport_type
;
128 case webrtc::PeerConnectionInterface::kNone
:
129 transport_type
= "none";
131 case webrtc::PeerConnectionInterface::kRelay
:
132 transport_type
= "relay";
134 case webrtc::PeerConnectionInterface::kAll
:
135 transport_type
= "all";
137 case webrtc::PeerConnectionInterface::kNoHost
:
138 transport_type
= "noHost";
143 return transport_type
;
146 #define GET_STRING_OF_STATE(state) \
147 case WebRTCPeerConnectionHandlerClient::state: \
151 static string
GetSignalingStateString(
152 WebRTCPeerConnectionHandlerClient::SignalingState state
) {
155 GET_STRING_OF_STATE(SignalingStateStable
)
156 GET_STRING_OF_STATE(SignalingStateHaveLocalOffer
)
157 GET_STRING_OF_STATE(SignalingStateHaveRemoteOffer
)
158 GET_STRING_OF_STATE(SignalingStateHaveLocalPrAnswer
)
159 GET_STRING_OF_STATE(SignalingStateHaveRemotePrAnswer
)
160 GET_STRING_OF_STATE(SignalingStateClosed
)
168 static string
GetIceConnectionStateString(
169 WebRTCPeerConnectionHandlerClient::ICEConnectionState state
) {
172 GET_STRING_OF_STATE(ICEConnectionStateStarting
)
173 GET_STRING_OF_STATE(ICEConnectionStateChecking
)
174 GET_STRING_OF_STATE(ICEConnectionStateConnected
)
175 GET_STRING_OF_STATE(ICEConnectionStateCompleted
)
176 GET_STRING_OF_STATE(ICEConnectionStateFailed
)
177 GET_STRING_OF_STATE(ICEConnectionStateDisconnected
)
178 GET_STRING_OF_STATE(ICEConnectionStateClosed
)
186 static string
GetIceGatheringStateString(
187 WebRTCPeerConnectionHandlerClient::ICEGatheringState state
) {
190 GET_STRING_OF_STATE(ICEGatheringStateNew
)
191 GET_STRING_OF_STATE(ICEGatheringStateGathering
)
192 GET_STRING_OF_STATE(ICEGatheringStateComplete
)
200 // Builds a DictionaryValue from the StatsReport.
201 // The caller takes the ownership of the returned value.
203 // The format must be consistent with what webrtc_internals.js expects.
204 // If you change it here, you must change webrtc_internals.js as well.
205 static base::DictionaryValue
* GetDictValueStats(
206 const webrtc::StatsReport
& report
) {
207 if (report
.values
.empty())
210 base::DictionaryValue
* dict
= new base::DictionaryValue();
211 dict
->SetDouble("timestamp", report
.timestamp
);
213 base::ListValue
* values
= new base::ListValue();
214 dict
->Set("values", values
);
216 for (size_t i
= 0; i
< report
.values
.size(); ++i
) {
217 values
->AppendString(report
.values
[i
].display_name());
218 values
->AppendString(report
.values
[i
].value
);
223 // Builds a DictionaryValue from the StatsReport.
224 // The caller takes the ownership of the returned value.
225 static base::DictionaryValue
* GetDictValue(const webrtc::StatsReport
& report
) {
226 scoped_ptr
<base::DictionaryValue
> stats
, result
;
228 stats
.reset(GetDictValueStats(report
));
232 result
.reset(new base::DictionaryValue());
234 // The format must be consistent with what webrtc_internals.js expects.
235 // If you change it here, you must change webrtc_internals.js as well.
236 result
->Set("stats", stats
.release());
237 result
->SetString("id", report
.id
);
238 result
->SetString("type", report
.type
);
240 return result
.release();
243 class InternalStatsObserver
: public webrtc::StatsObserver
{
245 InternalStatsObserver(int lid
)
248 virtual void OnComplete(
249 const std::vector
<webrtc::StatsReport
>& reports
) OVERRIDE
{
250 base::ListValue list
;
252 for (size_t i
= 0; i
< reports
.size(); ++i
) {
253 base::DictionaryValue
* report
= GetDictValue(reports
[i
]);
259 RenderThreadImpl::current()->Send(
260 new PeerConnectionTrackerHost_AddStats(lid_
, list
));
264 virtual ~InternalStatsObserver() {}
270 PeerConnectionTracker::PeerConnectionTracker() : next_lid_(1) {
273 PeerConnectionTracker::~PeerConnectionTracker() {
276 bool PeerConnectionTracker::OnControlMessageReceived(
277 const IPC::Message
& message
) {
279 IPC_BEGIN_MESSAGE_MAP(PeerConnectionTracker
, message
)
280 IPC_MESSAGE_HANDLER(PeerConnectionTracker_GetAllStats
, OnGetAllStats
)
281 IPC_MESSAGE_UNHANDLED(handled
= false)
282 IPC_END_MESSAGE_MAP()
286 void PeerConnectionTracker::OnGetAllStats() {
287 for (PeerConnectionIdMap::iterator it
= peer_connection_id_map_
.begin();
288 it
!= peer_connection_id_map_
.end(); ++it
) {
290 rtc::scoped_refptr
<InternalStatsObserver
> observer(
291 new rtc::RefCountedObject
<InternalStatsObserver
>(it
->second
));
296 webrtc::PeerConnectionInterface::kStatsOutputLevelDebug
);
300 void PeerConnectionTracker::RegisterPeerConnection(
301 RTCPeerConnectionHandler
* pc_handler
,
302 const webrtc::PeerConnectionInterface::RTCConfiguration
& config
,
303 const RTCMediaConstraints
& constraints
,
304 const blink::WebFrame
* frame
) {
305 DVLOG(1) << "PeerConnectionTracker::RegisterPeerConnection()";
306 PeerConnectionInfo info
;
308 info
.lid
= GetNextLocalID();
309 info
.rtc_configuration
=
310 "{ servers: " + SerializeServers(config
.servers
) + ", " +
311 "iceTransportType: " + SerializeIceTransportType(config
.type
) + " }";
313 info
.constraints
= SerializeMediaConstraints(constraints
);
314 info
.url
= frame
->document().url().spec();
315 RenderThreadImpl::current()->Send(
316 new PeerConnectionTrackerHost_AddPeerConnection(info
));
318 DCHECK(peer_connection_id_map_
.find(pc_handler
) ==
319 peer_connection_id_map_
.end());
320 peer_connection_id_map_
[pc_handler
] = info
.lid
;
323 void PeerConnectionTracker::UnregisterPeerConnection(
324 RTCPeerConnectionHandler
* pc_handler
) {
325 DVLOG(1) << "PeerConnectionTracker::UnregisterPeerConnection()";
327 std::map
<RTCPeerConnectionHandler
*, int>::iterator it
=
328 peer_connection_id_map_
.find(pc_handler
);
330 if (it
== peer_connection_id_map_
.end()) {
331 // The PeerConnection might not have been registered if its initilization
336 RenderThreadImpl::current()->Send(
337 new PeerConnectionTrackerHost_RemovePeerConnection(it
->second
));
339 peer_connection_id_map_
.erase(it
);
342 void PeerConnectionTracker::TrackCreateOffer(
343 RTCPeerConnectionHandler
* pc_handler
,
344 const RTCMediaConstraints
& constraints
) {
345 SendPeerConnectionUpdate(
346 pc_handler
, "createOffer",
347 "constraints: {" + SerializeMediaConstraints(constraints
) + "}");
350 void PeerConnectionTracker::TrackCreateAnswer(
351 RTCPeerConnectionHandler
* pc_handler
,
352 const RTCMediaConstraints
& constraints
) {
353 SendPeerConnectionUpdate(
354 pc_handler
, "createAnswer",
355 "constraints: {" + SerializeMediaConstraints(constraints
) + "}");
358 void PeerConnectionTracker::TrackSetSessionDescription(
359 RTCPeerConnectionHandler
* pc_handler
,
360 const blink::WebRTCSessionDescription
& desc
,
362 string sdp
= base::UTF16ToUTF8(desc
.sdp());
363 string type
= base::UTF16ToUTF8(desc
.type());
365 string value
= "type: " + type
+ ", sdp: " + sdp
;
366 SendPeerConnectionUpdate(
368 source
== SOURCE_LOCAL
? "setLocalDescription" : "setRemoteDescription",
372 void PeerConnectionTracker::TrackUpdateIce(
373 RTCPeerConnectionHandler
* pc_handler
,
374 const webrtc::PeerConnectionInterface::RTCConfiguration
& config
,
375 const RTCMediaConstraints
& options
) {
376 string servers_string
= "servers: " + SerializeServers(config
.servers
);
378 string transport_type
=
379 "iceTransportType: " + SerializeIceTransportType(config
.type
);
382 "constraints: {" + SerializeMediaConstraints(options
) + "}";
384 SendPeerConnectionUpdate(
387 servers_string
+ ", " + transport_type
+ ", " + constraints
);
390 void PeerConnectionTracker::TrackAddIceCandidate(
391 RTCPeerConnectionHandler
* pc_handler
,
392 const blink::WebRTCICECandidate
& candidate
,
394 string value
= "mid: " + base::UTF16ToUTF8(candidate
.sdpMid()) + ", " +
395 "candidate: " + base::UTF16ToUTF8(candidate
.candidate());
396 SendPeerConnectionUpdate(
398 source
== SOURCE_LOCAL
? "onIceCandidate" : "addIceCandidate", value
);
401 void PeerConnectionTracker::TrackAddStream(
402 RTCPeerConnectionHandler
* pc_handler
,
403 const blink::WebMediaStream
& stream
,
405 SendPeerConnectionUpdate(
406 pc_handler
, source
== SOURCE_LOCAL
? "addStream" : "onAddStream",
407 SerializeMediaDescriptor(stream
));
410 void PeerConnectionTracker::TrackRemoveStream(
411 RTCPeerConnectionHandler
* pc_handler
,
412 const blink::WebMediaStream
& stream
,
414 SendPeerConnectionUpdate(
415 pc_handler
, source
== SOURCE_LOCAL
? "removeStream" : "onRemoveStream",
416 SerializeMediaDescriptor(stream
));
419 void PeerConnectionTracker::TrackCreateDataChannel(
420 RTCPeerConnectionHandler
* pc_handler
,
421 const webrtc::DataChannelInterface
* data_channel
,
423 string value
= "label: " + data_channel
->label() +
424 ", reliable: " + (data_channel
->reliable() ? "true" : "false");
425 SendPeerConnectionUpdate(
427 source
== SOURCE_LOCAL
? "createLocalDataChannel" : "onRemoteDataChannel",
431 void PeerConnectionTracker::TrackStop(RTCPeerConnectionHandler
* pc_handler
) {
432 SendPeerConnectionUpdate(pc_handler
, "stop", std::string());
435 void PeerConnectionTracker::TrackSignalingStateChange(
436 RTCPeerConnectionHandler
* pc_handler
,
437 WebRTCPeerConnectionHandlerClient::SignalingState state
) {
438 SendPeerConnectionUpdate(
439 pc_handler
, "signalingStateChange", GetSignalingStateString(state
));
442 void PeerConnectionTracker::TrackIceConnectionStateChange(
443 RTCPeerConnectionHandler
* pc_handler
,
444 WebRTCPeerConnectionHandlerClient::ICEConnectionState state
) {
445 SendPeerConnectionUpdate(
446 pc_handler
, "iceConnectionStateChange",
447 GetIceConnectionStateString(state
));
450 void PeerConnectionTracker::TrackIceGatheringStateChange(
451 RTCPeerConnectionHandler
* pc_handler
,
452 WebRTCPeerConnectionHandlerClient::ICEGatheringState state
) {
453 SendPeerConnectionUpdate(
454 pc_handler
, "iceGatheringStateChange",
455 GetIceGatheringStateString(state
));
458 void PeerConnectionTracker::TrackSessionDescriptionCallback(
459 RTCPeerConnectionHandler
* pc_handler
, Action action
,
460 const string
& callback_type
, const string
& value
) {
463 case ACTION_SET_LOCAL_DESCRIPTION
:
464 update_type
= "setLocalDescription";
466 case ACTION_SET_REMOTE_DESCRIPTION
:
467 update_type
= "setRemoteDescription";
469 case ACTION_CREATE_OFFER
:
470 update_type
= "createOffer";
472 case ACTION_CREATE_ANSWER
:
473 update_type
= "createAnswer";
479 update_type
+= callback_type
;
481 SendPeerConnectionUpdate(pc_handler
, update_type
, value
);
484 void PeerConnectionTracker::TrackOnRenegotiationNeeded(
485 RTCPeerConnectionHandler
* pc_handler
) {
486 SendPeerConnectionUpdate(pc_handler
, "onRenegotiationNeeded", std::string());
489 void PeerConnectionTracker::TrackCreateDTMFSender(
490 RTCPeerConnectionHandler
* pc_handler
,
491 const blink::WebMediaStreamTrack
& track
) {
492 SendPeerConnectionUpdate(pc_handler
, "createDTMFSender",
493 base::UTF16ToUTF8(track
.id()));
496 void PeerConnectionTracker::TrackGetUserMedia(
497 const blink::WebUserMediaRequest
& user_media_request
) {
498 RTCMediaConstraints
audio_constraints(
499 GetNativeMediaConstraints(user_media_request
.audioConstraints()));
500 RTCMediaConstraints
video_constraints(
501 GetNativeMediaConstraints(user_media_request
.videoConstraints()));
503 RenderThreadImpl::current()->Send(new PeerConnectionTrackerHost_GetUserMedia(
504 user_media_request
.securityOrigin().toString().utf8(),
505 user_media_request
.audio(),
506 user_media_request
.video(),
507 SerializeMediaConstraints(audio_constraints
),
508 SerializeMediaConstraints(video_constraints
)));
511 int PeerConnectionTracker::GetNextLocalID() {
515 void PeerConnectionTracker::SendPeerConnectionUpdate(
516 RTCPeerConnectionHandler
* pc_handler
,
517 const std::string
& type
,
518 const std::string
& value
) {
519 if (peer_connection_id_map_
.find(pc_handler
) == peer_connection_id_map_
.end())
522 RenderThreadImpl::current()->Send(
523 new PeerConnectionTrackerHost_UpdatePeerConnection(
524 peer_connection_id_map_
[pc_handler
], type
, value
));
527 } // namespace content