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