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