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 |