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

Side by Side Diff: media/audio/mac/audio_low_latency_input_mac.cc

Issue 9418042: Adding microphone volume support to chrome. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: small changes on alsa code Created 8 years, 10 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 | Annotate | Revision Log
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 "media/audio/mac/audio_low_latency_input_mac.h" 5 #include "media/audio/mac/audio_low_latency_input_mac.h"
6 6
7 #include <CoreServices/CoreServices.h> 7 #include <CoreServices/CoreServices.h>
8 8
9 #include "base/basictypes.h" 9 #include "base/basictypes.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 19 matching lines...) Expand all
30 // for more details and background regarding this implementation. 30 // for more details and background regarding this implementation.
31 31
32 AUAudioInputStream::AUAudioInputStream( 32 AUAudioInputStream::AUAudioInputStream(
33 AudioManagerMac* manager, const AudioParameters& params, 33 AudioManagerMac* manager, const AudioParameters& params,
34 AudioDeviceID audio_device_id) 34 AudioDeviceID audio_device_id)
35 : manager_(manager), 35 : manager_(manager),
36 sink_(NULL), 36 sink_(NULL),
37 audio_unit_(0), 37 audio_unit_(0),
38 input_device_id_(audio_device_id), 38 input_device_id_(audio_device_id),
39 started_(false), 39 started_(false),
40 hardware_latency_frames_(0) { 40 hardware_latency_frames_(0),
41 number_of_channels_in_frame_(0) {
41 DCHECK(manager_); 42 DCHECK(manager_);
42 43
43 // Set up the desired (output) format specified by the client. 44 // Set up the desired (output) format specified by the client.
44 format_.mSampleRate = params.sample_rate; 45 format_.mSampleRate = params.sample_rate;
45 format_.mFormatID = kAudioFormatLinearPCM; 46 format_.mFormatID = kAudioFormatLinearPCM;
46 format_.mFormatFlags = kLinearPCMFormatFlagIsPacked | 47 format_.mFormatFlags = kLinearPCMFormatFlagIsPacked |
47 kLinearPCMFormatFlagIsSignedInteger; 48 kLinearPCMFormatFlagIsSignedInteger;
48 format_.mBitsPerChannel = params.bits_per_sample; 49 format_.mBitsPerChannel = params.bits_per_sample;
49 format_.mChannelsPerFrame = params.channels; 50 format_.mChannelsPerFrame = params.channels;
50 format_.mFramesPerPacket = 1; // uncompressed audio 51 format_.mFramesPerPacket = 1; // uncompressed audio
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
204 // it can produce in response to a single render call. 205 // it can produce in response to a single render call.
205 result = AudioUnitInitialize(audio_unit_); 206 result = AudioUnitInitialize(audio_unit_);
206 if (result) { 207 if (result) {
207 HandleError(result); 208 HandleError(result);
208 return false; 209 return false;
209 } 210 }
210 211
211 // The hardware latency is fixed and will not change during the call. 212 // The hardware latency is fixed and will not change during the call.
212 hardware_latency_frames_ = GetHardwareLatency(); 213 hardware_latency_frames_ = GetHardwareLatency();
213 214
215 number_of_channels_in_frame_ = GetNumberOfChannelsFromStream();
216
214 return true; 217 return true;
215 } 218 }
216 219
217 void AUAudioInputStream::Start(AudioInputCallback* callback) { 220 void AUAudioInputStream::Start(AudioInputCallback* callback) {
218 DCHECK(callback); 221 DCHECK(callback);
219 DLOG_IF(ERROR, !audio_unit_) << "Open() has not been called successfully"; 222 DLOG_IF(ERROR, !audio_unit_) << "Open() has not been called successfully";
220 if (started_ || !audio_unit_) 223 if (started_ || !audio_unit_)
221 return; 224 return;
222 sink_ = callback; 225 sink_ = callback;
223 OSStatus result = AudioOutputUnitStart(audio_unit_); 226 OSStatus result = AudioOutputUnitStart(audio_unit_);
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
256 if (sink_) { 259 if (sink_) {
257 sink_->OnClose(this); 260 sink_->OnClose(this);
258 sink_ = NULL; 261 sink_ = NULL;
259 } 262 }
260 263
261 // Inform the audio manager that we have been closed. This can cause our 264 // Inform the audio manager that we have been closed. This can cause our
262 // destruction. 265 // destruction.
263 manager_->ReleaseInputStream(this); 266 manager_->ReleaseInputStream(this);
264 } 267 }
265 268
269 double AUAudioInputStream::GetMaxVolume() {
270 // Verify that we have a valid device.
271 if (input_device_id_ == kAudioObjectUnknown)
272 return 0.0;
273
274 for (UInt32 i = 0; i <= number_of_channels_in_frame_; i++) {
275 // If the volume is settable, the valid volume range is [0.0, 1.0].
henrika (OOO until Aug 14) 2012/02/23 11:50:41 How do you know that this is a true statement?
no longer working on chromium 2012/02/24 09:27:48 From Apple document: kAudioDevicePropertyVolumeSca
276 if (IsVolumeSettableOnChannel(i))
277 return 1.0;
278 }
279
280 // Volume control is not available for the audio stream.
281 return 0.0;
282 }
283
284 void AUAudioInputStream::SetVolume(double volume) {
285 DCHECK(volume <= 1.0 && volume >= 0.0);
286
287 // Verify that we have a valid device.
288 if (input_device_id_ == kAudioObjectUnknown)
289 return;
290
291 Float32 volume_float32 = static_cast<Float32> (volume);
292 AudioObjectPropertyAddress property_address = {
293 kAudioDevicePropertyVolumeScalar,
294 kAudioDevicePropertyScopeInput,
295 kAudioObjectPropertyElementMaster
296 };
297
298 // Try to set the volume for master volume channel.
299 if (IsVolumeSettableOnChannel(kAudioObjectPropertyElementMaster)) {
300 UInt32 size = sizeof(volume_float32);
301 OSStatus result = AudioObjectSetPropertyData(input_device_id_,
302 &property_address,
303 0,
304 NULL,
305 size,
306 &volume_float32);
307 DLOG_IF(WARNING, result != noErr) << "SetVolume failed to set volume to "
308 << volume_float32;
309 return;
310 }
311
312 // There is no master volume control, try to set volume for each channel.
313 int success_on_channel = 0;
314 for (UInt32 i = 1; i <= number_of_channels_in_frame_; i++) {
315 property_address.mElement = i;
316 if (IsVolumeSettableOnChannel(i)) {
317 UInt32 size = sizeof(volume_float32);
318 OSStatus result = AudioObjectSetPropertyData(input_device_id_,
319 &property_address,
320 0,
321 NULL,
322 size,
323 &volume_float32);
324 if (result == noErr)
325 ++success_on_channel;
326 }
327 }
328
329 DLOG_IF(WARNING, success_on_channel == 0)
330 << "SetVolume failed to set volume to " << volume_float32;
331 }
332
333 double AUAudioInputStream::GetVolume() {
334 // Verify that we have a valid device.
335 if (input_device_id_ == kAudioObjectUnknown)
336 return 0.0;
337
338 AudioObjectPropertyAddress property_address = {
339 kAudioDevicePropertyVolumeScalar,
340 kAudioDevicePropertyScopeInput,
341 kAudioObjectPropertyElementMaster
342 };
343
344 if (AudioObjectHasProperty(input_device_id_, &property_address)) {
345 // The device supports master volume control, get the volume from the
346 // master channel.
347 Float32 volume_float32 = 0.0;
348 UInt32 size = sizeof(volume_float32);
349 OSStatus result = AudioObjectGetPropertyData(input_device_id_,
350 &property_address,
351 0,
352 NULL,
353 &size,
354 &volume_float32);
355 if (result == noErr)
356 return static_cast<double> (volume_float32);
357 } else {
358 // There is no master volume control, try to get the average volume of
359 // all the channels.
360 Float32 volume_float32 = 0.0;
361 int success_on_channel = 0;
362 for (UInt32 i = 1; i <= number_of_channels_in_frame_; i++) {
363 property_address.mElement = i;
364 if (AudioObjectHasProperty(input_device_id_, &property_address)) {
365 Float32 channel_volume = 0;
366 UInt32 size = sizeof(channel_volume);
367 OSStatus result = AudioObjectGetPropertyData(input_device_id_,
368 &property_address,
369 0,
370 NULL,
371 &size,
372 &channel_volume);
373 if (result == noErr) {
374 volume_float32 += channel_volume;
375 ++success_on_channel;
376 }
377 }
378 }
379
380 // Get the average volume of the channels.
381 if (success_on_channel != 0)
382 return static_cast<double> (volume_float32 / success_on_channel);
383 }
384
385 DLOG(WARNING) << "AudioObjectGetPropertyData failed not get volume";
henrika (OOO until Aug 14) 2012/02/23 11:50:41 Clean up the comment. "failed not get volume" ...
no longer working on chromium 2012/02/24 09:27:48 Done.
386 return 0.0;
387 }
388
266 // AUHAL AudioDeviceOutput unit callback 389 // AUHAL AudioDeviceOutput unit callback
267 OSStatus AUAudioInputStream::InputProc(void* user_data, 390 OSStatus AUAudioInputStream::InputProc(void* user_data,
268 AudioUnitRenderActionFlags* flags, 391 AudioUnitRenderActionFlags* flags,
269 const AudioTimeStamp* time_stamp, 392 const AudioTimeStamp* time_stamp,
270 UInt32 bus_number, 393 UInt32 bus_number,
271 UInt32 number_of_frames, 394 UInt32 number_of_frames,
272 AudioBufferList* io_data) { 395 AudioBufferList* io_data) {
273 // Verify that the correct bus is used (Input bus/Element 1) 396 // Verify that the correct bus is used (Input bus/Element 1)
274 DCHECK_EQ(bus_number, static_cast<UInt32>(1)); 397 DCHECK_EQ(bus_number, static_cast<UInt32>(1));
275 AUAudioInputStream* audio_input = 398 AUAudioInputStream* audio_input =
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
381 UInt32 device_latency_frames = 0; 504 UInt32 device_latency_frames = 0;
382 size = sizeof(device_latency_frames); 505 size = sizeof(device_latency_frames);
383 result = AudioObjectGetPropertyData(input_device_id_, 506 result = AudioObjectGetPropertyData(input_device_id_,
384 &property_address, 507 &property_address,
385 0, 508 0,
386 NULL, 509 NULL,
387 &size, 510 &size,
388 &device_latency_frames); 511 &device_latency_frames);
389 DLOG_IF(WARNING, result != noErr) << "Could not get audio device latency."; 512 DLOG_IF(WARNING, result != noErr) << "Could not get audio device latency.";
390 513
514 // Get the stream latency.
henrika (OOO until Aug 14) 2012/02/23 11:50:41 I don't understand where this part comes from. Not
no longer working on chromium 2012/02/24 09:27:48 Sorry, merge error.
515 property_address.mSelector = kAudioDevicePropertyStreams;
516 UInt32 stream_latency_frames = 0;
517 size = 0;
518 result = AudioObjectGetPropertyDataSize(input_device_id_,
519 &property_address,
520 0,
521 NULL,
522 &size);
523 if (!result) {
524 scoped_ptr_malloc<AudioStreamID>
525 streams(reinterpret_cast<AudioStreamID*>(malloc(size)));
526 AudioStreamID* stream_ids = streams.get();
527 result = AudioObjectGetPropertyData(input_device_id_,
528 &property_address,
529 0,
530 NULL,
531 &size,
532 stream_ids);
533 if (!result) {
534 property_address.mSelector = kAudioStreamPropertyLatency;
535 result = AudioObjectGetPropertyData(stream_ids[0],
536 &property_address,
537 0,
538 NULL,
539 &size,
540 &stream_latency_frames);
541 }
542 }
543 DLOG_IF(WARNING, result != noErr) << "Could not get audio stream latency.";
544
391 return static_cast<double>((audio_unit_latency_sec * 545 return static_cast<double>((audio_unit_latency_sec *
392 format_.mSampleRate) + device_latency_frames); 546 format_.mSampleRate) + device_latency_frames + stream_latency_frames);
393 } 547 }
394 548
395 double AUAudioInputStream::GetCaptureLatency( 549 double AUAudioInputStream::GetCaptureLatency(
396 const AudioTimeStamp* input_time_stamp) { 550 const AudioTimeStamp* input_time_stamp) {
397 // Get the delay between between the actual recording instant and the time 551 // Get the delay between between the actual recording instant and the time
398 // when the data packet is provided as a callback. 552 // when the data packet is provided as a callback.
399 UInt64 capture_time_ns = AudioConvertHostTimeToNanos( 553 UInt64 capture_time_ns = AudioConvertHostTimeToNanos(
400 input_time_stamp->mHostTime); 554 input_time_stamp->mHostTime);
401 UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); 555 UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime());
402 double delay_frames = static_cast<double> 556 double delay_frames = static_cast<double>
403 (1e-9 * (now_ns - capture_time_ns) * format_.mSampleRate); 557 (1e-9 * (now_ns - capture_time_ns) * format_.mSampleRate);
404 558
405 // Total latency is composed by the dynamic latency and the fixed 559 // Total latency is composed by the dynamic latency and the fixed
406 // hardware latency. 560 // hardware latency.
407 return (delay_frames + hardware_latency_frames_); 561 return (delay_frames + hardware_latency_frames_);
408 } 562 }
409 563
564 UInt32 AUAudioInputStream::GetNumberOfChannelsFromStream() {
565 // Get the stream format, to be able to read the number of channels.
566 AudioObjectPropertyAddress property_address = {
567 kAudioDevicePropertyStreamFormat,
568 kAudioDevicePropertyScopeInput,
569 kAudioObjectPropertyElementMaster
570 };
571 AudioStreamBasicDescription stream_format;
572 UInt32 size = sizeof(stream_format);
573 OSStatus result = AudioObjectGetPropertyData(input_device_id_,
574 &property_address,
575 0,
576 NULL,
577 &size,
578 &stream_format);
579 DLOG_IF(WARNING, result != noErr) << "Could not get stream format.";
580
581 return stream_format.mChannelsPerFrame;
582 }
583
410 void AUAudioInputStream::HandleError(OSStatus err) { 584 void AUAudioInputStream::HandleError(OSStatus err) {
411 NOTREACHED() << "error " << GetMacOSStatusErrorString(err) 585 NOTREACHED() << "error " << GetMacOSStatusErrorString(err)
412 << " (" << err << ")"; 586 << " (" << err << ")";
413 if (sink_) 587 if (sink_)
414 sink_->OnError(this, static_cast<int>(err)); 588 sink_->OnError(this, static_cast<int>(err));
415 } 589 }
590
591 bool AUAudioInputStream::IsVolumeSettableOnChannel(int channel) {
592 Boolean is_settable = false;
593 AudioObjectPropertyAddress property_address = {
594 kAudioDevicePropertyVolumeScalar,
595 kAudioDevicePropertyScopeInput,
596 kAudioObjectPropertyElementMaster
597 };
598 property_address.mElement = channel;
599 OSStatus result = AudioObjectIsPropertySettable(input_device_id_,
600 &property_address,
601 &is_settable);
602 return (result == noErr) ? is_settable : false;
603 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698