blob: f1f5900682909a09cde8a86afa9d62da6235a65e [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/renderer/media/webrtc/mock_peer_connection_impl.h"
#include <stddef.h>
#include <utility>
#include <vector>
#include "base/logging.h"
#include "base/stl_util.h"
#include "content/renderer/media/webrtc/mock_data_channel_impl.h"
#include "content/renderer/media/webrtc/mock_peer_connection_dependency_factory.h"
#include "content/renderer/media/webrtc/webrtc_util.h"
#include "third_party/webrtc/api/rtp_receiver_interface.h"
#include "third_party/webrtc/rtc_base/ref_counted_object.h"
using testing::_;
using webrtc::AudioTrackInterface;
using webrtc::CreateSessionDescriptionObserver;
using webrtc::DtmfSenderInterface;
using webrtc::DtmfSenderObserverInterface;
using webrtc::IceCandidateInterface;
using webrtc::MediaStreamInterface;
using webrtc::PeerConnectionInterface;
using webrtc::SessionDescriptionInterface;
using webrtc::SetSessionDescriptionObserver;
namespace content {
class MockStreamCollection : public webrtc::StreamCollectionInterface {
public:
size_t count() override { return streams_.size(); }
MediaStreamInterface* at(size_t index) override { return streams_[index]; }
MediaStreamInterface* find(const std::string& id) override {
for (size_t i = 0; i < streams_.size(); ++i) {
if (streams_[i]->id() == id)
return streams_[i];
}
return nullptr;
}
webrtc::MediaStreamTrackInterface* FindAudioTrack(
const std::string& id) override {
for (size_t i = 0; i < streams_.size(); ++i) {
webrtc::MediaStreamTrackInterface* track =
streams_.at(i)->FindAudioTrack(id);
if (track)
return track;
}
return nullptr;
}
webrtc::MediaStreamTrackInterface* FindVideoTrack(
const std::string& id) override {
for (size_t i = 0; i < streams_.size(); ++i) {
webrtc::MediaStreamTrackInterface* track =
streams_.at(i)->FindVideoTrack(id);
if (track)
return track;
}
return nullptr;
}
void AddStream(MediaStreamInterface* stream) {
streams_.push_back(stream);
}
void RemoveStream(MediaStreamInterface* stream) {
auto it = streams_.begin();
for (; it != streams_.end(); ++it) {
if (it->get() == stream) {
streams_.erase(it);
break;
}
}
}
protected:
~MockStreamCollection() override {}
private:
typedef std::vector<rtc::scoped_refptr<MediaStreamInterface> >
StreamVector;
StreamVector streams_;
};
class MockDtmfSender : public DtmfSenderInterface {
public:
void RegisterObserver(DtmfSenderObserverInterface* observer) override {
observer_ = observer;
}
void UnregisterObserver() override { observer_ = nullptr; }
bool CanInsertDtmf() override { return true; }
bool InsertDtmf(const std::string& tones,
int duration,
int inter_tone_gap) override {
tones_ = tones;
duration_ = duration;
inter_tone_gap_ = inter_tone_gap;
return true;
}
std::string tones() const override { return tones_; }
int duration() const override { return duration_; }
int inter_tone_gap() const override { return inter_tone_gap_; }
private:
DtmfSenderObserverInterface* observer_ = nullptr;
std::string tones_;
int duration_ = 0;
int inter_tone_gap_ = 0;
};
FakeRtpSender::FakeRtpSender(
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track,
std::vector<std::string> stream_ids)
: track_(std::move(track)), stream_ids_(std::move(stream_ids)) {}
FakeRtpSender::~FakeRtpSender() {}
bool FakeRtpSender::SetTrack(webrtc::MediaStreamTrackInterface* track) {
NOTIMPLEMENTED();
return false;
}
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> FakeRtpSender::track()
const {
return track_;
}
rtc::scoped_refptr<webrtc::DtlsTransportInterface>
FakeRtpSender::dtls_transport() const {
return transport_;
}
uint32_t FakeRtpSender::ssrc() const {
NOTIMPLEMENTED();
return 0;
}
cricket::MediaType FakeRtpSender::media_type() const {
NOTIMPLEMENTED();
return cricket::MEDIA_TYPE_AUDIO;
}
std::string FakeRtpSender::id() const {
NOTIMPLEMENTED();
return "";
}
std::vector<std::string> FakeRtpSender::stream_ids() const {
return stream_ids_;
}
std::vector<webrtc::RtpEncodingParameters> FakeRtpSender::init_send_encodings()
const {
return {};
}
webrtc::RtpParameters FakeRtpSender::GetParameters() const {
NOTIMPLEMENTED();
return webrtc::RtpParameters();
}
webrtc::RTCError FakeRtpSender::SetParameters(
const webrtc::RtpParameters& parameters) {
NOTIMPLEMENTED();
return webrtc::RTCError::OK();
}
rtc::scoped_refptr<webrtc::DtmfSenderInterface> FakeRtpSender::GetDtmfSender()
const {
return new rtc::RefCountedObject<MockDtmfSender>();
}
FakeRtpReceiver::FakeRtpReceiver(
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track,
std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>> streams)
: track_(std::move(track)), streams_(std::move(streams)) {}
FakeRtpReceiver::~FakeRtpReceiver() {}
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> FakeRtpReceiver::track()
const {
return track_;
}
rtc::scoped_refptr<webrtc::DtlsTransportInterface>
FakeRtpReceiver::dtls_transport() const {
return transport_;
}
std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>>
FakeRtpReceiver::streams() const {
return streams_;
}
std::vector<std::string> FakeRtpReceiver::stream_ids() const {
std::vector<std::string> stream_ids;
for (const auto& stream : streams_)
stream_ids.push_back(stream->id());
return stream_ids;
}
cricket::MediaType FakeRtpReceiver::media_type() const {
NOTIMPLEMENTED();
return cricket::MEDIA_TYPE_AUDIO;
}
std::string FakeRtpReceiver::id() const {
NOTIMPLEMENTED();
return "";
}
webrtc::RtpParameters FakeRtpReceiver::GetParameters() const {
NOTIMPLEMENTED();
return webrtc::RtpParameters();
}
bool FakeRtpReceiver::SetParameters(const webrtc::RtpParameters& parameters) {
NOTIMPLEMENTED();
return false;
}
void FakeRtpReceiver::SetObserver(
webrtc::RtpReceiverObserverInterface* observer) {
NOTIMPLEMENTED();
}
std::vector<webrtc::RtpSource> FakeRtpReceiver::GetSources() const {
NOTIMPLEMENTED();
return std::vector<webrtc::RtpSource>();
}
FakeRtpTransceiver::FakeRtpTransceiver(
cricket::MediaType media_type,
rtc::scoped_refptr<FakeRtpSender> sender,
rtc::scoped_refptr<FakeRtpReceiver> receiver,
base::Optional<std::string> mid,
bool stopped,
webrtc::RtpTransceiverDirection direction,
base::Optional<webrtc::RtpTransceiverDirection> current_direction)
: media_type_(media_type),
sender_(std::move(sender)),
receiver_(std::move(receiver)),
mid_(ToAbslOptional(std::move(mid))),
stopped_(stopped),
direction_(direction),
current_direction_(ToAbslOptional(current_direction)) {}
FakeRtpTransceiver::~FakeRtpTransceiver() {}
cricket::MediaType FakeRtpTransceiver::media_type() const {
return media_type_;
}
absl::optional<std::string> FakeRtpTransceiver::mid() const {
return mid_;
}
rtc::scoped_refptr<webrtc::RtpSenderInterface> FakeRtpTransceiver::sender()
const {
return sender_;
}
rtc::scoped_refptr<webrtc::RtpReceiverInterface> FakeRtpTransceiver::receiver()
const {
return receiver_;
}
bool FakeRtpTransceiver::stopped() const {
return stopped_;
}
webrtc::RtpTransceiverDirection FakeRtpTransceiver::direction() const {
return direction_;
}
void FakeRtpTransceiver::SetDirection(
webrtc::RtpTransceiverDirection new_direction) {
NOTIMPLEMENTED();
}
absl::optional<webrtc::RtpTransceiverDirection>
FakeRtpTransceiver::current_direction() const {
return current_direction_;
}
void FakeRtpTransceiver::Stop() {
NOTIMPLEMENTED();
}
void FakeRtpTransceiver::SetTransport(
rtc::scoped_refptr<webrtc::DtlsTransportInterface> transport) {
sender_->SetTransport(transport);
receiver_->SetTransport(transport);
}
FakeDtlsTransport::FakeDtlsTransport() {}
rtc::scoped_refptr<webrtc::IceTransportInterface>
FakeDtlsTransport::ice_transport() {
return nullptr;
}
webrtc::DtlsTransportInformation FakeDtlsTransport::Information() {
return webrtc::DtlsTransportInformation(webrtc::DtlsTransportState::kNew);
}
const char MockPeerConnectionImpl::kDummyOffer[] = "dummy offer";
const char MockPeerConnectionImpl::kDummyAnswer[] = "dummy answer";
MockPeerConnectionImpl::MockPeerConnectionImpl(
MockPeerConnectionDependencyFactory* factory,
webrtc::PeerConnectionObserver* observer)
: dependency_factory_(factory),
remote_streams_(new rtc::RefCountedObject<MockStreamCollection>),
hint_audio_(false),
hint_video_(false),
getstats_result_(true),
sdp_mline_index_(-1),
observer_(observer) {
ON_CALL(*this, SetLocalDescription(_, _)).WillByDefault(testing::Invoke(
this, &MockPeerConnectionImpl::SetLocalDescriptionWorker));
// TODO(hbos): Remove once no longer mandatory to implement.
ON_CALL(*this, SetRemoteDescription(_, _)).WillByDefault(testing::Invoke(
this, &MockPeerConnectionImpl::SetRemoteDescriptionWorker));
ON_CALL(*this, SetRemoteDescriptionForMock(_, _))
.WillByDefault(testing::Invoke(
[this](
std::unique_ptr<webrtc::SessionDescriptionInterface>* desc,
rtc::scoped_refptr<webrtc::SetRemoteDescriptionObserverInterface>*
observer) {
SetRemoteDescriptionWorker(nullptr, desc->release());
}));
}
MockPeerConnectionImpl::~MockPeerConnectionImpl() {}
webrtc::RTCErrorOr<rtc::scoped_refptr<webrtc::RtpSenderInterface>>
MockPeerConnectionImpl::AddTrack(
rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track,
const std::vector<std::string>& stream_ids) {
DCHECK(track);
DCHECK_EQ(1u, stream_ids.size());
for (const auto& sender : senders_) {
if (sender->track() == track)
return webrtc::RTCError(webrtc::RTCErrorType::INVALID_PARAMETER);
}
for (const auto& stream_id : stream_ids) {
if (!base::ContainsValue(local_stream_ids_, stream_id)) {
stream_label_ = stream_id;
local_stream_ids_.push_back(stream_id);
}
}
auto* sender = new rtc::RefCountedObject<FakeRtpSender>(track, stream_ids);
senders_.push_back(sender);
return rtc::scoped_refptr<webrtc::RtpSenderInterface>(sender);
}
bool MockPeerConnectionImpl::RemoveTrack(webrtc::RtpSenderInterface* s) {
rtc::scoped_refptr<FakeRtpSender> sender = static_cast<FakeRtpSender*>(s);
auto it = std::find(senders_.begin(), senders_.end(), sender);
if (it == senders_.end())
return false;
senders_.erase(it);
auto track = sender->track();
for (const auto& stream_id : sender->stream_ids()) {
auto local_stream_it = std::find(local_stream_ids_.begin(),
local_stream_ids_.end(), stream_id);
if (local_stream_it != local_stream_ids_.end())
local_stream_ids_.erase(local_stream_it);
}
return true;
}
std::vector<rtc::scoped_refptr<webrtc::RtpSenderInterface>>
MockPeerConnectionImpl::GetSenders() const {
std::vector<rtc::scoped_refptr<webrtc::RtpSenderInterface>> senders;
for (const auto& sender : senders_)
senders.push_back(sender);
return senders;
}
std::vector<rtc::scoped_refptr<webrtc::RtpReceiverInterface>>
MockPeerConnectionImpl::GetReceivers() const {
std::vector<rtc::scoped_refptr<webrtc::RtpReceiverInterface>> receivers;
for (size_t i = 0; i < remote_streams_->count(); ++i) {
for (const auto& audio_track : remote_streams_->at(i)->GetAudioTracks()) {
receivers.push_back(
new rtc::RefCountedObject<FakeRtpReceiver>(audio_track));
}
for (const auto& video_track : remote_streams_->at(i)->GetVideoTracks()) {
receivers.push_back(
new rtc::RefCountedObject<FakeRtpReceiver>(video_track));
}
}
return receivers;
}
rtc::scoped_refptr<webrtc::DataChannelInterface>
MockPeerConnectionImpl::CreateDataChannel(const std::string& label,
const webrtc::DataChannelInit* config) {
return new rtc::RefCountedObject<MockDataChannel>(label, config);
}
bool MockPeerConnectionImpl::GetStats(
webrtc::StatsObserver* observer,
webrtc::MediaStreamTrackInterface* track,
StatsOutputLevel level) {
if (!getstats_result_)
return false;
DCHECK_EQ(kStatsOutputLevelStandard, level);
webrtc::StatsReport report1(webrtc::StatsReport::NewTypedId(
webrtc::StatsReport::kStatsReportTypeSsrc, "1234"));
webrtc::StatsReport report2(webrtc::StatsReport::NewTypedId(
webrtc::StatsReport::kStatsReportTypeSession, "nontrack"));
report1.set_timestamp(42);
report1.AddString(webrtc::StatsReport::kStatsValueNameFingerprint,
"trackvalue");
webrtc::StatsReports reports;
reports.push_back(&report1);
// If selector is given, we pass back one report.
// If selector is not given, we pass back two.
if (!track) {
report2.set_timestamp(44);
report2.AddString(webrtc::StatsReport::kStatsValueNameFingerprintAlgorithm,
"somevalue");
reports.push_back(&report2);
}
// Note that the callback is synchronous, not asynchronous; it will
// happen before the request call completes.
observer->OnComplete(reports);
return true;
}
void MockPeerConnectionImpl::GetStats(
webrtc::RTCStatsCollectorCallback* callback) {
DCHECK(callback);
DCHECK(stats_report_);
callback->OnStatsDelivered(stats_report_);
}
void MockPeerConnectionImpl::GetStats(
rtc::scoped_refptr<webrtc::RtpSenderInterface> selector,
rtc::scoped_refptr<webrtc::RTCStatsCollectorCallback> callback) {
callback->OnStatsDelivered(stats_report_);
}
void MockPeerConnectionImpl::GetStats(
rtc::scoped_refptr<webrtc::RtpReceiverInterface> selector,
rtc::scoped_refptr<webrtc::RTCStatsCollectorCallback> callback) {
callback->OnStatsDelivered(stats_report_);
}
void MockPeerConnectionImpl::SetGetStatsReport(webrtc::RTCStatsReport* report) {
stats_report_ = report;
}
const webrtc::SessionDescriptionInterface*
MockPeerConnectionImpl::local_description() const {
return local_desc_.get();
}
const webrtc::SessionDescriptionInterface*
MockPeerConnectionImpl::remote_description() const {
return remote_desc_.get();
}
void MockPeerConnectionImpl::AddRemoteStream(MediaStreamInterface* stream) {
remote_streams_->AddStream(stream);
}
void MockPeerConnectionImpl::CreateOffer(
CreateSessionDescriptionObserver* observer,
const RTCOfferAnswerOptions& options) {
DCHECK(observer);
created_sessiondescription_.reset(
dependency_factory_->CreateSessionDescription("unknown", kDummyOffer,
nullptr));
}
void MockPeerConnectionImpl::CreateAnswer(
CreateSessionDescriptionObserver* observer,
const RTCOfferAnswerOptions& options) {
DCHECK(observer);
created_sessiondescription_.reset(
dependency_factory_->CreateSessionDescription("unknown", kDummyAnswer,
nullptr));
}
void MockPeerConnectionImpl::SetLocalDescriptionWorker(
SetSessionDescriptionObserver* observer,
SessionDescriptionInterface* desc) {
desc->ToString(&description_sdp_);
local_desc_.reset(desc);
}
void MockPeerConnectionImpl::SetRemoteDescriptionWorker(
SetSessionDescriptionObserver* observer,
SessionDescriptionInterface* desc) {
desc->ToString(&description_sdp_);
remote_desc_.reset(desc);
}
bool MockPeerConnectionImpl::SetConfiguration(
const RTCConfiguration& configuration,
webrtc::RTCError* error) {
if (setconfiguration_error_type_ == webrtc::RTCErrorType::NONE) {
return true;
}
error->set_type(setconfiguration_error_type_);
return false;
}
bool MockPeerConnectionImpl::AddIceCandidate(
const IceCandidateInterface* candidate) {
sdp_mid_ = candidate->sdp_mid();
sdp_mline_index_ = candidate->sdp_mline_index();
return candidate->ToString(&ice_sdp_);
}
webrtc::RTCError MockPeerConnectionImpl::SetBitrate(
const webrtc::BitrateSettings& bitrate) {
NOTIMPLEMENTED();
return webrtc::RTCError::OK();
}
} // namespace content