1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/filters/audio_clock.h"
9 #include "base/logging.h"
10 #include "media/base/buffers.h"
14 AudioClock::AudioClock(base::TimeDelta start_timestamp
, int sample_rate
)
15 : start_timestamp_(start_timestamp
),
16 microseconds_per_frame_(
17 static_cast<double>(base::Time::kMicrosecondsPerSecond
) /
19 total_buffered_frames_(0),
20 front_timestamp_(start_timestamp
),
21 back_timestamp_(start_timestamp
) {
24 AudioClock::~AudioClock() {
27 void AudioClock::WroteAudio(int frames_written
,
30 double playback_rate
) {
31 DCHECK_GE(frames_written
, 0);
32 DCHECK_LE(frames_written
, frames_requested
);
33 DCHECK_GE(delay_frames
, 0);
34 DCHECK_GE(playback_rate
, 0);
36 // First write: initialize buffer with silence.
37 if (start_timestamp_
== front_timestamp_
&& buffered_
.empty())
38 PushBufferedAudioData(delay_frames
, 0.0);
40 // Move frames from |buffered_| into the computed timestamp based on
43 // The ordering of compute -> push -> pop eliminates unnecessary memory
44 // reallocations in cases where |buffered_| gets emptied.
45 int64_t frames_played
=
46 std::max(INT64_C(0), total_buffered_frames_
- delay_frames
);
47 PushBufferedAudioData(frames_written
, playback_rate
);
48 PushBufferedAudioData(frames_requested
- frames_written
, 0.0);
49 PopBufferedAudioData(frames_played
);
51 // Update our front and back timestamps. The back timestamp is considered the
52 // authoritative source of truth, so base the front timestamp on range of data
53 // buffered. Doing so avoids accumulation errors on the front timestamp.
54 back_timestamp_
+= base::TimeDelta::FromMicroseconds(
55 frames_written
* playback_rate
* microseconds_per_frame_
);
56 // Don't let front timestamp move earlier in time, as could occur due to delay
57 // frames pushed in the first write, above.
58 front_timestamp_
= std::max(front_timestamp_
,
59 back_timestamp_
- ComputeBufferedMediaDuration());
60 DCHECK_GE(front_timestamp_
, start_timestamp_
);
61 DCHECK_LE(front_timestamp_
, back_timestamp_
);
64 void AudioClock::CompensateForSuspendedWrites(base::TimeDelta elapsed
,
66 const int64_t frames_elapsed
=
67 elapsed
.InMicroseconds() / microseconds_per_frame_
+ 0.5;
69 // No need to do anything if we're within the limits of our played out audio
70 // or there are no delay frames, the next WroteAudio() call will expire
71 // everything correctly.
72 if (frames_elapsed
< total_buffered_frames_
|| !delay_frames
)
75 // Otherwise, flush everything and prime with the delay frames.
76 WroteAudio(0, 0, 0, 0);
77 DCHECK(buffered_
.empty());
78 PushBufferedAudioData(delay_frames
, 0.0);
81 base::TimeDelta
AudioClock::TimeUntilPlayback(base::TimeDelta timestamp
) const {
82 DCHECK_GE(timestamp
, front_timestamp_
);
83 DCHECK_LE(timestamp
, back_timestamp_
);
85 int64_t frames_until_timestamp
= 0;
86 double timestamp_us
= timestamp
.InMicroseconds();
87 double media_time_us
= front_timestamp_
.InMicroseconds();
89 for (size_t i
= 0; i
< buffered_
.size(); ++i
) {
90 // Leading silence is always accounted prior to anything else.
91 if (buffered_
[i
].playback_rate
== 0) {
92 frames_until_timestamp
+= buffered_
[i
].frames
;
96 // Calculate upper bound on media time for current block of buffered frames.
97 double delta_us
= buffered_
[i
].frames
* buffered_
[i
].playback_rate
*
98 microseconds_per_frame_
;
99 double max_media_time_us
= media_time_us
+ delta_us
;
101 // Determine amount of media time to convert to frames for current block. If
102 // target timestamp falls within current block, scale the amount of frames
103 // based on remaining amount of media time.
104 if (timestamp_us
<= max_media_time_us
) {
105 frames_until_timestamp
+=
106 buffered_
[i
].frames
* (timestamp_us
- media_time_us
) / delta_us
;
110 media_time_us
= max_media_time_us
;
111 frames_until_timestamp
+= buffered_
[i
].frames
;
114 return base::TimeDelta::FromMicroseconds(frames_until_timestamp
*
115 microseconds_per_frame_
);
118 void AudioClock::ContiguousAudioDataBufferedForTesting(
119 base::TimeDelta
* total
,
120 base::TimeDelta
* same_rate_total
) const {
121 double scaled_frames
= 0;
122 double scaled_frames_at_same_rate
= 0;
123 bool found_silence
= false;
124 for (size_t i
= 0; i
< buffered_
.size(); ++i
) {
125 if (buffered_
[i
].playback_rate
== 0) {
126 found_silence
= true;
130 // Any buffered silence breaks our contiguous stretch of audio data.
134 scaled_frames
+= (buffered_
[i
].frames
* buffered_
[i
].playback_rate
);
137 scaled_frames_at_same_rate
= scaled_frames
;
140 *total
= base::TimeDelta::FromMicroseconds(scaled_frames
*
141 microseconds_per_frame_
);
142 *same_rate_total
= base::TimeDelta::FromMicroseconds(
143 scaled_frames_at_same_rate
* microseconds_per_frame_
);
146 AudioClock::AudioData::AudioData(int64_t frames
, double playback_rate
)
147 : frames(frames
), playback_rate(playback_rate
) {
150 void AudioClock::PushBufferedAudioData(int64_t frames
, double playback_rate
) {
154 total_buffered_frames_
+= frames
;
156 // Avoid creating extra elements where possible.
157 if (!buffered_
.empty() && buffered_
.back().playback_rate
== playback_rate
) {
158 buffered_
.back().frames
+= frames
;
162 buffered_
.push_back(AudioData(frames
, playback_rate
));
165 void AudioClock::PopBufferedAudioData(int64_t frames
) {
166 DCHECK_LE(frames
, total_buffered_frames_
);
168 total_buffered_frames_
-= frames
;
171 int64_t frames_to_pop
= std::min(buffered_
.front().frames
, frames
);
172 buffered_
.front().frames
-= frames_to_pop
;
173 if (buffered_
.front().frames
== 0)
174 buffered_
.pop_front();
176 frames
-= frames_to_pop
;
180 base::TimeDelta
AudioClock::ComputeBufferedMediaDuration() const {
181 double scaled_frames
= 0;
182 for (const auto& buffer
: buffered_
)
183 scaled_frames
+= buffer
.frames
* buffer
.playback_rate
;
184 return base::TimeDelta::FromMicroseconds(scaled_frames
*
185 microseconds_per_frame_
);