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

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 Mac CQ errors. Created 4 years, 2 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"
21 #include "media/base/audio_timestamp_helper.h"
19 22
20 namespace media { 23 namespace media {
21 24
22 static void WrapBufferList(AudioBufferList* buffer_list, 25 static void WrapBufferList(AudioBufferList* buffer_list,
23 AudioBus* bus, 26 AudioBus* bus,
24 int frames) { 27 int frames) {
25 DCHECK(buffer_list); 28 DCHECK(buffer_list);
26 DCHECK(bus); 29 DCHECK(bus);
27 const int channels = bus->channels(); 30 const int channels = bus->channels();
28 const int buffer_list_channels = buffer_list->mNumberBuffers; 31 const int buffer_list_channels = buffer_list->mNumberBuffers;
(...skipping 15 matching lines...) Expand all
44 const AudioManager::LogCallback& log_callback) 47 const AudioManager::LogCallback& log_callback)
45 : manager_(manager), 48 : manager_(manager),
46 params_(params), 49 params_(params),
47 output_channels_(params_.channels()), 50 output_channels_(params_.channels()),
48 number_of_frames_(params_.frames_per_buffer()), 51 number_of_frames_(params_.frames_per_buffer()),
49 number_of_frames_requested_(0), 52 number_of_frames_requested_(0),
50 source_(NULL), 53 source_(NULL),
51 device_(device), 54 device_(device),
52 audio_unit_(0), 55 audio_unit_(0),
53 volume_(1), 56 volume_(1),
54 hardware_latency_frames_(0),
55 stopped_(true), 57 stopped_(true),
56 current_hardware_pending_bytes_(0),
57 current_lost_frames_(0), 58 current_lost_frames_(0),
58 last_sample_time_(0.0), 59 last_sample_time_(0.0),
59 last_number_of_frames_(0), 60 last_number_of_frames_(0),
60 total_lost_frames_(0), 61 total_lost_frames_(0),
61 largest_glitch_frames_(0), 62 largest_glitch_frames_(0),
62 glitches_detected_(0), 63 glitches_detected_(0),
63 log_callback_(log_callback) { 64 log_callback_(log_callback) {
64 // We must have a manager. 65 // We must have a manager.
65 DCHECK(manager_); 66 DCHECK(manager_);
66 CHECK(!log_callback_.Equals(AudioManager::LogCallback())); 67 CHECK(!log_callback_.Equals(AudioManager::LogCallback()));
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
110 return false; 111 return false;
111 } 112 }
112 113
113 // The output bus will wrap the AudioBufferList given to us in 114 // The output bus will wrap the AudioBufferList given to us in
114 // the Render() callback. 115 // the Render() callback.
115 DCHECK_GT(output_channels_, 0); 116 DCHECK_GT(output_channels_, 0);
116 output_bus_ = AudioBus::CreateWrapper(output_channels_); 117 output_bus_ = AudioBus::CreateWrapper(output_channels_);
117 118
118 bool configured = ConfigureAUHAL(); 119 bool configured = ConfigureAUHAL();
119 if (configured) 120 if (configured)
120 hardware_latency_frames_ = GetHardwareLatency(); 121 hardware_latency_ = GetHardwareLatency();
121 122
122 return configured; 123 return configured;
123 } 124 }
124 125
125 void AUHALStream::Close() { 126 void AUHALStream::Close() {
126 DCHECK(thread_checker_.CalledOnValidThread()); 127 DCHECK(thread_checker_.CalledOnValidThread());
127 DVLOG(1) << "Close"; 128 DVLOG(1) << "Close";
128 CloseAudioUnit(); 129 CloseAudioUnit();
129 // Inform the audio manager that we have been closed. This will cause our 130 // 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 131 // 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( 231 audio_fifo_.reset(new AudioPullFifo(
231 output_channels_, 232 output_channels_,
232 number_of_frames_, 233 number_of_frames_,
233 base::Bind(&AUHALStream::ProvideInput, base::Unretained(this)))); 234 base::Bind(&AUHALStream::ProvideInput, base::Unretained(this))));
234 } 235 }
235 } 236 }
236 237
237 // Make |output_bus_| wrap the output AudioBufferList. 238 // Make |output_bus_| wrap the output AudioBufferList.
238 WrapBufferList(data, output_bus_.get(), number_of_frames); 239 WrapBufferList(data, output_bus_.get(), number_of_frames);
239 240
240 // Update the playout latency. 241 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 242
245 if (audio_fifo_) 243 if (audio_fifo_)
246 audio_fifo_->Consume(output_bus_.get(), output_bus_->frames()); 244 audio_fifo_->Consume(output_bus_.get(), output_bus_->frames());
247 else 245 else
248 ProvideInput(0, output_bus_.get()); 246 ProvideInput(0, output_bus_.get());
249 247
250 last_number_of_frames_ = number_of_frames; 248 last_number_of_frames_ = number_of_frames;
251 249
252 return noErr; 250 return noErr;
253 } 251 }
254 252
255 void AUHALStream::ProvideInput(int frame_delay, AudioBus* dest) { 253 void AUHALStream::ProvideInput(int frame_delay, AudioBus* dest) {
256 base::AutoLock auto_lock(source_lock_); 254 base::AutoLock auto_lock(source_lock_);
257 if (!source_) { 255 if (!source_) {
258 dest->Zero(); 256 dest->Zero();
259 return; 257 return;
260 } 258 }
261 259
260 const base::TimeTicks playout_time =
261 current_playout_time_ +
262 AudioTimestampHelper::FramesToTime(frame_delay, params_.sample_rate());
263 const base::TimeTicks now = base::TimeTicks::Now();
264 const base::TimeDelta delay = playout_time - now;
265
262 // Supply the input data and render the output data. 266 // Supply the input data and render the output data.
263 source_->OnMoreData(dest, current_hardware_pending_bytes_ + 267 source_->OnMoreData(delay, now, current_lost_frames_, dest);
264 frame_delay * params_.GetBytesPerFrame(),
265 current_lost_frames_);
266 dest->Scale(volume_); 268 dest->Scale(volume_);
267 current_lost_frames_ = 0; 269 current_lost_frames_ = 0;
268 } 270 }
269 271
270 // AUHAL callback. 272 // AUHAL callback.
271 OSStatus AUHALStream::InputProc( 273 OSStatus AUHALStream::InputProc(
272 void* user_data, 274 void* user_data,
273 AudioUnitRenderActionFlags* flags, 275 AudioUnitRenderActionFlags* flags,
274 const AudioTimeStamp* output_time_stamp, 276 const AudioTimeStamp* output_time_stamp,
275 UInt32 bus_number, 277 UInt32 bus_number,
276 UInt32 number_of_frames, 278 UInt32 number_of_frames,
277 AudioBufferList* io_data) { 279 AudioBufferList* io_data) {
278 // Dispatch to our class method. 280 // Dispatch to our class method.
279 AUHALStream* audio_output = 281 AUHALStream* audio_output =
280 static_cast<AUHALStream*>(user_data); 282 static_cast<AUHALStream*>(user_data);
281 if (!audio_output) 283 if (!audio_output)
282 return -1; 284 return -1;
283 285
284 return audio_output->Render( 286 return audio_output->Render(
285 flags, 287 flags,
286 output_time_stamp, 288 output_time_stamp,
287 bus_number, 289 bus_number,
288 number_of_frames, 290 number_of_frames,
289 io_data); 291 io_data);
290 } 292 }
291 293
292 double AUHALStream::GetHardwareLatency() { 294 base::TimeDelta AUHALStream::GetHardwareLatency() {
293 if (!audio_unit_ || device_ == kAudioObjectUnknown) { 295 if (!audio_unit_ || device_ == kAudioObjectUnknown) {
294 DLOG(WARNING) << "AudioUnit is NULL or device ID is unknown"; 296 DLOG(WARNING) << "AudioUnit is NULL or device ID is unknown";
295 return 0.0; 297 return base::TimeDelta();
296 } 298 }
297 299
298 // Get audio unit latency. 300 // Get audio unit latency.
299 Float64 audio_unit_latency_sec = 0.0; 301 Float64 audio_unit_latency_sec = 0.0;
300 UInt32 size = sizeof(audio_unit_latency_sec); 302 UInt32 size = sizeof(audio_unit_latency_sec);
301 OSStatus result = AudioUnitGetProperty( 303 OSStatus result = AudioUnitGetProperty(
302 audio_unit_, 304 audio_unit_,
303 kAudioUnitProperty_Latency, 305 kAudioUnitProperty_Latency,
304 kAudioUnitScope_Global, 306 kAudioUnitScope_Global,
305 0, 307 0,
306 &audio_unit_latency_sec, 308 &audio_unit_latency_sec,
307 &size); 309 &size);
308 if (result != noErr) { 310 if (result != noErr) {
309 OSSTATUS_DLOG(WARNING, result) << "Could not get AudioUnit latency"; 311 OSSTATUS_DLOG(WARNING, result) << "Could not get AudioUnit latency";
310 return 0.0; 312 return base::TimeDelta();
311 } 313 }
312 314
313 // Get output audio device latency. 315 // Get output audio device latency.
314 static const AudioObjectPropertyAddress property_address = { 316 static const AudioObjectPropertyAddress property_address = {
315 kAudioDevicePropertyLatency, 317 kAudioDevicePropertyLatency,
316 kAudioDevicePropertyScopeOutput, 318 kAudioDevicePropertyScopeOutput,
317 kAudioObjectPropertyElementMaster 319 kAudioObjectPropertyElementMaster
318 }; 320 };
319 321
320 UInt32 device_latency_frames = 0; 322 UInt32 device_latency_frames = 0;
321 size = sizeof(device_latency_frames); 323 size = sizeof(device_latency_frames);
322 result = AudioObjectGetPropertyData( 324 result = AudioObjectGetPropertyData(
323 device_, 325 device_,
324 &property_address, 326 &property_address,
325 0, 327 0,
326 NULL, 328 NULL,
327 &size, 329 &size,
328 &device_latency_frames); 330 &device_latency_frames);
329 if (result != noErr) { 331 if (result != noErr) {
330 OSSTATUS_DLOG(WARNING, result) << "Could not get audio device latency"; 332 OSSTATUS_DLOG(WARNING, result) << "Could not get audio device latency";
331 return 0.0; 333 return base::TimeDelta();
332 } 334 }
333 335
334 return static_cast<double>((audio_unit_latency_sec * 336 int latency_frames = audio_unit_latency_sec * output_format_.mSampleRate +
335 output_format_.mSampleRate) + device_latency_frames); 337 device_latency_frames;
338
339 return AudioTimestampHelper::FramesToTime(latency_frames,
340 params_.sample_rate());
336 } 341 }
337 342
338 double AUHALStream::GetPlayoutLatency( 343 base::TimeTicks AUHALStream::GetPlayoutTime(
339 const AudioTimeStamp* output_time_stamp) { 344 const AudioTimeStamp* output_time_stamp) {
340 // Ensure mHostTime is valid. 345 // A platform bug has been observed where the platform sometimes reports that
346 // the next frames will be output at an invalid time or a time in the past.
347 // Because the target playout time cannot be invalid or in the past, return
348 // "now" in these cases.
341 if ((output_time_stamp->mFlags & kAudioTimeStampHostTimeValid) == 0) 349 if ((output_time_stamp->mFlags & kAudioTimeStampHostTimeValid) == 0)
342 return 0; 350 return base::TimeTicks::Now();
343 351
344 // Get the delay between the moment getting the callback and the scheduled 352 return std::max(base::TimeTicks::FromMachAbsoluteTime(
345 // time stamp that tells when the data is going to be played out. 353 output_time_stamp->mHostTime),
346 UInt64 output_time_ns = AudioConvertHostTimeToNanos( 354 base::TimeTicks::Now()) +
347 output_time_stamp->mHostTime); 355 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 } 356 }
360 357
361 void AUHALStream::UpdatePlayoutTimestamp(const AudioTimeStamp* timestamp) { 358 void AUHALStream::UpdatePlayoutTimestamp(const AudioTimeStamp* timestamp) {
362 if ((timestamp->mFlags & kAudioTimeStampSampleTimeValid) == 0) 359 if ((timestamp->mFlags & kAudioTimeStampSampleTimeValid) == 0)
363 return; 360 return;
364 361
365 if (last_sample_time_) { 362 if (last_sample_time_) {
366 DCHECK_NE(0U, last_number_of_frames_); 363 DCHECK_NE(0U, last_number_of_frames_);
367 UInt32 diff = 364 UInt32 diff =
368 static_cast<UInt32>(timestamp->mSampleTime - last_sample_time_); 365 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_); 553 OSStatus result = AudioUnitUninitialize(audio_unit_);
557 OSSTATUS_DLOG_IF(ERROR, result != noErr, result) 554 OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
558 << "AudioUnitUninitialize() failed."; 555 << "AudioUnitUninitialize() failed.";
559 result = AudioComponentInstanceDispose(audio_unit_); 556 result = AudioComponentInstanceDispose(audio_unit_);
560 OSSTATUS_DLOG_IF(ERROR, result != noErr, result) 557 OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
561 << "AudioComponentInstanceDispose() failed."; 558 << "AudioComponentInstanceDispose() failed.";
562 audio_unit_ = 0; 559 audio_unit_ = 0;
563 } 560 }
564 561
565 } // namespace media 562 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698