diff --git a/media/libaudioclient/include/media/AudioMixer.h b/media/libaudioclient/include/media/AudioMixer.h index 0532232073..3ae7104459 100644 --- a/media/libaudioclient/include/media/AudioMixer.h +++ b/media/libaudioclient/include/media/AudioMixer.h @@ -78,6 +78,8 @@ public: DOWNMIX_TYPE = 0X4004, MIXER_FORMAT = 0x4005, // AUDIO_FORMAT_PCM_(FLOAT|16_BIT) MIXER_CHANNEL_MASK = 0x4006, // Channel mask for mixer output + // for haptic + HAPTIC_ENABLED = 0x4007, // Set haptic data from this track should be played or not. // for target RESAMPLE SAMPLE_RATE = 0x4100, // Configure sample rate conversion on this track name; // parameter 'value' is the new sample rate in Hz. @@ -329,6 +331,7 @@ private: * 7) mTimestretchBufferProvider: Adds timestretching for playback rate */ AudioBufferProvider* mInputBufferProvider; // externally provided buffer provider. + // TODO: combine AdjustChannelsBufferProvider and AdjustChannelsNonDestructiveBufferProvider std::unique_ptr mAdjustChannelsBufferProvider; std::unique_ptr mAdjustChannelsNonDestructiveBufferProvider; std::unique_ptr mReformatBufferProvider; @@ -360,6 +363,11 @@ private: AudioPlaybackRate mPlaybackRate; // Haptic + bool mHapticPlaybackEnabled; + audio_channel_mask_t mHapticChannelMask; + uint32_t mHapticChannelCount; + audio_channel_mask_t mMixerHapticChannelMask; + uint32_t mMixerHapticChannelCount; uint32_t mAdjustInChannelCount; uint32_t mAdjustOutChannelCount; uint32_t mAdjustNonDestructiveInChannelCount; diff --git a/media/libaudioprocessing/AudioMixer.cpp b/media/libaudioprocessing/AudioMixer.cpp index 365af75c1c..2567b3b238 100644 --- a/media/libaudioprocessing/AudioMixer.cpp +++ b/media/libaudioprocessing/AudioMixer.cpp @@ -136,6 +136,9 @@ status_t AudioMixer::create( // no initialization needed // t->frameCount + t->mHapticChannelMask = channelMask & AUDIO_CHANNEL_HAPTIC_ALL; + t->mHapticChannelCount = audio_channel_count_from_out_mask(t->mHapticChannelMask); + channelMask &= ~AUDIO_CHANNEL_HAPTIC_ALL; t->channelCount = audio_channel_count_from_out_mask(channelMask); t->enabled = false; ALOGV_IF(audio_channel_mask_get_bits(channelMask) != AUDIO_CHANNEL_OUT_STEREO, @@ -163,10 +166,13 @@ status_t AudioMixer::create( t->mMixerChannelCount = audio_channel_count_from_out_mask(t->mMixerChannelMask); t->mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT; // haptic - t->mAdjustInChannelCount = 0; - t->mAdjustOutChannelCount = 0; - t->mAdjustNonDestructiveInChannelCount = 0; - t->mAdjustNonDestructiveOutChannelCount = 0; + t->mHapticPlaybackEnabled = false; + t->mMixerHapticChannelMask = AUDIO_CHANNEL_NONE; + t->mMixerHapticChannelCount = 0; + t->mAdjustInChannelCount = t->channelCount + t->mHapticChannelCount; + t->mAdjustOutChannelCount = t->channelCount + t->mMixerHapticChannelCount; + t->mAdjustNonDestructiveInChannelCount = t->mAdjustOutChannelCount; + t->mAdjustNonDestructiveOutChannelCount = t->channelCount; t->mKeepContractedChannels = false; // Check the downmixing (or upmixing) requirements. status_t status = t->prepareForDownmix(); @@ -193,13 +199,20 @@ bool AudioMixer::setChannelMasks(int name, LOG_ALWAYS_FATAL_IF(!exists(name), "invalid name: %d", name); const std::shared_ptr &track = mTracks[name]; - if (trackChannelMask == track->channelMask - && mixerChannelMask == track->mMixerChannelMask) { + if (trackChannelMask == (track->channelMask | track->mHapticChannelMask) + && mixerChannelMask == (track->mMixerChannelMask | track->mMixerHapticChannelMask)) { return false; // no need to change } + const audio_channel_mask_t hapticChannelMask = trackChannelMask & AUDIO_CHANNEL_HAPTIC_ALL; + trackChannelMask &= ~AUDIO_CHANNEL_HAPTIC_ALL; + const audio_channel_mask_t mixerHapticChannelMask = mixerChannelMask & AUDIO_CHANNEL_HAPTIC_ALL; + mixerChannelMask &= ~AUDIO_CHANNEL_HAPTIC_ALL; // 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 uint32_t hapticChannelCount = audio_channel_count_from_out_mask(hapticChannelMask); + const uint32_t mixerHapticChannelCount = + audio_channel_count_from_out_mask(mixerHapticChannelMask); ALOG_ASSERT((trackChannelCount <= MAX_NUM_CHANNELS_TO_DOWNMIX) && trackChannelCount @@ -208,6 +221,24 @@ bool AudioMixer::setChannelMasks(int name, track->channelCount = trackChannelCount; track->mMixerChannelMask = mixerChannelMask; track->mMixerChannelCount = mixerChannelCount; + track->mHapticChannelMask = hapticChannelMask; + track->mHapticChannelCount = hapticChannelCount; + track->mMixerHapticChannelMask = mixerHapticChannelMask; + track->mMixerHapticChannelCount = mixerHapticChannelCount; + + if (track->mHapticChannelCount > 0) { + track->mAdjustInChannelCount = track->channelCount + track->mHapticChannelCount; + track->mAdjustOutChannelCount = track->channelCount + track->mMixerHapticChannelCount; + track->mAdjustNonDestructiveInChannelCount = track->mAdjustOutChannelCount; + track->mAdjustNonDestructiveOutChannelCount = track->channelCount; + track->mKeepContractedChannels = track->mHapticPlaybackEnabled; + } else { + track->mAdjustInChannelCount = 0; + track->mAdjustOutChannelCount = 0; + track->mAdjustNonDestructiveInChannelCount = 0; + track->mAdjustNonDestructiveOutChannelCount = 0; + track->mKeepContractedChannels = false; + } // channel masks have changed, does this track need a downmixer? // update to try using our desired format (if we aren't already using it) @@ -616,7 +647,8 @@ 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 | track->mMixerHapticChannelMask))) { ALOGV("setParameter(TRACK, CHANNEL_MASK, %x)", trackChannelMask); invalidate(); } @@ -665,11 +697,21 @@ void AudioMixer::setParameter(int name, int target, int param, void *value) case MIXER_CHANNEL_MASK: { const audio_channel_mask_t mixerChannelMask = static_cast(valueInt); - if (setChannelMasks(name, track->channelMask, mixerChannelMask)) { + if (setChannelMasks(name, track->channelMask | track->mHapticChannelMask, + mixerChannelMask)) { ALOGV("setParameter(TRACK, MIXER_CHANNEL_MASK, %#x)", mixerChannelMask); invalidate(); } } break; + case HAPTIC_ENABLED: { + const bool hapticPlaybackEnabled = static_cast(valueInt); + if (track->mHapticPlaybackEnabled != hapticPlaybackEnabled) { + track->mHapticPlaybackEnabled = hapticPlaybackEnabled; + track->mKeepContractedChannels = hapticPlaybackEnabled; + track->prepareForAdjustChannelsNonDestructive(mFrameCount); + track->prepareForAdjustChannels(); + } + } break; default: LOG_ALWAYS_FATAL("setParameter track: bad param %d", param); } @@ -1359,8 +1401,8 @@ void AudioMixer::process__nop() const std::shared_ptr &t = mTracks[group[0]]; memset(t->mainBuffer, 0, - mFrameCount * t->mMixerChannelCount - * audio_bytes_per_sample(t->mMixerFormat)); + mFrameCount * audio_bytes_per_frame( + t->mMixerChannelCount + t->mMixerHapticChannelCount, t->mMixerFormat)); // now consume data for (const int name : group) { diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp index d15841fcf2..f328577456 100644 --- a/services/audioflinger/FastMixer.cpp +++ b/services/audioflinger/FastMixer.cpp @@ -37,8 +37,9 @@ #include #endif #endif -#include +#include #include +#include #include #include "FastMixer.h" #include "TypedLogger.h" @@ -159,20 +160,24 @@ void FastMixer::onStateChange() if (current->mOutputSinkGen != mOutputSinkGen) { mOutputSink = current->mOutputSink; mOutputSinkGen = current->mOutputSinkGen; + mSinkChannelMask = current->mSinkChannelMask; if (mOutputSink == NULL) { mFormat = Format_Invalid; mSampleRate = 0; mSinkChannelCount = 0; mSinkChannelMask = AUDIO_CHANNEL_NONE; + mAudioChannelCount = 0; } else { mFormat = mOutputSink->format(); mSampleRate = Format_sampleRate(mFormat); mSinkChannelCount = Format_channelCount(mFormat); LOG_ALWAYS_FATAL_IF(mSinkChannelCount > AudioMixer::MAX_NUM_CHANNELS); - // TODO: Add channel mask to NBAIO_Format - // We assume that the channel mask must be a valid positional channel mask. - mSinkChannelMask = audio_channel_out_mask_from_count(mSinkChannelCount); + if (mSinkChannelMask == AUDIO_CHANNEL_NONE) { + mSinkChannelMask = audio_channel_out_mask_from_count(mSinkChannelCount); + } + mAudioChannelCount = mSinkChannelCount - audio_channel_count_from_out_mask( + mSinkChannelMask & AUDIO_CHANNEL_HAPTIC_ALL); } dumpState->mSampleRate = mSampleRate; } @@ -288,6 +293,8 @@ void FastMixer::onStateChange() (void *)(uintptr_t)fastTrack->mChannelMask); mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK, (void *)(uintptr_t)mSinkChannelMask); + mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::HAPTIC_ENABLED, + (void *)(uintptr_t)fastTrack->mHapticPlaybackEnabled); mMixer->enable(name); } mGenerations[i] = fastTrack->mGeneration; @@ -324,6 +331,8 @@ void FastMixer::onStateChange() (void *)(uintptr_t)fastTrack->mChannelMask); mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK, (void *)(uintptr_t)mSinkChannelMask); + mMixer->setParameter(name, AudioMixer::TRACK, AudioMixer::HAPTIC_ENABLED, + (void *)(uintptr_t)fastTrack->mHapticPlaybackEnabled); // already enabled } mGenerations[i] = fastTrack->mGeneration; @@ -468,6 +477,13 @@ void FastMixer::onWork() memcpy_by_audio_format(buffer, mFormat.mFormat, mMixerBuffer, mMixerBufferFormat, frameCount * Format_channelCount(mFormat)); } + if (mSinkChannelMask & AUDIO_CHANNEL_HAPTIC_ALL) { + // When there are haptic channels, the sample data is partially interleaved. + // Make the sample data fully interleaved here. + adjust_channels_non_destructive(buffer, mAudioChannelCount, buffer, mSinkChannelCount, + audio_bytes_per_sample(mFormat.mFormat), + frameCount * audio_bytes_per_frame(mAudioChannelCount, mFormat.mFormat)); + } // if non-NULL, then duplicate write() to this non-blocking sink #ifdef TEE_SINK mTee.write(buffer, frameCount); diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h index 1c86d9ae7d..1d332e01af 100644 --- a/services/audioflinger/FastMixer.h +++ b/services/audioflinger/FastMixer.h @@ -76,6 +76,8 @@ private: size_t mMixerBufferSize; audio_format_t mMixerBufferFormat; // mixer output format: AUDIO_FORMAT_PCM_(16_BIT|FLOAT). + uint32_t mAudioChannelCount; // audio channel count, excludes haptic channels. + enum {UNDEFINED, MIXED, ZEROED} mMixerBufferState; NBAIO_Format mFormat; unsigned mSampleRate; diff --git a/services/audioflinger/FastMixerState.h b/services/audioflinger/FastMixerState.h index c7fcbd83ce..9d2a733670 100644 --- a/services/audioflinger/FastMixerState.h +++ b/services/audioflinger/FastMixerState.h @@ -47,6 +47,7 @@ struct FastTrack { audio_channel_mask_t mChannelMask; // AUDIO_CHANNEL_OUT_MONO or AUDIO_CHANNEL_OUT_STEREO audio_format_t mFormat; // track format int mGeneration; // increment when any field is assigned + bool mHapticPlaybackEnabled = false; // haptic playback is enabled or not }; // Represents a single state of the fast mixer @@ -69,6 +70,9 @@ struct FastMixerState : FastThreadState { NBAIO_Sink* mOutputSink; // HAL output device, must already be negotiated int mOutputSinkGen; // increment when mOutputSink is assigned size_t mFrameCount; // number of frames per fast mix buffer + audio_channel_mask_t mSinkChannelMask; // If not AUDIO_CHANNEL_NONE, specifies sink channel + // mask when it cannot be directly calculated from + // channel count // Extends FastThreadState::Command static const Command diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h index 971f6a5077..d9f570dfe3 100644 --- a/services/audioflinger/PlaybackTracks.h +++ b/services/audioflinger/PlaybackTracks.h @@ -112,6 +112,14 @@ public: /** Copy the track metadata in the provided iterator. Thread safe. */ virtual void copyMetadataTo(MetadataInserter& backInserter) const; + /** Return haptic playback of the track is enabled or not, used in mixer. */ + bool getHapticPlaybackEnabled() const { return mHapticPlaybackEnabled; } + /** Set haptic playback of the track is enabled or not, should be + * set after query or get callback from vibrator service */ + void setHapticPlaybackEnabled(bool hapticPlaybackEnabled) { + mHapticPlaybackEnabled = hapticPlaybackEnabled; + } + protected: // for numerous friend class PlaybackThread; @@ -188,6 +196,8 @@ protected: sp mVolumeHandler; // handles multiple VolumeShaper configs and operations + bool mHapticPlaybackEnabled = false; // indicates haptic playback enabled or not + private: // The following fields are only for fast tracks, and should be in a subclass int mFastIndex; // index within FastMixerState::mFastTracks[]; diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 46e40c75ef..1fdb27e88e 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -751,6 +752,7 @@ String8 channelMaskToString(audio_channel_mask_t mask, bool output) { audio_channel_mask_get_representation(mask); switch (representation) { + // Travel all single bit channel mask to convert channel mask to string. case AUDIO_CHANNEL_REPRESENTATION_POSITION: { if (output) { if (mask & AUDIO_CHANNEL_OUT_FRONT_LEFT) s.append("front-left, "); @@ -773,6 +775,8 @@ String8 channelMaskToString(audio_channel_mask_t mask, bool output) { if (mask & AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT) s.append("top-back-right, " ); if (mask & AUDIO_CHANNEL_OUT_TOP_SIDE_LEFT) s.append("top-side-left, " ); if (mask & AUDIO_CHANNEL_OUT_TOP_SIDE_RIGHT) s.append("top-side-right, " ); + if (mask & AUDIO_CHANNEL_OUT_HAPTIC_B) s.append("haptic-B, " ); + if (mask & AUDIO_CHANNEL_OUT_HAPTIC_A) s.append("haptic-A, " ); if (mask & ~AUDIO_CHANNEL_OUT_ALL) s.append("unknown, "); } else { if (mask & AUDIO_CHANNEL_IN_LEFT) s.append("left, "); @@ -1845,6 +1849,10 @@ void AudioFlinger::PlaybackThread::dumpInternals(int fd, const Vector& dumpBase(fd, args); dprintf(fd, " Master mute: %s\n", mMasterMute ? "on" : "off"); + if (mHapticChannelMask != AUDIO_CHANNEL_NONE) { + dprintf(fd, " Haptic channel mask: %#x (%s)\n", mHapticChannelMask, + channelMaskToString(mHapticChannelMask, true /* output */).c_str()); + } dprintf(fd, " Normal frame count: %zu\n", mNormalFrameCount); dprintf(fd, " Last write occurred (msecs): %llu\n", (unsigned long long) ns2ms(systemTime() - mLastWriteTime)); @@ -1946,7 +1954,7 @@ sp AudioFlinger::PlaybackThread::createTrac audio_is_linear_pcm(format) && // TODO: extract as a data library function that checks that a computationally // expensive downmixer is not required: isFastOutputChannelConversion() - (channelMask == mChannelMask || + (channelMask == (mChannelMask | mHapticChannelMask) || mChannelMask != AUDIO_CHANNEL_OUT_STEREO || (channelMask == AUDIO_CHANNEL_OUT_MONO /* && mChannelMask == AUDIO_CHANNEL_OUT_STEREO */)) && @@ -2348,6 +2356,17 @@ status_t AudioFlinger::PlaybackThread::addTrack_l(const sp& track) track->sharedBuffer() != 0 ? Track::FS_FILLED : Track::FS_FILLING; } + // Disable all haptic playback for all other active tracks when haptic playback is supported + // and the track contains haptic channels. Enable haptic playback for current track. + // TODO: Request actual haptic playback status from vibrator service + if ((track->channelMask() & AUDIO_CHANNEL_HAPTIC_ALL) != AUDIO_CHANNEL_NONE + && mHapticChannelMask != AUDIO_CHANNEL_NONE) { + for (auto &t : mActiveTracks) { + t->setHapticPlaybackEnabled(false); + } + track->setHapticPlaybackEnabled(true); + } + track->mResetDone = false; track->mPresentationCompleteFrames = 0; mActiveTracks.add(track); @@ -2635,6 +2654,11 @@ void AudioFlinger::PlaybackThread::readOutputParameters_l() (void)posix_memalign(&mEffectBuffer, 32, mEffectBufferSize); } + mHapticChannelMask = mChannelMask & AUDIO_CHANNEL_HAPTIC_ALL; + mChannelMask &= ~mHapticChannelMask; + mHapticChannelCount = audio_channel_count_from_out_mask(mHapticChannelMask); + mChannelCount -= mHapticChannelCount; + // force reconfiguration of effect chains and engines to take new buffer size and audio // parameters into account // Note that mLock is not held when readOutputParameters_l() is called from the constructor @@ -3007,7 +3031,7 @@ status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp& c // Only one effect chain can be present in direct output thread and it uses // the sink buffer as input if (mType != DIRECT) { - size_t numSamples = mNormalFrameCount * mChannelCount; + size_t numSamples = mNormalFrameCount * (mChannelCount + mHapticChannelCount); status_t result = mAudioFlinger->mEffectsFactoryHal->allocateBuffer( numSamples * sizeof(effect_buffer_t), &halInBuffer); @@ -3506,7 +3530,17 @@ bool AudioFlinger::PlaybackThread::threadLoop() } memcpy_by_audio_format(buffer, format, mMixerBuffer, mMixerBufferFormat, - mNormalFrameCount * mChannelCount); + mNormalFrameCount * (mChannelCount + mHapticChannelCount)); + + // If we're going directly to the sink and there are haptic channels, + // we should adjust channels as the sample data is partially interleaved + // in this case. + if (!mEffectBufferValid && mHapticChannelCount > 0) { + adjust_channels_non_destructive(buffer, mChannelCount, buffer, + mChannelCount + mHapticChannelCount, + audio_bytes_per_sample(format), + audio_bytes_per_frame(mChannelCount, format) * mNormalFrameCount); + } } mBytesRemaining = mCurrentWriteLength; @@ -3550,7 +3584,15 @@ bool AudioFlinger::PlaybackThread::threadLoop() } memcpy_by_audio_format(mSinkBuffer, mFormat, mEffectBuffer, mEffectBufferFormat, - mNormalFrameCount * mChannelCount); + mNormalFrameCount * (mChannelCount + mHapticChannelCount)); + // The sample data is partially interleaved when haptic channels exist, + // we need to adjust channels here. + if (mHapticChannelCount > 0) { + adjust_channels_non_destructive(mSinkBuffer, mChannelCount, mSinkBuffer, + mChannelCount + mHapticChannelCount, + audio_bytes_per_sample(mFormat), + audio_bytes_per_frame(mChannelCount, mFormat) * mNormalFrameCount); + } } // enable changes in effect chain @@ -3716,6 +3758,7 @@ bool AudioFlinger::PlaybackThread::threadLoop() // removeTracks_l() must be called with ThreadBase::mLock held void AudioFlinger::PlaybackThread::removeTracks_l(const Vector< sp >& tracksToRemove) { + bool enabledHapticTracksRemoved = false; for (const auto& track : tracksToRemove) { mActiveTracks.remove(track); ALOGV("%s(%d): removing track on session %d", __func__, track->id(), track->sessionId()); @@ -3737,6 +3780,18 @@ void AudioFlinger::PlaybackThread::removeTracks_l(const Vector< sp >& tra // remove from our tracks vector removeTrack_l(track); } + enabledHapticTracksRemoved |= track->getHapticPlaybackEnabled(); + } + // If the thread supports haptic playback and the track playing haptic data was removed, + // enable haptic playback on the first active track that contains haptic channels. + // TODO: Query vibrator service to know which track should enable haptic playback. + if (enabledHapticTracksRemoved && mHapticChannelMask != AUDIO_CHANNEL_NONE) { + for (auto &t : mActiveTracks) { + if (t->channelMask() & AUDIO_CHANNEL_HAPTIC_ALL) { + t->setHapticPlaybackEnabled(true); + break; + } + } } } @@ -3942,7 +3997,8 @@ AudioFlinger::MixerThread::MixerThread(const sp& audioFlinger, Aud // create an NBAIO sink for the HAL output stream, and negotiate mOutputSink = new AudioStreamOutSink(output->stream); size_t numCounterOffers = 0; - const NBAIO_Format offers[1] = {Format_from_SR_C(mSampleRate, mChannelCount, mFormat)}; + const NBAIO_Format offers[1] = {Format_from_SR_C( + mSampleRate, mChannelCount + mHapticChannelCount, mFormat)}; #if !LOG_NDEBUG ssize_t index = #else @@ -3984,7 +4040,7 @@ AudioFlinger::MixerThread::MixerThread(const sp& audioFlinger, Aud // change our Sink format to accept our intermediate precision mFormat = fastMixerFormat; free(mSinkBuffer); - mFrameSize = mChannelCount * audio_bytes_per_sample(mFormat); + mFrameSize = audio_bytes_per_frame(mChannelCount + mHapticChannelCount, mFormat); const size_t sinkBufferSize = mNormalFrameCount * mFrameSize; (void)posix_memalign(&mSinkBuffer, 32, sinkBufferSize); } @@ -4026,8 +4082,10 @@ AudioFlinger::MixerThread::MixerThread(const sp& audioFlinger, Aud // wrap the source side of the MonoPipe to make it an AudioBufferProvider fastTrack->mBufferProvider = new SourceAudioBufferProvider(new MonoPipeReader(monoPipe)); fastTrack->mVolumeProvider = NULL; - fastTrack->mChannelMask = mChannelMask; // mPipeSink channel mask for audio to FastMixer + fastTrack->mChannelMask = mChannelMask | mHapticChannelMask; // mPipeSink channel mask for + // audio to FastMixer fastTrack->mFormat = mFormat; // mPipeSink format for audio to FastMixer + fastTrack->mHapticPlaybackEnabled = mHapticChannelMask != AUDIO_CHANNEL_NONE; fastTrack->mGeneration++; state->mFastTracksGen++; state->mTrackMask = 1; @@ -4035,6 +4093,10 @@ AudioFlinger::MixerThread::MixerThread(const sp& audioFlinger, Aud state->mOutputSink = mOutputSink.get(); state->mOutputSinkGen++; state->mFrameCount = mFrameCount; + // specify sink channel mask when haptic channel mask present as it can not + // be calculated directly from channel count + state->mSinkChannelMask = mHapticChannelMask == AUDIO_CHANNEL_NONE + ? AUDIO_CHANNEL_NONE : mChannelMask | mHapticChannelMask; state->mCommand = FastMixerState::COLD_IDLE; // already done in constructor initialization list //mFastMixerFutex = 0; @@ -4411,6 +4473,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac std::vector, size_t>> mUnderrunFrames; } deferredOperations(&mixerStatus); // implicit nested scope for variable capture + bool noFastHapticTrack = true; for (size_t i=0 ; i t = mActiveTracks[i]; @@ -4419,6 +4482,9 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac // process fast tracks if (track->isFastTrack()) { + if (track->getHapticPlaybackEnabled()) { + noFastHapticTrack = false; + } // It's theoretically possible (though unlikely) for a fast track to be created // and then removed within the same normal mix cycle. This is not a problem, as @@ -4544,6 +4610,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac fastTrack->mVolumeProvider = vp; fastTrack->mChannelMask = track->mChannelMask; fastTrack->mFormat = track->mFormat; + fastTrack->mHapticPlaybackEnabled = track->getHapticPlaybackEnabled(); fastTrack->mGeneration++; state->mTrackMask |= 1 << j; didModify = true; @@ -4589,6 +4656,10 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac // Avoids a misleading display in dumpsys track->mObservedUnderruns.mBitFields.mMostRecent = UNDERRUN_FULL; } + if (fastTrack->mHapticPlaybackEnabled != track->getHapticPlaybackEnabled()) { + fastTrack->mHapticPlaybackEnabled = track->getHapticPlaybackEnabled(); + didModify = true; + } continue; } @@ -4796,7 +4867,8 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac mAudioMixer->setParameter( trackId, AudioMixer::TRACK, - AudioMixer::MIXER_CHANNEL_MASK, (void *)(uintptr_t)mChannelMask); + AudioMixer::MIXER_CHANNEL_MASK, + (void *)(uintptr_t)(mChannelMask | mHapticChannelMask)); // limit track sample rate to 2 x output sample rate, which changes at re-configuration uint32_t maxSampleRate = mSampleRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX; uint32_t reqSampleRate = track->mAudioTrackServerProxy->getSampleRate(); @@ -4857,6 +4929,10 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac trackId, AudioMixer::TRACK, AudioMixer::AUX_BUFFER, (void *)track->auxBuffer()); + mAudioMixer->setParameter( + trackId, + AudioMixer::TRACK, + AudioMixer::HAPTIC_ENABLED, (void *)(uintptr_t)track->getHapticPlaybackEnabled()); // reset retry count track->mRetryCount = kMaxTrackRetries; @@ -4924,6 +5000,17 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac } + if (mHapticChannelMask != AUDIO_CHANNEL_NONE && sq != NULL) { + // When there is no fast track playing haptic and FastMixer exists, + // enabling the first FastTrack, which provides mixed data from normal + // tracks, to play haptic data. + FastTrack *fastTrack = &state->mFastTracks[0]; + if (fastTrack->mHapticPlaybackEnabled != noFastHapticTrack) { + fastTrack->mHapticPlaybackEnabled = noFastHapticTrack; + didModify = true; + } + } + // Push the new FastMixer state if necessary bool pauseAudioWatchdog = false; if (didModify) { diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index 7f3ea0f4e7..e8b2158e71 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -907,6 +907,11 @@ protected: int64_t mBytesWritten; int64_t mFramesWritten; // not reset on standby int64_t mSuspendedFrames; // not reset on standby + + // mHapticChannelMask and mHapticChannelCount will only be valid when the thread support + // haptic playback. + audio_channel_mask_t mHapticChannelMask = AUDIO_CHANNEL_NONE; + uint32_t mHapticChannelCount = 0; private: // mMasterMute is in both PlaybackThread and in AudioFlinger. When a // PlaybackThread needs to find out if master-muted, it checks it's local