upload android base code part6

This commit is contained in:
August 2018-08-08 17:48:24 +08:00
parent 421e214c7d
commit 4e516ec6ed
35396 changed files with 9188716 additions and 0 deletions

View file

@ -0,0 +1,172 @@
// Build the unit tests for audio_utils
cc_test {
name: "primitives_tests",
host_supported: true,
shared_libs: [
"liblog",
"libcutils",
],
srcs: ["primitives_tests.cpp"],
cflags: [
"-Werror",
"-Wall",
],
target: {
android: {
shared_libs: ["libaudioutils"],
},
host: {
static_libs: ["libaudioutils"],
},
}
}
cc_binary {
name: "fifo_tests",
host_supported: true,
srcs: ["fifo_tests.cpp"],
shared_libs: ["libaudioutils"],
static_libs: ["libsndfile"],
cflags: [
"-Werror",
"-Wall",
],
}
cc_binary {
name: "fifo_multiprocess",
host_supported: false,
srcs: ["fifo_multiprocess.cpp"],
shared_libs: ["libaudioutils", "libcutils"],
static_libs: ["libsndfile"],
cflags: [
"-Werror",
"-Wall",
],
}
cc_binary_host {
name: "fifo_threads",
// TODO move getch.c and .h to a utility library
srcs: [
"fifo_threads.cpp",
"getch.c",
],
static_libs: [
"libaudioutils",
"liblog",
],
cflags: [
"-Werror",
"-Wall",
],
}
cc_binary_host {
name: "limiter_tests",
srcs: ["limiter_tests.c"],
static_libs: ["libaudioutils"],
cflags: [
"-Werror",
"-Wall",
"-UNDEBUG",
],
}
cc_test {
name: "power_tests",
host_supported: true,
shared_libs: [
"libcutils",
"liblog",
],
srcs: ["power_tests.cpp"],
cflags: [
"-Wall",
"-Werror",
"-Wextra",
],
target: {
android: {
shared_libs: ["libaudioutils"],
},
host: {
static_libs: ["libaudioutils"],
},
}
}
cc_test {
name: "errorlog_tests",
host_supported: false,
shared_libs: [
"libcutils",
"liblog",
],
srcs: ["errorlog_tests.cpp"],
cflags: [
"-Wall",
"-Werror",
"-Wextra",
],
target: {
android: {
shared_libs: ["libaudioutils"],
},
host: {
static_libs: ["libaudioutils"],
},
}
}
cc_test {
name: "powerlog_tests",
host_supported: false,
shared_libs: [
"libcutils",
"liblog",
],
srcs: ["powerlog_tests.cpp"],
cflags: [
"-Wall",
"-Werror",
"-Wextra",
],
target: {
android: {
shared_libs: ["libaudioutils"],
},
host: {
static_libs: ["libaudioutils"],
},
}
}
cc_test {
name: "simplelog_tests",
host_supported: false,
shared_libs: [
"libcutils",
"liblog",
],
srcs: ["simplelog_tests.cpp"],
cflags: [
"-Wall",
"-Werror",
"-Wextra",
],
target: {
android: {
shared_libs: ["libaudioutils"],
},
host: {
static_libs: ["libaudioutils"],
},
}
}

View file

@ -0,0 +1,5 @@
primitive\_tests uses gtest framework
fifo\_tests does not run under gtest
FIXME: getch.[ch] are copied from ../../../../frameworks/wilhelm/tests/sandbox/

View file

@ -0,0 +1,28 @@
#!/bin/bash
#
# Run tests in this directory.
#
if [ -z "$ANDROID_BUILD_TOP" ]; then
echo "Android build environment not set"
exit -1
fi
# ensure we have mm
. $ANDROID_BUILD_TOP/build/envsetup.sh
mm
echo "waiting for device"
adb root && adb wait-for-device remount
echo "========================================"
echo "testing primitives"
adb push $OUT/system/lib/libaudioutils.so /system/lib
adb push $OUT/data/nativetest/primitives_tests/primitives_tests /system/bin
adb shell /system/bin/primitives_tests
echo "testing power"
adb push $OUT/data/nativetest/power_tests/power_tests /system/bin
adb shell /system/bin/power_tests

View file

@ -0,0 +1,104 @@
/*
* Copyright 2017 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.
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "audio_utils_errorlog_tests"
#include <audio_utils/ErrorLog.h>
#include <gtest/gtest.h>
#include <iostream>
#include <log/log.h>
using namespace android;
static size_t countNewLines(const std::string &s) {
return std::count(s.begin(), s.end(), '\n');
}
TEST(audio_utils_errorlog, basic) {
auto elog = std::make_unique<ErrorLog<int32_t>>(100 /* lines */);
const int64_t oneSecond = 1000000000;
EXPECT_EQ((size_t)1, countNewLines(elog->dumpToString()));
elog->log(1 /* code */, 0 /* nowNs */);
elog->log(2 /* code */, 1 /* nowNs */);
// two separate errors (4 lines including 2 header lines)
EXPECT_EQ((size_t)4, countNewLines(elog->dumpToString()));
// aggregation at (oneSecond - 1)
elog->log(2 /* code */, oneSecond /* nowNs */);
EXPECT_EQ((size_t)4, countNewLines(elog->dumpToString()));
// no aggregation if spaced exactly one second apart
elog->log(2 /* code */, oneSecond * 2 /* nowNs */);
EXPECT_EQ((size_t)5, countNewLines(elog->dumpToString()));
// Check log:
// truncate on lines
EXPECT_EQ((size_t)3, countNewLines(elog->dumpToString("" /* prefix */, 3 /* lines */)));
// truncate on time
EXPECT_EQ((size_t)4, countNewLines(
elog->dumpToString("" /* prefix */, 0 /* lines */, oneSecond - 1 /* limitNs */)));
// truncate on time
EXPECT_EQ((size_t)4, countNewLines(
elog->dumpToString("" /* prefix */, 0 /* lines */, oneSecond /* limitNs */)));
// truncate on time (more)
EXPECT_EQ((size_t)3, countNewLines(
elog->dumpToString("" /* prefix */, 0 /* lines */, oneSecond + 1 /* limitNs */)));
// truncate on time
EXPECT_EQ((size_t)3, countNewLines(
elog->dumpToString("" /* prefix */, 0 /* lines */, oneSecond * 2 /* limitNs */)));
// truncate on time (to first header line)
EXPECT_EQ((size_t)1, countNewLines(
elog->dumpToString("" /* prefix */, 0 /* lines */, oneSecond * 2 + 1/* limitNs */)));
elog->dump(0 /* fd (stdout) */);
// The output below depends on the local time zone.
// The indentation below is exact, check alignment.
/*
Errors: 4
Code Freq First time Last time
1 1 12-31 16:00:00.000 12-31 16:00:00.000
2 2 12-31 16:00:00.000 12-31 16:00:01.000
2 1 12-31 16:00:02.000 12-31 16:00:02.000
*/
}
TEST(audio_utils_errorlog, c) {
error_log_t *error_log =
error_log_create(100 /* lines */, 1000000000 /* one second aggregation */);
// just a sanity test
error_log_log(error_log, 2 /* code */, 1 /* now_ns */);
error_log_dump(error_log, 0 /* fd */, " " /* prefix */, 0 /* lines */, 0 /* limit_ns */);
error_log_destroy(error_log);
// This has a 2 character prefix offset from the previous test when dumping.
// The indentation below is exact, check alignment.
/*
Errors: 1
Code Freq First time Last time
2 1 12-31 16:00:00.000 12-31 16:00:00.000
*/
}

View file

@ -0,0 +1,224 @@
/*
* 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.
*/
#include <new>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <audio_utils/fifo.h>
#include <cutils/ashmem.h>
#define FRAME_COUNT 2048
#define FRAME_SIZE sizeof(int16_t)
#define BUFFER_SIZE (FRAME_COUNT * FRAME_SIZE)
int main(int argc __unused, char **argv __unused)
{
// TODO Add error checking for ashmem_create_region and mmap
const int frontFd = ashmem_create_region("front", sizeof(audio_utils_fifo_index));
printf("frontFd=%d\n", frontFd);
const int rearFd = ashmem_create_region("rear", sizeof(audio_utils_fifo_index));
printf("rearFd=%d\n", rearFd);
const int dataFd = ashmem_create_region("buffer", BUFFER_SIZE);
printf("dataFd=%d\n", dataFd);
// next two index constructors must execute exactly once, so we do it in the parent
audio_utils_fifo_index *frontIndex = (audio_utils_fifo_index *) mmap(NULL,
sizeof(audio_utils_fifo_index), PROT_READ | PROT_WRITE, MAP_SHARED, frontFd, (off_t) 0);
printf("parent frontIndex=%p\n", frontIndex);
(void) new(frontIndex) audio_utils_fifo_index();
audio_utils_fifo_index *rearIndex = (audio_utils_fifo_index *) mmap(NULL,
sizeof(audio_utils_fifo_index), PROT_READ | PROT_WRITE, MAP_SHARED, rearFd, (off_t) 0);
printf("parent rearIndex=%p\n", rearIndex);
(void) new(rearIndex) audio_utils_fifo_index();
int16_t *data = (int16_t *) mmap(NULL, sizeof(audio_utils_fifo_index), PROT_READ | PROT_WRITE,
MAP_SHARED, dataFd, (off_t) 0);
printf("parent data=%p\n", data);
memset(data, 0, BUFFER_SIZE);
const int pageSize = getpagesize();
printf("page size=%d\n", pageSize);
// create writer
printf("fork writer:\n");
const pid_t pidWriter = fork();
// TODO check if pidWriter < 0
if (!pidWriter) {
// Child inherits the parent's read/write mapping of front index.
// To confirm that there are no attempts to write to the front index,
// unmap it and then re-map it as read-only.
int ok = munmap(frontIndex, sizeof(audio_utils_fifo_index));
printf("writer unmap front ok=%d\n", ok);
ok = ashmem_set_prot_region(frontFd, PROT_READ);
printf("writer prot read front ok=%d\n", ok);
// The pagesize * 4 offset confirms that we don't assume identical mapping in both processes
frontIndex = (audio_utils_fifo_index *) mmap((char *) frontIndex + pageSize * 4,
sizeof(audio_utils_fifo_index), PROT_READ, MAP_SHARED | MAP_FIXED, frontFd,
(off_t) 0);
printf("writer frontIndex=%p\n", frontIndex);
// Retain our read/write mapping of rear index and data
audio_utils_fifo fifo(FRAME_COUNT, FRAME_SIZE, data, *rearIndex, frontIndex);
audio_utils_fifo_writer writer(fifo);
sleep(2);
for (int16_t value = 1; value <= 20; value++) {
printf("writing %d\n", value);
const ssize_t actual = writer.write(&value, 1);
if (actual != 1) {
printf("wrote unexpected actual = %zd\n", actual);
break;
}
// TODO needs a lot of work
switch (value) {
case 10:
sleep(2);
break;
case 14:
sleep(4);
break;
default:
usleep(500000);
break;
}
}
(void) close(frontFd);
(void) close(rearFd);
(void) close(dataFd);
return EXIT_SUCCESS;
}
// The sleep(2) above and sleep(1) here ensure that the order is:
// a. writer initializes
// b. reader initializes
// c. reader starts the read loop
// d. writer starts the write loop
// Actually, as long as (a) precedes (d) and (b) precedes (c), the order does not matter.
// TODO test all valid sequences.
sleep(1);
// create reader
printf("fork reader:\n");
const pid_t pidReader = fork();
// TODO check if pidReader < 0
if (!pidReader) {
// Child inherits the parent's read/write mapping of rear index.
// To confirm that there are no attempts to write to the rear index,
// unmap it and then re-map it as read-only.
int ok = munmap(rearIndex, sizeof(audio_utils_fifo_index));
printf("reader unmap rear ok=%d\n", ok);
ok = ashmem_set_prot_region(rearFd, PROT_READ);
printf("reader prot read rear ok=%d\n", ok);
// The pagesize * 4 offset confirms that we don't assume identical mapping in both processes
rearIndex = (audio_utils_fifo_index *) mmap((char *) rearIndex + pageSize * 4,
sizeof(audio_utils_fifo_index), PROT_READ, MAP_SHARED | MAP_FIXED, rearFd,
(off_t) 0);
printf("reader rearIndex=%p\n", rearIndex);
// Similarly for the data
ok = munmap(data, BUFFER_SIZE);
printf("reader unmap data ok=%d\n", ok);
ok = ashmem_set_prot_region(dataFd, PROT_READ);
printf("reader prot read data ok=%d\n", ok);
// The pagesize * 8 offset confirms that we don't assume identical mapping in both processes
data = (int16_t *) mmap((char *) data + pageSize * 8, BUFFER_SIZE, PROT_READ,
MAP_SHARED | MAP_FIXED, dataFd, (off_t) 0);
printf("reader data=%p\n", data);
// Retain our read/write mapping of front index
audio_utils_fifo fifo(FRAME_COUNT, FRAME_SIZE, data, *rearIndex, frontIndex);
audio_utils_fifo_reader reader(fifo);
for (;;) {
int16_t value;
struct timespec timeout = {
.tv_sec = 1,
.tv_nsec = 0
};
const ssize_t actual = reader.read(&value, 1, &timeout);
switch (actual) {
case 0:
break;
case 1:
printf("read %d\n", value);
if (value == 20) {
goto out;
}
break;
case -ETIMEDOUT:
printf("read timed out\n");
break;
default:
printf("read unexpected actual = %zd\n", actual);
goto out;
}
}
out:
(void) close(frontFd);
(void) close(rearFd);
(void) close(dataFd);
return EXIT_SUCCESS;
}
int status;
pid_t pid = waitpid(pidWriter, &status, 0);
if (pid == pidWriter) {
printf("writer exited with status %d\n", status);
} else {
printf("waitpid on writer = %d\n", pid);
}
pid = waitpid(pidReader, &status, 0);
if (pid == pidReader) {
printf("reader exited with status %d\n", status);
} else {
printf("waitpid on reader = %d\n", pid);
}
// next two index destructors must execute exactly once, so we do it in the parent
frontIndex->~audio_utils_fifo_index();
rearIndex->~audio_utils_fifo_index();
int ok = munmap(frontIndex, sizeof(audio_utils_fifo_index));
printf("parent unmap front ok=%d\n", ok);
ok = munmap(rearIndex, sizeof(audio_utils_fifo_index));
printf("parent unmap rear ok=%d\n", ok);
ok = munmap(data, BUFFER_SIZE);
printf("parent unmap data ok=%d\n", ok);
(void) close(frontFd);
(void) close(rearFd);
(void) close(dataFd);
return EXIT_SUCCESS;
}

View file

@ -0,0 +1,245 @@
/*
* Copyright (C) 2015 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.
*/
// Test program for audio_utils FIFO library.
// This only tests the single-threaded aspects, not the barriers.
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <audio_utils/fifo.h>
#include <audio_utils/sndfile.h>
#ifndef min
#define min(x, y) (((x) < (y)) ? (x) : (y))
#endif
int main(int argc, char **argv)
{
size_t frameCount = 0;
size_t maxFramesPerRead = 0;
size_t maxFramesPerWrite = 0;
bool readerThrottlesWriter = true;
bool verbose = false;
int i;
for (i = 1; i < argc; i++) {
char *arg = argv[i];
if (arg[0] != '-')
break;
switch (arg[1]) {
case 'f': // FIFO frame count
frameCount = atoi(&arg[2]);
break;
case 'r': // maximum frame count per read from FIFO
maxFramesPerRead = atoi(&arg[2]);
break;
case 't': // disable throttling of writer by reader
readerThrottlesWriter = false;
break;
case 'v': // enable verbose logging
verbose = true;
break;
case 'w': // maximum frame count per write to FIFO
maxFramesPerWrite = atoi(&arg[2]);
break;
default:
fprintf(stderr, "%s: unknown option %s\n", argv[0], arg);
goto usage;
}
}
if (frameCount == 0) {
frameCount = 256;
}
if (maxFramesPerRead == 0) {
maxFramesPerRead = frameCount;
}
if (maxFramesPerWrite == 0) {
maxFramesPerWrite = frameCount;
}
if (argc - i != 2) {
usage:
fprintf(stderr, "usage: %s [-f#] [-r#] [-t] [-v] [-w#] in.wav out.wav\n", argv[0]);
return EXIT_FAILURE;
}
char *inputFile = argv[i];
char *outputFile = argv[i+1];
SF_INFO sfinfoin;
memset(&sfinfoin, 0, sizeof(sfinfoin));
SNDFILE *sfin = sf_open(inputFile, SFM_READ, &sfinfoin);
if (sfin == NULL) {
perror(inputFile);
return EXIT_FAILURE;
}
switch (sfinfoin.format & (SF_FORMAT_TYPEMASK | SF_FORMAT_SUBMASK)) {
case SF_FORMAT_WAV | SF_FORMAT_PCM_16:
case SF_FORMAT_WAV | SF_FORMAT_PCM_U8:
break;
default:
fprintf(stderr, "%s: unsupported format\n", inputFile);
sf_close(sfin);
return EXIT_FAILURE;
}
size_t frameSize = sizeof(int16_t) * sfinfoin.channels;
int16_t *inputBuffer = new int16_t[sfinfoin.frames * sfinfoin.channels];
sf_count_t actualRead = sf_readf_short(sfin, inputBuffer, sfinfoin.frames);
if (actualRead != sfinfoin.frames) {
fprintf(stderr, "%s: unexpected EOF or error\n", inputFile);
sf_close(sfin);
return EXIT_FAILURE;
}
sf_close(sfin);
int16_t *outputBuffer = new int16_t[sfinfoin.frames * sfinfoin.channels];
size_t framesWritten = 0;
size_t framesRead = 0;
int16_t *fifoBuffer = new int16_t[frameCount * sfinfoin.channels];
audio_utils_fifo fifo(frameCount, frameSize, fifoBuffer, readerThrottlesWriter);
audio_utils_fifo_writer fifoWriter(fifo);
audio_utils_fifo_reader fifoReader(fifo, readerThrottlesWriter);
int fifoWriteCount = 0, fifoReadCount = 0;
int fifoFillLevel = 0, minFillLevel = INT_MAX, maxFillLevel = INT_MIN;
for (;;) {
size_t framesToWrite = sfinfoin.frames - framesWritten;
size_t framesToRead = sfinfoin.frames - framesRead;
if (framesToWrite == 0 && (framesToRead == 0 || !readerThrottlesWriter)) {
break;
}
if (framesToWrite > maxFramesPerWrite) {
framesToWrite = maxFramesPerWrite;
}
framesToWrite = rand() % (framesToWrite + 1);
ssize_t actualWritten = fifoWriter.write(
&inputBuffer[framesWritten * sfinfoin.channels], framesToWrite);
if (verbose) {
printf("wrote %d out of %d\n", (int) actualWritten, (int) framesToWrite);
}
if (actualWritten < 0 || (size_t) actualWritten > framesToWrite) {
fprintf(stderr, "write to FIFO failed\n");
break;
}
if (actualWritten < min((int) frameCount - fifoFillLevel, (int) framesToWrite)) {
fprintf(stderr, "only wrote %d when should have written min(%d, %d)\n",
(int) actualWritten, (int) frameCount - fifoFillLevel, (int) framesToWrite);
}
framesWritten += actualWritten;
if (actualWritten > 0) {
fifoWriteCount++;
}
fifoFillLevel += actualWritten;
if (verbose) {
printf("fill level after write %d\n", fifoFillLevel);
}
if (fifoFillLevel > maxFillLevel) {
maxFillLevel = fifoFillLevel;
if (maxFillLevel > (int) frameCount) {
if (readerThrottlesWriter) {
printf("maxFillLevel=%d > frameCount=%d\n", maxFillLevel, (int) frameCount);
abort();
}
}
}
if (framesToRead > maxFramesPerRead) {
framesToRead = maxFramesPerRead;
}
framesToRead = rand() % (framesToRead + 1);
ssize_t actualRead = fifoReader.read(
&outputBuffer[framesRead * sfinfoin.channels], framesToRead);
if (verbose) {
printf("read %d out of %d\n", (int) actualRead, (int) framesToRead);
}
if (actualRead < 0 || (size_t) actualRead > framesToRead) {
switch (actualRead) {
case -EIO:
fprintf(stderr, "read from FIFO failed: corrupted indices\n");
abort();
break;
case -EOVERFLOW:
if (readerThrottlesWriter) {
fprintf(stderr, "read from FIFO failed: unexpected overflow\n");
abort();
}
printf("warning: reader lost frames\n");
actualRead = 0;
break;
default:
if (actualRead < 0) {
fprintf(stderr, "read from FIFO failed: unexpected error code %d\n",
(int) actualRead);
} else {
fprintf(stderr, "read from FIFO failed: actualRead=%d > framesToRead=%d\n",
(int) actualRead, (int) framesToRead);
}
abort();
}
}
if (actualRead < min(fifoFillLevel, (int) framesToRead)) {
//fprintf(stderr, "only read %d when should have read min(%d, %d)\n",
// (int) actualRead, fifoFillLevel, (int) framesToRead);
}
framesRead += actualRead;
if (actualRead > 0) {
fifoReadCount++;
}
fifoFillLevel -= actualRead;
if (verbose) {
printf("fill level after read %d\n", fifoFillLevel);
}
if (fifoFillLevel < minFillLevel) {
minFillLevel = fifoFillLevel;
if (minFillLevel < 0) {
printf("minFillLevel=%d < 0\n", minFillLevel);
abort();
}
}
}
delete[] inputBuffer;
inputBuffer = NULL;
delete[] fifoBuffer;
fifoBuffer = NULL;
printf("FIFO non-empty writes: %d, non-empty reads: %d\n", fifoWriteCount, fifoReadCount);
printf("fill=%d, min=%d, max=%d\n", fifoFillLevel, minFillLevel, maxFillLevel);
printf("writing output\n");
SF_INFO sfinfoout;
memset(&sfinfoout, 0, sizeof(sfinfoout));
sfinfoout.samplerate = sfinfoin.samplerate;
sfinfoout.channels = sfinfoin.channels;
sfinfoout.format = sfinfoin.format;
SNDFILE *sfout = sf_open(outputFile, SFM_WRITE, &sfinfoout);
if (sfout == NULL) {
perror(outputFile);
return EXIT_FAILURE;
}
sf_count_t actualWritten = sf_writef_short(sfout, outputBuffer, framesRead);
delete[] outputBuffer;
outputBuffer = NULL;
if (actualWritten != (sf_count_t) framesRead) {
fprintf(stderr, "%s: unexpected error\n", outputFile);
sf_close(sfout);
return EXIT_FAILURE;
}
sf_close(sfout);
printf("done\n");
return EXIT_SUCCESS;
}

View file

@ -0,0 +1,166 @@
/*
* 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.
*/
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <audio_utils/fifo.h>
extern "C" {
#include "getch.h"
}
struct Context {
audio_utils_fifo_writer *mInputWriter;
audio_utils_fifo_reader *mInputReader;
audio_utils_fifo_writer *mTransferWriter;
audio_utils_fifo_reader *mTransferReader;
audio_utils_fifo_writer *mOutputWriter;
audio_utils_fifo_reader *mOutputReader;
};
void *input_routine(void *arg)
{
Context *context = (Context *) arg;
for (;;) {
struct timespec timeout;
timeout.tv_sec = 30;
timeout.tv_nsec = 0;
char buffer[4];
ssize_t actual = context->mInputReader->read(buffer, sizeof(buffer), &timeout);
// TODO this test is unreadable
if (actual > 0) {
if ((size_t) actual > sizeof(buffer)) {
printf("input.read actual = %d\n", (int) actual);
abort();
}
ssize_t actual2 = context->mTransferWriter->write(buffer, actual, &timeout);
if (actual2 != actual) {
printf("transfer.write(%d) = %d\n", (int) actual, (int) actual2);
}
//sleep(10);
} else if (actual == -ETIMEDOUT) {
(void) write(1, "t", 1);
} else {
printf("input.read actual = %d\n", (int) actual);
}
}
return NULL;
}
volatile bool outputPaused = false;
void *output_routine(void *arg)
{
Context *context = (Context *) arg;
for (;;) {
if (outputPaused) {
sleep(1);
continue;
}
struct timespec timeout;
timeout.tv_sec = 60;
timeout.tv_nsec = 0;
char buffer[4];
ssize_t actual = context->mTransferReader->read(buffer, sizeof(buffer), &timeout);
if (actual > 0) {
if ((size_t) actual > sizeof(buffer)) {
printf("transfer.read actual = %d\n", (int) actual);
abort();
}
ssize_t actual2 = context->mOutputWriter->write(buffer, actual, NULL /*timeout*/);
if (actual2 != actual) {
printf("output.write(%d) = %d\n", (int) actual, (int) actual2);
}
} else if (actual == -ETIMEDOUT) {
(void) write(1, "T", 1);
} else {
printf("transfer.read actual = %d\n", (int) actual);
}
}
return NULL;
}
int main(int argc, char **argv)
{
set_conio_terminal_mode();
argc = argc + 0;
argv = &argv[0];
char inputBuffer[16];
audio_utils_fifo inputFifo(sizeof(inputBuffer) /*frameCount*/, 1 /*frameSize*/, inputBuffer,
true /*throttlesWriter*/);
audio_utils_fifo_writer inputWriter(inputFifo);
audio_utils_fifo_reader inputReader(inputFifo, true /*throttlesWriter*/);
//inputWriter.setHysteresis(sizeof(inputBuffer) * 1/4, sizeof(inputBuffer) * 3/4);
char transferBuffer[64];
audio_utils_fifo transferFifo(sizeof(transferBuffer) /*frameCount*/, 1 /*frameSize*/,
transferBuffer, true /*throttlesWriter*/);
audio_utils_fifo_writer transferWriter(transferFifo);
audio_utils_fifo_reader transferReader(transferFifo, true /*throttlesWriter*/);
transferReader.setHysteresis(sizeof(transferBuffer) * 3/4, sizeof(transferBuffer) * 1/4);
//transferWriter.setEffective(8);
char outputBuffer[64];
audio_utils_fifo outputFifo(sizeof(outputBuffer) /*frameCount*/, 1 /*frameSize*/, outputBuffer,
true /*throttlesWriter*/);
audio_utils_fifo_writer outputWriter(outputFifo);
audio_utils_fifo_reader outputReader(outputFifo, true /*readerThrottlesWriter*/);
Context context;
context.mInputWriter = &inputWriter;
context.mInputReader = &inputReader;
context.mTransferWriter = &transferWriter;
context.mTransferReader = &transferReader;
context.mOutputWriter = &outputWriter;
context.mOutputReader = &outputReader;
pthread_t input_thread;
int ok = pthread_create(&input_thread, (const pthread_attr_t *) NULL, input_routine,
(void *) &context);
pthread_t output_thread;
ok = pthread_create(&output_thread, (const pthread_attr_t *) NULL, output_routine,
(void *) &context);
ok = ok + 0;
for (;;) {
char buffer[4];
ssize_t actual = outputReader.read(buffer, sizeof(buffer), NULL /*timeout*/);
if (actual > 0) {
printf("%.*s", (int) actual, buffer);
fflush(stdout);
} else if (actual != 0) {
printf("outputReader.read actual = %d\n", (int) actual);
}
if (kbhit()) {
int ch = getch();
if (ch <= 0 || ch == '\003' /*control-C*/) {
break;
}
if (ch == 'p')
outputPaused = true;
else if (ch == 'p')
outputPaused = false;
buffer[0] = ch;
actual = inputWriter.write(buffer, 1, NULL /*timeout*/);
if (actual != 1) {
printf("inputWriter.write actual = %d\n", (int) actual);
}
}
}
reset_terminal_mode();
}

View file

@ -0,0 +1,65 @@
/*
C non-blocking keyboard input
http://stackoverflow.com/questions/448944/c-non-blocking-keyboard-input
*/
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <termios.h>
#include <unistd.h>
#include "getch.h"
struct termios orig_termios;
void reset_terminal_mode()
{
tcsetattr(0, TCSANOW, &orig_termios);
}
void set_conio_terminal_mode()
{
struct termios new_termios;
/* take two copies - one for now, one for later */
tcgetattr(0, &orig_termios);
memcpy(&new_termios, &orig_termios, sizeof(new_termios));
/* register cleanup handler, and set the new terminal mode */
atexit(reset_terminal_mode);
cfmakeraw(&new_termios);
new_termios.c_oflag |= OPOST;
tcsetattr(0, TCSANOW, &new_termios);
}
int kbhit()
{
struct timeval tv = { 0L, 0L };
fd_set fds;
FD_ZERO(&fds); // not in original posting to stackoverflow
FD_SET(0, &fds);
return select(1, &fds, NULL, NULL, &tv);
}
int getch()
{
int r;
unsigned char c;
if ((r = read(0, &c, sizeof(c))) < 0) {
return r;
} else {
return c;
}
}
#if 0
int main(int argc, char *argv[])
{
set_conio_terminal_mode();
while (!kbhit()) {
/* do some work */
}
(void)getch(); /* consume the character */
}
#endif

View file

@ -0,0 +1,20 @@
/*
* Copyright (C) 2011 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.
*/
extern int kbhit();
extern int getch(void);
extern void set_conio_terminal_mode(void);
extern void reset_terminal_mode(void);

View file

@ -0,0 +1,42 @@
/*
* 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.
*/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <audio_utils/limiter.h>
int main(int argc, char **argv)
{
int i;
if (argc > 1) {
for (i = 1; i < argc; i++) {
float x = atof(argv[i]);
printf("limit(%g)=%g\n", x, limiter(x));
}
} else {
for (i = 0; i <= 150; i++) {
float in = (float) ((double) i * 0.01);
float out = limiter(in);
printf("%g,%g\n", in, out);
if (i != 0) {
out = limiter(-in);
printf("%g,%g\n", -in, out);
}
}
}
return EXIT_SUCCESS;
}

View file

@ -0,0 +1,173 @@
/*
* Copyright 2017 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.
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "audio_utils_power_tests"
#include <cmath>
#include <math.h>
#include <audio_utils/power.h>
#include <gtest/gtest.h>
#include <log/log.h>
typedef struct { uint8_t c[3]; } __attribute__((__packed__)) uint8x3_t;
void testFloatValue(float f_value, size_t length) {
const float power = audio_utils_power_from_amplitude(f_value);
float f_ary[length];
uint8_t u8_ary[length];
int16_t i16_ary[length];
int32_t i32_ary[length];
int32_t q8_23_ary[length];
uint8x3_t p24_ary[length];
// magic formulas to convert floating point to fixed point representations.
// we negate the floating point value to ensure full integer range for 1.f.
const uint8_t u8_value((1.f - f_value) * 128);
const int16_t i16_value(f_value * INT16_MIN);
const int32_t i32_value (f_value * INT32_MIN);
const int32_t q8_23_value(f_value * -(1 << 23));
// PCM_24_BIT_PACKED is native endian.
#if HAVE_BIG_ENDIAN
const uint8x3_t p24_value{{
uint8_t(q8_23_value >> 16),
uint8_t(q8_23_value >> 8),
uint8_t(q8_23_value),
}};
#else
const uint8x3_t p24_value{{
uint8_t(q8_23_value),
uint8_t(q8_23_value >> 8),
uint8_t(q8_23_value >> 16),
}};
#endif
for (size_t i = 0; i < length; ++i) {
f_ary[i] = f_value;
u8_ary[i] = u8_value;
i16_ary[i] = i16_value;
i32_ary[i] = i32_value;
q8_23_ary[i] = q8_23_value;
p24_ary[i] = p24_value;
}
// check offset by 1, 2, 3 elements for unaligned NEON vector handling.
for (size_t i = 0; i < 3; ++i) {
if (i >= length) break;
EXPECT_EQ(power,
audio_utils_compute_power_mono(f_ary + i, AUDIO_FORMAT_PCM_FLOAT, length - i));
EXPECT_EQ(power,
audio_utils_compute_power_mono(u8_ary + i, AUDIO_FORMAT_PCM_8_BIT, length - i));
EXPECT_EQ(power,
audio_utils_compute_power_mono(i16_ary + i, AUDIO_FORMAT_PCM_16_BIT, length - i));
EXPECT_EQ(power,
audio_utils_compute_power_mono(i32_ary + i, AUDIO_FORMAT_PCM_32_BIT, length - i));
EXPECT_EQ(power,
audio_utils_compute_power_mono(
q8_23_ary + i, AUDIO_FORMAT_PCM_8_24_BIT, length - i));
EXPECT_EQ(power,
audio_utils_compute_power_mono(
p24_ary + i, AUDIO_FORMAT_PCM_24_BIT_PACKED, length - i));
}
}
void testFloatRamp(size_t length) {
float f_ary[length];
uint8_t u8_ary[length];
int16_t i16_ary[length];
int32_t i32_ary[length];
int32_t q8_23_ary[length];
uint8x3_t p24_ary[length];
for (size_t i = 0; i < length; ++i) {
// must be expressed cleanly in uint8_t
const float f_value = (int(length & 0xff) - 128) / 128.f;
// magic formulas to convert floating point to fixed point representations.
// we negate the floating point value to ensure full integer range for 1.f.
const uint8_t u8_value((1.f - f_value) * 128);
const int16_t i16_value(f_value * INT16_MIN);
const int32_t i32_value (f_value * INT32_MIN);
const int32_t q8_23_value(f_value * -(1 << 23));
// PCM_24_BIT_PACKED is native endian.
#if HAVE_BIG_ENDIAN
const uint8x3_t p24_value{{
uint8_t(q8_23_value >> 16),
uint8_t(q8_23_value >> 8),
uint8_t(q8_23_value),
}};
#else
const uint8x3_t p24_value{{
uint8_t(q8_23_value),
uint8_t(q8_23_value >> 8),
uint8_t(q8_23_value >> 16),
}};
#endif
f_ary[i] = f_value;
u8_ary[i] = u8_value;
i16_ary[i] = i16_value;
i32_ary[i] = i32_value;
q8_23_ary[i] = q8_23_value;
p24_ary[i] = p24_value;
}
const float power8 = audio_utils_compute_power_mono(u8_ary, AUDIO_FORMAT_PCM_8_BIT, length);
EXPECT_EQ(power8,
audio_utils_compute_power_mono(f_ary, AUDIO_FORMAT_PCM_FLOAT, length));
EXPECT_EQ(power8,
audio_utils_compute_power_mono(i16_ary, AUDIO_FORMAT_PCM_16_BIT, length));
EXPECT_EQ(power8,
audio_utils_compute_power_mono(i32_ary, AUDIO_FORMAT_PCM_32_BIT, length));
EXPECT_EQ(power8,
audio_utils_compute_power_mono(q8_23_ary, AUDIO_FORMAT_PCM_8_24_BIT, length));
EXPECT_EQ(power8,
audio_utils_compute_power_mono(p24_ary, AUDIO_FORMAT_PCM_24_BIT_PACKED, length));
}
// power_mono implicitly tests energy_mono
TEST(audio_utils_power, power_mono) {
// f_values should have limited mantissa
for (float f_value : { 0.f, 0.25f, 0.5f, 0.75f, 1.f }) {
const float power = audio_utils_power_from_amplitude(f_value);
printf("power_mono: amplitude: %f power: %f\n", f_value, power);
for (size_t length : { 1, 3, 5, 7, 16, 21, 32, 37 }) {
testFloatValue(f_value, length);
}
}
}
// power_mono implicitly tests energy_mono
TEST(audio_utils_power, power_mono_ramp) {
for (size_t length : { 1, 3, 5, 7, 16, 21, 32, 37, 297 }) {
testFloatRamp(length);
}
}
TEST(audio_utils_power, power_from) {
EXPECT_EQ(0.f, audio_utils_power_from_amplitude(1.f));
EXPECT_EQ(-INFINITY, audio_utils_power_from_amplitude(0.f));
EXPECT_EQ(0.f, audio_utils_power_from_amplitude(-1.f));
EXPECT_EQ(0.f, audio_utils_power_from_energy(1.f));
EXPECT_EQ(-INFINITY, audio_utils_power_from_energy(0.f));
EXPECT_TRUE(std::isnan(audio_utils_power_from_energy(-1.f)));
}

View file

@ -0,0 +1,103 @@
/*
* Copyright 2017 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.
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "audio_utils_powerlog_tests"
#include <audio_utils/PowerLog.h>
#include <gtest/gtest.h>
#include <iostream>
#include <log/log.h>
using namespace android;
static size_t countNewLines(const std::string &s) {
return std::count(s.begin(), s.end(), '\n');
}
TEST(audio_utils_powerlog, basic) {
auto plog = std::make_unique<PowerLog>(
48000 /* sampleRate */,
1 /* channelCount */,
AUDIO_FORMAT_PCM_16_BIT,
100 /* entries */,
1 /* framesPerEntry */);
// header
EXPECT_EQ((size_t)1, countNewLines(plog->dumpToString()));
const int16_t zero = 0;
const int16_t half = 0x4000;
plog->log(&half, 1 /* frame */, 0 /* nowNs */);
plog->log(&half, 1 /* frame */, 1 /* nowNs */);
plog->log(&half, 1 /* frame */, 2 /* nowNs */);
// one line / signal
EXPECT_EQ((size_t)2, countNewLines(plog->dumpToString()));
plog->log(&zero, 1 /* frame */, 3 /* nowNs */);
// zero termination doesn't change this.
EXPECT_EQ((size_t)2, countNewLines(plog->dumpToString()));
// but adding next line does.
plog->log(&half, 1 /* frame */, 4 /* nowNs */);
EXPECT_EQ((size_t)3, countNewLines(plog->dumpToString()));
// truncating on lines
EXPECT_EQ((size_t)2, countNewLines(plog->dumpToString(
"" /* prefix */, 2 /* lines */)));
// truncating on time
EXPECT_EQ((size_t)3, countNewLines(plog->dumpToString(
"" /* prefix */, 0 /* lines */, 2 /* limitNs */)));
EXPECT_EQ((size_t)2, countNewLines(plog->dumpToString(
"" /* prefix */, 0 /* lines */, 3 /* limitNs */)));
plog->dump(0 /* fd (stdout) */);
// The output below depends on the local time zone.
// The indentation below is exact, check alignment.
/*
Signal power history:
12-31 16:00:00.000: [ -6.0 -6.0 -6.0 ] sum(-1.2)
12-31 16:00:00.000: [ -6.0
*/
}
TEST(audio_utils_powerlog, c) {
power_log_t *power_log = power_log_create(
48000 /* sample_rate */,
1 /* channel_count */,
AUDIO_FORMAT_PCM_16_BIT,
100 /* entries */,
1 /* frames_per_entry */);
// sanity test
const int16_t zero = 0;
const int16_t quarter = 0x2000;
power_log_log(power_log, &quarter, 1 /* frame */, 0 /* now_ns */);
power_log_log(power_log, &zero, 1 /* frame */, 1 /* now_ns */);
power_log_dump(power_log, 0 /* fd */, " " /* prefix */, 0 /* lines */, 0 /* limit_ns */);
power_log_destroy(power_log);
// This has a 2 character prefix offset from the previous test when dumping.
// The indentation below is exact, check alignment.
/*
Signal power history:
12-31 16:00:00.000: [ -12.0 ] sum(-12.0)
*/
}

View file

@ -0,0 +1,691 @@
/*
* Copyright (C) 2014 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.
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "audio_utils_primitives_tests"
#include <math.h>
#include <vector>
#include <gtest/gtest.h>
#include <log/log.h>
#include <audio_utils/primitives.h>
#include <audio_utils/format.h>
#include <audio_utils/channels.h>
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
static const int32_t lim8pos = 255;
static const int32_t lim8neg = 0;
static const int32_t lim16pos = (1 << 15) - 1;
static const int32_t lim16neg = -(1 << 15);
static const int32_t lim24pos = (1 << 23) - 1;
static const int32_t lim24neg = -(1 << 23);
inline void testClamp8(float f)
{
// f is in native u8 scaling to test rounding
uint8_t uval = clamp8_from_float((f - 128) / (1 << 7));
// test clamping
ALOGV("clamp8_from_float(%f) = %u\n", f, uval);
if (f > lim8pos) {
EXPECT_EQ(lim8pos, uval);
} else if (f < lim8neg) {
EXPECT_EQ(lim8neg, uval);
}
// if in range, make sure round trip clamp and conversion is correct.
if (f < lim8pos - 1. && f > lim8neg + 1.) {
uint8_t uval2 = clamp8_from_float(float_from_u8(uval));
int diff = abs(uval - uval2);
EXPECT_LE(diff, 1);
}
}
inline void testClamp16(float f)
{
int16_t ival = clamp16_from_float(f / (1 << 15));
// test clamping
ALOGV("clamp16_from_float(%f) = %d\n", f, ival);
if (f > lim16pos) {
EXPECT_EQ(lim16pos, ival);
} else if (f < lim16neg) {
EXPECT_EQ(lim16neg, ival);
}
// if in range, make sure round trip clamp and conversion is correct.
if (f < lim16pos - 1. && f > lim16neg + 1.) {
int ival2 = clamp16_from_float(float_from_i16(ival));
int diff = abs(ival - ival2);
EXPECT_LE(diff, 1);
}
}
inline void testClamp24(float f)
{
int32_t ival = clamp24_from_float(f / (1 << 23));
// test clamping
ALOGV("clamp24_from_float(%f) = %d\n", f, ival);
if (f > lim24pos) {
EXPECT_EQ(lim24pos, ival);
} else if (f < lim24neg) {
EXPECT_EQ(lim24neg, ival);
}
// if in range, make sure round trip clamp and conversion is correct.
if (f < lim24pos - 1. && f > lim24neg + 1.) {
int ival2 = clamp24_from_float(float_from_q8_23(ival));
int diff = abs(ival - ival2);
EXPECT_LE(diff, 1);
}
}
template<typename T>
void checkMonotone(const T *ary, size_t size)
{
for (size_t i = 1; i < size; ++i) {
EXPECT_LT(ary[i-1], ary[i]);
}
}
void checkMonotonep24(uint8_t * pary, size_t size)
{
size_t frames = size/3;
for (size_t i = 1; i < frames; ++i) {
EXPECT_LT(i32_from_p24(pary + 3*(i-1)), i32_from_p24(pary + 3*i));
}
}
TEST(audio_utils_primitives, clamp_to_int) {
static const float testArray[] = {
-NAN, -INFINITY,
-1.e20, -32768., 63.9,
-3.5, -3.4, -2.5, 2.4, -1.5, -1.4, -0.5, -0.2, 0., 0.2, 0.5, 0.8,
1.4, 1.5, 1.8, 2.4, 2.5, 2.6, 3.4, 3.5,
32767., 32768., 1.e20,
INFINITY, NAN };
for (size_t i = 0; i < ARRAY_SIZE(testArray); ++i) {
testClamp8(testArray[i]);
}
for (size_t i = 0; i < ARRAY_SIZE(testArray); ++i) {
testClamp16(testArray[i]);
}
for (size_t i = 0; i < ARRAY_SIZE(testArray); ++i) {
testClamp24(testArray[i]);
}
// used for ULP testing (tweaking the lsb of the float)
union {
int32_t i;
float f;
} val;
int32_t res;
// check clampq4_27_from_float()
val.f = 16.;
res = clampq4_27_from_float(val.f);
EXPECT_EQ(0x7fffffff, res);
val.i--;
res = clampq4_27_from_float(val.f);
EXPECT_LE(res, 0x7fffffff);
EXPECT_GE(res, 0x7fff0000);
val.f = -16.;
res = clampq4_27_from_float(val.f);
EXPECT_EQ((int32_t)0x80000000, res); // negative
val.i++;
res = clampq4_27_from_float(val.f);
EXPECT_GE(res, (int32_t)0x80000000); // negative
EXPECT_LE(res, (int32_t)0x80008000); // negative
// check u4_28_from_float and u4_12_from_float
uint32_t ures;
uint16_t ures16;
val.f = 16.;
ures = u4_28_from_float(val.f);
EXPECT_EQ(0xffffffff, ures);
ures16 = u4_12_from_float(val.f);
EXPECT_EQ(0xffff, ures16);
val.f = -1.;
ures = u4_28_from_float(val.f);
EXPECT_EQ((uint32_t)0, ures);
ures16 = u4_12_from_float(val.f);
EXPECT_EQ(0, ures16);
// check float_from_u4_28 and float_from_u4_12 (roundtrip)
for (uint32_t v = 0x100000; v <= 0xff000000; v += 0x100000) {
ures = u4_28_from_float(float_from_u4_28(v));
EXPECT_EQ(ures, v);
}
for (uint32_t v = 0; v <= 0xffff; ++v) { // uint32_t prevents overflow
ures16 = u4_12_from_float(float_from_u4_12(v));
EXPECT_EQ(ures16, v);
}
// check infinity
EXPECT_EQ(0, clamp8_from_float(-INFINITY));
EXPECT_EQ(255, clamp8_from_float(INFINITY));
}
TEST(audio_utils_primitives, memcpy) {
// test round-trip.
int16_t *i16ref = new int16_t[65536];
int16_t *i16ary = new int16_t[65536];
int32_t *i32ary = new int32_t[65536];
float *fary = new float[65536];
uint8_t *pary = new uint8_t[65536*3];
for (size_t i = 0; i < 65536; ++i) {
i16ref[i] = i16ary[i] = i - 32768;
}
// do round-trip testing i16 and float
memcpy_to_float_from_i16(fary, i16ary, 65536);
memset(i16ary, 0, 65536 * sizeof(i16ary[0]));
checkMonotone(fary, 65536);
memcpy_to_i16_from_float(i16ary, fary, 65536);
memset(fary, 0, 65536 * sizeof(fary[0]));
checkMonotone(i16ary, 65536);
// TODO make a template case for the following?
// do round-trip testing p24 to i16 and float
memcpy_to_p24_from_i16(pary, i16ary, 65536);
memset(i16ary, 0, 65536 * sizeof(i16ary[0]));
// check an intermediate format at a position(???)
#if 0
printf("pary[%d].0 = %u pary[%d].1 = %u pary[%d].2 = %u\n",
1025, (unsigned) pary[1025*3],
1025, (unsigned) pary[1025*3+1],
1025, (unsigned) pary[1025*3+2]
);
#endif
memcpy_to_float_from_p24(fary, pary, 65536);
memset(pary, 0, 65536 * 3 * sizeof(pary[0]));
checkMonotone(fary, 65536);
memcpy_to_p24_from_float(pary, fary, 65536);
memset(fary, 0, 65536 * sizeof(fary[0]));
memcpy_to_i16_from_p24(i16ary, pary, 65536);
memset(pary, 0, 65536 * 3 * sizeof(pary[0]));
checkMonotone(i16ary, 65536);
// do round-trip testing q8_23 to i16 and float
memcpy_to_q8_23_from_i16(i32ary, i16ary, 65536);
memset(i16ary, 0, 65536 * sizeof(i16ary[0]));
checkMonotone(i32ary, 65536);
memcpy_to_float_from_q8_23(fary, i32ary, 65536);
memset(i32ary, 0, 65536 * sizeof(i32ary[0]));
checkMonotone(fary, 65536);
memcpy_to_q8_23_from_float_with_clamp(i32ary, fary, 65536);
memset(fary, 0, 65536 * sizeof(fary[0]));
checkMonotone(i32ary, 65536);
memcpy_to_i16_from_q8_23(i16ary, i32ary, 65536);
memset(i32ary, 0, 65536 * sizeof(i32ary[0]));
checkMonotone(i16ary, 65536);
// do round-trip testing i32 to i16 and float
memcpy_to_i32_from_i16(i32ary, i16ary, 65536);
memset(i16ary, 0, 65536 * sizeof(i16ary[0]));
checkMonotone(i32ary, 65536);
memcpy_to_float_from_i32(fary, i32ary, 65536);
memset(i32ary, 0, 65536 * sizeof(i32ary[0]));
checkMonotone(fary, 65536);
memcpy_to_i32_from_float(i32ary, fary, 65536);
memset(fary, 0, 65536 * sizeof(fary[0]));
checkMonotone(i32ary, 65536);
memcpy_to_i16_from_i32(i16ary, i32ary, 65536);
memset(i32ary, 0, 65536 * sizeof(i32ary[0]));
checkMonotone(i16ary, 65536);
// do round-trip test i16 -> p24 -> i32 -> p24 -> q8_23 -> p24 -> i16
memcpy_to_p24_from_i16(pary, i16ary, 65536);
memset(i16ary, 0, 65536 * sizeof(i16ary[0]));
checkMonotonep24(pary, 65536 * 3);
memcpy_to_i32_from_p24(i32ary, pary, 65536);
memset(pary, 0, 65536 * 3 * sizeof(pary[0]));
checkMonotone(i32ary, 65536);
memcpy_to_p24_from_i32(pary, i32ary, 65536);
memset(i32ary, 0, 65536 * sizeof(i32ary[0]));
checkMonotonep24(pary, 65536 * 3);
memcpy_to_q8_23_from_p24(i32ary, pary, 65536);
memset(pary, 0, 65536 * 3 * sizeof(pary[0]));
checkMonotone(i32ary, 65536);
memcpy_to_p24_from_q8_23(pary, i32ary, 65536);
memset(i32ary, 0, 65536 * sizeof(i32ary[0]));
checkMonotonep24(pary, 65536 * 3);
memcpy_to_i16_from_p24(i16ary, pary, 65536);
memset(pary, 0, 65536 * 3 * sizeof(pary[0]));
checkMonotone(i16ary, 65536);
// do partial round-trip testing q4_27 to i16 and float
memcpy_to_float_from_i16(fary, i16ary, 65536);
//memset(i16ary, 0, 65536 * sizeof(i16ary[0])); // not cleared: we don't do full roundtrip
memcpy_to_q4_27_from_float(i32ary, fary, 65536);
memset(fary, 0, 65536 * sizeof(fary[0]));
checkMonotone(i32ary, 65536);
memcpy_to_float_from_q4_27(fary, i32ary, 65536);
memset(i32ary, 0, 65536 * sizeof(i32ary[0]));
checkMonotone(fary, 65536);
// at the end, our i16ary must be the same. (Monotone should be equivalent to this)
EXPECT_EQ(0, memcmp(i16ary, i16ref, 65536*sizeof(i16ary[0])));
// test round-trip for u8 and float.
uint8_t *u8ref = new uint8_t[256];
uint8_t *u8ary = new uint8_t[256];
for (unsigned i = 0; i < 256; ++i) {
u8ref[i] = i;
}
memcpy_to_float_from_u8(fary, u8ref, 256);
memcpy_to_u8_from_float(u8ary, fary, 256);
EXPECT_EQ(0, memcmp(u8ary, u8ref, 256 * sizeof(u8ary[0])));
delete[] u8ref;
delete[] u8ary;
delete[] i16ref;
delete[] i16ary;
delete[] i32ary;
delete[] fary;
delete[] pary;
}
template<typename T>
void checkMonotoneOrZero(const T *ary, size_t size)
{
T least = 0;
for (size_t i = 1; i < size; ++i) {
if (ary[i]) {
EXPECT_LT(least, ary[i]);
least = ary[i];
}
}
}
TEST(audio_utils_primitives, memcpy_by_channel_mask) {
uint32_t dst_mask;
uint32_t src_mask;
uint16_t *u16ref = new uint16_t[65536];
uint16_t *u16ary = new uint16_t[65536];
for (size_t i = 0; i < 65536; ++i) {
u16ref[i] = i;
}
// Test when src mask is 0. Everything copied is zero.
src_mask = 0;
dst_mask = 0x8d;
memset(u16ary, 0x99, 65536 * sizeof(u16ref[0]));
memcpy_by_channel_mask(u16ary, dst_mask, u16ref, src_mask, sizeof(u16ref[0]),
65536 / popcount(dst_mask));
EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530));
// Test when dst_mask is 0. Nothing should be copied.
src_mask = 0;
dst_mask = 0;
memset(u16ary, 0, 65536 * sizeof(u16ref[0]));
memcpy_by_channel_mask(u16ary, dst_mask, u16ref, src_mask, sizeof(u16ref[0]),
65536);
EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530));
// Test when masks are the same. One to one copy.
src_mask = dst_mask = 0x8d;
memset(u16ary, 0x99, 65536 * sizeof(u16ref[0]));
memcpy_by_channel_mask(u16ary, dst_mask, u16ref, src_mask, sizeof(u16ref[0]), 555);
EXPECT_EQ(0, memcmp(u16ary, u16ref, 555 * sizeof(u16ref[0]) * popcount(dst_mask)));
// Test with a gap in source:
// Input 3 samples, output 4 samples, one zero inserted.
src_mask = 0x8c;
dst_mask = 0x8d;
memset(u16ary, 0x9, 65536 * sizeof(u16ary[0]));
memcpy_by_channel_mask(u16ary, dst_mask, u16ref, src_mask, sizeof(u16ref[0]),
65536 / popcount(dst_mask));
checkMonotoneOrZero(u16ary, 65536);
EXPECT_EQ((size_t)(65536 * 3 / 4 - 1), nonZeroMono16((int16_t*)u16ary, 65536));
// Test with a gap in destination:
// Input 4 samples, output 3 samples, one deleted
src_mask = 0x8d;
dst_mask = 0x8c;
memset(u16ary, 0x9, 65536 * sizeof(u16ary[0]));
memcpy_by_channel_mask(u16ary, dst_mask, u16ref, src_mask, sizeof(u16ref[0]),
65536 / popcount(src_mask));
checkMonotone(u16ary, 65536 * 3 / 4);
delete[] u16ref;
delete[] u16ary;
}
void memcpy_by_channel_mask2(void *dst, uint32_t dst_mask,
const void *src, uint32_t src_mask, size_t sample_size, size_t count)
{
int8_t idxary[32];
uint32_t src_channels = popcount(src_mask);
uint32_t dst_channels =
memcpy_by_index_array_initialization(idxary, 32, dst_mask, src_mask);
memcpy_by_index_array(dst, dst_channels, src, src_channels, idxary, sample_size, count);
}
// a modified version of the memcpy_by_channel_mask test
// but using 24 bit type and memcpy_by_index_array()
TEST(audio_utils_primitives, memcpy_by_index_array) {
uint32_t dst_mask;
uint32_t src_mask;
typedef struct {uint8_t c[3];} __attribute__((__packed__)) uint8x3_t;
uint8x3_t *u24ref = new uint8x3_t[65536];
uint8x3_t *u24ary = new uint8x3_t[65536];
uint16_t *u16ref = new uint16_t[65536];
uint16_t *u16ary = new uint16_t[65536];
EXPECT_EQ((size_t)3, sizeof(uint8x3_t)); // 3 bytes per struct
// tests prepare_index_array_from_masks()
EXPECT_EQ((size_t)4, memcpy_by_index_array_initialization(NULL, 0, 0x8d, 0x8c));
EXPECT_EQ((size_t)3, memcpy_by_index_array_initialization(NULL, 0, 0x8c, 0x8d));
for (size_t i = 0; i < 65536; ++i) {
u16ref[i] = i;
}
memcpy_to_p24_from_i16((uint8_t*)u24ref, (int16_t*)u16ref, 65536);
// Test when src mask is 0. Everything copied is zero.
src_mask = 0;
dst_mask = 0x8d;
memset(u24ary, 0x99, 65536 * sizeof(u24ary[0]));
memcpy_by_channel_mask2(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
65536 / popcount(dst_mask));
memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530));
// Test when dst_mask is 0. Nothing should be copied.
src_mask = 0;
dst_mask = 0;
memset(u24ary, 0, 65536 * sizeof(u24ary[0]));
memcpy_by_channel_mask2(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
65536);
memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530));
// Test when masks are the same. One to one copy.
src_mask = dst_mask = 0x8d;
memset(u24ary, 0x99, 65536 * sizeof(u24ary[0]));
memcpy_by_channel_mask2(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 555);
EXPECT_EQ(0, memcmp(u24ary, u24ref, 555 * sizeof(u24ref[0]) * popcount(dst_mask)));
// Test with a gap in source:
// Input 3 samples, output 4 samples, one zero inserted.
src_mask = 0x8c;
dst_mask = 0x8d;
memset(u24ary, 0x9, 65536 * sizeof(u24ary[0]));
memcpy_by_channel_mask2(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
65536 / popcount(dst_mask));
memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
checkMonotoneOrZero(u16ary, 65536);
EXPECT_EQ((size_t)(65536 * 3 / 4 - 1), nonZeroMono16((int16_t*)u16ary, 65536));
// Test with a gap in destination:
// Input 4 samples, output 3 samples, one deleted
src_mask = 0x8d;
dst_mask = 0x8c;
memset(u24ary, 0x9, 65536 * sizeof(u24ary[0]));
memcpy_by_channel_mask2(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
65536 / popcount(src_mask));
memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
checkMonotone(u16ary, 65536 * 3 / 4);
delete[] u16ref;
delete[] u16ary;
delete[] u24ref;
delete[] u24ary;
}
void memcpy_by_channel_mask_dst_index(void *dst, uint32_t dst_mask,
const void *src, uint32_t src_mask, size_t sample_size, size_t count)
{
int8_t idxary[32];
uint32_t src_channels = popcount(src_mask);
uint32_t dst_channels =
memcpy_by_index_array_initialization_dst_index(idxary, 32, dst_mask, src_mask);
memcpy_by_index_array(dst, dst_channels, src, src_channels, idxary, sample_size, count);
}
// a modified version of the memcpy_by_channel_mask test
// but using 24 bit type and memcpy_by_index_array()
TEST(audio_utils_primitives, memcpy_by_index_array_dst_index) {
uint32_t dst_mask;
uint32_t src_mask;
typedef struct {uint8_t c[3];} __attribute__((__packed__)) uint8x3_t;
uint8x3_t *u24ref = new uint8x3_t[65536];
uint8x3_t *u24ary = new uint8x3_t[65536];
uint16_t *u16ref = new uint16_t[65536];
uint16_t *u16ary = new uint16_t[65536];
EXPECT_EQ((size_t)3, sizeof(uint8x3_t)); // 3 bytes per struct
// tests prepare_index_array_from_masks()
EXPECT_EQ((size_t)4, memcpy_by_index_array_initialization_dst_index(NULL, 0, 0x8d, 0x8c));
EXPECT_EQ((size_t)3, memcpy_by_index_array_initialization_dst_index(NULL, 0, 0x8c, 0x8d));
for (size_t i = 0; i < 65536; ++i) {
u16ref[i] = i;
}
memcpy_to_p24_from_i16((uint8_t*)u24ref, (int16_t*)u16ref, 65536);
// Test when src mask is 0. Everything copied is zero.
src_mask = 0;
dst_mask = 0x8d;
memset(u24ary, 0x99, 65536 * sizeof(u24ary[0]));
memcpy_by_channel_mask_dst_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
65536 / popcount(dst_mask));
memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530));
// Test when dst_mask is 0. Nothing should be copied.
src_mask = 0;
dst_mask = 0;
memset(u24ary, 0, 65536 * sizeof(u24ary[0]));
memcpy_by_channel_mask_dst_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
65536);
memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530));
// Test when dst mask equals source count size. One to one copy.
src_mask = 0x8d;
dst_mask = 0x0f;
memset(u24ary, 0x99, 65536 * sizeof(u24ary[0]));
memcpy_by_channel_mask_dst_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 555);
EXPECT_EQ(0, memcmp(u24ary, u24ref, 555 * sizeof(u24ref[0]) * popcount(dst_mask)));
// Test with a gap in source:
// Input 3 samples, output 4 samples, one zero inserted.
src_mask = 0x8c;
dst_mask = 0x0f;
memset(u24ary, 0x9, 65536 * sizeof(u24ary[0]));
memcpy_by_channel_mask_dst_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
65536 / popcount(dst_mask));
memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
checkMonotoneOrZero(u16ary, 65536);
EXPECT_EQ((size_t)(65536 * 3 / 4 - 1), nonZeroMono16((int16_t*)u16ary, 65536));
// Test with a gap in destination:
// Input 4 samples, output 3 samples, one deleted
src_mask = 0x8d;
dst_mask = 0x07;
memset(u24ary, 0x9, 65536 * sizeof(u24ary[0]));
memcpy_by_channel_mask_dst_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
65536 / popcount(src_mask));
memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
checkMonotone(u16ary, 65536 * 3 / 4);
delete[] u16ref;
delete[] u16ary;
delete[] u24ref;
delete[] u24ary;
}
void memcpy_by_channel_mask_src_index(void *dst, uint32_t dst_mask,
const void *src, uint32_t src_mask, size_t sample_size, size_t count)
{
int8_t idxary[32];
uint32_t src_channels = popcount(src_mask);
uint32_t dst_channels =
memcpy_by_index_array_initialization_src_index(idxary, 32, dst_mask, src_mask);
memcpy_by_index_array(dst, dst_channels, src, src_channels, idxary, sample_size, count);
}
// a modified version of the memcpy_by_channel_mask test
// but using 24 bit type and memcpy_by_index_array()
TEST(audio_utils_primitives, memcpy_by_index_array_src_index) {
uint32_t dst_mask;
uint32_t src_mask;
typedef struct {uint8_t c[3];} __attribute__((__packed__)) uint8x3_t;
uint8x3_t *u24ref = new uint8x3_t[65536];
uint8x3_t *u24ary = new uint8x3_t[65536];
uint16_t *u16ref = new uint16_t[65536];
uint16_t *u16ary = new uint16_t[65536];
EXPECT_EQ((size_t)3, sizeof(uint8x3_t)); // 3 bytes per struct
// tests prepare_index_array_from_masks()
EXPECT_EQ((size_t)4, memcpy_by_index_array_initialization_src_index(NULL, 0, 0x8d, 0x8c));
EXPECT_EQ((size_t)3, memcpy_by_index_array_initialization_src_index(NULL, 0, 0x8c, 0x8d));
for (size_t i = 0; i < 65536; ++i) {
u16ref[i] = i;
}
memcpy_to_p24_from_i16((uint8_t*)u24ref, (int16_t*)u16ref, 65536);
// Test when src mask is 0. Everything copied is zero.
src_mask = 0;
dst_mask = 0x8d;
memset(u24ary, 0x99, 65536 * sizeof(u24ary[0]));
memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
65536 / popcount(dst_mask));
memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530));
// Test when dst_mask is 0. Nothing should be copied.
src_mask = 0;
dst_mask = 0;
memset(u24ary, 0, 65536 * sizeof(u24ary[0]));
memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
65536);
memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
EXPECT_EQ((size_t)0, nonZeroMono16((int16_t*)u16ary, 65530));
// Test when source mask must copy to dst mask. One to one copy.
src_mask = 0xf;
dst_mask = 0xf;
memset(u24ary, 0x99, 65536 * sizeof(u24ary[0]));
memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 555);
EXPECT_EQ(0, memcmp(u24ary, u24ref, 555 * sizeof(u24ref[0]) * popcount(dst_mask)));
// Test when source mask must copy to dst mask. One to one copy.
src_mask = 0xf;
dst_mask = 0x8d;
memset(u24ary, 0x99, 65536 * sizeof(u24ary[0]));
memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]), 555);
EXPECT_EQ(0, memcmp(u24ary, u24ref, 555 * sizeof(u24ref[0]) * popcount(dst_mask)));
// Test with a gap in source:
// Input 3 samples, output 4 samples, one zero inserted.
src_mask = 0x07;
dst_mask = 0x8d;
memset(u24ary, 0x9, 65536 * sizeof(u24ary[0]));
memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
65536 / popcount(dst_mask));
memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
checkMonotoneOrZero(u16ary, 65536);
EXPECT_EQ((size_t)(65536 * 3 / 4 - 1), nonZeroMono16((int16_t*)u16ary, 65536));
// Test with a gap in destination:
// Input 4 samples, output 3 samples, one deleted
src_mask = 0x0f;
dst_mask = 0x8c;
memset(u24ary, 0x9, 65536 * sizeof(u24ary[0]));
memcpy_by_channel_mask_src_index(u24ary, dst_mask, u24ref, src_mask, sizeof(u24ref[0]),
65536 / popcount(src_mask));
memcpy_to_i16_from_p24((int16_t*)u16ary, (uint8_t*)u24ary, 65536);
checkMonotone(u16ary, 65536 * 3 / 4);
delete[] u16ref;
delete[] u16ary;
delete[] u24ref;
delete[] u24ary;
}
TEST(audio_utils_channels, adjust_channels) {
uint16_t *u16ref = new uint16_t[65536];
uint16_t *u16expand = new uint16_t[65536*2];
uint16_t *u16ary = new uint16_t[65536];
// reference buffer always increases
for (size_t i = 0; i < 65536; ++i) {
u16ref[i] = i;
}
// expand channels from stereo to quad.
adjust_channels(u16ref /*in_buff*/, 2 /*in_channels*/,
u16expand /*out_buff*/, 4 /*out_channels*/,
sizeof(u16ref[0]) /*sample_size_in_bytes*/,
sizeof(u16ref[0])*65536 /*num_in_bytes*/);
// expanded buffer must increase (or be zero)
checkMonotoneOrZero(u16expand, 65536*2);
// contract channels back to stereo.
adjust_channels(u16expand /*in_buff*/, 4 /*in_channels*/,
u16ary /*out_buff*/, 2 /*out_channels*/,
sizeof(u16expand[0]) /*sample_size_in_bytes*/,
sizeof(u16expand[0])*65536*2 /*num_in_bytes*/);
// must be identical to original.
EXPECT_EQ(0, memcmp(u16ary, u16ref, sizeof(u16ref[0])*65536));
delete[] u16ref;
delete[] u16expand;
delete[] u16ary;
}

View file

@ -0,0 +1,81 @@
/*
* Copyright 2017 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.
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "audio_utils_errorlog_tests"
#include <audio_utils/SimpleLog.h>
#include <gtest/gtest.h>
#include <iostream>
#include <log/log.h>
using namespace android;
static size_t countNewLines(const std::string &s) {
return std::count(s.begin(), s.end(), '\n');
}
TEST(audio_utils_simplelog, basic) {
auto slog = std::make_unique<SimpleLog>();
const int64_t oneSecond = 1000000000;
EXPECT_EQ((size_t)0, countNewLines(slog->dumpToString()));
const int nine = 9;
slog->log("Hello %d", nine);
slog->log("World");
// two lines (no header)
EXPECT_EQ((size_t)2, countNewLines(slog->dumpToString()));
// another two lines (this is out of time order, but the log doesn't care)
slog->log(oneSecond /* nowNs */, "Hello World %d", 10);
slog->log(oneSecond * 2 /* nowNs */, "%s", "Goodbye");
EXPECT_EQ((size_t)4, countNewLines(slog->dumpToString()));
// truncate on lines
EXPECT_EQ((size_t)1, countNewLines(slog->dumpToString("" /* prefix */, 1 /* lines */)));
// truncate on time
EXPECT_EQ((size_t)4, countNewLines(
slog->dumpToString("" /* prefix */, 0 /* lines */, oneSecond /* limitNs */)));
// truncate on time (more)
EXPECT_EQ((size_t)3, countNewLines(
slog->dumpToString("" /* prefix */, 0 /* lines */, oneSecond * 2 /* limitNs */)));
// truncate on time (more)
EXPECT_EQ((size_t)2, countNewLines(
slog->dumpToString("" /* prefix */, 0 /* lines */, oneSecond * 2 + 1 /* limitNs */)));
std::cout << slog->dumpToString() << std::flush;
slog->dump(0 /* fd (stdout) */, " "); // add a prefix
// The output below depends on the local time zone and current time.
// The indentation below is exact, check alignment.
/*
03-27 14:47:43.567 Hello 9
03-27 14:47:43.567 World
12-31 16:00:01.000 Hello World 10
12-31 16:00:02.000 Goodbye
03-27 14:47:43.567 Hello 9
03-27 14:47:43.567 World
12-31 16:00:01.000 Hello World 10
12-31 16:00:02.000 Goodbye
*/
}