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

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

Merge "Add floating and multichannel record to AudioFlinger"

parents b8aea1d4 d330ee46
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -73,18 +73,18 @@ class AudioMixer;
class AudioBuffer;
class AudioResampler;
class FastMixer;
class PassthruBufferProvider;
class ServerProxy;

// ----------------------------------------------------------------------------

// AudioFlinger has a hard-coded upper limit of 2 channels for capture and playback.
// There is support for > 2 channel tracks down-mixed to 2 channel output via a down-mix effect.
// Adding full support for > 2 channel capture or playback would require more than simply changing
// this #define.  There is an independent hard-coded upper limit in AudioMixer;
// removing that AudioMixer limit would be necessary but insufficient to support > 2 channels.
// The macro FCC_2 highlights some (but not all) places where there is are 2-channel assumptions.
// The macro FCC_2 highlights some (but not all) places where there are are 2-channel assumptions.
// This is typically due to legacy implementation of stereo input or output.
// Search also for "2", "left", "right", "[0]", "[1]", ">> 16", "<< 16", etc.
#define FCC_2 2     // FCC_2 = Fixed Channel Count 2
// The macro FCC_8 highlights places where there are 8-channel assumptions.
// This is typically due to audio mixer and resampler limitations.
#define FCC_8 8     // FCC_8 = Fixed Channel Count 8

static const nsecs_t kDefaultStandbyTimeInNsecs = seconds(3);

+1 −1
Original line number Diff line number Diff line
@@ -105,7 +105,7 @@ void FastCapture::onStateChange()
            mFormat = mInputSource->format();
            mSampleRate = Format_sampleRate(mFormat);
            unsigned channelCount = Format_channelCount(mFormat);
            ALOG_ASSERT(channelCount == 1 || channelCount == 2);
            ALOG_ASSERT(channelCount >= 1 && channelCount <= FCC_8);
        }
        dumpState->mSampleRate = mSampleRate;
        eitherChanged = true;
+144 −67
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@

#include "AudioFlinger.h"
#include "AudioMixer.h"
#include "BufferProviders.h"
#include "FastMixer.h"
#include "FastCapture.h"
#include "ServiceUtilities.h"
@@ -94,6 +95,10 @@ static inline T min(const T& a, const T& b)
    return a < b ? a : b;
}

#ifndef ARRAY_SIZE
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
#endif

namespace android {

// retry counts for buffer fill timeout
@@ -6246,7 +6251,11 @@ AudioFlinger::RecordThread::RecordBufferConverter::RecordBufferConverter(
            // mDstChannelCount
            // mDstFrameSize
            mBuf(NULL), mBufFrames(0), mBufFrameSize(0),
            mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpOutFrameCount(0)
            mResampler(NULL),
            mIsLegacyDownmix(false),
            mIsLegacyUpmix(false),
            mRequiresFloat(false),
            mInputConverterProvider(NULL)
{
    (void)updateParameters(srcChannelMask, srcFormat, srcSampleRate,
            dstChannelMask, dstFormat, dstSampleRate);
@@ -6255,13 +6264,18 @@ AudioFlinger::RecordThread::RecordBufferConverter::RecordBufferConverter(
AudioFlinger::RecordThread::RecordBufferConverter::~RecordBufferConverter() {
    free(mBuf);
    delete mResampler;
    free(mRsmpOutBuffer);
    delete mInputConverterProvider;
}

size_t AudioFlinger::RecordThread::RecordBufferConverter::convert(void *dst,
        AudioBufferProvider *provider, size_t frames)
{
    if (mSrcSampleRate == mDstSampleRate) {
    if (mInputConverterProvider != NULL) {
        mInputConverterProvider->setBufferProvider(provider);
        provider = mInputConverterProvider;
    }

    if (mResampler == NULL) {
        ALOGVV("NO RESAMPLING sampleRate:%u mSrcFormat:%#x mDstFormat:%#x",
                mSrcSampleRate, mSrcFormat, mDstFormat);

@@ -6273,8 +6287,8 @@ size_t AudioFlinger::RecordThread::RecordBufferConverter::convert(void *dst,
                frames -= i; // cannot fill request.
                break;
            }
            // convert to destination buffer
            convert(dst, buffer.raw, buffer.frameCount);
            // format convert to destination buffer
            convertNoResampler(dst, buffer.raw, buffer.frameCount);

            dst = (int8_t*)dst + buffer.frameCount * mDstFrameSize;
            i -= buffer.frameCount;
@@ -6284,20 +6298,17 @@ size_t AudioFlinger::RecordThread::RecordBufferConverter::convert(void *dst,
         ALOGVV("RESAMPLING mSrcSampleRate:%u mDstSampleRate:%u mSrcFormat:%#x mDstFormat:%#x",
                 mSrcSampleRate, mDstSampleRate, mSrcFormat, mDstFormat);

        // reallocate mRsmpOutBuffer as needed; we will grow but never shrink
        if (mRsmpOutFrameCount < frames) {
            // FIXME why does each track need it's own mRsmpOutBuffer? can't they share?
            free(mRsmpOutBuffer);
            // resampler always outputs stereo (FOR NOW)
            (void)posix_memalign(&mRsmpOutBuffer, 32, frames * FCC_2 * sizeof(int32_t) /*Q4.27*/);
            mRsmpOutFrameCount = frames;
         // reallocate buffer if needed
         if (mBufFrameSize != 0 && mBufFrames < frames) {
             free(mBuf);
             mBufFrames = frames;
             (void)posix_memalign(&mBuf, 32, mBufFrames * mBufFrameSize);
         }
        // resampler accumulates, but we only have one source track
        memset(mRsmpOutBuffer, 0, frames * FCC_2 * sizeof(int32_t));
        frames = mResampler->resample((int32_t*)mRsmpOutBuffer, frames, provider);

        // convert to destination buffer
        convert(dst, mRsmpOutBuffer, frames);
        memset(mBuf, 0, frames * mBufFrameSize);
        frames = mResampler->resample((int32_t*)mBuf, frames, provider);
        // format convert to destination buffer
        convertResampler(dst, mBuf, frames);
    }
    return frames;
}
@@ -6341,74 +6352,132 @@ status_t AudioFlinger::RecordThread::RecordBufferConverter::updateParameters(
    mDstChannelCount = audio_channel_count_from_in_mask(dstChannelMask);
    mDstFrameSize = mDstChannelCount * audio_bytes_per_sample(mDstFormat);

    // do we need a format buffer?
    if (mSrcFormat != mDstFormat && mDstChannelCount != mSrcChannelCount) {
    // do we need to resample?
    delete mResampler;
    mResampler = NULL;
    if (mSrcSampleRate != mDstSampleRate) {
        mResampler = AudioResampler::create(AUDIO_FORMAT_PCM_FLOAT,
                mSrcChannelCount, mDstSampleRate);
        mResampler->setSampleRate(mSrcSampleRate);
        mResampler->setVolume(AudioMixer::UNITY_GAIN_FLOAT, AudioMixer::UNITY_GAIN_FLOAT);
    }

    // are we running legacy channel conversion modes?
    mIsLegacyDownmix = (mSrcChannelMask == AUDIO_CHANNEL_IN_STEREO
                            || mSrcChannelMask == AUDIO_CHANNEL_IN_FRONT_BACK)
                   && mDstChannelMask == AUDIO_CHANNEL_IN_MONO;
    mIsLegacyUpmix = mSrcChannelMask == AUDIO_CHANNEL_IN_MONO
                   && (mDstChannelMask == AUDIO_CHANNEL_IN_STEREO
                            || mDstChannelMask == AUDIO_CHANNEL_IN_FRONT_BACK);

    // do we need to process in float?
    mRequiresFloat = mResampler != NULL || mIsLegacyDownmix || mIsLegacyUpmix;

    // do we need a staging buffer to convert for destination (we can still optimize this)?
    // we use mBufFrameSize > 0 to indicate both frame size as well as buffer necessity
    if (mResampler != NULL) {
        mBufFrameSize = max(mSrcChannelCount, FCC_2)
                * audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT);
    } else if ((mIsLegacyUpmix || mIsLegacyDownmix) && mDstFormat != AUDIO_FORMAT_PCM_FLOAT) {
        mBufFrameSize = mDstChannelCount * audio_bytes_per_sample(AUDIO_FORMAT_PCM_FLOAT);
    } else if (mSrcChannelMask != mDstChannelMask && mDstFormat != mSrcFormat) {
        mBufFrameSize = mDstChannelCount * audio_bytes_per_sample(mSrcFormat);
    } else {
        mBufFrameSize = 0;
    }
    mBufFrames = 0; // force the buffer to be resized.

    // do we need to resample?
    if (mSrcSampleRate != mDstSampleRate) {
        if (mResampler != NULL) {
            delete mResampler;
    // do we need an input converter buffer provider to give us float?
    delete mInputConverterProvider;
    mInputConverterProvider = NULL;
    if (mRequiresFloat && mSrcFormat != AUDIO_FORMAT_PCM_FLOAT) {
        mInputConverterProvider = new ReformatBufferProvider(
                audio_channel_count_from_in_mask(mSrcChannelMask),
                mSrcFormat,
                AUDIO_FORMAT_PCM_FLOAT,
                256 /* provider buffer frame count */);
    }
        mResampler = AudioResampler::create(AUDIO_FORMAT_PCM_16_BIT,
                mSrcChannelCount, mDstSampleRate); // may seem confusing...
        mResampler->setSampleRate(mSrcSampleRate);
        mResampler->setVolume(AudioMixer::UNITY_GAIN_FLOAT, AudioMixer::UNITY_GAIN_FLOAT);

    // do we need a remixer to do channel mask conversion
    if (!mIsLegacyDownmix && !mIsLegacyUpmix && mSrcChannelMask != mDstChannelMask) {
        (void) memcpy_by_index_array_initialization_from_channel_mask(
                mIdxAry, ARRAY_SIZE(mIdxAry), mDstChannelMask, mSrcChannelMask);
    }
    return NO_ERROR;
}

void AudioFlinger::RecordThread::RecordBufferConverter::convert(
        void *dst, /*const*/ void *src, size_t frames)
void AudioFlinger::RecordThread::RecordBufferConverter::convertNoResampler(
        void *dst, const void *src, size_t frames)
{
    // check if a memcpy will do
    if (mResampler == NULL
            && mSrcChannelCount == mDstChannelCount
            && mSrcFormat == mDstFormat) {
        memcpy(dst, src,
                frames * mDstChannelCount * audio_bytes_per_sample(mDstFormat));
        return;
    }
    // reallocate buffer if needed
    // src is native type unless there is legacy upmix or downmix, whereupon it is float.
    if (mBufFrameSize != 0 && mBufFrames < frames) {
        free(mBuf);
        mBufFrames = frames;
        (void)posix_memalign(&mBuf, 32, mBufFrames * mBufFrameSize);
    }
    // do processing
    if (mResampler != NULL) {
        // src channel count is always >= 2.
    // do we need to do legacy upmix and downmix?
    if (mIsLegacyUpmix || mIsLegacyDownmix) {
        void *dstBuf = mBuf != NULL ? mBuf : dst;
        // ditherAndClamp() works as long as all buffers returned by
        // activeTrack->getNextBuffer() are 32 bit aligned which should be always true.
        if (mDstChannelCount == 1) {
            // the resampler always outputs stereo samples.
            // FIXME: this rewrites back into src
            ditherAndClamp((int32_t *)src, (const int32_t *)src, frames);
            downmix_to_mono_i16_from_stereo_i16((int16_t *)dstBuf,
                    (const int16_t *)src, frames);
        } else {
            ditherAndClamp((int32_t *)dstBuf, (const int32_t *)src, frames);
        if (mIsLegacyUpmix) {
            upmix_to_stereo_float_from_mono_float((float *)dstBuf,
                    (const float *)src, frames);
        } else /*mIsLegacyDownmix */ {
            downmix_to_mono_float_from_stereo_float((float *)dstBuf,
                    (const float *)src, frames);
        }
        if (mBuf != NULL) {
            memcpy_by_audio_format(dst, mDstFormat, mBuf, AUDIO_FORMAT_PCM_FLOAT,
                    frames * mDstChannelCount);
        }
        return;
    }
    } else if (mSrcChannelCount != mDstChannelCount) {
    // do we need to do channel mask conversion?
    if (mSrcChannelMask != mDstChannelMask) {
        void *dstBuf = mBuf != NULL ? mBuf : dst;
        if (mSrcChannelCount == 1) {
            upmix_to_stereo_i16_from_mono_i16((int16_t *)dstBuf, (const int16_t *)src,
                    frames);
        } else {
            downmix_to_mono_i16_from_stereo_i16((int16_t *)dstBuf,
                    (const int16_t *)src, frames);
        memcpy_by_index_array(dstBuf, mDstChannelCount,
                src, mSrcChannelCount, mIdxAry, audio_bytes_per_sample(mSrcFormat), frames);
        if (dstBuf == dst) {
            return; // format is the same
        }
    }
    if (mSrcFormat != mDstFormat) {
        void *srcBuf = mBuf != NULL ? mBuf : src;
        memcpy_by_audio_format(dst, mDstFormat, srcBuf, mSrcFormat,
    // convert to destination buffer
    const void *convertBuf = mBuf != NULL ? mBuf : src;
    memcpy_by_audio_format(dst, mDstFormat, convertBuf, mSrcFormat,
            frames * mDstChannelCount);
}

void AudioFlinger::RecordThread::RecordBufferConverter::convertResampler(
        void *dst, /*not-a-const*/ void *src, size_t frames)
{
    // src buffer format is ALWAYS float when entering this routine
    if (mIsLegacyUpmix) {
        ; // mono to stereo already handled by resampler
    } else if (mIsLegacyDownmix
            || (mSrcChannelMask == mDstChannelMask && mSrcChannelCount == 1)) {
        // the resampler outputs stereo for mono input channel (a feature?)
        // must convert to mono
        downmix_to_mono_float_from_stereo_float((float *)src,
                (const float *)src, frames);
    } else if (mSrcChannelMask != mDstChannelMask) {
        // convert to mono channel again for channel mask conversion (could be skipped
        // with further optimization).
        if (mSrcChannelCount == 1) {
            downmix_to_mono_float_from_stereo_float((float *)src,
                (const float *)src, frames);
        }
        // convert to destination format (in place, OK as float is larger than other types)
        if (mDstFormat != AUDIO_FORMAT_PCM_FLOAT) {
            memcpy_by_audio_format(src, mDstFormat, src, AUDIO_FORMAT_PCM_FLOAT,
                    frames * mSrcChannelCount);
        }
        // channel convert and save to dst
        memcpy_by_index_array(dst, mDstChannelCount,
                src, mSrcChannelCount, mIdxAry, audio_bytes_per_sample(mDstFormat), frames);
        return;
    }
    // convert to destination format and save to dst
    memcpy_by_audio_format(dst, mDstFormat, src, AUDIO_FORMAT_PCM_FLOAT,
            frames * mDstChannelCount);
}

bool AudioFlinger::RecordThread::checkForNewParameter_l(const String8& keyValuePair,
@@ -6421,6 +6490,10 @@ bool AudioFlinger::RecordThread::checkForNewParameter_l(const String8& keyValueP
    audio_format_t reqFormat = mFormat;
    uint32_t samplingRate = mSampleRate;
    audio_channel_mask_t channelMask = audio_channel_in_mask_from_count(mChannelCount);
    // possible that we are > 2 channels, use channel index mask
    if (channelMask == AUDIO_CHANNEL_INVALID && mChannelCount <= FCC_8) {
        audio_channel_mask_for_index_assignment_from_count(mChannelCount);
    }

    AudioParameter param = AudioParameter(keyValuePair);
    int value;
@@ -6441,7 +6514,8 @@ bool AudioFlinger::RecordThread::checkForNewParameter_l(const String8& keyValueP
    }
    if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) {
        audio_channel_mask_t mask = (audio_channel_mask_t) value;
        if (mask != AUDIO_CHANNEL_IN_MONO && mask != AUDIO_CHANNEL_IN_STEREO) {
        if (!audio_is_input_channel(mask) ||
                audio_channel_count_from_in_mask(mask) > FCC_8) {
            status = BAD_VALUE;
        } else {
            channelMask = mask;
@@ -6566,10 +6640,13 @@ void AudioFlinger::RecordThread::readInputParameters_l()
    mSampleRate = mInput->stream->common.get_sample_rate(&mInput->stream->common);
    mChannelMask = mInput->stream->common.get_channels(&mInput->stream->common);
    mChannelCount = audio_channel_count_from_in_mask(mChannelMask);
    if (mChannelCount > FCC_8) {
        ALOGE("HAL channel count %d > %d", mChannelCount, FCC_8);
    }
    mHALFormat = mInput->stream->common.get_format(&mInput->stream->common);
    mFormat = mHALFormat;
    if (mFormat != AUDIO_FORMAT_PCM_16_BIT) {
        ALOGE("HAL format %#x not supported; must be AUDIO_FORMAT_PCM_16_BIT", mFormat);
    if (!audio_is_linear_pcm(mFormat)) {
        ALOGE("HAL format %#x is not linear pcm", mFormat);
    }
    mFrameSize = audio_stream_in_frame_size(mInput->stream);
    mBufferSize = mInput->stream->common.get_buffer_size(&mInput->stream->common);
+11 −6
Original line number Diff line number Diff line
@@ -1130,8 +1130,11 @@ public:
        }

    private:
        // internal convert function for format and channel mask.
        void convert(void *dst, /*const*/ void *src, size_t frames);
        // format conversion when not using resampler
        void convertNoResampler(void *dst, const void *src, size_t frames);

        // format conversion when using resampler; modifies src in-place
        void convertResampler(void *dst, /*not-a-const*/ void *src, size_t frames);

        // user provided information
        audio_channel_mask_t mSrcChannelMask;
@@ -1153,10 +1156,12 @@ public:

        // resampler info
        AudioResampler      *mResampler;
        // interleaved stereo pairs of fixed-point Q4.27 or float depending on resampler
        void                *mRsmpOutBuffer;
        // current allocated frame count for the above, which may be larger than needed
        size_t               mRsmpOutFrameCount;

        bool                 mIsLegacyDownmix;  // legacy stereo to mono conversion needed
        bool                 mIsLegacyUpmix;    // legacy mono to stereo conversion needed
        bool                 mRequiresFloat;    // data processing requires float (e.g. resampler)
        PassthruBufferProvider *mInputConverterProvider;    // converts input to float
        int8_t               mIdxAry[sizeof(uint32_t) * 8]; // used for channel mask conversion
    };

#include "RecordTracks.h"