| /* | 
 |  *  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; | 
 | } |