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

Unified Diff: media/audio/mac/audio_low_latency_input_mac.cc

Issue 8234009: Adding input and output delay estimation for mac. (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: remove the deprecated AudioHardwareGetProperty and update comments Created 9 years, 2 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 side-by-side diff with in-line comments
Download patch
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_)

Powered by Google App Engine
This is Rietveld 408576698