blob: d50b685b055360670127d8a00a87ebed8b02a17e [file] [log] [blame]
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "audio/utility/audio_frame_operations.h"
#include "rtc_base/checks.h"
#include "test/gtest.h"
namespace webrtc {
namespace {
class AudioFrameOperationsTest : public ::testing::Test {
protected:
AudioFrameOperationsTest() = default;
// Set typical values.
AudioFrame frame_{/*sample_rate=*/32000, /*num_channels*/ 2};
};
class AudioFrameOperationsDeathTest : public AudioFrameOperationsTest {};
void SetFrameData(int16_t ch1,
int16_t ch2,
int16_t ch3,
int16_t ch4,
AudioFrame* frame) {
rtc::ArrayView<int16_t> frame_data =
frame->mutable_data(frame->samples_per_channel_, 4);
for (size_t i = 0; i < frame->samples_per_channel_ * 4; i += 4) {
frame_data[i] = ch1;
frame_data[i + 1] = ch2;
frame_data[i + 2] = ch3;
frame_data[i + 3] = ch4;
}
}
void SetFrameData(int16_t left, int16_t right, AudioFrame* frame) {
rtc::ArrayView<int16_t> frame_data =
frame->mutable_data(frame->samples_per_channel_, 2);
for (size_t i = 0; i < frame->samples_per_channel_ * 2; i += 2) {
frame_data[i] = left;
frame_data[i + 1] = right;
}
}
void SetFrameData(int16_t data, AudioFrame* frame) {
rtc::ArrayView<int16_t> frame_data =
frame->mutable_data(frame->samples_per_channel_, 1);
for (size_t i = 0; i < frame->samples_per_channel_ * frame->num_channels_;
i++) {
frame_data[i] = data;
}
}
void VerifyFramesAreEqual(const AudioFrame& frame1, const AudioFrame& frame2) {
ASSERT_EQ(frame1.num_channels_, frame2.num_channels_);
ASSERT_EQ(frame1.samples_per_channel_, frame2.samples_per_channel_);
EXPECT_EQ(frame1.muted(), frame2.muted());
const int16_t* frame1_data = frame1.data();
const int16_t* frame2_data = frame2.data();
// TODO(tommi): Use sample_count() or data_view().
for (size_t i = 0; i < frame1.samples_per_channel_ * frame1.num_channels_;
i++) {
EXPECT_EQ(frame1_data[i], frame2_data[i]);
if (frame1_data[i] != frame2_data[i])
break; // To avoid spamming the log.
}
}
void InitFrame(AudioFrame* frame,
size_t channels,
size_t samples_per_channel,
int16_t left_data,
int16_t right_data) {
RTC_DCHECK_GE(2, channels);
RTC_DCHECK_GE(AudioFrame::kMaxDataSizeSamples,
samples_per_channel * channels);
frame->samples_per_channel_ = samples_per_channel;
if (channels == 2) {
SetFrameData(left_data, right_data, frame);
} else if (channels == 1) {
SetFrameData(left_data, frame);
}
ASSERT_EQ(frame->num_channels_, channels);
}
int16_t GetChannelData(const AudioFrame& frame, size_t channel, size_t index) {
RTC_DCHECK_LT(channel, frame.num_channels_);
RTC_DCHECK_LT(index, frame.samples_per_channel_);
return frame.data()[index * frame.num_channels_ + channel];
}
void VerifyFrameDataBounds(const AudioFrame& frame,
size_t channel,
int16_t max,
int16_t min) {
for (size_t i = 0; i < frame.samples_per_channel_; ++i) {
int16_t s = GetChannelData(frame, channel, i);
EXPECT_LE(min, s);
EXPECT_GE(max, s);
}
}
#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
TEST_F(AudioFrameOperationsDeathTest, MonoToStereoFailsWithBadParameters) {
EXPECT_DEATH(AudioFrameOperations::UpmixChannels(2, &frame_), "");
frame_.samples_per_channel_ = AudioFrame::kMaxDataSizeSamples;
frame_.num_channels_ = 1;
EXPECT_DEATH(AudioFrameOperations::UpmixChannels(2, &frame_), "");
}
#endif
TEST_F(AudioFrameOperationsTest, MonoToStereoSucceeds) {
SetFrameData(1, &frame_);
AudioFrameOperations::UpmixChannels(2, &frame_);
EXPECT_EQ(2u, frame_.num_channels_);
AudioFrame stereo_frame;
stereo_frame.samples_per_channel_ = 320;
SetFrameData(1, 1, &stereo_frame);
VerifyFramesAreEqual(stereo_frame, frame_);
}
TEST_F(AudioFrameOperationsTest, MonoToStereoMuted) {
frame_.num_channels_ = 1;
ASSERT_TRUE(frame_.muted());
AudioFrameOperations::UpmixChannels(2, &frame_);
EXPECT_EQ(2u, frame_.num_channels_);
EXPECT_TRUE(frame_.muted());
}
#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
TEST_F(AudioFrameOperationsDeathTest, StereoToMonoFailsWithBadParameters) {
frame_.num_channels_ = 1;
EXPECT_DEATH(AudioFrameOperations::DownmixChannels(1, &frame_), "");
}
#endif
TEST_F(AudioFrameOperationsTest, StereoToMonoSucceeds) {
SetFrameData(4, 2, &frame_);
AudioFrameOperations::DownmixChannels(1, &frame_);
EXPECT_EQ(1u, frame_.num_channels_);
AudioFrame mono_frame;
mono_frame.samples_per_channel_ = 320;
SetFrameData(3, &mono_frame);
VerifyFramesAreEqual(mono_frame, frame_);
}
TEST_F(AudioFrameOperationsTest, StereoToMonoMuted) {
ASSERT_TRUE(frame_.muted());
AudioFrameOperations::DownmixChannels(1, &frame_);
EXPECT_EQ(1u, frame_.num_channels_);
EXPECT_TRUE(frame_.muted());
}
TEST_F(AudioFrameOperationsTest, StereoToMonoBufferSucceeds) {
AudioFrame target_frame;
SetFrameData(4, 2, &frame_);
AudioFrameOperations::DownmixChannels(
frame_.data_view(), 2, frame_.samples_per_channel_, 1,
target_frame.mutable_data(frame_.samples_per_channel_, 1));
AudioFrame mono_frame;
mono_frame.samples_per_channel_ = 320;
SetFrameData(3, &mono_frame);
VerifyFramesAreEqual(mono_frame, target_frame);
}
TEST_F(AudioFrameOperationsTest, StereoToMonoDoesNotWrapAround) {
SetFrameData(-32768, -32768, &frame_);
AudioFrameOperations::DownmixChannels(1, &frame_);
EXPECT_EQ(1u, frame_.num_channels_);
AudioFrame mono_frame;
mono_frame.samples_per_channel_ = 320;
SetFrameData(-32768, &mono_frame);
VerifyFramesAreEqual(mono_frame, frame_);
}
TEST_F(AudioFrameOperationsTest, QuadToMonoSucceeds) {
SetFrameData(4, 2, 6, 8, &frame_);
AudioFrameOperations::DownmixChannels(1, &frame_);
EXPECT_EQ(1u, frame_.num_channels_);
AudioFrame mono_frame;
mono_frame.samples_per_channel_ = 320;
SetFrameData(5, &mono_frame);
VerifyFramesAreEqual(mono_frame, frame_);
}
TEST_F(AudioFrameOperationsTest, QuadToMonoMuted) {
frame_.num_channels_ = 4;
ASSERT_TRUE(frame_.muted());
AudioFrameOperations::DownmixChannels(1, &frame_);
EXPECT_EQ(1u, frame_.num_channels_);
EXPECT_TRUE(frame_.muted());
}
TEST_F(AudioFrameOperationsTest, QuadToMonoBufferSucceeds) {
AudioFrame target_frame;
SetFrameData(4, 2, 6, 8, &frame_);
AudioFrameOperations::DownmixChannels(
frame_.data_view(), 4, frame_.samples_per_channel_, 1,
target_frame.mutable_data(frame_.samples_per_channel_, 1));
AudioFrame mono_frame;
mono_frame.samples_per_channel_ = 320;
SetFrameData(5, &mono_frame);
VerifyFramesAreEqual(mono_frame, target_frame);
}
TEST_F(AudioFrameOperationsTest, QuadToMonoDoesNotWrapAround) {
SetFrameData(-32768, -32768, -32768, -32768, &frame_);
AudioFrameOperations::DownmixChannels(1, &frame_);
EXPECT_EQ(1u, frame_.num_channels_);
AudioFrame mono_frame;
mono_frame.samples_per_channel_ = 320;
SetFrameData(-32768, &mono_frame);
VerifyFramesAreEqual(mono_frame, frame_);
}
TEST_F(AudioFrameOperationsTest, QuadToStereoFailsWithBadParameters) {
frame_.num_channels_ = 1;
EXPECT_EQ(-1, AudioFrameOperations::QuadToStereo(&frame_));
frame_.num_channels_ = 2;
EXPECT_EQ(-1, AudioFrameOperations::QuadToStereo(&frame_));
}
TEST_F(AudioFrameOperationsTest, QuadToStereoSucceeds) {
SetFrameData(4, 2, 6, 8, &frame_);
EXPECT_EQ(0, AudioFrameOperations::QuadToStereo(&frame_));
AudioFrame stereo_frame;
stereo_frame.samples_per_channel_ = 320;
SetFrameData(3, 7, &stereo_frame);
VerifyFramesAreEqual(stereo_frame, frame_);
}
TEST_F(AudioFrameOperationsTest, QuadToStereoMuted) {
frame_.num_channels_ = 4;
ASSERT_TRUE(frame_.muted());
EXPECT_EQ(0, AudioFrameOperations::QuadToStereo(&frame_));
EXPECT_TRUE(frame_.muted());
}
TEST_F(AudioFrameOperationsTest, QuadToStereoBufferSucceeds) {
AudioFrame target_frame;
SetFrameData(4, 2, 6, 8, &frame_);
AudioFrameOperations::QuadToStereo(
frame_.data_view(), frame_.samples_per_channel_,
target_frame.mutable_data(frame_.samples_per_channel_, 2));
AudioFrame stereo_frame;
stereo_frame.samples_per_channel_ = 320;
SetFrameData(3, 7, &stereo_frame);
VerifyFramesAreEqual(stereo_frame, target_frame);
}
TEST_F(AudioFrameOperationsTest, QuadToStereoDoesNotWrapAround) {
SetFrameData(-32768, -32768, -32768, -32768, &frame_);
EXPECT_EQ(0, AudioFrameOperations::QuadToStereo(&frame_));
AudioFrame stereo_frame;
stereo_frame.samples_per_channel_ = 320;
SetFrameData(-32768, -32768, &stereo_frame);
VerifyFramesAreEqual(stereo_frame, frame_);
}
TEST_F(AudioFrameOperationsTest, SwapStereoChannelsSucceedsOnStereo) {
SetFrameData(0, 1, &frame_);
AudioFrame swapped_frame;
swapped_frame.samples_per_channel_ = 320;
SetFrameData(1, 0, &swapped_frame);
AudioFrameOperations::SwapStereoChannels(&frame_);
VerifyFramesAreEqual(swapped_frame, frame_);
}
TEST_F(AudioFrameOperationsTest, SwapStereoChannelsMuted) {
ASSERT_TRUE(frame_.muted());
AudioFrameOperations::SwapStereoChannels(&frame_);
EXPECT_TRUE(frame_.muted());
}
TEST_F(AudioFrameOperationsTest, SwapStereoChannelsFailsOnMono) {
// Set data to "stereo", despite it being a mono frame.
SetFrameData(0, 1, &frame_);
frame_.num_channels_ = 1; // Reset to mono after SetFrameData().
AudioFrame orig_frame;
orig_frame.CopyFrom(frame_);
AudioFrameOperations::SwapStereoChannels(&frame_);
// Verify that no swap occurred.
VerifyFramesAreEqual(orig_frame, frame_);
}
TEST_F(AudioFrameOperationsTest, MuteDisabled) {
SetFrameData(1000, -1000, &frame_);
AudioFrameOperations::Mute(&frame_, false, false);
AudioFrame muted_frame;
muted_frame.samples_per_channel_ = 320;
SetFrameData(1000, -1000, &muted_frame);
VerifyFramesAreEqual(muted_frame, frame_);
}
TEST_F(AudioFrameOperationsTest, MuteEnabled) {
SetFrameData(1000, -1000, &frame_);
AudioFrameOperations::Mute(&frame_, true, true);
AudioFrame muted_frame;
muted_frame.samples_per_channel_ = frame_.samples_per_channel_;
muted_frame.num_channels_ = frame_.num_channels_;
ASSERT_TRUE(muted_frame.muted());
VerifyFramesAreEqual(muted_frame, frame_);
}
// Verify that *beginning* to mute works for short and long (>128) frames, mono
// and stereo. Beginning mute should yield a ramp down to zero.
TEST_F(AudioFrameOperationsTest, MuteBeginMonoLong) {
InitFrame(&frame_, 1, 228, 1000, -1000);
AudioFrameOperations::Mute(&frame_, false, true);
VerifyFrameDataBounds(frame_, 0, 1000, 0);
EXPECT_EQ(1000, GetChannelData(frame_, 0, 99));
EXPECT_EQ(992, GetChannelData(frame_, 0, 100));
EXPECT_EQ(7, GetChannelData(frame_, 0, 226));
EXPECT_EQ(0, GetChannelData(frame_, 0, 227));
}
TEST_F(AudioFrameOperationsTest, MuteBeginMonoShort) {
InitFrame(&frame_, 1, 93, 1000, -1000);
AudioFrameOperations::Mute(&frame_, false, true);
VerifyFrameDataBounds(frame_, 0, 1000, 0);
EXPECT_EQ(989, GetChannelData(frame_, 0, 0));
EXPECT_EQ(978, GetChannelData(frame_, 0, 1));
EXPECT_EQ(10, GetChannelData(frame_, 0, 91));
EXPECT_EQ(0, GetChannelData(frame_, 0, 92));
}
TEST_F(AudioFrameOperationsTest, MuteBeginStereoLong) {
InitFrame(&frame_, 2, 228, 1000, -1000);
AudioFrameOperations::Mute(&frame_, false, true);
VerifyFrameDataBounds(frame_, 0, 1000, 0);
VerifyFrameDataBounds(frame_, 1, 0, -1000);
EXPECT_EQ(1000, GetChannelData(frame_, 0, 99));
EXPECT_EQ(-1000, GetChannelData(frame_, 1, 99));
EXPECT_EQ(992, GetChannelData(frame_, 0, 100));
EXPECT_EQ(-992, GetChannelData(frame_, 1, 100));
EXPECT_EQ(7, GetChannelData(frame_, 0, 226));
EXPECT_EQ(-7, GetChannelData(frame_, 1, 226));
EXPECT_EQ(0, GetChannelData(frame_, 0, 227));
EXPECT_EQ(0, GetChannelData(frame_, 1, 227));
}
TEST_F(AudioFrameOperationsTest, MuteBeginStereoShort) {
InitFrame(&frame_, 2, 93, 1000, -1000);
AudioFrameOperations::Mute(&frame_, false, true);
VerifyFrameDataBounds(frame_, 0, 1000, 0);
VerifyFrameDataBounds(frame_, 1, 0, -1000);
EXPECT_EQ(989, GetChannelData(frame_, 0, 0));
EXPECT_EQ(-989, GetChannelData(frame_, 1, 0));
EXPECT_EQ(978, GetChannelData(frame_, 0, 1));
EXPECT_EQ(-978, GetChannelData(frame_, 1, 1));
EXPECT_EQ(10, GetChannelData(frame_, 0, 91));
EXPECT_EQ(-10, GetChannelData(frame_, 1, 91));
EXPECT_EQ(0, GetChannelData(frame_, 0, 92));
EXPECT_EQ(0, GetChannelData(frame_, 1, 92));
}
// Verify that *ending* to mute works for short and long (>128) frames, mono
// and stereo. Ending mute should yield a ramp up from zero.
TEST_F(AudioFrameOperationsTest, MuteEndMonoLong) {
InitFrame(&frame_, 1, 228, 1000, -1000);
AudioFrameOperations::Mute(&frame_, true, false);
VerifyFrameDataBounds(frame_, 0, 1000, 0);
EXPECT_EQ(7, GetChannelData(frame_, 0, 0));
EXPECT_EQ(15, GetChannelData(frame_, 0, 1));
EXPECT_EQ(1000, GetChannelData(frame_, 0, 127));
EXPECT_EQ(1000, GetChannelData(frame_, 0, 128));
}
TEST_F(AudioFrameOperationsTest, MuteEndMonoShort) {
InitFrame(&frame_, 1, 93, 1000, -1000);
AudioFrameOperations::Mute(&frame_, true, false);
VerifyFrameDataBounds(frame_, 0, 1000, 0);
EXPECT_EQ(10, GetChannelData(frame_, 0, 0));
EXPECT_EQ(21, GetChannelData(frame_, 0, 1));
EXPECT_EQ(989, GetChannelData(frame_, 0, 91));
EXPECT_EQ(999, GetChannelData(frame_, 0, 92));
}
TEST_F(AudioFrameOperationsTest, MuteEndStereoLong) {
InitFrame(&frame_, 2, 228, 1000, -1000);
AudioFrameOperations::Mute(&frame_, true, false);
VerifyFrameDataBounds(frame_, 0, 1000, 0);
VerifyFrameDataBounds(frame_, 1, 0, -1000);
EXPECT_EQ(7, GetChannelData(frame_, 0, 0));
EXPECT_EQ(-7, GetChannelData(frame_, 1, 0));
EXPECT_EQ(15, GetChannelData(frame_, 0, 1));
EXPECT_EQ(-15, GetChannelData(frame_, 1, 1));
EXPECT_EQ(1000, GetChannelData(frame_, 0, 127));
EXPECT_EQ(-1000, GetChannelData(frame_, 1, 127));
EXPECT_EQ(1000, GetChannelData(frame_, 0, 128));
EXPECT_EQ(-1000, GetChannelData(frame_, 1, 128));
}
TEST_F(AudioFrameOperationsTest, MuteEndStereoShort) {
InitFrame(&frame_, 2, 93, 1000, -1000);
AudioFrameOperations::Mute(&frame_, true, false);
VerifyFrameDataBounds(frame_, 0, 1000, 0);
VerifyFrameDataBounds(frame_, 1, 0, -1000);
EXPECT_EQ(10, GetChannelData(frame_, 0, 0));
EXPECT_EQ(-10, GetChannelData(frame_, 1, 0));
EXPECT_EQ(21, GetChannelData(frame_, 0, 1));
EXPECT_EQ(-21, GetChannelData(frame_, 1, 1));
EXPECT_EQ(989, GetChannelData(frame_, 0, 91));
EXPECT_EQ(-989, GetChannelData(frame_, 1, 91));
EXPECT_EQ(999, GetChannelData(frame_, 0, 92));
EXPECT_EQ(-999, GetChannelData(frame_, 1, 92));
}
TEST_F(AudioFrameOperationsTest, MuteBeginAlreadyMuted) {
ASSERT_TRUE(frame_.muted());
AudioFrameOperations::Mute(&frame_, false, true);
EXPECT_TRUE(frame_.muted());
}
TEST_F(AudioFrameOperationsTest, MuteEndAlreadyMuted) {
ASSERT_TRUE(frame_.muted());
AudioFrameOperations::Mute(&frame_, true, false);
EXPECT_TRUE(frame_.muted());
}
// TODO(andrew): should fail with a negative scale.
TEST_F(AudioFrameOperationsTest, DISABLED_ScaleWithSatFailsWithBadParameters) {
EXPECT_EQ(-1, AudioFrameOperations::ScaleWithSat(-1.0, &frame_));
}
TEST_F(AudioFrameOperationsTest, ScaleWithSatDoesNotWrapAround) {
SetFrameData(4000, &frame_);
EXPECT_EQ(0, AudioFrameOperations::ScaleWithSat(10.0, &frame_));
AudioFrame clipped_frame;
clipped_frame.samples_per_channel_ = 320;
SetFrameData(32767, &clipped_frame);
VerifyFramesAreEqual(clipped_frame, frame_);
SetFrameData(-4000, &frame_);
EXPECT_EQ(0, AudioFrameOperations::ScaleWithSat(10.0, &frame_));
SetFrameData(-32768, &clipped_frame);
VerifyFramesAreEqual(clipped_frame, frame_);
}
TEST_F(AudioFrameOperationsTest, ScaleWithSatSucceeds) {
SetFrameData(1, &frame_);
EXPECT_EQ(0, AudioFrameOperations::ScaleWithSat(2.0, &frame_));
AudioFrame scaled_frame;
scaled_frame.samples_per_channel_ = 320;
SetFrameData(2, &scaled_frame);
VerifyFramesAreEqual(scaled_frame, frame_);
}
TEST_F(AudioFrameOperationsTest, ScaleWithSatMuted) {
ASSERT_TRUE(frame_.muted());
EXPECT_EQ(0, AudioFrameOperations::ScaleWithSat(2.0, &frame_));
EXPECT_TRUE(frame_.muted());
}
} // namespace
} // namespace webrtc