1 /* 2 * Copyright (c) 2015 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 "webrtc/modules/audio_processing/test/audio_file_processor.h" 12 13 #include <algorithm> 14 #include <utility> 15 16 #include "webrtc/base/checks.h" 17 #include "webrtc/modules/audio_processing/test/protobuf_utils.h" 18 19 using rtc::scoped_ptr; 20 using rtc::CheckedDivExact; 21 using std::vector; 22 using webrtc::audioproc::Event; 23 using webrtc::audioproc::Init; 24 using webrtc::audioproc::ReverseStream; 25 using webrtc::audioproc::Stream; 26 27 namespace webrtc { 28 namespace { 29 30 // Returns a StreamConfig corresponding to file. 31 StreamConfig GetStreamConfig(const WavFile& file) { 32 return StreamConfig(file.sample_rate(), file.num_channels()); 33 } 34 35 // Returns a ChannelBuffer corresponding to file. 36 ChannelBuffer<float> GetChannelBuffer(const WavFile& file) { 37 return ChannelBuffer<float>( 38 CheckedDivExact(file.sample_rate(), AudioFileProcessor::kChunksPerSecond), 39 file.num_channels()); 40 } 41 42 } // namespace 43 44 WavFileProcessor::WavFileProcessor(scoped_ptr<AudioProcessing> ap, 45 scoped_ptr<WavReader> in_file, 46 scoped_ptr<WavWriter> out_file) 47 : ap_(std::move(ap)), 48 in_buf_(GetChannelBuffer(*in_file)), 49 out_buf_(GetChannelBuffer(*out_file)), 50 input_config_(GetStreamConfig(*in_file)), 51 output_config_(GetStreamConfig(*out_file)), 52 buffer_reader_(std::move(in_file)), 53 buffer_writer_(std::move(out_file)) {} 54 55 bool WavFileProcessor::ProcessChunk() { 56 if (!buffer_reader_.Read(&in_buf_)) { 57 return false; 58 } 59 { 60 const auto st = ScopedTimer(mutable_proc_time()); 61 RTC_CHECK_EQ(kNoErr, 62 ap_->ProcessStream(in_buf_.channels(), input_config_, 63 output_config_, out_buf_.channels())); 64 } 65 buffer_writer_.Write(out_buf_); 66 return true; 67 } 68 69 AecDumpFileProcessor::AecDumpFileProcessor(scoped_ptr<AudioProcessing> ap, 70 FILE* dump_file, 71 scoped_ptr<WavWriter> out_file) 72 : ap_(std::move(ap)), 73 dump_file_(dump_file), 74 out_buf_(GetChannelBuffer(*out_file)), 75 output_config_(GetStreamConfig(*out_file)), 76 buffer_writer_(std::move(out_file)) { 77 RTC_CHECK(dump_file_) << "Could not open dump file for reading."; 78 } 79 80 AecDumpFileProcessor::~AecDumpFileProcessor() { 81 fclose(dump_file_); 82 } 83 84 bool AecDumpFileProcessor::ProcessChunk() { 85 Event event_msg; 86 87 // Continue until we process our first Stream message. 88 do { 89 if (!ReadMessageFromFile(dump_file_, &event_msg)) { 90 return false; 91 } 92 93 if (event_msg.type() == Event::INIT) { 94 RTC_CHECK(event_msg.has_init()); 95 HandleMessage(event_msg.init()); 96 97 } else if (event_msg.type() == Event::STREAM) { 98 RTC_CHECK(event_msg.has_stream()); 99 HandleMessage(event_msg.stream()); 100 101 } else if (event_msg.type() == Event::REVERSE_STREAM) { 102 RTC_CHECK(event_msg.has_reverse_stream()); 103 HandleMessage(event_msg.reverse_stream()); 104 } 105 } while (event_msg.type() != Event::STREAM); 106 107 return true; 108 } 109 110 void AecDumpFileProcessor::HandleMessage(const Init& msg) { 111 RTC_CHECK(msg.has_sample_rate()); 112 RTC_CHECK(msg.has_num_input_channels()); 113 RTC_CHECK(msg.has_num_reverse_channels()); 114 115 in_buf_.reset(new ChannelBuffer<float>( 116 CheckedDivExact(msg.sample_rate(), kChunksPerSecond), 117 msg.num_input_channels())); 118 const int reverse_sample_rate = msg.has_reverse_sample_rate() 119 ? msg.reverse_sample_rate() 120 : msg.sample_rate(); 121 reverse_buf_.reset(new ChannelBuffer<float>( 122 CheckedDivExact(reverse_sample_rate, kChunksPerSecond), 123 msg.num_reverse_channels())); 124 input_config_ = StreamConfig(msg.sample_rate(), msg.num_input_channels()); 125 reverse_config_ = 126 StreamConfig(reverse_sample_rate, msg.num_reverse_channels()); 127 128 const ProcessingConfig config = { 129 {input_config_, output_config_, reverse_config_, reverse_config_}}; 130 RTC_CHECK_EQ(kNoErr, ap_->Initialize(config)); 131 } 132 133 void AecDumpFileProcessor::HandleMessage(const Stream& msg) { 134 RTC_CHECK(!msg.has_input_data()); 135 RTC_CHECK_EQ(in_buf_->num_channels(), 136 static_cast<size_t>(msg.input_channel_size())); 137 138 for (int i = 0; i < msg.input_channel_size(); ++i) { 139 RTC_CHECK_EQ(in_buf_->num_frames() * sizeof(*in_buf_->channels()[i]), 140 msg.input_channel(i).size()); 141 std::memcpy(in_buf_->channels()[i], msg.input_channel(i).data(), 142 msg.input_channel(i).size()); 143 } 144 { 145 const auto st = ScopedTimer(mutable_proc_time()); 146 RTC_CHECK_EQ(kNoErr, ap_->set_stream_delay_ms(msg.delay())); 147 ap_->echo_cancellation()->set_stream_drift_samples(msg.drift()); 148 if (msg.has_keypress()) { 149 ap_->set_stream_key_pressed(msg.keypress()); 150 } 151 RTC_CHECK_EQ(kNoErr, 152 ap_->ProcessStream(in_buf_->channels(), input_config_, 153 output_config_, out_buf_.channels())); 154 } 155 156 buffer_writer_.Write(out_buf_); 157 } 158 159 void AecDumpFileProcessor::HandleMessage(const ReverseStream& msg) { 160 RTC_CHECK(!msg.has_data()); 161 RTC_CHECK_EQ(reverse_buf_->num_channels(), 162 static_cast<size_t>(msg.channel_size())); 163 164 for (int i = 0; i < msg.channel_size(); ++i) { 165 RTC_CHECK_EQ(reverse_buf_->num_frames() * sizeof(*in_buf_->channels()[i]), 166 msg.channel(i).size()); 167 std::memcpy(reverse_buf_->channels()[i], msg.channel(i).data(), 168 msg.channel(i).size()); 169 } 170 { 171 const auto st = ScopedTimer(mutable_proc_time()); 172 // TODO(ajm): This currently discards the processed output, which is needed 173 // for e.g. intelligibility enhancement. 174 RTC_CHECK_EQ(kNoErr, ap_->ProcessReverseStream( 175 reverse_buf_->channels(), reverse_config_, 176 reverse_config_, reverse_buf_->channels())); 177 } 178 } 179 180 } // namespace webrtc 181