cc: Fix logic for detecting when raster tasks were throttled
[chromium-blink-merge.git] / media / base / audio_buffer_queue.cc
blobabe8fcef4eb4d6124c0893a3e0073823afae28bb
1 // Copyright 2013 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/base/audio_buffer_queue.h"
7 #include <algorithm>
9 #include "base/logging.h"
10 #include "media/base/audio_bus.h"
11 #include "media/base/buffers.h"
13 namespace media {
15 AudioBufferQueue::AudioBufferQueue() { Clear(); }
16 AudioBufferQueue::~AudioBufferQueue() {}
18 void AudioBufferQueue::Clear() {
19 buffers_.clear();
20 current_buffer_ = buffers_.begin();
21 current_buffer_offset_ = 0;
22 frames_ = 0;
23 current_time_ = kNoTimestamp();
26 void AudioBufferQueue::Append(const scoped_refptr<AudioBuffer>& buffer_in) {
27 // If we have just written the first buffer, update |current_time_| to be the
28 // start time.
29 if (buffers_.empty() && buffer_in->timestamp() != kNoTimestamp()) {
30 current_time_ = buffer_in->timestamp();
33 // Add the buffer to the queue. Inserting into deque invalidates all
34 // iterators, so point to the first buffer.
35 buffers_.push_back(buffer_in);
36 current_buffer_ = buffers_.begin();
38 // Update the |frames_| counter since we have added frames.
39 frames_ += buffer_in->frame_count();
40 CHECK_GT(frames_, 0); // make sure it doesn't overflow.
43 int AudioBufferQueue::ReadFrames(int frames,
44 int dest_frame_offset,
45 AudioBus* dest) {
46 DCHECK_GE(dest->frames(), frames + dest_frame_offset);
47 return InternalRead(frames, true, 0, dest_frame_offset, dest);
50 int AudioBufferQueue::PeekFrames(int frames,
51 int source_frame_offset,
52 int dest_frame_offset,
53 AudioBus* dest) {
54 DCHECK_GE(dest->frames(), frames);
55 return InternalRead(
56 frames, false, source_frame_offset, dest_frame_offset, dest);
59 void AudioBufferQueue::SeekFrames(int frames) {
60 // Perform seek only if we have enough bytes in the queue.
61 CHECK_LE(frames, frames_);
62 int taken = InternalRead(frames, true, 0, 0, NULL);
63 DCHECK_EQ(taken, frames);
66 int AudioBufferQueue::InternalRead(int frames,
67 bool advance_position,
68 int source_frame_offset,
69 int dest_frame_offset,
70 AudioBus* dest) {
71 // Counts how many frames are actually read from the buffer queue.
72 int taken = 0;
73 BufferQueue::iterator current_buffer = current_buffer_;
74 int current_buffer_offset = current_buffer_offset_;
76 int frames_to_skip = source_frame_offset;
77 while (taken < frames) {
78 // |current_buffer| is valid since the first time this buffer is appended
79 // with data. Make sure there is data to be processed.
80 if (current_buffer == buffers_.end())
81 break;
83 scoped_refptr<AudioBuffer> buffer = *current_buffer;
85 int remaining_frames_in_buffer =
86 buffer->frame_count() - current_buffer_offset;
88 if (frames_to_skip > 0) {
89 // If there are frames to skip, do it first. May need to skip into
90 // subsequent buffers.
91 int skipped = std::min(remaining_frames_in_buffer, frames_to_skip);
92 current_buffer_offset += skipped;
93 frames_to_skip -= skipped;
94 } else {
95 // Find the right amount to copy from the current buffer. We shall copy no
96 // more than |frames| frames in total and each single step copies no more
97 // than the current buffer size.
98 int copied = std::min(frames - taken, remaining_frames_in_buffer);
100 // if |dest| is NULL, there's no need to copy.
101 if (dest) {
102 buffer->ReadFrames(
103 copied, current_buffer_offset, dest_frame_offset + taken, dest);
106 // Increase total number of frames copied, which regulates when to end
107 // this loop.
108 taken += copied;
110 // We have read |copied| frames from the current buffer. Advance the
111 // offset.
112 current_buffer_offset += copied;
115 // Has the buffer has been consumed?
116 if (current_buffer_offset == buffer->frame_count()) {
117 if (advance_position) {
118 // Next buffer may not have timestamp, so we need to update current
119 // timestamp before switching to the next buffer.
120 UpdateCurrentTime(current_buffer, current_buffer_offset);
123 // If we are at the last buffer, no more data to be copied, so stop.
124 BufferQueue::iterator next = current_buffer + 1;
125 if (next == buffers_.end())
126 break;
128 // Advances the iterator.
129 current_buffer = next;
130 current_buffer_offset = 0;
134 if (advance_position) {
135 // Update the appropriate values since |taken| frames have been copied out.
136 frames_ -= taken;
137 DCHECK_GE(frames_, 0);
138 DCHECK(current_buffer_ != buffers_.end() || frames_ == 0);
140 UpdateCurrentTime(current_buffer, current_buffer_offset);
142 // Remove any buffers before the current buffer as there is no going
143 // backwards.
144 buffers_.erase(buffers_.begin(), current_buffer);
145 current_buffer_ = buffers_.begin();
146 current_buffer_offset_ = current_buffer_offset;
149 return taken;
152 void AudioBufferQueue::UpdateCurrentTime(BufferQueue::iterator buffer,
153 int offset) {
154 if (buffer != buffers_.end() && (*buffer)->timestamp() != kNoTimestamp()) {
155 double time_offset = ((*buffer)->duration().InMicroseconds() * offset) /
156 static_cast<double>((*buffer)->frame_count());
157 current_time_ =
158 (*buffer)->timestamp() + base::TimeDelta::FromMicroseconds(
159 static_cast<int64>(time_offset + 0.5));
163 } // namespace media