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

Commit 39efb7a1 authored by Andy Hung's avatar Andy Hung
Browse files

AudioPolicyManager: abort when client is removed while active

This can result in a refcount mismatch. It is safer to
abort immediately.

Test: Audio sanity, phone call
Bug: 112067674
Change-Id: I7835e75342b4c1aa3d6d910ee782d3bc818bd553
parent af036dab
Loading
Loading
Loading
Loading
+9 −11
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ class AudioPolicyClientInterface;
// descriptor for audio inputs. Used to maintain current configuration of each opened audio input
// and keep track of the usage of this input.
class AudioInputDescriptor: public AudioPortConfig, public AudioIODescriptorInterface
    , public ClientMapHandler<RecordClientDescriptor>
{
public:
    explicit AudioInputDescriptor(const sp<IOProfile>& profile,
@@ -42,9 +43,9 @@ public:

    status_t    dump(int fd);

    audio_io_handle_t             mIoHandle;       // input handle
    audio_devices_t               mDevice;         // current device this input is routed to
    AudioMix                      *mPolicyMix;     // non NULL when used by a dynamic policy
    audio_io_handle_t   mIoHandle = AUDIO_IO_HANDLE_NONE; // input handle
    audio_devices_t     mDevice = AUDIO_DEVICE_NONE;  // current device this input is routed to
    AudioMix            *mPolicyMix = nullptr;        // non NULL when used by a dynamic policy
    const sp<IOProfile> mProfile;                     // I/O profile this output derives from

    virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
@@ -82,7 +83,6 @@ public:
    void stop();
    void close();

    RecordClientMap& clientsMap() { return mClients; }
    RecordClientVector getClientsForSession(audio_session_t session);
    RecordClientVector clientsList(bool activeOnly = false,
        audio_source_t source = AUDIO_SOURCE_DEFAULT, bool preferredDeviceOnly = false) const;
@@ -91,8 +91,8 @@ public:

    void updateClientRecordingConfiguration(int event, const sp<RecordClientDescriptor>& client);

    audio_patch_handle_t          mPatchHandle;
    audio_port_handle_t           mId;
    audio_patch_handle_t mPatchHandle = AUDIO_PATCH_HANDLE_NONE;
    audio_port_handle_t  mId = AUDIO_PORT_HANDLE_NONE;
    // Because a preemptible capture session can preempt another one, we end up in an endless loop
    // situation were each session is allowed to restart after being preempted,
    // thus preempting the other one which restarts and so on.
@@ -100,10 +100,8 @@ public:
    // a particular input started and prevent preemption of this active input by this session.
    // We also inherit sessions from the preempted input to avoid a 3 way preemption loop etc...
    SortedVector<audio_session_t> mPreemptedSessions;
    AudioPolicyClientInterface *mClientInterface;
    int32_t mGlobalActiveCount;  // non-client-specific activity ref count

    RecordClientMap mClients;
    AudioPolicyClientInterface * const mClientInterface;
    int32_t mGlobalActiveCount = 0;  // non-client-specific activity ref count
};

class AudioInputCollection :
+48 −19
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@

#include <sys/types.h>

#include <audio_utils/SimpleLog.h>
#include <utils/Errors.h>
#include <utils/Timers.h>
#include <utils/KeyedVector.h>
@@ -38,6 +37,7 @@ class DeviceDescriptor;
// 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 AudioIODescriptorInterface
    , public ClientMapHandler<TrackClientDescriptor>
{
public:
    AudioOutputDescriptor(const sp<AudioPort>& port,
@@ -61,9 +61,21 @@ public:
                           audio_devices_t device,
                           uint32_t delayMs,
                           bool force);

    /**
     * Changes the stream active count and mActiveClients only.
     * This does not change the client->active() state or the output descriptor's
     * global active count.
     */
    virtual void changeStreamActiveCount(const sp<TrackClientDescriptor>& client, int delta);
            uint32_t streamActiveCount(audio_stream_type_t stream) const
                            { return mActiveCount[stream]; }

    /**
     * Changes the client->active() state and the output descriptor's global active count,
     * along with the stream active count and mActiveClients.
     * The client must be previously added by the base class addClient().
     */
            void setClientActive(const sp<TrackClientDescriptor>& client, bool active);

    bool isActive(uint32_t inPastMs = 0) const;
@@ -76,12 +88,6 @@ public:
    virtual sp<AudioPort> getAudioPort() const { return mPort; }
    virtual void toAudioPort(struct audio_port *port) const;

    using ActiveClientMap = std::map<sp<TrackClientDescriptor>, size_t /* count */>;

    const ActiveClientMap& getActiveClients() const {
        return mActiveClients;
    }

    audio_module_handle_t getModuleHandle() const;

    // implementation of AudioIODescriptorInterface
@@ -89,28 +95,51 @@ public:
    audio_patch_handle_t getPatchHandle() const override;
    void setPatchHandle(audio_patch_handle_t handle) override;

    TrackClientMap& clientsMap() { return mClients; }
    TrackClientVector clientsList(bool activeOnly = false,
        routing_strategy strategy = STRATEGY_NONE, bool preferredDeviceOnly = false) const;

    sp<AudioPort> mPort;
    audio_devices_t mDevice;                   // current device this output is routed to
    // override ClientMapHandler to abort when removing a client when active.
    void removeClient(audio_port_handle_t portId) override {
        auto client = getClient(portId);
        LOG_ALWAYS_FATAL_IF(client.get() == nullptr,
                "%s(%d): nonexistent client portId %d", __func__, mId, portId);
        // it is possible that when a client is removed, we could remove its
        // associated active count by calling changeStreamActiveCount(),
        // but that would be hiding a problem, so we log fatal instead.
        auto it2 = mActiveClients.find(client);
        LOG_ALWAYS_FATAL_IF(it2 != mActiveClients.end(),
                "%s(%d) removing client portId %d which is active (count %zu)",
                __func__, mId, portId, it2->second);
        ClientMapHandler<TrackClientDescriptor>::removeClient(portId);
    }

    using ActiveClientMap = std::map<sp<TrackClientDescriptor>, size_t /* count */>;
    // required for duplicating thread
    const ActiveClientMap& getActiveClients() const {
        return mActiveClients;
    }

    audio_devices_t mDevice = AUDIO_DEVICE_NONE; // current device this output is routed to
    nsecs_t mStopTime[AUDIO_STREAM_CNT];
    float mCurVolume[AUDIO_STREAM_CNT];   // current stream volume in dB
    int mMuteCount[AUDIO_STREAM_CNT];            // mute request counter
    bool mStrategyMutedByDevice[NUM_STRATEGIES]; // strategies muted because of incompatible
                                        // device selection. See checkDeviceMuteStrategies()
    AudioPolicyClientInterface *mClientInterface;
    AudioMix *mPolicyMix;             // non NULL when used by a dynamic policy
    AudioMix *mPolicyMix = nullptr;              // non NULL when used by a dynamic policy

protected:
    const sp<AudioPort> mPort;
    AudioPolicyClientInterface * const mClientInterface;
    float mCurVolume[AUDIO_STREAM_CNT];   // current stream volume in dB
    uint32_t mActiveCount[AUDIO_STREAM_CNT]; // number of streams of each type active on this output
    uint32_t mGlobalActiveCount;  // non-client-specific active count
    audio_patch_handle_t mPatchHandle;
    audio_port_handle_t mId;
    TrackClientMap mClients;
    uint32_t mGlobalActiveCount = 0;  // non-client-specific active count
    audio_patch_handle_t mPatchHandle = AUDIO_PATCH_HANDLE_NONE;
    audio_port_handle_t mId = AUDIO_PORT_HANDLE_NONE;

    // The ActiveClientMap shows the clients that contribute to the streams counts
    // and may include upstream clients from a duplicating thread.
    // Compare with the ClientMap (mClients) which are external AudioTrack clients of the
    // output descriptor (and do not count internal PatchTracks).
    ActiveClientMap mActiveClients;
    SimpleLog mLocalLog;
};

// Audio output driven by a software mixer in audio flinger.
+81 −2
Original line number Diff line number Diff line
@@ -163,8 +163,87 @@ public:
};

typedef std::vector< sp<TrackClientDescriptor> > TrackClientVector;
typedef std::map< audio_port_handle_t, sp<TrackClientDescriptor> > TrackClientMap;
typedef std::vector< sp<RecordClientDescriptor> > RecordClientVector;
typedef std::map< audio_port_handle_t, sp<RecordClientDescriptor> > RecordClientMap;

// A Map that associates a portId with a client (type T)
// which is either TrackClientDescriptor or RecordClientDescriptor.

template<typename T>
class ClientMapHandler {
public:
    virtual ~ClientMapHandler() = default;

    // Track client management
    void addClient(const sp<T> &client) {
        const audio_port_handle_t portId = client->portId();
        LOG_ALWAYS_FATAL_IF(!mClients.emplace(portId, client).second,
                "%s(%d): attempting to add client that already exists", __func__, portId);
    }
    sp<T> getClient(audio_port_handle_t portId) const {
        auto it = mClients.find(portId);
        if (it == mClients.end()) return nullptr;
        return it->second;
    }
    virtual void removeClient(audio_port_handle_t portId) {
        LOG_ALWAYS_FATAL_IF(mClients.erase(portId) == 0,
                "%s(%d): client does not exist", __func__, portId);
    }
    size_t getClientCount() const {
        return mClients.size();
    }
    String8 dump() const {
        String8 result;
        size_t index = 0;
        for (const auto& client: getClientIterable()) {
            client->dump(result, 2, index++);
        }
        return result;
    }

    // helper types
    using ClientMap = std::map<audio_port_handle_t, sp<T>>;
    using ClientMapIterator = typename ClientMap::const_iterator;  // ClientMap is const qualified
    class ClientIterable {
    public:
        explicit ClientIterable(const ClientMapHandler<T> &ref) : mClientMapHandler(ref) { }

        class iterator {
        public:
            // traits
            using iterator_category = std::forward_iterator_tag;
            using value_type = sp<T>;
            using difference_type = ptrdiff_t;
            using pointer = const sp<T>*;    // Note: const
            using reference = const sp<T>&;  // Note: const

            // implementation
            explicit iterator(const ClientMapIterator &it) : mIt(it) { }
            iterator& operator++()    /* prefix */     { ++mIt; return *this; }
            reference operator* () const               { return mIt->second; }
            reference operator->() const               { return mIt->second; } // as if sp<>
            difference_type operator-(const iterator& rhs) {return mIt - rhs.mIt; }
            bool operator==(const iterator& rhs) const { return mIt == rhs.mIt; }
            bool operator!=(const iterator& rhs) const { return mIt != rhs.mIt; }
        private:
            ClientMapIterator mIt;
        };

        iterator begin() const { return iterator{mClientMapHandler.mClients.begin()}; }
        iterator end() const { return iterator{mClientMapHandler.mClients.end()}; }

    private:
        const ClientMapHandler<T>& mClientMapHandler; // iterating does not modify map.
    };

    // return an iterable object that can be used in a range-based-for to enumerate clients.
    // this iterable does not allow modification, it should be used as a temporary.
    ClientIterable getClientIterable() const {
        return ClientIterable{*this};
    }

private:
    // ClientMap maps a portId to a client descriptor (both uniquely identify each other).
    ClientMap mClients;
};

} // namespace android
+39 −54
Original line number Diff line number Diff line
@@ -29,10 +29,8 @@ namespace android {

AudioInputDescriptor::AudioInputDescriptor(const sp<IOProfile>& profile,
                                           AudioPolicyClientInterface *clientInterface)
    : mIoHandle(0),
      mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL),
      mProfile(profile), mPatchHandle(AUDIO_PATCH_HANDLE_NONE), mId(0),
      mClientInterface(clientInterface), mGlobalActiveCount(0)
    : mProfile(profile)
    ,  mClientInterface(clientInterface)
{
    if (profile != NULL) {
        profile->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
@@ -115,12 +113,12 @@ void AudioInputDescriptor::clearPreemptedSessions()

bool AudioInputDescriptor::isSourceActive(audio_source_t source) const
{
    for (const auto &client : mClients) {
        if (client.second->active() &&
            ((client.second->source() == source) ||
    for (const auto &client : getClientIterable()) {
        if (client->active() &&
            ((client->source() == source) ||
                ((source == AUDIO_SOURCE_VOICE_RECOGNITION) &&
                    (client.second->source() == AUDIO_SOURCE_HOTWORD) &&
                    client.second->isSoundTrigger()))) {
                    (client->source() == AUDIO_SOURCE_HOTWORD) &&
                    client->isSoundTrigger()))) {
            return true;
        }
    }
@@ -132,14 +130,14 @@ audio_source_t AudioInputDescriptor::getHighestPrioritySource(bool activeOnly) c
    audio_source_t source = AUDIO_SOURCE_DEFAULT;
    int32_t priority = -1;

    for (const auto &client : mClients) {
        if (activeOnly && !client.second->active() ) {
    for (const auto &client : getClientIterable()) {
        if (activeOnly && !client->active() ) {
            continue;
        }
        int32_t curPriority = source_priority(client.second->source());
        int32_t curPriority = source_priority(client->source());
        if (curPriority > priority) {
            priority = curPriority;
            source = client.second->source();
            source = client->source();
        }
    }
    return source;
@@ -148,10 +146,10 @@ audio_source_t AudioInputDescriptor::getHighestPrioritySource(bool activeOnly) c
bool AudioInputDescriptor::isSoundTrigger() const {
    // sound trigger and non sound trigger clients are not mixed on a given input
    // so check only first client
    if (mClients.size() == 0) {
    if (getClientCount() == 0) {
        return false;
    }
    return mClients.cbegin()->second->isSoundTrigger();
    return getClientIterable().begin()->isSoundTrigger();
}

audio_patch_handle_t AudioInputDescriptor::getPatchHandle() const
@@ -162,9 +160,9 @@ audio_patch_handle_t AudioInputDescriptor::getPatchHandle() const
void AudioInputDescriptor::setPatchHandle(audio_patch_handle_t handle)
{
    mPatchHandle = handle;
    for (const auto &client : mClients) {
        if (client.second->active()) {
            updateClientRecordingConfiguration(RECORD_CONFIG_EVENT_START, client.second);
    for (const auto &client : getClientIterable()) {
        if (client->active()) {
            updateClientRecordingConfiguration(RECORD_CONFIG_EVENT_START, client);
        }
    }
}
@@ -265,8 +263,9 @@ void AudioInputDescriptor::close()

void AudioInputDescriptor::setClientActive(const sp<RecordClientDescriptor>& client, bool active)
{
    if (mClients.find(client->portId()) == mClients.end()
         || active == client->active()) {
    LOG_ALWAYS_FATAL_IF(getClient(client->portId()) == nullptr,
        "%s(%d) does not exist on input descriptor", __func__, client->portId());
    if (active == client->active()) {
        return;
    }

@@ -276,7 +275,8 @@ void AudioInputDescriptor::setClientActive(const sp<RecordClientDescriptor>& cli
        ALOGW("%s invalid deactivation with globalRefCount %d", __FUNCTION__, mGlobalActiveCount);
        mGlobalActiveCount = 1;
    }
    mGlobalActiveCount += active ? 1 : -1;
    const int delta = active ? 1 : -1;
    mGlobalActiveCount += delta;

    if ((oldGlobalActiveCount == 0) && (mGlobalActiveCount > 0)) {
        if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
@@ -314,9 +314,9 @@ RecordClientVector AudioInputDescriptor::getClientsForSession(
    audio_session_t session)
{
    RecordClientVector clients;
    for (const auto &client : mClients) {
        if (client.second->session() == session) {
            clients.push_back(client.second);
    for (const auto &client : getClientIterable()) {
        if (client->session() == session) {
            clients.push_back(client);
        }
    }
    return clients;
@@ -326,11 +326,11 @@ RecordClientVector AudioInputDescriptor::clientsList(bool activeOnly, audio_sour
                                                     bool preferredDeviceOnly) const
{
    RecordClientVector clients;
    for (const auto &client : mClients) {
        if ((!activeOnly || client.second->active())
            && (source == AUDIO_SOURCE_DEFAULT || source == client.second->source())
            && (!preferredDeviceOnly || client.second->hasPreferredDevice())) {
            clients.push_back(client.second);
    for (const auto &client : getClientIterable()) {
        if ((!activeOnly || client->active())
            && (source == AUDIO_SOURCE_DEFAULT || source == client->source())
            && (!preferredDeviceOnly || client->hasPreferredDevice())) {
            clients.push_back(client);
        }
    }
    return clients;
@@ -338,28 +338,15 @@ RecordClientVector AudioInputDescriptor::clientsList(bool activeOnly, audio_sour

status_t AudioInputDescriptor::dump(int fd)
{
    const size_t SIZE = 256;
    char buffer[SIZE];
    String8 result;

    snprintf(buffer, SIZE, " ID: %d\n", getId());
    result.append(buffer);
    snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate);
    result.append(buffer);
    snprintf(buffer, SIZE, " Format: %d\n", mFormat);
    result.append(buffer);
    snprintf(buffer, SIZE, " Channels: %08x\n", mChannelMask);
    result.append(buffer);
    snprintf(buffer, SIZE, " Devices %08x\n", mDevice);
    result.append(buffer);

    write(fd, result.string(), result.size());

    size_t index = 0;
    result = " AudioRecord clients:\n";
    for (const auto& client: mClients) {
        client.second->dump(result, 2, index++);
    }
    result.appendFormat(" ID: %d\n", getId());
    result.appendFormat(" Sampling rate: %d\n", mSamplingRate);
    result.appendFormat(" Format: %d\n", mFormat);
    result.appendFormat(" Channels: %08x\n", mChannelMask);
    result.appendFormat(" Devices %08x\n", mDevice);
    result.append(" AudioRecord Clients:\n");
    result.append(ClientMapHandler<RecordClientDescriptor>::dump());
    result.append("\n");
    write(fd, result.string(), result.size());
    return NO_ERROR;
@@ -427,12 +414,10 @@ sp<AudioInputDescriptor> AudioInputCollection::getInputForClient(audio_port_hand
{
    for (size_t i = 0; i < size(); i++) {
        sp<AudioInputDescriptor> inputDesc = valueAt(i);
        for (const auto& client : inputDesc->clientsMap()) {
            if (client.second->portId() == portId) {
        if (inputDesc->getClient(portId) != nullptr) {
            return inputDesc;
        }
    }
    }
    return 0;
}

+31 −56
Original line number Diff line number Diff line
@@ -34,8 +34,8 @@ namespace android {

AudioOutputDescriptor::AudioOutputDescriptor(const sp<AudioPort>& port,
                                             AudioPolicyClientInterface *clientInterface)
    : mPort(port), mDevice(AUDIO_DEVICE_NONE), mClientInterface(clientInterface),
      mPolicyMix(NULL), mGlobalActiveCount(0), mPatchHandle(AUDIO_PATCH_HANDLE_NONE), mId(0)
    : mPort(port)
    , mClientInterface(clientInterface)
{
    // clear usage count for all stream types
    for (int i = 0; i < AUDIO_STREAM_CNT; i++) {
@@ -139,20 +139,17 @@ void AudioOutputDescriptor::changeStreamActiveCount(const sp<TrackClientDescript

void AudioOutputDescriptor::setClientActive(const sp<TrackClientDescriptor>& client, bool active)
{
    if (mClients.find(client->portId()) == mClients.end()
        || active == client->active()) {
    LOG_ALWAYS_FATAL_IF(getClient(client->portId()) == nullptr,
        "%s(%d) does not exist on output descriptor", __func__, client->portId());

        mLocalLog.log("%s(%s): ignored active: %d, current stream count %d",
    if (active == client->active()) {
        ALOGW("%s(%s): ignored active: %d, current stream count %d",
                __func__, client->toShortString().c_str(),
                active, mActiveCount[client->stream()]);
        return;
    }

    changeStreamActiveCount(client, active ? 1 : -1);

    mLocalLog.log("%s(%s): active: %d, current stream count %d",
            __func__, client->toShortString().c_str(),
             active, mActiveCount[client->stream()]);
    const int delta = active ? 1 : -1;
    changeStreamActiveCount(client, delta);

    // Handle non-client-specific activity ref count
    int32_t oldGlobalActiveCount = mGlobalActiveCount;
@@ -161,7 +158,7 @@ void AudioOutputDescriptor::setClientActive(const sp<TrackClientDescriptor>& cli
                __func__, client->toShortString().c_str(), mGlobalActiveCount);
        mGlobalActiveCount = 1;
    }
    mGlobalActiveCount += active ? 1 : -1;
    mGlobalActiveCount += delta;

    if ((oldGlobalActiveCount == 0) && (mGlobalActiveCount > 0)) {
        if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
@@ -269,11 +266,11 @@ TrackClientVector AudioOutputDescriptor::clientsList(bool activeOnly, routing_st
                                                     bool preferredDeviceOnly) const
{
    TrackClientVector clients;
    for (const auto &client : mClients) {
        if ((!activeOnly || client.second->active())
            && (strategy == STRATEGY_NONE || strategy == client.second->strategy())
            && (!preferredDeviceOnly || client.second->hasPreferredDevice())) {
            clients.push_back(client.second);
    for (const auto &client : getClientIterable()) {
        if ((!activeOnly || client->active())
            && (strategy == STRATEGY_NONE || strategy == client->strategy())
            && (!preferredDeviceOnly || client->hasPreferredDevice())) {
            clients.push_back(client);
        }
    }
    return clients;
@@ -281,49 +278,33 @@ TrackClientVector AudioOutputDescriptor::clientsList(bool activeOnly, routing_st

status_t AudioOutputDescriptor::dump(int fd)
{
    const size_t SIZE = 256;
    char buffer[SIZE];
    String8 result;

    snprintf(buffer, SIZE, " ID: %d\n", mId);
    result.append(buffer);
    snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate);
    result.append(buffer);
    snprintf(buffer, SIZE, " Format: %08x\n", mFormat);
    result.append(buffer);
    snprintf(buffer, SIZE, " Channels: %08x\n", mChannelMask);
    result.append(buffer);
    snprintf(buffer, SIZE, " Devices %08x\n", device());
    result.append(buffer);
    snprintf(buffer, SIZE, " Stream volume activeCount muteCount\n");
    result.append(buffer);
    result.appendFormat(" ID: %d\n", mId);
    result.appendFormat(" Sampling rate: %d\n", mSamplingRate);
    result.appendFormat(" Format: %08x\n", mFormat);
    result.appendFormat(" Channels: %08x\n", mChannelMask);
    result.appendFormat(" Devices: %08x\n", device());
    result.appendFormat(" Global active count: %u\n", mGlobalActiveCount);
    result.append(" Stream volume activeCount muteCount\n");
    for (int i = 0; i < (int)AUDIO_STREAM_CNT; i++) {
        snprintf(buffer, SIZE, " %02d     %.03f     %02d          %02d\n",
        result.appendFormat(" %02d     %.03f     %02d          %02d\n",
                 i, mCurVolume[i], streamActiveCount((audio_stream_type_t)i), mMuteCount[i]);
        result.append(buffer);
    }

    result.append(" AudioTrack clients:\n");
    size_t index = 0;
    for (const auto& client : mClients) {
        client.second->dump(result, 2, index++);
    }
    result.append(" AudioTrack Clients:\n");
    result.append(ClientMapHandler<TrackClientDescriptor>::dump());
    result.append("\n");

    if (mActiveClients.size() > 0) {
        result.append(" AudioTrack active clients:\n");
        index = 0;
        result.append(" AudioTrack active (stream) clients:\n");
        size_t index = 0;
        for (const auto& clientPair : mActiveClients) {
            result.appendFormat(" Refcount: %zu", clientPair.second);
            clientPair.first->dump(result, 2, index++);
        }
        result.append(" \n");
    }

    write(fd, result.string(), result.size());

    // write local log
    mLocalLog.dump(fd, "   " /* prefix */, 40 /* lines */);
    return NO_ERROR;
}

@@ -349,14 +330,10 @@ SwAudioOutputDescriptor::SwAudioOutputDescriptor(const sp<IOProfile>& profile,

status_t SwAudioOutputDescriptor::dump(int fd)
{
    const size_t SIZE = 256;
    char buffer[SIZE];
    String8 result;

    snprintf(buffer, SIZE, " Latency: %d\n", mLatency);
    result.append(buffer);
    snprintf(buffer, SIZE, " Flags %08x\n", mFlags);
    result.append(buffer);
    result.appendFormat(" Latency: %d\n", mLatency);
    result.appendFormat(" Flags %08x\n", mFlags);
    write(fd, result.string(), result.size());

    AudioOutputDescriptor::dump(fd);
@@ -808,12 +785,10 @@ sp<SwAudioOutputDescriptor> SwAudioOutputCollection::getOutputForClient(audio_po
{
    for (size_t i = 0; i < size(); i++) {
        sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
        for (const auto& client : outputDesc->clientsMap()) {
            if (client.second->portId() == portId) {
        if (outputDesc->getClient(portId) != nullptr) {
            return outputDesc;
        }
    }
    }
    return 0;
}

Loading