Home | History | Annotate | Download | only in utils
      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.
     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      */
    107     int32_t getChannelCount() const {
    108         return mChannelCount;
    109     }
    110 
    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 
    119     int32_t getSampleRate() const {
    120         return mSampleRate;
    121     }
    122 
    123     void setSampleRate(int32_t sampleRate) {
    124         mSampleRate = sampleRate;
    125     }
    126 
    127     aaudio_format_t getFormat() const {
    128         return mFormat;
    129     }
    130 
    131     void setFormat(aaudio_format_t format) {
    132         mFormat = format;
    133     }
    134 
    135     aaudio_sharing_mode_t getSharingMode() const {
    136         return mSharingMode;
    137     }
    138 
    139     void setSharingMode(aaudio_sharing_mode_t sharingMode) {
    140         mSharingMode = sharingMode;
    141     }
    142 
    143     int32_t getBufferCapacity() const {
    144         return mBufferCapacity;
    145     }
    146 
    147     void setBufferCapacity(int32_t frames) {
    148         mBufferCapacity = frames;
    149     }
    150 
    151     int32_t getPerformanceMode() const {
    152         return mPerformanceMode;
    153     }
    154 
    155     void setPerformanceMode(aaudio_performance_mode_t performanceMode) {
    156         mPerformanceMode = performanceMode;
    157     }
    158 
    159     aaudio_usage_t getUsage() const {
    160         return mUsage;
    161     }
    162 
    163     void setUsage(aaudio_usage_t usage) {
    164         mUsage = usage;
    165     }
    166 
    167     aaudio_content_type_t getContentType() const {
    168         return mContentType;
    169     }
    170 
    171     void setContentType(aaudio_content_type_t contentType) {
    172         mContentType = contentType;
    173     }
    174 
    175     aaudio_input_preset_t getInputPreset() const {
    176         return mInputPreset;
    177     }
    178 
    179     void setInputPreset(aaudio_input_preset_t inputPreset) {
    180         mInputPreset = inputPreset;
    181     }
    182 
    183     aaudio_allowed_capture_policy_t getAllowedCapturePolicy() const {
    184         return mAllowedCapturePolicy;
    185     }
    186 
    187     void setAllowedCapturePolicy(aaudio_allowed_capture_policy_t policy) {
    188         mAllowedCapturePolicy = policy;
    189     }
    190 
    191     int32_t getDeviceId() const {
    192         return mDeviceId;
    193     }
    194 
    195     void setDeviceId(int32_t deviceId) {
    196         mDeviceId = deviceId;
    197     }
    198 
    199     int32_t getNumberOfBursts() const {
    200         return mNumberOfBursts;
    201     }
    202 
    203     void setNumberOfBursts(int32_t numBursts) {
    204         mNumberOfBursts = numBursts;
    205     }
    206 
    207     int32_t getFramesPerCallback() const {
    208         return mFramesPerCallback;
    209     }
    210     void setFramesPerCallback(int32_t size) {
    211         mFramesPerCallback = size;
    212     }
    213 
    214     /**
    215      * Apply these parameters to a stream builder.
    216      * @param builder
    217      */
    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      */
    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      */
    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 
    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 
    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 
    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      */
    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 
    525     int32_t getDurationSeconds() const {
    526         return mDurationSeconds;
    527     }
    528 
    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