Android Audio代码分析(7): AudioTrack create

java 层AudioTrack

legacy method 1:
    public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,
            int bufferSizeInBytes, int mode) //这里的mode指的是static 还是stream
    throws IllegalArgumentException {
        this(streamType, sampleRateInHz, channelConfig, audioFormat,
                bufferSizeInBytes, mode, AudioManager.AUDIO_SESSION_ID_GENERATE); 

                                                        //ID_GENERATE 说的是native 分配一个session id
    }

legacy method 2: legacy method1 -> legacy method2 -> attribute way

    public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat,
            int bufferSizeInBytes, int mode, int sessionId)
    throws IllegalArgumentException {
        // mState already == STATE_UNINITIALIZED
        this((new AudioAttributes.Builder())
                    .setLegacyStreamType(streamType)
                    .build(),
                (new AudioFormat.Builder())
                    .setChannelMask(channelConfig)
                    .setEncoding(audioFormat)
                    .setSampleRate(sampleRateInHz)
                    .build(),
                bufferSizeInBytes,
                mode, sessionId);
        deprecateStreamTypeForPlayback(streamType, "AudioTrack", "AudioTrack()"); //提醒log
    }

attribure way 1

    public AudioTrack(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,
            int mode, int sessionId)
                    throws IllegalArgumentException {
        this(attributes, format, bufferSizeInBytes, mode, sessionId, false /*offload*/,
                ENCAPSULATION_MODE_NONE, null /* tunerConfiguration */);
    }

最终实现方式
// encapsulationMode: indicates metadata encapsulation, 数据中有metadata不是纯净的pcm data
// TunerConfiguration: 说的是 used to convey tuner information 
//                     from the android.media.tv.Tuner API to AudioTrack construction.
// offload 说的是hardware直接处理

// 这三个参数默认(正常情况)都是false
    private AudioTrack(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,
            int mode, int sessionId, boolean offload, int encapsulationMode,
            @Nullable TunerConfiguration tunerConfiguration)
                    throws IllegalArgumentException {

        // native initialization
        int initResult = native_setup(new WeakReference<AudioTrack>(this), mAttributes,
                sampleRate, mChannelMask, mChannelIndexMask, mAudioFormat,
                mNativeBufferSizeInBytes, mDataLoadMode, session, 0 /*nativeTrackInJavaObj*/,
                offload, encapsulationMode, tunerConfiguration,
                getCurrentOpPackageName());
        if (initResult != SUCCESS) {
            loge("Error code "+initResult+" when initializing AudioTrack.");
            return; // with mState == STATE_UNINITIALIZED
        }

    }

JNI level: native_setup

native_setup 创建native 层 AudioTrack 并set 赋值

1. lpTrack = new AudioTrack(opPackageNameStr.c_str());

2. lpTrack->set


frameworks/base/core/jni/android_media_AudioTrack.cpp
static const JNINativeMethod gMethods[] = {
        // name,              signature,     funcPtr
        {"native_setup",
         "(Ljava/lang/Object;Ljava/lang/Object;[IIIIII[IJZILjava/lang/Object;Ljava/lang/String;)I",
         (void *)android_media_AudioTrack_setup},
}

static jint android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this,
                                           jobject jaa, jintArray jSampleRate,
                                           jint channelPositionMask, jint channelIndexMask,
                                           jint audioFormat, jint buffSizeInBytes, jint memoryMode,
                                           jintArray jSession, jlong nativeAudioTrack,
                                           jboolean offload, jint encapsulationMode,
                                           jobject tunerConfiguration, jstring opPackageName) {
    ALOGV("sampleRates=%p, channel mask=%x, index mask=%x, audioFormat(Java)=%d, buffSize=%d,"
          " nativeAudioTrack=0x%" PRIX64 ", offload=%d encapsulationMode=%d tuner=%p",
          jSampleRate, channelPositionMask, channelIndexMask, audioFormat, buffSizeInBytes,
          nativeAudioTrack, offload, encapsulationMode, tunerConfiguration);

    // if we pass in an existing *Native* AudioTrack, we don't need to create/initialize one.
    sp<AudioTrack> lpTrack;
    if (nativeAudioTrack == 0) {

        // create the native AudioTrack object
        ScopedUtfChars opPackageNameStr(env, opPackageName);
        lpTrack = new AudioTrack(opPackageNameStr.c_str());

        // read the AudioAttributes values
        auto paa = JNIAudioAttributeHelper::makeUnique();
        jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jaa, paa.get());
        ALOGV("AudioTrack_setup for usage=%d content=%d flags=0x%#x tags=%s",
                paa->usage, paa->content_type, paa->flags, paa->tags);

        // initialize the native AudioTrack object
        status_t status = NO_ERROR;
        switch (memoryMode) {
        case MODE_STREAM:
            status = lpTrack->set(AUDIO_STREAM_DEFAULT,

                                                         // stream type, but more info conveyed
                                                        // in paa (last argument)
                                  sampleRateInHertz,
                                  format, // word length, PCM
                                  nativeChannelMask, offload ? 0 : frameCount,
                                  offload ? AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD
                                          : AUDIO_OUTPUT_FLAG_NONE,
                                  audioCallback,
                                  &(lpJniStorage->mCallbackData), // callback, callback data (user)
                                  0,    // notificationFrames == 0 since not using EVENT_MORE_DATA
                                        // to feed the AudioTrack
                                  0,    // shared mem
                                  true, // thread can call Java
                                  sessionId, // audio session ID
                                  offload ? AudioTrack::TRANSFER_SYNC_NOTIF_CALLBACK
                                          : AudioTrack::TRANSFER_SYNC,
                                  offload ? &offloadInfo : NULL, -1, -1, // default uid, pid values
                                  paa.get());
            break;
    }
}

Native AudioTack

AudioTrack构造函数

frameworks/av/media/libaudioclient/AudioTrack.cpp
AudioTrack::AudioTrack(const std::string& opPackageName)
    : mStatus(NO_INIT),
      mState(STATE_STOPPED),
      mPreviousPriority(ANDROID_PRIORITY_NORMAL),
      mPreviousSchedulingGroup(SP_DEFAULT),
      mPausedPosition(0),
      mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE),
      mRoutedDeviceId(AUDIO_PORT_HANDLE_NONE),
      mOpPackageName(opPackageName),
      mPauseTimeRealUs(0),
      mAudioTrackCallback(new AudioTrackCallback())
{
    mShootDetectWrapper = NULL;
    isAppSupported4D = false;
    mAttributes.content_type = AUDIO_CONTENT_TYPE_UNKNOWN;
    mAttributes.usage = AUDIO_USAGE_UNKNOWN;
    mAttributes.flags = 0x0;
    strcpy(mAttributes.tags, "");
}

AudioTrack::set

status_t AudioTrack::set(
        audio_stream_type_t streamType,
        uint32_t sampleRate,
        audio_format_t format,
        audio_channel_mask_t channelMask,
        size_t frameCount,
        audio_output_flags_t flags,
        callback_t cbf,
        void* user,
        int32_t notificationFrames,
        const sp<IMemory>& sharedBuffer,
        bool threadCanCallJava,
        audio_session_t sessionId,
        transfer_type transferType,
        const audio_offload_info_t *offloadInfo,
        uid_t uid,
        pid_t pid,
        const audio_attributes_t* pAttributes,
        bool doNotReconnect,
        float maxRequiredSpeed,
        audio_port_handle_t selectedDeviceId)
{
    status_t status;
    uint32_t channelCount;
    pid_t callingPid;
    pid_t myPid;

    ALOGD("set(sessionId=%d)", sessionId);
    // Note mPortId is not valid until the track is created, so omit mPortId in ALOG for set.
    ALOGD("%s(): streamType %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
          "flags #%x, notificationFrames %d, sessionId %d, transferType %d, uid %d, pid %d",
          __func__,
          streamType, sampleRate, format, channelMask, frameCount, flags, notificationFrames,
          sessionId, transferType, uid, pid);

   // AudioTrack Thread

  if (cbf != NULL) {
        mAudioTrackThread = new AudioTrackThread(*this);
        mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);
        // thread begins in paused state, and will not reference us until start()
    }

    // create the IAudioTrack
    {
        AutoMutex lock(mLock);
        status = createTrack_l();
    }

}

AudioTrackThread


AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver)
    : Thread(true /* bCanCallJava */)  // binder recursion on restoreTrack_l() may call Java.
    , mReceiver(receiver), mPaused(true), mPausedInt(false), mPausedNs(0LL),
      mIgnoreNextPausedInt(false)
{
}

bool AudioTrack::AudioTrackThread::threadLoop() //对应的执行体
{
}

createTrack_l()

根据输入参数 CreateTrackInput 得到 CreateTrackOutput

status_t AudioTrack::createTrack_l()
{
    const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();

    IAudioFlinger::CreateTrackInput input;
    if (mStreamType != AUDIO_STREAM_DEFAULT) {
        input.attr = AudioSystem::streamTypeToAttributes(mStreamType);
    } else {
        input.attr = mAttributes;
    }
    input.config = AUDIO_CONFIG_INITIALIZER;
    input.config.sample_rate = mSampleRate;
    input.config.channel_mask = mChannelMask;
    input.config.format = mFormat;
    input.config.offload_info = mOffloadInfoCopy;
    input.clientInfo.clientUid = mClientUid;
    input.clientInfo.clientPid = mClientPid;
    input.clientInfo.clientTid = -1;

    input.flags = mFlags;
    input.frameCount = mReqFrameCount;
    input.notificationFrameCount = mNotificationFramesReq;
    input.selectedDeviceId = mSelectedDeviceId;
    input.sessionId = mSessionId;
    input.audioTrackCallback = mAudioTrackCallback;
    input.opPackageName = mOpPackageName;

    IAudioFlinger::CreateTrackOutput output;

    sp<IAudioTrack> track = audioFlinger->createTrack(input,
                                                      output,
                                                      &status);

}

    /* CreateTrackInput contains all input arguments sent by AudioTrack to AudioFlinger
     * when calling createTrack() including arguments that will be updated by AudioFlinger
     * and returned in CreateTrackOutput object
     */
    class CreateTrackInput : public Parcelable {
        /* input */
        audio_attributes_t attr;
        audio_config_t config;
        AudioClient clientInfo;
        sp<IMemory> sharedBuffer;
        uint32_t notificationsPerBuffer;
        float speed;
        sp<media::IAudioTrackCallback> audioTrackCallback;
        std::string opPackageName;

        /* input/output */
        audio_output_flags_t flags;
        size_t frameCount;
        size_t notificationFrameCount;
        audio_port_handle_t selectedDeviceId; // (mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE))
        audio_session_t sessionId;
    };

    /* CreateTrackOutput contains all output arguments returned by AudioFlinger to AudioTrack
     * when calling createTrack() including arguments that were passed as I/O for update by
     * CreateTrackInput.
     */
    class CreateTrackOutput : public Parcelable {
        /* input/output */
        audio_output_flags_t flags;
        size_t frameCount;
        size_t notificationFrameCount;
        audio_port_handle_t selectedDeviceId; // (output.selectedDeviceId = input.selectedDeviceId;)
        audio_session_t sessionId;

        /* output */
        uint32_t sampleRate;
        size_t   afFrameCount;
        uint32_t afSampleRate;
        uint32_t afLatencyMs;
        audio_io_handle_t outputId;
        audio_port_handle_t portId;
    };

audioFlinger->createTrack

AudioTack最终调用到audioFlinger IBinder的createTrack

audioFlinger client: createTrack


class BpAudioFlinger : public BpInterface<IAudioFlinger>
{

    virtual sp<IAudioTrack> createTrack(const CreateTrackInput& input,
                                        CreateTrackOutput& output,
                                        status_t *status)
    {
        Parcel data, reply;
        sp<IAudioTrack> track;
        data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());

        if (status == nullptr) {
            return track;
        }

        input.writeToParcel(&data);

        status_t lStatus = remote()->transact(CREATE_TRACK, data, &reply);
        if (lStatus != NO_ERROR) {
            ALOGE("createTrack transaction error %d", lStatus);
            *status = DEAD_OBJECT;
            return track;
        }
        *status = reply.readInt32();
        if (*status != NO_ERROR) {
            ALOGE("createTrack returned error %d", *status);
            return track;
        }
        track = interface_cast<IAudioTrack>(reply.readStrongBinder());
        if (track == 0) {
            ALOGE("createTrack returned an NULL IAudioTrack with status OK");
            *status = DEAD_OBJECT;
            return track;
        }
        output.readFromParcel(&reply);
        return track;
    }
}

AudioFlinger Service: createTrack

status_t BnAudioFlinger::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch (code) {
        case CREATE_TRACK: {
            CHECK_INTERFACE(IAudioFlinger, data, reply);

            CreateTrackInput input;
            if (input.readFromParcel((Parcel*)&data) != NO_ERROR) {
                reply->writeInt32(DEAD_OBJECT);
                return NO_ERROR;
            }

            status_t status;
            CreateTrackOutput output;

            sp<IAudioTrack> track= createTrack(input,
                                               output,
                                               &status);

            LOG_ALWAYS_FATAL_IF((track != 0) != (status == NO_ERROR));
            reply->writeInt32(status);
            if (status != NO_ERROR) {
                return NO_ERROR;
            }
            reply->writeStrongBinder(IInterface::asBinder(track));
            output.writeToParcel(reply);
            return NO_ERROR;
        } break;
}

AudioFlinger service createTrack的实现

frameworks/av/services/audioflinger/AudioFlinger.cpp

sp<IAudioTrack> AudioFlinger::createTrack(const CreateTrackInput& input,
                                          CreateTrackOutput& output,
                                          status_t *status)
{
    sp<PlaybackThread::Track> track;
    sp<TrackHandle> trackHandle;
    sp<Client> client;
    status_t lStatus;
    audio_stream_type_t streamType;
    audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
    std::vector<audio_io_handle_t> secondaryOutputs;

    // session的生成

    audio_session_t sessionId = input.sessionId;
    if (sessionId == AUDIO_SESSION_ALLOCATE) {
        sessionId = (audio_session_t) newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
    }

    // AudioSystem::getOutputForAttr

    output.sessionId = sessionId;
    output.outputId = AUDIO_IO_HANDLE_NONE;
    output.selectedDeviceId = input.selectedDeviceId;
    lStatus = AudioSystem::getOutputForAttr(&localAttr, &output.outputId, sessionId, &streamType,
                                            clientPid, clientUid, &input.config, input.flags,
                                            &output.selectedDeviceId, &portId, &secondaryOutputs);

}

AudioSystem::getOutputForAttr


frameworks/av/media/libaudioclient/AudioSystem.cpp
status_t AudioSystem::getOutputForAttr(audio_attributes_t *attr,
                                        audio_io_handle_t *output,
                                        audio_session_t session,
                                        audio_stream_type_t *stream,
                                        pid_t pid,
                                        uid_t uid,
                                        const audio_config_t *config,
                                        audio_output_flags_t flags,
                                        audio_port_handle_t *selectedDeviceId,
                                        audio_port_handle_t *portId,
                                        std::vector<audio_io_handle_t> *secondaryOutputs)
{
    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
    if (aps == 0) return NO_INIT;
    return aps->getOutputForAttr(attr, output, session, stream, pid, uid,
                                 config,
                                 flags, selectedDeviceId, portId, secondaryOutputs);
}

AudioPolicyService client 接口getOutputForAttr

frameworks/av/media/libaudioclient/IAudioPolicyService.cpp
    status_t getOutputForAttr(audio_attributes_t *attr,
                              audio_io_handle_t *output,
                              audio_session_t session,
                              audio_stream_type_t *stream,
                              pid_t pid,
                              uid_t uid,
                              const audio_config_t *config,
                              audio_output_flags_t flags,
                              audio_port_handle_t *selectedDeviceId,
                              audio_port_handle_t *portId,
                              std::vector<audio_io_handle_t> *secondaryOutputs) override
        {
            Parcel data, reply;
            data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
            data.write(attr, sizeof(audio_attributes_t));
            data.writeInt32(session);
            if (stream == NULL) {
                data.writeInt32(0);
            } else {
                data.writeInt32(1);
                data.writeInt32(*stream);
            }
            data.writeInt32(pid);
            data.writeInt32(uid);
            data.write(config, sizeof(audio_config_t));
            data.writeInt32(static_cast <uint32_t>(flags));
            data.writeInt32(*selectedDeviceId);
            data.writeInt32(*portId);
            status_t status = remote()->transact(GET_OUTPUT_FOR_ATTR, data, &reply);
            if (status != NO_ERROR) {
                return status;
            }
            status = (status_t)reply.readInt32();
            if (status != NO_ERROR) {
                return status;
            }
            status = (status_t)reply.read(&attr, sizeof(audio_attributes_t));
            if (status != NO_ERROR) {
                return status;
            }
            *output = (audio_io_handle_t)reply.readInt32();
            audio_stream_type_t lStream = (audio_stream_type_t)reply.readInt32();
            if (stream != NULL) {
                *stream = lStream;
            }
            *selectedDeviceId = (audio_port_handle_t)reply.readInt32();
            *portId = (audio_port_handle_t)reply.readInt32();
            secondaryOutputs->resize(reply.readInt32());
            return reply.read(secondaryOutputs->data(),
                              secondaryOutputs->size() * sizeof(audio_io_handle_t));
        }

AudioPolicyService service 接口getOutputForAttr实现


status_t BnAudioPolicyService::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
        case GET_OUTPUT_FOR_ATTR: {
            CHECK_INTERFACE(IAudioPolicyService, data, reply);
            audio_attributes_t attr = AUDIO_ATTRIBUTES_INITIALIZER;
            status_t status = data.read(&attr, sizeof(audio_attributes_t));
            if (status != NO_ERROR) {
                return status;
            }
            audio_session_t session = (audio_session_t)data.readInt32();
            audio_stream_type_t stream = AUDIO_STREAM_DEFAULT;
            bool hasStream = data.readInt32() != 0;
            if (hasStream) {
                stream = (audio_stream_type_t)data.readInt32();
            }
            pid_t pid = (pid_t)data.readInt32();
            uid_t uid = (uid_t)data.readInt32();
            audio_config_t config;
            memset(&config, 0, sizeof(audio_config_t));
            data.read(&config, sizeof(audio_config_t));
            audio_output_flags_t flags =
                    static_cast <audio_output_flags_t>(data.readInt32());
            audio_port_handle_t selectedDeviceId = data.readInt32();
            audio_port_handle_t portId = (audio_port_handle_t)data.readInt32();
            audio_io_handle_t output = 0;
            std::vector<audio_io_handle_t> secondaryOutputs;

            status = AudioSanitizer::sanitizeAudioAttributes(&attr, "68953950");
            if (status == NO_ERROR) {
                status = getOutputForAttr(&attr,
                                          &output, session, &stream, pid, uid,
                                          &config,
                                          flags, &selectedDeviceId, &portId, &secondaryOutputs);
            }
            reply->writeInt32(status);
            status = reply->write(&attr, sizeof(audio_attributes_t));
            if (status != NO_ERROR) {
                return status;
            }
            reply->writeInt32(output);
            reply->writeInt32(stream);
            reply->writeInt32(selectedDeviceId);
            reply->writeInt32(portId);
            reply->writeInt32(secondaryOutputs.size());
            return reply->write(secondaryOutputs.data(),
                                secondaryOutputs.size() * sizeof(audio_io_handle_t));
        } break;

}

status_t AudioPolicyService::getOutputForAttr(audio_attributes_t *attr,
                                              audio_io_handle_t *output,
                                              audio_session_t session,
                                              audio_stream_type_t *stream,
                                              pid_t pid,
                                              uid_t uid,
                                              const audio_config_t *config,
                                              audio_output_flags_t flags,
                                              audio_port_handle_t *selectedDeviceId,
                                              audio_port_handle_t *portId,
                                              std::vector<audio_io_handle_t> *secondaryOutputs)
{

    ALOGV("%s()", __func__);
    mLock.lock();
    sp<AudioPolicyEffects> audioPolicyEffects = mAudioPolicyEffects;
    mLock.unlock();
    audioPolicyEffects -> createGlobalEffects();
    Mutex::Autolock _l(mLock);

    const uid_t callingUid = IPCThreadState::self()->getCallingUid();
    if (!isAudioServerOrMediaServerUid(callingUid) || uid == (uid_t)-1) {
        ALOGW_IF(uid != (uid_t)-1 && uid != callingUid,
                "%s uid %d tried to pass itself off as %d", __func__, callingUid, uid);
        uid = callingUid;
    }
    if (!mPackageManager.allowPlaybackCapture(uid)) {
        attr->flags |= AUDIO_FLAG_NO_MEDIA_PROJECTION;
    }
    if (((attr->flags & (AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY|AUDIO_FLAG_BYPASS_MUTE)) != 0)
            && !bypassInterruptionPolicyAllowed(pid, uid)) {
        attr->flags &= ~(AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY|AUDIO_FLAG_BYPASS_MUTE);
    }
    AutoCallerClear acc;
    AudioPolicyInterface::output_type_t outputType;
    result = mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, uid,
                                                 config,
                                                 &flags, selectedDeviceId, portId,
                                                 secondaryOutputs,
                                                 &outputType);

    // FIXME: Introduce a way to check for the the telephony device before opening the output
    if (result == NO_ERROR) {
        // enforce permission (if any) required for each type of input
        switch (outputType) {
        case AudioPolicyInterface::API_OUTPUT_LEGACY:
            break;
        case AudioPolicyInterface::API_OUTPUT_TELEPHONY_TX:
            if (!modifyPhoneStateAllowed(pid, uid)) {
                ALOGE("%s() permission denied: modify phone state not allowed for uid %d",
                    __func__, uid);
                result = PERMISSION_DENIED;
            }
            break;
        case AudioPolicyInterface::API_OUT_MIX_PLAYBACK:
            if (!modifyAudioRoutingAllowed(pid, uid)) {
                ALOGE("%s() permission denied: modify audio routing not allowed for uid %d",
                    __func__, uid);
                result = PERMISSION_DENIED;
            }
            break;
        case AudioPolicyInterface::API_OUTPUT_INVALID:
        default:
            LOG_ALWAYS_FATAL("%s() encountered an invalid output type %d",
                __func__, (int)outputType);
        }
    }

    if (result == NO_ERROR) {
        sp <AudioPlaybackClient> client =
            new AudioPlaybackClient(*attr, *output, uid, pid, session, *portId, *selectedDeviceId, *stream);
        mAudioPlaybackClients.add(*portId, client);
    }
    return result;
}

AudioPolicyService getOutputForAttr 由APM 实现


frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
                                              audio_io_handle_t *output,
                                              audio_session_t session,
                                              audio_stream_type_t *stream,
                                              uid_t uid,
                                              const audio_config_t *config,
                                              audio_output_flags_t *flags,
                                              audio_port_handle_t *selectedDeviceId,
                                              audio_port_handle_t *portId,
                                              std::vector<audio_io_handle_t> *secondaryOutputs,
                                              output_type_t *outputType)
{
    // The supplied portId must be AUDIO_PORT_HANDLE_NONE
    if (*portId != AUDIO_PORT_HANDLE_NONE) {
        return INVALID_OPERATION;
    }
    const audio_port_handle_t requestedPortId = *selectedDeviceId;
    audio_attributes_t resultAttr;
    bool isRequestedDeviceForExclusiveUse = false;
    std::vector<sp<AudioPolicyMix>> secondaryMixes;
    const sp<DeviceDescriptor> requestedDevice =
      mAvailableOutputDevices.getDeviceFromId(requestedPortId);

    // Prevent from storing invalid requested device id in clients
    const audio_port_handle_t sanitizedRequestedPortId =
      requestedDevice != nullptr ? requestedPortId : AUDIO_PORT_HANDLE_NONE;
    *selectedDeviceId = sanitizedRequestedPortId;

    callingAppuid = uid;
    callingAppName = getPackageName(uid);
    audio_app_type_f appType = getAppMaskByName(callingAppName);

    status_t status = getOutputForAttrInt(&resultAttr, output, session, attr, stream, uid,
            config, flags, selectedDeviceId, &isRequestedDeviceForExclusiveUse,
            secondaryOutputs != nullptr ? &secondaryMixes : nullptr, outputType);
    if (status != NO_ERROR) {
        return status;
    }
    std::vector<wp<SwAudioOutputDescriptor>> weakSecondaryOutputDescs;
    if (secondaryOutputs != nullptr) {
        for (auto &secondaryMix : secondaryMixes) {
            sp<SwAudioOutputDescriptor> outputDesc = secondaryMix->getOutput();
            if (outputDesc != nullptr &&
                outputDesc->mIoHandle != AUDIO_IO_HANDLE_NONE) {
                secondaryOutputs->push_back(outputDesc->mIoHandle);
                weakSecondaryOutputDescs.push_back(outputDesc);
            }
        }
    }

    audio_config_base_t clientConfig = {.sample_rate = config->sample_rate,
        .channel_mask = config->channel_mask,
        .format = config->format,
    };
    *portId = PolicyAudioPort::getNextUniqueId();

    sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(*output);
    sp<TrackClientDescriptor> clientDesc =
        new TrackClientDescriptor(*portId, uid, session, resultAttr, clientConfig,
                                  sanitizedRequestedPortId, *stream,
                                  mEngine->getProductStrategyForAttributes(resultAttr),
                                  toVolumeSource(resultAttr),
                                  *flags, isRequestedDeviceForExclusiveUse,
                                  std::move(weakSecondaryOutputDescs),
                                  outputDesc->mPolicyMix);
    outputDesc->addClient(clientDesc);

    clientDesc->setAppName(String8(callingAppName));
    outputDesc->setAppMask(appType); //output
    clientDesc->setAppMask(appType); //output

    if ((attr->content_type == AUDIO_CONTENT_TYPE_SONIFICATION) &&
        (attr->usage == AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE) &&
        (*stream == AUDIO_STREAM_RING)) {
        mpClientInterface->setParameters(outputDesc->mIoHandle, String8("output_for_sing"));
    }

    ALOGD("%s() returns output %d requestedPortId %d selectedDeviceId %d for port ID %d", __func__,
          *output, requestedPortId, *selectedDeviceId, *portId);

    return NO_ERROR;
}

AudioPolicyManager::getOutputForAttrInt

只关注getOutputForAttrInt部分,这是最终选择device的关键部分,policy的最终体现

status_t AudioPolicyManager::getOutputForAttrInt(
        audio_attributes_t *resultAttr,
        audio_io_handle_t *output,
        audio_session_t session,
        const audio_attributes_t *attr,
        audio_stream_type_t *stream,
        uid_t uid,
        const audio_config_t *config,
        audio_output_flags_t *flags,
        audio_port_handle_t *selectedDeviceId,
        bool *isRequestedDeviceForExclusiveUse,
        std::vector<sp<AudioPolicyMix>> *secondaryMixes,
        output_type_t *outputType)
{
    DeviceVector outputDevices;
    const audio_port_handle_t requestedPortId = *selectedDeviceId;
    DeviceVector msdDevices = getMsdAudioOutDevices();
    const sp<DeviceDescriptor> requestedDevice =
        mAvailableOutputDevices.getDeviceFromId(requestedPortId);
    *outputType = API_OUTPUT_INVALID;

    status_t status = getAudioAttributes(resultAttr, attr, *stream);

    // [1]: mEngine->getStreamTypeForAttributes
    *stream = mEngine->getStreamTypeForAttributes(*resultAttr);

    // 输入请求参数
    ALOGD("%s()+ attributes=%s stream=%s session %d output %d selectedDeviceId %d device %s sampling rate %d format %#x"
        "channel mask %#x flags %#x stream %s uid %d",
             __func__, toString(*resultAttr).c_str(), toString(*stream).c_str(), session, *output,
                    requestedPortId, outputDevices.toString().c_str(), config->sample_rate, config->format,
                            config->channel_mask, *flags, toString(*stream).c_str(), uid);

    // [2]: mEngine->getOutputDevicesForAttributes

    outputDevices = mEngine->getOutputDevicesForAttributes(*resultAttr, requestedDevice, false);

  // 选择到一组devices

    ALOGV("%s() device %s, sampling rate %d, format %#x, channel mask %#x, flags %#x stream %s",
          __func__, outputDevices.toString().c_str(), config->sample_rate, config->format,
          config->channel_mask, *flags, toString(*stream).c_str());

    *output = AUDIO_IO_HANDLE_NONE;
    if (*output == AUDIO_IO_HANDLE_NONE) {

     // [3]  getOutputForDevices
        *output = getOutputForDevices(outputDevices, session, *stream, config,
                flags, resultAttr->flags & AUDIO_FLAG_MUTE_HAPTIC);
    }

    *selectedDeviceId = getFirstDeviceId(outputDevices);

// 选择一个Device
    ALOGD("%s()- attributes=%s stream=%s session %d output %d selectedDeviceId %d device %s sampling rate %d format %#x"
        "channel mask %#x flags %#x stream %s uid %d",
             __func__, toString(*resultAttr).c_str(), toString(*stream).c_str(), session, *output,
                    requestedPortId, outputDevices.toString().c_str(), config->sample_rate, config->format,
                            config->channel_mask, *flags, toString(*stream).c_str(), uid);
    return NO_ERROR;
}

mEngine->getStreamTypeForAttributes
 

audio_stream_type_t EngineBase::getStreamTypeForAttributes(const audio_attributes_t &attr) const
{
    return mProductStrategies.getStreamTypeForAttributes(attr);
}

audio_stream_type_t ProductStrategy::getStreamTypeForAttributes(
        const audio_attributes_t &attr) const
{
    const auto &iter = std::find_if(begin(mAttributesVector), end(mAttributesVector),
                                   [&attr](const auto &supportedAttr) {
        return AudioProductStrategy::attributesMatches(supportedAttr.mAttributes, attr); });

    audio_stream_type_t streamType = iter->mStream;
    return streamType != AUDIO_STREAM_DEFAULT ? streamType : AUDIO_STREAM_MUSIC;
}

bool AudioProductStrategy::attributesMatches(const audio_attributes_t refAttributes,
                                        const audio_attributes_t clientAttritubes)
{
    return ((refAttributes.usage == AUDIO_USAGE_UNKNOWN) ||
            (clientAttritubes.usage == refAttributes.usage)) &&
            ((refAttributes.content_type == AUDIO_CONTENT_TYPE_UNKNOWN) ||
             (clientAttritubes.content_type == refAttributes.content_type)) &&
            ((refAttributes.flags == AUDIO_FLAG_NONE) ||
             (clientAttritubes.flags != AUDIO_FLAG_NONE &&
            (clientAttritubes.flags & refAttributes.flags) == refAttributes.flags)) &&
            ((strlen(refAttributes.tags) == 0) ||
             (std::strcmp(clientAttritubes.tags, refAttributes.tags) == 0));
}
 

getOutputDevicesForAttributes

根据Attributes 得到Devices由两种方式:1. findPrefferredDevice,

2. getDevicesForProductStrategy (这里忽略了mDevicesForStrategies.at(strategy))

findPrefferredDevice没有看懂,这里主要分析 getDevicesForProductStrategy

DeviceVector Engine::getOutputDevicesForAttributes(const audio_attributes_t &attributes,
                                                   const sp<DeviceDescriptor> &preferredDevice,
                                                   bool fromCache) const
{
    // First check for explict routing device, 显示routing 设备
    if (preferredDevice != nullptr) {
        ALOGV("%s explicit Routing on device %s", __func__, preferredDevice->toString().c_str());
        return DeviceVector(preferredDevice);
    }
    product_strategy_t strategy = getProductStrategyForAttributes(attributes);
    const DeviceVector availableOutputDevices =

                       getApmObserver()->getAvailableOutputDevices();
    const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs();
    //
    // Honor explicit routing requests only if all active clients have a preferred route in which
    // case the last active client route is used
    sp<DeviceDescriptor> device = findPreferredDevice(outputs,

                                                       strategy, availableOutputDevices);
    if (device != nullptr) {
        return DeviceVector(device);
    }

    return fromCache?

              mDevicesForStrategies.at(strategy) : getDevicesForProductStrategy(strategy);
}

findPreferredDevice

没看懂怎么找到 preferredDevice的

class DeviceVector : public SortedVector<sp<DeviceDescriptor> >
{
}
// 描述DevicePort
class DeviceDescriptor : public DeviceDescriptorBase,
                         public PolicyAudioPort, public PolicyAudioPortConfig
{
private:
    std::string mTagName; // Unique human readable identifier for a device port found in conf file.
    FormatVector        mEncodedFormats;
    audio_format_t      mCurrentEncodedFormat;
}

class SwAudioOutputCollection :
        public DefaultKeyedVector< audio_io_handle_t, sp<SwAudioOutputDescriptor> >
{
}

// Audio output driven by a software mixer in audio flinger.
class SwAudioOutputDescriptor: public AudioOutputDescriptor
{
}

// Audio output driven by an input device directly.
class HwAudioOutputDescriptor: public AudioOutputDescriptor
{
}

// descriptor for audio outputs. Used to maintain current configuration of each opened audio output
// and keep track of the usage of this output by each audio stream type.
class AudioOutputDescriptor: public AudioPortConfig,
        public PolicyAudioPortConfig,
        public AudioIODescriptorInterface,
        public ClientMapHandler<TrackClientDescriptor>
{
}

getDevicesForProductStrategy

getDevicesForProductStrategy 有两种方式:1. 直接从getPreferredDeviceForStrategy得到

2.  getDevicesForStrategyInt 根据strategy类型去选择

DeviceVector Engine::getDevicesForProductStrategy(product_strategy_t strategy) const {
    DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices();

    //[1] check if this strategy has a preferred device that is available,
    // if yes, give priority to it
    AudioDeviceTypeAddr preferredStrategyDevice;
    const status_t status = getPreferredDeviceForStrategy(strategy, preferredStrategyDevice);
    if (status == NO_ERROR) {
        // there is a preferred device, is it available?
        sp<DeviceDescriptor> preferredAvailableDevDescr = availableOutputDevices.getDevice(
                preferredStrategyDevice.mType,
                String8(preferredStrategyDevice.mAddress.c_str()),
                AUDIO_FORMAT_DEFAULT);
        if (preferredAvailableDevDescr != nullptr) {
            ALOGVV("%s using pref device 0x%08x/%s for strategy %u",
                   __func__, preferredStrategyDevice.mType,
                   preferredStrategyDevice.mAddress.c_str(), strategy);
            return DeviceVector(preferredAvailableDevDescr);
        }
    }

    //[2] legacyStrategy
    DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices();
    const SwAudioOutputCollection& outputs = getApmObserver()->getOutputs();
    auto legacyStrategy = mLegacyStrategyMap.find(strategy) != end(mLegacyStrategyMap) ?
                          mLegacyStrategyMap.at(strategy) : STRATEGY_NONE;
    return getDevicesForStrategyInt(legacyStrategy,
                                    availableOutputDevices,
                                    availableInputDevices, outputs);
}

[1] getPreferredDeviceForStrategy(strategy, preferredStrategyDevice)


// EngineBase::setPreferredDeviceForStrategy
// (product_strategy_t strategy, const AudioDeviceTypeAddr &device)
// 策略和Device的对应关系

status_t EngineBase::getPreferredDeviceForStrategy(product_strategy_t strategy,
            AudioDeviceTypeAddr &device) const
{
    // verify strategy exists
    if (mProductStrategies.find(strategy) == mProductStrategies.end()) {
        ALOGE("%s unknown strategy %u", __func__, strategy);
        return BAD_VALUE;
    }
    // preferred device for this strategy?
    auto devIt = mProductStrategyPreferredDevices.find(strategy);
    if (devIt == mProductStrategyPreferredDevices.end()) {
        ALOGV("%s no preferred device for strategy %u", __func__, strategy);
        return NAME_NOT_FOUND;
    }

    device = devIt->second;
    return NO_ERROR;
}

class ProductStrategyPreferredRoutingMap : public std::map<product_strategy_t, AudioDeviceTypeAddr>
{
public:
    void dump(String8 *dst, int spaces = 0) const;
};

//[2] getDevicesForStrategyInt :mLegacyStrategyMap


struct legacy_strategy_map { const char *name; legacy_strategy id; };
static const std::vector<legacy_strategy_map>& getLegacyStrategy() {
    static const std::vector<legacy_strategy_map> legacyStrategy = {
        { "STRATEGY_NONE", STRATEGY_NONE },
        { "STRATEGY_MEDIA", STRATEGY_MEDIA },
        { "STRATEGY_PHONE", STRATEGY_PHONE },
        { "STRATEGY_SONIFICATION", STRATEGY_SONIFICATION },
        { "STRATEGY_SONIFICATION_RESPECTFUL", STRATEGY_SONIFICATION_RESPECTFUL },
        { "STRATEGY_DTMF", STRATEGY_DTMF },
        { "STRATEGY_ENFORCED_AUDIBLE", STRATEGY_ENFORCED_AUDIBLE },
        { "STRATEGY_TRANSMITTED_THROUGH_SPEAKER", STRATEGY_TRANSMITTED_THROUGH_SPEAKER },
        { "STRATEGY_ACCESSIBILITY", STRATEGY_ACCESSIBILITY },
        { "STRATEGY_REROUTING", STRATEGY_REROUTING },
        { "STRATEGY_PATCH", STRATEGY_REROUTING }, // boiler to manage stream patch volume
        { "STRATEGY_CALL_ASSISTANT", STRATEGY_CALL_ASSISTANT },
    };
    return legacyStrategy;
}

getDevicesForStrategyInt:

代码的逻辑很简单switch 遍历strategy, 通过getDevicesFromType 找到devices
DeviceVector Engine::getDevicesForStrategyInt(legacy_strategy strategy,
                                              DeviceVector availableOutputDevices,
                                              DeviceVector availableInputDevices,
                                              const SwAudioOutputCollection &outputs) const
{
   DeviceVector devices;
   
   switch (strategy) {
   
   case  STRATEGY_MEDIA: {
        DeviceVector devices2;
        if ((devices2.isEmpty()) &&
                (getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP)) {
            devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_HEARING_AID);
        }
        if ((devices2.isEmpty()) &&
            (getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) == AUDIO_POLICY_FORCE_SPEAKER)) {
            devices2 = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
        }

   }

    if (devices.isEmpty()) {
        ALOGV("getDevicesForStrategy() no device found for strategy %d", strategy);
        sp<DeviceDescriptor> defaultOutputDevice = getApmObserver()->getDefaultOutputDevice();
        if (defaultOutputDevice != nullptr) {
            devices.add(defaultOutputDevice);
        }
        ALOGE_IF(devices.isEmpty(),
                 "getDevicesForStrategy() no default device defined");
    }

    // 输出的log

    ALOGV("getDevices ForStrategy() strategy %d, device %s",
           strategy, dumpDeviceTypes(devices.types()).c_str());
    return devices;
}
 

上面我们根据attribute已经找到一组 devices, 还没有使用具体的信息如sample rate, format等等

getOutputForDevices 从Devices 中根据sample rate等具体信息根据策略配置得到bestDevice.

getOutputForDevices

audio_io_handle_t AudioPolicyManager::getOutputForDevices(
        const DeviceVector &devices,
        audio_session_t session,
        audio_stream_type_t stream,
        const audio_config_t *config,
        audio_output_flags_t *flags,
        bool forceMutingHaptic)
{
    audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;

//[1] 对 flag的特殊处理
    // Discard haptic channel mask when forcing muting haptic channels.
    audio_channel_mask_t channelMask = forceMutingHaptic
            ? (config->channel_mask & ~AUDIO_CHANNEL_HAPTIC_ALL) : config->channel_mask;

    // open a direct output if required by specified parameters
    //force direct flag if offload flag is set: offloading implies a direct output stream
    // and all common behaviors are driven by checking only the direct flag
    // this should normally be set appropriately in the policy configuration file
    if ((*flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
        *flags = (audio_output_flags_t)(*flags | AUDIO_OUTPUT_FLAG_DIRECT);
    }
    if ((*flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) != 0) {
        *flags = (audio_output_flags_t)(*flags | AUDIO_OUTPUT_FLAG_DIRECT);
    }
    // only allow deep buffering for music stream type
    if (stream != AUDIO_STREAM_MUSIC) {
        *flags = (audio_output_flags_t)(*flags &~AUDIO_OUTPUT_FLAG_DEEP_BUFFER);
    } else if (/* stream == AUDIO_STREAM_MUSIC && */
            *flags == AUDIO_OUTPUT_FLAG_NONE &&
            property_get_bool("audio.deep_buffer.media", false /* default_value */)) {
        // use DEEP_BUFFER as default output for music stream type
        *flags = (audio_output_flags_t)AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
    }
    if (stream == AUDIO_STREAM_TTS) {
        *flags = AUDIO_OUTPUT_FLAG_TTS;
    } else if (stream == AUDIO_STREAM_VOICE_CALL &&
               audio_is_linear_pcm(config->format) &&
               (*flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) == 0) {
        *flags = (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_VOIP_RX |
                                       AUDIO_OUTPUT_FLAG_DIRECT);
        ALOGV("Set VoIP and Direct output flags for PCM format");
    }

//[2] openDirectOutput,没有 direct flag也需要openDirectOutput?
    audio_config_t directConfig = *config;
    directConfig.channel_mask = channelMask;
    status_t status = openDirectOutput(stream, session, &directConfig, *flags, devices, &output);
    if (status != NAME_NOT_FOUND) {
        return output;
    }

    // A request for HW A/V sync cannot fallback to a mixed output because time
    // stamps are embedded in audio data
    if ((*flags & (AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_MMAP_NOIRQ)) != 0) {
        return AUDIO_IO_HANDLE_NONE;
    }

    // ignoring channel mask due to downmix capability in mixer

    // open a non direct output

//[3] for non direct outputs, only PCM is supported
    if (audio_is_linear_pcm(config->format)) {
        // get which output is suitable for the specified stream. The actual
        // routing change will happen when startOutput() will be called
        SortedVector<audio_io_handle_t> outputs = getOutputsForDevices(devices, mOutputs);

        // at this stage we should ignore the DIRECT flag as no direct output could be found earlier
        *flags = (audio_output_flags_t)(*flags & ~AUDIO_OUTPUT_FLAG_DIRECT);
        output = selectOutput(outputs, *flags, config->format, channelMask, config->sample_rate);
    }
    ALOGW_IF((output == 0), "getOutputForDevices() could not find output for stream %d, "
            "sampling rate %d, format %#x, channels %#x, flags %#x",
            stream, config->sample_rate, config->format, channelMask, *flags);

    return output;
}

这里主要关注audio_is_linear_pcm, 其中包括getOutputsForDevices, selectOutput

SortedVector<audio_io_handle_t> outputs = getOutputsForDevices(devices, mOutputs);
output = selectOutput(outputs, *flags, config->format, channelMask, config->sample_rate);

getOutputsForDevices

从openOuputs中得到 DeviceVector

SortedVector<audio_io_handle_t> AudioPolicyManager::getOutputsForDevices(
            const DeviceVector &devices,
            const SwAudioOutputCollection& openOutputs)
{
    SortedVector<audio_io_handle_t> outputs;

    ALOGVV("%s() devices %s", __func__, devices.toString().c_str());
    for (size_t i = 0; i < openOutputs.size(); i++) {
        ALOGVV("output %zu isDuplicated=%d device=%s",
                i, openOutputs.valueAt(i)->isDuplicated(),
                openOutputs.valueAt(i)->supportedDevices().toString().c_str());
        if (openOutputs.valueAt(i)->supportsAllDevices(devices)
                && openOutputs.valueAt(i)->devicesSupportEncodedFormats(devices.types())) {
            ALOGVV("%s() found output %d", __func__, openOutputs.keyAt(i));
            outputs.add(openOutputs.keyAt(i));
        }
    }
    return outputs;
}

selectOutput

根据flags, format, channel_mask从audio_io_handles 中找到bestMatched

audio_io_handle_t AudioPolicyManager::selectOutput(

                                                       const SortedVector<audio_io_handle_t>& outputs,
                                                       audio_output_flags_t flags,
                                                       audio_format_t format,
                                                       audio_channel_mask_t channelMask,
                                                       uint32_t samplingRate)
{
    audio_io_handle_t primary_output = 0;
    bool isCts = getAppMaskByName(callingAppName) & APP_TYPE_CTS_AUDIOPRO ? true : false;

    LOG_ALWAYS_FATAL_IF(!(format == AUDIO_FORMAT_INVALID || audio_is_linear_pcm(format)),
        "%s called with format %#x", __func__, format);

    // Flags disqualifying an output: the match must happen before calling selectOutput()
    static const audio_output_flags_t kExcludedFlags = (audio_output_flags_t)
        (AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT);

    // Flags expressing a functional request: must be honored in priority over
    // other criteria
    static const audio_output_flags_t kFunctionalFlags = (audio_output_flags_t)
        (AUDIO_OUTPUT_FLAG_VOIP_RX | AUDIO_OUTPUT_FLAG_INCALL_MUSIC |
            AUDIO_OUTPUT_FLAG_TTS | AUDIO_OUTPUT_FLAG_DIRECT_PCM | AUDIO_OUTPUT_FLAG_VIRTUAL_DEEP_BUFFER);
    // Flags expressing a performance request: have lower priority than serving
    // requested sampling rate or channel mask
    static const audio_output_flags_t kPerformanceFlags = (audio_output_flags_t)
        (AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_DEEP_BUFFER |
            AUDIO_OUTPUT_FLAG_RAW | AUDIO_OUTPUT_FLAG_SYNC);

    const audio_output_flags_t functionalFlags =
        (audio_output_flags_t)(flags & kFunctionalFlags);
    const audio_output_flags_t performanceFlags =
        (audio_output_flags_t)(flags & kPerformanceFlags);

    audio_io_handle_t bestOutput = (outputs.size() == 0) ? AUDIO_IO_HANDLE_NONE : outputs[0];

    // select one output among several that provide a path to a particular device or set of
    // devices (the list was previously build by getOutputsForDevices()).
    // The priority is as follows:
    // 1: the output supporting haptic playback when requesting haptic playback
    // 2: the output with the highest number of requested functional flags
    // 3: the output supporting the exact channel mask
    // 4: the output with a higher channel count than requested
    // 5: the output with a higher sampling rate than requested
    // 6: the output with the highest number of requested performance flags
    // 7: the output with the bit depth the closest to the requested one
    // 8: the primary output
    // 9: the first output in the list

    // matching criteria values in priority order for best matching output so far
    std::vector<uint32_t> bestMatchCriteria(8, 0);

    const uint32_t channelCount = audio_channel_count_from_out_mask(channelMask);
    const uint32_t hapticChannelCount = audio_channel_count_from_out_mask(
        channelMask & AUDIO_CHANNEL_HAPTIC_ALL);

    for (audio_io_handle_t output : outputs) {
        sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
        // matching criteria values in priority order for current output
        std::vector<uint32_t> currentMatchCriteria(8, 0);

        if (outputDesc->isDuplicated()) {
            continue;
        }
        if ((kExcludedFlags & outputDesc->mFlags) != 0) {
            continue;
        }

        // If haptic channel is specified, use the haptic output if present.
        // When using haptic output, same audio format and sample rate are required.
        const uint32_t outputHapticChannelCount = audio_channel_count_from_out_mask(
            outputDesc->getChannelMask() & AUDIO_CHANNEL_HAPTIC_ALL);
        if ((hapticChannelCount == 0) != (outputHapticChannelCount == 0)) {
            continue;
        }
        if (outputHapticChannelCount >= hapticChannelCount
            && format == outputDesc->getFormat()
            && samplingRate == outputDesc->getSamplingRate()) {
                currentMatchCriteria[0] = outputHapticChannelCount;
        }

        // functional flags match
        currentMatchCriteria[1] = popcount(outputDesc->mFlags & functionalFlags);

        // channel mask and channel count match
        uint32_t outputChannelCount = audio_channel_count_from_out_mask(
                outputDesc->getChannelMask());
        if (channelMask != AUDIO_CHANNEL_NONE && channelCount > 2 &&
            channelCount <= outputChannelCount) {
            if ((audio_channel_mask_get_representation(channelMask) ==
                    audio_channel_mask_get_representation(outputDesc->getChannelMask())) &&
                    ((channelMask & outputDesc->getChannelMask()) == channelMask)) {
                currentMatchCriteria[2] = outputChannelCount;
            }
            currentMatchCriteria[3] = outputChannelCount;
        }

        // sampling rate match
        if (samplingRate > SAMPLE_RATE_HZ_DEFAULT &&
                samplingRate <= outputDesc->getSamplingRate()) {
            currentMatchCriteria[4] = outputDesc->getSamplingRate();
        }

        // performance flags match
        currentMatchCriteria[5] = popcount(outputDesc->mFlags & performanceFlags);

        // format match
        if (format != AUDIO_FORMAT_INVALID) {
            currentMatchCriteria[6] =
                PolicyAudioPort::kFormatDistanceMax -
                PolicyAudioPort::formatDistance(format, outputDesc->getFormat());
        }

        // primary output match
        currentMatchCriteria[7] = outputDesc->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY;
        if (currentMatchCriteria[7])
            primary_output = output;

        // compare match criteria by priority then value
        if (std::lexicographical_compare(bestMatchCriteria.begin(), bestMatchCriteria.end(),
                currentMatchCriteria.begin(), currentMatchCriteria.end())) {
            bestMatchCriteria = currentMatchCriteria;
            bestOutput = output;

            std::stringstream result;
            std::copy(bestMatchCriteria.begin(), bestMatchCriteria.end(),
                std::ostream_iterator<int>(result, " "));
            ALOGV("%s new bestOutput %d criteria %s",
                __func__, bestOutput, result.str().c_str());
        }
    }

    {
        //only cts use ull, the others use primary output
        //if do not have ull profile(audio_policy_configuration.xml), cannot create ull desc.
        //so it must create ull output first
        sp<SwAudioOutputDescriptor> outputDescPrimary = mOutputs.valueFor(bestOutput);
        if (outputDescPrimary != nullptr && (outputDescPrimary->mFlags == (AUDIO_OUTPUT_FLAG_FAST|AUDIO_OUTPUT_FLAG_RAW))
                     && !isCts && primary_output != 0) {
            bestOutput = primary_output;
        }
    }

    return bestOutput;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值