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

Commit 7c1ec5f0 authored by Eric Laurent's avatar Eric Laurent
Browse files

audio: several fixes in audio routing callbacks

- audio policy:
Force device change to ensure new audio patch creation
upon first track activity on a given output.
Fix function device_distinguishes_on_address() which could mistake
some output device with remote submix input device.

- audio flinger:
Reduce number of binder calls upon new client registration by only
sending ioConfigChanged() callbacks to newly registered client.
Fix first patch after output thread creation not triggering an
ioConfigChanged() callback.

-audio system:
Force client registration upon routing callback installation to force
new ioConfigChanged() callback from audio flinger.

Bug: 22381136.

Change-Id: Ieb0d9f92f563a40552eb31bc0499c8ac65f78ce4
parent 54c0659b
Loading
Loading
Loading
Loading
+14 −5
Original line number Diff line number Diff line
@@ -476,11 +476,13 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(audio_io_config_event even
        switch (event) {
        case AUDIO_OUTPUT_OPENED:
        case AUDIO_INPUT_OPENED: {
            if (getIoDescriptor(ioDesc->mIoHandle) != 0) {
                ALOGV("ioConfigChanged() opening already existing output! %d", ioDesc->mIoHandle);
                break;
            }
            sp<AudioIoDescriptor> oldDesc = getIoDescriptor(ioDesc->mIoHandle);
            if (oldDesc == 0) {
                mIoDescriptors.add(ioDesc->mIoHandle, ioDesc);
            } else {
                deviceId = oldDesc->getDeviceId();
                mIoDescriptors.replaceValueFor(ioDesc->mIoHandle, ioDesc);
            }

            if (ioDesc->getDeviceId() != AUDIO_PORT_HANDLE_NONE) {
                deviceId = ioDesc->getDeviceId();
@@ -1074,7 +1076,14 @@ status_t AudioSystem::addAudioDeviceCallback(
    if (afc == 0) {
        return NO_INIT;
    }
    return afc->addAudioDeviceCallback(callback, audioIo);
    status_t status = afc->addAudioDeviceCallback(callback, audioIo);
    if (status == NO_ERROR) {
        const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
        if (af != 0) {
            af->registerClient(afc);
        }
    }
    return status;
}

status_t AudioSystem::removeAudioDeviceCallback(
+13 −15
Original line number Diff line number Diff line
@@ -1252,11 +1252,9 @@ void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)
    if (client == 0) {
        return;
    }
    bool clientAdded = false;
    pid_t pid = IPCThreadState::self()->getCallingPid();
    {
        Mutex::Autolock _cl(mClientLock);

        pid_t pid = IPCThreadState::self()->getCallingPid();
        if (mNotificationClients.indexOfKey(pid) < 0) {
            sp<NotificationClient> notificationClient = new NotificationClient(this,
                                                                                client,
@@ -1267,22 +1265,19 @@ void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)

            sp<IBinder> binder = IInterface::asBinder(client);
            binder->linkToDeath(notificationClient);
            clientAdded = true;
        }
    }

    // mClientLock should not be held here because ThreadBase::sendIoConfigEvent() will lock the
    // ThreadBase mutex and the locking order is ThreadBase::mLock then AudioFlinger::mClientLock.
    if (clientAdded) {
    // the config change is always sent from playback or record threads to avoid deadlock
    // with AudioSystem::gLock
    for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
            mPlaybackThreads.valueAt(i)->sendIoConfigEvent(AUDIO_OUTPUT_OPENED);
        mPlaybackThreads.valueAt(i)->sendIoConfigEvent(AUDIO_OUTPUT_OPENED, pid);
    }

    for (size_t i = 0; i < mRecordThreads.size(); i++) {
            mRecordThreads.valueAt(i)->sendIoConfigEvent(AUDIO_INPUT_OPENED);
        }
        mRecordThreads.valueAt(i)->sendIoConfigEvent(AUDIO_INPUT_OPENED, pid);
    }
}

@@ -1316,14 +1311,17 @@ void AudioFlinger::removeNotificationClient(pid_t pid)
}

void AudioFlinger::ioConfigChanged(audio_io_config_event event,
                                   const sp<AudioIoDescriptor>& ioDesc)
                                   const sp<AudioIoDescriptor>& ioDesc,
                                   pid_t pid)
{
    Mutex::Autolock _l(mClientLock);
    size_t size = mNotificationClients.size();
    for (size_t i = 0; i < size; i++) {
        if ((pid == 0) || (mNotificationClients.keyAt(i) == pid)) {
            mNotificationClients.valueAt(i)->audioFlingerClient()->ioConfigChanged(event, ioDesc);
        }
    }
}

// removeClient_l() must be called with AudioFlinger::mClientLock held
void AudioFlinger::removeClient_l(pid_t pid)
+2 −1
Original line number Diff line number Diff line
@@ -559,7 +559,8 @@ private:
              float streamVolume_l(audio_stream_type_t stream) const
                                { return mStreamTypes[stream].volume; }
              void ioConfigChanged(audio_io_config_event event,
                                   const sp<AudioIoDescriptor>& ioDesc);
                                   const sp<AudioIoDescriptor>& ioDesc,
                                   pid_t pid = 0);

              // Allocate an audio_io_handle_t, session ID, effect ID, or audio_module_handle_t.
              // They all share the same ID space, but the namespaces are actually independent
+16 −11
Original line number Diff line number Diff line
@@ -532,7 +532,8 @@ AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio
        // RecordThread::readInputParameters_l()
        //FIXME: mStandby should be true here. Is this some kind of hack?
        mStandby(false), mOutDevice(outDevice), mInDevice(inDevice),
        mPrevInDevice(AUDIO_DEVICE_NONE), mAudioSource(AUDIO_SOURCE_DEFAULT), mId(id),
        mPrevOutDevice(AUDIO_DEVICE_NONE), mPrevInDevice(AUDIO_DEVICE_NONE),
        mAudioSource(AUDIO_SOURCE_DEFAULT), mId(id),
        // mName will be set by concrete (non-virtual) subclass
        mDeathRecipient(new PMDeathRecipient(this)),
        mSystemReady(systemReady)
@@ -627,16 +628,16 @@ status_t AudioFlinger::ThreadBase::sendConfigEvent_l(sp<ConfigEvent>& event)
    return status;
}

void AudioFlinger::ThreadBase::sendIoConfigEvent(audio_io_config_event event)
void AudioFlinger::ThreadBase::sendIoConfigEvent(audio_io_config_event event, pid_t pid)
{
    Mutex::Autolock _l(mLock);
    sendIoConfigEvent_l(event);
    sendIoConfigEvent_l(event, pid);
}

// sendIoConfigEvent_l() must be called with ThreadBase::mLock held
void AudioFlinger::ThreadBase::sendIoConfigEvent_l(audio_io_config_event event)
void AudioFlinger::ThreadBase::sendIoConfigEvent_l(audio_io_config_event event, pid_t pid)
{
    sp<ConfigEvent> configEvent = (ConfigEvent *)new IoConfigEvent(event);
    sp<ConfigEvent> configEvent = (ConfigEvent *)new IoConfigEvent(event, pid);
    sendConfigEvent_l(configEvent);
}

@@ -706,7 +707,7 @@ void AudioFlinger::ThreadBase::processConfigEvents_l()
        } break;
        case CFG_EVENT_IO: {
            IoConfigEventData *data = (IoConfigEventData *)event->mData.get();
            ioConfigChanged(data->mEvent);
            ioConfigChanged(data->mEvent, data->mPid);
        } break;
        case CFG_EVENT_SET_PARAMETER: {
            SetParameterConfigEventData *data = (SetParameterConfigEventData *)event->mData.get();
@@ -1999,7 +2000,7 @@ String8 AudioFlinger::PlaybackThread::getParameters(const String8& keys)
    return out_s8;
}

void AudioFlinger::PlaybackThread::ioConfigChanged(audio_io_config_event event) {
void AudioFlinger::PlaybackThread::ioConfigChanged(audio_io_config_event event, pid_t pid) {
    sp<AudioIoDescriptor> desc = new AudioIoDescriptor();
    ALOGV("PlaybackThread::ioConfigChanged, thread %p, event %d", this, event);

@@ -2021,7 +2022,7 @@ void AudioFlinger::PlaybackThread::ioConfigChanged(audio_io_config_event event)
    default:
        break;
    }
    mAudioFlinger->ioConfigChanged(event, desc);
    mAudioFlinger->ioConfigChanged(event, desc, pid);
}

void AudioFlinger::PlaybackThread::writeCallback()
@@ -3133,7 +3134,10 @@ status_t AudioFlinger::PlaybackThread::createAudioPatch_l(const struct audio_pat
    for (size_t i = 0; i < mEffectChains.size(); i++) {
        mEffectChains[i]->setDevice_l(type);
    }
    bool configChanged = mOutDevice != type;

    // mPrevOutDevice is the latest device set by createAudioPatch_l(). It is not set when
    // the thread is created so that the first patch creation triggers an ioConfigChanged callback
    bool configChanged = mPrevOutDevice != type;
    mOutDevice = type;
    mPatch = *patch;

@@ -3163,6 +3167,7 @@ status_t AudioFlinger::PlaybackThread::createAudioPatch_l(const struct audio_pat
        *handle = AUDIO_PATCH_HANDLE_NONE;
    }
    if (configChanged) {
        mPrevOutDevice = type;
        sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
    }
    return status;
@@ -6868,7 +6873,7 @@ String8 AudioFlinger::RecordThread::getParameters(const String8& keys)
    return out_s8;
}

void AudioFlinger::RecordThread::ioConfigChanged(audio_io_config_event event) {
void AudioFlinger::RecordThread::ioConfigChanged(audio_io_config_event event, pid_t pid) {
    sp<AudioIoDescriptor> desc = new AudioIoDescriptor();

    desc->mIoHandle = mId;
@@ -6888,7 +6893,7 @@ void AudioFlinger::RecordThread::ioConfigChanged(audio_io_config_event event) {
    default:
        break;
    }
    mAudioFlinger->ioConfigChanged(event, desc);
    mAudioFlinger->ioConfigChanged(event, desc, pid);
}

void AudioFlinger::RecordThread::readInputParameters_l()
+11 −9
Original line number Diff line number Diff line
@@ -104,21 +104,22 @@ public:

    class IoConfigEventData : public ConfigEventData {
    public:
        IoConfigEventData(audio_io_config_event event) :
            mEvent(event) {}
        IoConfigEventData(audio_io_config_event event, pid_t pid) :
            mEvent(event), mPid(pid) {}

        virtual  void dump(char *buffer, size_t size) {
            snprintf(buffer, size, "IO event: event %d\n", mEvent);
        }

        const audio_io_config_event mEvent;
        const pid_t                 mPid;
    };

    class IoConfigEvent : public ConfigEvent {
    public:
        IoConfigEvent(audio_io_config_event event) :
        IoConfigEvent(audio_io_config_event event, pid_t pid) :
            ConfigEvent(CFG_EVENT_IO) {
            mData = new IoConfigEventData(event);
            mData = new IoConfigEventData(event, pid);
        }
        virtual ~IoConfigEvent() {}
    };
@@ -255,13 +256,13 @@ public:
                                                    status_t& status) = 0;
    virtual     status_t    setParameters(const String8& keyValuePairs);
    virtual     String8     getParameters(const String8& keys) = 0;
    virtual     void        ioConfigChanged(audio_io_config_event event) = 0;
    virtual     void        ioConfigChanged(audio_io_config_event event, pid_t pid = 0) = 0;
                // sendConfigEvent_l() must be called with ThreadBase::mLock held
                // Can temporarily release the lock if waiting for a reply from
                // processConfigEvents_l().
                status_t    sendConfigEvent_l(sp<ConfigEvent>& event);
                void        sendIoConfigEvent(audio_io_config_event event);
                void        sendIoConfigEvent_l(audio_io_config_event event);
                void        sendIoConfigEvent(audio_io_config_event event, pid_t pid = 0);
                void        sendIoConfigEvent_l(audio_io_config_event event, pid_t pid = 0);
                void        sendPrioConfigEvent(pid_t pid, pid_t tid, int32_t prio);
                void        sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio);
                status_t    sendSetParameterConfigEvent_l(const String8& keyValuePair);
@@ -436,6 +437,7 @@ protected:
                bool                    mStandby;     // Whether thread is currently in standby.
                audio_devices_t         mOutDevice;   // output device
                audio_devices_t         mInDevice;    // input device
                audio_devices_t         mPrevOutDevice;   // previous output device
                audio_devices_t         mPrevInDevice;    // previous input device
                struct audio_patch      mPatch;
                audio_source_t          mAudioSource;
@@ -572,7 +574,7 @@ public:
                                { return android_atomic_acquire_load(&mSuspended) > 0; }

    virtual     String8     getParameters(const String8& keys);
    virtual     void        ioConfigChanged(audio_io_config_event event);
    virtual     void        ioConfigChanged(audio_io_config_event event, pid_t pid = 0);
                status_t    getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames);
                // FIXME rename mixBuffer() to sinkBuffer() and remove int16_t* dependency.
                // Consider also removing and passing an explicit mMainBuffer initialization
@@ -1254,7 +1256,7 @@ public:
                                               status_t& status);
    virtual void        cacheParameters_l() {}
    virtual String8     getParameters(const String8& keys);
    virtual void        ioConfigChanged(audio_io_config_event event);
    virtual void        ioConfigChanged(audio_io_config_event event, pid_t pid = 0);
    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);
Loading