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.
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 |