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