Network up/down signaling in Call.
BUG=2429 R=mflodman@webrtc.org, stefan@webrtc.org Review URL: https://webrtc-codereview.appspot.com/13109005 git-svn-id: http://webrtc.googlecode.com/svn/trunk@7044 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
ebee401230
commit
26c0c41a06
@ -1153,7 +1153,9 @@ void WebRtcVideoChannel2::OnRtcpReceived(
|
||||
}
|
||||
|
||||
void WebRtcVideoChannel2::OnReadyToSend(bool ready) {
|
||||
LOG(LS_VERBOSE) << "OnReadySend: " << (ready ? "Ready." : "Not ready.");
|
||||
LOG(LS_VERBOSE) << "OnReadyToSend: " << (ready ? "Ready." : "Not ready.");
|
||||
call_->SignalNetworkState(ready ? webrtc::Call::kNetworkUp
|
||||
: webrtc::Call::kNetworkDown);
|
||||
}
|
||||
|
||||
bool WebRtcVideoChannel2::MuteStream(uint32 ssrc, bool mute) {
|
||||
|
@ -157,7 +157,9 @@ void FakeVideoReceiveStream::Stop() {
|
||||
void FakeVideoReceiveStream::GetCurrentReceiveCodec(webrtc::VideoCodec* codec) {
|
||||
}
|
||||
|
||||
FakeCall::FakeCall() { SetVideoCodecs(GetDefaultVideoCodecs()); }
|
||||
FakeCall::FakeCall() : network_state_(kNetworkUp) {
|
||||
SetVideoCodecs(GetDefaultVideoCodecs());
|
||||
}
|
||||
|
||||
FakeCall::~FakeCall() {
|
||||
EXPECT_EQ(0u, video_send_streams_.size());
|
||||
@ -218,6 +220,10 @@ std::vector<webrtc::VideoCodec> FakeCall::GetDefaultVideoCodecs() {
|
||||
return codecs;
|
||||
}
|
||||
|
||||
webrtc::Call::NetworkState FakeCall::GetNetworkState() const {
|
||||
return network_state_;
|
||||
}
|
||||
|
||||
webrtc::VideoSendStream* FakeCall::CreateVideoSendStream(
|
||||
const webrtc::VideoSendStream::Config& config,
|
||||
const std::vector<webrtc::VideoStream>& video_streams,
|
||||
@ -274,6 +280,10 @@ uint32_t FakeCall::ReceiveBitrateEstimate() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FakeCall::SignalNetworkState(webrtc::Call::NetworkState state) {
|
||||
network_state_ = state;
|
||||
}
|
||||
|
||||
FakeWebRtcVideoChannel2::FakeWebRtcVideoChannel2(
|
||||
FakeCall* call,
|
||||
WebRtcVideoEngine2* engine,
|
||||
@ -289,6 +299,7 @@ FakeWebRtcVideoChannel2::~FakeWebRtcVideoChannel2() {
|
||||
VoiceMediaChannel* FakeWebRtcVideoChannel2::GetVoiceChannel() {
|
||||
return voice_channel_;
|
||||
}
|
||||
|
||||
FakeCall* FakeWebRtcVideoChannel2::GetFakeCall() {
|
||||
return fake_call_;
|
||||
}
|
||||
@ -1614,8 +1625,17 @@ TEST_F(WebRtcVideoChannel2Test, DISABLED_UpdateEncoderCodecsAfterSetFactory) {
|
||||
FAIL() << "Not implemented."; // TODO(pbos): Implement.
|
||||
}
|
||||
|
||||
TEST_F(WebRtcVideoChannel2Test, DISABLED_OnReadyToSend) {
|
||||
FAIL() << "Not implemented."; // TODO(pbos): Implement.
|
||||
TEST_F(WebRtcVideoChannel2Test, OnReadyToSendSignalsNetworkState) {
|
||||
EXPECT_EQ(webrtc::Call::kNetworkUp,
|
||||
fake_channel_->GetFakeCall()->GetNetworkState());
|
||||
|
||||
channel_->OnReadyToSend(false);
|
||||
EXPECT_EQ(webrtc::Call::kNetworkDown,
|
||||
fake_channel_->GetFakeCall()->GetNetworkState());
|
||||
|
||||
channel_->OnReadyToSend(true);
|
||||
EXPECT_EQ(webrtc::Call::kNetworkUp,
|
||||
fake_channel_->GetFakeCall()->GetNetworkState());
|
||||
}
|
||||
|
||||
TEST_F(WebRtcVideoChannel2Test, DISABLED_CaptureFrameTimestampToNtpTimestamp) {
|
||||
|
@ -103,6 +103,8 @@ class FakeCall : public webrtc::Call {
|
||||
|
||||
std::vector<webrtc::VideoCodec> GetDefaultVideoCodecs();
|
||||
|
||||
webrtc::Call::NetworkState GetNetworkState() const;
|
||||
|
||||
private:
|
||||
virtual webrtc::VideoSendStream* CreateVideoSendStream(
|
||||
const webrtc::VideoSendStream::Config& config,
|
||||
@ -122,6 +124,9 @@ class FakeCall : public webrtc::Call {
|
||||
virtual uint32_t SendBitrateEstimate() OVERRIDE;
|
||||
virtual uint32_t ReceiveBitrateEstimate() OVERRIDE;
|
||||
|
||||
virtual void SignalNetworkState(webrtc::Call::NetworkState state) OVERRIDE;
|
||||
|
||||
webrtc::Call::NetworkState network_state_;
|
||||
std::vector<webrtc::VideoCodec> codecs_;
|
||||
std::vector<FakeVideoSendStream*> video_send_streams_;
|
||||
std::vector<FakeVideoReceiveStream*> video_receive_streams_;
|
||||
|
@ -56,6 +56,10 @@ class OveruseCallback {
|
||||
// etc.
|
||||
class Call {
|
||||
public:
|
||||
enum NetworkState {
|
||||
kNetworkUp,
|
||||
kNetworkDown,
|
||||
};
|
||||
struct Config {
|
||||
explicit Config(newapi::Transport* send_transport)
|
||||
: webrtc_config(NULL),
|
||||
@ -111,6 +115,8 @@ class Call {
|
||||
// differ from the actual receive bitrate.
|
||||
virtual uint32_t ReceiveBitrateEstimate() = 0;
|
||||
|
||||
virtual void SignalNetworkState(NetworkState state) = 0;
|
||||
|
||||
virtual ~Call() {}
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
@ -28,6 +28,8 @@
|
||||
#include "webrtc/video_engine/include/vie_base.h"
|
||||
#include "webrtc/video_engine/include/vie_codec.h"
|
||||
#include "webrtc/video_engine/include/vie_rtp_rtcp.h"
|
||||
#include "webrtc/video_engine/include/vie_network.h"
|
||||
#include "webrtc/video_engine/include/vie_rtp_rtcp.h"
|
||||
|
||||
namespace webrtc {
|
||||
const char* RtpExtension::kTOffset = "urn:ietf:params:rtp-hdrext:toffset";
|
||||
@ -93,18 +95,26 @@ class Call : public webrtc::Call, public PacketReceiver {
|
||||
virtual DeliveryStatus DeliverPacket(const uint8_t* packet,
|
||||
size_t length) OVERRIDE;
|
||||
|
||||
virtual void SignalNetworkState(NetworkState state) OVERRIDE;
|
||||
|
||||
private:
|
||||
DeliveryStatus DeliverRtcp(const uint8_t* packet, size_t length);
|
||||
DeliveryStatus DeliverRtp(const uint8_t* packet, size_t length);
|
||||
|
||||
Call::Config config_;
|
||||
|
||||
std::map<uint32_t, VideoReceiveStream*> receive_ssrcs_
|
||||
GUARDED_BY(receive_lock_);
|
||||
scoped_ptr<RWLockWrapper> receive_lock_;
|
||||
// Needs to be held while write-locking |receive_crit_| or |send_crit_|. This
|
||||
// ensures that we have a consistent network state signalled to all senders
|
||||
// and receivers.
|
||||
scoped_ptr<CriticalSectionWrapper> network_enabled_crit_;
|
||||
bool network_enabled_ GUARDED_BY(network_enabled_crit_);
|
||||
|
||||
std::map<uint32_t, VideoSendStream*> send_ssrcs_ GUARDED_BY(send_lock_);
|
||||
scoped_ptr<RWLockWrapper> send_lock_;
|
||||
scoped_ptr<RWLockWrapper> receive_crit_;
|
||||
std::map<uint32_t, VideoReceiveStream*> receive_ssrcs_
|
||||
GUARDED_BY(receive_crit_);
|
||||
|
||||
scoped_ptr<RWLockWrapper> send_crit_;
|
||||
std::map<uint32_t, VideoSendStream*> send_ssrcs_ GUARDED_BY(send_crit_);
|
||||
|
||||
scoped_ptr<CpuOveruseObserverProxy> overuse_observer_proxy_;
|
||||
|
||||
@ -135,8 +145,10 @@ const int kDefaultVideoStreamBitrateBps = 300000;
|
||||
|
||||
Call::Call(webrtc::VideoEngine* video_engine, const Call::Config& config)
|
||||
: config_(config),
|
||||
receive_lock_(RWLockWrapper::CreateRWLock()),
|
||||
send_lock_(RWLockWrapper::CreateRWLock()),
|
||||
network_enabled_crit_(CriticalSectionWrapper::CreateCriticalSection()),
|
||||
network_enabled_(true),
|
||||
receive_crit_(RWLockWrapper::CreateRWLock()),
|
||||
send_crit_(RWLockWrapper::CreateRWLock()),
|
||||
video_engine_(video_engine),
|
||||
base_channel_id_(-1) {
|
||||
assert(video_engine != NULL);
|
||||
@ -192,11 +204,16 @@ VideoSendStream* Call::CreateVideoSendStream(
|
||||
config_.start_bitrate_bps != -1 ? config_.start_bitrate_bps
|
||||
: kDefaultVideoStreamBitrateBps);
|
||||
|
||||
WriteLockScoped write_lock(*send_lock_);
|
||||
// This needs to be taken before send_crit_ as both locks need to be held
|
||||
// while changing network state.
|
||||
CriticalSectionScoped lock(network_enabled_crit_.get());
|
||||
WriteLockScoped write_lock(*send_crit_);
|
||||
for (size_t i = 0; i < config.rtp.ssrcs.size(); ++i) {
|
||||
assert(send_ssrcs_.find(config.rtp.ssrcs[i]) == send_ssrcs_.end());
|
||||
send_ssrcs_[config.rtp.ssrcs[i]] = send_stream;
|
||||
}
|
||||
if (!network_enabled_)
|
||||
send_stream->SignalNetworkState(kNetworkDown);
|
||||
return send_stream;
|
||||
}
|
||||
|
||||
@ -207,7 +224,7 @@ void Call::DestroyVideoSendStream(webrtc::VideoSendStream* send_stream) {
|
||||
|
||||
VideoSendStream* send_stream_impl = NULL;
|
||||
{
|
||||
WriteLockScoped write_lock(*send_lock_);
|
||||
WriteLockScoped write_lock(*send_crit_);
|
||||
std::map<uint32_t, VideoSendStream*>::iterator it = send_ssrcs_.begin();
|
||||
while (it != send_ssrcs_.end()) {
|
||||
if (it->second == static_cast<VideoSendStream*>(send_stream)) {
|
||||
@ -240,7 +257,10 @@ VideoReceiveStream* Call::CreateVideoReceiveStream(
|
||||
config_.voice_engine,
|
||||
base_channel_id_);
|
||||
|
||||
WriteLockScoped write_lock(*receive_lock_);
|
||||
// This needs to be taken before receive_crit_ as both locks need to be held
|
||||
// while changing network state.
|
||||
CriticalSectionScoped lock(network_enabled_crit_.get());
|
||||
WriteLockScoped write_lock(*receive_crit_);
|
||||
assert(receive_ssrcs_.find(config.rtp.remote_ssrc) == receive_ssrcs_.end());
|
||||
receive_ssrcs_[config.rtp.remote_ssrc] = receive_stream;
|
||||
// TODO(pbos): Configure different RTX payloads per receive payload.
|
||||
@ -249,6 +269,8 @@ VideoReceiveStream* Call::CreateVideoReceiveStream(
|
||||
if (it != config.rtp.rtx.end())
|
||||
receive_ssrcs_[it->second.ssrc] = receive_stream;
|
||||
|
||||
if (!network_enabled_)
|
||||
receive_stream->SignalNetworkState(kNetworkDown);
|
||||
return receive_stream;
|
||||
}
|
||||
|
||||
@ -258,7 +280,7 @@ void Call::DestroyVideoReceiveStream(
|
||||
|
||||
VideoReceiveStream* receive_stream_impl = NULL;
|
||||
{
|
||||
WriteLockScoped write_lock(*receive_lock_);
|
||||
WriteLockScoped write_lock(*receive_crit_);
|
||||
// Remove all ssrcs pointing to a receive stream. As RTX retransmits on a
|
||||
// separate SSRC there can be either one or two.
|
||||
std::map<uint32_t, VideoReceiveStream*>::iterator it =
|
||||
@ -289,6 +311,31 @@ uint32_t Call::ReceiveBitrateEstimate() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Call::SignalNetworkState(NetworkState state) {
|
||||
// Take crit for entire function, it needs to be held while updating streams
|
||||
// to guarantee a consistent state across streams.
|
||||
CriticalSectionScoped lock(network_enabled_crit_.get());
|
||||
network_enabled_ = state == kNetworkUp;
|
||||
{
|
||||
ReadLockScoped write_lock(*send_crit_);
|
||||
for (std::map<uint32_t, VideoSendStream*>::iterator it =
|
||||
send_ssrcs_.begin();
|
||||
it != send_ssrcs_.end();
|
||||
++it) {
|
||||
it->second->SignalNetworkState(state);
|
||||
}
|
||||
}
|
||||
{
|
||||
ReadLockScoped write_lock(*receive_crit_);
|
||||
for (std::map<uint32_t, VideoReceiveStream*>::iterator it =
|
||||
receive_ssrcs_.begin();
|
||||
it != receive_ssrcs_.end();
|
||||
++it) {
|
||||
it->second->SignalNetworkState(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PacketReceiver::DeliveryStatus Call::DeliverRtcp(const uint8_t* packet,
|
||||
size_t length) {
|
||||
// TODO(pbos): Figure out what channel needs it actually.
|
||||
@ -297,7 +344,7 @@ PacketReceiver::DeliveryStatus Call::DeliverRtcp(const uint8_t* packet,
|
||||
// there's no receiver of the packet.
|
||||
bool rtcp_delivered = false;
|
||||
{
|
||||
ReadLockScoped read_lock(*receive_lock_);
|
||||
ReadLockScoped read_lock(*receive_crit_);
|
||||
for (std::map<uint32_t, VideoReceiveStream*>::iterator it =
|
||||
receive_ssrcs_.begin();
|
||||
it != receive_ssrcs_.end();
|
||||
@ -308,7 +355,7 @@ PacketReceiver::DeliveryStatus Call::DeliverRtcp(const uint8_t* packet,
|
||||
}
|
||||
|
||||
{
|
||||
ReadLockScoped read_lock(*send_lock_);
|
||||
ReadLockScoped read_lock(*send_crit_);
|
||||
for (std::map<uint32_t, VideoSendStream*>::iterator it =
|
||||
send_ssrcs_.begin();
|
||||
it != send_ssrcs_.end();
|
||||
@ -329,7 +376,7 @@ PacketReceiver::DeliveryStatus Call::DeliverRtp(const uint8_t* packet,
|
||||
const uint8_t* ptr = &packet[8];
|
||||
uint32_t ssrc = ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
|
||||
|
||||
ReadLockScoped read_lock(*receive_lock_);
|
||||
ReadLockScoped read_lock(*receive_crit_);
|
||||
std::map<uint32_t, VideoReceiveStream*>::iterator it =
|
||||
receive_ssrcs_.find(ssrc);
|
||||
|
||||
|
@ -43,6 +43,7 @@
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
static const unsigned long kSilenceTimeoutMs = 2000;
|
||||
static const int kRedPayloadType = 118;
|
||||
static const int kUlpfecPayloadType = 119;
|
||||
|
||||
@ -56,6 +57,19 @@ class EndToEndTest : public test::CallTest {
|
||||
}
|
||||
|
||||
protected:
|
||||
class UnusedTransport : public newapi::Transport {
|
||||
private:
|
||||
virtual bool SendRtp(const uint8_t* packet, size_t length) OVERRIDE {
|
||||
ADD_FAILURE() << "Unexpected RTP sent.";
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool SendRtcp(const uint8_t* packet, size_t length) OVERRIDE {
|
||||
ADD_FAILURE() << "Unexpected RTCP sent.";
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
void DecodesRetransmittedFrame(bool retransmit_over_rtx);
|
||||
void ReceivesPliAndRecovers(int rtp_history_ms);
|
||||
void RespectsRtcpMode(newapi::RtcpMode rtcp_mode);
|
||||
@ -1840,6 +1854,228 @@ TEST_F(EndToEndTest, RestartingSendStreamPreservesRtpStatesWithRtx) {
|
||||
TestRtpStatePreservation(true);
|
||||
}
|
||||
|
||||
TEST_F(EndToEndTest, RespectsNetworkState) {
|
||||
// TODO(pbos): Remove accepted downtime packets etc. when signaling network
|
||||
// down blocks until no more packets will be sent.
|
||||
|
||||
// Pacer will send from its packet list and then send required padding before
|
||||
// checking paused_ again. This should be enough for one round of pacing,
|
||||
// otherwise increase.
|
||||
static const int kNumAcceptedDowntimeRtp = 5;
|
||||
// A single RTCP may be in the pipeline.
|
||||
static const int kNumAcceptedDowntimeRtcp = 1;
|
||||
class NetworkStateTest : public test::EndToEndTest, public test::FakeEncoder {
|
||||
public:
|
||||
NetworkStateTest()
|
||||
: EndToEndTest(kDefaultTimeoutMs),
|
||||
FakeEncoder(Clock::GetRealTimeClock()),
|
||||
test_crit_(CriticalSectionWrapper::CreateCriticalSection()),
|
||||
encoded_frames_(EventWrapper::Create()),
|
||||
sender_packets_(EventWrapper::Create()),
|
||||
receiver_packets_(EventWrapper::Create()),
|
||||
sender_state_(Call::kNetworkUp),
|
||||
down_sender_rtp_(0),
|
||||
down_sender_rtcp_(0),
|
||||
receiver_state_(Call::kNetworkUp),
|
||||
down_receiver_rtcp_(0),
|
||||
down_frames_(0) {}
|
||||
|
||||
virtual Action OnSendRtp(const uint8_t* packet, size_t length) OVERRIDE {
|
||||
CriticalSectionScoped lock(test_crit_.get());
|
||||
if (sender_state_ == Call::kNetworkDown) {
|
||||
++down_sender_rtp_;
|
||||
EXPECT_LE(down_sender_rtp_, kNumAcceptedDowntimeRtp)
|
||||
<< "RTP sent during sender-side downtime.";
|
||||
if (down_sender_rtp_> kNumAcceptedDowntimeRtp)
|
||||
sender_packets_->Set();
|
||||
} else {
|
||||
sender_packets_->Set();
|
||||
}
|
||||
return SEND_PACKET;
|
||||
}
|
||||
|
||||
virtual Action OnSendRtcp(const uint8_t* packet, size_t length) OVERRIDE {
|
||||
CriticalSectionScoped lock(test_crit_.get());
|
||||
if (sender_state_ == Call::kNetworkDown) {
|
||||
++down_sender_rtcp_;
|
||||
EXPECT_LE(down_sender_rtcp_, kNumAcceptedDowntimeRtcp)
|
||||
<< "RTCP sent during sender-side downtime.";
|
||||
if (down_sender_rtcp_ > kNumAcceptedDowntimeRtcp)
|
||||
sender_packets_->Set();
|
||||
} else {
|
||||
sender_packets_->Set();
|
||||
}
|
||||
return SEND_PACKET;
|
||||
}
|
||||
|
||||
virtual Action OnReceiveRtp(const uint8_t* packet, size_t length) OVERRIDE {
|
||||
ADD_FAILURE() << "Unexpected receiver RTP, should not be sending.";
|
||||
return SEND_PACKET;
|
||||
}
|
||||
|
||||
virtual Action OnReceiveRtcp(const uint8_t* packet,
|
||||
size_t length) OVERRIDE {
|
||||
CriticalSectionScoped lock(test_crit_.get());
|
||||
if (receiver_state_ == Call::kNetworkDown) {
|
||||
++down_receiver_rtcp_;
|
||||
EXPECT_LE(down_receiver_rtcp_, kNumAcceptedDowntimeRtcp)
|
||||
<< "RTCP sent during receiver-side downtime.";
|
||||
if (down_receiver_rtcp_ > kNumAcceptedDowntimeRtcp)
|
||||
receiver_packets_->Set();
|
||||
} else {
|
||||
receiver_packets_->Set();
|
||||
}
|
||||
return SEND_PACKET;
|
||||
}
|
||||
|
||||
virtual void OnCallsCreated(Call* sender_call,
|
||||
Call* receiver_call) OVERRIDE {
|
||||
sender_call_ = sender_call;
|
||||
receiver_call_ = receiver_call;
|
||||
}
|
||||
|
||||
virtual void ModifyConfigs(
|
||||
VideoSendStream::Config* send_config,
|
||||
std::vector<VideoReceiveStream::Config>* receive_configs,
|
||||
std::vector<VideoStream>* video_streams) OVERRIDE {
|
||||
send_config->encoder_settings.encoder = this;
|
||||
}
|
||||
|
||||
virtual void PerformTest() OVERRIDE {
|
||||
EXPECT_EQ(kEventSignaled, encoded_frames_->Wait(kDefaultTimeoutMs))
|
||||
<< "No frames received by the encoder.";
|
||||
EXPECT_EQ(kEventSignaled, sender_packets_->Wait(kDefaultTimeoutMs))
|
||||
<< "Timed out waiting for send-side packets.";
|
||||
EXPECT_EQ(kEventSignaled, receiver_packets_->Wait(kDefaultTimeoutMs))
|
||||
<< "Timed out waiting for receiver-side packets.";
|
||||
|
||||
// Sender-side network down.
|
||||
sender_call_->SignalNetworkState(Call::kNetworkDown);
|
||||
{
|
||||
CriticalSectionScoped lock(test_crit_.get());
|
||||
sender_packets_->Reset(); // Earlier packets should not count.
|
||||
sender_state_ = Call::kNetworkDown;
|
||||
}
|
||||
EXPECT_EQ(kEventTimeout, sender_packets_->Wait(kSilenceTimeoutMs))
|
||||
<< "Packets sent during sender-network downtime.";
|
||||
EXPECT_EQ(kEventSignaled, receiver_packets_->Wait(kDefaultTimeoutMs))
|
||||
<< "Timed out waiting for receiver-side packets.";
|
||||
// Receiver-side network down.
|
||||
receiver_call_->SignalNetworkState(Call::kNetworkDown);
|
||||
{
|
||||
CriticalSectionScoped lock(test_crit_.get());
|
||||
receiver_packets_->Reset(); // Earlier packets should not count.
|
||||
receiver_state_ = Call::kNetworkDown;
|
||||
}
|
||||
EXPECT_EQ(kEventTimeout, receiver_packets_->Wait(kSilenceTimeoutMs))
|
||||
<< "Packets sent during receiver-network downtime.";
|
||||
|
||||
// Network back up again for both.
|
||||
{
|
||||
CriticalSectionScoped lock(test_crit_.get());
|
||||
sender_packets_->Reset(); // Earlier packets should not count.
|
||||
receiver_packets_->Reset(); // Earlier packets should not count.
|
||||
sender_state_ = receiver_state_ = Call::kNetworkUp;
|
||||
}
|
||||
sender_call_->SignalNetworkState(Call::kNetworkUp);
|
||||
receiver_call_->SignalNetworkState(Call::kNetworkUp);
|
||||
EXPECT_EQ(kEventSignaled, sender_packets_->Wait(kDefaultTimeoutMs))
|
||||
<< "Timed out waiting for send-side packets.";
|
||||
EXPECT_EQ(kEventSignaled, receiver_packets_->Wait(kDefaultTimeoutMs))
|
||||
<< "Timed out waiting for receiver-side packets.";
|
||||
}
|
||||
|
||||
virtual int32_t Encode(const I420VideoFrame& input_image,
|
||||
const CodecSpecificInfo* codec_specific_info,
|
||||
const std::vector<VideoFrameType>* frame_types)
|
||||
OVERRIDE {
|
||||
{
|
||||
CriticalSectionScoped lock(test_crit_.get());
|
||||
if (sender_state_ == Call::kNetworkDown) {
|
||||
++down_frames_;
|
||||
EXPECT_LE(down_frames_, 1)
|
||||
<< "Encoding more than one frame while network is down.";
|
||||
if (down_frames_ > 1)
|
||||
encoded_frames_->Set();
|
||||
} else {
|
||||
encoded_frames_->Set();
|
||||
}
|
||||
}
|
||||
return test::FakeEncoder::Encode(
|
||||
input_image, codec_specific_info, frame_types);
|
||||
}
|
||||
|
||||
private:
|
||||
const scoped_ptr<CriticalSectionWrapper> test_crit_;
|
||||
scoped_ptr<EventWrapper> encoded_frames_;
|
||||
scoped_ptr<EventWrapper> sender_packets_;
|
||||
scoped_ptr<EventWrapper> receiver_packets_;
|
||||
Call* sender_call_;
|
||||
Call* receiver_call_;
|
||||
Call::NetworkState sender_state_ GUARDED_BY(test_crit_);
|
||||
int down_sender_rtp_ GUARDED_BY(test_crit_);
|
||||
int down_sender_rtcp_ GUARDED_BY(test_crit_);
|
||||
Call::NetworkState receiver_state_ GUARDED_BY(test_crit_);
|
||||
int down_receiver_rtcp_ GUARDED_BY(test_crit_);
|
||||
int down_frames_ GUARDED_BY(test_crit_);
|
||||
} test;
|
||||
|
||||
RunBaseTest(&test);
|
||||
}
|
||||
|
||||
TEST_F(EndToEndTest, NewSendStreamsRespectNetworkDown) {
|
||||
class UnusedEncoder : public test::FakeEncoder {
|
||||
public:
|
||||
UnusedEncoder() : FakeEncoder(Clock::GetRealTimeClock()) {}
|
||||
virtual int32_t Encode(const I420VideoFrame& input_image,
|
||||
const CodecSpecificInfo* codec_specific_info,
|
||||
const std::vector<VideoFrameType>* frame_types)
|
||||
OVERRIDE {
|
||||
ADD_FAILURE() << "Unexpected frame encode.";
|
||||
return test::FakeEncoder::Encode(
|
||||
input_image, codec_specific_info, frame_types);
|
||||
}
|
||||
};
|
||||
|
||||
UnusedTransport transport;
|
||||
CreateSenderCall(Call::Config(&transport));
|
||||
sender_call_->SignalNetworkState(Call::kNetworkDown);
|
||||
|
||||
CreateSendConfig(1);
|
||||
UnusedEncoder unused_encoder;
|
||||
send_config_.encoder_settings.encoder = &unused_encoder;
|
||||
CreateStreams();
|
||||
CreateFrameGeneratorCapturer();
|
||||
|
||||
Start();
|
||||
SleepMs(kSilenceTimeoutMs);
|
||||
Stop();
|
||||
|
||||
DestroyStreams();
|
||||
}
|
||||
|
||||
TEST_F(EndToEndTest, NewReceiveStreamsRespectNetworkDown) {
|
||||
test::DirectTransport sender_transport;
|
||||
CreateSenderCall(Call::Config(&sender_transport));
|
||||
UnusedTransport transport;
|
||||
CreateReceiverCall(Call::Config(&transport));
|
||||
sender_transport.SetReceiver(receiver_call_->Receiver());
|
||||
|
||||
receiver_call_->SignalNetworkState(Call::kNetworkDown);
|
||||
|
||||
CreateSendConfig(1);
|
||||
CreateMatchingReceiveConfigs();
|
||||
CreateStreams();
|
||||
CreateFrameGeneratorCapturer();
|
||||
|
||||
Start();
|
||||
SleepMs(kSilenceTimeoutMs);
|
||||
Stop();
|
||||
|
||||
sender_transport.StopSending();
|
||||
|
||||
DestroyStreams();
|
||||
}
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // !WEBRTC_ANDROID
|
||||
|
@ -52,14 +52,7 @@ VideoReceiveStream::VideoReceiveStream(webrtc::VideoEngine* video_engine,
|
||||
// TODO(pbos): This is not fine grained enough...
|
||||
rtp_rtcp_->SetNACKStatus(channel_, config_.rtp.nack.rtp_history_ms > 0);
|
||||
rtp_rtcp_->SetKeyFrameRequestMethod(channel_, kViEKeyFrameRequestPliRtcp);
|
||||
switch (config_.rtp.rtcp_mode) {
|
||||
case newapi::kRtcpCompound:
|
||||
rtp_rtcp_->SetRTCPStatus(channel_, kRtcpCompound_RFC4585);
|
||||
break;
|
||||
case newapi::kRtcpReducedSize:
|
||||
rtp_rtcp_->SetRTCPStatus(channel_, kRtcpNonCompound_RFC5506);
|
||||
break;
|
||||
}
|
||||
SetRtcpMode(config_.rtp.rtcp_mode);
|
||||
|
||||
assert(config_.rtp.remote_ssrc != 0);
|
||||
// TODO(pbos): What's an appropriate local_ssrc for receive-only streams?
|
||||
@ -264,5 +257,24 @@ int32_t VideoReceiveStream::RenderFrame(const uint32_t stream_id,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void VideoReceiveStream::SignalNetworkState(Call::NetworkState state) {
|
||||
if (state == Call::kNetworkUp)
|
||||
SetRtcpMode(config_.rtp.rtcp_mode);
|
||||
network_->SetNetworkTransmissionState(channel_, state == Call::kNetworkUp);
|
||||
if (state == Call::kNetworkDown)
|
||||
rtp_rtcp_->SetRTCPStatus(channel_, kRtcpNone);
|
||||
}
|
||||
|
||||
void VideoReceiveStream::SetRtcpMode(newapi::RtcpMode mode) {
|
||||
switch (mode) {
|
||||
case newapi::kRtcpCompound:
|
||||
rtp_rtcp_->SetRTCPStatus(channel_, kRtcpCompound_RFC4585);
|
||||
break;
|
||||
case newapi::kRtcpReducedSize:
|
||||
rtp_rtcp_->SetRTCPStatus(channel_, kRtcpNonCompound_RFC5506);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} // namespace internal
|
||||
} // namespace webrtc
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/call.h"
|
||||
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
|
||||
#include "webrtc/modules/video_render/include/video_render_defines.h"
|
||||
#include "webrtc/system_wrappers/interface/clock.h"
|
||||
@ -61,11 +62,14 @@ class VideoReceiveStream : public webrtc::VideoReceiveStream,
|
||||
virtual int32_t RenderFrame(const uint32_t stream_id,
|
||||
I420VideoFrame& video_frame) OVERRIDE;
|
||||
|
||||
public:
|
||||
void SignalNetworkState(Call::NetworkState state);
|
||||
|
||||
virtual bool DeliverRtcp(const uint8_t* packet, size_t length);
|
||||
virtual bool DeliverRtp(const uint8_t* packet, size_t length);
|
||||
|
||||
private:
|
||||
void SetRtcpMode(newapi::RtcpMode mode);
|
||||
|
||||
TransportAdapter transport_adapter_;
|
||||
EncodedFrameCallbackAdapter encoded_frame_proxy_;
|
||||
const VideoReceiveStream::Config config_;
|
||||
|
@ -460,5 +460,16 @@ std::map<uint32_t, RtpState> VideoSendStream::GetRtpStates() const {
|
||||
return rtp_states;
|
||||
}
|
||||
|
||||
void VideoSendStream::SignalNetworkState(Call::NetworkState state) {
|
||||
// When network goes up, enable RTCP status before setting transmission state.
|
||||
// When it goes down, disable RTCP afterwards. This ensures that any packets
|
||||
// sent due to the network state changed will not be dropped.
|
||||
if (state == Call::kNetworkUp)
|
||||
rtp_rtcp_->SetRTCPStatus(channel_, kRtcpCompound_RFC4585);
|
||||
network_->SetNetworkTransmissionState(channel_, state == Call::kNetworkUp);
|
||||
if (state == Call::kNetworkDown)
|
||||
rtp_rtcp_->SetRTCPStatus(channel_, kRtcpNone);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace webrtc
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/call.h"
|
||||
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
|
||||
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
|
||||
#include "webrtc/video/encoded_frame_callback_adapter.h"
|
||||
@ -72,6 +73,8 @@ class VideoSendStream : public webrtc::VideoSendStream,
|
||||
typedef std::map<uint32_t, RtpState> RtpStateMap;
|
||||
RtpStateMap GetRtpStates() const;
|
||||
|
||||
void SignalNetworkState(Call::NetworkState state);
|
||||
|
||||
private:
|
||||
void ConfigureSsrcs();
|
||||
TransportAdapter transport_adapter_;
|
||||
|
Loading…
x
Reference in New Issue
Block a user