Index: media/audio/mac/audio_auhal_mac.cc |
diff --git a/media/audio/mac/audio_auhal_mac.cc b/media/audio/mac/audio_auhal_mac.cc |
index c02098c2346e6bfb232a357c6de8e1f652e9d314..d4d6075bd84a2bac8a586b1cb7337beee28a9b7c 100644 |
--- a/media/audio/mac/audio_auhal_mac.cc |
+++ b/media/audio/mac/audio_auhal_mac.cc |
@@ -6,16 +6,19 @@ |
#include <CoreServices/CoreServices.h> |
+#include <algorithm> |
+#include <string> |
+ |
#include "base/bind.h" |
#include "base/bind_helpers.h" |
#include "base/logging.h" |
#include "base/mac/mac_logging.h" |
#include "base/metrics/histogram_macros.h" |
#include "base/strings/stringprintf.h" |
-#include "base/time/time.h" |
#include "base/trace_event/trace_event.h" |
#include "media/audio/mac/audio_manager_mac.h" |
#include "media/base/audio_pull_fifo.h" |
+#include "media/base/audio_timestamp_helper.h" |
namespace media { |
@@ -51,9 +54,7 @@ AUHALStream::AUHALStream(AudioManagerMac* manager, |
device_(device), |
audio_unit_(0), |
volume_(1), |
- hardware_latency_frames_(0), |
stopped_(true), |
- current_hardware_pending_bytes_(0), |
current_lost_frames_(0), |
last_sample_time_(0.0), |
last_number_of_frames_(0), |
@@ -117,7 +118,7 @@ bool AUHALStream::Open() { |
bool configured = ConfigureAUHAL(); |
if (configured) |
- hardware_latency_frames_ = GetHardwareLatency(); |
+ hardware_latency_ = GetHardwareLatency(); |
return configured; |
} |
@@ -237,10 +238,7 @@ OSStatus AUHALStream::Render( |
// Make |output_bus_| wrap the output AudioBufferList. |
WrapBufferList(data, output_bus_.get(), number_of_frames); |
- // Update the playout latency. |
- const double playout_latency_frames = GetPlayoutLatency(output_time_stamp); |
- current_hardware_pending_bytes_ = static_cast<uint32_t>( |
- (playout_latency_frames + 0.5) * params_.GetBytesPerFrame()); |
+ current_playout_time_ = GetPlayoutTime(output_time_stamp); |
if (audio_fifo_) |
audio_fifo_->Consume(output_bus_.get(), output_bus_->frames()); |
@@ -259,10 +257,14 @@ void AUHALStream::ProvideInput(int frame_delay, AudioBus* dest) { |
return; |
} |
+ const base::TimeTicks playout_time = |
+ current_playout_time_ + |
+ AudioTimestampHelper::FramesToTime(frame_delay, params_.sample_rate()); |
+ const base::TimeTicks now = base::TimeTicks::Now(); |
+ const base::TimeDelta delay = playout_time - now; |
+ |
// Supply the input data and render the output data. |
- source_->OnMoreData(dest, current_hardware_pending_bytes_ + |
- frame_delay * params_.GetBytesPerFrame(), |
- current_lost_frames_); |
+ source_->OnMoreData(delay, now, current_lost_frames_, dest); |
dest->Scale(volume_); |
current_lost_frames_ = 0; |
} |
@@ -289,10 +291,10 @@ OSStatus AUHALStream::InputProc( |
io_data); |
} |
-double AUHALStream::GetHardwareLatency() { |
+base::TimeDelta AUHALStream::GetHardwareLatency() { |
if (!audio_unit_ || device_ == kAudioObjectUnknown) { |
DLOG(WARNING) << "AudioUnit is NULL or device ID is unknown"; |
- return 0.0; |
+ return base::TimeDelta(); |
} |
// Get audio unit latency. |
@@ -307,7 +309,7 @@ double AUHALStream::GetHardwareLatency() { |
&size); |
if (result != noErr) { |
OSSTATUS_DLOG(WARNING, result) << "Could not get AudioUnit latency"; |
- return 0.0; |
+ return base::TimeDelta(); |
} |
// Get output audio device latency. |
@@ -328,34 +330,29 @@ double AUHALStream::GetHardwareLatency() { |
&device_latency_frames); |
if (result != noErr) { |
OSSTATUS_DLOG(WARNING, result) << "Could not get audio device latency"; |
- return 0.0; |
+ return base::TimeDelta(); |
} |
- return static_cast<double>((audio_unit_latency_sec * |
- output_format_.mSampleRate) + device_latency_frames); |
+ int latency_frames = audio_unit_latency_sec * output_format_.mSampleRate + |
+ device_latency_frames; |
+ |
+ return AudioTimestampHelper::FramesToTime(latency_frames, |
+ params_.sample_rate()); |
} |
-double AUHALStream::GetPlayoutLatency( |
+base::TimeTicks AUHALStream::GetPlayoutTime( |
const AudioTimeStamp* output_time_stamp) { |
- // Ensure mHostTime is valid. |
+ // A platform bug has been observed where the platform sometimes reports that |
+ // the next frames will be output at an invalid time or a time in the past. |
+ // Because the target playout time cannot be invalid or in the past, return |
+ // "now" in these cases. |
if ((output_time_stamp->mFlags & kAudioTimeStampHostTimeValid) == 0) |
- return 0; |
- |
- // Get the delay between the moment getting the callback and the scheduled |
- // time stamp that tells when the data is going to be played out. |
- UInt64 output_time_ns = AudioConvertHostTimeToNanos( |
- output_time_stamp->mHostTime); |
- UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); |
- |
- // Prevent overflow leading to huge delay information; occurs regularly on |
- // the bots, probably less so in the wild. |
- if (now_ns > output_time_ns) |
- return 0; |
- |
- double delay_frames = static_cast<double> |
- (1e-9 * (output_time_ns - now_ns) * output_format_.mSampleRate); |
+ return base::TimeTicks::Now(); |
- return (delay_frames + hardware_latency_frames_); |
+ return std::max(base::TimeTicks::FromMachAbsoluteTime( |
+ output_time_stamp->mHostTime), |
+ base::TimeTicks::Now()) + |
+ hardware_latency_; |
} |
void AUHALStream::UpdatePlayoutTimestamp(const AudioTimeStamp* timestamp) { |