content/media/webaudio/DynamicsCompressorNode.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

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.

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

mercurial