Index: media/audio/mac/audio_low_latency_input_mac.cc |
=================================================================== |
--- media/audio/mac/audio_low_latency_input_mac.cc (revision 104447) |
+++ media/audio/mac/audio_low_latency_input_mac.cc (working copy) |
@@ -31,7 +31,10 @@ |
: manager_(manager), |
sink_(NULL), |
audio_unit_(0), |
- started_(false) { |
+ input_device_id_(kAudioDeviceUnknown), |
+ started_(false), |
+ hardware_latency_ms_(0), |
+ capture_latency_ms_(0) { |
DCHECK(manager_); |
// Set up the desired (output) format specified by the client. |
@@ -136,13 +139,12 @@ |
// Set the current device of the AudioOuputUnit to default input device. |
- AudioDeviceID input_device; |
- UInt32 size = sizeof(input_device); |
+ UInt32 size = sizeof(input_device_id_); |
henrika (OOO until Aug 14)
2011/10/12 12:10:11
I would use a local here and only assign if we are
no longer working on chromium
2011/10/12 15:28:47
Done.
|
// First, obtain the current input device selected by the user. |
result = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, |
&size, |
- &input_device); |
+ &input_device_id_); |
if (result) { |
HandleError(result); |
return false; |
@@ -154,8 +156,8 @@ |
kAudioOutputUnitProperty_CurrentDevice, |
kAudioUnitScope_Global, |
0, |
- &input_device, |
- sizeof(input_device)); |
+ &input_device_id_, |
+ sizeof(input_device_id_)); |
if (result) { |
HandleError(result); |
return false; |
@@ -212,6 +214,10 @@ |
HandleError(result); |
return false; |
} |
+ |
+ // Update the capture device hardware latency. |
henrika (OOO until Aug 14)
2011/10/12 12:10:11
Can be a static method instead.
no longer working on chromium
2011/10/12 15:28:47
Can't make it since the function needs some member
|
+ UpdateHardwareLatency(); |
+ |
return true; |
} |
@@ -289,19 +295,25 @@ |
// 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. |
+ UpdateCaptureLatency(time_stamp); |
henrika (OOO until Aug 14)
2011/10/12 12:10:11
Have you checked if we need to call it each callba
no longer working on chromium
2011/10/12 15:28:47
The value should be quite stable in the normal cas
|
+ |
AudioBuffer& buffer = io_data->mBuffers[0]; |
uint8* audio_data = reinterpret_cast<uint8*>(buffer.mData); |
+ uint32 capture_delay_bytes = (1.0e-3 * capture_latency_ms_ * |
henrika (OOO until Aug 14)
2011/10/12 12:10:11
I would divide by 1000, and clean up casting here.
no longer working on chromium
2011/10/12 15:28:47
Done.
|
+ format_.mSampleRate * format_.mBytesPerFrame); |
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; |
} |
@@ -347,6 +359,73 @@ |
return nominal_sample_rate; |
} |
+void AUAudioInputStream::UpdateHardwareLatency() { |
+ // Get audio unit latency. |
+ Float64 audio_unit_latency_s = 0; |
henrika (OOO until Aug 14)
2011/10/12 12:10:11
sec and 0.0.
no longer working on chromium
2011/10/12 15:28:47
Done.
|
+ UInt32 size = sizeof(audio_unit_latency_s); |
+ OSStatus result = AudioUnitGetProperty( |
henrika (OOO until Aug 14)
2011/10/12 12:10:11
Use same style as in rest of the code.
no longer working on chromium
2011/10/12 15:28:47
Done.
|
+ audio_unit_, kAudioUnitProperty_Latency, kAudioUnitScope_Global, |
+ 0, &audio_unit_latency_s, &size); |
+ if (result) { |
+ DLOG(WARNING) << "GetHardwareLatency: Could not get audio unit latency."; |
+ audio_unit_latency_s = 0; |
henrika (OOO until Aug 14)
2011/10/12 12:10:11
not needed
no longer working on chromium
2011/10/12 15:28:47
Done.
|
+ } |
+ |
+ // Get audio device latency. |
+ UInt32 device_latency_frames = 0; |
+ size = sizeof(device_latency_frames); |
+ result = AudioDeviceGetProperty(input_device_id_, 0, true, |
henrika (OOO until Aug 14)
2011/10/12 12:10:11
ditto
no longer working on chromium
2011/10/12 15:28:47
Done.
|
+ kAudioDevicePropertyLatency, &size, |
+ &device_latency_frames); |
+ if (result) { |
+ DLOG(WARNING) << "GetHardwareLatency: Could not get device latency."; |
+ device_latency_frames = 0; |
henrika (OOO until Aug 14)
2011/10/12 12:10:11
ditto
no longer working on chromium
2011/10/12 15:28:47
Done.
|
+ } |
+ |
+ // Get the stream latency. |
+ UInt32 stream_latency_frames = 0; |
+ size = 0; |
+ result = AudioDeviceGetPropertyInfo(input_device_id_, 0, true, |
henrika (OOO until Aug 14)
2011/10/12 12:10:11
ditto
no longer working on chromium
2011/10/12 15:28:47
Done.
|
+ kAudioDevicePropertyStreams, &size, NULL); |
+ if (!result) { |
+ scoped_ptr_malloc<AudioStreamID> |
+ streams(reinterpret_cast<AudioStreamID*>(malloc(size))); |
+ AudioStreamID* stream_ids = streams.get(); |
+ result = AudioDeviceGetProperty( |
henrika (OOO until Aug 14)
2011/10/12 12:10:11
ditto
no longer working on chromium
2011/10/12 15:28:47
Done.
|
+ input_device_id_, 0, true, |
+ kAudioDevicePropertyStreams, &size, stream_ids); |
+ if (result) { |
+ DLOG(WARNING) << "UpdateHardwareLatency: Could not get stream id."; |
+ return; |
henrika (OOO until Aug 14)
2011/10/12 12:10:11
Wrong!
no longer working on chromium
2011/10/12 15:28:47
Done.
|
+ } |
+ |
+ result = AudioStreamGetProperty( |
+ stream_ids[0], 0, kAudioStreamPropertyLatency, |
henrika (OOO until Aug 14)
2011/10/12 12:10:11
ditto
no longer working on chromium
2011/10/12 15:28:47
Done.
|
+ &size, &stream_latency_frames); |
+ if (result) { |
+ DLOG(WARNING) << "UpdateHardwareLatency: Could not get stream latency."; |
+ stream_latency_frames = 0; |
+ } |
+ } else { |
+ DLOG(WARNING) << "UpdateHardwareLatency: Could not get stream id."; |
+ } |
+ |
+ hardware_latency_ms_ = static_cast<uint32>(1.0e3 * audio_unit_latency_s + |
henrika (OOO until Aug 14)
2011/10/12 12:10:11
Are you sure?
no longer working on chromium
2011/10/12 15:28:47
Done.
|
+ (1.0e3 * (device_latency_frames + stream_latency_frames) |
+ / format_.mSampleRate) + 0.5); |
+} |
+ |
+void AUAudioInputStream::UpdateCaptureLatency( |
+ const AudioTimeStamp* input_time_stamp) { |
+ // Get the delay between now and when the data was hitting the hardware. |
henrika (OOO until Aug 14)
2011/10/12 12:10:11
aooch ;-)
no longer working on chromium
2011/10/12 15:28:47
Done.
|
+ UInt64 input_time_ns = AudioConvertHostTimeToNanos( |
+ input_time_stamp->mHostTime); |
+ UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); |
+ uint32 delay_ms = static_cast<uint32>(1e-6 * (now_ns - input_time_ns) + 0.5); |
henrika (OOO until Aug 14)
2011/10/12 12:10:11
Are you sure?
no longer working on chromium
2011/10/12 15:28:47
I would like to keep it, since it is a more readab
|
+ |
+ capture_latency_ms_ = delay_ms + hardware_latency_ms_; |
henrika (OOO until Aug 14)
2011/10/12 12:10:11
I would add a DCHECK here just in case (santity?)
no longer working on chromium
2011/10/12 15:28:47
I need to think a bit more here. For other platfor
|
+} |
+ |
void AUAudioInputStream::HandleError(OSStatus err) { |
NOTREACHED() << "error code: " << err; |
if (sink_) |