diff options
author | Torne (Richard Coles) <torne@google.com> | 2012-11-14 11:43:16 +0000 |
---|---|---|
committer | Torne (Richard Coles) <torne@google.com> | 2012-11-14 11:43:16 +0000 |
commit | 5821806d5e7f356e8fa4b058a389a808ea183019 (patch) | |
tree | e19f4793aac92e2c0d9a01087019a60d6657d838 /media/base/audio_fifo.cc | |
parent | 8e79a8efe247f109aafd917a69e8a392961b3687 (diff) | |
download | chromium_org-5821806d5e7f356e8fa4b058a389a808ea183019.tar.gz |
Merge from Chromium at DEPS revision r167172
This commit was generated by merge_to_master.py.
Change-Id: Ib8d56fd5ae39a2d7e8c91dcd76cc6d13f25f2aab
Diffstat (limited to 'media/base/audio_fifo.cc')
-rw-r--r-- | media/base/audio_fifo.cc | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/media/base/audio_fifo.cc b/media/base/audio_fifo.cc new file mode 100644 index 0000000000..b6e8f806e0 --- /dev/null +++ b/media/base/audio_fifo.cc @@ -0,0 +1,144 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/base/audio_fifo.h" + +#include "base/logging.h" + +using base::subtle::Atomic32; +using base::subtle::NoBarrier_Store; + +namespace media { + +// Given current position in the FIFO, the maximum number of elements in the +// FIFO and the size of the input; this method provides two output results: +// |size| and |wrap_size|. These two results can then be utilized for memcopy +// operations to and from the FIFO. +// Under "normal" circumstances, |size| will be equal to |in_size| and +// |wrap_size| will be zero. This case corresponding to the non-wrapping case +// where we have not yet reached the "edge" of the FIFO. If |pos| + |in_size| +// exceeds the total size of the FIFO, we must wrap around and start reusing +// a part the allocated memory. The size of this part is given by |wrap_size|. +static void GetSizes( + int pos, int max_size, int in_size, int* size, int* wrap_size) { + if (pos + in_size > max_size) { + // Wrapping is required => derive size of each segment. + *size = max_size - pos; + *wrap_size = in_size - *size; + } else { + // Wrapping is not required. + *size = in_size; + *wrap_size = 0; + } +} + +// Updates the read/write position with |step| modulo the maximum number of +// elements in the FIFO to ensure that the position counters wraps around at +// the endpoint. +static int UpdatePos(int pos, int step, int max_size) { + return ((pos + step) % max_size); +} + +AudioFifo::AudioFifo(int channels, int frames) + : audio_bus_(AudioBus::Create(channels, frames)), + max_frames_(frames), + frames_pushed_(0), + frames_consumed_(0), + read_pos_(0), + write_pos_(0) {} + +AudioFifo::~AudioFifo() {} + +int AudioFifo::frames() const { + int delta = frames_pushed_ - frames_consumed_; + base::subtle::MemoryBarrier(); + return delta; +} + +void AudioFifo::Push(const AudioBus* source) { + DCHECK(source); + DCHECK_EQ(source->channels(), audio_bus_->channels()); + + // Ensure that there is space for the new data in the FIFO. + const int source_size = source->frames(); + CHECK_LE(source_size + frames(), max_frames_); + + // Figure out if wrapping is needed and if so what segment sizes we need + // when adding the new audio bus content to the FIFO. + int append_size = 0; + int wrap_size = 0; + GetSizes(write_pos_, max_frames(), source_size, &append_size, &wrap_size); + + // Copy all channels from the source to the FIFO. Wrap around if needed. + for (int ch = 0; ch < source->channels(); ++ch) { + float* dest = audio_bus_->channel(ch); + const float* src = source->channel(ch); + + // Append part of (or the complete) source to the FIFO. + memcpy(&dest[write_pos_], &src[0], append_size * sizeof(src[0])); + if (wrap_size > 0) { + // Wrapping is needed: copy remaining part from the source to the FIFO. + memcpy(&dest[0], &src[append_size], wrap_size * sizeof(src[0])); + } + } + + // Ensure the data is *really* written before updating |frames_pushed_|. + base::subtle::MemoryBarrier(); + + Atomic32 new_frames_pushed = frames_pushed_ + source_size; + NoBarrier_Store(&frames_pushed_, new_frames_pushed); + + DCHECK_LE(frames(), max_frames()); + write_pos_ = UpdatePos(write_pos_, source_size, max_frames()); +} + +void AudioFifo::Consume(AudioBus* destination, + int start_frame, + int frames_to_consume) { + DCHECK(destination); + DCHECK_EQ(destination->channels(), audio_bus_->channels()); + + // It is not possible to ask for more data than what is available in the FIFO. + CHECK_LE(frames_to_consume, frames()); + + // A copy from the FIFO to |destination| will only be performed if the + // allocated memory in |destination| is sufficient. + CHECK_LE(frames_to_consume + start_frame, destination->frames()); + + // Figure out if wrapping is needed and if so what segment sizes we need + // when removing audio bus content from the FIFO. + int consume_size = 0; + int wrap_size = 0; + GetSizes(read_pos_, max_frames(), frames_to_consume, + &consume_size, &wrap_size); + + // For all channels, remove the requested amount of data from the FIFO + // and copy the content to the destination. Wrap around if needed. + for (int ch = 0; ch < destination->channels(); ++ch) { + float* dest = destination->channel(ch); + const float* src = audio_bus_->channel(ch); + + // Copy a selected part of the FIFO to the destination. + memcpy(&dest[start_frame], &src[read_pos_], consume_size * sizeof(src[0])); + if (wrap_size > 0) { + // Wrapping is needed: copy remaining part to the destination. + memcpy(&dest[consume_size + start_frame], &src[0], + wrap_size * sizeof(src[0])); + } + } + + Atomic32 new_frames_consumed = frames_consumed_ + frames_to_consume; + NoBarrier_Store(&frames_consumed_, new_frames_consumed); + + read_pos_ = UpdatePos(read_pos_, frames_to_consume, max_frames()); +} + +void AudioFifo::Clear() { + frames_pushed_ = 0; + frames_consumed_ = 0; + read_pos_ = 0; + write_pos_ = 0; +} + +} // namespace media |