15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/audio_fifo.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace media { 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Given current position in the FIFO, the maximum number of elements in the 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// FIFO and the size of the input; this method provides two output results: 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |size| and |wrap_size|. These two results can then be utilized for memcopy 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// operations to and from the FIFO. 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Under "normal" circumstances, |size| will be equal to |in_size| and 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |wrap_size| will be zero. This case corresponding to the non-wrapping case 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// where we have not yet reached the "edge" of the FIFO. If |pos| + |in_size| 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// exceeds the total size of the FIFO, we must wrap around and start reusing 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a part the allocated memory. The size of this part is given by |wrap_size|. 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void GetSizes( 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int pos, int max_size, int in_size, int* size, int* wrap_size) { 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pos + in_size > max_size) { 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Wrapping is required => derive size of each segment. 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *size = max_size - pos; 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *wrap_size = in_size - *size; 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Wrapping is not required. 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *size = in_size; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *wrap_size = 0; 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Updates the read/write position with |step| modulo the maximum number of 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// elements in the FIFO to ensure that the position counters wraps around at 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the endpoint. 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int UpdatePos(int pos, int step, int max_size) { 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ((pos + step) % max_size); 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioFifo::AudioFifo(int channels, int frames) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : audio_bus_(AudioBus::Create(channels, frames)), 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) max_frames_(frames), 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frames_pushed_(0), 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frames_consumed_(0), 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_pos_(0), 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_pos_(0) {} 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioFifo::~AudioFifo() {} 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int AudioFifo::frames() const { 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int delta = frames_pushed_ - frames_consumed_; 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return delta; 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioFifo::Push(const AudioBus* source) { 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(source); 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(source->channels(), audio_bus_->channels()); 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ensure that there is space for the new data in the FIFO. 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int source_size = source->frames(); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_LE(source_size + frames(), max_frames_); 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Figure out if wrapping is needed and if so what segment sizes we need 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // when adding the new audio bus content to the FIFO. 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int append_size = 0; 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int wrap_size = 0; 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetSizes(write_pos_, max_frames(), source_size, &append_size, &wrap_size); 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Copy all channels from the source to the FIFO. Wrap around if needed. 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int ch = 0; ch < source->channels(); ++ch) { 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float* dest = audio_bus_->channel(ch); 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const float* src = source->channel(ch); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Append part of (or the complete) source to the FIFO. 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(&dest[write_pos_], &src[0], append_size * sizeof(src[0])); 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (wrap_size > 0) { 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Wrapping is needed: copy remaining part from the source to the FIFO. 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(&dest[0], &src[append_size], wrap_size * sizeof(src[0])); 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 82f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) frames_pushed_ += source_size; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_LE(frames(), max_frames()); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_pos_ = UpdatePos(write_pos_, source_size, max_frames()); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioFifo::Consume(AudioBus* destination, 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int start_frame, 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int frames_to_consume) { 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(destination); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(destination->channels(), audio_bus_->channels()); 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It is not possible to ask for more data than what is available in the FIFO. 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_LE(frames_to_consume, frames()); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // A copy from the FIFO to |destination| will only be performed if the 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // allocated memory in |destination| is sufficient. 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CHECK_LE(frames_to_consume + start_frame, destination->frames()); 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Figure out if wrapping is needed and if so what segment sizes we need 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // when removing audio bus content from the FIFO. 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int consume_size = 0; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int wrap_size = 0; 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GetSizes(read_pos_, max_frames(), frames_to_consume, 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &consume_size, &wrap_size); 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For all channels, remove the requested amount of data from the FIFO 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and copy the content to the destination. Wrap around if needed. 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (int ch = 0; ch < destination->channels(); ++ch) { 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float* dest = destination->channel(ch); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const float* src = audio_bus_->channel(ch); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Copy a selected part of the FIFO to the destination. 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(&dest[start_frame], &src[read_pos_], consume_size * sizeof(src[0])); 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (wrap_size > 0) { 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Wrapping is needed: copy remaining part to the destination. 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) memcpy(&dest[consume_size + start_frame], &src[0], 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) wrap_size * sizeof(src[0])); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 122f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) frames_consumed_ += frames_to_consume; 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_pos_ = UpdatePos(read_pos_, frames_to_consume, max_frames()); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioFifo::Clear() { 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frames_pushed_ = 0; 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) frames_consumed_ = 0; 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_pos_ = 0; 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) write_pos_ = 0; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace media 134