test_timestamps.cpp revision c75d97f20843388b9084561635996a01a53d0c0f
1/* 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> 20#include <stdlib.h> 21#include <unistd.h> 22 23#include <aaudio/AAudio.h> 24#include <aaudio/AAudioTesting.h> 25#include "utils/AAudioExampleUtils.h" 26#include "../examples/utils/AAudioExampleUtils.h" 27 28// 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) 32 33#define MAX_TIMESTAMPS 1000 34 35#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 = ×tampData->timestamps[timestampData->timestampCount]; 87 timestamp->result = AAudioStream_getTimestamp(stream, 88 CLOCK_MONOTONIC, 89 ×tamp->timestampPosition, 90 ×tamp->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) { 111 aaudio_result_t result = AAUDIO_OK; 112 113 int32_t framesPerBurst = 0; 114 float *buffer = nullptr; 115 116 int32_t actualChannelCount = 0; 117 int32_t actualSampleRate = 0; 118 int32_t originalBufferSize = 0; 119 int32_t requestedBufferSize = 0; 120 int32_t finalBufferSize = 0; 121 aaudio_format_t actualDataFormat = AAUDIO_FORMAT_PCM_FLOAT; 122 aaudio_sharing_mode_t actualSharingMode = AAUDIO_SHARING_MODE_SHARED; 123 aaudio_sharing_mode_t actualPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE; 124 125 AAudioStreamBuilder *aaudioBuilder = nullptr; 126 AAudioStream *aaudioStream = nullptr; 127 128 memset(&sTimestampData, 0, sizeof(sTimestampData)); 129 130 printf("------------ testTimeStamps(policy = %d, sharing = %s, perf = %s, dir = %s) -----------\n", 131 mmapPolicy, 132 getSharingModeText(sharingMode), 133 getPerformanceModeText(performanceMode), 134 getDirectionText(direction)); 135 136 AAudio_setMMapPolicy(mmapPolicy); 137 138 // Use an AAudioStreamBuilder to contain requested parameters. 139 result = AAudio_createStreamBuilder(&aaudioBuilder); 140 if (result != AAUDIO_OK) { 141 printf("AAudio_createStreamBuilder returned %s", 142 AAudio_convertResultToText(result)); 143 goto finish; 144 } 145 146 // Request stream properties. 147 AAudioStreamBuilder_setFormat(aaudioBuilder, AAUDIO_FORMAT_PCM_I16); 148 AAudioStreamBuilder_setSharingMode(aaudioBuilder, sharingMode); 149 AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, performanceMode); 150 AAudioStreamBuilder_setDirection(aaudioBuilder, direction); 151 AAudioStreamBuilder_setDataCallback(aaudioBuilder, timestampDataCallbackProc, &sTimestampData); 152 153 // Create an AAudioStream using the Builder. 154 result = AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream); 155 if (result != AAUDIO_OK) { 156 printf("AAudioStreamBuilder_openStream returned %s", 157 AAudio_convertResultToText(result)); 158 goto finish; 159 } 160 161 // Check to see what kind of stream we actually got. 162 actualSampleRate = AAudioStream_getSampleRate(aaudioStream); 163 actualChannelCount = AAudioStream_getChannelCount(aaudioStream); 164 actualDataFormat = AAudioStream_getFormat(aaudioStream); 165 166 actualSharingMode = AAudioStream_getSharingMode(aaudioStream); 167 if (actualSharingMode != sharingMode) { 168 printf("did not get expected sharingMode, got %3d, skipping test\n", 169 actualSharingMode); 170 result = AAUDIO_OK; 171 goto finish; 172 } 173 actualPerformanceMode = AAudioStream_getPerformanceMode(aaudioStream); 174 if (actualPerformanceMode != performanceMode) { 175 printf("did not get expected performanceMode, got %3d, skipping test\n", 176 actualPerformanceMode); 177 result = AAUDIO_OK; 178 goto finish; 179 } 180 181 printf(" chans = %3d, rate = %6d format = %d\n", 182 actualChannelCount, actualSampleRate, actualDataFormat); 183 printf(" Is MMAP used? %s\n", AAudioStream_isMMapUsed(aaudioStream) 184 ? "yes" : "no"); 185 186 // This is the number of frames that are read in one chunk by a DMA controller 187 // or a DSP or a mixer. 188 framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream); 189 printf(" framesPerBurst = %3d\n", framesPerBurst); 190 191 originalBufferSize = AAudioStream_getBufferSizeInFrames(aaudioStream); 192 requestedBufferSize = 4 * framesPerBurst; 193 finalBufferSize = AAudioStream_setBufferSizeInFrames(aaudioStream, requestedBufferSize); 194 195 printf(" BufferSize: original = %4d, requested = %4d, final = %4d\n", 196 originalBufferSize, requestedBufferSize, finalBufferSize); 197 198 { 199 int64_t position; 200 int64_t nanoseconds; 201 result = AAudioStream_getTimestamp(aaudioStream, CLOCK_MONOTONIC, &position, &nanoseconds); 202 printf("before start, AAudioStream_getTimestamp() returns %s\n", 203 AAudio_convertResultToText(result)); 204 } 205 206 for (int runs = 0; runs < NUM_LOOPS; runs++) { 207 printf("------------------ loop #%d\n", runs); 208 209 int64_t temp = sTimestampData.framesTotal; 210 memset(&sTimestampData, 0, sizeof(sTimestampData)); 211 sTimestampData.framesTotal = temp; 212 213 sTimestampData.forceUnderruns = false; 214 215 result = AAudioStream_requestStart(aaudioStream); 216 if (result != AAUDIO_OK) { 217 printf("AAudioStream_requestStart returned %s", 218 AAudio_convertResultToText(result)); 219 goto finish; 220 } 221 222 for (int second = 0; second < NUM_SECONDS; second++) { 223 // Give AAudio callback time to run in the background. 224 sleep(1); 225 226 // Periodically print the progress so we know it hasn't died. 227 printf("framesWritten = %d, XRuns = %d\n", 228 (int) AAudioStream_getFramesWritten(aaudioStream), 229 (int) AAudioStream_getXRunCount(aaudioStream) 230 ); 231 } 232 233 result = AAudioStream_requestStop(aaudioStream); 234 if (result != AAUDIO_OK) { 235 printf("AAudioStream_requestStop returned %s\n", 236 AAudio_convertResultToText(result)); 237 } 238 239 printf("timestampCount = %d\n", sTimestampData.timestampCount); 240 int printed = 0; 241 for (int i = 0; i < sTimestampData.timestampCount; i++) { 242 TimestampInfo *timestamp = &sTimestampData.timestamps[i]; 243 bool posChanged = (timestamp->timestampPosition != (timestamp - 1)->timestampPosition); 244 bool timeChanged = (timestamp->timestampNanos != (timestamp - 1)->timestampNanos); 245 if ((printed < 20) && ((i < 10) || posChanged || timeChanged)) { 246 printf(" %3d : frames %8lld, xferd %8lld", i, 247 (long long) timestamp->framesTotal, 248 (long long) timestamp->appPosition); 249 if (timestamp->result != AAUDIO_OK) { 250 printf(", result = %s\n", AAudio_convertResultToText(timestamp->result)); 251 } else { 252 bool negative = timestamp->timestampPosition < 0; 253 bool retro = (i > 0 && (timestamp->timestampPosition < 254 (timestamp - 1)->timestampPosition)); 255 const char *message = negative ? " <=NEGATIVE!" 256 : (retro ? " <= RETROGRADE!" : ""); 257 258 double latency = calculateLatencyMillis(timestamp->timestampPosition, 259 timestamp->timestampNanos, 260 timestamp->appPosition, 261 timestamp->appNanoseconds, 262 actualSampleRate); 263 printf(", STAMP: pos = %8lld, nanos = %8lld, lat = %7.1f msec %s\n", 264 (long long) timestamp->timestampPosition, 265 (long long) timestamp->timestampNanos, 266 latency, 267 message); 268 } 269 printed++; 270 } 271 } 272 273 // Avoid race conditions in AudioFlinger. 274 // There is normally a delay between a real user stopping and restarting a stream. 275 sleep(1); 276 } 277 278finish: 279 if (aaudioStream != nullptr) { 280 AAudioStream_close(aaudioStream); 281 } 282 AAudioStreamBuilder_delete(aaudioBuilder); 283 printf("result = %d = %s\n", result, AAudio_convertResultToText(result)); 284 285 return result; 286} 287 288int main(int argc, char **argv) { 289 (void) argc; 290 (void *) argv; 291 292 aaudio_result_t result = AAUDIO_OK; 293 294 // Make printf print immediately so that debug info is not stuck 295 // in a buffer if we hang or crash. 296 setvbuf(stdout, nullptr, _IONBF, (size_t) 0); 297 298 printf("Test Timestamps V0.1.3\n"); 299 300 // Legacy 301 aaudio_policy_t policy = AAUDIO_POLICY_NEVER; 302 result = testTimeStamps(policy, 303 AAUDIO_SHARING_MODE_SHARED, 304 AAUDIO_PERFORMANCE_MODE_NONE, 305 AAUDIO_DIRECTION_INPUT); 306 result = testTimeStamps(policy, 307 AAUDIO_SHARING_MODE_SHARED, 308 AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, 309 AAUDIO_DIRECTION_INPUT); 310 result = testTimeStamps(policy, 311 AAUDIO_SHARING_MODE_SHARED, 312 AAUDIO_PERFORMANCE_MODE_NONE, 313 AAUDIO_DIRECTION_OUTPUT); 314 result = testTimeStamps(policy, 315 AAUDIO_SHARING_MODE_SHARED, 316 AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, 317 AAUDIO_DIRECTION_OUTPUT); 318 319 // MMAP 320 policy = AAUDIO_POLICY_ALWAYS; 321 result = testTimeStamps(policy, 322 AAUDIO_SHARING_MODE_EXCLUSIVE, 323 AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, 324 AAUDIO_DIRECTION_INPUT); 325 result = testTimeStamps(policy, 326 AAUDIO_SHARING_MODE_EXCLUSIVE, 327 AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, 328 AAUDIO_DIRECTION_OUTPUT); 329 result = testTimeStamps(policy, 330 AAUDIO_SHARING_MODE_SHARED, 331 AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, 332 AAUDIO_DIRECTION_INPUT); 333 result = testTimeStamps(policy, 334 AAUDIO_SHARING_MODE_SHARED, 335 AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, 336 AAUDIO_DIRECTION_OUTPUT); 337 338 return (result == AAUDIO_OK) ? EXIT_SUCCESS : EXIT_FAILURE; 339} 340