| OLD | NEW |
| 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 "media/audio/audio_input_device.h" | 5 #include "media/audio/audio_input_device.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 26 matching lines...) Expand all Loading... |
| 37 int total_segments, | 37 int total_segments, |
| 38 CaptureCallback* capture_callback); | 38 CaptureCallback* capture_callback); |
| 39 ~AudioThreadCallback() override; | 39 ~AudioThreadCallback() override; |
| 40 | 40 |
| 41 void MapSharedMemory() override; | 41 void MapSharedMemory() override; |
| 42 | 42 |
| 43 // Called whenever we receive notifications about pending data. | 43 // Called whenever we receive notifications about pending data. |
| 44 void Process(uint32_t pending_data) override; | 44 void Process(uint32_t pending_data) override; |
| 45 | 45 |
| 46 private: | 46 private: |
| 47 const double bytes_per_ms_; |
| 47 int current_segment_id_; | 48 int current_segment_id_; |
| 48 uint32_t last_buffer_id_; | 49 uint32_t last_buffer_id_; |
| 49 ScopedVector<media::AudioBus> audio_buses_; | 50 ScopedVector<media::AudioBus> audio_buses_; |
| 50 CaptureCallback* capture_callback_; | 51 CaptureCallback* capture_callback_; |
| 51 | 52 |
| 52 DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback); | 53 DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback); |
| 53 }; | 54 }; |
| 54 | 55 |
| 55 AudioInputDevice::AudioInputDevice( | 56 AudioInputDevice::AudioInputDevice( |
| 56 std::unique_ptr<AudioInputIPC> ipc, | 57 std::unique_ptr<AudioInputIPC> ipc, |
| (...skipping 30 matching lines...) Expand all Loading... |
| 87 DVLOG(1) << "Start()"; | 88 DVLOG(1) << "Start()"; |
| 88 task_runner()->PostTask(FROM_HERE, | 89 task_runner()->PostTask(FROM_HERE, |
| 89 base::Bind(&AudioInputDevice::StartUpOnIOThread, this)); | 90 base::Bind(&AudioInputDevice::StartUpOnIOThread, this)); |
| 90 } | 91 } |
| 91 | 92 |
| 92 void AudioInputDevice::Stop() { | 93 void AudioInputDevice::Stop() { |
| 93 DVLOG(1) << "Stop()"; | 94 DVLOG(1) << "Stop()"; |
| 94 | 95 |
| 95 { | 96 { |
| 96 base::AutoLock auto_lock(audio_thread_lock_); | 97 base::AutoLock auto_lock(audio_thread_lock_); |
| 97 audio_thread_.Stop(base::MessageLoop::current()); | 98 audio_thread_.reset(); |
| 98 stopping_hack_ = true; | 99 stopping_hack_ = true; |
| 99 } | 100 } |
| 100 | 101 |
| 101 task_runner()->PostTask(FROM_HERE, | 102 task_runner()->PostTask(FROM_HERE, |
| 102 base::Bind(&AudioInputDevice::ShutDownOnIOThread, this)); | 103 base::Bind(&AudioInputDevice::ShutDownOnIOThread, this)); |
| 103 } | 104 } |
| 104 | 105 |
| 105 void AudioInputDevice::SetVolume(double volume) { | 106 void AudioInputDevice::SetVolume(double volume) { |
| 106 if (volume < 0 || volume > 1.0) { | 107 if (volume < 0 || volume > 1.0) { |
| 107 DLOG(ERROR) << "Invalid volume value specified"; | 108 DLOG(ERROR) << "Invalid volume value specified"; |
| (...skipping 28 matching lines...) Expand all Loading... |
| 136 if (state_ != CREATING_STREAM) | 137 if (state_ != CREATING_STREAM) |
| 137 return; | 138 return; |
| 138 | 139 |
| 139 base::AutoLock auto_lock(audio_thread_lock_); | 140 base::AutoLock auto_lock(audio_thread_lock_); |
| 140 // TODO(miu): See TODO in OnStreamCreated method for AudioOutputDevice. | 141 // TODO(miu): See TODO in OnStreamCreated method for AudioOutputDevice. |
| 141 // Interface changes need to be made; likely, after AudioInputDevice is merged | 142 // Interface changes need to be made; likely, after AudioInputDevice is merged |
| 142 // into AudioOutputDevice (http://crbug.com/179597). | 143 // into AudioOutputDevice (http://crbug.com/179597). |
| 143 if (stopping_hack_) | 144 if (stopping_hack_) |
| 144 return; | 145 return; |
| 145 | 146 |
| 146 DCHECK(audio_thread_.IsStopped()); | 147 DCHECK(!audio_callback_); |
| 148 DCHECK(!audio_thread_); |
| 147 audio_callback_.reset(new AudioInputDevice::AudioThreadCallback( | 149 audio_callback_.reset(new AudioInputDevice::AudioThreadCallback( |
| 148 audio_parameters_, handle, length, total_segments, callback_)); | 150 audio_parameters_, handle, length, total_segments, callback_)); |
| 149 audio_thread_.Start( | 151 audio_thread_.reset(new AudioDeviceThread(audio_callback_.get(), |
| 150 audio_callback_.get(), socket_handle, "AudioInputDevice", true); | 152 socket_handle, "AudioInputDevice")); |
| 151 | 153 |
| 152 state_ = RECORDING; | 154 state_ = RECORDING; |
| 153 ipc_->RecordStream(); | 155 ipc_->RecordStream(); |
| 154 } | 156 } |
| 155 | 157 |
| 156 void AudioInputDevice::OnVolume(double volume) { | 158 void AudioInputDevice::OnVolume(double volume) { |
| 157 NOTIMPLEMENTED(); | 159 NOTIMPLEMENTED(); |
| 158 } | 160 } |
| 159 | 161 |
| 160 void AudioInputDevice::OnStateChanged( | 162 void AudioInputDevice::OnStateChanged( |
| (...skipping 14 matching lines...) Expand all Loading... |
| 175 NOTIMPLEMENTED(); | 177 NOTIMPLEMENTED(); |
| 176 break; | 178 break; |
| 177 case AUDIO_INPUT_IPC_DELEGATE_STATE_ERROR: | 179 case AUDIO_INPUT_IPC_DELEGATE_STATE_ERROR: |
| 178 DLOG(WARNING) << "AudioInputDevice::OnStateChanged(ERROR)"; | 180 DLOG(WARNING) << "AudioInputDevice::OnStateChanged(ERROR)"; |
| 179 // Don't dereference the callback object if the audio thread | 181 // Don't dereference the callback object if the audio thread |
| 180 // is stopped or stopping. That could mean that the callback | 182 // is stopped or stopping. That could mean that the callback |
| 181 // object has been deleted. | 183 // object has been deleted. |
| 182 // TODO(tommi): Add an explicit contract for clearing the callback | 184 // TODO(tommi): Add an explicit contract for clearing the callback |
| 183 // object. Possibly require calling Initialize again or provide | 185 // object. Possibly require calling Initialize again or provide |
| 184 // a callback object via Start() and clear it in Stop(). | 186 // a callback object via Start() and clear it in Stop(). |
| 185 if (!audio_thread_.IsStopped()) | 187 { |
| 186 callback_->OnCaptureError( | 188 base::AutoLock auto_lock_(audio_thread_lock_); |
| 187 "AudioInputDevice::OnStateChanged - audio thread still running"); | 189 if (audio_thread_) { |
| 190 callback_->OnCaptureError( |
| 191 "AudioInputDevice::OnStateChanged - audio thread still running"); |
| 192 } |
| 193 } |
| 188 break; | 194 break; |
| 189 default: | 195 default: |
| 190 NOTREACHED(); | 196 NOTREACHED(); |
| 191 break; | 197 break; |
| 192 } | 198 } |
| 193 } | 199 } |
| 194 | 200 |
| 195 void AudioInputDevice::OnIPCClosed() { | 201 void AudioInputDevice::OnIPCClosed() { |
| 196 DCHECK(task_runner()->BelongsToCurrentThread()); | 202 DCHECK(task_runner()->BelongsToCurrentThread()); |
| 197 state_ = IPC_CLOSED; | 203 state_ = IPC_CLOSED; |
| 198 ipc_.reset(); | 204 ipc_.reset(); |
| 199 } | 205 } |
| 200 | 206 |
| 201 AudioInputDevice::~AudioInputDevice() { | 207 AudioInputDevice::~AudioInputDevice() {} |
| 202 // TODO(henrika): The current design requires that the user calls | |
| 203 // Stop before deleting this class. | |
| 204 DCHECK(audio_thread_.IsStopped()); | |
| 205 } | |
| 206 | 208 |
| 207 void AudioInputDevice::StartUpOnIOThread() { | 209 void AudioInputDevice::StartUpOnIOThread() { |
| 208 DCHECK(task_runner()->BelongsToCurrentThread()); | 210 DCHECK(task_runner()->BelongsToCurrentThread()); |
| 209 | 211 |
| 210 // Make sure we don't call Start() more than once. | 212 // Make sure we don't call Start() more than once. |
| 211 if (state_ != IDLE) | 213 if (state_ != IDLE) |
| 212 return; | 214 return; |
| 213 | 215 |
| 214 if (session_id_ <= 0) { | 216 if (session_id_ <= 0) { |
| 215 DLOG(WARNING) << "Invalid session id for the input stream " << session_id_; | 217 DLOG(WARNING) << "Invalid session id for the input stream " << session_id_; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 234 // We can run into an issue where ShutDownOnIOThread is called right after | 236 // We can run into an issue where ShutDownOnIOThread is called right after |
| 235 // OnStreamCreated is called in cases where Start/Stop are called before we | 237 // OnStreamCreated is called in cases where Start/Stop are called before we |
| 236 // get the OnStreamCreated callback. To handle that corner case, we call | 238 // get the OnStreamCreated callback. To handle that corner case, we call |
| 237 // Stop(). In most cases, the thread will already be stopped. | 239 // Stop(). In most cases, the thread will already be stopped. |
| 238 // | 240 // |
| 239 // Another situation is when the IO thread goes away before Stop() is called | 241 // Another situation is when the IO thread goes away before Stop() is called |
| 240 // in which case, we cannot use the message loop to close the thread handle | 242 // in which case, we cannot use the message loop to close the thread handle |
| 241 // and can't not rely on the main thread existing either. | 243 // and can't not rely on the main thread existing either. |
| 242 base::AutoLock auto_lock_(audio_thread_lock_); | 244 base::AutoLock auto_lock_(audio_thread_lock_); |
| 243 base::ThreadRestrictions::ScopedAllowIO allow_io; | 245 base::ThreadRestrictions::ScopedAllowIO allow_io; |
| 244 audio_thread_.Stop(NULL); | 246 audio_thread_.reset(); |
| 245 audio_callback_.reset(); | 247 audio_callback_.reset(); |
| 246 stopping_hack_ = false; | 248 stopping_hack_ = false; |
| 247 } | 249 } |
| 248 | 250 |
| 249 void AudioInputDevice::SetVolumeOnIOThread(double volume) { | 251 void AudioInputDevice::SetVolumeOnIOThread(double volume) { |
| 250 DCHECK(task_runner()->BelongsToCurrentThread()); | 252 DCHECK(task_runner()->BelongsToCurrentThread()); |
| 251 if (state_ >= CREATING_STREAM) | 253 if (state_ >= CREATING_STREAM) |
| 252 ipc_->SetVolume(volume); | 254 ipc_->SetVolume(volume); |
| 253 } | 255 } |
| 254 | 256 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 270 ShutDownOnIOThread(); | 272 ShutDownOnIOThread(); |
| 271 } | 273 } |
| 272 | 274 |
| 273 // AudioInputDevice::AudioThreadCallback | 275 // AudioInputDevice::AudioThreadCallback |
| 274 AudioInputDevice::AudioThreadCallback::AudioThreadCallback( | 276 AudioInputDevice::AudioThreadCallback::AudioThreadCallback( |
| 275 const AudioParameters& audio_parameters, | 277 const AudioParameters& audio_parameters, |
| 276 base::SharedMemoryHandle memory, | 278 base::SharedMemoryHandle memory, |
| 277 int memory_length, | 279 int memory_length, |
| 278 int total_segments, | 280 int total_segments, |
| 279 CaptureCallback* capture_callback) | 281 CaptureCallback* capture_callback) |
| 280 : AudioDeviceThread::Callback(audio_parameters, memory, memory_length, | 282 : AudioDeviceThread::Callback(audio_parameters, |
| 283 memory, |
| 284 memory_length, |
| 281 total_segments), | 285 total_segments), |
| 286 bytes_per_ms_(static_cast<double>(audio_parameters.GetBytesPerSecond()) / |
| 287 base::Time::kMillisecondsPerSecond), |
| 282 current_segment_id_(0), | 288 current_segment_id_(0), |
| 283 last_buffer_id_(UINT32_MAX), | 289 last_buffer_id_(UINT32_MAX), |
| 284 capture_callback_(capture_callback) { | 290 capture_callback_(capture_callback) {} |
| 285 } | |
| 286 | 291 |
| 287 AudioInputDevice::AudioThreadCallback::~AudioThreadCallback() { | 292 AudioInputDevice::AudioThreadCallback::~AudioThreadCallback() { |
| 288 } | 293 } |
| 289 | 294 |
| 290 void AudioInputDevice::AudioThreadCallback::MapSharedMemory() { | 295 void AudioInputDevice::AudioThreadCallback::MapSharedMemory() { |
| 291 shared_memory_.Map(memory_length_); | 296 shared_memory_.Map(memory_length_); |
| 292 | 297 |
| 293 // Create vector of audio buses by wrapping existing blocks of memory. | 298 // Create vector of audio buses by wrapping existing blocks of memory. |
| 294 uint8_t* ptr = static_cast<uint8_t*>(shared_memory_.memory()); | 299 uint8_t* ptr = static_cast<uint8_t*>(shared_memory_.memory()); |
| 295 for (int i = 0; i < total_segments_; ++i) { | 300 for (int i = 0; i < total_segments_; ++i) { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 340 capture_callback_->Capture( | 345 capture_callback_->Capture( |
| 341 audio_bus, | 346 audio_bus, |
| 342 buffer->params.hardware_delay_bytes / bytes_per_ms_, // Delay in ms | 347 buffer->params.hardware_delay_bytes / bytes_per_ms_, // Delay in ms |
| 343 buffer->params.volume, buffer->params.key_pressed); | 348 buffer->params.volume, buffer->params.key_pressed); |
| 344 | 349 |
| 345 if (++current_segment_id_ >= total_segments_) | 350 if (++current_segment_id_ >= total_segments_) |
| 346 current_segment_id_ = 0; | 351 current_segment_id_ = 0; |
| 347 } | 352 } |
| 348 | 353 |
| 349 } // namespace media | 354 } // namespace media |
| OLD | NEW |