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 static void (*s_setAllowedCapturePolicy)(AAudioStreamBuilder* builder,
40                                           aaudio_allowed_capture_policy_t usage) = nullptr;
41 static void (*s_setPrivacySensitive)(AAudioStreamBuilder* builder,
42                                           bool privacySensitive) = nullptr;
43 
44 static bool s_loadAttempted = false;
45 static aaudio_usage_t (*s_getUsage)(AAudioStream *stream) = nullptr;
46 static aaudio_content_type_t (*s_getContentType)(AAudioStream *stream) = nullptr;
47 static aaudio_input_preset_t (*s_getInputPreset)(AAudioStream *stream) = nullptr;
48 static aaudio_allowed_capture_policy_t (*s_getAllowedCapturePolicy)(AAudioStream *stream) = nullptr;
49 static bool (*s_isPrivacySensitive)(AAudioStream *stream) = nullptr;
50 
51 // Link to test functions in shared library.
loadFutureFunctions()52 static void loadFutureFunctions() {
53     if (s_loadAttempted)  return; // only try once
54     s_loadAttempted = true;
55 
56     void *handle = dlopen("libaaudio.so", RTLD_NOW);
57     if (handle != nullptr) {
58         s_setUsage = (void (*)(AAudioStreamBuilder *, aaudio_usage_t))
59                 dlsym(handle, "AAudioStreamBuilder_setUsage");
60         if (s_setUsage == nullptr) goto error;
61 
62         s_setContentType = (void (*)(AAudioStreamBuilder *, aaudio_content_type_t))
63                 dlsym(handle, "AAudioStreamBuilder_setContentType");
64         if (s_setContentType == nullptr) goto error;
65 
66         s_setInputPreset = (void (*)(AAudioStreamBuilder *, aaudio_input_preset_t))
67                 dlsym(handle, "AAudioStreamBuilder_setInputPreset");
68         if (s_setInputPreset == nullptr) goto error;
69 
70         s_setAllowedCapturePolicy = (void (*)(AAudioStreamBuilder *, aaudio_input_preset_t))
71                 dlsym(handle, "AAudioStreamBuilder_setAllowedCapturePolicy");
72         if (s_setAllowedCapturePolicy == nullptr) goto error;
73 
74         s_setPrivacySensitive = (void (*)(AAudioStreamBuilder *, bool))
75                 dlsym(handle, "AAudioStreamBuilder_setPrivacySensitive");
76         if (s_setPrivacySensitive == nullptr) goto error;
77 
78         s_getUsage = (aaudio_usage_t (*)(AAudioStream *))
79                 dlsym(handle, "AAudioStream_getUsage");
80         if (s_getUsage == nullptr) goto error;
81 
82         s_getContentType = (aaudio_content_type_t (*)(AAudioStream *))
83                 dlsym(handle, "AAudioStream_getContentType");
84         if (s_getContentType == nullptr) goto error;
85 
86         s_getInputPreset = (aaudio_input_preset_t (*)(AAudioStream *))
87                 dlsym(handle, "AAudioStream_getInputPreset");
88         if (s_getInputPreset == nullptr) goto error;
89 
90         s_getAllowedCapturePolicy = (aaudio_input_preset_t (*)(AAudioStream *))
91                 dlsym(handle, "AAudioStream_getAllowedCapturePolicy");
92         if (s_getAllowedCapturePolicy == nullptr) goto error;
93 
94         s_isPrivacySensitive = (bool (*)(AAudioStream *))
95                 dlsym(handle, "AAudioStream_isPrivacySensitive");
96         if (s_isPrivacySensitive == nullptr) goto error;
97     }
98     return;
99 
100 error:
101     // prevent any calls to these functions
102     s_setUsage = nullptr;
103     s_setContentType = nullptr;
104     s_setInputPreset = nullptr;
105     s_setPrivacySensitive = nullptr;
106     s_getUsage = nullptr;
107     s_getContentType = nullptr;
108     s_getInputPreset = nullptr;
109     s_isPrivacySensitive = nullptr;
110     dlclose(handle);
111     return;
112 }
113 
114 class AAudioParameters {
115 public:
116 
117     /**
118      * This is also known as samplesPerFrame.
119      */
getChannelCount()120     int32_t getChannelCount() const {
121         return mChannelCount;
122     }
123 
setChannelCount(int32_t channelCount)124     void setChannelCount(int32_t channelCount) {
125         if (channelCount > MAX_CHANNELS) {
126             printf("Sorry, MAX of %d channels!\n", MAX_CHANNELS);
127             channelCount = MAX_CHANNELS;
128         }
129         mChannelCount = channelCount;
130     }
131 
getSampleRate()132     int32_t getSampleRate() const {
133         return mSampleRate;
134     }
135 
setSampleRate(int32_t sampleRate)136     void setSampleRate(int32_t sampleRate) {
137         mSampleRate = sampleRate;
138     }
139 
getFormat()140     aaudio_format_t getFormat() const {
141         return mFormat;
142     }
143 
setFormat(aaudio_format_t format)144     void setFormat(aaudio_format_t format) {
145         mFormat = format;
146     }
147 
getSharingMode()148     aaudio_sharing_mode_t getSharingMode() const {
149         return mSharingMode;
150     }
151 
setSharingMode(aaudio_sharing_mode_t sharingMode)152     void setSharingMode(aaudio_sharing_mode_t sharingMode) {
153         mSharingMode = sharingMode;
154     }
155 
getBufferCapacity()156     int32_t getBufferCapacity() const {
157         return mBufferCapacity;
158     }
159 
setBufferCapacity(int32_t frames)160     void setBufferCapacity(int32_t frames) {
161         mBufferCapacity = frames;
162     }
163 
getPerformanceMode()164     int32_t getPerformanceMode() const {
165         return mPerformanceMode;
166     }
167 
setPerformanceMode(aaudio_performance_mode_t performanceMode)168     void setPerformanceMode(aaudio_performance_mode_t performanceMode) {
169         mPerformanceMode = performanceMode;
170     }
171 
getUsage()172     aaudio_usage_t getUsage() const {
173         return mUsage;
174     }
175 
setUsage(aaudio_usage_t usage)176     void setUsage(aaudio_usage_t usage) {
177         mUsage = usage;
178     }
179 
getContentType()180     aaudio_content_type_t getContentType() const {
181         return mContentType;
182     }
183 
setContentType(aaudio_content_type_t contentType)184     void setContentType(aaudio_content_type_t contentType) {
185         mContentType = contentType;
186     }
187 
getInputPreset()188     aaudio_input_preset_t getInputPreset() const {
189         return mInputPreset;
190     }
191 
setInputPreset(aaudio_input_preset_t inputPreset)192     void setInputPreset(aaudio_input_preset_t inputPreset) {
193         mInputPreset = inputPreset;
194     }
195 
getAllowedCapturePolicy()196     aaudio_allowed_capture_policy_t getAllowedCapturePolicy() const {
197         return mAllowedCapturePolicy;
198     }
199 
setAllowedCapturePolicy(aaudio_allowed_capture_policy_t policy)200     void setAllowedCapturePolicy(aaudio_allowed_capture_policy_t policy) {
201         mAllowedCapturePolicy = policy;
202     }
203 
getDeviceId()204     int32_t getDeviceId() const {
205         return mDeviceId;
206     }
207 
setDeviceId(int32_t deviceId)208     void setDeviceId(int32_t deviceId) {
209         mDeviceId = deviceId;
210     }
211 
getNumberOfBursts()212     int32_t getNumberOfBursts() const {
213         return mNumberOfBursts;
214     }
215 
setNumberOfBursts(int32_t numBursts)216     void setNumberOfBursts(int32_t numBursts) {
217         mNumberOfBursts = numBursts;
218     }
219 
getFramesPerCallback()220     int32_t getFramesPerCallback() const {
221         return mFramesPerCallback;
222     }
setFramesPerCallback(int32_t size)223     void setFramesPerCallback(int32_t size) {
224         mFramesPerCallback = size;
225     }
226 
isPrivacySensitive()227     int32_t isPrivacySensitive() const {
228         return mPrivacySensitive;
229     }
230 
setPrivacySensitive(int32_t privacySensitive)231     void setPrivacySensitive(int32_t privacySensitive) {
232         mPrivacySensitive = privacySensitive;
233     }
234 
235     /**
236      * Apply these parameters to a stream builder.
237      * @param builder
238      */
applyParameters(AAudioStreamBuilder * builder)239     void applyParameters(AAudioStreamBuilder *builder) const {
240         AAudioStreamBuilder_setBufferCapacityInFrames(builder, getBufferCapacity());
241         AAudioStreamBuilder_setChannelCount(builder, mChannelCount);
242         AAudioStreamBuilder_setDeviceId(builder, mDeviceId);
243         AAudioStreamBuilder_setFormat(builder, mFormat);
244         AAudioStreamBuilder_setFramesPerDataCallback(builder, mFramesPerCallback);
245         AAudioStreamBuilder_setPerformanceMode(builder, mPerformanceMode);
246         AAudioStreamBuilder_setSampleRate(builder, mSampleRate);
247         AAudioStreamBuilder_setSharingMode(builder, mSharingMode);
248 
249         // Call P functions if supported.
250         loadFutureFunctions();
251         if (s_setUsage != nullptr) {
252             s_setUsage(builder, mUsage);
253         } else if (mUsage != AAUDIO_UNSPECIFIED){
254             printf("WARNING: setUsage not supported");
255         }
256         if (s_setContentType != nullptr) {
257             s_setContentType(builder, mContentType);
258         } else if (mContentType != AAUDIO_UNSPECIFIED){
259             printf("WARNING: setContentType not supported");
260         }
261         if (s_setInputPreset != nullptr) {
262             s_setInputPreset(builder, mInputPreset);
263         } else if (mInputPreset != AAUDIO_UNSPECIFIED){
264             printf("WARNING: setInputPreset not supported");
265         }
266 
267         // Call Q functions if supported.
268         if (s_setAllowedCapturePolicy != nullptr) {
269             s_setAllowedCapturePolicy(builder, mAllowedCapturePolicy);
270         } else if (mAllowedCapturePolicy != AAUDIO_UNSPECIFIED){
271             printf("WARNING: setAllowedCapturePolicy not supported");
272         }
273 
274         if (mPrivacySensitive != PRIVACY_SENSITIVE_DEFAULT) {
275             if (s_setPrivacySensitive != nullptr) {
276                 s_setPrivacySensitive(builder,
277                     mPrivacySensitive == PRIVACY_SENSITIVE_ENABLED);
278             } else {
279                 printf("WARNING: setPrivacySensitive not supported");
280             }
281         }
282     }
283 
284     static constexpr int32_t   kDefaultNumberOfBursts = 2;
285 
286 private:
287     int32_t                    mChannelCount    = AAUDIO_UNSPECIFIED;
288     aaudio_format_t            mFormat          = AAUDIO_FORMAT_UNSPECIFIED;
289     int32_t                    mSampleRate      = AAUDIO_UNSPECIFIED;
290 
291     int32_t                    mBufferCapacity  = AAUDIO_UNSPECIFIED;
292     int32_t                    mDeviceId        = AAUDIO_UNSPECIFIED;
293     aaudio_sharing_mode_t      mSharingMode     = AAUDIO_SHARING_MODE_SHARED;
294     aaudio_performance_mode_t  mPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
295 
296     aaudio_usage_t             mUsage           = AAUDIO_UNSPECIFIED;
297     aaudio_content_type_t      mContentType     = AAUDIO_UNSPECIFIED;
298     aaudio_input_preset_t      mInputPreset     = AAUDIO_UNSPECIFIED;
299     aaudio_allowed_capture_policy_t mAllowedCapturePolicy     = AAUDIO_UNSPECIFIED;
300 
301     int32_t                    mNumberOfBursts  = kDefaultNumberOfBursts;
302     int32_t                    mFramesPerCallback = AAUDIO_UNSPECIFIED;
303 
304     enum {
305         PRIVACY_SENSITIVE_DEFAULT = -1,
306         PRIVACY_SENSITIVE_DISABLED = 0,
307         PRIVACY_SENSITIVE_ENABLED = 1,
308     };
309     int32_t                    mPrivacySensitive = PRIVACY_SENSITIVE_DEFAULT;
310 };
311 
312 class AAudioArgsParser : public AAudioParameters {
313 public:
314     AAudioArgsParser() = default;
315     ~AAudioArgsParser() = default;
316 
317     enum {
318         DEFAULT_DURATION_SECONDS = 5
319     };
320 
321     /**
322      * @param arg
323      * @return true if the argument was not handled
324      */
parseArg(const char * arg)325     bool parseArg(const char *arg) {
326         bool unrecognized = false;
327         if (arg[0] == '-') {
328             char option = arg[1];
329             switch (option) {
330                 case 'b':
331                     setBufferCapacity(atoi(&arg[2]));
332                     break;
333                 case 'c':
334                     setChannelCount(atoi(&arg[2]));
335                     break;
336                 case 'C':
337                     setAllowedCapturePolicy(parseAllowedCapturePolicy(arg[2]));
338                     break;
339                 case 'd':
340                     setDeviceId(atoi(&arg[2]));
341                     break;
342                 case 'f':
343                     setFormat(atoi(&arg[2]));
344                     break;
345                 case 'i':
346                     setInputPreset(atoi(&arg[2]));
347                     break;
348                 case 'm': {
349                     aaudio_policy_t policy = AAUDIO_POLICY_AUTO;
350                     if (strlen(arg) > 2) {
351                         policy = atoi(&arg[2]);
352                     }
353                     if (AAudio_setMMapPolicy(policy) != AAUDIO_OK) {
354                         printf("ERROR: invalid MMAP policy mode %i\n", policy);
355                     }
356                 } break;
357                 case 'n':
358                     setNumberOfBursts(atoi(&arg[2]));
359                     break;
360                 case 'p':
361                     setPerformanceMode(parsePerformanceMode(arg[2]));
362                     break;
363                 case 'r':
364                     setSampleRate(atoi(&arg[2]));
365                     break;
366                 case 's':
367                     mDurationSeconds = atoi(&arg[2]);
368                     break;
369                 case 'u':
370                     setUsage(atoi(&arg[2]));
371                     break;
372                 case 'x':
373                     setSharingMode(AAUDIO_SHARING_MODE_EXCLUSIVE);
374                     break;
375                 case 'y':
376                     setContentType(atoi(&arg[2]));
377                     break;
378                 case 'z':
379                     setFramesPerCallback(atoi(&arg[2]));
380                     break;
381                 case 'S':
382                     setPrivacySensitive(atoi(&arg[2]));
383                     break;
384                 default:
385                     unrecognized = true;
386                     break;
387             }
388         }
389         return unrecognized;
390     }
391 
392     /**
393      *
394      * @param argc
395      * @param argv
396      * @return true if an unrecognized argument was passed
397      */
parseArgs(int argc,const char ** argv)398     bool parseArgs(int argc, const char **argv) {
399         for (int i = 1; i < argc; i++) {
400             const char *arg = argv[i];
401             if (parseArg(arg)) {
402                 usage();
403                 return true;
404             }
405 
406         }
407         return false;
408     }
409 
usage()410     static void usage() {
411         printf("-c{channels} -d{deviceId} -m{mmapPolicy} -n{burstsPerBuffer} -p{perfMode}");
412         printf(" -r{rate} -s{seconds} -x\n");
413         printf("      Default values are UNSPECIFIED unless otherwise stated.\n");
414         printf("      -b{bufferCapacity} frames\n");
415         printf("      -c{channels} for example 2 for stereo\n");
416         printf("      -C{a|s|n} set playback capture policy\n");
417         printf("          a = _ALL (default)\n");
418         printf("          s = _SYSTEM\n");
419         printf("          n = _NONE\n");
420         printf("      -d{deviceId} default is %d\n", AAUDIO_UNSPECIFIED);
421         printf("      -f{0|1|2} set format\n");
422         printf("          0 = UNSPECIFIED\n");
423         printf("          1 = PCM_I16\n");
424         printf("          2 = FLOAT\n");
425         printf("      -i{inputPreset} eg. 5 for AAUDIO_INPUT_PRESET_CAMCORDER\n");
426         printf("      -m{0|1|2|3} set MMAP policy\n");
427         printf("          0 = _UNSPECIFIED, use aaudio.mmap_policy system property, default\n");
428         printf("          1 = _NEVER, never use MMAP\n");
429         printf("          2 = _AUTO, use MMAP if available, default for -m with no number\n");
430         printf("          3 = _ALWAYS, use MMAP or fail\n");
431         printf("      -n{numberOfBursts} for setBufferSize, default %d\n", kDefaultNumberOfBursts);
432         printf("      -p{performanceMode} set output AAUDIO_PERFORMANCE_MODE*, default NONE\n");
433         printf("          n for _NONE\n");
434         printf("          l for _LATENCY\n");
435         printf("          p for _POWER_SAVING;\n");
436         printf("      -r{sampleRate} for example 44100\n");
437         printf("      -s{duration} in seconds, default is %d\n", DEFAULT_DURATION_SECONDS);
438         printf("      -u{usage} eg. 14 for AAUDIO_USAGE_GAME\n");
439         printf("      -x to use EXCLUSIVE mode\n");
440         printf("      -y{contentType} eg. 1 for AAUDIO_CONTENT_TYPE_SPEECH\n");
441         printf("      -z{callbackSize} or block size, in frames, default = 0\n");
442         printf("      -S{0|1} set privacy Sensitive enabled or disabled\n");
443         printf("          0 = disabled\n");
444         printf("          1 = enabled\n");
445     }
446 
parseAllowedCapturePolicy(char c)447     static aaudio_performance_mode_t parseAllowedCapturePolicy(char c) {
448         aaudio_allowed_capture_policy_t policy = AAUDIO_ALLOW_CAPTURE_BY_ALL;
449         switch (c) {
450             case 'a':
451                 policy = AAUDIO_ALLOW_CAPTURE_BY_ALL;
452                 break;
453             case 's':
454                 policy = AAUDIO_ALLOW_CAPTURE_BY_SYSTEM;
455                 break;
456             case 'n':
457                 policy = AAUDIO_ALLOW_CAPTURE_BY_NONE;
458                 break;
459             default:
460                 printf("ERROR: invalid playback capture policy %c\n", c);
461                 break;
462         }
463         return policy;
464     }
465 
parsePerformanceMode(char c)466     static aaudio_performance_mode_t parsePerformanceMode(char c) {
467         aaudio_performance_mode_t mode = AAUDIO_PERFORMANCE_MODE_NONE;
468         switch (c) {
469             case 'n':
470                 mode = AAUDIO_PERFORMANCE_MODE_NONE;
471                 break;
472             case 'l':
473                 mode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
474                 break;
475             case 'p':
476                 mode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING;
477                 break;
478             default:
479                 printf("ERROR: invalid performance mode %c\n", c);
480                 break;
481         }
482         return mode;
483     }
484 
485     /**
486      * Print stream parameters in comparison with requested values.
487      * @param stream
488      */
compareWithStream(AAudioStream * stream)489     void compareWithStream(AAudioStream *stream) const {
490 
491         printf("  DeviceId:     requested = %d, actual = %d\n",
492                getDeviceId(), AAudioStream_getDeviceId(stream));
493 
494         aaudio_stream_state_t state = AAudioStream_getState(stream);
495         printf("  State:        %s\n", AAudio_convertStreamStateToText(state));
496 
497         // Check to see what kind of stream we actually got.
498         printf("  SampleRate:   requested = %d, actual = %d\n",
499                getSampleRate(), AAudioStream_getSampleRate(stream));
500 
501         printf("  ChannelCount: requested = %d, actual = %d\n",
502                getChannelCount(), AAudioStream_getChannelCount(stream));
503 
504         printf("  DataFormat:   requested = %d, actual = %d\n",
505                getFormat(), AAudioStream_getFormat(stream));
506 
507         int32_t framesPerBurst = AAudioStream_getFramesPerBurst(stream);
508         printf("  Buffer:       burst     = %d\n", framesPerBurst);
509 
510         int32_t sizeFrames = AAudioStream_getBufferSizeInFrames(stream);
511         if (framesPerBurst > 0) {
512             int32_t requestedSize = getNumberOfBursts() * framesPerBurst;
513             printf("  BufferSize:   requested = %4d, actual = %4d = (%d * %d) + %d\n",
514                    requestedSize,
515                    sizeFrames,
516                    (sizeFrames / framesPerBurst),
517                    framesPerBurst,
518                    (sizeFrames % framesPerBurst));
519         } else {
520              printf("  BufferSize:    %d\n", sizeFrames);
521         }
522 
523         int32_t capacityFrames = AAudioStream_getBufferCapacityInFrames(stream);
524         printf("  Capacity:     requested = %4d, actual = %4d = (%d * %d) + %d\n",
525                getBufferCapacity(),
526                capacityFrames,
527                (capacityFrames / framesPerBurst),
528                framesPerBurst,
529                (capacityFrames % framesPerBurst));
530 
531         printf("  CallbackSize: requested = %d, actual = %d\n", getFramesPerCallback(),
532                AAudioStream_getFramesPerDataCallback(stream));
533 
534         printf("  SharingMode:  requested = %s, actual = %s\n",
535                getSharingModeText(getSharingMode()),
536                getSharingModeText(AAudioStream_getSharingMode(stream)));
537 
538         printf("  PerformanceMode: requested = %d, actual = %d\n",
539                getPerformanceMode(), AAudioStream_getPerformanceMode(stream));
540 
541         loadFutureFunctions();
542 
543         if (s_setUsage != nullptr) {
544             printf("  Usage:        requested = %d, actual = %d\n",
545                    getUsage(), s_getUsage(stream));
546         }
547         if (s_getContentType != nullptr) {
548             printf("  ContentType:  requested = %d, actual = %d\n",
549                    getContentType(), s_getContentType(stream));
550         }
551 
552         if (AAudioStream_getDirection(stream) == AAUDIO_DIRECTION_INPUT) {
553             if (s_getInputPreset != nullptr) {
554                 printf("  InputPreset:  requested = %d, actual = %d\n",
555                        getInputPreset(), s_getInputPreset(stream));
556             }
557             if (s_isPrivacySensitive != nullptr) {
558                 printf("  Privacy Sensitive:  requested = %d, actual = %d\n",
559                        isPrivacySensitive(), s_isPrivacySensitive(stream));
560             }
561         }
562 
563         printf("  Is MMAP used? %s\n", AAudioStream_isMMapUsed(stream)
564                ? "yes" : "no");
565 
566         if (s_getAllowedCapturePolicy != nullptr) {
567             printf("  ContentType:  requested = %d, actual = %d\n",
568                    getAllowedCapturePolicy(), s_getAllowedCapturePolicy(stream));
569         }
570 
571     }
572 
getDurationSeconds()573     int32_t getDurationSeconds() const {
574         return mDurationSeconds;
575     }
576 
setDurationSeconds(int32_t seconds)577     void setDurationSeconds(int32_t seconds) {
578         mDurationSeconds = seconds;
579     }
580 
581 private:
582     int32_t      mDurationSeconds = DEFAULT_DURATION_SECONDS;
583 };
584 
585 #endif // AAUDIO_EXAMPLE_ARGS_PARSER_H
586