Fix various AAudio device selection issues am: ad2e7b902c

am: 282ca69583

Change-Id: I051d56560608444c47b5a827ef921b878e8f4a4e
gugelfrei
Eric Laurent 7 years ago committed by android-build-merger
commit 92197f86b1

@ -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.
@ -1239,7 +1248,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;
}
@ -1247,9 +1256,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;
@ -1263,17 +1272,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) {

@ -278,7 +278,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();
@ -1231,19 +1231,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)
@ -1307,12 +1314,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.
@ -1517,12 +1522,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) {
@ -1584,6 +1591,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;
@ -1599,7 +1615,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;
}
}
@ -1644,15 +1661,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;
}
@ -2853,7 +2870,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;
}
@ -2861,9 +2878,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;
@ -2877,17 +2894,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,

@ -36,7 +36,7 @@ class AudioRecordClientProxy;
// ----------------------------------------------------------------------------
class AudioRecord : public RefBase
class AudioRecord : public AudioSystem::AudioDeviceCallback
{
public:
@ -427,7 +427,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.
@ -457,6 +462,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,
@ -564,6 +573,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;
@ -668,7 +679,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;
@ -7247,6 +7248,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;
@ -7918,8 +7920,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;

@ -1444,6 +1444,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 &&
@ -1451,13 +1471,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
@ -1467,30 +1489,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;
}
@ -1501,23 +1518,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;
@ -1526,7 +1533,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;
@ -1555,11 +1563,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;
@ -1567,6 +1575,10 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
*input, *inputType, *selectedDeviceId);
return NO_ERROR;
error:
mInputRoutes.removeRoute(session);
return status;
}
@ -4683,12 +4695,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();
}
}
@ -5083,9 +5096,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