IndexedDBFactory now ForceCloses databases.
[chromium-blink-merge.git] / content / browser / media / webrtc_internals.cc
blob713da32507f879fb08c0e447027b89026882c875
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.
5 #include "content/browser/media/webrtc_internals.h"
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"
18 using base::ProcessId;
19 using std::string;
21 namespace content {
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);
32 return log;
35 } // namespace
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
61 #endif // defined(ENABLE_WEBRTC)
64 WebRTCInternals::~WebRTCInternals() {
65 BrowserChildProcessObserver::Remove(this);
68 WebRTCInternals* WebRTCInternals::GetInstance() {
69 return Singleton<WebRTCInternals>::get();
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));
80 base::DictionaryValue* dict = new base::DictionaryValue();
81 if (!dict)
82 return;
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);
92 if (observers_.might_have_observers())
93 SendUpdate("addPeerConnection", dict);
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);
102 int this_pid = 0;
103 int this_lid = 0;
104 dict->GetInteger("pid", &this_pid);
105 dict->GetInteger("lid", &this_lid);
107 if (this_pid != static_cast<int>(pid) || this_lid != lid)
108 continue;
110 peer_connection_data_.Remove(i, NULL);
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);
118 break;
122 void WebRTCInternals::OnUpdatePeerConnection(
123 ProcessId pid, int lid, const string& type, const string& value) {
124 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
126 for (size_t i = 0; i < peer_connection_data_.GetSize(); ++i) {
127 base::DictionaryValue* record = NULL;
128 peer_connection_data_.GetDictionary(i, &record);
130 int this_pid = 0, this_lid = 0;
131 record->GetInteger("pid", &this_pid);
132 record->GetInteger("lid", &this_lid);
134 if (this_pid != static_cast<int>(pid) || this_lid != lid)
135 continue;
137 // Append the update to the end of the log.
138 base::ListValue* log = EnsureLogList(record);
139 if (!log)
140 return;
142 base::DictionaryValue* log_entry = new base::DictionaryValue();
143 if (!log_entry)
144 return;
146 log_entry->SetString("type", type);
147 log_entry->SetString("value", value);
148 log->Append(log_entry);
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);
157 SendUpdate("updatePeerConnection", &update);
159 return;
163 void WebRTCInternals::OnAddStats(base::ProcessId pid, int lid,
164 const base::ListValue& value) {
165 if (!observers_.might_have_observers())
166 return;
168 base::DictionaryValue dict;
169 dict.SetInteger("pid", static_cast<int>(pid));
170 dict.SetInteger("lid", lid);
172 base::ListValue* list = value.DeepCopy();
173 if (!list)
174 return;
176 dict.Set("reports", list);
178 SendUpdate("addStats", &dict);
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));
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);
199 get_user_media_requests_.Append(dict);
201 if (observers_.might_have_observers())
202 SendUpdate("addGetUserMedia", dict);
205 void WebRTCInternals::AddObserver(WebRTCInternalsUIObserver *observer) {
206 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
207 observers_.AddObserver(observer);
210 void WebRTCInternals::RemoveObserver(WebRTCInternalsUIObserver *observer) {
211 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
212 observers_.RemoveObserver(observer);
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();
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_);
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);
232 void WebRTCInternals::EnableAecDump(content::WebContents* web_contents) {
233 #if defined(ENABLE_WEBRTC)
234 select_file_dialog_ = ui::SelectFileDialog::Create(this, NULL);
235 select_file_dialog_->SelectFile(
236 ui::SelectFileDialog::SELECT_SAVEAS_FILE,
237 base::string16(),
238 aec_dump_file_path_,
239 NULL,
241 FILE_PATH_LITERAL(""),
242 web_contents->GetView()->GetTopLevelNativeWindow(),
243 NULL);
244 #endif
247 void WebRTCInternals::DisableAecDump() {
248 #if defined(ENABLE_WEBRTC)
249 aec_dump_enabled_ = false;
250 for (RenderProcessHost::iterator i(
251 content::RenderProcessHost::AllHostsIterator());
252 !i.IsAtEnd(); i.Advance()) {
253 i.GetCurrentValue()->DisableAecDump();
255 #endif
258 void WebRTCInternals::SendUpdate(const string& command, base::Value* value) {
259 DCHECK(observers_.might_have_observers());
261 FOR_EACH_OBSERVER(WebRTCInternalsUIObserver,
262 observers_,
263 OnUpdate(command, value));
266 void WebRTCInternals::BrowserChildProcessCrashed(
267 const ChildProcessData& data) {
268 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
269 OnRendererExit(data.id);
272 void WebRTCInternals::Observe(int type,
273 const NotificationSource& source,
274 const NotificationDetails& details) {
275 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
276 DCHECK_EQ(type, NOTIFICATION_RENDERER_PROCESS_TERMINATED);
277 OnRendererExit(Source<RenderProcessHost>(source)->GetID());
280 void WebRTCInternals::FileSelected(const base::FilePath& path,
281 int /* unused_index */,
282 void* /*unused_params */) {
283 #if defined(ENABLE_WEBRTC)
284 aec_dump_enabled_ = true;
285 aec_dump_file_path_ = path;
286 for (RenderProcessHost::iterator i(
287 content::RenderProcessHost::AllHostsIterator());
288 !i.IsAtEnd(); i.Advance()) {
289 i.GetCurrentValue()->EnableAecDump(aec_dump_file_path_);
291 #endif
294 void WebRTCInternals::OnRendererExit(int render_process_id) {
295 // Iterates from the end of the list to remove the PeerConnections created
296 // by the exitting renderer.
297 for (int i = peer_connection_data_.GetSize() - 1; i >= 0; --i) {
298 base::DictionaryValue* record = NULL;
299 peer_connection_data_.GetDictionary(i, &record);
301 int this_rid = 0;
302 record->GetInteger("rid", &this_rid);
304 if (this_rid == render_process_id) {
305 if (observers_.might_have_observers()) {
306 int lid = 0, pid = 0;
307 record->GetInteger("lid", &lid);
308 record->GetInteger("pid", &pid);
310 base::DictionaryValue update;
311 update.SetInteger("lid", lid);
312 update.SetInteger("pid", pid);
313 SendUpdate("removePeerConnection", &update);
315 peer_connection_data_.Remove(i, NULL);
319 bool found_any = false;
320 // Iterates from the end of the list to remove the getUserMedia requests
321 // created by the exiting renderer.
322 for (int i = get_user_media_requests_.GetSize() - 1; i >= 0; --i) {
323 base::DictionaryValue* record = NULL;
324 get_user_media_requests_.GetDictionary(i, &record);
326 int this_rid = 0;
327 record->GetInteger("rid", &this_rid);
329 if (this_rid == render_process_id) {
330 get_user_media_requests_.Remove(i, NULL);
331 found_any = true;
335 if (found_any && observers_.might_have_observers()) {
336 base::DictionaryValue update;
337 update.SetInteger("rid", render_process_id);
338 SendUpdate("removeGetUserMediaForRenderer", &update);
342 void WebRTCInternals::ResetForTesting() {
343 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
344 observers_.Clear();
345 peer_connection_data_.Clear();
346 get_user_media_requests_.Clear();
347 aec_dump_enabled_ = false;
350 } // namespace content