Home | History | Annotate | Download | only in src
      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 #include "AAudioExampleUtils.h"
     26 #include "AAudioSimpleRecorder.h"
     27 
     28 #define SAMPLE_RATE        48000
     29 
     30 #define NUM_SECONDS        10
     31 
     32 #define MIN_FRAMES_TO_READ 48  /* arbitrary, 1 msec at 48000 Hz */
     33 
     34 int main(int argc, char **argv)
     35 {
     36     (void)argc; // unused
     37 
     38     aaudio_result_t result;
     39     AAudioSimpleRecorder recorder;
     40     int actualSamplesPerFrame;
     41     int actualSampleRate;
     42     const aaudio_format_t requestedDataFormat = AAUDIO_FORMAT_PCM_I16;
     43     aaudio_format_t actualDataFormat;
     44 
     45     const int requestedInputChannelCount = 1; // Can affect whether we get a FAST path.
     46 
     47     //aaudio_performance_mode_t requestedPerformanceMode = AAUDIO_PERFORMANCE_MODE_NONE;
     48     const aaudio_performance_mode_t requestedPerformanceMode = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
     49     //aaudio_performance_mode_t requestedPerformanceMode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING;
     50     const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_SHARED;
     51     //const aaudio_sharing_mode_t requestedSharingMode = AAUDIO_SHARING_MODE_EXCLUSIVE;
     52     aaudio_sharing_mode_t actualSharingMode;
     53 
     54     AAudioStream *aaudioStream = nullptr;
     55     aaudio_stream_state_t state;
     56     int32_t framesPerBurst = 0;
     57     int32_t framesPerRead = 0;
     58     int32_t framesToRecord = 0;
     59     int32_t framesLeft = 0;
     60     int32_t xRunCount = 0;
     61     int16_t *data = nullptr;
     62     float peakLevel = 0.0;
     63     int loopCounter = 0;
     64 
     65     // Make printf print immediately so that debug info is not stuck
     66     // in a buffer if we hang or crash.
     67     setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
     68 
     69     printf("%s - Monitor input level using AAudio\n", argv[0]);
     70 
     71     recorder.setPerformanceMode(requestedPerformanceMode);
     72     recorder.setSharingMode(requestedSharingMode);
     73 
     74     result = recorder.open(requestedInputChannelCount, 48000, requestedDataFormat,
     75                            nullptr, nullptr, nullptr);
     76     if (result != AAUDIO_OK) {
     77         fprintf(stderr, "ERROR -  recorder.open() returned %d\n", result);
     78         goto finish;
     79     }
     80     aaudioStream = recorder.getStream();
     81 
     82     actualSamplesPerFrame = AAudioStream_getSamplesPerFrame(aaudioStream);
     83     printf("SamplesPerFrame = %d\n", actualSamplesPerFrame);
     84     actualSampleRate = AAudioStream_getSampleRate(aaudioStream);
     85     printf("SamplesPerFrame = %d\n", actualSampleRate);
     86 
     87     actualSharingMode = AAudioStream_getSharingMode(aaudioStream);
     88     printf("SharingMode: requested = %s, actual = %s\n",
     89             getSharingModeText(requestedSharingMode),
     90             getSharingModeText(actualSharingMode));
     91 
     92     // This is the number of frames that are written in one chunk by a DMA controller
     93     // or a DSP.
     94     framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream);
     95     printf("DataFormat: framesPerBurst = %d\n",framesPerBurst);
     96 
     97     // Some DMA might use very short bursts of 16 frames. We don't need to read such small
     98     // buffers. But it helps to use a multiple of the burst size for predictable scheduling.
     99     framesPerRead = framesPerBurst;
    100     while (framesPerRead < MIN_FRAMES_TO_READ) {
    101         framesPerRead *= 2;
    102     }
    103     printf("DataFormat: framesPerRead  = %d\n",framesPerRead);
    104 
    105     actualDataFormat = AAudioStream_getFormat(aaudioStream);
    106     printf("DataFormat: requested      = %d, actual = %d\n", requestedDataFormat, actualDataFormat);
    107     // TODO handle other data formats
    108     assert(actualDataFormat == AAUDIO_FORMAT_PCM_I16);
    109 
    110     printf("PerformanceMode: requested = %d, actual = %d\n", requestedPerformanceMode,
    111            AAudioStream_getPerformanceMode(aaudioStream));
    112 
    113     // Allocate a buffer for the audio data.
    114     data = new(std::nothrow) int16_t[framesPerRead * actualSamplesPerFrame];
    115     if (data == nullptr) {
    116         fprintf(stderr, "ERROR - could not allocate data buffer\n");
    117         result = AAUDIO_ERROR_NO_MEMORY;
    118         goto finish;
    119     }
    120 
    121     // Start the stream.
    122     result = recorder.start();
    123     if (result != AAUDIO_OK) {
    124         fprintf(stderr, "ERROR -  recorder.start() returned %d\n", result);
    125         goto finish;
    126     }
    127 
    128     state = AAudioStream_getState(aaudioStream);
    129     printf("after start, state = %s\n", AAudio_convertStreamStateToText(state));
    130 
    131     // Record for a while.
    132     framesToRecord = actualSampleRate * NUM_SECONDS;
    133     framesLeft = framesToRecord;
    134     while (framesLeft > 0) {
    135         // Read audio data from the stream.
    136         const int64_t timeoutNanos = 100 * NANOS_PER_MILLISECOND;
    137         int minFrames = (framesToRecord < framesPerRead) ? framesToRecord : framesPerRead;
    138         int actual = AAudioStream_read(aaudioStream, data, minFrames, timeoutNanos);
    139         if (actual < 0) {
    140             fprintf(stderr, "ERROR - AAudioStream_read() returned %d\n", actual);
    141             result = actual;
    142             goto finish;
    143         } else if (actual == 0) {
    144             fprintf(stderr, "WARNING - AAudioStream_read() returned %d\n", actual);
    145             goto finish;
    146         }
    147         framesLeft -= actual;
    148 
    149         // Peak finder.
    150         for (int frameIndex = 0; frameIndex < actual; frameIndex++) {
    151             float sample = data[frameIndex * actualSamplesPerFrame] * (1.0/32768);
    152             if (sample > peakLevel) {
    153                 peakLevel = sample;
    154             }
    155         }
    156 
    157         // Display level as stars, eg. "******".
    158         if ((loopCounter++ % 10) == 0) {
    159             displayPeakLevel(peakLevel);
    160             peakLevel = 0.0;
    161         }
    162     }
    163 
    164     xRunCount = AAudioStream_getXRunCount(aaudioStream);
    165     printf("AAudioStream_getXRunCount %d\n", xRunCount);
    166 
    167     result = recorder.stop();
    168     if (result != AAUDIO_OK) {
    169         goto finish;
    170     }
    171 
    172 finish:
    173     recorder.close();
    174     delete[] data;
    175     printf("exiting - AAudio result = %d = %s\n", result, AAudio_convertResultToText(result));
    176     return (result != AAUDIO_OK) ? EXIT_FAILURE : EXIT_SUCCESS;
    177 }
    178 
    179