mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-30 11:47:45 +00:00
331 lines
12 KiB
C++
331 lines
12 KiB
C++
|
/*
|
||
|
* 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 "webrtc/modules/audio_coding/neteq/timestamp_scaler.h"
|
||
|
|
||
|
#include "gmock/gmock.h"
|
||
|
#include "gtest/gtest.h"
|
||
|
#include "webrtc/modules/audio_coding/neteq/mock/mock_decoder_database.h"
|
||
|
#include "webrtc/modules/audio_coding/neteq/packet.h"
|
||
|
|
||
|
using ::testing::Return;
|
||
|
using ::testing::ReturnNull;
|
||
|
using ::testing::_;
|
||
|
|
||
|
namespace webrtc {
|
||
|
|
||
|
TEST(TimestampScaler, TestNoScaling) {
|
||
|
MockDecoderDatabase db;
|
||
|
DecoderDatabase::DecoderInfo info;
|
||
|
info.codec_type = kDecoderPCMu; // Does not use scaled timestamps.
|
||
|
static const uint8_t kRtpPayloadType = 0;
|
||
|
EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
|
||
|
.WillRepeatedly(Return(&info));
|
||
|
|
||
|
TimestampScaler scaler(db);
|
||
|
// Test both sides of the timestamp wrap-around.
|
||
|
for (uint32_t timestamp = 0xFFFFFFFF - 5; timestamp != 5; ++timestamp) {
|
||
|
// Scale to internal timestamp.
|
||
|
EXPECT_EQ(timestamp, scaler.ToInternal(timestamp, kRtpPayloadType));
|
||
|
// Scale back.
|
||
|
EXPECT_EQ(timestamp, scaler.ToExternal(timestamp));
|
||
|
}
|
||
|
|
||
|
EXPECT_CALL(db, Die()); // Called when database object is deleted.
|
||
|
}
|
||
|
|
||
|
TEST(TimestampScaler, TestNoScalingLargeStep) {
|
||
|
MockDecoderDatabase db;
|
||
|
DecoderDatabase::DecoderInfo info;
|
||
|
info.codec_type = kDecoderPCMu; // Does not use scaled timestamps.
|
||
|
static const uint8_t kRtpPayloadType = 0;
|
||
|
EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
|
||
|
.WillRepeatedly(Return(&info));
|
||
|
|
||
|
TimestampScaler scaler(db);
|
||
|
// Test both sides of the timestamp wrap-around.
|
||
|
static const uint32_t kStep = 160;
|
||
|
uint32_t start_timestamp = 0;
|
||
|
// |external_timestamp| will be a large positive value.
|
||
|
start_timestamp = start_timestamp - 5 * kStep;
|
||
|
for (uint32_t timestamp = start_timestamp; timestamp != 5 * kStep;
|
||
|
timestamp += kStep) {
|
||
|
// Scale to internal timestamp.
|
||
|
EXPECT_EQ(timestamp, scaler.ToInternal(timestamp, kRtpPayloadType));
|
||
|
// Scale back.
|
||
|
EXPECT_EQ(timestamp, scaler.ToExternal(timestamp));
|
||
|
}
|
||
|
|
||
|
EXPECT_CALL(db, Die()); // Called when database object is deleted.
|
||
|
}
|
||
|
|
||
|
TEST(TimestampScaler, TestG722) {
|
||
|
MockDecoderDatabase db;
|
||
|
DecoderDatabase::DecoderInfo info;
|
||
|
info.codec_type = kDecoderG722; // Uses a factor 2 scaling.
|
||
|
static const uint8_t kRtpPayloadType = 17;
|
||
|
EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
|
||
|
.WillRepeatedly(Return(&info));
|
||
|
|
||
|
TimestampScaler scaler(db);
|
||
|
// Test both sides of the timestamp wrap-around.
|
||
|
uint32_t external_timestamp = 0xFFFFFFFF - 5;
|
||
|
uint32_t internal_timestamp = external_timestamp;
|
||
|
for (; external_timestamp != 5; ++external_timestamp) {
|
||
|
// Scale to internal timestamp.
|
||
|
EXPECT_EQ(internal_timestamp,
|
||
|
scaler.ToInternal(external_timestamp, kRtpPayloadType));
|
||
|
// Scale back.
|
||
|
EXPECT_EQ(external_timestamp, scaler.ToExternal(internal_timestamp));
|
||
|
internal_timestamp += 2;
|
||
|
}
|
||
|
|
||
|
EXPECT_CALL(db, Die()); // Called when database object is deleted.
|
||
|
}
|
||
|
|
||
|
TEST(TimestampScaler, TestG722LargeStep) {
|
||
|
MockDecoderDatabase db;
|
||
|
DecoderDatabase::DecoderInfo info;
|
||
|
info.codec_type = kDecoderG722; // Uses a factor 2 scaling.
|
||
|
static const uint8_t kRtpPayloadType = 17;
|
||
|
EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
|
||
|
.WillRepeatedly(Return(&info));
|
||
|
|
||
|
TimestampScaler scaler(db);
|
||
|
// Test both sides of the timestamp wrap-around.
|
||
|
static const uint32_t kStep = 320;
|
||
|
uint32_t external_timestamp = 0;
|
||
|
// |external_timestamp| will be a large positive value.
|
||
|
external_timestamp = external_timestamp - 5 * kStep;
|
||
|
uint32_t internal_timestamp = external_timestamp;
|
||
|
for (; external_timestamp != 5 * kStep; external_timestamp += kStep) {
|
||
|
// Scale to internal timestamp.
|
||
|
EXPECT_EQ(internal_timestamp,
|
||
|
scaler.ToInternal(external_timestamp, kRtpPayloadType));
|
||
|
// Scale back.
|
||
|
EXPECT_EQ(external_timestamp, scaler.ToExternal(internal_timestamp));
|
||
|
// Internal timestamp should be incremented with twice the step.
|
||
|
internal_timestamp += 2 * kStep;
|
||
|
}
|
||
|
|
||
|
EXPECT_CALL(db, Die()); // Called when database object is deleted.
|
||
|
}
|
||
|
|
||
|
TEST(TimestampScaler, TestG722WithCng) {
|
||
|
MockDecoderDatabase db;
|
||
|
DecoderDatabase::DecoderInfo info_g722, info_cng;
|
||
|
info_g722.codec_type = kDecoderG722; // Uses a factor 2 scaling.
|
||
|
info_cng.codec_type = kDecoderCNGwb;
|
||
|
static const uint8_t kRtpPayloadTypeG722 = 17;
|
||
|
static const uint8_t kRtpPayloadTypeCng = 13;
|
||
|
EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadTypeG722))
|
||
|
.WillRepeatedly(Return(&info_g722));
|
||
|
EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadTypeCng))
|
||
|
.WillRepeatedly(Return(&info_cng));
|
||
|
|
||
|
TimestampScaler scaler(db);
|
||
|
// Test both sides of the timestamp wrap-around.
|
||
|
uint32_t external_timestamp = 0xFFFFFFFF - 5;
|
||
|
uint32_t internal_timestamp = external_timestamp;
|
||
|
bool next_is_cng = false;
|
||
|
for (; external_timestamp != 5; ++external_timestamp) {
|
||
|
// Alternate between G.722 and CNG every other packet.
|
||
|
if (next_is_cng) {
|
||
|
// Scale to internal timestamp.
|
||
|
EXPECT_EQ(internal_timestamp,
|
||
|
scaler.ToInternal(external_timestamp, kRtpPayloadTypeCng));
|
||
|
next_is_cng = false;
|
||
|
} else {
|
||
|
// Scale to internal timestamp.
|
||
|
EXPECT_EQ(internal_timestamp,
|
||
|
scaler.ToInternal(external_timestamp, kRtpPayloadTypeG722));
|
||
|
next_is_cng = true;
|
||
|
}
|
||
|
// Scale back.
|
||
|
EXPECT_EQ(external_timestamp, scaler.ToExternal(internal_timestamp));
|
||
|
internal_timestamp += 2;
|
||
|
}
|
||
|
|
||
|
EXPECT_CALL(db, Die()); // Called when database object is deleted.
|
||
|
}
|
||
|
|
||
|
// Make sure that the method ToInternal(Packet* packet) is wired up correctly.
|
||
|
// Since it is simply calling the other ToInternal method, we are not doing
|
||
|
// as many tests here.
|
||
|
TEST(TimestampScaler, TestG722Packet) {
|
||
|
MockDecoderDatabase db;
|
||
|
DecoderDatabase::DecoderInfo info;
|
||
|
info.codec_type = kDecoderG722; // Does uses a factor 2 scaling.
|
||
|
static const uint8_t kRtpPayloadType = 17;
|
||
|
EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
|
||
|
.WillRepeatedly(Return(&info));
|
||
|
|
||
|
TimestampScaler scaler(db);
|
||
|
// Test both sides of the timestamp wrap-around.
|
||
|
uint32_t external_timestamp = 0xFFFFFFFF - 5;
|
||
|
uint32_t internal_timestamp = external_timestamp;
|
||
|
Packet packet;
|
||
|
packet.header.payloadType = kRtpPayloadType;
|
||
|
for (; external_timestamp != 5; ++external_timestamp) {
|
||
|
packet.header.timestamp = external_timestamp;
|
||
|
// Scale to internal timestamp.
|
||
|
scaler.ToInternal(&packet);
|
||
|
EXPECT_EQ(internal_timestamp, packet.header.timestamp);
|
||
|
internal_timestamp += 2;
|
||
|
}
|
||
|
|
||
|
EXPECT_CALL(db, Die()); // Called when database object is deleted.
|
||
|
}
|
||
|
|
||
|
// Make sure that the method ToInternal(PacketList* packet_list) is wired up
|
||
|
// correctly. Since it is simply calling the ToInternal(Packet* packet) method,
|
||
|
// we are not doing as many tests here.
|
||
|
TEST(TimestampScaler, TestG722PacketList) {
|
||
|
MockDecoderDatabase db;
|
||
|
DecoderDatabase::DecoderInfo info;
|
||
|
info.codec_type = kDecoderG722; // Uses a factor 2 scaling.
|
||
|
static const uint8_t kRtpPayloadType = 17;
|
||
|
EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
|
||
|
.WillRepeatedly(Return(&info));
|
||
|
|
||
|
TimestampScaler scaler(db);
|
||
|
// Test both sides of the timestamp wrap-around.
|
||
|
uint32_t external_timestamp = 0xFFFFFFFF - 5;
|
||
|
uint32_t internal_timestamp = external_timestamp;
|
||
|
Packet packet1;
|
||
|
packet1.header.payloadType = kRtpPayloadType;
|
||
|
packet1.header.timestamp = external_timestamp;
|
||
|
Packet packet2;
|
||
|
packet2.header.payloadType = kRtpPayloadType;
|
||
|
packet2.header.timestamp = external_timestamp + 10;
|
||
|
PacketList packet_list;
|
||
|
packet_list.push_back(&packet1);
|
||
|
packet_list.push_back(&packet2);
|
||
|
|
||
|
scaler.ToInternal(&packet_list);
|
||
|
EXPECT_EQ(internal_timestamp, packet1.header.timestamp);
|
||
|
EXPECT_EQ(internal_timestamp + 20, packet2.header.timestamp);
|
||
|
|
||
|
EXPECT_CALL(db, Die()); // Called when database object is deleted.
|
||
|
}
|
||
|
|
||
|
TEST(TimestampScaler, TestG722Reset) {
|
||
|
MockDecoderDatabase db;
|
||
|
DecoderDatabase::DecoderInfo info;
|
||
|
info.codec_type = kDecoderG722; // Uses a factor 2 scaling.
|
||
|
static const uint8_t kRtpPayloadType = 17;
|
||
|
EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
|
||
|
.WillRepeatedly(Return(&info));
|
||
|
|
||
|
TimestampScaler scaler(db);
|
||
|
// Test both sides of the timestamp wrap-around.
|
||
|
uint32_t external_timestamp = 0xFFFFFFFF - 5;
|
||
|
uint32_t internal_timestamp = external_timestamp;
|
||
|
for (; external_timestamp != 5; ++external_timestamp) {
|
||
|
// Scale to internal timestamp.
|
||
|
EXPECT_EQ(internal_timestamp,
|
||
|
scaler.ToInternal(external_timestamp, kRtpPayloadType));
|
||
|
// Scale back.
|
||
|
EXPECT_EQ(external_timestamp, scaler.ToExternal(internal_timestamp));
|
||
|
internal_timestamp += 2;
|
||
|
}
|
||
|
// Reset the scaler. After this, we expect the internal and external to start
|
||
|
// over at the same value again.
|
||
|
scaler.Reset();
|
||
|
internal_timestamp = external_timestamp;
|
||
|
for (; external_timestamp != 15; ++external_timestamp) {
|
||
|
// Scale to internal timestamp.
|
||
|
EXPECT_EQ(internal_timestamp,
|
||
|
scaler.ToInternal(external_timestamp, kRtpPayloadType));
|
||
|
// Scale back.
|
||
|
EXPECT_EQ(external_timestamp, scaler.ToExternal(internal_timestamp));
|
||
|
internal_timestamp += 2;
|
||
|
}
|
||
|
|
||
|
EXPECT_CALL(db, Die()); // Called when database object is deleted.
|
||
|
}
|
||
|
|
||
|
// TODO(minyue): This test becomes trivial since Opus does not need a timestamp
|
||
|
// scaler. Therefore, this test may be removed in future. There is no harm to
|
||
|
// keep it, since it can be taken as a test case for the situation of a trivial
|
||
|
// timestamp scaler.
|
||
|
TEST(TimestampScaler, TestOpusLargeStep) {
|
||
|
MockDecoderDatabase db;
|
||
|
DecoderDatabase::DecoderInfo info;
|
||
|
info.codec_type = kDecoderOpus;
|
||
|
static const uint8_t kRtpPayloadType = 17;
|
||
|
EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
|
||
|
.WillRepeatedly(Return(&info));
|
||
|
|
||
|
TimestampScaler scaler(db);
|
||
|
// Test both sides of the timestamp wrap-around.
|
||
|
static const uint32_t kStep = 960;
|
||
|
uint32_t external_timestamp = 0;
|
||
|
// |external_timestamp| will be a large positive value.
|
||
|
external_timestamp = external_timestamp - 5 * kStep;
|
||
|
uint32_t internal_timestamp = external_timestamp;
|
||
|
for (; external_timestamp != 5 * kStep; external_timestamp += kStep) {
|
||
|
// Scale to internal timestamp.
|
||
|
EXPECT_EQ(internal_timestamp,
|
||
|
scaler.ToInternal(external_timestamp, kRtpPayloadType));
|
||
|
// Scale back.
|
||
|
EXPECT_EQ(external_timestamp, scaler.ToExternal(internal_timestamp));
|
||
|
internal_timestamp += kStep;
|
||
|
}
|
||
|
|
||
|
EXPECT_CALL(db, Die()); // Called when database object is deleted.
|
||
|
}
|
||
|
|
||
|
TEST(TimestampScaler, TestIsacFbLargeStep) {
|
||
|
MockDecoderDatabase db;
|
||
|
DecoderDatabase::DecoderInfo info;
|
||
|
info.codec_type = kDecoderISACfb;
|
||
|
static const uint8_t kRtpPayloadType = 17;
|
||
|
EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
|
||
|
.WillRepeatedly(Return(&info));
|
||
|
|
||
|
TimestampScaler scaler(db);
|
||
|
// Test both sides of the timestamp wrap-around.
|
||
|
static const uint32_t kStep = 960;
|
||
|
uint32_t external_timestamp = 0;
|
||
|
// |external_timestamp| will be a large positive value.
|
||
|
external_timestamp = external_timestamp - 5 * kStep;
|
||
|
uint32_t internal_timestamp = external_timestamp;
|
||
|
for (; external_timestamp != 5 * kStep; external_timestamp += kStep) {
|
||
|
// Scale to internal timestamp.
|
||
|
EXPECT_EQ(internal_timestamp,
|
||
|
scaler.ToInternal(external_timestamp, kRtpPayloadType));
|
||
|
// Scale back.
|
||
|
EXPECT_EQ(external_timestamp, scaler.ToExternal(internal_timestamp));
|
||
|
// Internal timestamp should be incremented with two-thirds the step.
|
||
|
internal_timestamp += 2 * kStep / 3;
|
||
|
}
|
||
|
|
||
|
EXPECT_CALL(db, Die()); // Called when database object is deleted.
|
||
|
}
|
||
|
|
||
|
TEST(TimestampScaler, Failures) {
|
||
|
static const uint8_t kRtpPayloadType = 17;
|
||
|
MockDecoderDatabase db;
|
||
|
EXPECT_CALL(db, GetDecoderInfo(kRtpPayloadType))
|
||
|
.WillOnce(ReturnNull()); // Return NULL to indicate unknown payload type.
|
||
|
|
||
|
TimestampScaler scaler(db);
|
||
|
uint32_t timestamp = 4711; // Some number.
|
||
|
EXPECT_EQ(timestamp, scaler.ToInternal(timestamp, kRtpPayloadType));
|
||
|
|
||
|
Packet* packet = NULL;
|
||
|
scaler.ToInternal(packet); // Should not crash. That's all we can test.
|
||
|
|
||
|
EXPECT_CALL(db, Die()); // Called when database object is deleted.
|
||
|
}
|
||
|
|
||
|
} // namespace webrtc
|