Merge "libaudioclient: force onAudioDeviceUpdate on registration"

gugelfrei
Eric Laurent 5 years ago committed by Android (Google) Code Review
commit 2ec0674146

@ -355,7 +355,10 @@ status_t AudioRecord::set(
} }
// create the IAudioRecord // create the IAudioRecord
status = createRecord_l(0 /*epoch*/, mOpPackageName); {
AutoMutex lock(mLock);
status = createRecord_l(0 /*epoch*/, mOpPackageName);
}
ALOGV("%s(%d): status %d", __func__, mPortId, status); ALOGV("%s(%d): status %d", __func__, mPortId, status);
@ -1358,12 +1361,14 @@ status_t AudioRecord::removeAudioDeviceCallback(
ALOGW("%s(%d): removing NULL callback!", __func__, mPortId); ALOGW("%s(%d): removing NULL callback!", __func__, mPortId);
return BAD_VALUE; return BAD_VALUE;
} }
AutoMutex lock(mLock); {
if (mDeviceCallback.unsafe_get() != callback.get()) { AutoMutex lock(mLock);
ALOGW("%s(%d): removing different callback!", __func__, mPortId); if (mDeviceCallback.unsafe_get() != callback.get()) {
return INVALID_OPERATION; ALOGW("%s(%d): removing different callback!", __func__, mPortId);
return INVALID_OPERATION;
}
mDeviceCallback.clear();
} }
mDeviceCallback.clear();
if (mInput != AUDIO_IO_HANDLE_NONE) { if (mInput != AUDIO_IO_HANDLE_NONE) {
AudioSystem::removeAudioDeviceCallback(this, mInput); AudioSystem::removeAudioDeviceCallback(this, mInput);
} }

@ -522,8 +522,9 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(audio_io_config_event even
if (ioDesc == 0 || ioDesc->mIoHandle == AUDIO_IO_HANDLE_NONE) return; if (ioDesc == 0 || ioDesc->mIoHandle == AUDIO_IO_HANDLE_NONE) return;
audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE; audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE;
Vector < wp<AudioDeviceCallback> > callbacks; AudioDeviceCallbacks callbacks;
bool deviceValidOrChanged = false;
Mutex::Autolock _l(mCallbacksLock);
{ {
Mutex::Autolock _l(mLock); Mutex::Autolock _l(mLock);
@ -546,6 +547,13 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(audio_io_config_event even
ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle); ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle);
if (ioIndex >= 0) { if (ioIndex >= 0) {
callbacks = mAudioDeviceCallbacks.valueAt(ioIndex); callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
deviceValidOrChanged = true;
}
}
if (event == AUDIO_OUTPUT_REGISTERED || event == AUDIO_INPUT_REGISTERED) {
ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle);
if ((ioIndex >= 0) && !mAudioDeviceCallbacks.valueAt(ioIndex).notifiedOnce()) {
callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
} }
} }
} }
@ -584,6 +592,7 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(audio_io_config_event even
mIoDescriptors.replaceValueFor(ioDesc->mIoHandle, ioDesc); mIoDescriptors.replaceValueFor(ioDesc->mIoHandle, ioDesc);
if (deviceId != ioDesc->getDeviceId()) { if (deviceId != ioDesc->getDeviceId()) {
deviceValidOrChanged = true;
deviceId = ioDesc->getDeviceId(); deviceId = ioDesc->getDeviceId();
ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle); ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle);
if (ioIndex >= 0) { if (ioIndex >= 0) {
@ -600,22 +609,28 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(audio_io_config_event even
} break; } break;
} }
} }
bool callbackRemoved = false;
// callbacks.size() != 0 => ioDesc->mIoHandle and deviceId are valid // callbacks.size() != 0 => ioDesc->mIoHandle and deviceId are valid
for (size_t i = 0; i < callbacks.size(); ) { if (callbacks.size() != 0) {
sp<AudioDeviceCallback> callback = callbacks[i].promote(); for (size_t i = 0; i < callbacks.size(); ) {
if (callback.get() != nullptr) { sp<AudioDeviceCallback> callback = callbacks[i].promote();
callback->onAudioDeviceUpdate(ioDesc->mIoHandle, deviceId); if (callback.get() != nullptr) {
i++; // Call the callback only if the device actually changed, the input or output was
} else { // opened or closed or the client was newly registered and the callback was never
callbacks.removeAt(i); // called
callbackRemoved = true; if (!callback->notifiedOnce() || deviceValidOrChanged) {
// Must be called without mLock held. May lead to dead lock if calling for
// example getRoutedDevice that updates the device and tries to acquire mLock.
callback->onAudioDeviceUpdate(ioDesc->mIoHandle, deviceId);
callback->setNotifiedOnce();
}
i++;
} else {
callbacks.removeAt(i);
}
} }
} callbacks.setNotifiedOnce();
// clean up callback list while we are here if some clients have disappeared without // clean up callback list while we are here if some clients have disappeared without
// unregistering their callback // unregistering their callback, or if cb was served for the first time since registered
if (callbackRemoved) {
Mutex::Autolock _l(mLock);
mAudioDeviceCallbacks.replaceValueFor(ioDesc->mIoHandle, callbacks); mAudioDeviceCallbacks.replaceValueFor(ioDesc->mIoHandle, callbacks);
} }
} }
@ -671,8 +686,8 @@ sp<AudioIoDescriptor> AudioSystem::AudioFlingerClient::getIoDescriptor(audio_io_
status_t AudioSystem::AudioFlingerClient::addAudioDeviceCallback( status_t AudioSystem::AudioFlingerClient::addAudioDeviceCallback(
const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo) const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
{ {
Mutex::Autolock _l(mLock); Mutex::Autolock _l(mCallbacksLock);
Vector < wp<AudioDeviceCallback> > callbacks; AudioDeviceCallbacks callbacks;
ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo); ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo);
if (ioIndex >= 0) { if (ioIndex >= 0) {
callbacks = mAudioDeviceCallbacks.valueAt(ioIndex); callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
@ -684,7 +699,7 @@ status_t AudioSystem::AudioFlingerClient::addAudioDeviceCallback(
} }
} }
callbacks.add(callback); callbacks.add(callback);
callbacks.resetNotifiedOnce();
mAudioDeviceCallbacks.replaceValueFor(audioIo, callbacks); mAudioDeviceCallbacks.replaceValueFor(audioIo, callbacks);
return NO_ERROR; return NO_ERROR;
} }
@ -692,12 +707,12 @@ status_t AudioSystem::AudioFlingerClient::addAudioDeviceCallback(
status_t AudioSystem::AudioFlingerClient::removeAudioDeviceCallback( status_t AudioSystem::AudioFlingerClient::removeAudioDeviceCallback(
const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo) const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
{ {
Mutex::Autolock _l(mLock); Mutex::Autolock _l(mCallbacksLock);
ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo); ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo);
if (ioIndex < 0) { if (ioIndex < 0) {
return INVALID_OPERATION; return INVALID_OPERATION;
} }
Vector < wp<AudioDeviceCallback> > callbacks = mAudioDeviceCallbacks.valueAt(ioIndex); AudioDeviceCallbacks callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
size_t cbIndex; size_t cbIndex;
for (cbIndex = 0; cbIndex < callbacks.size(); cbIndex++) { for (cbIndex = 0; cbIndex < callbacks.size(); cbIndex++) {

@ -621,8 +621,10 @@ status_t AudioTrack::set(
} }
// create the IAudioTrack // create the IAudioTrack
status = createTrack_l(); {
AutoMutex lock(mLock);
status = createTrack_l();
}
if (status != NO_ERROR) { if (status != NO_ERROR) {
if (mAudioTrackThread != 0) { if (mAudioTrackThread != 0) {
mAudioTrackThread->requestExit(); // see comment in AudioTrack.h mAudioTrackThread->requestExit(); // see comment in AudioTrack.h
@ -2957,12 +2959,14 @@ status_t AudioTrack::removeAudioDeviceCallback(
ALOGW("%s(%d): removing NULL callback!", __func__, mPortId); ALOGW("%s(%d): removing NULL callback!", __func__, mPortId);
return BAD_VALUE; return BAD_VALUE;
} }
AutoMutex lock(mLock); {
if (mDeviceCallback.unsafe_get() != callback.get()) { AutoMutex lock(mLock);
ALOGW("%s(%d): removing different callback!", __func__, mPortId); if (mDeviceCallback.unsafe_get() != callback.get()) {
return INVALID_OPERATION; ALOGW("%s removing different callback!", __FUNCTION__);
return INVALID_OPERATION;
}
mDeviceCallback.clear();
} }
mDeviceCallback.clear();
if (mOutput != AUDIO_IO_HANDLE_NONE) { if (mOutput != AUDIO_IO_HANDLE_NONE) {
AudioSystem::removeAudioDeviceCallback(this, mOutput); AudioSystem::removeAudioDeviceCallback(this, mOutput);
} }

@ -677,7 +677,7 @@ private:
sp<IMemory> mCblkMemory; sp<IMemory> mCblkMemory;
audio_track_cblk_t* mCblk; // re-load after mLock.unlock() audio_track_cblk_t* mCblk; // re-load after mLock.unlock()
sp<IMemory> mBufferMemory; sp<IMemory> mBufferMemory;
audio_io_handle_t mInput; // returned by AudioSystem::getInput() audio_io_handle_t mInput = AUDIO_IO_HANDLE_NONE; // from AudioSystem::getInputforAttr()
int mPreviousPriority; // before start() int mPreviousPriority; // before start()
SchedPolicy mPreviousSchedulingGroup; SchedPolicy mPreviousSchedulingGroup;

@ -399,6 +399,15 @@ public:
virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo, virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
audio_port_handle_t deviceId) = 0; audio_port_handle_t deviceId) = 0;
bool notifiedOnce() const { return mNotifiedOnce; }
void setNotifiedOnce() { mNotifiedOnce = true; }
private:
/**
* @brief mNotifiedOnce it forces the callback to be called at least once when
* registered with a VALID AudioDevice, and allows not to flood other listeners
* on this iohandle that already know the valid device.
*/
bool mNotifiedOnce = false;
}; };
static status_t addAudioDeviceCallback(const wp<AudioDeviceCallback>& callback, static status_t addAudioDeviceCallback(const wp<AudioDeviceCallback>& callback,
@ -444,8 +453,27 @@ private:
private: private:
Mutex mLock; Mutex mLock;
DefaultKeyedVector<audio_io_handle_t, sp<AudioIoDescriptor> > mIoDescriptors; DefaultKeyedVector<audio_io_handle_t, sp<AudioIoDescriptor> > mIoDescriptors;
DefaultKeyedVector<audio_io_handle_t, Vector < wp<AudioDeviceCallback> > >
mAudioDeviceCallbacks; class AudioDeviceCallbacks : public Vector<wp<AudioDeviceCallback>>
{
public:
/**
* @brief notifiedOnce ensures that if a client adds a callback, it must at least be
* called once with the device on which it will be routed to.
* @return true if already notified or nobody waits for a callback, false otherwise.
*/
bool notifiedOnce() const { return (size() == 0) || mNotifiedOnce; }
void setNotifiedOnce() { mNotifiedOnce = true; }
void resetNotifiedOnce() { mNotifiedOnce = false; }
private:
/**
* @brief mNotifiedOnce it forces each callback to be called at least once when
* registered with a VALID AudioDevice
*/
bool mNotifiedOnce = false;
};
Mutex mCallbacksLock; // prevents race on Callbacks
DefaultKeyedVector<audio_io_handle_t, AudioDeviceCallbacks> mAudioDeviceCallbacks;
// cached values for recording getInputBufferSize() queries // cached values for recording getInputBufferSize() queries
size_t mInBuffSize; // zero indicates cache is invalid size_t mInBuffSize; // zero indicates cache is invalid
uint32_t mInSamplingRate; uint32_t mInSamplingRate;

@ -1021,7 +1021,7 @@ public:
sp<IAudioTrack> mAudioTrack; sp<IAudioTrack> mAudioTrack;
sp<IMemory> mCblkMemory; sp<IMemory> mCblkMemory;
audio_track_cblk_t* mCblk; // re-load after mLock.unlock() audio_track_cblk_t* mCblk; // re-load after mLock.unlock()
audio_io_handle_t mOutput; // returned by AudioSystem::getOutputForAttr() audio_io_handle_t mOutput = AUDIO_IO_HANDLE_NONE; // from AudioSystem::getOutputForAttr()
sp<AudioTrackThread> mAudioTrackThread; sp<AudioTrackThread> mAudioTrackThread;
bool mThreadCanCallJava; bool mThreadCanCallJava;

Loading…
Cancel
Save