blob: b57f0a4e6c87bab11d91980fac484a94eef220e6 [file] [log] [blame]
Phil Burk97350f92017-07-21 15:59:44 -07001/*
2 * Copyright (C) 2017 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 silence and recover from dead servers or disconnected devices.
18
19#include <stdio.h>
Phil Burkcda5c072017-08-31 17:23:18 -070020#include <stdlib.h>
Phil Burk97350f92017-07-21 15:59:44 -070021#include <unistd.h>
22
23#include <aaudio/AAudio.h>
24#include <aaudio/AAudioTesting.h>
Phil Burk97350f92017-07-21 15:59:44 -070025#include "utils/AAudioExampleUtils.h"
Phil Burkcda5c072017-08-31 17:23:18 -070026#include "../examples/utils/AAudioExampleUtils.h"
Phil Burk97350f92017-07-21 15:59:44 -070027
Phil Burkcda5c072017-08-31 17:23:18 -070028// Arbitrary period for glitches, once per second at 48000 Hz.
29#define FORCED_UNDERRUN_PERIOD_FRAMES 48000
30// How long to sleep in a callback to cause an intentional glitch. For testing.
31#define FORCED_UNDERRUN_SLEEP_MICROS (10 * 1000)
Phil Burk97350f92017-07-21 15:59:44 -070032
Phil Burkcda5c072017-08-31 17:23:18 -070033#define MAX_TIMESTAMPS 1000
Phil Burk97350f92017-07-21 15:59:44 -070034
Phil Burkcda5c072017-08-31 17:23:18 -070035#define DEFAULT_TIMEOUT_NANOS ((int64_t)1000000000)
36
37#define NUM_SECONDS 1
38#define NUM_LOOPS 4
39
40typedef struct TimestampInfo {
41 int64_t framesTotal;
42 int64_t appPosition; // frames
43 int64_t appNanoseconds;
44 int64_t timestampPosition; // frames
45 int64_t timestampNanos;
46 aaudio_result_t result;
47} TimestampInfo;
48
49typedef struct TimestampCallbackData_s {
50 TimestampInfo timestamps[MAX_TIMESTAMPS];
51 int64_t framesTotal = 0;
52 int64_t nextFrameToGlitch = FORCED_UNDERRUN_PERIOD_FRAMES;
53 int32_t timestampCount = 0; // in timestamps
54 bool forceUnderruns = false;
55} TimestampCallbackData_t;
56
57// Callback function that fills the audio output buffer.
58aaudio_data_callback_result_t timestampDataCallbackProc(
59 AAudioStream *stream,
60 void *userData,
61 void *audioData __unused,
62 int32_t numFrames
63) {
64
65 // should not happen but just in case...
66 if (userData == nullptr) {
67 printf("ERROR - SimplePlayerDataCallbackProc needs userData\n");
68 return AAUDIO_CALLBACK_RESULT_STOP;
69 }
70 TimestampCallbackData_t *timestampData = (TimestampCallbackData_t *) userData;
71
72 aaudio_direction_t direction = AAudioStream_getDirection(stream);
73 if (direction == AAUDIO_DIRECTION_INPUT) {
74 timestampData->framesTotal += numFrames;
75 }
76
77 if (timestampData->forceUnderruns) {
78 if (timestampData->framesTotal > timestampData->nextFrameToGlitch) {
79 usleep(FORCED_UNDERRUN_SLEEP_MICROS);
80 printf("Simulate glitch at %lld\n", (long long) timestampData->framesTotal);
81 timestampData->nextFrameToGlitch += FORCED_UNDERRUN_PERIOD_FRAMES;
82 }
83 }
84
85 if (timestampData->timestampCount < MAX_TIMESTAMPS) {
86 TimestampInfo *timestamp = &timestampData->timestamps[timestampData->timestampCount];
87 timestamp->result = AAudioStream_getTimestamp(stream,
88 CLOCK_MONOTONIC,
89 &timestamp->timestampPosition,
90 &timestamp->timestampNanos);
91 timestamp->framesTotal = timestampData->framesTotal;
92 timestamp->appPosition = (direction == AAUDIO_DIRECTION_OUTPUT)
93 ? AAudioStream_getFramesWritten(stream)
94 : AAudioStream_getFramesRead(stream);
95 timestamp->appNanoseconds = getNanoseconds();
96 timestampData->timestampCount++;
97 }
98
99 if (direction == AAUDIO_DIRECTION_OUTPUT) {
100 timestampData->framesTotal += numFrames;
101 }
102 return AAUDIO_CALLBACK_RESULT_CONTINUE;
103}
104
105static TimestampCallbackData_t sTimestampData;
106
107static aaudio_result_t testTimeStamps(aaudio_policy_t mmapPolicy,
108 aaudio_sharing_mode_t sharingMode,
109 aaudio_performance_mode_t performanceMode,
110 aaudio_direction_t direction) {
Phil Burk97350f92017-07-21 15:59:44 -0700111 aaudio_result_t result = AAUDIO_OK;
112
Phil Burk97350f92017-07-21 15:59:44 -0700113 int32_t framesPerBurst = 0;
Phil Burk97350f92017-07-21 15:59:44 -0700114 int32_t actualChannelCount = 0;
115 int32_t actualSampleRate = 0;
116 int32_t originalBufferSize = 0;
117 int32_t requestedBufferSize = 0;
118 int32_t finalBufferSize = 0;
119 aaudio_format_t actualDataFormat = AAUDIO_FORMAT_PCM_FLOAT;
120 aaudio_sharing_mode_t actualSharingMode = AAUDIO_SHARING_MODE_SHARED;
Phil Burkcda5c072017-08-31 17:23:18 -0700121 aaudio_sharing_mode_t actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
Phil Burk97350f92017-07-21 15:59:44 -0700122
123 AAudioStreamBuilder *aaudioBuilder = nullptr;
124 AAudioStream *aaudioStream = nullptr;
125
Phil Burkcda5c072017-08-31 17:23:18 -0700126 memset(&sTimestampData, 0, sizeof(sTimestampData));
Phil Burk97350f92017-07-21 15:59:44 -0700127
Phil Burkcda5c072017-08-31 17:23:18 -0700128 printf("------------ testTimeStamps(policy = %d, sharing = %s, perf = %s, dir = %s) -----------\n",
129 mmapPolicy,
130 getSharingModeText(sharingMode),
131 getPerformanceModeText(performanceMode),
132 getDirectionText(direction));
Phil Burk97350f92017-07-21 15:59:44 -0700133
Phil Burkcda5c072017-08-31 17:23:18 -0700134 AAudio_setMMapPolicy(mmapPolicy);
Phil Burk97350f92017-07-21 15:59:44 -0700135
136 // Use an AAudioStreamBuilder to contain requested parameters.
137 result = AAudio_createStreamBuilder(&aaudioBuilder);
138 if (result != AAUDIO_OK) {
139 printf("AAudio_createStreamBuilder returned %s",
140 AAudio_convertResultToText(result));
141 goto finish;
142 }
143
144 // Request stream properties.
Phil Burkcda5c072017-08-31 17:23:18 -0700145 AAudioStreamBuilder_setFormat(aaudioBuilder, AAUDIO_FORMAT_PCM_I16);
146 AAudioStreamBuilder_setSharingMode(aaudioBuilder, sharingMode);
147 AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, performanceMode);
148 AAudioStreamBuilder_setDirection(aaudioBuilder, direction);
149 AAudioStreamBuilder_setDataCallback(aaudioBuilder, timestampDataCallbackProc, &sTimestampData);
Phil Burk97350f92017-07-21 15:59:44 -0700150
151 // Create an AAudioStream using the Builder.
152 result = AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream);
153 if (result != AAUDIO_OK) {
154 printf("AAudioStreamBuilder_openStream returned %s",
155 AAudio_convertResultToText(result));
156 goto finish;
157 }
158
159 // Check to see what kind of stream we actually got.
160 actualSampleRate = AAudioStream_getSampleRate(aaudioStream);
161 actualChannelCount = AAudioStream_getChannelCount(aaudioStream);
162 actualDataFormat = AAudioStream_getFormat(aaudioStream);
163
Phil Burkcda5c072017-08-31 17:23:18 -0700164 actualSharingMode = AAudioStream_getSharingMode(aaudioStream);
165 if (actualSharingMode != sharingMode) {
166 printf("did not get expected sharingMode, got %3d, skipping test\n",
167 actualSharingMode);
168 result = AAUDIO_OK;
169 goto finish;
170 }
171 actualPerformanceMode = AAudioStream_getPerformanceMode(aaudioStream);
172 if (actualPerformanceMode != performanceMode) {
173 printf("did not get expected performanceMode, got %3d, skipping test\n",
174 actualPerformanceMode);
175 result = AAUDIO_OK;
176 goto finish;
177 }
178
179 printf(" chans = %3d, rate = %6d format = %d\n",
180 actualChannelCount, actualSampleRate, actualDataFormat);
Phil Burk97350f92017-07-21 15:59:44 -0700181 printf(" Is MMAP used? %s\n", AAudioStream_isMMapUsed(aaudioStream)
Phil Burkcda5c072017-08-31 17:23:18 -0700182 ? "yes" : "no");
Phil Burk97350f92017-07-21 15:59:44 -0700183
184 // This is the number of frames that are read in one chunk by a DMA controller
185 // or a DSP or a mixer.
186 framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream);
187 printf(" framesPerBurst = %3d\n", framesPerBurst);
188
189 originalBufferSize = AAudioStream_getBufferSizeInFrames(aaudioStream);
Phil Burkcda5c072017-08-31 17:23:18 -0700190 requestedBufferSize = 4 * framesPerBurst;
Phil Burk97350f92017-07-21 15:59:44 -0700191 finalBufferSize = AAudioStream_setBufferSizeInFrames(aaudioStream, requestedBufferSize);
192
193 printf(" BufferSize: original = %4d, requested = %4d, final = %4d\n",
194 originalBufferSize, requestedBufferSize, finalBufferSize);
195
Phil Burkcda5c072017-08-31 17:23:18 -0700196 {
197 int64_t position;
198 int64_t nanoseconds;
199 result = AAudioStream_getTimestamp(aaudioStream, CLOCK_MONOTONIC, &position, &nanoseconds);
200 printf("before start, AAudioStream_getTimestamp() returns %s\n",
Phil Burk97350f92017-07-21 15:59:44 -0700201 AAudio_convertResultToText(result));
Phil Burk97350f92017-07-21 15:59:44 -0700202 }
203
Phil Burkcda5c072017-08-31 17:23:18 -0700204 for (int runs = 0; runs < NUM_LOOPS; runs++) {
205 printf("------------------ loop #%d\n", runs);
206
207 int64_t temp = sTimestampData.framesTotal;
208 memset(&sTimestampData, 0, sizeof(sTimestampData));
209 sTimestampData.framesTotal = temp;
210
211 sTimestampData.forceUnderruns = false;
212
213 result = AAudioStream_requestStart(aaudioStream);
214 if (result != AAUDIO_OK) {
215 printf("AAudioStream_requestStart returned %s",
216 AAudio_convertResultToText(result));
217 goto finish;
218 }
219
220 for (int second = 0; second < NUM_SECONDS; second++) {
221 // Give AAudio callback time to run in the background.
222 sleep(1);
223
224 // Periodically print the progress so we know it hasn't died.
225 printf("framesWritten = %d, XRuns = %d\n",
226 (int) AAudioStream_getFramesWritten(aaudioStream),
227 (int) AAudioStream_getXRunCount(aaudioStream)
228 );
229 }
230
231 result = AAudioStream_requestStop(aaudioStream);
232 if (result != AAUDIO_OK) {
233 printf("AAudioStream_requestStop returned %s\n",
234 AAudio_convertResultToText(result));
235 }
236
237 printf("timestampCount = %d\n", sTimestampData.timestampCount);
238 int printed = 0;
239 for (int i = 0; i < sTimestampData.timestampCount; i++) {
240 TimestampInfo *timestamp = &sTimestampData.timestamps[i];
241 bool posChanged = (timestamp->timestampPosition != (timestamp - 1)->timestampPosition);
242 bool timeChanged = (timestamp->timestampNanos != (timestamp - 1)->timestampNanos);
243 if ((printed < 20) && ((i < 10) || posChanged || timeChanged)) {
244 printf(" %3d : frames %8lld, xferd %8lld", i,
245 (long long) timestamp->framesTotal,
246 (long long) timestamp->appPosition);
247 if (timestamp->result != AAUDIO_OK) {
248 printf(", result = %s\n", AAudio_convertResultToText(timestamp->result));
249 } else {
250 bool negative = timestamp->timestampPosition < 0;
251 bool retro = (i > 0 && (timestamp->timestampPosition <
252 (timestamp - 1)->timestampPosition));
253 const char *message = negative ? " <=NEGATIVE!"
254 : (retro ? " <= RETROGRADE!" : "");
255
256 double latency = calculateLatencyMillis(timestamp->timestampPosition,
257 timestamp->timestampNanos,
258 timestamp->appPosition,
259 timestamp->appNanoseconds,
260 actualSampleRate);
261 printf(", STAMP: pos = %8lld, nanos = %8lld, lat = %7.1f msec %s\n",
262 (long long) timestamp->timestampPosition,
263 (long long) timestamp->timestampNanos,
264 latency,
265 message);
266 }
267 printed++;
Phil Burk97350f92017-07-21 15:59:44 -0700268 }
269 }
270
Phil Burkcda5c072017-08-31 17:23:18 -0700271 // Avoid race conditions in AudioFlinger.
272 // There is normally a delay between a real user stopping and restarting a stream.
273 sleep(1);
Phil Burk97350f92017-07-21 15:59:44 -0700274 }
275
Phil Burk97350f92017-07-21 15:59:44 -0700276finish:
277 if (aaudioStream != nullptr) {
278 AAudioStream_close(aaudioStream);
279 }
280 AAudioStreamBuilder_delete(aaudioBuilder);
Phil Burk97350f92017-07-21 15:59:44 -0700281 printf("result = %d = %s\n", result, AAudio_convertResultToText(result));
Phil Burkcda5c072017-08-31 17:23:18 -0700282
283 return result;
284}
285
286int main(int argc, char **argv) {
287 (void) argc;
Chih-Hung Hsieh68326fe2017-10-31 13:49:24 -0700288 (void) argv;
Phil Burkcda5c072017-08-31 17:23:18 -0700289
290 aaudio_result_t result = AAUDIO_OK;
291
292 // Make printf print immediately so that debug info is not stuck
293 // in a buffer if we hang or crash.
294 setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
295
Phil Burkc75d97f2017-09-08 15:48:36 -0700296 printf("Test Timestamps V0.1.3\n");
297
Phil Burkcda5c072017-08-31 17:23:18 -0700298 // Legacy
Phil Burkc75d97f2017-09-08 15:48:36 -0700299 aaudio_policy_t policy = AAUDIO_POLICY_NEVER;
300 result = testTimeStamps(policy,
301 AAUDIO_SHARING_MODE_SHARED,
302 AAUDIO_PERFORMANCE_MODE_NONE,
303 AAUDIO_DIRECTION_INPUT);
304 result = testTimeStamps(policy,
305 AAUDIO_SHARING_MODE_SHARED,
306 AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
307 AAUDIO_DIRECTION_INPUT);
308 result = testTimeStamps(policy,
309 AAUDIO_SHARING_MODE_SHARED,
310 AAUDIO_PERFORMANCE_MODE_NONE,
311 AAUDIO_DIRECTION_OUTPUT);
312 result = testTimeStamps(policy,
313 AAUDIO_SHARING_MODE_SHARED,
Phil Burkcda5c072017-08-31 17:23:18 -0700314 AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
315 AAUDIO_DIRECTION_OUTPUT);
Phil Burkc75d97f2017-09-08 15:48:36 -0700316
317 // MMAP
318 policy = AAUDIO_POLICY_ALWAYS;
319 result = testTimeStamps(policy,
320 AAUDIO_SHARING_MODE_EXCLUSIVE,
321 AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
322 AAUDIO_DIRECTION_INPUT);
323 result = testTimeStamps(policy,
324 AAUDIO_SHARING_MODE_EXCLUSIVE,
325 AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
326 AAUDIO_DIRECTION_OUTPUT);
327 result = testTimeStamps(policy,
328 AAUDIO_SHARING_MODE_SHARED,
329 AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
330 AAUDIO_DIRECTION_INPUT);
331 result = testTimeStamps(policy,
332 AAUDIO_SHARING_MODE_SHARED,
333 AAUDIO_PERFORMANCE_MODE_LOW_LATENCY,
334 AAUDIO_DIRECTION_OUTPUT);
Phil Burkcda5c072017-08-31 17:23:18 -0700335
336 return (result == AAUDIO_OK) ? EXIT_SUCCESS : EXIT_FAILURE;
Phil Burk97350f92017-07-21 15:59:44 -0700337}