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 #include <string.h>
13 
14 #include <memory>
15 
16 #include "common_types.h"  // NOLINT(build/include)
17 #include "modules/audio_coding/codecs/audio_format_conversion.h"
18 #include "modules/audio_coding/include/audio_coding_module.h"
19 #include "modules/audio_coding/test/Channel.h"
20 #include "modules/audio_coding/test/PCMFile.h"
21 #include "modules/include/module_common_types.h"
22 #include "rtc_base/flags.h"
23 #include "system_wrappers/include/clock.h"
24 #include "test/gtest.h"
25 #include "test/testsupport/fileutils.h"
26 
27 // Codec.
28 DEFINE_string(codec, "opus", "Codec Name");
29 DEFINE_int(codec_sample_rate_hz, 48000, "Sampling rate in Hertz.");
30 DEFINE_int(codec_channels, 1, "Number of channels of the codec.");
31 
32 // PCM input/output.
33 DEFINE_string(input, "", "Input PCM file at 16 kHz.");
34 DEFINE_bool(input_stereo, false, "Input is stereo.");
35 DEFINE_int(input_fs_hz, 32000, "Input sample rate Hz.");
36 DEFINE_string(output, "insert_rtp_with_timing_out.pcm", "OutputFile");
37 DEFINE_int(output_fs_hz, 32000, "Output sample rate Hz");
38 
39 // Timing files
40 DEFINE_string(seq_num, "seq_num", "Sequence number file.");
41 DEFINE_string(send_ts, "send_timestamp", "Send timestamp file.");
42 DEFINE_string(receive_ts, "last_rec_timestamp", "Receive timestamp file");
43 
44 // Delay logging
45 DEFINE_string(delay, "", "Log for delay.");
46 
47 // Other setups
48 DEFINE_bool(verbose, false, "Verbosity.");
49 DEFINE_float(loss_rate, 0, "Rate of packet loss < 1");
50 
51 DEFINE_bool(help, false, "Prints this message.");
52 
53 const int32_t kAudioPlayedOut = 0x00000001;
54 const int32_t kPacketPushedIn = 0x00000001 << 1;
55 const int kPlayoutPeriodMs = 10;
56 
57 namespace webrtc {
58 
59 class InsertPacketWithTiming {
60  public:
InsertPacketWithTiming()61   InsertPacketWithTiming()
62       : sender_clock_(new SimulatedClock(0)),
63         receiver_clock_(new SimulatedClock(0)),
64         send_acm_(AudioCodingModule::Create(sender_clock_)),
65         receive_acm_(AudioCodingModule::Create(receiver_clock_)),
66         channel_(new Channel),
67         seq_num_fid_(fopen(FLAG_seq_num, "rt")),
68         send_ts_fid_(fopen(FLAG_send_ts, "rt")),
69         receive_ts_fid_(fopen(FLAG_receive_ts, "rt")),
70         pcm_out_fid_(fopen(FLAG_output, "wb")),
71         samples_in_1ms_(48),
72         num_10ms_in_codec_frame_(2),  // Typical 20 ms frames.
73         time_to_insert_packet_ms_(3),  // An arbitrary offset on pushing packet.
74         next_receive_ts_(0),
75         time_to_playout_audio_ms_(kPlayoutPeriodMs),
76         loss_threshold_(0),
77         playout_timing_fid_(fopen("playout_timing.txt", "wt")) {}
78 
SetUp()79   void SetUp() {
80     ASSERT_TRUE(sender_clock_ != NULL);
81     ASSERT_TRUE(receiver_clock_ != NULL);
82 
83     ASSERT_TRUE(send_acm_.get() != NULL);
84     ASSERT_TRUE(receive_acm_.get() != NULL);
85     ASSERT_TRUE(channel_ != NULL);
86 
87     ASSERT_TRUE(seq_num_fid_ != NULL);
88     ASSERT_TRUE(send_ts_fid_ != NULL);
89     ASSERT_TRUE(receive_ts_fid_ != NULL);
90 
91     ASSERT_TRUE(playout_timing_fid_ != NULL);
92 
93     next_receive_ts_ = ReceiveTimestamp();
94 
95     CodecInst codec;
96     ASSERT_EQ(0, AudioCodingModule::Codec(FLAG_codec, &codec,
97                              FLAG_codec_sample_rate_hz,
98                              FLAG_codec_channels));
99     ASSERT_EQ(0, receive_acm_->InitializeReceiver());
100     ASSERT_EQ(0, send_acm_->RegisterSendCodec(codec));
101     ASSERT_EQ(true, receive_acm_->RegisterReceiveCodec(codec.pltype,
102                                                        CodecInstToSdp(codec)));
103 
104     // Set codec-dependent parameters.
105     samples_in_1ms_ = codec.plfreq / 1000;
106     num_10ms_in_codec_frame_ = codec.pacsize / (codec.plfreq / 100);
107 
108     channel_->RegisterReceiverACM(receive_acm_.get());
109     send_acm_->RegisterTransportCallback(channel_);
110 
111     if (strlen(FLAG_input) == 0) {
112       std::string file_name = test::ResourcePath("audio_coding/testfile32kHz",
113                                                  "pcm");
114       pcm_in_fid_.Open(file_name, 32000, "r", true);  // auto-rewind
115       std::cout << "Input file " << file_name << " 32 kHz mono." << std::endl;
116     } else {
117       pcm_in_fid_.Open(FLAG_input, static_cast<uint16_t>(FLAG_input_fs_hz),
118                     "r", true);  // auto-rewind
119       std::cout << "Input file " << FLAG_input << "at " << FLAG_input_fs_hz
120           << " Hz in " << ((FLAG_input_stereo) ? "stereo." : "mono.")
121           << std::endl;
122       pcm_in_fid_.ReadStereo(FLAG_input_stereo);
123     }
124 
125     ASSERT_TRUE(pcm_out_fid_ != NULL);
126     std::cout << "Output file " << FLAG_output << " at " << FLAG_output_fs_hz
127         << " Hz." << std::endl;
128 
129     // Other setups
130     if (FLAG_loss_rate > 0)
131       loss_threshold_ = RAND_MAX * FLAG_loss_rate;
132     else
133       loss_threshold_ = 0;
134   }
135 
TickOneMillisecond(uint32_t * action)136   void TickOneMillisecond(uint32_t* action) {
137     // One millisecond passed.
138     time_to_insert_packet_ms_--;
139     time_to_playout_audio_ms_--;
140     sender_clock_->AdvanceTimeMilliseconds(1);
141     receiver_clock_->AdvanceTimeMilliseconds(1);
142 
143     // Reset action.
144     *action = 0;
145 
146     // Is it time to pull audio?
147     if (time_to_playout_audio_ms_ == 0) {
148       time_to_playout_audio_ms_ = kPlayoutPeriodMs;
149       bool muted;
150       receive_acm_->PlayoutData10Ms(static_cast<int>(FLAG_output_fs_hz),
151                                     &frame_, &muted);
152       ASSERT_FALSE(muted);
153       fwrite(frame_.data(), sizeof(*frame_.data()),
154              frame_.samples_per_channel_ * frame_.num_channels_, pcm_out_fid_);
155       *action |= kAudioPlayedOut;
156     }
157 
158     // Is it time to push in next packet?
159     if (time_to_insert_packet_ms_ <= .5) {
160       *action |= kPacketPushedIn;
161 
162       // Update time-to-insert packet.
163       uint32_t t = next_receive_ts_;
164       next_receive_ts_ = ReceiveTimestamp();
165       time_to_insert_packet_ms_ += static_cast<float>(next_receive_ts_ - t) /
166           samples_in_1ms_;
167 
168       // Push in just enough audio.
169       for (int n = 0; n < num_10ms_in_codec_frame_; n++) {
170         pcm_in_fid_.Read10MsData(frame_);
171         EXPECT_GE(send_acm_->Add10MsData(frame_), 0);
172       }
173 
174       // Set the parameters for the packet to be pushed in receiver ACM right
175       // now.
176       uint32_t ts = SendTimestamp();
177       int seq_num = SequenceNumber();
178       bool lost = false;
179       channel_->set_send_timestamp(ts);
180       channel_->set_sequence_number(seq_num);
181       if (loss_threshold_ > 0 && rand() < loss_threshold_) {
182         channel_->set_num_packets_to_drop(1);
183         lost = true;
184       }
185 
186       if (FLAG_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 
TearDown()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 
~InsertPacketWithTiming()208   ~InsertPacketWithTiming() {
209     delete sender_clock_;
210     delete receiver_clock_;
211   }
212 
213   // Are there more info to simulate.
HasPackets()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.
Delay(int * optimal_delay,int * current_delay)221   void Delay(int* optimal_delay, int* current_delay) {
222     NetworkStatistics statistics;
223     receive_acm_->GetNetworkStatistics(&statistics);
224     *optimal_delay = statistics.preferredBufferSize;
225     *current_delay = statistics.currentBufferSize;
226   }
227 
228  private:
SendTimestamp()229   uint32_t SendTimestamp() {
230     uint32_t t;
231     EXPECT_EQ(1, fscanf(send_ts_fid_, "%u\n", &t));
232     return t;
233   }
234 
ReceiveTimestamp()235   uint32_t ReceiveTimestamp() {
236     uint32_t t;
237     EXPECT_EQ(1, fscanf(receive_ts_fid_, "%u\n", &t));
238     return t;
239   }
240 
SequenceNumber()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   std::unique_ptr<AudioCodingModule> send_acm_;
253   std::unique_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 
main(int argc,char * argv[])284 int main(int argc, char* argv[]) {
285   if (rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true)) {
286     return 1;
287   }
288   if (FLAG_help) {
289     rtc::FlagList::Print(nullptr, false);
290     return 0;
291   }
292 
293   webrtc::InsertPacketWithTiming test;
294   test.SetUp();
295 
296   FILE* delay_log = NULL;
297   if (strlen(FLAG_delay) > 0) {
298     delay_log = fopen(FLAG_delay, "wt");
299     if (delay_log == NULL) {
300       std::cout << "Cannot open the file to log delay values." << std::endl;
301       exit(1);
302     }
303   }
304 
305   uint32_t action_taken;
306   int optimal_delay_ms;
307   int current_delay_ms;
308   while (test.HasPackets()) {
309     test.TickOneMillisecond(&action_taken);
310 
311     if (action_taken != 0) {
312       test.Delay(&optimal_delay_ms, &current_delay_ms);
313       if (delay_log != NULL) {
314         fprintf(delay_log, "%3d %3d\n", optimal_delay_ms, current_delay_ms);
315       }
316     }
317   }
318   std::cout << std::endl;
319   test.TearDown();
320   if (delay_log != NULL)
321     fclose(delay_log);
322 }
323