Merge "Add features for Automotive usecases."
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index f6078a2..a6cb9c0 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -152,7 +152,8 @@
return BAD_VALUE;
}
if (patch->num_sources == 0 || patch->num_sources > AUDIO_PATCH_PORTS_MAX ||
- patch->num_sinks == 0 || patch->num_sinks > AUDIO_PATCH_PORTS_MAX) {
+ (patch->num_sinks == 0 && patch->num_sources != 2) ||
+ patch->num_sinks > AUDIO_PATCH_PORTS_MAX) {
return BAD_VALUE;
}
// limit number of sources to 1 for now or 2 sources for special cross hw module case.
@@ -203,18 +204,18 @@
}
// manage patches requiring a software bridge
+ // - special patch request with 2 sources (reuse one existing output mix) OR
// - Device to device AND
// - source HW module != destination HW module OR
// - audio HAL version < 3.0
- // - special patch request with 2 sources (reuse one existing output mix)
- if ((patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE) &&
- ((patch->sinks[0].ext.device.hw_module != srcModule) ||
- (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0) ||
- (patch->num_sources == 2))) {
+ if ((patch->num_sources == 2) ||
+ ((patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE) &&
+ ((patch->sinks[0].ext.device.hw_module != srcModule) ||
+ (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0)))) {
if (patch->num_sources == 2) {
if (patch->sources[1].type != AUDIO_PORT_TYPE_MIX ||
- patch->sinks[0].ext.device.hw_module !=
- patch->sources[1].ext.mix.hw_module) {
+ (patch->num_sinks != 0 && patch->sinks[0].ext.device.hw_module !=
+ patch->sources[1].ext.mix.hw_module)) {
ALOGW("createAudioPatch() invalid source combination");
status = INVALID_OPERATION;
goto exit;
@@ -379,12 +380,16 @@
}
// create patch from playback thread output to sink device
- patch->mPlaybackThread->getAudioPortConfig(&subPatch.sources[0]);
- subPatch.sinks[0] = audioPatch->sinks[0];
- status = createAudioPatch(&subPatch, &patch->mPlaybackPatchHandle);
- if (status != NO_ERROR) {
+ if (audioPatch->num_sinks != 0) {
+ patch->mPlaybackThread->getAudioPortConfig(&subPatch.sources[0]);
+ subPatch.sinks[0] = audioPatch->sinks[0];
+ status = createAudioPatch(&subPatch, &patch->mPlaybackPatchHandle);
+ if (status != NO_ERROR) {
+ patch->mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+ return status;
+ }
+ } else {
patch->mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
- return status;
}
// use a pseudo LCM between input and output framecount
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 3b7167f..b9e7a8b 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -2548,7 +2548,7 @@
size_t size = mTracks.size();
for (size_t i = 0; i < size; i++) {
sp<Track> t = mTracks[i];
- if (t->streamType() == streamType) {
+ if (t->streamType() == streamType && t->isExternalTrack()) {
t->invalidate();
}
}
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index c1e7bc0..7cf44dc 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -225,7 +225,8 @@
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
- audio_io_handle_t *handle) = 0;
+ audio_io_handle_t *handle,
+ uid_t uid) = 0;
virtual status_t stopAudioSource(audio_io_handle_t handle) = 0;
};
diff --git a/services/audiopolicy/common/managerdefinitions/Android.mk b/services/audiopolicy/common/managerdefinitions/Android.mk
index 8728ff3..6cd8b40 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.mk
+++ b/services/audiopolicy/common/managerdefinitions/Android.mk
@@ -17,6 +17,7 @@
src/ConfigParsingUtils.cpp \
src/SoundTriggerSession.cpp \
src/SessionRoute.cpp \
+ src/AudioSourceDescriptor.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 50f622d..f8439be 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -22,12 +22,14 @@
#include <utils/Timers.h>
#include <utils/KeyedVector.h>
#include <system/audio.h>
+#include "AudioSourceDescriptor.h"
namespace android {
class IOProfile;
class AudioMix;
class AudioPolicyClientInterface;
+class DeviceDescriptor;
// descriptor for audio outputs. Used to maintain current configuration of each opened audio output
// and keep track of the usage of this output by each audio stream type.
@@ -126,6 +128,31 @@
uint32_t mGlobalRefCount; // non-stream-specific ref count
};
+// Audio output driven by an input device directly.
+class HwAudioOutputDescriptor: public AudioOutputDescriptor
+{
+public:
+ HwAudioOutputDescriptor(const sp<AudioSourceDescriptor>& source,
+ AudioPolicyClientInterface *clientInterface);
+ virtual ~HwAudioOutputDescriptor() {}
+
+ status_t dump(int fd);
+
+ virtual audio_devices_t supportedDevices();
+ virtual bool setVolume(float volume,
+ audio_stream_type_t stream,
+ audio_devices_t device,
+ uint32_t delayMs,
+ bool force);
+
+ virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
+ const struct audio_port_config *srcConfig = NULL) const;
+ virtual void toAudioPort(struct audio_port *port) const;
+
+ const sp<AudioSourceDescriptor> mSource;
+
+};
+
class SwAudioOutputCollection :
public DefaultKeyedVector< audio_io_handle_t, sp<SwAudioOutputDescriptor> >
{
@@ -160,4 +187,19 @@
status_t dump(int fd) const;
};
+class HwAudioOutputCollection :
+ public DefaultKeyedVector< audio_io_handle_t, sp<HwAudioOutputDescriptor> >
+{
+public:
+ bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
+
+ /**
+ * return true if any output is playing anything besides the stream to ignore
+ */
+ bool isAnyOutputActive(audio_stream_type_t streamToIgnore) const;
+
+ status_t dump(int fd) const;
+};
+
+
}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioSourceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioSourceDescriptor.h
new file mode 100644
index 0000000..7e1e24d
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioSourceDescriptor.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <system/audio.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+#include <RoutingStrategy.h>
+#include <AudioPatch.h>
+
+namespace android {
+
+class SwAudioOutputDescriptor;
+class HwAudioOutputDescriptor;
+class DeviceDescriptor;
+
+class AudioSourceDescriptor: public RefBase
+{
+public:
+ AudioSourceDescriptor(const sp<DeviceDescriptor> device, const audio_attributes_t *attributes,
+ uid_t uid) :
+ mDevice(device), mAttributes(*attributes), mUid(uid) {}
+ virtual ~AudioSourceDescriptor() {}
+
+ audio_patch_handle_t getHandle() const { return mPatchDesc->mHandle; }
+
+ status_t dump(int fd);
+
+ const sp<DeviceDescriptor> mDevice;
+ const audio_attributes_t mAttributes;
+ uid_t mUid;
+ sp<AudioPatch> mPatchDesc;
+ wp<SwAudioOutputDescriptor> mSwOutput;
+ wp<HwAudioOutputDescriptor> mHwOutput;
+};
+
+class AudioSourceCollection :
+ public DefaultKeyedVector< audio_patch_handle_t, sp<AudioSourceDescriptor> >
+{
+public:
+ status_t dump(int fd) const;
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index a278375..17f2b92 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -220,8 +220,8 @@
}
// SwAudioOutputDescriptor implementation
-SwAudioOutputDescriptor::SwAudioOutputDescriptor(
- const sp<IOProfile>& profile, AudioPolicyClientInterface *clientInterface)
+SwAudioOutputDescriptor::SwAudioOutputDescriptor(const sp<IOProfile>& profile,
+ AudioPolicyClientInterface *clientInterface)
: AudioOutputDescriptor(profile, clientInterface),
mProfile(profile), mIoHandle(0), mLatency(0),
mFlags((audio_output_flags_t)0), mPolicyMix(NULL),
@@ -388,8 +388,64 @@
return changed;
}
-// SwAudioOutputCollection implementation
+// HwAudioOutputDescriptor implementation
+HwAudioOutputDescriptor::HwAudioOutputDescriptor(const sp<AudioSourceDescriptor>& source,
+ AudioPolicyClientInterface *clientInterface)
+ : AudioOutputDescriptor(source->mDevice, clientInterface),
+ mSource(source)
+{
+}
+status_t HwAudioOutputDescriptor::dump(int fd)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ AudioOutputDescriptor::dump(fd);
+
+ snprintf(buffer, SIZE, "Source:\n");
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+ mSource->dump(fd);
+
+ return NO_ERROR;
+}
+
+audio_devices_t HwAudioOutputDescriptor::supportedDevices()
+{
+ return mDevice;
+}
+
+void HwAudioOutputDescriptor::toAudioPortConfig(
+ struct audio_port_config *dstConfig,
+ const struct audio_port_config *srcConfig) const
+{
+ mSource->mDevice->toAudioPortConfig(dstConfig, srcConfig);
+}
+
+void HwAudioOutputDescriptor::toAudioPort(
+ struct audio_port *port) const
+{
+ mSource->mDevice->toAudioPort(port);
+}
+
+
+bool HwAudioOutputDescriptor::setVolume(float volume,
+ audio_stream_type_t stream,
+ audio_devices_t device,
+ uint32_t delayMs,
+ bool force)
+{
+ bool changed = AudioOutputDescriptor::setVolume(volume, stream, device, delayMs, force);
+
+ if (changed) {
+ // TODO: use gain controller on source device if any to adjust volume
+ }
+ return changed;
+}
+
+// SwAudioOutputCollection implementation
bool SwAudioOutputCollection::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
{
nsecs_t sysTime = systemTime();
@@ -494,4 +550,49 @@
return NO_ERROR;
}
+// HwAudioOutputCollection implementation
+bool HwAudioOutputCollection::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
+{
+ nsecs_t sysTime = systemTime();
+ for (size_t i = 0; i < this->size(); i++) {
+ const sp<HwAudioOutputDescriptor> outputDesc = this->valueAt(i);
+ if (outputDesc->isStreamActive(stream, inPastMs, sysTime)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool HwAudioOutputCollection::isAnyOutputActive(audio_stream_type_t streamToIgnore) const
+{
+ for (size_t s = 0 ; s < AUDIO_STREAM_CNT ; s++) {
+ if (s == (size_t) streamToIgnore) {
+ continue;
+ }
+ for (size_t i = 0; i < size(); i++) {
+ const sp<HwAudioOutputDescriptor> outputDesc = valueAt(i);
+ if (outputDesc->mRefCount[s] != 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+status_t HwAudioOutputCollection::dump(int fd) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, "\nOutputs dump:\n");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < size(); i++) {
+ snprintf(buffer, SIZE, "- Output %d dump:\n", keyAt(i));
+ write(fd, buffer, strlen(buffer));
+ valueAt(i)->dump(fd);
+ }
+
+ return NO_ERROR;
+}
+
}; //namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioSourceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioSourceDescriptor.cpp
new file mode 100644
index 0000000..ba33e57
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioSourceDescriptor.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "APM::AudioSourceDescriptor"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <media/AudioPolicyHelper.h>
+#include <HwModule.h>
+#include <AudioGain.h>
+#include <AudioSourceDescriptor.h>
+#include <DeviceDescriptor.h>
+#include <IOProfile.h>
+#include <AudioOutputDescriptor.h>
+
+namespace android {
+
+status_t AudioSourceDescriptor::dump(int fd)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, "mStream: %d\n", audio_attributes_to_stream_type(&mAttributes));
+ result.append(buffer);
+ snprintf(buffer, SIZE, "mDevice:\n");
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+ mDevice->dump(fd, 2 , 0);
+ return NO_ERROR;
+}
+
+
+status_t AudioSourceCollection::dump(int fd) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, "\nAudio sources dump:\n");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < size(); i++) {
+ snprintf(buffer, SIZE, "- Source %d dump:\n", keyAt(i));
+ write(fd, buffer, strlen(buffer));
+ valueAt(i)->dump(fd);
+ }
+
+ return NO_ERROR;
+}
+
+}; //namespace android
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index a5d4a0e..538addf 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -190,6 +190,10 @@
}
}
+ if (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) {
+ cleanUpForDevice(devDesc);
+ }
+
mpClientInterface->onAudioPortListUpdate();
return NO_ERROR;
} // end if is output device
@@ -266,6 +270,10 @@
updateCallRouting(newDevice);
}
+ if (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) {
+ cleanUpForDevice(devDesc);
+ }
+
mpClientInterface->onAudioPortListUpdate();
return NO_ERROR;
} // end if is input device
@@ -2575,6 +2583,7 @@
void AudioPolicyManager::releaseResourcesForUid(uid_t uid)
{
+ clearAudioSources(uid);
clearAudioPatches(uid);
clearSessionRoutes(uid);
}
@@ -2589,7 +2598,6 @@
}
}
-
void AudioPolicyManager::checkStrategyRoute(routing_strategy strategy,
audio_io_handle_t ouptutToSkip)
{
@@ -2664,6 +2672,15 @@
}
}
+void AudioPolicyManager::clearAudioSources(uid_t uid)
+{
+ for (ssize_t i = (ssize_t)mAudioSources.size() - 1; i >= 0; i--) {
+ sp<AudioSourceDescriptor> sourceDesc = mAudioSources.valueAt(i);
+ if (sourceDesc->mUid == uid) {
+ stopAudioSource(mAudioSources.keyAt(i));
+ }
+ }
+}
status_t AudioPolicyManager::acquireSoundTriggerSession(audio_session_t *session,
audio_io_handle_t *ioHandle,
@@ -2676,16 +2693,181 @@
return mSoundTriggerSessions.acquireSession(*session, *ioHandle);
}
-status_t AudioPolicyManager::startAudioSource(const struct audio_port_config *source __unused,
- const audio_attributes_t *attributes __unused,
- audio_io_handle_t *handle __unused)
+status_t AudioPolicyManager::startAudioSource(const struct audio_port_config *source,
+ const audio_attributes_t *attributes,
+ audio_io_handle_t *handle,
+ uid_t uid)
{
- return INVALID_OPERATION;
+ ALOGV("%s source %p attributes %p handle %p", __FUNCTION__, source, attributes, handle);
+ if (source == NULL || attributes == NULL || handle == NULL) {
+ return BAD_VALUE;
+ }
+
+ *handle = AUDIO_IO_HANDLE_NONE;
+
+ if (source->role != AUDIO_PORT_ROLE_SOURCE ||
+ source->type != AUDIO_PORT_TYPE_DEVICE) {
+ ALOGV("%s INVALID_OPERATION source->role %d source->type %d", __FUNCTION__, source->role, source->type);
+ return INVALID_OPERATION;
+ }
+
+ sp<DeviceDescriptor> srcDeviceDesc =
+ mAvailableInputDevices.getDevice(source->ext.device.type,
+ String8(source->ext.device.address));
+ if (srcDeviceDesc == 0) {
+ ALOGV("%s source->ext.device.type %08x not found", __FUNCTION__, source->ext.device.type);
+ return BAD_VALUE;
+ }
+ sp<AudioSourceDescriptor> sourceDesc =
+ new AudioSourceDescriptor(srcDeviceDesc, attributes, uid);
+
+ struct audio_patch dummyPatch;
+ sp<AudioPatch> patchDesc = new AudioPatch(&dummyPatch, uid);
+ sourceDesc->mPatchDesc = patchDesc;
+
+ status_t status = connectAudioSource(sourceDesc);
+ if (status == NO_ERROR) {
+ mAudioSources.add(sourceDesc->getHandle(), sourceDesc);
+ *handle = sourceDesc->getHandle();
+ }
+ return status;
+}
+
+status_t AudioPolicyManager::connectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc)
+{
+ ALOGV("%s handle %d", __FUNCTION__, sourceDesc->getHandle());
+
+ // make sure we only have one patch per source.
+ disconnectAudioSource(sourceDesc);
+
+ routing_strategy strategy = (routing_strategy) getStrategyForAttr(&sourceDesc->mAttributes);
+ audio_stream_type_t stream = audio_attributes_to_stream_type(&sourceDesc->mAttributes);
+ sp<DeviceDescriptor> srcDeviceDesc = sourceDesc->mDevice;
+
+ audio_devices_t sinkDevice = getDeviceForStrategy(strategy, true);
+ sp<DeviceDescriptor> sinkDeviceDesc =
+ mAvailableOutputDevices.getDevice(sinkDevice, String8(""));
+
+ audio_patch_handle_t afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+ struct audio_patch *patch = &sourceDesc->mPatchDesc->mPatch;
+
+ if (srcDeviceDesc->getAudioPort()->mModule->getHandle() ==
+ sinkDeviceDesc->getAudioPort()->mModule->getHandle() &&
+ srcDeviceDesc->getAudioPort()->mModule->mHalVersion >= AUDIO_DEVICE_API_VERSION_3_0 &&
+ srcDeviceDesc->getAudioPort()->mGains.size() > 0) {
+ ALOGV("%s AUDIO_DEVICE_API_VERSION_3_0", __FUNCTION__);
+ // create patch between src device and output device
+ // create Hwoutput and add to mHwOutputs
+ } else {
+ SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(sinkDevice, mOutputs);
+ audio_io_handle_t output =
+ selectOutput(outputs, AUDIO_OUTPUT_FLAG_NONE, AUDIO_FORMAT_INVALID);
+ if (output == AUDIO_IO_HANDLE_NONE) {
+ ALOGV("%s no output for device %08x", __FUNCTION__, sinkDevice);
+ return INVALID_OPERATION;
+ }
+ sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
+ if (outputDesc->isDuplicated()) {
+ ALOGV("%s output for device %08x is duplicated", __FUNCTION__, sinkDevice);
+ return INVALID_OPERATION;
+ }
+ // create a special patch with no sink and two sources:
+ // - the second source indicates to PatchPanel through which output mix this patch should
+ // be connected as well as the stream type for volume control
+ // - the sink is defined by whatever output device is currently selected for the output
+ // though which this patch is routed.
+ patch->num_sinks = 0;
+ patch->num_sources = 2;
+ srcDeviceDesc->toAudioPortConfig(&patch->sources[0], NULL);
+ outputDesc->toAudioPortConfig(&patch->sources[1], NULL);
+ patch->sources[1].ext.mix.usecase.stream = stream;
+ status_t status = mpClientInterface->createAudioPatch(patch,
+ &afPatchHandle,
+ 0);
+ ALOGV("%s patch panel returned %d patchHandle %d", __FUNCTION__,
+ status, afPatchHandle);
+ if (status != NO_ERROR) {
+ ALOGW("%s patch panel could not connect device patch, error %d",
+ __FUNCTION__, status);
+ return INVALID_OPERATION;
+ }
+ uint32_t delayMs = 0;
+ status = startSource(outputDesc, stream, sinkDevice, &delayMs);
+
+ if (status != NO_ERROR) {
+ mpClientInterface->releaseAudioPatch(sourceDesc->mPatchDesc->mAfPatchHandle, 0);
+ return status;
+ }
+ sourceDesc->mSwOutput = outputDesc;
+ if (delayMs != 0) {
+ usleep(delayMs * 1000);
+ }
+ }
+
+ sourceDesc->mPatchDesc->mAfPatchHandle = afPatchHandle;
+ addAudioPatch(sourceDesc->mPatchDesc->mHandle, sourceDesc->mPatchDesc);
+
+ return NO_ERROR;
}
status_t AudioPolicyManager::stopAudioSource(audio_io_handle_t handle __unused)
{
- return INVALID_OPERATION;
+ sp<AudioSourceDescriptor> sourceDesc = mAudioSources.valueFor(handle);
+ ALOGV("%s handle %d", __FUNCTION__, handle);
+ if (sourceDesc == 0) {
+ ALOGW("%s unknown source for handle %d", __FUNCTION__, handle);
+ return BAD_VALUE;
+ }
+ status_t status = disconnectAudioSource(sourceDesc);
+
+ mAudioSources.removeItem(handle);
+ return status;
+}
+
+status_t AudioPolicyManager::disconnectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc)
+{
+ ALOGV("%s handle %d", __FUNCTION__, sourceDesc->getHandle());
+
+ sp<AudioPatch> patchDesc = mAudioPatches.valueFor(sourceDesc->mPatchDesc->mHandle);
+ if (patchDesc == 0) {
+ ALOGW("%s source has no patch with handle %d", __FUNCTION__,
+ sourceDesc->mPatchDesc->mHandle);
+ return BAD_VALUE;
+ }
+ removeAudioPatch(sourceDesc->mPatchDesc->mHandle);
+
+ audio_stream_type_t stream = audio_attributes_to_stream_type(&sourceDesc->mAttributes);
+ sp<SwAudioOutputDescriptor> swOutputDesc = sourceDesc->mSwOutput.promote();
+ if (swOutputDesc != 0) {
+ stopSource(swOutputDesc, stream, false);
+ mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
+ } else {
+ sp<HwAudioOutputDescriptor> hwOutputDesc = sourceDesc->mHwOutput.promote();
+ if (hwOutputDesc != 0) {
+ // release patch between src device and output device
+ // close Hwoutput and remove from mHwOutputs
+ } else {
+ ALOGW("%s source has neither SW nor HW output", __FUNCTION__);
+ }
+ }
+ return NO_ERROR;
+}
+
+sp<AudioSourceDescriptor> AudioPolicyManager::getSourceForStrategyOnOutput(
+ audio_io_handle_t output, routing_strategy strategy)
+{
+ sp<AudioSourceDescriptor> source;
+ for (size_t i = 0; i < mAudioSources.size(); i++) {
+ sp<AudioSourceDescriptor> sourceDesc = mAudioSources.valueAt(i);
+ routing_strategy sourceStrategy =
+ (routing_strategy) getStrategyForAttr(&sourceDesc->mAttributes);
+ sp<SwAudioOutputDescriptor> outputDesc = sourceDesc->mSwOutput.promote();
+ if (sourceStrategy == strategy && outputDesc != 0 && outputDesc->mIoHandle == output) {
+ source = sourceDesc;
+ break;
+ }
+ }
+ return source;
}
// ----------------------------------------------------------------------------
@@ -3828,6 +4010,11 @@
setStrategyMute(strategy, true, desc);
setStrategyMute(strategy, false, desc, MUTE_TIME_MS, newDevice);
}
+ sp<AudioSourceDescriptor> source =
+ getSourceForStrategyOnOutput(srcOutputs[i], strategy);
+ if (source != 0){
+ connectAudioSource(source);
+ }
}
// Move effects associated to this strategy from previous output to new output
@@ -4922,4 +5109,39 @@
return is_state_in_call(state);
}
+void AudioPolicyManager::cleanUpForDevice(const sp<DeviceDescriptor>& deviceDesc)
+{
+ for (ssize_t i = (ssize_t)mAudioSources.size() - 1; i >= 0; i--) {
+ sp<AudioSourceDescriptor> sourceDesc = mAudioSources.valueAt(i);
+ if (sourceDesc->mDevice->equals(deviceDesc)) {
+ ALOGV("%s releasing audio source %d", __FUNCTION__, sourceDesc->getHandle());
+ stopAudioSource(sourceDesc->getHandle());
+ }
+ }
+
+ for (ssize_t i = (ssize_t)mAudioPatches.size() - 1; i >= 0; i--) {
+ sp<AudioPatch> patchDesc = mAudioPatches.valueAt(i);
+ bool release = false;
+ for (size_t j = 0; j < patchDesc->mPatch.num_sources && !release; j++) {
+ const struct audio_port_config *source = &patchDesc->mPatch.sources[j];
+ if (source->type == AUDIO_PORT_TYPE_DEVICE &&
+ source->ext.device.type == deviceDesc->type()) {
+ release = true;
+ }
+ }
+ for (size_t j = 0; j < patchDesc->mPatch.num_sinks && !release; j++) {
+ const struct audio_port_config *sink = &patchDesc->mPatch.sinks[j];
+ if (sink->type == AUDIO_PORT_TYPE_DEVICE &&
+ sink->ext.device.type == deviceDesc->type()) {
+ release = true;
+ }
+ }
+ if (release) {
+ ALOGV("%s releasing patch %u", __FUNCTION__, patchDesc->mHandle);
+ releaseAudioPatch(patchDesc->mHandle, patchDesc->mUid);
+ }
+ }
+}
+
+
}; // namespace android
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index bbdf396..bb71090 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -211,6 +211,8 @@
unsigned int *generation);
virtual status_t setAudioPortConfig(const struct audio_port_config *config);
+ virtual void releaseResourcesForUid(uid_t uid);
+
virtual status_t acquireSoundTriggerSession(audio_session_t *session,
audio_io_handle_t *ioHandle,
audio_devices_t *device);
@@ -225,11 +227,10 @@
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
- audio_io_handle_t *handle);
+ audio_io_handle_t *handle,
+ uid_t uid);
virtual status_t stopAudioSource(audio_io_handle_t handle);
- virtual void releaseResourcesForUid(uid_t uid);
-
// Audio policy configuration file parsing (audio_policy.conf)
// TODO candidates to be moved to ConfigParsingUtils
void defaultAudioPolicyConfig(void);
@@ -498,6 +499,17 @@
status_t hasPrimaryOutput() const { return mPrimaryOutput != 0; }
+ status_t connectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc);
+ status_t disconnectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc);
+
+ sp<AudioSourceDescriptor> getSourceForStrategyOnOutput(audio_io_handle_t output,
+ routing_strategy strategy);
+
+ void cleanUpForDevice(const sp<DeviceDescriptor>& deviceDesc);
+
+ void clearAudioSources(uid_t uid);
+
+
uid_t mUidCached;
AudioPolicyClientInterface *mpClientInterface; // audio policy client interface
sp<SwAudioOutputDescriptor> mPrimaryOutput; // primary output descriptor
@@ -537,6 +549,9 @@
sp<AudioPatch> mCallTxPatch;
sp<AudioPatch> mCallRxPatch;
+ HwAudioOutputCollection mHwOutputs;
+ AudioSourceCollection mAudioSources;
+
// for supporting "beacon" streams, i.e. streams that only play on speaker, and never
// when something other than STREAM_TTS (a.k.a. "Transmitted Through Speaker") is playing
enum {
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index a228798..41a3fcb 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -690,7 +690,8 @@
return NO_INIT;
}
- return mAudioPolicyManager->startAudioSource(source, attributes, handle);
+ return mAudioPolicyManager->startAudioSource(source, attributes, handle,
+ IPCThreadState::self()->getCallingUid());
}
status_t AudioPolicyService::stopAudioSource(audio_io_handle_t handle)