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 <stdio.h> 20#include <stdlib.h> 21#include <math.h> 22#include <aaudio/AAudio.h> 23#include <aaudio/AAudioTesting.h> 24#include "AAudioExampleUtils.h" 25#include "AAudioSimplePlayer.h" 26 27#define SAMPLE_RATE 48000 28#define NUM_SECONDS 20 29 30#define MMAP_POLICY AAUDIO_UNSPECIFIED 31//#define MMAP_POLICY AAUDIO_POLICY_NEVER 32//#define MMAP_POLICY AAUDIO_POLICY_AUTO 33//#define MMAP_POLICY AAUDIO_POLICY_ALWAYS 34 35#define REQUESTED_FORMAT AAUDIO_FORMAT_PCM_I16 36 37#define REQUESTED_SHARING_MODE AAUDIO_SHARING_MODE_SHARED 38//#define REQUESTED_SHARING_MODE AAUDIO_SHARING_MODE_EXCLUSIVE 39 40 41int main(int argc, char **argv) 42{ 43 (void)argc; // unused 44 45 AAudioSimplePlayer player; 46 SineThreadedData_t myData; 47 aaudio_result_t result = AAUDIO_OK; 48 49 const int requestedChannelCount = 2; 50 int actualChannelCount = 0; 51 const int requestedSampleRate = SAMPLE_RATE; 52 int actualSampleRate = 0; 53 aaudio_format_t requestedDataFormat = REQUESTED_FORMAT; 54 aaudio_format_t actualDataFormat = AAUDIO_FORMAT_UNSPECIFIED; 55 aaudio_sharing_mode_t actualSharingMode = AAUDIO_SHARING_MODE_SHARED; 56 57 AAudioStream *aaudioStream = nullptr; 58 aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNINITIALIZED; 59 int32_t framesPerBurst = 0; 60 int32_t framesPerWrite = 0; 61 int32_t bufferCapacity = 0; 62 int32_t framesToPlay = 0; 63 int32_t framesLeft = 0; 64 int32_t xRunCount = 0; 65 float *floatData = nullptr; 66 int16_t *shortData = nullptr; 67 68 // Make printf print immediately so that debug info is not stuck 69 // in a buffer if we hang or crash. 70 setvbuf(stdout, nullptr, _IONBF, (size_t) 0); 71 72 printf("%s - Play a sine wave using AAudio\n", argv[0]); 73 74 AAudio_setMMapPolicy(MMAP_POLICY); 75 printf("requested MMapPolicy = %d\n", AAudio_getMMapPolicy()); 76 77 player.setSharingMode(REQUESTED_SHARING_MODE); 78 79 result = player.open(requestedChannelCount, requestedSampleRate, requestedDataFormat, 80 nullptr, nullptr, &myData); 81 if (result != AAUDIO_OK) { 82 fprintf(stderr, "ERROR - player.open() returned %d\n", result); 83 goto finish; 84 } 85 86 aaudioStream = player.getStream(); 87 // Request stream properties. 88 89 state = AAudioStream_getState(aaudioStream); 90 printf("after open, state = %s\n", AAudio_convertStreamStateToText(state)); 91 92 // Check to see what kind of stream we actually got. 93 actualSampleRate = AAudioStream_getSampleRate(aaudioStream); 94 printf("SampleRate: requested = %d, actual = %d\n", requestedSampleRate, actualSampleRate); 95 96 myData.sineOsc1.setup(440.0, actualSampleRate); 97 myData.sineOsc2.setup(660.0, actualSampleRate); 98 99 actualChannelCount = AAudioStream_getChannelCount(aaudioStream); 100 printf("ChannelCount: requested = %d, actual = %d\n", 101 requestedChannelCount, actualChannelCount); 102 103 actualSharingMode = AAudioStream_getSharingMode(aaudioStream); 104 printf("SharingMode: requested = %s, actual = %s\n", 105 getSharingModeText(REQUESTED_SHARING_MODE), 106 getSharingModeText(actualSharingMode)); 107 108 // This is the number of frames that are read in one chunk by a DMA controller 109 // or a DSP or a mixer. 110 framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream); 111 printf("Buffer: bufferSize = %d\n", AAudioStream_getBufferSizeInFrames(aaudioStream)); 112 bufferCapacity = AAudioStream_getBufferCapacityInFrames(aaudioStream); 113 printf("Buffer: bufferCapacity = %d, remainder = %d\n", 114 bufferCapacity, bufferCapacity % framesPerBurst); 115 116 // Some DMA might use very short bursts of 16 frames. We don't need to write such small 117 // buffers. But it helps to use a multiple of the burst size for predictable scheduling. 118 framesPerWrite = framesPerBurst; 119 while (framesPerWrite < 48) { 120 framesPerWrite *= 2; 121 } 122 printf("Buffer: framesPerBurst = %d\n",framesPerBurst); 123 printf("Buffer: framesPerWrite = %d\n",framesPerWrite); 124 125 printf("PerformanceMode = %d\n", AAudioStream_getPerformanceMode(aaudioStream)); 126 printf("is MMAP used? = %s\n", AAudioStream_isMMapUsed(aaudioStream) ? "yes" : "no"); 127 128 actualDataFormat = AAudioStream_getFormat(aaudioStream); 129 printf("DataFormat: requested = %d, actual = %d\n", REQUESTED_FORMAT, actualDataFormat); 130 // TODO handle other data formats 131 132 // Allocate a buffer for the audio data. 133 if (actualDataFormat == AAUDIO_FORMAT_PCM_FLOAT) { 134 floatData = new float[framesPerWrite * actualChannelCount]; 135 } else if (actualDataFormat == AAUDIO_FORMAT_PCM_I16) { 136 shortData = new int16_t[framesPerWrite * actualChannelCount]; 137 } else { 138 printf("ERROR Unsupported data format!\n"); 139 goto finish; 140 } 141 142 // Start the stream. 143 printf("call player.start()\n"); 144 result = player.start(); 145 if (result != AAUDIO_OK) { 146 fprintf(stderr, "ERROR - AAudioStream_requestStart() returned %d\n", result); 147 goto finish; 148 } 149 150 state = AAudioStream_getState(aaudioStream); 151 printf("after start, state = %s\n", AAudio_convertStreamStateToText(state)); 152 153 // Play for a while. 154 framesToPlay = actualSampleRate * NUM_SECONDS; 155 framesLeft = framesToPlay; 156 while (framesLeft > 0) { 157 158 if (actualDataFormat == AAUDIO_FORMAT_PCM_FLOAT) { 159 // Render sine waves to left and right channels. 160 myData.sineOsc1.render(&floatData[0], actualChannelCount, framesPerWrite); 161 if (actualChannelCount > 1) { 162 myData.sineOsc2.render(&floatData[1], actualChannelCount, framesPerWrite); 163 } 164 } else if (actualDataFormat == AAUDIO_FORMAT_PCM_I16) { 165 // Render sine waves to left and right channels. 166 myData.sineOsc1.render(&shortData[0], actualChannelCount, framesPerWrite); 167 if (actualChannelCount > 1) { 168 myData.sineOsc2.render(&shortData[1], actualChannelCount, framesPerWrite); 169 } 170 } 171 172 // Write audio data to the stream. 173 int64_t timeoutNanos = 1000 * NANOS_PER_MILLISECOND; 174 int32_t minFrames = (framesToPlay < framesPerWrite) ? framesToPlay : framesPerWrite; 175 int32_t actual = 0; 176 if (actualDataFormat == AAUDIO_FORMAT_PCM_FLOAT) { 177 actual = AAudioStream_write(aaudioStream, floatData, minFrames, timeoutNanos); 178 } else if (actualDataFormat == AAUDIO_FORMAT_PCM_I16) { 179 actual = AAudioStream_write(aaudioStream, shortData, minFrames, timeoutNanos); 180 } 181 if (actual < 0) { 182 fprintf(stderr, "ERROR - AAudioStream_write() returned %d\n", actual); 183 goto finish; 184 } else if (actual == 0) { 185 fprintf(stderr, "WARNING - AAudioStream_write() returned %d\n", actual); 186 goto finish; 187 } 188 framesLeft -= actual; 189 190 // Use timestamp to estimate latency. 191 /* 192 { 193 int64_t presentationFrame; 194 int64_t presentationTime; 195 result = AAudioStream_getTimestamp(aaudioStream, 196 CLOCK_MONOTONIC, 197 &presentationFrame, 198 &presentationTime 199 ); 200 if (result == AAUDIO_OK) { 201 int64_t elapsedNanos = getNanoseconds() - presentationTime; 202 int64_t elapsedFrames = actualSampleRate * elapsedNanos / NANOS_PER_SECOND; 203 int64_t currentFrame = presentationFrame + elapsedFrames; 204 int64_t framesWritten = AAudioStream_getFramesWritten(aaudioStream); 205 int64_t estimatedLatencyFrames = framesWritten - currentFrame; 206 int64_t estimatedLatencyMillis = estimatedLatencyFrames * 1000 / actualSampleRate; 207 printf("estimatedLatencyMillis %d\n", (int)estimatedLatencyMillis); 208 } 209 } 210 */ 211 } 212 213 xRunCount = AAudioStream_getXRunCount(aaudioStream); 214 printf("AAudioStream_getXRunCount %d\n", xRunCount); 215 216 printf("call stop()\n"); 217 result = player.stop(); 218 if (result != AAUDIO_OK) { 219 goto finish; 220 } 221 222finish: 223 player.close(); 224 delete[] floatData; 225 delete[] shortData; 226 printf("exiting - AAudio result = %d = %s\n", result, AAudio_convertResultToText(result)); 227 return (result != AAUDIO_OK) ? EXIT_FAILURE : EXIT_SUCCESS; 228} 229 230