Since the packet loss rate cannot be estimated accurately, there is always a mismatch between the estimated packet loss rate and the true one. Such a mismatch will make Opus FEC suboptimal.
It is advisable to set the packet loss rate of FEC conservatively. Say, if the estimated loss rate is 5%, we can set it to 1%. The risk of degradation in quality is small and the overall performance is good. BUG= R=henrik.lundin@webrtc.org, turaj@webrtc.org Review URL: https://webrtc-codereview.appspot.com/16979004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@6844 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
ea25784107
commit
1d956dd1a7
@ -15,6 +15,8 @@
|
||||
#include "webrtc/modules/audio_coding/main/acm2/acm_codec_database.h"
|
||||
#include "webrtc/modules/audio_coding/main/acm2/acm_common_defs.h"
|
||||
#include "webrtc/system_wrappers/interface/trace.h"
|
||||
|
||||
#define SIGN(x) (x > 0 ? 1 : -1)
|
||||
#endif
|
||||
|
||||
namespace webrtc {
|
||||
@ -27,7 +29,9 @@ ACMOpus::ACMOpus(int16_t /* codec_id */)
|
||||
: encoder_inst_ptr_(NULL),
|
||||
sample_freq_(0),
|
||||
bitrate_(0),
|
||||
channels_(1) {
|
||||
channels_(1),
|
||||
fec_enabled_(false),
|
||||
packet_loss_rate_(0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -70,7 +74,9 @@ ACMOpus::ACMOpus(int16_t codec_id)
|
||||
: encoder_inst_ptr_(NULL),
|
||||
sample_freq_(32000), // Default sampling frequency.
|
||||
bitrate_(20000), // Default bit-rate.
|
||||
channels_(1) { // Default mono
|
||||
channels_(1), // Default mono.
|
||||
fec_enabled_(false), // Default FEC is off.
|
||||
packet_loss_rate_(0) {
|
||||
codec_id_ = codec_id;
|
||||
// Opus has internal DTX, but we dont use it for now.
|
||||
has_internal_dtx_ = false;
|
||||
@ -188,6 +194,7 @@ int16_t ACMOpus::SetBitRateSafe(const int32_t rate) {
|
||||
"SetBitRateSafe: Invalid rate Opus");
|
||||
return -1;
|
||||
}
|
||||
// Initial packet loss rate.
|
||||
|
||||
bitrate_ = rate;
|
||||
|
||||
@ -217,11 +224,40 @@ int ACMOpus::SetFEC(bool enable_fec) {
|
||||
}
|
||||
|
||||
int ACMOpus::SetPacketLossRate(int loss_rate) {
|
||||
// Ask the encoder to change the target packet loss rate.
|
||||
if (WebRtcOpus_SetPacketLossRate(encoder_inst_ptr_, loss_rate) == 0) {
|
||||
packet_loss_rate_ = loss_rate;
|
||||
// Optimize the loss rate to configure Opus. Basically, optimized loss rate is
|
||||
// the input loss rate rounded down to various levels, because a robustly good
|
||||
// audio quality is achieved by lowering the packet loss lower down.
|
||||
// Additionally, to prevent toggling, margins are used, i.e., when jumping to
|
||||
// a loss rate from below, a higher threshold is used than jumping to the same
|
||||
// level from above.
|
||||
const int kPacketLossRateHigh = 20;
|
||||
const int kPacketLossRateMedium = 10;
|
||||
const int kPacketLossRateLow = 1;
|
||||
const int kLossRateHighMargin = 2;
|
||||
const int kLossRateMediumMargin = 1;
|
||||
int opt_loss_rate;
|
||||
if (loss_rate >= kPacketLossRateHigh + kLossRateHighMargin *
|
||||
SIGN(kPacketLossRateHigh - packet_loss_rate_)) {
|
||||
opt_loss_rate = kPacketLossRateHigh;
|
||||
} else if (loss_rate >= kPacketLossRateMedium + kLossRateMediumMargin *
|
||||
SIGN(kPacketLossRateMedium - packet_loss_rate_)) {
|
||||
opt_loss_rate = kPacketLossRateMedium;
|
||||
} else if (loss_rate >= kPacketLossRateLow) {
|
||||
opt_loss_rate = kPacketLossRateLow;
|
||||
} else {
|
||||
opt_loss_rate = 0;
|
||||
}
|
||||
|
||||
if (packet_loss_rate_ == opt_loss_rate) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Ask the encoder to change the target packet loss rate.
|
||||
if (WebRtcOpus_SetPacketLossRate(encoder_inst_ptr_, opt_loss_rate) == 0) {
|
||||
packet_loss_rate_ = opt_loss_rate;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
86
webrtc/modules/audio_coding/main/acm2/acm_opus_unittest.cc
Normal file
86
webrtc/modules/audio_coding/main/acm2/acm_opus_unittest.cc
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/modules/audio_coding/main/acm2/acm_opus.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "webrtc/modules/audio_coding/main/acm2/acm_codec_database.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace acm2 {
|
||||
|
||||
namespace {
|
||||
const CodecInst kOpusCodecInst = {105, "opus", 48000, 960, 1, 32000};
|
||||
// These constants correspond to those used in ACMOpus::SetPacketLossRate().
|
||||
const int kPacketLossRateHigh = 20;
|
||||
const int kPacketLossRateMedium = 10;
|
||||
const int kPacketLossRateLow = 1;
|
||||
const int kLossRateHighMargin = 2;
|
||||
const int kLossRateMediumMargin = 1;
|
||||
} // namespace
|
||||
|
||||
class AcmOpusTest : public ACMOpus {
|
||||
public:
|
||||
explicit AcmOpusTest(int16_t codec_id)
|
||||
: ACMOpus(codec_id) {}
|
||||
~AcmOpusTest() {}
|
||||
int packet_loss_rate() { return packet_loss_rate_; }
|
||||
|
||||
void TestSetPacketLossRate(int from, int to, int expected_return);
|
||||
};
|
||||
|
||||
#ifdef WEBRTC_CODEC_OPUS
|
||||
void AcmOpusTest::TestSetPacketLossRate(int from, int to, int expected_return) {
|
||||
for (int loss = from; loss <= to; (to >= from) ? ++loss : --loss) {
|
||||
EXPECT_EQ(0, SetPacketLossRate(loss));
|
||||
EXPECT_EQ(expected_return, packet_loss_rate());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AcmOpusTest, PacketLossRateOptimized) {
|
||||
AcmOpusTest opus(ACMCodecDB::kOpus);
|
||||
WebRtcACMCodecParams params;
|
||||
memcpy(&(params.codec_inst), &kOpusCodecInst, sizeof(CodecInst));
|
||||
EXPECT_EQ(0, opus.InitEncoder(¶ms, true));
|
||||
EXPECT_EQ(0, opus.SetFEC(true));
|
||||
|
||||
// Note that the order of the following calls is critical.
|
||||
opus.TestSetPacketLossRate(0, 0, 0);
|
||||
opus.TestSetPacketLossRate(kPacketLossRateLow,
|
||||
kPacketLossRateMedium + kLossRateMediumMargin - 1,
|
||||
kPacketLossRateLow);
|
||||
opus.TestSetPacketLossRate(kPacketLossRateMedium + kLossRateMediumMargin,
|
||||
kPacketLossRateHigh + kLossRateHighMargin - 1,
|
||||
kPacketLossRateMedium);
|
||||
opus.TestSetPacketLossRate(kPacketLossRateHigh + kLossRateHighMargin,
|
||||
100,
|
||||
kPacketLossRateHigh);
|
||||
opus.TestSetPacketLossRate(kPacketLossRateHigh + kLossRateHighMargin,
|
||||
kPacketLossRateHigh - kLossRateHighMargin,
|
||||
kPacketLossRateHigh);
|
||||
opus.TestSetPacketLossRate(kPacketLossRateHigh - kLossRateHighMargin - 1,
|
||||
kPacketLossRateMedium - kLossRateMediumMargin,
|
||||
kPacketLossRateMedium);
|
||||
opus.TestSetPacketLossRate(kPacketLossRateMedium - kLossRateMediumMargin - 1,
|
||||
kPacketLossRateLow,
|
||||
kPacketLossRateLow);
|
||||
opus.TestSetPacketLossRate(0, 0, 0);
|
||||
}
|
||||
#else
|
||||
void AcmOpusTest:TestSetPacketLossRate(int /* from */, int /* to */,
|
||||
int /* expected_return */) {
|
||||
return;
|
||||
}
|
||||
#endif // WEBRTC_CODEC_OPUS
|
||||
|
||||
} // namespace acm2
|
||||
|
||||
} // namespace webrtc
|
@ -101,6 +101,7 @@
|
||||
'<(webrtc_root)/test/test.gyp:rtcp_packet_parser',
|
||||
],
|
||||
'sources': [
|
||||
'audio_coding/main/acm2/acm_opus_unittest.cc',
|
||||
'audio_coding/main/acm2/acm_receiver_unittest.cc',
|
||||
'audio_coding/main/acm2/audio_coding_module_unittest.cc',
|
||||
'audio_coding/main/acm2/call_statistics_unittest.cc',
|
||||
|
Loading…
Reference in New Issue
Block a user