blob: 5bdc485b082305608b986fbfa8e6cd65f328e9af [file] [log] [blame]
Alex Loiko99a2c5d2018-02-27 14:09:47 +01001/*
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
Jonas Olssona4d87372019-07-05 19:08:33 +020011#include "api/audio/audio_mixer.h"
12
Alex Loiko99a2c5d2018-02-27 14:09:47 +010013#include <cstring>
14#include <iostream>
15#include <vector>
16
Mirko Bonadei2ab97f62019-07-18 13:44:12 +020017#include "absl/flags/flag.h"
18#include "absl/flags/parse.h"
Alex Loiko99a2c5d2018-02-27 14:09:47 +010019#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"
Jonas Olsson366a50c2018-09-06 13:41:30 +020022#include "rtc_base/strings/string_builder.h"
Alex Loiko99a2c5d2018-02-27 14:09:47 +010023
Mirko Bonadei2ab97f62019-07-18 13:44:12 +020024ABSL_FLAG(int,
25 sampling_rate,
26 16000,
27 "Rate at which to mix (all input streams must have this rate)");
Alex Loiko99a2c5d2018-02-27 14:09:47 +010028
Mirko Bonadei2ab97f62019-07-18 13:44:12 +020029ABSL_FLAG(bool,
30 stereo,
31 false,
32 "Enable stereo (interleaved). Inputs need not be as this parameter.");
Alex Loiko99a2c5d2018-02-27 14:09:47 +010033
Mirko Bonadei2ab97f62019-07-18 13:44:12 +020034ABSL_FLAG(bool, limiter, true, "Enable limiter.");
35ABSL_FLAG(std::string,
36 output_file,
37 "mixed_file.wav",
38 "File in which to store the mixed result.");
39ABSL_FLAG(std::string, input_file_1, "", "First input. Default none.");
40ABSL_FLAG(std::string, input_file_2, "", "Second input. Default none.");
41ABSL_FLAG(std::string, input_file_3, "", "Third input. Default none.");
42ABSL_FLAG(std::string, input_file_4, "", "Fourth input. Default none.");
Alex Loiko99a2c5d2018-02-27 14:09:47 +010043
44namespace webrtc {
45namespace test {
46
47class FilePlayingSource : public AudioMixer::Source {
48 public:
49 explicit FilePlayingSource(std::string 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
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
74 int Ssrc() const override { return 0; }
75
76 int PreferredSampleRate() const override { return sample_rate_hz_; }
77
78 bool FileHasEnded() const { return file_has_ended_; }
79
80 std::string ToString() const {
Jonas Olsson366a50c2018-09-06 13:41:30 +020081 rtc::StringBuilder ss;
Alex Loiko99a2c5d2018-02-27 14:09:47 +010082 ss << "{rate: " << sample_rate_hz_ << ", channels: " << number_of_channels_
83 << ", samples_tot: " << wav_reader_->num_samples() << "}";
Jonas Olsson84df1c72018-09-14 16:59:32 +020084 return ss.Release();
Alex Loiko99a2c5d2018-02-27 14:09:47 +010085 }
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
97namespace {
98
99const std::vector<std::string> parse_input_files() {
100 std::vector<std::string> result;
Mirko Bonadei2ab97f62019-07-18 13:44:12 +0200101 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()) {
Alex Loiko99a2c5d2018-02-27 14:09:47 +0100105 result.push_back(x);
106 }
107 }
108 return result;
109}
110} // namespace
111
112int main(int argc, char* argv[]) {
Mirko Bonadei2ab97f62019-07-18 13:44:12 +0200113 absl::ParseCommandLine(argc, argv);
Alex Loiko99a2c5d2018-02-27 14:09:47 +0100114
115 rtc::scoped_refptr<webrtc::AudioMixerImpl> mixer(
116 webrtc::AudioMixerImpl::Create(
117 std::unique_ptr<webrtc::OutputRateCalculator>(
118 new webrtc::DefaultOutputRateCalculator()),
Mirko Bonadei2ab97f62019-07-18 13:44:12 +0200119 absl::GetFlag(FLAGS_limiter)));
Alex Loiko99a2c5d2018-02-27 14:09:47 +0100120
121 const std::vector<std::string> input_files = parse_input_files();
122 std::vector<webrtc::test::FilePlayingSource> sources;
Mirko Bonadei2ab97f62019-07-18 13:44:12 +0200123 const int num_channels = absl::GetFlag(FLAGS_stereo) ? 2 : 1;
Mirko Bonadei649a4c22019-01-29 10:11:53 +0100124 sources.reserve(input_files.size());
Mirko Bonadei739baf02019-01-27 17:29:42 +0100125 for (const auto& input_file : input_files) {
Alex Loiko99a2c5d2018-02-27 14:09:47 +0100126 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";
Alex Loiko99a2c5d2018-02-27 14:09:47 +0100136 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.
Mirko Bonadei2ab97f62019-07-18 13:44:12 +0200145 std::cout << "Limiting is: " << (absl::GetFlag(FLAGS_limiter) ? "on" : "off")
146 << "\n"
Jonas Olssonb2b20312020-01-14 12:11:31 +0100147 "Channels: "
148 << num_channels
149 << "\n"
150 "Rate: "
151 << sample_rate
152 << "\n"
153 "Number of input streams: "
154 << input_files.size() << "\n";
Alex Loiko99a2c5d2018-02-27 14:09:47 +0100155 for (const auto& source : sources) {
156 std::cout << "\t" << source.ToString() << "\n";
157 }
158 std::cout << "Now mixing\n...\n";
159
Mirko Bonadei2ab97f62019-07-18 13:44:12 +0200160 webrtc::WavWriter wav_writer(absl::GetFlag(FLAGS_output_file), sample_rate,
161 num_channels);
Alex Loiko99a2c5d2018-02-27 14:09:47 +0100162
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}