blob: 87fb40b16a031277413d36dded181992b5f84f67 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Play sine waves using AAudio.
#include <aaudio/AAudio.h>
#include <aaudio/AAudioTesting.h>
#include <asm/fcntl.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "AAudioExampleUtils.h"
#include "AAudioSimplePlayer.h"
#include "AAudioArgsParser.h"
#define NUM_SECONDS 4
int main(int argc, const char **argv)
{
AAudioArgsParser argParser;
AAudioSimplePlayer player;
SineThreadedData_t myData;
aaudio_result_t result = AAUDIO_OK;
int32_t actualChannelCount = 0;
int32_t actualSampleRate = 0;
aaudio_format_t actualDataFormat = AAUDIO_FORMAT_UNSPECIFIED;
AAudioStream *aaudioStream = nullptr;
int32_t framesPerBurst = 0;
int32_t framesPerWrite = 0;
int32_t bufferCapacity = 0;
int32_t framesToPlay = 0;
int32_t framesLeft = 0;
int32_t xRunCount = 0;
float *floatData = nullptr;
int16_t *shortData = nullptr;
int testFd = -1;
// Make printf print immediately so that debug info is not stuck
// in a buffer if we hang or crash.
setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
printf("%s - Play a sine wave using AAudio V0.1.1\n", argv[0]);
if (argParser.parseArgs(argc, argv)) {
return EXIT_FAILURE;
}
result = player.open(argParser);
if (result != AAUDIO_OK) {
fprintf(stderr, "ERROR - player.open() returned %d\n", result);
goto finish;
}
aaudioStream = player.getStream();
argParser.compareWithStream(aaudioStream);
actualChannelCount = AAudioStream_getChannelCount(aaudioStream);
actualSampleRate = AAudioStream_getSampleRate(aaudioStream);
actualDataFormat = AAudioStream_getFormat(aaudioStream);
myData.sineOsc1.setup(440.0, actualSampleRate);
myData.sineOsc2.setup(660.0, actualSampleRate);
// Some DMA might use very short bursts of 16 frames. We don't need to write such small
// buffers. But it helps to use a multiple of the burst size for predictable scheduling.
framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream);
framesPerWrite = framesPerBurst;
while (framesPerWrite < 48) {
framesPerWrite *= 2;
}
printf("Buffer: framesPerBurst = %d\n",framesPerBurst);
printf("Buffer: framesPerWrite = %d\n",framesPerWrite);
// Allocate a buffer for the audio data.
if (actualDataFormat == AAUDIO_FORMAT_PCM_FLOAT) {
floatData = new float[framesPerWrite * actualChannelCount];
} else if (actualDataFormat == AAUDIO_FORMAT_PCM_I16) {
shortData = new int16_t[framesPerWrite * actualChannelCount];
} else {
printf("ERROR Unsupported data format!\n");
goto finish;
}
testFd = open("/data/aaudio_temp.raw", O_CREAT | O_RDWR, S_IRWXU);
printf("testFd = %d, pid = %d\n", testFd, getpid());
// Start the stream.
printf("call player.start()\n");
result = player.start();
if (result != AAUDIO_OK) {
fprintf(stderr, "ERROR - AAudioStream_requestStart() returned %d\n", result);
goto finish;
}
printf("after start, state = %s\n",
AAudio_convertStreamStateToText(AAudioStream_getState(aaudioStream)));
// Play for a while.
framesToPlay = actualSampleRate * argParser.getDurationSeconds();
framesLeft = framesToPlay;
while (framesLeft > 0) {
if (actualDataFormat == AAUDIO_FORMAT_PCM_FLOAT) {
// Render sine waves to left and right channels.
myData.sineOsc1.render(&floatData[0], actualChannelCount, framesPerWrite);
if (actualChannelCount > 1) {
myData.sineOsc2.render(&floatData[1], actualChannelCount, framesPerWrite);
}
} else if (actualDataFormat == AAUDIO_FORMAT_PCM_I16) {
// Render sine waves to left and right channels.
myData.sineOsc1.render(&shortData[0], actualChannelCount, framesPerWrite);
if (actualChannelCount > 1) {
myData.sineOsc2.render(&shortData[1], actualChannelCount, framesPerWrite);
}
}
// Write audio data to the stream.
int64_t timeoutNanos = 1000 * NANOS_PER_MILLISECOND;
int32_t minFrames = (framesToPlay < framesPerWrite) ? framesToPlay : framesPerWrite;
int32_t actual = 0;
if (actualDataFormat == AAUDIO_FORMAT_PCM_FLOAT) {
actual = AAudioStream_write(aaudioStream, floatData, minFrames, timeoutNanos);
} else if (actualDataFormat == AAUDIO_FORMAT_PCM_I16) {
actual = AAudioStream_write(aaudioStream, shortData, minFrames, timeoutNanos);
}
if (actual < 0) {
fprintf(stderr, "ERROR - AAudioStream_write() returned %d\n", actual);
goto finish;
} else if (actual == 0) {
fprintf(stderr, "WARNING - AAudioStream_write() returned %d\n", actual);
goto finish;
}
framesLeft -= actual;
// Use timestamp to estimate latency.
/*
{
int64_t presentationFrame;
int64_t presentationTime;
result = AAudioStream_getTimestamp(aaudioStream,
CLOCK_MONOTONIC,
&presentationFrame,
&presentationTime
);
if (result == AAUDIO_OK) {
int64_t elapsedNanos = getNanoseconds() - presentationTime;
int64_t elapsedFrames = actualSampleRate * elapsedNanos / NANOS_PER_SECOND;
int64_t currentFrame = presentationFrame + elapsedFrames;
int64_t framesWritten = AAudioStream_getFramesWritten(aaudioStream);
int64_t estimatedLatencyFrames = framesWritten - currentFrame;
int64_t estimatedLatencyMillis = estimatedLatencyFrames * 1000 / actualSampleRate;
printf("estimatedLatencyMillis %d\n", (int)estimatedLatencyMillis);
}
}
*/
}
xRunCount = AAudioStream_getXRunCount(aaudioStream);
printf("AAudioStream_getXRunCount %d\n", xRunCount);
printf("call stop()\n");
result = player.stop();
if (result != AAUDIO_OK) {
goto finish;
}
finish:
printf("testFd = %d, fcntl before aaudio close returns 0x%08X\n",
testFd, fcntl(testFd, F_GETFD));
player.close();
printf("testFd = %d, fcntl after aaudio close returns 0x%08X\n",
testFd, fcntl(testFd, F_GETFD));
if (::close(testFd) != 0) {
printf("ERROR SharedMemoryParcelable::close() of testFd = %d, errno = %s\n",
testFd, strerror(errno));
}
printf("testFd = %d, fcntl after close() returns 0x%08X\n", testFd, fcntl(testFd, F_GETFD));
delete[] floatData;
delete[] shortData;
printf("exiting - AAudio result = %d = %s\n", result, AAudio_convertResultToText(result));
return (result != AAUDIO_OK) ? EXIT_FAILURE : EXIT_SUCCESS;
}