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