// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "content/browser/media/media_internals_proxy.h" #include "base/bind.h" #include "base/message_loop/message_loop.h" #include "content/browser/media/media_internals_handler.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_types.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/web_ui.h" namespace content { static const int kMediaInternalsProxyEventDelayMilliseconds = 100; static const net::NetLog::EventType kNetEventTypeFilter[] = { net::NetLog::TYPE_DISK_CACHE_ENTRY_IMPL, net::NetLog::TYPE_SPARSE_READ, net::NetLog::TYPE_SPARSE_WRITE, net::NetLog::TYPE_URL_REQUEST_START_JOB, net::NetLog::TYPE_HTTP_TRANSACTION_READ_RESPONSE_HEADERS, }; MediaInternalsProxy::MediaInternalsProxy() { registrar_.Add(this, NOTIFICATION_RENDERER_PROCESS_TERMINATED, NotificationService::AllBrowserContextsAndSources()); } void MediaInternalsProxy::Observe(int type, const NotificationSource& source, const NotificationDetails& details) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK_EQ(type, NOTIFICATION_RENDERER_PROCESS_TERMINATED); RenderProcessHost* process = Source<RenderProcessHost>(source).ptr(); CallJavaScriptFunctionOnUIThread("media.onRendererTerminated", new base::FundamentalValue(process->GetID())); } void MediaInternalsProxy::Attach(MediaInternalsMessageHandler* handler) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); handler_ = handler; BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind(&MediaInternalsProxy::ObserveMediaInternalsOnIOThread, this)); } void MediaInternalsProxy::Detach() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); handler_ = NULL; BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind( &MediaInternalsProxy::StopObservingMediaInternalsOnIOThread, this)); } void MediaInternalsProxy::GetEverything() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); // Ask MediaInternals for all its data. BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind(&MediaInternalsProxy::GetEverythingOnIOThread, this)); // Send the page names for constants. CallJavaScriptFunctionOnUIThread("media.onReceiveConstants", GetConstants()); } void MediaInternalsProxy::OnUpdate(const base::string16& update) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, base::Bind(&MediaInternalsProxy::UpdateUIOnUIThread, this, update)); } void MediaInternalsProxy::OnAddEntry(const net::NetLog::Entry& entry) { bool is_event_interesting = false; for (size_t i = 0; i < arraysize(kNetEventTypeFilter); i++) { if (entry.type() == kNetEventTypeFilter[i]) { is_event_interesting = true; break; } } if (!is_event_interesting) return; BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, base::Bind(&MediaInternalsProxy::AddNetEventOnUIThread, this, entry.ToValue())); } MediaInternalsProxy::~MediaInternalsProxy() {} base::Value* MediaInternalsProxy::GetConstants() { base::DictionaryValue* event_phases = new base::DictionaryValue(); event_phases->SetInteger( net::NetLog::EventPhaseToString(net::NetLog::PHASE_NONE), net::NetLog::PHASE_NONE); event_phases->SetInteger( net::NetLog::EventPhaseToString(net::NetLog::PHASE_BEGIN), net::NetLog::PHASE_BEGIN); event_phases->SetInteger( net::NetLog::EventPhaseToString(net::NetLog::PHASE_END), net::NetLog::PHASE_END); base::DictionaryValue* constants = new base::DictionaryValue(); constants->Set("eventTypes", net::NetLog::GetEventTypesAsValue()); constants->Set("eventPhases", event_phases); return constants; } void MediaInternalsProxy::ObserveMediaInternalsOnIOThread() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); update_callback_ = base::Bind(&MediaInternalsProxy::OnUpdate, base::Unretained(this)); MediaInternals::GetInstance()->AddUpdateCallback(update_callback_); if (GetContentClient()->browser()->GetNetLog()) { net::NetLog* net_log = GetContentClient()->browser()->GetNetLog(); net_log->AddThreadSafeObserver(this, net::NetLog::LOG_ALL_BUT_BYTES); } } void MediaInternalsProxy::StopObservingMediaInternalsOnIOThread() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); MediaInternals::GetInstance()->RemoveUpdateCallback(update_callback_); if (GetContentClient()->browser()->GetNetLog()) { net::NetLog* net_log = GetContentClient()->browser()->GetNetLog(); net_log->RemoveThreadSafeObserver(this); } } void MediaInternalsProxy::GetEverythingOnIOThread() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); MediaInternals::GetInstance()->SendEverything(); } void MediaInternalsProxy::UpdateUIOnUIThread(const base::string16& update) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); // Don't forward updates to a destructed UI. if (handler_) handler_->OnUpdate(update); } void MediaInternalsProxy::AddNetEventOnUIThread(base::Value* entry) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); // Send the updates to the page in kMediaInternalsProxyEventDelayMilliseconds // if an update is not already pending. if (!pending_net_updates_) { pending_net_updates_.reset(new base::ListValue()); base::MessageLoop::current()->PostDelayedTask( FROM_HERE, base::Bind(&MediaInternalsProxy::SendNetEventsOnUIThread, this), base::TimeDelta::FromMilliseconds( kMediaInternalsProxyEventDelayMilliseconds)); } pending_net_updates_->Append(entry); } void MediaInternalsProxy::SendNetEventsOnUIThread() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); CallJavaScriptFunctionOnUIThread("media.onNetUpdate", pending_net_updates_.release()); } void MediaInternalsProxy::CallJavaScriptFunctionOnUIThread( const std::string& function, base::Value* args) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); scoped_ptr<base::Value> args_value(args); std::vector<const base::Value*> args_vector; args_vector.push_back(args_value.get()); base::string16 update = WebUI::GetJavascriptCall(function, args_vector); UpdateUIOnUIThread(update); } } // namespace content