Home | History | Annotate | Download | only in tests
      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 <limits.h>
     21 #include <stdlib.h>
     22 #include <string.h>
     23 #include <audio_utils/fifo.h>
     24 #include <audio_utils/sndfile.h>
     25 
     26 int main(int argc, char **argv)
     27 {
     28     size_t frameCount = 256;
     29     size_t maxFramesPerRead = 1;
     30     size_t maxFramesPerWrite = 1;
     31     int i;
     32     for (i = 1; i < argc; i++) {
     33         char *arg = argv[i];
     34         if (arg[0] != '-')
     35             break;
     36         switch (arg[1]) {
     37         case 'c':   // FIFO frame count
     38             frameCount = atoi(&arg[2]);
     39             break;
     40         case 'r':   // maximum frame count per read from FIFO
     41             maxFramesPerRead = atoi(&arg[2]);
     42             break;
     43         case 'w':   // maximum frame count per write to FIFO
     44             maxFramesPerWrite = atoi(&arg[2]);
     45             break;
     46         default:
     47             fprintf(stderr, "%s: unknown option %s\n", argv[0], arg);
     48             goto usage;
     49         }
     50     }
     51 
     52     if (argc - i != 2) {
     53 usage:
     54         fprintf(stderr, "usage: %s [-c#] in.wav out.wav\n", argv[0]);
     55         return EXIT_FAILURE;
     56     }
     57     char *inputFile = argv[i];
     58     char *outputFile = argv[i+1];
     59 
     60     SF_INFO sfinfoin;
     61     memset(&sfinfoin, 0, sizeof(sfinfoin));
     62     SNDFILE *sfin = sf_open(inputFile, SFM_READ, &sfinfoin);
     63     if (sfin == NULL) {
     64         perror(inputFile);
     65         return EXIT_FAILURE;
     66     }
     67     // sf_readf_short() does conversion, so not strictly necessary to check the file format.
     68     // But I want to do "cmp" on input and output files afterwards,
     69     // and it is easier if they are all the same format.
     70     // Enforcing that everything is 16-bit is convenient for this.
     71     if ((sfinfoin.format & (SF_FORMAT_TYPEMASK | SF_FORMAT_SUBMASK)) !=
     72             (SF_FORMAT_WAV | SF_FORMAT_PCM_16)) {
     73         fprintf(stderr, "%s: unsupported format\n", inputFile);
     74         sf_close(sfin);
     75         return EXIT_FAILURE;
     76     }
     77     size_t frameSize = sizeof(short) * sfinfoin.channels;
     78     short *inputBuffer = new short[sfinfoin.frames * sfinfoin.channels];
     79     sf_count_t actualRead = sf_readf_short(sfin, inputBuffer, sfinfoin.frames);
     80     if (actualRead != sfinfoin.frames) {
     81         fprintf(stderr, "%s: unexpected EOF or error\n", inputFile);
     82         sf_close(sfin);
     83         return EXIT_FAILURE;
     84     }
     85     sf_close(sfin);
     86 
     87     short *outputBuffer = new short[sfinfoin.frames * sfinfoin.channels];
     88     size_t framesWritten = 0;
     89     size_t framesRead = 0;
     90     struct audio_utils_fifo fifo;
     91     short *fifoBuffer = new short[frameCount * sfinfoin.channels];
     92     audio_utils_fifo_init(&fifo, frameCount, frameSize, fifoBuffer);
     93     int fifoWriteCount = 0, fifoReadCount = 0;
     94     int fifoFillLevel = 0, minFillLevel = INT_MAX, maxFillLevel = INT_MIN;
     95     for (;;) {
     96         size_t framesToWrite = sfinfoin.frames - framesWritten;
     97         size_t framesToRead = sfinfoin.frames - framesRead;
     98         if (framesToWrite == 0 && framesToRead == 0) {
     99             break;
    100         }
    101 
    102         if (framesToWrite > maxFramesPerWrite) {
    103             framesToWrite = maxFramesPerWrite;
    104         }
    105         framesToWrite = rand() % (framesToWrite + 1);
    106         ssize_t actualWritten = audio_utils_fifo_write(&fifo,
    107                 &inputBuffer[framesWritten * sfinfoin.channels], framesToWrite);
    108         if (actualWritten < 0 || (size_t) actualWritten > framesToWrite) {
    109             fprintf(stderr, "write to FIFO failed\n");
    110             break;
    111         }
    112         framesWritten += actualWritten;
    113         if (actualWritten > 0) {
    114             fifoWriteCount++;
    115         }
    116         fifoFillLevel += actualWritten;
    117         if (fifoFillLevel > maxFillLevel) {
    118             maxFillLevel = fifoFillLevel;
    119             if (maxFillLevel > (int) frameCount)
    120                 abort();
    121         }
    122 
    123         if (framesToRead > maxFramesPerRead) {
    124             framesToRead = maxFramesPerRead;
    125         }
    126         framesToRead = rand() % (framesToRead + 1);
    127         ssize_t actualRead = audio_utils_fifo_read(&fifo,
    128                 &outputBuffer[framesRead * sfinfoin.channels], framesToRead);
    129         if (actualRead < 0 || (size_t) actualRead > framesToRead) {
    130             fprintf(stderr, "read from FIFO failed\n");
    131             break;
    132         }
    133         framesRead += actualRead;
    134         if (actualRead > 0) {
    135             fifoReadCount++;
    136         }
    137         fifoFillLevel -= actualRead;
    138         if (fifoFillLevel < minFillLevel) {
    139             minFillLevel = fifoFillLevel;
    140             if (minFillLevel < 0)
    141                 abort();
    142         }
    143     }
    144     printf("FIFO non-empty writes: %d, non-empty reads: %d\n", fifoWriteCount, fifoReadCount);
    145     printf("fill=%d, min=%d, max=%d\n", fifoFillLevel, minFillLevel, maxFillLevel);
    146     audio_utils_fifo_deinit(&fifo);
    147     delete[] fifoBuffer;
    148 
    149     SF_INFO sfinfoout;
    150     memset(&sfinfoout, 0, sizeof(sfinfoout));
    151     sfinfoout.samplerate = sfinfoin.samplerate;
    152     sfinfoout.channels = sfinfoin.channels;
    153     sfinfoout.format = sfinfoin.format;
    154     SNDFILE *sfout = sf_open(outputFile, SFM_WRITE, &sfinfoout);
    155     if (sfout == NULL) {
    156         perror(outputFile);
    157         return EXIT_FAILURE;
    158     }
    159     sf_count_t actualWritten = sf_writef_short(sfout, outputBuffer, framesRead);
    160     delete[] inputBuffer;
    161     delete[] outputBuffer;
    162     delete[] fifoBuffer;
    163     if (actualWritten != (sf_count_t) framesRead) {
    164         fprintf(stderr, "%s: unexpected error\n", outputFile);
    165         sf_close(sfout);
    166         return EXIT_FAILURE;
    167     }
    168     sf_close(sfout);
    169     return EXIT_SUCCESS;
    170 }
    171