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 "PeriodicWave.h"
8 #include "AudioContext.h"
9 #include "mozilla/dom/PeriodicWaveBinding.h"
10
11 namespace mozilla::dom {
12
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PeriodicWave,mContext)13 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PeriodicWave, mContext)
14
15 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(PeriodicWave, AddRef)
16 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(PeriodicWave, Release)
17
18 PeriodicWave::PeriodicWave(AudioContext* aContext, const float* aRealData,
19 const uint32_t aRealSize, const float* aImagData,
20 const uint32_t aImagSize,
21 const bool aDisableNormalization, ErrorResult& aRv)
22 : mContext(aContext), mDisableNormalization(aDisableNormalization) {
23 if (aRealData && aImagData && aRealSize != aImagSize) {
24 aRv.ThrowIndexSizeError("\"real\" and \"imag\" are different in length");
25 return;
26 }
27
28 uint32_t length = 0;
29 if (aRealData) {
30 length = aRealSize;
31 } else if (aImagData) {
32 length = aImagSize;
33 } else {
34 // If nothing has been passed, this PeriodicWave will be a sine wave: 2
35 // elements for each array, the second imaginary component set to 1.0.
36 length = 2;
37 }
38
39 if (length < 2) {
40 aRv.ThrowIndexSizeError(
41 "\"real\" and \"imag\" must have a length of "
42 "at least 2");
43 return;
44 }
45
46 MOZ_ASSERT(aContext);
47 MOZ_ASSERT((aRealData || aImagData) || length == 2);
48
49 // Caller should have checked this and thrown.
50 MOZ_ASSERT(length >= 2);
51 mCoefficients.mDuration = length;
52
53 // Copy coefficient data.
54 // The SharedBuffer and two arrays share a single allocation.
55 CheckedInt<size_t> bufferSize(sizeof(float));
56 bufferSize *= length;
57 bufferSize *= 2;
58 RefPtr<SharedBuffer> buffer = SharedBuffer::Create(bufferSize, fallible);
59 if (!buffer) {
60 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
61 return;
62 }
63
64 auto data = static_cast<float*>(buffer->Data());
65 mCoefficients.mBuffer = std::move(buffer);
66
67 if (!aRealData && !aImagData) {
68 PodZero(data, length);
69 mCoefficients.mChannelData.AppendElement(data);
70 data += length;
71 data[0] = 0.0f;
72 data[1] = 1.0f;
73 mCoefficients.mChannelData.AppendElement(data);
74 } else {
75 if (aRealData) {
76 PodCopy(data, aRealData, length);
77 } else {
78 PodZero(data, length);
79 }
80 mCoefficients.mChannelData.AppendElement(data);
81
82 data += length;
83 if (aImagData) {
84 PodCopy(data, aImagData, length);
85 } else {
86 PodZero(data, length);
87 }
88 mCoefficients.mChannelData.AppendElement(data);
89 }
90 mCoefficients.mVolume = 1.0f;
91 mCoefficients.mBufferFormat = AUDIO_FORMAT_FLOAT32;
92 }
93
94 /* static */
Constructor(const GlobalObject & aGlobal,AudioContext & aAudioContext,const PeriodicWaveOptions & aOptions,ErrorResult & aRv)95 already_AddRefed<PeriodicWave> PeriodicWave::Constructor(
96 const GlobalObject& aGlobal, AudioContext& aAudioContext,
97 const PeriodicWaveOptions& aOptions, ErrorResult& aRv) {
98 const float* realData;
99 const float* imagData;
100 uint32_t realSize;
101 uint32_t imagSize;
102
103 if (aOptions.mReal.WasPassed()) {
104 realData = aOptions.mReal.Value().Elements();
105 realSize = aOptions.mReal.Value().Length();
106 } else {
107 realData = nullptr;
108 realSize = 0;
109 }
110
111 if (aOptions.mImag.WasPassed()) {
112 imagData = aOptions.mImag.Value().Elements();
113 imagSize = aOptions.mImag.Value().Length();
114 } else {
115 imagData = nullptr;
116 imagSize = 0;
117 }
118
119 RefPtr<PeriodicWave> wave =
120 new PeriodicWave(&aAudioContext, realData, realSize, imagData, imagSize,
121 aOptions.mDisableNormalization, aRv);
122 if (aRv.Failed()) {
123 return nullptr;
124 }
125
126 return wave.forget();
127 }
128
SizeOfExcludingThisIfNotShared(MallocSizeOf aMallocSizeOf) const129 size_t PeriodicWave::SizeOfExcludingThisIfNotShared(
130 MallocSizeOf aMallocSizeOf) const {
131 // Not owned:
132 // - mContext
133 size_t amount = 0;
134 amount += mCoefficients.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
135
136 return amount;
137 }
138
SizeOfIncludingThisIfNotShared(MallocSizeOf aMallocSizeOf) const139 size_t PeriodicWave::SizeOfIncludingThisIfNotShared(
140 MallocSizeOf aMallocSizeOf) const {
141 return aMallocSizeOf(this) + SizeOfExcludingThisIfNotShared(aMallocSizeOf);
142 }
143
WrapObject(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)144 JSObject* PeriodicWave::WrapObject(JSContext* aCx,
145 JS::Handle<JSObject*> aGivenProto) {
146 return PeriodicWave_Binding::Wrap(aCx, this, aGivenProto);
147 }
148
149 } // namespace mozilla::dom
150