1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/command_line.h"
6#include "base/file_util.h"
7#include "base/files/file_path.h"
8#include "base/logging.h"
9#include "base/path_service.h"
10#include "base/time/time.h"
11#include "content/public/common/content_switches.h"
12#include "content/renderer/media/media_stream_audio_processor.h"
13#include "content/renderer/media/rtc_media_constraints.h"
14#include "media/audio/audio_parameters.h"
15#include "media/base/audio_bus.h"
16#include "testing/gmock/include/gmock/gmock.h"
17#include "testing/gtest/include/gtest/gtest.h"
18#include "third_party/libjingle/source/talk/app/webrtc/mediastreaminterface.h"
19
20using ::testing::_;
21using ::testing::AnyNumber;
22using ::testing::AtLeast;
23using ::testing::Return;
24
25namespace content {
26
27namespace {
28
29#if defined(ANDROID)
30const int kAudioProcessingSampleRate = 16000;
31#else
32const int kAudioProcessingSampleRate = 32000;
33#endif
34const int kAudioProcessingNumberOfChannel = 1;
35
36// The number of packers used for testing.
37const int kNumberOfPacketsForTest = 100;
38
39void ReadDataFromSpeechFile(char* data, int length) {
40  base::FilePath file;
41  CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &file));
42  file = file.Append(FILE_PATH_LITERAL("media"))
43             .Append(FILE_PATH_LITERAL("test"))
44             .Append(FILE_PATH_LITERAL("data"))
45             .Append(FILE_PATH_LITERAL("speech_16b_stereo_48kHz.raw"));
46  DCHECK(base::PathExists(file));
47  int64 data_file_size64 = 0;
48  DCHECK(base::GetFileSize(file, &data_file_size64));
49  EXPECT_EQ(length, base::ReadFile(file, data, length));
50  DCHECK(data_file_size64 > length);
51}
52
53void ApplyFixedAudioConstraints(RTCMediaConstraints* constraints) {
54  // Constant constraint keys which enables default audio constraints on
55  // mediastreams with audio.
56  struct {
57    const char* key;
58    const char* value;
59  } static const kDefaultAudioConstraints[] = {
60    { webrtc::MediaConstraintsInterface::kEchoCancellation,
61      webrtc::MediaConstraintsInterface::kValueTrue },
62  #if defined(OS_CHROMEOS) || defined(OS_MACOSX)
63    // Enable the extended filter mode AEC on platforms with known echo issues.
64    { webrtc::MediaConstraintsInterface::kExperimentalEchoCancellation,
65      webrtc::MediaConstraintsInterface::kValueTrue },
66  #endif
67    { webrtc::MediaConstraintsInterface::kAutoGainControl,
68      webrtc::MediaConstraintsInterface::kValueTrue },
69    { webrtc::MediaConstraintsInterface::kExperimentalAutoGainControl,
70      webrtc::MediaConstraintsInterface::kValueTrue },
71    { webrtc::MediaConstraintsInterface::kNoiseSuppression,
72      webrtc::MediaConstraintsInterface::kValueTrue },
73    { webrtc::MediaConstraintsInterface::kHighpassFilter,
74      webrtc::MediaConstraintsInterface::kValueTrue },
75  };
76
77  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kDefaultAudioConstraints); ++i) {
78    constraints->AddMandatory(kDefaultAudioConstraints[i].key,
79                              kDefaultAudioConstraints[i].value, false);
80  }
81}
82
83}  // namespace
84
85class MediaStreamAudioProcessorTest : public ::testing::Test {
86 public:
87  MediaStreamAudioProcessorTest()
88      : params_(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
89                media::CHANNEL_LAYOUT_STEREO, 48000, 16, 512) {
90    CommandLine::ForCurrentProcess()->AppendSwitch(
91        switches::kEnableAudioTrackProcessing);
92  }
93
94 protected:
95  // Helper method to save duplicated code.
96  void ProcessDataAndVerifyFormat(MediaStreamAudioProcessor* audio_processor,
97                                  int expected_output_sample_rate,
98                                  int expected_output_channels,
99                                  int expected_output_buffer_size) {
100    // Read the audio data from a file.
101    const int packet_size =
102        params_.frames_per_buffer() * 2 * params_.channels();
103    const size_t length = packet_size * kNumberOfPacketsForTest;
104    scoped_ptr<char[]> capture_data(new char[length]);
105    ReadDataFromSpeechFile(capture_data.get(), length);
106    const int16* data_ptr = reinterpret_cast<const int16*>(capture_data.get());
107    scoped_ptr<media::AudioBus> data_bus = media::AudioBus::Create(
108        params_.channels(), params_.frames_per_buffer());
109    for (int i = 0; i < kNumberOfPacketsForTest; ++i) {
110      data_bus->FromInterleaved(data_ptr, data_bus->frames(), 2);
111      audio_processor->PushCaptureData(data_bus.get());
112
113      // |audio_processor| does nothing when the audio processing is off in
114      // the processor.
115      audio_processor->PushRenderData(
116          data_ptr,
117          params_.sample_rate(), params_.channels(),
118          params_.frames_per_buffer(), base::TimeDelta::FromMilliseconds(10));
119
120      int16* output = NULL;
121      while(audio_processor->ProcessAndConsumeData(
122          base::TimeDelta::FromMilliseconds(10), 255, false, &output)) {
123        EXPECT_TRUE(output != NULL);
124        EXPECT_EQ(audio_processor->OutputFormat().sample_rate(),
125                  expected_output_sample_rate);
126        EXPECT_EQ(audio_processor->OutputFormat().channels(),
127                  expected_output_channels);
128        EXPECT_EQ(audio_processor->OutputFormat().frames_per_buffer(),
129                  expected_output_buffer_size);
130      }
131
132      data_ptr += params_.frames_per_buffer() * params_.channels();
133    }
134  }
135
136  media::AudioParameters params_;
137};
138
139TEST_F(MediaStreamAudioProcessorTest, WithoutAudioProcessing) {
140  // Setup the audio processor with empty constraint.
141  RTCMediaConstraints constraints;
142  MediaStreamAudioProcessor audio_processor(&constraints);
143  audio_processor.SetCaptureFormat(params_);
144  EXPECT_FALSE(audio_processor.has_audio_processing());
145
146  ProcessDataAndVerifyFormat(&audio_processor,
147                             params_.sample_rate(),
148                             params_.channels(),
149                             params_.sample_rate() / 100);
150}
151
152TEST_F(MediaStreamAudioProcessorTest, WithAudioProcessing) {
153  // Setup the audio processor with default constraint.
154  RTCMediaConstraints constraints;
155  ApplyFixedAudioConstraints(&constraints);
156  MediaStreamAudioProcessor audio_processor(&constraints);
157  audio_processor.SetCaptureFormat(params_);
158  EXPECT_TRUE(audio_processor.has_audio_processing());
159
160  ProcessDataAndVerifyFormat(&audio_processor,
161                             kAudioProcessingSampleRate,
162                             kAudioProcessingNumberOfChannel,
163                             kAudioProcessingSampleRate / 100);
164}
165
166}  // namespace content
167