Fix various AAudio device selection issues

Bug: 65292224
- Audio policy manager should not use an unavailable device when an explicit
route is requested. This causes a device selection made by a client to
become sticky after device disconnection.

Bug: 64945845
- Remove spurious device change callback occuring after registering a
new client to audio server by creating a specific configuration event
for client registration.
- Do not keep strong references to device callback interfaces in
AudioTrack, AudioRecord and AudioSystem.
- Do not update selected device in AudioTrack and AudioRecord when
not active as the new device selection on the stream is because of other
clients activity which is not relevant to an inactive client.

Bug: 65693340
- Fix missing increment of SessionRoute ref count in getInputForAttr() for
MMAP inputs

Test: AAudio CTS tests

Change-Id: I2a01b02e8b064d352004f6065495fd99aee55745
gugelfrei
Eric Laurent 7 years ago
parent b92c988ffc
commit ad2e7b902c

@ -120,7 +120,7 @@ AudioRecord::~AudioRecord()
}
// 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);
AudioSystem::removeAudioDeviceCallback(this, mInput);
}
IInterface::asBinder(mAudioRecord)->unlinkToDeath(mDeathNotifier, this);
mAudioRecord.clear();
@ -499,19 +499,26 @@ audio_port_handle_t AudioRecord::getInputDevice() {
return mSelectedDeviceId;
}
// must be called with mLock held
void AudioRecord::updateRoutedDeviceId_l()
{
// if the record is inactive, do not update actual device as the input stream maybe routed
// from a device not relevant to this client because of other active use cases.
if (!mActive) {
return;
}
if (mInput != AUDIO_IO_HANDLE_NONE) {
audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mInput);
if (deviceId != AUDIO_PORT_HANDLE_NONE) {
mRoutedDeviceId = deviceId;
}
}
}
audio_port_handle_t AudioRecord::getRoutedDeviceId() {
AutoMutex lock(mLock);
if (mInput == AUDIO_IO_HANDLE_NONE) {
return AUDIO_PORT_HANDLE_NONE;
}
// if the input stream does not have an active audio patch, use either the device initially
// selected by audio policy manager or the last routed device
audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mInput);
if (deviceId == AUDIO_PORT_HANDLE_NONE) {
deviceId = mRoutedDeviceId;
}
mRoutedDeviceId = deviceId;
return deviceId;
updateRoutedDeviceId_l();
return mRoutedDeviceId;
}
// -------------------------------------------------------------------------
@ -537,9 +544,6 @@ status_t AudioRecord::openRecord_l(const Modulo<uint32_t> &epoch, const String16
return NO_INIT;
}
if (mDeviceCallback != 0 && mInput != AUDIO_IO_HANDLE_NONE) {
AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
}
audio_io_handle_t input;
// mFlags (not mOrigFlags) is modified depending on whether fast request is accepted.
@ -744,6 +748,15 @@ status_t AudioRecord::openRecord_l(const Modulo<uint32_t> &epoch, const String16
}
mNotificationFramesAct = (uint32_t) notificationFrames;
//mInput != input includes the case where mInput == AUDIO_IO_HANDLE_NONE for first creation
if (mDeviceCallback != 0 && mInput != input) {
if (mInput != AUDIO_IO_HANDLE_NONE) {
AudioSystem::removeAudioDeviceCallback(this, mInput);
}
AudioSystem::addAudioDeviceCallback(this, input);
}
// We retain a copy of the I/O handle, but don't own the reference
mInput = input;
mRefreshRemaining = true;
@ -763,10 +776,6 @@ status_t AudioRecord::openRecord_l(const Modulo<uint32_t> &epoch, const String16
mDeathNotifier = new DeathNotifier(this);
IInterface::asBinder(mAudioRecord)->linkToDeath(mDeathNotifier, this);
if (mDeviceCallback != 0) {
AudioSystem::addAudioDeviceCallback(mDeviceCallback, mInput);
}
return NO_ERROR;
// End of retry loop.
@ -1238,7 +1247,7 @@ status_t AudioRecord::addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCa
return BAD_VALUE;
}
AutoMutex lock(mLock);
if (mDeviceCallback == callback) {
if (mDeviceCallback.unsafe_get() == callback.get()) {
ALOGW("%s adding same callback!", __FUNCTION__);
return INVALID_OPERATION;
}
@ -1246,9 +1255,9 @@ status_t AudioRecord::addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCa
if (mInput != AUDIO_IO_HANDLE_NONE) {
if (mDeviceCallback != 0) {
ALOGW("%s callback already present!", __FUNCTION__);
AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
AudioSystem::removeAudioDeviceCallback(this, mInput);
}
status = AudioSystem::addAudioDeviceCallback(callback, mInput);
status = AudioSystem::addAudioDeviceCallback(this, mInput);
}
mDeviceCallback = callback;
return status;
@ -1262,17 +1271,38 @@ status_t AudioRecord::removeAudioDeviceCallback(
return BAD_VALUE;
}
AutoMutex lock(mLock);
if (mDeviceCallback != callback) {
if (mDeviceCallback.unsafe_get() != callback.get()) {
ALOGW("%s removing different callback!", __FUNCTION__);
return INVALID_OPERATION;
}
mDeviceCallback.clear();
if (mInput != AUDIO_IO_HANDLE_NONE) {
AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
AudioSystem::removeAudioDeviceCallback(this, mInput);
}
mDeviceCallback = 0;
return NO_ERROR;
}
void AudioRecord::onAudioDeviceUpdate(audio_io_handle_t audioIo,
audio_port_handle_t deviceId)
{
sp<AudioSystem::AudioDeviceCallback> callback;
{
AutoMutex lock(mLock);
if (audioIo != mInput) {
return;
}
callback = mDeviceCallback.promote();
// only update device if the record is active as route changes due to other use cases are
// irrelevant for this client
if (mActive) {
mRoutedDeviceId = deviceId;
}
}
if (callback.get() != nullptr) {
callback->onAudioDeviceUpdate(mInput, mRoutedDeviceId);
}
}
// =========================================================================
void AudioRecord::DeathNotifier::binderDied(const wp<IBinder>& who __unused)

@ -493,14 +493,16 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(audio_io_config_event even
if (ioDesc == 0 || ioDesc->mIoHandle == AUDIO_IO_HANDLE_NONE) return;
audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE;
Vector < sp<AudioDeviceCallback> > callbacks;
Vector < wp<AudioDeviceCallback> > callbacks;
{
Mutex::Autolock _l(mLock);
switch (event) {
case AUDIO_OUTPUT_OPENED:
case AUDIO_INPUT_OPENED: {
case AUDIO_OUTPUT_REGISTERED:
case AUDIO_INPUT_OPENED:
case AUDIO_INPUT_REGISTERED: {
sp<AudioIoDescriptor> oldDesc = getIoDescriptor_l(ioDesc->mIoHandle);
if (oldDesc == 0) {
mIoDescriptors.add(ioDesc->mIoHandle, ioDesc);
@ -511,13 +513,19 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(audio_io_config_event even
if (ioDesc->getDeviceId() != AUDIO_PORT_HANDLE_NONE) {
deviceId = ioDesc->getDeviceId();
ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle);
if (ioIndex >= 0) {
callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
if (event == AUDIO_OUTPUT_OPENED || event == AUDIO_INPUT_OPENED) {
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",
ALOGV("ioConfigChanged() new %s %s %d samplingRate %u, format %#x channel mask %#x "
"frameCount %zu deviceId %d",
event == AUDIO_OUTPUT_OPENED || event == AUDIO_OUTPUT_REGISTERED ?
"output" : "input",
event == AUDIO_OUTPUT_OPENED || event == AUDIO_INPUT_OPENED ?
"opened" : "registered",
ioDesc->mIoHandle, ioDesc->mSamplingRate, ioDesc->mFormat, ioDesc->mChannelMask,
ioDesc->mFrameCount, ioDesc->getDeviceId());
} break;
@ -563,9 +571,23 @@ void AudioSystem::AudioFlingerClient::ioConfigChanged(audio_io_config_event even
} break;
}
}
bool callbackRemoved = false;
// callbacks.size() != 0 => ioDesc->mIoHandle and deviceId are valid
for (size_t i = 0; i < callbacks.size(); i++) {
callbacks[i]->onAudioDeviceUpdate(ioDesc->mIoHandle, deviceId);
for (size_t i = 0; i < callbacks.size(); ) {
sp<AudioDeviceCallback> callback = callbacks[i].promote();
if (callback.get() != nullptr) {
callback->onAudioDeviceUpdate(ioDesc->mIoHandle, deviceId);
i++;
} else {
callbacks.removeAt(i);
callbackRemoved = true;
}
}
// clean up callback list while we are here if some clients have disappeared without
// unregistering their callback
if (callbackRemoved) {
Mutex::Autolock _l(mLock);
mAudioDeviceCallbacks.replaceValueFor(ioDesc->mIoHandle, callbacks);
}
}
@ -618,17 +640,17 @@ sp<AudioIoDescriptor> AudioSystem::AudioFlingerClient::getIoDescriptor(audio_io_
}
status_t AudioSystem::AudioFlingerClient::addAudioDeviceCallback(
const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
{
Mutex::Autolock _l(mLock);
Vector < sp<AudioDeviceCallback> > callbacks;
Vector < wp<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) {
if (callbacks[cbIndex].unsafe_get() == callback.unsafe_get()) {
return INVALID_OPERATION;
}
}
@ -639,18 +661,18 @@ status_t AudioSystem::AudioFlingerClient::addAudioDeviceCallback(
}
status_t AudioSystem::AudioFlingerClient::removeAudioDeviceCallback(
const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
const wp<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);
Vector < wp<AudioDeviceCallback> > callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
size_t cbIndex;
for (cbIndex = 0; cbIndex < callbacks.size(); cbIndex++) {
if (callbacks[cbIndex] == callback) {
if (callbacks[cbIndex].unsafe_get() == callback.unsafe_get()) {
break;
}
}
@ -1128,7 +1150,7 @@ status_t AudioSystem::removeAudioPortCallback(const sp<AudioPortCallback>& callb
}
status_t AudioSystem::addAudioDeviceCallback(
const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
{
const sp<AudioFlingerClient> afc = getAudioFlingerClient();
if (afc == 0) {
@ -1145,7 +1167,7 @@ status_t AudioSystem::addAudioDeviceCallback(
}
status_t AudioSystem::removeAudioDeviceCallback(
const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
{
const sp<AudioFlingerClient> afc = getAudioFlingerClient();
if (afc == 0) {

@ -276,7 +276,7 @@ AudioTrack::~AudioTrack()
}
// 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);
AudioSystem::removeAudioDeviceCallback(this, mOutput);
}
IInterface::asBinder(mAudioTrack)->unlinkToDeath(mDeathNotifier, this);
mAudioTrack.clear();
@ -1229,19 +1229,26 @@ 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;
// must be called with mLock held
void AudioTrack::updateRoutedDeviceId_l()
{
// if the track is inactive, do not update actual device as the output stream maybe routed
// to a device not relevant to this client because of other active use cases.
if (mState != STATE_ACTIVE) {
return;
}
// if the output stream does not have an active audio patch, use either the device initially
// selected by audio policy manager or the last routed device
audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mOutput);
if (deviceId == AUDIO_PORT_HANDLE_NONE) {
deviceId = mRoutedDeviceId;
if (mOutput != AUDIO_IO_HANDLE_NONE) {
audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mOutput);
if (deviceId != AUDIO_PORT_HANDLE_NONE) {
mRoutedDeviceId = deviceId;
}
}
mRoutedDeviceId = deviceId;
return deviceId;
}
audio_port_handle_t AudioTrack::getRoutedDeviceId() {
AutoMutex lock(mLock);
updateRoutedDeviceId_l();
return mRoutedDeviceId;
}
status_t AudioTrack::attachAuxEffect(int effectId)
@ -1305,12 +1312,10 @@ 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;
bool callbackAdded = false;
// mFlags (not mOrigFlags) is modified depending on whether fast request is accepted.
// After fast request is denied, we will request again if IAudioTrack is re-created.
@ -1515,12 +1520,14 @@ status_t AudioTrack::createTrack_l()
sp<IMemory> iMem = track->getCblk();
if (iMem == 0) {
ALOGE("Could not get control block");
return NO_INIT;
status = NO_INIT;
goto release;
}
void *iMemPointer = iMem->pointer();
if (iMemPointer == NULL) {
ALOGE("Could not get control block pointer");
return NO_INIT;
status = NO_INIT;
goto release;
}
// invariant that mAudioTrack != 0 is true only after set() returns successfully
if (mAudioTrack != 0) {
@ -1582,6 +1589,15 @@ status_t AudioTrack::createTrack_l()
}
}
//mOutput != output includes the case where mOutput == AUDIO_IO_HANDLE_NONE for first creation
if (mDeviceCallback != 0 && mOutput != output) {
if (mOutput != AUDIO_IO_HANDLE_NONE) {
AudioSystem::removeAudioDeviceCallback(this, mOutput);
}
AudioSystem::addAudioDeviceCallback(this, output);
callbackAdded = true;
}
// We retain a copy of the I/O handle, but don't own the reference
mOutput = output;
mRefreshRemaining = true;
@ -1597,7 +1613,8 @@ status_t AudioTrack::createTrack_l()
buffers = mSharedBuffer->pointer();
if (buffers == NULL) {
ALOGE("Could not get buffer pointer");
return NO_INIT;
status = NO_INIT;
goto release;
}
}
@ -1642,15 +1659,15 @@ 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;
}
release:
AudioSystem::releaseOutput(output, streamType, mSessionId);
if (callbackAdded) {
// note: mOutput is always valid is callbackAdded is true
AudioSystem::removeAudioDeviceCallback(this, mOutput);
}
if (status == NO_ERROR) {
status = NO_INIT;
}
@ -2851,7 +2868,7 @@ status_t AudioTrack::addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCal
return BAD_VALUE;
}
AutoMutex lock(mLock);
if (mDeviceCallback == callback) {
if (mDeviceCallback.unsafe_get() == callback.get()) {
ALOGW("%s adding same callback!", __FUNCTION__);
return INVALID_OPERATION;
}
@ -2859,9 +2876,9 @@ status_t AudioTrack::addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCal
if (mOutput != AUDIO_IO_HANDLE_NONE) {
if (mDeviceCallback != 0) {
ALOGW("%s callback already present!", __FUNCTION__);
AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
AudioSystem::removeAudioDeviceCallback(this, mOutput);
}
status = AudioSystem::addAudioDeviceCallback(callback, mOutput);
status = AudioSystem::addAudioDeviceCallback(this, mOutput);
}
mDeviceCallback = callback;
return status;
@ -2875,17 +2892,39 @@ status_t AudioTrack::removeAudioDeviceCallback(
return BAD_VALUE;
}
AutoMutex lock(mLock);
if (mDeviceCallback != callback) {
if (mDeviceCallback.unsafe_get() != callback.get()) {
ALOGW("%s removing different callback!", __FUNCTION__);
return INVALID_OPERATION;
}
mDeviceCallback.clear();
if (mOutput != AUDIO_IO_HANDLE_NONE) {
AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
AudioSystem::removeAudioDeviceCallback(this, mOutput);
}
mDeviceCallback = 0;
return NO_ERROR;
}
void AudioTrack::onAudioDeviceUpdate(audio_io_handle_t audioIo,
audio_port_handle_t deviceId)
{
sp<AudioSystem::AudioDeviceCallback> callback;
{
AutoMutex lock(mLock);
if (audioIo != mOutput) {
return;
}
callback = mDeviceCallback.promote();
// only update device if the track is active as route changes due to other use cases are
// irrelevant for this client
if (mState == STATE_ACTIVE) {
mRoutedDeviceId = deviceId;
}
}
if (callback.get() != nullptr) {
callback->onAudioDeviceUpdate(mOutput, mRoutedDeviceId);
}
}
status_t AudioTrack::pendingDuration(int32_t *msec, ExtendedTimestamp::Location location)
{
if (msec == nullptr ||

@ -20,9 +20,11 @@
namespace android {
enum audio_io_config_event {
AUDIO_OUTPUT_REGISTERED,
AUDIO_OUTPUT_OPENED,
AUDIO_OUTPUT_CLOSED,
AUDIO_OUTPUT_CONFIG_CHANGED,
AUDIO_INPUT_REGISTERED,
AUDIO_INPUT_OPENED,
AUDIO_INPUT_CLOSED,
AUDIO_INPUT_CONFIG_CHANGED,

@ -33,7 +33,7 @@ class AudioRecordClientProxy;
// ----------------------------------------------------------------------------
class AudioRecord : public RefBase
class AudioRecord : public AudioSystem::AudioDeviceCallback
{
public:
@ -424,7 +424,12 @@ public:
/* 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.
* The device ID is relevant only if the AudioRecord is active.
* When the AudioRecord is inactive, the device ID returned can be either:
* - AUDIO_PORT_HANDLE_NONE if the AudioRecord is not attached to any output.
* - The device ID used before paused or stopped.
* - The device ID selected by audio policy manager of setOutputDevice() if the AudioRecord
* has not been started yet.
*
* Parameters:
* none.
@ -454,6 +459,10 @@ public:
status_t removeAudioDeviceCallback(
const sp<AudioSystem::AudioDeviceCallback>& callback);
// AudioSystem::AudioDeviceCallback> virtuals
virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
audio_port_handle_t deviceId);
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,
@ -561,6 +570,8 @@ private:
// FIXME enum is faster than strcmp() for parameter 'from'
status_t restoreRecord_l(const char *from);
void updateRoutedDeviceId_l();
sp<AudioRecordThread> mAudioRecordThread;
mutable Mutex mLock;
@ -665,7 +676,7 @@ private:
audio_port_handle_t mRoutedDeviceId; // Device actually selected by audio policy manager:
// May not match the app selection depending on other
// activity and connected devices
sp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
wp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
audio_port_handle_t mPortId; // unique ID allocated by audio policy
};

@ -370,9 +370,9 @@ public:
audio_port_handle_t deviceId) = 0;
};
static status_t addAudioDeviceCallback(const sp<AudioDeviceCallback>& callback,
static status_t addAudioDeviceCallback(const wp<AudioDeviceCallback>& callback,
audio_io_handle_t audioIo);
static status_t removeAudioDeviceCallback(const sp<AudioDeviceCallback>& callback,
static status_t removeAudioDeviceCallback(const wp<AudioDeviceCallback>& callback,
audio_io_handle_t audioIo);
static audio_port_handle_t getDeviceIdForIo(audio_io_handle_t audioIo);
@ -403,9 +403,9 @@ private:
const sp<AudioIoDescriptor>& ioDesc);
status_t addAudioDeviceCallback(const sp<AudioDeviceCallback>& callback,
status_t addAudioDeviceCallback(const wp<AudioDeviceCallback>& callback,
audio_io_handle_t audioIo);
status_t removeAudioDeviceCallback(const sp<AudioDeviceCallback>& callback,
status_t removeAudioDeviceCallback(const wp<AudioDeviceCallback>& callback,
audio_io_handle_t audioIo);
audio_port_handle_t getDeviceIdForIo(audio_io_handle_t audioIo);
@ -413,7 +413,7 @@ private:
private:
Mutex mLock;
DefaultKeyedVector<audio_io_handle_t, sp<AudioIoDescriptor> > mIoDescriptors;
DefaultKeyedVector<audio_io_handle_t, Vector < sp<AudioDeviceCallback> > >
DefaultKeyedVector<audio_io_handle_t, Vector < wp<AudioDeviceCallback> > >
mAudioDeviceCallbacks;
// cached values for recording getInputBufferSize() queries
size_t mInBuffSize; // zero indicates cache is invalid

@ -35,7 +35,7 @@ class StaticAudioTrackClientProxy;
// ----------------------------------------------------------------------------
class AudioTrack : public RefBase
class AudioTrack : public AudioSystem::AudioDeviceCallback
{
public:
@ -605,7 +605,11 @@ public:
/* 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.
* When the AudioTrack is inactive, the device ID returned can be either:
* - AUDIO_PORT_HANDLE_NONE if the AudioTrack is not attached to any output.
* - The device ID used before paused or stopped.
* - The device ID selected by audio policy manager of setOutputDevice() if the AudioTrack
* has not been started yet.
*
* Parameters:
* none.
@ -845,6 +849,12 @@ public:
status_t removeAudioDeviceCallback(
const sp<AudioSystem::AudioDeviceCallback>& callback);
// AudioSystem::AudioDeviceCallback> virtuals
virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
audio_port_handle_t deviceId);
/* Obtain the pending duration in milliseconds for playback of pure PCM
* (mixable without embedded timing) data remaining in AudioTrack.
*
@ -974,6 +984,8 @@ protected:
void restartIfDisabled();
void updateRoutedDeviceId_l();
// Next 4 fields may be changed if IAudioTrack is re-created, but always != 0
sp<IAudioTrack> mAudioTrack;
sp<IMemory> mCblkMemory;
@ -1165,7 +1177,7 @@ private:
uid_t mClientUid;
pid_t mClientPid;
sp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
wp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
audio_port_handle_t mPortId; // unique ID allocated by audio policy
};

@ -329,6 +329,11 @@ status_t AudioFlinger::openMmapStream(MmapStreamInterface::stream_direction_t di
thread->configure(attr, streamType, sessionId, callback, *deviceId, portId);
*handle = portId;
} else {
if (direction == MmapStreamInterface::DIRECTION_OUTPUT) {
AudioSystem::releaseOutput(io, streamType, sessionId);
} else {
AudioSystem::releaseInput(io, sessionId);
}
ret = NO_INIT;
}
@ -1397,11 +1402,11 @@ void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)
// 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);
mPlaybackThreads.valueAt(i)->sendIoConfigEvent(AUDIO_OUTPUT_REGISTERED, pid);
}
for (size_t i = 0; i < mRecordThreads.size(); i++) {
mRecordThreads.valueAt(i)->sendIoConfigEvent(AUDIO_INPUT_OPENED, pid);
mRecordThreads.valueAt(i)->sendIoConfigEvent(AUDIO_INPUT_REGISTERED, pid);
}
}

@ -2253,6 +2253,7 @@ void AudioFlinger::PlaybackThread::ioConfigChanged(audio_io_config_event event,
switch (event) {
case AUDIO_OUTPUT_OPENED:
case AUDIO_OUTPUT_REGISTERED:
case AUDIO_OUTPUT_CONFIG_CHANGED:
desc->mPatch = mPatch;
desc->mChannelMask = mChannelMask;
@ -7242,6 +7243,7 @@ void AudioFlinger::RecordThread::ioConfigChanged(audio_io_config_event event, pi
switch (event) {
case AUDIO_INPUT_OPENED:
case AUDIO_INPUT_REGISTERED:
case AUDIO_INPUT_CONFIG_CHANGED:
desc->mPatch = mPatch;
desc->mChannelMask = mChannelMask;
@ -7913,8 +7915,10 @@ void AudioFlinger::MmapThread::ioConfigChanged(audio_io_config_event event, pid_
switch (event) {
case AUDIO_INPUT_OPENED:
case AUDIO_INPUT_REGISTERED:
case AUDIO_INPUT_CONFIG_CHANGED:
case AUDIO_OUTPUT_OPENED:
case AUDIO_OUTPUT_REGISTERED:
case AUDIO_OUTPUT_CONFIG_CHANGED:
desc->mPatch = mPatch;
desc->mChannelMask = mChannelMask;

@ -1499,6 +1499,26 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
"session %d, flags %#x",
attr->source, config->sample_rate, config->format, config->channel_mask, session, flags);
status_t status = NO_ERROR;
// handle legacy remote submix case where the address was not always specified
String8 address = String8("");
audio_source_t halInputSource;
audio_source_t inputSource = attr->source;
AudioMix *policyMix = NULL;
DeviceVector inputDevices;
// Explicit routing?
sp<DeviceDescriptor> deviceDesc;
if (*selectedDeviceId != AUDIO_PORT_HANDLE_NONE) {
for (size_t i = 0; i < mAvailableInputDevices.size(); i++) {
if (mAvailableInputDevices[i]->getId() == *selectedDeviceId) {
deviceDesc = mAvailableInputDevices[i];
break;
}
}
}
mInputRoutes.addRoute(session, SessionRoute::STREAM_TYPE_NA, inputSource, deviceDesc, uid);
// special case for mmap capture: if an input IO handle is specified, we reuse this input if
// possible
if ((flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) == AUDIO_INPUT_FLAG_MMAP_NOIRQ &&
@ -1506,13 +1526,15 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
ssize_t index = mInputs.indexOfKey(*input);
if (index < 0) {
ALOGW("getInputForAttr() unknown MMAP input %d", *input);
return BAD_VALUE;
status = BAD_VALUE;
goto error;
}
sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
if (audioSession == 0) {
ALOGW("getInputForAttr() unknown session %d on input %d", session, *input);
return BAD_VALUE;
status = BAD_VALUE;
goto error;
}
// For MMAP mode, the first call to getInputForAttr() is made on behalf of audioflinger.
// The second call is for the first active client and sets the UID. Any further call
@ -1522,30 +1544,25 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
} else if (audioSession->uid() != uid) {
ALOGW("getInputForAttr() bad uid %d for session %d uid %d",
uid, session, audioSession->uid());
return INVALID_OPERATION;
status = INVALID_OPERATION;
goto error;
}
audioSession->changeOpenCount(1);
*inputType = API_INPUT_LEGACY;
if (*portId == AUDIO_PORT_HANDLE_NONE) {
*portId = AudioPort::getNextUniqueId();
}
DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromType(inputDesc->mDevice);
inputDevices = mAvailableInputDevices.getDevicesFromType(inputDesc->mDevice);
*selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId()
: AUDIO_PORT_HANDLE_NONE;
ALOGI("%s reusing MMAP input %d for session %d", __FUNCTION__, *input, session);
return NO_ERROR;
}
*input = AUDIO_IO_HANDLE_NONE;
*inputType = API_INPUT_INVALID;
audio_devices_t device;
// handle legacy remote submix case where the address was not always specified
String8 address = String8("");
audio_source_t inputSource = attr->source;
audio_source_t halInputSource;
AudioMix *policyMix = NULL;
if (inputSource == AUDIO_SOURCE_DEFAULT) {
inputSource = AUDIO_SOURCE_MIC;
}
@ -1556,23 +1573,13 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
*portId = AudioPort::getNextUniqueId();
}
// Explicit routing?
sp<DeviceDescriptor> deviceDesc;
if (*selectedDeviceId != AUDIO_PORT_HANDLE_NONE) {
for (size_t i = 0; i < mAvailableInputDevices.size(); i++) {
if (mAvailableInputDevices[i]->getId() == *selectedDeviceId) {
deviceDesc = mAvailableInputDevices[i];
break;
}
}
}
mInputRoutes.addRoute(session, SessionRoute::STREAM_TYPE_NA, inputSource, deviceDesc, uid);
audio_devices_t device;
if (inputSource == AUDIO_SOURCE_REMOTE_SUBMIX &&
strncmp(attr->tags, "addr=", strlen("addr=")) == 0) {
status_t ret = mPolicyMixes.getInputMixForAttr(*attr, &policyMix);
if (ret != NO_ERROR) {
return ret;
status = mPolicyMixes.getInputMixForAttr(*attr, &policyMix);
if (status != NO_ERROR) {
goto error;
}
*inputType = API_INPUT_MIX_EXT_POLICY_REROUTE;
device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
@ -1581,7 +1588,8 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
device = getDeviceAndMixForInputSource(inputSource, &policyMix);
if (device == AUDIO_DEVICE_NONE) {
ALOGW("getInputForAttr() could not find device for source %d", inputSource);
return BAD_VALUE;
status = BAD_VALUE;
goto error;
}
if (policyMix != NULL) {
address = policyMix->mDeviceAddress;
@ -1610,11 +1618,11 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
config->sample_rate, config->format, config->channel_mask, flags,
policyMix);
if (*input == AUDIO_IO_HANDLE_NONE) {
mInputRoutes.removeRoute(session);
return INVALID_OPERATION;
status = INVALID_OPERATION;
goto error;
}
DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromType(device);
inputDevices = mAvailableInputDevices.getDevicesFromType(device);
*selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId()
: AUDIO_PORT_HANDLE_NONE;
@ -1622,6 +1630,10 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
*input, *inputType, *selectedDeviceId);
return NO_ERROR;
error:
mInputRoutes.removeRoute(session);
return status;
}
@ -4926,12 +4938,13 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate
// scan the whole RouteMap, for each entry, convert the stream type to a strategy
// (getStrategy(stream)).
// if the strategy from the stream type in the RouteMap is the same as the argument above,
// and activity count is non-zero
// the device = the device from the descriptor in the RouteMap, and exit.
// and activity count is non-zero and the device in the route descriptor is available
// then select this device.
for (size_t routeIndex = 0; routeIndex < mOutputRoutes.size(); routeIndex++) {
sp<SessionRoute> route = mOutputRoutes.valueAt(routeIndex);
routing_strategy routeStrategy = getStrategy(route->mStreamType);
if ((routeStrategy == strategy) && route->isActive()) {
if ((routeStrategy == strategy) && route->isActive() &&
(mAvailableOutputDevices.indexOf(route->mDeviceDescriptor) >= 0)) {
return route->mDeviceDescriptor->type();
}
}
@ -5326,9 +5339,15 @@ audio_devices_t AudioPolicyManager::getDeviceAndMixForInputSource(audio_source_t
audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t inputSource)
{
// Routing
// Scan the whole RouteMap to see if we have an explicit route:
// if the input source in the RouteMap is the same as the argument above,
// and activity count is non-zero and the device in the route descriptor is available
// then select this device.
for (size_t routeIndex = 0; routeIndex < mInputRoutes.size(); routeIndex++) {
sp<SessionRoute> route = mInputRoutes.valueAt(routeIndex);
if (inputSource == route->mSource && route->isActive()) {
if ((inputSource == route->mSource) && route->isActive() &&
(mAvailableInputDevices.indexOf(route->mDeviceDescriptor) >= 0)) {
return route->mDeviceDescriptor->type();
}
}

Loading…
Cancel
Save