blob: 091d8decfaec65f792fbc21ffcdb6853825b00c7 [file] [log] [blame]
// Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <gtest/gtest.h>
#include <stdio.h>
extern "C" {
#include "cras_audio_area.h"
#include "cras_audio_format.h"
}
static const int8_t stereo[CRAS_CH_MAX] = {
0, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
};
static const int8_t mono[CRAS_CH_MAX] = {
-1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1,
};
static const int8_t kb_mic[CRAS_CH_MAX] = {
0, 1, -1, -1, 2, -1, -1, -1, -1, -1, -1,
};
static uint16_t buf1[32];
static uint16_t buf2[32];
struct cras_audio_area* a1;
struct cras_audio_area* a2;
namespace {
TEST(AudioArea, CopyAudioArea) {
struct cras_audio_format fmt;
int i;
fmt.num_channels = 2;
fmt.format = SND_PCM_FORMAT_S16_LE;
for (i = 0; i < CRAS_CH_MAX; i++)
fmt.channel_layout[i] = stereo[i];
a1 = cras_audio_area_create(2);
a2 = cras_audio_area_create(2);
cras_audio_area_config_channels(a1, &fmt);
cras_audio_area_config_channels(a2, &fmt);
cras_audio_area_config_buf_pointers(a1, &fmt, (uint8_t*)buf1);
cras_audio_area_config_buf_pointers(a2, &fmt, (uint8_t*)buf2);
a1->frames = 16;
a2->frames = 16;
memset(buf1, 0, 32 * 2);
for (i = 0; i < 32; i++)
buf2[i] = rand();
cras_audio_area_copy(a1, 0, &fmt, a2, 0, 1.0);
for (i = 0; i < 32; i++)
EXPECT_EQ(buf1[i], buf2[i]);
cras_audio_area_destroy(a1);
cras_audio_area_destroy(a2);
}
TEST(AudioArea, CopyAudioAreaWithGain) {
struct cras_audio_format fmt;
int i;
/* Check a gain of 10x can be applied. */
float gain_scaler = 10.0f;
fmt.num_channels = 2;
fmt.format = SND_PCM_FORMAT_S16_LE;
for (i = 0; i < CRAS_CH_MAX; i++)
fmt.channel_layout[i] = stereo[i];
a1 = cras_audio_area_create(2);
a2 = cras_audio_area_create(2);
cras_audio_area_config_channels(a1, &fmt);
cras_audio_area_config_channels(a2, &fmt);
cras_audio_area_config_buf_pointers(a1, &fmt, (uint8_t*)buf1);
cras_audio_area_config_buf_pointers(a2, &fmt, (uint8_t*)buf2);
a1->frames = 16;
a2->frames = 16;
memset(buf1, 0, 32 * 2);
/* Let src has some samples smaller than 32768/10 and some samples larger than
* 32768/10 to test clipping. */
for (i = 0; i < 16; i++)
buf2[i] = rand() % 3270;
for (i = 17; i < 32; i++)
buf2[i] = 3280 + rand() % 3200;
cras_audio_area_copy(a1, 0, &fmt, a2, 0, gain_scaler);
for (i = 0; i < 32; i++) {
int32_t expected_value = buf2[i] * gain_scaler;
if (expected_value > INT16_MAX)
expected_value = INT16_MAX;
EXPECT_EQ(buf1[i], expected_value);
}
cras_audio_area_destroy(a1);
cras_audio_area_destroy(a2);
}
TEST(AudioArea, CopyAudioAreaOffset) {
struct cras_audio_format fmt;
int i;
fmt.num_channels = 2;
fmt.format = SND_PCM_FORMAT_S16_LE;
for (i = 0; i < CRAS_CH_MAX; i++)
fmt.channel_layout[i] = stereo[i];
a1 = cras_audio_area_create(2);
a2 = cras_audio_area_create(2);
cras_audio_area_config_channels(a1, &fmt);
cras_audio_area_config_channels(a2, &fmt);
cras_audio_area_config_buf_pointers(a1, &fmt, (uint8_t*)buf1);
cras_audio_area_config_buf_pointers(a2, &fmt, (uint8_t*)buf2);
a1->frames = 16;
a2->frames = 14;
memset(buf1, 0, 32 * 2);
for (i = 0; i < 32; i++)
buf2[i] = rand();
cras_audio_area_copy(a1, 2, &fmt, a2, 0, 1.0);
EXPECT_EQ(buf1[0], 0);
EXPECT_EQ(buf1[1], 0);
EXPECT_EQ(buf1[2], 0);
EXPECT_EQ(buf1[3], 0);
for (i = 4; i < 32; i++)
EXPECT_EQ(buf1[i], buf2[i - 4]);
cras_audio_area_destroy(a1);
cras_audio_area_destroy(a2);
}
TEST(AudioArea, CopyAudioAreaOffsetLimit) {
struct cras_audio_format fmt;
int i;
fmt.num_channels = 2;
fmt.format = SND_PCM_FORMAT_S16_LE;
for (i = 0; i < CRAS_CH_MAX; i++)
fmt.channel_layout[i] = stereo[i];
a1 = cras_audio_area_create(2);
a2 = cras_audio_area_create(2);
cras_audio_area_config_channels(a1, &fmt);
cras_audio_area_config_channels(a2, &fmt);
cras_audio_area_config_buf_pointers(a1, &fmt, (uint8_t*)buf1);
cras_audio_area_config_buf_pointers(a2, &fmt, (uint8_t*)buf2);
a1->frames = 14;
a2->frames = 14;
memset(buf1, 0, 32 * 2);
for (i = 0; i < 32; i++)
buf2[i] = rand();
cras_audio_area_copy(a1, 2, &fmt, a2, 0, 1.0);
EXPECT_EQ(buf1[0], 0);
EXPECT_EQ(buf1[1], 0);
EXPECT_EQ(buf1[2], 0);
EXPECT_EQ(buf1[3], 0);
for (i = 4; i < 28; i++)
EXPECT_EQ(buf1[i], buf2[i - 4]);
EXPECT_EQ(buf1[28], 0);
EXPECT_EQ(buf1[29], 0);
EXPECT_EQ(buf1[30], 0);
EXPECT_EQ(buf1[31], 0);
cras_audio_area_destroy(a1);
cras_audio_area_destroy(a2);
}
TEST(AudioArea, CopyMonoToStereo) {
struct cras_audio_format dst_fmt;
struct cras_audio_format src_fmt;
int i;
dst_fmt.num_channels = 2;
dst_fmt.format = SND_PCM_FORMAT_S16_LE;
for (i = 0; i < CRAS_CH_MAX; i++)
dst_fmt.channel_layout[i] = stereo[i];
a1 = cras_audio_area_create(2);
a1->frames = 16;
cras_audio_area_config_channels(a1, &dst_fmt);
cras_audio_area_config_buf_pointers(a1, &dst_fmt, (uint8_t*)buf1);
src_fmt.num_channels = 1;
src_fmt.format = SND_PCM_FORMAT_S16_LE;
for (i = 0; i < CRAS_CH_MAX; i++)
src_fmt.channel_layout[i] = mono[i];
a2 = cras_audio_area_create(1);
a2->frames = 16;
cras_audio_area_config_channels(a2, &src_fmt);
cras_audio_area_config_buf_pointers(a2, &src_fmt, (uint8_t*)buf2);
memset(buf1, 0, 32 * 2);
for (i = 0; i < 32; i++)
buf2[i] = rand();
cras_audio_area_copy(a1, 0, &dst_fmt, a2, 0, 1.0);
for (i = 0; i < 16; i++) {
EXPECT_EQ(buf1[i * 2], buf2[i]);
EXPECT_EQ(buf1[i * 2 + 1], buf2[i]);
}
cras_audio_area_destroy(a1);
cras_audio_area_destroy(a2);
}
TEST(AudioArea, CopyStereoToMono) {
struct cras_audio_format fmt;
int i;
fmt.num_channels = 1;
fmt.format = SND_PCM_FORMAT_S16_LE;
for (i = 0; i < CRAS_CH_MAX; i++)
fmt.channel_layout[i] = mono[i];
a1 = cras_audio_area_create(1);
a1->frames = 16;
cras_audio_area_config_channels(a1, &fmt);
cras_audio_area_config_buf_pointers(a1, &fmt, (uint8_t*)buf1);
fmt.num_channels = 2;
for (i = 0; i < CRAS_CH_MAX; i++)
fmt.channel_layout[i] = stereo[i];
a2 = cras_audio_area_create(2);
a2->frames = 16;
cras_audio_area_config_channels(a2, &fmt);
cras_audio_area_config_buf_pointers(a2, &fmt, (uint8_t*)buf2);
memset(buf1, 0, 32 * 2);
for (i = 0; i < 32; i++)
buf2[i] = rand() % 10000;
cras_audio_area_copy(a1, 0, &fmt, a2, 0, 1.0);
for (i = 0; i < 16; i++)
EXPECT_EQ(buf1[i], buf2[i * 2] + buf2[i * 2 + 1]);
cras_audio_area_destroy(a1);
cras_audio_area_destroy(a2);
}
TEST(AudioArea, KeyboardMicCopyStereo) {
struct cras_audio_format fmt;
int i;
fmt.num_channels = 3;
fmt.format = SND_PCM_FORMAT_S16_LE;
for (i = 0; i < CRAS_CH_MAX; i++)
fmt.channel_layout[i] = kb_mic[i];
a1 = cras_audio_area_create(3);
a1->frames = 10;
cras_audio_area_config_channels(a1, &fmt);
cras_audio_area_config_buf_pointers(a1, &fmt, (uint8_t*)buf1);
fmt.num_channels = 2;
for (i = 0; i < CRAS_CH_MAX; i++)
fmt.channel_layout[i] = stereo[i];
a2 = cras_audio_area_create(2);
a2->frames = 10;
cras_audio_area_config_channels(a2, &fmt);
cras_audio_area_config_buf_pointers(a2, &fmt, (uint8_t*)buf2);
memset(buf1, 0, 32 * 2);
for (i = 0; i < 32; i++)
buf2[i] = rand();
cras_audio_area_copy(a1, 0, &fmt, a2, 0, 1.0);
for (i = 0; i < 10; i++) {
EXPECT_EQ(buf1[i * 3], buf2[i * 2]);
EXPECT_EQ(buf1[i * 3 + 1], buf2[i * 2 + 1]);
EXPECT_EQ(buf1[i * 3 + 2], 0);
}
cras_audio_area_destroy(a1);
cras_audio_area_destroy(a2);
}
TEST(AudioArea, KeyboardMicCopyFrontCenter) {
struct cras_audio_format dst_fmt;
struct cras_audio_format src_fmt;
int i;
dst_fmt.num_channels = 3;
dst_fmt.format = SND_PCM_FORMAT_S16_LE;
for (i = 0; i < CRAS_CH_MAX; i++)
dst_fmt.channel_layout[i] = kb_mic[i];
a1 = cras_audio_area_create(3);
a1->frames = 10;
cras_audio_area_config_channels(a1, &dst_fmt);
cras_audio_area_config_buf_pointers(a1, &dst_fmt, (uint8_t*)buf1);
/* Test 2 channels area with only front center in layout. */
src_fmt.num_channels = 2;
src_fmt.format = SND_PCM_FORMAT_S16_LE;
for (i = 0; i < CRAS_CH_MAX; i++)
src_fmt.channel_layout[i] = -1;
src_fmt.channel_layout[CRAS_CH_FC] = 0;
a2 = cras_audio_area_create(2);
a2->frames = 10;
cras_audio_area_config_channels(a2, &src_fmt);
cras_audio_area_config_buf_pointers(a2, &src_fmt, (uint8_t*)buf2);
memset(buf1, 0, 32 * 2);
for (i = 0; i < 32; i++)
buf2[i] = rand();
cras_audio_area_copy(a1, 0, &dst_fmt, a2, 0, 1.0);
for (i = 0; i < 10; i++) {
EXPECT_EQ(buf1[i * 3], 0);
EXPECT_EQ(buf1[i * 3 + 1], 0);
EXPECT_EQ(buf1[i * 3 + 2], buf2[i * 2]);
}
cras_audio_area_destroy(a1);
cras_audio_area_destroy(a2);
}
} // namespace
extern "C" {
void cras_mix_add_scale_stride(snd_pcm_format_t fmt,
uint8_t* dst,
uint8_t* src,
unsigned int count,
unsigned int dst_stride,
unsigned int src_stride,
float scaler) {
unsigned int i;
for (i = 0; i < count; i++) {
int32_t sum;
sum = *(int16_t*)dst + *(int16_t*)src * scaler;
if (sum > INT16_MAX)
sum = INT16_MAX;
else if (sum < INT16_MIN)
sum = INT16_MIN;
*(int16_t*)dst = sum;
dst += dst_stride;
src += src_stride;
}
}
} // extern "C"
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}