input_monitor.cpp revision c42d5f9ba80d827e135f21c7ff995bc752f6477c
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// Record input using AAudio and display the peak amplitudes. 18 19#include <new> 20#include <assert.h> 21#include <stdio.h> 22#include <stdlib.h> 23#include <math.h> 24#include <aaudio/AAudio.h> 25 26#define SAMPLE_RATE 48000 27#define NUM_SECONDS 5 28#define NANOS_PER_MICROSECOND ((int64_t)1000) 29#define NANOS_PER_MILLISECOND (NANOS_PER_MICROSECOND * 1000) 30#define NANOS_PER_SECOND (NANOS_PER_MILLISECOND * 1000) 31 32#define MIN_FRAMES_TO_READ 48 /* arbitrary, 1 msec at 48000 Hz */ 33 34static const char *getSharingModeText(aaudio_sharing_mode_t mode) { 35 const char *modeText = "unknown"; 36 switch (mode) { 37 case AAUDIO_SHARING_MODE_EXCLUSIVE: 38 modeText = "EXCLUSIVE"; 39 break; 40 case AAUDIO_SHARING_MODE_SHARED: 41 modeText = "SHARED"; 42 break; 43 default: 44 break; 45 } 46 return modeText; 47} 48 49int main(int argc, char **argv) 50{ 51 (void)argc; // unused 52 53 aaudio_result_t result; 54 55 int actualSamplesPerFrame; 56 int actualSampleRate; 57 const aaudio_audio_format_t requestedDataFormat = AAUDIO_FORMAT_PCM_I16; 58 aaudio_audio_format_t actualDataFormat; 59 60 const int requestedInputChannelCount = 1; // Can affect whether we get a FAST path. 61 62 //aaudio_performance_mode_t requestedPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE; 63 const aaudio_performance_mode_t requestedPerformanceMode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY; 64 //aaudio_performance_mode_t requestedPerformanceMode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING; 65 const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_SHARED; 66 //const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_EXCLUSIVE; 67 aaudio_sharing_mode_t actualSharingMode; 68 69 AAudioStreamBuilder *aaudioBuilder = nullptr; 70 AAudioStream *aaudioStream = nullptr; 71 aaudio_stream_state_t state; 72 int32_t framesPerBurst = 0; 73 int32_t framesPerRead = 0; 74 int32_t framesToRecord = 0; 75 int32_t framesLeft = 0; 76 int32_t xRunCount = 0; 77 int16_t *data = nullptr; 78 float peakLevel = 0.0; 79 int loopCounter = 0; 80 81 // Make printf print immediately so that debug info is not stuck 82 // in a buffer if we hang or crash. 83 setvbuf(stdout, nullptr, _IONBF, (size_t) 0); 84 85 printf("%s - Monitor input level using AAudio\n", argv[0]); 86 87 // Use an AAudioStreamBuilder to contain requested parameters. 88 result = AAudio_createStreamBuilder(&aaudioBuilder); 89 if (result != AAUDIO_OK) { 90 goto finish; 91 } 92 93 // Request stream properties. 94 AAudioStreamBuilder_setDirection(aaudioBuilder, AAUDIO_DIRECTION_INPUT); 95 AAudioStreamBuilder_setFormat(aaudioBuilder, requestedDataFormat); 96 AAudioStreamBuilder_setSharingMode(aaudioBuilder, requestedSharingMode); 97 AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, requestedPerformanceMode); 98 AAudioStreamBuilder_setChannelCount(aaudioBuilder, requestedInputChannelCount); 99 100 // Create an AAudioStream using the Builder. 101 result = AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream); 102 if (result != AAUDIO_OK) { 103 goto finish; 104 } 105 106 actualSamplesPerFrame = AAudioStream_getSamplesPerFrame(aaudioStream); 107 printf("SamplesPerFrame = %d\n", actualSamplesPerFrame); 108 actualSampleRate = AAudioStream_getSampleRate(aaudioStream); 109 printf("SamplesPerFrame = %d\n", actualSampleRate); 110 111 actualSharingMode = AAudioStream_getSharingMode(aaudioStream); 112 printf("SharingMode: requested = %s, actual = %s\n", 113 getSharingModeText(requestedSharingMode), 114 getSharingModeText(actualSharingMode)); 115 116 // This is the number of frames that are written in one chunk by a DMA controller 117 // or a DSP. 118 framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream); 119 printf("DataFormat: framesPerBurst = %d\n",framesPerBurst); 120 121 // Some DMA might use very short bursts of 16 frames. We don't need to read such small 122 // buffers. But it helps to use a multiple of the burst size for predictable scheduling. 123 framesPerRead = framesPerBurst; 124 while (framesPerRead < MIN_FRAMES_TO_READ) { 125 framesPerRead *= 2; 126 } 127 printf("DataFormat: framesPerRead = %d\n",framesPerRead); 128 129 actualDataFormat = AAudioStream_getFormat(aaudioStream); 130 printf("DataFormat: requested = %d, actual = %d\n", requestedDataFormat, actualDataFormat); 131 // TODO handle other data formats 132 assert(actualDataFormat == AAUDIO_FORMAT_PCM_I16); 133 134 printf("PerformanceMode: requested = %d, actual = %d\n", requestedPerformanceMode, 135 AAudioStream_getPerformanceMode(aaudioStream)); 136 137 // Allocate a buffer for the audio data. 138 data = new(std::nothrow) int16_t[framesPerRead * actualSamplesPerFrame]; 139 if (data == nullptr) { 140 fprintf(stderr, "ERROR - could not allocate data buffer\n"); 141 result = AAUDIO_ERROR_NO_MEMORY; 142 goto finish; 143 } 144 145 // Start the stream. 146 printf("call AAudioStream_requestStart()\n"); 147 result = AAudioStream_requestStart(aaudioStream); 148 if (result != AAUDIO_OK) { 149 fprintf(stderr, "ERROR - AAudioStream_requestStart() returned %d\n", result); 150 goto finish; 151 } 152 153 state = AAudioStream_getState(aaudioStream); 154 printf("after start, state = %s\n", AAudio_convertStreamStateToText(state)); 155 156 // Record for a while. 157 framesToRecord = actualSampleRate * NUM_SECONDS; 158 framesLeft = framesToRecord; 159 while (framesLeft > 0) { 160 // Read audio data from the stream. 161 const int64_t timeoutNanos = 100 * NANOS_PER_MILLISECOND; 162 int minFrames = (framesToRecord < framesPerRead) ? framesToRecord : framesPerRead; 163 int actual = AAudioStream_read(aaudioStream, data, minFrames, timeoutNanos); 164 if (actual < 0) { 165 fprintf(stderr, "ERROR - AAudioStream_read() returned %d\n", actual); 166 result = actual; 167 goto finish; 168 } else if (actual == 0) { 169 fprintf(stderr, "WARNING - AAudioStream_read() returned %d\n", actual); 170 goto finish; 171 } 172 framesLeft -= actual; 173 174 // Peak finder. 175 for (int frameIndex = 0; frameIndex < actual; frameIndex++) { 176 float sample = data[frameIndex * actualSamplesPerFrame] * (1.0/32768); 177 if (sample > peakLevel) { 178 peakLevel = sample; 179 } 180 } 181 182 // Display level as stars, eg. "******". 183 if ((loopCounter++ % 10) == 0) { 184 printf("%5.3f ", peakLevel); 185 int numStars = (int)(peakLevel * 50); 186 for (int i = 0; i < numStars; i++) { 187 printf("*"); 188 } 189 printf("\n"); 190 peakLevel = 0.0; 191 } 192 } 193 194 xRunCount = AAudioStream_getXRunCount(aaudioStream); 195 printf("AAudioStream_getXRunCount %d\n", xRunCount); 196 197finish: 198 AAudioStream_close(aaudioStream); 199 AAudioStreamBuilder_delete(aaudioBuilder); 200 delete[] data; 201 printf("exiting - AAudio result = %d = %s\n", result, AAudio_convertResultToText(result)); 202 return (result != AAUDIO_OK) ? EXIT_FAILURE : EXIT_SUCCESS; 203} 204 205