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