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_frames_(0), |
+ playout_latency_frames_(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; |
+ // Gets the playout device hardware latency and stores the value. |
+ StoreHardwareLatency(); |
scherkus (not reviewing)
2011/10/19 16:35:15
ditto
no longer working on chromium
2011/10/19 18:19:05
Done.
|
+ |
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); |
scherkus (not reviewing)
2011/10/19 16:35:15
ditto
no longer working on chromium
2011/10/19 18:19:05
Done.
|
+ |
AudioBuffer& buffer = io_data->mBuffers[0]; |
uint8* audio_data = reinterpret_cast<uint8*>(buffer.mData); |
+ uint32 hardware_pending_bytes = static_cast<uint32> |
+ (playout_latency_frames_ * format_.mBytesPerFrame + 0.5); |
uint32 filled = source_->OnMoreData( |
- this, audio_data, buffer.mDataByteSize, AudioBuffersState(0, 0)); |
+ this, audio_data, buffer.mDataByteSize, |
+ AudioBuffersState(0, 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,74 @@ |
return nominal_sample_rate; |
} |
+ |
+void AUAudioOutputStream::StoreHardwareLatency() { |
+ // Get audio unit latency. |
+ Float64 audio_unit_latency_sec = 0.0; |
+ UInt32 size = sizeof(audio_unit_latency_sec); |
+ OSStatus result = AudioUnitGetProperty(output_unit_, |
+ kAudioUnitProperty_Latency, |
+ kAudioUnitScope_Global, |
+ 0, |
+ &audio_unit_latency_sec, |
+ &size); |
+ if (result) |
+ DLOG(WARNING) << "StoreHardwareLatency: Could not get audio unit latency."; |
+ |
+ // 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) << "StoreHardwareLatency: Could not get device latency."; |
+ |
+ // 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) |
+ result = AudioStreamGetProperty(stream_ids[0], |
+ 0, |
+ kAudioStreamPropertyLatency, |
+ &size, |
+ &stream_latency_frames); |
+ } |
+ // Log the warning if it fails to get stream latency. |
+ if (result) |
+ DLOG(WARNING) << "StoreHardwareLatency: Could not get stream latency."; |
+ |
+ // Store the hardware latency value in freams. |
+ hardware_latency_frames_ = static_cast<double>(audio_unit_latency_sec * |
+ format_.mSampleRate + device_latency_frames + stream_latency_frames); |
+} |
+ |
+void AUAudioOutputStream::UpdatePlayoutLatency( |
+ const AudioTimeStamp* output_time_stamp) { |
+ // Get the delay between now and when the data is going to reach the hardware. |
+ UInt64 output_time_ns = AudioConvertHostTimeToNanos( |
+ output_time_stamp->mHostTime); |
+ UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); |
+ double delay_frames = static_cast<double> |
+ (1e-9 * (output_time_ns - now_ns) * format_.mSampleRate); |
+ |
+ playout_latency_frames_ = delay_frames + hardware_latency_frames_; |
+} |