 Chromium Code Reviews
 Chromium Code Reviews Issue 2101303004:
  Pass delay and timestamp to AudioSourceCallback::OnMoreData.  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src@master
    
  
    Issue 2101303004:
  Pass delay and timestamp to AudioSourceCallback::OnMoreData.  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src@master| 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 <string> | |
| 10 | |
| 9 #include "base/bind.h" | 11 #include "base/bind.h" | 
| 10 #include "base/bind_helpers.h" | 12 #include "base/bind_helpers.h" | 
| 11 #include "base/logging.h" | 13 #include "base/logging.h" | 
| 12 #include "base/mac/mac_logging.h" | 14 #include "base/mac/mac_logging.h" | 
| 13 #include "base/metrics/histogram_macros.h" | 15 #include "base/metrics/histogram_macros.h" | 
| 14 #include "base/strings/stringprintf.h" | 16 #include "base/strings/stringprintf.h" | 
| 15 #include "base/time/time.h" | |
| 16 #include "base/trace_event/trace_event.h" | 17 #include "base/trace_event/trace_event.h" | 
| 17 #include "media/audio/mac/audio_manager_mac.h" | 18 #include "media/audio/mac/audio_manager_mac.h" | 
| 18 #include "media/base/audio_pull_fifo.h" | 19 #include "media/base/audio_pull_fifo.h" | 
| 19 | 20 | 
| 20 namespace media { | 21 namespace media { | 
| 21 | 22 | 
| 22 static void WrapBufferList(AudioBufferList* buffer_list, | 23 static void WrapBufferList(AudioBufferList* buffer_list, | 
| 23 AudioBus* bus, | 24 AudioBus* bus, | 
| 24 int frames) { | 25 int frames) { | 
| 25 DCHECK(buffer_list); | 26 DCHECK(buffer_list); | 
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 229 audio_fifo_.reset(new AudioPullFifo( | 230 audio_fifo_.reset(new AudioPullFifo( | 
| 230 output_channels_, | 231 output_channels_, | 
| 231 number_of_frames_, | 232 number_of_frames_, | 
| 232 base::Bind(&AUHALStream::ProvideInput, base::Unretained(this)))); | 233 base::Bind(&AUHALStream::ProvideInput, base::Unretained(this)))); | 
| 233 } | 234 } | 
| 234 } | 235 } | 
| 235 | 236 | 
| 236 // Make |output_bus_| wrap the output AudioBufferList. | 237 // Make |output_bus_| wrap the output AudioBufferList. | 
| 237 WrapBufferList(data, output_bus_.get(), number_of_frames); | 238 WrapBufferList(data, output_bus_.get(), number_of_frames); | 
| 238 | 239 | 
| 239 // Update the playout latency. | 240 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 | 241 | 
| 244 if (audio_fifo_) | 242 if (audio_fifo_) | 
| 245 audio_fifo_->Consume(output_bus_.get(), output_bus_->frames()); | 243 audio_fifo_->Consume(output_bus_.get(), output_bus_->frames()); | 
| 246 else | 244 else | 
| 247 ProvideInput(0, output_bus_.get()); | 245 ProvideInput(0, output_bus_.get()); | 
| 248 | 246 | 
| 249 last_number_of_frames_ = number_of_frames; | 247 last_number_of_frames_ = number_of_frames; | 
| 250 | 248 | 
| 251 return noErr; | 249 return noErr; | 
| 252 } | 250 } | 
| 253 | 251 | 
| 254 void AUHALStream::ProvideInput(int frame_delay, AudioBus* dest) { | 252 void AUHALStream::ProvideInput(int frame_delay, AudioBus* dest) { | 
| 255 base::AutoLock auto_lock(source_lock_); | 253 base::AutoLock auto_lock(source_lock_); | 
| 256 if (!source_) { | 254 if (!source_) { | 
| 257 dest->Zero(); | 255 dest->Zero(); | 
| 258 return; | 256 return; | 
| 259 } | 257 } | 
| 260 | 258 | 
| 259 const base::TimeDelta delay = base::TimeDelta::FromMicroseconds( | |
| 260 frame_delay * base::Time::kMicrosecondsPerSecond / params_.sample_rate()); | |
| 261 const base::TimeTicks target_playout_time = | |
| 262 current_target_playout_time_ + delay; | |
| 263 | |
| 261 // Supply the input data and render the output data. | 264 // Supply the input data and render the output data. | 
| 262 source_->OnMoreData(dest, current_hardware_pending_bytes_ + | 265 source_->OnMoreData(target_playout_time, current_lost_frames_, dest); | 
| 263 frame_delay * params_.GetBytesPerFrame(), | |
| 264 current_lost_frames_); | |
| 265 dest->Scale(volume_); | 266 dest->Scale(volume_); | 
| 266 current_lost_frames_ = 0; | 267 current_lost_frames_ = 0; | 
| 267 } | 268 } | 
| 268 | 269 | 
| 269 // AUHAL callback. | 270 // AUHAL callback. | 
| 270 OSStatus AUHALStream::InputProc( | 271 OSStatus AUHALStream::InputProc( | 
| 271 void* user_data, | 272 void* user_data, | 
| 272 AudioUnitRenderActionFlags* flags, | 273 AudioUnitRenderActionFlags* flags, | 
| 273 const AudioTimeStamp* output_time_stamp, | 274 const AudioTimeStamp* output_time_stamp, | 
| 274 UInt32 bus_number, | 275 UInt32 bus_number, | 
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 327 &device_latency_frames); | 328 &device_latency_frames); | 
| 328 if (result != noErr) { | 329 if (result != noErr) { | 
| 329 OSSTATUS_DLOG(WARNING, result) << "Could not get audio device latency"; | 330 OSSTATUS_DLOG(WARNING, result) << "Could not get audio device latency"; | 
| 330 return 0.0; | 331 return 0.0; | 
| 331 } | 332 } | 
| 332 | 333 | 
| 333 return static_cast<double>((audio_unit_latency_sec * | 334 return static_cast<double>((audio_unit_latency_sec * | 
| 334 output_format_.mSampleRate) + device_latency_frames); | 335 output_format_.mSampleRate) + device_latency_frames); | 
| 335 } | 336 } | 
| 336 | 337 | 
| 337 double AUHALStream::GetPlayoutLatency( | 338 base::TimeTicks AUHALStream::GetTargetPlayoutTime( | 
| 338 const AudioTimeStamp* output_time_stamp) { | 339 const AudioTimeStamp* output_time_stamp) { | 
| 339 // Ensure mHostTime is valid. | 340 // Ensure mHostTime is valid. | 
| 340 if ((output_time_stamp->mFlags & kAudioTimeStampHostTimeValid) == 0) | 341 if ((output_time_stamp->mFlags & kAudioTimeStampHostTimeValid) == 0) | 
| 341 return 0; | 342 return 0; | 
| 
miu
2016/08/31 23:26:54
The two "return 0" statements in this method won't
 
jameswest
2016/09/07 21:52:16
I'll add the TODO, but it looks like it was writte
 
miu
2016/09/07 22:19:36
That's correct. He left several years ago. Hmm...G
 
miu
2016/09/08 20:56:23
Looking at this again, I think it hides a bug, but
 
James West
2016/09/13 07:40:50
Done.
 | |
| 342 | 343 | 
| 343 // Get the delay between the moment getting the callback and the scheduled | 344 // Get the delay between the moment getting the callback and the scheduled | 
| 344 // time stamp that tells when the data is going to be played out. | 345 // time stamp that tells when the data is going to be played out. | 
| 345 UInt64 output_time_ns = AudioConvertHostTimeToNanos( | 346 UInt64 output_time_ns = AudioConvertHostTimeToNanos( | 
| 346 output_time_stamp->mHostTime); | 347 output_time_stamp->mHostTime); | 
| 347 UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); | 348 UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); | 
| 348 | 349 | 
| 349 // Prevent overflow leading to huge delay information; occurs regularly on | 350 // Prevent overflow leading to huge delay information; occurs regularly on | 
| 350 // the bots, probably less so in the wild. | 351 // the bots, probably less so in the wild. | 
| 351 if (now_ns > output_time_ns) | 352 if (now_ns > output_time_ns) | 
| 352 return 0; | 353 return 0; | 
| 353 | 354 | 
| 354 double delay_frames = static_cast<double> | 355 // TODO(jameswest): Find an alternative to FromInternalValue. | 
| 355 (1e-9 * (output_time_ns - now_ns) * output_format_.mSampleRate); | 356 return base::TimeTicks::FromInternalValue( | 
| 
miu
2016/08/31 23:26:54
I'd suggest adding a TimeTicks::FromMachAbsoluteTi
 
James West
2016/09/13 07:40:50
Done.
 | |
| 356 | 357 output_time_ns / base::Time::kNanosecondsPerMicrosecond); | 
| 357 return (delay_frames + hardware_latency_frames_); | |
| 358 } | 358 } | 
| 359 | 359 | 
| 360 void AUHALStream::UpdatePlayoutTimestamp(const AudioTimeStamp* timestamp) { | 360 void AUHALStream::UpdatePlayoutTimestamp(const AudioTimeStamp* timestamp) { | 
| 361 if ((timestamp->mFlags & kAudioTimeStampSampleTimeValid) == 0) | 361 if ((timestamp->mFlags & kAudioTimeStampSampleTimeValid) == 0) | 
| 362 return; | 362 return; | 
| 363 | 363 | 
| 364 if (last_sample_time_) { | 364 if (last_sample_time_) { | 
| 365 DCHECK_NE(0U, last_number_of_frames_); | 365 DCHECK_NE(0U, last_number_of_frames_); | 
| 366 UInt32 diff = | 366 UInt32 diff = | 
| 367 static_cast<UInt32>(timestamp->mSampleTime - last_sample_time_); | 367 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_); | 555 OSStatus result = AudioUnitUninitialize(audio_unit_); | 
| 556 OSSTATUS_DLOG_IF(ERROR, result != noErr, result) | 556 OSSTATUS_DLOG_IF(ERROR, result != noErr, result) | 
| 557 << "AudioUnitUninitialize() failed."; | 557 << "AudioUnitUninitialize() failed."; | 
| 558 result = AudioComponentInstanceDispose(audio_unit_); | 558 result = AudioComponentInstanceDispose(audio_unit_); | 
| 559 OSSTATUS_DLOG_IF(ERROR, result != noErr, result) | 559 OSSTATUS_DLOG_IF(ERROR, result != noErr, result) | 
| 560 << "AudioComponentInstanceDispose() failed."; | 560 << "AudioComponentInstanceDispose() failed."; | 
| 561 audio_unit_ = 0; | 561 audio_unit_ = 0; | 
| 562 } | 562 } | 
| 563 | 563 | 
| 564 } // namespace media | 564 } // namespace media | 
| OLD | NEW |