/* * 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 #include #include #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(absl::string_view 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 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 parse_input_files() { std::vector 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 mixer( webrtc::AudioMixerImpl::Create( std::unique_ptr( new webrtc::DefaultOutputRateCalculator()), absl::GetFlag(FLAGS_limiter))); const std::vector input_files = parse_input_files(); std::vector 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; }