blob: a3cbfd77e79197a2244f7f2712709e6161c1031a [file] [log] [blame]
// Copyright 2014 The Chromium 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 "media/cast/sender/audio_sender.h"
#include <stdint.h>
#include <memory>
#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/test/simple_test_tick_clock.h"
#include "base/values.h"
#include "media/base/fake_single_thread_task_runner.h"
#include "media/base/media.h"
#include "media/cast/cast_config.h"
#include "media/cast/cast_environment.h"
#include "media/cast/constants.h"
#include "media/cast/net/cast_transport_config.h"
#include "media/cast/net/cast_transport_impl.h"
#include "media/cast/test/utility/audio_utility.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace media {
namespace cast {
namespace {
void SaveOperationalStatus(OperationalStatus* out_status,
OperationalStatus in_status) {
DVLOG(1) << "OperationalStatus transitioning from " << *out_status << " to "
<< in_status;
*out_status = in_status;
}
class TransportClient : public CastTransport::Client {
public:
TransportClient() = default;
void OnStatusChanged(CastTransportStatus status) final {
EXPECT_EQ(TRANSPORT_STREAM_INITIALIZED, status);
}
void OnLoggingEventsReceived(
std::unique_ptr<std::vector<FrameEvent>> frame_events,
std::unique_ptr<std::vector<PacketEvent>> packet_events) final {}
void ProcessRtpPacket(std::unique_ptr<Packet> packet) final {}
DISALLOW_COPY_AND_ASSIGN(TransportClient);
};
} // namespace
class TestPacketSender : public PacketTransport {
public:
TestPacketSender() : number_of_rtp_packets_(0), number_of_rtcp_packets_(0) {}
bool SendPacket(PacketRef packet, const base::Closure& cb) final {
if (IsRtcpPacket(&packet->data[0], packet->data.size())) {
++number_of_rtcp_packets_;
} else {
// Check that at least one RTCP packet was sent before the first RTP
// packet. This confirms that the receiver will have the necessary lip
// sync info before it has to calculate the playout time of the first
// frame.
if (number_of_rtp_packets_ == 0)
EXPECT_LE(1, number_of_rtcp_packets_);
++number_of_rtp_packets_;
}
return true;
}
int64_t GetBytesSent() final { return 0; }
void StartReceiving(
const PacketReceiverCallbackWithStatus& packet_receiver) final {}
void StopReceiving() final {}
int number_of_rtp_packets() const { return number_of_rtp_packets_; }
int number_of_rtcp_packets() const { return number_of_rtcp_packets_; }
private:
int number_of_rtp_packets_;
int number_of_rtcp_packets_;
DISALLOW_COPY_AND_ASSIGN(TestPacketSender);
};
class AudioSenderTest : public ::testing::Test {
protected:
AudioSenderTest() {
InitializeMediaLibrary();
testing_clock_.Advance(base::TimeTicks::Now() - base::TimeTicks());
task_runner_ = new FakeSingleThreadTaskRunner(&testing_clock_);
cast_environment_ = new CastEnvironment(&testing_clock_, task_runner_,
task_runner_, task_runner_);
audio_config_.codec = CODEC_AUDIO_OPUS;
audio_config_.use_external_encoder = false;
audio_config_.rtp_timebase = kDefaultAudioSamplingRate;
audio_config_.channels = 2;
audio_config_.max_bitrate = kDefaultAudioEncoderBitrate;
audio_config_.rtp_payload_type = RtpPayloadType::AUDIO_OPUS;
transport_ = new TestPacketSender();
transport_sender_.reset(new CastTransportImpl(
&testing_clock_, base::TimeDelta(), std::make_unique<TransportClient>(),
base::WrapUnique(transport_), task_runner_));
OperationalStatus operational_status = STATUS_UNINITIALIZED;
audio_sender_.reset(new AudioSender(
cast_environment_,
audio_config_,
base::Bind(&SaveOperationalStatus, &operational_status),
transport_sender_.get()));
task_runner_->RunTasks();
CHECK_EQ(STATUS_INITIALIZED, operational_status);
}
~AudioSenderTest() override = default;
base::SimpleTestTickClock testing_clock_;
TestPacketSender* transport_; // Owned by CastTransport.
std::unique_ptr<CastTransportImpl> transport_sender_;
scoped_refptr<FakeSingleThreadTaskRunner> task_runner_;
std::unique_ptr<AudioSender> audio_sender_;
scoped_refptr<CastEnvironment> cast_environment_;
FrameSenderConfig audio_config_;
};
TEST_F(AudioSenderTest, Encode20ms) {
const base::TimeDelta kDuration = base::TimeDelta::FromMilliseconds(20);
std::unique_ptr<AudioBus> bus(
TestAudioBusFactory(audio_config_.channels, audio_config_.rtp_timebase,
TestAudioBusFactory::kMiddleANoteFreq, 0.5f)
.NextAudioBus(kDuration));
audio_sender_->InsertAudio(std::move(bus), testing_clock_.NowTicks());
task_runner_->RunTasks();
EXPECT_LE(1, transport_->number_of_rtp_packets());
EXPECT_LE(1, transport_->number_of_rtcp_packets());
}
TEST_F(AudioSenderTest, RtcpTimer) {
const base::TimeDelta kDuration = base::TimeDelta::FromMilliseconds(20);
std::unique_ptr<AudioBus> bus(
TestAudioBusFactory(audio_config_.channels, audio_config_.rtp_timebase,
TestAudioBusFactory::kMiddleANoteFreq, 0.5f)
.NextAudioBus(kDuration));
audio_sender_->InsertAudio(std::move(bus), testing_clock_.NowTicks());
task_runner_->RunTasks();
// Make sure that we send at least one RTCP packet.
base::TimeDelta max_rtcp_timeout =
base::TimeDelta::FromMilliseconds(1 + kRtcpReportIntervalMs * 3 / 2);
testing_clock_.Advance(max_rtcp_timeout);
task_runner_->RunTasks();
EXPECT_LE(1, transport_->number_of_rtp_packets());
EXPECT_LE(1, transport_->number_of_rtcp_packets());
}
} // namespace cast
} // namespace media