| // Copyright 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "third_party/blink/renderer/modules/webaudio/audio_context.h" |
| |
| #include <memory> |
| |
| #include "build/build_config.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/blink/public/platform/platform.h" |
| #include "third_party/blink/public/platform/web_audio_device.h" |
| #include "third_party/blink/public/platform/web_audio_latency_hint.h" |
| #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h" |
| #include "third_party/blink/renderer/bindings/modules/v8/v8_audio_context_options.h" |
| #include "third_party/blink/renderer/core/dom/document.h" |
| #include "third_party/blink/renderer/core/frame/frame_test_helpers.h" |
| #include "third_party/blink/renderer/core/frame/frame_types.h" |
| #include "third_party/blink/renderer/core/frame/local_frame.h" |
| #include "third_party/blink/renderer/core/frame/settings.h" |
| #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" |
| #include "third_party/blink/renderer/core/html/media/autoplay_policy.h" |
| #include "third_party/blink/renderer/core/loader/empty_clients.h" |
| #include "third_party/blink/renderer/platform/testing/histogram_tester.h" |
| #include "third_party/blink/renderer/platform/testing/testing_platform_support.h" |
| #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" |
| |
| namespace blink { |
| |
| namespace { |
| |
| const char* const kAutoplayMetric = "WebAudio.Autoplay"; |
| const char* const kAutoplayCrossOriginMetric = "WebAudio.Autoplay.CrossOrigin"; |
| |
| class MockWebAudioDeviceForAutoplayTest : public WebAudioDevice { |
| public: |
| explicit MockWebAudioDeviceForAutoplayTest(double sample_rate, |
| int frames_per_buffer) |
| : sample_rate_(sample_rate), frames_per_buffer_(frames_per_buffer) {} |
| ~MockWebAudioDeviceForAutoplayTest() override = default; |
| |
| void Start() override {} |
| void Stop() override {} |
| void Pause() override {} |
| void Resume() override {} |
| double SampleRate() override { return sample_rate_; } |
| int FramesPerBuffer() override { return frames_per_buffer_; } |
| |
| private: |
| double sample_rate_; |
| int frames_per_buffer_; |
| }; |
| |
| class AudioContextAutoplayTestPlatform : public TestingPlatformSupport { |
| public: |
| std::unique_ptr<WebAudioDevice> CreateAudioDevice( |
| unsigned number_of_input_channels, |
| unsigned number_of_channels, |
| const WebAudioLatencyHint& latency_hint, |
| WebAudioDevice::RenderCallback*, |
| const WebString& device_id) override { |
| return std::make_unique<MockWebAudioDeviceForAutoplayTest>( |
| AudioHardwareSampleRate(), AudioHardwareBufferSize()); |
| } |
| |
| double AudioHardwareSampleRate() override { return 44100; } |
| size_t AudioHardwareBufferSize() override { return 128; } |
| }; |
| |
| } // anonymous namespace |
| |
| class AudioContextAutoplayTest |
| : public testing::TestWithParam<AutoplayPolicy::Type> { |
| protected: |
| using AutoplayStatus = AudioContext::AutoplayStatus; |
| |
| void SetUp() override { |
| helper_.Initialize(); |
| frame_test_helpers::LoadHTMLString(helper_.LocalMainFrame(), |
| "<iframe></iframe>", |
| WebURL(KURL("https://example.com"))); |
| frame_test_helpers::LoadHTMLString( |
| To<WebLocalFrameImpl>(helper_.LocalMainFrame()->FirstChild()), "", |
| WebURL(KURL("https://cross-origin.com"))); |
| GetDocument().GetSettings()->SetAutoplayPolicy(GetParam()); |
| ChildDocument().GetSettings()->SetAutoplayPolicy(GetParam()); |
| |
| histogram_tester_ = std::make_unique<HistogramTester>(); |
| } |
| |
| Document& GetDocument() { |
| return *helper_.LocalMainFrame()->GetFrame()->GetDocument(); |
| } |
| |
| Document& ChildDocument() { |
| return *To<WebLocalFrameImpl>(helper_.LocalMainFrame()->FirstChild()) |
| ->GetFrame() |
| ->GetDocument(); |
| } |
| |
| ScriptState* GetScriptStateFrom(const Document& document) { |
| return ToScriptStateForMainWorld(document.GetFrame()); |
| } |
| |
| void RejectPendingResolvers(AudioContext* audio_context) { |
| audio_context->RejectPendingResolvers(); |
| } |
| |
| void RecordAutoplayStatus(AudioContext* audio_context) { |
| audio_context->RecordAutoplayMetrics(); |
| } |
| |
| HistogramTester* GetHistogramTester() { |
| return histogram_tester_.get(); |
| } |
| |
| private: |
| ScopedTestingPlatformSupport<AudioContextAutoplayTestPlatform> platform_; |
| frame_test_helpers::WebViewHelper helper_; |
| std::unique_ptr<HistogramTester> histogram_tester_; |
| }; |
| |
| // Creates an AudioContext without a gesture inside a x-origin child frame. |
| TEST_P(AudioContextAutoplayTest, AutoplayMetrics_CreateNoGesture_Child) { |
| AudioContext* audio_context = AudioContext::Create( |
| ChildDocument(), AudioContextOptions::Create(), ASSERT_NO_EXCEPTION); |
| RecordAutoplayStatus(audio_context); |
| |
| switch (GetParam()) { |
| case AutoplayPolicy::Type::kNoUserGestureRequired: |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 0); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 0); |
| break; |
| case AutoplayPolicy::Type::kUserGestureRequired: |
| case AutoplayPolicy::Type::kDocumentUserActivationRequired: |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayMetric, static_cast<int>(AutoplayStatus::kFailed), 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 1); |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayCrossOriginMetric, static_cast<int>(AutoplayStatus::kFailed), |
| 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 1); |
| break; |
| } |
| } |
| |
| // Creates an AudioContext without a gesture inside a main frame. |
| TEST_P(AudioContextAutoplayTest, AutoplayMetrics_CreateNoGesture_Main) { |
| AudioContext* audio_context = AudioContext::Create( |
| GetDocument(), AudioContextOptions::Create(), ASSERT_NO_EXCEPTION); |
| RecordAutoplayStatus(audio_context); |
| |
| switch (GetParam()) { |
| case AutoplayPolicy::Type::kNoUserGestureRequired: |
| case AutoplayPolicy::Type::kUserGestureRequired: |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 0); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 0); |
| break; |
| case AutoplayPolicy::Type::kDocumentUserActivationRequired: |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayMetric, static_cast<int>(AutoplayStatus::kFailed), 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 0); |
| break; |
| } |
| } |
| |
| // Creates an AudioContext then call resume without a gesture in a x-origin |
| // child frame. |
| TEST_P(AudioContextAutoplayTest, |
| AutoplayMetrics_CallResumeNoGesture_Child) { |
| ScriptState::Scope scope(GetScriptStateFrom(ChildDocument())); |
| |
| AudioContext* audio_context = AudioContext::Create( |
| ChildDocument(), AudioContextOptions::Create(), ASSERT_NO_EXCEPTION); |
| audio_context->resumeContext(GetScriptStateFrom(ChildDocument()), |
| ASSERT_NO_EXCEPTION); |
| RejectPendingResolvers(audio_context); |
| RecordAutoplayStatus(audio_context); |
| |
| switch (GetParam()) { |
| case AutoplayPolicy::Type::kNoUserGestureRequired: |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 0); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 0); |
| break; |
| case AutoplayPolicy::Type::kUserGestureRequired: |
| case AutoplayPolicy::Type::kDocumentUserActivationRequired: |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayMetric, static_cast<int>(AutoplayStatus::kFailed), 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 1); |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayCrossOriginMetric, static_cast<int>(AutoplayStatus::kFailed), |
| 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 1); |
| break; |
| } |
| } |
| |
| // Creates an AudioContext then call resume without a gesture in a main frame. |
| TEST_P(AudioContextAutoplayTest, AutoplayMetrics_CallResumeNoGesture_Main) { |
| ScriptState::Scope scope(GetScriptStateFrom(GetDocument())); |
| |
| AudioContext* audio_context = AudioContext::Create( |
| GetDocument(), AudioContextOptions::Create(), ASSERT_NO_EXCEPTION); |
| audio_context->resumeContext(GetScriptStateFrom(ChildDocument()), |
| ASSERT_NO_EXCEPTION); |
| RejectPendingResolvers(audio_context); |
| RecordAutoplayStatus(audio_context); |
| |
| switch (GetParam()) { |
| case AutoplayPolicy::Type::kNoUserGestureRequired: |
| case AutoplayPolicy::Type::kUserGestureRequired: |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 0); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 0); |
| break; |
| case AutoplayPolicy::Type::kDocumentUserActivationRequired: |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayMetric, static_cast<int>(AutoplayStatus::kFailed), 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 0); |
| break; |
| } |
| } |
| |
| // Creates an AudioContext with a user gesture inside a x-origin child frame. |
| TEST_P(AudioContextAutoplayTest, AutoplayMetrics_CreateGesture_Child) { |
| LocalFrame::NotifyUserActivation( |
| ChildDocument().GetFrame(), mojom::UserActivationNotificationType::kTest); |
| |
| AudioContext* audio_context = AudioContext::Create( |
| ChildDocument(), AudioContextOptions::Create(), ASSERT_NO_EXCEPTION); |
| RecordAutoplayStatus(audio_context); |
| |
| switch (GetParam()) { |
| case AutoplayPolicy::Type::kNoUserGestureRequired: |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 0); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 0); |
| break; |
| case AutoplayPolicy::Type::kUserGestureRequired: |
| case AutoplayPolicy::Type::kDocumentUserActivationRequired: |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayMetric, static_cast<int>(AutoplayStatus::kSucceeded), 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 1); |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayCrossOriginMetric, |
| static_cast<int>(AutoplayStatus::kSucceeded), 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 1); |
| break; |
| } |
| } |
| |
| // Creates an AudioContext with a user gesture inside a main frame. |
| TEST_P(AudioContextAutoplayTest, AutoplayMetrics_CreateGesture_Main) { |
| LocalFrame::NotifyUserActivation( |
| GetDocument().GetFrame(), mojom::UserActivationNotificationType::kTest); |
| |
| AudioContext* audio_context = AudioContext::Create( |
| GetDocument(), AudioContextOptions::Create(), ASSERT_NO_EXCEPTION); |
| RecordAutoplayStatus(audio_context); |
| |
| switch (GetParam()) { |
| case AutoplayPolicy::Type::kNoUserGestureRequired: |
| case AutoplayPolicy::Type::kUserGestureRequired: |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 0); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 0); |
| break; |
| case AutoplayPolicy::Type::kDocumentUserActivationRequired: |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayMetric, static_cast<int>(AutoplayStatus::kSucceeded), 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 0); |
| break; |
| } |
| } |
| |
| // Creates an AudioContext then calls resume with a user gesture inside a |
| // x-origin child frame. |
| TEST_P(AudioContextAutoplayTest, AutoplayMetrics_CallResumeGesture_Child) { |
| ScriptState::Scope scope(GetScriptStateFrom(ChildDocument())); |
| |
| AudioContext* audio_context = AudioContext::Create( |
| ChildDocument(), AudioContextOptions::Create(), ASSERT_NO_EXCEPTION); |
| |
| LocalFrame::NotifyUserActivation( |
| ChildDocument().GetFrame(), mojom::UserActivationNotificationType::kTest); |
| |
| audio_context->resumeContext(GetScriptStateFrom(ChildDocument()), |
| ASSERT_NO_EXCEPTION); |
| RejectPendingResolvers(audio_context); |
| RecordAutoplayStatus(audio_context); |
| |
| switch (GetParam()) { |
| case AutoplayPolicy::Type::kNoUserGestureRequired: |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 0); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 0); |
| break; |
| case AutoplayPolicy::Type::kUserGestureRequired: |
| case AutoplayPolicy::Type::kDocumentUserActivationRequired: |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayMetric, static_cast<int>(AutoplayStatus::kSucceeded), 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 1); |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayCrossOriginMetric, |
| static_cast<int>(AutoplayStatus::kSucceeded), 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 1); |
| break; |
| } |
| } |
| |
| // Creates an AudioContext then calls resume with a user gesture inside a main |
| // frame. |
| TEST_P(AudioContextAutoplayTest, AutoplayMetrics_CallResumeGesture_Main) { |
| ScriptState::Scope scope(GetScriptStateFrom(GetDocument())); |
| |
| AudioContext* audio_context = AudioContext::Create( |
| GetDocument(), AudioContextOptions::Create(), ASSERT_NO_EXCEPTION); |
| |
| LocalFrame::NotifyUserActivation( |
| GetDocument().GetFrame(), mojom::UserActivationNotificationType::kTest); |
| |
| audio_context->resumeContext(GetScriptStateFrom(GetDocument()), |
| ASSERT_NO_EXCEPTION); |
| RejectPendingResolvers(audio_context); |
| RecordAutoplayStatus(audio_context); |
| |
| switch (GetParam()) { |
| case AutoplayPolicy::Type::kNoUserGestureRequired: |
| case AutoplayPolicy::Type::kUserGestureRequired: |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 0); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 0); |
| break; |
| case AutoplayPolicy::Type::kDocumentUserActivationRequired: |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayMetric, static_cast<int>(AutoplayStatus::kSucceeded), 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 0); |
| break; |
| } |
| } |
| |
| // Creates an AudioContext then calls start on a node without a gesture inside a |
| // x-origin child frame. |
| TEST_P(AudioContextAutoplayTest, AutoplayMetrics_NodeStartNoGesture_Child) { |
| AudioContext* audio_context = AudioContext::Create( |
| ChildDocument(), AudioContextOptions::Create(), ASSERT_NO_EXCEPTION); |
| audio_context->NotifySourceNodeStart(); |
| RecordAutoplayStatus(audio_context); |
| |
| switch (GetParam()) { |
| case AutoplayPolicy::Type::kNoUserGestureRequired: |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 0); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 0); |
| break; |
| case AutoplayPolicy::Type::kUserGestureRequired: |
| case AutoplayPolicy::Type::kDocumentUserActivationRequired: |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayMetric, static_cast<int>(AutoplayStatus::kFailed), 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 1); |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayCrossOriginMetric, static_cast<int>(AutoplayStatus::kFailed), |
| 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 1); |
| break; |
| } |
| } |
| |
| // Creates an AudioContext then calls start on a node without a gesture inside a |
| // main frame. |
| TEST_P(AudioContextAutoplayTest, AutoplayMetrics_NodeStartNoGesture_Main) { |
| AudioContext* audio_context = AudioContext::Create( |
| GetDocument(), AudioContextOptions::Create(), ASSERT_NO_EXCEPTION); |
| audio_context->NotifySourceNodeStart(); |
| RecordAutoplayStatus(audio_context); |
| |
| switch (GetParam()) { |
| case AutoplayPolicy::Type::kNoUserGestureRequired: |
| case AutoplayPolicy::Type::kUserGestureRequired: |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 0); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 0); |
| break; |
| case AutoplayPolicy::Type::kDocumentUserActivationRequired: |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayMetric, static_cast<int>(AutoplayStatus::kFailed), 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 0); |
| break; |
| } |
| } |
| |
| // Creates an AudioContext then calls start on a node with a gesture inside a |
| // x-origin child frame. |
| TEST_P(AudioContextAutoplayTest, AutoplayMetrics_NodeStartGesture_Child) { |
| AudioContext* audio_context = AudioContext::Create( |
| ChildDocument(), AudioContextOptions::Create(), ASSERT_NO_EXCEPTION); |
| |
| LocalFrame::NotifyUserActivation( |
| ChildDocument().GetFrame(), mojom::UserActivationNotificationType::kTest); |
| audio_context->NotifySourceNodeStart(); |
| RecordAutoplayStatus(audio_context); |
| |
| switch (GetParam()) { |
| case AutoplayPolicy::Type::kNoUserGestureRequired: |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 0); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 0); |
| break; |
| case AutoplayPolicy::Type::kUserGestureRequired: |
| case AutoplayPolicy::Type::kDocumentUserActivationRequired: |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayMetric, static_cast<int>(AutoplayStatus::kSucceeded), 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 1); |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayCrossOriginMetric, |
| static_cast<int>(AutoplayStatus::kSucceeded), 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 1); |
| break; |
| } |
| } |
| |
| // Creates an AudioContext then calls start on a node with a gesture inside a |
| // main frame. |
| TEST_P(AudioContextAutoplayTest, AutoplayMetrics_NodeStartGesture_Main) { |
| AudioContext* audio_context = AudioContext::Create( |
| GetDocument(), AudioContextOptions::Create(), ASSERT_NO_EXCEPTION); |
| |
| LocalFrame::NotifyUserActivation( |
| GetDocument().GetFrame(), mojom::UserActivationNotificationType::kTest); |
| audio_context->NotifySourceNodeStart(); |
| RecordAutoplayStatus(audio_context); |
| |
| switch (GetParam()) { |
| case AutoplayPolicy::Type::kNoUserGestureRequired: |
| case AutoplayPolicy::Type::kUserGestureRequired: |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 0); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 0); |
| break; |
| case AutoplayPolicy::Type::kDocumentUserActivationRequired: |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayMetric, static_cast<int>(AutoplayStatus::kSucceeded), 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 0); |
| break; |
| } |
| } |
| |
| // Creates an AudioContext then calls start on a node without a gesture and |
| // finally allows the AudioContext to produce sound inside x-origin child frame. |
| TEST_P(AudioContextAutoplayTest, |
| AutoplayMetrics_NodeStartNoGestureThenSuccess_Child) { |
| ScriptState::Scope scope(GetScriptStateFrom(ChildDocument())); |
| |
| AudioContext* audio_context = AudioContext::Create( |
| ChildDocument(), AudioContextOptions::Create(), ASSERT_NO_EXCEPTION); |
| audio_context->NotifySourceNodeStart(); |
| |
| LocalFrame::NotifyUserActivation( |
| ChildDocument().GetFrame(), mojom::UserActivationNotificationType::kTest); |
| audio_context->resumeContext(GetScriptStateFrom(ChildDocument()), |
| ASSERT_NO_EXCEPTION); |
| RejectPendingResolvers(audio_context); |
| RecordAutoplayStatus(audio_context); |
| |
| switch (GetParam()) { |
| case AutoplayPolicy::Type::kNoUserGestureRequired: |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 0); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 0); |
| break; |
| case AutoplayPolicy::Type::kUserGestureRequired: |
| case AutoplayPolicy::Type::kDocumentUserActivationRequired: |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayMetric, static_cast<int>(AutoplayStatus::kSucceeded), 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 1); |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayCrossOriginMetric, |
| static_cast<int>(AutoplayStatus::kSucceeded), 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 1); |
| break; |
| } |
| } |
| |
| // Creates an AudioContext then calls start on a node without a gesture and |
| // finally allows the AudioContext to produce sound inside a main frame. |
| TEST_P(AudioContextAutoplayTest, |
| AutoplayMetrics_NodeStartNoGestureThenSuccess_Main) { |
| ScriptState::Scope scope(GetScriptStateFrom(GetDocument())); |
| |
| AudioContext* audio_context = AudioContext::Create( |
| GetDocument(), AudioContextOptions::Create(), ASSERT_NO_EXCEPTION); |
| audio_context->NotifySourceNodeStart(); |
| |
| LocalFrame::NotifyUserActivation( |
| GetDocument().GetFrame(), mojom::UserActivationNotificationType::kTest); |
| audio_context->resumeContext(GetScriptStateFrom(GetDocument()), |
| ASSERT_NO_EXCEPTION); |
| RejectPendingResolvers(audio_context); |
| RecordAutoplayStatus(audio_context); |
| |
| switch (GetParam()) { |
| case AutoplayPolicy::Type::kNoUserGestureRequired: |
| case AutoplayPolicy::Type::kUserGestureRequired: |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 0); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 0); |
| break; |
| case AutoplayPolicy::Type::kDocumentUserActivationRequired: |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayMetric, static_cast<int>(AutoplayStatus::kSucceeded), 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 0); |
| break; |
| } |
| } |
| |
| // Creates an AudioContext then calls start on a node with a gesture and |
| // finally allows the AudioContext to produce sound inside x-origin child frame. |
| TEST_P(AudioContextAutoplayTest, |
| AutoplayMetrics_NodeStartGestureThenSucces_Child) { |
| ScriptState::Scope scope(GetScriptStateFrom(ChildDocument())); |
| |
| AudioContext* audio_context = AudioContext::Create( |
| ChildDocument(), AudioContextOptions::Create(), ASSERT_NO_EXCEPTION); |
| |
| LocalFrame::NotifyUserActivation( |
| ChildDocument().GetFrame(), mojom::UserActivationNotificationType::kTest); |
| audio_context->NotifySourceNodeStart(); |
| audio_context->resumeContext(GetScriptStateFrom(ChildDocument()), |
| ASSERT_NO_EXCEPTION); |
| RejectPendingResolvers(audio_context); |
| RecordAutoplayStatus(audio_context); |
| |
| switch (GetParam()) { |
| case AutoplayPolicy::Type::kNoUserGestureRequired: |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 0); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 0); |
| break; |
| case AutoplayPolicy::Type::kUserGestureRequired: |
| case AutoplayPolicy::Type::kDocumentUserActivationRequired: |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayMetric, static_cast<int>(AutoplayStatus::kSucceeded), 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 1); |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayCrossOriginMetric, |
| static_cast<int>(AutoplayStatus::kSucceeded), 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 1); |
| break; |
| } |
| } |
| |
| // Creates an AudioContext then calls start on a node with a gesture and |
| // finally allows the AudioContext to produce sound inside a main frame. |
| TEST_P(AudioContextAutoplayTest, |
| AutoplayMetrics_NodeStartGestureThenSucces_Main) { |
| ScriptState::Scope scope(GetScriptStateFrom(GetDocument())); |
| |
| AudioContext* audio_context = AudioContext::Create( |
| GetDocument(), AudioContextOptions::Create(), ASSERT_NO_EXCEPTION); |
| |
| LocalFrame::NotifyUserActivation( |
| GetDocument().GetFrame(), mojom::UserActivationNotificationType::kTest); |
| audio_context->NotifySourceNodeStart(); |
| audio_context->resumeContext(GetScriptStateFrom(GetDocument()), |
| ASSERT_NO_EXCEPTION); |
| RejectPendingResolvers(audio_context); |
| RecordAutoplayStatus(audio_context); |
| |
| switch (GetParam()) { |
| case AutoplayPolicy::Type::kNoUserGestureRequired: |
| case AutoplayPolicy::Type::kUserGestureRequired: |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 0); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 0); |
| break; |
| case AutoplayPolicy::Type::kDocumentUserActivationRequired: |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayMetric, static_cast<int>(AutoplayStatus::kSucceeded), 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 0); |
| break; |
| } |
| } |
| |
| // Attempts to autoplay an AudioContext in a x-origin child frame when the |
| // document previous received a user gesture. |
| TEST_P(AudioContextAutoplayTest, |
| AutoplayMetrics_DocumentReceivedGesture_Child) { |
| LocalFrame::NotifyUserActivation( |
| ChildDocument().GetFrame(), mojom::UserActivationNotificationType::kTest); |
| |
| AudioContext* audio_context = AudioContext::Create( |
| ChildDocument(), AudioContextOptions::Create(), ASSERT_NO_EXCEPTION); |
| RecordAutoplayStatus(audio_context); |
| |
| switch (GetParam()) { |
| case AutoplayPolicy::Type::kNoUserGestureRequired: |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 0); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 0); |
| break; |
| case AutoplayPolicy::Type::kUserGestureRequired: |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayMetric, static_cast<int>(AutoplayStatus::kSucceeded), 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 1); |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayCrossOriginMetric, |
| static_cast<int>(AutoplayStatus::kSucceeded), 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 1); |
| break; |
| case AutoplayPolicy::Type::kDocumentUserActivationRequired: |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayMetric, static_cast<int>(AutoplayStatus::kSucceeded), 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 1); |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayCrossOriginMetric, |
| static_cast<int>(AutoplayStatus::kSucceeded), 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 1); |
| break; |
| } |
| } |
| |
| // Attempts to autoplay an AudioContext in a main child frame when the |
| // document previous received a user gesture. |
| TEST_P(AudioContextAutoplayTest, |
| AutoplayMetrics_DocumentReceivedGesture_Main) { |
| LocalFrame::NotifyUserActivation( |
| ChildDocument().GetFrame(), mojom::UserActivationNotificationType::kTest); |
| |
| AudioContext* audio_context = AudioContext::Create( |
| GetDocument(), AudioContextOptions::Create(), ASSERT_NO_EXCEPTION); |
| RecordAutoplayStatus(audio_context); |
| |
| switch (GetParam()) { |
| case AutoplayPolicy::Type::kNoUserGestureRequired: |
| case AutoplayPolicy::Type::kUserGestureRequired: |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 0); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 0); |
| break; |
| case AutoplayPolicy::Type::kDocumentUserActivationRequired: |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayMetric, static_cast<int>(AutoplayStatus::kSucceeded), 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 0); |
| break; |
| } |
| } |
| |
| // Attempts to autoplay an AudioContext in a main child frame when the |
| // document received a user gesture before navigation. |
| TEST_P(AudioContextAutoplayTest, |
| AutoplayMetrics_DocumentReceivedGesture_BeforeNavigation) { |
| GetDocument().GetFrame()->SetHadStickyUserActivationBeforeNavigation(true); |
| |
| AudioContext* audio_context = AudioContext::Create( |
| GetDocument(), AudioContextOptions::Create(), ASSERT_NO_EXCEPTION); |
| RecordAutoplayStatus(audio_context); |
| |
| switch (GetParam()) { |
| case AutoplayPolicy::Type::kNoUserGestureRequired: |
| case AutoplayPolicy::Type::kUserGestureRequired: |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 0); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 0); |
| break; |
| case AutoplayPolicy::Type::kDocumentUserActivationRequired: |
| GetHistogramTester()->ExpectBucketCount( |
| kAutoplayMetric, static_cast<int>(AutoplayStatus::kSucceeded), 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayMetric, 1); |
| GetHistogramTester()->ExpectTotalCount(kAutoplayCrossOriginMetric, 0); |
| break; |
| } |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| AudioContextAutoplayTest, |
| AudioContextAutoplayTest, |
| testing::Values(AutoplayPolicy::Type::kNoUserGestureRequired, |
| AutoplayPolicy::Type::kUserGestureRequired, |
| AutoplayPolicy::Type::kDocumentUserActivationRequired)); |
| |
| } // namespace blink |