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.
4
5 #include "media/base/audio_buffer_queue.h"
6
7 #include <algorithm>
8
9 #include "base/check_op.h"
10 #include "media/base/audio_bus.h"
11
12 namespace media {
13
AudioBufferQueue()14 AudioBufferQueue::AudioBufferQueue() { Clear(); }
15 AudioBufferQueue::~AudioBufferQueue() = default;
16
Clear()17 void AudioBufferQueue::Clear() {
18 buffers_.clear();
19 front_buffer_offset_ = 0;
20 frames_ = 0;
21 }
22
Append(scoped_refptr<AudioBuffer> buffer_in)23 void AudioBufferQueue::Append(scoped_refptr<AudioBuffer> buffer_in) {
24 // Update the |frames_| counter since we have added frames.
25 frames_ += buffer_in->frame_count();
26 CHECK_GT(frames_, 0); // make sure it doesn't overflow.
27
28 // Add the buffer to the queue. Inserting into deque invalidates all
29 // iterators, so point to the first buffer.
30 buffers_.push_back(std::move(buffer_in));
31 }
32
ReadFrames(int frames,int dest_frame_offset,AudioBus * dest)33 int AudioBufferQueue::ReadFrames(int frames,
34 int dest_frame_offset,
35 AudioBus* dest) {
36 DCHECK_GE(dest->frames(), frames + dest_frame_offset);
37 return InternalRead(frames, true, 0, dest_frame_offset, dest);
38 }
39
PeekFrames(int frames,int source_frame_offset,int dest_frame_offset,AudioBus * dest)40 int AudioBufferQueue::PeekFrames(int frames,
41 int source_frame_offset,
42 int dest_frame_offset,
43 AudioBus* dest) {
44 DCHECK_GE(dest->frames(), frames);
45 return InternalRead(
46 frames, false, source_frame_offset, dest_frame_offset, dest);
47 }
48
SeekFrames(int frames)49 void AudioBufferQueue::SeekFrames(int frames) {
50 // Perform seek only if we have enough bytes in the queue.
51 CHECK_LE(frames, frames_);
52 int taken = InternalRead(frames, true, 0, 0, NULL);
53 DCHECK_EQ(taken, frames);
54 }
55
InternalRead(int frames,bool advance_position,int source_frame_offset,int dest_frame_offset,AudioBus * dest)56 int AudioBufferQueue::InternalRead(int frames,
57 bool advance_position,
58 int source_frame_offset,
59 int dest_frame_offset,
60 AudioBus* dest) {
61 if (buffers_.empty())
62 return 0;
63
64 if (buffers_.front()->IsBitstreamFormat()) {
65 // For compressed bitstream formats, a partial compressed audio frame is
66 // less useful, since it can't generate any PCM frame out of it. Also, we
67 // want to keep the granularity as fine as possible so that discarding a
68 // small chunk of PCM frames is still possible. Thus, we only transfer a
69 // complete AudioBuffer at a time.
70 DCHECK(!dest_frame_offset ||
71 dest_frame_offset == dest->GetBitstreamFrames());
72 DCHECK(!source_frame_offset);
73
74 const auto& buffer = buffers_.front();
75 int taken = buffer->frame_count();
76
77 // if |dest| is NULL, there's no need to copy.
78 if (dest) {
79 // We always copy a whole bitstream buffer. Make sure we have space.
80 CHECK_GE(frames, buffer->frame_count());
81 buffer->ReadFrames(buffer->frame_count(), 0, dest_frame_offset, dest);
82 }
83
84 if (advance_position) {
85 // Update the appropriate values since |taken| frames have been copied
86 // out.
87 frames_ -= taken;
88 DCHECK_GE(frames_, 0);
89
90 // Remove any buffers before the current buffer as there is no going
91 // backwards.
92 buffers_.pop_front();
93 }
94
95 return taken;
96 }
97
98 // Counts how many frames are actually read from the buffer queue.
99 int taken = 0;
100 BufferQueue::iterator current_buffer = buffers_.begin();
101 int current_buffer_offset = front_buffer_offset_;
102
103 int frames_to_skip = source_frame_offset;
104 while (taken < frames) {
105 // |current_buffer| is valid since the first time this buffer is appended
106 // with data. Make sure there is data to be processed.
107 if (current_buffer == buffers_.end())
108 break;
109
110 scoped_refptr<AudioBuffer> buffer = *current_buffer;
111
112 int remaining_frames_in_buffer =
113 buffer->frame_count() - current_buffer_offset;
114
115 if (frames_to_skip > 0) {
116 // If there are frames to skip, do it first. May need to skip into
117 // subsequent buffers.
118 int skipped = std::min(remaining_frames_in_buffer, frames_to_skip);
119 current_buffer_offset += skipped;
120 frames_to_skip -= skipped;
121 } else {
122 // Find the right amount to copy from the current buffer. We shall copy no
123 // more than |frames| frames in total and each single step copies no more
124 // than the current buffer size.
125 int copied = std::min(frames - taken, remaining_frames_in_buffer);
126
127 // if |dest| is NULL, there's no need to copy.
128 if (dest) {
129 buffer->ReadFrames(
130 copied, current_buffer_offset, dest_frame_offset + taken, dest);
131 }
132
133 // Increase total number of frames copied, which regulates when to end
134 // this loop.
135 taken += copied;
136
137 // We have read |copied| frames from the current buffer. Advance the
138 // offset.
139 current_buffer_offset += copied;
140 }
141
142 // Has the buffer has been consumed?
143 if (current_buffer_offset == buffer->frame_count()) {
144 // If we are at the last buffer, no more data to be copied, so stop.
145 BufferQueue::iterator next = current_buffer + 1;
146 if (next == buffers_.end())
147 break;
148
149 // Advances the iterator.
150 current_buffer = next;
151 current_buffer_offset = 0;
152 }
153 }
154
155 if (advance_position) {
156 // Update the appropriate values since |taken| frames have been copied out.
157 frames_ -= taken;
158 DCHECK_GE(frames_, 0);
159
160 // Remove any buffers before the current buffer as there is no going
161 // backwards.
162 buffers_.erase(buffers_.begin(), current_buffer);
163 front_buffer_offset_ = current_buffer_offset;
164 }
165
166 return taken;
167 }
168
169 } // namespace media
170