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