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/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"
20
21 using std::string;
22 using webrtc::MediaConstraintsInterface;
23 using blink::WebRTCPeerConnectionHandlerClient;
24
25 namespace content {
26
SerializeServers(const std::vector<webrtc::PeerConnectionInterface::IceServer> & servers)27 static string SerializeServers(
28 const std::vector<webrtc::PeerConnectionInterface::IceServer>& servers) {
29 string result = "[";
30 for (size_t i = 0; i < servers.size(); ++i) {
31 result += servers[i].uri;
32 if (i != servers.size() - 1)
33 result += ", ";
34 }
35 result += "]";
36 return result;
37 }
38
SerializeMediaConstraints(const RTCMediaConstraints & constraints)39 static string SerializeMediaConstraints(
40 const RTCMediaConstraints& constraints) {
41 string result;
42 MediaConstraintsInterface::Constraints mandatory = constraints.GetMandatory();
43 if (!mandatory.empty()) {
44 result += "mandatory: {";
45 for (size_t i = 0; i < mandatory.size(); ++i) {
46 result += mandatory[i].key + ":" + mandatory[i].value;
47 if (i != mandatory.size() - 1)
48 result += ", ";
49 }
50 result += "}";
51 }
52 MediaConstraintsInterface::Constraints optional = constraints.GetOptional();
53 if (!optional.empty()) {
54 if (!result.empty())
55 result += ", ";
56 result += "optional: {";
57 for (size_t i = 0; i < optional.size(); ++i) {
58 result += optional[i].key + ":" + optional[i].value;
59 if (i != optional.size() - 1)
60 result += ", ";
61 }
62 result += "}";
63 }
64 return result;
65 }
66
SerializeMediaStreamComponent(const blink::WebMediaStreamTrack component)67 static string SerializeMediaStreamComponent(
68 const blink::WebMediaStreamTrack component) {
69 string id = base::UTF16ToUTF8(component.source().id());
70 return id;
71 }
72
SerializeMediaDescriptor(const blink::WebMediaStream & stream)73 static string SerializeMediaDescriptor(
74 const blink::WebMediaStream& stream) {
75 string label = base::UTF16ToUTF8(stream.id());
76 string result = "label: " + label;
77 blink::WebVector<blink::WebMediaStreamTrack> tracks;
78 stream.audioTracks(tracks);
79 if (!tracks.isEmpty()) {
80 result += ", audio: [";
81 for (size_t i = 0; i < tracks.size(); ++i) {
82 result += SerializeMediaStreamComponent(tracks[i]);
83 if (i != tracks.size() - 1)
84 result += ", ";
85 }
86 result += "]";
87 }
88 stream.videoTracks(tracks);
89 if (!tracks.isEmpty()) {
90 result += ", video: [";
91 for (size_t i = 0; i < tracks.size(); ++i) {
92 result += SerializeMediaStreamComponent(tracks[i]);
93 if (i != tracks.size() - 1)
94 result += ", ";
95 }
96 result += "]";
97 }
98 return result;
99 }
100
101 #define GET_STRING_OF_STATE(state) \
102 case WebRTCPeerConnectionHandlerClient::state: \
103 result = #state; \
104 break;
105
GetSignalingStateString(WebRTCPeerConnectionHandlerClient::SignalingState state)106 static string GetSignalingStateString(
107 WebRTCPeerConnectionHandlerClient::SignalingState state) {
108 string result;
109 switch (state) {
110 GET_STRING_OF_STATE(SignalingStateStable)
111 GET_STRING_OF_STATE(SignalingStateHaveLocalOffer)
112 GET_STRING_OF_STATE(SignalingStateHaveRemoteOffer)
113 GET_STRING_OF_STATE(SignalingStateHaveLocalPrAnswer)
114 GET_STRING_OF_STATE(SignalingStateHaveRemotePrAnswer)
115 GET_STRING_OF_STATE(SignalingStateClosed)
116 default:
117 NOTREACHED();
118 break;
119 }
120 return result;
121 }
122
GetIceConnectionStateString(WebRTCPeerConnectionHandlerClient::ICEConnectionState state)123 static string GetIceConnectionStateString(
124 WebRTCPeerConnectionHandlerClient::ICEConnectionState state) {
125 string result;
126 switch (state) {
127 GET_STRING_OF_STATE(ICEConnectionStateStarting)
128 GET_STRING_OF_STATE(ICEConnectionStateChecking)
129 GET_STRING_OF_STATE(ICEConnectionStateConnected)
130 GET_STRING_OF_STATE(ICEConnectionStateCompleted)
131 GET_STRING_OF_STATE(ICEConnectionStateFailed)
132 GET_STRING_OF_STATE(ICEConnectionStateDisconnected)
133 GET_STRING_OF_STATE(ICEConnectionStateClosed)
134 default:
135 NOTREACHED();
136 break;
137 }
138 return result;
139 }
140
GetIceGatheringStateString(WebRTCPeerConnectionHandlerClient::ICEGatheringState state)141 static string GetIceGatheringStateString(
142 WebRTCPeerConnectionHandlerClient::ICEGatheringState state) {
143 string result;
144 switch (state) {
145 GET_STRING_OF_STATE(ICEGatheringStateNew)
146 GET_STRING_OF_STATE(ICEGatheringStateGathering)
147 GET_STRING_OF_STATE(ICEGatheringStateComplete)
148 default:
149 NOTREACHED();
150 break;
151 }
152 return result;
153 }
154
155 // Builds a DictionaryValue from the StatsReport.
156 // The caller takes the ownership of the returned value.
157 // Note:
158 // The format must be consistent with what webrtc_internals.js expects.
159 // If you change it here, you must change webrtc_internals.js as well.
GetDictValueStats(const webrtc::StatsReport & report)160 static base::DictionaryValue* GetDictValueStats(
161 const webrtc::StatsReport& report) {
162 if (report.values.empty())
163 return NULL;
164
165 base::DictionaryValue* dict = new base::DictionaryValue();
166 dict->SetDouble("timestamp", report.timestamp);
167
168 base::ListValue* values = new base::ListValue();
169 dict->Set("values", values);
170
171 for (size_t i = 0; i < report.values.size(); ++i) {
172 values->AppendString(report.values[i].name);
173 values->AppendString(report.values[i].value);
174 }
175 return dict;
176 }
177
178 // Builds a DictionaryValue from the StatsReport.
179 // The caller takes the ownership of the returned value.
GetDictValue(const webrtc::StatsReport & report)180 static base::DictionaryValue* GetDictValue(const webrtc::StatsReport& report) {
181 scoped_ptr<base::DictionaryValue> stats, result;
182
183 stats.reset(GetDictValueStats(report));
184 if (!stats)
185 return NULL;
186
187 result.reset(new base::DictionaryValue());
188 // Note:
189 // The format must be consistent with what webrtc_internals.js expects.
190 // If you change it here, you must change webrtc_internals.js as well.
191 result->Set("stats", stats.release());
192 result->SetString("id", report.id);
193 result->SetString("type", report.type);
194
195 return result.release();
196 }
197
198 class InternalStatsObserver : public webrtc::StatsObserver {
199 public:
InternalStatsObserver(int lid)200 InternalStatsObserver(int lid)
201 : lid_(lid){}
202
OnComplete(const std::vector<webrtc::StatsReport> & reports)203 virtual void OnComplete(
204 const std::vector<webrtc::StatsReport>& reports) OVERRIDE {
205 base::ListValue list;
206
207 for (size_t i = 0; i < reports.size(); ++i) {
208 base::DictionaryValue* report = GetDictValue(reports[i]);
209 if (report)
210 list.Append(report);
211 }
212
213 if (!list.empty())
214 RenderThreadImpl::current()->Send(
215 new PeerConnectionTrackerHost_AddStats(lid_, list));
216 }
217
218 protected:
~InternalStatsObserver()219 virtual ~InternalStatsObserver() {}
220
221 private:
222 int lid_;
223 };
224
PeerConnectionTracker()225 PeerConnectionTracker::PeerConnectionTracker() : next_lid_(1) {
226 }
227
~PeerConnectionTracker()228 PeerConnectionTracker::~PeerConnectionTracker() {
229 }
230
OnControlMessageReceived(const IPC::Message & message)231 bool PeerConnectionTracker::OnControlMessageReceived(
232 const IPC::Message& message) {
233 bool handled = true;
234 IPC_BEGIN_MESSAGE_MAP(PeerConnectionTracker, message)
235 IPC_MESSAGE_HANDLER(PeerConnectionTracker_GetAllStats, OnGetAllStats)
236 IPC_MESSAGE_UNHANDLED(handled = false)
237 IPC_END_MESSAGE_MAP()
238 return handled;
239 }
240
OnGetAllStats()241 void PeerConnectionTracker::OnGetAllStats() {
242 for (PeerConnectionIdMap::iterator it = peer_connection_id_map_.begin();
243 it != peer_connection_id_map_.end(); ++it) {
244
245 talk_base::scoped_refptr<InternalStatsObserver> observer(
246 new talk_base::RefCountedObject<InternalStatsObserver>(it->second));
247
248 it->first->GetStats(
249 observer,
250 NULL,
251 webrtc::PeerConnectionInterface::kStatsOutputLevelDebug);
252 }
253 }
254
RegisterPeerConnection(RTCPeerConnectionHandler * pc_handler,const std::vector<webrtc::PeerConnectionInterface::IceServer> & servers,const RTCMediaConstraints & constraints,const blink::WebFrame * frame)255 void PeerConnectionTracker::RegisterPeerConnection(
256 RTCPeerConnectionHandler* pc_handler,
257 const std::vector<webrtc::PeerConnectionInterface::IceServer>& servers,
258 const RTCMediaConstraints& constraints,
259 const blink::WebFrame* frame) {
260 DVLOG(1) << "PeerConnectionTracker::RegisterPeerConnection()";
261 PeerConnectionInfo info;
262
263 info.lid = GetNextLocalID();
264 info.servers = SerializeServers(servers);
265 info.constraints = SerializeMediaConstraints(constraints);
266 info.url = frame->document().url().spec();
267 RenderThreadImpl::current()->Send(
268 new PeerConnectionTrackerHost_AddPeerConnection(info));
269
270 DCHECK(peer_connection_id_map_.find(pc_handler) ==
271 peer_connection_id_map_.end());
272 peer_connection_id_map_[pc_handler] = info.lid;
273 }
274
UnregisterPeerConnection(RTCPeerConnectionHandler * pc_handler)275 void PeerConnectionTracker::UnregisterPeerConnection(
276 RTCPeerConnectionHandler* pc_handler) {
277 DVLOG(1) << "PeerConnectionTracker::UnregisterPeerConnection()";
278
279 std::map<RTCPeerConnectionHandler*, int>::iterator it =
280 peer_connection_id_map_.find(pc_handler);
281
282 if (it == peer_connection_id_map_.end()) {
283 // The PeerConnection might not have been registered if its initilization
284 // failed.
285 return;
286 }
287
288 RenderThreadImpl::current()->Send(
289 new PeerConnectionTrackerHost_RemovePeerConnection(it->second));
290
291 peer_connection_id_map_.erase(it);
292 }
293
TrackCreateOffer(RTCPeerConnectionHandler * pc_handler,const RTCMediaConstraints & constraints)294 void PeerConnectionTracker::TrackCreateOffer(
295 RTCPeerConnectionHandler* pc_handler,
296 const RTCMediaConstraints& constraints) {
297 SendPeerConnectionUpdate(
298 pc_handler, "createOffer",
299 "constraints: {" + SerializeMediaConstraints(constraints) + "}");
300 }
301
TrackCreateAnswer(RTCPeerConnectionHandler * pc_handler,const RTCMediaConstraints & constraints)302 void PeerConnectionTracker::TrackCreateAnswer(
303 RTCPeerConnectionHandler* pc_handler,
304 const RTCMediaConstraints& constraints) {
305 SendPeerConnectionUpdate(
306 pc_handler, "createAnswer",
307 "constraints: {" + SerializeMediaConstraints(constraints) + "}");
308 }
309
TrackSetSessionDescription(RTCPeerConnectionHandler * pc_handler,const blink::WebRTCSessionDescription & desc,Source source)310 void PeerConnectionTracker::TrackSetSessionDescription(
311 RTCPeerConnectionHandler* pc_handler,
312 const blink::WebRTCSessionDescription& desc,
313 Source source) {
314 string sdp = base::UTF16ToUTF8(desc.sdp());
315 string type = base::UTF16ToUTF8(desc.type());
316
317 string value = "type: " + type + ", sdp: " + sdp;
318 SendPeerConnectionUpdate(
319 pc_handler,
320 source == SOURCE_LOCAL ? "setLocalDescription" : "setRemoteDescription",
321 value);
322 }
323
TrackUpdateIce(RTCPeerConnectionHandler * pc_handler,const std::vector<webrtc::PeerConnectionInterface::IceServer> & servers,const RTCMediaConstraints & options)324 void PeerConnectionTracker::TrackUpdateIce(
325 RTCPeerConnectionHandler* pc_handler,
326 const std::vector<webrtc::PeerConnectionInterface::IceServer>& servers,
327 const RTCMediaConstraints& options) {
328 string servers_string = "servers: " + SerializeServers(servers);
329 string constraints =
330 "constraints: {" + SerializeMediaConstraints(options) + "}";
331
332 SendPeerConnectionUpdate(
333 pc_handler, "updateIce", servers_string + ", " + constraints);
334 }
335
TrackAddIceCandidate(RTCPeerConnectionHandler * pc_handler,const blink::WebRTCICECandidate & candidate,Source source)336 void PeerConnectionTracker::TrackAddIceCandidate(
337 RTCPeerConnectionHandler* pc_handler,
338 const blink::WebRTCICECandidate& candidate,
339 Source source) {
340 string value = "mid: " + base::UTF16ToUTF8(candidate.sdpMid()) + ", " +
341 "candidate: " + base::UTF16ToUTF8(candidate.candidate());
342 SendPeerConnectionUpdate(
343 pc_handler,
344 source == SOURCE_LOCAL ? "onIceCandidate" : "addIceCandidate", value);
345 }
346
TrackAddStream(RTCPeerConnectionHandler * pc_handler,const blink::WebMediaStream & stream,Source source)347 void PeerConnectionTracker::TrackAddStream(
348 RTCPeerConnectionHandler* pc_handler,
349 const blink::WebMediaStream& stream,
350 Source source){
351 SendPeerConnectionUpdate(
352 pc_handler, source == SOURCE_LOCAL ? "addStream" : "onAddStream",
353 SerializeMediaDescriptor(stream));
354 }
355
TrackRemoveStream(RTCPeerConnectionHandler * pc_handler,const blink::WebMediaStream & stream,Source source)356 void PeerConnectionTracker::TrackRemoveStream(
357 RTCPeerConnectionHandler* pc_handler,
358 const blink::WebMediaStream& stream,
359 Source source){
360 SendPeerConnectionUpdate(
361 pc_handler, source == SOURCE_LOCAL ? "removeStream" : "onRemoveStream",
362 SerializeMediaDescriptor(stream));
363 }
364
TrackCreateDataChannel(RTCPeerConnectionHandler * pc_handler,const webrtc::DataChannelInterface * data_channel,Source source)365 void PeerConnectionTracker::TrackCreateDataChannel(
366 RTCPeerConnectionHandler* pc_handler,
367 const webrtc::DataChannelInterface* data_channel,
368 Source source) {
369 string value = "label: " + data_channel->label() +
370 ", reliable: " + (data_channel->reliable() ? "true" : "false");
371 SendPeerConnectionUpdate(
372 pc_handler,
373 source == SOURCE_LOCAL ? "createLocalDataChannel" : "onRemoteDataChannel",
374 value);
375 }
376
TrackStop(RTCPeerConnectionHandler * pc_handler)377 void PeerConnectionTracker::TrackStop(RTCPeerConnectionHandler* pc_handler) {
378 SendPeerConnectionUpdate(pc_handler, "stop", std::string());
379 }
380
TrackSignalingStateChange(RTCPeerConnectionHandler * pc_handler,WebRTCPeerConnectionHandlerClient::SignalingState state)381 void PeerConnectionTracker::TrackSignalingStateChange(
382 RTCPeerConnectionHandler* pc_handler,
383 WebRTCPeerConnectionHandlerClient::SignalingState state) {
384 SendPeerConnectionUpdate(
385 pc_handler, "signalingStateChange", GetSignalingStateString(state));
386 }
387
TrackIceConnectionStateChange(RTCPeerConnectionHandler * pc_handler,WebRTCPeerConnectionHandlerClient::ICEConnectionState state)388 void PeerConnectionTracker::TrackIceConnectionStateChange(
389 RTCPeerConnectionHandler* pc_handler,
390 WebRTCPeerConnectionHandlerClient::ICEConnectionState state) {
391 SendPeerConnectionUpdate(
392 pc_handler, "iceConnectionStateChange",
393 GetIceConnectionStateString(state));
394 }
395
TrackIceGatheringStateChange(RTCPeerConnectionHandler * pc_handler,WebRTCPeerConnectionHandlerClient::ICEGatheringState state)396 void PeerConnectionTracker::TrackIceGatheringStateChange(
397 RTCPeerConnectionHandler* pc_handler,
398 WebRTCPeerConnectionHandlerClient::ICEGatheringState state) {
399 SendPeerConnectionUpdate(
400 pc_handler, "iceGatheringStateChange",
401 GetIceGatheringStateString(state));
402 }
403
TrackSessionDescriptionCallback(RTCPeerConnectionHandler * pc_handler,Action action,const string & callback_type,const string & value)404 void PeerConnectionTracker::TrackSessionDescriptionCallback(
405 RTCPeerConnectionHandler* pc_handler, Action action,
406 const string& callback_type, const string& value) {
407 string update_type;
408 switch (action) {
409 case ACTION_SET_LOCAL_DESCRIPTION:
410 update_type = "setLocalDescription";
411 break;
412 case ACTION_SET_REMOTE_DESCRIPTION:
413 update_type = "setRemoteDescription";
414 break;
415 case ACTION_CREATE_OFFER:
416 update_type = "createOffer";
417 break;
418 case ACTION_CREATE_ANSWER:
419 update_type = "createAnswer";
420 break;
421 default:
422 NOTREACHED();
423 break;
424 }
425 update_type += callback_type;
426
427 SendPeerConnectionUpdate(pc_handler, update_type, value);
428 }
429
TrackOnRenegotiationNeeded(RTCPeerConnectionHandler * pc_handler)430 void PeerConnectionTracker::TrackOnRenegotiationNeeded(
431 RTCPeerConnectionHandler* pc_handler) {
432 SendPeerConnectionUpdate(pc_handler, "onRenegotiationNeeded", std::string());
433 }
434
TrackCreateDTMFSender(RTCPeerConnectionHandler * pc_handler,const blink::WebMediaStreamTrack & track)435 void PeerConnectionTracker::TrackCreateDTMFSender(
436 RTCPeerConnectionHandler* pc_handler,
437 const blink::WebMediaStreamTrack& track) {
438 SendPeerConnectionUpdate(pc_handler, "createDTMFSender",
439 base::UTF16ToUTF8(track.id()));
440 }
441
TrackGetUserMedia(const blink::WebUserMediaRequest & user_media_request)442 void PeerConnectionTracker::TrackGetUserMedia(
443 const blink::WebUserMediaRequest& user_media_request) {
444 RTCMediaConstraints audio_constraints(user_media_request.audioConstraints());
445 RTCMediaConstraints video_constraints(user_media_request.videoConstraints());
446
447 RenderThreadImpl::current()->Send(new PeerConnectionTrackerHost_GetUserMedia(
448 user_media_request.securityOrigin().toString().utf8(),
449 user_media_request.audio(),
450 user_media_request.video(),
451 SerializeMediaConstraints(audio_constraints),
452 SerializeMediaConstraints(video_constraints)));
453 }
454
GetNextLocalID()455 int PeerConnectionTracker::GetNextLocalID() {
456 return next_lid_++;
457 }
458
SendPeerConnectionUpdate(RTCPeerConnectionHandler * pc_handler,const std::string & type,const std::string & value)459 void PeerConnectionTracker::SendPeerConnectionUpdate(
460 RTCPeerConnectionHandler* pc_handler,
461 const std::string& type,
462 const std::string& value) {
463 if (peer_connection_id_map_.find(pc_handler) == peer_connection_id_map_.end())
464 return;
465
466 RenderThreadImpl::current()->Send(
467 new PeerConnectionTrackerHost_UpdatePeerConnection(
468 peer_connection_id_map_[pc_handler], type, value));
469 }
470
471 } // namespace content
472