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. 4 5 #include "content/browser/renderer_host/media/audio_input_device_manager.h" 6 7 #include "base/bind.h" 8 #include "base/memory/scoped_ptr.h" 9 #include "content/public/browser/browser_thread.h" 10 #include "content/public/common/media_stream_request.h" 11 #include "media/audio/audio_input_ipc.h" 12 #include "media/audio/audio_manager_base.h" 13 #include "media/audio/audio_parameters.h" 14 #include "media/base/channel_layout.h" 15 #include "media/base/scoped_histogram_timer.h" 16 17 namespace content { 18 19 const int AudioInputDeviceManager::kFakeOpenSessionId = 1; 20 21 namespace { 22 // Starting id for the first capture session. 23 const int kFirstSessionId = AudioInputDeviceManager::kFakeOpenSessionId + 1; 24 } 25 26 AudioInputDeviceManager::AudioInputDeviceManager( 27 media::AudioManager* audio_manager) 28 : listener_(NULL), 29 next_capture_session_id_(kFirstSessionId), 30 use_fake_device_(false), 31 audio_manager_(audio_manager) { 32 } 33 34 AudioInputDeviceManager::~AudioInputDeviceManager() { 35 } 36 37 const StreamDeviceInfo* AudioInputDeviceManager::GetOpenedDeviceInfoById( 38 int session_id) { 39 DCHECK_CURRENTLY_ON(BrowserThread::IO); 40 StreamDeviceList::iterator device = GetDevice(session_id); 41 if (device == devices_.end()) 42 return NULL; 43 44 return &(*device); 45 } 46 47 void AudioInputDeviceManager::Register( 48 MediaStreamProviderListener* listener, 49 const scoped_refptr<base::SingleThreadTaskRunner>& device_task_runner) { 50 DCHECK_CURRENTLY_ON(BrowserThread::IO); 51 DCHECK(!listener_); 52 DCHECK(!device_task_runner_); 53 listener_ = listener; 54 device_task_runner_ = device_task_runner; 55 } 56 57 void AudioInputDeviceManager::Unregister() { 58 DCHECK(listener_); 59 listener_ = NULL; 60 } 61 62 void AudioInputDeviceManager::EnumerateDevices(MediaStreamType stream_type) { 63 DCHECK_CURRENTLY_ON(BrowserThread::IO); 64 DCHECK(listener_); 65 66 device_task_runner_->PostTask( 67 FROM_HERE, 68 base::Bind(&AudioInputDeviceManager::EnumerateOnDeviceThread, 69 this, stream_type)); 70 } 71 72 int AudioInputDeviceManager::Open(const StreamDeviceInfo& device) { 73 DCHECK_CURRENTLY_ON(BrowserThread::IO); 74 // Generate a new id for this device. 75 int session_id = next_capture_session_id_++; 76 device_task_runner_->PostTask( 77 FROM_HERE, 78 base::Bind(&AudioInputDeviceManager::OpenOnDeviceThread, 79 this, session_id, device)); 80 81 return session_id; 82 } 83 84 void AudioInputDeviceManager::Close(int session_id) { 85 DCHECK_CURRENTLY_ON(BrowserThread::IO); 86 DCHECK(listener_); 87 StreamDeviceList::iterator device = GetDevice(session_id); 88 if (device == devices_.end()) 89 return; 90 const MediaStreamType stream_type = device->device.type; 91 if (session_id != kFakeOpenSessionId) 92 devices_.erase(device); 93 94 // Post a callback through the listener on IO thread since 95 // MediaStreamManager is expecting the callback asynchronously. 96 BrowserThread::PostTask(BrowserThread::IO, 97 FROM_HERE, 98 base::Bind(&AudioInputDeviceManager::ClosedOnIOThread, 99 this, stream_type, session_id)); 100 } 101 102 void AudioInputDeviceManager::UseFakeDevice() { 103 DCHECK_CURRENTLY_ON(BrowserThread::IO); 104 use_fake_device_ = true; 105 } 106 107 bool AudioInputDeviceManager::ShouldUseFakeDevice() const { 108 DCHECK_CURRENTLY_ON(BrowserThread::IO); 109 return use_fake_device_; 110 } 111 112 void AudioInputDeviceManager::EnumerateOnDeviceThread( 113 MediaStreamType stream_type) { 114 SCOPED_UMA_HISTOGRAM_TIMER( 115 "Media.AudioInputDeviceManager.EnumerateOnDeviceThreadTime"); 116 DCHECK(IsOnDeviceThread()); 117 DCHECK_EQ(MEDIA_DEVICE_AUDIO_CAPTURE, stream_type); 118 119 media::AudioDeviceNames device_names; 120 if (use_fake_device_) { 121 // Use the fake devices. 122 GetFakeDeviceNames(&device_names); 123 } else { 124 // Enumerate the devices on the OS. 125 // AudioManager is guaranteed to outlive MediaStreamManager in 126 // BrowserMainloop. 127 audio_manager_->GetAudioInputDeviceNames(&device_names); 128 } 129 130 scoped_ptr<StreamDeviceInfoArray> devices(new StreamDeviceInfoArray()); 131 for (media::AudioDeviceNames::iterator it = device_names.begin(); 132 it != device_names.end(); ++it) { 133 // Add device information to device vector. 134 devices->push_back(StreamDeviceInfo( 135 stream_type, it->device_name, it->unique_id)); 136 } 137 138 // Return the device list through the listener by posting a task on 139 // IO thread since MediaStreamManager handles the callback asynchronously. 140 BrowserThread::PostTask( 141 BrowserThread::IO, 142 FROM_HERE, 143 base::Bind(&AudioInputDeviceManager::DevicesEnumeratedOnIOThread, 144 this, stream_type, base::Passed(&devices))); 145 } 146 147 void AudioInputDeviceManager::OpenOnDeviceThread( 148 int session_id, const StreamDeviceInfo& info) { 149 SCOPED_UMA_HISTOGRAM_TIMER( 150 "Media.AudioInputDeviceManager.OpenOnDeviceThreadTime"); 151 DCHECK(IsOnDeviceThread()); 152 153 StreamDeviceInfo out(info.device.type, info.device.name, info.device.id, 154 0, 0, 0); 155 out.session_id = session_id; 156 157 MediaStreamDevice::AudioDeviceParameters& input_params = out.device.input; 158 159 if (use_fake_device_) { 160 // Don't need to query the hardware information if using fake device. 161 input_params.sample_rate = 44100; 162 input_params.channel_layout = media::CHANNEL_LAYOUT_STEREO; 163 } else { 164 // Get the preferred sample rate and channel configuration for the 165 // audio device. 166 media::AudioParameters params = 167 audio_manager_->GetInputStreamParameters(info.device.id); 168 input_params.sample_rate = params.sample_rate(); 169 input_params.channel_layout = params.channel_layout(); 170 input_params.frames_per_buffer = params.frames_per_buffer(); 171 input_params.effects = params.effects(); 172 173 // Add preferred output device information if a matching output device 174 // exists. 175 out.device.matched_output_device_id = 176 audio_manager_->GetAssociatedOutputDeviceID(info.device.id); 177 if (!out.device.matched_output_device_id.empty()) { 178 params = audio_manager_->GetOutputStreamParameters( 179 out.device.matched_output_device_id); 180 MediaStreamDevice::AudioDeviceParameters& matched_output_params = 181 out.device.matched_output; 182 matched_output_params.sample_rate = params.sample_rate(); 183 matched_output_params.channel_layout = params.channel_layout(); 184 matched_output_params.frames_per_buffer = params.frames_per_buffer(); 185 } 186 } 187 188 // Return the |session_id| through the listener by posting a task on 189 // IO thread since MediaStreamManager handles the callback asynchronously. 190 BrowserThread::PostTask(BrowserThread::IO, 191 FROM_HERE, 192 base::Bind(&AudioInputDeviceManager::OpenedOnIOThread, 193 this, session_id, out)); 194 } 195 196 void AudioInputDeviceManager::DevicesEnumeratedOnIOThread( 197 MediaStreamType stream_type, 198 scoped_ptr<StreamDeviceInfoArray> devices) { 199 DCHECK_CURRENTLY_ON(BrowserThread::IO); 200 // Ensure that |devices| gets deleted on exit. 201 if (listener_) 202 listener_->DevicesEnumerated(stream_type, *devices); 203 } 204 205 void AudioInputDeviceManager::OpenedOnIOThread(int session_id, 206 const StreamDeviceInfo& info) { 207 DCHECK_CURRENTLY_ON(BrowserThread::IO); 208 DCHECK_EQ(session_id, info.session_id); 209 DCHECK(GetDevice(session_id) == devices_.end()); 210 211 devices_.push_back(info); 212 213 if (listener_) 214 listener_->Opened(info.device.type, session_id); 215 } 216 217 void AudioInputDeviceManager::ClosedOnIOThread(MediaStreamType stream_type, 218 int session_id) { 219 DCHECK_CURRENTLY_ON(BrowserThread::IO); 220 if (listener_) 221 listener_->Closed(stream_type, session_id); 222 } 223 224 bool AudioInputDeviceManager::IsOnDeviceThread() const { 225 return device_task_runner_->BelongsToCurrentThread(); 226 } 227 228 AudioInputDeviceManager::StreamDeviceList::iterator 229 AudioInputDeviceManager::GetDevice(int session_id) { 230 for (StreamDeviceList::iterator i(devices_.begin()); i != devices_.end(); 231 ++i) { 232 if (i->session_id == session_id) 233 return i; 234 } 235 236 return devices_.end(); 237 } 238 239 void AudioInputDeviceManager::GetFakeDeviceNames( 240 media::AudioDeviceNames* device_names) { 241 static const char kFakeDeviceName1[] = "Fake Audio 1"; 242 static const char kFakeDeviceId1[] = "fake_audio_1"; 243 static const char kFakeDeviceName2[] = "Fake Audio 2"; 244 static const char kFakeDeviceId2[] = "fake_audio_2"; 245 DCHECK(device_names->empty()); 246 DCHECK(use_fake_device_); 247 device_names->push_back(media::AudioDeviceName(kFakeDeviceName1, 248 kFakeDeviceId1)); 249 device_names->push_back(media::AudioDeviceName(kFakeDeviceName2, 250 kFakeDeviceId2)); 251 } 252 253 } // namespace content 254