Home | History | Annotate | Download | only in base
      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 
     15 AudioBufferQueue::AudioBufferQueue() { Clear(); }
     16 AudioBufferQueue::~AudioBufferQueue() {}
     17 
     18 void AudioBufferQueue::Clear() {
     19   buffers_.clear();
     20   current_buffer_ = buffers_.begin();
     21   current_buffer_offset_ = 0;
     22   frames_ = 0;
     23 }
     24 
     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 
     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 
     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 
     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 
     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