1 // Copyright 2016 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 "content/renderer/media/renderer_webaudiodevice_impl.h"
6
7 #include "base/bind.h"
8 #include "base/strings/stringprintf.h"
9 #include "base/test/task_environment.h"
10 #include "base/threading/thread_task_runner_handle.h"
11 #include "build/build_config.h"
12 #include "content/renderer/media/audio/audio_device_factory.h"
13 #include "media/base/audio_capturer_source.h"
14 #include "media/base/limits.h"
15 #include "media/base/mock_audio_renderer_sink.h"
16 #include "testing/gmock/include/gmock/gmock.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
19
20 using testing::_;
21
22 namespace content {
23
24 namespace {
25
26 const int kHardwareSampleRate = 44100;
27 const int kHardwareBufferSize = 128;
28 const int kRenderFrameId = 100;
29
MockFrameIdFromCurrentContext()30 int MockFrameIdFromCurrentContext() {
31 return kRenderFrameId;
32 }
33
MockGetOutputDeviceParameters(int frame_id,const base::UnguessableToken & session_id,const std::string & device_id)34 media::AudioParameters MockGetOutputDeviceParameters(
35 int frame_id,
36 const base::UnguessableToken& session_id,
37 const std::string& device_id) {
38 return media::AudioParameters(media::AudioParameters::AUDIO_PCM_LOW_LATENCY,
39 media::CHANNEL_LAYOUT_STEREO,
40 kHardwareSampleRate, kHardwareBufferSize);
41 }
42
43 class RendererWebAudioDeviceImplUnderTest : public RendererWebAudioDeviceImpl {
44 public:
RendererWebAudioDeviceImplUnderTest(media::ChannelLayout layout,int channels,const blink::WebAudioLatencyHint & latency_hint,blink::WebAudioDevice::RenderCallback * callback,const base::UnguessableToken & session_id)45 RendererWebAudioDeviceImplUnderTest(
46 media::ChannelLayout layout,
47 int channels,
48 const blink::WebAudioLatencyHint& latency_hint,
49 blink::WebAudioDevice::RenderCallback* callback,
50 const base::UnguessableToken& session_id)
51 : RendererWebAudioDeviceImpl(
52 layout,
53 channels,
54 latency_hint,
55 callback,
56 session_id,
57 base::BindOnce(&MockGetOutputDeviceParameters),
58 base::BindOnce(&MockFrameIdFromCurrentContext)) {}
59 };
60
61 } // namespace
62
63 class RendererWebAudioDeviceImplTest
64 : public blink::WebAudioDevice::RenderCallback,
65 public AudioDeviceFactory,
66 public testing::Test {
67 protected:
RendererWebAudioDeviceImplTest()68 RendererWebAudioDeviceImplTest() {}
69
SetupDevice(blink::WebAudioLatencyHint latencyHint)70 void SetupDevice(blink::WebAudioLatencyHint latencyHint) {
71 webaudio_device_.reset(new RendererWebAudioDeviceImplUnderTest(
72 media::CHANNEL_LAYOUT_MONO, 1, latencyHint, this,
73 base::UnguessableToken()));
74 webaudio_device_->SetMediaTaskRunnerForTesting(
75 blink::scheduler::GetSingleThreadTaskRunnerForTesting());
76 }
77
SetupDevice(media::ChannelLayout layout,int channels)78 void SetupDevice(media::ChannelLayout layout, int channels) {
79 webaudio_device_.reset(new RendererWebAudioDeviceImplUnderTest(
80 layout, channels,
81 blink::WebAudioLatencyHint(
82 blink::WebAudioLatencyHint::kCategoryInteractive),
83 this, base::UnguessableToken()));
84 webaudio_device_->SetMediaTaskRunnerForTesting(
85 blink::scheduler::GetSingleThreadTaskRunnerForTesting());
86 }
87
88 MOCK_METHOD2(CreateAudioCapturerSource,
89 scoped_refptr<media::AudioCapturerSource>(
90 int,
91 const media::AudioSourceParameters&));
92 MOCK_METHOD3(
93 CreateFinalAudioRendererSink,
94 scoped_refptr<media::AudioRendererSink>(int,
95 const media::AudioSinkParameters&,
96 base::TimeDelta));
97 MOCK_METHOD3(CreateSwitchableAudioRendererSink,
98 scoped_refptr<media::SwitchableAudioRendererSink>(
99 blink::WebAudioDeviceSourceType,
100 int,
101 const media::AudioSinkParameters&));
102
CreateAudioRendererSink(blink::WebAudioDeviceSourceType source_type,int render_frame_id,const media::AudioSinkParameters & params)103 scoped_refptr<media::AudioRendererSink> CreateAudioRendererSink(
104 blink::WebAudioDeviceSourceType source_type,
105 int render_frame_id,
106 const media::AudioSinkParameters& params) override {
107 scoped_refptr<media::MockAudioRendererSink> mock_sink =
108 new media::MockAudioRendererSink(
109 params.device_id, media::OUTPUT_DEVICE_STATUS_OK,
110 MockGetOutputDeviceParameters(render_frame_id, params.session_id,
111 params.device_id));
112
113 EXPECT_CALL(*mock_sink.get(), Start());
114 EXPECT_CALL(*mock_sink.get(), Play());
115 EXPECT_CALL(*mock_sink.get(), Stop());
116
117 return mock_sink;
118 }
119
TearDown()120 void TearDown() override { webaudio_device_.reset(); }
121
122 std::unique_ptr<RendererWebAudioDeviceImpl> webaudio_device_;
123 base::test::SingleThreadTaskEnvironment task_environment_;
124 };
125
TEST_F(RendererWebAudioDeviceImplTest,ChannelLayout)126 TEST_F(RendererWebAudioDeviceImplTest, ChannelLayout) {
127 for (int ch = 1; ch < static_cast<int>(media::limits::kMaxChannels); ++ch) {
128 SCOPED_TRACE(base::StringPrintf("ch == %d", ch));
129
130 media::ChannelLayout layout = media::GuessChannelLayout(ch);
131 if (layout == media::CHANNEL_LAYOUT_UNSUPPORTED)
132 layout = media::CHANNEL_LAYOUT_DISCRETE;
133
134 SetupDevice(layout, ch);
135 media::AudioParameters sink_params =
136 webaudio_device_->get_sink_params_for_testing();
137 EXPECT_TRUE(sink_params.IsValid());
138 EXPECT_EQ(layout, sink_params.channel_layout());
139 EXPECT_EQ(ch, sink_params.channels());
140 }
141 }
142
TEST_F(RendererWebAudioDeviceImplTest,TestLatencyHintValues)143 TEST_F(RendererWebAudioDeviceImplTest, TestLatencyHintValues) {
144 blink::WebAudioLatencyHint interactiveLatencyHint(
145 blink::WebAudioLatencyHint::kCategoryInteractive);
146 int interactiveBufferSize =
147 media::AudioLatency::GetInteractiveBufferSize(kHardwareBufferSize);
148 SetupDevice(interactiveLatencyHint);
149
150 EXPECT_EQ(webaudio_device_->SampleRate(), kHardwareSampleRate);
151 EXPECT_EQ(webaudio_device_->FramesPerBuffer(), interactiveBufferSize);
152
153 webaudio_device_->Start();
154 EXPECT_EQ(webaudio_device_->SampleRate(), kHardwareSampleRate);
155 EXPECT_EQ(webaudio_device_->FramesPerBuffer(), interactiveBufferSize);
156
157 webaudio_device_->Stop();
158 EXPECT_EQ(webaudio_device_->SampleRate(), kHardwareSampleRate);
159 EXPECT_EQ(webaudio_device_->FramesPerBuffer(), interactiveBufferSize);
160
161 webaudio_device_->Start();
162 EXPECT_EQ(webaudio_device_->SampleRate(), kHardwareSampleRate);
163 EXPECT_EQ(webaudio_device_->FramesPerBuffer(), interactiveBufferSize);
164
165 webaudio_device_->Stop();
166 EXPECT_EQ(webaudio_device_->SampleRate(), kHardwareSampleRate);
167 EXPECT_EQ(webaudio_device_->FramesPerBuffer(), interactiveBufferSize);
168
169 blink::WebAudioLatencyHint balancedLatencyHint(
170 blink::WebAudioLatencyHint::kCategoryBalanced);
171 int balancedBufferSize = media::AudioLatency::GetRtcBufferSize(
172 kHardwareSampleRate, kHardwareBufferSize);
173 SetupDevice(balancedLatencyHint);
174
175 EXPECT_EQ(webaudio_device_->SampleRate(), kHardwareSampleRate);
176 EXPECT_EQ(webaudio_device_->FramesPerBuffer(), balancedBufferSize);
177
178 webaudio_device_->Start();
179 EXPECT_EQ(webaudio_device_->SampleRate(), kHardwareSampleRate);
180 EXPECT_EQ(webaudio_device_->FramesPerBuffer(), balancedBufferSize);
181
182 webaudio_device_->Stop();
183 EXPECT_EQ(webaudio_device_->SampleRate(), kHardwareSampleRate);
184 EXPECT_EQ(webaudio_device_->FramesPerBuffer(), balancedBufferSize);
185
186 webaudio_device_->Start();
187 EXPECT_EQ(webaudio_device_->SampleRate(), kHardwareSampleRate);
188 EXPECT_EQ(webaudio_device_->FramesPerBuffer(), balancedBufferSize);
189
190 webaudio_device_->Stop();
191 EXPECT_EQ(webaudio_device_->SampleRate(), kHardwareSampleRate);
192 EXPECT_EQ(webaudio_device_->FramesPerBuffer(), balancedBufferSize);
193
194 blink::WebAudioLatencyHint playbackLatencyHint(
195 blink::WebAudioLatencyHint::kCategoryPlayback);
196 int playbackBufferSize = media::AudioLatency::GetHighLatencyBufferSize(
197 kHardwareSampleRate, kHardwareBufferSize);
198 SetupDevice(playbackLatencyHint);
199
200 EXPECT_EQ(webaudio_device_->SampleRate(), kHardwareSampleRate);
201 EXPECT_EQ(webaudio_device_->FramesPerBuffer(), playbackBufferSize);
202
203 webaudio_device_->Start();
204 EXPECT_EQ(webaudio_device_->SampleRate(), kHardwareSampleRate);
205 EXPECT_EQ(webaudio_device_->FramesPerBuffer(), playbackBufferSize);
206
207 webaudio_device_->Stop();
208 EXPECT_EQ(webaudio_device_->SampleRate(), kHardwareSampleRate);
209 EXPECT_EQ(webaudio_device_->FramesPerBuffer(), playbackBufferSize);
210
211 webaudio_device_->Start();
212 EXPECT_EQ(webaudio_device_->SampleRate(), kHardwareSampleRate);
213 EXPECT_EQ(webaudio_device_->FramesPerBuffer(), playbackBufferSize);
214
215 webaudio_device_->Stop();
216 EXPECT_EQ(webaudio_device_->SampleRate(), kHardwareSampleRate);
217 EXPECT_EQ(webaudio_device_->FramesPerBuffer(), playbackBufferSize);
218
219 EXPECT_GE(playbackBufferSize, balancedBufferSize);
220 EXPECT_GE(balancedBufferSize, interactiveBufferSize);
221 }
222
223 } // namespace content
224