Chromium Code Reviews| 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_; |
| +} |