Popular sites on the NTP: check that experiment group StartsWith (rather than IS...
[chromium-blink-merge.git] / chrome / browser / media / extension_media_access_handler.cc
blob9b4e7db2236d56a55bad79ca11effa82716782a7
1 // Copyright 2015 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/extension_media_access_handler.h"
7 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
8 #include "chrome/browser/media/media_stream_capture_indicator.h"
9 #include "chrome/browser/media/media_stream_device_permissions.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/common/pref_names.h"
12 #include "content/public/browser/web_contents.h"
13 #include "extensions/common/extension.h"
14 #include "extensions/common/permissions/permissions_data.h"
16 namespace {
18 // This is a short-term solution to grant camera and/or microphone access to
19 // extensions:
20 // 1. Virtual keyboard extension.
21 // 2. Flutter gesture recognition extension.
22 // 3. TODO(smus): Airbender experiment 1.
23 // 4. TODO(smus): Airbender experiment 2.
24 // 5. Hotwording component extension.
25 // 6. XKB input method component extension.
26 // 7. M17n/T13n/CJK input method component extension.
27 // Once http://crbug.com/292856 is fixed, remove this whitelist.
28 bool IsMediaRequestWhitelistedForExtension(
29 const extensions::Extension* extension) {
30 return extension->id() == "mppnpdlheglhdfmldimlhpnegondlapf" ||
31 extension->id() == "jokbpnebhdcladagohdnfgjcpejggllo" ||
32 extension->id() == "clffjmdilanldobdnedchkdbofoimcgb" ||
33 extension->id() == "nnckehldicaciogcbchegobnafnjkcne" ||
34 extension->id() == "nbpagnldghgfoolbancepceaanlmhfmd" ||
35 extension->id() == "jkghodnilhceideoidjikpgommlajknk" ||
36 extension->id() == "gjaehgfemfahhmlgpdfknkhdnemmolop";
39 } // namespace
41 ExtensionMediaAccessHandler::ExtensionMediaAccessHandler() {
44 ExtensionMediaAccessHandler::~ExtensionMediaAccessHandler() {
47 bool ExtensionMediaAccessHandler::SupportsStreamType(
48 const content::MediaStreamType type,
49 const extensions::Extension* extension) {
50 return extension && (extension->is_platform_app() ||
51 IsMediaRequestWhitelistedForExtension(extension)) &&
52 (type == content::MEDIA_DEVICE_AUDIO_CAPTURE ||
53 type == content::MEDIA_DEVICE_VIDEO_CAPTURE);
56 bool ExtensionMediaAccessHandler::CheckMediaAccessPermission(
57 content::WebContents* web_contents,
58 const GURL& security_origin,
59 content::MediaStreamType type,
60 const extensions::Extension* extension) {
61 return extension->permissions_data()->HasAPIPermission(
62 type == content::MEDIA_DEVICE_AUDIO_CAPTURE
63 ? extensions::APIPermission::kAudioCapture
64 : extensions::APIPermission::kVideoCapture);
67 void ExtensionMediaAccessHandler::HandleRequest(
68 content::WebContents* web_contents,
69 const content::MediaStreamRequest& request,
70 const content::MediaResponseCallback& callback,
71 const extensions::Extension* extension) {
72 // TODO(vrk): This code is largely duplicated in
73 // MediaStreamDevicesController::Accept(). Move this code into a shared method
74 // between the two classes.
76 Profile* profile =
77 Profile::FromBrowserContext(web_contents->GetBrowserContext());
79 bool audio_allowed =
80 request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE &&
81 extension->permissions_data()->HasAPIPermission(
82 extensions::APIPermission::kAudioCapture) &&
83 GetDevicePolicy(profile, extension->url(), prefs::kAudioCaptureAllowed,
84 prefs::kAudioCaptureAllowedUrls) != ALWAYS_DENY;
85 bool video_allowed =
86 request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE &&
87 extension->permissions_data()->HasAPIPermission(
88 extensions::APIPermission::kVideoCapture) &&
89 GetDevicePolicy(profile, extension->url(), prefs::kVideoCaptureAllowed,
90 prefs::kVideoCaptureAllowedUrls) != ALWAYS_DENY;
92 bool get_default_audio_device = audio_allowed;
93 bool get_default_video_device = video_allowed;
95 content::MediaStreamDevices devices;
97 // Set an initial error result. If neither audio or video is allowed, we'll
98 // never try to get any device below but will just create |ui| and return an
99 // empty list with "invalid state" result. If at least one is allowed, we'll
100 // try to get device(s), and if failure, we want to return "no hardware"
101 // result.
102 // TODO(grunell): The invalid state result should be changed to a new denied
103 // result + a dcheck to ensure at least one of audio or video types is
104 // capture.
105 content::MediaStreamRequestResult result =
106 (audio_allowed || video_allowed) ? content::MEDIA_DEVICE_NO_HARDWARE
107 : content::MEDIA_DEVICE_INVALID_STATE;
109 // Get the exact audio or video device if an id is specified.
110 // We only set any error result here and before running the callback change
111 // it to OK if we have any device.
112 if (audio_allowed && !request.requested_audio_device_id.empty()) {
113 const content::MediaStreamDevice* audio_device =
114 MediaCaptureDevicesDispatcher::GetInstance()->GetRequestedAudioDevice(
115 request.requested_audio_device_id);
116 if (audio_device) {
117 devices.push_back(*audio_device);
118 get_default_audio_device = false;
121 if (video_allowed && !request.requested_video_device_id.empty()) {
122 const content::MediaStreamDevice* video_device =
123 MediaCaptureDevicesDispatcher::GetInstance()->GetRequestedVideoDevice(
124 request.requested_video_device_id);
125 if (video_device) {
126 devices.push_back(*video_device);
127 get_default_video_device = false;
131 // If either or both audio and video devices were requested but not
132 // specified by id, get the default devices.
133 if (get_default_audio_device || get_default_video_device) {
134 MediaCaptureDevicesDispatcher::GetInstance()->GetDefaultDevicesForProfile(
135 profile, get_default_audio_device, get_default_video_device, &devices);
138 scoped_ptr<content::MediaStreamUI> ui;
139 if (!devices.empty()) {
140 result = content::MEDIA_DEVICE_OK;
141 ui = MediaCaptureDevicesDispatcher::GetInstance()
142 ->GetMediaStreamCaptureIndicator()
143 ->RegisterMediaStream(web_contents, devices);
146 callback.Run(devices, result, ui.Pass());