Fix WebRTC support (issue #531).

git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@1131 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
Marshall Greenblatt 2013-03-07 01:20:24 +00:00
parent 9b9c283ec2
commit 920ee60499
14 changed files with 417 additions and 53 deletions

View File

@ -874,6 +874,8 @@
'libcef/browser/javascript_dialog.h',
'libcef/browser/javascript_dialog_manager.cc',
'libcef/browser/javascript_dialog_manager.h',
'libcef/browser/media_capture_devices_dispatcher.cc',
'libcef/browser/media_capture_devices_dispatcher.h',
'libcef/browser/menu_creator.cc',
'libcef/browser/menu_creator.h',
'libcef/browser/menu_model_impl.cc',

View File

@ -10,16 +10,19 @@
#include "libcef/browser/browser_context.h"
#include "libcef/browser/browser_info.h"
#include "libcef/browser/browser_pref_store.h"
#include "libcef/browser/chrome_scheme_handler.h"
#include "libcef/browser/content_browser_client.h"
#include "libcef/browser/context.h"
#include "libcef/browser/devtools_delegate.h"
#include "libcef/browser/media_capture_devices_dispatcher.h"
#include "libcef/browser/navigate_params.h"
#include "libcef/browser/scheme_registration.h"
#include "libcef/browser/thread_util.h"
#include "libcef/browser/url_request_context_getter.h"
#include "libcef/browser/url_request_context_getter_proxy.h"
#include "libcef/common/cef_messages.h"
#include "libcef/common/cef_switches.h"
#include "libcef/common/http_header_utils.h"
#include "libcef/common/main_delegate.h"
#include "libcef/common/process_message_impl.h"
@ -27,6 +30,7 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/download_manager.h"
@ -1608,12 +1612,44 @@ void CefBrowserHostImpl::RequestMediaAccessPermission(
const content::MediaResponseCallback& callback) {
CEF_CURRENTLY_ON_UIT();
// TODO(cef): Get the default devices for the request. See for example
// chrome/browser/media/media_stream_devices_controller.cc.
content::MediaStreamDevices devices;
// TODO(cef): Give the user an opportunity to approve the device list or run
// the callback with an empty device list to cancel the request.
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
if (!command_line.HasSwitch(switches::kEnableMediaStream)) {
// Cancel the request.
callback.Run(devices);
return;
}
// Based on chrome/browser/media/media_stream_devices_controller.cc
bool microphone_requested =
(request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE);
bool webcam_requested =
(request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE);
if (microphone_requested || webcam_requested) {
switch (request.request_type) {
case content::MEDIA_OPEN_DEVICE:
// For open device request pick the desired device or fall back to the
// first available of the given type.
CefMediaCaptureDevicesDispatcher::GetInstance()->GetRequestedDevice(
request.requested_device_id,
microphone_requested,
webcam_requested,
&devices);
break;
case content::MEDIA_DEVICE_ACCESS:
case content::MEDIA_GENERATE_STREAM:
case content::MEDIA_ENUMERATE_DEVICES:
// Get the default devices for the request.
CefMediaCaptureDevicesDispatcher::GetInstance()->
GetDefaultDevices(_Context->pref_service(),
microphone_requested,
webcam_requested,
&devices);
break;
}
}
callback.Run(devices);
}

View File

@ -60,8 +60,9 @@ int CefBrowserMainParts::PreCreateThreads() {
content::GpuDataManager::GetInstance();
// Initialize user preferences.
user_prefs_ = new BrowserPrefStore();
user_prefs_->SetInitializationCompleted();
pref_store_ = new CefBrowserPrefStore();
pref_store_->SetInitializationCompleted();
pref_service_.reset(pref_store_->CreateService());
// Create a v8::Isolate for the current thread if it doesn't already exist.
if (!v8::Isolate::GetCurrent()) {
@ -75,7 +76,7 @@ int CefBrowserMainParts::PreCreateThreads() {
// Initialize proxy configuration tracker.
pref_proxy_config_tracker_.reset(
ProxyServiceFactory::CreatePrefProxyConfigTracker(
user_prefs_->CreateService()));
pref_service_.get()));
return 0;
}

View File

@ -10,6 +10,7 @@
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "base/prefs/pref_service.h"
#include "base/string_piece.h"
#include "chrome/browser/net/pref_proxy_config_tracker.h"
#include "content/public/browser/browser_main_parts.h"
@ -44,6 +45,7 @@ class CefBrowserMainParts : public content::BrowserMainParts {
CefBrowserContext* browser_context() const { return browser_context_.get(); }
CefDevToolsDelegate* devtools_delegate() const { return devtools_delegate_; }
PrefService* pref_service() const { return pref_service_.get(); }
scoped_ptr<net::ProxyConfigService> proxy_config_service() {
return proxy_config_service_.Pass();
}
@ -57,7 +59,8 @@ class CefBrowserMainParts : public content::BrowserMainParts {
scoped_ptr<MessageLoop> message_loop_;
scoped_ptr<PrefProxyConfigTracker> pref_proxy_config_tracker_;
scoped_ptr<net::ProxyConfigService> proxy_config_service_;
scoped_refptr<BrowserPrefStore> user_prefs_;
scoped_refptr<CefBrowserPrefStore> pref_store_;
scoped_ptr<PrefService> pref_service_;
v8::Isolate* proxy_v8_isolate_;
DISALLOW_COPY_AND_ASSIGN(CefBrowserMainParts);

View File

@ -3,19 +3,21 @@
// be found in the LICENSE file.
#include "libcef/browser/browser_pref_store.h"
#include "libcef/browser/media_capture_devices_dispatcher.h"
#include "base/command_line.h"
#include "base/prefs/pref_service_builder.h"
#include "base/prefs/pref_registry_simple.h"
#include "base/values.h"
#include "chrome/browser/net/pref_proxy_config_tracker_impl.h"
#include "chrome/browser/prefs/command_line_pref_store.h"
#include "chrome/browser/prefs/proxy_config_dictionary.h"
#include "chrome/common/pref_names.h"
BrowserPrefStore::BrowserPrefStore() {
CefBrowserPrefStore::CefBrowserPrefStore() {
}
PrefService* BrowserPrefStore::CreateService() {
PrefService* CefBrowserPrefStore::CreateService() {
PrefServiceBuilder builder;
builder.WithCommandLinePrefs(
new CommandLinePrefStore(CommandLine::ForCurrentProcess()));
@ -24,11 +26,11 @@ PrefService* BrowserPrefStore::CreateService() {
scoped_refptr<PrefRegistrySimple> registry(new PrefRegistrySimple());
// Default settings.
registry->RegisterDictionaryPref(prefs::kProxy,
ProxyConfigDictionary::CreateDirect());
CefMediaCaptureDevicesDispatcher::RegisterPrefs(registry);
PrefProxyConfigTrackerImpl::RegisterPrefs(registry);
return builder.Create(registry);
}
BrowserPrefStore::~BrowserPrefStore() {
CefBrowserPrefStore::~CefBrowserPrefStore() {
}

View File

@ -9,16 +9,16 @@
class PrefService;
class BrowserPrefStore : public TestingPrefStore {
class CefBrowserPrefStore : public TestingPrefStore {
public:
BrowserPrefStore();
CefBrowserPrefStore();
PrefService* CreateService();
protected:
virtual ~BrowserPrefStore();
virtual ~CefBrowserPrefStore();
DISALLOW_COPY_AND_ASSIGN(BrowserPrefStore);
DISALLOW_COPY_AND_ASSIGN(CefBrowserPrefStore);
};
#endif // CEF_LIBCEF_BROWSER_BROWSER_PREF_STORE_H_

View File

@ -14,6 +14,7 @@
#include "libcef/browser/browser_settings.h"
#include "libcef/browser/chrome_scheme_handler.h"
#include "libcef/browser/context.h"
#include "libcef/browser/media_capture_devices_dispatcher.h"
#include "libcef/browser/resource_dispatcher_host_delegate.h"
#include "libcef/browser/thread_util.h"
#include "libcef/browser/web_plugin_impl.h"
@ -27,7 +28,6 @@
#include "content/browser/plugin_service_impl.h"
#include "content/public/browser/access_token_store.h"
#include "content/public/browser/browser_url_handler.h"
#include "content/public/browser/media_observer.h"
#include "content/public/browser/plugin_service_filter.h"
#include "content/public/browser/quota_permission_context.h"
#include "content/public/browser/render_process_host.h"
@ -216,35 +216,6 @@ class CefPluginServiceFilter : public content::PluginServiceFilter {
} // namespace
class CefMediaObserver : public content::MediaObserver {
public:
CefMediaObserver() {}
virtual ~CefMediaObserver() {}
virtual void OnCaptureDevicesOpened(
int render_process_id,
int render_view_id,
const content::MediaStreamDevices& devices) OVERRIDE {}
virtual void OnCaptureDevicesClosed(
int render_process_id,
int render_view_id,
const content::MediaStreamDevices& devices) OVERRIDE {}
virtual void OnAudioCaptureDevicesChanged(
const content::MediaStreamDevices& devices) OVERRIDE {}
virtual void OnVideoCaptureDevicesChanged(
const content::MediaStreamDevices& devices) OVERRIDE {}
virtual void OnMediaRequestStateChanged(
int render_process_id,
int render_view_id,
const content::MediaStreamDevice& device,
content::MediaRequestState state) OVERRIDE {}
virtual void OnAudioStreamPlayingChanged(
int render_process_id,
int render_view_id,
int stream_id,
bool playing) OVERRIDE {}
};
CefContentBrowserClient::CefContentBrowserClient()
: browser_main_parts_(NULL),
next_browser_id_(0) {
@ -490,10 +461,7 @@ content::QuotaPermissionContext*
}
content::MediaObserver* CefContentBrowserClient::GetMediaObserver() {
// TODO(cef): Return NULL once it's supported. See crbug.com/116113.
if (!media_observer_.get())
media_observer_.reset(new CefMediaObserver());
return media_observer_.get();
return CefMediaCaptureDevicesDispatcher::GetInstance();
}
content::AccessTokenStore* CefContentBrowserClient::CreateAccessTokenStore() {

View File

@ -21,7 +21,6 @@
class CefBrowserContext;
class CefBrowserInfo;
class CefBrowserMainParts;
class CefMediaObserver;
class CefResourceDispatcherHostDelegate;
namespace content {
@ -134,7 +133,6 @@ class CefContentBrowserClient : public content::ContentBrowserClient {
CefBrowserMainParts* browser_main_parts_;
scoped_ptr<CefMediaObserver> media_observer_;
scoped_ptr<content::PluginServiceFilter> plugin_service_filter_;
scoped_ptr<CefResourceDispatcherHostDelegate>
resource_dispatcher_host_delegate_;

View File

@ -309,6 +309,10 @@ scoped_ptr<net::ProxyConfigService> CefContext::proxy_config_service() const {
proxy_config_service();
}
PrefService* CefContext::pref_service() const {
return main_delegate_->browser_client()->browser_main_parts()->pref_service();
}
CefTraceSubscriber* CefContext::GetTraceSubscriber() {
CEF_REQUIRE_UIT();
if (shutting_down_)

View File

@ -33,6 +33,7 @@ class CefBrowserHostImpl;
class CefDevToolsDelegate;
class CefMainDelegate;
class CefTraceSubscriber;
class PrefService;
class CefContext : public CefBase {
public:
@ -67,6 +68,7 @@ class CefContext : public CefBase {
CefRefPtr<CefApp> application() const;
CefBrowserContext* browser_context() const;
CefDevToolsDelegate* devtools_delegate() const;
PrefService* pref_service() const;
scoped_refptr<net::URLRequestContextGetter> request_context() const {
return request_context_;

View File

@ -0,0 +1,216 @@
// 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 "libcef/browser/media_capture_devices_dispatcher.h"
#include "base/prefs/pref_registry_simple.h"
#include "base/prefs/pref_service.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/media_devices_monitor.h"
#include "content/public/common/media_stream_request.h"
using content::BrowserThread;
using content::MediaStreamDevices;
namespace {
const content::MediaStreamDevice* FindDefaultDeviceWithId(
const content::MediaStreamDevices& devices,
const std::string& device_id) {
if (devices.empty())
return NULL;
content::MediaStreamDevices::const_iterator iter = devices.begin();
for (; iter != devices.end(); ++iter) {
if (iter->id == device_id) {
return &(*iter);
}
}
return &(*devices.begin());
};
} // namespace
CefMediaCaptureDevicesDispatcher*
CefMediaCaptureDevicesDispatcher::GetInstance() {
return Singleton<CefMediaCaptureDevicesDispatcher>::get();
}
CefMediaCaptureDevicesDispatcher::CefMediaCaptureDevicesDispatcher()
: devices_enumerated_(false) {}
CefMediaCaptureDevicesDispatcher::~CefMediaCaptureDevicesDispatcher() {}
void CefMediaCaptureDevicesDispatcher::RegisterPrefs(
PrefRegistrySimple* registry) {
registry->RegisterStringPref(prefs::kDefaultAudioCaptureDevice,
std::string());
registry->RegisterStringPref(prefs::kDefaultVideoCaptureDevice,
std::string());
}
void CefMediaCaptureDevicesDispatcher::AddObserver(Observer* observer) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!observers_.HasObserver(observer))
observers_.AddObserver(observer);
}
void CefMediaCaptureDevicesDispatcher::RemoveObserver(Observer* observer) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
observers_.RemoveObserver(observer);
}
const MediaStreamDevices&
CefMediaCaptureDevicesDispatcher::GetAudioCaptureDevices() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!devices_enumerated_) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&content::EnsureMonitorCaptureDevices));
devices_enumerated_ = true;
}
return audio_devices_;
}
const MediaStreamDevices&
CefMediaCaptureDevicesDispatcher::GetVideoCaptureDevices() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!devices_enumerated_) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&content::EnsureMonitorCaptureDevices));
devices_enumerated_ = true;
}
return video_devices_;
}
void CefMediaCaptureDevicesDispatcher::GetDefaultDevices(
PrefService* prefs,
bool audio,
bool video,
content::MediaStreamDevices* devices) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(audio || video);
std::string default_device;
if (audio) {
default_device = prefs->GetString(prefs::kDefaultAudioCaptureDevice);
GetRequestedDevice(default_device, true, false, devices);
}
if (video) {
default_device = prefs->GetString(prefs::kDefaultVideoCaptureDevice);
GetRequestedDevice(default_device, false, true, devices);
}
}
void CefMediaCaptureDevicesDispatcher::GetRequestedDevice(
const std::string& requested_device_id,
bool audio,
bool video,
content::MediaStreamDevices* devices) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(audio || video);
if (audio) {
const content::MediaStreamDevices& audio_devices = GetAudioCaptureDevices();
const content::MediaStreamDevice* const device =
FindDefaultDeviceWithId(audio_devices, requested_device_id);
if (device)
devices->push_back(*device);
}
if (video) {
const content::MediaStreamDevices& video_devices = GetVideoCaptureDevices();
const content::MediaStreamDevice* const device =
FindDefaultDeviceWithId(video_devices, requested_device_id);
if (device)
devices->push_back(*device);
}
}
void CefMediaCaptureDevicesDispatcher::OnCaptureDevicesOpened(
int render_process_id,
int render_view_id,
const content::MediaStreamDevices& devices) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
}
void CefMediaCaptureDevicesDispatcher::OnCaptureDevicesClosed(
int render_process_id,
int render_view_id,
const content::MediaStreamDevices& devices) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
}
void CefMediaCaptureDevicesDispatcher::OnAudioCaptureDevicesChanged(
const content::MediaStreamDevices& devices) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(
&CefMediaCaptureDevicesDispatcher::UpdateAudioDevicesOnUIThread,
base::Unretained(this), devices));
}
void CefMediaCaptureDevicesDispatcher::OnVideoCaptureDevicesChanged(
const content::MediaStreamDevices& devices) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(
&CefMediaCaptureDevicesDispatcher::UpdateVideoDevicesOnUIThread,
base::Unretained(this), devices));
}
void CefMediaCaptureDevicesDispatcher::OnMediaRequestStateChanged(
int render_process_id,
int render_view_id,
const content::MediaStreamDevice& device,
content::MediaRequestState state) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(
&CefMediaCaptureDevicesDispatcher::UpdateMediaRequestStateOnUIThread,
base::Unretained(this), render_process_id, render_view_id, device,
state));
}
void CefMediaCaptureDevicesDispatcher::OnAudioStreamPlayingChanged(
int render_process_id, int render_view_id, int stream_id, bool playing) {
}
void CefMediaCaptureDevicesDispatcher::UpdateAudioDevicesOnUIThread(
const content::MediaStreamDevices& devices) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
devices_enumerated_ = true;
audio_devices_ = devices;
FOR_EACH_OBSERVER(Observer, observers_,
OnUpdateAudioDevices(audio_devices_));
}
void CefMediaCaptureDevicesDispatcher::UpdateVideoDevicesOnUIThread(
const content::MediaStreamDevices& devices){
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
devices_enumerated_ = true;
video_devices_ = devices;
FOR_EACH_OBSERVER(Observer, observers_,
OnUpdateVideoDevices(video_devices_));
}
void CefMediaCaptureDevicesDispatcher::UpdateMediaRequestStateOnUIThread(
int render_process_id,
int render_view_id,
const content::MediaStreamDevice& device,
content::MediaRequestState state) {
FOR_EACH_OBSERVER(Observer, observers_,
OnRequestUpdate(render_process_id,
render_view_id,
device,
state));
}

View File

@ -0,0 +1,128 @@
// 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.
#ifndef CEF_LIBCEF_BROWSER_MEDIA_CAPTURE_DEVICES_DISPATCHER_H_
#define CEF_LIBCEF_BROWSER_MEDIA_CAPTURE_DEVICES_DISPATCHER_H_
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
#include "base/observer_list.h"
#include "content/public/browser/media_observer.h"
#include "content/public/common/media_stream_request.h"
class PrefRegistrySimple;
class PrefService;
// This singleton is used to receive updates about media events from the content
// layer. Based on chrome/browser/media/media_capture_devices_dispatcher.[h|cc].
class CefMediaCaptureDevicesDispatcher : public content::MediaObserver {
public:
class Observer {
public:
// Handle an information update consisting of a up-to-date audio capture
// device lists. This happens when a microphone is plugged in or unplugged.
virtual void OnUpdateAudioDevices(
const content::MediaStreamDevices& devices) {}
// Handle an information update consisting of a up-to-date video capture
// device lists. This happens when a camera is plugged in or unplugged.
virtual void OnUpdateVideoDevices(
const content::MediaStreamDevices& devices) {}
// Handle an information update related to a media stream request.
virtual void OnRequestUpdate(
int render_process_id,
int render_view_id,
const content::MediaStreamDevice& device,
const content::MediaRequestState state) {}
virtual ~Observer() {}
};
static CefMediaCaptureDevicesDispatcher* GetInstance();
// Registers the preferences related to Media Stream default devices.
static void RegisterPrefs(PrefRegistrySimple* registry);
// Methods for observers. Called on UI thread.
// Observers should add themselves on construction and remove themselves
// on destruction.
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
const content::MediaStreamDevices& GetAudioCaptureDevices();
const content::MediaStreamDevices& GetVideoCaptureDevices();
// Helper to get the default devices which can be used by the media request,
// if the return list is empty, it means there is no available device on the
// OS.
// Called on the UI thread.
void GetDefaultDevices(PrefService* prefs,
bool audio,
bool video,
content::MediaStreamDevices* devices);
// Helper for picking the device that was requested for an OpenDevice request.
// If the device requested is not available it will revert to using the first
// available one instead or will return an empty list if no devices of the
// requested kind are present.
void GetRequestedDevice(const std::string& requested_device_id,
bool audio,
bool video,
content::MediaStreamDevices* devices);
// Overridden from content::MediaObserver:
virtual void OnCaptureDevicesOpened(
int render_process_id,
int render_view_id,
const content::MediaStreamDevices& devices) OVERRIDE;
virtual void OnCaptureDevicesClosed(
int render_process_id,
int render_view_id,
const content::MediaStreamDevices& devices) OVERRIDE;
virtual void OnAudioCaptureDevicesChanged(
const content::MediaStreamDevices& devices) OVERRIDE;
virtual void OnVideoCaptureDevicesChanged(
const content::MediaStreamDevices& devices) OVERRIDE;
virtual void OnMediaRequestStateChanged(
int render_process_id,
int render_view_id,
const content::MediaStreamDevice& device,
content::MediaRequestState state) OVERRIDE;
virtual void OnAudioStreamPlayingChanged(
int render_process_id,
int render_view_id,
int stream_id,
bool playing) OVERRIDE;
private:
friend struct DefaultSingletonTraits<CefMediaCaptureDevicesDispatcher>;
CefMediaCaptureDevicesDispatcher();
virtual ~CefMediaCaptureDevicesDispatcher();
// Called by the MediaObserver() functions, executed on UI thread.
void UpdateAudioDevicesOnUIThread(const content::MediaStreamDevices& devices);
void UpdateVideoDevicesOnUIThread(const content::MediaStreamDevices& devices);
void UpdateMediaRequestStateOnUIThread(
int render_process_id,
int render_view_id,
const content::MediaStreamDevice& device,
content::MediaRequestState state);
// A list of cached audio capture devices.
content::MediaStreamDevices audio_devices_;
// A list of cached video capture devices.
content::MediaStreamDevices video_devices_;
// A list of observers for the device update notifications.
ObserverList<Observer> observers_;
// Flag to indicate if device enumeration has been done/doing.
// Only accessed on UI thread.
bool devices_enumerated_;
};
#endif // CEF_LIBCEF_BROWSER_MEDIA_CAPTURE_DEVICES_DISPATCHER_H_

View File

@ -86,4 +86,7 @@ const char kDisableDeveloperTools[] = "disable-developer-tools";
// Persist session cookies.
const char kPersistSessionCookies[] = "persist-session-cookies";
// Enable media (WebRTC audio/video) streaming.
const char kEnableMediaStream[] = "enable-media-stream";
} // namespace switches

View File

@ -39,6 +39,7 @@ extern const char kDisableTabToLinks[];
extern const char kDisableAuthorAndUserStyles[];
extern const char kDisableDeveloperTools[];
extern const char kPersistSessionCookies[];
extern const char kEnableMediaStream[];
} // namespace switches