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

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

Issue 8234009: Adding input and output delay estimation for mac. (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: '' 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_output_mac.cc
===================================================================
--- media/audio/mac/audio_low_latency_output_mac.cc (revision 104447)
+++ media/audio/mac/audio_low_latency_output_mac.cc (working copy)
@@ -47,7 +47,10 @@
: manager_(manager),
source_(NULL),
output_unit_(0),
- volume_(1) {
+ output_device_id_(kAudioDeviceUnknown),
+ volume_(1),
+ hardware_latency_ms_(0),
+ playout_latency_ms_(0) {
// We must have a manager.
DCHECK(manager_);
// A frame is one sample across all channels. In interleaved audio the per
@@ -72,6 +75,16 @@
}
bool AUAudioOutputStream::Open() {
+ // Obtain the current input device selected by the user.
+ UInt32 size = sizeof(output_device_id_);
+ OSStatus result = AudioHardwareGetProperty(
+ kAudioHardwarePropertyDefaultOutputDevice,
+ &size,
+ &output_device_id_);
+ DCHECK_EQ(result, 0);
+ if (result)
+ return false;
+
// Open and initialize the DefaultOutputUnit.
Component comp;
ComponentDescription desc;
@@ -84,7 +97,7 @@
comp = FindNextComponent(0, &desc);
DCHECK(comp);
- OSStatus result = OpenAComponent(comp, &output_unit_);
+ result = OpenAComponent(comp, &output_unit_);
DCHECK_EQ(result, 0);
if (result)
return false;
@@ -95,6 +108,9 @@
if (result)
return false;
+ // Update the playout device hardware latency.
+ UpdateHardwareLatency();
+
return Configure();
}
@@ -185,11 +201,18 @@
// Note to future hackers of this function: Do not add locks here because this
// is running on a real-time thread (for low-latency).
OSStatus AUAudioOutputStream::Render(UInt32 number_of_frames,
- AudioBufferList* io_data) {
+ AudioBufferList* io_data,
+ const AudioTimeStamp* output_time_stamp) {
+ // Update the playout latency.
+ UpdatePlayoutLatency(output_time_stamp);
+
AudioBuffer& buffer = io_data->mBuffers[0];
uint8* audio_data = reinterpret_cast<uint8*>(buffer.mData);
+ uint32 hardware_pending_bytes = (1.0e-3 * playout_latency_ms_ *
+ format_.mSampleRate * format_.mBytesPerFrame);
uint32 filled = source_->OnMoreData(
- this, audio_data, buffer.mDataByteSize, AudioBuffersState(0, 0));
+ this, audio_data, buffer.mDataByteSize,
+ AudioBuffersState(buffer.mDataByteSize, hardware_pending_bytes));
// Handle channel order for 5.1 audio.
if (format_.mChannelsPerFrame == 6) {
@@ -208,7 +231,7 @@
// DefaultOutputUnit callback
OSStatus AUAudioOutputStream::InputProc(void* user_data,
AudioUnitRenderActionFlags*,
- const AudioTimeStamp*,
+ const AudioTimeStamp* output_time_stamp,
UInt32,
UInt32 number_of_frames,
AudioBufferList* io_data) {
@@ -218,7 +241,7 @@
if (!audio_output)
return -1;
- return audio_output->Render(number_of_frames, io_data);
+ return audio_output->Render(number_of_frames, io_data, output_time_stamp);
}
double AUAudioOutputStream::HardwareSampleRate() {
@@ -261,3 +284,69 @@
return nominal_sample_rate;
}
+
+void AUAudioOutputStream::UpdateHardwareLatency() {
+ // Get audio unit latency.
+ Float64 audio_unit_latency_s = 0;
+ UInt32 size = sizeof(audio_unit_latency_s);
+ OSStatus result = AudioUnitGetProperty(
+ output_unit_, kAudioUnitProperty_Latency, kAudioUnitScope_Global,
+ 0, &audio_unit_latency_s, &size);
+ if (result) {
+ DLOG(WARNING) << "UpdateHardwareLatency: Could not get audio unit latency.";
+ audio_unit_latency_s = 0;
+ }
+
+ // Get audio device latency.
+ UInt32 device_latency_frames = 0;
+ size = sizeof(device_latency_frames);
+ result = AudioDeviceGetProperty(output_device_id_, 0, false,
+ kAudioDevicePropertyLatency, &size,
+ &device_latency_frames);
+ if (result) {
+ DLOG(WARNING) << "UpdateHardwareLatency: Could not get device latency.";
+ device_latency_frames = 0;
+ }
+
+ // Get the stream latency.
+ UInt32 stream_latency_frames = 0;
+ result = AudioDeviceGetPropertyInfo(output_device_id_, 0, false,
+ kAudioDevicePropertyStreams, &size, NULL);
+ if (!result) {
+ scoped_ptr_malloc<AudioStreamID>
+ streams(reinterpret_cast<AudioStreamID*>(malloc(size)));
+ AudioStreamID* stream_ids = streams.get();
+ result = AudioDeviceGetProperty(
+ output_device_id_, 0, false,
+ kAudioDevicePropertyStreams, &size, stream_ids);
+ if (result) {
+ DLOG(WARNING) << "UpdateHardwareLatency: Could not get stream id.";
+ return;
+ }
+
+ result = AudioStreamGetProperty(
+ stream_ids[0], 0, kAudioStreamPropertyLatency,
+ &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 +
+ (1.0e3 * (device_latency_frames + stream_latency_frames)
+ / format_.mSampleRate) + 0.5);
+}
+
+void AUAudioOutputStream::UpdatePlayoutLatency(
+ const AudioTimeStamp* output_time_stamp) {
+ // Get the delay between now and when the data is going to hit the hardware.
+ UInt64 output_time_ns = AudioConvertHostTimeToNanos(
+ output_time_stamp->mHostTime);
+ UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime());
+ uint32 delay_ms = static_cast<uint32>(1e-6 * (output_time_ns - now_ns) + 0.5);
+
+ playout_latency_ms_ = delay_ms + hardware_latency_ms_;
+}

Powered by Google App Engine
This is Rietveld 408576698