Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / content / renderer / media / peer_connection_tracker.cc
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
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
39 static RTCMediaConstraints GetNativeMediaConstraints(
40     const blink::WebMediaConstraints& constraints) {
41   RTCMediaConstraints native_constraints;
42
43   if (constraints.isNull())
44     return native_constraints;
45
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);
51   }
52
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);
58   }
59   return native_constraints;
60 }
61
62 static string SerializeMediaConstraints(
63     const RTCMediaConstraints& constraints) {
64   string result;
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)
71         result += ", ";
72     }
73     result += "}";
74   }
75   MediaConstraintsInterface::Constraints optional = constraints.GetOptional();
76   if (!optional.empty()) {
77     if (!result.empty())
78       result += ", ";
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)
83         result += ", ";
84     }
85     result += "}";
86   }
87   return result;
88 }
89
90 static string SerializeMediaStreamComponent(
91     const blink::WebMediaStreamTrack component) {
92   string id = base::UTF16ToUTF8(component.source().id());
93   return id;
94 }
95
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)
107         result += ", ";
108     }
109     result += "]";
110   }
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)
117         result += ", ";
118     }
119     result += "]";
120   }
121   return result;
122 }
123
124 static std::string SerializeIceTransportType(
125     webrtc::PeerConnectionInterface::IceTransportsType type) {
126   string transport_type;
127   switch (type) {
128   case webrtc::PeerConnectionInterface::kNone:
129     transport_type = "none";
130     break;
131   case webrtc::PeerConnectionInterface::kRelay:
132     transport_type = "relay";
133     break;
134   case webrtc::PeerConnectionInterface::kAll:
135     transport_type = "all";
136     break;
137   case webrtc::PeerConnectionInterface::kNoHost:
138     transport_type = "noHost";
139     break;
140   default:
141     NOTREACHED();
142   };
143   return transport_type;
144 }
145
146 #define GET_STRING_OF_STATE(state)                \
147   case WebRTCPeerConnectionHandlerClient::state:  \
148     result = #state;                              \
149     break;
150
151 static string GetSignalingStateString(
152     WebRTCPeerConnectionHandlerClient::SignalingState state) {
153   string result;
154   switch (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)
161     default:
162       NOTREACHED();
163       break;
164   }
165   return result;
166 }
167
168 static string GetIceConnectionStateString(
169     WebRTCPeerConnectionHandlerClient::ICEConnectionState state) {
170   string result;
171   switch (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)
179     default:
180       NOTREACHED();
181       break;
182   }
183   return result;
184 }
185
186 static string GetIceGatheringStateString(
187     WebRTCPeerConnectionHandlerClient::ICEGatheringState state) {
188   string result;
189   switch (state) {
190     GET_STRING_OF_STATE(ICEGatheringStateNew)
191     GET_STRING_OF_STATE(ICEGatheringStateGathering)
192     GET_STRING_OF_STATE(ICEGatheringStateComplete)
193     default:
194       NOTREACHED();
195       break;
196   }
197   return result;
198 }
199
200 // Builds a DictionaryValue from the StatsReport.
201 // The caller takes the ownership of the returned value.
202 // Note:
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())
208     return NULL;
209
210   base::DictionaryValue* dict = new base::DictionaryValue();
211   dict->SetDouble("timestamp", report.timestamp);
212
213   base::ListValue* values = new base::ListValue();
214   dict->Set("values", values);
215
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);
219   }
220   return dict;
221 }
222
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;
227
228   stats.reset(GetDictValueStats(report));
229   if (!stats)
230     return NULL;
231
232   result.reset(new base::DictionaryValue());
233   // Note:
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);
239
240   return result.release();
241 }
242
243 class InternalStatsObserver : public webrtc::StatsObserver {
244  public:
245   InternalStatsObserver(int lid)
246       : lid_(lid){}
247
248   virtual void OnComplete(
249       const std::vector<webrtc::StatsReport>& reports) OVERRIDE {
250     base::ListValue list;
251
252     for (size_t i = 0; i < reports.size(); ++i) {
253       base::DictionaryValue* report = GetDictValue(reports[i]);
254       if (report)
255         list.Append(report);
256     }
257
258     if (!list.empty())
259       RenderThreadImpl::current()->Send(
260           new PeerConnectionTrackerHost_AddStats(lid_, list));
261   }
262
263  protected:
264   virtual ~InternalStatsObserver() {}
265
266  private:
267   int lid_;
268 };
269
270 PeerConnectionTracker::PeerConnectionTracker() : next_lid_(1) {
271 }
272
273 PeerConnectionTracker::~PeerConnectionTracker() {
274 }
275
276 bool PeerConnectionTracker::OnControlMessageReceived(
277     const IPC::Message& message) {
278   bool handled = true;
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()
283   return handled;
284 }
285
286 void PeerConnectionTracker::OnGetAllStats() {
287   for (PeerConnectionIdMap::iterator it = peer_connection_id_map_.begin();
288        it != peer_connection_id_map_.end(); ++it) {
289
290     rtc::scoped_refptr<InternalStatsObserver> observer(
291         new rtc::RefCountedObject<InternalStatsObserver>(it->second));
292
293     it->first->GetStats(
294         observer,
295         NULL,
296         webrtc::PeerConnectionInterface::kStatsOutputLevelDebug);
297   }
298 }
299
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;
307
308   info.lid = GetNextLocalID();
309   info.rtc_configuration =
310       "{ servers: " +  SerializeServers(config.servers) + ", " +
311       "iceTransportType: " + SerializeIceTransportType(config.type) + " }";
312
313   info.constraints = SerializeMediaConstraints(constraints);
314   info.url = frame->document().url().spec();
315   RenderThreadImpl::current()->Send(
316       new PeerConnectionTrackerHost_AddPeerConnection(info));
317
318   DCHECK(peer_connection_id_map_.find(pc_handler) ==
319          peer_connection_id_map_.end());
320   peer_connection_id_map_[pc_handler] = info.lid;
321 }
322
323 void PeerConnectionTracker::UnregisterPeerConnection(
324     RTCPeerConnectionHandler* pc_handler) {
325   DVLOG(1) << "PeerConnectionTracker::UnregisterPeerConnection()";
326
327   std::map<RTCPeerConnectionHandler*, int>::iterator it =
328       peer_connection_id_map_.find(pc_handler);
329
330   if (it == peer_connection_id_map_.end()) {
331     // The PeerConnection might not have been registered if its initilization
332     // failed.
333     return;
334   }
335
336   RenderThreadImpl::current()->Send(
337       new PeerConnectionTrackerHost_RemovePeerConnection(it->second));
338
339   peer_connection_id_map_.erase(it);
340 }
341
342 void PeerConnectionTracker::TrackCreateOffer(
343     RTCPeerConnectionHandler* pc_handler,
344     const RTCMediaConstraints& constraints) {
345   SendPeerConnectionUpdate(
346       pc_handler, "createOffer",
347       "constraints: {" + SerializeMediaConstraints(constraints) + "}");
348 }
349
350 void PeerConnectionTracker::TrackCreateAnswer(
351     RTCPeerConnectionHandler* pc_handler,
352     const RTCMediaConstraints& constraints) {
353   SendPeerConnectionUpdate(
354       pc_handler, "createAnswer",
355       "constraints: {" + SerializeMediaConstraints(constraints) + "}");
356 }
357
358 void PeerConnectionTracker::TrackSetSessionDescription(
359     RTCPeerConnectionHandler* pc_handler,
360     const blink::WebRTCSessionDescription& desc,
361     Source source) {
362   string sdp = base::UTF16ToUTF8(desc.sdp());
363   string type = base::UTF16ToUTF8(desc.type());
364
365   string value = "type: " + type + ", sdp: " + sdp;
366   SendPeerConnectionUpdate(
367       pc_handler,
368       source == SOURCE_LOCAL ? "setLocalDescription" : "setRemoteDescription",
369       value);
370 }
371
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);
377
378   string transport_type =
379       "iceTransportType: " + SerializeIceTransportType(config.type);
380
381   string constraints =
382       "constraints: {" + SerializeMediaConstraints(options) + "}";
383
384   SendPeerConnectionUpdate(
385       pc_handler,
386       "updateIce",
387       servers_string + ", " + transport_type + ", " + constraints);
388 }
389
390 void PeerConnectionTracker::TrackAddIceCandidate(
391       RTCPeerConnectionHandler* pc_handler,
392       const blink::WebRTCICECandidate& candidate,
393       Source source) {
394   string value = "mid: " + base::UTF16ToUTF8(candidate.sdpMid()) + ", " +
395                  "candidate: " + base::UTF16ToUTF8(candidate.candidate());
396   SendPeerConnectionUpdate(
397       pc_handler,
398       source == SOURCE_LOCAL ? "onIceCandidate" : "addIceCandidate", value);
399 }
400
401 void PeerConnectionTracker::TrackAddStream(
402     RTCPeerConnectionHandler* pc_handler,
403     const blink::WebMediaStream& stream,
404     Source source){
405   SendPeerConnectionUpdate(
406       pc_handler, source == SOURCE_LOCAL ? "addStream" : "onAddStream",
407       SerializeMediaDescriptor(stream));
408 }
409
410 void PeerConnectionTracker::TrackRemoveStream(
411     RTCPeerConnectionHandler* pc_handler,
412     const blink::WebMediaStream& stream,
413     Source source){
414   SendPeerConnectionUpdate(
415       pc_handler, source == SOURCE_LOCAL ? "removeStream" : "onRemoveStream",
416       SerializeMediaDescriptor(stream));
417 }
418
419 void PeerConnectionTracker::TrackCreateDataChannel(
420     RTCPeerConnectionHandler* pc_handler,
421     const webrtc::DataChannelInterface* data_channel,
422     Source source) {
423   string value = "label: " + data_channel->label() +
424                  ", reliable: " + (data_channel->reliable() ? "true" : "false");
425   SendPeerConnectionUpdate(
426       pc_handler,
427       source == SOURCE_LOCAL ? "createLocalDataChannel" : "onRemoteDataChannel",
428       value);
429 }
430
431 void PeerConnectionTracker::TrackStop(RTCPeerConnectionHandler* pc_handler) {
432   SendPeerConnectionUpdate(pc_handler, "stop", std::string());
433 }
434
435 void PeerConnectionTracker::TrackSignalingStateChange(
436       RTCPeerConnectionHandler* pc_handler,
437       WebRTCPeerConnectionHandlerClient::SignalingState state) {
438   SendPeerConnectionUpdate(
439       pc_handler, "signalingStateChange", GetSignalingStateString(state));
440 }
441
442 void PeerConnectionTracker::TrackIceConnectionStateChange(
443       RTCPeerConnectionHandler* pc_handler,
444       WebRTCPeerConnectionHandlerClient::ICEConnectionState state) {
445   SendPeerConnectionUpdate(
446       pc_handler, "iceConnectionStateChange",
447       GetIceConnectionStateString(state));
448 }
449
450 void PeerConnectionTracker::TrackIceGatheringStateChange(
451       RTCPeerConnectionHandler* pc_handler,
452       WebRTCPeerConnectionHandlerClient::ICEGatheringState state) {
453   SendPeerConnectionUpdate(
454       pc_handler, "iceGatheringStateChange",
455       GetIceGatheringStateString(state));
456 }
457
458 void PeerConnectionTracker::TrackSessionDescriptionCallback(
459     RTCPeerConnectionHandler* pc_handler, Action action,
460     const string& callback_type, const string& value) {
461   string update_type;
462   switch (action) {
463     case ACTION_SET_LOCAL_DESCRIPTION:
464       update_type = "setLocalDescription";
465       break;
466     case ACTION_SET_REMOTE_DESCRIPTION:
467       update_type = "setRemoteDescription";
468       break;
469     case ACTION_CREATE_OFFER:
470       update_type = "createOffer";
471       break;
472     case ACTION_CREATE_ANSWER:
473       update_type = "createAnswer";
474       break;
475     default:
476       NOTREACHED();
477       break;
478   }
479   update_type += callback_type;
480
481   SendPeerConnectionUpdate(pc_handler, update_type, value);
482 }
483
484 void PeerConnectionTracker::TrackOnRenegotiationNeeded(
485     RTCPeerConnectionHandler* pc_handler) {
486   SendPeerConnectionUpdate(pc_handler, "onRenegotiationNeeded", std::string());
487 }
488
489 void PeerConnectionTracker::TrackCreateDTMFSender(
490     RTCPeerConnectionHandler* pc_handler,
491     const blink::WebMediaStreamTrack& track) {
492   SendPeerConnectionUpdate(pc_handler, "createDTMFSender",
493                            base::UTF16ToUTF8(track.id()));
494 }
495
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()));
502
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)));
509 }
510
511 int PeerConnectionTracker::GetNextLocalID() {
512   return next_lid_++;
513 }
514
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())
520     return;
521
522   RenderThreadImpl::current()->Send(
523       new PeerConnectionTrackerHost_UpdatePeerConnection(
524           peer_connection_id_map_[pc_handler], type, value));
525 }
526
527 }  // namespace content