From 296fb13dd9b5e90d6a05cce897c3b1e7914a478a Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 1 May 2015 11:38:42 -0700 Subject: Implement audio device callback Add class AudioSystem::AudioDeviceCallback notifying AudioSystem clients upon device selection change on a given input or output thread. Maintain a list of installed callback per I/O handle in AudioSystem and call registered callbacks when an OPEN of CONFIG_CHANGED event is received on IAudioFlingerClient::ioConfigChanged(). Add methods to AudioTrack and AudioRecord to add and remove device change callbacks. Add methods to AudioTrack and AudioRecord to query currently selected device. ioConfigChanged() events now convey the audio patch describing the input or output thread routing. Fix AudioRecord failure to start when invalidation is handled by start(). Change-Id: I9e938adf025fa712337c63b1e02a8c18f2a20d39 --- media/libmedia/AudioRecord.cpp | 71 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) (limited to 'media/libmedia/AudioRecord.cpp') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 23015c0..73fd3cb 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -112,6 +112,10 @@ AudioRecord::~AudioRecord() mAudioRecordThread->requestExitAndWait(); mAudioRecordThread.clear(); } + // No lock here: worst case we remove a NULL callback which will be a nop + if (mDeviceCallback != 0 && mInput != AUDIO_IO_HANDLE_NONE) { + AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput); + } IInterface::asBinder(mAudioRecord)->unlinkToDeath(mDeathNotifier, this); mAudioRecord.clear(); mCblkMemory.clear(); @@ -286,6 +290,8 @@ status_t AudioRecord::start(AudioSystem::sync_event_t event, int triggerSession) mNewPosition = mProxy->getPosition() + mUpdatePeriod; int32_t flags = android_atomic_acquire_load(&mCblk->mFlags); + mActive = true; + status_t status = NO_ERROR; if (!(flags & CBLK_INVALID)) { status = mAudioRecord->start(event, triggerSession); @@ -298,9 +304,9 @@ status_t AudioRecord::start(AudioSystem::sync_event_t event, int triggerSession) } if (status != NO_ERROR) { + mActive = false; ALOGE("start() status %d", status); } else { - mActive = true; sp t = mAudioRecordThread; if (t != 0) { t->resume(); @@ -425,6 +431,11 @@ status_t AudioRecord::setInputDevice(audio_port_handle_t deviceId) { AutoMutex lock(mLock); if (mSelectedDeviceId != deviceId) { mSelectedDeviceId = deviceId; + // stop capture so that audio policy manager does not reject the new instance start request + // as only one capture can be active at a time. + if (mAudioRecord != 0 && mActive) { + mAudioRecord->stop(); + } android_atomic_or(CBLK_INVALID, &mCblk->mFlags); } return NO_ERROR; @@ -435,6 +446,14 @@ audio_port_handle_t AudioRecord::getInputDevice() { return mSelectedDeviceId; } +audio_port_handle_t AudioRecord::getRoutedDeviceId() { + AutoMutex lock(mLock); + if (mInput == AUDIO_IO_HANDLE_NONE) { + return AUDIO_PORT_HANDLE_NONE; + } + return AudioSystem::getDeviceIdForIo(mInput); +} + // ------------------------------------------------------------------------- // must be called with mLock held @@ -478,6 +497,10 @@ status_t AudioRecord::openRecord_l(size_t epoch, const String16& opPackageName) } } + if (mDeviceCallback != 0 && mInput != AUDIO_IO_HANDLE_NONE) { + AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput); + } + audio_io_handle_t input; status_t status = AudioSystem::getInputForAttr(&mAttributes, &input, (audio_session_t)mSessionId, @@ -609,6 +632,10 @@ status_t AudioRecord::openRecord_l(size_t epoch, const String16& opPackageName) mDeathNotifier = new DeathNotifier(this); IInterface::asBinder(mAudioRecord)->linkToDeath(mDeathNotifier, this); + if (mDeviceCallback != 0) { + AudioSystem::addAudioDeviceCallback(mDeviceCallback, mInput); + } + return NO_ERROR; } @@ -1054,6 +1081,48 @@ status_t AudioRecord::restoreRecord_l(const char *from) return result; } +status_t AudioRecord::addAudioDeviceCallback(const sp& callback) +{ + if (callback == 0) { + ALOGW("%s adding NULL callback!", __FUNCTION__); + return BAD_VALUE; + } + AutoMutex lock(mLock); + if (mDeviceCallback == callback) { + ALOGW("%s adding same callback!", __FUNCTION__); + return INVALID_OPERATION; + } + status_t status = NO_ERROR; + if (mInput != AUDIO_IO_HANDLE_NONE) { + if (mDeviceCallback != 0) { + ALOGW("%s callback already present!", __FUNCTION__); + AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput); + } + status = AudioSystem::addAudioDeviceCallback(callback, mInput); + } + mDeviceCallback = callback; + return status; +} + +status_t AudioRecord::removeAudioDeviceCallback( + const sp& callback) +{ + if (callback == 0) { + ALOGW("%s removing NULL callback!", __FUNCTION__); + return BAD_VALUE; + } + AutoMutex lock(mLock); + if (mDeviceCallback != callback) { + ALOGW("%s removing different callback!", __FUNCTION__); + return INVALID_OPERATION; + } + if (mInput != AUDIO_IO_HANDLE_NONE) { + AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput); + } + mDeviceCallback = 0; + return NO_ERROR; +} + // ========================================================================= void AudioRecord::DeathNotifier::binderDied(const wp& who __unused) -- cgit v1.1