Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / webrtc / modules / audio_coding / main / test / insert_packet_with_timing.cc
1 /*
2  *  Copyright (c) 2013 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 <stdio.h>
12
13 #include "gflags/gflags.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "webrtc/common_types.h"
16 #include "webrtc/modules/audio_coding/main/interface/audio_coding_module.h"
17 #include "webrtc/modules/audio_coding/main/test/Channel.h"
18 #include "webrtc/modules/audio_coding/main/test/PCMFile.h"
19 #include "webrtc/modules/interface/module_common_types.h"
20 #include "webrtc/system_wrappers/interface/clock.h"
21 #include "webrtc/system_wrappers/interface/scoped_ptr.h"
22 #include "webrtc/test/testsupport/fileutils.h"
23
24 // Codec.
25 DEFINE_string(codec, "opus", "Codec Name");
26 DEFINE_int32(codec_sample_rate_hz, 48000, "Sampling rate in Hertz.");
27 DEFINE_int32(codec_channels, 1, "Number of channels of the codec.");
28
29 // PCM input/output.
30 DEFINE_string(input, "", "Input PCM file at 16 kHz.");
31 DEFINE_bool(input_stereo, false, "Input is stereo.");
32 DEFINE_int32(input_fs_hz, 32000, "Input sample rate Hz.");
33 DEFINE_string(output, "insert_rtp_with_timing_out.pcm", "OutputFile");
34 DEFINE_int32(output_fs_hz, 32000, "Output sample rate Hz");
35
36 // Timing files
37 DEFINE_string(seq_num, "seq_num", "Sequence number file.");
38 DEFINE_string(send_ts, "send_timestamp", "Send timestamp file.");
39 DEFINE_string(receive_ts, "last_rec_timestamp", "Receive timestamp file");
40
41 // Delay logging
42 DEFINE_string(delay, "", "Log for delay.");
43
44 // Other setups
45 DEFINE_int32(init_delay, 0, "Initial delay.");
46 DEFINE_bool(verbose, false, "Verbosity.");
47 DEFINE_double(loss_rate, 0, "Rate of packet loss < 1");
48
49 const int32_t kAudioPlayedOut = 0x00000001;
50 const int32_t kPacketPushedIn = 0x00000001 << 1;
51 const int kPlayoutPeriodMs = 10;
52
53 namespace webrtc {
54
55 class InsertPacketWithTiming {
56  public:
57   InsertPacketWithTiming()
58       : sender_clock_(new SimulatedClock(0)),
59         receiver_clock_(new SimulatedClock(0)),
60         send_acm_(AudioCodingModule::Create(0, sender_clock_)),
61         receive_acm_(AudioCodingModule::Create(0, receiver_clock_)),
62         channel_(new Channel),
63         seq_num_fid_(fopen(FLAGS_seq_num.c_str(), "rt")),
64         send_ts_fid_(fopen(FLAGS_send_ts.c_str(), "rt")),
65         receive_ts_fid_(fopen(FLAGS_receive_ts.c_str(), "rt")),
66         pcm_out_fid_(fopen(FLAGS_output.c_str(), "wb")),
67         samples_in_1ms_(48),
68         num_10ms_in_codec_frame_(2),  // Typical 20 ms frames.
69         time_to_insert_packet_ms_(3),  // An arbitrary offset on pushing packet.
70         next_receive_ts_(0),
71         time_to_playout_audio_ms_(kPlayoutPeriodMs),
72         loss_threshold_(0),
73         playout_timing_fid_(fopen("playout_timing.txt", "wt")) {}
74
75   void SetUp() {
76     ASSERT_TRUE(sender_clock_ != NULL);
77     ASSERT_TRUE(receiver_clock_ != NULL);
78
79     ASSERT_TRUE(send_acm_.get() != NULL);
80     ASSERT_TRUE(receive_acm_.get() != NULL);
81     ASSERT_TRUE(channel_ != NULL);
82
83     ASSERT_TRUE(seq_num_fid_ != NULL);
84     ASSERT_TRUE(send_ts_fid_ != NULL);
85     ASSERT_TRUE(receive_ts_fid_ != NULL);
86
87     ASSERT_TRUE(playout_timing_fid_ != NULL);
88
89     next_receive_ts_ = ReceiveTimestamp();
90
91     CodecInst codec;
92     ASSERT_EQ(0, AudioCodingModule::Codec(FLAGS_codec.c_str(), &codec,
93                              FLAGS_codec_sample_rate_hz,
94                              FLAGS_codec_channels));
95     ASSERT_EQ(0, receive_acm_->InitializeReceiver());
96     ASSERT_EQ(0, send_acm_->RegisterSendCodec(codec));
97     ASSERT_EQ(0, receive_acm_->RegisterReceiveCodec(codec));
98
99     // Set codec-dependent parameters.
100     samples_in_1ms_ = codec.plfreq / 1000;
101     num_10ms_in_codec_frame_ = codec.pacsize / (codec.plfreq / 100);
102
103     channel_->RegisterReceiverACM(receive_acm_.get());
104     send_acm_->RegisterTransportCallback(channel_);
105
106     if (FLAGS_input.size() == 0) {
107       std::string file_name = test::ResourcePath("audio_coding/testfile32kHz",
108                                                  "pcm");
109       pcm_in_fid_.Open(file_name, 32000, "r", true);  // auto-rewind
110       std::cout << "Input file " << file_name << " 32 kHz mono." << std::endl;
111     } else {
112       pcm_in_fid_.Open(FLAGS_input, static_cast<uint16_t>(FLAGS_input_fs_hz),
113                     "r", true);  // auto-rewind
114       std::cout << "Input file " << FLAGS_input << "at " << FLAGS_input_fs_hz
115           << " Hz in " << ((FLAGS_input_stereo) ? "stereo." : "mono.")
116           << std::endl;
117       pcm_in_fid_.ReadStereo(FLAGS_input_stereo);
118     }
119
120     ASSERT_TRUE(pcm_out_fid_ != NULL);
121     std::cout << "Output file " << FLAGS_output << " at " << FLAGS_output_fs_hz
122         << " Hz." << std::endl;
123
124     // Other setups
125     if (FLAGS_init_delay > 0)
126       EXPECT_EQ(0, receive_acm_->SetInitialPlayoutDelay(FLAGS_init_delay));
127
128     if (FLAGS_loss_rate > 0)
129       loss_threshold_ = RAND_MAX * FLAGS_loss_rate;
130     else
131       loss_threshold_ = 0;
132   }
133
134   void TickOneMillisecond(uint32_t* action) {
135     // One millisecond passed.
136     time_to_insert_packet_ms_--;
137     time_to_playout_audio_ms_--;
138     sender_clock_->AdvanceTimeMilliseconds(1);
139     receiver_clock_->AdvanceTimeMilliseconds(1);
140
141     // Reset action.
142     *action = 0;
143
144     // Is it time to pull audio?
145     if (time_to_playout_audio_ms_ == 0) {
146       time_to_playout_audio_ms_ = kPlayoutPeriodMs;
147       receive_acm_->PlayoutData10Ms(static_cast<int>(FLAGS_output_fs_hz),
148                                     &frame_);
149       fwrite(frame_.data_, sizeof(frame_.data_[0]),
150              frame_.samples_per_channel_ * frame_.num_channels_, pcm_out_fid_);
151       *action |= kAudioPlayedOut;
152     }
153
154     // Is it time to push in next packet?
155     if (time_to_insert_packet_ms_ <= .5) {
156       *action |= kPacketPushedIn;
157
158       // Update time-to-insert packet.
159       uint32_t t = next_receive_ts_;
160       next_receive_ts_ = ReceiveTimestamp();
161       time_to_insert_packet_ms_ += static_cast<float>(next_receive_ts_ - t) /
162           samples_in_1ms_;
163
164       // Push in just enough audio.
165       for (int n = 0; n < num_10ms_in_codec_frame_; n++) {
166         pcm_in_fid_.Read10MsData(frame_);
167         EXPECT_EQ(0, send_acm_->Add10MsData(frame_));
168       }
169
170       // Set the parameters for the packet to be pushed in receiver ACM right
171       // now.
172       uint32_t ts = SendTimestamp();
173       int seq_num = SequenceNumber();
174       bool lost = false;
175       channel_->set_send_timestamp(ts);
176       channel_->set_sequence_number(seq_num);
177       if (loss_threshold_ > 0 && rand() < loss_threshold_) {
178         channel_->set_num_packets_to_drop(1);
179         lost = true;
180       }
181
182       // Process audio in send ACM, this should result in generation of a
183       // packet.
184       EXPECT_GT(send_acm_->Process(), 0);
185
186       if (FLAGS_verbose) {
187         if (!lost) {
188           std::cout << "\nInserting packet number " << seq_num
189               << " timestamp " << ts << std::endl;
190         } else {
191           std::cout << "\nLost packet number " << seq_num
192               << " timestamp " << ts << std::endl;
193         }
194       }
195     }
196   }
197
198   void TearDown() {
199     delete channel_;
200
201     fclose(seq_num_fid_);
202     fclose(send_ts_fid_);
203     fclose(receive_ts_fid_);
204     fclose(pcm_out_fid_);
205     pcm_in_fid_.Close();
206   }
207
208   ~InsertPacketWithTiming() {
209     delete sender_clock_;
210     delete receiver_clock_;
211   }
212
213   // Are there more info to simulate.
214   bool HasPackets() {
215     if (feof(seq_num_fid_) || feof(send_ts_fid_) || feof(receive_ts_fid_))
216       return false;
217     return true;
218   }
219
220   // Jitter buffer delay.
221   void Delay(int* optimal_delay, int* current_delay) {
222     ACMNetworkStatistics statistics;
223     receive_acm_->NetworkStatistics(&statistics);
224     *optimal_delay = statistics.preferredBufferSize;
225     *current_delay = statistics.currentBufferSize;
226   }
227
228  private:
229   uint32_t SendTimestamp() {
230     uint32_t t;
231     EXPECT_EQ(1, fscanf(send_ts_fid_, "%u\n", &t));
232     return t;
233   }
234
235   uint32_t ReceiveTimestamp() {
236     uint32_t t;
237     EXPECT_EQ(1, fscanf(receive_ts_fid_, "%u\n", &t));
238     return t;
239   }
240
241   int SequenceNumber() {
242     int n;
243     EXPECT_EQ(1, fscanf(seq_num_fid_, "%d\n", &n));
244     return n;
245   }
246
247   // This class just creates these pointers, not deleting them. They are deleted
248   // by the associated ACM.
249   SimulatedClock* sender_clock_;
250   SimulatedClock* receiver_clock_;
251
252   scoped_ptr<AudioCodingModule> send_acm_;
253   scoped_ptr<AudioCodingModule> receive_acm_;
254   Channel* channel_;
255
256   FILE* seq_num_fid_;  // Input (text), one sequence number per line.
257   FILE* send_ts_fid_;  // Input (text), one send timestamp per line.
258   FILE* receive_ts_fid_;  // Input (text), one receive timestamp per line.
259   FILE* pcm_out_fid_;  // Output PCM16.
260
261   PCMFile pcm_in_fid_;  // Input PCM16.
262
263   int samples_in_1ms_;
264
265   // TODO(turajs): this can be computed from the send timestamp, but there is
266   // some complication to account for lost and reordered packets.
267   int num_10ms_in_codec_frame_;
268
269   float time_to_insert_packet_ms_;
270   uint32_t next_receive_ts_;
271   uint32_t time_to_playout_audio_ms_;
272
273   AudioFrame frame_;
274
275   double loss_threshold_;
276
277   // Output (text), sequence number, playout timestamp, time (ms) of playout,
278   // per line.
279   FILE* playout_timing_fid_;
280 };
281
282 }  // webrtc
283
284 int main(int argc, char* argv[]) {
285   google::ParseCommandLineFlags(&argc, &argv, true);
286   webrtc::InsertPacketWithTiming test;
287   test.SetUp();
288
289   FILE* delay_log = NULL;
290   if (FLAGS_delay.size() > 0) {
291     delay_log = fopen(FLAGS_delay.c_str(), "wt");
292     if (delay_log == NULL) {
293       std::cout << "Cannot open the file to log delay values." << std::endl;
294       exit(1);
295     }
296   }
297
298   uint32_t action_taken;
299   int optimal_delay_ms;
300   int current_delay_ms;
301   while (test.HasPackets()) {
302     test.TickOneMillisecond(&action_taken);
303
304     if (action_taken != 0) {
305       test.Delay(&optimal_delay_ms, &current_delay_ms);
306       if (delay_log != NULL) {
307         fprintf(delay_log, "%3d %3d\n", optimal_delay_ms, current_delay_ms);
308       }
309     }
310   }
311   std::cout << std::endl;
312   test.TearDown();
313   if (delay_log != NULL)
314     fclose(delay_log);
315 }