Only grant permissions to new extensions from sync if they have the expected version
[chromium-blink-merge.git] / chrome / browser / media / media_capture_devices_dispatcher.cc
blob0d876f35ed71a111d1f00b1b7099dfd496ed058d
1 // Copyright (c) 2012 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 "chrome/browser/media/media_capture_devices_dispatcher.h"
7 #include "base/command_line.h"
8 #include "base/logging.h"
9 #include "base/metrics/field_trial.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/prefs/scoped_user_pref_update.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "chrome/browser/media/desktop_streams_registry.h"
16 #include "chrome/browser/media/media_access_handler.h"
17 #include "chrome/browser/media/media_stream_capture_indicator.h"
18 #include "chrome/browser/media/permission_bubble_media_access_handler.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/ui/browser.h"
21 #include "chrome/browser/ui/browser_window.h"
22 #include "chrome/common/chrome_switches.h"
23 #include "chrome/common/pref_names.h"
24 #include "components/pref_registry/pref_registry_syncable.h"
25 #include "content/public/browser/browser_thread.h"
26 #include "content/public/browser/media_capture_devices.h"
27 #include "content/public/browser/notification_source.h"
28 #include "content/public/browser/render_frame_host.h"
29 #include "content/public/browser/render_process_host.h"
30 #include "content/public/browser/web_contents.h"
31 #include "content/public/common/media_stream_request.h"
32 #include "extensions/common/constants.h"
33 #include "media/base/media_switches.h"
34 #include "net/base/net_util.h"
36 #if defined(OS_CHROMEOS)
37 #include "ash/shell.h"
38 #endif // defined(OS_CHROMEOS)
40 #if defined(ENABLE_EXTENSIONS)
41 #include "chrome/browser/media/desktop_capture_access_handler.h"
42 #include "chrome/browser/media/extension_media_access_handler.h"
43 #include "chrome/browser/media/tab_capture_access_handler.h"
44 #include "extensions/browser/extension_registry.h"
45 #include "extensions/common/extension.h"
46 #include "extensions/common/permissions/permissions_data.h"
47 #endif
49 using content::BrowserThread;
50 using content::MediaCaptureDevices;
51 using content::MediaStreamDevices;
53 namespace {
55 // Finds a device in |devices| that has |device_id|, or NULL if not found.
56 const content::MediaStreamDevice* FindDeviceWithId(
57 const content::MediaStreamDevices& devices,
58 const std::string& device_id) {
59 content::MediaStreamDevices::const_iterator iter = devices.begin();
60 for (; iter != devices.end(); ++iter) {
61 if (iter->id == device_id) {
62 return &(*iter);
65 return NULL;
68 #if defined(ENABLE_EXTENSIONS)
69 inline DesktopCaptureAccessHandler* ToDesktopCaptureAccessHandler(
70 MediaAccessHandler* handler) {
71 return static_cast<DesktopCaptureAccessHandler*>(handler);
73 #endif
74 } // namespace
76 MediaCaptureDevicesDispatcher* MediaCaptureDevicesDispatcher::GetInstance() {
77 return base::Singleton<MediaCaptureDevicesDispatcher>::get();
80 MediaCaptureDevicesDispatcher::MediaCaptureDevicesDispatcher()
81 : is_device_enumeration_disabled_(false),
82 media_stream_capture_indicator_(new MediaStreamCaptureIndicator()) {
83 DCHECK_CURRENTLY_ON(BrowserThread::UI);
85 #if defined(OS_MACOSX)
86 // AVFoundation is used for video/audio device monitoring and video capture.
87 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
88 switches::kForceQTKit)) {
89 base::CommandLine::ForCurrentProcess()->AppendSwitch(
90 switches::kEnableAVFoundation);
92 #endif
94 #if defined(ENABLE_EXTENSIONS)
95 media_access_handlers_.push_back(new ExtensionMediaAccessHandler());
96 media_access_handlers_.push_back(new DesktopCaptureAccessHandler());
97 media_access_handlers_.push_back(new TabCaptureAccessHandler());
98 #endif
99 media_access_handlers_.push_back(new PermissionBubbleMediaAccessHandler());
102 MediaCaptureDevicesDispatcher::~MediaCaptureDevicesDispatcher() {}
104 void MediaCaptureDevicesDispatcher::RegisterProfilePrefs(
105 user_prefs::PrefRegistrySyncable* registry) {
106 registry->RegisterStringPref(prefs::kDefaultAudioCaptureDevice,
107 std::string());
108 registry->RegisterStringPref(prefs::kDefaultVideoCaptureDevice,
109 std::string());
112 bool MediaCaptureDevicesDispatcher::IsOriginForCasting(const GURL& origin) {
113 // Whitelisted tab casting extensions.
114 return
115 // Dev
116 origin.spec() == "chrome-extension://enhhojjnijigcajfphajepfemndkmdlo/" ||
117 // Canary
118 origin.spec() == "chrome-extension://hfaagokkkhdbgiakmmlclaapfelnkoah/" ||
119 // Beta (internal)
120 origin.spec() == "chrome-extension://fmfcbgogabcbclcofgocippekhfcmgfj/" ||
121 // Google Cast Beta
122 origin.spec() == "chrome-extension://dliochdbjfkdbacpmhlcpmleaejidimm/" ||
123 // Google Cast Stable
124 origin.spec() == "chrome-extension://boadgeojelhgndaghljhdicfkmllpafd/" ||
125 // http://crbug.com/457908
126 origin.spec() == "chrome-extension://ekpaaapppgpmolpcldedioblbkmijaca/" ||
127 origin.spec() == "chrome-extension://fjhoaacokmgbjemoflkofnenfaiekifl/";
130 void MediaCaptureDevicesDispatcher::AddObserver(Observer* observer) {
131 DCHECK_CURRENTLY_ON(BrowserThread::UI);
132 if (!observers_.HasObserver(observer))
133 observers_.AddObserver(observer);
136 void MediaCaptureDevicesDispatcher::RemoveObserver(Observer* observer) {
137 DCHECK_CURRENTLY_ON(BrowserThread::UI);
138 observers_.RemoveObserver(observer);
141 const MediaStreamDevices&
142 MediaCaptureDevicesDispatcher::GetAudioCaptureDevices() {
143 DCHECK_CURRENTLY_ON(BrowserThread::UI);
144 if (is_device_enumeration_disabled_ || !test_audio_devices_.empty())
145 return test_audio_devices_;
147 return MediaCaptureDevices::GetInstance()->GetAudioCaptureDevices();
150 const MediaStreamDevices&
151 MediaCaptureDevicesDispatcher::GetVideoCaptureDevices() {
152 DCHECK_CURRENTLY_ON(BrowserThread::UI);
153 if (is_device_enumeration_disabled_ || !test_video_devices_.empty())
154 return test_video_devices_;
156 return MediaCaptureDevices::GetInstance()->GetVideoCaptureDevices();
159 void MediaCaptureDevicesDispatcher::ProcessMediaAccessRequest(
160 content::WebContents* web_contents,
161 const content::MediaStreamRequest& request,
162 const content::MediaResponseCallback& callback,
163 const extensions::Extension* extension) {
164 DCHECK_CURRENTLY_ON(BrowserThread::UI);
166 for (MediaAccessHandler* handler : media_access_handlers_) {
167 if (handler->SupportsStreamType(request.video_type, extension) ||
168 handler->SupportsStreamType(request.audio_type, extension)) {
169 handler->HandleRequest(web_contents, request, callback, extension);
170 return;
173 callback.Run(content::MediaStreamDevices(),
174 content::MEDIA_DEVICE_NOT_SUPPORTED, nullptr);
177 bool MediaCaptureDevicesDispatcher::CheckMediaAccessPermission(
178 content::WebContents* web_contents,
179 const GURL& security_origin,
180 content::MediaStreamType type) {
181 DCHECK_CURRENTLY_ON(BrowserThread::UI);
182 return CheckMediaAccessPermission(web_contents, security_origin, type,
183 nullptr);
186 bool MediaCaptureDevicesDispatcher::CheckMediaAccessPermission(
187 content::WebContents* web_contents,
188 const GURL& security_origin,
189 content::MediaStreamType type,
190 const extensions::Extension* extension) {
191 DCHECK_CURRENTLY_ON(BrowserThread::UI);
192 for (MediaAccessHandler* handler : media_access_handlers_) {
193 if (handler->SupportsStreamType(type, extension)) {
194 return handler->CheckMediaAccessPermission(web_contents, security_origin,
195 type, extension);
198 return false;
201 void MediaCaptureDevicesDispatcher::GetDefaultDevicesForProfile(
202 Profile* profile,
203 bool audio,
204 bool video,
205 content::MediaStreamDevices* devices) {
206 DCHECK_CURRENTLY_ON(BrowserThread::UI);
207 DCHECK(audio || video);
209 PrefService* prefs = profile->GetPrefs();
210 std::string default_device;
211 if (audio) {
212 default_device = prefs->GetString(prefs::kDefaultAudioCaptureDevice);
213 const content::MediaStreamDevice* device =
214 GetRequestedAudioDevice(default_device);
215 if (!device)
216 device = GetFirstAvailableAudioDevice();
217 if (device)
218 devices->push_back(*device);
221 if (video) {
222 default_device = prefs->GetString(prefs::kDefaultVideoCaptureDevice);
223 const content::MediaStreamDevice* device =
224 GetRequestedVideoDevice(default_device);
225 if (!device)
226 device = GetFirstAvailableVideoDevice();
227 if (device)
228 devices->push_back(*device);
232 const content::MediaStreamDevice*
233 MediaCaptureDevicesDispatcher::GetRequestedAudioDevice(
234 const std::string& requested_audio_device_id) {
235 DCHECK_CURRENTLY_ON(BrowserThread::UI);
236 const content::MediaStreamDevices& audio_devices = GetAudioCaptureDevices();
237 const content::MediaStreamDevice* const device =
238 FindDeviceWithId(audio_devices, requested_audio_device_id);
239 return device;
242 const content::MediaStreamDevice*
243 MediaCaptureDevicesDispatcher::GetFirstAvailableAudioDevice() {
244 DCHECK_CURRENTLY_ON(BrowserThread::UI);
245 const content::MediaStreamDevices& audio_devices = GetAudioCaptureDevices();
246 if (audio_devices.empty())
247 return NULL;
248 return &(*audio_devices.begin());
251 const content::MediaStreamDevice*
252 MediaCaptureDevicesDispatcher::GetRequestedVideoDevice(
253 const std::string& requested_video_device_id) {
254 DCHECK_CURRENTLY_ON(BrowserThread::UI);
255 const content::MediaStreamDevices& video_devices = GetVideoCaptureDevices();
256 const content::MediaStreamDevice* const device =
257 FindDeviceWithId(video_devices, requested_video_device_id);
258 return device;
261 const content::MediaStreamDevice*
262 MediaCaptureDevicesDispatcher::GetFirstAvailableVideoDevice() {
263 DCHECK_CURRENTLY_ON(BrowserThread::UI);
264 const content::MediaStreamDevices& video_devices = GetVideoCaptureDevices();
265 if (video_devices.empty())
266 return NULL;
267 return &(*video_devices.begin());
270 void MediaCaptureDevicesDispatcher::DisableDeviceEnumerationForTesting() {
271 is_device_enumeration_disabled_ = true;
274 scoped_refptr<MediaStreamCaptureIndicator>
275 MediaCaptureDevicesDispatcher::GetMediaStreamCaptureIndicator() {
276 return media_stream_capture_indicator_;
279 DesktopStreamsRegistry*
280 MediaCaptureDevicesDispatcher::GetDesktopStreamsRegistry() {
281 if (!desktop_streams_registry_)
282 desktop_streams_registry_.reset(new DesktopStreamsRegistry());
283 return desktop_streams_registry_.get();
286 void MediaCaptureDevicesDispatcher::OnAudioCaptureDevicesChanged() {
287 DCHECK_CURRENTLY_ON(BrowserThread::IO);
288 BrowserThread::PostTask(
289 BrowserThread::UI, FROM_HERE,
290 base::Bind(
291 &MediaCaptureDevicesDispatcher::NotifyAudioDevicesChangedOnUIThread,
292 base::Unretained(this)));
295 void MediaCaptureDevicesDispatcher::OnVideoCaptureDevicesChanged() {
296 DCHECK_CURRENTLY_ON(BrowserThread::IO);
297 BrowserThread::PostTask(
298 BrowserThread::UI, FROM_HERE,
299 base::Bind(
300 &MediaCaptureDevicesDispatcher::NotifyVideoDevicesChangedOnUIThread,
301 base::Unretained(this)));
304 void MediaCaptureDevicesDispatcher::OnMediaRequestStateChanged(
305 int render_process_id,
306 int render_frame_id,
307 int page_request_id,
308 const GURL& security_origin,
309 content::MediaStreamType stream_type,
310 content::MediaRequestState state) {
311 DCHECK_CURRENTLY_ON(BrowserThread::IO);
312 BrowserThread::PostTask(
313 BrowserThread::UI, FROM_HERE,
314 base::Bind(
315 &MediaCaptureDevicesDispatcher::UpdateMediaRequestStateOnUIThread,
316 base::Unretained(this), render_process_id, render_frame_id,
317 page_request_id, security_origin, stream_type, state));
320 void MediaCaptureDevicesDispatcher::OnCreatingAudioStream(
321 int render_process_id,
322 int render_frame_id) {
323 DCHECK_CURRENTLY_ON(BrowserThread::IO);
324 BrowserThread::PostTask(
325 BrowserThread::UI, FROM_HERE,
326 base::Bind(
327 &MediaCaptureDevicesDispatcher::OnCreatingAudioStreamOnUIThread,
328 base::Unretained(this), render_process_id, render_frame_id));
331 void MediaCaptureDevicesDispatcher::NotifyAudioDevicesChangedOnUIThread() {
332 MediaStreamDevices devices = GetAudioCaptureDevices();
333 FOR_EACH_OBSERVER(Observer, observers_,
334 OnUpdateAudioDevices(devices));
337 void MediaCaptureDevicesDispatcher::NotifyVideoDevicesChangedOnUIThread() {
338 MediaStreamDevices devices = GetVideoCaptureDevices();
339 FOR_EACH_OBSERVER(Observer, observers_,
340 OnUpdateVideoDevices(devices));
343 void MediaCaptureDevicesDispatcher::UpdateMediaRequestStateOnUIThread(
344 int render_process_id,
345 int render_frame_id,
346 int page_request_id,
347 const GURL& security_origin,
348 content::MediaStreamType stream_type,
349 content::MediaRequestState state) {
350 for (MediaAccessHandler* handler : media_access_handlers_) {
351 if (handler->SupportsStreamType(stream_type, nullptr)) {
352 handler->UpdateMediaRequestState(render_process_id, render_frame_id,
353 page_request_id, stream_type, state);
354 break;
358 #if defined(OS_CHROMEOS)
359 if (IsOriginForCasting(security_origin) && IsVideoMediaType(stream_type)) {
360 // Notify ash that casting state has changed.
361 if (state == content::MEDIA_REQUEST_STATE_DONE) {
362 ash::Shell::GetInstance()->OnCastingSessionStartedOrStopped(true);
363 } else if (state == content::MEDIA_REQUEST_STATE_CLOSING) {
364 ash::Shell::GetInstance()->OnCastingSessionStartedOrStopped(false);
367 #endif
369 FOR_EACH_OBSERVER(Observer, observers_,
370 OnRequestUpdate(render_process_id,
371 render_frame_id,
372 stream_type,
373 state));
376 void MediaCaptureDevicesDispatcher::OnCreatingAudioStreamOnUIThread(
377 int render_process_id,
378 int render_frame_id) {
379 DCHECK_CURRENTLY_ON(BrowserThread::UI);
380 FOR_EACH_OBSERVER(Observer, observers_,
381 OnCreatingAudioStream(render_process_id, render_frame_id));
384 bool MediaCaptureDevicesDispatcher::IsDesktopCaptureInProgress() {
385 DCHECK_CURRENTLY_ON(BrowserThread::UI);
386 #if defined(ENABLE_EXTENSIONS)
387 for (MediaAccessHandler* handler : media_access_handlers_) {
388 if (handler->SupportsStreamType(content::MEDIA_DESKTOP_VIDEO_CAPTURE,
389 NULL)) {
390 return ToDesktopCaptureAccessHandler(handler)->IsCaptureInProgress();
393 #endif
394 return false;
397 void MediaCaptureDevicesDispatcher::SetTestAudioCaptureDevices(
398 const MediaStreamDevices& devices) {
399 test_audio_devices_ = devices;
402 void MediaCaptureDevicesDispatcher::SetTestVideoCaptureDevices(
403 const MediaStreamDevices& devices) {
404 test_video_devices_ = devices;