[-]
[+]
|
Changed |
_service:tar_git:pulseaudio-modules-droid.changes
|
|
[-]
[+]
|
Changed |
_service:tar_git:pulseaudio-modules-droid.spec
^
|
|
[-]
[+]
|
Changed |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/README
^
|
@@ -14,6 +14,7 @@
* 5.x
* 6.0.x
* 7.x
+ * 8.x
Headers for defining devices and strings for different droid versions are in
src/common/droid-util-audio.h (legacy headers for Jolla 1 in droid-util-41qc.h).
@@ -49,6 +50,35 @@
Components
==========
+common
+------
+
+The common part of PulseAudio Droid modules contains library for handling
+most operations towards audio HAL.
+
+### Audio policy configuration parsing
+
+To populate our configuration structs there exists two parsers, legacy parser
+for old .conf format present in Android versions 7.0 and older and new xml
+format present from version 7.0 upwards. The legacy format is obsoleted in
+version 7.0 but by default still in use and most 7.0 adaptations probably
+contain the legacy format. But 8.0 adaptations and up start to include only
+the new style xml format configuration files.
+
+### Configuration files
+
+By default new style xml format is tried first and if it is not found old
+config is read next. If the configuration is in non-default location for
+some reason "config" module argument (available for all modules, card, sink,
+and source) can be used to point to the configuration file location.
+
+By default files are tried in following order,
+
+ /vendor/etc/audio_policy_configuration.xml (new xml format)
+ /vendor/etc/audio_policy.conf (legacy format)
+ /system/etc/audio_policy_configuration.xml (new xml format)
+ /system/etc/audio_policy.conf (legacy format)
+
module-droid-card
-----------------
@@ -56,11 +86,6 @@
configuration, creates profiles and loads sinks and sources based on the
selected profile.
-Droid-card reads configuration from /vendor/etc/audio_policy.conf or
-/system/etc/audio_policy.conf, depending on which is found first. If vendor
-config is found, configuration is read from there, otherwise from system
-configuration.
-
default profile
---------------
@@ -289,6 +314,23 @@
* Some broken implementations are incorrectly probed for supporting hw
volume control. This is manifested by always full volume with volume
control not affecting volume level. To fix this enable this quirk.
+ * output_make_writable
+ * Disabled by default.
+ * Some implementations modify write buffer in-place when this should
+ not be done. This can result in random segfaults when playing audio.
+ As a workaround make the buffer memchunk writable before passing to
+ audio HAL.
+ * realcall
+ * Disabled by default.
+ * Some vendors apply custom realcall parameter to HAL device when
+ doing voicecall routing. If there is no voicecall audio you can
+ try enabling this quirk so that the realcall parameter is applied
+ when switching to voicecall profile.
+ * unload_call_exit
+ * Disabled by default.
+ * Some HAL module implementations get stuck in mutex or segfault when
+ trying to unload the module. To avoid confusing segfaults call
+ exit(0) instead of calling unload for the module.
For example, to disable input_atoi and enable close_input quirks, use module
argument
|
[-]
[+]
|
Changed |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/configure.ac
^
|
@@ -174,8 +174,6 @@
AC_SUBST(PULSEAUDIO_CFLAGS)
AC_SUBST(PULSEAUDIO_LIBS)
-pulseaudiodir=`pkg-config --variable=prefix pulsecore`
-
#PKG_CHECK_MODULES([DROIDHEADERS], [android-headers >= 0.0.6])
# android-headers.pc has broken version field
PKG_CHECK_MODULES([DROIDHEADERS], [android-headers])
@@ -189,6 +187,25 @@
AC_SUBST(DBUS_CFLAGS)
AC_SUBST(DBUS_LIBS)
+#### expat (for xml config format parsing) (optional) ####
+
+AC_ARG_ENABLE([xml],
+ AS_HELP_STRING([--disable-xml],[Disable optional xml config support]))
+
+AS_IF([test "x$enable_xml" != "xno"],
+ [PKG_CHECK_MODULES(EXPAT, [ expat >= 2.1 ], HAVE_EXPAT=1, HAVE_EXPAT=0)],
+ HAVE_EXPAT=0)
+
+AS_IF([test "x$enable_xml" = "xyes" && test "x$HAVE_EXPAT" = "x0"],
+ [AC_MSG_ERROR([*** expat not found])])
+
+AC_SUBST(HAVE_EXPAT)
+AC_SUBST(EXPAT_CFLAGS)
+AC_SUBST(EXPAT_LIBS)
+AM_CONDITIONAL([HAVE_EXPAT], [test "x$HAVE_EXPAT" = x1])
+AS_IF([test "x$HAVE_EXPAT" = "x1"], AC_DEFINE([HAVE_EXPAT], 1, [Have expat?]))
+AS_IF([test "x$HAVE_EXPAT" = "x1"], ENABLE_XML="yes (expat)", ENABLE_XML=no)
+
# Output devices
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_OUT_HDMI])
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_OUT_HDMI_ARC])
@@ -260,9 +277,10 @@
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_FORMAT_FLAC])
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_FORMAT_OPUS])
-AC_ARG_WITH([module-dir],
- AS_HELP_STRING([--with-module-dir],[Directory where to install the modules to (defaults to ${pulseaudiodir}/lib/pulse-${PA_MAJORMINOR}/modules/]),
- [modlibexecdir=$withval], [modlibexecdir="${pulseaudiodir}/lib/pulse-${PA_MAJORMINOR}/modules"])
+AC_ARG_WITH(
+ [module-dir],
+ AS_HELP_STRING([--with-module-dir],[Directory where to install the modules to (defaults to ${libdir}/pulse-${PA_MAJORMINOR}/modules]),
+ [modlibexecdir=$withval], [modlibexecdir="${libdir}/pulse-${PA_MAJORMINOR}/modules"])
AC_SUBST(modlibexecdir)
@@ -278,6 +296,12 @@
AC_SUBST([DROID_DEVICE_CFLAGS])
fi
+# Workaround for SBJ HAL headers
+if test "x$droiddevice" = xsbj ; then
+ SBJ_DEVICE_LDFLAGS="-Wl,--allow-multiple-definition"
+ AC_SUBST([SBJ_DEVICE_LDFLAGS])
+fi
+
AC_MSG_CHECKING([If we are using hardfp tool chain])
case `echo | gcc -v -xc -o - - 2>&1 | grep COLLECT_GCC_OPTIONS | tail -1` in
*float-abi=hard*) hardfp=yes; AC_MSG_RESULT([yes]) ;;
@@ -308,8 +332,8 @@
CFLAGS: ${CFLAGS}
prefix: ${prefix}
- PulseAudio prefix: ${pulseaudiodir}
modules directory: ${modlibexecdir}
- Droid device ${droiddevice}
+ Droid device: ${droiddevice}
+ XML config support: ${ENABLE_XML}
"
|
[-]
[+]
|
Changed |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/src/common/Makefile.am
^
|
@@ -1,18 +1,35 @@
AM_LIBADD = \
$(PULSEAUDIO_LIBS) \
- $(HYBRIS_LIBS)
+ $(HYBRIS_LIBS) \
+ $(EXPAT_LIBS)
AM_CFLAGS = \
$(DROID_DEVICE_CFLAGS) \
$(PULSEAUDIO_CFLAGS) \
$(DROIDHEADERS_CFLAGS) \
$(HYBRIS_CFLAGS) \
+ $(EXPAT_CFLAGS) \
-DPULSEAUDIO_VERSION=@PA_MAJOR@ \
- -I$(top_srcdir)/src/common
+ -I$(top_srcdir)/src/common \
+ -I$(top_srcdir)/src/common/include
modlibexec_LTLIBRARIES = libdroid-util.la
+includedir = @includedir@/pulsecore/modules/droid
+include_HEADERS = include/droid/version.h \
+ include/droid/conversion.h \
+ include/droid/droid-config.h \
+ include/droid/droid-util.h
-libdroid_util_la_SOURCES = droid-util.c droid-util.h
-libdroid_util_la_LDFLAGS = -avoid-version -Wl,-z,noexecstack -lhybris-common
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libdroid-util.pc
+
+libdroid_util_la_SOURCES = droid-util.c \
+ droid-config.c \
+ conversion.c \
+ config-parser-legacy.c \
+ config-parser-xml.c \
+ droid-util-audio.h \
+ droid-util-41qc.h
+libdroid_util_la_LDFLAGS = -avoid-version -Wl,-z,noexecstack -lhybris-common $(SBJ_DEVICE_LDFLAGS)
libdroid_util_la_LIBADD = $(AM_LIBADD)
libdroid_util_la_CFLAGS = $(AM_CFLAGS)
|
[-]
[+]
|
Added |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/src/common/config-parser-legacy.c
^
|
@@ -0,0 +1,436 @@
+/*
+ * Copyright (C) 2018 Jolla Ltd.
+ *
+ * Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
+ *
+ * These PulseAudio Modules are free software; you can redistribute
+ * it and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdbool.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/core-error.h>
+#include <pulsecore/log.h>
+#include <pulse/xmalloc.h>
+
+#include <hardware_legacy/audio_policy_conf.h>
+
+#include "droid/version.h"
+#include "droid/droid-config.h"
+#include "droid/conversion.h"
+#include "droid/sllist.h"
+
+/* Section defining custom global configuration variables. */
+#define GLOBAL_CONFIG_EXT_TAG "custom_properties"
+
+#define GAIN_TAG_PREFIX "gain_"
+
+#define MAX_LINE_LENGTH (1024)
+#define WHITESPACE "\n\r \t"
+
+static void log_parse_error(const char *fn, const unsigned ln, const char *section, const char *v) {
+ pa_log("[%s:%u] failed to parse line in section %s: unknown section (%s)", fn, ln, section, v);
+}
+
+pa_droid_config_audio *pa_parse_droid_audio_config_legacy(const char *filename) {
+ pa_droid_config_audio *config = NULL;
+ FILE *f;
+ unsigned n = 0;
+ bool ret = true;
+ char *full_line = NULL;
+ uint32_t hw_module_count = 0;
+
+ enum config_loc {
+ IN_ROOT = 0,
+ IN_GLOBAL = 1,
+ IN_GLOBAL_EXT = 2,
+ IN_HW_MODULES = 3,
+ IN_MODULE = 4,
+ IN_OUTPUT_INPUT = 5,
+ IN_CONFIG = 6,
+ IN_MODULE_GLOBAL = 10,
+ IN_DEVICES = 20,
+ IN_DEVICES_DEVICE = 21,
+ IN_GAINS = 22,
+ IN_GAIN_N = 23
+ } loc = IN_ROOT;
+
+ bool in_output = true;
+
+ pa_droid_config_hw_module *module = NULL;
+ pa_droid_config_device *output = NULL;
+ pa_droid_config_device *input = NULL;
+
+ pa_assert(filename);
+
+ f = fopen(filename, "r");
+
+ if (!f) {
+ pa_log_info("Failed to open config file (%s): %s", filename, pa_cstrerror(errno));
+ ret = false;
+ goto finish;
+ }
+
+ config = pa_xnew0(pa_droid_config_audio, 1);
+ config->global_config = pa_xnew0(pa_droid_config_global, 1);
+
+ pa_lock_fd(fileno(f), 1);
+
+ full_line = pa_xmalloc0(sizeof(char) * MAX_LINE_LENGTH);
+
+ while (!feof(f)) {
+ char *ln, *d, *v, *value;
+
+ if (!fgets(full_line, MAX_LINE_LENGTH, f))
+ break;
+
+ n++;
+
+ pa_strip_nl(full_line);
+
+ if (!*full_line)
+ continue;
+
+ ln = full_line + strspn(full_line, WHITESPACE);
+
+ if (ln[0] == '#')
+ continue;
+
+ v = ln;
+ d = v + strcspn(v, WHITESPACE);
+
+ value = d + strspn(d, WHITESPACE);
+ d[0] = '\0';
+ d = value + strcspn(value, WHITESPACE);
+ d[0] = '\0';
+
+ /* Enter section */
+ if (pa_streq(value, "{")) {
+
+ if (!*v) {
+ pa_log("[%s:%u] failed to parse line - too few words", filename, n);
+ goto finish;
+ }
+
+ switch (loc) {
+ case IN_ROOT:
+ if (pa_streq(v, GLOBAL_CONFIG_TAG)) {
+ loc = IN_GLOBAL;
+ }
+ else if (pa_streq(v, AUDIO_HW_MODULE_TAG))
+ loc = IN_HW_MODULES;
+ else {
+ log_parse_error(filename, n, "<root>", v);
+ ret = false;
+ goto finish;
+ }
+ break;
+
+ case IN_GLOBAL:
+ if (pa_streq(v, GLOBAL_CONFIG_EXT_TAG))
+ loc = IN_GLOBAL_EXT;
+ else {
+ log_parse_error(filename, n, GLOBAL_CONFIG_TAG, v);
+ ret = false;
+ goto finish;
+ }
+ break;
+
+ case IN_HW_MODULES:
+ pa_assert(!module);
+
+ module = pa_droid_config_hw_module_new(config, v);
+ SLLIST_APPEND(pa_droid_config_hw_module, config->hw_modules, module);
+ hw_module_count++;
+ loc = IN_MODULE;
+ pa_log_debug("config: New module: %s", module->name);
+ break;
+
+ case IN_MODULE:
+ pa_assert(module);
+
+ if (pa_streq(v, OUTPUTS_TAG)) {
+ loc = IN_OUTPUT_INPUT;
+ in_output = true;
+ } else if (pa_streq(v, INPUTS_TAG)) {
+ loc = IN_OUTPUT_INPUT;
+ in_output = false;
+ } else if (pa_streq(v, GLOBAL_CONFIG_TAG)) {
+ loc = IN_MODULE_GLOBAL;
+ } else if (pa_streq(v, DEVICES_TAG)) {
+ loc = IN_DEVICES;
+ } else {
+ log_parse_error(filename, n, module->name, v);
+ ret = false;
+ goto finish;
+ }
+ break;
+
+ case IN_OUTPUT_INPUT:
+ pa_assert(module);
+
+ if (in_output) {
+ output = pa_droid_config_device_new(module, PA_DIRECTION_OUTPUT, v);
+ SLLIST_APPEND(pa_droid_config_device, module->outputs, output);
+ loc = IN_CONFIG;
+ pa_log_debug("config: %s: New output: %s", module->name, output->name);
+ } else {
+ input = pa_droid_config_device_new(module, PA_DIRECTION_INPUT, v);
+ SLLIST_APPEND(pa_droid_config_device, module->inputs, input);
+ loc = IN_CONFIG;
+ pa_log_debug("config: %s: New input: %s", module->name, input->name);
+ }
+ break;
+
+ case IN_DEVICES:
+ /* TODO Missing implementation of parsing the module/devices section.
+ * As of now there is no need for the information, fix this when that
+ * changes. */
+ loc = IN_DEVICES_DEVICE;
+ break;
+
+ case IN_DEVICES_DEVICE:
+ if (pa_streq(v, GAINS_TAG))
+ loc = IN_GAINS;
+ else {
+ log_parse_error(filename, n, DEVICES_TAG, v);
+ ret = false;
+ goto finish;
+ }
+ break;
+
+ case IN_GAINS:
+ /* TODO Missing implementation of parsing the gain_n section.
+ * As of now there is no need for the information, fix this when that
+ * changes. */
+ if (pa_startswith(v, GAIN_TAG_PREFIX))
+ loc = IN_GAIN_N;
+ else {
+ log_parse_error(filename, n, GAINS_TAG, v);
+ ret = false;
+ goto finish;
+ }
+ break;
+
+ case IN_CONFIG:
+ if (pa_streq(v, GAINS_TAG)) {
+ loc = IN_GAINS;
+ } else {
+ log_parse_error(filename, n, in_output ? output->name : input->name, v);
+ ret = false;
+ goto finish;
+ }
+ break;
+
+ default:
+ pa_log("[%s:%u] failed to parse line: unknown section (%s)", filename, n, v);
+ ret = false;
+ goto finish;
+ }
+
+ continue;
+ }
+
+ /* Exit section */
+ if (pa_streq(v, "}")) {
+ switch (loc) {
+ case IN_ROOT:
+ pa_log("[%s:%u] failed to parse line - extra closing bracket", filename, n);
+ ret = false;
+ goto finish;
+
+ case IN_HW_MODULES:
+ /* fall through */
+ case IN_GLOBAL:
+ loc = IN_ROOT;
+ break;
+
+ case IN_MODULE:
+ module = NULL;
+ loc = IN_HW_MODULES;
+ break;
+
+ case IN_DEVICES:
+ /* fall through */
+ case IN_MODULE_GLOBAL:
+ loc = IN_MODULE;
+ break;
+
+ case IN_GAINS:
+ if (output || input)
+ loc = IN_CONFIG;
+ else
+ loc = IN_DEVICES_DEVICE;
+ break;
+
+ case IN_OUTPUT_INPUT:
+ if (in_output)
+ output = NULL;
+ else
+ input = NULL;
+ /* fall through */
+ case IN_GAIN_N:
+ /* fall through */
+ case IN_DEVICES_DEVICE:
+ /* fall through */
+ case IN_CONFIG:
+ /* fall through */
+ case IN_GLOBAL_EXT:
+ loc--;
+ break;
+ }
+
+ continue;
+ }
+
+ /* Parsing of values */
+ if (loc == IN_GLOBAL ||
+ loc == IN_GLOBAL_EXT ||
+ loc == IN_MODULE_GLOBAL ||
+ loc == IN_CONFIG ||
+ loc == IN_DEVICES_DEVICE ||
+ loc == IN_GAIN_N) {
+
+ bool success = false;
+
+ if (loc == IN_GLOBAL || loc == IN_MODULE_GLOBAL) {
+ pa_droid_config_global *global_config = NULL;
+
+ if (loc == IN_MODULE_GLOBAL) {
+ pa_assert(module);
+ if (!module->global_config)
+ module->global_config = pa_xnew0(pa_droid_config_global, 1);
+ global_config = module->global_config;
+ } else
+ global_config = config->global_config;
+
+ pa_assert(global_config);
+
+ /* Parse global configuration */
+
+ if (pa_streq(v, ATTACHED_OUTPUT_DEVICES_TAG))
+ success = pa_conversion_parse_output_devices(filename, n, value, true, true,
+ &global_config->attached_output_devices);
+ else if (pa_streq(v, DEFAULT_OUTPUT_DEVICE_TAG))
+ success = pa_conversion_parse_output_devices(filename, n, value, true, true,
+ &global_config->default_output_device);
+ else if (pa_streq(v, ATTACHED_INPUT_DEVICES_TAG))
+ success = pa_conversion_parse_input_devices(filename, n, value, true, false,
+ &global_config->attached_input_devices);
+ else if (pa_streq(v, AUDIO_HAL_VERSION_TAG))
+ success = pa_conversion_parse_version(filename, n, value,
+ &global_config->audio_hal_version);
+#ifdef SPEAKER_DRC_ENABLED_TAG
+ // SPEAKER_DRC_ENABLED_TAG is only from Android v4.4
+ else if (pa_streq(v, SPEAKER_DRC_ENABLED_TAG))
+ /* TODO - Add support for dynamic range control */
+ success = true; /* Do not fail while parsing speaker_drc_enabled entry */
+#endif
+ else {
+ pa_log("[%s:%u] failed to parse line - unknown config entry %s", filename, n, v);
+ success = false;
+ }
+
+ } else if (loc == IN_GLOBAL_EXT) {
+
+ /* Parse custom global configuration
+ * For now just log all custom variables, don't do
+ * anything with the values.
+ * TODO: Store custom values somehow */
+
+ pa_log_debug("[%s:%u] TODO custom variable: %s = %s", filename, n, v, value);
+ success = true;
+
+ } else if (loc == IN_CONFIG) {
+
+ /* Parse per-output or per-input configuration */
+
+ if ((in_output && !output) || (!in_output && !input)) {
+ pa_log("[%s:%u] failed to parse line", filename, n);
+ ret = false;
+ goto finish;
+ }
+
+ if (pa_streq(v, SAMPLING_RATES_TAG))
+ success = pa_conversion_parse_sampling_rates(filename, n, value, true,
+ in_output ? output->sampling_rates : input->sampling_rates);
+ else if (pa_streq(v, FORMATS_TAG))
+ success = pa_conversion_parse_formats(filename, n, value, true,
+ in_output ? &output->formats : &input->formats);
+ else if (pa_streq(v, CHANNELS_TAG)) {
+ if (in_output)
+ success = pa_conversion_parse_output_channels(filename, n, value, true, &output->channel_masks);
+ else
+ success = pa_conversion_parse_input_channels(filename, n, value, true, &input->channel_masks);
+ } else if (pa_streq(v, DEVICES_TAG)) {
+ if (in_output)
+ success = pa_conversion_parse_output_devices(filename, n, value, true, false, &output->devices);
+ else
+ success = pa_conversion_parse_input_devices(filename, n, value, true, false, &input->devices);
+ } else if (pa_streq(v, FLAGS_TAG)) {
+ if (in_output)
+ success = pa_conversion_parse_output_flags(filename, n, value, &output->flags);
+ else {
+#if AUDIO_API_VERSION_MAJ >= 3
+ success = pa_conversion_parse_input_flags(filename, n, value, &input->flags);
+#else
+ pa_log("[%s:%u] failed to parse line - output flags inside input definition", filename, n);
+ success = false;
+#endif
+ }
+ } else {
+ pa_log("[%s:%u] failed to parse line - unknown config entry %s", filename, n, v);
+ success = false;
+ }
+
+ } else if (loc == IN_DEVICES_DEVICE) {
+ /* TODO Missing implementation of parsing the module/devices section.
+ * As of now there is no need for the information, fix this when that
+ * changes. */
+ success = true;
+ } else if (loc == IN_GAIN_N) {
+ /* TODO Missing implementation of parsing the gain_n section.
+ * As of now there is no need for the information, fix this when that
+ * changes. */
+ success = true;
+ } else
+ pa_assert_not_reached();
+
+ if (!success) {
+ ret = false;
+ goto finish;
+ }
+ }
+ }
+
+ pa_log_info("Parsed config file (%s): %u modules.", filename, hw_module_count);
+
+finish:
+ if (f) {
+ pa_lock_fd(fileno(f), 0);
+ fclose(f);
+ }
+
+ pa_xfree(full_line);
+
+ if (!ret)
+ pa_droid_config_free(config), config = NULL;
+
+ return config;
+}
|
[-]
[+]
|
Added |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/src/common/config-parser-xml.c
^
|
@@ -0,0 +1,1064 @@
+/*
+ * Copyright (C) 2018 Jolla Ltd.
+ *
+ * Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
+ *
+ * These PulseAudio Modules are free software; you can redistribute
+ * it and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <pulsecore/log.h>
+
+#include "droid/droid-config.h"
+
+#ifndef HAVE_EXPAT
+#include <unistd.h>
+pa_droid_config_audio *pa_parse_droid_audio_config_xml(const char *filename) {
+ if (access(filename, F_OK) == 0)
+ pa_log_warn("Could not parse %s, xml configuration parsing support not compiled in", filename);
+ return NULL;
+}
+#else
+
+#include <stdarg.h>
+#include <string.h>
+#include <expat.h>
+
+#include <pulse/xmalloc.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/core-error.h>
+
+#include "droid/conversion.h"
+#include "droid/sllist.h"
+
+#ifdef XML_UNICODE_WCHAR_T
+# include <wchar.h>
+# define XML_FMT_STR "ls"
+#else
+# define XML_FMT_STR "s"
+#endif
+
+#define POLICY_SUPPORTED_VERSION "1.0"
+
+#define ELEMENT_audioPolicyConfiguration "audioPolicyConfiguration"
+#define ELEMENT_globalConfiguration "globalConfiguration"
+#define ELEMENT_modules "modules"
+#define ELEMENT_module "module"
+#define ELEMENT_attachedDevices "attachedDevices"
+#define ELEMENT_item "item"
+#define ELEMENT_defaultOutputDevice "defaultOutputDevice"
+#define ELEMENT_mixPorts "mixPorts"
+#define ELEMENT_mixPort "mixPort"
+#define ELEMENT_profile "profile"
+#define ELEMENT_devicePorts "devicePorts"
+#define ELEMENT_devicePort "devicePort"
+/* ELEMENT_profile */
+#define ELEMENT_routes "routes"
+#define ELEMENT_route "route"
+
+#define ATTRIBUTE_version "version"
+#define ATTRIBUTE_name "name"
+#define ATTRIBUTE_halVersion "halVersion"
+#define ATTRIBUTE_format "format"
+#define ATTRIBUTE_samplingRates "samplingRates"
+#define ATTRIBUTE_channelMasks "channelMasks"
+#define ATTRIBUTE_tagName "tagName"
+#define ATTRIBUTE_role "role"
+#define ATTRIBUTE_flags "flags"
+#define ATTRIBUTE_sink "sink"
+#define ATTRIBUTE_sources "sources"
+#define ATTRIBUTE_type "type"
+
+#define PORT_TYPE_sink "sink"
+#define PORT_TYPE_source "source"
+
+
+struct parser_data;
+
+struct element_parser {
+ const char *name;
+ bool (*attributes)(struct parser_data *data, const char *element_name, const XML_Char **attributes);
+ void (*char_data)(struct parser_data *data, const char *str);
+ const struct element_parser *next;
+ const struct element_parser *child;
+};
+
+struct element_parser_stack {
+ const struct element_parser *data;
+ struct element_parser_stack *next;
+};
+
+#define ELEMENT_STACK_PUSH(_stack, _item) \
+ do { \
+ struct element_parser_stack *_i; \
+ _i = pa_xmalloc0(sizeof(*_i)); \
+ _i->data = _item; \
+ _i->next = _stack; \
+ _stack = _i; \
+ } while(0)
+
+#define ELEMENT_STACK_POP(_stack, _item) \
+ do { \
+ if (_stack) { \
+ struct element_parser_stack *_t; \
+ _t = _stack; \
+ _item = _stack->data; \
+ _stack = _stack->next; \
+ pa_xfree(_t); \
+ } else \
+ _item = NULL; \
+ } while(0)
+
+static bool parse_audio_policy_configuration(struct parser_data *data, const char *element_name, const XML_Char **attributes);
+static bool parse_route(struct parser_data *data, const char *element_name, const XML_Char **attributes);
+static bool parse_profile(struct parser_data *data, const char *element_name, const XML_Char **attributes);
+static bool parse_device_port(struct parser_data *data, const char *element_name, const XML_Char **attributes);
+static bool parse_mix_port(struct parser_data *data, const char *element_name, const XML_Char **attributes);
+static void parse_default_output_device(struct parser_data *data, const char *str);
+static void parse_item(struct parser_data *data, const char *str);
+static bool parse_module(struct parser_data *data, const char *element_name, const XML_Char **attributes);
+static bool parse_global_configuration(struct parser_data *data, const char *element_name, const XML_Char **attributes);
+
+static const struct element_parser element_parse_route = {
+ ELEMENT_route,
+ parse_route,
+ NULL,
+ NULL,
+ NULL
+};
+
+static const struct element_parser element_parse_routes = {
+ ELEMENT_routes,
+ NULL,
+ NULL,
+ NULL,
+ &element_parse_route
+};
+
+static const struct element_parser element_parse_profile = {
+ ELEMENT_profile,
+ parse_profile,
+ NULL,
+ NULL,
+ NULL
+};
+
+static const struct element_parser element_parse_device_port = {
+ ELEMENT_devicePort,
+ parse_device_port,
+ NULL,
+ NULL,
+ &element_parse_profile
+};
+
+static const struct element_parser element_parse_device_ports = {
+ ELEMENT_devicePorts,
+ NULL,
+ NULL,
+ &element_parse_routes,
+ &element_parse_device_port
+};
+
+static const struct element_parser element_parse_mix_port = {
+ ELEMENT_mixPort,
+ parse_mix_port,
+ NULL,
+ NULL,
+ &element_parse_profile
+};
+
+static const struct element_parser element_parse_mix_ports = {
+ ELEMENT_mixPorts,
+ NULL,
+ NULL,
+ &element_parse_device_ports,
+ &element_parse_mix_port
+};
+
+static const struct element_parser element_parse_default_output_device = {
+ ELEMENT_defaultOutputDevice,
+ NULL,
+ parse_default_output_device,
+ &element_parse_mix_ports,
+ NULL
+};
+
+static const struct element_parser element_parse_item = {
+ ELEMENT_item,
+ NULL,
+ parse_item,
+ NULL,
+ NULL
+};
+
+static const struct element_parser element_parse_attached_devices = {
+ ELEMENT_attachedDevices,
+ NULL,
+ NULL,
+ &element_parse_default_output_device,
+ &element_parse_item
+};
+
+static const struct element_parser element_parse_module = {
+ ELEMENT_module,
+ parse_module,
+ NULL,
+ NULL,
+ &element_parse_attached_devices
+};
+
+static const struct element_parser element_parse_modules = {
+ ELEMENT_modules,
+ NULL,
+ NULL,
+ NULL,
+ &element_parse_module
+};
+
+static const struct element_parser element_parse_global_configuration = {
+ ELEMENT_globalConfiguration,
+ parse_global_configuration,
+ NULL,
+ &element_parse_modules,
+ NULL
+};
+
+static const struct element_parser element_parse_audio_policy_configuration = {
+ ELEMENT_audioPolicyConfiguration,
+ parse_audio_policy_configuration,
+ NULL,
+ NULL,
+ &element_parse_global_configuration
+};
+
+static const struct element_parser element_parse_root = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &element_parse_audio_policy_configuration
+};
+
+
+struct global_configuration {
+ char *key;
+ char *value;
+ struct global_configuration *next;
+};
+
+struct device {
+ char *name;
+ struct device *next;
+};
+
+struct profile {
+ char *name;
+ audio_format_t format;
+ uint32_t sampling_rates[AUDIO_MAX_SAMPLING_RATES];
+ audio_channel_mask_t channel_masks;
+ struct profile *next;
+};
+
+struct mix_port {
+ char *name;
+ char *role;
+ uint32_t flags;
+ struct profile *profiles;
+ struct mix_port *next;
+};
+
+struct device_port {
+ char *tag_name;
+ audio_devices_t type;
+ char *role;
+ struct profile *profiles;
+ struct device_port *next;
+};
+
+struct route {
+ char *type;
+ char *sink;
+ struct device *sources;
+ struct route *next;
+};
+
+struct module {
+ char *name;
+ uint32_t version;
+ struct device *attached_devices;
+ struct device *default_output;
+ struct mix_port *mix_ports;
+ struct device_port *device_ports;
+ struct route *routes;
+
+ struct module *next;
+};
+
+struct audio_policy_configuration {
+ struct global_configuration *global;
+ struct module *modules;
+};
+
+struct parser_data {
+ XML_Parser parser;
+ const char *fn;
+ unsigned lineno;
+
+ const struct element_parser *root;
+ const struct element_parser *current;
+ struct element_parser_stack *stack;
+
+ struct audio_policy_configuration *conf;
+ struct module *current_module;
+ struct mix_port *current_mix_port;
+ struct device_port *current_device_port;
+};
+
+
+static char *xml_string_dup(const XML_Char *xml_str, int len)
+{
+ char *str;
+
+ if (len > 0) {
+ str = pa_xmalloc0(len + 1);
+ snprintf(str, len + 1, "%" XML_FMT_STR, xml_str);
+ } else
+ str = pa_sprintf_malloc("%" XML_FMT_STR, xml_str);
+
+ return str;
+}
+
+static void device_free(struct device *d) {
+ pa_assert(d);
+ pa_xfree(d->name);
+ pa_xfree(d);
+}
+
+static void profile_free(struct profile *p) {
+ pa_assert(p);
+ pa_xfree(p->name);
+ pa_xfree(p);
+}
+
+static void mix_port_free(struct mix_port *p) {
+ struct profile *profile;
+
+ pa_assert(p);
+
+ while (p->profiles) {
+ SLLIST_STEAL_FIRST(profile, p->profiles);
+ profile_free(profile);
+ };
+
+ pa_xfree(p->name);
+ pa_xfree(p->role);
+ pa_xfree(p);
+}
+
+static void device_port_free(struct device_port *p) {
+ pa_assert(p);
+ pa_xfree(p->tag_name);
+ pa_xfree(p->role);
+ pa_xfree(p);
+}
+
+static void route_free(struct route *r) {
+ struct device *d;
+
+ pa_assert(r);
+
+ while (r->sources) {
+ SLLIST_STEAL_FIRST(d, r->sources);
+ device_free(d);
+ }
+ pa_xfree(r->type);
+ pa_xfree(r->sink);
+ pa_xfree(r);
+}
+
+static void module_free(struct module *m) {
+ struct device *dev;
+ struct mix_port *mix_port;
+ struct device_port *device_port;
+ struct route *route;
+
+ pa_assert(m);
+
+ while (m->attached_devices) {
+ SLLIST_STEAL_FIRST(dev, m->attached_devices);
+ device_free(dev);
+ };
+
+ while (m->default_output) {
+ SLLIST_STEAL_FIRST(dev, m->default_output);
+ device_free(dev);
+ };
+
+ while (m->mix_ports) {
+ SLLIST_STEAL_FIRST(mix_port, m->mix_ports);
+ mix_port_free(mix_port);
+ };
+
+ while (m->device_ports) {
+ SLLIST_STEAL_FIRST(device_port, m->device_ports);
+ device_port_free(device_port);
+ };
+
+ while (m->routes) {
+ SLLIST_STEAL_FIRST(route, m->routes);
+ route_free(route);
+ };
+
+ pa_xfree(m->name);
+ pa_xfree(m);
+}
+
+static void audio_policy_configuration_free(struct audio_policy_configuration *xml_config) {
+ struct global_configuration *global;
+ struct module *m;
+
+ pa_assert(xml_config);
+
+ while (xml_config->global) {
+ SLLIST_STEAL_FIRST(global, xml_config->global);
+ pa_xfree(global->key);
+ pa_xfree(global->value);
+ pa_xfree(global);
+ }
+
+ while (xml_config->modules) {
+ SLLIST_STEAL_FIRST(m, xml_config->modules);
+ module_free(m);
+ };
+
+ pa_xfree(xml_config);
+}
+
+static bool get_element_attr(struct parser_data *data, const XML_Char **attr, bool required,
+ const char *key, char **ret_value) {
+ int i;
+ bool found = false;
+
+ pa_assert(attr);
+ pa_assert(key);
+ pa_assert(ret_value);
+
+ for (i = 0; attr[i]; i += 2) {
+ if (pa_streq(attr[i], key)) {
+ *ret_value = xml_string_dup(attr[i + 1], -1);
+ found = true;
+ break;
+ }
+ }
+
+ if (!found && required)
+ pa_log_warn("[%s:%u] Could not find element attribute \"%s\"", data->fn, data->lineno, key);
+
+ return found;
+}
+
+static bool get_element_attrs(struct parser_data *data, const XML_Char **attr, ...) {
+ const char *key;
+ char **ret_value;
+ va_list ap;
+ uint32_t keys = 0;
+ uint32_t found = 0;
+
+ va_start(ap, attr);
+ for (;;) {
+ key = va_arg(ap, const char *);
+ if (!key)
+ break;
+ keys++;
+
+ ret_value = va_arg(ap, char **);
+ if (get_element_attr(data, attr, true, key, ret_value))
+ found++;
+ }
+ va_end(ap);
+
+ return keys == found;
+}
+
+static void XMLCALL xml_start_element(void *userdata, const XML_Char *element_name, const XML_Char **attributes) {
+ struct parser_data *data = userdata;
+ char *element = NULL;
+ const struct element_parser *node;
+
+ element = xml_string_dup(element_name, -1);
+ data->lineno = (unsigned) XML_GetCurrentLineNumber(data->parser);
+
+ SLLIST_FOREACH(node, data->current->child) {
+ if (pa_streq(node->name, element)) {
+ if (node->attributes) {
+ if (!node->attributes(data, element, attributes))
+ goto fail;
+ }
+
+ ELEMENT_STACK_PUSH(data->stack, data->current);
+ data->current = node;
+ break;
+ }
+ }
+
+ pa_xfree(element);
+
+ return;
+
+fail:
+ while (data->stack)
+ ELEMENT_STACK_POP(data->stack, node);
+
+ pa_xfree(element);
+
+ XML_StopParser(data->parser, 0);
+}
+
+static void XMLCALL xml_end_element(void *userdata, const XML_Char *element_name) {
+ struct parser_data *data = userdata;
+ char *element = NULL;
+
+ element = xml_string_dup(element_name, -1);
+
+ if (pa_streq(data->current->name, element)) {
+ ELEMENT_STACK_POP(data->stack, data->current);
+
+ if (pa_streq(element, ELEMENT_mixPort))
+ data->current_mix_port = NULL;
+ else if (pa_streq(element, ELEMENT_devicePort))
+ data->current_device_port = NULL;
+ else if (pa_streq(element, ELEMENT_module))
+ data->current_module = NULL;
+ }
+
+ pa_xfree(element);
+}
+
+static void XMLCALL xml_character_data_handler(void *userdata, const XML_Char *s, int len) {
+ struct parser_data *data = userdata;
+ int whitespace = 0;
+ char *str = NULL;
+
+ if (len <= 0)
+ goto done;
+
+ str = xml_string_dup(s, len);
+ whitespace = strspn(str, "\r\n\t ");
+
+ if (whitespace == len)
+ goto done;
+
+ if (data->current->char_data)
+ data->current->char_data(data, str);
+
+done:
+ pa_xfree(str);
+}
+
+static bool parse_audio_policy_configuration(struct parser_data *data,
+ const char *element_name,
+ const XML_Char **attributes) {
+ char *version = NULL;
+
+ if (!get_element_attr(data, attributes, true, ATTRIBUTE_version, &version))
+ return false;
+
+ if (!pa_streq(version, POLICY_SUPPORTED_VERSION)) {
+ pa_log_warn("[%s:%u] We only support " ELEMENT_audioPolicyConfiguration
+ " version " POLICY_SUPPORTED_VERSION ". Expect problems.",
+ data->fn, data->lineno);
+ }
+
+ pa_xfree(version);
+
+ return true;
+}
+
+static bool parse_module(struct parser_data *data, const char *element_name, const XML_Char **attributes) {
+ struct module *m;
+ char *halVersion = NULL;
+
+ m = pa_xmalloc0(sizeof(*m));
+
+ get_element_attr(data, attributes, false, ATTRIBUTE_name, &m->name);
+
+ if (get_element_attr(data, attributes, false, ATTRIBUTE_halVersion, &halVersion))
+ pa_conversion_parse_version(data->fn, data->lineno, halVersion, &m->version);
+ else if (get_element_attr(data, attributes, false, ATTRIBUTE_version, &halVersion))
+ pa_conversion_parse_version(data->fn, data->lineno, halVersion, &m->version);
+
+ if (!m->version) {
+ pa_log_debug("[%s:%u] Could not find valid <" ELEMENT_module "> attribute " ATTRIBUTE_halVersion " or "
+ ATTRIBUTE_version ". Guessing version is 2.0.", data->fn, data->lineno);
+ m->version = HARDWARE_DEVICE_API_VERSION(2, 0);
+ }
+
+ if (!m->name)
+ m->name = pa_sprintf_malloc("module_at_line_%u", data->lineno);
+
+ SLLIST_APPEND(struct module, data->conf->modules, m);
+ data->current_module = m;
+ pa_log_debug("New " ELEMENT_module ": \"%s\"", m->name);
+
+ pa_xfree(halVersion);
+
+ return true;
+}
+
+static bool parse_global_configuration(struct parser_data *data, const char *element_name, const XML_Char **attributes) {
+ int i;
+
+ for (i = 0; attributes[i]; i += 2) {
+ struct global_configuration *c;
+ c = pa_xmalloc0(sizeof(*c));
+ c->key = xml_string_dup(attributes[i], -1);
+ c->value = xml_string_dup(attributes[i + 1], -1);
+ SLLIST_APPEND(struct global_configuration, data->conf->global, c);
+ }
+
+ return true;
+}
+
+static void parse_item(struct parser_data *data, const char *str) {
+ struct device *d;
+
+ d = pa_xmalloc0(sizeof(*d));
+ d->name = pa_xstrdup(str);
+ SLLIST_APPEND(struct device, data->current_module->attached_devices, d);
+}
+
+static void parse_default_output_device(struct parser_data *data, const char *str) {
+ struct device *d;
+
+ d = pa_xmalloc0(sizeof(*d));
+ d->name = pa_xstrdup(str);
+ SLLIST_APPEND(struct device, data->current_module->default_output, d);
+}
+
+static bool parse_mix_port(struct parser_data *data, const char *element_name, const XML_Char **attributes) {
+ struct mix_port *p;
+ bool parsed = false;
+ char *flags = NULL;
+
+ p = pa_xmalloc0(sizeof(*p));
+
+ if (!get_element_attrs(data, attributes,
+ ATTRIBUTE_name, &p->name,
+ ATTRIBUTE_role, &p->role,
+ NULL))
+ goto done;
+
+ /* flags is not mandatory element attribute */
+ if (get_element_attr(data, attributes, false, ATTRIBUTE_flags, &flags)) {
+ if (!(pa_streq(p->role, PORT_TYPE_source) ?
+ pa_conversion_parse_output_flags(data->fn, data->lineno, flags, &p->flags)
+ : pa_conversion_parse_input_flags(data->fn, data->lineno, flags, &p->flags)))
+ goto done;
+ }
+
+ parsed = true;
+done:
+ pa_xfree(flags);
+
+ if (parsed) {
+ SLLIST_APPEND(struct mix_port, data->current_module->mix_ports, p);
+ data->current_mix_port = p;
+ } else {
+ pa_log("[%s:%u] Failed to parse element <" ELEMENT_mixPort ">", data->fn, data->lineno);
+ mix_port_free(p);
+ }
+
+ return parsed;
+}
+
+static void replace_in_place(char **string, const char *a, const char *b) {
+ char *tmp;
+
+ pa_assert(*string);
+ pa_assert(a);
+ pa_assert(b);
+
+ tmp = pa_replace(*string, a, b);
+ pa_xfree(*string);
+ *string = tmp;
+}
+
+static bool parse_profile(struct parser_data *data, const char *element_name, const XML_Char **attributes) {
+ struct profile *p;
+ bool parsed = false, unknown_format = false, output = true;
+ char *samplingRates = NULL, *channelMasks = NULL, *format = NULL;
+
+ /* if the parsing of parent devicePort or mixPort failed
+ * we skip child profiles as well. */
+ if (!data->current_mix_port && !data->current_device_port)
+ return true;
+
+ p = pa_xmalloc0(sizeof(*p));
+
+ if (!get_element_attrs(data, attributes,
+ ATTRIBUTE_name, &p->name,
+ ATTRIBUTE_format, &format,
+ ATTRIBUTE_samplingRates, &samplingRates,
+ NULL))
+ goto done;
+
+ if (data->current_mix_port)
+ output = pa_streq(data->current_mix_port->role, PORT_TYPE_source);
+ else if (data->current_device_port)
+ output = pa_streq(data->current_device_port->role, PORT_TYPE_sink);
+ else
+ pa_assert_not_reached();
+
+ /* some devicePorts do not have channel masks */
+ get_element_attr(data, attributes, false, ATTRIBUTE_channelMasks, &channelMasks);
+
+ /* Hard-coded workaround for incorrect audio policy configuration. */
+ if (channelMasks && data->current_device_port) {
+ if (output && pa_startswith(channelMasks, "AUDIO_CHANNEL_IN_")) {
+ pa_log_info("[%s:%u] Output has wrong direction channel mask (%s), reversing.",
+ data->fn, data->lineno, channelMasks);
+ replace_in_place(&channelMasks, "AUDIO_CHANNEL_IN_", "AUDIO_CHANNEL_OUT_");
+ }
+ else if (!output && pa_startswith(channelMasks, "AUDIO_CHANNEL_OUT_")) {
+ pa_log_info("[%s:%u] Input has wrong direction channel mask (%s), reversing.",
+ data->fn, data->lineno, channelMasks);
+ replace_in_place(&channelMasks, "AUDIO_CHANNEL_OUT_", "AUDIO_CHANNEL_IN_");
+ }
+ }
+
+ if (!pa_conversion_parse_sampling_rates(data->fn, data->lineno, samplingRates, false, p->sampling_rates))
+ goto done;
+
+ if (!pa_conversion_parse_formats(data->fn, data->lineno, format, false, &p->format))
+ unknown_format = true;
+
+ if (!unknown_format && channelMasks && !(output ?
+ pa_conversion_parse_output_channels(data->fn, data->lineno, channelMasks, false, &p->channel_masks)
+ : pa_conversion_parse_input_channels(data->fn, data->lineno, channelMasks, false, &p->channel_masks)))
+ goto done;
+
+ parsed = true;
+done:
+ pa_xfree(samplingRates);
+ pa_xfree(channelMasks);
+ pa_xfree(format);
+
+ if (!parsed) {
+ pa_log_error("[%s:%u] Failed to parse element <" ELEMENT_profile ">", data->fn, data->lineno);
+ profile_free(p);
+ } else if (unknown_format) {
+ pa_log_info("[%s:%u] Ignore profile with unknown format.", data->fn, data->lineno);
+ profile_free(p);
+ } else {
+ if (data->current_mix_port)
+ SLLIST_APPEND(struct profile, data->current_module->mix_ports->profiles, p);
+ else if (data->current_device_port)
+ SLLIST_APPEND(struct profile, data->current_module->device_ports->profiles, p);
+ else
+ pa_assert_not_reached();
+ }
+
+ return parsed;
+}
+
+static bool parse_device_port(struct parser_data *data, const char *element_name, const XML_Char **attributes) {
+ struct device_port *d;
+ bool parsed = false, unknown_device = false;
+ char *type = NULL;
+
+ d = pa_xmalloc0(sizeof(*d));
+
+ if (!get_element_attrs(data, attributes,
+ ATTRIBUTE_tagName, &d->tag_name,
+ ATTRIBUTE_role, &d->role,
+ NULL))
+ goto done;
+
+ if (!get_element_attr(data, attributes, true, ATTRIBUTE_type, &type))
+ goto done;
+
+ if (!(pa_streq(d->role, ATTRIBUTE_sink) ?
+ pa_conversion_parse_output_devices(data->fn, data->lineno, type, false, false, &d->type)
+ : pa_conversion_parse_input_devices(data->fn, data->lineno, type, false, false, &d->type)))
+ unknown_device = true;
+
+ parsed = true;
+done:
+ pa_xfree(type);
+
+ if (!parsed) {
+ pa_log("[%s:%u] Failed to parse element <" ELEMENT_devicePort ">", data->fn, data->lineno);
+ device_port_free(d);
+ } else if (unknown_device) {
+ pa_log_info("[%s:%u] Ignore <" ELEMENT_devicePort "> with unknown device.", data->fn, data->lineno);
+ device_port_free(d);
+ } else {
+ SLLIST_APPEND(struct device_port, data->current_module->device_ports, d);
+ data->current_device_port = d;
+ }
+
+ return parsed;
+}
+
+static bool parse_route(struct parser_data *data, const char *element_name, const XML_Char **attributes) {
+ struct route *r;
+ bool parsed = false;
+ char *sources = NULL;
+ const char *state = NULL;
+ char *source;
+
+ r = pa_xmalloc0(sizeof(*r));
+
+ if (!get_element_attrs(data, attributes,
+ ATTRIBUTE_type, &r->type,
+ ATTRIBUTE_sink, &r->sink,
+ ATTRIBUTE_sources, &sources,
+ NULL))
+ goto done;
+
+ while ((source = pa_split(sources, ",", &state))) {
+ struct device *d = pa_xmalloc0(sizeof(*d));
+ d->name = source;
+ SLLIST_APPEND(struct device, r->sources, d);
+ }
+
+ parsed = true;
+done:
+ pa_xfree(sources);
+
+ if (parsed) {
+ SLLIST_APPEND(struct route, data->current_module->routes, r);
+ } else {
+ pa_log("[%s:%u] Failed to parse element <" ELEMENT_route ">", data->fn, data->lineno);
+ route_free(r);
+ }
+
+ return parsed;
+}
+
+static bool parse_file(struct parser_data *data, const char *filename) {
+ char buf[BUFSIZ];
+ FILE *f = NULL;
+ XML_Parser parser = NULL;
+ bool done;
+ bool ret = true;
+
+ pa_assert(data);
+ pa_assert(filename);
+
+ f = fopen(filename, "r");
+
+ if (!f) {
+ pa_log_info("Failed to open file (%s): %s", filename, pa_cstrerror(errno));
+ ret = false;
+ goto done;
+ }
+
+ parser = XML_ParserCreate(NULL);
+ data->parser = parser;
+ data->fn = filename;
+ if (!data->conf)
+ data->conf = pa_xnew0(struct audio_policy_configuration, 1);
+
+ XML_SetUserData(parser, data);
+ XML_SetElementHandler(parser, xml_start_element, xml_end_element);
+ XML_SetCharacterDataHandler(parser, xml_character_data_handler);
+
+ pa_log_debug("Read %s ...", data->fn);
+
+ do {
+ size_t len = fread(buf, 1, sizeof(buf), f);
+ done = len < sizeof(buf);
+ if (XML_Parse(parser, buf, (int) len, done) == XML_STATUS_ERROR) {
+ unsigned long lineno = XML_GetCurrentLineNumber(parser);
+ pa_log("%" XML_FMT_STR " at line %lu\n",
+ XML_ErrorString(XML_GetErrorCode(parser)),
+ lineno);
+ ret = false;
+ goto done;
+ }
+ } while (!done);
+
+done:
+ if (parser)
+ XML_ParserFree(parser);
+
+ if (f)
+ fclose(f);
+
+ return ret;
+}
+
+static struct device_port *find_device_port(struct module *module, const char *name) {
+ struct device_port *port;
+
+ SLLIST_FOREACH(port, module->device_ports) {
+ if (pa_streq(port->tag_name, name))
+ return port;
+ }
+
+ return NULL;
+}
+
+static bool device_in_list(struct device *list, const char *name) {
+ struct device *dev;
+
+ pa_assert(name);
+
+ SLLIST_FOREACH(dev, list) {
+ if (pa_streq(name, dev->name))
+ return true;
+ }
+
+ return false;
+}
+
+static void add_output(struct module *module, struct mix_port *mix_port, pa_droid_config_hw_module *hw_module) {
+ pa_droid_config_device *output;
+ struct profile *profile;
+ struct route *route;
+ struct device_port *device_port;
+
+ output = pa_droid_config_device_new(hw_module, PA_DIRECTION_OUTPUT, mix_port->name);
+ output->flags = mix_port->flags;
+ SLLIST_FOREACH(profile, mix_port->profiles) {
+ memcpy(output->sampling_rates, profile->sampling_rates, sizeof(output->sampling_rates));
+ output->channel_masks |= profile->channel_masks;
+ output->formats |= profile->format;
+ }
+
+ SLLIST_FOREACH(route, module->routes) {
+ struct device *source;
+ SLLIST_FOREACH(source, route->sources) {
+ if (pa_streq(source->name, mix_port->name)) {
+ if ((device_port = find_device_port(module, route->sink))) {
+ output->devices |= device_port->type;
+ if (device_in_list(module->attached_devices, device_port->tag_name))
+ hw_module->global_config->attached_output_devices |= device_port->type;
+ if (device_in_list(module->default_output, device_port->tag_name))
+ hw_module->global_config->default_output_device |= device_port->type;
+ break;
+ } else
+ pa_log_info("Couldn't find matching <" ELEMENT_devicePort " tagName=%s> for <" ELEMENT_mixPort " name=%s>",
+ route->sink, source->name);
+ }
+ }
+ }
+
+ pa_log_debug("config: %s: New output: %s", hw_module->name, output->name);
+ SLLIST_APPEND(pa_droid_config_device, hw_module->outputs, output);
+}
+
+static void add_input(struct module *module, struct mix_port *mix_port, pa_droid_config_hw_module *hw_module) {
+ pa_droid_config_device *input;
+ struct profile *profile;
+ struct route *route;
+ struct device_port *device_port;
+
+ input = pa_droid_config_device_new(hw_module, PA_DIRECTION_INPUT, mix_port->name);
+ input->flags = mix_port->flags;
+ SLLIST_FOREACH(profile, mix_port->profiles) {
+ memcpy(input->sampling_rates, profile->sampling_rates, sizeof(input->sampling_rates));
+ input->channel_masks |= profile->channel_masks;
+ input->formats |= profile->format;
+ }
+
+ SLLIST_FOREACH(route, module->routes) {
+ if (pa_streq(route->sink, mix_port->name)) {
+ struct device *source;
+ SLLIST_FOREACH(source, route->sources) {
+ if ((device_port = find_device_port(module, source->name))) {
+ input->devices |= device_port->type;
+ if (device_in_list(module->attached_devices, device_port->tag_name))
+ hw_module->global_config->attached_input_devices |= device_port->type;
+ } else
+ pa_log_info("Couldn't find matching <" ELEMENT_mixPort " name=%s> for <" ELEMENT_devicePort " tagName=%s>",
+ source->name, route->sink);
+
+ }
+ }
+ }
+
+ pa_log_debug("config: %s: New input: %s", hw_module->name, input->name);
+ SLLIST_APPEND(pa_droid_config_device, hw_module->inputs, input);
+}
+
+static void generate_config_for_module(struct module *module, pa_droid_config_audio *config) {
+ pa_droid_config_hw_module *hw_module;
+ struct mix_port *mix_port;
+
+ pa_assert(module);
+ pa_assert(config);
+ pa_assert(config->global_config);
+
+ hw_module = pa_droid_config_hw_module_new(config, module->name);
+ if (module->attached_devices || module->default_output)
+ hw_module->global_config = pa_xnew0(pa_droid_config_global, 1);
+ SLLIST_APPEND(pa_droid_config_hw_module, config->hw_modules, hw_module);
+
+ SLLIST_FOREACH(mix_port, module->mix_ports) {
+ if (pa_streq(mix_port->role, PORT_TYPE_source))
+ add_output(module, mix_port, hw_module);
+ else if (pa_streq(mix_port->role, ATTRIBUTE_sink))
+ add_input(module, mix_port, hw_module);
+ else
+ pa_log_warn("Unknown <" ELEMENT_mixPort "> role \"%s\"", mix_port->role);
+ }
+}
+
+static pa_droid_config_audio *convert_config(struct audio_policy_configuration *source) {
+ pa_droid_config_audio *config = NULL;
+ struct module *module;
+
+ pa_assert(source);
+
+ config = pa_xnew0(pa_droid_config_audio, 1);
+ config->global_config = pa_xnew0(pa_droid_config_global, 1);
+
+ pa_log_debug("Convert configuration ...");
+ SLLIST_FOREACH(module, source->modules)
+ generate_config_for_module(module, config);
+
+ return config;
+}
+
+pa_droid_config_audio *pa_parse_droid_audio_config_xml(const char *filename) {
+ pa_droid_config_audio *config = NULL;
+ struct parser_data data;
+ bool ret = true;
+
+ pa_assert(filename);
+
+ memset(&data, 0, sizeof(data));
+
+ data.root = &element_parse_root;
+ data.current = data.root;
+
+ if (!(ret = parse_file(&data, filename)))
+ goto done;
+
+ config = convert_config(data.conf);
+
+done:
+ if (data.conf)
+ audio_policy_configuration_free(data.conf);
+
+ return config;
+}
+
+#endif
|
[-]
[+]
|
Added |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/src/common/conversion.c
^
|
@@ -0,0 +1,475 @@
+/*
+ * Copyright (C) 2013-2018 Jolla Ltd.
+ *
+ * Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
+ *
+ * These PulseAudio Modules are free software; you can redistribute
+ * it and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "droid/version.h"
+#if ANDROID_VERSION_MAJOR == 4 && ANDROID_VERSION_MINOR == 1
+#include "droid-util-41qc.h"
+#else
+#include "droid-util-audio.h"
+#endif
+
+#include <pulsecore/core-util.h>
+
+#include <hardware/audio.h>
+
+#include "droid/conversion.h"
+#include "droid/droid-config.h"
+
+#define CONVERT_FUNC(TABL) \
+bool pa_convert_ ## TABL (uint32_t value, pa_conversion_field_t field, uint32_t *to_value) { \
+ for (unsigned int i = 0; i < sizeof( conversion_table_ ## TABL )/(sizeof(uint32_t)*2); i++) { \
+ if ( conversion_table_ ## TABL [i][field] == value) { \
+ *to_value = conversion_table_ ## TABL [i][!field]; \
+ return true; \
+ } \
+ } \
+ return false; \
+} struct __funny_extra_to_allow_semicolon
+
+/* Creates convert_format convert_channel etc.
+ * bool pa_convert_func(uint32_t value, pa_conversion_field_t field, uint32_t *to_value);
+ * return true if conversion succesful */
+CONVERT_FUNC(format);
+CONVERT_FUNC(output_channel);
+CONVERT_FUNC(input_channel);
+
+#define value_separator(legacy) (legacy ? "|" : ",")
+
+static bool string_convert_num_to_str(const struct string_conversion *list, const uint32_t value, const char **to_str) {
+ pa_assert(list);
+ pa_assert(to_str);
+
+ for (unsigned int i = 0; list[i].str; i++) {
+ if (list[i].value == value) {
+ *to_str = list[i].str;
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool string_convert_str_to_num(const struct string_conversion *list, const char *str, uint32_t *to_value) {
+ pa_assert(list);
+ pa_assert(str);
+ pa_assert(to_value);
+
+ for (unsigned int i = 0; list[i].str; i++) {
+ if (pa_streq(list[i].str, str)) {
+ *to_value = list[i].value;
+ return true;
+ }
+ }
+ return false;
+}
+
+static char *list_string(struct string_conversion *list, uint32_t flags) {
+ char *str = NULL;
+ char *tmp;
+
+#if AUDIO_API_VERSION_MAJ >= 2
+ if (flags & AUDIO_DEVICE_BIT_IN)
+ flags &= ~AUDIO_DEVICE_BIT_IN;
+#endif
+
+ for (unsigned int i = 0; list[i].str; i++) {
+#if AUDIO_API_VERSION_MAJ >= 2
+ if (list[i].value & AUDIO_DEVICE_BIT_IN) {
+ if (popcount(list[i].value & ~AUDIO_DEVICE_BIT_IN) != 1)
+ continue;
+ } else
+#endif
+ if (popcount(list[i].value) != 1)
+ continue;
+
+ if (flags & list[i].value) {
+ if (str) {
+ tmp = pa_sprintf_malloc("%s|%s", str, list[i].str);
+ pa_xfree(str);
+ str = tmp;
+ } else {
+ str = pa_sprintf_malloc("%s", list[i].str);
+ }
+ }
+ }
+
+ return str;
+}
+
+
+/* Output device */
+bool pa_string_convert_output_device_num_to_str(audio_devices_t value, const char **to_str) {
+ return string_convert_num_to_str(string_conversion_table_output_device, (uint32_t) value, to_str);
+}
+
+bool pa_string_convert_output_device_str_to_num(const char *str, audio_devices_t *to_value) {
+ return string_convert_str_to_num(string_conversion_table_output_device, str, (uint32_t*) to_value);
+}
+
+char *pa_list_string_output_device(audio_devices_t devices) {
+ return list_string(string_conversion_table_output_device, devices);
+}
+
+/* Input device */
+bool pa_string_convert_input_device_num_to_str(audio_devices_t value, const char **to_str) {
+ return string_convert_num_to_str(string_conversion_table_input_device, (uint32_t) value, to_str);
+}
+
+bool pa_string_convert_input_device_str_to_num(const char *str, audio_devices_t *to_value) {
+ return string_convert_str_to_num(string_conversion_table_input_device, str, (uint32_t*) to_value);
+}
+
+char *pa_list_string_input_device(audio_devices_t devices) {
+ return list_string(string_conversion_table_input_device, devices);
+}
+
+/* Flags */
+bool pa_string_convert_flag_num_to_str(audio_output_flags_t value, const char **to_str) {
+ return string_convert_num_to_str(string_conversion_table_output_flag, (uint32_t) value, to_str);
+}
+
+bool pa_string_convert_flag_str_to_num(const char *str, audio_output_flags_t *to_value) {
+ return string_convert_str_to_num(string_conversion_table_output_flag, str, (uint32_t*) to_value);
+}
+
+char *pa_list_string_flags(audio_output_flags_t flags) {
+ return list_string(string_conversion_table_output_flag, flags);
+}
+
+bool pa_input_device_default_audio_source(audio_devices_t input_device, audio_source_t *default_source)
+{
+#if AUDIO_API_VERSION_MAJ >= 2
+ input_device &= ~AUDIO_DEVICE_BIT_IN;
+#endif
+
+ /* Note converting HAL values to different HAL values! */
+ for (unsigned int i = 0; i < sizeof(conversion_table_default_audio_source) / (sizeof(uint32_t) * 2); i++) {
+ if (conversion_table_default_audio_source[i][0] & input_device) {
+ *default_source = conversion_table_default_audio_source[i][1];
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool pa_droid_output_port_name(audio_devices_t value, const char **to_str) {
+ return string_convert_num_to_str(string_conversion_table_output_device_fancy, (uint32_t) value, to_str);
+}
+
+bool pa_droid_input_port_name(audio_devices_t value, const char **to_str) {
+ return string_convert_num_to_str(string_conversion_table_input_device_fancy, (uint32_t) value, to_str);
+}
+
+bool pa_droid_audio_source_name(audio_source_t value, const char **to_str) {
+ return string_convert_num_to_str(string_conversion_table_audio_source_fancy, (uint32_t) value, to_str);
+}
+
+static int parse_list(const struct string_conversion *table,
+ const char *separator,
+ const char *str,
+ uint32_t *dst,
+ char **unknown_entries) {
+ int count = 0;
+ char *entry;
+ char *unknown = NULL;
+ const char *state = NULL;
+
+ pa_assert(table);
+ pa_assert(separator);
+ pa_assert(str);
+ pa_assert(dst);
+ pa_assert(unknown_entries);
+
+ *dst = 0;
+ *unknown_entries = NULL;
+
+ while ((entry = pa_split(str, separator, &state))) {
+ uint32_t d = 0;
+
+ if (!string_convert_str_to_num(table, entry, &d)) {
+ if (*unknown_entries) {
+ unknown = pa_sprintf_malloc("%s|%s", *unknown_entries, entry);
+ pa_xfree(*unknown_entries);
+ pa_xfree(entry);
+ } else
+ unknown = entry;
+
+ *unknown_entries = unknown;
+ continue;
+ }
+
+ *dst |= d;
+ count++;
+
+ pa_xfree(entry);
+ }
+
+ return count;
+}
+
+int pa_conversion_parse_list(pa_conversion_string_t type, const char *separator,
+ const char *str, uint32_t *dst, char **unknown_entries) {
+ switch (type) {
+ case CONV_STRING_FORMAT:
+ return parse_list(string_conversion_table_format, separator, str, dst, unknown_entries);
+
+ case CONV_STRING_OUTPUT_CHANNELS:
+ return parse_list(string_conversion_table_output_channels, separator, str, dst, unknown_entries);
+
+ case CONV_STRING_INPUT_CHANNELS:
+ return parse_list(string_conversion_table_input_channels, separator, str, dst, unknown_entries);
+
+ case CONV_STRING_OUTPUT_DEVICE:
+ return parse_list(string_conversion_table_output_device, separator, str, dst, unknown_entries);
+
+ case CONV_STRING_INPUT_DEVICE:
+ return parse_list(string_conversion_table_input_device, separator, str, dst, unknown_entries);
+
+ case CONV_STRING_OUTPUT_FLAG:
+ return parse_list(string_conversion_table_output_flag, separator, str, dst, unknown_entries);
+
+ case CONV_STRING_INPUT_FLAG:
+ return parse_list(string_conversion_table_input_flag, separator, str, dst, unknown_entries);
+ }
+
+ pa_assert_not_reached();
+ return 0;
+}
+
+bool pa_conversion_parse_sampling_rates(const char *fn, const unsigned ln,
+ const char *str, bool legacy,
+ uint32_t sampling_rates[AUDIO_MAX_SAMPLING_RATES]) {
+ pa_assert(fn);
+ pa_assert(str);
+
+ char *entry;
+ const char *state = NULL;
+
+ uint32_t pos = 0;
+ while ((entry = pa_split(str, value_separator(legacy), &state))) {
+ int32_t val;
+
+#if AUDIO_API_VERSION_MAJ >= 3
+ if (pos == 0 && pa_streq(entry, "dynamic")) {
+ sampling_rates[pos++] = (uint32_t) -1;
+ pa_xfree(entry);
+ break;
+ }
+#endif
+
+ if (pos == AUDIO_MAX_SAMPLING_RATES) {
+ pa_log("[%s:%u] Too many sample rate entries (> %d)", fn, ln, AUDIO_MAX_SAMPLING_RATES);
+ pa_xfree(entry);
+ return false;
+ }
+
+ if (pa_atoi(entry, &val) < 0) {
+ pa_log("[%s:%u] Bad sample rate value %s", fn, ln, entry);
+ pa_xfree(entry);
+ return false;
+ }
+
+ sampling_rates[pos++] = val;
+
+ pa_xfree(entry);
+
+ }
+
+ sampling_rates[pos] = 0;
+
+ return true;
+}
+
+static bool check_and_log(const char *fn, const unsigned ln, const char *field,
+ const int count, const char *str, char *unknown,
+ const bool must_recognize_all) {
+ bool fail;
+
+ pa_assert(fn);
+ pa_assert(field);
+ pa_assert(str);
+
+ fail = must_recognize_all && unknown;
+
+ if (unknown) {
+ pa_log_info("[%s:%u] Unknown %s entries: %s", fn, ln, field, unknown);
+ pa_xfree(unknown);
+ }
+
+ if (count == 0 || fail) {
+ pa_log("[%s:%u] Failed to parse %s (%s).", fn, ln, field, str);
+ return false;
+ }
+
+ return true;
+}
+
+bool pa_conversion_parse_formats(const char *fn, const unsigned ln,
+ const char *str, bool legacy,
+ audio_format_t *formats) {
+ int count;
+ char *unknown = NULL;
+
+ pa_assert(fn);
+ pa_assert(str);
+ pa_assert(formats);
+
+#if AUDIO_API_VERSION_MAJ >= 3
+ /* Needs to be probed later */
+ if (pa_streq(str, "dynamic")) {
+ *formats = 0;
+ return true;
+ }
+#endif
+
+ count = pa_conversion_parse_list(CONV_STRING_FORMAT, value_separator(legacy), str, formats, &unknown);
+
+ if (legacy)
+ return check_and_log(fn, ln, "formats", count, str, unknown, false);
+
+ /* As the new XML configuration lists formats as one per profile, unknown
+ * formats will cause the parser to quit. As a workaround for non-legacy
+ * conversions with no recognized formats log only info level and return false. */
+ check_and_log(fn, ln, "format", count == 0 ? 1 : count, str, unknown, false);
+ return count > 0;
+}
+
+static bool parse_channels(const char *fn, const unsigned ln,
+ const char *str, bool in_output,
+ bool legacy, audio_channel_mask_t *channels) {
+ int count;
+ char *unknown = NULL;
+
+ pa_assert(fn);
+ pa_assert(str);
+ pa_assert(channels);
+
+ /* Needs to be probed later */
+ if (pa_streq(str, "dynamic")) {
+ *channels = 0;
+ return true;
+ }
+
+ count = pa_conversion_parse_list(in_output ? CONV_STRING_OUTPUT_CHANNELS : CONV_STRING_INPUT_CHANNELS,
+ value_separator(legacy), str, channels, &unknown);
+
+ return check_and_log(fn, ln, in_output ? "output channel_masks" : "input channel_masks",
+ count, str, unknown, false);
+}
+
+bool pa_conversion_parse_output_channels(const char *fn, const unsigned ln,
+ const char *str, bool legacy,
+ audio_channel_mask_t *channels) {
+ return parse_channels(fn, ln, str, true, legacy, channels);
+}
+
+bool pa_conversion_parse_input_channels(const char *fn, const unsigned ln,
+ const char *str, bool legacy,
+ audio_channel_mask_t *channels) {
+ return parse_channels(fn, ln, str, false, legacy, channels);
+}
+
+static bool parse_devices(const char *fn, const unsigned ln,
+ const char *str, bool in_output,
+ bool legacy, bool must_recognize_all,
+ audio_devices_t *devices) {
+ int count;
+ char *unknown = NULL;
+
+ pa_assert(fn);
+ pa_assert(str);
+ pa_assert(devices);
+
+ count = pa_conversion_parse_list(in_output ? CONV_STRING_OUTPUT_DEVICE : CONV_STRING_INPUT_DEVICE,
+ value_separator(legacy), str, devices, &unknown);
+
+ if (legacy)
+ return check_and_log(fn, ln, in_output ? "output devices" : "input devices",
+ count, str, unknown, must_recognize_all);
+
+ /* As the new XML configuration lists devices as one per devicePort, unknown
+ * devices will cause the parser to quit. As a workaround for non-legacy
+ * conversions with no recognized devices log only info level and return false. */
+ check_and_log(fn, ln, in_output ? "output device" : "input device",
+ count == 0 ? 1 : count, str, unknown, must_recognize_all);
+ return count > 0;
+}
+
+bool pa_conversion_parse_output_devices(const char *fn, const unsigned ln,
+ char *str, bool legacy, bool must_recognize_all,
+ audio_devices_t *devices) {
+ return parse_devices(fn, ln, str, true, legacy, must_recognize_all, devices);
+}
+
+bool pa_conversion_parse_input_devices(const char *fn, const unsigned ln,
+ char *str, bool legacy, bool must_recognize_all,
+ audio_devices_t *devices) {
+ return parse_devices(fn, ln, str, false, legacy, must_recognize_all, devices);
+}
+
+bool pa_conversion_parse_output_flags(const char *fn, const unsigned ln,
+ const char *str, audio_output_flags_t *flags) {
+ int count;
+ char *unknown = NULL;
+
+ pa_assert(fn);
+ pa_assert(str);
+ pa_assert(flags);
+
+ count = pa_conversion_parse_list(CONV_STRING_OUTPUT_FLAG, "|", str, flags, &unknown);
+
+ return check_and_log(fn, ln, "flags", count, str, unknown, false);
+}
+
+bool pa_conversion_parse_input_flags(const char *fn, const unsigned ln,
+ const char *str, uint32_t *flags) {
+ int count;
+ char *unknown = NULL;
+
+ pa_assert(fn);
+ pa_assert(str);
+ pa_assert(flags);
+
+ count = pa_conversion_parse_list(CONV_STRING_INPUT_FLAG, "|", str, flags, &unknown);
+
+ return check_and_log(fn, ln, "flags", count, str, unknown, false);
+}
+
+bool pa_conversion_parse_version(const char *fn, const unsigned ln, const char *str, uint32_t *version) {
+ uint32_t version_maj;
+ uint32_t version_min;
+
+ pa_assert(fn);
+ pa_assert(str);
+ pa_assert(version);
+
+ if ((sscanf(str, "%u.%u", &version_maj, &version_min)) != 2) {
+ pa_log("[%s:%u] Failed to parse %s (%s).", fn, ln, AUDIO_HAL_VERSION_TAG, str);
+ return false;
+ } else {
+ *version = HARDWARE_DEVICE_API_VERSION(version_maj, version_min);
+ return true;
+ }
+}
|
[-]
[+]
|
Added |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/src/common/droid-config.c
^
|
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2013-2018 Jolla Ltd.
+ *
+ * Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
+ *
+ * These PulseAudio Modules are free software; you can redistribute
+ * it and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "droid/version.h"
+#include "droid/droid-config.h"
+#include "droid/sllist.h"
+
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+
+#ifdef HAVE_VALGRIND_MEMCHECK_H
+#include <valgrind/memcheck.h>
+#endif
+
+#include <pulse/rtclock.h>
+#include <pulse/timeval.h>
+#include <pulse/volume.h>
+#include <pulse/xmalloc.h>
+
+#include <pulsecore/core.h>
+#include <pulsecore/core-error.h>
+#include <pulsecore/i18n.h>
+#include <pulsecore/module.h>
+#include <pulsecore/memchunk.h>
+#include <pulsecore/sink.h>
+#include <pulsecore/modargs.h>
+#include <pulsecore/core-rtclock.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/sample-util.h>
+#include <pulsecore/log.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/thread.h>
+#include <pulsecore/thread-mq.h>
+#include <pulsecore/rtpoll.h>
+#include <pulsecore/time-smoother.h>
+#include <pulsecore/refcnt.h>
+#include <pulsecore/shared.h>
+#include <pulsecore/mutex.h>
+#include <pulsecore/strlist.h>
+#include <pulsecore/atomic.h>
+
+#include <hardware/audio.h>
+#include <hardware_legacy/audio_policy_conf.h>
+
+#define VENDOR_AUDIO_POLICY_CONFIG_XML_FILE "/vendor/etc/audio_policy_configuration.xml"
+#define SYSTEM_AUDIO_POLICY_CONFIG_XML_FILE "/system/etc/audio_policy_configuration.xml"
+
+
+pa_droid_config_audio *pa_droid_config_load(pa_modargs *ma) {
+ pa_droid_config_audio *config = NULL;
+ const char *manual_config;
+ const char *config_location[] = {
+ VENDOR_AUDIO_POLICY_CONFIG_XML_FILE,
+ AUDIO_POLICY_VENDOR_CONFIG_FILE,
+ SYSTEM_AUDIO_POLICY_CONFIG_XML_FILE,
+ AUDIO_POLICY_CONFIG_FILE,
+ NULL};
+
+ pa_assert(ma);
+
+ if ((manual_config = pa_modargs_get_value(ma, "config", NULL))) {
+ if (!(config = pa_parse_droid_audio_config(manual_config)))
+ pa_log("Failed to parse configuration from %s", manual_config);
+ } else {
+ int i;
+ for (i = 0; config_location[i]; i++) {
+ if ((config = pa_parse_droid_audio_config(config_location[i])))
+ break;
+ else
+ pa_log_debug("Failed to parse configuration from %s", config_location[i]);
+ }
+
+ }
+
+ if (!config)
+ pa_log("Failed to parse any configuration.");
+
+ return config;
+}
+
+pa_droid_config_audio *pa_droid_config_dup(const pa_droid_config_audio *config) {
+ pa_droid_config_audio *config_copy;
+ pa_droid_config_hw_module *module, *module_copy;
+ pa_droid_config_device *device, *device_copy;
+
+ pa_assert(config);
+
+ config_copy = pa_xnew0(pa_droid_config_audio, 1);
+
+ if (config->global_config)
+ config_copy->global_config = pa_xmemdup(config->global_config, sizeof(*config->global_config));
+
+ SLLIST_FOREACH(module, config->hw_modules) {
+ module_copy = pa_droid_config_hw_module_new(config_copy, module->name);
+ if (module->global_config)
+ module_copy->global_config = pa_xmemdup(module->global_config, sizeof(*module->global_config));
+
+ SLLIST_FOREACH(device, module->outputs) {
+ device_copy = pa_xmemdup(device, sizeof(*device));
+ device_copy->module = module_copy;
+ device_copy->name = pa_xstrdup(device->name);
+ SLLIST_APPEND(pa_droid_config_device, module_copy->outputs, device_copy);
+ }
+
+ SLLIST_FOREACH(device, module->inputs) {
+ device_copy = pa_xmemdup(device, sizeof(*device));
+ device_copy->module = module_copy;
+ device_copy->name = pa_xstrdup(device->name);
+ SLLIST_APPEND(pa_droid_config_device, module_copy->inputs, device_copy);
+ }
+
+ SLLIST_APPEND(pa_droid_config_hw_module, config_copy->hw_modules, module_copy);
+ }
+
+ return config_copy;
+}
+
+pa_droid_config_audio *pa_parse_droid_audio_config(const char *filename) {
+ const char *suffix;
+
+ pa_assert(filename);
+
+ if ((suffix = rindex(filename, '.'))) {
+ if (strlen(suffix) == 4 && pa_streq(suffix, ".xml"))
+ return pa_parse_droid_audio_config_xml(filename);
+ else if (strlen(suffix) == 5 && pa_streq(suffix, ".conf"))
+ return pa_parse_droid_audio_config_legacy(filename);
+ }
+
+ return NULL;
+}
+
+void pa_droid_config_free(pa_droid_config_audio *config) {
+ pa_droid_config_hw_module *module;
+ pa_droid_config_device *device;
+
+ if (!config)
+ return;
+
+ while (config->hw_modules) {
+ SLLIST_STEAL_FIRST(module, config->hw_modules);
+
+ while (module->outputs) {
+ SLLIST_STEAL_FIRST(device, module->outputs);
+ pa_droid_config_device_free(device);
+ }
+
+ while (module->inputs) {
+ SLLIST_STEAL_FIRST(device, module->inputs);
+ pa_droid_config_device_free(device);
+ }
+
+ pa_droid_config_hw_module_free(module);
+ }
+
+ pa_xfree(config->global_config);
+ pa_xfree(config);
+}
+
+const pa_droid_config_hw_module *pa_droid_config_find_module(const pa_droid_config_audio *config, const char* module_id) {
+ pa_droid_config_hw_module *module;
+
+ pa_assert(config);
+ pa_assert(module_id);
+
+ SLLIST_FOREACH(module, config->hw_modules) {
+ if (pa_streq(module_id, module->name))
+ return module;
+ }
+
+ return NULL;
+}
+
+pa_droid_config_hw_module *pa_droid_config_hw_module_new(const pa_droid_config_audio *config, const char *name) {
+ pa_droid_config_hw_module *hw_module;
+
+ pa_assert(config);
+ pa_assert(name);
+
+ hw_module = pa_xnew0(pa_droid_config_hw_module, 1);
+ hw_module->config = config;
+ hw_module->name = pa_xstrndup(name, AUDIO_HARDWARE_MODULE_ID_MAX_LEN);
+
+ return hw_module;
+}
+
+void pa_droid_config_hw_module_free(pa_droid_config_hw_module *hw_module) {
+ if (!hw_module)
+ return;
+
+ pa_xfree(hw_module->name);
+ pa_xfree(hw_module->global_config);
+ pa_xfree(hw_module);
+}
+
+pa_droid_config_device *pa_droid_config_device_new(const pa_droid_config_hw_module *module,
+ pa_direction_t direction,
+ const char *name) {
+ pa_droid_config_device *device;
+
+ pa_assert(module);
+ pa_assert(direction == PA_DIRECTION_OUTPUT || direction == PA_DIRECTION_INPUT);
+ pa_assert(name);
+
+ device = pa_xnew0(pa_droid_config_device, 1);
+ device->module = module;
+ device->direction = direction;
+ device->name = pa_replace(name, " ", "_");
+
+ return device;
+}
+
+void pa_droid_config_device_free(pa_droid_config_device *device) {
+ if (!device)
+ return;
+
+ pa_xfree(device->name);
+ pa_xfree(device);
+}
|
[-]
[+]
|
Changed |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/src/common/droid-util-41qc.h
^
|
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2013 Jolla Ltd.
*
- * Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
+ * Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
*
* These PulseAudio Modules are free software; you can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public
@@ -29,6 +29,8 @@
#include <hardware/audio.h>
#include <hardware_legacy/audio_policy_conf.h>
+#include <pulse/channelmap.h>
+
// PulseAudio value - Android value
uint32_t conversion_table_output_channel[][2] = {
@@ -214,6 +216,10 @@
{ 0, NULL }
};
+struct string_conversion string_conversion_table_input_flag[] = {
+ { 0, NULL }
+};
+
/* Channels */
struct string_conversion string_conversion_table_output_channels[] = {
STRING_ENTRY(AUDIO_CHANNEL_OUT_FRONT_LEFT),
|
[-]
[+]
|
Changed |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/src/common/droid-util-audio.h
^
|
@@ -22,6 +22,7 @@
#ifndef _DROID_UTIL_AUDIO_H_
#define _DROID_UTIL_AUDIO_H_
+#include <android-config.h>
#ifdef QCOM_BSP
#define QCOM_HARDWARE
#endif
@@ -29,9 +30,7 @@
#include <hardware/audio.h>
#include <hardware_legacy/audio_policy_conf.h>
-#ifdef SPEAKER_DRC_ENABLED_TAG
-#define DROID_HAVE_DRC
-#endif
+#include <pulse/channelmap.h>
#ifdef STRING_ENTRY
|
[-]
[+]
|
Changed |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/src/common/droid-util.c
^
|
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2013 Jolla Ltd.
+ * Copyright (C) 2013-2018 Jolla Ltd.
*
- * Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
+ * Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
*
* These PulseAudio Modules are free software; you can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public
@@ -23,6 +23,7 @@
#include <config.h>
#endif
+#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
@@ -35,6 +36,7 @@
#include <pulse/timeval.h>
#include <pulse/volume.h>
#include <pulse/xmalloc.h>
+#include <pulse/direction.h>
#include <pulsecore/core.h>
#include <pulsecore/core-error.h>
@@ -58,7 +60,11 @@
#include <pulsecore/strlist.h>
#include <pulsecore/atomic.h>
-#include "droid-util.h"
+#include "droid/version.h"
+#include "droid/droid-util.h"
+#include "droid/droid-config.h"
+#include "droid/conversion.h"
+#include "droid/sllist.h"
struct droid_quirk {
const char *name;
@@ -71,855 +77,23 @@
{ "close_input", QUIRK_CLOSE_INPUT },
{ "unload_no_close", QUIRK_UNLOAD_NO_CLOSE },
{ "no_hw_volume", QUIRK_NO_HW_VOLUME },
+ { "output_make_writable", QUIRK_OUTPUT_MAKE_WRITABLE },
+ { "realcall", QUIRK_REALCALL },
+ { "unload_call_exit", QUIRK_UNLOAD_CALL_EXIT },
};
-struct pa_droid_quirks {
- bool enabled[QUIRK_COUNT];
-};
-
-#define SLLIST_APPEND(t, head, item) \
- do { \
- item->next = NULL; \
- if (!head) { \
- head = item; \
- } else { \
- t *_list; \
- for (_list = head; _list->next; _list = _list->next); \
- _list->next = item; \
- } \
- } while (0)
-
-#define SLLIST_FOREACH(i, head) \
- for (i = (head); i; i = i->next)
-
-#define SLLIST_STEAL_FIRST(i, head) \
- do { \
- if (head) { \
- i = head; \
- head = head->next; \
- } else \
- i = NULL; \
- } while (0)
-
-
-#define CONVERT_FUNC(TABL) \
-bool pa_convert_ ## TABL (uint32_t value, pa_conversion_field_t field, uint32_t *to_value) { \
- for (unsigned int i = 0; i < sizeof( conversion_table_ ## TABL )/(sizeof(uint32_t)*2); i++) { \
- if ( conversion_table_ ## TABL [i][field] == value) { \
- *to_value = conversion_table_ ## TABL [i][!field]; \
- return true; \
- } \
- } \
- return false; \
-} struct __funny_extra_to_allow_semicolon
-
-/* Creates convert_format convert_channel etc.
- * bool pa_convert_func(uint32_t value, pa_conversion_field_t field, uint32_t *to_value);
- * return true if conversion succesful */
-CONVERT_FUNC(format);
-CONVERT_FUNC(output_channel);
-CONVERT_FUNC(input_channel);
#define DEFAULT_PRIORITY (100)
-/* Section defining custom global configuration variables. */
-#define GLOBAL_CONFIG_EXT_TAG "custom_properties"
-
-/* From recent audio_policy_conf.h */
-#ifndef AUDIO_HAL_VERSION_TAG
-#define AUDIO_HAL_VERSION_TAG "audio_hal_version"
-#endif
-#ifndef GAINS_TAG
-#define GAINS_TAG "gains"
-#endif
-
-#define GAIN_TAG_PREFIX "gain_"
-
static const char * const droid_combined_auto_outputs[3] = { "primary", "low_latency", NULL };
static const char * const droid_combined_auto_inputs[2] = { "primary", NULL };
-static void droid_config_free(pa_droid_config_audio *config);
static void droid_port_free(pa_droid_port *p);
static pa_droid_stream *get_primary_output(pa_droid_hw_module *hw);
static int input_stream_set_route(pa_droid_stream *s, audio_devices_t device);
-static bool string_convert_num_to_str(const struct string_conversion *list, const uint32_t value, const char **to_str) {
- pa_assert(list);
- pa_assert(to_str);
-
- for (unsigned int i = 0; list[i].str; i++) {
- if (list[i].value == value) {
- *to_str = list[i].str;
- return true;
- }
- }
- return false;
-}
-
-static bool string_convert_str_to_num(const struct string_conversion *list, const char *str, uint32_t *to_value) {
- pa_assert(list);
- pa_assert(str);
- pa_assert(to_value);
-
- for (unsigned int i = 0; list[i].str; i++) {
- if (pa_streq(list[i].str, str)) {
- *to_value = list[i].value;
- return true;
- }
- }
- return false;
-}
-
-static char *list_string(struct string_conversion *list, uint32_t flags) {
- char *str = NULL;
- char *tmp;
-
-#if AUDIO_API_VERSION_MAJ >= 2
- if (flags & AUDIO_DEVICE_BIT_IN)
- flags &= ~AUDIO_DEVICE_BIT_IN;
-#endif
-
- for (unsigned int i = 0; list[i].str; i++) {
-#if AUDIO_API_VERSION_MAJ >= 2
- if (list[i].value & AUDIO_DEVICE_BIT_IN) {
- if (popcount(list[i].value & ~AUDIO_DEVICE_BIT_IN) != 1)
- continue;
- } else
-#endif
- if (popcount(list[i].value) != 1)
- continue;
-
- if (flags & list[i].value) {
- if (str) {
- tmp = pa_sprintf_malloc("%s|%s", str, list[i].str);
- pa_xfree(str);
- str = tmp;
- } else {
- str = pa_sprintf_malloc("%s", list[i].str);
- }
- }
- }
-
- return str;
-}
-
-
-/* Output device */
-bool pa_string_convert_output_device_num_to_str(audio_devices_t value, const char **to_str) {
- return string_convert_num_to_str(string_conversion_table_output_device, (uint32_t) value, to_str);
-}
-
-bool pa_string_convert_output_device_str_to_num(const char *str, audio_devices_t *to_value) {
- return string_convert_str_to_num(string_conversion_table_output_device, str, (uint32_t*) to_value);
-}
-
-char *pa_list_string_output_device(audio_devices_t devices) {
- return list_string(string_conversion_table_output_device, devices);
-}
-
-/* Input device */
-bool pa_string_convert_input_device_num_to_str(audio_devices_t value, const char **to_str) {
- return string_convert_num_to_str(string_conversion_table_input_device, (uint32_t) value, to_str);
-}
-
-bool pa_string_convert_input_device_str_to_num(const char *str, audio_devices_t *to_value) {
- return string_convert_str_to_num(string_conversion_table_input_device, str, (uint32_t*) to_value);
-}
-
-char *pa_list_string_input_device(audio_devices_t devices) {
- return list_string(string_conversion_table_input_device, devices);
-}
-
-/* Flags */
-bool pa_string_convert_flag_num_to_str(audio_output_flags_t value, const char **to_str) {
- return string_convert_num_to_str(string_conversion_table_output_flag, (uint32_t) value, to_str);
-}
-
-bool pa_string_convert_flag_str_to_num(const char *str, audio_output_flags_t *to_value) {
- return string_convert_str_to_num(string_conversion_table_output_flag, str, (uint32_t*) to_value);
-}
-
-char *pa_list_string_flags(audio_output_flags_t flags) {
- return list_string(string_conversion_table_output_flag, flags);
-}
-
-bool pa_input_device_default_audio_source(audio_devices_t input_device, audio_source_t *default_source)
-{
-#if AUDIO_API_VERSION_MAJ >= 2
- input_device &= ~AUDIO_DEVICE_BIT_IN;
-#endif
-
- /* Note converting HAL values to different HAL values! */
- for (unsigned int i = 0; i < sizeof(conversion_table_default_audio_source) / (sizeof(uint32_t) * 2); i++) {
- if (conversion_table_default_audio_source[i][0] & input_device) {
- *default_source = conversion_table_default_audio_source[i][1];
- return true;
- }
- }
- return false;
-}
-
-/* Config parser */
-
-#define WHITESPACE "\n\r \t"
-
-static int parse_list(const struct string_conversion *table,
- const char *str,
- uint32_t *dst,
- char **unknown_entries) {
- int count = 0;
- char *entry;
- char *unknown = NULL;
- const char *state = NULL;
-
- pa_assert(table);
- pa_assert(str);
- pa_assert(dst);
- pa_assert(unknown_entries);
-
- *dst = 0;
- *unknown_entries = NULL;
-
- while ((entry = pa_split(str, "|", &state))) {
- uint32_t d = 0;
-
- if (!string_convert_str_to_num(table, entry, &d)) {
- if (*unknown_entries) {
- unknown = pa_sprintf_malloc("%s|%s", *unknown_entries, entry);
- pa_xfree(*unknown_entries);
- pa_xfree(entry);
- } else
- unknown = entry;
-
- *unknown_entries = unknown;
- continue;
- }
-
- *dst |= d;
- count++;
-
- pa_xfree(entry);
- }
-
- return count;
-}
-
-static bool parse_sampling_rates(const char *fn, const unsigned ln,
- const char *str, uint32_t sampling_rates[32]) {
- pa_assert(fn);
- pa_assert(str);
-
- char *entry;
- const char *state = NULL;
-
- uint32_t pos = 0;
- while ((entry = pa_split(str, "|", &state))) {
- int32_t val;
-
-#if AUDIO_API_VERSION_MAJ >= 3
- if (pos == 0 && pa_streq(entry, "dynamic")) {
- sampling_rates[pos++] = (uint32_t) -1;
- pa_xfree(entry);
- break;
- }
-#endif
-
- if (pos == AUDIO_MAX_SAMPLING_RATES) {
- pa_log("[%s:%u] Too many sample rate entries (> %d)", fn, ln, AUDIO_MAX_SAMPLING_RATES);
- pa_xfree(entry);
- return false;
- }
-
- if (pa_atoi(entry, &val) < 0) {
- pa_log("[%s:%u] Bad sample rate value %s", fn, ln, entry);
- pa_xfree(entry);
- return false;
- }
-
- sampling_rates[pos++] = val;
-
- pa_xfree(entry);
-
- }
-
- sampling_rates[pos] = 0;
-
- return true;
-}
-
-static bool check_and_log(const char *fn, const unsigned ln, const char *field,
- const int count, const char *str, char *unknown,
- const bool must_have_all) {
- bool fail;
-
- pa_assert(fn);
- pa_assert(field);
- pa_assert(str);
-
- fail = must_have_all && unknown;
-
- if (unknown) {
- pa_log_info("[%s:%u] Unknown %s entries: %s", fn, ln, field, unknown);
- pa_xfree(unknown);
- }
-
- if (count == 0 || fail) {
- pa_log("[%s:%u] Failed to parse %s (%s).", fn, ln, field, str);
- return false;
- }
-
- return true;
-}
-
-static bool parse_formats(const char *fn, const unsigned ln,
- const char *str, audio_format_t *formats) {
- int count;
- char *unknown = NULL;
-
- pa_assert(fn);
- pa_assert(str);
- pa_assert(formats);
-
-#if AUDIO_API_VERSION_MAJ >= 3
- /* Needs to be probed later */
- if (pa_streq(str, "dynamic")) {
- *formats = 0;
- return true;
- }
-#endif
-
- count = parse_list(string_conversion_table_format, str, formats, &unknown);
-
- return check_and_log(fn, ln, "formats", count, str, unknown, false);
-}
-
-static bool parse_channels(const char *fn, const unsigned ln,
- const char *str, bool in_output, audio_channel_mask_t *channels) {
- int count;
- char *unknown = NULL;
-
- pa_assert(fn);
- pa_assert(str);
- pa_assert(channels);
-
- /* Needs to be probed later */
- if (pa_streq(str, "dynamic")) {
- *channels = 0;
- return true;
- }
-
- count = parse_list(in_output ? string_conversion_table_output_channels
- : string_conversion_table_input_channels,
- str, channels, &unknown);
-
- return check_and_log(fn, ln, in_output ? "output channel_masks" : "input channel_masks",
- count, str, unknown, false);
-}
-
-static bool parse_devices(const char *fn, const unsigned ln,
- const char *str, bool in_output, audio_devices_t *devices, bool must_have_all) {
- int count;
- char *unknown = NULL;
-
- pa_assert(fn);
- pa_assert(str);
- pa_assert(devices);
-
- count = parse_list(in_output ? string_conversion_table_output_device
- : string_conversion_table_input_device,
- str, devices, &unknown);
-
- return check_and_log(fn, ln, in_output ? "output devices" : "input devices",
- count, str, unknown, must_have_all);
-}
-
-static bool parse_output_flags(const char *fn, const unsigned ln,
- const char *str, audio_output_flags_t *flags) {
- int count;
- char *unknown = NULL;
-
- pa_assert(fn);
- pa_assert(str);
- pa_assert(flags);
-
- count = parse_list(string_conversion_table_output_flag, str, flags, &unknown);
-
- return check_and_log(fn, ln, "flags", count, str, unknown, false);
-}
-
-#if AUDIO_API_VERSION_MAJ >= 3
-static bool parse_input_flags(const char *fn, const unsigned ln,
- const char *str, audio_input_flags_t *flags) {
- int count;
- char *unknown = NULL;
-
- pa_assert(fn);
- pa_assert(str);
- pa_assert(flags);
-
- count = parse_list(string_conversion_table_input_flag, str, flags, &unknown);
-
- return check_and_log(fn, ln, "flags", count, str, unknown, false);
-}
-#endif
-
-static bool parse_version(const char *fn, const unsigned ln, const char *str, uint32_t *version) {
- uint32_t version_maj;
- uint32_t version_min;
-
- pa_assert(fn);
- pa_assert(str);
- pa_assert(version);
-
- if ((sscanf(str, "%u.%u", &version_maj, &version_min)) != 2) {
- pa_log("[%s:%u] Failed to parse %s (%s).", fn, ln, AUDIO_HAL_VERSION_TAG, str);
- return false;
- } else {
- *version = HARDWARE_DEVICE_API_VERSION(version_maj, version_min);
- return true;
- }
-}
-
-static void log_parse_error(const char *fn, const unsigned ln, const char *section, const char *v) {
- pa_log("[%s:%u] failed to parse line in section %s: unknown section (%s)", fn, ln, section, v);
-}
-
-#define MAX_LINE_LENGTH (1024)
-
-bool pa_parse_droid_audio_config(const char *filename, pa_droid_config_audio *config) {
- FILE *f;
- unsigned n = 0;
- bool ret = true;
- char *full_line = NULL;
- uint32_t hw_module_count = 0;
-
- enum config_loc {
- IN_ROOT = 0,
- IN_GLOBAL = 1,
- IN_GLOBAL_EXT = 2,
- IN_HW_MODULES = 3,
- IN_MODULE = 4,
- IN_OUTPUT_INPUT = 5,
- IN_CONFIG = 6,
- IN_MODULE_GLOBAL = 10,
- IN_DEVICES = 20,
- IN_DEVICES_DEVICE = 21,
- IN_GAINS = 22,
- IN_GAIN_N = 23
- } loc = IN_ROOT;
-
- bool in_output = true;
-
- pa_droid_config_hw_module *module = NULL;
- pa_droid_config_output *output = NULL;
- pa_droid_config_input *input = NULL;
-
- pa_assert(filename);
- pa_assert(config);
-
- memset(config, 0, sizeof(pa_droid_config_audio));
- config->global_config = pa_xnew0(pa_droid_config_global, 1);
-
- f = fopen(filename, "r");
-
- if (!f) {
- pa_log_info("Failed to open config file (%s): %s", filename, pa_cstrerror(errno));
- ret = false;
- goto finish;
- }
-
- pa_lock_fd(fileno(f), 1);
-
- full_line = pa_xmalloc0(sizeof(char) * MAX_LINE_LENGTH);
-
- while (!feof(f)) {
- char *ln, *d, *v, *value;
-
- if (!fgets(full_line, MAX_LINE_LENGTH, f))
- break;
-
- n++;
-
- pa_strip_nl(full_line);
-
- if (!*full_line)
- continue;
-
- ln = full_line + strspn(full_line, WHITESPACE);
-
- if (ln[0] == '#')
- continue;
-
- v = ln;
- d = v + strcspn(v, WHITESPACE);
-
- value = d + strspn(d, WHITESPACE);
- d[0] = '\0';
- d = value + strcspn(value, WHITESPACE);
- d[0] = '\0';
-
- /* Enter section */
- if (pa_streq(value, "{")) {
-
- if (!*v) {
- pa_log("[%s:%u] failed to parse line - too few words", filename, n);
- goto finish;
- }
-
- switch (loc) {
- case IN_ROOT:
- if (pa_streq(v, GLOBAL_CONFIG_TAG)) {
- loc = IN_GLOBAL;
- }
- else if (pa_streq(v, AUDIO_HW_MODULE_TAG))
- loc = IN_HW_MODULES;
- else {
- log_parse_error(filename, n, "<root>", v);
- ret = false;
- goto finish;
- }
- break;
-
- case IN_GLOBAL:
- if (pa_streq(v, GLOBAL_CONFIG_EXT_TAG))
- loc = IN_GLOBAL_EXT;
- else {
- log_parse_error(filename, n, GLOBAL_CONFIG_TAG, v);
- ret = false;
- goto finish;
- }
- break;
-
- case IN_HW_MODULES:
- pa_assert(!module);
-
- module = pa_xnew0(pa_droid_config_hw_module, 1);
- SLLIST_APPEND(pa_droid_config_hw_module, config->hw_modules, module);
- hw_module_count++;
- module->name = pa_xstrndup(v, AUDIO_HARDWARE_MODULE_ID_MAX_LEN);
- module->config = config;
- loc = IN_MODULE;
- pa_log_debug("config: New module: %s", module->name);
- break;
-
- case IN_MODULE:
- pa_assert(module);
-
- if (pa_streq(v, OUTPUTS_TAG)) {
- loc = IN_OUTPUT_INPUT;
- in_output = true;
- } else if (pa_streq(v, INPUTS_TAG)) {
- loc = IN_OUTPUT_INPUT;
- in_output = false;
- } else if (pa_streq(v, GLOBAL_CONFIG_TAG)) {
- loc = IN_MODULE_GLOBAL;
- } else if (pa_streq(v, DEVICES_TAG)) {
- loc = IN_DEVICES;
- } else {
- log_parse_error(filename, n, module->name, v);
- ret = false;
- goto finish;
- }
- break;
-
- case IN_OUTPUT_INPUT:
- pa_assert(module);
-
- if (in_output) {
- output = pa_xnew0(pa_droid_config_output, 1);
- SLLIST_APPEND(pa_droid_config_output, module->outputs, output);
- output->name = pa_xstrndup(v, AUDIO_HARDWARE_MODULE_ID_MAX_LEN);
- output->module = module;
- loc = IN_CONFIG;
- pa_log_debug("config: %s: New output: %s", module->name, output->name);
- } else {
- input = pa_xnew0(pa_droid_config_input, 1);
- SLLIST_APPEND(pa_droid_config_input, module->inputs, input);
- input->name = pa_xstrndup(v, AUDIO_HARDWARE_MODULE_ID_MAX_LEN);
- input->module = module;
- loc = IN_CONFIG;
- pa_log_debug("config: %s: New input: %s", module->name, input->name);
- }
- break;
-
- case IN_DEVICES:
- /* TODO Missing implementation of parsing the module/devices section.
- * As of now there is no need for the information, fix this when that
- * changes. */
- loc = IN_DEVICES_DEVICE;
- break;
-
- case IN_DEVICES_DEVICE:
- if (pa_streq(v, GAINS_TAG))
- loc = IN_GAINS;
- else {
- log_parse_error(filename, n, DEVICES_TAG, v);
- ret = false;
- goto finish;
- }
- break;
-
- case IN_GAINS:
- /* TODO Missing implementation of parsing the gain_n section.
- * As of now there is no need for the information, fix this when that
- * changes. */
- if (pa_startswith(v, GAIN_TAG_PREFIX))
- loc = IN_GAIN_N;
- else {
- log_parse_error(filename, n, GAINS_TAG, v);
- ret = false;
- goto finish;
- }
- break;
-
- case IN_CONFIG:
- if (pa_streq(v, GAINS_TAG)) {
- loc = IN_GAINS;
- } else {
- log_parse_error(filename, n, in_output ? output->name : input->name, v);
- ret = false;
- goto finish;
- }
- break;
-
- default:
- pa_log("[%s:%u] failed to parse line: unknown section (%s)", filename, n, v);
- ret = false;
- goto finish;
- }
-
- continue;
- }
-
- /* Exit section */
- if (pa_streq(v, "}")) {
- switch (loc) {
- case IN_ROOT:
- pa_log("[%s:%u] failed to parse line - extra closing bracket", filename, n);
- ret = false;
- goto finish;
-
- case IN_HW_MODULES:
- /* fall through */
- case IN_GLOBAL:
- loc = IN_ROOT;
- break;
-
- case IN_MODULE:
- module = NULL;
- loc = IN_HW_MODULES;
- break;
-
- case IN_DEVICES:
- /* fall through */
- case IN_MODULE_GLOBAL:
- loc = IN_MODULE;
- break;
-
- case IN_GAINS:
- if (output || input)
- loc = IN_CONFIG;
- else
- loc = IN_DEVICES_DEVICE;
- break;
-
- case IN_OUTPUT_INPUT:
- if (in_output)
- output = NULL;
- else
- input = NULL;
- /* fall through */
- case IN_GAIN_N:
- /* fall through */
- case IN_DEVICES_DEVICE:
- /* fall through */
- case IN_CONFIG:
- /* fall through */
- case IN_GLOBAL_EXT:
- loc--;
- break;
- }
-
- continue;
- }
-
- /* Parsing of values */
- if (loc == IN_GLOBAL ||
- loc == IN_GLOBAL_EXT ||
- loc == IN_MODULE_GLOBAL ||
- loc == IN_CONFIG ||
- loc == IN_DEVICES_DEVICE ||
- loc == IN_GAIN_N) {
-
- bool success = false;
-
- if (loc == IN_GLOBAL || loc == IN_MODULE_GLOBAL) {
- pa_droid_config_global *global_config = NULL;
-
- if (loc == IN_MODULE_GLOBAL) {
- pa_assert(module);
- if (!module->global_config)
- module->global_config = pa_xnew0(pa_droid_config_global, 1);
- global_config = module->global_config;
- } else
- global_config = config->global_config;
-
- pa_assert(global_config);
-
- /* Parse global configuration */
-
- if (pa_streq(v, ATTACHED_OUTPUT_DEVICES_TAG))
- success = parse_devices(filename, n, value, true,
- &global_config->attached_output_devices, false);
- else if (pa_streq(v, DEFAULT_OUTPUT_DEVICE_TAG))
- success = parse_devices(filename, n, value, true,
- &global_config->default_output_device, true);
- else if (pa_streq(v, ATTACHED_INPUT_DEVICES_TAG))
- success = parse_devices(filename, n, value, false,
- &global_config->attached_input_devices, false);
- else if (pa_streq(v, AUDIO_HAL_VERSION_TAG))
- success = parse_version(filename, n, value,
- &global_config->audio_hal_version);
-#ifdef DROID_HAVE_DRC
- // SPEAKER_DRC_ENABLED_TAG is only from Android v4.4
- else if (pa_streq(v, SPEAKER_DRC_ENABLED_TAG))
- /* TODO - Add support for dynamic range control */
- success = true; /* Do not fail while parsing speaker_drc_enabled entry */
-#endif
- else {
- pa_log("[%s:%u] failed to parse line - unknown config entry %s", filename, n, v);
- success = false;
- }
-
- } else if (loc == IN_GLOBAL_EXT) {
-
- /* Parse custom global configuration
- * For now just log all custom variables, don't do
- * anything with the values.
- * TODO: Store custom values somehow */
-
- pa_log_debug("[%s:%u] TODO custom variable: %s = %s", filename, n, v, value);
- success = true;
-
- } else if (loc == IN_CONFIG) {
-
- /* Parse per-output or per-input configuration */
-
- if ((in_output && !output) || (!in_output && !input)) {
- pa_log("[%s:%u] failed to parse line", filename, n);
- ret = false;
- goto finish;
- }
-
- if (pa_streq(v, SAMPLING_RATES_TAG))
- success = parse_sampling_rates(filename, n, value,
- in_output ? output->sampling_rates : input->sampling_rates);
- else if (pa_streq(v, FORMATS_TAG))
- success = parse_formats(filename, n, value, in_output ? &output->formats : &input->formats);
- else if (pa_streq(v, CHANNELS_TAG)) {
- if (in_output)
- success = parse_channels(filename, n, value, true, &output->channel_masks);
- else
- success = parse_channels(filename, n, value, false, &input->channel_masks);
- } else if (pa_streq(v, DEVICES_TAG)) {
- if (in_output)
- success = parse_devices(filename, n, value, true, &output->devices, false);
- else
- success = parse_devices(filename, n, value, false, &input->devices, false);
- } else if (pa_streq(v, FLAGS_TAG)) {
- if (in_output)
- success = parse_output_flags(filename, n, value, &output->flags);
- else {
-#if AUDIO_API_VERSION_MAJ >= 3
- success = parse_input_flags(filename, n, value, &input->flags);
-#else
- pa_log("[%s:%u] failed to parse line - output flags inside input definition", filename, n);
- success = false;
-#endif
- }
- } else {
- pa_log("[%s:%u] failed to parse line - unknown config entry %s", filename, n, v);
- success = false;
- }
-
- } else if (loc == IN_DEVICES_DEVICE) {
- /* TODO Missing implementation of parsing the module/devices section.
- * As of now there is no need for the information, fix this when that
- * changes. */
- success = true;
- } else if (loc == IN_GAIN_N) {
- /* TODO Missing implementation of parsing the gain_n section.
- * As of now there is no need for the information, fix this when that
- * changes. */
- success = true;
- } else
- pa_assert_not_reached();
-
- if (!success) {
- ret = false;
- goto finish;
- }
- }
- }
-
- pa_log_info("Parsed config file (%s): %u modules.", filename, hw_module_count);
-
-finish:
- if (f) {
- pa_lock_fd(fileno(f), 0);
- fclose(f);
- }
-
- pa_xfree(full_line);
-
- return ret;
-}
-
-
-const pa_droid_config_output *pa_droid_config_find_output(const pa_droid_config_hw_module *module, const char *name) {
- pa_droid_config_output *output;
-
- pa_assert(module);
- pa_assert(name);
-
- SLLIST_FOREACH(output, module->outputs) {
- if (pa_streq(name, output->name))
- return output;
- }
-
- return NULL;
-}
-
-const pa_droid_config_input *pa_droid_config_find_input(const pa_droid_config_hw_module *module, const char *name) {
- pa_droid_config_input *input;
-
- pa_assert(module);
- pa_assert(name);
-
- SLLIST_FOREACH(input, module->inputs) {
- if (pa_streq(name, input->name))
- return input;
- }
-
- return NULL;
-}
-
-const pa_droid_config_hw_module *pa_droid_config_find_module(const pa_droid_config_audio *config, const char* module_id) {
- pa_droid_config_hw_module *module;
-
- pa_assert(config);
- pa_assert(module_id);
-
- SLLIST_FOREACH(module, config->hw_modules) {
- if (pa_streq(module_id, module->name))
- return module;
- }
-
- return NULL;
-}
-
static pa_droid_profile *profile_new(pa_droid_profile_set *ps,
const pa_droid_config_hw_module *module,
const char *name,
@@ -947,15 +121,17 @@
}
static pa_droid_profile *droid_profile_new(pa_droid_profile_set *ps,
- const pa_droid_config_output *primary_output,
- const pa_droid_config_output *output,
- const pa_droid_config_input *input) {
+ const pa_droid_config_device *primary_output,
+ const pa_droid_config_device *output,
+ const pa_droid_config_device *input) {
pa_droid_profile *p;
char *name;
char *description;
pa_assert(ps);
pa_assert(output);
+ pa_assert(!primary_output || primary_output->direction == PA_DIRECTION_OUTPUT);
+ pa_assert(!input || input->direction == PA_DIRECTION_INPUT);
name = pa_sprintf_malloc("%s%s%s", output->name, input ? "-" : "", input ? input->name : "");
description = pa_sprintf_malloc("%s output%s%s%s", output->name,
@@ -975,11 +151,11 @@
}
if (primary_output && primary_output != output)
- pa_idxset_put(p->output_mappings, pa_droid_mapping_get(ps, PA_DIRECTION_OUTPUT, primary_output), NULL);
+ pa_idxset_put(p->output_mappings, pa_droid_mapping_get(ps, primary_output), NULL);
if (output)
- pa_idxset_put(p->output_mappings, pa_droid_mapping_get(ps, PA_DIRECTION_OUTPUT, output), NULL);
+ pa_idxset_put(p->output_mappings, pa_droid_mapping_get(ps, output), NULL);
if (input)
- pa_idxset_put(p->input_mappings, pa_droid_mapping_get(ps, PA_DIRECTION_INPUT, input), NULL);
+ pa_idxset_put(p->input_mappings, pa_droid_mapping_get(ps, input), NULL);
return p;
}
@@ -995,11 +171,15 @@
}
static pa_droid_profile *add_profile(pa_droid_profile_set *ps,
- const pa_droid_config_output *primary_output,
- const pa_droid_config_output *output,
- const pa_droid_config_input *input) {
+ const pa_droid_config_device *primary_output,
+ const pa_droid_config_device *output,
+ const pa_droid_config_device *input) {
pa_droid_profile *ap;
+ pa_assert(primary_output && primary_output->direction == PA_DIRECTION_OUTPUT);
+ pa_assert(output && output->direction == PA_DIRECTION_OUTPUT);
+ pa_assert(!input || input->direction == PA_DIRECTION_INPUT);
+
pa_log_debug("New profile: %s-%s", output->name, input ? input->name : "no input");
ap = droid_profile_new(ps, primary_output, output, input);
@@ -1030,12 +210,13 @@
static void add_all_profiles(pa_droid_profile_set *ps,
const pa_droid_config_hw_module *module,
- const pa_droid_config_output *primary_output) {
- pa_droid_config_output *output;
- pa_droid_config_input *input;
+ const pa_droid_config_device *primary_output) {
+ pa_droid_config_device *output;
+ pa_droid_config_device *input;
pa_assert(ps);
pa_assert(module);
+ pa_assert(primary_output && primary_output->direction == PA_DIRECTION_OUTPUT);
/* Each distinct hw module output matches one profile. If there are multiple inputs
* combinations are made so that all possible outputs and inputs can be selected.
@@ -1063,36 +244,41 @@
static void add_default_profile(pa_droid_profile_set *ps,
const pa_droid_config_hw_module *module,
- const pa_droid_config_output *primary_output,
- const pa_droid_config_output *low_latency_output,
- const pa_droid_config_output *media_latency_output,
- const pa_droid_config_input *builtin_input,
- const pa_droid_config_input *external_input,
+ const pa_droid_config_device *primary_output,
+ const pa_droid_config_device *low_latency_output,
+ const pa_droid_config_device *media_latency_output,
+ const pa_droid_config_device *builtin_input,
+ const pa_droid_config_device *external_input,
bool merge_inputs) {
pa_droid_profile *p;
pa_assert(ps);
pa_assert(module);
+ pa_assert(!primary_output || primary_output->direction == PA_DIRECTION_OUTPUT);
+ pa_assert(!low_latency_output || primary_output->direction == PA_DIRECTION_OUTPUT);
+ pa_assert(!media_latency_output || primary_output->direction == PA_DIRECTION_OUTPUT);
+ pa_assert(!builtin_input || builtin_input->direction == PA_DIRECTION_INPUT);
+ pa_assert(!external_input || external_input->direction == PA_DIRECTION_INPUT);
pa_log_debug("New default profile");
p = profile_new(ps, module, "default", "Default profile");
if (primary_output)
- pa_idxset_put(p->output_mappings, pa_droid_mapping_get(ps, PA_DIRECTION_OUTPUT, primary_output), NULL);
+ pa_idxset_put(p->output_mappings, pa_droid_mapping_get(ps, primary_output), NULL);
if (low_latency_output && primary_output != low_latency_output)
- pa_idxset_put(p->output_mappings, pa_droid_mapping_get(ps, PA_DIRECTION_OUTPUT, low_latency_output), NULL);
+ pa_idxset_put(p->output_mappings, pa_droid_mapping_get(ps, low_latency_output), NULL);
if (media_latency_output && primary_output != media_latency_output && low_latency_output != media_latency_output)
- pa_idxset_put(p->output_mappings, pa_droid_mapping_get(ps, PA_DIRECTION_OUTPUT, media_latency_output), NULL);
+ pa_idxset_put(p->output_mappings, pa_droid_mapping_get(ps, media_latency_output), NULL);
if (builtin_input && external_input && builtin_input != external_input && merge_inputs) {
pa_idxset_put(p->input_mappings, pa_droid_mapping_merged_get(ps, builtin_input, external_input), NULL);
} else {
if (builtin_input)
- pa_idxset_put(p->input_mappings, pa_droid_mapping_get(ps, PA_DIRECTION_INPUT, builtin_input), NULL);
+ pa_idxset_put(p->input_mappings, pa_droid_mapping_get(ps, builtin_input), NULL);
if (external_input && builtin_input != external_input)
- pa_idxset_put(p->input_mappings, pa_droid_mapping_get(ps, PA_DIRECTION_INPUT, external_input), NULL);
+ pa_idxset_put(p->input_mappings, pa_droid_mapping_get(ps, external_input), NULL);
}
p->priority += DEFAULT_PRIORITY * (pa_idxset_size(p->output_mappings) + pa_idxset_size(p->input_mappings));
@@ -1103,15 +289,15 @@
static void auto_add_profiles(pa_droid_profile_set *ps,
const pa_droid_config_hw_module *module,
bool merge_inputs) {
- const pa_droid_config_output *output;
- const pa_droid_config_input *input;
+ const pa_droid_config_device *output;
+ const pa_droid_config_device *input;
- const pa_droid_config_output *primary_output = NULL;
- const pa_droid_config_output *low_latency_output = NULL;
- const pa_droid_config_output *media_latency_output = NULL;
+ const pa_droid_config_device *primary_output = NULL;
+ const pa_droid_config_device *low_latency_output = NULL;
+ const pa_droid_config_device *media_latency_output = NULL;
- const pa_droid_config_input *builtin_input = NULL;
- const pa_droid_config_input *external_input = NULL;
+ const pa_droid_config_device *builtin_input = NULL;
+ const pa_droid_config_device *external_input = NULL;
uint32_t input_devices;
@@ -1390,42 +576,35 @@
pa_idxset_put(am->ports, p, NULL);
}
-pa_droid_mapping *pa_droid_mapping_get(pa_droid_profile_set *ps, pa_direction_t direction, const void *data) {
+pa_droid_mapping *pa_droid_mapping_get(pa_droid_profile_set *ps, const pa_droid_config_device *device) {
pa_droid_mapping *am;
pa_hashmap *map;
- const char *name;
- const pa_droid_config_output *output = NULL;
- const pa_droid_config_input *input = NULL;
- if (direction == PA_DIRECTION_OUTPUT) {
- output = (pa_droid_config_output *) data;
- map = ps->output_mappings;
- name = output->name;
- } else {
- input = (pa_droid_config_input *) data;
- map = ps->input_mappings;
- name = input->name;
- }
+ pa_assert(ps);
+ pa_assert(device);
- if ((am = pa_hashmap_get(map, name))) {
- pa_log_debug(" %s mapping %s from cache", input ? "Input" : "Output", name);
+ map = device->direction == PA_DIRECTION_OUTPUT ? ps->output_mappings : ps->input_mappings;
+
+ if ((am = pa_hashmap_get(map, device->name))) {
+ pa_log_debug(" %s mapping %s from cache", pa_direction_to_string(device->direction), device->name);
return am;
}
- pa_log_debug(" New %s mapping %s", input ? "input" : "output", name);
+ pa_log_debug(" New %s mapping %s", pa_direction_to_string(device->direction), device->name);
am = pa_xnew0(pa_droid_mapping, 1);
am->profile_set = ps;
- am->name = pa_xstrdup(name);
+ am->name = pa_xstrdup(device->name);
am->proplist = pa_proplist_new();
- am->direction = direction;
- am->output = output;
- am->input = input;
+ am->direction = device->direction;
am->ports = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);;
- if (am->direction == PA_DIRECTION_OUTPUT)
+ if (am->direction == PA_DIRECTION_OUTPUT) {
+ am->output = device;
add_o_ports(am);
- else
+ } else {
+ am->input = device;
add_i_ports(am);
+ }
pa_hashmap_put(map, am->name, am);
@@ -1433,16 +612,20 @@
}
pa_droid_mapping *pa_droid_mapping_merged_get(pa_droid_profile_set *ps,
- const pa_droid_config_input *input1,
- const pa_droid_config_input *input2) {
+ const pa_droid_config_device *input1,
+ const pa_droid_config_device *input2) {
pa_droid_mapping *am;
pa_hashmap *map = ps->input_mappings;
char *name;
+ pa_assert(ps);
+ pa_assert(input1 && input1->direction == PA_DIRECTION_INPUT);
+ pa_assert(input2 && input2->direction == PA_DIRECTION_INPUT);
+
name = pa_sprintf_malloc("%s+%s", input1->name, input2->name);
if ((am = pa_hashmap_get(map, name))) {
- pa_log_debug(" Input mapping %s from cache", name);
+ pa_log_debug(" input mapping %s from cache", name);
pa_xfree(name);
return am;
}
@@ -1470,10 +653,13 @@
if (am->direction == PA_DIRECTION_OUTPUT) {
pa_assert(am->output);
- return pa_streq(am->output->name, PA_DROID_PRIMARY_DEVICE);
+ return am->output->flags & AUDIO_OUTPUT_FLAG_PRIMARY;
} else {
pa_assert(am->input);
- return pa_streq(am->input->name, PA_DROID_PRIMARY_DEVICE);
+ /* merged input mapping is always primary */
+ if (am->input && am->input2)
+ return true;
+ return pa_startswith(am->input->name, PA_DROID_PRIMARY_DEVICE);
}
}
@@ -1491,16 +677,31 @@
return NULL;
}
-bool pa_droid_output_port_name(audio_devices_t value, const char **to_str) {
- return string_convert_num_to_str(string_conversion_table_output_device_fancy, (uint32_t) value, to_str);
-}
+pa_droid_mapping *pa_droid_idxset_mapping_with_device(pa_idxset *i, uint32_t device) {
+ pa_droid_mapping *am;
+ uint32_t idx;
-bool pa_droid_input_port_name(audio_devices_t value, const char **to_str) {
- return string_convert_num_to_str(string_conversion_table_input_device_fancy, (uint32_t) value, to_str);
-}
+ pa_assert(i);
-bool pa_droid_audio_source_name(audio_source_t value, const char **to_str) {
- return string_convert_num_to_str(string_conversion_table_audio_source_fancy, (uint32_t) value, to_str);
+#if AUDIO_API_VERSION_MAJ >= 2
+ device &= ~AUDIO_DEVICE_BIT_IN;
+#endif
+
+ PA_IDXSET_FOREACH(am, i, idx) {
+ if (am->direction == PA_DIRECTION_OUTPUT) {
+ pa_assert(am->output);
+ if (am->output->devices & device)
+ return am;
+ } else {
+ uint32_t all_devices;
+ pa_assert(am->input);
+ all_devices = am->input->devices | (am->input2 ? am->input2->devices : 0);
+ if (all_devices & device)
+ return am;
+ }
+ }
+
+ return NULL;
}
static int add_ports(pa_core *core, pa_card_profile *cp, pa_hashmap *ports, pa_droid_mapping *am, pa_hashmap *extra) {
@@ -1660,15 +861,6 @@
return false;
}
-bool pa_droid_quirk(pa_droid_hw_module *hw, enum pa_droid_quirk_type quirk) {
- pa_assert(hw);
-
- if (hw->quirks && hw->quirks->enabled[quirk])
- return true;
- else
- return false;
-}
-
static void update_sink_types(pa_droid_hw_module *hw, pa_sink *ignore_sink) {
pa_sink *sink;
pa_sink *primary_sink = NULL;
@@ -1818,7 +1010,7 @@
return pa_sprintf_malloc("droid-hardware-module-%s", module_id);
}
-static pa_droid_hw_module *droid_hw_module_open(pa_core *core, pa_droid_config_audio *config, const char *module_id) {
+static pa_droid_hw_module *droid_hw_module_open(pa_core *core, const pa_droid_config_audio *config, const char *module_id) {
const pa_droid_config_hw_module *module;
pa_droid_hw_module *hw = NULL;
struct hw_module_t *hwmod = NULL;
@@ -1829,13 +1021,13 @@
pa_assert(core);
pa_assert(module_id);
- pa_log_info("Droid hw module %s", VERSION);
-
if (!config) {
- pa_log("No configuration provided for opening module with id %s", module_id);
+ pa_log_debug("No configuration provided for opening module with id %s", module_id);
goto fail;
}
+ pa_log_info("Droid hw module %s", VERSION);
+
if (!(module = pa_droid_config_find_module(config, module_id))) {
pa_log("Couldn't find module with id %s", module_id);
goto fail;
@@ -1874,7 +1066,7 @@
hw->output_mutex = pa_mutex_new(true, false);
hw->input_mutex = pa_mutex_new(true, false);
hw->device = device;
- hw->config = config; /* We take ownership of config struct. */
+ hw->config = pa_droid_config_dup(config);
hw->enabled_module = pa_droid_config_find_module(hw->config, module_id);
hw->module_id = hw->enabled_module->name;
hw->shared_name = shared_name_get(hw->module_id);
@@ -1908,7 +1100,7 @@
return NULL;
}
-pa_droid_hw_module *pa_droid_hw_module_get(pa_core *core, pa_droid_config_audio *config, const char *module_id) {
+pa_droid_hw_module *pa_droid_hw_module_get(pa_core *core, const pa_droid_config_audio *config, const char *module_id) {
pa_droid_hw_module *hw;
char *shared_name;
@@ -1954,10 +1146,14 @@
pa_hook_done(&hw->hooks[h]);
if (hw->config)
- droid_config_free(hw->config);
+ pa_droid_config_free(hw->config);
- if (hw->device && !pa_droid_quirk(hw, QUIRK_UNLOAD_NO_CLOSE))
- audio_hw_device_close(hw->device);
+ if (hw->device) {
+ if (pa_droid_quirk(hw, QUIRK_UNLOAD_CALL_EXIT))
+ exit(EXIT_SUCCESS);
+ else if (!pa_droid_quirk(hw, QUIRK_UNLOAD_NO_CLOSE))
+ audio_hw_device_close(hw->device);
+ }
if (hw->hw_mutex)
pa_mutex_free(hw->hw_mutex);
@@ -1998,72 +1194,6 @@
droid_hw_module_close(hw);
}
-static void droid_config_free(pa_droid_config_audio *config) {
- pa_droid_config_hw_module *module;
- pa_droid_config_output *output;
- pa_droid_config_input *input;
-
- pa_assert(config);
-
- while (config->hw_modules) {
- SLLIST_STEAL_FIRST(module, config->hw_modules);
-
- while (module->outputs) {
- SLLIST_STEAL_FIRST(output, module->outputs);
- pa_xfree(output->name);
- pa_xfree(output);
- }
-
- while (module->inputs) {
- SLLIST_STEAL_FIRST(input, module->inputs);
- pa_xfree(input->name);
- pa_xfree(input);
- }
-
- pa_xfree(module->global_config);
- pa_xfree(module->name);
- pa_xfree(module);
- }
-
- pa_xfree(config->global_config);
- pa_xfree(config);
-}
-
-pa_droid_config_audio *pa_droid_config_load(pa_modargs *ma) {
- pa_droid_config_audio *config;
- const char *config_location;
-
- pa_assert(ma);
-
- config = pa_xnew0(pa_droid_config_audio, 1);
-
- if ((config_location = pa_modargs_get_value(ma, "config", NULL))) {
- if (!pa_parse_droid_audio_config(config_location, config)) {
- pa_log("Failed to parse configuration from %s", config_location);
- goto fail;
- }
- } else {
- config_location = AUDIO_POLICY_VENDOR_CONFIG_FILE;
-
- if (!pa_parse_droid_audio_config(config_location, config)) {
- pa_log_debug("Failed to parse configuration from vendor %s", config_location);
-
- config_location = AUDIO_POLICY_CONFIG_FILE;
-
- if (!pa_parse_droid_audio_config(config_location, config)) {
- pa_log("Failed to parse configuration from %s", config_location);
- goto fail;
- }
- }
- }
-
- return config;
-
-fail:
- droid_config_free(config);
- return NULL;
-}
-
void pa_droid_hw_module_lock(pa_droid_hw_module *hw) {
pa_assert(hw);
@@ -2264,7 +1394,7 @@
return NULL;
}
-static int input_stream_open(pa_droid_stream *s) {
+static int input_stream_open(pa_droid_stream *s, bool resume_from_suspend) {
pa_droid_input_stream *input;
audio_stream_in_t *stream;
audio_source_t audio_source = AUDIO_SOURCE_DEFAULT;
@@ -2308,7 +1438,8 @@
pa_droid_hw_module_unlock(s->module);
if (ret < 0 || !stream) {
- pa_log("Failed to open input stream: %d with device: %u flags: %u sample rate: %u channels: %u (%u) format: %u (%u)",
+ pa_logl(resume_from_suspend ? PA_LOG_DEBUG : PA_LOG_ERROR,
+ "Failed to open input stream: %d with device: %u flags: %u sample rate: %u channels: %u (%u) format: %u (%u)",
ret,
input->device,
0, /* AUDIO_INPUT_FLAG_NONE on v3. v1 and v2 don't have input flags. */
@@ -2395,7 +1526,7 @@
/* We need to open the stream for a while so that we can know
* what sample rate we get. We need the rate for droid source. */
- if ((ret = input_stream_open(s)) < 0)
+ if ((ret = input_stream_open(s, false)) < 0)
goto fail;
if ((input->sample_spec.rate = input->stream->common.get_sample_rate(&input->stream->common)) != spec->rate)
@@ -2699,7 +1830,7 @@
return s->input->stream->common.standby(&s->input->stream->common);
}
} else if (s->input->merged || pa_droid_quirk(s->module, QUIRK_CLOSE_INPUT))
- return input_stream_open(s);
+ return input_stream_open(s, true);
}
return 0;
|
[-]
[+]
|
Added |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/src/common/include/droid/conversion.h
^
|
@@ -0,0 +1,112 @@
+#ifndef foodroidconversionfoo
+#define foodroidconversionfoo
+
+/*
+ * Copyright (C) 2018 Jolla Ltd.
+ *
+ * Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
+ *
+ * These PulseAudio Modules are free software; you can redistribute
+ * it and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <pulsecore/modargs.h>
+
+#include <hardware/audio.h>
+
+/* From recent audio_policy_conf.h */
+#ifndef AUDIO_HAL_VERSION_TAG
+#define AUDIO_HAL_VERSION_TAG "audio_hal_version"
+#endif
+#ifndef GAINS_TAG
+#define GAINS_TAG "gains"
+#endif
+
+#include <droid/version.h>
+#include <droid/droid-config.h>
+
+typedef enum {
+ CONV_FROM_PA,
+ CONV_FROM_HAL
+} pa_conversion_field_t;
+
+typedef enum {
+ CONV_STRING_FORMAT,
+ CONV_STRING_OUTPUT_CHANNELS,
+ CONV_STRING_INPUT_CHANNELS,
+ CONV_STRING_OUTPUT_DEVICE,
+ CONV_STRING_INPUT_DEVICE,
+ CONV_STRING_OUTPUT_FLAG,
+ CONV_STRING_INPUT_FLAG
+} pa_conversion_string_t;
+
+bool pa_convert_output_channel(uint32_t value, pa_conversion_field_t from, uint32_t *to_value);
+bool pa_convert_input_channel(uint32_t value, pa_conversion_field_t from, uint32_t *to_value);
+bool pa_convert_format(uint32_t value, pa_conversion_field_t from, uint32_t *to_value);
+
+bool pa_string_convert_output_device_num_to_str(audio_devices_t value, const char **to_str);
+bool pa_string_convert_output_device_str_to_num(const char *str, audio_devices_t *to_value);
+bool pa_string_convert_input_device_num_to_str(audio_devices_t value, const char **to_str);
+bool pa_string_convert_input_device_str_to_num(const char *str, audio_devices_t *to_value);
+
+bool pa_string_convert_flag_num_to_str(audio_output_flags_t value, const char **to_str);
+bool pa_string_convert_flag_str_to_num(const char *str, audio_output_flags_t *to_value);
+
+char *pa_list_string_output_device(audio_devices_t devices);
+char *pa_list_string_input_device(audio_devices_t devices);
+char *pa_list_string_flags(audio_output_flags_t flags);
+
+/* Get default audio source associated with input device.
+ * Return true if default source was found. */
+bool pa_input_device_default_audio_source(audio_devices_t input_device, audio_source_t *default_source);
+
+/* Pretty port names */
+bool pa_droid_output_port_name(audio_devices_t value, const char **to_str);
+bool pa_droid_input_port_name(audio_devices_t value, const char **to_str);
+
+/* Pretty audio source names */
+bool pa_droid_audio_source_name(audio_source_t value, const char **to_str);
+
+int pa_conversion_parse_list(pa_conversion_string_t type, const char *separator,
+ const char *str, uint32_t *dst, char **unknown_entries);
+
+bool pa_conversion_parse_sampling_rates(const char *fn, const unsigned ln,
+ const char *str, bool legacy,
+ uint32_t sampling_rates[AUDIO_MAX_SAMPLING_RATES]);
+bool pa_conversion_parse_formats(const char *fn, const unsigned ln,
+ const char *str, bool legacy,
+ audio_format_t *formats);
+bool pa_conversion_parse_output_channels(const char *fn, const unsigned ln,
+ const char *str, bool legacy,
+ audio_channel_mask_t *channels);
+bool pa_conversion_parse_input_channels(const char *fn, const unsigned ln,
+ const char *str, bool legacy,
+ audio_channel_mask_t *channels);
+bool pa_conversion_parse_output_devices(const char *fn, const unsigned ln,
+ char *str, bool legacy, bool must_recognize_all,
+ audio_devices_t *devices);
+bool pa_conversion_parse_input_devices(const char *fn, const unsigned ln,
+ char *str, bool legacy, bool must_recognize_all,
+ audio_devices_t *devices);
+bool pa_conversion_parse_output_flags(const char *fn, const unsigned ln,
+ const char *str, audio_output_flags_t *flags);
+bool pa_conversion_parse_input_flags(const char *fn, const unsigned ln,
+ const char *str, uint32_t *flags);
+bool pa_conversion_parse_version(const char *fn, const unsigned ln, const char *str, uint32_t *version);
+
+#endif
|
[-]
[+]
|
Added |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/src/common/include/droid/droid-config.h
^
|
@@ -0,0 +1,102 @@
+#ifndef foodroidconfigfoo
+#define foodroidconfigfoo
+
+/*
+ * Copyright (C) 2018 Jolla Ltd.
+ *
+ * Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
+ *
+ * These PulseAudio Modules are free software; you can redistribute
+ * it and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <pulsecore/modargs.h>
+
+#include <android-config.h>
+#include <hardware/audio.h>
+
+#include <droid/version.h>
+
+typedef struct pa_droid_config_audio pa_droid_config_audio;
+typedef struct pa_droid_config_hw_module pa_droid_config_hw_module;
+
+#define AUDIO_MAX_SAMPLING_RATES (32)
+
+typedef struct pa_droid_config_global {
+ uint32_t audio_hal_version;
+ audio_devices_t attached_output_devices;
+ audio_devices_t default_output_device;
+ audio_devices_t attached_input_devices;
+} pa_droid_config_global;
+
+typedef struct pa_droid_config_device {
+ const pa_droid_config_hw_module *module;
+
+ char *name;
+ uint32_t sampling_rates[AUDIO_MAX_SAMPLING_RATES]; /* (uint32_t) -1 -> dynamic */
+ audio_channel_mask_t channel_masks; /* 0 -> dynamic */
+ audio_format_t formats; /* 0 -> dynamic */
+ audio_devices_t devices;
+ /* Instead of using audio_output_flags_t and audio_input_flags_t
+ * unify the flags as uint32_t so that we can have single struct for both
+ * output and input configurations.
+ * audio_input_flags_t was introduced in APIs 2 & 3, depending on adaptation,
+ * so having input flags as uint32_t is simpler from input implementation
+ * point of view as well. */
+ uint32_t flags;
+ pa_direction_t direction;
+
+ struct pa_droid_config_device *next;
+} pa_droid_config_device;
+
+struct pa_droid_config_hw_module {
+ const pa_droid_config_audio *config;
+
+ char *name;
+ /* If global config is not defined for module, use root global config. */
+ pa_droid_config_global *global_config;
+ pa_droid_config_device *outputs;
+ pa_droid_config_device *inputs;
+
+ struct pa_droid_config_hw_module *next;
+};
+
+struct pa_droid_config_audio {
+ pa_droid_config_global *global_config;
+ pa_droid_config_hw_module *hw_modules;
+};
+
+/* Config parser */
+pa_droid_config_audio *pa_droid_config_load(pa_modargs *ma);
+pa_droid_config_audio *pa_droid_config_dup(const pa_droid_config_audio *config);
+void pa_droid_config_free(pa_droid_config_audio *config);
+pa_droid_config_audio *pa_parse_droid_audio_config_legacy(const char *filename);
+pa_droid_config_audio *pa_parse_droid_audio_config_xml(const char *filename);
+/* autodetect config type from filename and parse */
+pa_droid_config_audio *pa_parse_droid_audio_config(const char *filename);
+
+const pa_droid_config_hw_module *pa_droid_config_find_module(const pa_droid_config_audio *config, const char* module_id);
+
+pa_droid_config_hw_module *pa_droid_config_hw_module_new(const pa_droid_config_audio *config, const char *name);
+void pa_droid_config_hw_module_free(pa_droid_config_hw_module *hw_module);
+pa_droid_config_device *pa_droid_config_device_new(const pa_droid_config_hw_module *module,
+ pa_direction_t direction,
+ const char *name);
+void pa_droid_config_device_free(pa_droid_config_device *device);
+
+#endif
|
[-]
[+]
|
Added |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/src/common/include/droid/droid-util.h
^
|
@@ -0,0 +1,333 @@
+#ifndef foodroidutilfoo
+#define foodroidutilfoo
+
+/*
+ * Copyright (C) 2013-2018 Jolla Ltd.
+ *
+ * Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
+ *
+ * These PulseAudio Modules are free software; you can redistribute
+ * it and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <pulsecore/core-util.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/mutex.h>
+#include <pulsecore/strlist.h>
+#include <pulsecore/atomic.h>
+
+#include <droid/version.h>
+#include <droid/droid-config.h>
+
+#if defined(QCOM_BSP) && (AUDIO_API_VERSION_MAJ >= 3)
+#define DROID_AUDIO_HAL_USE_VSID
+#endif
+
+#define PROP_DROID_DEVICES "droid.devices"
+#define PROP_DROID_FLAGS "droid.flags"
+#define PROP_DROID_HW_MODULE "droid.hw_module"
+#define PROP_DROID_API_STRING "droid-hal"
+
+#define PROP_DROID_OUTPUT_PRIMARY "droid.output.primary"
+#define PROP_DROID_OUTPUT_LOW_LATENCY "droid.output.low_latency"
+#define PROP_DROID_OUTPUT_MEDIA_LATENCY "droid.output.media_latency"
+#define PROP_DROID_OUTPUT_OFFLOAD "droid.output.offload"
+#define PROP_DROID_INPUT_BUILTIN "droid.input.builtin"
+#define PROP_DROID_INPUT_EXTERNAL "droid.input.external"
+
+#define PA_DROID_PRIMARY_DEVICE "primary"
+
+typedef struct pa_droid_hw_module pa_droid_hw_module;
+typedef struct pa_droid_stream pa_droid_stream;
+typedef struct pa_droid_output_stream pa_droid_output_stream;
+typedef struct pa_droid_input_stream pa_droid_input_stream;
+typedef struct pa_droid_card_data pa_droid_card_data;
+typedef int (*common_set_parameters_cb_t)(pa_droid_card_data *card_data, const char *str);
+
+typedef struct pa_droid_quirks pa_droid_quirks;
+
+typedef enum pa_droid_hook {
+ PA_DROID_HOOK_INPUT_CHANNEL_MAP_CHANGED, /* Call data: pa_droid_stream */
+ PA_DROID_HOOK_INPUT_BUFFER_SIZE_CHANGED, /* Call data: pa_droid_stream */
+ PA_DROID_HOOK_MAX
+} pa_droid_hook_t;
+
+
+struct pa_droid_hw_module {
+ PA_REFCNT_DECLARE;
+
+ pa_core *core;
+ char *shared_name;
+
+ pa_droid_config_audio *config;
+ const pa_droid_config_hw_module *enabled_module;
+ pa_mutex *hw_mutex;
+ pa_mutex *output_mutex;
+ pa_mutex *input_mutex;
+
+ struct hw_module_t *hwmod;
+ audio_hw_device_t *device;
+
+ const char *module_id;
+
+ uint32_t stream_out_id;
+ uint32_t stream_in_id;
+
+ pa_idxset *outputs;
+ pa_idxset *inputs;
+ pa_hook_slot *sink_put_hook_slot;
+ pa_hook_slot *sink_unlink_hook_slot;
+ pa_hook_slot *source_put_hook_slot;
+ pa_hook_slot *source_unlink_hook_slot;
+
+ pa_atomic_t active_outputs;
+
+ pa_droid_quirks *quirks;
+ pa_hook hooks[PA_DROID_HOOK_MAX];
+};
+
+struct pa_droid_output_stream {
+ struct audio_stream_out *stream;
+ pa_sample_spec sample_spec;
+ pa_channel_map channel_map;
+ uint32_t flags;
+ uint32_t device;
+};
+
+struct pa_droid_input_stream {
+ struct audio_stream_in *stream;
+ pa_sample_spec sample_spec;
+ pa_channel_map channel_map;
+ pa_sample_spec input_sample_spec;
+ pa_channel_map input_channel_map;
+ uint32_t flags;
+ uint32_t device;
+ audio_devices_t all_devices;
+ bool merged;
+};
+
+struct pa_droid_stream {
+ PA_REFCNT_DECLARE;
+
+ pa_droid_hw_module *module;
+ size_t buffer_size;
+ void *data;
+
+ pa_droid_output_stream *output;
+ pa_droid_input_stream *input;
+};
+
+struct pa_droid_card_data {
+ void *userdata;
+ /* General functions */
+ char *module_id;
+ common_set_parameters_cb_t set_parameters;
+};
+
+
+/* Profiles */
+
+typedef struct pa_droid_profile_set pa_droid_profile_set;
+typedef struct pa_droid_mapping pa_droid_mapping;
+
+typedef struct pa_droid_port_data {
+ audio_devices_t device;
+} pa_droid_port_data;
+
+typedef struct pa_droid_port {
+ pa_droid_mapping *mapping;
+
+ audio_devices_t device;
+ char *name;
+ char *description;
+ unsigned priority;
+} pa_droid_port;
+
+struct pa_droid_mapping {
+ pa_droid_profile_set *profile_set;
+
+ const pa_droid_config_device *output;
+ const pa_droid_config_device *input;
+ const pa_droid_config_device *input2;
+
+ char *name;
+ char *description;
+ unsigned priority;
+ pa_proplist *proplist;
+
+ /* Mapping doesn't own the ports */
+ pa_idxset *ports;
+
+ pa_direction_t direction;
+
+ pa_sink *sink;
+ pa_source *source;
+};
+
+typedef struct pa_droid_profile {
+ pa_droid_profile_set *profile_set;
+
+ const pa_droid_config_hw_module *module;
+
+ char *name;
+ char *description;
+ unsigned priority;
+
+ /* Idxsets contain pa_droid_mapping objects.
+ * Profile doesn't own the mappings. */
+ pa_idxset *output_mappings;
+ pa_idxset *input_mappings;
+
+} pa_droid_profile;
+
+struct pa_droid_profile_set {
+ const pa_droid_config_audio *config;
+
+ pa_hashmap *all_ports;
+ pa_hashmap *output_mappings;
+ pa_hashmap *input_mappings;
+ pa_hashmap *profiles;
+};
+
+#define PA_DROID_OUTPUT_PARKING "output-parking"
+#define PA_DROID_INPUT_PARKING "input-parking"
+
+enum pa_droid_quirk_type {
+ QUIRK_INPUT_ATOI,
+ QUIRK_SET_PARAMETERS,
+ QUIRK_CLOSE_INPUT,
+ QUIRK_UNLOAD_NO_CLOSE,
+ QUIRK_NO_HW_VOLUME,
+ QUIRK_OUTPUT_MAKE_WRITABLE,
+ QUIRK_REALCALL,
+ QUIRK_UNLOAD_CALL_EXIT,
+ QUIRK_COUNT
+};
+
+struct pa_droid_quirks {
+ bool enabled[QUIRK_COUNT];
+};
+
+/* Open hardware module */
+/* 'config' can be NULL if it is assumed that hw module with module_id already is open. */
+pa_droid_hw_module *pa_droid_hw_module_get(pa_core *core, const pa_droid_config_audio *config, const char *module_id);
+pa_droid_hw_module *pa_droid_hw_module_ref(pa_droid_hw_module *hw);
+void pa_droid_hw_module_unref(pa_droid_hw_module *hw);
+
+void pa_droid_hw_module_lock(pa_droid_hw_module *hw);
+bool pa_droid_hw_module_try_lock(pa_droid_hw_module *hw);
+void pa_droid_hw_module_unlock(pa_droid_hw_module *hw);
+
+bool pa_droid_quirk_parse(pa_droid_hw_module *hw, const char *quirks);
+void pa_droid_quirk_log(pa_droid_hw_module *hw);
+
+static inline bool pa_droid_quirk(pa_droid_hw_module *hw, enum pa_droid_quirk_type quirk) {
+ return hw->quirks && hw->quirks->enabled[quirk];
+}
+
+/* Profiles */
+pa_droid_profile_set *pa_droid_profile_set_new(const pa_droid_config_hw_module *module);
+pa_droid_profile_set *pa_droid_profile_set_default_new(const pa_droid_config_hw_module *module,
+ bool merge_inputs);
+void pa_droid_profile_set_free(pa_droid_profile_set *ps);
+
+void pa_droid_profile_add_mapping(pa_droid_profile *p, pa_droid_mapping *am);
+void pa_droid_profile_free(pa_droid_profile *p);
+
+pa_droid_mapping *pa_droid_mapping_get(pa_droid_profile_set *ps, const pa_droid_config_device *device);
+pa_droid_mapping *pa_droid_mapping_merged_get(pa_droid_profile_set *ps,
+ const pa_droid_config_device *input1,
+ const pa_droid_config_device *input2);
+bool pa_droid_mapping_is_primary(pa_droid_mapping *am);
+/* Go through idxset containing pa_droid_mapping objects and if primary output or input
+ * mapping is found, return pointer to that mapping. */
+pa_droid_mapping *pa_droid_idxset_get_primary(pa_idxset *i);
+pa_droid_mapping *pa_droid_idxset_mapping_with_device(pa_idxset *i, uint32_t flag);
+void pa_droid_mapping_free(pa_droid_mapping *am);
+
+/* Add ports from sinks/sources.
+ * May be called multiple times for one sink/source. */
+void pa_droid_add_ports(pa_hashmap *ports, pa_droid_mapping *am, pa_card *card);
+/* Add ports from card.
+ * May be called multiple times for one card profile. */
+void pa_droid_add_card_ports(pa_card_profile *cp, pa_hashmap *ports, pa_droid_mapping *am, pa_core *core);
+
+pa_hook *pa_droid_hooks(pa_droid_hw_module *hw);
+
+/* Module operations */
+int pa_droid_set_parameters(pa_droid_hw_module *hw, const char *parameters);
+
+/* Stream operations */
+pa_droid_stream *pa_droid_stream_ref(pa_droid_stream *s);
+void pa_droid_stream_unref(pa_droid_stream *s);
+
+int pa_droid_stream_set_parameters(pa_droid_stream *s, const char *parameters);
+
+/* Output stream operations */
+pa_droid_stream *pa_droid_open_output_stream(pa_droid_hw_module *module,
+ const pa_sample_spec *spec,
+ const pa_channel_map *map,
+ audio_output_flags_t flags,
+ audio_devices_t devices);
+
+/* Set routing to the input or output stream, with following side-effects:
+ * Output:
+ * - if routing is set to primary output stream, set routing to all other
+ * open streams as well
+ * - if routing is set to non-primary stream and primary stream exists, do nothing
+ * - if routing is set to non-primary stream and primary stream doesn't exist, set routing
+ * Input:
+ * - buffer size or channel count may change
+ */
+int pa_droid_stream_set_route(pa_droid_stream *s, audio_devices_t device);
+
+/* Input stream operations */
+pa_droid_stream *pa_droid_open_input_stream(pa_droid_hw_module *module,
+ const pa_sample_spec *spec,
+ const pa_channel_map *map,
+ audio_devices_t devices,
+ pa_droid_mapping *am);
+
+bool pa_droid_stream_is_primary(pa_droid_stream *s);
+
+int pa_droid_stream_suspend(pa_droid_stream *s, bool suspend);
+
+size_t pa_droid_stream_buffer_size(pa_droid_stream *s);
+pa_usec_t pa_droid_stream_get_latency(pa_droid_stream *s);
+
+static inline int pa_droid_output_stream_any_active(pa_droid_stream *s) {
+ return pa_atomic_load(&s->module->active_outputs);
+}
+
+static inline ssize_t pa_droid_stream_write(pa_droid_stream *stream, const void *buffer, size_t bytes) {
+ return stream->output->stream->write(stream->output->stream, buffer, bytes);
+}
+
+static inline ssize_t pa_droid_stream_read(pa_droid_stream *stream, void *buffer, size_t bytes) {
+ return stream->input->stream->read(stream->input->stream, buffer, bytes);
+}
+
+void pa_droid_stream_set_data(pa_droid_stream *s, void *data);
+void *pa_droid_stream_get_data(pa_droid_stream *s);
+bool pa_sink_is_droid_sink(pa_sink *sink);
+bool pa_source_is_droid_source(pa_source *source);
+
+/* Misc */
+size_t pa_droid_buffer_size_round_up(size_t buffer_size, size_t block_size);
+
+#endif
|
[-]
[+]
|
Added |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/src/common/include/droid/sllist.h
^
|
@@ -0,0 +1,49 @@
+#ifndef foosllistfoo
+#define foosllistfoo
+
+/*
+ * Copyright (C) 2018 Jolla Ltd.
+ *
+ * Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
+ *
+ * These PulseAudio Modules are free software; you can redistribute
+ * it and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA.
+ */
+
+#define SLLIST_APPEND(t, head, item) \
+ do { \
+ item->next = NULL; \
+ if (!head) { \
+ head = item; \
+ } else { \
+ t *_list; \
+ for (_list = head; _list->next; _list = _list->next); \
+ _list->next = item; \
+ } \
+ } while (0)
+
+#define SLLIST_FOREACH(i, head) \
+ for (i = (head); i; i = i->next)
+
+#define SLLIST_STEAL_FIRST(i, head) \
+ do { \
+ if (head) { \
+ i = head; \
+ head = head->next; \
+ } else \
+ i = NULL; \
+ } while (0)
+
+#endif
|
[-]
[+]
|
Added |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/src/common/include/droid/version.h
^
|
@@ -0,0 +1,51 @@
+#ifndef foodroidversionfoo
+#define foodroidversionfoo
+
+/*
+ * Copyright (C) 2018 Jolla Ltd.
+ *
+ * Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
+ *
+ * These PulseAudio Modules are free software; you can redistribute
+ * it and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA.
+ */
+
+
+#include <android-config.h>
+#if defined(QCOM_BSP) || defined(DROID_DEVICE_SBJ)
+#define QCOM_HARDWARE
+#endif
+
+#include <hardware/audio.h>
+
+#if !defined(ANDROID_VERSION_MAJOR) || !defined(ANDROID_VERSION_MINOR) || !defined(ANDROID_VERSION_PATCH)
+#error "ANDROID_VERSION_* not defined. Did you get your headers via extract-headers.sh?"
+#endif
+
+/* We currently support API version up-to 3.0 */
+#define DROID_API_VERSION_SUPPORT HARDWARE_DEVICE_API_VERSION(3, 0)
+
+#if AUDIO_DEVICE_API_VERSION_CURRENT > DROID_API_VERSION_SUPPORT
+#warning Compiling against higher audio device API version than currently supported!
+#warning Compile likely fails or module may malfunction.
+#endif
+
+#define AUDIO_API_VERSION_MAJ ((AUDIO_DEVICE_API_VERSION_CURRENT >> 8) & 0xff)
+#define AUDIO_API_VERSION_MIN (AUDIO_DEVICE_API_VERSION_CURRENT & 0xff)
+
+#define AUDIO_API_VERSION_GET_MAJ(x) ((x >> 8) & 0xff)
+#define AUDIO_API_VERSION_GET_MIN(x) (x & 0xff)
+
+#endif
|
[-]
[+]
|
Changed |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/src/droid/Makefile.am
^
|
@@ -9,7 +9,7 @@
$(HYBRIS_CFLAGS) \
-DPULSEAUDIO_VERSION=@PA_MAJOR@ \
-I$(top_srcdir)/src/droid \
- -I$(top_srcdir)/src/common
+ -I$(top_srcdir)/src/common/include
modlibexec_LTLIBRARIES = \
|
[-]
[+]
|
Changed |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/src/droid/droid-sink.c
^
|
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2013 Jolla Ltd.
+ * Copyright (C) 2013-2018 Jolla Ltd.
*
- * Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
+ * Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
*
* These PulseAudio Modules are free software; you can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public
@@ -56,7 +56,8 @@
#include <pulsecore/core-subscribe.h>
#include "droid-sink.h"
-#include "droid-util.h"
+#include <droid/droid-util.h>
+#include <droid/conversion.h>
struct userdata {
pa_core *core;
@@ -251,8 +252,8 @@
* is multiples of buffer_size. Even if we don't write whole buffer size
* here it's okay, as long as mute time isn't configured too strictly. */
- p = pa_memblock_acquire(u->silence.memblock);
- wrote = pa_droid_stream_write(u->stream, (const uint8_t *) p + u->silence.index, u->silence.length);
+ p = pa_memblock_acquire_chunk(&u->silence);
+ wrote = pa_droid_stream_write(u->stream, p, u->silence.length);
pa_memblock_release(u->silence.memblock);
u->write_time = pa_rtclock_now() - u->write_time;
@@ -276,8 +277,11 @@
u->write_time = pa_rtclock_now();
for (;;) {
- p = pa_memblock_acquire(c.memblock);
- wrote = pa_droid_stream_write(u->stream, (const uint8_t *) p + c.index, c.length);
+ if (pa_droid_quirk(u->hw_module, QUIRK_OUTPUT_MAKE_WRITABLE))
+ pa_memchunk_make_writable(&c, c.length);
+
+ p = pa_memblock_acquire_chunk(&c);
+ wrote = pa_droid_stream_write(u->stream, p, c.length);
pa_memblock_release(c.memblock);
if (wrote < 0) {
@@ -1135,18 +1139,17 @@
* hw module ourself.
*
* First let's find out if hw module has already been opened, or if we need to
- * do it ourself.
- */
+ * do it ourself. */
if (!(u->hw_module = pa_droid_hw_module_get(u->core, NULL, module_id))) {
-
/* No hw module object in shared object db, let's open the module now. */
-
if (!(config = pa_droid_config_load(ma)))
goto fail;
- /* Ownership of config transfers to hw_module if opening of hw module succeeds. */
if (!(u->hw_module = pa_droid_hw_module_get(u->core, config, module_id)))
goto fail;
+
+ pa_droid_config_free(config);
+ config = NULL;
}
}
@@ -1305,6 +1308,7 @@
return u->sink;
fail:
+ pa_droid_config_free(config);
pa_xfree(thread_name);
if (config)
|
[-]
[+]
|
Changed |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/src/droid/droid-sink.h
^
|
@@ -2,9 +2,9 @@
#define foodroidsinkfoo
/*
- * Copyright (C) 2013 Jolla Ltd.
+ * Copyright (C) 2013-2018 Jolla Ltd.
*
- * Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
+ * Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
*
* These PulseAudio Modules are free software; you can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public
@@ -41,7 +41,7 @@
#include <pulsecore/macro.h>
#include <pulsecore/card.h>
-#include "droid-util.h"
+#include <droid/droid-util.h>
pa_sink *pa_droid_sink_new(pa_module *m,
pa_modargs *ma,
|
[-]
[+]
|
Changed |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/src/droid/droid-source.c
^
|
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2013 Jolla Ltd.
+ * Copyright (C) 2013-2018 Jolla Ltd.
*
- * Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
+ * Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
*
* These PulseAudio Modules are free software; you can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public
@@ -53,7 +53,8 @@
#include <pulsecore/resampler.h>
#include "droid-source.h"
-#include "droid-util.h"
+#include <droid/droid-util.h>
+#include <droid/conversion.h>
struct userdata {
pa_core *core;
@@ -79,6 +80,7 @@
pa_droid_card_data *card_data;
pa_droid_hw_module *hw_module;
pa_droid_stream *stream;
+ bool stream_valid;
};
enum {
@@ -91,6 +93,8 @@
#define DROID_AUDIO_SOURCE_UNDEFINED "undefined"
static void userdata_free(struct userdata *u);
+static int suspend(struct userdata *u);
+static void unsuspend(struct userdata *u);
static int do_routing(struct userdata *u, audio_devices_t devices) {
int ret;
@@ -144,8 +148,22 @@
ssize_t readd;
pa_memchunk chunk;
+ chunk.index = 0;
chunk.memblock = pa_memblock_new(u->core->mempool, (size_t) u->buffer_size);
+ if (!u->stream_valid) {
+ /* try to resume or post silence */
+ unsuspend(u);
+ if (!u->stream_valid) {
+ p = pa_memblock_acquire(chunk.memblock);
+ chunk.length = pa_memblock_get_length(chunk.memblock);
+ memset(p, 0, chunk.length);
+ pa_source_post(u->source, &chunk);
+ pa_memblock_release(chunk.memblock);
+ goto end;
+ }
+ }
+
p = pa_memblock_acquire(chunk.memblock);
readd = pa_droid_stream_read(u->stream, p, pa_memblock_get_length(chunk.memblock));
pa_memblock_release(chunk.memblock);
@@ -157,7 +175,6 @@
u->timestamp += pa_bytes_to_usec(readd, &u->source->sample_spec);
- chunk.index = 0;
chunk.length = readd;
if (u->resampler) {
@@ -250,8 +267,11 @@
pa_assert(u);
pa_assert(u->stream);
- pa_droid_stream_suspend(u->stream, false);
- pa_log_info("Resuming...");
+ if (pa_droid_stream_suspend(u->stream, false) >= 0) {
+ u->stream_valid = true;
+ pa_log_info("Resuming...");
+ } else
+ u->stream_valid = false;
}
/* Called from IO context */
@@ -264,9 +284,9 @@
pa_assert(PA_SOURCE_IS_OPENED(u->source->thread_info.state));
- pa_droid_stream_suspend(u->stream, true);
+ suspend(u);
do_routing(u, device);
- pa_droid_stream_suspend(u->stream, false);
+ unsuspend(u);
break;
}
@@ -564,6 +584,7 @@
}
u = pa_xnew0(struct userdata, 1);
+ u->stream_valid = true;
u->core = m->core;
u->module = m;
u->card = card;
@@ -575,15 +596,20 @@
u->card_data = card_data;
pa_assert_se((u->hw_module = pa_droid_hw_module_get(u->core, NULL, card_data->module_id)));
} else {
- /* Stand-alone source */
-
+ /* Source wasn't created from inside card module, so we'll need to open
+ * hw module ourself.
+ *
+ * First let's find out if hw module has already been opened, or if we need to
+ * do it ourself. */
if (!(u->hw_module = pa_droid_hw_module_get(u->core, NULL, module_id))) {
if (!(config = pa_droid_config_load(ma)))
goto fail;
- /* Ownership of config transfers to hw_module if opening of hw module succeeds. */
if (!(u->hw_module = pa_droid_hw_module_get(u->core, config, module_id)))
goto fail;
+
+ pa_droid_config_free(config);
+ config = NULL;
}
}
@@ -699,11 +725,9 @@
return u->source;
fail:
+ pa_droid_config_free(config);
pa_xfree(thread_name);
- if (config)
- pa_xfree(config);
-
if (u)
userdata_free(u);
|
[-]
[+]
|
Changed |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/src/droid/droid-source.h
^
|
@@ -2,9 +2,9 @@
#define foodroidsourcefoo
/*
- * Copyright (C) 2013 Jolla Ltd.
+ * Copyright (C) 2013-2018 Jolla Ltd.
*
- * Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
+ * Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
*
* These PulseAudio Modules are free software; you can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public
@@ -41,7 +41,7 @@
#include <pulsecore/macro.h>
#include <pulsecore/card.h>
-#include "droid-util.h"
+#include <droid/droid-util.h>
/* If device is non-zero, it will override whatever is set in modargs for input device. */
pa_source *pa_droid_source_new(pa_module *m,
|
[-]
[+]
|
Changed |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/src/droid/keepalive.c
^
|
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2013 Jolla Ltd.
+ * Copyright (C) 2013-2018 Jolla Ltd.
*
- * Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
+ * Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
*
* These PulseAudio Modules are free software; you can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public
|
[-]
[+]
|
Changed |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/src/droid/keepalive.h
^
|
@@ -2,9 +2,9 @@
#define foodroidkeepalivefoo
/*
- * Copyright (C) 2013 Jolla Ltd.
+ * Copyright (C) 2013-2018 Jolla Ltd.
*
- * Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
+ * Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
*
* These PulseAudio Modules are free software; you can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public
|
[-]
[+]
|
Changed |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/src/droid/module-droid-card-symdef.h
^
|
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2013 Jolla Ltd.
+ * Copyright (C) 2013-2018 Jolla Ltd.
*
- * Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
+ * Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
*
* These PulseAudio Modules are free software; you can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public
|
[-]
[+]
|
Changed |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/src/droid/module-droid-card.c
^
|
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2013 Jolla Ltd.
+ * Copyright (C) 2013-2018 Jolla Ltd.
*
- * Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
+ * Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
*
* These PulseAudio Modules are free software; you can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public
@@ -59,7 +59,7 @@
//#include <droid/hardware/audio_policy.h>
//#include <droid/system/audio_policy.h>
-#include "droid-util.h"
+#include <droid/droid-util.h>
#include "droid-sink.h"
#include "droid-source.h"
@@ -130,6 +130,9 @@
#define COMMUNICATION_PROFILE_NAME "communication"
#define COMMUNICATION_PROFILE_DESC "Communication mode"
+#define VENDOR_EXT_REALCALL_ON "realcall=on"
+#define VENDOR_EXT_REALCALL_OFF "realcall=off"
+
struct userdata;
typedef bool (*virtual_profile_event_cb)(struct userdata *u, pa_droid_profile *p, bool enabling);
@@ -428,8 +431,8 @@
}
static bool voicecall_profile_event_cb(struct userdata *u, pa_droid_profile *p, bool enabling) {
- pa_card_profile *cp;
- pa_droid_mapping *am_output, *am_input;
+ pa_card_profile *cp = NULL;
+ pa_droid_mapping *am_output;
pa_assert(u);
pa_assert(p);
@@ -440,28 +443,27 @@
return false;
}
- if (!(am_input = pa_droid_idxset_get_primary(u->old_profile->input_mappings)))
- pa_log_warn("Active profile doesn't have primary input device.");
+ if (pa_droid_idxset_mapping_with_device(u->old_profile->input_mappings,
+ AUDIO_DEVICE_IN_VOICE_CALL))
+ cp = pa_hashmap_get(u->card->profiles, VOICE_RECORD_PROFILE_NAME);
/* call mode specialities */
if (enabling) {
pa_droid_sink_set_voice_control(am_output->sink, true);
- if (am_input && am_input->input->devices & AUDIO_DEVICE_IN_VOICE_CALL &&
- (cp = pa_hashmap_get(u->card->profiles, VOICE_RECORD_PROFILE_NAME))) {
- if (cp->available == PA_AVAILABLE_NO) {
- pa_log_debug("Enable %s profile.", VOICE_RECORD_PROFILE_NAME);
- pa_card_profile_set_available(cp, PA_AVAILABLE_YES);
- }
+ if (cp && cp->available == PA_AVAILABLE_NO) {
+ pa_log_debug("Enable " VOICE_RECORD_PROFILE_NAME " profile.");
+ pa_card_profile_set_available(cp, PA_AVAILABLE_YES);
}
+ if (pa_droid_quirk(u->hw_module, QUIRK_REALCALL))
+ pa_droid_set_parameters(u->hw_module, VENDOR_EXT_REALCALL_ON);
} else {
pa_droid_sink_set_voice_control(am_output->sink, false);
- if (am_input && am_input->input->devices & AUDIO_DEVICE_IN_VOICE_CALL &&
- (cp = pa_hashmap_get(u->card->profiles, VOICE_RECORD_PROFILE_NAME))) {
- if (cp->available == PA_AVAILABLE_YES) {
- pa_log_debug("Disable %s profile.", VOICE_RECORD_PROFILE_NAME);
- pa_card_profile_set_available(cp, PA_AVAILABLE_NO);
- }
+ if (cp && cp->available == PA_AVAILABLE_YES) {
+ pa_log_debug("Disable " VOICE_RECORD_PROFILE_NAME " profile.");
+ pa_card_profile_set_available(cp, PA_AVAILABLE_NO);
}
+ if (pa_droid_quirk(u->hw_module, QUIRK_REALCALL))
+ pa_droid_set_parameters(u->hw_module, VENDOR_EXT_REALCALL_OFF);
}
return true;
@@ -718,14 +720,21 @@
u->core = m->core;
m->userdata = u;
- if (!(config = pa_droid_config_load(ma)))
- goto fail;
-
module_id = pa_modargs_get_value(ma, "module_id", DEFAULT_MODULE_ID);
- /* Ownership of config transfers to hw_module if opening of hw module succeeds. */
- if (!(u->hw_module = pa_droid_hw_module_get(u->core, config, module_id)))
- goto fail;
+ /* First let's find out if hw module has already been opened, or if we need to
+ * do it ourself. */
+ if (!(u->hw_module = pa_droid_hw_module_get(u->core, NULL, module_id))) {
+ /* No hw module object in shared object db, let's open the module now. */
+ if (!(config = pa_droid_config_load(ma)))
+ goto fail;
+
+ if (!(u->hw_module = pa_droid_hw_module_get(u->core, config, module_id)))
+ goto fail;
+
+ pa_droid_config_free(config);
+ config = NULL;
+ }
if ((quirks = pa_modargs_get_value(ma, "quirks", NULL))) {
if (!pa_droid_quirk_parse(u->hw_module, quirks)) {
@@ -821,11 +830,20 @@
u->modargs = ma;
u->module = m;
+#if (PULSEAUDIO_VERSION >= 10)
+ pa_card_choose_initial_profile(u->card);
+#endif
init_profile(u);
+#if (PULSEAUDIO_VERSION >= 10)
+ pa_card_put(u->card);
+#endif
+
return 0;
fail:
+ pa_droid_config_free(config);
+
if (ma)
pa_modargs_free(ma);
|
[-]
[+]
|
Changed |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/src/droid/module-droid-keepalive-symdef.h
^
|
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2013 Jolla Ltd.
+ * Copyright (C) 2013-2018 Jolla Ltd.
*
- * Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
+ * Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
*
* These PulseAudio Modules are free software; you can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public
|
[-]
[+]
|
Changed |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/src/droid/module-droid-keepalive.c
^
|
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2013 Jolla Ltd.
+ * Copyright (C) 2013-2018 Jolla Ltd.
*
- * Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
+ * Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
*
* These PulseAudio Modules are free software; you can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public
@@ -103,42 +103,52 @@
u->active = false;
}
-static pa_hook_result_t device_state_changed_hook_cb(pa_core *c, pa_object *o, struct userdata *u) {
- pa_assert(c);
- pa_object_assert_ref(o);
+static void update_sink(pa_sink *sink, struct userdata *u) {
+ pa_assert(sink);
pa_assert(u);
- if (pa_source_isinstance(o)) {
- pa_source *s = PA_SOURCE(o);
+ if (pa_sink_get_state(sink) != PA_SINK_SUSPENDED)
+ start(u);
+ else
+ stop(u);
+}
- /* Don't react on monitor state changes. */
- if (!s->monitor_of) {
- pa_source_state_t state = pa_source_get_state(s);
-
- if (state != PA_SOURCE_SUSPENDED)
- start(u);
- else
- stop(u);
- }
- } else if (pa_sink_isinstance(o)) {
- pa_sink *s = PA_SINK(o);
- pa_sink_state_t state = pa_sink_get_state(s);
+static void update_source(pa_source *source, struct userdata *u) {
+ pa_assert(source);
+ pa_assert(u);
- if (state != PA_SINK_SUSPENDED)
+ /* Don't react on monitor state changes. */
+ if (!source->monitor_of) {
+ if (pa_source_get_state(source) != PA_SOURCE_SUSPENDED)
start(u);
else
stop(u);
}
+}
+
+static pa_hook_result_t device_state_changed_hook_cb(pa_core *c, pa_object *o, struct userdata *u) {
+ pa_assert(c);
+ pa_object_assert_ref(o);
+ pa_assert(u);
+
+ if (pa_source_isinstance(o))
+ update_source(PA_SOURCE(o), u);
+ else if (pa_sink_isinstance(o))
+ update_sink(PA_SINK(o), u);
return PA_HOOK_OK;
}
int pa__init(pa_module *m) {
+ uint32_t idx = 0;
+ pa_sink *sink;
+ pa_source *source;
+ struct userdata *u;
pa_assert(m);
- struct userdata *u = pa_xnew0(struct userdata, 1);
+ u = pa_xnew0(struct userdata, 1);
u->core = m->core;
u->active = false;
u->module = m;
@@ -152,6 +162,12 @@
u->sink_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) device_state_changed_hook_cb, u);
u->source_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) device_state_changed_hook_cb, u);
+ PA_IDXSET_FOREACH(source, u->core->sources, idx)
+ update_source(source, u);
+
+ PA_IDXSET_FOREACH(sink, u->core->sinks, idx)
+ update_sink(sink, u);
+
return 0;
fail:
@@ -173,7 +189,7 @@
pa_hook_slot_free(u->source_state_changed_slot);
if (u->keepalive) {
- stop(u);
+ pa_droid_keepalive_stop(u->keepalive);
pa_droid_keepalive_free(u->keepalive);
}
|
[-]
[+]
|
Changed |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/src/droid/module-droid-sink-symdef.h
^
|
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2013 Jolla Ltd.
+ * Copyright (C) 2013-2018 Jolla Ltd.
*
- * Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
+ * Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
*
* These PulseAudio Modules are free software; you can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public
|
[-]
[+]
|
Changed |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/src/droid/module-droid-sink.c
^
|
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2013 Jolla Ltd.
+ * Copyright (C) 2013-2018 Jolla Ltd.
*
- * Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
+ * Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
*
* These PulseAudio Modules are free software; you can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public
@@ -37,7 +37,8 @@
#include <pulsecore/log.h>
#include <pulsecore/macro.h>
-#include "droid-util.h"
+#include <droid/droid-util.h>
+#include <droid/conversion.h>
#include "droid-sink.h"
#include "module-droid-sink-symdef.h"
|
[-]
[+]
|
Changed |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/src/droid/module-droid-source-symdef.h
^
|
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2013 Jolla Ltd.
+ * Copyright (C) 2013-2018 Jolla Ltd.
*
- * Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
+ * Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
*
* These PulseAudio Modules are free software; you can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public
|
[-]
[+]
|
Changed |
_service:tar_git:pulseaudio-modules-droid-11.1.76.tar.bz2/src/droid/module-droid-source.c
^
|
@@ -1,7 +1,7 @@
/*
- * Copyright (C) 2013 Jolla Ltd.
+ * Copyright (C) 2013-2018 Jolla Ltd.
*
- * Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
+ * Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
*
* These PulseAudio Modules are free software; you can redistribute
* it and/or modify it under the terms of the GNU Lesser General Public
@@ -37,7 +37,7 @@
#include <pulsecore/log.h>
#include <pulsecore/macro.h>
-#include "droid-util.h"
+#include <droid/droid-util.h>
#include "droid-source.h"
#include "module-droid-source-symdef.h"
|
[-]
[+]
|
Deleted |
_service:tar_git:pulseaudio-modules-droid-8.0.64.1.tar.bz2/src/common/droid-util.h
^
|
@@ -1,446 +0,0 @@
-#ifndef foodroidutilfoo
-#define foodroidutilfoo
-
-/*
- * Copyright (C) 2013 Jolla Ltd.
- *
- * Contact: Juho Hämäläinen <juho.hamalainen@tieto.com>
- *
- * These PulseAudio Modules are free software; you can redistribute
- * it and/or modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation
- * version 2.1 of the License.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
- * USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <pulsecore/core-util.h>
-#include <pulsecore/macro.h>
-#include <pulsecore/mutex.h>
-#include <pulsecore/strlist.h>
-#include <pulsecore/atomic.h>
-
-#include <android-config.h>
-
-#if !defined(ANDROID_VERSION_MAJOR) || !defined(ANDROID_VERSION_MINOR) || !defined(ANDROID_VERSION_PATCH)
-#error "ANDROID_VERSION_* not defined. Did you get your headers via extract-headers.sh?"
-#endif
-
-#if ANDROID_VERSION_MAJOR == 4 && ANDROID_VERSION_MINOR == 1
-#include "droid-util-41qc.h"
-#else
-#include "droid-util-audio.h"
-#endif
-
-/* We currently support API version up-to 3.0 */
-#define DROID_API_VERSION_SUPPORT HARDWARE_DEVICE_API_VERSION(3, 0)
-
-#if AUDIO_DEVICE_API_VERSION_CURRENT > DROID_API_VERSION_SUPPORT
-#warning Compiling against higher audio device API version than currently supported!
-#warning Compile likely fails or module may malfunction.
-#endif
-
-#define AUDIO_API_VERSION_MAJ ((AUDIO_DEVICE_API_VERSION_CURRENT >> 8) & 0xff)
-#define AUDIO_API_VERSION_MIN (AUDIO_DEVICE_API_VERSION_CURRENT & 0xff)
-
-#define AUDIO_API_VERSION_GET_MAJ(x) ((x >> 8) & 0xff)
-#define AUDIO_API_VERSION_GET_MIN(x) (x & 0xff)
-
-#if defined(QCOM_BSP) && (AUDIO_API_VERSION_MAJ >= 3)
-#define DROID_AUDIO_HAL_USE_VSID
-#endif
-
-#define PROP_DROID_DEVICES "droid.devices"
-#define PROP_DROID_FLAGS "droid.flags"
-#define PROP_DROID_HW_MODULE "droid.hw_module"
-#define PROP_DROID_API_STRING "droid-hal"
-
-#define PROP_DROID_OUTPUT_PRIMARY "droid.output.primary"
-#define PROP_DROID_OUTPUT_LOW_LATENCY "droid.output.low_latency"
-#define PROP_DROID_OUTPUT_MEDIA_LATENCY "droid.output.media_latency"
-#define PROP_DROID_OUTPUT_OFFLOAD "droid.output.offload"
-#define PROP_DROID_INPUT_BUILTIN "droid.input.builtin"
-#define PROP_DROID_INPUT_EXTERNAL "droid.input.external"
-
-#define PA_DROID_PRIMARY_DEVICE "primary"
-
-typedef struct pa_droid_hw_module pa_droid_hw_module;
-typedef struct pa_droid_stream pa_droid_stream;
-typedef struct pa_droid_output_stream pa_droid_output_stream;
-typedef struct pa_droid_input_stream pa_droid_input_stream;
-typedef struct pa_droid_card_data pa_droid_card_data;
-typedef int (*common_set_parameters_cb_t)(pa_droid_card_data *card_data, const char *str);
-
-typedef struct pa_droid_config_audio pa_droid_config_audio;
-typedef struct pa_droid_config_hw_module pa_droid_config_hw_module;
-
-typedef struct pa_droid_quirks pa_droid_quirks;
-
-typedef enum pa_droid_hook {
- PA_DROID_HOOK_INPUT_CHANNEL_MAP_CHANGED, /* Call data: pa_droid_stream */
- PA_DROID_HOOK_INPUT_BUFFER_SIZE_CHANGED, /* Call data: pa_droid_stream */
- PA_DROID_HOOK_MAX
-} pa_droid_hook_t;
-
-
-struct pa_droid_hw_module {
- PA_REFCNT_DECLARE;
-
- pa_core *core;
- char *shared_name;
-
- pa_droid_config_audio *config;
- const pa_droid_config_hw_module *enabled_module;
- pa_mutex *hw_mutex;
- pa_mutex *output_mutex;
- pa_mutex *input_mutex;
-
- struct hw_module_t *hwmod;
- audio_hw_device_t *device;
-
- const char *module_id;
-
- uint32_t stream_out_id;
- uint32_t stream_in_id;
-
- pa_idxset *outputs;
- pa_idxset *inputs;
- pa_hook_slot *sink_put_hook_slot;
- pa_hook_slot *sink_unlink_hook_slot;
- pa_hook_slot *source_put_hook_slot;
- pa_hook_slot *source_unlink_hook_slot;
-
- pa_atomic_t active_outputs;
-
- pa_droid_quirks *quirks;
- pa_hook hooks[PA_DROID_HOOK_MAX];
-};
-
-struct pa_droid_output_stream {
- struct audio_stream_out *stream;
- pa_sample_spec sample_spec;
- pa_channel_map channel_map;
- uint32_t flags;
- uint32_t device;
-};
-
-struct pa_droid_input_stream {
- struct audio_stream_in *stream;
- pa_sample_spec sample_spec;
- pa_channel_map channel_map;
- pa_sample_spec input_sample_spec;
- pa_channel_map input_channel_map;
- uint32_t flags;
- uint32_t device;
- audio_devices_t all_devices;
- bool merged;
-};
-
-struct pa_droid_stream {
- PA_REFCNT_DECLARE;
-
- pa_droid_hw_module *module;
- size_t buffer_size;
- void *data;
-
- pa_droid_output_stream *output;
- pa_droid_input_stream *input;
-};
-
-struct pa_droid_card_data {
- void *userdata;
- /* General functions */
- char *module_id;
- common_set_parameters_cb_t set_parameters;
-};
-
-#define AUDIO_MAX_SAMPLING_RATES (32)
-
-typedef struct pa_droid_config_global {
- uint32_t audio_hal_version;
- audio_devices_t attached_output_devices;
- audio_devices_t default_output_device;
- audio_devices_t attached_input_devices;
-} pa_droid_config_global;
-
-typedef struct pa_droid_config_output {
- const pa_droid_config_hw_module *module;
-
- char *name;
- uint32_t sampling_rates[AUDIO_MAX_SAMPLING_RATES]; /* (uint32_t) -1 -> dynamic */
- audio_channel_mask_t channel_masks; /* 0 -> dynamic */
- audio_format_t formats; /* 0 -> dynamic */
- audio_devices_t devices;
- audio_output_flags_t flags;
-
- struct pa_droid_config_output *next;
-} pa_droid_config_output;
-
-typedef struct pa_droid_config_input {
- const pa_droid_config_hw_module *module;
-
- char *name;
- uint32_t sampling_rates[AUDIO_MAX_SAMPLING_RATES]; /* (uint32_t) -1 -> dynamic */
- audio_channel_mask_t channel_masks; /* 0 -> dynamic */
- audio_format_t formats; /* 0 -> dynamic */
- audio_devices_t devices;
-#if AUDIO_API_VERSION_MAJ >= 3
- audio_input_flags_t flags;
-#endif
-
- struct pa_droid_config_input *next;
-} pa_droid_config_input;
-
-struct pa_droid_config_hw_module {
- const pa_droid_config_audio *config;
-
- char *name;
- /* If global config is not defined for module, use root global config. */
- pa_droid_config_global *global_config;
- pa_droid_config_output *outputs;
- pa_droid_config_input *inputs;
-
- struct pa_droid_config_hw_module *next;
-};
-
-struct pa_droid_config_audio {
- pa_droid_config_global *global_config;
- pa_droid_config_hw_module *hw_modules;
-};
-
-
-/* Profiles */
-
-typedef struct pa_droid_profile_set pa_droid_profile_set;
-typedef struct pa_droid_mapping pa_droid_mapping;
-
-typedef struct pa_droid_port_data {
- audio_devices_t device;
-} pa_droid_port_data;
-
-typedef struct pa_droid_port {
- pa_droid_mapping *mapping;
-
- audio_devices_t device;
- char *name;
- char *description;
- unsigned priority;
-} pa_droid_port;
-
-struct pa_droid_mapping {
- pa_droid_profile_set *profile_set;
-
- const pa_droid_config_output *output;
- const pa_droid_config_input *input;
- const pa_droid_config_input *input2;
-
- char *name;
- char *description;
- unsigned priority;
- pa_proplist *proplist;
-
- /* Mapping doesn't own the ports */
- pa_idxset *ports;
-
- pa_direction_t direction;
-
- pa_sink *sink;
- pa_source *source;
-};
-
-typedef struct pa_droid_profile {
- pa_droid_profile_set *profile_set;
-
- const pa_droid_config_hw_module *module;
-
- char *name;
- char *description;
- unsigned priority;
-
- /* Idxsets contain pa_droid_mapping objects.
- * Profile doesn't own the mappings. */
- pa_idxset *output_mappings;
- pa_idxset *input_mappings;
-
-} pa_droid_profile;
-
-struct pa_droid_profile_set {
- const pa_droid_config_audio *config;
-
- pa_hashmap *all_ports;
- pa_hashmap *output_mappings;
- pa_hashmap *input_mappings;
- pa_hashmap *profiles;
-};
-
-#define PA_DROID_OUTPUT_PARKING "output-parking"
-#define PA_DROID_INPUT_PARKING "input-parking"
-
-enum pa_droid_quirk_type {
- QUIRK_INPUT_ATOI,
- QUIRK_SET_PARAMETERS,
- QUIRK_CLOSE_INPUT,
- QUIRK_UNLOAD_NO_CLOSE,
- QUIRK_NO_HW_VOLUME,
- QUIRK_COUNT
-};
-
-/* Open hardware module */
-/* 'config' can be NULL if it is assumed that hw module with module_id already is open. */
-/* if opening of hw_module succeeds, config ownership is transferred to hw_module and config
- * shouldn't be freed. */
-pa_droid_hw_module *pa_droid_hw_module_get(pa_core *core, pa_droid_config_audio *config, const char *module_id);
-pa_droid_hw_module *pa_droid_hw_module_ref(pa_droid_hw_module *hw);
-void pa_droid_hw_module_unref(pa_droid_hw_module *hw);
-
-void pa_droid_hw_module_lock(pa_droid_hw_module *hw);
-bool pa_droid_hw_module_try_lock(pa_droid_hw_module *hw);
-void pa_droid_hw_module_unlock(pa_droid_hw_module *hw);
-
-bool pa_droid_quirk_parse(pa_droid_hw_module *hw, const char *quirks);
-bool pa_droid_quirk(pa_droid_hw_module *hw, enum pa_droid_quirk_type quirk);
-void pa_droid_quirk_log(pa_droid_hw_module *hw);
-
-/* Conversion helpers */
-typedef enum {
- CONV_FROM_PA,
- CONV_FROM_HAL
-} pa_conversion_field_t;
-
-bool pa_convert_output_channel(uint32_t value, pa_conversion_field_t from, uint32_t *to_value);
-bool pa_convert_input_channel(uint32_t value, pa_conversion_field_t from, uint32_t *to_value);
-bool pa_convert_format(uint32_t value, pa_conversion_field_t from, uint32_t *to_value);
-
-bool pa_string_convert_output_device_num_to_str(audio_devices_t value, const char **to_str);
-bool pa_string_convert_output_device_str_to_num(const char *str, audio_devices_t *to_value);
-bool pa_string_convert_input_device_num_to_str(audio_devices_t value, const char **to_str);
-bool pa_string_convert_input_device_str_to_num(const char *str, audio_devices_t *to_value);
-
-bool pa_string_convert_flag_num_to_str(audio_output_flags_t value, const char **to_str);
-bool pa_string_convert_flag_str_to_num(const char *str, audio_output_flags_t *to_value);
-
-char *pa_list_string_output_device(audio_devices_t devices);
-char *pa_list_string_input_device(audio_devices_t devices);
-char *pa_list_string_flags(audio_output_flags_t flags);
-
-/* Get default audio source associated with input device.
- * Return true if default source was found, false if not. */
-bool pa_input_device_default_audio_source(audio_devices_t input_device, audio_source_t *default_source);
-
-/* Config parser */
-bool pa_parse_droid_audio_config(const char *filename, pa_droid_config_audio *config);
-pa_droid_config_audio *pa_droid_config_load(pa_modargs *ma);
-
-const pa_droid_config_output *pa_droid_config_find_output(const pa_droid_config_hw_module *module, const char *name);
-const pa_droid_config_input *pa_droid_config_find_input(const pa_droid_config_hw_module *module, const char *name);
-const pa_droid_config_hw_module *pa_droid_config_find_module(const pa_droid_config_audio *config, const char* module_id);
-
-
-/* Profiles */
-pa_droid_profile_set *pa_droid_profile_set_new(const pa_droid_config_hw_module *module);
-pa_droid_profile_set *pa_droid_profile_set_default_new(const pa_droid_config_hw_module *module,
- bool merge_inputs);
-void pa_droid_profile_set_free(pa_droid_profile_set *ps);
-
-void pa_droid_profile_add_mapping(pa_droid_profile *p, pa_droid_mapping *am);
-void pa_droid_profile_free(pa_droid_profile *p);
-
-pa_droid_mapping *pa_droid_mapping_get(pa_droid_profile_set *ps, pa_direction_t direction, const void *data);
-pa_droid_mapping *pa_droid_mapping_merged_get(pa_droid_profile_set *ps,
- const pa_droid_config_input *input1,
- const pa_droid_config_input *input2);
-bool pa_droid_mapping_is_primary(pa_droid_mapping *am);
-/* Go through idxset containing pa_droid_mapping objects and if primary output or input
- * mapping is found, return pointer to that mapping. */
-pa_droid_mapping *pa_droid_idxset_get_primary(pa_idxset *i);
-void pa_droid_mapping_free(pa_droid_mapping *am);
-
-/* Add ports from sinks/sources.
- * May be called multiple times for one sink/source. */
-void pa_droid_add_ports(pa_hashmap *ports, pa_droid_mapping *am, pa_card *card);
-/* Add ports from card.
- * May be called multiple times for one card profile. */
-void pa_droid_add_card_ports(pa_card_profile *cp, pa_hashmap *ports, pa_droid_mapping *am, pa_core *core);
-
-/* Pretty port names */
-bool pa_droid_output_port_name(audio_devices_t value, const char **to_str);
-bool pa_droid_input_port_name(audio_devices_t value, const char **to_str);
-
-/* Pretty audio source names */
-bool pa_droid_audio_source_name(audio_source_t value, const char **to_str);
-
-pa_hook *pa_droid_hooks(pa_droid_hw_module *hw);
-
-/* Module operations */
-int pa_droid_set_parameters(pa_droid_hw_module *hw, const char *parameters);
-
-/* Stream operations */
-pa_droid_stream *pa_droid_stream_ref(pa_droid_stream *s);
-void pa_droid_stream_unref(pa_droid_stream *s);
-
-int pa_droid_stream_set_parameters(pa_droid_stream *s, const char *parameters);
-
-/* Output stream operations */
-pa_droid_stream *pa_droid_open_output_stream(pa_droid_hw_module *module,
- const pa_sample_spec *spec,
- const pa_channel_map *map,
- audio_output_flags_t flags,
- audio_devices_t devices);
-
-/* Set routing to the input or output stream, with following side-effects:
- * Output:
- * - if routing is set to primary output stream, set routing to all other
- * open streams as well
- * - if routing is set to non-primary stream and primary stream exists, do nothing
- * - if routing is set to non-primary stream and primary stream doesn't exist, set routing
- * Input:
- * - buffer size or channel count may change
- */
-int pa_droid_stream_set_route(pa_droid_stream *s, audio_devices_t device);
-
-/* Input stream operations */
-pa_droid_stream *pa_droid_open_input_stream(pa_droid_hw_module *module,
- const pa_sample_spec *spec,
- const pa_channel_map *map,
- audio_devices_t devices,
- pa_droid_mapping *am);
-
-bool pa_droid_stream_is_primary(pa_droid_stream *s);
-
-int pa_droid_stream_suspend(pa_droid_stream *s, bool suspend);
-
-size_t pa_droid_stream_buffer_size(pa_droid_stream *s);
-pa_usec_t pa_droid_stream_get_latency(pa_droid_stream *s);
-
-static inline int pa_droid_output_stream_any_active(pa_droid_stream *s) {
- return pa_atomic_load(&s->module->active_outputs);
-}
-
-static inline ssize_t pa_droid_stream_write(pa_droid_stream *stream, const void *buffer, size_t bytes) {
- return stream->output->stream->write(stream->output->stream, buffer, bytes);
-}
-
-static inline ssize_t pa_droid_stream_read(pa_droid_stream *stream, void *buffer, size_t bytes) {
- return stream->input->stream->read(stream->input->stream, buffer, bytes);
-}
-
-void pa_droid_stream_set_data(pa_droid_stream *s, void *data);
-void *pa_droid_stream_get_data(pa_droid_stream *s);
-bool pa_sink_is_droid_sink(pa_sink *sink);
-bool pa_source_is_droid_source(pa_source *source);
-
-/* Misc */
-size_t pa_droid_buffer_size_round_up(size_t buffer_size, size_t block_size);
-
-#endif
|