1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker **
3*ec779b8eSAndroid Build Coastguard Worker ** Copyright 2007, The Android Open Source Project
4*ec779b8eSAndroid Build Coastguard Worker **
5*ec779b8eSAndroid Build Coastguard Worker ** Licensed under the Apache License, Version 2.0 (the "License");
6*ec779b8eSAndroid Build Coastguard Worker ** you may not use this file except in compliance with the License.
7*ec779b8eSAndroid Build Coastguard Worker ** You may obtain a copy of the License at
8*ec779b8eSAndroid Build Coastguard Worker **
9*ec779b8eSAndroid Build Coastguard Worker ** http://www.apache.org/licenses/LICENSE-2.0
10*ec779b8eSAndroid Build Coastguard Worker **
11*ec779b8eSAndroid Build Coastguard Worker ** Unless required by applicable law or agreed to in writing, software
12*ec779b8eSAndroid Build Coastguard Worker ** distributed under the License is distributed on an "AS IS" BASIS,
13*ec779b8eSAndroid Build Coastguard Worker ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*ec779b8eSAndroid Build Coastguard Worker ** See the License for the specific language governing permissions and
15*ec779b8eSAndroid Build Coastguard Worker ** limitations under the License.
16*ec779b8eSAndroid Build Coastguard Worker */
17*ec779b8eSAndroid Build Coastguard Worker
18*ec779b8eSAndroid Build Coastguard Worker #define LOG_TAG "AudioMixer"
19*ec779b8eSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
20*ec779b8eSAndroid Build Coastguard Worker
21*ec779b8eSAndroid Build Coastguard Worker #include <sstream>
22*ec779b8eSAndroid Build Coastguard Worker #include <stdint.h>
23*ec779b8eSAndroid Build Coastguard Worker #include <string.h>
24*ec779b8eSAndroid Build Coastguard Worker #include <stdlib.h>
25*ec779b8eSAndroid Build Coastguard Worker #include <math.h>
26*ec779b8eSAndroid Build Coastguard Worker #include <sys/types.h>
27*ec779b8eSAndroid Build Coastguard Worker
28*ec779b8eSAndroid Build Coastguard Worker #include <utils/Errors.h>
29*ec779b8eSAndroid Build Coastguard Worker #include <utils/Log.h>
30*ec779b8eSAndroid Build Coastguard Worker
31*ec779b8eSAndroid Build Coastguard Worker #include <system/audio.h>
32*ec779b8eSAndroid Build Coastguard Worker
33*ec779b8eSAndroid Build Coastguard Worker #include <audio_utils/primitives.h>
34*ec779b8eSAndroid Build Coastguard Worker #include <audio_utils/format.h>
35*ec779b8eSAndroid Build Coastguard Worker #include <media/AudioMixer.h>
36*ec779b8eSAndroid Build Coastguard Worker
37*ec779b8eSAndroid Build Coastguard Worker #include "AudioMixerOps.h"
38*ec779b8eSAndroid Build Coastguard Worker
39*ec779b8eSAndroid Build Coastguard Worker // The FCC_2 macro refers to the Fixed Channel Count of 2 for the legacy integer mixer.
40*ec779b8eSAndroid Build Coastguard Worker #ifndef FCC_2
41*ec779b8eSAndroid Build Coastguard Worker #define FCC_2 2
42*ec779b8eSAndroid Build Coastguard Worker #endif
43*ec779b8eSAndroid Build Coastguard Worker
44*ec779b8eSAndroid Build Coastguard Worker // Look for MONO_HACK for any Mono hack involving legacy mono channel to
45*ec779b8eSAndroid Build Coastguard Worker // stereo channel conversion.
46*ec779b8eSAndroid Build Coastguard Worker
47*ec779b8eSAndroid Build Coastguard Worker /* VERY_VERY_VERBOSE_LOGGING will show exactly which process hook and track hook is
48*ec779b8eSAndroid Build Coastguard Worker * being used. This is a considerable amount of log spam, so don't enable unless you
49*ec779b8eSAndroid Build Coastguard Worker * are verifying the hook based code.
50*ec779b8eSAndroid Build Coastguard Worker */
51*ec779b8eSAndroid Build Coastguard Worker //#define VERY_VERY_VERBOSE_LOGGING
52*ec779b8eSAndroid Build Coastguard Worker #ifdef VERY_VERY_VERBOSE_LOGGING
53*ec779b8eSAndroid Build Coastguard Worker #define ALOGVV ALOGV
54*ec779b8eSAndroid Build Coastguard Worker //define ALOGVV printf // for test-mixer.cpp
55*ec779b8eSAndroid Build Coastguard Worker #else
56*ec779b8eSAndroid Build Coastguard Worker #define ALOGVV(a...) do { } while (0)
57*ec779b8eSAndroid Build Coastguard Worker #endif
58*ec779b8eSAndroid Build Coastguard Worker
59*ec779b8eSAndroid Build Coastguard Worker // Set to default copy buffer size in frames for input processing.
60*ec779b8eSAndroid Build Coastguard Worker static constexpr size_t kCopyBufferFrameCount = 256;
61*ec779b8eSAndroid Build Coastguard Worker
62*ec779b8eSAndroid Build Coastguard Worker namespace android {
63*ec779b8eSAndroid Build Coastguard Worker
64*ec779b8eSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
65*ec779b8eSAndroid Build Coastguard Worker
isValidChannelMask(audio_channel_mask_t channelMask) const66*ec779b8eSAndroid Build Coastguard Worker bool AudioMixer::isValidChannelMask(audio_channel_mask_t channelMask) const {
67*ec779b8eSAndroid Build Coastguard Worker return audio_channel_mask_is_valid(channelMask); // the RemixBufferProvider is flexible.
68*ec779b8eSAndroid Build Coastguard Worker }
69*ec779b8eSAndroid Build Coastguard Worker
70*ec779b8eSAndroid Build Coastguard Worker // Called when channel masks have changed for a track name
71*ec779b8eSAndroid Build Coastguard Worker // TODO: Fix DownmixerBufferProvider not to (possibly) change mixer input format,
72*ec779b8eSAndroid Build Coastguard Worker // which will simplify this logic.
setChannelMasks(int name,audio_channel_mask_t trackChannelMask,audio_channel_mask_t mixerChannelMask)73*ec779b8eSAndroid Build Coastguard Worker bool AudioMixer::setChannelMasks(int name,
74*ec779b8eSAndroid Build Coastguard Worker audio_channel_mask_t trackChannelMask, audio_channel_mask_t mixerChannelMask) {
75*ec779b8eSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(!exists(name), "invalid name: %d", name);
76*ec779b8eSAndroid Build Coastguard Worker const std::shared_ptr<Track> &track = getTrack(name);
77*ec779b8eSAndroid Build Coastguard Worker
78*ec779b8eSAndroid Build Coastguard Worker if (trackChannelMask == (track->channelMask | track->mHapticChannelMask)
79*ec779b8eSAndroid Build Coastguard Worker && mixerChannelMask == (track->mMixerChannelMask | track->mMixerHapticChannelMask)) {
80*ec779b8eSAndroid Build Coastguard Worker return false; // no need to change
81*ec779b8eSAndroid Build Coastguard Worker }
82*ec779b8eSAndroid Build Coastguard Worker const audio_channel_mask_t hapticChannelMask =
83*ec779b8eSAndroid Build Coastguard Worker static_cast<audio_channel_mask_t>(trackChannelMask & AUDIO_CHANNEL_HAPTIC_ALL);
84*ec779b8eSAndroid Build Coastguard Worker trackChannelMask = static_cast<audio_channel_mask_t>(
85*ec779b8eSAndroid Build Coastguard Worker trackChannelMask & ~AUDIO_CHANNEL_HAPTIC_ALL);
86*ec779b8eSAndroid Build Coastguard Worker const audio_channel_mask_t mixerHapticChannelMask = static_cast<audio_channel_mask_t>(
87*ec779b8eSAndroid Build Coastguard Worker mixerChannelMask & AUDIO_CHANNEL_HAPTIC_ALL);
88*ec779b8eSAndroid Build Coastguard Worker mixerChannelMask = static_cast<audio_channel_mask_t>(
89*ec779b8eSAndroid Build Coastguard Worker mixerChannelMask & ~AUDIO_CHANNEL_HAPTIC_ALL);
90*ec779b8eSAndroid Build Coastguard Worker // always recompute for both channel masks even if only one has changed.
91*ec779b8eSAndroid Build Coastguard Worker const uint32_t trackChannelCount = audio_channel_count_from_out_mask(trackChannelMask);
92*ec779b8eSAndroid Build Coastguard Worker const uint32_t mixerChannelCount = audio_channel_count_from_out_mask(mixerChannelMask);
93*ec779b8eSAndroid Build Coastguard Worker const uint32_t hapticChannelCount = audio_channel_count_from_out_mask(hapticChannelMask);
94*ec779b8eSAndroid Build Coastguard Worker const uint32_t mixerHapticChannelCount =
95*ec779b8eSAndroid Build Coastguard Worker audio_channel_count_from_out_mask(mixerHapticChannelMask);
96*ec779b8eSAndroid Build Coastguard Worker
97*ec779b8eSAndroid Build Coastguard Worker ALOG_ASSERT((trackChannelCount <= MAX_NUM_CHANNELS_TO_DOWNMIX)
98*ec779b8eSAndroid Build Coastguard Worker && trackChannelCount
99*ec779b8eSAndroid Build Coastguard Worker && mixerChannelCount);
100*ec779b8eSAndroid Build Coastguard Worker track->channelMask = trackChannelMask;
101*ec779b8eSAndroid Build Coastguard Worker track->channelCount = trackChannelCount;
102*ec779b8eSAndroid Build Coastguard Worker track->mMixerChannelMask = mixerChannelMask;
103*ec779b8eSAndroid Build Coastguard Worker track->mMixerChannelCount = mixerChannelCount;
104*ec779b8eSAndroid Build Coastguard Worker track->mHapticChannelMask = hapticChannelMask;
105*ec779b8eSAndroid Build Coastguard Worker track->mHapticChannelCount = hapticChannelCount;
106*ec779b8eSAndroid Build Coastguard Worker track->mMixerHapticChannelMask = mixerHapticChannelMask;
107*ec779b8eSAndroid Build Coastguard Worker track->mMixerHapticChannelCount = mixerHapticChannelCount;
108*ec779b8eSAndroid Build Coastguard Worker
109*ec779b8eSAndroid Build Coastguard Worker if (track->mHapticChannelCount > 0) {
110*ec779b8eSAndroid Build Coastguard Worker track->mAdjustInChannelCount = track->channelCount + track->mHapticChannelCount;
111*ec779b8eSAndroid Build Coastguard Worker track->mAdjustOutChannelCount = track->channelCount;
112*ec779b8eSAndroid Build Coastguard Worker track->mKeepContractedChannels = track->mHapticPlaybackEnabled;
113*ec779b8eSAndroid Build Coastguard Worker } else {
114*ec779b8eSAndroid Build Coastguard Worker track->mAdjustInChannelCount = 0;
115*ec779b8eSAndroid Build Coastguard Worker track->mAdjustOutChannelCount = 0;
116*ec779b8eSAndroid Build Coastguard Worker track->mKeepContractedChannels = false;
117*ec779b8eSAndroid Build Coastguard Worker }
118*ec779b8eSAndroid Build Coastguard Worker
119*ec779b8eSAndroid Build Coastguard Worker track->mInputFrameSize = audio_bytes_per_frame(
120*ec779b8eSAndroid Build Coastguard Worker track->channelCount + track->mHapticChannelCount, track->mFormat);
121*ec779b8eSAndroid Build Coastguard Worker
122*ec779b8eSAndroid Build Coastguard Worker // channel masks have changed, does this track need a downmixer?
123*ec779b8eSAndroid Build Coastguard Worker // update to try using our desired format (if we aren't already using it)
124*ec779b8eSAndroid Build Coastguard Worker const status_t status = track->prepareForDownmix();
125*ec779b8eSAndroid Build Coastguard Worker ALOGE_IF(status != OK,
126*ec779b8eSAndroid Build Coastguard Worker "prepareForDownmix error %d, track channel mask %#x, mixer channel mask %#x",
127*ec779b8eSAndroid Build Coastguard Worker status, track->channelMask, track->mMixerChannelMask);
128*ec779b8eSAndroid Build Coastguard Worker
129*ec779b8eSAndroid Build Coastguard Worker // always do reformat since channel mask changed,
130*ec779b8eSAndroid Build Coastguard Worker // do it after downmix since track format may change!
131*ec779b8eSAndroid Build Coastguard Worker track->prepareForReformat();
132*ec779b8eSAndroid Build Coastguard Worker
133*ec779b8eSAndroid Build Coastguard Worker track->prepareForAdjustChannels(mFrameCount);
134*ec779b8eSAndroid Build Coastguard Worker
135*ec779b8eSAndroid Build Coastguard Worker // Resampler channels may have changed.
136*ec779b8eSAndroid Build Coastguard Worker track->recreateResampler(mSampleRate);
137*ec779b8eSAndroid Build Coastguard Worker return true;
138*ec779b8eSAndroid Build Coastguard Worker }
139*ec779b8eSAndroid Build Coastguard Worker
unprepareForDownmix()140*ec779b8eSAndroid Build Coastguard Worker void AudioMixer::Track::unprepareForDownmix() {
141*ec779b8eSAndroid Build Coastguard Worker ALOGV("AudioMixer::unprepareForDownmix(%p)", this);
142*ec779b8eSAndroid Build Coastguard Worker
143*ec779b8eSAndroid Build Coastguard Worker if (mPostDownmixReformatBufferProvider.get() != nullptr) {
144*ec779b8eSAndroid Build Coastguard Worker // release any buffers held by the mPostDownmixReformatBufferProvider
145*ec779b8eSAndroid Build Coastguard Worker // before deallocating the mDownmixerBufferProvider.
146*ec779b8eSAndroid Build Coastguard Worker mPostDownmixReformatBufferProvider->reset();
147*ec779b8eSAndroid Build Coastguard Worker }
148*ec779b8eSAndroid Build Coastguard Worker
149*ec779b8eSAndroid Build Coastguard Worker mDownmixRequiresFormat = AUDIO_FORMAT_INVALID;
150*ec779b8eSAndroid Build Coastguard Worker if (mDownmixerBufferProvider.get() != nullptr) {
151*ec779b8eSAndroid Build Coastguard Worker // this track had previously been configured with a downmixer, delete it
152*ec779b8eSAndroid Build Coastguard Worker mDownmixerBufferProvider.reset(nullptr);
153*ec779b8eSAndroid Build Coastguard Worker reconfigureBufferProviders();
154*ec779b8eSAndroid Build Coastguard Worker } else {
155*ec779b8eSAndroid Build Coastguard Worker ALOGV(" nothing to do, no downmixer to delete");
156*ec779b8eSAndroid Build Coastguard Worker }
157*ec779b8eSAndroid Build Coastguard Worker }
158*ec779b8eSAndroid Build Coastguard Worker
prepareForDownmix()159*ec779b8eSAndroid Build Coastguard Worker status_t AudioMixer::Track::prepareForDownmix()
160*ec779b8eSAndroid Build Coastguard Worker {
161*ec779b8eSAndroid Build Coastguard Worker ALOGV("AudioMixer::prepareForDownmix(%p) with mask 0x%x",
162*ec779b8eSAndroid Build Coastguard Worker this, channelMask);
163*ec779b8eSAndroid Build Coastguard Worker
164*ec779b8eSAndroid Build Coastguard Worker // discard the previous downmixer if there was one
165*ec779b8eSAndroid Build Coastguard Worker unprepareForDownmix();
166*ec779b8eSAndroid Build Coastguard Worker // MONO_HACK Only remix (upmix or downmix) if the track and mixer/device channel masks
167*ec779b8eSAndroid Build Coastguard Worker // are not the same and not handled internally, as mono for channel position masks is.
168*ec779b8eSAndroid Build Coastguard Worker if (channelMask == mMixerChannelMask
169*ec779b8eSAndroid Build Coastguard Worker || (channelMask == AUDIO_CHANNEL_OUT_MONO
170*ec779b8eSAndroid Build Coastguard Worker && isAudioChannelPositionMask(mMixerChannelMask))) {
171*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
172*ec779b8eSAndroid Build Coastguard Worker }
173*ec779b8eSAndroid Build Coastguard Worker // DownmixerBufferProvider is only used for position masks.
174*ec779b8eSAndroid Build Coastguard Worker if (audio_channel_mask_get_representation(channelMask)
175*ec779b8eSAndroid Build Coastguard Worker == AUDIO_CHANNEL_REPRESENTATION_POSITION
176*ec779b8eSAndroid Build Coastguard Worker && DownmixerBufferProvider::isMultichannelCapable()) {
177*ec779b8eSAndroid Build Coastguard Worker
178*ec779b8eSAndroid Build Coastguard Worker // Check if we have a float or int16 downmixer, in that order.
179*ec779b8eSAndroid Build Coastguard Worker for (const audio_format_t format : { AUDIO_FORMAT_PCM_FLOAT, AUDIO_FORMAT_PCM_16_BIT }) {
180*ec779b8eSAndroid Build Coastguard Worker mDownmixerBufferProvider.reset(new DownmixerBufferProvider(
181*ec779b8eSAndroid Build Coastguard Worker channelMask, mMixerChannelMask,
182*ec779b8eSAndroid Build Coastguard Worker format,
183*ec779b8eSAndroid Build Coastguard Worker sampleRate, sessionId, kCopyBufferFrameCount));
184*ec779b8eSAndroid Build Coastguard Worker if (static_cast<DownmixerBufferProvider *>(mDownmixerBufferProvider.get())
185*ec779b8eSAndroid Build Coastguard Worker ->isValid()) {
186*ec779b8eSAndroid Build Coastguard Worker mDownmixRequiresFormat = format;
187*ec779b8eSAndroid Build Coastguard Worker reconfigureBufferProviders();
188*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
189*ec779b8eSAndroid Build Coastguard Worker }
190*ec779b8eSAndroid Build Coastguard Worker }
191*ec779b8eSAndroid Build Coastguard Worker // mDownmixerBufferProvider reset below.
192*ec779b8eSAndroid Build Coastguard Worker }
193*ec779b8eSAndroid Build Coastguard Worker
194*ec779b8eSAndroid Build Coastguard Worker // See if we should use our built-in non-effect downmixer.
195*ec779b8eSAndroid Build Coastguard Worker if (mMixerInFormat == AUDIO_FORMAT_PCM_FLOAT
196*ec779b8eSAndroid Build Coastguard Worker && ChannelMixBufferProvider::isOutputChannelMaskSupported(mMixerChannelMask)
197*ec779b8eSAndroid Build Coastguard Worker && audio_channel_mask_get_representation(channelMask)
198*ec779b8eSAndroid Build Coastguard Worker == AUDIO_CHANNEL_REPRESENTATION_POSITION) {
199*ec779b8eSAndroid Build Coastguard Worker mDownmixerBufferProvider.reset(new ChannelMixBufferProvider(channelMask,
200*ec779b8eSAndroid Build Coastguard Worker mMixerChannelMask, mMixerInFormat, kCopyBufferFrameCount));
201*ec779b8eSAndroid Build Coastguard Worker if (static_cast<ChannelMixBufferProvider *>(mDownmixerBufferProvider.get())
202*ec779b8eSAndroid Build Coastguard Worker ->isValid()) {
203*ec779b8eSAndroid Build Coastguard Worker mDownmixRequiresFormat = mMixerInFormat;
204*ec779b8eSAndroid Build Coastguard Worker reconfigureBufferProviders();
205*ec779b8eSAndroid Build Coastguard Worker ALOGD("%s: Fallback using ChannelMix", __func__);
206*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
207*ec779b8eSAndroid Build Coastguard Worker } else {
208*ec779b8eSAndroid Build Coastguard Worker ALOGD("%s: ChannelMix not supported for channel mask %#x", __func__, channelMask);
209*ec779b8eSAndroid Build Coastguard Worker }
210*ec779b8eSAndroid Build Coastguard Worker }
211*ec779b8eSAndroid Build Coastguard Worker
212*ec779b8eSAndroid Build Coastguard Worker // Effect downmixer does not accept the channel conversion. Let's use our remixer.
213*ec779b8eSAndroid Build Coastguard Worker mDownmixerBufferProvider.reset(new RemixBufferProvider(channelMask,
214*ec779b8eSAndroid Build Coastguard Worker mMixerChannelMask, mMixerInFormat, kCopyBufferFrameCount));
215*ec779b8eSAndroid Build Coastguard Worker // Remix always finds a conversion whereas Downmixer effect above may fail.
216*ec779b8eSAndroid Build Coastguard Worker reconfigureBufferProviders();
217*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
218*ec779b8eSAndroid Build Coastguard Worker }
219*ec779b8eSAndroid Build Coastguard Worker
unprepareForReformat()220*ec779b8eSAndroid Build Coastguard Worker void AudioMixer::Track::unprepareForReformat() {
221*ec779b8eSAndroid Build Coastguard Worker ALOGV("AudioMixer::unprepareForReformat(%p)", this);
222*ec779b8eSAndroid Build Coastguard Worker bool requiresReconfigure = false;
223*ec779b8eSAndroid Build Coastguard Worker if (mReformatBufferProvider.get() != nullptr) {
224*ec779b8eSAndroid Build Coastguard Worker mReformatBufferProvider.reset(nullptr);
225*ec779b8eSAndroid Build Coastguard Worker requiresReconfigure = true;
226*ec779b8eSAndroid Build Coastguard Worker }
227*ec779b8eSAndroid Build Coastguard Worker if (mPostDownmixReformatBufferProvider.get() != nullptr) {
228*ec779b8eSAndroid Build Coastguard Worker mPostDownmixReformatBufferProvider.reset(nullptr);
229*ec779b8eSAndroid Build Coastguard Worker requiresReconfigure = true;
230*ec779b8eSAndroid Build Coastguard Worker }
231*ec779b8eSAndroid Build Coastguard Worker if (requiresReconfigure) {
232*ec779b8eSAndroid Build Coastguard Worker reconfigureBufferProviders();
233*ec779b8eSAndroid Build Coastguard Worker }
234*ec779b8eSAndroid Build Coastguard Worker }
235*ec779b8eSAndroid Build Coastguard Worker
prepareForReformat()236*ec779b8eSAndroid Build Coastguard Worker status_t AudioMixer::Track::prepareForReformat()
237*ec779b8eSAndroid Build Coastguard Worker {
238*ec779b8eSAndroid Build Coastguard Worker ALOGV("AudioMixer::prepareForReformat(%p) with format %#x", this, mFormat);
239*ec779b8eSAndroid Build Coastguard Worker // discard previous reformatters
240*ec779b8eSAndroid Build Coastguard Worker unprepareForReformat();
241*ec779b8eSAndroid Build Coastguard Worker // only configure reformatters as needed
242*ec779b8eSAndroid Build Coastguard Worker const audio_format_t targetFormat = mDownmixRequiresFormat != AUDIO_FORMAT_INVALID
243*ec779b8eSAndroid Build Coastguard Worker ? mDownmixRequiresFormat : mMixerInFormat;
244*ec779b8eSAndroid Build Coastguard Worker bool requiresReconfigure = false;
245*ec779b8eSAndroid Build Coastguard Worker if (mFormat != targetFormat) {
246*ec779b8eSAndroid Build Coastguard Worker mReformatBufferProvider.reset(new ReformatBufferProvider(
247*ec779b8eSAndroid Build Coastguard Worker audio_channel_count_from_out_mask(channelMask),
248*ec779b8eSAndroid Build Coastguard Worker mFormat,
249*ec779b8eSAndroid Build Coastguard Worker targetFormat,
250*ec779b8eSAndroid Build Coastguard Worker kCopyBufferFrameCount));
251*ec779b8eSAndroid Build Coastguard Worker requiresReconfigure = true;
252*ec779b8eSAndroid Build Coastguard Worker } else if (mFormat == AUDIO_FORMAT_PCM_FLOAT) {
253*ec779b8eSAndroid Build Coastguard Worker // Input and output are floats, make sure application did not provide > 3db samples
254*ec779b8eSAndroid Build Coastguard Worker // that would break volume application (b/68099072)
255*ec779b8eSAndroid Build Coastguard Worker // TODO: add a trusted source flag to avoid the overhead
256*ec779b8eSAndroid Build Coastguard Worker mReformatBufferProvider.reset(new ClampFloatBufferProvider(
257*ec779b8eSAndroid Build Coastguard Worker audio_channel_count_from_out_mask(channelMask),
258*ec779b8eSAndroid Build Coastguard Worker kCopyBufferFrameCount));
259*ec779b8eSAndroid Build Coastguard Worker requiresReconfigure = true;
260*ec779b8eSAndroid Build Coastguard Worker }
261*ec779b8eSAndroid Build Coastguard Worker if (targetFormat != mMixerInFormat) {
262*ec779b8eSAndroid Build Coastguard Worker mPostDownmixReformatBufferProvider.reset(new ReformatBufferProvider(
263*ec779b8eSAndroid Build Coastguard Worker audio_channel_count_from_out_mask(mMixerChannelMask),
264*ec779b8eSAndroid Build Coastguard Worker targetFormat,
265*ec779b8eSAndroid Build Coastguard Worker mMixerInFormat,
266*ec779b8eSAndroid Build Coastguard Worker kCopyBufferFrameCount));
267*ec779b8eSAndroid Build Coastguard Worker requiresReconfigure = true;
268*ec779b8eSAndroid Build Coastguard Worker }
269*ec779b8eSAndroid Build Coastguard Worker if (requiresReconfigure) {
270*ec779b8eSAndroid Build Coastguard Worker reconfigureBufferProviders();
271*ec779b8eSAndroid Build Coastguard Worker }
272*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
273*ec779b8eSAndroid Build Coastguard Worker }
274*ec779b8eSAndroid Build Coastguard Worker
unprepareForAdjustChannels()275*ec779b8eSAndroid Build Coastguard Worker void AudioMixer::Track::unprepareForAdjustChannels()
276*ec779b8eSAndroid Build Coastguard Worker {
277*ec779b8eSAndroid Build Coastguard Worker ALOGV("AUDIOMIXER::unprepareForAdjustChannels");
278*ec779b8eSAndroid Build Coastguard Worker if (mAdjustChannelsBufferProvider.get() != nullptr) {
279*ec779b8eSAndroid Build Coastguard Worker mAdjustChannelsBufferProvider.reset(nullptr);
280*ec779b8eSAndroid Build Coastguard Worker reconfigureBufferProviders();
281*ec779b8eSAndroid Build Coastguard Worker }
282*ec779b8eSAndroid Build Coastguard Worker }
283*ec779b8eSAndroid Build Coastguard Worker
prepareForAdjustChannels(size_t frames)284*ec779b8eSAndroid Build Coastguard Worker status_t AudioMixer::Track::prepareForAdjustChannels(size_t frames)
285*ec779b8eSAndroid Build Coastguard Worker {
286*ec779b8eSAndroid Build Coastguard Worker ALOGV("AudioMixer::prepareForAdjustChannels(%p) with inChannelCount: %u, outChannelCount: %u",
287*ec779b8eSAndroid Build Coastguard Worker this, mAdjustInChannelCount, mAdjustOutChannelCount);
288*ec779b8eSAndroid Build Coastguard Worker unprepareForAdjustChannels();
289*ec779b8eSAndroid Build Coastguard Worker if (mAdjustInChannelCount != mAdjustOutChannelCount) {
290*ec779b8eSAndroid Build Coastguard Worker uint8_t* buffer = mKeepContractedChannels
291*ec779b8eSAndroid Build Coastguard Worker ? (uint8_t*)mainBuffer + frames * audio_bytes_per_frame(
292*ec779b8eSAndroid Build Coastguard Worker mMixerChannelCount, mMixerFormat)
293*ec779b8eSAndroid Build Coastguard Worker : nullptr;
294*ec779b8eSAndroid Build Coastguard Worker mAdjustChannelsBufferProvider.reset(new AdjustChannelsBufferProvider(
295*ec779b8eSAndroid Build Coastguard Worker mFormat, mAdjustInChannelCount, mAdjustOutChannelCount, frames,
296*ec779b8eSAndroid Build Coastguard Worker mKeepContractedChannels ? mMixerFormat : AUDIO_FORMAT_INVALID,
297*ec779b8eSAndroid Build Coastguard Worker buffer, mMixerHapticChannelCount));
298*ec779b8eSAndroid Build Coastguard Worker reconfigureBufferProviders();
299*ec779b8eSAndroid Build Coastguard Worker }
300*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
301*ec779b8eSAndroid Build Coastguard Worker }
302*ec779b8eSAndroid Build Coastguard Worker
unprepareForTee()303*ec779b8eSAndroid Build Coastguard Worker void AudioMixer::Track::unprepareForTee() {
304*ec779b8eSAndroid Build Coastguard Worker ALOGV("AudioMixer::%s", __func__);
305*ec779b8eSAndroid Build Coastguard Worker if (mTeeBufferProvider.get() != nullptr) {
306*ec779b8eSAndroid Build Coastguard Worker mTeeBufferProvider.reset(nullptr);
307*ec779b8eSAndroid Build Coastguard Worker reconfigureBufferProviders();
308*ec779b8eSAndroid Build Coastguard Worker }
309*ec779b8eSAndroid Build Coastguard Worker }
310*ec779b8eSAndroid Build Coastguard Worker
prepareForTee()311*ec779b8eSAndroid Build Coastguard Worker status_t AudioMixer::Track::prepareForTee() {
312*ec779b8eSAndroid Build Coastguard Worker ALOGV("AudioMixer::%s(%p) teeBuffer=%p", __func__, this, teeBuffer);
313*ec779b8eSAndroid Build Coastguard Worker unprepareForTee();
314*ec779b8eSAndroid Build Coastguard Worker if (teeBuffer != nullptr) {
315*ec779b8eSAndroid Build Coastguard Worker mTeeBufferProvider.reset(new TeeBufferProvider(
316*ec779b8eSAndroid Build Coastguard Worker mInputFrameSize, mInputFrameSize, kCopyBufferFrameCount,
317*ec779b8eSAndroid Build Coastguard Worker (uint8_t*)teeBuffer, mTeeBufferFrameCount));
318*ec779b8eSAndroid Build Coastguard Worker reconfigureBufferProviders();
319*ec779b8eSAndroid Build Coastguard Worker }
320*ec779b8eSAndroid Build Coastguard Worker return NO_ERROR;
321*ec779b8eSAndroid Build Coastguard Worker }
322*ec779b8eSAndroid Build Coastguard Worker
clearContractedBuffer()323*ec779b8eSAndroid Build Coastguard Worker void AudioMixer::Track::clearContractedBuffer()
324*ec779b8eSAndroid Build Coastguard Worker {
325*ec779b8eSAndroid Build Coastguard Worker if (mAdjustChannelsBufferProvider.get() != nullptr) {
326*ec779b8eSAndroid Build Coastguard Worker static_cast<AdjustChannelsBufferProvider*>(
327*ec779b8eSAndroid Build Coastguard Worker mAdjustChannelsBufferProvider.get())->clearContractedFrames();
328*ec779b8eSAndroid Build Coastguard Worker }
329*ec779b8eSAndroid Build Coastguard Worker }
330*ec779b8eSAndroid Build Coastguard Worker
clearTeeFrameCopied()331*ec779b8eSAndroid Build Coastguard Worker void AudioMixer::Track::clearTeeFrameCopied() {
332*ec779b8eSAndroid Build Coastguard Worker if (mTeeBufferProvider.get() != nullptr) {
333*ec779b8eSAndroid Build Coastguard Worker static_cast<TeeBufferProvider*>(mTeeBufferProvider.get())->clearFramesCopied();
334*ec779b8eSAndroid Build Coastguard Worker }
335*ec779b8eSAndroid Build Coastguard Worker }
336*ec779b8eSAndroid Build Coastguard Worker
reconfigureBufferProviders()337*ec779b8eSAndroid Build Coastguard Worker void AudioMixer::Track::reconfigureBufferProviders()
338*ec779b8eSAndroid Build Coastguard Worker {
339*ec779b8eSAndroid Build Coastguard Worker // configure from upstream to downstream buffer providers.
340*ec779b8eSAndroid Build Coastguard Worker bufferProvider = mInputBufferProvider;
341*ec779b8eSAndroid Build Coastguard Worker if (mTeeBufferProvider != nullptr) {
342*ec779b8eSAndroid Build Coastguard Worker mTeeBufferProvider->setBufferProvider(bufferProvider);
343*ec779b8eSAndroid Build Coastguard Worker bufferProvider = mTeeBufferProvider.get();
344*ec779b8eSAndroid Build Coastguard Worker }
345*ec779b8eSAndroid Build Coastguard Worker if (mAdjustChannelsBufferProvider.get() != nullptr) {
346*ec779b8eSAndroid Build Coastguard Worker mAdjustChannelsBufferProvider->setBufferProvider(bufferProvider);
347*ec779b8eSAndroid Build Coastguard Worker bufferProvider = mAdjustChannelsBufferProvider.get();
348*ec779b8eSAndroid Build Coastguard Worker }
349*ec779b8eSAndroid Build Coastguard Worker if (mReformatBufferProvider.get() != nullptr) {
350*ec779b8eSAndroid Build Coastguard Worker mReformatBufferProvider->setBufferProvider(bufferProvider);
351*ec779b8eSAndroid Build Coastguard Worker bufferProvider = mReformatBufferProvider.get();
352*ec779b8eSAndroid Build Coastguard Worker }
353*ec779b8eSAndroid Build Coastguard Worker if (mDownmixerBufferProvider.get() != nullptr) {
354*ec779b8eSAndroid Build Coastguard Worker mDownmixerBufferProvider->setBufferProvider(bufferProvider);
355*ec779b8eSAndroid Build Coastguard Worker bufferProvider = mDownmixerBufferProvider.get();
356*ec779b8eSAndroid Build Coastguard Worker }
357*ec779b8eSAndroid Build Coastguard Worker if (mPostDownmixReformatBufferProvider.get() != nullptr) {
358*ec779b8eSAndroid Build Coastguard Worker mPostDownmixReformatBufferProvider->setBufferProvider(bufferProvider);
359*ec779b8eSAndroid Build Coastguard Worker bufferProvider = mPostDownmixReformatBufferProvider.get();
360*ec779b8eSAndroid Build Coastguard Worker }
361*ec779b8eSAndroid Build Coastguard Worker if (mTimestretchBufferProvider.get() != nullptr) {
362*ec779b8eSAndroid Build Coastguard Worker mTimestretchBufferProvider->setBufferProvider(bufferProvider);
363*ec779b8eSAndroid Build Coastguard Worker bufferProvider = mTimestretchBufferProvider.get();
364*ec779b8eSAndroid Build Coastguard Worker }
365*ec779b8eSAndroid Build Coastguard Worker }
366*ec779b8eSAndroid Build Coastguard Worker
setParameter(int name,int target,int param,void * value)367*ec779b8eSAndroid Build Coastguard Worker void AudioMixer::setParameter(int name, int target, int param, void *value)
368*ec779b8eSAndroid Build Coastguard Worker {
369*ec779b8eSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(!exists(name), "invalid name: %d", name);
370*ec779b8eSAndroid Build Coastguard Worker const std::shared_ptr<Track> &track = getTrack(name);
371*ec779b8eSAndroid Build Coastguard Worker
372*ec779b8eSAndroid Build Coastguard Worker int valueInt = static_cast<int>(reinterpret_cast<uintptr_t>(value));
373*ec779b8eSAndroid Build Coastguard Worker int32_t *valueBuf = reinterpret_cast<int32_t*>(value);
374*ec779b8eSAndroid Build Coastguard Worker
375*ec779b8eSAndroid Build Coastguard Worker switch (target) {
376*ec779b8eSAndroid Build Coastguard Worker
377*ec779b8eSAndroid Build Coastguard Worker case TRACK:
378*ec779b8eSAndroid Build Coastguard Worker switch (param) {
379*ec779b8eSAndroid Build Coastguard Worker case CHANNEL_MASK: {
380*ec779b8eSAndroid Build Coastguard Worker const audio_channel_mask_t trackChannelMask =
381*ec779b8eSAndroid Build Coastguard Worker static_cast<audio_channel_mask_t>(valueInt);
382*ec779b8eSAndroid Build Coastguard Worker if (setChannelMasks(name, trackChannelMask,
383*ec779b8eSAndroid Build Coastguard Worker static_cast<audio_channel_mask_t>(
384*ec779b8eSAndroid Build Coastguard Worker track->mMixerChannelMask | track->mMixerHapticChannelMask))) {
385*ec779b8eSAndroid Build Coastguard Worker ALOGV("setParameter(TRACK, CHANNEL_MASK, %x)", trackChannelMask);
386*ec779b8eSAndroid Build Coastguard Worker invalidate();
387*ec779b8eSAndroid Build Coastguard Worker }
388*ec779b8eSAndroid Build Coastguard Worker } break;
389*ec779b8eSAndroid Build Coastguard Worker case MAIN_BUFFER:
390*ec779b8eSAndroid Build Coastguard Worker if (track->mainBuffer != valueBuf) {
391*ec779b8eSAndroid Build Coastguard Worker track->mainBuffer = valueBuf;
392*ec779b8eSAndroid Build Coastguard Worker ALOGV("setParameter(TRACK, MAIN_BUFFER, %p)", valueBuf);
393*ec779b8eSAndroid Build Coastguard Worker if (track->mKeepContractedChannels) {
394*ec779b8eSAndroid Build Coastguard Worker track->prepareForAdjustChannels(mFrameCount);
395*ec779b8eSAndroid Build Coastguard Worker }
396*ec779b8eSAndroid Build Coastguard Worker invalidate();
397*ec779b8eSAndroid Build Coastguard Worker }
398*ec779b8eSAndroid Build Coastguard Worker break;
399*ec779b8eSAndroid Build Coastguard Worker case AUX_BUFFER:
400*ec779b8eSAndroid Build Coastguard Worker AudioMixerBase::setParameter(name, target, param, value);
401*ec779b8eSAndroid Build Coastguard Worker break;
402*ec779b8eSAndroid Build Coastguard Worker case FORMAT: {
403*ec779b8eSAndroid Build Coastguard Worker audio_format_t format = static_cast<audio_format_t>(valueInt);
404*ec779b8eSAndroid Build Coastguard Worker if (track->mFormat != format) {
405*ec779b8eSAndroid Build Coastguard Worker ALOG_ASSERT(audio_is_linear_pcm(format), "Invalid format %#x", format);
406*ec779b8eSAndroid Build Coastguard Worker track->mFormat = format;
407*ec779b8eSAndroid Build Coastguard Worker ALOGV("setParameter(TRACK, FORMAT, %#x)", format);
408*ec779b8eSAndroid Build Coastguard Worker track->prepareForReformat();
409*ec779b8eSAndroid Build Coastguard Worker invalidate();
410*ec779b8eSAndroid Build Coastguard Worker }
411*ec779b8eSAndroid Build Coastguard Worker } break;
412*ec779b8eSAndroid Build Coastguard Worker // FIXME do we want to support setting the downmix type from AudioFlinger?
413*ec779b8eSAndroid Build Coastguard Worker // for a specific track? or per mixer?
414*ec779b8eSAndroid Build Coastguard Worker /* case DOWNMIX_TYPE:
415*ec779b8eSAndroid Build Coastguard Worker break */
416*ec779b8eSAndroid Build Coastguard Worker case MIXER_FORMAT: {
417*ec779b8eSAndroid Build Coastguard Worker audio_format_t format = static_cast<audio_format_t>(valueInt);
418*ec779b8eSAndroid Build Coastguard Worker if (track->mMixerFormat != format) {
419*ec779b8eSAndroid Build Coastguard Worker track->mMixerFormat = format;
420*ec779b8eSAndroid Build Coastguard Worker ALOGV("setParameter(TRACK, MIXER_FORMAT, %#x)", format);
421*ec779b8eSAndroid Build Coastguard Worker if (track->mKeepContractedChannels) {
422*ec779b8eSAndroid Build Coastguard Worker track->prepareForAdjustChannels(mFrameCount);
423*ec779b8eSAndroid Build Coastguard Worker }
424*ec779b8eSAndroid Build Coastguard Worker }
425*ec779b8eSAndroid Build Coastguard Worker } break;
426*ec779b8eSAndroid Build Coastguard Worker case MIXER_CHANNEL_MASK: {
427*ec779b8eSAndroid Build Coastguard Worker const audio_channel_mask_t mixerChannelMask =
428*ec779b8eSAndroid Build Coastguard Worker static_cast<audio_channel_mask_t>(valueInt);
429*ec779b8eSAndroid Build Coastguard Worker if (setChannelMasks(name, static_cast<audio_channel_mask_t>(
430*ec779b8eSAndroid Build Coastguard Worker track->channelMask | track->mHapticChannelMask),
431*ec779b8eSAndroid Build Coastguard Worker mixerChannelMask)) {
432*ec779b8eSAndroid Build Coastguard Worker ALOGV("setParameter(TRACK, MIXER_CHANNEL_MASK, %#x)", mixerChannelMask);
433*ec779b8eSAndroid Build Coastguard Worker invalidate();
434*ec779b8eSAndroid Build Coastguard Worker }
435*ec779b8eSAndroid Build Coastguard Worker } break;
436*ec779b8eSAndroid Build Coastguard Worker case HAPTIC_ENABLED: {
437*ec779b8eSAndroid Build Coastguard Worker const bool hapticPlaybackEnabled = static_cast<bool>(valueInt);
438*ec779b8eSAndroid Build Coastguard Worker if (track->mHapticPlaybackEnabled != hapticPlaybackEnabled) {
439*ec779b8eSAndroid Build Coastguard Worker track->mHapticPlaybackEnabled = hapticPlaybackEnabled;
440*ec779b8eSAndroid Build Coastguard Worker track->mKeepContractedChannels = hapticPlaybackEnabled;
441*ec779b8eSAndroid Build Coastguard Worker track->prepareForAdjustChannels(mFrameCount);
442*ec779b8eSAndroid Build Coastguard Worker }
443*ec779b8eSAndroid Build Coastguard Worker } break;
444*ec779b8eSAndroid Build Coastguard Worker case HAPTIC_SCALE: {
445*ec779b8eSAndroid Build Coastguard Worker const os::HapticScale hapticScale = *reinterpret_cast<os::HapticScale*>(value);
446*ec779b8eSAndroid Build Coastguard Worker if (track->mHapticScale != hapticScale) {
447*ec779b8eSAndroid Build Coastguard Worker track->mHapticScale = hapticScale;
448*ec779b8eSAndroid Build Coastguard Worker }
449*ec779b8eSAndroid Build Coastguard Worker } break;
450*ec779b8eSAndroid Build Coastguard Worker case HAPTIC_MAX_AMPLITUDE: {
451*ec779b8eSAndroid Build Coastguard Worker const float hapticMaxAmplitude = *reinterpret_cast<float*>(value);
452*ec779b8eSAndroid Build Coastguard Worker if (track->mHapticMaxAmplitude != hapticMaxAmplitude) {
453*ec779b8eSAndroid Build Coastguard Worker track->mHapticMaxAmplitude = hapticMaxAmplitude;
454*ec779b8eSAndroid Build Coastguard Worker }
455*ec779b8eSAndroid Build Coastguard Worker } break;
456*ec779b8eSAndroid Build Coastguard Worker case TEE_BUFFER:
457*ec779b8eSAndroid Build Coastguard Worker if (track->teeBuffer != valueBuf) {
458*ec779b8eSAndroid Build Coastguard Worker track->teeBuffer = valueBuf;
459*ec779b8eSAndroid Build Coastguard Worker ALOGV("setParameter(TRACK, TEE_BUFFER, %p)", valueBuf);
460*ec779b8eSAndroid Build Coastguard Worker track->prepareForTee();
461*ec779b8eSAndroid Build Coastguard Worker }
462*ec779b8eSAndroid Build Coastguard Worker break;
463*ec779b8eSAndroid Build Coastguard Worker case TEE_BUFFER_FRAME_COUNT:
464*ec779b8eSAndroid Build Coastguard Worker if (track->mTeeBufferFrameCount != valueInt) {
465*ec779b8eSAndroid Build Coastguard Worker track->mTeeBufferFrameCount = valueInt;
466*ec779b8eSAndroid Build Coastguard Worker ALOGV("setParameter(TRACK, TEE_BUFFER_FRAME_COUNT, %i)", valueInt);
467*ec779b8eSAndroid Build Coastguard Worker track->prepareForTee();
468*ec779b8eSAndroid Build Coastguard Worker }
469*ec779b8eSAndroid Build Coastguard Worker break;
470*ec779b8eSAndroid Build Coastguard Worker default:
471*ec779b8eSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL("setParameter track: bad param %d", param);
472*ec779b8eSAndroid Build Coastguard Worker }
473*ec779b8eSAndroid Build Coastguard Worker break;
474*ec779b8eSAndroid Build Coastguard Worker
475*ec779b8eSAndroid Build Coastguard Worker case RESAMPLE:
476*ec779b8eSAndroid Build Coastguard Worker case RAMP_VOLUME:
477*ec779b8eSAndroid Build Coastguard Worker case VOLUME:
478*ec779b8eSAndroid Build Coastguard Worker AudioMixerBase::setParameter(name, target, param, value);
479*ec779b8eSAndroid Build Coastguard Worker break;
480*ec779b8eSAndroid Build Coastguard Worker case TIMESTRETCH:
481*ec779b8eSAndroid Build Coastguard Worker switch (param) {
482*ec779b8eSAndroid Build Coastguard Worker case PLAYBACK_RATE: {
483*ec779b8eSAndroid Build Coastguard Worker const AudioPlaybackRate *playbackRate =
484*ec779b8eSAndroid Build Coastguard Worker reinterpret_cast<AudioPlaybackRate*>(value);
485*ec779b8eSAndroid Build Coastguard Worker ALOGW_IF(!isAudioPlaybackRateValid(*playbackRate),
486*ec779b8eSAndroid Build Coastguard Worker "bad parameters speed %f, pitch %f",
487*ec779b8eSAndroid Build Coastguard Worker playbackRate->mSpeed, playbackRate->mPitch);
488*ec779b8eSAndroid Build Coastguard Worker if (track->setPlaybackRate(*playbackRate)) {
489*ec779b8eSAndroid Build Coastguard Worker ALOGV("setParameter(TIMESTRETCH, PLAYBACK_RATE, STRETCH_MODE, FALLBACK_MODE "
490*ec779b8eSAndroid Build Coastguard Worker "%f %f %d %d",
491*ec779b8eSAndroid Build Coastguard Worker playbackRate->mSpeed,
492*ec779b8eSAndroid Build Coastguard Worker playbackRate->mPitch,
493*ec779b8eSAndroid Build Coastguard Worker playbackRate->mStretchMode,
494*ec779b8eSAndroid Build Coastguard Worker playbackRate->mFallbackMode);
495*ec779b8eSAndroid Build Coastguard Worker // invalidate(); (should not require reconfigure)
496*ec779b8eSAndroid Build Coastguard Worker }
497*ec779b8eSAndroid Build Coastguard Worker } break;
498*ec779b8eSAndroid Build Coastguard Worker default:
499*ec779b8eSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL("setParameter timestretch: bad param %d", param);
500*ec779b8eSAndroid Build Coastguard Worker }
501*ec779b8eSAndroid Build Coastguard Worker break;
502*ec779b8eSAndroid Build Coastguard Worker
503*ec779b8eSAndroid Build Coastguard Worker default:
504*ec779b8eSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL("setParameter: bad target %d", target);
505*ec779b8eSAndroid Build Coastguard Worker }
506*ec779b8eSAndroid Build Coastguard Worker }
507*ec779b8eSAndroid Build Coastguard Worker
setPlaybackRate(const AudioPlaybackRate & playbackRate)508*ec779b8eSAndroid Build Coastguard Worker bool AudioMixer::Track::setPlaybackRate(const AudioPlaybackRate &playbackRate)
509*ec779b8eSAndroid Build Coastguard Worker {
510*ec779b8eSAndroid Build Coastguard Worker if ((mTimestretchBufferProvider.get() == nullptr &&
511*ec779b8eSAndroid Build Coastguard Worker fabs(playbackRate.mSpeed - mPlaybackRate.mSpeed) < AUDIO_TIMESTRETCH_SPEED_MIN_DELTA &&
512*ec779b8eSAndroid Build Coastguard Worker fabs(playbackRate.mPitch - mPlaybackRate.mPitch) < AUDIO_TIMESTRETCH_PITCH_MIN_DELTA) ||
513*ec779b8eSAndroid Build Coastguard Worker isAudioPlaybackRateEqual(playbackRate, mPlaybackRate)) {
514*ec779b8eSAndroid Build Coastguard Worker return false;
515*ec779b8eSAndroid Build Coastguard Worker }
516*ec779b8eSAndroid Build Coastguard Worker mPlaybackRate = playbackRate;
517*ec779b8eSAndroid Build Coastguard Worker if (mTimestretchBufferProvider.get() == nullptr) {
518*ec779b8eSAndroid Build Coastguard Worker // TODO: Remove MONO_HACK. Resampler sees #channels after the downmixer
519*ec779b8eSAndroid Build Coastguard Worker // but if none exists, it is the channel count (1 for mono).
520*ec779b8eSAndroid Build Coastguard Worker const int timestretchChannelCount = getOutputChannelCount();
521*ec779b8eSAndroid Build Coastguard Worker mTimestretchBufferProvider.reset(new TimestretchBufferProvider(timestretchChannelCount,
522*ec779b8eSAndroid Build Coastguard Worker mMixerInFormat, sampleRate, playbackRate));
523*ec779b8eSAndroid Build Coastguard Worker reconfigureBufferProviders();
524*ec779b8eSAndroid Build Coastguard Worker } else {
525*ec779b8eSAndroid Build Coastguard Worker static_cast<TimestretchBufferProvider*>(mTimestretchBufferProvider.get())
526*ec779b8eSAndroid Build Coastguard Worker ->setPlaybackRate(playbackRate);
527*ec779b8eSAndroid Build Coastguard Worker }
528*ec779b8eSAndroid Build Coastguard Worker return true;
529*ec779b8eSAndroid Build Coastguard Worker }
530*ec779b8eSAndroid Build Coastguard Worker
setBufferProvider(int name,AudioBufferProvider * bufferProvider)531*ec779b8eSAndroid Build Coastguard Worker void AudioMixer::setBufferProvider(int name, AudioBufferProvider* bufferProvider)
532*ec779b8eSAndroid Build Coastguard Worker {
533*ec779b8eSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(!exists(name), "invalid name: %d", name);
534*ec779b8eSAndroid Build Coastguard Worker const std::shared_ptr<Track> &track = getTrack(name);
535*ec779b8eSAndroid Build Coastguard Worker
536*ec779b8eSAndroid Build Coastguard Worker if (track->mInputBufferProvider == bufferProvider) {
537*ec779b8eSAndroid Build Coastguard Worker return; // don't reset any buffer providers if identical.
538*ec779b8eSAndroid Build Coastguard Worker }
539*ec779b8eSAndroid Build Coastguard Worker // reset order from downstream to upstream buffer providers.
540*ec779b8eSAndroid Build Coastguard Worker if (track->mTimestretchBufferProvider.get() != nullptr) {
541*ec779b8eSAndroid Build Coastguard Worker track->mTimestretchBufferProvider->reset();
542*ec779b8eSAndroid Build Coastguard Worker } else if (track->mPostDownmixReformatBufferProvider.get() != nullptr) {
543*ec779b8eSAndroid Build Coastguard Worker track->mPostDownmixReformatBufferProvider->reset();
544*ec779b8eSAndroid Build Coastguard Worker } else if (track->mDownmixerBufferProvider != nullptr) {
545*ec779b8eSAndroid Build Coastguard Worker track->mDownmixerBufferProvider->reset();
546*ec779b8eSAndroid Build Coastguard Worker } else if (track->mReformatBufferProvider.get() != nullptr) {
547*ec779b8eSAndroid Build Coastguard Worker track->mReformatBufferProvider->reset();
548*ec779b8eSAndroid Build Coastguard Worker } else if (track->mAdjustChannelsBufferProvider.get() != nullptr) {
549*ec779b8eSAndroid Build Coastguard Worker track->mAdjustChannelsBufferProvider->reset();
550*ec779b8eSAndroid Build Coastguard Worker } else if (track->mTeeBufferProvider.get() != nullptr) {
551*ec779b8eSAndroid Build Coastguard Worker track->mTeeBufferProvider->reset();
552*ec779b8eSAndroid Build Coastguard Worker }
553*ec779b8eSAndroid Build Coastguard Worker
554*ec779b8eSAndroid Build Coastguard Worker track->mInputBufferProvider = bufferProvider;
555*ec779b8eSAndroid Build Coastguard Worker track->reconfigureBufferProviders();
556*ec779b8eSAndroid Build Coastguard Worker }
557*ec779b8eSAndroid Build Coastguard Worker
558*ec779b8eSAndroid Build Coastguard Worker /*static*/ pthread_once_t AudioMixer::sOnceControl = PTHREAD_ONCE_INIT;
559*ec779b8eSAndroid Build Coastguard Worker
sInitRoutine()560*ec779b8eSAndroid Build Coastguard Worker /*static*/ void AudioMixer::sInitRoutine()
561*ec779b8eSAndroid Build Coastguard Worker {
562*ec779b8eSAndroid Build Coastguard Worker DownmixerBufferProvider::init(); // for the downmixer
563*ec779b8eSAndroid Build Coastguard Worker }
564*ec779b8eSAndroid Build Coastguard Worker
preCreateTrack()565*ec779b8eSAndroid Build Coastguard Worker std::shared_ptr<AudioMixerBase::TrackBase> AudioMixer::preCreateTrack()
566*ec779b8eSAndroid Build Coastguard Worker {
567*ec779b8eSAndroid Build Coastguard Worker return std::make_shared<Track>();
568*ec779b8eSAndroid Build Coastguard Worker }
569*ec779b8eSAndroid Build Coastguard Worker
postCreateTrack(TrackBase * track)570*ec779b8eSAndroid Build Coastguard Worker status_t AudioMixer::postCreateTrack(TrackBase *track)
571*ec779b8eSAndroid Build Coastguard Worker {
572*ec779b8eSAndroid Build Coastguard Worker Track* t = static_cast<Track*>(track);
573*ec779b8eSAndroid Build Coastguard Worker
574*ec779b8eSAndroid Build Coastguard Worker audio_channel_mask_t channelMask = t->channelMask;
575*ec779b8eSAndroid Build Coastguard Worker t->mHapticChannelMask = static_cast<audio_channel_mask_t>(
576*ec779b8eSAndroid Build Coastguard Worker channelMask & AUDIO_CHANNEL_HAPTIC_ALL);
577*ec779b8eSAndroid Build Coastguard Worker t->mHapticChannelCount = audio_channel_count_from_out_mask(t->mHapticChannelMask);
578*ec779b8eSAndroid Build Coastguard Worker channelMask = static_cast<audio_channel_mask_t>(channelMask & ~AUDIO_CHANNEL_HAPTIC_ALL);
579*ec779b8eSAndroid Build Coastguard Worker t->channelCount = audio_channel_count_from_out_mask(channelMask);
580*ec779b8eSAndroid Build Coastguard Worker ALOGV_IF(audio_channel_mask_get_bits(channelMask) != AUDIO_CHANNEL_OUT_STEREO,
581*ec779b8eSAndroid Build Coastguard Worker "Non-stereo channel mask: %d\n", channelMask);
582*ec779b8eSAndroid Build Coastguard Worker t->channelMask = channelMask;
583*ec779b8eSAndroid Build Coastguard Worker t->mInputBufferProvider = NULL;
584*ec779b8eSAndroid Build Coastguard Worker t->mDownmixRequiresFormat = AUDIO_FORMAT_INVALID; // no format required
585*ec779b8eSAndroid Build Coastguard Worker t->mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT;
586*ec779b8eSAndroid Build Coastguard Worker // haptic
587*ec779b8eSAndroid Build Coastguard Worker t->mHapticPlaybackEnabled = false;
588*ec779b8eSAndroid Build Coastguard Worker t->mHapticScale = os::HapticScale::none();
589*ec779b8eSAndroid Build Coastguard Worker t->mHapticMaxAmplitude = NAN;
590*ec779b8eSAndroid Build Coastguard Worker t->mMixerHapticChannelMask = AUDIO_CHANNEL_NONE;
591*ec779b8eSAndroid Build Coastguard Worker t->mMixerHapticChannelCount = 0;
592*ec779b8eSAndroid Build Coastguard Worker t->mAdjustInChannelCount = t->channelCount + t->mHapticChannelCount;
593*ec779b8eSAndroid Build Coastguard Worker t->mAdjustOutChannelCount = t->channelCount;
594*ec779b8eSAndroid Build Coastguard Worker t->mKeepContractedChannels = false;
595*ec779b8eSAndroid Build Coastguard Worker t->mInputFrameSize = audio_bytes_per_frame(
596*ec779b8eSAndroid Build Coastguard Worker t->channelCount + t->mHapticChannelCount, t->mFormat);
597*ec779b8eSAndroid Build Coastguard Worker // Check the downmixing (or upmixing) requirements.
598*ec779b8eSAndroid Build Coastguard Worker status_t status = t->prepareForDownmix();
599*ec779b8eSAndroid Build Coastguard Worker if (status != OK) {
600*ec779b8eSAndroid Build Coastguard Worker ALOGE("AudioMixer::getTrackName invalid channelMask (%#x)", channelMask);
601*ec779b8eSAndroid Build Coastguard Worker return BAD_VALUE;
602*ec779b8eSAndroid Build Coastguard Worker }
603*ec779b8eSAndroid Build Coastguard Worker // prepareForDownmix() may change mDownmixRequiresFormat
604*ec779b8eSAndroid Build Coastguard Worker ALOGVV("mMixerFormat:%#x mMixerInFormat:%#x\n", t->mMixerFormat, t->mMixerInFormat);
605*ec779b8eSAndroid Build Coastguard Worker t->prepareForReformat();
606*ec779b8eSAndroid Build Coastguard Worker t->prepareForAdjustChannels(mFrameCount);
607*ec779b8eSAndroid Build Coastguard Worker return OK;
608*ec779b8eSAndroid Build Coastguard Worker }
609*ec779b8eSAndroid Build Coastguard Worker
preProcess()610*ec779b8eSAndroid Build Coastguard Worker void AudioMixer::preProcess()
611*ec779b8eSAndroid Build Coastguard Worker {
612*ec779b8eSAndroid Build Coastguard Worker for (const auto &pair : mTracks) {
613*ec779b8eSAndroid Build Coastguard Worker // Clear contracted buffer before processing if contracted channels are saved
614*ec779b8eSAndroid Build Coastguard Worker const std::shared_ptr<TrackBase> &tb = pair.second;
615*ec779b8eSAndroid Build Coastguard Worker Track *t = static_cast<Track*>(tb.get());
616*ec779b8eSAndroid Build Coastguard Worker if (t->mKeepContractedChannels) {
617*ec779b8eSAndroid Build Coastguard Worker t->clearContractedBuffer();
618*ec779b8eSAndroid Build Coastguard Worker }
619*ec779b8eSAndroid Build Coastguard Worker t->clearTeeFrameCopied();
620*ec779b8eSAndroid Build Coastguard Worker }
621*ec779b8eSAndroid Build Coastguard Worker }
622*ec779b8eSAndroid Build Coastguard Worker
postProcess()623*ec779b8eSAndroid Build Coastguard Worker void AudioMixer::postProcess()
624*ec779b8eSAndroid Build Coastguard Worker {
625*ec779b8eSAndroid Build Coastguard Worker // Process haptic data.
626*ec779b8eSAndroid Build Coastguard Worker // Need to keep consistent with VibrationEffect.scale(int, float, int)
627*ec779b8eSAndroid Build Coastguard Worker for (const auto &pair : mGroups) {
628*ec779b8eSAndroid Build Coastguard Worker // process by group of tracks with same output main buffer.
629*ec779b8eSAndroid Build Coastguard Worker const auto &group = pair.second;
630*ec779b8eSAndroid Build Coastguard Worker for (const int name : group) {
631*ec779b8eSAndroid Build Coastguard Worker const std::shared_ptr<Track> &t = getTrack(name);
632*ec779b8eSAndroid Build Coastguard Worker if (t->mHapticPlaybackEnabled) {
633*ec779b8eSAndroid Build Coastguard Worker size_t sampleCount = mFrameCount * t->mMixerHapticChannelCount;
634*ec779b8eSAndroid Build Coastguard Worker uint8_t* buffer = (uint8_t*)pair.first + mFrameCount * audio_bytes_per_frame(
635*ec779b8eSAndroid Build Coastguard Worker t->mMixerChannelCount, t->mMixerFormat);
636*ec779b8eSAndroid Build Coastguard Worker switch (t->mMixerFormat) {
637*ec779b8eSAndroid Build Coastguard Worker // Mixer format should be AUDIO_FORMAT_PCM_FLOAT.
638*ec779b8eSAndroid Build Coastguard Worker case AUDIO_FORMAT_PCM_FLOAT: {
639*ec779b8eSAndroid Build Coastguard Worker os::scaleHapticData((float*) buffer, sampleCount, t->mHapticScale,
640*ec779b8eSAndroid Build Coastguard Worker t->mHapticMaxAmplitude);
641*ec779b8eSAndroid Build Coastguard Worker } break;
642*ec779b8eSAndroid Build Coastguard Worker default:
643*ec779b8eSAndroid Build Coastguard Worker LOG_ALWAYS_FATAL("bad mMixerFormat: %#x", t->mMixerFormat);
644*ec779b8eSAndroid Build Coastguard Worker break;
645*ec779b8eSAndroid Build Coastguard Worker }
646*ec779b8eSAndroid Build Coastguard Worker break;
647*ec779b8eSAndroid Build Coastguard Worker }
648*ec779b8eSAndroid Build Coastguard Worker if (t->teeBuffer != nullptr && t->volumeRL == 0) {
649*ec779b8eSAndroid Build Coastguard Worker // Need to mute tee
650*ec779b8eSAndroid Build Coastguard Worker memset(t->teeBuffer, 0, t->mTeeBufferFrameCount * t->mInputFrameSize);
651*ec779b8eSAndroid Build Coastguard Worker }
652*ec779b8eSAndroid Build Coastguard Worker }
653*ec779b8eSAndroid Build Coastguard Worker }
654*ec779b8eSAndroid Build Coastguard Worker }
655*ec779b8eSAndroid Build Coastguard Worker
656*ec779b8eSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
657*ec779b8eSAndroid Build Coastguard Worker } // namespace android
658