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