[WTF] Add makeUnique<T>, which ensures T is fast-allocated, makeUnique / makeUniqueWi...
[WebKit-https.git] / Source / WebCore / Modules / webaudio / MediaElementAudioSourceNode.cpp
1 /*
2  * Copyright (C) 2011, Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1.  Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2.  Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 #include "config.h"
26
27 #if ENABLE(WEB_AUDIO) && ENABLE(VIDEO)
28
29 #include "MediaElementAudioSourceNode.h"
30
31 #include "AudioContext.h"
32 #include "AudioNodeOutput.h"
33 #include "Logging.h"
34 #include "MediaPlayer.h"
35 #include <wtf/IsoMallocInlines.h>
36 #include <wtf/Locker.h>
37
38 // These are somewhat arbitrary limits, but we need to do some kind of sanity-checking.
39 const unsigned minSampleRate = 8000;
40 const unsigned maxSampleRate = 192000;
41
42 namespace WebCore {
43
44 WTF_MAKE_ISO_ALLOCATED_IMPL(MediaElementAudioSourceNode);
45
46 Ref<MediaElementAudioSourceNode> MediaElementAudioSourceNode::create(AudioContext& context, HTMLMediaElement& mediaElement)
47 {
48     return adoptRef(*new MediaElementAudioSourceNode(context, mediaElement));
49 }
50
51 MediaElementAudioSourceNode::MediaElementAudioSourceNode(AudioContext& context, HTMLMediaElement& mediaElement)
52     : AudioNode(context, context.sampleRate())
53     , m_mediaElement(mediaElement)
54     , m_sourceNumberOfChannels(0)
55     , m_sourceSampleRate(0)
56 {
57     setNodeType(NodeTypeMediaElementAudioSource);
58
59     // Default to stereo. This could change depending on what the media element .src is set to.
60     addOutput(makeUnique<AudioNodeOutput>(this, 2));
61
62     initialize();
63 }
64
65 MediaElementAudioSourceNode::~MediaElementAudioSourceNode()
66 {
67     m_mediaElement->setAudioSourceNode(nullptr);
68     uninitialize();
69 }
70
71 void MediaElementAudioSourceNode::setFormat(size_t numberOfChannels, float sourceSampleRate)
72 {
73     m_muted = wouldTaintOrigin();
74
75     if (numberOfChannels != m_sourceNumberOfChannels || sourceSampleRate != m_sourceSampleRate) {
76         if (!numberOfChannels || numberOfChannels > AudioContext::maxNumberOfChannels() || sourceSampleRate < minSampleRate || sourceSampleRate > maxSampleRate) {
77             // process() will generate silence for these uninitialized values.
78             LOG(Media, "MediaElementAudioSourceNode::setFormat(%u, %f) - unhandled format change", static_cast<unsigned>(numberOfChannels), sourceSampleRate);
79             m_sourceNumberOfChannels = 0;
80             m_sourceSampleRate = 0;
81             return;
82         }
83
84         m_sourceNumberOfChannels = numberOfChannels;
85         m_sourceSampleRate = sourceSampleRate;
86
87         // Synchronize with process().
88         std::lock_guard<MediaElementAudioSourceNode> lock(*this);
89
90         if (sourceSampleRate != sampleRate()) {
91             double scaleFactor = sourceSampleRate / sampleRate();
92             m_multiChannelResampler = makeUnique<MultiChannelResampler>(scaleFactor, numberOfChannels);
93         } else {
94             // Bypass resampling.
95             m_multiChannelResampler = nullptr;
96         }
97
98         {
99             // The context must be locked when changing the number of output channels.
100             AudioContext::AutoLocker contextLocker(context());
101
102             // Do any necesssary re-configuration to the output's number of channels.
103             output(0)->setNumberOfChannels(numberOfChannels);
104         }
105     }
106 }
107
108 bool MediaElementAudioSourceNode::wouldTaintOrigin()
109 {
110     if (!m_mediaElement->hasSingleSecurityOrigin())
111         return true;
112
113     if (m_mediaElement->didPassCORSAccessCheck())
114         return false;
115
116     if (auto* origin = context().origin())
117         return m_mediaElement->wouldTaintOrigin(*origin);
118
119     return true;
120 }
121
122 void MediaElementAudioSourceNode::process(size_t numberOfFrames)
123 {
124     AudioBus* outputBus = output(0)->bus();
125
126     if (m_muted || !m_sourceNumberOfChannels || !m_sourceSampleRate) {
127         outputBus->zero();
128         return;
129     }
130
131     // Use a std::try_to_lock to avoid contention in the real-time audio thread.
132     // If we fail to acquire the lock then the HTMLMediaElement must be in the middle of
133     // reconfiguring its playback engine, so we output silence in this case.
134     std::unique_lock<Lock> lock(m_processMutex, std::try_to_lock);
135     if (!lock.owns_lock()) {
136         // We failed to acquire the lock.
137         outputBus->zero();
138         return;
139     }
140     if (m_sourceNumberOfChannels != outputBus->numberOfChannels()) {
141         outputBus->zero();
142         return;
143     }
144
145     if (AudioSourceProvider* provider = mediaElement().audioSourceProvider()) {
146         if (m_multiChannelResampler.get()) {
147             ASSERT(m_sourceSampleRate != sampleRate());
148             m_multiChannelResampler->process(provider, outputBus, numberOfFrames);
149         } else {
150             // Bypass the resampler completely if the source is at the context's sample-rate.
151             ASSERT(m_sourceSampleRate == sampleRate());
152             provider->provideInput(outputBus, numberOfFrames);
153         }
154     } else {
155         // Either this port doesn't yet support HTMLMediaElement audio stream access,
156         // or the stream is not yet available.
157         outputBus->zero();
158     }
159 }
160
161 void MediaElementAudioSourceNode::reset()
162 {
163 }
164
165 void MediaElementAudioSourceNode::lock()
166 {
167     ref();
168     m_processMutex.lock();
169 }
170
171 void MediaElementAudioSourceNode::unlock()
172 {
173     m_processMutex.unlock();
174     deref();
175 }
176
177 } // namespace WebCore
178
179 #endif // ENABLE(WEB_AUDIO)