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 
main(int argc,const char ** argv)33 int 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  framesToPlay = 0;
48     int32_t  framesLeft = 0;
49     int32_t  xRunCount = 0;
50     int      numActiveOscillators = 0;
51     float   *floatData = nullptr;
52     int16_t *shortData = nullptr;
53     int32_t *int32Data = nullptr;
54     uint8_t *byteData = nullptr;
55 
56     int      testFd = -1;
57 
58     // Make printf print immediately so that debug info is not stuck
59     // in a buffer if we hang or crash.
60     setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
61 
62     printf("%s - Play a sine wave using AAudio V0.1.4\n", argv[0]);
63 
64     if (argParser.parseArgs(argc, argv)) {
65         return EXIT_FAILURE;
66     }
67 
68     result = player.open(argParser);
69     if (result != AAUDIO_OK) {
70         fprintf(stderr, "ERROR -  player.open() returned %d\n", result);
71         goto finish;
72     }
73 
74     aaudioStream = player.getStream();
75 
76     argParser.compareWithStream(aaudioStream);
77 
78     actualChannelCount = AAudioStream_getChannelCount(aaudioStream);
79     actualSampleRate = AAudioStream_getSampleRate(aaudioStream);
80     actualDataFormat = AAudioStream_getFormat(aaudioStream);
81 
82     myData.sampleRate = actualSampleRate;
83     myData.setupSineSweeps();
84 
85     // Some DMA might use very short bursts of 16 frames. We don't need to write such small
86     // buffers. But it helps to use a multiple of the burst size for predictable scheduling.
87     framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream);
88     framesPerWrite = framesPerBurst;
89     while (framesPerWrite < 48) {
90         framesPerWrite *= 2;
91     }
92     printf("Buffer: framesPerBurst = %d\n",framesPerBurst);
93     printf("Buffer: framesPerWrite = %d\n",framesPerWrite);
94 
95     // Allocate a buffer for the audio data.
96     switch (actualDataFormat) {
97         case AAUDIO_FORMAT_PCM_FLOAT:
98             floatData = new float[framesPerWrite * actualChannelCount];
99             break;
100         case AAUDIO_FORMAT_PCM_I16:
101             shortData = new int16_t[framesPerWrite * actualChannelCount];
102             break;
103         case AAUDIO_FORMAT_PCM_I24_PACKED:
104             byteData = new uint8_t[framesPerWrite * actualChannelCount
105                                    * getBytesPerSample(AAUDIO_FORMAT_PCM_I24_PACKED)];
106             break;
107         case AAUDIO_FORMAT_PCM_I32:
108             int32Data = new int32_t[framesPerWrite * actualChannelCount];
109             break;
110         default:
111             printf("ERROR Unsupported data format!\n");
112             goto finish;
113     }
114 
115     testFd = open("/data/aaudio_temp.raw", O_CREAT | O_RDWR, S_IRWXU);
116     printf("testFd = %d, pid = %d\n", testFd, getpid());
117 
118     // Start the stream.
119     printf("call player.start()\n");
120     result = player.start();
121     if (result != AAUDIO_OK) {
122         fprintf(stderr, "ERROR - AAudioStream_requestStart() returned %d\n", result);
123         goto finish;
124     }
125 
126     printf("after start, state = %s\n",
127             AAudio_convertStreamStateToText(AAudioStream_getState(aaudioStream)));
128 
129     // Play for a while.
130     framesToPlay = actualSampleRate * argParser.getDurationSeconds();
131     framesLeft = framesToPlay;
132     numActiveOscillators = (actualChannelCount > MAX_CHANNELS) ? MAX_CHANNELS : actualChannelCount;
133     while (framesLeft > 0) {
134         // Render as FLOAT or PCM
135         switch (actualDataFormat) {
136             case AAUDIO_FORMAT_PCM_FLOAT:
137                 for (int i = 0; i < numActiveOscillators; ++i) {
138                     myData.sineOscillators[i].render(&floatData[i], actualChannelCount,
139                                                      framesPerWrite);
140                 }
141                 break;
142             case AAUDIO_FORMAT_PCM_I16:
143                 for (int i = 0; i < numActiveOscillators; ++i) {
144                     myData.sineOscillators[i].render(&shortData[i], actualChannelCount,
145                                                      framesPerWrite);
146                 }
147                 break;
148             case AAUDIO_FORMAT_PCM_I32:
149                 for (int i = 0; i < numActiveOscillators; ++i) {
150                     myData.sineOscillators[i].render(&int32Data[i], actualChannelCount,
151                                                      framesPerWrite);
152                 }
153                 break;
154             case AAUDIO_FORMAT_PCM_I24_PACKED:
155                 for (int i = 0; i < numActiveOscillators; ++i) {
156                     static const int
157                         bytesPerSample = getBytesPerSample(AAUDIO_FORMAT_PCM_I24_PACKED);
158                     myData.sineOscillators[i].render24(&byteData[i * bytesPerSample],
159                                                        actualChannelCount,
160                                                        framesPerWrite);
161                 }
162                 break;
163         }
164 
165         // Write audio data to the stream.
166         int64_t timeoutNanos = 1000 * NANOS_PER_MILLISECOND;
167         int32_t minFrames = (framesToPlay < framesPerWrite) ? framesToPlay : framesPerWrite;
168         int32_t actual = 0;
169         switch (actualDataFormat) {
170             case AAUDIO_FORMAT_PCM_FLOAT:
171                 actual = AAudioStream_write(aaudioStream, floatData, minFrames, timeoutNanos);
172                 break;
173             case AAUDIO_FORMAT_PCM_I16:
174                 actual = AAudioStream_write(aaudioStream, shortData, minFrames, timeoutNanos);
175                 break;
176             case AAUDIO_FORMAT_PCM_I32:
177                 actual = AAudioStream_write(aaudioStream, int32Data, minFrames, timeoutNanos);
178                 break;
179             case AAUDIO_FORMAT_PCM_I24_PACKED:
180                 actual = AAudioStream_write(aaudioStream, byteData, minFrames, timeoutNanos);
181                 break;
182         }
183         if (actual < 0) {
184             fprintf(stderr, "ERROR - AAudioStream_write() returned %d\n", actual);
185             goto finish;
186         } else if (actual == 0) {
187             fprintf(stderr, "WARNING - AAudioStream_write() returned %d\n", actual);
188             goto finish;
189         }
190         framesLeft -= actual;
191 
192         // Use timestamp to estimate latency.
193         /*
194         {
195             int64_t presentationFrame;
196             int64_t presentationTime;
197             result = AAudioStream_getTimestamp(aaudioStream,
198                                                CLOCK_MONOTONIC,
199                                                &presentationFrame,
200                                                &presentationTime
201                                                );
202             if (result == AAUDIO_OK) {
203                 int64_t elapsedNanos = getNanoseconds() - presentationTime;
204                 int64_t elapsedFrames = actualSampleRate * elapsedNanos / NANOS_PER_SECOND;
205                 int64_t currentFrame = presentationFrame + elapsedFrames;
206                 int64_t framesWritten = AAudioStream_getFramesWritten(aaudioStream);
207                 int64_t estimatedLatencyFrames = framesWritten - currentFrame;
208                 int64_t estimatedLatencyMillis = estimatedLatencyFrames * 1000 / actualSampleRate;
209                 printf("estimatedLatencyMillis %d\n", (int)estimatedLatencyMillis);
210             }
211         }
212          */
213     }
214 
215     xRunCount = AAudioStream_getXRunCount(aaudioStream);
216     printf("AAudioStream_getXRunCount %d\n", xRunCount);
217 
218     printf("call stop()\n");
219     result = player.stop();
220     if (result != AAUDIO_OK) {
221         goto finish;
222     }
223 
224 finish:
225     printf("testFd = %d, fcntl before aaudio close returns 0x%08X\n",
226            testFd, fcntl(testFd, F_GETFD));
227     player.close();
228     printf("testFd = %d, fcntl after aaudio close returns 0x%08X\n",
229            testFd, fcntl(testFd, F_GETFD));
230     if (::close(testFd) != 0) {
231         printf("ERROR SharedMemoryParcelable::close() of testFd = %d, errno = %s\n",
232                testFd, strerror(errno));
233     }
234     printf("testFd = %d, fcntl after close() returns 0x%08X\n", testFd, fcntl(testFd, F_GETFD));
235 
236     delete[] floatData;
237     delete[] shortData;
238     delete[] int32Data;
239     delete[] byteData;
240     printf("exiting - AAudio result = %d = %s\n", result, AAudio_convertResultToText(result));
241     return (result != AAUDIO_OK) ? EXIT_FAILURE : EXIT_SUCCESS;
242 }
243 
244