Commit 973509d4 authored by Dale Curtis's avatar Dale Curtis Committed by Commit Bot

Include stream latency for macOS audio latency calculations.

We were incorrectly ignoring the stream latency component when
calculating the fixed latency of streams. This needs to be done
for both input and output.

Since these methods are very similar I've refactored the one our
input and output streams had into a common AudioMangerMac method.

BUG=783282
TEST=none

Cq-Include-Trybots: master.tryserver.chromium.android:android_optional_gpu_tests_rel;master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel
Change-Id: Ic583a2f314728b566a5a3e3de8c8ffd118652f91
Reviewed-on: https://chromium-review.googlesource.com/764542
Commit-Queue: Dale Curtis <dalecurtis@chromium.org>
Reviewed-by: default avatarOlga Sharonova <olka@chromium.org>
Cr-Commit-Position: refs/heads/master@{#516056}
parent 0cc2a698
......@@ -198,7 +198,9 @@ bool AUHALStream::Open() {
if (configured) {
DCHECK(audio_unit_);
DCHECK(audio_unit_->is_valid());
hardware_latency_ = GetHardwareLatency();
hardware_latency_ = AudioManagerMac::GetHardwareLatency(
audio_unit_->audio_unit(), device_, kAudioDevicePropertyScopeOutput,
params_.sample_rate());
}
return configured;
......@@ -354,41 +356,6 @@ OSStatus AUHALStream::InputProc(void* user_data,
number_of_frames, io_data);
}
base::TimeDelta AUHALStream::GetHardwareLatency() {
DCHECK(audio_unit_);
// Get audio unit latency.
Float64 audio_unit_latency_sec;
UInt32 size = sizeof(audio_unit_latency_sec);
OSStatus result = AudioUnitGetProperty(
audio_unit_->audio_unit(), kAudioUnitProperty_Latency,
kAudioUnitScope_Global, 0, &audio_unit_latency_sec, &size);
if (result != noErr) {
OSSTATUS_DLOG(WARNING, result) << "Could not get AudioUnit latency";
return base::TimeDelta();
}
// Get output audio device latency.
static const AudioObjectPropertyAddress property_address = {
kAudioDevicePropertyLatency, kAudioDevicePropertyScopeOutput,
kAudioObjectPropertyElementMaster};
UInt32 device_latency_frames = 0;
size = sizeof(device_latency_frames);
result = AudioObjectGetPropertyData(device_, &property_address, 0, NULL,
&size, &device_latency_frames);
if (result != noErr) {
OSSTATUS_DLOG(WARNING, result) << "Could not get audio device latency";
return base::TimeDelta();
}
int latency_frames = audio_unit_latency_sec * output_format_.mSampleRate +
device_latency_frames;
return AudioTimestampHelper::FramesToTime(latency_frames,
params_.sample_rate());
}
base::TimeTicks AUHALStream::GetPlayoutTime(
const AudioTimeStamp* output_time_stamp) {
// A platform bug has been observed where the platform sometimes reports that
......
......@@ -119,9 +119,6 @@ class AUHALStream : public AudioOutputStream {
// Creates the input and output busses.
void CreateIOBusses();
// Returns the fixed hardware latency, or zero if not available.
base::TimeDelta GetHardwareLatency();
// Returns the playout time for a given AudioTimeStamp.
base::TimeTicks GetPlayoutTime(const AudioTimeStamp* output_time_stamp);
......
......@@ -485,7 +485,9 @@ bool AUAudioInputStream::Open() {
}
// The hardware latency is fixed and will not change during the call.
hardware_latency_ = GetHardwareLatency();
hardware_latency_ = AudioManagerMac::GetHardwareLatency(
audio_unit_, input_device_id_, kAudioDevicePropertyScopeInput,
format_.mSampleRate);
// The master channel is 0, Left and right are channels 1 and 2.
// And the master channel is not counted in |number_of_channels_in_frame_|.
......@@ -1059,36 +1061,6 @@ int AUAudioInputStream::HardwareSampleRate() {
return static_cast<int>(nominal_sample_rate);
}
base::TimeDelta AUAudioInputStream::GetHardwareLatency() {
if (!audio_unit_ || input_device_id_ == kAudioObjectUnknown) {
DLOG(WARNING) << "Audio unit object is NULL or device ID is unknown";
return base::TimeDelta();
}
// 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);
OSSTATUS_DLOG_IF(WARNING, result != noErr, result)
<< "Could not get audio unit latency";
// Get input audio device latency.
AudioObjectPropertyAddress property_address = {
kAudioDevicePropertyLatency, kAudioDevicePropertyScopeInput,
kAudioObjectPropertyElementMaster};
UInt32 device_latency_frames = 0;
size = sizeof(device_latency_frames);
result = AudioObjectGetPropertyData(input_device_id_, &property_address, 0,
nullptr, &size, &device_latency_frames);
DLOG_IF(WARNING, result != noErr) << "Could not get audio device latency.";
return base::TimeDelta::FromSecondsD(audio_unit_latency_sec) +
AudioTimestampHelper::FramesToTime(device_latency_frames,
format_.mSampleRate);
}
base::TimeTicks AUAudioInputStream::GetCaptureTime(
const AudioTimeStamp* input_time_stamp) {
// Total latency is composed by the dynamic latency and the fixed
......
......@@ -136,10 +136,6 @@ class MEDIA_EXPORT AUAudioInputStream
// Stop listening for changes in device properties.
void DeRegisterDeviceChangeListener();
// Gets the fixed capture hardware latency and store it during initialization.
// Returns 0 if not available.
base::TimeDelta GetHardwareLatency();
// Gets the current capture time.
base::TimeTicks GetCaptureTime(const AudioTimeStamp* input_time_stamp);
......
......@@ -26,6 +26,7 @@
#include "media/audio/mac/coreaudio_dispatch_override.h"
#include "media/audio/mac/scoped_audio_unit.h"
#include "media/base/audio_parameters.h"
#include "media/base/audio_timestamp_helper.h"
#include "media/base/bind_to_current_loop.h"
#include "media/base/channel_layout.h"
#include "media/base/limits.h"
......@@ -1071,6 +1072,49 @@ bool AudioManagerMac::MaybeChangeBufferSize(AudioDeviceID device_id,
return (result == noErr);
}
// static
base::TimeDelta AudioManagerMac::GetHardwareLatency(
AudioUnit audio_unit,
AudioDeviceID device_id,
AudioObjectPropertyScope scope,
int sample_rate) {
if (!audio_unit || device_id == kAudioObjectUnknown) {
DLOG(WARNING) << "Audio unit object is NULL or device ID is unknown";
return base::TimeDelta();
}
// 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);
OSSTATUS_DLOG_IF(WARNING, result != noErr, result)
<< "Could not get audio unit latency";
// Get audio device latency.
AudioObjectPropertyAddress property_address = {
kAudioDevicePropertyLatency, scope, kAudioObjectPropertyElementMaster};
UInt32 device_latency_frames = 0;
size = sizeof(device_latency_frames);
result = AudioObjectGetPropertyData(device_id, &property_address, 0, nullptr,
&size, &device_latency_frames);
OSSTATUS_DLOG_IF(WARNING, result != noErr, result)
<< "Could not get audio device latency.";
property_address.mSelector = kAudioStreamPropertyLatency;
UInt32 stream_latency_frames = 0;
size = sizeof(stream_latency_frames);
result = AudioObjectGetPropertyData(device_id, &property_address, 0, nullptr,
&size, &stream_latency_frames);
OSSTATUS_DLOG_IF(WARNING, result != noErr, result)
<< "Could not get stream latency.";
return base::TimeDelta::FromSecondsD(audio_unit_latency_sec) +
AudioTimestampHelper::FramesToTime(
device_latency_frames + stream_latency_frames, sample_rate);
}
bool AudioManagerMac::IncreaseIOBufferSizeIfPossible(AudioDeviceID device_id) {
DCHECK(GetTaskRunner()->BelongsToCurrentThread());
DVLOG(1) << "IncreaseIOBufferSizeIfPossible(id=0x" << std::hex << device_id
......
......@@ -112,6 +112,14 @@ class MEDIA_EXPORT AudioManagerMac : public AudioManagerBase {
bool* size_was_changed,
size_t* io_buffer_frame_size);
// Returns the latency for the given audio unit and device. Total latency is
// the sum of the latency of the AudioUnit, device, and stream. If any one
// component of the latency can't be retrieved it is considered as zero.
static base::TimeDelta GetHardwareLatency(AudioUnit audio_unit,
AudioDeviceID device_id,
AudioObjectPropertyScope scope,
int sample_rate);
// Number of constructed output and input streams.
size_t output_streams() const { return output_streams_.size(); }
size_t low_latency_input_streams() const {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment