Merge "audio policy: introduce audio route concept"
diff --git a/services/audiopolicy/common/managerdefinitions/Android.mk b/services/audiopolicy/common/managerdefinitions/Android.mk
index dffeb7e..0c28fc9 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.mk
+++ b/services/audiopolicy/common/managerdefinitions/Android.mk
@@ -10,10 +10,12 @@
src/IOProfile.cpp \
src/AudioPort.cpp \
src/AudioProfile.cpp \
+ src/AudioRoute.cpp \
src/AudioPolicyMix.cpp \
src/AudioPatch.cpp \
src/AudioInputDescriptor.cpp \
src/AudioOutputDescriptor.cpp \
+ src/AudioCollections.cpp \
src/EffectDescriptor.cpp \
src/ConfigParsingUtils.cpp \
src/SoundTriggerSession.cpp \
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h b/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h
new file mode 100644
index 0000000..814c5c2
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h
@@ -0,0 +1,44 @@
+/*
+ * 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 <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <system/audio.h>
+#include <cutils/config_utils.h>
+
+namespace android {
+
+class AudioPort;
+class AudioRoute;
+
+class AudioPortVector : public Vector<sp<AudioPort> >
+{
+public:
+ sp<AudioPort> findByTagName(const String8 &tagName) const;
+};
+
+
+class AudioRouteVector : public Vector<sp<AudioRoute> >
+{
+public:
+ status_t dump(int fd) const;
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
index 9aaaddf..12e42ea 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
@@ -16,6 +16,7 @@
#pragma once
+#include "AudioCollections.h"
#include "AudioProfile.h"
#include <utils/String8.h>
#include <utils/Vector.h>
@@ -28,6 +29,7 @@
class HwModule;
class AudioGain;
+class AudioRoute;
typedef Vector<sp<AudioGain> > AudioGainCollection;
class AudioPort : public virtual RefBase
@@ -44,6 +46,8 @@
audio_port_type_t getType() const { return mType; }
audio_port_role_t getRole() const { return mRole; }
+ virtual const String8 getTagName() const = 0;
+
void setGains(const AudioGainCollection &gains) { mGains = gains; }
const AudioGainCollection &getGains() const { return mGains; }
@@ -114,6 +118,9 @@
(mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD));
}
+ void addRoute(const sp<AudioRoute> &route) { mRoutes.add(route); }
+ const AudioRouteVector &getRoutes() const { return mRoutes; }
+
void dump(int fd, int spaces, bool verbose = true) const;
void log(const char* indent) const;
@@ -124,11 +131,12 @@
void pickChannelMask(audio_channel_mask_t &channelMask, const ChannelsVector &channelMasks) const;
void pickSamplingRate(uint32_t &rate,const SampleRateVector &samplingRates) const;
- String8 mName;
+ String8 mName;
audio_port_type_t mType;
audio_port_role_t mRole;
uint32_t mFlags; // attribute flags mask (e.g primary output, direct output...).
AudioProfileVector mProfiles; // AudioProfiles supported by this port (format, Rates, Channels)
+ AudioRouteVector mRoutes; // Routes involving this port
static volatile int32_t mNextUniqueId;
};
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h b/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h
new file mode 100644
index 0000000..67e197f
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h
@@ -0,0 +1,58 @@
+/*
+ * 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 "AudioCollections.h"
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+
+namespace android
+{
+
+class AudioPort;
+class DeviceDescriptor;
+
+typedef enum {
+ AUDIO_ROUTE_MUX = 0,
+ AUDIO_ROUTE_MIX = 1
+} audio_route_type_t;
+
+class AudioRoute : public virtual RefBase
+{
+public:
+ AudioRoute(audio_route_type_t type) : mType(type) {}
+
+ void setSources(const AudioPortVector &sources) { mSources = sources; }
+ const AudioPortVector &getSources() const { return mSources; }
+
+ void setSink(const sp<AudioPort> &sink) { mSink = sink; }
+ const sp<AudioPort> &getSink() const { return mSink; }
+
+ audio_route_type_t getType() const { return mType; }
+
+ void dump(int fd, int spaces) const;
+
+private:
+ AudioPortVector mSources;
+ sp<AudioPort> mSink;
+ audio_route_type_t mType;
+
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index 8ece51b..54fcd0b 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -34,8 +34,9 @@
virtual ~DeviceDescriptor() {}
+ virtual const String8 getTagName() const { return mTagName; }
+
audio_devices_t type() const { return mDeviceType; }
- const String8 getTagName() const { return mTagName; }
bool equals(const sp<DeviceDescriptor>& other) const;
@@ -56,7 +57,7 @@
String8 mAddress;
private:
- String8 mTagName;
+ String8 mTagName; // Unique human readable identifier for a device port found in conf file.
audio_devices_t mDeviceType;
audio_port_handle_t mId;
diff --git a/services/audiopolicy/common/managerdefinitions/include/HwModule.h b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
index f71a1a4..93d03e6 100644
--- a/services/audiopolicy/common/managerdefinitions/include/HwModule.h
+++ b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
@@ -17,6 +17,7 @@
#pragma once
#include "DeviceDescriptor.h"
+#include "AudioRoute.h"
#include <hardware/audio.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
@@ -46,7 +47,7 @@
const DeviceVector &getDeclaredDevices() const { return mDeclaredDevices; }
- void setDeclaredDevices(const DeviceVector &devices) { mDeclaredDevices = devices; }
+ void setDeclaredDevices(const DeviceVector &devices);
const InputProfileCollection &getInputProfiles() const { return mInputProfiles; }
@@ -57,6 +58,10 @@
void setHalVersion(uint32_t halVersion) { mHalVersion = halVersion; }
uint32_t getHalVersion() const { return mHalVersion; }
+ sp<DeviceDescriptor> getRouteSinkDevice(const sp<AudioRoute> &route) const;
+ DeviceVector getRouteSourceDevices(const sp<AudioRoute> &route) const;
+ void setRoutes(const AudioRouteVector &routes);
+
status_t addOutputProfile(const sp<IOProfile> &profile);
status_t addInputProfile(const sp<IOProfile> &profile);
status_t addProfile(const sp<IOProfile> &profile);
@@ -70,6 +75,11 @@
audio_module_handle_t getHandle() const { return mHandle; }
+ sp<AudioPort> findPortByTagName(const String8 &tagName) const
+ {
+ return mPorts.findByTagName(tagName);
+ }
+
// TODO remove from here (split serialization)
void dump(int fd);
@@ -79,8 +89,12 @@
InputProfileCollection mInputProfiles; // input profiles exposed by this module
private:
+ void refreshSupportedDevices();
+
uint32_t mHalVersion; // audio HAL API version
DeviceVector mDeclaredDevices; // devices declared in audio_policy configuration file.
+ AudioRouteVector mRoutes;
+ AudioPortVector mPorts;
};
class HwModuleCollection : public Vector<sp<HwModule> >
diff --git a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
index 310acff..eae9586 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
@@ -33,8 +33,11 @@
class IOProfile : public AudioPort
{
public:
- IOProfile(const String8 &name, audio_port_role_t role);
- virtual ~IOProfile();
+ IOProfile(const String8 &name, audio_port_role_t role)
+ : AudioPort(name, AUDIO_PORT_TYPE_MIX, role) {}
+
+ // For a Profile aka MixPort, tag name and name are equivalent.
+ virtual const String8 getTagName() const { return getName(); }
// This method is used for both output and input.
// If parameter updatedSamplingRate is non-NULL, it is assigned the actual sample rate.
@@ -101,8 +104,7 @@
const DeviceVector &getSupportedDevices() const { return mSupportedDevices; }
private:
- DeviceVector mSupportedDevices; // supported devices
- // (devices this output can be routed to)
+ DeviceVector mSupportedDevices; // supported devices: this input/output can be routed from/to
};
class InputProfile : public IOProfile
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp
new file mode 100644
index 0000000..6cd2b91
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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::AudioCollections"
+//#define LOG_NDEBUG 0
+
+#include "AudioCollections.h"
+#include "AudioPort.h"
+#include "AudioRoute.h"
+#include "HwModule.h"
+#include "AudioGain.h"
+
+namespace android {
+
+sp<AudioPort> AudioPortVector::findByTagName(const String8 &tagName) const
+{
+ sp<AudioPort> port = 0;
+ for (size_t i = 0; i < size(); i++) {
+ if (itemAt(i)->getTagName() == tagName) {
+ port = itemAt(i);
+ break;
+ }
+ }
+ return port;
+}
+
+status_t AudioRouteVector::dump(int fd) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, "\nAudio Route dump (%d):\n", size());
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < size(); i++) {
+ snprintf(buffer, SIZE, "- Route %zu:\n", i + 1);
+ write(fd, buffer, strlen(buffer));
+ itemAt(i)->dump(fd, 4);
+ }
+ return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
new file mode 100644
index 0000000..79ad1f7
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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::AudioRoute"
+//#define LOG_NDEBUG 0
+
+#include "AudioRoute.h"
+#include "HwModule.h"
+#include "AudioGain.h"
+
+namespace android
+{
+
+void AudioRoute::dump(int fd, int spaces) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, "%*s- Type: %s\n", spaces, "", mType == AUDIO_ROUTE_MUX ? "Mux" : "Mix");
+ result.append(buffer);
+
+ snprintf(buffer, SIZE, "%*s- Sink: %s\n", spaces, "", mSink->getTagName().string());
+ result.append(buffer);
+
+ if (mSources.size() != 0) {
+ snprintf(buffer, SIZE, "%*s- Sources: \n", spaces, "");
+ result.append(buffer);
+ for (size_t i = 0; i < mSources.size(); i++) {
+ snprintf(buffer, SIZE, "%*s%s \n", spaces + 4, "", mSources[i]->getTagName().string());
+ result.append(buffer);
+ }
+ }
+ result.append("\n");
+
+ write(fd, result.string(), result.size());
+}
+
+}
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index d752485..538876c 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -281,6 +281,10 @@
snprintf(buffer, SIZE, "%*s- id: %2d\n", spaces, "", mId);
result.append(buffer);
}
+ if (!mTagName.isEmpty()) {
+ snprintf(buffer, SIZE, "%*s- tag name: %s\n", spaces, "", mTagName.string());
+ result.append(buffer);
+ }
std::string deviceLiteral;
if (DeviceConverter::toString(mDeviceType, deviceLiteral)) {
snprintf(buffer, SIZE, "%*s- type: %-48s\n", spaces, "", deviceLiteral.c_str());
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index dce0890..93ab9c7 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -61,6 +61,7 @@
{
profile->attach(this);
mOutputProfiles.add(profile);
+ mPorts.add(profile);
return NO_ERROR;
}
@@ -68,6 +69,7 @@
{
profile->attach(this);
mInputProfiles.add(profile);
+ mPorts.add(profile);
return NO_ERROR;
}
@@ -132,6 +134,88 @@
return NO_ERROR;
}
+void HwModule::setDeclaredDevices(const DeviceVector &devices)
+{
+ mDeclaredDevices = devices;
+ for (size_t i = 0; i < devices.size(); i++) {
+ mPorts.add(devices[i]);
+ }
+}
+
+sp<DeviceDescriptor> HwModule::getRouteSinkDevice(const sp<AudioRoute> &route) const
+{
+ sp<DeviceDescriptor> sinkDevice = 0;
+ if (route->getSink()->getType() == AUDIO_PORT_TYPE_DEVICE) {
+ sinkDevice = mDeclaredDevices.getDeviceFromTagName(route->getSink()->getTagName());
+ }
+ return sinkDevice;
+}
+
+DeviceVector HwModule::getRouteSourceDevices(const sp<AudioRoute> &route) const
+{
+ DeviceVector sourceDevices;
+ Vector <sp<AudioPort> > sources = route->getSources();
+ for (size_t i = 0; i < sources.size(); i++) {
+ if (sources[i]->getType() == AUDIO_PORT_TYPE_DEVICE) {
+ sourceDevices.add(mDeclaredDevices.getDeviceFromTagName(sources[i]->getTagName()));
+ }
+ }
+ return sourceDevices;
+}
+
+void HwModule::setRoutes(const AudioRouteVector &routes)
+{
+ mRoutes = routes;
+ // Now updating the streams (aka IOProfile until now) supported devices
+ refreshSupportedDevices();
+}
+
+void HwModule::refreshSupportedDevices()
+{
+ // Now updating the streams (aka IOProfile until now) supported devices
+ for (size_t i = 0; i < mInputProfiles.size(); i++) {
+ sp<IOProfile> stream = mInputProfiles[i];
+ DeviceVector sourceDevices;
+ const AudioRouteVector &routes = stream->getRoutes();
+ for (size_t j = 0; j < routes.size(); j++) {
+ sp<AudioPort> sink = routes[j]->getSink();
+ if (sink == 0 || stream != sink) {
+ ALOGE("%s: Invalid route attached to input stream", __FUNCTION__);
+ continue;
+ }
+ DeviceVector sourceDevicesForRoute = getRouteSourceDevices(routes[j]);
+ if (sourceDevicesForRoute.isEmpty()) {
+ ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().string());
+ continue;
+ }
+ sourceDevices.add(sourceDevicesForRoute);
+ }
+ if (sourceDevices.isEmpty()) {
+ ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().string());
+ continue;
+ }
+ stream->setSupportedDevices(sourceDevices);
+ }
+ for (size_t i = 0; i < mOutputProfiles.size(); i++) {
+ sp<IOProfile> stream = mOutputProfiles[i];
+ DeviceVector sinkDevices;
+ const AudioRouteVector &routes = stream->getRoutes();
+ for (size_t j = 0; j < routes.size(); j++) {
+ sp<AudioPort> source = routes[j]->getSources().findByTagName(stream->getTagName());
+ if (source == 0 || stream != source) {
+ ALOGE("%s: Invalid route attached to output stream", __FUNCTION__);
+ continue;
+ }
+ sp<DeviceDescriptor> sinkDevice = getRouteSinkDevice(routes[j]);
+ if (sinkDevice == 0) {
+ ALOGE("%s: invalid sink device for %s", __FUNCTION__, stream->getName().string());
+ continue;
+ }
+ sinkDevices.add(sinkDevice);
+ }
+ stream->setSupportedDevices(sinkDevices);
+ }
+}
void HwModule::dump(int fd)
{
@@ -163,6 +247,10 @@
}
}
mDeclaredDevices.dump(fd, String8("Declared"), 2, true);
+ if (!mRoutes.empty()) {
+ write(fd, " - Audio Route:\n", strlen(" - Audio Route:\n"));
+ mRoutes.dump(fd);
+ }
}
sp <HwModule> HwModuleCollection::getModuleFromName(const char *name) const
diff --git a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
index fe38f54..6e0a071 100644
--- a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
@@ -24,15 +24,6 @@
namespace android {
-IOProfile::IOProfile(const String8 &name, audio_port_role_t role)
- : AudioPort(name, AUDIO_PORT_TYPE_MIX, role)
-{
-}
-
-IOProfile::~IOProfile()
-{
-}
-
// checks if the IO profile is compatible with specified parameters.
// Sampling rate, format and channel mask must be specified in order to
// get a valid a match