Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(104)

Side by Side Diff: media/audio/mac/audio_auhal_mac.cc

Issue 2101303004: Pass delay and timestamp to AudioSourceCallback::OnMoreData. (Closed) Base URL: https://chromium.googlesource.com/chromium/src@master
Patch Set: Fix Windows CQ errors. Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
22 namespace {
23
24 base::TimeDelta FramesToTimeDelta(int frames, int sample_rate) {
25 return base::TimeDelta::FromMicroseconds(
26 frames * base::Time::kMicrosecondsPerSecond / sample_rate);
chcunningham 2016/09/23 20:53:30 integer division
jameswest 2016/09/29 00:52:24 Removed.
27 }
28
29 } // namespace
30
20 namespace media { 31 namespace media {
21 32
22 static void WrapBufferList(AudioBufferList* buffer_list, 33 static void WrapBufferList(AudioBufferList* buffer_list,
23 AudioBus* bus, 34 AudioBus* bus,
24 int frames) { 35 int frames) {
25 DCHECK(buffer_list); 36 DCHECK(buffer_list);
26 DCHECK(bus); 37 DCHECK(bus);
27 const int channels = bus->channels(); 38 const int channels = bus->channels();
28 const int buffer_list_channels = buffer_list->mNumberBuffers; 39 const int buffer_list_channels = buffer_list->mNumberBuffers;
29 CHECK_EQ(channels, buffer_list_channels); 40 CHECK_EQ(channels, buffer_list_channels);
(...skipping 14 matching lines...) Expand all
44 const AudioManager::LogCallback& log_callback) 55 const AudioManager::LogCallback& log_callback)
45 : manager_(manager), 56 : manager_(manager),
46 params_(params), 57 params_(params),
47 output_channels_(params_.channels()), 58 output_channels_(params_.channels()),
48 number_of_frames_(params_.frames_per_buffer()), 59 number_of_frames_(params_.frames_per_buffer()),
49 number_of_frames_requested_(0), 60 number_of_frames_requested_(0),
50 source_(NULL), 61 source_(NULL),
51 device_(device), 62 device_(device),
52 audio_unit_(0), 63 audio_unit_(0),
53 volume_(1), 64 volume_(1),
54 hardware_latency_frames_(0),
55 stopped_(true), 65 stopped_(true),
56 current_hardware_pending_bytes_(0),
57 current_lost_frames_(0), 66 current_lost_frames_(0),
58 last_sample_time_(0.0), 67 last_sample_time_(0.0),
59 last_number_of_frames_(0), 68 last_number_of_frames_(0),
60 total_lost_frames_(0), 69 total_lost_frames_(0),
61 largest_glitch_frames_(0), 70 largest_glitch_frames_(0),
62 glitches_detected_(0), 71 glitches_detected_(0),
63 log_callback_(log_callback) { 72 log_callback_(log_callback) {
64 // We must have a manager. 73 // We must have a manager.
65 DCHECK(manager_); 74 DCHECK(manager_);
66 CHECK(!log_callback_.Equals(AudioManager::LogCallback())); 75 CHECK(!log_callback_.Equals(AudioManager::LogCallback()));
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
110 return false; 119 return false;
111 } 120 }
112 121
113 // The output bus will wrap the AudioBufferList given to us in 122 // The output bus will wrap the AudioBufferList given to us in
114 // the Render() callback. 123 // the Render() callback.
115 DCHECK_GT(output_channels_, 0); 124 DCHECK_GT(output_channels_, 0);
116 output_bus_ = AudioBus::CreateWrapper(output_channels_); 125 output_bus_ = AudioBus::CreateWrapper(output_channels_);
117 126
118 bool configured = ConfigureAUHAL(); 127 bool configured = ConfigureAUHAL();
119 if (configured) 128 if (configured)
120 hardware_latency_frames_ = GetHardwareLatency(); 129 hardware_latency_ = GetHardwareLatency();
121 130
122 return configured; 131 return configured;
123 } 132 }
124 133
125 void AUHALStream::Close() { 134 void AUHALStream::Close() {
126 DCHECK(thread_checker_.CalledOnValidThread()); 135 DCHECK(thread_checker_.CalledOnValidThread());
127 DVLOG(1) << "Close"; 136 DVLOG(1) << "Close";
128 CloseAudioUnit(); 137 CloseAudioUnit();
129 // Inform the audio manager that we have been closed. This will cause our 138 // Inform the audio manager that we have been closed. This will cause our
130 // destruction. Also include the device ID as a signal to the audio manager 139 // destruction. Also include the device ID as a signal to the audio manager
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
230 audio_fifo_.reset(new AudioPullFifo( 239 audio_fifo_.reset(new AudioPullFifo(
231 output_channels_, 240 output_channels_,
232 number_of_frames_, 241 number_of_frames_,
233 base::Bind(&AUHALStream::ProvideInput, base::Unretained(this)))); 242 base::Bind(&AUHALStream::ProvideInput, base::Unretained(this))));
234 } 243 }
235 } 244 }
236 245
237 // Make |output_bus_| wrap the output AudioBufferList. 246 // Make |output_bus_| wrap the output AudioBufferList.
238 WrapBufferList(data, output_bus_.get(), number_of_frames); 247 WrapBufferList(data, output_bus_.get(), number_of_frames);
239 248
240 // Update the playout latency. 249 current_playout_time_ = GetPlayoutTime(output_time_stamp);
241 const double playout_latency_frames = GetPlayoutLatency(output_time_stamp);
242 current_hardware_pending_bytes_ = static_cast<uint32_t>(
243 (playout_latency_frames + 0.5) * params_.GetBytesPerFrame());
244 250
245 if (audio_fifo_) 251 if (audio_fifo_)
246 audio_fifo_->Consume(output_bus_.get(), output_bus_->frames()); 252 audio_fifo_->Consume(output_bus_.get(), output_bus_->frames());
247 else 253 else
248 ProvideInput(0, output_bus_.get()); 254 ProvideInput(0, output_bus_.get());
249 255
250 last_number_of_frames_ = number_of_frames; 256 last_number_of_frames_ = number_of_frames;
251 257
252 return noErr; 258 return noErr;
253 } 259 }
254 260
255 void AUHALStream::ProvideInput(int frame_delay, AudioBus* dest) { 261 void AUHALStream::ProvideInput(int frame_delay, AudioBus* dest) {
256 base::AutoLock auto_lock(source_lock_); 262 base::AutoLock auto_lock(source_lock_);
257 if (!source_) { 263 if (!source_) {
258 dest->Zero(); 264 dest->Zero();
259 return; 265 return;
260 } 266 }
261 267
268 const base::TimeTicks playout_time =
269 current_playout_time_ +
270 FramesToTimeDelta(frame_delay, params_.sample_rate());
271 const base::TimeTicks now = base::TimeTicks::Now();
272 const base::TimeDelta delay = playout_time - now;
273
262 // Supply the input data and render the output data. 274 // Supply the input data and render the output data.
263 source_->OnMoreData(dest, current_hardware_pending_bytes_ + 275 source_->OnMoreData(delay, now, current_lost_frames_, dest);
264 frame_delay * params_.GetBytesPerFrame(),
265 current_lost_frames_);
266 dest->Scale(volume_); 276 dest->Scale(volume_);
267 current_lost_frames_ = 0; 277 current_lost_frames_ = 0;
268 } 278 }
269 279
270 // AUHAL callback. 280 // AUHAL callback.
271 OSStatus AUHALStream::InputProc( 281 OSStatus AUHALStream::InputProc(
272 void* user_data, 282 void* user_data,
273 AudioUnitRenderActionFlags* flags, 283 AudioUnitRenderActionFlags* flags,
274 const AudioTimeStamp* output_time_stamp, 284 const AudioTimeStamp* output_time_stamp,
275 UInt32 bus_number, 285 UInt32 bus_number,
276 UInt32 number_of_frames, 286 UInt32 number_of_frames,
277 AudioBufferList* io_data) { 287 AudioBufferList* io_data) {
278 // Dispatch to our class method. 288 // Dispatch to our class method.
279 AUHALStream* audio_output = 289 AUHALStream* audio_output =
280 static_cast<AUHALStream*>(user_data); 290 static_cast<AUHALStream*>(user_data);
281 if (!audio_output) 291 if (!audio_output)
282 return -1; 292 return -1;
283 293
284 return audio_output->Render( 294 return audio_output->Render(
285 flags, 295 flags,
286 output_time_stamp, 296 output_time_stamp,
287 bus_number, 297 bus_number,
288 number_of_frames, 298 number_of_frames,
289 io_data); 299 io_data);
290 } 300 }
291 301
292 double AUHALStream::GetHardwareLatency() { 302 base::TimeDelta AUHALStream::GetHardwareLatency() {
293 if (!audio_unit_ || device_ == kAudioObjectUnknown) { 303 if (!audio_unit_ || device_ == kAudioObjectUnknown) {
294 DLOG(WARNING) << "AudioUnit is NULL or device ID is unknown"; 304 DLOG(WARNING) << "AudioUnit is NULL or device ID is unknown";
295 return 0.0; 305 return base::TimeDelta();
296 } 306 }
297 307
298 // Get audio unit latency. 308 // Get audio unit latency.
299 Float64 audio_unit_latency_sec = 0.0; 309 Float64 audio_unit_latency_sec = 0.0;
300 UInt32 size = sizeof(audio_unit_latency_sec); 310 UInt32 size = sizeof(audio_unit_latency_sec);
301 OSStatus result = AudioUnitGetProperty( 311 OSStatus result = AudioUnitGetProperty(
302 audio_unit_, 312 audio_unit_,
303 kAudioUnitProperty_Latency, 313 kAudioUnitProperty_Latency,
304 kAudioUnitScope_Global, 314 kAudioUnitScope_Global,
305 0, 315 0,
306 &audio_unit_latency_sec, 316 &audio_unit_latency_sec,
307 &size); 317 &size);
308 if (result != noErr) { 318 if (result != noErr) {
309 OSSTATUS_DLOG(WARNING, result) << "Could not get AudioUnit latency"; 319 OSSTATUS_DLOG(WARNING, result) << "Could not get AudioUnit latency";
310 return 0.0; 320 return base::TimeDelta();
311 } 321 }
312 322
313 // Get output audio device latency. 323 // Get output audio device latency.
314 static const AudioObjectPropertyAddress property_address = { 324 static const AudioObjectPropertyAddress property_address = {
315 kAudioDevicePropertyLatency, 325 kAudioDevicePropertyLatency,
316 kAudioDevicePropertyScopeOutput, 326 kAudioDevicePropertyScopeOutput,
317 kAudioObjectPropertyElementMaster 327 kAudioObjectPropertyElementMaster
318 }; 328 };
319 329
320 UInt32 device_latency_frames = 0; 330 UInt32 device_latency_frames = 0;
321 size = sizeof(device_latency_frames); 331 size = sizeof(device_latency_frames);
322 result = AudioObjectGetPropertyData( 332 result = AudioObjectGetPropertyData(
323 device_, 333 device_,
324 &property_address, 334 &property_address,
325 0, 335 0,
326 NULL, 336 NULL,
327 &size, 337 &size,
328 &device_latency_frames); 338 &device_latency_frames);
329 if (result != noErr) { 339 if (result != noErr) {
330 OSSTATUS_DLOG(WARNING, result) << "Could not get audio device latency"; 340 OSSTATUS_DLOG(WARNING, result) << "Could not get audio device latency";
331 return 0.0; 341 return base::TimeDelta();
332 } 342 }
333 343
334 return static_cast<double>((audio_unit_latency_sec * 344 int latency_frames = audio_unit_latency_sec * output_format_.mSampleRate +
335 output_format_.mSampleRate) + device_latency_frames); 345 device_latency_frames;
346
347 return FramesToTimeDelta(latency_frames, params_.sample_rate());
336 } 348 }
337 349
338 double AUHALStream::GetPlayoutLatency( 350 base::TimeTicks AUHALStream::GetPlayoutTime(
339 const AudioTimeStamp* output_time_stamp) { 351 const AudioTimeStamp* output_time_stamp) {
340 // Ensure mHostTime is valid. 352 // A platform bug has been observed where the platform sometimes reports that
353 // the next frames will be output at an invalid time or a time in the past.
354 // Because the target playout time cannot be invalid or in the past, return
355 // "now" in these cases.
341 if ((output_time_stamp->mFlags & kAudioTimeStampHostTimeValid) == 0) 356 if ((output_time_stamp->mFlags & kAudioTimeStampHostTimeValid) == 0)
342 return 0; 357 return base::TimeTicks::Now();
343 358
344 // Get the delay between the moment getting the callback and the scheduled 359 return std::max(base::TimeTicks::FromMachAbsoluteTime(
345 // time stamp that tells when the data is going to be played out. 360 output_time_stamp->mHostTime),
346 UInt64 output_time_ns = AudioConvertHostTimeToNanos( 361 base::TimeTicks::Now()) +
347 output_time_stamp->mHostTime); 362 hardware_latency_;
348 UInt64 now_ns = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime());
349
350 // Prevent overflow leading to huge delay information; occurs regularly on
351 // the bots, probably less so in the wild.
352 if (now_ns > output_time_ns)
353 return 0;
354
355 double delay_frames = static_cast<double>
356 (1e-9 * (output_time_ns - now_ns) * output_format_.mSampleRate);
357
358 return (delay_frames + hardware_latency_frames_);
359 } 363 }
360 364
361 void AUHALStream::UpdatePlayoutTimestamp(const AudioTimeStamp* timestamp) { 365 void AUHALStream::UpdatePlayoutTimestamp(const AudioTimeStamp* timestamp) {
362 if ((timestamp->mFlags & kAudioTimeStampSampleTimeValid) == 0) 366 if ((timestamp->mFlags & kAudioTimeStampSampleTimeValid) == 0)
363 return; 367 return;
364 368
365 if (last_sample_time_) { 369 if (last_sample_time_) {
366 DCHECK_NE(0U, last_number_of_frames_); 370 DCHECK_NE(0U, last_number_of_frames_);
367 UInt32 diff = 371 UInt32 diff =
368 static_cast<UInt32>(timestamp->mSampleTime - last_sample_time_); 372 static_cast<UInt32>(timestamp->mSampleTime - last_sample_time_);
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after
556 OSStatus result = AudioUnitUninitialize(audio_unit_); 560 OSStatus result = AudioUnitUninitialize(audio_unit_);
557 OSSTATUS_DLOG_IF(ERROR, result != noErr, result) 561 OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
558 << "AudioUnitUninitialize() failed."; 562 << "AudioUnitUninitialize() failed.";
559 result = AudioComponentInstanceDispose(audio_unit_); 563 result = AudioComponentInstanceDispose(audio_unit_);
560 OSSTATUS_DLOG_IF(ERROR, result != noErr, result) 564 OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
561 << "AudioComponentInstanceDispose() failed."; 565 << "AudioComponentInstanceDispose() failed.";
562 audio_unit_ = 0; 566 audio_unit_ = 0;
563 } 567 }
564 568
565 } // namespace media 569 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698