Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(76)

Side by Side Diff: third_party/WebKit/Source/modules/webaudio/BaseAudioContext.cpp

Issue 2314903002: Web Audio: when media playback requires a user gesture, apply rule to cross origin iframes. (Closed)
Patch Set: Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2010, Google Inc. All rights reserved. 2 * Copyright (C) 2010, Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 1. Redistributions of source code must retain the above copyright 7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright 9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
(...skipping 15 matching lines...) Expand all
26 26
27 #include "bindings/core/v8/Dictionary.h" 27 #include "bindings/core/v8/Dictionary.h"
28 #include "bindings/core/v8/ExceptionMessages.h" 28 #include "bindings/core/v8/ExceptionMessages.h"
29 #include "bindings/core/v8/ExceptionState.h" 29 #include "bindings/core/v8/ExceptionState.h"
30 #include "bindings/core/v8/ScriptPromiseResolver.h" 30 #include "bindings/core/v8/ScriptPromiseResolver.h"
31 #include "bindings/core/v8/ScriptState.h" 31 #include "bindings/core/v8/ScriptState.h"
32 #include "core/dom/DOMException.h" 32 #include "core/dom/DOMException.h"
33 #include "core/dom/Document.h" 33 #include "core/dom/Document.h"
34 #include "core/dom/ExceptionCode.h" 34 #include "core/dom/ExceptionCode.h"
35 #include "core/dom/ExecutionContextTask.h" 35 #include "core/dom/ExecutionContextTask.h"
36 #include "core/frame/Deprecation.h"
37 #include "core/frame/Settings.h" 36 #include "core/frame/Settings.h"
38 #include "core/html/HTMLMediaElement.h" 37 #include "core/html/HTMLMediaElement.h"
39 #include "modules/mediastream/MediaStream.h" 38 #include "modules/mediastream/MediaStream.h"
40 #include "modules/webaudio/AnalyserNode.h" 39 #include "modules/webaudio/AnalyserNode.h"
41 #include "modules/webaudio/AudioBuffer.h" 40 #include "modules/webaudio/AudioBuffer.h"
42 #include "modules/webaudio/AudioBufferCallback.h" 41 #include "modules/webaudio/AudioBufferCallback.h"
43 #include "modules/webaudio/AudioBufferSourceNode.h" 42 #include "modules/webaudio/AudioBufferSourceNode.h"
44 #include "modules/webaudio/AudioContext.h" 43 #include "modules/webaudio/AudioContext.h"
45 #include "modules/webaudio/AudioListener.h" 44 #include "modules/webaudio/AudioListener.h"
46 #include "modules/webaudio/AudioNodeInput.h" 45 #include "modules/webaudio/AudioNodeInput.h"
(...skipping 22 matching lines...) Expand all
69 #include "modules/webaudio/WaveShaperNode.h" 68 #include "modules/webaudio/WaveShaperNode.h"
70 #include "platform/CrossThreadFunctional.h" 69 #include "platform/CrossThreadFunctional.h"
71 #include "platform/Histogram.h" 70 #include "platform/Histogram.h"
72 #include "platform/UserGestureIndicator.h" 71 #include "platform/UserGestureIndicator.h"
73 #include "platform/audio/IIRFilter.h" 72 #include "platform/audio/IIRFilter.h"
74 #include "public/platform/Platform.h" 73 #include "public/platform/Platform.h"
75 #include "wtf/text/WTFString.h" 74 #include "wtf/text/WTFString.h"
76 75
77 namespace blink { 76 namespace blink {
78 77
79 namespace {
80
81 enum UserGestureRecord {
82 UserGestureRequiredAndAvailable = 0,
83 UserGestureRequiredAndNotAvailable,
84 UserGestureNotRequiredAndAvailable,
85 UserGestureNotRequiredAndNotAvailable,
86 UserGestureRecordMax
87 };
88
89 } // anonymous namespace
90
91 BaseAudioContext* BaseAudioContext::create(Document& document, ExceptionState& e xceptionState) 78 BaseAudioContext* BaseAudioContext::create(Document& document, ExceptionState& e xceptionState)
92 { 79 {
93 return AudioContext::create(document, exceptionState); 80 return AudioContext::create(document, exceptionState);
94 } 81 }
95 82
96 // FIXME(dominicc): Devolve these constructors to AudioContext 83 // FIXME(dominicc): Devolve these constructors to AudioContext
97 // and OfflineAudioContext respectively. 84 // and OfflineAudioContext respectively.
98 85
99 // Constructor for rendering to the audio hardware. 86 // Constructor for rendering to the audio hardware.
100 BaseAudioContext::BaseAudioContext(Document* document) 87 BaseAudioContext::BaseAudioContext(Document* document)
101 : ActiveScriptWrappable(this) 88 : ActiveScriptWrappable(this)
102 , ActiveDOMObject(document) 89 , ActiveDOMObject(document)
103 , m_destinationNode(nullptr) 90 , m_destinationNode(nullptr)
104 , m_isCleared(false) 91 , m_isCleared(false)
105 , m_isResolvingResumePromises(false) 92 , m_isResolvingResumePromises(false)
106 , m_userGestureRequired(false) 93 , m_userGestureRequired(false)
107 , m_connectionCount(0) 94 , m_connectionCount(0)
108 , m_deferredTaskHandler(DeferredTaskHandler::create()) 95 , m_deferredTaskHandler(DeferredTaskHandler::create())
109 , m_contextState(Suspended) 96 , m_contextState(Suspended)
110 , m_closedContextSampleRate(-1) 97 , m_closedContextSampleRate(-1)
111 , m_periodicWaveSine(nullptr) 98 , m_periodicWaveSine(nullptr)
112 , m_periodicWaveSquare(nullptr) 99 , m_periodicWaveSquare(nullptr)
113 , m_periodicWaveSawtooth(nullptr) 100 , m_periodicWaveSawtooth(nullptr)
114 , m_periodicWaveTriangle(nullptr) 101 , m_periodicWaveTriangle(nullptr)
115 { 102 {
116 // TODO(mlamouri): we might want to use other ways of checking for this but 103 // If mediaPlaybackRequiresUserGesture is enabled, cross origin iframes will
117 // in order to record metrics, re-using the HTMLMediaElement setting is 104 // require user gesture for the AudioContext to produce sound.
118 // probably the simplest solution. 105 if (document->settings() && document->settings()->mediaPlaybackRequiresUserG esture()
119 if (document->settings() && document->settings()->mediaPlaybackRequiresUserG esture()) 106 && document->frame()) && document->frame()->isCrossOriginSubframe()) {
120 m_userGestureRequired = true; 107 m_userGestureRequired = true;
108 }
121 109
122 m_destinationNode = DefaultAudioDestinationNode::create(this); 110 m_destinationNode = DefaultAudioDestinationNode::create(this);
123 111
124 initialize(); 112 initialize();
125 } 113 }
126 114
127 // Constructor for offline (non-realtime) rendering. 115 // Constructor for offline (non-realtime) rendering.
128 BaseAudioContext::BaseAudioContext(Document* document, unsigned numberOfChannels , size_t numberOfFrames, float sampleRate) 116 BaseAudioContext::BaseAudioContext(Document* document, unsigned numberOfChannels , size_t numberOfFrames, float sampleRate)
129 : ActiveScriptWrappable(this) 117 : ActiveScriptWrappable(this)
130 , ActiveDOMObject(document) 118 , ActiveDOMObject(document)
131 , m_destinationNode(nullptr) 119 , m_destinationNode(nullptr)
132 , m_isCleared(false) 120 , m_isCleared(false)
133 , m_isResolvingResumePromises(false) 121 , m_isResolvingResumePromises(false)
134 , m_userGestureRequired(false) 122 , m_userGestureRequired(false)
135 , m_connectionCount(0) 123 , m_connectionCount(0)
136 , m_deferredTaskHandler(DeferredTaskHandler::create()) 124 , m_deferredTaskHandler(DeferredTaskHandler::create())
137 , m_contextState(Suspended) 125 , m_contextState(Suspended)
138 , m_closedContextSampleRate(-1) 126 , m_closedContextSampleRate(-1)
139 , m_periodicWaveSine(nullptr) 127 , m_periodicWaveSine(nullptr)
140 , m_periodicWaveSquare(nullptr) 128 , m_periodicWaveSquare(nullptr)
141 , m_periodicWaveSawtooth(nullptr) 129 , m_periodicWaveSawtooth(nullptr)
142 , m_periodicWaveTriangle(nullptr) 130 , m_periodicWaveTriangle(nullptr)
143 { 131 {
144 // TODO(mlamouri): we might want to use other ways of checking for this but 132 // If mediaPlaybackRequiresUserGesture is enabled, cross origin iframes will
145 // in order to record metrics, re-using the HTMLMediaElement setting is 133 // require user gesture for the AudioContext to produce sound.
146 // probably the simplest solution. 134 if (document->settings() && document->settings()->mediaPlaybackRequiresUserG esture()
147 if (document->settings() && document->settings()->mediaPlaybackRequiresUserG esture()) 135 && document->frame() && document->frame()->isCrossOriginSubframe()) {
148 m_userGestureRequired = true; 136 m_userGestureRequired = true;
137 }
hongchan 2016/09/07 16:59:00 Blocking audio rendering should be limited to the
mlamouri (slow - plz ping) 2016/09/08 13:12:42 The goal here is to be compatible with Safari iOS
149 } 138 }
150 139
151 BaseAudioContext::~BaseAudioContext() 140 BaseAudioContext::~BaseAudioContext()
152 { 141 {
153 deferredTaskHandler().contextWillBeDestroyed(); 142 deferredTaskHandler().contextWillBeDestroyed();
154 // AudioNodes keep a reference to their context, so there should be no way t o be in the destructor if there are still AudioNodes around. 143 // AudioNodes keep a reference to their context, so there should be no way t o be in the destructor if there are still AudioNodes around.
155 DCHECK(!isDestinationInitialized()); 144 DCHECK(!isDestinationInitialized());
156 DCHECK(!m_activeSourceNodes.size()); 145 DCHECK(!m_activeSourceNodes.size());
157 DCHECK(!m_finishedSourceHandlers.size()); 146 DCHECK(!m_finishedSourceHandlers.size());
158 DCHECK(!m_isResolvingResumePromises); 147 DCHECK(!m_isResolvingResumePromises);
(...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after
536 // Initialize the table if necessary 525 // Initialize the table if necessary
537 if (!m_periodicWaveTriangle) 526 if (!m_periodicWaveTriangle)
538 m_periodicWaveTriangle = PeriodicWave::createTriangle(sampleRate()); 527 m_periodicWaveTriangle = PeriodicWave::createTriangle(sampleRate());
539 return m_periodicWaveTriangle; 528 return m_periodicWaveTriangle;
540 default: 529 default:
541 NOTREACHED(); 530 NOTREACHED();
542 return nullptr; 531 return nullptr;
543 } 532 }
544 } 533 }
545 534
546 void BaseAudioContext::recordUserGestureState() 535 void BaseAudioContext::startRenderingIfNeeded()
547 { 536 {
548 DEFINE_STATIC_LOCAL(EnumerationHistogram, userGestureHistogram, ("WebAudio.U serGesture", UserGestureRecordMax)); 537 if (!m_userGestureRequired)
549
550 if (!m_userGestureRequired) {
551 if (UserGestureIndicator::processingUserGesture())
552 userGestureHistogram.count(UserGestureNotRequiredAndAvailable);
553 else
554 userGestureHistogram.count(UserGestureNotRequiredAndNotAvailable);
555 return; 538 return;
556 } 539 startRendering();
557
558 DCHECK(m_userGestureRequired);
559 if (!UserGestureIndicator::processingUserGesture()) {
560 userGestureHistogram.count(UserGestureRequiredAndNotAvailable);
561
562 Document* document = toDocument(getExecutionContext());
563 if (document)
564 Deprecation::countDeprecationCrossOriginIframe(*document, UseCounter ::WebAudioAutoplayCrossOriginIframe);
565
566 return;
567 }
568 userGestureHistogram.count(UserGestureRequiredAndAvailable);
569 m_userGestureRequired = false;
570 } 540 }
571 541
572 String BaseAudioContext::state() const 542 String BaseAudioContext::state() const
573 { 543 {
574 // These strings had better match the strings for AudioContextState in Audio Context.idl. 544 // These strings had better match the strings for AudioContextState in Audio Context.idl.
575 switch (m_contextState) { 545 switch (m_contextState) {
576 case Suspended: 546 case Suspended:
577 return "suspended"; 547 return "suspended";
578 case Running: 548 case Running:
579 return "running"; 549 return "running";
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
694 continue; 664 continue;
695 if (node->handler().getNodeType() == AudioHandler::NodeTypeAudioBufferSo urce) { 665 if (node->handler().getNodeType() == AudioHandler::NodeTypeAudioBufferSo urce) {
696 AudioBufferSourceNode* sourceNode = static_cast<AudioBufferSourceNod e*>(node); 666 AudioBufferSourceNode* sourceNode = static_cast<AudioBufferSourceNod e*>(node);
697 sourceNode->audioBufferSourceHandler().handleStoppableSourceNode(); 667 sourceNode->audioBufferSourceHandler().handleStoppableSourceNode();
698 } 668 }
699 } 669 }
700 } 670 }
701 671
702 void BaseAudioContext::handlePreRenderTasks() 672 void BaseAudioContext::handlePreRenderTasks()
703 { 673 {
674 LOG(INFO) << "handlePreRenderTasks";
Raymond Toy 2016/09/07 16:13:19 handlePreRenderTask gets called about every 3 ms o
mlamouri (slow - plz ping) 2016/09/08 13:12:42 sorry, that's a leftover from some investigations.
704 DCHECK(isAudioThread()); 675 DCHECK(isAudioThread());
705 676
706 // At the beginning of every render quantum, try to update the internal rend ering graph state (from main thread changes). 677 // At the beginning of every render quantum, try to update the internal rend ering graph state (from main thread changes).
707 // It's OK if the tryLock() fails, we'll just take slightly longer to pick u p the changes. 678 // It's OK if the tryLock() fails, we'll just take slightly longer to pick u p the changes.
708 if (tryLock()) { 679 if (tryLock()) {
709 deferredTaskHandler().handleDeferredTasks(); 680 deferredTaskHandler().handleDeferredTasks();
710 681
711 resolvePromisesForResume(); 682 resolvePromisesForResume();
712 683
713 // Check to see if source nodes can be stopped because the end time has passed. 684 // Check to see if source nodes can be stopped because the end time has passed.
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
806 { 777 {
807 return ActiveDOMObject::getExecutionContext(); 778 return ActiveDOMObject::getExecutionContext();
808 } 779 }
809 780
810 void BaseAudioContext::startRendering() 781 void BaseAudioContext::startRendering()
811 { 782 {
812 // This is called for both online and offline contexts. 783 // This is called for both online and offline contexts.
813 DCHECK(isMainThread()); 784 DCHECK(isMainThread());
814 DCHECK(m_destinationNode); 785 DCHECK(m_destinationNode);
815 786
816 recordUserGestureState(); 787 if (m_userGestureRequired) {
788 if (!UserGestureIndicator::processingUserGesture()) {
789 UseCounter::count(getExecutionContext(), UseCounter::WebAudioAutopla yCrossOriginIframe);
hongchan 2016/09/07 16:59:00 Can you add a comment on what this does? This loo
mlamouri (slow - plz ping) 2016/09/08 13:12:42 m_userGestureRequired only applies for cross origi
790 return;
791 }
792 m_userGestureRequired = false;
793 }
817 794
818 if (m_contextState == Suspended) { 795 if (m_contextState == Suspended) {
819 destination()->audioDestinationHandler().startRendering(); 796 destination()->audioDestinationHandler().startRendering();
820 setContextState(Running); 797 setContextState(Running);
821 } 798 }
822 } 799 }
823 800
824 DEFINE_TRACE(BaseAudioContext) 801 DEFINE_TRACE(BaseAudioContext)
825 { 802 {
826 visitor->trace(m_destinationNode); 803 visitor->trace(m_destinationNode);
(...skipping 12 matching lines...) Expand all
839 816
840 SecurityOrigin* BaseAudioContext::getSecurityOrigin() const 817 SecurityOrigin* BaseAudioContext::getSecurityOrigin() const
841 { 818 {
842 if (getExecutionContext()) 819 if (getExecutionContext())
843 return getExecutionContext()->getSecurityOrigin(); 820 return getExecutionContext()->getSecurityOrigin();
844 821
845 return nullptr; 822 return nullptr;
846 } 823 }
847 824
848 } // namespace blink 825 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698