/* * Copyright (c) 2004 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. */ #ifndef WEBRTC_MEDIA_BASE_FAKEMEDIAENGINE_H_ #define WEBRTC_MEDIA_BASE_FAKEMEDIAENGINE_H_ #include #include #include #include #include #include #include "webrtc/audio_sink.h" #include "webrtc/base/copyonwritebuffer.h" #include "webrtc/base/networkroute.h" #include "webrtc/base/stringutils.h" #include "webrtc/media/base/audiosource.h" #include "webrtc/media/base/mediaengine.h" #include "webrtc/media/base/rtputils.h" #include "webrtc/media/base/streamparams.h" #include "webrtc/p2p/base/sessiondescription.h" using webrtc::RtpExtension; namespace cricket { class FakeMediaEngine; class FakeVideoEngine; class FakeVoiceEngine; // A common helper class that handles sending and receiving RTP/RTCP packets. template class RtpHelper : public Base { public: RtpHelper() : sending_(false), playout_(false), fail_set_send_codecs_(false), fail_set_recv_codecs_(false), send_ssrc_(0), ready_to_send_(false) {} const std::vector& recv_extensions() { return recv_extensions_; } const std::vector& send_extensions() { return send_extensions_; } bool sending() const { return sending_; } bool playout() const { return playout_; } const std::list& rtp_packets() const { return rtp_packets_; } const std::list& rtcp_packets() const { return rtcp_packets_; } bool SendRtp(const void* data, size_t len, const rtc::PacketOptions& options) { if (!sending_) { return false; } rtc::CopyOnWriteBuffer packet(reinterpret_cast(data), len, kMaxRtpPacketLen); return Base::SendPacket(&packet, options); } bool SendRtcp(const void* data, size_t len) { rtc::CopyOnWriteBuffer packet(reinterpret_cast(data), len, kMaxRtpPacketLen); return Base::SendRtcp(&packet, rtc::PacketOptions()); } bool CheckRtp(const void* data, size_t len) { bool success = !rtp_packets_.empty(); if (success) { std::string packet = rtp_packets_.front(); rtp_packets_.pop_front(); success = (packet == std::string(static_cast(data), len)); } return success; } bool CheckRtcp(const void* data, size_t len) { bool success = !rtcp_packets_.empty(); if (success) { std::string packet = rtcp_packets_.front(); rtcp_packets_.pop_front(); success = (packet == std::string(static_cast(data), len)); } return success; } bool CheckNoRtp() { return rtp_packets_.empty(); } bool CheckNoRtcp() { return rtcp_packets_.empty(); } void set_fail_set_send_codecs(bool fail) { fail_set_send_codecs_ = fail; } void set_fail_set_recv_codecs(bool fail) { fail_set_recv_codecs_ = fail; } virtual bool AddSendStream(const StreamParams& sp) { if (std::find(send_streams_.begin(), send_streams_.end(), sp) != send_streams_.end()) { return false; } send_streams_.push_back(sp); rtp_send_parameters_[sp.first_ssrc()] = CreateRtpParametersWithOneEncoding(); return true; } virtual bool RemoveSendStream(uint32_t ssrc) { auto parameters_iterator = rtp_send_parameters_.find(ssrc); if (parameters_iterator != rtp_send_parameters_.end()) { rtp_send_parameters_.erase(parameters_iterator); } return RemoveStreamBySsrc(&send_streams_, ssrc); } virtual bool AddRecvStream(const StreamParams& sp) { if (std::find(receive_streams_.begin(), receive_streams_.end(), sp) != receive_streams_.end()) { return false; } receive_streams_.push_back(sp); rtp_receive_parameters_[sp.first_ssrc()] = CreateRtpParametersWithOneEncoding(); return true; } virtual bool RemoveRecvStream(uint32_t ssrc) { auto parameters_iterator = rtp_receive_parameters_.find(ssrc); if (parameters_iterator != rtp_receive_parameters_.end()) { rtp_receive_parameters_.erase(parameters_iterator); } return RemoveStreamBySsrc(&receive_streams_, ssrc); } virtual webrtc::RtpParameters GetRtpSendParameters(uint32_t ssrc) const { auto parameters_iterator = rtp_send_parameters_.find(ssrc); if (parameters_iterator != rtp_send_parameters_.end()) { return parameters_iterator->second; } return webrtc::RtpParameters(); } virtual bool SetRtpSendParameters(uint32_t ssrc, const webrtc::RtpParameters& parameters) { auto parameters_iterator = rtp_send_parameters_.find(ssrc); if (parameters_iterator != rtp_send_parameters_.end()) { parameters_iterator->second = parameters; return true; } // Replicate the behavior of the real media channel: return false // when setting parameters for unknown SSRCs. return false; } virtual webrtc::RtpParameters GetRtpReceiveParameters(uint32_t ssrc) const { auto parameters_iterator = rtp_receive_parameters_.find(ssrc); if (parameters_iterator != rtp_receive_parameters_.end()) { return parameters_iterator->second; } return webrtc::RtpParameters(); } virtual bool SetRtpReceiveParameters( uint32_t ssrc, const webrtc::RtpParameters& parameters) { auto parameters_iterator = rtp_receive_parameters_.find(ssrc); if (parameters_iterator != rtp_receive_parameters_.end()) { parameters_iterator->second = parameters; return true; } // Replicate the behavior of the real media channel: return false // when setting parameters for unknown SSRCs. return false; } bool IsStreamMuted(uint32_t ssrc) const { bool ret = muted_streams_.find(ssrc) != muted_streams_.end(); // If |ssrc = 0| check if the first send stream is muted. if (!ret && ssrc == 0 && !send_streams_.empty()) { return muted_streams_.find(send_streams_[0].first_ssrc()) != muted_streams_.end(); } return ret; } const std::vector& send_streams() const { return send_streams_; } const std::vector& recv_streams() const { return receive_streams_; } bool HasRecvStream(uint32_t ssrc) const { return GetStreamBySsrc(receive_streams_, ssrc) != nullptr; } bool HasSendStream(uint32_t ssrc) const { return GetStreamBySsrc(send_streams_, ssrc) != nullptr; } // TODO(perkj): This is to support legacy unit test that only check one // sending stream. uint32_t send_ssrc() const { if (send_streams_.empty()) return 0; return send_streams_[0].first_ssrc(); } // TODO(perkj): This is to support legacy unit test that only check one // sending stream. const std::string rtcp_cname() { if (send_streams_.empty()) return ""; return send_streams_[0].cname; } bool ready_to_send() const { return ready_to_send_; } rtc::NetworkRoute last_network_route() const { return last_network_route_; } int num_network_route_changes() const { return num_network_route_changes_; } void set_num_network_route_changes(int changes) { num_network_route_changes_ = changes; } protected: bool MuteStream(uint32_t ssrc, bool mute) { if (!HasSendStream(ssrc) && ssrc != 0) { return false; } if (mute) { muted_streams_.insert(ssrc); } else { muted_streams_.erase(ssrc); } return true; } bool set_sending(bool send) { sending_ = send; return true; } void set_playout(bool playout) { playout_ = playout; } bool SetRecvRtpHeaderExtensions(const std::vector& extensions) { recv_extensions_ = extensions; return true; } bool SetSendRtpHeaderExtensions(const std::vector& extensions) { send_extensions_ = extensions; return true; } virtual void OnPacketReceived(rtc::CopyOnWriteBuffer* packet, const rtc::PacketTime& packet_time) { rtp_packets_.push_back(std::string(packet->data(), packet->size())); } virtual void OnRtcpReceived(rtc::CopyOnWriteBuffer* packet, const rtc::PacketTime& packet_time) { rtcp_packets_.push_back(std::string(packet->data(), packet->size())); } virtual void OnReadyToSend(bool ready) { ready_to_send_ = ready; } virtual void OnNetworkRouteChanged(const std::string& transport_name, const rtc::NetworkRoute& network_route) { last_network_route_ = network_route; ++num_network_route_changes_; } bool fail_set_send_codecs() const { return fail_set_send_codecs_; } bool fail_set_recv_codecs() const { return fail_set_recv_codecs_; } private: bool sending_; bool playout_; std::vector recv_extensions_; std::vector send_extensions_; std::list rtp_packets_; std::list rtcp_packets_; std::vector send_streams_; std::vector receive_streams_; std::set muted_streams_; std::map rtp_send_parameters_; std::map rtp_receive_parameters_; bool fail_set_send_codecs_; bool fail_set_recv_codecs_; uint32_t send_ssrc_; std::string rtcp_cname_; bool ready_to_send_; rtc::NetworkRoute last_network_route_; int num_network_route_changes_ = 0; }; class FakeVoiceMediaChannel : public RtpHelper { public: struct DtmfInfo { DtmfInfo(uint32_t ssrc, int event_code, int duration) : ssrc(ssrc), event_code(event_code), duration(duration) {} uint32_t ssrc; int event_code; int duration; }; explicit FakeVoiceMediaChannel(FakeVoiceEngine* engine, const AudioOptions& options) : engine_(engine), time_since_last_typing_(-1), max_bps_(-1) { output_scalings_[0] = 1.0; // For default channel. SetOptions(options); } ~FakeVoiceMediaChannel(); const std::vector& recv_codecs() const { return recv_codecs_; } const std::vector& send_codecs() const { return send_codecs_; } const std::vector& codecs() const { return send_codecs(); } const std::vector& dtmf_info_queue() const { return dtmf_info_queue_; } const AudioOptions& options() const { return options_; } int max_bps() const { return max_bps_; } virtual bool SetSendParameters(const AudioSendParameters& params) { return (SetSendCodecs(params.codecs) && SetSendRtpHeaderExtensions(params.extensions) && SetMaxSendBandwidth(params.max_bandwidth_bps) && SetOptions(params.options)); } virtual bool SetRecvParameters(const AudioRecvParameters& params) { return (SetRecvCodecs(params.codecs) && SetRecvRtpHeaderExtensions(params.extensions)); } virtual bool SetPlayout(bool playout) { set_playout(playout); return true; } virtual void SetSend(bool send) { set_sending(send); } virtual bool SetAudioSend(uint32_t ssrc, bool enable, const AudioOptions* options, AudioSource* source) { if (!SetLocalSource(ssrc, source)) { return false; } if (!RtpHelper::MuteStream(ssrc, !enable)) { return false; } if (enable && options) { return SetOptions(*options); } return true; } virtual bool AddRecvStream(const StreamParams& sp) { if (!RtpHelper::AddRecvStream(sp)) return false; output_scalings_[sp.first_ssrc()] = 1.0; return true; } virtual bool RemoveRecvStream(uint32_t ssrc) { if (!RtpHelper::RemoveRecvStream(ssrc)) return false; output_scalings_.erase(ssrc); return true; } virtual bool GetActiveStreams(AudioInfo::StreamList* streams) { return true; } virtual int GetOutputLevel() { return 0; } void set_time_since_last_typing(int ms) { time_since_last_typing_ = ms; } virtual int GetTimeSinceLastTyping() { return time_since_last_typing_; } virtual void SetTypingDetectionParameters( int time_window, int cost_per_typing, int reporting_threshold, int penalty_decay, int type_event_delay) {} virtual bool CanInsertDtmf() { for (std::vector::const_iterator it = send_codecs_.begin(); it != send_codecs_.end(); ++it) { // Find the DTMF telephone event "codec". if (_stricmp(it->name.c_str(), "telephone-event") == 0) { return true; } } return false; } virtual bool InsertDtmf(uint32_t ssrc, int event_code, int duration) { dtmf_info_queue_.push_back(DtmfInfo(ssrc, event_code, duration)); return true; } virtual bool SetOutputVolume(uint32_t ssrc, double volume) { if (0 == ssrc) { std::map::iterator it; for (it = output_scalings_.begin(); it != output_scalings_.end(); ++it) { it->second = volume; } return true; } else if (output_scalings_.find(ssrc) != output_scalings_.end()) { output_scalings_[ssrc] = volume; return true; } return false; } bool GetOutputVolume(uint32_t ssrc, double* volume) { if (output_scalings_.find(ssrc) == output_scalings_.end()) return false; *volume = output_scalings_[ssrc]; return true; } virtual bool GetStats(VoiceMediaInfo* info) { return false; } virtual void SetRawAudioSink( uint32_t ssrc, std::unique_ptr sink) { sink_ = std::move(sink); } private: class VoiceChannelAudioSink : public AudioSource::Sink { public: explicit VoiceChannelAudioSink(AudioSource* source) : source_(source) { source_->SetSink(this); } virtual ~VoiceChannelAudioSink() { if (source_) { source_->SetSink(nullptr); } } void OnData(const void* audio_data, int bits_per_sample, int sample_rate, size_t number_of_channels, size_t number_of_frames) override {} void OnClose() override { source_ = nullptr; } AudioSource* source() const { return source_; } private: AudioSource* source_; }; bool SetRecvCodecs(const std::vector& codecs) { if (fail_set_recv_codecs()) { // Fake the failure in SetRecvCodecs. return false; } recv_codecs_ = codecs; return true; } bool SetSendCodecs(const std::vector& codecs) { if (fail_set_send_codecs()) { // Fake the failure in SetSendCodecs. return false; } send_codecs_ = codecs; return true; } bool SetMaxSendBandwidth(int bps) { max_bps_ = bps; return true; } bool SetOptions(const AudioOptions& options) { // Does a "merge" of current options and set options. options_.SetAll(options); return true; } bool SetLocalSource(uint32_t ssrc, AudioSource* source) { auto it = local_sinks_.find(ssrc); if (source) { if (it != local_sinks_.end()) { ASSERT(it->second->source() == source); } else { local_sinks_.insert( std::make_pair(ssrc, new VoiceChannelAudioSink(source))); } } else { if (it != local_sinks_.end()) { delete it->second; local_sinks_.erase(it); } } return true; } FakeVoiceEngine* engine_; std::vector recv_codecs_; std::vector send_codecs_; std::map output_scalings_; std::vector dtmf_info_queue_; int time_since_last_typing_; AudioOptions options_; std::map local_sinks_; std::unique_ptr sink_; int max_bps_; }; // A helper function to compare the FakeVoiceMediaChannel::DtmfInfo. inline 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); } class FakeVideoMediaChannel : public RtpHelper { public: explicit FakeVideoMediaChannel(FakeVideoEngine* engine, const VideoOptions& options) : engine_(engine), max_bps_(-1) { SetOptions(options); } ~FakeVideoMediaChannel(); const std::vector& recv_codecs() const { return recv_codecs_; } const std::vector& send_codecs() const { return send_codecs_; } const std::vector& codecs() const { return send_codecs(); } bool rendering() const { return playout(); } const VideoOptions& options() const { return options_; } const std::map*>& sinks() const { return sinks_; } int max_bps() const { return max_bps_; } bool SetSendParameters(const VideoSendParameters& params) override { return (SetSendCodecs(params.codecs) && SetSendRtpHeaderExtensions(params.extensions) && SetMaxSendBandwidth(params.max_bandwidth_bps)); } bool SetRecvParameters(const VideoRecvParameters& params) override { return (SetRecvCodecs(params.codecs) && SetRecvRtpHeaderExtensions(params.extensions)); } bool AddSendStream(const StreamParams& sp) override { return RtpHelper::AddSendStream(sp); } bool RemoveSendStream(uint32_t ssrc) override { return RtpHelper::RemoveSendStream(ssrc); } bool GetSendCodec(VideoCodec* send_codec) override { if (send_codecs_.empty()) { return false; } *send_codec = send_codecs_[0]; return true; } bool SetSink(uint32_t ssrc, rtc::VideoSinkInterface* sink) override { if (ssrc != 0 && sinks_.find(ssrc) == sinks_.end()) { return false; } if (ssrc != 0) { sinks_[ssrc] = sink; } return true; } bool SetSend(bool send) override { return set_sending(send); } bool SetVideoSend( uint32_t ssrc, bool enable, const VideoOptions* options, rtc::VideoSourceInterface* source) override { if (!RtpHelper::MuteStream(ssrc, !enable)) { return false; } if (enable && options) { return SetOptions(*options); } sources_[ssrc] = source; return true; } bool HasSource(uint32_t ssrc) const { return sources_.find(ssrc) != sources_.end(); } bool AddRecvStream(const StreamParams& sp) override { if (!RtpHelper::AddRecvStream(sp)) return false; sinks_[sp.first_ssrc()] = NULL; return true; } bool RemoveRecvStream(uint32_t ssrc) override { if (!RtpHelper::RemoveRecvStream(ssrc)) return false; sinks_.erase(ssrc); return true; } bool GetStats(VideoMediaInfo* info) override { return false; } private: bool SetRecvCodecs(const std::vector& codecs) { if (fail_set_recv_codecs()) { // Fake the failure in SetRecvCodecs. return false; } recv_codecs_ = codecs; return true; } bool SetSendCodecs(const std::vector& codecs) { if (fail_set_send_codecs()) { // Fake the failure in SetSendCodecs. return false; } send_codecs_ = codecs; return true; } bool SetOptions(const VideoOptions& options) { options_ = options; return true; } bool SetMaxSendBandwidth(int bps) { max_bps_ = bps; return true; } FakeVideoEngine* engine_; std::vector recv_codecs_; std::vector send_codecs_; std::map*> sinks_; std::map*> sources_; VideoOptions options_; int max_bps_; }; // Dummy option class, needed for the DataTraits abstraction in // channel_unittest.c. class DataOptions {}; class FakeDataMediaChannel : public RtpHelper { public: explicit FakeDataMediaChannel(void* unused, const DataOptions& options) : send_blocked_(false), max_bps_(-1) {} ~FakeDataMediaChannel() {} const std::vector& recv_codecs() const { return recv_codecs_; } const std::vector& send_codecs() const { return send_codecs_; } const std::vector& codecs() const { return send_codecs(); } int max_bps() const { return max_bps_; } virtual bool SetSendParameters(const DataSendParameters& params) { return (SetSendCodecs(params.codecs) && SetMaxSendBandwidth(params.max_bandwidth_bps)); } virtual bool SetRecvParameters(const DataRecvParameters& params) { return SetRecvCodecs(params.codecs); } virtual bool SetSend(bool send) { return set_sending(send); } virtual bool SetReceive(bool receive) { set_playout(receive); return true; } virtual bool AddRecvStream(const StreamParams& sp) { if (!RtpHelper::AddRecvStream(sp)) return false; return true; } virtual bool RemoveRecvStream(uint32_t ssrc) { if (!RtpHelper::RemoveRecvStream(ssrc)) return false; return true; } virtual bool SendData(const SendDataParams& params, const rtc::CopyOnWriteBuffer& payload, SendDataResult* result) { if (send_blocked_) { *result = SDR_BLOCK; return false; } else { last_sent_data_params_ = params; last_sent_data_ = std::string(payload.data(), payload.size()); return true; } } SendDataParams last_sent_data_params() { return last_sent_data_params_; } std::string last_sent_data() { return last_sent_data_; } bool is_send_blocked() { return send_blocked_; } void set_send_blocked(bool blocked) { send_blocked_ = blocked; } private: bool SetRecvCodecs(const std::vector& codecs) { if (fail_set_recv_codecs()) { // Fake the failure in SetRecvCodecs. return false; } recv_codecs_ = codecs; return true; } bool SetSendCodecs(const std::vector& codecs) { if (fail_set_send_codecs()) { // Fake the failure in SetSendCodecs. return false; } send_codecs_ = codecs; return true; } bool SetMaxSendBandwidth(int bps) { max_bps_ = bps; return true; } std::vector recv_codecs_; std::vector send_codecs_; SendDataParams last_sent_data_params_; std::string last_sent_data_; bool send_blocked_; int max_bps_; }; // A base class for all of the shared parts between FakeVoiceEngine // and FakeVideoEngine. class FakeBaseEngine { public: FakeBaseEngine() : options_changed_(false), fail_create_channel_(false) {} void set_fail_create_channel(bool fail) { fail_create_channel_ = fail; } RtpCapabilities GetCapabilities() const { return capabilities_; } void set_rtp_header_extensions(const std::vector& extensions) { capabilities_.header_extensions = extensions; } void set_rtp_header_extensions( const std::vector& extensions) { for (const cricket::RtpHeaderExtension& ext : extensions) { RtpExtension webrtc_ext; webrtc_ext.uri = ext.uri; webrtc_ext.id = ext.id; capabilities_.header_extensions.push_back(webrtc_ext); } } protected: // Flag used by optionsmessagehandler_unittest for checking whether any // relevant setting has been updated. // TODO(thaloun): Replace with explicit checks of before & after values. bool options_changed_; bool fail_create_channel_; RtpCapabilities capabilities_; }; class FakeVoiceEngine : public FakeBaseEngine { public: FakeVoiceEngine( webrtc::AudioDeviceModule* adm, const rtc::scoped_refptr& audio_decoder_factory) { // Add a fake audio codec. Note that the name must not be "" as there are // sanity checks against that. codecs_.push_back(AudioCodec(101, "fake_audio_codec", 0, 0, 1)); } rtc::scoped_refptr GetAudioState() const { return rtc::scoped_refptr(); } VoiceMediaChannel* CreateChannel(webrtc::Call* call, const MediaConfig& config, const AudioOptions& options) { if (fail_create_channel_) { return nullptr; } FakeVoiceMediaChannel* ch = new FakeVoiceMediaChannel(this, options); channels_.push_back(ch); return ch; } FakeVoiceMediaChannel* GetChannel(size_t index) { return (channels_.size() > index) ? channels_[index] : NULL; } void UnregisterChannel(VoiceMediaChannel* channel) { channels_.erase(std::find(channels_.begin(), channels_.end(), channel)); } // TODO(ossu): For proper testing, These should either individually settable // or the voice engine should reference mockable factories. const std::vector& send_codecs() { return codecs_; } const std::vector& recv_codecs() { return codecs_; } void SetCodecs(const std::vector& codecs) { codecs_ = codecs; } int GetInputLevel() { return 0; } bool StartAecDump(rtc::PlatformFile file, int64_t max_size_bytes) { return false; } void StopAecDump() {} bool StartRtcEventLog(rtc::PlatformFile file, int64_t max_size_bytes) { return false; } void StopRtcEventLog() {} private: std::vector channels_; std::vector codecs_; friend class FakeMediaEngine; }; class FakeVideoEngine : public FakeBaseEngine { public: FakeVideoEngine() : capture_(false) { // Add a fake video codec. Note that the name must not be "" as there are // sanity checks against that. codecs_.push_back(VideoCodec(0, "fake_video_codec", 0, 0, 0)); } void Init() {} bool SetOptions(const VideoOptions& options) { options_ = options; options_changed_ = true; return true; } VideoMediaChannel* CreateChannel(webrtc::Call* call, const MediaConfig& config, const VideoOptions& options) { if (fail_create_channel_) { return NULL; } FakeVideoMediaChannel* ch = new FakeVideoMediaChannel(this, options); channels_.push_back(ch); return ch; } FakeVideoMediaChannel* GetChannel(size_t index) { return (channels_.size() > index) ? channels_[index] : NULL; } void UnregisterChannel(VideoMediaChannel* channel) { channels_.erase(std::find(channels_.begin(), channels_.end(), channel)); } const std::vector& codecs() const { return codecs_; } void SetCodecs(const std::vector codecs) { codecs_ = codecs; } bool SetCapture(bool capture) { capture_ = capture; return true; } private: std::vector channels_; std::vector codecs_; bool capture_; VideoOptions options_; friend class FakeMediaEngine; }; class FakeMediaEngine : public CompositeMediaEngine { public: FakeMediaEngine() : CompositeMediaEngine(nullptr, nullptr) {} virtual ~FakeMediaEngine() {} void SetAudioCodecs(const std::vector& codecs) { voice_.SetCodecs(codecs); } void SetVideoCodecs(const std::vector& codecs) { video_.SetCodecs(codecs); } void SetAudioRtpHeaderExtensions( const std::vector& extensions) { voice_.set_rtp_header_extensions(extensions); } void SetVideoRtpHeaderExtensions( const std::vector& extensions) { video_.set_rtp_header_extensions(extensions); } void SetAudioRtpHeaderExtensions( const std::vector& extensions) { voice_.set_rtp_header_extensions(extensions); } void SetVideoRtpHeaderExtensions( const std::vector& extensions) { video_.set_rtp_header_extensions(extensions); } FakeVoiceMediaChannel* GetVoiceChannel(size_t index) { return voice_.GetChannel(index); } FakeVideoMediaChannel* GetVideoChannel(size_t index) { return video_.GetChannel(index); } bool capture() const { return video_.capture_; } bool options_changed() const { return video_.options_changed_; } void clear_options_changed() { video_.options_changed_ = false; } void set_fail_create_channel(bool fail) { voice_.set_fail_create_channel(fail); video_.set_fail_create_channel(fail); } }; // CompositeMediaEngine with FakeVoiceEngine to expose SetAudioCodecs to // establish a media connectionwith minimum set of audio codes required template class CompositeMediaEngineWithFakeVoiceEngine : public CompositeMediaEngine { public: CompositeMediaEngineWithFakeVoiceEngine() {} virtual ~CompositeMediaEngineWithFakeVoiceEngine() {} virtual void SetAudioCodecs(const std::vector& codecs) { CompositeMediaEngine::voice_.SetCodecs(codecs); } }; // Have to come afterwards due to declaration order inline FakeVoiceMediaChannel::~FakeVoiceMediaChannel() { if (engine_) { engine_->UnregisterChannel(this); } } inline FakeVideoMediaChannel::~FakeVideoMediaChannel() { if (engine_) { engine_->UnregisterChannel(this); } } class FakeDataEngine : public DataEngineInterface { public: FakeDataEngine() : last_channel_type_(DCT_NONE) {} virtual DataMediaChannel* CreateChannel(DataChannelType data_channel_type) { last_channel_type_ = data_channel_type; FakeDataMediaChannel* ch = new FakeDataMediaChannel(this, DataOptions()); channels_.push_back(ch); return ch; } FakeDataMediaChannel* GetChannel(size_t index) { return (channels_.size() > index) ? channels_[index] : NULL; } void UnregisterChannel(DataMediaChannel* channel) { channels_.erase(std::find(channels_.begin(), channels_.end(), channel)); } virtual void SetDataCodecs(const std::vector& data_codecs) { data_codecs_ = data_codecs; } virtual const std::vector& data_codecs() { return data_codecs_; } DataChannelType last_channel_type() const { return last_channel_type_; } private: std::vector channels_; std::vector data_codecs_; DataChannelType last_channel_type_; }; } // namespace cricket #endif // WEBRTC_MEDIA_BASE_FAKEMEDIAENGINE_H_