• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
13 namespace media {
14 
AudioBufferQueue()15 AudioBufferQueue::AudioBufferQueue() { Clear(); }
~AudioBufferQueue()16 AudioBufferQueue::~AudioBufferQueue() {}
17 
Clear()18 void AudioBufferQueue::Clear() {
19   buffers_.clear();
20   current_buffer_ = buffers_.begin();
21   current_buffer_offset_ = 0;
22   frames_ = 0;
23 }
24 
Append(const scoped_refptr<AudioBuffer> & buffer_in)25 void 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 
ReadFrames(int frames,int dest_frame_offset,AudioBus * dest)36 int 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 
PeekFrames(int frames,int source_frame_offset,int dest_frame_offset,AudioBus * dest)43 int 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 
SeekFrames(int frames)52 void 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 
InternalRead(int frames,bool advance_position,int source_frame_offset,int dest_frame_offset,AudioBus * dest)59 int 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