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   current_time_ = kNoTimestamp();
     24 }
     25 
     26 void AudioBufferQueue::Append(const scoped_refptr<AudioBuffer>& buffer_in) {
     27   // If we have just written the first buffer, update |current_time_| to be the
     28   // start time.
     29   if (buffers_.empty() && buffer_in->timestamp() != kNoTimestamp()) {
     30     current_time_ = buffer_in->timestamp();
     31   }
     32 
     33   // Add the buffer to the queue. Inserting into deque invalidates all
     34   // iterators, so point to the first buffer.
     35   buffers_.push_back(buffer_in);
     36   current_buffer_ = buffers_.begin();
     37 
     38   // Update the |frames_| counter since we have added frames.
     39   frames_ += buffer_in->frame_count();
     40   CHECK_GT(frames_, 0);  // make sure it doesn't overflow.
     41 }
     42 
     43 int AudioBufferQueue::ReadFrames(int frames,
     44                                  int dest_frame_offset,
     45                                  AudioBus* dest) {
     46   DCHECK_GE(dest->frames(), frames + dest_frame_offset);
     47   return InternalRead(frames, true, 0, dest_frame_offset, dest);
     48 }
     49 
     50 int AudioBufferQueue::PeekFrames(int frames,
     51                                  int source_frame_offset,
     52                                  int dest_frame_offset,
     53                                  AudioBus* dest) {
     54   DCHECK_GE(dest->frames(), frames);
     55   return InternalRead(
     56       frames, false, source_frame_offset, dest_frame_offset, dest);
     57 }
     58 
     59 void AudioBufferQueue::SeekFrames(int frames) {
     60   // Perform seek only if we have enough bytes in the queue.
     61   CHECK_LE(frames, frames_);
     62   int taken = InternalRead(frames, true, 0, 0, NULL);
     63   DCHECK_EQ(taken, frames);
     64 }
     65 
     66 int AudioBufferQueue::InternalRead(int frames,
     67                                    bool advance_position,
     68                                    int source_frame_offset,
     69                                    int dest_frame_offset,
     70                                    AudioBus* dest) {
     71   // Counts how many frames are actually read from the buffer queue.
     72   int taken = 0;
     73   BufferQueue::iterator current_buffer = current_buffer_;
     74   int current_buffer_offset = current_buffer_offset_;
     75 
     76   int frames_to_skip = source_frame_offset;
     77   while (taken < frames) {
     78     // |current_buffer| is valid since the first time this buffer is appended
     79     // with data. Make sure there is data to be processed.
     80     if (current_buffer == buffers_.end())
     81       break;
     82 
     83     scoped_refptr<AudioBuffer> buffer = *current_buffer;
     84 
     85     int remaining_frames_in_buffer =
     86         buffer->frame_count() - current_buffer_offset;
     87 
     88     if (frames_to_skip > 0) {
     89       // If there are frames to skip, do it first. May need to skip into
     90       // subsequent buffers.
     91       int skipped = std::min(remaining_frames_in_buffer, frames_to_skip);
     92       current_buffer_offset += skipped;
     93       frames_to_skip -= skipped;
     94     } else {
     95       // Find the right amount to copy from the current buffer. We shall copy no
     96       // more than |frames| frames in total and each single step copies no more
     97       // than the current buffer size.
     98       int copied = std::min(frames - taken, remaining_frames_in_buffer);
     99 
    100       // if |dest| is NULL, there's no need to copy.
    101       if (dest) {
    102         buffer->ReadFrames(
    103             copied, current_buffer_offset, dest_frame_offset + taken, dest);
    104       }
    105 
    106       // Increase total number of frames copied, which regulates when to end
    107       // this loop.
    108       taken += copied;
    109 
    110       // We have read |copied| frames from the current buffer. Advance the
    111       // offset.
    112       current_buffer_offset += copied;
    113     }
    114 
    115     // Has the buffer has been consumed?
    116     if (current_buffer_offset == buffer->frame_count()) {
    117       if (advance_position) {
    118         // Next buffer may not have timestamp, so we need to update current
    119         // timestamp before switching to the next buffer.
    120         UpdateCurrentTime(current_buffer, current_buffer_offset);
    121       }
    122 
    123       // If we are at the last buffer, no more data to be copied, so stop.
    124       BufferQueue::iterator next = current_buffer + 1;
    125       if (next == buffers_.end())
    126         break;
    127 
    128       // Advances the iterator.
    129       current_buffer = next;
    130       current_buffer_offset = 0;
    131     }
    132   }
    133 
    134   if (advance_position) {
    135     // Update the appropriate values since |taken| frames have been copied out.
    136     frames_ -= taken;
    137     DCHECK_GE(frames_, 0);
    138     DCHECK(current_buffer_ != buffers_.end() || frames_ == 0);
    139 
    140     UpdateCurrentTime(current_buffer, current_buffer_offset);
    141 
    142     // Remove any buffers before the current buffer as there is no going
    143     // backwards.
    144     buffers_.erase(buffers_.begin(), current_buffer);
    145     current_buffer_ = buffers_.begin();
    146     current_buffer_offset_ = current_buffer_offset;
    147   }
    148 
    149   return taken;
    150 }
    151 
    152 void AudioBufferQueue::UpdateCurrentTime(BufferQueue::iterator buffer,
    153                                          int offset) {
    154   if (buffer != buffers_.end() && (*buffer)->timestamp() != kNoTimestamp()) {
    155     double time_offset = ((*buffer)->duration().InMicroseconds() * offset) /
    156                          static_cast<double>((*buffer)->frame_count());
    157     current_time_ =
    158         (*buffer)->timestamp() + base::TimeDelta::FromMicroseconds(
    159                                      static_cast<int64>(time_offset + 0.5));
    160   }
    161 }
    162 
    163 }  // namespace media
    164