diff --git a/media/libaudioclient/include/media/AudioMixer.h b/media/libaudioclient/include/media/AudioMixer.h index d4ce417fc9..2e29316043 100644 --- a/media/libaudioclient/include/media/AudioMixer.h +++ b/media/libaudioclient/include/media/AudioMixer.h @@ -18,8 +18,11 @@ #ifndef ANDROID_AUDIO_MIXER_H #define ANDROID_AUDIO_MIXER_H +#include +#include #include #include +#include #include #include @@ -43,20 +46,14 @@ namespace android { class AudioMixer { public: - AudioMixer(size_t frameCount, uint32_t sampleRate, - uint32_t maxNumTracks = MAX_NUM_TRACKS); - - /*virtual*/ ~AudioMixer(); // non-virtual saves a v-table, restore if sub-classed - - - // This mixer has a hard-coded upper limit of 32 active track inputs. - // Adding support for > 32 tracks would require more than simply changing this value. - static const uint32_t MAX_NUM_TRACKS = 32; - // maximum number of channels supported by the mixer + // This mixer has a hard-coded upper limit of active track inputs; + // the value is arbitrary but should be less than TRACK0 to avoid confusion. + static constexpr int32_t MAX_NUM_TRACKS = 256; + // Do not change these unless underlying code changes. // This mixer has a hard-coded upper limit of 8 channels for output. - static const uint32_t MAX_NUM_CHANNELS = 8; - static const uint32_t MAX_NUM_VOLUMES = 2; // stereo volume only + static constexpr uint32_t MAX_NUM_CHANNELS = FCC_8; + static constexpr uint32_t MAX_NUM_VOLUMES = FCC_2; // stereo volume only // maximum number of channels supported for the content static const uint32_t MAX_NUM_CHANNELS_TO_DOWNMIX = AUDIO_CHANNEL_COUNT_MAX; @@ -108,6 +105,12 @@ public: // parameter 'value' is a pointer to the new playback rate. }; + AudioMixer(size_t frameCount, uint32_t sampleRate, int32_t maxNumTracks = MAX_NUM_TRACKS) + : mMaxNumTracks(maxNumTracks) + , mSampleRate(sampleRate) + , mFrameCount(frameCount) { + pthread_once(&sOnceControl, &sInitRoutine); + } // For all APIs with "name": TRACK0 <= name < TRACK0 + MAX_NUM_TRACKS @@ -127,27 +130,38 @@ public: void setParameter(int name, int target, int param, void *value); void setBufferProvider(int name, AudioBufferProvider* bufferProvider); - void process(); - uint32_t trackNames() const { return mTrackNames; } + void process() { + (this->*mHook)(); + } size_t getUnreleasedFrames(int name) const; - static inline bool isValidPcmTrackFormat(audio_format_t format) { - switch (format) { - case AUDIO_FORMAT_PCM_8_BIT: - case AUDIO_FORMAT_PCM_16_BIT: - case AUDIO_FORMAT_PCM_24_BIT_PACKED: - case AUDIO_FORMAT_PCM_32_BIT: - case AUDIO_FORMAT_PCM_FLOAT: - return true; - default: - return false; + std::string trackNames() const { + std::stringstream ss; + for (const auto &pair : mTracks) { + ss << pair.first << " "; } + return ss.str(); + } + + void setNBLogWriter(NBLog::Writer *logWriter) { + mNBLogWriter = logWriter; } private: + /* For multi-format functions (calls template functions + * in AudioMixerOps.h). The template parameters are as follows: + * + * MIXTYPE (see AudioMixerOps.h MIXTYPE_* enumeration) + * USEFLOATVOL (set to true if float volume is used) + * ADJUSTVOL (set to true if volume ramp parameters needs adjustment afterwards) + * TO: int32_t (Q4.27) or float + * TI: int32_t (Q4.27) or int16_t (Q0.15) or float + * TA: int32_t (Q4.27) + */ + enum { // FIXME this representation permits up to 8 channels NEEDS_CHANNEL_COUNT__MASK = 0x00000007, @@ -164,14 +178,67 @@ private: NEEDS_AUX = 0x00010000, }; - struct state_t; - struct track_t; + // hook types + enum { + PROCESSTYPE_NORESAMPLEONETRACK, // others set elsewhere + }; + + enum { + TRACKTYPE_NOP, + TRACKTYPE_RESAMPLE, + TRACKTYPE_NORESAMPLE, + TRACKTYPE_NORESAMPLEMONO, + }; + + // process hook functionality + using process_hook_t = void(AudioMixer::*)(); + + struct Track; + using hook_t = void(Track::*)(int32_t* output, size_t numOutFrames, int32_t* temp, int32_t* aux); + + struct Track { + Track() + : bufferProvider(nullptr) + { + // TODO: move additional initialization here. + } + + ~Track() + { + // bufferProvider, mInputBufferProvider need not be deleted. + mResampler.reset(nullptr); + // Ensure the order of destruction of buffer providers as they + // release the upstream provider in the destructor. + mTimestretchBufferProvider.reset(nullptr); + mPostDownmixReformatBufferProvider.reset(nullptr); + mDownmixerBufferProvider.reset(nullptr); + mReformatBufferProvider.reset(nullptr); + } + + bool needsRamp() { return (volumeInc[0] | volumeInc[1] | auxInc) != 0; } + bool setResampler(uint32_t trackSampleRate, uint32_t devSampleRate); + bool doesResample() const { return mResampler.get() != nullptr; } + void resetResampler() { if (mResampler.get() != nullptr) mResampler->reset(); } + void adjustVolumeRamp(bool aux, bool useFloat = false); + size_t getUnreleasedFrames() const { return mResampler.get() != nullptr ? + mResampler->getUnreleasedFrames() : 0; }; + + status_t prepareForDownmix(); + void unprepareForDownmix(); + status_t prepareForReformat(); + void unprepareForReformat(); + bool setPlaybackRate(const AudioPlaybackRate &playbackRate); + void reconfigureBufferProviders(); + + static hook_t getTrackHook(int trackType, uint32_t channelCount, + audio_format_t mixerInFormat, audio_format_t mixerOutFormat); + + void track__nop(int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux); - typedef void (*hook_t)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp, - int32_t* aux); - static const int BLOCKSIZE = 16; // 4 cache lines + template + void volumeMix(TO *out, size_t outFrames, const TI *in, TA *aux, bool ramp); - struct track_t { uint32_t needs; // TODO: Eventually remove legacy integer volume settings @@ -181,16 +248,11 @@ private: }; int32_t prevVolume[MAX_NUM_VOLUMES]; - - // 16-byte boundary - int32_t volumeInc[MAX_NUM_VOLUMES]; int32_t auxInc; int32_t prevAuxLevel; - - // 16-byte boundary - int16_t auxLevel; // 0 <= auxLevel <= MAX_GAIN_INT, but signed for mul performance + uint16_t frameCount; uint8_t channelCount; // 1 or 2, redundant with (needs & NEEDS_CHANNEL_COUNT__MASK) @@ -202,22 +264,16 @@ private: // for how the Track buffer provider is wrapped by another one when dowmixing is required AudioBufferProvider* bufferProvider; - // 16-byte boundary - mutable AudioBufferProvider::Buffer buffer; // 8 bytes hook_t hook; - const void* in; // current location in buffer + const void *mIn; // current location in buffer - // 16-byte boundary - - AudioResampler* resampler; + std::unique_ptr mResampler; uint32_t sampleRate; int32_t* mainBuffer; int32_t* auxBuffer; - // 16-byte boundary - /* Buffer providers are constructed to translate the track input data as needed. * * TODO: perhaps make a single PlaybackConverterProvider class to move @@ -228,17 +284,17 @@ private: * match either mMixerInFormat or mDownmixRequiresFormat, if the downmixer * requires reformat. For example, it may convert floating point input to * PCM_16_bit if that's required by the downmixer. - * 3) downmixerBufferProvider: If not NULL, performs the channel remixing to match + * 3) mDownmixerBufferProvider: If not NULL, performs the channel remixing to match * the number of channels required by the mixer sink. * 4) mPostDownmixReformatBufferProvider: If not NULL, performs reformatting from * the downmixer requirements to the mixer engine input requirements. * 5) mTimestretchBufferProvider: Adds timestretching for playback rate */ AudioBufferProvider* mInputBufferProvider; // externally provided buffer provider. - PassthruBufferProvider* mReformatBufferProvider; // provider wrapper for reformatting. - PassthruBufferProvider* downmixerBufferProvider; // wrapper for channel conversion. - PassthruBufferProvider* mPostDownmixReformatBufferProvider; - PassthruBufferProvider* mTimestretchBufferProvider; + std::unique_ptr mReformatBufferProvider; + std::unique_ptr mDownmixerBufferProvider; + std::unique_ptr mPostDownmixReformatBufferProvider; + std::unique_ptr mTimestretchBufferProvider; int32_t sessionId; @@ -263,129 +319,94 @@ private: AudioPlaybackRate mPlaybackRate; - bool needsRamp() { return (volumeInc[0] | volumeInc[1] | auxInc) != 0; } - bool setResampler(uint32_t trackSampleRate, uint32_t devSampleRate); - bool doesResample() const { return resampler != NULL; } - void resetResampler() { if (resampler != NULL) resampler->reset(); } - void adjustVolumeRamp(bool aux, bool useFloat = false); - size_t getUnreleasedFrames() const { return resampler != NULL ? - resampler->getUnreleasedFrames() : 0; }; + private: + // hooks + void track__genericResample(int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux); + void track__16BitsStereo(int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux); + void track__16BitsMono(int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux); - status_t prepareForDownmix(); - void unprepareForDownmix(); - status_t prepareForReformat(); - void unprepareForReformat(); - bool setPlaybackRate(const AudioPlaybackRate &playbackRate); - void reconfigureBufferProviders(); - }; + void volumeRampStereo(int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux); + void volumeStereo(int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux); - typedef void (*process_hook_t)(state_t* state); - - // pad to 32-bytes to fill cache line - struct state_t { - uint32_t enabledTracks; - uint32_t needsChanged; - size_t frameCount; - process_hook_t hook; // one of process__*, never NULL - int32_t *outputTemp; - int32_t *resampleTemp; - NBLog::Writer* mNBLogWriter; // associated NBLog::Writer or &mDummyLog - int32_t reserved[1]; - // FIXME allocate dynamically to save some memory when maxNumTracks < MAX_NUM_TRACKS - track_t tracks[MAX_NUM_TRACKS] __attribute__((aligned(32))); + // multi-format track hooks + template + void track__Resample(TO* out, size_t frameCount, TO* temp __unused, TA* aux); + template + void track__NoResample(TO* out, size_t frameCount, TO* temp __unused, TA* aux); }; - // bitmask of allocated track names, where bit 0 corresponds to TRACK0 etc. - uint32_t mTrackNames; - - // bitmask of configured track names; ~0 if maxNumTracks == MAX_NUM_TRACKS, - // but will have fewer bits set if maxNumTracks < MAX_NUM_TRACKS - const uint32_t mConfiguredNames; - - const uint32_t mSampleRate; - - NBLog::Writer mDummyLogWriter; -public: - // Called by FastMixer to inform AudioMixer of it's associated NBLog::Writer. - // FIXME It would be safer to use TLS for this, so we don't accidentally use wrong one. - void setNBLogWriter(NBLog::Writer* log); -private: - state_t mState __attribute__((aligned(32))); - - // Call after changing either the enabled status of a track, or parameters of an enabled track. - // OK to call more often than that, but unnecessary. - void invalidateState(uint32_t mask); + // TODO: remove BLOCKSIZE unit of processing - it isn't needed anymore. + static constexpr int BLOCKSIZE = 16; bool setChannelMasks(int name, audio_channel_mask_t trackChannelMask, audio_channel_mask_t mixerChannelMask); - static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, - int32_t* aux); - static void track__nop(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux); - static void track__16BitsStereo(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, - int32_t* aux); - static void track__16BitsMono(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, - int32_t* aux); - static void volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, - int32_t* aux); - static void volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, - int32_t* aux); - - static void process__validate(state_t* state); - static void process__nop(state_t* state); - static void process__genericNoResampling(state_t* state); - static void process__genericResampling(state_t* state); - static void process__OneTrack16BitsStereoNoResampling(state_t* state); - - static pthread_once_t sOnceControl; - static void sInitRoutine(); - - /* multi-format volume mixing function (calls template functions - * in AudioMixerOps.h). The template parameters are as follows: - * - * MIXTYPE (see AudioMixerOps.h MIXTYPE_* enumeration) - * USEFLOATVOL (set to true if float volume is used) - * ADJUSTVOL (set to true if volume ramp parameters needs adjustment afterwards) - * TO: int32_t (Q4.27) or float - * TI: int32_t (Q4.27) or int16_t (Q0.15) or float - * TA: int32_t (Q4.27) - */ - template - static void volumeMix(TO *out, size_t outFrames, - const TI *in, TA *aux, bool ramp, AudioMixer::track_t *t); + // Called when track info changes and a new process hook should be determined. + void invalidate() { + mHook = &AudioMixer::process__validate; + } - // multi-format process hooks - template - static void process_NoResampleOneTrack(state_t* state); + void process__validate(); + void process__nop(); + void process__genericNoResampling(); + void process__genericResampling(); + void process__oneTrack16BitsStereoNoResampling(); - // multi-format track hooks - template - static void track__Resample(track_t* t, TO* out, size_t frameCount, - TO* temp __unused, TA* aux); template - static void track__NoResample(track_t* t, TO* out, size_t frameCount, - TO* temp __unused, TA* aux); + void process__noResampleOneTrack(); + + static process_hook_t getProcessHook(int processType, uint32_t channelCount, + audio_format_t mixerInFormat, audio_format_t mixerOutFormat); static void convertMixerFormat(void *out, audio_format_t mixerOutFormat, void *in, audio_format_t mixerInFormat, size_t sampleCount); - // hook types - enum { - PROCESSTYPE_NORESAMPLEONETRACK, - }; - enum { - TRACKTYPE_NOP, - TRACKTYPE_RESAMPLE, - TRACKTYPE_NORESAMPLE, - TRACKTYPE_NORESAMPLEMONO, - }; + static inline bool isValidPcmTrackFormat(audio_format_t format) { + switch (format) { + case AUDIO_FORMAT_PCM_8_BIT: + case AUDIO_FORMAT_PCM_16_BIT: + case AUDIO_FORMAT_PCM_24_BIT_PACKED: + case AUDIO_FORMAT_PCM_32_BIT: + case AUDIO_FORMAT_PCM_FLOAT: + return true; + default: + return false; + } + } - // functions for determining the proper process and track hooks. - static process_hook_t getProcessHook(int processType, uint32_t channelCount, - audio_format_t mixerInFormat, audio_format_t mixerOutFormat); - static hook_t getTrackHook(int trackType, uint32_t channelCount, - audio_format_t mixerInFormat, audio_format_t mixerOutFormat); + static void sInitRoutine(); + + // initialization constants + const int mMaxNumTracks; + const uint32_t mSampleRate; + const size_t mFrameCount; + + NBLog::Writer *mNBLogWriter = nullptr; // associated NBLog::Writer + + process_hook_t mHook = &AudioMixer::process__nop; // one of process__*, never nullptr + + // the size of the type (int32_t) should be the largest of all types supported + // by the mixer. + std::unique_ptr mOutputTemp; + std::unique_ptr mResampleTemp; + + // fast lookup of previously deleted track names for reuse. + // the AudioMixer tries to return the smallest unused name - + // this is an arbitrary decision (actually any non-negative + // integer that isn't in mTracks could be used). + std::set mUnusedNames; // set of unused track names (may be empty) + + // track names grouped by main buffer, in no particular order of main buffer. + // however names for a particular main buffer are in order (by construction). + std::unordered_map> mGroups; + + // track names that are enabled, in increasing order (by construction). + std::vector mEnabled; + + // track smart pointers, by name, in increasing order of name. + std::map> mTracks; + + static pthread_once_t sOnceControl; // initialized in constructor by first new }; // ---------------------------------------------------------------------------- diff --git a/media/libaudioprocessing/AudioMixer.cpp b/media/libaudioprocessing/AudioMixer.cpp index 5fafb8ac1f..f1daeb4a4e 100644 --- a/media/libaudioprocessing/AudioMixer.cpp +++ b/media/libaudioprocessing/AudioMixer.cpp @@ -62,13 +62,6 @@ #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) #endif -// TODO: Move these macro/inlines to a header file. -template -static inline -T max(const T& x, const T& y) { - return x > y ? x : y; -} - // Set kUseNewMixer to true to use the new mixer engine always. Otherwise the // original code will be used for stereo sinks, the new mixer for multichannel. static constexpr bool kUseNewMixer = true; @@ -93,88 +86,41 @@ namespace android { // ---------------------------------------------------------------------------- -template -T min(const T& a, const T& b) -{ - return a < b ? a : b; -} - -// ---------------------------------------------------------------------------- - -// Ensure mConfiguredNames bitmask is initialized properly on all architectures. -// The value of 1 << x is undefined in C when x >= 32. - -AudioMixer::AudioMixer(size_t frameCount, uint32_t sampleRate, uint32_t maxNumTracks) - : mTrackNames(0), mConfiguredNames((maxNumTracks >= 32 ? 0 : 1 << maxNumTracks) - 1), - mSampleRate(sampleRate) -{ - ALOG_ASSERT(maxNumTracks <= MAX_NUM_TRACKS, "maxNumTracks %u > MAX_NUM_TRACKS %u", - maxNumTracks, MAX_NUM_TRACKS); - - // AudioMixer is not yet capable of more than 32 active track inputs - ALOG_ASSERT(32 >= MAX_NUM_TRACKS, "bad MAX_NUM_TRACKS %d", MAX_NUM_TRACKS); - - pthread_once(&sOnceControl, &sInitRoutine); - - mState.enabledTracks= 0; - mState.needsChanged = 0; - mState.frameCount = frameCount; - mState.hook = process__nop; - mState.outputTemp = NULL; - mState.resampleTemp = NULL; - mState.mNBLogWriter = &mDummyLogWriter; - // mState.reserved - - // FIXME Most of the following initialization is probably redundant since - // tracks[i] should only be referenced if (mTrackNames & (1 << i)) != 0 - // and mTrackNames is initially 0. However, leave it here until that's verified. - track_t* t = mState.tracks; - for (unsigned i=0 ; i < MAX_NUM_TRACKS ; i++) { - t->resampler = NULL; - t->downmixerBufferProvider = NULL; - t->mReformatBufferProvider = NULL; - t->mTimestretchBufferProvider = NULL; - t++; - } - -} - -AudioMixer::~AudioMixer() -{ - track_t* t = mState.tracks; - for (unsigned i=0 ; i < MAX_NUM_TRACKS ; i++) { - delete t->resampler; - delete t->downmixerBufferProvider; - delete t->mReformatBufferProvider; - delete t->mTimestretchBufferProvider; - t++; - } - delete [] mState.outputTemp; - delete [] mState.resampleTemp; -} - -void AudioMixer::setNBLogWriter(NBLog::Writer *logWriter) -{ - mState.mNBLogWriter = logWriter; -} - static inline audio_format_t selectMixerInFormat(audio_format_t inputFormat __unused) { return kUseFloat && kUseNewMixer ? AUDIO_FORMAT_PCM_FLOAT : AUDIO_FORMAT_PCM_16_BIT; } -int AudioMixer::getTrackName(audio_channel_mask_t channelMask, - audio_format_t format, int sessionId) +int AudioMixer::getTrackName( + audio_channel_mask_t channelMask, audio_format_t format, int sessionId) { if (!isValidPcmTrackFormat(format)) { ALOGE("AudioMixer::getTrackName invalid format (%#x)", format); return -1; } - uint32_t names = (~mTrackNames) & mConfiguredNames; - if (names != 0) { - int n = __builtin_ctz(names); - ALOGV("add track (%d)", n); + if (mTracks.size() >= (size_t)mMaxNumTracks) { + ALOGE("%s: out of track names (max = %d)", __func__, mMaxNumTracks); + return -1; + } + + // get a new name for the track. + int name; + if (mUnusedNames.size() != 0) { + // reuse first name for deleted track. + auto it = mUnusedNames.begin(); + name = *it; + (void)mUnusedNames.erase(it); + } else { + // we're fully populated, so create a new name. + name = mTracks.size(); + } + ALOGV("add track (%d)", name); + + auto t = std::make_shared(); + mTracks[name] = t; + + { + // TODO: move initialization to the Track constructor. // assume default parameters for the track, except where noted below - track_t* t = &mState.tracks[n]; t->needs = 0; // Integer volume. @@ -215,17 +161,12 @@ int AudioMixer::getTrackName(audio_channel_mask_t channelMask, // no initialization needed // t->buffer.frameCount t->hook = NULL; - t->in = NULL; - t->resampler = NULL; + t->mIn = NULL; t->sampleRate = mSampleRate; // setParameter(name, TRACK, MAIN_BUFFER, mixBuffer) is required before enable(name) t->mainBuffer = NULL; t->auxBuffer = NULL; t->mInputBufferProvider = NULL; - t->mReformatBufferProvider = NULL; - t->downmixerBufferProvider = NULL; - t->mPostDownmixReformatBufferProvider = NULL; - t->mTimestretchBufferProvider = NULL; t->mMixerFormat = AUDIO_FORMAT_PCM_16_BIT; t->mFormat = format; t->mMixerInFormat = selectMixerInFormat(format); @@ -243,91 +184,78 @@ int AudioMixer::getTrackName(audio_channel_mask_t channelMask, // prepareForDownmix() may change mDownmixRequiresFormat ALOGVV("mMixerFormat:%#x mMixerInFormat:%#x\n", t->mMixerFormat, t->mMixerInFormat); t->prepareForReformat(); - mTrackNames |= 1 << n; - return TRACK0 + n; + return TRACK0 + name; } - ALOGE("AudioMixer::getTrackName out of available tracks"); - return -1; } -void AudioMixer::invalidateState(uint32_t mask) -{ - if (mask != 0) { - mState.needsChanged |= mask; - mState.hook = process__validate; - } - } - // Called when channel masks have changed for a track name // TODO: Fix DownmixerBufferProvider not to (possibly) change mixer input format, // which will simplify this logic. bool AudioMixer::setChannelMasks(int name, audio_channel_mask_t trackChannelMask, audio_channel_mask_t mixerChannelMask) { - track_t &track = mState.tracks[name]; + LOG_ALWAYS_FATAL_IF(mTracks.find(name) == mTracks.end(), "invalid name: %d", name); + const std::shared_ptr &track = mTracks[name]; - if (trackChannelMask == track.channelMask - && mixerChannelMask == track.mMixerChannelMask) { + if (trackChannelMask == track->channelMask + && mixerChannelMask == track->mMixerChannelMask) { return false; // no need to change } // always recompute for both channel masks even if only one has changed. const uint32_t trackChannelCount = audio_channel_count_from_out_mask(trackChannelMask); const uint32_t mixerChannelCount = audio_channel_count_from_out_mask(mixerChannelMask); - const bool mixerChannelCountChanged = track.mMixerChannelCount != mixerChannelCount; + const bool mixerChannelCountChanged = track->mMixerChannelCount != mixerChannelCount; ALOG_ASSERT((trackChannelCount <= MAX_NUM_CHANNELS_TO_DOWNMIX) && trackChannelCount && mixerChannelCount); - track.channelMask = trackChannelMask; - track.channelCount = trackChannelCount; - track.mMixerChannelMask = mixerChannelMask; - track.mMixerChannelCount = mixerChannelCount; + track->channelMask = trackChannelMask; + track->channelCount = trackChannelCount; + track->mMixerChannelMask = mixerChannelMask; + track->mMixerChannelCount = mixerChannelCount; // channel masks have changed, does this track need a downmixer? // update to try using our desired format (if we aren't already using it) - const audio_format_t prevDownmixerFormat = track.mDownmixRequiresFormat; - const status_t status = mState.tracks[name].prepareForDownmix(); + const audio_format_t prevDownmixerFormat = track->mDownmixRequiresFormat; + const status_t status = track->prepareForDownmix(); ALOGE_IF(status != OK, "prepareForDownmix error %d, track channel mask %#x, mixer channel mask %#x", - status, track.channelMask, track.mMixerChannelMask); + status, track->channelMask, track->mMixerChannelMask); - if (prevDownmixerFormat != track.mDownmixRequiresFormat) { - track.prepareForReformat(); // because of downmixer, track format may change! + if (prevDownmixerFormat != track->mDownmixRequiresFormat) { + track->prepareForReformat(); // because of downmixer, track format may change! } - if (track.resampler && mixerChannelCountChanged) { + if (track->mResampler.get() != nullptr && mixerChannelCountChanged) { // resampler channels may have changed. - const uint32_t resetToSampleRate = track.sampleRate; - delete track.resampler; - track.resampler = NULL; - track.sampleRate = mSampleRate; // without resampler, track rate is device sample rate. + const uint32_t resetToSampleRate = track->sampleRate; + track->mResampler.reset(nullptr); + track->sampleRate = mSampleRate; // without resampler, track rate is device sample rate. // recreate the resampler with updated format, channels, saved sampleRate. - track.setResampler(resetToSampleRate /*trackSampleRate*/, mSampleRate /*devSampleRate*/); + track->setResampler(resetToSampleRate /*trackSampleRate*/, mSampleRate /*devSampleRate*/); } return true; } -void AudioMixer::track_t::unprepareForDownmix() { +void AudioMixer::Track::unprepareForDownmix() { ALOGV("AudioMixer::unprepareForDownmix(%p)", this); - if (mPostDownmixReformatBufferProvider != nullptr) { + if (mPostDownmixReformatBufferProvider.get() != nullptr) { // release any buffers held by the mPostDownmixReformatBufferProvider - // before deallocating the downmixerBufferProvider. + // before deallocating the mDownmixerBufferProvider. mPostDownmixReformatBufferProvider->reset(); } mDownmixRequiresFormat = AUDIO_FORMAT_INVALID; - if (downmixerBufferProvider != NULL) { + if (mDownmixerBufferProvider.get() != nullptr) { // this track had previously been configured with a downmixer, delete it - ALOGV(" deleting old downmixer"); - delete downmixerBufferProvider; - downmixerBufferProvider = NULL; + mDownmixerBufferProvider.reset(nullptr); reconfigureBufferProviders(); } else { ALOGV(" nothing to do, no downmixer to delete"); } } -status_t AudioMixer::track_t::prepareForDownmix() +status_t AudioMixer::Track::prepareForDownmix() { ALOGV("AudioMixer::prepareForDownmix(%p) with mask 0x%x", this, channelMask); @@ -345,40 +273,35 @@ status_t AudioMixer::track_t::prepareForDownmix() if (audio_channel_mask_get_representation(channelMask) == AUDIO_CHANNEL_REPRESENTATION_POSITION && DownmixerBufferProvider::isMultichannelCapable()) { - DownmixerBufferProvider* pDbp = new DownmixerBufferProvider(channelMask, + mDownmixerBufferProvider.reset(new DownmixerBufferProvider(channelMask, mMixerChannelMask, AUDIO_FORMAT_PCM_16_BIT /* TODO: use mMixerInFormat, now only PCM 16 */, - sampleRate, sessionId, kCopyBufferFrameCount); - - if (pDbp->isValid()) { // if constructor completed properly + sampleRate, sessionId, kCopyBufferFrameCount)); + if (static_cast(mDownmixerBufferProvider.get())->isValid()) { mDownmixRequiresFormat = AUDIO_FORMAT_PCM_16_BIT; // PCM 16 bit required for downmix - downmixerBufferProvider = pDbp; reconfigureBufferProviders(); return NO_ERROR; } - delete pDbp; + // mDownmixerBufferProvider reset below. } // Effect downmixer does not accept the channel conversion. Let's use our remixer. - RemixBufferProvider* pRbp = new RemixBufferProvider(channelMask, - mMixerChannelMask, mMixerInFormat, kCopyBufferFrameCount); + mDownmixerBufferProvider.reset(new RemixBufferProvider(channelMask, + mMixerChannelMask, mMixerInFormat, kCopyBufferFrameCount)); // Remix always finds a conversion whereas Downmixer effect above may fail. - downmixerBufferProvider = pRbp; reconfigureBufferProviders(); return NO_ERROR; } -void AudioMixer::track_t::unprepareForReformat() { +void AudioMixer::Track::unprepareForReformat() { ALOGV("AudioMixer::unprepareForReformat(%p)", this); bool requiresReconfigure = false; - if (mReformatBufferProvider != NULL) { - delete mReformatBufferProvider; - mReformatBufferProvider = NULL; + if (mReformatBufferProvider.get() != nullptr) { + mReformatBufferProvider.reset(nullptr); requiresReconfigure = true; } - if (mPostDownmixReformatBufferProvider != NULL) { - delete mPostDownmixReformatBufferProvider; - mPostDownmixReformatBufferProvider = NULL; + if (mPostDownmixReformatBufferProvider.get() != nullptr) { + mPostDownmixReformatBufferProvider.reset(nullptr); requiresReconfigure = true; } if (requiresReconfigure) { @@ -386,7 +309,7 @@ void AudioMixer::track_t::unprepareForReformat() { } } -status_t AudioMixer::track_t::prepareForReformat() +status_t AudioMixer::Track::prepareForReformat() { ALOGV("AudioMixer::prepareForReformat(%p) with format %#x", this, mFormat); // discard previous reformatters @@ -396,19 +319,19 @@ status_t AudioMixer::track_t::prepareForReformat() ? mDownmixRequiresFormat : mMixerInFormat; bool requiresReconfigure = false; if (mFormat != targetFormat) { - mReformatBufferProvider = new ReformatBufferProvider( + mReformatBufferProvider.reset(new ReformatBufferProvider( audio_channel_count_from_out_mask(channelMask), mFormat, targetFormat, - kCopyBufferFrameCount); + kCopyBufferFrameCount)); requiresReconfigure = true; } if (targetFormat != mMixerInFormat) { - mPostDownmixReformatBufferProvider = new ReformatBufferProvider( + mPostDownmixReformatBufferProvider.reset(new ReformatBufferProvider( audio_channel_count_from_out_mask(mMixerChannelMask), targetFormat, mMixerInFormat, - kCopyBufferFrameCount); + kCopyBufferFrameCount)); requiresReconfigure = true; } if (requiresReconfigure) { @@ -417,74 +340,63 @@ status_t AudioMixer::track_t::prepareForReformat() return NO_ERROR; } -void AudioMixer::track_t::reconfigureBufferProviders() +void AudioMixer::Track::reconfigureBufferProviders() { bufferProvider = mInputBufferProvider; - if (mReformatBufferProvider) { + if (mReformatBufferProvider.get() != nullptr) { mReformatBufferProvider->setBufferProvider(bufferProvider); - bufferProvider = mReformatBufferProvider; + bufferProvider = mReformatBufferProvider.get(); } - if (downmixerBufferProvider) { - downmixerBufferProvider->setBufferProvider(bufferProvider); - bufferProvider = downmixerBufferProvider; + if (mDownmixerBufferProvider.get() != nullptr) { + mDownmixerBufferProvider->setBufferProvider(bufferProvider); + bufferProvider = mDownmixerBufferProvider.get(); } - if (mPostDownmixReformatBufferProvider) { + if (mPostDownmixReformatBufferProvider.get() != nullptr) { mPostDownmixReformatBufferProvider->setBufferProvider(bufferProvider); - bufferProvider = mPostDownmixReformatBufferProvider; + bufferProvider = mPostDownmixReformatBufferProvider.get(); } - if (mTimestretchBufferProvider) { + if (mTimestretchBufferProvider.get() != nullptr) { mTimestretchBufferProvider->setBufferProvider(bufferProvider); - bufferProvider = mTimestretchBufferProvider; + bufferProvider = mTimestretchBufferProvider.get(); } } void AudioMixer::deleteTrackName(int name) { - ALOGV("AudioMixer::deleteTrackName(%d)", name); name -= TRACK0; - LOG_ALWAYS_FATAL_IF(name < 0 || name >= (int)MAX_NUM_TRACKS, "bad track name %d", name); + LOG_ALWAYS_FATAL_IF(mTracks.find(name) == mTracks.end(), "invalid name: %d", name); ALOGV("deleteTrackName(%d)", name); - track_t& track(mState.tracks[ name ]); - if (track.enabled) { - track.enabled = false; - invalidateState(1<enabled) { + invalidate(); } - // delete the resampler - delete track.resampler; - track.resampler = NULL; - // delete the downmixer - mState.tracks[name].unprepareForDownmix(); - // delete the reformatter - mState.tracks[name].unprepareForReformat(); - // delete the timestretch provider - delete track.mTimestretchBufferProvider; - track.mTimestretchBufferProvider = NULL; - mTrackNames &= ~(1< &track = mTracks[name]; - if (!track.enabled) { - track.enabled = true; + if (!track->enabled) { + track->enabled = true; ALOGV("enable(%d)", name); - invalidateState(1 << name); + invalidate(); } } void AudioMixer::disable(int name) { name -= TRACK0; - ALOG_ASSERT(uint32_t(name) < MAX_NUM_TRACKS, "bad track name %d", name); - track_t& track = mState.tracks[name]; + LOG_ALWAYS_FATAL_IF(mTracks.find(name) == mTracks.end(), "invalid name: %d", name); + const std::shared_ptr &track = mTracks[name]; - if (track.enabled) { - track.enabled = false; + if (track->enabled) { + track->enabled = false; ALOGV("disable(%d)", name); - invalidateState(1 << name); + invalidate(); } } @@ -562,7 +474,8 @@ static inline bool setVolumeRampVariables(float newVolume, int32_t ramp, ALOGD_IF(*pPrevVolume != *pSetVolume, "previous float ramp hasn't finished," " prev:%f set_to:%f", *pPrevVolume, *pSetVolume); const float inc = (newVolume - *pPrevVolume) / ramp; // could be inf, nan, subnormal - const float maxv = max(newVolume, *pPrevVolume); // could be inf, cannot be nan, subnormal + // could be inf, cannot be nan, subnormal + const float maxv = std::max(newVolume, *pPrevVolume); if (isnormal(inc) // inc must be a normal number (no subnormals, infinite, nan) && maxv + inc != maxv) { // inc must make forward progress @@ -616,8 +529,8 @@ static inline bool setVolumeRampVariables(float newVolume, int32_t ramp, void AudioMixer::setParameter(int name, int target, int param, void *value) { name -= TRACK0; - ALOG_ASSERT(uint32_t(name) < MAX_NUM_TRACKS, "bad track name %d", name); - track_t& track = mState.tracks[name]; + LOG_ALWAYS_FATAL_IF(mTracks.find(name) == mTracks.end(), "invalid name: %d", name); + const std::shared_ptr &track = mTracks[name]; int valueInt = static_cast(reinterpret_cast(value)); int32_t *valueBuf = reinterpret_cast(value); @@ -629,33 +542,33 @@ void AudioMixer::setParameter(int name, int target, int param, void *value) case CHANNEL_MASK: { const audio_channel_mask_t trackChannelMask = static_cast(valueInt); - if (setChannelMasks(name, trackChannelMask, track.mMixerChannelMask)) { + if (setChannelMasks(name, trackChannelMask, track->mMixerChannelMask)) { ALOGV("setParameter(TRACK, CHANNEL_MASK, %x)", trackChannelMask); - invalidateState(1 << name); + invalidate(); } } break; case MAIN_BUFFER: - if (track.mainBuffer != valueBuf) { - track.mainBuffer = valueBuf; + if (track->mainBuffer != valueBuf) { + track->mainBuffer = valueBuf; ALOGV("setParameter(TRACK, MAIN_BUFFER, %p)", valueBuf); - invalidateState(1 << name); + invalidate(); } break; case AUX_BUFFER: - if (track.auxBuffer != valueBuf) { - track.auxBuffer = valueBuf; + if (track->auxBuffer != valueBuf) { + track->auxBuffer = valueBuf; ALOGV("setParameter(TRACK, AUX_BUFFER, %p)", valueBuf); - invalidateState(1 << name); + invalidate(); } break; case FORMAT: { audio_format_t format = static_cast(valueInt); - if (track.mFormat != format) { + if (track->mFormat != format) { ALOG_ASSERT(audio_is_linear_pcm(format), "Invalid format %#x", format); - track.mFormat = format; + track->mFormat = format; ALOGV("setParameter(TRACK, FORMAT, %#x)", format); - track.prepareForReformat(); - invalidateState(1 << name); + track->prepareForReformat(); + invalidate(); } } break; // FIXME do we want to support setting the downmix type from AudioFlinger? @@ -664,17 +577,17 @@ void AudioMixer::setParameter(int name, int target, int param, void *value) break */ case MIXER_FORMAT: { audio_format_t format = static_cast(valueInt); - if (track.mMixerFormat != format) { - track.mMixerFormat = format; + if (track->mMixerFormat != format) { + track->mMixerFormat = format; ALOGV("setParameter(TRACK, MIXER_FORMAT, %#x)", format); } } break; case MIXER_CHANNEL_MASK: { const audio_channel_mask_t mixerChannelMask = static_cast(valueInt); - if (setChannelMasks(name, track.channelMask, mixerChannelMask)) { + if (setChannelMasks(name, track->channelMask, mixerChannelMask)) { ALOGV("setParameter(TRACK, MIXER_CHANNEL_MASK, %#x)", mixerChannelMask); - invalidateState(1 << name); + invalidate(); } } break; default: @@ -686,21 +599,20 @@ void AudioMixer::setParameter(int name, int target, int param, void *value) switch (param) { case SAMPLE_RATE: ALOG_ASSERT(valueInt > 0, "bad sample rate %d", valueInt); - if (track.setResampler(uint32_t(valueInt), mSampleRate)) { + if (track->setResampler(uint32_t(valueInt), mSampleRate)) { ALOGV("setParameter(RESAMPLE, SAMPLE_RATE, %u)", uint32_t(valueInt)); - invalidateState(1 << name); + invalidate(); } break; case RESET: - track.resetResampler(); - invalidateState(1 << name); + track->resetResampler(); + invalidate(); break; case REMOVE: - delete track.resampler; - track.resampler = NULL; - track.sampleRate = mSampleRate; - invalidateState(1 << name); + track->mResampler.reset(nullptr); + track->sampleRate = mSampleRate; + invalidate(); break; default: LOG_ALWAYS_FATAL("setParameter resample: bad param %d", param); @@ -712,26 +624,28 @@ void AudioMixer::setParameter(int name, int target, int param, void *value) switch (param) { case AUXLEVEL: if (setVolumeRampVariables(*reinterpret_cast(value), - target == RAMP_VOLUME ? mState.frameCount : 0, - &track.auxLevel, &track.prevAuxLevel, &track.auxInc, - &track.mAuxLevel, &track.mPrevAuxLevel, &track.mAuxInc)) { + target == RAMP_VOLUME ? mFrameCount : 0, + &track->auxLevel, &track->prevAuxLevel, &track->auxInc, + &track->mAuxLevel, &track->mPrevAuxLevel, &track->mAuxInc)) { ALOGV("setParameter(%s, AUXLEVEL: %04x)", - target == VOLUME ? "VOLUME" : "RAMP_VOLUME", track.auxLevel); - invalidateState(1 << name); + target == VOLUME ? "VOLUME" : "RAMP_VOLUME", track->auxLevel); + invalidate(); } break; default: if ((unsigned)param >= VOLUME0 && (unsigned)param < VOLUME0 + MAX_NUM_VOLUMES) { if (setVolumeRampVariables(*reinterpret_cast(value), - target == RAMP_VOLUME ? mState.frameCount : 0, - &track.volume[param - VOLUME0], &track.prevVolume[param - VOLUME0], - &track.volumeInc[param - VOLUME0], - &track.mVolume[param - VOLUME0], &track.mPrevVolume[param - VOLUME0], - &track.mVolumeInc[param - VOLUME0])) { + target == RAMP_VOLUME ? mFrameCount : 0, + &track->volume[param - VOLUME0], + &track->prevVolume[param - VOLUME0], + &track->volumeInc[param - VOLUME0], + &track->mVolume[param - VOLUME0], + &track->mPrevVolume[param - VOLUME0], + &track->mVolumeInc[param - VOLUME0])) { ALOGV("setParameter(%s, VOLUME%d: %04x)", target == VOLUME ? "VOLUME" : "RAMP_VOLUME", param - VOLUME0, - track.volume[param - VOLUME0]); - invalidateState(1 << name); + track->volume[param - VOLUME0]); + invalidate(); } } else { LOG_ALWAYS_FATAL("setParameter volume: bad param %d", param); @@ -744,16 +658,16 @@ void AudioMixer::setParameter(int name, int target, int param, void *value) const AudioPlaybackRate *playbackRate = reinterpret_cast(value); ALOGW_IF(!isAudioPlaybackRateValid(*playbackRate), - "bad parameters speed %f, pitch %f",playbackRate->mSpeed, - playbackRate->mPitch); - if (track.setPlaybackRate(*playbackRate)) { + "bad parameters speed %f, pitch %f", + playbackRate->mSpeed, playbackRate->mPitch); + if (track->setPlaybackRate(*playbackRate)) { ALOGV("setParameter(TIMESTRETCH, PLAYBACK_RATE, STRETCH_MODE, FALLBACK_MODE " "%f %f %d %d", playbackRate->mSpeed, playbackRate->mPitch, playbackRate->mStretchMode, playbackRate->mFallbackMode); - // invalidateState(1 << name); + // invalidate(); (should not require reconfigure) } } break; default: @@ -766,12 +680,12 @@ void AudioMixer::setParameter(int name, int target, int param, void *value) } } -bool AudioMixer::track_t::setResampler(uint32_t trackSampleRate, uint32_t devSampleRate) +bool AudioMixer::Track::setResampler(uint32_t trackSampleRate, uint32_t devSampleRate) { - if (trackSampleRate != devSampleRate || resampler != NULL) { + if (trackSampleRate != devSampleRate || mResampler.get() != nullptr) { if (sampleRate != trackSampleRate) { sampleRate = trackSampleRate; - if (resampler == NULL) { + if (mResampler.get() == nullptr) { ALOGV("Creating resampler from track %d Hz to device %d Hz", trackSampleRate, devSampleRate); AudioResampler::src_quality quality; @@ -787,15 +701,15 @@ bool AudioMixer::track_t::setResampler(uint32_t trackSampleRate, uint32_t devSam // TODO: Remove MONO_HACK. Resampler sees #channels after the downmixer // but if none exists, it is the channel count (1 for mono). - const int resamplerChannelCount = downmixerBufferProvider != NULL + const int resamplerChannelCount = mDownmixerBufferProvider.get() != nullptr ? mMixerChannelCount : channelCount; ALOGVV("Creating resampler:" " format(%#x) channels(%d) devSampleRate(%u) quality(%d)\n", mMixerInFormat, resamplerChannelCount, devSampleRate, quality); - resampler = AudioResampler::create( + mResampler.reset(AudioResampler::create( mMixerInFormat, resamplerChannelCount, - devSampleRate, quality); + devSampleRate, quality)); } return true; } @@ -803,25 +717,25 @@ bool AudioMixer::track_t::setResampler(uint32_t trackSampleRate, uint32_t devSam return false; } -bool AudioMixer::track_t::setPlaybackRate(const AudioPlaybackRate &playbackRate) +bool AudioMixer::Track::setPlaybackRate(const AudioPlaybackRate &playbackRate) { - if ((mTimestretchBufferProvider == NULL && + if ((mTimestretchBufferProvider.get() == nullptr && fabs(playbackRate.mSpeed - mPlaybackRate.mSpeed) < AUDIO_TIMESTRETCH_SPEED_MIN_DELTA && fabs(playbackRate.mPitch - mPlaybackRate.mPitch) < AUDIO_TIMESTRETCH_PITCH_MIN_DELTA) || isAudioPlaybackRateEqual(playbackRate, mPlaybackRate)) { return false; } mPlaybackRate = playbackRate; - if (mTimestretchBufferProvider == NULL) { + if (mTimestretchBufferProvider.get() == nullptr) { // TODO: Remove MONO_HACK. Resampler sees #channels after the downmixer // but if none exists, it is the channel count (1 for mono). - const int timestretchChannelCount = downmixerBufferProvider != NULL + const int timestretchChannelCount = mDownmixerBufferProvider.get() != nullptr ? mMixerChannelCount : channelCount; - mTimestretchBufferProvider = new TimestretchBufferProvider(timestretchChannelCount, - mMixerInFormat, sampleRate, playbackRate); + mTimestretchBufferProvider.reset(new TimestretchBufferProvider(timestretchChannelCount, + mMixerInFormat, sampleRate, playbackRate)); reconfigureBufferProviders(); } else { - static_cast(mTimestretchBufferProvider) + static_cast(mTimestretchBufferProvider.get()) ->setPlaybackRate(playbackRate); } return true; @@ -840,7 +754,7 @@ bool AudioMixer::track_t::setPlaybackRate(const AudioPlaybackRate &playbackRate) * * There is a bit of duplicated code here, but it keeps backward compatibility. */ -inline void AudioMixer::track_t::adjustVolumeRamp(bool aux, bool useFloat) +inline void AudioMixer::Track::adjustVolumeRamp(bool aux, bool useFloat) { if (useFloat) { for (uint32_t i = 0; i < MAX_NUM_VOLUMES; i++) { @@ -895,8 +809,9 @@ inline void AudioMixer::track_t::adjustVolumeRamp(bool aux, bool useFloat) size_t AudioMixer::getUnreleasedFrames(int name) const { name -= TRACK0; - if (uint32_t(name) < MAX_NUM_TRACKS) { - return mState.tracks[name].getUnreleasedFrames(); + const auto it = mTracks.find(name); + if (it != mTracks.end()) { + return it->second->getUnreleasedFrames(); } return 0; } @@ -904,87 +819,63 @@ size_t AudioMixer::getUnreleasedFrames(int name) const void AudioMixer::setBufferProvider(int name, AudioBufferProvider* bufferProvider) { name -= TRACK0; - ALOG_ASSERT(uint32_t(name) < MAX_NUM_TRACKS, "bad track name %d", name); + const std::shared_ptr &track = mTracks[name]; - if (mState.tracks[name].mInputBufferProvider == bufferProvider) { + if (track->mInputBufferProvider == bufferProvider) { return; // don't reset any buffer providers if identical. } - if (mState.tracks[name].mReformatBufferProvider != NULL) { - mState.tracks[name].mReformatBufferProvider->reset(); - } else if (mState.tracks[name].downmixerBufferProvider != NULL) { - mState.tracks[name].downmixerBufferProvider->reset(); - } else if (mState.tracks[name].mPostDownmixReformatBufferProvider != NULL) { - mState.tracks[name].mPostDownmixReformatBufferProvider->reset(); - } else if (mState.tracks[name].mTimestretchBufferProvider != NULL) { - mState.tracks[name].mTimestretchBufferProvider->reset(); + if (track->mReformatBufferProvider.get() != nullptr) { + track->mReformatBufferProvider->reset(); + } else if (track->mDownmixerBufferProvider != nullptr) { + track->mDownmixerBufferProvider->reset(); + } else if (track->mPostDownmixReformatBufferProvider.get() != nullptr) { + track->mPostDownmixReformatBufferProvider->reset(); + } else if (track->mTimestretchBufferProvider.get() != nullptr) { + track->mTimestretchBufferProvider->reset(); } - mState.tracks[name].mInputBufferProvider = bufferProvider; - mState.tracks[name].reconfigureBufferProviders(); + track->mInputBufferProvider = bufferProvider; + track->reconfigureBufferProviders(); } - -void AudioMixer::process() -{ - mState.hook(&mState); -} - - -void AudioMixer::process__validate(state_t* state) +void AudioMixer::process__validate() { - ALOGW_IF(!state->needsChanged, - "in process__validate() but nothing's invalid"); - - uint32_t changed = state->needsChanged; - state->needsChanged = 0; // clear the validation flag - - // recompute which tracks are enabled / disabled - uint32_t enabled = 0; - uint32_t disabled = 0; - while (changed) { - const int i = 31 - __builtin_clz(changed); - const uint32_t mask = 1<tracks[i]; - (t.enabled ? enabled : disabled) |= mask; - } - state->enabledTracks &= ~disabled; - state->enabledTracks |= enabled; - - // compute everything we need... - int countActiveTracks = 0; // TODO: fix all16BitsStereNoResample logic to // either properly handle muted tracks (it should ignore them) // or remove altogether as an obsolete optimization. bool all16BitsStereoNoResample = true; bool resampling = false; bool volumeRamp = false; - uint32_t en = state->enabledTracks; - while (en) { - const int i = 31 - __builtin_clz(en); - en &= ~(1<tracks[i]; + mEnabled.clear(); + mGroups.clear(); + for (const auto &pair : mTracks) { + const int name = pair.first; + const std::shared_ptr &t = pair.second; + if (!t->enabled) continue; + + mEnabled.emplace_back(name); // we add to mEnabled in order of name. + mGroups[t->mainBuffer].emplace_back(name); // mGroups also in order of name. + uint32_t n = 0; // FIXME can overflow (mask is only 3 bits) - n |= NEEDS_CHANNEL_1 + t.channelCount - 1; - if (t.doesResample()) { + n |= NEEDS_CHANNEL_1 + t->channelCount - 1; + if (t->doesResample()) { n |= NEEDS_RESAMPLE; } - if (t.auxLevel != 0 && t.auxBuffer != NULL) { + if (t->auxLevel != 0 && t->auxBuffer != NULL) { n |= NEEDS_AUX; } - if (t.volumeInc[0]|t.volumeInc[1]) { + if (t->volumeInc[0]|t->volumeInc[1]) { volumeRamp = true; - } else if (!t.doesResample() && t.volumeRL == 0) { + } else if (!t->doesResample() && t->volumeRL == 0) { n |= NEEDS_MUTE; } - t.needs = n; + t->needs = n; if (n & NEEDS_MUTE) { - t.hook = track__nop; + t->hook = &Track::track__nop; } else { if (n & NEEDS_AUX) { all16BitsStereoNoResample = false; @@ -992,23 +883,23 @@ void AudioMixer::process__validate(state_t* state) if (n & NEEDS_RESAMPLE) { all16BitsStereoNoResample = false; resampling = true; - t.hook = getTrackHook(TRACKTYPE_RESAMPLE, t.mMixerChannelCount, - t.mMixerInFormat, t.mMixerFormat); + t->hook = Track::getTrackHook(TRACKTYPE_RESAMPLE, t->mMixerChannelCount, + t->mMixerInFormat, t->mMixerFormat); ALOGV_IF((n & NEEDS_CHANNEL_COUNT__MASK) > NEEDS_CHANNEL_2, "Track %d needs downmix + resample", i); } else { if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_1){ - t.hook = getTrackHook( - (t.mMixerChannelMask == AUDIO_CHANNEL_OUT_STEREO // TODO: MONO_HACK - && t.channelMask == AUDIO_CHANNEL_OUT_MONO) + t->hook = Track::getTrackHook( + (t->mMixerChannelMask == AUDIO_CHANNEL_OUT_STEREO // TODO: MONO_HACK + && t->channelMask == AUDIO_CHANNEL_OUT_MONO) ? TRACKTYPE_NORESAMPLEMONO : TRACKTYPE_NORESAMPLE, - t.mMixerChannelCount, - t.mMixerInFormat, t.mMixerFormat); + t->mMixerChannelCount, + t->mMixerInFormat, t->mMixerFormat); all16BitsStereoNoResample = false; } if ((n & NEEDS_CHANNEL_COUNT__MASK) >= NEEDS_CHANNEL_2){ - t.hook = getTrackHook(TRACKTYPE_NORESAMPLE, t.mMixerChannelCount, - t.mMixerInFormat, t.mMixerFormat); + t->hook = Track::getTrackHook(TRACKTYPE_NORESAMPLE, t->mMixerChannelCount, + t->mMixerInFormat, t->mMixerFormat); ALOGV_IF((n & NEEDS_CHANNEL_COUNT__MASK) > NEEDS_CHANNEL_2, "Track %d needs downmix", i); } @@ -1017,137 +908,125 @@ void AudioMixer::process__validate(state_t* state) } // select the processing hooks - state->hook = process__nop; - if (countActiveTracks > 0) { + mHook = &AudioMixer::process__nop; + if (mEnabled.size() > 0) { if (resampling) { - if (!state->outputTemp) { - state->outputTemp = new int32_t[MAX_NUM_CHANNELS * state->frameCount]; + if (mOutputTemp.get() == nullptr) { + mOutputTemp.reset(new int32_t[MAX_NUM_CHANNELS * mFrameCount]); } - if (!state->resampleTemp) { - state->resampleTemp = new int32_t[MAX_NUM_CHANNELS * state->frameCount]; + if (mResampleTemp.get() == nullptr) { + mResampleTemp.reset(new int32_t[MAX_NUM_CHANNELS * mFrameCount]); } - state->hook = process__genericResampling; + mHook = &AudioMixer::process__genericResampling; } else { - if (state->outputTemp) { - delete [] state->outputTemp; - state->outputTemp = NULL; - } - if (state->resampleTemp) { - delete [] state->resampleTemp; - state->resampleTemp = NULL; - } - state->hook = process__genericNoResampling; + // we keep temp arrays around. + mHook = &AudioMixer::process__genericNoResampling; if (all16BitsStereoNoResample && !volumeRamp) { - if (countActiveTracks == 1) { - const int i = 31 - __builtin_clz(state->enabledTracks); - track_t& t = state->tracks[i]; - if ((t.needs & NEEDS_MUTE) == 0) { + if (mEnabled.size() == 1) { + const std::shared_ptr &t = mTracks[mEnabled[0]]; + if ((t->needs & NEEDS_MUTE) == 0) { // The check prevents a muted track from acquiring a process hook. // // This is dangerous if the track is MONO as that requires // special case handling due to implicit channel duplication. // Stereo or Multichannel should actually be fine here. - state->hook = getProcessHook(PROCESSTYPE_NORESAMPLEONETRACK, - t.mMixerChannelCount, t.mMixerInFormat, t.mMixerFormat); + mHook = getProcessHook(PROCESSTYPE_NORESAMPLEONETRACK, + t->mMixerChannelCount, t->mMixerInFormat, t->mMixerFormat); } } } } } - ALOGV("mixer configuration change: %d activeTracks (%08x) " + ALOGV("mixer configuration change: %zu " "all16BitsStereoNoResample=%d, resampling=%d, volumeRamp=%d", - countActiveTracks, state->enabledTracks, - all16BitsStereoNoResample, resampling, volumeRamp); + mEnabled.size(), all16BitsStereoNoResample, resampling, volumeRamp); - state->hook(state); + process(); // Now that the volume ramp has been done, set optimal state and // track hooks for subsequent mixer process - if (countActiveTracks > 0) { + if (mEnabled.size() > 0) { bool allMuted = true; - uint32_t en = state->enabledTracks; - while (en) { - const int i = 31 - __builtin_clz(en); - en &= ~(1<tracks[i]; - if (!t.doesResample() && t.volumeRL == 0) { - t.needs |= NEEDS_MUTE; - t.hook = track__nop; + + for (const int name : mEnabled) { + const std::shared_ptr &t = mTracks[name]; + if (!t->doesResample() && t->volumeRL == 0) { + t->needs |= NEEDS_MUTE; + t->hook = &Track::track__nop; } else { allMuted = false; } } if (allMuted) { - state->hook = process__nop; + mHook = &AudioMixer::process__nop; } else if (all16BitsStereoNoResample) { - if (countActiveTracks == 1) { - const int i = 31 - __builtin_clz(state->enabledTracks); - track_t& t = state->tracks[i]; + if (mEnabled.size() == 1) { + //const int i = 31 - __builtin_clz(enabledTracks); + const std::shared_ptr &t = mTracks[mEnabled[0]]; // Muted single tracks handled by allMuted above. - state->hook = getProcessHook(PROCESSTYPE_NORESAMPLEONETRACK, - t.mMixerChannelCount, t.mMixerInFormat, t.mMixerFormat); + mHook = getProcessHook(PROCESSTYPE_NORESAMPLEONETRACK, + t->mMixerChannelCount, t->mMixerInFormat, t->mMixerFormat); } } } } - -void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFrameCount, - int32_t* temp, int32_t* aux) +void AudioMixer::Track::track__genericResample( + int32_t* out, size_t outFrameCount, int32_t* temp, int32_t* aux) { ALOGVV("track__genericResample\n"); - t->resampler->setSampleRate(t->sampleRate); + mResampler->setSampleRate(sampleRate); // ramp gain - resample to temp buffer and scale/mix in 2nd step if (aux != NULL) { // always resample with unity gain when sending to auxiliary buffer to be able // to apply send level after resampling - t->resampler->setVolume(UNITY_GAIN_FLOAT, UNITY_GAIN_FLOAT); - memset(temp, 0, outFrameCount * t->mMixerChannelCount * sizeof(int32_t)); - t->resampler->resample(temp, outFrameCount, t->bufferProvider); - if (CC_UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc)) { - volumeRampStereo(t, out, outFrameCount, temp, aux); + mResampler->setVolume(UNITY_GAIN_FLOAT, UNITY_GAIN_FLOAT); + memset(temp, 0, outFrameCount * mMixerChannelCount * sizeof(int32_t)); + mResampler->resample(temp, outFrameCount, bufferProvider); + if (CC_UNLIKELY(volumeInc[0]|volumeInc[1]|auxInc)) { + volumeRampStereo(out, outFrameCount, temp, aux); } else { - volumeStereo(t, out, outFrameCount, temp, aux); + volumeStereo(out, outFrameCount, temp, aux); } } else { - if (CC_UNLIKELY(t->volumeInc[0]|t->volumeInc[1])) { - t->resampler->setVolume(UNITY_GAIN_FLOAT, UNITY_GAIN_FLOAT); + if (CC_UNLIKELY(volumeInc[0]|volumeInc[1])) { + mResampler->setVolume(UNITY_GAIN_FLOAT, UNITY_GAIN_FLOAT); memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t)); - t->resampler->resample(temp, outFrameCount, t->bufferProvider); - volumeRampStereo(t, out, outFrameCount, temp, aux); + mResampler->resample(temp, outFrameCount, bufferProvider); + volumeRampStereo(out, outFrameCount, temp, aux); } // constant gain else { - t->resampler->setVolume(t->mVolume[0], t->mVolume[1]); - t->resampler->resample(out, outFrameCount, t->bufferProvider); + mResampler->setVolume(mVolume[0], mVolume[1]); + mResampler->resample(out, outFrameCount, bufferProvider); } } } -void AudioMixer::track__nop(track_t* t __unused, int32_t* out __unused, +void AudioMixer::Track::track__nop(int32_t* out __unused, size_t outFrameCount __unused, int32_t* temp __unused, int32_t* aux __unused) { } -void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, - int32_t* aux) +void AudioMixer::Track::volumeRampStereo( + int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux) { - int32_t vl = t->prevVolume[0]; - int32_t vr = t->prevVolume[1]; - const int32_t vlInc = t->volumeInc[0]; - const int32_t vrInc = t->volumeInc[1]; + int32_t vl = prevVolume[0]; + int32_t vr = prevVolume[1]; + const int32_t vlInc = volumeInc[0]; + const int32_t vrInc = volumeInc[1]; //ALOGD("[0] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d", - // t, vlInc/65536.0f, vl/65536.0f, t->volume[0], + // t, vlInc/65536.0f, vl/65536.0f, volume[0], // (vl + vlInc*frameCount)/65536.0f, frameCount); // ramp volume if (CC_UNLIKELY(aux != NULL)) { - int32_t va = t->prevAuxLevel; - const int32_t vaInc = t->auxInc; + int32_t va = prevAuxLevel; + const int32_t vaInc = auxInc; int32_t l; int32_t r; @@ -1161,7 +1040,7 @@ void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, i vr += vrInc; va += vaInc; } while (--frameCount); - t->prevAuxLevel = va; + prevAuxLevel = va; } else { do { *out++ += (vl >> 16) * (*temp++ >> 12); @@ -1170,19 +1049,19 @@ void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, i vr += vrInc; } while (--frameCount); } - t->prevVolume[0] = vl; - t->prevVolume[1] = vr; - t->adjustVolumeRamp(aux != NULL); + prevVolume[0] = vl; + prevVolume[1] = vr; + adjustVolumeRamp(aux != NULL); } -void AudioMixer::volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, - int32_t* aux) +void AudioMixer::Track::volumeStereo( + int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux) { - const int16_t vl = t->volume[0]; - const int16_t vr = t->volume[1]; + const int16_t vl = volume[0]; + const int16_t vr = volume[1]; if (CC_UNLIKELY(aux != NULL)) { - const int16_t va = t->auxLevel; + const int16_t va = auxLevel; do { int16_t l = (int16_t)(*temp++ >> 12); int16_t r = (int16_t)(*temp++ >> 12); @@ -1204,25 +1083,25 @@ void AudioMixer::volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32 } } -void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount, - int32_t* temp __unused, int32_t* aux) +void AudioMixer::Track::track__16BitsStereo( + int32_t* out, size_t frameCount, int32_t* temp __unused, int32_t* aux) { ALOGVV("track__16BitsStereo\n"); - const int16_t *in = static_cast(t->in); + const int16_t *in = static_cast(mIn); if (CC_UNLIKELY(aux != NULL)) { int32_t l; int32_t r; // ramp gain - if (CC_UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc)) { - int32_t vl = t->prevVolume[0]; - int32_t vr = t->prevVolume[1]; - int32_t va = t->prevAuxLevel; - const int32_t vlInc = t->volumeInc[0]; - const int32_t vrInc = t->volumeInc[1]; - const int32_t vaInc = t->auxInc; + if (CC_UNLIKELY(volumeInc[0]|volumeInc[1]|auxInc)) { + int32_t vl = prevVolume[0]; + int32_t vr = prevVolume[1]; + int32_t va = prevAuxLevel; + const int32_t vlInc = volumeInc[0]; + const int32_t vrInc = volumeInc[1]; + const int32_t vaInc = auxInc; // ALOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d", - // t, vlInc/65536.0f, vl/65536.0f, t->volume[0], + // t, vlInc/65536.0f, vl/65536.0f, volume[0], // (vl + vlInc*frameCount)/65536.0f, frameCount); do { @@ -1236,16 +1115,16 @@ void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount va += vaInc; } while (--frameCount); - t->prevVolume[0] = vl; - t->prevVolume[1] = vr; - t->prevAuxLevel = va; - t->adjustVolumeRamp(true); + prevVolume[0] = vl; + prevVolume[1] = vr; + prevAuxLevel = va; + adjustVolumeRamp(true); } // constant gain else { - const uint32_t vrl = t->volumeRL; - const int16_t va = (int16_t)t->auxLevel; + const uint32_t vrl = volumeRL; + const int16_t va = (int16_t)auxLevel; do { uint32_t rl = *reinterpret_cast(in); int16_t a = (int16_t)(((int32_t)in[0] + in[1]) >> 1); @@ -1259,14 +1138,14 @@ void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount } } else { // ramp gain - if (CC_UNLIKELY(t->volumeInc[0]|t->volumeInc[1])) { - int32_t vl = t->prevVolume[0]; - int32_t vr = t->prevVolume[1]; - const int32_t vlInc = t->volumeInc[0]; - const int32_t vrInc = t->volumeInc[1]; + if (CC_UNLIKELY(volumeInc[0]|volumeInc[1])) { + int32_t vl = prevVolume[0]; + int32_t vr = prevVolume[1]; + const int32_t vlInc = volumeInc[0]; + const int32_t vrInc = volumeInc[1]; // ALOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d", - // t, vlInc/65536.0f, vl/65536.0f, t->volume[0], + // t, vlInc/65536.0f, vl/65536.0f, volume[0], // (vl + vlInc*frameCount)/65536.0f, frameCount); do { @@ -1276,14 +1155,14 @@ void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount vr += vrInc; } while (--frameCount); - t->prevVolume[0] = vl; - t->prevVolume[1] = vr; - t->adjustVolumeRamp(false); + prevVolume[0] = vl; + prevVolume[1] = vr; + adjustVolumeRamp(false); } // constant gain else { - const uint32_t vrl = t->volumeRL; + const uint32_t vrl = volumeRL; do { uint32_t rl = *reinterpret_cast(in); in += 2; @@ -1293,27 +1172,27 @@ void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount } while (--frameCount); } } - t->in = in; + mIn = in; } -void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount, - int32_t* temp __unused, int32_t* aux) +void AudioMixer::Track::track__16BitsMono( + int32_t* out, size_t frameCount, int32_t* temp __unused, int32_t* aux) { ALOGVV("track__16BitsMono\n"); - const int16_t *in = static_cast(t->in); + const int16_t *in = static_cast(mIn); if (CC_UNLIKELY(aux != NULL)) { // ramp gain - if (CC_UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc)) { - int32_t vl = t->prevVolume[0]; - int32_t vr = t->prevVolume[1]; - int32_t va = t->prevAuxLevel; - const int32_t vlInc = t->volumeInc[0]; - const int32_t vrInc = t->volumeInc[1]; - const int32_t vaInc = t->auxInc; + if (CC_UNLIKELY(volumeInc[0]|volumeInc[1]|auxInc)) { + int32_t vl = prevVolume[0]; + int32_t vr = prevVolume[1]; + int32_t va = prevAuxLevel; + const int32_t vlInc = volumeInc[0]; + const int32_t vrInc = volumeInc[1]; + const int32_t vaInc = auxInc; // ALOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d", - // t, vlInc/65536.0f, vl/65536.0f, t->volume[0], + // t, vlInc/65536.0f, vl/65536.0f, volume[0], // (vl + vlInc*frameCount)/65536.0f, frameCount); do { @@ -1326,16 +1205,16 @@ void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount, va += vaInc; } while (--frameCount); - t->prevVolume[0] = vl; - t->prevVolume[1] = vr; - t->prevAuxLevel = va; - t->adjustVolumeRamp(true); + prevVolume[0] = vl; + prevVolume[1] = vr; + prevAuxLevel = va; + adjustVolumeRamp(true); } // constant gain else { - const int16_t vl = t->volume[0]; - const int16_t vr = t->volume[1]; - const int16_t va = (int16_t)t->auxLevel; + const int16_t vl = volume[0]; + const int16_t vr = volume[1]; + const int16_t va = (int16_t)auxLevel; do { int16_t l = *in++; out[0] = mulAdd(l, vl, out[0]); @@ -1347,14 +1226,14 @@ void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount, } } else { // ramp gain - if (CC_UNLIKELY(t->volumeInc[0]|t->volumeInc[1])) { - int32_t vl = t->prevVolume[0]; - int32_t vr = t->prevVolume[1]; - const int32_t vlInc = t->volumeInc[0]; - const int32_t vrInc = t->volumeInc[1]; + if (CC_UNLIKELY(volumeInc[0]|volumeInc[1])) { + int32_t vl = prevVolume[0]; + int32_t vr = prevVolume[1]; + const int32_t vlInc = volumeInc[0]; + const int32_t vrInc = volumeInc[1]; // ALOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d", - // t, vlInc/65536.0f, vl/65536.0f, t->volume[0], + // t, vlInc/65536.0f, vl/65536.0f, volume[0], // (vl + vlInc*frameCount)/65536.0f, frameCount); do { @@ -1365,14 +1244,14 @@ void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount, vr += vrInc; } while (--frameCount); - t->prevVolume[0] = vl; - t->prevVolume[1] = vr; - t->adjustVolumeRamp(false); + prevVolume[0] = vl; + prevVolume[1] = vr; + adjustVolumeRamp(false); } // constant gain else { - const int16_t vl = t->volume[0]; - const int16_t vr = t->volume[1]; + const int16_t vl = volume[0]; + const int16_t vr = volume[1]; do { int16_t l = *in++; out[0] = mulAdd(l, vl, out[0]); @@ -1381,274 +1260,214 @@ void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount, } while (--frameCount); } } - t->in = in; + mIn = in; } // no-op case -void AudioMixer::process__nop(state_t* state) +void AudioMixer::process__nop() { ALOGVV("process__nop\n"); - uint32_t e0 = state->enabledTracks; - while (e0) { + + for (const auto &pair : mGroups) { // process by group of tracks with same output buffer to // avoid multiple memset() on same buffer - uint32_t e1 = e0, e2 = e0; - int i = 31 - __builtin_clz(e1); - { - track_t& t1 = state->tracks[i]; - e2 &= ~(1<tracks[i]; - if (CC_UNLIKELY(t2.mainBuffer != t1.mainBuffer)) { - e1 &= ~(1<frameCount * t1.mMixerChannelCount - * audio_bytes_per_sample(t1.mMixerFormat)); - } - - while (e1) { - i = 31 - __builtin_clz(e1); - e1 &= ~(1<tracks[i]; - size_t outFrames = state->frameCount; - while (outFrames) { - t3.buffer.frameCount = outFrames; - t3.bufferProvider->getNextBuffer(&t3.buffer); - if (t3.buffer.raw == NULL) break; - outFrames -= t3.buffer.frameCount; - t3.bufferProvider->releaseBuffer(&t3.buffer); - } + const auto &group = pair.second; + + const std::shared_ptr &t = mTracks[group[0]]; + memset(t->mainBuffer, 0, + mFrameCount * t->mMixerChannelCount + * audio_bytes_per_sample(t->mMixerFormat)); + + // now consume data + for (const int name : group) { + const std::shared_ptr &t = mTracks[name]; + size_t outFrames = mFrameCount; + while (outFrames) { + t->buffer.frameCount = outFrames; + t->bufferProvider->getNextBuffer(&t->buffer); + if (t->buffer.raw == NULL) break; + outFrames -= t->buffer.frameCount; + t->bufferProvider->releaseBuffer(&t->buffer); } } } } // generic code without resampling -void AudioMixer::process__genericNoResampling(state_t* state) +void AudioMixer::process__genericNoResampling() { ALOGVV("process__genericNoResampling\n"); int32_t outTemp[BLOCKSIZE * MAX_NUM_CHANNELS] __attribute__((aligned(32))); - // acquire each track's buffer - uint32_t enabledTracks = state->enabledTracks; - uint32_t e0 = enabledTracks; - while (e0) { - const int i = 31 - __builtin_clz(e0); - e0 &= ~(1<tracks[i]; - t.buffer.frameCount = state->frameCount; - t.bufferProvider->getNextBuffer(&t.buffer); - t.frameCount = t.buffer.frameCount; - t.in = t.buffer.raw; - } - - e0 = enabledTracks; - while (e0) { - // process by group of tracks with same output buffer to - // optimize cache use - uint32_t e1 = e0, e2 = e0; - int j = 31 - __builtin_clz(e1); - track_t& t1 = state->tracks[j]; - e2 &= ~(1<tracks[j]; - if (CC_UNLIKELY(t2.mainBuffer != t1.mainBuffer)) { - e1 &= ~(1< &t = mTracks[name]; + t->buffer.frameCount = mFrameCount; + t->bufferProvider->getNextBuffer(&t->buffer); + t->frameCount = t->buffer.frameCount; + t->mIn = t->buffer.raw; } - e0 &= ~(e1); - // this assumes output 16 bits stereo, no resampling - int32_t *out = t1.mainBuffer; + + int32_t *out = (int *)pair.first; size_t numFrames = 0; do { - const size_t frameCount = min((size_t)BLOCKSIZE, state->frameCount - numFrames); + const size_t frameCount = std::min((size_t)BLOCKSIZE, mFrameCount - numFrames); memset(outTemp, 0, sizeof(outTemp)); - e2 = e1; - while (e2) { - const int i = 31 - __builtin_clz(e2); - e2 &= ~(1<tracks[i]; - size_t outFrames = frameCount; + for (const int name : group) { + const std::shared_ptr &t = mTracks[name]; int32_t *aux = NULL; - if (CC_UNLIKELY(t.needs & NEEDS_AUX)) { - aux = t.auxBuffer + numFrames; + if (CC_UNLIKELY(t->needs & NEEDS_AUX)) { + aux = t->auxBuffer + numFrames; } - while (outFrames) { - // t.in == NULL can happen if the track was flushed just after having + for (int outFrames = frameCount; outFrames > 0; ) { + // t->in == nullptr can happen if the track was flushed just after having // been enabled for mixing. - if (t.in == NULL) { - enabledTracks &= ~(1<mIn == nullptr) { break; } - size_t inFrames = (t.frameCount > outFrames)?outFrames:t.frameCount; + size_t inFrames = (t->frameCount > outFrames)?outFrames:t->frameCount; if (inFrames > 0) { - t.hook(&t, outTemp + (frameCount - outFrames) * t.mMixerChannelCount, - inFrames, state->resampleTemp, aux); - t.frameCount -= inFrames; + (t.get()->*t->hook)( + outTemp + (frameCount - outFrames) * t->mMixerChannelCount, + inFrames, mResampleTemp.get() /* naked ptr */, aux); + t->frameCount -= inFrames; outFrames -= inFrames; if (CC_UNLIKELY(aux != NULL)) { aux += inFrames; } } - if (t.frameCount == 0 && outFrames) { - t.bufferProvider->releaseBuffer(&t.buffer); - t.buffer.frameCount = (state->frameCount - numFrames) - + if (t->frameCount == 0 && outFrames) { + t->bufferProvider->releaseBuffer(&t->buffer); + t->buffer.frameCount = (mFrameCount - numFrames) - (frameCount - outFrames); - t.bufferProvider->getNextBuffer(&t.buffer); - t.in = t.buffer.raw; - if (t.in == NULL) { - enabledTracks &= ~(1<bufferProvider->getNextBuffer(&t->buffer); + t->mIn = t->buffer.raw; + if (t->mIn == nullptr) { break; } - t.frameCount = t.buffer.frameCount; + t->frameCount = t->buffer.frameCount; } } } - convertMixerFormat(out, t1.mMixerFormat, outTemp, t1.mMixerInFormat, - frameCount * t1.mMixerChannelCount); + const std::shared_ptr &t1 = mTracks[group[0]]; + convertMixerFormat(out, t1->mMixerFormat, outTemp, t1->mMixerInFormat, + frameCount * t1->mMixerChannelCount); // TODO: fix ugly casting due to choice of out pointer type out = reinterpret_cast((uint8_t*)out - + frameCount * t1.mMixerChannelCount - * audio_bytes_per_sample(t1.mMixerFormat)); + + frameCount * t1->mMixerChannelCount + * audio_bytes_per_sample(t1->mMixerFormat)); numFrames += frameCount; - } while (numFrames < state->frameCount); - } + } while (numFrames < mFrameCount); - // release each track's buffer - e0 = enabledTracks; - while (e0) { - const int i = 31 - __builtin_clz(e0); - e0 &= ~(1<tracks[i]; - t.bufferProvider->releaseBuffer(&t.buffer); + // release each track's buffer + for (const int name : group) { + const std::shared_ptr &t = mTracks[name]; + t->bufferProvider->releaseBuffer(&t->buffer); + } } } - // generic code with resampling -void AudioMixer::process__genericResampling(state_t* state) +void AudioMixer::process__genericResampling() { ALOGVV("process__genericResampling\n"); - // this const just means that local variable outTemp doesn't change - int32_t* const outTemp = state->outputTemp; - size_t numFrames = state->frameCount; - - uint32_t e0 = state->enabledTracks; - while (e0) { - // process by group of tracks with same output buffer - // to optimize cache use - uint32_t e1 = e0, e2 = e0; - int j = 31 - __builtin_clz(e1); - track_t& t1 = state->tracks[j]; - e2 &= ~(1<tracks[j]; - if (CC_UNLIKELY(t2.mainBuffer != t1.mainBuffer)) { - e1 &= ~(1<frameCount); - while (e1) { - const int i = 31 - __builtin_clz(e1); - e1 &= ~(1<tracks[i]; + int32_t * const outTemp = mOutputTemp.get(); // naked ptr + size_t numFrames = mFrameCount; + + for (const auto &pair : mGroups) { + const auto &group = pair.second; + const std::shared_ptr &t1 = mTracks[group[0]]; + + // clear temp buffer + memset(outTemp, 0, sizeof(*outTemp) * t1->mMixerChannelCount * mFrameCount); + for (const int name : group) { + const std::shared_ptr &t = mTracks[name]; int32_t *aux = NULL; - if (CC_UNLIKELY(t.needs & NEEDS_AUX)) { - aux = t.auxBuffer; + if (CC_UNLIKELY(t->needs & NEEDS_AUX)) { + aux = t->auxBuffer; } // this is a little goofy, on the resampling case we don't // acquire/release the buffers because it's done by // the resampler. - if (t.needs & NEEDS_RESAMPLE) { - t.hook(&t, outTemp, numFrames, state->resampleTemp, aux); + if (t->needs & NEEDS_RESAMPLE) { + (t.get()->*t->hook)(outTemp, numFrames, mResampleTemp.get() /* naked ptr */, aux); } else { size_t outFrames = 0; while (outFrames < numFrames) { - t.buffer.frameCount = numFrames - outFrames; - t.bufferProvider->getNextBuffer(&t.buffer); - t.in = t.buffer.raw; - // t.in == NULL can happen if the track was flushed just after having + t->buffer.frameCount = numFrames - outFrames; + t->bufferProvider->getNextBuffer(&t->buffer); + t->mIn = t->buffer.raw; + // t->mIn == nullptr can happen if the track was flushed just after having // been enabled for mixing. - if (t.in == NULL) break; + if (t->mIn == nullptr) break; if (CC_UNLIKELY(aux != NULL)) { aux += outFrames; } - t.hook(&t, outTemp + outFrames * t.mMixerChannelCount, t.buffer.frameCount, - state->resampleTemp, aux); - outFrames += t.buffer.frameCount; - t.bufferProvider->releaseBuffer(&t.buffer); + (t.get()->*t->hook)( + outTemp + outFrames * t->mMixerChannelCount, t->buffer.frameCount, + mResampleTemp.get() /* naked ptr */, aux); + outFrames += t->buffer.frameCount; + t->bufferProvider->releaseBuffer(&t->buffer); } } } - convertMixerFormat(out, t1.mMixerFormat, - outTemp, t1.mMixerInFormat, numFrames * t1.mMixerChannelCount); + convertMixerFormat(t1->mainBuffer, t1->mMixerFormat, + outTemp, t1->mMixerInFormat, numFrames * t1->mMixerChannelCount); } } // one track, 16 bits stereo without resampling is the most common case -void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state) +void AudioMixer::process__oneTrack16BitsStereoNoResampling() { - ALOGVV("process__OneTrack16BitsStereoNoResampling\n"); - // This method is only called when state->enabledTracks has exactly - // one bit set. The asserts below would verify this, but are commented out - // since the whole point of this method is to optimize performance. - //ALOG_ASSERT(0 != state->enabledTracks, "no tracks enabled"); - const int i = 31 - __builtin_clz(state->enabledTracks); - //ALOG_ASSERT((1 << i) == state->enabledTracks, "more than 1 track enabled"); - const track_t& t = state->tracks[i]; - - AudioBufferProvider::Buffer& b(t.buffer); - - int32_t* out = t.mainBuffer; + ALOGVV("process__oneTrack16BitsStereoNoResampling\n"); + LOG_ALWAYS_FATAL_IF(mEnabled.size() != 0, + "%zu != 1 tracks enabled", mEnabled.size()); + const int name = mEnabled[0]; + const std::shared_ptr &t = mTracks[name]; + + AudioBufferProvider::Buffer& b(t->buffer); + + int32_t* out = t->mainBuffer; float *fout = reinterpret_cast(out); - size_t numFrames = state->frameCount; + size_t numFrames = mFrameCount; - const int16_t vl = t.volume[0]; - const int16_t vr = t.volume[1]; - const uint32_t vrl = t.volumeRL; + const int16_t vl = t->volume[0]; + const int16_t vr = t->volume[1]; + const uint32_t vrl = t->volumeRL; while (numFrames) { b.frameCount = numFrames; - t.bufferProvider->getNextBuffer(&b); + t->bufferProvider->getNextBuffer(&b); const int16_t *in = b.i16; // in == NULL can happen if the track was flushed just after having // been enabled for mixing. if (in == NULL || (((uintptr_t)in) & 3)) { - if ( AUDIO_FORMAT_PCM_FLOAT == t.mMixerFormat ) { + if ( AUDIO_FORMAT_PCM_FLOAT == t->mMixerFormat ) { memset((char*)fout, 0, numFrames - * t.mMixerChannelCount * audio_bytes_per_sample(t.mMixerFormat)); + * t->mMixerChannelCount * audio_bytes_per_sample(t->mMixerFormat)); } else { memset((char*)out, 0, numFrames - * t.mMixerChannelCount * audio_bytes_per_sample(t.mMixerFormat)); + * t->mMixerChannelCount * audio_bytes_per_sample(t->mMixerFormat)); } ALOGE_IF((((uintptr_t)in) & 3), - "process__OneTrack16BitsStereoNoResampling: misaligned buffer" + "process__oneTrack16BitsStereoNoResampling: misaligned buffer" " %p track %d, channels %d, needs %08x, volume %08x vfl %f vfr %f", - in, i, t.channelCount, t.needs, vrl, t.mVolume[0], t.mVolume[1]); + in, name, t->channelCount, t->needs, vrl, t->mVolume[0], t->mVolume[1]); return; } size_t outFrames = b.frameCount; - switch (t.mMixerFormat) { + switch (t->mMixerFormat) { case AUDIO_FORMAT_PCM_FLOAT: do { uint32_t rl = *reinterpret_cast(in); @@ -1686,10 +1505,10 @@ void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state) } break; default: - LOG_ALWAYS_FATAL("bad mixer format: %d", t.mMixerFormat); + LOG_ALWAYS_FATAL("bad mixer format: %d", t->mMixerFormat); } numFrames -= b.frameCount; - t.bufferProvider->releaseBuffer(&b); + t->bufferProvider->releaseBuffer(&b); } } @@ -1800,42 +1619,42 @@ static void volumeMulti(uint32_t channels, TO* out, size_t frameCount, */ template -void AudioMixer::volumeMix(TO *out, size_t outFrames, - const TI *in, TA *aux, bool ramp, AudioMixer::track_t *t) +void AudioMixer::Track::volumeMix(TO *out, size_t outFrames, + const TI *in, TA *aux, bool ramp) { if (USEFLOATVOL) { if (ramp) { - volumeRampMulti(t->mMixerChannelCount, out, outFrames, in, aux, - t->mPrevVolume, t->mVolumeInc, + volumeRampMulti(mMixerChannelCount, out, outFrames, in, aux, + mPrevVolume, mVolumeInc, #ifdef FLOAT_AUX - &t->mPrevAuxLevel, t->mAuxInc + &mPrevAuxLevel, mAuxInc #else - &t->prevAuxLevel, t->auxInc + &prevAuxLevel, auxInc #endif ); if (ADJUSTVOL) { - t->adjustVolumeRamp(aux != NULL, true); + adjustVolumeRamp(aux != NULL, true); } } else { - volumeMulti(t->mMixerChannelCount, out, outFrames, in, aux, - t->mVolume, + volumeMulti(mMixerChannelCount, out, outFrames, in, aux, + mVolume, #ifdef FLOAT_AUX - t->mAuxLevel + mAuxLevel #else - t->auxLevel + auxLevel #endif ); } } else { if (ramp) { - volumeRampMulti(t->mMixerChannelCount, out, outFrames, in, aux, - t->prevVolume, t->volumeInc, &t->prevAuxLevel, t->auxInc); + volumeRampMulti(mMixerChannelCount, out, outFrames, in, aux, + prevVolume, volumeInc, &prevAuxLevel, auxInc); if (ADJUSTVOL) { - t->adjustVolumeRamp(aux != NULL); + adjustVolumeRamp(aux != NULL); } } else { - volumeMulti(t->mMixerChannelCount, out, outFrames, in, aux, - t->volume, t->auxLevel); + volumeMulti(mMixerChannelCount, out, outFrames, in, aux, + volume, auxLevel); } } } @@ -1850,19 +1669,18 @@ void AudioMixer::volumeMix(TO *out, size_t outFrames, * TA: int32_t (Q4.27) */ template -void AudioMixer::process_NoResampleOneTrack(state_t* state) +void AudioMixer::process__noResampleOneTrack() { - ALOGVV("process_NoResampleOneTrack\n"); - // CLZ is faster than CTZ on ARM, though really not sure if true after 31 - clz. - const int i = 31 - __builtin_clz(state->enabledTracks); - ALOG_ASSERT((1 << i) == state->enabledTracks, "more than 1 track enabled"); - track_t *t = &state->tracks[i]; + ALOGVV("process__noResampleOneTrack\n"); + LOG_ALWAYS_FATAL_IF(mEnabled.size() != 1, + "%zu != 1 tracks enabled", mEnabled.size()); + const std::shared_ptr &t = mTracks[mEnabled[0]]; const uint32_t channels = t->mMixerChannelCount; TO* out = reinterpret_cast(t->mainBuffer); TA* aux = reinterpret_cast(t->auxBuffer); const bool ramp = t->needsRamp(); - for (size_t numFrames = state->frameCount; numFrames; ) { + for (size_t numFrames = mFrameCount; numFrames > 0; ) { AudioBufferProvider::Buffer& b(t->buffer); // get input buffer b.frameCount = numFrames; @@ -1874,15 +1692,15 @@ void AudioMixer::process_NoResampleOneTrack(state_t* state) if (in == NULL || (((uintptr_t)in) & 3)) { memset(out, 0, numFrames * channels * audio_bytes_per_sample(t->mMixerFormat)); - ALOGE_IF((((uintptr_t)in) & 3), "process_NoResampleOneTrack: bus error: " + ALOGE_IF((((uintptr_t)in) & 3), "process__noResampleOneTrack: bus error: " "buffer %p track %p, channels %d, needs %#x", - in, t, t->channelCount, t->needs); + in, &t, t->channelCount, t->needs); return; } const size_t outFrames = b.frameCount; - volumeMix::value /* USEFLOATVOL */, false /* ADJUSTVOL */> ( - out, outFrames, in, aux, ramp, t); + t->volumeMix::value /* USEFLOATVOL */, false /* ADJUSTVOL */> ( + out, outFrames, in, aux, ramp); out += outFrames * channels; if (aux != NULL) { @@ -1907,30 +1725,30 @@ void AudioMixer::process_NoResampleOneTrack(state_t* state) * TA: int32_t (Q4.27) or float */ template -void AudioMixer::track__Resample(track_t* t, TO* out, size_t outFrameCount, TO* temp, TA* aux) +void AudioMixer::Track::track__Resample(TO* out, size_t outFrameCount, TO* temp, TA* aux) { ALOGVV("track__Resample\n"); - t->resampler->setSampleRate(t->sampleRate); - const bool ramp = t->needsRamp(); + mResampler->setSampleRate(sampleRate); + const bool ramp = needsRamp(); if (ramp || aux != NULL) { // if ramp: resample with unity gain to temp buffer and scale/mix in 2nd step. // if aux != NULL: resample with unity gain to temp buffer then apply send level. - t->resampler->setVolume(UNITY_GAIN_FLOAT, UNITY_GAIN_FLOAT); - memset(temp, 0, outFrameCount * t->mMixerChannelCount * sizeof(TO)); - t->resampler->resample((int32_t*)temp, outFrameCount, t->bufferProvider); + mResampler->setVolume(UNITY_GAIN_FLOAT, UNITY_GAIN_FLOAT); + memset(temp, 0, outFrameCount * mMixerChannelCount * sizeof(TO)); + mResampler->resample((int32_t*)temp, outFrameCount, bufferProvider); volumeMix::value /* USEFLOATVOL */, true /* ADJUSTVOL */>( - out, outFrameCount, temp, aux, ramp, t); + out, outFrameCount, temp, aux, ramp); } else { // constant volume gain - t->resampler->setVolume(t->mVolume[0], t->mVolume[1]); - t->resampler->resample((int32_t*)out, outFrameCount, t->bufferProvider); + mResampler->setVolume(mVolume[0], mVolume[1]); + mResampler->resample((int32_t*)out, outFrameCount, bufferProvider); } } /* This track hook is called to mix a track, when no resampling is required. - * The input buffer should be present in t->in. + * The input buffer should be present in in. * * MIXTYPE (see AudioMixerOps.h MIXTYPE_* enumeration) * TO: int32_t (Q4.27) or float @@ -1938,25 +1756,25 @@ void AudioMixer::track__Resample(track_t* t, TO* out, size_t outFrameCount, TO* * TA: int32_t (Q4.27) or float */ template -void AudioMixer::track__NoResample(track_t* t, TO* out, size_t frameCount, - TO* temp __unused, TA* aux) +void AudioMixer::Track::track__NoResample(TO* out, size_t frameCount, TO* temp __unused, TA* aux) { ALOGVV("track__NoResample\n"); - const TI *in = static_cast(t->in); + const TI *in = static_cast(mIn); volumeMix::value /* USEFLOATVOL */, true /* ADJUSTVOL */>( - out, frameCount, in, aux, t->needsRamp(), t); + out, frameCount, in, aux, needsRamp()); // MIXTYPE_MONOEXPAND reads a single input channel and expands to NCHAN output channels. // MIXTYPE_MULTI reads NCHAN input channels and places to NCHAN output channels. - in += (MIXTYPE == MIXTYPE_MONOEXPAND) ? frameCount : frameCount * t->mMixerChannelCount; - t->in = in; + in += (MIXTYPE == MIXTYPE_MONOEXPAND) ? frameCount : frameCount * mMixerChannelCount; + mIn = in; } /* The Mixer engine generates either int32_t (Q4_27) or float data. * We use this function to convert the engine buffers * to the desired mixer output format, either int16_t (Q.15) or float. */ +/* static */ void AudioMixer::convertMixerFormat(void *out, audio_format_t mixerOutFormat, void *in, audio_format_t mixerInFormat, size_t sampleCount) { @@ -1995,19 +1813,20 @@ void AudioMixer::convertMixerFormat(void *out, audio_format_t mixerOutFormat, /* Returns the proper track hook to use for mixing the track into the output buffer. */ -AudioMixer::hook_t AudioMixer::getTrackHook(int trackType, uint32_t channelCount, +/* static */ +AudioMixer::hook_t AudioMixer::Track::getTrackHook(int trackType, uint32_t channelCount, audio_format_t mixerInFormat, audio_format_t mixerOutFormat __unused) { if (!kUseNewMixer && channelCount == FCC_2 && mixerInFormat == AUDIO_FORMAT_PCM_16_BIT) { switch (trackType) { case TRACKTYPE_NOP: - return track__nop; + return &Track::track__nop; case TRACKTYPE_RESAMPLE: - return track__genericResample; + return &Track::track__genericResample; case TRACKTYPE_NORESAMPLEMONO: - return track__16BitsMono; + return &Track::track__16BitsMono; case TRACKTYPE_NORESAMPLE: - return track__16BitsStereo; + return &Track::track__16BitsStereo; default: LOG_ALWAYS_FATAL("bad trackType: %d", trackType); break; @@ -2016,14 +1835,14 @@ AudioMixer::hook_t AudioMixer::getTrackHook(int trackType, uint32_t channelCount LOG_ALWAYS_FATAL_IF(channelCount > MAX_NUM_CHANNELS); switch (trackType) { case TRACKTYPE_NOP: - return track__nop; + return &Track::track__nop; case TRACKTYPE_RESAMPLE: switch (mixerInFormat) { case AUDIO_FORMAT_PCM_FLOAT: - return (AudioMixer::hook_t)track__Resample< + return (AudioMixer::hook_t) &Track::track__Resample< MIXTYPE_MULTI, float /*TO*/, float /*TI*/, TYPE_AUX>; case AUDIO_FORMAT_PCM_16_BIT: - return (AudioMixer::hook_t)track__Resample< + return (AudioMixer::hook_t) &Track::track__Resample< MIXTYPE_MULTI, int32_t /*TO*/, int16_t /*TI*/, TYPE_AUX>; default: LOG_ALWAYS_FATAL("bad mixerInFormat: %#x", mixerInFormat); @@ -2033,10 +1852,10 @@ AudioMixer::hook_t AudioMixer::getTrackHook(int trackType, uint32_t channelCount case TRACKTYPE_NORESAMPLEMONO: switch (mixerInFormat) { case AUDIO_FORMAT_PCM_FLOAT: - return (AudioMixer::hook_t)track__NoResample< + return (AudioMixer::hook_t) &Track::track__NoResample< MIXTYPE_MONOEXPAND, float /*TO*/, float /*TI*/, TYPE_AUX>; case AUDIO_FORMAT_PCM_16_BIT: - return (AudioMixer::hook_t)track__NoResample< + return (AudioMixer::hook_t) &Track::track__NoResample< MIXTYPE_MONOEXPAND, int32_t /*TO*/, int16_t /*TI*/, TYPE_AUX>; default: LOG_ALWAYS_FATAL("bad mixerInFormat: %#x", mixerInFormat); @@ -2046,10 +1865,10 @@ AudioMixer::hook_t AudioMixer::getTrackHook(int trackType, uint32_t channelCount case TRACKTYPE_NORESAMPLE: switch (mixerInFormat) { case AUDIO_FORMAT_PCM_FLOAT: - return (AudioMixer::hook_t)track__NoResample< + return (AudioMixer::hook_t) &Track::track__NoResample< MIXTYPE_MULTI, float /*TO*/, float /*TI*/, TYPE_AUX>; case AUDIO_FORMAT_PCM_16_BIT: - return (AudioMixer::hook_t)track__NoResample< + return (AudioMixer::hook_t) &Track::track__NoResample< MIXTYPE_MULTI, int32_t /*TO*/, int16_t /*TI*/, TYPE_AUX>; default: LOG_ALWAYS_FATAL("bad mixerInFormat: %#x", mixerInFormat); @@ -2070,7 +1889,9 @@ AudioMixer::hook_t AudioMixer::getTrackHook(int trackType, uint32_t channelCount * a stereo output track, the input track cannot be MONO. This should be * prevented by the caller. */ -AudioMixer::process_hook_t AudioMixer::getProcessHook(int processType, uint32_t channelCount, +/* static */ +AudioMixer::process_hook_t AudioMixer::getProcessHook( + int processType, uint32_t channelCount, audio_format_t mixerInFormat, audio_format_t mixerOutFormat) { if (processType != PROCESSTYPE_NORESAMPLEONETRACK) { // Only NORESAMPLEONETRACK @@ -2078,17 +1899,17 @@ AudioMixer::process_hook_t AudioMixer::getProcessHook(int processType, uint32_t return NULL; } if (!kUseNewMixer && channelCount == FCC_2 && mixerInFormat == AUDIO_FORMAT_PCM_16_BIT) { - return process__OneTrack16BitsStereoNoResampling; + return &AudioMixer::process__oneTrack16BitsStereoNoResampling; } LOG_ALWAYS_FATAL_IF(channelCount > MAX_NUM_CHANNELS); switch (mixerInFormat) { case AUDIO_FORMAT_PCM_FLOAT: switch (mixerOutFormat) { case AUDIO_FORMAT_PCM_FLOAT: - return process_NoResampleOneTrack< + return &AudioMixer::process__noResampleOneTrack< MIXTYPE_MULTI_SAVEONLY, float /*TO*/, float /*TI*/, TYPE_AUX>; case AUDIO_FORMAT_PCM_16_BIT: - return process_NoResampleOneTrack< + return &AudioMixer::process__noResampleOneTrack< MIXTYPE_MULTI_SAVEONLY, int16_t /*TO*/, float /*TI*/, TYPE_AUX>; default: LOG_ALWAYS_FATAL("bad mixerOutFormat: %#x", mixerOutFormat); @@ -2098,10 +1919,10 @@ AudioMixer::process_hook_t AudioMixer::getProcessHook(int processType, uint32_t case AUDIO_FORMAT_PCM_16_BIT: switch (mixerOutFormat) { case AUDIO_FORMAT_PCM_FLOAT: - return process_NoResampleOneTrack< + return &AudioMixer::process__noResampleOneTrack< MIXTYPE_MULTI_SAVEONLY, float /*TO*/, int16_t /*TI*/, TYPE_AUX>; case AUDIO_FORMAT_PCM_16_BIT: - return process_NoResampleOneTrack< + return &AudioMixer::process__noResampleOneTrack< MIXTYPE_MULTI_SAVEONLY, int16_t /*TO*/, int16_t /*TI*/, TYPE_AUX>; default: LOG_ALWAYS_FATAL("bad mixerOutFormat: %#x", mixerOutFormat); diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 3a41ac8c8c..146bd9c690 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -4872,7 +4872,7 @@ void AudioFlinger::MixerThread::dumpInternals(int fd, const Vector& ar { PlaybackThread::dumpInternals(fd, args); dprintf(fd, " Thread throttle time (msecs): %u\n", mThreadThrottleTimeMs); - dprintf(fd, " AudioMixer tracks: 0x%08x\n", mAudioMixer->trackNames()); + dprintf(fd, " AudioMixer tracks: %s\n", mAudioMixer->trackNames().c_str()); dprintf(fd, " Master mono: %s\n", mMasterMono ? "on" : "off"); if (hasFastMixer()) { diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index 17f26c5f03..a5193419fe 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -623,8 +623,7 @@ public: static const int8_t kMaxTrackRetriesOffload = 20; static const int8_t kMaxTrackStartupRetriesOffload = 100; static const int8_t kMaxTrackStopRetriesOffload = 2; - // 14 tracks max per client allows for 2 misbehaving application leaving 4 available tracks. - static const uint32_t kMaxTracksPerUid = 14; + static constexpr uint32_t kMaxTracksPerUid = 40; // Maximum delay (in nanoseconds) for upcoming buffers in suspend mode, otherwise // if delay is greater, the estimated time for timeLoopNextNs is reset.