Index: media/audio/mac/audio_low_latency_input_mac.cc |
=================================================================== |
--- media/audio/mac/audio_low_latency_input_mac.cc (revision 106304) |
+++ media/audio/mac/audio_low_latency_input_mac.cc (working copy) |
@@ -31,7 +31,9 @@ |
: manager_(manager), |
sink_(NULL), |
audio_unit_(0), |
- started_(false) { |
+ input_device_id_(kAudioObjectUnknown), |
+ started_(false), |
+ hardware_latency_frames_(0) { |
DCHECK(manager_); |
// Set up the desired (output) format specified by the client. |
@@ -136,25 +138,35 @@ |
// Set the current device of the AudioOuputUnit to default input device. |
- AudioDeviceID input_device; |
+ // First, obtain the current input device selected by the user. |
henrika (OOO until Aug 14)
2011/10/21 07:27:23
May I ask why you decided to use another API here?
no longer working on chromium
2011/10/21 12:21:46
Andrew pointed out that the AudioHardwareGetProper
|
+ AudioObjectPropertyAddress default_intput_device_address = { |
+ kAudioHardwarePropertyDefaultInputDevice, |
+ kAudioObjectPropertyScopeGlobal, |
+ kAudioObjectPropertyElementMaster |
+ }; |
+ AudioDeviceID input_device = kAudioObjectUnknown; |
UInt32 size = sizeof(input_device); |
- |
- // First, obtain the current input device selected by the user. |
- result = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, |
- &size, |
- &input_device); |
+ result = AudioObjectGetPropertyData(kAudioObjectSystemObject, |
+ &default_intput_device_address, |
+ 0, |
+ 0, |
+ &size, |
+ &input_device); |
if (result) { |
HandleError(result); |
return false; |
} |
+ // Store the input device id. |
henrika (OOO until Aug 14)
2011/10/21 07:27:23
Don't think this comment adds much.
no longer working on chromium
2011/10/21 12:21:46
Done.
|
+ input_device_id_ = input_device; |
+ |
// Next, set the audio device to be the Audio Unit's current device. |
// Note that, devices can only be set to the AUHAL after enabling IO. |
result = AudioUnitSetProperty(audio_unit_, |
kAudioOutputUnitProperty_CurrentDevice, |
kAudioUnitScope_Global, |
0, |
- &input_device, |
+ &input_device_id_, |
sizeof(input_device)); |
if (result) { |
HandleError(result); |
@@ -212,6 +224,9 @@ |
HandleError(result); |
return false; |
} |
+ |
+ hardware_latency_frames_ = GetHardwareLatency(); |
henrika (OOO until Aug 14)
2011/10/21 07:27:23
But a comment here could emphasize that parts of t
no longer working on chromium
2011/10/21 12:21:46
Done.
|
+ |
return true; |
} |
@@ -289,26 +304,32 @@ |
// Deliver recorded data to the consumer as a callback. |
return audio_input->Provide(number_of_frames, |
- audio_input->audio_buffer_list()); |
+ audio_input->audio_buffer_list(), |
+ time_stamp); |
} |
OSStatus AUAudioInputStream::Provide(UInt32 number_of_frames, |
- AudioBufferList* io_data) { |
+ AudioBufferList* io_data, |
+ const AudioTimeStamp* time_stamp) { |
+ // Update the capture latency. |
+ double capture_latency_frames = GetCaptureLatency(time_stamp); |
+ |
AudioBuffer& buffer = io_data->mBuffers[0]; |
uint8* audio_data = reinterpret_cast<uint8*>(buffer.mData); |
+ uint32 capture_delay_bytes = static_cast<uint32> |
+ (capture_latency_frames * format_.mBytesPerFrame + 0.5); |
DCHECK(audio_data); |
if (!audio_data) |
return kAudioUnitErr_InvalidElement; |
- // TODO(henrika): improve delay estimation. Using buffer size for now. |
- sink_->OnData(this, audio_data, buffer.mDataByteSize, buffer.mDataByteSize); |
+ sink_->OnData(this, audio_data, buffer.mDataByteSize, capture_delay_bytes); |
return noErr; |
} |
double AUAudioInputStream::HardwareSampleRate() { |
// Determine the default input device's sample-rate. |
- AudioDeviceID device_id = kAudioDeviceUnknown; |
+ AudioDeviceID device_id = kAudioObjectUnknown; |
UInt32 info_size = sizeof(device_id); |
AudioObjectPropertyAddress default_input_device_address = { |
@@ -347,6 +368,83 @@ |
return nominal_sample_rate; |
} |
+double AUAudioInputStream::GetHardwareLatency() { |
+ if (!audio_unit_ || input_device_id_ == kAudioObjectUnknown) |
henrika (OOO until Aug 14)
2011/10/21 07:27:23
Is this a valid state? Guess it is since this part
no longer working on chromium
2011/10/21 12:21:46
It is safer to add a check here, since this functi
|
+ return 0.0; |
+ |
+ // Get audio unit latency. |
+ Float64 audio_unit_latency_sec = 0.0; |
+ UInt32 size = sizeof(audio_unit_latency_sec); |
+ OSStatus result = AudioUnitGetProperty(audio_unit_, |
+ kAudioUnitProperty_Latency, |
+ kAudioUnitScope_Global, |
+ 0, |
+ &audio_unit_latency_sec, |
+ &size); |
+ if (result) { |
+ DLOG(WARNING) << "GetHardwareLatency: Could not get audio unit latency."; |
henrika (OOO until Aug 14)
2011/10/21 07:27:23
Don't need GetHardwareLatency:, the log message is
no longer working on chromium
2011/10/21 12:21:46
Done.
|
+ } |
+ |
+ // Get audio device latency. |
+ UInt32 device_latency_frames = 0; |
+ size = sizeof(device_latency_frames); |
+ result = AudioDeviceGetProperty(input_device_id_, 0, |
+ true, |
+ kAudioDevicePropertyLatency, |
+ &size, |
+ &device_latency_frames); |
+ if (result) { |
+ DLOG(WARNING) << "GetHardwareLatency: Could not get device latency."; |
henrika (OOO until Aug 14)
2011/10/21 07:27:23
ditto
no longer working on chromium
2011/10/21 12:21:46
Done.
|
+ } |
+ |
+ // Get the stream latency. |
+ UInt32 stream_latency_frames = 0; |
+ size = 0; |
+ result = AudioDeviceGetPropertyInfo(input_device_id_, |
+ 0, |
+ true, |
+ kAudioDevicePropertyStreams, |
+ &size, |
+ NULL); |
+ if (!result) { |
+ scoped_ptr_malloc<AudioStreamID> |
+ streams(reinterpret_cast<AudioStreamID*>(malloc(size))); |
+ AudioStreamID* stream_ids = streams.get(); |
+ result = AudioDeviceGetProperty(input_device_id_, |
+ 0, |
+ true, |
+ kAudioDevicePropertyStreams, |
+ &size, |
+ stream_ids); |
+ if (!result) |
+ result = AudioStreamGetProperty(stream_ids[0], |
+ 0, |
+ kAudioStreamPropertyLatency, |
+ &size, |
+ &stream_latency_frames); |
+ } |
+ // Logs the warning if it fails to get the stream latency. |
scherkus (not reviewing)
2011/10/21 00:20:58
nit: comment adds no value -- remove
no longer working on chromium
2011/10/21 12:21:46
Done.
|
+ if (result) { |
+ DLOG(WARNING) << "GetHardwareLatency: Could not get stream latency."; |
+ } |
+ |
+ // Store the hardware latency value in frames. |
scherkus (not reviewing)
2011/10/21 00:20:58
ditto
no longer working on chromium
2011/10/21 12:21:46
Done.
|
+ return static_cast<double>(audio_unit_latency_sec * |
henrika (OOO until Aug 14)
2011/10/21 07:27:23
I would write it as ((x*a) + b + c)
no longer working on chromium
2011/10/21 12:21:46
Done.
|
+ format_.mSampleRate + device_latency_frames + stream_latency_frames); |
+} |
+ |
+double AUAudioInputStream::GetCaptureLatency( |
+ const AudioTimeStamp* input_time_stamp) { |
+ // Get the delay between now and when the data was reaching the hardware. |
henrika (OOO until Aug 14)
2011/10/21 07:27:23
This comment is not clear. See my proposal in the
no longer working on chromium
2011/10/21 12:21:46
Done.
|
+ UInt64 input_time_ns = AudioConvertHostTimeToNanos( |
henrika (OOO until Aug 14)
2011/10/21 07:27:23
capture_time_ns
no longer working on chromium
2011/10/21 12:21:46
Done.
|
+ input_time_stamp->mHostTime); |
+ UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); |
+ double delay_frames = static_cast<double> |
+ (1e-9 * (now_ns - input_time_ns) * format_.mSampleRate); |
+ |
+ return (delay_frames + hardware_latency_frames_); |
henrika (OOO until Aug 14)
2011/10/21 07:27:23
Comment about sum of fixed parts and dynamic part
no longer working on chromium
2011/10/21 12:21:46
Done.
|
+} |
+ |
void AUAudioInputStream::HandleError(OSStatus err) { |
NOTREACHED() << "error code: " << err; |
if (sink_) |