/* * 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 #include #include #include #include #include #include #include #include #include "absl/strings/match.h" #include "api/audio/audio_device.h" #include "api/audio_options.h" #include "api/call/audio_sink.h" #include "api/crypto/crypto_options.h" #include "api/environment/environment.h" #include "api/field_trials_view.h" #include "api/make_ref_counted.h" #include "api/rtp_parameters.h" #include "api/scoped_refptr.h" #include "api/task_queue/task_queue_base.h" #include "api/transport/rtp/rtp_source.h" #include "api/video/recordable_encoded_frame.h" #include "api/video/video_bitrate_allocator_factory.h" #include "api/video/video_sink_interface.h" #include "api/video/video_source_interface.h" #include "call/audio_state.h" #include "call/call.h" #include "media/base/audio_source.h" #include "media/base/codec.h" #include "media/base/media_channel.h" #include "media/base/media_config.h" #include "media/base/media_engine.h" #include "media/base/stream_params.h" #include "rtc_base/checks.h" #include "rtc_base/system/file_wrapper.h" namespace webrtc { FakeVoiceMediaReceiveChannel::DtmfInfo::DtmfInfo(uint32_t ssrc, int event_code, int duration) : ssrc(ssrc), event_code(event_code), duration(duration) {} FakeVoiceMediaReceiveChannel::VoiceChannelAudioSink::VoiceChannelAudioSink( AudioSource* source) : source_(source) { source_->SetSink(this); } FakeVoiceMediaReceiveChannel::VoiceChannelAudioSink::~VoiceChannelAudioSink() { if (source_) { source_->SetSink(nullptr); } } void FakeVoiceMediaReceiveChannel::VoiceChannelAudioSink::OnData( const void* /* audio_data */, int /* bits_per_sample */, int /* sample_rate */, size_t /* number_of_channels */, size_t /* number_of_frames */, std::optional /* absolute_capture_timestamp_ms */) {} void FakeVoiceMediaReceiveChannel::VoiceChannelAudioSink::OnClose() { source_ = nullptr; } AudioSource* FakeVoiceMediaReceiveChannel::VoiceChannelAudioSink::source() const { return source_; } FakeVoiceMediaReceiveChannel::FakeVoiceMediaReceiveChannel( const AudioOptions& options, TaskQueueBase* network_thread) : RtpReceiveChannelHelper( network_thread), max_bps_(-1) { output_scalings_[0] = 1.0; // For default channel. SetOptions(options); } FakeVoiceMediaReceiveChannel::~FakeVoiceMediaReceiveChannel() = default; const std::vector& FakeVoiceMediaReceiveChannel::recv_codecs() const { return recv_codecs_; } const std::vector& FakeVoiceMediaReceiveChannel::dtmf_info_queue() const { return dtmf_info_queue_; } const AudioOptions& FakeVoiceMediaReceiveChannel::options() const { return options_; } int FakeVoiceMediaReceiveChannel::max_bps() const { return max_bps_; } bool FakeVoiceMediaReceiveChannel::SetReceiverParameters( const AudioReceiverParameters& params) { set_recv_rtcp_parameters(params.rtcp); return (SetRecvCodecs(params.codecs) && SetRecvRtpHeaderExtensions(params.extensions)); } void FakeVoiceMediaReceiveChannel::SetPlayout(bool playout) { set_playout(playout); } bool FakeVoiceMediaReceiveChannel::HasSource(uint32_t ssrc) const { return local_sinks_.find(ssrc) != local_sinks_.end(); } bool FakeVoiceMediaReceiveChannel::AddRecvStream(const StreamParams& sp) { if (!RtpReceiveChannelHelper< VoiceMediaReceiveChannelInterface>::AddRecvStream(sp)) return false; output_scalings_[sp.first_ssrc()] = 1.0; output_delays_[sp.first_ssrc()] = 0; return true; } bool FakeVoiceMediaReceiveChannel::RemoveRecvStream(uint32_t ssrc) { if (!RtpReceiveChannelHelper< VoiceMediaReceiveChannelInterface>::RemoveRecvStream(ssrc)) return false; output_scalings_.erase(ssrc); output_delays_.erase(ssrc); return true; } bool FakeVoiceMediaReceiveChannel::SetOutputVolume(uint32_t ssrc, double volume) { if (output_scalings_.find(ssrc) != output_scalings_.end()) { output_scalings_[ssrc] = volume; return true; } return false; } bool FakeVoiceMediaReceiveChannel::SetDefaultOutputVolume(double volume) { for (auto& entry : output_scalings_) { entry.second = volume; } return true; } bool FakeVoiceMediaReceiveChannel::GetOutputVolume(uint32_t ssrc, double* volume) { if (output_scalings_.find(ssrc) == output_scalings_.end()) return false; *volume = output_scalings_[ssrc]; return true; } bool FakeVoiceMediaReceiveChannel::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; } } std::optional FakeVoiceMediaReceiveChannel::GetBaseMinimumPlayoutDelayMs( uint32_t ssrc) const { const auto it = output_delays_.find(ssrc); if (it != output_delays_.end()) { return it->second; } return std::nullopt; } bool FakeVoiceMediaReceiveChannel::GetStats( VoiceMediaReceiveInfo* /* info */, bool /* get_and_clear_legacy_stats */) { return false; } void FakeVoiceMediaReceiveChannel::SetRawAudioSink( uint32_t /* ssrc */, std::unique_ptr sink) { sink_ = std::move(sink); } void FakeVoiceMediaReceiveChannel::SetDefaultRawAudioSink( std::unique_ptr sink) { sink_ = std::move(sink); } std::vector FakeVoiceMediaReceiveChannel::GetSources( uint32_t /* ssrc */) const { return std::vector(); } bool FakeVoiceMediaReceiveChannel::SetRecvCodecs( const std::vector& codecs) { if (fail_set_recv_codecs()) { // Fake the failure in SetRecvCodecs. return false; } recv_codecs_ = codecs; return true; } bool FakeVoiceMediaReceiveChannel::SetMaxSendBandwidth(int bps) { max_bps_ = bps; return true; } bool FakeVoiceMediaReceiveChannel::SetOptions(const AudioOptions& options) { // Does a "merge" of current options and set options. options_.SetAll(options); return true; } FakeVoiceMediaSendChannel::DtmfInfo::DtmfInfo(uint32_t ssrc, int event_code, int duration) : ssrc(ssrc), event_code(event_code), duration(duration) {} FakeVoiceMediaSendChannel::VoiceChannelAudioSink::VoiceChannelAudioSink( AudioSource* source) : source_(source) { source_->SetSink(this); } FakeVoiceMediaSendChannel::VoiceChannelAudioSink::~VoiceChannelAudioSink() { if (source_) { source_->SetSink(nullptr); } } void FakeVoiceMediaSendChannel::VoiceChannelAudioSink::OnData( const void* /* audio_data */, int /* bits_per_sample */, int /* sample_rate */, size_t /* number_of_channels */, size_t /* number_of_frames */, std::optional /* absolute_capture_timestamp_ms */) {} void FakeVoiceMediaSendChannel::VoiceChannelAudioSink::OnClose() { source_ = nullptr; } AudioSource* FakeVoiceMediaSendChannel::VoiceChannelAudioSink::source() const { return source_; } FakeVoiceMediaSendChannel::FakeVoiceMediaSendChannel( const AudioOptions& options, TaskQueueBase* network_thread) : RtpSendChannelHelper(network_thread), max_bps_(-1) { output_scalings_[0] = 1.0; // For default channel. SetOptions(options); } FakeVoiceMediaSendChannel::~FakeVoiceMediaSendChannel() = default; const std::vector& FakeVoiceMediaSendChannel::send_codecs() const { return send_codecs_; } std::optional FakeVoiceMediaSendChannel::GetSendCodec() const { if (!send_codecs_.empty()) { return send_codecs_.front(); } return std::nullopt; } const std::vector& FakeVoiceMediaSendChannel::dtmf_info_queue() const { return dtmf_info_queue_; } const AudioOptions& FakeVoiceMediaSendChannel::options() const { return options_; } int FakeVoiceMediaSendChannel::max_bps() const { return max_bps_; } bool FakeVoiceMediaSendChannel::SetSenderParameters( const AudioSenderParameter& params) { set_send_rtcp_parameters(params.rtcp); SetExtmapAllowMixed(params.extmap_allow_mixed); return (SetSendCodecs(params.codecs) && SetSendRtpHeaderExtensions(params.extensions) && SetMaxSendBandwidth(params.max_bandwidth_bps) && SetOptions(params.options)); } void FakeVoiceMediaSendChannel::SetSend(bool send) { set_sending(send); } bool FakeVoiceMediaSendChannel::SetAudioSend(uint32_t ssrc, bool enable, const AudioOptions* options, AudioSource* source) { if (!SetLocalSource(ssrc, source)) { return false; } if (!RtpSendChannelHelper::MuteStream( ssrc, !enable)) { return false; } if (enable && options) { return SetOptions(*options); } return true; } bool FakeVoiceMediaSendChannel::HasSource(uint32_t ssrc) const { return local_sinks_.find(ssrc) != local_sinks_.end(); } bool FakeVoiceMediaSendChannel::CanInsertDtmf() { for (std::vector::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 FakeVoiceMediaSendChannel::InsertDtmf(uint32_t ssrc, int event_code, int duration) { dtmf_info_queue_.push_back(DtmfInfo(ssrc, event_code, duration)); return true; } bool FakeVoiceMediaSendChannel::GetOutputVolume(uint32_t ssrc, double* volume) { if (output_scalings_.find(ssrc) == output_scalings_.end()) return false; *volume = output_scalings_[ssrc]; return true; } bool FakeVoiceMediaSendChannel::GetStats(VoiceMediaSendInfo* /* info */) { return false; } bool FakeVoiceMediaSendChannel::SetSendCodecs( const std::vector& codecs) { if (fail_set_send_codecs()) { // Fake the failure in SetSendCodecs. return false; } send_codecs_ = codecs; return true; } bool FakeVoiceMediaSendChannel::SetMaxSendBandwidth(int bps) { max_bps_ = bps; return true; } bool FakeVoiceMediaSendChannel::SetOptions(const AudioOptions& options) { // Does a "merge" of current options and set options. options_.SetAll(options); return true; } bool FakeVoiceMediaSendChannel::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(source))); } } else { if (it != local_sinks_.end()) { local_sinks_.erase(it); } } return true; } bool CompareDtmfInfo(const FakeVoiceMediaSendChannel::DtmfInfo& info, uint32_t ssrc, int event_code, int duration) { return (info.duration == duration && info.event_code == event_code && info.ssrc == ssrc); } FakeVideoMediaSendChannel::FakeVideoMediaSendChannel( const VideoOptions& options, TaskQueueBase* network_thread) : RtpSendChannelHelper(network_thread), max_bps_(-1) { SetOptions(options); } FakeVideoMediaSendChannel::~FakeVideoMediaSendChannel() = default; const std::vector& FakeVideoMediaSendChannel::send_codecs() const { return send_codecs_; } const std::vector& FakeVideoMediaSendChannel::codecs() const { return send_codecs(); } const VideoOptions& FakeVideoMediaSendChannel::options() const { return options_; } int FakeVideoMediaSendChannel::max_bps() const { return max_bps_; } bool FakeVideoMediaSendChannel::SetSenderParameters( const VideoSenderParameters& params) { set_send_rtcp_parameters(params.rtcp); SetExtmapAllowMixed(params.extmap_allow_mixed); return (SetSendCodecs(params.codecs) && SetSendRtpHeaderExtensions(params.extensions) && SetMaxSendBandwidth(params.max_bandwidth_bps)); } std::optional FakeVideoMediaSendChannel::GetSendCodec() const { if (send_codecs_.empty()) { return std::nullopt; } return send_codecs_[0]; } bool FakeVideoMediaSendChannel::SetSend(bool send) { return set_sending(send); } bool FakeVideoMediaSendChannel::SetVideoSend( uint32_t ssrc, const VideoOptions* options, VideoSourceInterface* source) { if (options) { if (!SetOptions(*options)) { return false; } } sources_[ssrc] = source; return true; } bool FakeVideoMediaSendChannel::HasSource(uint32_t ssrc) const { return sources_.find(ssrc) != sources_.end() && sources_.at(ssrc) != nullptr; } void FakeVideoMediaSendChannel::FillBitrateInfo( BandwidthEstimationInfo* /* bwe_info */) {} bool FakeVideoMediaSendChannel::GetStats(VideoMediaSendInfo* /* info */) { return false; } bool FakeVideoMediaSendChannel::SetSendCodecs( const std::vector& codecs) { if (fail_set_send_codecs()) { // Fake the failure in SetSendCodecs. return false; } send_codecs_ = codecs; return true; } bool FakeVideoMediaSendChannel::SetOptions(const VideoOptions& options) { options_ = options; return true; } bool FakeVideoMediaSendChannel::SetMaxSendBandwidth(int bps) { max_bps_ = bps; return true; } void FakeVideoMediaSendChannel::GenerateSendKeyFrame( uint32_t /* ssrc */, const std::vector& /* rids */) {} FakeVideoMediaReceiveChannel::FakeVideoMediaReceiveChannel( const VideoOptions& options, TaskQueueBase* network_thread) : RtpReceiveChannelHelper( network_thread), max_bps_(-1) { SetOptions(options); } FakeVideoMediaReceiveChannel::~FakeVideoMediaReceiveChannel() = default; const std::vector& FakeVideoMediaReceiveChannel::recv_codecs() const { return recv_codecs_; } bool FakeVideoMediaReceiveChannel::rendering() const { return playout(); } const VideoOptions& FakeVideoMediaReceiveChannel::options() const { return options_; } const std::map*>& FakeVideoMediaReceiveChannel::sinks() const { return sinks_; } int FakeVideoMediaReceiveChannel::max_bps() const { return max_bps_; } bool FakeVideoMediaReceiveChannel::SetReceiverParameters( const VideoReceiverParameters& params) { set_recv_rtcp_parameters(params.rtcp); return (SetRecvCodecs(params.codecs) && SetRecvRtpHeaderExtensions(params.extensions)); } bool FakeVideoMediaReceiveChannel::SetSink( uint32_t ssrc, VideoSinkInterface* sink) { auto it = sinks_.find(ssrc); if (it == sinks_.end()) { return false; } it->second = sink; return true; } void FakeVideoMediaReceiveChannel::SetDefaultSink( VideoSinkInterface* /* sink */) {} bool FakeVideoMediaReceiveChannel::HasSink(uint32_t ssrc) const { return sinks_.find(ssrc) != sinks_.end() && sinks_.at(ssrc) != nullptr; } bool FakeVideoMediaReceiveChannel::HasSource(uint32_t ssrc) const { return sources_.find(ssrc) != sources_.end() && sources_.at(ssrc) != nullptr; } bool FakeVideoMediaReceiveChannel::AddRecvStream(const StreamParams& sp) { if (!RtpReceiveChannelHelper< VideoMediaReceiveChannelInterface>::AddRecvStream(sp)) return false; sinks_[sp.first_ssrc()] = nullptr; output_delays_[sp.first_ssrc()] = 0; return true; } bool FakeVideoMediaReceiveChannel::RemoveRecvStream(uint32_t ssrc) { if (!RtpReceiveChannelHelper< VideoMediaReceiveChannelInterface>::RemoveRecvStream(ssrc)) return false; sinks_.erase(ssrc); output_delays_.erase(ssrc); return true; } std::vector FakeVideoMediaReceiveChannel::GetSources( uint32_t /* ssrc */) const { return {}; } bool FakeVideoMediaReceiveChannel::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; } } std::optional FakeVideoMediaReceiveChannel::GetBaseMinimumPlayoutDelayMs( uint32_t ssrc) const { const auto it = output_delays_.find(ssrc); if (it != output_delays_.end()) { return it->second; } return std::nullopt; } bool FakeVideoMediaReceiveChannel::SetRecvCodecs( const std::vector& codecs) { if (fail_set_recv_codecs()) { // Fake the failure in SetRecvCodecs. return false; } recv_codecs_ = codecs; return true; } bool FakeVideoMediaReceiveChannel::SetOptions(const VideoOptions& options) { options_ = options; return true; } bool FakeVideoMediaReceiveChannel::SetMaxSendBandwidth(int bps) { max_bps_ = bps; return true; } void FakeVideoMediaReceiveChannel::SetRecordableEncodedFrameCallback( uint32_t /* ssrc */, std::function /* callback */) {} void FakeVideoMediaReceiveChannel::ClearRecordableEncodedFrameCallback( uint32_t /* ssrc */) {} void FakeVideoMediaReceiveChannel::RequestRecvKeyFrame(uint32_t /* ssrc */) {} bool FakeVideoMediaReceiveChannel::GetStats(VideoMediaReceiveInfo* /* info */) { return false; } FakeVoiceEngine::FakeVoiceEngine() : encoder_factory_(make_ref_counted(this)), decoder_factory_(make_ref_counted(this)) { // Add a fake audio codec. Note that the name must not be "" as there are // sanity checks against that. SetCodecs({CreateAudioCodec(101, "fake_audio_codec", 8000, 1)}); } void FakeVoiceEngine::Init() {} void FakeVoiceEngine::Terminate() {} scoped_refptr FakeVoiceEngine::GetAudioState() const { return scoped_refptr(); } std::unique_ptr FakeVoiceEngine::CreateSendChannel(const Environment& /*env*/, Call* call, const MediaConfig& /* config */, const AudioOptions& options, const CryptoOptions& /* crypto_options */) { std::unique_ptr ch = std::make_unique(options, call->network_thread()); return ch; } std::unique_ptr FakeVoiceEngine::CreateReceiveChannel( const Environment& /*env*/, Call* call, const MediaConfig& /* config */, const AudioOptions& options, const CryptoOptions& /* crypto_options */) { std::unique_ptr ch = std::make_unique(options, call->network_thread()); return ch; } const std::vector& FakeVoiceEngine::LegacySendCodecs() const { return send_codecs_; } const std::vector& FakeVoiceEngine::LegacyRecvCodecs() const { return recv_codecs_; } void FakeVoiceEngine::SetCodecs(const std::vector& codecs) { send_codecs_ = codecs; recv_codecs_ = codecs; } void FakeVoiceEngine::SetRecvCodecs(const std::vector& codecs) { recv_codecs_ = codecs; } void FakeVoiceEngine::SetSendCodecs(const std::vector& codecs) { send_codecs_ = codecs; } int FakeVoiceEngine::GetInputLevel() { return 0; } bool FakeVoiceEngine::StartAecDump(FileWrapper /* file */, int64_t /* max_size_bytes */) { return false; } std::optional FakeVoiceEngine::GetAudioDeviceStats() { return std::nullopt; } void FakeVoiceEngine::StopAecDump() {} std::vector FakeVoiceEngine::GetRtpHeaderExtensions( const FieldTrialsView* field_trials) const { return header_extensions_; } void FakeVoiceEngine::SetRtpHeaderExtensions( std::vector header_extensions) { header_extensions_ = std::move(header_extensions); } FakeVideoEngine::FakeVideoEngine() : capture_(false) { // Add a fake video codec. Note that the name must not be "" as there are // sanity checks against that. send_codecs_.push_back(CreateVideoCodec(111, "fake_video_codec")); recv_codecs_.push_back(CreateVideoCodec(111, "fake_video_codec")); } bool FakeVideoEngine::SetOptions(const VideoOptions& options) { options_ = options; return true; } std::unique_ptr FakeVideoEngine::CreateSendChannel( const Environment& /* env */, Call* call, const MediaConfig& /* config */, const VideoOptions& options, const CryptoOptions& /* crypto_options */, VideoBitrateAllocatorFactory* /* video_bitrate_allocator_factory */) { std::unique_ptr ch = std::make_unique(options, call->network_thread()); return ch; } std::unique_ptr FakeVideoEngine::CreateReceiveChannel( const Environment& /* env */, Call* call, const MediaConfig& /* config */, const VideoOptions& options, const CryptoOptions& /* crypto_options */) { std::unique_ptr ch = std::make_unique(options, call->network_thread()); return ch; } std::vector FakeVideoEngine::LegacySendCodecs(bool use_rtx) const { if (use_rtx) { return send_codecs_; } else { std::vector non_rtx_codecs; for (auto& codec : send_codecs_) { if (codec.name != "rtx") { non_rtx_codecs.push_back(codec); } } return non_rtx_codecs; } } std::vector FakeVideoEngine::LegacyRecvCodecs(bool /* use_rtx */) const { return recv_codecs_; } void FakeVideoEngine::SetSendCodecs(const std::vector& codecs) { send_codecs_ = codecs; } void FakeVideoEngine::SetRecvCodecs(const std::vector& codecs) { recv_codecs_ = codecs; } bool FakeVideoEngine::SetCapture(bool capture) { capture_ = capture; return true; } std::vector FakeVideoEngine::GetRtpHeaderExtensions( const FieldTrialsView* field_trials) const { return header_extensions_; } void FakeVideoEngine::SetRtpHeaderExtensions( std::vector header_extensions) { header_extensions_ = std::move(header_extensions); } FakeMediaEngine::FakeMediaEngine() : CompositeMediaEngine(std::make_unique(), std::make_unique()), voice_(static_cast(&voice())), video_(static_cast(&video())) {} FakeMediaEngine::~FakeMediaEngine() {} void FakeMediaEngine::SetAudioCodecs(const std::vector& codecs) { voice_->SetCodecs(codecs); } void FakeMediaEngine::SetAudioRecvCodecs(const std::vector& codecs) { voice_->SetRecvCodecs(codecs); } void FakeMediaEngine::SetAudioSendCodecs(const std::vector& codecs) { voice_->SetSendCodecs(codecs); } void FakeMediaEngine::SetVideoCodecs(const std::vector& codecs) { video_->SetSendCodecs(codecs); video_->SetRecvCodecs(codecs); } void FakeMediaEngine::SetVideoRecvCodecs(const std::vector& codecs) { video_->SetRecvCodecs(codecs); } void FakeMediaEngine::SetVideoSendCodecs(const std::vector& codecs) { video_->SetSendCodecs(codecs); } } // namespace webrtc