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