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

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: please review 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();
henrika (OOO until Aug 14) 2012/02/21 14:03:47 Why adding "FromStream()"?
no longer working on chromium 2012/02/21 18:01:38 I want to make it more specific to differentiate t
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 void AUAudioInputStream::SetMicVolume(double volume) {
270 DCHECK(volume <= 1.0 && volume >= 0.0);
271
272 // Verify that we have a valid device.
273 if (input_device_id_ == kAudioObjectUnknown)
274 return;
275
276 Float32 volume_float32 = static_cast<Float32> (volume);
277 AudioObjectPropertyAddress property_address = {
278 kAudioDevicePropertyVolumeScalar,
279 kAudioDevicePropertyScopeInput,
280 kAudioObjectPropertyElementMaster
281 };
282
283 // Try to set the volume for master volume channel.
284 if (IsVolumeSettableOnChannel(kAudioObjectPropertyElementMaster)) {
285 UInt32 size = sizeof(volume_float32);
286 OSStatus result = AudioObjectSetPropertyData(input_device_id_,
287 &property_address,
288 0,
289 NULL,
290 size,
291 &volume_float32);
292 DLOG_IF(WARNING, result != noErr) << "SetMicVolume failed to set volume to "
293 << volume_float32;
294 return;
295 }
296
297 // There is no master volume control, try to set volume for each channel.
henrika (OOO until Aug 14) 2012/02/21 14:03:47 Can there be one master volume and channel volumes
no longer working on chromium 2012/02/21 18:01:38 If it supports master volume, we use master volume
298 int success = 0;
299 for (UInt32 i = 1; i <= number_of_channels_in_frame_; i++) {
300 property_address.mElement = i;
301 if (IsVolumeSettableOnChannel(i)) {
302 UInt32 size = sizeof(volume_float32);
303 OSStatus result = AudioObjectSetPropertyData(input_device_id_,
304 &property_address,
305 0,
306 NULL,
307 size,
308 &volume_float32);
309 if (result == noErr)
310 ++success;
311 }
312 }
313
314 DLOG_IF(WARNING, success == noErr) << "SetMicVolume failed to set volume to "
315 << volume_float32;
316 }
317
318 void AUAudioInputStream::GetMicVolume(double* volume) {
319 // Verify that we have a valid device.
320 if (input_device_id_ == kAudioObjectUnknown)
321 return;
322
323 *volume = 0.0;
324 AudioObjectPropertyAddress property_address = {
325 kAudioDevicePropertyVolumeScalar,
326 kAudioDevicePropertyScopeInput,
327 kAudioObjectPropertyElementMaster
328 };
329
330 if (AudioObjectHasProperty(input_device_id_, &property_address)) {
331 // The device supports master volume control, get the volume from the
332 // master channel.
333 Float32 volume_float32 = 0.0;
334 UInt32 size = sizeof(volume_float32);
335 OSStatus result = AudioObjectGetPropertyData(input_device_id_,
336 &property_address,
337 0,
338 NULL,
339 &size,
340 &volume_float32);
341 if (result != noErr) {
342 DLOG(WARNING) << "AudioObjectGetPropertyData failed not get volume.";
343 return;
344 }
345 *volume = static_cast<double> (volume_float32);
346 } else {
347 // There is no master volume control, try to get the average volume of
348 // all the channels.
349 Float32 volume_float32 = 0.0;
350 int success = 0;
henrika (OOO until Aug 14) 2012/02/21 14:03:47 Not clear that this is a counter.
no longer working on chromium 2012/02/21 18:01:38 Done.
351 for (UInt32 i = 1; i <= number_of_channels_in_frame_; i++) {
352 property_address.mElement = i;
353 if (AudioObjectHasProperty(input_device_id_, &property_address)) {
354 Float32 channel_volume = 0;
355 UInt32 size = sizeof(channel_volume);
356 OSStatus result = AudioObjectGetPropertyData(input_device_id_,
357 &property_address,
358 0,
359 NULL,
360 &size,
361 &channel_volume);
362 if (result == noErr) {
363 volume_float32 += channel_volume;
364 ++success;
365 }
366 }
367 }
368 if (success == 0) {
369 DLOG(WARNING) << "Unable to get volume from any channel";
370 return;
371 }
372
373 // Get the average volume of the channels.
374 *volume = static_cast<double> (volume_float32 / success);
375 }
376 }
377
378 void AUAudioInputStream::GetMaxMicVolume(double* volume) {
379 // Verify that we have a valid device.
380 if (input_device_id_ == kAudioObjectUnknown)
381 return;
382
383 if (IsVolumeSettableOnChannel(0)) {
384 // If the volume is settable, the valid volume range is [0.0, 1.0].
385 *volume = 1.0;
386 return;
387 }
388
389 // There is no master volume control, try to set volume for each channel.
390 for (UInt32 i = 1; i <= number_of_channels_in_frame_; i++) {
391 if (IsVolumeSettableOnChannel(i)) {
392 *volume = 1.0;
393 return;
394 }
395 }
396
397 // Volume control is not available for the audio stream.
398 *volume = 0.0;
399 }
400
266 // AUHAL AudioDeviceOutput unit callback 401 // AUHAL AudioDeviceOutput unit callback
267 OSStatus AUAudioInputStream::InputProc(void* user_data, 402 OSStatus AUAudioInputStream::InputProc(void* user_data,
268 AudioUnitRenderActionFlags* flags, 403 AudioUnitRenderActionFlags* flags,
269 const AudioTimeStamp* time_stamp, 404 const AudioTimeStamp* time_stamp,
270 UInt32 bus_number, 405 UInt32 bus_number,
271 UInt32 number_of_frames, 406 UInt32 number_of_frames,
272 AudioBufferList* io_data) { 407 AudioBufferList* io_data) {
273 // Verify that the correct bus is used (Input bus/Element 1) 408 // Verify that the correct bus is used (Input bus/Element 1)
274 DCHECK_EQ(bus_number, static_cast<UInt32>(1)); 409 DCHECK_EQ(bus_number, static_cast<UInt32>(1));
275 AUAudioInputStream* audio_input = 410 AUAudioInputStream* audio_input =
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
431 input_time_stamp->mHostTime); 566 input_time_stamp->mHostTime);
432 UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); 567 UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime());
433 double delay_frames = static_cast<double> 568 double delay_frames = static_cast<double>
434 (1e-9 * (now_ns - capture_time_ns) * format_.mSampleRate); 569 (1e-9 * (now_ns - capture_time_ns) * format_.mSampleRate);
435 570
436 // Total latency is composed by the dynamic latency and the fixed 571 // Total latency is composed by the dynamic latency and the fixed
437 // hardware latency. 572 // hardware latency.
438 return (delay_frames + hardware_latency_frames_); 573 return (delay_frames + hardware_latency_frames_);
439 } 574 }
440 575
576 UInt32 AUAudioInputStream::GetNumberOfChannelsFromStream() {
henrika (OOO until Aug 14) 2012/02/21 14:03:47 Why not the same APIs as in the audio manager for
no longer working on chromium 2012/02/21 18:01:38 I explored a bit on the apple documentation. It se
577 // Get the stream format, to be able to read the number of channels.
578 AudioObjectPropertyAddress property_address = {
579 kAudioDevicePropertyStreamFormat,
580 kAudioDevicePropertyScopeInput,
581 kAudioObjectPropertyElementMaster
582 };
583 AudioStreamBasicDescription stream_format;
584 UInt32 size = sizeof(stream_format);
585 OSStatus result = AudioObjectGetPropertyData(input_device_id_,
586 &property_address,
587 0,
588 NULL,
589 &size,
590 &stream_format);
591 DLOG_IF(WARNING, result != noErr) << "Could not get stream format.";
592
593 return stream_format.mChannelsPerFrame;
594 }
595
441 void AUAudioInputStream::HandleError(OSStatus err) { 596 void AUAudioInputStream::HandleError(OSStatus err) {
442 NOTREACHED() << "error " << GetMacOSStatusErrorString(err) 597 NOTREACHED() << "error " << GetMacOSStatusErrorString(err)
443 << " (" << err << ")"; 598 << " (" << err << ")";
444 if (sink_) 599 if (sink_)
445 sink_->OnError(this, static_cast<int>(err)); 600 sink_->OnError(this, static_cast<int>(err));
446 } 601 }
602
603 bool AUAudioInputStream::IsVolumeSettableOnChannel(int channel) {
604 Boolean is_settable = false;
605 AudioObjectPropertyAddress property_address = {
606 kAudioDevicePropertyVolumeScalar,
607 kAudioDevicePropertyScopeInput,
608 kAudioObjectPropertyElementMaster
609 };
610 property_address.mElement = channel;
611 OSStatus result = AudioObjectIsPropertySettable(input_device_id_,
612 &property_address,
613 &is_settable);
614 return (result == noErr)? is_settable : false;
henrika (OOO until Aug 14) 2012/02/21 14:03:47 Same nit again. Please use ") ? is_"
no longer working on chromium 2012/02/21 18:01:38 Done.
615 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698