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
SerializeServers(const std::vector<webrtc::PeerConnectionInterface::IceServer> & servers)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
SerializeMediaConstraints(const RTCMediaConstraints & constraints)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
SerializeMediaStreamComponent(const blink::WebMediaStreamTrack component)65 static string SerializeMediaStreamComponent(
66 const blink::WebMediaStreamTrack component) {
67 string id = UTF16ToUTF8(component.source().id());
68 return id;
69 }
70
SerializeMediaDescriptor(const blink::WebMediaStream & stream)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
GetSignalingStateString(WebRTCPeerConnectionHandlerClient::SignalingState state)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
GetIceConnectionStateString(WebRTCPeerConnectionHandlerClient::ICEConnectionState state)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
GetIceGatheringStateString(WebRTCPeerConnectionHandlerClient::ICEGatheringState state)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.
GetDictValueStats(const webrtc::StatsReport & report)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.
GetDictValue(const webrtc::StatsReport & report)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:
InternalStatsObserver(int lid)198 InternalStatsObserver(int lid)
199 : lid_(lid){}
200
OnComplete(const std::vector<webrtc::StatsReport> & reports)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:
~InternalStatsObserver()217 virtual ~InternalStatsObserver() {}
218
219 private:
220 int lid_;
221 };
222
PeerConnectionTracker()223 PeerConnectionTracker::PeerConnectionTracker() : next_lid_(1) {
224 }
225
~PeerConnectionTracker()226 PeerConnectionTracker::~PeerConnectionTracker() {
227 }
228
OnControlMessageReceived(const IPC::Message & message)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
OnGetAllStats()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
RegisterPeerConnection(RTCPeerConnectionHandler * pc_handler,const std::vector<webrtc::PeerConnectionInterface::IceServer> & servers,const RTCMediaConstraints & constraints,const blink::WebFrame * frame)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
UnregisterPeerConnection(RTCPeerConnectionHandler * pc_handler)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
TrackCreateOffer(RTCPeerConnectionHandler * pc_handler,const RTCMediaConstraints & constraints)289 void PeerConnectionTracker::TrackCreateOffer(
290 RTCPeerConnectionHandler* pc_handler,
291 const RTCMediaConstraints& constraints) {
292 SendPeerConnectionUpdate(
293 pc_handler, "createOffer",
294 "constraints: {" + SerializeMediaConstraints(constraints) + "}");
295 }
296
TrackCreateAnswer(RTCPeerConnectionHandler * pc_handler,const RTCMediaConstraints & constraints)297 void PeerConnectionTracker::TrackCreateAnswer(
298 RTCPeerConnectionHandler* pc_handler,
299 const RTCMediaConstraints& constraints) {
300 SendPeerConnectionUpdate(
301 pc_handler, "createAnswer",
302 "constraints: {" + SerializeMediaConstraints(constraints) + "}");
303 }
304
TrackSetSessionDescription(RTCPeerConnectionHandler * pc_handler,const blink::WebRTCSessionDescription & desc,Source source)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
TrackUpdateIce(RTCPeerConnectionHandler * pc_handler,const std::vector<webrtc::PeerConnectionInterface::IceServer> & servers,const RTCMediaConstraints & options)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
TrackAddIceCandidate(RTCPeerConnectionHandler * pc_handler,const blink::WebRTCICECandidate & candidate,Source source)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
TrackAddStream(RTCPeerConnectionHandler * pc_handler,const blink::WebMediaStream & stream,Source source)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
TrackRemoveStream(RTCPeerConnectionHandler * pc_handler,const blink::WebMediaStream & stream,Source source)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
TrackCreateDataChannel(RTCPeerConnectionHandler * pc_handler,const webrtc::DataChannelInterface * data_channel,Source source)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
TrackStop(RTCPeerConnectionHandler * pc_handler)372 void PeerConnectionTracker::TrackStop(RTCPeerConnectionHandler* pc_handler) {
373 SendPeerConnectionUpdate(pc_handler, "stop", std::string());
374 }
375
TrackSignalingStateChange(RTCPeerConnectionHandler * pc_handler,WebRTCPeerConnectionHandlerClient::SignalingState state)376 void PeerConnectionTracker::TrackSignalingStateChange(
377 RTCPeerConnectionHandler* pc_handler,
378 WebRTCPeerConnectionHandlerClient::SignalingState state) {
379 SendPeerConnectionUpdate(
380 pc_handler, "signalingStateChange", GetSignalingStateString(state));
381 }
382
TrackIceConnectionStateChange(RTCPeerConnectionHandler * pc_handler,WebRTCPeerConnectionHandlerClient::ICEConnectionState state)383 void PeerConnectionTracker::TrackIceConnectionStateChange(
384 RTCPeerConnectionHandler* pc_handler,
385 WebRTCPeerConnectionHandlerClient::ICEConnectionState state) {
386 SendPeerConnectionUpdate(
387 pc_handler, "iceConnectionStateChange",
388 GetIceConnectionStateString(state));
389 }
390
TrackIceGatheringStateChange(RTCPeerConnectionHandler * pc_handler,WebRTCPeerConnectionHandlerClient::ICEGatheringState state)391 void PeerConnectionTracker::TrackIceGatheringStateChange(
392 RTCPeerConnectionHandler* pc_handler,
393 WebRTCPeerConnectionHandlerClient::ICEGatheringState state) {
394 SendPeerConnectionUpdate(
395 pc_handler, "iceGatheringStateChange",
396 GetIceGatheringStateString(state));
397 }
398
TrackSessionDescriptionCallback(RTCPeerConnectionHandler * pc_handler,Action action,const string & callback_type,const string & value)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
TrackOnRenegotiationNeeded(RTCPeerConnectionHandler * pc_handler)425 void PeerConnectionTracker::TrackOnRenegotiationNeeded(
426 RTCPeerConnectionHandler* pc_handler) {
427 SendPeerConnectionUpdate(pc_handler, "onRenegotiationNeeded", std::string());
428 }
429
TrackCreateDTMFSender(RTCPeerConnectionHandler * pc_handler,const blink::WebMediaStreamTrack & track)430 void PeerConnectionTracker::TrackCreateDTMFSender(
431 RTCPeerConnectionHandler* pc_handler,
432 const blink::WebMediaStreamTrack& track) {
433 SendPeerConnectionUpdate(pc_handler, "createDTMFSender",
434 UTF16ToUTF8(track.id()));
435 }
436
GetNextLocalID()437 int PeerConnectionTracker::GetNextLocalID() {
438 return next_lid_++;
439 }
440
SendPeerConnectionUpdate(RTCPeerConnectionHandler * pc_handler,const std::string & type,const std::string & value)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