summaryrefslogtreecommitdiff
path: root/media
diff options
context:
space:
mode:
authorTorne (Richard Coles) <torne@google.com>2014-06-20 14:52:48 +0100
committerTorne (Richard Coles) <torne@google.com>2014-06-20 14:52:48 +0100
commit99bc8f39c7d7784a6d03c08add97b0f97c44db53 (patch)
tree3b4bc0bedfa949af7f8fd4ae7633f7a0870e6e86 /media
parent92d181beaac81934497a46fa15e218b0fd6569a6 (diff)
parent6de09a1dbcfa359a587b972f3e0fe30ffbd5be41 (diff)
downloadtalk-99bc8f39c7d7784a6d03c08add97b0f97c44db53.tar.gz
Merge from Chromium at DEPS revision 278205
This commit was generated by merge_to_master.py. Change-Id: I708b08f68e2ffaf5f127f628e6d299007754091d
Diffstat (limited to 'media')
-rw-r--r--media/base/mediachannel.h31
-rw-r--r--media/base/videoengine_unittest.h52
-rw-r--r--media/sctp/sctpdataengine.cc11
-rw-r--r--media/webrtc/OWNERS3
-rw-r--r--media/webrtc/fakewebrtcvoiceengine.h69
-rw-r--r--media/webrtc/webrtcmediaengine.cc33
-rw-r--r--media/webrtc/webrtcvideoengine.cc143
-rw-r--r--media/webrtc/webrtcvideoengine.h1
-rw-r--r--media/webrtc/webrtcvideoengine2.cc301
-rw-r--r--media/webrtc/webrtcvideoengine2.h50
-rw-r--r--media/webrtc/webrtcvideoengine2_unittest.cc618
-rw-r--r--media/webrtc/webrtcvideoengine2_unittest.h157
-rw-r--r--media/webrtc/webrtcvideoengine_unittest.cc128
-rw-r--r--media/webrtc/webrtcvoiceengine.cc43
-rw-r--r--media/webrtc/webrtcvoiceengine_unittest.cc144
15 files changed, 1221 insertions, 563 deletions
diff --git a/media/base/mediachannel.h b/media/base/mediachannel.h
index 0bb0f04..49902ee 100644
--- a/media/base/mediachannel.h
+++ b/media/base/mediachannel.h
@@ -314,6 +314,10 @@ struct VideoOptions {
cpu_overuse_detection.SetFrom(change.cpu_overuse_detection);
cpu_underuse_threshold.SetFrom(change.cpu_underuse_threshold);
cpu_overuse_threshold.SetFrom(change.cpu_overuse_threshold);
+ cpu_underuse_encode_rsd_threshold.SetFrom(
+ change.cpu_underuse_encode_rsd_threshold);
+ cpu_overuse_encode_rsd_threshold.SetFrom(
+ change.cpu_overuse_encode_rsd_threshold);
cpu_overuse_encode_usage.SetFrom(change.cpu_overuse_encode_usage);
conference_mode.SetFrom(change.conference_mode);
process_adaptation_threshhold.SetFrom(change.process_adaptation_threshhold);
@@ -350,6 +354,10 @@ struct VideoOptions {
cpu_overuse_detection == o.cpu_overuse_detection &&
cpu_underuse_threshold == o.cpu_underuse_threshold &&
cpu_overuse_threshold == o.cpu_overuse_threshold &&
+ cpu_underuse_encode_rsd_threshold ==
+ o.cpu_underuse_encode_rsd_threshold &&
+ cpu_overuse_encode_rsd_threshold ==
+ o.cpu_overuse_encode_rsd_threshold &&
cpu_overuse_encode_usage == o.cpu_overuse_encode_usage &&
conference_mode == o.conference_mode &&
process_adaptation_threshhold == o.process_adaptation_threshhold &&
@@ -390,6 +398,10 @@ struct VideoOptions {
ost << ToStringIfSet("cpu overuse detection", cpu_overuse_detection);
ost << ToStringIfSet("cpu underuse threshold", cpu_underuse_threshold);
ost << ToStringIfSet("cpu overuse threshold", cpu_overuse_threshold);
+ ost << ToStringIfSet("cpu underuse encode rsd threshold",
+ cpu_underuse_encode_rsd_threshold);
+ ost << ToStringIfSet("cpu overuse encode rsd threshold",
+ cpu_overuse_encode_rsd_threshold);
ost << ToStringIfSet("cpu overuse encode usage",
cpu_overuse_encode_usage);
ost << ToStringIfSet("conference mode", conference_mode);
@@ -443,10 +455,22 @@ struct VideoOptions {
// adaptation algorithm. So this option will override the
// |adapt_input_to_cpu_usage|.
Settable<bool> cpu_overuse_detection;
- // Low threshold for cpu overuse adaptation in ms. (Adapt up)
+ // Low threshold (t1) for cpu overuse adaptation. (Adapt up)
+ // Metric: encode usage (m1). m1 < t1 => underuse.
Settable<int> cpu_underuse_threshold;
- // High threshold for cpu overuse adaptation in ms. (Adapt down)
+ // High threshold (t1) for cpu overuse adaptation. (Adapt down)
+ // Metric: encode usage (m1). m1 > t1 => overuse.
Settable<int> cpu_overuse_threshold;
+ // Low threshold (t2) for cpu overuse adaptation. (Adapt up)
+ // Metric: relative standard deviation of encode time (m2).
+ // Optional threshold. If set, (m1 < t1 && m2 < t2) => underuse.
+ // Note: t2 will have no effect if t1 is not set.
+ Settable<int> cpu_underuse_encode_rsd_threshold;
+ // High threshold (t2) for cpu overuse adaptation. (Adapt down)
+ // Metric: relative standard deviation of encode time (m2).
+ // Optional threshold. If set, (m1 > t1 || m2 > t2) => overuse.
+ // Note: t2 will have no effect if t1 is not set.
+ Settable<int> cpu_overuse_encode_rsd_threshold;
// Use encode usage for cpu detection.
Settable<bool> cpu_overuse_encode_usage;
// Use conference mode?
@@ -787,6 +811,7 @@ struct MediaReceiverInfo {
int packets_rcvd;
int packets_lost;
float fraction_lost;
+ std::string codec_name;
std::vector<SsrcReceiverInfo> local_stats;
std::vector<SsrcSenderInfo> remote_stats;
};
@@ -869,6 +894,7 @@ struct VideoSenderInfo : public MediaSenderInfo {
capture_jitter_ms(0),
avg_encode_ms(0),
encode_usage_percent(0),
+ encode_rsd(0),
capture_queue_delay_ms_per_s(0) {
}
@@ -889,6 +915,7 @@ struct VideoSenderInfo : public MediaSenderInfo {
int capture_jitter_ms;
int avg_encode_ms;
int encode_usage_percent;
+ int encode_rsd;
int capture_queue_delay_ms_per_s;
VariableInfo<int> adapt_frame_drops;
VariableInfo<int> effects_frame_drops;
diff --git a/media/base/videoengine_unittest.h b/media/base/videoengine_unittest.h
index 54b5500..382fb77 100644
--- a/media/base/videoengine_unittest.h
+++ b/media/base/videoengine_unittest.h
@@ -792,14 +792,45 @@ class VideoMediaChannelTest : public testing::Test,
EXPECT_FRAME_WAIT(3, codec.width, codec.height, kTimeout);
EXPECT_EQ(2, renderer_.num_set_sizes());
}
+ void SendReceiveManyAndGetStats(const cricket::VideoCodec& codec,
+ int duration_sec, int fps) {
+ EXPECT_TRUE(SetOneCodec(codec));
+ EXPECT_TRUE(SetSend(true));
+ EXPECT_TRUE(channel_->SetRender(true));
+ EXPECT_EQ(0, renderer_.num_rendered_frames());
+ for (int i = 0; i < duration_sec; ++i) {
+ for (int frame = 1; frame <= fps; ++frame) {
+ EXPECT_TRUE(WaitAndSendFrame(1000 / fps));
+ EXPECT_FRAME_WAIT(frame + i * fps, codec.width, codec.height, kTimeout);
+ }
+ cricket::VideoMediaInfo info;
+ EXPECT_TRUE(channel_->GetStats(cricket::StatsOptions(), &info));
+ // For webrtc, |framerate_sent| and |framerate_rcvd| depend on periodic
+ // callbacks (1 sec).
+ // Received |fraction_lost| and |packets_lost| are from sent RTCP packet.
+ // One sent packet needed (sent about once per second).
+ // |framerate_input|, |framerate_decoded| and |framerate_output| are using
+ // RateTracker. RateTracker needs to be called twice (with >1 second in
+ // b/w calls) before a framerate is calculated.
+ // Therefore insert frames (and call GetStats each sec) for a few seconds
+ // before testing stats.
+ }
+ talk_base::scoped_ptr<const talk_base::Buffer> p(GetRtpPacket(0));
+ EXPECT_EQ(codec.id, GetPayloadType(p.get()));
+ }
+
// Test that stats work properly for a 1-1 call.
void GetStats() {
- SendAndReceive(DefaultCodec());
+ const int kDurationSec = 3;
+ const int kFps = 10;
+ SendReceiveManyAndGetStats(DefaultCodec(), kDurationSec, kFps);
+
cricket::VideoMediaInfo info;
EXPECT_TRUE(channel_->GetStats(cricket::StatsOptions(), &info));
ASSERT_EQ(1U, info.senders.size());
// TODO(whyuan): bytes_sent and bytes_rcvd are different. Are both payload?
+ // For webrtc, bytes_sent does not include the RTP header length.
EXPECT_GT(info.senders[0].bytes_sent, 0);
EXPECT_EQ(NumRtpPackets(), info.senders[0].packets_sent);
EXPECT_EQ(0.0, info.senders[0].fraction_lost);
@@ -819,7 +850,8 @@ class VideoMediaChannelTest : public testing::Test,
EXPECT_EQ(NumRtpPackets(), info.receivers[0].packets_rcvd);
EXPECT_EQ(0.0, info.receivers[0].fraction_lost);
EXPECT_EQ(0, info.receivers[0].packets_lost);
- EXPECT_EQ(0, info.receivers[0].packets_concealed);
+ // TODO(asapersson): Not set for webrtc. Handle missing stats.
+ // EXPECT_EQ(0, info.receivers[0].packets_concealed);
EXPECT_EQ(0, info.receivers[0].firs_sent);
EXPECT_EQ(0, info.receivers[0].plis_sent);
EXPECT_EQ(0, info.receivers[0].nacks_sent);
@@ -860,16 +892,11 @@ class VideoMediaChannelTest : public testing::Test,
ASSERT_EQ(1U, info.senders.size());
// TODO(whyuan): bytes_sent and bytes_rcvd are different. Are both payload?
+ // For webrtc, bytes_sent does not include the RTP header length.
EXPECT_GT(info.senders[0].bytes_sent, 0);
EXPECT_EQ(NumRtpPackets(), info.senders[0].packets_sent);
- EXPECT_EQ(0.0, info.senders[0].fraction_lost);
- EXPECT_EQ(0, info.senders[0].firs_rcvd);
- EXPECT_EQ(0, info.senders[0].plis_rcvd);
- EXPECT_EQ(0, info.senders[0].nacks_rcvd);
EXPECT_EQ(DefaultCodec().width, info.senders[0].send_frame_width);
EXPECT_EQ(DefaultCodec().height, info.senders[0].send_frame_height);
- EXPECT_GT(info.senders[0].framerate_input, 0);
- EXPECT_GT(info.senders[0].framerate_sent, 0);
ASSERT_EQ(2U, info.receivers.size());
for (size_t i = 0; i < info.receivers.size(); ++i) {
@@ -877,17 +904,8 @@ class VideoMediaChannelTest : public testing::Test,
EXPECT_EQ(i + 1, info.receivers[i].ssrcs()[0]);
EXPECT_EQ(NumRtpBytes(), info.receivers[i].bytes_rcvd);
EXPECT_EQ(NumRtpPackets(), info.receivers[i].packets_rcvd);
- EXPECT_EQ(0.0, info.receivers[i].fraction_lost);
- EXPECT_EQ(0, info.receivers[i].packets_lost);
- EXPECT_EQ(0, info.receivers[i].packets_concealed);
- EXPECT_EQ(0, info.receivers[i].firs_sent);
- EXPECT_EQ(0, info.receivers[i].plis_sent);
- EXPECT_EQ(0, info.receivers[i].nacks_sent);
EXPECT_EQ(DefaultCodec().width, info.receivers[i].frame_width);
EXPECT_EQ(DefaultCodec().height, info.receivers[i].frame_height);
- EXPECT_GT(info.receivers[i].framerate_rcvd, 0);
- EXPECT_GT(info.receivers[i].framerate_decoded, 0);
- EXPECT_GT(info.receivers[i].framerate_output, 0);
}
}
// Test that stats work properly for a conf call with multiple send streams.
diff --git a/media/sctp/sctpdataengine.cc b/media/sctp/sctpdataengine.cc
index 017454f..46b2ece 100644
--- a/media/sctp/sctpdataengine.cc
+++ b/media/sctp/sctpdataengine.cc
@@ -781,7 +781,6 @@ void SctpDataMediaChannel::OnStreamResetEvent(
<< ListStreams(open_streams_) << "], Q'd: ["
<< ListStreams(queued_reset_streams_) << "], Sent: ["
<< ListStreams(sent_reset_streams_) << "]";
- bool local_stream_reset_acknowledged = false;
// If both sides try to reset some streams at the same time (even if they're
// disjoint sets), we can get reset failures.
@@ -792,7 +791,6 @@ void SctpDataMediaChannel::OnStreamResetEvent(
sent_reset_streams_.begin(),
sent_reset_streams_.end());
sent_reset_streams_.clear();
- local_stream_reset_acknowledged = true;
} else if (evt->strreset_flags & SCTP_STREAM_RESET_INCOMING_SSN) {
// Each side gets an event for each direction of a stream. That is,
@@ -809,7 +807,6 @@ void SctpDataMediaChannel::OnStreamResetEvent(
if (it != sent_reset_streams_.end()) {
LOG(LS_VERBOSE) << "SCTP_STREAM_RESET_EVENT(" << debug_name_
<< "): local sid " << stream_id << " acknowledged.";
- local_stream_reset_acknowledged = true;
sent_reset_streams_.erase(it);
} else if ((it = open_streams_.find(stream_id))
@@ -840,11 +837,9 @@ void SctpDataMediaChannel::OnStreamResetEvent(
}
}
- if (local_stream_reset_acknowledged) {
- // This message acknowledges the last stream-reset request we sent out
- // (only one can be outstanding at a time). Send out the next one.
- SendQueuedStreamResets();
- }
+ // Always try to send the queued RESET because this call indicates that the
+ // last local RESET or remote RESET has made some progress.
+ SendQueuedStreamResets();
}
// Puts the specified |param| from the codec identified by |id| into |dest|
diff --git a/media/webrtc/OWNERS b/media/webrtc/OWNERS
new file mode 100644
index 0000000..9a3546e
--- /dev/null
+++ b/media/webrtc/OWNERS
@@ -0,0 +1,3 @@
+mflodman@webrtc.org
+pthatcher@webrtc.org
+wu@webrtc.org
diff --git a/media/webrtc/fakewebrtcvoiceengine.h b/media/webrtc/fakewebrtcvoiceengine.h
index 1df2195..ff2079b 100644
--- a/media/webrtc/fakewebrtcvoiceengine.h
+++ b/media/webrtc/fakewebrtcvoiceengine.h
@@ -36,6 +36,7 @@
#include "talk/base/gunit.h"
#include "talk/base/stringutils.h"
#include "talk/media/base/codec.h"
+#include "talk/media/base/rtputils.h"
#include "talk/media/base/voiceprocessor.h"
#include "talk/media/webrtc/fakewebrtccommon.h"
#include "talk/media/webrtc/webrtcvoe.h"
@@ -96,7 +97,8 @@ class FakeWebRtcVoiceEngine
volume_pan_right(1.0),
file(false),
vad(false),
- fec(false),
+ codec_fec(false),
+ red(false),
nack(false),
media_processor_registered(false),
rx_agc_enabled(false),
@@ -104,7 +106,7 @@ class FakeWebRtcVoiceEngine
cn8_type(13),
cn16_type(105),
dtmf_type(106),
- fec_type(117),
+ red_type(117),
nack_max_packets(0),
vie_network(NULL),
video_channel(-1),
@@ -124,7 +126,8 @@ class FakeWebRtcVoiceEngine
float volume_pan_right;
bool file;
bool vad;
- bool fec;
+ bool codec_fec;
+ bool red;
bool nack;
bool media_processor_registered;
bool rx_agc_enabled;
@@ -133,7 +136,7 @@ class FakeWebRtcVoiceEngine
int cn8_type;
int cn16_type;
int dtmf_type;
- int fec_type;
+ int red_type;
int nack_max_packets;
webrtc::ViENetwork* vie_network;
int video_channel;
@@ -214,8 +217,11 @@ class FakeWebRtcVoiceEngine
bool GetVAD(int channel) {
return channels_[channel]->vad;
}
- bool GetFEC(int channel) {
- return channels_[channel]->fec;
+ bool GetRED(int channel) {
+ return channels_[channel]->red;
+ }
+ bool GetCodecFEC(int channel) {
+ return channels_[channel]->codec_fec;
}
bool GetNACK(int channel) {
return channels_[channel]->nack;
@@ -243,8 +249,8 @@ class FakeWebRtcVoiceEngine
int GetSendTelephoneEventPayloadType(int channel) {
return channels_[channel]->dtmf_type;
}
- int GetSendFECPayloadType(int channel) {
- return channels_[channel]->fec_type;
+ int GetSendREDPayloadType(int channel) {
+ return channels_[channel]->red_type;
}
bool CheckPacket(int channel, const void* data, size_t len) {
bool result = !CheckNoPacket(channel);
@@ -437,7 +443,26 @@ class FakeWebRtcVoiceEngine
WEBRTC_STUB(RemoveSecondarySendCodec, (int channel));
WEBRTC_STUB(GetSecondarySendCodec, (int channel,
webrtc::CodecInst& codec));
- WEBRTC_STUB(GetRecCodec, (int channel, webrtc::CodecInst& codec));
+ WEBRTC_FUNC(GetRecCodec, (int channel, webrtc::CodecInst& codec)) {
+ WEBRTC_CHECK_CHANNEL(channel);
+ const Channel* c = channels_[channel];
+ for (std::list<std::string>::const_iterator it_packet = c->packets.begin();
+ it_packet != c->packets.end(); ++it_packet) {
+ int pltype;
+ if (!GetRtpPayloadType(it_packet->data(), it_packet->length(), &pltype)) {
+ continue;
+ }
+ for (std::vector<webrtc::CodecInst>::const_iterator it_codec =
+ c->recv_codecs.begin(); it_codec != c->recv_codecs.end();
+ ++it_codec) {
+ if (it_codec->pltype == pltype) {
+ codec = *it_codec;
+ return 0;
+ }
+ }
+ }
+ return -1;
+ }
WEBRTC_STUB(SetAMREncFormat, (int channel, webrtc::AmrMode mode));
WEBRTC_STUB(SetAMRDecFormat, (int channel, webrtc::AmrMode mode));
WEBRTC_STUB(SetAMRWbEncFormat, (int channel, webrtc::AmrMode mode));
@@ -511,6 +536,16 @@ class FakeWebRtcVoiceEngine
}
WEBRTC_STUB(GetVADStatus, (int channel, bool& enabled,
webrtc::VadModes& mode, bool& disabledDTX));
+ WEBRTC_FUNC(SetFECStatus, (int channel, bool enable)) {
+ WEBRTC_CHECK_CHANNEL(channel);
+ channels_[channel]->codec_fec = enable;
+ return 0;
+ }
+ WEBRTC_FUNC(GetFECStatus, (int channel, bool& enable)) {
+ WEBRTC_CHECK_CHANNEL(channel);
+ enable = channels_[channel]->codec_fec;
+ return 0;
+ }
// webrtc::VoEDtmf
WEBRTC_FUNC(SendTelephoneEvent, (int channel, int event_code,
@@ -823,16 +858,24 @@ class FakeWebRtcVoiceEngine
stats.packetsReceived = kIntStatValue;
return 0;
}
+#ifdef USE_WEBRTC_DEV_BRANCH
+ WEBRTC_FUNC(SetREDStatus, (int channel, bool enable, int redPayloadtype)) {
+#else
WEBRTC_FUNC(SetFECStatus, (int channel, bool enable, int redPayloadtype)) {
+#endif // USE_WEBRTC_DEV_BRANCH
WEBRTC_CHECK_CHANNEL(channel);
- channels_[channel]->fec = enable;
- channels_[channel]->fec_type = redPayloadtype;
+ channels_[channel]->red = enable;
+ channels_[channel]->red_type = redPayloadtype;
return 0;
}
+#ifdef USE_WEBRTC_DEV_BRANCH
+ WEBRTC_FUNC(GetREDStatus, (int channel, bool& enable, int& redPayloadtype)) {
+#else
WEBRTC_FUNC(GetFECStatus, (int channel, bool& enable, int& redPayloadtype)) {
+#endif // USE_WEBRTC_DEV_BRANCH
WEBRTC_CHECK_CHANNEL(channel);
- enable = channels_[channel]->fec;
- redPayloadtype = channels_[channel]->fec_type;
+ enable = channels_[channel]->red;
+ redPayloadtype = channels_[channel]->red_type;
return 0;
}
WEBRTC_FUNC(SetNACKStatus, (int channel, bool enable, int maxNoPackets)) {
diff --git a/media/webrtc/webrtcmediaengine.cc b/media/webrtc/webrtcmediaengine.cc
index 03f7b9b..445564c 100644
--- a/media/webrtc/webrtcmediaengine.cc
+++ b/media/webrtc/webrtcmediaengine.cc
@@ -25,5 +25,34 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-// TODO(pbos): Move CreateWebRtcMediaEngine here as soon as
-// libjingle/libjingle.gyp in Chromium builds this file.
+#include "talk/media/webrtc/webrtcmediaengine.h"
+#include "webrtc/system_wrappers/interface/field_trial.h"
+
+WRME_EXPORT
+cricket::MediaEngineInterface* CreateWebRtcMediaEngine(
+ webrtc::AudioDeviceModule* adm,
+ webrtc::AudioDeviceModule* adm_sc,
+ cricket::WebRtcVideoEncoderFactory* encoder_factory,
+ cricket::WebRtcVideoDecoderFactory* decoder_factory) {
+#ifdef WEBRTC_CHROMIUM_BUILD
+ if (webrtc::field_trial::FindFullName("WebRTC-NewVideoAPI") == "Enabled") {
+ return new cricket::WebRtcMediaEngine2(
+ adm, adm_sc, encoder_factory, decoder_factory);
+ }
+#endif // WEBRTC_CHROMIUM_BUILD
+ return new cricket::WebRtcMediaEngine(
+ adm, adm_sc, encoder_factory, decoder_factory);
+}
+
+WRME_EXPORT
+void DestroyWebRtcMediaEngine(cricket::MediaEngineInterface* media_engine) {
+#ifdef WEBRTC_CHROMIUM_BUILD
+ if (webrtc::field_trial::FindFullName("WebRTC-NewVideoAPI") == "Enabled") {
+ delete static_cast<cricket::WebRtcMediaEngine2*>(media_engine);
+ } else {
+#endif // WEBRTC_CHROMIUM_BUILD
+ delete static_cast<cricket::WebRtcMediaEngine*>(media_engine);
+#ifdef WEBRTC_CHROMIUM_BUILD
+ }
+#endif // WEBRTC_CHROMIUM_BUILD
+}
diff --git a/media/webrtc/webrtcvideoengine.cc b/media/webrtc/webrtcvideoengine.cc
index a029ec2..f1810bf 100644
--- a/media/webrtc/webrtcvideoengine.cc
+++ b/media/webrtc/webrtcvideoengine.cc
@@ -62,44 +62,6 @@
#include "talk/media/webrtc/webrtcvoiceengine.h"
#include "webrtc/experiments.h"
#include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
-#ifdef WEBRTC_CHROMIUM_BUILD
-#include "webrtc/system_wrappers/interface/field_trial.h"
-#endif
-
-#if !defined(LIBPEERCONNECTION_LIB)
-#include "talk/media/webrtc/webrtcmediaengine.h"
-
-WRME_EXPORT
-cricket::MediaEngineInterface* CreateWebRtcMediaEngine(
- webrtc::AudioDeviceModule* adm, webrtc::AudioDeviceModule* adm_sc,
- cricket::WebRtcVideoEncoderFactory* encoder_factory,
- cricket::WebRtcVideoDecoderFactory* decoder_factory) {
-#ifdef WEBRTC_CHROMIUM_BUILD
- if (webrtc::field_trial::FindFullName("WebRTC-NewVideoAPI") == "Enabled") {
- return new cricket::WebRtcMediaEngine2(
- adm, adm_sc, encoder_factory, decoder_factory);
- } else {
-#endif
- return new cricket::WebRtcMediaEngine(
- adm, adm_sc, encoder_factory, decoder_factory);
-#ifdef WEBRTC_CHROMIUM_BUILD
- }
-#endif
-}
-
-WRME_EXPORT
-void DestroyWebRtcMediaEngine(cricket::MediaEngineInterface* media_engine) {
-#ifdef WEBRTC_CHROMIUM_BUILD
- if (webrtc::field_trial::FindFullName("WebRTC-NewVideoAPI") == "Enabled") {
- delete static_cast<cricket::WebRtcMediaEngine2*>(media_engine);
- } else {
-#endif
- delete static_cast<cricket::WebRtcMediaEngine*>(media_engine);
-#ifdef WEBRTC_CHROMIUM_BUILD
- }
-#endif
-}
-#endif
namespace cricket {
@@ -260,11 +222,11 @@ class WebRtcRenderAdapter : public webrtc::ExternalRenderer {
const int kVideoCodecClockratekHz = cricket::kVideoCodecClockrate / 1000;
+ int64 elapsed_time_ms =
+ (rtp_ts_wraparound_handler_.Unwrap(rtp_time_stamp) -
+ capture_start_rtp_time_stamp_) / kVideoCodecClockratekHz;
#ifdef USE_WEBRTC_DEV_BRANCH
if (ntp_time_ms > 0) {
- int64 elapsed_time_ms =
- (rtp_ts_wraparound_handler_.Unwrap(rtp_time_stamp) -
- capture_start_rtp_time_stamp_) / kVideoCodecClockratekHz;
capture_start_ntp_time_ms_ = ntp_time_ms - elapsed_time_ms;
}
#endif
@@ -272,30 +234,31 @@ class WebRtcRenderAdapter : public webrtc::ExternalRenderer {
if (renderer_ == NULL) {
return 0;
}
- // Convert 90K rtp timestamp to ns timestamp.
- int64 rtp_time_stamp_in_ns = (rtp_time_stamp / kVideoCodecClockratekHz) *
- talk_base::kNumNanosecsPerMillisec;
+ // Convert elapsed_time_ms to ns timestamp.
+ int64 elapsed_time_ns =
+ elapsed_time_ms * talk_base::kNumNanosecsPerMillisec;
// Convert milisecond render time to ns timestamp.
- int64 render_time_stamp_in_ns = render_time *
+ int64 render_time_ns = render_time *
talk_base::kNumNanosecsPerMillisec;
- // Send the rtp timestamp to renderer as the VideoFrame timestamp.
- // and the render timestamp as the VideoFrame elapsed_time.
+ // Note that here we send the |elapsed_time_ns| to renderer as the
+ // cricket::VideoFrame's elapsed_time_ and the |render_time_ns| as the
+ // cricket::VideoFrame's time_stamp_.
if (handle == NULL) {
- return DeliverBufferFrame(buffer, buffer_size, render_time_stamp_in_ns,
- rtp_time_stamp_in_ns);
+ return DeliverBufferFrame(buffer, buffer_size, render_time_ns,
+ elapsed_time_ns);
} else {
- return DeliverTextureFrame(handle, render_time_stamp_in_ns,
- rtp_time_stamp_in_ns);
+ return DeliverTextureFrame(handle, render_time_ns,
+ elapsed_time_ns);
}
}
virtual bool IsTextureSupported() { return true; }
int DeliverBufferFrame(unsigned char* buffer, int buffer_size,
- int64 elapsed_time, int64 rtp_time_stamp_in_ns) {
+ int64 time_stamp, int64 elapsed_time) {
WebRtcVideoFrame video_frame;
video_frame.Alias(buffer, buffer_size, width_, height_,
- 1, 1, elapsed_time, rtp_time_stamp_in_ns, 0);
+ 1, 1, elapsed_time, time_stamp, 0);
// Sanity check on decoded frame size.
if (buffer_size != static_cast<int>(VideoFrame::SizeOf(width_, height_))) {
@@ -308,12 +271,10 @@ class WebRtcRenderAdapter : public webrtc::ExternalRenderer {
return ret;
}
- int DeliverTextureFrame(void* handle,
- int64 elapsed_time,
- int64 rtp_time_stamp_in_ns) {
+ int DeliverTextureFrame(void* handle, int64 time_stamp, int64 elapsed_time) {
WebRtcTextureVideoFrame video_frame(
static_cast<webrtc::NativeHandle*>(handle), width_, height_,
- elapsed_time, rtp_time_stamp_in_ns);
+ elapsed_time, time_stamp);
return renderer_->RenderFrame(&video_frame);
}
@@ -925,6 +886,18 @@ static bool GetCpuOveruseOptions(const VideoOptions& options,
// Use method based on encode usage.
overuse_options->low_encode_usage_threshold_percent = underuse_threshold;
overuse_options->high_encode_usage_threshold_percent = overuse_threshold;
+#ifdef USE_WEBRTC_DEV_BRANCH
+ // Set optional thresholds, if configured.
+ int underuse_rsd_threshold = 0;
+ if (options.cpu_underuse_encode_rsd_threshold.Get(
+ &underuse_rsd_threshold)) {
+ overuse_options->low_encode_time_rsd_threshold = underuse_rsd_threshold;
+ }
+ int overuse_rsd_threshold = 0;
+ if (options.cpu_overuse_encode_rsd_threshold.Get(&overuse_rsd_threshold)) {
+ overuse_options->high_encode_time_rsd_threshold = overuse_rsd_threshold;
+ }
+#endif
} else {
// Use default method based on capture jitter.
overuse_options->low_capture_jitter_threshold_ms =
@@ -2050,6 +2023,9 @@ bool WebRtcVideoMediaChannel::AddRecvStream(const StreamParams& sp) {
<< " reuse default channel #"
<< vie_channel_;
first_receive_ssrc_ = sp.first_ssrc();
+ if (!MaybeSetRtxSsrc(sp, vie_channel_)) {
+ return false;
+ }
if (render_started_) {
if (engine()->vie()->render()->StartRender(vie_channel_) !=0) {
LOG_RTCERR1(StartRender, vie_channel_);
@@ -2088,19 +2064,8 @@ bool WebRtcVideoMediaChannel::AddRecvStream(const StreamParams& sp) {
}
channel_iterator = recv_channels_.find(sp.first_ssrc());
- // Set the corresponding RTX SSRC.
- uint32 rtx_ssrc;
- bool has_rtx = sp.GetFidSsrc(sp.first_ssrc(), &rtx_ssrc);
- if (has_rtx) {
- LOG(LS_INFO) << "Setting rtx ssrc " << rtx_ssrc << " for stream "
- << sp.first_ssrc();
- if (engine()->vie()->rtp()->SetRemoteSSRCType(
- channel_id, webrtc::kViEStreamTypeRtx, rtx_ssrc) != 0) {
- LOG_RTCERR3(SetRemoteSSRCType, channel_id, webrtc::kViEStreamTypeRtx,
- rtx_ssrc);
- return false;
- }
- rtx_to_primary_ssrc_[rtx_ssrc] = sp.first_ssrc();
+ if (!MaybeSetRtxSsrc(sp, channel_id)) {
+ return false;
}
// Get the default renderer.
@@ -2129,6 +2094,24 @@ bool WebRtcVideoMediaChannel::AddRecvStream(const StreamParams& sp) {
return true;
}
+bool WebRtcVideoMediaChannel::MaybeSetRtxSsrc(const StreamParams& sp,
+ int channel_id) {
+ uint32 rtx_ssrc;
+ bool has_rtx = sp.GetFidSsrc(sp.first_ssrc(), &rtx_ssrc);
+ if (has_rtx) {
+ LOG(LS_INFO) << "Setting rtx ssrc " << rtx_ssrc << " for stream "
+ << sp.first_ssrc();
+ if (engine()->vie()->rtp()->SetRemoteSSRCType(
+ channel_id, webrtc::kViEStreamTypeRtx, rtx_ssrc) != 0) {
+ LOG_RTCERR3(SetRemoteSSRCType, channel_id, webrtc::kViEStreamTypeRtx,
+ rtx_ssrc);
+ return false;
+ }
+ rtx_to_primary_ssrc_[rtx_ssrc] = sp.first_ssrc();
+ }
+ return true;
+}
+
bool WebRtcVideoMediaChannel::RemoveRecvStream(uint32 ssrc) {
if (ssrc == 0) {
LOG(LS_ERROR) << "RemoveRecvStream with 0 ssrc is not supported.";
@@ -2523,6 +2506,7 @@ bool WebRtcVideoMediaChannel::GetStats(const StatsOptions& options,
sinfo.capture_jitter_ms = metrics.capture_jitter_ms;
sinfo.avg_encode_ms = metrics.avg_encode_time_ms;
sinfo.encode_usage_percent = metrics.encode_usage_percent;
+ sinfo.encode_rsd = metrics.encode_rsd;
sinfo.capture_queue_delay_ms_per_s = metrics.capture_queue_delay_ms_per_s;
#else
sinfo.capture_jitter_ms = -1;
@@ -3056,10 +3040,13 @@ bool WebRtcVideoMediaChannel::SetOptions(const VideoOptions &options) {
if (leaky_bucket_changed) {
bool enable_leaky_bucket =
- options_.video_leaky_bucket.GetWithDefaultIfUnset(false);
+ options_.video_leaky_bucket.GetWithDefaultIfUnset(true);
LOG(LS_INFO) << "Leaky bucket is enabled? " << enable_leaky_bucket;
for (SendChannelMap::iterator it = send_channels_.begin();
it != send_channels_.end(); ++it) {
+ // TODO(holmer): This API will be removed as we move to the new
+ // webrtc::Call API. We should clean up this experiment when that is
+ // happening.
if (engine()->vie()->rtp()->SetTransmissionSmoothingStatus(
it->second->channel_id(), enable_leaky_bucket) != 0) {
LOG_RTCERR2(SetTransmissionSmoothingStatus, it->second->channel_id(),
@@ -3602,7 +3589,7 @@ bool WebRtcVideoMediaChannel::ConfigureSending(int channel_id,
return false;
}
- if (options_.video_leaky_bucket.GetWithDefaultIfUnset(false)) {
+ if (options_.video_leaky_bucket.GetWithDefaultIfUnset(true)) {
if (engine()->vie()->rtp()->SetTransmissionSmoothingStatus(channel_id,
true) != 0) {
LOG_RTCERR2(SetTransmissionSmoothingStatus, channel_id, true);
@@ -3927,9 +3914,13 @@ int WebRtcVideoMediaChannel::GetRecvChannelNum(uint32 ssrc) {
// Check if we have an RTX stream registered on this SSRC.
SsrcMap::iterator rtx_it = rtx_to_primary_ssrc_.find(ssrc);
if (rtx_it != rtx_to_primary_ssrc_.end()) {
- it = recv_channels_.find(rtx_it->second);
- assert(it != recv_channels_.end());
- recv_channel = it->second->channel_id();
+ if (rtx_it->second == first_receive_ssrc_) {
+ recv_channel = vie_channel_;
+ } else {
+ it = recv_channels_.find(rtx_it->second);
+ assert(it != recv_channels_.end());
+ recv_channel = it->second->channel_id();
+ }
}
} else {
recv_channel = it->second->channel_id();
@@ -3990,7 +3981,7 @@ bool WebRtcVideoMediaChannel::MaybeResetVieSendCodec(
options_.video_noise_reduction.GetWithDefaultIfUnset(false);
int screencast_min_bitrate =
options_.screencast_min_bitrate.GetWithDefaultIfUnset(0);
- bool leaky_bucket = options_.video_leaky_bucket.GetWithDefaultIfUnset(false);
+ bool leaky_bucket = options_.video_leaky_bucket.GetWithDefaultIfUnset(true);
bool denoising = !is_screencast && enable_denoising;
bool reset_send_codec =
target_width != cur_width || target_height != cur_height ||
diff --git a/media/webrtc/webrtcvideoengine.h b/media/webrtc/webrtcvideoengine.h
index 3928542..775f4e4 100644
--- a/media/webrtc/webrtcvideoengine.h
+++ b/media/webrtc/webrtcvideoengine.h
@@ -345,6 +345,7 @@ class WebRtcVideoMediaChannel : public talk_base::MessageHandler,
bool SetReceiveCodecs(WebRtcVideoChannelRecvInfo* info);
// Returns the channel number that receives the stream with SSRC |ssrc|.
int GetRecvChannelNum(uint32 ssrc);
+ bool MaybeSetRtxSsrc(const StreamParams& sp, int channel_id);
// Given captured video frame size, checks if we need to reset vie send codec.
// |reset| is set to whether resetting has happened on vie or not.
// Returns false on error.
diff --git a/media/webrtc/webrtcvideoengine2.cc b/media/webrtc/webrtcvideoengine2.cc
index 723ef1d..d6d1354 100644
--- a/media/webrtc/webrtcvideoengine2.cc
+++ b/media/webrtc/webrtcvideoengine2.cc
@@ -161,6 +161,22 @@ static bool FindBestVideoFormat(int max_width,
return false;
}
+static void AddDefaultFeedbackParams(VideoCodec* codec) {
+ const FeedbackParam kFir(kRtcpFbParamCcm, kRtcpFbCcmParamFir);
+ codec->AddFeedbackParam(kFir);
+ const FeedbackParam kNack(kRtcpFbParamNack, kParamValueEmpty);
+ codec->AddFeedbackParam(kNack);
+ const FeedbackParam kPli(kRtcpFbParamNack, kRtcpFbNackParamPli);
+ codec->AddFeedbackParam(kPli);
+ const FeedbackParam kRemb(kRtcpFbParamRemb, kParamValueEmpty);
+ codec->AddFeedbackParam(kRemb);
+}
+
+static bool IsNackEnabled(const VideoCodec& codec) {
+ return codec.HasFeedbackParam(
+ FeedbackParam(kRtcpFbParamNack, kParamValueEmpty));
+}
+
static VideoCodec DefaultVideoCodec() {
VideoCodec default_codec(kDefaultVideoCodecPref.payload_type,
kDefaultVideoCodecPref.name,
@@ -168,6 +184,7 @@ static VideoCodec DefaultVideoCodec() {
kDefaultVideoFormat.height,
kDefaultFramerate,
0);
+ AddDefaultFeedbackParams(&default_codec);
return default_codec;
}
@@ -195,54 +212,47 @@ static std::vector<VideoCodec> DefaultVideoCodecs() {
WebRtcVideoEncoderFactory2::~WebRtcVideoEncoderFactory2() {
}
-class DefaultVideoEncoderFactory : public WebRtcVideoEncoderFactory2 {
- public:
- virtual bool CreateEncoderSettings(
- webrtc::VideoSendStream::Config::EncoderSettings* encoder_settings,
- const VideoOptions& options,
- const VideoCodec& codec,
- size_t num_streams) OVERRIDE {
- if (num_streams != 1) {
- LOG(LS_ERROR) << "Unsupported number of streams: " << num_streams;
- return false;
- }
- if (!SupportsCodec(codec)) {
- LOG(LS_ERROR) << "Can't create encoder settings for unsupported codec: '"
- << codec.name << "'";
- return false;
- }
-
- *encoder_settings = webrtc::VideoSendStream::Config::EncoderSettings();
-
- webrtc::VideoStream stream;
- stream.width = codec.width;
- stream.height = codec.height;
- stream.max_framerate =
- codec.framerate != 0 ? codec.framerate : kDefaultFramerate;
+std::vector<webrtc::VideoStream> WebRtcVideoEncoderFactory2::CreateVideoStreams(
+ const VideoCodec& codec,
+ const VideoOptions& options,
+ size_t num_streams) {
+ assert(SupportsCodec(codec));
+ if (num_streams != 1) {
+ LOG(LS_ERROR) << "Unsupported number of streams: " << num_streams;
+ return std::vector<webrtc::VideoStream>();
+ }
- int min_bitrate = kMinVideoBitrate;
- codec.GetParam(kCodecParamMinBitrate, &min_bitrate);
- int max_bitrate = kMaxVideoBitrate;
- codec.GetParam(kCodecParamMaxBitrate, &max_bitrate);
- stream.min_bitrate_bps = min_bitrate * 1000;
- stream.target_bitrate_bps = stream.max_bitrate_bps = max_bitrate * 1000;
+ webrtc::VideoStream stream;
+ stream.width = codec.width;
+ stream.height = codec.height;
+ stream.max_framerate =
+ codec.framerate != 0 ? codec.framerate : kDefaultFramerate;
- int max_qp = 56;
- codec.GetParam(kCodecParamMaxQuantization, &max_qp);
- stream.max_qp = max_qp;
- encoder_settings->streams.push_back(stream);
+ int min_bitrate = kMinVideoBitrate;
+ codec.GetParam(kCodecParamMinBitrate, &min_bitrate);
+ int max_bitrate = kMaxVideoBitrate;
+ codec.GetParam(kCodecParamMaxBitrate, &max_bitrate);
+ stream.min_bitrate_bps = min_bitrate * 1000;
+ stream.target_bitrate_bps = stream.max_bitrate_bps = max_bitrate * 1000;
- encoder_settings->encoder = webrtc::VP8Encoder::Create();
- encoder_settings->payload_type = kDefaultVideoCodecPref.payload_type;
- encoder_settings->payload_name = kDefaultVideoCodecPref.name;
+ int max_qp = 56;
+ codec.GetParam(kCodecParamMaxQuantization, &max_qp);
+ stream.max_qp = max_qp;
+ std::vector<webrtc::VideoStream> streams;
+ streams.push_back(stream);
+ return streams;
+}
- return true;
- }
+webrtc::VideoEncoder* WebRtcVideoEncoderFactory2::CreateVideoEncoder(
+ const VideoCodec& codec,
+ const VideoOptions& options) {
+ assert(SupportsCodec(codec));
+ return webrtc::VP8Encoder::Create();
+}
- virtual bool SupportsCodec(const VideoCodec& codec) OVERRIDE {
- return _stricmp(codec.name.c_str(), kVp8PayloadName) == 0;
- }
-};
+bool WebRtcVideoEncoderFactory2::SupportsCodec(const VideoCodec& codec) {
+ return _stricmp(codec.name.c_str(), kVp8PayloadName) == 0;
+}
WebRtcVideoEngine2::WebRtcVideoEngine2() {
// Construct without a factory or voice engine.
@@ -268,7 +278,6 @@ void WebRtcVideoEngine2::Construct(WebRtcVideoChannelFactory* channel_factory,
video_codecs_ = DefaultVideoCodecs();
default_codec_format_ = VideoFormat(kDefaultVideoFormat);
- default_video_encoder_factory_.reset(new DefaultVideoEncoderFactory());
}
WebRtcVideoEngine2::~WebRtcVideoEngine2() {
@@ -337,6 +346,7 @@ WebRtcVideoChannel2* WebRtcVideoEngine2::CreateChannel(
delete channel;
return NULL;
}
+ channel->SetRecvCodecs(video_codecs_);
return channel;
}
@@ -467,15 +477,15 @@ bool WebRtcVideoEngine2::ShouldIgnoreTrace(const std::string& trace) {
return false;
}
-WebRtcVideoEncoderFactory2* WebRtcVideoEngine2::GetVideoEncoderFactory() const {
- return default_video_encoder_factory_.get();
+WebRtcVideoEncoderFactory2* WebRtcVideoEngine2::GetVideoEncoderFactory() {
+ return &default_video_encoder_factory_;
}
-// Thin map between cricket::VideoFrame and an existing webrtc::I420VideoFrame
+// Thin map between VideoFrame and an existing webrtc::I420VideoFrame
// to avoid having to copy the rendered VideoFrame prematurely.
// This implementation is only safe to use in a const context and should never
// be written to.
-class WebRtcVideoRenderFrame : public cricket::VideoFrame {
+class WebRtcVideoRenderFrame : public VideoFrame {
public:
explicit WebRtcVideoRenderFrame(const webrtc::I420VideoFrame* frame)
: frame_(frame) {}
@@ -733,15 +743,6 @@ bool WebRtcVideoChannel2::Init() { return true; }
namespace {
-static bool ValidateCodecFormats(const std::vector<VideoCodec>& codecs) {
- for (size_t i = 0; i < codecs.size(); ++i) {
- if (!codecs[i].ValidateCodecFormat()) {
- return false;
- }
- }
- return true;
-}
-
static std::string CodecVectorToString(const std::vector<VideoCodec>& codecs) {
std::stringstream out;
out << '{';
@@ -755,6 +756,24 @@ static std::string CodecVectorToString(const std::vector<VideoCodec>& codecs) {
return out.str();
}
+static bool ValidateCodecFormats(const std::vector<VideoCodec>& codecs) {
+ bool has_video = false;
+ for (size_t i = 0; i < codecs.size(); ++i) {
+ if (!codecs[i].ValidateCodecFormat()) {
+ return false;
+ }
+ if (codecs[i].GetCodecType() == VideoCodec::CODEC_VIDEO) {
+ has_video = true;
+ }
+ }
+ if (!has_video) {
+ LOG(LS_ERROR) << "Setting codecs without a video codec is invalid: "
+ << CodecVectorToString(codecs);
+ return false;
+ }
+ return true;
+}
+
} // namespace
bool WebRtcVideoChannel2::SetRecvCodecs(const std::vector<VideoCodec>& codecs) {
@@ -860,30 +879,37 @@ static bool ConfigureSendSsrcs(webrtc::VideoSendStream::Config* config,
return false;
}
- const SsrcGroup* sim_group = sp.get_ssrc_group(kSimSsrcGroupSemantics);
- if (sim_group == NULL) {
- LOG(LS_ERROR) << "Grouped StreamParams without regular SSRC group: "
- << sp.ToString();
- return false;
- }
-
// Map RTX SSRCs.
+ std::vector<uint32_t> ssrcs;
std::vector<uint32_t> rtx_ssrcs;
- for (size_t i = 0; i < sim_group->ssrcs.size(); ++i) {
+ const SsrcGroup* sim_group = sp.get_ssrc_group(kSimSsrcGroupSemantics);
+ if (sim_group == NULL) {
+ ssrcs.push_back(sp.first_ssrc());
uint32_t rtx_ssrc;
- if (!sp.GetFidSsrc(sim_group->ssrcs[i], &rtx_ssrc)) {
- continue;
+ if (!sp.GetFidSsrc(sp.first_ssrc(), &rtx_ssrc)) {
+ LOG(LS_ERROR) << "Could not find FID ssrc for primary SSRC '"
+ << sp.first_ssrc() << "':" << sp.ToString();
+ return false;
}
rtx_ssrcs.push_back(rtx_ssrc);
+ } else {
+ ssrcs = sim_group->ssrcs;
+ for (size_t i = 0; i < sim_group->ssrcs.size(); ++i) {
+ uint32_t rtx_ssrc;
+ if (!sp.GetFidSsrc(sim_group->ssrcs[i], &rtx_ssrc)) {
+ continue;
+ }
+ rtx_ssrcs.push_back(rtx_ssrc);
+ }
}
- if (!rtx_ssrcs.empty() && sim_group->ssrcs.size() != rtx_ssrcs.size()) {
+ if (!rtx_ssrcs.empty() && ssrcs.size() != rtx_ssrcs.size()) {
LOG(LS_ERROR)
<< "RTX SSRCs exist, but don't cover all SSRCs (unsupported): "
<< sp.ToString();
return false;
}
config->rtp.rtx.ssrcs = rtx_ssrcs;
- config->rtp.ssrcs = sim_group->ssrcs;
+ config->rtp.ssrcs = ssrcs;
return true;
}
@@ -924,25 +950,35 @@ bool WebRtcVideoChannel2::AddSendStream(const StreamParams& sp) {
// CreateEncoderSettings will allocate a suitable VideoEncoder instance
// matching current settings.
- if (!encoder_factory_->CreateEncoderSettings(&config.encoder_settings,
- options_,
- codec_settings.codec,
- config.rtp.ssrcs.size())) {
- LOG(LS_ERROR) << "Failed to create suitable encoder settings.";
+ std::vector<webrtc::VideoStream> video_streams =
+ encoder_factory_->CreateVideoStreams(
+ codec_settings.codec, options_, config.rtp.ssrcs.size());
+ if (video_streams.empty()) {
return false;
}
+ config.encoder_settings.encoder =
+ encoder_factory_->CreateVideoEncoder(codec_settings.codec, options_);
+ config.encoder_settings.payload_name = codec_settings.codec.name;
+ config.encoder_settings.payload_type = codec_settings.codec.id;
config.rtp.c_name = sp.cname;
config.rtp.fec = codec_settings.fec;
if (!config.rtp.rtx.ssrcs.empty()) {
config.rtp.rtx.payload_type = codec_settings.rtx_payload_type;
}
- config.rtp.nack.rtp_history_ms = kNackHistoryMs;
+ if (IsNackEnabled(codec_settings.codec)) {
+ config.rtp.nack.rtp_history_ms = kNackHistoryMs;
+ }
config.rtp.max_packet_size = kVideoMtu;
WebRtcVideoSendStream* stream =
- new WebRtcVideoSendStream(call_.get(), config, encoder_factory_);
+ new WebRtcVideoSendStream(call_.get(),
+ config,
+ options_,
+ codec_settings.codec,
+ video_streams,
+ encoder_factory_);
send_streams_[ssrc] = stream;
if (rtcp_receiver_report_ssrc_ == kDefaultRtcpReceiverReportSsrc) {
@@ -1006,15 +1042,10 @@ bool WebRtcVideoChannel2::AddRecvStream(const StreamParams& sp) {
webrtc::VideoReceiveStream::Config config = call_->GetDefaultReceiveConfig();
config.rtp.remote_ssrc = ssrc;
config.rtp.local_ssrc = rtcp_receiver_report_ssrc_;
- uint32 rtx_ssrc = 0;
- if (sp.GetFidSsrc(ssrc, &rtx_ssrc)) {
- // TODO(pbos): Right now, VideoReceiveStream accepts any rtx payload, this
- // should use the actual codec payloads that may be received.
- // (for each receive payload, set rtx[payload].ssrc = rtx_ssrc.
- config.rtp.rtx[0].ssrc = rtx_ssrc;
- }
- config.rtp.nack.rtp_history_ms = kNackHistoryMs;
+ if (IsNackEnabled(recv_codecs_.begin()->codec)) {
+ config.rtp.nack.rtp_history_ms = kNackHistoryMs;
+ }
config.rtp.remb = true;
// TODO(pbos): This protection is against setting the same local ssrc as
// remote which is not permitted by the lower-level API. RTCP requires a
@@ -1068,7 +1099,9 @@ bool WebRtcVideoChannel2::AddRecvStream(const StreamParams& sp) {
for (size_t i = 0; i < recv_codecs_.size(); ++i) {
if (recv_codecs_[i].codec.id == codec.plType) {
config.rtp.fec = recv_codecs_[i].fec;
- if (recv_codecs_[i].rtx_payload_type != -1 && rtx_ssrc != 0) {
+ uint32 rtx_ssrc;
+ if (recv_codecs_[i].rtx_payload_type != -1 &&
+ sp.GetFidSsrc(ssrc, &rtx_ssrc)) {
config.rtp.rtx[codec.plType].ssrc = rtx_ssrc;
config.rtp.rtx[codec.plType].payload_type =
recv_codecs_[i].rtx_payload_type;
@@ -1339,21 +1372,35 @@ void WebRtcVideoChannel2::SetCodecForAllSendStreams(
}
}
+WebRtcVideoChannel2::WebRtcVideoSendStream::VideoSendStreamParameters::
+ VideoSendStreamParameters(
+ const webrtc::VideoSendStream::Config& config,
+ const VideoOptions& options,
+ const VideoCodec& codec,
+ const std::vector<webrtc::VideoStream>& video_streams)
+ : config(config),
+ options(options),
+ codec(codec),
+ video_streams(video_streams) {
+}
+
WebRtcVideoChannel2::WebRtcVideoSendStream::WebRtcVideoSendStream(
webrtc::Call* call,
const webrtc::VideoSendStream::Config& config,
+ const VideoOptions& options,
+ const VideoCodec& codec,
+ const std::vector<webrtc::VideoStream>& video_streams,
WebRtcVideoEncoderFactory2* encoder_factory)
: call_(call),
- config_(config),
+ parameters_(config, options, codec, video_streams),
encoder_factory_(encoder_factory),
capturer_(NULL),
stream_(NULL),
sending_(false),
muted_(false),
- format_(static_cast<int>(config.encoder_settings.streams.back().height),
- static_cast<int>(config.encoder_settings.streams.back().width),
- VideoFormat::FpsToInterval(
- config.encoder_settings.streams.back().max_framerate),
+ format_(static_cast<int>(video_streams.back().height),
+ static_cast<int>(video_streams.back().width),
+ VideoFormat::FpsToInterval(video_streams.back().max_framerate),
FOURCC_I420) {
RecreateWebRtcStream();
}
@@ -1361,7 +1408,7 @@ WebRtcVideoChannel2::WebRtcVideoSendStream::WebRtcVideoSendStream(
WebRtcVideoChannel2::WebRtcVideoSendStream::~WebRtcVideoSendStream() {
DisconnectCapturer();
call_->DestroyVideoSendStream(stream_);
- delete config_.encoder_settings.encoder;
+ delete parameters_.config.encoder_settings.encoder;
}
static void SetWebRtcFrameToBlack(webrtc::I420VideoFrame* video_frame) {
@@ -1428,8 +1475,8 @@ void WebRtcVideoChannel2::WebRtcVideoSendStream::InputFrame(
}
LOG(LS_VERBOSE) << "SwapFrame: " << video_frame_.width() << "x"
<< video_frame_.height() << " -> (codec) "
- << config_.encoder_settings.streams.back().width << "x"
- << config_.encoder_settings.streams.back().height;
+ << parameters_.video_streams.back().width << "x"
+ << parameters_.video_streams.back().height;
stream_->Input()->SwapFrame(&video_frame_);
}
@@ -1480,10 +1527,10 @@ bool WebRtcVideoChannel2::WebRtcVideoSendStream::SetVideoFormat(
if (format.width == 0 && format.height == 0) {
LOG(LS_INFO)
<< "0x0 resolution selected. Captured frames will be dropped for ssrc: "
- << config_.rtp.ssrcs[0] << ".";
+ << parameters_.config.rtp.ssrcs[0] << ".";
} else {
// TODO(pbos): Fix me, this only affects the last stream!
- config_.encoder_settings.streams.back().max_framerate =
+ parameters_.video_streams.back().max_framerate =
VideoFormat::IntervalToFps(format.interval);
SetDimensions(format.width, format.height);
}
@@ -1513,44 +1560,46 @@ void WebRtcVideoChannel2::WebRtcVideoSendStream::SetCodec(
const VideoOptions& options,
const VideoCodecSettings& codec) {
talk_base::CritScope cs(&lock_);
- webrtc::VideoEncoder* old_encoder = config_.encoder_settings.encoder;
- if (!encoder_factory_->CreateEncoderSettings(
- &config_.encoder_settings,
- options,
- codec.codec,
- config_.encoder_settings.streams.size())) {
- LOG(LS_ERROR) << "Could not create encoder settings for: '"
- << codec.codec.name
- << "'. This is most definitely a bug as SetCodec should only "
- "receive codecs which the encoder factory claims to "
- "support.";
+
+ std::vector<webrtc::VideoStream> video_streams =
+ encoder_factory_->CreateVideoStreams(
+ codec.codec, options, parameters_.video_streams.size());
+ if (video_streams.empty()) {
return;
}
+ parameters_.video_streams = video_streams;
format_ = VideoFormat(codec.codec.width,
codec.codec.height,
VideoFormat::FpsToInterval(30),
FOURCC_I420);
- config_.rtp.fec = codec.fec;
+
+ webrtc::VideoEncoder* old_encoder =
+ parameters_.config.encoder_settings.encoder;
+ parameters_.config.encoder_settings.encoder =
+ encoder_factory_->CreateVideoEncoder(codec.codec, options);
+ parameters_.config.rtp.fec = codec.fec;
// TODO(pbos): Should changing RTX payload type be allowed?
+ parameters_.codec = codec.codec;
+ parameters_.options = options;
RecreateWebRtcStream();
delete old_encoder;
}
void WebRtcVideoChannel2::WebRtcVideoSendStream::SetDimensions(int width,
- int height) {
- assert(!config_.encoder_settings.streams.empty());
+ int height) {
+ assert(!parameters_.video_streams.empty());
LOG(LS_VERBOSE) << "SetDimensions: " << width << "x" << height;
- if (config_.encoder_settings.streams.back().width == width &&
- config_.encoder_settings.streams.back().height == height) {
+ if (parameters_.video_streams.back().width == width &&
+ parameters_.video_streams.back().height == height) {
return;
}
// TODO(pbos): Fix me, this only affects the last stream!
- config_.encoder_settings.streams.back().width = width;
- config_.encoder_settings.streams.back().height = height;
- // TODO(pbos): Last parameter shouldn't always be NULL?
- if (!stream_->ReconfigureVideoEncoder(config_.encoder_settings.streams,
- NULL)) {
+ parameters_.video_streams.back().width = width;
+ parameters_.video_streams.back().height = height;
+
+ // TODO(pbos): Wire up encoder_parameters, webrtc:3424.
+ if (!stream_->ReconfigureVideoEncoder(parameters_.video_streams, NULL)) {
LOG(LS_WARNING) << "Failed to reconfigure video encoder for dimensions: "
<< width << "x" << height;
return;
@@ -1573,7 +1622,10 @@ void WebRtcVideoChannel2::WebRtcVideoSendStream::RecreateWebRtcStream() {
if (stream_ != NULL) {
call_->DestroyVideoSendStream(stream_);
}
- stream_ = call_->CreateVideoSendStream(config_);
+
+ // TODO(pbos): Wire up encoder_parameters, webrtc:3424.
+ stream_ = call_->CreateVideoSendStream(
+ parameters_.config, parameters_.video_streams, NULL);
if (sending_) {
stream_->Start();
}
@@ -1588,6 +1640,7 @@ WebRtcVideoChannel2::MapCodecs(const std::vector<VideoCodec>& codecs) {
std::vector<VideoCodecSettings> video_codecs;
std::map<int, bool> payload_used;
+ std::map<int, VideoCodec::CodecType> payload_codec_type;
std::map<int, int> rtx_mapping; // video payload type -> rtx payload type.
webrtc::FecConfig fec_settings;
@@ -1602,6 +1655,7 @@ WebRtcVideoChannel2::MapCodecs(const std::vector<VideoCodec>& codecs) {
return std::vector<VideoCodecSettings>();
}
payload_used[payload_type] = true;
+ payload_codec_type[payload_type] = in_codec.GetCodecType();
switch (in_codec.GetCodecType()) {
case VideoCodec::CODEC_RED: {
@@ -1642,6 +1696,19 @@ WebRtcVideoChannel2::MapCodecs(const std::vector<VideoCodec>& codecs) {
// parameters into this code is a logic error.
assert(!video_codecs.empty());
+ for (std::map<int, int>::const_iterator it = rtx_mapping.begin();
+ it != rtx_mapping.end();
+ ++it) {
+ if (!payload_used[it->first]) {
+ LOG(LS_ERROR) << "RTX mapped to payload not in codec list.";
+ return std::vector<VideoCodecSettings>();
+ }
+ if (payload_codec_type[it->first] != VideoCodec::CODEC_VIDEO) {
+ LOG(LS_ERROR) << "RTX not mapped to regular video codec.";
+ return std::vector<VideoCodecSettings>();
+ }
+ }
+
// TODO(pbos): Write tests that figure out that I have not verified that RTX
// codecs aren't mapped to bogus payloads.
for (size_t i = 0; i < video_codecs.size(); ++i) {
diff --git a/media/webrtc/webrtcvideoengine2.h b/media/webrtc/webrtcvideoengine2.h
index 10a1608..d1a784d 100644
--- a/media/webrtc/webrtcvideoengine2.h
+++ b/media/webrtc/webrtcvideoengine2.h
@@ -83,12 +83,16 @@ class WebRtcVideoChannel2;
class WebRtcVideoEncoderFactory2 {
public:
virtual ~WebRtcVideoEncoderFactory2();
- virtual bool CreateEncoderSettings(
- webrtc::VideoSendStream::Config::EncoderSettings* encoder_settings,
+ virtual std::vector<webrtc::VideoStream> CreateVideoStreams(
+ const VideoCodec& codec,
const VideoOptions& options,
- const cricket::VideoCodec& codec,
- size_t num_streams) = 0;
- virtual bool SupportsCodec(const cricket::VideoCodec& codec) = 0;
+ size_t num_streams);
+
+ virtual webrtc::VideoEncoder* CreateVideoEncoder(
+ const VideoCodec& codec,
+ const VideoOptions& options);
+
+ virtual bool SupportsCodec(const cricket::VideoCodec& codec);
};
// WebRtcVideoEngine2 is used for the new native WebRTC Video API (webrtc:1667).
@@ -140,7 +144,7 @@ class WebRtcVideoEngine2 : public sigslot::has_slots<> {
talk_base::CpuMonitor* cpu_monitor() { return cpu_monitor_.get(); }
- virtual WebRtcVideoEncoderFactory2* GetVideoEncoderFactory() const;
+ virtual WebRtcVideoEncoderFactory2* GetVideoEncoderFactory();
private:
void Construct(WebRtcVideoChannelFactory* channel_factory,
@@ -163,8 +167,7 @@ class WebRtcVideoEngine2 : public sigslot::has_slots<> {
talk_base::scoped_ptr<talk_base::CpuMonitor> cpu_monitor_;
WebRtcVideoChannelFactory* channel_factory_;
- talk_base::scoped_ptr<WebRtcVideoEncoderFactory2>
- default_video_encoder_factory_;
+ WebRtcVideoEncoderFactory2 default_video_encoder_factory_;
};
// Adapter between webrtc::VideoRenderer and cricket::VideoRenderer.
@@ -258,7 +261,7 @@ class WebRtcVideoChannel2 : public talk_base::MessageHandler,
struct VideoCodecSettings {
VideoCodecSettings();
- cricket::VideoCodec codec;
+ VideoCodec codec;
webrtc::FecConfig fec;
int rtx_payload_type;
};
@@ -266,8 +269,11 @@ class WebRtcVideoChannel2 : public talk_base::MessageHandler,
class WebRtcVideoSendStream : public sigslot::has_slots<> {
public:
WebRtcVideoSendStream(webrtc::Call* call,
- const webrtc::VideoSendStream::Config& config,
- WebRtcVideoEncoderFactory2* encoder_factory);
+ const webrtc::VideoSendStream::Config& config,
+ const VideoOptions& options,
+ const VideoCodec& codec,
+ const std::vector<webrtc::VideoStream>& video_streams,
+ WebRtcVideoEncoderFactory2* encoder_factory);
~WebRtcVideoSendStream();
void SetCodec(const VideoOptions& options, const VideoCodecSettings& codec);
@@ -281,6 +287,25 @@ class WebRtcVideoChannel2 : public talk_base::MessageHandler,
void Stop();
private:
+ // Parameters needed to reconstruct the underlying stream.
+ // webrtc::VideoSendStream doesn't support setting a lot of options on the
+ // fly, so when those need to be changed we tear down and reconstruct with
+ // similar parameters depending on which options changed etc.
+ struct VideoSendStreamParameters {
+ VideoSendStreamParameters(
+ const webrtc::VideoSendStream::Config& config,
+ const VideoOptions& options,
+ const VideoCodec& codec,
+ const std::vector<webrtc::VideoStream>& video_streams);
+ webrtc::VideoSendStream::Config config;
+ VideoOptions options;
+ VideoCodec codec;
+ // Sent resolutions + bitrates etc. by the underlying VideoSendStream,
+ // typically changes when setting a new resolution or reconfiguring
+ // bitrates.
+ std::vector<webrtc::VideoStream> video_streams;
+ };
+
void RecreateWebRtcStream();
void SetDimensions(int width, int height);
@@ -289,7 +314,8 @@ class WebRtcVideoChannel2 : public talk_base::MessageHandler,
talk_base::CriticalSection lock_;
webrtc::VideoSendStream* stream_ GUARDED_BY(lock_);
- webrtc::VideoSendStream::Config config_ GUARDED_BY(lock_);
+ VideoSendStreamParameters parameters_ GUARDED_BY(lock_);
+
VideoCapturer* capturer_ GUARDED_BY(lock_);
bool sending_ GUARDED_BY(lock_);
bool muted_ GUARDED_BY(lock_);
diff --git a/media/webrtc/webrtcvideoengine2_unittest.cc b/media/webrtc/webrtcvideoengine2_unittest.cc
index bba1455..c9ff182 100644
--- a/media/webrtc/webrtcvideoengine2_unittest.cc
+++ b/media/webrtc/webrtcvideoengine2_unittest.cc
@@ -26,13 +26,14 @@
*/
#include <map>
+#include <vector>
#include "talk/base/gunit.h"
#include "talk/media/base/testutils.h"
#include "talk/media/base/videoengine_unittest.h"
#include "talk/media/webrtc/webrtcvideoengine2.h"
+#include "talk/media/webrtc/webrtcvideoengine2_unittest.h"
#include "talk/media/webrtc/webrtcvideochannelfactory.h"
-#include "webrtc/call.h"
namespace {
static const cricket::VideoCodec kVp8Codec720p(100, "VP8", 1280, 720, 30, 0);
@@ -47,250 +48,259 @@ static const cricket::VideoCodec kUlpfecCodec(117, "ulpfec", 0, 0, 0, 0);
static const uint32 kSsrcs1[] = {1};
static const uint32 kRtxSsrcs1[] = {4};
+
+void VerifyCodecHasDefaultFeedbackParams(const cricket::VideoCodec& codec) {
+ EXPECT_TRUE(codec.HasFeedbackParam(cricket::FeedbackParam(
+ cricket::kRtcpFbParamNack, cricket::kParamValueEmpty)));
+ EXPECT_TRUE(codec.HasFeedbackParam(cricket::FeedbackParam(
+ cricket::kRtcpFbParamNack, cricket::kRtcpFbNackParamPli)));
+ EXPECT_TRUE(codec.HasFeedbackParam(cricket::FeedbackParam(
+ cricket::kRtcpFbParamRemb, cricket::kParamValueEmpty)));
+ EXPECT_TRUE(codec.HasFeedbackParam(cricket::FeedbackParam(
+ cricket::kRtcpFbParamCcm, cricket::kRtcpFbCcmParamFir)));
+}
+
} // namespace
namespace cricket {
-class FakeVideoSendStream : public webrtc::VideoSendStream {
- public:
- explicit FakeVideoSendStream(const webrtc::VideoSendStream::Config& config)
- : sending_(false) {
- config_ = config;
- }
+FakeVideoSendStream::FakeVideoSendStream(
+ const webrtc::VideoSendStream::Config& config,
+ const std::vector<webrtc::VideoStream>& video_streams)
+ : sending_(false), config_(config), video_streams_(video_streams) {
+}
- webrtc::VideoSendStream::Config GetConfig() { return config_; }
+webrtc::VideoSendStream::Config FakeVideoSendStream::GetConfig() {
+ return config_;
+}
- bool IsSending() { return sending_; }
+std::vector<webrtc::VideoStream> FakeVideoSendStream::GetVideoStreams() {
+ return video_streams_;
+}
- private:
- virtual webrtc::VideoSendStream::Stats GetStats() const OVERRIDE {
- return webrtc::VideoSendStream::Stats();
- }
+bool FakeVideoSendStream::IsSending() {
+ return sending_;
+}
- virtual bool ReconfigureVideoEncoder(
- const std::vector<webrtc::VideoStream>& streams,
- void* encoder_specific) OVERRIDE {
- // TODO(pbos): Store encoder_specific ptr?
- config_.encoder_settings.streams = streams;
- return true;
- }
+webrtc::VideoSendStream::Stats FakeVideoSendStream::GetStats() const {
+ return webrtc::VideoSendStream::Stats();
+}
- virtual webrtc::VideoSendStreamInput* Input() OVERRIDE {
- // TODO(pbos): Fix.
- return NULL;
- }
+bool FakeVideoSendStream::ReconfigureVideoEncoder(
+ const std::vector<webrtc::VideoStream>& streams,
+ const void* encoder_specific) {
+ video_streams_ = streams;
+ return true;
+}
- virtual void Start() OVERRIDE { sending_ = true; }
+webrtc::VideoSendStreamInput* FakeVideoSendStream::Input() {
+ // TODO(pbos): Fix.
+ return NULL;
+}
- virtual void Stop() OVERRIDE { sending_ = false; }
+void FakeVideoSendStream::Start() {
+ sending_ = true;
+}
- bool sending_;
- webrtc::VideoSendStream::Config config_;
-};
+void FakeVideoSendStream::Stop() {
+ sending_ = false;
+}
-class FakeVideoReceiveStream : public webrtc::VideoReceiveStream {
- public:
- explicit FakeVideoReceiveStream(
- const webrtc::VideoReceiveStream::Config& config)
- : config_(config), receiving_(false) {}
+FakeVideoReceiveStream::FakeVideoReceiveStream(
+ const webrtc::VideoReceiveStream::Config& config)
+ : config_(config), receiving_(false) {
+}
- webrtc::VideoReceiveStream::Config GetConfig() { return config_; }
+webrtc::VideoReceiveStream::Config FakeVideoReceiveStream::GetConfig() {
+ return config_;
+}
- private:
- virtual webrtc::VideoReceiveStream::Stats GetStats() const OVERRIDE {
- return webrtc::VideoReceiveStream::Stats();
- }
+webrtc::VideoReceiveStream::Stats FakeVideoReceiveStream::GetStats() const {
+ return webrtc::VideoReceiveStream::Stats();
+}
- virtual void Start() OVERRIDE { receiving_ = true; }
- virtual void Stop() OVERRIDE { receiving_ = false; }
- virtual void GetCurrentReceiveCodec(webrtc::VideoCodec* codec) OVERRIDE {}
+void FakeVideoReceiveStream::Start() {
+ receiving_ = true;
+}
+void FakeVideoReceiveStream::Stop() {
+ receiving_ = false;
+}
+void FakeVideoReceiveStream::GetCurrentReceiveCodec(webrtc::VideoCodec* codec) {
+}
- webrtc::VideoReceiveStream::Config config_;
- bool receiving_;
-};
+FakeCall::FakeCall() { SetVideoCodecs(GetDefaultVideoCodecs()); }
-class FakeCall : public webrtc::Call {
- public:
- FakeCall() { SetVideoCodecs(GetDefaultVideoCodecs()); }
+FakeCall::~FakeCall() {
+ EXPECT_EQ(0u, video_send_streams_.size());
+ EXPECT_EQ(0u, video_receive_streams_.size());
+}
- ~FakeCall() {
- EXPECT_EQ(0u, video_send_streams_.size());
- EXPECT_EQ(0u, video_receive_streams_.size());
- }
+void FakeCall::SetVideoCodecs(const std::vector<webrtc::VideoCodec> codecs) {
+ codecs_ = codecs;
+}
- void SetVideoCodecs(const std::vector<webrtc::VideoCodec> codecs) {
- codecs_ = codecs;
- }
+std::vector<FakeVideoSendStream*> FakeCall::GetVideoSendStreams() {
+ return video_send_streams_;
+}
- std::vector<FakeVideoSendStream*> GetVideoSendStreams() {
- return video_send_streams_;
- }
+std::vector<FakeVideoReceiveStream*> FakeCall::GetVideoReceiveStreams() {
+ return video_receive_streams_;
+}
- std::vector<FakeVideoReceiveStream*> GetVideoReceiveStreams() {
- return video_receive_streams_;
- }
+webrtc::VideoCodec FakeCall::GetEmptyVideoCodec() {
+ webrtc::VideoCodec codec;
+ codec.minBitrate = 300;
+ codec.startBitrate = 800;
+ codec.maxBitrate = 1500;
+ codec.maxFramerate = 10;
+ codec.width = 640;
+ codec.height = 480;
+ codec.qpMax = 56;
- webrtc::VideoCodec GetEmptyVideoCodec() {
- webrtc::VideoCodec codec;
- codec.minBitrate = 300;
- codec.startBitrate = 800;
- codec.maxBitrate = 1500;
- codec.maxFramerate = 10;
- codec.width = 640;
- codec.height = 480;
- codec.qpMax = 56;
-
- return codec;
- }
+ return codec;
+}
- webrtc::VideoCodec GetVideoCodecVp8() {
- webrtc::VideoCodec vp8_codec = GetEmptyVideoCodec();
- vp8_codec.codecType = webrtc::kVideoCodecVP8;
- strcpy(vp8_codec.plName, kVp8Codec.name.c_str());
- vp8_codec.plType = kVp8Codec.id;
+webrtc::VideoCodec FakeCall::GetVideoCodecVp8() {
+ webrtc::VideoCodec vp8_codec = GetEmptyVideoCodec();
+ vp8_codec.codecType = webrtc::kVideoCodecVP8;
+ strcpy(vp8_codec.plName, kVp8Codec.name.c_str());
+ vp8_codec.plType = kVp8Codec.id;
- return vp8_codec;
- }
+ return vp8_codec;
+}
- webrtc::VideoCodec GetVideoCodecVp9() {
- webrtc::VideoCodec vp9_codec = GetEmptyVideoCodec();
- // TODO(pbos): Add a correct codecType when webrtc has one.
- vp9_codec.codecType = webrtc::kVideoCodecVP8;
- strcpy(vp9_codec.plName, kVp9Codec.name.c_str());
- vp9_codec.plType = kVp9Codec.id;
+webrtc::VideoCodec FakeCall::GetVideoCodecVp9() {
+ webrtc::VideoCodec vp9_codec = GetEmptyVideoCodec();
+ // TODO(pbos): Add a correct codecType when webrtc has one.
+ vp9_codec.codecType = webrtc::kVideoCodecVP8;
+ strcpy(vp9_codec.plName, kVp9Codec.name.c_str());
+ vp9_codec.plType = kVp9Codec.id;
- return vp9_codec;
- }
+ return vp9_codec;
+}
- std::vector<webrtc::VideoCodec> GetDefaultVideoCodecs() {
- std::vector<webrtc::VideoCodec> codecs;
- codecs.push_back(GetVideoCodecVp8());
- // codecs.push_back(GetVideoCodecVp9());
+std::vector<webrtc::VideoCodec> FakeCall::GetDefaultVideoCodecs() {
+ std::vector<webrtc::VideoCodec> codecs;
+ codecs.push_back(GetVideoCodecVp8());
+ // codecs.push_back(GetVideoCodecVp9());
- return codecs;
- }
+ return codecs;
+}
- private:
- virtual webrtc::VideoSendStream::Config GetDefaultSendConfig() OVERRIDE {
- webrtc::VideoSendStream::Config config;
- // TODO(pbos): Encoder settings.
- // config.codec = GetVideoCodecVp8();
- return config;
- }
+webrtc::VideoSendStream::Config FakeCall::GetDefaultSendConfig() {
+ webrtc::VideoSendStream::Config config;
+ // TODO(pbos): Encoder settings.
+ // config.codec = GetVideoCodecVp8();
+ return config;
+}
- virtual webrtc::VideoSendStream* CreateVideoSendStream(
- const webrtc::VideoSendStream::Config& config) OVERRIDE {
- FakeVideoSendStream* fake_stream = new FakeVideoSendStream(config);
- video_send_streams_.push_back(fake_stream);
- return fake_stream;
- }
+webrtc::VideoSendStream* FakeCall::CreateVideoSendStream(
+ const webrtc::VideoSendStream::Config& config,
+ const std::vector<webrtc::VideoStream>& video_streams,
+ const void* encoder_settings) {
+ FakeVideoSendStream* fake_stream =
+ new FakeVideoSendStream(config, video_streams);
+ video_send_streams_.push_back(fake_stream);
+ return fake_stream;
+}
- virtual void DestroyVideoSendStream(webrtc::VideoSendStream* send_stream)
- OVERRIDE {
- FakeVideoSendStream* fake_stream =
- static_cast<FakeVideoSendStream*>(send_stream);
- for (size_t i = 0; i < video_send_streams_.size(); ++i) {
- if (video_send_streams_[i] == fake_stream) {
- delete video_send_streams_[i];
- video_send_streams_.erase(video_send_streams_.begin() + i);
- return;
- }
+void FakeCall::DestroyVideoSendStream(webrtc::VideoSendStream* send_stream) {
+ FakeVideoSendStream* fake_stream =
+ static_cast<FakeVideoSendStream*>(send_stream);
+ for (size_t i = 0; i < video_send_streams_.size(); ++i) {
+ if (video_send_streams_[i] == fake_stream) {
+ delete video_send_streams_[i];
+ video_send_streams_.erase(video_send_streams_.begin() + i);
+ return;
}
- ADD_FAILURE() << "DestroyVideoSendStream called with unknown paramter.";
}
+ ADD_FAILURE() << "DestroyVideoSendStream called with unknown paramter.";
+}
- virtual webrtc::VideoReceiveStream::Config GetDefaultReceiveConfig()
- OVERRIDE {
- return webrtc::VideoReceiveStream::Config();
- }
+webrtc::VideoReceiveStream::Config FakeCall::GetDefaultReceiveConfig() {
+ return webrtc::VideoReceiveStream::Config();
+}
- virtual webrtc::VideoReceiveStream* CreateVideoReceiveStream(
- const webrtc::VideoReceiveStream::Config& config) OVERRIDE {
- video_receive_streams_.push_back(new FakeVideoReceiveStream(config));
- return video_receive_streams_[video_receive_streams_.size() - 1];
- }
+webrtc::VideoReceiveStream* FakeCall::CreateVideoReceiveStream(
+ const webrtc::VideoReceiveStream::Config& config) {
+ video_receive_streams_.push_back(new FakeVideoReceiveStream(config));
+ return video_receive_streams_[video_receive_streams_.size() - 1];
+}
- virtual void DestroyVideoReceiveStream(
- webrtc::VideoReceiveStream* receive_stream) OVERRIDE {
- FakeVideoReceiveStream* fake_stream =
- static_cast<FakeVideoReceiveStream*>(receive_stream);
- for (size_t i = 0; i < video_receive_streams_.size(); ++i) {
- if (video_receive_streams_[i] == fake_stream) {
- delete video_receive_streams_[i];
- video_receive_streams_.erase(video_receive_streams_.begin() + i);
- return;
- }
+void FakeCall::DestroyVideoReceiveStream(
+ webrtc::VideoReceiveStream* receive_stream) {
+ FakeVideoReceiveStream* fake_stream =
+ static_cast<FakeVideoReceiveStream*>(receive_stream);
+ for (size_t i = 0; i < video_receive_streams_.size(); ++i) {
+ if (video_receive_streams_[i] == fake_stream) {
+ delete video_receive_streams_[i];
+ video_receive_streams_.erase(video_receive_streams_.begin() + i);
+ return;
}
- ADD_FAILURE() << "DestroyVideoReceiveStream called with unknown paramter.";
}
+ ADD_FAILURE() << "DestroyVideoReceiveStream called with unknown paramter.";
+}
- virtual webrtc::PacketReceiver* Receiver() OVERRIDE {
- // TODO(pbos): Fix this.
- return NULL;
- }
-
- virtual uint32_t SendBitrateEstimate() OVERRIDE { return 0; }
-
- virtual uint32_t ReceiveBitrateEstimate() OVERRIDE { return 0; }
-
- private:
- std::vector<webrtc::VideoCodec> codecs_;
- std::vector<FakeVideoSendStream*> video_send_streams_;
- std::vector<FakeVideoReceiveStream*> video_receive_streams_;
-};
+webrtc::PacketReceiver* FakeCall::Receiver() {
+ // TODO(pbos): Fix this.
+ return NULL;
+}
-class FakeWebRtcVideoChannel2 : public WebRtcVideoChannel2 {
- public:
- FakeWebRtcVideoChannel2(FakeCall* call,
- WebRtcVideoEngine2* engine,
- VoiceMediaChannel* voice_channel)
- : WebRtcVideoChannel2(call, engine, engine->GetVideoEncoderFactory()),
- fake_call_(call),
- voice_channel_(voice_channel) {}
+uint32_t FakeCall::SendBitrateEstimate() {
+ return 0;
+}
- virtual ~FakeWebRtcVideoChannel2() {}
+uint32_t FakeCall::ReceiveBitrateEstimate() {
+ return 0;
+}
- VoiceMediaChannel* GetVoiceChannel() { return voice_channel_; }
- FakeCall* GetFakeCall() { return fake_call_; }
+FakeWebRtcVideoChannel2::FakeWebRtcVideoChannel2(
+ FakeCall* call,
+ WebRtcVideoEngine2* engine,
+ VoiceMediaChannel* voice_channel)
+ : WebRtcVideoChannel2(call, engine, engine->GetVideoEncoderFactory()),
+ fake_call_(call),
+ voice_channel_(voice_channel) {
+}
- private:
- FakeCall* fake_call_;
- VoiceMediaChannel* voice_channel_;
-};
+FakeWebRtcVideoChannel2::~FakeWebRtcVideoChannel2() {
+}
-class FakeWebRtcVideoMediaChannelFactory : public WebRtcVideoChannelFactory {
- public:
- FakeWebRtcVideoChannel2* GetFakeChannel(VideoMediaChannel* channel) {
- return channel_map_[channel];
- }
+VoiceMediaChannel* FakeWebRtcVideoChannel2::GetVoiceChannel() {
+ return voice_channel_;
+}
+FakeCall* FakeWebRtcVideoChannel2::GetFakeCall() {
+ return fake_call_;
+}
- private:
- virtual WebRtcVideoChannel2* Create(WebRtcVideoEngine2* engine,
- VoiceMediaChannel* voice_channel)
- OVERRIDE {
- FakeWebRtcVideoChannel2* channel =
- new FakeWebRtcVideoChannel2(new FakeCall(), engine, voice_channel);
- channel_map_[channel] = channel;
- return channel;
- }
+FakeWebRtcVideoChannel2* FakeWebRtcVideoMediaChannelFactory::GetFakeChannel(
+ VideoMediaChannel* channel) {
+ return channel_map_[channel];
+}
- std::map<VideoMediaChannel*, FakeWebRtcVideoChannel2*> channel_map_;
-};
+WebRtcVideoChannel2* FakeWebRtcVideoMediaChannelFactory::Create(
+ WebRtcVideoEngine2* engine,
+ VoiceMediaChannel* voice_channel) {
+ FakeWebRtcVideoChannel2* channel =
+ new FakeWebRtcVideoChannel2(new FakeCall(), engine, voice_channel);
+ channel_map_[channel] = channel;
+ return channel;
+}
class WebRtcVideoEngine2Test : public testing::Test {
public:
- WebRtcVideoEngine2Test()
- : engine_(&factory_), engine_codecs_(engine_.codecs()) {
- assert(!engine_codecs_.empty());
+ WebRtcVideoEngine2Test() : engine_(&factory_) {
+ std::vector<VideoCodec> engine_codecs = engine_.codecs();
+ assert(!engine_codecs.empty());
bool codec_set = false;
- for (size_t i = 0; i < engine_codecs_.size(); ++i) {
- if (engine_codecs_[i].name == "red") {
- default_red_codec_ = engine_codecs_[i];
- } else if (engine_codecs_[i].name == "ulpfec") {
- default_ulpfec_codec_ = engine_codecs_[i];
- } else if (engine_codecs_[i].name == "rtx") {
- default_rtx_codec_ = engine_codecs_[i];
+ for (size_t i = 0; i < engine_codecs.size(); ++i) {
+ if (engine_codecs[i].name == "red") {
+ default_red_codec_ = engine_codecs[i];
+ } else if (engine_codecs[i].name == "ulpfec") {
+ default_ulpfec_codec_ = engine_codecs[i];
+ } else if (engine_codecs[i].name == "rtx") {
+ default_rtx_codec_ = engine_codecs[i];
} else if (!codec_set) {
- default_codec_ = engine_codecs_[i];
+ default_codec_ = engine_codecs[i];
codec_set = true;
}
}
@@ -305,8 +315,6 @@ class WebRtcVideoEngine2Test : public testing::Test {
VideoCodec default_red_codec_;
VideoCodec default_ulpfec_codec_;
VideoCodec default_rtx_codec_;
- // TODO(pbos): Remove engine_codecs_ unless used a lot.
- std::vector<VideoCodec> engine_codecs_;
};
TEST_F(WebRtcVideoEngine2Test, CreateChannel) {
@@ -332,6 +340,62 @@ TEST_F(WebRtcVideoEngine2Test, CreateChannelWithVoiceEngine) {
<< "Different VoiceChannel set than the provided one.";
}
+TEST_F(WebRtcVideoEngine2Test, FindCodec) {
+ const std::vector<cricket::VideoCodec>& c = engine_.codecs();
+ EXPECT_EQ(4U, c.size());
+
+ cricket::VideoCodec vp8(104, "VP8", 320, 200, 30, 0);
+ EXPECT_TRUE(engine_.FindCodec(vp8));
+
+ cricket::VideoCodec vp8_ci(104, "vp8", 320, 200, 30, 0);
+ EXPECT_TRUE(engine_.FindCodec(vp8));
+
+ cricket::VideoCodec vp8_diff_fr_diff_pref(104, "VP8", 320, 200, 50, 50);
+ EXPECT_TRUE(engine_.FindCodec(vp8_diff_fr_diff_pref));
+
+ cricket::VideoCodec vp8_diff_id(95, "VP8", 320, 200, 30, 0);
+ EXPECT_FALSE(engine_.FindCodec(vp8_diff_id));
+ vp8_diff_id.id = 97;
+ EXPECT_TRUE(engine_.FindCodec(vp8_diff_id));
+
+ cricket::VideoCodec vp8_diff_res(104, "VP8", 320, 111, 30, 0);
+ EXPECT_FALSE(engine_.FindCodec(vp8_diff_res));
+
+ // PeerConnection doesn't negotiate the resolution at this point.
+ // Test that FindCodec can handle the case when width/height is 0.
+ cricket::VideoCodec vp8_zero_res(104, "VP8", 0, 0, 30, 0);
+ EXPECT_TRUE(engine_.FindCodec(vp8_zero_res));
+
+ cricket::VideoCodec red(101, "RED", 0, 0, 30, 0);
+ EXPECT_TRUE(engine_.FindCodec(red));
+
+ cricket::VideoCodec red_ci(101, "red", 0, 0, 30, 0);
+ EXPECT_TRUE(engine_.FindCodec(red));
+
+ cricket::VideoCodec fec(102, "ULPFEC", 0, 0, 30, 0);
+ EXPECT_TRUE(engine_.FindCodec(fec));
+
+ cricket::VideoCodec fec_ci(102, "ulpfec", 0, 0, 30, 0);
+ EXPECT_TRUE(engine_.FindCodec(fec));
+
+ cricket::VideoCodec rtx(96, "rtx", 0, 0, 30, 0);
+ EXPECT_TRUE(engine_.FindCodec(rtx));
+}
+
+TEST_F(WebRtcVideoEngine2Test, DefaultRtxCodecHasAssociatedPayloadTypeSet) {
+ std::vector<VideoCodec> engine_codecs = engine_.codecs();
+ for (size_t i = 0; i < engine_codecs.size(); ++i) {
+ if (engine_codecs[i].name != kRtxCodecName)
+ continue;
+ int associated_payload_type;
+ EXPECT_TRUE(engine_codecs[i].GetParam(kCodecParamAssociatedPayloadType,
+ &associated_payload_type));
+ EXPECT_EQ(default_codec_.id, associated_payload_type);
+ return;
+ }
+ FAIL() << "No RTX codec found among default codecs.";
+}
+
class WebRtcVideoChannel2BaseTest
: public VideoMediaChannelTest<WebRtcVideoEngine2, WebRtcVideoChannel2> {
protected:
@@ -515,13 +579,10 @@ class WebRtcVideoChannel2Test : public WebRtcVideoEngine2Test {
FakeVideoSendStream* stream = AddSendStream();
- webrtc::VideoSendStream::Config::EncoderSettings encoder_settings =
- stream->GetConfig().encoder_settings;
- ASSERT_EQ(1u, encoder_settings.streams.size());
- EXPECT_EQ(atoi(min_bitrate),
- encoder_settings.streams.back().min_bitrate_bps / 1000);
- EXPECT_EQ(atoi(max_bitrate),
- encoder_settings.streams.back().max_bitrate_bps / 1000);
+ std::vector<webrtc::VideoStream> video_streams = stream->GetVideoStreams();
+ ASSERT_EQ(1u, video_streams.size());
+ EXPECT_EQ(atoi(min_bitrate), video_streams.back().min_bitrate_bps / 1000);
+ EXPECT_EQ(atoi(max_bitrate), video_streams.back().max_bitrate_bps / 1000);
VideoCodec codec;
EXPECT_TRUE(channel_->GetSendCodec(&codec));
@@ -556,15 +617,14 @@ TEST_F(WebRtcVideoChannel2Test, DISABLED_StartSendBitrate) {
const unsigned int kVideoTargetSendBitrateKbps = 300;
const unsigned int kVideoMaxSendBitrateKbps = 2000;
FakeVideoSendStream* stream = AddSendStream();
- webrtc::VideoSendStream::Config::EncoderSettings encoder_settings =
- stream->GetConfig().encoder_settings;
- ASSERT_EQ(1u, encoder_settings.streams.size());
+ std::vector<webrtc::VideoStream> video_streams = stream->GetVideoStreams();
+ ASSERT_EQ(1u, video_streams.size());
EXPECT_EQ(kVideoMinSendBitrateKbps,
- encoder_settings.streams.back().min_bitrate_bps / 1000);
+ video_streams.back().min_bitrate_bps / 1000);
EXPECT_EQ(kVideoTargetSendBitrateKbps,
- encoder_settings.streams.back().target_bitrate_bps / 1000);
+ video_streams.back().target_bitrate_bps / 1000);
EXPECT_EQ(kVideoMaxSendBitrateKbps,
- encoder_settings.streams.back().max_bitrate_bps / 1000);
+ video_streams.back().max_bitrate_bps / 1000);
#if 0
// TODO(pbos): un-#if
VerifyVP8SendCodec(send_channel, kVP8Codec.width, kVP8Codec.height, 0,
@@ -615,7 +675,7 @@ TEST_F(WebRtcVideoChannel2Test, DISABLED_RembEnabledOnReceiveChannels) {
FAIL() << "Not implemented."; // TODO(pbos): Implement.
}
-TEST_F(WebRtcVideoChannel2Test, RecvStreamWithRtx) {
+TEST_F(WebRtcVideoChannel2Test, RecvStreamWithSimAndRtx) {
EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
EXPECT_TRUE(channel_->SetSend(true));
cricket::VideoOptions options;
@@ -644,12 +704,23 @@ TEST_F(WebRtcVideoChannel2Test, RecvStreamWithRtx) {
// TODO(pbos): Make sure we set the RTX for correct payloads etc.
}
-TEST_F(WebRtcVideoChannel2Test, DISABLED_RecvStreamWithRtxOnMultiplePayloads) {
- FAIL() << "Not implemented.";
+TEST_F(WebRtcVideoChannel2Test, RecvStreamWithRtx) {
+ // Setup one channel with an associated RTX stream.
+ cricket::StreamParams params =
+ cricket::StreamParams::CreateLegacy(kSsrcs1[0]);
+ params.AddFidSsrc(kSsrcs1[0], kRtxSsrcs1[0]);
+ FakeVideoReceiveStream* recv_stream = AddRecvStream(params);
+ ASSERT_EQ(1u, recv_stream->GetConfig().rtp.rtx.size());
+ EXPECT_EQ(kRtxSsrcs1[0],
+ recv_stream->GetConfig().rtp.rtx.begin()->second.ssrc);
}
-TEST_F(WebRtcVideoChannel2Test, DISABLED_RecvStreamNoRtx) {
- FAIL() << "Not implemented."; // TODO(pbos): Implement.
+TEST_F(WebRtcVideoChannel2Test, RecvStreamNoRtx) {
+ // Setup one channel without an associated RTX stream.
+ cricket::StreamParams params =
+ cricket::StreamParams::CreateLegacy(kSsrcs1[0]);
+ FakeVideoReceiveStream* recv_stream = AddRecvStream(params);
+ ASSERT_TRUE(recv_stream->GetConfig().rtp.rtx.empty());
}
TEST_F(WebRtcVideoChannel2Test, DISABLED_RtpTimestampOffsetHeaderExtensions) {
@@ -685,7 +756,9 @@ TEST_F(WebRtcVideoChannel2Test, DISABLED_RembOnOff) {
FAIL() << "Not implemented."; // TODO(pbos): Implement.
}
-TEST_F(WebRtcVideoChannel2Test, NackIsEnabled) {
+TEST_F(WebRtcVideoChannel2Test, NackIsEnabledByDefault) {
+ VerifyCodecHasDefaultFeedbackParams(default_codec_);
+
EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
EXPECT_TRUE(channel_->SetSend(true));
@@ -704,6 +777,23 @@ TEST_F(WebRtcVideoChannel2Test, NackIsEnabled) {
recv_stream->GetConfig().rtp.nack.rtp_history_ms);
}
+TEST_F(WebRtcVideoChannel2Test, NackCanBeDisabled) {
+ std::vector<VideoCodec> codecs;
+ codecs.push_back(kVp8Codec);
+
+ // Send side.
+ ASSERT_TRUE(channel_->SetSendCodecs(codecs));
+ FakeVideoSendStream* send_stream =
+ AddSendStream(cricket::StreamParams::CreateLegacy(1));
+ EXPECT_EQ(0, send_stream->GetConfig().rtp.nack.rtp_history_ms);
+
+ // Receiver side.
+ ASSERT_TRUE(channel_->SetRecvCodecs(codecs));
+ FakeVideoReceiveStream* recv_stream =
+ AddRecvStream(cricket::StreamParams::CreateLegacy(1));
+ EXPECT_EQ(0, recv_stream->GetConfig().rtp.nack.rtp_history_ms);
+}
+
TEST_F(WebRtcVideoChannel2Test, DISABLED_VideoProtectionInterop) {
FAIL() << "Not implemented."; // TODO(pbos): Implement.
}
@@ -785,67 +875,12 @@ TEST_F(WebRtcVideoChannel2Test, DISABLED_WebRtcShouldNotLog) {
FAIL() << "Not implemented."; // TODO(pbos): Implement.
}
-TEST_F(WebRtcVideoEngine2Test, FindCodec) {
- const std::vector<cricket::VideoCodec>& c = engine_.codecs();
- EXPECT_EQ(4U, c.size());
-
- cricket::VideoCodec vp8(104, "VP8", 320, 200, 30, 0);
- EXPECT_TRUE(engine_.FindCodec(vp8));
-
- cricket::VideoCodec vp8_ci(104, "vp8", 320, 200, 30, 0);
- EXPECT_TRUE(engine_.FindCodec(vp8));
-
- cricket::VideoCodec vp8_diff_fr_diff_pref(104, "VP8", 320, 200, 50, 50);
- EXPECT_TRUE(engine_.FindCodec(vp8_diff_fr_diff_pref));
-
- cricket::VideoCodec vp8_diff_id(95, "VP8", 320, 200, 30, 0);
- EXPECT_FALSE(engine_.FindCodec(vp8_diff_id));
- vp8_diff_id.id = 97;
- EXPECT_TRUE(engine_.FindCodec(vp8_diff_id));
-
- cricket::VideoCodec vp8_diff_res(104, "VP8", 320, 111, 30, 0);
- EXPECT_FALSE(engine_.FindCodec(vp8_diff_res));
-
- // PeerConnection doesn't negotiate the resolution at this point.
- // Test that FindCodec can handle the case when width/height is 0.
- cricket::VideoCodec vp8_zero_res(104, "VP8", 0, 0, 30, 0);
- EXPECT_TRUE(engine_.FindCodec(vp8_zero_res));
-
- cricket::VideoCodec red(101, "RED", 0, 0, 30, 0);
- EXPECT_TRUE(engine_.FindCodec(red));
-
- cricket::VideoCodec red_ci(101, "red", 0, 0, 30, 0);
- EXPECT_TRUE(engine_.FindCodec(red));
-
- cricket::VideoCodec fec(102, "ULPFEC", 0, 0, 30, 0);
- EXPECT_TRUE(engine_.FindCodec(fec));
-
- cricket::VideoCodec fec_ci(102, "ulpfec", 0, 0, 30, 0);
- EXPECT_TRUE(engine_.FindCodec(fec));
-
- cricket::VideoCodec rtx(96, "rtx", 0, 0, 30, 0);
- EXPECT_TRUE(engine_.FindCodec(rtx));
-}
-
-TEST_F(WebRtcVideoEngine2Test, DefaultRtxCodecHasAssociatedPayloadTypeSet) {
- for (size_t i = 0; i < engine_codecs_.size(); ++i) {
- if (engine_codecs_[i].name != kRtxCodecName)
- continue;
- int associated_payload_type;
- EXPECT_TRUE(engine_codecs_[i].GetParam(kCodecParamAssociatedPayloadType,
- &associated_payload_type));
- EXPECT_EQ(default_codec_.id, associated_payload_type);
- return;
- }
- FAIL() << "No RTX codec found among default codecs.";
-}
-
TEST_F(WebRtcVideoChannel2Test, SetDefaultSendCodecs) {
- ASSERT_TRUE(channel_->SetSendCodecs(engine_codecs_));
+ ASSERT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
VideoCodec codec;
EXPECT_TRUE(channel_->GetSendCodec(&codec));
- EXPECT_TRUE(codec.Matches(engine_codecs_[0]));
+ EXPECT_TRUE(codec.Matches(engine_.codecs()[0]));
// Using a RTX setup to verify that the default RTX payload type is good.
const std::vector<uint32> ssrcs = MAKE_VECTOR(kSsrcs1);
@@ -854,7 +889,7 @@ TEST_F(WebRtcVideoChannel2Test, SetDefaultSendCodecs) {
cricket::CreateSimWithRtxStreamParams("cname", ssrcs, rtx_ssrcs));
webrtc::VideoSendStream::Config config = stream->GetConfig();
// TODO(pbos): Replace ExpectEqualCodecs.
- // ExpectEqualCodecs(engine_codecs_[0], config.codec);
+ // ExpectEqualCodecs(engine_.codecs()[0], config.codec);
// Make sure NACK and FEC are enabled on the correct payload types.
EXPECT_EQ(1000, config.rtp.nack.rtp_history_ms);
@@ -910,9 +945,10 @@ TEST_F(WebRtcVideoChannel2Test, SetSendCodecsWithMinMaxBitrate) {
}
TEST_F(WebRtcVideoChannel2Test, SetSendCodecsRejectsMaxLessThanMinBitrate) {
- engine_codecs_[0].params[kCodecParamMinBitrate] = "30";
- engine_codecs_[0].params[kCodecParamMaxBitrate] = "20";
- EXPECT_FALSE(channel_->SetSendCodecs(engine_codecs_));
+ std::vector<VideoCodec> video_codecs = engine_.codecs();
+ video_codecs[0].params[kCodecParamMinBitrate] = "30";
+ video_codecs[0].params[kCodecParamMaxBitrate] = "20";
+ EXPECT_FALSE(channel_->SetSendCodecs(video_codecs));
}
TEST_F(WebRtcVideoChannel2Test, SetSendCodecsAcceptLargeMinMaxBitrate) {
@@ -925,9 +961,8 @@ TEST_F(WebRtcVideoChannel2Test, SetSendCodecsWithMaxQuantization) {
codecs.push_back(kVp8Codec);
codecs[0].params[kCodecParamMaxQuantization] = kMaxQuantization;
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
- EXPECT_EQ(
- static_cast<unsigned int>(atoi(kMaxQuantization)),
- AddSendStream()->GetConfig().encoder_settings.streams.back().max_qp);
+ EXPECT_EQ(static_cast<unsigned int>(atoi(kMaxQuantization)),
+ AddSendStream()->GetVideoStreams().back().max_qp);
VideoCodec codec;
EXPECT_TRUE(channel_->GetSendCodec(&codec));
@@ -983,6 +1018,31 @@ TEST_F(WebRtcVideoChannel2Test, SetRecvCodecsWithOnlyVp8) {
EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
}
+// Test that we set our inbound RTX codecs properly.
+TEST_F(WebRtcVideoChannel2Test, SetRecvCodecsWithRtx) {
+ std::vector<cricket::VideoCodec> codecs;
+ codecs.push_back(kVp8Codec);
+ cricket::VideoCodec rtx_codec(96, "rtx", 0, 0, 0, 0);
+ codecs.push_back(rtx_codec);
+ EXPECT_FALSE(channel_->SetRecvCodecs(codecs))
+ << "RTX codec without associated payload should be rejected.";
+
+ codecs[1].SetParam("apt", kVp8Codec.id + 1);
+ EXPECT_FALSE(channel_->SetRecvCodecs(codecs))
+ << "RTX codec with invalid associated payload type should be rejected.";
+
+ codecs[1].SetParam("apt", kVp8Codec.id);
+ EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
+
+ cricket::VideoCodec rtx_codec2(97, "rtx", 0, 0, 0, 0);
+ rtx_codec2.SetParam("apt", rtx_codec.id);
+ codecs.push_back(rtx_codec2);
+
+ EXPECT_FALSE(channel_->SetRecvCodecs(codecs)) << "RTX codec with another RTX "
+ "as associated payload type "
+ "should be rejected.";
+}
+
TEST_F(WebRtcVideoChannel2Test, SetRecvCodecsDifferentPayloadType) {
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(kVp8Codec);
diff --git a/media/webrtc/webrtcvideoengine2_unittest.h b/media/webrtc/webrtcvideoengine2_unittest.h
new file mode 100644
index 0000000..879b4f4
--- /dev/null
+++ b/media/webrtc/webrtcvideoengine2_unittest.h
@@ -0,0 +1,157 @@
+/*
+ * libjingle
+ * Copyright 2014 Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TALK_MEDIA_WEBRTC_WEBRTCVIDEOENGINE2_UNITTEST_H_
+#define TALK_MEDIA_WEBRTC_WEBRTCVIDEOENGINE2_UNITTEST_H_
+
+#include <map>
+#include <vector>
+
+#include "webrtc/call.h"
+#include "webrtc/video_receive_stream.h"
+#include "webrtc/video_send_stream.h"
+
+namespace cricket {
+class FakeVideoSendStream : public webrtc::VideoSendStream {
+ public:
+ FakeVideoSendStream(const webrtc::VideoSendStream::Config& config,
+ const std::vector<webrtc::VideoStream>& video_streams);
+ webrtc::VideoSendStream::Config GetConfig();
+ std::vector<webrtc::VideoStream> GetVideoStreams();
+
+ bool IsSending();
+
+ private:
+ virtual webrtc::VideoSendStream::Stats GetStats() const OVERRIDE;
+
+ virtual bool ReconfigureVideoEncoder(
+ const std::vector<webrtc::VideoStream>& streams,
+ const void* encoder_specific);
+
+ virtual webrtc::VideoSendStreamInput* Input() OVERRIDE;
+
+ virtual void Start() OVERRIDE;
+ virtual void Stop() OVERRIDE;
+
+ bool sending_;
+ webrtc::VideoSendStream::Config config_;
+ std::vector<webrtc::VideoStream> video_streams_;
+};
+
+class FakeVideoReceiveStream : public webrtc::VideoReceiveStream {
+ public:
+ explicit FakeVideoReceiveStream(
+ const webrtc::VideoReceiveStream::Config& config);
+
+ webrtc::VideoReceiveStream::Config GetConfig();
+
+ private:
+ virtual webrtc::VideoReceiveStream::Stats GetStats() const OVERRIDE;
+
+ virtual void Start() OVERRIDE;
+ virtual void Stop() OVERRIDE;
+ virtual void GetCurrentReceiveCodec(webrtc::VideoCodec* codec);
+
+ webrtc::VideoReceiveStream::Config config_;
+ bool receiving_;
+};
+
+class FakeCall : public webrtc::Call {
+ public:
+ FakeCall();
+ ~FakeCall();
+
+ void SetVideoCodecs(const std::vector<webrtc::VideoCodec> codecs);
+
+ std::vector<FakeVideoSendStream*> GetVideoSendStreams();
+ std::vector<FakeVideoReceiveStream*> GetVideoReceiveStreams();
+
+ webrtc::VideoCodec GetEmptyVideoCodec();
+
+ webrtc::VideoCodec GetVideoCodecVp8();
+ webrtc::VideoCodec GetVideoCodecVp9();
+
+ std::vector<webrtc::VideoCodec> GetDefaultVideoCodecs();
+
+ private:
+ virtual webrtc::VideoSendStream::Config GetDefaultSendConfig() OVERRIDE;
+
+ virtual webrtc::VideoSendStream* CreateVideoSendStream(
+ const webrtc::VideoSendStream::Config& config,
+ const std::vector<webrtc::VideoStream>& video_streams,
+ const void* encoder_settings) OVERRIDE;
+
+ virtual void DestroyVideoSendStream(
+ webrtc::VideoSendStream* send_stream) OVERRIDE;
+
+ virtual webrtc::VideoReceiveStream::Config GetDefaultReceiveConfig() OVERRIDE;
+
+ virtual webrtc::VideoReceiveStream* CreateVideoReceiveStream(
+ const webrtc::VideoReceiveStream::Config& config) OVERRIDE;
+
+ virtual void DestroyVideoReceiveStream(
+ webrtc::VideoReceiveStream* receive_stream) OVERRIDE;
+ virtual webrtc::PacketReceiver* Receiver() OVERRIDE;
+
+ virtual uint32_t SendBitrateEstimate() OVERRIDE;
+ virtual uint32_t ReceiveBitrateEstimate() OVERRIDE;
+
+ std::vector<webrtc::VideoCodec> codecs_;
+ std::vector<FakeVideoSendStream*> video_send_streams_;
+ std::vector<FakeVideoReceiveStream*> video_receive_streams_;
+};
+
+class FakeWebRtcVideoChannel2 : public WebRtcVideoChannel2 {
+ public:
+ FakeWebRtcVideoChannel2(FakeCall* call,
+ WebRtcVideoEngine2* engine,
+ VoiceMediaChannel* voice_channel);
+ virtual ~FakeWebRtcVideoChannel2();
+
+ VoiceMediaChannel* GetVoiceChannel();
+ FakeCall* GetFakeCall();
+
+ private:
+ FakeCall* fake_call_;
+ VoiceMediaChannel* voice_channel_;
+};
+
+class FakeWebRtcVideoMediaChannelFactory : public WebRtcVideoChannelFactory {
+ public:
+ FakeWebRtcVideoChannel2* GetFakeChannel(VideoMediaChannel* channel);
+
+ private:
+ virtual WebRtcVideoChannel2* Create(
+ WebRtcVideoEngine2* engine,
+ VoiceMediaChannel* voice_channel) OVERRIDE;
+
+ std::map<VideoMediaChannel*, FakeWebRtcVideoChannel2*> channel_map_;
+};
+
+
+} // namespace cricket
+#endif // TALK_MEDIA_WEBRTC_WEBRTCVIDEOENGINE2_UNITTEST_H_
diff --git a/media/webrtc/webrtcvideoengine_unittest.cc b/media/webrtc/webrtcvideoengine_unittest.cc
index 804b70f..307e594 100644
--- a/media/webrtc/webrtcvideoengine_unittest.cc
+++ b/media/webrtc/webrtcvideoengine_unittest.cc
@@ -74,7 +74,7 @@ static const unsigned int kMaxBandwidthKbps = 2000;
static const uint32 kSsrcs1[] = {1};
static const uint32 kSsrcs2[] = {1, 2};
static const uint32 kSsrcs3[] = {1, 2, 3};
-static const uint32 kRtxSsrc1[] = {4};
+static const uint32 kRtxSsrcs1[] = {4};
static const uint32 kRtxSsrcs3[] = {4, 5, 6};
@@ -749,8 +749,44 @@ TEST_F(WebRtcVideoEngineTestFake, SetRecvCodecsWithRtx) {
EXPECT_EQ(rtx_codec.id, vie_.GetRtxRecvPayloadType(channel_num));
}
+// Test that RTX packets are routed to the default video channel if
+// there's only one recv stream.
+TEST_F(WebRtcVideoEngineTestFake, TestReceiveRtxOneStream) {
+ EXPECT_TRUE(SetupEngine());
+
+ // Setup one channel with an associated RTX stream.
+ cricket::StreamParams params =
+ cricket::StreamParams::CreateLegacy(kSsrcs1[0]);
+ params.AddFidSsrc(kSsrcs1[0], kRtxSsrcs1[0]);
+ EXPECT_TRUE(channel_->AddRecvStream(params));
+ int channel_num = vie_.GetLastChannel();
+ EXPECT_EQ(static_cast<int>(kRtxSsrcs1[0]),
+ vie_.GetRemoteRtxSsrc(channel_num));
+
+ // Register codecs.
+ std::vector<cricket::VideoCodec> codec_list;
+ codec_list.push_back(kVP8Codec720p);
+ cricket::VideoCodec rtx_codec(96, "rtx", 0, 0, 0, 0);
+ rtx_codec.SetParam("apt", kVP8Codec.id);
+ codec_list.push_back(rtx_codec);
+ EXPECT_TRUE(channel_->SetRecvCodecs(codec_list));
+
+ // Construct a fake RTX packet and verify that it is passed to the
+ // right WebRTC channel.
+ const size_t kDataLength = 12;
+ uint8_t data[kDataLength];
+ memset(data, 0, sizeof(data));
+ data[0] = 0x80;
+ data[1] = rtx_codec.id;
+ talk_base::SetBE32(&data[8], kRtxSsrcs1[0]);
+ talk_base::Buffer packet(data, kDataLength);
+ talk_base::PacketTime packet_time;
+ channel_->OnPacketReceived(&packet, packet_time);
+ EXPECT_EQ(rtx_codec.id, vie_.GetLastRecvdPayloadType(channel_num));
+}
+
// Test that RTX packets are routed to the correct video channel.
-TEST_F(WebRtcVideoEngineTestFake, TestReceiveRtx) {
+TEST_F(WebRtcVideoEngineTestFake, TestReceiveRtxThreeStreams) {
EXPECT_TRUE(SetupEngine());
// Setup three channels with associated RTX streams.
@@ -880,7 +916,7 @@ TEST_F(WebRtcVideoEngineTestFake, RecvStreamWithRtx) {
EXPECT_TRUE(channel_->AddRecvStream(
cricket::CreateSimWithRtxStreamParams("cname",
MAKE_VECTOR(kSsrcs1),
- MAKE_VECTOR(kRtxSsrc1))));
+ MAKE_VECTOR(kRtxSsrcs1))));
int new_channel_num = vie_.GetLastChannel();
EXPECT_NE(default_channel, new_channel_num);
EXPECT_EQ(4, vie_.GetRemoteRtxSsrc(new_channel_num));
@@ -923,17 +959,17 @@ TEST_F(WebRtcVideoEngineTestFake, RecvAbsoluteSendTimeHeaderExtensions) {
TEST_F(WebRtcVideoEngineTestFake, LeakyBucketTest) {
EXPECT_TRUE(SetupEngine());
- // Verify this is off by default.
+ // Verify this is on by default.
EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(1)));
int first_send_channel = vie_.GetLastChannel();
- EXPECT_FALSE(vie_.GetTransmissionSmoothingStatus(first_send_channel));
+ EXPECT_TRUE(vie_.GetTransmissionSmoothingStatus(first_send_channel));
- // Enable the experiment and verify.
+ // Disable the experiment and verify.
cricket::VideoOptions options;
options.conference_mode.Set(true);
- options.video_leaky_bucket.Set(true);
+ options.video_leaky_bucket.Set(false);
EXPECT_TRUE(channel_->SetOptions(options));
- EXPECT_TRUE(vie_.GetTransmissionSmoothingStatus(first_send_channel));
+ EXPECT_FALSE(vie_.GetTransmissionSmoothingStatus(first_send_channel));
// Add a receive channel and verify leaky bucket isn't enabled.
EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(2)));
@@ -941,10 +977,16 @@ TEST_F(WebRtcVideoEngineTestFake, LeakyBucketTest) {
EXPECT_NE(first_send_channel, recv_channel_num);
EXPECT_FALSE(vie_.GetTransmissionSmoothingStatus(recv_channel_num));
- // Add a new send stream and verify leaky bucket is enabled from start.
+ // Add a new send stream and verify leaky bucket is disabled from start.
EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(3)));
int second_send_channel = vie_.GetLastChannel();
EXPECT_NE(first_send_channel, second_send_channel);
+ EXPECT_FALSE(vie_.GetTransmissionSmoothingStatus(second_send_channel));
+
+ // Reenable leaky bucket.
+ options.video_leaky_bucket.Set(true);
+ EXPECT_TRUE(channel_->SetOptions(options));
+ EXPECT_TRUE(vie_.GetTransmissionSmoothingStatus(first_send_channel));
EXPECT_TRUE(vie_.GetTransmissionSmoothingStatus(second_send_channel));
}
@@ -1026,12 +1068,12 @@ TEST_F(WebRtcVideoEngineTestFake, AdditiveVideoOptions) {
EXPECT_TRUE(channel_->SetOptions(options1));
EXPECT_EQ(100, vie_.GetSenderTargetDelay(first_send_channel));
EXPECT_EQ(100, vie_.GetReceiverTargetDelay(first_send_channel));
- EXPECT_FALSE(vie_.GetTransmissionSmoothingStatus(first_send_channel));
+ EXPECT_TRUE(vie_.GetTransmissionSmoothingStatus(first_send_channel));
cricket::VideoOptions options2;
- options2.video_leaky_bucket.Set(true);
+ options2.video_leaky_bucket.Set(false);
EXPECT_TRUE(channel_->SetOptions(options2));
- EXPECT_TRUE(vie_.GetTransmissionSmoothingStatus(first_send_channel));
+ EXPECT_FALSE(vie_.GetTransmissionSmoothingStatus(first_send_channel));
// The buffered_mode_latency still takes effect.
EXPECT_EQ(100, vie_.GetSenderTargetDelay(first_send_channel));
EXPECT_EQ(100, vie_.GetReceiverTargetDelay(first_send_channel));
@@ -1041,7 +1083,7 @@ TEST_F(WebRtcVideoEngineTestFake, AdditiveVideoOptions) {
EXPECT_EQ(50, vie_.GetSenderTargetDelay(first_send_channel));
EXPECT_EQ(50, vie_.GetReceiverTargetDelay(first_send_channel));
// The video_leaky_bucket still takes effect.
- EXPECT_TRUE(vie_.GetTransmissionSmoothingStatus(first_send_channel));
+ EXPECT_FALSE(vie_.GetTransmissionSmoothingStatus(first_send_channel));
}
TEST_F(WebRtcVideoEngineTestFake, SetCpuOveruseOptionsWithCaptureJitterMethod) {
@@ -1144,6 +1186,11 @@ TEST_F(WebRtcVideoEngineTestFake, SetCpuOveruseOptionsWithEncodeUsageMethod) {
EXPECT_EQ(20, cpu_option.high_encode_usage_threshold_percent);
EXPECT_FALSE(cpu_option.enable_capture_jitter_method);
EXPECT_TRUE(cpu_option.enable_encode_usage_method);
+#ifdef USE_WEBRTC_DEV_BRANCH
+ // Verify that optional encode rsd thresholds are not set.
+ EXPECT_EQ(-1, cpu_option.low_encode_time_rsd_threshold);
+ EXPECT_EQ(-1, cpu_option.high_encode_time_rsd_threshold);
+#endif
// Add a new send stream and verify that cpu options are set from start.
EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(3)));
@@ -1154,6 +1201,51 @@ TEST_F(WebRtcVideoEngineTestFake, SetCpuOveruseOptionsWithEncodeUsageMethod) {
EXPECT_EQ(20, cpu_option.high_encode_usage_threshold_percent);
EXPECT_FALSE(cpu_option.enable_capture_jitter_method);
EXPECT_TRUE(cpu_option.enable_encode_usage_method);
+#ifdef USE_WEBRTC_DEV_BRANCH
+ // Verify that optional encode rsd thresholds are not set.
+ EXPECT_EQ(-1, cpu_option.low_encode_time_rsd_threshold);
+ EXPECT_EQ(-1, cpu_option.high_encode_time_rsd_threshold);
+#endif
+}
+
+TEST_F(WebRtcVideoEngineTestFake, SetCpuOveruseOptionsWithEncodeRsdThresholds) {
+ EXPECT_TRUE(SetupEngine());
+ EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(1)));
+ int first_send_channel = vie_.GetLastChannel();
+
+ // Set optional encode rsd thresholds and verify cpu options.
+ cricket::VideoOptions options;
+ options.conference_mode.Set(true);
+ options.cpu_underuse_threshold.Set(10);
+ options.cpu_overuse_threshold.Set(20);
+ options.cpu_underuse_encode_rsd_threshold.Set(30);
+ options.cpu_overuse_encode_rsd_threshold.Set(40);
+ options.cpu_overuse_encode_usage.Set(true);
+ EXPECT_TRUE(channel_->SetOptions(options));
+ webrtc::CpuOveruseOptions cpu_option =
+ vie_.GetCpuOveruseOptions(first_send_channel);
+ EXPECT_EQ(10, cpu_option.low_encode_usage_threshold_percent);
+ EXPECT_EQ(20, cpu_option.high_encode_usage_threshold_percent);
+ EXPECT_FALSE(cpu_option.enable_capture_jitter_method);
+ EXPECT_TRUE(cpu_option.enable_encode_usage_method);
+#ifdef USE_WEBRTC_DEV_BRANCH
+ EXPECT_EQ(30, cpu_option.low_encode_time_rsd_threshold);
+ EXPECT_EQ(40, cpu_option.high_encode_time_rsd_threshold);
+#endif
+
+ // Add a new send stream and verify that cpu options are set from start.
+ EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(3)));
+ int second_send_channel = vie_.GetLastChannel();
+ EXPECT_NE(first_send_channel, second_send_channel);
+ cpu_option = vie_.GetCpuOveruseOptions(second_send_channel);
+ EXPECT_EQ(10, cpu_option.low_encode_usage_threshold_percent);
+ EXPECT_EQ(20, cpu_option.high_encode_usage_threshold_percent);
+ EXPECT_FALSE(cpu_option.enable_capture_jitter_method);
+ EXPECT_TRUE(cpu_option.enable_encode_usage_method);
+#ifdef USE_WEBRTC_DEV_BRANCH
+ EXPECT_EQ(30, cpu_option.low_encode_time_rsd_threshold);
+ EXPECT_EQ(40, cpu_option.high_encode_time_rsd_threshold);
+#endif
}
// Test that AddRecvStream doesn't create new channel for 1:1 call.
@@ -2235,13 +2327,19 @@ TEST_F(WebRtcVideoMediaChannelTest, DISABLED_SendVp8HdAndReceiveAdaptedVp8Vga) {
EXPECT_FRAME_WAIT(1, codec.width, codec.height, kTimeout);
}
-// TODO(juberti): Fix this test to tolerate missing stats.
+#ifdef USE_WEBRTC_DEV_BRANCH
+TEST_F(WebRtcVideoMediaChannelTest, GetStats) {
+#else
TEST_F(WebRtcVideoMediaChannelTest, DISABLED_GetStats) {
+#endif
Base::GetStats();
}
-// TODO(juberti): Fix this test to tolerate missing stats.
+#ifdef USE_WEBRTC_DEV_BRANCH
+TEST_F(WebRtcVideoMediaChannelTest, GetStatsMultipleRecvStreams) {
+#else
TEST_F(WebRtcVideoMediaChannelTest, DISABLED_GetStatsMultipleRecvStreams) {
+#endif
Base::GetStatsMultipleRecvStreams();
}
diff --git a/media/webrtc/webrtcvoiceengine.cc b/media/webrtc/webrtcvoiceengine.cc
index 1bd2ffe..785cdf1 100644
--- a/media/webrtc/webrtcvoiceengine.cc
+++ b/media/webrtc/webrtcvoiceengine.cc
@@ -426,6 +426,16 @@ static int GetOpusBitrateFromParams(const AudioCodec& codec) {
return bitrate;
}
+// True if params["useinbandfec"] == "1"
+static bool IsOpusFecEnabled(const AudioCodec& codec) {
+ CodecParameterMap::const_iterator param =
+ codec.params.find(kCodecParamUseInbandFec);
+ if (param == codec.params.end())
+ return false;
+
+ return param->second == kParamValueTrue;
+}
+
void WebRtcVoiceEngine::ConstructCodecs() {
LOG(LS_INFO) << "WebRtc VoiceEngine codecs:";
int ncodecs = voe_wrapper_->codec()->NumOfCodecs();
@@ -1943,10 +1953,16 @@ bool WebRtcVoiceMediaChannel::SetRecvCodecs(
bool WebRtcVoiceMediaChannel::SetSendCodecs(
int channel, const std::vector<AudioCodec>& codecs) {
- // Disable VAD, and FEC unless we know the other side wants them.
+ // Disable VAD, FEC, and RED unless we know the other side wants them.
engine()->voe()->codec()->SetVADStatus(channel, false);
engine()->voe()->rtp()->SetNACKStatus(channel, false, 0);
+#ifdef USE_WEBRTC_DEV_BRANCH
+ engine()->voe()->rtp()->SetREDStatus(channel, false);
+ engine()->voe()->codec()->SetFECStatus(channel, false);
+#else
+ // TODO(minyue): Remove code under #else case after new WebRTC roll.
engine()->voe()->rtp()->SetFECStatus(channel, false);
+#endif // USE_WEBRTC_DEV_BRANCH
// Scan through the list to figure out the codec to use for sending, along
// with the proper configuration for VAD and DTMF.
@@ -2005,11 +2021,24 @@ bool WebRtcVoiceMediaChannel::SetSendCodecs(
if (bitrate_from_params != 0) {
voe_codec.rate = bitrate_from_params;
}
+
+ // If FEC is enabled.
+ if (IsOpusFecEnabled(*it)) {
+ LOG(LS_INFO) << "Enabling Opus FEC on channel " << channel;
+#ifdef USE_WEBRTC_DEV_BRANCH
+ if (engine()->voe()->codec()->SetFECStatus(channel, true) == -1) {
+ // Enable in-band FEC of the Opus codec. Treat any failure as a fatal
+ // internal error.
+ LOG_RTCERR2(SetFECStatus, channel, true);
+ return false;
+ }
+#endif // USE_WEBRTC_DEV_BRANCH
+ }
}
// We'll use the first codec in the list to actually send audio data.
// Be sure to use the payload type requested by the remote side.
- // "red", for FEC audio, is a special case where the actual codec to be
+ // "red", for RED audio, is a special case where the actual codec to be
// used is specified in params.
if (IsRedCodec(it->name)) {
// Parse out the RED parameters. If we fail, just ignore RED;
@@ -2020,9 +2049,16 @@ bool WebRtcVoiceMediaChannel::SetSendCodecs(
// Enable redundant encoding of the specified codec. Treat any
// failure as a fatal internal error.
+#ifdef USE_WEBRTC_DEV_BRANCH
+ LOG(LS_INFO) << "Enabling RED on channel " << channel;
+ if (engine()->voe()->rtp()->SetREDStatus(channel, true, it->id) == -1) {
+ LOG_RTCERR3(SetREDStatus, channel, true, it->id);
+#else
+ // TODO(minyue): Remove code under #else case after new WebRTC roll.
LOG(LS_INFO) << "Enabling FEC";
if (engine()->voe()->rtp()->SetFECStatus(channel, true, it->id) == -1) {
LOG_RTCERR3(SetFECStatus, channel, true, it->id);
+#endif // USE_WEBRTC_DEV_BRANCH
return false;
}
} else {
@@ -3270,6 +3306,9 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) {
#ifdef USE_WEBRTC_DEV_BRANCH
rinfo.capture_start_ntp_time_ms = cs.capture_start_ntp_time_ms_;
#endif
+ if (codec.pltype != -1) {
+ rinfo.codec_name = codec.plname;
+ }
// Convert samples to milliseconds.
if (codec.plfreq / 1000 > 0) {
rinfo.jitter_ms = cs.jitterSamples / (codec.plfreq / 1000);
diff --git a/media/webrtc/webrtcvoiceengine_unittest.cc b/media/webrtc/webrtcvoiceengine_unittest.cc
index cbc0007..80a50c5 100644
--- a/media/webrtc/webrtcvoiceengine_unittest.cc
+++ b/media/webrtc/webrtcvoiceengine_unittest.cc
@@ -745,7 +745,7 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecs) {
EXPECT_EQ(48000, gcodec.rate);
EXPECT_STREQ("ISAC", gcodec.plname);
EXPECT_FALSE(voe_.GetVAD(channel_num));
- EXPECT_FALSE(voe_.GetFEC(channel_num));
+ EXPECT_FALSE(voe_.GetRED(channel_num));
EXPECT_EQ(13, voe_.GetSendCNPayloadType(channel_num, false));
EXPECT_EQ(105, voe_.GetSendCNPayloadType(channel_num, true));
EXPECT_EQ(106, voe_.GetSendTelephoneEventPayloadType(channel_num));
@@ -1144,6 +1144,81 @@ TEST_F(WebRtcVoiceEngineTestFake, AddRecvStreamEnableNack) {
EXPECT_TRUE(voe_.GetNACK(channel_num));
}
+#ifdef USE_WEBRTC_DEV_BRANCH
+// Test that without useinbandfec, Opus FEC is off.
+TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecNoOpusFEC) {
+ EXPECT_TRUE(SetupEngine());
+ int channel_num = voe_.GetLastChannel();
+ std::vector<cricket::AudioCodec> codecs;
+ codecs.push_back(kOpusCodec);
+ codecs[0].bitrate = 0;
+ EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+ EXPECT_FALSE(voe_.GetCodecFEC(channel_num));
+}
+
+// Test that with useinbandfec=0, Opus FEC is off.
+TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecOpusDisableFEC) {
+ EXPECT_TRUE(SetupEngine());
+ int channel_num = voe_.GetLastChannel();
+ std::vector<cricket::AudioCodec> codecs;
+ codecs.push_back(kOpusCodec);
+ codecs[0].bitrate = 0;
+ codecs[0].params["useinbandfec"] = "0";
+ EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+ EXPECT_FALSE(voe_.GetCodecFEC(channel_num));
+ webrtc::CodecInst gcodec;
+ EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
+ EXPECT_STREQ("opus", gcodec.plname);
+ EXPECT_EQ(1, gcodec.channels);
+ EXPECT_EQ(32000, gcodec.rate);
+}
+
+// Test that with useinbandfec=1, Opus FEC is on.
+TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecOpusEnableFEC) {
+ EXPECT_TRUE(SetupEngine());
+ int channel_num = voe_.GetLastChannel();
+ std::vector<cricket::AudioCodec> codecs;
+ codecs.push_back(kOpusCodec);
+ codecs[0].bitrate = 0;
+ codecs[0].params["useinbandfec"] = "1";
+ EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+ EXPECT_TRUE(voe_.GetCodecFEC(channel_num));
+ webrtc::CodecInst gcodec;
+ EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
+ EXPECT_STREQ("opus", gcodec.plname);
+ EXPECT_EQ(1, gcodec.channels);
+ EXPECT_EQ(32000, gcodec.rate);
+}
+
+// Test that with useinbandfec=1, stereo=1, Opus FEC is on.
+TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecOpusEnableFECStereo) {
+ EXPECT_TRUE(SetupEngine());
+ int channel_num = voe_.GetLastChannel();
+ std::vector<cricket::AudioCodec> codecs;
+ codecs.push_back(kOpusCodec);
+ codecs[0].bitrate = 0;
+ codecs[0].params["stereo"] = "1";
+ codecs[0].params["useinbandfec"] = "1";
+ EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+ EXPECT_TRUE(voe_.GetCodecFEC(channel_num));
+ webrtc::CodecInst gcodec;
+ EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
+ EXPECT_STREQ("opus", gcodec.plname);
+ EXPECT_EQ(2, gcodec.channels);
+ EXPECT_EQ(64000, gcodec.rate);
+}
+
+// Test that with non-Opus, codec FEC is off.
+TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecIsacNoFEC) {
+ EXPECT_TRUE(SetupEngine());
+ int channel_num = voe_.GetLastChannel();
+ std::vector<cricket::AudioCodec> codecs;
+ codecs.push_back(kIsacCodec);
+ EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+ EXPECT_FALSE(voe_.GetCodecFEC(channel_num));
+}
+#endif // USE_WEBRTC_DEV_BRANCH
+
// Test that we can apply CELT with stereo mode but fail with mono mode.
TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsCelt) {
EXPECT_TRUE(SetupEngine());
@@ -1315,7 +1390,7 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsCNandDTMFAsCaller) {
EXPECT_EQ(96, gcodec.pltype);
EXPECT_STREQ("ISAC", gcodec.plname);
EXPECT_TRUE(voe_.GetVAD(channel_num));
- EXPECT_FALSE(voe_.GetFEC(channel_num));
+ EXPECT_FALSE(voe_.GetRED(channel_num));
EXPECT_EQ(13, voe_.GetSendCNPayloadType(channel_num, false));
EXPECT_EQ(97, voe_.GetSendCNPayloadType(channel_num, true));
EXPECT_EQ(98, voe_.GetSendTelephoneEventPayloadType(channel_num));
@@ -1348,7 +1423,7 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsCNandDTMFAsCallee) {
EXPECT_EQ(96, gcodec.pltype);
EXPECT_STREQ("ISAC", gcodec.plname);
EXPECT_TRUE(voe_.GetVAD(channel_num));
- EXPECT_FALSE(voe_.GetFEC(channel_num));
+ EXPECT_FALSE(voe_.GetRED(channel_num));
EXPECT_EQ(13, voe_.GetSendCNPayloadType(channel_num, false));
EXPECT_EQ(97, voe_.GetSendCNPayloadType(channel_num, true));
EXPECT_EQ(98, voe_.GetSendTelephoneEventPayloadType(channel_num));
@@ -1412,13 +1487,13 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsCaseInsensitive) {
EXPECT_EQ(96, gcodec.pltype);
EXPECT_STREQ("ISAC", gcodec.plname);
EXPECT_TRUE(voe_.GetVAD(channel_num));
- EXPECT_FALSE(voe_.GetFEC(channel_num));
+ EXPECT_FALSE(voe_.GetRED(channel_num));
EXPECT_EQ(13, voe_.GetSendCNPayloadType(channel_num, false));
EXPECT_EQ(97, voe_.GetSendCNPayloadType(channel_num, true));
EXPECT_EQ(98, voe_.GetSendTelephoneEventPayloadType(channel_num));
}
-// Test that we set up FEC correctly as caller.
+// Test that we set up RED correctly as caller.
TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsREDAsCaller) {
EXPECT_TRUE(SetupEngine());
int channel_num = voe_.GetLastChannel();
@@ -1434,11 +1509,11 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsREDAsCaller) {
EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
EXPECT_EQ(96, gcodec.pltype);
EXPECT_STREQ("ISAC", gcodec.plname);
- EXPECT_TRUE(voe_.GetFEC(channel_num));
- EXPECT_EQ(127, voe_.GetSendFECPayloadType(channel_num));
+ EXPECT_TRUE(voe_.GetRED(channel_num));
+ EXPECT_EQ(127, voe_.GetSendREDPayloadType(channel_num));
}
-// Test that we set up FEC correctly as callee.
+// Test that we set up RED correctly as callee.
TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsREDAsCallee) {
EXPECT_TRUE(engine_.Init(talk_base::Thread::Current()));
channel_ = engine_.CreateChannel();
@@ -1459,11 +1534,11 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsREDAsCallee) {
EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
EXPECT_EQ(96, gcodec.pltype);
EXPECT_STREQ("ISAC", gcodec.plname);
- EXPECT_TRUE(voe_.GetFEC(channel_num));
- EXPECT_EQ(127, voe_.GetSendFECPayloadType(channel_num));
+ EXPECT_TRUE(voe_.GetRED(channel_num));
+ EXPECT_EQ(127, voe_.GetSendREDPayloadType(channel_num));
}
-// Test that we set up FEC correctly if params are omitted.
+// Test that we set up RED correctly if params are omitted.
TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsREDNoParams) {
EXPECT_TRUE(SetupEngine());
int channel_num = voe_.GetLastChannel();
@@ -1478,8 +1553,8 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsREDNoParams) {
EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
EXPECT_EQ(96, gcodec.pltype);
EXPECT_STREQ("ISAC", gcodec.plname);
- EXPECT_TRUE(voe_.GetFEC(channel_num));
- EXPECT_EQ(127, voe_.GetSendFECPayloadType(channel_num));
+ EXPECT_TRUE(voe_.GetRED(channel_num));
+ EXPECT_EQ(127, voe_.GetSendREDPayloadType(channel_num));
}
// Test that we ignore RED if the parameters aren't named the way we expect.
@@ -1498,7 +1573,7 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsBadRED1) {
EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
EXPECT_EQ(96, gcodec.pltype);
EXPECT_STREQ("ISAC", gcodec.plname);
- EXPECT_FALSE(voe_.GetFEC(channel_num));
+ EXPECT_FALSE(voe_.GetRED(channel_num));
}
// Test that we ignore RED if it uses different primary/secondary encoding.
@@ -1517,7 +1592,7 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsBadRED2) {
EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
EXPECT_EQ(96, gcodec.pltype);
EXPECT_STREQ("ISAC", gcodec.plname);
- EXPECT_FALSE(voe_.GetFEC(channel_num));
+ EXPECT_FALSE(voe_.GetRED(channel_num));
}
// Test that we ignore RED if it uses more than 2 encodings.
@@ -1536,7 +1611,7 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsBadRED3) {
EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
EXPECT_EQ(96, gcodec.pltype);
EXPECT_STREQ("ISAC", gcodec.plname);
- EXPECT_FALSE(voe_.GetFEC(channel_num));
+ EXPECT_FALSE(voe_.GetRED(channel_num));
}
// Test that we ignore RED if it has bogus codec ids.
@@ -1555,7 +1630,7 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsBadRED4) {
EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
EXPECT_EQ(96, gcodec.pltype);
EXPECT_STREQ("ISAC", gcodec.plname);
- EXPECT_FALSE(voe_.GetFEC(channel_num));
+ EXPECT_FALSE(voe_.GetRED(channel_num));
}
// Test that we ignore RED if it refers to a codec that is not present.
@@ -1574,7 +1649,7 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendCodecsBadRED5) {
EXPECT_EQ(0, voe_.GetSendCodec(channel_num, gcodec));
EXPECT_EQ(96, gcodec.pltype);
EXPECT_STREQ("ISAC", gcodec.plname);
- EXPECT_FALSE(voe_.GetFEC(channel_num));
+ EXPECT_FALSE(voe_.GetRED(channel_num));
}
// Test support for audio level header extension.
@@ -1726,11 +1801,15 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStatsWithMultipleSendStreams) {
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(kSsrcs4[i])));
}
-
+ // Create a receive stream to check that none of the send streams end up in
+ // the receive stream stats.
+ EXPECT_TRUE(channel_->AddRecvStream(
+ cricket::StreamParams::CreateLegacy(kSsrc2)));
// We need send codec to be set to get all stats.
std::vector<cricket::AudioCodec> codecs;
codecs.push_back(kPcmuCodec);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+ EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
cricket::VoiceMediaInfo info;
EXPECT_EQ(true, channel_->GetStats(&info));
@@ -1747,9 +1826,19 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStatsWithMultipleSendStreams) {
EXPECT_EQ(cricket::kIntStatValue, info.senders[i].ext_seqnum);
EXPECT_EQ(cricket::kIntStatValue, info.senders[i].rtt_ms);
EXPECT_EQ(cricket::kIntStatValue, info.senders[i].jitter_ms);
+ EXPECT_EQ(kPcmuCodec.name, info.senders[i].codec_name);
}
+ EXPECT_EQ(0u, info.receivers.size());
+ DeliverPacket(kPcmuFrame, sizeof(kPcmuFrame));
+ EXPECT_EQ(true, channel_->GetStats(&info));
+
EXPECT_EQ(1u, info.receivers.size());
+ EXPECT_EQ(cricket::kIntStatValue, info.receivers[0].bytes_rcvd);
+ EXPECT_EQ(cricket::kIntStatValue, info.receivers[0].packets_rcvd);
+ EXPECT_EQ(cricket::kIntStatValue, info.receivers[0].packets_lost);
+ EXPECT_EQ(cricket::kIntStatValue, info.receivers[0].ext_seqnum);
+ EXPECT_EQ(kPcmuCodec.name, info.receivers[0].codec_name);
}
// Test that we can add and remove receive streams, and do proper send/playout.
@@ -2036,9 +2125,14 @@ TEST_F(WebRtcVoiceEngineTestFake, SetSendSsrc) {
TEST_F(WebRtcVoiceEngineTestFake, GetStats) {
// Setup. We need send codec to be set to get all stats.
EXPECT_TRUE(SetupEngine());
+ // SetupEngine adds a send stream with kSsrc1, so the receive stream has to
+ // use a different SSRC.
+ EXPECT_TRUE(channel_->AddRecvStream(
+ cricket::StreamParams::CreateLegacy(kSsrc2)));
std::vector<cricket::AudioCodec> codecs;
codecs.push_back(kPcmuCodec);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
+ EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
cricket::VoiceMediaInfo info;
EXPECT_EQ(true, channel_->GetStats(&info));
@@ -2052,6 +2146,7 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStats) {
EXPECT_EQ(cricket::kIntStatValue, info.senders[0].ext_seqnum);
EXPECT_EQ(cricket::kIntStatValue, info.senders[0].rtt_ms);
EXPECT_EQ(cricket::kIntStatValue, info.senders[0].jitter_ms);
+ EXPECT_EQ(kPcmuCodec.name, info.senders[0].codec_name);
// TODO(sriniv): Add testing for more fields. These are not populated
// in FakeWebrtcVoiceEngine yet.
// EXPECT_EQ(cricket::kIntStatValue, info.senders[0].audio_level);
@@ -2061,8 +2156,17 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStats) {
// EXPECT_EQ(cricket::kIntStatValue,
// info.senders[0].echo_return_loss_enhancement);
+ EXPECT_EQ(0u, info.receivers.size());
+ DeliverPacket(kPcmuFrame, sizeof(kPcmuFrame));
+ EXPECT_EQ(true, channel_->GetStats(&info));
EXPECT_EQ(1u, info.receivers.size());
- // TODO(sriniv): Add testing for receiver fields.
+
+ EXPECT_EQ(cricket::kIntStatValue, info.receivers[0].bytes_rcvd);
+ EXPECT_EQ(cricket::kIntStatValue, info.receivers[0].packets_rcvd);
+ EXPECT_EQ(cricket::kIntStatValue, info.receivers[0].packets_lost);
+ EXPECT_EQ(cricket::kIntStatValue, info.receivers[0].ext_seqnum);
+ EXPECT_EQ(kPcmuCodec.name, info.receivers[0].codec_name);
+ // TODO(sriniv): Add testing for more receiver fields.
}
// Test that we can set the outgoing SSRC properly with multiple streams.