Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(56)

Side by Side Diff: content/browser/renderer_host/media/audio_input_device_manager.cc

Issue 2763383002: Switching AudioInputDeviceManager from using AudioManager interface to AudioSystem one. (Closed)
Patch Set: Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/renderer_host/media/audio_input_device_manager.h" 5 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
6 6
7 #include <memory> 7 #include <memory>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/command_line.h" 10 #include "base/command_line.h"
11 #include "base/memory/ptr_util.h"
11 #include "base/metrics/histogram_macros.h" 12 #include "base/metrics/histogram_macros.h"
12 #include "build/build_config.h" 13 #include "build/build_config.h"
13 #include "content/public/browser/browser_thread.h" 14 #include "content/public/browser/browser_thread.h"
14 #include "content/public/common/media_stream_request.h" 15 #include "content/public/common/media_stream_request.h"
15 #include "media/audio/audio_input_ipc.h" 16 #include "media/audio/audio_input_ipc.h"
16 #include "media/audio/audio_manager_base.h" 17 #include "media/audio/audio_system.h"
17 #include "media/base/audio_parameters.h" 18 #include "media/base/audio_parameters.h"
19 #include "media/base/bind_to_current_loop.h"
18 #include "media/base/channel_layout.h" 20 #include "media/base/channel_layout.h"
19 #include "media/base/media_switches.h" 21 #include "media/base/media_switches.h"
20 22
21 #if defined(OS_CHROMEOS) 23 #if defined(OS_CHROMEOS)
22 #include "chromeos/audio/cras_audio_handler.h" 24 #include "chromeos/audio/cras_audio_handler.h"
23 #endif 25 #endif
24 26
25 namespace content { 27 namespace content {
26 28
27 const int AudioInputDeviceManager::kFakeOpenSessionId = 1; 29 const int AudioInputDeviceManager::kFakeOpenSessionId = 1;
28 30
29 namespace { 31 namespace {
30 // Starting id for the first capture session. 32 // Starting id for the first capture session.
31 const int kFirstSessionId = AudioInputDeviceManager::kFakeOpenSessionId + 1; 33 const int kFirstSessionId = AudioInputDeviceManager::kFakeOpenSessionId + 1;
34
35 // The object of this class lives on AudioSystem thread and at each given
36 // moment is owned by a callback it posted to that thread.
37 class DeviceOpener {
38 public:
39 using OnOpenedCallback = base::Callback<void(const StreamDeviceInfo&)>;
40
41 ~DeviceOpener();
42
43 // Wwill reply with |on_opened_cb| on the thread Open() is called on.
Max Morin 2017/03/22 17:46:24 Typo Wwill
44 static void Open(media::AudioSystem* audio_system,
45 const MediaStreamDevice& device,
46 int session_id,
47 OnOpenedCallback on_opened_cb);
48
49 protected:
50 DeviceOpener(media::AudioSystem* audio_system,
51 const MediaStreamDevice& device,
52 int session_id,
53 OnOpenedCallback on_opened_cb);
54
55 private:
56 void DoOpen(std::unique_ptr<DeviceOpener> owned_this);
57 void OpenWithMatchedOutputId(std::unique_ptr<DeviceOpener> owned_this,
58 const std::string& matched_output_id);
59 void OpenWithInputParams(std::unique_ptr<DeviceOpener> owned_this,
60 const media::AudioParameters& params);
61 void OpenWithOutputParams(std::unique_ptr<DeviceOpener> owned_this,
62 const media::AudioParameters& params);
63 void ReplyOpened();
64
65 base::WeakPtr<media::AudioSystem> audio_system_;
66 base::TimeTicks start_time_;
67 OnOpenedCallback on_opened_cb_;
68 StreamDeviceInfo info_;
69
70 DISALLOW_COPY_AND_ASSIGN(DeviceOpener);
71 };
72
73 DeviceOpener::DeviceOpener(media::AudioSystem* audio_system,
74 const MediaStreamDevice& device,
75 int session_id,
76 OnOpenedCallback on_opened_cb)
77 : audio_system_(audio_system->GetWeakPtr()),
78 on_opened_cb_(std::move(on_opened_cb)),
79 info_(device.type, device.name, device.id, 0, 0, 0) {
80 info_.session_id = session_id;
32 } 81 }
33 82
83 DeviceOpener::~DeviceOpener() {
84 if (!audio_system_)
85 return;
86 DCHECK(audio_system_->GetTaskRunner()->BelongsToCurrentThread());
87
88 // Do not ReplyOpened() here, since destructor may be called on message
89 // loop destruction before callback runs.
90
91 DCHECK(start_time_ == base::TimeTicks() ||
92 (base::TimeTicks::Now() - start_time_).InSeconds() < 30)
93 << "DeviceOpener hang";
94 }
95
96 // static
97 void DeviceOpener::Open(media::AudioSystem* audio_system,
98 const MediaStreamDevice& device,
99 int session_id,
100 OnOpenedCallback on_opened_cb) {
101 DCHECK(audio_system);
102
103 std::unique_ptr<DeviceOpener> opener(
104 new DeviceOpener(audio_system, device, session_id,
105 media::BindToCurrentLoop(on_opened_cb)));
106
107 audio_system->GetTaskRunner()->PostTask(
108 FROM_HERE,
109 base::Bind(&DeviceOpener::DoOpen, base::Unretained(opener.get()),
110 base::Passed(&opener)));
111 }
112
113 void DeviceOpener::DoOpen(std::unique_ptr<DeviceOpener> owned_this) {
114 if (!audio_system_)
115 return;
116 DCHECK(audio_system_->GetTaskRunner()->BelongsToCurrentThread());
117
118 start_time_ = base::TimeTicks::Now();
119
120 audio_system_->GetAssociatedOutputDeviceID(
121 info_.device.id,
122 base::Bind(&DeviceOpener::OpenWithMatchedOutputId, base::Unretained(this),
123 base::Passed(&owned_this)));
124 }
125
126 void DeviceOpener::OpenWithMatchedOutputId(
127 std::unique_ptr<DeviceOpener> owned_this,
128 const std::string& matched_output_id) {
129 if (!audio_system_)
130 return;
131 DCHECK(audio_system_->GetTaskRunner()->BelongsToCurrentThread());
132
133 info_.device.matched_output_device_id = matched_output_id;
134
135 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
136 switches::kUseFakeDeviceForMediaStream)) {
137 audio_system_->GetInputStreamParameters(
138 info_.device.id,
139 base::Bind(&DeviceOpener::OpenWithInputParams, base::Unretained(this),
140 base::Passed(&owned_this)));
141 return;
142 }
143
144 // Don't need to query the hardware information if using fake device.
145 info_.device.input.sample_rate = 44100;
146 info_.device.input.channel_layout = media::CHANNEL_LAYOUT_STEREO;
147 if (!info_.device.matched_output_device_id.empty()) {
148 info_.device.matched_output.sample_rate = 44100;
149 info_.device.matched_output.channel_layout = media::CHANNEL_LAYOUT_STEREO;
150 }
151 ReplyOpened();
152 }
153
154 void DeviceOpener::OpenWithInputParams(std::unique_ptr<DeviceOpener> owned_this,
155 const media::AudioParameters& params) {
156 if (!audio_system_)
157 return;
158 DCHECK(audio_system_->GetTaskRunner()->BelongsToCurrentThread());
159
160 // TODO(tommi): As is, we hit this code path when device.type is
161 // MEDIA_TAB_AUDIO_CAPTURE and the device id is not a device that
162 // the AudioManager can know about. This currently does not fail because
163 // the implementation of GetInputStreamParameters returns valid parameters
164 // by default for invalid devices. That behavior is problematic because it
165 // causes other parts of the code to attempt to open truly invalid or
166 // missing devices and falling back on alternate devices (and likely fail
167 // twice in a row). Tab audio capture should not pass through here and
168 // GetInputStreamParameters should return invalid parameters for invalid
169 // devices.
170
171 // Get the preferred sample rate and channel configuration for the
172 // audio device.
173 info_.device.input.sample_rate = params.sample_rate();
174 info_.device.input.channel_layout = params.channel_layout();
175 info_.device.input.frames_per_buffer = params.frames_per_buffer();
176 info_.device.input.effects = params.effects();
177 info_.device.input.mic_positions = params.mic_positions();
178
179 if (info_.device.matched_output_device_id.empty()) {
180 ReplyOpened();
181 return;
182 }
183
184 audio_system_->GetOutputStreamParameters(
185 info_.device.matched_output_device_id,
186 base::Bind(&DeviceOpener::OpenWithOutputParams, base::Unretained(this),
187 base::Passed(&owned_this)));
188 }
189
190 void DeviceOpener::OpenWithOutputParams(
191 std::unique_ptr<DeviceOpener> owned_this,
192 const media::AudioParameters& params) {
193 if (!audio_system_)
194 return;
195 DCHECK(audio_system_->GetTaskRunner()->BelongsToCurrentThread());
196
197 info_.device.matched_output.sample_rate = params.sample_rate();
198 info_.device.matched_output.channel_layout = params.channel_layout();
199 info_.device.matched_output.frames_per_buffer = params.frames_per_buffer();
200 ReplyOpened();
201 }
202
203 void DeviceOpener::ReplyOpened() {
204 if (!audio_system_)
205 return;
206 DCHECK(audio_system_->GetTaskRunner()->BelongsToCurrentThread());
207
208 DCHECK(start_time_ > base::TimeTicks());
209 UMA_HISTOGRAM_TIMES("Media.AudioInputDeviceManager.OpenOnDeviceThreadTime",
o1ka 2017/03/22 17:09:33 TODO: Make sure UMA meaning is unchanged. Add UMA
210 base::TimeTicks::Now() - start_time_);
211 std::move(on_opened_cb_).Run(info_);
212 start_time_ = base::TimeTicks();
213 }
214
215 } // namespace
216
34 AudioInputDeviceManager::AudioInputDeviceManager( 217 AudioInputDeviceManager::AudioInputDeviceManager(
35 media::AudioManager* audio_manager) 218 media::AudioSystem* audio_system)
36 : next_capture_session_id_(kFirstSessionId), 219 : next_capture_session_id_(kFirstSessionId),
37 #if defined(OS_CHROMEOS) 220 #if defined(OS_CHROMEOS)
38 keyboard_mic_streams_count_(0), 221 keyboard_mic_streams_count_(0),
39 #endif 222 #endif
40 audio_manager_(audio_manager), 223 audio_system_(audio_system) {
41 device_task_runner_(audio_manager_->GetTaskRunner()) {
42 } 224 }
43 225
44 AudioInputDeviceManager::~AudioInputDeviceManager() { 226 AudioInputDeviceManager::~AudioInputDeviceManager() {}
45 }
46 227
47 const StreamDeviceInfo* AudioInputDeviceManager::GetOpenedDeviceInfoById( 228 const StreamDeviceInfo* AudioInputDeviceManager::GetOpenedDeviceInfoById(
48 int session_id) { 229 int session_id) {
49 DCHECK_CURRENTLY_ON(BrowserThread::IO); 230 DCHECK_CURRENTLY_ON(BrowserThread::IO);
50 StreamDeviceList::iterator device = GetDevice(session_id); 231 StreamDeviceList::iterator device = GetDevice(session_id);
51 if (device == devices_.end()) 232 if (device == devices_.end())
52 return nullptr; 233 return nullptr;
53 234
54 return &(*device); 235 return &(*device);
55 } 236 }
56 237
57 void AudioInputDeviceManager::RegisterListener( 238 void AudioInputDeviceManager::RegisterListener(
58 MediaStreamProviderListener* listener) { 239 MediaStreamProviderListener* listener) {
59 DCHECK_CURRENTLY_ON(BrowserThread::IO); 240 DCHECK_CURRENTLY_ON(BrowserThread::IO);
60 DCHECK(listener); 241 DCHECK(listener);
61 DCHECK(device_task_runner_);
62 listeners_.AddObserver(listener); 242 listeners_.AddObserver(listener);
63 } 243 }
64 244
65 void AudioInputDeviceManager::UnregisterListener( 245 void AudioInputDeviceManager::UnregisterListener(
66 MediaStreamProviderListener* listener) { 246 MediaStreamProviderListener* listener) {
67 DCHECK_CURRENTLY_ON(BrowserThread::IO); 247 DCHECK_CURRENTLY_ON(BrowserThread::IO);
68 DCHECK(listener); 248 DCHECK(listener);
69 listeners_.RemoveObserver(listener); 249 listeners_.RemoveObserver(listener);
70 } 250 }
71 251
72 int AudioInputDeviceManager::Open(const MediaStreamDevice& device) { 252 int AudioInputDeviceManager::Open(const MediaStreamDevice& device) {
73 DCHECK_CURRENTLY_ON(BrowserThread::IO); 253 DCHECK_CURRENTLY_ON(BrowserThread::IO);
74 // Generate a new id for this device. 254 // Generate a new id for this device.
75 int session_id = next_capture_session_id_++; 255 int session_id = next_capture_session_id_++;
76 device_task_runner_->PostTask( 256 DeviceOpener::Open(
77 FROM_HERE, 257 audio_system_, device, session_id,
78 base::Bind(&AudioInputDeviceManager::OpenOnDeviceThread, 258 base::Bind(&AudioInputDeviceManager::OpenedOnIOThread, this, session_id));
79 this, session_id, device));
80 259
81 return session_id; 260 return session_id;
82 } 261 }
83 262
84 void AudioInputDeviceManager::Close(int session_id) { 263 void AudioInputDeviceManager::Close(int session_id) {
85 DCHECK_CURRENTLY_ON(BrowserThread::IO); 264 DCHECK_CURRENTLY_ON(BrowserThread::IO);
86 StreamDeviceList::iterator device = GetDevice(session_id); 265 StreamDeviceList::iterator device = GetDevice(session_id);
87 if (device == devices_.end()) 266 if (device == devices_.end())
88 return; 267 return;
89 const MediaStreamType stream_type = device->device.type; 268 const MediaStreamType stream_type = device->device.type;
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
128 BrowserThread::UI, 307 BrowserThread::UI,
129 FROM_HERE, 308 FROM_HERE,
130 base::Bind( 309 base::Bind(
131 &AudioInputDeviceManager::SetKeyboardMicStreamActiveOnUIThread, 310 &AudioInputDeviceManager::SetKeyboardMicStreamActiveOnUIThread,
132 this, 311 this,
133 false)); 312 false));
134 } 313 }
135 } 314 }
136 #endif 315 #endif
137 316
138 void AudioInputDeviceManager::OpenOnDeviceThread(
139 int session_id,
140 const MediaStreamDevice& device) {
141 SCOPED_UMA_HISTOGRAM_TIMER(
142 "Media.AudioInputDeviceManager.OpenOnDeviceThreadTime");
143 DCHECK(IsOnDeviceThread());
144
145 StreamDeviceInfo out(device.type, device.name, device.id, 0, 0, 0);
146 out.session_id = session_id;
147
148 MediaStreamDevice::AudioDeviceParameters& input_params = out.device.input;
149
150 // Add preferred output device information if a matching output device
151 // exists.
152 out.device.matched_output_device_id =
153 audio_manager_->GetAssociatedOutputDeviceID(device.id);
154
155 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
156 switches::kUseFakeDeviceForMediaStream)) {
157 // Don't need to query the hardware information if using fake device.
158 input_params.sample_rate = 44100;
159 input_params.channel_layout = media::CHANNEL_LAYOUT_STEREO;
160 if (!out.device.matched_output_device_id.empty()) {
161 out.device.matched_output.sample_rate = 44100;
162 out.device.matched_output.channel_layout = media::CHANNEL_LAYOUT_STEREO;
163 }
164 } else {
165 // TODO(tommi): As is, we hit this code path when device.type is
166 // MEDIA_TAB_AUDIO_CAPTURE and the device id is not a device that
167 // the AudioManager can know about. This currently does not fail because
168 // the implementation of GetInputStreamParameters returns valid parameters
169 // by default for invalid devices. That behavior is problematic because it
170 // causes other parts of the code to attempt to open truly invalid or
171 // missing devices and falling back on alternate devices (and likely fail
172 // twice in a row). Tab audio capture should not pass through here and
173 // GetInputStreamParameters should return invalid parameters for invalid
174 // devices.
175
176 // Get the preferred sample rate and channel configuration for the
177 // audio device.
178 media::AudioParameters params =
179 audio_manager_->GetInputStreamParameters(device.id);
180 input_params.sample_rate = params.sample_rate();
181 input_params.channel_layout = params.channel_layout();
182 input_params.frames_per_buffer = params.frames_per_buffer();
183 input_params.effects = params.effects();
184 input_params.mic_positions = params.mic_positions();
185 if (!out.device.matched_output_device_id.empty()) {
186 params = audio_manager_->GetOutputStreamParameters(
187 out.device.matched_output_device_id);
188 MediaStreamDevice::AudioDeviceParameters& matched_output_params =
189 out.device.matched_output;
190 matched_output_params.sample_rate = params.sample_rate();
191 matched_output_params.channel_layout = params.channel_layout();
192 matched_output_params.frames_per_buffer = params.frames_per_buffer();
193 }
194 }
195
196 // Return the |session_id| through the listener by posting a task on
197 // IO thread since MediaStreamManager handles the callback asynchronously.
198 BrowserThread::PostTask(BrowserThread::IO,
199 FROM_HERE,
200 base::Bind(&AudioInputDeviceManager::OpenedOnIOThread,
201 this, session_id, out));
202 }
203
204 void AudioInputDeviceManager::OpenedOnIOThread(int session_id, 317 void AudioInputDeviceManager::OpenedOnIOThread(int session_id,
205 const StreamDeviceInfo& info) { 318 const StreamDeviceInfo& info) {
206 DCHECK_CURRENTLY_ON(BrowserThread::IO); 319 DCHECK_CURRENTLY_ON(BrowserThread::IO);
207 DCHECK_EQ(session_id, info.session_id); 320 DCHECK_EQ(session_id, info.session_id);
208 DCHECK(GetDevice(session_id) == devices_.end()); 321 DCHECK(GetDevice(session_id) == devices_.end());
209 322
210 devices_.push_back(info); 323 devices_.push_back(info);
211 324
212 for (auto& listener : listeners_) 325 for (auto& listener : listeners_)
213 listener.Opened(info.device.type, session_id); 326 listener.Opened(info.device.type, session_id);
214 } 327 }
215 328
216 void AudioInputDeviceManager::ClosedOnIOThread(MediaStreamType stream_type, 329 void AudioInputDeviceManager::ClosedOnIOThread(MediaStreamType stream_type,
217 int session_id) { 330 int session_id) {
218 DCHECK_CURRENTLY_ON(BrowserThread::IO); 331 DCHECK_CURRENTLY_ON(BrowserThread::IO);
219 for (auto& listener : listeners_) 332 for (auto& listener : listeners_)
220 listener.Closed(stream_type, session_id); 333 listener.Closed(stream_type, session_id);
221 } 334 }
222 335
223 bool AudioInputDeviceManager::IsOnDeviceThread() const {
224 return device_task_runner_->BelongsToCurrentThread();
225 }
226
227 AudioInputDeviceManager::StreamDeviceList::iterator 336 AudioInputDeviceManager::StreamDeviceList::iterator
228 AudioInputDeviceManager::GetDevice(int session_id) { 337 AudioInputDeviceManager::GetDevice(int session_id) {
229 for (StreamDeviceList::iterator i(devices_.begin()); i != devices_.end(); 338 for (StreamDeviceList::iterator i(devices_.begin()); i != devices_.end();
230 ++i) { 339 ++i) {
231 if (i->session_id == session_id) 340 if (i->session_id == session_id)
232 return i; 341 return i;
233 } 342 }
234 343
235 return devices_.end(); 344 return devices_.end();
236 } 345 }
237 346
238 #if defined(OS_CHROMEOS) 347 #if defined(OS_CHROMEOS)
239 void AudioInputDeviceManager::SetKeyboardMicStreamActiveOnUIThread( 348 void AudioInputDeviceManager::SetKeyboardMicStreamActiveOnUIThread(
240 bool active) { 349 bool active) {
241 DCHECK_CURRENTLY_ON(BrowserThread::UI); 350 DCHECK_CURRENTLY_ON(BrowserThread::UI);
242 chromeos::CrasAudioHandler::Get()->SetKeyboardMicActive(active); 351 chromeos::CrasAudioHandler::Get()->SetKeyboardMicActive(active);
243 } 352 }
244 #endif 353 #endif
245 354
246
247 } // namespace content 355 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698