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. 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 */ 96 int32_t getChannelCount() const { 97 return mChannelCount; 98 } 99 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 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 148 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 172 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 188 /** 189 * Apply these parameters to a stream builder. 190 * @param builder 191 */ 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 */ 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 */ 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 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 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 */ 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 436 int32_t getDurationSeconds() const { 437 return mDurationSeconds; 438 } 439 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