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