Tue, 06 Jan 2015 21:39:09 +0100
Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "DynamicsCompressorNode.h"
8 #include "mozilla/dom/DynamicsCompressorNodeBinding.h"
9 #include "AudioNodeEngine.h"
10 #include "AudioNodeStream.h"
11 #include "AudioDestinationNode.h"
12 #include "WebAudioUtils.h"
13 #include "blink/DynamicsCompressor.h"
15 using WebCore::DynamicsCompressor;
17 namespace mozilla {
18 namespace dom {
20 NS_IMPL_CYCLE_COLLECTION_INHERITED(DynamicsCompressorNode, AudioNode,
21 mThreshold,
22 mKnee,
23 mRatio,
24 mReduction,
25 mAttack,
26 mRelease)
28 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DynamicsCompressorNode)
29 NS_INTERFACE_MAP_END_INHERITING(AudioNode)
31 NS_IMPL_ADDREF_INHERITED(DynamicsCompressorNode, AudioNode)
32 NS_IMPL_RELEASE_INHERITED(DynamicsCompressorNode, AudioNode)
34 class DynamicsCompressorNodeEngine : public AudioNodeEngine
35 {
36 public:
37 explicit DynamicsCompressorNodeEngine(AudioNode* aNode,
38 AudioDestinationNode* aDestination)
39 : AudioNodeEngine(aNode)
40 , mSource(nullptr)
41 , mDestination(static_cast<AudioNodeStream*> (aDestination->Stream()))
42 // Keep the default value in sync with the default value in
43 // DynamicsCompressorNode::DynamicsCompressorNode.
44 , mThreshold(-24.f)
45 , mKnee(30.f)
46 , mRatio(12.f)
47 , mAttack(0.003f)
48 , mRelease(0.25f)
49 , mCompressor(new DynamicsCompressor(mDestination->SampleRate(), 2))
50 {
51 }
53 void SetSourceStream(AudioNodeStream* aSource)
54 {
55 mSource = aSource;
56 }
58 enum Parameters {
59 THRESHOLD,
60 KNEE,
61 RATIO,
62 ATTACK,
63 RELEASE
64 };
65 void SetTimelineParameter(uint32_t aIndex,
66 const AudioParamTimeline& aValue,
67 TrackRate aSampleRate) MOZ_OVERRIDE
68 {
69 MOZ_ASSERT(mSource && mDestination);
70 switch (aIndex) {
71 case THRESHOLD:
72 mThreshold = aValue;
73 WebAudioUtils::ConvertAudioParamToTicks(mThreshold, mSource, mDestination);
74 break;
75 case KNEE:
76 mKnee = aValue;
77 WebAudioUtils::ConvertAudioParamToTicks(mKnee, mSource, mDestination);
78 break;
79 case RATIO:
80 mRatio = aValue;
81 WebAudioUtils::ConvertAudioParamToTicks(mRatio, mSource, mDestination);
82 break;
83 case ATTACK:
84 mAttack = aValue;
85 WebAudioUtils::ConvertAudioParamToTicks(mAttack, mSource, mDestination);
86 break;
87 case RELEASE:
88 mRelease = aValue;
89 WebAudioUtils::ConvertAudioParamToTicks(mRelease, mSource, mDestination);
90 break;
91 default:
92 NS_ERROR("Bad DynamicsCompresssorNodeEngine TimelineParameter");
93 }
94 }
96 virtual void ProcessBlock(AudioNodeStream* aStream,
97 const AudioChunk& aInput,
98 AudioChunk* aOutput,
99 bool* aFinished) MOZ_OVERRIDE
100 {
101 if (aInput.IsNull()) {
102 // Just output silence
103 *aOutput = aInput;
104 return;
105 }
107 const uint32_t channelCount = aInput.mChannelData.Length();
108 if (mCompressor->numberOfChannels() != channelCount) {
109 // Create a new compressor object with a new channel count
110 mCompressor = new WebCore::DynamicsCompressor(aStream->SampleRate(),
111 aInput.mChannelData.Length());
112 }
114 TrackTicks pos = aStream->GetCurrentPosition();
115 mCompressor->setParameterValue(DynamicsCompressor::ParamThreshold,
116 mThreshold.GetValueAtTime(pos));
117 mCompressor->setParameterValue(DynamicsCompressor::ParamKnee,
118 mKnee.GetValueAtTime(pos));
119 mCompressor->setParameterValue(DynamicsCompressor::ParamRatio,
120 mRatio.GetValueAtTime(pos));
121 mCompressor->setParameterValue(DynamicsCompressor::ParamAttack,
122 mAttack.GetValueAtTime(pos));
123 mCompressor->setParameterValue(DynamicsCompressor::ParamRelease,
124 mRelease.GetValueAtTime(pos));
126 AllocateAudioBlock(channelCount, aOutput);
127 mCompressor->process(&aInput, aOutput, aInput.GetDuration());
129 SendReductionParamToMainThread(aStream,
130 mCompressor->parameterValue(DynamicsCompressor::ParamReduction));
131 }
133 virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE
134 {
135 // Not owned:
136 // - mSource (probably)
137 // - mDestination (probably)
138 // - Don't count the AudioParamTimelines, their inner refs are owned by the
139 // AudioNode.
140 size_t amount = AudioNodeEngine::SizeOfExcludingThis(aMallocSizeOf);
141 amount += mCompressor->sizeOfIncludingThis(aMallocSizeOf);
142 return amount;
143 }
145 virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE
146 {
147 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
148 }
150 private:
151 void SendReductionParamToMainThread(AudioNodeStream* aStream, float aReduction)
152 {
153 MOZ_ASSERT(!NS_IsMainThread());
155 class Command : public nsRunnable
156 {
157 public:
158 Command(AudioNodeStream* aStream, float aReduction)
159 : mStream(aStream)
160 , mReduction(aReduction)
161 {
162 }
164 NS_IMETHODIMP Run()
165 {
166 nsRefPtr<DynamicsCompressorNode> node;
167 {
168 // No need to keep holding the lock for the whole duration of this
169 // function, since we're holding a strong reference to it, so if
170 // we can obtain the reference, we will hold the node alive in
171 // this function.
172 MutexAutoLock lock(mStream->Engine()->NodeMutex());
173 node = static_cast<DynamicsCompressorNode*>(mStream->Engine()->Node());
174 }
175 if (node) {
176 AudioParam* reduction = node->Reduction();
177 reduction->CancelAllEvents();
178 reduction->SetValue(mReduction);
179 }
180 return NS_OK;
181 }
183 private:
184 nsRefPtr<AudioNodeStream> mStream;
185 float mReduction;
186 };
188 NS_DispatchToMainThread(new Command(aStream, aReduction));
189 }
191 private:
192 AudioNodeStream* mSource;
193 AudioNodeStream* mDestination;
194 AudioParamTimeline mThreshold;
195 AudioParamTimeline mKnee;
196 AudioParamTimeline mRatio;
197 AudioParamTimeline mAttack;
198 AudioParamTimeline mRelease;
199 nsAutoPtr<DynamicsCompressor> mCompressor;
200 };
202 DynamicsCompressorNode::DynamicsCompressorNode(AudioContext* aContext)
203 : AudioNode(aContext,
204 2,
205 ChannelCountMode::Explicit,
206 ChannelInterpretation::Speakers)
207 , mThreshold(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
208 SendThresholdToStream, -24.f))
209 , mKnee(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
210 SendKneeToStream, 30.f))
211 , mRatio(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
212 SendRatioToStream, 12.f))
213 , mReduction(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
214 Callback, 0.f))
215 , mAttack(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
216 SendAttackToStream, 0.003f))
217 , mRelease(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(),
218 SendReleaseToStream, 0.25f))
219 {
220 DynamicsCompressorNodeEngine* engine = new DynamicsCompressorNodeEngine(this, aContext->Destination());
221 mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM);
222 engine->SetSourceStream(static_cast<AudioNodeStream*> (mStream.get()));
223 }
225 size_t
226 DynamicsCompressorNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
227 {
228 size_t amount = AudioNode::SizeOfExcludingThis(aMallocSizeOf);
229 amount += mThreshold->SizeOfIncludingThis(aMallocSizeOf);
230 amount += mKnee->SizeOfIncludingThis(aMallocSizeOf);
231 amount += mRatio->SizeOfIncludingThis(aMallocSizeOf);
232 amount += mAttack->SizeOfIncludingThis(aMallocSizeOf);
233 amount += mRelease->SizeOfIncludingThis(aMallocSizeOf);
234 return amount;
235 }
237 size_t
238 DynamicsCompressorNode::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
239 {
240 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
241 }
243 JSObject*
244 DynamicsCompressorNode::WrapObject(JSContext* aCx)
245 {
246 return DynamicsCompressorNodeBinding::Wrap(aCx, this);
247 }
249 void
250 DynamicsCompressorNode::SendThresholdToStream(AudioNode* aNode)
251 {
252 DynamicsCompressorNode* This = static_cast<DynamicsCompressorNode*>(aNode);
253 SendTimelineParameterToStream(This, DynamicsCompressorNodeEngine::THRESHOLD, *This->mThreshold);
254 }
256 void
257 DynamicsCompressorNode::SendKneeToStream(AudioNode* aNode)
258 {
259 DynamicsCompressorNode* This = static_cast<DynamicsCompressorNode*>(aNode);
260 SendTimelineParameterToStream(This, DynamicsCompressorNodeEngine::KNEE, *This->mKnee);
261 }
263 void
264 DynamicsCompressorNode::SendRatioToStream(AudioNode* aNode)
265 {
266 DynamicsCompressorNode* This = static_cast<DynamicsCompressorNode*>(aNode);
267 SendTimelineParameterToStream(This, DynamicsCompressorNodeEngine::RATIO, *This->mRatio);
268 }
270 void
271 DynamicsCompressorNode::SendAttackToStream(AudioNode* aNode)
272 {
273 DynamicsCompressorNode* This = static_cast<DynamicsCompressorNode*>(aNode);
274 SendTimelineParameterToStream(This, DynamicsCompressorNodeEngine::ATTACK, *This->mAttack);
275 }
277 void
278 DynamicsCompressorNode::SendReleaseToStream(AudioNode* aNode)
279 {
280 DynamicsCompressorNode* This = static_cast<DynamicsCompressorNode*>(aNode);
281 SendTimelineParameterToStream(This, DynamicsCompressorNodeEngine::RELEASE, *This->mRelease);
282 }
284 }
285 }