Update To 11.40.268.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/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"
22
23 using std::string;
24 using webrtc::MediaConstraintsInterface;
25 using blink::WebRTCPeerConnectionHandlerClient;
26
27 namespace content {
28
29 static string SerializeServers(
30     const std::vector<webrtc::PeerConnectionInterface::IceServer>& servers) {
31   string result = "[";
32   for (size_t i = 0; i < servers.size(); ++i) {
33     result += servers[i].uri;
34     if (i != servers.size() - 1)
35       result += ", ";
36   }
37   result += "]";
38   return result;
39 }
40
41 static RTCMediaConstraints GetNativeMediaConstraints(
42     const blink::WebMediaConstraints& constraints) {
43   RTCMediaConstraints native_constraints;
44
45   if (constraints.isNull())
46     return native_constraints;
47
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);
53   }
54
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);
60   }
61   return native_constraints;
62 }
63
64 static string SerializeMediaConstraints(
65     const RTCMediaConstraints& constraints) {
66   string result;
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)
73         result += ", ";
74     }
75     result += "}";
76   }
77   MediaConstraintsInterface::Constraints optional = constraints.GetOptional();
78   if (!optional.empty()) {
79     if (!result.empty())
80       result += ", ";
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)
85         result += ", ";
86     }
87     result += "}";
88   }
89   return result;
90 }
91
92 static string SerializeMediaStreamComponent(
93     const blink::WebMediaStreamTrack component) {
94   string id = base::UTF16ToUTF8(component.source().id());
95   return id;
96 }
97
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)
109         result += ", ";
110     }
111     result += "]";
112   }
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)
119         result += ", ";
120     }
121     result += "]";
122   }
123   return result;
124 }
125
126 static std::string SerializeIceTransportType(
127     webrtc::PeerConnectionInterface::IceTransportsType type) {
128   string transport_type;
129   switch (type) {
130   case webrtc::PeerConnectionInterface::kNone:
131     transport_type = "none";
132     break;
133   case webrtc::PeerConnectionInterface::kRelay:
134     transport_type = "relay";
135     break;
136   case webrtc::PeerConnectionInterface::kAll:
137     transport_type = "all";
138     break;
139   case webrtc::PeerConnectionInterface::kNoHost:
140     transport_type = "noHost";
141     break;
142   default:
143     NOTREACHED();
144   };
145   return transport_type;
146 }
147
148 #define GET_STRING_OF_STATE(state)                \
149   case WebRTCPeerConnectionHandlerClient::state:  \
150     result = #state;                              \
151     break;
152
153 static string GetSignalingStateString(
154     WebRTCPeerConnectionHandlerClient::SignalingState state) {
155   string result;
156   switch (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)
163     default:
164       NOTREACHED();
165       break;
166   }
167   return result;
168 }
169
170 static string GetIceConnectionStateString(
171     WebRTCPeerConnectionHandlerClient::ICEConnectionState state) {
172   string result;
173   switch (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)
181     default:
182       NOTREACHED();
183       break;
184   }
185   return result;
186 }
187
188 static string GetIceGatheringStateString(
189     WebRTCPeerConnectionHandlerClient::ICEGatheringState state) {
190   string result;
191   switch (state) {
192     GET_STRING_OF_STATE(ICEGatheringStateNew)
193     GET_STRING_OF_STATE(ICEGatheringStateGathering)
194     GET_STRING_OF_STATE(ICEGatheringStateComplete)
195     default:
196       NOTREACHED();
197       break;
198   }
199   return result;
200 }
201
202 // Builds a DictionaryValue from the StatsReport.
203 // The caller takes the ownership of the returned value.
204 // Note:
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())
210     return NULL;
211
212   base::DictionaryValue* dict = new base::DictionaryValue();
213   dict->SetDouble("timestamp", report.timestamp);
214
215   base::ListValue* values = new base::ListValue();
216   dict->Set("values", values);
217
218   for (size_t i = 0; i < report.values.size(); ++i) {
219     values->AppendString(report.values[i].display_name());
220     values->AppendString(report.values[i].value);
221   }
222   return dict;
223 }
224
225 // Builds a DictionaryValue from the StatsReport.
226 // The caller takes the ownership of the returned value.
227 static base::DictionaryValue* GetDictValue(const webrtc::StatsReport& report) {
228   scoped_ptr<base::DictionaryValue> stats, result;
229
230   stats.reset(GetDictValueStats(report));
231   if (!stats)
232     return NULL;
233
234   result.reset(new base::DictionaryValue());
235   // Note:
236   // The format must be consistent with what webrtc_internals.js expects.
237   // If you change it here, you must change webrtc_internals.js as well.
238   result->Set("stats", stats.release());
239   result->SetString("id", report.id);
240   result->SetString("type", report.type);
241
242   return result.release();
243 }
244
245 class InternalStatsObserver : public webrtc::StatsObserver {
246  public:
247   InternalStatsObserver(int lid)
248       : lid_(lid), main_thread_(base::ThreadTaskRunnerHandle::Get()) {}
249
250   void OnComplete(const std::vector<webrtc::StatsReport>& reports) override {
251     scoped_ptr<base::ListValue> list(new base::ListValue());
252
253     for (size_t i = 0; i < reports.size(); ++i) {
254       base::DictionaryValue* report = GetDictValue(reports[i]);
255       if (report)
256         list->Append(report);
257     }
258
259     if (!list->empty()) {
260       main_thread_->PostTask(FROM_HERE,
261           base::Bind(&InternalStatsObserver::OnCompleteImpl,
262                      base::Passed(&list), lid_));
263     }
264   }
265
266  protected:
267   ~InternalStatsObserver() override {
268     // Will be destructed on libjingle's signaling thread.
269     // The signaling thread is where libjingle's objects live and from where
270     // libjingle makes callbacks.  This may or may not be the same thread as
271     // the main thread.
272   }
273
274  private:
275   // Static since |this| will most likely have been deleted by the time we
276   // get here.
277   static void OnCompleteImpl(scoped_ptr<base::ListValue> list, int lid) {
278     DCHECK(!list->empty());
279     RenderThreadImpl::current()->Send(
280         new PeerConnectionTrackerHost_AddStats(lid, *list.get()));
281   }
282
283   const int lid_;
284   const scoped_refptr<base::SingleThreadTaskRunner> main_thread_;
285 };
286
287 PeerConnectionTracker::PeerConnectionTracker() : next_lid_(1) {
288 }
289
290 PeerConnectionTracker::~PeerConnectionTracker() {
291 }
292
293 bool PeerConnectionTracker::OnControlMessageReceived(
294     const IPC::Message& message) {
295   bool handled = true;
296   IPC_BEGIN_MESSAGE_MAP(PeerConnectionTracker, message)
297     IPC_MESSAGE_HANDLER(PeerConnectionTracker_GetAllStats, OnGetAllStats)
298     IPC_MESSAGE_HANDLER(PeerConnectionTracker_OnSuspend, OnSuspend)
299     IPC_MESSAGE_UNHANDLED(handled = false)
300   IPC_END_MESSAGE_MAP()
301   return handled;
302 }
303
304 void PeerConnectionTracker::OnGetAllStats() {
305   DCHECK(main_thread_.CalledOnValidThread());
306
307   const std::string empty_track_id;
308   for (PeerConnectionIdMap::iterator it = peer_connection_id_map_.begin();
309        it != peer_connection_id_map_.end(); ++it) {
310     rtc::scoped_refptr<InternalStatsObserver> observer(
311         new rtc::RefCountedObject<InternalStatsObserver>(it->second));
312
313     // The last type parameter is ignored when the track id is empty.
314     it->first->GetStats(
315         observer,
316         webrtc::PeerConnectionInterface::kStatsOutputLevelDebug,
317         empty_track_id, blink::WebMediaStreamSource::TypeAudio);
318   }
319 }
320
321 void PeerConnectionTracker::OnSuspend() {
322   DCHECK(main_thread_.CalledOnValidThread());
323   for (PeerConnectionIdMap::iterator it = peer_connection_id_map_.begin();
324        it != peer_connection_id_map_.end(); ++it) {
325     it->first->CloseClientPeerConnection();
326   }
327 }
328
329 void PeerConnectionTracker::RegisterPeerConnection(
330     RTCPeerConnectionHandler* pc_handler,
331     const webrtc::PeerConnectionInterface::RTCConfiguration& config,
332     const RTCMediaConstraints& constraints,
333     const blink::WebFrame* frame) {
334   DCHECK(main_thread_.CalledOnValidThread());
335   DVLOG(1) << "PeerConnectionTracker::RegisterPeerConnection()";
336   PeerConnectionInfo info;
337
338   info.lid = GetNextLocalID();
339   info.rtc_configuration =
340       "{ servers: " +  SerializeServers(config.servers) + ", " +
341       "iceTransportType: " + SerializeIceTransportType(config.type) + " }";
342
343   info.constraints = SerializeMediaConstraints(constraints);
344   info.url = frame->document().url().spec();
345   RenderThreadImpl::current()->Send(
346       new PeerConnectionTrackerHost_AddPeerConnection(info));
347
348   DCHECK(peer_connection_id_map_.find(pc_handler) ==
349          peer_connection_id_map_.end());
350   peer_connection_id_map_[pc_handler] = info.lid;
351 }
352
353 void PeerConnectionTracker::UnregisterPeerConnection(
354     RTCPeerConnectionHandler* pc_handler) {
355   DCHECK(main_thread_.CalledOnValidThread());
356   DVLOG(1) << "PeerConnectionTracker::UnregisterPeerConnection()";
357
358   std::map<RTCPeerConnectionHandler*, int>::iterator it =
359       peer_connection_id_map_.find(pc_handler);
360
361   if (it == peer_connection_id_map_.end()) {
362     // The PeerConnection might not have been registered if its initilization
363     // failed.
364     return;
365   }
366
367   RenderThreadImpl::current()->Send(
368       new PeerConnectionTrackerHost_RemovePeerConnection(it->second));
369
370   peer_connection_id_map_.erase(it);
371 }
372
373 void PeerConnectionTracker::TrackCreateOffer(
374     RTCPeerConnectionHandler* pc_handler,
375     const RTCMediaConstraints& constraints) {
376   DCHECK(main_thread_.CalledOnValidThread());
377   SendPeerConnectionUpdate(
378       pc_handler, "createOffer",
379       "constraints: {" + SerializeMediaConstraints(constraints) + "}");
380 }
381
382 void PeerConnectionTracker::TrackCreateAnswer(
383     RTCPeerConnectionHandler* pc_handler,
384     const RTCMediaConstraints& constraints) {
385   DCHECK(main_thread_.CalledOnValidThread());
386   SendPeerConnectionUpdate(
387       pc_handler, "createAnswer",
388       "constraints: {" + SerializeMediaConstraints(constraints) + "}");
389 }
390
391 void PeerConnectionTracker::TrackSetSessionDescription(
392     RTCPeerConnectionHandler* pc_handler,
393     const std::string& sdp, const std::string& type, Source source) {
394   DCHECK(main_thread_.CalledOnValidThread());
395   string value = "type: " + type + ", sdp: " + sdp;
396   SendPeerConnectionUpdate(
397       pc_handler,
398       source == SOURCE_LOCAL ? "setLocalDescription" : "setRemoteDescription",
399       value);
400 }
401
402 void PeerConnectionTracker::TrackUpdateIce(
403       RTCPeerConnectionHandler* pc_handler,
404       const webrtc::PeerConnectionInterface::RTCConfiguration& config,
405       const RTCMediaConstraints& options) {
406   DCHECK(main_thread_.CalledOnValidThread());
407   string servers_string = "servers: " + SerializeServers(config.servers);
408
409   string transport_type =
410       "iceTransportType: " + SerializeIceTransportType(config.type);
411
412   string constraints =
413       "constraints: {" + SerializeMediaConstraints(options) + "}";
414
415   SendPeerConnectionUpdate(
416       pc_handler,
417       "updateIce",
418       servers_string + ", " + transport_type + ", " + constraints);
419 }
420
421 void PeerConnectionTracker::TrackAddIceCandidate(
422       RTCPeerConnectionHandler* pc_handler,
423       const blink::WebRTCICECandidate& candidate,
424       Source source,
425       bool succeeded) {
426   DCHECK(main_thread_.CalledOnValidThread());
427   string value =
428       "sdpMid: " + base::UTF16ToUTF8(candidate.sdpMid()) + ", " +
429       "sdpMLineIndex: " + base::IntToString(candidate.sdpMLineIndex()) + ", " +
430       "candidate: " + base::UTF16ToUTF8(candidate.candidate());
431
432   // OnIceCandidate always succeeds as it's a callback from the browser.
433   DCHECK(source != SOURCE_LOCAL || succeeded);
434
435   string event =
436       (source == SOURCE_LOCAL) ? "onIceCandidate"
437                                : (succeeded ? "addIceCandidate"
438                                             : "addIceCandidateFailed");
439
440   SendPeerConnectionUpdate(pc_handler, event, value);
441 }
442
443 void PeerConnectionTracker::TrackAddStream(
444     RTCPeerConnectionHandler* pc_handler,
445     const blink::WebMediaStream& stream,
446     Source source) {
447   DCHECK(main_thread_.CalledOnValidThread());
448   SendPeerConnectionUpdate(
449       pc_handler, source == SOURCE_LOCAL ? "addStream" : "onAddStream",
450       SerializeMediaDescriptor(stream));
451 }
452
453 void PeerConnectionTracker::TrackRemoveStream(
454     RTCPeerConnectionHandler* pc_handler,
455     const blink::WebMediaStream& stream,
456     Source source){
457   DCHECK(main_thread_.CalledOnValidThread());
458   SendPeerConnectionUpdate(
459       pc_handler, source == SOURCE_LOCAL ? "removeStream" : "onRemoveStream",
460       SerializeMediaDescriptor(stream));
461 }
462
463 void PeerConnectionTracker::TrackCreateDataChannel(
464     RTCPeerConnectionHandler* pc_handler,
465     const webrtc::DataChannelInterface* data_channel,
466     Source source) {
467   DCHECK(main_thread_.CalledOnValidThread());
468   string value = "label: " + data_channel->label() +
469                  ", reliable: " + (data_channel->reliable() ? "true" : "false");
470   SendPeerConnectionUpdate(
471       pc_handler,
472       source == SOURCE_LOCAL ? "createLocalDataChannel" : "onRemoteDataChannel",
473       value);
474 }
475
476 void PeerConnectionTracker::TrackStop(RTCPeerConnectionHandler* pc_handler) {
477   DCHECK(main_thread_.CalledOnValidThread());
478   SendPeerConnectionUpdate(pc_handler, "stop", std::string());
479 }
480
481 void PeerConnectionTracker::TrackSignalingStateChange(
482       RTCPeerConnectionHandler* pc_handler,
483       WebRTCPeerConnectionHandlerClient::SignalingState state) {
484   DCHECK(main_thread_.CalledOnValidThread());
485   SendPeerConnectionUpdate(
486       pc_handler, "signalingStateChange", GetSignalingStateString(state));
487 }
488
489 void PeerConnectionTracker::TrackIceConnectionStateChange(
490       RTCPeerConnectionHandler* pc_handler,
491       WebRTCPeerConnectionHandlerClient::ICEConnectionState state) {
492   DCHECK(main_thread_.CalledOnValidThread());
493   SendPeerConnectionUpdate(
494       pc_handler, "iceConnectionStateChange",
495       GetIceConnectionStateString(state));
496 }
497
498 void PeerConnectionTracker::TrackIceGatheringStateChange(
499       RTCPeerConnectionHandler* pc_handler,
500       WebRTCPeerConnectionHandlerClient::ICEGatheringState state) {
501   DCHECK(main_thread_.CalledOnValidThread());
502   SendPeerConnectionUpdate(
503       pc_handler, "iceGatheringStateChange",
504       GetIceGatheringStateString(state));
505 }
506
507 void PeerConnectionTracker::TrackSessionDescriptionCallback(
508     RTCPeerConnectionHandler* pc_handler, Action action,
509     const string& callback_type, const string& value) {
510   DCHECK(main_thread_.CalledOnValidThread());
511   string update_type;
512   switch (action) {
513     case ACTION_SET_LOCAL_DESCRIPTION:
514       update_type = "setLocalDescription";
515       break;
516     case ACTION_SET_REMOTE_DESCRIPTION:
517       update_type = "setRemoteDescription";
518       break;
519     case ACTION_CREATE_OFFER:
520       update_type = "createOffer";
521       break;
522     case ACTION_CREATE_ANSWER:
523       update_type = "createAnswer";
524       break;
525     default:
526       NOTREACHED();
527       break;
528   }
529   update_type += callback_type;
530
531   SendPeerConnectionUpdate(pc_handler, update_type, value);
532 }
533
534 void PeerConnectionTracker::TrackOnRenegotiationNeeded(
535     RTCPeerConnectionHandler* pc_handler) {
536   DCHECK(main_thread_.CalledOnValidThread());
537   SendPeerConnectionUpdate(pc_handler, "onRenegotiationNeeded", std::string());
538 }
539
540 void PeerConnectionTracker::TrackCreateDTMFSender(
541     RTCPeerConnectionHandler* pc_handler,
542     const blink::WebMediaStreamTrack& track) {
543   DCHECK(main_thread_.CalledOnValidThread());
544   SendPeerConnectionUpdate(pc_handler, "createDTMFSender",
545                            base::UTF16ToUTF8(track.id()));
546 }
547
548 void PeerConnectionTracker::TrackGetUserMedia(
549     const blink::WebUserMediaRequest& user_media_request) {
550   DCHECK(main_thread_.CalledOnValidThread());
551   RTCMediaConstraints audio_constraints(
552       GetNativeMediaConstraints(user_media_request.audioConstraints()));
553   RTCMediaConstraints video_constraints(
554       GetNativeMediaConstraints(user_media_request.videoConstraints()));
555
556   RenderThreadImpl::current()->Send(new PeerConnectionTrackerHost_GetUserMedia(
557       user_media_request.securityOrigin().toString().utf8(),
558       user_media_request.audio(),
559       user_media_request.video(),
560       SerializeMediaConstraints(audio_constraints),
561       SerializeMediaConstraints(video_constraints)));
562 }
563
564 int PeerConnectionTracker::GetNextLocalID() {
565   DCHECK(main_thread_.CalledOnValidThread());
566   return next_lid_++;
567 }
568
569 void PeerConnectionTracker::SendPeerConnectionUpdate(
570     RTCPeerConnectionHandler* pc_handler,
571     const std::string& type,
572     const std::string& value) {
573   DCHECK(main_thread_.CalledOnValidThread());
574   if (peer_connection_id_map_.find(pc_handler) == peer_connection_id_map_.end())
575     return;
576
577   RenderThreadImpl::current()->Send(
578       new PeerConnectionTrackerHost_UpdatePeerConnection(
579           peer_connection_id_map_[pc_handler], type, value));
580 }
581
582 }  // namespace content