OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/audio/mac/audio_auhal_mac.h" | 5 #include "media/audio/mac/audio_auhal_mac.h" |
6 | 6 |
7 #include <CoreServices/CoreServices.h> | 7 #include <CoreServices/CoreServices.h> |
8 | 8 |
9 #include <algorithm> | |
10 #include <string> | |
11 | |
9 #include "base/bind.h" | 12 #include "base/bind.h" |
10 #include "base/bind_helpers.h" | 13 #include "base/bind_helpers.h" |
11 #include "base/logging.h" | 14 #include "base/logging.h" |
12 #include "base/mac/mac_logging.h" | 15 #include "base/mac/mac_logging.h" |
13 #include "base/metrics/histogram_macros.h" | 16 #include "base/metrics/histogram_macros.h" |
14 #include "base/strings/stringprintf.h" | 17 #include "base/strings/stringprintf.h" |
15 #include "base/time/time.h" | |
16 #include "base/trace_event/trace_event.h" | 18 #include "base/trace_event/trace_event.h" |
17 #include "media/audio/mac/audio_manager_mac.h" | 19 #include "media/audio/mac/audio_manager_mac.h" |
18 #include "media/base/audio_pull_fifo.h" | 20 #include "media/base/audio_pull_fifo.h" |
19 | 21 |
20 namespace media { | 22 namespace media { |
21 | 23 |
22 static void WrapBufferList(AudioBufferList* buffer_list, | 24 static void WrapBufferList(AudioBufferList* buffer_list, |
23 AudioBus* bus, | 25 AudioBus* bus, |
24 int frames) { | 26 int frames) { |
25 DCHECK(buffer_list); | 27 DCHECK(buffer_list); |
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
229 audio_fifo_.reset(new AudioPullFifo( | 231 audio_fifo_.reset(new AudioPullFifo( |
230 output_channels_, | 232 output_channels_, |
231 number_of_frames_, | 233 number_of_frames_, |
232 base::Bind(&AUHALStream::ProvideInput, base::Unretained(this)))); | 234 base::Bind(&AUHALStream::ProvideInput, base::Unretained(this)))); |
233 } | 235 } |
234 } | 236 } |
235 | 237 |
236 // Make |output_bus_| wrap the output AudioBufferList. | 238 // Make |output_bus_| wrap the output AudioBufferList. |
237 WrapBufferList(data, output_bus_.get(), number_of_frames); | 239 WrapBufferList(data, output_bus_.get(), number_of_frames); |
238 | 240 |
239 // Update the playout latency. | 241 current_target_playout_time_ = GetTargetPlayoutTime(output_time_stamp); |
240 const double playout_latency_frames = GetPlayoutLatency(output_time_stamp); | |
241 current_hardware_pending_bytes_ = static_cast<uint32_t>( | |
242 (playout_latency_frames + 0.5) * params_.GetBytesPerFrame()); | |
243 | 242 |
244 if (audio_fifo_) | 243 if (audio_fifo_) |
245 audio_fifo_->Consume(output_bus_.get(), output_bus_->frames()); | 244 audio_fifo_->Consume(output_bus_.get(), output_bus_->frames()); |
246 else | 245 else |
247 ProvideInput(0, output_bus_.get()); | 246 ProvideInput(0, output_bus_.get()); |
248 | 247 |
249 last_number_of_frames_ = number_of_frames; | 248 last_number_of_frames_ = number_of_frames; |
250 | 249 |
251 return noErr; | 250 return noErr; |
252 } | 251 } |
253 | 252 |
254 void AUHALStream::ProvideInput(int frame_delay, AudioBus* dest) { | 253 void AUHALStream::ProvideInput(int frame_delay, AudioBus* dest) { |
255 base::AutoLock auto_lock(source_lock_); | 254 base::AutoLock auto_lock(source_lock_); |
256 if (!source_) { | 255 if (!source_) { |
257 dest->Zero(); | 256 dest->Zero(); |
258 return; | 257 return; |
259 } | 258 } |
260 | 259 |
260 const base::TimeDelta delay = base::TimeDelta::FromMicroseconds( | |
261 frame_delay * base::Time::kMicrosecondsPerSecond / params_.sample_rate()); | |
262 const base::TimeTicks target_playout_time = | |
263 current_target_playout_time_ + delay; | |
jameswest
2016/09/16 21:59:43
I realized I'm no longer adding hardware_latency_f
miu
2016/09/16 23:38:28
I think the math you have is correct: First, note
jameswest
2016/09/17 00:06:50
|hardware_latency_frames_| is no longer used with
miu
2016/09/17 00:33:56
OIC! I was confused (I thought you were referring
jameswest
2016/09/19 23:32:36
I changed GetHardwareLatency() to return TimeDelta
| |
264 | |
261 // Supply the input data and render the output data. | 265 // Supply the input data and render the output data. |
262 source_->OnMoreData(dest, current_hardware_pending_bytes_ + | 266 source_->OnMoreData(target_playout_time, current_lost_frames_, dest); |
263 frame_delay * params_.GetBytesPerFrame(), | |
264 current_lost_frames_); | |
265 dest->Scale(volume_); | 267 dest->Scale(volume_); |
266 current_lost_frames_ = 0; | 268 current_lost_frames_ = 0; |
267 } | 269 } |
268 | 270 |
269 // AUHAL callback. | 271 // AUHAL callback. |
270 OSStatus AUHALStream::InputProc( | 272 OSStatus AUHALStream::InputProc( |
271 void* user_data, | 273 void* user_data, |
272 AudioUnitRenderActionFlags* flags, | 274 AudioUnitRenderActionFlags* flags, |
273 const AudioTimeStamp* output_time_stamp, | 275 const AudioTimeStamp* output_time_stamp, |
274 UInt32 bus_number, | 276 UInt32 bus_number, |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
327 &device_latency_frames); | 329 &device_latency_frames); |
328 if (result != noErr) { | 330 if (result != noErr) { |
329 OSSTATUS_DLOG(WARNING, result) << "Could not get audio device latency"; | 331 OSSTATUS_DLOG(WARNING, result) << "Could not get audio device latency"; |
330 return 0.0; | 332 return 0.0; |
331 } | 333 } |
332 | 334 |
333 return static_cast<double>((audio_unit_latency_sec * | 335 return static_cast<double>((audio_unit_latency_sec * |
334 output_format_.mSampleRate) + device_latency_frames); | 336 output_format_.mSampleRate) + device_latency_frames); |
335 } | 337 } |
336 | 338 |
337 double AUHALStream::GetPlayoutLatency( | 339 base::TimeTicks AUHALStream::GetTargetPlayoutTime( |
338 const AudioTimeStamp* output_time_stamp) { | 340 const AudioTimeStamp* output_time_stamp) { |
339 // Ensure mHostTime is valid. | 341 // A platform bug has been observed where the platform sometimes reports that |
342 // the next frames will be output at an invalid time or a time in the past. | |
343 // Because the target playout time cannot be invalid or in the past, return | |
344 // "now" in these cases. | |
340 if ((output_time_stamp->mFlags & kAudioTimeStampHostTimeValid) == 0) | 345 if ((output_time_stamp->mFlags & kAudioTimeStampHostTimeValid) == 0) |
341 return 0; | 346 return base::TimeTicks::Now(); |
miu
2016/09/16 18:35:58
base::TimeTicks::Now() is being called twice in th
jameswest
2016/09/16 21:59:43
I'm not opposed to this, but I'm curious what the
miu
2016/09/16 23:38:28
Oh, I missed that. Yeah, no change necessary here.
jameswest
2016/09/19 23:32:36
Acknowledged.
| |
342 | 347 |
343 // Get the delay between the moment getting the callback and the scheduled | 348 return std::max( |
344 // time stamp that tells when the data is going to be played out. | 349 base::TimeTicks::FromMachAbsoluteTime(output_time_stamp->mHostTime), |
345 UInt64 output_time_ns = AudioConvertHostTimeToNanos( | 350 base::TimeTicks::Now()); |
346 output_time_stamp->mHostTime); | |
347 UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); | |
348 | |
349 // Prevent overflow leading to huge delay information; occurs regularly on | |
350 // the bots, probably less so in the wild. | |
351 if (now_ns > output_time_ns) | |
352 return 0; | |
353 | |
354 double delay_frames = static_cast<double> | |
355 (1e-9 * (output_time_ns - now_ns) * output_format_.mSampleRate); | |
356 | |
357 return (delay_frames + hardware_latency_frames_); | |
358 } | 351 } |
359 | 352 |
360 void AUHALStream::UpdatePlayoutTimestamp(const AudioTimeStamp* timestamp) { | 353 void AUHALStream::UpdatePlayoutTimestamp(const AudioTimeStamp* timestamp) { |
361 if ((timestamp->mFlags & kAudioTimeStampSampleTimeValid) == 0) | 354 if ((timestamp->mFlags & kAudioTimeStampSampleTimeValid) == 0) |
362 return; | 355 return; |
363 | 356 |
364 if (last_sample_time_) { | 357 if (last_sample_time_) { |
365 DCHECK_NE(0U, last_number_of_frames_); | 358 DCHECK_NE(0U, last_number_of_frames_); |
366 UInt32 diff = | 359 UInt32 diff = |
367 static_cast<UInt32>(timestamp->mSampleTime - last_sample_time_); | 360 static_cast<UInt32>(timestamp->mSampleTime - last_sample_time_); |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
555 OSStatus result = AudioUnitUninitialize(audio_unit_); | 548 OSStatus result = AudioUnitUninitialize(audio_unit_); |
556 OSSTATUS_DLOG_IF(ERROR, result != noErr, result) | 549 OSSTATUS_DLOG_IF(ERROR, result != noErr, result) |
557 << "AudioUnitUninitialize() failed."; | 550 << "AudioUnitUninitialize() failed."; |
558 result = AudioComponentInstanceDispose(audio_unit_); | 551 result = AudioComponentInstanceDispose(audio_unit_); |
559 OSSTATUS_DLOG_IF(ERROR, result != noErr, result) | 552 OSSTATUS_DLOG_IF(ERROR, result != noErr, result) |
560 << "AudioComponentInstanceDispose() failed."; | 553 << "AudioComponentInstanceDispose() failed."; |
561 audio_unit_ = 0; | 554 audio_unit_ = 0; |
562 } | 555 } |
563 | 556 |
564 } // namespace media | 557 } // namespace media |
OLD | NEW |