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

Commit 9a59276f authored by Andy Hung's avatar Andy Hung
Browse files

Add multichannel capability to AudioFlinger

But not enabled (kEnableExtendedChannels == false).

Change-Id: I62f7e31fbd29ad703a9a02f5d1a280b6972dd423
parent e93b6b73
Loading
Loading
Loading
Loading
+31 −13
Original line number Diff line number Diff line
@@ -1594,16 +1594,25 @@ sp<AudioFlinger::PlaybackThread> AudioFlinger::openOutput_l(audio_module_handle_
    audio_stream_out_t *outStream = NULL;

    // FOR TESTING ONLY:
    // Enable increased sink precision for mixing mode if kEnableExtendedPrecision is true.
    if (kEnableExtendedPrecision &&  // Check only for Normal Mixing mode
            !(flags & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD | AUDIO_OUTPUT_FLAG_DIRECT))) {
        // Update format
        //config.format = AUDIO_FORMAT_PCM_FLOAT;
        //config.format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
        //config.format = AUDIO_FORMAT_PCM_32_BIT;
        //config.format = AUDIO_FORMAT_PCM_8_24_BIT;
    // This if statement allows overriding the audio policy settings
    // and forcing a specific format or channel mask to the HAL/Sink device for testing.
    if (!(flags & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD | AUDIO_OUTPUT_FLAG_DIRECT))) {
        // Check only for Normal Mixing mode
        if (kEnableExtendedPrecision) {
            // Specify format (uncomment one below to choose)
            //config->format = AUDIO_FORMAT_PCM_FLOAT;
            //config->format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
            //config->format = AUDIO_FORMAT_PCM_32_BIT;
            //config->format = AUDIO_FORMAT_PCM_8_24_BIT;
            // ALOGV("openOutput() upgrading format to %#08x", config.format);
        }
        if (kEnableExtendedChannels) {
            // Specify channel mask (uncomment one below to choose)
            //config->channel_mask = audio_channel_out_mask_from_count(4);  // for USB 4ch
            //config->channel_mask = audio_channel_mask_from_representation_and_bits(
            //        AUDIO_CHANNEL_REPRESENTATION_INDEX, (1 << 4) - 1);  // another 4ch example
        }
    }

    status_t status = hwDevHal->open_output_stream(hwDevHal,
                                          id,
@@ -1613,8 +1622,8 @@ sp<AudioFlinger::PlaybackThread> AudioFlinger::openOutput_l(audio_module_handle_
                                          &outStream);

    mHardwareStatus = AUDIO_HW_IDLE;
    ALOGV("openOutput_l() openOutputStream returned output %p, SamplingRate %d, Format %#08x, "
            "Channels %x, status %d",
    ALOGV("openOutput() openOutputStream returned output %p, sampleRate %d, Format %#x, "
            "channelMask %#x, status %d",
            outStream,
            config->sample_rate,
            config->format,
@@ -1630,7 +1639,7 @@ sp<AudioFlinger::PlaybackThread> AudioFlinger::openOutput_l(audio_module_handle_
            ALOGV("openOutput() created offload output: ID %d thread %p", id, thread);
        } else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT)
                || !isValidPcmSinkFormat(config->format)
                || (config->channel_mask != AUDIO_CHANNEL_OUT_STEREO)) {
                || !isValidPcmSinkChannelMask(config->channel_mask)) {
            thread = new DirectOutputThread(this, output, id, device);
            ALOGV("openOutput() created direct output: ID %d thread %p", id, thread);
        } else {
@@ -1792,7 +1801,6 @@ status_t AudioFlinger::closeOutput_nonvirtual(audio_io_handle_t output)
        closeOutputFinish(thread);
    }

    thread.clear();
    return NO_ERROR;
}

@@ -2515,6 +2523,16 @@ status_t AudioFlinger::moveEffectChain_l(int sessionId,
        return INVALID_OPERATION;
    }

    // Check whether the destination thread has a channel count of FCC_2, which is
    // currently required for (most) effects. Prevent moving the effect chain here rather
    // than disabling the addEffect_l() call in dstThread below.
    if (dstThread->mChannelCount != FCC_2) {
        ALOGW("moveEffectChain_l() effect chain failed because"
                " destination thread %p channel count(%u) != %u",
                dstThread, dstThread->mChannelCount, FCC_2);
        return INVALID_OPERATION;
    }

    // remove chain first. This is useful only if reconfiguring effect chain on same output thread,
    // so that a new chain is created with correct parameters when first effect is added. This is
    // otherwise unnecessary as removeEffect_l() will remove the chain when last effect is
+26 −1
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@
#include "FastMixer.h"
#include <media/nbaio/NBAIO.h>
#include "AudioWatchdog.h"
#include "AudioMixer.h"

#include <powermanager/IPowerManager.h>

@@ -327,6 +328,30 @@ private:
                                                audio_devices_t devices);
    void                    purgeStaleEffects_l();

    // Set kEnableExtendedChannels to true to enable greater than stereo output
    // for the MixerThread and device sink.  Number of channels allowed is
    // FCC_2 <= channels <= AudioMixer::MAX_NUM_CHANNELS.
    static const bool kEnableExtendedChannels = false;

    // Returns true if channel mask is permitted for the PCM sink in the MixerThread
    static inline bool isValidPcmSinkChannelMask(audio_channel_mask_t channelMask) {
        switch (audio_channel_mask_get_representation(channelMask)) {
        case AUDIO_CHANNEL_REPRESENTATION_POSITION: {
            uint32_t channelCount = FCC_2; // stereo is default
            if (kEnableExtendedChannels) {
                channelCount = audio_channel_count_from_out_mask(channelMask);
                if (channelCount > AudioMixer::MAX_NUM_CHANNELS) {
                    return false;
                }
            }
            // check that channelMask is the "canonical" one we expect for the channelCount.
            return channelMask == audio_channel_out_mask_from_count(channelCount);
            }
        default:
            return false;
        }
    }

    // Set kEnableExtendedPrecision to true to use extended precision in MixerThread
    static const bool kEnableExtendedPrecision = true;

@@ -565,7 +590,7 @@ private:
        uint32_t version() const { return mHwDevice->common.version; }

    private:
        audio_module_handle_t mHandle;
        const audio_module_handle_t mHandle;
        const char * const mModuleName;
        audio_hw_device_t * const mHwDevice;
        const Flags mFlags;
+4 −1
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@
#include <common_time/cc_helper.h>

#include <media/EffectsFactoryApi.h>
#include <audio_effects/effect_downmix.h>

#include "AudioMixerOps.h"
#include "AudioMixer.h"
@@ -941,7 +942,9 @@ bool AudioMixer::track_t::setResampler(uint32_t trackSampleRate, uint32_t devSam
                // but if none exists, it is the channel count (1 for mono).
                const int resamplerChannelCount = downmixerBufferProvider != NULL
                        ? mMixerChannelCount : channelCount;
                ALOGVV("Creating resampler with %#x format\n", mMixerInFormat);
                ALOGVV("Creating resampler:"
                        " format(%#x) channels(%d) devSampleRate(%u) quality(%d)\n",
                        mMixerInFormat, resamplerChannelCount, devSampleRate, quality);
                resampler = AudioResampler::create(
                        mMixerInFormat,
                        resamplerChannelCount,
+1 −1
Original line number Diff line number Diff line
@@ -26,7 +26,7 @@
#include <media/AudioBufferProvider.h>
#include "AudioResampler.h"

#include <audio_effects/effect_downmix.h>
#include <hardware/audio_effect.h>
#include <system/audio.h>
#include <media/nbaio/NBLog.h>

+24 −5
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ FastMixer::FastMixer() : FastThread(),
    mixer(NULL),
    mSinkBuffer(NULL),
    mSinkBufferSize(0),
    mSinkChannelCount(FCC_2),
    mMixerBuffer(NULL),
    mMixerBufferSize(0),
    mMixerBufferFormat(AUDIO_FORMAT_PCM_16_BIT),
@@ -71,6 +72,9 @@ FastMixer::FastMixer() : FastThread(),
    current = &initial;

    mDummyDumpState = &dummyDumpState;
    // 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);

    unsigned i;
    for (i = 0; i < FastMixerState::kMaxFastTracks; ++i) {
@@ -148,10 +152,17 @@ void FastMixer::onStateChange()
        if (outputSink == NULL) {
            format = Format_Invalid;
            sampleRate = 0;
            mSinkChannelCount = 0;
            mSinkChannelMask = AUDIO_CHANNEL_NONE;
        } else {
            format = outputSink->format();
            sampleRate = Format_sampleRate(format);
            ALOG_ASSERT(Format_channelCount(format) == FCC_2);
            mSinkChannelCount = Format_channelCount(format);
            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);
        }
        dumpState->mSampleRate = sampleRate;
    }
@@ -169,10 +180,12 @@ void FastMixer::onStateChange()
            //       implementation; it would be better to have normal mixer allocate for us
            //       to avoid blocking here and to prevent possible priority inversion
            mixer = new AudioMixer(frameCount, sampleRate, FastMixerState::kMaxFastTracks);
            const size_t mixerFrameSize = FCC_2 * audio_bytes_per_sample(mMixerBufferFormat);
            const size_t mixerFrameSize = mSinkChannelCount
                    * audio_bytes_per_sample(mMixerBufferFormat);
            mMixerBufferSize = mixerFrameSize * frameCount;
            (void)posix_memalign(&mMixerBuffer, 32, mMixerBufferSize);
            const size_t sinkFrameSize = FCC_2 * audio_bytes_per_sample(format.mFormat);
            const size_t sinkFrameSize = mSinkChannelCount
                    * audio_bytes_per_sample(format.mFormat);
            if (sinkFrameSize > mixerFrameSize) { // need a sink buffer
                mSinkBufferSize = sinkFrameSize * frameCount;
                (void)posix_memalign(&mSinkBuffer, 32, mSinkBufferSize);
@@ -252,6 +265,10 @@ void FastMixer::onStateChange()
                        AudioMixer::MIXER_FORMAT, (void *)mMixerBufferFormat);
                mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::FORMAT,
                        (void *)(uintptr_t)fastTrack->mFormat);
                mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK,
                        (void *)(uintptr_t)fastTrack->mChannelMask);
                mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK,
                        (void *)(uintptr_t)mSinkChannelMask);
                mixer->enable(name);
            }
            generations[i] = fastTrack->mGeneration;
@@ -287,6 +304,8 @@ void FastMixer::onStateChange()
                            (void *)(uintptr_t)fastTrack->mFormat);
                    mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK,
                            (void *)(uintptr_t)fastTrack->mChannelMask);
                    mixer->setParameter(name, AudioMixer::TRACK, AudioMixer::MIXER_CHANNEL_MASK,
                            (void *)(uintptr_t)mSinkChannelMask);
                    // already enabled
                }
                generations[i] = fastTrack->mGeneration;
Loading