AudioMixer: Expand mono track to multi-channel
Extend MONO_HACK to multi-channel output.
Mono track will have only one channel output on multi-channel devices.
Since ARC++ exposed a 4-channel output device and downmix track in
ChromeOS, we need to add this feature to support mono track sample
expansion.
Add support for both re-sample and non-resample path.
For resample path, we need to add MIXTYPE_STEREOEXPAND in
AudioMixerOps.h since AudioResampler will upmix mono track to stereo
track.
Bug: 120222604
Bug: 112341269
Bug: 117116052
Bug: crbug.com/890560
Test: Play mono tracks without re-sampling on ARC++
Test: Play mono tracks with re-sampling on ARC++
Test: Play normal stereo tracks on ARC++
(cherry picked from commit 9b79e0752e6536c31430aa31838a9de1b7b56f9f)
Change-Id: I51f5914c41dd0196db9c6a2e1a99b44e5d87c0d6
diff --git a/media/libaudioprocessing/AudioMixerOps.h b/media/libaudioprocessing/AudioMixerOps.h
index d3a26ad..2748182 100644
--- a/media/libaudioprocessing/AudioMixerOps.h
+++ b/media/libaudioprocessing/AudioMixerOps.h
@@ -219,6 +219,7 @@
MIXTYPE_MULTI_SAVEONLY_MONOVOL,
MIXTYPE_MULTI_STEREOVOL,
MIXTYPE_MULTI_SAVEONLY_STEREOVOL,
+ MIXTYPE_STEREOEXPAND,
};
/*
@@ -232,7 +233,8 @@
void stereoVolumeHelper(TO*& out, const TI*& in, const TV *vol, F f) {
static_assert(NCHAN > 0 && NCHAN <= 8);
static_assert(MIXTYPE == MIXTYPE_MULTI_STEREOVOL
- || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL);
+ || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL
+ || MIXTYPE == MIXTYPE_STEREOEXPAND);
auto proc = [](auto& a, const auto& b) {
if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL) {
a += b;
@@ -240,14 +242,22 @@
a = b;
}
};
+ auto inp = [&in]() -> const TI& {
+ if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND) {
+ return *in;
+ } else {
+ return *in++;
+ }
+ };
+
// HALs should only expose the canonical channel masks.
- proc(*out++, f(*in++, vol[0])); // front left
+ proc(*out++, f(inp(), vol[0])); // front left
if constexpr (NCHAN == 1) return;
- proc(*out++, f(*in++, vol[1])); // front right
+ proc(*out++, f(inp(), vol[1])); // front right
if constexpr (NCHAN == 2) return;
if constexpr (NCHAN == 4) {
- proc(*out++, f(*in++, vol[0])); // back left
- proc(*out++, f(*in++, vol[1])); // back right
+ proc(*out++, f(inp(), vol[0])); // back left
+ proc(*out++, f(inp(), vol[1])); // back right
return;
}
@@ -258,25 +268,25 @@
} else {
center = (vol[0] >> 1) + (vol[1] >> 1); // rounds to 0.
}
- proc(*out++, f(*in++, center)); // center (or 2.1 LFE)
+ proc(*out++, f(inp(), center)); // center (or 2.1 LFE)
if constexpr (NCHAN == 3) return;
if constexpr (NCHAN == 5) {
- proc(*out++, f(*in++, vol[0])); // back left
- proc(*out++, f(*in++, vol[1])); // back right
+ proc(*out++, f(inp(), vol[0])); // back left
+ proc(*out++, f(inp(), vol[1])); // back right
return;
}
- proc(*out++, f(*in++, center)); // lfe
- proc(*out++, f(*in++, vol[0])); // back left
- proc(*out++, f(*in++, vol[1])); // back right
+ proc(*out++, f(inp(), center)); // lfe
+ proc(*out++, f(inp(), vol[0])); // back left
+ proc(*out++, f(inp(), vol[1])); // back right
if constexpr (NCHAN == 6) return;
if constexpr (NCHAN == 7) {
- proc(*out++, f(*in++, center)); // back center
+ proc(*out++, f(inp(), center)); // back center
return;
}
// NCHAN == 8
- proc(*out++, f(*in++, vol[0])); // side left
- proc(*out++, f(*in++, vol[1])); // side right
+ proc(*out++, f(inp(), vol[0])); // side left
+ proc(*out++, f(inp(), vol[1])); // side right
}
/*
@@ -326,6 +336,11 @@
* MIXTYPE_MULTI_SAVEONLY_STEREOVOL:
* Same as MIXTYPE_MULTI_SAVEONLY, but uses only volume[0] and volume[1].
*
+ * MIXTYPE_STEREOEXPAND:
+ * Stereo input channel. NCHAN represents number of output channels.
+ * Expand size 2 array "in" and "vol" to multi-channel output. Note
+ * that the 2 array is assumed to have replicated L+R.
+ *
*/
template <int MIXTYPE, int NCHAN,
@@ -366,11 +381,13 @@
}
vol[0] += volinc[0];
} else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL
- || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL) {
+ || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL
+ || MIXTYPE == MIXTYPE_STEREOEXPAND) {
stereoVolumeHelper<MIXTYPE, NCHAN>(
out, in, vol, [&auxaccum] (auto &a, const auto &b) {
return MixMulAux<TO, TI, TV, TA>(a, b, &auxaccum);
});
+ if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND) in += 2;
vol[0] += volinc[0];
vol[1] += volinc[1];
} else /* constexpr */ {
@@ -409,10 +426,12 @@
}
vol[0] += volinc[0];
} else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL
- || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL) {
+ || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL
+ || MIXTYPE == MIXTYPE_STEREOEXPAND) {
stereoVolumeHelper<MIXTYPE, NCHAN>(out, in, vol, [] (auto &a, const auto &b) {
return MixMul<TO, TI, TV>(a, b);
});
+ if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND) in += 2;
vol[0] += volinc[0];
vol[1] += volinc[1];
} else /* constexpr */ {
@@ -455,11 +474,13 @@
*out++ = MixMulAux<TO, TI, TV, TA>(*in++, vol[0], &auxaccum);
}
} else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL
- || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL) {
+ || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL
+ || MIXTYPE == MIXTYPE_STEREOEXPAND) {
stereoVolumeHelper<MIXTYPE, NCHAN>(
out, in, vol, [&auxaccum] (auto &a, const auto &b) {
return MixMulAux<TO, TI, TV, TA>(a, b, &auxaccum);
});
+ if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND) in += 2;
} else /* constexpr */ {
static_assert(dependent_false<MIXTYPE>, "invalid mixtype");
}
@@ -490,10 +511,12 @@
*out++ = MixMul<TO, TI, TV>(*in++, vol[0]);
}
} else if constexpr (MIXTYPE == MIXTYPE_MULTI_STEREOVOL
- || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL) {
+ || MIXTYPE == MIXTYPE_MULTI_SAVEONLY_STEREOVOL
+ || MIXTYPE == MIXTYPE_STEREOEXPAND) {
stereoVolumeHelper<MIXTYPE, NCHAN>(out, in, vol, [] (auto &a, const auto &b) {
return MixMul<TO, TI, TV>(a, b);
});
+ if constexpr (MIXTYPE == MIXTYPE_STEREOEXPAND) in += 2;
} else /* constexpr */ {
static_assert(dependent_false<MIXTYPE>, "invalid mixtype");
}