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 #ifndef AudioParamTimeline_h_
8 #define AudioParamTimeline_h_
9 
10 #include "AudioEventTimeline.h"
11 #include "mozilla/ErrorResult.h"
12 #include "MediaStreamGraph.h"
13 #include "AudioSegment.h"
14 
15 namespace mozilla {
16 
17 namespace dom {
18 
19 // This helper class is used to represent the part of the AudioParam
20 // class that gets sent to AudioNodeEngine instances.  In addition to
21 // AudioEventTimeline methods, it holds a pointer to an optional
22 // MediaStream which represents the AudioNode inputs to the AudioParam.
23 // This MediaStream is managed by the AudioParam subclass on the main
24 // thread, and can only be obtained from the AudioNodeEngine instances
25 // consuming this class.
26 class AudioParamTimeline : public AudioEventTimeline {
27   typedef AudioEventTimeline BaseClass;
28 
29  public:
AudioParamTimeline(float aDefaultValue)30   explicit AudioParamTimeline(float aDefaultValue) : BaseClass(aDefaultValue) {}
31 
Stream()32   MediaStream* Stream() const { return mStream; }
33 
HasSimpleValue()34   bool HasSimpleValue() const {
35     return BaseClass::HasSimpleValue() && !mStream;
36   }
37 
38   template <class TimeType>
GetValueAtTime(TimeType aTime)39   float GetValueAtTime(TimeType aTime) {
40     return GetValueAtTime(aTime, 0);
41   }
42 
43   template <typename TimeType>
InsertEvent(const AudioTimelineEvent & aEvent)44   void InsertEvent(const AudioTimelineEvent& aEvent) {
45     if (aEvent.mType == AudioTimelineEvent::Cancel) {
46       CancelScheduledValues(aEvent.template Time<TimeType>());
47       return;
48     }
49     if (aEvent.mType == AudioTimelineEvent::Stream) {
50       mStream = aEvent.mStream;
51       return;
52     }
53     if (aEvent.mType == AudioTimelineEvent::SetValue) {
54       AudioEventTimeline::SetValue(aEvent.mValue);
55       return;
56     }
57     AudioEventTimeline::InsertEvent<TimeType>(aEvent);
58   }
59 
60   // Get the value of the AudioParam at time aTime + aCounter.
61   // aCounter here is an offset to aTime if we try to get the value in ticks,
62   // otherwise it should always be zero.  aCounter is meant to be used when
63   template <class TimeType>
64   float GetValueAtTime(TimeType aTime, size_t aCounter);
65 
66   // Get the values of the AudioParam at time aTime + (0 to aSize).
67   // aBuffer must have the correct aSize.
68   // aSize here is an offset to aTime if we try to get the value in ticks,
69   // otherwise it should always be zero.  aSize is meant to be used when
70   // getting the value of an a-rate AudioParam for each tick inside an
71   // AudioNodeEngine implementation.
72   template <class TimeType>
73   void GetValuesAtTime(TimeType aTime, float* aBuffer, const size_t aSize);
74 
SizeOfExcludingThis(MallocSizeOf aMallocSizeOf)75   virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
76     return mStream ? mStream->SizeOfIncludingThis(aMallocSizeOf) : 0;
77   }
78 
SizeOfIncludingThis(MallocSizeOf aMallocSizeOf)79   virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
80     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
81   }
82 
83  private:
84   float AudioNodeInputValue(size_t aCounter) const;
85 
86  protected:
87   // This is created lazily when needed.
88   RefPtr<MediaStream> mStream;
89 };
90 
91 template <>
GetValueAtTime(double aTime,size_t aCounter)92 inline float AudioParamTimeline::GetValueAtTime(double aTime, size_t aCounter) {
93   MOZ_ASSERT(!aCounter);
94 
95   // Getting an AudioParam value on an AudioNode does not consider input from
96   // other AudioNodes, which is managed only on the graph thread.
97   return BaseClass::GetValueAtTime(aTime);
98 }
99 
100 template <>
GetValueAtTime(int64_t aTime,size_t aCounter)101 inline float AudioParamTimeline::GetValueAtTime(int64_t aTime,
102                                                 size_t aCounter) {
103   MOZ_ASSERT(aCounter < WEBAUDIO_BLOCK_SIZE);
104   MOZ_ASSERT(!aCounter || !HasSimpleValue());
105 
106   // Mix the value of the AudioParam itself with that of the AudioNode inputs.
107   return BaseClass::GetValueAtTime(static_cast<int64_t>(aTime + aCounter)) +
108          (mStream ? AudioNodeInputValue(aCounter) : 0.0f);
109 }
110 
111 template <>
GetValuesAtTime(double aTime,float * aBuffer,const size_t aSize)112 inline void AudioParamTimeline::GetValuesAtTime(double aTime, float* aBuffer,
113                                                 const size_t aSize) {
114   MOZ_ASSERT(aBuffer);
115   MOZ_ASSERT(aSize == 1);
116 
117   // Getting an AudioParam value on an AudioNode does not consider input from
118   // other AudioNodes, which is managed only on the graph thread.
119   *aBuffer = BaseClass::GetValueAtTime(aTime);
120 }
121 
122 template <>
GetValuesAtTime(int64_t aTime,float * aBuffer,const size_t aSize)123 inline void AudioParamTimeline::GetValuesAtTime(int64_t aTime, float* aBuffer,
124                                                 const size_t aSize) {
125   MOZ_ASSERT(aBuffer);
126   MOZ_ASSERT(aSize <= WEBAUDIO_BLOCK_SIZE);
127   MOZ_ASSERT(aSize == 1 || !HasSimpleValue());
128 
129   // Mix the value of the AudioParam itself with that of the AudioNode inputs.
130   BaseClass::GetValuesAtTime(aTime, aBuffer, aSize);
131   if (mStream) {
132     for (size_t i = 0; i < aSize; ++i) {
133       aBuffer[i] += AudioNodeInputValue(i);
134     }
135   }
136 }
137 
138 }  // namespace dom
139 }  // namespace mozilla
140 
141 #endif
142