webrtc/audio/channel_send_unittest.cc
Jakob Ivarsson db208317eb Update RTP timestamp based on capture timestamp when audio send stream is resumed.
This removes the previous approach where we continued to update the timestamp when the capturer is running but the send stream is stopped in favor of a more general approach that also works when the capturer is paused.

Some assumptions for this change to be correct: input sample rate and frame size will be the same before/after the stream is paused.

Bug: webrtc:12397
Change-Id: I3b03741cd6d3285cbc9aee3893800729852e6cfa
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/291526
Commit-Queue: Jakob Ivarsson‎ <jakobi@webrtc.org>
Reviewed-by: Henrik Lundin <henrik.lundin@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#39213}
2023-01-27 15:46:32 +00:00

151 lines
5.1 KiB
C++

/*
* Copyright 2023 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/channel_send.h"
#include <utility>
#include "api/audio/audio_frame.h"
#include "api/audio_codecs/builtin_audio_encoder_factory.h"
#include "api/rtc_event_log/rtc_event_log.h"
#include "api/scoped_refptr.h"
#include "api/units/time_delta.h"
#include "api/units/timestamp.h"
#include "call/rtp_transport_controller_send.h"
#include "test/gtest.h"
#include "test/mock_transport.h"
#include "test/scoped_key_value_config.h"
#include "test/time_controller/simulated_time_controller.h"
namespace webrtc {
namespace voe {
namespace {
using ::testing::Invoke;
using ::testing::NiceMock;
using ::testing::Return;
constexpr int kRtcpIntervalMs = 1000;
constexpr int kSsrc = 333;
constexpr int kPayloadType = 1;
constexpr int kSampleRateHz = 48000;
constexpr int kRtpRateHz = 48000;
BitrateConstraints GetBitrateConfig() {
BitrateConstraints bitrate_config;
bitrate_config.min_bitrate_bps = 10000;
bitrate_config.start_bitrate_bps = 100000;
bitrate_config.max_bitrate_bps = 1000000;
return bitrate_config;
}
class ChannelSendTest : public ::testing::Test {
protected:
ChannelSendTest()
: time_controller_(Timestamp::Seconds(1)),
transport_controller_(
time_controller_.GetClock(),
RtpTransportConfig{
.bitrate_config = GetBitrateConfig(),
.event_log = &event_log_,
.task_queue_factory = time_controller_.GetTaskQueueFactory(),
.trials = &field_trials_,
}) {
channel_ = voe::CreateChannelSend(
time_controller_.GetClock(), time_controller_.GetTaskQueueFactory(),
&transport_, nullptr, &event_log_, nullptr, crypto_options_, false,
kRtcpIntervalMs, kSsrc, nullptr, nullptr, field_trials_);
encoder_factory_ = CreateBuiltinAudioEncoderFactory();
std::unique_ptr<AudioEncoder> encoder = encoder_factory_->MakeAudioEncoder(
kPayloadType, SdpAudioFormat("opus", kRtpRateHz, 2), {});
channel_->SetEncoder(kPayloadType, std::move(encoder));
transport_controller_.EnsureStarted();
channel_->RegisterSenderCongestionControlObjects(&transport_controller_,
nullptr);
ON_CALL(transport_, SendRtcp).WillByDefault(Return(true));
ON_CALL(transport_, SendRtp).WillByDefault(Return(true));
}
std::unique_ptr<AudioFrame> CreateAudioFrame() {
auto frame = std::make_unique<AudioFrame>();
frame->sample_rate_hz_ = kSampleRateHz;
frame->samples_per_channel_ = kSampleRateHz / 100;
frame->num_channels_ = 1;
frame->set_absolute_capture_timestamp_ms(
time_controller_.GetClock()->TimeInMilliseconds());
return frame;
}
void ProcessNextFrame() {
channel_->ProcessAndEncodeAudio(CreateAudioFrame());
// Advance time to process the task queue.
time_controller_.AdvanceTime(TimeDelta::Millis(10));
}
GlobalSimulatedTimeController time_controller_;
webrtc::test::ScopedKeyValueConfig field_trials_;
RtcEventLogNull event_log_;
NiceMock<MockTransport> transport_;
CryptoOptions crypto_options_;
RtpTransportControllerSend transport_controller_;
std::unique_ptr<ChannelSendInterface> channel_;
rtc::scoped_refptr<AudioEncoderFactory> encoder_factory_;
};
TEST_F(ChannelSendTest, StopSendShouldResetEncoder) {
channel_->StartSend();
// Insert two frames which should trigger a new packet.
EXPECT_CALL(transport_, SendRtp).Times(1);
ProcessNextFrame();
ProcessNextFrame();
EXPECT_CALL(transport_, SendRtp).Times(0);
ProcessNextFrame();
// StopSend should clear the previous audio frame stored in the encoder.
channel_->StopSend();
channel_->StartSend();
// The following frame should not trigger a new packet since the encoder
// needs 20 ms audio.
EXPECT_CALL(transport_, SendRtp).Times(0);
ProcessNextFrame();
}
TEST_F(ChannelSendTest, IncreaseRtpTimestampByPauseDuration) {
channel_->StartSend();
uint32_t timestamp;
int sent_packets = 0;
auto send_rtp = [&](const uint8_t* data, size_t length,
const PacketOptions& options) {
++sent_packets;
RtpPacketReceived packet;
packet.Parse(data, length);
timestamp = packet.Timestamp();
return true;
};
EXPECT_CALL(transport_, SendRtp).WillRepeatedly(Invoke(send_rtp));
ProcessNextFrame();
ProcessNextFrame();
EXPECT_EQ(sent_packets, 1);
uint32_t first_timestamp = timestamp;
channel_->StopSend();
time_controller_.AdvanceTime(TimeDelta::Seconds(10));
channel_->StartSend();
ProcessNextFrame();
ProcessNextFrame();
EXPECT_EQ(sent_packets, 2);
int64_t timestamp_gap_ms =
static_cast<int64_t>(timestamp - first_timestamp) * 1000 / kRtpRateHz;
EXPECT_EQ(timestamp_gap_ms, 10020);
}
} // namespace
} // namespace voe
} // namespace webrtc