Revert "[M120 Migration]Fix for crash during chrome exit"
[platform/framework/web/chromium-efl.git] / media / filters / audio_clock.cc
1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/filters/audio_clock.h"
6
7 #include <stdint.h>
8 #include <stddef.h>
9
10 #include <algorithm>
11 #include <cmath>
12
13 #include "base/check_op.h"
14 #include "base/numerics/safe_conversions.h"
15
16 namespace media {
17
18 AudioClock::AudioClock(base::TimeDelta start_timestamp, int sample_rate)
19     : start_timestamp_(start_timestamp),
20       microseconds_per_frame_(
21           static_cast<double>(base::Time::kMicrosecondsPerSecond) /
22           sample_rate),
23       total_buffered_frames_(0),
24       front_timestamp_micros_(start_timestamp.InMicrosecondsF()),
25       back_timestamp_micros_(start_timestamp.InMicrosecondsF()) {}
26
27 AudioClock::~AudioClock() = default;
28
29 void AudioClock::WroteAudio(int frames_written,
30                             int frames_requested,
31                             int delay_frames,
32                             double playback_rate) {
33   DCHECK_GE(frames_written, 0);
34   DCHECK_LE(frames_written, frames_requested);
35   DCHECK_GE(delay_frames, 0);
36   DCHECK_GE(playback_rate, 0);
37
38   // First write: initialize buffer with silence.
39   if (start_timestamp_.InMicrosecondsF() == front_timestamp_micros_ &&
40       buffered_.empty()) {
41     PushBufferedAudioData(delay_frames, 0.0);
42   }
43
44   // Move frames from |buffered_| into the computed timestamp based on
45   // |delay_frames|.
46   //
47   // The ordering of compute -> push -> pop eliminates unnecessary memory
48   // reallocations in cases where |buffered_| gets emptied.
49   int64_t frames_played =
50       std::max(INT64_C(0), total_buffered_frames_ - delay_frames);
51   PushBufferedAudioData(frames_written, playback_rate);
52   PushBufferedAudioData(frames_requested - frames_written, 0.0);
53   PopBufferedAudioData(frames_played);
54
55   // Update our front and back timestamps.  The back timestamp is considered the
56   // authoritative source of truth, so base the front timestamp on range of data
57   // buffered.  Doing so avoids accumulation errors on the front timestamp.
58   back_timestamp_micros_ +=
59       frames_written * playback_rate * microseconds_per_frame_;
60
61   // Don't let front timestamp move earlier in time, as could occur due to delay
62   // frames pushed in the first write, above.
63   front_timestamp_micros_ =
64       std::max(front_timestamp_micros_,
65                back_timestamp_micros_ - ComputeBufferedMediaDurationMicros());
66   DCHECK_GE(front_timestamp_micros_, start_timestamp_.InMicrosecondsF());
67   DCHECK_LE(front_timestamp_micros_, back_timestamp_micros_);
68 }
69
70 void AudioClock::CompensateForSuspendedWrites(base::TimeDelta elapsed,
71                                               int delay_frames) {
72   const int64_t frames_elapsed = base::ClampRound<int64_t>(
73       elapsed.InMicrosecondsF() / microseconds_per_frame_);
74
75   // No need to do anything if we're within the limits of our played out audio
76   // or there are no delay frames, the next WroteAudio() call will expire
77   // everything correctly.
78   if (frames_elapsed < total_buffered_frames_ || !delay_frames)
79     return;
80
81   // Otherwise, flush everything and prime with the delay frames.
82   WroteAudio(0, 0, 0, 0);
83   DCHECK(buffered_.empty());
84   PushBufferedAudioData(delay_frames, 0.0);
85 }
86
87 base::TimeDelta AudioClock::TimeUntilPlayback(base::TimeDelta timestamp) const {
88   // Use front/back_timestamp() methods rather than internal members. The public
89   // methods round to the nearest microsecond for conversion to TimeDelta and
90   // the rounded value will likely be used by the caller.
91   DCHECK_GE(timestamp, front_timestamp());
92   DCHECK_LE(timestamp, back_timestamp());
93
94   int64_t frames_until_timestamp = 0;
95   double timestamp_us = timestamp.InMicrosecondsF();
96   double media_time_us = front_timestamp().InMicrosecondsF();
97
98   for (size_t i = 0; i < buffered_.size(); ++i) {
99     // Leading silence is always accounted prior to anything else.
100     if (buffered_[i].playback_rate == 0) {
101       frames_until_timestamp += buffered_[i].frames;
102       continue;
103     }
104
105     // Calculate upper bound on media time for current block of buffered frames.
106     double delta_us = buffered_[i].frames * buffered_[i].playback_rate *
107                       microseconds_per_frame_;
108     double max_media_time_us = media_time_us + delta_us;
109
110     // Determine amount of media time to convert to frames for current block. If
111     // target timestamp falls within current block, scale the amount of frames
112     // based on remaining amount of media time.
113     if (timestamp_us <= max_media_time_us) {
114       frames_until_timestamp +=
115           buffered_[i].frames * (timestamp_us - media_time_us) / delta_us;
116       break;
117     }
118
119     media_time_us = max_media_time_us;
120     frames_until_timestamp += buffered_[i].frames;
121   }
122
123   return base::Microseconds(
124       std::round(frames_until_timestamp * microseconds_per_frame_));
125 }
126
127 void AudioClock::ContiguousAudioDataBufferedForTesting(
128     base::TimeDelta* total,
129     base::TimeDelta* same_rate_total) const {
130   double scaled_frames = 0;
131   double scaled_frames_at_same_rate = 0;
132   bool found_silence = false;
133   for (size_t i = 0; i < buffered_.size(); ++i) {
134     if (buffered_[i].playback_rate == 0) {
135       found_silence = true;
136       continue;
137     }
138
139     // Any buffered silence breaks our contiguous stretch of audio data.
140     if (found_silence)
141       break;
142
143     scaled_frames += (buffered_[i].frames * buffered_[i].playback_rate);
144
145     if (i == 0)
146       scaled_frames_at_same_rate = scaled_frames;
147   }
148
149   *total = base::Microseconds(scaled_frames * microseconds_per_frame_);
150   *same_rate_total =
151       base::Microseconds(scaled_frames_at_same_rate * microseconds_per_frame_);
152 }
153
154 AudioClock::AudioData::AudioData(int64_t frames, double playback_rate)
155     : frames(frames), playback_rate(playback_rate) {
156 }
157
158 void AudioClock::PushBufferedAudioData(int64_t frames, double playback_rate) {
159   if (frames == 0)
160     return;
161
162   total_buffered_frames_ += frames;
163
164   // Avoid creating extra elements where possible.
165   if (!buffered_.empty() && buffered_.back().playback_rate == playback_rate) {
166     buffered_.back().frames += frames;
167     return;
168   }
169
170   buffered_.push_back(AudioData(frames, playback_rate));
171 }
172
173 void AudioClock::PopBufferedAudioData(int64_t frames) {
174   DCHECK_LE(frames, total_buffered_frames_);
175
176   total_buffered_frames_ -= frames;
177
178   while (frames > 0) {
179     int64_t frames_to_pop = std::min(buffered_.front().frames, frames);
180     buffered_.front().frames -= frames_to_pop;
181     if (buffered_.front().frames == 0)
182       buffered_.pop_front();
183
184     frames -= frames_to_pop;
185   }
186 }
187
188 double AudioClock::ComputeBufferedMediaDurationMicros() const {
189   double scaled_frames = 0;
190   for (const auto& buffer : buffered_)
191     scaled_frames += buffer.frames * buffer.playback_rate;
192   return scaled_frames * microseconds_per_frame_;
193 }
194
195 }  // namespace media