/* * libjingle * Copyright 2004 Google Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef TALK_MEDIA_BASE_FAKEMEDIAENGINE_H_ #define TALK_MEDIA_BASE_FAKEMEDIAENGINE_H_ #include #include #include #include #include #include "talk/media/base/audiorenderer.h" #include "talk/media/base/mediaengine.h" #include "talk/media/base/rtputils.h" #include "talk/media/base/streamparams.h" #include "talk/p2p/base/sessiondescription.h" #include "webrtc/base/buffer.h" #include "webrtc/base/stringutils.h" 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, int len) { if (!sending_) { return false; } rtc::Buffer packet(data, len, kMaxRtpPacketLen); return Base::SendPacket(&packet); } bool SendRtcp(const void* data, int len) { rtc::Buffer packet(data, len, kMaxRtpPacketLen); return Base::SendRtcp(&packet); } bool CheckRtp(const void* data, int 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, int 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(); } virtual bool SetRecvRtpHeaderExtensions( const std::vector& extensions) { recv_extensions_ = extensions; return true; } virtual bool SetSendRtpHeaderExtensions( const std::vector& extensions) { send_extensions_ = extensions; return true; } 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); return true; } virtual bool RemoveSendStream(uint32 ssrc) { 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); return true; } virtual bool RemoveRecvStream(uint32 ssrc) { return RemoveStreamBySsrc(&receive_streams_, ssrc); } virtual bool MuteStream(uint32 ssrc, bool on) { if (!HasSendStream(ssrc) && ssrc != 0) return false; if (on) muted_streams_.insert(ssrc); else muted_streams_.erase(ssrc); return true; } bool IsStreamMuted(uint32 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 ssrc) const { return GetStreamBySsrc(receive_streams_, ssrc, NULL); } bool HasSendStream(uint32 ssrc) const { return GetStreamBySsrc(send_streams_, ssrc, NULL); } // TODO(perkj): This is to support legacy unit test that only check one // sending stream. const uint32 send_ssrc() { 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_; } protected: bool set_sending(bool send) { sending_ = send; return true; } void set_playout(bool playout) { playout_ = playout; } virtual void OnPacketReceived(rtc::Buffer* packet, const rtc::PacketTime& packet_time) { rtp_packets_.push_back(std::string(packet->data(), packet->length())); } virtual void OnRtcpReceived(rtc::Buffer* packet, const rtc::PacketTime& packet_time) { rtcp_packets_.push_back(std::string(packet->data(), packet->length())); } virtual void OnReadyToSend(bool ready) { ready_to_send_ = ready; } 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_; bool fail_set_send_codecs_; bool fail_set_recv_codecs_; uint32 send_ssrc_; std::string rtcp_cname_; bool ready_to_send_; }; class FakeVoiceMediaChannel : public RtpHelper { public: struct DtmfInfo { DtmfInfo(uint32 ssrc, int event_code, int duration, int flags) : ssrc(ssrc), event_code(event_code), duration(duration), flags(flags) { } uint32 ssrc; int event_code; int duration; int flags; }; explicit FakeVoiceMediaChannel(FakeVoiceEngine* engine) : engine_(engine), fail_set_send_(false), ringback_tone_ssrc_(0), ringback_tone_play_(false), ringback_tone_loop_(false), time_since_last_typing_(-1) { output_scalings_[0] = OutputScaling(); // For default channel. } ~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_; } uint32 ringback_tone_ssrc() const { return ringback_tone_ssrc_; } bool ringback_tone_play() const { return ringback_tone_play_; } bool ringback_tone_loop() const { return ringback_tone_loop_; } virtual bool SetRecvCodecs(const std::vector& codecs) { if (fail_set_recv_codecs()) { // Fake the failure in SetRecvCodecs. return false; } recv_codecs_ = codecs; return true; } virtual bool SetSendCodecs(const std::vector& codecs) { if (fail_set_send_codecs()) { // Fake the failure in SetSendCodecs. return false; } send_codecs_ = codecs; return true; } virtual bool SetPlayout(bool playout) { set_playout(playout); return true; } virtual bool SetSend(SendFlags flag) { if (fail_set_send_) { return false; } return set_sending(flag != SEND_NOTHING); } virtual bool SetMaxSendBandwidth(int bps) { return true; } virtual bool AddRecvStream(const StreamParams& sp) { if (!RtpHelper::AddRecvStream(sp)) return false; output_scalings_[sp.first_ssrc()] = OutputScaling(); return true; } virtual bool RemoveRecvStream(uint32 ssrc) { if (!RtpHelper::RemoveRecvStream(ssrc)) return false; output_scalings_.erase(ssrc); return true; } virtual bool SetRemoteRenderer(uint32 ssrc, AudioRenderer* renderer) { std::map::iterator it = remote_renderers_.find(ssrc); if (renderer) { if (it != remote_renderers_.end()) { ASSERT(it->second == renderer); } else { remote_renderers_.insert(std::make_pair(ssrc, renderer)); renderer->AddChannel(0); } } else { if (it != remote_renderers_.end()) { it->second->RemoveChannel(0); remote_renderers_.erase(it); } else { return false; } } return true; } virtual bool SetLocalRenderer(uint32 ssrc, AudioRenderer* renderer) { std::map::iterator it = local_renderers_.find(ssrc); if (renderer) { if (it != local_renderers_.end()) { ASSERT(it->second->renderer() == renderer); } else { local_renderers_.insert(std::make_pair( ssrc, new VoiceChannelAudioSink(renderer))); } } else { if (it != local_renderers_.end()) { delete it->second; local_renderers_.erase(it); } else { return false; } } 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 SetRingbackTone(const char* buf, int len) { return true; } virtual bool PlayRingbackTone(uint32 ssrc, bool play, bool loop) { ringback_tone_ssrc_ = ssrc; ringback_tone_play_ = play; ringback_tone_loop_ = loop; return true; } 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 ssrc, int event_code, int duration, int flags) { dtmf_info_queue_.push_back(DtmfInfo(ssrc, event_code, duration, flags)); return true; } virtual bool SetOutputScaling(uint32 ssrc, double left, double right) { if (0 == ssrc) { std::map::iterator it; for (it = output_scalings_.begin(); it != output_scalings_.end(); ++it) { it->second.left = left; it->second.right = right; } return true; } else if (output_scalings_.find(ssrc) != output_scalings_.end()) { output_scalings_[ssrc].left = left; output_scalings_[ssrc].right = right; return true; } return false; } virtual bool GetOutputScaling(uint32 ssrc, double* left, double* right) { if (output_scalings_.find(ssrc) == output_scalings_.end()) return false; *left = output_scalings_[ssrc].left; *right = output_scalings_[ssrc].right; return true; } virtual bool GetStats(VoiceMediaInfo* info) { return false; } virtual void GetLastMediaError(uint32* ssrc, VoiceMediaChannel::Error* error) { *ssrc = 0; *error = fail_set_send_ ? VoiceMediaChannel::ERROR_REC_DEVICE_OPEN_FAILED : VoiceMediaChannel::ERROR_NONE; } void set_fail_set_send(bool fail) { fail_set_send_ = fail; } void TriggerError(uint32 ssrc, VoiceMediaChannel::Error error) { VoiceMediaChannel::SignalMediaError(ssrc, error); } virtual bool SetOptions(const AudioOptions& options) { // Does a "merge" of current options and set options. options_.SetAll(options); return true; } virtual bool GetOptions(AudioOptions* options) const { *options = options_; return true; } private: struct OutputScaling { OutputScaling() : left(1.0), right(1.0) {} double left, right; }; class VoiceChannelAudioSink : public AudioRenderer::Sink { public: explicit VoiceChannelAudioSink(AudioRenderer* renderer) : renderer_(renderer) { renderer_->AddChannel(0); renderer_->SetSink(this); } virtual ~VoiceChannelAudioSink() { if (renderer_) { renderer_->RemoveChannel(0); renderer_->SetSink(NULL); } } virtual void OnData(const void* audio_data, int bits_per_sample, int sample_rate, int number_of_channels, int number_of_frames) OVERRIDE {} virtual void OnClose() OVERRIDE { renderer_ = NULL; } AudioRenderer* renderer() const { return renderer_; } private: AudioRenderer* renderer_; }; FakeVoiceEngine* engine_; std::vector recv_codecs_; std::vector send_codecs_; std::map output_scalings_; std::vector dtmf_info_queue_; bool fail_set_send_; uint32 ringback_tone_ssrc_; bool ringback_tone_play_; bool ringback_tone_loop_; int time_since_last_typing_; AudioOptions options_; std::map local_renderers_; std::map remote_renderers_; }; // A helper function to compare the FakeVoiceMediaChannel::DtmfInfo. inline bool CompareDtmfInfo(const FakeVoiceMediaChannel::DtmfInfo& info, uint32 ssrc, int event_code, int duration, int flags) { return (info.duration == duration && info.event_code == event_code && info.flags == flags && info.ssrc == ssrc); } class FakeVideoMediaChannel : public RtpHelper { public: explicit FakeVideoMediaChannel(FakeVideoEngine* engine) : engine_(engine), sent_intra_frame_(false), requested_intra_frame_(false), max_bps_(-1) {} ~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& renderers() const { return renderers_; } int max_bps() const { return max_bps_; } bool GetSendStreamFormat(uint32 ssrc, VideoFormat* format) { if (send_formats_.find(ssrc) == send_formats_.end()) { return false; } *format = send_formats_[ssrc]; return true; } virtual bool SetSendStreamFormat(uint32 ssrc, const VideoFormat& format) { if (send_formats_.find(ssrc) == send_formats_.end()) { return false; } send_formats_[ssrc] = format; return true; } virtual bool AddSendStream(const StreamParams& sp) { if (!RtpHelper::AddSendStream(sp)) { return false; } SetSendStreamDefaultFormat(sp.first_ssrc()); return true; } virtual bool RemoveSendStream(uint32 ssrc) { send_formats_.erase(ssrc); return RtpHelper::RemoveSendStream(ssrc); } virtual bool SetRecvCodecs(const std::vector& codecs) { if (fail_set_recv_codecs()) { // Fake the failure in SetRecvCodecs. return false; } recv_codecs_ = codecs; return true; } virtual bool SetSendCodecs(const std::vector& codecs) { if (fail_set_send_codecs()) { // Fake the failure in SetSendCodecs. return false; } send_codecs_ = codecs; for (std::vector::const_iterator it = send_streams().begin(); it != send_streams().end(); ++it) { SetSendStreamDefaultFormat(it->first_ssrc()); } return true; } virtual bool GetSendCodec(VideoCodec* send_codec) { if (send_codecs_.empty()) { return false; } *send_codec = send_codecs_[0]; return true; } virtual bool SetRender(bool render) { set_playout(render); return true; } virtual bool SetRenderer(uint32 ssrc, VideoRenderer* r) { if (ssrc != 0 && renderers_.find(ssrc) == renderers_.end()) { return false; } if (ssrc != 0) { renderers_[ssrc] = r; } return true; } virtual bool SetSend(bool send) { return set_sending(send); } virtual bool SetCapturer(uint32 ssrc, VideoCapturer* capturer) { capturers_[ssrc] = capturer; return true; } bool HasCapturer(uint32 ssrc) const { return capturers_.find(ssrc) != capturers_.end(); } virtual bool SetMaxSendBandwidth(int bps) { max_bps_ = bps; return true; } virtual bool AddRecvStream(const StreamParams& sp) { if (!RtpHelper::AddRecvStream(sp)) return false; renderers_[sp.first_ssrc()] = NULL; return true; } virtual bool RemoveRecvStream(uint32 ssrc) { if (!RtpHelper::RemoveRecvStream(ssrc)) return false; renderers_.erase(ssrc); return true; } virtual bool GetStats(const StatsOptions& options, VideoMediaInfo* info) { return false; } virtual bool SendIntraFrame() { sent_intra_frame_ = true; return true; } virtual bool RequestIntraFrame() { requested_intra_frame_ = true; return true; } virtual bool SetOptions(const VideoOptions& options) { options_ = options; return true; } virtual bool GetOptions(VideoOptions* options) const { *options = options_; return true; } virtual void UpdateAspectRatio(int ratio_w, int ratio_h) {} void set_sent_intra_frame(bool v) { sent_intra_frame_ = v; } bool sent_intra_frame() const { return sent_intra_frame_; } void set_requested_intra_frame(bool v) { requested_intra_frame_ = v; } bool requested_intra_frame() const { return requested_intra_frame_; } private: // Be default, each send stream uses the first send codec format. void SetSendStreamDefaultFormat(uint32 ssrc) { if (!send_codecs_.empty()) { send_formats_[ssrc] = VideoFormat( send_codecs_[0].width, send_codecs_[0].height, cricket::VideoFormat::FpsToInterval(send_codecs_[0].framerate), cricket::FOURCC_I420); } } FakeVideoEngine* engine_; std::vector recv_codecs_; std::vector send_codecs_; std::map renderers_; std::map send_formats_; std::map capturers_; bool sent_intra_frame_; bool requested_intra_frame_; VideoOptions options_; int max_bps_; }; class FakeSoundclipMedia : public SoundclipMedia { public: virtual bool PlaySound(const char* buf, int len, int flags) { return true; } }; class FakeDataMediaChannel : public RtpHelper { public: explicit FakeDataMediaChannel(void* unused) : 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 SetRecvCodecs(const std::vector& codecs) { if (fail_set_recv_codecs()) { // Fake the failure in SetRecvCodecs. return false; } recv_codecs_ = codecs; return true; } virtual bool SetSendCodecs(const std::vector& codecs) { if (fail_set_send_codecs()) { // Fake the failure in SetSendCodecs. return false; } send_codecs_ = codecs; return true; } virtual bool SetSend(bool send) { return set_sending(send); } virtual bool SetReceive(bool receive) { set_playout(receive); return true; } virtual bool SetMaxSendBandwidth(int bps) { max_bps_ = bps; return true; } virtual bool AddRecvStream(const StreamParams& sp) { if (!RtpHelper::AddRecvStream(sp)) return false; return true; } virtual bool RemoveRecvStream(uint32 ssrc) { if (!RtpHelper::RemoveRecvStream(ssrc)) return false; return true; } virtual bool SendData(const SendDataParams& params, const rtc::Buffer& 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.length()); 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: 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() : loglevel_(-1), options_changed_(false), fail_create_channel_(false) {} bool Init(rtc::Thread* worker_thread) { return true; } void Terminate() {} void SetLogging(int level, const char* filter) { loglevel_ = level; logfilter_ = filter; } void set_fail_create_channel(bool fail) { fail_create_channel_ = fail; } const std::vector& rtp_header_extensions() const { return rtp_header_extensions_; } void set_rtp_header_extensions( const std::vector& extensions) { rtp_header_extensions_ = extensions; } protected: int loglevel_; std::string logfilter_; // 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_; std::vector rtp_header_extensions_; }; class FakeVoiceEngine : public FakeBaseEngine { public: FakeVoiceEngine() : output_volume_(-1), delay_offset_(0), rx_processor_(NULL), tx_processor_(NULL) { // 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, 0)); } int GetCapabilities() { return AUDIO_SEND | AUDIO_RECV; } AudioOptions GetAudioOptions() const { return options_; } AudioOptions GetOptions() const { return options_; } bool SetOptions(const AudioOptions& options) { options_ = options; options_changed_ = true; return true; } VoiceMediaChannel* CreateChannel() { if (fail_create_channel_) { return NULL; } FakeVoiceMediaChannel* ch = new FakeVoiceMediaChannel(this); 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)); } SoundclipMedia* CreateSoundclip() { return new FakeSoundclipMedia(); } const std::vector& codecs() { return codecs_; } void SetCodecs(const std::vector codecs) { codecs_ = codecs; } bool SetDelayOffset(int offset) { delay_offset_ = offset; return true; } bool SetDevices(const Device* in_device, const Device* out_device) { in_device_ = (in_device) ? in_device->name : ""; out_device_ = (out_device) ? out_device->name : ""; options_changed_ = true; return true; } bool GetOutputVolume(int* level) { *level = output_volume_; return true; } bool SetOutputVolume(int level) { output_volume_ = level; options_changed_ = true; return true; } int GetInputLevel() { return 0; } bool SetLocalMonitor(bool enable) { return true; } bool StartAecDump(rtc::PlatformFile file) { return false; } bool RegisterProcessor(uint32 ssrc, VoiceProcessor* voice_processor, MediaProcessorDirection direction) { if (direction == MPD_RX) { rx_processor_ = voice_processor; return true; } else if (direction == MPD_TX) { tx_processor_ = voice_processor; return true; } return false; } bool UnregisterProcessor(uint32 ssrc, VoiceProcessor* voice_processor, MediaProcessorDirection direction) { bool unregistered = false; if (direction & MPD_RX) { rx_processor_ = NULL; unregistered = true; } if (direction & MPD_TX) { tx_processor_ = NULL; unregistered = true; } return unregistered; } private: std::vector channels_; std::vector codecs_; int output_volume_; int delay_offset_; std::string in_device_; std::string out_device_; VoiceProcessor* rx_processor_; VoiceProcessor* tx_processor_; AudioOptions options_; friend class FakeMediaEngine; }; class FakeVideoEngine : public FakeBaseEngine { public: FakeVideoEngine() : capture_(false), processor_(NULL) { // 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, 0)); } bool GetOptions(VideoOptions* options) const { *options = options_; return true; } bool SetOptions(const VideoOptions& options) { options_ = options; options_changed_ = true; return true; } int GetCapabilities() { return VIDEO_SEND | VIDEO_RECV; } bool SetDefaultEncoderConfig(const VideoEncoderConfig& config) { default_encoder_config_ = config; return true; } VideoEncoderConfig GetDefaultEncoderConfig() const { return default_encoder_config_; } const VideoEncoderConfig& default_encoder_config() const { return default_encoder_config_; } VideoMediaChannel* CreateChannel(const VideoOptions& options, VoiceMediaChannel* channel) { if (fail_create_channel_) { return NULL; } FakeVideoMediaChannel* ch = new FakeVideoMediaChannel(this); ch->SetOptions(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_; } bool FindCodec(const VideoCodec& in) { for (size_t i = 0; i < codecs_.size(); ++i) { if (codecs_[i].Matches(in)) { return true; } } return false; } void SetCodecs(const std::vector codecs) { codecs_ = codecs; } bool SetCaptureDevice(const Device* device) { in_device_ = (device) ? device->name : ""; options_changed_ = true; return true; } bool SetCapture(bool capture) { capture_ = capture; return true; } VideoFormat GetStartCaptureFormat() const { return VideoFormat(640, 480, cricket::VideoFormat::FpsToInterval(30), FOURCC_I420); } sigslot::repeater2 SignalCaptureStateChange; private: std::vector channels_; std::vector codecs_; VideoEncoderConfig default_encoder_config_; std::string in_device_; bool capture_; VideoProcessor* processor_; VideoOptions options_; friend class FakeMediaEngine; }; class FakeMediaEngine : public CompositeMediaEngine { public: FakeMediaEngine() { voice_ = FakeVoiceEngine(); video_ = FakeVideoEngine(); } 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); } FakeVoiceMediaChannel* GetVoiceChannel(size_t index) { return voice_.GetChannel(index); } FakeVideoMediaChannel* GetVideoChannel(size_t index) { return video_.GetChannel(index); } AudioOptions audio_options() const { return voice_.options_; } int audio_delay_offset() const { return voice_.delay_offset_; } int output_volume() const { return voice_.output_volume_; } const VideoEncoderConfig& default_video_encoder_config() const { return video_.default_encoder_config_; } const std::string& audio_in_device() const { return voice_.in_device_; } const std::string& audio_out_device() const { return voice_.out_device_; } int voice_loglevel() const { return voice_.loglevel_; } const std::string& voice_logfilter() const { return voice_.logfilter_; } int video_loglevel() const { return video_.loglevel_; } const std::string& video_logfilter() const { return video_.logfilter_; } bool capture() const { return video_.capture_; } bool options_changed() const { return voice_.options_changed_ || video_.options_changed_; } void clear_options_changed() { video_.options_changed_ = false; voice_.options_changed_ = false; } void set_fail_create_channel(bool fail) { voice_.set_fail_create_channel(fail); video_.set_fail_create_channel(fail); } bool voice_processor_registered(MediaProcessorDirection direction) const { if (direction == MPD_RX) { return voice_.rx_processor_ != NULL; } else if (direction == MPD_TX) { return voice_.tx_processor_ != NULL; } return false; } }; // 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); 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 // TALK_MEDIA_BASE_FAKEMEDIAENGINE_H_