input_monitor.cpp revision 9dca9824da74d50be02bc81f539cc77b7bde678a
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
34int 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
172finish:
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