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

Commit 09b4ba82 authored by Eric Laurent's avatar Eric Laurent
Browse files

Issue 2265163: Audio still reported routed through earpiece on sholes

This is a second attempt to fix the audio routed to earpiece syndrom.
The root cause identified this time is the crash of an application having an active AudioTrack playing on the VOICE_CALL stream type.
When this happens, the AudioTrack destructor is not called and the audio policy manager is not notified of the track stop.
Results a situation where the VOICE_CALL stream is considered as always in use by audio policy manager which makes that audio is routed to earpiece.

The fix consists in moving the track start/stop/close notification to audio policiy manager from AudioTrack to AudioFlinger Track objet.
The net result is that in the case of a client application crash, the AudioFlinger TrackHandle object (which implements the remote side of the IAudioTrack binder interface) destructor is called which in turn destroys the Track object and we can notify the audio policy manager of the track stop and removal.

The same modification is made for AudioRecord although no bug related to record has been reported yet.
Also fixed a potential problem if record stop is called while the record thread is exiting.
parent 574917c8
Loading
Loading
Loading
Loading
+147 −90
Original line number Original line Diff line number Diff line
@@ -674,25 +674,7 @@ void AudioFlinger::binderDied(const wp<IBinder>& who) {
}
}


// audioConfigChanged_l() must be called with AudioFlinger::mLock held
// audioConfigChanged_l() must be called with AudioFlinger::mLock held
void AudioFlinger::audioConfigChanged_l(int event, const sp<ThreadBase>& thread, void *param2) {
void AudioFlinger::audioConfigChanged_l(int event, int ioHandle, void *param2) {
    int ioHandle = 0;

    for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
        if (mPlaybackThreads.valueAt(i) == thread) {
            ioHandle = mPlaybackThreads.keyAt(i);
            break;
        }
    }
    if (ioHandle == 0) {
        for (size_t i = 0; i < mRecordThreads.size(); i++) {
            if (mRecordThreads.valueAt(i) == thread) {
                ioHandle = mRecordThreads.keyAt(i);
                break;
            }
        }
    }

    if (ioHandle != 0) {
    size_t size = mNotificationClients.size();
    size_t size = mNotificationClients.size();
    for (size_t i = 0; i < size; i++) {
    for (size_t i = 0; i < size; i++) {
        sp<IBinder> binder = mNotificationClients.itemAt(i);
        sp<IBinder> binder = mNotificationClients.itemAt(i);
@@ -701,7 +683,6 @@ void AudioFlinger::audioConfigChanged_l(int event, const sp<ThreadBase>& thread,
        client->ioConfigChanged(event, ioHandle, param2);
        client->ioConfigChanged(event, ioHandle, param2);
    }
    }
}
}
}


// removeClient_l() must be called with AudioFlinger::mLock held
// removeClient_l() must be called with AudioFlinger::mLock held
void AudioFlinger::removeClient_l(pid_t pid)
void AudioFlinger::removeClient_l(pid_t pid)
@@ -712,10 +693,10 @@ void AudioFlinger::removeClient_l(pid_t pid)


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


AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger)
AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, int id)
    :   Thread(false),
    :   Thread(false),
        mAudioFlinger(audioFlinger), mSampleRate(0), mFrameCount(0), mChannelCount(0),
        mAudioFlinger(audioFlinger), mSampleRate(0), mFrameCount(0), mChannelCount(0),
        mFormat(0), mFrameSize(1), mStandby(false)
        mFormat(0), mFrameSize(1), mStandby(false), mId(id), mExiting(false)
{
{
}
}


@@ -734,6 +715,7 @@ void AudioFlinger::ThreadBase::exit()
    LOGV("ThreadBase::exit");
    LOGV("ThreadBase::exit");
    {
    {
        AutoMutex lock(&mLock);
        AutoMutex lock(&mLock);
        mExiting = true;
        requestExit();
        requestExit();
        mWaitWorkCV.signal();
        mWaitWorkCV.signal();
    }
    }
@@ -870,8 +852,8 @@ status_t AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args


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


AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output)
AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id)
    :   ThreadBase(audioFlinger),
    :   ThreadBase(audioFlinger, id),
        mMixBuffer(0), mSuspended(0), mBytesWritten(0), mOutput(output),
        mMixBuffer(0), mSuspended(0), mBytesWritten(0), mOutput(output),
        mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false)
        mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false)
{
{
@@ -1106,15 +1088,6 @@ status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track)
{
{
    status_t status = ALREADY_EXISTS;
    status_t status = ALREADY_EXISTS;


    // here the track could be either new, or restarted
    // in both cases "unstop" the track
    if (track->isPaused()) {
        track->mState = TrackBase::RESUMING;
        LOGV("PAUSED => RESUMING (%d) on thread %p", track->name(), this);
    } else {
        track->mState = TrackBase::ACTIVE;
        LOGV("? => ACTIVE (%d) on thread %p", track->name(), this);
    }
    // set retry count for buffer fill
    // set retry count for buffer fill
    track->mRetryCount = kMaxTrackStartupRetries;
    track->mRetryCount = kMaxTrackStartupRetries;
    if (mActiveTracks.indexOf(track) < 0) {
    if (mActiveTracks.indexOf(track) < 0) {
@@ -1173,7 +1146,7 @@ void AudioFlinger::PlaybackThread::audioConfigChanged(int event, int param) {
        break;
        break;
    }
    }
    Mutex::Autolock _l(mAudioFlinger->mLock);
    Mutex::Autolock _l(mAudioFlinger->mLock);
    mAudioFlinger->audioConfigChanged_l(event, this, param2);
    mAudioFlinger->audioConfigChanged_l(event, mId, param2);
}
}


void AudioFlinger::PlaybackThread::readOutputParameters()
void AudioFlinger::PlaybackThread::readOutputParameters()
@@ -1194,8 +1167,8 @@ void AudioFlinger::PlaybackThread::readOutputParameters()


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


AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output)
AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id)
    :   PlaybackThread(audioFlinger, output),
    :   PlaybackThread(audioFlinger, output, id),
        mAudioMixer(0)
        mAudioMixer(0)
{
{
    mType = PlaybackThread::MIXER;
    mType = PlaybackThread::MIXER;
@@ -1303,7 +1276,6 @@ bool AudioFlinger::MixerThread::threadLoop()
                }
                }
            } else if (mBytesWritten != 0 ||
            } else if (mBytesWritten != 0 ||
                       (mixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)) {
                       (mixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)) {
                LOGV("NO DATA READY, %p", this);
                memset (curBuf, 0, mixBufferSize);
                memset (curBuf, 0, mixBufferSize);
                sleepTime = 0;
                sleepTime = 0;
                LOGV_IF((mBytesWritten == 0 && (mixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)), "anticipated start");
                LOGV_IF((mBytesWritten == 0 && (mixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)), "anticipated start");
@@ -1639,8 +1611,8 @@ uint32_t AudioFlinger::MixerThread::idleSleepTimeUs()
}
}


// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output)
AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id)
    :   PlaybackThread(audioFlinger, output),
    :   PlaybackThread(audioFlinger, output, id),
    mLeftVolume (1.0), mRightVolume(1.0)
    mLeftVolume (1.0), mRightVolume(1.0)
{
{
    mType = PlaybackThread::DIRECT;
    mType = PlaybackThread::DIRECT;
@@ -1941,8 +1913,8 @@ uint32_t AudioFlinger::DirectOutputThread::idleSleepTimeUs()


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


AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger, AudioFlinger::MixerThread* mainThread)
AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger, AudioFlinger::MixerThread* mainThread, int id)
    :   MixerThread(audioFlinger, mainThread->getOutput())
    :   MixerThread(audioFlinger, mainThread->getOutput(), id)
{
{
    mType = PlaybackThread::DUPLICATING;
    mType = PlaybackThread::DUPLICATING;
    addOutputTrack(mainThread);
    addOutputTrack(mainThread);
@@ -2305,8 +2277,10 @@ AudioFlinger::PlaybackThread::Track::~Track()
    LOGV("PlaybackThread::Track destructor");
    LOGV("PlaybackThread::Track destructor");
    sp<ThreadBase> thread = mThread.promote();
    sp<ThreadBase> thread = mThread.promote();
    if (thread != 0) {
    if (thread != 0) {
        Mutex::Autolock _l(thread->mLock);
        thread->mLock.lock();
        mState = TERMINATED;
        mState = TERMINATED;
        thread->mLock.unlock();
        AudioSystem::releaseOutput(thread->id());
    }
    }
}
}


@@ -2324,6 +2298,9 @@ void AudioFlinger::PlaybackThread::Track::destroy()
    { // scope for mLock
    { // scope for mLock
        sp<ThreadBase> thread = mThread.promote();
        sp<ThreadBase> thread = mThread.promote();
        if (thread != 0) {
        if (thread != 0) {
            if (!isOutputTrack() && (mState == ACTIVE || mState == RESUMING)) {
                AudioSystem::stopOutput(thread->id(), (AudioSystem::stream_type)mStreamType);
            }
            Mutex::Autolock _l(thread->mLock);
            Mutex::Autolock _l(thread->mLock);
            PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
            PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
            playbackThread->destroyTrack_l(this);
            playbackThread->destroyTrack_l(this);
@@ -2405,14 +2382,37 @@ bool AudioFlinger::PlaybackThread::Track::isReady() const {


status_t AudioFlinger::PlaybackThread::Track::start()
status_t AudioFlinger::PlaybackThread::Track::start()
{
{
    status_t status = NO_ERROR;
    LOGV("start(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
    LOGV("start(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
    sp<ThreadBase> thread = mThread.promote();
    sp<ThreadBase> thread = mThread.promote();
    if (thread != 0) {
    if (thread != 0) {
        Mutex::Autolock _l(thread->mLock);
        Mutex::Autolock _l(thread->mLock);
        int state = mState;
        // here the track could be either new, or restarted
        // in both cases "unstop" the track
        if (mState == PAUSED) {
            mState = TrackBase::RESUMING;
            LOGV("PAUSED => RESUMING (%d) on thread %p", mName, this);
        } else {
            mState = TrackBase::ACTIVE;
            LOGV("? => ACTIVE (%d) on thread %p", mName, this);
        }

        if (!isOutputTrack() && state != ACTIVE && state != RESUMING) {
            thread->mLock.unlock();
            status = AudioSystem::startOutput(thread->id(), (AudioSystem::stream_type)mStreamType);
            thread->mLock.lock();
        }
        if (status == NO_ERROR) {
            PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
            PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
            playbackThread->addTrack_l(this);
            playbackThread->addTrack_l(this);
        } else {
            mState = state;
        }
        }
    return NO_ERROR;
    } else {
        status = BAD_VALUE;
    }
    return status;
}
}


void AudioFlinger::PlaybackThread::Track::stop()
void AudioFlinger::PlaybackThread::Track::stop()
@@ -2421,6 +2421,7 @@ void AudioFlinger::PlaybackThread::Track::stop()
    sp<ThreadBase> thread = mThread.promote();
    sp<ThreadBase> thread = mThread.promote();
    if (thread != 0) {
    if (thread != 0) {
        Mutex::Autolock _l(thread->mLock);
        Mutex::Autolock _l(thread->mLock);
        int state = mState;
        if (mState > STOPPED) {
        if (mState > STOPPED) {
            mState = STOPPED;
            mState = STOPPED;
            // If the track is not active (PAUSED and buffers full), flush buffers
            // If the track is not active (PAUSED and buffers full), flush buffers
@@ -2430,6 +2431,11 @@ void AudioFlinger::PlaybackThread::Track::stop()
            }
            }
            LOGV("(> STOPPED) => STOPPED (%d) on thread %p", mName, playbackThread);
            LOGV("(> STOPPED) => STOPPED (%d) on thread %p", mName, playbackThread);
        }
        }
        if (!isOutputTrack() && (state == ACTIVE || state == RESUMING)) {
            thread->mLock.unlock();
            AudioSystem::stopOutput(thread->id(), (AudioSystem::stream_type)mStreamType);
            thread->mLock.lock();
        }
    }
    }
}
}


@@ -2442,6 +2448,11 @@ void AudioFlinger::PlaybackThread::Track::pause()
        if (mState == ACTIVE || mState == RESUMING) {
        if (mState == ACTIVE || mState == RESUMING) {
            mState = PAUSING;
            mState = PAUSING;
            LOGV("ACTIVE/RESUMING => PAUSING (%d) on thread %p", mName, thread.get());
            LOGV("ACTIVE/RESUMING => PAUSING (%d) on thread %p", mName, thread.get());
            if (!isOutputTrack()) {
                thread->mLock.unlock();
                AudioSystem::stopOutput(thread->id(), (AudioSystem::stream_type)mStreamType);
                thread->mLock.lock();
            }
        }
        }
    }
    }
}
}
@@ -2525,6 +2536,10 @@ AudioFlinger::RecordThread::RecordTrack::RecordTrack(


AudioFlinger::RecordThread::RecordTrack::~RecordTrack()
AudioFlinger::RecordThread::RecordTrack::~RecordTrack()
{
{
    sp<ThreadBase> thread = mThread.promote();
    if (thread != 0) {
        AudioSystem::releaseInput(thread->id());
    }
}
}


status_t AudioFlinger::RecordThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
status_t AudioFlinger::RecordThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
@@ -2572,8 +2587,9 @@ status_t AudioFlinger::RecordThread::RecordTrack::start()
    if (thread != 0) {
    if (thread != 0) {
        RecordThread *recordThread = (RecordThread *)thread.get();
        RecordThread *recordThread = (RecordThread *)thread.get();
        return recordThread->start(this);
        return recordThread->start(this);
    } else {
        return BAD_VALUE;
    }
    }
    return NO_INIT;
}
}


void AudioFlinger::RecordThread::RecordTrack::stop()
void AudioFlinger::RecordThread::RecordTrack::stop()
@@ -3010,8 +3026,8 @@ status_t AudioFlinger::RecordHandle::onTransact(


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


AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, AudioStreamIn *input, uint32_t sampleRate, uint32_t channels) :
AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, AudioStreamIn *input, uint32_t sampleRate, uint32_t channels, int id) :
    ThreadBase(audioFlinger),
    ThreadBase(audioFlinger, id),
    mInput(input), mResampler(0), mRsmpOutBuffer(0), mRsmpInBuffer(0)
    mInput(input), mResampler(0), mRsmpOutBuffer(0), mRsmpInBuffer(0)
{
{
    mReqChannelCount = AudioSystem::popCount(channels);
    mReqChannelCount = AudioSystem::popCount(channels);
@@ -3039,6 +3055,7 @@ void AudioFlinger::RecordThread::onFirstRef()


    run(buffer, PRIORITY_URGENT_AUDIO);
    run(buffer, PRIORITY_URGENT_AUDIO);
}
}

bool AudioFlinger::RecordThread::threadLoop()
bool AudioFlinger::RecordThread::threadLoop()
{
{
    AudioBufferProvider::Buffer buffer;
    AudioBufferProvider::Buffer buffer;
@@ -3084,6 +3101,10 @@ bool AudioFlinger::RecordThread::threadLoop()
        }
        }


        if (mActiveTrack != 0) {
        if (mActiveTrack != 0) {
            if (mActiveTrack->mState != TrackBase::ACTIVE) {
                usleep(5000);
                continue;
            }
            buffer.frameCount = mFrameCount;
            buffer.frameCount = mFrameCount;
            if (LIKELY(mActiveTrack->getNextBuffer(&buffer) == NO_ERROR)) {
            if (LIKELY(mActiveTrack->getNextBuffer(&buffer) == NO_ERROR)) {
                size_t framesOut = buffer.frameCount;
                size_t framesOut = buffer.frameCount;
@@ -3181,6 +3202,8 @@ bool AudioFlinger::RecordThread::threadLoop()
    }
    }
    mActiveTrack.clear();
    mActiveTrack.clear();


    mStartStopCond.broadcast();

    LOGV("RecordThread %p exiting", this);
    LOGV("RecordThread %p exiting", this);
    return false;
    return false;
}
}
@@ -3188,37 +3211,71 @@ bool AudioFlinger::RecordThread::threadLoop()
status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrack)
status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrack)
{
{
    LOGV("RecordThread::start");
    LOGV("RecordThread::start");
    sp <ThreadBase> strongMe = this;
    status_t status = NO_ERROR;
    {
        AutoMutex lock(&mLock);
        AutoMutex lock(&mLock);

        if (mActiveTrack != 0) {
        if (mActiveTrack != 0) {
        if (recordTrack != mActiveTrack.get()) return -EBUSY;
            if (recordTrack != mActiveTrack.get()) {

                status = -EBUSY;
        if (mActiveTrack->mState == TrackBase::PAUSING) mActiveTrack->mState = TrackBase::RESUMING;
            } else if (mActiveTrack->mState == TrackBase::PAUSING) {

                mActiveTrack->mState = TrackBase::RESUMING;
        return NO_ERROR;
            }
            return status;
        }
        }


        recordTrack->mState = TrackBase::IDLE;
        mActiveTrack = recordTrack;
        mActiveTrack = recordTrack;
        mLock.unlock();
        status_t status = AudioSystem::startInput(mId);
        mLock.lock();
        if (status != NO_ERROR) {
            mActiveTrack.clear();
            return status;
        }
        mActiveTrack->mState = TrackBase::RESUMING;
        mActiveTrack->mState = TrackBase::RESUMING;
        // signal thread to start
        // signal thread to start
        LOGV("Signal record thread");
        LOGV("Signal record thread");
        mWaitWorkCV.signal();
        mWaitWorkCV.signal();
        // do not wait for mStartStopCond if exiting
        if (mExiting) {
            mActiveTrack.clear();
            status = INVALID_OPERATION;
            goto startError;
        }
        mStartStopCond.wait(mLock);
        mStartStopCond.wait(mLock);
    if (mActiveTrack != 0) {
        if (mActiveTrack == 0) {
        LOGV("Record started OK");
        return NO_ERROR;
    } else {
            LOGV("Record failed to start");
            LOGV("Record failed to start");
        return BAD_VALUE;
            status = BAD_VALUE;
            goto startError;
        }
        }
        LOGV("Record started OK");
        return status;
    }
startError:
    AudioSystem::stopInput(mId);
    return status;
}
}


void AudioFlinger::RecordThread::stop(RecordThread::RecordTrack* recordTrack) {
void AudioFlinger::RecordThread::stop(RecordThread::RecordTrack* recordTrack) {
    LOGV("RecordThread::stop");
    LOGV("RecordThread::stop");
    sp <ThreadBase> strongMe = this;
    {
        AutoMutex lock(&mLock);
        AutoMutex lock(&mLock);
        if (mActiveTrack != 0 && recordTrack == mActiveTrack.get()) {
        if (mActiveTrack != 0 && recordTrack == mActiveTrack.get()) {
            mActiveTrack->mState = TrackBase::PAUSING;
            mActiveTrack->mState = TrackBase::PAUSING;
            // do not wait for mStartStopCond if exiting
            if (mExiting) {
                return;
            }
            mStartStopCond.wait(mLock);
            mStartStopCond.wait(mLock);
            // if we have been restarted, recordTrack == mActiveTrack.get() here
            if (mActiveTrack == 0 || recordTrack != mActiveTrack.get()) {
                mLock.unlock();
                AudioSystem::stopInput(mId);
                mLock.lock();
            }
        }
    }
    }
}
}


@@ -3388,7 +3445,7 @@ void AudioFlinger::RecordThread::audioConfigChanged(int event, int param) {
        break;
        break;
    }
    }
    Mutex::Autolock _l(mAudioFlinger->mLock);
    Mutex::Autolock _l(mAudioFlinger->mLock);
    mAudioFlinger->audioConfigChanged_l(event, this, param2);
    mAudioFlinger->audioConfigChanged_l(event, mId, param2);
}
}


void AudioFlinger::RecordThread::readInputParameters()
void AudioFlinger::RecordThread::readInputParameters()
@@ -3476,13 +3533,13 @@ int AudioFlinger::openOutput(uint32_t *pDevices,
        if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) ||
        if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) ||
            (format != AudioSystem::PCM_16_BIT) ||
            (format != AudioSystem::PCM_16_BIT) ||
            (channels != AudioSystem::CHANNEL_OUT_STEREO)) {
            (channels != AudioSystem::CHANNEL_OUT_STEREO)) {
            thread = new DirectOutputThread(this, output);
            thread = new DirectOutputThread(this, output, ++mNextThreadId);
            LOGV("openOutput() created direct output: ID %d thread %p", (mNextThreadId + 1), thread);
            LOGV("openOutput() created direct output: ID %d thread %p", mNextThreadId, thread);
        } else {
        } else {
            thread = new MixerThread(this, output);
            thread = new MixerThread(this, output, ++mNextThreadId);
            LOGV("openOutput() created mixer output: ID %d thread %p", (mNextThreadId + 1), thread);
            LOGV("openOutput() created mixer output: ID %d thread %p", mNextThreadId, thread);
        }
        }
        mPlaybackThreads.add(++mNextThreadId, thread);
        mPlaybackThreads.add(mNextThreadId, thread);


        if (pSamplingRate) *pSamplingRate = samplingRate;
        if (pSamplingRate) *pSamplingRate = samplingRate;
        if (pFormat) *pFormat = format;
        if (pFormat) *pFormat = format;
@@ -3505,9 +3562,9 @@ int AudioFlinger::openDuplicateOutput(int output1, int output2)
    }
    }




    DuplicatingThread *thread = new DuplicatingThread(this, thread1);
    DuplicatingThread *thread = new DuplicatingThread(this, thread1, ++mNextThreadId);
    thread->addOutputTrack(thread2);
    thread->addOutputTrack(thread2);
    mPlaybackThreads.add(++mNextThreadId, thread);
    mPlaybackThreads.add(mNextThreadId, thread);
    return mNextThreadId;
    return mNextThreadId;
}
}


@@ -3534,7 +3591,7 @@ status_t AudioFlinger::closeOutput(int output)
            }
            }
        }
        }
        void *param2 = 0;
        void *param2 = 0;
        audioConfigChanged_l(AudioSystem::OUTPUT_CLOSED, thread, param2);
        audioConfigChanged_l(AudioSystem::OUTPUT_CLOSED, output, param2);
        mPlaybackThreads.removeItem(output);
        mPlaybackThreads.removeItem(output);
    }
    }
    thread->exit();
    thread->exit();
@@ -3628,8 +3685,8 @@ int AudioFlinger::openInput(uint32_t *pDevices,


    if (input != 0) {
    if (input != 0) {
         // Start record thread
         // Start record thread
        thread = new RecordThread(this, input, reqSamplingRate, reqChannels);
        thread = new RecordThread(this, input, reqSamplingRate, reqChannels, ++mNextThreadId);
        mRecordThreads.add(++mNextThreadId, thread);
        mRecordThreads.add(mNextThreadId, thread);
        LOGV("openInput() created record thread: ID %d thread %p", mNextThreadId, thread);
        LOGV("openInput() created record thread: ID %d thread %p", mNextThreadId, thread);
        if (pSamplingRate) *pSamplingRate = reqSamplingRate;
        if (pSamplingRate) *pSamplingRate = reqSamplingRate;
        if (pFormat) *pFormat = format;
        if (pFormat) *pFormat = format;
@@ -3655,7 +3712,7 @@ status_t AudioFlinger::closeInput(int input)


        LOGV("closeInput() %d", input);
        LOGV("closeInput() %d", input);
        void *param2 = 0;
        void *param2 = 0;
        audioConfigChanged_l(AudioSystem::INPUT_CLOSED, thread, param2);
        audioConfigChanged_l(AudioSystem::INPUT_CLOSED, input, param2);
        mRecordThreads.removeItem(input);
        mRecordThreads.removeItem(input);
    }
    }
    thread->exit();
    thread->exit();
+15 −7
Original line number Original line Diff line number Diff line
@@ -213,7 +213,7 @@ private:


    class ThreadBase : public Thread {
    class ThreadBase : public Thread {
    public:
    public:
        ThreadBase (const sp<AudioFlinger>& audioFlinger);
        ThreadBase (const sp<AudioFlinger>& audioFlinger, int id);
        virtual             ~ThreadBase();
        virtual             ~ThreadBase();


        status_t dumpBase(int fd, const Vector<String16>& args);
        status_t dumpBase(int fd, const Vector<String16>& args);
@@ -323,6 +323,7 @@ private:
                    void        sendConfigEvent(int event, int param = 0);
                    void        sendConfigEvent(int event, int param = 0);
                    void        sendConfigEvent_l(int event, int param = 0);
                    void        sendConfigEvent_l(int event, int param = 0);
                    void        processConfigEvents();
                    void        processConfigEvents();
                    int         id() const { return mId;}


        mutable     Mutex                   mLock;
        mutable     Mutex                   mLock;


@@ -349,6 +350,8 @@ private:
                    status_t                mParamStatus;
                    status_t                mParamStatus;
                    Vector<ConfigEvent *>   mConfigEvents;
                    Vector<ConfigEvent *>   mConfigEvents;
                    bool                    mStandby;
                    bool                    mStandby;
                    int                     mId;
                    bool                    mExiting;
    };
    };


    // --- PlaybackThread ---
    // --- PlaybackThread ---
@@ -421,6 +424,10 @@ private:
            void setPaused() { mState = PAUSED; }
            void setPaused() { mState = PAUSED; }
            void reset();
            void reset();


            bool isOutputTrack() const {
                return (mStreamType == AudioSystem::NUM_STREAM_TYPES);
            }

            // we don't really need a lock for these
            // we don't really need a lock for these
            float               mVolume[2];
            float               mVolume[2];
            volatile bool       mMute;
            volatile bool       mMute;
@@ -473,7 +480,7 @@ private:


        };  // end of OutputTrack
        };  // end of OutputTrack


        PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output);
        PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id);
        virtual             ~PlaybackThread();
        virtual             ~PlaybackThread();


        virtual     status_t    dump(int fd, const Vector<String16>& args);
        virtual     status_t    dump(int fd, const Vector<String16>& args);
@@ -573,7 +580,7 @@ private:


    class MixerThread : public PlaybackThread {
    class MixerThread : public PlaybackThread {
    public:
    public:
        MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output);
        MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id);
        virtual             ~MixerThread();
        virtual             ~MixerThread();


        // Thread virtuals
        // Thread virtuals
@@ -600,7 +607,7 @@ private:
    class DirectOutputThread : public PlaybackThread {
    class DirectOutputThread : public PlaybackThread {
    public:
    public:


        DirectOutputThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output);
        DirectOutputThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id);
        ~DirectOutputThread();
        ~DirectOutputThread();


        // Thread virtuals
        // Thread virtuals
@@ -621,7 +628,7 @@ private:


    class DuplicatingThread : public MixerThread {
    class DuplicatingThread : public MixerThread {
    public:
    public:
        DuplicatingThread (const sp<AudioFlinger>& audioFlinger, MixerThread* mainThread);
        DuplicatingThread (const sp<AudioFlinger>& audioFlinger, MixerThread* mainThread, int id);
        ~DuplicatingThread();
        ~DuplicatingThread();


        // Thread virtuals
        // Thread virtuals
@@ -637,7 +644,7 @@ private:
              MixerThread *checkMixerThread_l(int output) const;
              MixerThread *checkMixerThread_l(int output) const;
              RecordThread *checkRecordThread_l(int input) const;
              RecordThread *checkRecordThread_l(int input) const;
              float streamVolumeInternal(int stream) const { return mStreamTypes[stream].volume; }
              float streamVolumeInternal(int stream) const { return mStreamTypes[stream].volume; }
              void audioConfigChanged_l(int event, const sp<ThreadBase>& thread, void *param2);
              void audioConfigChanged_l(int event, int ioHandle, void *param2);


    friend class AudioBuffer;
    friend class AudioBuffer;


@@ -705,7 +712,8 @@ private:
                RecordThread(const sp<AudioFlinger>& audioFlinger,
                RecordThread(const sp<AudioFlinger>& audioFlinger,
                        AudioStreamIn *input,
                        AudioStreamIn *input,
                        uint32_t sampleRate,
                        uint32_t sampleRate,
                        uint32_t channels);
                        uint32_t channels,
                        int id);
                ~RecordThread();
                ~RecordThread();


        virtual bool        threadLoop();
        virtual bool        threadLoop();