Merge "ACodec: call cancelBufferToNativeWindow() only when the buffer is owned by us." into mnc-dev
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index f13bcf3..3bfb09a 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -476,11 +476,13 @@
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;
+ sp<AudioIoDescriptor> oldDesc = getIoDescriptor(ioDesc->mIoHandle);
+ if (oldDesc == 0) {
+ mIoDescriptors.add(ioDesc->mIoHandle, ioDesc);
+ } else {
+ deviceId = oldDesc->getDeviceId();
+ mIoDescriptors.replaceValueFor(ioDesc->mIoHandle, ioDesc);
}
- mIoDescriptors.add(ioDesc->mIoHandle, ioDesc);
if (ioDesc->getDeviceId() != AUDIO_PORT_HANDLE_NONE) {
deviceId = ioDesc->getDeviceId();
@@ -1074,7 +1076,14 @@
if (afc == 0) {
return NO_INIT;
}
- return afc->addAudioDeviceCallback(callback, audioIo);
+ status_t status = afc->addAudioDeviceCallback(callback, audioIo);
+ if (status == NO_ERROR) {
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af != 0) {
+ af->registerClient(afc);
+ }
+ }
+ return status;
}
status_t AudioSystem::removeAudioDeviceCallback(
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index ae869d6..0ecfb1e 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1335,21 +1335,23 @@
mCallbackCookie(NULL),
mCallbackData(NULL),
mBytesWritten(0),
+ mStreamType(AUDIO_STREAM_MUSIC),
+ mAttributes(attr),
+ mLeftVolume(1.0),
+ mRightVolume(1.0),
+ mPlaybackRate(AUDIO_PLAYBACK_RATE_DEFAULT),
+ mSampleRateHz(0),
+ mMsecsPerFrame(0),
+ mFrameSize(0),
mSessionId(sessionId),
mUid(uid),
mPid(pid),
- mFlags(AUDIO_OUTPUT_FLAG_NONE) {
+ mSendLevel(0.0),
+ mAuxEffectId(0),
+ mFlags(AUDIO_OUTPUT_FLAG_NONE)
+{
ALOGV("AudioOutput(%d)", sessionId);
- mStreamType = AUDIO_STREAM_MUSIC;
- mLeftVolume = 1.0;
- mRightVolume = 1.0;
- mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT;
- mSampleRateHz = 0;
- mMsecsPerFrame = 0;
- mAuxEffectId = 0;
- mSendLevel = 0.0;
setMinBufferCount();
- mAttributes = attr;
}
MediaPlayerService::AudioOutput::~AudioOutput()
@@ -1358,6 +1360,7 @@
delete mCallbackData;
}
+//static
void MediaPlayerService::AudioOutput::setMinBufferCount()
{
char value[PROPERTY_VALUE_MAX];
@@ -1367,92 +1370,105 @@
}
}
+// static
bool MediaPlayerService::AudioOutput::isOnEmulator()
{
- setMinBufferCount();
+ setMinBufferCount(); // benign race wrt other threads
return mIsOnEmulator;
}
+// static
int MediaPlayerService::AudioOutput::getMinBufferCount()
{
- setMinBufferCount();
+ setMinBufferCount(); // benign race wrt other threads
return mMinBufferCount;
}
ssize_t MediaPlayerService::AudioOutput::bufferSize() const
{
+ Mutex::Autolock lock(mLock);
if (mTrack == 0) return NO_INIT;
- return mTrack->frameCount() * frameSize();
+ return mTrack->frameCount() * mFrameSize;
}
ssize_t MediaPlayerService::AudioOutput::frameCount() const
{
+ Mutex::Autolock lock(mLock);
if (mTrack == 0) return NO_INIT;
return mTrack->frameCount();
}
ssize_t MediaPlayerService::AudioOutput::channelCount() const
{
+ Mutex::Autolock lock(mLock);
if (mTrack == 0) return NO_INIT;
return mTrack->channelCount();
}
ssize_t MediaPlayerService::AudioOutput::frameSize() const
{
+ Mutex::Autolock lock(mLock);
if (mTrack == 0) return NO_INIT;
- return mTrack->frameSize();
+ return mFrameSize;
}
uint32_t MediaPlayerService::AudioOutput::latency () const
{
+ Mutex::Autolock lock(mLock);
if (mTrack == 0) return 0;
return mTrack->latency();
}
float MediaPlayerService::AudioOutput::msecsPerFrame() const
{
+ Mutex::Autolock lock(mLock);
return mMsecsPerFrame;
}
status_t MediaPlayerService::AudioOutput::getPosition(uint32_t *position) const
{
+ Mutex::Autolock lock(mLock);
if (mTrack == 0) return NO_INIT;
return mTrack->getPosition(position);
}
status_t MediaPlayerService::AudioOutput::getTimestamp(AudioTimestamp &ts) const
{
+ Mutex::Autolock lock(mLock);
if (mTrack == 0) return NO_INIT;
return mTrack->getTimestamp(ts);
}
status_t MediaPlayerService::AudioOutput::getFramesWritten(uint32_t *frameswritten) const
{
+ Mutex::Autolock lock(mLock);
if (mTrack == 0) return NO_INIT;
- *frameswritten = mBytesWritten / frameSize();
+ *frameswritten = mBytesWritten / mFrameSize;
return OK;
}
status_t MediaPlayerService::AudioOutput::setParameters(const String8& keyValuePairs)
{
+ Mutex::Autolock lock(mLock);
if (mTrack == 0) return NO_INIT;
return mTrack->setParameters(keyValuePairs);
}
String8 MediaPlayerService::AudioOutput::getParameters(const String8& keys)
{
+ Mutex::Autolock lock(mLock);
if (mTrack == 0) return String8::empty();
return mTrack->getParameters(keys);
}
void MediaPlayerService::AudioOutput::setAudioAttributes(const audio_attributes_t * attributes) {
+ Mutex::Autolock lock(mLock);
mAttributes = attributes;
}
-void MediaPlayerService::AudioOutput::deleteRecycledTrack()
+void MediaPlayerService::AudioOutput::deleteRecycledTrack_l()
{
- ALOGV("deleteRecycledTrack");
-
+ ALOGV("deleteRecycledTrack_l");
if (mRecycledTrack != 0) {
if (mCallbackData != NULL) {
@@ -1470,12 +1486,17 @@
// AudioFlinger to drain the track.
mRecycledTrack.clear();
+ close_l();
delete mCallbackData;
mCallbackData = NULL;
- close();
}
}
+void MediaPlayerService::AudioOutput::close_l()
+{
+ mTrack.clear();
+}
+
status_t MediaPlayerService::AudioOutput::open(
uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
audio_format_t format, int bufferCount,
@@ -1535,6 +1556,7 @@
}
}
+ Mutex::Autolock lock(mLock);
mCallback = cb;
mCallbackCookie = cookie;
@@ -1577,7 +1599,7 @@
// we must close the previous output before opening a new one
if (bothOffloaded && !reuse) {
ALOGV("both offloaded and not recycling");
- deleteRecycledTrack();
+ deleteRecycledTrack_l();
}
sp<AudioTrack> t;
@@ -1655,7 +1677,7 @@
if (reuse) {
ALOGV("chaining to next output and recycling track");
- close();
+ close_l();
mTrack = mRecycledTrack;
mRecycledTrack.clear();
if (mCallbackData != NULL) {
@@ -1669,7 +1691,7 @@
// we're not going to reuse the track, unblock and flush it
// this was done earlier if both tracks are offloaded
if (!bothOffloaded) {
- deleteRecycledTrack();
+ deleteRecycledTrack_l();
}
CHECK((t != NULL) && ((mCallback == NULL) || (newcbd != NULL)));
@@ -1681,9 +1703,10 @@
mSampleRateHz = sampleRate;
mFlags = t->getFlags(); // we suggest the flags above, but new AudioTrack() may not grant it.
mMsecsPerFrame = 1E3f / (mPlaybackRate.mSpeed * sampleRate);
+ mFrameSize = t->frameSize();
uint32_t pos;
if (t->getPosition(&pos) == OK) {
- mBytesWritten = uint64_t(pos) * t->frameSize();
+ mBytesWritten = uint64_t(pos) * mFrameSize;
}
mTrack = t;
@@ -1704,6 +1727,7 @@
status_t MediaPlayerService::AudioOutput::start()
{
ALOGV("start");
+ Mutex::Autolock lock(mLock);
if (mCallbackData != NULL) {
mCallbackData->endTrackSwitch();
}
@@ -1716,30 +1740,88 @@
}
void MediaPlayerService::AudioOutput::setNextOutput(const sp<AudioOutput>& nextOutput) {
+ Mutex::Autolock lock(mLock);
mNextOutput = nextOutput;
}
-
void MediaPlayerService::AudioOutput::switchToNextOutput() {
ALOGV("switchToNextOutput");
- if (mNextOutput != NULL) {
- if (mCallbackData != NULL) {
- mCallbackData->beginTrackSwitch();
+
+ // Try to acquire the callback lock before moving track (without incurring deadlock).
+ const unsigned kMaxSwitchTries = 100;
+ Mutex::Autolock lock(mLock);
+ for (unsigned tries = 0;;) {
+ if (mTrack == 0) {
+ return;
}
- delete mNextOutput->mCallbackData;
- mNextOutput->mCallbackData = mCallbackData;
- mCallbackData = NULL;
- mNextOutput->mRecycledTrack = mTrack;
- mTrack.clear();
- mNextOutput->mSampleRateHz = mSampleRateHz;
- mNextOutput->mMsecsPerFrame = mMsecsPerFrame;
- mNextOutput->mBytesWritten = mBytesWritten;
- mNextOutput->mFlags = mFlags;
+ if (mNextOutput != NULL && mNextOutput != this) {
+ if (mCallbackData != NULL) {
+ // two alternative approaches
+#if 1
+ CallbackData *callbackData = mCallbackData;
+ mLock.unlock();
+ // proper acquisition sequence
+ callbackData->lock();
+ mLock.lock();
+ // Caution: it is unlikely that someone deleted our callback or changed our target
+ if (callbackData != mCallbackData || mNextOutput == NULL || mNextOutput == this) {
+ // fatal if we are starved out.
+ LOG_ALWAYS_FATAL_IF(++tries > kMaxSwitchTries,
+ "switchToNextOutput() cannot obtain correct lock sequence");
+ callbackData->unlock();
+ continue;
+ }
+ callbackData->mSwitching = true; // begin track switch
+#else
+ // tryBeginTrackSwitch() returns false if the callback has the lock.
+ if (!mCallbackData->tryBeginTrackSwitch()) {
+ // fatal if we are starved out.
+ LOG_ALWAYS_FATAL_IF(++tries > kMaxSwitchTries,
+ "switchToNextOutput() cannot obtain callback lock");
+ mLock.unlock();
+ usleep(5 * 1000 /* usec */); // allow callback to use AudioOutput
+ mLock.lock();
+ continue;
+ }
+#endif
+ }
+
+ Mutex::Autolock nextLock(mNextOutput->mLock);
+
+ // If the next output track is not NULL, then it has been
+ // opened already for playback.
+ // This is possible even without the next player being started,
+ // for example, the next player could be prepared and seeked.
+ //
+ // Presuming it isn't advisable to force the track over.
+ if (mNextOutput->mTrack == NULL) {
+ ALOGD("Recycling track for gapless playback");
+ delete mNextOutput->mCallbackData;
+ mNextOutput->mCallbackData = mCallbackData;
+ mNextOutput->mRecycledTrack = mTrack;
+ mNextOutput->mSampleRateHz = mSampleRateHz;
+ mNextOutput->mMsecsPerFrame = mMsecsPerFrame;
+ mNextOutput->mBytesWritten = mBytesWritten;
+ mNextOutput->mFlags = mFlags;
+ mNextOutput->mFrameSize = mFrameSize;
+ close_l();
+ mCallbackData = NULL; // destruction handled by mNextOutput
+ } else {
+ ALOGW("Ignoring gapless playback because next player has already started");
+ // remove track in case resource needed for future players.
+ if (mCallbackData != NULL) {
+ mCallbackData->endTrackSwitch(); // release lock for callbacks before close.
+ }
+ close_l();
+ }
+ }
+ break;
}
}
ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size, bool blocking)
{
+ Mutex::Autolock lock(mLock);
LOG_ALWAYS_FATAL_IF(mCallback != NULL, "Don't call write if supplying a callback.");
//ALOGV("write(%p, %u)", buffer, size);
@@ -1756,6 +1838,7 @@
void MediaPlayerService::AudioOutput::stop()
{
ALOGV("stop");
+ Mutex::Autolock lock(mLock);
mBytesWritten = 0;
if (mTrack != 0) mTrack->stop();
}
@@ -1763,6 +1846,7 @@
void MediaPlayerService::AudioOutput::flush()
{
ALOGV("flush");
+ Mutex::Autolock lock(mLock);
mBytesWritten = 0;
if (mTrack != 0) mTrack->flush();
}
@@ -1770,18 +1854,21 @@
void MediaPlayerService::AudioOutput::pause()
{
ALOGV("pause");
+ Mutex::Autolock lock(mLock);
if (mTrack != 0) mTrack->pause();
}
void MediaPlayerService::AudioOutput::close()
{
ALOGV("close");
- mTrack.clear();
+ Mutex::Autolock lock(mLock);
+ close_l();
}
void MediaPlayerService::AudioOutput::setVolume(float left, float right)
{
ALOGV("setVolume(%f, %f)", left, right);
+ Mutex::Autolock lock(mLock);
mLeftVolume = left;
mRightVolume = right;
if (mTrack != 0) {
@@ -1793,6 +1880,7 @@
{
ALOGV("setPlaybackRate(%f %f %d %d)",
rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode);
+ Mutex::Autolock lock(mLock);
if (mTrack == 0) {
// remember rate so that we can set it when the track is opened
mPlaybackRate = rate;
@@ -1814,6 +1902,7 @@
status_t MediaPlayerService::AudioOutput::getPlaybackRate(AudioPlaybackRate *rate)
{
ALOGV("setPlaybackRate");
+ Mutex::Autolock lock(mLock);
if (mTrack == 0) {
return NO_INIT;
}
@@ -1824,6 +1913,7 @@
status_t MediaPlayerService::AudioOutput::setAuxEffectSendLevel(float level)
{
ALOGV("setAuxEffectSendLevel(%f)", level);
+ Mutex::Autolock lock(mLock);
mSendLevel = level;
if (mTrack != 0) {
return mTrack->setAuxEffectSendLevel(level);
@@ -1834,6 +1924,7 @@
status_t MediaPlayerService::AudioOutput::attachAuxEffect(int effectId)
{
ALOGV("attachAuxEffect(%d)", effectId);
+ Mutex::Autolock lock(mLock);
mAuxEffectId = effectId;
if (mTrack != 0) {
return mTrack->attachAuxEffect(effectId);
@@ -1846,6 +1937,7 @@
int event, void *cookie, void *info) {
//ALOGV("callbackwrapper");
CallbackData *data = (CallbackData*)cookie;
+ // lock to ensure we aren't caught in the middle of a track switch.
data->lock();
AudioOutput *me = data->getOutput();
AudioTrack::Buffer *buffer = (AudioTrack::Buffer *)info;
@@ -1915,11 +2007,13 @@
int MediaPlayerService::AudioOutput::getSessionId() const
{
+ Mutex::Autolock lock(mLock);
return mSessionId;
}
uint32_t MediaPlayerService::AudioOutput::getSampleRate() const
{
+ Mutex::Autolock lock(mLock);
if (mTrack == 0) return 0;
return mTrack->getSampleRate();
}
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 7527506..9e6ca52 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -132,7 +132,8 @@
static void setMinBufferCount();
static void CallbackWrapper(
int event, void *me, void *info);
- void deleteRecycledTrack();
+ void deleteRecycledTrack_l();
+ void close_l();
sp<AudioTrack> mTrack;
sp<AudioTrack> mRecycledTrack;
@@ -148,32 +149,47 @@
AudioPlaybackRate mPlaybackRate;
uint32_t mSampleRateHz; // sample rate of the content, as set in open()
float mMsecsPerFrame;
+ size_t mFrameSize;
int mSessionId;
int mUid;
int mPid;
float mSendLevel;
int mAuxEffectId;
+ audio_output_flags_t mFlags;
+ mutable Mutex mLock;
+
+ // static variables below not protected by mutex
static bool mIsOnEmulator;
static int mMinBufferCount; // 12 for emulator; otherwise 4
- audio_output_flags_t mFlags;
// CallbackData is what is passed to the AudioTrack as the "user" data.
// We need to be able to target this to a different Output on the fly,
// so we can't use the Output itself for this.
class CallbackData {
+ friend AudioOutput;
public:
CallbackData(AudioOutput *cookie) {
mData = cookie;
mSwitching = false;
}
- AudioOutput * getOutput() { return mData;}
+ AudioOutput * getOutput() const { return mData; }
void setOutput(AudioOutput* newcookie) { mData = newcookie; }
// lock/unlock are used by the callback before accessing the payload of this object
- void lock() { mLock.lock(); }
- void unlock() { mLock.unlock(); }
- // beginTrackSwitch/endTrackSwitch are used when this object is being handed over
+ void lock() const { mLock.lock(); }
+ void unlock() const { mLock.unlock(); }
+
+ // tryBeginTrackSwitch/endTrackSwitch are used when the CallbackData is handed over
// to the next sink.
- void beginTrackSwitch() { mLock.lock(); mSwitching = true; }
+
+ // tryBeginTrackSwitch() returns true only if it obtains the lock.
+ bool tryBeginTrackSwitch() {
+ LOG_ALWAYS_FATAL_IF(mSwitching, "tryBeginTrackSwitch() already called");
+ if (mLock.tryLock() != OK) {
+ return false;
+ }
+ mSwitching = true;
+ return true;
+ }
void endTrackSwitch() {
if (mSwitching) {
mLock.unlock();
@@ -182,7 +198,7 @@
}
private:
AudioOutput * mData;
- mutable Mutex mLock;
+ mutable Mutex mLock; // a recursive mutex might make this unnecessary.
bool mSwitching;
DISALLOW_EVIL_CONSTRUCTORS(CallbackData);
};
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 52fce34..8f1e050 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1252,11 +1252,9 @@
if (client == 0) {
return;
}
- bool clientAdded = false;
+ pid_t pid = IPCThreadState::self()->getCallingPid();
{
Mutex::Autolock _cl(mClientLock);
-
- pid_t pid = IPCThreadState::self()->getCallingPid();
if (mNotificationClients.indexOfKey(pid) < 0) {
sp<NotificationClient> notificationClient = new NotificationClient(this,
client,
@@ -1267,22 +1265,19 @@
sp<IBinder> binder = IInterface::asBinder(client);
binder->linkToDeath(notificationClient);
- clientAdded = true;
}
}
// mClientLock should not be held here because ThreadBase::sendIoConfigEvent() will lock the
// ThreadBase mutex and the locking order is ThreadBase::mLock then AudioFlinger::mClientLock.
- if (clientAdded) {
- // the config change is always sent from playback or record threads to avoid deadlock
- // with AudioSystem::gLock
- for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
- mPlaybackThreads.valueAt(i)->sendIoConfigEvent(AUDIO_OUTPUT_OPENED);
- }
+ // the config change is always sent from playback or record threads to avoid deadlock
+ // with AudioSystem::gLock
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+ mPlaybackThreads.valueAt(i)->sendIoConfigEvent(AUDIO_OUTPUT_OPENED, pid);
+ }
- for (size_t i = 0; i < mRecordThreads.size(); i++) {
- mRecordThreads.valueAt(i)->sendIoConfigEvent(AUDIO_INPUT_OPENED);
- }
+ for (size_t i = 0; i < mRecordThreads.size(); i++) {
+ mRecordThreads.valueAt(i)->sendIoConfigEvent(AUDIO_INPUT_OPENED, pid);
}
}
@@ -1316,12 +1311,15 @@
}
void AudioFlinger::ioConfigChanged(audio_io_config_event event,
- const sp<AudioIoDescriptor>& ioDesc)
+ const sp<AudioIoDescriptor>& ioDesc,
+ pid_t pid)
{
Mutex::Autolock _l(mClientLock);
size_t size = mNotificationClients.size();
for (size_t i = 0; i < size; i++) {
- mNotificationClients.valueAt(i)->audioFlingerClient()->ioConfigChanged(event, ioDesc);
+ if ((pid == 0) || (mNotificationClients.keyAt(i) == pid)) {
+ mNotificationClients.valueAt(i)->audioFlingerClient()->ioConfigChanged(event, ioDesc);
+ }
}
}
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index d087ced..4f7e27d 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -559,7 +559,8 @@
float streamVolume_l(audio_stream_type_t stream) const
{ return mStreamTypes[stream].volume; }
void ioConfigChanged(audio_io_config_event event,
- const sp<AudioIoDescriptor>& ioDesc);
+ const sp<AudioIoDescriptor>& ioDesc,
+ pid_t pid = 0);
// Allocate an audio_io_handle_t, session ID, effect ID, or audio_module_handle_t.
// They all share the same ID space, but the namespaces are actually independent
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index d3ea9d8..0880c5d 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -532,7 +532,8 @@
// RecordThread::readInputParameters_l()
//FIXME: mStandby should be true here. Is this some kind of hack?
mStandby(false), mOutDevice(outDevice), mInDevice(inDevice),
- mPrevInDevice(AUDIO_DEVICE_NONE), mAudioSource(AUDIO_SOURCE_DEFAULT), mId(id),
+ mPrevOutDevice(AUDIO_DEVICE_NONE), mPrevInDevice(AUDIO_DEVICE_NONE),
+ mAudioSource(AUDIO_SOURCE_DEFAULT), mId(id),
// mName will be set by concrete (non-virtual) subclass
mDeathRecipient(new PMDeathRecipient(this)),
mSystemReady(systemReady)
@@ -627,16 +628,16 @@
return status;
}
-void AudioFlinger::ThreadBase::sendIoConfigEvent(audio_io_config_event event)
+void AudioFlinger::ThreadBase::sendIoConfigEvent(audio_io_config_event event, pid_t pid)
{
Mutex::Autolock _l(mLock);
- sendIoConfigEvent_l(event);
+ sendIoConfigEvent_l(event, pid);
}
// sendIoConfigEvent_l() must be called with ThreadBase::mLock held
-void AudioFlinger::ThreadBase::sendIoConfigEvent_l(audio_io_config_event event)
+void AudioFlinger::ThreadBase::sendIoConfigEvent_l(audio_io_config_event event, pid_t pid)
{
- sp<ConfigEvent> configEvent = (ConfigEvent *)new IoConfigEvent(event);
+ sp<ConfigEvent> configEvent = (ConfigEvent *)new IoConfigEvent(event, pid);
sendConfigEvent_l(configEvent);
}
@@ -706,7 +707,7 @@
} break;
case CFG_EVENT_IO: {
IoConfigEventData *data = (IoConfigEventData *)event->mData.get();
- ioConfigChanged(data->mEvent);
+ ioConfigChanged(data->mEvent, data->mPid);
} break;
case CFG_EVENT_SET_PARAMETER: {
SetParameterConfigEventData *data = (SetParameterConfigEventData *)event->mData.get();
@@ -1999,7 +2000,7 @@
return out_s8;
}
-void AudioFlinger::PlaybackThread::ioConfigChanged(audio_io_config_event event) {
+void AudioFlinger::PlaybackThread::ioConfigChanged(audio_io_config_event event, pid_t pid) {
sp<AudioIoDescriptor> desc = new AudioIoDescriptor();
ALOGV("PlaybackThread::ioConfigChanged, thread %p, event %d", this, event);
@@ -2021,7 +2022,7 @@
default:
break;
}
- mAudioFlinger->ioConfigChanged(event, desc);
+ mAudioFlinger->ioConfigChanged(event, desc, pid);
}
void AudioFlinger::PlaybackThread::writeCallback()
@@ -3133,7 +3134,10 @@
for (size_t i = 0; i < mEffectChains.size(); i++) {
mEffectChains[i]->setDevice_l(type);
}
- bool configChanged = mOutDevice != type;
+
+ // mPrevOutDevice is the latest device set by createAudioPatch_l(). It is not set when
+ // the thread is created so that the first patch creation triggers an ioConfigChanged callback
+ bool configChanged = mPrevOutDevice != type;
mOutDevice = type;
mPatch = *patch;
@@ -3163,6 +3167,7 @@
*handle = AUDIO_PATCH_HANDLE_NONE;
}
if (configChanged) {
+ mPrevOutDevice = type;
sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
}
return status;
@@ -6868,7 +6873,7 @@
return out_s8;
}
-void AudioFlinger::RecordThread::ioConfigChanged(audio_io_config_event event) {
+void AudioFlinger::RecordThread::ioConfigChanged(audio_io_config_event event, pid_t pid) {
sp<AudioIoDescriptor> desc = new AudioIoDescriptor();
desc->mIoHandle = mId;
@@ -6888,7 +6893,7 @@
default:
break;
}
- mAudioFlinger->ioConfigChanged(event, desc);
+ mAudioFlinger->ioConfigChanged(event, desc, pid);
}
void AudioFlinger::RecordThread::readInputParameters_l()
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 0783371..46ac300 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -104,21 +104,22 @@
class IoConfigEventData : public ConfigEventData {
public:
- IoConfigEventData(audio_io_config_event event) :
- mEvent(event) {}
+ IoConfigEventData(audio_io_config_event event, pid_t pid) :
+ mEvent(event), mPid(pid) {}
virtual void dump(char *buffer, size_t size) {
snprintf(buffer, size, "IO event: event %d\n", mEvent);
}
const audio_io_config_event mEvent;
+ const pid_t mPid;
};
class IoConfigEvent : public ConfigEvent {
public:
- IoConfigEvent(audio_io_config_event event) :
+ IoConfigEvent(audio_io_config_event event, pid_t pid) :
ConfigEvent(CFG_EVENT_IO) {
- mData = new IoConfigEventData(event);
+ mData = new IoConfigEventData(event, pid);
}
virtual ~IoConfigEvent() {}
};
@@ -255,13 +256,13 @@
status_t& status) = 0;
virtual status_t setParameters(const String8& keyValuePairs);
virtual String8 getParameters(const String8& keys) = 0;
- virtual void ioConfigChanged(audio_io_config_event event) = 0;
+ virtual void ioConfigChanged(audio_io_config_event event, pid_t pid = 0) = 0;
// sendConfigEvent_l() must be called with ThreadBase::mLock held
// Can temporarily release the lock if waiting for a reply from
// processConfigEvents_l().
status_t sendConfigEvent_l(sp<ConfigEvent>& event);
- void sendIoConfigEvent(audio_io_config_event event);
- void sendIoConfigEvent_l(audio_io_config_event event);
+ void sendIoConfigEvent(audio_io_config_event event, pid_t pid = 0);
+ void sendIoConfigEvent_l(audio_io_config_event event, pid_t pid = 0);
void sendPrioConfigEvent(pid_t pid, pid_t tid, int32_t prio);
void sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio);
status_t sendSetParameterConfigEvent_l(const String8& keyValuePair);
@@ -436,6 +437,7 @@
bool mStandby; // Whether thread is currently in standby.
audio_devices_t mOutDevice; // output device
audio_devices_t mInDevice; // input device
+ audio_devices_t mPrevOutDevice; // previous output device
audio_devices_t mPrevInDevice; // previous input device
struct audio_patch mPatch;
audio_source_t mAudioSource;
@@ -572,7 +574,7 @@
{ return android_atomic_acquire_load(&mSuspended) > 0; }
virtual String8 getParameters(const String8& keys);
- virtual void ioConfigChanged(audio_io_config_event event);
+ virtual void ioConfigChanged(audio_io_config_event event, pid_t pid = 0);
status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames);
// FIXME rename mixBuffer() to sinkBuffer() and remove int16_t* dependency.
// Consider also removing and passing an explicit mMainBuffer initialization
@@ -1254,7 +1256,7 @@
status_t& status);
virtual void cacheParameters_l() {}
virtual String8 getParameters(const String8& keys);
- virtual void ioConfigChanged(audio_io_config_event event);
+ virtual void ioConfigChanged(audio_io_config_event event, pid_t pid = 0);
virtual status_t createAudioPatch_l(const struct audio_patch *patch,
audio_patch_handle_t *handle);
virtual status_t releaseAudioPatch_l(const audio_patch_handle_t handle);
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index 4eef02f2..4b73e3c 100755
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -37,8 +37,9 @@
* A device mask for all audio input and output devices where matching inputs/outputs on device
* type alone is not enough: the address must match too
*/
-#define APM_AUDIO_DEVICE_MATCH_ADDRESS_ALL (AUDIO_DEVICE_IN_REMOTE_SUBMIX | \
- AUDIO_DEVICE_OUT_REMOTE_SUBMIX)
+#define APM_AUDIO_DEVICE_OUT_MATCH_ADDRESS_ALL (AUDIO_DEVICE_OUT_REMOTE_SUBMIX)
+
+#define APM_AUDIO_DEVICE_IN_MATCH_ADDRESS_ALL (AUDIO_DEVICE_IN_REMOTE_SUBMIX)
/**
* Check if the state given correspond to an in call state.
@@ -80,5 +81,8 @@
*/
static inline bool device_distinguishes_on_address(audio_devices_t device)
{
- return ((device & APM_AUDIO_DEVICE_MATCH_ADDRESS_ALL & ~AUDIO_DEVICE_BIT_IN) != 0);
+ return (((device & AUDIO_DEVICE_BIT_IN) != 0) &&
+ ((~AUDIO_DEVICE_BIT_IN & device & APM_AUDIO_DEVICE_IN_MATCH_ADDRESS_ALL) != 0)) ||
+ (((device & AUDIO_DEVICE_BIT_IN) == 0) &&
+ ((device & APM_AUDIO_DEVICE_OUT_MATCH_ADDRESS_ALL) != 0));
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index de204e5..6d99640 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1076,6 +1076,9 @@
beaconMuteLatency = handleEventForBeacon(STARTING_OUTPUT);
}
+ // check active before incrementing usage count
+ bool force = !outputDesc->isActive();
+
// increment usage count for this stream on the requested output:
// NOTE that the usage count is the same for duplicated output and hardware output which is
// necessary for a correct control of hardware output routing by startOutput() and stopOutput()
@@ -1091,7 +1094,6 @@
(strategy == STRATEGY_SONIFICATION_RESPECTFUL) ||
(beaconMuteLatency > 0);
uint32_t waitMs = beaconMuteLatency;
- bool force = false;
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i);
if (desc != outputDesc) {