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

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

Issue 256163005: Introduce AudioClock to improve playback delay calculations. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: AudioClock Created 6 years, 7 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 | Annotate | Revision Log
OLDNEW
(Empty)
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 "base/logging.h"
8 #include "media/base/buffers.h"
9
10 namespace media {
11
12 AudioClock::AudioClock(int sample_rate)
13 : sample_rate_(sample_rate), last_endpoint_timestamp_(kNoTimestamp()) {
DaleCurtis 2014/04/30 20:36:33 Instead of storing sample_rate_ you could store a
scherkus (not reviewing) 2014/05/02 19:26:05 opted to combine the expression in CurrentMediaTim
14 }
15
16 AudioClock::~AudioClock() {
17 }
18
19 void AudioClock::WroteAudio(int frames,
20 int delay_frames,
21 float playback_rate,
22 base::TimeDelta timestamp) {
23 CHECK_GT(playback_rate, 0);
DaleCurtis 2014/04/30 20:36:33 DCHECK_GE(frames, 0) ? Add to WroteSilence() as we
scherkus (not reviewing) 2014/05/02 19:26:05 Done.
24 CHECK(timestamp != kNoTimestamp());
25
26 if (last_endpoint_timestamp_ == kNoTimestamp())
27 PushBufferedAudio(delay_frames, 0, kNoTimestamp());
28
29 TrimBufferedAudioToMatchDelay(delay_frames);
30 PushBufferedAudio(frames, playback_rate, timestamp);
31
32 last_endpoint_timestamp_ = timestamp;
33 }
34
35 void AudioClock::WroteSilence(int frames, int delay_frames) {
36 if (last_endpoint_timestamp_ == kNoTimestamp())
37 PushBufferedAudio(delay_frames, 0, kNoTimestamp());
38
39 TrimBufferedAudioToMatchDelay(delay_frames);
40 PushBufferedAudio(frames, 0, kNoTimestamp());
41 }
42
43 base::TimeDelta AudioClock::CurrentMediaTimestamp() const {
44 base::TimeDelta silence;
45 for (size_t i = 0; i < buffered_audio_.size(); ++i) {
46 // Account for silence ahead of the buffer closest to being played.
47 if (buffered_audio_[i].playback_rate == 0) {
48 silence += base::TimeDelta::FromMicroseconds(
DaleCurtis 2014/04/30 20:36:33 Instead of repeatedly converting this, it'd be bet
scherkus (not reviewing) 2014/05/02 19:26:05 Done.
49 base::Time::kMicrosecondsPerSecond * buffered_audio_[i].frames /
50 sample_rate_);
51 continue;
52 }
53
54 // Multiply by playback rate as frames represent time-scaled audio.
55 base::TimeDelta current_media_time = buffered_audio_[i].endpoint_timestamp;
DaleCurtis 2014/04/30 20:36:33 You could write this as a single return statement.
scherkus (not reviewing) 2014/05/02 19:26:05 Done.
56 current_media_time -= base::TimeDelta::FromMicroseconds(
57 base::Time::kMicrosecondsPerSecond * buffered_audio_[i].frames *
58 buffered_audio_[i].playback_rate / sample_rate_);
59 current_media_time -= silence;
60 return current_media_time;
61 }
62
63 // Either:
64 // 1) AudioClock is uninitialziated and we'll return kNoTimestamp()
65 // 2) All previously buffered audio has been replaced by silence,
66 // meaning media time is now at the last endpoint
67 return last_endpoint_timestamp_;
68 }
69
70 base::TimeDelta AudioClock::LastEndpointTimestamp() const {
DaleCurtis 2014/04/30 20:36:33 hacker_style() if you want.
scherkus (not reviewing) 2014/05/02 19:26:05 Done.
71 return last_endpoint_timestamp_;
72 }
73
74 void AudioClock::TrimBufferedAudioToMatchDelay(int delay_frames) {
75 if (buffered_audio_.empty())
76 return;
77
78 size_t i = buffered_audio_.size() - 1;
79 while (true) {
80 if (buffered_audio_[i].frames <= delay_frames) {
81 // Reached the end before accounting for all of |delay_frames|. This
DaleCurtis 2014/04/30 20:36:33 Reflow comment block. Line breaks are off.
scherkus (not reviewing) 2014/05/02 19:26:05 Done.
82 // means
83 // we haven't written enough audio data yet to account for hardware
84 // delay.
85 // In this case, do nothing.
86 if (i == 0)
87 return;
88
89 // Keep accounting for |delay_frames|.
90 delay_frames -= buffered_audio_[i].frames;
91 --i;
92 continue;
93 }
94
95 // All of |delay_frames| has been accounted for: adjust amount of frames
96 // left in current buffer. All preceeding elements with index < |i| should
97 // be considered played out and hence discared.
DaleCurtis 2014/04/30 20:36:33 discarded
scherkus (not reviewing) 2014/05/02 19:26:05 Done.
98 buffered_audio_[i].frames = delay_frames;
DaleCurtis 2014/04/30 20:36:33 Is this right? delay_frames may be 0 now. Shouldn
scherkus (not reviewing) 2014/05/02 19:26:05 Say we have: [20, 20, 20] with a delay of 45, we g
DaleCurtis 2014/05/02 19:37:06 Oh I see, I had this turned around and was conside
99 break;
100 }
101
102 // At this point |i| points at what will be the new head of
DaleCurtis 2014/04/30 20:36:33 Reflow comment block.
scherkus (not reviewing) 2014/05/02 19:26:05 Done.
103 // |buffered_audio_|
104 // however if it contains no audio it should be removed as well.
105 if (buffered_audio_[i].frames == 0)
106 ++i;
107
108 buffered_audio_.erase(buffered_audio_.begin(), buffered_audio_.begin() + i);
109 }
110
111 void AudioClock::PushBufferedAudio(int frames,
112 float playback_rate,
113 base::TimeDelta endpoint_timestamp) {
114 DCHECK_EQ(playback_rate == 0, endpoint_timestamp == kNoTimestamp());
DaleCurtis 2014/04/30 20:36:33 These DCHECKS are kind of a pain when they fire. I
scherkus (not reviewing) 2014/05/02 19:26:05 Done.
115
116 if (frames == 0)
117 return;
118
119 // Avoid creating extra elements where possible.
120 if (!buffered_audio_.empty() &&
121 buffered_audio_.back().playback_rate == playback_rate) {
122 buffered_audio_.back().frames += frames;
123 buffered_audio_.back().endpoint_timestamp = endpoint_timestamp;
124 return;
125 }
126
127 buffered_audio_.push_back(
128 BufferedAudio(frames, playback_rate, endpoint_timestamp));
129 }
130
131 AudioClock::BufferedAudio::BufferedAudio(int frames,
132 float playback_rate,
133 base::TimeDelta endpoint_timestamp)
134 : frames(frames),
135 playback_rate(playback_rate),
136 endpoint_timestamp(endpoint_timestamp) {
137 }
138
139 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698