diff options
-rw-r--r-- | include/media/AudioIoDescriptor.h | 21 | ||||
-rw-r--r-- | include/media/AudioRecord.h | 34 | ||||
-rw-r--r-- | include/media/AudioSystem.h | 43 | ||||
-rw-r--r-- | include/media/AudioTrack.h | 35 | ||||
-rw-r--r-- | media/libmedia/AudioRecord.cpp | 71 | ||||
-rw-r--r-- | media/libmedia/AudioSystem.cpp | 249 | ||||
-rw-r--r-- | media/libmedia/AudioTrack.cpp | 61 | ||||
-rw-r--r-- | media/libmedia/IAudioFlingerClient.cpp | 2 | ||||
-rw-r--r-- | services/audioflinger/Threads.cpp | 8 | ||||
-rw-r--r-- | services/audioflinger/Threads.h | 1 |
10 files changed, 454 insertions, 71 deletions
diff --git a/include/media/AudioIoDescriptor.h b/include/media/AudioIoDescriptor.h index 2437901..c94b738 100644 --- a/include/media/AudioIoDescriptor.h +++ b/include/media/AudioIoDescriptor.h @@ -33,12 +33,31 @@ enum audio_io_config_event { class AudioIoDescriptor : public RefBase { public: AudioIoDescriptor() : + mIoHandle(AUDIO_IO_HANDLE_NONE), mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT), mChannelMask(AUDIO_CHANNEL_NONE), - mFrameCount(0), mLatency(0) {} + mFrameCount(0), mLatency(0) + { + memset(&mPatch, 0, sizeof(struct audio_patch)); + } virtual ~AudioIoDescriptor() {} + audio_port_handle_t getDeviceId() { + if (mPatch.num_sources != 0 && mPatch.num_sinks != 0) { + if (mPatch.sources[0].type == AUDIO_PORT_TYPE_MIX) { + // this is an output mix + // FIXME: the API only returns the first device in case of multiple device selection + return mPatch.sinks[0].id; + } else { + // this is an input mix + return mPatch.sources[0].id; + } + } + return AUDIO_PORT_HANDLE_NONE; + } + audio_io_handle_t mIoHandle; + struct audio_patch mPatch; uint32_t mSamplingRate; audio_format_t mFormat; audio_channel_mask_t mChannelMask; diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h index b743c11..0403e1a 100644 --- a/include/media/AudioRecord.h +++ b/include/media/AudioRecord.h @@ -390,6 +390,39 @@ public: * TODO Document this method. */ audio_port_handle_t getInputDevice(); + + /* Returns the ID of the audio device actually used by the input to which this AudioRecord + * is attached. + * A value of AUDIO_PORT_HANDLE_NONE indicates the AudioRecord is not attached to any input. + * + * Parameters: + * none. + */ + audio_port_handle_t getRoutedDeviceId(); + + /* Add an AudioDeviceCallback. The caller will be notified when the audio device + * to which this AudioRecord is routed is updated. + * Replaces any previously installed callback. + * Parameters: + * callback: The callback interface + * Returns NO_ERROR if successful. + * INVALID_OPERATION if the same callback is already installed. + * NO_INIT or PREMISSION_DENIED if AudioFlinger service is not reachable + * BAD_VALUE if the callback is NULL + */ + status_t addAudioDeviceCallback( + const sp<AudioSystem::AudioDeviceCallback>& callback); + + /* remove an AudioDeviceCallback. + * Parameters: + * callback: The callback interface + * Returns NO_ERROR if successful. + * INVALID_OPERATION if the callback is not installed + * BAD_VALUE if the callback is NULL + */ + status_t removeAudioDeviceCallback( + const sp<AudioSystem::AudioDeviceCallback>& callback); + private: /* If nonContig is non-NULL, it is an output parameter that will be set to the number of * additional non-contiguous frames that are predicted to be available immediately, @@ -582,6 +615,7 @@ private: // For Device Selection API // a value of AUDIO_PORT_HANDLE_NONE indicated default (AudioPolicyManager) routing. audio_port_handle_t mSelectedDeviceId; + sp<AudioSystem::AudioDeviceCallback> mDeviceCallback; }; }; // namespace android diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h index 0cbcdb1..3241e9c 100644 --- a/include/media/AudioSystem.h +++ b/include/media/AudioSystem.h @@ -332,8 +332,26 @@ public: }; - static status_t addAudioPortCallback(const sp<AudioPortCallback>& callBack); - static status_t removeAudioPortCallback(const sp<AudioPortCallback>& callBack); + static status_t addAudioPortCallback(const sp<AudioPortCallback>& callback); + static status_t removeAudioPortCallback(const sp<AudioPortCallback>& callback); + + class AudioDeviceCallback : public RefBase + { + public: + + AudioDeviceCallback() {} + virtual ~AudioDeviceCallback() {} + + virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo, + audio_port_handle_t deviceId) = 0; + }; + + static status_t addAudioDeviceCallback(const sp<AudioDeviceCallback>& callback, + audio_io_handle_t audioIo); + static status_t removeAudioDeviceCallback(const sp<AudioDeviceCallback>& callback, + audio_io_handle_t audioIo); + + static audio_port_handle_t getDeviceIdForIo(audio_io_handle_t audioIo); private: @@ -359,10 +377,20 @@ private: // values for output/input parameters up-to-date in client process virtual void ioConfigChanged(audio_io_config_event event, const sp<AudioIoDescriptor>& ioDesc); + + + status_t addAudioDeviceCallback(const sp<AudioDeviceCallback>& callback, + audio_io_handle_t audioIo); + status_t removeAudioDeviceCallback(const sp<AudioDeviceCallback>& callback, + audio_io_handle_t audioIo); + + audio_port_handle_t getDeviceIdForIo(audio_io_handle_t audioIo); + private: Mutex mLock; - DefaultKeyedVector<audio_io_handle_t, sp<AudioIoDescriptor> > mIoDescriptors; - + DefaultKeyedVector<audio_io_handle_t, sp<AudioIoDescriptor> > mIoDescriptors; + DefaultKeyedVector<audio_io_handle_t, Vector < sp<AudioDeviceCallback> > > + mAudioDeviceCallbacks; // cached values for recording getInputBufferSize() queries size_t mInBuffSize; // zero indicates cache is invalid uint32_t mInSamplingRate; @@ -377,8 +405,8 @@ private: AudioPolicyServiceClient() { } - status_t addAudioPortCallback(const sp<AudioPortCallback>& callBack); - status_t removeAudioPortCallback(const sp<AudioPortCallback>& callBack); + status_t addAudioPortCallback(const sp<AudioPortCallback>& callback); + status_t removeAudioPortCallback(const sp<AudioPortCallback>& callback); // DeathRecipient virtual void binderDied(const wp<IBinder>& who); @@ -393,6 +421,9 @@ private: Vector <sp <AudioPortCallback> > mAudioPortCallbacks; }; + static const sp<AudioFlingerClient> getAudioFlingerClient(); + static sp<AudioIoDescriptor> getIoDescriptor(audio_io_handle_t ioHandle); + static sp<AudioFlingerClient> gAudioFlingerClient; static sp<AudioPolicyServiceClient> gAudioPolicyServiceClient; friend class AudioFlingerClient; diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h index 0ccd19e..458f4b4 100644 --- a/include/media/AudioTrack.h +++ b/include/media/AudioTrack.h @@ -510,7 +510,7 @@ public: */ status_t setOutputDevice(audio_port_handle_t deviceId); - /* Returns the ID of the audio device used for output of this AudioTrack. + /* Returns the ID of the audio device selected for this AudioTrack. * A value of AUDIO_PORT_HANDLE_NONE indicates default (AudioPolicyManager) routing. * * Parameters: @@ -518,6 +518,15 @@ public: */ audio_port_handle_t getOutputDevice(); + /* Returns the ID of the audio device actually used by the output to which this AudioTrack is + * attached. + * A value of AUDIO_PORT_HANDLE_NONE indicates the audio track is not attached to any output. + * + * Parameters: + * none. + */ + audio_port_handle_t getRoutedDeviceId(); + /* Returns the unique session ID associated with this track. * * Parameters: @@ -664,6 +673,28 @@ public: */ status_t getTimestamp(AudioTimestamp& timestamp); + /* Add an AudioDeviceCallback. The caller will be notified when the audio device to which this + * AudioTrack is routed is updated. + * Replaces any previously installed callback. + * Parameters: + * callback: The callback interface + * Returns NO_ERROR if successful. + * INVALID_OPERATION if the same callback is already installed. + * NO_INIT or PREMISSION_DENIED if AudioFlinger service is not reachable + * BAD_VALUE if the callback is NULL + */ + status_t addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback); + + /* remove an AudioDeviceCallback. + * Parameters: + * callback: The callback interface + * Returns NO_ERROR if successful. + * INVALID_OPERATION if the callback is not installed + * BAD_VALUE if the callback is NULL + */ + status_t removeAudioDeviceCallback( + const sp<AudioSystem::AudioDeviceCallback>& callback); + protected: /* copying audio tracks is not allowed */ AudioTrack(const AudioTrack& other); @@ -885,6 +916,8 @@ private: uint32_t mSequence; // incremented for each new IAudioTrack attempt int mClientUid; pid_t mClientPid; + + sp<AudioSystem::AudioDeviceCallback> mDeviceCallback; }; class TimedAudioTrack : public AudioTrack 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<AudioRecordThread> 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<AudioSystem::AudioDeviceCallback>& 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<AudioSystem::AudioDeviceCallback>& 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<IBinder>& who __unused) diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 85ed2b1..4c2e77b 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -76,6 +76,25 @@ const sp<IAudioFlinger> AudioSystem::get_audio_flinger() return af; } +const sp<AudioSystem::AudioFlingerClient> AudioSystem::getAudioFlingerClient() +{ + // calling get_audio_flinger() will initialize gAudioFlingerClient if needed + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) return 0; + Mutex::Autolock _l(gLock); + return gAudioFlingerClient; +} + +sp<AudioIoDescriptor> AudioSystem::getIoDescriptor(audio_io_handle_t ioHandle) +{ + sp<AudioIoDescriptor> desc; + const sp<AudioFlingerClient> afc = getAudioFlingerClient(); + if (afc != 0) { + desc = afc->getIoDescriptor(ioHandle); + } + return desc; +} + /* static */ status_t AudioSystem::checkAudioFlinger() { if (defaultServiceManager()->checkService(String16("media.audio_flinger")) != 0) { @@ -249,9 +268,7 @@ status_t AudioSystem::getSamplingRate(audio_io_handle_t output, { const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; - - LOG_ALWAYS_FATAL_IF(gAudioFlingerClient == 0); - sp<AudioIoDescriptor> outputDesc = gAudioFlingerClient->getIoDescriptor(output); + sp<AudioIoDescriptor> outputDesc = getIoDescriptor(output); if (outputDesc == 0) { ALOGV("getOutputSamplingRate() no output descriptor for output %d in gOutputs", output); *samplingRate = af->sampleRate(output); @@ -290,9 +307,7 @@ status_t AudioSystem::getFrameCount(audio_io_handle_t output, { const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; - - LOG_ALWAYS_FATAL_IF(gAudioFlingerClient == 0); - sp<AudioIoDescriptor> outputDesc = gAudioFlingerClient->getIoDescriptor(output); + sp<AudioIoDescriptor> outputDesc = getIoDescriptor(output); if (outputDesc == 0) { *frameCount = af->frameCount(output); } else { @@ -329,9 +344,7 @@ status_t AudioSystem::getLatency(audio_io_handle_t output, { const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; - - LOG_ALWAYS_FATAL_IF(gAudioFlingerClient == 0); - sp<AudioIoDescriptor> outputDesc = gAudioFlingerClient->getIoDescriptor(output); + sp<AudioIoDescriptor> outputDesc = getIoDescriptor(output); if (outputDesc == 0) { *latency = af->latency(output); } else { @@ -346,10 +359,11 @@ status_t AudioSystem::getLatency(audio_io_handle_t output, status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, size_t* buffSize) { - const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); - if (af == 0) return PERMISSION_DENIED; - LOG_ALWAYS_FATAL_IF(gAudioFlingerClient == 0); - return gAudioFlingerClient->getInputBufferSize(sampleRate, format, channelMask, buffSize); + const sp<AudioFlingerClient> afc = getAudioFlingerClient(); + if (afc == 0) { + return NO_INIT; + } + return afc->getInputBufferSize(sampleRate, format, channelMask, buffSize); } status_t AudioSystem::setVoiceVolume(float value) @@ -446,47 +460,77 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(audio_io_config_event even if (ioDesc == 0 || ioDesc->mIoHandle == AUDIO_IO_HANDLE_NONE) return; - Mutex::Autolock _l(mLock); + audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE; + Vector < sp<AudioDeviceCallback> > callbacks; - 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; - } - mIoDescriptors.add(ioDesc->mIoHandle, ioDesc); - ALOGV("ioConfigChanged() new %s opened %d samplingRate %u, format %#x channel mask %#x " - "frameCount %zu", event == AUDIO_OUTPUT_OPENED ? "output" : "input", - ioDesc->mIoHandle, ioDesc->mSamplingRate, ioDesc->mFormat, ioDesc->mChannelMask, - ioDesc->mFrameCount); - } break; - case AUDIO_OUTPUT_CLOSED: - case AUDIO_INPUT_CLOSED: { - if (getIoDescriptor(ioDesc->mIoHandle) == 0) { - ALOGW("ioConfigChanged() closing unknown %s %d", + { + Mutex::Autolock _l(mLock); + + 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; + } + mIoDescriptors.add(ioDesc->mIoHandle, ioDesc); + + if (ioDesc->getDeviceId() != AUDIO_PORT_HANDLE_NONE) { + deviceId = ioDesc->getDeviceId(); + ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle); + if (ioIndex >= 0) { + callbacks = mAudioDeviceCallbacks.valueAt(ioIndex); + } + } + ALOGV("ioConfigChanged() new %s opened %d samplingRate %u, format %#x channel mask %#x " + "frameCount %zu deviceId %d", event == AUDIO_OUTPUT_OPENED ? "output" : "input", + ioDesc->mIoHandle, ioDesc->mSamplingRate, ioDesc->mFormat, ioDesc->mChannelMask, + ioDesc->mFrameCount, ioDesc->getDeviceId()); + } break; + case AUDIO_OUTPUT_CLOSED: + case AUDIO_INPUT_CLOSED: { + if (getIoDescriptor(ioDesc->mIoHandle) == 0) { + ALOGW("ioConfigChanged() closing unknown %s %d", + event == AUDIO_OUTPUT_CLOSED ? "output" : "input", ioDesc->mIoHandle); + break; + } + ALOGV("ioConfigChanged() %s %d closed", event == AUDIO_OUTPUT_CLOSED ? "output" : "input", ioDesc->mIoHandle); - break; - } - ALOGV("ioConfigChanged() %s %d closed", event == AUDIO_OUTPUT_CLOSED ? "output" : "input", - ioDesc->mIoHandle); - mIoDescriptors.removeItem(ioDesc->mIoHandle); - } break; + mIoDescriptors.removeItem(ioDesc->mIoHandle); + mAudioDeviceCallbacks.removeItem(ioDesc->mIoHandle); + } break; - case AUDIO_OUTPUT_CONFIG_CHANGED: - case AUDIO_INPUT_CONFIG_CHANGED: { - if (getIoDescriptor(ioDesc->mIoHandle) == 0) { - ALOGW("ioConfigChanged() modifying unknown output! %d", ioDesc->mIoHandle); - break; + case AUDIO_OUTPUT_CONFIG_CHANGED: + case AUDIO_INPUT_CONFIG_CHANGED: { + sp<AudioIoDescriptor> oldDesc = getIoDescriptor(ioDesc->mIoHandle); + if (oldDesc == 0) { + ALOGW("ioConfigChanged() modifying unknown output! %d", ioDesc->mIoHandle); + break; + } + + deviceId = oldDesc->getDeviceId(); + mIoDescriptors.replaceValueFor(ioDesc->mIoHandle, ioDesc); + + if (deviceId != ioDesc->getDeviceId()) { + deviceId = ioDesc->getDeviceId(); + ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle); + if (ioIndex >= 0) { + callbacks = mAudioDeviceCallbacks.valueAt(ioIndex); + } + } + ALOGV("ioConfigChanged() new config for %s %d samplingRate %u, format %#x " + "channel mask %#x frameCount %zu deviceId %d", + event == AUDIO_OUTPUT_CONFIG_CHANGED ? "output" : "input", + ioDesc->mIoHandle, ioDesc->mSamplingRate, ioDesc->mFormat, + ioDesc->mChannelMask, ioDesc->mFrameCount, ioDesc->getDeviceId()); + + } break; } - mIoDescriptors.replaceValueFor(ioDesc->mIoHandle, ioDesc); - ALOGV("ioConfigChanged() new config for %s %d samplingRate %u, format %#x " - "channel mask %#x frameCount %zu", - event == AUDIO_OUTPUT_CONFIG_CHANGED ? "output" : "input", - ioDesc->mIoHandle, ioDesc->mSamplingRate, ioDesc->mFormat, - ioDesc->mChannelMask, ioDesc->mFrameCount); - } break; + } + // callbacks.size() != 0 => ioDesc->mIoHandle and deviceId are valid + for (size_t i = 0; i < callbacks.size(); i++) { + callbacks[i]->onAudioDeviceUpdate(ioDesc->mIoHandle, deviceId); } } @@ -532,7 +576,56 @@ sp<AudioIoDescriptor> AudioSystem::AudioFlingerClient::getIoDescriptor(audio_io_ return desc; } -/*static*/ void AudioSystem::setErrorCallback(audio_error_callback cb) +status_t AudioSystem::AudioFlingerClient::addAudioDeviceCallback( + const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo) +{ + Mutex::Autolock _l(mLock); + Vector < sp<AudioDeviceCallback> > callbacks; + ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo); + if (ioIndex >= 0) { + callbacks = mAudioDeviceCallbacks.valueAt(ioIndex); + } + + for (size_t cbIndex = 0; cbIndex < callbacks.size(); cbIndex++) { + if (callbacks[cbIndex] == callback) { + return INVALID_OPERATION; + } + } + callbacks.add(callback); + + mAudioDeviceCallbacks.replaceValueFor(audioIo, callbacks); + return NO_ERROR; +} + +status_t AudioSystem::AudioFlingerClient::removeAudioDeviceCallback( + const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo) +{ + Mutex::Autolock _l(mLock); + ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo); + if (ioIndex < 0) { + return INVALID_OPERATION; + } + Vector < sp<AudioDeviceCallback> > callbacks = mAudioDeviceCallbacks.valueAt(ioIndex); + + size_t cbIndex; + for (cbIndex = 0; cbIndex < callbacks.size(); cbIndex++) { + if (callbacks[cbIndex] == callback) { + break; + } + } + if (cbIndex == callbacks.size()) { + return INVALID_OPERATION; + } + callbacks.removeAt(cbIndex); + if (callbacks.size() != 0) { + mAudioDeviceCallbacks.replaceValueFor(audioIo, callbacks); + } else { + mAudioDeviceCallbacks.removeItem(audioIo); + } + return NO_ERROR; +} + +/* static */ void AudioSystem::setErrorCallback(audio_error_callback cb) { Mutex::Autolock _l(gLock); gAudioErrorCallback = cb; @@ -864,11 +957,11 @@ void AudioSystem::clearAudioConfigCache() { // called by restoreTrack_l(), which needs new IAudioFlinger and IAudioPolicyService instances ALOGV("clearAudioConfigCache()"); - if (gAudioFlingerClient != 0) { - gAudioFlingerClient->clearIoCache(); - } { Mutex::Autolock _l(gLock); + if (gAudioFlingerClient != 0) { + gAudioFlingerClient->clearIoCache(); + } gAudioFlinger.clear(); } { @@ -934,7 +1027,7 @@ status_t AudioSystem::setAudioPortConfig(const struct audio_port_config *config) return aps->setAudioPortConfig(config); } -status_t AudioSystem::addAudioPortCallback(const sp<AudioPortCallback>& callBack) +status_t AudioSystem::addAudioPortCallback(const sp<AudioPortCallback>& callback) { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return PERMISSION_DENIED; @@ -943,11 +1036,11 @@ status_t AudioSystem::addAudioPortCallback(const sp<AudioPortCallback>& callBack if (gAudioPolicyServiceClient == 0) { return NO_INIT; } - return gAudioPolicyServiceClient->addAudioPortCallback(callBack); + return gAudioPolicyServiceClient->addAudioPortCallback(callback); } /*static*/ -status_t AudioSystem::removeAudioPortCallback(const sp<AudioPortCallback>& callBack) +status_t AudioSystem::removeAudioPortCallback(const sp<AudioPortCallback>& callback) { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return PERMISSION_DENIED; @@ -956,7 +1049,38 @@ status_t AudioSystem::removeAudioPortCallback(const sp<AudioPortCallback>& callB if (gAudioPolicyServiceClient == 0) { return NO_INIT; } - return gAudioPolicyServiceClient->removeAudioPortCallback(callBack); + return gAudioPolicyServiceClient->removeAudioPortCallback(callback); +} + +status_t AudioSystem::addAudioDeviceCallback( + const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo) +{ + const sp<AudioFlingerClient> afc = getAudioFlingerClient(); + if (afc == 0) { + return NO_INIT; + } + return afc->addAudioDeviceCallback(callback, audioIo); +} + +status_t AudioSystem::removeAudioDeviceCallback( + const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo) +{ + const sp<AudioFlingerClient> afc = getAudioFlingerClient(); + if (afc == 0) { + return NO_INIT; + } + return afc->removeAudioDeviceCallback(callback, audioIo); +} + +audio_port_handle_t AudioSystem::getDeviceIdForIo(audio_io_handle_t audioIo) +{ + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + const sp<AudioIoDescriptor> desc = getIoDescriptor(audioIo); + if (desc == 0) { + return AUDIO_PORT_HANDLE_NONE; + } + return desc->getDeviceId(); } status_t AudioSystem::acquireSoundTriggerSession(audio_session_t *session, @@ -1008,25 +1132,25 @@ status_t AudioSystem::stopAudioSource(audio_io_handle_t handle) // --------------------------------------------------------------------------- status_t AudioSystem::AudioPolicyServiceClient::addAudioPortCallback( - const sp<AudioPortCallback>& callBack) + const sp<AudioPortCallback>& callback) { Mutex::Autolock _l(mLock); for (size_t i = 0; i < mAudioPortCallbacks.size(); i++) { - if (mAudioPortCallbacks[i] == callBack) { + if (mAudioPortCallbacks[i] == callback) { return INVALID_OPERATION; } } - mAudioPortCallbacks.add(callBack); + mAudioPortCallbacks.add(callback); return NO_ERROR; } status_t AudioSystem::AudioPolicyServiceClient::removeAudioPortCallback( - const sp<AudioPortCallback>& callBack) + const sp<AudioPortCallback>& callback) { Mutex::Autolock _l(mLock); size_t i; for (i = 0; i < mAudioPortCallbacks.size(); i++) { - if (mAudioPortCallbacks[i] == callBack) { + if (mAudioPortCallbacks[i] == callback) { break; } } @@ -1037,6 +1161,7 @@ status_t AudioSystem::AudioPolicyServiceClient::removeAudioPortCallback( return NO_ERROR; } + void AudioSystem::AudioPolicyServiceClient::onAudioPortListUpdate() { Mutex::Autolock _l(mLock); diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index bb47d3e..db316b0 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -234,6 +234,10 @@ AudioTrack::~AudioTrack() mAudioTrackThread->requestExitAndWait(); mAudioTrackThread.clear(); } + // No lock here: worst case we remove a NULL callback which will be a nop + if (mDeviceCallback != 0 && mOutput != AUDIO_IO_HANDLE_NONE) { + AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput); + } IInterface::asBinder(mAudioTrack)->unlinkToDeath(mDeathNotifier, this); mAudioTrack.clear(); mCblkMemory.clear(); @@ -1042,6 +1046,14 @@ audio_port_handle_t AudioTrack::getOutputDevice() { return mSelectedDeviceId; } +audio_port_handle_t AudioTrack::getRoutedDeviceId() { + AutoMutex lock(mLock); + if (mOutput == AUDIO_IO_HANDLE_NONE) { + return AUDIO_PORT_HANDLE_NONE; + } + return AudioSystem::getDeviceIdForIo(mOutput); +} + status_t AudioTrack::attachAuxEffect(int effectId) { AutoMutex lock(mLock); @@ -1071,6 +1083,9 @@ status_t AudioTrack::createTrack_l() return NO_INIT; } + if (mDeviceCallback != 0 && mOutput != AUDIO_IO_HANDLE_NONE) { + AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput); + } audio_io_handle_t output; audio_stream_type_t streamType = mStreamType; audio_attributes_t *attr = (mStreamType == AUDIO_STREAM_DEFAULT) ? &mAttributes : NULL; @@ -1375,6 +1390,10 @@ status_t AudioTrack::createTrack_l() mDeathNotifier = new DeathNotifier(this); IInterface::asBinder(mAudioTrack)->linkToDeath(mDeathNotifier, this); + if (mDeviceCallback != 0) { + AudioSystem::addAudioDeviceCallback(mDeviceCallback, mOutput); + } + return NO_ERROR; } @@ -2308,6 +2327,48 @@ uint32_t AudioTrack::getUnderrunFrames() const return mProxy->getUnderrunFrames(); } +status_t AudioTrack::addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& 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 (mOutput != AUDIO_IO_HANDLE_NONE) { + if (mDeviceCallback != 0) { + ALOGW("%s callback already present!", __FUNCTION__); + AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput); + } + status = AudioSystem::addAudioDeviceCallback(callback, mOutput); + } + mDeviceCallback = callback; + return status; +} + +status_t AudioTrack::removeAudioDeviceCallback( + const sp<AudioSystem::AudioDeviceCallback>& 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 (mOutput != AUDIO_IO_HANDLE_NONE) { + AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput); + } + mDeviceCallback = 0; + return NO_ERROR; +} + // ========================================================================= void AudioTrack::DeathNotifier::binderDied(const wp<IBinder>& who __unused) diff --git a/media/libmedia/IAudioFlingerClient.cpp b/media/libmedia/IAudioFlingerClient.cpp index a622241..3429d36 100644 --- a/media/libmedia/IAudioFlingerClient.cpp +++ b/media/libmedia/IAudioFlingerClient.cpp @@ -45,6 +45,7 @@ public: data.writeInterfaceToken(IAudioFlingerClient::getInterfaceDescriptor()); data.writeInt32(event); data.writeInt32((int32_t)ioDesc->mIoHandle); + data.write(&ioDesc->mPatch, sizeof(struct audio_patch)); data.writeInt32(ioDesc->mSamplingRate); data.writeInt32(ioDesc->mFormat); data.writeInt32(ioDesc->mChannelMask); @@ -67,6 +68,7 @@ status_t BnAudioFlingerClient::onTransact( audio_io_config_event event = (audio_io_config_event)data.readInt32(); sp<AudioIoDescriptor> ioDesc = new AudioIoDescriptor(); ioDesc->mIoHandle = (audio_io_handle_t) data.readInt32(); + data.read(&ioDesc->mPatch, sizeof(struct audio_patch)); ioDesc->mSamplingRate = data.readInt32(); ioDesc->mFormat = (audio_format_t) data.readInt32(); ioDesc->mChannelMask = (audio_channel_mask_t) data.readInt32(); diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 8b8dd78..2c4d801 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -500,6 +500,7 @@ AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio // mName will be set by concrete (non-virtual) subclass mDeathRecipient(new PMDeathRecipient(this)) { + memset(&mPatch, 0, sizeof(struct audio_patch)); } AudioFlinger::ThreadBase::~ThreadBase() @@ -1930,6 +1931,7 @@ void AudioFlinger::PlaybackThread::ioConfigChanged(audio_io_config_event event) switch (event) { case AUDIO_OUTPUT_OPENED: case AUDIO_OUTPUT_CONFIG_CHANGED: + desc->mPatch = mPatch; desc->mChannelMask = mChannelMask; desc->mSamplingRate = mSampleRate; desc->mFormat = mFormat; @@ -3002,6 +3004,7 @@ status_t AudioFlinger::PlaybackThread::createAudioPatch_l(const struct audio_pat mEffectChains[i]->setDevice_l(type); } mOutDevice = type; + mPatch = *patch; if (mOutput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) { audio_hw_device_t *hwDevice = mOutput->audioHwDev->hwDevice(); @@ -3028,6 +3031,7 @@ status_t AudioFlinger::PlaybackThread::createAudioPatch_l(const struct audio_pat param.toString().string()); *handle = AUDIO_PATCH_HANDLE_NONE; } + sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED); return status; } @@ -6727,6 +6731,7 @@ void AudioFlinger::RecordThread::ioConfigChanged(audio_io_config_event event) { switch (event) { case AUDIO_INPUT_OPENED: case AUDIO_INPUT_CONFIG_CHANGED: + desc->mPatch = mPatch; desc->mChannelMask = mChannelMask; desc->mSamplingRate = mSampleRate; desc->mFormat = mFormat; @@ -6884,6 +6889,7 @@ status_t AudioFlinger::RecordThread::createAudioPatch_l(const struct audio_patch // store new device and send to effects mInDevice = patch->sources[0].ext.device.type; + mPatch = *patch; for (size_t i = 0; i < mEffectChains.size(); i++) { mEffectChains[i]->setDevice_l(mInDevice); } @@ -6936,6 +6942,8 @@ status_t AudioFlinger::RecordThread::createAudioPatch_l(const struct audio_patch *handle = AUDIO_PATCH_HANDLE_NONE; } + sendIoConfigEvent_l(AUDIO_INPUT_CONFIG_CHANGED); + return status; } diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index 8167bd1..0a5597f 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -426,6 +426,7 @@ protected: bool mStandby; // Whether thread is currently in standby. audio_devices_t mOutDevice; // output device audio_devices_t mInDevice; // input device + struct audio_patch mPatch; audio_source_t mAudioSource; const audio_io_handle_t mId; |