Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / media / filters / audio_clock.cc
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.
4
5 #include "media/filters/audio_clock.h"
6
7 #include <algorithm>
8
9 #include "base/logging.h"
10 #include "media/base/buffers.h"
11
12 namespace media {
13
14 AudioClock::AudioClock(base::TimeDelta start_timestamp, int sample_rate)
15     : start_timestamp_(start_timestamp),
16       sample_rate_(sample_rate),
17       microseconds_per_frame_(
18           static_cast<double>(base::Time::kMicrosecondsPerSecond) /
19           sample_rate),
20       total_buffered_frames_(0),
21       front_timestamp_(start_timestamp),
22       back_timestamp_(start_timestamp) {
23 }
24
25 AudioClock::~AudioClock() {
26 }
27
28 void AudioClock::WroteAudio(int frames_written,
29                             int frames_requested,
30                             int delay_frames,
31                             float playback_rate) {
32   DCHECK_GE(frames_written, 0);
33   DCHECK_LE(frames_written, frames_requested);
34   DCHECK_GE(delay_frames, 0);
35   DCHECK_GE(playback_rate, 0);
36
37   // First write: initialize buffer with silence.
38   if (start_timestamp_ == front_timestamp_ && buffered_.empty())
39     PushBufferedAudioData(delay_frames, 0.0f);
40
41   // Move frames from |buffered_| into the computed timestamp based on
42   // |delay_frames|.
43   //
44   // The ordering of compute -> push -> pop eliminates unnecessary memory
45   // reallocations in cases where |buffered_| gets emptied.
46   int64_t frames_played =
47       std::max(INT64_C(0), total_buffered_frames_ - delay_frames);
48   front_timestamp_ += ComputeBufferedMediaTime(frames_played);
49   PushBufferedAudioData(frames_written, playback_rate);
50   PushBufferedAudioData(frames_requested - frames_written, 0.0f);
51   PopBufferedAudioData(frames_played);
52
53   back_timestamp_ += base::TimeDelta::FromMicroseconds(
54       frames_written * playback_rate * microseconds_per_frame_);
55
56   // Update cached values.
57   double scaled_frames = 0;
58   double scaled_frames_at_same_rate = 0;
59   bool found_silence = false;
60   for (size_t i = 0; i < buffered_.size(); ++i) {
61     if (buffered_[i].playback_rate == 0) {
62       found_silence = true;
63       continue;
64     }
65
66     // Any buffered silence breaks our contiguous stretch of audio data.
67     if (found_silence)
68       break;
69
70     scaled_frames += (buffered_[i].frames * buffered_[i].playback_rate);
71
72     if (i == 0)
73       scaled_frames_at_same_rate = scaled_frames;
74   }
75
76   contiguous_audio_data_buffered_ = base::TimeDelta::FromMicroseconds(
77       scaled_frames * microseconds_per_frame_);
78   contiguous_audio_data_buffered_at_same_rate_ =
79       base::TimeDelta::FromMicroseconds(scaled_frames_at_same_rate *
80                                         microseconds_per_frame_);
81 }
82
83 base::TimeDelta AudioClock::TimestampSinceWriting(
84     base::TimeDelta time_since_writing) const {
85   int64_t frames_played_since_writing = std::min(
86       total_buffered_frames_,
87       static_cast<int64_t>(time_since_writing.InSecondsF() * sample_rate_));
88   return front_timestamp_ +
89          ComputeBufferedMediaTime(frames_played_since_writing);
90 }
91
92 base::TimeDelta AudioClock::TimeUntilPlayback(base::TimeDelta timestamp) const {
93   DCHECK(timestamp >= front_timestamp_);
94   DCHECK(timestamp <= back_timestamp_);
95
96   int64_t frames_until_timestamp = 0;
97   double timestamp_us = timestamp.InMicroseconds();
98   double media_time_us = front_timestamp_.InMicroseconds();
99
100   for (size_t i = 0; i < buffered_.size(); ++i) {
101     // Leading silence is always accounted prior to anything else.
102     if (buffered_[i].playback_rate == 0) {
103       frames_until_timestamp += buffered_[i].frames;
104       continue;
105     }
106
107     // Calculate upper bound on media time for current block of buffered frames.
108     double delta_us = buffered_[i].frames * buffered_[i].playback_rate *
109                       microseconds_per_frame_;
110     double max_media_time_us = media_time_us + delta_us;
111
112     // Determine amount of media time to convert to frames for current block. If
113     // target timestamp falls within current block, scale the amount of frames
114     // based on remaining amount of media time.
115     if (timestamp_us <= max_media_time_us) {
116       frames_until_timestamp +=
117           buffered_[i].frames * (timestamp_us - media_time_us) / delta_us;
118       break;
119     }
120
121     media_time_us = max_media_time_us;
122     frames_until_timestamp += buffered_[i].frames;
123   }
124
125   return base::TimeDelta::FromMicroseconds(frames_until_timestamp *
126                                            microseconds_per_frame_);
127 }
128
129 AudioClock::AudioData::AudioData(int64_t frames, float playback_rate)
130     : frames(frames), playback_rate(playback_rate) {
131 }
132
133 void AudioClock::PushBufferedAudioData(int64_t frames, float playback_rate) {
134   if (frames == 0)
135     return;
136
137   total_buffered_frames_ += frames;
138
139   // Avoid creating extra elements where possible.
140   if (!buffered_.empty() && buffered_.back().playback_rate == playback_rate) {
141     buffered_.back().frames += frames;
142     return;
143   }
144
145   buffered_.push_back(AudioData(frames, playback_rate));
146 }
147
148 void AudioClock::PopBufferedAudioData(int64_t frames) {
149   DCHECK_LE(frames, total_buffered_frames_);
150
151   total_buffered_frames_ -= frames;
152
153   while (frames > 0) {
154     int64_t frames_to_pop = std::min(buffered_.front().frames, frames);
155     buffered_.front().frames -= frames_to_pop;
156     if (buffered_.front().frames == 0)
157       buffered_.pop_front();
158
159     frames -= frames_to_pop;
160   }
161 }
162
163 base::TimeDelta AudioClock::ComputeBufferedMediaTime(int64_t frames) const {
164   DCHECK_LE(frames, total_buffered_frames_);
165
166   double scaled_frames = 0;
167   for (size_t i = 0; i < buffered_.size() && frames > 0; ++i) {
168     int64_t min_frames = std::min(buffered_[i].frames, frames);
169     scaled_frames += min_frames * buffered_[i].playback_rate;
170     frames -= min_frames;
171   }
172
173   return base::TimeDelta::FromMicroseconds(scaled_frames *
174                                            microseconds_per_frame_);
175 }
176
177 }  // namespace media