OSDN Git Service

Issue 2265163: Audio still reported routed through earpiece on sholes
authorEric Laurent <elaurent@google.com>
Thu, 19 Nov 2009 17:00:56 +0000 (09:00 -0800)
committerEric Laurent <elaurent@google.com>
Fri, 20 Nov 2009 07:57:45 +0000 (23:57 -0800)
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.

include/media/AudioRecord.h
libs/audioflinger/AudioFlinger.cpp
libs/audioflinger/AudioFlinger.h
media/libmedia/AudioRecord.cpp
media/libmedia/AudioTrack.cpp

index 008468c..622c596 100644 (file)
@@ -268,7 +268,7 @@ public:
      * Returned value:
      *  handle on audio hardware input
      */
-            audio_io_handle_t    getInput() { return mInput; }
+            audio_io_handle_t    getInput();
 
     /* obtains a buffer of "frameCount" frames. The buffer must be
      * filled entirely. If the track is stopped, obtainBuffer() returns
@@ -318,7 +318,8 @@ private:
                                 int format,
                                 int channelCount,
                                 int frameCount,
-                                uint32_t flags);
+                                uint32_t flags,
+                                audio_io_handle_t input);
 
     sp<IAudioRecord>        mAudioRecord;
     sp<IMemory>             mCblkMemory;
@@ -345,8 +346,8 @@ private:
     bool                    mMarkerReached;
     uint32_t                mNewPosition;
     uint32_t                mUpdatePeriod;
-    audio_io_handle_t       mInput;
     uint32_t                mFlags;
+    uint32_t                mChannels;
 };
 
 }; // namespace android
index d918998..daec6e8 100644 (file)
@@ -674,32 +674,13 @@ void AudioFlinger::binderDied(const wp<IBinder>& who) {
 }
 
 // audioConfigChanged_l() must be called with AudioFlinger::mLock held
-void AudioFlinger::audioConfigChanged_l(int event, const sp<ThreadBase>& thread, 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();
-        for (size_t i = 0; i < size; i++) {
-            sp<IBinder> binder = mNotificationClients.itemAt(i);
-            LOGV("audioConfigChanged_l() Notifying change to client %p", binder.get());
-            sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient> (binder);
-            client->ioConfigChanged(event, ioHandle, param2);
-        }
+void AudioFlinger::audioConfigChanged_l(int event, int ioHandle, void *param2) {
+    size_t size = mNotificationClients.size();
+    for (size_t i = 0; i < size; i++) {
+        sp<IBinder> binder = mNotificationClients.itemAt(i);
+        LOGV("audioConfigChanged_l() Notifying change to client %p", binder.get());
+        sp<IAudioFlingerClient> client = interface_cast<IAudioFlingerClient> (binder);
+        client->ioConfigChanged(event, ioHandle, param2);
     }
 }
 
@@ -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),
         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");
     {
         AutoMutex lock(&mLock);
+        mExiting = true;
         requestExit();
         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)
-    :   ThreadBase(audioFlinger),
+AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id)
+    :   ThreadBase(audioFlinger, id),
         mMixBuffer(0), mSuspended(0), mBytesWritten(0), mOutput(output),
         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;
 
-    // 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
     track->mRetryCount = kMaxTrackStartupRetries;
     if (mActiveTracks.indexOf(track) < 0) {
@@ -1173,7 +1146,7 @@ void AudioFlinger::PlaybackThread::audioConfigChanged(int event, int param) {
         break;
     }
     Mutex::Autolock _l(mAudioFlinger->mLock);
-    mAudioFlinger->audioConfigChanged_l(event, this, param2);
+    mAudioFlinger->audioConfigChanged_l(event, mId, param2);
 }
 
 void AudioFlinger::PlaybackThread::readOutputParameters()
@@ -1194,8 +1167,8 @@ void AudioFlinger::PlaybackThread::readOutputParameters()
 
 // ----------------------------------------------------------------------------
 
-AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output)
-    :   PlaybackThread(audioFlinger, output),
+AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id)
+    :   PlaybackThread(audioFlinger, output, id),
         mAudioMixer(0)
 {
     mType = PlaybackThread::MIXER;
@@ -1303,7 +1276,6 @@ bool AudioFlinger::MixerThread::threadLoop()
                 }
             } else if (mBytesWritten != 0 ||
                        (mixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)) {
-                LOGV("NO DATA READY, %p", this);
                 memset (curBuf, 0, mixBufferSize);
                 sleepTime = 0;
                 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)
-    :   PlaybackThread(audioFlinger, output),
+AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id)
+    :   PlaybackThread(audioFlinger, output, id),
     mLeftVolume (1.0), mRightVolume(1.0)
 {
     mType = PlaybackThread::DIRECT;
@@ -1941,8 +1913,8 @@ uint32_t AudioFlinger::DirectOutputThread::idleSleepTimeUs()
 
 // ----------------------------------------------------------------------------
 
-AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger, AudioFlinger::MixerThread* mainThread)
-    :   MixerThread(audioFlinger, mainThread->getOutput())
+AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger, AudioFlinger::MixerThread* mainThread, int id)
+    :   MixerThread(audioFlinger, mainThread->getOutput(), id)
 {
     mType = PlaybackThread::DUPLICATING;
     addOutputTrack(mainThread);
@@ -2305,8 +2277,10 @@ AudioFlinger::PlaybackThread::Track::~Track()
     LOGV("PlaybackThread::Track destructor");
     sp<ThreadBase> thread = mThread.promote();
     if (thread != 0) {
-        Mutex::Autolock _l(thread->mLock);
+        thread->mLock.lock();
         mState = TERMINATED;
+        thread->mLock.unlock();
+        AudioSystem::releaseOutput(thread->id());
     }
 }
 
@@ -2324,6 +2298,9 @@ void AudioFlinger::PlaybackThread::Track::destroy()
     { // scope for mLock
         sp<ThreadBase> thread = mThread.promote();
         if (thread != 0) {
+            if (!isOutputTrack() && (mState == ACTIVE || mState == RESUMING)) {
+                AudioSystem::stopOutput(thread->id(), (AudioSystem::stream_type)mStreamType);
+            }
             Mutex::Autolock _l(thread->mLock);
             PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
             playbackThread->destroyTrack_l(this);
@@ -2405,14 +2382,37 @@ bool AudioFlinger::PlaybackThread::Track::isReady() const {
 
 status_t AudioFlinger::PlaybackThread::Track::start()
 {
+    status_t status = NO_ERROR;
     LOGV("start(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
     sp<ThreadBase> thread = mThread.promote();
     if (thread != 0) {
         Mutex::Autolock _l(thread->mLock);
-        PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
-        playbackThread->addTrack_l(this);
+        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->addTrack_l(this);
+        } else {
+            mState = state;
+        }
+    } else {
+        status = BAD_VALUE;
     }
-    return NO_ERROR;
+    return status;
 }
 
 void AudioFlinger::PlaybackThread::Track::stop()
@@ -2421,6 +2421,7 @@ void AudioFlinger::PlaybackThread::Track::stop()
     sp<ThreadBase> thread = mThread.promote();
     if (thread != 0) {
         Mutex::Autolock _l(thread->mLock);
+        int state = mState;
         if (mState > STOPPED) {
             mState = STOPPED;
             // 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);
         }
+        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) {
             mState = PAUSING;
             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()
 {
+    sp<ThreadBase> thread = mThread.promote();
+    if (thread != 0) {
+        AudioSystem::releaseInput(thread->id());
+    }
 }
 
 status_t AudioFlinger::RecordThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
@@ -2572,8 +2587,9 @@ status_t AudioFlinger::RecordThread::RecordTrack::start()
     if (thread != 0) {
         RecordThread *recordThread = (RecordThread *)thread.get();
         return recordThread->start(this);
+    } else {
+        return BAD_VALUE;
     }
-    return NO_INIT;
 }
 
 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) :
-    ThreadBase(audioFlinger),
+AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, AudioStreamIn *input, uint32_t sampleRate, uint32_t channels, int id) :
+    ThreadBase(audioFlinger, id),
     mInput(input), mResampler(0), mRsmpOutBuffer(0), mRsmpInBuffer(0)
 {
     mReqChannelCount = AudioSystem::popCount(channels);
@@ -3039,6 +3055,7 @@ void AudioFlinger::RecordThread::onFirstRef()
 
     run(buffer, PRIORITY_URGENT_AUDIO);
 }
+
 bool AudioFlinger::RecordThread::threadLoop()
 {
     AudioBufferProvider::Buffer buffer;
@@ -3084,6 +3101,10 @@ bool AudioFlinger::RecordThread::threadLoop()
         }
 
         if (mActiveTrack != 0) {
+            if (mActiveTrack->mState != TrackBase::ACTIVE) {
+                usleep(5000);
+                continue;
+            }
             buffer.frameCount = mFrameCount;
             if (LIKELY(mActiveTrack->getNextBuffer(&buffer) == NO_ERROR)) {
                 size_t framesOut = buffer.frameCount;
@@ -3181,6 +3202,8 @@ bool AudioFlinger::RecordThread::threadLoop()
     }
     mActiveTrack.clear();
 
+    mStartStopCond.broadcast();
+
     LOGV("RecordThread %p exiting", this);
     return false;
 }
@@ -3188,37 +3211,71 @@ bool AudioFlinger::RecordThread::threadLoop()
 status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrack)
 {
     LOGV("RecordThread::start");
-    AutoMutex lock(&mLock);
-
-    if (mActiveTrack != 0) {
-        if (recordTrack != mActiveTrack.get()) return -EBUSY;
-
-        if (mActiveTrack->mState == TrackBase::PAUSING) mActiveTrack->mState = TrackBase::RESUMING;
-
-        return NO_ERROR;
-    }
+    sp <ThreadBase> strongMe = this;
+    status_t status = NO_ERROR;
+    {
+        AutoMutex lock(&mLock);
+        if (mActiveTrack != 0) {
+            if (recordTrack != mActiveTrack.get()) {
+                status = -EBUSY;
+            } else if (mActiveTrack->mState == TrackBase::PAUSING) {
+                mActiveTrack->mState = TrackBase::RESUMING;
+            }
+            return status;
+        }
 
-    mActiveTrack = recordTrack;
-    mActiveTrack->mState = TrackBase::RESUMING;
-    // signal thread to start
-    LOGV("Signal record thread");
-    mWaitWorkCV.signal();
-    mStartStopCond.wait(mLock);
-    if (mActiveTrack != 0) {
+        recordTrack->mState = TrackBase::IDLE;
+        mActiveTrack = recordTrack;
+        mLock.unlock();
+        status_t status = AudioSystem::startInput(mId);
+        mLock.lock();
+        if (status != NO_ERROR) {
+            mActiveTrack.clear();
+            return status;
+        }
+        mActiveTrack->mState = TrackBase::RESUMING;
+        // signal thread to start
+        LOGV("Signal record thread");
+        mWaitWorkCV.signal();
+        // do not wait for mStartStopCond if exiting
+        if (mExiting) {
+            mActiveTrack.clear();
+            status = INVALID_OPERATION;
+            goto startError;
+        }
+        mStartStopCond.wait(mLock);
+        if (mActiveTrack == 0) {
+            LOGV("Record failed to start");
+            status = BAD_VALUE;
+            goto startError;
+        }
         LOGV("Record started OK");
-        return NO_ERROR;
-    } else {
-        LOGV("Record failed to start");
-        return BAD_VALUE;
+        return status;
     }
+startError:
+    AudioSystem::stopInput(mId);
+    return status;
 }
 
 void AudioFlinger::RecordThread::stop(RecordThread::RecordTrack* recordTrack) {
     LOGV("RecordThread::stop");
-    AutoMutex lock(&mLock);
-    if (mActiveTrack != 0 && recordTrack == mActiveTrack.get()) {
-        mActiveTrack->mState = TrackBase::PAUSING;
-        mStartStopCond.wait(mLock);
+    sp <ThreadBase> strongMe = this;
+    {
+        AutoMutex lock(&mLock);
+        if (mActiveTrack != 0 && recordTrack == mActiveTrack.get()) {
+            mActiveTrack->mState = TrackBase::PAUSING;
+            // do not wait for mStartStopCond if exiting
+            if (mExiting) {
+                return;
+            }
+            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;
     }
     Mutex::Autolock _l(mAudioFlinger->mLock);
-    mAudioFlinger->audioConfigChanged_l(event, this, param2);
+    mAudioFlinger->audioConfigChanged_l(event, mId, param2);
 }
 
 void AudioFlinger::RecordThread::readInputParameters()
@@ -3476,13 +3533,13 @@ int AudioFlinger::openOutput(uint32_t *pDevices,
         if ((flags & AudioSystem::OUTPUT_FLAG_DIRECT) ||
             (format != AudioSystem::PCM_16_BIT) ||
             (channels != AudioSystem::CHANNEL_OUT_STEREO)) {
-            thread = new DirectOutputThread(this, output);
-            LOGV("openOutput() created direct output: ID %d thread %p", (mNextThreadId + 1), thread);
+            thread = new DirectOutputThread(this, output, ++mNextThreadId);
+            LOGV("openOutput() created direct output: ID %d thread %p", mNextThreadId, thread);
         } else {
-            thread = new MixerThread(this, output);
-            LOGV("openOutput() created mixer output: ID %d thread %p", (mNextThreadId + 1), thread);
+            thread = new MixerThread(this, output, ++mNextThreadId);
+            LOGV("openOutput() created mixer output: ID %d thread %p", mNextThreadId, thread);
         }
-        mPlaybackThreads.add(++mNextThreadId, thread);
+        mPlaybackThreads.add(mNextThreadId, thread);
 
         if (pSamplingRate) *pSamplingRate = samplingRate;
         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);
-    mPlaybackThreads.add(++mNextThreadId, thread);
+    mPlaybackThreads.add(mNextThreadId, thread);
     return mNextThreadId;
 }
 
@@ -3534,7 +3591,7 @@ status_t AudioFlinger::closeOutput(int output)
             }
         }
         void *param2 = 0;
-        audioConfigChanged_l(AudioSystem::OUTPUT_CLOSED, thread, param2);
+        audioConfigChanged_l(AudioSystem::OUTPUT_CLOSED, output, param2);
         mPlaybackThreads.removeItem(output);
     }
     thread->exit();
@@ -3628,8 +3685,8 @@ int AudioFlinger::openInput(uint32_t *pDevices,
 
     if (input != 0) {
          // Start record thread
-        thread = new RecordThread(this, input, reqSamplingRate, reqChannels);
-        mRecordThreads.add(++mNextThreadId, thread);
+        thread = new RecordThread(this, input, reqSamplingRate, reqChannels, ++mNextThreadId);
+        mRecordThreads.add(mNextThreadId, thread);
         LOGV("openInput() created record thread: ID %d thread %p", mNextThreadId, thread);
         if (pSamplingRate) *pSamplingRate = reqSamplingRate;
         if (pFormat) *pFormat = format;
@@ -3655,7 +3712,7 @@ status_t AudioFlinger::closeInput(int input)
 
         LOGV("closeInput() %d", input);
         void *param2 = 0;
-        audioConfigChanged_l(AudioSystem::INPUT_CLOSED, thread, param2);
+        audioConfigChanged_l(AudioSystem::INPUT_CLOSED, input, param2);
         mRecordThreads.removeItem(input);
     }
     thread->exit();
index 594d878..5a17294 100644 (file)
@@ -213,7 +213,7 @@ private:
 
     class ThreadBase : public Thread {
     public:
-        ThreadBase (const sp<AudioFlinger>& audioFlinger);
+        ThreadBase (const sp<AudioFlinger>& audioFlinger, int id);
         virtual             ~ThreadBase();
 
         status_t dumpBase(int fd, const Vector<String16>& args);
@@ -323,6 +323,7 @@ private:
                     void        sendConfigEvent(int event, int param = 0);
                     void        sendConfigEvent_l(int event, int param = 0);
                     void        processConfigEvents();
+                    int         id() const { return mId;}
 
         mutable     Mutex                   mLock;
 
@@ -349,6 +350,8 @@ private:
                     status_t                mParamStatus;
                     Vector<ConfigEvent *>   mConfigEvents;
                     bool                    mStandby;
+                    int                     mId;
+                    bool                    mExiting;
     };
 
     // --- PlaybackThread ---
@@ -421,6 +424,10 @@ private:
             void setPaused() { mState = PAUSED; }
             void reset();
 
+            bool isOutputTrack() const {
+                return (mStreamType == AudioSystem::NUM_STREAM_TYPES);
+            }
+
             // we don't really need a lock for these
             float               mVolume[2];
             volatile bool       mMute;
@@ -473,7 +480,7 @@ private:
 
         };  // end of OutputTrack
 
-        PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output);
+        PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id);
         virtual             ~PlaybackThread();
 
         virtual     status_t    dump(int fd, const Vector<String16>& args);
@@ -573,7 +580,7 @@ private:
 
     class MixerThread : public PlaybackThread {
     public:
-        MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output);
+        MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id);
         virtual             ~MixerThread();
 
         // Thread virtuals
@@ -600,7 +607,7 @@ private:
     class DirectOutputThread : public PlaybackThread {
     public:
 
-        DirectOutputThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output);
+        DirectOutputThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id);
         ~DirectOutputThread();
 
         // Thread virtuals
@@ -621,7 +628,7 @@ private:
 
     class DuplicatingThread : public MixerThread {
     public:
-        DuplicatingThread (const sp<AudioFlinger>& audioFlinger, MixerThread* mainThread);
+        DuplicatingThread (const sp<AudioFlinger>& audioFlinger, MixerThread* mainThread, int id);
         ~DuplicatingThread();
 
         // Thread virtuals
@@ -637,7 +644,7 @@ private:
               MixerThread *checkMixerThread_l(int output) const;
               RecordThread *checkRecordThread_l(int input) const;
               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;
 
@@ -705,7 +712,8 @@ private:
                 RecordThread(const sp<AudioFlinger>& audioFlinger,
                         AudioStreamIn *input,
                         uint32_t sampleRate,
-                        uint32_t channels);
+                        uint32_t channels,
+                        int id);
                 ~RecordThread();
 
         virtual bool        threadLoop();
index e63c0d2..c3828f0 100644 (file)
@@ -46,7 +46,7 @@ namespace android {
 // ---------------------------------------------------------------------------
 
 AudioRecord::AudioRecord()
-    : mStatus(NO_INIT), mInput(0)
+    : mStatus(NO_INIT)
 {
 }
 
@@ -60,7 +60,7 @@ AudioRecord::AudioRecord(
         callback_t cbf,
         void* user,
         int notificationFrames)
-    : mStatus(NO_INIT), mInput(0)
+    : mStatus(NO_INIT)
 {
     mStatus = set(inputSource, sampleRate, format, channels,
             frameCount, flags, cbf, user, notificationFrames);
@@ -79,7 +79,6 @@ AudioRecord::~AudioRecord()
         }
         mAudioRecord.clear();
         IPCThreadState::self()->flushCommands();
-        AudioSystem::releaseInput(mInput);
     }
 }
 
@@ -123,9 +122,9 @@ status_t AudioRecord::set(
     }
     int channelCount = AudioSystem::popCount(channels);
 
-    mInput = AudioSystem::getInput(inputSource,
+    audio_io_handle_t input = AudioSystem::getInput(inputSource,
                                     sampleRate, format, channels, (AudioSystem::audio_in_acoustics)flags);
-    if (mInput == 0) {
+    if (input == 0) {
         LOGE("Could not get audio output for stream type %d", inputSource);
         return BAD_VALUE;
     }
@@ -168,7 +167,7 @@ status_t AudioRecord::set(
 
     // create the IAudioRecord
     status_t status = openRecord(sampleRate, format, channelCount,
-                                 frameCount, flags);
+                                 frameCount, flags, input);
 
     if (status != NO_ERROR) {
         return status;
@@ -187,6 +186,7 @@ status_t AudioRecord::set(
     // Update buffer size in case it has been limited by AudioFlinger during track creation
     mFrameCount = mCblk->frameCount;
     mChannelCount = (uint8_t)channelCount;
+    mChannels = channels;
     mActive = 0;
     mCbf = cbf;
     mNotificationFrames = notificationFrames;
@@ -265,28 +265,27 @@ status_t AudioRecord::start()
      }
 
     if (android_atomic_or(1, &mActive) == 0) {
-        ret = AudioSystem::startInput(mInput);
-        if (ret == NO_ERROR) {
-            ret = mAudioRecord->start();
-            if (ret == DEAD_OBJECT) {
-                LOGV("start() dead IAudioRecord: creating a new one");
-                ret = openRecord(mCblk->sampleRate, mFormat, mChannelCount,
-                        mFrameCount, mFlags);
-            }
+        ret = mAudioRecord->start();
+        if (ret == DEAD_OBJECT) {
+            LOGV("start() dead IAudioRecord: creating a new one");
+            ret = openRecord(mCblk->sampleRate, mFormat, mChannelCount,
+                    mFrameCount, mFlags, getInput());
             if (ret == NO_ERROR) {
-                mNewPosition = mCblk->user + mUpdatePeriod;
-                mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
-                mCblk->waitTimeMs = 0;
-                if (t != 0) {
-                   t->run("ClientRecordThread", THREAD_PRIORITY_AUDIO_CLIENT);
-                } else {
-                    setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
-                }
+                ret = mAudioRecord->start();
+            }
+        }
+        if (ret == NO_ERROR) {
+            mNewPosition = mCblk->user + mUpdatePeriod;
+            mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
+            mCblk->waitTimeMs = 0;
+            if (t != 0) {
+               t->run("ClientRecordThread", THREAD_PRIORITY_AUDIO_CLIENT);
             } else {
-                LOGV("start() failed");
-                AudioSystem::stopInput(mInput);
-                android_atomic_and(~1, &mActive);
+                setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
             }
+        } else {
+            LOGV("start() failed");
+            android_atomic_and(~1, &mActive);
         }
     }
 
@@ -318,7 +317,6 @@ status_t AudioRecord::stop()
         } else {
             setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
         }
-        AudioSystem::stopInput(mInput);
     }
 
     if (t != 0) {
@@ -395,7 +393,8 @@ status_t AudioRecord::openRecord(
         int format,
         int channelCount,
         int frameCount,
-        uint32_t flags)
+        uint32_t flags,
+        audio_io_handle_t input)
 {
     status_t status;
     const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
@@ -403,7 +402,7 @@ status_t AudioRecord::openRecord(
         return NO_INIT;
     }
 
-    sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), mInput,
+    sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), input,
                                                        sampleRate, format,
                                                        channelCount,
                                                        frameCount,
@@ -425,7 +424,8 @@ status_t AudioRecord::openRecord(
     mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer());
     mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t);
     mCblk->out = 0;
-
+    mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
+    mCblk->waitTimeMs = 0;
     return NO_ERROR;
 }
 
@@ -466,10 +466,10 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
                     if (result == DEAD_OBJECT) {
                         LOGW("obtainBuffer() dead IAudioRecord: creating a new one");
                         result = openRecord(cblk->sampleRate, mFormat, mChannelCount,
-                                            mFrameCount, mFlags);
+                                            mFrameCount, mFlags, getInput());
                         if (result == NO_ERROR) {
                             cblk = mCblk;
-                            cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
+                            mAudioRecord->start();
                         }
                     }
                     cblk->lock.lock();
@@ -516,6 +516,14 @@ void AudioRecord::releaseBuffer(Buffer* audioBuffer)
     cblk->stepUser(audioBuffer->frameCount);
 }
 
+audio_io_handle_t AudioRecord::getInput()
+{
+   return AudioSystem::getInput(mInputSource,
+                                mCblk->sampleRate,
+                                mFormat, mChannels,
+                                (AudioSystem::audio_in_acoustics)mFlags);
+}
+
 // -------------------------------------------------------------------------
 
 ssize_t AudioRecord::read(void* buffer, size_t userSize)
index cedd79d..ad0f42e 100644 (file)
@@ -97,7 +97,6 @@ AudioTrack::~AudioTrack()
         }
         mAudioTrack.clear();
         IPCThreadState::self()->flushCommands();
-        AudioSystem::releaseOutput(getOutput());
     }
 }
 
@@ -318,8 +317,6 @@ void AudioTrack::start()
      }
 
     if (android_atomic_or(1, &mActive) == 0) {
-        audio_io_handle_t output = getOutput();
-        AudioSystem::startOutput(output, (AudioSystem::stream_type)mStreamType);
         mNewPosition = mCblk->server + mUpdatePeriod;
         mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
         mCblk->waitTimeMs = 0;
@@ -333,10 +330,13 @@ void AudioTrack::start()
         if (status == DEAD_OBJECT) {
             LOGV("start() dead IAudioTrack: creating a new one");
             status = createTrack(mStreamType, mCblk->sampleRate, mFormat, mChannelCount,
-                                 mFrameCount, mFlags, mSharedBuffer, output);
-            mNewPosition = mCblk->server + mUpdatePeriod;
-            mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
-            mCblk->waitTimeMs = 0;
+                                 mFrameCount, mFlags, mSharedBuffer, getOutput());
+            if (status == NO_ERROR) {
+                status = mAudioTrack->start();
+                if (status == NO_ERROR) {
+                    mNewPosition = mCblk->server + mUpdatePeriod;
+                }
+            }
         }
         if (status != NO_ERROR) {
             LOGV("start() failed");
@@ -346,7 +346,6 @@ void AudioTrack::start()
             } else {
                 setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
             }
-            AudioSystem::stopOutput(output, (AudioSystem::stream_type)mStreamType);
         }
     }
 
@@ -383,7 +382,6 @@ void AudioTrack::stop()
         } else {
             setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
         }
-        AudioSystem::stopOutput(getOutput(), (AudioSystem::stream_type)mStreamType);
     }
 
     if (t != 0) {
@@ -418,9 +416,7 @@ void AudioTrack::pause()
 {
     LOGV("pause");
     if (android_atomic_and(~1, &mActive) == 1) {
-        mActive = 0;
         mAudioTrack->pause();
-        AudioSystem::stopOutput(getOutput(), (AudioSystem::stream_type)mStreamType);
     }
 }
 
@@ -658,7 +654,8 @@ status_t AudioTrack::createTrack(
     }
 
     mCblk->volumeLR = (int32_t(int16_t(mVolume[LEFT] * 0x1000)) << 16) | int16_t(mVolume[RIGHT] * 0x1000);
-
+    mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
+    mCblk->waitTimeMs = 0;
     return NO_ERROR;
 }
 
@@ -709,6 +706,7 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
                             if (result == NO_ERROR) {
                                 cblk = mCblk;
                                 cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
+                                mAudioTrack->start();
                             }
                         }
                         cblk->lock.lock();