1/* 2 * Copyright (C) 2015 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 17// Test program for audio_utils FIFO library. 18// This only tests the single-threaded aspects, not the barriers. 19 20#include <errno.h> 21#include <limits.h> 22#include <stdlib.h> 23#include <string.h> 24#include <audio_utils/fifo.h> 25#include <audio_utils/sndfile.h> 26 27#ifndef min 28#define min(x, y) (((x) < (y)) ? (x) : (y)) 29#endif 30 31int main(int argc, char **argv) 32{ 33 size_t frameCount = 0; 34 size_t maxFramesPerRead = 0; 35 size_t maxFramesPerWrite = 0; 36 bool readerThrottlesWriter = true; 37 bool verbose = false; 38 int i; 39 for (i = 1; i < argc; i++) { 40 char *arg = argv[i]; 41 if (arg[0] != '-') 42 break; 43 switch (arg[1]) { 44 case 'f': // FIFO frame count 45 frameCount = atoi(&arg[2]); 46 break; 47 case 'r': // maximum frame count per read from FIFO 48 maxFramesPerRead = atoi(&arg[2]); 49 break; 50 case 't': // disable throttling of writer by reader 51 readerThrottlesWriter = false; 52 break; 53 case 'v': // enable verbose logging 54 verbose = true; 55 break; 56 case 'w': // maximum frame count per write to FIFO 57 maxFramesPerWrite = atoi(&arg[2]); 58 break; 59 default: 60 fprintf(stderr, "%s: unknown option %s\n", argv[0], arg); 61 goto usage; 62 } 63 } 64 if (frameCount == 0) { 65 frameCount = 256; 66 } 67 if (maxFramesPerRead == 0) { 68 maxFramesPerRead = frameCount; 69 } 70 if (maxFramesPerWrite == 0) { 71 maxFramesPerWrite = frameCount; 72 } 73 74 if (argc - i != 2) { 75usage: 76 fprintf(stderr, "usage: %s [-f#] [-r#] [-t] [-v] [-w#] in.wav out.wav\n", argv[0]); 77 return EXIT_FAILURE; 78 } 79 char *inputFile = argv[i]; 80 char *outputFile = argv[i+1]; 81 82 SF_INFO sfinfoin; 83 memset(&sfinfoin, 0, sizeof(sfinfoin)); 84 SNDFILE *sfin = sf_open(inputFile, SFM_READ, &sfinfoin); 85 if (sfin == NULL) { 86 perror(inputFile); 87 return EXIT_FAILURE; 88 } 89 switch (sfinfoin.format & (SF_FORMAT_TYPEMASK | SF_FORMAT_SUBMASK)) { 90 case SF_FORMAT_WAV | SF_FORMAT_PCM_16: 91 case SF_FORMAT_WAV | SF_FORMAT_PCM_U8: 92 break; 93 default: 94 fprintf(stderr, "%s: unsupported format\n", inputFile); 95 sf_close(sfin); 96 return EXIT_FAILURE; 97 } 98 size_t frameSize = sizeof(int16_t) * sfinfoin.channels; 99 int16_t *inputBuffer = new int16_t[sfinfoin.frames * sfinfoin.channels]; 100 sf_count_t actualRead = sf_readf_short(sfin, inputBuffer, sfinfoin.frames); 101 if (actualRead != sfinfoin.frames) { 102 fprintf(stderr, "%s: unexpected EOF or error\n", inputFile); 103 sf_close(sfin); 104 return EXIT_FAILURE; 105 } 106 sf_close(sfin); 107 108 int16_t *outputBuffer = new int16_t[sfinfoin.frames * sfinfoin.channels]; 109 size_t framesWritten = 0; 110 size_t framesRead = 0; 111 int16_t *fifoBuffer = new int16_t[frameCount * sfinfoin.channels]; 112 audio_utils_fifo fifo(frameCount, frameSize, fifoBuffer, readerThrottlesWriter); 113 audio_utils_fifo_writer fifoWriter(fifo); 114 audio_utils_fifo_reader fifoReader(fifo, readerThrottlesWriter); 115 int fifoWriteCount = 0, fifoReadCount = 0; 116 int fifoFillLevel = 0, minFillLevel = INT_MAX, maxFillLevel = INT_MIN; 117 for (;;) { 118 size_t framesToWrite = sfinfoin.frames - framesWritten; 119 size_t framesToRead = sfinfoin.frames - framesRead; 120 if (framesToWrite == 0 && (framesToRead == 0 || !readerThrottlesWriter)) { 121 break; 122 } 123 124 if (framesToWrite > maxFramesPerWrite) { 125 framesToWrite = maxFramesPerWrite; 126 } 127 framesToWrite = rand() % (framesToWrite + 1); 128 ssize_t actualWritten = fifoWriter.write( 129 &inputBuffer[framesWritten * sfinfoin.channels], framesToWrite); 130 if (verbose) { 131 printf("wrote %d out of %d\n", (int) actualWritten, (int) framesToWrite); 132 } 133 if (actualWritten < 0 || (size_t) actualWritten > framesToWrite) { 134 fprintf(stderr, "write to FIFO failed\n"); 135 break; 136 } 137 if (actualWritten < min((int) frameCount - fifoFillLevel, (int) framesToWrite)) { 138 fprintf(stderr, "only wrote %d when should have written min(%d, %d)\n", 139 (int) actualWritten, (int) frameCount - fifoFillLevel, (int) framesToWrite); 140 } 141 framesWritten += actualWritten; 142 if (actualWritten > 0) { 143 fifoWriteCount++; 144 } 145 fifoFillLevel += actualWritten; 146 if (verbose) { 147 printf("fill level after write %d\n", fifoFillLevel); 148 } 149 if (fifoFillLevel > maxFillLevel) { 150 maxFillLevel = fifoFillLevel; 151 if (maxFillLevel > (int) frameCount) { 152 if (readerThrottlesWriter) { 153 printf("maxFillLevel=%d > frameCount=%d\n", maxFillLevel, (int) frameCount); 154 abort(); 155 } 156 } 157 } 158 159 if (framesToRead > maxFramesPerRead) { 160 framesToRead = maxFramesPerRead; 161 } 162 framesToRead = rand() % (framesToRead + 1); 163 ssize_t actualRead = fifoReader.read( 164 &outputBuffer[framesRead * sfinfoin.channels], framesToRead); 165 if (verbose) { 166 printf("read %d out of %d\n", (int) actualRead, (int) framesToRead); 167 } 168 if (actualRead < 0 || (size_t) actualRead > framesToRead) { 169 switch (actualRead) { 170 case -EIO: 171 fprintf(stderr, "read from FIFO failed: corrupted indices\n"); 172 abort(); 173 break; 174 case -EOVERFLOW: 175 if (readerThrottlesWriter) { 176 fprintf(stderr, "read from FIFO failed: unexpected overflow\n"); 177 abort(); 178 } 179 printf("warning: reader lost frames\n"); 180 actualRead = 0; 181 break; 182 default: 183 if (actualRead < 0) { 184 fprintf(stderr, "read from FIFO failed: unexpected error code %d\n", 185 (int) actualRead); 186 } else { 187 fprintf(stderr, "read from FIFO failed: actualRead=%d > framesToRead=%d\n", 188 (int) actualRead, (int) framesToRead); 189 } 190 abort(); 191 } 192 } 193 if (actualRead < min(fifoFillLevel, (int) framesToRead)) { 194 //fprintf(stderr, "only read %d when should have read min(%d, %d)\n", 195 // (int) actualRead, fifoFillLevel, (int) framesToRead); 196 } 197 framesRead += actualRead; 198 if (actualRead > 0) { 199 fifoReadCount++; 200 } 201 fifoFillLevel -= actualRead; 202 if (verbose) { 203 printf("fill level after read %d\n", fifoFillLevel); 204 } 205 if (fifoFillLevel < minFillLevel) { 206 minFillLevel = fifoFillLevel; 207 if (minFillLevel < 0) { 208 printf("minFillLevel=%d < 0\n", minFillLevel); 209 abort(); 210 } 211 } 212 } 213 delete[] inputBuffer; 214 inputBuffer = NULL; 215 delete[] fifoBuffer; 216 fifoBuffer = NULL; 217 218 printf("FIFO non-empty writes: %d, non-empty reads: %d\n", fifoWriteCount, fifoReadCount); 219 printf("fill=%d, min=%d, max=%d\n", fifoFillLevel, minFillLevel, maxFillLevel); 220 221 printf("writing output\n"); 222 SF_INFO sfinfoout; 223 memset(&sfinfoout, 0, sizeof(sfinfoout)); 224 sfinfoout.samplerate = sfinfoin.samplerate; 225 sfinfoout.channels = sfinfoin.channels; 226 sfinfoout.format = sfinfoin.format; 227 SNDFILE *sfout = sf_open(outputFile, SFM_WRITE, &sfinfoout); 228 if (sfout == NULL) { 229 perror(outputFile); 230 return EXIT_FAILURE; 231 } 232 sf_count_t actualWritten = sf_writef_short(sfout, outputBuffer, framesRead); 233 delete[] outputBuffer; 234 outputBuffer = NULL; 235 236 if (actualWritten != (sf_count_t) framesRead) { 237 fprintf(stderr, "%s: unexpected error\n", outputFile); 238 sf_close(sfout); 239 return EXIT_FAILURE; 240 } 241 sf_close(sfout); 242 printf("done\n"); 243 244 return EXIT_SUCCESS; 245} 246