Compare commits

..

4 commits

Author SHA1 Message Date
Simonas Leleiva
dccef3aef6 Merge pull request #3 from jusa/i9305-fix
[droid-sink] Workaround use OUT_SPEAKER as default device.
2014-02-23 11:53:47 +00:00
Juho Hämäläinen
7183df5788 [droid-sink] Workaround use OUT_SPEAKER as default device.
AUDIO_DEVICE_OUT_DEFAULT is defined as AUDIO_DEVICE_BIT_DEFAULT instead
of real output device. Use OUT_SPEAKER as default output so that default
opens working routing.
2014-02-23 13:34:11 +02:00
David Greaves
7f5649c442 Merge pull request #2 from sledges/i9305-fix
fix i9305
2014-02-22 18:47:36 +00:00
Simonas Leleiva
0fad8598a6 Revert "[util] Add asserts to port name lookups."
This reverts commit 140fbea03f.

There is some bug in source port lookup with i9305 hal headers,
which results in bad ports. but doesn't prevent sink usage.
2014-02-22 18:35:56 +00:00
64 changed files with 3677 additions and 9333 deletions

3
.gitignore vendored
View file

@ -19,6 +19,3 @@ config.status
libtool
*.pc
stamp-*
# Added by Droidian
!.circleci/

View file

@ -1,10 +1,3 @@
SUBDIRS = src
ACLOCAL_AMFLAGS = -I m4
$(top_srcdir)/.version:
echo $(VERSION) > $@-t && mv $@-t $@
dist-hook:
echo $(VERSION) > $(distdir)/.tarball-version
echo $(VERSION) > $(distdir)/.version

3
README Normal file
View file

@ -0,0 +1,3 @@
PulseAudio Droid modules
========================

356
README.md
View file

@ -1,356 +0,0 @@
PulseAudio Droid modules
========================
For adapdations for Android versions 4 to 10,
see [pulseaudio-modules-droid-jb2q](https://github.com/mer-hybris/pulseaudio-modules-droid-jb2q)
Building of droid modules is split to two packages
* **common** (and **common-devel**) which contains shared library code for use in
PulseAudio modules in this package and for inclusion in other projects
* **droid** with actual PulseAudio modules
Linking to libdroid is **not encouraged**, usually only HAL functions are needed
which can be accessed using the pulsecore shared API (see below).
Supported Android versions:
* 11.x
Headers for defining devices and strings for different droid versions are in
src/common/droid-util-audio.h.
When new devices with relevant new enums appear, add enum check to configure.ac.
CC_CHECK_DROID_ENUM macro will create macros HAVE_ENUM_FOO, STRING_ENTRY_IF_FOO
and FANCY_ENTRY_IF_FOO if enum FOO exists in HAL audio.h.
For example:
# configure.ac:
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_OUT_IP])
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_OUT_OTHER_NEW])
# and then in droid-util-audio.h add macros to proper tables:
/* string_conversion_table_output_device[] */
STRING_ENTRY_IF_OUT_IP
STRING_ENTRY_IF_OUT_OTHER_NEW
/* string_conversion_table_output_device_fancy[] */
FANCY_ENTRY_IF_OUT_IP("output-ip")
FANCY_ENTRY_IF_OUT_OTHER_NEW("output-other_new")
In addition to the above macros there are also now defines
HAVE_ENUM_AUDIO_DEVICE_OUT_IP and HAVE_ENUM_AUDIO_DEVICE_OUT_OTHER_NEW.
The purpose of droid-modules is to "replace AudioFlinger". Many hardware
adaptations use ALSA as the kernel interface, but there is no saying that
someday vendor would create and use something proprietary or otherwise
different from ALSA. Also the ALSA implementation in droid devices may contain
funny ways to achieve things (notable example is voicecall) which might be
difficult to do if interfacing directly with ALSA to replace AudioFlinger.
Also using ALSA directly would mean that the whole HAL adaptation would need to
be ported for each new device adaptation. With droid-modules this is much more
simpler, with somewhat stable HAL (HALv3 as of now, also different vendors add
their own incompatible extensions) API. In best scenarios using droid-modules
with new device is just compiling against target.
Components
==========
common
------
The common part of PulseAudio Droid modules contains library for handling
most operations towards audio HAL.
### Audio policy configuration parsing
Configuration parser reads audio policy xml files.
### Configuration files
If the configuration is in non-default location for some reason "config"
module argument can be used to point to the configuration file location.
By default files are tried in following order,
/odm/etc/audio_policy_configuration.xml
/vendor/etc/audio/audio_policy_configuration.xml
/vendor/etc/audio_policy_configuration.xml
/system/etc/audio_policy_configuration.xml
module-droid-card
-----------------
Ideally only module-droid-card is loaded and then droid-card loads
configuration, creates profiles and loads sinks and sources based on the
selected profile.
default profile
---------------
When module-droid-card is loaded with default arguments, droid-card will
create a default profile (called unsurprisingly "default"). The default
profile will merge supported output and input streams to one profile,
to allow use of possible low latency or deep buffer outputs.
virtual profiles
----------------
In addition to aforementioned card profile, droid-card creates some additional
virtual profiles. These virtual profiles are used when enabling voicecall
routings etc. When virtual profile is enabled, possible sinks and sources
previously active profile had are not removed.
As an illustration, following command line sequence enables voicecall mode and
routes audio to internal handsfree (ihf - "handsfree speaker"):
pactl set-card-profile droid_card.primary voicecall
pactl set-sink-port sink.primary output-parking
pactl set-sink-port sink.primary output-speaker
After this, when there is an active voicecall (created by ofono for example),
voice audio starts to flow between modem and audio chip.
To disable voicecall and return to media audio:
pactl set-card-profile droid_card.primary default
pactl set-sink-port sink.primary output-parking
pactl set-sink-port sink.primary output-speaker
With this example sequence sinks and sources are the ones from default
card profile, and they are maintained for the whole duration of the voicecall
and after.
This sequence follows the droid HAL idea that when changing audio mode the mode
change is done when next routing change happens. output-parking and
input-parking ports are just convenience for PulseAudio, where setting already
active port is a no-op (output/input-parking doesn't do any real routing
changes).
Current virtual profiles are:
* voicecall
* voicecall-record
* communication
* ringtone
Communication profile is used for VoIP-like applications, to enable some
voicecall related algorithms without being in voicecall. Ringtone profile
should be used when ringtone is playing, to again enable possible loudness
related optimizations etc. Voicecall-record profile can be enabled when
voicecall profile is active.
If mix port with flag AUDIO_OUTPUT_FLAG_VOIP_RX exists when communication
virtual profile is enabled additional droid-sink is created with the config
defined in the mix port. Voip audio should then be played to this new sink.
module-droid-sink and module-droid-source
-----------------------------------------
Normally user should not need to load droid-sink or droid-source modules by
hand, but droid-card loads appropriate modules based on the active card
profile.
Changing output routing is as simple as
pactl set-sink-port sink.primary output-wired_headphone
Sinks or sources do not track possible headphone/other wired accessory
plugging, but this needs to be handled elsewhere and then that other entity
needs to control sinks and sources. (For example in SailfishOS this entity is
OHM with accessory-plugin and pulseaudio-policy-enforcement module for
actually making the port switching)
Droid source automatic reconfiguration
--------------------------------------
As droid HAL makes assumptions on (input) routing based on what the parameters
for the stream are (device, sample rate, channels, format, etc.) normal
PulseAudio sources are a bit inflexible as only sample rate can change after
source creation and even then there are restrictions based on alternative
sample rate value.
To overcome this and to allow some more variables affecting the stream being
passed to the input stream droid source is modified to reconfigure itself
with the source-output that connects to it. This means, that just looking at
inactive source from "pactl list" listing doesn't tell the whole story.
Droid source is always reconfigured with the *last* source-output that
connects to it, possibly already connected source-outputs will continue
to read from the source but through resampler.
For example,
1) source-output 44100Hz, stereo connects (so1)
1) source is configured with 44100Hz, stereo
2) so1 connects to the source without resampler
2) source-output 16000Hz, mono connects (so2)
1) so1 is detached from the source
2) source is configured with 16000Hz, mono
3) so2 connects to the source without resampler
4) resampler is created for so1, 16000Hz, mono -> 44100Hz stereo
5) so1 is re-attached to the source through resampler
3) source-output 16000Hz, mono connects (so3)
1) so1 and so2 are detached from the source
2) so3 connects to the source without resampler
3) so1 is re-attached to the source through resampler
4) so2 is attached to the source
Classifying sinks and sources
-----------------------------
Certain property values are set to all active sinks and sources based on their
functionality to ease device classification.
Currently following properties are set:
* For droid sinks
* droid.output.primary
* droid.output.low_latency
* droid.output.media_latency
* droid.output.offload
* droid.output.voip
* For droid sources
* droid.input.builtin
* droid.input.external
If the property is set and with value "true", the sink or source should be
used for the property type. If the property is not defined or contains
value "false" it shouldn't be used for the property type.
For example, we might have sink.primary and sink.low_latency with following
properties:
* sink.primary
* droid.output.primary "true"
* droid.output.media_latency "true"
* sink.low_latency
* droid.output.low_latency "true"
There also may be just one sink, with all the properties defined as "true"
and so on.
Right now there exists only one source (input device) which will always have
both properties as true.
Options
-------
There are some adaptations that require hacks to get things working. These
hacks can be enabled or disabled with module argument "options". Some options
are enabled by default with some adaptations etc. There are also some more
generic options.
Currently there are following options:
* input_atoi
* Enabled by default with Android versions 5 and up.
* Due to how atoi works in bionic vs libc we need to pass the input
route a bit funny. If input routing doesn't work switch this on or off.
* close_input
* Enabled by default.
* Close input stream when not in use instead of suspending the stream.
Cannot be changed when multiple inputs are merged to single source.
* unload_no_close
* Disabled by default.
* Don't call audio_hw_device_close() for the hw module when unloading.
Mostly useful for tracking module unload issues.
* hw_volume
* Enabled by default.
* 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 disable this option.
* 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 option 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.
* output_fast
* Enabled by default.
* Create separate sink if AUDIO_OUTPUT_FLAG_FAST is found. If this sink
is misbehaving try disabling this option.
* output_deep_buffer
* Enabled by default.
* Create separate sink if AUDIO_OUTPUT_FLAG_DEEP_BUFFER is found. If
this sink is misbehaving try disabling this option.
* audio_cal_wait
* Disabled by default.
* Certain devices do audio calibration during hw module open and
writing audio too early will break the calibration. In these cases
this option can be enabled and 10 seconds of sleep is added after
opening hw module.
* speaker_before_voice
* Disabled by default.
* Set route to speaker before changing audio mode to AUDIO_MODE_IN_CALL.
Some devices don't get routing right if the route is something else
(like AUDIO_DEVICE_OUT_WIRED_HEADSET) before calling set_mode().
If routing is wrong when call starts with wired accessory connected
try enabling this option.
* output_voip_rx
* Enabled by default.
* When audio configuration has AUDIO_OUTPUT_FLAG_VOIP_RX special voip
sink is created when AUDIO_MODE_IN_COMMUNICATION is active and the
sink is classified as droid.output.voip. If this is not desired then
by disabling this option the voip sink is not classified but is still
created normally.
* record_voice_16k
* Disabled by default.
* When enabled voice call recording source is forced to sample rate
of 16kHz.
Options can be enabled or disabled normally as module arguments, for example:
load-module module-droid-card hw_volume=false record_voice_16k=true
Volume control during voicecall
-------------------------------
When voicecall virtual profile is enabled, active droid-sink is internally
switched to voicecall volume control mode. What this means is changing the sink
volume or volume of normal streams connected to the sink do not change active
voicecall volume. Special stream is needed to control the voicecall volume
level. By default this stream is identified by stream property media.role,
with value "phone". This can be changed by providing module arguments
voice_property_key and voice_property_value to module-droid-card.
Usually droid HAL has 6 volume levels for voicecall.
Temporary sink audio routing
----------------------------
It is possible to add temporary route to sink audio routing with specific
stream property. When stream with property key
droid.device.additional-route connects to droid-sink, this extra route is set
(if possible) as the enabled route for the duration of the stream.
For example, if droid-sink has active port output-wired_headphone:
paplay --property=droid.device.additional-route=AUDIO_DEVICE_OUT_SPEAKER a.wav
As long as the new stream is connected to droid-sink, output routing is
SPEAKER.
HAL API
-------
If there is need to call HAL directly from other modules it can be done with
function pointer API stored in PulseAudio shared map.
Once the function pointers are acquired when called they will work the same
way as defined in Android audio.h. For example:
void *handle;
int (*set_parameters)(void *handle, const char *key_value_pairs);
char* (*get_parameters)(void *handle, const char *keys);
handle = pa_shared_get(core, "droid.handle.v1");
set_parameters = pa_shared_get(core, "droid.set_parameters.v1");
get_parameters = pa_shared_get(core, "droid.get_parameters.v1");
set_parameters(handle, "route=2;");
char *value = get_parameters(handle, "connected");

View file

@ -1,15 +1,15 @@
AC_PREREQ(2.60)
AC_INIT([pulseaudio-modules-droid-modern], [m4_esyscmd(./git-version-gen .tarball-version)], [mer-general@lists.merproject.org])
m4_define(PA_MAJOR, [4])
m4_define(PA_MINOR, [0])
m4_define(NEMO_MICRO, [1])
AC_INIT([pulseaudio-modules-droid], [PA_MAJOR.PA_MINOR.NEMO_MICRO], [mer-general@lists.merproject.org])
AC_CONFIG_HEADER([config.h])
AM_INIT_AUTOMAKE([foreign -Wall silent-rules])
AC_CONFIG_MACRO_DIR(m4)
AM_SILENT_RULES([yes])
AS_IF([! test -n "$VERSION"], [
AC_MSG_ERROR([git-version-gen failed])
])
if type -p stow > /dev/null && test -d /usr/local/stow ; then
AC_MSG_NOTICE([*** Found /usr/local/stow: default install prefix set to /usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION} ***])
ac_default_prefix="/usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION}"
@ -20,15 +20,9 @@ AC_PROG_CC_C99
AM_PROG_CC_C_O
AC_PROG_GCC_TRADITIONAL
m4_define(pa_major, `pkg-config --modversion libpulse | cut -d. -f1 | cut -d- -f1`)
m4_define(pa_minor, `pkg-config --modversion libpulse | cut -d. -f2 | cut -d- -f1`)
m4_define(pa_module_version, `echo $VERSION | cut -d. -f3 | cut -d- -f1`)
AC_SUBST(PA_MAJORMINOR, PA_MAJOR.PA_MINOR)
AC_SUBST(PA_MAJOR, pa_major)
AC_SUBST(PA_MAJORMINOR, pa_major.pa_minor)
AC_SUBST(PA_MODULE_VERSION, pa_module_version)
DESIRED_FLAGS="-std=gnu11 -Wall -W -Wextra -pipe -Wno-long-long -Wno-overlength-strings -Wunsafe-loop-optimizations -Wundef -Wformat=2 -Wlogical-op -Wsign-compare -Wformat-security -Wmissing-include-dirs -Wformat-nonliteral -Wold-style-definition -Wpointer-arith -Winit-self -Wdeclaration-after-statement -Wfloat-equal -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls -Wmissing-declarations -Wmissing-noreturn -Wshadow -Wendif-labels -Wcast-align -Wstrict-aliasing -Wwrite-strings -Wno-unused-parameter -fno-common -fdiagnostics-show-option -fdiagnostics-color=auto"
DESIRED_FLAGS="-Wall -W -Wextra -pedantic -pipe -Wno-long-long -Winline -Wvla -Wno-overlength-strings -Wunsafe-loop-optimizations -Wundef -Wformat=2 -Wlogical-op -Wsign-compare -Wpacked -Wformat-security -Wmissing-include-dirs -Wformat-nonliteral -Wold-style-definition -Wpointer-arith -Winit-self -Wfloat-equal -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls -Wmissing-declarations -Wmissing-noreturn -Wshadow -Wendif-labels -Wstrict-aliasing=2 -Wwrite-strings -Wno-unused-parameter -ffast-math -Wp,-D_FORTIFY_SOURCE=2 -fno-common -fdiagnostics-show-option" # PulseAudio 0.9.15 usess same + -Wcast-align -Wdeclaration-after-statement
for flag in $DESIRED_FLAGS ; do
CC_CHECK_CFLAGS([$flag], [CFLAGS="$CFLAGS $flag"])
@ -170,10 +164,12 @@ AS_IF([test "$pulseaudio_cv__Bool" = "yes"], [
#LT_INIT([dlopen win32-dll disable-static])
AC_PROG_LIBTOOL
PKG_CHECK_MODULES([PULSEAUDIO], [libpulse >= 14.2 pulsecore >= 14.2])
PKG_CHECK_MODULES([PULSEAUDIO], [libpulse >= 2.1 pulsecore >= 2.1 ])
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])
@ -183,43 +179,13 @@ PKG_CHECK_MODULES([HYBRIS], [libhardware >= 0.1.0])
AC_SUBST(HYBRIS_CFLAGS)
AC_SUBST(HYBRIS_LIBS)
PKG_CHECK_MODULES([EVDEV], [libevdev >= 1.0])
AC_SUBST(EVDEV_CFLAGS)
AC_SUBST(EVDEV_LIBS)
PKG_CHECK_MODULES([DBUS], [dbus-1 >= 1.2])
AC_SUBST(DBUS_CFLAGS)
AC_SUBST(DBUS_LIBS)
#### expat (for xml config format parsing) ####
PKG_CHECK_MODULES([EXPAT], [expat >= 2.1])
AC_SUBST(EXPAT_CFLAGS)
AC_SUBST(EXPAT_LIBS)
# Input devices
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_IN_FM_RX])
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_IN_FM_RX_A2DP])
# Audio sources
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_SOURCE_ECHO_REFERENCE])
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_SOURCE_FM_TUNER])
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_SOURCE_FM_RX])
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_SOURCE_FM_RX_A2DP])
# Output flags
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH])
# Channels
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_CHANNEL_IN_VOICE_CALL_MONO])
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO])
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO])
# Formats
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_FORMAT_PCM_OFFLOAD])
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 ${libdir}/pulse-${PA_MAJORMINOR}/modules]),
[modlibexecdir=$withval], [modlibexecdir="${libdir}/pulse-${PA_MAJORMINOR}/modules"])
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_SUBST(modlibexecdir)
@ -230,15 +196,10 @@ AC_ARG_WITH([droid-device],
AS_HELP_STRING([--with-droid-device], [Droid device type for possible specific quirks (defaults to generic).]),
[droiddevice=$withval], [droiddevice="generic"]
)
if test "x$droiddevice" != x ; then
DROID_DEVICE_CFLAGS="-DDROID_DEVICE_`echo $droiddevice | tr '[a-z]' '[A-Z]'`=1 -DDROID_DEVICE_STRING=\"\\\"$droiddevice\\\"\""
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])
if test "x$droiddevice" = xmako ; then
AC_DEFINE([DROID_DEVICE_MAKO], [1], [Using droid device mako.])
else
AC_DEFINE([DROID_DEVICE_GENERIC], [1], [Using droid device generic.])
fi
AC_MSG_CHECKING([If we are using hardfp tool chain])
@ -256,8 +217,6 @@ fi
AC_CONFIG_FILES([
Makefile
src/Makefile
src/common/Makefile
src/common/libdroid-util.pc
src/droid/Makefile
])
@ -271,7 +230,8 @@ echo "
CFLAGS: ${CFLAGS}
prefix: ${prefix}
PulseAudio prefix: ${pulseaudiodir}
modules directory: ${modlibexecdir}
Droid device: ${droiddevice}
Droid device ${droiddevice}
"

98
debian/changelog vendored
View file

@ -1,98 +0,0 @@
pulseaudio-modules-droid-modern (16.1.101+gemian11+nmu1) bookworm; urgency=medium
* Non-maintainer upload.
* add config files
-- Penelope Gwen <support@pogmom.me> Sun, 29 Mar 2026 14:04:19 -0700
pulseaudio-modules-droid-modern (16.1.101+gemian1) unstable; urgency=medium
* New upstream nabbed from droidian
-- Adam Boardman <adamboardman@gmail.com> Tue, 04 Apr 2023 16:02:47 +0100
pulseaudio-modules-droid (12.2.84+gemian) buster; urgency=medium
* New upstream release
-- TheKit <thekit@disroot.org> Wed, 03 Jun 2020 01:55:10 +0100
pulseaudio-modules-droid (12.2.79+gemian) buster; urgency=medium
* Branch packaging for Gemian
-- TheKit <thekit@disroot.org> Wed, 13 Nov 2019 13:39:31 +0100
pulseaudio-modules-droid (12.2.79-3) unstable; urgency=medium
* Fix pulseaudio droid module version
-- Jonah Brüchert <jbb@kaidan.im> Tue, 12 Nov 2019 12:35:51 +0100
pulseaudio-modules-droid (12.2.79-2) unstable; urgency=medium
* Fix generating the pkgconfig files with proper pathes
-- Jonah Brüchert <jbb@kaidan.im> Tue, 12 Nov 2019 12:06:47 +0100
pulseaudio-modules-droid (12.2.79-1) unstable; urgency=medium
* New upstream release
-- Jonah Brüchert <jbb@kaidan.im> Sun, 06 Oct 2019 15:23:45 +0200
pulseaudio-modules-droid (12.2.78-1) unstable; urgency=medium
* New upstream release
-- Jonah Brüchert <jbb@kaidan.im> Thu, 25 Apr 2019 22:37:38 +0200
pulseaudio-modules-droid (11.1.75-1) unstable; urgency=medium
* New upstream release
-- Jonah Brüchert <jbb@kaidan.im> Tue, 13 Nov 2018 21:17:39 +0100
pulseaudio-modules-droid (11.1.74-1) unstable; urgency=medium
* New upstream release
-- Jonah Brüchert <jbb@kaidan.im> Sat, 13 Oct 2018 20:43:53 +0200
pulseaudio-modules-droid (11.1.73-1) unstable; urgency=medium
* New upstream release
-- Jonah Brüchert <jbb@kaidan.im> Sat, 13 Oct 2018 20:43:29 +0200
pulseaudio-modules-droid (11.1.72-1) unstable; urgency=medium
* New upstream release
-- Jonah Brüchert <jbb@kaidan.im> Sun, 26 Aug 2018 12:27:09 +0200
pulseaudio-modules-droid (11.1.71-1) unstable; urgency=medium
* New upstream release
-- Jonah Brüchert <jbb@kaidan.im> Wed, 22 Aug 2018 14:04:55 +0200
pulseaudio-modules-droid (11.1.68-1) unstable; urgency=medium
* New upstream release
-- Jonah Brüchert <jbb@kaidan.im> Wed, 06 Jun 2018 14:03:22 +0200
pulseaudio-modules-droid (11.1.67-1) unstable; urgency=medium
* New upstream release
* Move to mer-hybris upstream
* Split packaging from source
-- Jonah Brüchert <jbb@kaidan.im> Sat, 26 May 2018 20:06:24 +0200
pulseaudio-modules-droid (0.1) xenial; urgency=medium
* Initial release.
-- Marius Gripsgard <marius@ubports.com> Fri, 19 Jan 2018 07:39:13 +0100

1
debian/compat vendored
View file

@ -1 +0,0 @@
11

43
debian/control vendored
View file

@ -1,43 +0,0 @@
Source: pulseaudio-modules-droid-modern
Section: sound
Priority: optional
Build-Depends: android-headers,
check,
debhelper (>= 11),
dh-exec,
intltool,
pulseaudio-pulsecore-dev,
libdbus-1-dev,
libhardware-dev,
libhybris-common-dev,
libltdl-dev,
libpulse-dev,
libexpat1-dev,
libevdev-dev,
libudev-dev
Maintainer: Adam Boardman <adamboardman@gmail.com>
Standards-Version: 4.3.0
Homepage: https://github.com/mer-hybris/pulseaudio-modules-droid
Vcs-Git: https://github.com/gemian/pulseaudio-modules-droid-modern.git
Vcs-Browser: https://github.com/gemian/pulseaudio-modules-droid-modern
Package: pulseaudio-modules-droid-modern
Architecture: any
Depends: ${misc:Depends}, ${shlibs:Depends}
Provides: pulseaudio-modules-droid-apispecific
Conflicts: pulseaudio-modules-droid-apispecific
Description: PulseAudio Droid HAL module
Pulseaudio modules to interact with the Android HAL.
.
This package contains the actual modules, for Android 11+.
Package: pulseaudio-modules-droid-modern-dev
Architecture: any
Depends: pulseaudio-modules-droid-modern (= ${binary:Version}),
${misc:Depends},
Provides: pulseaudio-modules-droid-apispecific-dev
Conflicts: pulseaudio-modules-droid-apispecific-dev
Description: PulseAudio Droid HAL module - development headers
Pulseaudio modules to interact with the Android HAL.
.
This package contains the development headers.

44
debian/copyright vendored
View file

@ -1,44 +0,0 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: pulseaudio-modules-droid-modern
Source: https://github.com/mer-hybris/pulseaudio-modules-droid-modern
Files: *
Copyright: 2013-2022, Jolla Ltd.
License: LGPL-2.1
Files: debian/*
Copyright: 2018, Jonah Brüchert
2017, 2018, Marius Gripsgard
License: LGPL-2.1
Files: m4/*
Copyright: 2006, 2007, xine project
2006, 2007, Diego Pettenò <flameeyes@gmail.com>
License: GPL-2+
License: GPL-2+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991, or (at
your option) any later version.
.
On Debian systems, the complete text of version 2 of the GNU General
Public License can be found in '/usr/share/common-licenses/GPL-2'.
License: LGPL-2.1
This package is 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 package 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 package; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
.
On Debian systems, the complete text of the GNU Lesser General
Public License can be found in `/usr/share/common-licenses/LGPL-2.1'.

4
debian/preinst vendored
View file

@ -1,4 +0,0 @@
#!/bin/sh
rm /etc/pulse/default.pa.gemian || true
rm /etc/pulse/arm_droid_card_custom.pa || true

View file

@ -1,2 +0,0 @@
usr/include/pulsecore/modules/droid/*.h
usr/lib/*/pkgconfig/*

View file

@ -1,7 +0,0 @@
usr/lib/pulse-*/modules/libdroid-sink*.so
usr/lib/pulse-*/modules/libdroid-source*.so
usr/lib/pulse-*/modules/libdroid-util*.so
usr/lib/pulse-*/modules/module-droid-card*.so
usr/lib/pulse-*/modules/module-droid-sink*.so
usr/lib/pulse-*/modules/module-droid-source*.so
etc/*

33
debian/rules vendored
View file

@ -1,33 +0,0 @@
#!/usr/bin/make -f
# -*- makefile -*-
include /usr/share/dpkg/default.mk
PA_MODULE_DIR := $$(readlink -f /usr/lib/pulse-*/modules)
%:
dh $@ --with=autoreconf
override_dh_auto_configure:
dh_auto_configure -- --disable-static --with-module-dir=${PA_MODULE_DIR}
override_dh_autoreconf:
echo ${DEB_VERSION_UPSTREAM} > .tarball-version
dh_autoreconf
override_dh_auto_clean:
if [ -f .tarball-version ]; then rm .tarball-version; fi
dh_auto_clean
override_dh_shlibdeps:
dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info -l/usr/lib/${DEB_HOST_MULTIARCH}/pulseaudio:/usr/lib/pulse-*/modules
override_dh_auto_install:
dh_auto_install
rm debian/tmp/usr/lib/pulse-*/modules/*.la
install -d debian/tmp/usr/include/pulsecore/modules/droid
install -m 644 src/common/*.h debian/tmp/usr/include/pulsecore/modules/droid
install -d debian/tmp/usr/lib/${DEB_HOST_MULTIARCH}/pkgconfig
install -m 644 src/common/*.pc debian/tmp/usr/lib/${DEB_HOST_MULTIARCH}/pkgconfig

View file

@ -1 +0,0 @@
3.0 (native)

View file

@ -1 +0,0 @@
load-module module-droid-card

View file

@ -1,142 +0,0 @@
#!/usr/bin/pulseaudio -nF
#
# This file is part of PulseAudio.
#
# PulseAudio is 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; either version 2 of the License, or
# (at your option) any later version.
#
# PulseAudio 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
# General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
# This startup script is used only if PulseAudio is started per-user
# (i.e. not in system mode)
.nofail
.fail
load-module module-droid-keepalive
### Automatically augment property information from .desktop files
### stored in /usr/share/application
load-module module-augment-properties
load-module module-null-sink sink_name=sink.null rate=48000
load-module module-stream-restore
### Switch when connected by default (ubports)
load-module module-switch-on-connect ignore_virtual=yes
### Should be after module-*-restore but before module-*-detect (sfos)
load-module module-switch-on-port-available
### If droid-card needs other arguments than the default, have the new
### load-module line in /etc/pulse/arm_droid_card_custom.pa
.ifexists /etc/pulse/arm_droid_card_custom.pa
.include /etc/pulse/arm_droid_card_custom.pa
.else
load-module module-droid-card rate=48000
.endif
### Needed on many new devices. HADK guide explains how to implement this fully
.ifexists module-droid-glue.so
.nofail
load-module module-droid-glue
.fail
.endif
.ifexists module-droid-hidl-28.so
.nofail
load-module module-droid-hidl-28
.fail
.endif
load-module module-null-sink sink_name=sink.fake.sco rate=8000 channels=1
load-module module-null-source source_name=source.fake.sco rate=8000 channels=1
#load-module module-bluetooth-discover bluez4_args="sco_sink=sink.fake.sco sco_source=source.fake.sco" bluez5_args="headset=droid"
load-module module-bluetooth-discover
load-module module-bluetooth-policy
#load-module module-policy-enforcement
load-module module-role-ducking trigger_roles=alarm,notification,warning ducking_roles=x-maemo volume=-200dB
### Load several protocols
.ifexists module-esound-protocol-unix.so
load-module module-esound-protocol-unix
.endif
load-module module-native-protocol-unix
### Network access (may be configured with paprefs, so leave this commented
### here if you plan to use paprefs)
#load-module module-esound-protocol-tcp
#load-module module-native-protocol-tcp
#load-module module-zeroconf-publish
### Load the RTP receiver module (also configured via paprefs, see above)
#load-module module-rtp-recv
### Load the RTP sender module (also configured via paprefs, see above)
#load-module module-null-sink sink_name=rtp format=s16be channels=2 rate=44100 sink_properties="device.description='RTP Multicast Sink'"
#load-module module-rtp-send source=rtp.monitor
### Load additional modules from GSettings. This can be configured with the paprefs tool.
### Please keep in mind that the modules configured by paprefs might conflict with manually
### loaded modules.
.ifexists module-gsettings.so
.nofail
load-module module-gsettings
.fail
.endif
### Make sure we always have a sink around, even if it is a null sink.
load-module module-always-sink
### Honour intended role device property
load-module module-intended-roles
### Automatically suspend sinks/sources that become idle for too long
load-module module-suspend-on-idle timeout=1
### If autoexit on idle is enabled we want to make sure we only quit
### when no local session needs us anymore.
.ifexists module-console-kit.so
load-module module-console-kit
.endif
.ifexists module-systemd-login.so
load-module module-systemd-login
.endif
### Load DBus protocol
.ifexists module-dbus-protocol.so
load-module module-dbus-protocol
.endif
### Move orphan streams to placeholder sinks or sources so that playback doesn't get
### interrupted. Policy enforcement module then moves the streams to new appropriate
### sinks or sources.
#load-module module-rescue-streams sink_name=sink.null source_name=sink.null.monitor
### Enable positioned event sounds
load-module module-position-event-sounds
### Modules to allow auto-loading of filters (such as echo cancellation)
### on demand. module-filter-heuristics tries to determine what filters
### make sense, and module-filter-apply does the heavy-lifting of
### loading modules and rerouting streams.
load-module module-filter-heuristics
load-module module-filter-apply
### Make some devices default
set-default-sink sink.primary_output
set-default-source source.droid

View file

@ -1,26 +0,0 @@
#!/bin/sh
if test $# -lt 1
then
echo 1>&2 "Usage: $0 \$srcdir/.tarball-version"
exit 1
fi
VF=$1
# First see if there is a version file,
# then try git-describe, otherwise fail.
if test -f $VF
then
VN=$(cat $VF)
elif test -d ${GIT_DIR:-.git} -o -f .git &&
V=$(git describe --match "[0-9]*" --abbrev=7 --tags 2>/dev/null)
then
VN=$V
else
echo 1>&2 "$0: Failed to determine revision"
exit 1
fi
# Omit the trailing newline, so that m4_esyscmd can use the result directly.
echo "$VN" | tr -d '\012'

View file

@ -1,26 +0,0 @@
AC_DEFUN([CC_CHECK_DROID_ENUM],
[AC_MSG_CHECKING([if droid headers have enum $2])
AC_LANG_SAVE
AC_LANG_C
SAVE_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $1"
AC_TRY_COMPILE(
[ #include <android-config.h>
#ifdef QCOM_BSP
#define QCOM_HARDWARE
#endif
#include <system/audio.h> ],
[ unsigned int e = $2; ],
cc_check_droid_enum=yes, cc_check_droid_enum=no)
CFLAGS="$SAVE_CFLAGS"
AC_LANG_RESTORE
AC_MSG_RESULT([$cc_check_droid_enum])
if test x"$cc_check_droid_enum" = x"yes"; then
AC_DEFINE(HAVE_ENUM_$2,,[define if enum $2 is found in headers])
AC_DEFINE(STRING_ENTRY_IF_$2,[STRING_ENTRY($2),],[string entry for enum $2])
AC_DEFINE(FANCY_ENTRY_IF_$2(n),[{$2, n},],[fancy entry for enum $2])
else
AC_DEFINE(STRING_ENTRY_IF_$2,,[string entry for enum $2])
AC_DEFINE(FANCY_ENTRY_IF_$2(n),,[fancy entry for enum $2])
fi
])

7
rpm/precheckin.sh Executable file
View file

@ -0,0 +1,7 @@
#!/bin/sh
DEVICES="boston mako sbj i9305"
for dev in $DEVICES; do
sed -e "s/@DEVICE@/$dev/g" pulseaudio-modules-droid.spec.in > pulseaudio-modules-droid-$dev.spec
done

View file

@ -0,0 +1,42 @@
%define device boston
%define pulseversion 4.0
Name: pulseaudio-modules-droid-%{device}
Summary: PulseAudio Droid HAL modules
Version: %{pulseversion}.1
Release: 1
Group: Multimedia/PulseAudio
License: LGPLv2.1+
URL: https://github.com/mer-hybris/multimedia-pulseaudio-modules-droid
Source0: %{name}-%{version}.tar.bz2
Source1: pulseaudio-modules-droid.spec.in
Source2: precheckin.sh
Requires: pulseaudio >= %{pulseversion}
BuildRequires: automake
BuildRequires: libtool
BuildRequires: libtool-ltdl-devel
BuildRequires: pkgconfig(pulsecore) >= %{pulseversion}
BuildRequires: pkgconfig(android-headers)
BuildRequires: pkgconfig(libhardware)
BuildRequires: pkgconfig(dbus-1)
Provides: pulseaudio-modules-droid
%description
PulseAudio Droid HAL modules.
%prep
%setup -q -n %{name}-%{version}
%build
%reconfigure --disable-static --with-droid-device=%{device}
make %{?jobs:-j%jobs}
%install
rm -rf %{buildroot}
%make_install
%files
%defattr(-,root,root,-)
%{_libdir}/pulse-%{pulseversion}/modules/*.so

View file

@ -0,0 +1,42 @@
%define device i9305
%define pulseversion 4.0
Name: pulseaudio-modules-droid-%{device}
Summary: PulseAudio Droid HAL modules
Version: %{pulseversion}.1
Release: 1
Group: Multimedia/PulseAudio
License: LGPLv2.1+
URL: https://github.com/mer-hybris/multimedia-pulseaudio-modules-droid
Source0: %{name}-%{version}.tar.bz2
Source1: pulseaudio-modules-droid.spec.in
Source2: precheckin.sh
Requires: pulseaudio >= %{pulseversion}
BuildRequires: automake
BuildRequires: libtool
BuildRequires: libtool-ltdl-devel
BuildRequires: pkgconfig(pulsecore) >= %{pulseversion}
BuildRequires: pkgconfig(android-headers)
BuildRequires: pkgconfig(libhardware)
BuildRequires: pkgconfig(dbus-1)
Provides: pulseaudio-modules-droid
%description
PulseAudio Droid HAL modules.
%prep
%setup -q -n %{name}-%{version}
%build
%reconfigure --disable-static --with-droid-device=%{device}
make %{?jobs:-j%jobs}
%install
rm -rf %{buildroot}
%make_install
%files
%defattr(-,root,root,-)
%{_libdir}/pulse-%{pulseversion}/modules/*.so

View file

@ -0,0 +1,42 @@
%define device mako
%define pulseversion 4.0
Name: pulseaudio-modules-droid-%{device}
Summary: PulseAudio Droid HAL modules
Version: %{pulseversion}.1
Release: 1
Group: Multimedia/PulseAudio
License: LGPLv2.1+
URL: https://github.com/mer-hybris/multimedia-pulseaudio-modules-droid
Source0: %{name}-%{version}.tar.bz2
Source1: pulseaudio-modules-droid.spec.in
Source2: precheckin.sh
Requires: pulseaudio >= %{pulseversion}
BuildRequires: automake
BuildRequires: libtool
BuildRequires: libtool-ltdl-devel
BuildRequires: pkgconfig(pulsecore) >= %{pulseversion}
BuildRequires: pkgconfig(android-headers)
BuildRequires: pkgconfig(libhardware)
BuildRequires: pkgconfig(dbus-1)
Provides: pulseaudio-modules-droid
%description
PulseAudio Droid HAL modules.
%prep
%setup -q -n %{name}-%{version}
%build
%reconfigure --disable-static --with-droid-device=%{device}
make %{?jobs:-j%jobs}
%install
rm -rf %{buildroot}
%make_install
%files
%defattr(-,root,root,-)
%{_libdir}/pulse-%{pulseversion}/modules/*.so

View file

@ -0,0 +1,42 @@
%define device sbj
%define pulseversion 4.0
Name: pulseaudio-modules-droid-%{device}
Summary: PulseAudio Droid HAL modules
Version: %{pulseversion}.1
Release: 1
Group: Multimedia/PulseAudio
License: LGPLv2.1+
URL: https://github.com/mer-hybris/multimedia-pulseaudio-modules-droid
Source0: %{name}-%{version}.tar.bz2
Source1: pulseaudio-modules-droid.spec.in
Source2: precheckin.sh
Requires: pulseaudio >= %{pulseversion}
BuildRequires: automake
BuildRequires: libtool
BuildRequires: libtool-ltdl-devel
BuildRequires: pkgconfig(pulsecore) >= %{pulseversion}
BuildRequires: pkgconfig(android-headers)
BuildRequires: pkgconfig(libhardware)
BuildRequires: pkgconfig(dbus-1)
Provides: pulseaudio-modules-droid
%description
PulseAudio Droid HAL modules.
%prep
%setup -q -n %{name}-%{version}
%build
%reconfigure --disable-static --with-droid-device=%{device}
make %{?jobs:-j%jobs}
%install
rm -rf %{buildroot}
%make_install
%files
%defattr(-,root,root,-)
%{_libdir}/pulse-%{pulseversion}/modules/*.so

View file

@ -1,81 +0,0 @@
%define pulseversion %{expand:%(rpm -q --qf '[%%{version}]' pulseaudio)}
%define pulsemajorminor %{expand:%(echo '%{pulseversion}' | cut -d+ -f1)}
%define moduleversion %{pulsemajorminor}.%{expand:%(echo '%{version}' | cut -d. -f3)}
Name: pulseaudio-modules-droid
Summary: PulseAudio Droid HAL modules
Version: %{pulsemajorminor}.101
Release: 1
License: LGPLv2+
URL: https://github.com/mer-hybris/pulseaudio-modules-droid
Source0: %{name}-%{version}.tar.bz2
Requires: pulseaudio >= %{pulseversion}
Requires: %{name}-common = %{version}-%{release}
Requires: pulseaudio-module-keepalive >= 1.0.0
BuildRequires: automake
BuildRequires: libtool
BuildRequires: libtool-ltdl-devel
BuildRequires: pkgconfig(pulsecore) >= %{pulsemajorminor}
BuildRequires: pkgconfig(android-headers)
BuildRequires: pkgconfig(libhardware)
BuildRequires: pkgconfig(expat)
%description
PulseAudio Droid HAL modules.
%package common
Summary: Common libs for the PulseAudio droid modules
Requires: pulseaudio >= %{pulseversion}
%description common
This contains common libs for the PulseAudio droid modules.
%package devel
Summary: Development files for PulseAudio droid modules
Requires: %{name}-common = %{version}-%{release}
Requires: pulseaudio >= %{pulseversion}
%description devel
This contains development files for PulseAudio droid modules.
%prep
%autosetup -n %{name}-%{version}
%build
echo "%{moduleversion}" > .tarball-version
# Obtain the DEVICE from the same source as used in /etc/os-release
if [ -e "%{_includedir}/droid-devel/hw-release.vars" ]; then
. %{_includedir}/droid-devel/hw-release.vars
else
. %{_libdir}/droid-devel/hw-release.vars
fi
%reconfigure --disable-static --with-droid-device=$MER_HA_DEVICE
%make_build
%install
%make_install
%files
%defattr(-,root,root,-)
%{_libdir}/pulse-%{pulsemajorminor}/modules/libdroid-sink.so
%{_libdir}/pulse-%{pulsemajorminor}/modules/libdroid-source.so
%{_libdir}/pulse-%{pulsemajorminor}/modules/module-droid-sink.so
%{_libdir}/pulse-%{pulsemajorminor}/modules/module-droid-source.so
%{_libdir}/pulse-%{pulsemajorminor}/modules/module-droid-card.so
%license COPYING
%files common
%defattr(-,root,root,-)
%{_libdir}/pulse-%{pulsemajorminor}/modules/libdroid-util.so
%files devel
%defattr(-,root,root,-)
%dir %{_includedir}/pulsecore/modules/droid
%{_includedir}/pulsecore/modules/droid/conversion.h
%{_includedir}/pulsecore/modules/droid/droid-config.h
%{_includedir}/pulsecore/modules/droid/droid-util.h
%{_includedir}/pulsecore/modules/droid/sllist.h
%{_includedir}/pulsecore/modules/droid/utils.h
%{_includedir}/pulsecore/modules/droid/version.h
%{_libdir}/pkgconfig/*.pc

View file

@ -0,0 +1,42 @@
%define device @DEVICE@
%define pulseversion 4.0
Name: pulseaudio-modules-droid-%{device}
Summary: PulseAudio Droid HAL modules
Version: %{pulseversion}.1
Release: 1
Group: Multimedia/PulseAudio
License: LGPLv2.1+
URL: https://github.com/mer-hybris/multimedia-pulseaudio-modules-droid
Source0: %{name}-%{version}.tar.bz2
Source1: pulseaudio-modules-droid.spec.in
Source2: precheckin.sh
Requires: pulseaudio >= %{pulseversion}
BuildRequires: automake
BuildRequires: libtool
BuildRequires: libtool-ltdl-devel
BuildRequires: pkgconfig(pulsecore) >= %{pulseversion}
BuildRequires: pkgconfig(android-headers)
BuildRequires: pkgconfig(libhardware)
BuildRequires: pkgconfig(dbus-1)
Provides: pulseaudio-modules-droid
%description
PulseAudio Droid HAL modules.
%prep
%setup -q -n %{name}-%{version}
%build
%reconfigure --disable-static --with-droid-device=%{device}
make %{?jobs:-j%jobs}
%install
rm -rf %{buildroot}
%make_install
%files
%defattr(-,root,root,-)
%{_libdir}/pulse-%{pulseversion}/modules/*.so

View file

@ -1 +1 @@
SUBDIRS = common droid
SUBDIRS = droid

View file

@ -1,38 +0,0 @@
AM_LIBADD = \
$(PULSEAUDIO_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/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 \
include/droid/sllist.h \
include/droid/utils.h
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libdroid-util.pc
libdroid_util_la_SOURCES = droid-util.c \
droid-config.c \
conversion.c \
config-parser-xml.c \
config-parser-xml.h \
sllist.c \
utils.c \
droid-util-audio.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)

File diff suppressed because it is too large Load diff

View file

@ -1,529 +0,0 @@
/*
* Copyright (C) 2013-2022 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 ","
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;
for (unsigned int i = 0; list[i].str; i++) {
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;
}
/* Generic conversion */
bool pa_string_convert_num_to_str(pa_conversion_string_t type, uint32_t value, const char **to_str) {
switch (type) {
case CONV_STRING_FORMAT:
return string_convert_num_to_str(string_conversion_table_format, value, to_str);
case CONV_STRING_OUTPUT_CHANNELS:
return string_convert_num_to_str(string_conversion_table_output_channels, value, to_str);
case CONV_STRING_INPUT_CHANNELS:
return string_convert_num_to_str(string_conversion_table_input_channels, value, to_str);
case CONV_STRING_OUTPUT_DEVICE:
return string_convert_num_to_str(string_conversion_table_output_device, value, to_str);
case CONV_STRING_INPUT_DEVICE:
return string_convert_num_to_str(string_conversion_table_input_device, value, to_str);
case CONV_STRING_OUTPUT_FLAG:
return string_convert_num_to_str(string_conversion_table_output_flag, value, to_str);
case CONV_STRING_INPUT_FLAG:
return string_convert_num_to_str(string_conversion_table_input_flag, value, to_str);
case CONV_STRING_AUDIO_SOURCE_FANCY:
return string_convert_num_to_str(string_conversion_table_audio_source_fancy, value, to_str);
}
pa_assert_not_reached();
return false;
}
bool pa_string_convert_str_to_num(pa_conversion_string_t type, const char *str, uint32_t *to_value) {
switch (type) {
case CONV_STRING_FORMAT:
return string_convert_str_to_num(string_conversion_table_format, str, to_value);
case CONV_STRING_OUTPUT_CHANNELS:
return string_convert_str_to_num(string_conversion_table_output_channels, str, to_value);
case CONV_STRING_INPUT_CHANNELS:
return string_convert_str_to_num(string_conversion_table_input_channels, str, to_value);
case CONV_STRING_OUTPUT_DEVICE:
return string_convert_str_to_num(string_conversion_table_output_device, str, to_value);
case CONV_STRING_INPUT_DEVICE:
return string_convert_str_to_num(string_conversion_table_input_device, str, to_value);
case CONV_STRING_OUTPUT_FLAG:
return string_convert_str_to_num(string_conversion_table_output_flag, str, to_value);
case CONV_STRING_INPUT_FLAG:
return string_convert_str_to_num(string_conversion_table_input_flag, str, to_value);
case CONV_STRING_AUDIO_SOURCE_FANCY:
return string_convert_str_to_num(string_conversion_table_audio_source_fancy, str, to_value);
}
pa_assert_not_reached();
return false;
}
/* 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);
}
/* 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);
}
/* 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)
{
/* 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);
}
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);
/* Not handled in this context */
case CONV_STRING_AUDIO_SOURCE_FANCY:
return 0;
}
pa_assert_not_reached();
return 0;
}
bool pa_conversion_parse_sampling_rates(const char *fn, const unsigned ln,
const char *str,
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, &state))) {
int32_t val;
if (pos == 0 && pa_streq(entry, "dynamic")) {
sampling_rates[pos++] = (uint32_t) -1;
pa_xfree(entry);
break;
}
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,
audio_format_t *formats) {
int count;
char *unknown = NULL;
pa_assert(fn);
pa_assert(str);
pa_assert(formats);
/* Needs to be probed later */
if (pa_streq(str, "dynamic")) {
*formats = 0;
return true;
}
count = pa_conversion_parse_list(CONV_STRING_FORMAT, VALUE_SEPARATOR, str, formats, &unknown);
/* 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 int parse_channels(const char *fn, const unsigned ln,
const char *str, bool in_output,
audio_channel_mask_t channel_masks[AUDIO_MAX_CHANNEL_MASKS]) {
bool success;
int count = 0;
char *unknown = NULL;
char *entry;
const char *state = NULL;
pa_assert(fn);
pa_assert(str);
/* Needs to be probed later */
if (pa_streq(str, "dynamic")) {
channel_masks[0] = 0;
return 1;
}
while ((entry = pa_split(str, VALUE_SEPARATOR, &state))) {
uint32_t val;
if (count == AUDIO_MAX_CHANNEL_MASKS) {
pa_log("[%s:%u] Too many channel mask entries (> %d)", fn, ln, AUDIO_MAX_CHANNEL_MASKS);
pa_xfree(entry);
return false;
}
if (!string_convert_str_to_num(in_output ? string_conversion_table_output_channels
: string_conversion_table_input_channels,
entry,
&val)) {
pa_log_debug("[%s:%u] Ignore unknown channel mask value %s", fn, ln, entry);
pa_xfree(entry);
continue;
}
channel_masks[count++] = val;
pa_xfree(entry);
}
channel_masks[count] = 0;
/* Avoid aborting parsing when no supported channel is found */
success = check_and_log(fn, ln, in_output ? "output channel_masks" : "input channel_masks",
count == 0 ? 1 : count, str, unknown, false);
return success ? count : -1;
}
int pa_conversion_parse_output_channels(const char *fn, const unsigned ln,
const char *str,
audio_channel_mask_t channel_masks[AUDIO_MAX_CHANNEL_MASKS]) {
return parse_channels(fn, ln, str, true, channel_masks);
}
int pa_conversion_parse_input_channels(const char *fn, const unsigned ln,
const char *str,
audio_channel_mask_t channel_masks[AUDIO_MAX_CHANNEL_MASKS]) {
return parse_channels(fn, ln, str, false, channel_masks);
}
static bool parse_devices(const char *fn, const unsigned ln,
const char *str, bool in_output,
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, str, devices, &unknown);
/* 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 must_recognize_all,
audio_devices_t *devices) {
return parse_devices(fn, ln, str, true, must_recognize_all, devices);
}
bool pa_conversion_parse_input_devices(const char *fn, const unsigned ln,
char *str, bool must_recognize_all,
audio_devices_t *devices) {
return parse_devices(fn, ln, str, false, 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;
}
}

View file

@ -1,366 +0,0 @@
/*
* Copyright (C) 2013-2022 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 "config-parser-xml.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/xmalloc.h>
#include <pulsecore/core-util.h>
#include <pulsecore/log.h>
#include <pulsecore/macro.h>
#include <pulsecore/modargs.h>
#include <hardware/audio.h>
#define ODM_AUDIO_POLICY_CONFIG_XML_FILE "/odm/etc/audio_policy_configuration.xml"
#define VENDOR_AUDIO_AUDIO_POLICY_CONFIG_XML_FILE "/vendor/etc/audio/audio_policy_configuration.xml"
#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"
dm_config_device *dm_config_load(pa_modargs *ma) {
dm_config_device *config = NULL;
const char *manual_config;
const char *config_location[] = {
ODM_AUDIO_POLICY_CONFIG_XML_FILE,
VENDOR_AUDIO_AUDIO_POLICY_CONFIG_XML_FILE,
VENDOR_AUDIO_POLICY_CONFIG_XML_FILE,
SYSTEM_AUDIO_POLICY_CONFIG_XML_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;
}
static dm_config_profile *config_profile_dup(const dm_config_profile *profile) {
dm_config_profile *copy = pa_xnew0(dm_config_profile, 1);
copy->name = pa_xstrdup(profile->name);
copy->format = profile->format;
memcpy(copy->sampling_rates,
profile->sampling_rates,
sizeof(profile->sampling_rates));
memcpy(copy->channel_masks,
profile->channel_masks,
sizeof(profile->channel_masks));
return copy;
}
static dm_config_port *config_port_dup(const dm_config_port *port, dm_config_module *module) {
dm_config_port *copy = pa_xnew0(dm_config_port, 1);
const dm_list_entry *i;
copy->module = module;
copy->port_type = port->port_type;
copy->name = pa_xstrdup(port->name);
copy->role = port->role;
copy->profiles = dm_list_new();
DM_LIST_FOREACH(i, port->profiles)
dm_list_push_back(copy->profiles, config_profile_dup(i->data));
if (port->port_type == DM_CONFIG_TYPE_DEVICE_PORT) {
copy->type = port->type;
copy->address = pa_xstrdup(port->address);
}
if (port->port_type == DM_CONFIG_TYPE_MIX_PORT) {
copy->flags = port->flags;
copy->max_open_count = port->max_open_count;
copy->max_active_count = port->max_active_count;
}
return copy;
}
static dm_config_route *config_route_dup(const dm_config_route *route, dm_list *ports) {
dm_config_route *copy = pa_xnew0(dm_config_route, 1);
dm_config_port *port_copy, *port;
void *state, *state2;
copy->type = route->type;
copy->sources = dm_list_new();
DM_LIST_FOREACH_DATA(port, route->sources, state) {
DM_LIST_FOREACH_DATA(port_copy, ports, state2) {
if (dm_config_port_equal(port, port_copy)) {
dm_list_push_back(copy->sources, port_copy);
break;
}
}
}
DM_LIST_FOREACH_DATA(port_copy, ports, state) {
if (dm_config_port_equal(port_copy, route->sink)) {
copy->sink = port_copy;
break;
}
}
return copy;
}
static dm_config_module *config_module_dup(const dm_config_module *module) {
dm_config_module *copy = pa_xnew0(dm_config_module, 1);
dm_config_port *device_port, *attached_device, *mix_port;
dm_config_route *route;
void *state, *state2;
copy = pa_xnew0(dm_config_module, 1);
copy->name = pa_xstrdup(module->name);
copy->version_major = module->version_major;
copy->version_minor = module->version_minor;
copy->attached_devices = dm_list_new();
copy->default_output_device = NULL;
copy->mix_ports = dm_list_new();
copy->device_ports = dm_list_new();
copy->ports = dm_list_new();
copy->routes = dm_list_new();
DM_LIST_FOREACH_DATA(device_port, module->device_ports, state) {
dm_config_port *device_port_copy = config_port_dup(device_port, copy);
dm_list_push_back(copy->device_ports, device_port_copy);
dm_list_push_back(copy->ports, device_port_copy);
if (module->default_output_device == device_port)
copy->default_output_device = device_port_copy;
DM_LIST_FOREACH_DATA(attached_device, module->attached_devices, state2) {
if (attached_device == device_port) {
dm_list_push_back(copy->attached_devices, device_port_copy);
break;
}
}
}
DM_LIST_FOREACH_DATA(mix_port, module->mix_ports, state) {
dm_config_port *mix_port_copy = config_port_dup(mix_port, copy);
dm_list_push_back(copy->mix_ports, mix_port_copy);
dm_list_push_back(copy->ports, mix_port_copy);
}
DM_LIST_FOREACH_DATA(route, module->routes, state)
dm_list_push_back(copy->routes, config_route_dup(route, copy->ports));
return copy;
}
dm_config_device *dm_config_dup(const dm_config_device *config) {
dm_config_device *copy;
dm_config_module *module;
void *state;
pa_assert(config);
copy = pa_xnew0(dm_config_device, 1);
copy->global_config = dm_list_new();
copy->modules = dm_list_new();
if (config->global_config) {
dm_config_global *global, *global_copy;
DM_LIST_FOREACH_DATA(global, config->global_config, state) {
global_copy = pa_xnew0(dm_config_global, 1);
global_copy->key = pa_xstrdup(global->key);
global_copy->value = pa_xstrdup(global->value);
dm_list_push_back(copy->global_config, global_copy);
}
}
DM_LIST_FOREACH_DATA(module, config->modules, state)
dm_list_push_back(copy->modules, config_module_dup(module));
return copy;
}
dm_config_device *pa_parse_droid_audio_config(const char *filename) {
return pa_parse_droid_audio_config_xml(filename);
}
static void config_global_free(void *data) {
dm_config_global *global = data;
pa_xfree(global->key);
pa_xfree(global->value);
pa_xfree(global);
}
static void config_profile_free(void *data) {
dm_config_profile *profile = data;
pa_xfree(profile->name);
pa_xfree(profile);
}
static void config_port_free(void *data) {
dm_config_port *port = data;
pa_xfree(port->name);
pa_xfree(port->address);
dm_list_free(port->profiles, config_profile_free);
pa_xfree(port);
}
static void config_route_free(void *data) {
dm_config_route *route = data;
dm_list_free(route->sources, NULL);
pa_xfree(route);
}
static void config_module_free(void *data) {
dm_config_module *module = data;
pa_xfree(module->name);
dm_list_free(module->attached_devices, NULL);
dm_list_free(module->ports, config_port_free);
dm_list_free(module->device_ports, NULL);
dm_list_free(module->mix_ports, NULL);
dm_list_free(module->routes, config_route_free);
pa_xfree(module);
}
void dm_config_free(dm_config_device *config) {
if (!config)
return;
dm_list_free(config->global_config, config_global_free);
dm_list_free(config->modules, config_module_free);
pa_xfree(config);
}
dm_config_module *dm_config_find_module(dm_config_device *config, const char* module_id) {
dm_config_module *module;
void *state;
pa_assert(config);
pa_assert(module_id);
DM_LIST_FOREACH_DATA(module, config->modules, state) {
if (pa_streq(module_id, module->name))
return module;
}
return NULL;
}
dm_config_port *dm_config_find_port(dm_config_module *module, const char* name) {
dm_config_port *port;
void *state;
pa_assert(module);
pa_assert(name);
DM_LIST_FOREACH_DATA(port, module->ports, state) {
if (pa_streq(name, port->name))
return port;
}
return NULL;
}
dm_config_port *dm_config_default_output_device(dm_config_module *module) {
pa_assert(module);
if (module->default_output_device)
return module->default_output_device;
else {
pa_log("Module %s doesn't have default output device.", module->name);
return 0;
}
}
char *dm_config_escape_string(const char *string) {
if (!string)
return NULL;
/* Just replace whitespace with underscores for now. */
return pa_replace(string, " ", "_");
}
dm_config_port *dm_config_find_device_port(dm_config_port *port, audio_devices_t device) {
dm_config_port *device_port;
void *state;
pa_assert(port);
DM_LIST_FOREACH_DATA(device_port, port->module->device_ports, state) {
if (device_port->type == device)
return device_port;
}
return NULL;
}
bool dm_config_port_equal(const dm_config_port *a, const dm_config_port *b) {
if ((!a && b) || (a && !b))
return false;
else if (!a && !b)
return true;
return (pa_streq(a->name, b->name) && a->type == b->type);
}
dm_config_port *dm_config_find_mix_port(dm_config_module *module, const char *name) {
dm_config_port *mix_port = NULL;
void *state;
DM_LIST_FOREACH_DATA(mix_port, module->mix_ports, state) {
if (pa_streq(mix_port->name, name))
return mix_port;
}
return NULL;
}

View file

@ -1,433 +0,0 @@
/*
* Copyright (C) 2017-2022 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.
*/
#ifndef _DROID_UTIL_AUDIO_H_
#define _DROID_UTIL_AUDIO_H_
#include <android-config.h>
#ifdef QCOM_BSP
#define QCOM_HARDWARE
#endif
#include <hardware/audio.h>
#include <pulse/channelmap.h>
#ifdef STRING_ENTRY
#error Macro clashing with our helper macro already defined somewhere, fix this droid lib.
#endif
struct string_conversion {
uint32_t value;
const char *str;
};
#define STRING_ENTRY(str) { str, #str }
// PulseAudio value - Android value
uint32_t conversion_table_output_channel[][2] = {
{ PA_CHANNEL_POSITION_MONO, AUDIO_CHANNEL_OUT_MONO },
{ PA_CHANNEL_POSITION_FRONT_LEFT, AUDIO_CHANNEL_OUT_FRONT_LEFT },
{ PA_CHANNEL_POSITION_FRONT_RIGHT, AUDIO_CHANNEL_OUT_FRONT_RIGHT },
{ PA_CHANNEL_POSITION_FRONT_CENTER, AUDIO_CHANNEL_OUT_FRONT_CENTER },
{ PA_CHANNEL_POSITION_SUBWOOFER, AUDIO_CHANNEL_OUT_LOW_FREQUENCY },
{ PA_CHANNEL_POSITION_REAR_LEFT, AUDIO_CHANNEL_OUT_BACK_LEFT },
{ PA_CHANNEL_POSITION_REAR_RIGHT, AUDIO_CHANNEL_OUT_BACK_RIGHT },
{ PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER },
{ PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER },
{ PA_CHANNEL_POSITION_REAR_CENTER, AUDIO_CHANNEL_OUT_BACK_CENTER },
{ PA_CHANNEL_POSITION_SIDE_LEFT, AUDIO_CHANNEL_OUT_SIDE_LEFT },
{ PA_CHANNEL_POSITION_SIDE_RIGHT, AUDIO_CHANNEL_OUT_SIDE_RIGHT },
{ PA_CHANNEL_POSITION_TOP_CENTER, AUDIO_CHANNEL_OUT_TOP_CENTER },
{ PA_CHANNEL_POSITION_TOP_FRONT_LEFT, AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT },
{ PA_CHANNEL_POSITION_TOP_FRONT_CENTER, AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER },
{ PA_CHANNEL_POSITION_TOP_FRONT_RIGHT, AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT },
{ PA_CHANNEL_POSITION_TOP_REAR_LEFT, AUDIO_CHANNEL_OUT_TOP_BACK_LEFT },
{ PA_CHANNEL_POSITION_TOP_REAR_CENTER, AUDIO_CHANNEL_OUT_TOP_BACK_CENTER },
{ PA_CHANNEL_POSITION_TOP_REAR_RIGHT, AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT }
};
uint32_t conversion_table_input_channel[][2] = {
{ PA_CHANNEL_POSITION_MONO, AUDIO_CHANNEL_IN_MONO },
{ PA_CHANNEL_POSITION_FRONT_LEFT, AUDIO_CHANNEL_IN_LEFT },
{ PA_CHANNEL_POSITION_FRONT_RIGHT, AUDIO_CHANNEL_IN_RIGHT },
{ PA_CHANNEL_POSITION_FRONT_CENTER, AUDIO_CHANNEL_IN_FRONT },
{ PA_CHANNEL_POSITION_REAR_CENTER, AUDIO_CHANNEL_IN_BACK },
/* Following are missing suitable counterparts on PulseAudio side. */
{ PA_CHANNEL_POSITION_FRONT_LEFT, AUDIO_CHANNEL_IN_LEFT_PROCESSED },
{ PA_CHANNEL_POSITION_FRONT_RIGHT, AUDIO_CHANNEL_IN_RIGHT_PROCESSED },
{ PA_CHANNEL_POSITION_FRONT_CENTER, AUDIO_CHANNEL_IN_FRONT_PROCESSED },
{ PA_CHANNEL_POSITION_REAR_CENTER, AUDIO_CHANNEL_IN_BACK_PROCESSED },
{ PA_CHANNEL_POSITION_SUBWOOFER, AUDIO_CHANNEL_IN_PRESSURE },
{ PA_CHANNEL_POSITION_AUX0, AUDIO_CHANNEL_IN_X_AXIS },
{ PA_CHANNEL_POSITION_AUX1, AUDIO_CHANNEL_IN_Y_AXIS },
{ PA_CHANNEL_POSITION_AUX2, AUDIO_CHANNEL_IN_Z_AXIS },
{ PA_CHANNEL_POSITION_MONO, AUDIO_CHANNEL_IN_VOICE_UPLINK },
{ PA_CHANNEL_POSITION_MONO, AUDIO_CHANNEL_IN_VOICE_DNLINK }
};
uint32_t conversion_table_format[][2] = {
{ PA_SAMPLE_U8, AUDIO_FORMAT_PCM_8_BIT },
{ PA_SAMPLE_S16LE, AUDIO_FORMAT_PCM_16_BIT },
{ PA_SAMPLE_S24_32LE, AUDIO_FORMAT_PCM_8_24_BIT },
{ PA_SAMPLE_S24LE, AUDIO_FORMAT_PCM_24_BIT_PACKED },
{ PA_SAMPLE_S32LE, AUDIO_FORMAT_PCM_32_BIT }
};
uint32_t conversion_table_default_audio_source[][2] = {
{ AUDIO_DEVICE_IN_COMMUNICATION, AUDIO_SOURCE_MIC },
{ AUDIO_DEVICE_IN_AMBIENT, AUDIO_SOURCE_MIC },
{ AUDIO_DEVICE_IN_BUILTIN_MIC, AUDIO_SOURCE_MIC },
{ AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, AUDIO_SOURCE_MIC },
{ AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_SOURCE_MIC },
{ AUDIO_DEVICE_IN_AUX_DIGITAL, AUDIO_SOURCE_MIC },
{ AUDIO_DEVICE_IN_VOICE_CALL, AUDIO_SOURCE_VOICE_CALL },
{ AUDIO_DEVICE_IN_TELEPHONY_RX, AUDIO_SOURCE_VOICE_CALL },
{ AUDIO_DEVICE_IN_BACK_MIC, AUDIO_SOURCE_MIC },
{ AUDIO_DEVICE_IN_REMOTE_SUBMIX, AUDIO_SOURCE_REMOTE_SUBMIX },
{ AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET, AUDIO_SOURCE_MIC },
{ AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET, AUDIO_SOURCE_MIC },
{ AUDIO_DEVICE_IN_USB_ACCESSORY, AUDIO_SOURCE_MIC },
{ AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_SOURCE_MIC },
{ AUDIO_DEVICE_IN_FM_TUNER, AUDIO_SOURCE_FM_TUNER },
{ AUDIO_DEVICE_IN_TV_TUNER, AUDIO_SOURCE_MIC },
{ AUDIO_DEVICE_IN_LINE, AUDIO_SOURCE_MIC },
{ AUDIO_DEVICE_IN_SPDIF, AUDIO_SOURCE_MIC },
{ AUDIO_DEVICE_IN_BLUETOOTH_A2DP, AUDIO_SOURCE_MIC },
{ AUDIO_DEVICE_IN_LOOPBACK, AUDIO_SOURCE_MIC },
{ AUDIO_DEVICE_IN_IP, AUDIO_SOURCE_MIC },
{ AUDIO_DEVICE_IN_BUS, AUDIO_SOURCE_MIC },
{ AUDIO_DEVICE_IN_PROXY, AUDIO_SOURCE_MIC },
{ AUDIO_DEVICE_IN_USB_HEADSET, AUDIO_SOURCE_MIC },
{ AUDIO_DEVICE_IN_BLUETOOTH_BLE, AUDIO_SOURCE_MIC },
{ AUDIO_DEVICE_IN_HDMI_ARC, AUDIO_SOURCE_MIC },
{ AUDIO_DEVICE_IN_ECHO_REFERENCE, AUDIO_SOURCE_MIC },
#if defined(HAVE_ENUM_AUDIO_DEVICE_IN_FM_RX) && defined(HAVE_ENUM_AUDIO_SOURCE_FM_RX)
{ AUDIO_DEVICE_IN_FM_RX, AUDIO_SOURCE_FM_RX },
#endif
#if defined(HAVE_ENUM_AUDIO_DEVICE_IN_FM_RX_A2DP) && defined(HAVE_ENUM_AUDIO_SOURCE_FM_RX_A2DP)
{ AUDIO_DEVICE_IN_FM_RX_A2DP, AUDIO_SOURCE_FM_RX_A2DP },
#endif
};
/* Output devices */
struct string_conversion string_conversion_table_output_device[] = {
/* Each device listed here needs fancy name counterpart
* in string_conversion_table_output_device_fancy. */
STRING_ENTRY( AUDIO_DEVICE_OUT_EARPIECE ),
STRING_ENTRY( AUDIO_DEVICE_OUT_SPEAKER ),
STRING_ENTRY( AUDIO_DEVICE_OUT_WIRED_HEADSET ),
STRING_ENTRY( AUDIO_DEVICE_OUT_WIRED_HEADPHONE ),
STRING_ENTRY( AUDIO_DEVICE_OUT_BLUETOOTH_SCO ),
STRING_ENTRY( AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET ),
STRING_ENTRY( AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT ),
STRING_ENTRY( AUDIO_DEVICE_OUT_BLUETOOTH_A2DP ),
STRING_ENTRY( AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES ),
STRING_ENTRY( AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER ),
STRING_ENTRY( AUDIO_DEVICE_OUT_AUX_DIGITAL ),
STRING_ENTRY( AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET ),
STRING_ENTRY( AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET ),
STRING_ENTRY( AUDIO_DEVICE_OUT_USB_ACCESSORY ),
STRING_ENTRY( AUDIO_DEVICE_OUT_USB_DEVICE ),
STRING_ENTRY( AUDIO_DEVICE_OUT_REMOTE_SUBMIX ),
STRING_ENTRY( AUDIO_DEVICE_OUT_TELEPHONY_TX ),
STRING_ENTRY( AUDIO_DEVICE_OUT_LINE ),
STRING_ENTRY( AUDIO_DEVICE_OUT_HDMI_ARC ),
STRING_ENTRY( AUDIO_DEVICE_OUT_SPDIF ),
STRING_ENTRY( AUDIO_DEVICE_OUT_FM ),
STRING_ENTRY( AUDIO_DEVICE_OUT_AUX_LINE ),
STRING_ENTRY( AUDIO_DEVICE_OUT_SPEAKER_SAFE ),
STRING_ENTRY( AUDIO_DEVICE_OUT_IP ),
STRING_ENTRY( AUDIO_DEVICE_OUT_BUS ),
STRING_ENTRY( AUDIO_DEVICE_OUT_PROXY ),
STRING_ENTRY( AUDIO_DEVICE_OUT_USB_HEADSET ),
STRING_ENTRY( AUDIO_DEVICE_OUT_HEARING_AID ),
STRING_ENTRY( AUDIO_DEVICE_OUT_ECHO_CANCELLER ),
STRING_ENTRY( AUDIO_DEVICE_OUT_DEFAULT ),
{ 0, NULL }
};
struct string_conversion string_conversion_table_audio_mode_fancy[] = {
{ AUDIO_MODE_NORMAL, "normal" },
{ AUDIO_MODE_RINGTONE, "ringtone" },
{ AUDIO_MODE_IN_CALL, "in call" },
{ AUDIO_MODE_IN_COMMUNICATION, "in communication" },
{ AUDIO_MODE_CALL_SCREEN, "call screen" },
{ 0, NULL }
};
struct string_conversion string_conversion_table_output_device_fancy[] = {
{ AUDIO_DEVICE_OUT_EARPIECE, "output-earpiece" },
{ AUDIO_DEVICE_OUT_SPEAKER, "output-speaker" },
{ AUDIO_DEVICE_OUT_WIRED_HEADSET, "output-wired_headset" },
{ AUDIO_DEVICE_OUT_WIRED_HEADPHONE, "output-wired_headphone" },
{ AUDIO_DEVICE_OUT_BLUETOOTH_SCO, "output-bluetooth_sco" },
{ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET, "output-sco_headset" },
{ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT, "output-sco_carkit" },
{ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, "output-a2dp" },
{ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES, "output-a2dp_headphones" },
{ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER, "output-a2dp_speaker" },
{ AUDIO_DEVICE_OUT_AUX_DIGITAL, "output-aux_digital" },
{ AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET, "output-analog_dock_headset" },
{ AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, "output-digital_dock_headset" },
{ AUDIO_DEVICE_OUT_USB_ACCESSORY, "output-usb_accessory" },
{ AUDIO_DEVICE_OUT_USB_DEVICE, "output-usb_device" },
{ AUDIO_DEVICE_OUT_REMOTE_SUBMIX, "output-remote_submix" },
{ AUDIO_DEVICE_OUT_TELEPHONY_TX, "output-telephony_tx" },
{ AUDIO_DEVICE_OUT_LINE, "output-line" },
{ AUDIO_DEVICE_OUT_HDMI_ARC, "output-hdmi_arc" },
{ AUDIO_DEVICE_OUT_SPDIF, "output-spdif" },
{ AUDIO_DEVICE_OUT_FM, "output-fm" },
{ AUDIO_DEVICE_OUT_AUX_LINE, "output-aux_line" },
{ AUDIO_DEVICE_OUT_SPEAKER_SAFE, "output-speaker_safe" },
{ AUDIO_DEVICE_OUT_IP, "output-ip" },
{ AUDIO_DEVICE_OUT_BUS, "output-bus" },
{ AUDIO_DEVICE_OUT_PROXY, "output-proxy" },
{ AUDIO_DEVICE_OUT_USB_HEADSET, "output-usb_headset" },
{ AUDIO_DEVICE_OUT_HEARING_AID, "output-hearing_aid" },
{ AUDIO_DEVICE_OUT_ECHO_CANCELLER, "output-echo_canceller" },
{ AUDIO_DEVICE_OUT_DEFAULT, "output-default" },
{ 0, NULL }
};
/* Input devices */
struct string_conversion string_conversion_table_input_device[] = {
/* Each device listed here needs fancy name counterpart
* in string_conversion_table_input_device_fancy. */
STRING_ENTRY( AUDIO_DEVICE_IN_COMMUNICATION ),
STRING_ENTRY( AUDIO_DEVICE_IN_AMBIENT ),
STRING_ENTRY( AUDIO_DEVICE_IN_BUILTIN_MIC ),
STRING_ENTRY( AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET ),
STRING_ENTRY( AUDIO_DEVICE_IN_WIRED_HEADSET ),
STRING_ENTRY( AUDIO_DEVICE_IN_AUX_DIGITAL ),
STRING_ENTRY( AUDIO_DEVICE_IN_HDMI ), /* Same as AUDIO_DEVICE_IN_AUX_DIGITAL */
STRING_ENTRY( AUDIO_DEVICE_IN_VOICE_CALL ),
STRING_ENTRY( AUDIO_DEVICE_IN_TELEPHONY_RX ), /* Same as AUDIO_DEVICE_IN_VOICE_CALL */
STRING_ENTRY( AUDIO_DEVICE_IN_BACK_MIC ),
STRING_ENTRY( AUDIO_DEVICE_IN_REMOTE_SUBMIX ),
STRING_ENTRY( AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET ),
STRING_ENTRY( AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET ),
STRING_ENTRY( AUDIO_DEVICE_IN_USB_ACCESSORY ),
STRING_ENTRY( AUDIO_DEVICE_IN_USB_DEVICE ),
STRING_ENTRY( AUDIO_DEVICE_IN_FM_TUNER ),
STRING_ENTRY( AUDIO_DEVICE_IN_TV_TUNER ),
STRING_ENTRY( AUDIO_DEVICE_IN_LINE ),
STRING_ENTRY( AUDIO_DEVICE_IN_SPDIF ),
STRING_ENTRY( AUDIO_DEVICE_IN_BLUETOOTH_A2DP ),
STRING_ENTRY( AUDIO_DEVICE_IN_LOOPBACK ),
STRING_ENTRY( AUDIO_DEVICE_IN_IP ),
STRING_ENTRY( AUDIO_DEVICE_IN_BUS ),
STRING_ENTRY( AUDIO_DEVICE_IN_PROXY ),
STRING_ENTRY( AUDIO_DEVICE_IN_USB_HEADSET ),
STRING_ENTRY( AUDIO_DEVICE_IN_BLUETOOTH_BLE ),
STRING_ENTRY( AUDIO_DEVICE_IN_HDMI_ARC ),
STRING_ENTRY( AUDIO_DEVICE_IN_ECHO_REFERENCE ),
STRING_ENTRY( AUDIO_DEVICE_IN_DEFAULT ),
/* Devices which may or may not be defined for all devices. */
STRING_ENTRY_IF_AUDIO_DEVICE_IN_FM_RX
STRING_ENTRY_IF_AUDIO_DEVICE_IN_FM_RX_A2DP
{ 0, NULL }
};
struct string_conversion string_conversion_table_input_device_fancy[] = {
{ AUDIO_DEVICE_IN_COMMUNICATION, "input-communication" },
{ AUDIO_DEVICE_IN_AMBIENT, "input-ambient" },
{ AUDIO_DEVICE_IN_BUILTIN_MIC, "input-builtin_mic" },
{ AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, "input-bluetooth_sco_headset" },
{ AUDIO_DEVICE_IN_WIRED_HEADSET, "input-wired_headset" },
{ AUDIO_DEVICE_IN_AUX_DIGITAL, "input-aux_digital" },
{ AUDIO_DEVICE_IN_VOICE_CALL, "input-voice_call" },
{ AUDIO_DEVICE_IN_TELEPHONY_RX, "input-telephony_rx", },
{ AUDIO_DEVICE_IN_BACK_MIC, "input-back_mic" },
{ AUDIO_DEVICE_IN_REMOTE_SUBMIX, "input-remote_submix" },
{ AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET, "input-analog_dock_headset" },
{ AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET, "input-digital_dock_headset" },
{ AUDIO_DEVICE_IN_USB_ACCESSORY, "input-usb_accessory" },
{ AUDIO_DEVICE_IN_USB_DEVICE, "input-usb_device" },
{ AUDIO_DEVICE_IN_FM_TUNER, "input-fm_tuner" },
{ AUDIO_DEVICE_IN_TV_TUNER, "input-tv_tuner" },
{ AUDIO_DEVICE_IN_LINE, "input-line" },
{ AUDIO_DEVICE_IN_SPDIF, "input-spdif" },
{ AUDIO_DEVICE_IN_BLUETOOTH_A2DP, "input-bluetooth_a2dp" },
{ AUDIO_DEVICE_IN_LOOPBACK, "input-loopback" },
{ AUDIO_DEVICE_IN_IP, "input-ip" },
{ AUDIO_DEVICE_IN_BUS, "input-bus" },
{ AUDIO_DEVICE_IN_PROXY, "input-proxy" },
{ AUDIO_DEVICE_IN_USB_HEADSET, "input-usb_headset" },
{ AUDIO_DEVICE_IN_BLUETOOTH_BLE, "input-bluetooth_ble" },
{ AUDIO_DEVICE_IN_HDMI_ARC, "input-hdmi_arc" },
{ AUDIO_DEVICE_IN_ECHO_REFERENCE, "input-echo_reference" },
{ AUDIO_DEVICE_IN_DEFAULT, "input-default" },
/* Devices which may or may not be defined for all devices. */
FANCY_ENTRY_IF_AUDIO_DEVICE_IN_FM_RX ( "input-fm_rx" )
FANCY_ENTRY_IF_AUDIO_DEVICE_IN_FM_RX_A2DP ( "input-fm_rx_a2dp" )
{ 0, NULL }
};
/* Audio source fancy names */
struct string_conversion string_conversion_table_audio_source_fancy[] = {
{ AUDIO_SOURCE_DEFAULT, "default" },
{ AUDIO_SOURCE_MIC, "mic" },
{ AUDIO_SOURCE_VOICE_UPLINK, "voice uplink" },
{ AUDIO_SOURCE_VOICE_DOWNLINK, "voice downlink" },
{ AUDIO_SOURCE_VOICE_CALL, "voice call" },
{ AUDIO_SOURCE_CAMCORDER, "camcorder" },
{ AUDIO_SOURCE_VOICE_RECOGNITION, "voice recognition" },
{ AUDIO_SOURCE_VOICE_COMMUNICATION, "voice communication" },
{ AUDIO_SOURCE_REMOTE_SUBMIX, "remote submix" },
{ AUDIO_SOURCE_UNPROCESSED, "unprocessed" },
{ AUDIO_SOURCE_VOICE_PERFORMANCE, "voice performance" },
/* Audio sources which may or may not be defined for all devices. */
FANCY_ENTRY_IF_AUDIO_SOURCE_ECHO_REFERENCE ( "echo reference" )
FANCY_ENTRY_IF_AUDIO_SOURCE_FM_TUNER ( "fm tuner" )
FANCY_ENTRY_IF_AUDIO_SOURCE_FM_RX ( "fm rx" )
FANCY_ENTRY_IF_AUDIO_SOURCE_FM_RX_A2DP ( "fm rx a2dp" )
{ (uint32_t)-1, NULL }
};
/* Flags */
struct string_conversion string_conversion_table_output_flag[] = {
STRING_ENTRY( AUDIO_OUTPUT_FLAG_NONE ),
STRING_ENTRY( AUDIO_OUTPUT_FLAG_DIRECT ),
STRING_ENTRY( AUDIO_OUTPUT_FLAG_PRIMARY ),
STRING_ENTRY( AUDIO_OUTPUT_FLAG_FAST ),
STRING_ENTRY( AUDIO_OUTPUT_FLAG_DEEP_BUFFER ),
STRING_ENTRY( AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD ),
STRING_ENTRY( AUDIO_OUTPUT_FLAG_NON_BLOCKING ),
STRING_ENTRY( AUDIO_OUTPUT_FLAG_HW_AV_SYNC ),
STRING_ENTRY( AUDIO_OUTPUT_FLAG_TTS ),
STRING_ENTRY( AUDIO_OUTPUT_FLAG_RAW ),
STRING_ENTRY( AUDIO_OUTPUT_FLAG_SYNC ),
STRING_ENTRY( AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO ),
STRING_ENTRY( AUDIO_OUTPUT_FLAG_DIRECT_PCM ),
STRING_ENTRY( AUDIO_OUTPUT_FLAG_MMAP_NOIRQ ),
STRING_ENTRY( AUDIO_OUTPUT_FLAG_VOIP_RX ),
STRING_ENTRY( AUDIO_OUTPUT_FLAG_INCALL_MUSIC ),
/* Audio output flags which may or may not be defined for all devices. */
STRING_ENTRY_IF_AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH
{ 0, NULL }
};
struct string_conversion string_conversion_table_input_flag[] = {
STRING_ENTRY( AUDIO_INPUT_FLAG_NONE ),
STRING_ENTRY( AUDIO_INPUT_FLAG_FAST ),
STRING_ENTRY( AUDIO_INPUT_FLAG_HW_HOTWORD ),
STRING_ENTRY( AUDIO_INPUT_FLAG_RAW ),
STRING_ENTRY( AUDIO_INPUT_FLAG_SYNC ),
STRING_ENTRY( AUDIO_INPUT_FLAG_MMAP_NOIRQ ),
STRING_ENTRY( AUDIO_INPUT_FLAG_VOIP_TX ),
STRING_ENTRY( AUDIO_INPUT_FLAG_HW_AV_SYNC ),
STRING_ENTRY( AUDIO_INPUT_FLAG_DIRECT ),
{ 0, NULL }
};
/* Channels */
struct string_conversion string_conversion_table_output_channels[] = {
STRING_ENTRY( AUDIO_CHANNEL_OUT_FRONT_LEFT ),
STRING_ENTRY( AUDIO_CHANNEL_OUT_FRONT_RIGHT ),
STRING_ENTRY( AUDIO_CHANNEL_OUT_FRONT_CENTER ),
STRING_ENTRY( AUDIO_CHANNEL_OUT_LOW_FREQUENCY ),
STRING_ENTRY( AUDIO_CHANNEL_OUT_BACK_LEFT ),
STRING_ENTRY( AUDIO_CHANNEL_OUT_BACK_RIGHT ),
STRING_ENTRY( AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER ),
STRING_ENTRY( AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER ),
STRING_ENTRY( AUDIO_CHANNEL_OUT_BACK_CENTER ),
STRING_ENTRY( AUDIO_CHANNEL_OUT_SIDE_LEFT ),
STRING_ENTRY( AUDIO_CHANNEL_OUT_SIDE_RIGHT ),
STRING_ENTRY( AUDIO_CHANNEL_OUT_TOP_CENTER ),
STRING_ENTRY( AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT ),
STRING_ENTRY( AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER ),
STRING_ENTRY( AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT ),
STRING_ENTRY( AUDIO_CHANNEL_OUT_TOP_BACK_LEFT ),
STRING_ENTRY( AUDIO_CHANNEL_OUT_TOP_BACK_CENTER ),
STRING_ENTRY( AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT ),
STRING_ENTRY( AUDIO_CHANNEL_OUT_MONO ),
STRING_ENTRY( AUDIO_CHANNEL_OUT_STEREO ),
STRING_ENTRY( AUDIO_CHANNEL_OUT_QUAD ),
{ 0, NULL }
};
struct string_conversion string_conversion_table_input_channels[] = {
STRING_ENTRY( AUDIO_CHANNEL_IN_LEFT ),
STRING_ENTRY( AUDIO_CHANNEL_IN_RIGHT ),
STRING_ENTRY( AUDIO_CHANNEL_IN_FRONT ),
STRING_ENTRY( AUDIO_CHANNEL_IN_BACK ),
STRING_ENTRY( AUDIO_CHANNEL_IN_LEFT_PROCESSED ),
STRING_ENTRY( AUDIO_CHANNEL_IN_RIGHT_PROCESSED ),
STRING_ENTRY( AUDIO_CHANNEL_IN_FRONT_PROCESSED ),
STRING_ENTRY( AUDIO_CHANNEL_IN_BACK_PROCESSED ),
STRING_ENTRY( AUDIO_CHANNEL_IN_PRESSURE ),
STRING_ENTRY( AUDIO_CHANNEL_IN_X_AXIS ),
STRING_ENTRY( AUDIO_CHANNEL_IN_Y_AXIS ),
STRING_ENTRY( AUDIO_CHANNEL_IN_Z_AXIS ),
STRING_ENTRY( AUDIO_CHANNEL_IN_VOICE_UPLINK ),
STRING_ENTRY( AUDIO_CHANNEL_IN_VOICE_DNLINK ),
STRING_ENTRY( AUDIO_CHANNEL_IN_MONO ),
STRING_ENTRY( AUDIO_CHANNEL_IN_STEREO ),
STRING_ENTRY( AUDIO_CHANNEL_IN_FRONT_BACK ),
STRING_ENTRY_IF_AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO
STRING_ENTRY_IF_AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO
STRING_ENTRY_IF_AUDIO_CHANNEL_IN_VOICE_CALL_MONO
{ 0, NULL }
};
/* Formats */
struct string_conversion string_conversion_table_format[] = {
/* Omit most formats as we aren't usually interested in
* other than the pcm formats anyway. */
STRING_ENTRY( AUDIO_FORMAT_INVALID ),
STRING_ENTRY( AUDIO_FORMAT_DEFAULT ),
STRING_ENTRY( AUDIO_FORMAT_PCM ),
STRING_ENTRY( AUDIO_FORMAT_AMR_NB ),
STRING_ENTRY( AUDIO_FORMAT_AMR_WB ),
STRING_ENTRY( AUDIO_FORMAT_FLAC ),
STRING_ENTRY( AUDIO_FORMAT_MP3 ),
STRING_ENTRY( AUDIO_FORMAT_OPUS ),
STRING_ENTRY( AUDIO_FORMAT_SBC ),
STRING_ENTRY( AUDIO_FORMAT_VORBIS ),
STRING_ENTRY( AUDIO_FORMAT_PCM_16_BIT ),
STRING_ENTRY( AUDIO_FORMAT_PCM_8_BIT ),
STRING_ENTRY( AUDIO_FORMAT_PCM_32_BIT ),
STRING_ENTRY( AUDIO_FORMAT_PCM_8_24_BIT ),
{ 0, NULL }
};
#undef STRING_ENTRY
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,111 +0,0 @@
#ifndef foodroidconversionfoo
#define foodroidconversionfoo
/*
* Copyright (C) 2018-2022 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,
CONV_STRING_AUDIO_SOURCE_FANCY,
} pa_conversion_string_t;
bool pa_string_convert_num_to_str(pa_conversion_string_t type, uint32_t value, const char **to_str);
bool pa_string_convert_str_to_num(pa_conversion_string_t type, const char *str, uint32_t *to_value);
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_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);
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,
uint32_t sampling_rates[AUDIO_MAX_SAMPLING_RATES]);
bool pa_conversion_parse_formats(const char *fn, const unsigned ln,
const char *str,
audio_format_t *formats);
int pa_conversion_parse_output_channels(const char *fn, const unsigned ln,
const char *str,
audio_channel_mask_t channel_masks[AUDIO_MAX_CHANNEL_MASKS]);
int pa_conversion_parse_input_channels(const char *fn, const unsigned ln,
const char *str,
audio_channel_mask_t channel_masks[AUDIO_MAX_CHANNEL_MASKS]);
bool pa_conversion_parse_output_devices(const char *fn, const unsigned ln,
char *str, bool must_recognize_all,
audio_devices_t *devices);
bool pa_conversion_parse_input_devices(const char *fn, const unsigned ln,
char *str, 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

View file

@ -1,135 +0,0 @@
#ifndef foodroidconfigfoo
#define foodroidconfigfoo
/*
* Copyright (C) 2018-2022 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/sllist.h>
#include <droid/version.h>
#define AUDIO_MAX_SAMPLING_RATES (32)
#define AUDIO_MAX_CHANNEL_MASKS (32)
typedef struct dm_config_global dm_config_global;
typedef struct dm_config_port dm_config_port;
typedef struct dm_config_route dm_config_route;
typedef struct dm_config_module dm_config_module;
typedef struct dm_config_device dm_config_device;
typedef struct dm_config_profile dm_config_profile;
struct dm_config_global {
char *key;
char *value;
};
struct dm_config_profile {
char *name;
audio_format_t format; /* 0 -> dynamic TODO check that this is still true */
uint32_t sampling_rates[AUDIO_MAX_SAMPLING_RATES]; /* sampling_rates[0] == 0 -> dynamic, otherwise 0 terminates list */
audio_channel_mask_t channel_masks[AUDIO_MAX_CHANNEL_MASKS]; /* channel_masks[0] == 0 -> dynamic */
};
typedef enum dm_config_role {
DM_CONFIG_ROLE_SINK,
DM_CONFIG_ROLE_SOURCE,
} dm_config_role_t;
typedef enum dm_config_type {
DM_CONFIG_TYPE_MIX,
DM_CONFIG_TYPE_DEVICE_PORT,
DM_CONFIG_TYPE_MIX_PORT,
} dm_config_type_t;
struct dm_config_port {
dm_config_module *module;
/* common values */
dm_config_type_t port_type; /* either mixPort or devicePort */
char *name;
dm_config_role_t role;
dm_list *profiles; /* dm_config_profile* */
/* devicePort specific values */
audio_devices_t type;
char *address;
/* mixPort specific values */
uint32_t flags; /* audio_output_flag_t or audio_input_flag_t */
int max_open_count; /* 0 == not defined */
int max_active_count; /* 0 == not defined */
};
struct dm_config_route {
dm_config_type_t type;
dm_config_port *sink;
dm_list *sources; /* dm_config_port* */
};
struct dm_config_module {
dm_config_device *config;
char *name;
int version_major;
int version_minor;
dm_list *attached_devices; /* dm_config_port* owned by device_ports list below */
dm_config_port *default_output_device; /* owned by device_ports list below */
dm_list *ports; /* dm_config_port* - for convenience port types are filtered to two lists below: */
dm_list *mix_ports; /* dm_config_port* */
dm_list *device_ports; /* dm_config_port* */
dm_list *routes; /* dm_config_route* */
};
struct dm_config_device {
dm_list *global_config; /* dm_config_global* */
dm_list *modules; /* dm_config_module* */
};
/* Config parser */
dm_config_device *dm_config_load(pa_modargs *ma);
dm_config_device *dm_config_dup(const dm_config_device *config);
void dm_config_free(dm_config_device *config);
/* autodetect config type from filename and parse */
dm_config_device *pa_parse_droid_audio_config(const char *filename);
dm_config_module *dm_config_find_module(dm_config_device *config, const char* module_id);
dm_config_port *dm_config_find_port(dm_config_module *module, const char* name);
dm_config_port *dm_config_default_output_device(dm_config_module *module);
dm_config_port *dm_config_find_device_port(dm_config_port *port, audio_devices_t device);
char *dm_config_escape_string(const char *string);
bool dm_config_port_equal(const dm_config_port *a, const dm_config_port *b);
dm_config_port *dm_config_find_mix_port(dm_config_module *module, const char *name);
#endif

View file

@ -1,358 +0,0 @@
#ifndef foodroidutilfoo
#define foodroidutilfoo
/*
* Copyright (C) 2013-2022 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 <pulsecore/modargs.h>
#include <droid/version.h>
#include <droid/droid-config.h>
#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_OUTPUT_VOIP "droid.output.voip"
#define PROP_DROID_INPUT_BUILTIN "droid.input.builtin"
#define PROP_DROID_INPUT_EXTERNAL "droid.input.external"
#define PROP_DROID_INPUT_VOIP "droid.input.voip"
#define EXT_PROP_AUDIO_SOURCE "audio.source"
#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 struct pa_droid_options pa_droid_options;
enum pa_droid_option_type {
DM_OPTION_INPUT_ATOI,
DM_OPTION_CLOSE_INPUT,
DM_OPTION_UNLOAD_NO_CLOSE,
DM_OPTION_HW_VOLUME,
DM_OPTION_REALCALL,
DM_OPTION_UNLOAD_CALL_EXIT,
DM_OPTION_OUTPUT_FAST,
DM_OPTION_OUTPUT_DEEP_BUFFER,
DM_OPTION_AUDIO_CAL_WAIT,
DM_OPTION_SPEAKER_BEFORE_VOICE,
DM_OPTION_OUTPUT_VOIP_RX,
DM_OPTION_RECORD_VOICE_16K,
DM_OPTION_COUNT
};
struct pa_droid_options {
bool enabled[DM_OPTION_COUNT];
};
struct pa_droid_hw_module {
PA_REFCNT_DECLARE;
pa_core *core;
char *shared_name;
dm_config_device *config;
dm_config_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_id;
bool bt_sco_enabled;
pa_idxset *outputs;
pa_idxset *inputs;
pa_hook_slot *sink_put_hook_slot;
pa_hook_slot *sink_unlink_hook_slot;
pa_atomic_t active_outputs;
pa_droid_options options;
/* Mode and input control */
struct _state {
audio_mode_t mode;
} state;
};
struct pa_droid_output_stream {
struct audio_stream_out *stream;
pa_sample_spec sample_spec;
pa_channel_map channel_map;
};
struct pa_droid_input_stream {
struct audio_stream_in *stream;
pa_sample_spec default_sample_spec;
pa_channel_map default_channel_map;
pa_sample_spec sample_spec;
pa_channel_map channel_map;
pa_sample_spec req_sample_spec;
pa_channel_map req_channel_map;
audio_source_t audio_source;
dm_config_port *default_mix_port;
dm_config_port *input_port;
pa_droid_stream *active_input;
uint32_t flags;
uint32_t device;
bool first;
};
struct pa_droid_stream {
PA_REFCNT_DECLARE;
pa_droid_hw_module *module;
dm_config_port *mix_port;
size_t buffer_size;
void *data;
audio_io_handle_t io_handle;
audio_patch_handle_t audio_patch;
const dm_config_port *active_device_port;
pa_droid_output_stream *output;
pa_droid_input_stream *input;
};
struct pa_droid_card_data {
void *userdata;
char *module_id;
};
/* 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 {
dm_config_port *device_port;
} pa_droid_port_data;
typedef struct pa_droid_port {
pa_droid_mapping *mapping;
dm_config_port *device_port;
char *name;
char *description;
unsigned priority;
} pa_droid_port;
struct pa_droid_mapping {
pa_droid_profile_set *profile_set;
dm_config_module *module;
dm_config_port *mix_port;
dm_list *device_ports;
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;
dm_config_module *module;
char *name;
char *description;
unsigned priority;
/* Idxsets contain pa_droid_mapping objects.
* Profile doesn't own the mappings, these
* are references to structs in profile set
* hashmaps. */
pa_idxset *output_mappings;
/* Only one input */
pa_idxset *input_mappings;
pa_droid_mapping *input_mapping;
} pa_droid_profile;
struct pa_droid_profile_set {
dm_config_device *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"
/* 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, dm_config_device *config, const char *module_id);
/* First try to get already open hw module and if none found parse config and options from modargs
* and do initial open. */
pa_droid_hw_module *pa_droid_hw_module_get2(pa_core *core, pa_modargs *ma, 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);
void pa_droid_options_log(pa_droid_hw_module *hw);
static inline bool pa_droid_option(pa_droid_hw_module *hw, enum pa_droid_option_type option) {
return hw && hw->options.enabled[option];
}
bool pa_droid_hw_set_mode(pa_droid_hw_module *hw_module, audio_mode_t mode);
bool pa_droid_hw_has_mic_control(pa_droid_hw_module *hw);
int pa_droid_hw_mic_get_mute(pa_droid_hw_module *hw_module, bool *muted);
void pa_droid_hw_mic_set_mute(pa_droid_hw_module *hw_module, bool muted);
/* Profiles */
pa_droid_profile_set *pa_droid_profile_set_default_new(dm_config_module *module);
void pa_droid_profile_set_free(pa_droid_profile_set *ps);
void pa_droid_profile_free(pa_droid_profile *p);
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);
/* Module operations */
int pa_droid_set_parameters(pa_droid_hw_module *hw, const char *parameters);
pa_droid_stream *pa_droid_hw_primary_output_stream(pa_droid_hw_module *hw);
/* 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,
dm_config_port *mix_port,
dm_config_port *device_port);
/* 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, dm_config_port *device_port);
/* Open input stream with currently active routing, sample_spec and channel_map
* are requests and may change when opening the stream. */
pa_droid_stream *pa_droid_open_input_stream(pa_droid_hw_module *hw_module,
const pa_sample_spec *default_sample_spec,
const pa_channel_map *default_channel_map,
const char *mix_port_name);
/* Test if reconfiguring of input stream is needed */
bool pa_droid_stream_reconfigure_input_needed(pa_droid_stream *s,
const pa_sample_spec *requested_sample_spec,
const pa_channel_map *requested_channel_map,
const pa_proplist *proplist);
bool pa_droid_stream_reconfigure_input(pa_droid_stream *s,
const pa_sample_spec *requested_sample_spec,
const pa_channel_map *requested_channel_map,
const pa_proplist *proplist);
bool pa_droid_hw_set_input_device(pa_droid_stream *s,
dm_config_port *device_port);
const pa_sample_spec *pa_droid_stream_sample_spec(pa_droid_stream *stream);
const pa_channel_map *pa_droid_stream_channel_map(pa_droid_stream *stream);
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);
pa_modargs *pa_droid_modargs_new(const char *args, const char* const keys[]);
/* Misc */
size_t pa_droid_buffer_size_round_up(size_t buffer_size, size_t block_size);
#endif

View file

@ -1,94 +0,0 @@
#ifndef foosllistfoo
#define foosllistfoo
/*
* Copyright (C) 2018-2022 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 <pulse/def.h>
#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)
typedef struct dm_list_entry dm_list_entry;
typedef struct dm_list dm_list;
struct dm_list_entry {
struct dm_list_entry *next;
struct dm_list_entry *prev;
void *data;
};
struct dm_list {
struct dm_list_entry *head;
struct dm_list_entry *tail;
ssize_t size;
};
dm_list *dm_list_new(void);
void dm_list_free(dm_list *list, pa_free_cb_t free_cb);
bool dm_list_remove(dm_list *list, dm_list_entry *entry);
void dm_list_prepend(dm_list *list, void *data);
void dm_list_push_back(dm_list *list, void *data);
dm_list_entry *dm_list_last(dm_list *list);
void *dm_list_steal_first(dm_list *list);
ssize_t dm_list_size(dm_list *list);
void *dm_list_first_data(dm_list *list, void **state);
void *dm_list_next_data(dm_list *list, void **state);
/* For example
* dm_list *list;
* void *state;
* my_data *data;
* DM_LIST_FOREACH_DATA(data, list, state) {
* do_something_with_my(data);
* }
*/
#define DM_LIST_FOREACH_DATA(i, list, state) \
for (i = dm_list_first_data(list, &(state)); state; i = dm_list_next_data(list, &(state)))
/* Access i->data */
#define DM_LIST_FOREACH(i, list) \
for (i = list->head; i; i = i->next)
#endif

View file

@ -1,32 +0,0 @@
#ifndef foodroidcommonutilsfoo
#define foodroidcommonutilsfoo
/*
* Copyright (C) 2022 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
void dm_replace_in_place(char **string, const char *a, const char *b);
bool dm_strcasestr(const char *haystack, const char *needle);
#endif

View file

@ -1,55 +0,0 @@
#ifndef foodroidversionfoo
#define foodroidversionfoo
/*
* Copyright (C) 2018-2022 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.1 */
#define DROID_API_VERSION_SUPPORT HARDWARE_DEVICE_API_VERSION(3, 1)
#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 AUDIO_API_VERSION_MAJ < 3
#error This module only supports audio API version 3 and upwards.
#endif
#endif

View file

@ -1,11 +0,0 @@
prefix=@prefix@
exec_prefix=${prefix}
libdir=@libdir@
includedir=${prefix}/include
libexecdir=@libexecdir@
Name: libdroid-util
Description: Common droid module building interface.
Version: @PA_MODULE_VERSION@
Libs: -L${prefix}/lib/pulse-@PA_MAJORMINOR@/modules -ldroid-util
Cflags: -D_REENTRANT -I${includedir}/pulsecore/modules

View file

@ -1,172 +0,0 @@
/*
* Copyright (C) 2022 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 <pulse/xmalloc.h>
#include <pulsecore/macro.h>
#include "droid/sllist.h"
dm_list *dm_list_new(void) {
return pa_xnew0(dm_list, 1);
}
void dm_list_free(dm_list *list, pa_free_cb_t free_cb) {
pa_assert(list);
while (list->head) {
void *data = dm_list_steal_first(list);
if (free_cb)
free_cb(data);
}
pa_xfree(list);
}
bool dm_list_remove(dm_list *list, dm_list_entry *entry) {
dm_list_entry *i;
bool removed = false;
for (i = list->head; i; i = i->next) {
if (i == entry) {
removed = true;
if (list->head == entry)
list->head = entry->next;
if (list->tail == entry)
list->tail = entry->prev;
if (entry->next)
entry->next->prev = entry->prev;
if (entry->prev)
entry->prev->next = entry->next;
pa_xfree(entry);
break;
}
}
return removed;
}
void dm_list_prepend(dm_list *list, void *data) {
dm_list_entry *entry;
pa_assert(list);
entry = pa_xnew0(dm_list_entry, 1);
entry->data = data;
if (!list->tail)
list->tail = entry;
if (list->head) {
entry->next = list->head;
list->head->prev = entry;
}
list->head = entry;
list->size++;
}
void dm_list_push_back(dm_list *list, void *data) {
dm_list_entry *entry;
pa_assert(list);
entry = pa_xnew0(dm_list_entry, 1);
entry->data = data;
if (!list->head)
list->head = entry;
if (list->tail) {
list->tail->next = entry;
entry->prev = list->tail;
}
list->tail = entry;
list->size++;
}
dm_list_entry *dm_list_last(dm_list *list) {
pa_assert(list);
return list->tail;
}
void *dm_list_steal_first(dm_list *list) {
dm_list_entry *entry;
void *data = NULL;
pa_assert(list);
if (list->head) {
data = list->head->data;
entry = list->head;
if (list->head == list->tail) {
list->head = NULL;
list->tail = NULL;
} else {
list->head->next->prev = NULL;
list->head = list->head->next;
}
pa_xfree(entry);
list->size--;
}
return data;
}
ssize_t dm_list_size(dm_list *list) {
pa_assert(list);
return list->size;
}
/* For iteration */
void *dm_list_first_data(dm_list *list, void **state) {
pa_assert(list);
pa_assert(state);
*state = list->head;
if (list->head)
return list->head->data;
else
return NULL;
}
void *dm_list_next_data(dm_list *list, void **state) {
dm_list_entry *entry;
pa_assert(list);
pa_assert(state);
entry = *state;
*state = entry->next;
if (entry->next)
return entry->next->data;
else
return NULL;
}

View file

@ -1,64 +0,0 @@
/*
* Copyright (C) 2022 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 <string.h>
#include <strings.h>
#include <pulsecore/core-util.h>
#include <pulse/xmalloc.h>
#include "droid/utils.h"
void dm_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;
}
/* Simple strcasestr replacement. */
bool dm_strcasestr(const char *haystack, const char *needle) {
size_t len_haystack, len_needle;
len_haystack = strlen(haystack);
len_needle = strlen(needle);
if (len_needle > len_haystack)
return false;
for (size_t i = 0; i < len_haystack; i++) {
if (len_needle > len_haystack - i)
return false;
if (strncasecmp(haystack + i, needle, len_needle) == 0)
return true;
}
return false;
}

View file

@ -1,45 +1,55 @@
AM_LIBADD = \
$(PULSEAUDIO_LIBS) \
$(HYBRIS_LIBS)
AM_CFLAGS = \
$(DROID_DEVICE_CFLAGS) \
$(PULSEAUDIO_CFLAGS) \
$(DROIDHEADERS_CFLAGS) \
$(HYBRIS_CFLAGS) \
-DPULSEAUDIO_VERSION=@PA_MAJOR@ \
-I$(top_srcdir)/src/droid \
-I$(top_srcdir)/src/common/include
-I$(top_srcdir)/src/droid
modlibexec_LTLIBRARIES = \
libdroid-util.la \
libdroid-sink.la \
libdroid-source.la \
module-droid-keepalive.la \
module-droid-sink.la \
module-droid-source.la \
module-droid-card.la
noinst_HEADERS = module-droid-sink-symdef.h module-droid-source-symdef.h module-droid-card-symdef.h module-droid-keepalive-symdef.h
module_droid_keepalive_la_SOURCES = keepalive.c keepalive.h module-droid-keepalive.c
module_droid_keepalive_la_LDFLAGS = -module -avoid-version -Wl,-no-undefined -Wl,-z,noexecstack
module_droid_keepalive_la_LIBADD = $(AM_LIBADD) $(DBUS_LIBS)
module_droid_keepalive_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS)
libdroid_util_la_SOURCES = droid-util.c droid-util.h
libdroid_util_la_LDFLAGS = -avoid-version -Wl,-no-undefined -Wl,-z,noexecstack -lhybris-common
libdroid_util_la_LIBADD = $(AM_LIBADD)
libdroid_util_la_CFLAGS = $(AM_CFLAGS)
libdroid_sink_la_SOURCES = droid-sink.c droid-sink.h
libdroid_sink_la_LDFLAGS = -avoid-version -Wl,-z,noexecstack -lhybris-common
libdroid_sink_la_LIBADD = $(top_builddir)/src/common/libdroid-util.la $(AM_LIBADD)
libdroid_sink_la_LDFLAGS = -avoid-version -Wl,-no-undefined -Wl,-z,noexecstack -lhybris-common
libdroid_sink_la_LIBADD = $(AM_LIBADD) libdroid-util.la
libdroid_sink_la_CFLAGS = $(AM_CFLAGS)
libdroid_source_la_SOURCES = droid-source.c droid-source.h
libdroid_source_la_LDFLAGS = -avoid-version -Wl,-z,noexecstack -lhybris-common
libdroid_source_la_LIBADD = $(top_builddir)/src/common/libdroid-util.la $(AM_LIBADD)
libdroid_source_la_LDFLAGS = -avoid-version -Wl,-no-undefined -Wl,-z,noexecstack -lhybris-common
libdroid_source_la_LIBADD = $(AM_LIBADD) libdroid-util.la
libdroid_source_la_CFLAGS = $(AM_CFLAGS)
module_droid_sink_la_SOURCES = module-droid-sink.c
module_droid_sink_la_LDFLAGS = -module -avoid-version -Wl,-z,noexecstack -lhybris-common
module_droid_sink_la_LIBADD = -lm libdroid-sink.la $(AM_LIBADD)
module_droid_sink_la_CFLAGS = $(AM_CFLAGS) -DPA_MODULE_NAME=module_droid_sink
module_droid_sink_la_LDFLAGS = -module -avoid-version -Wl,-no-undefined -Wl,-z,noexecstack -lhybris-common
module_droid_sink_la_LIBADD = $(AM_LIBADD) -lm libdroid-util.la libdroid-sink.la
module_droid_sink_la_CFLAGS = $(AM_CFLAGS)
module_droid_source_la_SOURCES = module-droid-source.c
module_droid_source_la_LDFLAGS = -module -avoid-version -Wl,-z,noexecstack -lhybris-common
module_droid_source_la_LIBADD = -lm libdroid-source.la $(AM_LIBADD)
module_droid_source_la_CFLAGS = $(AM_CFLAGS) -DPA_MODULE_NAME=module_droid_source
module_droid_source_la_LDFLAGS = -module -avoid-version -Wl,-no-undefined -Wl,-z,noexecstack -lhybris-common
module_droid_source_la_LIBADD = $(AM_LIBADD) -lm libdroid-util.la libdroid-source.la
module_droid_source_la_CFLAGS = $(AM_CFLAGS)
module_droid_card_la_SOURCES = module-droid-card.c droid-extcon.c droid-extevdev.c
module_droid_card_la_LDFLAGS = -module -avoid-version -Wl,-z,noexecstack -lhybris-common -ludev
module_droid_card_la_LIBADD = -lm libdroid-sink.la libdroid-source.la $(top_builddir)/src/common/libdroid-util.la $(AM_LIBADD) $(EVDEV_LIBS)
module_droid_card_la_CFLAGS = $(AM_CFLAGS) $(EVDEV_CFLAGS) -DPA_MODULE_NAME=module_droid_card
module_droid_card_la_SOURCES = module-droid-card.c
module_droid_card_la_LDFLAGS = -module -avoid-version -Wl,-no-undefined -Wl,-z,noexecstack -lhybris-common
module_droid_card_la_LIBADD = $(AM_LIBADD) -lm libdroid-util.la libdroid-sink.la libdroid-source.la
module_droid_card_la_CFLAGS = $(AM_CFLAGS)

View file

@ -1,269 +0,0 @@
/***
This file is part of PulseAudio.
Copyright (C) 2013 Canonical Ltd.
Contact: David Henningsson
Ricardo Salveti de Araujo <ricardo.salveti@canonical.com>
PulseAudio is 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; either version 2.1 of the License,
or (at your option) any later version.
PulseAudio 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
General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with PulseAudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <pulsecore/core-util.h>
#include <pulsecore/device-port.h>
#include <pulsecore/i18n.h>
#include <libudev.h>
#include "droid-extcon.h"
/* For android */
#define EXTCON_NAME "switch"
/* TODO: Backport stuff to 4.0, remove before upstreaming */
#ifndef PA_PORT_AVAILABLE_YES
#define PA_PORT_AVAILABLE_YES PA_AVAILABLE_YES
#define PA_PORT_AVAILABLE_NO PA_AVAILABLE_NO
#define PA_PORT_AVAILABLE_UNKNOWN PA_AVAILABLE_UNKNOWN
#define pa_port_available_t pa_available_t
#endif
static pa_port_available_t hponly_avail(int state)
{
return (state & 2) ? PA_PORT_AVAILABLE_YES : PA_PORT_AVAILABLE_NO;
}
static pa_port_available_t hsmic_avail(int state)
{
return (state & 1) ? PA_PORT_AVAILABLE_YES : PA_PORT_AVAILABLE_NO;
}
struct droid_switch {
char *name;
uint32_t current_value;
};
static void droid_switch_free(struct droid_switch *as) {
if (!as)
return;
pa_xfree(as->name);
pa_xfree(as);
}
static struct droid_switch *droid_switch_new(const char *name) {
struct droid_switch *as = NULL;
char *filename = pa_sprintf_malloc("/sys/class/%s/%s/state", EXTCON_NAME, name);
char *state = pa_read_line_from_file(filename);
if (state == NULL) {
pa_log_debug("Cannot open '%s'. Skipping.", filename);
pa_xfree(filename);
return NULL;
}
pa_xfree(filename);
as = pa_xnew0(struct droid_switch, 1);
as->name = pa_xstrdup(name);
if (pa_atou(state, &as->current_value) < 0) {
pa_log_warn("Switch '%s' has invalid value '%s'", name, state);
pa_xfree(state);
droid_switch_free(as);
return NULL;
}
pa_log_debug("Switch '%s' opened with value '%s'", name, state);
return as;
}
struct udev_data {
struct udev *udev;
struct udev_monitor *monitor;
pa_io_event *event;
};
struct pa_droid_extcon {
pa_card *card;
struct droid_switch *h2w;
struct udev_data udev;
};
static struct droid_switch *find_matching_switch(pa_droid_extcon *u,
const char *devpath) {
if (pa_streq(devpath, "/devices/virtual/" EXTCON_NAME "/h2w"))
return u->h2w; /* To be extended if we ever support more switches */
return NULL;
}
static void notify_ports(pa_droid_extcon *u, struct droid_switch *as) {
pa_device_port *p;
void *state;
pa_assert(as == u->h2w); /* To be extended if we ever support more switches */
pa_log_debug("Value of switch %s is now %d.", as->name, as->current_value);
PA_HASHMAP_FOREACH(p, u->card->ports, state) {
if (p->direction == PA_DIRECTION_OUTPUT) {
if (!strcmp(p->name, "output-wired_headset"))
pa_device_port_set_available(p, hsmic_avail(as->current_value));
if (!strcmp(p->name, "output-wired_headphone"))
pa_device_port_set_available(p, hponly_avail(as->current_value));
}
if (p->direction == PA_DIRECTION_INPUT) {
if (!strcmp(p->name, "input-wired_headset"))
pa_device_port_set_available(p, hsmic_avail(as->current_value));
}
}
}
static void udev_cb(pa_mainloop_api *a, pa_io_event *e, int fd,
pa_io_event_flags_t events, void *userdata) {
pa_droid_extcon *u = userdata;
struct udev_device *d = udev_monitor_receive_device(u->udev.monitor);
struct udev_list_entry *entry;
struct droid_switch *as;
const char *devpath, *state;
if (!d) {
pa_log("udev_monitor_receive_device failed.");
pa_assert(a);
a->io_free(u->udev.event);
u->udev.event = NULL;
return;
}
devpath = udev_device_get_devpath(d);
if (!devpath) {
pa_log("udev_device_get_devpath failed.");
goto out;
}
pa_log_debug("Got uevent with devpath=%s", devpath);
as = find_matching_switch(u, devpath);
if (!as)
goto out;
entry = udev_list_entry_get_by_name(
udev_device_get_properties_list_entry(d), "SWITCH_STATE");
if (!entry) {
pa_log("udev_list_entry_get_by_name failed to find 'SWITCH_STATE' entry.");
goto out;
}
state = udev_list_entry_get_value(entry);
if (!state) {
pa_log("udev_list_entry_get_by_name failed.");
goto out;
}
if (pa_atou(state, &as->current_value) < 0) {
pa_log_warn("Switch '%s' has invalid value '%s'", as->name, state);
goto out;
}
notify_ports(u, as);
out:
udev_device_unref(d);
}
static bool init_udev(pa_droid_extcon *u, pa_core *core) {
int fd;
u->udev.udev = udev_new();
if (!u->udev.udev) {
pa_log("udev_new failed.");
return false;
}
u->udev.monitor = udev_monitor_new_from_netlink(u->udev.udev, "udev");
if (!u->udev.monitor) {
pa_log("udev_monitor_new_from_netlink failed.");
return false;
}
if (udev_monitor_filter_add_match_subsystem_devtype(u->udev.monitor, EXTCON_NAME, NULL) < 0) {
pa_log("udev_monitor_filter_add_match_subsystem_devtype failed.");
return false;
}
if (udev_monitor_enable_receiving(u->udev.monitor) < 0) {
pa_log("udev_monitor_enable_receiving failed.");
return false;
}
fd = udev_monitor_get_fd(u->udev.monitor);
if (fd < 0) {
pa_log("udev_monitor_get_fd failed");
return false;
}
pa_assert_se(u->udev.event = core->mainloop->io_new(core->mainloop, fd,
PA_IO_EVENT_INPUT, udev_cb, u));
return true;
}
pa_droid_extcon *pa_droid_extcon_new(pa_core *core, pa_card *card) {
pa_droid_extcon *u = pa_xnew0(pa_droid_extcon, 1);
pa_assert(core);
pa_assert(card);
u->card = card;
u->h2w = droid_switch_new("h2w");
if (!u->h2w)
goto fail;
if (!init_udev(u, core))
goto fail;
notify_ports(u, u->h2w);
return u;
fail:
pa_droid_extcon_free(u);
return NULL;
}
void pa_droid_extcon_free(pa_droid_extcon *u) {
pa_assert(u);
if (u->udev.event)
u->card->core->mainloop->io_free(u->udev.event);
if (u->udev.monitor)
udev_monitor_unref(u->udev.monitor);
if (u->udev.udev)
udev_unref(u->udev.udev);
if (u->h2w)
droid_switch_free(u->h2w);
pa_xfree(u);
}

View file

@ -1,32 +0,0 @@
#ifndef foodroidextconhfoo
#define foodroidextconhfoo
/***
This file is part of PulseAudio.
Copyright (C) 2013 Canonical Ltd.
Contact: David Henningsson
PulseAudio is 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; either version 2.1 of the License,
or (at your option) any later version.
PulseAudio 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
General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with PulseAudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
typedef struct pa_droid_extcon pa_droid_extcon;
pa_droid_extcon *pa_droid_extcon_new(pa_core *, pa_card *);
void pa_droid_extcon_free(pa_droid_extcon *);
#endif

View file

@ -1,278 +0,0 @@
/***
This file is part of PulseAudio.
Copyright (C) 2019 UBports foundation.
Author(s): Ratchanan Srirattanamet <ratchanan@ubports.com>
PulseAudio is 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; either version 2.1 of the License,
or (at your option) any later version.
PulseAudio 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
General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with PulseAudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
#define _GNU_SOURCE // For scandir and versionsort
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <dirent.h>
#include <fcntl.h>
#include <errno.h>
#include <libevdev/libevdev.h>
#include <pulsecore/core-util.h>
#include <pulsecore/device-port.h>
#include "droid-extevdev.h"
#define DEV_INPUT_EVENT "/dev/input"
#define EVENT_DEV_NAME "event"
#define N_ELEMENTS(X) (sizeof(X)/sizeof(*(X)))
struct pa_droid_extevdev {
pa_card *card;
struct libevdev *evdev_dev;
pa_io_event *event;
/* Switch values */
bool sw_headphone_insert : 1;
bool sw_microphone_insert : 1;
bool sw_lineout_insert : 1;
};
static int is_event_device(const struct dirent *dir) {
return strncmp(EVENT_DEV_NAME, dir->d_name, 5) == 0;
}
static struct libevdev *find_switch_evdev(void) {
struct dirent **namelist;
int ndev, i;
struct libevdev *ret = NULL;
ndev = scandir(DEV_INPUT_EVENT, &namelist, is_event_device, versionsort);
for (i=0; i<ndev; i++) {
char fname[PATH_MAX];
int fd;
struct libevdev *dev;
int err;
snprintf(fname, sizeof(fname),
"%s/%s", DEV_INPUT_EVENT, namelist[i]->d_name);
pa_log_debug("Checking %s for headphone switch.", fname);
fd = open(fname, O_RDONLY|O_NONBLOCK);
if (fd < 0) {
err = errno;
pa_log_warn("Unable to open device %s, ignored: %s",
fname, strerror(err));
continue;
}
if ((err = libevdev_new_from_fd(fd, &dev)) < 0) {
err = -err;
pa_log_warn("Unable to create libevdev device for %s, ignored: %s",
fname, strerror(err));
close(fd);
continue;
}
if (libevdev_has_event_code(dev, EV_SW, SW_HEADPHONE_INSERT)) {
ret = dev;
break;
}
libevdev_free(dev);
close(fd);
}
for (i=0; i<ndev; i++)
free(namelist[i]);
free(namelist);
return ret;
}
/* Put the port we want to be active (for each direction) later in the list.
* module-switch-on-port-available will switch to the available port as it
* become available, so the last port available will stay active. */
static const char *headphone_ports[] = {
"output-speaker+wired_headphone",
"output-wired_headphone",
};
static const char *headset_ports[] = {
"output-wired_headset",
"input-wired_headset",
};
static void notify_ports(pa_droid_extevdev *u) {
unsigned int i;
pa_log_debug("headphone: %d, microphone: %d, lineout: %d, yes: %d, no: %d", u->sw_headphone_insert,
u->sw_microphone_insert, u->sw_lineout_insert, PA_AVAILABLE_YES, PA_AVAILABLE_NO);
pa_available_t has_headphone =
((u->sw_headphone_insert || u->sw_lineout_insert)
&& !u->sw_microphone_insert) ? PA_AVAILABLE_YES : PA_AVAILABLE_NO;
pa_log_debug("has_headphone: %d", has_headphone);
for (i=0; i < N_ELEMENTS(headphone_ports); i++) {
pa_device_port *p = pa_hashmap_get(u->card->ports, headphone_ports[i]);
pa_log_debug("headphone device port %d, %p", i, p);
if (p)
pa_device_port_set_available(p, has_headphone);
}
pa_available_t has_headset =
((u->sw_headphone_insert || u->sw_lineout_insert)
&& u->sw_microphone_insert) ? PA_AVAILABLE_YES : PA_AVAILABLE_NO;
pa_log_debug("has_headset: %d", has_headset);
for (i=0; i < N_ELEMENTS(headset_ports); i++) {
pa_device_port *p = pa_hashmap_get(u->card->ports, headset_ports[i]);
if (p)
pa_device_port_set_available(p, has_headset);
}
}
/* Called from IO context */
static void evdev_cb(pa_mainloop_api *a, pa_io_event *e, int fd,
pa_io_event_flags_t events, void *userdata) {
pa_droid_extevdev *u = userdata;
unsigned int flags = LIBEVDEV_READ_FLAG_NORMAL;
int err;
struct input_event ev;
pa_log_debug("EV callback start...");
while (1) {
err = libevdev_next_event(u->evdev_dev, flags, &ev);
if (err == -EAGAIN) {
if (flags == LIBEVDEV_READ_FLAG_SYNC) {
/* Switch the flag back to read next normal events. */
flags = LIBEVDEV_READ_FLAG_NORMAL;
continue;
} else {
/* We run out of event. */
break;
}
} else if (err == LIBEVDEV_READ_STATUS_SYNC) {
if (flags == LIBEVDEV_READ_FLAG_NORMAL) {
/* Handle dropped events by switching to SYNC mode. */
flags = LIBEVDEV_READ_FLAG_SYNC;
continue;
} /* Otherwise we're in the middle of handling it. */
} else if (err < 0) {
pa_log_error("Error in reading the event from evdev: %s",
strerror(-err));
/* TODO: Should we just remove the event source? */
break;
}
/* ev now contains the current event. */
if (ev.type == EV_SW) {
switch (ev.code) {
case SW_HEADPHONE_INSERT:
pa_log_debug("Headphone Insert %d", ev.value);
u->sw_headphone_insert = ev.value;
break;
case SW_MICROPHONE_INSERT:
pa_log_debug("Microphone Insert %d", ev.value);
u->sw_microphone_insert = ev.value;
break;
case SW_LINEOUT_INSERT:
pa_log_debug("Lineout Insert %d", ev.value);
u->sw_lineout_insert = ev.value;
break;
default:
pa_log_debug("Unknown switch %d", ev.code);
/* Ignore unknown switch. */
break;
}
} else if (ev.type == EV_SYN && ev.code == SYN_REPORT) {
pa_log_debug("SYN Report");
notify_ports(u);
}
}
pa_log_debug("EV callback end.");
}
static void read_initial_switch_values(pa_droid_extevdev *u) {
/* A local variable is needed because sw_* are bitfields. */
int value;
#define INIT_SW(code, sw_var) \
if (libevdev_fetch_event_value(u->evdev_dev, EV_SW, code, &value)) \
u->sw_var = value; \
else \
u->sw_var = false;
INIT_SW(SW_HEADPHONE_INSERT, sw_headphone_insert)
INIT_SW(SW_MICROPHONE_INSERT, sw_microphone_insert)
INIT_SW(SW_LINEOUT_INSERT, sw_lineout_insert)
#undef INIT_SW
notify_ports(u);
}
pa_droid_extevdev *pa_droid_extevdev_new(pa_core *core, pa_card *card) {
pa_droid_extevdev *u = pa_xnew0(pa_droid_extevdev, 1);
pa_assert(core);
pa_assert(card);
u->card = card;
u->evdev_dev = find_switch_evdev();
if (!u->evdev_dev)
goto fail;
pa_assert_se(u->event = core->mainloop->io_new(core->mainloop,
libevdev_get_fd(u->evdev_dev), PA_IO_EVENT_INPUT, evdev_cb, u));
read_initial_switch_values(u);
return u;
fail:
pa_droid_extevdev_free(u);
return NULL;
}
void pa_droid_extevdev_free(pa_droid_extevdev *u) {
if (u->event)
u->card->core->mainloop->io_free(u->event);
if (u->evdev_dev) {
int fd = libevdev_get_fd(u->evdev_dev);
libevdev_free(u->evdev_dev);
close(fd);
}
pa_xfree(u);
}

View file

@ -1,32 +0,0 @@
#ifndef foodroidextevdevhfoo
#define foodroidextevdevhfoo
/***
This file is part of PulseAudio.
Copyright (C) 2019 UBports foundation.
Author(s): Ratchanan Srirattanamet <ratchanan@ubports.com>
PulseAudio is 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; either version 2.1 of the License,
or (at your option) any later version.
PulseAudio 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
General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with PulseAudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
typedef struct pa_droid_extevdev pa_droid_extevdev;
pa_droid_extevdev *pa_droid_extevdev_new(pa_core *, pa_card *);
void pa_droid_extevdev_free(pa_droid_extevdev *);
#endif

File diff suppressed because it is too large Load diff

View file

@ -2,9 +2,9 @@
#define foodroidsinkfoo
/*
* Copyright (C) 2013-2018 Jolla Ltd.
* Copyright (C) 2013 Jolla Ltd.
*
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
* 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
@ -41,7 +41,7 @@
#include <pulsecore/macro.h>
#include <pulsecore/card.h>
#include <droid/droid-util.h>
#include "droid-util.h"
pa_sink *pa_droid_sink_new(pa_module *m,
pa_modargs *ma,
@ -52,6 +52,6 @@ pa_sink *pa_droid_sink_new(pa_module *m,
pa_card *card);
void pa_droid_sink_free(pa_sink *s);
void pa_droid_sink_set_voice_control(pa_sink* sink, bool enable);
void pa_droid_sink_set_voice_control(pa_sink* sink, pa_bool_t enable);
#endif

View file

@ -1,7 +1,7 @@
/*
* Copyright (C) 2013-2022 Jolla Ltd.
* Copyright (C) 2013 Jolla Ltd.
*
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
* 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
@ -50,13 +50,9 @@
#include <pulsecore/thread-mq.h>
#include <pulsecore/rtpoll.h>
#include <pulsecore/time-smoother.h>
#include <pulsecore/resampler.h>
#include <pulse/util.h>
#include <pulse/version.h>
#include "droid-source.h"
#include <droid/droid-util.h>
#include <droid/conversion.h>
#include "droid-util.h"
struct userdata {
pa_core *core;
@ -69,85 +65,103 @@ struct userdata {
pa_rtpoll *rtpoll;
pa_memchunk memchunk;
audio_devices_t primary_devices;
audio_devices_t enabled_devices;
pa_bool_t routing_changes_enabled;
size_t source_buffer_size;
size_t buffer_size;
pa_usec_t timestamp;
pa_resampler *resampler;
pa_droid_card_data *card_data;
pa_droid_hw_module *hw_module;
pa_droid_stream *stream;
bool stream_valid;
audio_stream_in_t *stream;
};
#define DEFAULT_MODULE_ID "primary"
#define DROID_AUDIO_SOURCE "droid.audio_source"
#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 void source_reconfigure(struct userdata *u,
const pa_sample_spec *reconfigure_sample_spec,
const pa_channel_map *reconfigure_channel_map,
const pa_proplist *proplist,
dm_config_port *update_device_port);
/* Our droid source may be left in a state of not having an input stream
* if reconfiguration fails and fallback to previously active values fails
* as well. In this case just avoid using the stream but don't die. */
#define assert_stream(x, action) if (!x) do { pa_log_warn("Assert " #x " failed."); action; } while(0)
static pa_bool_t do_routing(struct userdata *u, audio_devices_t devices) {
char tmp[32];
char *devlist;
pa_assert(u);
pa_assert(u->stream);
if (!u->routing_changes_enabled) {
pa_log_debug("Skipping routing change.");
return FALSE;
}
if (u->primary_devices == devices)
pa_log_debug("Refresh active device routing.");
u->enabled_devices &= ~u->primary_devices;
u->primary_devices = devices;
u->enabled_devices |= u->primary_devices;
devlist = pa_list_string_input_device(devices);
pa_assert(devlist);
pa_snprintf(tmp, sizeof(tmp), "routing=%u", devices);
pa_log_debug("set_parameters(): %s (%s)", tmp, devlist);
pa_xfree(devlist);
#ifdef DROID_DEVICE_MAKO
#warning Using mako set_parameters hack.
u->card_data->set_parameters(u->card_data, tmp);
#else
u->stream->common.set_parameters(&u->stream->common, tmp);
#endif
return TRUE;
}
static pa_bool_t parse_device_list(const char *str, audio_devices_t *dst) {
pa_assert(str);
pa_assert(dst);
char *dev;
const char *state = NULL;
*dst = 0;
while ((dev = pa_split(str, "|", &state))) {
audio_devices_t d;
if (!pa_string_convert_input_device_str_to_num(dev, &d)) {
pa_log_warn("Unknown device %s", dev);
pa_xfree(dev);
return FALSE;
}
*dst |= d;
pa_xfree(dev);
}
return TRUE;
}
static int thread_read(struct userdata *u) {
void *p;
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);
pa_silence_memory(p, chunk.length, &u->source->sample_spec);
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));
readd = u->stream->read(u->stream, (uint8_t*) p, pa_memblock_get_length(chunk.memblock));
pa_memblock_release(chunk.memblock);
if (readd < 0) {
pa_log("Failed to read from stream. (err %zd)", readd);
pa_log("Failed to read from stream. (err %i)", readd);
goto end;
}
u->timestamp += pa_bytes_to_usec(readd, &u->source->sample_spec);
chunk.index = 0;
chunk.length = readd;
if (u->resampler) {
pa_memchunk rchunk;
pa_resampler_run(u->resampler, &chunk, &rchunk);
if (rchunk.length > 0)
pa_source_post(u->source, &rchunk);
if (rchunk.memblock)
pa_memblock_unref(rchunk.memblock);
goto end;
}
if (chunk.length > 0)
pa_source_post(u->source, &chunk);
@ -161,16 +175,11 @@ static void thread_func(void *userdata) {
struct userdata *u = userdata;
pa_assert(u);
pa_assert(u->stream);
pa_log_debug("Thread starting up.");
if (u->core->realtime_scheduling)
#if PA_CHECK_VERSION(13,0,0)
pa_thread_make_realtime(u->core->realtime_priority);
#else
pa_make_realtime(u->core->realtime_priority);
#endif
pa_thread_mq_install(&u->thread_mq);
@ -187,7 +196,7 @@ static void thread_func(void *userdata) {
pa_rtpoll_set_timer_disabled(u->rtpoll);
/* Sleep */
if ((ret = pa_rtpoll_run(u->rtpoll)) < 0)
if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0)
goto fail;
if (ret == 0)
@ -210,9 +219,9 @@ static int suspend(struct userdata *u) {
int ret;
pa_assert(u);
assert_stream(u->stream, return 0);
pa_assert(u->stream);
ret = pa_droid_stream_suspend(u->stream, true);
ret = u->stream->common.standby(&u->stream->common);
if (ret == 0)
pa_log_info("Device suspended.");
@ -221,61 +230,42 @@ static int suspend(struct userdata *u) {
}
/* Called from IO context */
static void unsuspend(struct userdata *u) {
pa_assert(u);
static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
struct userdata *u = PA_SOURCE(o)->userdata;
if (!u->stream) {
assert_stream(u->stream, u->stream_valid = false);
} else if (pa_droid_stream_suspend(u->stream, false) >= 0) {
u->stream_valid = true;
pa_log_info("Resuming...");
} else
u->stream_valid = false;
}
switch (code) {
case PA_SOURCE_MESSAGE_SET_STATE: {
switch ((pa_source_state_t) PA_PTR_TO_UINT(data)) {
case PA_SOURCE_SUSPENDED: {
int r;
/* Called from IO context */
static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_state, pa_suspend_cause_t new_suspend_cause) {
struct userdata *u;
int r;
pa_assert(PA_SOURCE_IS_OPENED(u->source->thread_info.state));
pa_assert(s);
pa_assert_se(u = s->userdata);
if ((r = suspend(u)) < 0)
return r;
/* It may be that only the suspend cause is changing, in which case there's
* nothing more to do. */
if (new_state == s->thread_info.state)
return 0;
break;
}
switch (new_state) {
case PA_SOURCE_SUSPENDED:
if (PA_SOURCE_IS_OPENED(u->source->thread_info.state)) {
if ((r = suspend(u)) < 0)
return r;
}
case PA_SOURCE_IDLE:
break;
case PA_SOURCE_RUNNING: {
pa_log_info("Resuming...");
u->timestamp = pa_rtclock_now();
break;
}
break;
case PA_SOURCE_IDLE:
/* Fall through */
case PA_SOURCE_RUNNING:
if (u->source->thread_info.state == PA_SOURCE_SUSPENDED) {
unsuspend(u);
u->timestamp = pa_rtclock_now();
/* not needed */
case PA_SOURCE_UNLINKED:
case PA_SOURCE_INIT:
case PA_SOURCE_INVALID_STATE:
;
}
break;
case PA_SOURCE_UNLINKED:
/* Suspending since some implementations do not want to free running stream. */
suspend(u);
break;
/* not needed */
case PA_SOURCE_INIT:
case PA_SOURCE_INVALID_STATE:
break;
}
}
return 0;
return pa_source_process_msg(o, code, data, offset, chunk);
}
static int source_set_port_cb(pa_source *s, pa_device_port *p) {
@ -287,7 +277,7 @@ static int source_set_port_cb(pa_source *s, pa_device_port *p) {
data = PA_DEVICE_PORT_DATA(p);
if (!data->device_port) {
if (!data->device) {
/* If there is no device defined, just return 0 to say everything is ok.
* Then next port change can be whatever source port, even the one enabled
* before parking. */
@ -295,16 +285,14 @@ static int source_set_port_cb(pa_source *s, pa_device_port *p) {
return 0;
}
pa_log_debug("Source set port %#010x (%s)", data->device_port->type, data->device_port->name);
pa_log_debug("Source set port %u", data->device);
if (!PA_SOURCE_IS_OPENED(u->source->state))
pa_droid_stream_set_route(u->stream, data->device_port);
else
source_reconfigure(u, NULL, NULL, NULL, data->device_port);
do_routing(u, data->device);
return 0;
}
static void source_set_name(pa_modargs *ma, pa_source_new_data *data, const char *module_id) {
const char *tmp;
@ -313,7 +301,7 @@ static void source_set_name(pa_modargs *ma, pa_source_new_data *data, const char
if ((tmp = pa_modargs_get_value(ma, "source_name", NULL))) {
pa_source_new_data_set_name(data, tmp);
data->namereg_fail = true;
data->namereg_fail = TRUE;
pa_proplist_sets(data->proplist, PA_PROP_DEVICE_DESCRIPTION, "Droid source");
} else {
char *tt;
@ -321,179 +309,65 @@ static void source_set_name(pa_modargs *ma, pa_source_new_data *data, const char
tt = pa_sprintf_malloc("source.%s", module_id);
pa_source_new_data_set_name(data, tt);
pa_xfree(tt);
data->namereg_fail = false;
data->namereg_fail = FALSE;
pa_proplist_setf(data->proplist, PA_PROP_DEVICE_DESCRIPTION, "Droid source %s", module_id);
}
}
static int source_get_mute_cb(pa_source *s, bool *muted) {
static void source_get_mute_cb(pa_source *s) {
struct userdata *u = s->userdata;
pa_bool_t b;
pa_assert(u);
pa_assert(u->hw_module);
pa_assert(u->hw_module && u->hw_module->device);
return pa_droid_hw_mic_get_mute(u->hw_module, muted);
pa_droid_hw_module_lock(u->hw_module);
if (u->hw_module->device->get_mic_mute(u->hw_module->device, &b) < 0) {
pa_log("Failed to get mute state.");
pa_droid_hw_module_unlock(u->hw_module);
return;
}
pa_droid_hw_module_unlock(u->hw_module);
s->muted = b;
}
static void source_set_mute_cb(pa_source *s) {
struct userdata *u = s->userdata;
pa_assert(u);
pa_assert(u->hw_module && u->hw_module->device);
pa_droid_hw_mic_set_mute(u->hw_module, s->muted);
pa_droid_hw_module_lock(u->hw_module);
if (u->hw_module->device->set_mic_mute(u->hw_module->device, s->muted) < 0)
pa_log("Failed to set mute state to %smuted.", s->muted ? "" : "un");
pa_droid_hw_module_unlock(u->hw_module);
}
static void source_set_mute_control(struct userdata *u) {
pa_assert(u);
pa_assert(u->hw_module && u->hw_module->device);
if (pa_droid_hw_has_mic_control(u->hw_module)) {
if (u->hw_module->device->set_mic_mute) {
pa_log_info("Using hardware mute control for %s", u->source->name);
pa_source_set_get_mute_callback(u->source, source_get_mute_cb);
pa_source_set_set_mute_callback(u->source, source_set_mute_cb);
} else {
pa_log_info("Using software mute control for %s", u->source->name);
pa_source_set_get_mute_callback(u->source, NULL);
pa_source_set_set_mute_callback(u->source, NULL);
}
}
/* Called from main and IO context */
static void update_latency(struct userdata *u) {
pa_assert(u);
pa_assert(u->source);
void pa_droid_source_set_routing(pa_source *s, pa_bool_t enabled) {
struct userdata *u = s->userdata;
if (u->stream)
u->buffer_size = pa_droid_stream_buffer_size(u->stream);
else
u->buffer_size = 1024; /* Random valid value */
pa_assert(s);
pa_assert(s->userdata);
assert_stream(u->stream, return);
if (u->source_buffer_size) {
u->buffer_size = pa_droid_buffer_size_round_up(u->source_buffer_size, u->buffer_size);
pa_log_info("Using buffer size %zu (requested %zu).", u->buffer_size, u->source_buffer_size);
} else
pa_log_info("Using buffer size %zu.", u->buffer_size);
if (pa_thread_mq_get())
pa_source_set_fixed_latency_within_thread(u->source, pa_bytes_to_usec(u->buffer_size, pa_droid_stream_sample_spec(u->stream)));
else
pa_source_set_fixed_latency(u->source, pa_bytes_to_usec(u->buffer_size, pa_droid_stream_sample_spec(u->stream)));
pa_log_debug("Set fixed latency %" PRIu64 " usec", pa_bytes_to_usec(u->buffer_size, pa_droid_stream_sample_spec(u->stream)));
}
static void source_reconfigure(struct userdata *u,
const pa_sample_spec *reconfigure_sample_spec,
const pa_channel_map *reconfigure_channel_map,
const pa_proplist *proplist,
dm_config_port *update_device_port) {
pa_channel_map old_channel_map;
pa_sample_spec old_sample_spec;
pa_channel_map new_channel_map;
pa_sample_spec new_sample_spec;
pa_queue *source_outputs = NULL;
if (pa_source_used_by(u->source)) {
/* If we already have connected source outputs detach those
* so that when re-attaching them to our source resampling etc.
* is renegotiated correctly. */
source_outputs = pa_source_move_all_start(u->source, NULL);
}
pa_source_suspend(u->source, true, PA_SUSPEND_UNAVAILABLE);
old_channel_map = *pa_droid_stream_channel_map(u->stream);
old_sample_spec = *pa_droid_stream_sample_spec(u->stream);
new_channel_map = reconfigure_channel_map ? *reconfigure_channel_map : old_channel_map;
new_sample_spec = reconfigure_sample_spec ? *reconfigure_sample_spec : old_sample_spec;
if (update_device_port)
pa_droid_stream_set_route(u->stream, update_device_port);
if (pa_droid_stream_reconfigure_input(u->stream, &new_sample_spec, &new_channel_map, proplist))
pa_log_info("Source reconfigured.");
else
pa_log_info("Failed to reconfigure input stream, no worries, using defaults.");
/* We need to be really careful here as we are modifying
* quite profound internal structures. */
new_sample_spec = *pa_droid_stream_sample_spec(u->stream);
new_channel_map = *pa_droid_stream_channel_map(u->stream);
u->source->channel_map = new_channel_map;
u->source->sample_spec = new_sample_spec;
pa_assert_se(pa_cvolume_remap(&u->source->reference_volume, &old_channel_map, &new_channel_map));
pa_assert_se(pa_cvolume_remap(&u->source->real_volume, &old_channel_map, &new_channel_map));
pa_assert_se(pa_cvolume_remap(&u->source->soft_volume, &old_channel_map, &new_channel_map));
update_latency(u);
pa_source_suspend(u->source, false, PA_SUSPEND_UNAVAILABLE);
if (source_outputs && u->source) {
pa_source_move_all_finish(u->source, source_outputs, false);
}
}
static pa_hook_result_t source_output_new_hook_callback(void *hook_data,
void *call_data,
void *slot_data) {
pa_source_output_new_data *new_data = call_data;
struct userdata *u = slot_data;
pa_droid_stream *primary_output;
/* Not meant for us */
if (new_data->source != u->source)
return PA_HOOK_OK;
if (!pa_droid_stream_reconfigure_input_needed(u->stream,
&new_data->sample_spec,
&new_data->channel_map,
new_data->proplist))
return PA_HOOK_OK;
pa_log_info("New source-output connecting and our source needs to be reconfigured.");
/* Workaround for fm-radio loopback */
if (pa_safe_streq(pa_proplist_gets(new_data->proplist, "media.name"), "fmradio-loopback-source") &&
(primary_output = pa_droid_hw_primary_output_stream(u->hw_module))) {
pa_log_debug("Workaround for fm-radio loopback.");
source_reconfigure(u,
pa_droid_stream_sample_spec(primary_output),
pa_droid_stream_channel_map(primary_output),
new_data->proplist,
NULL);
} else
source_reconfigure(u, &new_data->sample_spec, &new_data->channel_map, new_data->proplist, NULL);
return PA_HOOK_OK;
}
static void source_reconfigure_after_changes(struct userdata *u) {
pa_source_output *so = NULL;
pa_source_output *so_i;
void *state = NULL;
if (!pa_source_used_by(u->source))
return;
/* Find last inserted source-output */
so = pa_idxset_iterate(u->source->outputs, &state, NULL);
if (so) {
while ((so_i = pa_idxset_iterate(u->source->outputs, &state, NULL)))
so = so_i;
}
if (so && pa_droid_stream_reconfigure_input_needed(u->stream,
&so->sample_spec,
&so->channel_map,
so->proplist)) {
pa_log_info("Source-output disconnected and our source needs to be reconfigured.");
source_reconfigure(u, &so->sample_spec, &so->channel_map, so->proplist, NULL);
}
}
static pa_hook_result_t source_output_unlink_post_hook_callback(void *hook_data,
void *call_data,
void *slot_data) {
source_reconfigure_after_changes(slot_data);
return PA_HOOK_OK;
if (u->routing_changes_enabled != enabled)
pa_log_debug("%s source routing changes.", enabled ? "Enabling" : "Disabling");
u->routing_changes_enabled = enabled;
}
pa_source *pa_droid_source_new(pa_module *m,
@ -507,58 +381,35 @@ pa_source *pa_droid_source_new(pa_module *m,
char *thread_name = NULL;
pa_source_new_data data;
const char *module_id = NULL;
const char *tmp;
uint32_t sample_rate;
uint32_t alternate_sample_rate;
audio_devices_t dev_in;
pa_sample_spec sample_spec;
pa_channel_map channel_map;
const char *format;
bool namereg_fail = false;
pa_bool_t namereg_fail = FALSE;
pa_droid_config_audio *config = NULL; /* Only used when source is created without card */
uint32_t source_buffer = 0;
int ret;
audio_format_t hal_audio_format = 0;
audio_channel_mask_t hal_channel_mask = 0;
pa_assert(m);
pa_assert(ma);
pa_assert(driver);
pa_log_info("Create new droid-source");
/* When running under card use hw module name for source by default. */
if (am)
module_id = am->mix_port->name;
if (card && ma)
module_id = am->input->module->name;
else
module_id = pa_modargs_get_value(ma, "module_id", DEFAULT_MODULE_ID);
sample_spec = m->core->default_sample_spec;
channel_map = m->core->default_channel_map;
/* First parse both sample spec and channel map, then see if source_* override some
* of the values. */
if (pa_modargs_get_sample_spec_and_channel_map(ma, &sample_spec, &channel_map, PA_CHANNEL_MAP_AIFF) < 0) {
pa_log("Failed to parse source sample specification and channel map.");
goto fail;
}
if (pa_modargs_get_value(ma, "source_channel_map", NULL)) {
if (pa_modargs_get_channel_map(ma, "source_channel_map", &channel_map) < 0) {
pa_log("Failed to parse source channel map.");
goto fail;
}
sample_spec.channels = channel_map.channels;
}
if ((format = pa_modargs_get_value(ma, "source_format", NULL))) {
if ((sample_spec.format = pa_parse_sample_format(format)) < 0) {
pa_log("Failed to parse source format.");
goto fail;
}
}
if (pa_modargs_get_value_u32(ma, "source_rate", &sample_spec.rate) < 0) {
pa_log("Failed to parse source_rate.");
goto fail;
}
if (!pa_sample_spec_valid(&sample_spec)) {
pa_log("Sample spec is not valid.");
pa_log("Failed to parse sample specification and channel map.");
goto fail;
}
@ -574,48 +425,116 @@ pa_source *pa_droid_source_new(pa_module *m,
}
u = pa_xnew0(struct userdata, 1);
u->stream_valid = true;
u->core = m->core;
u->module = m;
u->card = card;
u->rtpoll = pa_rtpoll_new();
pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
/* Enabled routing changes by default. */
u->routing_changes_enabled = TRUE;
if (card_data) {
pa_assert(card);
u->card_data = card_data;
pa_assert_se((u->hw_module = pa_droid_hw_module_get(u->core, NULL, card_data->module_id)));
} else {
/* Source wasn't created from inside card module, so we'll need to open
* hw module ourself. */
/* Stand-alone source */
if (!(u->hw_module = pa_droid_hw_module_get2(u->core, ma, 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;
}
u->stream = pa_droid_open_input_stream(u->hw_module, &sample_spec, &channel_map, am->mix_port->name);
if (!pa_convert_format(sample_spec.format, CONV_FROM_PA, &hal_audio_format)) {
pa_log("Sample spec format %u not supported.", sample_spec.format);
goto fail;
}
if (!u->stream) {
for (int i = 0; i < channel_map.channels; i++) {
audio_channel_mask_t c;
if (!pa_convert_input_channel(channel_map.map[i], CONV_FROM_PA, &c)) {
pa_log("Failed to convert channel map.");
goto fail;
}
hal_channel_mask |= c;
}
struct audio_config config_in = {
.sample_rate = sample_spec.rate,
.channel_mask = hal_channel_mask,
.format = hal_audio_format
};
/* Default routing */
/* FIXME So while setting routing through stream with HALv2 API fails, creation of stream
* requires HALv2 style device to work properly. So until that oddity is resolved we always
* set AUDIO_DEVICE_IN_BUILTIN_MIC as initial device here. */
#if 0
pa_assert_se(pa_string_convert_input_device_str_to_num("AUDIO_DEVICE_IN_BUILTIN_MIC", &dev_in));
if ((tmp = pa_modargs_get_value(ma, "input_devices", NULL))) {
audio_devices_t tmp_dev;
if (parse_device_list(tmp, &tmp_dev) && tmp_dev)
dev_in = tmp_dev;
pa_log_debug("Set initial devices %s", tmp);
}
#else
pa_log_info("FIXME: Setting AUDIO_DEVICE_IN_BUILTIN_MIC as initial device.");
dev_in = AUDIO_DEVICE_IN_BUILTIN_MIC;
#endif
dev_in = AUDIO_DEVICE_IN_DEFAULT;
pa_droid_hw_module_lock(u->hw_module);
ret = u->hw_module->device->open_input_stream(u->hw_module->device,
u->hw_module->stream_in_id++,
dev_in,
&config_in,
&u->stream);
pa_droid_hw_module_unlock(u->hw_module);
if (ret < 0) {
pa_log("Failed to open input stream.");
goto fail;
}
if ((sample_rate = u->stream->common.get_sample_rate(&u->stream->common)) != sample_spec.rate) {
pa_log_warn("Requested sample rate %u but got %u instead.", sample_spec.rate, sample_rate);
sample_spec.rate = sample_rate;
}
u->buffer_size = u->stream->common.get_buffer_size(&u->stream->common);
if (source_buffer) {
if (source_buffer < u->buffer_size)
pa_log_warn("Requested buffer size %u less than HAL reported buffer size (%u).", source_buffer, u->buffer_size);
else if (source_buffer % u->buffer_size) {
uint32_t trunc = (source_buffer / u->buffer_size) * u->buffer_size;
pa_log_warn("Requested buffer size %u not multiple of HAL buffer size (%u). Using buffer size %u", source_buffer, u->buffer_size, trunc);
u->buffer_size = trunc;
} else {
pa_log_info("Using requested buffer size %u.", source_buffer);
u->buffer_size = source_buffer;
}
}
pa_log_info("Created Android stream with device: %u sample rate: %u channel mask: %u format: %u buffer size: %u",
dev_in,
sample_rate,
config_in.channel_mask,
config_in.format,
u->buffer_size);
pa_source_new_data_init(&data);
data.driver = driver;
data.module = m;
data.card = card;
/* Start suspended */
data.suspend_cause = PA_SUSPEND_IDLE;
if (am)
source_set_name(ma, &data, am->name);
else
source_set_name(ma, &data, module_id);
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "sound");
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_API, PROP_DROID_API_STRING);
pa_proplist_sets(data.proplist, PROP_DROID_INPUT_EXTERNAL, "true");
pa_proplist_sets(data.proplist, PROP_DROID_INPUT_BUILTIN, "true");
source_set_name(ma, &data, module_id);
/* We need to give pa_modargs_get_value_boolean() a pointer to a local
* variable instead of using &data.namereg_fail directly, because
@ -629,11 +548,11 @@ pa_source *pa_droid_source_new(pa_module *m,
}
data.namereg_fail = namereg_fail;
pa_source_new_data_set_sample_spec(&data, pa_droid_stream_sample_spec(u->stream));
pa_source_new_data_set_channel_map(&data, pa_droid_stream_channel_map(u->stream));
pa_source_new_data_set_sample_spec(&data, &sample_spec);
pa_source_new_data_set_channel_map(&data, &channel_map);
pa_source_new_data_set_alternate_sample_rate(&data, alternate_sample_rate);
if (am && card)
if (am)
pa_droid_add_ports(data.ports, am, card);
u->source = pa_source_new(m->core, &data, PA_SOURCE_HARDWARE);
@ -646,8 +565,7 @@ pa_source *pa_droid_source_new(pa_module *m,
u->source->userdata = u;
u->source->parent.process_msg = pa_source_process_msg;
u->source->set_state_in_io_thread = source_set_state_in_io_thread_cb;
u->source->parent.process_msg = source_process_msg;
source_set_mute_control(u);
@ -667,33 +585,22 @@ pa_source *pa_droid_source_new(pa_module *m,
pa_xfree(thread_name);
thread_name = NULL;
update_latency(u);
pa_source_set_fixed_latency(u->source, pa_bytes_to_usec(u->buffer_size, &sample_spec));
pa_log_debug("Set fixed latency %" PRIu64 " usec", pa_bytes_to_usec(u->buffer_size, &sample_spec));
if (u->source->active_port)
source_set_port_cb(u->source, u->source->active_port);
/* Since we started in suspended mode suspend our stream immediately as well. */
pa_droid_stream_suspend(u->stream, true);
pa_droid_stream_set_data(u->stream, u->source);
pa_source_put(u->source);
/* As late as possible */
pa_module_hook_connect(u->module,
&u->module->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW],
PA_HOOK_LATE * 2,
source_output_new_hook_callback, u);
pa_module_hook_connect(u->module,
&u->module->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK_POST],
PA_HOOK_LATE * 2,
source_output_unlink_post_hook_callback, u);
return u->source;
fail:
pa_xfree(thread_name);
if (config)
pa_xfree(config);
if (u)
userdata_free(u);
@ -710,7 +617,6 @@ void pa_droid_source_free(pa_source *s) {
}
static void userdata_free(struct userdata *u) {
pa_assert(u);
if (u->source)
pa_source_unlink(u->source);
@ -728,9 +634,13 @@ static void userdata_free(struct userdata *u) {
if (u->memchunk.memblock)
pa_memblock_unref(u->memchunk.memblock);
if (u->stream)
pa_droid_stream_unref(u->stream);
if (u->hw_module && u->stream) {
pa_droid_hw_module_lock(u->hw_module);
u->hw_module->device->close_input_stream(u->hw_module->device, u->stream);
pa_droid_hw_module_unlock(u->hw_module);
}
// Stand alone source
if (u->hw_module)
pa_droid_hw_module_unref(u->hw_module);

View file

@ -2,9 +2,9 @@
#define foodroidsourcefoo
/*
* Copyright (C) 2013-2022 Jolla Ltd.
* Copyright (C) 2013 Jolla Ltd.
*
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
* 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
@ -41,7 +41,7 @@
#include <pulsecore/macro.h>
#include <pulsecore/card.h>
#include <droid/droid-util.h>
#include "droid-util.h"
pa_source *pa_droid_source_new(pa_module *m,
pa_modargs *ma,
@ -51,4 +51,6 @@ pa_source *pa_droid_source_new(pa_module *m,
pa_card *card);
void pa_droid_source_free(pa_source *s);
void pa_droid_source_set_routing(pa_source *s, pa_bool_t enabled);
#endif

274
src/droid/droid-util-41qc.h Normal file
View file

@ -0,0 +1,274 @@
/*
* 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.
*/
#ifndef _ANDROID_UTIL_V412_H_
#define _ANDROID_UTIL_V412_H_
// PulseAudio value - Android value
static uint32_t conversion_table_output_channel[][2] = {
{ PA_CHANNEL_POSITION_MONO, AUDIO_CHANNEL_OUT_MONO },
{ PA_CHANNEL_POSITION_FRONT_LEFT, AUDIO_CHANNEL_OUT_FRONT_LEFT },
{ PA_CHANNEL_POSITION_FRONT_RIGHT, AUDIO_CHANNEL_OUT_FRONT_RIGHT},
{ PA_CHANNEL_POSITION_FRONT_CENTER, AUDIO_CHANNEL_OUT_FRONT_CENTER },
{ PA_CHANNEL_POSITION_SUBWOOFER, AUDIO_CHANNEL_OUT_LOW_FREQUENCY },
{ PA_CHANNEL_POSITION_REAR_LEFT, AUDIO_CHANNEL_OUT_BACK_LEFT },
{ PA_CHANNEL_POSITION_REAR_RIGHT, AUDIO_CHANNEL_OUT_BACK_RIGHT },
{ PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER },
{ PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER },
{ PA_CHANNEL_POSITION_REAR_CENTER, AUDIO_CHANNEL_OUT_BACK_CENTER },
{ PA_CHANNEL_POSITION_SIDE_LEFT, AUDIO_CHANNEL_OUT_SIDE_LEFT },
{ PA_CHANNEL_POSITION_SIDE_RIGHT, AUDIO_CHANNEL_OUT_SIDE_RIGHT },
{ PA_CHANNEL_POSITION_TOP_CENTER, AUDIO_CHANNEL_OUT_TOP_CENTER },
{ PA_CHANNEL_POSITION_TOP_FRONT_LEFT, AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT },
{ PA_CHANNEL_POSITION_TOP_FRONT_CENTER, AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER },
{ PA_CHANNEL_POSITION_TOP_FRONT_RIGHT, AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT },
{ PA_CHANNEL_POSITION_TOP_REAR_LEFT, AUDIO_CHANNEL_OUT_TOP_BACK_LEFT },
{ PA_CHANNEL_POSITION_TOP_REAR_CENTER, AUDIO_CHANNEL_OUT_TOP_BACK_CENTER },
{ PA_CHANNEL_POSITION_TOP_REAR_RIGHT, AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT }
};
static uint32_t conversion_table_input_channel[][2] = {
{ PA_CHANNEL_POSITION_MONO, AUDIO_CHANNEL_IN_MONO },
{ PA_CHANNEL_POSITION_FRONT_LEFT, AUDIO_CHANNEL_IN_LEFT },
{ PA_CHANNEL_POSITION_FRONT_RIGHT, AUDIO_CHANNEL_IN_RIGHT},
{ PA_CHANNEL_POSITION_FRONT_CENTER, AUDIO_CHANNEL_IN_FRONT },
{ PA_CHANNEL_POSITION_REAR_CENTER, AUDIO_CHANNEL_IN_BACK },
/* Following are missing suitable counterparts on PulseAudio side. */
{ AUDIO_CHANNEL_IN_LEFT_PROCESSED, AUDIO_CHANNEL_IN_LEFT_PROCESSED },
{ AUDIO_CHANNEL_IN_RIGHT_PROCESSED, AUDIO_CHANNEL_IN_RIGHT_PROCESSED },
{ AUDIO_CHANNEL_IN_FRONT_PROCESSED, AUDIO_CHANNEL_IN_FRONT_PROCESSED },
{ AUDIO_CHANNEL_IN_BACK_PROCESSED, AUDIO_CHANNEL_IN_BACK_PROCESSED },
{ AUDIO_CHANNEL_IN_PRESSURE, AUDIO_CHANNEL_IN_PRESSURE },
{ AUDIO_CHANNEL_IN_X_AXIS, AUDIO_CHANNEL_IN_X_AXIS },
{ AUDIO_CHANNEL_IN_Y_AXIS, AUDIO_CHANNEL_IN_Y_AXIS },
{ AUDIO_CHANNEL_IN_Z_AXIS, AUDIO_CHANNEL_IN_Z_AXIS },
{ AUDIO_CHANNEL_IN_VOICE_UPLINK, AUDIO_CHANNEL_IN_VOICE_UPLINK },
{ AUDIO_CHANNEL_IN_VOICE_DNLINK, AUDIO_CHANNEL_IN_VOICE_DNLINK }
};
static uint32_t conversion_table_format[][2] = {
{ PA_SAMPLE_U8, AUDIO_FORMAT_PCM_8_BIT },
{ PA_SAMPLE_S16LE, AUDIO_FORMAT_PCM_16_BIT },
{ PA_SAMPLE_S32LE, AUDIO_FORMAT_PCM_32_BIT },
{ PA_SAMPLE_S24LE, AUDIO_FORMAT_PCM_8_24_BIT }
};
struct string_conversion {
uint32_t value;
const char *str;
};
#if defined(STRING_ENTRY) || defined(STRING_ENTRY)
#error STRING_ENTRY already defined somewhere, fix this lib.
#endif
#define STRING_ENTRY(str) { str, #str }
/* Output devices */
static struct string_conversion string_conversion_table_output_device[] = {
STRING_ENTRY(AUDIO_DEVICE_OUT_EARPIECE),
STRING_ENTRY(AUDIO_DEVICE_OUT_SPEAKER),
STRING_ENTRY(AUDIO_DEVICE_OUT_WIRED_HEADSET),
STRING_ENTRY(AUDIO_DEVICE_OUT_WIRED_HEADPHONE),
STRING_ENTRY(AUDIO_DEVICE_OUT_BLUETOOTH_SCO),
STRING_ENTRY(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET),
STRING_ENTRY(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT),
STRING_ENTRY(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP),
STRING_ENTRY(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES),
STRING_ENTRY(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),
STRING_ENTRY(AUDIO_DEVICE_OUT_AUX_DIGITAL),
STRING_ENTRY(AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET),
STRING_ENTRY(AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET),
STRING_ENTRY(AUDIO_DEVICE_OUT_USB_ACCESSORY),
STRING_ENTRY(AUDIO_DEVICE_OUT_USB_DEVICE),
STRING_ENTRY(AUDIO_DEVICE_OUT_FM),
STRING_ENTRY(AUDIO_DEVICE_OUT_FM_TX),
STRING_ENTRY(AUDIO_DEVICE_OUT_ANC_HEADSET),
STRING_ENTRY(AUDIO_DEVICE_OUT_ANC_HEADPHONE),
STRING_ENTRY(AUDIO_DEVICE_OUT_PROXY),
STRING_ENTRY(AUDIO_DEVICE_OUT_ALL),
STRING_ENTRY(AUDIO_DEVICE_OUT_ALL_A2DP),
STRING_ENTRY(AUDIO_DEVICE_OUT_ALL_SCO),
STRING_ENTRY(AUDIO_DEVICE_OUT_ALL_USB),
{ 0, NULL }
};
static struct string_conversion string_conversion_table_output_device_fancy[] = {
{ AUDIO_DEVICE_OUT_EARPIECE, "output-earpiece" },
{ AUDIO_DEVICE_OUT_SPEAKER, "output-speaker" },
{ AUDIO_DEVICE_OUT_SPEAKER
| AUDIO_DEVICE_OUT_WIRED_HEADPHONE, "output-speaker+wired_headphone" },
{ AUDIO_DEVICE_OUT_WIRED_HEADSET, "output-wired_headset" },
{ AUDIO_DEVICE_OUT_WIRED_HEADPHONE, "output-wired_headphone" },
{ AUDIO_DEVICE_OUT_BLUETOOTH_SCO, "output-bluetooth_sco" },
{ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET, "output-sco_headset" },
{ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT, "output-sco_carkit" },
{ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, "output-a2dp" },
{ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES, "output-a2dp_headphones" },
{ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER, "output-a2dp_speaker" },
{ AUDIO_DEVICE_OUT_AUX_DIGITAL, "output-aux_digital" },
{ AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET, "output-analog_dock_headset" },
{ AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, "output-digital_dock_headset" },
{ AUDIO_DEVICE_OUT_USB_ACCESSORY, "output-usb_accessory" },
{ AUDIO_DEVICE_OUT_USB_DEVICE, "output-usb_device" },
{ AUDIO_DEVICE_OUT_FM, "output-fm" },
{ AUDIO_DEVICE_OUT_FM_TX, "output-fm_tx" },
{ AUDIO_DEVICE_OUT_ANC_HEADSET, "output-anc_headset" },
{ AUDIO_DEVICE_OUT_ANC_HEADPHONE, "output-anc_headphone" },
{ AUDIO_DEVICE_OUT_PROXY, "output-proxy" },
{ 0, NULL }
};
/* Input devices */
static struct string_conversion string_conversion_table_input_device[] = {
STRING_ENTRY(AUDIO_DEVICE_IN_COMMUNICATION),
STRING_ENTRY(AUDIO_DEVICE_IN_AMBIENT),
STRING_ENTRY(AUDIO_DEVICE_IN_BUILTIN_MIC),
STRING_ENTRY(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET),
STRING_ENTRY(AUDIO_DEVICE_IN_WIRED_HEADSET),
STRING_ENTRY(AUDIO_DEVICE_IN_AUX_DIGITAL),
STRING_ENTRY(AUDIO_DEVICE_IN_VOICE_CALL),
STRING_ENTRY(AUDIO_DEVICE_IN_BACK_MIC),
STRING_ENTRY(AUDIO_DEVICE_IN_ANC_HEADSET),
STRING_ENTRY(AUDIO_DEVICE_IN_FM_RX),
STRING_ENTRY(AUDIO_DEVICE_IN_FM_RX_A2DP),
STRING_ENTRY(AUDIO_DEVICE_IN_PROXY),
{ 0, NULL }
};
static struct string_conversion string_conversion_table_input_device_fancy[] = {
{ AUDIO_DEVICE_IN_COMMUNICATION, "input-in_communication" },
{ AUDIO_DEVICE_IN_AMBIENT, "input-ambient" },
{ AUDIO_DEVICE_IN_BUILTIN_MIC, "input-builtin_mic" },
{ AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, "input-bluetooth_sco_headset" },
{ AUDIO_DEVICE_IN_WIRED_HEADSET, "input-wired_headset" },
{ AUDIO_DEVICE_IN_AUX_DIGITAL, "input-aux_digital" },
{ AUDIO_DEVICE_IN_VOICE_CALL, "input-voice_call" },
{ AUDIO_DEVICE_IN_BACK_MIC, "input-back_mic" },
{ AUDIO_DEVICE_IN_ANC_HEADSET, "input-anc_headset" },
{ AUDIO_DEVICE_IN_FM_RX, "input-fm_rx" },
{ AUDIO_DEVICE_IN_FM_RX_A2DP, "input-fm_rx_a2dp" },
{ AUDIO_DEVICE_IN_PROXY, "input-in_proxy" },
{ 0, NULL }
};
/* Flags */
static struct string_conversion string_conversion_table_flag[] = {
STRING_ENTRY(AUDIO_OUTPUT_FLAG_NONE),
STRING_ENTRY(AUDIO_OUTPUT_FLAG_DIRECT),
STRING_ENTRY(AUDIO_OUTPUT_FLAG_PRIMARY),
STRING_ENTRY(AUDIO_OUTPUT_FLAG_FAST),
STRING_ENTRY(AUDIO_OUTPUT_FLAG_DEEP_BUFFER),
/* Qualcomm flags */
STRING_ENTRY(AUDIO_OUTPUT_FLAG_LPA),
STRING_ENTRY(AUDIO_OUTPUT_FLAG_TUNNEL),
STRING_ENTRY(AUDIO_OUTPUT_FLAG_VOIP_RX),
{ 0, NULL }
};
/* Channels */
static struct string_conversion string_conversion_table_output_channels[] = {
STRING_ENTRY(AUDIO_CHANNEL_OUT_FRONT_LEFT),
STRING_ENTRY(AUDIO_CHANNEL_OUT_FRONT_RIGHT),
STRING_ENTRY(AUDIO_CHANNEL_OUT_FRONT_CENTER),
STRING_ENTRY(AUDIO_CHANNEL_OUT_LOW_FREQUENCY),
STRING_ENTRY(AUDIO_CHANNEL_OUT_BACK_LEFT),
STRING_ENTRY(AUDIO_CHANNEL_OUT_BACK_RIGHT),
STRING_ENTRY(AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER),
STRING_ENTRY(AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER),
STRING_ENTRY(AUDIO_CHANNEL_OUT_BACK_CENTER),
STRING_ENTRY(AUDIO_CHANNEL_OUT_SIDE_LEFT),
STRING_ENTRY(AUDIO_CHANNEL_OUT_SIDE_RIGHT),
STRING_ENTRY(AUDIO_CHANNEL_OUT_TOP_CENTER),
STRING_ENTRY(AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT),
STRING_ENTRY(AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER),
STRING_ENTRY(AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT),
STRING_ENTRY(AUDIO_CHANNEL_OUT_TOP_BACK_LEFT),
STRING_ENTRY(AUDIO_CHANNEL_OUT_TOP_BACK_CENTER),
STRING_ENTRY(AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT),
STRING_ENTRY(AUDIO_CHANNEL_OUT_MONO),
STRING_ENTRY(AUDIO_CHANNEL_OUT_STEREO),
STRING_ENTRY(AUDIO_CHANNEL_OUT_QUAD),
STRING_ENTRY(AUDIO_CHANNEL_OUT_SURROUND),
STRING_ENTRY(AUDIO_CHANNEL_OUT_5POINT1),
STRING_ENTRY(AUDIO_CHANNEL_OUT_7POINT1),
STRING_ENTRY(AUDIO_CHANNEL_OUT_ALL),
{ 0, NULL }
};
static struct string_conversion string_conversion_table_input_channels[] = {
STRING_ENTRY(AUDIO_CHANNEL_IN_LEFT),
STRING_ENTRY(AUDIO_CHANNEL_IN_RIGHT),
STRING_ENTRY(AUDIO_CHANNEL_IN_FRONT),
STRING_ENTRY(AUDIO_CHANNEL_IN_BACK),
STRING_ENTRY(AUDIO_CHANNEL_IN_LEFT_PROCESSED),
STRING_ENTRY(AUDIO_CHANNEL_IN_RIGHT_PROCESSED),
STRING_ENTRY(AUDIO_CHANNEL_IN_FRONT_PROCESSED),
STRING_ENTRY(AUDIO_CHANNEL_IN_BACK_PROCESSED),
STRING_ENTRY(AUDIO_CHANNEL_IN_PRESSURE),
STRING_ENTRY(AUDIO_CHANNEL_IN_X_AXIS),
STRING_ENTRY(AUDIO_CHANNEL_IN_Y_AXIS),
STRING_ENTRY(AUDIO_CHANNEL_IN_Z_AXIS),
STRING_ENTRY(AUDIO_CHANNEL_IN_VOICE_UPLINK),
STRING_ENTRY(AUDIO_CHANNEL_IN_VOICE_DNLINK),
STRING_ENTRY(AUDIO_CHANNEL_IN_MONO),
STRING_ENTRY(AUDIO_CHANNEL_IN_STEREO),
STRING_ENTRY(AUDIO_CHANNEL_IN_5POINT1),
STRING_ENTRY(AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO),
STRING_ENTRY(AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO),
STRING_ENTRY(AUDIO_CHANNEL_IN_VOICE_CALL_MONO),
STRING_ENTRY(AUDIO_CHANNEL_IN_ALL),
{ 0, NULL }
};
/* Formats */
static struct string_conversion string_conversion_table_format[] = {
STRING_ENTRY(AUDIO_FORMAT_DEFAULT),
STRING_ENTRY(AUDIO_FORMAT_PCM),
STRING_ENTRY(AUDIO_FORMAT_MP3),
STRING_ENTRY(AUDIO_FORMAT_AMR_NB),
STRING_ENTRY(AUDIO_FORMAT_AMR_WB),
STRING_ENTRY(AUDIO_FORMAT_AAC),
STRING_ENTRY(AUDIO_FORMAT_HE_AAC_V1),
STRING_ENTRY(AUDIO_FORMAT_HE_AAC_V2),
STRING_ENTRY(AUDIO_FORMAT_VORBIS),
STRING_ENTRY(AUDIO_FORMAT_EVRC),
STRING_ENTRY(AUDIO_FORMAT_QCELP),
STRING_ENTRY(AUDIO_FORMAT_AC3),
STRING_ENTRY(AUDIO_FORMAT_AC3_PLUS),
STRING_ENTRY(AUDIO_FORMAT_DTS),
STRING_ENTRY(AUDIO_FORMAT_WMA),
STRING_ENTRY(AUDIO_FORMAT_WMA_PRO),
STRING_ENTRY(AUDIO_FORMAT_AAC_ADIF),
STRING_ENTRY(AUDIO_FORMAT_EVRCB),
STRING_ENTRY(AUDIO_FORMAT_EVRCWB),
STRING_ENTRY(AUDIO_FORMAT_EAC3),
STRING_ENTRY(AUDIO_FORMAT_DTS_LBR),
STRING_ENTRY(AUDIO_FORMAT_AMR_WB_PLUS),
/* Currently we support only PCM formats, but keep all formats
* here so audio_policy.conf can be parsed. */
STRING_ENTRY(AUDIO_FORMAT_PCM_16_BIT),
STRING_ENTRY(AUDIO_FORMAT_PCM_8_BIT),
STRING_ENTRY(AUDIO_FORMAT_PCM_32_BIT),
STRING_ENTRY(AUDIO_FORMAT_PCM_8_24_BIT),
{ 0, NULL }
};
#undef STRING_ENTRY
#endif

275
src/droid/droid-util-42.h Normal file
View file

@ -0,0 +1,275 @@
/*
* 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.
*/
#ifndef _ANDROID_UTIL_V42_H_
#define _ANDROID_UTIL_V42_H_
#define HAL_V2
// PulseAudio value - Android value
static uint32_t conversion_table_output_channel[][2] = {
{ PA_CHANNEL_POSITION_MONO, AUDIO_CHANNEL_OUT_MONO },
{ PA_CHANNEL_POSITION_FRONT_LEFT, AUDIO_CHANNEL_OUT_FRONT_LEFT },
{ PA_CHANNEL_POSITION_FRONT_RIGHT, AUDIO_CHANNEL_OUT_FRONT_RIGHT},
{ PA_CHANNEL_POSITION_FRONT_CENTER, AUDIO_CHANNEL_OUT_FRONT_CENTER },
{ PA_CHANNEL_POSITION_SUBWOOFER, AUDIO_CHANNEL_OUT_LOW_FREQUENCY },
{ PA_CHANNEL_POSITION_REAR_LEFT, AUDIO_CHANNEL_OUT_BACK_LEFT },
{ PA_CHANNEL_POSITION_REAR_RIGHT, AUDIO_CHANNEL_OUT_BACK_RIGHT },
{ PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER },
{ PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER },
{ PA_CHANNEL_POSITION_REAR_CENTER, AUDIO_CHANNEL_OUT_BACK_CENTER },
{ PA_CHANNEL_POSITION_SIDE_LEFT, AUDIO_CHANNEL_OUT_SIDE_LEFT },
{ PA_CHANNEL_POSITION_SIDE_RIGHT, AUDIO_CHANNEL_OUT_SIDE_RIGHT },
{ PA_CHANNEL_POSITION_TOP_CENTER, AUDIO_CHANNEL_OUT_TOP_CENTER },
{ PA_CHANNEL_POSITION_TOP_FRONT_LEFT, AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT },
{ PA_CHANNEL_POSITION_TOP_FRONT_CENTER, AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER },
{ PA_CHANNEL_POSITION_TOP_FRONT_RIGHT, AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT },
{ PA_CHANNEL_POSITION_TOP_REAR_LEFT, AUDIO_CHANNEL_OUT_TOP_BACK_LEFT },
{ PA_CHANNEL_POSITION_TOP_REAR_CENTER, AUDIO_CHANNEL_OUT_TOP_BACK_CENTER },
{ PA_CHANNEL_POSITION_TOP_REAR_RIGHT, AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT }
};
static uint32_t conversion_table_input_channel[][2] = {
{ PA_CHANNEL_POSITION_MONO, AUDIO_CHANNEL_IN_MONO },
{ PA_CHANNEL_POSITION_FRONT_LEFT, AUDIO_CHANNEL_IN_LEFT },
{ PA_CHANNEL_POSITION_FRONT_RIGHT, AUDIO_CHANNEL_IN_RIGHT},
{ PA_CHANNEL_POSITION_FRONT_CENTER, AUDIO_CHANNEL_IN_FRONT },
{ PA_CHANNEL_POSITION_REAR_CENTER, AUDIO_CHANNEL_IN_BACK },
/* Following are missing suitable counterparts on PulseAudio side. */
{ AUDIO_CHANNEL_IN_LEFT_PROCESSED, AUDIO_CHANNEL_IN_LEFT_PROCESSED },
{ AUDIO_CHANNEL_IN_RIGHT_PROCESSED, AUDIO_CHANNEL_IN_RIGHT_PROCESSED },
{ AUDIO_CHANNEL_IN_FRONT_PROCESSED, AUDIO_CHANNEL_IN_FRONT_PROCESSED },
{ AUDIO_CHANNEL_IN_BACK_PROCESSED, AUDIO_CHANNEL_IN_BACK_PROCESSED },
{ AUDIO_CHANNEL_IN_PRESSURE, AUDIO_CHANNEL_IN_PRESSURE },
{ AUDIO_CHANNEL_IN_X_AXIS, AUDIO_CHANNEL_IN_X_AXIS },
{ AUDIO_CHANNEL_IN_Y_AXIS, AUDIO_CHANNEL_IN_Y_AXIS },
{ AUDIO_CHANNEL_IN_Z_AXIS, AUDIO_CHANNEL_IN_Z_AXIS },
{ AUDIO_CHANNEL_IN_VOICE_UPLINK, AUDIO_CHANNEL_IN_VOICE_UPLINK },
{ AUDIO_CHANNEL_IN_VOICE_DNLINK, AUDIO_CHANNEL_IN_VOICE_DNLINK }
};
static uint32_t conversion_table_format[][2] = {
{ PA_SAMPLE_U8, AUDIO_FORMAT_PCM_8_BIT },
{ PA_SAMPLE_S16LE, AUDIO_FORMAT_PCM_16_BIT },
{ PA_SAMPLE_S32LE, AUDIO_FORMAT_PCM_32_BIT },
{ PA_SAMPLE_S24LE, AUDIO_FORMAT_PCM_8_24_BIT }
};
struct string_conversion {
uint32_t value;
const char *str;
};
#if defined(STRING_ENTRY)
#error STRING_ENTRY already defined somewhere, fix this lib.
#endif
#define STRING_ENTRY(str) { str, #str }
/* Output devices */
static struct string_conversion string_conversion_table_output_device[] = {
STRING_ENTRY(AUDIO_DEVICE_OUT_EARPIECE),
STRING_ENTRY(AUDIO_DEVICE_OUT_SPEAKER),
STRING_ENTRY(AUDIO_DEVICE_OUT_WIRED_HEADSET),
STRING_ENTRY(AUDIO_DEVICE_OUT_WIRED_HEADPHONE),
STRING_ENTRY(AUDIO_DEVICE_OUT_BLUETOOTH_SCO),
STRING_ENTRY(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET),
STRING_ENTRY(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT),
STRING_ENTRY(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP),
STRING_ENTRY(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES),
STRING_ENTRY(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),
STRING_ENTRY(AUDIO_DEVICE_OUT_AUX_DIGITAL),
STRING_ENTRY(AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET),
STRING_ENTRY(AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET),
STRING_ENTRY(AUDIO_DEVICE_OUT_USB_ACCESSORY),
STRING_ENTRY(AUDIO_DEVICE_OUT_USB_DEVICE),
STRING_ENTRY(AUDIO_DEVICE_OUT_REMOTE_SUBMIX),
STRING_ENTRY(AUDIO_DEVICE_OUT_DEFAULT),
STRING_ENTRY(AUDIO_DEVICE_OUT_ALL),
STRING_ENTRY(AUDIO_DEVICE_OUT_ALL_A2DP),
STRING_ENTRY(AUDIO_DEVICE_OUT_ALL_SCO),
STRING_ENTRY(AUDIO_DEVICE_OUT_ALL_USB),
{ 0, NULL }
};
static struct string_conversion string_conversion_table_output_device_fancy[] = {
{ AUDIO_DEVICE_OUT_EARPIECE, "output-earpiece" },
{ AUDIO_DEVICE_OUT_SPEAKER, "output-speaker" },
{ AUDIO_DEVICE_OUT_SPEAKER
| AUDIO_DEVICE_OUT_WIRED_HEADPHONE, "output-speaker+wired_headphone" },
{ AUDIO_DEVICE_OUT_WIRED_HEADSET, "output-wired_headset" },
{ AUDIO_DEVICE_OUT_WIRED_HEADPHONE, "output-wired_headphone" },
{ AUDIO_DEVICE_OUT_BLUETOOTH_SCO, "output-bluetooth_sco" },
{ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET, "output-sco_headset" },
{ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT, "output-sco_carkit" },
{ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, "output-a2dp" },
{ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES, "output-a2dp_headphones" },
{ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER, "output-a2dp_speaker" },
{ AUDIO_DEVICE_OUT_AUX_DIGITAL, "output-aux_digital" },
{ AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET, "output-analog_dock_headset" },
{ AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, "output-digital_dock_headset" },
{ AUDIO_DEVICE_OUT_USB_ACCESSORY, "output-usb_accessory" },
{ AUDIO_DEVICE_OUT_USB_DEVICE, "output-usb_device" },
{ AUDIO_DEVICE_OUT_REMOTE_SUBMIX, "output-remote_submix" },
{ 0, NULL }
};
/* Input devices */
#ifdef DROID_DEVICE_MAKO
static struct string_conversion string_conversion_table_input_device[] = {
{ 0x10000, "AUDIO_DEVICE_IN_COMMUNICATION" },
{ 0x20000, "AUDIO_DEVICE_IN_AMBIENT" },
{ 0x40000, "AUDIO_DEVICE_IN_BUILTIN_MIC" },
{ 0x80000, "AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET" },
{ 0x100000, "AUDIO_DEVICE_IN_WIRED_HEADSET" },
{ 0x200000, "AUDIO_DEVICE_IN_AUX_DIGITAL" },
{ 0x400000, "AUDIO_DEVICE_IN_VOICE_CALL" },
{ 0x800000, "AUDIO_DEVICE_IN_BACK_MIC" },
{ 0x80000000, "AUDIO_DEVICE_IN_DEFAULT" },
{ 0x80000000, "AUDIO_DEVICE_IN_REMOTE_SUBMIX" }, // What's this really??
{ 0, NULL }
};
static struct string_conversion string_conversion_table_input_device_fancy[] = {
{ 0x10000, "input-communication" },
{ 0x20000, "input-ambient" },
{ 0x40000, "input-builtin_mic" },
{ 0x80000, "input-bluetooth_sco_headset" },
{ 0x100000, "input-wired_headset" },
{ 0x200000, "input-aux_digital" },
{ 0x400000, "input-voice_call" },
{ 0x800000, "input-back_mic" },
{ 0x80000000, "input-remote_submix" },
{ 0, NULL }
};
#else
static struct string_conversion string_conversion_table_input_device[] = {
STRING_ENTRY(AUDIO_DEVICE_IN_COMMUNICATION),
STRING_ENTRY(AUDIO_DEVICE_IN_AMBIENT),
STRING_ENTRY(AUDIO_DEVICE_IN_BUILTIN_MIC),
STRING_ENTRY(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET),
STRING_ENTRY(AUDIO_DEVICE_IN_WIRED_HEADSET),
STRING_ENTRY(AUDIO_DEVICE_IN_AUX_DIGITAL),
STRING_ENTRY(AUDIO_DEVICE_IN_VOICE_CALL),
STRING_ENTRY(AUDIO_DEVICE_IN_BACK_MIC),
STRING_ENTRY(AUDIO_DEVICE_IN_REMOTE_SUBMIX),
STRING_ENTRY(AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET),
STRING_ENTRY(AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET),
STRING_ENTRY(AUDIO_DEVICE_IN_USB_ACCESSORY),
STRING_ENTRY(AUDIO_DEVICE_IN_USB_DEVICE),
{ 0, NULL }
};
static struct string_conversion string_conversion_table_input_device_fancy[] = {
{ AUDIO_DEVICE_IN_COMMUNICATION, "input-communication" },
{ AUDIO_DEVICE_IN_AMBIENT, "input-ambient" },
{ AUDIO_DEVICE_IN_BUILTIN_MIC, "input-builtin_mic" },
{ AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, "input-bluetooth_sco_headset" },
{ AUDIO_DEVICE_IN_WIRED_HEADSET, "input-wired_headset" },
{ AUDIO_DEVICE_IN_AUX_DIGITAL, "input-aux_digital" },
{ AUDIO_DEVICE_IN_VOICE_CALL, "input-voice_call" },
{ AUDIO_DEVICE_IN_BACK_MIC, "input-back_mic" },
{ AUDIO_DEVICE_IN_REMOTE_SUBMIX, "input-remote_submix" },
{ 0, NULL }
};
#endif
/* Flags */
static struct string_conversion string_conversion_table_flag[] = {
STRING_ENTRY(AUDIO_OUTPUT_FLAG_NONE),
STRING_ENTRY(AUDIO_OUTPUT_FLAG_DIRECT),
STRING_ENTRY(AUDIO_OUTPUT_FLAG_PRIMARY),
STRING_ENTRY(AUDIO_OUTPUT_FLAG_FAST),
STRING_ENTRY(AUDIO_OUTPUT_FLAG_DEEP_BUFFER),
{ 0, NULL }
};
/* Channels */
static struct string_conversion string_conversion_table_output_channels[] = {
STRING_ENTRY(AUDIO_CHANNEL_OUT_FRONT_LEFT),
STRING_ENTRY(AUDIO_CHANNEL_OUT_FRONT_RIGHT),
STRING_ENTRY(AUDIO_CHANNEL_OUT_FRONT_CENTER),
STRING_ENTRY(AUDIO_CHANNEL_OUT_LOW_FREQUENCY),
STRING_ENTRY(AUDIO_CHANNEL_OUT_BACK_LEFT),
STRING_ENTRY(AUDIO_CHANNEL_OUT_BACK_RIGHT),
STRING_ENTRY(AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER),
STRING_ENTRY(AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER),
STRING_ENTRY(AUDIO_CHANNEL_OUT_BACK_CENTER),
STRING_ENTRY(AUDIO_CHANNEL_OUT_SIDE_LEFT),
STRING_ENTRY(AUDIO_CHANNEL_OUT_SIDE_RIGHT),
STRING_ENTRY(AUDIO_CHANNEL_OUT_TOP_CENTER),
STRING_ENTRY(AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT),
STRING_ENTRY(AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER),
STRING_ENTRY(AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT),
STRING_ENTRY(AUDIO_CHANNEL_OUT_TOP_BACK_LEFT),
STRING_ENTRY(AUDIO_CHANNEL_OUT_TOP_BACK_CENTER),
STRING_ENTRY(AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT),
STRING_ENTRY(AUDIO_CHANNEL_OUT_MONO),
STRING_ENTRY(AUDIO_CHANNEL_OUT_STEREO),
STRING_ENTRY(AUDIO_CHANNEL_OUT_QUAD),
STRING_ENTRY(AUDIO_CHANNEL_OUT_SURROUND),
STRING_ENTRY(AUDIO_CHANNEL_OUT_5POINT1),
STRING_ENTRY(AUDIO_CHANNEL_OUT_7POINT1),
STRING_ENTRY(AUDIO_CHANNEL_OUT_ALL),
{ 0, NULL }
};
static struct string_conversion string_conversion_table_input_channels[] = {
STRING_ENTRY(AUDIO_CHANNEL_IN_LEFT),
STRING_ENTRY(AUDIO_CHANNEL_IN_RIGHT),
STRING_ENTRY(AUDIO_CHANNEL_IN_FRONT),
STRING_ENTRY(AUDIO_CHANNEL_IN_BACK),
STRING_ENTRY(AUDIO_CHANNEL_IN_LEFT_PROCESSED),
STRING_ENTRY(AUDIO_CHANNEL_IN_RIGHT_PROCESSED),
STRING_ENTRY(AUDIO_CHANNEL_IN_FRONT_PROCESSED),
STRING_ENTRY(AUDIO_CHANNEL_IN_BACK_PROCESSED),
STRING_ENTRY(AUDIO_CHANNEL_IN_PRESSURE),
STRING_ENTRY(AUDIO_CHANNEL_IN_X_AXIS),
STRING_ENTRY(AUDIO_CHANNEL_IN_Y_AXIS),
STRING_ENTRY(AUDIO_CHANNEL_IN_Z_AXIS),
STRING_ENTRY(AUDIO_CHANNEL_IN_VOICE_UPLINK),
STRING_ENTRY(AUDIO_CHANNEL_IN_VOICE_DNLINK),
STRING_ENTRY(AUDIO_CHANNEL_IN_MONO),
STRING_ENTRY(AUDIO_CHANNEL_IN_STEREO),
STRING_ENTRY(AUDIO_CHANNEL_IN_ALL),
{ 0, NULL }
};
/* Formats */
static struct string_conversion string_conversion_table_format[] = {
STRING_ENTRY(AUDIO_FORMAT_DEFAULT),
STRING_ENTRY(AUDIO_FORMAT_PCM),
STRING_ENTRY(AUDIO_FORMAT_MP3),
STRING_ENTRY(AUDIO_FORMAT_AMR_NB),
STRING_ENTRY(AUDIO_FORMAT_AMR_WB),
STRING_ENTRY(AUDIO_FORMAT_AAC),
STRING_ENTRY(AUDIO_FORMAT_HE_AAC_V1),
STRING_ENTRY(AUDIO_FORMAT_HE_AAC_V2),
STRING_ENTRY(AUDIO_FORMAT_VORBIS),
STRING_ENTRY(AUDIO_FORMAT_MAIN_MASK),
STRING_ENTRY(AUDIO_FORMAT_SUB_MASK),
STRING_ENTRY(AUDIO_FORMAT_PCM_16_BIT),
STRING_ENTRY(AUDIO_FORMAT_PCM_8_BIT),
STRING_ENTRY(AUDIO_FORMAT_PCM_32_BIT),
STRING_ENTRY(AUDIO_FORMAT_PCM_8_24_BIT),
{ 0, NULL }
};
#undef STRING_ENTRY
#endif

1145
src/droid/droid-util.c Normal file

File diff suppressed because it is too large Load diff

248
src/droid/droid-util.h Normal file
View file

@ -0,0 +1,248 @@
#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 <hardware/audio.h>
#include <hardware_legacy/audio_policy_conf.h>
#define PROP_DROID_DEVICES "droid.devices"
#define PROP_DROID_FLAGS "droid.flags"
#define PROP_DROID_HW_MODULE "droid.hw_module"
typedef struct pa_droid_hw_module pa_droid_hw_module;
typedef struct pa_droid_card_data pa_droid_card_data;
typedef void (*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;
struct pa_droid_hw_module {
PA_REFCNT_DECLARE;
pa_core *core;
pa_droid_config_audio *config;
const pa_droid_config_hw_module *enabled_module;
pa_mutex *hw_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;
};
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)
#define AUDIO_MAX_HW_MODULES (8)
#define AUDIO_MAX_INPUTS (8)
#define AUDIO_MAX_OUTPUTS (8)
typedef struct pa_droid_config_global {
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[AUDIO_HARDWARE_MODULE_ID_MAX_LEN];
uint32_t sampling_rates[AUDIO_MAX_SAMPLING_RATES];
audio_channel_mask_t channel_masks; /* 0 -> dynamic */
audio_format_t formats;
audio_devices_t devices;
audio_output_flags_t flags;
} pa_droid_config_output;
typedef struct pa_droid_config_input {
const pa_droid_config_hw_module *module;
char name[AUDIO_HARDWARE_MODULE_ID_MAX_LEN];
uint32_t sampling_rates[AUDIO_MAX_SAMPLING_RATES];
audio_channel_mask_t channel_masks; /* 0 -> dynamic */
audio_format_t formats;
audio_devices_t devices;
} pa_droid_config_input;
struct pa_droid_config_hw_module {
const pa_droid_config_audio *config;
char name[AUDIO_HARDWARE_MODULE_ID_MAX_LEN];
pa_droid_config_output outputs[AUDIO_MAX_OUTPUTS];
uint32_t outputs_size;
pa_droid_config_input inputs[AUDIO_MAX_INPUTS];
uint32_t inputs_size;
};
struct pa_droid_config_audio {
pa_droid_config_global global_config;
pa_droid_config_hw_module hw_modules[AUDIO_MAX_HW_MODULES];
uint32_t hw_modules_size;
};
/* 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;
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;
/* Profile doesn't own the mappings */
pa_droid_mapping *output;
pa_droid_mapping *input;
} 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"
/* 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);
pa_bool_t pa_droid_hw_module_try_lock(pa_droid_hw_module *hw);
void pa_droid_hw_module_unlock(pa_droid_hw_module *hw);
/* Conversion helpers */
typedef enum {
CONV_FROM_PA,
CONV_FROM_HAL
} pa_conversion_field_t;
pa_bool_t pa_convert_output_channel(uint32_t value, pa_conversion_field_t from, uint32_t *to_value);
pa_bool_t pa_convert_input_channel(uint32_t value, pa_conversion_field_t from, uint32_t *to_value);
pa_bool_t pa_convert_format(uint32_t value, pa_conversion_field_t from, uint32_t *to_value);
pa_bool_t pa_string_convert_output_device_num_to_str(audio_devices_t value, const char **to_str);
pa_bool_t pa_string_convert_output_device_str_to_num(const char *str, audio_devices_t *to_value);
pa_bool_t pa_string_convert_input_device_num_to_str(audio_devices_t value, const char **to_str);
pa_bool_t pa_string_convert_input_device_str_to_num(const char *str, audio_devices_t *to_value);
pa_bool_t pa_string_convert_flag_num_to_str(audio_output_flags_t value, const char **to_str);
pa_bool_t 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);
/* Config parser */
pa_bool_t 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);
void pa_droid_profile_set_free(pa_droid_profile_set *ps);
pa_droid_profile *pa_droid_profile_new(pa_droid_profile_set *ps, const pa_droid_config_output *output, const pa_droid_config_input *input);
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);
void pa_droid_mapping_free(pa_droid_mapping *am);
/* Add ports from sinks/sources */
void pa_droid_add_ports(pa_hashmap *ports, pa_droid_mapping *am, pa_card *card);
/* Add ports from card */
void pa_droid_add_card_ports(pa_card_profile *cp, pa_hashmap *ports, pa_droid_mapping *am, pa_core *core);
/* Pretty port names */
pa_bool_t pa_droid_output_port_name(audio_devices_t value, const char **to_str);
pa_bool_t pa_droid_input_port_name(audio_devices_t value, const char **to_str);
#endif

223
src/droid/keepalive.c Normal file
View file

@ -0,0 +1,223 @@
/*
* 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 <signal.h>
#include <stdio.h>
#ifdef HAVE_VALGRIND_MEMCHECK_H
#include <valgrind/memcheck.h>
#endif
#include <pulse/rtclock.h>
#include <pulse/timeval.h>
#include <pulse/xmalloc.h>
#include <pulsecore/core.h>
#include <pulsecore/core-error.h>
#include <pulsecore/dbus-shared.h>
#include <pulsecore/dbus-util.h>
#include <pulsecore/atomic.h>
#include "keepalive.h"
#define MCE_BUS (DBUS_BUS_SYSTEM)
#define MCE_DBUS_NAME "com.nokia.mce"
#define MCE_DBUS_PATH "/com/nokia/mce/request"
#define MCE_DBUS_IFACE "com.nokia.mce.request"
#define MCE_DBUS_KEEPALIVE_PERIOD_REQ "req_cpu_keepalive_period"
#define MCE_DBUS_KEEPALIVE_START_REQ "req_cpu_keepalive_start"
#define MCE_DBUS_KEEPALIVE_STOP_REQ "req_cpu_keepalive_stop"
struct pa_droid_keepalive {
pa_core *core;
pa_dbus_connection *dbus_connection;
pa_atomic_t started;
pa_usec_t timeout;
pa_time_event *timer_event;
};
pa_droid_keepalive* pa_droid_keepalive_new(pa_core *c) {
pa_droid_keepalive *k;
pa_dbus_connection *dbus;
DBusError error;
pa_assert(c);
dbus_error_init(&error);
dbus = pa_dbus_bus_get(c, MCE_BUS, &error);
if (dbus_error_is_set(&error)) {
pa_log("Failed to get %s bus: %s", MCE_BUS == DBUS_BUS_SESSION ? "session" : "system", error.message);
dbus_error_free(&error);
return NULL;
}
k = pa_xnew0(pa_droid_keepalive, 1);
k->core = c;
k->dbus_connection = dbus;
k->timeout = 0;
pa_atomic_store(&k->started, 0);
return k;
}
static void send_dbus_signal(pa_dbus_connection *dbus) {
DBusMessage *msg;
pa_assert(dbus);
/* pa_log_debug("Send keepalive heartbeat."); */
pa_assert_se((msg = dbus_message_new_method_call(MCE_DBUS_NAME,
MCE_DBUS_PATH,
MCE_DBUS_IFACE,
MCE_DBUS_KEEPALIVE_START_REQ)));
dbus_connection_send(pa_dbus_connection_get(dbus), msg, NULL);
dbus_message_unref(msg);
}
static void keepalive_cb(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) {
pa_droid_keepalive *k = userdata;
pa_assert(k);
pa_assert(k->timer_event == e);
send_dbus_signal(k->dbus_connection);
pa_core_rttime_restart(k->core, k->timer_event, pa_rtclock_now() + k->timeout);
}
static void keepalive_start(pa_droid_keepalive *k) {
pa_assert(k);
pa_assert(k->timeout);
pa_assert(!k->timer_event);
pa_log_info("Start keepalive heartbeat with interval %lu seconds.", (unsigned long) (k->timeout / PA_USEC_PER_SEC));
/* Send first keepalive heartbeat immediately. */
send_dbus_signal(k->dbus_connection);
k->timer_event = pa_core_rttime_new(k->core, pa_rtclock_now() + k->timeout, keepalive_cb, k);
}
static void pending_req_reply_cb(DBusPendingCall *pending, void *userdata) {
pa_droid_keepalive *k = userdata;
DBusMessage *msg;
uint32_t period;
pa_assert(pending);
pa_assert(k);
pa_assert_se(msg = dbus_pending_call_steal_reply(pending));
if (dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_ERROR) {
pa_log("Failed to get %s", MCE_DBUS_KEEPALIVE_PERIOD_REQ);
goto finish;
}
pa_assert_se(dbus_message_get_args(msg, NULL,
DBUS_TYPE_INT32, &period,
DBUS_TYPE_INVALID));
k->timeout = PA_USEC_PER_SEC * (period - 5);
keepalive_start(k);
finish:
dbus_message_unref(msg);
dbus_pending_call_unref(pending);
}
void pa_droid_keepalive_start(pa_droid_keepalive *k) {
DBusPendingCall *pending = NULL;
DBusMessage *msg = NULL;
pa_assert(k);
/* Only allow first call go through. pa_atomic_inc() returns previous value before incrementing. */
if (pa_atomic_inc(&k->started) > 0)
return;
pa_assert(!k->timer_event);
/* Period time already requested, just start hearbeat. */
if (k->timeout > 0) {
keepalive_start(k);
return;
}
pa_log_debug("Starting keepalive - Request keepalive period.");
/* Send first keepalive heartbeat immediately. */
send_dbus_signal(k->dbus_connection);
pa_assert_se((msg = dbus_message_new_method_call(MCE_DBUS_NAME,
MCE_DBUS_PATH,
MCE_DBUS_IFACE,
MCE_DBUS_KEEPALIVE_PERIOD_REQ)));
dbus_connection_send_with_reply(pa_dbus_connection_get(k->dbus_connection), msg, &pending, -1);
dbus_message_unref(msg);
dbus_pending_call_set_notify(pending, pending_req_reply_cb, k, NULL);
}
void pa_droid_keepalive_stop(pa_droid_keepalive *k) {
DBusMessage *msg;
pa_assert(k);
/* Only allow last call go through. pa_atomic_dec() returns previous value before decrementing. */
if (pa_atomic_dec(&k->started) != 1)
return;
pa_assert(pa_atomic_load(&k->started) == 0);
if (!k->timer_event)
return;
pa_log_debug("Stopping keepalive.");
k->core->mainloop->time_free(k->timer_event);
k->timer_event = NULL;
pa_assert_se((msg = dbus_message_new_method_call(MCE_DBUS_NAME,
MCE_DBUS_PATH,
MCE_DBUS_IFACE,
MCE_DBUS_KEEPALIVE_STOP_REQ)));
dbus_connection_send(pa_dbus_connection_get(k->dbus_connection), msg, NULL);
dbus_message_unref(msg);
}
void pa_droid_keepalive_free(pa_droid_keepalive *k) {
pa_assert(k);
pa_assert(k->dbus_connection);
pa_assert(pa_atomic_load(&k->started) == 0);
pa_dbus_connection_unref(k->dbus_connection);
pa_xfree(k);
}

View file

@ -1,10 +1,10 @@
#ifndef foodroidconfigparserxmlfoo
#define foodroidconfigparserxmlfoo
#ifndef foodroidkeepalivefoo
#define foodroidkeepalivefoo
/*
* Copyright (C) 2022 Jolla Ltd.
* Copyright (C) 2013 Jolla Ltd.
*
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
* 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
@ -26,8 +26,19 @@
#include <config.h>
#endif
#include <droid/droid-config.h>
#include <pulsecore/core.h>
#include <pulsecore/core-util.h>
#include <pulsecore/macro.h>
#include <pulsecore/dbus-shared.h>
#include <pulsecore/atomic.h>
typedef struct pa_droid_keepalive pa_droid_keepalive;
pa_droid_keepalive* pa_droid_keepalive_new(pa_core *c);
void pa_droid_keepalive_free(pa_droid_keepalive *k);
void pa_droid_keepalive_start(pa_droid_keepalive *k);
void pa_droid_keepalive_stop(pa_droid_keepalive *k);
dm_config_device *pa_parse_droid_audio_config_xml(const char *filename);
#endif

View file

@ -0,0 +1,42 @@
/*
* 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.
*/
#ifndef foomoduledroidcardsymdeffoo
#define foomoduledroidcardsymdeffoo
#include <pulsecore/core.h>
#include <pulsecore/module.h>
#define pa__init module_droid_card_LTX_pa__init
#define pa__done module_droid_card_LTX_pa__done
#define pa__get_author module_droid_card_LTX_pa__get_author
#define pa__get_description module_droid_card_LTX_pa__get_description
#define pa__get_usage module_droid_card_LTX_pa__get_usage
#define pa__get_version module_droid_card_LTX_pa__get_version
int pa__init(struct pa_module*m);
void pa__done(struct pa_module*m);
const char* pa__get_author(void);
const char* pa__get_description(void);
const char* pa__get_usage(void);
const char* pa__get_version(void);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,42 @@
/*
* 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.
*/
#ifndef foomoduledroidkeepalivesymdeffoo
#define foomoduledroidkeepalivesymdeffoo
#include <pulsecore/core.h>
#include <pulsecore/module.h>
#define pa__init module_droid_keepalive_LTX_pa__init
#define pa__done module_droid_keepalive_LTX_pa__done
#define pa__get_author module_droid_keepalive_LTX_pa__get_author
#define pa__get_description module_droid_keepalive_LTX_pa__get_description
#define pa__get_usage module_droid_keepalive_LTX_pa__get_usage
#define pa__get_version module_droid_keepalive_LTX_pa__get_version
int pa__init(struct pa_module*m);
void pa__done(struct pa_module*m);
const char* pa__get_author(void);
const char* pa__get_description(void);
const char* pa__get_usage(void);
const char* pa__get_version(void);
#endif

View file

@ -0,0 +1,182 @@
/*
* 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 <signal.h>
#include <stdio.h>
#ifdef HAVE_VALGRIND_MEMCHECK_H
#include <valgrind/memcheck.h>
#endif
#include <pulse/xmalloc.h>
#include <pulsecore/core.h>
#include <pulsecore/i18n.h>
#include <pulsecore/module.h>
#include <pulsecore/sink.h>
#include <pulsecore/source.h>
#include <pulsecore/modargs.h>
#include <pulsecore/core-util.h>
#include <pulsecore/log.h>
#include <pulsecore/macro.h>
#include <pulsecore/idxset.h>
#include "keepalive.h"
#include "module-droid-keepalive-symdef.h"
PA_MODULE_AUTHOR("Juho Hämäläinen");
PA_MODULE_DESCRIPTION("Droid keepalive. Send cpu wakeup heartbeat while streams are active.");
PA_MODULE_VERSION(PACKAGE_VERSION);
PA_MODULE_USAGE(
"-"
);
static const char* const valid_modargs[] = {
NULL,
};
struct userdata {
pa_core *core;
pa_module *module;
pa_droid_keepalive *keepalive;
pa_bool_t active;
pa_hook_slot *sink_state_changed_slot;
pa_hook_slot *source_state_changed_slot;
};
static void start(struct userdata *u) {
if (u->active)
return;
u->active = TRUE;
pa_droid_keepalive_start(u->keepalive);
}
static void stop(struct userdata *u) {
void *state = NULL;
pa_sink *sink;
pa_source *source;
if (!u->active)
return;
while ((sink = pa_idxset_iterate(u->core->sinks, &state, NULL))) {
if (pa_sink_get_state(sink) != PA_SINK_SUSPENDED)
return;
}
state = NULL;
while ((source = pa_idxset_iterate(u->core->sources, &state, NULL))) {
if (source->monitor_of)
continue;
if (pa_source_get_state(source) != PA_SOURCE_SUSPENDED)
return;
}
/* We get here if all sinks and sources are in suspended state. */
pa_droid_keepalive_stop(u->keepalive);
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);
pa_assert(u);
if (pa_source_isinstance(o)) {
pa_source *s = PA_SOURCE(o);
/* 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);
if (state != PA_SINK_SUSPENDED)
start(u);
else
stop(u);
}
return PA_HOOK_OK;
}
int pa__init(pa_module *m) {
pa_assert(m);
struct userdata *u = pa_xnew0(struct userdata, 1);
u->core = m->core;
u->active = FALSE;
u->module = m;
m->userdata = u;
if (!(u->keepalive = pa_droid_keepalive_new(u->core))) {
pa_log("Failed to create keepalive handler.");
goto fail;
}
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);
return 0;
fail:
pa__done(m);
return -1;
}
void pa__done(pa_module *m) {
struct userdata *u;
pa_assert(m);
if ((u = m->userdata)) {
if (u->sink_state_changed_slot)
pa_hook_slot_free(u->sink_state_changed_slot);
if (u->source_state_changed_slot)
pa_hook_slot_free(u->source_state_changed_slot);
if (u->keepalive) {
stop(u);
pa_droid_keepalive_free(u->keepalive);
}
pa_xfree(u);
}
}

View file

@ -0,0 +1,42 @@
/*
* 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.
*/
#ifndef foomoduledroidsinksymdeffoo
#define foomoduledroidsinksymdeffoo
#include <pulsecore/core.h>
#include <pulsecore/module.h>
#define pa__init module_droid_sink_LTX_pa__init
#define pa__done module_droid_sink_LTX_pa__done
#define pa__get_author module_droid_sink_LTX_pa__get_author
#define pa__get_description module_droid_sink_LTX_pa__get_description
#define pa__get_usage module_droid_sink_LTX_pa__get_usage
#define pa__get_version module_droid_sink_LTX_pa__get_version
int pa__init(struct pa_module*m);
void pa__done(struct pa_module*m);
const char* pa__get_author(void);
const char* pa__get_description(void);
const char* pa__get_usage(void);
const char* pa__get_version(void);
#endif

View file

@ -1,7 +1,7 @@
/*
* Copyright (C) 2013-2018 Jolla Ltd.
* Copyright (C) 2013 Jolla Ltd.
*
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
* 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
@ -37,10 +37,11 @@
#include <pulsecore/log.h>
#include <pulsecore/macro.h>
#include <droid/droid-util.h>
#include <droid/conversion.h>
#include "droid-util.h"
#include "droid-sink.h"
#include "module-droid-sink-symdef.h"
PA_MODULE_AUTHOR("Juho Hämäläinen");
PA_MODULE_DESCRIPTION("Droid sink");
PA_MODULE_USAGE("master_sink=<sink to connect to> "
@ -48,28 +49,15 @@ PA_MODULE_USAGE("master_sink=<sink to connect to> "
PA_MODULE_VERSION(PACKAGE_VERSION);
static const char* const valid_modargs[] = {
"config",
"rate",
"format",
"channels",
"channel_map",
"sink_rate",
"sink_format",
"sink_channel_map",
"sink_mix_route",
"flags",
"output",
"output_devices",
"devices",
"sink_name",
"module_id",
"mute_routing_before",
"mute_routing_after",
"prewrite_on_resume",
"sink_buffer",
"deferred_volume",
"voice_property_key",
"voice_property_value",
"voice_virtual_stream",
NULL,
};
@ -84,24 +72,15 @@ void pa__done(pa_module *m) {
int pa__init(pa_module *m) {
pa_modargs *ma = NULL;
const char *flags_str;
audio_output_flags_t flags = 0;
pa_assert(m);
if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
pa_log("Failed to parse module arguments.");
pa_log("Failed to parse module argumets.");
goto fail;
}
if ((flags_str = pa_modargs_get_value(ma, "flags", NULL))) {
if (!pa_string_convert_flag_str_to_num(flags_str, &flags)) {
pa_log("Failed to parse flags");
goto fail;
}
}
if (!(m->userdata = pa_droid_sink_new(m, ma, __FILE__, NULL, flags, NULL, NULL)))
if (!(m->userdata = pa_droid_sink_new(m, ma, __FILE__, NULL, 0, NULL, NULL)))
goto fail;
pa_modargs_free(ma);

View file

@ -0,0 +1,42 @@
/*
* 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.
*/
#ifndef foomoduledroidsourcesymdeffoo
#define foomoduledroidsourcesymdeffoo
#include <pulsecore/core.h>
#include <pulsecore/module.h>
#define pa__init module_droid_source_LTX_pa__init
#define pa__done module_droid_source_LTX_pa__done
#define pa__get_author module_droid_source_LTX_pa__get_author
#define pa__get_description module_droid_source_LTX_pa__get_description
#define pa__get_usage module_droid_source_LTX_pa__get_usage
#define pa__get_version module_droid_source_LTX_pa__get_version
int pa__init(struct pa_module*m);
void pa__done(struct pa_module*m);
const char* pa__get_author(void);
const char* pa__get_description(void);
const char* pa__get_usage(void);
const char* pa__get_version(void);
#endif

View file

@ -1,7 +1,7 @@
/*
* Copyright (C) 2013-2022 Jolla Ltd.
* Copyright (C) 2013 Jolla Ltd.
*
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
* 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
@ -37,9 +37,11 @@
#include <pulsecore/log.h>
#include <pulsecore/macro.h>
#include <droid/droid-util.h>
#include "droid-util.h"
#include "droid-source.h"
#include "module-droid-source-symdef.h"
PA_MODULE_AUTHOR("Juho Hämäläinen");
PA_MODULE_DESCRIPTION("Droid source");
PA_MODULE_USAGE("master_source=<source to connect to> "
@ -47,16 +49,9 @@ PA_MODULE_USAGE("master_source=<source to connect to> "
PA_MODULE_VERSION(PACKAGE_VERSION);
static const char* const valid_modargs[] = {
"config",
"rate",
"format",
"channels",
"channel_map",
"source_rate",
"source_format",
"source_channel_map",
"flags",
"input_devices",
"devices",
"source_name",
"module_id",
"source_buffer",
@ -79,7 +74,7 @@ int pa__init(pa_module *m) {
pa_assert(m);
if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
pa_log("Failed to parse module arguments.");
pa_log("Failed to parse module argumets.");
goto fail;
}