1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.cts.verifier.audio.analyzers; 17 18 import java.util.concurrent.atomic.AtomicInteger; 19 20 /** 21 * Provides a circular buffer for audio data. 22 */ 23 public class InfiniteRecording { 24 25 private float[] mData; 26 private AtomicInteger mWritten = new AtomicInteger(); 27 private int mMaxSamples; 28 InfiniteRecording(int maxSamples)29 public InfiniteRecording(int maxSamples) { 30 mMaxSamples = maxSamples; 31 mData = new float[mMaxSamples]; 32 } 33 34 /** 35 * 36 * @param buffer 37 * @param position 38 * @param count 39 * @return 40 */ readFrom(float[] buffer, int position, int count)41 public int readFrom(float[] buffer, int position, int count) { 42 final int maxPosition = mWritten.get(); 43 position = Math.min(position, maxPosition); 44 int numToRead = Math.min(count, mMaxSamples); 45 numToRead = Math.min(numToRead, maxPosition - position); 46 if (numToRead == 0) { 47 return 0; 48 } 49 50 // We may need to read in two parts if it wraps. 51 final int offset = position % mMaxSamples; 52 final int firstReadSize = Math.min(numToRead, mMaxSamples - offset); 53 // copy (InputIterator first, InputIterator last, OutputIterator result) 54 // std::copy(&mData[offset], &mData[offset + firstReadSize], buffer); 55 // arraycopy(Object src, int srcPos, Object dest, int destPos, int length) 56 System.arraycopy(mData, offset, buffer, 0, firstReadSize); 57 if (firstReadSize < numToRead) { 58 // Second read needed. 59 // std::copy(&mData[0], &mData[numToRead - firstReadSize], &buffer[firstReadSize]); 60 System.arraycopy(mData, 0, buffer, firstReadSize, numToRead - firstReadSize); 61 } 62 return numToRead; 63 } 64 65 /** 66 * Get all the available audio data recorded during the analysis. 67 * @return recorded data 68 */ readAll()69 public float[] readAll() { 70 int numWritten = getTotalWritten(); 71 int numAvailable = getAvailable(); 72 float[] data = new float[numAvailable]; 73 readFrom(data, numWritten - numAvailable, numAvailable); 74 return data; 75 } 76 77 /** 78 * 79 * @param sample 80 */ write(float sample)81 public void write(float sample) { 82 final int position = mWritten.get(); 83 final int offset = position % mMaxSamples; 84 mData[offset] = sample; 85 mWritten.incrementAndGet(); 86 } 87 88 /** 89 * 90 * @return total number of samples written 91 */ getTotalWritten()92 public int getTotalWritten() { 93 return mWritten.get(); 94 } 95 96 /** 97 * Get the maximum number of frames that are available to read. 98 * 99 * @return total number of samples written or maxSamples 100 */ getAvailable()101 public int getAvailable() { 102 return Math.min(mMaxSamples, mWritten.get()); 103 } 104 105 /** 106 * Erase the previously recorded data. 107 */ clear()108 public void clear() { 109 mWritten.set(0); 110 } 111 }; 112