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