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

Commit f129b03f authored by Andy Hung's avatar Andy Hung
Browse files

Enable 8 bit and float pcm record formats for AudioPolicyManager

Add capability for handling different record channel masks.

Change-Id: I63f6b029aca5cefff7adf26198a3b594a7ea2d71
parent b6347ac6
Loading
Loading
Loading
Loading
+11 −2
Original line number Diff line number Diff line
@@ -62,8 +62,12 @@ public:
    // searches for an exact match
    status_t checkExactChannelMask(audio_channel_mask_t channelMask) const;
    // searches for a compatible match, currently implemented for input channel masks only
    status_t checkCompatibleChannelMask(audio_channel_mask_t channelMask) const;
    status_t checkFormat(audio_format_t format) const;
    status_t checkCompatibleChannelMask(audio_channel_mask_t channelMask,
            audio_channel_mask_t *updatedChannelMask) const;

    status_t checkExactFormat(audio_format_t format) const;
    // searches for a compatible match, currently implemented for input formats only
    status_t checkCompatibleFormat(audio_format_t format, audio_format_t *updatedFormat) const;
    status_t checkGain(const struct audio_gain_config *gainConfig, int index) const;

    uint32_t pickSamplingRate() const;
@@ -71,6 +75,11 @@ public:
    audio_format_t pickFormat() const;

    static const audio_format_t sPcmFormatCompareTable[];
    static int compareFormatsGoodToBad(
            const audio_format_t *format1, const audio_format_t *format2) {
        // compareFormats sorts from bad to good, we reverse it here
        return compareFormats(*format2, *format1);
    }
    static int compareFormats(audio_format_t format1, audio_format_t format2);

    audio_module_handle_t getModuleHandle() const;
+2 −0
Original line number Diff line number Diff line
@@ -45,7 +45,9 @@ public:
                             uint32_t samplingRate,
                             uint32_t *updatedSamplingRate,
                             audio_format_t format,
                             audio_format_t *updatedFormat,
                             audio_channel_mask_t channelMask,
                             audio_channel_mask_t *updatedChannelMask,
                             uint32_t flags) const;

    void dump(int fd);
+48 −13
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@

#define LOG_TAG "APM::AudioPort"
//#define LOG_NDEBUG 0

#include <media/AudioResamplerPublic.h>
#include "AudioPort.h"
#include "HwModule.h"
#include "AudioGain.h"
@@ -216,6 +216,7 @@ void AudioPort::loadFormats(char *name)
        }
        str = strtok(NULL, "|");
    }
    mFormats.sort(compareFormatsGoodToBad);
}

void AudioPort::loadInChannels(char *name)
@@ -358,6 +359,9 @@ status_t AudioPort::checkCompatibleSamplingRate(uint32_t samplingRate,
        uint32_t *updatedSamplingRate) const
{
    if (mSamplingRates.isEmpty()) {
        if (updatedSamplingRate != NULL) {
            *updatedSamplingRate = samplingRate;
        }
        return NO_ERROR;
    }

@@ -387,16 +391,11 @@ status_t AudioPort::checkCompatibleSamplingRate(uint32_t samplingRate,
            }
        }
    }
    // This uses hard-coded knowledge about AudioFlinger resampling ratios.
    // TODO Move these assumptions out.
    static const uint32_t kMaxDownSampleRatio = 6;  // beyond this aliasing occurs
    static const uint32_t kMaxUpSampleRatio = 256;  // beyond this sample rate inaccuracies occur
                                                    // due to approximation by an int32_t of the
                                                    // phase increments

    // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
    if (minAbove >= 0) {
        candidate = mSamplingRates[minAbove];
        if (candidate / kMaxDownSampleRatio <= samplingRate) {
        if (candidate / AUDIO_RESAMPLER_DOWN_RATIO_MAX <= samplingRate) {
            if (updatedSamplingRate != NULL) {
                *updatedSamplingRate = candidate;
            }
@@ -406,7 +405,7 @@ status_t AudioPort::checkCompatibleSamplingRate(uint32_t samplingRate,
    // But if we have to up-sample from a lower sampling rate, that's OK.
    if (maxBelow >= 0) {
        candidate = mSamplingRates[maxBelow];
        if (candidate * kMaxUpSampleRatio >= samplingRate) {
        if (candidate * AUDIO_RESAMPLER_UP_RATIO_MAX >= samplingRate) {
            if (updatedSamplingRate != NULL) {
                *updatedSamplingRate = candidate;
            }
@@ -431,10 +430,13 @@ status_t AudioPort::checkExactChannelMask(audio_channel_mask_t channelMask) cons
    return BAD_VALUE;
}

status_t AudioPort::checkCompatibleChannelMask(audio_channel_mask_t channelMask)
        const
status_t AudioPort::checkCompatibleChannelMask(audio_channel_mask_t channelMask,
        audio_channel_mask_t *updatedChannelMask) const
{
    if (mChannelMasks.isEmpty()) {
        if (updatedChannelMask != NULL) {
            *updatedChannelMask = channelMask;
        }
        return NO_ERROR;
    }

@@ -443,6 +445,9 @@ status_t AudioPort::checkCompatibleChannelMask(audio_channel_mask_t channelMask)
        // FIXME Does not handle multi-channel automatic conversions yet
        audio_channel_mask_t supported = mChannelMasks[i];
        if (supported == channelMask) {
            if (updatedChannelMask != NULL) {
                *updatedChannelMask = channelMask;
            }
            return NO_ERROR;
        }
        if (isRecordThread) {
@@ -452,6 +457,9 @@ status_t AudioPort::checkCompatibleChannelMask(audio_channel_mask_t channelMask)
                    && channelMask == AUDIO_CHANNEL_IN_MONO) ||
                (supported == AUDIO_CHANNEL_IN_MONO && (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK
                    || channelMask == AUDIO_CHANNEL_IN_STEREO))) {
                if (updatedChannelMask != NULL) {
                    *updatedChannelMask = supported;
                }
                return NO_ERROR;
            }
        }
@@ -459,7 +467,7 @@ status_t AudioPort::checkCompatibleChannelMask(audio_channel_mask_t channelMask)
    return BAD_VALUE;
}

status_t AudioPort::checkFormat(audio_format_t format) const
status_t AudioPort::checkExactFormat(audio_format_t format) const
{
    if (mFormats.isEmpty()) {
        return NO_ERROR;
@@ -473,6 +481,33 @@ status_t AudioPort::checkFormat(audio_format_t format) const
    return BAD_VALUE;
}

status_t AudioPort::checkCompatibleFormat(audio_format_t format, audio_format_t *updatedFormat)
        const
{
    if (mFormats.isEmpty()) {
        if (updatedFormat != NULL) {
            *updatedFormat = format;
        }
        return NO_ERROR;
    }

    const bool checkInexact = // when port is input and format is linear pcm
            mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK
            && audio_is_linear_pcm(format);

    for (size_t i = 0; i < mFormats.size(); ++i) {
        if (mFormats[i] == format ||
                (checkInexact && audio_is_linear_pcm(mFormats[i]))) {
            // for inexact checks we take the first linear pcm format since
            // mFormats is sorted from best PCM format to worst PCM format.
            if (updatedFormat != NULL) {
                *updatedFormat = mFormats[i];
            }
            return NO_ERROR;
        }
    }
    return BAD_VALUE;
}

uint32_t AudioPort::pickSamplingRate() const
{
@@ -756,7 +791,7 @@ status_t AudioPortConfig::applyAudioPortConfig(
        mChannelMask = config->channel_mask;
    }
    if (config->config_mask & AUDIO_PORT_CONFIG_FORMAT) {
        status = audioport->checkFormat(config->format);
        status = audioport->checkExactFormat(config->format);
        if (status != NO_ERROR) {
            goto exit;
        }
+18 −2
Original line number Diff line number Diff line
@@ -40,7 +40,9 @@ bool IOProfile::isCompatibleProfile(audio_devices_t device,
                                    uint32_t samplingRate,
                                    uint32_t *updatedSamplingRate,
                                    audio_format_t format,
                                    audio_format_t *updatedFormat,
                                    audio_channel_mask_t channelMask,
                                    audio_channel_mask_t *updatedChannelMask,
                                    uint32_t flags) const
{
    const bool isPlaybackThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SOURCE;
@@ -71,7 +73,14 @@ bool IOProfile::isCompatibleProfile(audio_devices_t device,
         return false;
    }

    if (!audio_is_valid_format(format) || checkFormat(format) != NO_ERROR) {
    if (!audio_is_valid_format(format)) {
        return false;
    }
    if (isPlaybackThread && checkExactFormat(format) != NO_ERROR) {
        return false;
    }
    audio_format_t myUpdatedFormat = format;
    if (isRecordThread && checkCompatibleFormat(format, &myUpdatedFormat) != NO_ERROR) {
        return false;
    }

@@ -79,8 +88,9 @@ bool IOProfile::isCompatibleProfile(audio_devices_t device,
            checkExactChannelMask(channelMask) != NO_ERROR)) {
        return false;
    }
    audio_channel_mask_t myUpdatedChannelMask = channelMask;
    if (isRecordThread && (!audio_is_input_channel(channelMask) ||
            checkCompatibleChannelMask(channelMask) != NO_ERROR)) {
            checkCompatibleChannelMask(channelMask, &myUpdatedChannelMask) != NO_ERROR)) {
        return false;
    }

@@ -99,6 +109,12 @@ bool IOProfile::isCompatibleProfile(audio_devices_t device,
    if (updatedSamplingRate != NULL) {
        *updatedSamplingRate = myUpdatedSamplingRate;
    }
    if (updatedFormat != NULL) {
        *updatedFormat = myUpdatedFormat;
    }
    if (updatedChannelMask != NULL) {
        *updatedChannelMask = myUpdatedChannelMask;
    }
    return true;
}

+48 −28
Original line number Diff line number Diff line
@@ -585,8 +585,10 @@ sp<IOProfile> AudioPolicyManager::getProfileForDirectOutput(
        }
        for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) {
            sp<IOProfile> profile = mHwModules[i]->mOutputProfiles[j];
            bool found = profile->isCompatibleProfile(device, String8(""), samplingRate,
                    NULL /*updatedSamplingRate*/, format, channelMask,
            bool found = profile->isCompatibleProfile(device, String8(""),
                    samplingRate, NULL /*updatedSamplingRate*/,
                    format, NULL /*updatedFormat*/,
                    channelMask, NULL /*updatedChannelMask*/,
                    flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD ?
                        AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD : AUDIO_OUTPUT_FLAG_DIRECT);
            if (found && (mAvailableOutputDevices.types() & profile->mSupportedDevices.types())) {
@@ -1303,20 +1305,25 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
        }
    }

    sp<IOProfile> profile = getInputProfile(device, address,
                                            samplingRate, format, channelMask,
                                            flags);
    if (profile == 0) {
        //retry without flags
        audio_input_flags_t log_flags = flags;
        flags = AUDIO_INPUT_FLAG_NONE;
    // find a compatible input profile (not necessarily identical in parameters)
    sp<IOProfile> profile;
    // samplingRate and flags may be updated by getInputProfile
    uint32_t profileSamplingRate = samplingRate;
    audio_format_t profileFormat = format;
    audio_channel_mask_t profileChannelMask = channelMask;
    audio_input_flags_t profileFlags = flags;
    for (;;) {
        profile = getInputProfile(device, address,
                                  samplingRate, format, channelMask,
                                  flags);
        if (profile == 0) {
                                  profileSamplingRate, profileFormat, profileChannelMask,
                                  profileFlags);
        if (profile != 0) {
            break; // success
        } else if (profileFlags != AUDIO_INPUT_FLAG_NONE) {
            profileFlags = AUDIO_INPUT_FLAG_NONE; // retry
        } else { // fail
            ALOGW("getInputForAttr() could not find profile for device 0x%X, samplingRate %u,"
                    "format %#x, channelMask 0x%X, flags %#x",
                    device, samplingRate, format, channelMask, log_flags);
                    device, samplingRate, format, channelMask, flags);
            return BAD_VALUE;
        }
    }
@@ -1327,9 +1334,9 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
    }

    audio_config_t config = AUDIO_CONFIG_INITIALIZER;
    config.sample_rate = samplingRate;
    config.channel_mask = channelMask;
    config.format = format;
    config.sample_rate = profileSamplingRate;
    config.channel_mask = profileChannelMask;
    config.format = profileFormat;

    status_t status = mpClientInterface->openInput(profile->getModuleHandle(),
                                                   input,
@@ -1337,14 +1344,15 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
                                                   &device,
                                                   address,
                                                   halInputSource,
                                                   flags);
                                                   profileFlags);

    // only accept input with the exact requested set of parameters
    if (status != NO_ERROR || *input == AUDIO_IO_HANDLE_NONE ||
        (samplingRate != config.sample_rate) ||
        (format != config.format) ||
        (channelMask != config.channel_mask)) {
        ALOGW("getInputForAttr() failed opening input: samplingRate %d, format %d, channelMask %x",
        (profileSamplingRate != config.sample_rate) ||
        (profileFormat != config.format) ||
        (profileChannelMask != config.channel_mask)) {
        ALOGW("getInputForAttr() failed opening input: samplingRate %d, format %d,"
                " channelMask %x",
                samplingRate, format, channelMask);
        if (*input != AUDIO_IO_HANDLE_NONE) {
            mpClientInterface->closeInput(*input);
@@ -1356,9 +1364,9 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
    inputDesc->mInputSource = inputSource;
    inputDesc->mRefCount = 0;
    inputDesc->mOpenRefCount = 1;
    inputDesc->mSamplingRate = samplingRate;
    inputDesc->mFormat = format;
    inputDesc->mChannelMask = channelMask;
    inputDesc->mSamplingRate = profileSamplingRate;
    inputDesc->mFormat = profileFormat;
    inputDesc->mChannelMask = profileChannelMask;
    inputDesc->mDevice = device;
    inputDesc->mSessions.add(session);
    inputDesc->mIsSoundTrigger = isSoundTrigger;
@@ -2122,9 +2130,12 @@ status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch,
                                                           patch->sources[0].sample_rate,
                                                           NULL,  // updatedSamplingRate
                                                           patch->sources[0].format,
                                                           NULL,  // updatedFormat
                                                           patch->sources[0].channel_mask,
                                                           NULL,  // updatedChannelMask
                                                           AUDIO_OUTPUT_FLAG_NONE /*FIXME*/)) {
                ALOGV("createAudioPatch() profile not supported for device %08x", devDesc->type());
                ALOGV("createAudioPatch() profile not supported for device %08x",
                        devDesc->type());
                return INVALID_OPERATION;
            }
            devices.add(devDesc);
@@ -2176,7 +2187,9 @@ status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch,
                                                          patch->sinks[0].sample_rate,
                                                          NULL, /*updatedSampleRate*/
                                                          patch->sinks[0].format,
                                                          NULL, /*updatedFormat*/
                                                          patch->sinks[0].channel_mask,
                                                          NULL, /*updatedChannelMask*/
                                                          // FIXME for the parameter type,
                                                          // and the NONE
                                                          (audio_output_flags_t)
@@ -4201,12 +4214,15 @@ status_t AudioPolicyManager::resetInputDevice(audio_io_handle_t input,
sp<IOProfile> AudioPolicyManager::getInputProfile(audio_devices_t device,
                                                  String8 address,
                                                  uint32_t& samplingRate,
                                                  audio_format_t format,
                                                  audio_channel_mask_t channelMask,
                                                  audio_format_t& format,
                                                  audio_channel_mask_t& channelMask,
                                                  audio_input_flags_t flags)
{
    // Choose an input profile based on the requested capture parameters: select the first available
    // profile supporting all requested parameters.
    //
    // TODO: perhaps isCompatibleProfile should return a "matching" score so we can return
    // the best matching profile, not the first one.

    for (size_t i = 0; i < mHwModules.size(); i++)
    {
@@ -4219,7 +4235,11 @@ sp<IOProfile> AudioPolicyManager::getInputProfile(audio_devices_t device,
            // profile->log();
            if (profile->isCompatibleProfile(device, address, samplingRate,
                                             &samplingRate /*updatedSamplingRate*/,
                                             format, channelMask, (audio_output_flags_t) flags)) {
                                             format,
                                             &format /*updatedFormat*/,
                                             channelMask,
                                             &channelMask /*updatedChannelMask*/,
                                             (audio_output_flags_t) flags)) {

                return profile;
            }
Loading