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:
		| @@ -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', | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 minyue@webrtc.org
					minyue@webrtc.org