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.

     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 }

mercurial