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 "BiquadFilterNode.h" |
michael@0 | 8 | #include "AudioNodeEngine.h" |
michael@0 | 9 | #include "AudioNodeStream.h" |
michael@0 | 10 | #include "AudioDestinationNode.h" |
michael@0 | 11 | #include "PlayingRefChangeHandler.h" |
michael@0 | 12 | #include "WebAudioUtils.h" |
michael@0 | 13 | #include "blink/Biquad.h" |
michael@0 | 14 | #include "mozilla/Preferences.h" |
michael@0 | 15 | #include "AudioParamTimeline.h" |
michael@0 | 16 | |
michael@0 | 17 | namespace mozilla { |
michael@0 | 18 | namespace dom { |
michael@0 | 19 | |
michael@0 | 20 | NS_IMPL_CYCLE_COLLECTION_INHERITED(BiquadFilterNode, AudioNode, |
michael@0 | 21 | mFrequency, mDetune, mQ, mGain) |
michael@0 | 22 | |
michael@0 | 23 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BiquadFilterNode) |
michael@0 | 24 | NS_INTERFACE_MAP_END_INHERITING(AudioNode) |
michael@0 | 25 | |
michael@0 | 26 | NS_IMPL_ADDREF_INHERITED(BiquadFilterNode, AudioNode) |
michael@0 | 27 | NS_IMPL_RELEASE_INHERITED(BiquadFilterNode, AudioNode) |
michael@0 | 28 | |
michael@0 | 29 | static void |
michael@0 | 30 | SetParamsOnBiquad(WebCore::Biquad& aBiquad, |
michael@0 | 31 | float aSampleRate, |
michael@0 | 32 | BiquadFilterType aType, |
michael@0 | 33 | double aFrequency, |
michael@0 | 34 | double aQ, |
michael@0 | 35 | double aGain, |
michael@0 | 36 | double aDetune) |
michael@0 | 37 | { |
michael@0 | 38 | const double nyquist = aSampleRate * 0.5; |
michael@0 | 39 | double normalizedFrequency = aFrequency / nyquist; |
michael@0 | 40 | |
michael@0 | 41 | if (aDetune) { |
michael@0 | 42 | normalizedFrequency *= std::pow(2.0, aDetune / 1200); |
michael@0 | 43 | } |
michael@0 | 44 | |
michael@0 | 45 | switch (aType) { |
michael@0 | 46 | case BiquadFilterType::Lowpass: |
michael@0 | 47 | aBiquad.setLowpassParams(normalizedFrequency, aQ); |
michael@0 | 48 | break; |
michael@0 | 49 | case BiquadFilterType::Highpass: |
michael@0 | 50 | aBiquad.setHighpassParams(normalizedFrequency, aQ); |
michael@0 | 51 | break; |
michael@0 | 52 | case BiquadFilterType::Bandpass: |
michael@0 | 53 | aBiquad.setBandpassParams(normalizedFrequency, aQ); |
michael@0 | 54 | break; |
michael@0 | 55 | case BiquadFilterType::Lowshelf: |
michael@0 | 56 | aBiquad.setLowShelfParams(normalizedFrequency, aGain); |
michael@0 | 57 | break; |
michael@0 | 58 | case BiquadFilterType::Highshelf: |
michael@0 | 59 | aBiquad.setHighShelfParams(normalizedFrequency, aGain); |
michael@0 | 60 | break; |
michael@0 | 61 | case BiquadFilterType::Peaking: |
michael@0 | 62 | aBiquad.setPeakingParams(normalizedFrequency, aQ, aGain); |
michael@0 | 63 | break; |
michael@0 | 64 | case BiquadFilterType::Notch: |
michael@0 | 65 | aBiquad.setNotchParams(normalizedFrequency, aQ); |
michael@0 | 66 | break; |
michael@0 | 67 | case BiquadFilterType::Allpass: |
michael@0 | 68 | aBiquad.setAllpassParams(normalizedFrequency, aQ); |
michael@0 | 69 | break; |
michael@0 | 70 | default: |
michael@0 | 71 | NS_NOTREACHED("We should never see the alternate names here"); |
michael@0 | 72 | break; |
michael@0 | 73 | } |
michael@0 | 74 | } |
michael@0 | 75 | |
michael@0 | 76 | class BiquadFilterNodeEngine : public AudioNodeEngine |
michael@0 | 77 | { |
michael@0 | 78 | public: |
michael@0 | 79 | BiquadFilterNodeEngine(AudioNode* aNode, AudioDestinationNode* aDestination) |
michael@0 | 80 | : AudioNodeEngine(aNode) |
michael@0 | 81 | , mSource(nullptr) |
michael@0 | 82 | , mDestination(static_cast<AudioNodeStream*> (aDestination->Stream())) |
michael@0 | 83 | // Keep the default values in sync with the default values in |
michael@0 | 84 | // BiquadFilterNode::BiquadFilterNode |
michael@0 | 85 | , mType(BiquadFilterType::Lowpass) |
michael@0 | 86 | , mFrequency(350.f) |
michael@0 | 87 | , mDetune(0.f) |
michael@0 | 88 | , mQ(1.f) |
michael@0 | 89 | , mGain(0.f) |
michael@0 | 90 | { |
michael@0 | 91 | } |
michael@0 | 92 | |
michael@0 | 93 | void SetSourceStream(AudioNodeStream* aSource) |
michael@0 | 94 | { |
michael@0 | 95 | mSource = aSource; |
michael@0 | 96 | } |
michael@0 | 97 | |
michael@0 | 98 | enum Parameteres { |
michael@0 | 99 | TYPE, |
michael@0 | 100 | FREQUENCY, |
michael@0 | 101 | DETUNE, |
michael@0 | 102 | Q, |
michael@0 | 103 | GAIN |
michael@0 | 104 | }; |
michael@0 | 105 | void SetInt32Parameter(uint32_t aIndex, int32_t aValue) MOZ_OVERRIDE |
michael@0 | 106 | { |
michael@0 | 107 | switch (aIndex) { |
michael@0 | 108 | case TYPE: mType = static_cast<BiquadFilterType>(aValue); break; |
michael@0 | 109 | default: |
michael@0 | 110 | NS_ERROR("Bad BiquadFilterNode Int32Parameter"); |
michael@0 | 111 | } |
michael@0 | 112 | } |
michael@0 | 113 | void SetTimelineParameter(uint32_t aIndex, |
michael@0 | 114 | const AudioParamTimeline& aValue, |
michael@0 | 115 | TrackRate aSampleRate) MOZ_OVERRIDE |
michael@0 | 116 | { |
michael@0 | 117 | MOZ_ASSERT(mSource && mDestination); |
michael@0 | 118 | switch (aIndex) { |
michael@0 | 119 | case FREQUENCY: |
michael@0 | 120 | mFrequency = aValue; |
michael@0 | 121 | WebAudioUtils::ConvertAudioParamToTicks(mFrequency, mSource, mDestination); |
michael@0 | 122 | break; |
michael@0 | 123 | case DETUNE: |
michael@0 | 124 | mDetune = aValue; |
michael@0 | 125 | WebAudioUtils::ConvertAudioParamToTicks(mDetune, mSource, mDestination); |
michael@0 | 126 | break; |
michael@0 | 127 | case Q: |
michael@0 | 128 | mQ = aValue; |
michael@0 | 129 | WebAudioUtils::ConvertAudioParamToTicks(mQ, mSource, mDestination); |
michael@0 | 130 | break; |
michael@0 | 131 | case GAIN: |
michael@0 | 132 | mGain = aValue; |
michael@0 | 133 | WebAudioUtils::ConvertAudioParamToTicks(mGain, mSource, mDestination); |
michael@0 | 134 | break; |
michael@0 | 135 | default: |
michael@0 | 136 | NS_ERROR("Bad BiquadFilterNodeEngine TimelineParameter"); |
michael@0 | 137 | } |
michael@0 | 138 | } |
michael@0 | 139 | |
michael@0 | 140 | virtual void ProcessBlock(AudioNodeStream* aStream, |
michael@0 | 141 | const AudioChunk& aInput, |
michael@0 | 142 | AudioChunk* aOutput, |
michael@0 | 143 | bool* aFinished) MOZ_OVERRIDE |
michael@0 | 144 | { |
michael@0 | 145 | float inputBuffer[WEBAUDIO_BLOCK_SIZE]; |
michael@0 | 146 | |
michael@0 | 147 | if (aInput.IsNull()) { |
michael@0 | 148 | bool hasTail = false; |
michael@0 | 149 | for (uint32_t i = 0; i < mBiquads.Length(); ++i) { |
michael@0 | 150 | if (mBiquads[i].hasTail()) { |
michael@0 | 151 | hasTail = true; |
michael@0 | 152 | break; |
michael@0 | 153 | } |
michael@0 | 154 | } |
michael@0 | 155 | if (!hasTail) { |
michael@0 | 156 | if (!mBiquads.IsEmpty()) { |
michael@0 | 157 | mBiquads.Clear(); |
michael@0 | 158 | |
michael@0 | 159 | nsRefPtr<PlayingRefChangeHandler> refchanged = |
michael@0 | 160 | new PlayingRefChangeHandler(aStream, PlayingRefChangeHandler::RELEASE); |
michael@0 | 161 | aStream->Graph()-> |
michael@0 | 162 | DispatchToMainThreadAfterStreamStateUpdate(refchanged.forget()); |
michael@0 | 163 | } |
michael@0 | 164 | |
michael@0 | 165 | aOutput->SetNull(WEBAUDIO_BLOCK_SIZE); |
michael@0 | 166 | return; |
michael@0 | 167 | } |
michael@0 | 168 | |
michael@0 | 169 | PodArrayZero(inputBuffer); |
michael@0 | 170 | |
michael@0 | 171 | } else if(mBiquads.Length() != aInput.mChannelData.Length()){ |
michael@0 | 172 | if (mBiquads.IsEmpty()) { |
michael@0 | 173 | nsRefPtr<PlayingRefChangeHandler> refchanged = |
michael@0 | 174 | new PlayingRefChangeHandler(aStream, PlayingRefChangeHandler::ADDREF); |
michael@0 | 175 | aStream->Graph()-> |
michael@0 | 176 | DispatchToMainThreadAfterStreamStateUpdate(refchanged.forget()); |
michael@0 | 177 | } else { // Help people diagnose bug 924718 |
michael@0 | 178 | NS_WARNING("BiquadFilterNode channel count changes may produce audio glitches"); |
michael@0 | 179 | } |
michael@0 | 180 | |
michael@0 | 181 | // Adjust the number of biquads based on the number of channels |
michael@0 | 182 | mBiquads.SetLength(aInput.mChannelData.Length()); |
michael@0 | 183 | } |
michael@0 | 184 | |
michael@0 | 185 | uint32_t numberOfChannels = mBiquads.Length(); |
michael@0 | 186 | AllocateAudioBlock(numberOfChannels, aOutput); |
michael@0 | 187 | |
michael@0 | 188 | TrackTicks pos = aStream->GetCurrentPosition(); |
michael@0 | 189 | |
michael@0 | 190 | double freq = mFrequency.GetValueAtTime(pos); |
michael@0 | 191 | double q = mQ.GetValueAtTime(pos); |
michael@0 | 192 | double gain = mGain.GetValueAtTime(pos); |
michael@0 | 193 | double detune = mDetune.GetValueAtTime(pos); |
michael@0 | 194 | |
michael@0 | 195 | for (uint32_t i = 0; i < numberOfChannels; ++i) { |
michael@0 | 196 | const float* input; |
michael@0 | 197 | if (aInput.IsNull()) { |
michael@0 | 198 | input = inputBuffer; |
michael@0 | 199 | } else { |
michael@0 | 200 | input = static_cast<const float*>(aInput.mChannelData[i]); |
michael@0 | 201 | if (aInput.mVolume != 1.0) { |
michael@0 | 202 | AudioBlockCopyChannelWithScale(input, aInput.mVolume, inputBuffer); |
michael@0 | 203 | input = inputBuffer; |
michael@0 | 204 | } |
michael@0 | 205 | } |
michael@0 | 206 | SetParamsOnBiquad(mBiquads[i], aStream->SampleRate(), mType, freq, q, gain, detune); |
michael@0 | 207 | |
michael@0 | 208 | mBiquads[i].process(input, |
michael@0 | 209 | static_cast<float*>(const_cast<void*>(aOutput->mChannelData[i])), |
michael@0 | 210 | aInput.GetDuration()); |
michael@0 | 211 | } |
michael@0 | 212 | } |
michael@0 | 213 | |
michael@0 | 214 | virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE |
michael@0 | 215 | { |
michael@0 | 216 | // Not owned: |
michael@0 | 217 | // - mSource - probably not owned |
michael@0 | 218 | // - mDestination - probably not owned |
michael@0 | 219 | // - AudioParamTimelines - counted in the AudioNode |
michael@0 | 220 | size_t amount = AudioNodeEngine::SizeOfExcludingThis(aMallocSizeOf); |
michael@0 | 221 | amount += mBiquads.SizeOfExcludingThis(aMallocSizeOf); |
michael@0 | 222 | return amount; |
michael@0 | 223 | } |
michael@0 | 224 | |
michael@0 | 225 | virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE |
michael@0 | 226 | { |
michael@0 | 227 | return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); |
michael@0 | 228 | } |
michael@0 | 229 | |
michael@0 | 230 | private: |
michael@0 | 231 | AudioNodeStream* mSource; |
michael@0 | 232 | AudioNodeStream* mDestination; |
michael@0 | 233 | BiquadFilterType mType; |
michael@0 | 234 | AudioParamTimeline mFrequency; |
michael@0 | 235 | AudioParamTimeline mDetune; |
michael@0 | 236 | AudioParamTimeline mQ; |
michael@0 | 237 | AudioParamTimeline mGain; |
michael@0 | 238 | nsTArray<WebCore::Biquad> mBiquads; |
michael@0 | 239 | }; |
michael@0 | 240 | |
michael@0 | 241 | BiquadFilterNode::BiquadFilterNode(AudioContext* aContext) |
michael@0 | 242 | : AudioNode(aContext, |
michael@0 | 243 | 2, |
michael@0 | 244 | ChannelCountMode::Max, |
michael@0 | 245 | ChannelInterpretation::Speakers) |
michael@0 | 246 | , mType(BiquadFilterType::Lowpass) |
michael@0 | 247 | , mFrequency(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(), |
michael@0 | 248 | SendFrequencyToStream, 350.f)) |
michael@0 | 249 | , mDetune(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(), |
michael@0 | 250 | SendDetuneToStream, 0.f)) |
michael@0 | 251 | , mQ(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(), |
michael@0 | 252 | SendQToStream, 1.f)) |
michael@0 | 253 | , mGain(new AudioParam(MOZ_THIS_IN_INITIALIZER_LIST(), |
michael@0 | 254 | SendGainToStream, 0.f)) |
michael@0 | 255 | { |
michael@0 | 256 | BiquadFilterNodeEngine* engine = new BiquadFilterNodeEngine(this, aContext->Destination()); |
michael@0 | 257 | mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM); |
michael@0 | 258 | engine->SetSourceStream(static_cast<AudioNodeStream*> (mStream.get())); |
michael@0 | 259 | } |
michael@0 | 260 | |
michael@0 | 261 | |
michael@0 | 262 | size_t |
michael@0 | 263 | BiquadFilterNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const |
michael@0 | 264 | { |
michael@0 | 265 | size_t amount = AudioNode::SizeOfExcludingThis(aMallocSizeOf); |
michael@0 | 266 | |
michael@0 | 267 | if (mFrequency) { |
michael@0 | 268 | amount += mFrequency->SizeOfIncludingThis(aMallocSizeOf); |
michael@0 | 269 | } |
michael@0 | 270 | |
michael@0 | 271 | if (mDetune) { |
michael@0 | 272 | amount += mDetune->SizeOfIncludingThis(aMallocSizeOf); |
michael@0 | 273 | } |
michael@0 | 274 | |
michael@0 | 275 | if (mQ) { |
michael@0 | 276 | amount += mQ->SizeOfIncludingThis(aMallocSizeOf); |
michael@0 | 277 | } |
michael@0 | 278 | |
michael@0 | 279 | if (mGain) { |
michael@0 | 280 | amount += mGain->SizeOfIncludingThis(aMallocSizeOf); |
michael@0 | 281 | } |
michael@0 | 282 | |
michael@0 | 283 | return amount; |
michael@0 | 284 | } |
michael@0 | 285 | |
michael@0 | 286 | size_t |
michael@0 | 287 | BiquadFilterNode::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const |
michael@0 | 288 | { |
michael@0 | 289 | return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); |
michael@0 | 290 | } |
michael@0 | 291 | |
michael@0 | 292 | JSObject* |
michael@0 | 293 | BiquadFilterNode::WrapObject(JSContext* aCx) |
michael@0 | 294 | { |
michael@0 | 295 | return BiquadFilterNodeBinding::Wrap(aCx, this); |
michael@0 | 296 | } |
michael@0 | 297 | |
michael@0 | 298 | void |
michael@0 | 299 | BiquadFilterNode::SetType(BiquadFilterType aType) |
michael@0 | 300 | { |
michael@0 | 301 | if (!Preferences::GetBool("media.webaudio.legacy.BiquadFilterNode")) { |
michael@0 | 302 | // Do not accept the alternate enum values unless the legacy pref |
michael@0 | 303 | // has been turned on. |
michael@0 | 304 | switch (aType) { |
michael@0 | 305 | case BiquadFilterType::_0: |
michael@0 | 306 | case BiquadFilterType::_1: |
michael@0 | 307 | case BiquadFilterType::_2: |
michael@0 | 308 | case BiquadFilterType::_3: |
michael@0 | 309 | case BiquadFilterType::_4: |
michael@0 | 310 | case BiquadFilterType::_5: |
michael@0 | 311 | case BiquadFilterType::_6: |
michael@0 | 312 | case BiquadFilterType::_7: |
michael@0 | 313 | // Do nothing in order to emulate setting an invalid enum value. |
michael@0 | 314 | return; |
michael@0 | 315 | default: |
michael@0 | 316 | // Shut up the compiler warning |
michael@0 | 317 | break; |
michael@0 | 318 | } |
michael@0 | 319 | } |
michael@0 | 320 | |
michael@0 | 321 | // Handle the alternate enum values |
michael@0 | 322 | switch (aType) { |
michael@0 | 323 | case BiquadFilterType::_0: aType = BiquadFilterType::Lowpass; break; |
michael@0 | 324 | case BiquadFilterType::_1: aType = BiquadFilterType::Highpass; break; |
michael@0 | 325 | case BiquadFilterType::_2: aType = BiquadFilterType::Bandpass; break; |
michael@0 | 326 | case BiquadFilterType::_3: aType = BiquadFilterType::Lowshelf; break; |
michael@0 | 327 | case BiquadFilterType::_4: aType = BiquadFilterType::Highshelf; break; |
michael@0 | 328 | case BiquadFilterType::_5: aType = BiquadFilterType::Peaking; break; |
michael@0 | 329 | case BiquadFilterType::_6: aType = BiquadFilterType::Notch; break; |
michael@0 | 330 | case BiquadFilterType::_7: aType = BiquadFilterType::Allpass; break; |
michael@0 | 331 | default: |
michael@0 | 332 | // Shut up the compiler warning |
michael@0 | 333 | break; |
michael@0 | 334 | } |
michael@0 | 335 | |
michael@0 | 336 | mType = aType; |
michael@0 | 337 | SendInt32ParameterToStream(BiquadFilterNodeEngine::TYPE, |
michael@0 | 338 | static_cast<int32_t>(aType)); |
michael@0 | 339 | } |
michael@0 | 340 | |
michael@0 | 341 | void |
michael@0 | 342 | BiquadFilterNode::GetFrequencyResponse(const Float32Array& aFrequencyHz, |
michael@0 | 343 | const Float32Array& aMagResponse, |
michael@0 | 344 | const Float32Array& aPhaseResponse) |
michael@0 | 345 | { |
michael@0 | 346 | aFrequencyHz.ComputeLengthAndData(); |
michael@0 | 347 | aMagResponse.ComputeLengthAndData(); |
michael@0 | 348 | aPhaseResponse.ComputeLengthAndData(); |
michael@0 | 349 | |
michael@0 | 350 | uint32_t length = std::min(std::min(aFrequencyHz.Length(), aMagResponse.Length()), |
michael@0 | 351 | aPhaseResponse.Length()); |
michael@0 | 352 | if (!length) { |
michael@0 | 353 | return; |
michael@0 | 354 | } |
michael@0 | 355 | |
michael@0 | 356 | nsAutoArrayPtr<float> frequencies(new float[length]); |
michael@0 | 357 | float* frequencyHz = aFrequencyHz.Data(); |
michael@0 | 358 | const double nyquist = Context()->SampleRate() * 0.5; |
michael@0 | 359 | |
michael@0 | 360 | // Normalize the frequencies |
michael@0 | 361 | for (uint32_t i = 0; i < length; ++i) { |
michael@0 | 362 | frequencies[i] = static_cast<float>(frequencyHz[i] / nyquist); |
michael@0 | 363 | } |
michael@0 | 364 | |
michael@0 | 365 | const double currentTime = Context()->CurrentTime(); |
michael@0 | 366 | |
michael@0 | 367 | double freq = mFrequency->GetValueAtTime(currentTime); |
michael@0 | 368 | double q = mQ->GetValueAtTime(currentTime); |
michael@0 | 369 | double gain = mGain->GetValueAtTime(currentTime); |
michael@0 | 370 | double detune = mDetune->GetValueAtTime(currentTime); |
michael@0 | 371 | |
michael@0 | 372 | WebCore::Biquad biquad; |
michael@0 | 373 | SetParamsOnBiquad(biquad, Context()->SampleRate(), mType, freq, q, gain, detune); |
michael@0 | 374 | biquad.getFrequencyResponse(int(length), frequencies, aMagResponse.Data(), aPhaseResponse.Data()); |
michael@0 | 375 | } |
michael@0 | 376 | |
michael@0 | 377 | void |
michael@0 | 378 | BiquadFilterNode::SendFrequencyToStream(AudioNode* aNode) |
michael@0 | 379 | { |
michael@0 | 380 | BiquadFilterNode* This = static_cast<BiquadFilterNode*>(aNode); |
michael@0 | 381 | SendTimelineParameterToStream(This, BiquadFilterNodeEngine::FREQUENCY, *This->mFrequency); |
michael@0 | 382 | } |
michael@0 | 383 | |
michael@0 | 384 | void |
michael@0 | 385 | BiquadFilterNode::SendDetuneToStream(AudioNode* aNode) |
michael@0 | 386 | { |
michael@0 | 387 | BiquadFilterNode* This = static_cast<BiquadFilterNode*>(aNode); |
michael@0 | 388 | SendTimelineParameterToStream(This, BiquadFilterNodeEngine::DETUNE, *This->mDetune); |
michael@0 | 389 | } |
michael@0 | 390 | |
michael@0 | 391 | void |
michael@0 | 392 | BiquadFilterNode::SendQToStream(AudioNode* aNode) |
michael@0 | 393 | { |
michael@0 | 394 | BiquadFilterNode* This = static_cast<BiquadFilterNode*>(aNode); |
michael@0 | 395 | SendTimelineParameterToStream(This, BiquadFilterNodeEngine::Q, *This->mQ); |
michael@0 | 396 | } |
michael@0 | 397 | |
michael@0 | 398 | void |
michael@0 | 399 | BiquadFilterNode::SendGainToStream(AudioNode* aNode) |
michael@0 | 400 | { |
michael@0 | 401 | BiquadFilterNode* This = static_cast<BiquadFilterNode*>(aNode); |
michael@0 | 402 | SendTimelineParameterToStream(This, BiquadFilterNodeEngine::GAIN, *This->mGain); |
michael@0 | 403 | } |
michael@0 | 404 | |
michael@0 | 405 | } |
michael@0 | 406 | } |
michael@0 | 407 |