1 /*
2 * Copyright (c) 2018 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 "api/audio/audio_mixer.h"
12
13 #include <cstring>
14 #include <iostream>
15 #include <vector>
16
17 #include "absl/flags/flag.h"
18 #include "absl/flags/parse.h"
19 #include "common_audio/wav_file.h"
20 #include "modules/audio_mixer/audio_mixer_impl.h"
21 #include "modules/audio_mixer/default_output_rate_calculator.h"
22 #include "rtc_base/strings/string_builder.h"
23
24 ABSL_FLAG(int,
25 sampling_rate,
26 16000,
27 "Rate at which to mix (all input streams must have this rate)");
28
29 ABSL_FLAG(bool,
30 stereo,
31 false,
32 "Enable stereo (interleaved). Inputs need not be as this parameter.");
33
34 ABSL_FLAG(bool, limiter, true, "Enable limiter.");
35 ABSL_FLAG(std::string,
36 output_file,
37 "mixed_file.wav",
38 "File in which to store the mixed result.");
39 ABSL_FLAG(std::string, input_file_1, "", "First input. Default none.");
40 ABSL_FLAG(std::string, input_file_2, "", "Second input. Default none.");
41 ABSL_FLAG(std::string, input_file_3, "", "Third input. Default none.");
42 ABSL_FLAG(std::string, input_file_4, "", "Fourth input. Default none.");
43
44 namespace webrtc {
45 namespace test {
46
47 class FilePlayingSource : public AudioMixer::Source {
48 public:
FilePlayingSource(absl::string_view filename)49 explicit FilePlayingSource(absl::string_view filename)
50 : wav_reader_(new WavReader(filename)),
51 sample_rate_hz_(wav_reader_->sample_rate()),
52 samples_per_channel_(sample_rate_hz_ / 100),
53 number_of_channels_(wav_reader_->num_channels()) {}
54
GetAudioFrameWithInfo(int target_rate_hz,AudioFrame * frame)55 AudioFrameInfo GetAudioFrameWithInfo(int target_rate_hz,
56 AudioFrame* frame) override {
57 frame->samples_per_channel_ = samples_per_channel_;
58 frame->num_channels_ = number_of_channels_;
59 frame->sample_rate_hz_ = target_rate_hz;
60
61 RTC_CHECK_EQ(target_rate_hz, sample_rate_hz_);
62
63 const size_t num_to_read = number_of_channels_ * samples_per_channel_;
64 const size_t num_read =
65 wav_reader_->ReadSamples(num_to_read, frame->mutable_data());
66
67 file_has_ended_ = num_to_read != num_read;
68 if (file_has_ended_) {
69 frame->Mute();
70 }
71 return file_has_ended_ ? AudioFrameInfo::kMuted : AudioFrameInfo::kNormal;
72 }
73
Ssrc() const74 int Ssrc() const override { return 0; }
75
PreferredSampleRate() const76 int PreferredSampleRate() const override { return sample_rate_hz_; }
77
FileHasEnded() const78 bool FileHasEnded() const { return file_has_ended_; }
79
ToString() const80 std::string ToString() const {
81 rtc::StringBuilder ss;
82 ss << "{rate: " << sample_rate_hz_ << ", channels: " << number_of_channels_
83 << ", samples_tot: " << wav_reader_->num_samples() << "}";
84 return ss.Release();
85 }
86
87 private:
88 std::unique_ptr<WavReader> wav_reader_;
89 int sample_rate_hz_;
90 int samples_per_channel_;
91 int number_of_channels_;
92 bool file_has_ended_ = false;
93 };
94 } // namespace test
95 } // namespace webrtc
96
97 namespace {
98
parse_input_files()99 const std::vector<std::string> parse_input_files() {
100 std::vector<std::string> result;
101 for (auto& x :
102 {absl::GetFlag(FLAGS_input_file_1), absl::GetFlag(FLAGS_input_file_2),
103 absl::GetFlag(FLAGS_input_file_3), absl::GetFlag(FLAGS_input_file_4)}) {
104 if (!x.empty()) {
105 result.push_back(x);
106 }
107 }
108 return result;
109 }
110 } // namespace
111
main(int argc,char * argv[])112 int main(int argc, char* argv[]) {
113 absl::ParseCommandLine(argc, argv);
114
115 rtc::scoped_refptr<webrtc::AudioMixerImpl> mixer(
116 webrtc::AudioMixerImpl::Create(
117 std::unique_ptr<webrtc::OutputRateCalculator>(
118 new webrtc::DefaultOutputRateCalculator()),
119 absl::GetFlag(FLAGS_limiter)));
120
121 const std::vector<std::string> input_files = parse_input_files();
122 std::vector<webrtc::test::FilePlayingSource> sources;
123 const int num_channels = absl::GetFlag(FLAGS_stereo) ? 2 : 1;
124 sources.reserve(input_files.size());
125 for (const auto& input_file : input_files) {
126 sources.emplace_back(input_file);
127 }
128
129 for (auto& source : sources) {
130 auto error = mixer->AddSource(&source);
131 RTC_CHECK(error);
132 }
133
134 if (sources.empty()) {
135 std::cout << "Need at least one source!\n";
136 return 1;
137 }
138
139 const size_t sample_rate = sources[0].PreferredSampleRate();
140 for (const auto& source : sources) {
141 RTC_CHECK_EQ(sample_rate, source.PreferredSampleRate());
142 }
143
144 // Print stats.
145 std::cout << "Limiting is: " << (absl::GetFlag(FLAGS_limiter) ? "on" : "off")
146 << "\n"
147 "Channels: "
148 << num_channels
149 << "\n"
150 "Rate: "
151 << sample_rate
152 << "\n"
153 "Number of input streams: "
154 << input_files.size() << "\n";
155 for (const auto& source : sources) {
156 std::cout << "\t" << source.ToString() << "\n";
157 }
158 std::cout << "Now mixing\n...\n";
159
160 webrtc::WavWriter wav_writer(absl::GetFlag(FLAGS_output_file), sample_rate,
161 num_channels);
162
163 webrtc::AudioFrame frame;
164
165 bool all_streams_finished = false;
166 while (!all_streams_finished) {
167 mixer->Mix(num_channels, &frame);
168 RTC_CHECK_EQ(sample_rate / 100, frame.samples_per_channel_);
169 RTC_CHECK_EQ(sample_rate, frame.sample_rate_hz_);
170 RTC_CHECK_EQ(num_channels, frame.num_channels_);
171 wav_writer.WriteSamples(frame.data(),
172 num_channels * frame.samples_per_channel_);
173
174 all_streams_finished =
175 std::all_of(sources.begin(), sources.end(),
176 [](const webrtc::test::FilePlayingSource& source) {
177 return source.FileHasEnded();
178 });
179 }
180
181 std::cout << "Done!\n" << std::endl;
182 }
183