1 // Copyright 2016 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.
4 
5 #include "chrome/browser/ui/webui/settings/settings_media_devices_selection_handler.h"
6 
7 #include <stddef.h>
8 
9 #include <memory>
10 #include <utility>
11 
12 #include "base/bind.h"
13 #include "base/macros.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/common/pref_names.h"
16 #include "components/prefs/pref_service.h"
17 
18 #if BUILDFLAG(ENABLE_EXTENSIONS)
19 #include "extensions/strings/grit/extensions_strings.h"
20 #include "ui/base/l10n/l10n_util.h"
21 #endif
22 
23 namespace {
24 
25 const char kAudio[] = "mic";
26 const char kVideo[] = "camera";
27 
28 }  // namespace
29 
30 namespace settings {
31 
MediaDevicesSelectionHandler(Profile * profile)32 MediaDevicesSelectionHandler::MediaDevicesSelectionHandler(Profile* profile)
33     : profile_(profile), observer_(this) {
34 }
35 
~MediaDevicesSelectionHandler()36 MediaDevicesSelectionHandler::~MediaDevicesSelectionHandler() {
37 }
38 
OnJavascriptAllowed()39 void MediaDevicesSelectionHandler::OnJavascriptAllowed() {
40   // Register to the device observer list to get up-to-date device lists.
41   observer_.Add(MediaCaptureDevicesDispatcher::GetInstance());
42 }
43 
OnJavascriptDisallowed()44 void MediaDevicesSelectionHandler::OnJavascriptDisallowed() {
45   observer_.RemoveAll();
46 }
47 
RegisterMessages()48 void MediaDevicesSelectionHandler::RegisterMessages() {
49   web_ui()->RegisterMessageCallback(
50       "getDefaultCaptureDevices",
51       base::BindRepeating(
52           &MediaDevicesSelectionHandler::GetDefaultCaptureDevices,
53           base::Unretained(this)));
54   web_ui()->RegisterMessageCallback(
55       "setDefaultCaptureDevice",
56       base::BindRepeating(
57           &MediaDevicesSelectionHandler::SetDefaultCaptureDevice,
58           base::Unretained(this)));
59 }
60 
OnUpdateAudioDevices(const blink::MediaStreamDevices & devices)61 void MediaDevicesSelectionHandler::OnUpdateAudioDevices(
62     const blink::MediaStreamDevices& devices) {
63   UpdateDevicesMenu(AUDIO, devices);
64 }
65 
OnUpdateVideoDevices(const blink::MediaStreamDevices & devices)66 void MediaDevicesSelectionHandler::OnUpdateVideoDevices(
67     const blink::MediaStreamDevices& devices) {
68   UpdateDevicesMenu(VIDEO, devices);
69 }
70 
GetDefaultCaptureDevices(const base::ListValue * args)71 void MediaDevicesSelectionHandler::GetDefaultCaptureDevices(
72     const base::ListValue* args) {
73   DCHECK_EQ(1U, args->GetSize());
74   std::string type;
75   if (!args->GetString(0, &type)) {
76     NOTREACHED();
77     return;
78   }
79   DCHECK(!type.empty());
80 
81   if (type == kAudio)
82     UpdateDevicesMenuForType(AUDIO);
83   else if (type == kVideo)
84     UpdateDevicesMenuForType(VIDEO);
85 }
86 
SetDefaultCaptureDevice(const base::ListValue * args)87 void MediaDevicesSelectionHandler::SetDefaultCaptureDevice(
88     const base::ListValue* args) {
89   DCHECK_EQ(2U, args->GetSize());
90   std::string type, device;
91   if (!(args->GetString(0, &type) && args->GetString(1, &device))) {
92     NOTREACHED();
93     return;
94   }
95 
96   DCHECK(!type.empty());
97   DCHECK(!device.empty());
98 
99   PrefService* prefs = profile_->GetPrefs();
100   if (type == kAudio)
101     prefs->SetString(prefs::kDefaultAudioCaptureDevice, device);
102   else if (type == kVideo)
103     prefs->SetString(prefs::kDefaultVideoCaptureDevice, device);
104   else
105     NOTREACHED();
106 }
107 
UpdateDevicesMenu(DeviceType type,const blink::MediaStreamDevices & devices)108 void MediaDevicesSelectionHandler::UpdateDevicesMenu(
109     DeviceType type,
110     const blink::MediaStreamDevices& devices) {
111   AllowJavascript();
112 
113   // Get the default device unique id from prefs.
114   PrefService* prefs = profile_->GetPrefs();
115   std::string default_device;
116   std::string device_type;
117   switch (type) {
118     case AUDIO:
119       default_device = prefs->GetString(prefs::kDefaultAudioCaptureDevice);
120       device_type = kAudio;
121       break;
122     case VIDEO:
123       default_device = prefs->GetString(prefs::kDefaultVideoCaptureDevice);
124       device_type = kVideo;
125       break;
126   }
127 
128   // Build the list of devices to send to JS.
129   std::string default_id;
130   base::ListValue device_list;
131   for (size_t i = 0; i < devices.size(); ++i) {
132     std::unique_ptr<base::DictionaryValue> entry(new base::DictionaryValue());
133     entry->SetString("name", GetDeviceDisplayName(devices[i]));
134     entry->SetString("id",  devices[i].id);
135     device_list.Append(std::move(entry));
136     if (devices[i].id == default_device)
137       default_id = default_device;
138   }
139 
140   // Use the first device as the default device if the preferred default device
141   // does not exist in the OS.
142   if (!devices.empty() && default_id.empty())
143     default_id = devices[0].id;
144 
145   base::Value default_value(default_id);
146   base::Value type_value(device_type);
147   FireWebUIListener("updateDevicesMenu", type_value, device_list,
148                     default_value);
149 }
150 
GetDeviceDisplayName(const blink::MediaStreamDevice & device) const151 std::string MediaDevicesSelectionHandler::GetDeviceDisplayName(
152     const blink::MediaStreamDevice& device) const {
153   std::string facing_info;
154 
155 #if BUILDFLAG(ENABLE_EXTENSIONS)
156   switch (device.video_facing) {
157     case media::VideoFacingMode::MEDIA_VIDEO_FACING_USER:
158       facing_info = l10n_util::GetStringUTF8(IDS_CAMERA_FACING_USER);
159       break;
160     case media::VideoFacingMode::MEDIA_VIDEO_FACING_ENVIRONMENT:
161       facing_info = l10n_util::GetStringUTF8(IDS_CAMERA_FACING_ENVIRONMENT);
162       break;
163     case media::VideoFacingMode::MEDIA_VIDEO_FACING_NONE:
164       break;
165     case media::VideoFacingMode::NUM_MEDIA_VIDEO_FACING_MODES:
166       NOTREACHED();
167       break;
168   }
169 #endif
170 
171   if (facing_info.empty())
172     return device.name;
173   return device.name + " " + facing_info;
174 }
175 
UpdateDevicesMenuForType(DeviceType type)176 void MediaDevicesSelectionHandler::UpdateDevicesMenuForType(DeviceType type) {
177   blink::MediaStreamDevices devices;
178   switch (type) {
179     case AUDIO:
180       devices = MediaCaptureDevicesDispatcher::GetInstance()->
181           GetAudioCaptureDevices();
182       break;
183     case VIDEO:
184       devices = MediaCaptureDevicesDispatcher::GetInstance()->
185           GetVideoCaptureDevices();
186       break;
187   }
188 
189   UpdateDevicesMenu(type, devices);
190 }
191 
192 }  // namespace settings
193