webrtc/talk/media/base/fakemediaengine.h
Karl Wiberg 9478437fde rtc::Buffer improvements
1. Constructors, SetData(), and AppendData() now accept uint8_t*,
     int8_t*, and char*. Previously, they accepted void*, meaning that
     any kind of pointer was accepted. I think requiring an explicit
     cast in cases where the input array isn't already of a byte-sized
     type is a better compromise between convenience and safety.

  2. data() can now return a uint8_t* instead of a char*, which seems
     more appropriate for a byte array, and is harder to mix up with
     zero-terminated C strings. data<int8_t>() is also available so
     that callers that want that type instead won't have to cast, as
     is data<char>() (which remains the default until all existing
     callers have been fixed).

  3. Constructors, SetData(), and AppendData() now accept arrays
     natively, not just decayed to pointers. The advantage of this is
     that callers don't have to pass the size separately.

  4. There are new constructors that allow setting size and capacity
     without initializing the array. Previously, this had to be done
     separately after construction.

  5. Instead of TransferTo(), Buffer now supports swap(), and move
     construction and assignment, and has a Pass() method that works
     just like std::move(). (The Pass method is modeled after
     scoped_ptr::Pass().)

R=jmarusic@webrtc.org, tommi@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/42989004

Cr-Commit-Position: refs/heads/master@{#9033}
2015-04-20 12:03:00 +00:00

1067 lines
33 KiB
C++

/*
* 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 <list>
#include <map>
#include <set>
#include <string>
#include <vector>
#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 "webrtc/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 Base> 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<RtpHeaderExtension>& recv_extensions() {
return recv_extensions_;
}
const std::vector<RtpHeaderExtension>& send_extensions() {
return send_extensions_;
}
bool sending() const { return sending_; }
bool playout() const { return playout_; }
const std::list<std::string>& rtp_packets() const { return rtp_packets_; }
const std::list<std::string>& rtcp_packets() const { return rtcp_packets_; }
bool SendRtp(const void* data, int len) {
if (!sending_) {
return false;
}
rtc::Buffer packet(reinterpret_cast<const uint8_t*>(data), len,
kMaxRtpPacketLen);
return Base::SendPacket(&packet);
}
bool SendRtcp(const void* data, int len) {
rtc::Buffer packet(reinterpret_cast<const uint8_t*>(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<const char*>(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<const char*>(data), len));
}
return success;
}
bool CheckNoRtp() { return rtp_packets_.empty(); }
bool CheckNoRtcp() { return rtcp_packets_.empty(); }
virtual bool SetRecvRtpHeaderExtensions(
const std::vector<RtpHeaderExtension>& extensions) {
recv_extensions_ = extensions;
return true;
}
virtual bool SetSendRtpHeaderExtensions(
const std::vector<RtpHeaderExtension>& 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<StreamParams>& send_streams() const {
return send_streams_;
}
const std::vector<StreamParams>& recv_streams() const {
return receive_streams_;
}
bool HasRecvStream(uint32 ssrc) const {
return GetStreamBySsrc(receive_streams_, ssrc) != nullptr;
}
bool HasSendStream(uint32 ssrc) const {
return GetStreamBySsrc(send_streams_, ssrc) != nullptr;
}
// TODO(perkj): This is to support legacy unit test that only check one
// sending stream.
uint32 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_;
}
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<char>(), packet->size()));
}
virtual void OnRtcpReceived(rtc::Buffer* packet,
const rtc::PacketTime& packet_time) {
rtcp_packets_.push_back(std::string(packet->data<char>(), packet->size()));
}
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<RtpHeaderExtension> recv_extensions_;
std::vector<RtpHeaderExtension> send_extensions_;
std::list<std::string> rtp_packets_;
std::list<std::string> rtcp_packets_;
std::vector<StreamParams> send_streams_;
std::vector<StreamParams> receive_streams_;
std::set<uint32> 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<VoiceMediaChannel> {
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<AudioCodec>& recv_codecs() const { return recv_codecs_; }
const std::vector<AudioCodec>& send_codecs() const { return send_codecs_; }
const std::vector<AudioCodec>& codecs() const { return send_codecs(); }
const std::vector<DtmfInfo>& 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<AudioCodec>& codecs) {
if (fail_set_recv_codecs()) {
// Fake the failure in SetRecvCodecs.
return false;
}
recv_codecs_ = codecs;
return true;
}
virtual bool SetSendCodecs(const std::vector<AudioCodec>& 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<VoiceMediaChannel>::AddRecvStream(sp))
return false;
output_scalings_[sp.first_ssrc()] = OutputScaling();
return true;
}
virtual bool RemoveRecvStream(uint32 ssrc) {
if (!RtpHelper<VoiceMediaChannel>::RemoveRecvStream(ssrc))
return false;
output_scalings_.erase(ssrc);
return true;
}
virtual bool SetRemoteRenderer(uint32 ssrc, AudioRenderer* renderer) {
std::map<uint32, AudioRenderer*>::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<uint32, VoiceChannelAudioSink*>::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<AudioCodec>::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<uint32, OutputScaling>::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);
}
}
void OnData(const void* audio_data,
int bits_per_sample,
int sample_rate,
int number_of_channels,
int number_of_frames) override {}
void OnClose() override { renderer_ = NULL; }
AudioRenderer* renderer() const { return renderer_; }
private:
AudioRenderer* renderer_;
};
FakeVoiceEngine* engine_;
std::vector<AudioCodec> recv_codecs_;
std::vector<AudioCodec> send_codecs_;
std::map<uint32, OutputScaling> output_scalings_;
std::vector<DtmfInfo> 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<uint32, VoiceChannelAudioSink*> local_renderers_;
std::map<uint32, AudioRenderer*> 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<VideoMediaChannel> {
public:
explicit FakeVideoMediaChannel(FakeVideoEngine* engine)
: engine_(engine),
sent_intra_frame_(false),
requested_intra_frame_(false),
max_bps_(-1) {}
~FakeVideoMediaChannel();
const std::vector<VideoCodec>& recv_codecs() const { return recv_codecs_; }
const std::vector<VideoCodec>& send_codecs() const { return send_codecs_; }
const std::vector<VideoCodec>& codecs() const { return send_codecs(); }
bool rendering() const { return playout(); }
const VideoOptions& options() const { return options_; }
const std::map<uint32, VideoRenderer*>& 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<VideoMediaChannel>::AddSendStream(sp)) {
return false;
}
SetSendStreamDefaultFormat(sp.first_ssrc());
return true;
}
virtual bool RemoveSendStream(uint32 ssrc) {
send_formats_.erase(ssrc);
return RtpHelper<VideoMediaChannel>::RemoveSendStream(ssrc);
}
virtual bool SetRecvCodecs(const std::vector<VideoCodec>& codecs) {
if (fail_set_recv_codecs()) {
// Fake the failure in SetRecvCodecs.
return false;
}
recv_codecs_ = codecs;
return true;
}
virtual bool SetSendCodecs(const std::vector<VideoCodec>& codecs) {
if (fail_set_send_codecs()) {
// Fake the failure in SetSendCodecs.
return false;
}
send_codecs_ = codecs;
for (std::vector<StreamParams>::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<VideoMediaChannel>::AddRecvStream(sp))
return false;
renderers_[sp.first_ssrc()] = NULL;
return true;
}
virtual bool RemoveRecvStream(uint32 ssrc) {
if (!RtpHelper<VideoMediaChannel>::RemoveRecvStream(ssrc))
return false;
renderers_.erase(ssrc);
return true;
}
virtual bool GetStats(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<VideoCodec> recv_codecs_;
std::vector<VideoCodec> send_codecs_;
std::map<uint32, VideoRenderer*> renderers_;
std::map<uint32, VideoFormat> send_formats_;
std::map<uint32, VideoCapturer*> 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<DataMediaChannel> {
public:
explicit FakeDataMediaChannel(void* unused)
: send_blocked_(false), max_bps_(-1) {}
~FakeDataMediaChannel() {}
const std::vector<DataCodec>& recv_codecs() const { return recv_codecs_; }
const std::vector<DataCodec>& send_codecs() const { return send_codecs_; }
const std::vector<DataCodec>& codecs() const { return send_codecs(); }
int max_bps() const { return max_bps_; }
virtual bool SetRecvCodecs(const std::vector<DataCodec>& codecs) {
if (fail_set_recv_codecs()) {
// Fake the failure in SetRecvCodecs.
return false;
}
recv_codecs_ = codecs;
return true;
}
virtual bool SetSendCodecs(const std::vector<DataCodec>& 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<DataMediaChannel>::AddRecvStream(sp))
return false;
return true;
}
virtual bool RemoveRecvStream(uint32 ssrc) {
if (!RtpHelper<DataMediaChannel>::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<char>(), 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:
std::vector<DataCodec> recv_codecs_;
std::vector<DataCodec> 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<RtpHeaderExtension>& rtp_header_extensions() const {
return rtp_header_extensions_;
}
void set_rtp_header_extensions(
const std::vector<RtpHeaderExtension>& 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<RtpHeaderExtension> 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<AudioCodec>& codecs() { return codecs_; }
void SetCodecs(const std::vector<AudioCodec> 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<FakeVoiceMediaChannel*> channels_;
std::vector<AudioCodec> 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() : FakeVideoEngine(nullptr) {}
explicit FakeVideoEngine(FakeVoiceEngine* voice)
: 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;
}
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<VideoCodec>& 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<VideoCodec> 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;
}
private:
std::vector<FakeVideoMediaChannel*> channels_;
std::vector<VideoCodec> codecs_;
VideoEncoderConfig default_encoder_config_;
std::string in_device_;
bool capture_;
VideoProcessor* processor_;
VideoOptions options_;
friend class FakeMediaEngine;
};
class FakeMediaEngine :
public CompositeMediaEngine<FakeVoiceEngine, FakeVideoEngine> {
public:
FakeMediaEngine() {
voice_ = FakeVoiceEngine();
video_ = FakeVideoEngine();
}
virtual ~FakeMediaEngine() {}
void SetAudioCodecs(const std::vector<AudioCodec>& codecs) {
voice_.SetCodecs(codecs);
}
void SetVideoCodecs(const std::vector<VideoCodec>& codecs) {
video_.SetCodecs(codecs);
}
void SetAudioRtpHeaderExtensions(
const std::vector<RtpHeaderExtension>& extensions) {
voice_.set_rtp_header_extensions(extensions);
}
void SetVideoRtpHeaderExtensions(
const std::vector<RtpHeaderExtension>& 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 VIDEO>
class CompositeMediaEngineWithFakeVoiceEngine :
public CompositeMediaEngine<FakeVoiceEngine, VIDEO> {
public:
CompositeMediaEngineWithFakeVoiceEngine() {}
virtual ~CompositeMediaEngineWithFakeVoiceEngine() {}
virtual void SetAudioCodecs(const std::vector<AudioCodec>& codecs) {
CompositeMediaEngine<FakeVoiceEngine, VIDEO>::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<DataCodec>& data_codecs) {
data_codecs_ = data_codecs;
}
virtual const std::vector<DataCodec>& data_codecs() { return data_codecs_; }
DataChannelType last_channel_type() const { return last_channel_type_; }
private:
std::vector<FakeDataMediaChannel*> channels_;
std::vector<DataCodec> data_codecs_;
DataChannelType last_channel_type_;
};
} // namespace cricket
#endif // TALK_MEDIA_BASE_FAKEMEDIAENGINE_H_