Add a FrameHostMsg_BeginNavigation IPC
[chromium-blink-merge.git] / content / browser / media / webrtc_internals.cc
blobdcfc9051ab2a06c4f67ef11d03a4f1d28a316fe6
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/path_service.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "content/browser/media/webrtc_internals_ui_observer.h"
10 #include "content/browser/web_contents/web_contents_view.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "content/public/browser/content_browser_client.h"
13 #include "content/public/browser/notification_service.h"
14 #include "content/public/browser/notification_types.h"
15 #include "content/public/browser/render_process_host.h"
16 #include "content/public/browser/web_contents.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 // TODO(grunell): Shouldn't all the webrtc_internals* files be excluded from the
42 // build if WebRTC is disabled?
43 #if defined(ENABLE_WEBRTC)
44 aec_dump_file_path_ =
45 GetContentClient()->browser()->GetDefaultDownloadDirectory();
46 if (aec_dump_file_path_.empty()) {
47 // In this case the default path (|aec_dump_file_path_|) will be empty and
48 // the platform default path will be used in the file dialog (with no
49 // default file name). See SelectFileDialog::SelectFile. On Android where
50 // there's no dialog we'll fail to open the file.
51 VLOG(1) << "Could not get the download directory.";
52 } else {
53 aec_dump_file_path_ =
54 aec_dump_file_path_.Append(FILE_PATH_LITERAL("audio.aecdump"));
56 #endif // defined(ENABLE_WEBRTC)
59 WebRTCInternals::~WebRTCInternals() {
62 WebRTCInternals* WebRTCInternals::GetInstance() {
63 return Singleton<WebRTCInternals>::get();
66 void WebRTCInternals::OnAddPeerConnection(int render_process_id,
67 ProcessId pid,
68 int lid,
69 const string& url,
70 const string& servers,
71 const string& constraints) {
72 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
74 base::DictionaryValue* dict = new base::DictionaryValue();
75 if (!dict)
76 return;
78 dict->SetInteger("rid", render_process_id);
79 dict->SetInteger("pid", static_cast<int>(pid));
80 dict->SetInteger("lid", lid);
81 dict->SetString("servers", servers);
82 dict->SetString("constraints", constraints);
83 dict->SetString("url", url);
84 peer_connection_data_.Append(dict);
86 if (observers_.might_have_observers())
87 SendUpdate("addPeerConnection", dict);
90 void WebRTCInternals::OnRemovePeerConnection(ProcessId pid, int lid) {
91 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
92 for (size_t i = 0; i < peer_connection_data_.GetSize(); ++i) {
93 base::DictionaryValue* dict = NULL;
94 peer_connection_data_.GetDictionary(i, &dict);
96 int this_pid = 0;
97 int this_lid = 0;
98 dict->GetInteger("pid", &this_pid);
99 dict->GetInteger("lid", &this_lid);
101 if (this_pid != static_cast<int>(pid) || this_lid != lid)
102 continue;
104 peer_connection_data_.Remove(i, NULL);
106 if (observers_.might_have_observers()) {
107 base::DictionaryValue id;
108 id.SetInteger("pid", static_cast<int>(pid));
109 id.SetInteger("lid", lid);
110 SendUpdate("removePeerConnection", &id);
112 break;
116 void WebRTCInternals::OnUpdatePeerConnection(
117 ProcessId pid, int lid, const string& type, const string& value) {
118 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
120 for (size_t i = 0; i < peer_connection_data_.GetSize(); ++i) {
121 base::DictionaryValue* record = NULL;
122 peer_connection_data_.GetDictionary(i, &record);
124 int this_pid = 0, this_lid = 0;
125 record->GetInteger("pid", &this_pid);
126 record->GetInteger("lid", &this_lid);
128 if (this_pid != static_cast<int>(pid) || this_lid != lid)
129 continue;
131 // Append the update to the end of the log.
132 base::ListValue* log = EnsureLogList(record);
133 if (!log)
134 return;
136 base::DictionaryValue* log_entry = new base::DictionaryValue();
137 if (!log_entry)
138 return;
140 int64 milliseconds = (base::Time::Now() - base::Time()).InMilliseconds();
141 string time = base::Int64ToString(milliseconds);
142 log_entry->SetString("time", time);
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.MergeDictionary(log_entry);
153 SendUpdate("updatePeerConnection", &update);
155 return;
159 void WebRTCInternals::OnAddStats(base::ProcessId pid, int lid,
160 const base::ListValue& value) {
161 if (!observers_.might_have_observers())
162 return;
164 base::DictionaryValue dict;
165 dict.SetInteger("pid", static_cast<int>(pid));
166 dict.SetInteger("lid", lid);
168 base::ListValue* list = value.DeepCopy();
169 if (!list)
170 return;
172 dict.Set("reports", list);
174 SendUpdate("addStats", &dict);
177 void WebRTCInternals::OnGetUserMedia(int rid,
178 base::ProcessId pid,
179 const std::string& origin,
180 bool audio,
181 bool video,
182 const std::string& audio_constraints,
183 const std::string& video_constraints) {
184 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
186 base::DictionaryValue* dict = new base::DictionaryValue();
187 dict->SetInteger("rid", rid);
188 dict->SetInteger("pid", static_cast<int>(pid));
189 dict->SetString("origin", origin);
190 if (audio)
191 dict->SetString("audio", audio_constraints);
192 if (video)
193 dict->SetString("video", video_constraints);
195 get_user_media_requests_.Append(dict);
197 if (observers_.might_have_observers())
198 SendUpdate("addGetUserMedia", dict);
201 void WebRTCInternals::AddObserver(WebRTCInternalsUIObserver *observer) {
202 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
203 observers_.AddObserver(observer);
206 void WebRTCInternals::RemoveObserver(WebRTCInternalsUIObserver *observer) {
207 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
208 observers_.RemoveObserver(observer);
210 // Disables the AEC recording if it is enabled and the last webrtc-internals
211 // page is going away.
212 if (aec_dump_enabled_ && !observers_.might_have_observers())
213 DisableAecDump();
216 void WebRTCInternals::UpdateObserver(WebRTCInternalsUIObserver* observer) {
217 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
218 if (peer_connection_data_.GetSize() > 0)
219 observer->OnUpdate("updateAllPeerConnections", &peer_connection_data_);
221 for (base::ListValue::iterator it = get_user_media_requests_.begin();
222 it != get_user_media_requests_.end();
223 ++it) {
224 observer->OnUpdate("addGetUserMedia", *it);
228 void WebRTCInternals::EnableAecDump(content::WebContents* web_contents) {
229 #if defined(ENABLE_WEBRTC)
230 #if defined(OS_ANDROID)
231 EnableAecDumpOnAllRenderProcessHosts();
232 #else
233 select_file_dialog_ = ui::SelectFileDialog::Create(this, NULL);
234 select_file_dialog_->SelectFile(
235 ui::SelectFileDialog::SELECT_SAVEAS_FILE,
236 base::string16(),
237 aec_dump_file_path_,
238 NULL,
240 FILE_PATH_LITERAL(""),
241 web_contents->GetTopLevelNativeWindow(),
242 NULL);
243 #endif
244 #endif
247 void WebRTCInternals::DisableAecDump() {
248 #if defined(ENABLE_WEBRTC)
249 aec_dump_enabled_ = false;
251 // Tear down the dialog since the user has unchecked the AEC dump box.
252 select_file_dialog_ = NULL;
254 for (RenderProcessHost::iterator i(
255 content::RenderProcessHost::AllHostsIterator());
256 !i.IsAtEnd(); i.Advance()) {
257 i.GetCurrentValue()->DisableAecDump();
259 #endif
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;
270 void WebRTCInternals::SendUpdate(const string& command, base::Value* value) {
271 DCHECK(observers_.might_have_observers());
273 FOR_EACH_OBSERVER(WebRTCInternalsUIObserver,
274 observers_,
275 OnUpdate(command, value));
278 void WebRTCInternals::Observe(int type,
279 const NotificationSource& source,
280 const NotificationDetails& details) {
281 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
282 DCHECK_EQ(type, NOTIFICATION_RENDERER_PROCESS_TERMINATED);
283 OnRendererExit(Source<RenderProcessHost>(source)->GetID());
286 void WebRTCInternals::FileSelected(const base::FilePath& path,
287 int /* unused_index */,
288 void* /*unused_params */) {
289 #if defined(ENABLE_WEBRTC)
290 aec_dump_file_path_ = path;
291 EnableAecDumpOnAllRenderProcessHosts();
292 #endif
295 void WebRTCInternals::FileSelectionCanceled(void* params) {
296 #if defined(ENABLE_WEBRTC)
297 SendUpdate("aecRecordingFileSelectionCancelled", NULL);
298 #endif
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);
308 int this_rid = 0;
309 record->GetInteger("rid", &this_rid);
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);
317 base::DictionaryValue update;
318 update.SetInteger("lid", lid);
319 update.SetInteger("pid", pid);
320 SendUpdate("removePeerConnection", &update);
322 peer_connection_data_.Remove(i, NULL);
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);
333 int this_rid = 0;
334 record->GetInteger("rid", &this_rid);
336 if (this_rid == render_process_id) {
337 get_user_media_requests_.Remove(i, NULL);
338 found_any = true;
342 if (found_any && observers_.might_have_observers()) {
343 base::DictionaryValue update;
344 update.SetInteger("rid", render_process_id);
345 SendUpdate("removeGetUserMediaForRenderer", &update);
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_);
358 #endif
360 } // namespace content