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 #ifndef AAUDIO_EXAMPLE_ARGS_PARSER_H
18 #define AAUDIO_EXAMPLE_ARGS_PARSER_H
19
20 #define MAX_CHANNELS 8
21
22 //#include <cctype>
23 #include <dlfcn.h>
24 #include <unistd.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27
28 #include <aaudio/AAudio.h>
29 #include <aaudio/AAudioTesting.h>
30
31 #include "AAudioExampleUtils.h"
32
33
34 static void (*s_setUsage)(AAudioStreamBuilder* builder, aaudio_usage_t usage) = nullptr;
35 static void (*s_setContentType)(AAudioStreamBuilder* builder,
36 aaudio_content_type_t contentType) = nullptr;
37 static void (*s_setInputPreset)(AAudioStreamBuilder* builder,
38 aaudio_input_preset_t inputPreset) = nullptr;
39
40 static bool s_loadAttempted = false;
41 static aaudio_usage_t (*s_getUsage)(AAudioStream *stream) = nullptr;
42 static aaudio_content_type_t (*s_getContentType)(AAudioStream *stream) = nullptr;
43 static aaudio_input_preset_t (*s_getInputPreset)(AAudioStream *stream) = nullptr;
44
45 // Link to test functions in shared library.
loadFutureFunctions()46 static 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
78 error:
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
90 class AAudioParameters {
91 public:
92
93 /**
94 * This is also known as samplesPerFrame.
95 */
getChannelCount()96 int32_t getChannelCount() const {
97 return mChannelCount;
98 }
99
setChannelCount(int32_t channelCount)100 void setChannelCount(int32_t channelCount) {
101 if (channelCount > MAX_CHANNELS) {
102 printf("Sorry, MAX of %d channels!\n", MAX_CHANNELS);
103 channelCount = MAX_CHANNELS;
104 }
105 mChannelCount = channelCount;
106 }
107
getSampleRate()108 int32_t getSampleRate() const {
109 return mSampleRate;
110 }
111
setSampleRate(int32_t sampleRate)112 void setSampleRate(int32_t sampleRate) {
113 mSampleRate = sampleRate;
114 }
115
getFormat()116 aaudio_format_t getFormat() const {
117 return mFormat;
118 }
119
setFormat(aaudio_format_t format)120 void setFormat(aaudio_format_t format) {
121 mFormat = format;
122 }
123
getSharingMode()124 aaudio_sharing_mode_t getSharingMode() const {
125 return mSharingMode;
126 }
127
setSharingMode(aaudio_sharing_mode_t sharingMode)128 void setSharingMode(aaudio_sharing_mode_t sharingMode) {
129 mSharingMode = sharingMode;
130 }
131
getBufferCapacity()132 int32_t getBufferCapacity() const {
133 return mBufferCapacity;
134 }
135
setBufferCapacity(int32_t frames)136 void setBufferCapacity(int32_t frames) {
137 mBufferCapacity = frames;
138 }
139
getPerformanceMode()140 int32_t getPerformanceMode() const {
141 return mPerformanceMode;
142 }
143
setPerformanceMode(aaudio_performance_mode_t performanceMode)144 void setPerformanceMode(aaudio_performance_mode_t performanceMode) {
145 mPerformanceMode = performanceMode;
146 }
147
getUsage()148 aaudio_usage_t getUsage() const {
149 return mUsage;
150 }
151
setUsage(aaudio_usage_t usage)152 void setUsage(aaudio_usage_t usage) {
153 mUsage = usage;
154 }
155
getContentType()156 aaudio_content_type_t getContentType() const {
157 return mContentType;
158 }
159
setContentType(aaudio_content_type_t contentType)160 void setContentType(aaudio_content_type_t contentType) {
161 mContentType = contentType;
162 }
163
getInputPreset()164 aaudio_input_preset_t getInputPreset() const {
165 return mInputPreset;
166 }
167
setInputPreset(aaudio_input_preset_t inputPreset)168 void setInputPreset(aaudio_input_preset_t inputPreset) {
169 mInputPreset = inputPreset;
170 }
171
getDeviceId()172 int32_t getDeviceId() const {
173 return mDeviceId;
174 }
175
setDeviceId(int32_t deviceId)176 void setDeviceId(int32_t deviceId) {
177 mDeviceId = deviceId;
178 }
179
getNumberOfBursts()180 int32_t getNumberOfBursts() const {
181 return mNumberOfBursts;
182 }
183
setNumberOfBursts(int32_t numBursts)184 void setNumberOfBursts(int32_t numBursts) {
185 mNumberOfBursts = numBursts;
186 }
187
188 /**
189 * Apply these parameters to a stream builder.
190 * @param builder
191 */
applyParameters(AAudioStreamBuilder * builder)192 void applyParameters(AAudioStreamBuilder *builder) const {
193 AAudioStreamBuilder_setChannelCount(builder, mChannelCount);
194 AAudioStreamBuilder_setFormat(builder, mFormat);
195 AAudioStreamBuilder_setSampleRate(builder, mSampleRate);
196 AAudioStreamBuilder_setBufferCapacityInFrames(builder, mBufferCapacity);
197 AAudioStreamBuilder_setDeviceId(builder, mDeviceId);
198 AAudioStreamBuilder_setSharingMode(builder, mSharingMode);
199 AAudioStreamBuilder_setPerformanceMode(builder, mPerformanceMode);
200
201 // Call P functions if supported.
202 loadFutureFunctions();
203 if (s_setUsage != nullptr) {
204 s_setUsage(builder, mUsage);
205 } else if (mUsage != AAUDIO_UNSPECIFIED){
206 printf("WARNING: setUsage not supported");
207 }
208 if (s_setContentType != nullptr) {
209 s_setContentType(builder, mContentType);
210 } else if (mUsage != AAUDIO_UNSPECIFIED){
211 printf("WARNING: setContentType not supported");
212 }
213 if (s_setInputPreset != nullptr) {
214 s_setInputPreset(builder, mInputPreset);
215 } else if (mUsage != AAUDIO_UNSPECIFIED){
216 printf("WARNING: setInputPreset not supported");
217 }
218 }
219
220 private:
221 int32_t mChannelCount = AAUDIO_UNSPECIFIED;
222 aaudio_format_t mFormat = AAUDIO_FORMAT_UNSPECIFIED;
223 int32_t mSampleRate = AAUDIO_UNSPECIFIED;
224
225 int32_t mBufferCapacity = AAUDIO_UNSPECIFIED;
226 int32_t mDeviceId = AAUDIO_UNSPECIFIED;
227 aaudio_sharing_mode_t mSharingMode = AAUDIO_SHARING_MODE_SHARED;
228 aaudio_performance_mode_t mPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
229
230 aaudio_usage_t mUsage = AAUDIO_UNSPECIFIED;
231 aaudio_content_type_t mContentType = AAUDIO_UNSPECIFIED;
232 aaudio_input_preset_t mInputPreset = AAUDIO_UNSPECIFIED;
233
234 int32_t mNumberOfBursts = AAUDIO_UNSPECIFIED;
235 };
236
237 class AAudioArgsParser : public AAudioParameters {
238 public:
239 AAudioArgsParser() = default;
240 ~AAudioArgsParser() = default;
241
242 enum {
243 DEFAULT_DURATION_SECONDS = 5
244 };
245
246 /**
247 * @param arg
248 * @return true if the argument was not handled
249 */
parseArg(const char * arg)250 bool parseArg(const char *arg) {
251 bool unrecognized = false;
252 if (arg[0] == '-') {
253 char option = arg[1];
254 switch (option) {
255 case 'b':
256 setBufferCapacity(atoi(&arg[2]));
257 break;
258 case 'c':
259 setChannelCount(atoi(&arg[2]));
260 break;
261 case 'd':
262 setDeviceId(atoi(&arg[2]));
263 break;
264 case 'f':
265 setFormat(atoi(&arg[2]));
266 break;
267 case 'i':
268 setInputPreset(atoi(&arg[2]));
269 break;
270 case 'm': {
271 aaudio_policy_t policy = AAUDIO_POLICY_AUTO;
272 if (strlen(arg) > 2) {
273 policy = atoi(&arg[2]);
274 }
275 AAudio_setMMapPolicy(policy);
276 } break;
277 case 'n':
278 setNumberOfBursts(atoi(&arg[2]));
279 break;
280 case 'p':
281 setPerformanceMode(parsePerformanceMode(arg[2]));
282 break;
283 case 'r':
284 setSampleRate(atoi(&arg[2]));
285 break;
286 case 's':
287 mDurationSeconds = atoi(&arg[2]);
288 break;
289 case 'u':
290 setUsage(atoi(&arg[2]));
291 break;
292 case 'x':
293 setSharingMode(AAUDIO_SHARING_MODE_EXCLUSIVE);
294 break;
295 case 'y':
296 setContentType(atoi(&arg[2]));
297 break;
298 default:
299 unrecognized = true;
300 break;
301 }
302 }
303 return unrecognized;
304 }
305
306 /**
307 *
308 * @param argc
309 * @param argv
310 * @return true if an unrecognized argument was passed
311 */
parseArgs(int argc,const char ** argv)312 bool parseArgs(int argc, const char **argv) {
313 for (int i = 1; i < argc; i++) {
314 const char *arg = argv[i];
315 if (parseArg(arg)) {
316 usage();
317 return true;
318 }
319
320 }
321 return false;
322 }
323
usage()324 static void usage() {
325 printf("-c{channels} -d{deviceId} -m{mmapPolicy} -n{burstsPerBuffer} -p{perfMode}");
326 printf(" -r{rate} -s{seconds} -x\n");
327 printf(" Default values are UNSPECIFIED unless otherwise stated.\n");
328 printf(" -b{bufferCapacity} frames\n");
329 printf(" -c{channels} for example 2 for stereo\n");
330 printf(" -d{deviceId} default is %d\n", AAUDIO_UNSPECIFIED);
331 printf(" -f{0|1|2} set format\n");
332 printf(" 0 = UNSPECIFIED\n");
333 printf(" 1 = PCM_I16\n");
334 printf(" 2 = FLOAT\n");
335 printf(" -i{inputPreset} eg. 5 for AAUDIO_INPUT_PRESET_CAMCORDER\n");
336 printf(" -m{0|1|2|3} set MMAP policy\n");
337 printf(" 0 = _UNSPECIFIED, use aaudio.mmap_policy system property, default\n");
338 printf(" 1 = _NEVER, never use MMAP\n");
339 printf(" 2 = _AUTO, use MMAP if available, default for -m with no number\n");
340 printf(" 3 = _ALWAYS, use MMAP or fail\n");
341 printf(" -n{numberOfBursts} for setBufferSize\n");
342 printf(" -p{performanceMode} set output AAUDIO_PERFORMANCE_MODE*, default NONE\n");
343 printf(" n for _NONE\n");
344 printf(" l for _LATENCY\n");
345 printf(" p for _POWER_SAVING;\n");
346 printf(" -r{sampleRate} for example 44100\n");
347 printf(" -s{duration} in seconds, default is %d\n", DEFAULT_DURATION_SECONDS);
348 printf(" -u{usage} eg. 14 for AAUDIO_USAGE_GAME\n");
349 printf(" -x to use EXCLUSIVE mode\n");
350 printf(" -y{contentType} eg. 1 for AAUDIO_CONTENT_TYPE_SPEECH\n");
351 }
352
parsePerformanceMode(char c)353 static aaudio_performance_mode_t parsePerformanceMode(char c) {
354 aaudio_performance_mode_t mode = AAUDIO_PERFORMANCE_MODE_NONE;
355 switch (c) {
356 case 'n':
357 mode = AAUDIO_PERFORMANCE_MODE_NONE;
358 break;
359 case 'l':
360 mode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
361 break;
362 case 'p':
363 mode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING;
364 break;
365 default:
366 printf("ERROR invalid performance mode %c\n", c);
367 break;
368 }
369 return mode;
370 }
371
372 /**
373 * Print stream parameters in comparison with requested values.
374 * @param stream
375 */
compareWithStream(AAudioStream * stream)376 void compareWithStream(AAudioStream *stream) const {
377
378 printf(" DeviceId: requested = %d, actual = %d\n",
379 getDeviceId(), AAudioStream_getDeviceId(stream));
380
381 aaudio_stream_state_t state = AAudioStream_getState(stream);
382 printf(" State: %s\n", AAudio_convertStreamStateToText(state));
383
384 // Check to see what kind of stream we actually got.
385 printf(" SampleRate: requested = %d, actual = %d\n",
386 getSampleRate(), AAudioStream_getSampleRate(stream));
387
388 printf(" ChannelCount: requested = %d, actual = %d\n",
389 getChannelCount(), AAudioStream_getChannelCount(stream));
390
391 printf(" DataFormat: requested = %d, actual = %d\n",
392 getFormat(), AAudioStream_getFormat(stream));
393
394 int32_t framesPerBurst = AAudioStream_getFramesPerBurst(stream);
395 int32_t sizeFrames = AAudioStream_getBufferSizeInFrames(stream);
396 printf(" Buffer: burst = %d\n", framesPerBurst);
397 if (framesPerBurst > 0) {
398 printf(" Buffer: size = %d = (%d * %d) + %d\n",
399 sizeFrames,
400 (sizeFrames / framesPerBurst),
401 framesPerBurst,
402 (sizeFrames % framesPerBurst));
403 }
404 printf(" Capacity: requested = %d, actual = %d\n", getBufferCapacity(),
405 AAudioStream_getBufferCapacityInFrames(stream));
406
407 printf(" SharingMode: requested = %s, actual = %s\n",
408 getSharingModeText(getSharingMode()),
409 getSharingModeText(AAudioStream_getSharingMode(stream)));
410
411 printf(" PerformanceMode: requested = %d, actual = %d\n",
412 getPerformanceMode(), AAudioStream_getPerformanceMode(stream));
413
414 loadFutureFunctions();
415
416 if (s_setUsage != nullptr) {
417 printf(" Usage: requested = %d, actual = %d\n",
418 getUsage(), s_getUsage(stream));
419 }
420 if (s_getContentType != nullptr) {
421 printf(" ContentType: requested = %d, actual = %d\n",
422 getContentType(), s_getContentType(stream));
423 }
424
425 if (AAudioStream_getDirection(stream) == AAUDIO_DIRECTION_INPUT
426 && s_getInputPreset != nullptr) {
427 printf(" InputPreset: requested = %d, actual = %d\n",
428 getInputPreset(), s_getInputPreset(stream));
429 }
430
431 printf(" Is MMAP used? %s\n", AAudioStream_isMMapUsed(stream)
432 ? "yes" : "no");
433
434 }
435
getDurationSeconds()436 int32_t getDurationSeconds() const {
437 return mDurationSeconds;
438 }
439
setDurationSeconds(int32_t seconds)440 void setDurationSeconds(int32_t seconds) {
441 mDurationSeconds = seconds;
442 }
443
444 private:
445 int32_t mDurationSeconds = DEFAULT_DURATION_SECONDS;
446 };
447
448 #endif // AAUDIO_EXAMPLE_ARGS_PARSER_H
449