Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / webrtc / modules / audio_coding / codecs / opus / opus_fec_test.cc
1 /*
2  *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10
11 #include "testing/gtest/include/gtest/gtest.h"
12 #include "webrtc/modules/audio_coding/codecs/opus/interface/opus_interface.h"
13 #include "webrtc/test/testsupport/fileutils.h"
14 #include "webrtc/system_wrappers/interface/scoped_ptr.h"
15
16 using ::std::string;
17 using ::std::tr1::tuple;
18 using ::std::tr1::make_tuple;
19 using ::std::tr1::get;
20 using ::testing::TestWithParam;
21 using ::testing::ValuesIn;
22
23 namespace webrtc {
24
25 // Define coding parameter as <channels, bit_rate, filename, extension>.
26 typedef tuple<int, int, string, string> coding_param;
27 typedef struct mode mode;
28
29 struct mode {
30   bool fec;
31   uint8_t target_packet_loss_rate;
32 };
33
34 const int kOpusBlockDurationMs = 20;
35 const int kOpusSamplingKhz = 48;
36
37 class OpusFecTest : public TestWithParam<coding_param> {
38  protected:
39   OpusFecTest();
40
41   virtual void SetUp();
42   virtual void TearDown();
43
44   virtual void EncodeABlock();
45
46   virtual void DecodeABlock(bool lost_previous, bool lost_current);
47
48   int block_duration_ms_;
49   int sampling_khz_;
50   int block_length_sample_;
51
52   int channels_;
53   int bit_rate_;
54
55   size_t data_pointer_;
56   size_t loop_length_samples_;
57   int max_bytes_;
58   int encoded_bytes_;
59
60   WebRtcOpusEncInst* opus_encoder_;
61   WebRtcOpusDecInst* opus_decoder_;
62
63   string in_filename_;
64
65   scoped_ptr<int16_t[]> in_data_;
66   scoped_ptr<int16_t[]> out_data_;
67   scoped_ptr<uint8_t[]> bit_stream_;
68 };
69
70 void OpusFecTest::SetUp() {
71   channels_ = get<0>(GetParam());
72   bit_rate_ = get<1>(GetParam());
73   printf("Coding %d channel signal at %d bps.\n", channels_, bit_rate_);
74
75   in_filename_ = test::ResourcePath(get<2>(GetParam()), get<3>(GetParam()));
76
77   FILE* fp = fopen(in_filename_.c_str(), "rb");
78   ASSERT_FALSE(fp == NULL);
79
80   // Obtain file size.
81   fseek(fp, 0, SEEK_END);
82   loop_length_samples_ = ftell(fp) / sizeof(int16_t);
83   rewind(fp);
84
85   // Allocate memory to contain the whole file.
86   in_data_.reset(new int16_t[loop_length_samples_ +
87       block_length_sample_ * channels_]);
88
89   // Copy the file into the buffer.
90   ASSERT_EQ(fread(&in_data_[0], sizeof(int16_t), loop_length_samples_, fp),
91             loop_length_samples_);
92   fclose(fp);
93
94   // The audio will be used in a looped manner. To ease the acquisition of an
95   // audio frame that crosses the end of the excerpt, we add an extra block
96   // length of samples to the end of the array, starting over again from the
97   // beginning of the array. Audio frames cross the end of the excerpt always
98   // appear as a continuum of memory.
99   memcpy(&in_data_[loop_length_samples_], &in_data_[0],
100          block_length_sample_ * channels_ * sizeof(int16_t));
101
102   // Maximum number of bytes in output bitstream.
103   max_bytes_ = block_length_sample_ * channels_ * sizeof(int16_t);
104
105   out_data_.reset(new int16_t[2 * block_length_sample_ * channels_]);
106   bit_stream_.reset(new uint8_t[max_bytes_]);
107
108   // Create encoder memory.
109   EXPECT_EQ(0, WebRtcOpus_EncoderCreate(&opus_encoder_, channels_));
110   EXPECT_EQ(0, WebRtcOpus_DecoderCreate(&opus_decoder_, channels_));
111   // Set bitrate.
112   EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_encoder_, bit_rate_));
113 }
114
115 void OpusFecTest::TearDown() {
116   // Free memory.
117   EXPECT_EQ(0, WebRtcOpus_EncoderFree(opus_encoder_));
118   EXPECT_EQ(0, WebRtcOpus_DecoderFree(opus_decoder_));
119 }
120
121 OpusFecTest::OpusFecTest()
122     : block_duration_ms_(kOpusBlockDurationMs),
123       sampling_khz_(kOpusSamplingKhz),
124       block_length_sample_(block_duration_ms_ * sampling_khz_),
125       data_pointer_(0),
126       max_bytes_(0),
127       encoded_bytes_(0),
128       opus_encoder_(NULL),
129       opus_decoder_(NULL) {
130 }
131
132 void OpusFecTest::EncodeABlock() {
133   int16_t value = WebRtcOpus_Encode(opus_encoder_,
134                                     &in_data_[data_pointer_],
135                                     block_length_sample_,
136                                     max_bytes_, &bit_stream_[0]);
137   EXPECT_GT(value, 0);
138
139   encoded_bytes_ = value;
140 }
141
142 void OpusFecTest::DecodeABlock(bool lost_previous, bool lost_current) {
143   int16_t audio_type;
144   int16_t value_1 = 0, value_2 = 0;
145
146   if (lost_previous) {
147     // Decode previous frame.
148     if (!lost_current &&
149         WebRtcOpus_PacketHasFec(&bit_stream_[0], encoded_bytes_) == 1) {
150       value_1 = WebRtcOpus_DecodeFec(opus_decoder_, &bit_stream_[0],
151                                      encoded_bytes_, &out_data_[0],
152                                      &audio_type);
153     } else {
154       value_1 = WebRtcOpus_DecodePlc(opus_decoder_, &out_data_[0], 1);
155     }
156     EXPECT_EQ(block_length_sample_, value_1);
157   }
158
159   if (!lost_current) {
160     // Decode current frame.
161     value_2 = WebRtcOpus_DecodeNew(opus_decoder_, &bit_stream_[0],
162                                    encoded_bytes_,
163                                    &out_data_[value_1 * channels_],
164                                    &audio_type);
165     EXPECT_EQ(block_length_sample_, value_2);
166   }
167 }
168
169 TEST_P(OpusFecTest, RandomPacketLossTest) {
170   const int kDurationMs = 200000;
171   int time_now_ms, fec_frames;
172   int actual_packet_loss_rate;
173   bool lost_current, lost_previous;
174   mode mode_set[3] = {{true, 0},
175                       {false, 0},
176                       {true, 50}};
177
178   lost_current = false;
179   for (int i = 0; i < 3; i++) {
180     if (mode_set[i].fec) {
181       EXPECT_EQ(0, WebRtcOpus_EnableFec(opus_encoder_));
182       EXPECT_EQ(0, WebRtcOpus_SetPacketLossRate(opus_encoder_,
183           mode_set[i].target_packet_loss_rate));
184       printf("FEC is ON, target at packet loss rate %d percent.\n",
185              mode_set[i].target_packet_loss_rate);
186     } else {
187       EXPECT_EQ(0, WebRtcOpus_DisableFec(opus_encoder_));
188       printf("FEC is OFF.\n");
189     }
190     // In this test, we let the target packet loss rate match the actual rate.
191     actual_packet_loss_rate = mode_set[i].target_packet_loss_rate;
192     // Run every mode a certain time.
193     time_now_ms = 0;
194     fec_frames = 0;
195     while (time_now_ms < kDurationMs) {
196       // Encode & decode.
197       EncodeABlock();
198
199       // Check if payload has FEC.
200       int16_t fec = WebRtcOpus_PacketHasFec(&bit_stream_[0], encoded_bytes_);
201
202       // If FEC is disabled or the target packet loss rate is set to 0, there
203       // should be no FEC in the bit stream.
204       if (!mode_set[i].fec || mode_set[i].target_packet_loss_rate == 0) {
205         EXPECT_EQ(fec, 0);
206       } else if (fec == 1) {
207         fec_frames++;
208       }
209
210       lost_previous = lost_current;
211       lost_current = rand() < actual_packet_loss_rate * (RAND_MAX / 100);
212       DecodeABlock(lost_previous, lost_current);
213
214       time_now_ms += block_duration_ms_;
215
216       // |data_pointer_| is incremented and wrapped across
217       // |loop_length_samples_|.
218       data_pointer_ = (data_pointer_ + block_length_sample_ * channels_) %
219         loop_length_samples_;
220     }
221     if (mode_set[i].fec) {
222       printf("%.2f percent frames has FEC.\n",
223              static_cast<float>(fec_frames) * block_duration_ms_ / 2000);
224     }
225   }
226 }
227
228 const coding_param param_set[] =
229     {make_tuple(1, 64000, string("audio_coding/testfile32kHz"),
230                 string("pcm")),
231      make_tuple(1, 32000, string("audio_coding/testfile32kHz"),
232                 string("pcm")),
233      make_tuple(2, 64000, string("audio_coding/teststereo32kHz"),
234                 string("pcm"))};
235
236 // 64 kbps, stereo
237 INSTANTIATE_TEST_CASE_P(AllTest, OpusFecTest,
238                         ValuesIn(param_set));
239
240 }  // namespace webrtc