1/* 2 * Copyright (C) 2016 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// Play sine waves using AAudio. 18 19#include <aaudio/AAudio.h> 20#include <aaudio/AAudioTesting.h> 21#include <asm/fcntl.h> 22#include <fcntl.h> 23#include <stdio.h> 24#include <stdlib.h> 25#include <unistd.h> 26 27#include "AAudioExampleUtils.h" 28#include "AAudioSimplePlayer.h" 29#include "AAudioArgsParser.h" 30 31#define NUM_SECONDS 4 32 33int main(int argc, const char **argv) 34{ 35 AAudioArgsParser argParser; 36 AAudioSimplePlayer player; 37 SineThreadedData_t myData; 38 aaudio_result_t result = AAUDIO_OK; 39 40 int32_t actualChannelCount = 0; 41 int32_t actualSampleRate = 0; 42 aaudio_format_t actualDataFormat = AAUDIO_FORMAT_UNSPECIFIED; 43 44 AAudioStream *aaudioStream = nullptr; 45 int32_t framesPerBurst = 0; 46 int32_t framesPerWrite = 0; 47 int32_t bufferCapacity = 0; 48 int32_t framesToPlay = 0; 49 int32_t framesLeft = 0; 50 int32_t xRunCount = 0; 51 float *floatData = nullptr; 52 int16_t *shortData = nullptr; 53 54 int testFd = -1; 55 56 // Make printf print immediately so that debug info is not stuck 57 // in a buffer if we hang or crash. 58 setvbuf(stdout, nullptr, _IONBF, (size_t) 0); 59 60 printf("%s - Play a sine wave using AAudio V0.1.2\n", argv[0]); 61 62 if (argParser.parseArgs(argc, argv)) { 63 return EXIT_FAILURE; 64 } 65 66 result = player.open(argParser); 67 if (result != AAUDIO_OK) { 68 fprintf(stderr, "ERROR - player.open() returned %d\n", result); 69 goto finish; 70 } 71 72 aaudioStream = player.getStream(); 73 74 argParser.compareWithStream(aaudioStream); 75 76 actualChannelCount = AAudioStream_getChannelCount(aaudioStream); 77 actualSampleRate = AAudioStream_getSampleRate(aaudioStream); 78 actualDataFormat = AAudioStream_getFormat(aaudioStream); 79 80 myData.sineOsc1.setup(440.0, actualSampleRate); 81 myData.sineOsc2.setup(660.0, actualSampleRate); 82 83 // Some DMA might use very short bursts of 16 frames. We don't need to write such small 84 // buffers. But it helps to use a multiple of the burst size for predictable scheduling. 85 framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream); 86 framesPerWrite = framesPerBurst; 87 while (framesPerWrite < 48) { 88 framesPerWrite *= 2; 89 } 90 printf("Buffer: framesPerBurst = %d\n",framesPerBurst); 91 printf("Buffer: framesPerWrite = %d\n",framesPerWrite); 92 93 // Allocate a buffer for the audio data. 94 if (actualDataFormat == AAUDIO_FORMAT_PCM_FLOAT) { 95 floatData = new float[framesPerWrite * actualChannelCount]; 96 } else if (actualDataFormat == AAUDIO_FORMAT_PCM_I16) { 97 shortData = new int16_t[framesPerWrite * actualChannelCount]; 98 } else { 99 printf("ERROR Unsupported data format!\n"); 100 goto finish; 101 } 102 103 testFd = open("/data/aaudio_temp.raw", O_CREAT | O_RDWR, S_IRWXU); 104 printf("testFd = %d, pid = %d\n", testFd, getpid()); 105 106 // Start the stream. 107 printf("call player.start()\n"); 108 result = player.start(); 109 if (result != AAUDIO_OK) { 110 fprintf(stderr, "ERROR - AAudioStream_requestStart() returned %d\n", result); 111 goto finish; 112 } 113 114 printf("after start, state = %s\n", 115 AAudio_convertStreamStateToText(AAudioStream_getState(aaudioStream))); 116 117 // Play for a while. 118 framesToPlay = actualSampleRate * argParser.getDurationSeconds(); 119 framesLeft = framesToPlay; 120 while (framesLeft > 0) { 121 122 if (actualDataFormat == AAUDIO_FORMAT_PCM_FLOAT) { 123 // Render sine waves to left and right channels. 124 myData.sineOsc1.render(&floatData[0], actualChannelCount, framesPerWrite); 125 if (actualChannelCount > 1) { 126 myData.sineOsc2.render(&floatData[1], actualChannelCount, framesPerWrite); 127 } 128 } else if (actualDataFormat == AAUDIO_FORMAT_PCM_I16) { 129 // Render sine waves to left and right channels. 130 myData.sineOsc1.render(&shortData[0], actualChannelCount, framesPerWrite); 131 if (actualChannelCount > 1) { 132 myData.sineOsc2.render(&shortData[1], actualChannelCount, framesPerWrite); 133 } 134 } 135 136 // Write audio data to the stream. 137 int64_t timeoutNanos = 1000 * NANOS_PER_MILLISECOND; 138 int32_t minFrames = (framesToPlay < framesPerWrite) ? framesToPlay : framesPerWrite; 139 int32_t actual = 0; 140 if (actualDataFormat == AAUDIO_FORMAT_PCM_FLOAT) { 141 actual = AAudioStream_write(aaudioStream, floatData, minFrames, timeoutNanos); 142 } else if (actualDataFormat == AAUDIO_FORMAT_PCM_I16) { 143 actual = AAudioStream_write(aaudioStream, shortData, minFrames, timeoutNanos); 144 } 145 if (actual < 0) { 146 fprintf(stderr, "ERROR - AAudioStream_write() returned %d\n", actual); 147 goto finish; 148 } else if (actual == 0) { 149 fprintf(stderr, "WARNING - AAudioStream_write() returned %d\n", actual); 150 goto finish; 151 } 152 framesLeft -= actual; 153 154 // Use timestamp to estimate latency. 155 /* 156 { 157 int64_t presentationFrame; 158 int64_t presentationTime; 159 result = AAudioStream_getTimestamp(aaudioStream, 160 CLOCK_MONOTONIC, 161 &presentationFrame, 162 &presentationTime 163 ); 164 if (result == AAUDIO_OK) { 165 int64_t elapsedNanos = getNanoseconds() - presentationTime; 166 int64_t elapsedFrames = actualSampleRate * elapsedNanos / NANOS_PER_SECOND; 167 int64_t currentFrame = presentationFrame + elapsedFrames; 168 int64_t framesWritten = AAudioStream_getFramesWritten(aaudioStream); 169 int64_t estimatedLatencyFrames = framesWritten - currentFrame; 170 int64_t estimatedLatencyMillis = estimatedLatencyFrames * 1000 / actualSampleRate; 171 printf("estimatedLatencyMillis %d\n", (int)estimatedLatencyMillis); 172 } 173 } 174 */ 175 } 176 177 xRunCount = AAudioStream_getXRunCount(aaudioStream); 178 printf("AAudioStream_getXRunCount %d\n", xRunCount); 179 180 printf("call stop()\n"); 181 result = player.stop(); 182 if (result != AAUDIO_OK) { 183 goto finish; 184 } 185 186finish: 187 printf("testFd = %d, fcntl before aaudio close returns 0x%08X\n", 188 testFd, fcntl(testFd, F_GETFD)); 189 player.close(); 190 printf("testFd = %d, fcntl after aaudio close returns 0x%08X\n", 191 testFd, fcntl(testFd, F_GETFD)); 192 if (::close(testFd) != 0) { 193 printf("ERROR SharedMemoryParcelable::close() of testFd = %d, errno = %s\n", 194 testFd, strerror(errno)); 195 } 196 printf("testFd = %d, fcntl after close() returns 0x%08X\n", testFd, fcntl(testFd, F_GETFD)); 197 198 delete[] floatData; 199 delete[] shortData; 200 printf("exiting - AAudio result = %d = %s\n", result, AAudio_convertResultToText(result)); 201 return (result != AAUDIO_OK) ? EXIT_FAILURE : EXIT_SUCCESS; 202} 203 204