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

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: added a comment about the number of channel, and fix a compiling issue on mac 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 26 matching lines...) Expand all
77 78
78 AUAudioInputStream::~AUAudioInputStream() {} 79 AUAudioInputStream::~AUAudioInputStream() {}
79 80
80 // Obtain and open the AUHAL AudioOutputUnit for recording. 81 // Obtain and open the AUHAL AudioOutputUnit for recording.
81 bool AUAudioInputStream::Open() { 82 bool AUAudioInputStream::Open() {
82 // Verify that we are not already opened. 83 // Verify that we are not already opened.
83 if (audio_unit_) 84 if (audio_unit_)
84 return false; 85 return false;
85 86
86 // Verify that we have a valid device. 87 // Verify that we have a valid device.
87 if (input_device_id_ == kAudioObjectUnknown) 88 if (input_device_id_ == kAudioObjectUnknown) {
89 NOTREACHED() << "Device ID is unknown";
88 return false; 90 return false;
91 }
89 92
90 // Start by obtaining an AudioOuputUnit using an AUHAL component description. 93 // Start by obtaining an AudioOuputUnit using an AUHAL component description.
91 94
92 Component comp; 95 Component comp;
93 ComponentDescription desc; 96 ComponentDescription desc;
94 97
95 // Description for the Audio Unit we want to use (AUHAL in this case). 98 // Description for the Audio Unit we want to use (AUHAL in this case).
96 desc.componentType = kAudioUnitType_Output; 99 desc.componentType = kAudioUnitType_Output;
97 desc.componentSubType = kAudioUnitSubType_HALOutput; 100 desc.componentSubType = kAudioUnitSubType_HALOutput;
98 desc.componentManufacturer = kAudioUnitManufacturer_Apple; 101 desc.componentManufacturer = kAudioUnitManufacturer_Apple;
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
204 // it can produce in response to a single render call. 207 // it can produce in response to a single render call.
205 result = AudioUnitInitialize(audio_unit_); 208 result = AudioUnitInitialize(audio_unit_);
206 if (result) { 209 if (result) {
207 HandleError(result); 210 HandleError(result);
208 return false; 211 return false;
209 } 212 }
210 213
211 // The hardware latency is fixed and will not change during the call. 214 // The hardware latency is fixed and will not change during the call.
212 hardware_latency_frames_ = GetHardwareLatency(); 215 hardware_latency_frames_ = GetHardwareLatency();
213 216
217 // The master channel is 0, Left and right are channels 1 and 2.
218 // And the master channel is not counted in |number_of_channels_in_frame_|.
219 number_of_channels_in_frame_ = GetNumberOfChannelsFromStream();
220
214 return true; 221 return true;
215 } 222 }
216 223
217 void AUAudioInputStream::Start(AudioInputCallback* callback) { 224 void AUAudioInputStream::Start(AudioInputCallback* callback) {
218 DCHECK(callback); 225 DCHECK(callback);
219 DLOG_IF(ERROR, !audio_unit_) << "Open() has not been called successfully"; 226 DLOG_IF(ERROR, !audio_unit_) << "Open() has not been called successfully";
220 if (started_ || !audio_unit_) 227 if (started_ || !audio_unit_)
221 return; 228 return;
222 sink_ = callback; 229 sink_ = callback;
223 OSStatus result = AudioOutputUnitStart(audio_unit_); 230 OSStatus result = AudioOutputUnitStart(audio_unit_);
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
256 if (sink_) { 263 if (sink_) {
257 sink_->OnClose(this); 264 sink_->OnClose(this);
258 sink_ = NULL; 265 sink_ = NULL;
259 } 266 }
260 267
261 // Inform the audio manager that we have been closed. This can cause our 268 // Inform the audio manager that we have been closed. This can cause our
262 // destruction. 269 // destruction.
263 manager_->ReleaseInputStream(this); 270 manager_->ReleaseInputStream(this);
264 } 271 }
265 272
273 double AUAudioInputStream::GetMaxVolume() {
274 // Verify that we have a valid device.
275 if (input_device_id_ == kAudioObjectUnknown) {
276 NOTREACHED() << "Device ID is unknown";
277 return 0.0;
278 }
279
280 // Query if any of the master, left or right channels has volume control.
281 for (int i = 0; i <= number_of_channels_in_frame_; ++i) {
282 // If the volume is settable, the valid volume range is [0.0, 1.0].
283 if (IsVolumeSettableOnChannel(i))
284 return 1.0;
285 }
286
287 // Volume control is not available for the audio stream.
288 return 0.0;
289 }
290
291 void AUAudioInputStream::SetVolume(double volume) {
292 DCHECK(volume <= 1.0 && volume >= 0.0);
293
294 // Verify that we have a valid device.
295 if (input_device_id_ == kAudioObjectUnknown) {
296 NOTREACHED() << "Device ID is unknown";
297 return;
298 }
299
300 Float32 volume_float32 = static_cast<Float32>(volume);
301 AudioObjectPropertyAddress property_address = {
302 kAudioDevicePropertyVolumeScalar,
303 kAudioDevicePropertyScopeInput,
304 kAudioObjectPropertyElementMaster
305 };
306
307 // Try to set the volume for master volume channel.
308 if (IsVolumeSettableOnChannel(kAudioObjectPropertyElementMaster)) {
309 OSStatus result = AudioObjectSetPropertyData(input_device_id_,
310 &property_address,
311 0,
312 NULL,
313 sizeof(volume_float32),
314 &volume_float32);
315 if (result != noErr) {
316 DLOG(WARNING) << "Failed to set volume to " << volume_float32;
317 }
318 return;
319 }
320
321 // There is no master volume control, try to set volume for each channel.
322 int successful_channels = 0;
323 for (int i = 1; i <= number_of_channels_in_frame_; ++i) {
324 property_address.mElement = static_cast<UInt32>(i);
325 if (IsVolumeSettableOnChannel(i)) {
326 OSStatus result = AudioObjectSetPropertyData(input_device_id_,
327 &property_address,
328 0,
329 NULL,
330 sizeof(volume_float32),
331 &volume_float32);
332 if (result == noErr)
333 ++successful_channels;
334 }
335 }
336
337 DLOG_IF(WARNING, successful_channels == 0)
338 << "Failed to set volume to " << volume_float32;
339 }
340
341 double AUAudioInputStream::GetVolume() {
342 // Verify that we have a valid device.
343 if (input_device_id_ == kAudioObjectUnknown){
344 NOTREACHED() << "Device ID is unknown";
345 return 0.0;
346 }
347
348 AudioObjectPropertyAddress property_address = {
349 kAudioDevicePropertyVolumeScalar,
350 kAudioDevicePropertyScopeInput,
351 kAudioObjectPropertyElementMaster
352 };
353
354 if (AudioObjectHasProperty(input_device_id_, &property_address)) {
355 // The device supports master volume control, get the volume from the
356 // master channel.
357 Float32 volume_float32 = 0.0;
358 UInt32 size = sizeof(volume_float32);
359 OSStatus result = AudioObjectGetPropertyData(input_device_id_,
360 &property_address,
361 0,
362 NULL,
363 &size,
364 &volume_float32);
365 if (result == noErr)
366 return static_cast<double>(volume_float32);
367 } else {
368 // There is no master volume control, try to get the average volume of
369 // all the channels.
370 Float32 volume_float32 = 0.0;
371 int successful_channels = 0;
372 for (int i = 1; i <= number_of_channels_in_frame_; ++i) {
373 property_address.mElement = static_cast<UInt32>(i);
374 if (AudioObjectHasProperty(input_device_id_, &property_address)) {
375 Float32 channel_volume = 0;
376 UInt32 size = sizeof(channel_volume);
377 OSStatus result = AudioObjectGetPropertyData(input_device_id_,
378 &property_address,
379 0,
380 NULL,
381 &size,
382 &channel_volume);
383 if (result == noErr) {
384 volume_float32 += channel_volume;
385 ++successful_channels;
386 }
387 }
388 }
389
390 // Get the average volume of the channels.
391 if (successful_channels != 0)
392 return static_cast<double>(volume_float32 / successful_channels);
393 }
394
395 DLOG(WARNING) << "Failed to get volume";
396 return 0.0;
397 }
398
266 // AUHAL AudioDeviceOutput unit callback 399 // AUHAL AudioDeviceOutput unit callback
267 OSStatus AUAudioInputStream::InputProc(void* user_data, 400 OSStatus AUAudioInputStream::InputProc(void* user_data,
268 AudioUnitRenderActionFlags* flags, 401 AudioUnitRenderActionFlags* flags,
269 const AudioTimeStamp* time_stamp, 402 const AudioTimeStamp* time_stamp,
270 UInt32 bus_number, 403 UInt32 bus_number,
271 UInt32 number_of_frames, 404 UInt32 number_of_frames,
272 AudioBufferList* io_data) { 405 AudioBufferList* io_data) {
273 // Verify that the correct bus is used (Input bus/Element 1) 406 // Verify that the correct bus is used (Input bus/Element 1)
274 DCHECK_EQ(bus_number, static_cast<UInt32>(1)); 407 DCHECK_EQ(bus_number, static_cast<UInt32>(1));
275 AUAudioInputStream* audio_input = 408 AUAudioInputStream* audio_input =
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
400 input_time_stamp->mHostTime); 533 input_time_stamp->mHostTime);
401 UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); 534 UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime());
402 double delay_frames = static_cast<double> 535 double delay_frames = static_cast<double>
403 (1e-9 * (now_ns - capture_time_ns) * format_.mSampleRate); 536 (1e-9 * (now_ns - capture_time_ns) * format_.mSampleRate);
404 537
405 // Total latency is composed by the dynamic latency and the fixed 538 // Total latency is composed by the dynamic latency and the fixed
406 // hardware latency. 539 // hardware latency.
407 return (delay_frames + hardware_latency_frames_); 540 return (delay_frames + hardware_latency_frames_);
408 } 541 }
409 542
543 int AUAudioInputStream::GetNumberOfChannelsFromStream() {
544 // Get the stream format, to be able to read the number of channels.
545 AudioObjectPropertyAddress property_address = {
546 kAudioDevicePropertyStreamFormat,
547 kAudioDevicePropertyScopeInput,
548 kAudioObjectPropertyElementMaster
549 };
550 AudioStreamBasicDescription stream_format;
551 UInt32 size = sizeof(stream_format);
552 OSStatus result = AudioObjectGetPropertyData(input_device_id_,
553 &property_address,
554 0,
555 NULL,
556 &size,
557 &stream_format);
558 if (result != noErr) {
559 DLOG(WARNING) << "Could not get stream format";
560 return 0;
561 }
562
563 return static_cast<int>(stream_format.mChannelsPerFrame);
564 }
565
410 void AUAudioInputStream::HandleError(OSStatus err) { 566 void AUAudioInputStream::HandleError(OSStatus err) {
411 NOTREACHED() << "error " << GetMacOSStatusErrorString(err) 567 NOTREACHED() << "error " << GetMacOSStatusErrorString(err)
412 << " (" << err << ")"; 568 << " (" << err << ")";
413 if (sink_) 569 if (sink_)
414 sink_->OnError(this, static_cast<int>(err)); 570 sink_->OnError(this, static_cast<int>(err));
415 } 571 }
572
573 bool AUAudioInputStream::IsVolumeSettableOnChannel(int channel) {
574 Boolean is_settable = false;
575 AudioObjectPropertyAddress property_address = {
576 kAudioDevicePropertyVolumeScalar,
577 kAudioDevicePropertyScopeInput,
578 static_cast<UInt32>(channel)
579 };
580 OSStatus result = AudioObjectIsPropertySettable(input_device_id_,
581 &property_address,
582 &is_settable);
583 return (result == noErr) ? is_settable : false;
584 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698