1 // Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
2 //
3 // Use of this source code is governed by a BSD-style license
4 // that can be found in the LICENSE file in the root of the source
5 // tree. An additional intellectual property rights grant can be found
6 // in the file PATENTS.  All contributing project authors may
7 // be found in the AUTHORS file in the root of the source tree.
8 
9 #include <array>
10 #include <fstream>
11 #include <memory>
12 
13 #include "common_audio/vad/include/vad.h"
14 #include "common_audio/wav_file.h"
15 #include "rtc_base/flags.h"
16 #include "rtc_base/logging.h"
17 
18 namespace webrtc {
19 namespace test {
20 namespace {
21 
22 // The allowed values are 10, 20 or 30 ms.
23 constexpr uint8_t kAudioFrameLengthMilliseconds = 30;
24 constexpr int kMaxSampleRate = 48000;
25 constexpr size_t kMaxFrameLen =
26     kAudioFrameLengthMilliseconds * kMaxSampleRate / 1000;
27 
28 constexpr uint8_t kBitmaskBuffSize = 8;
29 
30 DEFINE_string(i, "", "Input wav file");
31 DEFINE_string(o, "", "VAD output file");
32 
main(int argc,char * argv[])33 int main(int argc, char* argv[]) {
34   if (rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true))
35     return 1;
36 
37   // Open wav input file and check properties.
38   WavReader wav_reader(FLAG_i);
39   if (wav_reader.num_channels() != 1) {
40     RTC_LOG(LS_ERROR) << "Only mono wav files supported";
41     return 1;
42   }
43   if (wav_reader.sample_rate() > kMaxSampleRate) {
44     RTC_LOG(LS_ERROR) << "Beyond maximum sample rate (" << kMaxSampleRate
45                       << ")";
46     return 1;
47   }
48   const size_t audio_frame_length = rtc::CheckedDivExact(
49       kAudioFrameLengthMilliseconds * wav_reader.sample_rate(), 1000);
50   if (audio_frame_length > kMaxFrameLen) {
51     RTC_LOG(LS_ERROR) << "The frame size and/or the sample rate are too large.";
52     return 1;
53   }
54 
55   // Create output file and write header.
56   std::ofstream out_file(FLAG_o, std::ofstream::binary);
57   const char audio_frame_length_ms = kAudioFrameLengthMilliseconds;
58   out_file.write(&audio_frame_length_ms, 1);  // Header.
59 
60   // Run VAD and write decisions.
61   std::unique_ptr<Vad> vad = CreateVad(Vad::Aggressiveness::kVadNormal);
62   std::array<int16_t, kMaxFrameLen> samples;
63   char buff = 0;     // Buffer to write one bit per frame.
64   uint8_t next = 0;  // Points to the next bit to write in |buff|.
65   while (true) {
66     // Process frame.
67     const auto read_samples =
68         wav_reader.ReadSamples(audio_frame_length, samples.data());
69     if (read_samples < audio_frame_length)
70       break;
71     const auto is_speech = vad->VoiceActivity(
72         samples.data(), audio_frame_length, wav_reader.sample_rate());
73 
74     // Write output.
75     buff = is_speech ? buff | (1 << next) : buff & ~(1 << next);
76     if (++next == kBitmaskBuffSize) {
77       out_file.write(&buff, 1);  // Flush.
78       buff = 0;                  // Reset.
79       next = 0;
80     }
81   }
82 
83   // Finalize.
84   char extra_bits = 0;
85   if (next > 0) {
86     extra_bits = kBitmaskBuffSize - next;
87     out_file.write(&buff, 1);  // Flush.
88   }
89   out_file.write(&extra_bits, 1);
90   out_file.close();
91 
92   return 0;
93 }
94 
95 }  // namespace
96 }  // namespace test
97 }  // namespace webrtc
98 
main(int argc,char * argv[])99 int main(int argc, char* argv[]) {
100   return webrtc::test::main(argc, argv);
101 }
102