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:
pbos@webrtc.org 2014-09-03 16:17:12 +00:00
parent ebee401230
commit 26c0c41a06
10 changed files with 373 additions and 27 deletions

View File

@ -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) {

View File

@ -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) {

View File

@ -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_;

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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_;

View File

@ -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

View File

@ -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_;