Support audio-haptic coupled playback.

When trying to play with haptic channel mask, use adjust channels
buffer provider to make the haptic channel the same as the output one.
If haptic playback is supported, use adjust channel non destructive
buffer provider to output haptic data to the end of the sink buffer.
Otherwise, haptic data will be ignored.

Test: Manually
Bug: 111454766
Change-Id: Ic5f780de48c1e71de6ba5c4774d1ed2e9c8c51a0
diff --git a/media/libaudioclient/include/media/AudioMixer.h b/media/libaudioclient/include/media/AudioMixer.h
index 0532232..3ae7104 100644
--- a/media/libaudioclient/include/media/AudioMixer.h
+++ b/media/libaudioclient/include/media/AudioMixer.h
@@ -78,6 +78,8 @@
         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 @@
          * 7) mTimestretchBufferProvider: Adds timestretching for playback rate
          */
         AudioBufferProvider*     mInputBufferProvider;    // externally provided buffer provider.
+        // TODO: combine AdjustChannelsBufferProvider and AdjustChannelsNonDestructiveBufferProvider
         std::unique_ptr<PassthruBufferProvider> mAdjustChannelsBufferProvider;
         std::unique_ptr<PassthruBufferProvider> mAdjustChannelsNonDestructiveBufferProvider;
         std::unique_ptr<PassthruBufferProvider> mReformatBufferProvider;
@@ -360,6 +363,11 @@
         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 365af75..2567b3b 100644
--- a/media/libaudioprocessing/AudioMixer.cpp
+++ b/media/libaudioprocessing/AudioMixer.cpp
@@ -136,6 +136,9 @@
 
         // 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 @@
         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 @@
     LOG_ALWAYS_FATAL_IF(!exists(name), "invalid name: %d", name);
     const std::shared_ptr<Track> &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 @@
     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 @@
         case CHANNEL_MASK: {
             const audio_channel_mask_t trackChannelMask =
                 static_cast<audio_channel_mask_t>(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 @@
         case MIXER_CHANNEL_MASK: {
             const audio_channel_mask_t mixerChannelMask =
                     static_cast<audio_channel_mask_t>(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<bool>(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 @@
 
         const std::shared_ptr<Track> &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 d15841f..f328577 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -37,8 +37,9 @@
 #include <cpustats/ThreadCpuUsage.h>
 #endif
 #endif
-#include <audio_utils/mono_blend.h>
+#include <audio_utils/channels.h>
 #include <audio_utils/format.h>
+#include <audio_utils/mono_blend.h>
 #include <media/AudioMixer.h>
 #include "FastMixer.h"
 #include "TypedLogger.h"
@@ -159,20 +160,24 @@
     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 *)(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 *)(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 @@
             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 1c86d9a..1d332e0 100644
--- a/services/audioflinger/FastMixer.h
+++ b/services/audioflinger/FastMixer.h
@@ -76,6 +76,8 @@
     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 c7fcbd8..9d2a733 100644
--- a/services/audioflinger/FastMixerState.h
+++ b/services/audioflinger/FastMixerState.h
@@ -47,6 +47,7 @@
     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 @@
     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 971f6a5..d9f570d 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -112,6 +112,14 @@
     /** 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 @@
 
     sp<media::VolumeHandler>  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 46e40c7..1fdb27e 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -38,6 +38,7 @@
 
 #include <private/media/AudioTrackShared.h>
 #include <private/android_filesystem_config.h>
+#include <audio_utils/channels.h>
 #include <audio_utils/mono_blend.h>
 #include <audio_utils/primitives.h>
 #include <audio_utils/format.h>
@@ -751,6 +752,7 @@
             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 @@
             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 @@
     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 @@
             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 @@
                     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)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 @@
         // 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 @@
                 }
 
                 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 @@
             }
 
             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 @@
 // removeTracks_l() must be called with ThreadBase::mLock held
 void AudioFlinger::PlaybackThread::removeTracks_l(const Vector< sp<Track> >& 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 @@
             // 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 @@
     // 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 @@
             // 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 @@
         // 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 @@
         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 @@
         std::vector<std::pair<sp<Track>, size_t>> mUnderrunFrames;
     } deferredOperations(&mixerStatus); // implicit nested scope for variable capture
 
+    bool noFastHapticTrack = true;
     for (size_t i=0 ; i<count ; i++) {
         const sp<Track> t = mActiveTracks[i];
 
@@ -4419,6 +4482,9 @@
 
         // 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 @@
                     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 @@
                 // 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 @@
             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 @@
                 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 @@
 
     }
 
+    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 7f3ea0f..e8b2158 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -907,6 +907,11 @@
     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