Merge remote-tracking branch 'upstream/bookworm' into bookworm
This commit is contained in:
commit
f1fb79c3e0
32 changed files with 2726 additions and 3159 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -19,3 +19,6 @@ config.status
|
||||||
libtool
|
libtool
|
||||||
*.pc
|
*.pc
|
||||||
stamp-*
|
stamp-*
|
||||||
|
|
||||||
|
# Added by Droidian
|
||||||
|
!.circleci/
|
||||||
|
|
|
||||||
238
README.md
238
README.md
|
|
@ -1,25 +1,23 @@
|
||||||
PulseAudio Droid modules
|
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
|
Building of droid modules is split to two packages
|
||||||
* **common** (and **common-devel**) which contains shared library code for use in
|
* **common** (and **common-devel**) which contains shared library code for use in
|
||||||
PulseAudio modules in this package and for inclusion in other projects
|
PulseAudio modules in this package and for inclusion in other projects
|
||||||
* **droid** with actual PulseAudio modules
|
* **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:
|
Supported Android versions:
|
||||||
|
|
||||||
* 4.1.x with Qualcomm extensions (tested with 4.1.2)
|
* 11.x
|
||||||
* 4.2.x
|
|
||||||
* 4.4.x
|
|
||||||
* 5.x
|
|
||||||
* 6.0.x
|
|
||||||
* 7.x
|
|
||||||
* 8.x
|
|
||||||
* 9.x
|
|
||||||
* 10.x
|
|
||||||
|
|
||||||
Headers for defining devices and strings for different droid versions are in
|
Headers for defining devices and strings for different droid versions are in
|
||||||
src/common/droid-util-audio.h (legacy headers for Jolla 1 in droid-util-41qc.h).
|
src/common/droid-util-audio.h.
|
||||||
|
|
||||||
When new devices with relevant new enums appear, add enum check to configure.ac.
|
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
|
CC_CHECK_DROID_ENUM macro will create macros HAVE_ENUM_FOO, STRING_ENTRY_IF_FOO
|
||||||
|
|
@ -66,28 +64,19 @@ most operations towards audio HAL.
|
||||||
|
|
||||||
### Audio policy configuration parsing
|
### Audio policy configuration parsing
|
||||||
|
|
||||||
To populate our configuration structs there exists two parsers, legacy parser
|
Configuration parser reads audio policy xml files.
|
||||||
for old .conf format present in Android versions 7.0 and older and new xml
|
|
||||||
format present from version 7.0 upwards. The legacy format is obsoleted in
|
|
||||||
version 7.0 but by default still in use and most 7.0 adaptations probably
|
|
||||||
contain the legacy format. But 8.0 adaptations and up start to include only
|
|
||||||
the new style xml format configuration files.
|
|
||||||
|
|
||||||
### Configuration files
|
### Configuration files
|
||||||
|
|
||||||
By default new style xml format is tried first and if it is not found old
|
If the configuration is in non-default location for some reason "config"
|
||||||
config is read next. If the configuration is in non-default location for
|
module argument can be used to point to the configuration file location.
|
||||||
some reason "config" module argument (available for all modules, card, sink,
|
|
||||||
and source) can be used to point to the configuration file location.
|
|
||||||
|
|
||||||
By default files are tried in following order,
|
By default files are tried in following order,
|
||||||
|
|
||||||
/odm/etc/audio_policy_configuration.xml (new xml format)
|
/odm/etc/audio_policy_configuration.xml
|
||||||
/vendor/etc/audio/audio_policy_configuration.xml (new xml format)
|
/vendor/etc/audio/audio_policy_configuration.xml
|
||||||
/vendor/etc/audio_policy_configuration.xml (new xml format)
|
/vendor/etc/audio_policy_configuration.xml
|
||||||
/vendor/etc/audio_policy.conf (legacy format)
|
/system/etc/audio_policy_configuration.xml
|
||||||
/system/etc/audio_policy_configuration.xml (new xml format)
|
|
||||||
/system/etc/audio_policy.conf (legacy format)
|
|
||||||
|
|
||||||
module-droid-card
|
module-droid-card
|
||||||
-----------------
|
-----------------
|
||||||
|
|
@ -99,39 +88,15 @@ selected profile.
|
||||||
default profile
|
default profile
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
When module-droid-card is loaded with default arguments, droid-card will try
|
When module-droid-card is loaded with default arguments, droid-card will
|
||||||
to create a default profile (called surprisingly "default"). The default
|
create a default profile (called unsurprisingly "default"). The default
|
||||||
profile will try to merge useful output and input streams to one profile,
|
profile will merge supported output and input streams to one profile,
|
||||||
to allow use of possible low latency or deep buffer outputs.
|
to allow use of possible low latency or deep buffer outputs.
|
||||||
|
|
||||||
For example configuration with
|
|
||||||
|
|
||||||
audio_hw_modules {
|
|
||||||
primary {
|
|
||||||
outputs {
|
|
||||||
primary {}
|
|
||||||
deep_buffer {}
|
|
||||||
}
|
|
||||||
inputs {
|
|
||||||
primary {}
|
|
||||||
voice_rx {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
other {
|
|
||||||
...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
The default profile would contain two sinks, sink.primary and sink.deep_buffer
|
|
||||||
and one source, source.droid.
|
|
||||||
|
|
||||||
Usually this default profile is everything that is needed in normal use, and
|
|
||||||
additional profiles created should be needed only for testing things out etc.
|
|
||||||
|
|
||||||
virtual profiles
|
virtual profiles
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
In addition to aforementioned card profiles, droid-card creates some additional
|
In addition to aforementioned card profile, droid-card creates some additional
|
||||||
virtual profiles. These virtual profiles are used when enabling voicecall
|
virtual profiles. These virtual profiles are used when enabling voicecall
|
||||||
routings etc. When virtual profile is enabled, possible sinks and sources
|
routings etc. When virtual profile is enabled, possible sinks and sources
|
||||||
previously active profile had are not removed.
|
previously active profile had are not removed.
|
||||||
|
|
@ -139,9 +104,6 @@ previously active profile had are not removed.
|
||||||
As an illustration, following command line sequence enables voicecall mode and
|
As an illustration, following command line sequence enables voicecall mode and
|
||||||
routes audio to internal handsfree (ihf - "handsfree speaker"):
|
routes audio to internal handsfree (ihf - "handsfree speaker"):
|
||||||
|
|
||||||
(Before starting, droid_card.primary is using profile primary-primary and
|
|
||||||
sink.primary port output-speaker)
|
|
||||||
|
|
||||||
pactl set-card-profile droid_card.primary voicecall
|
pactl set-card-profile droid_card.primary voicecall
|
||||||
pactl set-sink-port sink.primary output-parking
|
pactl set-sink-port sink.primary output-parking
|
||||||
pactl set-sink-port sink.primary output-speaker
|
pactl set-sink-port sink.primary output-speaker
|
||||||
|
|
@ -151,11 +113,11 @@ voice audio starts to flow between modem and audio chip.
|
||||||
|
|
||||||
To disable voicecall and return to media audio:
|
To disable voicecall and return to media audio:
|
||||||
|
|
||||||
pactl set-card-profile droid_card.primary primary-primary
|
pactl set-card-profile droid_card.primary default
|
||||||
pactl set-sink-port sink.primary output-parking
|
pactl set-sink-port sink.primary output-parking
|
||||||
pactl set-sink-port sink.primary output-speaker
|
pactl set-sink-port sink.primary output-speaker
|
||||||
|
|
||||||
With this example sequence sinks and sources are the ones from primary-primary
|
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
|
card profile, and they are maintained for the whole duration of the voicecall
|
||||||
and after.
|
and after.
|
||||||
|
|
||||||
|
|
@ -177,32 +139,9 @@ should be used when ringtone is playing, to again enable possible loudness
|
||||||
related optimizations etc. Voicecall-record profile can be enabled when
|
related optimizations etc. Voicecall-record profile can be enabled when
|
||||||
voicecall profile is active.
|
voicecall profile is active.
|
||||||
|
|
||||||
debugging profiles
|
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.
|
||||||
If needed in favour of default profile one can opt to creating combinations
|
|
||||||
of all output and input definitions in a module definition. This can be
|
|
||||||
done by passing "default=false" to module-droid-card. Module argument
|
|
||||||
module_id will then defines which module to load (by default "primary").
|
|
||||||
Without default profile all input and output definitions are translated
|
|
||||||
to PulseAudio card profiles. For example configuration with
|
|
||||||
|
|
||||||
audio_hw_modules {
|
|
||||||
primary {
|
|
||||||
outputs {
|
|
||||||
primary {}
|
|
||||||
lpa {}
|
|
||||||
}
|
|
||||||
inputs {
|
|
||||||
primary {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
other {
|
|
||||||
...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Would map to card profiles ([output]-[input]) primary-primary and lpa-primary.
|
|
||||||
|
|
||||||
module-droid-sink and module-droid-source
|
module-droid-sink and module-droid-source
|
||||||
-----------------------------------------
|
-----------------------------------------
|
||||||
|
|
@ -211,49 +150,15 @@ 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
|
hand, but droid-card loads appropriate modules based on the active card
|
||||||
profile.
|
profile.
|
||||||
|
|
||||||
Output and input ports for droid-sink and droid-source are generated from the
|
Changing output routing is as simple as
|
||||||
audio_policy_configuration.xml (where available) or audio_policy.conf (legacy),
|
|
||||||
where each device generates (usually) one port, for example:
|
|
||||||
|
|
||||||
audio_hw_modules {
|
|
||||||
primary {
|
|
||||||
outputs {
|
|
||||||
primary {
|
|
||||||
devices = AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_EARPIECE|AUDIO_DEVICE_OUT_WIRED_HEADPHONE
|
|
||||||
}
|
|
||||||
lpa {}
|
|
||||||
}
|
|
||||||
inputs {
|
|
||||||
primary {
|
|
||||||
devices = AUDIO_DEVICE_IN_BUILTIN_MIC
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Would create following ports for sink.primary:
|
|
||||||
* output-speaker
|
|
||||||
* output-earpiece
|
|
||||||
* output-wired_headphone
|
|
||||||
* output-speaker+wired_headphone
|
|
||||||
|
|
||||||
And for source.primary:
|
|
||||||
* input-builtin_mic
|
|
||||||
|
|
||||||
Only exception to one device one port rule is if output device list has both
|
|
||||||
OUT_SPEAKER and OUT_WIRED_HEADPHONE, then one additional combination port is
|
|
||||||
generated. How the devices are called in sink and source ports are defined in
|
|
||||||
droid-util-XXX.h
|
|
||||||
|
|
||||||
Changing output routing is then as simple as
|
|
||||||
|
|
||||||
pactl set-sink-port sink.primary output-wired_headphone
|
pactl set-sink-port sink.primary output-wired_headphone
|
||||||
|
|
||||||
Sink or source do not track possible headphone/other wired accessory plugging,
|
Sinks or sources do not track possible headphone/other wired accessory
|
||||||
but this needs to be handled elsewhere and then that other entity needs to
|
plugging, but this needs to be handled elsewhere and then that other entity
|
||||||
control sinks and sources. (For example in SailfishOS this entity is OHM with
|
needs to control sinks and sources. (For example in SailfishOS this entity is
|
||||||
accessory-plugin and pulseaudio-policy-enforcement module for actually making
|
OHM with accessory-plugin and pulseaudio-policy-enforcement module for
|
||||||
the port switching)
|
actually making the port switching)
|
||||||
|
|
||||||
Droid source automatic reconfiguration
|
Droid source automatic reconfiguration
|
||||||
--------------------------------------
|
--------------------------------------
|
||||||
|
|
@ -303,6 +208,7 @@ Currently following properties are set:
|
||||||
* droid.output.low_latency
|
* droid.output.low_latency
|
||||||
* droid.output.media_latency
|
* droid.output.media_latency
|
||||||
* droid.output.offload
|
* droid.output.offload
|
||||||
|
* droid.output.voip
|
||||||
* For droid sources
|
* For droid sources
|
||||||
* droid.input.builtin
|
* droid.input.builtin
|
||||||
* droid.input.external
|
* droid.input.external
|
||||||
|
|
@ -326,24 +232,20 @@ and so on.
|
||||||
Right now there exists only one source (input device) which will always have
|
Right now there exists only one source (input device) which will always have
|
||||||
both properties as true.
|
both properties as true.
|
||||||
|
|
||||||
Quirks
|
Options
|
||||||
------
|
-------
|
||||||
|
|
||||||
There are some adaptations that require hacks to get things working. These
|
There are some adaptations that require hacks to get things working. These
|
||||||
hacks can be enabled or disabled with module argument "quirks". Some quirks
|
hacks can be enabled or disabled with module argument "options". Some options
|
||||||
are enabled by default with some adaptations etc.
|
are enabled by default with some adaptations etc. There are also some more
|
||||||
|
generic options.
|
||||||
|
|
||||||
Currently there are following quirks:
|
Currently there are following options:
|
||||||
|
|
||||||
* input_atoi
|
* input_atoi
|
||||||
* Enabled by default with Android versions 5 and up.
|
* Enabled by default with Android versions 5 and up.
|
||||||
* Due to how atoi works in bionic vs libc we need to pass the input
|
* 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.
|
route a bit funny. If input routing doesn't work switch this on or off.
|
||||||
* set_parameters
|
|
||||||
* Disabled by default.
|
|
||||||
* Some adaptations need to use hw module's generic set_parameters call
|
|
||||||
to change input routing. If input routing doesn't work switch this
|
|
||||||
on or off. (mostly just older adaptations)
|
|
||||||
* close_input
|
* close_input
|
||||||
* Enabled by default.
|
* Enabled by default.
|
||||||
* Close input stream when not in use instead of suspending the stream.
|
* Close input stream when not in use instead of suspending the stream.
|
||||||
|
|
@ -352,22 +254,16 @@ Currently there are following quirks:
|
||||||
* Disabled by default.
|
* Disabled by default.
|
||||||
* Don't call audio_hw_device_close() for the hw module when unloading.
|
* Don't call audio_hw_device_close() for the hw module when unloading.
|
||||||
Mostly useful for tracking module unload issues.
|
Mostly useful for tracking module unload issues.
|
||||||
* no_hw_volume
|
* hw_volume
|
||||||
* Disabled by default.
|
* Enabled by default.
|
||||||
* Some broken implementations are incorrectly probed for supporting hw
|
* Some broken implementations are incorrectly probed for supporting hw
|
||||||
volume control. This is manifested by always full volume with volume
|
volume control. This is manifested by always full volume with volume
|
||||||
control not affecting volume level. To fix this enable this quirk.
|
control not affecting volume level. To fix this disable this option.
|
||||||
* output_make_writable
|
|
||||||
* Disabled by default.
|
|
||||||
* Some implementations modify write buffer in-place when this should
|
|
||||||
not be done. This can result in random segfaults when playing audio.
|
|
||||||
As a workaround make the buffer memchunk writable before passing to
|
|
||||||
audio HAL.
|
|
||||||
* realcall
|
* realcall
|
||||||
* Disabled by default.
|
* Disabled by default.
|
||||||
* Some vendors apply custom realcall parameter to HAL device when
|
* Some vendors apply custom realcall parameter to HAL device when
|
||||||
doing voicecall routing. If there is no voicecall audio you can
|
doing voicecall routing. If there is no voicecall audio you can
|
||||||
try enabling this quirk so that the realcall parameter is applied
|
try enabling this option so that the realcall parameter is applied
|
||||||
when switching to voicecall profile.
|
when switching to voicecall profile.
|
||||||
* unload_call_exit
|
* unload_call_exit
|
||||||
* Disabled by default.
|
* Disabled by default.
|
||||||
|
|
@ -377,36 +273,39 @@ Currently there are following quirks:
|
||||||
* output_fast
|
* output_fast
|
||||||
* Enabled by default.
|
* Enabled by default.
|
||||||
* Create separate sink if AUDIO_OUTPUT_FLAG_FAST is found. If this sink
|
* Create separate sink if AUDIO_OUTPUT_FLAG_FAST is found. If this sink
|
||||||
is misbehaving try disabling this quirk.
|
is misbehaving try disabling this option.
|
||||||
* output_deep_buffer
|
* output_deep_buffer
|
||||||
* Enabled by default.
|
* Enabled by default.
|
||||||
* Create separate sink if AUDIO_OUTPUT_FLAG_DEEP_BUFFER is found. If
|
* Create separate sink if AUDIO_OUTPUT_FLAG_DEEP_BUFFER is found. If
|
||||||
this sink is misbehaving try disabling this quirk.
|
this sink is misbehaving try disabling this option.
|
||||||
* audio_cal_wait
|
* audio_cal_wait
|
||||||
* Disabled by default.
|
* Disabled by default.
|
||||||
* Certain devices do audio calibration during hw module open and
|
* Certain devices do audio calibration during hw module open and
|
||||||
writing audio too early will break the calibration. In these cases
|
writing audio too early will break the calibration. In these cases
|
||||||
this quirk can be enabled and 10 seconds of sleep is added after
|
this option can be enabled and 10 seconds of sleep is added after
|
||||||
opening hw module.
|
opening hw module.
|
||||||
* standby_set_route
|
|
||||||
* Disabled by default.
|
|
||||||
* Some devices don't like to receive set_parameters() call while they
|
|
||||||
are in write(), even if it seems the mutexes are correctly in place.
|
|
||||||
Standby is another synchronization point which seems to work better.
|
|
||||||
If there are hiccups like long delays when setting route during
|
|
||||||
voice call start try enabling this quirk.
|
|
||||||
* speaker_before_voice
|
* speaker_before_voice
|
||||||
* Disabled by default.
|
* Disabled by default.
|
||||||
* Set route to speaker before changing audio mode to AUDIO_MODE_IN_CALL.
|
* 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
|
Some devices don't get routing right if the route is something else
|
||||||
(like AUDIO_DEVICE_OUT_WIRED_HEADSET) before calling set_mode().
|
(like AUDIO_DEVICE_OUT_WIRED_HEADSET) before calling set_mode().
|
||||||
If routing is wrong when call starts with wired accessory connected
|
If routing is wrong when call starts with wired accessory connected
|
||||||
try enabling this quirk.
|
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.
|
||||||
|
|
||||||
For example, to disable input_atoi and enable close_input quirks, use module
|
Options can be enabled or disabled normally as module arguments, for example:
|
||||||
argument
|
|
||||||
|
|
||||||
quirks=-input_atoi,+close_input
|
load-module module-droid-card hw_volume=false record_voice_16k=true
|
||||||
|
|
||||||
Volume control during voicecall
|
Volume control during voicecall
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
@ -436,7 +335,22 @@ For example, if droid-sink has active port output-wired_headphone:
|
||||||
As long as the new stream is connected to droid-sink, output routing is
|
As long as the new stream is connected to droid-sink, output routing is
|
||||||
SPEAKER.
|
SPEAKER.
|
||||||
|
|
||||||
module-droid-keepalive
|
HAL API
|
||||||
----------------------
|
-------
|
||||||
|
|
||||||
Module relocated to its own package pulseaudio-module-keepalive.
|
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");
|
||||||
|
|
|
||||||
73
configure.ac
73
configure.ac
|
|
@ -28,7 +28,7 @@ AC_SUBST(PA_MAJOR, pa_major)
|
||||||
AC_SUBST(PA_MAJORMINOR, pa_major.pa_minor)
|
AC_SUBST(PA_MAJORMINOR, pa_major.pa_minor)
|
||||||
AC_SUBST(PA_MODULE_VERSION, pa_module_version)
|
AC_SUBST(PA_MODULE_VERSION, pa_module_version)
|
||||||
|
|
||||||
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
|
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"
|
||||||
|
|
||||||
for flag in $DESIRED_FLAGS ; do
|
for flag in $DESIRED_FLAGS ; do
|
||||||
CC_CHECK_CFLAGS([$flag], [CFLAGS="$CFLAGS $flag"])
|
CC_CHECK_CFLAGS([$flag], [CFLAGS="$CFLAGS $flag"])
|
||||||
|
|
@ -170,7 +170,7 @@ AS_IF([test "$pulseaudio_cv__Bool" = "yes"], [
|
||||||
#LT_INIT([dlopen win32-dll disable-static])
|
#LT_INIT([dlopen win32-dll disable-static])
|
||||||
AC_PROG_LIBTOOL
|
AC_PROG_LIBTOOL
|
||||||
|
|
||||||
PKG_CHECK_MODULES([PULSEAUDIO], [libpulse >= 5.0 pulsecore >= 5.0])
|
PKG_CHECK_MODULES([PULSEAUDIO], [libpulse >= 14.2 pulsecore >= 14.2])
|
||||||
AC_SUBST(PULSEAUDIO_CFLAGS)
|
AC_SUBST(PULSEAUDIO_CFLAGS)
|
||||||
AC_SUBST(PULSEAUDIO_LIBS)
|
AC_SUBST(PULSEAUDIO_LIBS)
|
||||||
|
|
||||||
|
|
@ -187,88 +187,26 @@ PKG_CHECK_MODULES([EVDEV], [libevdev >= 1.0])
|
||||||
AC_SUBST(EVDEV_CFLAGS)
|
AC_SUBST(EVDEV_CFLAGS)
|
||||||
AC_SUBST(EVDEV_LIBS)
|
AC_SUBST(EVDEV_LIBS)
|
||||||
|
|
||||||
#### expat (for xml config format parsing) (optional) ####
|
#### expat (for xml config format parsing) ####
|
||||||
|
|
||||||
AC_ARG_ENABLE([xml],
|
PKG_CHECK_MODULES([EXPAT], [expat >= 2.1])
|
||||||
AS_HELP_STRING([--disable-xml],[Disable optional xml config support]))
|
|
||||||
|
|
||||||
AS_IF([test "x$enable_xml" != "xno"],
|
|
||||||
[PKG_CHECK_MODULES(EXPAT, [ expat >= 2.1 ], HAVE_EXPAT=1, HAVE_EXPAT=0)],
|
|
||||||
HAVE_EXPAT=0)
|
|
||||||
|
|
||||||
AS_IF([test "x$enable_xml" = "xyes" && test "x$HAVE_EXPAT" = "x0"],
|
|
||||||
[AC_MSG_ERROR([*** expat not found])])
|
|
||||||
|
|
||||||
AC_SUBST(HAVE_EXPAT)
|
|
||||||
AC_SUBST(EXPAT_CFLAGS)
|
AC_SUBST(EXPAT_CFLAGS)
|
||||||
AC_SUBST(EXPAT_LIBS)
|
AC_SUBST(EXPAT_LIBS)
|
||||||
AM_CONDITIONAL([HAVE_EXPAT], [test "x$HAVE_EXPAT" = x1])
|
|
||||||
AS_IF([test "x$HAVE_EXPAT" = "x1"], AC_DEFINE([HAVE_EXPAT], 1, [Have expat?]))
|
|
||||||
AS_IF([test "x$HAVE_EXPAT" = "x1"], ENABLE_XML="yes (expat)", ENABLE_XML=no)
|
|
||||||
|
|
||||||
# Output devices
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_OUT_HDMI])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_OUT_HDMI_ARC])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_OUT_TELEPHONY_TX])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_OUT_LINE])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_OUT_SPDIF])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_OUT_AUX_LINE])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_OUT_SPEAKER_SAFE])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_OUT_FM])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_OUT_FM_TX])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_OUT_ANC_HEADSET])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_OUT_ANC_HEADPHONE])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_OUT_PROXY])
|
|
||||||
# Added in 6.0
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_OUT_IP])
|
|
||||||
|
|
||||||
# Input devices
|
# Input devices
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_IN_HDMI])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_IN_TELEPHONY_RX])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_IN_FM_TUNER])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_IN_TV_TUNER])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_IN_LINE])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_IN_SPDIF])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_IN_BLUETOOTH_A2DP])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_IN_LOOPBACK])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_IN_PROXY])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_IN_FM_RX])
|
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_IN_FM_RX])
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_IN_FM_RX_A2DP])
|
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_IN_FM_RX_A2DP])
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_IN_ALL_USB])
|
|
||||||
# Added in 6.0
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_IN_IP])
|
|
||||||
|
|
||||||
# Audio sources
|
# 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_TUNER])
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_SOURCE_FM_RX])
|
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_SOURCE_FM_RX])
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_SOURCE_FM_RX_A2DP])
|
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_SOURCE_FM_RX_A2DP])
|
||||||
|
|
||||||
# Output flags
|
# Output flags
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_OUTPUT_FLAG_NON_BLOCKING])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_OUTPUT_FLAG_HW_AV_SYNC])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_OUTPUT_FLAG_VOIP_RX])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_OUTPUT_FLAG_INCALL_MUSIC])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH])
|
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH])
|
||||||
# Added in 6.0
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_OUTPUT_FLAG_TTS])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_OUTPUT_FLAG_RAW])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_OUTPUT_FLAG_SYNC])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO])
|
|
||||||
|
|
||||||
# Input flags
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_INPUT_FLAG_NONE])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_INPUT_FLAG_FAST])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_INPUT_FLAG_HW_HOTWORD])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_INPUT_FLAG_RAW])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_INPUT_FLAG_SYNC])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_INPUT_FLAG_MMAP_NOIRQ])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_INPUT_FLAG_VOIP_TX])
|
|
||||||
|
|
||||||
# Channels
|
# Channels
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_CHANNEL_OUT_SURROUND])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_CHANNEL_OUT_5POINT1_BACK])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_CHANNEL_OUT_5POINT1_SIDE])
|
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_CHANNEL_IN_VOICE_CALL_MONO])
|
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_UPLINK_MONO])
|
||||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO])
|
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO])
|
||||||
|
|
@ -336,5 +274,4 @@ echo "
|
||||||
modules directory: ${modlibexecdir}
|
modules directory: ${modlibexecdir}
|
||||||
|
|
||||||
Droid device: ${droiddevice}
|
Droid device: ${droiddevice}
|
||||||
XML config support: ${ENABLE_XML}
|
|
||||||
"
|
"
|
||||||
|
|
|
||||||
31
debian/control
vendored
31
debian/control
vendored
|
|
@ -1,7 +1,7 @@
|
||||||
Source: pulseaudio-modules-droid
|
Source: pulseaudio-modules-droid-modern
|
||||||
Section: sound
|
Section: sound
|
||||||
Priority: optional
|
Priority: optional
|
||||||
Build-Depends: android-headers (>= 23),
|
Build-Depends: android-headers,
|
||||||
check,
|
check,
|
||||||
debhelper (>= 11),
|
debhelper (>= 11),
|
||||||
dh-exec,
|
dh-exec,
|
||||||
|
|
@ -15,18 +15,29 @@ Build-Depends: android-headers (>= 23),
|
||||||
libexpat1-dev,
|
libexpat1-dev,
|
||||||
libevdev-dev,
|
libevdev-dev,
|
||||||
libudev-dev
|
libudev-dev
|
||||||
Maintainer: Marius Gripsgard <marius@ubports.com>
|
Maintainer: Adam Boardman <adamboardman@gmail.com>
|
||||||
Standards-Version: 4.3.0
|
Standards-Version: 4.3.0
|
||||||
Homepage: https://github.com/mer-hybris/pulseaudio-modules-droid
|
Homepage: https://github.com/mer-hybris/pulseaudio-modules-droid
|
||||||
Vcs-Git: https://gitlab.com/debian-pm/halium/pulseaudio-modules-droid.git
|
Vcs-Git: https://github.com/gemian/pulseaudio-modules-droid-modern.git
|
||||||
Vcs-Browser: https://gitlab.com/debian-pm/halium/pulseaudio-modules-droid
|
Vcs-Browser: https://github.com/gemian/pulseaudio-modules-droid-modern
|
||||||
|
|
||||||
Package: pulseaudio-module-droid
|
Package: pulseaudio-modules-droid-modern
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: ${misc:Depends}, ${shlibs:Depends}
|
Depends: ${misc:Depends}, ${shlibs:Depends}
|
||||||
Description: PulseAudio Droid HAL module.
|
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-module-droid-dev
|
Package: pulseaudio-modules-droid-modern-dev
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: pulseaudio-module-droid, ${misc:Depends}
|
Depends: pulseaudio-modules-droid-modern (= ${binary:Version}),
|
||||||
Description: PulseAudio Droid HAL module development headers.
|
${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.
|
||||||
|
|
|
||||||
26
debian/copyright
vendored
26
debian/copyright
vendored
|
|
@ -1,11 +1,10 @@
|
||||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||||
Upstream-Name: pulseaudio-modules-droid
|
Upstream-Name: pulseaudio-modules-droid-modern
|
||||||
Source: https://github.com/mer-hybris/pulseaudio-modules-droid
|
Source: https://github.com/mer-hybris/pulseaudio-modules-droid-modern
|
||||||
|
|
||||||
Files: *
|
Files: *
|
||||||
Copyright: 1991, 1999, Free Software Foundation, Inc.
|
Copyright: 2013-2022, Jolla Ltd.
|
||||||
License: UNKNOWN
|
License: LGPL-2.1
|
||||||
Please fill license UNKNOWN from header of *
|
|
||||||
|
|
||||||
Files: debian/*
|
Files: debian/*
|
||||||
Copyright: 2018, Jonah Brüchert
|
Copyright: 2018, Jonah Brüchert
|
||||||
|
|
@ -17,23 +16,6 @@ Copyright: 2006, 2007, xine project
|
||||||
2006, 2007, Diego Pettenò <flameeyes@gmail.com>
|
2006, 2007, Diego Pettenò <flameeyes@gmail.com>
|
||||||
License: GPL-2+
|
License: GPL-2+
|
||||||
|
|
||||||
Files: src/*
|
|
||||||
Copyright: 2013-2018, Jolla Ltd.
|
|
||||||
License: LGPL-2.1
|
|
||||||
|
|
||||||
Files: src/Makefile.am
|
|
||||||
Copyright: 2013, 2017, Jolla Ltd.
|
|
||||||
License: LGPL-2.1
|
|
||||||
|
|
||||||
Files: src/common/Makefile.am
|
|
||||||
src/common/libdroid-util.pc.in
|
|
||||||
Copyright: 2013, 2017, Jolla Ltd.
|
|
||||||
License: LGPL-2.1
|
|
||||||
|
|
||||||
Files: src/droid/Makefile.am
|
|
||||||
Copyright: 2013, 2017, Jolla Ltd.
|
|
||||||
License: LGPL-2.1
|
|
||||||
|
|
||||||
License: GPL-2+
|
License: GPL-2+
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
|
|
|
||||||
|
|
@ -1,75 +0,0 @@
|
||||||
%define device sbj
|
|
||||||
%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-%{device}
|
|
||||||
|
|
||||||
Summary: PulseAudio Droid HAL modules
|
|
||||||
Version: %{pulsemajorminor}.92
|
|
||||||
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)
|
|
||||||
Provides: pulseaudio-modules-droid
|
|
||||||
|
|
||||||
%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
|
|
||||||
%setup -q -n %{name}-%{version}
|
|
||||||
|
|
||||||
%build
|
|
||||||
echo "%{moduleversion}" > .tarball-version
|
|
||||||
%reconfigure --disable-static --with-droid-device=%{device} --disable-xml
|
|
||||||
make %{?jobs:-j%jobs}
|
|
||||||
|
|
||||||
%install
|
|
||||||
rm -rf %{buildroot}
|
|
||||||
%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 %{_prefix}/include/pulsecore/modules/droid
|
|
||||||
%{_prefix}/include/pulsecore/modules/droid/version.h
|
|
||||||
%{_prefix}/include/pulsecore/modules/droid/conversion.h
|
|
||||||
%{_prefix}/include/pulsecore/modules/droid/droid-config.h
|
|
||||||
%{_prefix}/include/pulsecore/modules/droid/droid-util.h
|
|
||||||
%{_libdir}/pkgconfig/*.pc
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
Name: pulseaudio-modules-droid
|
Name: pulseaudio-modules-droid
|
||||||
|
|
||||||
Summary: PulseAudio Droid HAL modules
|
Summary: PulseAudio Droid HAL modules
|
||||||
Version: %{pulsemajorminor}.92
|
Version: %{pulsemajorminor}.97
|
||||||
Release: 1
|
Release: 1
|
||||||
License: LGPLv2+
|
License: LGPLv2+
|
||||||
URL: https://github.com/mer-hybris/pulseaudio-modules-droid
|
URL: https://github.com/mer-hybris/pulseaudio-modules-droid
|
||||||
|
|
@ -40,7 +40,7 @@ Requires: pulseaudio >= %{pulseversion}
|
||||||
This contains development files for PulseAudio droid modules.
|
This contains development files for PulseAudio droid modules.
|
||||||
|
|
||||||
%prep
|
%prep
|
||||||
%setup -q -n %{name}-%{version}
|
%autosetup -n %{name}-%{version}
|
||||||
|
|
||||||
%build
|
%build
|
||||||
echo "%{moduleversion}" > .tarball-version
|
echo "%{moduleversion}" > .tarball-version
|
||||||
|
|
@ -51,10 +51,9 @@ else
|
||||||
. %{_libdir}/droid-devel/hw-release.vars
|
. %{_libdir}/droid-devel/hw-release.vars
|
||||||
fi
|
fi
|
||||||
%reconfigure --disable-static --with-droid-device=$MER_HA_DEVICE
|
%reconfigure --disable-static --with-droid-device=$MER_HA_DEVICE
|
||||||
make %{?jobs:-j%jobs}
|
%make_build
|
||||||
|
|
||||||
%install
|
%install
|
||||||
rm -rf %{buildroot}
|
|
||||||
%make_install
|
%make_install
|
||||||
|
|
||||||
%files
|
%files
|
||||||
|
|
@ -72,9 +71,11 @@ rm -rf %{buildroot}
|
||||||
|
|
||||||
%files devel
|
%files devel
|
||||||
%defattr(-,root,root,-)
|
%defattr(-,root,root,-)
|
||||||
%dir %{_prefix}/include/pulsecore/modules/droid
|
%dir %{_includedir}/pulsecore/modules/droid
|
||||||
%{_prefix}/include/pulsecore/modules/droid/version.h
|
%{_includedir}/pulsecore/modules/droid/conversion.h
|
||||||
%{_prefix}/include/pulsecore/modules/droid/conversion.h
|
%{_includedir}/pulsecore/modules/droid/droid-config.h
|
||||||
%{_prefix}/include/pulsecore/modules/droid/droid-config.h
|
%{_includedir}/pulsecore/modules/droid/droid-util.h
|
||||||
%{_prefix}/include/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
|
%{_libdir}/pkgconfig/*.pc
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,9 @@ includedir = @includedir@/pulsecore/modules/droid
|
||||||
include_HEADERS = include/droid/version.h \
|
include_HEADERS = include/droid/version.h \
|
||||||
include/droid/conversion.h \
|
include/droid/conversion.h \
|
||||||
include/droid/droid-config.h \
|
include/droid/droid-config.h \
|
||||||
include/droid/droid-util.h
|
include/droid/droid-util.h \
|
||||||
|
include/droid/sllist.h \
|
||||||
|
include/droid/utils.h
|
||||||
|
|
||||||
pkgconfigdir = $(libdir)/pkgconfig
|
pkgconfigdir = $(libdir)/pkgconfig
|
||||||
pkgconfig_DATA = libdroid-util.pc
|
pkgconfig_DATA = libdroid-util.pc
|
||||||
|
|
@ -26,10 +28,11 @@ pkgconfig_DATA = libdroid-util.pc
|
||||||
libdroid_util_la_SOURCES = droid-util.c \
|
libdroid_util_la_SOURCES = droid-util.c \
|
||||||
droid-config.c \
|
droid-config.c \
|
||||||
conversion.c \
|
conversion.c \
|
||||||
config-parser-legacy.c \
|
|
||||||
config-parser-xml.c \
|
config-parser-xml.c \
|
||||||
droid-util-audio.h \
|
config-parser-xml.h \
|
||||||
droid-util-41qc.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_LDFLAGS = -avoid-version -Wl,-z,noexecstack -lhybris-common $(SBJ_DEVICE_LDFLAGS)
|
||||||
libdroid_util_la_LIBADD = $(AM_LIBADD)
|
libdroid_util_la_LIBADD = $(AM_LIBADD)
|
||||||
libdroid_util_la_CFLAGS = $(AM_CFLAGS)
|
libdroid_util_la_CFLAGS = $(AM_CFLAGS)
|
||||||
|
|
|
||||||
|
|
@ -1,436 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
|
||||||
*
|
|
||||||
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
|
||||||
*
|
|
||||||
* These PulseAudio Modules are free software; you can redistribute
|
|
||||||
* it and/or modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation
|
|
||||||
* version 2.1 of the License.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
|
||||||
* USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include <config.h>
|
|
||||||
#endif
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <pulsecore/macro.h>
|
|
||||||
#include <pulsecore/core-util.h>
|
|
||||||
#include <pulsecore/core-error.h>
|
|
||||||
#include <pulsecore/log.h>
|
|
||||||
#include <pulse/xmalloc.h>
|
|
||||||
|
|
||||||
#include <hardware_legacy/audio_policy_conf.h>
|
|
||||||
|
|
||||||
#include "droid/version.h"
|
|
||||||
#include "droid/droid-config.h"
|
|
||||||
#include "droid/conversion.h"
|
|
||||||
#include "droid/sllist.h"
|
|
||||||
|
|
||||||
/* Section defining custom global configuration variables. */
|
|
||||||
#define GLOBAL_CONFIG_EXT_TAG "custom_properties"
|
|
||||||
|
|
||||||
#define GAIN_TAG_PREFIX "gain_"
|
|
||||||
|
|
||||||
#define MAX_LINE_LENGTH (1024)
|
|
||||||
#define WHITESPACE "\n\r \t"
|
|
||||||
|
|
||||||
static void log_parse_error(const char *fn, const unsigned ln, const char *section, const char *v) {
|
|
||||||
pa_log("[%s:%u] failed to parse line in section %s: unknown section (%s)", fn, ln, section, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
pa_droid_config_audio *pa_parse_droid_audio_config_legacy(const char *filename) {
|
|
||||||
pa_droid_config_audio *config = NULL;
|
|
||||||
FILE *f;
|
|
||||||
unsigned n = 0;
|
|
||||||
bool ret = true;
|
|
||||||
char *full_line = NULL;
|
|
||||||
uint32_t hw_module_count = 0;
|
|
||||||
|
|
||||||
enum config_loc {
|
|
||||||
IN_ROOT = 0,
|
|
||||||
IN_GLOBAL = 1,
|
|
||||||
IN_GLOBAL_EXT = 2,
|
|
||||||
IN_HW_MODULES = 3,
|
|
||||||
IN_MODULE = 4,
|
|
||||||
IN_OUTPUT_INPUT = 5,
|
|
||||||
IN_CONFIG = 6,
|
|
||||||
IN_MODULE_GLOBAL = 10,
|
|
||||||
IN_DEVICES = 20,
|
|
||||||
IN_DEVICES_DEVICE = 21,
|
|
||||||
IN_GAINS = 22,
|
|
||||||
IN_GAIN_N = 23
|
|
||||||
} loc = IN_ROOT;
|
|
||||||
|
|
||||||
bool in_output = true;
|
|
||||||
|
|
||||||
pa_droid_config_hw_module *module = NULL;
|
|
||||||
pa_droid_config_device *output = NULL;
|
|
||||||
pa_droid_config_device *input = NULL;
|
|
||||||
|
|
||||||
pa_assert(filename);
|
|
||||||
|
|
||||||
f = fopen(filename, "r");
|
|
||||||
|
|
||||||
if (!f) {
|
|
||||||
pa_log_info("Failed to open config file (%s): %s", filename, pa_cstrerror(errno));
|
|
||||||
ret = false;
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
|
|
||||||
config = pa_xnew0(pa_droid_config_audio, 1);
|
|
||||||
config->global_config = pa_xnew0(pa_droid_config_global, 1);
|
|
||||||
|
|
||||||
pa_lock_fd(fileno(f), 1);
|
|
||||||
|
|
||||||
full_line = pa_xmalloc0(sizeof(char) * MAX_LINE_LENGTH);
|
|
||||||
|
|
||||||
while (!feof(f)) {
|
|
||||||
char *ln, *d, *v, *value;
|
|
||||||
|
|
||||||
if (!fgets(full_line, MAX_LINE_LENGTH, f))
|
|
||||||
break;
|
|
||||||
|
|
||||||
n++;
|
|
||||||
|
|
||||||
pa_strip_nl(full_line);
|
|
||||||
|
|
||||||
if (!*full_line)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ln = full_line + strspn(full_line, WHITESPACE);
|
|
||||||
|
|
||||||
if (ln[0] == '#')
|
|
||||||
continue;
|
|
||||||
|
|
||||||
v = ln;
|
|
||||||
d = v + strcspn(v, WHITESPACE);
|
|
||||||
|
|
||||||
value = d + strspn(d, WHITESPACE);
|
|
||||||
d[0] = '\0';
|
|
||||||
d = value + strcspn(value, WHITESPACE);
|
|
||||||
d[0] = '\0';
|
|
||||||
|
|
||||||
/* Enter section */
|
|
||||||
if (pa_streq(value, "{")) {
|
|
||||||
|
|
||||||
if (!*v) {
|
|
||||||
pa_log("[%s:%u] failed to parse line - too few words", filename, n);
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (loc) {
|
|
||||||
case IN_ROOT:
|
|
||||||
if (pa_streq(v, GLOBAL_CONFIG_TAG)) {
|
|
||||||
loc = IN_GLOBAL;
|
|
||||||
}
|
|
||||||
else if (pa_streq(v, AUDIO_HW_MODULE_TAG))
|
|
||||||
loc = IN_HW_MODULES;
|
|
||||||
else {
|
|
||||||
log_parse_error(filename, n, "<root>", v);
|
|
||||||
ret = false;
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IN_GLOBAL:
|
|
||||||
if (pa_streq(v, GLOBAL_CONFIG_EXT_TAG))
|
|
||||||
loc = IN_GLOBAL_EXT;
|
|
||||||
else {
|
|
||||||
log_parse_error(filename, n, GLOBAL_CONFIG_TAG, v);
|
|
||||||
ret = false;
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IN_HW_MODULES:
|
|
||||||
pa_assert(!module);
|
|
||||||
|
|
||||||
module = pa_droid_config_hw_module_new(config, v);
|
|
||||||
SLLIST_APPEND(pa_droid_config_hw_module, config->hw_modules, module);
|
|
||||||
hw_module_count++;
|
|
||||||
loc = IN_MODULE;
|
|
||||||
pa_log_debug("config: New module: %s", module->name);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IN_MODULE:
|
|
||||||
pa_assert(module);
|
|
||||||
|
|
||||||
if (pa_streq(v, OUTPUTS_TAG)) {
|
|
||||||
loc = IN_OUTPUT_INPUT;
|
|
||||||
in_output = true;
|
|
||||||
} else if (pa_streq(v, INPUTS_TAG)) {
|
|
||||||
loc = IN_OUTPUT_INPUT;
|
|
||||||
in_output = false;
|
|
||||||
} else if (pa_streq(v, GLOBAL_CONFIG_TAG)) {
|
|
||||||
loc = IN_MODULE_GLOBAL;
|
|
||||||
} else if (pa_streq(v, DEVICES_TAG)) {
|
|
||||||
loc = IN_DEVICES;
|
|
||||||
} else {
|
|
||||||
log_parse_error(filename, n, module->name, v);
|
|
||||||
ret = false;
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IN_OUTPUT_INPUT:
|
|
||||||
pa_assert(module);
|
|
||||||
|
|
||||||
if (in_output) {
|
|
||||||
output = pa_droid_config_device_new(module, PA_DIRECTION_OUTPUT, v);
|
|
||||||
SLLIST_APPEND(pa_droid_config_device, module->outputs, output);
|
|
||||||
loc = IN_CONFIG;
|
|
||||||
pa_log_debug("config: %s: New output: %s", module->name, output->name);
|
|
||||||
} else {
|
|
||||||
input = pa_droid_config_device_new(module, PA_DIRECTION_INPUT, v);
|
|
||||||
SLLIST_APPEND(pa_droid_config_device, module->inputs, input);
|
|
||||||
loc = IN_CONFIG;
|
|
||||||
pa_log_debug("config: %s: New input: %s", module->name, input->name);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IN_DEVICES:
|
|
||||||
/* TODO Missing implementation of parsing the module/devices section.
|
|
||||||
* As of now there is no need for the information, fix this when that
|
|
||||||
* changes. */
|
|
||||||
loc = IN_DEVICES_DEVICE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IN_DEVICES_DEVICE:
|
|
||||||
if (pa_streq(v, GAINS_TAG))
|
|
||||||
loc = IN_GAINS;
|
|
||||||
else {
|
|
||||||
log_parse_error(filename, n, DEVICES_TAG, v);
|
|
||||||
ret = false;
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IN_GAINS:
|
|
||||||
/* TODO Missing implementation of parsing the gain_n section.
|
|
||||||
* As of now there is no need for the information, fix this when that
|
|
||||||
* changes. */
|
|
||||||
if (pa_startswith(v, GAIN_TAG_PREFIX))
|
|
||||||
loc = IN_GAIN_N;
|
|
||||||
else {
|
|
||||||
log_parse_error(filename, n, GAINS_TAG, v);
|
|
||||||
ret = false;
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IN_CONFIG:
|
|
||||||
if (pa_streq(v, GAINS_TAG)) {
|
|
||||||
loc = IN_GAINS;
|
|
||||||
} else {
|
|
||||||
log_parse_error(filename, n, in_output ? output->name : input->name, v);
|
|
||||||
ret = false;
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
pa_log("[%s:%u] failed to parse line: unknown section (%s)", filename, n, v);
|
|
||||||
ret = false;
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Exit section */
|
|
||||||
if (pa_streq(v, "}")) {
|
|
||||||
switch (loc) {
|
|
||||||
case IN_ROOT:
|
|
||||||
pa_log("[%s:%u] failed to parse line - extra closing bracket", filename, n);
|
|
||||||
ret = false;
|
|
||||||
goto finish;
|
|
||||||
|
|
||||||
case IN_HW_MODULES:
|
|
||||||
/* fall through */
|
|
||||||
case IN_GLOBAL:
|
|
||||||
loc = IN_ROOT;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IN_MODULE:
|
|
||||||
module = NULL;
|
|
||||||
loc = IN_HW_MODULES;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IN_DEVICES:
|
|
||||||
/* fall through */
|
|
||||||
case IN_MODULE_GLOBAL:
|
|
||||||
loc = IN_MODULE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IN_GAINS:
|
|
||||||
if (output || input)
|
|
||||||
loc = IN_CONFIG;
|
|
||||||
else
|
|
||||||
loc = IN_DEVICES_DEVICE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IN_OUTPUT_INPUT:
|
|
||||||
if (in_output)
|
|
||||||
output = NULL;
|
|
||||||
else
|
|
||||||
input = NULL;
|
|
||||||
/* fall through */
|
|
||||||
case IN_GAIN_N:
|
|
||||||
/* fall through */
|
|
||||||
case IN_DEVICES_DEVICE:
|
|
||||||
/* fall through */
|
|
||||||
case IN_CONFIG:
|
|
||||||
/* fall through */
|
|
||||||
case IN_GLOBAL_EXT:
|
|
||||||
loc--;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Parsing of values */
|
|
||||||
if (loc == IN_GLOBAL ||
|
|
||||||
loc == IN_GLOBAL_EXT ||
|
|
||||||
loc == IN_MODULE_GLOBAL ||
|
|
||||||
loc == IN_CONFIG ||
|
|
||||||
loc == IN_DEVICES_DEVICE ||
|
|
||||||
loc == IN_GAIN_N) {
|
|
||||||
|
|
||||||
bool success = false;
|
|
||||||
|
|
||||||
if (loc == IN_GLOBAL || loc == IN_MODULE_GLOBAL) {
|
|
||||||
pa_droid_config_global *global_config = NULL;
|
|
||||||
|
|
||||||
if (loc == IN_MODULE_GLOBAL) {
|
|
||||||
pa_assert(module);
|
|
||||||
if (!module->global_config)
|
|
||||||
module->global_config = pa_xnew0(pa_droid_config_global, 1);
|
|
||||||
global_config = module->global_config;
|
|
||||||
} else
|
|
||||||
global_config = config->global_config;
|
|
||||||
|
|
||||||
pa_assert(global_config);
|
|
||||||
|
|
||||||
/* Parse global configuration */
|
|
||||||
|
|
||||||
if (pa_streq(v, ATTACHED_OUTPUT_DEVICES_TAG))
|
|
||||||
success = pa_conversion_parse_output_devices(filename, n, value, true, true,
|
|
||||||
&global_config->attached_output_devices);
|
|
||||||
else if (pa_streq(v, DEFAULT_OUTPUT_DEVICE_TAG))
|
|
||||||
success = pa_conversion_parse_output_devices(filename, n, value, true, true,
|
|
||||||
&global_config->default_output_device);
|
|
||||||
else if (pa_streq(v, ATTACHED_INPUT_DEVICES_TAG))
|
|
||||||
success = pa_conversion_parse_input_devices(filename, n, value, true, false,
|
|
||||||
&global_config->attached_input_devices);
|
|
||||||
else if (pa_streq(v, AUDIO_HAL_VERSION_TAG))
|
|
||||||
success = pa_conversion_parse_version(filename, n, value,
|
|
||||||
&global_config->audio_hal_version);
|
|
||||||
#ifdef SPEAKER_DRC_ENABLED_TAG
|
|
||||||
// SPEAKER_DRC_ENABLED_TAG is only from Android v4.4
|
|
||||||
else if (pa_streq(v, SPEAKER_DRC_ENABLED_TAG))
|
|
||||||
/* TODO - Add support for dynamic range control */
|
|
||||||
success = true; /* Do not fail while parsing speaker_drc_enabled entry */
|
|
||||||
#endif
|
|
||||||
else {
|
|
||||||
pa_log("[%s:%u] failed to parse line - unknown config entry %s", filename, n, v);
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (loc == IN_GLOBAL_EXT) {
|
|
||||||
|
|
||||||
/* Parse custom global configuration
|
|
||||||
* For now just log all custom variables, don't do
|
|
||||||
* anything with the values.
|
|
||||||
* TODO: Store custom values somehow */
|
|
||||||
|
|
||||||
pa_log_debug("[%s:%u] TODO custom variable: %s = %s", filename, n, v, value);
|
|
||||||
success = true;
|
|
||||||
|
|
||||||
} else if (loc == IN_CONFIG) {
|
|
||||||
|
|
||||||
/* Parse per-output or per-input configuration */
|
|
||||||
|
|
||||||
if ((in_output && !output) || (!in_output && !input)) {
|
|
||||||
pa_log("[%s:%u] failed to parse line", filename, n);
|
|
||||||
ret = false;
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pa_streq(v, SAMPLING_RATES_TAG))
|
|
||||||
success = pa_conversion_parse_sampling_rates(filename, n, value, true,
|
|
||||||
in_output ? output->sampling_rates : input->sampling_rates);
|
|
||||||
else if (pa_streq(v, FORMATS_TAG))
|
|
||||||
success = pa_conversion_parse_formats(filename, n, value, true,
|
|
||||||
in_output ? &output->formats : &input->formats);
|
|
||||||
else if (pa_streq(v, CHANNELS_TAG)) {
|
|
||||||
if (in_output)
|
|
||||||
success = pa_conversion_parse_output_channels(filename, n, value, true, &output->channel_masks);
|
|
||||||
else
|
|
||||||
success = pa_conversion_parse_input_channels(filename, n, value, true, &input->channel_masks);
|
|
||||||
} else if (pa_streq(v, DEVICES_TAG)) {
|
|
||||||
if (in_output)
|
|
||||||
success = pa_conversion_parse_output_devices(filename, n, value, true, false, &output->devices);
|
|
||||||
else
|
|
||||||
success = pa_conversion_parse_input_devices(filename, n, value, true, false, &input->devices);
|
|
||||||
} else if (pa_streq(v, FLAGS_TAG)) {
|
|
||||||
if (in_output)
|
|
||||||
success = pa_conversion_parse_output_flags(filename, n, value, &output->flags);
|
|
||||||
else {
|
|
||||||
#if AUDIO_API_VERSION_MAJ >= 3
|
|
||||||
success = pa_conversion_parse_input_flags(filename, n, value, &input->flags);
|
|
||||||
#else
|
|
||||||
pa_log("[%s:%u] failed to parse line - output flags inside input definition", filename, n);
|
|
||||||
success = false;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pa_log("[%s:%u] failed to parse line - unknown config entry %s", filename, n, v);
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (loc == IN_DEVICES_DEVICE) {
|
|
||||||
/* TODO Missing implementation of parsing the module/devices section.
|
|
||||||
* As of now there is no need for the information, fix this when that
|
|
||||||
* changes. */
|
|
||||||
success = true;
|
|
||||||
} else if (loc == IN_GAIN_N) {
|
|
||||||
/* TODO Missing implementation of parsing the gain_n section.
|
|
||||||
* As of now there is no need for the information, fix this when that
|
|
||||||
* changes. */
|
|
||||||
success = true;
|
|
||||||
} else
|
|
||||||
pa_assert_not_reached();
|
|
||||||
|
|
||||||
if (!success) {
|
|
||||||
ret = false;
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pa_log_info("Parsed config file (%s): %u modules.", filename, hw_module_count);
|
|
||||||
|
|
||||||
finish:
|
|
||||||
if (f) {
|
|
||||||
pa_lock_fd(fileno(f), 0);
|
|
||||||
fclose(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
pa_xfree(full_line);
|
|
||||||
|
|
||||||
if (!ret)
|
|
||||||
pa_droid_config_free(config), config = NULL;
|
|
||||||
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2022 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
||||||
*
|
*
|
||||||
|
|
@ -26,15 +26,6 @@
|
||||||
|
|
||||||
#include "droid/droid-config.h"
|
#include "droid/droid-config.h"
|
||||||
|
|
||||||
#ifndef HAVE_EXPAT
|
|
||||||
#include <unistd.h>
|
|
||||||
pa_droid_config_audio *pa_parse_droid_audio_config_xml(const char *filename) {
|
|
||||||
if (access(filename, F_OK) == 0)
|
|
||||||
pa_log_warn("Could not parse %s, xml configuration parsing support not compiled in", filename);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <expat.h>
|
#include <expat.h>
|
||||||
|
|
@ -46,6 +37,9 @@ pa_droid_config_audio *pa_parse_droid_audio_config_xml(const char *filename) {
|
||||||
|
|
||||||
#include "droid/conversion.h"
|
#include "droid/conversion.h"
|
||||||
#include "droid/sllist.h"
|
#include "droid/sllist.h"
|
||||||
|
#include "droid/utils.h"
|
||||||
|
#include "droid/droid-config.h"
|
||||||
|
#include "config-parser-xml.h"
|
||||||
|
|
||||||
#ifdef XML_UNICODE_WCHAR_T
|
#ifdef XML_UNICODE_WCHAR_T
|
||||||
# include <wchar.h>
|
# include <wchar.h>
|
||||||
|
|
@ -86,6 +80,9 @@ pa_droid_config_audio *pa_parse_droid_audio_config_xml(const char *filename) {
|
||||||
#define ATTRIBUTE_sources "sources"
|
#define ATTRIBUTE_sources "sources"
|
||||||
#define ATTRIBUTE_type "type"
|
#define ATTRIBUTE_type "type"
|
||||||
#define ATTRIBUTE_href "href"
|
#define ATTRIBUTE_href "href"
|
||||||
|
#define ATTRIBUTE_maxOpenCount "maxOpenCount"
|
||||||
|
#define ATTRIBUTE_maxActiveCount "maxActiveCount"
|
||||||
|
#define ATTRIBUTE_address "address"
|
||||||
|
|
||||||
#define PORT_TYPE_sink "sink"
|
#define PORT_TYPE_sink "sink"
|
||||||
#define PORT_TYPE_source "source"
|
#define PORT_TYPE_source "source"
|
||||||
|
|
@ -282,7 +279,7 @@ struct profile {
|
||||||
char *name;
|
char *name;
|
||||||
audio_format_t format;
|
audio_format_t format;
|
||||||
uint32_t sampling_rates[AUDIO_MAX_SAMPLING_RATES];
|
uint32_t sampling_rates[AUDIO_MAX_SAMPLING_RATES];
|
||||||
audio_channel_mask_t channel_masks;
|
audio_channel_mask_t channel_masks[AUDIO_MAX_CHANNEL_MASKS];
|
||||||
struct profile *next;
|
struct profile *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -290,6 +287,8 @@ struct mix_port {
|
||||||
char *name;
|
char *name;
|
||||||
char *role;
|
char *role;
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
|
int max_open_count;
|
||||||
|
int max_active_count;
|
||||||
struct profile *profiles;
|
struct profile *profiles;
|
||||||
struct mix_port *next;
|
struct mix_port *next;
|
||||||
};
|
};
|
||||||
|
|
@ -298,6 +297,7 @@ struct device_port {
|
||||||
char *tag_name;
|
char *tag_name;
|
||||||
audio_devices_t type;
|
audio_devices_t type;
|
||||||
char *role;
|
char *role;
|
||||||
|
char *address;
|
||||||
struct profile *profiles;
|
struct profile *profiles;
|
||||||
struct device_port *next;
|
struct device_port *next;
|
||||||
};
|
};
|
||||||
|
|
@ -403,6 +403,7 @@ static void device_port_list_free(struct device_port *list) {
|
||||||
profile_list_free(p->profiles);
|
profile_list_free(p->profiles);
|
||||||
pa_xfree(p->tag_name);
|
pa_xfree(p->tag_name);
|
||||||
pa_xfree(p->role);
|
pa_xfree(p->role);
|
||||||
|
pa_xfree(p->address);
|
||||||
pa_xfree(p);
|
pa_xfree(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -697,6 +698,8 @@ static bool parse_mix_port(struct parser_data *data, const char *element_name, c
|
||||||
struct mix_port *p;
|
struct mix_port *p;
|
||||||
bool parsed = false;
|
bool parsed = false;
|
||||||
char *flags = NULL;
|
char *flags = NULL;
|
||||||
|
char *max_open_count = NULL;
|
||||||
|
char *max_active_count = NULL;
|
||||||
|
|
||||||
p = pa_xmalloc0(sizeof(*p));
|
p = pa_xmalloc0(sizeof(*p));
|
||||||
|
|
||||||
|
|
@ -714,6 +717,14 @@ static bool parse_mix_port(struct parser_data *data, const char *element_name, c
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* maxOpenCount is not mandatory element attribute */
|
||||||
|
if (get_element_attr(data, attributes, false, ATTRIBUTE_maxOpenCount, &max_open_count))
|
||||||
|
pa_atoi(max_open_count, &p->max_open_count);
|
||||||
|
|
||||||
|
/* maxActiveCount is not mandatory element attribute */
|
||||||
|
if (get_element_attr(data, attributes, false, ATTRIBUTE_maxActiveCount, &max_active_count))
|
||||||
|
pa_atoi(max_open_count, &p->max_active_count);
|
||||||
|
|
||||||
parsed = true;
|
parsed = true;
|
||||||
done:
|
done:
|
||||||
pa_xfree(flags);
|
pa_xfree(flags);
|
||||||
|
|
@ -729,20 +740,9 @@ done:
|
||||||
return parsed;
|
return parsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void replace_in_place(char **string, const char *a, const char *b) {
|
|
||||||
char *tmp;
|
|
||||||
|
|
||||||
pa_assert(*string);
|
|
||||||
pa_assert(a);
|
|
||||||
pa_assert(b);
|
|
||||||
|
|
||||||
tmp = pa_replace(*string, a, b);
|
|
||||||
pa_xfree(*string);
|
|
||||||
*string = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool parse_profile(struct parser_data *data, const char *element_name, const XML_Char **attributes) {
|
static bool parse_profile(struct parser_data *data, const char *element_name, const XML_Char **attributes) {
|
||||||
struct profile *p;
|
struct profile *p;
|
||||||
|
int channel_count = -1;
|
||||||
bool parsed = false, unknown_format = false, output = true;
|
bool parsed = false, unknown_format = false, output = true;
|
||||||
char *samplingRates = NULL, *channelMasks = NULL, *format = NULL;
|
char *samplingRates = NULL, *channelMasks = NULL, *format = NULL;
|
||||||
|
|
||||||
|
|
@ -775,24 +775,24 @@ static bool parse_profile(struct parser_data *data, const char *element_name, co
|
||||||
if (output && pa_startswith(channelMasks, "AUDIO_CHANNEL_IN_")) {
|
if (output && pa_startswith(channelMasks, "AUDIO_CHANNEL_IN_")) {
|
||||||
pa_log_info("[%s:%u] Output has wrong direction channel mask (%s), reversing.",
|
pa_log_info("[%s:%u] Output has wrong direction channel mask (%s), reversing.",
|
||||||
data->fn, data->lineno, channelMasks);
|
data->fn, data->lineno, channelMasks);
|
||||||
replace_in_place(&channelMasks, "AUDIO_CHANNEL_IN_", "AUDIO_CHANNEL_OUT_");
|
dm_replace_in_place(&channelMasks, "AUDIO_CHANNEL_IN_", "AUDIO_CHANNEL_OUT_");
|
||||||
}
|
}
|
||||||
else if (!output && pa_startswith(channelMasks, "AUDIO_CHANNEL_OUT_")) {
|
else if (!output && pa_startswith(channelMasks, "AUDIO_CHANNEL_OUT_")) {
|
||||||
pa_log_info("[%s:%u] Input has wrong direction channel mask (%s), reversing.",
|
pa_log_info("[%s:%u] Input has wrong direction channel mask (%s), reversing.",
|
||||||
data->fn, data->lineno, channelMasks);
|
data->fn, data->lineno, channelMasks);
|
||||||
replace_in_place(&channelMasks, "AUDIO_CHANNEL_OUT_", "AUDIO_CHANNEL_IN_");
|
dm_replace_in_place(&channelMasks, "AUDIO_CHANNEL_OUT_", "AUDIO_CHANNEL_IN_");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pa_conversion_parse_sampling_rates(data->fn, data->lineno, samplingRates, false, p->sampling_rates))
|
if (!pa_conversion_parse_sampling_rates(data->fn, data->lineno, samplingRates, p->sampling_rates))
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (!pa_conversion_parse_formats(data->fn, data->lineno, format, false, &p->format))
|
if (!pa_conversion_parse_formats(data->fn, data->lineno, format, &p->format))
|
||||||
unknown_format = true;
|
unknown_format = true;
|
||||||
|
|
||||||
if (!unknown_format && channelMasks && !(output ?
|
if (!unknown_format && channelMasks && (channel_count = output ?
|
||||||
pa_conversion_parse_output_channels(data->fn, data->lineno, channelMasks, false, &p->channel_masks)
|
pa_conversion_parse_output_channels(data->fn, data->lineno, channelMasks, p->channel_masks)
|
||||||
: pa_conversion_parse_input_channels(data->fn, data->lineno, channelMasks, false, &p->channel_masks)))
|
: pa_conversion_parse_input_channels(data->fn, data->lineno, channelMasks, p->channel_masks)) == -1)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
parsed = true;
|
parsed = true;
|
||||||
|
|
@ -801,7 +801,10 @@ done:
|
||||||
pa_xfree(channelMasks);
|
pa_xfree(channelMasks);
|
||||||
pa_xfree(format);
|
pa_xfree(format);
|
||||||
|
|
||||||
if (!parsed) {
|
if (channel_count == 0) {
|
||||||
|
pa_log_info("[%s:%u] Ignore profile with no supported channels.", data->fn, data->lineno);
|
||||||
|
profile_list_free(p);
|
||||||
|
} else if (!parsed) {
|
||||||
pa_log_error("[%s:%u] Failed to parse element <" ELEMENT_profile ">", data->fn, data->lineno);
|
pa_log_error("[%s:%u] Failed to parse element <" ELEMENT_profile ">", data->fn, data->lineno);
|
||||||
profile_list_free(p);
|
profile_list_free(p);
|
||||||
} else if (unknown_format) {
|
} else if (unknown_format) {
|
||||||
|
|
@ -836,10 +839,13 @@ static bool parse_device_port(struct parser_data *data, const char *element_name
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (!(pa_streq(d->role, ATTRIBUTE_sink) ?
|
if (!(pa_streq(d->role, ATTRIBUTE_sink) ?
|
||||||
pa_conversion_parse_output_devices(data->fn, data->lineno, type, false, false, &d->type)
|
pa_conversion_parse_output_devices(data->fn, data->lineno, type, false, &d->type)
|
||||||
: pa_conversion_parse_input_devices(data->fn, data->lineno, type, false, false, &d->type)))
|
: pa_conversion_parse_input_devices(data->fn, data->lineno, type, false, &d->type)))
|
||||||
unknown_device = true;
|
unknown_device = true;
|
||||||
|
|
||||||
|
/* address is not mandatory element attribute */
|
||||||
|
get_element_attr(data, attributes, false, ATTRIBUTE_address, &d->address);
|
||||||
|
|
||||||
parsed = true;
|
parsed = true;
|
||||||
done:
|
done:
|
||||||
pa_xfree(type);
|
pa_xfree(type);
|
||||||
|
|
@ -949,133 +955,184 @@ done:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct device_port *find_device_port(struct module *module, const char *name) {
|
static void generate_config_profiles(struct profile *profiles, dm_list *list) {
|
||||||
struct device_port *port;
|
|
||||||
|
|
||||||
SLLIST_FOREACH(port, module->device_ports) {
|
|
||||||
if (pa_streq(port->tag_name, name))
|
|
||||||
return port;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool device_in_list(struct device *list, const char *name) {
|
|
||||||
struct device *dev;
|
|
||||||
|
|
||||||
pa_assert(name);
|
|
||||||
|
|
||||||
SLLIST_FOREACH(dev, list) {
|
|
||||||
if (pa_streq(name, dev->name))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void add_output(struct module *module, struct mix_port *mix_port, pa_droid_config_hw_module *hw_module) {
|
|
||||||
pa_droid_config_device *output;
|
|
||||||
struct profile *profile;
|
struct profile *profile;
|
||||||
struct route *route;
|
|
||||||
struct device_port *device_port;
|
|
||||||
|
|
||||||
output = pa_droid_config_device_new(hw_module, PA_DIRECTION_OUTPUT, mix_port->name);
|
SLLIST_FOREACH(profile, profiles) {
|
||||||
output->flags = mix_port->flags;
|
dm_config_profile *c_profile = pa_xnew0(dm_config_profile, 1);
|
||||||
SLLIST_FOREACH(profile, mix_port->profiles) {
|
c_profile->name = pa_xstrdup(profile->name ? profile->name : "");
|
||||||
memcpy(output->sampling_rates, profile->sampling_rates, sizeof(output->sampling_rates));
|
c_profile->format = profile->format;
|
||||||
output->channel_masks |= profile->channel_masks;
|
memcpy(c_profile->sampling_rates,
|
||||||
output->formats |= profile->format;
|
profile->sampling_rates,
|
||||||
|
sizeof(c_profile->sampling_rates));
|
||||||
|
memcpy(c_profile->channel_masks,
|
||||||
|
profile->channel_masks,
|
||||||
|
sizeof(c_profile->channel_masks));
|
||||||
|
dm_list_push_back(list, c_profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
SLLIST_FOREACH(route, module->routes) {
|
|
||||||
struct device *source;
|
|
||||||
SLLIST_FOREACH(source, route->sources) {
|
|
||||||
if (pa_streq(source->name, mix_port->name)) {
|
|
||||||
if ((device_port = find_device_port(module, route->sink))) {
|
|
||||||
output->devices |= device_port->type;
|
|
||||||
if (device_in_list(module->attached_devices, device_port->tag_name))
|
|
||||||
hw_module->global_config->attached_output_devices |= device_port->type;
|
|
||||||
if (device_in_list(module->default_output, device_port->tag_name))
|
|
||||||
hw_module->global_config->default_output_device |= device_port->type;
|
|
||||||
break;
|
|
||||||
} else
|
|
||||||
pa_log_info("Couldn't find matching <" ELEMENT_devicePort " tagName=%s> for <" ELEMENT_mixPort " name=%s>",
|
|
||||||
route->sink, source->name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pa_log_debug("config: %s: New output: %s", hw_module->name, output->name);
|
|
||||||
SLLIST_APPEND(pa_droid_config_device, hw_module->outputs, output);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void add_input(struct module *module, struct mix_port *mix_port, pa_droid_config_hw_module *hw_module) {
|
static dm_config_port *config_device_port_new(dm_config_module *module,
|
||||||
pa_droid_config_device *input;
|
struct device_port *device_port) {
|
||||||
struct profile *profile;
|
dm_config_port *c_device_port = pa_xnew0(dm_config_port, 1);
|
||||||
struct route *route;
|
|
||||||
struct device_port *device_port;
|
|
||||||
|
|
||||||
input = pa_droid_config_device_new(hw_module, PA_DIRECTION_INPUT, mix_port->name);
|
c_device_port->module = module;
|
||||||
input->flags = mix_port->flags;
|
c_device_port->port_type = DM_CONFIG_TYPE_DEVICE_PORT;
|
||||||
SLLIST_FOREACH(profile, mix_port->profiles) {
|
c_device_port->name = pa_xstrdup(device_port->tag_name);
|
||||||
memcpy(input->sampling_rates, profile->sampling_rates, sizeof(input->sampling_rates));
|
c_device_port->type = device_port->type;
|
||||||
input->channel_masks |= profile->channel_masks;
|
c_device_port->role = pa_safe_streq(device_port->role, "sink") ? DM_CONFIG_ROLE_SINK : DM_CONFIG_ROLE_SOURCE;
|
||||||
input->formats |= profile->format;
|
c_device_port->address = pa_xstrdup(device_port->address ? device_port->address : "");
|
||||||
}
|
c_device_port->profiles = dm_list_new();
|
||||||
|
if (device_port->profiles->next)
|
||||||
|
pa_log("More than 1 profile for devicePort %s, ignoring extra profiles.", device_port->tag_name);
|
||||||
|
generate_config_profiles(device_port->profiles, c_device_port->profiles);
|
||||||
|
|
||||||
SLLIST_FOREACH(route, module->routes) {
|
return c_device_port;
|
||||||
if (pa_streq(route->sink, mix_port->name)) {
|
|
||||||
struct device *source;
|
|
||||||
SLLIST_FOREACH(source, route->sources) {
|
|
||||||
if ((device_port = find_device_port(module, source->name))) {
|
|
||||||
input->devices |= device_port->type;
|
|
||||||
if (device_in_list(module->attached_devices, device_port->tag_name))
|
|
||||||
hw_module->global_config->attached_input_devices |= device_port->type;
|
|
||||||
} else
|
|
||||||
pa_log_info("Couldn't find matching <" ELEMENT_mixPort " name=%s> for <" ELEMENT_devicePort " tagName=%s>",
|
|
||||||
source->name, route->sink);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pa_log_debug("config: %s: New input: %s", hw_module->name, input->name);
|
|
||||||
SLLIST_APPEND(pa_droid_config_device, hw_module->inputs, input);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void generate_config_for_module(struct module *module, pa_droid_config_audio *config) {
|
static dm_config_port *config_mix_port_new(dm_config_module *module,
|
||||||
pa_droid_config_hw_module *hw_module;
|
struct mix_port *mix_port) {
|
||||||
|
dm_config_port *c_mix_port = pa_xnew0(dm_config_port, 1);
|
||||||
|
|
||||||
|
c_mix_port->module = module;
|
||||||
|
c_mix_port->port_type = DM_CONFIG_TYPE_MIX_PORT;
|
||||||
|
c_mix_port->name = pa_xstrdup(mix_port->name);
|
||||||
|
c_mix_port->role = pa_safe_streq(mix_port->role, "sink") ? DM_CONFIG_ROLE_SINK : DM_CONFIG_ROLE_SOURCE;
|
||||||
|
c_mix_port->flags = mix_port->flags;
|
||||||
|
c_mix_port->max_open_count = mix_port->max_open_count;
|
||||||
|
c_mix_port->max_active_count = mix_port->max_active_count;
|
||||||
|
c_mix_port->profiles = dm_list_new();
|
||||||
|
generate_config_profiles(mix_port->profiles, c_mix_port->profiles);
|
||||||
|
|
||||||
|
return c_mix_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void generate_config_for_module(struct module *module, dm_config_device *config) {
|
||||||
|
dm_config_module *c_module;
|
||||||
struct mix_port *mix_port;
|
struct mix_port *mix_port;
|
||||||
|
struct device_port *device_port;
|
||||||
|
struct device *device;
|
||||||
|
struct route *route;
|
||||||
|
|
||||||
pa_assert(module);
|
pa_assert(module);
|
||||||
pa_assert(config);
|
pa_assert(config);
|
||||||
pa_assert(config->global_config);
|
|
||||||
|
|
||||||
hw_module = pa_droid_config_hw_module_new(config, module->name);
|
c_module = pa_xnew0(dm_config_module, 1);
|
||||||
if (module->attached_devices || module->default_output)
|
c_module->config = config;
|
||||||
hw_module->global_config = pa_xnew0(pa_droid_config_global, 1);
|
c_module->name = pa_xstrdup(module->name);
|
||||||
SLLIST_APPEND(pa_droid_config_hw_module, config->hw_modules, hw_module);
|
c_module->version_major = 0; /* Not used */
|
||||||
|
c_module->version_minor = 0; /* Not used */
|
||||||
|
c_module->attached_devices = dm_list_new();
|
||||||
|
c_module->mix_ports = dm_list_new();
|
||||||
|
c_module->device_ports = dm_list_new();
|
||||||
|
c_module->ports = dm_list_new();
|
||||||
|
c_module->routes = dm_list_new();
|
||||||
|
|
||||||
|
/* Device ports */
|
||||||
|
|
||||||
|
SLLIST_FOREACH(device_port, module->device_ports) {
|
||||||
|
dm_config_port *c_device_port;
|
||||||
|
|
||||||
|
if (!device_port->profiles) {
|
||||||
|
pa_log("No profile defined for devicePort %s", device_port->tag_name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
c_device_port = config_device_port_new(c_module, device_port);
|
||||||
|
dm_list_push_back(c_module->ports, c_device_port);
|
||||||
|
dm_list_push_back(c_module->device_ports, c_device_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Attached devices */
|
||||||
|
|
||||||
|
SLLIST_FOREACH(device, module->attached_devices) {
|
||||||
|
dm_config_port *c_device_port;
|
||||||
|
void *state;
|
||||||
|
|
||||||
|
DM_LIST_FOREACH_DATA(c_device_port, c_module->device_ports, state) {
|
||||||
|
if (pa_safe_streq(c_device_port->name, device->name)) {
|
||||||
|
dm_list_push_back(c_module->attached_devices, c_device_port);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Default output device */
|
||||||
|
|
||||||
|
if (module->default_output) {
|
||||||
|
dm_config_port *c_device_port;
|
||||||
|
void *state;
|
||||||
|
|
||||||
|
DM_LIST_FOREACH_DATA(c_device_port, c_module->device_ports, state) {
|
||||||
|
if (pa_safe_streq(c_device_port->name, module->default_output->name)) {
|
||||||
|
c_module->default_output_device = c_device_port;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mix ports */
|
||||||
|
|
||||||
SLLIST_FOREACH(mix_port, module->mix_ports) {
|
SLLIST_FOREACH(mix_port, module->mix_ports) {
|
||||||
if (pa_streq(mix_port->role, PORT_TYPE_source))
|
dm_config_port *c_mix_port = config_mix_port_new(c_module, mix_port);
|
||||||
add_output(module, mix_port, hw_module);
|
dm_list_push_back(c_module->ports, c_mix_port);
|
||||||
else if (pa_streq(mix_port->role, ATTRIBUTE_sink))
|
dm_list_push_back(c_module->mix_ports, c_mix_port);
|
||||||
add_input(module, mix_port, hw_module);
|
|
||||||
else
|
|
||||||
pa_log_warn("Unknown <" ELEMENT_mixPort "> role \"%s\"", mix_port->role);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Routes */
|
||||||
|
|
||||||
|
SLLIST_FOREACH(route, module->routes) {
|
||||||
|
dm_config_route *c_route = pa_xnew0(dm_config_route, 1);
|
||||||
|
dm_config_port *c_port;
|
||||||
|
void *state;
|
||||||
|
c_route->sources = dm_list_new();
|
||||||
|
|
||||||
|
if (!pa_safe_streq(route->type, "mix"))
|
||||||
|
pa_log("Unknown route type %s.", route->type);
|
||||||
|
c_route->type = DM_CONFIG_TYPE_MIX;
|
||||||
|
|
||||||
|
DM_LIST_FOREACH_DATA(c_port, c_module->ports, state) {
|
||||||
|
if (pa_safe_streq(route->sink, c_port->name)) {
|
||||||
|
c_route->sink = c_port;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SLLIST_FOREACH(device, route->sources) {
|
||||||
|
DM_LIST_FOREACH_DATA(c_port, c_module->ports, state) {
|
||||||
|
if (pa_safe_streq(device->name, c_port->name)) {
|
||||||
|
dm_list_push_back(c_route->sources, c_port);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dm_list_push_back(c_module->routes, c_route);
|
||||||
|
}
|
||||||
|
|
||||||
|
dm_list_push_back(config->modules, c_module);
|
||||||
}
|
}
|
||||||
|
|
||||||
static pa_droid_config_audio *convert_config(struct audio_policy_configuration *source) {
|
static dm_config_device *process_config(struct audio_policy_configuration *source) {
|
||||||
pa_droid_config_audio *config = NULL;
|
dm_config_device *config = NULL;
|
||||||
|
struct global_configuration *global_config;
|
||||||
struct module *module;
|
struct module *module;
|
||||||
|
|
||||||
pa_assert(source);
|
pa_assert(source);
|
||||||
|
|
||||||
config = pa_xnew0(pa_droid_config_audio, 1);
|
config = pa_xnew0(dm_config_device, 1);
|
||||||
config->global_config = pa_xnew0(pa_droid_config_global, 1);
|
config->global_config = dm_list_new();
|
||||||
|
config->modules = dm_list_new();
|
||||||
|
|
||||||
|
pa_log_debug("Process configuration ...");
|
||||||
|
|
||||||
|
SLLIST_FOREACH(global_config, source->global) {
|
||||||
|
dm_config_global *c_global = pa_xnew0(dm_config_global, 1);
|
||||||
|
c_global->key = pa_xstrdup(global_config->key);
|
||||||
|
c_global->value = pa_xstrdup(global_config->value);
|
||||||
|
dm_list_push_back(config->global_config, c_global);
|
||||||
|
};
|
||||||
|
|
||||||
pa_log_debug("Convert configuration ...");
|
|
||||||
SLLIST_FOREACH(module, source->modules)
|
SLLIST_FOREACH(module, source->modules)
|
||||||
generate_config_for_module(module, config);
|
generate_config_for_module(module, config);
|
||||||
|
|
||||||
|
|
@ -1107,8 +1164,8 @@ static char *build_path(const char *base_file, const char *filename) {
|
||||||
return fn;
|
return fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
pa_droid_config_audio *pa_parse_droid_audio_config_xml(const char *filename) {
|
dm_config_device *pa_parse_droid_audio_config_xml(const char *filename) {
|
||||||
pa_droid_config_audio *config = NULL;
|
dm_config_device *config = NULL;
|
||||||
struct parser_data data;
|
struct parser_data data;
|
||||||
bool ret = true;
|
bool ret = true;
|
||||||
|
|
||||||
|
|
@ -1140,7 +1197,7 @@ pa_droid_config_audio *pa_parse_droid_audio_config_xml(const char *filename) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
config = convert_config(data.conf);
|
config = process_config(data.conf);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if (data.conf)
|
if (data.conf)
|
||||||
|
|
@ -1148,5 +1205,3 @@ done:
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
||||||
33
src/common/config-parser-xml.h
Normal file
33
src/common/config-parser-xml.h
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef foodroidconfigparserxmlfoo
|
||||||
|
#define foodroidconfigparserxmlfoo
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 <droid/droid-config.h>
|
||||||
|
|
||||||
|
dm_config_device *pa_parse_droid_audio_config_xml(const char *filename);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2013-2018 Jolla Ltd.
|
* Copyright (C) 2013-2022 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
||||||
*
|
*
|
||||||
|
|
@ -55,7 +55,7 @@ CONVERT_FUNC(format);
|
||||||
CONVERT_FUNC(output_channel);
|
CONVERT_FUNC(output_channel);
|
||||||
CONVERT_FUNC(input_channel);
|
CONVERT_FUNC(input_channel);
|
||||||
|
|
||||||
#define value_separator(legacy) (legacy ? "|" : ",")
|
#define VALUE_SEPARATOR ","
|
||||||
|
|
||||||
static bool string_convert_num_to_str(const struct string_conversion *list, const uint32_t value, const char **to_str) {
|
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(list);
|
||||||
|
|
@ -88,18 +88,7 @@ static char *list_string(struct string_conversion *list, uint32_t flags) {
|
||||||
char *str = NULL;
|
char *str = NULL;
|
||||||
char *tmp;
|
char *tmp;
|
||||||
|
|
||||||
#if AUDIO_API_VERSION_MAJ >= 2
|
|
||||||
if (flags & AUDIO_DEVICE_BIT_IN)
|
|
||||||
flags &= ~AUDIO_DEVICE_BIT_IN;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (unsigned int i = 0; list[i].str; i++) {
|
for (unsigned int i = 0; list[i].str; i++) {
|
||||||
#if AUDIO_API_VERSION_MAJ >= 2
|
|
||||||
if (list[i].value & AUDIO_DEVICE_BIT_IN) {
|
|
||||||
if (popcount(list[i].value & ~AUDIO_DEVICE_BIT_IN) != 1)
|
|
||||||
continue;
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
if (popcount(list[i].value) != 1)
|
if (popcount(list[i].value) != 1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
@ -140,6 +129,40 @@ bool pa_string_convert_num_to_str(pa_conversion_string_t type, uint32_t value, c
|
||||||
|
|
||||||
case CONV_STRING_INPUT_FLAG:
|
case CONV_STRING_INPUT_FLAG:
|
||||||
return string_convert_num_to_str(string_conversion_table_input_flag, value, to_str);
|
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();
|
pa_assert_not_reached();
|
||||||
|
|
@ -155,10 +178,6 @@ bool pa_string_convert_output_device_str_to_num(const char *str, audio_devices_t
|
||||||
return string_convert_str_to_num(string_conversion_table_output_device, str, (uint32_t*) to_value);
|
return string_convert_str_to_num(string_conversion_table_output_device, str, (uint32_t*) to_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *pa_list_string_output_device(audio_devices_t devices) {
|
|
||||||
return list_string(string_conversion_table_output_device, devices);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Input device */
|
/* Input device */
|
||||||
bool pa_string_convert_input_device_num_to_str(audio_devices_t value, const char **to_str) {
|
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);
|
return string_convert_num_to_str(string_conversion_table_input_device, (uint32_t) value, to_str);
|
||||||
|
|
@ -168,10 +187,6 @@ bool pa_string_convert_input_device_str_to_num(const char *str, audio_devices_t
|
||||||
return string_convert_str_to_num(string_conversion_table_input_device, str, (uint32_t*) to_value);
|
return string_convert_str_to_num(string_conversion_table_input_device, str, (uint32_t*) to_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *pa_list_string_input_device(audio_devices_t devices) {
|
|
||||||
return list_string(string_conversion_table_input_device, devices);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Flags */
|
/* Flags */
|
||||||
bool pa_string_convert_flag_num_to_str(audio_output_flags_t value, const char **to_str) {
|
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);
|
return string_convert_num_to_str(string_conversion_table_output_flag, (uint32_t) value, to_str);
|
||||||
|
|
@ -187,13 +202,9 @@ char *pa_list_string_flags(audio_output_flags_t flags) {
|
||||||
|
|
||||||
bool pa_input_device_default_audio_source(audio_devices_t input_device, audio_source_t *default_source)
|
bool pa_input_device_default_audio_source(audio_devices_t input_device, audio_source_t *default_source)
|
||||||
{
|
{
|
||||||
#if AUDIO_API_VERSION_MAJ >= 2
|
|
||||||
input_device &= ~AUDIO_DEVICE_BIT_IN;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Note converting HAL values to different HAL values! */
|
/* 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++) {
|
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) {
|
if (conversion_table_default_audio_source[i][0] == input_device) {
|
||||||
*default_source = conversion_table_default_audio_source[i][1];
|
*default_source = conversion_table_default_audio_source[i][1];
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -210,10 +221,6 @@ 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);
|
return string_convert_num_to_str(string_conversion_table_input_device_fancy, (uint32_t) value, to_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pa_droid_audio_source_name(audio_source_t value, const char **to_str) {
|
|
||||||
return string_convert_num_to_str(string_conversion_table_audio_source_fancy, (uint32_t) value, to_str);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int parse_list(const struct string_conversion *table,
|
static int parse_list(const struct string_conversion *table,
|
||||||
const char *separator,
|
const char *separator,
|
||||||
const char *str,
|
const char *str,
|
||||||
|
|
@ -280,6 +287,10 @@ int pa_conversion_parse_list(pa_conversion_string_t type, const char *separator,
|
||||||
|
|
||||||
case CONV_STRING_INPUT_FLAG:
|
case CONV_STRING_INPUT_FLAG:
|
||||||
return parse_list(string_conversion_table_input_flag, separator, str, dst, unknown_entries);
|
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();
|
pa_assert_not_reached();
|
||||||
|
|
@ -287,7 +298,7 @@ int pa_conversion_parse_list(pa_conversion_string_t type, const char *separator,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pa_conversion_parse_sampling_rates(const char *fn, const unsigned ln,
|
bool pa_conversion_parse_sampling_rates(const char *fn, const unsigned ln,
|
||||||
const char *str, bool legacy,
|
const char *str,
|
||||||
uint32_t sampling_rates[AUDIO_MAX_SAMPLING_RATES]) {
|
uint32_t sampling_rates[AUDIO_MAX_SAMPLING_RATES]) {
|
||||||
pa_assert(fn);
|
pa_assert(fn);
|
||||||
pa_assert(str);
|
pa_assert(str);
|
||||||
|
|
@ -296,16 +307,14 @@ bool pa_conversion_parse_sampling_rates(const char *fn, const unsigned ln,
|
||||||
const char *state = NULL;
|
const char *state = NULL;
|
||||||
|
|
||||||
uint32_t pos = 0;
|
uint32_t pos = 0;
|
||||||
while ((entry = pa_split(str, value_separator(legacy), &state))) {
|
while ((entry = pa_split(str, VALUE_SEPARATOR, &state))) {
|
||||||
int32_t val;
|
int32_t val;
|
||||||
|
|
||||||
#if AUDIO_API_VERSION_MAJ >= 3
|
|
||||||
if (pos == 0 && pa_streq(entry, "dynamic")) {
|
if (pos == 0 && pa_streq(entry, "dynamic")) {
|
||||||
sampling_rates[pos++] = (uint32_t) -1;
|
sampling_rates[pos++] = (uint32_t) -1;
|
||||||
pa_xfree(entry);
|
pa_xfree(entry);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
if (pos == AUDIO_MAX_SAMPLING_RATES) {
|
if (pos == AUDIO_MAX_SAMPLING_RATES) {
|
||||||
pa_log("[%s:%u] Too many sample rate entries (> %d)", fn, ln, AUDIO_MAX_SAMPLING_RATES);
|
pa_log("[%s:%u] Too many sample rate entries (> %d)", fn, ln, AUDIO_MAX_SAMPLING_RATES);
|
||||||
|
|
@ -355,7 +364,7 @@ static bool check_and_log(const char *fn, const unsigned ln, const char *field,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pa_conversion_parse_formats(const char *fn, const unsigned ln,
|
bool pa_conversion_parse_formats(const char *fn, const unsigned ln,
|
||||||
const char *str, bool legacy,
|
const char *str,
|
||||||
audio_format_t *formats) {
|
audio_format_t *formats) {
|
||||||
int count;
|
int count;
|
||||||
char *unknown = NULL;
|
char *unknown = NULL;
|
||||||
|
|
@ -364,18 +373,13 @@ bool pa_conversion_parse_formats(const char *fn, const unsigned ln,
|
||||||
pa_assert(str);
|
pa_assert(str);
|
||||||
pa_assert(formats);
|
pa_assert(formats);
|
||||||
|
|
||||||
#if AUDIO_API_VERSION_MAJ >= 3
|
|
||||||
/* Needs to be probed later */
|
/* Needs to be probed later */
|
||||||
if (pa_streq(str, "dynamic")) {
|
if (pa_streq(str, "dynamic")) {
|
||||||
*formats = 0;
|
*formats = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
count = pa_conversion_parse_list(CONV_STRING_FORMAT, value_separator(legacy), str, formats, &unknown);
|
count = pa_conversion_parse_list(CONV_STRING_FORMAT, VALUE_SEPARATOR, str, formats, &unknown);
|
||||||
|
|
||||||
if (legacy)
|
|
||||||
return check_and_log(fn, ln, "formats", count, str, unknown, false);
|
|
||||||
|
|
||||||
/* As the new XML configuration lists formats as one per profile, unknown
|
/* 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
|
* formats will cause the parser to quit. As a workaround for non-legacy
|
||||||
|
|
@ -384,44 +388,70 @@ bool pa_conversion_parse_formats(const char *fn, const unsigned ln,
|
||||||
return count > 0;
|
return count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool parse_channels(const char *fn, const unsigned ln,
|
static int parse_channels(const char *fn, const unsigned ln,
|
||||||
const char *str, bool in_output,
|
const char *str, bool in_output,
|
||||||
bool legacy, audio_channel_mask_t *channels) {
|
audio_channel_mask_t channel_masks[AUDIO_MAX_CHANNEL_MASKS]) {
|
||||||
int count;
|
bool success;
|
||||||
|
int count = 0;
|
||||||
char *unknown = NULL;
|
char *unknown = NULL;
|
||||||
|
char *entry;
|
||||||
|
const char *state = NULL;
|
||||||
|
|
||||||
pa_assert(fn);
|
pa_assert(fn);
|
||||||
pa_assert(str);
|
pa_assert(str);
|
||||||
pa_assert(channels);
|
|
||||||
|
|
||||||
/* Needs to be probed later */
|
/* Needs to be probed later */
|
||||||
if (pa_streq(str, "dynamic")) {
|
if (pa_streq(str, "dynamic")) {
|
||||||
*channels = 0;
|
channel_masks[0] = 0;
|
||||||
return true;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
count = pa_conversion_parse_list(in_output ? CONV_STRING_OUTPUT_CHANNELS : CONV_STRING_INPUT_CHANNELS,
|
while ((entry = pa_split(str, VALUE_SEPARATOR, &state))) {
|
||||||
value_separator(legacy), str, channels, &unknown);
|
uint32_t val;
|
||||||
|
|
||||||
return check_and_log(fn, ln, in_output ? "output channel_masks" : "input channel_masks",
|
if (count == AUDIO_MAX_CHANNEL_MASKS) {
|
||||||
count, str, unknown, false);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pa_conversion_parse_output_channels(const char *fn, const unsigned ln,
|
int pa_conversion_parse_output_channels(const char *fn, const unsigned ln,
|
||||||
const char *str, bool legacy,
|
const char *str,
|
||||||
audio_channel_mask_t *channels) {
|
audio_channel_mask_t channel_masks[AUDIO_MAX_CHANNEL_MASKS]) {
|
||||||
return parse_channels(fn, ln, str, true, legacy, channels);
|
return parse_channels(fn, ln, str, true, channel_masks);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pa_conversion_parse_input_channels(const char *fn, const unsigned ln,
|
int pa_conversion_parse_input_channels(const char *fn, const unsigned ln,
|
||||||
const char *str, bool legacy,
|
const char *str,
|
||||||
audio_channel_mask_t *channels) {
|
audio_channel_mask_t channel_masks[AUDIO_MAX_CHANNEL_MASKS]) {
|
||||||
return parse_channels(fn, ln, str, false, legacy, channels);
|
return parse_channels(fn, ln, str, false, channel_masks);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool parse_devices(const char *fn, const unsigned ln,
|
static bool parse_devices(const char *fn, const unsigned ln,
|
||||||
const char *str, bool in_output,
|
const char *str, bool in_output,
|
||||||
bool legacy, bool must_recognize_all,
|
bool must_recognize_all,
|
||||||
audio_devices_t *devices) {
|
audio_devices_t *devices) {
|
||||||
int count;
|
int count;
|
||||||
char *unknown = NULL;
|
char *unknown = NULL;
|
||||||
|
|
@ -431,11 +461,7 @@ static bool parse_devices(const char *fn, const unsigned ln,
|
||||||
pa_assert(devices);
|
pa_assert(devices);
|
||||||
|
|
||||||
count = pa_conversion_parse_list(in_output ? CONV_STRING_OUTPUT_DEVICE : CONV_STRING_INPUT_DEVICE,
|
count = pa_conversion_parse_list(in_output ? CONV_STRING_OUTPUT_DEVICE : CONV_STRING_INPUT_DEVICE,
|
||||||
value_separator(legacy), str, devices, &unknown);
|
VALUE_SEPARATOR, str, devices, &unknown);
|
||||||
|
|
||||||
if (legacy)
|
|
||||||
return check_and_log(fn, ln, in_output ? "output devices" : "input devices",
|
|
||||||
count, str, unknown, must_recognize_all);
|
|
||||||
|
|
||||||
/* As the new XML configuration lists devices as one per devicePort, unknown
|
/* 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
|
* devices will cause the parser to quit. As a workaround for non-legacy
|
||||||
|
|
@ -446,15 +472,15 @@ static bool parse_devices(const char *fn, const unsigned ln,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pa_conversion_parse_output_devices(const char *fn, const unsigned ln,
|
bool pa_conversion_parse_output_devices(const char *fn, const unsigned ln,
|
||||||
char *str, bool legacy, bool must_recognize_all,
|
char *str, bool must_recognize_all,
|
||||||
audio_devices_t *devices) {
|
audio_devices_t *devices) {
|
||||||
return parse_devices(fn, ln, str, true, legacy, must_recognize_all, devices);
|
return parse_devices(fn, ln, str, true, must_recognize_all, devices);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pa_conversion_parse_input_devices(const char *fn, const unsigned ln,
|
bool pa_conversion_parse_input_devices(const char *fn, const unsigned ln,
|
||||||
char *str, bool legacy, bool must_recognize_all,
|
char *str, bool must_recognize_all,
|
||||||
audio_devices_t *devices) {
|
audio_devices_t *devices) {
|
||||||
return parse_devices(fn, ln, str, false, legacy, must_recognize_all, devices);
|
return parse_devices(fn, ln, str, false, must_recognize_all, devices);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pa_conversion_parse_output_flags(const char *fn, const unsigned ln,
|
bool pa_conversion_parse_output_flags(const char *fn, const unsigned ln,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2013-2018 Jolla Ltd.
|
* Copyright (C) 2013-2022 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
||||||
*
|
*
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
#include "droid/version.h"
|
#include "droid/version.h"
|
||||||
#include "droid/droid-config.h"
|
#include "droid/droid-config.h"
|
||||||
#include "droid/sllist.h"
|
#include "droid/sllist.h"
|
||||||
|
#include "config-parser-xml.h"
|
||||||
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
@ -36,52 +37,28 @@
|
||||||
#include <valgrind/memcheck.h>
|
#include <valgrind/memcheck.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <pulse/rtclock.h>
|
|
||||||
#include <pulse/timeval.h>
|
|
||||||
#include <pulse/volume.h>
|
|
||||||
#include <pulse/xmalloc.h>
|
#include <pulse/xmalloc.h>
|
||||||
|
|
||||||
#include <pulsecore/core.h>
|
|
||||||
#include <pulsecore/core-error.h>
|
|
||||||
#include <pulsecore/i18n.h>
|
|
||||||
#include <pulsecore/module.h>
|
|
||||||
#include <pulsecore/memchunk.h>
|
|
||||||
#include <pulsecore/sink.h>
|
|
||||||
#include <pulsecore/modargs.h>
|
|
||||||
#include <pulsecore/core-rtclock.h>
|
|
||||||
#include <pulsecore/core-util.h>
|
#include <pulsecore/core-util.h>
|
||||||
#include <pulsecore/sample-util.h>
|
|
||||||
#include <pulsecore/log.h>
|
#include <pulsecore/log.h>
|
||||||
#include <pulsecore/macro.h>
|
#include <pulsecore/macro.h>
|
||||||
#include <pulsecore/thread.h>
|
#include <pulsecore/modargs.h>
|
||||||
#include <pulsecore/thread-mq.h>
|
|
||||||
#include <pulsecore/rtpoll.h>
|
|
||||||
#include <pulsecore/time-smoother.h>
|
|
||||||
#include <pulsecore/refcnt.h>
|
|
||||||
#include <pulsecore/shared.h>
|
|
||||||
#include <pulsecore/mutex.h>
|
|
||||||
#include <pulsecore/strlist.h>
|
|
||||||
#include <pulsecore/atomic.h>
|
|
||||||
|
|
||||||
#include <hardware/audio.h>
|
#include <hardware/audio.h>
|
||||||
#include <hardware_legacy/audio_policy_conf.h>
|
|
||||||
|
|
||||||
#define ODM_AUDIO_POLICY_CONFIG_XML_FILE "/odm/etc/audio_policy_configuration.xml"
|
#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_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 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"
|
#define SYSTEM_AUDIO_POLICY_CONFIG_XML_FILE "/system/etc/audio_policy_configuration.xml"
|
||||||
|
|
||||||
|
|
||||||
pa_droid_config_audio *pa_droid_config_load(pa_modargs *ma) {
|
dm_config_device *dm_config_load(pa_modargs *ma) {
|
||||||
pa_droid_config_audio *config = NULL;
|
dm_config_device *config = NULL;
|
||||||
const char *manual_config;
|
const char *manual_config;
|
||||||
const char *config_location[] = {
|
const char *config_location[] = {
|
||||||
ODM_AUDIO_POLICY_CONFIG_XML_FILE,
|
ODM_AUDIO_POLICY_CONFIG_XML_FILE,
|
||||||
VENDOR_AUDIO_AUDIO_POLICY_CONFIG_XML_FILE,
|
VENDOR_AUDIO_AUDIO_POLICY_CONFIG_XML_FILE,
|
||||||
VENDOR_AUDIO_POLICY_CONFIG_XML_FILE,
|
VENDOR_AUDIO_POLICY_CONFIG_XML_FILE,
|
||||||
AUDIO_POLICY_VENDOR_CONFIG_FILE,
|
|
||||||
SYSTEM_AUDIO_POLICY_CONFIG_XML_FILE,
|
SYSTEM_AUDIO_POLICY_CONFIG_XML_FILE,
|
||||||
AUDIO_POLICY_CONFIG_FILE,
|
|
||||||
NULL};
|
NULL};
|
||||||
|
|
||||||
pa_assert(ma);
|
pa_assert(ma);
|
||||||
|
|
@ -106,92 +83,210 @@ pa_droid_config_audio *pa_droid_config_load(pa_modargs *ma) {
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
pa_droid_config_audio *pa_droid_config_dup(const pa_droid_config_audio *config) {
|
static dm_config_profile *config_profile_dup(const dm_config_profile *profile) {
|
||||||
pa_droid_config_audio *config_copy;
|
dm_config_profile *copy = pa_xnew0(dm_config_profile, 1);
|
||||||
pa_droid_config_hw_module *module, *module_copy;
|
|
||||||
pa_droid_config_device *device, *device_copy;
|
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);
|
pa_assert(config);
|
||||||
|
|
||||||
config_copy = pa_xnew0(pa_droid_config_audio, 1);
|
copy = pa_xnew0(dm_config_device, 1);
|
||||||
|
copy->global_config = dm_list_new();
|
||||||
|
copy->modules = dm_list_new();
|
||||||
|
|
||||||
if (config->global_config)
|
if (config->global_config) {
|
||||||
config_copy->global_config = pa_xmemdup(config->global_config, sizeof(*config->global_config));
|
dm_config_global *global, *global_copy;
|
||||||
|
|
||||||
SLLIST_FOREACH(module, config->hw_modules) {
|
DM_LIST_FOREACH_DATA(global, config->global_config, state) {
|
||||||
module_copy = pa_droid_config_hw_module_new(config_copy, module->name);
|
global_copy = pa_xnew0(dm_config_global, 1);
|
||||||
if (module->global_config)
|
global_copy->key = pa_xstrdup(global->key);
|
||||||
module_copy->global_config = pa_xmemdup(module->global_config, sizeof(*module->global_config));
|
global_copy->value = pa_xstrdup(global->value);
|
||||||
|
dm_list_push_back(copy->global_config, global_copy);
|
||||||
SLLIST_FOREACH(device, module->outputs) {
|
|
||||||
device_copy = pa_xmemdup(device, sizeof(*device));
|
|
||||||
device_copy->module = module_copy;
|
|
||||||
device_copy->name = pa_xstrdup(device->name);
|
|
||||||
SLLIST_APPEND(pa_droid_config_device, module_copy->outputs, device_copy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SLLIST_FOREACH(device, module->inputs) {
|
|
||||||
device_copy = pa_xmemdup(device, sizeof(*device));
|
|
||||||
device_copy->module = module_copy;
|
|
||||||
device_copy->name = pa_xstrdup(device->name);
|
|
||||||
SLLIST_APPEND(pa_droid_config_device, module_copy->inputs, device_copy);
|
|
||||||
}
|
|
||||||
|
|
||||||
SLLIST_APPEND(pa_droid_config_hw_module, config_copy->hw_modules, module_copy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return config_copy;
|
DM_LIST_FOREACH_DATA(module, config->modules, state)
|
||||||
|
dm_list_push_back(copy->modules, config_module_dup(module));
|
||||||
|
|
||||||
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
pa_droid_config_audio *pa_parse_droid_audio_config(const char *filename) {
|
dm_config_device *pa_parse_droid_audio_config(const char *filename) {
|
||||||
const char *suffix;
|
return pa_parse_droid_audio_config_xml(filename);
|
||||||
|
|
||||||
pa_assert(filename);
|
|
||||||
|
|
||||||
if ((suffix = rindex(filename, '.'))) {
|
|
||||||
if (strlen(suffix) == 4 && pa_streq(suffix, ".xml"))
|
|
||||||
return pa_parse_droid_audio_config_xml(filename);
|
|
||||||
else if (strlen(suffix) == 5 && pa_streq(suffix, ".conf"))
|
|
||||||
return pa_parse_droid_audio_config_legacy(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pa_droid_config_free(pa_droid_config_audio *config) {
|
static void config_global_free(void *data) {
|
||||||
pa_droid_config_hw_module *module;
|
dm_config_global *global = data;
|
||||||
pa_droid_config_device *device;
|
|
||||||
|
|
||||||
|
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)
|
if (!config)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
while (config->hw_modules) {
|
dm_list_free(config->global_config, config_global_free);
|
||||||
SLLIST_STEAL_FIRST(module, config->hw_modules);
|
dm_list_free(config->modules, config_module_free);
|
||||||
|
|
||||||
while (module->outputs) {
|
|
||||||
SLLIST_STEAL_FIRST(device, module->outputs);
|
|
||||||
pa_droid_config_device_free(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (module->inputs) {
|
|
||||||
SLLIST_STEAL_FIRST(device, module->inputs);
|
|
||||||
pa_droid_config_device_free(device);
|
|
||||||
}
|
|
||||||
|
|
||||||
pa_droid_config_hw_module_free(module);
|
|
||||||
}
|
|
||||||
|
|
||||||
pa_xfree(config->global_config);
|
|
||||||
pa_xfree(config);
|
pa_xfree(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
const pa_droid_config_hw_module *pa_droid_config_find_module(const pa_droid_config_audio *config, const char* module_id) {
|
dm_config_module *dm_config_find_module(dm_config_device *config, const char* module_id) {
|
||||||
pa_droid_config_hw_module *module;
|
dm_config_module *module;
|
||||||
|
void *state;
|
||||||
|
|
||||||
pa_assert(config);
|
pa_assert(config);
|
||||||
pa_assert(module_id);
|
pa_assert(module_id);
|
||||||
|
|
||||||
SLLIST_FOREACH(module, config->hw_modules) {
|
DM_LIST_FOREACH_DATA(module, config->modules, state) {
|
||||||
if (pa_streq(module_id, module->name))
|
if (pa_streq(module_id, module->name))
|
||||||
return module;
|
return module;
|
||||||
}
|
}
|
||||||
|
|
@ -199,71 +294,73 @@ const pa_droid_config_hw_module *pa_droid_config_find_module(const pa_droid_conf
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const pa_droid_config_device *find_device(const pa_droid_config_hw_module *module, bool output, const char* device_name) {
|
dm_config_port *dm_config_find_port(dm_config_module *module, const char* name) {
|
||||||
pa_droid_config_device *device;
|
dm_config_port *port;
|
||||||
|
void *state;
|
||||||
|
|
||||||
pa_assert(module);
|
pa_assert(module);
|
||||||
pa_assert(device_name);
|
pa_assert(name);
|
||||||
|
|
||||||
SLLIST_FOREACH(device, output ? module->outputs : module->inputs) {
|
DM_LIST_FOREACH_DATA(port, module->ports, state) {
|
||||||
if (pa_streq(device_name, device->name))
|
if (pa_streq(name, port->name))
|
||||||
return device;
|
return port;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const pa_droid_config_device *pa_droid_config_find_output(const pa_droid_config_hw_module *module, const char* output_name) {
|
dm_config_port *dm_config_default_output_device(dm_config_module *module) {
|
||||||
return find_device(module, true, output_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
const pa_droid_config_device *pa_droid_config_find_input(const pa_droid_config_hw_module *module, const char* input_name) {
|
|
||||||
return find_device(module, false, input_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
pa_droid_config_hw_module *pa_droid_config_hw_module_new(const pa_droid_config_audio *config, const char *name) {
|
|
||||||
pa_droid_config_hw_module *hw_module;
|
|
||||||
|
|
||||||
pa_assert(config);
|
|
||||||
pa_assert(name);
|
|
||||||
|
|
||||||
hw_module = pa_xnew0(pa_droid_config_hw_module, 1);
|
|
||||||
hw_module->config = config;
|
|
||||||
hw_module->name = pa_xstrndup(name, AUDIO_HARDWARE_MODULE_ID_MAX_LEN);
|
|
||||||
|
|
||||||
return hw_module;
|
|
||||||
}
|
|
||||||
|
|
||||||
void pa_droid_config_hw_module_free(pa_droid_config_hw_module *hw_module) {
|
|
||||||
if (!hw_module)
|
|
||||||
return;
|
|
||||||
|
|
||||||
pa_xfree(hw_module->name);
|
|
||||||
pa_xfree(hw_module->global_config);
|
|
||||||
pa_xfree(hw_module);
|
|
||||||
}
|
|
||||||
|
|
||||||
pa_droid_config_device *pa_droid_config_device_new(const pa_droid_config_hw_module *module,
|
|
||||||
pa_direction_t direction,
|
|
||||||
const char *name) {
|
|
||||||
pa_droid_config_device *device;
|
|
||||||
|
|
||||||
pa_assert(module);
|
pa_assert(module);
|
||||||
pa_assert(direction == PA_DIRECTION_OUTPUT || direction == PA_DIRECTION_INPUT);
|
|
||||||
pa_assert(name);
|
|
||||||
|
|
||||||
device = pa_xnew0(pa_droid_config_device, 1);
|
if (module->default_output_device)
|
||||||
device->module = module;
|
return module->default_output_device;
|
||||||
device->direction = direction;
|
else {
|
||||||
device->name = pa_replace(name, " ", "_");
|
pa_log("Module %s doesn't have default output device.", module->name);
|
||||||
|
return 0;
|
||||||
return device;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pa_droid_config_device_free(pa_droid_config_device *device) {
|
char *dm_config_escape_string(const char *string) {
|
||||||
if (!device)
|
if (!string)
|
||||||
return;
|
return NULL;
|
||||||
|
|
||||||
pa_xfree(device->name);
|
/* Just replace whitespace with underscores for now. */
|
||||||
pa_xfree(device);
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,311 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2013 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 _ANDROID_UTIL_V412_H_
|
|
||||||
#define _ANDROID_UTIL_V412_H_
|
|
||||||
|
|
||||||
#ifdef DROID_DEVICE_SBJ
|
|
||||||
#define QCOM_HARDWARE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <hardware/audio.h>
|
|
||||||
#include <hardware_legacy/audio_policy_conf.h>
|
|
||||||
|
|
||||||
#include <pulse/channelmap.h>
|
|
||||||
|
|
||||||
// PulseAudio value - Android value
|
|
||||||
|
|
||||||
uint32_t conversion_table_output_channel[][2] = {
|
|
||||||
{ 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. */
|
|
||||||
{ 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 }
|
|
||||||
};
|
|
||||||
|
|
||||||
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 }
|
|
||||||
};
|
|
||||||
|
|
||||||
uint32_t conversion_table_default_audio_source[][2] = {
|
|
||||||
{ AUDIO_DEVICE_IN_ALL, AUDIO_SOURCE_DEFAULT }
|
|
||||||
};
|
|
||||||
|
|
||||||
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 */
|
|
||||||
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 }
|
|
||||||
};
|
|
||||||
|
|
||||||
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 */
|
|
||||||
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),
|
|
||||||
STRING_ENTRY(AUDIO_DEVICE_IN_DEFAULT),
|
|
||||||
/* Combination entries consisting of multiple devices defined above.
|
|
||||||
* These don't require counterpart in string_conversion_table_input_device_fancy. */
|
|
||||||
STRING_ENTRY(AUDIO_DEVICE_IN_ALL),
|
|
||||||
STRING_ENTRY(AUDIO_DEVICE_IN_ALL_SCO),
|
|
||||||
{ 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_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" },
|
|
||||||
{ AUDIO_DEVICE_IN_DEFAULT, "input-default" },
|
|
||||||
{ 0, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
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_FM_RX, "fm rx" },
|
|
||||||
{ 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),
|
|
||||||
/* Qualcomm flags */
|
|
||||||
STRING_ENTRY(AUDIO_OUTPUT_FLAG_LPA),
|
|
||||||
STRING_ENTRY(AUDIO_OUTPUT_FLAG_TUNNEL),
|
|
||||||
STRING_ENTRY(AUDIO_OUTPUT_FLAG_VOIP_RX),
|
|
||||||
{ 0, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct string_conversion string_conversion_table_input_flag[] = {
|
|
||||||
{ 0, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Channels */
|
|
||||||
struct string_conversion string_conversion_table_output_channels[] = {
|
|
||||||
STRING_ENTRY(AUDIO_CHANNEL_OUT_FRONT_LEFT),
|
|
||||||
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 }
|
|
||||||
};
|
|
||||||
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 */
|
|
||||||
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
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2017 Jolla Ltd.
|
* Copyright (C) 2017-2022 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
||||||
*
|
*
|
||||||
|
|
@ -28,7 +28,6 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <hardware/audio.h>
|
#include <hardware/audio.h>
|
||||||
#include <hardware_legacy/audio_policy_conf.h>
|
|
||||||
|
|
||||||
#include <pulse/channelmap.h>
|
#include <pulse/channelmap.h>
|
||||||
|
|
||||||
|
|
@ -102,18 +101,33 @@ uint32_t conversion_table_default_audio_source[][2] = {
|
||||||
{ AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_SOURCE_MIC },
|
{ AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_SOURCE_MIC },
|
||||||
{ AUDIO_DEVICE_IN_AUX_DIGITAL, AUDIO_SOURCE_MIC },
|
{ AUDIO_DEVICE_IN_AUX_DIGITAL, AUDIO_SOURCE_MIC },
|
||||||
{ AUDIO_DEVICE_IN_VOICE_CALL, AUDIO_SOURCE_VOICE_CALL },
|
{ 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_BACK_MIC, AUDIO_SOURCE_MIC },
|
||||||
{ AUDIO_DEVICE_IN_REMOTE_SUBMIX, AUDIO_SOURCE_REMOTE_SUBMIX },
|
{ 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)
|
#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 },
|
{ AUDIO_DEVICE_IN_FM_RX, AUDIO_SOURCE_FM_RX },
|
||||||
#endif
|
#endif
|
||||||
#if defined(HAVE_ENUM_AUDIO_DEVICE_IN_FM_TUNER) && defined(HAVE_ENUM_AUDIO_SOURCE_FM_TUNER)
|
|
||||||
{ AUDIO_DEVICE_IN_FM_TUNER, AUDIO_SOURCE_FM_TUNER },
|
|
||||||
#endif
|
|
||||||
#if defined(HAVE_ENUM_AUDIO_DEVICE_IN_FM_RX_A2DP) && defined(HAVE_ENUM_AUDIO_SOURCE_FM_RX_A2DP)
|
#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 },
|
{ AUDIO_DEVICE_IN_FM_RX_A2DP, AUDIO_SOURCE_FM_RX_A2DP },
|
||||||
#endif
|
#endif
|
||||||
{ AUDIO_DEVICE_IN_ALL, AUDIO_SOURCE_DEFAULT }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Output devices */
|
/* Output devices */
|
||||||
|
|
@ -136,30 +150,30 @@ struct string_conversion string_conversion_table_output_device[] = {
|
||||||
STRING_ENTRY( AUDIO_DEVICE_OUT_USB_ACCESSORY ),
|
STRING_ENTRY( AUDIO_DEVICE_OUT_USB_ACCESSORY ),
|
||||||
STRING_ENTRY( AUDIO_DEVICE_OUT_USB_DEVICE ),
|
STRING_ENTRY( AUDIO_DEVICE_OUT_USB_DEVICE ),
|
||||||
STRING_ENTRY( AUDIO_DEVICE_OUT_REMOTE_SUBMIX ),
|
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 ),
|
STRING_ENTRY( AUDIO_DEVICE_OUT_DEFAULT ),
|
||||||
|
|
||||||
/* Devices which may or may not be defined for all devices,
|
{ 0, NULL }
|
||||||
* update configure.ac CC_CHECK_DROID_ENUM list if you encounter new ones. */
|
};
|
||||||
STRING_ENTRY_IF_AUDIO_DEVICE_OUT_HDMI
|
|
||||||
STRING_ENTRY_IF_AUDIO_DEVICE_OUT_HDMI_ARC
|
|
||||||
STRING_ENTRY_IF_AUDIO_DEVICE_OUT_TELEPHONY_TX
|
|
||||||
STRING_ENTRY_IF_AUDIO_DEVICE_OUT_LINE
|
|
||||||
STRING_ENTRY_IF_AUDIO_DEVICE_OUT_SPDIF
|
|
||||||
STRING_ENTRY_IF_AUDIO_DEVICE_OUT_AUX_LINE
|
|
||||||
STRING_ENTRY_IF_AUDIO_DEVICE_OUT_SPEAKER_SAFE
|
|
||||||
STRING_ENTRY_IF_AUDIO_DEVICE_OUT_FM
|
|
||||||
STRING_ENTRY_IF_AUDIO_DEVICE_OUT_FM_TX
|
|
||||||
STRING_ENTRY_IF_AUDIO_DEVICE_OUT_ANC_HEADSET
|
|
||||||
STRING_ENTRY_IF_AUDIO_DEVICE_OUT_ANC_HEADPHONE
|
|
||||||
STRING_ENTRY_IF_AUDIO_DEVICE_OUT_PROXY
|
|
||||||
STRING_ENTRY_IF_AUDIO_DEVICE_OUT_IP
|
|
||||||
|
|
||||||
/* Combination entries consisting of multiple devices defined above.
|
struct string_conversion string_conversion_table_audio_mode_fancy[] = {
|
||||||
* These don't require counterpart in string_conversion_table_output_device_fancy. */
|
{ AUDIO_MODE_NORMAL, "normal" },
|
||||||
STRING_ENTRY( AUDIO_DEVICE_OUT_ALL ),
|
{ AUDIO_MODE_RINGTONE, "ringtone" },
|
||||||
STRING_ENTRY( AUDIO_DEVICE_OUT_ALL_A2DP ),
|
{ AUDIO_MODE_IN_CALL, "in call" },
|
||||||
STRING_ENTRY( AUDIO_DEVICE_OUT_ALL_SCO ),
|
{ AUDIO_MODE_IN_COMMUNICATION, "in communication" },
|
||||||
STRING_ENTRY( AUDIO_DEVICE_OUT_ALL_USB ),
|
{ AUDIO_MODE_CALL_SCREEN, "call screen" },
|
||||||
|
|
||||||
{ 0, NULL }
|
{ 0, NULL }
|
||||||
};
|
};
|
||||||
|
|
@ -167,8 +181,6 @@ struct string_conversion string_conversion_table_output_device[] = {
|
||||||
struct string_conversion string_conversion_table_output_device_fancy[] = {
|
struct string_conversion string_conversion_table_output_device_fancy[] = {
|
||||||
{ AUDIO_DEVICE_OUT_EARPIECE, "output-earpiece" },
|
{ AUDIO_DEVICE_OUT_EARPIECE, "output-earpiece" },
|
||||||
{ AUDIO_DEVICE_OUT_SPEAKER, "output-speaker" },
|
{ 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_HEADSET, "output-wired_headset" },
|
||||||
{ AUDIO_DEVICE_OUT_WIRED_HEADPHONE, "output-wired_headphone" },
|
{ AUDIO_DEVICE_OUT_WIRED_HEADPHONE, "output-wired_headphone" },
|
||||||
{ AUDIO_DEVICE_OUT_BLUETOOTH_SCO, "output-bluetooth_sco" },
|
{ AUDIO_DEVICE_OUT_BLUETOOTH_SCO, "output-bluetooth_sco" },
|
||||||
|
|
@ -183,23 +195,21 @@ struct string_conversion string_conversion_table_output_device_fancy[] = {
|
||||||
{ AUDIO_DEVICE_OUT_USB_ACCESSORY, "output-usb_accessory" },
|
{ AUDIO_DEVICE_OUT_USB_ACCESSORY, "output-usb_accessory" },
|
||||||
{ AUDIO_DEVICE_OUT_USB_DEVICE, "output-usb_device" },
|
{ AUDIO_DEVICE_OUT_USB_DEVICE, "output-usb_device" },
|
||||||
{ AUDIO_DEVICE_OUT_REMOTE_SUBMIX, "output-remote_submix" },
|
{ 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" },
|
{ AUDIO_DEVICE_OUT_DEFAULT, "output-default" },
|
||||||
|
|
||||||
/* Devices which may or may not be defined for all devices, */
|
|
||||||
FANCY_ENTRY_IF_AUDIO_DEVICE_OUT_HDMI ( "output-hdmi" )
|
|
||||||
FANCY_ENTRY_IF_AUDIO_DEVICE_OUT_HDMI_ARC ( "output-hdmi_arc" )
|
|
||||||
FANCY_ENTRY_IF_AUDIO_DEVICE_OUT_TELEPHONY_TX ( "output-telephony_tx" )
|
|
||||||
FANCY_ENTRY_IF_AUDIO_DEVICE_OUT_LINE ( "output-line" )
|
|
||||||
FANCY_ENTRY_IF_AUDIO_DEVICE_OUT_SPDIF ( "output-spdif" )
|
|
||||||
FANCY_ENTRY_IF_AUDIO_DEVICE_OUT_AUX_LINE ( "output-aux_line" )
|
|
||||||
FANCY_ENTRY_IF_AUDIO_DEVICE_OUT_SPEAKER_SAFE ( "output-speaker_safe" )
|
|
||||||
FANCY_ENTRY_IF_AUDIO_DEVICE_OUT_FM ( "output-fm" )
|
|
||||||
FANCY_ENTRY_IF_AUDIO_DEVICE_OUT_FM_TX ( "output-fm_tx" )
|
|
||||||
FANCY_ENTRY_IF_AUDIO_DEVICE_OUT_ANC_HEADSET ( "output-and_headset" )
|
|
||||||
FANCY_ENTRY_IF_AUDIO_DEVICE_OUT_ANC_HEADPHONE ( "output-anc_headphone" )
|
|
||||||
FANCY_ENTRY_IF_AUDIO_DEVICE_OUT_PROXY ( "output-proxy" )
|
|
||||||
FANCY_ENTRY_IF_AUDIO_DEVICE_OUT_IP ( "output-ip" )
|
|
||||||
|
|
||||||
{ 0, NULL }
|
{ 0, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -213,39 +223,33 @@ struct string_conversion string_conversion_table_input_device[] = {
|
||||||
STRING_ENTRY( AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET ),
|
STRING_ENTRY( AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET ),
|
||||||
STRING_ENTRY( AUDIO_DEVICE_IN_WIRED_HEADSET ),
|
STRING_ENTRY( AUDIO_DEVICE_IN_WIRED_HEADSET ),
|
||||||
STRING_ENTRY( AUDIO_DEVICE_IN_AUX_DIGITAL ),
|
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_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_BACK_MIC ),
|
||||||
STRING_ENTRY( AUDIO_DEVICE_IN_REMOTE_SUBMIX ),
|
STRING_ENTRY( AUDIO_DEVICE_IN_REMOTE_SUBMIX ),
|
||||||
STRING_ENTRY( AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET ),
|
STRING_ENTRY( AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET ),
|
||||||
STRING_ENTRY( AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET ),
|
STRING_ENTRY( AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET ),
|
||||||
STRING_ENTRY( AUDIO_DEVICE_IN_USB_ACCESSORY ),
|
STRING_ENTRY( AUDIO_DEVICE_IN_USB_ACCESSORY ),
|
||||||
STRING_ENTRY( AUDIO_DEVICE_IN_USB_DEVICE ),
|
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 ),
|
STRING_ENTRY( AUDIO_DEVICE_IN_DEFAULT ),
|
||||||
|
|
||||||
/* Devices which may or may not be defined for all devices,
|
/* Devices which may or may not be defined for all devices. */
|
||||||
* update configure.ac CC_CHECK_DROID_ENUM list if you encounter new ones. */
|
|
||||||
STRING_ENTRY_IF_AUDIO_DEVICE_IN_HDMI
|
|
||||||
STRING_ENTRY_IF_AUDIO_DEVICE_IN_TELEPHONY_RX
|
|
||||||
STRING_ENTRY_IF_AUDIO_DEVICE_IN_FM_TUNER
|
|
||||||
STRING_ENTRY_IF_AUDIO_DEVICE_IN_TV_TUNER
|
|
||||||
STRING_ENTRY_IF_AUDIO_DEVICE_IN_LINE
|
|
||||||
STRING_ENTRY_IF_AUDIO_DEVICE_IN_SPDIF
|
|
||||||
STRING_ENTRY_IF_AUDIO_DEVICE_IN_BLUETOOTH_A2DP
|
|
||||||
STRING_ENTRY_IF_AUDIO_DEVICE_IN_LOOPBACK
|
|
||||||
STRING_ENTRY_IF_AUDIO_DEVICE_IN_PROXY
|
|
||||||
STRING_ENTRY_IF_AUDIO_DEVICE_IN_FM_RX
|
STRING_ENTRY_IF_AUDIO_DEVICE_IN_FM_RX
|
||||||
STRING_ENTRY_IF_AUDIO_DEVICE_IN_FM_RX_A2DP
|
STRING_ENTRY_IF_AUDIO_DEVICE_IN_FM_RX_A2DP
|
||||||
STRING_ENTRY_IF_AUDIO_DEVICE_IN_IP
|
|
||||||
|
|
||||||
#ifdef DROID_AUDIO_HAL_SECONDARY_MIC
|
|
||||||
STRING_ENTRY( AUDIO_DEVICE_IN_SECONDARY_MIC ),
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Combination entries consisting of multiple devices defined above.
|
|
||||||
* These don't require counterpart in string_conversion_table_input_device_fancy. */
|
|
||||||
STRING_ENTRY( AUDIO_DEVICE_IN_ALL ),
|
|
||||||
STRING_ENTRY( AUDIO_DEVICE_IN_ALL_SCO ),
|
|
||||||
STRING_ENTRY_IF_AUDIO_DEVICE_IN_ALL_USB
|
|
||||||
|
|
||||||
{ 0, NULL }
|
{ 0, NULL }
|
||||||
};
|
};
|
||||||
|
|
@ -258,31 +262,31 @@ struct string_conversion string_conversion_table_input_device_fancy[] = {
|
||||||
{ AUDIO_DEVICE_IN_WIRED_HEADSET, "input-wired_headset" },
|
{ AUDIO_DEVICE_IN_WIRED_HEADSET, "input-wired_headset" },
|
||||||
{ AUDIO_DEVICE_IN_AUX_DIGITAL, "input-aux_digital" },
|
{ AUDIO_DEVICE_IN_AUX_DIGITAL, "input-aux_digital" },
|
||||||
{ AUDIO_DEVICE_IN_VOICE_CALL, "input-voice_call" },
|
{ 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_BACK_MIC, "input-back_mic" },
|
||||||
{ AUDIO_DEVICE_IN_REMOTE_SUBMIX, "input-remote_submix" },
|
{ AUDIO_DEVICE_IN_REMOTE_SUBMIX, "input-remote_submix" },
|
||||||
{ AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET, "input-analog_dock_headset" },
|
{ AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET, "input-analog_dock_headset" },
|
||||||
{ AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET, "input-digital_dock_headset" },
|
{ AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET, "input-digital_dock_headset" },
|
||||||
{ AUDIO_DEVICE_IN_USB_ACCESSORY, "input-usb_accessory" },
|
{ AUDIO_DEVICE_IN_USB_ACCESSORY, "input-usb_accessory" },
|
||||||
{ AUDIO_DEVICE_IN_USB_DEVICE, "input-usb_device" },
|
{ 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" },
|
{ AUDIO_DEVICE_IN_DEFAULT, "input-default" },
|
||||||
|
|
||||||
/* Devices which may or may not be defined for all devices, */
|
/* Devices which may or may not be defined for all devices. */
|
||||||
FANCY_ENTRY_IF_AUDIO_DEVICE_IN_HDMI ( "input-hdmi" )
|
|
||||||
FANCY_ENTRY_IF_AUDIO_DEVICE_IN_TELEPHONY_RX ( "input-telephony_rx" )
|
|
||||||
FANCY_ENTRY_IF_AUDIO_DEVICE_IN_FM_TUNER ( "input-fm_tuner" )
|
|
||||||
FANCY_ENTRY_IF_AUDIO_DEVICE_IN_TV_TUNER ( "input-tv_tuner" )
|
|
||||||
FANCY_ENTRY_IF_AUDIO_DEVICE_IN_LINE ( "input-line" )
|
|
||||||
FANCY_ENTRY_IF_AUDIO_DEVICE_IN_SPDIF ( "input-spdif" )
|
|
||||||
FANCY_ENTRY_IF_AUDIO_DEVICE_IN_BLUETOOTH_A2DP ( "input-bluetooth_a2dp" )
|
|
||||||
FANCY_ENTRY_IF_AUDIO_DEVICE_IN_LOOPBACK ( "input-loopback" )
|
|
||||||
FANCY_ENTRY_IF_AUDIO_DEVICE_IN_PROXY ( "input-proxy" )
|
|
||||||
FANCY_ENTRY_IF_AUDIO_DEVICE_IN_FM_RX ( "input-fm_rx" )
|
FANCY_ENTRY_IF_AUDIO_DEVICE_IN_FM_RX ( "input-fm_rx" )
|
||||||
FANCY_ENTRY_IF_AUDIO_DEVICE_IN_FM_RX_A2DP ( "input-fm_rx_a2dp" )
|
FANCY_ENTRY_IF_AUDIO_DEVICE_IN_FM_RX_A2DP ( "input-fm_rx_a2dp" )
|
||||||
FANCY_ENTRY_IF_AUDIO_DEVICE_IN_IP ( "input-ip" )
|
|
||||||
|
|
||||||
#ifdef DROID_AUDIO_HAL_SECONDARY_MIC
|
|
||||||
{ AUDIO_DEVICE_IN_SECONDARY_MIC, "input-secondary_mic" },
|
|
||||||
#endif
|
|
||||||
|
|
||||||
{ 0, NULL }
|
{ 0, NULL }
|
||||||
};
|
};
|
||||||
|
|
@ -298,8 +302,11 @@ struct string_conversion string_conversion_table_audio_source_fancy[] = {
|
||||||
{ AUDIO_SOURCE_VOICE_RECOGNITION, "voice recognition" },
|
{ AUDIO_SOURCE_VOICE_RECOGNITION, "voice recognition" },
|
||||||
{ AUDIO_SOURCE_VOICE_COMMUNICATION, "voice communication" },
|
{ AUDIO_SOURCE_VOICE_COMMUNICATION, "voice communication" },
|
||||||
{ AUDIO_SOURCE_REMOTE_SUBMIX, "remote submix" },
|
{ 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, */
|
/* 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_TUNER ( "fm tuner" )
|
||||||
FANCY_ENTRY_IF_AUDIO_SOURCE_FM_RX ( "fm rx" )
|
FANCY_ENTRY_IF_AUDIO_SOURCE_FM_RX ( "fm rx" )
|
||||||
FANCY_ENTRY_IF_AUDIO_SOURCE_FM_RX_A2DP ( "fm rx a2dp" )
|
FANCY_ENTRY_IF_AUDIO_SOURCE_FM_RX_A2DP ( "fm rx a2dp" )
|
||||||
|
|
@ -314,33 +321,34 @@ struct string_conversion string_conversion_table_output_flag[] = {
|
||||||
STRING_ENTRY( AUDIO_OUTPUT_FLAG_PRIMARY ),
|
STRING_ENTRY( AUDIO_OUTPUT_FLAG_PRIMARY ),
|
||||||
STRING_ENTRY( AUDIO_OUTPUT_FLAG_FAST ),
|
STRING_ENTRY( AUDIO_OUTPUT_FLAG_FAST ),
|
||||||
STRING_ENTRY( AUDIO_OUTPUT_FLAG_DEEP_BUFFER ),
|
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,
|
/* Audio output flags which may or may not be defined for all devices. */
|
||||||
* update configure.ac CC_CHECK_DROID_ENUM list if you encounter new ones. */
|
|
||||||
STRING_ENTRY_IF_AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD
|
|
||||||
STRING_ENTRY_IF_AUDIO_OUTPUT_FLAG_NON_BLOCKING
|
|
||||||
STRING_ENTRY_IF_AUDIO_OUTPUT_FLAG_HW_AV_SYNC
|
|
||||||
STRING_ENTRY_IF_AUDIO_OUTPUT_FLAG_VOIP_RX
|
|
||||||
STRING_ENTRY_IF_AUDIO_OUTPUT_FLAG_INCALL_MUSIC
|
|
||||||
STRING_ENTRY_IF_AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH
|
STRING_ENTRY_IF_AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH
|
||||||
STRING_ENTRY_IF_AUDIO_OUTPUT_FLAG_TTS
|
|
||||||
STRING_ENTRY_IF_AUDIO_OUTPUT_FLAG_RAW
|
|
||||||
STRING_ENTRY_IF_AUDIO_OUTPUT_FLAG_SYNC
|
|
||||||
STRING_ENTRY_IF_AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO
|
|
||||||
|
|
||||||
{ 0, NULL }
|
{ 0, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct string_conversion string_conversion_table_input_flag[] = {
|
struct string_conversion string_conversion_table_input_flag[] = {
|
||||||
/* Audio output flags which may or may not be defined for all devices,
|
STRING_ENTRY( AUDIO_INPUT_FLAG_NONE ),
|
||||||
* update configure.ac CC_CHECK_DROID_ENUM list if you encounter new ones. */
|
STRING_ENTRY( AUDIO_INPUT_FLAG_FAST ),
|
||||||
STRING_ENTRY_IF_AUDIO_INPUT_FLAG_NONE
|
STRING_ENTRY( AUDIO_INPUT_FLAG_HW_HOTWORD ),
|
||||||
STRING_ENTRY_IF_AUDIO_INPUT_FLAG_FAST
|
STRING_ENTRY( AUDIO_INPUT_FLAG_RAW ),
|
||||||
STRING_ENTRY_IF_AUDIO_INPUT_FLAG_HW_HOTWORD
|
STRING_ENTRY( AUDIO_INPUT_FLAG_SYNC ),
|
||||||
STRING_ENTRY_IF_AUDIO_INPUT_FLAG_RAW
|
STRING_ENTRY( AUDIO_INPUT_FLAG_MMAP_NOIRQ ),
|
||||||
STRING_ENTRY_IF_AUDIO_INPUT_FLAG_SYNC
|
STRING_ENTRY( AUDIO_INPUT_FLAG_VOIP_TX ),
|
||||||
STRING_ENTRY_IF_AUDIO_INPUT_FLAG_MMAP_NOIRQ
|
STRING_ENTRY( AUDIO_INPUT_FLAG_HW_AV_SYNC ),
|
||||||
STRING_ENTRY_IF_AUDIO_INPUT_FLAG_VOIP_TX
|
STRING_ENTRY( AUDIO_INPUT_FLAG_DIRECT ),
|
||||||
|
|
||||||
{ 0, NULL }
|
{ 0, NULL }
|
||||||
};
|
};
|
||||||
|
|
@ -369,13 +377,6 @@ struct string_conversion string_conversion_table_output_channels[] = {
|
||||||
STRING_ENTRY( AUDIO_CHANNEL_OUT_STEREO ),
|
STRING_ENTRY( AUDIO_CHANNEL_OUT_STEREO ),
|
||||||
STRING_ENTRY( AUDIO_CHANNEL_OUT_QUAD ),
|
STRING_ENTRY( AUDIO_CHANNEL_OUT_QUAD ),
|
||||||
|
|
||||||
STRING_ENTRY_IF_AUDIO_CHANNEL_OUT_SURROUND
|
|
||||||
STRING_ENTRY( AUDIO_CHANNEL_OUT_5POINT1 ),
|
|
||||||
STRING_ENTRY_IF_AUDIO_CHANNEL_OUT_5POINT1_BACK
|
|
||||||
STRING_ENTRY_IF_AUDIO_CHANNEL_OUT_5POINT1_SIDE
|
|
||||||
STRING_ENTRY(AUDIO_CHANNEL_OUT_7POINT1 ),
|
|
||||||
STRING_ENTRY(AUDIO_CHANNEL_OUT_ALL ),
|
|
||||||
|
|
||||||
{ 0, NULL }
|
{ 0, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -397,7 +398,6 @@ struct string_conversion string_conversion_table_input_channels[] = {
|
||||||
STRING_ENTRY( AUDIO_CHANNEL_IN_MONO ),
|
STRING_ENTRY( AUDIO_CHANNEL_IN_MONO ),
|
||||||
STRING_ENTRY( AUDIO_CHANNEL_IN_STEREO ),
|
STRING_ENTRY( AUDIO_CHANNEL_IN_STEREO ),
|
||||||
STRING_ENTRY( AUDIO_CHANNEL_IN_FRONT_BACK ),
|
STRING_ENTRY( AUDIO_CHANNEL_IN_FRONT_BACK ),
|
||||||
STRING_ENTRY( AUDIO_CHANNEL_IN_ALL ),
|
|
||||||
STRING_ENTRY_IF_AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO
|
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_DNLINK_MONO
|
||||||
STRING_ENTRY_IF_AUDIO_CHANNEL_IN_VOICE_CALL_MONO
|
STRING_ENTRY_IF_AUDIO_CHANNEL_IN_VOICE_CALL_MONO
|
||||||
|
|
@ -409,14 +409,15 @@ struct string_conversion string_conversion_table_input_channels[] = {
|
||||||
struct string_conversion string_conversion_table_format[] = {
|
struct string_conversion string_conversion_table_format[] = {
|
||||||
/* Omit most formats as we aren't usually interested in
|
/* Omit most formats as we aren't usually interested in
|
||||||
* other than the pcm formats anyway. */
|
* other than the pcm formats anyway. */
|
||||||
|
STRING_ENTRY( AUDIO_FORMAT_INVALID ),
|
||||||
STRING_ENTRY( AUDIO_FORMAT_DEFAULT ),
|
STRING_ENTRY( AUDIO_FORMAT_DEFAULT ),
|
||||||
STRING_ENTRY( AUDIO_FORMAT_PCM ),
|
STRING_ENTRY( AUDIO_FORMAT_PCM ),
|
||||||
STRING_ENTRY( AUDIO_FORMAT_MP3 ),
|
|
||||||
STRING_ENTRY( AUDIO_FORMAT_AMR_NB ),
|
STRING_ENTRY( AUDIO_FORMAT_AMR_NB ),
|
||||||
STRING_ENTRY( AUDIO_FORMAT_AMR_WB ),
|
STRING_ENTRY( AUDIO_FORMAT_AMR_WB ),
|
||||||
STRING_ENTRY( AUDIO_FORMAT_AAC ),
|
STRING_ENTRY( AUDIO_FORMAT_FLAC ),
|
||||||
STRING_ENTRY( AUDIO_FORMAT_HE_AAC_V1 ),
|
STRING_ENTRY( AUDIO_FORMAT_MP3 ),
|
||||||
STRING_ENTRY( AUDIO_FORMAT_HE_AAC_V2 ),
|
STRING_ENTRY( AUDIO_FORMAT_OPUS ),
|
||||||
|
STRING_ENTRY( AUDIO_FORMAT_SBC ),
|
||||||
STRING_ENTRY( AUDIO_FORMAT_VORBIS ),
|
STRING_ENTRY( AUDIO_FORMAT_VORBIS ),
|
||||||
|
|
||||||
STRING_ENTRY( AUDIO_FORMAT_PCM_16_BIT ),
|
STRING_ENTRY( AUDIO_FORMAT_PCM_16_BIT ),
|
||||||
|
|
@ -424,12 +425,6 @@ struct string_conversion string_conversion_table_format[] = {
|
||||||
STRING_ENTRY( AUDIO_FORMAT_PCM_32_BIT ),
|
STRING_ENTRY( AUDIO_FORMAT_PCM_32_BIT ),
|
||||||
STRING_ENTRY( AUDIO_FORMAT_PCM_8_24_BIT ),
|
STRING_ENTRY( AUDIO_FORMAT_PCM_8_24_BIT ),
|
||||||
|
|
||||||
/* Audio formats which may or may not be defined for all devices,
|
|
||||||
* update configure.ac CC_CHECK_DROID_ENUM list if you encounter new ones. */
|
|
||||||
STRING_ENTRY_IF_AUDIO_FORMAT_PCM_OFFLOAD
|
|
||||||
STRING_ENTRY_IF_AUDIO_FORMAT_FLAC
|
|
||||||
STRING_ENTRY_IF_AUDIO_FORMAT_OPUS
|
|
||||||
|
|
||||||
{ 0, NULL }
|
{ 0, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -2,7 +2,7 @@
|
||||||
#define foodroidconversionfoo
|
#define foodroidconversionfoo
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2022 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
||||||
*
|
*
|
||||||
|
|
@ -52,10 +52,12 @@ typedef enum {
|
||||||
CONV_STRING_OUTPUT_DEVICE,
|
CONV_STRING_OUTPUT_DEVICE,
|
||||||
CONV_STRING_INPUT_DEVICE,
|
CONV_STRING_INPUT_DEVICE,
|
||||||
CONV_STRING_OUTPUT_FLAG,
|
CONV_STRING_OUTPUT_FLAG,
|
||||||
CONV_STRING_INPUT_FLAG
|
CONV_STRING_INPUT_FLAG,
|
||||||
|
CONV_STRING_AUDIO_SOURCE_FANCY,
|
||||||
} pa_conversion_string_t;
|
} 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_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_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_input_channel(uint32_t value, pa_conversion_field_t from, uint32_t *to_value);
|
||||||
|
|
@ -69,8 +71,6 @@ bool pa_string_convert_input_device_str_to_num(const char *str, audio_devices_t
|
||||||
bool pa_string_convert_flag_num_to_str(audio_output_flags_t value, const char **to_str);
|
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);
|
bool pa_string_convert_flag_str_to_num(const char *str, audio_output_flags_t *to_value);
|
||||||
|
|
||||||
char *pa_list_string_output_device(audio_devices_t devices);
|
|
||||||
char *pa_list_string_input_device(audio_devices_t devices);
|
|
||||||
char *pa_list_string_flags(audio_output_flags_t flags);
|
char *pa_list_string_flags(audio_output_flags_t flags);
|
||||||
|
|
||||||
/* Get default audio source associated with input device.
|
/* Get default audio source associated with input device.
|
||||||
|
|
@ -81,29 +81,26 @@ bool pa_input_device_default_audio_source(audio_devices_t input_device, audio_so
|
||||||
bool pa_droid_output_port_name(audio_devices_t value, const char **to_str);
|
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);
|
bool pa_droid_input_port_name(audio_devices_t value, const char **to_str);
|
||||||
|
|
||||||
/* Pretty audio source names */
|
|
||||||
bool pa_droid_audio_source_name(audio_source_t value, const char **to_str);
|
|
||||||
|
|
||||||
int pa_conversion_parse_list(pa_conversion_string_t type, const char *separator,
|
int pa_conversion_parse_list(pa_conversion_string_t type, const char *separator,
|
||||||
const char *str, uint32_t *dst, char **unknown_entries);
|
const char *str, uint32_t *dst, char **unknown_entries);
|
||||||
|
|
||||||
bool pa_conversion_parse_sampling_rates(const char *fn, const unsigned ln,
|
bool pa_conversion_parse_sampling_rates(const char *fn, const unsigned ln,
|
||||||
const char *str, bool legacy,
|
const char *str,
|
||||||
uint32_t sampling_rates[AUDIO_MAX_SAMPLING_RATES]);
|
uint32_t sampling_rates[AUDIO_MAX_SAMPLING_RATES]);
|
||||||
bool pa_conversion_parse_formats(const char *fn, const unsigned ln,
|
bool pa_conversion_parse_formats(const char *fn, const unsigned ln,
|
||||||
const char *str, bool legacy,
|
const char *str,
|
||||||
audio_format_t *formats);
|
audio_format_t *formats);
|
||||||
bool pa_conversion_parse_output_channels(const char *fn, const unsigned ln,
|
int pa_conversion_parse_output_channels(const char *fn, const unsigned ln,
|
||||||
const char *str, bool legacy,
|
const char *str,
|
||||||
audio_channel_mask_t *channels);
|
audio_channel_mask_t channel_masks[AUDIO_MAX_CHANNEL_MASKS]);
|
||||||
bool pa_conversion_parse_input_channels(const char *fn, const unsigned ln,
|
int pa_conversion_parse_input_channels(const char *fn, const unsigned ln,
|
||||||
const char *str, bool legacy,
|
const char *str,
|
||||||
audio_channel_mask_t *channels);
|
audio_channel_mask_t channel_masks[AUDIO_MAX_CHANNEL_MASKS]);
|
||||||
bool pa_conversion_parse_output_devices(const char *fn, const unsigned ln,
|
bool pa_conversion_parse_output_devices(const char *fn, const unsigned ln,
|
||||||
char *str, bool legacy, bool must_recognize_all,
|
char *str, bool must_recognize_all,
|
||||||
audio_devices_t *devices);
|
audio_devices_t *devices);
|
||||||
bool pa_conversion_parse_input_devices(const char *fn, const unsigned ln,
|
bool pa_conversion_parse_input_devices(const char *fn, const unsigned ln,
|
||||||
char *str, bool legacy, bool must_recognize_all,
|
char *str, bool must_recognize_all,
|
||||||
audio_devices_t *devices);
|
audio_devices_t *devices);
|
||||||
bool pa_conversion_parse_output_flags(const char *fn, const unsigned ln,
|
bool pa_conversion_parse_output_flags(const char *fn, const unsigned ln,
|
||||||
const char *str, audio_output_flags_t *flags);
|
const char *str, audio_output_flags_t *flags);
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#define foodroidconfigfoo
|
#define foodroidconfigfoo
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2022 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
||||||
*
|
*
|
||||||
|
|
@ -30,75 +30,106 @@
|
||||||
#include <android-config.h>
|
#include <android-config.h>
|
||||||
#include <hardware/audio.h>
|
#include <hardware/audio.h>
|
||||||
|
|
||||||
|
#include <droid/sllist.h>
|
||||||
#include <droid/version.h>
|
#include <droid/version.h>
|
||||||
|
|
||||||
typedef struct pa_droid_config_audio pa_droid_config_audio;
|
#define AUDIO_MAX_SAMPLING_RATES (32)
|
||||||
typedef struct pa_droid_config_hw_module pa_droid_config_hw_module;
|
#define AUDIO_MAX_CHANNEL_MASKS (32)
|
||||||
|
|
||||||
#define AUDIO_MAX_SAMPLING_RATES (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;
|
||||||
|
|
||||||
typedef struct pa_droid_config_global {
|
struct dm_config_global {
|
||||||
uint32_t audio_hal_version;
|
char *key;
|
||||||
audio_devices_t attached_output_devices;
|
char *value;
|
||||||
audio_devices_t default_output_device;
|
|
||||||
audio_devices_t attached_input_devices;
|
|
||||||
} pa_droid_config_global;
|
|
||||||
|
|
||||||
typedef struct pa_droid_config_device {
|
|
||||||
const pa_droid_config_hw_module *module;
|
|
||||||
|
|
||||||
char *name;
|
|
||||||
uint32_t sampling_rates[AUDIO_MAX_SAMPLING_RATES]; /* (uint32_t) -1 -> dynamic */
|
|
||||||
audio_channel_mask_t channel_masks; /* 0 -> dynamic */
|
|
||||||
audio_format_t formats; /* 0 -> dynamic */
|
|
||||||
audio_devices_t devices;
|
|
||||||
/* Instead of using audio_output_flags_t and audio_input_flags_t
|
|
||||||
* unify the flags as uint32_t so that we can have single struct for both
|
|
||||||
* output and input configurations.
|
|
||||||
* audio_input_flags_t was introduced in APIs 2 & 3, depending on adaptation,
|
|
||||||
* so having input flags as uint32_t is simpler from input implementation
|
|
||||||
* point of view as well. */
|
|
||||||
uint32_t flags;
|
|
||||||
pa_direction_t direction;
|
|
||||||
|
|
||||||
struct pa_droid_config_device *next;
|
|
||||||
} pa_droid_config_device;
|
|
||||||
|
|
||||||
struct pa_droid_config_hw_module {
|
|
||||||
const pa_droid_config_audio *config;
|
|
||||||
|
|
||||||
char *name;
|
|
||||||
/* If global config is not defined for module, use root global config. */
|
|
||||||
pa_droid_config_global *global_config;
|
|
||||||
pa_droid_config_device *outputs;
|
|
||||||
pa_droid_config_device *inputs;
|
|
||||||
|
|
||||||
struct pa_droid_config_hw_module *next;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pa_droid_config_audio {
|
struct dm_config_profile {
|
||||||
pa_droid_config_global *global_config;
|
char *name;
|
||||||
pa_droid_config_hw_module *hw_modules;
|
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 */
|
/* Config parser */
|
||||||
pa_droid_config_audio *pa_droid_config_load(pa_modargs *ma);
|
dm_config_device *dm_config_load(pa_modargs *ma);
|
||||||
pa_droid_config_audio *pa_droid_config_dup(const pa_droid_config_audio *config);
|
dm_config_device *dm_config_dup(const dm_config_device *config);
|
||||||
void pa_droid_config_free(pa_droid_config_audio *config);
|
void dm_config_free(dm_config_device *config);
|
||||||
pa_droid_config_audio *pa_parse_droid_audio_config_legacy(const char *filename);
|
|
||||||
pa_droid_config_audio *pa_parse_droid_audio_config_xml(const char *filename);
|
|
||||||
/* autodetect config type from filename and parse */
|
/* autodetect config type from filename and parse */
|
||||||
pa_droid_config_audio *pa_parse_droid_audio_config(const char *filename);
|
dm_config_device *pa_parse_droid_audio_config(const char *filename);
|
||||||
|
|
||||||
const pa_droid_config_hw_module *pa_droid_config_find_module(const pa_droid_config_audio *config, const char* module_id);
|
dm_config_module *dm_config_find_module(dm_config_device *config, const char* module_id);
|
||||||
const pa_droid_config_device *pa_droid_config_find_output(const pa_droid_config_hw_module *module, const char* output_name);
|
dm_config_port *dm_config_find_port(dm_config_module *module, const char* name);
|
||||||
const pa_droid_config_device *pa_droid_config_find_input(const pa_droid_config_hw_module *module, const char* input_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);
|
||||||
|
|
||||||
pa_droid_config_hw_module *pa_droid_config_hw_module_new(const pa_droid_config_audio *config, const char *name);
|
bool dm_config_port_equal(const dm_config_port *a, const dm_config_port *b);
|
||||||
void pa_droid_config_hw_module_free(pa_droid_config_hw_module *hw_module);
|
|
||||||
pa_droid_config_device *pa_droid_config_device_new(const pa_droid_config_hw_module *module,
|
dm_config_port *dm_config_find_mix_port(dm_config_module *module, const char *name);
|
||||||
pa_direction_t direction,
|
|
||||||
const char *name);
|
|
||||||
void pa_droid_config_device_free(pa_droid_config_device *device);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#define foodroidutilfoo
|
#define foodroidutilfoo
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2013-2018 Jolla Ltd.
|
* Copyright (C) 2013-2022 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
||||||
*
|
*
|
||||||
|
|
@ -35,10 +35,6 @@
|
||||||
#include <droid/version.h>
|
#include <droid/version.h>
|
||||||
#include <droid/droid-config.h>
|
#include <droid/droid-config.h>
|
||||||
|
|
||||||
#if defined(QCOM_BSP) && (AUDIO_API_VERSION_MAJ >= 3)
|
|
||||||
#define DROID_AUDIO_HAL_USE_VSID
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define PROP_DROID_DEVICES "droid.devices"
|
#define PROP_DROID_DEVICES "droid.devices"
|
||||||
#define PROP_DROID_FLAGS "droid.flags"
|
#define PROP_DROID_FLAGS "droid.flags"
|
||||||
#define PROP_DROID_HW_MODULE "droid.hw_module"
|
#define PROP_DROID_HW_MODULE "droid.hw_module"
|
||||||
|
|
@ -48,8 +44,12 @@
|
||||||
#define PROP_DROID_OUTPUT_LOW_LATENCY "droid.output.low_latency"
|
#define PROP_DROID_OUTPUT_LOW_LATENCY "droid.output.low_latency"
|
||||||
#define PROP_DROID_OUTPUT_MEDIA_LATENCY "droid.output.media_latency"
|
#define PROP_DROID_OUTPUT_MEDIA_LATENCY "droid.output.media_latency"
|
||||||
#define PROP_DROID_OUTPUT_OFFLOAD "droid.output.offload"
|
#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_BUILTIN "droid.input.builtin"
|
||||||
#define PROP_DROID_INPUT_EXTERNAL "droid.input.external"
|
#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"
|
#define PA_DROID_PRIMARY_DEVICE "primary"
|
||||||
|
|
||||||
|
|
@ -58,35 +58,27 @@ typedef struct pa_droid_stream pa_droid_stream;
|
||||||
typedef struct pa_droid_output_stream pa_droid_output_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_input_stream pa_droid_input_stream;
|
||||||
typedef struct pa_droid_card_data pa_droid_card_data;
|
typedef struct pa_droid_card_data pa_droid_card_data;
|
||||||
typedef int (*common_set_parameters_cb_t)(pa_droid_card_data *card_data, const char *str);
|
|
||||||
|
|
||||||
typedef struct pa_droid_quirks pa_droid_quirks;
|
typedef struct pa_droid_options pa_droid_options;
|
||||||
|
|
||||||
typedef enum pa_droid_hook {
|
enum pa_droid_option_type {
|
||||||
PA_DROID_HOOK_INPUT_CHANNEL_MAP_CHANGED, /* Call data: pa_droid_stream */
|
DM_OPTION_INPUT_ATOI,
|
||||||
PA_DROID_HOOK_INPUT_BUFFER_SIZE_CHANGED, /* Call data: pa_droid_stream */
|
DM_OPTION_CLOSE_INPUT,
|
||||||
PA_DROID_HOOK_MAX
|
DM_OPTION_UNLOAD_NO_CLOSE,
|
||||||
} pa_droid_hook_t;
|
DM_OPTION_HW_VOLUME,
|
||||||
|
DM_OPTION_REALCALL,
|
||||||
enum pa_droid_quirk_type {
|
DM_OPTION_UNLOAD_CALL_EXIT,
|
||||||
QUIRK_INPUT_ATOI,
|
DM_OPTION_OUTPUT_FAST,
|
||||||
QUIRK_SET_PARAMETERS,
|
DM_OPTION_OUTPUT_DEEP_BUFFER,
|
||||||
QUIRK_CLOSE_INPUT,
|
DM_OPTION_AUDIO_CAL_WAIT,
|
||||||
QUIRK_UNLOAD_NO_CLOSE,
|
DM_OPTION_SPEAKER_BEFORE_VOICE,
|
||||||
QUIRK_NO_HW_VOLUME,
|
DM_OPTION_OUTPUT_VOIP_RX,
|
||||||
QUIRK_OUTPUT_MAKE_WRITABLE,
|
DM_OPTION_RECORD_VOICE_16K,
|
||||||
QUIRK_REALCALL,
|
DM_OPTION_COUNT
|
||||||
QUIRK_UNLOAD_CALL_EXIT,
|
|
||||||
QUIRK_OUTPUT_FAST,
|
|
||||||
QUIRK_OUTPUT_DEEP_BUFFER,
|
|
||||||
QUIRK_AUDIO_CAL_WAIT,
|
|
||||||
QUIRK_STANDBY_SET_ROUTE,
|
|
||||||
QUIRK_SPEAKER_BEFORE_VOICE,
|
|
||||||
QUIRK_COUNT
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pa_droid_quirks {
|
struct pa_droid_options {
|
||||||
bool enabled[QUIRK_COUNT];
|
bool enabled[DM_OPTION_COUNT];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pa_droid_hw_module {
|
struct pa_droid_hw_module {
|
||||||
|
|
@ -95,8 +87,8 @@ struct pa_droid_hw_module {
|
||||||
pa_core *core;
|
pa_core *core;
|
||||||
char *shared_name;
|
char *shared_name;
|
||||||
|
|
||||||
pa_droid_config_audio *config;
|
dm_config_device *config;
|
||||||
const pa_droid_config_hw_module *enabled_module;
|
dm_config_module *enabled_module;
|
||||||
pa_mutex *hw_mutex;
|
pa_mutex *hw_mutex;
|
||||||
pa_mutex *output_mutex;
|
pa_mutex *output_mutex;
|
||||||
pa_mutex *input_mutex;
|
pa_mutex *input_mutex;
|
||||||
|
|
@ -106,8 +98,8 @@ struct pa_droid_hw_module {
|
||||||
|
|
||||||
const char *module_id;
|
const char *module_id;
|
||||||
|
|
||||||
uint32_t stream_out_id;
|
uint32_t stream_id;
|
||||||
uint32_t stream_in_id;
|
bool bt_sco_enabled;
|
||||||
|
|
||||||
pa_idxset *outputs;
|
pa_idxset *outputs;
|
||||||
pa_idxset *inputs;
|
pa_idxset *inputs;
|
||||||
|
|
@ -116,14 +108,11 @@ struct pa_droid_hw_module {
|
||||||
|
|
||||||
pa_atomic_t active_outputs;
|
pa_atomic_t active_outputs;
|
||||||
|
|
||||||
pa_droid_quirks quirks;
|
pa_droid_options options;
|
||||||
|
|
||||||
/* Mode and input control */
|
/* Mode and input control */
|
||||||
struct _state {
|
struct _state {
|
||||||
audio_mode_t mode;
|
audio_mode_t mode;
|
||||||
audio_devices_t input_device;
|
|
||||||
audio_source_t audio_source;
|
|
||||||
pa_droid_stream *active_input;
|
|
||||||
} state;
|
} state;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -131,8 +120,6 @@ struct pa_droid_output_stream {
|
||||||
struct audio_stream_out *stream;
|
struct audio_stream_out *stream;
|
||||||
pa_sample_spec sample_spec;
|
pa_sample_spec sample_spec;
|
||||||
pa_channel_map channel_map;
|
pa_channel_map channel_map;
|
||||||
uint32_t flags;
|
|
||||||
uint32_t device;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pa_droid_input_stream {
|
struct pa_droid_input_stream {
|
||||||
|
|
@ -143,6 +130,12 @@ struct pa_droid_input_stream {
|
||||||
pa_channel_map channel_map;
|
pa_channel_map channel_map;
|
||||||
pa_sample_spec req_sample_spec;
|
pa_sample_spec req_sample_spec;
|
||||||
pa_channel_map req_channel_map;
|
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 flags;
|
||||||
uint32_t device;
|
uint32_t device;
|
||||||
bool first;
|
bool first;
|
||||||
|
|
@ -152,19 +145,21 @@ struct pa_droid_stream {
|
||||||
PA_REFCNT_DECLARE;
|
PA_REFCNT_DECLARE;
|
||||||
|
|
||||||
pa_droid_hw_module *module;
|
pa_droid_hw_module *module;
|
||||||
const pa_droid_config_device *device_def;
|
dm_config_port *mix_port;
|
||||||
size_t buffer_size;
|
size_t buffer_size;
|
||||||
void *data;
|
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_output_stream *output;
|
||||||
pa_droid_input_stream *input;
|
pa_droid_input_stream *input;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pa_droid_card_data {
|
struct pa_droid_card_data {
|
||||||
void *userdata;
|
void *userdata;
|
||||||
/* General functions */
|
|
||||||
char *module_id;
|
char *module_id;
|
||||||
common_set_parameters_cb_t set_parameters;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -174,13 +169,13 @@ typedef struct pa_droid_profile_set pa_droid_profile_set;
|
||||||
typedef struct pa_droid_mapping pa_droid_mapping;
|
typedef struct pa_droid_mapping pa_droid_mapping;
|
||||||
|
|
||||||
typedef struct pa_droid_port_data {
|
typedef struct pa_droid_port_data {
|
||||||
audio_devices_t device;
|
dm_config_port *device_port;
|
||||||
} pa_droid_port_data;
|
} pa_droid_port_data;
|
||||||
|
|
||||||
typedef struct pa_droid_port {
|
typedef struct pa_droid_port {
|
||||||
pa_droid_mapping *mapping;
|
pa_droid_mapping *mapping;
|
||||||
|
|
||||||
audio_devices_t device;
|
dm_config_port *device_port;
|
||||||
char *name;
|
char *name;
|
||||||
char *description;
|
char *description;
|
||||||
unsigned priority;
|
unsigned priority;
|
||||||
|
|
@ -189,9 +184,9 @@ typedef struct pa_droid_port {
|
||||||
struct pa_droid_mapping {
|
struct pa_droid_mapping {
|
||||||
pa_droid_profile_set *profile_set;
|
pa_droid_profile_set *profile_set;
|
||||||
|
|
||||||
const pa_droid_config_device *output;
|
dm_config_module *module;
|
||||||
/* Use all devices in one input */
|
dm_config_port *mix_port;
|
||||||
const pa_droid_config_device *inputs;
|
dm_list *device_ports;
|
||||||
|
|
||||||
char *name;
|
char *name;
|
||||||
char *description;
|
char *description;
|
||||||
|
|
@ -210,7 +205,7 @@ struct pa_droid_mapping {
|
||||||
typedef struct pa_droid_profile {
|
typedef struct pa_droid_profile {
|
||||||
pa_droid_profile_set *profile_set;
|
pa_droid_profile_set *profile_set;
|
||||||
|
|
||||||
const pa_droid_config_hw_module *module;
|
dm_config_module *module;
|
||||||
|
|
||||||
char *name;
|
char *name;
|
||||||
char *description;
|
char *description;
|
||||||
|
|
@ -222,12 +217,13 @@ typedef struct pa_droid_profile {
|
||||||
* hashmaps. */
|
* hashmaps. */
|
||||||
pa_idxset *output_mappings;
|
pa_idxset *output_mappings;
|
||||||
/* Only one input */
|
/* Only one input */
|
||||||
|
pa_idxset *input_mappings;
|
||||||
pa_droid_mapping *input_mapping;
|
pa_droid_mapping *input_mapping;
|
||||||
|
|
||||||
} pa_droid_profile;
|
} pa_droid_profile;
|
||||||
|
|
||||||
struct pa_droid_profile_set {
|
struct pa_droid_profile_set {
|
||||||
const pa_droid_config_audio *config;
|
dm_config_device *config;
|
||||||
|
|
||||||
pa_hashmap *all_ports;
|
pa_hashmap *all_ports;
|
||||||
pa_hashmap *output_mappings;
|
pa_hashmap *output_mappings;
|
||||||
|
|
@ -240,8 +236,8 @@ struct pa_droid_profile_set {
|
||||||
|
|
||||||
/* Open hardware module */
|
/* Open hardware module */
|
||||||
/* 'config' can be NULL if it is assumed that hw module with module_id already is open. */
|
/* 'config' can be NULL if it is assumed that hw module with module_id already is open. */
|
||||||
pa_droid_hw_module *pa_droid_hw_module_get(pa_core *core, const pa_droid_config_audio *config, const char *module_id);
|
pa_droid_hw_module *pa_droid_hw_module_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 quirks from modargs
|
/* First try to get already open hw module and if none found parse config and options from modargs
|
||||||
* and do initial open. */
|
* 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_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);
|
pa_droid_hw_module *pa_droid_hw_module_ref(pa_droid_hw_module *hw);
|
||||||
|
|
@ -251,11 +247,10 @@ void pa_droid_hw_module_lock(pa_droid_hw_module *hw);
|
||||||
bool pa_droid_hw_module_try_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_hw_module_unlock(pa_droid_hw_module *hw);
|
||||||
|
|
||||||
bool pa_droid_quirk_parse(pa_droid_quirks *quirks, const char *quirks_def);
|
void pa_droid_options_log(pa_droid_hw_module *hw);
|
||||||
void pa_droid_quirk_log(pa_droid_hw_module *hw);
|
|
||||||
|
|
||||||
static inline bool pa_droid_quirk(pa_droid_hw_module *hw, enum pa_droid_quirk_type quirk) {
|
static inline bool pa_droid_option(pa_droid_hw_module *hw, enum pa_droid_option_type option) {
|
||||||
return hw && hw->quirks.enabled[quirk];
|
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_set_mode(pa_droid_hw_module *hw_module, audio_mode_t mode);
|
||||||
|
|
@ -264,14 +259,11 @@ 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);
|
void pa_droid_hw_mic_set_mute(pa_droid_hw_module *hw_module, bool muted);
|
||||||
|
|
||||||
/* Profiles */
|
/* Profiles */
|
||||||
pa_droid_profile_set *pa_droid_profile_set_new(const pa_droid_config_hw_module *module);
|
pa_droid_profile_set *pa_droid_profile_set_default_new(dm_config_module *module);
|
||||||
pa_droid_profile_set *pa_droid_profile_set_default_new(const pa_droid_config_hw_module *module);
|
|
||||||
void pa_droid_profile_set_free(pa_droid_profile_set *ps);
|
void pa_droid_profile_set_free(pa_droid_profile_set *ps);
|
||||||
|
|
||||||
void pa_droid_profile_add_mapping(pa_droid_profile *p, pa_droid_mapping *am);
|
|
||||||
void pa_droid_profile_free(pa_droid_profile *p);
|
void pa_droid_profile_free(pa_droid_profile *p);
|
||||||
|
|
||||||
pa_droid_mapping *pa_droid_mapping_get(pa_droid_profile_set *ps, const pa_droid_config_device *device);
|
|
||||||
bool pa_droid_mapping_is_primary(pa_droid_mapping *am);
|
bool pa_droid_mapping_is_primary(pa_droid_mapping *am);
|
||||||
/* Go through idxset containing pa_droid_mapping objects and if primary output or input
|
/* Go through idxset containing pa_droid_mapping objects and if primary output or input
|
||||||
* mapping is found, return pointer to that mapping. */
|
* mapping is found, return pointer to that mapping. */
|
||||||
|
|
@ -299,8 +291,8 @@ int pa_droid_stream_set_parameters(pa_droid_stream *s, const char *parameters);
|
||||||
pa_droid_stream *pa_droid_open_output_stream(pa_droid_hw_module *module,
|
pa_droid_stream *pa_droid_open_output_stream(pa_droid_hw_module *module,
|
||||||
const pa_sample_spec *spec,
|
const pa_sample_spec *spec,
|
||||||
const pa_channel_map *map,
|
const pa_channel_map *map,
|
||||||
const char *module_output_name,
|
dm_config_port *mix_port,
|
||||||
audio_devices_t devices);
|
dm_config_port *device_port);
|
||||||
|
|
||||||
/* Set routing to the input or output stream, with following side-effects:
|
/* Set routing to the input or output stream, with following side-effects:
|
||||||
* Output:
|
* Output:
|
||||||
|
|
@ -311,18 +303,25 @@ pa_droid_stream *pa_droid_open_output_stream(pa_droid_hw_module *module,
|
||||||
* Input:
|
* Input:
|
||||||
* - buffer size or channel count may change
|
* - buffer size or channel count may change
|
||||||
*/
|
*/
|
||||||
int pa_droid_stream_set_route(pa_droid_stream *s, audio_devices_t device);
|
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
|
/* Open input stream with currently active routing, sample_spec and channel_map
|
||||||
* are requests and may change when opening the stream. */
|
* are requests and may change when opening the stream. */
|
||||||
pa_droid_stream *pa_droid_open_input_stream(pa_droid_hw_module *hw_module,
|
pa_droid_stream *pa_droid_open_input_stream(pa_droid_hw_module *hw_module,
|
||||||
const pa_sample_spec *default_sample_spec,
|
const pa_sample_spec *default_sample_spec,
|
||||||
const pa_channel_map *default_channel_map);
|
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,
|
bool pa_droid_stream_reconfigure_input(pa_droid_stream *s,
|
||||||
const pa_sample_spec *requested_sample_spec,
|
const pa_sample_spec *requested_sample_spec,
|
||||||
const pa_channel_map *requested_channel_map);
|
const pa_channel_map *requested_channel_map,
|
||||||
bool pa_droid_hw_set_input_device(pa_droid_hw_module *hw_module,
|
const pa_proplist *proplist);
|
||||||
audio_devices_t device);
|
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_sample_spec *pa_droid_stream_sample_spec(pa_droid_stream *stream);
|
||||||
const pa_channel_map *pa_droid_stream_channel_map(pa_droid_stream *stream);
|
const pa_channel_map *pa_droid_stream_channel_map(pa_droid_stream *stream);
|
||||||
|
|
@ -351,6 +350,8 @@ void *pa_droid_stream_get_data(pa_droid_stream *s);
|
||||||
bool pa_sink_is_droid_sink(pa_sink *sink);
|
bool pa_sink_is_droid_sink(pa_sink *sink);
|
||||||
bool pa_source_is_droid_source(pa_source *source);
|
bool pa_source_is_droid_source(pa_source *source);
|
||||||
|
|
||||||
|
pa_modargs *pa_droid_modargs_new(const char *args, const char* const keys[]);
|
||||||
|
|
||||||
/* Misc */
|
/* Misc */
|
||||||
size_t pa_droid_buffer_size_round_up(size_t buffer_size, size_t block_size);
|
size_t pa_droid_buffer_size_round_up(size_t buffer_size, size_t block_size);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#define foosllistfoo
|
#define foosllistfoo
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2022 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
||||||
*
|
*
|
||||||
|
|
@ -22,6 +22,12 @@
|
||||||
* USA.
|
* USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <pulse/def.h>
|
||||||
|
|
||||||
#define SLLIST_APPEND(t, head, item) \
|
#define SLLIST_APPEND(t, head, item) \
|
||||||
do { \
|
do { \
|
||||||
item->next = NULL; \
|
item->next = NULL; \
|
||||||
|
|
@ -46,4 +52,43 @@
|
||||||
i = NULL; \
|
i = NULL; \
|
||||||
} while (0)
|
} 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
|
#endif
|
||||||
|
|
|
||||||
32
src/common/include/droid/utils.h
Normal file
32
src/common/include/droid/utils.h
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
#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
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#define foodroidversionfoo
|
#define foodroidversionfoo
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 Jolla Ltd.
|
* Copyright (C) 2018-2022 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
||||||
*
|
*
|
||||||
|
|
@ -34,8 +34,8 @@
|
||||||
#error "ANDROID_VERSION_* not defined. Did you get your headers via extract-headers.sh?"
|
#error "ANDROID_VERSION_* not defined. Did you get your headers via extract-headers.sh?"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* We currently support API version up-to 3.0 */
|
/* We currently support API version up to 3.1 */
|
||||||
#define DROID_API_VERSION_SUPPORT HARDWARE_DEVICE_API_VERSION(3, 0)
|
#define DROID_API_VERSION_SUPPORT HARDWARE_DEVICE_API_VERSION(3, 1)
|
||||||
|
|
||||||
#if AUDIO_DEVICE_API_VERSION_CURRENT > DROID_API_VERSION_SUPPORT
|
#if AUDIO_DEVICE_API_VERSION_CURRENT > DROID_API_VERSION_SUPPORT
|
||||||
#warning Compiling against higher audio device API version than currently supported!
|
#warning Compiling against higher audio device API version than currently supported!
|
||||||
|
|
@ -48,4 +48,8 @@
|
||||||
#define AUDIO_API_VERSION_GET_MAJ(x) ((x >> 8) & 0xff)
|
#define AUDIO_API_VERSION_GET_MAJ(x) ((x >> 8) & 0xff)
|
||||||
#define AUDIO_API_VERSION_GET_MIN(x) (x & 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
|
#endif
|
||||||
|
|
|
||||||
172
src/common/sllist.c
Normal file
172
src/common/sllist.c
Normal file
|
|
@ -0,0 +1,172 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
64
src/common/utils.c
Normal file
64
src/common/utils.c
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
@ -136,19 +136,19 @@ static void notify_ports(pa_droid_extevdev *u) {
|
||||||
|
|
||||||
for (i=0; i < N_ELEMENTS(headphone_ports); i++) {
|
for (i=0; i < N_ELEMENTS(headphone_ports); i++) {
|
||||||
pa_device_port *p = pa_hashmap_get(u->card->ports, headphone_ports[i]);
|
pa_device_port *p = pa_hashmap_get(u->card->ports, headphone_ports[i]);
|
||||||
pa_log_debug("headphone device port %d, %d", i, p);
|
pa_log_debug("headphone device port %d, %p", i, p);
|
||||||
if (p)
|
if (p)
|
||||||
pa_device_port_set_available(p, has_headphone);
|
pa_device_port_set_available(p, has_headphone);
|
||||||
}
|
}
|
||||||
|
|
||||||
pa_available_t has_headset =
|
pa_available_t has_headset =
|
||||||
u->sw_microphone_insert ? PA_AVAILABLE_YES : PA_AVAILABLE_NO;
|
((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);
|
pa_log_debug("has_headset: %d", has_headset);
|
||||||
|
|
||||||
for (i=0; i < N_ELEMENTS(headset_ports); i++) {
|
for (i=0; i < N_ELEMENTS(headset_ports); i++) {
|
||||||
pa_device_port *p = pa_hashmap_get(u->card->ports, headset_ports[i]);
|
pa_device_port *p = pa_hashmap_get(u->card->ports, headset_ports[i]);
|
||||||
pa_log_debug("headset device port %d, %d", i, p);
|
|
||||||
if (p)
|
if (p)
|
||||||
pa_device_port_set_available(p, has_headset);
|
pa_device_port_set_available(p, has_headset);
|
||||||
}
|
}
|
||||||
|
|
@ -207,6 +207,7 @@ static void evdev_cb(pa_mainloop_api *a, pa_io_event *e, int fd,
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
pa_log_debug("Unknown switch %d", ev.code);
|
pa_log_debug("Unknown switch %d", ev.code);
|
||||||
|
|
||||||
/* Ignore unknown switch. */
|
/* Ignore unknown switch. */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2013-2018 Jolla Ltd.
|
* Copyright (C) 2013-2022 Jolla Ltd.
|
||||||
* Copyright (C) 2010 Nokia Corporation.
|
* Copyright (C) 2010 Nokia Corporation.
|
||||||
*
|
*
|
||||||
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
||||||
|
|
@ -61,6 +61,7 @@
|
||||||
#include "droid-sink.h"
|
#include "droid-sink.h"
|
||||||
#include <droid/droid-util.h>
|
#include <droid/droid-util.h>
|
||||||
#include <droid/conversion.h>
|
#include <droid/conversion.h>
|
||||||
|
#include <droid/sllist.h>
|
||||||
|
|
||||||
struct userdata {
|
struct userdata {
|
||||||
pa_core *core;
|
pa_core *core;
|
||||||
|
|
@ -80,18 +81,10 @@ struct userdata {
|
||||||
pa_usec_t buffer_time;
|
pa_usec_t buffer_time;
|
||||||
pa_usec_t write_time;
|
pa_usec_t write_time;
|
||||||
pa_usec_t write_threshold;
|
pa_usec_t write_threshold;
|
||||||
audio_devices_t prewrite_devices;
|
|
||||||
bool prewrite_always;
|
|
||||||
uint32_t prewrite_silence;
|
|
||||||
pa_hook_slot *sink_put_hook_slot;
|
|
||||||
pa_hook_slot *sink_unlink_hook_slot;
|
|
||||||
pa_hook_slot *sink_port_changed_hook_slot;
|
|
||||||
pa_sink *primary_stream_sink;
|
|
||||||
|
|
||||||
audio_devices_t primary_devices;
|
dm_config_port *active_device_port;
|
||||||
audio_devices_t extra_devices;
|
dm_config_port *override_device_port;
|
||||||
pa_hashmap *extra_devices_map;
|
dm_list *extra_devices_stack;
|
||||||
bool mix_route;
|
|
||||||
|
|
||||||
bool use_hw_volume;
|
bool use_hw_volume;
|
||||||
bool use_voice_volume;
|
bool use_voice_volume;
|
||||||
|
|
@ -99,7 +92,6 @@ struct userdata {
|
||||||
char *voice_property_key;
|
char *voice_property_key;
|
||||||
char *voice_property_value;
|
char *voice_property_value;
|
||||||
pa_sink_input *voice_virtual_sink_input;
|
pa_sink_input *voice_virtual_sink_input;
|
||||||
pa_sink_input *voice_control_sink_input;
|
|
||||||
pa_hook_slot *sink_input_volume_changed_hook_slot;
|
pa_hook_slot *sink_input_volume_changed_hook_slot;
|
||||||
|
|
||||||
pa_hook_slot *sink_input_put_hook_slot;
|
pa_hook_slot *sink_input_put_hook_slot;
|
||||||
|
|
@ -137,87 +129,84 @@ static void set_voice_volume(struct userdata *u, pa_sink_input *i);
|
||||||
static void apply_volume(pa_sink *s);
|
static void apply_volume(pa_sink *s);
|
||||||
static pa_sink_input *find_volume_control_sink_input(struct userdata *u);
|
static pa_sink_input *find_volume_control_sink_input(struct userdata *u);
|
||||||
|
|
||||||
static void set_primary_devices(struct userdata *u, audio_devices_t devices) {
|
static bool add_extra_devices(struct userdata *u, audio_devices_t device) {
|
||||||
pa_assert(u);
|
dm_list_entry *prev;
|
||||||
pa_assert(devices);
|
dm_config_port *device_port;
|
||||||
|
|
||||||
u->primary_devices = devices;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool add_extra_devices(struct userdata *u, audio_devices_t devices) {
|
|
||||||
void *value;
|
|
||||||
uint32_t count;
|
|
||||||
bool need_update = false;
|
|
||||||
|
|
||||||
pa_assert(u);
|
pa_assert(u);
|
||||||
pa_assert(u->extra_devices_map);
|
pa_assert(u->extra_devices_stack);
|
||||||
pa_assert(devices);
|
|
||||||
|
|
||||||
if ((value = pa_hashmap_get(u->extra_devices_map, PA_UINT_TO_PTR(devices)))) {
|
if (!(device_port = dm_config_find_device_port(u->active_device_port, device))) {
|
||||||
count = PA_PTR_TO_UINT(value);
|
pa_log("Unknown device port %u", device);
|
||||||
count++;
|
return false;
|
||||||
pa_hashmap_remove(u->extra_devices_map, PA_UINT_TO_PTR(devices));
|
|
||||||
pa_hashmap_put(u->extra_devices_map, PA_UINT_TO_PTR(devices), PA_UINT_TO_PTR(count));
|
|
||||||
|
|
||||||
/* added extra device already exists in hashmap, so no need to update route. */
|
|
||||||
need_update = false;
|
|
||||||
} else {
|
|
||||||
pa_hashmap_put(u->extra_devices_map, PA_UINT_TO_PTR(devices), PA_UINT_TO_PTR(1));
|
|
||||||
u->extra_devices |= devices;
|
|
||||||
need_update = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return need_update;
|
prev = dm_list_last(u->extra_devices_stack);
|
||||||
|
|
||||||
|
dm_list_push_back(u->extra_devices_stack, device_port);
|
||||||
|
|
||||||
|
if (prev) {
|
||||||
|
dm_config_port *last_port = prev->data;
|
||||||
|
if (dm_config_port_equal(last_port, device_port))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
u->override_device_port = device_port;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool remove_extra_devices(struct userdata *u, audio_devices_t devices) {
|
static bool remove_extra_devices(struct userdata *u, audio_devices_t device) {
|
||||||
void *value;
|
dm_config_port *device_port;
|
||||||
uint32_t count;
|
dm_list_entry *remove = NULL, *i = NULL;
|
||||||
bool need_update = false;
|
bool need_update = false;
|
||||||
|
|
||||||
pa_assert(u);
|
pa_assert(u);
|
||||||
pa_assert(u->extra_devices_map);
|
pa_assert(u->extra_devices_stack);
|
||||||
pa_assert(devices);
|
|
||||||
|
|
||||||
if ((value = pa_hashmap_get(u->extra_devices_map, PA_UINT_TO_PTR(devices)))) {
|
if (!(device_port = dm_config_find_device_port(u->active_device_port, device))) {
|
||||||
pa_hashmap_remove(u->extra_devices_map, PA_UINT_TO_PTR(devices));
|
pa_log("Unknown device port %u", device);
|
||||||
count = PA_PTR_TO_UINT(value);
|
return false;
|
||||||
count--;
|
}
|
||||||
if (count == 0) {
|
|
||||||
u->extra_devices &= ~devices;
|
DM_LIST_FOREACH(i, u->extra_devices_stack) {
|
||||||
need_update = true;
|
if (dm_config_port_equal(i->data, device_port)) {
|
||||||
} else {
|
remove = i;
|
||||||
/* added extra devices still exists in hashmap, so no need to update route. */
|
break;
|
||||||
pa_hashmap_put(u->extra_devices_map, PA_UINT_TO_PTR(devices), PA_UINT_TO_PTR(count));
|
|
||||||
need_update = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (remove && dm_list_last(u->extra_devices_stack) == remove)
|
||||||
|
need_update = true;
|
||||||
|
|
||||||
|
if (remove)
|
||||||
|
dm_list_remove(u->extra_devices_stack, remove);
|
||||||
|
|
||||||
return need_update;
|
return need_update;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clear_extra_devices(struct userdata *u) {
|
static void clear_extra_devices(struct userdata *u) {
|
||||||
pa_assert(u);
|
pa_assert(u);
|
||||||
pa_assert(u->extra_devices_map);
|
pa_assert(u->extra_devices_stack);
|
||||||
|
|
||||||
pa_hashmap_remove_all(u->extra_devices_map);
|
while (dm_list_steal_first(u->extra_devices_stack));
|
||||||
u->extra_devices = 0;
|
u->override_device_port = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called from main context during voice calls, and from IO context during media operation. */
|
/* Called from main context during voice calls, and from IO context during media operation. */
|
||||||
static void do_routing(struct userdata *u) {
|
static void do_routing(struct userdata *u) {
|
||||||
audio_devices_t routing;
|
dm_config_port *routing = NULL;
|
||||||
|
|
||||||
pa_assert(u);
|
pa_assert(u);
|
||||||
pa_assert(u->stream);
|
pa_assert(u->stream);
|
||||||
|
|
||||||
if (u->use_voice_volume && u->extra_devices)
|
if (u->use_voice_volume && u->override_device_port)
|
||||||
clear_extra_devices(u);
|
clear_extra_devices(u);
|
||||||
|
|
||||||
if (!u->mix_route && u->extra_devices)
|
if (u->override_device_port)
|
||||||
routing = u->extra_devices;
|
routing = u->override_device_port;
|
||||||
else
|
else
|
||||||
routing = u->primary_devices | u->extra_devices;
|
routing = u->active_device_port;
|
||||||
|
|
||||||
pa_droid_stream_set_route(u->stream, routing);
|
pa_droid_stream_set_route(u->stream, routing);
|
||||||
}
|
}
|
||||||
|
|
@ -248,30 +237,6 @@ static bool parse_device_list(const char *str, audio_devices_t *dst) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int thread_write_silence(struct userdata *u) {
|
|
||||||
const void *p;
|
|
||||||
ssize_t wrote;
|
|
||||||
|
|
||||||
/* Drop our rendered audio and write silence to HAL. */
|
|
||||||
pa_memblockq_drop(u->memblockq, u->buffer_size);
|
|
||||||
u->write_time = pa_rtclock_now();
|
|
||||||
|
|
||||||
/* We should be able to write everything in one go as long as memblock size
|
|
||||||
* is multiples of buffer_size. Even if we don't write whole buffer size
|
|
||||||
* here it's okay, as long as mute time isn't configured too strictly. */
|
|
||||||
|
|
||||||
p = pa_memblock_acquire_chunk(&u->silence);
|
|
||||||
wrote = pa_droid_stream_write(u->stream, p, u->silence.length);
|
|
||||||
pa_memblock_release(u->silence.memblock);
|
|
||||||
|
|
||||||
u->write_time = pa_rtclock_now() - u->write_time;
|
|
||||||
|
|
||||||
if (wrote < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int thread_write(struct userdata *u) {
|
static int thread_write(struct userdata *u) {
|
||||||
pa_memchunk c;
|
pa_memchunk c;
|
||||||
const void *p;
|
const void *p;
|
||||||
|
|
@ -285,9 +250,6 @@ static int thread_write(struct userdata *u) {
|
||||||
u->write_time = pa_rtclock_now();
|
u->write_time = pa_rtclock_now();
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (pa_droid_quirk(u->hw_module, QUIRK_OUTPUT_MAKE_WRITABLE))
|
|
||||||
pa_memchunk_make_writable(&c, c.length);
|
|
||||||
|
|
||||||
p = pa_memblock_acquire_chunk(&c);
|
p = pa_memblock_acquire_chunk(&c);
|
||||||
wrote = pa_droid_stream_write(u->stream, p, c.length);
|
wrote = pa_droid_stream_write(u->stream, p, c.length);
|
||||||
pa_memblock_release(c.memblock);
|
pa_memblock_release(c.memblock);
|
||||||
|
|
@ -458,8 +420,6 @@ static int suspend(struct userdata *u) {
|
||||||
|
|
||||||
/* Called from IO context */
|
/* Called from IO context */
|
||||||
static int unsuspend(struct userdata *u) {
|
static int unsuspend(struct userdata *u) {
|
||||||
uint32_t i;
|
|
||||||
|
|
||||||
pa_assert(u);
|
pa_assert(u);
|
||||||
pa_assert(u->sink);
|
pa_assert(u->sink);
|
||||||
|
|
||||||
|
|
@ -470,13 +430,6 @@ static int unsuspend(struct userdata *u) {
|
||||||
|
|
||||||
apply_volume(u->sink);
|
apply_volume(u->sink);
|
||||||
|
|
||||||
if (u->prewrite_silence &&
|
|
||||||
(u->primary_devices | u->extra_devices) & u->prewrite_devices &&
|
|
||||||
(u->prewrite_always || pa_droid_output_stream_any_active(u->stream) == 0)) {
|
|
||||||
for (i = 0; i < u->prewrite_silence; i++)
|
|
||||||
thread_write_silence(u);
|
|
||||||
}
|
|
||||||
|
|
||||||
pa_droid_stream_suspend(u->stream, false);
|
pa_droid_stream_suspend(u->stream, false);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -552,7 +505,7 @@ static int sink_set_port_cb(pa_sink *s, pa_device_port *p) {
|
||||||
|
|
||||||
data = PA_DEVICE_PORT_DATA(p);
|
data = PA_DEVICE_PORT_DATA(p);
|
||||||
|
|
||||||
if (!data->device) {
|
if (!data->device_port) {
|
||||||
/* If there is no device defined, just return 0 to say everything is ok.
|
/* If there is no device defined, just return 0 to say everything is ok.
|
||||||
* Then next port change can be whatever sink port, even the one enabled
|
* Then next port change can be whatever sink port, even the one enabled
|
||||||
* before parking. */
|
* before parking. */
|
||||||
|
|
@ -560,9 +513,9 @@ static int sink_set_port_cb(pa_sink *s, pa_device_port *p) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pa_log_debug("Sink set port %u", data->device);
|
pa_log_debug("Sink set port %#010x (%s)", data->device_port->type, data->device_port->name);
|
||||||
|
|
||||||
set_primary_devices(u, data->device);
|
u->active_device_port = data->device_port;
|
||||||
do_routing(u);
|
do_routing(u);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -637,9 +590,9 @@ static void update_volumes(struct userdata *u) {
|
||||||
u->use_hw_volume = (ret == 0);
|
u->use_hw_volume = (ret == 0);
|
||||||
if (u->use_hw_volume &&
|
if (u->use_hw_volume &&
|
||||||
#if defined(HAVE_ENUM_AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)
|
#if defined(HAVE_ENUM_AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)
|
||||||
!(u->stream->output->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
|
!(u->stream->mix_port->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
|
||||||
#endif
|
#endif
|
||||||
pa_droid_quirk(u->hw_module, QUIRK_NO_HW_VOLUME)) {
|
!pa_droid_option(u->hw_module, DM_OPTION_HW_VOLUME)) {
|
||||||
pa_log_info("Forcing software volume control with %s", u->sink->name);
|
pa_log_info("Forcing software volume control with %s", u->sink->name);
|
||||||
u->use_hw_volume = false;
|
u->use_hw_volume = false;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -653,7 +606,7 @@ static void update_volumes(struct userdata *u) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_sink_name(pa_modargs *ma, pa_sink_new_data *data, const char *module_id) {
|
static void set_sink_name(pa_modargs *ma, pa_sink_new_data *data, pa_droid_mapping *am, const char *name) {
|
||||||
const char *tmp;
|
const char *tmp;
|
||||||
|
|
||||||
pa_assert(ma);
|
pa_assert(ma);
|
||||||
|
|
@ -664,13 +617,14 @@ static void set_sink_name(pa_modargs *ma, pa_sink_new_data *data, const char *mo
|
||||||
data->namereg_fail = true;
|
data->namereg_fail = true;
|
||||||
pa_proplist_sets(data->proplist, PA_PROP_DEVICE_DESCRIPTION, "Droid sink");
|
pa_proplist_sets(data->proplist, PA_PROP_DEVICE_DESCRIPTION, "Droid sink");
|
||||||
} else {
|
} else {
|
||||||
char *tt;
|
char *full_name;
|
||||||
pa_assert(module_id);
|
pa_assert(name);
|
||||||
tt = pa_sprintf_malloc("sink.%s", module_id);
|
pa_assert(am);
|
||||||
pa_sink_new_data_set_name(data, tt);
|
full_name = pa_sprintf_malloc("sink.%s", name);
|
||||||
pa_xfree(tt);
|
pa_sink_new_data_set_name(data, full_name);
|
||||||
|
pa_xfree(full_name);
|
||||||
data->namereg_fail = false;
|
data->namereg_fail = false;
|
||||||
pa_proplist_setf(data->proplist, PA_PROP_DEVICE_DESCRIPTION, "Droid sink %s", module_id);
|
pa_proplist_setf(data->proplist, PA_PROP_DEVICE_DESCRIPTION, "Droid sink %s", am->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -714,13 +668,8 @@ static pa_hook_result_t sink_input_volume_changed_hook_cb(pa_core *c, pa_sink_in
|
||||||
if (!u->use_voice_volume)
|
if (!u->use_voice_volume)
|
||||||
return PA_HOOK_OK;
|
return PA_HOOK_OK;
|
||||||
|
|
||||||
if (!u->voice_control_sink_input && sink_input_is_voice_control(u, sink_input))
|
if (sink_input_is_voice_control(u, sink_input))
|
||||||
u->voice_control_sink_input = sink_input;
|
set_voice_volume(u, sink_input);
|
||||||
|
|
||||||
if (u->voice_control_sink_input != sink_input)
|
|
||||||
return PA_HOOK_OK;
|
|
||||||
|
|
||||||
set_voice_volume(u, sink_input);
|
|
||||||
|
|
||||||
return PA_HOOK_OK;
|
return PA_HOOK_OK;
|
||||||
}
|
}
|
||||||
|
|
@ -823,14 +772,10 @@ void pa_droid_sink_set_voice_control(pa_sink* sink, bool enable) {
|
||||||
if (u->voice_virtual_stream)
|
if (u->voice_virtual_stream)
|
||||||
create_voice_virtual_stream(u);
|
create_voice_virtual_stream(u);
|
||||||
|
|
||||||
if (u->use_hw_volume)
|
|
||||||
pa_sink_set_set_volume_callback(u->sink, NULL);
|
|
||||||
|
|
||||||
u->sink_input_volume_changed_hook_slot = pa_hook_connect(&u->core->hooks[PA_CORE_HOOK_SINK_INPUT_VOLUME_CHANGED],
|
u->sink_input_volume_changed_hook_slot = pa_hook_connect(&u->core->hooks[PA_CORE_HOOK_SINK_INPUT_VOLUME_CHANGED],
|
||||||
PA_HOOK_LATE+10, (pa_hook_cb_t) sink_input_volume_changed_hook_cb, u);
|
PA_HOOK_LATE+10, (pa_hook_cb_t) sink_input_volume_changed_hook_cb, u);
|
||||||
|
|
||||||
if ((i = find_volume_control_sink_input(u))) {
|
if ((i = find_volume_control_sink_input(u))) {
|
||||||
u->voice_control_sink_input = i;
|
|
||||||
set_voice_volume(u, i);
|
set_voice_volume(u, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -840,15 +785,11 @@ void pa_droid_sink_set_voice_control(pa_sink* sink, bool enable) {
|
||||||
if (u->voice_virtual_stream)
|
if (u->voice_virtual_stream)
|
||||||
destroy_voice_virtual_stream(u);
|
destroy_voice_virtual_stream(u);
|
||||||
|
|
||||||
u->voice_control_sink_input = NULL;
|
|
||||||
pa_hook_slot_free(u->sink_input_volume_changed_hook_slot);
|
pa_hook_slot_free(u->sink_input_volume_changed_hook_slot);
|
||||||
u->sink_input_volume_changed_hook_slot = NULL;
|
u->sink_input_volume_changed_hook_slot = NULL;
|
||||||
|
|
||||||
pa_log_debug("Using %s volume control with %s",
|
pa_log_debug("Using %s volume control with %s",
|
||||||
u->use_hw_volume ? "hardware" : "software", u->sink->name);
|
u->use_hw_volume ? "hardware" : "software", u->sink->name);
|
||||||
|
|
||||||
if (u->use_hw_volume)
|
|
||||||
pa_sink_set_set_volume_callback(u->sink, sink_set_volume_cb);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -859,8 +800,7 @@ static pa_hook_result_t sink_input_put_hook_cb(pa_core *c, pa_sink_input *sink_i
|
||||||
const char *media_str;
|
const char *media_str;
|
||||||
audio_devices_t devices;
|
audio_devices_t devices;
|
||||||
|
|
||||||
if (u->use_voice_volume && !u->voice_control_sink_input && sink_input_is_voice_control(u, sink_input)) {
|
if (u->use_voice_volume && sink_input_is_voice_control(u, sink_input)) {
|
||||||
u->voice_control_sink_input = sink_input;
|
|
||||||
set_voice_volume(u, sink_input);
|
set_voice_volume(u, sink_input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -878,7 +818,7 @@ static pa_hook_result_t sink_input_put_hook_cb(pa_core *c, pa_sink_input *sink_i
|
||||||
|
|
||||||
if (parse_device_list(dev_str, &devices) && devices) {
|
if (parse_device_list(dev_str, &devices) && devices) {
|
||||||
|
|
||||||
pa_log_debug("Add extra route %s (%u).", dev_str, devices);
|
pa_log_debug("%s: Add extra route %s (%u).", u->sink->name, dev_str, devices);
|
||||||
|
|
||||||
/* if this device was not routed to previously post routing change */
|
/* if this device was not routed to previously post routing change */
|
||||||
if (add_extra_devices(u, devices))
|
if (add_extra_devices(u, devices))
|
||||||
|
|
@ -895,9 +835,6 @@ static pa_hook_result_t sink_input_unlink_hook_cb(pa_core *c, pa_sink_input *sin
|
||||||
const char *media_str;
|
const char *media_str;
|
||||||
audio_devices_t devices;
|
audio_devices_t devices;
|
||||||
|
|
||||||
if (u->voice_control_sink_input == sink_input)
|
|
||||||
u->voice_control_sink_input = NULL;
|
|
||||||
|
|
||||||
/* Dynamic routing changes do not apply during active voice call. */
|
/* Dynamic routing changes do not apply during active voice call. */
|
||||||
if (u->use_voice_volume)
|
if (u->use_voice_volume)
|
||||||
return PA_HOOK_OK;
|
return PA_HOOK_OK;
|
||||||
|
|
@ -977,167 +914,6 @@ static pa_hook_result_t sink_proplist_changed_hook_cb(pa_core *c, pa_sink *sink,
|
||||||
return PA_HOOK_OK;
|
return PA_HOOK_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static pa_hook_result_t sink_port_changed_hook_cb(pa_core *c, pa_sink *sink, struct userdata *u) {
|
|
||||||
pa_device_port *port;
|
|
||||||
|
|
||||||
pa_assert(c);
|
|
||||||
pa_assert(sink);
|
|
||||||
pa_assert(u);
|
|
||||||
|
|
||||||
if (sink != u->primary_stream_sink)
|
|
||||||
return PA_HOOK_OK;
|
|
||||||
|
|
||||||
port = sink->active_port;
|
|
||||||
pa_log_info("Set slave sink port to %s", port->name);
|
|
||||||
pa_sink_set_port(u->sink, port->name, false);
|
|
||||||
|
|
||||||
return PA_HOOK_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void unset_primary_stream_sink(struct userdata *u) {
|
|
||||||
pa_assert(u);
|
|
||||||
pa_assert(u->primary_stream_sink);
|
|
||||||
pa_assert(u->sink_port_changed_hook_slot);
|
|
||||||
|
|
||||||
pa_hook_slot_free(u->sink_port_changed_hook_slot);
|
|
||||||
u->sink_port_changed_hook_slot = NULL;
|
|
||||||
u->primary_stream_sink = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static pa_hook_result_t sink_unlink_hook_cb(pa_core *c, pa_sink *sink, struct userdata *u) {
|
|
||||||
pa_assert(c);
|
|
||||||
pa_assert(sink);
|
|
||||||
pa_assert(u);
|
|
||||||
|
|
||||||
if (sink != u->primary_stream_sink)
|
|
||||||
return PA_HOOK_OK;
|
|
||||||
|
|
||||||
pa_log_info("Primary stream sink disappeared.");
|
|
||||||
unset_primary_stream_sink(u);
|
|
||||||
|
|
||||||
return PA_HOOK_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static pa_hook_result_t sink_put_hook_cb(pa_core *c, pa_sink *sink, struct userdata *u) {
|
|
||||||
struct userdata *sink_u;
|
|
||||||
|
|
||||||
pa_assert(c);
|
|
||||||
pa_assert(sink);
|
|
||||||
pa_assert(u);
|
|
||||||
|
|
||||||
if (!pa_sink_is_droid_sink(sink))
|
|
||||||
return PA_HOOK_OK;
|
|
||||||
|
|
||||||
sink_u = sink->userdata;
|
|
||||||
|
|
||||||
if (!pa_droid_stream_is_primary(sink_u->stream))
|
|
||||||
return PA_HOOK_OK;
|
|
||||||
|
|
||||||
u->primary_stream_sink = sink;
|
|
||||||
|
|
||||||
pa_assert(!u->sink_port_changed_hook_slot);
|
|
||||||
u->sink_port_changed_hook_slot = pa_hook_connect(&u->core->hooks[PA_CORE_HOOK_SINK_PORT_CHANGED], PA_HOOK_NORMAL,
|
|
||||||
(pa_hook_cb_t) sink_port_changed_hook_cb, u);
|
|
||||||
|
|
||||||
pa_log_info("Primary stream sink setup for slave.");
|
|
||||||
|
|
||||||
sink_port_changed_hook_cb(c, sink, u);
|
|
||||||
|
|
||||||
return PA_HOOK_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setup_track_primary(struct userdata *u) {
|
|
||||||
pa_sink *sink;
|
|
||||||
struct userdata *sink_u;
|
|
||||||
uint32_t idx;
|
|
||||||
|
|
||||||
pa_assert(u);
|
|
||||||
|
|
||||||
u->sink_put_hook_slot = pa_hook_connect(&u->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_NORMAL,
|
|
||||||
(pa_hook_cb_t) sink_put_hook_cb, u);
|
|
||||||
u->sink_unlink_hook_slot = pa_hook_connect(&u->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_NORMAL,
|
|
||||||
(pa_hook_cb_t) sink_unlink_hook_cb, u);
|
|
||||||
|
|
||||||
PA_IDXSET_FOREACH(sink, u->core->sinks, idx) {
|
|
||||||
if (pa_sink_is_droid_sink(sink)) {
|
|
||||||
sink_u = sink->userdata;
|
|
||||||
if (pa_droid_stream_is_primary(sink_u->stream)) {
|
|
||||||
sink_put_hook_cb(u->core, sink, u);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool parse_prewrite_on_resume(struct userdata *u, const char *prewrite_resume, const char *name) {
|
|
||||||
const char *state = NULL;
|
|
||||||
char *entry = NULL;
|
|
||||||
char *devices, *stream, *value;
|
|
||||||
uint32_t devices_len, devices_index, value_index, entry_len;
|
|
||||||
uint32_t b;
|
|
||||||
|
|
||||||
pa_assert(u);
|
|
||||||
pa_assert(prewrite_resume);
|
|
||||||
pa_assert(name);
|
|
||||||
|
|
||||||
/* Argument is string of for example "deep_buffer=AUDIO_DEVICE_OUT_SPEAKER:1,primary=FOO:5" */
|
|
||||||
|
|
||||||
while ((entry = pa_split(prewrite_resume, ",", &state))) {
|
|
||||||
audio_devices_t prewrite_devices = 0;
|
|
||||||
bool prewrite_always = false;
|
|
||||||
char *tmp;
|
|
||||||
|
|
||||||
entry_len = strlen(entry);
|
|
||||||
devices_index = strcspn(entry, "=");
|
|
||||||
|
|
||||||
if (devices_index == 0 || devices_index >= entry_len - 1)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
entry[devices_index] = '\0';
|
|
||||||
devices = entry + devices_index + 1;
|
|
||||||
stream = entry;
|
|
||||||
|
|
||||||
devices_len = strlen(devices);
|
|
||||||
value_index = strcspn(devices, ":");
|
|
||||||
|
|
||||||
if (value_index == 0 || value_index >= devices_len - 1)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
devices[value_index] = '\0';
|
|
||||||
value = devices + value_index + 1;
|
|
||||||
|
|
||||||
if (!parse_device_list(devices, &prewrite_devices))
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if ((tmp = strstr(value, "/always"))) {
|
|
||||||
prewrite_always = true;
|
|
||||||
*tmp = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlen(value) == 0 || pa_atou(value, &b) < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (pa_streq(stream, name)) {
|
|
||||||
pa_log_info("Using requested prewrite%s size for %s: %zu (%u * %zu).",
|
|
||||||
prewrite_always ? "_always" : "",
|
|
||||||
name, u->buffer_size * b, b, u->buffer_size);
|
|
||||||
u->prewrite_devices = prewrite_devices;
|
|
||||||
u->prewrite_always = prewrite_always;
|
|
||||||
u->prewrite_silence = b;
|
|
||||||
pa_xfree(entry);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
pa_xfree(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
error:
|
|
||||||
pa_xfree(entry);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
pa_sink *pa_droid_sink_new(pa_module *m,
|
pa_sink *pa_droid_sink_new(pa_module *m,
|
||||||
pa_modargs *ma,
|
pa_modargs *ma,
|
||||||
const char *driver,
|
const char *driver,
|
||||||
|
|
@ -1147,24 +923,22 @@ pa_sink *pa_droid_sink_new(pa_module *m,
|
||||||
pa_card *card) {
|
pa_card *card) {
|
||||||
|
|
||||||
struct userdata *u = NULL;
|
struct userdata *u = NULL;
|
||||||
const pa_droid_config_device *output = NULL;
|
dm_config_port *mix_port = NULL;
|
||||||
|
dm_config_port *device_port = NULL;
|
||||||
bool deferred_volume = false;
|
bool deferred_volume = false;
|
||||||
bool voice_virtual_stream = false;
|
bool voice_virtual_stream = false;
|
||||||
char *thread_name = NULL;
|
char *thread_name = NULL;
|
||||||
pa_sink_new_data data;
|
pa_sink_new_data data;
|
||||||
const char *module_id = NULL;
|
const char *module_id = NULL;
|
||||||
const char *tmp;
|
|
||||||
char *list = NULL;
|
char *list = NULL;
|
||||||
uint32_t alternate_sample_rate;
|
uint32_t alternate_sample_rate;
|
||||||
const char *format;
|
const char *format;
|
||||||
audio_devices_t dev_out;
|
|
||||||
pa_sample_spec sample_spec;
|
pa_sample_spec sample_spec;
|
||||||
pa_channel_map channel_map;
|
pa_channel_map channel_map;
|
||||||
bool namereg_fail = false;
|
bool namereg_fail = false;
|
||||||
pa_usec_t latency;
|
pa_usec_t latency;
|
||||||
uint32_t sink_buffer = 0;
|
uint32_t sink_buffer = 0;
|
||||||
const char *prewrite_resume = NULL;
|
char *sink_name = NULL;
|
||||||
bool mix_route = false;
|
|
||||||
|
|
||||||
pa_assert(m);
|
pa_assert(m);
|
||||||
pa_assert(ma);
|
pa_assert(ma);
|
||||||
|
|
@ -1179,8 +953,8 @@ pa_sink *pa_droid_sink_new(pa_module *m,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (card && am) {
|
if (card && am) {
|
||||||
output = am->output;
|
mix_port = am->mix_port;
|
||||||
module_id = output->module->name;
|
module_id = mix_port->name;
|
||||||
} else
|
} else
|
||||||
module_id = pa_modargs_get_value(ma, "module_id", DEFAULT_MODULE_ID);
|
module_id = pa_modargs_get_value(ma, "module_id", DEFAULT_MODULE_ID);
|
||||||
|
|
||||||
|
|
@ -1189,18 +963,22 @@ pa_sink *pa_droid_sink_new(pa_module *m,
|
||||||
|
|
||||||
/* First parse both sample spec and channel map, then see if sink_* override some
|
/* First parse both sample spec and channel map, then see if sink_* override some
|
||||||
* of the values. */
|
* 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 sink sample specification and channel map.");
|
if (pa_modargs_get_sample_spec(ma, &sample_spec) < 0) {
|
||||||
|
pa_log("Failed to parse sink sample specification.");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pa_modargs_get_value(ma, "sink_channel_map", NULL)) {
|
if (pa_modargs_get_channel_map(ma, NULL, &channel_map) < 0) {
|
||||||
if (pa_modargs_get_channel_map(ma, "sink_channel_map", &channel_map) < 0) {
|
pa_log("Failed to parse sink channel map.");
|
||||||
pa_log("Failed to parse sink channel map.");
|
goto fail;
|
||||||
goto fail;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
sample_spec.channels = channel_map.channels;
|
/* Possible overrides. */
|
||||||
|
|
||||||
|
if (pa_modargs_get_channel_map(ma, "sink_channel_map", &channel_map) < 0) {
|
||||||
|
pa_log("Failed to parse sink channel map.");
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((format = pa_modargs_get_value(ma, "sink_format", NULL))) {
|
if ((format = pa_modargs_get_value(ma, "sink_format", NULL))) {
|
||||||
|
|
@ -1210,6 +988,11 @@ pa_sink *pa_droid_sink_new(pa_module *m,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pa_modargs_get_value_u32(ma, "rate", &sample_spec.rate) < 0) {
|
||||||
|
pa_log("Failed to parse sink samplerate");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
if (pa_modargs_get_value_u32(ma, "sink_rate", &sample_spec.rate) < 0) {
|
if (pa_modargs_get_value_u32(ma, "sink_rate", &sample_spec.rate) < 0) {
|
||||||
pa_log("Failed to parse sink samplerate");
|
pa_log("Failed to parse sink samplerate");
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
@ -1231,11 +1014,6 @@ pa_sink *pa_droid_sink_new(pa_module *m,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pa_modargs_get_value_boolean(ma, "sink_mix_route", &mix_route) < 0) {
|
|
||||||
pa_log("Failed to parse sink_mix_route, expects boolean argument.");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pa_modargs_get_value_boolean(ma, "voice_virtual_stream", &voice_virtual_stream) < 0) {
|
if (pa_modargs_get_value_boolean(ma, "voice_virtual_stream", &voice_virtual_stream) < 0) {
|
||||||
pa_log("Failed to parse voice_virtual_stream. Needs to be a boolean argument.");
|
pa_log("Failed to parse voice_virtual_stream. Needs to be a boolean argument.");
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
@ -1253,8 +1031,7 @@ pa_sink *pa_droid_sink_new(pa_module *m,
|
||||||
u->voice_virtual_stream = voice_virtual_stream;
|
u->voice_virtual_stream = voice_virtual_stream;
|
||||||
u->voice_property_key = pa_xstrdup(pa_modargs_get_value(ma, "voice_property_key", DEFAULT_VOICE_CONTROL_PROPERTY_KEY));
|
u->voice_property_key = pa_xstrdup(pa_modargs_get_value(ma, "voice_property_key", DEFAULT_VOICE_CONTROL_PROPERTY_KEY));
|
||||||
u->voice_property_value = pa_xstrdup(pa_modargs_get_value(ma, "voice_property_value", DEFAULT_VOICE_CONTROL_PROPERTY_VALUE));
|
u->voice_property_value = pa_xstrdup(pa_modargs_get_value(ma, "voice_property_value", DEFAULT_VOICE_CONTROL_PROPERTY_VALUE));
|
||||||
u->extra_devices_map = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
|
u->extra_devices_stack = dm_list_new();
|
||||||
u->mix_route = mix_route;
|
|
||||||
|
|
||||||
if (card_data) {
|
if (card_data) {
|
||||||
u->card_data = card_data;
|
u->card_data = card_data;
|
||||||
|
|
@ -1268,34 +1045,25 @@ pa_sink *pa_droid_sink_new(pa_module *m,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(output = pa_droid_config_find_output(u->hw_module->enabled_module, output_name))) {
|
|
||||||
pa_log("Could not find output %s from module %s.", output_name, u->hw_module->enabled_module->name);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sink wasn't created from inside card module, so we'll need to open
|
/* Sink wasn't created from inside card module, so we'll need to open
|
||||||
* hw module ourself. */
|
* hw module ourself. */
|
||||||
|
|
||||||
if (!(u->hw_module = pa_droid_hw_module_get2(u->core, ma, module_id)))
|
if (!(u->hw_module = pa_droid_hw_module_get2(u->core, ma, module_id)))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
if (!(mix_port = dm_config_find_port(u->hw_module->enabled_module, output_name)) ||
|
||||||
|
mix_port->port_type != DM_CONFIG_TYPE_MIX_PORT) {
|
||||||
|
pa_log("Could not find output %s from module %s.", output_name, u->hw_module->enabled_module->name);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Default routing */
|
pa_assert(mix_port);
|
||||||
dev_out = output->module->global_config ? output->module->global_config->default_output_device
|
|
||||||
: u->hw_module->config->global_config->default_output_device;
|
|
||||||
|
|
||||||
if ((tmp = pa_modargs_get_value(ma, "output_devices", NULL))) {
|
/* Start with default output device */
|
||||||
audio_devices_t tmp_dev;
|
device_port = dm_config_default_output_device(mix_port->module);
|
||||||
|
|
||||||
if (parse_device_list(tmp, &tmp_dev) && tmp_dev)
|
u->stream = pa_droid_open_output_stream(u->hw_module, &sample_spec, &channel_map, mix_port, device_port);
|
||||||
dev_out = tmp_dev;
|
|
||||||
|
|
||||||
pa_log_debug("Set initial devices %s", tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
flags = output->flags;
|
|
||||||
|
|
||||||
u->stream = pa_droid_open_output_stream(u->hw_module, &sample_spec, &channel_map, output->name, dev_out);
|
|
||||||
|
|
||||||
if (!u->stream) {
|
if (!u->stream) {
|
||||||
pa_log("Failed to open output stream.");
|
pa_log("Failed to open output stream.");
|
||||||
|
|
@ -1309,13 +1077,6 @@ pa_sink *pa_droid_sink_new(pa_module *m,
|
||||||
} else
|
} else
|
||||||
pa_log_info("Using buffer size %zu.", u->buffer_size);
|
pa_log_info("Using buffer size %zu.", u->buffer_size);
|
||||||
|
|
||||||
if ((prewrite_resume = pa_modargs_get_value(ma, "prewrite_on_resume", NULL))) {
|
|
||||||
if (!parse_prewrite_on_resume(u, prewrite_resume, output->name)) {
|
|
||||||
pa_log("Failed to parse prewrite_on_resume (%s)", prewrite_resume);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
u->buffer_time = pa_bytes_to_usec(u->buffer_size, &u->stream->output->sample_spec);
|
u->buffer_time = pa_bytes_to_usec(u->buffer_size, &u->stream->output->sample_spec);
|
||||||
u->write_threshold = u->buffer_time - u->buffer_time / 6;
|
u->write_threshold = u->buffer_time - u->buffer_time / 6;
|
||||||
|
|
||||||
|
|
@ -1327,7 +1088,8 @@ pa_sink *pa_droid_sink_new(pa_module *m,
|
||||||
data.module = m;
|
data.module = m;
|
||||||
data.card = card;
|
data.card = card;
|
||||||
|
|
||||||
set_sink_name(ma, &data, output->name);
|
sink_name = dm_config_escape_string(module_id);
|
||||||
|
set_sink_name(ma, &data, am, sink_name);
|
||||||
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "sound");
|
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, PA_PROP_DEVICE_API, PROP_DROID_API_STRING);
|
||||||
|
|
||||||
|
|
@ -1347,15 +1109,6 @@ pa_sink *pa_droid_sink_new(pa_module *m,
|
||||||
pa_sink_new_data_set_channel_map(&data, &u->stream->output->channel_map);
|
pa_sink_new_data_set_channel_map(&data, &u->stream->output->channel_map);
|
||||||
pa_sink_new_data_set_alternate_sample_rate(&data, alternate_sample_rate);
|
pa_sink_new_data_set_alternate_sample_rate(&data, alternate_sample_rate);
|
||||||
|
|
||||||
/*
|
|
||||||
if (!(list = pa_list_string_output_device(dev_out))) {
|
|
||||||
pa_log("Couldn't format device list string.");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
pa_proplist_sets(data.proplist, PROP_DROID_DEVICES, list);
|
|
||||||
pa_xfree(list);
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (flags) {
|
if (flags) {
|
||||||
if (!(list = pa_list_string_flags(flags))) {
|
if (!(list = pa_list_string_flags(flags))) {
|
||||||
pa_log("Couldn't format flag list string.");
|
pa_log("Couldn't format flag list string.");
|
||||||
|
|
@ -1383,15 +1136,13 @@ pa_sink *pa_droid_sink_new(pa_module *m,
|
||||||
u->sink->parent.process_msg = sink_process_msg;
|
u->sink->parent.process_msg = sink_process_msg;
|
||||||
u->sink->set_state_in_io_thread = sink_set_state_in_io_thread_cb;
|
u->sink->set_state_in_io_thread = sink_set_state_in_io_thread_cb;
|
||||||
|
|
||||||
u->sink->set_port = sink_set_port_cb;
|
|
||||||
|
|
||||||
pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
|
pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
|
||||||
pa_sink_set_rtpoll(u->sink, u->rtpoll);
|
pa_sink_set_rtpoll(u->sink, u->rtpoll);
|
||||||
|
|
||||||
/* Rewind internal memblockq */
|
/* Rewind internal memblockq */
|
||||||
pa_sink_set_max_rewind(u->sink, 0);
|
pa_sink_set_max_rewind(u->sink, 0);
|
||||||
|
|
||||||
thread_name = pa_sprintf_malloc("droid-sink-%s", output->name);
|
thread_name = pa_sprintf_malloc("droid-sink-%s", sink_name);
|
||||||
if (!(u->thread = pa_thread_new(thread_name, thread_func, u))) {
|
if (!(u->thread = pa_thread_new(thread_name, thread_func, u))) {
|
||||||
pa_log("Failed to create thread.");
|
pa_log("Failed to create thread.");
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
@ -1408,28 +1159,34 @@ pa_sink *pa_droid_sink_new(pa_module *m,
|
||||||
if (u->sink->active_port)
|
if (u->sink->active_port)
|
||||||
sink_set_port_cb(u->sink, u->sink->active_port);
|
sink_set_port_cb(u->sink, u->sink->active_port);
|
||||||
|
|
||||||
/* Hooks to track appearance and disappearance of sink-inputs. */
|
if (pa_droid_stream_is_primary(u->stream)) {
|
||||||
/* Hook a little bit earlier and later than module-role-ducking. */
|
/* Hooks to track appearance and disappearance of sink-inputs.
|
||||||
u->sink_input_put_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], PA_HOOK_LATE+10,
|
* Hook a little bit earlier and later than module-role-ducking.
|
||||||
(pa_hook_cb_t) sink_input_put_hook_cb, u);
|
* Used only in primary sink. */
|
||||||
u->sink_input_unlink_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK], PA_HOOK_EARLY-10,
|
u->sink_input_put_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], PA_HOOK_LATE+10,
|
||||||
(pa_hook_cb_t) sink_input_unlink_hook_cb, u);
|
(pa_hook_cb_t) sink_input_put_hook_cb, u);
|
||||||
u->sink_proplist_changed_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], PA_HOOK_EARLY,
|
u->sink_input_unlink_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK], PA_HOOK_EARLY-10,
|
||||||
(pa_hook_cb_t) sink_proplist_changed_hook_cb, u);
|
(pa_hook_cb_t) sink_input_unlink_hook_cb, u);
|
||||||
|
u->sink_proplist_changed_hook_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], PA_HOOK_EARLY,
|
||||||
|
(pa_hook_cb_t) sink_proplist_changed_hook_cb, u);
|
||||||
|
|
||||||
|
/* Port changes are done only in primary sink. */
|
||||||
|
u->sink->set_port = sink_set_port_cb;
|
||||||
|
}
|
||||||
|
|
||||||
update_volumes(u);
|
update_volumes(u);
|
||||||
|
|
||||||
if (!pa_droid_stream_is_primary(u->stream))
|
|
||||||
setup_track_primary(u);
|
|
||||||
|
|
||||||
pa_droid_stream_suspend(u->stream, false);
|
pa_droid_stream_suspend(u->stream, false);
|
||||||
pa_droid_stream_set_data(u->stream, u->sink);
|
pa_droid_stream_set_data(u->stream, u->sink);
|
||||||
pa_sink_put(u->sink);
|
pa_sink_put(u->sink);
|
||||||
|
|
||||||
|
pa_xfree(sink_name);
|
||||||
|
|
||||||
return u->sink;
|
return u->sink;
|
||||||
|
|
||||||
fail:
|
fail:
|
||||||
pa_xfree(thread_name);
|
pa_xfree(thread_name);
|
||||||
|
pa_xfree(sink_name);
|
||||||
|
|
||||||
if (u)
|
if (u)
|
||||||
userdata_free(u);
|
userdata_free(u);
|
||||||
|
|
@ -1456,18 +1213,6 @@ static void parameter_free(droid_parameter_mapping *m) {
|
||||||
|
|
||||||
static void userdata_free(struct userdata *u) {
|
static void userdata_free(struct userdata *u) {
|
||||||
|
|
||||||
if (u->primary_stream_sink)
|
|
||||||
unset_primary_stream_sink(u);
|
|
||||||
|
|
||||||
if (u->sink_put_hook_slot)
|
|
||||||
pa_hook_slot_free(u->sink_put_hook_slot);
|
|
||||||
|
|
||||||
if (u->sink_unlink_hook_slot)
|
|
||||||
pa_hook_slot_free(u->sink_unlink_hook_slot);
|
|
||||||
|
|
||||||
if (u->sink_port_changed_hook_slot)
|
|
||||||
pa_hook_slot_free(u->sink_port_changed_hook_slot);
|
|
||||||
|
|
||||||
if (u->sink)
|
if (u->sink)
|
||||||
pa_sink_unlink(u->sink);
|
pa_sink_unlink(u->sink);
|
||||||
|
|
||||||
|
|
@ -1513,8 +1258,8 @@ static void userdata_free(struct userdata *u) {
|
||||||
if (u->voice_property_value)
|
if (u->voice_property_value)
|
||||||
pa_xfree(u->voice_property_value);
|
pa_xfree(u->voice_property_value);
|
||||||
|
|
||||||
if (u->extra_devices_map)
|
if (u->extra_devices_stack)
|
||||||
pa_hashmap_free(u->extra_devices_map);
|
dm_list_free(u->extra_devices_stack, NULL);
|
||||||
|
|
||||||
pa_xfree(u);
|
pa_xfree(u);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2013-2018 Jolla Ltd.
|
* Copyright (C) 2013-2022 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
||||||
*
|
*
|
||||||
|
|
@ -69,7 +69,6 @@ struct userdata {
|
||||||
pa_rtpoll *rtpoll;
|
pa_rtpoll *rtpoll;
|
||||||
|
|
||||||
pa_memchunk memchunk;
|
pa_memchunk memchunk;
|
||||||
audio_devices_t primary_devices;
|
|
||||||
|
|
||||||
size_t source_buffer_size;
|
size_t source_buffer_size;
|
||||||
size_t buffer_size;
|
size_t buffer_size;
|
||||||
|
|
@ -94,60 +93,14 @@ static void unsuspend(struct userdata *u);
|
||||||
static void source_reconfigure(struct userdata *u,
|
static void source_reconfigure(struct userdata *u,
|
||||||
const pa_sample_spec *reconfigure_sample_spec,
|
const pa_sample_spec *reconfigure_sample_spec,
|
||||||
const pa_channel_map *reconfigure_channel_map,
|
const pa_channel_map *reconfigure_channel_map,
|
||||||
audio_devices_t update_device);
|
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
|
/* 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
|
* if reconfiguration fails and fallback to previously active values fails
|
||||||
* as well. In this case just avoid using the stream but don't die. */
|
* 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)
|
#define assert_stream(x, action) if (!x) do { pa_log_warn("Assert " #x " failed."); action; } while(0)
|
||||||
|
|
||||||
static int do_routing(struct userdata *u, audio_devices_t devices) {
|
|
||||||
int ret;
|
|
||||||
audio_devices_t old_device;
|
|
||||||
|
|
||||||
pa_assert(u);
|
|
||||||
assert_stream(u->stream, return 0);
|
|
||||||
|
|
||||||
if (u->primary_devices == devices)
|
|
||||||
pa_log_debug("Refresh active device routing.");
|
|
||||||
|
|
||||||
old_device = u->primary_devices;
|
|
||||||
u->primary_devices = devices;
|
|
||||||
|
|
||||||
ret = pa_droid_stream_set_route(u->stream, devices);
|
|
||||||
|
|
||||||
if (ret < 0)
|
|
||||||
u->primary_devices = old_device;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool 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) {
|
static int thread_read(struct userdata *u) {
|
||||||
void *p;
|
void *p;
|
||||||
ssize_t readd;
|
ssize_t readd;
|
||||||
|
|
@ -334,7 +287,7 @@ static int source_set_port_cb(pa_source *s, pa_device_port *p) {
|
||||||
|
|
||||||
data = PA_DEVICE_PORT_DATA(p);
|
data = PA_DEVICE_PORT_DATA(p);
|
||||||
|
|
||||||
if (!data->device) {
|
if (!data->device_port) {
|
||||||
/* If there is no device defined, just return 0 to say everything is ok.
|
/* 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
|
* Then next port change can be whatever source port, even the one enabled
|
||||||
* before parking. */
|
* before parking. */
|
||||||
|
|
@ -342,12 +295,12 @@ static int source_set_port_cb(pa_source *s, pa_device_port *p) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pa_log_debug("Source set port %#010x", data->device);
|
pa_log_debug("Source set port %#010x (%s)", data->device_port->type, data->device_port->name);
|
||||||
|
|
||||||
if (!PA_SOURCE_IS_OPENED(u->source->state))
|
if (!PA_SOURCE_IS_OPENED(u->source->state))
|
||||||
do_routing(u, data->device);
|
pa_droid_stream_set_route(u->stream, data->device_port);
|
||||||
else
|
else
|
||||||
source_reconfigure(u, NULL, NULL, data->device);
|
source_reconfigure(u, NULL, NULL, NULL, data->device_port);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -429,7 +382,8 @@ static void update_latency(struct userdata *u) {
|
||||||
static void source_reconfigure(struct userdata *u,
|
static void source_reconfigure(struct userdata *u,
|
||||||
const pa_sample_spec *reconfigure_sample_spec,
|
const pa_sample_spec *reconfigure_sample_spec,
|
||||||
const pa_channel_map *reconfigure_channel_map,
|
const pa_channel_map *reconfigure_channel_map,
|
||||||
audio_devices_t update_device) {
|
const pa_proplist *proplist,
|
||||||
|
dm_config_port *update_device_port) {
|
||||||
pa_channel_map old_channel_map;
|
pa_channel_map old_channel_map;
|
||||||
pa_sample_spec old_sample_spec;
|
pa_sample_spec old_sample_spec;
|
||||||
pa_channel_map new_channel_map;
|
pa_channel_map new_channel_map;
|
||||||
|
|
@ -450,10 +404,10 @@ static void source_reconfigure(struct userdata *u,
|
||||||
new_channel_map = reconfigure_channel_map ? *reconfigure_channel_map : old_channel_map;
|
new_channel_map = reconfigure_channel_map ? *reconfigure_channel_map : old_channel_map;
|
||||||
new_sample_spec = reconfigure_sample_spec ? *reconfigure_sample_spec : old_sample_spec;
|
new_sample_spec = reconfigure_sample_spec ? *reconfigure_sample_spec : old_sample_spec;
|
||||||
|
|
||||||
if (update_device)
|
if (update_device_port)
|
||||||
do_routing(u, update_device);
|
pa_droid_stream_set_route(u->stream, update_device_port);
|
||||||
|
|
||||||
if (pa_droid_stream_reconfigure_input(u->stream, &new_sample_spec, &new_channel_map))
|
if (pa_droid_stream_reconfigure_input(u->stream, &new_sample_spec, &new_channel_map, proplist))
|
||||||
pa_log_info("Source reconfigured.");
|
pa_log_info("Source reconfigured.");
|
||||||
else
|
else
|
||||||
pa_log_info("Failed to reconfigure input stream, no worries, using defaults.");
|
pa_log_info("Failed to reconfigure input stream, no worries, using defaults.");
|
||||||
|
|
@ -487,8 +441,10 @@ static pa_hook_result_t source_output_new_hook_callback(void *hook_data,
|
||||||
if (new_data->source != u->source)
|
if (new_data->source != u->source)
|
||||||
return PA_HOOK_OK;
|
return PA_HOOK_OK;
|
||||||
|
|
||||||
if (pa_sample_spec_equal(&new_data->sample_spec, pa_droid_stream_sample_spec(u->stream)) &&
|
if (!pa_droid_stream_reconfigure_input_needed(u->stream,
|
||||||
pa_channel_map_equal(&new_data->channel_map, pa_droid_stream_channel_map(u->stream)))
|
&new_data->sample_spec,
|
||||||
|
&new_data->channel_map,
|
||||||
|
new_data->proplist))
|
||||||
return PA_HOOK_OK;
|
return PA_HOOK_OK;
|
||||||
|
|
||||||
pa_log_info("New source-output connecting and our source needs to be reconfigured.");
|
pa_log_info("New source-output connecting and our source needs to be reconfigured.");
|
||||||
|
|
@ -500,10 +456,11 @@ static pa_hook_result_t source_output_new_hook_callback(void *hook_data,
|
||||||
source_reconfigure(u,
|
source_reconfigure(u,
|
||||||
pa_droid_stream_sample_spec(primary_output),
|
pa_droid_stream_sample_spec(primary_output),
|
||||||
pa_droid_stream_channel_map(primary_output),
|
pa_droid_stream_channel_map(primary_output),
|
||||||
0);
|
new_data->proplist,
|
||||||
|
NULL);
|
||||||
|
|
||||||
} else
|
} else
|
||||||
source_reconfigure(u, &new_data->sample_spec, &new_data->channel_map, 0);
|
source_reconfigure(u, &new_data->sample_spec, &new_data->channel_map, new_data->proplist, NULL);
|
||||||
|
|
||||||
return PA_HOOK_OK;
|
return PA_HOOK_OK;
|
||||||
}
|
}
|
||||||
|
|
@ -523,12 +480,12 @@ static void source_reconfigure_after_changes(struct userdata *u) {
|
||||||
so = so_i;
|
so = so_i;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (so) {
|
if (so && pa_droid_stream_reconfigure_input_needed(u->stream,
|
||||||
if (!pa_sample_spec_equal(&so->sample_spec, pa_droid_stream_sample_spec(u->stream)) ||
|
&so->sample_spec,
|
||||||
!pa_channel_map_equal(&so->channel_map, pa_droid_stream_channel_map(u->stream))) {
|
&so->channel_map,
|
||||||
pa_log_info("Source-output disconnected and our source needs to be reconfigured.");
|
so->proplist)) {
|
||||||
source_reconfigure(u, &so->sample_spec, &so->channel_map, 0);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -542,7 +499,6 @@ static pa_hook_result_t source_output_unlink_post_hook_callback(void *hook_data,
|
||||||
pa_source *pa_droid_source_new(pa_module *m,
|
pa_source *pa_droid_source_new(pa_module *m,
|
||||||
pa_modargs *ma,
|
pa_modargs *ma,
|
||||||
const char *driver,
|
const char *driver,
|
||||||
audio_devices_t device,
|
|
||||||
pa_droid_card_data *card_data,
|
pa_droid_card_data *card_data,
|
||||||
pa_droid_mapping *am,
|
pa_droid_mapping *am,
|
||||||
pa_card *card) {
|
pa_card *card) {
|
||||||
|
|
@ -551,9 +507,7 @@ pa_source *pa_droid_source_new(pa_module *m,
|
||||||
char *thread_name = NULL;
|
char *thread_name = NULL;
|
||||||
pa_source_new_data data;
|
pa_source_new_data data;
|
||||||
const char *module_id = NULL;
|
const char *module_id = NULL;
|
||||||
const char *tmp;
|
|
||||||
uint32_t alternate_sample_rate;
|
uint32_t alternate_sample_rate;
|
||||||
audio_devices_t dev_in;
|
|
||||||
pa_sample_spec sample_spec;
|
pa_sample_spec sample_spec;
|
||||||
pa_channel_map channel_map;
|
pa_channel_map channel_map;
|
||||||
const char *format;
|
const char *format;
|
||||||
|
|
@ -568,7 +522,7 @@ pa_source *pa_droid_source_new(pa_module *m,
|
||||||
|
|
||||||
/* When running under card use hw module name for source by default. */
|
/* When running under card use hw module name for source by default. */
|
||||||
if (am)
|
if (am)
|
||||||
module_id = am->inputs->module->name;
|
module_id = am->mix_port->name;
|
||||||
else
|
else
|
||||||
module_id = pa_modargs_get_value(ma, "module_id", DEFAULT_MODULE_ID);
|
module_id = pa_modargs_get_value(ma, "module_id", DEFAULT_MODULE_ID);
|
||||||
|
|
||||||
|
|
@ -639,28 +593,7 @@ pa_source *pa_droid_source_new(pa_module *m,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Default routing */
|
u->stream = pa_droid_open_input_stream(u->hw_module, &sample_spec, &channel_map, am->mix_port->name);
|
||||||
if (device)
|
|
||||||
dev_in = device;
|
|
||||||
else {
|
|
||||||
/* 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. */
|
|
||||||
pa_log_info("FIXME: Setting AUDIO_DEVICE_IN_BUILTIN_MIC as initial device.");
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pa_droid_hw_set_input_device(u->hw_module, dev_in);
|
|
||||||
u->stream = pa_droid_open_input_stream(u->hw_module, &sample_spec, &channel_map);
|
|
||||||
|
|
||||||
if (!u->stream) {
|
if (!u->stream) {
|
||||||
pa_log("Failed to open input stream.");
|
pa_log("Failed to open input stream.");
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#define foodroidsourcefoo
|
#define foodroidsourcefoo
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2013-2018 Jolla Ltd.
|
* Copyright (C) 2013-2022 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
||||||
*
|
*
|
||||||
|
|
@ -43,11 +43,9 @@
|
||||||
|
|
||||||
#include <droid/droid-util.h>
|
#include <droid/droid-util.h>
|
||||||
|
|
||||||
/* If device is non-zero, it will override whatever is set in modargs for input device. */
|
|
||||||
pa_source *pa_droid_source_new(pa_module *m,
|
pa_source *pa_droid_source_new(pa_module *m,
|
||||||
pa_modargs *ma,
|
pa_modargs *ma,
|
||||||
const char *driver,
|
const char *driver,
|
||||||
audio_devices_t device,
|
|
||||||
pa_droid_card_data *card_data,
|
pa_droid_card_data *card_data,
|
||||||
pa_droid_mapping *am,
|
pa_droid_mapping *am,
|
||||||
pa_card *card);
|
pa_card *card);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2013-2018 Jolla Ltd.
|
* Copyright (C) 2013-2022 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
||||||
*
|
*
|
||||||
|
|
@ -61,6 +61,7 @@
|
||||||
|
|
||||||
#include <droid/droid-util.h>
|
#include <droid/droid-util.h>
|
||||||
#include <droid/sllist.h>
|
#include <droid/sllist.h>
|
||||||
|
#include <droid/utils.h>
|
||||||
#include "droid-sink.h"
|
#include "droid-sink.h"
|
||||||
#include "droid-source.h"
|
#include "droid-source.h"
|
||||||
#include "droid-extcon.h"
|
#include "droid-extcon.h"
|
||||||
|
|
@ -75,7 +76,6 @@ PA_MODULE_USAGE(
|
||||||
"source_name=<name for the source> "
|
"source_name=<name for the source> "
|
||||||
"namereg_fail=<when false attempt to synthesise new names if they are already taken> "
|
"namereg_fail=<when false attempt to synthesise new names if they are already taken> "
|
||||||
"rate=<sample rate> "
|
"rate=<sample rate> "
|
||||||
"output_flags=<flags for sink> "
|
|
||||||
"module_id=<which droid hw module to load, default primary> "
|
"module_id=<which droid hw module to load, default primary> "
|
||||||
"voice_source_routing=<always true, parameter left for compatibility> "
|
"voice_source_routing=<always true, parameter left for compatibility> "
|
||||||
"deferred_volume=<synchronize software and hardware volume changes to avoid momentary jumps?> "
|
"deferred_volume=<synchronize software and hardware volume changes to avoid momentary jumps?> "
|
||||||
|
|
@ -83,9 +83,7 @@ PA_MODULE_USAGE(
|
||||||
"voice_property_key=<proplist key searched for sink-input that should control voice call volume> "
|
"voice_property_key=<proplist key searched for sink-input that should control voice call volume> "
|
||||||
"voice_property_value=<proplist value for the key for voice control sink-input> "
|
"voice_property_value=<proplist value for the key for voice control sink-input> "
|
||||||
"voice_virtual_stream=<true/false> create virtual stream for voice call volume control (default false)"
|
"voice_virtual_stream=<true/false> create virtual stream for voice call volume control (default false)"
|
||||||
"default_profile=<boolean. create default profile for primary module or not. defaults to true> "
|
"options=<comma separated list of options to enable/disable>"
|
||||||
"merge_inputs=<unused, always true> "
|
|
||||||
"quirks=<comma separated list of quirks to enable/disable>"
|
|
||||||
);
|
);
|
||||||
|
|
||||||
static const char* const valid_modargs[] = {
|
static const char* const valid_modargs[] = {
|
||||||
|
|
@ -100,27 +98,19 @@ static const char* const valid_modargs[] = {
|
||||||
"sink_rate",
|
"sink_rate",
|
||||||
"sink_format",
|
"sink_format",
|
||||||
"sink_channel_map",
|
"sink_channel_map",
|
||||||
"sink_mix_route",
|
|
||||||
"source_rate",
|
"source_rate",
|
||||||
"source_format",
|
"source_format",
|
||||||
"source_channel_map",
|
"source_channel_map",
|
||||||
"output_flags",
|
|
||||||
"module_id",
|
"module_id",
|
||||||
"voice_source_routing",
|
"voice_source_routing",
|
||||||
"sink_buffer",
|
"sink_buffer",
|
||||||
"source_buffer",
|
"source_buffer",
|
||||||
"deferred_volume",
|
"deferred_volume",
|
||||||
"mute_routing_before",
|
|
||||||
"mute_routing_after",
|
|
||||||
"prewrite_on_resume",
|
|
||||||
"config",
|
"config",
|
||||||
"voice_property_key",
|
"voice_property_key",
|
||||||
"voice_property_value",
|
"voice_property_value",
|
||||||
"voice_virtual_stream",
|
"voice_virtual_stream",
|
||||||
"default_profile",
|
/* DM_OPTIONS */
|
||||||
"combine",
|
|
||||||
"merge_inputs",
|
|
||||||
"quirks",
|
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -178,7 +168,7 @@ struct profile_data {
|
||||||
struct virtual_profile virtual;
|
struct virtual_profile virtual;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef DROID_AUDIO_HAL_USE_VSID
|
#ifdef DROID_AUDIO_HAL_DEBUG_VSID
|
||||||
|
|
||||||
/* From hal/voice_extn/voice_extn.c */
|
/* From hal/voice_extn/voice_extn.c */
|
||||||
#define AUDIO_PARAMETER_KEY_VSID "vsid"
|
#define AUDIO_PARAMETER_KEY_VSID "vsid"
|
||||||
|
|
@ -222,7 +212,7 @@ static bool voicecall_vowlan_vsid_profile_event_cb(struct userdata *u, pa_droid_
|
||||||
static bool voicecall_voicemmode1_vsid_profile_event_cb(struct userdata *u, pa_droid_profile *p, bool enabling);
|
static bool voicecall_voicemmode1_vsid_profile_event_cb(struct userdata *u, pa_droid_profile *p, bool enabling);
|
||||||
static bool voicecall_voicemmode2_vsid_profile_event_cb(struct userdata *u, pa_droid_profile *p, bool enabling);
|
static bool voicecall_voicemmode2_vsid_profile_event_cb(struct userdata *u, pa_droid_profile *p, bool enabling);
|
||||||
|
|
||||||
#endif /* DROID_AUDIO_HAL_USE_VSID */
|
#endif /* DROID_AUDIO_HAL_DEBUG_VSID */
|
||||||
|
|
||||||
static void add_disabled_profile(pa_hashmap *profiles) {
|
static void add_disabled_profile(pa_hashmap *profiles) {
|
||||||
pa_card_profile *cp;
|
pa_card_profile *cp;
|
||||||
|
|
@ -275,16 +265,6 @@ static pa_card_profile* add_virtual_profile(struct userdata *u, const char *name
|
||||||
return cp;
|
return cp;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int set_parameters_cb(pa_droid_card_data *card_data, const char *str) {
|
|
||||||
struct userdata *u;
|
|
||||||
|
|
||||||
pa_assert(card_data);
|
|
||||||
pa_assert_se((u = card_data->userdata));
|
|
||||||
pa_assert(str);
|
|
||||||
|
|
||||||
return pa_droid_set_parameters(u->hw_module, str);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_card_name(pa_modargs *ma, pa_card_new_data *data, const char *module_id) {
|
static void set_card_name(pa_modargs *ma, pa_card_new_data *data, const char *module_id) {
|
||||||
const char *tmp;
|
const char *tmp;
|
||||||
char *name;
|
char *name;
|
||||||
|
|
@ -306,16 +286,57 @@ static void set_card_name(pa_modargs *ma, pa_card_new_data *data, const char *mo
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool output_enabled(struct userdata *u, pa_droid_mapping *am) {
|
static bool output_enabled(struct userdata *u, pa_droid_mapping *am) {
|
||||||
|
bool enabled = false;
|
||||||
|
|
||||||
pa_assert(u);
|
pa_assert(u);
|
||||||
pa_assert(am);
|
pa_assert(am);
|
||||||
|
|
||||||
if (!pa_droid_quirk(u->hw_module, QUIRK_OUTPUT_FAST) && am->output->flags & AUDIO_OUTPUT_FLAG_FAST)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!pa_droid_quirk(u->hw_module, QUIRK_OUTPUT_DEEP_BUFFER) && am->output->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER)
|
if (am->mix_port->flags & AUDIO_OUTPUT_FLAG_PRIMARY)
|
||||||
return false;
|
enabled = true;
|
||||||
|
|
||||||
return true;
|
else if (am->mix_port->flags & AUDIO_OUTPUT_FLAG_RAW)
|
||||||
|
enabled = false;
|
||||||
|
|
||||||
|
else if (pa_droid_option(u->hw_module, DM_OPTION_OUTPUT_FAST) && am->mix_port->flags & AUDIO_OUTPUT_FLAG_FAST)
|
||||||
|
enabled = true;
|
||||||
|
|
||||||
|
else if (pa_droid_option(u->hw_module, DM_OPTION_OUTPUT_DEEP_BUFFER) && am->mix_port->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER)
|
||||||
|
enabled = true;
|
||||||
|
|
||||||
|
pa_log_debug("Output mix port \"%s\" %s", am->name, enabled ? "enabled" : "disabled");
|
||||||
|
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool input_enabled(struct userdata *u, pa_droid_mapping *am) {
|
||||||
|
bool enabled = false;
|
||||||
|
|
||||||
|
pa_assert(u);
|
||||||
|
pa_assert(am);
|
||||||
|
|
||||||
|
/* Look for primary mix port as the one used for creating droid-source. */
|
||||||
|
if (dm_strcasestr(am->name, "primary"))
|
||||||
|
enabled = true;
|
||||||
|
|
||||||
|
pa_log_debug("Input mix port \"%s\" %s", am->name, enabled ? "enabled" : "disabled");
|
||||||
|
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t max_channels_for_mix_port(dm_config_port *mix_port, uint32_t previous_max_channels) {
|
||||||
|
uint32_t max_channels = 0;
|
||||||
|
dm_config_profile *profile;
|
||||||
|
void *state;
|
||||||
|
|
||||||
|
DM_LIST_FOREACH_DATA(profile, mix_port->profiles, state) {
|
||||||
|
for (int i = 0; profile->channel_masks[i]; i++) {
|
||||||
|
max_channels = audio_channel_count_from_out_mask(profile->channel_masks[i]) > max_channels
|
||||||
|
? audio_channel_count_from_out_mask(profile->channel_masks[i]) : max_channels;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return max_channels > previous_max_channels ? max_channels : previous_max_channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void add_profile(struct userdata *u, pa_hashmap *h, pa_hashmap *ports, pa_droid_profile *ap) {
|
static void add_profile(struct userdata *u, pa_hashmap *h, pa_hashmap *ports, pa_droid_profile *ap) {
|
||||||
|
|
@ -336,26 +357,23 @@ static void add_profile(struct userdata *u, pa_hashmap *h, pa_hashmap *ports, pa
|
||||||
cp->available = PA_AVAILABLE_YES;
|
cp->available = PA_AVAILABLE_YES;
|
||||||
cp->priority = ap->priority;
|
cp->priority = ap->priority;
|
||||||
|
|
||||||
|
/* Output mappings */
|
||||||
|
|
||||||
max_channels = 0;
|
max_channels = 0;
|
||||||
PA_IDXSET_FOREACH(am, ap->output_mappings, idx) {
|
PA_IDXSET_FOREACH(am, ap->output_mappings, idx) {
|
||||||
if (!output_enabled(u, am))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
cp->n_sinks++;
|
cp->n_sinks++;
|
||||||
pa_droid_add_card_ports(cp, ports, am, u->core);
|
pa_droid_add_card_ports(cp, ports, am, u->core);
|
||||||
max_channels = popcount(am->output->channel_masks) > max_channels
|
max_channels = max_channels_for_mix_port(am->mix_port, max_channels);
|
||||||
? popcount(am->output->channel_masks) : max_channels;
|
|
||||||
}
|
}
|
||||||
cp->max_sink_channels = max_channels;
|
cp->max_sink_channels = max_channels;
|
||||||
|
|
||||||
|
/* Input mappings */
|
||||||
|
|
||||||
max_channels = 0;
|
max_channels = 0;
|
||||||
if ((am = ap->input_mapping)) {
|
PA_IDXSET_FOREACH(am, ap->input_mappings, idx) {
|
||||||
const pa_droid_config_device *input;
|
|
||||||
cp->n_sources++;
|
cp->n_sources++;
|
||||||
pa_droid_add_card_ports(cp, ports, am, u->core);
|
pa_droid_add_card_ports(cp, ports, am, u->core);
|
||||||
SLLIST_FOREACH(input, am->inputs)
|
max_channels = max_channels_for_mix_port(am->mix_port, max_channels);
|
||||||
max_channels = popcount(input->channel_masks) > max_channels
|
|
||||||
? popcount(input->channel_masks) : max_channels;
|
|
||||||
}
|
}
|
||||||
cp->max_source_channels = max_channels;
|
cp->max_source_channels = max_channels;
|
||||||
|
|
||||||
|
|
@ -401,8 +419,13 @@ static void init_profile(struct userdata *u) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (d->droid_profile && (am = d->droid_profile->input_mapping)) {
|
if (d->droid_profile && pa_idxset_size(d->droid_profile->input_mappings) > 0) {
|
||||||
am->source = pa_droid_source_new(u->module, u->modargs, __FILE__, (audio_devices_t) 0, &u->card_data, am, u->card);
|
PA_IDXSET_FOREACH(am, d->droid_profile->input_mappings, idx) {
|
||||||
|
if (!input_enabled(u, am))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
am->source = pa_droid_source_new(u->module, u->modargs, __FILE__, &u->card_data, am, u->card);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -454,19 +477,51 @@ static bool voicecall_profile_event_cb(struct userdata *u, pa_droid_profile *p,
|
||||||
if (enabling) {
|
if (enabling) {
|
||||||
pa_droid_sink_set_voice_control(am_output->sink, true);
|
pa_droid_sink_set_voice_control(am_output->sink, true);
|
||||||
|
|
||||||
if (pa_droid_quirk(u->hw_module, QUIRK_REALCALL))
|
if (pa_droid_option(u->hw_module, DM_OPTION_REALCALL))
|
||||||
pa_droid_set_parameters(u->hw_module, VENDOR_EXT_REALCALL_ON);
|
pa_droid_set_parameters(u->hw_module, VENDOR_EXT_REALCALL_ON);
|
||||||
} else {
|
} else {
|
||||||
pa_droid_sink_set_voice_control(am_output->sink, false);
|
pa_droid_sink_set_voice_control(am_output->sink, false);
|
||||||
|
|
||||||
if (pa_droid_quirk(u->hw_module, QUIRK_REALCALL))
|
if (pa_droid_option(u->hw_module, DM_OPTION_REALCALL))
|
||||||
pa_droid_set_parameters(u->hw_module, VENDOR_EXT_REALCALL_OFF);
|
pa_droid_set_parameters(u->hw_module, VENDOR_EXT_REALCALL_OFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DROID_AUDIO_HAL_USE_VSID
|
static bool in_communication_profile_event_cb(struct userdata *u, pa_droid_profile *p, bool enabling) {
|
||||||
|
pa_droid_profile *dp;
|
||||||
|
|
||||||
|
pa_assert(u);
|
||||||
|
pa_assert(u->real_profile);
|
||||||
|
|
||||||
|
dp = card_get_droid_profile(u->real_profile);
|
||||||
|
|
||||||
|
if (pa_idxset_size(dp->output_mappings) > 0) {
|
||||||
|
pa_droid_mapping *am;
|
||||||
|
uint32_t idx;
|
||||||
|
|
||||||
|
PA_IDXSET_FOREACH(am, dp->output_mappings, idx) {
|
||||||
|
|
||||||
|
if (am->mix_port->flags & AUDIO_OUTPUT_FLAG_VOIP_RX) {
|
||||||
|
if (enabling && !am->sink) {
|
||||||
|
pa_log_info("in communication: enable VOIP sink");
|
||||||
|
am->sink = pa_droid_sink_new(u->module, u->modargs, __FILE__, &u->card_data, 0, am, u->card);
|
||||||
|
} else if (!enabling && am->sink) {
|
||||||
|
/* Don't rescue sink-inputs. */
|
||||||
|
pa_log_info("in communication: disable VOIP sink");
|
||||||
|
pa_droid_sink_free(am->sink);
|
||||||
|
am->sink = NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DROID_AUDIO_HAL_DEBUG_VSID
|
||||||
static bool voicecall_vsid(struct userdata *u, pa_droid_profile *p, uint32_t vsid, bool enabling)
|
static bool voicecall_vsid(struct userdata *u, pa_droid_profile *p, uint32_t vsid, bool enabling)
|
||||||
{
|
{
|
||||||
char *setparam;
|
char *setparam;
|
||||||
|
|
@ -515,7 +570,7 @@ static bool voicecall_voicemmode2_vsid_profile_event_cb(struct userdata *u, pa_d
|
||||||
{
|
{
|
||||||
return voicecall_vsid(u, p, VOICEMMODE2_VSID, enabling);
|
return voicecall_vsid(u, p, VOICEMMODE2_VSID, enabling);
|
||||||
}
|
}
|
||||||
#endif /* DROID_AUDIO_HAL_USE_VSID */
|
#endif /* DROID_AUDIO_HAL_DEBUG_VSID */
|
||||||
|
|
||||||
static void virtual_event(struct userdata *u, struct profile_data *profile, bool enabling) {
|
static void virtual_event(struct userdata *u, struct profile_data *profile, bool enabling) {
|
||||||
pa_assert(u);
|
pa_assert(u);
|
||||||
|
|
@ -698,13 +753,18 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (next->droid_profile && (am = next->droid_profile->input_mapping)) {
|
if (next->droid_profile && pa_idxset_size(next->droid_profile->input_mappings) > 0) {
|
||||||
if (!am->source)
|
PA_IDXSET_FOREACH(am, next->droid_profile->input_mappings, idx) {
|
||||||
am->source = pa_droid_source_new(u->module, u->modargs, __FILE__, (audio_devices_t) 0, &u->card_data, am, u->card);
|
if (!input_enabled(u, am))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (source_outputs && am->source) {
|
if (!am->source)
|
||||||
pa_source_move_all_finish(am->source, source_outputs, false);
|
am->source = pa_droid_source_new(u->module, u->modargs, __FILE__, &u->card_data, am, u->card);
|
||||||
source_outputs = NULL;
|
|
||||||
|
if (source_outputs && am->source) {
|
||||||
|
pa_source_move_all_finish(am->source, source_outputs, false);
|
||||||
|
source_outputs = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -731,23 +791,17 @@ int pa__init(pa_module *m) {
|
||||||
pa_card_new_data data;
|
pa_card_new_data data;
|
||||||
const char *module_id;
|
const char *module_id;
|
||||||
bool namereg_fail = false;
|
bool namereg_fail = false;
|
||||||
bool default_profile = true;
|
|
||||||
pa_card_profile *voicecall = NULL;
|
pa_card_profile *voicecall = NULL;
|
||||||
|
|
||||||
pa_assert(m);
|
pa_assert(m);
|
||||||
|
|
||||||
pa_log_info("Create new droid-card");
|
pa_log_info("Create new droid-card");
|
||||||
|
|
||||||
if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
|
if (!(ma = pa_droid_modargs_new(m->argument, valid_modargs))) {
|
||||||
pa_log("Failed to parse module arguments.");
|
pa_log("Failed to parse module arguments.");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pa_modargs_get_value_boolean(ma, "default_profile", &default_profile) < 0) {
|
|
||||||
pa_log("Failed to parse default_profile argument. Expects boolean value");
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
u = pa_xnew0(struct userdata, 1);
|
u = pa_xnew0(struct userdata, 1);
|
||||||
u->core = m->core;
|
u->core = m->core;
|
||||||
m->userdata = u;
|
m->userdata = u;
|
||||||
|
|
@ -757,16 +811,12 @@ int pa__init(pa_module *m) {
|
||||||
if (!(u->hw_module = pa_droid_hw_module_get2(u->core, ma, module_id)))
|
if (!(u->hw_module = pa_droid_hw_module_get2(u->core, ma, module_id)))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
pa_droid_quirk_log(u->hw_module);
|
pa_droid_options_log(u->hw_module);
|
||||||
|
|
||||||
u->card_data.set_parameters = set_parameters_cb;
|
|
||||||
u->card_data.module_id = pa_xstrdup(module_id);
|
u->card_data.module_id = pa_xstrdup(module_id);
|
||||||
u->card_data.userdata = u;
|
u->card_data.userdata = u;
|
||||||
|
|
||||||
if (default_profile)
|
u->profile_set = pa_droid_profile_set_default_new(u->hw_module->enabled_module);
|
||||||
u->profile_set = pa_droid_profile_set_default_new(u->hw_module->enabled_module);
|
|
||||||
else
|
|
||||||
u->profile_set = pa_droid_profile_set_new(u->hw_module->enabled_module);
|
|
||||||
|
|
||||||
pa_card_new_data_init(&data);
|
pa_card_new_data_init(&data);
|
||||||
data.driver = __FILE__;
|
data.driver = __FILE__;
|
||||||
|
|
@ -802,19 +852,18 @@ int pa__init(pa_module *m) {
|
||||||
AUDIO_MODE_IN_CALL, NULL,
|
AUDIO_MODE_IN_CALL, NULL,
|
||||||
PA_AVAILABLE_YES, voicecall, data.profiles);
|
PA_AVAILABLE_YES, voicecall, data.profiles);
|
||||||
add_virtual_profile(u, COMMUNICATION_PROFILE_NAME, COMMUNICATION_PROFILE_DESC,
|
add_virtual_profile(u, COMMUNICATION_PROFILE_NAME, COMMUNICATION_PROFILE_DESC,
|
||||||
AUDIO_MODE_IN_COMMUNICATION, NULL,
|
AUDIO_MODE_IN_COMMUNICATION, in_communication_profile_event_cb,
|
||||||
PA_AVAILABLE_YES, NULL, data.profiles);
|
PA_AVAILABLE_YES, NULL, data.profiles);
|
||||||
add_virtual_profile(u, RINGTONE_PROFILE_NAME, RINGTONE_PROFILE_DESC,
|
add_virtual_profile(u, RINGTONE_PROFILE_NAME, RINGTONE_PROFILE_DESC,
|
||||||
AUDIO_MODE_RINGTONE, NULL,
|
AUDIO_MODE_RINGTONE, NULL,
|
||||||
PA_AVAILABLE_YES, NULL, data.profiles);
|
PA_AVAILABLE_YES, NULL, data.profiles);
|
||||||
#ifdef DROID_AUDIO_HAL_USE_VSID
|
#ifdef DROID_AUDIO_HAL_DEBUG_VSID
|
||||||
add_virtual_profile(u, VOICE_SESSION_VOICE1_PROFILE_NAME, VOICE_SESSION_VOICE1_PROFILE_DESC,
|
add_virtual_profile(u, VOICE_SESSION_VOICE1_PROFILE_NAME, VOICE_SESSION_VOICE1_PROFILE_DESC,
|
||||||
AUDIO_MODE_IN_CALL, voicecall_voice1_vsid_profile_event_cb,
|
AUDIO_MODE_IN_CALL, voicecall_voice1_vsid_profile_event_cb,
|
||||||
PA_AVAILABLE_YES, voicecall, data.profiles);
|
PA_AVAILABLE_YES, voicecall, data.profiles);
|
||||||
add_virtual_profile(u, VOICE_SESSION_VOICE2_PROFILE_NAME, VOICE_SESSION_VOICE2_PROFILE_DESC,
|
add_virtual_profile(u, VOICE_SESSION_VOICE2_PROFILE_NAME, VOICE_SESSION_VOICE2_PROFILE_DESC,
|
||||||
AUDIO_MODE_IN_CALL, voicecall_voice2_vsid_profile_event_cb,
|
AUDIO_MODE_IN_CALL, voicecall_voice2_vsid_profile_event_cb,
|
||||||
PA_AVAILABLE_YES, voicecall, data.profiles);
|
PA_AVAILABLE_YES, voicecall, data.profiles);
|
||||||
/* TODO: Probably enabled state needs to be determined dynamically for VOLTE and friends. */
|
|
||||||
add_virtual_profile(u, VOICE_SESSION_VOLTE_PROFILE_NAME, VOICE_SESSION_VOLTE_PROFILE_DESC,
|
add_virtual_profile(u, VOICE_SESSION_VOLTE_PROFILE_NAME, VOICE_SESSION_VOLTE_PROFILE_DESC,
|
||||||
AUDIO_MODE_IN_CALL, voicecall_volte_vsid_profile_event_cb,
|
AUDIO_MODE_IN_CALL, voicecall_volte_vsid_profile_event_cb,
|
||||||
PA_AVAILABLE_YES, voicecall, data.profiles);
|
PA_AVAILABLE_YES, voicecall, data.profiles);
|
||||||
|
|
@ -830,7 +879,7 @@ int pa__init(pa_module *m) {
|
||||||
add_virtual_profile(u, VOICE_SESSION_VOICEMMODE2_PROFILE_NAME, VOICE_SESSION_VOICEMMODE2_PROFILE_DESC,
|
add_virtual_profile(u, VOICE_SESSION_VOICEMMODE2_PROFILE_NAME, VOICE_SESSION_VOICEMMODE2_PROFILE_DESC,
|
||||||
AUDIO_MODE_IN_CALL, voicecall_voicemmode2_vsid_profile_event_cb,
|
AUDIO_MODE_IN_CALL, voicecall_voicemmode2_vsid_profile_event_cb,
|
||||||
PA_AVAILABLE_YES, voicecall, data.profiles);
|
PA_AVAILABLE_YES, voicecall, data.profiles);
|
||||||
#endif /* DROID_AUDIO_HAL_USE_VSID */
|
#endif /* DROID_AUDIO_HAL_DEBUG_VSID */
|
||||||
|
|
||||||
add_disabled_profile(data.profiles);
|
add_disabled_profile(data.profiles);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2013-2018 Jolla Ltd.
|
* Copyright (C) 2013-2022 Jolla Ltd.
|
||||||
*
|
*
|
||||||
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
||||||
*
|
*
|
||||||
|
|
@ -83,7 +83,7 @@ int pa__init(pa_module *m) {
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(m->userdata = pa_droid_source_new(m, ma, __FILE__, (audio_devices_t) 0, NULL, NULL, NULL)))
|
if (!(m->userdata = pa_droid_source_new(m, ma, __FILE__, NULL, NULL, NULL)))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
pa_modargs_free(ma);
|
pa_modargs_free(ma);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue