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 "content/renderer/media/audio_input_device.h" | 5 #include "content/renderer/media/audio_input_device.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/message_loop.h" | 8 #include "base/message_loop.h" |
9 #include "base/threading/thread_restrictions.h" | 9 #include "base/threading/thread_restrictions.h" |
10 #include "base/time.h" | 10 #include "base/time.h" |
11 #include "content/common/child_process.h" | |
12 #include "content/common/media/audio_messages.h" | |
13 #include "content/common/view_messages.h" | |
14 #include "content/renderer/render_thread_impl.h" | |
15 #include "media/audio/audio_manager_base.h" | 11 #include "media/audio/audio_manager_base.h" |
16 #include "media/audio/audio_util.h" | 12 #include "media/audio/audio_util.h" |
17 | 13 |
18 // Takes care of invoking the capture callback on the audio thread. | 14 // Takes care of invoking the capture callback on the audio thread. |
19 // An instance of this class is created for each capture stream in | 15 // An instance of this class is created for each capture stream in |
20 // OnLowLatencyCreated(). | 16 // OnLowLatencyCreated(). |
21 class AudioInputDevice::AudioThreadCallback | 17 class AudioInputDevice::AudioThreadCallback |
22 : public AudioDeviceThread::Callback { | 18 : public AudioDeviceThread::Callback { |
23 public: | 19 public: |
24 AudioThreadCallback(const media::AudioParameters& audio_parameters, | 20 AudioThreadCallback(const media::AudioParameters& audio_parameters, |
25 base::SharedMemoryHandle memory, | 21 base::SharedMemoryHandle memory, |
26 int memory_length, | 22 int memory_length, |
27 CaptureCallback* capture_callback); | 23 CaptureCallback* capture_callback); |
28 virtual ~AudioThreadCallback(); | 24 virtual ~AudioThreadCallback(); |
29 | 25 |
30 virtual void MapSharedMemory() OVERRIDE; | 26 virtual void MapSharedMemory() OVERRIDE; |
31 | 27 |
32 // Called whenever we receive notifications about pending data. | 28 // Called whenever we receive notifications about pending data. |
33 virtual void Process(int pending_data) OVERRIDE; | 29 virtual void Process(int pending_data) OVERRIDE; |
34 | 30 |
35 private: | 31 private: |
36 CaptureCallback* capture_callback_; | 32 CaptureCallback* capture_callback_; |
37 DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback); | 33 DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback); |
38 }; | 34 }; |
39 | 35 |
40 AudioInputDevice::AudioInputDevice(const media::AudioParameters& params, | 36 AudioInputDevice::AudioInputDevice( |
41 CaptureCallback* callback, | 37 media::AudioInputIPC* ipc, |
42 CaptureEventHandler* event_handler) | 38 const scoped_refptr<base::MessageLoopProxy>& io_loop) |
43 : ScopedLoopObserver( | 39 : ScopedLoopObserver(io_loop), |
44 ChildProcess::current()->io_message_loop()->message_loop_proxy()), | 40 callback_(NULL), |
45 audio_parameters_(params), | 41 event_handler_(NULL), |
46 callback_(callback), | 42 ipc_(ipc), |
47 event_handler_(event_handler), | |
48 volume_(1.0), | |
49 stream_id_(0), | 43 stream_id_(0), |
50 session_id_(0), | 44 session_id_(0), |
51 pending_device_ready_(false), | 45 pending_device_ready_(false), |
52 agc_is_enabled_(false) { | 46 agc_is_enabled_(false) { |
53 filter_ = RenderThreadImpl::current()->audio_input_message_filter(); | 47 CHECK(ipc_); |
| 48 } |
| 49 |
| 50 void AudioInputDevice::Initialize(const media::AudioParameters& params, |
| 51 CaptureCallback* callback, |
| 52 CaptureEventHandler* event_handler) { |
| 53 DCHECK(!callback_); |
| 54 DCHECK(!event_handler_); |
| 55 audio_parameters_ = params; |
| 56 callback_ = callback; |
| 57 event_handler_ = event_handler; |
54 } | 58 } |
55 | 59 |
56 void AudioInputDevice::SetDevice(int session_id) { | 60 void AudioInputDevice::SetDevice(int session_id) { |
57 DVLOG(1) << "SetDevice (session_id=" << session_id << ")"; | 61 DVLOG(1) << "SetDevice (session_id=" << session_id << ")"; |
58 message_loop()->PostTask(FROM_HERE, | 62 message_loop()->PostTask(FROM_HERE, |
59 base::Bind(&AudioInputDevice::SetSessionIdOnIOThread, this, session_id)); | 63 base::Bind(&AudioInputDevice::SetSessionIdOnIOThread, this, session_id)); |
60 } | 64 } |
61 | 65 |
62 void AudioInputDevice::Start() { | 66 void AudioInputDevice::Start() { |
63 DVLOG(1) << "Start()"; | 67 DVLOG(1) << "Start()"; |
(...skipping 26 matching lines...) Expand all Loading... |
90 void AudioInputDevice::SetAutomaticGainControl(bool enabled) { | 94 void AudioInputDevice::SetAutomaticGainControl(bool enabled) { |
91 DVLOG(1) << "SetAutomaticGainControl(enabled=" << enabled << ")"; | 95 DVLOG(1) << "SetAutomaticGainControl(enabled=" << enabled << ")"; |
92 message_loop()->PostTask(FROM_HERE, | 96 message_loop()->PostTask(FROM_HERE, |
93 base::Bind(&AudioInputDevice::SetAutomaticGainControlOnIOThread, | 97 base::Bind(&AudioInputDevice::SetAutomaticGainControlOnIOThread, |
94 this, enabled)); | 98 this, enabled)); |
95 } | 99 } |
96 | 100 |
97 void AudioInputDevice::OnStreamCreated( | 101 void AudioInputDevice::OnStreamCreated( |
98 base::SharedMemoryHandle handle, | 102 base::SharedMemoryHandle handle, |
99 base::SyncSocket::Handle socket_handle, | 103 base::SyncSocket::Handle socket_handle, |
100 uint32 length) { | 104 int length) { |
101 DCHECK(message_loop()->BelongsToCurrentThread()); | 105 DCHECK(message_loop()->BelongsToCurrentThread()); |
102 #if defined(OS_WIN) | 106 #if defined(OS_WIN) |
103 DCHECK(handle); | 107 DCHECK(handle); |
104 DCHECK(socket_handle); | 108 DCHECK(socket_handle); |
105 #else | 109 #else |
106 DCHECK_GE(handle.fd, 0); | 110 DCHECK_GE(handle.fd, 0); |
107 DCHECK_GE(socket_handle, 0); | 111 DCHECK_GE(socket_handle, 0); |
108 #endif | 112 #endif |
109 DCHECK(length); | 113 DCHECK(length); |
110 DVLOG(1) << "OnStreamCreated (stream_id=" << stream_id_ << ")"; | 114 DVLOG(1) << "OnStreamCreated (stream_id=" << stream_id_ << ")"; |
111 | 115 |
| 116 // We should only get this callback if stream_id_ is valid. If it is not, |
| 117 // the IPC layer should have closed the shared memory and socket handles |
| 118 // for us and not invoked the callback. The basic assertion is that when |
| 119 // stream_id_ is 0 the AudioInputDevice instance is not registered as a |
| 120 // delegate and hence it should not receive callbacks. |
| 121 DCHECK(stream_id_); |
| 122 |
112 base::AutoLock auto_lock(audio_thread_lock_); | 123 base::AutoLock auto_lock(audio_thread_lock_); |
113 | 124 |
114 // Takes care of the case when Stop() is called before OnStreamCreated(). | |
115 if (!stream_id_) { | |
116 base::SharedMemory::CloseHandle(handle); | |
117 // Close the socket handler. | |
118 base::SyncSocket socket(socket_handle); | |
119 return; | |
120 } | |
121 | |
122 DCHECK(audio_thread_.IsStopped()); | 125 DCHECK(audio_thread_.IsStopped()); |
123 audio_callback_.reset( | 126 audio_callback_.reset( |
124 new AudioInputDevice::AudioThreadCallback(audio_parameters_, handle, | 127 new AudioInputDevice::AudioThreadCallback(audio_parameters_, handle, |
125 length, callback_)); | 128 length, callback_)); |
126 audio_thread_.Start(audio_callback_.get(), socket_handle, "AudioInputDevice"); | 129 audio_thread_.Start(audio_callback_.get(), socket_handle, "AudioInputDevice"); |
127 | 130 |
128 MessageLoop::current()->PostTask(FROM_HERE, | 131 MessageLoop::current()->PostTask(FROM_HERE, |
129 base::Bind(&AudioInputDevice::StartOnIOThread, this)); | 132 base::Bind(&AudioInputDevice::StartOnIOThread, this)); |
130 } | 133 } |
131 | 134 |
132 void AudioInputDevice::OnVolume(double volume) { | 135 void AudioInputDevice::OnVolume(double volume) { |
133 NOTIMPLEMENTED(); | 136 NOTIMPLEMENTED(); |
134 } | 137 } |
135 | 138 |
136 void AudioInputDevice::OnStateChanged(AudioStreamState state) { | 139 void AudioInputDevice::OnStateChanged( |
| 140 media::AudioInputIPCDelegate::State state) { |
137 DCHECK(message_loop()->BelongsToCurrentThread()); | 141 DCHECK(message_loop()->BelongsToCurrentThread()); |
138 | 142 |
139 // Do nothing if the stream has been closed. | 143 // Do nothing if the stream has been closed. |
140 if (!stream_id_) | 144 if (!stream_id_) |
141 return; | 145 return; |
142 | 146 |
143 switch (state) { | 147 switch (state) { |
144 // TODO(xians): This should really be kAudioStreamStopped since the stream | 148 case media::AudioInputIPCDelegate::kStopped: |
145 // has been closed at this point. | |
146 case kAudioStreamPaused: | |
147 // TODO(xians): Should we just call ShutDownOnIOThread here instead? | 149 // TODO(xians): Should we just call ShutDownOnIOThread here instead? |
148 filter_->RemoveDelegate(stream_id_); | 150 ipc_->RemoveDelegate(stream_id_); |
149 | 151 |
150 audio_thread_.Stop(MessageLoop::current()); | 152 audio_thread_.Stop(MessageLoop::current()); |
151 audio_callback_.reset(); | 153 audio_callback_.reset(); |
152 | 154 |
153 if (event_handler_) | 155 if (event_handler_) |
154 event_handler_->OnDeviceStopped(); | 156 event_handler_->OnDeviceStopped(); |
155 | 157 |
156 stream_id_ = 0; | 158 stream_id_ = 0; |
157 pending_device_ready_ = false; | 159 pending_device_ready_ = false; |
158 break; | 160 break; |
159 case kAudioStreamPlaying: | 161 case media::AudioInputIPCDelegate::kRecording: |
160 NOTIMPLEMENTED(); | 162 NOTIMPLEMENTED(); |
161 break; | 163 break; |
162 case kAudioStreamError: | 164 case media::AudioInputIPCDelegate::kError: |
163 DLOG(WARNING) << "AudioInputDevice::OnStateChanged(kError)"; | 165 DLOG(WARNING) << "AudioInputDevice::OnStateChanged(kError)"; |
164 // Don't dereference the callback object if the audio thread | 166 // Don't dereference the callback object if the audio thread |
165 // is stopped or stopping. That could mean that the callback | 167 // is stopped or stopping. That could mean that the callback |
166 // object has been deleted. | 168 // object has been deleted. |
167 // TODO(tommi): Add an explicit contract for clearing the callback | 169 // TODO(tommi): Add an explicit contract for clearing the callback |
168 // object. Possibly require calling Initialize again or provide | 170 // object. Possibly require calling Initialize again or provide |
169 // a callback object via Start() and clear it in Stop(). | 171 // a callback object via Start() and clear it in Stop(). |
170 if (!audio_thread_.IsStopped()) | 172 if (!audio_thread_.IsStopped()) |
171 callback_->OnCaptureError(); | 173 callback_->OnCaptureError(); |
172 break; | 174 break; |
173 default: | 175 default: |
174 NOTREACHED(); | 176 NOTREACHED(); |
175 break; | 177 break; |
176 } | 178 } |
177 } | 179 } |
178 | 180 |
179 void AudioInputDevice::OnDeviceReady(const std::string& device_id) { | 181 void AudioInputDevice::OnDeviceReady(const std::string& device_id) { |
180 DCHECK(message_loop()->BelongsToCurrentThread()); | 182 DCHECK(message_loop()->BelongsToCurrentThread()); |
181 DVLOG(1) << "OnDeviceReady (device_id=" << device_id << ")"; | 183 DVLOG(1) << "OnDeviceReady (device_id=" << device_id << ")"; |
182 | 184 |
183 // Takes care of the case when Stop() is called before OnDeviceReady(). | 185 // Takes care of the case when Stop() is called before OnDeviceReady(). |
184 if (!pending_device_ready_) | 186 if (!pending_device_ready_) |
185 return; | 187 return; |
186 | 188 |
187 // If AudioInputDeviceManager returns an empty string, it means no device | 189 // If AudioInputDeviceManager returns an empty string, it means no device |
188 // is ready for start. | 190 // is ready for start. |
189 if (device_id.empty()) { | 191 if (device_id.empty()) { |
190 filter_->RemoveDelegate(stream_id_); | 192 ipc_->RemoveDelegate(stream_id_); |
191 stream_id_ = 0; | 193 stream_id_ = 0; |
192 } else { | 194 } else { |
193 Send(new AudioInputHostMsg_CreateStream(stream_id_, audio_parameters_, | 195 ipc_->CreateStream(stream_id_, audio_parameters_, device_id, |
194 device_id, agc_is_enabled_)); | 196 agc_is_enabled_); |
195 } | 197 } |
196 | 198 |
197 pending_device_ready_ = false; | 199 pending_device_ready_ = false; |
198 // Notify the client that the device has been started. | 200 // Notify the client that the device has been started. |
199 if (event_handler_) | 201 if (event_handler_) |
200 event_handler_->OnDeviceStarted(device_id); | 202 event_handler_->OnDeviceStarted(device_id); |
201 } | 203 } |
202 | 204 |
| 205 void AudioInputDevice::OnIPCClosed() { |
| 206 ipc_ = NULL; |
| 207 } |
| 208 |
203 AudioInputDevice::~AudioInputDevice() { | 209 AudioInputDevice::~AudioInputDevice() { |
204 // TODO(henrika): The current design requires that the user calls | 210 // TODO(henrika): The current design requires that the user calls |
205 // Stop before deleting this class. | 211 // Stop before deleting this class. |
206 CHECK_EQ(0, stream_id_); | 212 CHECK_EQ(0, stream_id_); |
207 } | 213 } |
208 | 214 |
209 void AudioInputDevice::InitializeOnIOThread() { | 215 void AudioInputDevice::InitializeOnIOThread() { |
210 DCHECK(message_loop()->BelongsToCurrentThread()); | 216 DCHECK(message_loop()->BelongsToCurrentThread()); |
211 // Make sure we don't call Start() more than once. | 217 // Make sure we don't call Start() more than once. |
212 DCHECK_EQ(0, stream_id_); | 218 DCHECK_EQ(0, stream_id_); |
213 if (stream_id_) | 219 if (stream_id_) |
214 return; | 220 return; |
215 | 221 |
216 stream_id_ = filter_->AddDelegate(this); | 222 stream_id_ = ipc_->AddDelegate(this); |
217 // If |session_id_| is not specified, it will directly create the stream; | 223 // If |session_id_| is not specified, it will directly create the stream; |
218 // otherwise it will send a AudioInputHostMsg_StartDevice msg to the browser | 224 // otherwise it will send a AudioInputHostMsg_StartDevice msg to the browser |
219 // and create the stream when getting a OnDeviceReady() callback. | 225 // and create the stream when getting a OnDeviceReady() callback. |
220 if (!session_id_) { | 226 if (!session_id_) { |
221 Send(new AudioInputHostMsg_CreateStream( | 227 ipc_->CreateStream(stream_id_, audio_parameters_, |
222 stream_id_, audio_parameters_, | 228 media::AudioManagerBase::kDefaultDeviceId, agc_is_enabled_); |
223 media::AudioManagerBase::kDefaultDeviceId, | |
224 agc_is_enabled_)); | |
225 } else { | 229 } else { |
226 Send(new AudioInputHostMsg_StartDevice(stream_id_, session_id_)); | 230 ipc_->StartDevice(stream_id_, session_id_); |
227 pending_device_ready_ = true; | 231 pending_device_ready_ = true; |
228 } | 232 } |
229 } | 233 } |
230 | 234 |
231 void AudioInputDevice::SetSessionIdOnIOThread(int session_id) { | 235 void AudioInputDevice::SetSessionIdOnIOThread(int session_id) { |
232 DCHECK(message_loop()->BelongsToCurrentThread()); | 236 DCHECK(message_loop()->BelongsToCurrentThread()); |
233 session_id_ = session_id; | 237 session_id_ = session_id; |
234 } | 238 } |
235 | 239 |
236 void AudioInputDevice::StartOnIOThread() { | 240 void AudioInputDevice::StartOnIOThread() { |
237 DCHECK(message_loop()->BelongsToCurrentThread()); | 241 DCHECK(message_loop()->BelongsToCurrentThread()); |
238 if (stream_id_) | 242 if (stream_id_) |
239 Send(new AudioInputHostMsg_RecordStream(stream_id_)); | 243 ipc_->RecordStream(stream_id_); |
240 } | 244 } |
241 | 245 |
242 void AudioInputDevice::ShutDownOnIOThread() { | 246 void AudioInputDevice::ShutDownOnIOThread() { |
243 DCHECK(message_loop()->BelongsToCurrentThread()); | 247 DCHECK(message_loop()->BelongsToCurrentThread()); |
244 // NOTE: |completion| may be NULL. | 248 // NOTE: |completion| may be NULL. |
245 // Make sure we don't call shutdown more than once. | 249 // Make sure we don't call shutdown more than once. |
246 if (stream_id_) { | 250 if (stream_id_) { |
247 filter_->RemoveDelegate(stream_id_); | 251 ipc_->CloseStream(stream_id_); |
248 Send(new AudioInputHostMsg_CloseStream(stream_id_)); | 252 ipc_->RemoveDelegate(stream_id_); |
249 | 253 |
250 stream_id_ = 0; | 254 stream_id_ = 0; |
251 session_id_ = 0; | 255 session_id_ = 0; |
252 pending_device_ready_ = false; | 256 pending_device_ready_ = false; |
253 agc_is_enabled_ = false; | 257 agc_is_enabled_ = false; |
254 } | 258 } |
255 | 259 |
256 // We can run into an issue where ShutDownOnIOThread is called right after | 260 // We can run into an issue where ShutDownOnIOThread is called right after |
257 // OnStreamCreated is called in cases where Start/Stop are called before we | 261 // OnStreamCreated is called in cases where Start/Stop are called before we |
258 // get the OnStreamCreated callback. To handle that corner case, we call | 262 // get the OnStreamCreated callback. To handle that corner case, we call |
259 // Stop(). In most cases, the thread will already be stopped. | 263 // Stop(). In most cases, the thread will already be stopped. |
260 // Another situation is when the IO thread goes away before Stop() is called | 264 // Another situation is when the IO thread goes away before Stop() is called |
261 // in which case, we cannot use the message loop to close the thread handle | 265 // in which case, we cannot use the message loop to close the thread handle |
262 // and can't not rely on the main thread existing either. | 266 // and can't not rely on the main thread existing either. |
263 base::ThreadRestrictions::ScopedAllowIO allow_io; | 267 base::ThreadRestrictions::ScopedAllowIO allow_io; |
264 audio_thread_.Stop(NULL); | 268 audio_thread_.Stop(NULL); |
265 audio_callback_.reset(); | 269 audio_callback_.reset(); |
266 } | 270 } |
267 | 271 |
268 void AudioInputDevice::SetVolumeOnIOThread(double volume) { | 272 void AudioInputDevice::SetVolumeOnIOThread(double volume) { |
269 DCHECK(message_loop()->BelongsToCurrentThread()); | 273 DCHECK(message_loop()->BelongsToCurrentThread()); |
270 if (stream_id_) | 274 if (stream_id_) |
271 Send(new AudioInputHostMsg_SetVolume(stream_id_, volume)); | 275 ipc_->SetVolume(stream_id_, volume); |
272 } | 276 } |
273 | 277 |
274 void AudioInputDevice::SetAutomaticGainControlOnIOThread(bool enabled) { | 278 void AudioInputDevice::SetAutomaticGainControlOnIOThread(bool enabled) { |
275 DCHECK(message_loop()->BelongsToCurrentThread()); | 279 DCHECK(message_loop()->BelongsToCurrentThread()); |
276 DCHECK_EQ(0, stream_id_) << | 280 DCHECK_EQ(0, stream_id_) << |
277 "The AGC state can not be modified while capturing is active."; | 281 "The AGC state can not be modified while capturing is active."; |
278 if (stream_id_) | 282 if (stream_id_) |
279 return; | 283 return; |
280 | 284 |
281 // We simply store the new AGC setting here. This value will be used when | 285 // We simply store the new AGC setting here. This value will be used when |
282 // a new stream is initialized and by GetAutomaticGainControl(). | 286 // a new stream is initialized and by GetAutomaticGainControl(). |
283 agc_is_enabled_ = enabled; | 287 agc_is_enabled_ = enabled; |
284 } | 288 } |
285 | 289 |
286 void AudioInputDevice::Send(IPC::Message* message) { | |
287 filter_->Send(message); | |
288 } | |
289 | |
290 void AudioInputDevice::WillDestroyCurrentMessageLoop() { | 290 void AudioInputDevice::WillDestroyCurrentMessageLoop() { |
291 LOG(ERROR) << "IO loop going away before the input device has been stopped"; | 291 LOG(ERROR) << "IO loop going away before the input device has been stopped"; |
292 ShutDownOnIOThread(); | 292 ShutDownOnIOThread(); |
293 } | 293 } |
294 | 294 |
295 // AudioInputDevice::AudioThreadCallback | 295 // AudioInputDevice::AudioThreadCallback |
296 AudioInputDevice::AudioThreadCallback::AudioThreadCallback( | 296 AudioInputDevice::AudioThreadCallback::AudioThreadCallback( |
297 const media::AudioParameters& audio_parameters, | 297 const media::AudioParameters& audio_parameters, |
298 base::SharedMemoryHandle memory, | 298 base::SharedMemoryHandle memory, |
299 int memory_length, | 299 int memory_length, |
300 CaptureCallback* capture_callback) | 300 CaptureCallback* capture_callback) |
301 : AudioDeviceThread::Callback(audio_parameters, memory, memory_length), | 301 : AudioDeviceThread::Callback(audio_parameters, memory, memory_length), |
302 capture_callback_(capture_callback) { | 302 capture_callback_(capture_callback) { |
303 } | 303 } |
304 | 304 |
305 AudioInputDevice::AudioThreadCallback::~AudioThreadCallback() { | 305 AudioInputDevice::AudioThreadCallback::~AudioThreadCallback() { |
306 } | 306 } |
307 | 307 |
308 void AudioInputDevice::AudioThreadCallback::MapSharedMemory() { | 308 void AudioInputDevice::AudioThreadCallback::MapSharedMemory() { |
309 shared_memory_.Map(memory_length_); | 309 shared_memory_.Map(memory_length_); |
310 } | 310 } |
311 | 311 |
312 void AudioInputDevice::AudioThreadCallback::Process(int pending_data) { | 312 void AudioInputDevice::AudioThreadCallback::Process(int pending_data) { |
313 // The shared memory represents parameters, size of the data buffer and the | 313 // The shared memory represents parameters, size of the data buffer and the |
314 // actual data buffer containing audio data. Map the memory into this | 314 // actual data buffer containing audio data. Map the memory into this |
315 // structure and parse out parameters and the data area. | 315 // structure and parse out parameters and the data area. |
316 media::AudioInputBuffer* buffer = | 316 media::AudioInputBuffer* buffer = |
317 reinterpret_cast<media::AudioInputBuffer*>(shared_memory_.memory()); | 317 reinterpret_cast<media::AudioInputBuffer*>(shared_memory_.memory()); |
318 uint32 size = buffer->params.size; | 318 DCHECK_EQ(buffer->params.size, |
319 DCHECK_EQ(size, memory_length_ - sizeof(media::AudioInputBufferParameters)); | 319 memory_length_ - sizeof(media::AudioInputBufferParameters)); |
320 double volume = buffer->params.volume; | 320 double volume = buffer->params.volume; |
321 | 321 |
322 int audio_delay_milliseconds = pending_data / bytes_per_ms_; | 322 int audio_delay_milliseconds = pending_data / bytes_per_ms_; |
323 int16* memory = reinterpret_cast<int16*>(&buffer->audio[0]); | 323 int16* memory = reinterpret_cast<int16*>(&buffer->audio[0]); |
324 const size_t number_of_frames = audio_parameters_.frames_per_buffer(); | 324 const size_t number_of_frames = audio_parameters_.frames_per_buffer(); |
325 const int bytes_per_sample = sizeof(memory[0]); | 325 const int bytes_per_sample = sizeof(memory[0]); |
326 | 326 |
327 // Deinterleave each channel and convert to 32-bit floating-point | 327 // Deinterleave each channel and convert to 32-bit floating-point |
328 // with nominal range -1.0 -> +1.0. | 328 // with nominal range -1.0 -> +1.0. |
329 for (int channel_index = 0; channel_index < audio_parameters_.channels(); | 329 for (int channel_index = 0; channel_index < audio_parameters_.channels(); |
330 ++channel_index) { | 330 ++channel_index) { |
331 media::DeinterleaveAudioChannel(memory, | 331 media::DeinterleaveAudioChannel(memory, |
332 audio_data_[channel_index], | 332 audio_data_[channel_index], |
333 audio_parameters_.channels(), | 333 audio_parameters_.channels(), |
334 channel_index, | 334 channel_index, |
335 bytes_per_sample, | 335 bytes_per_sample, |
336 number_of_frames); | 336 number_of_frames); |
337 } | 337 } |
338 | 338 |
339 // Deliver captured data to the client in floating point format | 339 // Deliver captured data to the client in floating point format |
340 // and update the audio-delay measurement. | 340 // and update the audio-delay measurement. |
341 capture_callback_->Capture(audio_data_, number_of_frames, | 341 capture_callback_->Capture(audio_data_, number_of_frames, |
342 audio_delay_milliseconds, volume); | 342 audio_delay_milliseconds, volume); |
343 } | 343 } |
OLD | NEW |