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

Side by Side Diff: media/filters/audio_clock.cc

Issue 1711473002: Use double microseconds for tracking back/front timestamp in AudioClock. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixes for feedback && rebase. Created 4 years, 10 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
« no previous file with comments | « media/filters/audio_clock.h ('k') | media/filters/audio_clock_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 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/filters/audio_clock.h" 5 #include "media/filters/audio_clock.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 #include <stddef.h> 8 #include <stddef.h>
9 9
10 #include <algorithm> 10 #include <algorithm>
11 #include <cmath>
11 12
12 #include "base/logging.h" 13 #include "base/logging.h"
13 14
14 namespace media { 15 namespace media {
15 16
16 AudioClock::AudioClock(base::TimeDelta start_timestamp, int sample_rate) 17 AudioClock::AudioClock(base::TimeDelta start_timestamp, int sample_rate)
17 : start_timestamp_(start_timestamp), 18 : start_timestamp_(start_timestamp),
18 microseconds_per_frame_( 19 microseconds_per_frame_(
19 static_cast<double>(base::Time::kMicrosecondsPerSecond) / 20 static_cast<double>(base::Time::kMicrosecondsPerSecond) /
20 sample_rate), 21 sample_rate),
21 total_buffered_frames_(0), 22 total_buffered_frames_(0),
22 front_timestamp_(start_timestamp), 23 front_timestamp_micros_(start_timestamp.InMicroseconds()),
23 back_timestamp_(start_timestamp) { 24 back_timestamp_micros_(start_timestamp.InMicroseconds()) {}
24 }
25 25
26 AudioClock::~AudioClock() { 26 AudioClock::~AudioClock() {
27 } 27 }
28 28
29 void AudioClock::WroteAudio(int frames_written, 29 void AudioClock::WroteAudio(int frames_written,
30 int frames_requested, 30 int frames_requested,
31 int delay_frames, 31 int delay_frames,
32 double playback_rate) { 32 double playback_rate) {
33 DCHECK_GE(frames_written, 0); 33 DCHECK_GE(frames_written, 0);
34 DCHECK_LE(frames_written, frames_requested); 34 DCHECK_LE(frames_written, frames_requested);
35 DCHECK_GE(delay_frames, 0); 35 DCHECK_GE(delay_frames, 0);
36 DCHECK_GE(playback_rate, 0); 36 DCHECK_GE(playback_rate, 0);
37 37
38 // First write: initialize buffer with silence. 38 // First write: initialize buffer with silence.
39 if (start_timestamp_ == front_timestamp_ && buffered_.empty()) 39 if (start_timestamp_.InMicroseconds() == front_timestamp_micros_ &&
40 buffered_.empty()) {
40 PushBufferedAudioData(delay_frames, 0.0); 41 PushBufferedAudioData(delay_frames, 0.0);
42 }
41 43
42 // Move frames from |buffered_| into the computed timestamp based on 44 // Move frames from |buffered_| into the computed timestamp based on
43 // |delay_frames|. 45 // |delay_frames|.
44 // 46 //
45 // The ordering of compute -> push -> pop eliminates unnecessary memory 47 // The ordering of compute -> push -> pop eliminates unnecessary memory
46 // reallocations in cases where |buffered_| gets emptied. 48 // reallocations in cases where |buffered_| gets emptied.
47 int64_t frames_played = 49 int64_t frames_played =
48 std::max(INT64_C(0), total_buffered_frames_ - delay_frames); 50 std::max(INT64_C(0), total_buffered_frames_ - delay_frames);
49 PushBufferedAudioData(frames_written, playback_rate); 51 PushBufferedAudioData(frames_written, playback_rate);
50 PushBufferedAudioData(frames_requested - frames_written, 0.0); 52 PushBufferedAudioData(frames_requested - frames_written, 0.0);
51 PopBufferedAudioData(frames_played); 53 PopBufferedAudioData(frames_played);
52 54
53 // Update our front and back timestamps. The back timestamp is considered the 55 // Update our front and back timestamps. The back timestamp is considered the
54 // authoritative source of truth, so base the front timestamp on range of data 56 // authoritative source of truth, so base the front timestamp on range of data
55 // buffered. Doing so avoids accumulation errors on the front timestamp. 57 // buffered. Doing so avoids accumulation errors on the front timestamp.
56 back_timestamp_ += base::TimeDelta::FromMicroseconds( 58 back_timestamp_micros_ +=
57 frames_written * playback_rate * microseconds_per_frame_); 59 frames_written * playback_rate * microseconds_per_frame_;
60
58 // Don't let front timestamp move earlier in time, as could occur due to delay 61 // Don't let front timestamp move earlier in time, as could occur due to delay
59 // frames pushed in the first write, above. 62 // frames pushed in the first write, above.
60 front_timestamp_ = std::max(front_timestamp_, 63 front_timestamp_micros_ =
61 back_timestamp_ - ComputeBufferedMediaDuration()); 64 std::max(front_timestamp_micros_,
62 DCHECK_GE(front_timestamp_, start_timestamp_); 65 back_timestamp_micros_ - ComputeBufferedMediaDurationMicros());
63 DCHECK_LE(front_timestamp_, back_timestamp_); 66 DCHECK_GE(front_timestamp_micros_, start_timestamp_.InMicroseconds());
67 DCHECK_LE(front_timestamp_micros_, back_timestamp_micros_);
64 } 68 }
65 69
66 void AudioClock::CompensateForSuspendedWrites(base::TimeDelta elapsed, 70 void AudioClock::CompensateForSuspendedWrites(base::TimeDelta elapsed,
67 int delay_frames) { 71 int delay_frames) {
68 const int64_t frames_elapsed = 72 const int64_t frames_elapsed =
69 elapsed.InMicroseconds() / microseconds_per_frame_ + 0.5; 73 elapsed.InMicroseconds() / microseconds_per_frame_ + 0.5;
70 74
71 // No need to do anything if we're within the limits of our played out audio 75 // No need to do anything if we're within the limits of our played out audio
72 // or there are no delay frames, the next WroteAudio() call will expire 76 // or there are no delay frames, the next WroteAudio() call will expire
73 // everything correctly. 77 // everything correctly.
74 if (frames_elapsed < total_buffered_frames_ || !delay_frames) 78 if (frames_elapsed < total_buffered_frames_ || !delay_frames)
75 return; 79 return;
76 80
77 // Otherwise, flush everything and prime with the delay frames. 81 // Otherwise, flush everything and prime with the delay frames.
78 WroteAudio(0, 0, 0, 0); 82 WroteAudio(0, 0, 0, 0);
79 DCHECK(buffered_.empty()); 83 DCHECK(buffered_.empty());
80 PushBufferedAudioData(delay_frames, 0.0); 84 PushBufferedAudioData(delay_frames, 0.0);
81 } 85 }
82 86
83 base::TimeDelta AudioClock::TimeUntilPlayback(base::TimeDelta timestamp) const { 87 base::TimeDelta AudioClock::TimeUntilPlayback(base::TimeDelta timestamp) const {
84 DCHECK_GE(timestamp, front_timestamp_); 88 // Use front/back_timestamp() methods rather than internal members. The public
85 DCHECK_LE(timestamp, back_timestamp_); 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());
86 93
87 int64_t frames_until_timestamp = 0; 94 int64_t frames_until_timestamp = 0;
88 double timestamp_us = timestamp.InMicroseconds(); 95 double timestamp_us = timestamp.InMicroseconds();
89 double media_time_us = front_timestamp_.InMicroseconds(); 96 double media_time_us = front_timestamp().InMicroseconds();
90 97
91 for (size_t i = 0; i < buffered_.size(); ++i) { 98 for (size_t i = 0; i < buffered_.size(); ++i) {
92 // Leading silence is always accounted prior to anything else. 99 // Leading silence is always accounted prior to anything else.
93 if (buffered_[i].playback_rate == 0) { 100 if (buffered_[i].playback_rate == 0) {
94 frames_until_timestamp += buffered_[i].frames; 101 frames_until_timestamp += buffered_[i].frames;
95 continue; 102 continue;
96 } 103 }
97 104
98 // Calculate upper bound on media time for current block of buffered frames. 105 // Calculate upper bound on media time for current block of buffered frames.
99 double delta_us = buffered_[i].frames * buffered_[i].playback_rate * 106 double delta_us = buffered_[i].frames * buffered_[i].playback_rate *
100 microseconds_per_frame_; 107 microseconds_per_frame_;
101 double max_media_time_us = media_time_us + delta_us; 108 double max_media_time_us = media_time_us + delta_us;
102 109
103 // Determine amount of media time to convert to frames for current block. If 110 // Determine amount of media time to convert to frames for current block. If
104 // target timestamp falls within current block, scale the amount of frames 111 // target timestamp falls within current block, scale the amount of frames
105 // based on remaining amount of media time. 112 // based on remaining amount of media time.
106 if (timestamp_us <= max_media_time_us) { 113 if (timestamp_us <= max_media_time_us) {
107 frames_until_timestamp += 114 frames_until_timestamp +=
108 buffered_[i].frames * (timestamp_us - media_time_us) / delta_us; 115 buffered_[i].frames * (timestamp_us - media_time_us) / delta_us;
109 break; 116 break;
110 } 117 }
111 118
112 media_time_us = max_media_time_us; 119 media_time_us = max_media_time_us;
113 frames_until_timestamp += buffered_[i].frames; 120 frames_until_timestamp += buffered_[i].frames;
114 } 121 }
115 122
116 return base::TimeDelta::FromMicroseconds(frames_until_timestamp * 123 return base::TimeDelta::FromMicroseconds(
117 microseconds_per_frame_); 124 std::round(frames_until_timestamp * microseconds_per_frame_));
118 } 125 }
119 126
120 void AudioClock::ContiguousAudioDataBufferedForTesting( 127 void AudioClock::ContiguousAudioDataBufferedForTesting(
121 base::TimeDelta* total, 128 base::TimeDelta* total,
122 base::TimeDelta* same_rate_total) const { 129 base::TimeDelta* same_rate_total) const {
123 double scaled_frames = 0; 130 double scaled_frames = 0;
124 double scaled_frames_at_same_rate = 0; 131 double scaled_frames_at_same_rate = 0;
125 bool found_silence = false; 132 bool found_silence = false;
126 for (size_t i = 0; i < buffered_.size(); ++i) { 133 for (size_t i = 0; i < buffered_.size(); ++i) {
127 if (buffered_[i].playback_rate == 0) { 134 if (buffered_[i].playback_rate == 0) {
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
172 while (frames > 0) { 179 while (frames > 0) {
173 int64_t frames_to_pop = std::min(buffered_.front().frames, frames); 180 int64_t frames_to_pop = std::min(buffered_.front().frames, frames);
174 buffered_.front().frames -= frames_to_pop; 181 buffered_.front().frames -= frames_to_pop;
175 if (buffered_.front().frames == 0) 182 if (buffered_.front().frames == 0)
176 buffered_.pop_front(); 183 buffered_.pop_front();
177 184
178 frames -= frames_to_pop; 185 frames -= frames_to_pop;
179 } 186 }
180 } 187 }
181 188
182 base::TimeDelta AudioClock::ComputeBufferedMediaDuration() const { 189 double AudioClock::ComputeBufferedMediaDurationMicros() const {
183 double scaled_frames = 0; 190 double scaled_frames = 0;
184 for (const auto& buffer : buffered_) 191 for (const auto& buffer : buffered_)
185 scaled_frames += buffer.frames * buffer.playback_rate; 192 scaled_frames += buffer.frames * buffer.playback_rate;
186 return base::TimeDelta::FromMicroseconds(scaled_frames * 193 return scaled_frames * microseconds_per_frame_;
187 microseconds_per_frame_);
188 } 194 }
189 195
190 } // namespace media 196 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/audio_clock.h ('k') | media/filters/audio_clock_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698