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) {
|
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) {
|
bool WebRtcVideoChannel2::MuteStream(uint32 ssrc, bool mute) {
|
||||||
|
@ -157,7 +157,9 @@ void FakeVideoReceiveStream::Stop() {
|
|||||||
void FakeVideoReceiveStream::GetCurrentReceiveCodec(webrtc::VideoCodec* codec) {
|
void FakeVideoReceiveStream::GetCurrentReceiveCodec(webrtc::VideoCodec* codec) {
|
||||||
}
|
}
|
||||||
|
|
||||||
FakeCall::FakeCall() { SetVideoCodecs(GetDefaultVideoCodecs()); }
|
FakeCall::FakeCall() : network_state_(kNetworkUp) {
|
||||||
|
SetVideoCodecs(GetDefaultVideoCodecs());
|
||||||
|
}
|
||||||
|
|
||||||
FakeCall::~FakeCall() {
|
FakeCall::~FakeCall() {
|
||||||
EXPECT_EQ(0u, video_send_streams_.size());
|
EXPECT_EQ(0u, video_send_streams_.size());
|
||||||
@ -218,6 +220,10 @@ std::vector<webrtc::VideoCodec> FakeCall::GetDefaultVideoCodecs() {
|
|||||||
return codecs;
|
return codecs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
webrtc::Call::NetworkState FakeCall::GetNetworkState() const {
|
||||||
|
return network_state_;
|
||||||
|
}
|
||||||
|
|
||||||
webrtc::VideoSendStream* FakeCall::CreateVideoSendStream(
|
webrtc::VideoSendStream* FakeCall::CreateVideoSendStream(
|
||||||
const webrtc::VideoSendStream::Config& config,
|
const webrtc::VideoSendStream::Config& config,
|
||||||
const std::vector<webrtc::VideoStream>& video_streams,
|
const std::vector<webrtc::VideoStream>& video_streams,
|
||||||
@ -274,6 +280,10 @@ uint32_t FakeCall::ReceiveBitrateEstimate() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FakeCall::SignalNetworkState(webrtc::Call::NetworkState state) {
|
||||||
|
network_state_ = state;
|
||||||
|
}
|
||||||
|
|
||||||
FakeWebRtcVideoChannel2::FakeWebRtcVideoChannel2(
|
FakeWebRtcVideoChannel2::FakeWebRtcVideoChannel2(
|
||||||
FakeCall* call,
|
FakeCall* call,
|
||||||
WebRtcVideoEngine2* engine,
|
WebRtcVideoEngine2* engine,
|
||||||
@ -289,6 +299,7 @@ FakeWebRtcVideoChannel2::~FakeWebRtcVideoChannel2() {
|
|||||||
VoiceMediaChannel* FakeWebRtcVideoChannel2::GetVoiceChannel() {
|
VoiceMediaChannel* FakeWebRtcVideoChannel2::GetVoiceChannel() {
|
||||||
return voice_channel_;
|
return voice_channel_;
|
||||||
}
|
}
|
||||||
|
|
||||||
FakeCall* FakeWebRtcVideoChannel2::GetFakeCall() {
|
FakeCall* FakeWebRtcVideoChannel2::GetFakeCall() {
|
||||||
return fake_call_;
|
return fake_call_;
|
||||||
}
|
}
|
||||||
@ -1614,8 +1625,17 @@ TEST_F(WebRtcVideoChannel2Test, DISABLED_UpdateEncoderCodecsAfterSetFactory) {
|
|||||||
FAIL() << "Not implemented."; // TODO(pbos): Implement.
|
FAIL() << "Not implemented."; // TODO(pbos): Implement.
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WebRtcVideoChannel2Test, DISABLED_OnReadyToSend) {
|
TEST_F(WebRtcVideoChannel2Test, OnReadyToSendSignalsNetworkState) {
|
||||||
FAIL() << "Not implemented."; // TODO(pbos): Implement.
|
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) {
|
TEST_F(WebRtcVideoChannel2Test, DISABLED_CaptureFrameTimestampToNtpTimestamp) {
|
||||||
|
@ -103,6 +103,8 @@ class FakeCall : public webrtc::Call {
|
|||||||
|
|
||||||
std::vector<webrtc::VideoCodec> GetDefaultVideoCodecs();
|
std::vector<webrtc::VideoCodec> GetDefaultVideoCodecs();
|
||||||
|
|
||||||
|
webrtc::Call::NetworkState GetNetworkState() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual webrtc::VideoSendStream* CreateVideoSendStream(
|
virtual webrtc::VideoSendStream* CreateVideoSendStream(
|
||||||
const webrtc::VideoSendStream::Config& config,
|
const webrtc::VideoSendStream::Config& config,
|
||||||
@ -122,6 +124,9 @@ class FakeCall : public webrtc::Call {
|
|||||||
virtual uint32_t SendBitrateEstimate() OVERRIDE;
|
virtual uint32_t SendBitrateEstimate() OVERRIDE;
|
||||||
virtual uint32_t ReceiveBitrateEstimate() 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<webrtc::VideoCodec> codecs_;
|
||||||
std::vector<FakeVideoSendStream*> video_send_streams_;
|
std::vector<FakeVideoSendStream*> video_send_streams_;
|
||||||
std::vector<FakeVideoReceiveStream*> video_receive_streams_;
|
std::vector<FakeVideoReceiveStream*> video_receive_streams_;
|
||||||
|
@ -56,6 +56,10 @@ class OveruseCallback {
|
|||||||
// etc.
|
// etc.
|
||||||
class Call {
|
class Call {
|
||||||
public:
|
public:
|
||||||
|
enum NetworkState {
|
||||||
|
kNetworkUp,
|
||||||
|
kNetworkDown,
|
||||||
|
};
|
||||||
struct Config {
|
struct Config {
|
||||||
explicit Config(newapi::Transport* send_transport)
|
explicit Config(newapi::Transport* send_transport)
|
||||||
: webrtc_config(NULL),
|
: webrtc_config(NULL),
|
||||||
@ -111,6 +115,8 @@ class Call {
|
|||||||
// differ from the actual receive bitrate.
|
// differ from the actual receive bitrate.
|
||||||
virtual uint32_t ReceiveBitrateEstimate() = 0;
|
virtual uint32_t ReceiveBitrateEstimate() = 0;
|
||||||
|
|
||||||
|
virtual void SignalNetworkState(NetworkState state) = 0;
|
||||||
|
|
||||||
virtual ~Call() {}
|
virtual ~Call() {}
|
||||||
};
|
};
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -28,6 +28,8 @@
|
|||||||
#include "webrtc/video_engine/include/vie_base.h"
|
#include "webrtc/video_engine/include/vie_base.h"
|
||||||
#include "webrtc/video_engine/include/vie_codec.h"
|
#include "webrtc/video_engine/include/vie_codec.h"
|
||||||
#include "webrtc/video_engine/include/vie_rtp_rtcp.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 {
|
namespace webrtc {
|
||||||
const char* RtpExtension::kTOffset = "urn:ietf:params:rtp-hdrext:toffset";
|
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,
|
virtual DeliveryStatus DeliverPacket(const uint8_t* packet,
|
||||||
size_t length) OVERRIDE;
|
size_t length) OVERRIDE;
|
||||||
|
|
||||||
|
virtual void SignalNetworkState(NetworkState state) OVERRIDE;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DeliveryStatus DeliverRtcp(const uint8_t* packet, size_t length);
|
DeliveryStatus DeliverRtcp(const uint8_t* packet, size_t length);
|
||||||
DeliveryStatus DeliverRtp(const uint8_t* packet, size_t length);
|
DeliveryStatus DeliverRtp(const uint8_t* packet, size_t length);
|
||||||
|
|
||||||
Call::Config config_;
|
Call::Config config_;
|
||||||
|
|
||||||
std::map<uint32_t, VideoReceiveStream*> receive_ssrcs_
|
// Needs to be held while write-locking |receive_crit_| or |send_crit_|. This
|
||||||
GUARDED_BY(receive_lock_);
|
// ensures that we have a consistent network state signalled to all senders
|
||||||
scoped_ptr<RWLockWrapper> receive_lock_;
|
// 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> receive_crit_;
|
||||||
scoped_ptr<RWLockWrapper> send_lock_;
|
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_;
|
scoped_ptr<CpuOveruseObserverProxy> overuse_observer_proxy_;
|
||||||
|
|
||||||
@ -135,8 +145,10 @@ const int kDefaultVideoStreamBitrateBps = 300000;
|
|||||||
|
|
||||||
Call::Call(webrtc::VideoEngine* video_engine, const Call::Config& config)
|
Call::Call(webrtc::VideoEngine* video_engine, const Call::Config& config)
|
||||||
: config_(config),
|
: config_(config),
|
||||||
receive_lock_(RWLockWrapper::CreateRWLock()),
|
network_enabled_crit_(CriticalSectionWrapper::CreateCriticalSection()),
|
||||||
send_lock_(RWLockWrapper::CreateRWLock()),
|
network_enabled_(true),
|
||||||
|
receive_crit_(RWLockWrapper::CreateRWLock()),
|
||||||
|
send_crit_(RWLockWrapper::CreateRWLock()),
|
||||||
video_engine_(video_engine),
|
video_engine_(video_engine),
|
||||||
base_channel_id_(-1) {
|
base_channel_id_(-1) {
|
||||||
assert(video_engine != NULL);
|
assert(video_engine != NULL);
|
||||||
@ -192,11 +204,16 @@ VideoSendStream* Call::CreateVideoSendStream(
|
|||||||
config_.start_bitrate_bps != -1 ? config_.start_bitrate_bps
|
config_.start_bitrate_bps != -1 ? config_.start_bitrate_bps
|
||||||
: kDefaultVideoStreamBitrateBps);
|
: 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) {
|
for (size_t i = 0; i < config.rtp.ssrcs.size(); ++i) {
|
||||||
assert(send_ssrcs_.find(config.rtp.ssrcs[i]) == send_ssrcs_.end());
|
assert(send_ssrcs_.find(config.rtp.ssrcs[i]) == send_ssrcs_.end());
|
||||||
send_ssrcs_[config.rtp.ssrcs[i]] = send_stream;
|
send_ssrcs_[config.rtp.ssrcs[i]] = send_stream;
|
||||||
}
|
}
|
||||||
|
if (!network_enabled_)
|
||||||
|
send_stream->SignalNetworkState(kNetworkDown);
|
||||||
return send_stream;
|
return send_stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,7 +224,7 @@ void Call::DestroyVideoSendStream(webrtc::VideoSendStream* send_stream) {
|
|||||||
|
|
||||||
VideoSendStream* send_stream_impl = NULL;
|
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();
|
std::map<uint32_t, VideoSendStream*>::iterator it = send_ssrcs_.begin();
|
||||||
while (it != send_ssrcs_.end()) {
|
while (it != send_ssrcs_.end()) {
|
||||||
if (it->second == static_cast<VideoSendStream*>(send_stream)) {
|
if (it->second == static_cast<VideoSendStream*>(send_stream)) {
|
||||||
@ -240,7 +257,10 @@ VideoReceiveStream* Call::CreateVideoReceiveStream(
|
|||||||
config_.voice_engine,
|
config_.voice_engine,
|
||||||
base_channel_id_);
|
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());
|
assert(receive_ssrcs_.find(config.rtp.remote_ssrc) == receive_ssrcs_.end());
|
||||||
receive_ssrcs_[config.rtp.remote_ssrc] = receive_stream;
|
receive_ssrcs_[config.rtp.remote_ssrc] = receive_stream;
|
||||||
// TODO(pbos): Configure different RTX payloads per receive payload.
|
// TODO(pbos): Configure different RTX payloads per receive payload.
|
||||||
@ -249,6 +269,8 @@ VideoReceiveStream* Call::CreateVideoReceiveStream(
|
|||||||
if (it != config.rtp.rtx.end())
|
if (it != config.rtp.rtx.end())
|
||||||
receive_ssrcs_[it->second.ssrc] = receive_stream;
|
receive_ssrcs_[it->second.ssrc] = receive_stream;
|
||||||
|
|
||||||
|
if (!network_enabled_)
|
||||||
|
receive_stream->SignalNetworkState(kNetworkDown);
|
||||||
return receive_stream;
|
return receive_stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,7 +280,7 @@ void Call::DestroyVideoReceiveStream(
|
|||||||
|
|
||||||
VideoReceiveStream* receive_stream_impl = NULL;
|
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
|
// Remove all ssrcs pointing to a receive stream. As RTX retransmits on a
|
||||||
// separate SSRC there can be either one or two.
|
// separate SSRC there can be either one or two.
|
||||||
std::map<uint32_t, VideoReceiveStream*>::iterator it =
|
std::map<uint32_t, VideoReceiveStream*>::iterator it =
|
||||||
@ -289,6 +311,31 @@ uint32_t Call::ReceiveBitrateEstimate() {
|
|||||||
return 0;
|
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,
|
PacketReceiver::DeliveryStatus Call::DeliverRtcp(const uint8_t* packet,
|
||||||
size_t length) {
|
size_t length) {
|
||||||
// TODO(pbos): Figure out what channel needs it actually.
|
// 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.
|
// there's no receiver of the packet.
|
||||||
bool rtcp_delivered = false;
|
bool rtcp_delivered = false;
|
||||||
{
|
{
|
||||||
ReadLockScoped read_lock(*receive_lock_);
|
ReadLockScoped read_lock(*receive_crit_);
|
||||||
for (std::map<uint32_t, VideoReceiveStream*>::iterator it =
|
for (std::map<uint32_t, VideoReceiveStream*>::iterator it =
|
||||||
receive_ssrcs_.begin();
|
receive_ssrcs_.begin();
|
||||||
it != receive_ssrcs_.end();
|
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 =
|
for (std::map<uint32_t, VideoSendStream*>::iterator it =
|
||||||
send_ssrcs_.begin();
|
send_ssrcs_.begin();
|
||||||
it != send_ssrcs_.end();
|
it != send_ssrcs_.end();
|
||||||
@ -329,7 +376,7 @@ PacketReceiver::DeliveryStatus Call::DeliverRtp(const uint8_t* packet,
|
|||||||
const uint8_t* ptr = &packet[8];
|
const uint8_t* ptr = &packet[8];
|
||||||
uint32_t ssrc = ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
|
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 =
|
std::map<uint32_t, VideoReceiveStream*>::iterator it =
|
||||||
receive_ssrcs_.find(ssrc);
|
receive_ssrcs_.find(ssrc);
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
|
static const unsigned long kSilenceTimeoutMs = 2000;
|
||||||
static const int kRedPayloadType = 118;
|
static const int kRedPayloadType = 118;
|
||||||
static const int kUlpfecPayloadType = 119;
|
static const int kUlpfecPayloadType = 119;
|
||||||
|
|
||||||
@ -56,6 +57,19 @@ class EndToEndTest : public test::CallTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
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 DecodesRetransmittedFrame(bool retransmit_over_rtx);
|
||||||
void ReceivesPliAndRecovers(int rtp_history_ms);
|
void ReceivesPliAndRecovers(int rtp_history_ms);
|
||||||
void RespectsRtcpMode(newapi::RtcpMode rtcp_mode);
|
void RespectsRtcpMode(newapi::RtcpMode rtcp_mode);
|
||||||
@ -1840,6 +1854,228 @@ TEST_F(EndToEndTest, RestartingSendStreamPreservesRtpStatesWithRtx) {
|
|||||||
TestRtpStatePreservation(true);
|
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
|
} // namespace webrtc
|
||||||
|
|
||||||
#endif // !WEBRTC_ANDROID
|
#endif // !WEBRTC_ANDROID
|
||||||
|
@ -52,14 +52,7 @@ VideoReceiveStream::VideoReceiveStream(webrtc::VideoEngine* video_engine,
|
|||||||
// TODO(pbos): This is not fine grained enough...
|
// TODO(pbos): This is not fine grained enough...
|
||||||
rtp_rtcp_->SetNACKStatus(channel_, config_.rtp.nack.rtp_history_ms > 0);
|
rtp_rtcp_->SetNACKStatus(channel_, config_.rtp.nack.rtp_history_ms > 0);
|
||||||
rtp_rtcp_->SetKeyFrameRequestMethod(channel_, kViEKeyFrameRequestPliRtcp);
|
rtp_rtcp_->SetKeyFrameRequestMethod(channel_, kViEKeyFrameRequestPliRtcp);
|
||||||
switch (config_.rtp.rtcp_mode) {
|
SetRtcpMode(config_.rtp.rtcp_mode);
|
||||||
case newapi::kRtcpCompound:
|
|
||||||
rtp_rtcp_->SetRTCPStatus(channel_, kRtcpCompound_RFC4585);
|
|
||||||
break;
|
|
||||||
case newapi::kRtcpReducedSize:
|
|
||||||
rtp_rtcp_->SetRTCPStatus(channel_, kRtcpNonCompound_RFC5506);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(config_.rtp.remote_ssrc != 0);
|
assert(config_.rtp.remote_ssrc != 0);
|
||||||
// TODO(pbos): What's an appropriate local_ssrc for receive-only streams?
|
// 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;
|
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 internal
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "webrtc/call.h"
|
||||||
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
|
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
|
||||||
#include "webrtc/modules/video_render/include/video_render_defines.h"
|
#include "webrtc/modules/video_render/include/video_render_defines.h"
|
||||||
#include "webrtc/system_wrappers/interface/clock.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,
|
virtual int32_t RenderFrame(const uint32_t stream_id,
|
||||||
I420VideoFrame& video_frame) OVERRIDE;
|
I420VideoFrame& video_frame) OVERRIDE;
|
||||||
|
|
||||||
public:
|
void SignalNetworkState(Call::NetworkState state);
|
||||||
|
|
||||||
virtual bool DeliverRtcp(const uint8_t* packet, size_t length);
|
virtual bool DeliverRtcp(const uint8_t* packet, size_t length);
|
||||||
virtual bool DeliverRtp(const uint8_t* packet, size_t length);
|
virtual bool DeliverRtp(const uint8_t* packet, size_t length);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void SetRtcpMode(newapi::RtcpMode mode);
|
||||||
|
|
||||||
TransportAdapter transport_adapter_;
|
TransportAdapter transport_adapter_;
|
||||||
EncodedFrameCallbackAdapter encoded_frame_proxy_;
|
EncodedFrameCallbackAdapter encoded_frame_proxy_;
|
||||||
const VideoReceiveStream::Config config_;
|
const VideoReceiveStream::Config config_;
|
||||||
|
@ -460,5 +460,16 @@ std::map<uint32_t, RtpState> VideoSendStream::GetRtpStates() const {
|
|||||||
return rtp_states;
|
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 internal
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "webrtc/call.h"
|
||||||
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
|
#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
|
||||||
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
|
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h"
|
||||||
#include "webrtc/video/encoded_frame_callback_adapter.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;
|
typedef std::map<uint32_t, RtpState> RtpStateMap;
|
||||||
RtpStateMap GetRtpStates() const;
|
RtpStateMap GetRtpStates() const;
|
||||||
|
|
||||||
|
void SignalNetworkState(Call::NetworkState state);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ConfigureSsrcs();
|
void ConfigureSsrcs();
|
||||||
TransportAdapter transport_adapter_;
|
TransportAdapter transport_adapter_;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user