Skip to content

[Temporary] Rebase webrtc #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 12 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,4 @@
/xcodebuild
/.vscode
!webrtc/*
out_ios_libs
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
This repository is a private branch of [Google's WebRTC Source](https://chromium.googlesource.com/external/webrtc.git).

This repository is used to compile [SendBirdWebRTC](https://github.com/sendbird/sendbird-webrtc-ios), and keep track of SendBird's changes.

In order to use this repository as a reflection of Google's Public WebRTC source, refer to this [medium guide](https://medium.com/@bilalbayasut/github-how-to-make-a-fork-of-public-repository-private-6ee8cacaf9d3) to fork public repository into this private repository.

---

**WebRTC is a free, open software project** that provides browsers and mobile
applications with Real-Time Communications (RTC) capabilities via simple APIs.
The WebRTC components have been optimized to best serve this purpose.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,68 @@ TEST_F(VideoDecoderSoftwareFallbackWrapperTest,
fallback_wrapper_->Release();
}

TEST_F(VideoDecoderSoftwareFallbackWrapperTest, FallbacksOnTooManyErrors) {
VideoCodec codec = {};
fallback_wrapper_->InitDecode(&codec, 2);

fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_ERROR;
EncodedImage encoded_image;
encoded_image._frameType = VideoFrameType::kVideoFrameKey;
// Doesn't fallback from a single error.
fallback_wrapper_->Decode(encoded_image, false, -1);
EXPECT_STREQ("fake-decoder", fallback_wrapper_->ImplementationName());

// However, many frames with the same error, fallback should happen.
const int kNumFramesToEncode = 10;
for (int i = 0; i < kNumFramesToEncode; ++i) {
fallback_wrapper_->Decode(encoded_image, false, -1);
}
// Hard coded expected value since libvpx is the software implementation name
// for VP8. Change accordingly if the underlying implementation does.
EXPECT_STREQ("libvpx (fallback from: fake-decoder)",
fallback_wrapper_->ImplementationName());
fallback_wrapper_->Release();
}

TEST_F(VideoDecoderSoftwareFallbackWrapperTest,
DoesNotFallbackOnDeltaFramesErrors) {
VideoCodec codec = {};
fallback_wrapper_->InitDecode(&codec, 2);

fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_ERROR;
EncodedImage encoded_image;
encoded_image._frameType = VideoFrameType::kVideoFrameDelta;

// Many decoded frames with the same error
const int kNumFramesToEncode = 10;
for (int i = 0; i < kNumFramesToEncode; ++i) {
fallback_wrapper_->Decode(encoded_image, false, -1);
}
EXPECT_STREQ("fake-decoder", fallback_wrapper_->ImplementationName());

fallback_wrapper_->Release();
}

TEST_F(VideoDecoderSoftwareFallbackWrapperTest,
DoesNotFallbacksOnNonConsequtiveErrors) {
VideoCodec codec = {};
fallback_wrapper_->InitDecode(&codec, 2);

EncodedImage encoded_image;
encoded_image._frameType = VideoFrameType::kVideoFrameKey;

const int kNumFramesToEncode = 10;
for (int i = 0; i < kNumFramesToEncode; ++i) {
// Interleaved errors and successful decodes.
fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_ERROR;
fallback_wrapper_->Decode(encoded_image, false, -1);
fake_decoder_->decode_return_code_ = WEBRTC_VIDEO_CODEC_OK;
fallback_wrapper_->Decode(encoded_image, false, -1);
}
EXPECT_STREQ("fake-decoder", fallback_wrapper_->ImplementationName());
fallback_wrapper_->Release();
}

class ForcedSoftwareDecoderFallbackTest
: public VideoDecoderSoftwareFallbackWrapperTest {
public:
Expand Down
22 changes: 18 additions & 4 deletions api/video_codecs/video_decoder_software_fallback_wrapper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ namespace webrtc {

namespace {

constexpr size_t kMaxConsequtiveHwErrors = 4;

class VideoDecoderSoftwareFallbackWrapper final : public VideoDecoder {
public:
VideoDecoderSoftwareFallbackWrapper(
Expand Down Expand Up @@ -74,6 +76,7 @@ class VideoDecoderSoftwareFallbackWrapper final : public VideoDecoder {
const std::string fallback_implementation_name_;
DecodedImageCallback* callback_;
int32_t hw_decoded_frames_since_last_fallback_;
size_t hw_consequtive_generic_errors_;
};

VideoDecoderSoftwareFallbackWrapper::VideoDecoderSoftwareFallbackWrapper(
Expand All @@ -86,7 +89,8 @@ VideoDecoderSoftwareFallbackWrapper::VideoDecoderSoftwareFallbackWrapper(
std::string(fallback_decoder_->ImplementationName()) +
" (fallback from: " + hw_decoder_->ImplementationName() + ")"),
callback_(nullptr),
hw_decoded_frames_since_last_fallback_(0) {}
hw_decoded_frames_since_last_fallback_(0),
hw_consequtive_generic_errors_(0) {}
VideoDecoderSoftwareFallbackWrapper::~VideoDecoderSoftwareFallbackWrapper() =
default;

Expand Down Expand Up @@ -196,14 +200,24 @@ int32_t VideoDecoderSoftwareFallbackWrapper::Decode(
int32_t ret = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
ret = hw_decoder_->Decode(input_image, missing_frames, render_time_ms);
if (ret != WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE) {
if (ret == WEBRTC_VIDEO_CODEC_OK) {
if (ret != WEBRTC_VIDEO_CODEC_ERROR) {
++hw_decoded_frames_since_last_fallback_;
hw_consequtive_generic_errors_ = 0;
return ret;
}
if (input_image._frameType == VideoFrameType::kVideoFrameKey) {
// Only count errors on key-frames, since generic errors can happen
// with hw decoder due to many arbitrary reasons.
// However, requesting a key-frame is supposed to fix the issue.
++hw_consequtive_generic_errors_;
}
if (hw_consequtive_generic_errors_ < kMaxConsequtiveHwErrors) {
return ret;
}
return ret;
}

// HW decoder returned WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE or
// initialization failed, fallback to software.
// too many generic errors on key-frames encountered.
if (!InitFallbackDecoder()) {
return ret;
}
Expand Down
2 changes: 2 additions & 0 deletions call/rtp_video_sender.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "rtc_base/checks.h"
#include "rtc_base/location.h"
#include "rtc_base/logging.h"
#include "rtc_base/task_queue.h"

namespace webrtc {

Expand Down Expand Up @@ -281,6 +282,7 @@ std::vector<RtpStreamSender> CreateRtpStreamSenders(
video_config.fec_overhead_bytes = fec_generator->MaxPacketOverhead();
}
video_config.frame_transformer = frame_transformer;
video_config.worker_queue = transport->GetWorkerQueue()->Get();
auto sender_video = std::make_unique<RTPSenderVideo>(video_config);
rtp_streams.emplace_back(std::move(rtp_rtcp), std::move(sender_video),
std::move(fec_generator));
Expand Down
4 changes: 3 additions & 1 deletion media/engine/webrtc_video_engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1587,6 +1587,8 @@ void WebRtcVideoChannel::FillSenderStats(VideoMediaInfo* video_media_info,
send_streams_.begin();
it != send_streams_.end(); ++it) {
auto infos = it->second->GetPerLayerVideoSenderInfos(log_stats);
if (infos.empty())
continue;
video_media_info->aggregated_senders.push_back(
it->second->GetAggregatedVideoSenderInfo(infos));
for (auto&& info : infos) {
Expand Down Expand Up @@ -2594,7 +2596,7 @@ VideoSenderInfo
WebRtcVideoChannel::WebRtcVideoSendStream::GetAggregatedVideoSenderInfo(
const std::vector<VideoSenderInfo>& infos) const {
RTC_DCHECK_RUN_ON(&thread_checker_);
RTC_DCHECK(!infos.empty());
RTC_CHECK(!infos.empty());
if (infos.size() == 1) {
return infos[0];
}
Expand Down
21 changes: 21 additions & 0 deletions media/engine/webrtc_video_engine_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5595,6 +5595,27 @@ TEST_F(WebRtcVideoChannelTest, GetPerLayerStatsReportForSubStreams) {
EXPECT_EQ(sender.rid, absl::nullopt);
}

TEST_F(WebRtcVideoChannelTest, MediaSubstreamMissingProducesEmpyStats) {
FakeVideoSendStream* stream = AddSendStream();

const uint32_t kRtxSsrc = 123u;
const uint32_t kMissingMediaSsrc = 124u;

// Set up a scenarios where we have a substream that is not kMedia (in this
// case: kRtx) but its associated kMedia stream does not exist yet. This
// results in zero GetPerLayerVideoSenderInfos despite non-empty substreams.
// Covers https://crbug.com/1090712.
auto stats = GetInitialisedStats();
auto& substream = stats.substreams[kRtxSsrc];
substream.type = webrtc::VideoSendStream::StreamStats::StreamType::kRtx;
substream.referenced_media_ssrc = kMissingMediaSsrc;
stream->SetStats(stats);

cricket::VideoMediaInfo video_media_info;
ASSERT_TRUE(channel_->GetStats(&video_media_info));
EXPECT_TRUE(video_media_info.senders.empty());
}

TEST_F(WebRtcVideoChannelTest, GetStatsReportsUpperResolution) {
FakeVideoSendStream* stream = AddSendStream();
webrtc::VideoSendStream::Stats stats;
Expand Down
101 changes: 91 additions & 10 deletions media/sctp/sctp_transport.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ enum PreservedErrno {
#include <stdio.h>

#include <memory>
#include <unordered_map>

#include "absl/algorithm/container.h"
#include "absl/base/attributes.h"
Expand All @@ -39,6 +40,7 @@ enum PreservedErrno {
#include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "rtc_base/string_utils.h"
#include "rtc_base/thread_annotations.h"
#include "rtc_base/thread_checker.h"
#include "rtc_base/trace_event.h"
#include "usrsctplib/usrsctp.h"
Expand Down Expand Up @@ -72,6 +74,59 @@ enum PayloadProtocolIdentifier {
PPID_TEXT_LAST = 51
};

// Maps SCTP transport ID to SctpTransport object, necessary in send threshold
// callback and outgoing packet callback.
// TODO(crbug.com/1076703): Remove once the underlying problem is fixed or
// workaround is provided in usrsctp.
class SctpTransportMap {
public:
SctpTransportMap() = default;

// Assigns a new unused ID to the following transport.
uintptr_t Register(cricket::SctpTransport* transport) {
rtc::CritScope cs(&lock_);
// usrsctp_connect fails with a value of 0...
if (next_id_ == 0) {
++next_id_;
}
// In case we've wrapped around and need to find an empty spot from a
// removed transport. Assumes we'll never be full.
while (map_.find(next_id_) != map_.end()) {
++next_id_;
if (next_id_ == 0) {
++next_id_;
}
};
map_[next_id_] = transport;
return next_id_++;
}

// Returns true if found.
bool Deregister(uintptr_t id) {
rtc::CritScope cs(&lock_);
return map_.erase(id) > 0;
}

cricket::SctpTransport* Retrieve(uintptr_t id) const {
rtc::CritScope cs(&lock_);
auto it = map_.find(id);
if (it == map_.end()) {
return nullptr;
}
return it->second;
}

private:
rtc::CriticalSection lock_;

uintptr_t next_id_ RTC_GUARDED_BY(lock_) = 0;
std::unordered_map<uintptr_t, cricket::SctpTransport*> map_
RTC_GUARDED_BY(lock_);
};

// Should only be modified by UsrSctpWrapper.
ABSL_CONST_INIT SctpTransportMap* g_transport_map_ = nullptr;

// Helper for logging SCTP messages.
#if defined(__GNUC__)
__attribute__((__format__(__printf__, 1, 2)))
Expand Down Expand Up @@ -242,6 +297,8 @@ class SctpTransport::UsrSctpWrapper {
// Set the number of default outgoing streams. This is the number we'll
// send in the SCTP INIT message.
usrsctp_sysctl_set_sctp_nr_outgoing_streams_default(kMaxSctpStreams);

g_transport_map_ = new SctpTransportMap();
}

static void UninitializeUsrSctp() {
Expand All @@ -251,11 +308,15 @@ class SctpTransport::UsrSctpWrapper {
// closed. Wait and try again until it succeeds for up to 3 seconds.
for (size_t i = 0; i < 300; ++i) {
if (usrsctp_finish() == 0) {
delete g_transport_map_;
g_transport_map_ = nullptr;
return;
}

rtc::Thread::SleepMs(10);
}
delete g_transport_map_;
g_transport_map_ = nullptr;
RTC_LOG(LS_ERROR) << "Failed to shutdown usrsctp.";
}

Expand All @@ -282,7 +343,19 @@ class SctpTransport::UsrSctpWrapper {
size_t length,
uint8_t tos,
uint8_t set_df) {
SctpTransport* transport = static_cast<SctpTransport*>(addr);
if (!g_transport_map_) {
RTC_LOG(LS_ERROR)
<< "OnSctpOutboundPacket called after usrsctp uninitialized?";
return EINVAL;
}
SctpTransport* transport =
g_transport_map_->Retrieve(reinterpret_cast<uintptr_t>(addr));
if (!transport) {
RTC_LOG(LS_ERROR)
<< "OnSctpOutboundPacket: Failed to get transport for socket ID "
<< addr;
return EINVAL;
}
RTC_LOG(LS_VERBOSE) << "global OnSctpOutboundPacket():"
"addr: "
<< addr << "; length: " << length
Expand Down Expand Up @@ -392,14 +465,20 @@ class SctpTransport::UsrSctpWrapper {
return nullptr;
}
// usrsctp_getladdrs() returns the addresses bound to this socket, which
// contains the SctpTransport* as sconn_addr. Read the pointer,
// contains the SctpTransport id as sconn_addr. Read the id,
// then free the list of addresses once we have the pointer. We only open
// AF_CONN sockets, and they should all have the sconn_addr set to the
// pointer that created them, so [0] is as good as any other.
// id of the transport that created them, so [0] is as good as any other.
struct sockaddr_conn* sconn =
reinterpret_cast<struct sockaddr_conn*>(&addrs[0]);
SctpTransport* transport =
reinterpret_cast<SctpTransport*>(sconn->sconn_addr);
if (!g_transport_map_) {
RTC_LOG(LS_ERROR)
<< "GetTransportFromSocket called after usrsctp uninitialized?";
usrsctp_freeladdrs(addrs);
return nullptr;
}
SctpTransport* transport = g_transport_map_->Retrieve(
reinterpret_cast<uintptr_t>(sconn->sconn_addr));
usrsctp_freeladdrs(addrs);

return transport;
Expand Down Expand Up @@ -779,9 +858,10 @@ bool SctpTransport::OpenSctpSocket() {
UsrSctpWrapper::DecrementUsrSctpUsageCount();
return false;
}
// Register this class as an address for usrsctp. This is used by SCTP to
id_ = g_transport_map_->Register(this);
// Register our id as an address for usrsctp. This is used by SCTP to
// direct the packets received (by the created socket) to this class.
usrsctp_register_address(this);
usrsctp_register_address(reinterpret_cast<void*>(id_));
return true;
}

Expand Down Expand Up @@ -872,7 +952,8 @@ void SctpTransport::CloseSctpSocket() {
// discarded instead of being sent.
usrsctp_close(sock_);
sock_ = nullptr;
usrsctp_deregister_address(this);
usrsctp_deregister_address(reinterpret_cast<void*>(id_));
RTC_CHECK(g_transport_map_->Deregister(id_));
UsrSctpWrapper::DecrementUsrSctpUsageCount();
ready_to_send_data_ = false;
}
Expand Down Expand Up @@ -1003,7 +1084,7 @@ void SctpTransport::OnPacketRead(rtc::PacketTransportInternal* transport,
// will be will be given to the global OnSctpInboundData, and then,
// marshalled by the AsyncInvoker.
VerboseLogPacket(data, len, SCTP_DUMP_INBOUND);
usrsctp_conninput(this, data, len, 0);
usrsctp_conninput(reinterpret_cast<void*>(id_), data, len, 0);
} else {
// TODO(ldixon): Consider caching the packet for very slightly better
// reliability.
Expand Down Expand Up @@ -1033,7 +1114,7 @@ sockaddr_conn SctpTransport::GetSctpSockAddr(int port) {
#endif
// Note: conversion from int to uint16_t happens here.
sconn.sconn_port = rtc::HostToNetwork16(port);
sconn.sconn_addr = this;
sconn.sconn_addr = reinterpret_cast<void*>(id_);
return sconn;
}

Expand Down
Loading