xref: /aosp_15_r20/frameworks/av/media/libaudioprocessing/AudioMixer.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
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