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

Commit 018d324d authored by Andy Hung's avatar Andy Hung Committed by Android (Google) Code Review
Browse files

Merge "Add multiple format capability to AudioMixer"

parents 1a83b736 ef7c7fbd
Loading
Loading
Loading
Loading
+167 −26
Original line number Original line Diff line number Diff line
@@ -34,6 +34,7 @@
#include <system/audio.h>
#include <system/audio.h>


#include <audio_utils/primitives.h>
#include <audio_utils/primitives.h>
#include <audio_utils/format.h>
#include <common_time/local_clock.h>
#include <common_time/local_clock.h>
#include <common_time/cc_helper.h>
#include <common_time/cc_helper.h>


@@ -88,6 +89,103 @@ void AudioMixer::DownmixerBufferProvider::releaseBuffer(AudioBufferProvider::Buf
    }
    }
}
}


template <typename T>
T min(const T& a, const T& b)
{
    return a < b ? a : b;
}

AudioMixer::ReformatBufferProvider::ReformatBufferProvider(int32_t channels,
        audio_format_t inputFormat, audio_format_t outputFormat) :
        mTrackBufferProvider(NULL),
        mChannels(channels),
        mInputFormat(inputFormat),
        mOutputFormat(outputFormat),
        mInputFrameSize(channels * audio_bytes_per_sample(inputFormat)),
        mOutputFrameSize(channels * audio_bytes_per_sample(outputFormat)),
        mOutputData(NULL),
        mOutputCount(0),
        mConsumed(0)
{
    ALOGV("ReformatBufferProvider(%p)(%d, %#x, %#x)", this, channels, inputFormat, outputFormat);
    if (requiresInternalBuffers()) {
        mOutputCount = 256;
        (void)posix_memalign(&mOutputData, 32, mOutputCount * mOutputFrameSize);
    }
    mBuffer.frameCount = 0;
}

AudioMixer::ReformatBufferProvider::~ReformatBufferProvider()
{
    ALOGV("~ReformatBufferProvider(%p)", this);
    if (mBuffer.frameCount != 0) {
        mTrackBufferProvider->releaseBuffer(&mBuffer);
    }
    free(mOutputData);
}

status_t AudioMixer::ReformatBufferProvider::getNextBuffer(AudioBufferProvider::Buffer *pBuffer,
        int64_t pts) {
    //ALOGV("ReformatBufferProvider(%p)::getNextBuffer(%p (%zu), %lld)",
    //        this, pBuffer, pBuffer->frameCount, pts);
    if (!requiresInternalBuffers()) {
        status_t res = mTrackBufferProvider->getNextBuffer(pBuffer, pts);
        if (res == OK) {
            memcpy_by_audio_format(pBuffer->raw, mOutputFormat, pBuffer->raw, mInputFormat,
                    pBuffer->frameCount * mChannels);
        }
        return res;
    }
    if (mBuffer.frameCount == 0) {
        mBuffer.frameCount = pBuffer->frameCount;
        status_t res = mTrackBufferProvider->getNextBuffer(&mBuffer, pts);
        // TODO: Track down a bug in the upstream provider
        // LOG_ALWAYS_FATAL_IF(res == OK && mBuffer.frameCount == 0,
        //        "ReformatBufferProvider::getNextBuffer():"
        //        " Invalid zero framecount returned from getNextBuffer()");
        if (res != OK || mBuffer.frameCount == 0) {
            pBuffer->raw = NULL;
            pBuffer->frameCount = 0;
            return res;
        }
    }
    ALOG_ASSERT(mConsumed < mBuffer.frameCount);
    size_t count = min(mOutputCount, mBuffer.frameCount - mConsumed);
    count = min(count, pBuffer->frameCount);
    pBuffer->raw = mOutputData;
    pBuffer->frameCount = count;
    //ALOGV("reformatting %d frames from %#x to %#x, %d chan",
    //        pBuffer->frameCount, mInputFormat, mOutputFormat, mChannels);
    memcpy_by_audio_format(pBuffer->raw, mOutputFormat,
            (uint8_t*)mBuffer.raw + mConsumed * mInputFrameSize, mInputFormat,
            pBuffer->frameCount * mChannels);
    return OK;
}

void AudioMixer::ReformatBufferProvider::releaseBuffer(AudioBufferProvider::Buffer *pBuffer) {
    //ALOGV("ReformatBufferProvider(%p)::releaseBuffer(%p(%zu))",
    //        this, pBuffer, pBuffer->frameCount);
    if (!requiresInternalBuffers()) {
        mTrackBufferProvider->releaseBuffer(pBuffer);
        return;
    }
    // LOG_ALWAYS_FATAL_IF(pBuffer->frameCount == 0, "Invalid framecount");
    mConsumed += pBuffer->frameCount; // TODO: update for efficiency to reuse existing content
    if (mConsumed != 0 && mConsumed >= mBuffer.frameCount) {
        mConsumed = 0;
        mTrackBufferProvider->releaseBuffer(&mBuffer);
        // ALOG_ASSERT(mBuffer.frameCount == 0);
    }
    pBuffer->raw = NULL;
    pBuffer->frameCount = 0;
}

void AudioMixer::ReformatBufferProvider::reset() {
    if (mBuffer.frameCount != 0) {
        mTrackBufferProvider->releaseBuffer(&mBuffer);
    }
    mConsumed = 0;
}


// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
bool AudioMixer::sIsMultichannelCapable = false;
bool AudioMixer::sIsMultichannelCapable = false;
@@ -181,7 +279,8 @@ int AudioMixer::getTrackName(audio_channel_mask_t channelMask,
        // t->frameCount
        // t->frameCount
        t->channelCount = audio_channel_count_from_out_mask(channelMask);
        t->channelCount = audio_channel_count_from_out_mask(channelMask);
        t->enabled = false;
        t->enabled = false;
        t->format = 16;
        ALOGV_IF(channelMask != AUDIO_CHANNEL_OUT_STEREO,
                "Non-stereo channel mask: %d\n", channelMask);
        t->channelMask = channelMask;
        t->channelMask = channelMask;
        t->sessionId = sessionId;
        t->sessionId = sessionId;
        // setBufferProvider(name, AudioBufferProvider *) is required before enable(name)
        // setBufferProvider(name, AudioBufferProvider *) is required before enable(name)
@@ -196,9 +295,15 @@ int AudioMixer::getTrackName(audio_channel_mask_t channelMask,
        // setParameter(name, TRACK, MAIN_BUFFER, mixBuffer) is required before enable(name)
        // setParameter(name, TRACK, MAIN_BUFFER, mixBuffer) is required before enable(name)
        t->mainBuffer = NULL;
        t->mainBuffer = NULL;
        t->auxBuffer = NULL;
        t->auxBuffer = NULL;
        t->mInputBufferProvider = NULL;
        t->mReformatBufferProvider = NULL;
        t->downmixerBufferProvider = NULL;
        t->downmixerBufferProvider = NULL;
        t->mMixerFormat = AUDIO_FORMAT_PCM_16_BIT;
        t->mMixerFormat = AUDIO_FORMAT_PCM_16_BIT;
        t->mFormat = format;
        t->mFormat = format;
        t->mMixerInFormat = AUDIO_FORMAT_PCM_16_BIT;
        if (t->mFormat != t->mMixerInFormat) {
            prepareTrackForReformat(t, n);
        }
        status_t status = initTrackDownmix(&mState.tracks[n], n, channelMask);
        status_t status = initTrackDownmix(&mState.tracks[n], n, channelMask);
        if (status != OK) {
        if (status != OK) {
            ALOGE("AudioMixer::getTrackName invalid channelMask (%#x)", channelMask);
            ALOGE("AudioMixer::getTrackName invalid channelMask (%#x)", channelMask);
@@ -242,9 +347,9 @@ void AudioMixer::unprepareTrackForDownmix(track_t* pTrack, int trackName __unuse
    if (pTrack->downmixerBufferProvider != NULL) {
    if (pTrack->downmixerBufferProvider != NULL) {
        // this track had previously been configured with a downmixer, delete it
        // this track had previously been configured with a downmixer, delete it
        ALOGV(" deleting old downmixer");
        ALOGV(" deleting old downmixer");
        pTrack->bufferProvider = pTrack->downmixerBufferProvider->mTrackBufferProvider;
        delete pTrack->downmixerBufferProvider;
        delete pTrack->downmixerBufferProvider;
        pTrack->downmixerBufferProvider = NULL;
        pTrack->downmixerBufferProvider = NULL;
        reconfigureBufferProviders(pTrack);
    } else {
    } else {
        ALOGV(" nothing to do, no downmixer to delete");
        ALOGV(" nothing to do, no downmixer to delete");
    }
    }
@@ -338,21 +443,51 @@ status_t AudioMixer::prepareTrackForDownmix(track_t* pTrack, int trackName)
    }// end of scope for local variables that are not used in goto label "noDownmixForActiveTrack"
    }// end of scope for local variables that are not used in goto label "noDownmixForActiveTrack"


    // initialization successful:
    // initialization successful:
    // - keep track of the real buffer provider in case it was set before
    pDbp->mTrackBufferProvider = pTrack->bufferProvider;
    // - we'll use the downmix effect integrated inside this
    //    track's buffer provider, and we'll use it as the track's buffer provider
    pTrack->downmixerBufferProvider = pDbp;
    pTrack->downmixerBufferProvider = pDbp;
    pTrack->bufferProvider = pDbp;
    reconfigureBufferProviders(pTrack);

    return NO_ERROR;
    return NO_ERROR;


noDownmixForActiveTrack:
noDownmixForActiveTrack:
    delete pDbp;
    delete pDbp;
    pTrack->downmixerBufferProvider = NULL;
    pTrack->downmixerBufferProvider = NULL;
    reconfigureBufferProviders(pTrack);
    return NO_INIT;
    return NO_INIT;
}
}


void AudioMixer::unprepareTrackForReformat(track_t* pTrack, int trackName __unused) {
    ALOGV("AudioMixer::unprepareTrackForReformat(%d)", trackName);
    if (pTrack->mReformatBufferProvider != NULL) {
        delete pTrack->mReformatBufferProvider;
        pTrack->mReformatBufferProvider = NULL;
        reconfigureBufferProviders(pTrack);
    }
}

status_t AudioMixer::prepareTrackForReformat(track_t* pTrack, int trackName)
{
    ALOGV("AudioMixer::prepareTrackForReformat(%d) with format %#x", trackName, pTrack->mFormat);
    // discard the previous reformatter if there was one
     unprepareTrackForReformat(pTrack, trackName);
     pTrack->mReformatBufferProvider = new ReformatBufferProvider(
             audio_channel_count_from_out_mask(pTrack->channelMask),
             pTrack->mFormat, pTrack->mMixerInFormat);
     reconfigureBufferProviders(pTrack);
     return NO_ERROR;
}

void AudioMixer::reconfigureBufferProviders(track_t* pTrack)
{
    pTrack->bufferProvider = pTrack->mInputBufferProvider;
    if (pTrack->mReformatBufferProvider) {
        pTrack->mReformatBufferProvider->mTrackBufferProvider = pTrack->bufferProvider;
        pTrack->bufferProvider = pTrack->mReformatBufferProvider;
    }
    if (pTrack->downmixerBufferProvider) {
        pTrack->downmixerBufferProvider->mTrackBufferProvider = pTrack->bufferProvider;
        pTrack->bufferProvider = pTrack->downmixerBufferProvider;
    }
}

void AudioMixer::deleteTrackName(int name)
void AudioMixer::deleteTrackName(int name)
{
{
    ALOGV("AudioMixer::deleteTrackName(%d)", name);
    ALOGV("AudioMixer::deleteTrackName(%d)", name);
@@ -369,6 +504,8 @@ void AudioMixer::deleteTrackName(int name)
    track.resampler = NULL;
    track.resampler = NULL;
    // delete the downmixer
    // delete the downmixer
    unprepareTrackForDownmix(&mState.tracks[name], name);
    unprepareTrackForDownmix(&mState.tracks[name], name);
    // delete the reformatter
    unprepareTrackForReformat(&mState.tracks[name], name);


    mTrackNames &= ~(1<<name);
    mTrackNames &= ~(1<<name);
}
}
@@ -440,9 +577,20 @@ void AudioMixer::setParameter(int name, int target, int param, void *value)
                invalidateState(1 << name);
                invalidateState(1 << name);
            }
            }
            break;
            break;
        case FORMAT:
        case FORMAT: {
            ALOG_ASSERT(valueInt == AUDIO_FORMAT_PCM_16_BIT);
            audio_format_t format = static_cast<audio_format_t>(valueInt);
            break;
            if (track.mFormat != format) {
                ALOG_ASSERT(audio_is_linear_pcm(format), "Invalid format %#x", format);
                track.mFormat = format;
                ALOGV("setParameter(TRACK, FORMAT, %#x)", format);
                //if (track.mFormat != track.mMixerInFormat)
                {
                    ALOGD("Reformatting!");
                    prepareTrackForReformat(&track, name);
                }
                invalidateState(1 << name);
            }
            } break;
        // FIXME do we want to support setting the downmix type from AudioFlinger?
        // FIXME do we want to support setting the downmix type from AudioFlinger?
        //         for a specific track? or per mixer?
        //         for a specific track? or per mixer?
        /* case DOWNMIX_TYPE:
        /* case DOWNMIX_TYPE:
@@ -555,8 +703,9 @@ bool AudioMixer::track_t::setResampler(uint32_t value, uint32_t devSampleRate)
                } else {
                } else {
                    quality = AudioResampler::DEFAULT_QUALITY;
                    quality = AudioResampler::DEFAULT_QUALITY;
                }
                }
                const int bits = mMixerInFormat == AUDIO_FORMAT_PCM_16_BIT ? 16 : /* FLOAT */ 32;
                resampler = AudioResampler::create(
                resampler = AudioResampler::create(
                        format,
                        bits,
                        // the resampler sees the number of channels after the downmixer, if any
                        // the resampler sees the number of channels after the downmixer, if any
                        (int) (downmixerBufferProvider != NULL ? MAX_NUM_CHANNELS : channelCount),
                        (int) (downmixerBufferProvider != NULL ? MAX_NUM_CHANNELS : channelCount),
                        devSampleRate, quality);
                        devSampleRate, quality);
@@ -601,21 +750,13 @@ void AudioMixer::setBufferProvider(int name, AudioBufferProvider* bufferProvider
    name -= TRACK0;
    name -= TRACK0;
    ALOG_ASSERT(uint32_t(name) < MAX_NUM_TRACKS, "bad track name %d", name);
    ALOG_ASSERT(uint32_t(name) < MAX_NUM_TRACKS, "bad track name %d", name);


    if (mState.tracks[name].downmixerBufferProvider != NULL) {
    if (mState.tracks[name].mReformatBufferProvider != NULL) {
        // update required?
        mState.tracks[name].mReformatBufferProvider->reset();
        if (mState.tracks[name].downmixerBufferProvider->mTrackBufferProvider != bufferProvider) {
    } else if (mState.tracks[name].downmixerBufferProvider != NULL) {
            ALOGV("AudioMixer::setBufferProvider(%p) for downmix", bufferProvider);
            // setting the buffer provider for a track that gets downmixed consists in:
            //  1/ setting the buffer provider to the "downmix / buffer provider" wrapper
            //     so it's the one that gets called when the buffer provider is needed,
            mState.tracks[name].bufferProvider = mState.tracks[name].downmixerBufferProvider;
            //  2/ saving the buffer provider for the track so the wrapper can use it
            //     when it downmixes.
            mState.tracks[name].downmixerBufferProvider->mTrackBufferProvider = bufferProvider;
        }
    } else {
        mState.tracks[name].bufferProvider = bufferProvider;
    }
    }

    mState.tracks[name].mInputBufferProvider = bufferProvider;
    reconfigureBufferProviders(&mState.tracks[name]);
}
}




+45 −3
Original line number Original line Diff line number Diff line
@@ -126,7 +126,10 @@ public:
    size_t      getUnreleasedFrames(int name) const;
    size_t      getUnreleasedFrames(int name) const;


    static inline bool isValidPcmTrackFormat(audio_format_t format) {
    static inline bool isValidPcmTrackFormat(audio_format_t format) {
        return format == AUDIO_FORMAT_PCM_16_BIT;
        return format == AUDIO_FORMAT_PCM_16_BIT ||
                format == AUDIO_FORMAT_PCM_24_BIT_PACKED ||
                format == AUDIO_FORMAT_PCM_32_BIT ||
                format == AUDIO_FORMAT_PCM_FLOAT;
    }
    }


private:
private:
@@ -150,6 +153,7 @@ private:
    struct state_t;
    struct state_t;
    struct track_t;
    struct track_t;
    class DownmixerBufferProvider;
    class DownmixerBufferProvider;
    class ReformatBufferProvider;


    typedef void (*hook_t)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp,
    typedef void (*hook_t)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp,
                           int32_t* aux);
                           int32_t* aux);
@@ -177,7 +181,7 @@ private:
        uint16_t    frameCount;
        uint16_t    frameCount;


        uint8_t     channelCount;   // 1 or 2, redundant with (needs & NEEDS_CHANNEL_COUNT__MASK)
        uint8_t     channelCount;   // 1 or 2, redundant with (needs & NEEDS_CHANNEL_COUNT__MASK)
        uint8_t     format;         // always 16
        uint8_t     unused_padding; // formerly format, was always 16
        uint16_t    enabled;        // actually bool
        uint16_t    enabled;        // actually bool
        audio_channel_mask_t channelMask;
        audio_channel_mask_t channelMask;


@@ -200,13 +204,19 @@ private:
        int32_t*           auxBuffer;
        int32_t*           auxBuffer;


        // 16-byte boundary
        // 16-byte boundary

        AudioBufferProvider*     mInputBufferProvider;    // 4 bytes
        ReformatBufferProvider*  mReformatBufferProvider; // 4 bytes
        DownmixerBufferProvider* downmixerBufferProvider; // 4 bytes
        DownmixerBufferProvider* downmixerBufferProvider; // 4 bytes


        int32_t     sessionId;
        int32_t     sessionId;


        // 16-byte boundary
        audio_format_t mMixerFormat;     // output mix format: AUDIO_FORMAT_PCM_(FLOAT|16_BIT)
        audio_format_t mMixerFormat;     // output mix format: AUDIO_FORMAT_PCM_(FLOAT|16_BIT)
        audio_format_t mFormat;          // input track format
        audio_format_t mFormat;          // input track format
        audio_format_t mMixerInFormat;   // mix internal format AUDIO_FORMAT_PCM_(FLOAT|16_BIT)
                                         // each track must be converted to this format.

        int32_t        mUnused[1];       // alignment padding


        // 16-byte boundary
        // 16-byte boundary


@@ -245,6 +255,35 @@ private:
        effect_config_t    mDownmixConfig;
        effect_config_t    mDownmixConfig;
    };
    };


    // AudioBufferProvider wrapper that reformats track to acceptable mixer input type
    class ReformatBufferProvider : public AudioBufferProvider {
    public:
        ReformatBufferProvider(int32_t channels,
                audio_format_t inputFormat, audio_format_t outputFormat);
        virtual ~ReformatBufferProvider();

        // overrides AudioBufferProvider methods
        virtual status_t getNextBuffer(Buffer* buffer, int64_t pts);
        virtual void releaseBuffer(Buffer* buffer);

        void reset();
        inline bool requiresInternalBuffers() {
            return true; //mInputFrameSize < mOutputFrameSize;
        }

        AudioBufferProvider* mTrackBufferProvider;
        int32_t              mChannels;
        audio_format_t       mInputFormat;
        audio_format_t       mOutputFormat;
        size_t               mInputFrameSize;
        size_t               mOutputFrameSize;
        // (only) required for reformatting to a larger size.
        AudioBufferProvider::Buffer mBuffer;
        void*                mOutputData;
        size_t               mOutputCount;
        size_t               mConsumed;
    };

    // bitmask of allocated track names, where bit 0 corresponds to TRACK0 etc.
    // bitmask of allocated track names, where bit 0 corresponds to TRACK0 etc.
    uint32_t        mTrackNames;
    uint32_t        mTrackNames;


@@ -272,6 +311,9 @@ private:
    static status_t initTrackDownmix(track_t* pTrack, int trackNum, audio_channel_mask_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 status_t prepareTrackForDownmix(track_t* pTrack, int trackNum);
    static void unprepareTrackForDownmix(track_t* pTrack, int trackName);
    static void unprepareTrackForDownmix(track_t* pTrack, int trackName);
    static status_t prepareTrackForReformat(track_t* pTrack, int trackNum);
    static void unprepareTrackForReformat(track_t* pTrack, int trackName);
    static void reconfigureBufferProviders(track_t* pTrack);


    static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp,
    static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp,
            int32_t* aux);
            int32_t* aux);
+5 −1
Original line number Original line Diff line number Diff line
@@ -231,6 +231,8 @@ void FastMixer::onStateChange()
                mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER,
                mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MAIN_BUFFER,
                        (void *) mixBuffer);
                        (void *) mixBuffer);
                // newly allocated track names default to full scale volume
                // newly allocated track names default to full scale volume
                mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT,
                        (void *)(uintptr_t)fastTrack->mFormat);
                mixer->enable(name);
                mixer->enable(name);
            }
            }
            generations[i] = fastTrack->mGeneration;
            generations[i] = fastTrack->mGeneration;
@@ -259,6 +261,8 @@ void FastMixer::onStateChange()
                    }
                    }
                    mixer->setParameter(name, AudioMixer::RESAMPLE,
                    mixer->setParameter(name, AudioMixer::RESAMPLE,
                            AudioMixer::REMOVE, NULL);
                            AudioMixer::REMOVE, NULL);
                    mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT,
                            (void *)(uintptr_t)fastTrack->mFormat);
                    mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK,
                    mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK,
                            (void *)(uintptr_t) fastTrack->mChannelMask);
                            (void *)(uintptr_t) fastTrack->mChannelMask);
                    // already enabled
                    // already enabled
@@ -281,7 +285,7 @@ void FastMixer::onWork()
    const size_t frameCount = current->mFrameCount;
    const size_t frameCount = current->mFrameCount;


    if ((command & FastMixerState::MIX) && (mixer != NULL) && isWarm) {
    if ((command & FastMixerState::MIX) && (mixer != NULL) && isWarm) {
        ALOG_ASSERT(mixBuffer != NULL);
        ALOG_ASSERT(mMixerBuffer != NULL);
        // for each track, update volume and check for underrun
        // for each track, update volume and check for underrun
        unsigned currentTrackMask = current->mTrackMask;
        unsigned currentTrackMask = current->mTrackMask;
        while (currentTrackMask != 0) {
        while (currentTrackMask != 0) {