Home | History | Annotate | Download | only in test
      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