Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / content / browser / media / webrtc_internals.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
5 #include "content/browser/media/webrtc_internals.h"
6
7 #include "base/command_line.h"
8 #include "content/browser/media/webrtc_internals_ui_observer.h"
9 #include "content/public/browser/browser_thread.h"
10 #include "content/public/browser/child_process_data.h"
11 #include "content/public/browser/notification_service.h"
12 #include "content/public/browser/notification_types.h"
13 #include "content/public/browser/render_process_host.h"
14 #include "content/public/browser/web_contents.h"
15 #include "content/public/browser/web_contents_view.h"
16 #include "content/public/common/content_switches.h"
17
18 using base::ProcessId;
19 using std::string;
20
21 namespace content {
22
23 namespace {
24 // Makes sure that |dict| has a ListValue under path "log".
25 static base::ListValue* EnsureLogList(base::DictionaryValue* dict) {
26   base::ListValue* log = NULL;
27   if (!dict->GetList("log", &log)) {
28     log = new base::ListValue();
29     if (log)
30       dict->Set("log", log);
31   }
32   return log;
33 }
34
35 }  // namespace
36
37 WebRTCInternals::WebRTCInternals()
38     : aec_dump_enabled_(false) {
39   registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_TERMINATED,
40                  NotificationService::AllBrowserContextsAndSources());
41   BrowserChildProcessObserver::Add(this);
42 // TODO(grunell): Shouldn't all the webrtc_internals* files be excluded from the
43 // build if WebRTC is disabled?
44 #if defined(ENABLE_WEBRTC)
45   if (CommandLine::ForCurrentProcess()->HasSwitch(
46           switches::kEnableWebRtcAecRecordings)) {
47     aec_dump_enabled_ = true;
48     aec_dump_file_path_ = CommandLine::ForCurrentProcess()->GetSwitchValuePath(
49         switches::kEnableWebRtcAecRecordings);
50   } else {
51 #if defined(OS_CHROMEOS)
52     aec_dump_file_path_ =
53         base::FilePath(FILE_PATH_LITERAL("/tmp/audio.aecdump"));
54 #elif defined(OS_ANDROID)
55     aec_dump_file_path_ =
56         base::FilePath(FILE_PATH_LITERAL("/sdcard/audio.aecdump"));
57 #else
58     aec_dump_file_path_ = base::FilePath(FILE_PATH_LITERAL("audio.aecdump"));
59 #endif
60   }
61 #endif  // defined(ENABLE_WEBRTC)
62 }
63
64 WebRTCInternals::~WebRTCInternals() {
65   BrowserChildProcessObserver::Remove(this);
66 }
67
68 WebRTCInternals* WebRTCInternals::GetInstance() {
69   return Singleton<WebRTCInternals>::get();
70 }
71
72 void WebRTCInternals::OnAddPeerConnection(int render_process_id,
73                                           ProcessId pid,
74                                           int lid,
75                                           const string& url,
76                                           const string& servers,
77                                           const string& constraints) {
78   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
79
80   base::DictionaryValue* dict = new base::DictionaryValue();
81   if (!dict)
82     return;
83
84   dict->SetInteger("rid", render_process_id);
85   dict->SetInteger("pid", static_cast<int>(pid));
86   dict->SetInteger("lid", lid);
87   dict->SetString("servers", servers);
88   dict->SetString("constraints", constraints);
89   dict->SetString("url", url);
90   peer_connection_data_.Append(dict);
91
92   if (observers_.might_have_observers())
93     SendUpdate("addPeerConnection", dict);
94 }
95
96 void WebRTCInternals::OnRemovePeerConnection(ProcessId pid, int lid) {
97   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
98   for (size_t i = 0; i < peer_connection_data_.GetSize(); ++i) {
99     base::DictionaryValue* dict = NULL;
100     peer_connection_data_.GetDictionary(i, &dict);
101
102     int this_pid = 0;
103     int this_lid = 0;
104     dict->GetInteger("pid", &this_pid);
105     dict->GetInteger("lid", &this_lid);
106
107     if (this_pid != static_cast<int>(pid) || this_lid != lid)
108       continue;
109
110     peer_connection_data_.Remove(i, NULL);
111
112     if (observers_.might_have_observers()) {
113       base::DictionaryValue id;
114       id.SetInteger("pid", static_cast<int>(pid));
115       id.SetInteger("lid", lid);
116       SendUpdate("removePeerConnection", &id);
117     }
118     break;
119   }
120 }
121
122 void WebRTCInternals::OnUpdatePeerConnection(
123     ProcessId pid, int lid, const string& type, const string& value) {
124   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
125
126   for (size_t i = 0; i < peer_connection_data_.GetSize(); ++i) {
127     base::DictionaryValue* record = NULL;
128     peer_connection_data_.GetDictionary(i, &record);
129
130     int this_pid = 0, this_lid = 0;
131     record->GetInteger("pid", &this_pid);
132     record->GetInteger("lid", &this_lid);
133
134     if (this_pid != static_cast<int>(pid) || this_lid != lid)
135       continue;
136
137     // Append the update to the end of the log.
138     base::ListValue* log = EnsureLogList(record);
139     if (!log)
140       return;
141
142     base::DictionaryValue* log_entry = new base::DictionaryValue();
143     if (!log_entry)
144       return;
145
146     log_entry->SetString("type", type);
147     log_entry->SetString("value", value);
148     log->Append(log_entry);
149
150     if (observers_.might_have_observers()) {
151       base::DictionaryValue update;
152       update.SetInteger("pid", static_cast<int>(pid));
153       update.SetInteger("lid", lid);
154       update.SetString("type", type);
155       update.SetString("value", value);
156
157       SendUpdate("updatePeerConnection", &update);
158     }
159     return;
160   }
161 }
162
163 void WebRTCInternals::OnAddStats(base::ProcessId pid, int lid,
164                                  const base::ListValue& value) {
165   if (!observers_.might_have_observers())
166     return;
167
168   base::DictionaryValue dict;
169   dict.SetInteger("pid", static_cast<int>(pid));
170   dict.SetInteger("lid", lid);
171
172   base::ListValue* list = value.DeepCopy();
173   if (!list)
174     return;
175
176   dict.Set("reports", list);
177
178   SendUpdate("addStats", &dict);
179 }
180
181 void WebRTCInternals::OnGetUserMedia(int rid,
182                                      base::ProcessId pid,
183                                      const std::string& origin,
184                                      bool audio,
185                                      bool video,
186                                      const std::string& audio_constraints,
187                                      const std::string& video_constraints) {
188   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
189
190   base::DictionaryValue* dict = new base::DictionaryValue();
191   dict->SetInteger("rid", rid);
192   dict->SetInteger("pid", static_cast<int>(pid));
193   dict->SetString("origin", origin);
194   if (audio)
195     dict->SetString("audio", audio_constraints);
196   if (video)
197     dict->SetString("video", video_constraints);
198
199   get_user_media_requests_.Append(dict);
200
201   if (observers_.might_have_observers())
202     SendUpdate("addGetUserMedia", dict);
203 }
204
205 void WebRTCInternals::AddObserver(WebRTCInternalsUIObserver *observer) {
206   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
207   observers_.AddObserver(observer);
208 }
209
210 void WebRTCInternals::RemoveObserver(WebRTCInternalsUIObserver *observer) {
211   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
212   observers_.RemoveObserver(observer);
213
214   // Disables the AEC recording if it is enabled and the last webrtc-internals
215   // page is going away.
216   if (aec_dump_enabled_ && !observers_.might_have_observers())
217     DisableAecDump();
218 }
219
220 void WebRTCInternals::UpdateObserver(WebRTCInternalsUIObserver* observer) {
221   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
222   if (peer_connection_data_.GetSize() > 0)
223     observer->OnUpdate("updateAllPeerConnections", &peer_connection_data_);
224
225   for (base::ListValue::iterator it = get_user_media_requests_.begin();
226        it != get_user_media_requests_.end();
227        ++it) {
228     observer->OnUpdate("addGetUserMedia", *it);
229   }
230 }
231
232 void WebRTCInternals::EnableAecDump(content::WebContents* web_contents) {
233 #if defined(ENABLE_WEBRTC)
234 #if defined(OS_ANDROID)
235   EnableAecDumpOnAllRenderProcessHosts();
236 #else
237   select_file_dialog_ = ui::SelectFileDialog::Create(this, NULL);
238   select_file_dialog_->SelectFile(
239       ui::SelectFileDialog::SELECT_SAVEAS_FILE,
240       base::string16(),
241       aec_dump_file_path_,
242       NULL,
243       0,
244       FILE_PATH_LITERAL(""),
245       web_contents->GetView()->GetTopLevelNativeWindow(),
246       NULL);
247 #endif
248 #endif
249 }
250
251 void WebRTCInternals::DisableAecDump() {
252 #if defined(ENABLE_WEBRTC)
253   aec_dump_enabled_ = false;
254   for (RenderProcessHost::iterator i(
255            content::RenderProcessHost::AllHostsIterator());
256        !i.IsAtEnd(); i.Advance()) {
257     i.GetCurrentValue()->DisableAecDump();
258   }
259 #endif
260 }
261
262 void WebRTCInternals::ResetForTesting() {
263   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
264   observers_.Clear();
265   peer_connection_data_.Clear();
266   get_user_media_requests_.Clear();
267   aec_dump_enabled_ = false;
268 }
269
270 void WebRTCInternals::SendUpdate(const string& command, base::Value* value) {
271   DCHECK(observers_.might_have_observers());
272
273   FOR_EACH_OBSERVER(WebRTCInternalsUIObserver,
274                     observers_,
275                     OnUpdate(command, value));
276 }
277
278 void WebRTCInternals::BrowserChildProcessCrashed(
279     const ChildProcessData& data) {
280   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
281   OnRendererExit(data.id);
282 }
283
284 void WebRTCInternals::Observe(int type,
285                               const NotificationSource& source,
286                               const NotificationDetails& details) {
287   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
288   DCHECK_EQ(type, NOTIFICATION_RENDERER_PROCESS_TERMINATED);
289   OnRendererExit(Source<RenderProcessHost>(source)->GetID());
290 }
291
292 void WebRTCInternals::FileSelected(const base::FilePath& path,
293                                    int /* unused_index */,
294                                    void* /*unused_params */) {
295 #if defined(ENABLE_WEBRTC)
296   aec_dump_file_path_ = path;
297   EnableAecDumpOnAllRenderProcessHosts();
298 #endif
299 }
300
301 void WebRTCInternals::OnRendererExit(int render_process_id) {
302   // Iterates from the end of the list to remove the PeerConnections created
303   // by the exitting renderer.
304   for (int i = peer_connection_data_.GetSize() - 1; i >= 0; --i) {
305     base::DictionaryValue* record = NULL;
306     peer_connection_data_.GetDictionary(i, &record);
307
308     int this_rid = 0;
309     record->GetInteger("rid", &this_rid);
310
311     if (this_rid == render_process_id) {
312       if (observers_.might_have_observers()) {
313         int lid = 0, pid = 0;
314         record->GetInteger("lid", &lid);
315         record->GetInteger("pid", &pid);
316
317         base::DictionaryValue update;
318         update.SetInteger("lid", lid);
319         update.SetInteger("pid", pid);
320         SendUpdate("removePeerConnection", &update);
321       }
322       peer_connection_data_.Remove(i, NULL);
323     }
324   }
325
326   bool found_any = false;
327   // Iterates from the end of the list to remove the getUserMedia requests
328   // created by the exiting renderer.
329   for (int i = get_user_media_requests_.GetSize() - 1; i >= 0; --i) {
330     base::DictionaryValue* record = NULL;
331     get_user_media_requests_.GetDictionary(i, &record);
332
333     int this_rid = 0;
334     record->GetInteger("rid", &this_rid);
335
336     if (this_rid == render_process_id) {
337       get_user_media_requests_.Remove(i, NULL);
338       found_any = true;
339     }
340   }
341
342   if (found_any && observers_.might_have_observers()) {
343     base::DictionaryValue update;
344     update.SetInteger("rid", render_process_id);
345     SendUpdate("removeGetUserMediaForRenderer", &update);
346   }
347 }
348
349 #if defined(ENABLE_WEBRTC)
350 void WebRTCInternals::EnableAecDumpOnAllRenderProcessHosts() {
351   aec_dump_enabled_ = true;
352   for (RenderProcessHost::iterator i(
353            content::RenderProcessHost::AllHostsIterator());
354        !i.IsAtEnd(); i.Advance()) {
355     i.GetCurrentValue()->EnableAecDump(aec_dump_file_path_);
356   }
357 }
358 #endif
359
360 }  // namespace content