1eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Copyright 2013 The Chromium Authors. All rights reserved. 2eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// found in the LICENSE file. 4eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "media/base/audio_buffer_queue.h" 6eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <algorithm> 8eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 9eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/logging.h" 10eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "media/base/audio_bus.h" 11eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "media/base/buffers.h" 12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace media { 14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochAudioBufferQueue::AudioBufferQueue() { Clear(); } 16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochAudioBufferQueue::~AudioBufferQueue() {} 17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 18eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid AudioBufferQueue::Clear() { 19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch buffers_.clear(); 20eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch current_buffer_ = buffers_.begin(); 21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch current_buffer_offset_ = 0; 22eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch frames_ = 0; 23eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 25eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid AudioBufferQueue::Append(const scoped_refptr<AudioBuffer>& buffer_in) { 26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Add the buffer to the queue. Inserting into deque invalidates all 27eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // iterators, so point to the first buffer. 28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch buffers_.push_back(buffer_in); 29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch current_buffer_ = buffers_.begin(); 30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Update the |frames_| counter since we have added frames. 32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch frames_ += buffer_in->frame_count(); 33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CHECK_GT(frames_, 0); // make sure it doesn't overflow. 34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochint AudioBufferQueue::ReadFrames(int frames, 377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch int dest_frame_offset, 387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch AudioBus* dest) { 397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch DCHECK_GE(dest->frames(), frames + dest_frame_offset); 407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return InternalRead(frames, true, 0, dest_frame_offset, dest); 41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint AudioBufferQueue::PeekFrames(int frames, 447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch int source_frame_offset, 457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch int dest_frame_offset, 46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch AudioBus* dest) { 47eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK_GE(dest->frames(), frames); 487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch return InternalRead( 497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch frames, false, source_frame_offset, dest_frame_offset, dest); 50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 52eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid AudioBufferQueue::SeekFrames(int frames) { 53eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Perform seek only if we have enough bytes in the queue. 54eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch CHECK_LE(frames, frames_); 557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch int taken = InternalRead(frames, true, 0, 0, NULL); 56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK_EQ(taken, frames); 57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochint AudioBufferQueue::InternalRead(int frames, 60eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool advance_position, 617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch int source_frame_offset, 627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch int dest_frame_offset, 63eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch AudioBus* dest) { 64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Counts how many frames are actually read from the buffer queue. 65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int taken = 0; 66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch BufferQueue::iterator current_buffer = current_buffer_; 67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int current_buffer_offset = current_buffer_offset_; 68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch int frames_to_skip = source_frame_offset; 70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch while (taken < frames) { 71eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // |current_buffer| is valid since the first time this buffer is appended 72eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // with data. Make sure there is data to be processed. 73eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (current_buffer == buffers_.end()) 74eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch break; 75eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 76eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch scoped_refptr<AudioBuffer> buffer = *current_buffer; 77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int remaining_frames_in_buffer = 79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch buffer->frame_count() - current_buffer_offset; 80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (frames_to_skip > 0) { 82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // If there are frames to skip, do it first. May need to skip into 83eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // subsequent buffers. 84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int skipped = std::min(remaining_frames_in_buffer, frames_to_skip); 85eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch current_buffer_offset += skipped; 86eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch frames_to_skip -= skipped; 87eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } else { 88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Find the right amount to copy from the current buffer. We shall copy no 89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // more than |frames| frames in total and each single step copies no more 90eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // than the current buffer size. 91eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch int copied = std::min(frames - taken, remaining_frames_in_buffer); 92eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 93eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // if |dest| is NULL, there's no need to copy. 947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if (dest) { 957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch buffer->ReadFrames( 967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch copied, current_buffer_offset, dest_frame_offset + taken, dest); 977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch } 98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Increase total number of frames copied, which regulates when to end 100eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // this loop. 101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch taken += copied; 102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // We have read |copied| frames from the current buffer. Advance the 104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // offset. 105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch current_buffer_offset += copied; 106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Has the buffer has been consumed? 109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (current_buffer_offset == buffer->frame_count()) { 110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // If we are at the last buffer, no more data to be copied, so stop. 111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch BufferQueue::iterator next = current_buffer + 1; 112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (next == buffers_.end()) 113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch break; 114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Advances the iterator. 116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch current_buffer = next; 117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch current_buffer_offset = 0; 118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (advance_position) { 122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Update the appropriate values since |taken| frames have been copied out. 123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch frames_ -= taken; 124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK_GE(frames_, 0); 125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(current_buffer_ != buffers_.end() || frames_ == 0); 126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 127eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // Remove any buffers before the current buffer as there is no going 128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch // backwards. 1297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch buffers_.erase(buffers_.begin(), current_buffer); 1307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch current_buffer_ = buffers_.begin(); 1317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch current_buffer_offset_ = current_buffer_offset; 132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch } 133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return taken; 135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} // namespace media 138