Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9bd23229 authored by Jean-Michel Trivi's avatar Jean-Michel Trivi
Browse files

Fix multichannel downmix pause bug on video player

Pausing a video player will cause the track audio mixer to be
 disabled, which causes the downmixer to be deleted. When reenabled,
 the track channel mask hasn't changed but the downmixer is there
 anymore.
Fixed by:
- instanciating a downmixer when the AudioMixer track
 gets initialized (in getTrackName(), now taking a channel mask
 as input), and deleted when in deleteTrackName().
- when the channel changes on a track, check whether it
 needs a downmixer or not. Preparing a track for downmix
 automatically removes the old downmixer if there was one.

Also: initialize the track downmixerBufferProvider field
 when AudioMixer is instanciated, so we can safely call
 delete on it in AudioMixer's destructor, in case
 deleteTrackName() wasn't called before the mixer was
 destroyed.

Change-Id: I589b0781cda5b3c82f85b561c52b08546cac21f8
parent 0ca3cf94
Loading
Loading
Loading
Loading
+1 −7
Original line number Diff line number Diff line
@@ -2664,13 +2664,7 @@ void AudioFlinger::MixerThread::invalidateTracks(audio_stream_type_t streamType)
// getTrackName_l() must be called with ThreadBase::mLock held
int AudioFlinger::MixerThread::getTrackName_l(audio_channel_mask_t channelMask)
{
    int name = mAudioMixer->getTrackName();
    if (name >= 0) {
        mAudioMixer->setParameter(name,
                AudioMixer::TRACK,
                AudioMixer::CHANNEL_MASK, (void *)channelMask);
    }
    return name;
    return mAudioMixer->getTrackName(channelMask);
}

// deleteTrackName_l() must be called with ThreadBase::mLock held
+51 −20
Original line number Diff line number Diff line
@@ -69,7 +69,7 @@ status_t AudioMixer::DownmixerBufferProvider::getNextBuffer(AudioBufferProvider:

            res = (*mDownmixHandle)->process(mDownmixHandle,
                    &mDownmixConfig.inputCfg.buffer, &mDownmixConfig.outputCfg.buffer);
            ALOGV("getNextBuffer is downmixing");
            //ALOGV("getNextBuffer is downmixing");
        }
        return res;
    } else {
@@ -79,7 +79,7 @@ status_t AudioMixer::DownmixerBufferProvider::getNextBuffer(AudioBufferProvider:
}

void AudioMixer::DownmixerBufferProvider::releaseBuffer(AudioBufferProvider::Buffer *pBuffer) {
    ALOGV("DownmixerBufferProvider::releaseBuffer()");
    //ALOGV("DownmixerBufferProvider::releaseBuffer()");
    if (this->mTrackBufferProvider != NULL) {
        mTrackBufferProvider->releaseBuffer(pBuffer);
    } else {
@@ -120,6 +120,7 @@ AudioMixer::AudioMixer(size_t frameCount, uint32_t sampleRate, uint32_t maxNumTr
        // FIXME redundant per track
        t->localTimeFreq = lc.getLocalFreq();
        t->resampler = NULL;
        t->downmixerBufferProvider = NULL;
        t++;
    }

@@ -151,13 +152,14 @@ AudioMixer::~AudioMixer()
    track_t* t = mState.tracks;
    for (unsigned i=0 ; i < MAX_NUM_TRACKS ; i++) {
        delete t->resampler;
        delete t->downmixerBufferProvider;
        t++;
    }
    delete [] mState.outputTemp;
    delete [] mState.resampleTemp;
}

int AudioMixer::getTrackName()
int AudioMixer::getTrackName(audio_channel_mask_t channelMask)
{
    uint32_t names = (~mTrackNames) & mConfiguredNames;
    if (names != 0) {
@@ -197,8 +199,14 @@ int AudioMixer::getTrackName()
        t->mainBuffer = NULL;
        t->auxBuffer = NULL;
        // see t->localTimeFreq in constructor above

        status_t status = initTrackDownmix(&mState.tracks[n], n, channelMask);
        if (status == OK) {
            return TRACK0 + n;
        }
        ALOGE("AudioMixer::getTrackName(0x%x) failed, error preparing track for downmix",
                channelMask);
    }
    return -1;
}

@@ -210,17 +218,44 @@ void AudioMixer::invalidateState(uint32_t mask)
    }
 }

status_t AudioMixer::prepareTrackForDownmix(track_t* pTrack, int trackName)
status_t AudioMixer::initTrackDownmix(track_t* pTrack, int trackNum, audio_channel_mask_t mask)
{
    ALOGV("AudioMixer::prepareTrackForDownmix(%d) with mask 0x%x", trackName, pTrack->channelMask);
    uint32_t channelCount = popcount(mask);
    ALOG_ASSERT((channelCount <= MAX_NUM_CHANNELS_TO_DOWNMIX) && channelCount);
    status_t status = OK;
    if (channelCount > MAX_NUM_CHANNELS) {
        pTrack->channelMask = mask;
        pTrack->channelCount = channelCount;
        ALOGV("initTrackDownmix(track=%d, mask=0x%x) calls prepareTrackForDownmix()",
                trackNum, mask);
        status = prepareTrackForDownmix(pTrack, trackNum);
    } else {
        unprepareTrackForDownmix(pTrack, trackNum);
    }
    return status;
}

void AudioMixer::unprepareTrackForDownmix(track_t* pTrack, int trackName) {
    ALOGV("AudioMixer::unprepareTrackForDownmix(%d)", trackName);

    if (pTrack->downmixerBufferProvider != NULL) {
        // this track had previously been configured with a downmixer, reset it
        ALOGV("AudioMixer::prepareTrackForDownmix(%d) deleting old downmixer", trackName);
        // this track had previously been configured with a downmixer, delete it
        ALOGV(" deleting old downmixer");
        pTrack->bufferProvider = pTrack->downmixerBufferProvider->mTrackBufferProvider;
        delete pTrack->downmixerBufferProvider;
        pTrack->downmixerBufferProvider = NULL;
    } else {
        ALOGV(" nothing to do, no downmixer to delete");
    }
}

status_t AudioMixer::prepareTrackForDownmix(track_t* pTrack, int trackName)
{
    ALOGV("AudioMixer::prepareTrackForDownmix(%d) with mask 0x%x", trackName, pTrack->channelMask);

    // discard the previous downmixer if there was one
    unprepareTrackForDownmix(pTrack, trackName);

    DownmixerBufferProvider* pDbp = new DownmixerBufferProvider();
    int32_t status;

@@ -319,6 +354,7 @@ noDownmixForActiveTrack:

void AudioMixer::deleteTrackName(int name)
{
    ALOGV("AudioMixer::deleteTrackName(%d)", name);
    name -= TRACK0;
    ALOG_ASSERT(uint32_t(name) < MAX_NUM_TRACKS, "bad track name %d", name);
    ALOGV("deleteTrackName(%d)", name);
@@ -330,6 +366,9 @@ void AudioMixer::deleteTrackName(int name)
    // delete the resampler
    delete track.resampler;
    track.resampler = NULL;
    // delete the downmixer
    unprepareTrackForDownmix(&mState.tracks[name], name);

    mTrackNames &= ~(1<<name);
}

@@ -353,11 +392,6 @@ void AudioMixer::disable(int name)
    track_t& track = mState.tracks[name];

    if (track.enabled) {
        if (track.downmixerBufferProvider != NULL) {
            ALOGV("AudioMixer::disable(%d) deleting downmixerBufferProvider", name);
            delete track.downmixerBufferProvider;
            track.downmixerBufferProvider = NULL;
        }
        track.enabled = false;
        ALOGV("disable(%d)", name);
        invalidateState(1 << name);
@@ -384,11 +418,8 @@ void AudioMixer::setParameter(int name, int target, int param, void *value)
                ALOG_ASSERT((channelCount <= MAX_NUM_CHANNELS_TO_DOWNMIX) && channelCount);
                track.channelMask = mask;
                track.channelCount = channelCount;
                if (channelCount > MAX_NUM_CHANNELS) {
                    ALOGV("AudioMixer::setParameter(TRACK, CHANNEL_MASK, mask=0x%x count=%d)",
                            mask, channelCount);
                    status_t status = prepareTrackForDownmix(&mState.tracks[name], name);
                }
                // the mask has changed, does this track need a downmixer?
                initTrackDownmix(&mState.tracks[name], name, mask);
                ALOGV("setParameter(TRACK, CHANNEL_MASK, %x)", mask);
                invalidateState(1 << name);
            }
@@ -633,7 +664,7 @@ void AudioMixer::process__validate(state_t* state, int64_t pts)
                resampling = true;
                t.hook = track__genericResample;
                ALOGV_IF((n & NEEDS_CHANNEL_COUNT__MASK) > NEEDS_CHANNEL_2,
                        "Track needs downmix + resample");
                        "Track %d needs downmix + resample", i);
            } else {
                if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_1){
                    t.hook = track__16BitsMono;
@@ -642,7 +673,7 @@ void AudioMixer::process__validate(state_t* state, int64_t pts)
                if ((n & NEEDS_CHANNEL_COUNT__MASK) >= NEEDS_CHANNEL_2){
                    t.hook = track__16BitsStereo;
                    ALOGV_IF((n & NEEDS_CHANNEL_COUNT__MASK) > NEEDS_CHANNEL_2,
                            "Track needs downmix");
                            "Track %d needs downmix", i);
                }
            }
        }
+3 −1
Original line number Diff line number Diff line
@@ -91,7 +91,7 @@ public:
    // For all APIs with "name": TRACK0 <= name < TRACK0 + MAX_NUM_TRACKS

    // Allocate a track name.  Returns new track name if successful, -1 on failure.
    int         getTrackName();
    int         getTrackName(audio_channel_mask_t channelMask);

    // Free an allocated track by name
    void        deleteTrackName(int name);
@@ -250,7 +250,9 @@ private:
    // OK to call more often than that, but unnecessary.
    void invalidateState(uint32_t mask);

    static status_t initTrackDownmix(track_t* pTrack, int trackNum, audio_channel_mask_t mask);
    static status_t prepareTrackForDownmix(track_t* pTrack, int trackNum);
    static void unprepareTrackForDownmix(track_t* pTrack, int trackName);

    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);
+2 −1
Original line number Diff line number Diff line
@@ -243,7 +243,8 @@ bool FastMixer::threadLoop()
                    AudioBufferProvider *bufferProvider = fastTrack->mBufferProvider;
                    ALOG_ASSERT(bufferProvider != NULL && fastTrackNames[i] == -1);
                    if (mixer != NULL) {
                        name = mixer->getTrackName();
                        // calling getTrackName with default channel mask
                        name = mixer->getTrackName(AUDIO_CHANNEL_OUT_STEREO);
                        ALOG_ASSERT(name >= 0);
                        fastTrackNames[i] = name;
                        mixer->setBufferProvider(name, bufferProvider);