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