blob: 8bb2e861ee22504a73be91d5381a05004cf8ab9c [file] [log] [blame]
Phil Burk44795232017-06-30 16:27:38 -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#ifndef AAUDIO_EXAMPLE_ARGS_PARSER_H
18#define AAUDIO_EXAMPLE_ARGS_PARSER_H
19
Phil Burk67ed9da2017-09-06 16:26:52 -070020#define MAX_CHANNELS 8
21
Phil Burk4e98efa2018-02-05 18:41:55 -080022//#include <cctype>
23#include <dlfcn.h>
Phil Burk44795232017-06-30 16:27:38 -070024#include <unistd.h>
25#include <stdio.h>
26#include <stdlib.h>
27
28#include <aaudio/AAudio.h>
29#include <aaudio/AAudioTesting.h>
Phil Burka5222e22017-07-28 13:31:14 -070030
31#include "AAudioExampleUtils.h"
Phil Burk44795232017-06-30 16:27:38 -070032
Phil Burk4e98efa2018-02-05 18:41:55 -080033
34static void (*s_setUsage)(AAudioStreamBuilder* builder, aaudio_usage_t usage) = nullptr;
35static void (*s_setContentType)(AAudioStreamBuilder* builder,
36 aaudio_content_type_t contentType) = nullptr;
37static void (*s_setInputPreset)(AAudioStreamBuilder* builder,
38 aaudio_input_preset_t inputPreset) = nullptr;
39
40static bool s_loadAttempted = false;
41static aaudio_usage_t (*s_getUsage)(AAudioStream *stream) = nullptr;
42static aaudio_content_type_t (*s_getContentType)(AAudioStream *stream) = nullptr;
43static aaudio_input_preset_t (*s_getInputPreset)(AAudioStream *stream) = nullptr;
44
45// Link to test functions in shared library.
46static void loadFutureFunctions() {
47 if (s_loadAttempted) return; // only try once
48 s_loadAttempted = true;
49
50 void *handle = dlopen("libaaudio.so", RTLD_NOW);
51 if (handle != nullptr) {
52 s_setUsage = (void (*)(AAudioStreamBuilder *, aaudio_usage_t))
53 dlsym(handle, "AAudioStreamBuilder_setUsage");
54 if (s_setUsage == nullptr) goto error;
55
56 s_setContentType = (void (*)(AAudioStreamBuilder *, aaudio_content_type_t))
57 dlsym(handle, "AAudioStreamBuilder_setContentType");
58 if (s_setContentType == nullptr) goto error;
59
60 s_setInputPreset = (void (*)(AAudioStreamBuilder *, aaudio_input_preset_t))
61 dlsym(handle, "AAudioStreamBuilder_setInputPreset");
62 if (s_setInputPreset == nullptr) goto error;
63
64 s_getUsage = (aaudio_usage_t (*)(AAudioStream *))
65 dlsym(handle, "AAudioStream_getUsage");
66 if (s_getUsage == nullptr) goto error;
67
68 s_getContentType = (aaudio_content_type_t (*)(AAudioStream *))
69 dlsym(handle, "AAudioStream_getContentType");
70 if (s_getContentType == nullptr) goto error;
71
72 s_getInputPreset = (aaudio_input_preset_t (*)(AAudioStream *))
73 dlsym(handle, "AAudioStream_getInputPreset");
74 if (s_getInputPreset == nullptr) goto error;
75 }
76 return;
77
78error:
79 // prevent any calls to these functions
80 s_setUsage = nullptr;
81 s_setContentType = nullptr;
82 s_setInputPreset = nullptr;
83 s_getUsage = nullptr;
84 s_getContentType = nullptr;
85 s_getInputPreset = nullptr;
86 dlclose(handle);
87 return;
88}
89
Phil Burk44795232017-06-30 16:27:38 -070090class AAudioParameters {
91public:
92
93 /**
94 * This is also known as samplesPerFrame.
95 */
96 int32_t getChannelCount() const {
97 return mChannelCount;
98 }
99
100 void setChannelCount(int32_t channelCount) {
Phil Burk67ed9da2017-09-06 16:26:52 -0700101 if (channelCount > MAX_CHANNELS) {
102 printf("Sorry, MAX of %d channels!\n", MAX_CHANNELS);
103 channelCount = MAX_CHANNELS;
104 }
Phil Burk44795232017-06-30 16:27:38 -0700105 mChannelCount = channelCount;
106 }
107
108 int32_t getSampleRate() const {
109 return mSampleRate;
110 }
111
112 void setSampleRate(int32_t sampleRate) {
113 mSampleRate = sampleRate;
114 }
115
116 aaudio_format_t getFormat() const {
117 return mFormat;
118 }
119
120 void setFormat(aaudio_format_t format) {
121 mFormat = format;
122 }
123
124 aaudio_sharing_mode_t getSharingMode() const {
125 return mSharingMode;
126 }
127
128 void setSharingMode(aaudio_sharing_mode_t sharingMode) {
129 mSharingMode = sharingMode;
130 }
131
132 int32_t getBufferCapacity() const {
133 return mBufferCapacity;
134 }
135
136 void setBufferCapacity(int32_t frames) {
137 mBufferCapacity = frames;
138 }
139
140 int32_t getPerformanceMode() const {
141 return mPerformanceMode;
142 }
143
144 void setPerformanceMode(aaudio_performance_mode_t performanceMode) {
145 mPerformanceMode = performanceMode;
146 }
147
Phil Burk6d6f3f62018-01-12 17:27:54 -0800148 aaudio_usage_t getUsage() const {
149 return mUsage;
150 }
151
152 void setUsage(aaudio_usage_t usage) {
153 mUsage = usage;
154 }
155
156 aaudio_content_type_t getContentType() const {
157 return mContentType;
158 }
159
160 void setContentType(aaudio_content_type_t contentType) {
161 mContentType = contentType;
162 }
163
164 aaudio_input_preset_t getInputPreset() const {
165 return mInputPreset;
166 }
167
168 void setInputPreset(aaudio_input_preset_t inputPreset) {
169 mInputPreset = inputPreset;
170 }
171
Phil Burk44795232017-06-30 16:27:38 -0700172 int32_t getDeviceId() const {
173 return mDeviceId;
174 }
175
176 void setDeviceId(int32_t deviceId) {
177 mDeviceId = deviceId;
178 }
179
180 int32_t getNumberOfBursts() const {
181 return mNumberOfBursts;
182 }
183
184 void setNumberOfBursts(int32_t numBursts) {
185 mNumberOfBursts = numBursts;
186 }
187
Phil Burk10ffb192018-09-26 12:09:00 -0700188 int32_t getFramesPerCallback() const {
189 return mFramesPerCallback;
190 }
191 void setFramesPerCallback(int32_t size) {
192 mFramesPerCallback = size;
193 }
194
Phil Burk44795232017-06-30 16:27:38 -0700195 /**
196 * Apply these parameters to a stream builder.
197 * @param builder
198 */
199 void applyParameters(AAudioStreamBuilder *builder) const {
Phil Burke0a4d2a2018-11-05 11:40:36 -0800200 AAudioStreamBuilder_setBufferCapacityInFrames(builder, getBufferCapacity());
Phil Burk10ffb192018-09-26 12:09:00 -0700201 AAudioStreamBuilder_setChannelCount(builder, mChannelCount);
Phil Burk44795232017-06-30 16:27:38 -0700202 AAudioStreamBuilder_setDeviceId(builder, mDeviceId);
Phil Burk10ffb192018-09-26 12:09:00 -0700203 AAudioStreamBuilder_setFormat(builder, mFormat);
204 AAudioStreamBuilder_setFramesPerDataCallback(builder, mFramesPerCallback);
Phil Burk44795232017-06-30 16:27:38 -0700205 AAudioStreamBuilder_setPerformanceMode(builder, mPerformanceMode);
Phil Burk10ffb192018-09-26 12:09:00 -0700206 AAudioStreamBuilder_setSampleRate(builder, mSampleRate);
207 AAudioStreamBuilder_setSharingMode(builder, mSharingMode);
Phil Burk4e98efa2018-02-05 18:41:55 -0800208
209 // Call P functions if supported.
210 loadFutureFunctions();
211 if (s_setUsage != nullptr) {
212 s_setUsage(builder, mUsage);
213 } else if (mUsage != AAUDIO_UNSPECIFIED){
214 printf("WARNING: setUsage not supported");
215 }
216 if (s_setContentType != nullptr) {
217 s_setContentType(builder, mContentType);
218 } else if (mUsage != AAUDIO_UNSPECIFIED){
219 printf("WARNING: setContentType not supported");
220 }
221 if (s_setInputPreset != nullptr) {
222 s_setInputPreset(builder, mInputPreset);
223 } else if (mUsage != AAUDIO_UNSPECIFIED){
224 printf("WARNING: setInputPreset not supported");
225 }
Phil Burk44795232017-06-30 16:27:38 -0700226 }
227
Phil Burkbad0f572019-03-29 11:03:13 -0700228 static constexpr int32_t kDefaultNumberOfBursts = 2;
229
Phil Burk44795232017-06-30 16:27:38 -0700230private:
231 int32_t mChannelCount = AAUDIO_UNSPECIFIED;
232 aaudio_format_t mFormat = AAUDIO_FORMAT_UNSPECIFIED;
233 int32_t mSampleRate = AAUDIO_UNSPECIFIED;
234
235 int32_t mBufferCapacity = AAUDIO_UNSPECIFIED;
236 int32_t mDeviceId = AAUDIO_UNSPECIFIED;
237 aaudio_sharing_mode_t mSharingMode = AAUDIO_SHARING_MODE_SHARED;
238 aaudio_performance_mode_t mPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
239
Phil Burk6d6f3f62018-01-12 17:27:54 -0800240 aaudio_usage_t mUsage = AAUDIO_UNSPECIFIED;
241 aaudio_content_type_t mContentType = AAUDIO_UNSPECIFIED;
242 aaudio_input_preset_t mInputPreset = AAUDIO_UNSPECIFIED;
243
Phil Burkbad0f572019-03-29 11:03:13 -0700244 int32_t mNumberOfBursts = kDefaultNumberOfBursts;
Phil Burk10ffb192018-09-26 12:09:00 -0700245 int32_t mFramesPerCallback = AAUDIO_UNSPECIFIED;
Phil Burk44795232017-06-30 16:27:38 -0700246};
247
248class AAudioArgsParser : public AAudioParameters {
249public:
250 AAudioArgsParser() = default;
251 ~AAudioArgsParser() = default;
252
253 enum {
254 DEFAULT_DURATION_SECONDS = 5
255 };
256
257 /**
258 * @param arg
259 * @return true if the argument was not handled
260 */
261 bool parseArg(const char *arg) {
262 bool unrecognized = false;
263 if (arg[0] == '-') {
264 char option = arg[1];
265 switch (option) {
266 case 'b':
267 setBufferCapacity(atoi(&arg[2]));
268 break;
269 case 'c':
270 setChannelCount(atoi(&arg[2]));
271 break;
272 case 'd':
Phil Burke008d022017-08-23 12:56:15 -0700273 setDeviceId(atoi(&arg[2]));
274 break;
Phil Burkdd574ca2018-04-04 14:41:28 -0700275 case 'f':
276 setFormat(atoi(&arg[2]));
277 break;
Phil Burk6d6f3f62018-01-12 17:27:54 -0800278 case 'i':
279 setInputPreset(atoi(&arg[2]));
Phil Burk44795232017-06-30 16:27:38 -0700280 break;
Phil Burkfcf9efd2017-07-14 08:25:08 -0700281 case 'm': {
282 aaudio_policy_t policy = AAUDIO_POLICY_AUTO;
283 if (strlen(arg) > 2) {
284 policy = atoi(&arg[2]);
285 }
Phil Burke0a4d2a2018-11-05 11:40:36 -0800286 if (AAudio_setMMapPolicy(policy) != AAUDIO_OK) {
Kevin Rocard9dcd34f2018-06-13 16:19:36 -0700287 printf("ERROR: invalid MMAP policy mode %i\n", policy);
288 }
Phil Burkfcf9efd2017-07-14 08:25:08 -0700289 } break;
Phil Burk44795232017-06-30 16:27:38 -0700290 case 'n':
291 setNumberOfBursts(atoi(&arg[2]));
292 break;
293 case 'p':
294 setPerformanceMode(parsePerformanceMode(arg[2]));
295 break;
296 case 'r':
297 setSampleRate(atoi(&arg[2]));
298 break;
Phil Burk6d6f3f62018-01-12 17:27:54 -0800299 case 's':
300 mDurationSeconds = atoi(&arg[2]);
301 break;
302 case 'u':
303 setUsage(atoi(&arg[2]));
304 break;
Phil Burk44795232017-06-30 16:27:38 -0700305 case 'x':
306 setSharingMode(AAUDIO_SHARING_MODE_EXCLUSIVE);
307 break;
Phil Burk6d6f3f62018-01-12 17:27:54 -0800308 case 'y':
309 setContentType(atoi(&arg[2]));
310 break;
Phil Burk10ffb192018-09-26 12:09:00 -0700311 case 'z':
312 setFramesPerCallback(atoi(&arg[2]));
313 break;
Phil Burk44795232017-06-30 16:27:38 -0700314 default:
315 unrecognized = true;
316 break;
317 }
318 }
319 return unrecognized;
320 }
321
322 /**
323 *
324 * @param argc
325 * @param argv
326 * @return true if an unrecognized argument was passed
327 */
328 bool parseArgs(int argc, const char **argv) {
329 for (int i = 1; i < argc; i++) {
330 const char *arg = argv[i];
331 if (parseArg(arg)) {
332 usage();
333 return true;
334 }
335
336 }
337 return false;
338 }
339
340 static void usage() {
Phil Burk6d6f3f62018-01-12 17:27:54 -0800341 printf("-c{channels} -d{deviceId} -m{mmapPolicy} -n{burstsPerBuffer} -p{perfMode}");
342 printf(" -r{rate} -s{seconds} -x\n");
Phil Burk44795232017-06-30 16:27:38 -0700343 printf(" Default values are UNSPECIFIED unless otherwise stated.\n");
344 printf(" -b{bufferCapacity} frames\n");
345 printf(" -c{channels} for example 2 for stereo\n");
Phil Burke008d022017-08-23 12:56:15 -0700346 printf(" -d{deviceId} default is %d\n", AAUDIO_UNSPECIFIED);
Phil Burkdd574ca2018-04-04 14:41:28 -0700347 printf(" -f{0|1|2} set format\n");
348 printf(" 0 = UNSPECIFIED\n");
349 printf(" 1 = PCM_I16\n");
350 printf(" 2 = FLOAT\n");
Phil Burk6d6f3f62018-01-12 17:27:54 -0800351 printf(" -i{inputPreset} eg. 5 for AAUDIO_INPUT_PRESET_CAMCORDER\n");
Phil Burkfcf9efd2017-07-14 08:25:08 -0700352 printf(" -m{0|1|2|3} set MMAP policy\n");
Phil Burk6d6f3f62018-01-12 17:27:54 -0800353 printf(" 0 = _UNSPECIFIED, use aaudio.mmap_policy system property, default\n");
354 printf(" 1 = _NEVER, never use MMAP\n");
355 printf(" 2 = _AUTO, use MMAP if available, default for -m with no number\n");
356 printf(" 3 = _ALWAYS, use MMAP or fail\n");
Phil Burkbad0f572019-03-29 11:03:13 -0700357 printf(" -n{numberOfBursts} for setBufferSize, default %d\n", kDefaultNumberOfBursts);
Phil Burk44795232017-06-30 16:27:38 -0700358 printf(" -p{performanceMode} set output AAUDIO_PERFORMANCE_MODE*, default NONE\n");
359 printf(" n for _NONE\n");
360 printf(" l for _LATENCY\n");
361 printf(" p for _POWER_SAVING;\n");
362 printf(" -r{sampleRate} for example 44100\n");
Phil Burk6d6f3f62018-01-12 17:27:54 -0800363 printf(" -s{duration} in seconds, default is %d\n", DEFAULT_DURATION_SECONDS);
364 printf(" -u{usage} eg. 14 for AAUDIO_USAGE_GAME\n");
Phil Burk44795232017-06-30 16:27:38 -0700365 printf(" -x to use EXCLUSIVE mode\n");
Phil Burk6d6f3f62018-01-12 17:27:54 -0800366 printf(" -y{contentType} eg. 1 for AAUDIO_CONTENT_TYPE_SPEECH\n");
Phil Burk10ffb192018-09-26 12:09:00 -0700367 printf(" -z{callbackSize} or block size, in frames, default = 0\n");
Phil Burk44795232017-06-30 16:27:38 -0700368 }
369
370 static aaudio_performance_mode_t parsePerformanceMode(char c) {
371 aaudio_performance_mode_t mode = AAUDIO_PERFORMANCE_MODE_NONE;
372 switch (c) {
373 case 'n':
374 mode = AAUDIO_PERFORMANCE_MODE_NONE;
375 break;
376 case 'l':
377 mode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
378 break;
379 case 'p':
380 mode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING;
381 break;
382 default:
Kevin Rocard9dcd34f2018-06-13 16:19:36 -0700383 printf("ERROR: invalid performance mode %c\n", c);
Phil Burk44795232017-06-30 16:27:38 -0700384 break;
385 }
386 return mode;
387 }
388
389 /**
390 * Print stream parameters in comparison with requested values.
391 * @param stream
392 */
Phil Burka5222e22017-07-28 13:31:14 -0700393 void compareWithStream(AAudioStream *stream) const {
Phil Burk44795232017-06-30 16:27:38 -0700394
395 printf(" DeviceId: requested = %d, actual = %d\n",
396 getDeviceId(), AAudioStream_getDeviceId(stream));
397
398 aaudio_stream_state_t state = AAudioStream_getState(stream);
399 printf(" State: %s\n", AAudio_convertStreamStateToText(state));
400
401 // Check to see what kind of stream we actually got.
402 printf(" SampleRate: requested = %d, actual = %d\n",
403 getSampleRate(), AAudioStream_getSampleRate(stream));
404
405 printf(" ChannelCount: requested = %d, actual = %d\n",
406 getChannelCount(), AAudioStream_getChannelCount(stream));
407
408 printf(" DataFormat: requested = %d, actual = %d\n",
409 getFormat(), AAudioStream_getFormat(stream));
410
411 int32_t framesPerBurst = AAudioStream_getFramesPerBurst(stream);
Phil Burk44795232017-06-30 16:27:38 -0700412 printf(" Buffer: burst = %d\n", framesPerBurst);
Phil Burkbad0f572019-03-29 11:03:13 -0700413
414 int32_t sizeFrames = AAudioStream_getBufferSizeInFrames(stream);
Phil Burk44795232017-06-30 16:27:38 -0700415 if (framesPerBurst > 0) {
Phil Burkbad0f572019-03-29 11:03:13 -0700416 int32_t requestedSize = getNumberOfBursts() * framesPerBurst;
417 printf(" BufferSize: requested = %4d, actual = %4d = (%d * %d) + %d\n",
418 requestedSize,
Phil Burk44795232017-06-30 16:27:38 -0700419 sizeFrames,
420 (sizeFrames / framesPerBurst),
421 framesPerBurst,
422 (sizeFrames % framesPerBurst));
Phil Burkbad0f572019-03-29 11:03:13 -0700423 } else {
424 printf(" BufferSize: %d\n", sizeFrames);
Phil Burk44795232017-06-30 16:27:38 -0700425 }
Phil Burkbad0f572019-03-29 11:03:13 -0700426
427 int32_t capacityFrames = AAudioStream_getBufferCapacityInFrames(stream);
428 printf(" Capacity: requested = %4d, actual = %4d = (%d * %d) + %d\n",
429 getBufferCapacity(),
430 capacityFrames,
431 (capacityFrames / framesPerBurst),
432 framesPerBurst,
433 (capacityFrames % framesPerBurst));
Phil Burk44795232017-06-30 16:27:38 -0700434
Phil Burk10ffb192018-09-26 12:09:00 -0700435 printf(" CallbackSize: requested = %d, actual = %d\n", getFramesPerCallback(),
436 AAudioStream_getFramesPerDataCallback(stream));
437
Phil Burk44795232017-06-30 16:27:38 -0700438 printf(" SharingMode: requested = %s, actual = %s\n",
439 getSharingModeText(getSharingMode()),
440 getSharingModeText(AAudioStream_getSharingMode(stream)));
441
442 printf(" PerformanceMode: requested = %d, actual = %d\n",
443 getPerformanceMode(), AAudioStream_getPerformanceMode(stream));
Phil Burk6d6f3f62018-01-12 17:27:54 -0800444
Phil Burk4e98efa2018-02-05 18:41:55 -0800445 loadFutureFunctions();
Phil Burk6d6f3f62018-01-12 17:27:54 -0800446
Phil Burk4e98efa2018-02-05 18:41:55 -0800447 if (s_setUsage != nullptr) {
448 printf(" Usage: requested = %d, actual = %d\n",
449 getUsage(), s_getUsage(stream));
450 }
451 if (s_getContentType != nullptr) {
452 printf(" ContentType: requested = %d, actual = %d\n",
453 getContentType(), s_getContentType(stream));
454 }
455
456 if (AAudioStream_getDirection(stream) == AAUDIO_DIRECTION_INPUT
457 && s_getInputPreset != nullptr) {
458 printf(" InputPreset: requested = %d, actual = %d\n",
459 getInputPreset(), s_getInputPreset(stream));
Phil Burk6d6f3f62018-01-12 17:27:54 -0800460 }
461
Phil Burk44795232017-06-30 16:27:38 -0700462 printf(" Is MMAP used? %s\n", AAudioStream_isMMapUsed(stream)
463 ? "yes" : "no");
464
465 }
466
467 int32_t getDurationSeconds() const {
468 return mDurationSeconds;
469 }
470
471 void setDurationSeconds(int32_t seconds) {
472 mDurationSeconds = seconds;
473 }
474
475private:
476 int32_t mDurationSeconds = DEFAULT_DURATION_SECONDS;
477};
478
479#endif // AAUDIO_EXAMPLE_ARGS_PARSER_H