• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/logging.h"
6 #include "content/renderer/media/rtc_media_constraints.h"
7 #include "content/renderer/media/webrtc_audio_capturer.h"
8 #include "content/renderer/media/webrtc_local_audio_track.h"
9 #include "media/audio/audio_parameters.h"
10 #include "media/base/audio_bus.h"
11 #include "testing/gmock/include/gmock/gmock.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 
14 using ::testing::_;
15 using ::testing::AtLeast;
16 
17 namespace content {
18 
19 namespace {
20 
21 // TODO(xians): Consolidate the similar methods in different unittests into
22 // one.
ApplyFixedAudioConstraints(RTCMediaConstraints * constraints)23 void ApplyFixedAudioConstraints(RTCMediaConstraints* constraints) {
24   // Constant constraint keys which enables default audio constraints on
25   // mediastreams with audio.
26   struct {
27     const char* key;
28     const char* value;
29   } static const kDefaultAudioConstraints[] = {
30     { webrtc::MediaConstraintsInterface::kEchoCancellation,
31       webrtc::MediaConstraintsInterface::kValueTrue },
32   #if defined(OS_CHROMEOS) || defined(OS_MACOSX)
33     // Enable the extended filter mode AEC on platforms with known echo issues.
34     { webrtc::MediaConstraintsInterface::kExperimentalEchoCancellation,
35       webrtc::MediaConstraintsInterface::kValueTrue },
36   #endif
37     { webrtc::MediaConstraintsInterface::kAutoGainControl,
38       webrtc::MediaConstraintsInterface::kValueTrue },
39     { webrtc::MediaConstraintsInterface::kExperimentalAutoGainControl,
40       webrtc::MediaConstraintsInterface::kValueTrue },
41     { webrtc::MediaConstraintsInterface::kNoiseSuppression,
42       webrtc::MediaConstraintsInterface::kValueTrue },
43     { webrtc::MediaConstraintsInterface::kHighpassFilter,
44       webrtc::MediaConstraintsInterface::kValueTrue },
45   };
46 
47   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kDefaultAudioConstraints); ++i) {
48     constraints->AddMandatory(kDefaultAudioConstraints[i].key,
49                               kDefaultAudioConstraints[i].value, false);
50   }
51 }
52 
53 class MockCapturerSource : public media::AudioCapturerSource {
54  public:
MockCapturerSource()55   MockCapturerSource() {}
56   MOCK_METHOD3(Initialize, void(const media::AudioParameters& params,
57                                 CaptureCallback* callback,
58                                 int session_id));
59   MOCK_METHOD0(Start, void());
60   MOCK_METHOD0(Stop, void());
61   MOCK_METHOD1(SetVolume, void(double volume));
62   MOCK_METHOD1(SetAutomaticGainControl, void(bool enable));
63 
64  protected:
~MockCapturerSource()65   virtual ~MockCapturerSource() {}
66 };
67 
68 class MockPeerConnectionAudioSink : public PeerConnectionAudioSink {
69  public:
MockPeerConnectionAudioSink()70   MockPeerConnectionAudioSink() {}
~MockPeerConnectionAudioSink()71   ~MockPeerConnectionAudioSink() {}
72   MOCK_METHOD9(OnData, int(const int16* audio_data,
73                            int sample_rate,
74                            int number_of_channels,
75                            int number_of_frames,
76                            const std::vector<int>& channels,
77                            int audio_delay_milliseconds,
78                            int current_volume,
79                            bool need_audio_processing,
80                            bool key_pressed));
81   MOCK_METHOD1(OnSetFormat, void(const media::AudioParameters& params));
82 };
83 
84 }  // namespace
85 
86 class WebRtcAudioCapturerTest : public testing::Test {
87  protected:
WebRtcAudioCapturerTest()88   WebRtcAudioCapturerTest()
89 #if defined(OS_ANDROID)
90       : params_(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
91                 media::CHANNEL_LAYOUT_STEREO, 48000, 16, 960) {
92     // Android works with a buffer size bigger than 20ms.
93 #else
94       : params_(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
95                 media::CHANNEL_LAYOUT_STEREO, 48000, 16, 128) {
96 #endif
97     capturer_ = WebRtcAudioCapturer::CreateCapturer();
98     capturer_->Initialize(-1, params_.channel_layout(), params_.sample_rate(),
99                           params_.frames_per_buffer(), 0, std::string(), 0, 0,
100                           params_.effects());
101     capturer_source_ = new MockCapturerSource();
102     EXPECT_CALL(*capturer_source_.get(), Initialize(_, capturer_.get(), 0));
103     capturer_->SetCapturerSource(capturer_source_,
104                                  params_.channel_layout(),
105                                  params_.sample_rate(),
106                                  params_.effects());
107 
108     EXPECT_CALL(*capturer_source_.get(), SetAutomaticGainControl(true));
109     EXPECT_CALL(*capturer_source_.get(), Start());
110     RTCMediaConstraints constraints;
111     ApplyFixedAudioConstraints(&constraints);
112     track_ = WebRtcLocalAudioTrack::Create(std::string(), capturer_, NULL,
113                                            NULL, &constraints);
114     static_cast<WebRtcLocalAudioSourceProvider*>(
115         track_->audio_source_provider())->SetSinkParamsForTesting(params_);
116     track_->Start();
117     EXPECT_TRUE(track_->enabled());
118   }
119 
120   media::AudioParameters params_;
121   scoped_refptr<MockCapturerSource> capturer_source_;
122   scoped_refptr<WebRtcAudioCapturer> capturer_;
123   scoped_refptr<WebRtcLocalAudioTrack> track_;
124 };
125 
126 // Pass the delay value, vollume and key_pressed info via capture callback, and
127 // those values should be correctly stored and passed to the track.
TEST_F(WebRtcAudioCapturerTest,VerifyAudioParams)128 TEST_F(WebRtcAudioCapturerTest, VerifyAudioParams) {
129   // Connect a mock sink to the track.
130   scoped_ptr<MockPeerConnectionAudioSink> sink(
131       new MockPeerConnectionAudioSink());
132   track_->AddSink(sink.get());
133 
134   int delay_ms = 65;
135   bool key_pressed = true;
136   double volume = 0.9;
137   // MaxVolume() in WebRtcAudioCapturer is hard-coded to return 255, we add 0.5
138   // to do the correct truncation as how the production code does.
139   int expected_volume_value = volume * capturer_->MaxVolume() + 0.5;
140   scoped_ptr<media::AudioBus> audio_bus = media::AudioBus::Create(params_);
141   audio_bus->Zero();
142 #if defined(OS_ANDROID)
143   const int expected_buffer_size = params_.sample_rate() / 100;
144 #else
145   const int expected_buffer_size = params_.frames_per_buffer();
146 #endif
147   bool expected_need_audio_processing = true;
148   media::AudioCapturerSource::CaptureCallback* callback =
149       static_cast<media::AudioCapturerSource::CaptureCallback*>(capturer_);
150   // Verify the sink is getting the correct values.
151   EXPECT_CALL(*sink, OnSetFormat(_));
152   EXPECT_CALL(*sink,
153               OnData(_, params_.sample_rate(), params_.channels(),
154                      expected_buffer_size, _, delay_ms,
155                      expected_volume_value, expected_need_audio_processing,
156                      key_pressed)).Times(AtLeast(1));
157   callback->Capture(audio_bus.get(), delay_ms, volume, key_pressed);
158 
159   // Verify the cached values in the capturer fits what we expect.
160   base::TimeDelta cached_delay;
161   int cached_volume = !expected_volume_value;
162   bool cached_key_pressed = !key_pressed;
163   capturer_->GetAudioProcessingParams(&cached_delay, &cached_volume,
164                                       &cached_key_pressed);
165   EXPECT_EQ(cached_delay.InMilliseconds(), delay_ms);
166   EXPECT_EQ(cached_volume, expected_volume_value);
167   EXPECT_EQ(cached_key_pressed, key_pressed);
168 
169   track_->RemoveSink(sink.get());
170   EXPECT_CALL(*capturer_source_.get(), Stop());
171   capturer_->Stop();
172 }
173 
174 }  // namespace content
175