webrtc_m130/media/base/fake_media_engine.cc
Tommi c9625f09de Make MediaChannel classes aware of the network thread.
This CL mostly adds plumbing to get awareness of the network thread
to the media channel classes. Currently this pointer is only used
to DCHECK that `SetInterface` for the `NetworkInterface` pointer, is
called on the network thread. Follow up changes will establish that
most of the methods are called on the network thread and the mutex
in the MediaChannel base class, can be removed.

Most of the changes in the CL are in channel_unittest.cc. They're mostly
around updating the tests to incorporate the network thread in ways
that reflect how the classes are used in production. Another change is
to use accessor methods for the media channel instances instead of
caching potentially dangling pointers.

Bug: webrtc:11993
Change-Id: I8e2ed1bc23724e238554dbce386789d69660f7e4
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/217682
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Tommi <tommi@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33951}
2021-05-07 14:16:21 +00:00

594 lines
18 KiB
C++

/*
* Copyright 2018 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 "media/base/fake_media_engine.h"
#include <memory>
#include <utility>
#include "absl/algorithm/container.h"
#include "absl/strings/match.h"
#include "rtc_base/checks.h"
namespace cricket {
using webrtc::TaskQueueBase;
FakeVoiceMediaChannel::DtmfInfo::DtmfInfo(uint32_t ssrc,
int event_code,
int duration)
: ssrc(ssrc), event_code(event_code), duration(duration) {}
FakeVoiceMediaChannel::VoiceChannelAudioSink::VoiceChannelAudioSink(
AudioSource* source)
: source_(source) {
source_->SetSink(this);
}
FakeVoiceMediaChannel::VoiceChannelAudioSink::~VoiceChannelAudioSink() {
if (source_) {
source_->SetSink(nullptr);
}
}
void FakeVoiceMediaChannel::VoiceChannelAudioSink::OnData(
const void* audio_data,
int bits_per_sample,
int sample_rate,
size_t number_of_channels,
size_t number_of_frames,
absl::optional<int64_t> absolute_capture_timestamp_ms) {}
void FakeVoiceMediaChannel::VoiceChannelAudioSink::OnClose() {
source_ = nullptr;
}
AudioSource* FakeVoiceMediaChannel::VoiceChannelAudioSink::source() const {
return source_;
}
FakeVoiceMediaChannel::FakeVoiceMediaChannel(FakeVoiceEngine* engine,
const AudioOptions& options,
TaskQueueBase* network_thread)
: RtpHelper<VoiceMediaChannel>(network_thread),
engine_(engine),
max_bps_(-1) {
output_scalings_[0] = 1.0; // For default channel.
SetOptions(options);
}
FakeVoiceMediaChannel::~FakeVoiceMediaChannel() {
if (engine_) {
engine_->UnregisterChannel(this);
}
}
const std::vector<AudioCodec>& FakeVoiceMediaChannel::recv_codecs() const {
return recv_codecs_;
}
const std::vector<AudioCodec>& FakeVoiceMediaChannel::send_codecs() const {
return send_codecs_;
}
const std::vector<AudioCodec>& FakeVoiceMediaChannel::codecs() const {
return send_codecs();
}
const std::vector<FakeVoiceMediaChannel::DtmfInfo>&
FakeVoiceMediaChannel::dtmf_info_queue() const {
return dtmf_info_queue_;
}
const AudioOptions& FakeVoiceMediaChannel::options() const {
return options_;
}
int FakeVoiceMediaChannel::max_bps() const {
return max_bps_;
}
bool FakeVoiceMediaChannel::SetSendParameters(
const AudioSendParameters& params) {
set_send_rtcp_parameters(params.rtcp);
return (SetSendCodecs(params.codecs) &&
SetSendExtmapAllowMixed(params.extmap_allow_mixed) &&
SetSendRtpHeaderExtensions(params.extensions) &&
SetMaxSendBandwidth(params.max_bandwidth_bps) &&
SetOptions(params.options));
}
bool FakeVoiceMediaChannel::SetRecvParameters(
const AudioRecvParameters& params) {
set_recv_rtcp_parameters(params.rtcp);
return (SetRecvCodecs(params.codecs) &&
SetRecvRtpHeaderExtensions(params.extensions));
}
void FakeVoiceMediaChannel::SetPlayout(bool playout) {
set_playout(playout);
}
void FakeVoiceMediaChannel::SetSend(bool send) {
set_sending(send);
}
bool FakeVoiceMediaChannel::SetAudioSend(uint32_t ssrc,
bool enable,
const AudioOptions* options,
AudioSource* source) {
if (!SetLocalSource(ssrc, source)) {
return false;
}
if (!RtpHelper<VoiceMediaChannel>::MuteStream(ssrc, !enable)) {
return false;
}
if (enable && options) {
return SetOptions(*options);
}
return true;
}
bool FakeVoiceMediaChannel::HasSource(uint32_t ssrc) const {
return local_sinks_.find(ssrc) != local_sinks_.end();
}
bool FakeVoiceMediaChannel::AddRecvStream(const StreamParams& sp) {
if (!RtpHelper<VoiceMediaChannel>::AddRecvStream(sp))
return false;
output_scalings_[sp.first_ssrc()] = 1.0;
output_delays_[sp.first_ssrc()] = 0;
return true;
}
bool FakeVoiceMediaChannel::RemoveRecvStream(uint32_t ssrc) {
if (!RtpHelper<VoiceMediaChannel>::RemoveRecvStream(ssrc))
return false;
output_scalings_.erase(ssrc);
output_delays_.erase(ssrc);
return true;
}
bool FakeVoiceMediaChannel::CanInsertDtmf() {
for (std::vector<AudioCodec>::const_iterator it = send_codecs_.begin();
it != send_codecs_.end(); ++it) {
// Find the DTMF telephone event "codec".
if (absl::EqualsIgnoreCase(it->name, "telephone-event")) {
return true;
}
}
return false;
}
bool FakeVoiceMediaChannel::InsertDtmf(uint32_t ssrc,
int event_code,
int duration) {
dtmf_info_queue_.push_back(DtmfInfo(ssrc, event_code, duration));
return true;
}
bool FakeVoiceMediaChannel::SetOutputVolume(uint32_t ssrc, double volume) {
if (output_scalings_.find(ssrc) != output_scalings_.end()) {
output_scalings_[ssrc] = volume;
return true;
}
return false;
}
bool FakeVoiceMediaChannel::SetDefaultOutputVolume(double volume) {
for (auto& entry : output_scalings_) {
entry.second = volume;
}
return true;
}
bool FakeVoiceMediaChannel::GetOutputVolume(uint32_t ssrc, double* volume) {
if (output_scalings_.find(ssrc) == output_scalings_.end())
return false;
*volume = output_scalings_[ssrc];
return true;
}
bool FakeVoiceMediaChannel::SetBaseMinimumPlayoutDelayMs(uint32_t ssrc,
int delay_ms) {
if (output_delays_.find(ssrc) == output_delays_.end()) {
return false;
} else {
output_delays_[ssrc] = delay_ms;
return true;
}
}
absl::optional<int> FakeVoiceMediaChannel::GetBaseMinimumPlayoutDelayMs(
uint32_t ssrc) const {
const auto it = output_delays_.find(ssrc);
if (it != output_delays_.end()) {
return it->second;
}
return absl::nullopt;
}
bool FakeVoiceMediaChannel::GetStats(VoiceMediaInfo* info,
bool get_and_clear_legacy_stats) {
return false;
}
void FakeVoiceMediaChannel::SetRawAudioSink(
uint32_t ssrc,
std::unique_ptr<webrtc::AudioSinkInterface> sink) {
sink_ = std::move(sink);
}
void FakeVoiceMediaChannel::SetDefaultRawAudioSink(
std::unique_ptr<webrtc::AudioSinkInterface> sink) {
sink_ = std::move(sink);
}
std::vector<webrtc::RtpSource> FakeVoiceMediaChannel::GetSources(
uint32_t ssrc) const {
return std::vector<webrtc::RtpSource>();
}
bool FakeVoiceMediaChannel::SetRecvCodecs(
const std::vector<AudioCodec>& codecs) {
if (fail_set_recv_codecs()) {
// Fake the failure in SetRecvCodecs.
return false;
}
recv_codecs_ = codecs;
return true;
}
bool FakeVoiceMediaChannel::SetSendCodecs(
const std::vector<AudioCodec>& codecs) {
if (fail_set_send_codecs()) {
// Fake the failure in SetSendCodecs.
return false;
}
send_codecs_ = codecs;
return true;
}
bool FakeVoiceMediaChannel::SetMaxSendBandwidth(int bps) {
max_bps_ = bps;
return true;
}
bool FakeVoiceMediaChannel::SetOptions(const AudioOptions& options) {
// Does a "merge" of current options and set options.
options_.SetAll(options);
return true;
}
bool FakeVoiceMediaChannel::SetLocalSource(uint32_t ssrc, AudioSource* source) {
auto it = local_sinks_.find(ssrc);
if (source) {
if (it != local_sinks_.end()) {
RTC_CHECK(it->second->source() == source);
} else {
local_sinks_.insert(std::make_pair(
ssrc, std::make_unique<VoiceChannelAudioSink>(source)));
}
} else {
if (it != local_sinks_.end()) {
local_sinks_.erase(it);
}
}
return true;
}
bool CompareDtmfInfo(const FakeVoiceMediaChannel::DtmfInfo& info,
uint32_t ssrc,
int event_code,
int duration) {
return (info.duration == duration && info.event_code == event_code &&
info.ssrc == ssrc);
}
FakeVideoMediaChannel::FakeVideoMediaChannel(FakeVideoEngine* engine,
const VideoOptions& options,
TaskQueueBase* network_thread)
: RtpHelper<VideoMediaChannel>(network_thread),
engine_(engine),
max_bps_(-1) {
SetOptions(options);
}
FakeVideoMediaChannel::~FakeVideoMediaChannel() {
if (engine_) {
engine_->UnregisterChannel(this);
}
}
const std::vector<VideoCodec>& FakeVideoMediaChannel::recv_codecs() const {
return recv_codecs_;
}
const std::vector<VideoCodec>& FakeVideoMediaChannel::send_codecs() const {
return send_codecs_;
}
const std::vector<VideoCodec>& FakeVideoMediaChannel::codecs() const {
return send_codecs();
}
bool FakeVideoMediaChannel::rendering() const {
return playout();
}
const VideoOptions& FakeVideoMediaChannel::options() const {
return options_;
}
const std::map<uint32_t, rtc::VideoSinkInterface<webrtc::VideoFrame>*>&
FakeVideoMediaChannel::sinks() const {
return sinks_;
}
int FakeVideoMediaChannel::max_bps() const {
return max_bps_;
}
bool FakeVideoMediaChannel::SetSendParameters(
const VideoSendParameters& params) {
set_send_rtcp_parameters(params.rtcp);
return (SetSendCodecs(params.codecs) &&
SetSendExtmapAllowMixed(params.extmap_allow_mixed) &&
SetSendRtpHeaderExtensions(params.extensions) &&
SetMaxSendBandwidth(params.max_bandwidth_bps));
}
bool FakeVideoMediaChannel::SetRecvParameters(
const VideoRecvParameters& params) {
set_recv_rtcp_parameters(params.rtcp);
return (SetRecvCodecs(params.codecs) &&
SetRecvRtpHeaderExtensions(params.extensions));
}
bool FakeVideoMediaChannel::AddSendStream(const StreamParams& sp) {
return RtpHelper<VideoMediaChannel>::AddSendStream(sp);
}
bool FakeVideoMediaChannel::RemoveSendStream(uint32_t ssrc) {
return RtpHelper<VideoMediaChannel>::RemoveSendStream(ssrc);
}
bool FakeVideoMediaChannel::GetSendCodec(VideoCodec* send_codec) {
if (send_codecs_.empty()) {
return false;
}
*send_codec = send_codecs_[0];
return true;
}
bool FakeVideoMediaChannel::SetSink(
uint32_t ssrc,
rtc::VideoSinkInterface<webrtc::VideoFrame>* sink) {
auto it = sinks_.find(ssrc);
if (it == sinks_.end()) {
return false;
}
it->second = sink;
return true;
}
void FakeVideoMediaChannel::SetDefaultSink(
rtc::VideoSinkInterface<webrtc::VideoFrame>* sink) {}
bool FakeVideoMediaChannel::HasSink(uint32_t ssrc) const {
return sinks_.find(ssrc) != sinks_.end() && sinks_.at(ssrc) != nullptr;
}
bool FakeVideoMediaChannel::SetSend(bool send) {
return set_sending(send);
}
bool FakeVideoMediaChannel::SetVideoSend(
uint32_t ssrc,
const VideoOptions* options,
rtc::VideoSourceInterface<webrtc::VideoFrame>* source) {
if (options) {
if (!SetOptions(*options)) {
return false;
}
}
sources_[ssrc] = source;
return true;
}
bool FakeVideoMediaChannel::HasSource(uint32_t ssrc) const {
return sources_.find(ssrc) != sources_.end() && sources_.at(ssrc) != nullptr;
}
bool FakeVideoMediaChannel::AddRecvStream(const StreamParams& sp) {
if (!RtpHelper<VideoMediaChannel>::AddRecvStream(sp))
return false;
sinks_[sp.first_ssrc()] = NULL;
output_delays_[sp.first_ssrc()] = 0;
return true;
}
bool FakeVideoMediaChannel::RemoveRecvStream(uint32_t ssrc) {
if (!RtpHelper<VideoMediaChannel>::RemoveRecvStream(ssrc))
return false;
sinks_.erase(ssrc);
output_delays_.erase(ssrc);
return true;
}
void FakeVideoMediaChannel::FillBitrateInfo(BandwidthEstimationInfo* bwe_info) {
}
bool FakeVideoMediaChannel::GetStats(VideoMediaInfo* info) {
return false;
}
std::vector<webrtc::RtpSource> FakeVideoMediaChannel::GetSources(
uint32_t ssrc) const {
return {};
}
bool FakeVideoMediaChannel::SetBaseMinimumPlayoutDelayMs(uint32_t ssrc,
int delay_ms) {
if (output_delays_.find(ssrc) == output_delays_.end()) {
return false;
} else {
output_delays_[ssrc] = delay_ms;
return true;
}
}
absl::optional<int> FakeVideoMediaChannel::GetBaseMinimumPlayoutDelayMs(
uint32_t ssrc) const {
const auto it = output_delays_.find(ssrc);
if (it != output_delays_.end()) {
return it->second;
}
return absl::nullopt;
}
bool FakeVideoMediaChannel::SetRecvCodecs(
const std::vector<VideoCodec>& codecs) {
if (fail_set_recv_codecs()) {
// Fake the failure in SetRecvCodecs.
return false;
}
recv_codecs_ = codecs;
return true;
}
bool FakeVideoMediaChannel::SetSendCodecs(
const std::vector<VideoCodec>& codecs) {
if (fail_set_send_codecs()) {
// Fake the failure in SetSendCodecs.
return false;
}
send_codecs_ = codecs;
return true;
}
bool FakeVideoMediaChannel::SetOptions(const VideoOptions& options) {
options_ = options;
return true;
}
bool FakeVideoMediaChannel::SetMaxSendBandwidth(int bps) {
max_bps_ = bps;
return true;
}
void FakeVideoMediaChannel::SetRecordableEncodedFrameCallback(
uint32_t ssrc,
std::function<void(const webrtc::RecordableEncodedFrame&)> callback) {}
void FakeVideoMediaChannel::ClearRecordableEncodedFrameCallback(uint32_t ssrc) {
}
void FakeVideoMediaChannel::GenerateKeyFrame(uint32_t ssrc) {}
FakeVoiceEngine::FakeVoiceEngine() : fail_create_channel_(false) {
// Add a fake audio codec. Note that the name must not be "" as there are
// sanity checks against that.
SetCodecs({AudioCodec(101, "fake_audio_codec", 0, 0, 1)});
}
void FakeVoiceEngine::Init() {}
rtc::scoped_refptr<webrtc::AudioState> FakeVoiceEngine::GetAudioState() const {
return rtc::scoped_refptr<webrtc::AudioState>();
}
VoiceMediaChannel* FakeVoiceEngine::CreateMediaChannel(
webrtc::Call* call,
const MediaConfig& config,
const AudioOptions& options,
const webrtc::CryptoOptions& crypto_options) {
if (fail_create_channel_) {
return nullptr;
}
FakeVoiceMediaChannel* ch =
new FakeVoiceMediaChannel(this, options, call->network_thread());
channels_.push_back(ch);
return ch;
}
FakeVoiceMediaChannel* FakeVoiceEngine::GetChannel(size_t index) {
return (channels_.size() > index) ? channels_[index] : NULL;
}
void FakeVoiceEngine::UnregisterChannel(VoiceMediaChannel* channel) {
channels_.erase(absl::c_find(channels_, channel));
}
const std::vector<AudioCodec>& FakeVoiceEngine::send_codecs() const {
return send_codecs_;
}
const std::vector<AudioCodec>& FakeVoiceEngine::recv_codecs() const {
return recv_codecs_;
}
void FakeVoiceEngine::SetCodecs(const std::vector<AudioCodec>& codecs) {
send_codecs_ = codecs;
recv_codecs_ = codecs;
}
void FakeVoiceEngine::SetRecvCodecs(const std::vector<AudioCodec>& codecs) {
recv_codecs_ = codecs;
}
void FakeVoiceEngine::SetSendCodecs(const std::vector<AudioCodec>& codecs) {
send_codecs_ = codecs;
}
int FakeVoiceEngine::GetInputLevel() {
return 0;
}
bool FakeVoiceEngine::StartAecDump(webrtc::FileWrapper file,
int64_t max_size_bytes) {
return false;
}
void FakeVoiceEngine::StopAecDump() {}
std::vector<webrtc::RtpHeaderExtensionCapability>
FakeVoiceEngine::GetRtpHeaderExtensions() const {
return header_extensions_;
}
void FakeVoiceEngine::SetRtpHeaderExtensions(
std::vector<webrtc::RtpHeaderExtensionCapability> header_extensions) {
header_extensions_ = std::move(header_extensions);
}
FakeVideoEngine::FakeVideoEngine()
: capture_(false), fail_create_channel_(false) {
// Add a fake video codec. Note that the name must not be "" as there are
// sanity checks against that.
send_codecs_.push_back(VideoCodec(0, "fake_video_codec"));
recv_codecs_.push_back(VideoCodec(0, "fake_video_codec"));
}
bool FakeVideoEngine::SetOptions(const VideoOptions& options) {
options_ = options;
return true;
}
VideoMediaChannel* FakeVideoEngine::CreateMediaChannel(
webrtc::Call* call,
const MediaConfig& config,
const VideoOptions& options,
const webrtc::CryptoOptions& crypto_options,
webrtc::VideoBitrateAllocatorFactory* video_bitrate_allocator_factory) {
if (fail_create_channel_) {
return nullptr;
}
FakeVideoMediaChannel* ch =
new FakeVideoMediaChannel(this, options, call->network_thread());
channels_.emplace_back(ch);
return ch;
}
FakeVideoMediaChannel* FakeVideoEngine::GetChannel(size_t index) {
return (channels_.size() > index) ? channels_[index] : nullptr;
}
void FakeVideoEngine::UnregisterChannel(VideoMediaChannel* channel) {
auto it = absl::c_find(channels_, channel);
RTC_DCHECK(it != channels_.end());
channels_.erase(it);
}
std::vector<VideoCodec> FakeVideoEngine::send_codecs() const {
return send_codecs_;
}
std::vector<VideoCodec> FakeVideoEngine::recv_codecs() const {
return recv_codecs_;
}
void FakeVideoEngine::SetSendCodecs(const std::vector<VideoCodec>& codecs) {
send_codecs_ = codecs;
}
void FakeVideoEngine::SetRecvCodecs(const std::vector<VideoCodec>& codecs) {
recv_codecs_ = codecs;
}
bool FakeVideoEngine::SetCapture(bool capture) {
capture_ = capture;
return true;
}
std::vector<webrtc::RtpHeaderExtensionCapability>
FakeVideoEngine::GetRtpHeaderExtensions() const {
return header_extensions_;
}
void FakeVideoEngine::SetRtpHeaderExtensions(
std::vector<webrtc::RtpHeaderExtensionCapability> header_extensions) {
header_extensions_ = std::move(header_extensions);
}
FakeMediaEngine::FakeMediaEngine()
: CompositeMediaEngine(std::make_unique<FakeVoiceEngine>(),
std::make_unique<FakeVideoEngine>()),
voice_(static_cast<FakeVoiceEngine*>(&voice())),
video_(static_cast<FakeVideoEngine*>(&video())) {}
FakeMediaEngine::~FakeMediaEngine() {}
void FakeMediaEngine::SetAudioCodecs(const std::vector<AudioCodec>& codecs) {
voice_->SetCodecs(codecs);
}
void FakeMediaEngine::SetAudioRecvCodecs(
const std::vector<AudioCodec>& codecs) {
voice_->SetRecvCodecs(codecs);
}
void FakeMediaEngine::SetAudioSendCodecs(
const std::vector<AudioCodec>& codecs) {
voice_->SetSendCodecs(codecs);
}
void FakeMediaEngine::SetVideoCodecs(const std::vector<VideoCodec>& codecs) {
video_->SetSendCodecs(codecs);
video_->SetRecvCodecs(codecs);
}
FakeVoiceMediaChannel* FakeMediaEngine::GetVoiceChannel(size_t index) {
return voice_->GetChannel(index);
}
FakeVideoMediaChannel* FakeMediaEngine::GetVideoChannel(size_t index) {
return video_->GetChannel(index);
}
void FakeMediaEngine::set_fail_create_channel(bool fail) {
voice_->fail_create_channel_ = fail;
video_->fail_create_channel_ = fail;
}
} // namespace cricket