You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
183 lines
5.7 KiB
183 lines
5.7 KiB
/*
|
|
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
#include "api/audio/audio_mixer.h"
|
|
|
|
#include <cstring>
|
|
#include <iostream>
|
|
#include <vector>
|
|
|
|
#include "absl/flags/flag.h"
|
|
#include "absl/flags/parse.h"
|
|
#include "common_audio/wav_file.h"
|
|
#include "modules/audio_mixer/audio_mixer_impl.h"
|
|
#include "modules/audio_mixer/default_output_rate_calculator.h"
|
|
#include "rtc_base/strings/string_builder.h"
|
|
|
|
ABSL_FLAG(int,
|
|
sampling_rate,
|
|
16000,
|
|
"Rate at which to mix (all input streams must have this rate)");
|
|
|
|
ABSL_FLAG(bool,
|
|
stereo,
|
|
false,
|
|
"Enable stereo (interleaved). Inputs need not be as this parameter.");
|
|
|
|
ABSL_FLAG(bool, limiter, true, "Enable limiter.");
|
|
ABSL_FLAG(std::string,
|
|
output_file,
|
|
"mixed_file.wav",
|
|
"File in which to store the mixed result.");
|
|
ABSL_FLAG(std::string, input_file_1, "", "First input. Default none.");
|
|
ABSL_FLAG(std::string, input_file_2, "", "Second input. Default none.");
|
|
ABSL_FLAG(std::string, input_file_3, "", "Third input. Default none.");
|
|
ABSL_FLAG(std::string, input_file_4, "", "Fourth input. Default none.");
|
|
|
|
namespace webrtc {
|
|
namespace test {
|
|
|
|
class FilePlayingSource : public AudioMixer::Source {
|
|
public:
|
|
explicit FilePlayingSource(std::string filename)
|
|
: wav_reader_(new WavReader(filename)),
|
|
sample_rate_hz_(wav_reader_->sample_rate()),
|
|
samples_per_channel_(sample_rate_hz_ / 100),
|
|
number_of_channels_(wav_reader_->num_channels()) {}
|
|
|
|
AudioFrameInfo GetAudioFrameWithInfo(int target_rate_hz,
|
|
AudioFrame* frame) override {
|
|
frame->samples_per_channel_ = samples_per_channel_;
|
|
frame->num_channels_ = number_of_channels_;
|
|
frame->sample_rate_hz_ = target_rate_hz;
|
|
|
|
RTC_CHECK_EQ(target_rate_hz, sample_rate_hz_);
|
|
|
|
const size_t num_to_read = number_of_channels_ * samples_per_channel_;
|
|
const size_t num_read =
|
|
wav_reader_->ReadSamples(num_to_read, frame->mutable_data());
|
|
|
|
file_has_ended_ = num_to_read != num_read;
|
|
if (file_has_ended_) {
|
|
frame->Mute();
|
|
}
|
|
return file_has_ended_ ? AudioFrameInfo::kMuted : AudioFrameInfo::kNormal;
|
|
}
|
|
|
|
int Ssrc() const override { return 0; }
|
|
|
|
int PreferredSampleRate() const override { return sample_rate_hz_; }
|
|
|
|
bool FileHasEnded() const { return file_has_ended_; }
|
|
|
|
std::string ToString() const {
|
|
rtc::StringBuilder ss;
|
|
ss << "{rate: " << sample_rate_hz_ << ", channels: " << number_of_channels_
|
|
<< ", samples_tot: " << wav_reader_->num_samples() << "}";
|
|
return ss.Release();
|
|
}
|
|
|
|
private:
|
|
std::unique_ptr<WavReader> wav_reader_;
|
|
int sample_rate_hz_;
|
|
int samples_per_channel_;
|
|
int number_of_channels_;
|
|
bool file_has_ended_ = false;
|
|
};
|
|
} // namespace test
|
|
} // namespace webrtc
|
|
|
|
namespace {
|
|
|
|
const std::vector<std::string> parse_input_files() {
|
|
std::vector<std::string> result;
|
|
for (auto& x :
|
|
{absl::GetFlag(FLAGS_input_file_1), absl::GetFlag(FLAGS_input_file_2),
|
|
absl::GetFlag(FLAGS_input_file_3), absl::GetFlag(FLAGS_input_file_4)}) {
|
|
if (!x.empty()) {
|
|
result.push_back(x);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
} // namespace
|
|
|
|
int main(int argc, char* argv[]) {
|
|
absl::ParseCommandLine(argc, argv);
|
|
|
|
rtc::scoped_refptr<webrtc::AudioMixerImpl> mixer(
|
|
webrtc::AudioMixerImpl::Create(
|
|
std::unique_ptr<webrtc::OutputRateCalculator>(
|
|
new webrtc::DefaultOutputRateCalculator()),
|
|
absl::GetFlag(FLAGS_limiter)));
|
|
|
|
const std::vector<std::string> input_files = parse_input_files();
|
|
std::vector<webrtc::test::FilePlayingSource> sources;
|
|
const int num_channels = absl::GetFlag(FLAGS_stereo) ? 2 : 1;
|
|
sources.reserve(input_files.size());
|
|
for (const auto& input_file : input_files) {
|
|
sources.emplace_back(input_file);
|
|
}
|
|
|
|
for (auto& source : sources) {
|
|
auto error = mixer->AddSource(&source);
|
|
RTC_CHECK(error);
|
|
}
|
|
|
|
if (sources.empty()) {
|
|
std::cout << "Need at least one source!\n";
|
|
return 1;
|
|
}
|
|
|
|
const size_t sample_rate = sources[0].PreferredSampleRate();
|
|
for (const auto& source : sources) {
|
|
RTC_CHECK_EQ(sample_rate, source.PreferredSampleRate());
|
|
}
|
|
|
|
// Print stats.
|
|
std::cout << "Limiting is: " << (absl::GetFlag(FLAGS_limiter) ? "on" : "off")
|
|
<< "\n"
|
|
"Channels: "
|
|
<< num_channels
|
|
<< "\n"
|
|
"Rate: "
|
|
<< sample_rate
|
|
<< "\n"
|
|
"Number of input streams: "
|
|
<< input_files.size() << "\n";
|
|
for (const auto& source : sources) {
|
|
std::cout << "\t" << source.ToString() << "\n";
|
|
}
|
|
std::cout << "Now mixing\n...\n";
|
|
|
|
webrtc::WavWriter wav_writer(absl::GetFlag(FLAGS_output_file), sample_rate,
|
|
num_channels);
|
|
|
|
webrtc::AudioFrame frame;
|
|
|
|
bool all_streams_finished = false;
|
|
while (!all_streams_finished) {
|
|
mixer->Mix(num_channels, &frame);
|
|
RTC_CHECK_EQ(sample_rate / 100, frame.samples_per_channel_);
|
|
RTC_CHECK_EQ(sample_rate, frame.sample_rate_hz_);
|
|
RTC_CHECK_EQ(num_channels, frame.num_channels_);
|
|
wav_writer.WriteSamples(frame.data(),
|
|
num_channels * frame.samples_per_channel_);
|
|
|
|
all_streams_finished =
|
|
std::all_of(sources.begin(), sources.end(),
|
|
[](const webrtc::test::FilePlayingSource& source) {
|
|
return source.FileHasEnded();
|
|
});
|
|
}
|
|
|
|
std::cout << "Done!\n" << std::endl;
|
|
}
|