fifo_tests.cpp 8.5 KB

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