Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/media/webaudio/GainNode.cpp
Line
Count
Source (jump to first uncovered line)
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/. */
6
7
#include "GainNode.h"
8
#include "mozilla/dom/GainNodeBinding.h"
9
#include "AlignmentUtils.h"
10
#include "AudioNodeEngine.h"
11
#include "AudioNodeStream.h"
12
#include "AudioDestinationNode.h"
13
#include "WebAudioUtils.h"
14
15
namespace mozilla {
16
namespace dom {
17
18
NS_IMPL_CYCLE_COLLECTION_INHERITED(GainNode, AudioNode,
19
                                   mGain)
20
21
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(GainNode)
22
0
NS_INTERFACE_MAP_END_INHERITING(AudioNode)
23
24
NS_IMPL_ADDREF_INHERITED(GainNode, AudioNode)
25
NS_IMPL_RELEASE_INHERITED(GainNode, AudioNode)
26
27
class GainNodeEngine final : public AudioNodeEngine
28
{
29
public:
30
  GainNodeEngine(AudioNode* aNode, AudioDestinationNode* aDestination)
31
    : AudioNodeEngine(aNode)
32
    , mDestination(aDestination->Stream())
33
    // Keep the default value in sync with the default value in GainNode::GainNode.
34
    , mGain(1.f)
35
0
  {
36
0
  }
37
38
  enum Parameters {
39
    GAIN
40
  };
41
  void RecvTimelineEvent(uint32_t aIndex,
42
                         AudioTimelineEvent& aEvent) override
43
0
  {
44
0
    MOZ_ASSERT(mDestination);
45
0
    WebAudioUtils::ConvertAudioTimelineEventToTicks(aEvent,
46
0
                                                    mDestination);
47
0
48
0
    switch (aIndex) {
49
0
    case GAIN:
50
0
      mGain.InsertEvent<int64_t>(aEvent);
51
0
      break;
52
0
    default:
53
0
      NS_ERROR("Bad GainNodeEngine TimelineParameter");
54
0
    }
55
0
  }
56
57
  void ProcessBlock(AudioNodeStream* aStream,
58
                    GraphTime aFrom,
59
                    const AudioBlock& aInput,
60
                    AudioBlock* aOutput,
61
                    bool* aFinished) override
62
0
  {
63
0
    if (aInput.IsNull()) {
64
0
      // If input is silent, so is the output
65
0
      aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
66
0
    } else if (mGain.HasSimpleValue()) {
67
0
      // Optimize the case where we only have a single value set as the volume
68
0
      float gain = mGain.GetValue();
69
0
      if (gain == 0.0f) {
70
0
        aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
71
0
      } else {
72
0
        *aOutput = aInput;
73
0
        aOutput->mVolume *= gain;
74
0
      }
75
0
    } else {
76
0
      // First, compute a vector of gains for each track tick based on the
77
0
      // timeline at hand, and then for each channel, multiply the values
78
0
      // in the buffer with the gain vector.
79
0
      aOutput->AllocateChannels(aInput.ChannelCount());
80
0
81
0
      // Compute the gain values for the duration of the input AudioChunk
82
0
      StreamTime tick = mDestination->GraphTimeToStreamTime(aFrom);
83
0
      float computedGain[WEBAUDIO_BLOCK_SIZE + 4];
84
0
      float* alignedComputedGain = ALIGNED16(computedGain);
85
0
      ASSERT_ALIGNED16(alignedComputedGain);
86
0
      mGain.GetValuesAtTime(tick, alignedComputedGain, WEBAUDIO_BLOCK_SIZE);
87
0
88
0
      for (size_t counter = 0; counter < WEBAUDIO_BLOCK_SIZE; ++counter) {
89
0
        alignedComputedGain[counter] *= aInput.mVolume;
90
0
      }
91
0
92
0
      // Apply the gain to the output buffer
93
0
      for (size_t channel = 0; channel < aOutput->ChannelCount(); ++channel) {
94
0
        const float* inputBuffer = static_cast<const float*> (aInput.mChannelData[channel]);
95
0
        float* buffer = aOutput->ChannelFloatsForWrite(channel);
96
0
        AudioBlockCopyChannelWithScale(inputBuffer, alignedComputedGain, buffer);
97
0
      }
98
0
    }
99
0
  }
100
101
  size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override
102
0
  {
103
0
    // Not owned:
104
0
    // - mDestination - MediaStreamGraphImpl::CollectSizesForMemoryReport() accounts for mDestination.
105
0
    // - mGain - Internal ref owned by AudioNode
106
0
    return AudioNodeEngine::SizeOfExcludingThis(aMallocSizeOf);
107
0
  }
108
109
  size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
110
0
  {
111
0
    return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
112
0
  }
113
114
  RefPtr<AudioNodeStream> mDestination;
115
  AudioParamTimeline mGain;
116
};
117
118
GainNode::GainNode(AudioContext* aContext)
119
  : AudioNode(aContext,
120
              2,
121
              ChannelCountMode::Max,
122
              ChannelInterpretation::Speakers)
123
  , mGain(new AudioParam(this, GainNodeEngine::GAIN, "gain", 1.0f))
124
0
{
125
0
  GainNodeEngine* engine = new GainNodeEngine(this, aContext->Destination());
126
0
  mStream = AudioNodeStream::Create(aContext, engine,
127
0
                                    AudioNodeStream::NO_STREAM_FLAGS,
128
0
                                    aContext->Graph());
129
0
}
130
131
/* static */ already_AddRefed<GainNode>
132
GainNode::Create(AudioContext& aAudioContext,
133
                 const GainOptions& aOptions,
134
                 ErrorResult& aRv)
135
0
{
136
0
  if (aAudioContext.CheckClosed(aRv)) {
137
0
    return nullptr;
138
0
  }
139
0
140
0
  RefPtr<GainNode> audioNode = new GainNode(&aAudioContext);
141
0
142
0
  audioNode->Initialize(aOptions, aRv);
143
0
  if (NS_WARN_IF(aRv.Failed())) {
144
0
    return nullptr;
145
0
  }
146
0
147
0
  audioNode->Gain()->SetValue(aOptions.mGain);
148
0
  return audioNode.forget();
149
0
}
150
151
size_t
152
GainNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
153
0
{
154
0
  size_t amount = AudioNode::SizeOfExcludingThis(aMallocSizeOf);
155
0
  amount += mGain->SizeOfIncludingThis(aMallocSizeOf);
156
0
  return amount;
157
0
}
158
159
size_t
160
GainNode::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
161
0
{
162
0
  return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
163
0
}
164
165
JSObject*
166
GainNode::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
167
0
{
168
0
  return GainNode_Binding::Wrap(aCx, this, aGivenProto);
169
0
}
170
171
} // namespace dom
172
} // namespace mozilla