1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
|
Alsa-Hook-Plugin
Object: Provide a Hook on Alsa PCM to check permission again AGL Advance Audio Agent
Status: Release Candidate
Author: Fulup Ar Foll fulup@iot.bzh
Date : August-2017
References: https://www.spinics.net/lists/alsa-devel/msg54235.html
## Functionalities:
- Execute a set of unix/ws RPC request again AGL binders to allow/deny access
- Keep websocket open in an idependant thread in order to monitor event received from AGL audio agent
## Installation
- Alsaplugins are typically search in /usr/share/alsa-lib. Nevertheless a full path might be given
- This plugin implement a hook on a slave PCM. Typically this slave PCM is a dedicated virtual channel (eg: navigation, emergency,...)
- Config should be place in ~/.asoundrc (see config sample in PROJECT_ROOT/conf.d/alsa)
## Test
- Install a full .asoundrc from conf.d/project/alsa.d
- Check SoundCard ==> speaker-test -Dhw:v1340 -c2 -twav
- Check MixerPCM ==> speaker-test -DSpeakers -c2 -twav
- Check SoftVol ==> speaker-test -DMusicPCM -c2 -twav
- Check Plugin ==> speaker-test -DMultimedia -c2 -twav
- Check MultiMedia aplay -DDMyNavPCM /usr/share/sounds/alsa/test.wav
## Pulse audio integration
By default Pulse only auto detect hardware sound card and virtual channel should be specified
1) update ~/.asoundrc file and check basic ALSA virtual channel works as expected
2) kill/restart pulseaudio server to force alsa hookplugin loading
3) declare alsa virtual channel as pulse sink
- pacmd load-module module-alsa-sink device=MusicPCM
- pacmd load-module module-alsa-sink device=NavPCM control=NavAlsaCtl
- pacmd list-sinks | grep -i music
4) check your virtual pulse sink work
- paplay -d alsa_output.MusicPCM /usr/share/sounds/alsa/test.wav
- paplay -d alsa_output.NavPCM /usr/share/sounds/alsa/Front_Center.wav
optional integration with ALSA legacy apps
5) start audio-pol4a controller
- repeat previous step(3) this time with device=Multimedia device=Navigation, ....
6) check virtual channel with policy controller protection
- paplay -d alsa_output.Multimedia /usr/share/sounds/alsa/test.wav
- paplay -d alsa_output.Navigation /usr/share/sounds/alsa/Front_Center.wav
Bug/Feature:
1) when softvol control is initialised from plugin and not
from AGL binding. At 1st run ctl has invalid TLV and cannot be used
Bypass Solution:
* start audio-binder before playing sound (binding create control before softvol plugin)
* run a dummy aplay -DMyNavPCM "" to get a clean control
2) When using Audio-Pol4a to protect virtual channel, the audio policy controller should
run before adding virtual channel into pulse.
3) In order to leverage SMACK to protect virtual audio role, a Pulse rooting plugin should be used.
## Alsa Config Sample
```
# ------------------------------------------------------
# Mixer PCM allow to play multiple stream simultaneously
# ------------------------------------------------------
pcm.Speakers {
type dmix
slave {pcm "hw:v1340"} #Jabra Solmate 1
ipc_key 1001 # ipc_key should be unique to each dmix
}
# -----------------------------------------------------
# Register ControllerHookPlugin (ToiBeFix fullpath)
# -----------------------------------------------------
pcm_hook_type.CtlHookPlugin {
install "AlsaInstallHook"
lib "/home/fulup/Workspace/Audio-4a/alsa-4a/build/alsa-hook/policy_alsa_hook.so"
}
# -------------------------------------------------------
# Define one Audio Virtual Channel per Audio Roles
# -------------------------------------------------------
pcm.MusicPCM {
type softvol
# Point Slave on HOOK for policies control
slave.pcm "Speakers"
# name should match with HAL definition
control.name "Playback Multimedia"
}
pcm.NaviPCM {
type softvol
# Point Slave on HOOK for policies control
slave.pcm "Speakers"
# name should match with HAL definition
control.name "Playback Navigation"
}
pcm.UrgentPCM {
type softvol
# Point Slave on HOOK for policies control
slave.pcm "Speakers"
# name should match with HAL definition
control.name "Playback Emergency"
}
# ----------------------------------------------------
# Define one hooked PCM channel per Audio Roles
# ----------------------------------------------------
pcm.Multimedia {
type hooks
slave {pcm "MusicPCM"}
hooks.0 {
comment "Defined used hook sharelib and provide arguments/config to install func"
type "CtlHookPlugin"
hook_args {
# print few log messages (default false)
verbose true
# uri to audio-4a policy engine
uri="unix:/var/tmp/ahl-4a"
# timeout in ms (default 500)
timeout 5000
# force API synchronous mode
synchronous true
# api subcall to request a role
request {
open_stream "{'role': 'entertainment'}"
set-stream "{'role': 'entertainment'}"
}
# api subcall to request a role
release {
close-stream "{'role': 'entertainment'}"
}
# map AGL event on Unix signal. Search in event for json key=value
events {
sig-02 {search state_event, value 1}
sig-31 {search state_event, value 2}
sig-32 {search state_event, value 3}
}
}
}
}
pcm.Navigation {
type hooks
slave {pcm "NaviPCM"}
hooks.0 {
comment "Defined used hook sharelib and provide arguments/config to install func"
type "CtlHookPlugin"
hook_args {
# print few log messages (default false)
verbose true
# uri to audio-4a policy engine
uri="unix:/var/tmp/pol4a"
# timeout in ms (default 500)
timeout 5000
# force API synchronous mode
synchronous true
# api subcall to request a role
request {
navigation-role "{'uid':'alsa-hook-client'}"
signal-timeout "{'timeout':5, 'navi':'quit'}"
}
# api subcall to request a role
release {
release-role "{'uid':'alsa-hook-client'}"
}
# map AGL event on Unix signal. Search in event for json key=value
events {
sig-02 {search navi, value quit}
sig-31 {search event, value start}
sig-32 {search event, value start}
}
}
}
}
```
NOTE:
* Hook plugin is loaded by Alsa libasound within client context. It inherits client process attributes, as UID/GID and
SMACK label when running on AGL. The smack label is control by AGL security framework.
As a result a control request succeeds only when client application permission match requested audio role inside Cynara security database.
* Hook plugin keep a connection with the Audio-Agent until PCM is closed by the application. This connection allow the
Audio-Agent to send events. eg: pause, quit, mute, ...
|