Compare commits
301 commits
12.2.77
...
bookworm-m
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c0e8232a36 | ||
|
|
18e6cd030e | ||
|
|
e689a5abc9 | ||
|
|
974ae573ad | ||
|
|
f28da7fddf | ||
|
|
caf6773723 | ||
|
|
5c0ca5b077 | ||
|
|
f1fb79c3e0 | ||
|
|
112843b765 | ||
|
|
10599fe519 | ||
|
|
85813e293a | ||
|
|
145e49611a | ||
|
|
d3253e5175 | ||
|
|
cef8f78746 | ||
|
|
04b14b8aac | ||
|
|
0adc96eb56 | ||
|
|
47a043d8dc | ||
|
|
a995948689 | ||
|
|
c4be583fbf | ||
|
|
51d85423d5 | ||
|
|
ffe02f26b1 | ||
|
|
8b1bc6cbce | ||
|
|
1c1d82dfb9 | ||
|
|
5c53ef736f | ||
|
|
77b1e60df0 | ||
|
|
385ccb8e4c | ||
|
|
a37363a46c | ||
|
|
e0d66cf4ad | ||
|
|
2d1a50d450 | ||
|
|
c895311db5 | ||
|
|
5238bfd192 | ||
|
|
d4a8167c11 | ||
|
|
b08cc4d219 | ||
|
|
0b1221a047 | ||
|
|
9ffca4ecd5 | ||
|
|
c359126658 | ||
|
|
73f93f1967 | ||
|
|
5d4a5af1f5 | ||
|
|
532f6c55bf | ||
|
|
1ac75ed3b0 | ||
|
|
c02f917ebb | ||
|
|
4ca8716bd1 | ||
|
|
67eeb83105 | ||
|
|
9e4c6fa8f1 | ||
|
|
40c320bc07 | ||
|
|
eefdb31f57 | ||
|
|
b4fb20eafe | ||
|
|
fdd22b6949 | ||
|
|
17fcb9e074 | ||
|
|
1e992b6954 | ||
|
|
1daab94724 | ||
|
|
0898217179 | ||
|
|
dbc7d678bb | ||
|
|
ef56dd4964 | ||
|
|
1cc2a0822e | ||
|
|
8df3961333 | ||
|
|
b23e20db5c | ||
|
|
0886d509fc | ||
|
|
80015ede82 | ||
|
|
9c6842e7d9 | ||
|
|
0d739ca587 | ||
|
|
1781dab3b8 | ||
|
|
98d2c7358a | ||
|
|
11a09b005d | ||
|
|
d9e2ddfd72 | ||
|
|
baecfc7cdd | ||
|
|
2d7ee841ed | ||
|
|
4103c31aec | ||
|
|
a5477e617b | ||
|
|
130edc502b | ||
|
|
8283bbe5c9 | ||
|
|
42af5e85c5 | ||
|
|
a676accf88 | ||
|
|
446ac62a6e | ||
|
|
930e65658c | ||
|
|
edec25347e | ||
|
|
8f936ba66f | ||
|
|
5be0189b91 | ||
|
|
38b07e6d45 | ||
|
|
eac4b34d39 | ||
|
|
3f1cc042bc | ||
|
|
c6da10943a | ||
|
|
b310103c0f | ||
|
|
898aacd38e | ||
|
|
4414037c47 | ||
|
|
c9c66b4750 | ||
|
|
65483884ae | ||
|
|
6ef0459669 | ||
|
|
f01f0a53a7 | ||
|
|
997a9c87de | ||
|
|
0cd9a16bee | ||
|
|
45badd1a75 | ||
|
|
cb40bac4c5 | ||
|
|
b7cbd0ef3d | ||
|
|
9cad56c426 | ||
|
|
9517a067de | ||
|
|
9282a566c8 | ||
|
|
7bb06f6a30 | ||
|
|
501d881534 | ||
|
|
74c17e4dab | ||
|
|
88d0b2954a | ||
|
|
3ab49846d2 | ||
|
|
2f14557d02 | ||
|
|
db423101e8 | ||
|
|
5ff7642ca7 | ||
|
|
bbc921b9e5 | ||
|
|
52711026c2 | ||
|
|
7c8862acc4 | ||
|
|
59203f085e | ||
|
|
995913eaf3 | ||
|
|
11697f2cc1 | ||
|
|
e84166816b | ||
|
|
a784a5a8fa | ||
|
|
efea2f5e7f | ||
|
|
a3d9a12b94 | ||
|
|
7090354d13 | ||
|
|
d991352f66 | ||
|
|
2bd9ba3f7e | ||
|
|
69a12761d6 | ||
|
|
6d2dacec5b | ||
|
|
83acc45987 | ||
|
|
9b4a813680 | ||
|
|
5024ba675d | ||
|
|
da247905d2 | ||
|
|
a49e117ff7 | ||
|
|
209537d75f | ||
|
|
e9de637e3a | ||
|
|
beecdf67e9 | ||
|
|
0d69581452 | ||
|
|
c6f5ed1bed | ||
|
|
44e9b517e6 | ||
|
|
3b47553add | ||
|
|
cbbaf3ab42 | ||
|
|
6b1debc680 | ||
|
|
e5f6f476a3 | ||
|
|
268d4a1230 | ||
|
|
7d3f3cdc78 | ||
|
|
1707b34059 | ||
|
|
31aa7777d6 | ||
|
|
407371a656 | ||
|
|
c0584f6dff | ||
|
|
2d43babb6a | ||
|
|
3ab10f1e45 | ||
|
|
4568e2cf84 | ||
|
|
15efaa50ff | ||
|
|
7003fef295 | ||
|
|
6ce6d707d5 | ||
|
|
5348730a70 | ||
|
|
050fd80a16 | ||
|
|
fe0f517719 | ||
|
|
2ccbf14739 | ||
|
|
22be43a324 | ||
|
|
91e9bcbbe7 | ||
|
|
b540528aab | ||
|
|
d885b86121 | ||
|
|
7052e809f9 | ||
|
|
2f5ddab8f4 | ||
|
|
08afdc0932 | ||
|
|
dd83f69d87 | ||
|
|
e46b8c7b0e | ||
|
|
d8faa4a703 | ||
|
|
bc67f05782 | ||
|
|
5cab2af137 | ||
|
|
81504b9ec4 | ||
|
|
0730b77e39 | ||
|
|
e5ba918cdb | ||
|
|
0e120cf797 | ||
|
|
72d4e0aaca | ||
|
|
dcb0b67f67 | ||
|
|
08c4558f15 | ||
|
|
976a6cf58c | ||
|
|
b36b2431fb | ||
|
|
fa0e8a5535 | ||
|
|
90ca699176 | ||
|
|
25abbb4388 | ||
|
|
ca93e01a91 | ||
|
|
8ed068f68b | ||
|
|
6986d9bf06 | ||
|
|
bfd377a109 | ||
|
|
9d5226d841 | ||
|
|
9936dfa44f | ||
|
|
0e60d133c6 | ||
|
|
0af48ffd73 | ||
|
|
5aeee81b49 | ||
|
|
de0d98e6d5 | ||
|
|
44e7b1479d | ||
|
|
124139f5b9 | ||
|
|
a46a5c91a1 | ||
|
|
3192069095 | ||
|
|
a2eb4143ef | ||
|
|
7b531dfff9 | ||
|
|
c7a62db215 | ||
|
|
8bc33cfb25 | ||
|
|
1151993324 | ||
|
|
4afa908867 | ||
|
|
24e3661259 | ||
|
|
82b46a9ec4 | ||
|
|
fcb720b6a3 | ||
|
|
caead9d18c | ||
|
|
39fdb85b13 | ||
|
|
3ba217920b | ||
|
|
1866de8e8d | ||
|
|
1f6e402f82 | ||
|
|
1787c87407 | ||
|
|
58d1e45090 | ||
|
|
c5cca5314f | ||
|
|
5edb6d17e8 | ||
|
|
6b9b141ac8 | ||
|
|
b5972a7dcc | ||
|
|
940476a773 | ||
|
|
2b9ac12840 | ||
|
|
a574c42d7c | ||
|
|
9363d97953 | ||
|
|
11ea0a60bd | ||
|
|
3ee8e16ad3 | ||
|
|
d10db89b9f | ||
|
|
033ad34ca6 | ||
|
|
efb1bcf8cc | ||
|
|
21b3c42db7 | ||
|
|
97a0c98f84 | ||
|
|
e099a0884e | ||
|
|
48a96e89ce | ||
|
|
89cdbb8be7 | ||
|
|
c16bfaa1ce | ||
|
|
adebe47929 | ||
|
|
772b9ca3f1 | ||
|
|
9d5daf5f87 | ||
|
|
ea451e9879 | ||
|
|
97e2ec2e11 | ||
|
|
95c37782c3 | ||
|
|
1d47383623 | ||
|
|
9f27eaed6a | ||
|
|
c6b8807fac | ||
|
|
ba839c52f4 | ||
|
|
1ce36525e0 | ||
|
|
841fa93a03 | ||
|
|
367a587453 | ||
|
|
0708ad905d | ||
|
|
70b624d663 | ||
|
|
6803ef07e7 | ||
|
|
185fb1add0 | ||
|
|
4d5c17bed0 | ||
|
|
f69afe38c6 | ||
|
|
57b1848dbf | ||
|
|
c93ea363b2 | ||
|
|
fc250744f4 | ||
|
|
b1cf9bfcdc | ||
|
|
2bbeb30522 | ||
|
|
2a7dba4d5c | ||
|
|
98b7553bc8 | ||
|
|
87e36be31e | ||
|
|
26bf0ee2ca | ||
|
|
5a47cc2c56 | ||
|
|
24bcbbd373 | ||
|
|
cd3465b2f2 | ||
|
|
09c3cca84e | ||
|
|
f7850df526 | ||
|
|
77de8c289a | ||
|
|
3df73147d9 | ||
|
|
96c4e2ea97 | ||
|
|
3a195e0929 | ||
|
|
0861b3beff | ||
|
|
abf4c9037b | ||
|
|
1e41bf5a45 | ||
|
|
f032e4a37b | ||
|
|
13b3ed1a75 | ||
|
|
0fdfef668d | ||
|
|
ab883c792b | ||
|
|
a9566c26b3 | ||
|
|
73bf39a07a | ||
|
|
07df5e6953 | ||
|
|
ec3260a88f | ||
|
|
a61a670284 | ||
|
|
b4414fb5a1 | ||
|
|
4a558ba35f | ||
|
|
f652f1f52a | ||
|
|
ad620b712a | ||
|
|
8ef0e32e18 | ||
|
|
05a5925baf | ||
|
|
f293111905 | ||
|
|
addd9f1adc | ||
|
|
6355803c66 | ||
|
|
ed595dec5b | ||
|
|
9d09908b82 | ||
|
|
36c03408c1 | ||
|
|
8ad1d210a8 | ||
|
|
ec084f07a2 | ||
|
|
5573d62ebe | ||
|
|
88c2be2333 | ||
|
|
ffee6f91fc | ||
|
|
95860ffe29 | ||
|
|
12185c8601 | ||
|
|
32edc3fea0 | ||
|
|
736a82a7a1 | ||
|
|
9e5b1fa04a | ||
|
|
1a7bf9de98 | ||
|
|
c31ce84c0f | ||
|
|
672f6a9455 | ||
|
|
91dbb2459e | ||
|
|
48756afc70 | ||
|
|
4edf08d933 |
52 changed files with 5243 additions and 4646 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -19,3 +19,6 @@ config.status
|
|||
libtool
|
||||
*.pc
|
||||
stamp-*
|
||||
|
||||
# Added by Droidian
|
||||
!.circleci/
|
||||
|
|
|
|||
373
README
373
README
|
|
@ -1,373 +0,0 @@
|
|||
PulseAudio Droid modules
|
||||
========================
|
||||
|
||||
Building of droid modules is split to two packages
|
||||
* common (and common-devel) which contains shared library code for use in
|
||||
PulseAudio modules in this package and for inclusion in other projects
|
||||
* droid with actual PulseAudio modules
|
||||
|
||||
Supported Android versions:
|
||||
|
||||
* 4.1.x with Qualcomm extensions (tested with 4.1.2)
|
||||
* 4.2.x
|
||||
* 4.4.x
|
||||
* 5.x
|
||||
* 6.0.x
|
||||
* 7.x
|
||||
* 8.x
|
||||
|
||||
Headers for defining devices and strings for different droid versions are in
|
||||
src/common/droid-util-audio.h (legacy headers for Jolla 1 in droid-util-41qc.h).
|
||||
|
||||
When new devices with relevant new enums appear, add enum check to configure.ac,
|
||||
for example: (the CC_CHECK_DROID_ENUM m4 macro will create define HAVE_ENUM_FOO
|
||||
if the enum FOO exists in HAL audio.h)
|
||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_OUT_IP])
|
||||
|
||||
and then in droid-util-audio.h add the enum to proper tables with ifdefs:
|
||||
/* string_conversion_table_output_device[] */
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_OUT_IP
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_IP ),
|
||||
#endif
|
||||
|
||||
/* string_conversion_table_output_device_fancy[] */
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_OUT_IP
|
||||
{ AUDIO_DEVICE_OUT_IP, "output-ip" },
|
||||
#endif
|
||||
|
||||
The purpose of droid-modules is to "replace AudioFlinger". Many hardware
|
||||
adaptations use ALSA as the kernel interface, but there is no saying that
|
||||
someday vendor would create and use something proprietary or otherwise
|
||||
different from ALSA. Also the ALSA implementation in droid devices may contain
|
||||
funny ways to achieve things (notable example is voicecall) which might be
|
||||
difficult to do if interfacing directly with ALSA to replace AudioFlinger.
|
||||
Also using ALSA directly would mean that the whole HAL adaptation would need to
|
||||
be ported for each new device adaptation. With droid-modules this is much more
|
||||
simpler, with somewhat stable HAL (HALv3 as of now, also different vendors add
|
||||
their own incompatible extensions) API. In best scenarios using droid-modules
|
||||
with new device is just compiling against target.
|
||||
|
||||
Components
|
||||
==========
|
||||
|
||||
common
|
||||
------
|
||||
|
||||
The common part of PulseAudio Droid modules contains library for handling
|
||||
most operations towards audio HAL.
|
||||
|
||||
### Audio policy configuration parsing
|
||||
|
||||
To populate our configuration structs there exists two parsers, legacy parser
|
||||
for old .conf format present in Android versions 7.0 and older and new xml
|
||||
format present from version 7.0 upwards. The legacy format is obsoleted in
|
||||
version 7.0 but by default still in use and most 7.0 adaptations probably
|
||||
contain the legacy format. But 8.0 adaptations and up start to include only
|
||||
the new style xml format configuration files.
|
||||
|
||||
### Configuration files
|
||||
|
||||
By default new style xml format is tried first and if it is not found old
|
||||
config is read next. If the configuration is in non-default location for
|
||||
some reason "config" module argument (available for all modules, card, sink,
|
||||
and source) can be used to point to the configuration file location.
|
||||
|
||||
By default files are tried in following order,
|
||||
|
||||
/vendor/etc/audio_policy_configuration.xml (new xml format)
|
||||
/vendor/etc/audio_policy.conf (legacy format)
|
||||
/system/etc/audio_policy_configuration.xml (new xml format)
|
||||
/system/etc/audio_policy.conf (legacy format)
|
||||
|
||||
module-droid-card
|
||||
-----------------
|
||||
|
||||
Ideally only module-droid-card is loaded and then droid-card loads
|
||||
configuration, creates profiles and loads sinks and sources based on the
|
||||
selected profile.
|
||||
|
||||
default profile
|
||||
---------------
|
||||
|
||||
When module-droid-card is loaded with default arguments, droid-card will try
|
||||
to create a default profile (called surprisingly "default"). The default
|
||||
profile will try to merge useful output and input streams to one profile,
|
||||
to allow use of possible low latency outputs or multiple inputs if the
|
||||
input streams are split to multiple devices.
|
||||
|
||||
For example configuration with
|
||||
|
||||
audio_hw_modules {
|
||||
primary {
|
||||
outputs {
|
||||
primary {}
|
||||
deep_buffer {}
|
||||
}
|
||||
inputs {
|
||||
builtin {}
|
||||
external {}
|
||||
}
|
||||
}
|
||||
other {
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
The default profile would contain two sinks, sink.primary and sink.deep_buffer
|
||||
and one source, source.builtin_external. Then this combined source would use
|
||||
either "builtin" or "external" input stream, depending on which one has the
|
||||
input route currently in use (for example, input-wired_headset from "external"
|
||||
and input-back_mic from "builtin" input stream).
|
||||
|
||||
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.
|
||||
|
||||
additional profiles
|
||||
-------------------
|
||||
|
||||
In addition to the 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 (input-output) primary-primary and lpa-primary.
|
||||
When module-droid-card is run without module_id argument, as default "primary"
|
||||
is used.
|
||||
|
||||
virtual profiles
|
||||
----------------
|
||||
|
||||
In addition to aforementioned card profiles, droid-card creates some additional
|
||||
virtual profiles. These virtual profiles are used when enabling voicecall
|
||||
routings etc. When virtual profile is enabled, possible sinks and sources
|
||||
previously active profile had are not removed.
|
||||
|
||||
As an illustration, following command line sequence enables voicecall mode and
|
||||
routes audio to internal handsfree (ihf - "handsfree speaker"):
|
||||
|
||||
(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-sink-port sink.primary output-parking
|
||||
pactl set-sink-port sink.primary output-speaker
|
||||
|
||||
After this, when there is an active voicecall (created by ofono for example),
|
||||
voice audio starts to flow between modem and audio chip.
|
||||
|
||||
To disable voicecall and return to media audio:
|
||||
|
||||
pactl set-card-profile droid_card.primary primary-primary
|
||||
pactl set-sink-port sink.primary output-parking
|
||||
pactl set-sink-port sink.primary output-speaker
|
||||
|
||||
With this example sequence sinks and sources are the ones from primary-primary
|
||||
card profile, and they are maintained for the whole duration of the voicecall
|
||||
and after.
|
||||
|
||||
This sequence follows the droid HAL idea that when changing audio mode the mode
|
||||
change is done when next routing change happens. output-parking and
|
||||
input-parking ports are just convenience for PulseAudio, where setting already
|
||||
active port is a no-op (output/input-parking doesn't do any real routing
|
||||
changes).
|
||||
|
||||
Current virtual profiles are:
|
||||
* voicecall
|
||||
* voicecall-record
|
||||
* communication
|
||||
* ringtone
|
||||
|
||||
Communication profile is used for VoIP-like applications, to enable some
|
||||
voicecall related algorithms without being in voicecall. Ringtone profile
|
||||
should be used when ringtone is playing, to again enable possible loudness
|
||||
related optimizations etc. Voicecall-record profile can be enabled when
|
||||
voicecall profile is active.
|
||||
|
||||
module-droid-sink and module-droid-source
|
||||
-----------------------------------------
|
||||
|
||||
Normally user should not need to load droid-sink or droid-source modules by
|
||||
hand, but droid-card loads appropriate modules based on the active card
|
||||
profile.
|
||||
|
||||
Output and input ports for droid-sink and droid-source are generated from the
|
||||
audio_policy.conf, 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
|
||||
|
||||
Sink or source do not track possible headphone/other wired accessory plugging,
|
||||
but this needs to be handled elsewhere and then that other entity needs to
|
||||
control sinks and sources. (For example in SailfishOS this entity is OHM with
|
||||
accessory-plugin and pulseaudio-policy-enforcement module for actually making
|
||||
the port switching)
|
||||
|
||||
Classifying sinks and sources
|
||||
-----------------------------
|
||||
|
||||
Certain property values are set to all active sinks and sources based on their
|
||||
functionality to ease device classification.
|
||||
|
||||
Currently following properties are set:
|
||||
|
||||
* For droid sinks
|
||||
* droid.output.primary
|
||||
* droid.output.low_latency
|
||||
* droid.output.media_latency
|
||||
* droid.output.offload
|
||||
* For droid sources
|
||||
* droid.input.builtin
|
||||
* droid.input.external
|
||||
|
||||
If the property is set and with value "true", the sink or source should be
|
||||
used for the property type. If the property is not defined or contains
|
||||
value "false" it shouldn't be used for the property type.
|
||||
|
||||
For example, we might have sink.primary and sink.low_latency with following
|
||||
properties:
|
||||
|
||||
* sink.primary
|
||||
* droid.output.primary "true"
|
||||
* droid.output.media_latency "true"
|
||||
* sink.low_latency
|
||||
* droid.output.low_latency "true"
|
||||
|
||||
There also may be just one sink, with all the properties defined as "true"
|
||||
and so on.
|
||||
|
||||
Similarly if there is only one input device the sole source would have both
|
||||
input type properties set as "true", but it also might be that the different
|
||||
input type properties are split to two different sources.
|
||||
|
||||
Quirks
|
||||
------
|
||||
|
||||
There are some adaptations that require hacks to get things working. These
|
||||
hacks can be enabled or disabled with module argument "quirks". Some quirks
|
||||
are enabled by default with some adaptations etc.
|
||||
|
||||
Currently there are following quirks:
|
||||
|
||||
* input_atoi
|
||||
* Enabled by default with Android versions 5 and up.
|
||||
* Due to how atoi works in bionic vs libc we need to pass the input
|
||||
route a bit funny. If input routing doesn't work switch this on or off.
|
||||
* 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
|
||||
* Enabled by default.
|
||||
* Close input stream when not in use instead of suspending the stream.
|
||||
Cannot be changed when multiple inputs are merged to single source.
|
||||
* unload_no_close
|
||||
* Disabled by default.
|
||||
* Don't call audio_hw_device_close() for the hw module when unloading.
|
||||
Mostly useful for tracking module unload issues.
|
||||
* no_hw_volume
|
||||
* Disabled by default.
|
||||
* Some broken implementations are incorrectly probed for supporting hw
|
||||
volume control. This is manifested by always full volume with volume
|
||||
control not affecting volume level. To fix this enable this quirk.
|
||||
* output_make_writable
|
||||
* Disabled by default.
|
||||
* Some implementations modify write buffer in-place when this should
|
||||
not be done. This can result in random segfaults when playing audio.
|
||||
As a workaround make the buffer memchunk writable before passing to
|
||||
audio HAL.
|
||||
* realcall
|
||||
* Disabled by default.
|
||||
* Some vendors apply custom realcall parameter to HAL device when
|
||||
doing voicecall routing. If there is no voicecall audio you can
|
||||
try enabling this quirk so that the realcall parameter is applied
|
||||
when switching to voicecall profile.
|
||||
* unload_call_exit
|
||||
* Disabled by default.
|
||||
* Some HAL module implementations get stuck in mutex or segfault when
|
||||
trying to unload the module. To avoid confusing segfaults call
|
||||
exit(0) instead of calling unload for the module.
|
||||
|
||||
For example, to disable input_atoi and enable close_input quirks, use module
|
||||
argument
|
||||
|
||||
quirks=-input_atoi,+close_input
|
||||
|
||||
Volume control during voicecall
|
||||
-------------------------------
|
||||
|
||||
When voicecall virtual profile is enabled, active droid-sink is internally
|
||||
switched to voicecall volume control mode. What this means is changing the sink
|
||||
volume or volume of normal streams connected to the sink do not change active
|
||||
voicecall volume. Special stream is needed to control the voicecall volume
|
||||
level. By default this stream is identified by stream property media.role,
|
||||
with value "phone". This can be changed by providing module arguments
|
||||
voice_property_key and voice_property_value to module-droid-card.
|
||||
|
||||
Usually droid HAL has 6 volume levels for voicecall.
|
||||
|
||||
Temporary sink audio routing
|
||||
----------------------------
|
||||
|
||||
It is possible to add temporary route to sink audio routing with specific
|
||||
stream property. When stream with property key
|
||||
droid.device.additional-route connects to droid-sink, this extra route is set
|
||||
(if possible) as the enabled route for the duration of the stream.
|
||||
|
||||
For example, if droid-sink has active port output-wired_headphone:
|
||||
|
||||
paplay --property=droid.device.additional-route=AUDIO_DEVICE_OUT_SPEAKER a.wav
|
||||
|
||||
As long as the new stream is connected to droid-sink, output routing is
|
||||
SPEAKER.
|
||||
|
||||
module-droid-keepalive
|
||||
----------------------
|
||||
|
||||
Keepalive module is MCE (https://github.com/nemomobile/mce) specific module
|
||||
tracking sink/source activity and keeping a WAKELOCK when there are active
|
||||
streams.
|
||||
356
README.md
Normal file
356
README.md
Normal file
|
|
@ -0,0 +1,356 @@
|
|||
PulseAudio Droid modules
|
||||
========================
|
||||
|
||||
For adapdations for Android versions 4 to 10,
|
||||
see [pulseaudio-modules-droid-jb2q](https://github.com/mer-hybris/pulseaudio-modules-droid-jb2q)
|
||||
|
||||
Building of droid modules is split to two packages
|
||||
* **common** (and **common-devel**) which contains shared library code for use in
|
||||
PulseAudio modules in this package and for inclusion in other projects
|
||||
* **droid** with actual PulseAudio modules
|
||||
|
||||
Linking to libdroid is **not encouraged**, usually only HAL functions are needed
|
||||
which can be accessed using the pulsecore shared API (see below).
|
||||
|
||||
Supported Android versions:
|
||||
|
||||
* 11.x
|
||||
|
||||
Headers for defining devices and strings for different droid versions are in
|
||||
src/common/droid-util-audio.h.
|
||||
|
||||
When new devices with relevant new enums appear, add enum check to configure.ac.
|
||||
CC_CHECK_DROID_ENUM macro will create macros HAVE_ENUM_FOO, STRING_ENTRY_IF_FOO
|
||||
and FANCY_ENTRY_IF_FOO if enum FOO exists in HAL audio.h.
|
||||
|
||||
For example:
|
||||
|
||||
# configure.ac:
|
||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_OUT_IP])
|
||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_OUT_OTHER_NEW])
|
||||
|
||||
# and then in droid-util-audio.h add macros to proper tables:
|
||||
/* string_conversion_table_output_device[] */
|
||||
STRING_ENTRY_IF_OUT_IP
|
||||
STRING_ENTRY_IF_OUT_OTHER_NEW
|
||||
|
||||
/* string_conversion_table_output_device_fancy[] */
|
||||
FANCY_ENTRY_IF_OUT_IP("output-ip")
|
||||
FANCY_ENTRY_IF_OUT_OTHER_NEW("output-other_new")
|
||||
|
||||
In addition to the above macros there are also now defines
|
||||
HAVE_ENUM_AUDIO_DEVICE_OUT_IP and HAVE_ENUM_AUDIO_DEVICE_OUT_OTHER_NEW.
|
||||
|
||||
The purpose of droid-modules is to "replace AudioFlinger". Many hardware
|
||||
adaptations use ALSA as the kernel interface, but there is no saying that
|
||||
someday vendor would create and use something proprietary or otherwise
|
||||
different from ALSA. Also the ALSA implementation in droid devices may contain
|
||||
funny ways to achieve things (notable example is voicecall) which might be
|
||||
difficult to do if interfacing directly with ALSA to replace AudioFlinger.
|
||||
Also using ALSA directly would mean that the whole HAL adaptation would need to
|
||||
be ported for each new device adaptation. With droid-modules this is much more
|
||||
simpler, with somewhat stable HAL (HALv3 as of now, also different vendors add
|
||||
their own incompatible extensions) API. In best scenarios using droid-modules
|
||||
with new device is just compiling against target.
|
||||
|
||||
Components
|
||||
==========
|
||||
|
||||
common
|
||||
------
|
||||
|
||||
The common part of PulseAudio Droid modules contains library for handling
|
||||
most operations towards audio HAL.
|
||||
|
||||
### Audio policy configuration parsing
|
||||
|
||||
Configuration parser reads audio policy xml files.
|
||||
|
||||
### Configuration files
|
||||
|
||||
If the configuration is in non-default location for some reason "config"
|
||||
module argument can be used to point to the configuration file location.
|
||||
|
||||
By default files are tried in following order,
|
||||
|
||||
/odm/etc/audio_policy_configuration.xml
|
||||
/vendor/etc/audio/audio_policy_configuration.xml
|
||||
/vendor/etc/audio_policy_configuration.xml
|
||||
/system/etc/audio_policy_configuration.xml
|
||||
|
||||
module-droid-card
|
||||
-----------------
|
||||
|
||||
Ideally only module-droid-card is loaded and then droid-card loads
|
||||
configuration, creates profiles and loads sinks and sources based on the
|
||||
selected profile.
|
||||
|
||||
default profile
|
||||
---------------
|
||||
|
||||
When module-droid-card is loaded with default arguments, droid-card will
|
||||
create a default profile (called unsurprisingly "default"). The default
|
||||
profile will merge supported output and input streams to one profile,
|
||||
to allow use of possible low latency or deep buffer outputs.
|
||||
|
||||
virtual profiles
|
||||
----------------
|
||||
|
||||
In addition to aforementioned card profile, droid-card creates some additional
|
||||
virtual profiles. These virtual profiles are used when enabling voicecall
|
||||
routings etc. When virtual profile is enabled, possible sinks and sources
|
||||
previously active profile had are not removed.
|
||||
|
||||
As an illustration, following command line sequence enables voicecall mode and
|
||||
routes audio to internal handsfree (ihf - "handsfree speaker"):
|
||||
|
||||
pactl set-card-profile droid_card.primary voicecall
|
||||
pactl set-sink-port sink.primary output-parking
|
||||
pactl set-sink-port sink.primary output-speaker
|
||||
|
||||
After this, when there is an active voicecall (created by ofono for example),
|
||||
voice audio starts to flow between modem and audio chip.
|
||||
|
||||
To disable voicecall and return to media audio:
|
||||
|
||||
pactl set-card-profile droid_card.primary default
|
||||
pactl set-sink-port sink.primary output-parking
|
||||
pactl set-sink-port sink.primary output-speaker
|
||||
|
||||
With this example sequence sinks and sources are the ones from default
|
||||
card profile, and they are maintained for the whole duration of the voicecall
|
||||
and after.
|
||||
|
||||
This sequence follows the droid HAL idea that when changing audio mode the mode
|
||||
change is done when next routing change happens. output-parking and
|
||||
input-parking ports are just convenience for PulseAudio, where setting already
|
||||
active port is a no-op (output/input-parking doesn't do any real routing
|
||||
changes).
|
||||
|
||||
Current virtual profiles are:
|
||||
* voicecall
|
||||
* voicecall-record
|
||||
* communication
|
||||
* ringtone
|
||||
|
||||
Communication profile is used for VoIP-like applications, to enable some
|
||||
voicecall related algorithms without being in voicecall. Ringtone profile
|
||||
should be used when ringtone is playing, to again enable possible loudness
|
||||
related optimizations etc. Voicecall-record profile can be enabled when
|
||||
voicecall profile is active.
|
||||
|
||||
If mix port with flag AUDIO_OUTPUT_FLAG_VOIP_RX exists when communication
|
||||
virtual profile is enabled additional droid-sink is created with the config
|
||||
defined in the mix port. Voip audio should then be played to this new sink.
|
||||
|
||||
module-droid-sink and module-droid-source
|
||||
-----------------------------------------
|
||||
|
||||
Normally user should not need to load droid-sink or droid-source modules by
|
||||
hand, but droid-card loads appropriate modules based on the active card
|
||||
profile.
|
||||
|
||||
Changing output routing is as simple as
|
||||
|
||||
pactl set-sink-port sink.primary output-wired_headphone
|
||||
|
||||
Sinks or sources do not track possible headphone/other wired accessory
|
||||
plugging, but this needs to be handled elsewhere and then that other entity
|
||||
needs to control sinks and sources. (For example in SailfishOS this entity is
|
||||
OHM with accessory-plugin and pulseaudio-policy-enforcement module for
|
||||
actually making the port switching)
|
||||
|
||||
Droid source automatic reconfiguration
|
||||
--------------------------------------
|
||||
|
||||
As droid HAL makes assumptions on (input) routing based on what the parameters
|
||||
for the stream are (device, sample rate, channels, format, etc.) normal
|
||||
PulseAudio sources are a bit inflexible as only sample rate can change after
|
||||
source creation and even then there are restrictions based on alternative
|
||||
sample rate value.
|
||||
|
||||
To overcome this and to allow some more variables affecting the stream being
|
||||
passed to the input stream droid source is modified to reconfigure itself
|
||||
with the source-output that connects to it. This means, that just looking at
|
||||
inactive source from "pactl list" listing doesn't tell the whole story.
|
||||
|
||||
Droid source is always reconfigured with the *last* source-output that
|
||||
connects to it, possibly already connected source-outputs will continue
|
||||
to read from the source but through resampler.
|
||||
|
||||
For example,
|
||||
|
||||
1) source-output 44100Hz, stereo connects (so1)
|
||||
1) source is configured with 44100Hz, stereo
|
||||
2) so1 connects to the source without resampler
|
||||
2) source-output 16000Hz, mono connects (so2)
|
||||
1) so1 is detached from the source
|
||||
2) source is configured with 16000Hz, mono
|
||||
3) so2 connects to the source without resampler
|
||||
4) resampler is created for so1, 16000Hz, mono -> 44100Hz stereo
|
||||
5) so1 is re-attached to the source through resampler
|
||||
3) source-output 16000Hz, mono connects (so3)
|
||||
1) so1 and so2 are detached from the source
|
||||
2) so3 connects to the source without resampler
|
||||
3) so1 is re-attached to the source through resampler
|
||||
4) so2 is attached to the source
|
||||
|
||||
Classifying sinks and sources
|
||||
-----------------------------
|
||||
|
||||
Certain property values are set to all active sinks and sources based on their
|
||||
functionality to ease device classification.
|
||||
|
||||
Currently following properties are set:
|
||||
|
||||
* For droid sinks
|
||||
* droid.output.primary
|
||||
* droid.output.low_latency
|
||||
* droid.output.media_latency
|
||||
* droid.output.offload
|
||||
* droid.output.voip
|
||||
* For droid sources
|
||||
* droid.input.builtin
|
||||
* droid.input.external
|
||||
|
||||
If the property is set and with value "true", the sink or source should be
|
||||
used for the property type. If the property is not defined or contains
|
||||
value "false" it shouldn't be used for the property type.
|
||||
|
||||
For example, we might have sink.primary and sink.low_latency with following
|
||||
properties:
|
||||
|
||||
* sink.primary
|
||||
* droid.output.primary "true"
|
||||
* droid.output.media_latency "true"
|
||||
* sink.low_latency
|
||||
* droid.output.low_latency "true"
|
||||
|
||||
There also may be just one sink, with all the properties defined as "true"
|
||||
and so on.
|
||||
|
||||
Right now there exists only one source (input device) which will always have
|
||||
both properties as true.
|
||||
|
||||
Options
|
||||
-------
|
||||
|
||||
There are some adaptations that require hacks to get things working. These
|
||||
hacks can be enabled or disabled with module argument "options". Some options
|
||||
are enabled by default with some adaptations etc. There are also some more
|
||||
generic options.
|
||||
|
||||
Currently there are following options:
|
||||
|
||||
* input_atoi
|
||||
* Enabled by default with Android versions 5 and up.
|
||||
* Due to how atoi works in bionic vs libc we need to pass the input
|
||||
route a bit funny. If input routing doesn't work switch this on or off.
|
||||
* close_input
|
||||
* Enabled by default.
|
||||
* Close input stream when not in use instead of suspending the stream.
|
||||
Cannot be changed when multiple inputs are merged to single source.
|
||||
* unload_no_close
|
||||
* Disabled by default.
|
||||
* Don't call audio_hw_device_close() for the hw module when unloading.
|
||||
Mostly useful for tracking module unload issues.
|
||||
* hw_volume
|
||||
* Enabled by default.
|
||||
* Some broken implementations are incorrectly probed for supporting hw
|
||||
volume control. This is manifested by always full volume with volume
|
||||
control not affecting volume level. To fix this disable this option.
|
||||
* realcall
|
||||
* Disabled by default.
|
||||
* Some vendors apply custom realcall parameter to HAL device when
|
||||
doing voicecall routing. If there is no voicecall audio you can
|
||||
try enabling this option so that the realcall parameter is applied
|
||||
when switching to voicecall profile.
|
||||
* unload_call_exit
|
||||
* Disabled by default.
|
||||
* Some HAL module implementations get stuck in mutex or segfault when
|
||||
trying to unload the module. To avoid confusing segfaults call
|
||||
exit(0) instead of calling unload for the module.
|
||||
* output_fast
|
||||
* Enabled by default.
|
||||
* Create separate sink if AUDIO_OUTPUT_FLAG_FAST is found. If this sink
|
||||
is misbehaving try disabling this option.
|
||||
* output_deep_buffer
|
||||
* Enabled by default.
|
||||
* Create separate sink if AUDIO_OUTPUT_FLAG_DEEP_BUFFER is found. If
|
||||
this sink is misbehaving try disabling this option.
|
||||
* audio_cal_wait
|
||||
* Disabled by default.
|
||||
* Certain devices do audio calibration during hw module open and
|
||||
writing audio too early will break the calibration. In these cases
|
||||
this option can be enabled and 10 seconds of sleep is added after
|
||||
opening hw module.
|
||||
* speaker_before_voice
|
||||
* Disabled by default.
|
||||
* Set route to speaker before changing audio mode to AUDIO_MODE_IN_CALL.
|
||||
Some devices don't get routing right if the route is something else
|
||||
(like AUDIO_DEVICE_OUT_WIRED_HEADSET) before calling set_mode().
|
||||
If routing is wrong when call starts with wired accessory connected
|
||||
try enabling this option.
|
||||
* output_voip_rx
|
||||
* Enabled by default.
|
||||
* When audio configuration has AUDIO_OUTPUT_FLAG_VOIP_RX special voip
|
||||
sink is created when AUDIO_MODE_IN_COMMUNICATION is active and the
|
||||
sink is classified as droid.output.voip. If this is not desired then
|
||||
by disabling this option the voip sink is not classified but is still
|
||||
created normally.
|
||||
* record_voice_16k
|
||||
* Disabled by default.
|
||||
* When enabled voice call recording source is forced to sample rate
|
||||
of 16kHz.
|
||||
|
||||
Options can be enabled or disabled normally as module arguments, for example:
|
||||
|
||||
load-module module-droid-card hw_volume=false record_voice_16k=true
|
||||
|
||||
Volume control during voicecall
|
||||
-------------------------------
|
||||
|
||||
When voicecall virtual profile is enabled, active droid-sink is internally
|
||||
switched to voicecall volume control mode. What this means is changing the sink
|
||||
volume or volume of normal streams connected to the sink do not change active
|
||||
voicecall volume. Special stream is needed to control the voicecall volume
|
||||
level. By default this stream is identified by stream property media.role,
|
||||
with value "phone". This can be changed by providing module arguments
|
||||
voice_property_key and voice_property_value to module-droid-card.
|
||||
|
||||
Usually droid HAL has 6 volume levels for voicecall.
|
||||
|
||||
Temporary sink audio routing
|
||||
----------------------------
|
||||
|
||||
It is possible to add temporary route to sink audio routing with specific
|
||||
stream property. When stream with property key
|
||||
droid.device.additional-route connects to droid-sink, this extra route is set
|
||||
(if possible) as the enabled route for the duration of the stream.
|
||||
|
||||
For example, if droid-sink has active port output-wired_headphone:
|
||||
|
||||
paplay --property=droid.device.additional-route=AUDIO_DEVICE_OUT_SPEAKER a.wav
|
||||
|
||||
As long as the new stream is connected to droid-sink, output routing is
|
||||
SPEAKER.
|
||||
|
||||
HAL API
|
||||
-------
|
||||
|
||||
If there is need to call HAL directly from other modules it can be done with
|
||||
function pointer API stored in PulseAudio shared map.
|
||||
|
||||
Once the function pointers are acquired when called they will work the same
|
||||
way as defined in Android audio.h. For example:
|
||||
|
||||
void *handle;
|
||||
int (*set_parameters)(void *handle, const char *key_value_pairs);
|
||||
char* (*get_parameters)(void *handle, const char *keys);
|
||||
|
||||
handle = pa_shared_get(core, "droid.handle.v1");
|
||||
set_parameters = pa_shared_get(core, "droid.set_parameters.v1");
|
||||
get_parameters = pa_shared_get(core, "droid.get_parameters.v1");
|
||||
|
||||
set_parameters(handle, "route=2;");
|
||||
char *value = get_parameters(handle, "connected");
|
||||
88
configure.ac
88
configure.ac
|
|
@ -1,6 +1,6 @@
|
|||
AC_PREREQ(2.60)
|
||||
|
||||
AC_INIT([pulseaudio-modules-droid], [m4_esyscmd(./git-version-gen .tarball-version)], [mer-general@lists.merproject.org])
|
||||
AC_INIT([pulseaudio-modules-droid-modern], [m4_esyscmd(./git-version-gen .tarball-version)], [mer-general@lists.merproject.org])
|
||||
AC_CONFIG_HEADER([config.h])
|
||||
AM_INIT_AUTOMAKE([foreign -Wall silent-rules])
|
||||
AC_CONFIG_MACRO_DIR(m4)
|
||||
|
|
@ -20,15 +20,15 @@ AC_PROG_CC_C99
|
|||
AM_PROG_CC_C_O
|
||||
AC_PROG_GCC_TRADITIONAL
|
||||
|
||||
m4_define(pa_major, `echo $VERSION | cut -d. -f1 | cut -d- -f1`)
|
||||
m4_define(pa_minor, `echo $VERSION | cut -d. -f2 | cut -d- -f1`)
|
||||
m4_define(pa_major, `pkg-config --modversion libpulse | cut -d. -f1 | cut -d- -f1`)
|
||||
m4_define(pa_minor, `pkg-config --modversion libpulse | cut -d. -f2 | cut -d- -f1`)
|
||||
m4_define(pa_module_version, `echo $VERSION | cut -d. -f3 | cut -d- -f1`)
|
||||
|
||||
AC_SUBST(PA_MAJOR, pa_major)
|
||||
AC_SUBST(PA_MAJORMINOR, pa_major.pa_minor)
|
||||
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
|
||||
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])
|
||||
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_LIBS)
|
||||
|
||||
|
|
@ -183,94 +183,33 @@ PKG_CHECK_MODULES([HYBRIS], [libhardware >= 0.1.0])
|
|||
AC_SUBST(HYBRIS_CFLAGS)
|
||||
AC_SUBST(HYBRIS_LIBS)
|
||||
|
||||
PKG_CHECK_MODULES([DBUS], [dbus-1 >= 1.2])
|
||||
AC_SUBST(DBUS_CFLAGS)
|
||||
AC_SUBST(DBUS_LIBS)
|
||||
PKG_CHECK_MODULES([EVDEV], [libevdev >= 1.0])
|
||||
AC_SUBST(EVDEV_CFLAGS)
|
||||
AC_SUBST(EVDEV_LIBS)
|
||||
|
||||
#### expat (for xml config format parsing) (optional) ####
|
||||
#### expat (for xml config format parsing) ####
|
||||
|
||||
AC_ARG_ENABLE([xml],
|
||||
AS_HELP_STRING([--disable-xml],[Disable optional xml config support]))
|
||||
|
||||
AS_IF([test "x$enable_xml" != "xno"],
|
||||
[PKG_CHECK_MODULES(EXPAT, [ expat >= 2.1 ], HAVE_EXPAT=1, HAVE_EXPAT=0)],
|
||||
HAVE_EXPAT=0)
|
||||
|
||||
AS_IF([test "x$enable_xml" = "xyes" && test "x$HAVE_EXPAT" = "x0"],
|
||||
[AC_MSG_ERROR([*** expat not found])])
|
||||
|
||||
AC_SUBST(HAVE_EXPAT)
|
||||
PKG_CHECK_MODULES([EXPAT], [expat >= 2.1])
|
||||
AC_SUBST(EXPAT_CFLAGS)
|
||||
AC_SUBST(EXPAT_LIBS)
|
||||
AM_CONDITIONAL([HAVE_EXPAT], [test "x$HAVE_EXPAT" = x1])
|
||||
AS_IF([test "x$HAVE_EXPAT" = "x1"], AC_DEFINE([HAVE_EXPAT], 1, [Have expat?]))
|
||||
AS_IF([test "x$HAVE_EXPAT" = "x1"], ENABLE_XML="yes (expat)", ENABLE_XML=no)
|
||||
|
||||
# Output devices
|
||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_OUT_HDMI])
|
||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_DEVICE_OUT_HDMI_ARC])
|
||||
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
|
||||
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_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
|
||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_SOURCE_ECHO_REFERENCE])
|
||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_SOURCE_FM_TUNER])
|
||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_SOURCE_FM_RX])
|
||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_SOURCE_FM_RX_A2DP])
|
||||
|
||||
# Output flags
|
||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_OUTPUT_FLAG_COMPRESS_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])
|
||||
# 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])
|
||||
# Added in 6.0
|
||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_INPUT_FLAG_RAW])
|
||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_INPUT_FLAG_SYNC])
|
||||
|
||||
# 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_UPLINK])
|
||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_CHANNEL_IN_VOICE_DNLINK])
|
||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO])
|
||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO])
|
||||
|
||||
# Formats
|
||||
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_FORMAT_PCM_OFFLOAD])
|
||||
|
|
@ -335,5 +274,4 @@ echo "
|
|||
modules directory: ${modlibexecdir}
|
||||
|
||||
Droid device: ${droiddevice}
|
||||
XML config support: ${ENABLE_XML}
|
||||
"
|
||||
|
|
|
|||
98
debian/changelog
vendored
Normal file
98
debian/changelog
vendored
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
pulseaudio-modules-droid-modern (16.1.101+gemian11+nmu1) bookworm; urgency=medium
|
||||
|
||||
* Non-maintainer upload.
|
||||
* add config files
|
||||
|
||||
-- Penelope Gwen <support@pogmom.me> Sun, 29 Mar 2026 14:04:19 -0700
|
||||
|
||||
pulseaudio-modules-droid-modern (16.1.101+gemian1) unstable; urgency=medium
|
||||
|
||||
* New upstream nabbed from droidian
|
||||
|
||||
-- Adam Boardman <adamboardman@gmail.com> Tue, 04 Apr 2023 16:02:47 +0100
|
||||
|
||||
pulseaudio-modules-droid (12.2.84+gemian) buster; urgency=medium
|
||||
|
||||
* New upstream release
|
||||
|
||||
-- TheKit <thekit@disroot.org> Wed, 03 Jun 2020 01:55:10 +0100
|
||||
|
||||
pulseaudio-modules-droid (12.2.79+gemian) buster; urgency=medium
|
||||
|
||||
* Branch packaging for Gemian
|
||||
|
||||
-- TheKit <thekit@disroot.org> Wed, 13 Nov 2019 13:39:31 +0100
|
||||
|
||||
pulseaudio-modules-droid (12.2.79-3) unstable; urgency=medium
|
||||
|
||||
* Fix pulseaudio droid module version
|
||||
|
||||
-- Jonah Brüchert <jbb@kaidan.im> Tue, 12 Nov 2019 12:35:51 +0100
|
||||
|
||||
pulseaudio-modules-droid (12.2.79-2) unstable; urgency=medium
|
||||
|
||||
* Fix generating the pkgconfig files with proper pathes
|
||||
|
||||
-- Jonah Brüchert <jbb@kaidan.im> Tue, 12 Nov 2019 12:06:47 +0100
|
||||
|
||||
pulseaudio-modules-droid (12.2.79-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release
|
||||
|
||||
-- Jonah Brüchert <jbb@kaidan.im> Sun, 06 Oct 2019 15:23:45 +0200
|
||||
|
||||
pulseaudio-modules-droid (12.2.78-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release
|
||||
|
||||
-- Jonah Brüchert <jbb@kaidan.im> Thu, 25 Apr 2019 22:37:38 +0200
|
||||
|
||||
pulseaudio-modules-droid (11.1.75-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release
|
||||
|
||||
-- Jonah Brüchert <jbb@kaidan.im> Tue, 13 Nov 2018 21:17:39 +0100
|
||||
|
||||
pulseaudio-modules-droid (11.1.74-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release
|
||||
|
||||
-- Jonah Brüchert <jbb@kaidan.im> Sat, 13 Oct 2018 20:43:53 +0200
|
||||
|
||||
pulseaudio-modules-droid (11.1.73-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release
|
||||
|
||||
-- Jonah Brüchert <jbb@kaidan.im> Sat, 13 Oct 2018 20:43:29 +0200
|
||||
|
||||
pulseaudio-modules-droid (11.1.72-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release
|
||||
|
||||
-- Jonah Brüchert <jbb@kaidan.im> Sun, 26 Aug 2018 12:27:09 +0200
|
||||
|
||||
pulseaudio-modules-droid (11.1.71-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release
|
||||
|
||||
-- Jonah Brüchert <jbb@kaidan.im> Wed, 22 Aug 2018 14:04:55 +0200
|
||||
|
||||
pulseaudio-modules-droid (11.1.68-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release
|
||||
|
||||
-- Jonah Brüchert <jbb@kaidan.im> Wed, 06 Jun 2018 14:03:22 +0200
|
||||
|
||||
pulseaudio-modules-droid (11.1.67-1) unstable; urgency=medium
|
||||
|
||||
* New upstream release
|
||||
* Move to mer-hybris upstream
|
||||
* Split packaging from source
|
||||
|
||||
-- Jonah Brüchert <jbb@kaidan.im> Sat, 26 May 2018 20:06:24 +0200
|
||||
|
||||
pulseaudio-modules-droid (0.1) xenial; urgency=medium
|
||||
|
||||
* Initial release.
|
||||
|
||||
-- Marius Gripsgard <marius@ubports.com> Fri, 19 Jan 2018 07:39:13 +0100
|
||||
1
debian/compat
vendored
Normal file
1
debian/compat
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
11
|
||||
43
debian/control
vendored
Normal file
43
debian/control
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
Source: pulseaudio-modules-droid-modern
|
||||
Section: sound
|
||||
Priority: optional
|
||||
Build-Depends: android-headers,
|
||||
check,
|
||||
debhelper (>= 11),
|
||||
dh-exec,
|
||||
intltool,
|
||||
pulseaudio-pulsecore-dev,
|
||||
libdbus-1-dev,
|
||||
libhardware-dev,
|
||||
libhybris-common-dev,
|
||||
libltdl-dev,
|
||||
libpulse-dev,
|
||||
libexpat1-dev,
|
||||
libevdev-dev,
|
||||
libudev-dev
|
||||
Maintainer: Adam Boardman <adamboardman@gmail.com>
|
||||
Standards-Version: 4.3.0
|
||||
Homepage: https://github.com/mer-hybris/pulseaudio-modules-droid
|
||||
Vcs-Git: https://github.com/gemian/pulseaudio-modules-droid-modern.git
|
||||
Vcs-Browser: https://github.com/gemian/pulseaudio-modules-droid-modern
|
||||
|
||||
Package: pulseaudio-modules-droid-modern
|
||||
Architecture: any
|
||||
Depends: ${misc:Depends}, ${shlibs:Depends}
|
||||
Provides: pulseaudio-modules-droid-apispecific
|
||||
Conflicts: pulseaudio-modules-droid-apispecific
|
||||
Description: PulseAudio Droid HAL module
|
||||
Pulseaudio modules to interact with the Android HAL.
|
||||
.
|
||||
This package contains the actual modules, for Android 11+.
|
||||
|
||||
Package: pulseaudio-modules-droid-modern-dev
|
||||
Architecture: any
|
||||
Depends: pulseaudio-modules-droid-modern (= ${binary:Version}),
|
||||
${misc:Depends},
|
||||
Provides: pulseaudio-modules-droid-apispecific-dev
|
||||
Conflicts: pulseaudio-modules-droid-apispecific-dev
|
||||
Description: PulseAudio Droid HAL module - development headers
|
||||
Pulseaudio modules to interact with the Android HAL.
|
||||
.
|
||||
This package contains the development headers.
|
||||
44
debian/copyright
vendored
Normal file
44
debian/copyright
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: pulseaudio-modules-droid-modern
|
||||
Source: https://github.com/mer-hybris/pulseaudio-modules-droid-modern
|
||||
|
||||
Files: *
|
||||
Copyright: 2013-2022, Jolla Ltd.
|
||||
License: LGPL-2.1
|
||||
|
||||
Files: debian/*
|
||||
Copyright: 2018, Jonah Brüchert
|
||||
2017, 2018, Marius Gripsgard
|
||||
License: LGPL-2.1
|
||||
|
||||
Files: m4/*
|
||||
Copyright: 2006, 2007, xine project
|
||||
2006, 2007, Diego Pettenò <flameeyes@gmail.com>
|
||||
License: GPL-2+
|
||||
|
||||
License: GPL-2+
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 dated June, 1991, or (at
|
||||
your option) any later version.
|
||||
.
|
||||
On Debian systems, the complete text of version 2 of the GNU General
|
||||
Public License can be found in '/usr/share/common-licenses/GPL-2'.
|
||||
|
||||
License: LGPL-2.1
|
||||
This package is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation, version 2.1 of
|
||||
the License.
|
||||
.
|
||||
This package is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
.
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this package; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
.
|
||||
On Debian systems, the complete text of the GNU Lesser General
|
||||
Public License can be found in `/usr/share/common-licenses/LGPL-2.1'.
|
||||
4
debian/preinst
vendored
Executable file
4
debian/preinst
vendored
Executable file
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/sh
|
||||
|
||||
rm /etc/pulse/default.pa.gemian || true
|
||||
rm /etc/pulse/arm_droid_card_custom.pa || true
|
||||
2
debian/pulseaudio-modules-droid-modern-dev.install
vendored
Normal file
2
debian/pulseaudio-modules-droid-modern-dev.install
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
usr/include/pulsecore/modules/droid/*.h
|
||||
usr/lib/*/pkgconfig/*
|
||||
7
debian/pulseaudio-modules-droid-modern.install
vendored
Normal file
7
debian/pulseaudio-modules-droid-modern.install
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
usr/lib/pulse-*/modules/libdroid-sink*.so
|
||||
usr/lib/pulse-*/modules/libdroid-source*.so
|
||||
usr/lib/pulse-*/modules/libdroid-util*.so
|
||||
usr/lib/pulse-*/modules/module-droid-card*.so
|
||||
usr/lib/pulse-*/modules/module-droid-sink*.so
|
||||
usr/lib/pulse-*/modules/module-droid-source*.so
|
||||
etc/*
|
||||
33
debian/rules
vendored
Executable file
33
debian/rules
vendored
Executable file
|
|
@ -0,0 +1,33 @@
|
|||
#!/usr/bin/make -f
|
||||
# -*- makefile -*-
|
||||
|
||||
include /usr/share/dpkg/default.mk
|
||||
|
||||
PA_MODULE_DIR := $$(readlink -f /usr/lib/pulse-*/modules)
|
||||
|
||||
%:
|
||||
dh $@ --with=autoreconf
|
||||
|
||||
override_dh_auto_configure:
|
||||
dh_auto_configure -- --disable-static --with-module-dir=${PA_MODULE_DIR}
|
||||
|
||||
override_dh_autoreconf:
|
||||
echo ${DEB_VERSION_UPSTREAM} > .tarball-version
|
||||
dh_autoreconf
|
||||
|
||||
override_dh_auto_clean:
|
||||
if [ -f .tarball-version ]; then rm .tarball-version; fi
|
||||
dh_auto_clean
|
||||
|
||||
override_dh_shlibdeps:
|
||||
dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info -l/usr/lib/${DEB_HOST_MULTIARCH}/pulseaudio:/usr/lib/pulse-*/modules
|
||||
|
||||
override_dh_auto_install:
|
||||
dh_auto_install
|
||||
|
||||
rm debian/tmp/usr/lib/pulse-*/modules/*.la
|
||||
|
||||
install -d debian/tmp/usr/include/pulsecore/modules/droid
|
||||
install -m 644 src/common/*.h debian/tmp/usr/include/pulsecore/modules/droid
|
||||
install -d debian/tmp/usr/lib/${DEB_HOST_MULTIARCH}/pkgconfig
|
||||
install -m 644 src/common/*.pc debian/tmp/usr/lib/${DEB_HOST_MULTIARCH}/pkgconfig
|
||||
1
debian/source/format
vendored
Normal file
1
debian/source/format
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
3.0 (native)
|
||||
1
etc/pulse/arm_droid_card_custom.pa
Normal file
1
etc/pulse/arm_droid_card_custom.pa
Normal file
|
|
@ -0,0 +1 @@
|
|||
load-module module-droid-card
|
||||
142
etc/pulse/default.pa.gemian
Normal file
142
etc/pulse/default.pa.gemian
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
#!/usr/bin/pulseaudio -nF
|
||||
#
|
||||
# This file is part of PulseAudio.
|
||||
#
|
||||
# PulseAudio is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# PulseAudio is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# This startup script is used only if PulseAudio is started per-user
|
||||
# (i.e. not in system mode)
|
||||
|
||||
.nofail
|
||||
|
||||
.fail
|
||||
|
||||
load-module module-droid-keepalive
|
||||
|
||||
|
||||
### Automatically augment property information from .desktop files
|
||||
### stored in /usr/share/application
|
||||
load-module module-augment-properties
|
||||
|
||||
load-module module-null-sink sink_name=sink.null rate=48000
|
||||
|
||||
load-module module-stream-restore
|
||||
|
||||
### Switch when connected by default (ubports)
|
||||
load-module module-switch-on-connect ignore_virtual=yes
|
||||
### Should be after module-*-restore but before module-*-detect (sfos)
|
||||
load-module module-switch-on-port-available
|
||||
|
||||
|
||||
### If droid-card needs other arguments than the default, have the new
|
||||
### load-module line in /etc/pulse/arm_droid_card_custom.pa
|
||||
.ifexists /etc/pulse/arm_droid_card_custom.pa
|
||||
.include /etc/pulse/arm_droid_card_custom.pa
|
||||
.else
|
||||
load-module module-droid-card rate=48000
|
||||
.endif
|
||||
|
||||
### Needed on many new devices. HADK guide explains how to implement this fully
|
||||
.ifexists module-droid-glue.so
|
||||
.nofail
|
||||
load-module module-droid-glue
|
||||
.fail
|
||||
.endif
|
||||
|
||||
.ifexists module-droid-hidl-28.so
|
||||
.nofail
|
||||
load-module module-droid-hidl-28
|
||||
.fail
|
||||
.endif
|
||||
|
||||
load-module module-null-sink sink_name=sink.fake.sco rate=8000 channels=1
|
||||
load-module module-null-source source_name=source.fake.sco rate=8000 channels=1
|
||||
#load-module module-bluetooth-discover bluez4_args="sco_sink=sink.fake.sco sco_source=source.fake.sco" bluez5_args="headset=droid"
|
||||
load-module module-bluetooth-discover
|
||||
load-module module-bluetooth-policy
|
||||
|
||||
#load-module module-policy-enforcement
|
||||
|
||||
load-module module-role-ducking trigger_roles=alarm,notification,warning ducking_roles=x-maemo volume=-200dB
|
||||
|
||||
### Load several protocols
|
||||
.ifexists module-esound-protocol-unix.so
|
||||
load-module module-esound-protocol-unix
|
||||
.endif
|
||||
load-module module-native-protocol-unix
|
||||
|
||||
### Network access (may be configured with paprefs, so leave this commented
|
||||
### here if you plan to use paprefs)
|
||||
#load-module module-esound-protocol-tcp
|
||||
#load-module module-native-protocol-tcp
|
||||
#load-module module-zeroconf-publish
|
||||
|
||||
### Load the RTP receiver module (also configured via paprefs, see above)
|
||||
#load-module module-rtp-recv
|
||||
|
||||
### Load the RTP sender module (also configured via paprefs, see above)
|
||||
#load-module module-null-sink sink_name=rtp format=s16be channels=2 rate=44100 sink_properties="device.description='RTP Multicast Sink'"
|
||||
#load-module module-rtp-send source=rtp.monitor
|
||||
|
||||
### Load additional modules from GSettings. This can be configured with the paprefs tool.
|
||||
### Please keep in mind that the modules configured by paprefs might conflict with manually
|
||||
### loaded modules.
|
||||
.ifexists module-gsettings.so
|
||||
.nofail
|
||||
load-module module-gsettings
|
||||
.fail
|
||||
.endif
|
||||
|
||||
|
||||
### Make sure we always have a sink around, even if it is a null sink.
|
||||
load-module module-always-sink
|
||||
|
||||
### Honour intended role device property
|
||||
load-module module-intended-roles
|
||||
|
||||
### Automatically suspend sinks/sources that become idle for too long
|
||||
load-module module-suspend-on-idle timeout=1
|
||||
|
||||
### If autoexit on idle is enabled we want to make sure we only quit
|
||||
### when no local session needs us anymore.
|
||||
.ifexists module-console-kit.so
|
||||
load-module module-console-kit
|
||||
.endif
|
||||
.ifexists module-systemd-login.so
|
||||
load-module module-systemd-login
|
||||
.endif
|
||||
|
||||
### Load DBus protocol
|
||||
.ifexists module-dbus-protocol.so
|
||||
load-module module-dbus-protocol
|
||||
.endif
|
||||
|
||||
### Move orphan streams to placeholder sinks or sources so that playback doesn't get
|
||||
### interrupted. Policy enforcement module then moves the streams to new appropriate
|
||||
### sinks or sources.
|
||||
#load-module module-rescue-streams sink_name=sink.null source_name=sink.null.monitor
|
||||
|
||||
### Enable positioned event sounds
|
||||
load-module module-position-event-sounds
|
||||
|
||||
### Modules to allow auto-loading of filters (such as echo cancellation)
|
||||
### on demand. module-filter-heuristics tries to determine what filters
|
||||
### make sense, and module-filter-apply does the heavy-lifting of
|
||||
### loading modules and rerouting streams.
|
||||
load-module module-filter-heuristics
|
||||
load-module module-filter-apply
|
||||
|
||||
### Make some devices default
|
||||
set-default-sink sink.primary_output
|
||||
set-default-source source.droid
|
||||
|
|
@ -17,5 +17,10 @@ AC_DEFUN([CC_CHECK_DROID_ENUM],
|
|||
AC_MSG_RESULT([$cc_check_droid_enum])
|
||||
if test x"$cc_check_droid_enum" = x"yes"; then
|
||||
AC_DEFINE(HAVE_ENUM_$2,,[define if enum $2 is found in headers])
|
||||
AC_DEFINE(STRING_ENTRY_IF_$2,[STRING_ENTRY($2),],[string entry for enum $2])
|
||||
AC_DEFINE(FANCY_ENTRY_IF_$2(n),[{$2, n},],[fancy entry for enum $2])
|
||||
else
|
||||
AC_DEFINE(STRING_ENTRY_IF_$2,,[string entry for enum $2])
|
||||
AC_DEFINE(FANCY_ENTRY_IF_$2(n),,[fancy entry for enum $2])
|
||||
fi
|
||||
])
|
||||
|
|
|
|||
|
|
@ -1,78 +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}.77
|
||||
Release: 1
|
||||
Group: Multimedia/PulseAudio
|
||||
License: LGPLv2.1+
|
||||
URL: https://github.com/mer-hybris/pulseaudio-modules-droid
|
||||
Source0: %{name}-%{version}.tar.bz2
|
||||
Requires: pulseaudio >= %{pulseversion}
|
||||
Requires: %{name}-common = %{version}-%{release}
|
||||
BuildRequires: automake
|
||||
BuildRequires: libtool
|
||||
BuildRequires: libtool-ltdl-devel
|
||||
BuildRequires: pkgconfig(pulsecore) >= %{pulsemajorminor}
|
||||
BuildRequires: pkgconfig(android-headers)
|
||||
BuildRequires: pkgconfig(libhardware)
|
||||
BuildRequires: pkgconfig(dbus-1)
|
||||
Provides: pulseaudio-modules-droid
|
||||
|
||||
%description
|
||||
PulseAudio Droid HAL modules.
|
||||
|
||||
%package common
|
||||
Summary: Common libs for the PulseAudio droid modules
|
||||
Group: Multimedia/PulseAudio
|
||||
Requires: pulseaudio >= %{pulseversion}
|
||||
|
||||
%description common
|
||||
This contains common libs for the PulseAudio droid modules.
|
||||
|
||||
%package devel
|
||||
Summary: Development files for PulseAudio droid modules
|
||||
Group: Development/Libraries
|
||||
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
|
||||
%{_libdir}/pulse-%{pulsemajorminor}/modules/module-droid-keepalive.so
|
||||
|
||||
%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,21 +5,20 @@
|
|||
Name: pulseaudio-modules-droid
|
||||
|
||||
Summary: PulseAudio Droid HAL modules
|
||||
Version: %{pulsemajorminor}.77
|
||||
Version: %{pulsemajorminor}.101
|
||||
Release: 1
|
||||
Group: Multimedia/PulseAudio
|
||||
License: LGPLv2.1+
|
||||
License: LGPLv2+
|
||||
URL: https://github.com/mer-hybris/pulseaudio-modules-droid
|
||||
Source0: %{name}-%{version}.tar.bz2
|
||||
Requires: pulseaudio >= %{pulseversion}
|
||||
Requires: %{name}-common = %{version}-%{release}
|
||||
Requires: pulseaudio-module-keepalive >= 1.0.0
|
||||
BuildRequires: automake
|
||||
BuildRequires: libtool
|
||||
BuildRequires: libtool-ltdl-devel
|
||||
BuildRequires: pkgconfig(pulsecore) >= %{pulsemajorminor}
|
||||
BuildRequires: pkgconfig(android-headers)
|
||||
BuildRequires: pkgconfig(libhardware)
|
||||
BuildRequires: pkgconfig(dbus-1)
|
||||
BuildRequires: pkgconfig(expat)
|
||||
|
||||
%description
|
||||
|
|
@ -27,7 +26,6 @@ PulseAudio Droid HAL modules.
|
|||
|
||||
%package common
|
||||
Summary: Common libs for the PulseAudio droid modules
|
||||
Group: Multimedia/PulseAudio
|
||||
Requires: pulseaudio >= %{pulseversion}
|
||||
|
||||
%description common
|
||||
|
|
@ -35,7 +33,6 @@ This contains common libs for the PulseAudio droid modules.
|
|||
|
||||
%package devel
|
||||
Summary: Development files for PulseAudio droid modules
|
||||
Group: Development/Libraries
|
||||
Requires: %{name}-common = %{version}-%{release}
|
||||
Requires: pulseaudio >= %{pulseversion}
|
||||
|
||||
|
|
@ -43,17 +40,20 @@ Requires: pulseaudio >= %{pulseversion}
|
|||
This contains development files for PulseAudio droid modules.
|
||||
|
||||
%prep
|
||||
%setup -q -n %{name}-%{version}
|
||||
%autosetup -n %{name}-%{version}
|
||||
|
||||
%build
|
||||
echo "%{moduleversion}" > .tarball-version
|
||||
# Obtain the DEVICE from the same source as used in /etc/os-release
|
||||
. /usr/lib/droid-devel/hw-release.vars
|
||||
if [ -e "%{_includedir}/droid-devel/hw-release.vars" ]; then
|
||||
. %{_includedir}/droid-devel/hw-release.vars
|
||||
else
|
||||
. %{_libdir}/droid-devel/hw-release.vars
|
||||
fi
|
||||
%reconfigure --disable-static --with-droid-device=$MER_HA_DEVICE
|
||||
make %{?jobs:-j%jobs}
|
||||
%make_build
|
||||
|
||||
%install
|
||||
rm -rf %{buildroot}
|
||||
%make_install
|
||||
|
||||
%files
|
||||
|
|
@ -63,7 +63,7 @@ rm -rf %{buildroot}
|
|||
%{_libdir}/pulse-%{pulsemajorminor}/modules/module-droid-sink.so
|
||||
%{_libdir}/pulse-%{pulsemajorminor}/modules/module-droid-source.so
|
||||
%{_libdir}/pulse-%{pulsemajorminor}/modules/module-droid-card.so
|
||||
%{_libdir}/pulse-%{pulsemajorminor}/modules/module-droid-keepalive.so
|
||||
%license COPYING
|
||||
|
||||
%files common
|
||||
%defattr(-,root,root,-)
|
||||
|
|
@ -71,9 +71,11 @@ rm -rf %{buildroot}
|
|||
|
||||
%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
|
||||
%dir %{_includedir}/pulsecore/modules/droid
|
||||
%{_includedir}/pulsecore/modules/droid/conversion.h
|
||||
%{_includedir}/pulsecore/modules/droid/droid-config.h
|
||||
%{_includedir}/pulsecore/modules/droid/droid-util.h
|
||||
%{_includedir}/pulsecore/modules/droid/sllist.h
|
||||
%{_includedir}/pulsecore/modules/droid/utils.h
|
||||
%{_includedir}/pulsecore/modules/droid/version.h
|
||||
%{_libdir}/pkgconfig/*.pc
|
||||
|
|
|
|||
|
|
@ -18,7 +18,9 @@ includedir = @includedir@/pulsecore/modules/droid
|
|||
include_HEADERS = include/droid/version.h \
|
||||
include/droid/conversion.h \
|
||||
include/droid/droid-config.h \
|
||||
include/droid/droid-util.h
|
||||
include/droid/droid-util.h \
|
||||
include/droid/sllist.h \
|
||||
include/droid/utils.h
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = libdroid-util.pc
|
||||
|
|
@ -26,10 +28,11 @@ pkgconfig_DATA = libdroid-util.pc
|
|||
libdroid_util_la_SOURCES = droid-util.c \
|
||||
droid-config.c \
|
||||
conversion.c \
|
||||
config-parser-legacy.c \
|
||||
config-parser-xml.c \
|
||||
droid-util-audio.h \
|
||||
droid-util-41qc.h
|
||||
config-parser-xml.h \
|
||||
sllist.c \
|
||||
utils.c \
|
||||
droid-util-audio.h
|
||||
libdroid_util_la_LDFLAGS = -avoid-version -Wl,-z,noexecstack -lhybris-common $(SBJ_DEVICE_LDFLAGS)
|
||||
libdroid_util_la_LIBADD = $(AM_LIBADD)
|
||||
libdroid_util_la_CFLAGS = $(AM_CFLAGS)
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
*
|
||||
|
|
@ -26,15 +26,6 @@
|
|||
|
||||
#include "droid/droid-config.h"
|
||||
|
||||
#ifndef HAVE_EXPAT
|
||||
#include <unistd.h>
|
||||
pa_droid_config_audio *pa_parse_droid_audio_config_xml(const char *filename) {
|
||||
if (access(filename, F_OK) == 0)
|
||||
pa_log_warn("Could not parse %s, xml configuration parsing support not compiled in", filename);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <expat.h>
|
||||
|
|
@ -42,9 +33,13 @@ pa_droid_config_audio *pa_parse_droid_audio_config_xml(const char *filename) {
|
|||
#include <pulse/xmalloc.h>
|
||||
#include <pulsecore/core-util.h>
|
||||
#include <pulsecore/core-error.h>
|
||||
#include <pulsecore/strbuf.h>
|
||||
|
||||
#include "droid/conversion.h"
|
||||
#include "droid/sllist.h"
|
||||
#include "droid/utils.h"
|
||||
#include "droid/droid-config.h"
|
||||
#include "config-parser-xml.h"
|
||||
|
||||
#ifdef XML_UNICODE_WCHAR_T
|
||||
# include <wchar.h>
|
||||
|
|
@ -70,6 +65,7 @@ pa_droid_config_audio *pa_parse_droid_audio_config_xml(const char *filename) {
|
|||
/* ELEMENT_profile */
|
||||
#define ELEMENT_routes "routes"
|
||||
#define ELEMENT_route "route"
|
||||
#define ELEMENT_include "xi:include"
|
||||
|
||||
#define ATTRIBUTE_version "version"
|
||||
#define ATTRIBUTE_name "name"
|
||||
|
|
@ -83,6 +79,10 @@ pa_droid_config_audio *pa_parse_droid_audio_config_xml(const char *filename) {
|
|||
#define ATTRIBUTE_sink "sink"
|
||||
#define ATTRIBUTE_sources "sources"
|
||||
#define ATTRIBUTE_type "type"
|
||||
#define ATTRIBUTE_href "href"
|
||||
#define ATTRIBUTE_maxOpenCount "maxOpenCount"
|
||||
#define ATTRIBUTE_maxActiveCount "maxActiveCount"
|
||||
#define ATTRIBUTE_address "address"
|
||||
|
||||
#define PORT_TYPE_sink "sink"
|
||||
#define PORT_TYPE_source "source"
|
||||
|
|
@ -133,6 +133,7 @@ static void parse_default_output_device(struct parser_data *data, const char *st
|
|||
static void parse_item(struct parser_data *data, const char *str);
|
||||
static bool parse_module(struct parser_data *data, const char *element_name, const XML_Char **attributes);
|
||||
static bool parse_global_configuration(struct parser_data *data, const char *element_name, const XML_Char **attributes);
|
||||
static bool parse_module_include(struct parser_data *data, const char *element_name, const XML_Char **attributes);
|
||||
|
||||
static const struct element_parser element_parse_route = {
|
||||
ELEMENT_route,
|
||||
|
|
@ -214,12 +215,40 @@ static const struct element_parser element_parse_attached_devices = {
|
|||
&element_parse_item
|
||||
};
|
||||
|
||||
/* Entries like
|
||||
* <modules>
|
||||
* <module name="primary"> <xi:include href="other.xml"/> </module>
|
||||
* </modules>
|
||||
* Where other.xml contains module elements
|
||||
*/
|
||||
static const struct element_parser element_parse_module_include = {
|
||||
ELEMENT_include,
|
||||
parse_module_include,
|
||||
NULL,
|
||||
&element_parse_attached_devices,
|
||||
NULL
|
||||
};
|
||||
|
||||
/* Entries like
|
||||
* <modules>
|
||||
* <xi:include href="other.xml"/>
|
||||
* </modules>
|
||||
* Where other.xml contains <module name="primary">...
|
||||
*/
|
||||
static const struct element_parser element_parse_modules_include = {
|
||||
ELEMENT_include,
|
||||
parse_module_include,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct element_parser element_parse_module = {
|
||||
ELEMENT_module,
|
||||
parse_module,
|
||||
NULL,
|
||||
NULL,
|
||||
&element_parse_attached_devices
|
||||
&element_parse_modules_include,
|
||||
&element_parse_module_include
|
||||
};
|
||||
|
||||
static const struct element_parser element_parse_modules = {
|
||||
|
|
@ -270,7 +299,7 @@ struct profile {
|
|||
char *name;
|
||||
audio_format_t format;
|
||||
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;
|
||||
};
|
||||
|
||||
|
|
@ -278,6 +307,8 @@ struct mix_port {
|
|||
char *name;
|
||||
char *role;
|
||||
uint32_t flags;
|
||||
int max_open_count;
|
||||
int max_active_count;
|
||||
struct profile *profiles;
|
||||
struct mix_port *next;
|
||||
};
|
||||
|
|
@ -286,6 +317,7 @@ struct device_port {
|
|||
char *tag_name;
|
||||
audio_devices_t type;
|
||||
char *role;
|
||||
char *address;
|
||||
struct profile *profiles;
|
||||
struct device_port *next;
|
||||
};
|
||||
|
|
@ -309,9 +341,17 @@ struct module {
|
|||
struct module *next;
|
||||
};
|
||||
|
||||
struct includes {
|
||||
char *href;
|
||||
struct module *module;
|
||||
|
||||
struct includes *next;
|
||||
};
|
||||
|
||||
struct audio_policy_configuration {
|
||||
struct global_configuration *global;
|
||||
struct module *modules;
|
||||
struct includes *includes;
|
||||
};
|
||||
|
||||
struct parser_data {
|
||||
|
|
@ -319,7 +359,6 @@ struct parser_data {
|
|||
const char *fn;
|
||||
unsigned lineno;
|
||||
|
||||
const struct element_parser *root;
|
||||
const struct element_parser *current;
|
||||
struct element_parser_stack *stack;
|
||||
|
||||
|
|
@ -327,6 +366,7 @@ struct parser_data {
|
|||
struct module *current_module;
|
||||
struct mix_port *current_mix_port;
|
||||
struct device_port *current_device_port;
|
||||
struct includes *current_include;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -343,94 +383,85 @@ static char *xml_string_dup(const XML_Char *xml_str, int len)
|
|||
return str;
|
||||
}
|
||||
|
||||
static void device_free(struct device *d) {
|
||||
pa_assert(d);
|
||||
pa_xfree(d->name);
|
||||
pa_xfree(d);
|
||||
}
|
||||
|
||||
static void profile_free(struct profile *p) {
|
||||
pa_assert(p);
|
||||
pa_xfree(p->name);
|
||||
pa_xfree(p);
|
||||
}
|
||||
|
||||
static void mix_port_free(struct mix_port *p) {
|
||||
struct profile *profile;
|
||||
|
||||
pa_assert(p);
|
||||
|
||||
while (p->profiles) {
|
||||
SLLIST_STEAL_FIRST(profile, p->profiles);
|
||||
profile_free(profile);
|
||||
};
|
||||
|
||||
pa_xfree(p->name);
|
||||
pa_xfree(p->role);
|
||||
pa_xfree(p);
|
||||
}
|
||||
|
||||
static void device_port_free(struct device_port *p) {
|
||||
pa_assert(p);
|
||||
pa_xfree(p->tag_name);
|
||||
pa_xfree(p->role);
|
||||
pa_xfree(p);
|
||||
}
|
||||
|
||||
static void route_free(struct route *r) {
|
||||
static void device_list_free(struct device *list) {
|
||||
struct device *d;
|
||||
|
||||
pa_assert(r);
|
||||
|
||||
while (r->sources) {
|
||||
SLLIST_STEAL_FIRST(d, r->sources);
|
||||
device_free(d);
|
||||
while (list) {
|
||||
SLLIST_STEAL_FIRST(d, list);
|
||||
pa_xfree(d->name);
|
||||
pa_xfree(d);
|
||||
}
|
||||
}
|
||||
|
||||
static void profile_list_free(struct profile *list) {
|
||||
struct profile *p;
|
||||
|
||||
while (list) {
|
||||
SLLIST_STEAL_FIRST(p, list);
|
||||
pa_xfree(p->name);
|
||||
pa_xfree(p);
|
||||
};
|
||||
}
|
||||
|
||||
static void mix_port_list_free(struct mix_port *list) {
|
||||
struct mix_port *p;
|
||||
|
||||
while (list) {
|
||||
SLLIST_STEAL_FIRST(p, list);
|
||||
profile_list_free(p->profiles);
|
||||
pa_xfree(p->name);
|
||||
pa_xfree(p->role);
|
||||
pa_xfree(p);
|
||||
}
|
||||
}
|
||||
|
||||
static void device_port_list_free(struct device_port *list) {
|
||||
struct device_port *p;
|
||||
|
||||
while (list) {
|
||||
SLLIST_STEAL_FIRST(p, list);
|
||||
profile_list_free(p->profiles);
|
||||
pa_xfree(p->tag_name);
|
||||
pa_xfree(p->role);
|
||||
pa_xfree(p->address);
|
||||
pa_xfree(p);
|
||||
}
|
||||
}
|
||||
|
||||
static void route_list_free(struct route *list) {
|
||||
struct route *r;
|
||||
|
||||
while (list) {
|
||||
SLLIST_STEAL_FIRST(r, list);
|
||||
device_list_free(r->sources);
|
||||
pa_xfree(r->type);
|
||||
pa_xfree(r->sink);
|
||||
pa_xfree(r);
|
||||
}
|
||||
pa_xfree(r->type);
|
||||
pa_xfree(r->sink);
|
||||
pa_xfree(r);
|
||||
}
|
||||
|
||||
static void module_free(struct module *m) {
|
||||
struct device *dev;
|
||||
struct mix_port *mix_port;
|
||||
struct device_port *device_port;
|
||||
struct route *route;
|
||||
|
||||
pa_assert(m);
|
||||
|
||||
while (m->attached_devices) {
|
||||
SLLIST_STEAL_FIRST(dev, m->attached_devices);
|
||||
device_free(dev);
|
||||
};
|
||||
|
||||
while (m->default_output) {
|
||||
SLLIST_STEAL_FIRST(dev, m->default_output);
|
||||
device_free(dev);
|
||||
};
|
||||
|
||||
while (m->mix_ports) {
|
||||
SLLIST_STEAL_FIRST(mix_port, m->mix_ports);
|
||||
mix_port_free(mix_port);
|
||||
};
|
||||
|
||||
while (m->device_ports) {
|
||||
SLLIST_STEAL_FIRST(device_port, m->device_ports);
|
||||
device_port_free(device_port);
|
||||
};
|
||||
|
||||
while (m->routes) {
|
||||
SLLIST_STEAL_FIRST(route, m->routes);
|
||||
route_free(route);
|
||||
};
|
||||
device_list_free(m->attached_devices);
|
||||
device_list_free(m->default_output);
|
||||
mix_port_list_free(m->mix_ports);
|
||||
device_port_list_free(m->device_ports);
|
||||
route_list_free(m->routes);
|
||||
|
||||
pa_xfree(m->name);
|
||||
pa_xfree(m);
|
||||
}
|
||||
|
||||
static void includes_free(struct includes *i) {
|
||||
pa_assert(i);
|
||||
|
||||
pa_xfree(i->href);
|
||||
pa_xfree(i);
|
||||
}
|
||||
|
||||
static void audio_policy_configuration_free(struct audio_policy_configuration *xml_config) {
|
||||
struct global_configuration *global;
|
||||
struct module *m;
|
||||
|
||||
pa_assert(xml_config);
|
||||
|
||||
|
|
@ -442,9 +473,16 @@ static void audio_policy_configuration_free(struct audio_policy_configuration *x
|
|||
}
|
||||
|
||||
while (xml_config->modules) {
|
||||
struct module *m;
|
||||
SLLIST_STEAL_FIRST(m, xml_config->modules);
|
||||
module_free(m);
|
||||
};
|
||||
}
|
||||
|
||||
while (xml_config->includes) {
|
||||
struct includes *i;
|
||||
SLLIST_STEAL_FIRST(i, xml_config->includes);
|
||||
includes_free(i);
|
||||
}
|
||||
|
||||
pa_xfree(xml_config);
|
||||
}
|
||||
|
|
@ -535,7 +573,7 @@ static void XMLCALL xml_end_element(void *userdata, const XML_Char *element_name
|
|||
|
||||
element = xml_string_dup(element_name, -1);
|
||||
|
||||
if (pa_streq(data->current->name, element)) {
|
||||
if (pa_safe_streq(data->current->name, element)) {
|
||||
ELEMENT_STACK_POP(data->stack, data->current);
|
||||
|
||||
if (pa_streq(element, ELEMENT_mixPort))
|
||||
|
|
@ -554,7 +592,7 @@ static void XMLCALL xml_character_data_handler(void *userdata, const XML_Char *s
|
|||
int whitespace = 0;
|
||||
char *str = NULL;
|
||||
|
||||
if (len <= 0)
|
||||
if (len <= 0 || !data->current->char_data)
|
||||
goto done;
|
||||
|
||||
str = xml_string_dup(s, len);
|
||||
|
|
@ -563,8 +601,7 @@ static void XMLCALL xml_character_data_handler(void *userdata, const XML_Char *s
|
|||
if (whitespace == len)
|
||||
goto done;
|
||||
|
||||
if (data->current->char_data)
|
||||
data->current->char_data(data, str);
|
||||
data->current->char_data(data, str);
|
||||
|
||||
done:
|
||||
pa_xfree(str);
|
||||
|
|
@ -589,10 +626,37 @@ static bool parse_audio_policy_configuration(struct parser_data *data,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool parse_module_include(struct parser_data *data, const char *element_name, const XML_Char **attributes) {
|
||||
struct includes *i;
|
||||
char *href = NULL;
|
||||
|
||||
if (!get_element_attr(data, attributes, true, ATTRIBUTE_href, &href)) {
|
||||
pa_log("[%s:%u] Include but no href.", data->fn, data->lineno);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* We ignore xpointer attribute for now and just use the module element
|
||||
* we are currently in when parsing the included file. */
|
||||
|
||||
i = pa_xmalloc0(sizeof(*i));
|
||||
i->module = data->current_module;
|
||||
i->href = href;
|
||||
|
||||
SLLIST_APPEND(struct includes, data->conf->includes, i);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_module(struct parser_data *data, const char *element_name, const XML_Char **attributes) {
|
||||
struct module *m;
|
||||
char *halVersion = NULL;
|
||||
|
||||
if (data->current_include && data->current_include->module) {
|
||||
/* We are processing included file, get our module definition from cache. */
|
||||
data->current_module = data->current_include->module;
|
||||
return true;
|
||||
}
|
||||
|
||||
m = pa_xmalloc0(sizeof(*m));
|
||||
|
||||
get_element_attr(data, attributes, false, ATTRIBUTE_name, &m->name);
|
||||
|
|
@ -654,6 +718,8 @@ static bool parse_mix_port(struct parser_data *data, const char *element_name, c
|
|||
struct mix_port *p;
|
||||
bool parsed = false;
|
||||
char *flags = NULL;
|
||||
char *max_open_count = NULL;
|
||||
char *max_active_count = NULL;
|
||||
|
||||
p = pa_xmalloc0(sizeof(*p));
|
||||
|
||||
|
|
@ -671,6 +737,14 @@ static bool parse_mix_port(struct parser_data *data, const char *element_name, c
|
|||
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_active_count, &p->max_active_count);
|
||||
|
||||
parsed = true;
|
||||
done:
|
||||
pa_xfree(flags);
|
||||
|
|
@ -680,26 +754,15 @@ done:
|
|||
data->current_mix_port = p;
|
||||
} else {
|
||||
pa_log("[%s:%u] Failed to parse element <" ELEMENT_mixPort ">", data->fn, data->lineno);
|
||||
mix_port_free(p);
|
||||
mix_port_list_free(p);
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
static void replace_in_place(char **string, const char *a, const char *b) {
|
||||
char *tmp;
|
||||
|
||||
pa_assert(*string);
|
||||
pa_assert(a);
|
||||
pa_assert(b);
|
||||
|
||||
tmp = pa_replace(*string, a, b);
|
||||
pa_xfree(*string);
|
||||
*string = tmp;
|
||||
}
|
||||
|
||||
static bool parse_profile(struct parser_data *data, const char *element_name, const XML_Char **attributes) {
|
||||
struct profile *p;
|
||||
int channel_count = -1;
|
||||
bool parsed = false, unknown_format = false, output = true;
|
||||
char *samplingRates = NULL, *channelMasks = NULL, *format = NULL;
|
||||
|
||||
|
|
@ -732,24 +795,24 @@ static bool parse_profile(struct parser_data *data, const char *element_name, co
|
|||
if (output && pa_startswith(channelMasks, "AUDIO_CHANNEL_IN_")) {
|
||||
pa_log_info("[%s:%u] Output has wrong direction channel mask (%s), reversing.",
|
||||
data->fn, data->lineno, channelMasks);
|
||||
replace_in_place(&channelMasks, "AUDIO_CHANNEL_IN_", "AUDIO_CHANNEL_OUT_");
|
||||
dm_replace_in_place(&channelMasks, "AUDIO_CHANNEL_IN_", "AUDIO_CHANNEL_OUT_");
|
||||
}
|
||||
else if (!output && pa_startswith(channelMasks, "AUDIO_CHANNEL_OUT_")) {
|
||||
pa_log_info("[%s:%u] Input has wrong direction channel mask (%s), reversing.",
|
||||
data->fn, data->lineno, channelMasks);
|
||||
replace_in_place(&channelMasks, "AUDIO_CHANNEL_OUT_", "AUDIO_CHANNEL_IN_");
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
if (!unknown_format && channelMasks && !(output ?
|
||||
pa_conversion_parse_output_channels(data->fn, data->lineno, channelMasks, false, &p->channel_masks)
|
||||
: pa_conversion_parse_input_channels(data->fn, data->lineno, channelMasks, false, &p->channel_masks)))
|
||||
if (!unknown_format && channelMasks && (channel_count = output ?
|
||||
pa_conversion_parse_output_channels(data->fn, data->lineno, channelMasks, p->channel_masks)
|
||||
: pa_conversion_parse_input_channels(data->fn, data->lineno, channelMasks, p->channel_masks)) == -1)
|
||||
goto done;
|
||||
|
||||
parsed = true;
|
||||
|
|
@ -758,17 +821,20 @@ done:
|
|||
pa_xfree(channelMasks);
|
||||
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);
|
||||
profile_free(p);
|
||||
profile_list_free(p);
|
||||
} else if (unknown_format) {
|
||||
pa_log_info("[%s:%u] Ignore profile with unknown format.", data->fn, data->lineno);
|
||||
profile_free(p);
|
||||
profile_list_free(p);
|
||||
} else {
|
||||
if (data->current_mix_port)
|
||||
SLLIST_APPEND(struct profile, data->current_module->mix_ports->profiles, p);
|
||||
SLLIST_APPEND(struct profile, data->current_mix_port->profiles, p);
|
||||
else if (data->current_device_port)
|
||||
SLLIST_APPEND(struct profile, data->current_module->device_ports->profiles, p);
|
||||
SLLIST_APPEND(struct profile, data->current_device_port->profiles, p);
|
||||
else
|
||||
pa_assert_not_reached();
|
||||
}
|
||||
|
|
@ -793,20 +859,23 @@ static bool parse_device_port(struct parser_data *data, const char *element_name
|
|||
goto done;
|
||||
|
||||
if (!(pa_streq(d->role, ATTRIBUTE_sink) ?
|
||||
pa_conversion_parse_output_devices(data->fn, data->lineno, type, false, false, &d->type)
|
||||
: pa_conversion_parse_input_devices(data->fn, data->lineno, type, false, false, &d->type)))
|
||||
pa_conversion_parse_output_devices(data->fn, data->lineno, type, false, &d->type)
|
||||
: pa_conversion_parse_input_devices(data->fn, data->lineno, type, false, &d->type)))
|
||||
unknown_device = true;
|
||||
|
||||
/* address is not mandatory element attribute */
|
||||
get_element_attr(data, attributes, false, ATTRIBUTE_address, &d->address);
|
||||
|
||||
parsed = true;
|
||||
done:
|
||||
pa_xfree(type);
|
||||
|
||||
if (!parsed) {
|
||||
pa_log("[%s:%u] Failed to parse element <" ELEMENT_devicePort ">", data->fn, data->lineno);
|
||||
device_port_free(d);
|
||||
device_port_list_free(d);
|
||||
} else if (unknown_device) {
|
||||
pa_log_info("[%s:%u] Ignore <" ELEMENT_devicePort "> with unknown device.", data->fn, data->lineno);
|
||||
device_port_free(d);
|
||||
device_port_list_free(d);
|
||||
} else {
|
||||
SLLIST_APPEND(struct device_port, data->current_module->device_ports, d);
|
||||
data->current_device_port = d;
|
||||
|
|
@ -845,13 +914,13 @@ done:
|
|||
SLLIST_APPEND(struct route, data->current_module->routes, r);
|
||||
} else {
|
||||
pa_log("[%s:%u] Failed to parse element <" ELEMENT_route ">", data->fn, data->lineno);
|
||||
route_free(r);
|
||||
route_list_free(r);
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
static bool parse_file(struct parser_data *data, const char *filename) {
|
||||
static bool parse_file(struct parser_data *data, const struct element_parser *root, const char *filename) {
|
||||
char buf[BUFSIZ];
|
||||
FILE *f = NULL;
|
||||
XML_Parser parser = NULL;
|
||||
|
|
@ -875,6 +944,8 @@ static bool parse_file(struct parser_data *data, const char *filename) {
|
|||
if (!data->conf)
|
||||
data->conf = pa_xnew0(struct audio_policy_configuration, 1);
|
||||
|
||||
data->current = root;
|
||||
|
||||
XML_SetUserData(parser, data);
|
||||
XML_SetElementHandler(parser, xml_start_element, xml_end_element);
|
||||
XML_SetCharacterDataHandler(parser, xml_character_data_handler);
|
||||
|
|
@ -904,141 +975,238 @@ done:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static struct device_port *find_device_port(struct module *module, const char *name) {
|
||||
struct device_port *port;
|
||||
|
||||
SLLIST_FOREACH(port, module->device_ports) {
|
||||
if (pa_streq(port->tag_name, name))
|
||||
return port;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool device_in_list(struct device *list, const char *name) {
|
||||
struct device *dev;
|
||||
|
||||
pa_assert(name);
|
||||
|
||||
SLLIST_FOREACH(dev, list) {
|
||||
if (pa_streq(name, dev->name))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void add_output(struct module *module, struct mix_port *mix_port, pa_droid_config_hw_module *hw_module) {
|
||||
pa_droid_config_device *output;
|
||||
static void generate_config_profiles(struct profile *profiles, dm_list *list) {
|
||||
struct profile *profile;
|
||||
struct route *route;
|
||||
struct device_port *device_port;
|
||||
|
||||
output = pa_droid_config_device_new(hw_module, PA_DIRECTION_OUTPUT, mix_port->name);
|
||||
output->flags = mix_port->flags;
|
||||
SLLIST_FOREACH(profile, mix_port->profiles) {
|
||||
memcpy(output->sampling_rates, profile->sampling_rates, sizeof(output->sampling_rates));
|
||||
output->channel_masks |= profile->channel_masks;
|
||||
output->formats |= profile->format;
|
||||
SLLIST_FOREACH(profile, profiles) {
|
||||
dm_config_profile *c_profile = pa_xnew0(dm_config_profile, 1);
|
||||
c_profile->name = pa_xstrdup(profile->name ? profile->name : "");
|
||||
c_profile->format = profile->format;
|
||||
memcpy(c_profile->sampling_rates,
|
||||
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) {
|
||||
pa_droid_config_device *input;
|
||||
struct profile *profile;
|
||||
struct route *route;
|
||||
struct device_port *device_port;
|
||||
static dm_config_port *config_device_port_new(dm_config_module *module,
|
||||
struct device_port *device_port) {
|
||||
dm_config_port *c_device_port = pa_xnew0(dm_config_port, 1);
|
||||
|
||||
input = pa_droid_config_device_new(hw_module, PA_DIRECTION_INPUT, mix_port->name);
|
||||
input->flags = mix_port->flags;
|
||||
SLLIST_FOREACH(profile, mix_port->profiles) {
|
||||
memcpy(input->sampling_rates, profile->sampling_rates, sizeof(input->sampling_rates));
|
||||
input->channel_masks |= profile->channel_masks;
|
||||
input->formats |= profile->format;
|
||||
}
|
||||
c_device_port->module = module;
|
||||
c_device_port->port_type = DM_CONFIG_TYPE_DEVICE_PORT;
|
||||
c_device_port->name = pa_xstrdup(device_port->tag_name);
|
||||
c_device_port->type = device_port->type;
|
||||
c_device_port->role = pa_safe_streq(device_port->role, "sink") ? DM_CONFIG_ROLE_SINK : DM_CONFIG_ROLE_SOURCE;
|
||||
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) {
|
||||
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);
|
||||
return c_device_port;
|
||||
}
|
||||
|
||||
static void generate_config_for_module(struct module *module, pa_droid_config_audio *config) {
|
||||
pa_droid_config_hw_module *hw_module;
|
||||
static dm_config_port *config_mix_port_new(dm_config_module *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;
|
||||
}
|
||||
|
||||
/* If a devicePort doesn't have any profiles defined let's just make something
|
||||
* up that could work. */
|
||||
static struct profile *default_profile(const char *role) {
|
||||
struct profile *p;
|
||||
bool output;
|
||||
|
||||
output = pa_safe_streq(role, PORT_TYPE_sink);
|
||||
|
||||
p = pa_xmalloc0(sizeof(*p));
|
||||
|
||||
p->name = pa_sprintf_malloc("generated-default");
|
||||
pa_assert(pa_string_convert_str_to_num(CONV_STRING_FORMAT, "AUDIO_FORMAT_PCM_16_BIT", &p->format));
|
||||
p->sampling_rates[0] = 48000;
|
||||
pa_assert(pa_string_convert_str_to_num(output ? CONV_STRING_OUTPUT_CHANNELS : CONV_STRING_INPUT_CHANNELS,
|
||||
output ? "AUDIO_CHANNEL_OUT_STEREO" : "AUDIO_CHANNEL_IN_STEREO",
|
||||
&p->channel_masks[0]));
|
||||
p->next = NULL;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static void generate_config_for_module(struct module *module, dm_config_device *config) {
|
||||
dm_config_module *c_module;
|
||||
struct mix_port *mix_port;
|
||||
struct device_port *device_port;
|
||||
struct device *device;
|
||||
struct route *route;
|
||||
|
||||
pa_assert(module);
|
||||
pa_assert(config);
|
||||
pa_assert(config->global_config);
|
||||
|
||||
hw_module = pa_droid_config_hw_module_new(config, module->name);
|
||||
if (module->attached_devices || module->default_output)
|
||||
hw_module->global_config = pa_xnew0(pa_droid_config_global, 1);
|
||||
SLLIST_APPEND(pa_droid_config_hw_module, config->hw_modules, hw_module);
|
||||
c_module = pa_xnew0(dm_config_module, 1);
|
||||
c_module->config = config;
|
||||
c_module->name = pa_xstrdup(module->name);
|
||||
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_info("No profile defined for devicePort %s, generating default.", device_port->tag_name);
|
||||
SLLIST_APPEND(struct profile, device_port->profiles, default_profile(device_port->role));
|
||||
}
|
||||
|
||||
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) {
|
||||
if (pa_streq(mix_port->role, PORT_TYPE_source))
|
||||
add_output(module, mix_port, hw_module);
|
||||
else if (pa_streq(mix_port->role, ATTRIBUTE_sink))
|
||||
add_input(module, mix_port, hw_module);
|
||||
else
|
||||
pa_log_warn("Unknown <" ELEMENT_mixPort "> role \"%s\"", mix_port->role);
|
||||
dm_config_port *c_mix_port = config_mix_port_new(c_module, mix_port);
|
||||
dm_list_push_back(c_module->ports, c_mix_port);
|
||||
dm_list_push_back(c_module->mix_ports, c_mix_port);
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
pa_droid_config_audio *config = NULL;
|
||||
static dm_config_device *process_config(struct audio_policy_configuration *source) {
|
||||
dm_config_device *config = NULL;
|
||||
struct global_configuration *global_config;
|
||||
struct module *module;
|
||||
|
||||
pa_assert(source);
|
||||
|
||||
config = pa_xnew0(pa_droid_config_audio, 1);
|
||||
config->global_config = pa_xnew0(pa_droid_config_global, 1);
|
||||
config = pa_xnew0(dm_config_device, 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)
|
||||
generate_config_for_module(module, config);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
pa_droid_config_audio *pa_parse_droid_audio_config_xml(const char *filename) {
|
||||
pa_droid_config_audio *config = NULL;
|
||||
/* Take base filename and relative path to filename and construct new
|
||||
* path replacing file part from the base filename with new filename.
|
||||
* For example, base_file="x/y/file.xml", filename="a/other.xml"
|
||||
* result "x/y/a/other.xml"
|
||||
*/
|
||||
static char *build_path(const char *base_file, const char *filename) {
|
||||
char *fn = NULL;
|
||||
pa_strbuf *buf;
|
||||
char *end;
|
||||
int len;
|
||||
|
||||
pa_assert(base_file);
|
||||
pa_assert(filename);
|
||||
|
||||
if ((end = strrchr(base_file, '/'))) {
|
||||
buf = pa_strbuf_new();
|
||||
len = end - base_file + 1;
|
||||
pa_strbuf_putsn(buf, base_file, len);
|
||||
pa_strbuf_puts(buf, filename);
|
||||
fn = pa_strbuf_to_string_free(buf);
|
||||
}
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
dm_config_device *pa_parse_droid_audio_config_xml(const char *filename) {
|
||||
dm_config_device *config = NULL;
|
||||
struct parser_data data;
|
||||
bool ret = true;
|
||||
|
||||
|
|
@ -1046,13 +1214,31 @@ pa_droid_config_audio *pa_parse_droid_audio_config_xml(const char *filename) {
|
|||
|
||||
memset(&data, 0, sizeof(data));
|
||||
|
||||
data.root = &element_parse_root;
|
||||
data.current = data.root;
|
||||
|
||||
if (!(ret = parse_file(&data, filename)))
|
||||
if (!(ret = parse_file(&data, &element_parse_root, filename)))
|
||||
goto done;
|
||||
|
||||
config = convert_config(data.conf);
|
||||
if (data.conf->includes) {
|
||||
/* Only handle module includes for now. */
|
||||
SLLIST_FOREACH(data.current_include, data.conf->includes) {
|
||||
char *fn = NULL;
|
||||
|
||||
// if (!data.current_include->module)
|
||||
// continue;
|
||||
|
||||
if (data.current_include->href[0] != '/')
|
||||
fn = build_path(filename, data.current_include->href);
|
||||
|
||||
ret = parse_file(&data, &element_parse_modules, fn ? fn : data.current_include->href);
|
||||
|
||||
pa_assert(!data.current_module);
|
||||
pa_xfree(fn);
|
||||
|
||||
if (!ret)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
config = process_config(data.conf);
|
||||
|
||||
done:
|
||||
if (data.conf)
|
||||
|
|
@ -1060,5 +1246,3 @@ done:
|
|||
|
||||
return config;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#ifndef foodroidkeepalivefoo
|
||||
#define foodroidkeepalivefoo
|
||||
#ifndef foodroidconfigparserxmlfoo
|
||||
#define foodroidconfigparserxmlfoo
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013-2018 Jolla Ltd.
|
||||
* Copyright (C) 2022 Jolla Ltd.
|
||||
*
|
||||
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
||||
*
|
||||
|
|
@ -26,19 +26,8 @@
|
|||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <pulsecore/core.h>
|
||||
#include <pulsecore/core-util.h>
|
||||
#include <pulsecore/macro.h>
|
||||
#include <pulsecore/dbus-shared.h>
|
||||
#include <pulsecore/atomic.h>
|
||||
|
||||
typedef struct pa_droid_keepalive pa_droid_keepalive;
|
||||
|
||||
pa_droid_keepalive* pa_droid_keepalive_new(pa_core *c);
|
||||
void pa_droid_keepalive_free(pa_droid_keepalive *k);
|
||||
|
||||
void pa_droid_keepalive_start(pa_droid_keepalive *k);
|
||||
void pa_droid_keepalive_stop(pa_droid_keepalive *k);
|
||||
#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>
|
||||
*
|
||||
|
|
@ -55,7 +55,7 @@ CONVERT_FUNC(format);
|
|||
CONVERT_FUNC(output_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) {
|
||||
pa_assert(list);
|
||||
|
|
@ -88,18 +88,7 @@ static char *list_string(struct string_conversion *list, uint32_t flags) {
|
|||
char *str = NULL;
|
||||
char *tmp;
|
||||
|
||||
#if AUDIO_API_VERSION_MAJ >= 2
|
||||
if (flags & AUDIO_DEVICE_BIT_IN)
|
||||
flags &= ~AUDIO_DEVICE_BIT_IN;
|
||||
#endif
|
||||
|
||||
for (unsigned int i = 0; list[i].str; i++) {
|
||||
#if AUDIO_API_VERSION_MAJ >= 2
|
||||
if (list[i].value & AUDIO_DEVICE_BIT_IN) {
|
||||
if (popcount(list[i].value & ~AUDIO_DEVICE_BIT_IN) != 1)
|
||||
continue;
|
||||
} else
|
||||
#endif
|
||||
if (popcount(list[i].value) != 1)
|
||||
continue;
|
||||
|
||||
|
|
@ -117,6 +106,68 @@ static char *list_string(struct string_conversion *list, uint32_t flags) {
|
|||
return str;
|
||||
}
|
||||
|
||||
/* Generic conversion */
|
||||
bool pa_string_convert_num_to_str(pa_conversion_string_t type, uint32_t value, const char **to_str) {
|
||||
switch (type) {
|
||||
case CONV_STRING_FORMAT:
|
||||
return string_convert_num_to_str(string_conversion_table_format, value, to_str);
|
||||
|
||||
case CONV_STRING_OUTPUT_CHANNELS:
|
||||
return string_convert_num_to_str(string_conversion_table_output_channels, value, to_str);
|
||||
|
||||
case CONV_STRING_INPUT_CHANNELS:
|
||||
return string_convert_num_to_str(string_conversion_table_input_channels, value, to_str);
|
||||
|
||||
case CONV_STRING_OUTPUT_DEVICE:
|
||||
return string_convert_num_to_str(string_conversion_table_output_device, value, to_str);
|
||||
|
||||
case CONV_STRING_INPUT_DEVICE:
|
||||
return string_convert_num_to_str(string_conversion_table_input_device, value, to_str);
|
||||
|
||||
case CONV_STRING_OUTPUT_FLAG:
|
||||
return string_convert_num_to_str(string_conversion_table_output_flag, value, to_str);
|
||||
|
||||
case CONV_STRING_INPUT_FLAG:
|
||||
return string_convert_num_to_str(string_conversion_table_input_flag, value, to_str);
|
||||
|
||||
case CONV_STRING_AUDIO_SOURCE_FANCY:
|
||||
return string_convert_num_to_str(string_conversion_table_audio_source_fancy, value, to_str);
|
||||
}
|
||||
|
||||
pa_assert_not_reached();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool pa_string_convert_str_to_num(pa_conversion_string_t type, const char *str, uint32_t *to_value) {
|
||||
switch (type) {
|
||||
case CONV_STRING_FORMAT:
|
||||
return string_convert_str_to_num(string_conversion_table_format, str, to_value);
|
||||
|
||||
case CONV_STRING_OUTPUT_CHANNELS:
|
||||
return string_convert_str_to_num(string_conversion_table_output_channels, str, to_value);
|
||||
|
||||
case CONV_STRING_INPUT_CHANNELS:
|
||||
return string_convert_str_to_num(string_conversion_table_input_channels, str, to_value);
|
||||
|
||||
case CONV_STRING_OUTPUT_DEVICE:
|
||||
return string_convert_str_to_num(string_conversion_table_output_device, str, to_value);
|
||||
|
||||
case CONV_STRING_INPUT_DEVICE:
|
||||
return string_convert_str_to_num(string_conversion_table_input_device, str, to_value);
|
||||
|
||||
case CONV_STRING_OUTPUT_FLAG:
|
||||
return string_convert_str_to_num(string_conversion_table_output_flag, str, to_value);
|
||||
|
||||
case CONV_STRING_INPUT_FLAG:
|
||||
return string_convert_str_to_num(string_conversion_table_input_flag, str, to_value);
|
||||
|
||||
case CONV_STRING_AUDIO_SOURCE_FANCY:
|
||||
return string_convert_str_to_num(string_conversion_table_audio_source_fancy, str, to_value);
|
||||
}
|
||||
|
||||
pa_assert_not_reached();
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Output device */
|
||||
bool pa_string_convert_output_device_num_to_str(audio_devices_t value, const char **to_str) {
|
||||
|
|
@ -127,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);
|
||||
}
|
||||
|
||||
char *pa_list_string_output_device(audio_devices_t devices) {
|
||||
return list_string(string_conversion_table_output_device, devices);
|
||||
}
|
||||
|
||||
/* Input device */
|
||||
bool pa_string_convert_input_device_num_to_str(audio_devices_t value, const char **to_str) {
|
||||
return string_convert_num_to_str(string_conversion_table_input_device, (uint32_t) value, to_str);
|
||||
|
|
@ -140,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);
|
||||
}
|
||||
|
||||
char *pa_list_string_input_device(audio_devices_t devices) {
|
||||
return list_string(string_conversion_table_input_device, devices);
|
||||
}
|
||||
|
||||
/* Flags */
|
||||
bool pa_string_convert_flag_num_to_str(audio_output_flags_t value, const char **to_str) {
|
||||
return string_convert_num_to_str(string_conversion_table_output_flag, (uint32_t) value, to_str);
|
||||
|
|
@ -159,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)
|
||||
{
|
||||
#if AUDIO_API_VERSION_MAJ >= 2
|
||||
input_device &= ~AUDIO_DEVICE_BIT_IN;
|
||||
#endif
|
||||
|
||||
/* Note converting HAL values to different HAL values! */
|
||||
for (unsigned int i = 0; i < sizeof(conversion_table_default_audio_source) / (sizeof(uint32_t) * 2); i++) {
|
||||
if (conversion_table_default_audio_source[i][0] & input_device) {
|
||||
if (conversion_table_default_audio_source[i][0] == input_device) {
|
||||
*default_source = conversion_table_default_audio_source[i][1];
|
||||
return true;
|
||||
}
|
||||
|
|
@ -182,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);
|
||||
}
|
||||
|
||||
bool pa_droid_audio_source_name(audio_source_t value, const char **to_str) {
|
||||
return string_convert_num_to_str(string_conversion_table_audio_source_fancy, (uint32_t) value, to_str);
|
||||
}
|
||||
|
||||
static int parse_list(const struct string_conversion *table,
|
||||
const char *separator,
|
||||
const char *str,
|
||||
|
|
@ -252,6 +287,10 @@ int pa_conversion_parse_list(pa_conversion_string_t type, const char *separator,
|
|||
|
||||
case CONV_STRING_INPUT_FLAG:
|
||||
return parse_list(string_conversion_table_input_flag, separator, str, dst, unknown_entries);
|
||||
|
||||
/* Not handled in this context */
|
||||
case CONV_STRING_AUDIO_SOURCE_FANCY:
|
||||
return 0;
|
||||
}
|
||||
|
||||
pa_assert_not_reached();
|
||||
|
|
@ -259,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,
|
||||
const char *str, bool legacy,
|
||||
const char *str,
|
||||
uint32_t sampling_rates[AUDIO_MAX_SAMPLING_RATES]) {
|
||||
pa_assert(fn);
|
||||
pa_assert(str);
|
||||
|
|
@ -268,16 +307,14 @@ bool pa_conversion_parse_sampling_rates(const char *fn, const unsigned ln,
|
|||
const char *state = NULL;
|
||||
|
||||
uint32_t pos = 0;
|
||||
while ((entry = pa_split(str, value_separator(legacy), &state))) {
|
||||
while ((entry = pa_split(str, VALUE_SEPARATOR, &state))) {
|
||||
int32_t val;
|
||||
|
||||
#if AUDIO_API_VERSION_MAJ >= 3
|
||||
if (pos == 0 && pa_streq(entry, "dynamic")) {
|
||||
sampling_rates[pos++] = (uint32_t) -1;
|
||||
pa_xfree(entry);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (pos == AUDIO_MAX_SAMPLING_RATES) {
|
||||
pa_log("[%s:%u] Too many sample rate entries (> %d)", fn, ln, AUDIO_MAX_SAMPLING_RATES);
|
||||
|
|
@ -327,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,
|
||||
const char *str, bool legacy,
|
||||
const char *str,
|
||||
audio_format_t *formats) {
|
||||
int count;
|
||||
char *unknown = NULL;
|
||||
|
|
@ -336,18 +373,13 @@ bool pa_conversion_parse_formats(const char *fn, const unsigned ln,
|
|||
pa_assert(str);
|
||||
pa_assert(formats);
|
||||
|
||||
#if AUDIO_API_VERSION_MAJ >= 3
|
||||
/* Needs to be probed later */
|
||||
if (pa_streq(str, "dynamic")) {
|
||||
*formats = 0;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
count = pa_conversion_parse_list(CONV_STRING_FORMAT, value_separator(legacy), str, formats, &unknown);
|
||||
|
||||
if (legacy)
|
||||
return check_and_log(fn, ln, "formats", count, str, unknown, false);
|
||||
count = pa_conversion_parse_list(CONV_STRING_FORMAT, VALUE_SEPARATOR, str, formats, &unknown);
|
||||
|
||||
/* As the new XML configuration lists formats as one per profile, unknown
|
||||
* formats will cause the parser to quit. As a workaround for non-legacy
|
||||
|
|
@ -356,44 +388,70 @@ bool pa_conversion_parse_formats(const char *fn, const unsigned ln,
|
|||
return count > 0;
|
||||
}
|
||||
|
||||
static bool parse_channels(const char *fn, const unsigned ln,
|
||||
const char *str, bool in_output,
|
||||
bool legacy, audio_channel_mask_t *channels) {
|
||||
int count;
|
||||
static int parse_channels(const char *fn, const unsigned ln,
|
||||
const char *str, bool in_output,
|
||||
audio_channel_mask_t channel_masks[AUDIO_MAX_CHANNEL_MASKS]) {
|
||||
bool success;
|
||||
int count = 0;
|
||||
char *unknown = NULL;
|
||||
char *entry;
|
||||
const char *state = NULL;
|
||||
|
||||
pa_assert(fn);
|
||||
pa_assert(str);
|
||||
pa_assert(channels);
|
||||
|
||||
/* Needs to be probed later */
|
||||
if (pa_streq(str, "dynamic")) {
|
||||
*channels = 0;
|
||||
return true;
|
||||
channel_masks[0] = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
count = pa_conversion_parse_list(in_output ? CONV_STRING_OUTPUT_CHANNELS : CONV_STRING_INPUT_CHANNELS,
|
||||
value_separator(legacy), str, channels, &unknown);
|
||||
while ((entry = pa_split(str, VALUE_SEPARATOR, &state))) {
|
||||
uint32_t val;
|
||||
|
||||
return check_and_log(fn, ln, in_output ? "output channel_masks" : "input channel_masks",
|
||||
count, str, unknown, false);
|
||||
if (count == AUDIO_MAX_CHANNEL_MASKS) {
|
||||
pa_log("[%s:%u] Too many channel mask entries (> %d)", fn, ln, AUDIO_MAX_CHANNEL_MASKS);
|
||||
pa_xfree(entry);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!string_convert_str_to_num(in_output ? string_conversion_table_output_channels
|
||||
: string_conversion_table_input_channels,
|
||||
entry,
|
||||
&val)) {
|
||||
pa_log_debug("[%s:%u] Ignore unknown channel mask value %s", fn, ln, entry);
|
||||
pa_xfree(entry);
|
||||
continue;
|
||||
}
|
||||
|
||||
channel_masks[count++] = val;
|
||||
|
||||
pa_xfree(entry);
|
||||
}
|
||||
|
||||
channel_masks[count] = 0;
|
||||
|
||||
/* Avoid aborting parsing when no supported channel is found */
|
||||
success = check_and_log(fn, ln, in_output ? "output channel_masks" : "input channel_masks",
|
||||
count == 0 ? 1 : count, str, unknown, false);
|
||||
return success ? count : -1;
|
||||
}
|
||||
|
||||
bool pa_conversion_parse_output_channels(const char *fn, const unsigned ln,
|
||||
const char *str, bool legacy,
|
||||
audio_channel_mask_t *channels) {
|
||||
return parse_channels(fn, ln, str, true, legacy, channels);
|
||||
int pa_conversion_parse_output_channels(const char *fn, const unsigned ln,
|
||||
const char *str,
|
||||
audio_channel_mask_t channel_masks[AUDIO_MAX_CHANNEL_MASKS]) {
|
||||
return parse_channels(fn, ln, str, true, channel_masks);
|
||||
}
|
||||
|
||||
bool pa_conversion_parse_input_channels(const char *fn, const unsigned ln,
|
||||
const char *str, bool legacy,
|
||||
audio_channel_mask_t *channels) {
|
||||
return parse_channels(fn, ln, str, false, legacy, channels);
|
||||
int pa_conversion_parse_input_channels(const char *fn, const unsigned ln,
|
||||
const char *str,
|
||||
audio_channel_mask_t channel_masks[AUDIO_MAX_CHANNEL_MASKS]) {
|
||||
return parse_channels(fn, ln, str, false, channel_masks);
|
||||
}
|
||||
|
||||
static bool parse_devices(const char *fn, const unsigned ln,
|
||||
const char *str, bool in_output,
|
||||
bool legacy, bool must_recognize_all,
|
||||
bool must_recognize_all,
|
||||
audio_devices_t *devices) {
|
||||
int count;
|
||||
char *unknown = NULL;
|
||||
|
|
@ -403,11 +461,7 @@ static bool parse_devices(const char *fn, const unsigned ln,
|
|||
pa_assert(devices);
|
||||
|
||||
count = pa_conversion_parse_list(in_output ? CONV_STRING_OUTPUT_DEVICE : CONV_STRING_INPUT_DEVICE,
|
||||
value_separator(legacy), str, devices, &unknown);
|
||||
|
||||
if (legacy)
|
||||
return check_and_log(fn, ln, in_output ? "output devices" : "input devices",
|
||||
count, str, unknown, must_recognize_all);
|
||||
VALUE_SEPARATOR, str, devices, &unknown);
|
||||
|
||||
/* As the new XML configuration lists devices as one per devicePort, unknown
|
||||
* devices will cause the parser to quit. As a workaround for non-legacy
|
||||
|
|
@ -418,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,
|
||||
char *str, bool legacy, bool must_recognize_all,
|
||||
char *str, bool must_recognize_all,
|
||||
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,
|
||||
char *str, bool legacy, bool must_recognize_all,
|
||||
char *str, bool must_recognize_all,
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
*
|
||||
|
|
@ -26,6 +26,7 @@
|
|||
#include "droid/version.h"
|
||||
#include "droid/droid-config.h"
|
||||
#include "droid/sllist.h"
|
||||
#include "config-parser-xml.h"
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
|
|
@ -36,48 +37,28 @@
|
|||
#include <valgrind/memcheck.h>
|
||||
#endif
|
||||
|
||||
#include <pulse/rtclock.h>
|
||||
#include <pulse/timeval.h>
|
||||
#include <pulse/volume.h>
|
||||
#include <pulse/xmalloc.h>
|
||||
|
||||
#include <pulsecore/core.h>
|
||||
#include <pulsecore/core-error.h>
|
||||
#include <pulsecore/i18n.h>
|
||||
#include <pulsecore/module.h>
|
||||
#include <pulsecore/memchunk.h>
|
||||
#include <pulsecore/sink.h>
|
||||
#include <pulsecore/modargs.h>
|
||||
#include <pulsecore/core-rtclock.h>
|
||||
#include <pulsecore/core-util.h>
|
||||
#include <pulsecore/sample-util.h>
|
||||
#include <pulsecore/log.h>
|
||||
#include <pulsecore/macro.h>
|
||||
#include <pulsecore/thread.h>
|
||||
#include <pulsecore/thread-mq.h>
|
||||
#include <pulsecore/rtpoll.h>
|
||||
#include <pulsecore/time-smoother.h>
|
||||
#include <pulsecore/refcnt.h>
|
||||
#include <pulsecore/shared.h>
|
||||
#include <pulsecore/mutex.h>
|
||||
#include <pulsecore/strlist.h>
|
||||
#include <pulsecore/atomic.h>
|
||||
#include <pulsecore/modargs.h>
|
||||
|
||||
#include <hardware/audio.h>
|
||||
#include <hardware_legacy/audio_policy_conf.h>
|
||||
|
||||
#define VENDOR_AUDIO_POLICY_CONFIG_XML_FILE "/vendor/etc/audio_policy_configuration.xml"
|
||||
#define SYSTEM_AUDIO_POLICY_CONFIG_XML_FILE "/system/etc/audio_policy_configuration.xml"
|
||||
#define ODM_AUDIO_POLICY_CONFIG_XML_FILE "/odm/etc/audio_policy_configuration.xml"
|
||||
#define VENDOR_AUDIO_AUDIO_POLICY_CONFIG_XML_FILE "/vendor/etc/audio/audio_policy_configuration.xml"
|
||||
#define VENDOR_AUDIO_POLICY_CONFIG_XML_FILE "/vendor/etc/audio_policy_configuration.xml"
|
||||
#define SYSTEM_AUDIO_POLICY_CONFIG_XML_FILE "/system/etc/audio_policy_configuration.xml"
|
||||
|
||||
|
||||
pa_droid_config_audio *pa_droid_config_load(pa_modargs *ma) {
|
||||
pa_droid_config_audio *config = NULL;
|
||||
dm_config_device *dm_config_load(pa_modargs *ma) {
|
||||
dm_config_device *config = NULL;
|
||||
const char *manual_config;
|
||||
const char *config_location[] = {
|
||||
ODM_AUDIO_POLICY_CONFIG_XML_FILE,
|
||||
VENDOR_AUDIO_AUDIO_POLICY_CONFIG_XML_FILE,
|
||||
VENDOR_AUDIO_POLICY_CONFIG_XML_FILE,
|
||||
AUDIO_POLICY_VENDOR_CONFIG_FILE,
|
||||
SYSTEM_AUDIO_POLICY_CONFIG_XML_FILE,
|
||||
AUDIO_POLICY_CONFIG_FILE,
|
||||
NULL};
|
||||
|
||||
pa_assert(ma);
|
||||
|
|
@ -102,92 +83,210 @@ pa_droid_config_audio *pa_droid_config_load(pa_modargs *ma) {
|
|||
return config;
|
||||
}
|
||||
|
||||
pa_droid_config_audio *pa_droid_config_dup(const pa_droid_config_audio *config) {
|
||||
pa_droid_config_audio *config_copy;
|
||||
pa_droid_config_hw_module *module, *module_copy;
|
||||
pa_droid_config_device *device, *device_copy;
|
||||
static dm_config_profile *config_profile_dup(const dm_config_profile *profile) {
|
||||
dm_config_profile *copy = pa_xnew0(dm_config_profile, 1);
|
||||
|
||||
copy->name = pa_xstrdup(profile->name);
|
||||
copy->format = profile->format;
|
||||
memcpy(copy->sampling_rates,
|
||||
profile->sampling_rates,
|
||||
sizeof(profile->sampling_rates));
|
||||
memcpy(copy->channel_masks,
|
||||
profile->channel_masks,
|
||||
sizeof(profile->channel_masks));
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
static dm_config_port *config_port_dup(const dm_config_port *port, dm_config_module *module) {
|
||||
dm_config_port *copy = pa_xnew0(dm_config_port, 1);
|
||||
const dm_list_entry *i;
|
||||
|
||||
copy->module = module;
|
||||
copy->port_type = port->port_type;
|
||||
copy->name = pa_xstrdup(port->name);
|
||||
copy->role = port->role;
|
||||
copy->profiles = dm_list_new();
|
||||
|
||||
DM_LIST_FOREACH(i, port->profiles)
|
||||
dm_list_push_back(copy->profiles, config_profile_dup(i->data));
|
||||
|
||||
if (port->port_type == DM_CONFIG_TYPE_DEVICE_PORT) {
|
||||
copy->type = port->type;
|
||||
copy->address = pa_xstrdup(port->address);
|
||||
}
|
||||
|
||||
if (port->port_type == DM_CONFIG_TYPE_MIX_PORT) {
|
||||
copy->flags = port->flags;
|
||||
copy->max_open_count = port->max_open_count;
|
||||
copy->max_active_count = port->max_active_count;
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
static dm_config_route *config_route_dup(const dm_config_route *route, dm_list *ports) {
|
||||
dm_config_route *copy = pa_xnew0(dm_config_route, 1);
|
||||
dm_config_port *port_copy, *port;
|
||||
void *state, *state2;
|
||||
|
||||
copy->type = route->type;
|
||||
copy->sources = dm_list_new();
|
||||
|
||||
DM_LIST_FOREACH_DATA(port, route->sources, state) {
|
||||
DM_LIST_FOREACH_DATA(port_copy, ports, state2) {
|
||||
if (dm_config_port_equal(port, port_copy)) {
|
||||
dm_list_push_back(copy->sources, port_copy);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DM_LIST_FOREACH_DATA(port_copy, ports, state) {
|
||||
if (dm_config_port_equal(port_copy, route->sink)) {
|
||||
copy->sink = port_copy;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
static dm_config_module *config_module_dup(const dm_config_module *module) {
|
||||
dm_config_module *copy = pa_xnew0(dm_config_module, 1);
|
||||
dm_config_port *device_port, *attached_device, *mix_port;
|
||||
dm_config_route *route;
|
||||
void *state, *state2;
|
||||
|
||||
copy = pa_xnew0(dm_config_module, 1);
|
||||
copy->name = pa_xstrdup(module->name);
|
||||
copy->version_major = module->version_major;
|
||||
copy->version_minor = module->version_minor;
|
||||
copy->attached_devices = dm_list_new();
|
||||
copy->default_output_device = NULL;
|
||||
copy->mix_ports = dm_list_new();
|
||||
copy->device_ports = dm_list_new();
|
||||
copy->ports = dm_list_new();
|
||||
copy->routes = dm_list_new();
|
||||
|
||||
DM_LIST_FOREACH_DATA(device_port, module->device_ports, state) {
|
||||
dm_config_port *device_port_copy = config_port_dup(device_port, copy);
|
||||
dm_list_push_back(copy->device_ports, device_port_copy);
|
||||
dm_list_push_back(copy->ports, device_port_copy);
|
||||
if (module->default_output_device == device_port)
|
||||
copy->default_output_device = device_port_copy;
|
||||
DM_LIST_FOREACH_DATA(attached_device, module->attached_devices, state2) {
|
||||
if (attached_device == device_port) {
|
||||
dm_list_push_back(copy->attached_devices, device_port_copy);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DM_LIST_FOREACH_DATA(mix_port, module->mix_ports, state) {
|
||||
dm_config_port *mix_port_copy = config_port_dup(mix_port, copy);
|
||||
dm_list_push_back(copy->mix_ports, mix_port_copy);
|
||||
dm_list_push_back(copy->ports, mix_port_copy);
|
||||
}
|
||||
|
||||
DM_LIST_FOREACH_DATA(route, module->routes, state)
|
||||
dm_list_push_back(copy->routes, config_route_dup(route, copy->ports));
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
dm_config_device *dm_config_dup(const dm_config_device *config) {
|
||||
dm_config_device *copy;
|
||||
dm_config_module *module;
|
||||
void *state;
|
||||
|
||||
pa_assert(config);
|
||||
|
||||
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)
|
||||
config_copy->global_config = pa_xmemdup(config->global_config, sizeof(*config->global_config));
|
||||
if (config->global_config) {
|
||||
dm_config_global *global, *global_copy;
|
||||
|
||||
SLLIST_FOREACH(module, config->hw_modules) {
|
||||
module_copy = pa_droid_config_hw_module_new(config_copy, module->name);
|
||||
if (module->global_config)
|
||||
module_copy->global_config = pa_xmemdup(module->global_config, sizeof(*module->global_config));
|
||||
|
||||
SLLIST_FOREACH(device, module->outputs) {
|
||||
device_copy = pa_xmemdup(device, sizeof(*device));
|
||||
device_copy->module = module_copy;
|
||||
device_copy->name = pa_xstrdup(device->name);
|
||||
SLLIST_APPEND(pa_droid_config_device, module_copy->outputs, device_copy);
|
||||
DM_LIST_FOREACH_DATA(global, config->global_config, state) {
|
||||
global_copy = pa_xnew0(dm_config_global, 1);
|
||||
global_copy->key = pa_xstrdup(global->key);
|
||||
global_copy->value = pa_xstrdup(global->value);
|
||||
dm_list_push_back(copy->global_config, global_copy);
|
||||
}
|
||||
|
||||
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) {
|
||||
const char *suffix;
|
||||
|
||||
pa_assert(filename);
|
||||
|
||||
if ((suffix = rindex(filename, '.'))) {
|
||||
if (strlen(suffix) == 4 && pa_streq(suffix, ".xml"))
|
||||
return pa_parse_droid_audio_config_xml(filename);
|
||||
else if (strlen(suffix) == 5 && pa_streq(suffix, ".conf"))
|
||||
return pa_parse_droid_audio_config_legacy(filename);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
dm_config_device *pa_parse_droid_audio_config(const char *filename) {
|
||||
return pa_parse_droid_audio_config_xml(filename);
|
||||
}
|
||||
|
||||
void pa_droid_config_free(pa_droid_config_audio *config) {
|
||||
pa_droid_config_hw_module *module;
|
||||
pa_droid_config_device *device;
|
||||
static void config_global_free(void *data) {
|
||||
dm_config_global *global = data;
|
||||
|
||||
pa_xfree(global->key);
|
||||
pa_xfree(global->value);
|
||||
pa_xfree(global);
|
||||
}
|
||||
|
||||
static void config_profile_free(void *data) {
|
||||
dm_config_profile *profile = data;
|
||||
|
||||
pa_xfree(profile->name);
|
||||
pa_xfree(profile);
|
||||
}
|
||||
|
||||
static void config_port_free(void *data) {
|
||||
dm_config_port *port = data;
|
||||
|
||||
pa_xfree(port->name);
|
||||
pa_xfree(port->address);
|
||||
dm_list_free(port->profiles, config_profile_free);
|
||||
pa_xfree(port);
|
||||
}
|
||||
|
||||
static void config_route_free(void *data) {
|
||||
dm_config_route *route = data;
|
||||
|
||||
dm_list_free(route->sources, NULL);
|
||||
pa_xfree(route);
|
||||
}
|
||||
|
||||
static void config_module_free(void *data) {
|
||||
dm_config_module *module = data;
|
||||
|
||||
pa_xfree(module->name);
|
||||
dm_list_free(module->attached_devices, NULL);
|
||||
dm_list_free(module->ports, config_port_free);
|
||||
dm_list_free(module->device_ports, NULL);
|
||||
dm_list_free(module->mix_ports, NULL);
|
||||
dm_list_free(module->routes, config_route_free);
|
||||
pa_xfree(module);
|
||||
}
|
||||
|
||||
void dm_config_free(dm_config_device *config) {
|
||||
if (!config)
|
||||
return;
|
||||
|
||||
while (config->hw_modules) {
|
||||
SLLIST_STEAL_FIRST(module, config->hw_modules);
|
||||
|
||||
while (module->outputs) {
|
||||
SLLIST_STEAL_FIRST(device, module->outputs);
|
||||
pa_droid_config_device_free(device);
|
||||
}
|
||||
|
||||
while (module->inputs) {
|
||||
SLLIST_STEAL_FIRST(device, module->inputs);
|
||||
pa_droid_config_device_free(device);
|
||||
}
|
||||
|
||||
pa_droid_config_hw_module_free(module);
|
||||
}
|
||||
|
||||
pa_xfree(config->global_config);
|
||||
dm_list_free(config->global_config, config_global_free);
|
||||
dm_list_free(config->modules, config_module_free);
|
||||
pa_xfree(config);
|
||||
}
|
||||
|
||||
const pa_droid_config_hw_module *pa_droid_config_find_module(const pa_droid_config_audio *config, const char* module_id) {
|
||||
pa_droid_config_hw_module *module;
|
||||
dm_config_module *dm_config_find_module(dm_config_device *config, const char* module_id) {
|
||||
dm_config_module *module;
|
||||
void *state;
|
||||
|
||||
pa_assert(config);
|
||||
pa_assert(module_id);
|
||||
|
||||
SLLIST_FOREACH(module, config->hw_modules) {
|
||||
DM_LIST_FOREACH_DATA(module, config->modules, state) {
|
||||
if (pa_streq(module_id, module->name))
|
||||
return module;
|
||||
}
|
||||
|
|
@ -195,49 +294,73 @@ const pa_droid_config_hw_module *pa_droid_config_find_module(const pa_droid_conf
|
|||
return NULL;
|
||||
}
|
||||
|
||||
pa_droid_config_hw_module *pa_droid_config_hw_module_new(const pa_droid_config_audio *config, const char *name) {
|
||||
pa_droid_config_hw_module *hw_module;
|
||||
|
||||
pa_assert(config);
|
||||
pa_assert(name);
|
||||
|
||||
hw_module = pa_xnew0(pa_droid_config_hw_module, 1);
|
||||
hw_module->config = config;
|
||||
hw_module->name = pa_xstrndup(name, AUDIO_HARDWARE_MODULE_ID_MAX_LEN);
|
||||
|
||||
return hw_module;
|
||||
}
|
||||
|
||||
void pa_droid_config_hw_module_free(pa_droid_config_hw_module *hw_module) {
|
||||
if (!hw_module)
|
||||
return;
|
||||
|
||||
pa_xfree(hw_module->name);
|
||||
pa_xfree(hw_module->global_config);
|
||||
pa_xfree(hw_module);
|
||||
}
|
||||
|
||||
pa_droid_config_device *pa_droid_config_device_new(const pa_droid_config_hw_module *module,
|
||||
pa_direction_t direction,
|
||||
const char *name) {
|
||||
pa_droid_config_device *device;
|
||||
dm_config_port *dm_config_find_port(dm_config_module *module, const char* name) {
|
||||
dm_config_port *port;
|
||||
void *state;
|
||||
|
||||
pa_assert(module);
|
||||
pa_assert(direction == PA_DIRECTION_OUTPUT || direction == PA_DIRECTION_INPUT);
|
||||
pa_assert(name);
|
||||
|
||||
device = pa_xnew0(pa_droid_config_device, 1);
|
||||
device->module = module;
|
||||
device->direction = direction;
|
||||
device->name = pa_replace(name, " ", "_");
|
||||
DM_LIST_FOREACH_DATA(port, module->ports, state) {
|
||||
if (pa_streq(name, port->name))
|
||||
return port;
|
||||
}
|
||||
|
||||
return device;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void pa_droid_config_device_free(pa_droid_config_device *device) {
|
||||
if (!device)
|
||||
return;
|
||||
dm_config_port *dm_config_default_output_device(dm_config_module *module) {
|
||||
pa_assert(module);
|
||||
|
||||
pa_xfree(device->name);
|
||||
pa_xfree(device);
|
||||
if (module->default_output_device)
|
||||
return module->default_output_device;
|
||||
else {
|
||||
pa_log("Module %s doesn't have default output device.", module->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
char *dm_config_escape_string(const char *string) {
|
||||
if (!string)
|
||||
return NULL;
|
||||
|
||||
/* Just replace whitespace with underscores for now. */
|
||||
|
||||
return pa_replace(string, " ", "_");
|
||||
}
|
||||
|
||||
dm_config_port *dm_config_find_device_port(dm_config_port *port, audio_devices_t device) {
|
||||
dm_config_port *device_port;
|
||||
void *state;
|
||||
|
||||
pa_assert(port);
|
||||
|
||||
DM_LIST_FOREACH_DATA(device_port, port->module->device_ports, state) {
|
||||
if (device_port->type == device)
|
||||
return device_port;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool dm_config_port_equal(const dm_config_port *a, const dm_config_port *b) {
|
||||
if ((!a && b) || (a && !b))
|
||||
return false;
|
||||
|
||||
else if (!a && !b)
|
||||
return true;
|
||||
|
||||
return (pa_streq(a->name, b->name) && a->type == b->type);
|
||||
}
|
||||
|
||||
dm_config_port *dm_config_find_mix_port(dm_config_module *module, const char *name) {
|
||||
dm_config_port *mix_port = NULL;
|
||||
void *state;
|
||||
|
||||
DM_LIST_FOREACH_DATA(mix_port, module->mix_ports, state) {
|
||||
if (pa_streq(mix_port->name, name))
|
||||
return mix_port;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
*
|
||||
|
|
@ -28,7 +28,6 @@
|
|||
#endif
|
||||
|
||||
#include <hardware/audio.h>
|
||||
#include <hardware_legacy/audio_policy_conf.h>
|
||||
|
||||
#include <pulse/channelmap.h>
|
||||
|
||||
|
|
@ -90,8 +89,9 @@ uint32_t conversion_table_input_channel[][2] = {
|
|||
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 }
|
||||
{ PA_SAMPLE_S24_32LE, AUDIO_FORMAT_PCM_8_24_BIT },
|
||||
{ PA_SAMPLE_S24LE, AUDIO_FORMAT_PCM_24_BIT_PACKED },
|
||||
{ PA_SAMPLE_S32LE, AUDIO_FORMAT_PCM_32_BIT }
|
||||
};
|
||||
|
||||
uint32_t conversion_table_default_audio_source[][2] = {
|
||||
|
|
@ -102,18 +102,33 @@ uint32_t conversion_table_default_audio_source[][2] = {
|
|||
{ AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_SOURCE_MIC },
|
||||
{ AUDIO_DEVICE_IN_AUX_DIGITAL, AUDIO_SOURCE_MIC },
|
||||
{ AUDIO_DEVICE_IN_VOICE_CALL, AUDIO_SOURCE_VOICE_CALL },
|
||||
{ AUDIO_DEVICE_IN_TELEPHONY_RX, AUDIO_SOURCE_VOICE_CALL },
|
||||
{ AUDIO_DEVICE_IN_BACK_MIC, AUDIO_SOURCE_MIC },
|
||||
{ AUDIO_DEVICE_IN_REMOTE_SUBMIX, AUDIO_SOURCE_REMOTE_SUBMIX },
|
||||
{ AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET, AUDIO_SOURCE_MIC },
|
||||
{ AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET, AUDIO_SOURCE_MIC },
|
||||
{ AUDIO_DEVICE_IN_USB_ACCESSORY, AUDIO_SOURCE_MIC },
|
||||
{ AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_SOURCE_MIC },
|
||||
{ AUDIO_DEVICE_IN_FM_TUNER, AUDIO_SOURCE_FM_TUNER },
|
||||
{ AUDIO_DEVICE_IN_TV_TUNER, AUDIO_SOURCE_MIC },
|
||||
{ AUDIO_DEVICE_IN_LINE, AUDIO_SOURCE_MIC },
|
||||
{ AUDIO_DEVICE_IN_SPDIF, AUDIO_SOURCE_MIC },
|
||||
{ AUDIO_DEVICE_IN_BLUETOOTH_A2DP, AUDIO_SOURCE_MIC },
|
||||
{ AUDIO_DEVICE_IN_LOOPBACK, AUDIO_SOURCE_MIC },
|
||||
{ AUDIO_DEVICE_IN_IP, AUDIO_SOURCE_MIC },
|
||||
{ AUDIO_DEVICE_IN_BUS, AUDIO_SOURCE_MIC },
|
||||
{ AUDIO_DEVICE_IN_PROXY, AUDIO_SOURCE_MIC },
|
||||
{ AUDIO_DEVICE_IN_USB_HEADSET, AUDIO_SOURCE_MIC },
|
||||
{ AUDIO_DEVICE_IN_BLUETOOTH_BLE, AUDIO_SOURCE_MIC },
|
||||
{ AUDIO_DEVICE_IN_HDMI_ARC, AUDIO_SOURCE_MIC },
|
||||
{ AUDIO_DEVICE_IN_ECHO_REFERENCE, AUDIO_SOURCE_MIC },
|
||||
|
||||
#if defined(HAVE_ENUM_AUDIO_DEVICE_IN_FM_RX) && defined(HAVE_ENUM_AUDIO_SOURCE_FM_RX)
|
||||
{ AUDIO_DEVICE_IN_FM_RX, AUDIO_SOURCE_FM_RX },
|
||||
#endif
|
||||
#if defined(HAVE_ENUM_AUDIO_DEVICE_IN_FM_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)
|
||||
{ AUDIO_DEVICE_IN_FM_RX_A2DP, AUDIO_SOURCE_FM_RX_A2DP },
|
||||
#endif
|
||||
{ AUDIO_DEVICE_IN_ALL, AUDIO_SOURCE_DEFAULT }
|
||||
};
|
||||
|
||||
/* Output devices */
|
||||
|
|
@ -136,56 +151,30 @@ struct string_conversion string_conversion_table_output_device[] = {
|
|||
STRING_ENTRY( AUDIO_DEVICE_OUT_USB_ACCESSORY ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_USB_DEVICE ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_REMOTE_SUBMIX ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_TELEPHONY_TX ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_LINE ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_HDMI_ARC ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_SPDIF ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_FM ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_AUX_LINE ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_SPEAKER_SAFE ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_IP ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_BUS ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_PROXY ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_USB_HEADSET ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_HEARING_AID ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_ECHO_CANCELLER ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_DEFAULT ),
|
||||
|
||||
/* Devices which may or may not be defined for all devices,
|
||||
* update configure.ac CC_CHECK_DROID_ENUM list if you encounter new ones. */
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_OUT_HDMI
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_HDMI ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_OUT_HDMI_ARC
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_HDMI_ARC ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_OUT_TELEPHONY_TX
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_TELEPHONY_TX ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_OUT_LINE
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_LINE ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_OUT_SPDIF
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_SPDIF ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_OUT_AUX_LINE
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_AUX_LINE ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_OUT_SPEAKER_SAFE
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_SPEAKER_SAFE ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_OUT_FM
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_FM ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_OUT_FM_TX
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_FM_TX ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_OUT_ANC_HEADSET
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_ANC_HEADSET ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_OUT_ANC_HEADPHONE
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_ANC_HEADPHONE ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_OUT_PROXY
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_PROXY ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_OUT_IP
|
||||
STRING_ENTRY( AUDIO_DEVICE_OUT_IP ),
|
||||
#endif
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
/* Combination entries consisting of multiple devices defined above.
|
||||
* These don't require counterpart in string_conversion_table_output_device_fancy. */
|
||||
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 ),
|
||||
struct string_conversion string_conversion_table_audio_mode_fancy[] = {
|
||||
{ AUDIO_MODE_NORMAL, "normal" },
|
||||
{ AUDIO_MODE_RINGTONE, "ringtone" },
|
||||
{ AUDIO_MODE_IN_CALL, "in call" },
|
||||
{ AUDIO_MODE_IN_COMMUNICATION, "in communication" },
|
||||
{ AUDIO_MODE_CALL_SCREEN, "call screen" },
|
||||
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
|
@ -193,8 +182,6 @@ struct string_conversion string_conversion_table_output_device[] = {
|
|||
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" },
|
||||
|
|
@ -209,48 +196,20 @@ struct string_conversion string_conversion_table_output_device_fancy[] = {
|
|||
{ AUDIO_DEVICE_OUT_USB_ACCESSORY, "output-usb_accessory" },
|
||||
{ AUDIO_DEVICE_OUT_USB_DEVICE, "output-usb_device" },
|
||||
{ AUDIO_DEVICE_OUT_REMOTE_SUBMIX, "output-remote_submix" },
|
||||
{ AUDIO_DEVICE_OUT_DEFAULT, "output-default" },
|
||||
|
||||
/* Devices which may or may not be defined for all devices, */
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_OUT_HDMI
|
||||
{ AUDIO_DEVICE_OUT_HDMI, "output-hdmi" },
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_OUT_HDMI_ARC
|
||||
{ AUDIO_DEVICE_OUT_HDMI_ARC, "output-hdmi_arc" },
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_OUT_TELEPHONY_TX
|
||||
{ AUDIO_DEVICE_OUT_TELEPHONY_TX, "output-telephony_tx" },
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_OUT_LINE
|
||||
{ AUDIO_DEVICE_OUT_LINE, "output-line" },
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_OUT_SPDIF
|
||||
{ AUDIO_DEVICE_OUT_HDMI_ARC, "output-hdmi_arc" },
|
||||
{ AUDIO_DEVICE_OUT_SPDIF, "output-spdif" },
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_OUT_AUX_LINE
|
||||
{ AUDIO_DEVICE_OUT_AUX_LINE, "output-aux_line" },
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_OUT_SPEAKER_SAFE
|
||||
{ AUDIO_DEVICE_OUT_SPEAKER_SAFE, "output-speaker_safe" },
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_OUT_FM
|
||||
{ AUDIO_DEVICE_OUT_FM, "output-fm" },
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_OUT_FM_TX
|
||||
{ AUDIO_DEVICE_OUT_FM_TX, "output-fm_tx" },
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_OUT_ANC_HEADSET
|
||||
{ AUDIO_DEVICE_OUT_ANC_HEADSET, "output-anc_headset" },
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_OUT_ANC_HEADPHONE
|
||||
{ AUDIO_DEVICE_OUT_ANC_HEADPHONE, "output-anc_headphone" },
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_OUT_PROXY
|
||||
{ AUDIO_DEVICE_OUT_PROXY, "output-proxy" },
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_OUT_IP
|
||||
{ AUDIO_DEVICE_OUT_AUX_LINE, "output-aux_line" },
|
||||
{ AUDIO_DEVICE_OUT_SPEAKER_SAFE, "output-speaker_safe" },
|
||||
{ AUDIO_DEVICE_OUT_IP, "output-ip" },
|
||||
#endif
|
||||
{ AUDIO_DEVICE_OUT_BUS, "output-bus" },
|
||||
{ AUDIO_DEVICE_OUT_PROXY, "output-proxy" },
|
||||
{ AUDIO_DEVICE_OUT_USB_HEADSET, "output-usb_headset" },
|
||||
{ AUDIO_DEVICE_OUT_HEARING_AID, "output-hearing_aid" },
|
||||
{ AUDIO_DEVICE_OUT_ECHO_CANCELLER, "output-echo_canceller" },
|
||||
{ AUDIO_DEVICE_OUT_DEFAULT, "output-default" },
|
||||
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
|
@ -265,65 +224,33 @@ struct string_conversion string_conversion_table_input_device[] = {
|
|||
STRING_ENTRY( AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_WIRED_HEADSET ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_AUX_DIGITAL ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_HDMI ), /* Same as AUDIO_DEVICE_IN_AUX_DIGITAL */
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_VOICE_CALL ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_TELEPHONY_RX ), /* Same as AUDIO_DEVICE_IN_VOICE_CALL */
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_BACK_MIC ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_REMOTE_SUBMIX ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_USB_ACCESSORY ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_USB_DEVICE ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_FM_TUNER ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_TV_TUNER ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_LINE ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_SPDIF ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_BLUETOOTH_A2DP ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_LOOPBACK ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_IP ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_BUS ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_PROXY ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_USB_HEADSET ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_BLUETOOTH_BLE ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_HDMI_ARC ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_ECHO_REFERENCE ),
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_DEFAULT ),
|
||||
|
||||
/* Devices which may or may not be defined for all devices,
|
||||
* update configure.ac CC_CHECK_DROID_ENUM list if you encounter new ones. */
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_IN_HDMI
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_HDMI ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_IN_TELEPHONY_RX
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_TELEPHONY_RX ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_IN_FM_TUNER
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_FM_TUNER ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_IN_TV_TUNER
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_TV_TUNER ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_IN_LINE
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_LINE ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_IN_SPDIF
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_SPDIF ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_IN_BLUETOOTH_A2DP
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_BLUETOOTH_A2DP ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_IN_LOOPBACK
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_LOOPBACK ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_IN_PROXY
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_PROXY ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_IN_FM_RX
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_FM_RX ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_IN_FM_RX_A2DP
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_FM_RX_A2DP ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_IN_IP
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_IP ),
|
||||
#endif
|
||||
|
||||
#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 ),
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_IN_ALL_USB
|
||||
STRING_ENTRY( AUDIO_DEVICE_IN_ALL_USB ),
|
||||
#endif
|
||||
/* Devices which may or may not be defined for all devices. */
|
||||
STRING_ENTRY_IF_AUDIO_DEVICE_IN_FM_RX
|
||||
STRING_ENTRY_IF_AUDIO_DEVICE_IN_FM_RX_A2DP
|
||||
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
|
@ -336,55 +263,31 @@ struct string_conversion string_conversion_table_input_device_fancy[] = {
|
|||
{ AUDIO_DEVICE_IN_WIRED_HEADSET, "input-wired_headset" },
|
||||
{ AUDIO_DEVICE_IN_AUX_DIGITAL, "input-aux_digital" },
|
||||
{ AUDIO_DEVICE_IN_VOICE_CALL, "input-voice_call" },
|
||||
{ AUDIO_DEVICE_IN_TELEPHONY_RX, "input-telephony_rx", },
|
||||
{ AUDIO_DEVICE_IN_BACK_MIC, "input-back_mic" },
|
||||
{ AUDIO_DEVICE_IN_REMOTE_SUBMIX, "input-remote_submix" },
|
||||
{ AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET, "input-analog_dock_headset" },
|
||||
{ AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET, "input-digital_dock_headset" },
|
||||
{ AUDIO_DEVICE_IN_USB_ACCESSORY, "input-usb_accessory" },
|
||||
{ AUDIO_DEVICE_IN_USB_DEVICE, "input-usb_device" },
|
||||
{ AUDIO_DEVICE_IN_FM_TUNER, "input-fm_tuner" },
|
||||
{ AUDIO_DEVICE_IN_TV_TUNER, "input-tv_tuner" },
|
||||
{ AUDIO_DEVICE_IN_LINE, "input-line" },
|
||||
{ AUDIO_DEVICE_IN_SPDIF, "input-spdif" },
|
||||
{ AUDIO_DEVICE_IN_BLUETOOTH_A2DP, "input-bluetooth_a2dp" },
|
||||
{ AUDIO_DEVICE_IN_LOOPBACK, "input-loopback" },
|
||||
{ AUDIO_DEVICE_IN_IP, "input-ip" },
|
||||
{ AUDIO_DEVICE_IN_BUS, "input-bus" },
|
||||
{ AUDIO_DEVICE_IN_PROXY, "input-proxy" },
|
||||
{ AUDIO_DEVICE_IN_USB_HEADSET, "input-usb_headset" },
|
||||
{ AUDIO_DEVICE_IN_BLUETOOTH_BLE, "input-bluetooth_ble" },
|
||||
{ AUDIO_DEVICE_IN_HDMI_ARC, "input-hdmi_arc" },
|
||||
{ AUDIO_DEVICE_IN_ECHO_REFERENCE, "input-echo_reference" },
|
||||
{ AUDIO_DEVICE_IN_DEFAULT, "input-default" },
|
||||
|
||||
/* Devices which may or may not be defined for all devices, */
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_IN_HDMI
|
||||
{ AUDIO_DEVICE_IN_HDMI, "input-hdmi" },
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_IN_TELEPHONY_RX
|
||||
{ AUDIO_DEVICE_IN_TELEPHONY_RX, "input-telephony_rx" },
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_IN_FM_TUNER
|
||||
{ AUDIO_DEVICE_IN_FM_TUNER, "input-fm_tuner" },
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_IN_TV_TUNER
|
||||
{ AUDIO_DEVICE_IN_TV_TUNER, "input-tv_tuner" },
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_IN_LINE
|
||||
{ AUDIO_DEVICE_IN_LINE, "input-line" },
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_IN_SPDIF
|
||||
{ AUDIO_DEVICE_IN_SPDIF, "input-spdif" },
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_IN_BLUETOOTH_A2DP
|
||||
{ AUDIO_DEVICE_IN_BLUETOOTH_A2DP, "input-bluetooth_a2dp" },
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_IN_LOOPBACK
|
||||
{ AUDIO_DEVICE_IN_LOOPBACK, "input-loopback" },
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_IN_PROXY
|
||||
{ AUDIO_DEVICE_IN_PROXY, "input-proxy" },
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_IN_FM_RX
|
||||
{ AUDIO_DEVICE_IN_FM_RX, "input-fm_rx" },
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_IN_FM_RX_A2DP
|
||||
{ AUDIO_DEVICE_IN_FM_RX_A2DP, "input-fm_rx_a2dp" },
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_DEVICE_IN_IP
|
||||
{ AUDIO_DEVICE_IN_IP, "input-ip" },
|
||||
#endif
|
||||
|
||||
#ifdef DROID_AUDIO_HAL_SECONDARY_MIC
|
||||
{ AUDIO_DEVICE_IN_SECONDARY_MIC, "input-secondary_mic" },
|
||||
#endif
|
||||
/* Devices which may or may not be defined for all devices. */
|
||||
FANCY_ENTRY_IF_AUDIO_DEVICE_IN_FM_RX ( "input-fm_rx" )
|
||||
FANCY_ENTRY_IF_AUDIO_DEVICE_IN_FM_RX_A2DP ( "input-fm_rx_a2dp" )
|
||||
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
|
@ -400,17 +303,14 @@ struct string_conversion string_conversion_table_audio_source_fancy[] = {
|
|||
{ AUDIO_SOURCE_VOICE_RECOGNITION, "voice recognition" },
|
||||
{ AUDIO_SOURCE_VOICE_COMMUNICATION, "voice communication" },
|
||||
{ AUDIO_SOURCE_REMOTE_SUBMIX, "remote submix" },
|
||||
{ AUDIO_SOURCE_UNPROCESSED, "unprocessed" },
|
||||
{ AUDIO_SOURCE_VOICE_PERFORMANCE, "voice performance" },
|
||||
|
||||
/* Audio sources which may or may not be defined for all devices, */
|
||||
#ifdef HAVE_ENUM_AUDIO_SOURCE_FM_TUNER
|
||||
{ AUDIO_SOURCE_FM_TUNER, "fm tuner" },
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_SOURCE_FM_RX
|
||||
{ AUDIO_SOURCE_FM_RX, "fm rx" },
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_SOURCE_FM_RX_A2DP
|
||||
{ AUDIO_SOURCE_FM_RX_A2DP, "fm rx a2dp" },
|
||||
#endif
|
||||
/* Audio sources which may or may not be defined for all devices. */
|
||||
FANCY_ENTRY_IF_AUDIO_SOURCE_ECHO_REFERENCE ( "echo reference" )
|
||||
FANCY_ENTRY_IF_AUDIO_SOURCE_FM_TUNER ( "fm tuner" )
|
||||
FANCY_ENTRY_IF_AUDIO_SOURCE_FM_RX ( "fm rx" )
|
||||
FANCY_ENTRY_IF_AUDIO_SOURCE_FM_RX_A2DP ( "fm rx a2dp" )
|
||||
|
||||
{ (uint32_t)-1, NULL }
|
||||
};
|
||||
|
|
@ -422,61 +322,34 @@ struct string_conversion string_conversion_table_output_flag[] = {
|
|||
STRING_ENTRY( AUDIO_OUTPUT_FLAG_PRIMARY ),
|
||||
STRING_ENTRY( AUDIO_OUTPUT_FLAG_FAST ),
|
||||
STRING_ENTRY( AUDIO_OUTPUT_FLAG_DEEP_BUFFER ),
|
||||
|
||||
/* 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. */
|
||||
#ifdef HAVE_ENUM_AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD
|
||||
STRING_ENTRY( AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_OUTPUT_FLAG_NON_BLOCKING
|
||||
STRING_ENTRY( AUDIO_OUTPUT_FLAG_NON_BLOCKING ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_OUTPUT_FLAG_HW_AV_SYNC
|
||||
STRING_ENTRY( AUDIO_OUTPUT_FLAG_HW_AV_SYNC ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_OUTPUT_FLAG_VOIP_RX
|
||||
STRING_ENTRY( AUDIO_OUTPUT_FLAG_VOIP_RX ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_OUTPUT_FLAG_INCALL_MUSIC
|
||||
STRING_ENTRY( AUDIO_OUTPUT_FLAG_INCALL_MUSIC ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH
|
||||
STRING_ENTRY( AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_OUTPUT_FLAG_TTS
|
||||
STRING_ENTRY( AUDIO_OUTPUT_FLAG_TTS ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_OUTPUT_FLAG_RAW
|
||||
STRING_ENTRY( AUDIO_OUTPUT_FLAG_RAW ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_OUTPUT_FLAG_SYNC
|
||||
STRING_ENTRY( AUDIO_OUTPUT_FLAG_SYNC ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO
|
||||
STRING_ENTRY( AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO ),
|
||||
#endif
|
||||
STRING_ENTRY( AUDIO_OUTPUT_FLAG_DIRECT_PCM ),
|
||||
STRING_ENTRY( AUDIO_OUTPUT_FLAG_MMAP_NOIRQ ),
|
||||
STRING_ENTRY( AUDIO_OUTPUT_FLAG_VOIP_RX ),
|
||||
STRING_ENTRY( AUDIO_OUTPUT_FLAG_INCALL_MUSIC ),
|
||||
|
||||
/* Audio output flags which may or may not be defined for all devices. */
|
||||
STRING_ENTRY_IF_AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH
|
||||
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
struct string_conversion string_conversion_table_input_flag[] = {
|
||||
/* 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. */
|
||||
#ifdef HAVE_ENUM_AUDIO_INPUT_FLAG_NONE
|
||||
STRING_ENTRY( AUDIO_INPUT_FLAG_NONE ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_INPUT_FLAG_FAST
|
||||
STRING_ENTRY( AUDIO_INPUT_FLAG_FAST ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_INPUT_FLAG_HW_HOTWORD
|
||||
STRING_ENTRY( AUDIO_INPUT_FLAG_HW_HOTWORD ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_INPUT_FLAG_RAW
|
||||
STRING_ENTRY( AUDIO_INPUT_FLAG_RAW ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_INPUT_FLAG_SYNC
|
||||
STRING_ENTRY( AUDIO_INPUT_FLAG_SYNC ),
|
||||
#endif
|
||||
STRING_ENTRY( AUDIO_INPUT_FLAG_MMAP_NOIRQ ),
|
||||
STRING_ENTRY( AUDIO_INPUT_FLAG_VOIP_TX ),
|
||||
STRING_ENTRY( AUDIO_INPUT_FLAG_HW_AV_SYNC ),
|
||||
STRING_ENTRY( AUDIO_INPUT_FLAG_DIRECT ),
|
||||
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
|
@ -504,18 +377,6 @@ struct string_conversion string_conversion_table_output_channels[] = {
|
|||
STRING_ENTRY( AUDIO_CHANNEL_OUT_MONO ),
|
||||
STRING_ENTRY( AUDIO_CHANNEL_OUT_STEREO ),
|
||||
STRING_ENTRY( AUDIO_CHANNEL_OUT_QUAD ),
|
||||
#ifdef HAVE_ENUM_AUDIO_CHANNEL_OUT_SURROUND
|
||||
STRING_ENTRY( AUDIO_CHANNEL_OUT_SURROUND ),
|
||||
#endif
|
||||
STRING_ENTRY( AUDIO_CHANNEL_OUT_5POINT1 ),
|
||||
#ifdef HAVE_ENUM_AUDIO_CHANNEL_OUT_5POINT1_BACK
|
||||
STRING_ENTRY( AUDIO_CHANNEL_OUT_5POINT1_BACK ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_CHANNEL_OUT_5POINT1_SIDE
|
||||
STRING_ENTRY( AUDIO_CHANNEL_OUT_5POINT1_SIDE ),
|
||||
#endif
|
||||
STRING_ENTRY(AUDIO_CHANNEL_OUT_7POINT1 ),
|
||||
STRING_ENTRY(AUDIO_CHANNEL_OUT_ALL ),
|
||||
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
|
@ -538,16 +399,9 @@ struct string_conversion string_conversion_table_input_channels[] = {
|
|||
STRING_ENTRY( AUDIO_CHANNEL_IN_MONO ),
|
||||
STRING_ENTRY( AUDIO_CHANNEL_IN_STEREO ),
|
||||
STRING_ENTRY( AUDIO_CHANNEL_IN_FRONT_BACK ),
|
||||
STRING_ENTRY( AUDIO_CHANNEL_IN_ALL ),
|
||||
#ifdef HAVE_ENUM_AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO
|
||||
STRING_ENTRY( AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO
|
||||
STRING_ENTRY( AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_CHANNEL_IN_VOICE_CALL_MONO
|
||||
STRING_ENTRY( AUDIO_CHANNEL_IN_VOICE_CALL_MONO ),
|
||||
#endif
|
||||
STRING_ENTRY_IF_AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO
|
||||
STRING_ENTRY_IF_AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO
|
||||
STRING_ENTRY_IF_AUDIO_CHANNEL_IN_VOICE_CALL_MONO
|
||||
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
|
@ -556,14 +410,15 @@ struct string_conversion string_conversion_table_input_channels[] = {
|
|||
struct string_conversion string_conversion_table_format[] = {
|
||||
/* Omit most formats as we aren't usually interested in
|
||||
* other than the pcm formats anyway. */
|
||||
STRING_ENTRY( AUDIO_FORMAT_INVALID ),
|
||||
STRING_ENTRY( AUDIO_FORMAT_DEFAULT ),
|
||||
STRING_ENTRY( AUDIO_FORMAT_PCM ),
|
||||
STRING_ENTRY( AUDIO_FORMAT_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_FLAC ),
|
||||
STRING_ENTRY( AUDIO_FORMAT_MP3 ),
|
||||
STRING_ENTRY( AUDIO_FORMAT_OPUS ),
|
||||
STRING_ENTRY( AUDIO_FORMAT_SBC ),
|
||||
STRING_ENTRY( AUDIO_FORMAT_VORBIS ),
|
||||
|
||||
STRING_ENTRY( AUDIO_FORMAT_PCM_16_BIT ),
|
||||
|
|
@ -571,18 +426,6 @@ struct string_conversion string_conversion_table_format[] = {
|
|||
STRING_ENTRY( AUDIO_FORMAT_PCM_32_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. */
|
||||
#ifdef HAVE_ENUM_AUDIO_FORMAT_PCM_OFFLOAD
|
||||
STRING_ENTRY( AUDIO_FORMAT_PCM_OFFLOAD ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_FORMAT_FLAC
|
||||
STRING_ENTRY( AUDIO_FORMAT_FLAC ),
|
||||
#endif
|
||||
#ifdef HAVE_ENUM_AUDIO_FORMAT_OPUS
|
||||
STRING_ENTRY( AUDIO_FORMAT_OPUS ),
|
||||
#endif
|
||||
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -2,7 +2,7 @@
|
|||
#define foodroidconversionfoo
|
||||
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018-2022 Jolla Ltd.
|
||||
*
|
||||
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
||||
*
|
||||
|
|
@ -52,9 +52,13 @@ typedef enum {
|
|||
CONV_STRING_OUTPUT_DEVICE,
|
||||
CONV_STRING_INPUT_DEVICE,
|
||||
CONV_STRING_OUTPUT_FLAG,
|
||||
CONV_STRING_INPUT_FLAG
|
||||
CONV_STRING_INPUT_FLAG,
|
||||
CONV_STRING_AUDIO_SOURCE_FANCY,
|
||||
} pa_conversion_string_t;
|
||||
|
||||
bool pa_string_convert_num_to_str(pa_conversion_string_t type, uint32_t value, const char **to_str);
|
||||
bool pa_string_convert_str_to_num(pa_conversion_string_t type, const char *str, uint32_t *to_value);
|
||||
|
||||
bool pa_convert_output_channel(uint32_t value, pa_conversion_field_t from, uint32_t *to_value);
|
||||
bool pa_convert_input_channel(uint32_t value, pa_conversion_field_t from, uint32_t *to_value);
|
||||
bool pa_convert_format(uint32_t value, pa_conversion_field_t from, uint32_t *to_value);
|
||||
|
|
@ -67,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_str_to_num(const char *str, audio_output_flags_t *to_value);
|
||||
|
||||
char *pa_list_string_output_device(audio_devices_t devices);
|
||||
char *pa_list_string_input_device(audio_devices_t devices);
|
||||
char *pa_list_string_flags(audio_output_flags_t flags);
|
||||
|
||||
/* Get default audio source associated with input device.
|
||||
|
|
@ -79,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_input_port_name(audio_devices_t value, const char **to_str);
|
||||
|
||||
/* Pretty audio source names */
|
||||
bool pa_droid_audio_source_name(audio_source_t value, const char **to_str);
|
||||
|
||||
int pa_conversion_parse_list(pa_conversion_string_t type, const char *separator,
|
||||
const char *str, uint32_t *dst, char **unknown_entries);
|
||||
|
||||
bool pa_conversion_parse_sampling_rates(const char *fn, const unsigned ln,
|
||||
const char *str, bool legacy,
|
||||
const char *str,
|
||||
uint32_t sampling_rates[AUDIO_MAX_SAMPLING_RATES]);
|
||||
bool pa_conversion_parse_formats(const char *fn, const unsigned ln,
|
||||
const char *str, bool legacy,
|
||||
const char *str,
|
||||
audio_format_t *formats);
|
||||
bool pa_conversion_parse_output_channels(const char *fn, const unsigned ln,
|
||||
const char *str, bool legacy,
|
||||
audio_channel_mask_t *channels);
|
||||
bool pa_conversion_parse_input_channels(const char *fn, const unsigned ln,
|
||||
const char *str, bool legacy,
|
||||
audio_channel_mask_t *channels);
|
||||
int pa_conversion_parse_output_channels(const char *fn, const unsigned ln,
|
||||
const char *str,
|
||||
audio_channel_mask_t channel_masks[AUDIO_MAX_CHANNEL_MASKS]);
|
||||
int pa_conversion_parse_input_channels(const char *fn, const unsigned ln,
|
||||
const char *str,
|
||||
audio_channel_mask_t channel_masks[AUDIO_MAX_CHANNEL_MASKS]);
|
||||
bool pa_conversion_parse_output_devices(const char *fn, const unsigned ln,
|
||||
char *str, bool legacy, bool must_recognize_all,
|
||||
char *str, bool must_recognize_all,
|
||||
audio_devices_t *devices);
|
||||
bool pa_conversion_parse_input_devices(const char *fn, const unsigned ln,
|
||||
char *str, bool legacy, bool must_recognize_all,
|
||||
char *str, bool must_recognize_all,
|
||||
audio_devices_t *devices);
|
||||
bool pa_conversion_parse_output_flags(const char *fn, const unsigned ln,
|
||||
const char *str, audio_output_flags_t *flags);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#define foodroidconfigfoo
|
||||
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018-2022 Jolla Ltd.
|
||||
*
|
||||
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
||||
*
|
||||
|
|
@ -30,73 +30,106 @@
|
|||
#include <android-config.h>
|
||||
#include <hardware/audio.h>
|
||||
|
||||
#include <droid/sllist.h>
|
||||
#include <droid/version.h>
|
||||
|
||||
typedef struct pa_droid_config_audio pa_droid_config_audio;
|
||||
typedef struct pa_droid_config_hw_module pa_droid_config_hw_module;
|
||||
#define AUDIO_MAX_SAMPLING_RATES (32)
|
||||
#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 {
|
||||
uint32_t audio_hal_version;
|
||||
audio_devices_t attached_output_devices;
|
||||
audio_devices_t default_output_device;
|
||||
audio_devices_t attached_input_devices;
|
||||
} pa_droid_config_global;
|
||||
|
||||
typedef struct pa_droid_config_device {
|
||||
const pa_droid_config_hw_module *module;
|
||||
|
||||
char *name;
|
||||
uint32_t sampling_rates[AUDIO_MAX_SAMPLING_RATES]; /* (uint32_t) -1 -> dynamic */
|
||||
audio_channel_mask_t channel_masks; /* 0 -> dynamic */
|
||||
audio_format_t formats; /* 0 -> dynamic */
|
||||
audio_devices_t devices;
|
||||
/* Instead of using audio_output_flags_t and audio_input_flags_t
|
||||
* unify the flags as uint32_t so that we can have single struct for both
|
||||
* output and input configurations.
|
||||
* audio_input_flags_t was introduced in APIs 2 & 3, depending on adaptation,
|
||||
* so having input flags as uint32_t is simpler from input implementation
|
||||
* point of view as well. */
|
||||
uint32_t flags;
|
||||
pa_direction_t direction;
|
||||
|
||||
struct pa_droid_config_device *next;
|
||||
} pa_droid_config_device;
|
||||
|
||||
struct pa_droid_config_hw_module {
|
||||
const pa_droid_config_audio *config;
|
||||
|
||||
char *name;
|
||||
/* If global config is not defined for module, use root global config. */
|
||||
pa_droid_config_global *global_config;
|
||||
pa_droid_config_device *outputs;
|
||||
pa_droid_config_device *inputs;
|
||||
|
||||
struct pa_droid_config_hw_module *next;
|
||||
struct dm_config_global {
|
||||
char *key;
|
||||
char *value;
|
||||
};
|
||||
|
||||
struct pa_droid_config_audio {
|
||||
pa_droid_config_global *global_config;
|
||||
pa_droid_config_hw_module *hw_modules;
|
||||
struct dm_config_profile {
|
||||
char *name;
|
||||
audio_format_t format; /* 0 -> dynamic TODO check that this is still true */
|
||||
uint32_t sampling_rates[AUDIO_MAX_SAMPLING_RATES]; /* sampling_rates[0] == 0 -> dynamic, otherwise 0 terminates list */
|
||||
audio_channel_mask_t channel_masks[AUDIO_MAX_CHANNEL_MASKS]; /* channel_masks[0] == 0 -> dynamic */
|
||||
};
|
||||
|
||||
typedef enum dm_config_role {
|
||||
DM_CONFIG_ROLE_SINK,
|
||||
DM_CONFIG_ROLE_SOURCE,
|
||||
} dm_config_role_t;
|
||||
|
||||
typedef enum dm_config_type {
|
||||
DM_CONFIG_TYPE_MIX,
|
||||
DM_CONFIG_TYPE_DEVICE_PORT,
|
||||
DM_CONFIG_TYPE_MIX_PORT,
|
||||
} dm_config_type_t;
|
||||
|
||||
struct dm_config_port {
|
||||
dm_config_module *module;
|
||||
|
||||
/* common values */
|
||||
|
||||
dm_config_type_t port_type; /* either mixPort or devicePort */
|
||||
char *name;
|
||||
dm_config_role_t role;
|
||||
dm_list *profiles; /* dm_config_profile* */
|
||||
|
||||
/* devicePort specific values */
|
||||
|
||||
audio_devices_t type;
|
||||
char *address;
|
||||
|
||||
/* mixPort specific values */
|
||||
|
||||
uint32_t flags; /* audio_output_flag_t or audio_input_flag_t */
|
||||
int max_open_count; /* 0 == not defined */
|
||||
int max_active_count; /* 0 == not defined */
|
||||
};
|
||||
|
||||
struct dm_config_route {
|
||||
dm_config_type_t type;
|
||||
dm_config_port *sink;
|
||||
dm_list *sources; /* dm_config_port* */
|
||||
};
|
||||
|
||||
struct dm_config_module {
|
||||
dm_config_device *config;
|
||||
|
||||
char *name;
|
||||
int version_major;
|
||||
int version_minor;
|
||||
|
||||
dm_list *attached_devices; /* dm_config_port* owned by device_ports list below */
|
||||
dm_config_port *default_output_device; /* owned by device_ports list below */
|
||||
dm_list *ports; /* dm_config_port* - for convenience port types are filtered to two lists below: */
|
||||
dm_list *mix_ports; /* dm_config_port* */
|
||||
dm_list *device_ports; /* dm_config_port* */
|
||||
dm_list *routes; /* dm_config_route* */
|
||||
};
|
||||
|
||||
struct dm_config_device {
|
||||
dm_list *global_config; /* dm_config_global* */
|
||||
dm_list *modules; /* dm_config_module* */
|
||||
};
|
||||
|
||||
|
||||
/* Config parser */
|
||||
pa_droid_config_audio *pa_droid_config_load(pa_modargs *ma);
|
||||
pa_droid_config_audio *pa_droid_config_dup(const pa_droid_config_audio *config);
|
||||
void pa_droid_config_free(pa_droid_config_audio *config);
|
||||
pa_droid_config_audio *pa_parse_droid_audio_config_legacy(const char *filename);
|
||||
pa_droid_config_audio *pa_parse_droid_audio_config_xml(const char *filename);
|
||||
dm_config_device *dm_config_load(pa_modargs *ma);
|
||||
dm_config_device *dm_config_dup(const dm_config_device *config);
|
||||
void dm_config_free(dm_config_device *config);
|
||||
/* autodetect config type from filename and parse */
|
||||
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);
|
||||
dm_config_port *dm_config_find_port(dm_config_module *module, const char* name);
|
||||
dm_config_port *dm_config_default_output_device(dm_config_module *module);
|
||||
dm_config_port *dm_config_find_device_port(dm_config_port *port, audio_devices_t device);
|
||||
char *dm_config_escape_string(const char *string);
|
||||
|
||||
pa_droid_config_hw_module *pa_droid_config_hw_module_new(const pa_droid_config_audio *config, const char *name);
|
||||
void pa_droid_config_hw_module_free(pa_droid_config_hw_module *hw_module);
|
||||
pa_droid_config_device *pa_droid_config_device_new(const pa_droid_config_hw_module *module,
|
||||
pa_direction_t direction,
|
||||
const char *name);
|
||||
void pa_droid_config_device_free(pa_droid_config_device *device);
|
||||
bool dm_config_port_equal(const dm_config_port *a, const dm_config_port *b);
|
||||
|
||||
dm_config_port *dm_config_find_mix_port(dm_config_module *module, const char *name);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#define foodroidutilfoo
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013-2018 Jolla Ltd.
|
||||
* Copyright (C) 2013-2022 Jolla Ltd.
|
||||
*
|
||||
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
||||
*
|
||||
|
|
@ -30,14 +30,11 @@
|
|||
#include <pulsecore/mutex.h>
|
||||
#include <pulsecore/strlist.h>
|
||||
#include <pulsecore/atomic.h>
|
||||
#include <pulsecore/modargs.h>
|
||||
|
||||
#include <droid/version.h>
|
||||
#include <droid/droid-config.h>
|
||||
|
||||
#if defined(QCOM_BSP) && (AUDIO_API_VERSION_MAJ >= 3)
|
||||
#define DROID_AUDIO_HAL_USE_VSID
|
||||
#endif
|
||||
|
||||
#define PROP_DROID_DEVICES "droid.devices"
|
||||
#define PROP_DROID_FLAGS "droid.flags"
|
||||
#define PROP_DROID_HW_MODULE "droid.hw_module"
|
||||
|
|
@ -47,8 +44,12 @@
|
|||
#define PROP_DROID_OUTPUT_LOW_LATENCY "droid.output.low_latency"
|
||||
#define PROP_DROID_OUTPUT_MEDIA_LATENCY "droid.output.media_latency"
|
||||
#define PROP_DROID_OUTPUT_OFFLOAD "droid.output.offload"
|
||||
#define PROP_DROID_OUTPUT_VOIP "droid.output.voip"
|
||||
#define PROP_DROID_INPUT_BUILTIN "droid.input.builtin"
|
||||
#define PROP_DROID_INPUT_EXTERNAL "droid.input.external"
|
||||
#define PROP_DROID_INPUT_VOIP "droid.input.voip"
|
||||
|
||||
#define EXT_PROP_AUDIO_SOURCE "audio.source"
|
||||
|
||||
#define PA_DROID_PRIMARY_DEVICE "primary"
|
||||
|
||||
|
|
@ -57,16 +58,28 @@ typedef struct pa_droid_stream pa_droid_stream;
|
|||
typedef struct pa_droid_output_stream pa_droid_output_stream;
|
||||
typedef struct pa_droid_input_stream pa_droid_input_stream;
|
||||
typedef struct pa_droid_card_data pa_droid_card_data;
|
||||
typedef int (*common_set_parameters_cb_t)(pa_droid_card_data *card_data, const char *str);
|
||||
|
||||
typedef struct pa_droid_quirks pa_droid_quirks;
|
||||
typedef struct pa_droid_options pa_droid_options;
|
||||
|
||||
typedef enum pa_droid_hook {
|
||||
PA_DROID_HOOK_INPUT_CHANNEL_MAP_CHANGED, /* Call data: pa_droid_stream */
|
||||
PA_DROID_HOOK_INPUT_BUFFER_SIZE_CHANGED, /* Call data: pa_droid_stream */
|
||||
PA_DROID_HOOK_MAX
|
||||
} pa_droid_hook_t;
|
||||
enum pa_droid_option_type {
|
||||
DM_OPTION_INPUT_ATOI,
|
||||
DM_OPTION_CLOSE_INPUT,
|
||||
DM_OPTION_UNLOAD_NO_CLOSE,
|
||||
DM_OPTION_HW_VOLUME,
|
||||
DM_OPTION_REALCALL,
|
||||
DM_OPTION_UNLOAD_CALL_EXIT,
|
||||
DM_OPTION_OUTPUT_FAST,
|
||||
DM_OPTION_OUTPUT_DEEP_BUFFER,
|
||||
DM_OPTION_AUDIO_CAL_WAIT,
|
||||
DM_OPTION_SPEAKER_BEFORE_VOICE,
|
||||
DM_OPTION_OUTPUT_VOIP_RX,
|
||||
DM_OPTION_RECORD_VOICE_16K,
|
||||
DM_OPTION_COUNT
|
||||
};
|
||||
|
||||
struct pa_droid_options {
|
||||
bool enabled[DM_OPTION_COUNT];
|
||||
};
|
||||
|
||||
struct pa_droid_hw_module {
|
||||
PA_REFCNT_DECLARE;
|
||||
|
|
@ -74,8 +87,8 @@ struct pa_droid_hw_module {
|
|||
pa_core *core;
|
||||
char *shared_name;
|
||||
|
||||
pa_droid_config_audio *config;
|
||||
const pa_droid_config_hw_module *enabled_module;
|
||||
dm_config_device *config;
|
||||
dm_config_module *enabled_module;
|
||||
pa_mutex *hw_mutex;
|
||||
pa_mutex *output_mutex;
|
||||
pa_mutex *input_mutex;
|
||||
|
|
@ -85,58 +98,68 @@ struct pa_droid_hw_module {
|
|||
|
||||
const char *module_id;
|
||||
|
||||
uint32_t stream_out_id;
|
||||
uint32_t stream_in_id;
|
||||
uint32_t stream_id;
|
||||
bool bt_sco_enabled;
|
||||
|
||||
pa_idxset *outputs;
|
||||
pa_idxset *inputs;
|
||||
pa_hook_slot *sink_put_hook_slot;
|
||||
pa_hook_slot *sink_unlink_hook_slot;
|
||||
pa_hook_slot *source_put_hook_slot;
|
||||
pa_hook_slot *source_unlink_hook_slot;
|
||||
|
||||
pa_atomic_t active_outputs;
|
||||
|
||||
pa_droid_quirks *quirks;
|
||||
pa_hook hooks[PA_DROID_HOOK_MAX];
|
||||
pa_droid_options options;
|
||||
|
||||
/* Mode and input control */
|
||||
struct _state {
|
||||
audio_mode_t mode;
|
||||
} state;
|
||||
};
|
||||
|
||||
struct pa_droid_output_stream {
|
||||
struct audio_stream_out *stream;
|
||||
pa_sample_spec sample_spec;
|
||||
pa_channel_map channel_map;
|
||||
uint32_t flags;
|
||||
uint32_t device;
|
||||
};
|
||||
|
||||
struct pa_droid_input_stream {
|
||||
struct audio_stream_in *stream;
|
||||
pa_sample_spec default_sample_spec;
|
||||
pa_channel_map default_channel_map;
|
||||
pa_sample_spec sample_spec;
|
||||
pa_channel_map channel_map;
|
||||
pa_sample_spec input_sample_spec;
|
||||
pa_channel_map input_channel_map;
|
||||
pa_sample_spec req_sample_spec;
|
||||
pa_channel_map req_channel_map;
|
||||
|
||||
audio_source_t audio_source;
|
||||
dm_config_port *default_mix_port;
|
||||
dm_config_port *input_port;
|
||||
pa_droid_stream *active_input;
|
||||
|
||||
uint32_t flags;
|
||||
uint32_t device;
|
||||
audio_devices_t all_devices;
|
||||
bool merged;
|
||||
bool first;
|
||||
};
|
||||
|
||||
struct pa_droid_stream {
|
||||
PA_REFCNT_DECLARE;
|
||||
|
||||
pa_droid_hw_module *module;
|
||||
dm_config_port *mix_port;
|
||||
size_t buffer_size;
|
||||
void *data;
|
||||
|
||||
audio_io_handle_t io_handle;
|
||||
audio_patch_handle_t audio_patch;
|
||||
const dm_config_port *active_device_port;
|
||||
|
||||
pa_droid_output_stream *output;
|
||||
pa_droid_input_stream *input;
|
||||
};
|
||||
|
||||
struct pa_droid_card_data {
|
||||
void *userdata;
|
||||
/* General functions */
|
||||
char *module_id;
|
||||
common_set_parameters_cb_t set_parameters;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -146,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_port_data {
|
||||
audio_devices_t device;
|
||||
dm_config_port *device_port;
|
||||
} pa_droid_port_data;
|
||||
|
||||
typedef struct pa_droid_port {
|
||||
pa_droid_mapping *mapping;
|
||||
|
||||
audio_devices_t device;
|
||||
dm_config_port *device_port;
|
||||
char *name;
|
||||
char *description;
|
||||
unsigned priority;
|
||||
|
|
@ -161,9 +184,9 @@ typedef struct pa_droid_port {
|
|||
struct pa_droid_mapping {
|
||||
pa_droid_profile_set *profile_set;
|
||||
|
||||
const pa_droid_config_device *output;
|
||||
const pa_droid_config_device *input;
|
||||
const pa_droid_config_device *input2;
|
||||
dm_config_module *module;
|
||||
dm_config_port *mix_port;
|
||||
dm_list *device_ports;
|
||||
|
||||
char *name;
|
||||
char *description;
|
||||
|
|
@ -182,21 +205,25 @@ struct pa_droid_mapping {
|
|||
typedef struct pa_droid_profile {
|
||||
pa_droid_profile_set *profile_set;
|
||||
|
||||
const pa_droid_config_hw_module *module;
|
||||
dm_config_module *module;
|
||||
|
||||
char *name;
|
||||
char *description;
|
||||
unsigned priority;
|
||||
|
||||
/* Idxsets contain pa_droid_mapping objects.
|
||||
* Profile doesn't own the mappings. */
|
||||
* Profile doesn't own the mappings, these
|
||||
* are references to structs in profile set
|
||||
* hashmaps. */
|
||||
pa_idxset *output_mappings;
|
||||
/* Only one input */
|
||||
pa_idxset *input_mappings;
|
||||
pa_droid_mapping *input_mapping;
|
||||
|
||||
} pa_droid_profile;
|
||||
|
||||
struct pa_droid_profile_set {
|
||||
const pa_droid_config_audio *config;
|
||||
dm_config_device *config;
|
||||
|
||||
pa_hashmap *all_ports;
|
||||
pa_hashmap *output_mappings;
|
||||
|
|
@ -207,25 +234,12 @@ struct pa_droid_profile_set {
|
|||
#define PA_DROID_OUTPUT_PARKING "output-parking"
|
||||
#define PA_DROID_INPUT_PARKING "input-parking"
|
||||
|
||||
enum pa_droid_quirk_type {
|
||||
QUIRK_INPUT_ATOI,
|
||||
QUIRK_SET_PARAMETERS,
|
||||
QUIRK_CLOSE_INPUT,
|
||||
QUIRK_UNLOAD_NO_CLOSE,
|
||||
QUIRK_NO_HW_VOLUME,
|
||||
QUIRK_OUTPUT_MAKE_WRITABLE,
|
||||
QUIRK_REALCALL,
|
||||
QUIRK_UNLOAD_CALL_EXIT,
|
||||
QUIRK_COUNT
|
||||
};
|
||||
|
||||
struct pa_droid_quirks {
|
||||
bool enabled[QUIRK_COUNT];
|
||||
};
|
||||
|
||||
/* Open hardware module */
|
||||
/* 'config' can be NULL if it is assumed that hw module with module_id already is open. */
|
||||
pa_droid_hw_module *pa_droid_hw_module_get(pa_core *core, const pa_droid_config_audio *config, const char *module_id);
|
||||
pa_droid_hw_module *pa_droid_hw_module_get(pa_core *core, dm_config_device *config, const char *module_id);
|
||||
/* First try to get already open hw module and if none found parse config and options from modargs
|
||||
* and do initial open. */
|
||||
pa_droid_hw_module *pa_droid_hw_module_get2(pa_core *core, pa_modargs *ma, const char *module_id);
|
||||
pa_droid_hw_module *pa_droid_hw_module_ref(pa_droid_hw_module *hw);
|
||||
void pa_droid_hw_module_unref(pa_droid_hw_module *hw);
|
||||
|
||||
|
|
@ -233,31 +247,27 @@ void pa_droid_hw_module_lock(pa_droid_hw_module *hw);
|
|||
bool pa_droid_hw_module_try_lock(pa_droid_hw_module *hw);
|
||||
void pa_droid_hw_module_unlock(pa_droid_hw_module *hw);
|
||||
|
||||
bool pa_droid_quirk_parse(pa_droid_hw_module *hw, const char *quirks);
|
||||
void pa_droid_quirk_log(pa_droid_hw_module *hw);
|
||||
void pa_droid_options_log(pa_droid_hw_module *hw);
|
||||
|
||||
static inline bool pa_droid_quirk(pa_droid_hw_module *hw, enum pa_droid_quirk_type quirk) {
|
||||
return hw->quirks && hw->quirks->enabled[quirk];
|
||||
static inline bool pa_droid_option(pa_droid_hw_module *hw, enum pa_droid_option_type option) {
|
||||
return hw && hw->options.enabled[option];
|
||||
}
|
||||
|
||||
bool pa_droid_hw_set_mode(pa_droid_hw_module *hw_module, audio_mode_t mode);
|
||||
bool pa_droid_hw_has_mic_control(pa_droid_hw_module *hw);
|
||||
int pa_droid_hw_mic_get_mute(pa_droid_hw_module *hw_module, bool *muted);
|
||||
void pa_droid_hw_mic_set_mute(pa_droid_hw_module *hw_module, bool muted);
|
||||
|
||||
/* Profiles */
|
||||
pa_droid_profile_set *pa_droid_profile_set_new(const pa_droid_config_hw_module *module);
|
||||
pa_droid_profile_set *pa_droid_profile_set_default_new(const pa_droid_config_hw_module *module,
|
||||
bool merge_inputs);
|
||||
pa_droid_profile_set *pa_droid_profile_set_default_new(dm_config_module *module);
|
||||
void pa_droid_profile_set_free(pa_droid_profile_set *ps);
|
||||
|
||||
void pa_droid_profile_add_mapping(pa_droid_profile *p, pa_droid_mapping *am);
|
||||
void pa_droid_profile_free(pa_droid_profile *p);
|
||||
|
||||
pa_droid_mapping *pa_droid_mapping_get(pa_droid_profile_set *ps, const pa_droid_config_device *device);
|
||||
pa_droid_mapping *pa_droid_mapping_merged_get(pa_droid_profile_set *ps,
|
||||
const pa_droid_config_device *input1,
|
||||
const pa_droid_config_device *input2);
|
||||
bool pa_droid_mapping_is_primary(pa_droid_mapping *am);
|
||||
/* Go through idxset containing pa_droid_mapping objects and if primary output or input
|
||||
* mapping is found, return pointer to that mapping. */
|
||||
pa_droid_mapping *pa_droid_idxset_get_primary(pa_idxset *i);
|
||||
pa_droid_mapping *pa_droid_idxset_mapping_with_device(pa_idxset *i, uint32_t flag);
|
||||
void pa_droid_mapping_free(pa_droid_mapping *am);
|
||||
|
||||
/* Add ports from sinks/sources.
|
||||
|
|
@ -267,10 +277,9 @@ void pa_droid_add_ports(pa_hashmap *ports, pa_droid_mapping *am, pa_card *card);
|
|||
* May be called multiple times for one card profile. */
|
||||
void pa_droid_add_card_ports(pa_card_profile *cp, pa_hashmap *ports, pa_droid_mapping *am, pa_core *core);
|
||||
|
||||
pa_hook *pa_droid_hooks(pa_droid_hw_module *hw);
|
||||
|
||||
/* Module operations */
|
||||
int pa_droid_set_parameters(pa_droid_hw_module *hw, const char *parameters);
|
||||
pa_droid_stream *pa_droid_hw_primary_output_stream(pa_droid_hw_module *hw);
|
||||
|
||||
/* Stream operations */
|
||||
pa_droid_stream *pa_droid_stream_ref(pa_droid_stream *s);
|
||||
|
|
@ -282,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,
|
||||
const pa_sample_spec *spec,
|
||||
const pa_channel_map *map,
|
||||
audio_output_flags_t flags,
|
||||
audio_devices_t devices);
|
||||
dm_config_port *mix_port,
|
||||
dm_config_port *device_port);
|
||||
|
||||
/* Set routing to the input or output stream, with following side-effects:
|
||||
* Output:
|
||||
|
|
@ -294,14 +303,28 @@ pa_droid_stream *pa_droid_open_output_stream(pa_droid_hw_module *module,
|
|||
* Input:
|
||||
* - 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);
|
||||
|
||||
/* Input stream operations */
|
||||
pa_droid_stream *pa_droid_open_input_stream(pa_droid_hw_module *module,
|
||||
const pa_sample_spec *spec,
|
||||
const pa_channel_map *map,
|
||||
audio_devices_t devices,
|
||||
pa_droid_mapping *am);
|
||||
/* Open input stream with currently active routing, sample_spec and channel_map
|
||||
* are requests and may change when opening the stream. */
|
||||
pa_droid_stream *pa_droid_open_input_stream(pa_droid_hw_module *hw_module,
|
||||
const pa_sample_spec *default_sample_spec,
|
||||
const pa_channel_map *default_channel_map,
|
||||
const char *mix_port_name);
|
||||
/* Test if reconfiguring of input stream is needed */
|
||||
bool pa_droid_stream_reconfigure_input_needed(pa_droid_stream *s,
|
||||
const pa_sample_spec *requested_sample_spec,
|
||||
const pa_channel_map *requested_channel_map,
|
||||
const pa_proplist *proplist);
|
||||
bool pa_droid_stream_reconfigure_input(pa_droid_stream *s,
|
||||
const pa_sample_spec *requested_sample_spec,
|
||||
const pa_channel_map *requested_channel_map,
|
||||
const pa_proplist *proplist);
|
||||
bool pa_droid_hw_set_input_device(pa_droid_stream *s,
|
||||
dm_config_port *device_port);
|
||||
|
||||
const pa_sample_spec *pa_droid_stream_sample_spec(pa_droid_stream *stream);
|
||||
const pa_channel_map *pa_droid_stream_channel_map(pa_droid_stream *stream);
|
||||
|
||||
bool pa_droid_stream_is_primary(pa_droid_stream *s);
|
||||
|
||||
|
|
@ -327,6 +350,8 @@ void *pa_droid_stream_get_data(pa_droid_stream *s);
|
|||
bool pa_sink_is_droid_sink(pa_sink *sink);
|
||||
bool pa_source_is_droid_source(pa_source *source);
|
||||
|
||||
pa_modargs *pa_droid_modargs_new(const char *args, const char* const keys[]);
|
||||
|
||||
/* Misc */
|
||||
size_t pa_droid_buffer_size_round_up(size_t buffer_size, size_t block_size);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#define foosllistfoo
|
||||
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018-2022 Jolla Ltd.
|
||||
*
|
||||
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
||||
*
|
||||
|
|
@ -22,6 +22,12 @@
|
|||
* USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
#include <stdbool.h>
|
||||
#include <pulse/def.h>
|
||||
|
||||
#define SLLIST_APPEND(t, head, item) \
|
||||
do { \
|
||||
item->next = NULL; \
|
||||
|
|
@ -46,4 +52,43 @@
|
|||
i = NULL; \
|
||||
} while (0)
|
||||
|
||||
typedef struct dm_list_entry dm_list_entry;
|
||||
typedef struct dm_list dm_list;
|
||||
|
||||
struct dm_list_entry {
|
||||
struct dm_list_entry *next;
|
||||
struct dm_list_entry *prev;
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct dm_list {
|
||||
struct dm_list_entry *head;
|
||||
struct dm_list_entry *tail;
|
||||
ssize_t size;
|
||||
};
|
||||
|
||||
dm_list *dm_list_new(void);
|
||||
void dm_list_free(dm_list *list, pa_free_cb_t free_cb);
|
||||
bool dm_list_remove(dm_list *list, dm_list_entry *entry);
|
||||
void dm_list_prepend(dm_list *list, void *data);
|
||||
void dm_list_push_back(dm_list *list, void *data);
|
||||
dm_list_entry *dm_list_last(dm_list *list);
|
||||
void *dm_list_steal_first(dm_list *list);
|
||||
ssize_t dm_list_size(dm_list *list);
|
||||
void *dm_list_first_data(dm_list *list, void **state);
|
||||
void *dm_list_next_data(dm_list *list, void **state);
|
||||
/* For example
|
||||
* dm_list *list;
|
||||
* void *state;
|
||||
* my_data *data;
|
||||
* DM_LIST_FOREACH_DATA(data, list, state) {
|
||||
* do_something_with_my(data);
|
||||
* }
|
||||
*/
|
||||
#define DM_LIST_FOREACH_DATA(i, list, state) \
|
||||
for (i = dm_list_first_data(list, &(state)); state; i = dm_list_next_data(list, &(state)))
|
||||
/* Access i->data */
|
||||
#define DM_LIST_FOREACH(i, list) \
|
||||
for (i = list->head; i; i = i->next)
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
#ifndef foodroidcommonutilsfoo
|
||||
#define foodroidcommonutilsfoo
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013-2018 Jolla Ltd.
|
||||
* Copyright (C) 2022 Jolla Ltd.
|
||||
*
|
||||
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
||||
*
|
||||
|
|
@ -18,25 +21,12 @@
|
|||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||
* USA.
|
||||
*/
|
||||
#ifndef foomoduledroidcardsymdeffoo
|
||||
#define foomoduledroidcardsymdeffoo
|
||||
|
||||
#include <pulsecore/core.h>
|
||||
#include <pulsecore/module.h>
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#define pa__init module_droid_card_LTX_pa__init
|
||||
#define pa__done module_droid_card_LTX_pa__done
|
||||
#define pa__get_author module_droid_card_LTX_pa__get_author
|
||||
#define pa__get_description module_droid_card_LTX_pa__get_description
|
||||
#define pa__get_usage module_droid_card_LTX_pa__get_usage
|
||||
#define pa__get_version module_droid_card_LTX_pa__get_version
|
||||
|
||||
int pa__init(struct pa_module*m);
|
||||
void pa__done(struct pa_module*m);
|
||||
|
||||
const char* pa__get_author(void);
|
||||
const char* pa__get_description(void);
|
||||
const char* pa__get_usage(void);
|
||||
const char* pa__get_version(void);
|
||||
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
|
||||
|
||||
/*
|
||||
* Copyright (C) 2018 Jolla Ltd.
|
||||
* Copyright (C) 2018-2022 Jolla Ltd.
|
||||
*
|
||||
* 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?"
|
||||
#endif
|
||||
|
||||
/* We currently support API version up-to 3.0 */
|
||||
#define DROID_API_VERSION_SUPPORT HARDWARE_DEVICE_API_VERSION(3, 0)
|
||||
/* We currently support API version up to 3.1 */
|
||||
#define DROID_API_VERSION_SUPPORT HARDWARE_DEVICE_API_VERSION(3, 1)
|
||||
|
||||
#if AUDIO_DEVICE_API_VERSION_CURRENT > DROID_API_VERSION_SUPPORT
|
||||
#warning Compiling against higher audio device API version than currently supported!
|
||||
|
|
@ -48,4 +48,8 @@
|
|||
#define AUDIO_API_VERSION_GET_MAJ(x) ((x >> 8) & 0xff)
|
||||
#define AUDIO_API_VERSION_GET_MIN(x) (x & 0xff)
|
||||
|
||||
#if AUDIO_API_VERSION_MAJ < 3
|
||||
#error This module only supports audio API version 3 and upwards.
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -7,5 +7,5 @@ libexecdir=@libexecdir@
|
|||
Name: libdroid-util
|
||||
Description: Common droid module building interface.
|
||||
Version: @PA_MODULE_VERSION@
|
||||
Libs: -L${libdir}/pulse-@PA_MAJORMINOR@/modules -ldroid-util
|
||||
Libs: -L${prefix}/lib/pulse-@PA_MAJORMINOR@/modules -ldroid-util
|
||||
Cflags: -D_REENTRANT -I${includedir}/pulsecore/modules
|
||||
|
|
|
|||
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;
|
||||
}
|
||||
|
|
@ -15,18 +15,10 @@ AM_CFLAGS = \
|
|||
modlibexec_LTLIBRARIES = \
|
||||
libdroid-sink.la \
|
||||
libdroid-source.la \
|
||||
module-droid-keepalive.la \
|
||||
module-droid-sink.la \
|
||||
module-droid-source.la \
|
||||
module-droid-card.la
|
||||
|
||||
noinst_HEADERS = module-droid-sink-symdef.h module-droid-source-symdef.h module-droid-card-symdef.h module-droid-keepalive-symdef.h
|
||||
|
||||
module_droid_keepalive_la_SOURCES = keepalive.c keepalive.h module-droid-keepalive.c
|
||||
module_droid_keepalive_la_LDFLAGS = -module -avoid-version -Wl,-z,noexecstack
|
||||
module_droid_keepalive_la_LIBADD = $(AM_LIBADD) $(DBUS_LIBS)
|
||||
module_droid_keepalive_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS)
|
||||
|
||||
libdroid_sink_la_SOURCES = droid-sink.c droid-sink.h
|
||||
libdroid_sink_la_LDFLAGS = -avoid-version -Wl,-z,noexecstack -lhybris-common
|
||||
libdroid_sink_la_LIBADD = $(top_builddir)/src/common/libdroid-util.la $(AM_LIBADD)
|
||||
|
|
@ -40,14 +32,14 @@ libdroid_source_la_CFLAGS = $(AM_CFLAGS)
|
|||
module_droid_sink_la_SOURCES = module-droid-sink.c
|
||||
module_droid_sink_la_LDFLAGS = -module -avoid-version -Wl,-z,noexecstack -lhybris-common
|
||||
module_droid_sink_la_LIBADD = -lm libdroid-sink.la $(AM_LIBADD)
|
||||
module_droid_sink_la_CFLAGS = $(AM_CFLAGS)
|
||||
module_droid_sink_la_CFLAGS = $(AM_CFLAGS) -DPA_MODULE_NAME=module_droid_sink
|
||||
|
||||
module_droid_source_la_SOURCES = module-droid-source.c
|
||||
module_droid_source_la_LDFLAGS = -module -avoid-version -Wl,-z,noexecstack -lhybris-common
|
||||
module_droid_source_la_LIBADD = -lm libdroid-source.la $(AM_LIBADD)
|
||||
module_droid_source_la_CFLAGS = $(AM_CFLAGS)
|
||||
module_droid_source_la_CFLAGS = $(AM_CFLAGS) -DPA_MODULE_NAME=module_droid_source
|
||||
|
||||
module_droid_card_la_SOURCES = module-droid-card.c
|
||||
module_droid_card_la_LDFLAGS = -module -avoid-version -Wl,-z,noexecstack -lhybris-common
|
||||
module_droid_card_la_LIBADD = -lm libdroid-sink.la libdroid-source.la $(top_builddir)/src/common/libdroid-util.la $(AM_LIBADD)
|
||||
module_droid_card_la_CFLAGS = $(AM_CFLAGS)
|
||||
module_droid_card_la_SOURCES = module-droid-card.c droid-extcon.c droid-extevdev.c
|
||||
module_droid_card_la_LDFLAGS = -module -avoid-version -Wl,-z,noexecstack -lhybris-common -ludev
|
||||
module_droid_card_la_LIBADD = -lm libdroid-sink.la libdroid-source.la $(top_builddir)/src/common/libdroid-util.la $(AM_LIBADD) $(EVDEV_LIBS)
|
||||
module_droid_card_la_CFLAGS = $(AM_CFLAGS) $(EVDEV_CFLAGS) -DPA_MODULE_NAME=module_droid_card
|
||||
|
|
|
|||
269
src/droid/droid-extcon.c
Normal file
269
src/droid/droid-extcon.c
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
/***
|
||||
This file is part of PulseAudio.
|
||||
|
||||
Copyright (C) 2013 Canonical Ltd.
|
||||
Contact: David Henningsson
|
||||
Ricardo Salveti de Araujo <ricardo.salveti@canonical.com>
|
||||
|
||||
PulseAudio is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published
|
||||
by the Free Software Foundation; either version 2.1 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
PulseAudio is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with PulseAudio; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
USA.
|
||||
***/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <pulsecore/core-util.h>
|
||||
#include <pulsecore/device-port.h>
|
||||
#include <pulsecore/i18n.h>
|
||||
#include <libudev.h>
|
||||
|
||||
#include "droid-extcon.h"
|
||||
|
||||
/* For android */
|
||||
#define EXTCON_NAME "switch"
|
||||
|
||||
/* TODO: Backport stuff to 4.0, remove before upstreaming */
|
||||
#ifndef PA_PORT_AVAILABLE_YES
|
||||
#define PA_PORT_AVAILABLE_YES PA_AVAILABLE_YES
|
||||
#define PA_PORT_AVAILABLE_NO PA_AVAILABLE_NO
|
||||
#define PA_PORT_AVAILABLE_UNKNOWN PA_AVAILABLE_UNKNOWN
|
||||
#define pa_port_available_t pa_available_t
|
||||
#endif
|
||||
|
||||
static pa_port_available_t hponly_avail(int state)
|
||||
{
|
||||
return (state & 2) ? PA_PORT_AVAILABLE_YES : PA_PORT_AVAILABLE_NO;
|
||||
}
|
||||
|
||||
static pa_port_available_t hsmic_avail(int state)
|
||||
{
|
||||
return (state & 1) ? PA_PORT_AVAILABLE_YES : PA_PORT_AVAILABLE_NO;
|
||||
}
|
||||
|
||||
struct droid_switch {
|
||||
char *name;
|
||||
uint32_t current_value;
|
||||
};
|
||||
|
||||
static void droid_switch_free(struct droid_switch *as) {
|
||||
if (!as)
|
||||
return;
|
||||
pa_xfree(as->name);
|
||||
pa_xfree(as);
|
||||
}
|
||||
|
||||
static struct droid_switch *droid_switch_new(const char *name) {
|
||||
|
||||
struct droid_switch *as = NULL;
|
||||
char *filename = pa_sprintf_malloc("/sys/class/%s/%s/state", EXTCON_NAME, name);
|
||||
char *state = pa_read_line_from_file(filename);
|
||||
|
||||
if (state == NULL) {
|
||||
pa_log_debug("Cannot open '%s'. Skipping.", filename);
|
||||
pa_xfree(filename);
|
||||
return NULL;
|
||||
}
|
||||
pa_xfree(filename);
|
||||
|
||||
as = pa_xnew0(struct droid_switch, 1);
|
||||
as->name = pa_xstrdup(name);
|
||||
|
||||
if (pa_atou(state, &as->current_value) < 0) {
|
||||
pa_log_warn("Switch '%s' has invalid value '%s'", name, state);
|
||||
pa_xfree(state);
|
||||
droid_switch_free(as);
|
||||
return NULL;
|
||||
}
|
||||
pa_log_debug("Switch '%s' opened with value '%s'", name, state);
|
||||
|
||||
return as;
|
||||
}
|
||||
|
||||
struct udev_data {
|
||||
struct udev *udev;
|
||||
struct udev_monitor *monitor;
|
||||
pa_io_event *event;
|
||||
};
|
||||
|
||||
struct pa_droid_extcon {
|
||||
pa_card *card;
|
||||
struct droid_switch *h2w;
|
||||
struct udev_data udev;
|
||||
};
|
||||
|
||||
static struct droid_switch *find_matching_switch(pa_droid_extcon *u,
|
||||
const char *devpath) {
|
||||
|
||||
if (pa_streq(devpath, "/devices/virtual/" EXTCON_NAME "/h2w"))
|
||||
return u->h2w; /* To be extended if we ever support more switches */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void notify_ports(pa_droid_extcon *u, struct droid_switch *as) {
|
||||
|
||||
pa_device_port *p;
|
||||
void *state;
|
||||
|
||||
pa_assert(as == u->h2w); /* To be extended if we ever support more switches */
|
||||
|
||||
pa_log_debug("Value of switch %s is now %d.", as->name, as->current_value);
|
||||
|
||||
PA_HASHMAP_FOREACH(p, u->card->ports, state) {
|
||||
if (p->direction == PA_DIRECTION_OUTPUT) {
|
||||
if (!strcmp(p->name, "output-wired_headset"))
|
||||
pa_device_port_set_available(p, hsmic_avail(as->current_value));
|
||||
if (!strcmp(p->name, "output-wired_headphone"))
|
||||
pa_device_port_set_available(p, hponly_avail(as->current_value));
|
||||
}
|
||||
if (p->direction == PA_DIRECTION_INPUT) {
|
||||
if (!strcmp(p->name, "input-wired_headset"))
|
||||
pa_device_port_set_available(p, hsmic_avail(as->current_value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void udev_cb(pa_mainloop_api *a, pa_io_event *e, int fd,
|
||||
pa_io_event_flags_t events, void *userdata) {
|
||||
|
||||
pa_droid_extcon *u = userdata;
|
||||
struct udev_device *d = udev_monitor_receive_device(u->udev.monitor);
|
||||
struct udev_list_entry *entry;
|
||||
struct droid_switch *as;
|
||||
const char *devpath, *state;
|
||||
|
||||
if (!d) {
|
||||
pa_log("udev_monitor_receive_device failed.");
|
||||
pa_assert(a);
|
||||
a->io_free(u->udev.event);
|
||||
u->udev.event = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
devpath = udev_device_get_devpath(d);
|
||||
if (!devpath) {
|
||||
pa_log("udev_device_get_devpath failed.");
|
||||
goto out;
|
||||
}
|
||||
pa_log_debug("Got uevent with devpath=%s", devpath);
|
||||
|
||||
as = find_matching_switch(u, devpath);
|
||||
if (!as)
|
||||
goto out;
|
||||
|
||||
entry = udev_list_entry_get_by_name(
|
||||
udev_device_get_properties_list_entry(d), "SWITCH_STATE");
|
||||
if (!entry) {
|
||||
pa_log("udev_list_entry_get_by_name failed to find 'SWITCH_STATE' entry.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
state = udev_list_entry_get_value(entry);
|
||||
if (!state) {
|
||||
pa_log("udev_list_entry_get_by_name failed.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (pa_atou(state, &as->current_value) < 0) {
|
||||
pa_log_warn("Switch '%s' has invalid value '%s'", as->name, state);
|
||||
goto out;
|
||||
}
|
||||
|
||||
notify_ports(u, as);
|
||||
|
||||
out:
|
||||
udev_device_unref(d);
|
||||
}
|
||||
|
||||
static bool init_udev(pa_droid_extcon *u, pa_core *core) {
|
||||
|
||||
int fd;
|
||||
|
||||
u->udev.udev = udev_new();
|
||||
if (!u->udev.udev) {
|
||||
pa_log("udev_new failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
u->udev.monitor = udev_monitor_new_from_netlink(u->udev.udev, "udev");
|
||||
if (!u->udev.monitor) {
|
||||
pa_log("udev_monitor_new_from_netlink failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (udev_monitor_filter_add_match_subsystem_devtype(u->udev.monitor, EXTCON_NAME, NULL) < 0) {
|
||||
pa_log("udev_monitor_filter_add_match_subsystem_devtype failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (udev_monitor_enable_receiving(u->udev.monitor) < 0) {
|
||||
pa_log("udev_monitor_enable_receiving failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
fd = udev_monitor_get_fd(u->udev.monitor);
|
||||
if (fd < 0) {
|
||||
pa_log("udev_monitor_get_fd failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
pa_assert_se(u->udev.event = core->mainloop->io_new(core->mainloop, fd,
|
||||
PA_IO_EVENT_INPUT, udev_cb, u));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
pa_droid_extcon *pa_droid_extcon_new(pa_core *core, pa_card *card) {
|
||||
|
||||
pa_droid_extcon *u = pa_xnew0(pa_droid_extcon, 1);
|
||||
|
||||
pa_assert(core);
|
||||
pa_assert(card);
|
||||
|
||||
u->card = card;
|
||||
u->h2w = droid_switch_new("h2w");
|
||||
if (!u->h2w)
|
||||
goto fail;
|
||||
|
||||
if (!init_udev(u, core))
|
||||
goto fail;
|
||||
|
||||
notify_ports(u, u->h2w);
|
||||
|
||||
return u;
|
||||
|
||||
fail:
|
||||
pa_droid_extcon_free(u);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void pa_droid_extcon_free(pa_droid_extcon *u) {
|
||||
|
||||
pa_assert(u);
|
||||
|
||||
if (u->udev.event)
|
||||
u->card->core->mainloop->io_free(u->udev.event);
|
||||
|
||||
if (u->udev.monitor)
|
||||
udev_monitor_unref(u->udev.monitor);
|
||||
|
||||
if (u->udev.udev)
|
||||
udev_unref(u->udev.udev);
|
||||
|
||||
if (u->h2w)
|
||||
droid_switch_free(u->h2w);
|
||||
|
||||
pa_xfree(u);
|
||||
}
|
||||
32
src/droid/droid-extcon.h
Normal file
32
src/droid/droid-extcon.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef foodroidextconhfoo
|
||||
#define foodroidextconhfoo
|
||||
|
||||
/***
|
||||
This file is part of PulseAudio.
|
||||
|
||||
Copyright (C) 2013 Canonical Ltd.
|
||||
Contact: David Henningsson
|
||||
|
||||
PulseAudio is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published
|
||||
by the Free Software Foundation; either version 2.1 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
PulseAudio is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with PulseAudio; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
USA.
|
||||
***/
|
||||
|
||||
typedef struct pa_droid_extcon pa_droid_extcon;
|
||||
|
||||
pa_droid_extcon *pa_droid_extcon_new(pa_core *, pa_card *);
|
||||
|
||||
void pa_droid_extcon_free(pa_droid_extcon *);
|
||||
|
||||
#endif
|
||||
278
src/droid/droid-extevdev.c
Normal file
278
src/droid/droid-extevdev.c
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
/***
|
||||
This file is part of PulseAudio.
|
||||
|
||||
Copyright (C) 2019 UBports foundation.
|
||||
Author(s): Ratchanan Srirattanamet <ratchanan@ubports.com>
|
||||
|
||||
PulseAudio is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published
|
||||
by the Free Software Foundation; either version 2.1 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
PulseAudio is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with PulseAudio; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
USA.
|
||||
***/
|
||||
|
||||
#define _GNU_SOURCE // For scandir and versionsort
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <libevdev/libevdev.h>
|
||||
|
||||
#include <pulsecore/core-util.h>
|
||||
#include <pulsecore/device-port.h>
|
||||
|
||||
#include "droid-extevdev.h"
|
||||
|
||||
#define DEV_INPUT_EVENT "/dev/input"
|
||||
#define EVENT_DEV_NAME "event"
|
||||
|
||||
#define N_ELEMENTS(X) (sizeof(X)/sizeof(*(X)))
|
||||
|
||||
struct pa_droid_extevdev {
|
||||
pa_card *card;
|
||||
struct libevdev *evdev_dev;
|
||||
pa_io_event *event;
|
||||
|
||||
/* Switch values */
|
||||
bool sw_headphone_insert : 1;
|
||||
bool sw_microphone_insert : 1;
|
||||
bool sw_lineout_insert : 1;
|
||||
};
|
||||
|
||||
static int is_event_device(const struct dirent *dir) {
|
||||
return strncmp(EVENT_DEV_NAME, dir->d_name, 5) == 0;
|
||||
}
|
||||
|
||||
static struct libevdev *find_switch_evdev(void) {
|
||||
struct dirent **namelist;
|
||||
int ndev, i;
|
||||
struct libevdev *ret = NULL;
|
||||
|
||||
ndev = scandir(DEV_INPUT_EVENT, &namelist, is_event_device, versionsort);
|
||||
|
||||
for (i=0; i<ndev; i++) {
|
||||
char fname[PATH_MAX];
|
||||
int fd;
|
||||
struct libevdev *dev;
|
||||
int err;
|
||||
|
||||
snprintf(fname, sizeof(fname),
|
||||
"%s/%s", DEV_INPUT_EVENT, namelist[i]->d_name);
|
||||
|
||||
pa_log_debug("Checking %s for headphone switch.", fname);
|
||||
|
||||
fd = open(fname, O_RDONLY|O_NONBLOCK);
|
||||
if (fd < 0) {
|
||||
err = errno;
|
||||
pa_log_warn("Unable to open device %s, ignored: %s",
|
||||
fname, strerror(err));
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((err = libevdev_new_from_fd(fd, &dev)) < 0) {
|
||||
err = -err;
|
||||
pa_log_warn("Unable to create libevdev device for %s, ignored: %s",
|
||||
fname, strerror(err));
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (libevdev_has_event_code(dev, EV_SW, SW_HEADPHONE_INSERT)) {
|
||||
ret = dev;
|
||||
break;
|
||||
}
|
||||
|
||||
libevdev_free(dev);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
for (i=0; i<ndev; i++)
|
||||
free(namelist[i]);
|
||||
free(namelist);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Put the port we want to be active (for each direction) later in the list.
|
||||
* module-switch-on-port-available will switch to the available port as it
|
||||
* become available, so the last port available will stay active. */
|
||||
|
||||
static const char *headphone_ports[] = {
|
||||
"output-speaker+wired_headphone",
|
||||
"output-wired_headphone",
|
||||
};
|
||||
|
||||
static const char *headset_ports[] = {
|
||||
"output-wired_headset",
|
||||
"input-wired_headset",
|
||||
};
|
||||
|
||||
static void notify_ports(pa_droid_extevdev *u) {
|
||||
unsigned int i;
|
||||
|
||||
pa_log_debug("headphone: %d, microphone: %d, lineout: %d, yes: %d, no: %d", u->sw_headphone_insert,
|
||||
u->sw_microphone_insert, u->sw_lineout_insert, PA_AVAILABLE_YES, PA_AVAILABLE_NO);
|
||||
|
||||
pa_available_t has_headphone =
|
||||
((u->sw_headphone_insert || u->sw_lineout_insert)
|
||||
&& !u->sw_microphone_insert) ? PA_AVAILABLE_YES : PA_AVAILABLE_NO;
|
||||
|
||||
pa_log_debug("has_headphone: %d", has_headphone);
|
||||
|
||||
for (i=0; i < N_ELEMENTS(headphone_ports); i++) {
|
||||
pa_device_port *p = pa_hashmap_get(u->card->ports, headphone_ports[i]);
|
||||
pa_log_debug("headphone device port %d, %p", i, p);
|
||||
if (p)
|
||||
pa_device_port_set_available(p, has_headphone);
|
||||
}
|
||||
|
||||
pa_available_t has_headset =
|
||||
((u->sw_headphone_insert || u->sw_lineout_insert)
|
||||
&& u->sw_microphone_insert) ? PA_AVAILABLE_YES : PA_AVAILABLE_NO;
|
||||
|
||||
pa_log_debug("has_headset: %d", has_headset);
|
||||
|
||||
for (i=0; i < N_ELEMENTS(headset_ports); i++) {
|
||||
pa_device_port *p = pa_hashmap_get(u->card->ports, headset_ports[i]);
|
||||
if (p)
|
||||
pa_device_port_set_available(p, has_headset);
|
||||
}
|
||||
}
|
||||
|
||||
/* Called from IO context */
|
||||
static void evdev_cb(pa_mainloop_api *a, pa_io_event *e, int fd,
|
||||
pa_io_event_flags_t events, void *userdata) {
|
||||
pa_droid_extevdev *u = userdata;
|
||||
|
||||
unsigned int flags = LIBEVDEV_READ_FLAG_NORMAL;
|
||||
int err;
|
||||
struct input_event ev;
|
||||
|
||||
pa_log_debug("EV callback start...");
|
||||
|
||||
while (1) {
|
||||
err = libevdev_next_event(u->evdev_dev, flags, &ev);
|
||||
|
||||
if (err == -EAGAIN) {
|
||||
if (flags == LIBEVDEV_READ_FLAG_SYNC) {
|
||||
/* Switch the flag back to read next normal events. */
|
||||
flags = LIBEVDEV_READ_FLAG_NORMAL;
|
||||
continue;
|
||||
} else {
|
||||
/* We run out of event. */
|
||||
break;
|
||||
}
|
||||
} else if (err == LIBEVDEV_READ_STATUS_SYNC) {
|
||||
if (flags == LIBEVDEV_READ_FLAG_NORMAL) {
|
||||
/* Handle dropped events by switching to SYNC mode. */
|
||||
flags = LIBEVDEV_READ_FLAG_SYNC;
|
||||
continue;
|
||||
} /* Otherwise we're in the middle of handling it. */
|
||||
} else if (err < 0) {
|
||||
pa_log_error("Error in reading the event from evdev: %s",
|
||||
strerror(-err));
|
||||
/* TODO: Should we just remove the event source? */
|
||||
break;
|
||||
}
|
||||
|
||||
/* ev now contains the current event. */
|
||||
if (ev.type == EV_SW) {
|
||||
switch (ev.code) {
|
||||
case SW_HEADPHONE_INSERT:
|
||||
pa_log_debug("Headphone Insert %d", ev.value);
|
||||
u->sw_headphone_insert = ev.value;
|
||||
break;
|
||||
case SW_MICROPHONE_INSERT:
|
||||
pa_log_debug("Microphone Insert %d", ev.value);
|
||||
u->sw_microphone_insert = ev.value;
|
||||
break;
|
||||
case SW_LINEOUT_INSERT:
|
||||
pa_log_debug("Lineout Insert %d", ev.value);
|
||||
u->sw_lineout_insert = ev.value;
|
||||
break;
|
||||
default:
|
||||
pa_log_debug("Unknown switch %d", ev.code);
|
||||
|
||||
/* Ignore unknown switch. */
|
||||
break;
|
||||
}
|
||||
} else if (ev.type == EV_SYN && ev.code == SYN_REPORT) {
|
||||
pa_log_debug("SYN Report");
|
||||
notify_ports(u);
|
||||
}
|
||||
}
|
||||
|
||||
pa_log_debug("EV callback end.");
|
||||
|
||||
}
|
||||
|
||||
static void read_initial_switch_values(pa_droid_extevdev *u) {
|
||||
/* A local variable is needed because sw_* are bitfields. */
|
||||
int value;
|
||||
|
||||
#define INIT_SW(code, sw_var) \
|
||||
if (libevdev_fetch_event_value(u->evdev_dev, EV_SW, code, &value)) \
|
||||
u->sw_var = value; \
|
||||
else \
|
||||
u->sw_var = false;
|
||||
|
||||
INIT_SW(SW_HEADPHONE_INSERT, sw_headphone_insert)
|
||||
INIT_SW(SW_MICROPHONE_INSERT, sw_microphone_insert)
|
||||
INIT_SW(SW_LINEOUT_INSERT, sw_lineout_insert)
|
||||
|
||||
#undef INIT_SW
|
||||
|
||||
notify_ports(u);
|
||||
}
|
||||
|
||||
pa_droid_extevdev *pa_droid_extevdev_new(pa_core *core, pa_card *card) {
|
||||
pa_droid_extevdev *u = pa_xnew0(pa_droid_extevdev, 1);
|
||||
|
||||
pa_assert(core);
|
||||
pa_assert(card);
|
||||
|
||||
u->card = card;
|
||||
u->evdev_dev = find_switch_evdev();
|
||||
|
||||
if (!u->evdev_dev)
|
||||
goto fail;
|
||||
|
||||
pa_assert_se(u->event = core->mainloop->io_new(core->mainloop,
|
||||
libevdev_get_fd(u->evdev_dev), PA_IO_EVENT_INPUT, evdev_cb, u));
|
||||
|
||||
read_initial_switch_values(u);
|
||||
|
||||
return u;
|
||||
|
||||
fail:
|
||||
pa_droid_extevdev_free(u);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void pa_droid_extevdev_free(pa_droid_extevdev *u) {
|
||||
if (u->event)
|
||||
u->card->core->mainloop->io_free(u->event);
|
||||
|
||||
if (u->evdev_dev) {
|
||||
int fd = libevdev_get_fd(u->evdev_dev);
|
||||
libevdev_free(u->evdev_dev);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
pa_xfree(u);
|
||||
}
|
||||
32
src/droid/droid-extevdev.h
Normal file
32
src/droid/droid-extevdev.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef foodroidextevdevhfoo
|
||||
#define foodroidextevdevhfoo
|
||||
|
||||
/***
|
||||
This file is part of PulseAudio.
|
||||
|
||||
Copyright (C) 2019 UBports foundation.
|
||||
Author(s): Ratchanan Srirattanamet <ratchanan@ubports.com>
|
||||
|
||||
PulseAudio is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published
|
||||
by the Free Software Foundation; either version 2.1 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
PulseAudio is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with PulseAudio; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
||||
USA.
|
||||
***/
|
||||
|
||||
typedef struct pa_droid_extevdev pa_droid_extevdev;
|
||||
|
||||
pa_droid_extevdev *pa_droid_extevdev_new(pa_core *, pa_card *);
|
||||
|
||||
void pa_droid_extevdev_free(pa_droid_extevdev *);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -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>
|
||||
*
|
||||
|
|
@ -51,6 +51,8 @@
|
|||
#include <pulsecore/rtpoll.h>
|
||||
#include <pulsecore/time-smoother.h>
|
||||
#include <pulsecore/resampler.h>
|
||||
#include <pulse/util.h>
|
||||
#include <pulse/version.h>
|
||||
|
||||
#include "droid-source.h"
|
||||
#include <droid/droid-util.h>
|
||||
|
|
@ -67,14 +69,11 @@ struct userdata {
|
|||
pa_rtpoll *rtpoll;
|
||||
|
||||
pa_memchunk memchunk;
|
||||
audio_devices_t primary_devices;
|
||||
|
||||
size_t source_buffer_size;
|
||||
size_t buffer_size;
|
||||
pa_usec_t timestamp;
|
||||
|
||||
pa_hook_slot *input_buffer_size_changed_slot;
|
||||
pa_hook_slot *input_channel_map_changed_slot;
|
||||
pa_resampler *resampler;
|
||||
|
||||
pa_droid_card_data *card_data;
|
||||
|
|
@ -83,10 +82,6 @@ struct userdata {
|
|||
bool stream_valid;
|
||||
};
|
||||
|
||||
enum {
|
||||
SOURCE_MESSAGE_DO_ROUTING = PA_SOURCE_MESSAGE_MAX
|
||||
};
|
||||
|
||||
#define DEFAULT_MODULE_ID "primary"
|
||||
|
||||
#define DROID_AUDIO_SOURCE "droid.audio_source"
|
||||
|
|
@ -95,53 +90,16 @@ enum {
|
|||
static void userdata_free(struct userdata *u);
|
||||
static int suspend(struct userdata *u);
|
||||
static void unsuspend(struct userdata *u);
|
||||
static void source_reconfigure(struct userdata *u,
|
||||
const pa_sample_spec *reconfigure_sample_spec,
|
||||
const pa_channel_map *reconfigure_channel_map,
|
||||
const pa_proplist *proplist,
|
||||
dm_config_port *update_device_port);
|
||||
|
||||
static int do_routing(struct userdata *u, audio_devices_t devices) {
|
||||
int ret;
|
||||
audio_devices_t old_device;
|
||||
|
||||
pa_assert(u);
|
||||
pa_assert(u->stream);
|
||||
|
||||
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;
|
||||
}
|
||||
/* Our droid source may be left in a state of not having an input stream
|
||||
* if reconfiguration fails and fallback to previously active values fails
|
||||
* as well. In this case just avoid using the stream but don't die. */
|
||||
#define assert_stream(x, action) if (!x) do { pa_log_warn("Assert " #x " failed."); action; } while(0)
|
||||
|
||||
static int thread_read(struct userdata *u) {
|
||||
void *p;
|
||||
|
|
@ -157,7 +115,7 @@ static int thread_read(struct userdata *u) {
|
|||
if (!u->stream_valid) {
|
||||
p = pa_memblock_acquire(chunk.memblock);
|
||||
chunk.length = pa_memblock_get_length(chunk.memblock);
|
||||
memset(p, 0, chunk.length);
|
||||
pa_silence_memory(p, chunk.length, &u->source->sample_spec);
|
||||
pa_source_post(u->source, &chunk);
|
||||
pa_memblock_release(chunk.memblock);
|
||||
goto end;
|
||||
|
|
@ -169,7 +127,7 @@ static int thread_read(struct userdata *u) {
|
|||
pa_memblock_release(chunk.memblock);
|
||||
|
||||
if (readd < 0) {
|
||||
pa_log("Failed to read from stream. (err %i)", readd);
|
||||
pa_log("Failed to read from stream. (err %zd)", readd);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
|
@ -208,7 +166,11 @@ static void thread_func(void *userdata) {
|
|||
pa_log_debug("Thread starting up.");
|
||||
|
||||
if (u->core->realtime_scheduling)
|
||||
#if PA_CHECK_VERSION(13,0,0)
|
||||
pa_thread_make_realtime(u->core->realtime_priority);
|
||||
#else
|
||||
pa_make_realtime(u->core->realtime_priority);
|
||||
#endif
|
||||
|
||||
pa_thread_mq_install(&u->thread_mq);
|
||||
|
||||
|
|
@ -225,11 +187,7 @@ static void thread_func(void *userdata) {
|
|||
pa_rtpoll_set_timer_disabled(u->rtpoll);
|
||||
|
||||
/* Sleep */
|
||||
#if (PULSEAUDIO_VERSION == 5)
|
||||
if ((ret = pa_rtpoll_run(u->rtpoll, true)) < 0)
|
||||
#elif (PULSEAUDIO_VERSION >= 6)
|
||||
if ((ret = pa_rtpoll_run(u->rtpoll)) < 0)
|
||||
#endif
|
||||
goto fail;
|
||||
|
||||
if (ret == 0)
|
||||
|
|
@ -252,7 +210,7 @@ static int suspend(struct userdata *u) {
|
|||
int ret;
|
||||
|
||||
pa_assert(u);
|
||||
pa_assert(u->stream);
|
||||
assert_stream(u->stream, return 0);
|
||||
|
||||
ret = pa_droid_stream_suspend(u->stream, true);
|
||||
|
||||
|
|
@ -265,9 +223,10 @@ static int suspend(struct userdata *u) {
|
|||
/* Called from IO context */
|
||||
static void unsuspend(struct userdata *u) {
|
||||
pa_assert(u);
|
||||
pa_assert(u->stream);
|
||||
|
||||
if (pa_droid_stream_suspend(u->stream, false) >= 0) {
|
||||
if (!u->stream) {
|
||||
assert_stream(u->stream, u->stream_valid = false);
|
||||
} else if (pa_droid_stream_suspend(u->stream, false) >= 0) {
|
||||
u->stream_valid = true;
|
||||
pa_log_info("Resuming...");
|
||||
} else
|
||||
|
|
@ -319,32 +278,6 @@ static int source_set_state_in_io_thread_cb(pa_source *s, pa_source_state_t new_
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Called from IO context */
|
||||
static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
|
||||
struct userdata *u = PA_SOURCE(o)->userdata;
|
||||
|
||||
switch (code) {
|
||||
case SOURCE_MESSAGE_DO_ROUTING: {
|
||||
audio_devices_t device = PA_PTR_TO_UINT(data);
|
||||
|
||||
pa_assert(PA_SOURCE_IS_OPENED(u->source->thread_info.state));
|
||||
|
||||
suspend(u);
|
||||
do_routing(u, device);
|
||||
unsuspend(u);
|
||||
break;
|
||||
}
|
||||
|
||||
#if PULSEAUDIO_VERSION < 12
|
||||
case PA_SOURCE_MESSAGE_SET_STATE: {
|
||||
return source_set_state_in_io_thread_cb(u->source, PA_PTR_TO_UINT(data), 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return pa_source_process_msg(o, code, data, offset, chunk);
|
||||
}
|
||||
|
||||
static int source_set_port_cb(pa_source *s, pa_device_port *p) {
|
||||
struct userdata *u = s->userdata;
|
||||
pa_droid_port_data *data;
|
||||
|
|
@ -354,7 +287,7 @@ static int source_set_port_cb(pa_source *s, pa_device_port *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.
|
||||
* Then next port change can be whatever source port, even the one enabled
|
||||
* before parking. */
|
||||
|
|
@ -362,13 +295,12 @@ static int source_set_port_cb(pa_source *s, pa_device_port *p) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
pa_log_debug("Source set port %u", data->device);
|
||||
pa_log_debug("Source set port %#010x (%s)", data->device_port->type, data->device_port->name);
|
||||
|
||||
if (!PA_SOURCE_IS_OPENED(pa_source_get_state(u->source)))
|
||||
do_routing(u, data->device);
|
||||
else {
|
||||
pa_asyncmsgq_post(u->source->asyncmsgq, PA_MSGOBJECT(u->source), SOURCE_MESSAGE_DO_ROUTING, PA_UINT_TO_PTR(data->device), 0, NULL, NULL);
|
||||
}
|
||||
if (!PA_SOURCE_IS_OPENED(u->source->state))
|
||||
pa_droid_stream_set_route(u->stream, data->device_port);
|
||||
else
|
||||
source_reconfigure(u, NULL, NULL, NULL, data->device_port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -394,60 +326,30 @@ static void source_set_name(pa_modargs *ma, pa_source_new_data *data, const char
|
|||
}
|
||||
}
|
||||
|
||||
#if (PULSEAUDIO_VERSION == 5)
|
||||
static void source_get_mute_cb(pa_source *s) {
|
||||
#elif (PULSEAUDIO_VERSION >= 6)
|
||||
static int source_get_mute_cb(pa_source *s, bool *muted) {
|
||||
#endif
|
||||
struct userdata *u = s->userdata;
|
||||
int ret = 0;
|
||||
bool b;
|
||||
|
||||
pa_assert(u);
|
||||
pa_assert(u->hw_module && u->hw_module->device);
|
||||
pa_assert(u->hw_module);
|
||||
|
||||
pa_droid_hw_module_lock(u->hw_module);
|
||||
if (u->hw_module->device->get_mic_mute(u->hw_module->device, &b) < 0) {
|
||||
pa_log("Failed to get mute state.");
|
||||
ret = -1;
|
||||
}
|
||||
pa_droid_hw_module_unlock(u->hw_module);
|
||||
|
||||
#if (PULSEAUDIO_VERSION == 5)
|
||||
if (ret == 0)
|
||||
s->muted = b;
|
||||
#elif (PULSEAUDIO_VERSION >= 6)
|
||||
if (ret == 0)
|
||||
*muted = b;
|
||||
|
||||
return ret;
|
||||
#endif
|
||||
return pa_droid_hw_mic_get_mute(u->hw_module, muted);
|
||||
}
|
||||
|
||||
static void source_set_mute_cb(pa_source *s) {
|
||||
struct userdata *u = s->userdata;
|
||||
|
||||
pa_assert(u);
|
||||
pa_assert(u->hw_module && u->hw_module->device);
|
||||
|
||||
pa_droid_hw_module_lock(u->hw_module);
|
||||
if (u->hw_module->device->set_mic_mute(u->hw_module->device, s->muted) < 0)
|
||||
pa_log("Failed to set mute state to %smuted.", s->muted ? "" : "un");
|
||||
pa_droid_hw_module_unlock(u->hw_module);
|
||||
pa_droid_hw_mic_set_mute(u->hw_module, s->muted);
|
||||
}
|
||||
|
||||
static void source_set_mute_control(struct userdata *u) {
|
||||
pa_assert(u);
|
||||
pa_assert(u->hw_module && u->hw_module->device);
|
||||
|
||||
if (u->hw_module->device->set_mic_mute) {
|
||||
pa_log_info("Using hardware mute control for %s", u->source->name);
|
||||
if (pa_droid_hw_has_mic_control(u->hw_module)) {
|
||||
pa_source_set_get_mute_callback(u->source, source_get_mute_cb);
|
||||
pa_source_set_set_mute_callback(u->source, source_set_mute_cb);
|
||||
} else {
|
||||
pa_log_info("Using software mute control for %s", u->source->name);
|
||||
pa_source_set_get_mute_callback(u->source, NULL);
|
||||
pa_source_set_set_mute_callback(u->source, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -455,73 +357,148 @@ static void source_set_mute_control(struct userdata *u) {
|
|||
static void update_latency(struct userdata *u) {
|
||||
pa_assert(u);
|
||||
pa_assert(u->source);
|
||||
pa_assert(u->stream);
|
||||
|
||||
u->buffer_size = pa_droid_stream_buffer_size(u->stream);
|
||||
if (u->stream)
|
||||
u->buffer_size = pa_droid_stream_buffer_size(u->stream);
|
||||
else
|
||||
u->buffer_size = 1024; /* Random valid value */
|
||||
|
||||
assert_stream(u->stream, return);
|
||||
|
||||
if (u->source_buffer_size) {
|
||||
u->buffer_size = pa_droid_buffer_size_round_up(u->source_buffer_size, u->buffer_size);
|
||||
pa_log_info("Using buffer size %u (requested %u).", u->buffer_size, u->source_buffer_size);
|
||||
pa_log_info("Using buffer size %zu (requested %zu).", u->buffer_size, u->source_buffer_size);
|
||||
} else
|
||||
pa_log_info("Using buffer size %u.", u->buffer_size);
|
||||
pa_log_info("Using buffer size %zu.", u->buffer_size);
|
||||
|
||||
if (pa_thread_mq_get())
|
||||
pa_source_set_fixed_latency_within_thread(u->source, pa_bytes_to_usec(u->buffer_size, &u->stream->input->sample_spec));
|
||||
pa_source_set_fixed_latency_within_thread(u->source, pa_bytes_to_usec(u->buffer_size, pa_droid_stream_sample_spec(u->stream)));
|
||||
else
|
||||
pa_source_set_fixed_latency(u->source, pa_bytes_to_usec(u->buffer_size, &u->stream->input->sample_spec));
|
||||
pa_source_set_fixed_latency(u->source, pa_bytes_to_usec(u->buffer_size, pa_droid_stream_sample_spec(u->stream)));
|
||||
|
||||
pa_log_debug("Set fixed latency %" PRIu64 " usec", pa_bytes_to_usec(u->buffer_size, &u->stream->input->sample_spec));
|
||||
pa_log_debug("Set fixed latency %" PRIu64 " usec", pa_bytes_to_usec(u->buffer_size, pa_droid_stream_sample_spec(u->stream)));
|
||||
}
|
||||
|
||||
/* Called from IO context. */
|
||||
static pa_hook_result_t input_buffer_size_changed_cb(pa_droid_hw_module *module,
|
||||
pa_droid_stream *stream,
|
||||
struct userdata *u) {
|
||||
pa_assert(module);
|
||||
pa_assert(stream);
|
||||
pa_assert(u);
|
||||
static void source_reconfigure(struct userdata *u,
|
||||
const pa_sample_spec *reconfigure_sample_spec,
|
||||
const pa_channel_map *reconfigure_channel_map,
|
||||
const pa_proplist *proplist,
|
||||
dm_config_port *update_device_port) {
|
||||
pa_channel_map old_channel_map;
|
||||
pa_sample_spec old_sample_spec;
|
||||
pa_channel_map new_channel_map;
|
||||
pa_sample_spec new_sample_spec;
|
||||
pa_queue *source_outputs = NULL;
|
||||
|
||||
if (stream != u->stream)
|
||||
return PA_HOOK_OK;
|
||||
if (pa_source_used_by(u->source)) {
|
||||
/* If we already have connected source outputs detach those
|
||||
* so that when re-attaching them to our source resampling etc.
|
||||
* is renegotiated correctly. */
|
||||
source_outputs = pa_source_move_all_start(u->source, NULL);
|
||||
}
|
||||
|
||||
pa_source_suspend(u->source, true, PA_SUSPEND_UNAVAILABLE);
|
||||
|
||||
old_channel_map = *pa_droid_stream_channel_map(u->stream);
|
||||
old_sample_spec = *pa_droid_stream_sample_spec(u->stream);
|
||||
new_channel_map = reconfigure_channel_map ? *reconfigure_channel_map : old_channel_map;
|
||||
new_sample_spec = reconfigure_sample_spec ? *reconfigure_sample_spec : old_sample_spec;
|
||||
|
||||
if (update_device_port)
|
||||
pa_droid_stream_set_route(u->stream, update_device_port);
|
||||
|
||||
if (pa_droid_stream_reconfigure_input(u->stream, &new_sample_spec, &new_channel_map, proplist))
|
||||
pa_log_info("Source reconfigured.");
|
||||
else
|
||||
pa_log_info("Failed to reconfigure input stream, no worries, using defaults.");
|
||||
|
||||
/* We need to be really careful here as we are modifying
|
||||
* quite profound internal structures. */
|
||||
new_sample_spec = *pa_droid_stream_sample_spec(u->stream);
|
||||
new_channel_map = *pa_droid_stream_channel_map(u->stream);
|
||||
u->source->channel_map = new_channel_map;
|
||||
u->source->sample_spec = new_sample_spec;
|
||||
pa_assert_se(pa_cvolume_remap(&u->source->reference_volume, &old_channel_map, &new_channel_map));
|
||||
pa_assert_se(pa_cvolume_remap(&u->source->real_volume, &old_channel_map, &new_channel_map));
|
||||
pa_assert_se(pa_cvolume_remap(&u->source->soft_volume, &old_channel_map, &new_channel_map));
|
||||
|
||||
update_latency(u);
|
||||
pa_source_suspend(u->source, false, PA_SUSPEND_UNAVAILABLE);
|
||||
|
||||
if (source_outputs && u->source) {
|
||||
pa_source_move_all_finish(u->source, source_outputs, false);
|
||||
}
|
||||
}
|
||||
|
||||
static pa_hook_result_t source_output_new_hook_callback(void *hook_data,
|
||||
void *call_data,
|
||||
void *slot_data) {
|
||||
pa_source_output_new_data *new_data = call_data;
|
||||
struct userdata *u = slot_data;
|
||||
pa_droid_stream *primary_output;
|
||||
|
||||
/* Not meant for us */
|
||||
if (new_data->source != u->source)
|
||||
return PA_HOOK_OK;
|
||||
|
||||
if (!pa_droid_stream_reconfigure_input_needed(u->stream,
|
||||
&new_data->sample_spec,
|
||||
&new_data->channel_map,
|
||||
new_data->proplist))
|
||||
return PA_HOOK_OK;
|
||||
|
||||
pa_log_info("New source-output connecting and our source needs to be reconfigured.");
|
||||
|
||||
/* Workaround for fm-radio loopback */
|
||||
if (pa_safe_streq(pa_proplist_gets(new_data->proplist, "media.name"), "fmradio-loopback-source") &&
|
||||
(primary_output = pa_droid_hw_primary_output_stream(u->hw_module))) {
|
||||
pa_log_debug("Workaround for fm-radio loopback.");
|
||||
source_reconfigure(u,
|
||||
pa_droid_stream_sample_spec(primary_output),
|
||||
pa_droid_stream_channel_map(primary_output),
|
||||
new_data->proplist,
|
||||
NULL);
|
||||
|
||||
} else
|
||||
source_reconfigure(u, &new_data->sample_spec, &new_data->channel_map, new_data->proplist, NULL);
|
||||
|
||||
return PA_HOOK_OK;
|
||||
}
|
||||
|
||||
/* Called from IO context. */
|
||||
static pa_hook_result_t input_channel_map_changed_cb(pa_droid_hw_module *module,
|
||||
pa_droid_stream *stream,
|
||||
struct userdata *u) {
|
||||
pa_assert(module);
|
||||
pa_assert(stream);
|
||||
pa_assert(u);
|
||||
static void source_reconfigure_after_changes(struct userdata *u) {
|
||||
pa_source_output *so = NULL;
|
||||
pa_source_output *so_i;
|
||||
void *state = NULL;
|
||||
|
||||
if (stream != u->stream)
|
||||
return PA_HOOK_OK;
|
||||
if (!pa_source_used_by(u->source))
|
||||
return;
|
||||
|
||||
if (u->stream->input->input_channel_map.channels != u->source->channel_map.channels) {
|
||||
if (u->resampler)
|
||||
pa_resampler_free(u->resampler);
|
||||
|
||||
u->resampler = pa_resampler_new(u->core->mempool,
|
||||
&u->stream->input->input_sample_spec, &u->stream->input->input_channel_map,
|
||||
&u->source->sample_spec, &u->source->channel_map,
|
||||
u->core->lfe_crossover_freq,
|
||||
PA_RESAMPLER_COPY,
|
||||
0);
|
||||
} else if (u->resampler) {
|
||||
pa_resampler_free(u->resampler);
|
||||
u->resampler = NULL;
|
||||
/* Find last inserted source-output */
|
||||
so = pa_idxset_iterate(u->source->outputs, &state, NULL);
|
||||
if (so) {
|
||||
while ((so_i = pa_idxset_iterate(u->source->outputs, &state, NULL)))
|
||||
so = so_i;
|
||||
}
|
||||
|
||||
if (so && pa_droid_stream_reconfigure_input_needed(u->stream,
|
||||
&so->sample_spec,
|
||||
&so->channel_map,
|
||||
so->proplist)) {
|
||||
pa_log_info("Source-output disconnected and our source needs to be reconfigured.");
|
||||
source_reconfigure(u, &so->sample_spec, &so->channel_map, so->proplist, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static pa_hook_result_t source_output_unlink_post_hook_callback(void *hook_data,
|
||||
void *call_data,
|
||||
void *slot_data) {
|
||||
source_reconfigure_after_changes(slot_data);
|
||||
return PA_HOOK_OK;
|
||||
}
|
||||
|
||||
pa_source *pa_droid_source_new(pa_module *m,
|
||||
pa_modargs *ma,
|
||||
const char *driver,
|
||||
audio_devices_t device,
|
||||
pa_droid_card_data *card_data,
|
||||
pa_droid_mapping *am,
|
||||
pa_card *card) {
|
||||
|
|
@ -530,23 +507,22 @@ pa_source *pa_droid_source_new(pa_module *m,
|
|||
char *thread_name = NULL;
|
||||
pa_source_new_data data;
|
||||
const char *module_id = NULL;
|
||||
const char *tmp;
|
||||
uint32_t alternate_sample_rate;
|
||||
audio_devices_t dev_in;
|
||||
pa_sample_spec sample_spec;
|
||||
pa_channel_map channel_map;
|
||||
const char *format;
|
||||
bool namereg_fail = false;
|
||||
pa_droid_config_audio *config = NULL; /* Only used when source is created without card */
|
||||
uint32_t source_buffer = 0;
|
||||
|
||||
pa_assert(m);
|
||||
pa_assert(ma);
|
||||
pa_assert(driver);
|
||||
|
||||
pa_log_info("Create new droid-source");
|
||||
|
||||
/* When running under card use hw module name for source by default. */
|
||||
if (am)
|
||||
module_id = am->input->module->name;
|
||||
module_id = am->mix_port->name;
|
||||
else
|
||||
module_id = pa_modargs_get_value(ma, "module_id", DEFAULT_MODULE_ID);
|
||||
|
||||
|
|
@ -611,46 +587,13 @@ pa_source *pa_droid_source_new(pa_module *m,
|
|||
pa_assert_se((u->hw_module = pa_droid_hw_module_get(u->core, NULL, card_data->module_id)));
|
||||
} else {
|
||||
/* Source wasn't created from inside card module, so we'll need to open
|
||||
* hw module ourself.
|
||||
*
|
||||
* First let's find out if hw module has already been opened, or if we need to
|
||||
* do it ourself. */
|
||||
if (!(u->hw_module = pa_droid_hw_module_get(u->core, NULL, module_id))) {
|
||||
if (!(config = pa_droid_config_load(ma)))
|
||||
goto fail;
|
||||
* hw module ourself. */
|
||||
|
||||
if (!(u->hw_module = pa_droid_hw_module_get(u->core, config, module_id)))
|
||||
goto fail;
|
||||
|
||||
pa_droid_config_free(config);
|
||||
config = NULL;
|
||||
}
|
||||
if (!(u->hw_module = pa_droid_hw_module_get2(u->core, ma, module_id)))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Default routing */
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if (am)
|
||||
u->stream = pa_droid_open_input_stream(u->hw_module, &sample_spec, &channel_map, dev_in, am);
|
||||
else
|
||||
u->stream = pa_droid_open_input_stream(u->hw_module, &sample_spec, &channel_map, dev_in, NULL);
|
||||
u->stream = pa_droid_open_input_stream(u->hw_module, &sample_spec, &channel_map, am->mix_port->name);
|
||||
|
||||
if (!u->stream) {
|
||||
pa_log("Failed to open input stream.");
|
||||
|
|
@ -661,6 +604,7 @@ pa_source *pa_droid_source_new(pa_module *m,
|
|||
data.driver = driver;
|
||||
data.module = m;
|
||||
data.card = card;
|
||||
/* Start suspended */
|
||||
data.suspend_cause = PA_SUSPEND_IDLE;
|
||||
|
||||
if (am)
|
||||
|
|
@ -670,6 +614,8 @@ pa_source *pa_droid_source_new(pa_module *m,
|
|||
|
||||
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "sound");
|
||||
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_API, PROP_DROID_API_STRING);
|
||||
pa_proplist_sets(data.proplist, PROP_DROID_INPUT_EXTERNAL, "true");
|
||||
pa_proplist_sets(data.proplist, PROP_DROID_INPUT_BUILTIN, "true");
|
||||
|
||||
/* We need to give pa_modargs_get_value_boolean() a pointer to a local
|
||||
* variable instead of using &data.namereg_fail directly, because
|
||||
|
|
@ -683,8 +629,8 @@ pa_source *pa_droid_source_new(pa_module *m,
|
|||
}
|
||||
data.namereg_fail = namereg_fail;
|
||||
|
||||
pa_source_new_data_set_sample_spec(&data, &u->stream->input->sample_spec);
|
||||
pa_source_new_data_set_channel_map(&data, &u->stream->input->channel_map);
|
||||
pa_source_new_data_set_sample_spec(&data, pa_droid_stream_sample_spec(u->stream));
|
||||
pa_source_new_data_set_channel_map(&data, pa_droid_stream_channel_map(u->stream));
|
||||
pa_source_new_data_set_alternate_sample_rate(&data, alternate_sample_rate);
|
||||
|
||||
if (am && card)
|
||||
|
|
@ -700,10 +646,8 @@ pa_source *pa_droid_source_new(pa_module *m,
|
|||
|
||||
u->source->userdata = u;
|
||||
|
||||
u->source->parent.process_msg = source_process_msg;
|
||||
#if PULSEAUDIO_VERSION >= 12
|
||||
u->source->parent.process_msg = pa_source_process_msg;
|
||||
u->source->set_state_in_io_thread = source_set_state_in_io_thread_cb;
|
||||
#endif
|
||||
|
||||
source_set_mute_control(u);
|
||||
|
||||
|
|
@ -728,21 +672,26 @@ pa_source *pa_droid_source_new(pa_module *m,
|
|||
if (u->source->active_port)
|
||||
source_set_port_cb(u->source, u->source->active_port);
|
||||
|
||||
u->input_buffer_size_changed_slot = pa_hook_connect(&pa_droid_hooks(u->hw_module)[PA_DROID_HOOK_INPUT_BUFFER_SIZE_CHANGED],
|
||||
PA_HOOK_NORMAL,
|
||||
(pa_hook_cb_t) input_buffer_size_changed_cb, u);
|
||||
|
||||
u->input_channel_map_changed_slot = pa_hook_connect(&pa_droid_hooks(u->hw_module)[PA_DROID_HOOK_INPUT_CHANNEL_MAP_CHANGED],
|
||||
PA_HOOK_NORMAL,
|
||||
(pa_hook_cb_t) input_channel_map_changed_cb, u);
|
||||
/* Since we started in suspended mode suspend our stream immediately as well. */
|
||||
pa_droid_stream_suspend(u->stream, true);
|
||||
|
||||
pa_droid_stream_set_data(u->stream, u->source);
|
||||
pa_source_put(u->source);
|
||||
|
||||
/* As late as possible */
|
||||
pa_module_hook_connect(u->module,
|
||||
&u->module->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_NEW],
|
||||
PA_HOOK_LATE * 2,
|
||||
source_output_new_hook_callback, u);
|
||||
|
||||
pa_module_hook_connect(u->module,
|
||||
&u->module->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK_POST],
|
||||
PA_HOOK_LATE * 2,
|
||||
source_output_unlink_post_hook_callback, u);
|
||||
|
||||
return u->source;
|
||||
|
||||
fail:
|
||||
pa_droid_config_free(config);
|
||||
pa_xfree(thread_name);
|
||||
|
||||
if (u)
|
||||
|
|
@ -763,12 +712,6 @@ void pa_droid_source_free(pa_source *s) {
|
|||
static void userdata_free(struct userdata *u) {
|
||||
pa_assert(u);
|
||||
|
||||
if (u->input_channel_map_changed_slot)
|
||||
pa_hook_slot_free(u->input_channel_map_changed_slot);
|
||||
|
||||
if (u->input_buffer_size_changed_slot)
|
||||
pa_hook_slot_free(u->input_buffer_size_changed_slot);
|
||||
|
||||
if (u->source)
|
||||
pa_source_unlink(u->source);
|
||||
|
||||
|
|
@ -788,7 +731,6 @@ static void userdata_free(struct userdata *u) {
|
|||
if (u->stream)
|
||||
pa_droid_stream_unref(u->stream);
|
||||
|
||||
// Stand alone source
|
||||
if (u->hw_module)
|
||||
pa_droid_hw_module_unref(u->hw_module);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#define foodroidsourcefoo
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013-2018 Jolla Ltd.
|
||||
* Copyright (C) 2013-2022 Jolla Ltd.
|
||||
*
|
||||
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
||||
*
|
||||
|
|
@ -43,11 +43,9 @@
|
|||
|
||||
#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_modargs *ma,
|
||||
const char *driver,
|
||||
audio_devices_t device,
|
||||
pa_droid_card_data *card_data,
|
||||
pa_droid_mapping *am,
|
||||
pa_card *card);
|
||||
|
|
|
|||
|
|
@ -1,243 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2013-2018 Jolla Ltd.
|
||||
*
|
||||
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
||||
*
|
||||
* These PulseAudio Modules are free software; you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef HAVE_VALGRIND_MEMCHECK_H
|
||||
#include <valgrind/memcheck.h>
|
||||
#endif
|
||||
|
||||
#include <pulse/rtclock.h>
|
||||
#include <pulse/timeval.h>
|
||||
#include <pulse/xmalloc.h>
|
||||
|
||||
#include <pulsecore/core.h>
|
||||
#include <pulsecore/core-error.h>
|
||||
#include <pulsecore/dbus-shared.h>
|
||||
#include <pulsecore/dbus-util.h>
|
||||
#include <pulsecore/atomic.h>
|
||||
|
||||
#include "keepalive.h"
|
||||
|
||||
#define MCE_BUS (DBUS_BUS_SYSTEM)
|
||||
#define MCE_DBUS_NAME "com.nokia.mce"
|
||||
#define MCE_DBUS_PATH "/com/nokia/mce/request"
|
||||
#define MCE_DBUS_IFACE "com.nokia.mce.request"
|
||||
#define MCE_DBUS_KEEPALIVE_PERIOD_REQ "req_cpu_keepalive_period"
|
||||
#define MCE_DBUS_KEEPALIVE_START_REQ "req_cpu_keepalive_start"
|
||||
#define MCE_DBUS_KEEPALIVE_STOP_REQ "req_cpu_keepalive_stop"
|
||||
|
||||
struct pa_droid_keepalive {
|
||||
pa_core *core;
|
||||
pa_dbus_connection *dbus_connection;
|
||||
DBusPendingCall *pending;
|
||||
|
||||
pa_atomic_t started;
|
||||
pa_usec_t timeout;
|
||||
pa_time_event *timer_event;
|
||||
|
||||
};
|
||||
|
||||
pa_droid_keepalive* pa_droid_keepalive_new(pa_core *c) {
|
||||
pa_droid_keepalive *k;
|
||||
pa_dbus_connection *dbus;
|
||||
DBusError error;
|
||||
|
||||
pa_assert(c);
|
||||
|
||||
dbus_error_init(&error);
|
||||
|
||||
dbus = pa_dbus_bus_get(c, MCE_BUS, &error);
|
||||
if (dbus_error_is_set(&error)) {
|
||||
pa_log("Failed to get %s bus: %s", MCE_BUS == DBUS_BUS_SESSION ? "session" : "system", error.message);
|
||||
dbus_error_free(&error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
k = pa_xnew0(pa_droid_keepalive, 1);
|
||||
k->core = c;
|
||||
k->dbus_connection = dbus;
|
||||
k->timeout = 0;
|
||||
pa_atomic_store(&k->started, 0);
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
static void send_dbus_signal(pa_dbus_connection *dbus) {
|
||||
DBusMessage *msg;
|
||||
|
||||
pa_assert(dbus);
|
||||
|
||||
/* pa_log_debug("Send keepalive heartbeat."); */
|
||||
|
||||
pa_assert_se((msg = dbus_message_new_method_call(MCE_DBUS_NAME,
|
||||
MCE_DBUS_PATH,
|
||||
MCE_DBUS_IFACE,
|
||||
MCE_DBUS_KEEPALIVE_START_REQ)));
|
||||
|
||||
dbus_connection_send(pa_dbus_connection_get(dbus), msg, NULL);
|
||||
dbus_message_unref(msg);
|
||||
}
|
||||
|
||||
static void keepalive_cb(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) {
|
||||
pa_droid_keepalive *k = userdata;
|
||||
|
||||
pa_assert(k);
|
||||
pa_assert(k->timer_event == e);
|
||||
|
||||
send_dbus_signal(k->dbus_connection);
|
||||
pa_core_rttime_restart(k->core, k->timer_event, pa_rtclock_now() + k->timeout);
|
||||
}
|
||||
|
||||
static void keepalive_start(pa_droid_keepalive *k) {
|
||||
pa_assert(k);
|
||||
pa_assert(k->timeout);
|
||||
pa_assert(!k->timer_event);
|
||||
|
||||
pa_log_info("Start keepalive heartbeat with interval %lu seconds.", (unsigned long) (k->timeout / PA_USEC_PER_SEC));
|
||||
|
||||
/* Send first keepalive heartbeat immediately. */
|
||||
send_dbus_signal(k->dbus_connection);
|
||||
|
||||
k->timer_event = pa_core_rttime_new(k->core, pa_rtclock_now() + k->timeout, keepalive_cb, k);
|
||||
}
|
||||
|
||||
static void pending_req_reply_cb(DBusPendingCall *pending, void *userdata) {
|
||||
pa_droid_keepalive *k = userdata;
|
||||
DBusMessage *msg;
|
||||
uint32_t period;
|
||||
|
||||
pa_assert(pending);
|
||||
pa_assert(k);
|
||||
pa_assert(pending == k->pending);
|
||||
|
||||
k->pending = NULL;
|
||||
pa_assert_se(msg = dbus_pending_call_steal_reply(pending));
|
||||
|
||||
if (dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_ERROR) {
|
||||
pa_log("Failed to get %s", MCE_DBUS_KEEPALIVE_PERIOD_REQ);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
pa_assert_se(dbus_message_get_args(msg, NULL,
|
||||
DBUS_TYPE_INT32, &period,
|
||||
DBUS_TYPE_INVALID));
|
||||
|
||||
k->timeout = PA_USEC_PER_SEC * period;
|
||||
|
||||
keepalive_start(k);
|
||||
|
||||
finish:
|
||||
dbus_message_unref(msg);
|
||||
dbus_pending_call_unref(pending);
|
||||
}
|
||||
|
||||
void pa_droid_keepalive_start(pa_droid_keepalive *k) {
|
||||
DBusMessage *msg = NULL;
|
||||
|
||||
pa_assert(k);
|
||||
|
||||
/* Only allow first call go through. pa_atomic_inc() returns previous value before incrementing. */
|
||||
if (pa_atomic_inc(&k->started) > 0)
|
||||
return;
|
||||
|
||||
pa_assert(!k->timer_event);
|
||||
pa_assert(!k->pending);
|
||||
|
||||
/* Period time already requested, just start hearbeat. */
|
||||
if (k->timeout > 0) {
|
||||
keepalive_start(k);
|
||||
return;
|
||||
}
|
||||
|
||||
pa_log_debug("Starting keepalive - Request keepalive period.");
|
||||
/* Send first keepalive heartbeat immediately. */
|
||||
send_dbus_signal(k->dbus_connection);
|
||||
|
||||
pa_assert_se((msg = dbus_message_new_method_call(MCE_DBUS_NAME,
|
||||
MCE_DBUS_PATH,
|
||||
MCE_DBUS_IFACE,
|
||||
MCE_DBUS_KEEPALIVE_PERIOD_REQ)));
|
||||
|
||||
dbus_connection_send_with_reply(pa_dbus_connection_get(k->dbus_connection), msg, &k->pending, -1);
|
||||
dbus_message_unref(msg);
|
||||
|
||||
if (k->pending)
|
||||
dbus_pending_call_set_notify(k->pending, pending_req_reply_cb, k, NULL);
|
||||
else
|
||||
pa_log("D-Bus method call failed.");
|
||||
}
|
||||
|
||||
void pa_droid_keepalive_stop(pa_droid_keepalive *k) {
|
||||
DBusMessage *msg;
|
||||
|
||||
pa_assert(k);
|
||||
|
||||
/* Only allow last call go through. pa_atomic_dec() returns previous value before decrementing. */
|
||||
if (pa_atomic_dec(&k->started) != 1)
|
||||
return;
|
||||
|
||||
pa_assert(pa_atomic_load(&k->started) == 0);
|
||||
|
||||
pa_log_debug("Stopping keepalive.");
|
||||
|
||||
if (k->pending) {
|
||||
dbus_pending_call_cancel(k->pending);
|
||||
dbus_pending_call_unref(k->pending);
|
||||
k->pending = NULL;
|
||||
}
|
||||
|
||||
if (k->timer_event) {
|
||||
k->core->mainloop->time_free(k->timer_event);
|
||||
k->timer_event = NULL;
|
||||
}
|
||||
|
||||
pa_assert_se((msg = dbus_message_new_method_call(MCE_DBUS_NAME,
|
||||
MCE_DBUS_PATH,
|
||||
MCE_DBUS_IFACE,
|
||||
MCE_DBUS_KEEPALIVE_STOP_REQ)));
|
||||
|
||||
dbus_connection_send(pa_dbus_connection_get(k->dbus_connection), msg, NULL);
|
||||
dbus_message_unref(msg);
|
||||
}
|
||||
|
||||
void pa_droid_keepalive_free(pa_droid_keepalive *k) {
|
||||
pa_assert(k);
|
||||
pa_assert(k->dbus_connection);
|
||||
|
||||
pa_assert(pa_atomic_load(&k->started) == 0);
|
||||
|
||||
if (k->timer_event)
|
||||
k->core->mainloop->time_free(k->timer_event);
|
||||
|
||||
if (k->pending) {
|
||||
dbus_pending_call_cancel(k->pending);
|
||||
dbus_pending_call_unref(k->pending);
|
||||
}
|
||||
|
||||
pa_dbus_connection_unref(k->dbus_connection);
|
||||
pa_xfree(k);
|
||||
}
|
||||
|
|
@ -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>
|
||||
*
|
||||
|
|
@ -60,10 +60,12 @@
|
|||
//#include <droid/system/audio_policy.h>
|
||||
|
||||
#include <droid/droid-util.h>
|
||||
#include <droid/sllist.h>
|
||||
#include <droid/utils.h>
|
||||
#include "droid-sink.h"
|
||||
#include "droid-source.h"
|
||||
|
||||
#include "module-droid-card-symdef.h"
|
||||
#include "droid-extcon.h"
|
||||
#include "droid-extevdev.h"
|
||||
|
||||
PA_MODULE_AUTHOR("Juho Hämäläinen");
|
||||
PA_MODULE_DESCRIPTION("Droid card");
|
||||
|
|
@ -74,16 +76,14 @@ PA_MODULE_USAGE(
|
|||
"source_name=<name for the source> "
|
||||
"namereg_fail=<when false attempt to synthesise new names if they are already taken> "
|
||||
"rate=<sample rate> "
|
||||
"output_flags=<flags for sink> "
|
||||
"module_id=<which droid hw module to load, default primary> "
|
||||
"voice_source_routing=<always true, parameter left for compatibility> "
|
||||
"deferred_volume=<synchronize software and hardware volume changes to avoid momentary jumps?> "
|
||||
"config=<location for droid audio configuration> "
|
||||
"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> "
|
||||
"default_profile=<boolean. create default profile for primary module or not. defaults to true> "
|
||||
"merge_inputs=<boolean. merge input streams to single source with default profile. defaults to true> "
|
||||
"quirks=<comma separated list of quirks to enable/disable>"
|
||||
"voice_virtual_stream=<true/false> create virtual stream for voice call volume control (default false)"
|
||||
"options=<comma separated list of options to enable/disable>"
|
||||
);
|
||||
|
||||
static const char* const valid_modargs[] = {
|
||||
|
|
@ -98,25 +98,19 @@ static const char* const valid_modargs[] = {
|
|||
"sink_rate",
|
||||
"sink_format",
|
||||
"sink_channel_map",
|
||||
"sink_mix_route",
|
||||
"source_rate",
|
||||
"source_format",
|
||||
"source_channel_map",
|
||||
"output_flags",
|
||||
"module_id",
|
||||
"voice_source_routing",
|
||||
"sink_buffer",
|
||||
"source_buffer",
|
||||
"deferred_volume",
|
||||
"mute_routing_before",
|
||||
"mute_routing_after",
|
||||
"prewrite_on_resume",
|
||||
"config",
|
||||
"voice_property_key",
|
||||
"voice_property_value",
|
||||
"default_profile",
|
||||
"combine",
|
||||
"quirks",
|
||||
"voice_virtual_stream",
|
||||
/* DM_OPTIONS */
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
|
@ -138,8 +132,8 @@ struct userdata;
|
|||
typedef bool (*virtual_profile_event_cb)(struct userdata *u, pa_droid_profile *p, bool enabling);
|
||||
|
||||
struct virtual_profile {
|
||||
bool enabled;
|
||||
pa_card_profile *parent;
|
||||
pa_card_profile *extension;
|
||||
virtual_profile_event_cb event_cb;
|
||||
};
|
||||
|
||||
|
|
@ -156,31 +150,37 @@ struct userdata {
|
|||
pa_droid_hw_module *hw_module;
|
||||
pa_droid_card_data card_data;
|
||||
|
||||
pa_droid_profile *old_profile;
|
||||
pa_card_profile *real_profile;
|
||||
|
||||
pa_droid_extcon *extcon;
|
||||
pa_droid_extevdev *extevdev;
|
||||
|
||||
pa_modargs *modargs;
|
||||
pa_card *card;
|
||||
};
|
||||
|
||||
struct profile_data {
|
||||
pa_droid_profile *profile;
|
||||
pa_droid_profile *droid_profile;
|
||||
pa_card_profile *card_profile;
|
||||
audio_mode_t mode;
|
||||
bool virtual_profile;
|
||||
/* Variables for virtual profiles: */
|
||||
struct virtual_profile virtual;
|
||||
};
|
||||
|
||||
#ifdef DROID_AUDIO_HAL_USE_VSID
|
||||
#ifdef DROID_AUDIO_HAL_DEBUG_VSID
|
||||
|
||||
/* From hal/voice_extn/voice_extn.c */
|
||||
#define AUDIO_PARAMETER_KEY_VSID "vsid"
|
||||
#define AUDIO_PARAMETER_KEY_CALL_STATE "call_state"
|
||||
|
||||
/* From hal/voice_extn/voice_extn.c */
|
||||
#define VOICE2_VSID 0x10DC1000
|
||||
#define VOLTE_VSID 0x10C02000
|
||||
#define QCHAT_VSID 0x10803000
|
||||
#define VOWLAN_VSID 0x10002000
|
||||
#define VOICE2_VSID (0x10DC1000)
|
||||
#define VOLTE_VSID (0x10C02000)
|
||||
#define QCHAT_VSID (0x10803000)
|
||||
#define VOWLAN_VSID (0x10002000)
|
||||
#define VOICEMMODE1_VSID (0x11C05000)
|
||||
#define VOICEMMODE2_VSID (0x11DC5000)
|
||||
|
||||
/* From hal/voice.h */
|
||||
#define BASE_CALL_STATE 1
|
||||
|
|
@ -189,24 +189,30 @@ struct profile_data {
|
|||
#define VOICE_VSID 0x10C01000
|
||||
|
||||
/* For virtual profiles */
|
||||
#define VOICE_SESSION_VOICE1_PROFILE_NAME "voicecall-voice1"
|
||||
#define VOICE_SESSION_VOICE1_PROFILE_DESC "Call mode, default to voice 1 vsid"
|
||||
#define VOICE_SESSION_VOICE2_PROFILE_NAME "voicecall-voice2"
|
||||
#define VOICE_SESSION_VOICE2_PROFILE_DESC "Call mode, default to voice 2 vsid"
|
||||
#define VOICE_SESSION_VOLTE_PROFILE_NAME "voicecall-volte"
|
||||
#define VOICE_SESSION_VOLTE_PROFILE_DESC "Call mode, default to volte vsid"
|
||||
#define VOICE_SESSION_QCHAT_PROFILE_NAME "voicecall-qchat"
|
||||
#define VOICE_SESSION_QCHAT_PROFILE_DESC "Call mode, default to qchat vsid"
|
||||
#define VOICE_SESSION_VOWLAN_PROFILE_NAME "voicecall-vowlan"
|
||||
#define VOICE_SESSION_VOWLAN_PROFILE_DESC "Call mode, default to vowlan vsid"
|
||||
#define VOICE_SESSION_VOICE1_PROFILE_NAME "voicecall-voice1"
|
||||
#define VOICE_SESSION_VOICE1_PROFILE_DESC "Call mode, default to voice 1 vsid"
|
||||
#define VOICE_SESSION_VOICE2_PROFILE_NAME "voicecall-voice2"
|
||||
#define VOICE_SESSION_VOICE2_PROFILE_DESC "Call mode, default to voice 2 vsid"
|
||||
#define VOICE_SESSION_VOLTE_PROFILE_NAME "voicecall-volte"
|
||||
#define VOICE_SESSION_VOLTE_PROFILE_DESC "Call mode, default to volte vsid"
|
||||
#define VOICE_SESSION_QCHAT_PROFILE_NAME "voicecall-qchat"
|
||||
#define VOICE_SESSION_QCHAT_PROFILE_DESC "Call mode, default to qchat vsid"
|
||||
#define VOICE_SESSION_VOWLAN_PROFILE_NAME "voicecall-vowlan"
|
||||
#define VOICE_SESSION_VOWLAN_PROFILE_DESC "Call mode, default to vowlan vsid"
|
||||
#define VOICE_SESSION_VOICEMMODE1_PROFILE_NAME "voicecall-voicemmode1"
|
||||
#define VOICE_SESSION_VOICEMMODE1_PROFILE_DESC "Call mode, default to voicemmode1 vsid"
|
||||
#define VOICE_SESSION_VOICEMMODE2_PROFILE_NAME "voicecall-voicemmode2"
|
||||
#define VOICE_SESSION_VOICEMMODE2_PROFILE_DESC "Call mode, default to voicemmode2 vsid"
|
||||
|
||||
static bool voicecall_voice1_vsid_profile_event_cb(struct userdata *u, pa_droid_profile *p, bool enabling);
|
||||
static bool voicecall_voice2_vsid_profile_event_cb(struct userdata *u, pa_droid_profile *p, bool enabling);
|
||||
static bool voicecall_volte_vsid_profile_event_cb(struct userdata *u, pa_droid_profile *p, bool enabling);
|
||||
static bool voicecall_qchat_vsid_profile_event_cb(struct userdata *u, pa_droid_profile *p, bool enabling);
|
||||
static bool voicecall_vowlan_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);
|
||||
|
||||
#endif /* DROID_AUDIO_HAL_USE_VSID */
|
||||
#endif /* DROID_AUDIO_HAL_DEBUG_VSID */
|
||||
|
||||
static void add_disabled_profile(pa_hashmap *profiles) {
|
||||
pa_card_profile *cp;
|
||||
|
|
@ -216,7 +222,8 @@ static void add_disabled_profile(pa_hashmap *profiles) {
|
|||
cp->available = PA_AVAILABLE_YES;
|
||||
|
||||
d = PA_CARD_PROFILE_DATA(cp);
|
||||
d->profile = NULL;
|
||||
d->droid_profile = NULL;
|
||||
d->card_profile = cp;
|
||||
|
||||
pa_hashmap_put(profiles, cp->name, cp);
|
||||
}
|
||||
|
|
@ -228,7 +235,7 @@ static pa_card_profile* add_virtual_profile(struct userdata *u, const char *name
|
|||
pa_hashmap *profiles) {
|
||||
pa_droid_profile *ap;
|
||||
pa_card_profile *cp;
|
||||
struct profile_data *d, *ext;
|
||||
struct profile_data *d;
|
||||
|
||||
pa_assert(u);
|
||||
pa_assert(u->profile_set);
|
||||
|
|
@ -246,33 +253,18 @@ static pa_card_profile* add_virtual_profile(struct userdata *u, const char *name
|
|||
cp = pa_card_profile_new(ap->name, ap->description, sizeof(struct profile_data));
|
||||
cp->available = available;
|
||||
d = PA_CARD_PROFILE_DATA(cp);
|
||||
d->profile = ap;
|
||||
d->droid_profile = ap;
|
||||
d->card_profile = cp;
|
||||
d->virtual_profile = true;
|
||||
d->mode = audio_mode;
|
||||
d->virtual.event_cb = event_cb;
|
||||
d->virtual.extension = NULL;
|
||||
if (extension_to) {
|
||||
ext = PA_CARD_PROFILE_DATA(extension_to);
|
||||
ext->virtual.extension = cp;
|
||||
d->virtual.parent = extension_to;
|
||||
} else
|
||||
d->virtual.parent = NULL;
|
||||
d->virtual.parent = extension_to;
|
||||
|
||||
pa_hashmap_put(profiles, cp->name, 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) {
|
||||
const char *tmp;
|
||||
char *name;
|
||||
|
|
@ -293,6 +285,60 @@ static void set_card_name(pa_modargs *ma, pa_card_new_data *data, const char *mo
|
|||
data->namereg_fail = false;
|
||||
}
|
||||
|
||||
static bool output_enabled(struct userdata *u, pa_droid_mapping *am) {
|
||||
bool enabled = false;
|
||||
|
||||
pa_assert(u);
|
||||
pa_assert(am);
|
||||
|
||||
|
||||
if (am->mix_port->flags & AUDIO_OUTPUT_FLAG_PRIMARY)
|
||||
enabled = 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) {
|
||||
pa_card_profile *cp;
|
||||
struct profile_data *d;
|
||||
|
|
@ -311,26 +357,29 @@ static void add_profile(struct userdata *u, pa_hashmap *h, pa_hashmap *ports, pa
|
|||
cp->available = PA_AVAILABLE_YES;
|
||||
cp->priority = ap->priority;
|
||||
|
||||
/* Output mappings */
|
||||
|
||||
max_channels = 0;
|
||||
PA_IDXSET_FOREACH(am, ap->output_mappings, idx) {
|
||||
cp->n_sinks++;
|
||||
pa_droid_add_card_ports(cp, ports, am, u->core);
|
||||
max_channels = popcount(am->output->channel_masks) > max_channels
|
||||
? popcount(am->output->channel_masks) : max_channels;
|
||||
max_channels = max_channels_for_mix_port(am->mix_port, max_channels);
|
||||
}
|
||||
cp->max_sink_channels = max_channels;
|
||||
|
||||
/* Input mappings */
|
||||
|
||||
max_channels = 0;
|
||||
PA_IDXSET_FOREACH(am, ap->input_mappings, idx) {
|
||||
cp->n_sources++;
|
||||
pa_droid_add_card_ports(cp, ports, am, u->core);
|
||||
max_channels = popcount(am->input->channel_masks) > max_channels
|
||||
? popcount(am->input->channel_masks) : max_channels;
|
||||
max_channels = max_channels_for_mix_port(am->mix_port, max_channels);
|
||||
}
|
||||
cp->max_source_channels = max_channels;
|
||||
|
||||
d = PA_CARD_PROFILE_DATA(cp);
|
||||
d->profile = ap;
|
||||
d->droid_profile = ap;
|
||||
d->card_profile = cp;
|
||||
d->virtual_profile = false;
|
||||
d->mode = AUDIO_MODE_NORMAL;
|
||||
|
||||
|
|
@ -361,52 +410,25 @@ static void init_profile(struct userdata *u) {
|
|||
|
||||
d = PA_CARD_PROFILE_DATA(u->card->active_profile);
|
||||
|
||||
if (d->profile && pa_idxset_size(d->profile->output_mappings) > 0) {
|
||||
PA_IDXSET_FOREACH(am, d->profile->output_mappings, idx) {
|
||||
if (d->droid_profile && pa_idxset_size(d->droid_profile->output_mappings) > 0) {
|
||||
PA_IDXSET_FOREACH(am, d->droid_profile->output_mappings, idx) {
|
||||
if (!output_enabled(u, am))
|
||||
continue;
|
||||
|
||||
am->sink = pa_droid_sink_new(u->module, u->modargs, __FILE__, &u->card_data, 0, am, u->card);
|
||||
}
|
||||
}
|
||||
|
||||
if (d->profile && pa_idxset_size(d->profile->input_mappings) > 0) {
|
||||
PA_IDXSET_FOREACH(am, d->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 (d->droid_profile && pa_idxset_size(d->droid_profile->input_mappings) > 0) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int set_mode(struct userdata *u, audio_mode_t mode) {
|
||||
int ret;
|
||||
const char *mode_str;
|
||||
|
||||
pa_assert(u);
|
||||
pa_assert(u->hw_module);
|
||||
pa_assert(u->hw_module->device);
|
||||
|
||||
switch (mode) {
|
||||
case AUDIO_MODE_RINGTONE:
|
||||
mode_str = "AUDIO_MODE_RINGTONE";
|
||||
break;
|
||||
case AUDIO_MODE_IN_CALL:
|
||||
mode_str = "AUDIO_MODE_IN_CALL";
|
||||
break;
|
||||
case AUDIO_MODE_IN_COMMUNICATION:
|
||||
mode_str = "AUDIO_MODE_IN_COMMUNICATION";
|
||||
break;
|
||||
default:
|
||||
mode_str = "AUDIO_MODE_NORMAL";
|
||||
break;
|
||||
}
|
||||
|
||||
pa_log_debug("Set mode to %s.", mode_str);
|
||||
|
||||
pa_droid_hw_module_lock(u->hw_module);
|
||||
if ((ret = u->hw_module->device->set_mode(u->hw_module->device, mode)) < 0)
|
||||
pa_log("Failed to set mode.");
|
||||
pa_droid_hw_module_unlock(u->hw_module);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void park_profile(pa_droid_profile *dp) {
|
||||
pa_droid_mapping *am;
|
||||
uint32_t idx;
|
||||
|
|
@ -422,60 +444,88 @@ static void park_profile(pa_droid_profile *dp) {
|
|||
};
|
||||
|
||||
/* Virtual profiles don't have input mappings. */
|
||||
if (dp->input_mappings) {
|
||||
PA_IDXSET_FOREACH(am, dp->input_mappings, idx) {
|
||||
if (pa_droid_mapping_is_primary(am))
|
||||
pa_source_set_port(am->source, PA_DROID_INPUT_PARKING, false);
|
||||
}
|
||||
if ((am = dp->input_mapping)) {
|
||||
if (pa_droid_mapping_is_primary(am))
|
||||
pa_source_set_port(am->source, PA_DROID_INPUT_PARKING, false);
|
||||
};
|
||||
}
|
||||
|
||||
static pa_droid_profile *card_get_droid_profile(pa_card_profile *cp) {
|
||||
struct profile_data *pd;
|
||||
|
||||
pa_assert(cp);
|
||||
|
||||
pd = PA_CARD_PROFILE_DATA(cp);
|
||||
return pd->droid_profile;
|
||||
}
|
||||
|
||||
static bool voicecall_profile_event_cb(struct userdata *u, pa_droid_profile *p, bool enabling) {
|
||||
pa_card_profile *cp = NULL;
|
||||
pa_droid_profile *dp = NULL;
|
||||
pa_droid_mapping *am_output;
|
||||
|
||||
pa_assert(u);
|
||||
pa_assert(p);
|
||||
pa_assert(u->old_profile);
|
||||
pa_assert(u->real_profile);
|
||||
|
||||
if (!(am_output = pa_droid_idxset_get_primary(u->old_profile->output_mappings))) {
|
||||
dp = card_get_droid_profile(u->real_profile);
|
||||
if (!(am_output = pa_droid_idxset_get_primary(dp->output_mappings))) {
|
||||
pa_log("Active profile doesn't have primary output device.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pa_droid_idxset_mapping_with_device(u->old_profile->input_mappings,
|
||||
AUDIO_DEVICE_IN_VOICE_CALL))
|
||||
cp = pa_hashmap_get(u->card->profiles, VOICE_RECORD_PROFILE_NAME);
|
||||
|
||||
/* call mode specialities */
|
||||
if (enabling) {
|
||||
pa_droid_sink_set_voice_control(am_output->sink, true);
|
||||
if (cp && cp->available == PA_AVAILABLE_NO) {
|
||||
pa_log_debug("Enable " VOICE_RECORD_PROFILE_NAME " profile.");
|
||||
pa_card_profile_set_available(cp, PA_AVAILABLE_YES);
|
||||
}
|
||||
if (pa_droid_quirk(u->hw_module, QUIRK_REALCALL))
|
||||
|
||||
if (pa_droid_option(u->hw_module, DM_OPTION_REALCALL))
|
||||
pa_droid_set_parameters(u->hw_module, VENDOR_EXT_REALCALL_ON);
|
||||
} else {
|
||||
pa_droid_sink_set_voice_control(am_output->sink, false);
|
||||
if (cp && cp->available == PA_AVAILABLE_YES) {
|
||||
pa_log_debug("Disable " VOICE_RECORD_PROFILE_NAME " profile.");
|
||||
pa_card_profile_set_available(cp, PA_AVAILABLE_NO);
|
||||
}
|
||||
if (pa_droid_quirk(u->hw_module, QUIRK_REALCALL))
|
||||
|
||||
if (pa_droid_option(u->hw_module, DM_OPTION_REALCALL))
|
||||
pa_droid_set_parameters(u->hw_module, VENDOR_EXT_REALCALL_OFF);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
char *setparam;
|
||||
|
||||
voicecall_profile_event_cb(u, p, enabling);
|
||||
|
||||
setparam = pa_sprintf_malloc("%s=%u;%s=%d", AUDIO_PARAMETER_KEY_VSID, vsid,
|
||||
AUDIO_PARAMETER_KEY_CALL_STATE,
|
||||
enabling ? CALL_ACTIVE : CALL_INACTIVE);
|
||||
|
|
@ -510,43 +560,123 @@ static bool voicecall_vowlan_vsid_profile_event_cb(struct userdata *u, pa_droid_
|
|||
{
|
||||
return voicecall_vsid(u, p, VOWLAN_VSID, enabling);
|
||||
}
|
||||
#endif /* DROID_AUDIO_HAL_USE_VSID */
|
||||
|
||||
static void leave_virtual_profile(struct userdata *u, pa_card *c, pa_card_profile *cp, pa_card_profile *new_profile) {
|
||||
struct profile_data *pd, *parent;
|
||||
static bool voicecall_voicemmode1_vsid_profile_event_cb(struct userdata *u, pa_droid_profile *p, bool enabling)
|
||||
{
|
||||
return voicecall_vsid(u, p, VOICEMMODE1_VSID, enabling);
|
||||
}
|
||||
|
||||
static bool voicecall_voicemmode2_vsid_profile_event_cb(struct userdata *u, pa_droid_profile *p, bool enabling)
|
||||
{
|
||||
return voicecall_vsid(u, p, VOICEMMODE2_VSID, enabling);
|
||||
}
|
||||
#endif /* DROID_AUDIO_HAL_DEBUG_VSID */
|
||||
|
||||
static void virtual_event(struct userdata *u, struct profile_data *profile, bool enabling) {
|
||||
pa_assert(u);
|
||||
pa_assert(profile);
|
||||
pa_assert(profile->virtual_profile);
|
||||
|
||||
if (profile->virtual.enabled == enabling)
|
||||
return;
|
||||
|
||||
pa_log_info("Virtual profile %s changes to %s%s", profile->droid_profile->name,
|
||||
enabling ? "enabled" : "disabled",
|
||||
profile->virtual.event_cb ? " (calling event callback)" : "");
|
||||
|
||||
if (profile->virtual.event_cb)
|
||||
profile->virtual.event_cb(u, profile->droid_profile, enabling);
|
||||
|
||||
profile->virtual.enabled = enabling;
|
||||
}
|
||||
|
||||
static pa_card_profile *leave_virtual_profile(struct userdata *u, pa_card *c,
|
||||
struct profile_data *current, struct profile_data *next) {
|
||||
pa_card_profile *real = NULL;
|
||||
|
||||
pa_assert(u);
|
||||
pa_assert(c);
|
||||
pa_assert(cp);
|
||||
pa_assert_se((pd = PA_CARD_PROFILE_DATA(cp)));
|
||||
pa_assert(current);
|
||||
pa_assert(next);
|
||||
pa_assert(current->virtual_profile);
|
||||
|
||||
if (pd->virtual.parent)
|
||||
pa_log_debug("Leaving extension %s.", cp->name);
|
||||
pa_log_debug("Leave virtual profile %s", current->droid_profile->name);
|
||||
|
||||
/* First run event for old virtual profile, unless new profile is extension
|
||||
* to the old profile. */
|
||||
if (pd->virtual.extension) {
|
||||
if (pd->virtual.extension != new_profile && pd->virtual.event_cb)
|
||||
pd->virtual.event_cb(u, pd->profile, false);
|
||||
} else {
|
||||
if (pd->virtual.event_cb)
|
||||
pd->virtual.event_cb(u, pd->profile, false);
|
||||
if (next->mode != current->mode) {
|
||||
park_profile(card_get_droid_profile(u->real_profile));
|
||||
pa_droid_hw_set_mode(u->hw_module, next->mode);
|
||||
}
|
||||
|
||||
/* If old virtual profile was extension, and new profile is not extensions parent, run event
|
||||
* for extension's parent as well. */
|
||||
if (pd->virtual.parent != new_profile && pd->virtual.parent) {
|
||||
parent = PA_CARD_PROFILE_DATA(pd->virtual.parent);
|
||||
virtual_event(u, current, false);
|
||||
|
||||
if (parent->virtual.event_cb)
|
||||
parent->virtual.event_cb(u, parent->profile, false);
|
||||
/* If new profile is the same as from which we switched to
|
||||
* virtual profile, transfer ownership back to that profile.
|
||||
* Otherwise destroy sinks & sources and switch to new profile. */
|
||||
if (!next->virtual_profile) {
|
||||
if (current->virtual.parent) {
|
||||
struct profile_data *pd = PA_CARD_PROFILE_DATA(current->virtual.parent);
|
||||
virtual_event(u, pd, false);
|
||||
}
|
||||
|
||||
if (next->card_profile != u->real_profile)
|
||||
real = u->real_profile;
|
||||
u->real_profile = NULL;
|
||||
}
|
||||
|
||||
pa_log_debug("Left virtual profile %s%s", current->droid_profile->name,
|
||||
next->virtual_profile ? "" : " for real profile");
|
||||
|
||||
return real;
|
||||
}
|
||||
|
||||
static void enter_virtual_profile(struct userdata *u, pa_card *c,
|
||||
struct profile_data *current, struct profile_data *next) {
|
||||
pa_assert(u);
|
||||
pa_assert(c);
|
||||
pa_assert(current);
|
||||
pa_assert(next);
|
||||
pa_assert(next->virtual_profile);
|
||||
|
||||
pa_log_debug("Enter virtual profile %s", next->droid_profile->name);
|
||||
|
||||
/* real_profile should always be real profile. */
|
||||
if (u->real_profile == NULL) {
|
||||
pa_assert(!current->virtual_profile);
|
||||
u->real_profile = current->card_profile;
|
||||
}
|
||||
|
||||
if (current->virtual_profile) {
|
||||
if (current->card_profile != next->virtual.parent) {
|
||||
struct profile_data *parent = current;
|
||||
while (parent && parent != next && parent->card_profile != next->virtual.parent) {
|
||||
virtual_event(u, parent, false);
|
||||
parent = parent->virtual.parent ? PA_CARD_PROFILE_DATA(parent->virtual.parent) : NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (next->mode != current->mode) {
|
||||
park_profile(card_get_droid_profile(u->real_profile));
|
||||
pa_droid_hw_set_mode(u->hw_module, next->mode);
|
||||
}
|
||||
|
||||
if (next->virtual.parent) {
|
||||
if (next->virtual.parent != current->card_profile) {
|
||||
struct profile_data *pd = PA_CARD_PROFILE_DATA(next->virtual.parent);
|
||||
virtual_event(u, pd, true);
|
||||
}
|
||||
}
|
||||
|
||||
virtual_event(u, next, true);
|
||||
|
||||
pa_log_debug("Entered virtual profile %s", next->droid_profile->name);
|
||||
}
|
||||
|
||||
static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
|
||||
struct userdata *u;
|
||||
pa_card_profile *real_profile;
|
||||
pa_droid_mapping *am;
|
||||
struct profile_data *nd, *od;
|
||||
struct profile_data *next, *curr;
|
||||
pa_queue *sink_inputs = NULL, *source_outputs = NULL;
|
||||
pa_sink *primary_sink = NULL;
|
||||
uint32_t idx;
|
||||
|
|
@ -560,65 +690,34 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
nd = PA_CARD_PROFILE_DATA(new_profile);
|
||||
od = PA_CARD_PROFILE_DATA(c->active_profile);
|
||||
|
||||
if (nd->virtual_profile) {
|
||||
/* old_profile should always be real profile. */
|
||||
if (u->old_profile == NULL) {
|
||||
pa_assert(!od->virtual_profile);
|
||||
u->old_profile = od->profile;
|
||||
}
|
||||
|
||||
if (od->virtual_profile)
|
||||
leave_virtual_profile(u, c, c->active_profile, new_profile);
|
||||
|
||||
park_profile(od->profile);
|
||||
|
||||
if (nd->mode != od->mode)
|
||||
set_mode(u, nd->mode);
|
||||
|
||||
if (od->virtual.parent != new_profile && nd->virtual.event_cb)
|
||||
nd->virtual.event_cb(u, nd->profile, true);
|
||||
next = PA_CARD_PROFILE_DATA(new_profile);
|
||||
curr = PA_CARD_PROFILE_DATA(c->active_profile);
|
||||
|
||||
if (next->virtual_profile) {
|
||||
enter_virtual_profile(u, c, curr, next);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (od->virtual_profile) {
|
||||
pa_assert(u->old_profile);
|
||||
|
||||
if (od->virtual_profile)
|
||||
leave_virtual_profile(u, c, c->active_profile, NULL);
|
||||
|
||||
park_profile(nd->profile);
|
||||
|
||||
if (nd->mode != od->mode)
|
||||
set_mode(u, nd->mode);
|
||||
|
||||
/* If new profile is the same as from which we switched to
|
||||
* virtual profile, transfer ownership back to that profile.
|
||||
* Otherwise destroy sinks & sources and switch to new profile. */
|
||||
if (nd->profile == u->old_profile) {
|
||||
u->old_profile = NULL;
|
||||
return 0;
|
||||
} else {
|
||||
od->profile = u->old_profile;
|
||||
u->old_profile = NULL;
|
||||
|
||||
/* Continue to sink-input/source-output transfer below. */
|
||||
} else {
|
||||
if (curr->virtual_profile) {
|
||||
if ((real_profile = leave_virtual_profile(u, c, curr, next)))
|
||||
curr = PA_CARD_PROFILE_DATA(real_profile);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Continue to sink-input/source-output transfer below. */
|
||||
}
|
||||
|
||||
/* If there are connected sink inputs/source outputs in old profile's sinks/sources move
|
||||
* them all to new sinks/sources. */
|
||||
pa_log_debug("Update sinks and sources for profile %s", new_profile->name);
|
||||
|
||||
if (od->profile && pa_idxset_size(od->profile->output_mappings) > 0) {
|
||||
PA_IDXSET_FOREACH(am, od->profile->output_mappings, idx) {
|
||||
if (curr->droid_profile && pa_idxset_size(curr->droid_profile->output_mappings) > 0) {
|
||||
PA_IDXSET_FOREACH(am, curr->droid_profile->output_mappings, idx) {
|
||||
if (!am->sink)
|
||||
continue;
|
||||
|
||||
if (nd->profile &&
|
||||
pa_idxset_get_by_data(nd->profile->output_mappings, am, NULL)) {
|
||||
if (next->droid_profile &&
|
||||
pa_idxset_get_by_data(next->droid_profile->output_mappings, am, NULL)) {
|
||||
|
||||
if (pa_droid_mapping_is_primary(am))
|
||||
primary_sink = am->sink;
|
||||
|
|
@ -631,23 +730,19 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
|
|||
}
|
||||
}
|
||||
|
||||
if (od->profile && pa_idxset_size(od->profile->input_mappings) > 0) {
|
||||
PA_IDXSET_FOREACH(am, od->profile->input_mappings, idx) {
|
||||
if (!am->source)
|
||||
continue;
|
||||
|
||||
if (nd->profile &&
|
||||
pa_idxset_get_by_data(nd->profile->input_mappings, am, NULL))
|
||||
continue;
|
||||
|
||||
if (curr->droid_profile && (am = curr->droid_profile->input_mapping)) {
|
||||
if (am->source && next->droid_profile && next->droid_profile->input_mapping) {
|
||||
source_outputs = pa_source_move_all_start(am->source, source_outputs);
|
||||
pa_droid_source_free(am->source);
|
||||
am->source = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (nd->profile && pa_idxset_size(nd->profile->output_mappings) > 0) {
|
||||
PA_IDXSET_FOREACH(am, nd->profile->output_mappings, idx) {
|
||||
if (next->droid_profile && pa_idxset_size(next->droid_profile->output_mappings) > 0) {
|
||||
PA_IDXSET_FOREACH(am, next->droid_profile->output_mappings, idx) {
|
||||
if (!output_enabled(u, am))
|
||||
continue;
|
||||
|
||||
if (!am->sink)
|
||||
am->sink = pa_droid_sink_new(u->module, u->modargs, __FILE__, &u->card_data, 0, am, u->card);
|
||||
|
||||
|
|
@ -658,10 +753,13 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
|
|||
}
|
||||
}
|
||||
|
||||
if (nd->profile && pa_idxset_size(nd->profile->input_mappings) > 0) {
|
||||
PA_IDXSET_FOREACH(am, nd->profile->input_mappings, idx) {
|
||||
if (next->droid_profile && pa_idxset_size(next->droid_profile->input_mappings) > 0) {
|
||||
PA_IDXSET_FOREACH(am, next->droid_profile->input_mappings, idx) {
|
||||
if (!input_enabled(u, am))
|
||||
continue;
|
||||
|
||||
if (!am->source)
|
||||
am->source = pa_droid_source_new(u->module, u->modargs, __FILE__, (audio_devices_t) 0, &u->card_data, am, u->card);
|
||||
am->source = pa_droid_source_new(u->module, u->modargs, __FILE__, &u->card_data, am, u->card);
|
||||
|
||||
if (source_outputs && am->source) {
|
||||
pa_source_move_all_finish(am->source, source_outputs, false);
|
||||
|
|
@ -691,68 +789,34 @@ int pa__init(pa_module *m) {
|
|||
struct userdata *u = NULL;
|
||||
pa_modargs *ma = NULL;
|
||||
pa_card_new_data data;
|
||||
pa_droid_config_audio *config = NULL;
|
||||
const char *module_id;
|
||||
bool namereg_fail = false;
|
||||
pa_card_profile *virtual;
|
||||
bool default_profile = true;
|
||||
bool merge_inputs = true;
|
||||
const char *quirks;
|
||||
pa_card_profile *voicecall = NULL;
|
||||
|
||||
pa_assert(m);
|
||||
|
||||
if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
|
||||
pa_log_info("Create new droid-card");
|
||||
|
||||
if (!(ma = pa_droid_modargs_new(m->argument, valid_modargs))) {
|
||||
pa_log("Failed to parse module arguments.");
|
||||
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;
|
||||
}
|
||||
|
||||
if (pa_modargs_get_value_boolean(ma, "merge_inputs", &merge_inputs) < 0) {
|
||||
pa_log("Failed to parse merge_inputs argument. Expects boolean value");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
u = pa_xnew0(struct userdata, 1);
|
||||
u->core = m->core;
|
||||
m->userdata = u;
|
||||
|
||||
module_id = pa_modargs_get_value(ma, "module_id", DEFAULT_MODULE_ID);
|
||||
|
||||
/* First let's find out if hw module has already been opened, or if we need to
|
||||
* do it ourself. */
|
||||
if (!(u->hw_module = pa_droid_hw_module_get(u->core, NULL, module_id))) {
|
||||
/* No hw module object in shared object db, let's open the module now. */
|
||||
if (!(config = pa_droid_config_load(ma)))
|
||||
goto fail;
|
||||
if (!(u->hw_module = pa_droid_hw_module_get2(u->core, ma, module_id)))
|
||||
goto fail;
|
||||
|
||||
if (!(u->hw_module = pa_droid_hw_module_get(u->core, config, module_id)))
|
||||
goto fail;
|
||||
pa_droid_options_log(u->hw_module);
|
||||
|
||||
pa_droid_config_free(config);
|
||||
config = NULL;
|
||||
}
|
||||
|
||||
if ((quirks = pa_modargs_get_value(ma, "quirks", NULL))) {
|
||||
if (!pa_droid_quirk_parse(u->hw_module, quirks)) {
|
||||
pa_log("Failed to parse quirks.");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
pa_droid_quirk_log(u->hw_module);
|
||||
|
||||
u->card_data.set_parameters = set_parameters_cb;
|
||||
u->card_data.module_id = pa_xstrdup(module_id);
|
||||
u->card_data.userdata = u;
|
||||
|
||||
if (!default_profile || !pa_streq(module_id, DEFAULT_MODULE_ID))
|
||||
u->profile_set = pa_droid_profile_set_new(u->hw_module->enabled_module);
|
||||
else
|
||||
u->profile_set = pa_droid_profile_set_default_new(u->hw_module->enabled_module, merge_inputs);
|
||||
u->profile_set = pa_droid_profile_set_default_new(u->hw_module->enabled_module);
|
||||
|
||||
pa_card_new_data_init(&data);
|
||||
data.driver = __FILE__;
|
||||
|
|
@ -780,37 +844,42 @@ int pa__init(pa_module *m) {
|
|||
goto fail;
|
||||
}
|
||||
|
||||
virtual =
|
||||
voicecall =
|
||||
add_virtual_profile(u, VOICE_CALL_PROFILE_NAME, VOICE_CALL_PROFILE_DESC,
|
||||
AUDIO_MODE_IN_CALL, voicecall_profile_event_cb,
|
||||
PA_AVAILABLE_YES, NULL, data.profiles);
|
||||
add_virtual_profile(u, VOICE_RECORD_PROFILE_NAME, VOICE_RECORD_PROFILE_DESC,
|
||||
AUDIO_MODE_IN_CALL, NULL,
|
||||
PA_AVAILABLE_NO, virtual, data.profiles);
|
||||
PA_AVAILABLE_YES, voicecall, data.profiles);
|
||||
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);
|
||||
add_virtual_profile(u, RINGTONE_PROFILE_NAME, RINGTONE_PROFILE_DESC,
|
||||
AUDIO_MODE_RINGTONE, NULL,
|
||||
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,
|
||||
AUDIO_MODE_IN_CALL, voicecall_voice1_vsid_profile_event_cb,
|
||||
PA_AVAILABLE_YES, NULL, data.profiles);
|
||||
PA_AVAILABLE_YES, voicecall, data.profiles);
|
||||
add_virtual_profile(u, VOICE_SESSION_VOICE2_PROFILE_NAME, VOICE_SESSION_VOICE2_PROFILE_DESC,
|
||||
AUDIO_MODE_IN_CALL, voicecall_voice2_vsid_profile_event_cb,
|
||||
PA_AVAILABLE_YES, NULL, data.profiles);
|
||||
/* TODO: Probably enabled state needs to be determined dynamically for VOLTE and friends. */
|
||||
PA_AVAILABLE_YES, voicecall, data.profiles);
|
||||
add_virtual_profile(u, VOICE_SESSION_VOLTE_PROFILE_NAME, VOICE_SESSION_VOLTE_PROFILE_DESC,
|
||||
AUDIO_MODE_IN_CALL, voicecall_volte_vsid_profile_event_cb,
|
||||
PA_AVAILABLE_YES, NULL, data.profiles);
|
||||
PA_AVAILABLE_YES, voicecall, data.profiles);
|
||||
add_virtual_profile(u, VOICE_SESSION_QCHAT_PROFILE_NAME, VOICE_SESSION_QCHAT_PROFILE_DESC,
|
||||
AUDIO_MODE_IN_CALL, voicecall_qchat_vsid_profile_event_cb,
|
||||
PA_AVAILABLE_YES, NULL, data.profiles);
|
||||
PA_AVAILABLE_YES, voicecall, data.profiles);
|
||||
add_virtual_profile(u, VOICE_SESSION_VOWLAN_PROFILE_NAME, VOICE_SESSION_VOWLAN_PROFILE_DESC,
|
||||
AUDIO_MODE_IN_CALL, voicecall_vowlan_vsid_profile_event_cb,
|
||||
PA_AVAILABLE_YES, NULL, data.profiles);
|
||||
#endif /* DROID_AUDIO_HAL_USE_VSID */
|
||||
PA_AVAILABLE_YES, voicecall, data.profiles);
|
||||
add_virtual_profile(u, VOICE_SESSION_VOICEMMODE1_PROFILE_NAME, VOICE_SESSION_VOICEMMODE1_PROFILE_DESC,
|
||||
AUDIO_MODE_IN_CALL, voicecall_voicemmode1_vsid_profile_event_cb,
|
||||
PA_AVAILABLE_YES, voicecall, data.profiles);
|
||||
add_virtual_profile(u, VOICE_SESSION_VOICEMMODE2_PROFILE_NAME, VOICE_SESSION_VOICEMMODE2_PROFILE_DESC,
|
||||
AUDIO_MODE_IN_CALL, voicecall_voicemmode2_vsid_profile_event_cb,
|
||||
PA_AVAILABLE_YES, voicecall, data.profiles);
|
||||
#endif /* DROID_AUDIO_HAL_DEBUG_VSID */
|
||||
|
||||
add_disabled_profile(data.profiles);
|
||||
|
||||
|
|
@ -830,20 +899,20 @@ int pa__init(pa_module *m) {
|
|||
u->modargs = ma;
|
||||
u->module = m;
|
||||
|
||||
#if (PULSEAUDIO_VERSION >= 10)
|
||||
pa_card_choose_initial_profile(u->card);
|
||||
#endif
|
||||
init_profile(u);
|
||||
u->extcon = pa_droid_extcon_new(m->core, u->card);
|
||||
|
||||
if (!u->extcon)
|
||||
u->extevdev = pa_droid_extevdev_new(m->core, u->card);
|
||||
else
|
||||
u->extevdev = NULL;
|
||||
|
||||
#if (PULSEAUDIO_VERSION >= 10)
|
||||
pa_card_put(u->card);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
pa_droid_config_free(config);
|
||||
|
||||
if (ma)
|
||||
pa_modargs_free(ma);
|
||||
|
||||
|
|
@ -865,6 +934,11 @@ void pa__done(pa_module *m) {
|
|||
if (u->card && u->card->sources)
|
||||
pa_idxset_remove_all(u->card->sources, (pa_free_cb_t) pa_droid_source_free);
|
||||
|
||||
if (u->extcon)
|
||||
pa_droid_extcon_free(u->extcon);
|
||||
|
||||
if (u->extevdev)
|
||||
pa_droid_extevdev_free(u->extevdev);
|
||||
|
||||
if (u->card)
|
||||
pa_card_free(u->card);
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2013-2018 Jolla Ltd.
|
||||
*
|
||||
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
||||
*
|
||||
* These PulseAudio Modules are free software; you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||
* USA.
|
||||
*/
|
||||
#ifndef foomoduledroidkeepalivesymdeffoo
|
||||
#define foomoduledroidkeepalivesymdeffoo
|
||||
|
||||
#include <pulsecore/core.h>
|
||||
#include <pulsecore/module.h>
|
||||
|
||||
#define pa__init module_droid_keepalive_LTX_pa__init
|
||||
#define pa__done module_droid_keepalive_LTX_pa__done
|
||||
#define pa__get_author module_droid_keepalive_LTX_pa__get_author
|
||||
#define pa__get_description module_droid_keepalive_LTX_pa__get_description
|
||||
#define pa__get_usage module_droid_keepalive_LTX_pa__get_usage
|
||||
#define pa__get_version module_droid_keepalive_LTX_pa__get_version
|
||||
|
||||
int pa__init(struct pa_module*m);
|
||||
void pa__done(struct pa_module*m);
|
||||
|
||||
const char* pa__get_author(void);
|
||||
const char* pa__get_description(void);
|
||||
const char* pa__get_usage(void);
|
||||
const char* pa__get_version(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,198 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2013-2018 Jolla Ltd.
|
||||
*
|
||||
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
||||
*
|
||||
* These PulseAudio Modules are free software; you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||
* USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef HAVE_VALGRIND_MEMCHECK_H
|
||||
#include <valgrind/memcheck.h>
|
||||
#endif
|
||||
|
||||
#include <pulse/xmalloc.h>
|
||||
|
||||
#include <pulsecore/core.h>
|
||||
#include <pulsecore/i18n.h>
|
||||
#include <pulsecore/module.h>
|
||||
#include <pulsecore/sink.h>
|
||||
#include <pulsecore/source.h>
|
||||
#include <pulsecore/modargs.h>
|
||||
#include <pulsecore/core-util.h>
|
||||
#include <pulsecore/log.h>
|
||||
#include <pulsecore/macro.h>
|
||||
#include <pulsecore/idxset.h>
|
||||
|
||||
#include "keepalive.h"
|
||||
|
||||
#include "module-droid-keepalive-symdef.h"
|
||||
|
||||
PA_MODULE_AUTHOR("Juho Hämäläinen");
|
||||
PA_MODULE_DESCRIPTION("Droid keepalive. Send cpu wakeup heartbeat while streams are active.");
|
||||
PA_MODULE_VERSION(PACKAGE_VERSION);
|
||||
PA_MODULE_USAGE(
|
||||
"-"
|
||||
);
|
||||
|
||||
static const char* const valid_modargs[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
struct userdata {
|
||||
pa_core *core;
|
||||
pa_module *module;
|
||||
|
||||
pa_droid_keepalive *keepalive;
|
||||
bool active;
|
||||
pa_hook_slot *sink_state_changed_slot;
|
||||
pa_hook_slot *source_state_changed_slot;
|
||||
};
|
||||
|
||||
static void start(struct userdata *u) {
|
||||
if (u->active)
|
||||
return;
|
||||
|
||||
u->active = true;
|
||||
|
||||
pa_droid_keepalive_start(u->keepalive);
|
||||
}
|
||||
|
||||
static void stop(struct userdata *u) {
|
||||
void *state = NULL;
|
||||
pa_sink *sink;
|
||||
pa_source *source;
|
||||
|
||||
if (!u->active)
|
||||
return;
|
||||
|
||||
while ((sink = pa_idxset_iterate(u->core->sinks, &state, NULL))) {
|
||||
if (pa_sink_get_state(sink) != PA_SINK_SUSPENDED)
|
||||
return;
|
||||
}
|
||||
|
||||
state = NULL;
|
||||
while ((source = pa_idxset_iterate(u->core->sources, &state, NULL))) {
|
||||
if (source->monitor_of)
|
||||
continue;
|
||||
if (pa_source_get_state(source) != PA_SOURCE_SUSPENDED)
|
||||
return;
|
||||
}
|
||||
|
||||
/* We get here if all sinks and sources are in suspended state. */
|
||||
pa_droid_keepalive_stop(u->keepalive);
|
||||
u->active = false;
|
||||
}
|
||||
|
||||
static void update_sink(pa_sink *sink, struct userdata *u) {
|
||||
pa_assert(sink);
|
||||
pa_assert(u);
|
||||
|
||||
if (pa_sink_get_state(sink) != PA_SINK_SUSPENDED)
|
||||
start(u);
|
||||
else
|
||||
stop(u);
|
||||
}
|
||||
|
||||
static void update_source(pa_source *source, struct userdata *u) {
|
||||
pa_assert(source);
|
||||
pa_assert(u);
|
||||
|
||||
/* Don't react on monitor state changes. */
|
||||
if (!source->monitor_of) {
|
||||
if (pa_source_get_state(source) != PA_SOURCE_SUSPENDED)
|
||||
start(u);
|
||||
else
|
||||
stop(u);
|
||||
}
|
||||
}
|
||||
|
||||
static pa_hook_result_t device_state_changed_hook_cb(pa_core *c, pa_object *o, struct userdata *u) {
|
||||
pa_assert(c);
|
||||
pa_object_assert_ref(o);
|
||||
pa_assert(u);
|
||||
|
||||
if (pa_source_isinstance(o))
|
||||
update_source(PA_SOURCE(o), u);
|
||||
else if (pa_sink_isinstance(o))
|
||||
update_sink(PA_SINK(o), u);
|
||||
|
||||
return PA_HOOK_OK;
|
||||
}
|
||||
|
||||
|
||||
int pa__init(pa_module *m) {
|
||||
uint32_t idx = 0;
|
||||
pa_sink *sink;
|
||||
pa_source *source;
|
||||
struct userdata *u;
|
||||
|
||||
pa_assert(m);
|
||||
|
||||
u = pa_xnew0(struct userdata, 1);
|
||||
u->core = m->core;
|
||||
u->active = false;
|
||||
u->module = m;
|
||||
m->userdata = u;
|
||||
|
||||
if (!(u->keepalive = pa_droid_keepalive_new(u->core))) {
|
||||
pa_log("Failed to create keepalive handler.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
u->sink_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) device_state_changed_hook_cb, u);
|
||||
u->source_state_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) device_state_changed_hook_cb, u);
|
||||
|
||||
PA_IDXSET_FOREACH(source, u->core->sources, idx)
|
||||
update_source(source, u);
|
||||
|
||||
PA_IDXSET_FOREACH(sink, u->core->sinks, idx)
|
||||
update_sink(sink, u);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
pa__done(m);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void pa__done(pa_module *m) {
|
||||
struct userdata *u;
|
||||
|
||||
pa_assert(m);
|
||||
|
||||
if ((u = m->userdata)) {
|
||||
|
||||
if (u->sink_state_changed_slot)
|
||||
pa_hook_slot_free(u->sink_state_changed_slot);
|
||||
if (u->source_state_changed_slot)
|
||||
pa_hook_slot_free(u->source_state_changed_slot);
|
||||
|
||||
if (u->keepalive) {
|
||||
pa_droid_keepalive_stop(u->keepalive);
|
||||
pa_droid_keepalive_free(u->keepalive);
|
||||
}
|
||||
|
||||
pa_xfree(u);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2013-2018 Jolla Ltd.
|
||||
*
|
||||
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
||||
*
|
||||
* These PulseAudio Modules are free software; you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||
* USA.
|
||||
*/
|
||||
#ifndef foomoduledroidsinksymdeffoo
|
||||
#define foomoduledroidsinksymdeffoo
|
||||
|
||||
#include <pulsecore/core.h>
|
||||
#include <pulsecore/module.h>
|
||||
|
||||
#define pa__init module_droid_sink_LTX_pa__init
|
||||
#define pa__done module_droid_sink_LTX_pa__done
|
||||
#define pa__get_author module_droid_sink_LTX_pa__get_author
|
||||
#define pa__get_description module_droid_sink_LTX_pa__get_description
|
||||
#define pa__get_usage module_droid_sink_LTX_pa__get_usage
|
||||
#define pa__get_version module_droid_sink_LTX_pa__get_version
|
||||
|
||||
int pa__init(struct pa_module*m);
|
||||
void pa__done(struct pa_module*m);
|
||||
|
||||
const char* pa__get_author(void);
|
||||
const char* pa__get_description(void);
|
||||
const char* pa__get_usage(void);
|
||||
const char* pa__get_version(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -41,8 +41,6 @@
|
|||
#include <droid/conversion.h>
|
||||
#include "droid-sink.h"
|
||||
|
||||
#include "module-droid-sink-symdef.h"
|
||||
|
||||
PA_MODULE_AUTHOR("Juho Hämäläinen");
|
||||
PA_MODULE_DESCRIPTION("Droid sink");
|
||||
PA_MODULE_USAGE("master_sink=<sink to connect to> "
|
||||
|
|
@ -50,6 +48,7 @@ PA_MODULE_USAGE("master_sink=<sink to connect to> "
|
|||
PA_MODULE_VERSION(PACKAGE_VERSION);
|
||||
|
||||
static const char* const valid_modargs[] = {
|
||||
"config",
|
||||
"rate",
|
||||
"format",
|
||||
"channels",
|
||||
|
|
@ -59,6 +58,7 @@ static const char* const valid_modargs[] = {
|
|||
"sink_channel_map",
|
||||
"sink_mix_route",
|
||||
"flags",
|
||||
"output",
|
||||
"output_devices",
|
||||
"sink_name",
|
||||
"module_id",
|
||||
|
|
@ -69,6 +69,7 @@ static const char* const valid_modargs[] = {
|
|||
"deferred_volume",
|
||||
"voice_property_key",
|
||||
"voice_property_value",
|
||||
"voice_virtual_stream",
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2013-2018 Jolla Ltd.
|
||||
*
|
||||
* Contact: Juho Hämäläinen <juho.hamalainen@jolla.com>
|
||||
*
|
||||
* These PulseAudio Modules are free software; you can redistribute
|
||||
* it and/or modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation
|
||||
* version 2.1 of the License.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
|
||||
* USA.
|
||||
*/
|
||||
#ifndef foomoduledroidsourcesymdeffoo
|
||||
#define foomoduledroidsourcesymdeffoo
|
||||
|
||||
#include <pulsecore/core.h>
|
||||
#include <pulsecore/module.h>
|
||||
|
||||
#define pa__init module_droid_source_LTX_pa__init
|
||||
#define pa__done module_droid_source_LTX_pa__done
|
||||
#define pa__get_author module_droid_source_LTX_pa__get_author
|
||||
#define pa__get_description module_droid_source_LTX_pa__get_description
|
||||
#define pa__get_usage module_droid_source_LTX_pa__get_usage
|
||||
#define pa__get_version module_droid_source_LTX_pa__get_version
|
||||
|
||||
int pa__init(struct pa_module*m);
|
||||
void pa__done(struct pa_module*m);
|
||||
|
||||
const char* pa__get_author(void);
|
||||
const char* pa__get_description(void);
|
||||
const char* pa__get_usage(void);
|
||||
const char* pa__get_version(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -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>
|
||||
*
|
||||
|
|
@ -40,8 +40,6 @@
|
|||
#include <droid/droid-util.h>
|
||||
#include "droid-source.h"
|
||||
|
||||
#include "module-droid-source-symdef.h"
|
||||
|
||||
PA_MODULE_AUTHOR("Juho Hämäläinen");
|
||||
PA_MODULE_DESCRIPTION("Droid source");
|
||||
PA_MODULE_USAGE("master_source=<source to connect to> "
|
||||
|
|
@ -49,6 +47,7 @@ PA_MODULE_USAGE("master_source=<source to connect to> "
|
|||
PA_MODULE_VERSION(PACKAGE_VERSION);
|
||||
|
||||
static const char* const valid_modargs[] = {
|
||||
"config",
|
||||
"rate",
|
||||
"format",
|
||||
"channels",
|
||||
|
|
@ -84,7 +83,7 @@ int pa__init(pa_module *m) {
|
|||
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;
|
||||
|
||||
pa_modargs_free(ma);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue