Ensure that WebRTC AEC recording checkbox is not set if cancelling file dialog.
[chromium-blink-merge.git] / content / browser / media / webrtc_internals.cc
blob8ded1a0c4360a32c115283c8e1f6b2272346dc7b
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/notification_service.h"
11 #include "content/public/browser/notification_types.h"
12 #include "content/public/browser/render_process_host.h"
13 #include "content/public/browser/web_contents.h"
14 #include "content/public/browser/web_contents_view.h"
15 #include "content/public/common/content_switches.h"
17 using base::ProcessId;
18 using std::string;
20 namespace content {
22 namespace {
23 // Makes sure that |dict| has a ListValue under path "log".
24 static base::ListValue* EnsureLogList(base::DictionaryValue* dict) {
25 base::ListValue* log = NULL;
26 if (!dict->GetList("log", &log)) {
27 log = new base::ListValue();
28 if (log)
29 dict->Set("log", log);
31 return log;
34 } // namespace
36 WebRTCInternals::WebRTCInternals()
37 : aec_dump_enabled_(false) {
38 registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_TERMINATED,
39 NotificationService::AllBrowserContextsAndSources());
40 // TODO(grunell): Shouldn't all the webrtc_internals* files be excluded from the
41 // build if WebRTC is disabled?
42 #if defined(ENABLE_WEBRTC)
43 if (CommandLine::ForCurrentProcess()->HasSwitch(
44 switches::kEnableWebRtcAecRecordings)) {
45 aec_dump_enabled_ = true;
46 aec_dump_file_path_ = CommandLine::ForCurrentProcess()->GetSwitchValuePath(
47 switches::kEnableWebRtcAecRecordings);
48 } else {
49 #if defined(OS_CHROMEOS)
50 aec_dump_file_path_ =
51 base::FilePath(FILE_PATH_LITERAL("/tmp/audio.aecdump"));
52 #elif defined(OS_ANDROID)
53 aec_dump_file_path_ =
54 base::FilePath(FILE_PATH_LITERAL("/sdcard/audio.aecdump"));
55 #else
56 aec_dump_file_path_ = base::FilePath(FILE_PATH_LITERAL("audio.aecdump"));
57 #endif
59 #endif // defined(ENABLE_WEBRTC)
62 WebRTCInternals::~WebRTCInternals() {
65 WebRTCInternals* WebRTCInternals::GetInstance() {
66 return Singleton<WebRTCInternals>::get();
69 void WebRTCInternals::OnAddPeerConnection(int render_process_id,
70 ProcessId pid,
71 int lid,
72 const string& url,
73 const string& servers,
74 const string& constraints) {
75 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
77 base::DictionaryValue* dict = new base::DictionaryValue();
78 if (!dict)
79 return;
81 dict->SetInteger("rid", render_process_id);
82 dict->SetInteger("pid", static_cast<int>(pid));
83 dict->SetInteger("lid", lid);
84 dict->SetString("servers", servers);
85 dict->SetString("constraints", constraints);
86 dict->SetString("url", url);
87 peer_connection_data_.Append(dict);
89 if (observers_.might_have_observers())
90 SendUpdate("addPeerConnection", dict);
93 void WebRTCInternals::OnRemovePeerConnection(ProcessId pid, int lid) {
94 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
95 for (size_t i = 0; i < peer_connection_data_.GetSize(); ++i) {
96 base::DictionaryValue* dict = NULL;
97 peer_connection_data_.GetDictionary(i, &dict);
99 int this_pid = 0;
100 int this_lid = 0;
101 dict->GetInteger("pid", &this_pid);
102 dict->GetInteger("lid", &this_lid);
104 if (this_pid != static_cast<int>(pid) || this_lid != lid)
105 continue;
107 peer_connection_data_.Remove(i, NULL);
109 if (observers_.might_have_observers()) {
110 base::DictionaryValue id;
111 id.SetInteger("pid", static_cast<int>(pid));
112 id.SetInteger("lid", lid);
113 SendUpdate("removePeerConnection", &id);
115 break;
119 void WebRTCInternals::OnUpdatePeerConnection(
120 ProcessId pid, int lid, const string& type, const string& value) {
121 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
123 for (size_t i = 0; i < peer_connection_data_.GetSize(); ++i) {
124 base::DictionaryValue* record = NULL;
125 peer_connection_data_.GetDictionary(i, &record);
127 int this_pid = 0, this_lid = 0;
128 record->GetInteger("pid", &this_pid);
129 record->GetInteger("lid", &this_lid);
131 if (this_pid != static_cast<int>(pid) || this_lid != lid)
132 continue;
134 // Append the update to the end of the log.
135 base::ListValue* log = EnsureLogList(record);
136 if (!log)
137 return;
139 base::DictionaryValue* log_entry = new base::DictionaryValue();
140 if (!log_entry)
141 return;
143 log_entry->SetString("type", type);
144 log_entry->SetString("value", value);
145 log->Append(log_entry);
147 if (observers_.might_have_observers()) {
148 base::DictionaryValue update;
149 update.SetInteger("pid", static_cast<int>(pid));
150 update.SetInteger("lid", lid);
151 update.SetString("type", type);
152 update.SetString("value", value);
154 SendUpdate("updatePeerConnection", &update);
156 return;
160 void WebRTCInternals::OnAddStats(base::ProcessId pid, int lid,
161 const base::ListValue& value) {
162 if (!observers_.might_have_observers())
163 return;
165 base::DictionaryValue dict;
166 dict.SetInteger("pid", static_cast<int>(pid));
167 dict.SetInteger("lid", lid);
169 base::ListValue* list = value.DeepCopy();
170 if (!list)
171 return;
173 dict.Set("reports", list);
175 SendUpdate("addStats", &dict);
178 void WebRTCInternals::OnGetUserMedia(int rid,
179 base::ProcessId pid,
180 const std::string& origin,
181 bool audio,
182 bool video,
183 const std::string& audio_constraints,
184 const std::string& video_constraints) {
185 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
187 base::DictionaryValue* dict = new base::DictionaryValue();
188 dict->SetInteger("rid", rid);
189 dict->SetInteger("pid", static_cast<int>(pid));
190 dict->SetString("origin", origin);
191 if (audio)
192 dict->SetString("audio", audio_constraints);
193 if (video)
194 dict->SetString("video", video_constraints);
196 get_user_media_requests_.Append(dict);
198 if (observers_.might_have_observers())
199 SendUpdate("addGetUserMedia", dict);
202 void WebRTCInternals::AddObserver(WebRTCInternalsUIObserver *observer) {
203 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
204 observers_.AddObserver(observer);
207 void WebRTCInternals::RemoveObserver(WebRTCInternalsUIObserver *observer) {
208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
209 observers_.RemoveObserver(observer);
211 // Disables the AEC recording if it is enabled and the last webrtc-internals
212 // page is going away.
213 if (aec_dump_enabled_ && !observers_.might_have_observers())
214 DisableAecDump();
217 void WebRTCInternals::UpdateObserver(WebRTCInternalsUIObserver* observer) {
218 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
219 if (peer_connection_data_.GetSize() > 0)
220 observer->OnUpdate("updateAllPeerConnections", &peer_connection_data_);
222 for (base::ListValue::iterator it = get_user_media_requests_.begin();
223 it != get_user_media_requests_.end();
224 ++it) {
225 observer->OnUpdate("addGetUserMedia", *it);
229 void WebRTCInternals::EnableAecDump(content::WebContents* web_contents) {
230 #if defined(ENABLE_WEBRTC)
231 #if defined(OS_ANDROID)
232 EnableAecDumpOnAllRenderProcessHosts();
233 #else
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
245 #endif
248 void WebRTCInternals::DisableAecDump() {
249 #if defined(ENABLE_WEBRTC)
250 aec_dump_enabled_ = false;
251 for (RenderProcessHost::iterator i(
252 content::RenderProcessHost::AllHostsIterator());
253 !i.IsAtEnd(); i.Advance()) {
254 i.GetCurrentValue()->DisableAecDump();
256 #endif
259 void WebRTCInternals::ResetForTesting() {
260 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
261 observers_.Clear();
262 peer_connection_data_.Clear();
263 get_user_media_requests_.Clear();
264 aec_dump_enabled_ = false;
267 void WebRTCInternals::SendUpdate(const string& command, base::Value* value) {
268 DCHECK(observers_.might_have_observers());
270 FOR_EACH_OBSERVER(WebRTCInternalsUIObserver,
271 observers_,
272 OnUpdate(command, value));
275 void WebRTCInternals::Observe(int type,
276 const NotificationSource& source,
277 const NotificationDetails& details) {
278 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
279 DCHECK_EQ(type, NOTIFICATION_RENDERER_PROCESS_TERMINATED);
280 OnRendererExit(Source<RenderProcessHost>(source)->GetID());
283 void WebRTCInternals::FileSelected(const base::FilePath& path,
284 int /* unused_index */,
285 void* /*unused_params */) {
286 #if defined(ENABLE_WEBRTC)
287 aec_dump_file_path_ = path;
288 EnableAecDumpOnAllRenderProcessHosts();
289 #endif
292 void WebRTCInternals::FileSelectionCanceled(void* params) {
293 #if defined(ENABLE_WEBRTC)
294 SendUpdate("aecRecordingFileSelectionCancelled", NULL);
295 #endif
298 void WebRTCInternals::OnRendererExit(int render_process_id) {
299 // Iterates from the end of the list to remove the PeerConnections created
300 // by the exitting renderer.
301 for (int i = peer_connection_data_.GetSize() - 1; i >= 0; --i) {
302 base::DictionaryValue* record = NULL;
303 peer_connection_data_.GetDictionary(i, &record);
305 int this_rid = 0;
306 record->GetInteger("rid", &this_rid);
308 if (this_rid == render_process_id) {
309 if (observers_.might_have_observers()) {
310 int lid = 0, pid = 0;
311 record->GetInteger("lid", &lid);
312 record->GetInteger("pid", &pid);
314 base::DictionaryValue update;
315 update.SetInteger("lid", lid);
316 update.SetInteger("pid", pid);
317 SendUpdate("removePeerConnection", &update);
319 peer_connection_data_.Remove(i, NULL);
323 bool found_any = false;
324 // Iterates from the end of the list to remove the getUserMedia requests
325 // created by the exiting renderer.
326 for (int i = get_user_media_requests_.GetSize() - 1; i >= 0; --i) {
327 base::DictionaryValue* record = NULL;
328 get_user_media_requests_.GetDictionary(i, &record);
330 int this_rid = 0;
331 record->GetInteger("rid", &this_rid);
333 if (this_rid == render_process_id) {
334 get_user_media_requests_.Remove(i, NULL);
335 found_any = true;
339 if (found_any && observers_.might_have_observers()) {
340 base::DictionaryValue update;
341 update.SetInteger("rid", render_process_id);
342 SendUpdate("removeGetUserMediaForRenderer", &update);
346 #if defined(ENABLE_WEBRTC)
347 void WebRTCInternals::EnableAecDumpOnAllRenderProcessHosts() {
348 aec_dump_enabled_ = true;
349 for (RenderProcessHost::iterator i(
350 content::RenderProcessHost::AllHostsIterator());
351 !i.IsAtEnd(); i.Advance()) {
352 i.GetCurrentValue()->EnableAecDump(aec_dump_file_path_);
355 #endif
357 } // namespace content