Home | History | Annotate | Download | only in base
      1 // Copyright 2014 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 <algorithm>
      6 
      7 #include "media/base/audio_block_fifo.h"
      8 
      9 #include "base/logging.h"
     10 
     11 namespace media {
     12 
     13 AudioBlockFifo::AudioBlockFifo(int channels, int frames, int blocks)
     14     : channels_(channels),
     15       block_frames_(frames),
     16       write_block_(0),
     17       read_block_(0),
     18       available_blocks_(0),
     19       write_pos_(0) {
     20   IncreaseCapacity(blocks);
     21 }
     22 
     23 AudioBlockFifo::~AudioBlockFifo() {}
     24 
     25 void AudioBlockFifo::Push(const void* source,
     26                           int frames,
     27                           int bytes_per_sample) {
     28   DCHECK(source);
     29   DCHECK_GT(frames, 0);
     30   DCHECK_GT(bytes_per_sample, 0);
     31   DCHECK_LT(available_blocks_, static_cast<int>(audio_blocks_.size()));
     32   CHECK_LE(frames, GetUnfilledFrames());
     33 
     34   const uint8* source_ptr = static_cast<const uint8*>(source);
     35   int frames_to_push = frames;
     36   while (frames_to_push) {
     37     // Get the current write block.
     38     AudioBus* current_block = audio_blocks_[write_block_];
     39 
     40     // Figure out what segment sizes we need when adding the new content to
     41     // the FIFO.
     42     const int push_frames =
     43         std::min(block_frames_ - write_pos_, frames_to_push);
     44 
     45     // Deinterleave the content to the FIFO and update the |write_pos_|.
     46     current_block->FromInterleavedPartial(
     47         source_ptr, write_pos_, push_frames, bytes_per_sample);
     48     write_pos_ = (write_pos_ + push_frames) % block_frames_;
     49     if (!write_pos_) {
     50       // The current block is completely filled, increment |write_block_| and
     51       // |available_blocks_|.
     52       write_block_ = (write_block_ + 1) % audio_blocks_.size();
     53       ++available_blocks_;
     54     }
     55 
     56     source_ptr += push_frames * bytes_per_sample * channels_;
     57     frames_to_push -= push_frames;
     58     DCHECK_GE(frames_to_push, 0);
     59   }
     60 }
     61 
     62 const AudioBus* AudioBlockFifo::Consume() {
     63   DCHECK(available_blocks_);
     64   AudioBus* audio_bus = audio_blocks_[read_block_];
     65   read_block_ = (read_block_ + 1) % audio_blocks_.size();
     66   --available_blocks_;
     67   return audio_bus;
     68 }
     69 
     70 void AudioBlockFifo::Clear() {
     71   write_pos_ = 0;
     72   write_block_ = 0;
     73   read_block_ = 0;
     74   available_blocks_ = 0;
     75 }
     76 
     77 int AudioBlockFifo::GetAvailableFrames() const {
     78   return available_blocks_ * block_frames_ + write_pos_;
     79 }
     80 
     81 int AudioBlockFifo::GetUnfilledFrames() const {
     82   const int unfilled_frames =
     83       (audio_blocks_.size() - available_blocks_) * block_frames_ - write_pos_;
     84   DCHECK_GE(unfilled_frames, 0);
     85   return unfilled_frames;
     86 }
     87 
     88 void AudioBlockFifo::IncreaseCapacity(int blocks) {
     89   DCHECK_GT(blocks, 0);
     90 
     91   // Create |blocks| of audio buses and insert them to the containers.
     92   audio_blocks_.reserve(audio_blocks_.size() + blocks);
     93 
     94   const int original_size = audio_blocks_.size();
     95   for (int i = 0; i < blocks; ++i) {
     96     audio_blocks_.push_back(
     97         AudioBus::Create(channels_, block_frames_).release());
     98   }
     99 
    100   if (!original_size)
    101     return;
    102 
    103   std::rotate(audio_blocks_.begin() + read_block_,
    104               audio_blocks_.begin() + original_size,
    105               audio_blocks_.end());
    106 
    107   // Update the write pointer if it is on top of the new inserted blocks.
    108   if (write_block_ >= read_block_)
    109     write_block_ += blocks;
    110 
    111   // Update the read pointers correspondingly.
    112   read_block_ += blocks;
    113 
    114   DCHECK_LT(read_block_, static_cast<int>(audio_blocks_.size()));
    115   DCHECK_LT(write_block_, static_cast<int>(audio_blocks_.size()));
    116 }
    117 
    118 }  // namespace media
    119