diff options
author | Glenn Kasten <gkasten@google.com> | 2012-08-01 09:48:26 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2012-08-01 09:48:27 -0700 |
commit | 5665fde6d4520c8e6cec81a4e1e9c86f1537f689 (patch) | |
tree | 774c48425035787b816a743cefd39ba86d1a2145 /services | |
parent | 428b77a2b94b74665a47375b3fdb893b98d71269 (diff) | |
parent | 510a3d6b8018a77683dac466127ffd0af34bef6e (diff) | |
download | frameworks_av-5665fde6d4520c8e6cec81a4e1e9c86f1537f689.zip frameworks_av-5665fde6d4520c8e6cec81a4e1e9c86f1537f689.tar.gz frameworks_av-5665fde6d4520c8e6cec81a4e1e9c86f1537f689.tar.bz2 |
Merge "Start adding support for multiple record tracks" into jb-mr1-dev
Diffstat (limited to 'services')
-rw-r--r-- | services/audioflinger/AudioFlinger.cpp | 160 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.h | 20 |
2 files changed, 141 insertions, 39 deletions
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index fe9d09d..a921ad6 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -868,16 +868,19 @@ status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8& if (mBtNrecIsOff != btNrecIsOff) { for (size_t i = 0; i < mRecordThreads.size(); i++) { sp<RecordThread> thread = mRecordThreads.valueAt(i); - RecordThread::RecordTrack *track = thread->track(); - if (track != NULL) { - audio_devices_t device = thread->device() & AUDIO_DEVICE_IN_ALL; - bool suspend = audio_is_bluetooth_sco_device(device) && btNrecIsOff; + audio_devices_t device = thread->device() & AUDIO_DEVICE_IN_ALL; + bool suspend = audio_is_bluetooth_sco_device(device) && btNrecIsOff; + // collect all of the thread's session IDs + KeyedVector<int, bool> ids = thread->sessionIds(); + // suspend effects associated with those session IDs + for (size_t j = 0; j < ids.size(); ++j) { + int sessionId = ids.keyAt(j); thread->setEffectSuspended(FX_IID_AEC, suspend, - track->sessionId()); + sessionId); thread->setEffectSuspended(FX_IID_NS, suspend, - track->sessionId()); + sessionId); } } mBtNrecIsOff = btNrecIsOff; @@ -4277,11 +4280,6 @@ AudioFlinger::PlaybackThread::Track::Track( AudioFlinger::PlaybackThread::Track::~Track() { ALOGV("PlaybackThread::Track destructor"); - sp<ThreadBase> thread = mThread.promote(); - if (thread != 0) { - Mutex::Autolock _l(thread->mLock); - mState = TERMINATED; - } } void AudioFlinger::PlaybackThread::Track::destroy() @@ -5301,10 +5299,7 @@ AudioFlinger::RecordThread::RecordTrack::RecordTrack( AudioFlinger::RecordThread::RecordTrack::~RecordTrack() { - sp<ThreadBase> thread = mThread.promote(); - if (thread != 0) { - AudioSystem::releaseInput(thread->id()); - } + ALOGV("%s", __func__); } // AudioBufferProvider interface @@ -5377,6 +5372,11 @@ void AudioFlinger::RecordThread::RecordTrack::stop() } } +/*static*/ void AudioFlinger::RecordThread::RecordTrack::appendDumpHeader(String8& result) +{ + result.append(" Clien Fmt Chn mask Session Buf S SRate Serv User\n"); +} + void AudioFlinger::RecordThread::RecordTrack::dump(char* buffer, size_t size) { snprintf(buffer, size, " %05d %03u 0x%08x %05d %04u %01d %05u %08x %08x\n", @@ -5861,6 +5861,7 @@ AudioFlinger::RecordHandle::RecordHandle(const sp<AudioFlinger::RecordThread::Re AudioFlinger::RecordHandle::~RecordHandle() { stop_nonvirtual(); + mRecordTrack->destroy(); } sp<IMemory> AudioFlinger::RecordHandle::getCblk() const { @@ -5896,7 +5897,7 @@ AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id, audio_devices_t device) : ThreadBase(audioFlinger, id, device, RECORD), - mInput(input), mTrack(NULL), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpInBuffer(NULL), + mInput(input), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpInBuffer(NULL), // mRsmpInIndex and mInputBytes set by readInputParameters() mReqChannelCount(popcount(channelMask)), mReqSampleRate(sampleRate) @@ -5980,6 +5981,9 @@ bool AudioFlinger::RecordThread::threadLoop() mStartStopCond.broadcast(); } mStandby = false; + } else if (mActiveTrack->mState == TrackBase::TERMINATED) { + removeTrack_l(mActiveTrack); + mActiveTrack.clear(); } } lockEffectChains_l(effectChains); @@ -6168,8 +6172,8 @@ sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createR lStatus = NO_MEMORY; goto Exit; } + mTracks.add(track); - mTrack = track.get(); // disable AEC and NS if the device is a BT SCO headset supporting those pre processings bool suspend = audio_is_bluetooth_sco_device(mDevice & AUDIO_DEVICE_IN_ALL) && mAudioFlinger->btNrecIsOff(); @@ -6320,17 +6324,64 @@ status_t AudioFlinger::RecordThread::setSyncEvent(const sp<SyncEvent>& event) return BAD_VALUE; } + int eventSession = event->triggerSession(); + status_t ret = NAME_NOT_FOUND; + Mutex::Autolock _l(mLock); - if (mTrack != NULL && event->triggerSession() == mTrack->sessionId()) { - mTrack->setSyncEvent(event); - return NO_ERROR; + for (size_t i = 0; i < mTracks.size(); i++) { + sp<RecordTrack> track = mTracks[i]; + if (eventSession == track->sessionId()) { + track->setSyncEvent(event); + ret = NO_ERROR; + } + } + return ret; +} + +void AudioFlinger::RecordThread::RecordTrack::destroy() +{ + // see comments at AudioFlinger::PlaybackThread::Track::destroy() + sp<RecordTrack> keep(this); + { + sp<ThreadBase> thread = mThread.promote(); + if (thread != 0) { + if (mState == ACTIVE || mState == RESUMING) { + AudioSystem::stopInput(thread->id()); + } + AudioSystem::releaseInput(thread->id()); + Mutex::Autolock _l(thread->mLock); + RecordThread *recordThread = (RecordThread *) thread.get(); + recordThread->destroyTrack_l(this); + } } - return NAME_NOT_FOUND; +} + +// destroyTrack_l() must be called with ThreadBase::mLock held +void AudioFlinger::RecordThread::destroyTrack_l(const sp<RecordTrack>& track) +{ + track->mState = TrackBase::TERMINATED; + // active tracks are removed by threadLoop() + if (mActiveTrack != track) { + removeTrack_l(track); + } +} + +void AudioFlinger::RecordThread::removeTrack_l(const sp<RecordTrack>& track) +{ + mTracks.remove(track); + // need anything related to effects here? } void AudioFlinger::RecordThread::dump(int fd, const Vector<String16>& args) { + dumpInternals(fd, args); + dumpTracks(fd, args); + dumpEffectChains(fd, args); +} + +void AudioFlinger::RecordThread::dumpInternals(int fd, const Vector<String16>& args) +{ const size_t SIZE = 256; char buffer[SIZE]; String8 result; @@ -6339,11 +6390,6 @@ void AudioFlinger::RecordThread::dump(int fd, const Vector<String16>& args) result.append(buffer); if (mActiveTrack != 0) { - result.append("Active Track:\n"); - result.append(" Clien Fmt Chn mask Session Buf S SRate Serv User\n"); - mActiveTrack->dump(buffer, SIZE); - result.append(buffer); - snprintf(buffer, SIZE, "In index: %d\n", mRsmpInIndex); result.append(buffer); snprintf(buffer, SIZE, "In size: %d\n", mInputBytes); @@ -6354,15 +6400,41 @@ void AudioFlinger::RecordThread::dump(int fd, const Vector<String16>& args) result.append(buffer); snprintf(buffer, SIZE, "Out sample rate: %d\n", mReqSampleRate); result.append(buffer); - - } else { - result.append("No record client\n"); + result.append("No active record client\n"); } + write(fd, result.string(), result.size()); dumpBase(fd, args); - dumpEffectChains(fd, args); +} + +void AudioFlinger::RecordThread::dumpTracks(int fd, const Vector<String16>& args) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + + snprintf(buffer, SIZE, "Input thread %p tracks\n", this); + result.append(buffer); + RecordTrack::appendDumpHeader(result); + for (size_t i = 0; i < mTracks.size(); ++i) { + sp<RecordTrack> track = mTracks[i]; + if (track != 0) { + track->dump(buffer, SIZE); + result.append(buffer); + } + } + + if (mActiveTrack != 0) { + snprintf(buffer, SIZE, "\nInput thread %p active tracks\n", this); + result.append(buffer); + RecordTrack::appendDumpHeader(result); + mActiveTrack->dump(buffer, SIZE); + result.append(buffer); + + } + write(fd, result.string(), result.size()); } // AudioBufferProvider interface @@ -6462,11 +6534,14 @@ bool AudioFlinger::RecordThread::checkForNewParameters_l() } else { newDevice &= ~(value & AUDIO_DEVICE_IN_ALL); // disable AEC and NS if the device is a BT SCO headset supporting those pre processings - if (mTrack != NULL) { + if (mTracks.size() > 0) { bool suspend = audio_is_bluetooth_sco_device( (audio_devices_t)value) && mAudioFlinger->btNrecIsOff(); - setEffectSuspended_l(FX_IID_AEC, suspend, mTrack->sessionId()); - setEffectSuspended_l(FX_IID_NS, suspend, mTrack->sessionId()); + for (size_t i = 0; i < mTracks.size(); i++) { + sp<RecordTrack> track = mTracks[i]; + setEffectSuspended_l(FX_IID_AEC, suspend, track->sessionId()); + setEffectSuspended_l(FX_IID_NS, suspend, track->sessionId()); + } } } newDevice |= value; @@ -6605,17 +6680,28 @@ uint32_t AudioFlinger::RecordThread::hasAudioSession(int sessionId) result = EFFECT_SESSION; } - if (mTrack != NULL && sessionId == mTrack->sessionId()) { - result |= TRACK_SESSION; + for (size_t i = 0; i < mTracks.size(); ++i) { + if (sessionId == mTracks[i]->sessionId()) { + result |= TRACK_SESSION; + break; + } } return result; } -AudioFlinger::RecordThread::RecordTrack* AudioFlinger::RecordThread::track() +KeyedVector<int, bool> AudioFlinger::RecordThread::sessionIds() { + KeyedVector<int, bool> ids; Mutex::Autolock _l(mLock); - return mTrack; + for (size_t j = 0; j < mTracks.size(); ++j) { + sp<RecordThread::RecordTrack> track = mTracks[j]; + int sessionId = track->sessionId(); + if (ids.indexOfKey(sessionId) < 0) { + ids.add(sessionId, true); + } + } + return ids; } AudioFlinger::AudioStreamIn* AudioFlinger::RecordThread::clearInput() diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index e629533..2b6d00f 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -1381,11 +1381,14 @@ private: virtual status_t start(AudioSystem::sync_event_t event, int triggerSession); virtual void stop(); + void destroy(); + // clear the buffer overflow flag void clearOverflow() { mOverflow = false; } // set the buffer overflow flag and return previous value bool setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; } + static void appendDumpHeader(String8& result); void dump(char* buffer, size_t size); private: @@ -1409,6 +1412,13 @@ private: audio_devices_t device); virtual ~RecordThread(); + // no addTrack_l ? + void destroyTrack_l(const sp<RecordTrack>& track); + void removeTrack_l(const sp<RecordTrack>& track); + + void dumpInternals(int fd, const Vector<String16>& args); + void dumpTracks(int fd, const Vector<String16>& args); + // Thread virtual bool threadLoop(); virtual status_t readyToRun(); @@ -1453,7 +1463,11 @@ private: virtual status_t addEffectChain_l(const sp<EffectChain>& chain); virtual size_t removeEffectChain_l(const sp<EffectChain>& chain); virtual uint32_t hasAudioSession(int sessionId); - RecordTrack* track(); + + // Return the set of unique session IDs across all tracks. + // The keys are the session IDs, and the associated values are meaningless. + // FIXME replace by Set [and implement Bag/Multiset for other uses]. + KeyedVector<int, bool> sessionIds(); virtual status_t setSyncEvent(const sp<SyncEvent>& event); virtual bool isValidSyncEvent(const sp<SyncEvent>& event); @@ -1471,7 +1485,9 @@ private: void inputStandBy(); AudioStreamIn *mInput; - RecordTrack* mTrack; + SortedVector < sp<RecordTrack> > mTracks; + // mActiveTrack has dual roles: it indicates the current active track, and + // is used together with mStartStopCond to indicate start()/stop() progress sp<RecordTrack> mActiveTrack; Condition mStartStopCond; AudioResampler *mResampler; |