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
gugelfrei
jiabin 6 years ago
parent dce8f8cc41
commit 245cdd9155

@ -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<PassthruBufferProvider> mAdjustChannelsBufferProvider;
std::unique_ptr<PassthruBufferProvider> mAdjustChannelsNonDestructiveBufferProvider;
std::unique_ptr<PassthruBufferProvider> 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;

@ -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> &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<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 @@ void AudioMixer::setParameter(int name, int target, int param, void *value)
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 @@ void AudioMixer::process__nop()
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) {

@ -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 @@ 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);

@ -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;

@ -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

@ -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<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[];

@ -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 @@ 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<String16>&
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::Track> 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)
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<EffectChain>& 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<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 @@ void AudioFlinger::PlaybackThread::removeTracks_l(const Vector< sp<Track> >& 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>& 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>& 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>& 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>& 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<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 @@ 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) {

@ -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

Loading…
Cancel
Save