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

Commit dc769682 authored by Mikhail Naganov's avatar Mikhail Naganov
Browse files

audio_server: Unify audio_patch creation

Provide PatchBuilder helper class instead of fiddling with
struct audio_patch directly.

Rename 'getAudioPortConfig' methods of AudioFlinger helper
classes into 'toAudioPortConfig' to match classes
of AudioPolicyManager.

Factor out common code in AudioPolicyManager that was
adding audio patches. For that, AudioOutputDescriptor now inherits
from AudioSessionInfoProvider, and the latter has been extended
with 'setPatchHandle' method.

Test: switch to/from Bluetooth on phone calls and media playback,
      use camcorder
Change-Id: Idd99645dc6943ed078c4d94d0197fead7831ab4d
parent f1040d20
Loading
Loading
Loading
Loading
+103 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ANDROID_PATCH_BUILDER_H
#define ANDROID_PATCH_BUILDER_H

#include <functional>
#include <utility>

#include <system/audio.h>
#include <utils/StrongPointer.h>

// This is a header-only utility.

namespace android {

class PatchBuilder {
  public:
    using mix_usecase_t = decltype(audio_port_config_mix_ext::usecase);

    PatchBuilder() = default;

    // All existing methods operating on audio patches take a pointer to const.
    // It's OK to construct a temporary PatchBuilder while preparing a parameter
    // to such a function because the Builder will be kept alive until the code
    // execution reaches the function call statement semicolon.
    const struct audio_patch* patch() const { return &mPatch; }

    template<typename T, typename... S>
    PatchBuilder& addSink(T&& t, S&&... s) {
        sinks().add(std::forward<T>(t), std::forward<S>(s)...);
        return *this;
    }
    // Explicit type of the second parameter allows clients to provide the struct inline.
    template<typename T>
    PatchBuilder& addSink(T&& t, const mix_usecase_t& update) {
        sinks().add(std::forward<T>(t), update);
        return *this;
    }
    template<typename T, typename... S>
    PatchBuilder& addSource(T&& t, S&&... s) {
        sources().add(std::forward<T>(t), std::forward<S>(s)...);
        return *this;
    }
    // Explicit type of the second parameter allows clients to provide the struct inline.
    template<typename T>
    PatchBuilder& addSource(T&& t, const mix_usecase_t& update) {
        sources().add(std::forward<T>(t), update);
        return *this;
    }

  private:
    struct PortCfgs {
        PortCfgs(unsigned int *countPtr, struct audio_port_config *portCfgs)
                : mCountPtr(countPtr), mPortCfgs(portCfgs) {}
        audio_port_config& add(const audio_port_config& portCfg) {
            return *advance() = portCfg;
        }
        template<typename T>
        audio_port_config& add(const sp<T>& entity) {
            audio_port_config* added = advance();
            entity->toAudioPortConfig(added);
            return *added;
        }
        template<typename T>
        void add(const sp<T>& entity, const mix_usecase_t& usecaseUpdate) {
            add(entity).ext.mix.usecase = usecaseUpdate;
        }
        template<typename T>
        void add(const sp<T>& entity,
                std::function<mix_usecase_t(const mix_usecase_t&)> usecaseUpdater) {
            mix_usecase_t* usecase = &add(entity).ext.mix.usecase;
            *usecase = usecaseUpdater(*usecase);
        }
        struct audio_port_config* advance() {
            return &mPortCfgs[(*mCountPtr)++];
        }
        unsigned int *mCountPtr;
        struct audio_port_config *mPortCfgs;
    };

    PortCfgs sinks() { return PortCfgs(&mPatch.num_sinks, mPatch.sinks); }
    PortCfgs sources() { return PortCfgs(&mPatch.num_sources, mPatch.sources); }

    struct audio_patch mPatch = {};
};

}  // namespace android

#endif  // ANDROID_PATCH_BUILDER_H
+8 −12
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include "AudioFlinger.h"
#include "ServiceUtilities.h"
#include <media/AudioParameter.h>
#include <media/PatchBuilder.h>

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

@@ -373,15 +374,10 @@ AudioFlinger::PatchPanel::Patch::~Patch()
status_t AudioFlinger::PatchPanel::Patch::createConnections(PatchPanel *panel)
{
    // create patch from source device to record thread input
    struct audio_patch subPatch;
    subPatch.num_sources = 1;
    subPatch.sources[0] = mAudioPatch.sources[0];
    subPatch.num_sinks = 1;

    mRecord.thread()->getAudioPortConfig(&subPatch.sinks[0]);
    subPatch.sinks[0].ext.mix.usecase.source = AUDIO_SOURCE_MIC;

    status_t status = panel->createAudioPatch(&subPatch, mRecord.handlePtr());
    status_t status = panel->createAudioPatch(
            PatchBuilder().addSource(mAudioPatch.sources[0]).
                addSink(mRecord.thread(), { .source = AUDIO_SOURCE_MIC }).patch(),
            mRecord.handlePtr());
    if (status != NO_ERROR) {
        *mRecord.handlePtr() = AUDIO_PATCH_HANDLE_NONE;
        return status;
@@ -389,9 +385,9 @@ status_t AudioFlinger::PatchPanel::Patch::createConnections(PatchPanel *panel)

    // create patch from playback thread output to sink device
    if (mAudioPatch.num_sinks != 0) {
        mPlayback.thread()->getAudioPortConfig(&subPatch.sources[0]);
        subPatch.sinks[0] = mAudioPatch.sinks[0];
        status = panel->createAudioPatch(&subPatch, mPlayback.handlePtr());
        status = panel->createAudioPatch(
                PatchBuilder().addSource(mPlayback.thread()).addSink(mAudioPatch.sinks[0]).patch(),
                mPlayback.handlePtr());
        if (status != NO_ERROR) {
            *mPlayback.handlePtr() = AUDIO_PATCH_HANDLE_NONE;
            return status;
+7 −7
Original line number Diff line number Diff line
@@ -1527,7 +1527,7 @@ void AudioFlinger::ThreadBase::setMode(audio_mode_t mode)
    }
}

void AudioFlinger::ThreadBase::getAudioPortConfig(struct audio_port_config *config)
void AudioFlinger::ThreadBase::toAudioPortConfig(struct audio_port_config *config)
{
    config->type = AUDIO_PORT_TYPE_MIX;
    config->ext.mix.handle = mId;
@@ -3780,9 +3780,9 @@ void AudioFlinger::PlaybackThread::deletePatchTrack(const sp<PatchTrack>& track)
    destroyTrack_l(track);
}

void AudioFlinger::PlaybackThread::getAudioPortConfig(struct audio_port_config *config)
void AudioFlinger::PlaybackThread::toAudioPortConfig(struct audio_port_config *config)
{
    ThreadBase::getAudioPortConfig(config);
    ThreadBase::toAudioPortConfig(config);
    config->role = AUDIO_PORT_ROLE_SOURCE;
    config->ext.mix.hw_module = mOutput->audioHwDev->handle();
    config->ext.mix.usecase.stream = AUDIO_STREAM_DEFAULT;
@@ -7875,9 +7875,9 @@ void AudioFlinger::RecordThread::deletePatchTrack(const sp<PatchRecord>& record)
    destroyTrack_l(record);
}

void AudioFlinger::RecordThread::getAudioPortConfig(struct audio_port_config *config)
void AudioFlinger::RecordThread::toAudioPortConfig(struct audio_port_config *config)
{
    ThreadBase::getAudioPortConfig(config);
    ThreadBase::toAudioPortConfig(config);
    config->role = AUDIO_PORT_ROLE_SINK;
    config->ext.mix.hw_module = mInput->audioHwDev->handle();
    config->ext.mix.usecase.source = mAudioSource;
@@ -8462,9 +8462,9 @@ status_t AudioFlinger::MmapThread::releaseAudioPatch_l(const audio_patch_handle_
    return status;
}

void AudioFlinger::MmapThread::getAudioPortConfig(struct audio_port_config *config)
void AudioFlinger::MmapThread::toAudioPortConfig(struct audio_port_config *config)
{
    ThreadBase::getAudioPortConfig(config);
    ThreadBase::toAudioPortConfig(config);
    if (isOutput()) {
        config->role = AUDIO_PORT_ROLE_SOURCE;
        config->ext.mix.hw_module = mAudioHwDev->handle();
+4 −4
Original line number Diff line number Diff line
@@ -281,7 +281,7 @@ public:
    virtual     status_t    createAudioPatch_l(const struct audio_patch *patch,
                                               audio_patch_handle_t *handle) = 0;
    virtual     status_t    releaseAudioPatch_l(const audio_patch_handle_t handle) = 0;
    virtual     void        getAudioPortConfig(struct audio_port_config *config) = 0;
    virtual     void        toAudioPortConfig(struct audio_port_config *config) = 0;


                // see note at declaration of mStandby, mOutDevice and mInDevice
@@ -782,7 +782,7 @@ public:
                void        addPatchTrack(const sp<PatchTrack>& track);
                void        deletePatchTrack(const sp<PatchTrack>& track);

    virtual     void        getAudioPortConfig(struct audio_port_config *config);
    virtual     void        toAudioPortConfig(struct audio_port_config *config);

                // Return the asynchronous signal wait time.
    virtual     int64_t     computeWaitTimeNs_l() const { return INT64_MAX; }
@@ -1459,7 +1459,7 @@ public:

    virtual size_t      frameCount() const { return mFrameCount; }
            bool        hasFastCapture() const { return mFastCapture != 0; }
    virtual void        getAudioPortConfig(struct audio_port_config *config);
    virtual void        toAudioPortConfig(struct audio_port_config *config);

    virtual status_t    checkEffectCompatibility_l(const effect_descriptor_t *desc,
                                                   audio_session_t sessionId);
@@ -1602,7 +1602,7 @@ class MmapThread : public ThreadBase
    virtual     status_t    createAudioPatch_l(const struct audio_patch *patch,
                                               audio_patch_handle_t *handle);
    virtual     status_t    releaseAudioPatch_l(const audio_patch_handle_t handle);
    virtual     void        getAudioPortConfig(struct audio_port_config *config);
    virtual     void        toAudioPortConfig(struct audio_port_config *config);

    virtual     sp<StreamHalInterface> stream() const { return mHalStream; }
    virtual     status_t    addEffectChain_l(const sp<EffectChain>& chain);
+8 −7
Original line number Diff line number Diff line
@@ -19,26 +19,27 @@
namespace android {

/**
 * Interface for input descriptors to implement so dependent audio sessions can query information
 * about their context
 * Interface for I/O descriptors to implement so information about their context
 * can be queried and updated.
 */
class AudioSessionInfoProvider
class AudioIODescriptorInterface
{
public:
    virtual ~AudioSessionInfoProvider() {};
    virtual ~AudioIODescriptorInterface() {};

    virtual audio_config_base_t getConfig() const = 0;

    virtual audio_patch_handle_t getPatchHandle() const = 0;

    virtual void setPatchHandle(audio_patch_handle_t handle) = 0;
};

class AudioSessionInfoUpdateListener
class AudioIODescriptorUpdateListener
{
public:
    virtual ~AudioSessionInfoUpdateListener() {};
    virtual ~AudioIODescriptorUpdateListener() {};

    virtual void onSessionInfoUpdate() const = 0;;
    virtual void onIODescriptorUpdate() const = 0;
};

} // namespace android
Loading