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.
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "AudioChannelFormat.h"
7 #include "nsTArray.h"
9 #include <algorithm>
11 namespace mozilla {
13 enum {
14 SURROUND_L,
15 SURROUND_R,
16 SURROUND_C,
17 SURROUND_LFE,
18 SURROUND_SL,
19 SURROUND_SR
20 };
22 static const uint32_t CUSTOM_CHANNEL_LAYOUTS = 6;
24 static const int IGNORE = CUSTOM_CHANNEL_LAYOUTS;
25 static const float IGNORE_F = 0.0f;
27 uint32_t
28 GetAudioChannelsSuperset(uint32_t aChannels1, uint32_t aChannels2)
29 {
30 return std::max(aChannels1, aChannels2);
31 }
33 /**
34 * UpMixMatrix represents a conversion matrix by exploiting the fact that
35 * each output channel comes from at most one input channel.
36 */
37 struct UpMixMatrix {
38 uint8_t mInputDestination[CUSTOM_CHANNEL_LAYOUTS];
39 };
41 static const UpMixMatrix
42 gUpMixMatrices[CUSTOM_CHANNEL_LAYOUTS*(CUSTOM_CHANNEL_LAYOUTS - 1)/2] =
43 {
44 // Upmixes from mono
45 { { 0, 0 } },
46 { { 0, IGNORE, IGNORE } },
47 { { 0, 0, IGNORE, IGNORE } },
48 { { 0, IGNORE, IGNORE, IGNORE, IGNORE } },
49 { { IGNORE, IGNORE, 0, IGNORE, IGNORE, IGNORE } },
50 // Upmixes from stereo
51 { { 0, 1, IGNORE } },
52 { { 0, 1, IGNORE, IGNORE } },
53 { { 0, 1, IGNORE, IGNORE, IGNORE } },
54 { { 0, 1, IGNORE, IGNORE, IGNORE, IGNORE } },
55 // Upmixes from 3-channel
56 { { 0, 1, 2, IGNORE } },
57 { { 0, 1, 2, IGNORE, IGNORE } },
58 { { 0, 1, 2, IGNORE, IGNORE, IGNORE } },
59 // Upmixes from quad
60 { { 0, 1, 2, 3, IGNORE } },
61 { { 0, 1, IGNORE, IGNORE, 2, 3 } },
62 // Upmixes from 5-channel
63 { { 0, 1, 2, 3, 4, IGNORE } }
64 };
66 static const int gMixingMatrixIndexByChannels[CUSTOM_CHANNEL_LAYOUTS - 1] =
67 { 0, 5, 9, 12, 14 };
69 void
70 AudioChannelsUpMix(nsTArray<const void*>* aChannelArray,
71 uint32_t aOutputChannelCount,
72 const void* aZeroChannel)
73 {
74 uint32_t inputChannelCount = aChannelArray->Length();
75 uint32_t outputChannelCount =
76 GetAudioChannelsSuperset(aOutputChannelCount, inputChannelCount);
77 NS_ASSERTION(outputChannelCount > inputChannelCount,
78 "No up-mix needed");
79 NS_ASSERTION(inputChannelCount > 0, "Bad number of channels");
80 NS_ASSERTION(outputChannelCount > 0, "Bad number of channels");
82 aChannelArray->SetLength(outputChannelCount);
84 if (inputChannelCount < CUSTOM_CHANNEL_LAYOUTS &&
85 outputChannelCount <= CUSTOM_CHANNEL_LAYOUTS) {
86 const UpMixMatrix& m = gUpMixMatrices[
87 gMixingMatrixIndexByChannels[inputChannelCount - 1] +
88 outputChannelCount - inputChannelCount - 1];
90 const void* outputChannels[CUSTOM_CHANNEL_LAYOUTS];
92 for (uint32_t i = 0; i < outputChannelCount; ++i) {
93 uint8_t channelIndex = m.mInputDestination[i];
94 if (channelIndex == IGNORE) {
95 outputChannels[i] = aZeroChannel;
96 } else {
97 outputChannels[i] = aChannelArray->ElementAt(channelIndex);
98 }
99 }
100 for (uint32_t i = 0; i < outputChannelCount; ++i) {
101 aChannelArray->ElementAt(i) = outputChannels[i];
102 }
103 return;
104 }
106 for (uint32_t i = inputChannelCount; i < outputChannelCount; ++i) {
107 aChannelArray->ElementAt(i) = aZeroChannel;
108 }
109 }
111 /**
112 * DownMixMatrix represents a conversion matrix efficiently by exploiting the
113 * fact that each input channel contributes to at most one output channel,
114 * except possibly for the C input channel in layouts that have one. Also,
115 * every input channel is multiplied by the same coefficient for every output
116 * channel it contributes to.
117 */
118 struct DownMixMatrix {
119 // Every input channel c is copied to output channel mInputDestination[c]
120 // after multiplying by mInputCoefficient[c].
121 uint8_t mInputDestination[CUSTOM_CHANNEL_LAYOUTS];
122 // If not IGNORE, then the C channel is copied to this output channel after
123 // multiplying by its coefficient.
124 uint8_t mCExtraDestination;
125 float mInputCoefficient[CUSTOM_CHANNEL_LAYOUTS];
126 };
128 static const DownMixMatrix
129 gDownMixMatrices[CUSTOM_CHANNEL_LAYOUTS*(CUSTOM_CHANNEL_LAYOUTS - 1)/2] =
130 {
131 // Downmixes to mono
132 { { 0, 0 }, IGNORE, { 0.5f, 0.5f } },
133 { { 0, IGNORE, IGNORE }, IGNORE, { 1.0f, IGNORE_F, IGNORE_F } },
134 { { 0, 0, 0, 0 }, IGNORE, { 0.25f, 0.25f, 0.25f, 0.25f } },
135 { { 0, IGNORE, IGNORE, IGNORE, IGNORE }, IGNORE, { 1.0f, IGNORE_F, IGNORE_F, IGNORE_F, IGNORE_F } },
136 { { 0, 0, 0, IGNORE, 0, 0 }, IGNORE, { 0.7071f, 0.7071f, 1.0f, IGNORE_F, 0.5f, 0.5f } },
137 // Downmixes to stereo
138 { { 0, 1, IGNORE }, IGNORE, { 1.0f, 1.0f, IGNORE_F } },
139 { { 0, 1, 0, 1 }, IGNORE, { 0.5f, 0.5f, 0.5f, 0.5f } },
140 { { 0, 1, IGNORE, IGNORE, IGNORE }, IGNORE, { 1.0f, 1.0f, IGNORE_F, IGNORE_F, IGNORE_F } },
141 { { 0, 1, 0, IGNORE, 0, 1 }, 1, { 1.0f, 1.0f, 0.7071f, IGNORE_F, 0.7071f, 0.7071f } },
142 // Downmixes to 3-channel
143 { { 0, 1, 2, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, IGNORE_F } },
144 { { 0, 1, 2, IGNORE, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, IGNORE_F, IGNORE_F } },
145 { { 0, 1, 2, IGNORE, IGNORE, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, IGNORE_F, IGNORE_F, IGNORE_F } },
146 // Downmixes to quad
147 { { 0, 1, 2, 3, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, 1.0f, IGNORE_F } },
148 { { 0, 1, 0, IGNORE, 2, 3 }, 1, { 1.0f, 1.0f, 0.7071f, IGNORE_F, 1.0f, 1.0f } },
149 // Downmixes to 5-channel
150 { { 0, 1, 2, 3, 4, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, IGNORE_F } }
151 };
153 void
154 AudioChannelsDownMix(const nsTArray<const void*>& aChannelArray,
155 float** aOutputChannels,
156 uint32_t aOutputChannelCount,
157 uint32_t aDuration)
158 {
159 uint32_t inputChannelCount = aChannelArray.Length();
160 const void* const* inputChannels = aChannelArray.Elements();
161 NS_ASSERTION(inputChannelCount > aOutputChannelCount, "Nothing to do");
163 if (inputChannelCount > 6) {
164 // Just drop the unknown channels.
165 for (uint32_t o = 0; o < aOutputChannelCount; ++o) {
166 memcpy(aOutputChannels[o], inputChannels[o], aDuration*sizeof(float));
167 }
168 return;
169 }
171 // Ignore unknown channels, they're just dropped.
172 inputChannelCount = std::min<uint32_t>(6, inputChannelCount);
174 const DownMixMatrix& m = gDownMixMatrices[
175 gMixingMatrixIndexByChannels[aOutputChannelCount - 1] +
176 inputChannelCount - aOutputChannelCount - 1];
178 // This is slow, but general. We can define custom code for special
179 // cases later.
180 for (uint32_t s = 0; s < aDuration; ++s) {
181 // Reserve an extra junk channel at the end for the cases where we
182 // want an input channel to contribute to nothing
183 float outputChannels[CUSTOM_CHANNEL_LAYOUTS + 1];
184 memset(outputChannels, 0, sizeof(float)*(CUSTOM_CHANNEL_LAYOUTS));
185 for (uint32_t c = 0; c < inputChannelCount; ++c) {
186 outputChannels[m.mInputDestination[c]] +=
187 m.mInputCoefficient[c]*(static_cast<const float*>(inputChannels[c]))[s];
188 }
189 // Utilize the fact that in every layout, C is the third channel.
190 if (m.mCExtraDestination != IGNORE) {
191 outputChannels[m.mCExtraDestination] +=
192 m.mInputCoefficient[SURROUND_C]*(static_cast<const float*>(inputChannels[SURROUND_C]))[s];
193 }
195 for (uint32_t c = 0; c < aOutputChannelCount; ++c) {
196 aOutputChannels[c][s] = outputChannels[c];
197 }
198 }
199 }
201 }