| 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 |  | 
 | 21 | #include <stdint.h> | 
 | 22 | #include <string.h> | 
 | 23 | #include <stdlib.h> | 
 | 24 | #include <sys/types.h> | 
 | 25 |  | 
 | 26 | #include <utils/Errors.h> | 
 | 27 | #include <utils/Log.h> | 
 | 28 |  | 
| Jean-Michel Trivi | 0d255b2 | 2011-05-24 15:53:33 -0700 | [diff] [blame] | 29 | #include <cutils/bitops.h> | 
| Glenn Kasten | f6b1678 | 2011-12-15 09:51:17 -0800 | [diff] [blame] | 30 | #include <cutils/compiler.h> | 
| Glenn Kasten | 5798d4e | 2012-03-08 12:18:35 -0800 | [diff] [blame] | 31 | #include <utils/Debug.h> | 
| Jean-Michel Trivi | 0d255b2 | 2011-05-24 15:53:33 -0700 | [diff] [blame] | 32 |  | 
 | 33 | #include <system/audio.h> | 
 | 34 |  | 
| Glenn Kasten | 3b21c50 | 2011-12-15 09:52:39 -0800 | [diff] [blame] | 35 | #include <audio_utils/primitives.h> | 
| John Grossman | 4ff14ba | 2012-02-08 16:37:41 -0800 | [diff] [blame] | 36 | #include <common_time/local_clock.h> | 
 | 37 | #include <common_time/cc_helper.h> | 
| Glenn Kasten | 3b21c50 | 2011-12-15 09:52:39 -0800 | [diff] [blame] | 38 |  | 
| Jean-Michel Trivi | 7d5b262 | 2012-04-04 18:54:36 -0700 | [diff] [blame] | 39 | #include <media/EffectsFactoryApi.h> | 
 | 40 |  | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 41 | #include "AudioMixer.h" | 
 | 42 |  | 
 | 43 | namespace android { | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 44 |  | 
 | 45 | // ---------------------------------------------------------------------------- | 
| Jean-Michel Trivi | 7d5b262 | 2012-04-04 18:54:36 -0700 | [diff] [blame] | 46 | AudioMixer::DownmixerBufferProvider::DownmixerBufferProvider() : AudioBufferProvider(), | 
 | 47 |         mTrackBufferProvider(NULL), mDownmixHandle(NULL) | 
 | 48 | { | 
 | 49 | } | 
 | 50 |  | 
 | 51 | AudioMixer::DownmixerBufferProvider::~DownmixerBufferProvider() | 
 | 52 | { | 
 | 53 |     ALOGV("AudioMixer deleting DownmixerBufferProvider (%p)", this); | 
 | 54 |     EffectRelease(mDownmixHandle); | 
 | 55 | } | 
 | 56 |  | 
 | 57 | status_t AudioMixer::DownmixerBufferProvider::getNextBuffer(AudioBufferProvider::Buffer *pBuffer, | 
 | 58 |         int64_t pts) { | 
 | 59 |     //ALOGV("DownmixerBufferProvider::getNextBuffer()"); | 
 | 60 |     if (this->mTrackBufferProvider != NULL) { | 
 | 61 |         status_t res = mTrackBufferProvider->getNextBuffer(pBuffer, pts); | 
 | 62 |         if (res == OK) { | 
 | 63 |             mDownmixConfig.inputCfg.buffer.frameCount = pBuffer->frameCount; | 
 | 64 |             mDownmixConfig.inputCfg.buffer.raw = pBuffer->raw; | 
 | 65 |             mDownmixConfig.outputCfg.buffer.frameCount = pBuffer->frameCount; | 
 | 66 |             mDownmixConfig.outputCfg.buffer.raw = mDownmixConfig.inputCfg.buffer.raw; | 
 | 67 |             // in-place so overwrite the buffer contents, has been set in prepareTrackForDownmix() | 
 | 68 |             //mDownmixConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_WRITE; | 
 | 69 |  | 
 | 70 |             res = (*mDownmixHandle)->process(mDownmixHandle, | 
 | 71 |                     &mDownmixConfig.inputCfg.buffer, &mDownmixConfig.outputCfg.buffer); | 
| Jean-Michel Trivi | 9bd2322 | 2012-04-16 13:43:48 -0700 | [diff] [blame] | 72 |             //ALOGV("getNextBuffer is downmixing"); | 
| Jean-Michel Trivi | 7d5b262 | 2012-04-04 18:54:36 -0700 | [diff] [blame] | 73 |         } | 
 | 74 |         return res; | 
 | 75 |     } else { | 
 | 76 |         ALOGE("DownmixerBufferProvider::getNextBuffer() error: NULL track buffer provider"); | 
 | 77 |         return NO_INIT; | 
 | 78 |     } | 
 | 79 | } | 
 | 80 |  | 
 | 81 | void AudioMixer::DownmixerBufferProvider::releaseBuffer(AudioBufferProvider::Buffer *pBuffer) { | 
| Jean-Michel Trivi | 9bd2322 | 2012-04-16 13:43:48 -0700 | [diff] [blame] | 82 |     //ALOGV("DownmixerBufferProvider::releaseBuffer()"); | 
| Jean-Michel Trivi | 7d5b262 | 2012-04-04 18:54:36 -0700 | [diff] [blame] | 83 |     if (this->mTrackBufferProvider != NULL) { | 
 | 84 |         mTrackBufferProvider->releaseBuffer(pBuffer); | 
 | 85 |     } else { | 
 | 86 |         ALOGE("DownmixerBufferProvider::releaseBuffer() error: NULL track buffer provider"); | 
 | 87 |     } | 
 | 88 | } | 
 | 89 |  | 
 | 90 |  | 
 | 91 | // ---------------------------------------------------------------------------- | 
 | 92 | bool AudioMixer::isMultichannelCapable = false; | 
 | 93 |  | 
 | 94 | effect_descriptor_t AudioMixer::dwnmFxDesc; | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 95 |  | 
| Paul Lind | 3c0a0e8 | 2012-08-01 18:49:49 -0700 | [diff] [blame] | 96 | // Ensure mConfiguredNames bitmask is initialized properly on all architectures. | 
 | 97 | // The value of 1 << x is undefined in C when x >= 32. | 
 | 98 |  | 
| Glenn Kasten | 5c94b6c | 2012-03-20 17:01:29 -0700 | [diff] [blame] | 99 | AudioMixer::AudioMixer(size_t frameCount, uint32_t sampleRate, uint32_t maxNumTracks) | 
| Paul Lind | 3c0a0e8 | 2012-08-01 18:49:49 -0700 | [diff] [blame] | 100 |     :   mTrackNames(0), mConfiguredNames((maxNumTracks >= 32 ? 0 : 1 << maxNumTracks) - 1), | 
| Glenn Kasten | 7f5d335 | 2013-02-15 23:55:04 +0000 | [diff] [blame] | 101 |         mSampleRate(sampleRate) | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 102 | { | 
| Glenn Kasten | 788040c | 2011-05-05 08:19:00 -0700 | [diff] [blame] | 103 |     // AudioMixer is not yet capable of multi-channel beyond stereo | 
| Glenn Kasten | 5798d4e | 2012-03-08 12:18:35 -0800 | [diff] [blame] | 104 |     COMPILE_TIME_ASSERT_FUNCTION_SCOPE(2 == MAX_NUM_CHANNELS); | 
| Jean-Michel Trivi | acb86cc | 2012-04-16 12:43:57 -0700 | [diff] [blame] | 105 |  | 
| Glenn Kasten | 5c94b6c | 2012-03-20 17:01:29 -0700 | [diff] [blame] | 106 |     ALOG_ASSERT(maxNumTracks <= MAX_NUM_TRACKS, "maxNumTracks %u > MAX_NUM_TRACKS %u", | 
 | 107 |             maxNumTracks, MAX_NUM_TRACKS); | 
 | 108 |  | 
| Glenn Kasten | 599fabc | 2012-03-08 12:33:37 -0800 | [diff] [blame] | 109 |     // AudioMixer is not yet capable of more than 32 active track inputs | 
 | 110 |     ALOG_ASSERT(32 >= MAX_NUM_TRACKS, "bad MAX_NUM_TRACKS %d", MAX_NUM_TRACKS); | 
 | 111 |  | 
 | 112 |     // AudioMixer is not yet capable of multi-channel output beyond stereo | 
 | 113 |     ALOG_ASSERT(2 == MAX_NUM_CHANNELS, "bad MAX_NUM_CHANNELS %d", MAX_NUM_CHANNELS); | 
 | 114 |  | 
| John Grossman | 4ff14ba | 2012-02-08 16:37:41 -0800 | [diff] [blame] | 115 |     LocalClock lc; | 
 | 116 |  | 
| Glenn Kasten | 52008f8 | 2012-03-18 09:34:41 -0700 | [diff] [blame] | 117 |     pthread_once(&sOnceControl, &sInitRoutine); | 
 | 118 |  | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 119 |     mState.enabledTracks= 0; | 
 | 120 |     mState.needsChanged = 0; | 
 | 121 |     mState.frameCount   = frameCount; | 
| Glenn Kasten | 84afa3b | 2012-01-25 15:28:08 -0800 | [diff] [blame] | 122 |     mState.hook         = process__nop; | 
| Glenn Kasten | e0feee3 | 2011-12-13 11:53:26 -0800 | [diff] [blame] | 123 |     mState.outputTemp   = NULL; | 
 | 124 |     mState.resampleTemp = NULL; | 
| Glenn Kasten | 84afa3b | 2012-01-25 15:28:08 -0800 | [diff] [blame] | 125 |     // mState.reserved | 
| Glenn Kasten | 17a736c | 2012-02-14 08:52:15 -0800 | [diff] [blame] | 126 |  | 
 | 127 |     // FIXME Most of the following initialization is probably redundant since | 
 | 128 |     // tracks[i] should only be referenced if (mTrackNames & (1 << i)) != 0 | 
 | 129 |     // and mTrackNames is initially 0.  However, leave it here until that's verified. | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 130 |     track_t* t = mState.tracks; | 
| Glenn Kasten | bf71f1e | 2011-12-13 11:52:35 -0800 | [diff] [blame] | 131 |     for (unsigned i=0 ; i < MAX_NUM_TRACKS ; i++) { | 
| Eric Laurent | a5e8214 | 2012-04-16 13:47:17 -0700 | [diff] [blame] | 132 |         t->resampler = NULL; | 
| Jean-Michel Trivi | 9bd2322 | 2012-04-16 13:43:48 -0700 | [diff] [blame] | 133 |         t->downmixerBufferProvider = NULL; | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 134 |         t++; | 
 | 135 |     } | 
| Jean-Michel Trivi | 7d5b262 | 2012-04-04 18:54:36 -0700 | [diff] [blame] | 136 |  | 
 | 137 |     // find multichannel downmix effect if we have to play multichannel content | 
 | 138 |     uint32_t numEffects = 0; | 
 | 139 |     int ret = EffectQueryNumberEffects(&numEffects); | 
 | 140 |     if (ret != 0) { | 
 | 141 |         ALOGE("AudioMixer() error %d querying number of effects", ret); | 
 | 142 |         return; | 
 | 143 |     } | 
 | 144 |     ALOGV("EffectQueryNumberEffects() numEffects=%d", numEffects); | 
 | 145 |  | 
 | 146 |     for (uint32_t i = 0 ; i < numEffects ; i++) { | 
 | 147 |         if (EffectQueryEffect(i, &dwnmFxDesc) == 0) { | 
 | 148 |             ALOGV("effect %d is called %s", i, dwnmFxDesc.name); | 
 | 149 |             if (memcmp(&dwnmFxDesc.type, EFFECT_UIID_DOWNMIX, sizeof(effect_uuid_t)) == 0) { | 
 | 150 |                 ALOGI("found effect \"%s\" from %s", | 
 | 151 |                         dwnmFxDesc.name, dwnmFxDesc.implementor); | 
 | 152 |                 isMultichannelCapable = true; | 
 | 153 |                 break; | 
 | 154 |             } | 
 | 155 |         } | 
 | 156 |     } | 
 | 157 |     ALOGE_IF(!isMultichannelCapable, "unable to find downmix effect"); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 158 | } | 
 | 159 |  | 
| Glenn Kasten | c5ac4cb | 2011-12-12 09:05:55 -0800 | [diff] [blame] | 160 | AudioMixer::~AudioMixer() | 
 | 161 | { | 
 | 162 |     track_t* t = mState.tracks; | 
| Glenn Kasten | bf71f1e | 2011-12-13 11:52:35 -0800 | [diff] [blame] | 163 |     for (unsigned i=0 ; i < MAX_NUM_TRACKS ; i++) { | 
| Glenn Kasten | c5ac4cb | 2011-12-12 09:05:55 -0800 | [diff] [blame] | 164 |         delete t->resampler; | 
| Jean-Michel Trivi | 9bd2322 | 2012-04-16 13:43:48 -0700 | [diff] [blame] | 165 |         delete t->downmixerBufferProvider; | 
| Glenn Kasten | c5ac4cb | 2011-12-12 09:05:55 -0800 | [diff] [blame] | 166 |         t++; | 
 | 167 |     } | 
 | 168 |     delete [] mState.outputTemp; | 
 | 169 |     delete [] mState.resampleTemp; | 
 | 170 | } | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 171 |  | 
| Jean-Michel Trivi | d06e132 | 2012-09-12 15:47:07 -0700 | [diff] [blame] | 172 | int AudioMixer::getTrackName(audio_channel_mask_t channelMask, int sessionId) | 
| Glenn Kasten | c5ac4cb | 2011-12-12 09:05:55 -0800 | [diff] [blame] | 173 | { | 
| Glenn Kasten | 5c94b6c | 2012-03-20 17:01:29 -0700 | [diff] [blame] | 174 |     uint32_t names = (~mTrackNames) & mConfiguredNames; | 
| Glenn Kasten | 98dd542 | 2011-12-15 14:38:29 -0800 | [diff] [blame] | 175 |     if (names != 0) { | 
 | 176 |         int n = __builtin_ctz(names); | 
| Steve Block | 3856b09 | 2011-10-20 11:56:00 +0100 | [diff] [blame] | 177 |         ALOGV("add track (%d)", n); | 
| Glenn Kasten | 98dd542 | 2011-12-15 14:38:29 -0800 | [diff] [blame] | 178 |         mTrackNames |= 1 << n; | 
| Glenn Kasten | deeb128 | 2012-03-25 11:59:31 -0700 | [diff] [blame] | 179 |         // assume default parameters for the track, except where noted below | 
 | 180 |         track_t* t = &mState.tracks[n]; | 
 | 181 |         t->needs = 0; | 
 | 182 |         t->volume[0] = UNITY_GAIN; | 
 | 183 |         t->volume[1] = UNITY_GAIN; | 
 | 184 |         // no initialization needed | 
 | 185 |         // t->prevVolume[0] | 
 | 186 |         // t->prevVolume[1] | 
 | 187 |         t->volumeInc[0] = 0; | 
 | 188 |         t->volumeInc[1] = 0; | 
 | 189 |         t->auxLevel = 0; | 
 | 190 |         t->auxInc = 0; | 
 | 191 |         // no initialization needed | 
 | 192 |         // t->prevAuxLevel | 
 | 193 |         // t->frameCount | 
 | 194 |         t->channelCount = 2; | 
 | 195 |         t->enabled = false; | 
 | 196 |         t->format = 16; | 
 | 197 |         t->channelMask = AUDIO_CHANNEL_OUT_STEREO; | 
| Jean-Michel Trivi | d06e132 | 2012-09-12 15:47:07 -0700 | [diff] [blame] | 198 |         t->sessionId = sessionId; | 
| Glenn Kasten | deeb128 | 2012-03-25 11:59:31 -0700 | [diff] [blame] | 199 |         // setBufferProvider(name, AudioBufferProvider *) is required before enable(name) | 
 | 200 |         t->bufferProvider = NULL; | 
 | 201 |         t->buffer.raw = NULL; | 
 | 202 |         // no initialization needed | 
 | 203 |         // t->buffer.frameCount | 
 | 204 |         t->hook = NULL; | 
 | 205 |         t->in = NULL; | 
 | 206 |         t->resampler = NULL; | 
 | 207 |         t->sampleRate = mSampleRate; | 
 | 208 |         // setParameter(name, TRACK, MAIN_BUFFER, mixBuffer) is required before enable(name) | 
 | 209 |         t->mainBuffer = NULL; | 
 | 210 |         t->auxBuffer = NULL; | 
| Glenn Kasten | 52008f8 | 2012-03-18 09:34:41 -0700 | [diff] [blame] | 211 |         t->downmixerBufferProvider = NULL; | 
| Jean-Michel Trivi | 9bd2322 | 2012-04-16 13:43:48 -0700 | [diff] [blame] | 212 |  | 
 | 213 |         status_t status = initTrackDownmix(&mState.tracks[n], n, channelMask); | 
 | 214 |         if (status == OK) { | 
 | 215 |             return TRACK0 + n; | 
 | 216 |         } | 
 | 217 |         ALOGE("AudioMixer::getTrackName(0x%x) failed, error preparing track for downmix", | 
 | 218 |                 channelMask); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 219 |     } | 
 | 220 |     return -1; | 
| Glenn Kasten | c5ac4cb | 2011-12-12 09:05:55 -0800 | [diff] [blame] | 221 | } | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 222 |  | 
| Glenn Kasten | c5ac4cb | 2011-12-12 09:05:55 -0800 | [diff] [blame] | 223 | void AudioMixer::invalidateState(uint32_t mask) | 
 | 224 | { | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 225 |     if (mask) { | 
 | 226 |         mState.needsChanged |= mask; | 
 | 227 |         mState.hook = process__validate; | 
 | 228 |     } | 
 | 229 |  } | 
 | 230 |  | 
| Jean-Michel Trivi | 9bd2322 | 2012-04-16 13:43:48 -0700 | [diff] [blame] | 231 | status_t AudioMixer::initTrackDownmix(track_t* pTrack, int trackNum, audio_channel_mask_t mask) | 
 | 232 | { | 
 | 233 |     uint32_t channelCount = popcount(mask); | 
 | 234 |     ALOG_ASSERT((channelCount <= MAX_NUM_CHANNELS_TO_DOWNMIX) && channelCount); | 
 | 235 |     status_t status = OK; | 
 | 236 |     if (channelCount > MAX_NUM_CHANNELS) { | 
 | 237 |         pTrack->channelMask = mask; | 
 | 238 |         pTrack->channelCount = channelCount; | 
 | 239 |         ALOGV("initTrackDownmix(track=%d, mask=0x%x) calls prepareTrackForDownmix()", | 
 | 240 |                 trackNum, mask); | 
 | 241 |         status = prepareTrackForDownmix(pTrack, trackNum); | 
 | 242 |     } else { | 
 | 243 |         unprepareTrackForDownmix(pTrack, trackNum); | 
 | 244 |     } | 
 | 245 |     return status; | 
 | 246 | } | 
 | 247 |  | 
 | 248 | void AudioMixer::unprepareTrackForDownmix(track_t* pTrack, int trackName) { | 
 | 249 |     ALOGV("AudioMixer::unprepareTrackForDownmix(%d)", trackName); | 
 | 250 |  | 
 | 251 |     if (pTrack->downmixerBufferProvider != NULL) { | 
 | 252 |         // this track had previously been configured with a downmixer, delete it | 
 | 253 |         ALOGV(" deleting old downmixer"); | 
 | 254 |         pTrack->bufferProvider = pTrack->downmixerBufferProvider->mTrackBufferProvider; | 
 | 255 |         delete pTrack->downmixerBufferProvider; | 
 | 256 |         pTrack->downmixerBufferProvider = NULL; | 
 | 257 |     } else { | 
 | 258 |         ALOGV(" nothing to do, no downmixer to delete"); | 
 | 259 |     } | 
 | 260 | } | 
 | 261 |  | 
| Jean-Michel Trivi | 7d5b262 | 2012-04-04 18:54:36 -0700 | [diff] [blame] | 262 | status_t AudioMixer::prepareTrackForDownmix(track_t* pTrack, int trackName) | 
 | 263 | { | 
 | 264 |     ALOGV("AudioMixer::prepareTrackForDownmix(%d) with mask 0x%x", trackName, pTrack->channelMask); | 
 | 265 |  | 
| Jean-Michel Trivi | 9bd2322 | 2012-04-16 13:43:48 -0700 | [diff] [blame] | 266 |     // discard the previous downmixer if there was one | 
 | 267 |     unprepareTrackForDownmix(pTrack, trackName); | 
| Jean-Michel Trivi | 7d5b262 | 2012-04-04 18:54:36 -0700 | [diff] [blame] | 268 |  | 
 | 269 |     DownmixerBufferProvider* pDbp = new DownmixerBufferProvider(); | 
 | 270 |     int32_t status; | 
 | 271 |  | 
 | 272 |     if (!isMultichannelCapable) { | 
 | 273 |         ALOGE("prepareTrackForDownmix(%d) fails: mixer doesn't support multichannel content", | 
 | 274 |                 trackName); | 
 | 275 |         goto noDownmixForActiveTrack; | 
 | 276 |     } | 
 | 277 |  | 
 | 278 |     if (EffectCreate(&dwnmFxDesc.uuid, | 
| Jean-Michel Trivi | d06e132 | 2012-09-12 15:47:07 -0700 | [diff] [blame] | 279 |             pTrack->sessionId /*sessionId*/, -2 /*ioId not relevant here, using random value*/, | 
| Jean-Michel Trivi | 7d5b262 | 2012-04-04 18:54:36 -0700 | [diff] [blame] | 280 |             &pDbp->mDownmixHandle/*pHandle*/) != 0) { | 
 | 281 |         ALOGE("prepareTrackForDownmix(%d) fails: error creating downmixer effect", trackName); | 
 | 282 |         goto noDownmixForActiveTrack; | 
 | 283 |     } | 
 | 284 |  | 
 | 285 |     // channel input configuration will be overridden per-track | 
 | 286 |     pDbp->mDownmixConfig.inputCfg.channels = pTrack->channelMask; | 
 | 287 |     pDbp->mDownmixConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO; | 
 | 288 |     pDbp->mDownmixConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT; | 
 | 289 |     pDbp->mDownmixConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT; | 
 | 290 |     pDbp->mDownmixConfig.inputCfg.samplingRate = pTrack->sampleRate; | 
 | 291 |     pDbp->mDownmixConfig.outputCfg.samplingRate = pTrack->sampleRate; | 
 | 292 |     pDbp->mDownmixConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; | 
 | 293 |     pDbp->mDownmixConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_WRITE; | 
 | 294 |     // input and output buffer provider, and frame count will not be used as the downmix effect | 
 | 295 |     // process() function is called directly (see DownmixerBufferProvider::getNextBuffer()) | 
 | 296 |     pDbp->mDownmixConfig.inputCfg.mask = EFFECT_CONFIG_SMP_RATE | EFFECT_CONFIG_CHANNELS | | 
 | 297 |             EFFECT_CONFIG_FORMAT | EFFECT_CONFIG_ACC_MODE; | 
 | 298 |     pDbp->mDownmixConfig.outputCfg.mask = pDbp->mDownmixConfig.inputCfg.mask; | 
 | 299 |  | 
 | 300 |     {// scope for local variables that are not used in goto label "noDownmixForActiveTrack" | 
 | 301 |         int cmdStatus; | 
 | 302 |         uint32_t replySize = sizeof(int); | 
 | 303 |  | 
 | 304 |         // Configure and enable downmixer | 
 | 305 |         status = (*pDbp->mDownmixHandle)->command(pDbp->mDownmixHandle, | 
 | 306 |                 EFFECT_CMD_SET_CONFIG /*cmdCode*/, sizeof(effect_config_t) /*cmdSize*/, | 
 | 307 |                 &pDbp->mDownmixConfig /*pCmdData*/, | 
 | 308 |                 &replySize /*replySize*/, &cmdStatus /*pReplyData*/); | 
 | 309 |         if ((status != 0) || (cmdStatus != 0)) { | 
 | 310 |             ALOGE("error %d while configuring downmixer for track %d", status, trackName); | 
 | 311 |             goto noDownmixForActiveTrack; | 
 | 312 |         } | 
 | 313 |         replySize = sizeof(int); | 
 | 314 |         status = (*pDbp->mDownmixHandle)->command(pDbp->mDownmixHandle, | 
 | 315 |                 EFFECT_CMD_ENABLE /*cmdCode*/, 0 /*cmdSize*/, NULL /*pCmdData*/, | 
 | 316 |                 &replySize /*replySize*/, &cmdStatus /*pReplyData*/); | 
 | 317 |         if ((status != 0) || (cmdStatus != 0)) { | 
 | 318 |             ALOGE("error %d while enabling downmixer for track %d", status, trackName); | 
 | 319 |             goto noDownmixForActiveTrack; | 
 | 320 |         } | 
 | 321 |  | 
 | 322 |         // Set downmix type | 
 | 323 |         // parameter size rounded for padding on 32bit boundary | 
 | 324 |         const int psizePadded = ((sizeof(downmix_params_t) - 1)/sizeof(int) + 1) * sizeof(int); | 
 | 325 |         const int downmixParamSize = | 
 | 326 |                 sizeof(effect_param_t) + psizePadded + sizeof(downmix_type_t); | 
 | 327 |         effect_param_t * const param = (effect_param_t *) malloc(downmixParamSize); | 
 | 328 |         param->psize = sizeof(downmix_params_t); | 
 | 329 |         const downmix_params_t downmixParam = DOWNMIX_PARAM_TYPE; | 
 | 330 |         memcpy(param->data, &downmixParam, param->psize); | 
 | 331 |         const downmix_type_t downmixType = DOWNMIX_TYPE_FOLD; | 
 | 332 |         param->vsize = sizeof(downmix_type_t); | 
 | 333 |         memcpy(param->data + psizePadded, &downmixType, param->vsize); | 
 | 334 |  | 
 | 335 |         status = (*pDbp->mDownmixHandle)->command(pDbp->mDownmixHandle, | 
 | 336 |                 EFFECT_CMD_SET_PARAM /* cmdCode */, downmixParamSize/* cmdSize */, | 
 | 337 |                 param /*pCmndData*/, &replySize /*replySize*/, &cmdStatus /*pReplyData*/); | 
 | 338 |  | 
 | 339 |         free(param); | 
 | 340 |  | 
 | 341 |         if ((status != 0) || (cmdStatus != 0)) { | 
 | 342 |             ALOGE("error %d while setting downmix type for track %d", status, trackName); | 
 | 343 |             goto noDownmixForActiveTrack; | 
 | 344 |         } else { | 
 | 345 |             ALOGV("downmix type set to %d for track %d", (int) downmixType, trackName); | 
 | 346 |         } | 
 | 347 |     }// end of scope for local variables that are not used in goto label "noDownmixForActiveTrack" | 
 | 348 |  | 
 | 349 |     // initialization successful: | 
 | 350 |     // - keep track of the real buffer provider in case it was set before | 
 | 351 |     pDbp->mTrackBufferProvider = pTrack->bufferProvider; | 
 | 352 |     // - we'll use the downmix effect integrated inside this | 
 | 353 |     //    track's buffer provider, and we'll use it as the track's buffer provider | 
 | 354 |     pTrack->downmixerBufferProvider = pDbp; | 
 | 355 |     pTrack->bufferProvider = pDbp; | 
 | 356 |  | 
 | 357 |     return NO_ERROR; | 
 | 358 |  | 
 | 359 | noDownmixForActiveTrack: | 
 | 360 |     delete pDbp; | 
 | 361 |     pTrack->downmixerBufferProvider = NULL; | 
 | 362 |     return NO_INIT; | 
 | 363 | } | 
 | 364 |  | 
| Glenn Kasten | c5ac4cb | 2011-12-12 09:05:55 -0800 | [diff] [blame] | 365 | void AudioMixer::deleteTrackName(int name) | 
 | 366 | { | 
| Jean-Michel Trivi | 9bd2322 | 2012-04-16 13:43:48 -0700 | [diff] [blame] | 367 |     ALOGV("AudioMixer::deleteTrackName(%d)", name); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 368 |     name -= TRACK0; | 
| Glenn Kasten | 5798d4e | 2012-03-08 12:18:35 -0800 | [diff] [blame] | 369 |     ALOG_ASSERT(uint32_t(name) < MAX_NUM_TRACKS, "bad track name %d", name); | 
| Glenn Kasten | 237a624 | 2011-12-15 15:32:27 -0800 | [diff] [blame] | 370 |     ALOGV("deleteTrackName(%d)", name); | 
 | 371 |     track_t& track(mState.tracks[ name ]); | 
| Glenn Kasten | 4c340c6 | 2012-01-27 12:33:54 -0800 | [diff] [blame] | 372 |     if (track.enabled) { | 
 | 373 |         track.enabled = false; | 
| Glenn Kasten | 237a624 | 2011-12-15 15:32:27 -0800 | [diff] [blame] | 374 |         invalidateState(1<<name); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 375 |     } | 
| Glenn Kasten | 4e2293f | 2012-04-12 09:39:07 -0700 | [diff] [blame] | 376 |     // delete the resampler | 
 | 377 |     delete track.resampler; | 
 | 378 |     track.resampler = NULL; | 
| Jean-Michel Trivi | 9bd2322 | 2012-04-16 13:43:48 -0700 | [diff] [blame] | 379 |     // delete the downmixer | 
 | 380 |     unprepareTrackForDownmix(&mState.tracks[name], name); | 
 | 381 |  | 
| Glenn Kasten | 237a624 | 2011-12-15 15:32:27 -0800 | [diff] [blame] | 382 |     mTrackNames &= ~(1<<name); | 
| Glenn Kasten | c5ac4cb | 2011-12-12 09:05:55 -0800 | [diff] [blame] | 383 | } | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 384 |  | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 385 | void AudioMixer::enable(int name) | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 386 | { | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 387 |     name -= TRACK0; | 
| Glenn Kasten | 5798d4e | 2012-03-08 12:18:35 -0800 | [diff] [blame] | 388 |     ALOG_ASSERT(uint32_t(name) < MAX_NUM_TRACKS, "bad track name %d", name); | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 389 |     track_t& track = mState.tracks[name]; | 
 | 390 |  | 
| Glenn Kasten | 4c340c6 | 2012-01-27 12:33:54 -0800 | [diff] [blame] | 391 |     if (!track.enabled) { | 
 | 392 |         track.enabled = true; | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 393 |         ALOGV("enable(%d)", name); | 
 | 394 |         invalidateState(1 << name); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 395 |     } | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 396 | } | 
 | 397 |  | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 398 | void AudioMixer::disable(int name) | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 399 | { | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 400 |     name -= TRACK0; | 
| Glenn Kasten | 5798d4e | 2012-03-08 12:18:35 -0800 | [diff] [blame] | 401 |     ALOG_ASSERT(uint32_t(name) < MAX_NUM_TRACKS, "bad track name %d", name); | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 402 |     track_t& track = mState.tracks[name]; | 
 | 403 |  | 
| Glenn Kasten | 4c340c6 | 2012-01-27 12:33:54 -0800 | [diff] [blame] | 404 |     if (track.enabled) { | 
 | 405 |         track.enabled = false; | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 406 |         ALOGV("disable(%d)", name); | 
 | 407 |         invalidateState(1 << name); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 408 |     } | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 409 | } | 
 | 410 |  | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 411 | void AudioMixer::setParameter(int name, int target, int param, void *value) | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 412 | { | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 413 |     name -= TRACK0; | 
| Glenn Kasten | 5798d4e | 2012-03-08 12:18:35 -0800 | [diff] [blame] | 414 |     ALOG_ASSERT(uint32_t(name) < MAX_NUM_TRACKS, "bad track name %d", name); | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 415 |     track_t& track = mState.tracks[name]; | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 416 |  | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 417 |     int valueInt = (int)value; | 
 | 418 |     int32_t *valueBuf = (int32_t *)value; | 
 | 419 |  | 
 | 420 |     switch (target) { | 
| Glenn Kasten | 788040c | 2011-05-05 08:19:00 -0700 | [diff] [blame] | 421 |  | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 422 |     case TRACK: | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 423 |         switch (param) { | 
| Glenn Kasten | 788040c | 2011-05-05 08:19:00 -0700 | [diff] [blame] | 424 |         case CHANNEL_MASK: { | 
| Glenn Kasten | 254af18 | 2012-07-03 14:59:05 -0700 | [diff] [blame] | 425 |             audio_channel_mask_t mask = (audio_channel_mask_t) value; | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 426 |             if (track.channelMask != mask) { | 
| Glenn Kasten | 5798d4e | 2012-03-08 12:18:35 -0800 | [diff] [blame] | 427 |                 uint32_t channelCount = popcount(mask); | 
| Jean-Michel Trivi | 7d5b262 | 2012-04-04 18:54:36 -0700 | [diff] [blame] | 428 |                 ALOG_ASSERT((channelCount <= MAX_NUM_CHANNELS_TO_DOWNMIX) && channelCount); | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 429 |                 track.channelMask = mask; | 
 | 430 |                 track.channelCount = channelCount; | 
| Jean-Michel Trivi | 9bd2322 | 2012-04-16 13:43:48 -0700 | [diff] [blame] | 431 |                 // the mask has changed, does this track need a downmixer? | 
 | 432 |                 initTrackDownmix(&mState.tracks[name], name, mask); | 
| Glenn Kasten | 788040c | 2011-05-05 08:19:00 -0700 | [diff] [blame] | 433 |                 ALOGV("setParameter(TRACK, CHANNEL_MASK, %x)", mask); | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 434 |                 invalidateState(1 << name); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 435 |             } | 
| Glenn Kasten | 788040c | 2011-05-05 08:19:00 -0700 | [diff] [blame] | 436 |             } break; | 
 | 437 |         case MAIN_BUFFER: | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 438 |             if (track.mainBuffer != valueBuf) { | 
 | 439 |                 track.mainBuffer = valueBuf; | 
| Steve Block | 3856b09 | 2011-10-20 11:56:00 +0100 | [diff] [blame] | 440 |                 ALOGV("setParameter(TRACK, MAIN_BUFFER, %p)", valueBuf); | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 441 |                 invalidateState(1 << name); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 442 |             } | 
| Glenn Kasten | 788040c | 2011-05-05 08:19:00 -0700 | [diff] [blame] | 443 |             break; | 
 | 444 |         case AUX_BUFFER: | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 445 |             if (track.auxBuffer != valueBuf) { | 
 | 446 |                 track.auxBuffer = valueBuf; | 
| Steve Block | 3856b09 | 2011-10-20 11:56:00 +0100 | [diff] [blame] | 447 |                 ALOGV("setParameter(TRACK, AUX_BUFFER, %p)", valueBuf); | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 448 |                 invalidateState(1 << name); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 449 |             } | 
| Glenn Kasten | 788040c | 2011-05-05 08:19:00 -0700 | [diff] [blame] | 450 |             break; | 
| Glenn Kasten | deeb128 | 2012-03-25 11:59:31 -0700 | [diff] [blame] | 451 |         case FORMAT: | 
 | 452 |             ALOG_ASSERT(valueInt == AUDIO_FORMAT_PCM_16_BIT); | 
 | 453 |             break; | 
| Jean-Michel Trivi | 7d5b262 | 2012-04-04 18:54:36 -0700 | [diff] [blame] | 454 |         // FIXME do we want to support setting the downmix type from AudioFlinger? | 
 | 455 |         //         for a specific track? or per mixer? | 
 | 456 |         /* case DOWNMIX_TYPE: | 
 | 457 |             break          */ | 
| Glenn Kasten | 788040c | 2011-05-05 08:19:00 -0700 | [diff] [blame] | 458 |         default: | 
| Glenn Kasten | 5798d4e | 2012-03-08 12:18:35 -0800 | [diff] [blame] | 459 |             LOG_FATAL("bad param"); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 460 |         } | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 461 |         break; | 
| Glenn Kasten | 788040c | 2011-05-05 08:19:00 -0700 | [diff] [blame] | 462 |  | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 463 |     case RESAMPLE: | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 464 |         switch (param) { | 
 | 465 |         case SAMPLE_RATE: | 
| Glenn Kasten | 5798d4e | 2012-03-08 12:18:35 -0800 | [diff] [blame] | 466 |             ALOG_ASSERT(valueInt > 0, "bad sample rate %d", valueInt); | 
| Glenn Kasten | 788040c | 2011-05-05 08:19:00 -0700 | [diff] [blame] | 467 |             if (track.setResampler(uint32_t(valueInt), mSampleRate)) { | 
 | 468 |                 ALOGV("setParameter(RESAMPLE, SAMPLE_RATE, %u)", | 
 | 469 |                         uint32_t(valueInt)); | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 470 |                 invalidateState(1 << name); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 471 |             } | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 472 |             break; | 
 | 473 |         case RESET: | 
| Eric Laurent | 243f5f9 | 2011-02-28 16:52:51 -0800 | [diff] [blame] | 474 |             track.resetResampler(); | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 475 |             invalidateState(1 << name); | 
 | 476 |             break; | 
| Glenn Kasten | 4e2293f | 2012-04-12 09:39:07 -0700 | [diff] [blame] | 477 |         case REMOVE: | 
 | 478 |             delete track.resampler; | 
 | 479 |             track.resampler = NULL; | 
 | 480 |             track.sampleRate = mSampleRate; | 
 | 481 |             invalidateState(1 << name); | 
 | 482 |             break; | 
| Glenn Kasten | 788040c | 2011-05-05 08:19:00 -0700 | [diff] [blame] | 483 |         default: | 
| Glenn Kasten | 5798d4e | 2012-03-08 12:18:35 -0800 | [diff] [blame] | 484 |             LOG_FATAL("bad param"); | 
| Eric Laurent | 243f5f9 | 2011-02-28 16:52:51 -0800 | [diff] [blame] | 485 |         } | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 486 |         break; | 
| Glenn Kasten | 788040c | 2011-05-05 08:19:00 -0700 | [diff] [blame] | 487 |  | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 488 |     case RAMP_VOLUME: | 
 | 489 |     case VOLUME: | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 490 |         switch (param) { | 
| Glenn Kasten | 788040c | 2011-05-05 08:19:00 -0700 | [diff] [blame] | 491 |         case VOLUME0: | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 492 |         case VOLUME1: | 
 | 493 |             if (track.volume[param-VOLUME0] != valueInt) { | 
| Steve Block | 3856b09 | 2011-10-20 11:56:00 +0100 | [diff] [blame] | 494 |                 ALOGV("setParameter(VOLUME, VOLUME0/1: %04x)", valueInt); | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 495 |                 track.prevVolume[param-VOLUME0] = track.volume[param-VOLUME0] << 16; | 
 | 496 |                 track.volume[param-VOLUME0] = valueInt; | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 497 |                 if (target == VOLUME) { | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 498 |                     track.prevVolume[param-VOLUME0] = valueInt << 16; | 
 | 499 |                     track.volumeInc[param-VOLUME0] = 0; | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 500 |                 } else { | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 501 |                     int32_t d = (valueInt<<16) - track.prevVolume[param-VOLUME0]; | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 502 |                     int32_t volInc = d / int32_t(mState.frameCount); | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 503 |                     track.volumeInc[param-VOLUME0] = volInc; | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 504 |                     if (volInc == 0) { | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 505 |                         track.prevVolume[param-VOLUME0] = valueInt << 16; | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 506 |                     } | 
 | 507 |                 } | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 508 |                 invalidateState(1 << name); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 509 |             } | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 510 |             break; | 
 | 511 |         case AUXLEVEL: | 
| Glenn Kasten | 5798d4e | 2012-03-08 12:18:35 -0800 | [diff] [blame] | 512 |             //ALOG_ASSERT(0 <= valueInt && valueInt <= MAX_GAIN_INT, "bad aux level %d", valueInt); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 513 |             if (track.auxLevel != valueInt) { | 
| Steve Block | 3856b09 | 2011-10-20 11:56:00 +0100 | [diff] [blame] | 514 |                 ALOGV("setParameter(VOLUME, AUXLEVEL: %04x)", valueInt); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 515 |                 track.prevAuxLevel = track.auxLevel << 16; | 
 | 516 |                 track.auxLevel = valueInt; | 
 | 517 |                 if (target == VOLUME) { | 
 | 518 |                     track.prevAuxLevel = valueInt << 16; | 
 | 519 |                     track.auxInc = 0; | 
 | 520 |                 } else { | 
 | 521 |                     int32_t d = (valueInt<<16) - track.prevAuxLevel; | 
 | 522 |                     int32_t volInc = d / int32_t(mState.frameCount); | 
 | 523 |                     track.auxInc = volInc; | 
 | 524 |                     if (volInc == 0) { | 
 | 525 |                         track.prevAuxLevel = valueInt << 16; | 
 | 526 |                     } | 
 | 527 |                 } | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 528 |                 invalidateState(1 << name); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 529 |             } | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 530 |             break; | 
| Glenn Kasten | 788040c | 2011-05-05 08:19:00 -0700 | [diff] [blame] | 531 |         default: | 
| Glenn Kasten | 5798d4e | 2012-03-08 12:18:35 -0800 | [diff] [blame] | 532 |             LOG_FATAL("bad param"); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 533 |         } | 
 | 534 |         break; | 
| Glenn Kasten | 788040c | 2011-05-05 08:19:00 -0700 | [diff] [blame] | 535 |  | 
 | 536 |     default: | 
| Glenn Kasten | 5798d4e | 2012-03-08 12:18:35 -0800 | [diff] [blame] | 537 |         LOG_FATAL("bad target"); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 538 |     } | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 539 | } | 
 | 540 |  | 
 | 541 | bool AudioMixer::track_t::setResampler(uint32_t value, uint32_t devSampleRate) | 
 | 542 | { | 
| Glenn Kasten | 4e2293f | 2012-04-12 09:39:07 -0700 | [diff] [blame] | 543 |     if (value != devSampleRate || resampler != NULL) { | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 544 |         if (sampleRate != value) { | 
 | 545 |             sampleRate = value; | 
| Glenn Kasten | e0feee3 | 2011-12-13 11:53:26 -0800 | [diff] [blame] | 546 |             if (resampler == NULL) { | 
| Glenn Kasten | ac60205 | 2012-10-01 14:04:31 -0700 | [diff] [blame] | 547 |                 ALOGV("creating resampler from track %d Hz to device %d Hz", value, devSampleRate); | 
 | 548 |                 AudioResampler::src_quality quality; | 
 | 549 |                 // force lowest quality level resampler if use case isn't music or video | 
 | 550 |                 // FIXME this is flawed for dynamic sample rates, as we choose the resampler | 
 | 551 |                 // quality level based on the initial ratio, but that could change later. | 
 | 552 |                 // Should have a way to distinguish tracks with static ratios vs. dynamic ratios. | 
 | 553 |                 if (!((value == 44100 && devSampleRate == 48000) || | 
 | 554 |                       (value == 48000 && devSampleRate == 44100))) { | 
 | 555 |                     quality = AudioResampler::LOW_QUALITY; | 
 | 556 |                 } else { | 
 | 557 |                     quality = AudioResampler::DEFAULT_QUALITY; | 
 | 558 |                 } | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 559 |                 resampler = AudioResampler::create( | 
| Jean-Michel Trivi | acb86cc | 2012-04-16 12:43:57 -0700 | [diff] [blame] | 560 |                         format, | 
 | 561 |                         // the resampler sees the number of channels after the downmixer, if any | 
 | 562 |                         downmixerBufferProvider != NULL ? MAX_NUM_CHANNELS : channelCount, | 
| Glenn Kasten | ac60205 | 2012-10-01 14:04:31 -0700 | [diff] [blame] | 563 |                         devSampleRate, quality); | 
| Glenn Kasten | 52008f8 | 2012-03-18 09:34:41 -0700 | [diff] [blame] | 564 |                 resampler->setLocalTimeFreq(sLocalTimeFreq); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 565 |             } | 
 | 566 |             return true; | 
 | 567 |         } | 
 | 568 |     } | 
 | 569 |     return false; | 
 | 570 | } | 
 | 571 |  | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 572 | inline | 
 | 573 | void AudioMixer::track_t::adjustVolumeRamp(bool aux) | 
 | 574 | { | 
| Glenn Kasten | f9a2777 | 2012-01-06 07:47:26 -0800 | [diff] [blame] | 575 |     for (uint32_t i=0 ; i<MAX_NUM_CHANNELS ; i++) { | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 576 |         if (((volumeInc[i]>0) && (((prevVolume[i]+volumeInc[i])>>16) >= volume[i])) || | 
 | 577 |             ((volumeInc[i]<0) && (((prevVolume[i]+volumeInc[i])>>16) <= volume[i]))) { | 
 | 578 |             volumeInc[i] = 0; | 
 | 579 |             prevVolume[i] = volume[i]<<16; | 
 | 580 |         } | 
 | 581 |     } | 
 | 582 |     if (aux) { | 
 | 583 |         if (((auxInc>0) && (((prevAuxLevel+auxInc)>>16) >= auxLevel)) || | 
 | 584 |             ((auxInc<0) && (((prevAuxLevel+auxInc)>>16) <= auxLevel))) { | 
 | 585 |             auxInc = 0; | 
 | 586 |             prevAuxLevel = auxLevel<<16; | 
 | 587 |         } | 
 | 588 |     } | 
 | 589 | } | 
 | 590 |  | 
| Glenn Kasten | c59c004 | 2012-02-02 14:06:11 -0800 | [diff] [blame] | 591 | size_t AudioMixer::getUnreleasedFrames(int name) const | 
| Eric Laurent | 071ccd5 | 2011-12-22 16:08:41 -0800 | [diff] [blame] | 592 | { | 
 | 593 |     name -= TRACK0; | 
 | 594 |     if (uint32_t(name) < MAX_NUM_TRACKS) { | 
| Glenn Kasten | c59c004 | 2012-02-02 14:06:11 -0800 | [diff] [blame] | 595 |         return mState.tracks[name].getUnreleasedFrames(); | 
| Eric Laurent | 071ccd5 | 2011-12-22 16:08:41 -0800 | [diff] [blame] | 596 |     } | 
 | 597 |     return 0; | 
 | 598 | } | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 599 |  | 
| Glenn Kasten | 01c4ebf | 2012-02-22 10:47:35 -0800 | [diff] [blame] | 600 | void AudioMixer::setBufferProvider(int name, AudioBufferProvider* bufferProvider) | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 601 | { | 
| Glenn Kasten | 9c56d4a | 2011-12-19 15:06:39 -0800 | [diff] [blame] | 602 |     name -= TRACK0; | 
| Glenn Kasten | 5798d4e | 2012-03-08 12:18:35 -0800 | [diff] [blame] | 603 |     ALOG_ASSERT(uint32_t(name) < MAX_NUM_TRACKS, "bad track name %d", name); | 
| Jean-Michel Trivi | 7d5b262 | 2012-04-04 18:54:36 -0700 | [diff] [blame] | 604 |  | 
 | 605 |     if (mState.tracks[name].downmixerBufferProvider != NULL) { | 
 | 606 |         // update required? | 
 | 607 |         if (mState.tracks[name].downmixerBufferProvider->mTrackBufferProvider != bufferProvider) { | 
 | 608 |             ALOGV("AudioMixer::setBufferProvider(%p) for downmix", bufferProvider); | 
 | 609 |             // setting the buffer provider for a track that gets downmixed consists in: | 
 | 610 |             //  1/ setting the buffer provider to the "downmix / buffer provider" wrapper | 
 | 611 |             //     so it's the one that gets called when the buffer provider is needed, | 
 | 612 |             mState.tracks[name].bufferProvider = mState.tracks[name].downmixerBufferProvider; | 
 | 613 |             //  2/ saving the buffer provider for the track so the wrapper can use it | 
 | 614 |             //     when it downmixes. | 
 | 615 |             mState.tracks[name].downmixerBufferProvider->mTrackBufferProvider = bufferProvider; | 
 | 616 |         } | 
 | 617 |     } else { | 
 | 618 |         mState.tracks[name].bufferProvider = bufferProvider; | 
 | 619 |     } | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 620 | } | 
 | 621 |  | 
 | 622 |  | 
 | 623 |  | 
| John Grossman | 4ff14ba | 2012-02-08 16:37:41 -0800 | [diff] [blame] | 624 | void AudioMixer::process(int64_t pts) | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 625 | { | 
| John Grossman | 4ff14ba | 2012-02-08 16:37:41 -0800 | [diff] [blame] | 626 |     mState.hook(&mState, pts); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 627 | } | 
 | 628 |  | 
 | 629 |  | 
| John Grossman | 4ff14ba | 2012-02-08 16:37:41 -0800 | [diff] [blame] | 630 | void AudioMixer::process__validate(state_t* state, int64_t pts) | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 631 | { | 
| Steve Block | 5ff1dd5 | 2012-01-05 23:22:43 +0000 | [diff] [blame] | 632 |     ALOGW_IF(!state->needsChanged, | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 633 |         "in process__validate() but nothing's invalid"); | 
 | 634 |  | 
 | 635 |     uint32_t changed = state->needsChanged; | 
 | 636 |     state->needsChanged = 0; // clear the validation flag | 
 | 637 |  | 
 | 638 |     // recompute which tracks are enabled / disabled | 
 | 639 |     uint32_t enabled = 0; | 
 | 640 |     uint32_t disabled = 0; | 
 | 641 |     while (changed) { | 
 | 642 |         const int i = 31 - __builtin_clz(changed); | 
 | 643 |         const uint32_t mask = 1<<i; | 
 | 644 |         changed &= ~mask; | 
 | 645 |         track_t& t = state->tracks[i]; | 
 | 646 |         (t.enabled ? enabled : disabled) |= mask; | 
 | 647 |     } | 
 | 648 |     state->enabledTracks &= ~disabled; | 
 | 649 |     state->enabledTracks |=  enabled; | 
 | 650 |  | 
 | 651 |     // compute everything we need... | 
 | 652 |     int countActiveTracks = 0; | 
| Glenn Kasten | 4c340c6 | 2012-01-27 12:33:54 -0800 | [diff] [blame] | 653 |     bool all16BitsStereoNoResample = true; | 
 | 654 |     bool resampling = false; | 
 | 655 |     bool volumeRamp = false; | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 656 |     uint32_t en = state->enabledTracks; | 
 | 657 |     while (en) { | 
 | 658 |         const int i = 31 - __builtin_clz(en); | 
 | 659 |         en &= ~(1<<i); | 
 | 660 |  | 
 | 661 |         countActiveTracks++; | 
 | 662 |         track_t& t = state->tracks[i]; | 
 | 663 |         uint32_t n = 0; | 
 | 664 |         n |= NEEDS_CHANNEL_1 + t.channelCount - 1; | 
 | 665 |         n |= NEEDS_FORMAT_16; | 
 | 666 |         n |= t.doesResample() ? NEEDS_RESAMPLE_ENABLED : NEEDS_RESAMPLE_DISABLED; | 
 | 667 |         if (t.auxLevel != 0 && t.auxBuffer != NULL) { | 
 | 668 |             n |= NEEDS_AUX_ENABLED; | 
 | 669 |         } | 
 | 670 |  | 
 | 671 |         if (t.volumeInc[0]|t.volumeInc[1]) { | 
| Glenn Kasten | 4c340c6 | 2012-01-27 12:33:54 -0800 | [diff] [blame] | 672 |             volumeRamp = true; | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 673 |         } else if (!t.doesResample() && t.volumeRL == 0) { | 
 | 674 |             n |= NEEDS_MUTE_ENABLED; | 
 | 675 |         } | 
 | 676 |         t.needs = n; | 
 | 677 |  | 
 | 678 |         if ((n & NEEDS_MUTE__MASK) == NEEDS_MUTE_ENABLED) { | 
 | 679 |             t.hook = track__nop; | 
 | 680 |         } else { | 
 | 681 |             if ((n & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) { | 
| Glenn Kasten | 4c340c6 | 2012-01-27 12:33:54 -0800 | [diff] [blame] | 682 |                 all16BitsStereoNoResample = false; | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 683 |             } | 
 | 684 |             if ((n & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) { | 
| Glenn Kasten | 4c340c6 | 2012-01-27 12:33:54 -0800 | [diff] [blame] | 685 |                 all16BitsStereoNoResample = false; | 
 | 686 |                 resampling = true; | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 687 |                 t.hook = track__genericResample; | 
| Jean-Michel Trivi | 7d5b262 | 2012-04-04 18:54:36 -0700 | [diff] [blame] | 688 |                 ALOGV_IF((n & NEEDS_CHANNEL_COUNT__MASK) > NEEDS_CHANNEL_2, | 
| Jean-Michel Trivi | 9bd2322 | 2012-04-16 13:43:48 -0700 | [diff] [blame] | 689 |                         "Track %d needs downmix + resample", i); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 690 |             } else { | 
 | 691 |                 if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_1){ | 
 | 692 |                     t.hook = track__16BitsMono; | 
| Glenn Kasten | 4c340c6 | 2012-01-27 12:33:54 -0800 | [diff] [blame] | 693 |                     all16BitsStereoNoResample = false; | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 694 |                 } | 
| Jean-Michel Trivi | 7d5b262 | 2012-04-04 18:54:36 -0700 | [diff] [blame] | 695 |                 if ((n & NEEDS_CHANNEL_COUNT__MASK) >= NEEDS_CHANNEL_2){ | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 696 |                     t.hook = track__16BitsStereo; | 
| Jean-Michel Trivi | 7d5b262 | 2012-04-04 18:54:36 -0700 | [diff] [blame] | 697 |                     ALOGV_IF((n & NEEDS_CHANNEL_COUNT__MASK) > NEEDS_CHANNEL_2, | 
| Jean-Michel Trivi | 9bd2322 | 2012-04-16 13:43:48 -0700 | [diff] [blame] | 698 |                             "Track %d needs downmix", i); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 699 |                 } | 
 | 700 |             } | 
 | 701 |         } | 
 | 702 |     } | 
 | 703 |  | 
 | 704 |     // select the processing hooks | 
 | 705 |     state->hook = process__nop; | 
 | 706 |     if (countActiveTracks) { | 
 | 707 |         if (resampling) { | 
 | 708 |             if (!state->outputTemp) { | 
 | 709 |                 state->outputTemp = new int32_t[MAX_NUM_CHANNELS * state->frameCount]; | 
 | 710 |             } | 
 | 711 |             if (!state->resampleTemp) { | 
 | 712 |                 state->resampleTemp = new int32_t[MAX_NUM_CHANNELS * state->frameCount]; | 
 | 713 |             } | 
 | 714 |             state->hook = process__genericResampling; | 
 | 715 |         } else { | 
 | 716 |             if (state->outputTemp) { | 
 | 717 |                 delete [] state->outputTemp; | 
| Glenn Kasten | e0feee3 | 2011-12-13 11:53:26 -0800 | [diff] [blame] | 718 |                 state->outputTemp = NULL; | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 719 |             } | 
 | 720 |             if (state->resampleTemp) { | 
 | 721 |                 delete [] state->resampleTemp; | 
| Glenn Kasten | e0feee3 | 2011-12-13 11:53:26 -0800 | [diff] [blame] | 722 |                 state->resampleTemp = NULL; | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 723 |             } | 
 | 724 |             state->hook = process__genericNoResampling; | 
 | 725 |             if (all16BitsStereoNoResample && !volumeRamp) { | 
 | 726 |                 if (countActiveTracks == 1) { | 
 | 727 |                     state->hook = process__OneTrack16BitsStereoNoResampling; | 
 | 728 |                 } | 
 | 729 |             } | 
 | 730 |         } | 
 | 731 |     } | 
 | 732 |  | 
| Steve Block | 3856b09 | 2011-10-20 11:56:00 +0100 | [diff] [blame] | 733 |     ALOGV("mixer configuration change: %d activeTracks (%08x) " | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 734 |         "all16BitsStereoNoResample=%d, resampling=%d, volumeRamp=%d", | 
 | 735 |         countActiveTracks, state->enabledTracks, | 
 | 736 |         all16BitsStereoNoResample, resampling, volumeRamp); | 
 | 737 |  | 
| John Grossman | 4ff14ba | 2012-02-08 16:37:41 -0800 | [diff] [blame] | 738 |    state->hook(state, pts); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 739 |  | 
| Glenn Kasten | c5ac4cb | 2011-12-12 09:05:55 -0800 | [diff] [blame] | 740 |     // Now that the volume ramp has been done, set optimal state and | 
 | 741 |     // track hooks for subsequent mixer process | 
 | 742 |     if (countActiveTracks) { | 
| Glenn Kasten | 4c340c6 | 2012-01-27 12:33:54 -0800 | [diff] [blame] | 743 |         bool allMuted = true; | 
| Glenn Kasten | c5ac4cb | 2011-12-12 09:05:55 -0800 | [diff] [blame] | 744 |         uint32_t en = state->enabledTracks; | 
 | 745 |         while (en) { | 
 | 746 |             const int i = 31 - __builtin_clz(en); | 
 | 747 |             en &= ~(1<<i); | 
 | 748 |             track_t& t = state->tracks[i]; | 
 | 749 |             if (!t.doesResample() && t.volumeRL == 0) | 
 | 750 |             { | 
 | 751 |                 t.needs |= NEEDS_MUTE_ENABLED; | 
 | 752 |                 t.hook = track__nop; | 
 | 753 |             } else { | 
| Glenn Kasten | 4c340c6 | 2012-01-27 12:33:54 -0800 | [diff] [blame] | 754 |                 allMuted = false; | 
| Glenn Kasten | c5ac4cb | 2011-12-12 09:05:55 -0800 | [diff] [blame] | 755 |             } | 
 | 756 |         } | 
 | 757 |         if (allMuted) { | 
 | 758 |             state->hook = process__nop; | 
 | 759 |         } else if (all16BitsStereoNoResample) { | 
 | 760 |             if (countActiveTracks == 1) { | 
 | 761 |                 state->hook = process__OneTrack16BitsStereoNoResampling; | 
 | 762 |             } | 
 | 763 |         } | 
 | 764 |     } | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 765 | } | 
 | 766 |  | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 767 |  | 
| Glenn Kasten | 85ab62c | 2012-11-01 11:11:38 -0700 | [diff] [blame] | 768 | void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFrameCount, | 
 | 769 |         int32_t* temp, int32_t* aux) | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 770 | { | 
 | 771 |     t->resampler->setSampleRate(t->sampleRate); | 
 | 772 |  | 
 | 773 |     // ramp gain - resample to temp buffer and scale/mix in 2nd step | 
 | 774 |     if (aux != NULL) { | 
 | 775 |         // always resample with unity gain when sending to auxiliary buffer to be able | 
 | 776 |         // to apply send level after resampling | 
 | 777 |         // TODO: modify each resampler to support aux channel? | 
 | 778 |         t->resampler->setVolume(UNITY_GAIN, UNITY_GAIN); | 
 | 779 |         memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t)); | 
 | 780 |         t->resampler->resample(temp, outFrameCount, t->bufferProvider); | 
| Glenn Kasten | f6b1678 | 2011-12-15 09:51:17 -0800 | [diff] [blame] | 781 |         if (CC_UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc)) { | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 782 |             volumeRampStereo(t, out, outFrameCount, temp, aux); | 
 | 783 |         } else { | 
 | 784 |             volumeStereo(t, out, outFrameCount, temp, aux); | 
 | 785 |         } | 
 | 786 |     } else { | 
| Glenn Kasten | f6b1678 | 2011-12-15 09:51:17 -0800 | [diff] [blame] | 787 |         if (CC_UNLIKELY(t->volumeInc[0]|t->volumeInc[1])) { | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 788 |             t->resampler->setVolume(UNITY_GAIN, UNITY_GAIN); | 
 | 789 |             memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t)); | 
 | 790 |             t->resampler->resample(temp, outFrameCount, t->bufferProvider); | 
 | 791 |             volumeRampStereo(t, out, outFrameCount, temp, aux); | 
 | 792 |         } | 
 | 793 |  | 
 | 794 |         // constant gain | 
 | 795 |         else { | 
 | 796 |             t->resampler->setVolume(t->volume[0], t->volume[1]); | 
 | 797 |             t->resampler->resample(out, outFrameCount, t->bufferProvider); | 
 | 798 |         } | 
 | 799 |     } | 
 | 800 | } | 
 | 801 |  | 
| Glenn Kasten | 85ab62c | 2012-11-01 11:11:38 -0700 | [diff] [blame] | 802 | void AudioMixer::track__nop(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp, | 
 | 803 |         int32_t* aux) | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 804 | { | 
 | 805 | } | 
 | 806 |  | 
| Glenn Kasten | 85ab62c | 2012-11-01 11:11:38 -0700 | [diff] [blame] | 807 | void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, | 
 | 808 |         int32_t* aux) | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 809 | { | 
 | 810 |     int32_t vl = t->prevVolume[0]; | 
 | 811 |     int32_t vr = t->prevVolume[1]; | 
 | 812 |     const int32_t vlInc = t->volumeInc[0]; | 
 | 813 |     const int32_t vrInc = t->volumeInc[1]; | 
 | 814 |  | 
| Steve Block | b8a8052 | 2011-12-20 16:23:08 +0000 | [diff] [blame] | 815 |     //ALOGD("[0] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d", | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 816 |     //        t, vlInc/65536.0f, vl/65536.0f, t->volume[0], | 
 | 817 |     //       (vl + vlInc*frameCount)/65536.0f, frameCount); | 
 | 818 |  | 
 | 819 |     // ramp volume | 
| Glenn Kasten | f6b1678 | 2011-12-15 09:51:17 -0800 | [diff] [blame] | 820 |     if (CC_UNLIKELY(aux != NULL)) { | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 821 |         int32_t va = t->prevAuxLevel; | 
 | 822 |         const int32_t vaInc = t->auxInc; | 
 | 823 |         int32_t l; | 
 | 824 |         int32_t r; | 
 | 825 |  | 
 | 826 |         do { | 
 | 827 |             l = (*temp++ >> 12); | 
 | 828 |             r = (*temp++ >> 12); | 
 | 829 |             *out++ += (vl >> 16) * l; | 
 | 830 |             *out++ += (vr >> 16) * r; | 
 | 831 |             *aux++ += (va >> 17) * (l + r); | 
 | 832 |             vl += vlInc; | 
 | 833 |             vr += vrInc; | 
 | 834 |             va += vaInc; | 
 | 835 |         } while (--frameCount); | 
 | 836 |         t->prevAuxLevel = va; | 
 | 837 |     } else { | 
 | 838 |         do { | 
 | 839 |             *out++ += (vl >> 16) * (*temp++ >> 12); | 
 | 840 |             *out++ += (vr >> 16) * (*temp++ >> 12); | 
 | 841 |             vl += vlInc; | 
 | 842 |             vr += vrInc; | 
 | 843 |         } while (--frameCount); | 
 | 844 |     } | 
 | 845 |     t->prevVolume[0] = vl; | 
 | 846 |     t->prevVolume[1] = vr; | 
| Glenn Kasten | a111792 | 2012-01-26 10:53:32 -0800 | [diff] [blame] | 847 |     t->adjustVolumeRamp(aux != NULL); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 848 | } | 
 | 849 |  | 
| Glenn Kasten | 85ab62c | 2012-11-01 11:11:38 -0700 | [diff] [blame] | 850 | void AudioMixer::volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, | 
 | 851 |         int32_t* aux) | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 852 | { | 
 | 853 |     const int16_t vl = t->volume[0]; | 
 | 854 |     const int16_t vr = t->volume[1]; | 
 | 855 |  | 
| Glenn Kasten | f6b1678 | 2011-12-15 09:51:17 -0800 | [diff] [blame] | 856 |     if (CC_UNLIKELY(aux != NULL)) { | 
| Glenn Kasten | 3b81aca | 2012-01-27 15:26:23 -0800 | [diff] [blame] | 857 |         const int16_t va = t->auxLevel; | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 858 |         do { | 
 | 859 |             int16_t l = (int16_t)(*temp++ >> 12); | 
 | 860 |             int16_t r = (int16_t)(*temp++ >> 12); | 
 | 861 |             out[0] = mulAdd(l, vl, out[0]); | 
 | 862 |             int16_t a = (int16_t)(((int32_t)l + r) >> 1); | 
 | 863 |             out[1] = mulAdd(r, vr, out[1]); | 
 | 864 |             out += 2; | 
 | 865 |             aux[0] = mulAdd(a, va, aux[0]); | 
 | 866 |             aux++; | 
 | 867 |         } while (--frameCount); | 
 | 868 |     } else { | 
 | 869 |         do { | 
 | 870 |             int16_t l = (int16_t)(*temp++ >> 12); | 
 | 871 |             int16_t r = (int16_t)(*temp++ >> 12); | 
 | 872 |             out[0] = mulAdd(l, vl, out[0]); | 
 | 873 |             out[1] = mulAdd(r, vr, out[1]); | 
 | 874 |             out += 2; | 
 | 875 |         } while (--frameCount); | 
 | 876 |     } | 
 | 877 | } | 
 | 878 |  | 
| Glenn Kasten | 85ab62c | 2012-11-01 11:11:38 -0700 | [diff] [blame] | 879 | void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, | 
 | 880 |         int32_t* aux) | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 881 | { | 
| Glenn Kasten | 54c3b66 | 2012-01-06 07:46:30 -0800 | [diff] [blame] | 882 |     const int16_t *in = static_cast<const int16_t *>(t->in); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 883 |  | 
| Glenn Kasten | f6b1678 | 2011-12-15 09:51:17 -0800 | [diff] [blame] | 884 |     if (CC_UNLIKELY(aux != NULL)) { | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 885 |         int32_t l; | 
 | 886 |         int32_t r; | 
 | 887 |         // ramp gain | 
| Glenn Kasten | f6b1678 | 2011-12-15 09:51:17 -0800 | [diff] [blame] | 888 |         if (CC_UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc)) { | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 889 |             int32_t vl = t->prevVolume[0]; | 
 | 890 |             int32_t vr = t->prevVolume[1]; | 
 | 891 |             int32_t va = t->prevAuxLevel; | 
 | 892 |             const int32_t vlInc = t->volumeInc[0]; | 
 | 893 |             const int32_t vrInc = t->volumeInc[1]; | 
 | 894 |             const int32_t vaInc = t->auxInc; | 
| Steve Block | b8a8052 | 2011-12-20 16:23:08 +0000 | [diff] [blame] | 895 |             // ALOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d", | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 896 |             //        t, vlInc/65536.0f, vl/65536.0f, t->volume[0], | 
 | 897 |             //        (vl + vlInc*frameCount)/65536.0f, frameCount); | 
 | 898 |  | 
 | 899 |             do { | 
 | 900 |                 l = (int32_t)*in++; | 
 | 901 |                 r = (int32_t)*in++; | 
 | 902 |                 *out++ += (vl >> 16) * l; | 
 | 903 |                 *out++ += (vr >> 16) * r; | 
 | 904 |                 *aux++ += (va >> 17) * (l + r); | 
 | 905 |                 vl += vlInc; | 
 | 906 |                 vr += vrInc; | 
 | 907 |                 va += vaInc; | 
 | 908 |             } while (--frameCount); | 
 | 909 |  | 
 | 910 |             t->prevVolume[0] = vl; | 
 | 911 |             t->prevVolume[1] = vr; | 
 | 912 |             t->prevAuxLevel = va; | 
 | 913 |             t->adjustVolumeRamp(true); | 
 | 914 |         } | 
 | 915 |  | 
 | 916 |         // constant gain | 
 | 917 |         else { | 
 | 918 |             const uint32_t vrl = t->volumeRL; | 
 | 919 |             const int16_t va = (int16_t)t->auxLevel; | 
 | 920 |             do { | 
| Glenn Kasten | 54c3b66 | 2012-01-06 07:46:30 -0800 | [diff] [blame] | 921 |                 uint32_t rl = *reinterpret_cast<const uint32_t *>(in); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 922 |                 int16_t a = (int16_t)(((int32_t)in[0] + in[1]) >> 1); | 
 | 923 |                 in += 2; | 
 | 924 |                 out[0] = mulAddRL(1, rl, vrl, out[0]); | 
 | 925 |                 out[1] = mulAddRL(0, rl, vrl, out[1]); | 
 | 926 |                 out += 2; | 
 | 927 |                 aux[0] = mulAdd(a, va, aux[0]); | 
 | 928 |                 aux++; | 
 | 929 |             } while (--frameCount); | 
 | 930 |         } | 
 | 931 |     } else { | 
 | 932 |         // ramp gain | 
| Glenn Kasten | f6b1678 | 2011-12-15 09:51:17 -0800 | [diff] [blame] | 933 |         if (CC_UNLIKELY(t->volumeInc[0]|t->volumeInc[1])) { | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 934 |             int32_t vl = t->prevVolume[0]; | 
 | 935 |             int32_t vr = t->prevVolume[1]; | 
 | 936 |             const int32_t vlInc = t->volumeInc[0]; | 
 | 937 |             const int32_t vrInc = t->volumeInc[1]; | 
 | 938 |  | 
| Steve Block | b8a8052 | 2011-12-20 16:23:08 +0000 | [diff] [blame] | 939 |             // ALOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d", | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 940 |             //        t, vlInc/65536.0f, vl/65536.0f, t->volume[0], | 
 | 941 |             //        (vl + vlInc*frameCount)/65536.0f, frameCount); | 
 | 942 |  | 
 | 943 |             do { | 
 | 944 |                 *out++ += (vl >> 16) * (int32_t) *in++; | 
 | 945 |                 *out++ += (vr >> 16) * (int32_t) *in++; | 
 | 946 |                 vl += vlInc; | 
 | 947 |                 vr += vrInc; | 
 | 948 |             } while (--frameCount); | 
 | 949 |  | 
 | 950 |             t->prevVolume[0] = vl; | 
 | 951 |             t->prevVolume[1] = vr; | 
 | 952 |             t->adjustVolumeRamp(false); | 
 | 953 |         } | 
 | 954 |  | 
 | 955 |         // constant gain | 
 | 956 |         else { | 
 | 957 |             const uint32_t vrl = t->volumeRL; | 
 | 958 |             do { | 
| Glenn Kasten | 54c3b66 | 2012-01-06 07:46:30 -0800 | [diff] [blame] | 959 |                 uint32_t rl = *reinterpret_cast<const uint32_t *>(in); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 960 |                 in += 2; | 
 | 961 |                 out[0] = mulAddRL(1, rl, vrl, out[0]); | 
 | 962 |                 out[1] = mulAddRL(0, rl, vrl, out[1]); | 
 | 963 |                 out += 2; | 
 | 964 |             } while (--frameCount); | 
 | 965 |         } | 
 | 966 |     } | 
 | 967 |     t->in = in; | 
 | 968 | } | 
 | 969 |  | 
| Glenn Kasten | 85ab62c | 2012-11-01 11:11:38 -0700 | [diff] [blame] | 970 | void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, | 
 | 971 |         int32_t* aux) | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 972 | { | 
| Glenn Kasten | 54c3b66 | 2012-01-06 07:46:30 -0800 | [diff] [blame] | 973 |     const int16_t *in = static_cast<int16_t const *>(t->in); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 974 |  | 
| Glenn Kasten | f6b1678 | 2011-12-15 09:51:17 -0800 | [diff] [blame] | 975 |     if (CC_UNLIKELY(aux != NULL)) { | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 976 |         // ramp gain | 
| Glenn Kasten | f6b1678 | 2011-12-15 09:51:17 -0800 | [diff] [blame] | 977 |         if (CC_UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc)) { | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 978 |             int32_t vl = t->prevVolume[0]; | 
 | 979 |             int32_t vr = t->prevVolume[1]; | 
 | 980 |             int32_t va = t->prevAuxLevel; | 
 | 981 |             const int32_t vlInc = t->volumeInc[0]; | 
 | 982 |             const int32_t vrInc = t->volumeInc[1]; | 
 | 983 |             const int32_t vaInc = t->auxInc; | 
 | 984 |  | 
| Steve Block | b8a8052 | 2011-12-20 16:23:08 +0000 | [diff] [blame] | 985 |             // ALOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d", | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 986 |             //         t, vlInc/65536.0f, vl/65536.0f, t->volume[0], | 
 | 987 |             //         (vl + vlInc*frameCount)/65536.0f, frameCount); | 
 | 988 |  | 
 | 989 |             do { | 
 | 990 |                 int32_t l = *in++; | 
 | 991 |                 *out++ += (vl >> 16) * l; | 
 | 992 |                 *out++ += (vr >> 16) * l; | 
 | 993 |                 *aux++ += (va >> 16) * l; | 
 | 994 |                 vl += vlInc; | 
 | 995 |                 vr += vrInc; | 
 | 996 |                 va += vaInc; | 
 | 997 |             } while (--frameCount); | 
 | 998 |  | 
 | 999 |             t->prevVolume[0] = vl; | 
 | 1000 |             t->prevVolume[1] = vr; | 
 | 1001 |             t->prevAuxLevel = va; | 
 | 1002 |             t->adjustVolumeRamp(true); | 
 | 1003 |         } | 
 | 1004 |         // constant gain | 
 | 1005 |         else { | 
 | 1006 |             const int16_t vl = t->volume[0]; | 
 | 1007 |             const int16_t vr = t->volume[1]; | 
 | 1008 |             const int16_t va = (int16_t)t->auxLevel; | 
 | 1009 |             do { | 
 | 1010 |                 int16_t l = *in++; | 
 | 1011 |                 out[0] = mulAdd(l, vl, out[0]); | 
 | 1012 |                 out[1] = mulAdd(l, vr, out[1]); | 
 | 1013 |                 out += 2; | 
 | 1014 |                 aux[0] = mulAdd(l, va, aux[0]); | 
 | 1015 |                 aux++; | 
 | 1016 |             } while (--frameCount); | 
 | 1017 |         } | 
 | 1018 |     } else { | 
 | 1019 |         // ramp gain | 
| Glenn Kasten | f6b1678 | 2011-12-15 09:51:17 -0800 | [diff] [blame] | 1020 |         if (CC_UNLIKELY(t->volumeInc[0]|t->volumeInc[1])) { | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1021 |             int32_t vl = t->prevVolume[0]; | 
 | 1022 |             int32_t vr = t->prevVolume[1]; | 
 | 1023 |             const int32_t vlInc = t->volumeInc[0]; | 
 | 1024 |             const int32_t vrInc = t->volumeInc[1]; | 
 | 1025 |  | 
| Steve Block | b8a8052 | 2011-12-20 16:23:08 +0000 | [diff] [blame] | 1026 |             // ALOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d", | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1027 |             //         t, vlInc/65536.0f, vl/65536.0f, t->volume[0], | 
 | 1028 |             //         (vl + vlInc*frameCount)/65536.0f, frameCount); | 
 | 1029 |  | 
 | 1030 |             do { | 
 | 1031 |                 int32_t l = *in++; | 
 | 1032 |                 *out++ += (vl >> 16) * l; | 
 | 1033 |                 *out++ += (vr >> 16) * l; | 
 | 1034 |                 vl += vlInc; | 
 | 1035 |                 vr += vrInc; | 
 | 1036 |             } while (--frameCount); | 
 | 1037 |  | 
 | 1038 |             t->prevVolume[0] = vl; | 
 | 1039 |             t->prevVolume[1] = vr; | 
 | 1040 |             t->adjustVolumeRamp(false); | 
 | 1041 |         } | 
 | 1042 |         // constant gain | 
 | 1043 |         else { | 
 | 1044 |             const int16_t vl = t->volume[0]; | 
 | 1045 |             const int16_t vr = t->volume[1]; | 
 | 1046 |             do { | 
 | 1047 |                 int16_t l = *in++; | 
 | 1048 |                 out[0] = mulAdd(l, vl, out[0]); | 
 | 1049 |                 out[1] = mulAdd(l, vr, out[1]); | 
 | 1050 |                 out += 2; | 
 | 1051 |             } while (--frameCount); | 
 | 1052 |         } | 
 | 1053 |     } | 
 | 1054 |     t->in = in; | 
 | 1055 | } | 
 | 1056 |  | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1057 | // no-op case | 
| John Grossman | 4ff14ba | 2012-02-08 16:37:41 -0800 | [diff] [blame] | 1058 | void AudioMixer::process__nop(state_t* state, int64_t pts) | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1059 | { | 
 | 1060 |     uint32_t e0 = state->enabledTracks; | 
 | 1061 |     size_t bufSize = state->frameCount * sizeof(int16_t) * MAX_NUM_CHANNELS; | 
 | 1062 |     while (e0) { | 
 | 1063 |         // process by group of tracks with same output buffer to | 
 | 1064 |         // avoid multiple memset() on same buffer | 
 | 1065 |         uint32_t e1 = e0, e2 = e0; | 
 | 1066 |         int i = 31 - __builtin_clz(e1); | 
| Glenn Kasten | fc900c9 | 2013-02-18 12:47:49 -0800 | [diff] [blame] | 1067 |         { | 
 | 1068 |             track_t& t1 = state->tracks[i]; | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1069 |             e2 &= ~(1<<i); | 
| Glenn Kasten | fc900c9 | 2013-02-18 12:47:49 -0800 | [diff] [blame] | 1070 |             while (e2) { | 
 | 1071 |                 i = 31 - __builtin_clz(e2); | 
 | 1072 |                 e2 &= ~(1<<i); | 
 | 1073 |                 track_t& t2 = state->tracks[i]; | 
 | 1074 |                 if (CC_UNLIKELY(t2.mainBuffer != t1.mainBuffer)) { | 
 | 1075 |                     e1 &= ~(1<<i); | 
 | 1076 |                 } | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1077 |             } | 
| Glenn Kasten | fc900c9 | 2013-02-18 12:47:49 -0800 | [diff] [blame] | 1078 |             e0 &= ~(e1); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1079 |  | 
| Glenn Kasten | fc900c9 | 2013-02-18 12:47:49 -0800 | [diff] [blame] | 1080 |             memset(t1.mainBuffer, 0, bufSize); | 
 | 1081 |         } | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1082 |  | 
 | 1083 |         while (e1) { | 
 | 1084 |             i = 31 - __builtin_clz(e1); | 
 | 1085 |             e1 &= ~(1<<i); | 
| Glenn Kasten | fc900c9 | 2013-02-18 12:47:49 -0800 | [diff] [blame] | 1086 |             { | 
 | 1087 |                 track_t& t3 = state->tracks[i]; | 
 | 1088 |                 size_t outFrames = state->frameCount; | 
 | 1089 |                 while (outFrames) { | 
 | 1090 |                     t3.buffer.frameCount = outFrames; | 
 | 1091 |                     int64_t outputPTS = calculateOutputPTS( | 
 | 1092 |                         t3, pts, state->frameCount - outFrames); | 
 | 1093 |                     t3.bufferProvider->getNextBuffer(&t3.buffer, outputPTS); | 
 | 1094 |                     if (t3.buffer.raw == NULL) break; | 
 | 1095 |                     outFrames -= t3.buffer.frameCount; | 
 | 1096 |                     t3.bufferProvider->releaseBuffer(&t3.buffer); | 
 | 1097 |                 } | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1098 |             } | 
 | 1099 |         } | 
 | 1100 |     } | 
 | 1101 | } | 
 | 1102 |  | 
 | 1103 | // generic code without resampling | 
| John Grossman | 4ff14ba | 2012-02-08 16:37:41 -0800 | [diff] [blame] | 1104 | void AudioMixer::process__genericNoResampling(state_t* state, int64_t pts) | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1105 | { | 
 | 1106 |     int32_t outTemp[BLOCKSIZE * MAX_NUM_CHANNELS] __attribute__((aligned(32))); | 
 | 1107 |  | 
 | 1108 |     // acquire each track's buffer | 
 | 1109 |     uint32_t enabledTracks = state->enabledTracks; | 
 | 1110 |     uint32_t e0 = enabledTracks; | 
 | 1111 |     while (e0) { | 
 | 1112 |         const int i = 31 - __builtin_clz(e0); | 
 | 1113 |         e0 &= ~(1<<i); | 
 | 1114 |         track_t& t = state->tracks[i]; | 
 | 1115 |         t.buffer.frameCount = state->frameCount; | 
| John Grossman | 4ff14ba | 2012-02-08 16:37:41 -0800 | [diff] [blame] | 1116 |         t.bufferProvider->getNextBuffer(&t.buffer, pts); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1117 |         t.frameCount = t.buffer.frameCount; | 
 | 1118 |         t.in = t.buffer.raw; | 
 | 1119 |         // t.in == NULL can happen if the track was flushed just after having | 
 | 1120 |         // been enabled for mixing. | 
 | 1121 |         if (t.in == NULL) | 
 | 1122 |             enabledTracks &= ~(1<<i); | 
 | 1123 |     } | 
 | 1124 |  | 
 | 1125 |     e0 = enabledTracks; | 
 | 1126 |     while (e0) { | 
 | 1127 |         // process by group of tracks with same output buffer to | 
 | 1128 |         // optimize cache use | 
 | 1129 |         uint32_t e1 = e0, e2 = e0; | 
 | 1130 |         int j = 31 - __builtin_clz(e1); | 
 | 1131 |         track_t& t1 = state->tracks[j]; | 
 | 1132 |         e2 &= ~(1<<j); | 
 | 1133 |         while (e2) { | 
 | 1134 |             j = 31 - __builtin_clz(e2); | 
 | 1135 |             e2 &= ~(1<<j); | 
 | 1136 |             track_t& t2 = state->tracks[j]; | 
| Glenn Kasten | f6b1678 | 2011-12-15 09:51:17 -0800 | [diff] [blame] | 1137 |             if (CC_UNLIKELY(t2.mainBuffer != t1.mainBuffer)) { | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1138 |                 e1 &= ~(1<<j); | 
 | 1139 |             } | 
 | 1140 |         } | 
 | 1141 |         e0 &= ~(e1); | 
 | 1142 |         // this assumes output 16 bits stereo, no resampling | 
 | 1143 |         int32_t *out = t1.mainBuffer; | 
 | 1144 |         size_t numFrames = 0; | 
 | 1145 |         do { | 
 | 1146 |             memset(outTemp, 0, sizeof(outTemp)); | 
 | 1147 |             e2 = e1; | 
 | 1148 |             while (e2) { | 
 | 1149 |                 const int i = 31 - __builtin_clz(e2); | 
 | 1150 |                 e2 &= ~(1<<i); | 
 | 1151 |                 track_t& t = state->tracks[i]; | 
 | 1152 |                 size_t outFrames = BLOCKSIZE; | 
 | 1153 |                 int32_t *aux = NULL; | 
| Glenn Kasten | f6b1678 | 2011-12-15 09:51:17 -0800 | [diff] [blame] | 1154 |                 if (CC_UNLIKELY((t.needs & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED)) { | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1155 |                     aux = t.auxBuffer + numFrames; | 
 | 1156 |                 } | 
 | 1157 |                 while (outFrames) { | 
 | 1158 |                     size_t inFrames = (t.frameCount > outFrames)?outFrames:t.frameCount; | 
 | 1159 |                     if (inFrames) { | 
| Glenn Kasten | 85ab62c | 2012-11-01 11:11:38 -0700 | [diff] [blame] | 1160 |                         t.hook(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, | 
 | 1161 |                                 state->resampleTemp, aux); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1162 |                         t.frameCount -= inFrames; | 
 | 1163 |                         outFrames -= inFrames; | 
| Glenn Kasten | f6b1678 | 2011-12-15 09:51:17 -0800 | [diff] [blame] | 1164 |                         if (CC_UNLIKELY(aux != NULL)) { | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1165 |                             aux += inFrames; | 
 | 1166 |                         } | 
 | 1167 |                     } | 
 | 1168 |                     if (t.frameCount == 0 && outFrames) { | 
 | 1169 |                         t.bufferProvider->releaseBuffer(&t.buffer); | 
| Glenn Kasten | 85ab62c | 2012-11-01 11:11:38 -0700 | [diff] [blame] | 1170 |                         t.buffer.frameCount = (state->frameCount - numFrames) - | 
 | 1171 |                                 (BLOCKSIZE - outFrames); | 
| John Grossman | 4ff14ba | 2012-02-08 16:37:41 -0800 | [diff] [blame] | 1172 |                         int64_t outputPTS = calculateOutputPTS( | 
 | 1173 |                             t, pts, numFrames + (BLOCKSIZE - outFrames)); | 
 | 1174 |                         t.bufferProvider->getNextBuffer(&t.buffer, outputPTS); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1175 |                         t.in = t.buffer.raw; | 
 | 1176 |                         if (t.in == NULL) { | 
 | 1177 |                             enabledTracks &= ~(1<<i); | 
 | 1178 |                             e1 &= ~(1<<i); | 
 | 1179 |                             break; | 
 | 1180 |                         } | 
 | 1181 |                         t.frameCount = t.buffer.frameCount; | 
 | 1182 |                     } | 
 | 1183 |                 } | 
 | 1184 |             } | 
 | 1185 |             ditherAndClamp(out, outTemp, BLOCKSIZE); | 
 | 1186 |             out += BLOCKSIZE; | 
 | 1187 |             numFrames += BLOCKSIZE; | 
 | 1188 |         } while (numFrames < state->frameCount); | 
 | 1189 |     } | 
 | 1190 |  | 
 | 1191 |     // release each track's buffer | 
 | 1192 |     e0 = enabledTracks; | 
 | 1193 |     while (e0) { | 
 | 1194 |         const int i = 31 - __builtin_clz(e0); | 
 | 1195 |         e0 &= ~(1<<i); | 
 | 1196 |         track_t& t = state->tracks[i]; | 
 | 1197 |         t.bufferProvider->releaseBuffer(&t.buffer); | 
 | 1198 |     } | 
 | 1199 | } | 
 | 1200 |  | 
 | 1201 |  | 
| Glenn Kasten | c5ac4cb | 2011-12-12 09:05:55 -0800 | [diff] [blame] | 1202 | // generic code with resampling | 
| John Grossman | 4ff14ba | 2012-02-08 16:37:41 -0800 | [diff] [blame] | 1203 | void AudioMixer::process__genericResampling(state_t* state, int64_t pts) | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1204 | { | 
| Glenn Kasten | 54c3b66 | 2012-01-06 07:46:30 -0800 | [diff] [blame] | 1205 |     // this const just means that local variable outTemp doesn't change | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1206 |     int32_t* const outTemp = state->outputTemp; | 
 | 1207 |     const size_t size = sizeof(int32_t) * MAX_NUM_CHANNELS * state->frameCount; | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1208 |  | 
 | 1209 |     size_t numFrames = state->frameCount; | 
 | 1210 |  | 
 | 1211 |     uint32_t e0 = state->enabledTracks; | 
 | 1212 |     while (e0) { | 
 | 1213 |         // process by group of tracks with same output buffer | 
 | 1214 |         // to optimize cache use | 
 | 1215 |         uint32_t e1 = e0, e2 = e0; | 
 | 1216 |         int j = 31 - __builtin_clz(e1); | 
 | 1217 |         track_t& t1 = state->tracks[j]; | 
 | 1218 |         e2 &= ~(1<<j); | 
 | 1219 |         while (e2) { | 
 | 1220 |             j = 31 - __builtin_clz(e2); | 
 | 1221 |             e2 &= ~(1<<j); | 
 | 1222 |             track_t& t2 = state->tracks[j]; | 
| Glenn Kasten | f6b1678 | 2011-12-15 09:51:17 -0800 | [diff] [blame] | 1223 |             if (CC_UNLIKELY(t2.mainBuffer != t1.mainBuffer)) { | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1224 |                 e1 &= ~(1<<j); | 
 | 1225 |             } | 
 | 1226 |         } | 
 | 1227 |         e0 &= ~(e1); | 
 | 1228 |         int32_t *out = t1.mainBuffer; | 
| Yuuhi Yamaguchi | 2151d7b | 2011-02-04 15:24:34 +0100 | [diff] [blame] | 1229 |         memset(outTemp, 0, size); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1230 |         while (e1) { | 
 | 1231 |             const int i = 31 - __builtin_clz(e1); | 
 | 1232 |             e1 &= ~(1<<i); | 
 | 1233 |             track_t& t = state->tracks[i]; | 
 | 1234 |             int32_t *aux = NULL; | 
| Glenn Kasten | f6b1678 | 2011-12-15 09:51:17 -0800 | [diff] [blame] | 1235 |             if (CC_UNLIKELY((t.needs & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED)) { | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1236 |                 aux = t.auxBuffer; | 
 | 1237 |             } | 
 | 1238 |  | 
 | 1239 |             // this is a little goofy, on the resampling case we don't | 
 | 1240 |             // acquire/release the buffers because it's done by | 
 | 1241 |             // the resampler. | 
 | 1242 |             if ((t.needs & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) { | 
| John Grossman | 4ff14ba | 2012-02-08 16:37:41 -0800 | [diff] [blame] | 1243 |                 t.resampler->setPTS(pts); | 
| Glenn Kasten | a111792 | 2012-01-26 10:53:32 -0800 | [diff] [blame] | 1244 |                 t.hook(&t, outTemp, numFrames, state->resampleTemp, aux); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1245 |             } else { | 
 | 1246 |  | 
 | 1247 |                 size_t outFrames = 0; | 
 | 1248 |  | 
 | 1249 |                 while (outFrames < numFrames) { | 
 | 1250 |                     t.buffer.frameCount = numFrames - outFrames; | 
| John Grossman | 4ff14ba | 2012-02-08 16:37:41 -0800 | [diff] [blame] | 1251 |                     int64_t outputPTS = calculateOutputPTS(t, pts, outFrames); | 
 | 1252 |                     t.bufferProvider->getNextBuffer(&t.buffer, outputPTS); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1253 |                     t.in = t.buffer.raw; | 
 | 1254 |                     // t.in == NULL can happen if the track was flushed just after having | 
 | 1255 |                     // been enabled for mixing. | 
 | 1256 |                     if (t.in == NULL) break; | 
 | 1257 |  | 
| Glenn Kasten | f6b1678 | 2011-12-15 09:51:17 -0800 | [diff] [blame] | 1258 |                     if (CC_UNLIKELY(aux != NULL)) { | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1259 |                         aux += outFrames; | 
 | 1260 |                     } | 
| Glenn Kasten | 85ab62c | 2012-11-01 11:11:38 -0700 | [diff] [blame] | 1261 |                     t.hook(&t, outTemp + outFrames*MAX_NUM_CHANNELS, t.buffer.frameCount, | 
 | 1262 |                             state->resampleTemp, aux); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1263 |                     outFrames += t.buffer.frameCount; | 
 | 1264 |                     t.bufferProvider->releaseBuffer(&t.buffer); | 
 | 1265 |                 } | 
 | 1266 |             } | 
 | 1267 |         } | 
 | 1268 |         ditherAndClamp(out, outTemp, numFrames); | 
 | 1269 |     } | 
 | 1270 | } | 
 | 1271 |  | 
 | 1272 | // one track, 16 bits stereo without resampling is the most common case | 
| John Grossman | 4ff14ba | 2012-02-08 16:37:41 -0800 | [diff] [blame] | 1273 | void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state, | 
 | 1274 |                                                            int64_t pts) | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1275 | { | 
| Glenn Kasten | 99e53b8 | 2012-01-19 08:59:58 -0800 | [diff] [blame] | 1276 |     // This method is only called when state->enabledTracks has exactly | 
 | 1277 |     // one bit set.  The asserts below would verify this, but are commented out | 
 | 1278 |     // since the whole point of this method is to optimize performance. | 
| Glenn Kasten | 5798d4e | 2012-03-08 12:18:35 -0800 | [diff] [blame] | 1279 |     //ALOG_ASSERT(0 != state->enabledTracks, "no tracks enabled"); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1280 |     const int i = 31 - __builtin_clz(state->enabledTracks); | 
| Glenn Kasten | 5798d4e | 2012-03-08 12:18:35 -0800 | [diff] [blame] | 1281 |     //ALOG_ASSERT((1 << i) == state->enabledTracks, "more than 1 track enabled"); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1282 |     const track_t& t = state->tracks[i]; | 
 | 1283 |  | 
 | 1284 |     AudioBufferProvider::Buffer& b(t.buffer); | 
 | 1285 |  | 
 | 1286 |     int32_t* out = t.mainBuffer; | 
 | 1287 |     size_t numFrames = state->frameCount; | 
 | 1288 |  | 
 | 1289 |     const int16_t vl = t.volume[0]; | 
 | 1290 |     const int16_t vr = t.volume[1]; | 
 | 1291 |     const uint32_t vrl = t.volumeRL; | 
 | 1292 |     while (numFrames) { | 
 | 1293 |         b.frameCount = numFrames; | 
| John Grossman | 4ff14ba | 2012-02-08 16:37:41 -0800 | [diff] [blame] | 1294 |         int64_t outputPTS = calculateOutputPTS(t, pts, out - t.mainBuffer); | 
 | 1295 |         t.bufferProvider->getNextBuffer(&b, outputPTS); | 
| Glenn Kasten | 54c3b66 | 2012-01-06 07:46:30 -0800 | [diff] [blame] | 1296 |         const int16_t *in = b.i16; | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1297 |  | 
 | 1298 |         // in == NULL can happen if the track was flushed just after having | 
 | 1299 |         // been enabled for mixing. | 
 | 1300 |         if (in == NULL || ((unsigned long)in & 3)) { | 
 | 1301 |             memset(out, 0, numFrames*MAX_NUM_CHANNELS*sizeof(int16_t)); | 
| Glenn Kasten | 85ab62c | 2012-11-01 11:11:38 -0700 | [diff] [blame] | 1302 |             ALOGE_IF(((unsigned long)in & 3), "process stereo track: input buffer alignment pb: " | 
 | 1303 |                                               "buffer %p track %d, channels %d, needs %08x", | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1304 |                     in, i, t.channelCount, t.needs); | 
 | 1305 |             return; | 
 | 1306 |         } | 
 | 1307 |         size_t outFrames = b.frameCount; | 
 | 1308 |  | 
| Glenn Kasten | f6b1678 | 2011-12-15 09:51:17 -0800 | [diff] [blame] | 1309 |         if (CC_UNLIKELY(uint32_t(vl) > UNITY_GAIN || uint32_t(vr) > UNITY_GAIN)) { | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1310 |             // volume is boosted, so we might need to clamp even though | 
 | 1311 |             // we process only one track. | 
 | 1312 |             do { | 
| Glenn Kasten | 54c3b66 | 2012-01-06 07:46:30 -0800 | [diff] [blame] | 1313 |                 uint32_t rl = *reinterpret_cast<const uint32_t *>(in); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1314 |                 in += 2; | 
 | 1315 |                 int32_t l = mulRL(1, rl, vrl) >> 12; | 
 | 1316 |                 int32_t r = mulRL(0, rl, vrl) >> 12; | 
 | 1317 |                 // clamping... | 
 | 1318 |                 l = clamp16(l); | 
 | 1319 |                 r = clamp16(r); | 
 | 1320 |                 *out++ = (r<<16) | (l & 0xFFFF); | 
 | 1321 |             } while (--outFrames); | 
 | 1322 |         } else { | 
 | 1323 |             do { | 
| Glenn Kasten | 54c3b66 | 2012-01-06 07:46:30 -0800 | [diff] [blame] | 1324 |                 uint32_t rl = *reinterpret_cast<const uint32_t *>(in); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1325 |                 in += 2; | 
 | 1326 |                 int32_t l = mulRL(1, rl, vrl) >> 12; | 
 | 1327 |                 int32_t r = mulRL(0, rl, vrl) >> 12; | 
 | 1328 |                 *out++ = (r<<16) | (l & 0xFFFF); | 
 | 1329 |             } while (--outFrames); | 
 | 1330 |         } | 
 | 1331 |         numFrames -= b.frameCount; | 
 | 1332 |         t.bufferProvider->releaseBuffer(&b); | 
 | 1333 |     } | 
 | 1334 | } | 
 | 1335 |  | 
| Glenn Kasten | 81a028f | 2011-12-15 09:53:12 -0800 | [diff] [blame] | 1336 | #if 0 | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1337 | // 2 tracks is also a common case | 
 | 1338 | // NEVER used in current implementation of process__validate() | 
 | 1339 | // only use if the 2 tracks have the same output buffer | 
| John Grossman | 4ff14ba | 2012-02-08 16:37:41 -0800 | [diff] [blame] | 1340 | void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state, | 
 | 1341 |                                                             int64_t pts) | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1342 | { | 
 | 1343 |     int i; | 
 | 1344 |     uint32_t en = state->enabledTracks; | 
 | 1345 |  | 
 | 1346 |     i = 31 - __builtin_clz(en); | 
 | 1347 |     const track_t& t0 = state->tracks[i]; | 
 | 1348 |     AudioBufferProvider::Buffer& b0(t0.buffer); | 
 | 1349 |  | 
 | 1350 |     en &= ~(1<<i); | 
 | 1351 |     i = 31 - __builtin_clz(en); | 
 | 1352 |     const track_t& t1 = state->tracks[i]; | 
 | 1353 |     AudioBufferProvider::Buffer& b1(t1.buffer); | 
 | 1354 |  | 
| Glenn Kasten | 54c3b66 | 2012-01-06 07:46:30 -0800 | [diff] [blame] | 1355 |     const int16_t *in0; | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1356 |     const int16_t vl0 = t0.volume[0]; | 
 | 1357 |     const int16_t vr0 = t0.volume[1]; | 
 | 1358 |     size_t frameCount0 = 0; | 
 | 1359 |  | 
| Glenn Kasten | 54c3b66 | 2012-01-06 07:46:30 -0800 | [diff] [blame] | 1360 |     const int16_t *in1; | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1361 |     const int16_t vl1 = t1.volume[0]; | 
 | 1362 |     const int16_t vr1 = t1.volume[1]; | 
 | 1363 |     size_t frameCount1 = 0; | 
 | 1364 |  | 
 | 1365 |     //FIXME: only works if two tracks use same buffer | 
 | 1366 |     int32_t* out = t0.mainBuffer; | 
 | 1367 |     size_t numFrames = state->frameCount; | 
| Glenn Kasten | 54c3b66 | 2012-01-06 07:46:30 -0800 | [diff] [blame] | 1368 |     const int16_t *buff = NULL; | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1369 |  | 
 | 1370 |  | 
 | 1371 |     while (numFrames) { | 
 | 1372 |  | 
 | 1373 |         if (frameCount0 == 0) { | 
 | 1374 |             b0.frameCount = numFrames; | 
| John Grossman | 4ff14ba | 2012-02-08 16:37:41 -0800 | [diff] [blame] | 1375 |             int64_t outputPTS = calculateOutputPTS(t0, pts, | 
 | 1376 |                                                    out - t0.mainBuffer); | 
 | 1377 |             t0.bufferProvider->getNextBuffer(&b0, outputPTS); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1378 |             if (b0.i16 == NULL) { | 
 | 1379 |                 if (buff == NULL) { | 
 | 1380 |                     buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount]; | 
 | 1381 |                 } | 
 | 1382 |                 in0 = buff; | 
 | 1383 |                 b0.frameCount = numFrames; | 
 | 1384 |             } else { | 
 | 1385 |                 in0 = b0.i16; | 
 | 1386 |             } | 
 | 1387 |             frameCount0 = b0.frameCount; | 
 | 1388 |         } | 
 | 1389 |         if (frameCount1 == 0) { | 
 | 1390 |             b1.frameCount = numFrames; | 
| John Grossman | 4ff14ba | 2012-02-08 16:37:41 -0800 | [diff] [blame] | 1391 |             int64_t outputPTS = calculateOutputPTS(t1, pts, | 
 | 1392 |                                                    out - t0.mainBuffer); | 
 | 1393 |             t1.bufferProvider->getNextBuffer(&b1, outputPTS); | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1394 |             if (b1.i16 == NULL) { | 
 | 1395 |                 if (buff == NULL) { | 
 | 1396 |                     buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount]; | 
 | 1397 |                 } | 
 | 1398 |                 in1 = buff; | 
 | 1399 |                 b1.frameCount = numFrames; | 
| Glenn Kasten | c5ac4cb | 2011-12-12 09:05:55 -0800 | [diff] [blame] | 1400 |             } else { | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1401 |                 in1 = b1.i16; | 
 | 1402 |             } | 
 | 1403 |             frameCount1 = b1.frameCount; | 
 | 1404 |         } | 
 | 1405 |  | 
 | 1406 |         size_t outFrames = frameCount0 < frameCount1?frameCount0:frameCount1; | 
 | 1407 |  | 
 | 1408 |         numFrames -= outFrames; | 
 | 1409 |         frameCount0 -= outFrames; | 
 | 1410 |         frameCount1 -= outFrames; | 
 | 1411 |  | 
 | 1412 |         do { | 
 | 1413 |             int32_t l0 = *in0++; | 
 | 1414 |             int32_t r0 = *in0++; | 
 | 1415 |             l0 = mul(l0, vl0); | 
 | 1416 |             r0 = mul(r0, vr0); | 
 | 1417 |             int32_t l = *in1++; | 
 | 1418 |             int32_t r = *in1++; | 
 | 1419 |             l = mulAdd(l, vl1, l0) >> 12; | 
 | 1420 |             r = mulAdd(r, vr1, r0) >> 12; | 
 | 1421 |             // clamping... | 
 | 1422 |             l = clamp16(l); | 
 | 1423 |             r = clamp16(r); | 
 | 1424 |             *out++ = (r<<16) | (l & 0xFFFF); | 
 | 1425 |         } while (--outFrames); | 
 | 1426 |  | 
 | 1427 |         if (frameCount0 == 0) { | 
 | 1428 |             t0.bufferProvider->releaseBuffer(&b0); | 
 | 1429 |         } | 
 | 1430 |         if (frameCount1 == 0) { | 
 | 1431 |             t1.bufferProvider->releaseBuffer(&b1); | 
 | 1432 |         } | 
 | 1433 |     } | 
 | 1434 |  | 
| Glenn Kasten | e9dd017 | 2012-01-27 18:08:45 -0800 | [diff] [blame] | 1435 |     delete [] buff; | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1436 | } | 
| Glenn Kasten | 81a028f | 2011-12-15 09:53:12 -0800 | [diff] [blame] | 1437 | #endif | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1438 |  | 
| John Grossman | 4ff14ba | 2012-02-08 16:37:41 -0800 | [diff] [blame] | 1439 | int64_t AudioMixer::calculateOutputPTS(const track_t& t, int64_t basePTS, | 
 | 1440 |                                        int outputFrameIndex) | 
 | 1441 | { | 
 | 1442 |     if (AudioBufferProvider::kInvalidPTS == basePTS) | 
 | 1443 |         return AudioBufferProvider::kInvalidPTS; | 
 | 1444 |  | 
| Glenn Kasten | 52008f8 | 2012-03-18 09:34:41 -0700 | [diff] [blame] | 1445 |     return basePTS + ((outputFrameIndex * sLocalTimeFreq) / t.sampleRate); | 
 | 1446 | } | 
 | 1447 |  | 
 | 1448 | /*static*/ uint64_t AudioMixer::sLocalTimeFreq; | 
 | 1449 | /*static*/ pthread_once_t AudioMixer::sOnceControl = PTHREAD_ONCE_INIT; | 
 | 1450 |  | 
 | 1451 | /*static*/ void AudioMixer::sInitRoutine() | 
 | 1452 | { | 
 | 1453 |     LocalClock lc; | 
 | 1454 |     sLocalTimeFreq = lc.getLocalFreq(); | 
| John Grossman | 4ff14ba | 2012-02-08 16:37:41 -0800 | [diff] [blame] | 1455 | } | 
 | 1456 |  | 
| Mathias Agopian | 65ab471 | 2010-07-14 17:59:35 -0700 | [diff] [blame] | 1457 | // ---------------------------------------------------------------------------- | 
 | 1458 | }; // namespace android |