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