Compare commits

...

252 commits

Author SHA1 Message Date
Penelope Gwen
c0e8232a36 version bump 2026-03-29 18:17:19 -07:00
Penelope Gwen
18e6cd030e correct config file paths 2026-03-29 18:00:33 -07:00
Penelope Gwen
e689a5abc9 add config files 2026-03-29 14:10:35 -07:00
Adam Boardman
974ae573ad Various upstream (sfos) fixes and avoid an assert on internal structure confusion caused by move to new upstream Pulseaudio that appears to do things differently, this will probably need revisiting 2023-05-05 10:16:14 +01:00
Adam Boardman
f28da7fddf Build fixes post numbering fix 2023-05-04 15:35:11 +01:00
Adam Boardman
caf6773723 Updated version number 2023-04-23 10:02:48 +01:00
Adam Boardman
5c0ca5b077 Update changelog and possible build fixes 2023-04-04 16:05:33 +01:00
Adam Boardman
f1fb79c3e0 Merge remote-tracking branch 'upstream/bookworm' into bookworm 2023-04-04 15:10:10 +01:00
Eugenio Paolantonio (g7)
112843b765 [skip ci] [ci] Use the checkout step provided by the droidian-buildd orb
Signed-off-by: Eugenio Paolantonio (g7) <me@medesimo.eu>
2023-01-07 01:43:51 +01:00
Eugenio Paolantonio (g7)
10599fe519 [skip ci] Replace Drone with CircleCI
Signed-off-by: Eugenio Paolantonio (g7) <me@medesimo.eu>
2022-10-09 13:26:56 +02:00
Eugenio Paolantonio (g7)
85813e293a [packaging] Provide the virtual packages pulseaudio-modules-droid-apispecific{,-dev}
Signed-off-by: Eugenio Paolantonio (g7) <me@medesimo.eu>
2022-03-06 20:57:49 +01:00
Eugenio Paolantonio (g7)
145e49611a [packaging] Move to the -modern variant
Signed-off-by: Eugenio Paolantonio (g7) <me@medesimo.eu>
2022-02-28 00:59:48 +01:00
Eugenio Paolantonio (g7)
d3253e5175 Merge tag 'upstream/14.2.97' into feature/bookworm/upgrade-14.2.97-modern 2022-02-28 00:57:12 +01:00
Juho Hämäläinen
cef8f78746 Bump packaging version. 2022-02-25 13:11:05 +02:00
Juho Hämäläinen
04b14b8aac
Merge pull request #114 from jusa/cal_wait
Enable audio_cal_wait properly.
2022-02-25 13:10:20 +02:00
Juho Hämäläinen
0adc96eb56 common: Whitespace fix. 2022-02-25 13:05:27 +02:00
Juho Hämäläinen
47a043d8dc common: Enable audio_cal_wait properly.
Actual call to the function was missing.

[common] Enable audio_cal_wait properly. JB#55832
2022-02-25 13:05:10 +02:00
Juho Hämäläinen
a995948689 Bump packaging version. 2022-02-24 15:36:40 +02:00
Juho Hämäläinen
c4be583fbf
Merge pull request #113 from jusa/droid11
Update implementation for Android 11, drop old support.
2022-02-24 15:35:18 +02:00
Juho Hämäläinen
51d85423d5 common: Force mono 16kHz with AUDIO_OUTPUT_FLAG_VOIP_RX. 2022-02-24 15:05:08 +02:00
Juho Hämäläinen
ffe02f26b1 packaging: Update spec.
[pulseaudio-modules-droid] Update implementation for Android 11. Fixes JB#55832
2022-02-24 15:05:08 +02:00
Juho Hämäläinen
8b1bc6cbce packaging: Remove old sbj spec. 2022-02-24 15:05:08 +02:00
Juho Hämäläinen
1c1d82dfb9 README: Update content. 2022-02-24 15:05:06 +02:00
Juho Hämäläinen
5c53ef736f build: Update build flags. 2022-02-24 14:48:12 +02:00
Juho Hämäläinen
77b1e60df0 common: Always flag voip rx if enabled. 2022-02-24 14:48:12 +02:00
Juho Hämäläinen
385ccb8e4c options: voip rx is always enabled 2022-02-24 14:48:12 +02:00
Juho Hämäläinen
a37363a46c card: Create voip_rx sink in communication profile. 2022-02-24 14:48:12 +02:00
Juho Hämäläinen
e0d66cf4ad card: Update card with new common. 2022-02-24 14:48:12 +02:00
Juho Hämäläinen
2d1a50d450 card: Use VSID profiles only for debugging. 2022-02-24 14:48:12 +02:00
Juho Hämäläinen
c895311db5 source: Update source with new common. 2022-02-24 14:48:12 +02:00
Juho Hämäläinen
5238bfd192 sink: Update sink with new common. 2022-02-24 14:48:12 +02:00
Juho Hämäläinen
d4a8167c11 common: Update version requirements. 2022-02-24 14:48:12 +02:00
Juho Hämäläinen
b08cc4d219 common: Implement stream handling using device and mix ports. 2022-02-24 14:48:12 +02:00
Juho Hämäläinen
0b1221a047 card: Remove set_parameters callback. 2022-02-24 14:48:12 +02:00
Juho Hämäläinen
9ffca4ecd5 common: Remove set_parameters callback from card data. 2022-02-24 14:48:12 +02:00
Juho Hämäläinen
c359126658 common: Remove unused enums. 2022-02-24 14:48:12 +02:00
Juho Hämäläinen
73f93f1967 common: Remove _VSID define. 2022-02-24 14:48:12 +02:00
Juho Hämäläinen
5d4a5af1f5 common: Rename quirks to options and use normal modargs for parsing. 2022-02-24 14:48:10 +02:00
Juho Hämäläinen
532f6c55bf common: Update audio enum header.
Use current droid version 11 as base.
2022-02-24 09:08:28 +02:00
Juho Hämäläinen
1ac75ed3b0 common: Remove legacy from converter, parse channels as values. 2022-02-24 09:08:26 +02:00
Juho Hämäläinen
c02f917ebb common: Parser uses new config structures. 2022-02-24 09:08:21 +02:00
Juho Hämäläinen
4ca8716bd1 common: Use replace in place from utils in parser. 2022-02-24 09:08:21 +02:00
Juho Hämäläinen
67eeb83105 common: Parser supports new xml attributes. 2022-02-24 09:08:21 +02:00
Juho Hämäläinen
9e4c6fa8f1 common: Update config structures.
Match xml format style.
2022-02-24 09:08:17 +02:00
Juho Hämäläinen
40c320bc07 common: Add two string utility functions. 2022-02-24 09:08:14 +02:00
Juho Hämäläinen
eefdb31f57 common: Simple list implementation. 2022-02-24 09:08:11 +02:00
Juho Hämäläinen
b4fb20eafe common: Always use expat implementation for parser. 2022-02-23 10:27:49 +02:00
Juho Hämäläinen
fdd22b6949 common: Remove legacy conversion header. 2022-02-23 10:22:22 +02:00
Juho Hämäläinen
17fcb9e074 common: Remove legacy parser. 2022-02-23 10:21:03 +02:00
Juho Hämäläinen
1e992b6954 build: Update flag checks for current version. 2022-02-23 09:23:27 +02:00
Juho Hämäläinen
1daab94724 build: Expat is mandatory. 2022-02-23 09:23:03 +02:00
Juho Hämäläinen
0898217179 Bump packaging version. 2022-02-21 09:34:20 +02:00
Juho Hämäläinen
dbc7d678bb
Merge pull request #112 from jusa/new-api
New API for calling HAL functions.
2022-02-21 09:31:03 +02:00
Juho Hämäläinen
ef56dd4964 README: Add section about pa_shared based API. 2022-02-18 15:45:32 +02:00
Juho Hämäläinen
1cc2a0822e common: New API for calling HAL functions.
New pa_shared based API for calling HAL functions so that other modules
needing these functions don't need to link with libdroid.

[common] New API for calling HAL functions. JB#55832
2022-02-18 15:45:32 +02:00
Juho Hämäläinen
8df3961333
Merge pull request #111 from g7/for-upstream/mer-hybris/no-channels
common: Handle profiles with no supported channels
2022-02-18 15:10:19 +02:00
Eugenio Paolantonio (g7)
b23e20db5c common: Handle profiles with no supported channels
When a profile doesn't have any supported channels, pa_conversion_parse_*_channels
returns false even though the parsing itself succeeded.
This in turn makes the parsing to be aborted altogether.

Handle this case by properly ignoring the profile.

This commit changes the pa_conversion_parse_*_channels functions so that
they return the channel count, or -1 if the parsing has been unsuccessful.

[common] Handle profiles with no supported channels

Signed-off-by: Eugenio Paolantonio (g7) <me@medesimo.eu>
2022-02-18 13:15:21 +01:00
Eugenio Paolantonio (g7)
0886d509fc Merge tag 'upstream/14.2.93' into feature/bookworm/upgrade-14.2.93 2022-01-30 19:10:35 +01:00
Eugenio Paolantonio (g7)
80015ede82 [pulseaudio-modules-droid] Move to bookworm
Signed-off-by: Eugenio Paolantonio (g7) <me@medesimo.eu>
2021-12-08 16:19:04 +01:00
Juho Hämäläinen
9c6842e7d9 Bump packaging version. 2021-10-08 15:43:09 +03:00
Juho Hämäläinen
0d739ca587
Merge pull request #109 from jusa/jb55711
Use more generic stream property for audio source.
2021-10-08 15:42:31 +03:00
Juho Hämäläinen
1781dab3b8 common: Use more generic stream property for audio source.
[common] Use more generic stream property for audio source. JB#55711
2021-10-08 15:20:58 +03:00
Juho Hämäläinen
98d2c7358a Bump packaging version. 2021-10-08 08:32:35 +03:00
Juho Hämäläinen
11a09b005d
Merge pull request #108 from jusa/jb55711
Enable custom audio sources with input streams.
2021-10-08 08:31:12 +03:00
Juho Hämäläinen
d9e2ddfd72 common: Fix segfault with adaptations which assume empty adress is not NULL.
Some adaptations don't check for NULL before using the address which
leads to a crash. Let's just use empty string for address.

[common] Fix segfault with adaptations which assume empty adress is not NULL. Fixes JB#55831
2021-10-08 08:30:12 +03:00
Juho Hämäläinen
baecfc7cdd source: Use source-output proplist when reconfiguring input stream.
Use updated functions from common which utilize proplist when reconfiguring
input stream.

[source] Use source-output proplist when reconfiguring input stream. JB#55711
2021-10-07 12:06:31 +03:00
Juho Hämäläinen
2d7ee841ed common: Allow custom audio source based on property.
When reconfiguring input stream set custom audio source if one
is defined in droid.input.source property. Allowed values are
audio source fancy names listed in
string_conversion_table_audio_source_fancy.

[common] Allow custom audio source based on property. JB#55711
2021-10-07 12:04:52 +03:00
Juho Hämäläinen
4103c31aec common: Add generic converter for fancy audio sources.
[common] Add generic converter for fancy audio sources.
2021-10-07 12:00:59 +03:00
Adam Boardman
a5477e617b Build fix 2021-06-30 19:14:32 +01:00
Adam Boardman
130edc502b Merge remote-tracking branch 'upstream/master' into bullseye 2021-06-18 20:48:34 +01:00
Juho Hämäläinen
8283bbe5c9 Bump packaging version. 2021-05-06 13:11:14 +03:00
Juho Hämäläinen
42af5e85c5
Merge pull request #107 from jusa/jb53992
Add quirks standby_set_route and speaker_before_voice.
2021-05-06 13:10:28 +03:00
Juho Hämäläinen
a676accf88 common: Add quirk speaker_before_voice.
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().

[common] Add quirk speaker_before_voice. JB#53992
2021-05-05 16:05:36 +03:00
Juho Hämäläinen
446ac62a6e common: Add quirk standby_set_route.
Some devices don't like to receive set_parameters() call while they
are in write(), even if it seems the mutexes are correctly in place.
Standby is another synchronization point which seems to work better.

[common] Add quirk standby_set_route. JB#53992
2021-05-05 16:02:51 +03:00
Adam Boardman
930e65658c Fix for presense detection of headset plugging which only reports presence/absense of the microphone part, relates to gemian/gemian#7 2021-05-02 17:06:46 +01:00
Juho Hämäläinen
edec25347e Bump packaging version. 2021-04-22 15:40:52 +03:00
Juho Hämäläinen
8f936ba66f
Merge pull request #104 from jusa/bt_sco
Set BT_SCO parameter for Bluetooth routes.
2021-04-22 15:39:48 +03:00
Juho Hämäläinen
5be0189b91 common: Set BT_SCO parameter for Bluetooth routes.
Some adaptations need parameter BT_SCO set before enabling Bluetooth
HFP/HSP routes. It should be fine to set this parameter for adaptations
which don't need it as they would just ignore a parameter that is
unknown.

[common] Set BT_SCO parameter for Bluetooth routes. Fixes JB#53996
2021-04-21 22:59:19 +03:00
Juho Hämäläinen
38b07e6d45 Bump packaging version. 2021-03-25 21:43:13 +02:00
Juho Hämäläinen
eac4b34d39
Merge pull request #103 from jusa/volume_control
Avoid segfault when voice call starts with deferred volume.
2021-03-25 21:42:14 +02:00
Juho Hämäläinen
3f1cc042bc sink: Avoid segfault when voice call starts with deferred volume.
Calling pa_sink_set_write_volume_callback() from main
thread changes a callback pointer in pa_sink which is
accessed from io thread.

When audio is playing and voice call starts there is a
window where the callback is changed to NULL while io
thread is using it, causing a segfault.

[sink] Avoid segfault when voice call starts with deferred volume. JB#53687
2021-03-25 13:52:56 +02:00
Eugenio Paolantonio (g7)
c6da10943a [ci] Updated to match new name [CI SKIP]
Signed-off-by: Eugenio Paolantonio (g7) <me@medesimo.eu>
2021-03-24 00:39:36 +01:00
Juho Hämäläinen
b310103c0f Bump packaging version. 2021-03-23 18:11:06 +02:00
Juho Hämäläinen
898aacd38e
Merge pull request #102 from jusa/volume_control
Improvements to volume control.
2021-03-23 18:09:28 +02:00
Juho Hämäläinen
4414037c47 sink: Add option to prewrite silence always.
In some cases silence prewrite needs to be done even if the target
device is already active. In this case new "/always" modifier can
be used to enable prewriting always. For example:

prewrite_on_resume=deep_buffer=AUDIO_DEVICE_OUT_SPEAKER:2/always

[sink] Add option to prewrite silence always. JB#53590
2021-03-23 18:08:41 +02:00
Juho Hämäläinen
c9c66b4750 sink: Apply channel average volume to stream.
HAL implementations expect identical volume for both channels
anyway.

[sink] Apply channel average volume to stream. JB#53590
2021-03-23 18:08:02 +02:00
Juho Hämäläinen
65483884ae sink: Enable deferred volume for hw volume control.
Make sure volume changes are applied in between writing to hardware
to avoid volume glitches. As the writing is blocking we cannot synchronize
the changes from main thread easily so better to apply the changes
when nothing is written.

[sink] Enable deferred volume for hw volume control. JB#53590
2021-03-23 18:08:02 +02:00
Juho Hämäläinen
6ef0459669
Merge pull request #101 from jusa/cal
Add quirk for audio calibration.
2021-03-23 18:06:48 +02:00
Juho Hämäläinen
f01f0a53a7 source: Get hw module with new function in stand alone mode.
[source] Get hw module with new function in stand alone mode.
2021-03-18 11:54:12 +02:00
Juho Hämäläinen
997a9c87de sink: Get hw module with new function in stand alone mode.
[sink] Get hw module with new function in stand alone mode.
2021-03-18 11:53:53 +02:00
Juho Hämäläinen
0cd9a16bee README.md: Markdown formatting fixes. 2021-03-18 11:44:57 +02:00
Juho Hämäläinen
45badd1a75 README.md: Rename from README. 2021-03-18 11:44:57 +02:00
Juho Hämäläinen
cb40bac4c5 README: Add notes about audio_cal_wait quirk. 2021-03-18 11:44:57 +02:00
Juho Hämäläinen
b7cbd0ef3d source: Fix format specifiers. 2021-03-18 11:44:57 +02:00
Juho Hämäläinen
9cad56c426 sink: Fix format specifiers. 2021-03-18 11:44:57 +02:00
Juho Hämäläinen
9517a067de common: Fix format specifiers. 2021-03-18 11:44:57 +02:00
Juho Hämäläinen
9282a566c8 common: Add quirk audio_cal_wait.
If there is a device which runs threaded audio calibration after hw
module open we need to wait for a while after opening the first output
stream.

Also when the calibration is already done and we are starting we again
need to wait for a while for the calibration loading to finish.

[common] Add quirk audio_cal_wait. JB#52328
2021-03-18 11:44:54 +02:00
Juho Hämäläinen
7bb06f6a30 card: Parse quirks while loading hw module.
Parse quirks while loading hw module using new pa_droid_hw_module_get2().

[card] Parse quirks while loading hw module. JB#52328
2021-03-18 11:44:09 +02:00
Juho Hämäläinen
501d881534 common: Refactor quirks parsing.
Right now quirks can be used only after hw module is created.
In order to have quirks in the hw module loading phase as well
we need to have a mechanism to have quirk parsing earlier.

[common] Refactor quirks parsing. JB#52328
2021-03-18 11:44:03 +02:00
Eugenio Paolantonio (g7)
74c17e4dab [packaging] pulseaudio-modules-droid-dev: fix dependency on pulseaudio-modules-droid
Signed-off-by: Eugenio Paolantonio (g7) <me@medesimo.eu>
2021-03-13 19:18:47 +01:00
r3vn
88d0b2954a [ci] build using Drone CI 2021-03-02 23:50:32 +01:00
r3vn
3ab49846d2 Merge remote-tracking branch 'mer-hybris/master' into feature/bullseye/14.2.88 2021-03-02 23:49:27 +01:00
Matti Lehtimäki
2f14557d02
Merge pull request #99 from jusa/pa14.2
Update for PulseAudio 14.2.
2021-03-01 14:01:04 +02:00
Juho Hämäläinen
db423101e8 build: Stop using symdef headers for modules.
New simpler macro method does the trick now.
2021-03-01 13:58:22 +02:00
Juho Hämäläinen
5ff7642ca7 source: Remove code needed for versions below 12.
We are moving from 12.2 to 14.2, those are only versions we need to build
against.
2021-03-01 13:58:22 +02:00
Juho Hämäläinen
bbc921b9e5 sink: Remove code needed for versions below 12.
We are moving from 12.2 to 14.2, those are only versions we need to build
against.
2021-03-01 13:58:22 +02:00
Juho Hämäläinen
52711026c2 modules: Add missing include for pa_thread_make_realtime().
[modules] Add missing include. JB#47666
2021-03-01 13:58:22 +02:00
Matti Lehtimäki
7c8862acc4
Merge pull request #100 from mer-hybris/includedir
packaging: Support new droid-devel header location.
2021-02-26 18:20:56 +02:00
Matti Lehtimäki
59203f085e packaging: Support new droid-devel header location.
[packaging] Support new droid-devel header location. JB#51449
2021-02-26 15:07:52 +02:00
Ratchanan Srirattanamet
995913eaf3 add libevdev-dev as a build dependency 2021-01-14 14:07:19 +00:00
Ratchanan Srirattanamet
11697f2cc1 card: read headphone availability from input device
Recent Android devices start to provide headphone availability via input
device instead of h2w switch. This renders droid-extcon useless.

This commit introduce droid-extevdev, a simple code that will read
headphone availability from the input device, using libevdev as an
abstraction layer. This means the code now depends on libevdev (but it
can be made optional later on if needed).

This should make headphone availability works on newer Android devices
without having to resort to h2w kernel driver.
2021-01-14 14:07:19 +00:00
Ratchanan Srirattanamet
e84166816b Add virtual_voice_stream
Adding option to create voice virtual stream when voicecall is active
2021-01-14 14:07:19 +00:00
Alfred Neumayer
a784a5a8fa src: Add h2w detection code from pulseaudio-packaging
This applies changes from pulseaudio-packaging for detecting
headset & headphones via the h2w virtual switch file and udev.

Compared to pulseaudio-packaging this now forces udev as a requirement
rather than providing a compile-time switch.
2021-01-14 14:07:19 +00:00
NeKit
efea2f5e7f New upstream release 12.2.84 2021-01-14 14:07:19 +00:00
NeKit
a3d9a12b94 Add libexpat1-dev as build dependency (for XML config parsing) 2021-01-14 14:07:19 +00:00
TheKit
7090354d13 Branch packaging for Gemian 2021-01-14 14:07:19 +00:00
Jonah Brüchert
d991352f66 Detect pulseaudio version from the system, don't assume it's always the same as the droid module's one 2021-01-14 14:07:19 +00:00
Marius Gripsgard
2bd9ba3f7e Fix pkgconf for debian based systems.
Since debian based systems uses lib/{arch}/ as libdir and /usr/lib/pulse-* for modules this causes -L to search for -ldroid-utils in lib/{arch}/
2021-01-14 14:07:19 +00:00
Jonah Brüchert
69a12761d6 Fix pulseaudio droid module version 2021-01-14 14:07:19 +00:00
Jonah Brüchert
6d2dacec5b Release 12.2.79-2 2021-01-14 14:07:19 +00:00
Jonah Brüchert
83acc45987 Fix generating the pkgconfig files with proper pathes 2021-01-14 14:07:19 +00:00
Jonah Brüchert
9b4a813680 Release new upstream version 12.2.79-1 2021-01-14 14:07:19 +00:00
Jonah Brüchert
5024ba675d Release 12.2.78-1 2021-01-14 14:07:19 +00:00
Jonah Brüchert
da247905d2 New upstream release 12.2.78-1 2021-01-14 14:07:19 +00:00
Jonah Brüchert
a49e117ff7 New upstream release 11.1.76 2021-01-14 14:07:19 +00:00
Jonah Brüchert
209537d75f New upstream release 11.1.75 2021-01-14 14:07:19 +00:00
Jonah Brüchert
e9de637e3a Update Vcs information 2021-01-14 14:07:19 +00:00
Jonah Brüchert
beecdf67e9 Move .gitlab-ci.yml into debian folder 2021-01-14 14:07:19 +00:00
Jonah Brüchert
0d69581452 New upstream release (11.1.74) 2021-01-14 14:07:19 +00:00
Jonah Brüchert
c6f5ed1bed Make sure we install to the correct module path 2021-01-14 14:07:19 +00:00
Jonah Brüchert
44e9b517e6 Add GitLab ci configuration 2021-01-14 14:07:19 +00:00
JBBgameich
3b47553add New upstrem release (11.1.73) 2021-01-14 14:07:19 +00:00
JBBgameich
cbbaf3ab42 New upstream release 2021-01-14 14:07:19 +00:00
JBBgameich
6b1debc680 New upstream release 2021-01-14 14:07:19 +00:00
Bhushan Shah
e5f6f476a3 Revert "rules: Use $(overridden_command)"
This reverts commit 95860ffe29.
2021-01-14 14:07:19 +00:00
JBBgameich
268d4a1230 Remove unused parts according to lintian 2021-01-14 14:07:19 +00:00
JBBgameich
7d3f3cdc78 Run wrap-and-sort 2021-01-14 14:07:19 +00:00
JBBgameich
1707b34059 Update git repository url 2021-01-14 14:07:19 +00:00
JBBgameich
31aa7777d6 rules: Use $(overridden_command) 2021-01-14 14:07:19 +00:00
JBBgameich
407371a656 pulseaudio-module-droid-dev: update dependency name 2021-01-14 14:07:19 +00:00
JBBgameich
c0584f6dff Add workaround for proper path detection 2021-01-14 14:07:19 +00:00
JBBgameich
2d43babb6a New upstream release 11.1.68 2021-01-14 14:07:19 +00:00
JBBgameich
3ab10f1e45 Fix rules 2021-01-14 14:07:19 +00:00
JBBgameich
4568e2cf84 Rename to pulseaudio-module-droid 2021-01-14 14:07:19 +00:00
JBBgameich
15efaa50ff Remove fail-missing 2021-01-14 14:07:19 +00:00
JBBgameich
7003fef295 Fix clean step 2021-01-14 14:07:19 +00:00
JBBgameich
6ce6d707d5 Fix dependency name 2021-01-14 14:07:19 +00:00
JBBgameich
5348730a70 Add basic copyright 2021-01-14 14:07:19 +00:00
JBBgameich
050fd80a16 Initial commit 2021-01-14 14:07:18 +00:00
r3vn
fe0f517719 [packaging] fix missing files 2020-11-02 16:05:09 +01:00
r3vn
2ccbf14739 Merge branch 'upstream' into feature/bullseye/12.2.86 2020-10-30 00:11:03 +01:00
Juho Hämäläinen
22be43a324 Bump packaging version.
And remove Group from spec files.
2020-10-21 13:22:45 +03:00
Juho Hämäläinen
91e9bcbbe7
Merge pull request #98 from jusa/xml-includes
Support includes in module elements with xml configuration.
2020-10-21 13:19:41 +03:00
Juho Hämäläinen
b540528aab parser-xml: Support module includes in configuration files.
[parser-xml] Support module includes in configuration files. Fixes JB#51666
2020-10-21 07:56:25 +03:00
Juho Hämäläinen
d885b86121 parser-xml: Pass root element in parse_file().
Instead of setting it directly to struct parser_data. Also remove
unused root from the struct.
2020-10-20 11:12:11 +03:00
r3vn
7052e809f9 [packaging] fixed package name 2020-10-13 00:31:20 +02:00
Eugenio Paolantonio (g7)
2f5ddab8f4 [packaging] Build-depend on pulseaudio-pulsecore-dev
Signed-off-by: Eugenio Paolantonio (g7) <me@medesimo.eu>
2020-10-11 00:24:48 +02:00
r3vn
08afdc0932 build using travis-ci 2020-10-09 23:17:10 +02:00
Simonas Leleiva
dd83f69d87 Bump packaging version.
Signed-off-by: Simonas Leleiva <simonas.leleiva@jolla.com>
2020-06-22 16:18:54 +02:00
Simonas Leleiva
e46b8c7b0e
Merge pull request #97 from mer-hybris/64bit
Fix for 64bit
2020-06-22 15:17:12 +01:00
Simonas Leleiva
d8faa4a703 packaging: Fix for 64bit
[packaging] Fix for 64bit. JB#50285

Signed-off-by: Simonas Leleiva <simonas.leleiva@jolla.com>
2020-06-22 09:54:49 +02:00
Ratchanan Srirattanamet
bc67f05782 add libevdev-dev as a build dependency 2020-06-03 15:01:49 +02:00
Ratchanan Srirattanamet
5cab2af137 card: read headphone availability from input device
Recent Android devices start to provide headphone availability via input
device instead of h2w switch. This renders droid-extcon useless.

This commit introduce droid-extevdev, a simple code that will read
headphone availability from the input device, using libevdev as an
abstraction layer. This means the code now depends on libevdev (but it
can be made optional later on if needed).

This should make headphone availability works on newer Android devices
without having to resort to h2w kernel driver.
2020-06-03 13:51:08 +02:00
Ratchanan Srirattanamet
81504b9ec4 Add virtual_voice_stream
Adding option to create voice virtual stream when voicecall is active
2020-06-03 13:49:09 +02:00
Alfred Neumayer
0730b77e39 src: Add h2w detection code from pulseaudio-packaging
This applies changes from pulseaudio-packaging for detecting
headset & headphones via the h2w virtual switch file and udev.

Compared to pulseaudio-packaging this now forces udev as a requirement
rather than providing a compile-time switch.
2020-06-03 13:49:09 +02:00
NeKit
e5ba918cdb New upstream release 12.2.84 2020-06-03 01:55:32 +02:00
NeKit
0e120cf797 Merge remote-tracking branch 'mer/master' into buster 2020-06-03 01:54:22 +02:00
Juho Hämäläinen
72d4e0aaca Bump packaging version. 2019-12-10 10:48:34 +02:00
Juho Hämäläinen
dcb0b67f67
Merge pull request #96 from jusa/jb47194
Improve audio mode changes.
2019-12-10 10:47:19 +02:00
Juho Hämäläinen
08c4558f15 common: Always set earpiece routing after enabling voice call mode.
Mode change is applied only after next set_parameters call with route
is made. Usually it's ok to switch to whatever route after mode switch
but some devices don't like it and we end up with silent audio. To work
around these devices always set earpiece as the initial route after
mode change. Correct route is then applied later when other parts of
the system decide what the route should be.

[common] Always set earpiece routing after enabling voice call mode. Fixes JB#47194
2019-12-09 13:48:23 +02:00
Juho Hämäläinen
976a6cf58c card: Park profiles correctly when switching between virtual profiles.
Virtual profiles don't have output or input mappings so calling park_profile()
for one is no-op. To correctly park the sink and source ports we need to call
park_profiles() for the last active real profile.

[card] Park profiles correctly when switching between virtual profiles. JB#47194
2019-12-09 13:44:31 +02:00
Juho Hämäläinen
b36b2431fb common: Remove unused variables. 2019-12-09 13:33:04 +02:00
NeKit
fa0e8a5535 Add libexpat1-dev as build dependency (for XML config parsing) 2019-11-20 00:24:54 +01:00
Juho Hämäläinen
90ca699176 Bump packaging version. 2019-11-19 15:47:29 +02:00
Juho Hämäläinen
25abbb4388
Merge pull request #95 from jusa/input-fixes
Input fixes
2019-11-19 15:46:09 +02:00
Juho Hämäläinen
ca93e01a91 README: Add description for two new quirks. 2019-11-19 15:21:29 +02:00
Juho Hämäläinen
8ed068f68b card: Don't create fast or deep buffer sinks if disabled by quirks. 2019-11-19 15:21:29 +02:00
Juho Hämäläinen
6986d9bf06 common: Add two new quirks and set them enabled by default.
When the quirks are enabled everything works the same as before. Setting
them disabled will affect the behaviour.

[common] Add quirks for FAST and DEEP_BUFFER sinks. JB#48097
2019-11-19 15:21:25 +02:00
Juho Hämäläinen
bfd377a109 common: Check for right pointers in asserts. 2019-11-19 15:21:25 +02:00
Juho Hämäläinen
9d5226d841 parser-xml: Refactor element list frees. 2019-11-19 15:21:25 +02:00
Juho Hämäläinen
9936dfa44f parser-xml: Store profiles correctly for mix and device ports.
[parser-xml] Store profiles correctly for mix and device ports.
2019-11-19 15:21:25 +02:00
Juho Hämäläinen
0e60d133c6 source: Don't cast function pointers. 2019-11-19 15:21:25 +02:00
Juho Hämäläinen
0af48ffd73 source: Reconfigure source to last connected source-output.
When source-output is disconnected from our source reconfigure
to previously connected source-output if applicable.
2019-11-19 15:21:25 +02:00
Juho Hämäläinen
5aeee81b49 source: Reconfigure source if port is changed while source is running.
To ensure proper stream configuration with updated routing
reconfigure running stream on port change.
2019-11-19 15:21:25 +02:00
Juho Hämäläinen
de0d98e6d5 source: Add a workaround for fm-radio loopback.
Refactor reconfiguring part a bit and add a workaround for fm-radio
loopback. As the loopback module is instantiated without defined sink
or source, it uses as default really silly values. But since our source
is reconfiguring itself to whatever is requested things get a bit
hairy. To ensure good values for the source in case of loopback module
connection use metrics from our primary output stream.

[source] Add a workaround for fm-radio loopback. JB#48080
2019-11-19 15:20:47 +02:00
Juho Hämäläinen
44e7b1479d source: Have input stream in correct state after startup. 2019-11-19 15:20:47 +02:00
Juho Hämäläinen
124139f5b9 common: Try opening input stream with defaults before giving up.
[common] Revert to default values if input stream reconfigure fails.
2019-11-19 15:20:14 +02:00
Juho Hämäläinen
a46a5c91a1 common: Use device definition with config fill function. 2019-11-19 15:20:14 +02:00
Juho Hämäläinen
3192069095 common: Store initial input stream metrics as defaults.
And if reconfiguration fails restore defaults instead of
previously used values.
2019-11-19 15:20:14 +02:00
Juho Hämäläinen
a2eb4143ef common: Apply input route immediately after creating input stream.
With some adaptations audio_source_t does not have any effect when
opening the input stream. To ensure proper routing we need to set
input parameters immediately after opening the stream just in case.
2019-11-19 15:20:14 +02:00
Juho Hämäläinen
7b531dfff9 common: Improve stream config fill function for input streams.
We need to be more careful with input streams as due to dynamic
source reconfiguring it may be that bizarre combinations are requested.
Try to make sure that sane combination is actually requested when
opening the input stream.
2019-11-19 15:20:14 +02:00
Juho Hämäläinen
c7a62db215 common: Use device definition when creating output stream. 2019-11-19 15:20:14 +02:00
Juho Hämäläinen
8bc33cfb25 sink: Use device definition regardless of operation mode.
Use device definition for needed info for both standalone mode
and when run under droid card.
2019-11-19 15:20:14 +02:00
Juho Hämäläinen
1151993324 common: Store device definition to droid stream. 2019-11-19 15:20:14 +02:00
Juho Hämäläinen
4afa908867 common: Make primary output stream lookup function public. 2019-11-19 15:20:14 +02:00
Juho Hämäläinen
24e3661259 config: Lookup output or input modules by name. 2019-11-19 15:20:14 +02:00
Juho Hämäläinen
82b46a9ec4 conversion: Add generic string lookup. 2019-11-19 15:20:14 +02:00
Juho Hämäläinen
fcb720b6a3 source: Use reconfigure instead of freeing and re-creating stream.
[source] Reconfigure stream instead of freeing and re-creating.
2019-11-19 15:19:45 +02:00
Juho Hämäläinen
caead9d18c common: Allow reconfiguring input stream.
Instead of needing to free the input stream completely to
reconfigure its metrics allow reconfiguring in-place. Rollback
to previous good values on failure.
2019-11-18 15:52:54 +02:00
Juho Hämäläinen
39fdb85b13 common: Use correct pointer when logging input stream. 2019-11-15 16:28:53 +02:00
Juho Hämäläinen
3ba217920b common: Log input device names when setting new value. 2019-11-15 16:28:53 +02:00
Juho Hämäläinen
1866de8e8d common: Refactor input stream closing a bit. 2019-11-15 16:28:53 +02:00
Juho Hämäläinen
1f6e402f82 common: Refactor stream standby calls. 2019-11-15 16:28:48 +02:00
TheKit
1787c87407 Branch packaging for Gemian 2019-11-13 22:29:18 +01:00
Jonah Brüchert
58d1e45090 Detect pulseaudio version from the system, don't assume it's always the same as the droid module's one 2019-11-13 13:12:02 +01:00
Marius Gripsgard
c5cca5314f Fix pkgconf for debian based systems.
Since debian based systems uses lib/{arch}/ as libdir and /usr/lib/pulse-* for modules this causes -L to search for -ldroid-utils in lib/{arch}/
2019-11-13 13:10:06 +01:00
TheKit
5edb6d17e8 Merge remote-tracking branch 'debian-pm/master' 2019-11-13 13:05:53 +01:00
Juho Hämäläinen
6b9b141ac8 modules: Log when creating.
Easier to spot the log of single entity.
2019-11-13 10:57:43 +02:00
Jonah Brüchert
b5972a7dcc
Fix pulseaudio droid module version 2019-11-12 12:35:59 +01:00
Jonah Brüchert
940476a773
Release 12.2.79-2 2019-11-12 12:06:58 +01:00
Jonah Brüchert
2b9ac12840
Fix generating the pkgconfig files with proper pathes 2019-11-12 12:05:02 +01:00
Juho Hämäläinen
a574c42d7c Bump packaging version. 2019-11-11 09:59:30 +02:00
Juho Hämäläinen
9363d97953
Merge pull request #94 from mer-hybris/jb48080
common: Add missing configuration file search locations.
2019-11-11 09:58:09 +02:00
Matti Lehtimäki
11ea0a60bd common: Add missing configuration file search locations.
[common] Add missing configuration file search locations. JB#48080
2019-11-11 14:47:20 +07:00
Juho Hämäläinen
3ee8e16ad3 Bump packaging version. 2019-10-09 15:02:54 +03:00
Juho Hämäläinen
d10db89b9f Merge branch 'license' 2019-10-09 11:39:22 +03:00
MikeSalmela
033ad34ca6 license: Fix license in spec.
[license] Fix license in spec. JB#45486
2019-10-09 11:28:48 +03:00
Juho Hämäläinen
efb1bcf8cc Merge branch 'pulse-13-compat' 2019-10-09 11:18:26 +03:00
Alexey Min
21b3c42db7 modules: Fix compatibility with PulseAudio 13.0.
There were some API changes:
 - 878ef44079
 - 6665b466d2

Leading to:
 Error relocating /usr/lib/pulse-13.0/modules/libdroid-sink.so: pa_make_realtime: symbol not found
 Error relocating /usr/lib/pulse-13.0/modules/libdroid-source.so: pa_make_realtime: symbol not found
 Error relocating /usr/lib/pulse-13.0/modules/libdroid-source.so: pa_source_get_state: symbol not found

Fixes are:
 - include <pulse/util.h>, replace pa_make_realtime -> pa_thread_make_realtime
 - replace pa_source_get_state(X) -> X->state
 - replace pa_sink_get_state(X) -> X->state

[modules] Fix compatibility with PulseAudio 13.0. JB#47666
2019-10-09 11:18:21 +03:00
Juho Hämäläinen
97a0c98f84 README: Update keepalive state. 2019-10-09 11:18:08 +03:00
Juho Hämäläinen
e099a0884e packaging: Add require for pulseaudio-module-keepalive. 2019-10-09 10:58:15 +03:00
Juho Hämäläinen
48a96e89ce packaging: No more keepalive, nothing needs D-Bus. 2019-10-09 10:56:52 +03:00
Juho Hämäläinen
89cdbb8be7 build: Nothing needs D-Bus. 2019-10-09 10:56:52 +03:00
Juho Hämäläinen
c16bfaa1ce keepalive: Remove module.
[keepalive] Module relocated to its own package. JB#47579

Module relocated to its own package pulseaudio-module-keepalive.
2019-10-09 10:56:19 +03:00
Jonah Brüchert
6803ef07e7
Release new upstream version 12.2.79-1 2019-10-06 15:23:59 +02:00
Jonah Brüchert
ec3260a88f
Release 12.2.78-1 2019-04-25 22:37:48 +02:00
Jonah Brüchert
a61a670284
New upstream release 12.2.78-1 2019-04-25 22:37:32 +02:00
Jonah Brüchert
ad620b712a
New upstream release 11.1.76 2018-12-03 21:39:37 +01:00
Jonah Brüchert
8ef0e32e18
New upstream release 11.1.75 2018-11-13 21:18:48 +01:00
Jonah Brüchert
05a5925baf
Update Vcs information 2018-11-02 19:14:50 +01:00
Jonah Brüchert
f293111905
Move .gitlab-ci.yml into debian folder 2018-10-24 18:17:10 +02:00
Jonah Brüchert
addd9f1adc
New upstream release (11.1.74) 2018-10-13 20:53:09 +02:00
Jonah Brüchert
6355803c66
Make sure we install to the correct module path 2018-10-13 20:52:37 +02:00
Jonah Brüchert
ed595dec5b
Add GitLab ci configuration 2018-10-07 00:52:19 +02:00
JBBgameich
9d09908b82 New upstrem release (11.1.73) 2018-08-28 18:57:12 +02:00
JBBgameich
36c03408c1 New upstream release 2018-08-28 18:24:35 +02:00
JBBgameich
8ad1d210a8 New upstream release 2018-08-28 18:24:35 +02:00
Bhushan Shah
ec084f07a2 Revert "rules: Use $(overridden_command)"
This reverts commit 95860ffe29.
2018-08-27 09:40:14 +05:30
JBBgameich
5573d62ebe
Remove unused parts according to lintian 2018-07-04 14:21:03 +02:00
JBBgameich
88c2be2333 Run wrap-and-sort 2018-06-24 16:19:11 +00:00
JBBgameich
ffee6f91fc Update git repository url 2018-06-22 19:22:01 +00:00
JBBgameich
95860ffe29 rules: Use $(overridden_command) 2018-06-19 19:43:40 +02:00
JBBgameich
12185c8601 pulseaudio-module-droid-dev: update dependency name 2018-06-08 17:20:50 +00:00
JBBgameich
32edc3fea0 Add workaround for proper path detection 2018-06-06 15:01:08 +00:00
JBBgameich
736a82a7a1 New upstream release 11.1.68 2018-06-06 14:06:27 +00:00
JBBgameich
9e5b1fa04a Fix rules 2018-06-03 10:33:56 +00:00
JBBgameich
1a7bf9de98 Rename to pulseaudio-module-droid 2018-06-03 09:08:01 +00:00
JBBgameich
c31ce84c0f Remove fail-missing 2018-05-27 00:10:39 +02:00
JBBgameich
672f6a9455 Fix clean step 2018-05-26 22:31:21 +02:00
JBBgameich
91dbb2459e Fix dependency name 2018-05-26 22:03:45 +02:00
JBBgameich
48756afc70 Add basic copyright 2018-05-26 20:58:02 +02:00
JBBgameich
4edf08d933 Initial commit 2018-05-26 20:51:54 +02:00
51 changed files with 4702 additions and 4077 deletions

3
.gitignore vendored
View file

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

411
README
View file

@ -1,411 +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.
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
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 or deep buffer outputs.
For example configuration with
audio_hw_modules {
primary {
outputs {
primary {}
deep_buffer {}
}
inputs {
primary {}
voice_rx {}
}
}
other {
...
}
}
The default profile would contain two sinks, sink.primary and sink.deep_buffer
and one source, source.droid.
Usually this default profile is everything that is needed in normal use, and
additional profiles created should be needed only for testing things out etc.
virtual profiles
----------------
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.
debugging profiles
------------------
If needed in favour of default profile one can opt to creating combinations
of all output and input definitions in a module definition. This can be
done by passing "default=false" to module-droid-card. Module argument
module_id will then defines which module to load (by default "primary").
Without default profile all input and output definitions are translated
to PulseAudio card profiles. For example configuration with
audio_hw_modules {
primary {
outputs {
primary {}
lpa {}
}
inputs {
primary {}
}
}
other {
...
}
}
Would map to card profiles (<output>-<input>) primary-primary and lpa-primary.
module-droid-sink and module-droid-source
-----------------------------------------
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)
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)
a) source is configured with 44100Hz, stereo
b) so1 connects to the source without resampler
2) source-output 16000Hz, mono connects (so2)
a) so1 is detached from the source
b) source is configured with 16000Hz, mono
c) so2 connects to the source without resampler
d) resampler is created for so1, 16000Hz, mono -> 44100Hz stereo
f) so1 is re-attached to the source through resampler
3) source-output 16000Hz, mono connects (so3)
a) so1 and so2 are detached from the source
b) so3 connects to the source without resampler
c) so1 is re-attached to the source through resampler
d) 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
* 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.
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
View 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");

View file

@ -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,92 +183,30 @@ 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])
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_INPUT_FLAG_RAW])
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_INPUT_FLAG_SYNC])
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_INPUT_FLAG_MMAP_NOIRQ])
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_INPUT_FLAG_VOIP_TX])
# Channels
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_MONO])
CC_CHECK_DROID_ENUM([${DROIDHEADERS_CFLAGS}], [AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO])
@ -336,5 +274,4 @@ echo "
modules directory: ${modlibexecdir}
Droid device: ${droiddevice}
XML config support: ${ENABLE_XML}
"

98
debian/changelog vendored Normal file
View 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
View file

@ -0,0 +1 @@
11

43
debian/control vendored Normal file
View 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
View 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
View file

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

View file

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

View 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
View 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
View file

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

View file

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

142
etc/pulse/default.pa.gemian Normal file
View 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

View file

@ -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}.80
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

View file

@ -5,21 +5,20 @@
Name: pulseaudio-modules-droid
Summary: PulseAudio Droid HAL modules
Version: %{pulsemajorminor}.80
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

View file

@ -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)

View file

@ -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;
}

View file

@ -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);
}
@ -588,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);
@ -653,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));
@ -670,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);
@ -679,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;
@ -731,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;
@ -757,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();
}
@ -792,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;
@ -844,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;
@ -874,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);
@ -903,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;
@ -1045,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)
@ -1059,5 +1246,3 @@ done:
return config;
}
#endif

View file

@ -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

View file

@ -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,

View file

@ -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;
}

View file

@ -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

View file

@ -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,30 +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. */
STRING_ENTRY_IF_AUDIO_DEVICE_OUT_HDMI
STRING_ENTRY_IF_AUDIO_DEVICE_OUT_HDMI_ARC
STRING_ENTRY_IF_AUDIO_DEVICE_OUT_TELEPHONY_TX
STRING_ENTRY_IF_AUDIO_DEVICE_OUT_LINE
STRING_ENTRY_IF_AUDIO_DEVICE_OUT_SPDIF
STRING_ENTRY_IF_AUDIO_DEVICE_OUT_AUX_LINE
STRING_ENTRY_IF_AUDIO_DEVICE_OUT_SPEAKER_SAFE
STRING_ENTRY_IF_AUDIO_DEVICE_OUT_FM
STRING_ENTRY_IF_AUDIO_DEVICE_OUT_FM_TX
STRING_ENTRY_IF_AUDIO_DEVICE_OUT_ANC_HEADSET
STRING_ENTRY_IF_AUDIO_DEVICE_OUT_ANC_HEADPHONE
STRING_ENTRY_IF_AUDIO_DEVICE_OUT_PROXY
STRING_ENTRY_IF_AUDIO_DEVICE_OUT_IP
{ 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 }
};
@ -167,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" },
@ -183,23 +196,21 @@ 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_TELEPHONY_TX, "output-telephony_tx" },
{ AUDIO_DEVICE_OUT_LINE, "output-line" },
{ AUDIO_DEVICE_OUT_HDMI_ARC, "output-hdmi_arc" },
{ AUDIO_DEVICE_OUT_SPDIF, "output-spdif" },
{ AUDIO_DEVICE_OUT_FM, "output-fm" },
{ AUDIO_DEVICE_OUT_AUX_LINE, "output-aux_line" },
{ AUDIO_DEVICE_OUT_SPEAKER_SAFE, "output-speaker_safe" },
{ AUDIO_DEVICE_OUT_IP, "output-ip" },
{ AUDIO_DEVICE_OUT_BUS, "output-bus" },
{ AUDIO_DEVICE_OUT_PROXY, "output-proxy" },
{ AUDIO_DEVICE_OUT_USB_HEADSET, "output-usb_headset" },
{ AUDIO_DEVICE_OUT_HEARING_AID, "output-hearing_aid" },
{ AUDIO_DEVICE_OUT_ECHO_CANCELLER, "output-echo_canceller" },
{ AUDIO_DEVICE_OUT_DEFAULT, "output-default" },
/* Devices which may or may not be defined for all devices, */
FANCY_ENTRY_IF_AUDIO_DEVICE_OUT_HDMI ( "output-hdmi" )
FANCY_ENTRY_IF_AUDIO_DEVICE_OUT_HDMI_ARC ( "output-hdmi_arc" )
FANCY_ENTRY_IF_AUDIO_DEVICE_OUT_TELEPHONY_TX ( "output-telephony_tx" )
FANCY_ENTRY_IF_AUDIO_DEVICE_OUT_LINE ( "output-line" )
FANCY_ENTRY_IF_AUDIO_DEVICE_OUT_SPDIF ( "output-spdif" )
FANCY_ENTRY_IF_AUDIO_DEVICE_OUT_AUX_LINE ( "output-aux_line" )
FANCY_ENTRY_IF_AUDIO_DEVICE_OUT_SPEAKER_SAFE ( "output-speaker_safe" )
FANCY_ENTRY_IF_AUDIO_DEVICE_OUT_FM ( "output-fm" )
FANCY_ENTRY_IF_AUDIO_DEVICE_OUT_FM_TX ( "output-fm_tx" )
FANCY_ENTRY_IF_AUDIO_DEVICE_OUT_ANC_HEADSET ( "output-and_headset" )
FANCY_ENTRY_IF_AUDIO_DEVICE_OUT_ANC_HEADPHONE ( "output-anc_headphone" )
FANCY_ENTRY_IF_AUDIO_DEVICE_OUT_PROXY ( "output-proxy" )
FANCY_ENTRY_IF_AUDIO_DEVICE_OUT_IP ( "output-ip" )
{ 0, NULL }
};
@ -213,39 +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. */
STRING_ENTRY_IF_AUDIO_DEVICE_IN_HDMI
STRING_ENTRY_IF_AUDIO_DEVICE_IN_TELEPHONY_RX
STRING_ENTRY_IF_AUDIO_DEVICE_IN_FM_TUNER
STRING_ENTRY_IF_AUDIO_DEVICE_IN_TV_TUNER
STRING_ENTRY_IF_AUDIO_DEVICE_IN_LINE
STRING_ENTRY_IF_AUDIO_DEVICE_IN_SPDIF
STRING_ENTRY_IF_AUDIO_DEVICE_IN_BLUETOOTH_A2DP
STRING_ENTRY_IF_AUDIO_DEVICE_IN_LOOPBACK
STRING_ENTRY_IF_AUDIO_DEVICE_IN_PROXY
/* 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
STRING_ENTRY_IF_AUDIO_DEVICE_IN_IP
#ifdef DROID_AUDIO_HAL_SECONDARY_MIC
STRING_ENTRY( AUDIO_DEVICE_IN_SECONDARY_MIC ),
#endif
/* Combination entries consisting of multiple devices defined above.
* These don't require counterpart in string_conversion_table_input_device_fancy. */
STRING_ENTRY( AUDIO_DEVICE_IN_ALL ),
STRING_ENTRY( AUDIO_DEVICE_IN_ALL_SCO ),
STRING_ENTRY_IF_AUDIO_DEVICE_IN_ALL_USB
{ 0, NULL }
};
@ -258,31 +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, */
FANCY_ENTRY_IF_AUDIO_DEVICE_IN_HDMI ( "input-hdmi" )
FANCY_ENTRY_IF_AUDIO_DEVICE_IN_TELEPHONY_RX ( "input-telephony_rx" )
FANCY_ENTRY_IF_AUDIO_DEVICE_IN_FM_TUNER ( "input-fm_tuner" )
FANCY_ENTRY_IF_AUDIO_DEVICE_IN_TV_TUNER ( "input-tv_tuner" )
FANCY_ENTRY_IF_AUDIO_DEVICE_IN_LINE ( "input-line" )
FANCY_ENTRY_IF_AUDIO_DEVICE_IN_SPDIF ( "input-spdif" )
FANCY_ENTRY_IF_AUDIO_DEVICE_IN_BLUETOOTH_A2DP ( "input-bluetooth_a2dp" )
FANCY_ENTRY_IF_AUDIO_DEVICE_IN_LOOPBACK ( "input-loopback" )
FANCY_ENTRY_IF_AUDIO_DEVICE_IN_PROXY ( "input-proxy" )
/* 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" )
FANCY_ENTRY_IF_AUDIO_DEVICE_IN_IP ( "input-ip" )
#ifdef DROID_AUDIO_HAL_SECONDARY_MIC
{ AUDIO_DEVICE_IN_SECONDARY_MIC, "input-secondary_mic" },
#endif
{ 0, NULL }
};
@ -298,8 +303,11 @@ 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, */
/* 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" )
@ -314,33 +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 ),
STRING_ENTRY( AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD ),
STRING_ENTRY( AUDIO_OUTPUT_FLAG_NON_BLOCKING ),
STRING_ENTRY( AUDIO_OUTPUT_FLAG_HW_AV_SYNC ),
STRING_ENTRY( AUDIO_OUTPUT_FLAG_TTS ),
STRING_ENTRY( AUDIO_OUTPUT_FLAG_RAW ),
STRING_ENTRY( AUDIO_OUTPUT_FLAG_SYNC ),
STRING_ENTRY( AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO ),
STRING_ENTRY( AUDIO_OUTPUT_FLAG_DIRECT_PCM ),
STRING_ENTRY( AUDIO_OUTPUT_FLAG_MMAP_NOIRQ ),
STRING_ENTRY( AUDIO_OUTPUT_FLAG_VOIP_RX ),
STRING_ENTRY( AUDIO_OUTPUT_FLAG_INCALL_MUSIC ),
/* Audio output flags which may or may not be defined for all devices,
* update configure.ac CC_CHECK_DROID_ENUM list if you encounter new ones. */
STRING_ENTRY_IF_AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD
STRING_ENTRY_IF_AUDIO_OUTPUT_FLAG_NON_BLOCKING
STRING_ENTRY_IF_AUDIO_OUTPUT_FLAG_HW_AV_SYNC
STRING_ENTRY_IF_AUDIO_OUTPUT_FLAG_VOIP_RX
STRING_ENTRY_IF_AUDIO_OUTPUT_FLAG_INCALL_MUSIC
/* Audio output flags which may or may not be defined for all devices. */
STRING_ENTRY_IF_AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH
STRING_ENTRY_IF_AUDIO_OUTPUT_FLAG_TTS
STRING_ENTRY_IF_AUDIO_OUTPUT_FLAG_RAW
STRING_ENTRY_IF_AUDIO_OUTPUT_FLAG_SYNC
STRING_ENTRY_IF_AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO
{ 0, NULL }
};
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. */
STRING_ENTRY_IF_AUDIO_INPUT_FLAG_NONE
STRING_ENTRY_IF_AUDIO_INPUT_FLAG_FAST
STRING_ENTRY_IF_AUDIO_INPUT_FLAG_HW_HOTWORD
STRING_ENTRY_IF_AUDIO_INPUT_FLAG_RAW
STRING_ENTRY_IF_AUDIO_INPUT_FLAG_SYNC
STRING_ENTRY_IF_AUDIO_INPUT_FLAG_MMAP_NOIRQ
STRING_ENTRY_IF_AUDIO_INPUT_FLAG_VOIP_TX
STRING_ENTRY( AUDIO_INPUT_FLAG_NONE ),
STRING_ENTRY( AUDIO_INPUT_FLAG_FAST ),
STRING_ENTRY( AUDIO_INPUT_FLAG_HW_HOTWORD ),
STRING_ENTRY( AUDIO_INPUT_FLAG_RAW ),
STRING_ENTRY( AUDIO_INPUT_FLAG_SYNC ),
STRING_ENTRY( AUDIO_INPUT_FLAG_MMAP_NOIRQ ),
STRING_ENTRY( AUDIO_INPUT_FLAG_VOIP_TX ),
STRING_ENTRY( AUDIO_INPUT_FLAG_HW_AV_SYNC ),
STRING_ENTRY( AUDIO_INPUT_FLAG_DIRECT ),
{ 0, NULL }
};
@ -369,13 +378,6 @@ struct string_conversion string_conversion_table_output_channels[] = {
STRING_ENTRY( AUDIO_CHANNEL_OUT_STEREO ),
STRING_ENTRY( AUDIO_CHANNEL_OUT_QUAD ),
STRING_ENTRY_IF_AUDIO_CHANNEL_OUT_SURROUND
STRING_ENTRY( AUDIO_CHANNEL_OUT_5POINT1 ),
STRING_ENTRY_IF_AUDIO_CHANNEL_OUT_5POINT1_BACK
STRING_ENTRY_IF_AUDIO_CHANNEL_OUT_5POINT1_SIDE
STRING_ENTRY(AUDIO_CHANNEL_OUT_7POINT1 ),
STRING_ENTRY(AUDIO_CHANNEL_OUT_ALL ),
{ 0, NULL }
};
@ -397,7 +399,6 @@ 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 ),
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
@ -409,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 ),
@ -424,12 +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. */
STRING_ENTRY_IF_AUDIO_FORMAT_PCM_OFFLOAD
STRING_ENTRY_IF_AUDIO_FORMAT_FLAC
STRING_ENTRY_IF_AUDIO_FORMAT_OPUS
{ 0, NULL }
};

File diff suppressed because it is too large Load diff

View file

@ -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);

View file

@ -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

View file

@ -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,8 +98,8 @@ 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;
@ -95,14 +108,11 @@ struct pa_droid_hw_module {
pa_atomic_t active_outputs;
pa_droid_quirks *quirks;
pa_droid_options options;
/* Mode and input control */
struct _state {
audio_mode_t mode;
audio_devices_t input_device;
audio_source_t audio_source;
pa_droid_stream *active_input;
} state;
};
@ -110,36 +120,46 @@ 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 req_sample_spec;
pa_channel_map req_channel_map;
audio_source_t audio_source;
dm_config_port *default_mix_port;
dm_config_port *input_port;
pa_droid_stream *active_input;
uint32_t flags;
uint32_t device;
bool first;
};
struct pa_droid_stream {
PA_REFCNT_DECLARE;
pa_droid_hw_module *module;
dm_config_port *mix_port;
size_t buffer_size;
void *data;
audio_io_handle_t io_handle;
audio_patch_handle_t audio_patch;
const dm_config_port *active_device_port;
pa_droid_output_stream *output;
pa_droid_input_stream *input;
};
struct pa_droid_card_data {
void *userdata;
/* General functions */
char *module_id;
common_set_parameters_cb_t set_parameters;
};
@ -149,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;
@ -164,9 +184,9 @@ typedef struct pa_droid_port {
struct pa_droid_mapping {
pa_droid_profile_set *profile_set;
const pa_droid_config_device *output;
/* Use all devices in one input */
const pa_droid_config_device *inputs;
dm_config_module *module;
dm_config_port *mix_port;
dm_list *device_ports;
char *name;
char *description;
@ -185,7 +205,7 @@ 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;
@ -197,12 +217,13 @@ typedef struct pa_droid_profile {
* 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;
@ -213,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);
@ -239,11 +247,10 @@ void pa_droid_hw_module_lock(pa_droid_hw_module *hw);
bool pa_droid_hw_module_try_lock(pa_droid_hw_module *hw);
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);
@ -252,14 +259,11 @@ int pa_droid_hw_mic_get_mute(pa_droid_hw_module *hw_module, bool *muted);
void pa_droid_hw_mic_set_mute(pa_droid_hw_module *hw_module, bool muted);
/* 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);
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);
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. */
@ -275,6 +279,7 @@ void pa_droid_add_card_ports(pa_card_profile *cp, pa_hashmap *ports, pa_droid_ma
/* 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);
@ -286,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:
@ -298,15 +303,25 @@ 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);
/* 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 *requested_sample_spec,
const pa_channel_map *requested_channel_map);
bool pa_droid_hw_set_input_device(pa_droid_hw_module *hw_module,
audio_devices_t device);
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);
@ -335,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);

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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
View 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
View 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;
}

View file

@ -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
View 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
View 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
View 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);
}

View 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

View file

@ -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,7 +69,6 @@ struct userdata {
pa_rtpoll *rtpoll;
pa_memchunk memchunk;
audio_devices_t primary_devices;
size_t source_buffer_size;
size_t buffer_size;
@ -81,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"
@ -93,59 +90,17 @@ 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);
/* 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 do_routing(struct userdata *u, audio_devices_t devices) {
int ret;
audio_devices_t old_device;
pa_assert(u);
assert_stream(u->stream, return 0);
if (u->primary_devices == devices)
pa_log_debug("Refresh active device routing.");
old_device = u->primary_devices;
u->primary_devices = devices;
ret = pa_droid_stream_set_route(u->stream, devices);
if (ret < 0)
u->primary_devices = old_device;
return ret;
}
static bool parse_device_list(const char *str, audio_devices_t *dst) {
pa_assert(str);
pa_assert(dst);
char *dev;
const char *state = NULL;
*dst = 0;
while ((dev = pa_split(str, "|", &state))) {
audio_devices_t d;
if (!pa_string_convert_input_device_str_to_num(dev, &d)) {
pa_log_warn("Unknown device %s", dev);
pa_xfree(dev);
return false;
}
*dst |= d;
pa_xfree(dev);
}
return true;
}
static int thread_read(struct userdata *u) {
void *p;
ssize_t readd;
@ -172,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;
}
@ -211,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);
@ -319,34 +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: {
int r;
if ((r = source_set_state_in_io_thread_cb(u->source, PA_PTR_TO_UINT(data), 0)) < 0)
return r;
}
#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;
@ -356,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. */
@ -364,13 +295,12 @@ static int source_set_port_cb(pa_source *s, pa_device_port *p) {
return 0;
}
pa_log_debug("Source set port %#010x", data->device);
pa_log_debug("Source set port %#010x (%s)", data->device_port->type, data->device_port->name);
if (!PA_SOURCE_IS_OPENED(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;
}
@ -437,9 +367,9 @@ static void update_latency(struct userdata *u) {
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, pa_droid_stream_sample_spec(u->stream)));
@ -449,23 +379,17 @@ static void update_latency(struct userdata *u) {
pa_log_debug("Set fixed latency %" PRIu64 " usec", pa_bytes_to_usec(u->buffer_size, pa_droid_stream_sample_spec(u->stream)));
}
static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_output_new_data *new_data, 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) {
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;
/* Not meant for us */
if (new_data->source != u->source)
return PA_HOOK_OK;
if (pa_sample_spec_equal(&new_data->sample_spec, pa_droid_stream_sample_spec(u->stream)) &&
pa_channel_map_equal(&new_data->channel_map, pa_droid_stream_channel_map(u->stream)))
return PA_HOOK_OK;
pa_log_info("New source-output connecting and our source needs to be reconfigured.");
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.
@ -477,25 +401,26 @@ static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_ou
old_channel_map = *pa_droid_stream_channel_map(u->stream);
old_sample_spec = *pa_droid_stream_sample_spec(u->stream);
new_channel_map = new_data->channel_map;
new_sample_spec = new_data->sample_spec;
new_channel_map = reconfigure_channel_map ? *reconfigure_channel_map : old_channel_map;
new_sample_spec = reconfigure_sample_spec ? *reconfigure_sample_spec : old_sample_spec;
pa_droid_stream_unref(u->stream);
if (!(u->stream = pa_droid_open_input_stream(u->hw_module, &new_sample_spec, &new_channel_map)))
u->stream = pa_droid_open_input_stream(u->hw_module, &old_sample_spec, &old_channel_map);
if (update_device_port)
pa_droid_stream_set_route(u->stream, update_device_port);
if (u->stream) {
/* 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));
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);
@ -503,14 +428,77 @@ static pa_hook_result_t source_output_new_hook_callback(pa_core *c, pa_source_ou
if (source_outputs && u->source) {
pa_source_move_all_finish(u->source, source_outputs, false);
}
}
static pa_hook_result_t source_output_new_hook_callback(void *hook_data,
void *call_data,
void *slot_data) {
pa_source_output_new_data *new_data = call_data;
struct userdata *u = slot_data;
pa_droid_stream *primary_output;
/* Not meant for us */
if (new_data->source != u->source)
return PA_HOOK_OK;
if (!pa_droid_stream_reconfigure_input_needed(u->stream,
&new_data->sample_spec,
&new_data->channel_map,
new_data->proplist))
return PA_HOOK_OK;
pa_log_info("New source-output connecting and our source needs to be reconfigured.");
/* Workaround for fm-radio loopback */
if (pa_safe_streq(pa_proplist_gets(new_data->proplist, "media.name"), "fmradio-loopback-source") &&
(primary_output = pa_droid_hw_primary_output_stream(u->hw_module))) {
pa_log_debug("Workaround for fm-radio loopback.");
source_reconfigure(u,
pa_droid_stream_sample_spec(primary_output),
pa_droid_stream_channel_map(primary_output),
new_data->proplist,
NULL);
} else
source_reconfigure(u, &new_data->sample_spec, &new_data->channel_map, new_data->proplist, NULL);
return PA_HOOK_OK;
}
static void source_reconfigure_after_changes(struct userdata *u) {
pa_source_output *so = NULL;
pa_source_output *so_i;
void *state = NULL;
if (!pa_source_used_by(u->source))
return;
/* Find last inserted source-output */
so = pa_idxset_iterate(u->source->outputs, &state, NULL);
if (so) {
while ((so_i = pa_idxset_iterate(u->source->outputs, &state, NULL)))
so = so_i;
}
if (so && pa_droid_stream_reconfigure_input_needed(u->stream,
&so->sample_spec,
&so->channel_map,
so->proplist)) {
pa_log_info("Source-output disconnected and our source needs to be reconfigured.");
source_reconfigure(u, &so->sample_spec, &so->channel_map, so->proplist, NULL);
}
}
static pa_hook_result_t source_output_unlink_post_hook_callback(void *hook_data,
void *call_data,
void *slot_data) {
source_reconfigure_after_changes(slot_data);
return PA_HOOK_OK;
}
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) {
@ -519,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->inputs->module->name;
module_id = am->mix_port->name;
else
module_id = pa_modargs_get_value(ma, "module_id", DEFAULT_MODULE_ID);
@ -600,44 +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);
}
}
pa_droid_hw_set_input_device(u->hw_module, dev_in);
u->stream = pa_droid_open_input_stream(u->hw_module, &sample_spec, &channel_map);
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.");
@ -648,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)
@ -689,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);
@ -717,16 +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);
/* 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, (pa_hook_cb_t) source_output_new_hook_callback, u);
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)

View file

@ -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);

View file

@ -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);
}

View file

@ -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>
*
@ -61,10 +61,11 @@
#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");
@ -75,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=<unused, always 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[] = {
@ -99,26 +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",
"merge_inputs",
"quirks",
"voice_virtual_stream",
/* DM_OPTIONS */
NULL,
};
@ -160,6 +152,9 @@ struct userdata {
pa_card_profile *real_profile;
pa_droid_extcon *extcon;
pa_droid_extevdev *extevdev;
pa_modargs *modargs;
pa_card *card;
};
@ -173,7 +168,7 @@ struct profile_data {
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"
@ -217,7 +212,7 @@ static bool voicecall_vowlan_vsid_profile_event_cb(struct userdata *u, pa_droid_
static bool voicecall_voicemmode1_vsid_profile_event_cb(struct userdata *u, pa_droid_profile *p, bool enabling);
static bool voicecall_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;
@ -270,16 +265,6 @@ static pa_card_profile* add_virtual_profile(struct userdata *u, const char *name
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;
@ -300,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;
@ -318,23 +357,23 @@ 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;
if ((am = ap->input_mapping)) {
const pa_droid_config_device *input;
PA_IDXSET_FOREACH(am, ap->input_mappings, idx) {
cp->n_sources++;
pa_droid_add_card_ports(cp, ports, am, u->core);
SLLIST_FOREACH(input, am->inputs)
max_channels = popcount(input->channel_masks) > max_channels
? popcount(input->channel_masks) : max_channels;
max_channels = max_channels_for_mix_port(am->mix_port, max_channels);
}
cp->max_source_channels = max_channels;
@ -373,12 +412,20 @@ static void init_profile(struct userdata *u) {
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->droid_profile && (am = d->droid_profile->input_mapping)) {
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);
}
}
}
@ -430,19 +477,51 @@ static bool voicecall_profile_event_cb(struct userdata *u, pa_droid_profile *p,
if (enabling) {
pa_droid_sink_set_voice_control(am_output->sink, true);
if (pa_droid_quirk(u->hw_module, QUIRK_REALCALL))
if (pa_droid_option(u->hw_module, DM_OPTION_REALCALL))
pa_droid_set_parameters(u->hw_module, VENDOR_EXT_REALCALL_ON);
} else {
pa_droid_sink_set_voice_control(am_output->sink, false);
if (pa_droid_quirk(u->hw_module, QUIRK_REALCALL))
if (pa_droid_option(u->hw_module, DM_OPTION_REALCALL))
pa_droid_set_parameters(u->hw_module, VENDOR_EXT_REALCALL_OFF);
}
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;
@ -491,7 +570,7 @@ static bool voicecall_voicemmode2_vsid_profile_event_cb(struct userdata *u, pa_d
{
return voicecall_vsid(u, p, VOICEMMODE2_VSID, enabling);
}
#endif /* DROID_AUDIO_HAL_USE_VSID */
#endif /* DROID_AUDIO_HAL_DEBUG_VSID */
static void virtual_event(struct userdata *u, struct profile_data *profile, bool enabling) {
pa_assert(u);
@ -524,7 +603,7 @@ static pa_card_profile *leave_virtual_profile(struct userdata *u, pa_card *c,
pa_log_debug("Leave virtual profile %s", current->droid_profile->name);
if (next->mode != current->mode) {
park_profile(current->droid_profile);
park_profile(card_get_droid_profile(u->real_profile));
pa_droid_hw_set_mode(u->hw_module, next->mode);
}
@ -577,7 +656,7 @@ static void enter_virtual_profile(struct userdata *u, pa_card *c,
}
if (next->mode != current->mode) {
park_profile(current->droid_profile);
park_profile(card_get_droid_profile(u->real_profile));
pa_droid_hw_set_mode(u->hw_module, next->mode);
}
@ -661,6 +740,9 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
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);
@ -671,13 +753,18 @@ static int card_set_profile(pa_card *c, pa_card_profile *new_profile) {
}
}
if (next->droid_profile && (am = next->droid_profile->input_mapping)) {
if (!am->source)
am->source = pa_droid_source_new(u->module, u->modargs, __FILE__, (audio_devices_t) 0, &u->card_data, am, u->card);
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 (source_outputs && am->source) {
pa_source_move_all_finish(am->source, source_outputs, false);
source_outputs = NULL;
if (!am->source)
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);
source_outputs = NULL;
}
}
}
@ -702,22 +789,16 @@ 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;
bool default_profile = true;
const char *quirks;
pa_card_profile *voicecall = NULL;
pa_assert(m);
if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
pa_log("Failed to parse module arguments.");
goto fail;
}
pa_log_info("Create new droid-card");
if (pa_modargs_get_value_boolean(ma, "default_profile", &default_profile) < 0) {
pa_log("Failed to parse default_profile argument. Expects boolean value");
if (!(ma = pa_droid_modargs_new(m->argument, valid_modargs))) {
pa_log("Failed to parse module arguments.");
goto fail;
}
@ -727,37 +808,15 @@ int pa__init(pa_module *m) {
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)
u->profile_set = pa_droid_profile_set_default_new(u->hw_module->enabled_module);
else
u->profile_set = pa_droid_profile_set_new(u->hw_module->enabled_module);
u->profile_set = pa_droid_profile_set_default_new(u->hw_module->enabled_module);
pa_card_new_data_init(&data);
data.driver = __FILE__;
@ -793,19 +852,18 @@ int pa__init(pa_module *m) {
AUDIO_MODE_IN_CALL, NULL,
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, 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, voicecall, data.profiles);
/* TODO: Probably enabled state needs to be determined dynamically for VOLTE and friends. */
add_virtual_profile(u, VOICE_SESSION_VOLTE_PROFILE_NAME, VOICE_SESSION_VOLTE_PROFILE_DESC,
AUDIO_MODE_IN_CALL, voicecall_volte_vsid_profile_event_cb,
PA_AVAILABLE_YES, voicecall, data.profiles);
@ -821,7 +879,7 @@ int pa__init(pa_module *m) {
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_USE_VSID */
#endif /* DROID_AUDIO_HAL_DEBUG_VSID */
add_disabled_profile(data.profiles);
@ -843,13 +901,18 @@ int pa__init(pa_module *m) {
pa_card_choose_initial_profile(u->card);
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;
pa_card_put(u->card);
return 0;
fail:
pa_droid_config_free(config);
if (ma)
pa_modargs_free(ma);
@ -871,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);

View file

@ -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

View file

@ -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);
}
}

View file

@ -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

View file

@ -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> "
@ -60,6 +58,7 @@ static const char* const valid_modargs[] = {
"sink_channel_map",
"sink_mix_route",
"flags",
"output",
"output_devices",
"sink_name",
"module_id",
@ -70,6 +69,7 @@ static const char* const valid_modargs[] = {
"deferred_volume",
"voice_property_key",
"voice_property_value",
"voice_virtual_stream",
NULL,
};

View file

@ -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

View file

@ -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> "
@ -85,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);