Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / media / base / audio_buffer_queue.cc
blobdfa655a3be33498c11f125d12ff32d68626cacc0
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"
12 namespace media {
14 AudioBufferQueue::AudioBufferQueue() { Clear(); }
15 AudioBufferQueue::~AudioBufferQueue() {}
17 void AudioBufferQueue::Clear() {
18 buffers_.clear();
19 current_buffer_ = buffers_.begin();
20 current_buffer_offset_ = 0;
21 frames_ = 0;
24 void AudioBufferQueue::Append(const scoped_refptr<AudioBuffer>& buffer_in) {
25 // Add the buffer to the queue. Inserting into deque invalidates all
26 // iterators, so point to the first buffer.
27 buffers_.push_back(buffer_in);
28 current_buffer_ = buffers_.begin();
30 // Update the |frames_| counter since we have added frames.
31 frames_ += buffer_in->frame_count();
32 CHECK_GT(frames_, 0); // make sure it doesn't overflow.
35 int AudioBufferQueue::ReadFrames(int frames,
36 int dest_frame_offset,
37 AudioBus* dest) {
38 DCHECK_GE(dest->frames(), frames + dest_frame_offset);
39 return InternalRead(frames, true, 0, dest_frame_offset, dest);
42 int AudioBufferQueue::PeekFrames(int frames,
43 int source_frame_offset,
44 int dest_frame_offset,
45 AudioBus* dest) {
46 DCHECK_GE(dest->frames(), frames);
47 return InternalRead(
48 frames, false, source_frame_offset, dest_frame_offset, dest);
51 void AudioBufferQueue::SeekFrames(int frames) {
52 // Perform seek only if we have enough bytes in the queue.
53 CHECK_LE(frames, frames_);
54 int taken = InternalRead(frames, true, 0, 0, NULL);
55 DCHECK_EQ(taken, frames);
58 int AudioBufferQueue::InternalRead(int frames,
59 bool advance_position,
60 int source_frame_offset,
61 int dest_frame_offset,
62 AudioBus* dest) {
63 // Counts how many frames are actually read from the buffer queue.
64 int taken = 0;
65 BufferQueue::iterator current_buffer = current_buffer_;
66 int current_buffer_offset = current_buffer_offset_;
68 int frames_to_skip = source_frame_offset;
69 while (taken < frames) {
70 // |current_buffer| is valid since the first time this buffer is appended
71 // with data. Make sure there is data to be processed.
72 if (current_buffer == buffers_.end())
73 break;
75 scoped_refptr<AudioBuffer> buffer = *current_buffer;
77 int remaining_frames_in_buffer =
78 buffer->frame_count() - current_buffer_offset;
80 if (frames_to_skip > 0) {
81 // If there are frames to skip, do it first. May need to skip into
82 // subsequent buffers.
83 int skipped = std::min(remaining_frames_in_buffer, frames_to_skip);
84 current_buffer_offset += skipped;
85 frames_to_skip -= skipped;
86 } else {
87 // Find the right amount to copy from the current buffer. We shall copy no
88 // more than |frames| frames in total and each single step copies no more
89 // than the current buffer size.
90 int copied = std::min(frames - taken, remaining_frames_in_buffer);
92 // if |dest| is NULL, there's no need to copy.
93 if (dest) {
94 buffer->ReadFrames(
95 copied, current_buffer_offset, dest_frame_offset + taken, dest);
98 // Increase total number of frames copied, which regulates when to end
99 // this loop.
100 taken += copied;
102 // We have read |copied| frames from the current buffer. Advance the
103 // offset.
104 current_buffer_offset += copied;
107 // Has the buffer has been consumed?
108 if (current_buffer_offset == buffer->frame_count()) {
109 // If we are at the last buffer, no more data to be copied, so stop.
110 BufferQueue::iterator next = current_buffer + 1;
111 if (next == buffers_.end())
112 break;
114 // Advances the iterator.
115 current_buffer = next;
116 current_buffer_offset = 0;
120 if (advance_position) {
121 // Update the appropriate values since |taken| frames have been copied out.
122 frames_ -= taken;
123 DCHECK_GE(frames_, 0);
124 DCHECK(current_buffer_ != buffers_.end() || frames_ == 0);
126 // Remove any buffers before the current buffer as there is no going
127 // backwards.
128 buffers_.erase(buffers_.begin(), current_buffer);
129 current_buffer_ = buffers_.begin();
130 current_buffer_offset_ = current_buffer_offset;
133 return taken;
136 } // namespace media