blob: 0088ef190919a2820df3bbf6575d4cd6fb8e403f [file] [log] [blame]
// Copyright 2020 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 "third_party/blink/renderer/platform/peerconnection/webrtc_audio_sink.h"
#include "media/base/fake_single_thread_task_runner.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
namespace blink {
namespace {
class MockAudioSink : public webrtc::AudioTrackSinkInterface {
public:
MockAudioSink() = default;
~MockAudioSink() override = default;
MOCK_METHOD6(OnData,
void(const void* audio_data,
int bits_per_sample,
int sample_rate,
size_t number_of_channels,
size_t number_of_samples,
absl::optional<int64_t> absolute_capture_timestamp_ms));
};
class ScopedFakeClock : public rtc::ClockInterface {
public:
explicit ScopedFakeClock(int64_t init_time_ms)
: prev_clock_(rtc::SetClockForTesting(this)),
time_ns_(init_time_ms * rtc::kNumNanosecsPerMillisec) {}
~ScopedFakeClock() override { rtc::SetClockForTesting(prev_clock_); }
int64_t TimeNanos() const override { return time_ns_; }
void AdvanceTimeMilliseconds(int64_t time_ms) {
time_ns_ += time_ms * rtc::kNumNanosecsPerMillisec;
}
private:
ClockInterface* const prev_clock_;
int64_t time_ns_;
};
} // namespace
TEST(WebRtcAudioSinkTest, CaptureTimestamp) {
MockAudioSink sink_1;
MockAudioSink sink_2;
base::SimpleTestTickClock dummy_clock;
std::unique_ptr<WebRtcAudioSink> webrtc_audio_sink(
new WebRtcAudioSink("test_sink", nullptr,
/*signaling_task_runner=*/
new media::FakeSingleThreadTaskRunner(&dummy_clock),
/*main_task_runner=*/
new media::FakeSingleThreadTaskRunner(&dummy_clock)));
// |web_media_stream_audio_sink| is to access methods that are privately
// inherited by WebRtcAudioSink.
WebMediaStreamAudioSink* const web_media_stream_audio_sink =
static_cast<WebMediaStreamAudioSink*>(webrtc_audio_sink.get());
webrtc_audio_sink->webrtc_audio_track()->AddSink(&sink_1);
webrtc_audio_sink->webrtc_audio_track()->AddSink(&sink_2);
constexpr int kInputChannels = 2;
constexpr int kInputFramesPerBuffer = 96;
constexpr int kSampleRateHz = 8000;
constexpr int kOutputFramesPerBuffer = kSampleRateHz / 100;
constexpr int kEnqueueFrames = kInputFramesPerBuffer - kOutputFramesPerBuffer;
constexpr int64_t kStartRtcTimestampMs = 87654321;
constexpr int64_t kStartCaptureTimestampMs = 12345678;
constexpr int64_t kCaptureIntervalMs = 567;
web_media_stream_audio_sink->OnSetFormat(media::AudioParameters(
media::AudioParameters::AUDIO_PCM_LINEAR, media::CHANNEL_LAYOUT_STEREO,
kSampleRateHz, kOutputFramesPerBuffer));
std::unique_ptr<media::AudioBus> bus =
media::AudioBus::Create(kInputChannels, kInputFramesPerBuffer);
bus->Zero();
{
ScopedFakeClock clock(kStartRtcTimestampMs);
base::TimeTicks capture_time =
base::TimeTicks() +
base::TimeDelta::FromMilliseconds(kStartCaptureTimestampMs);
// The first time to the call OnData(), the TimestampAligner should have no
// effect work. So expected capture timestamp is from fake_clock.
EXPECT_CALL(
sink_1,
OnData(_, _, kSampleRateHz, kInputChannels, kOutputFramesPerBuffer,
absl::make_optional<int64_t>(kStartRtcTimestampMs)));
EXPECT_CALL(
sink_2,
OnData(_, _, kSampleRateHz, kInputChannels, kOutputFramesPerBuffer,
absl::make_optional<int64_t>(kStartRtcTimestampMs)));
web_media_stream_audio_sink->OnData(*bus, capture_time);
capture_time += base::TimeDelta::FromMilliseconds(kCaptureIntervalMs);
clock.AdvanceTimeMilliseconds(kCaptureIntervalMs);
constexpr int64_t kExpectedTimestampMs =
kStartRtcTimestampMs + kCaptureIntervalMs -
kEnqueueFrames * 1000 / kSampleRateHz;
EXPECT_CALL(
sink_1,
OnData(_, _, kSampleRateHz, kInputChannels, kOutputFramesPerBuffer,
absl::make_optional<int64_t>(kExpectedTimestampMs)));
EXPECT_CALL(
sink_2,
OnData(_, _, kSampleRateHz, kInputChannels, kOutputFramesPerBuffer,
absl::make_optional<int64_t>(kExpectedTimestampMs)));
web_media_stream_audio_sink->OnData(*bus, capture_time);
}
}
} // namespace blink