Merge ~ssweeny/snappy-hwe-snaps/+git/alsa-utils:workaround-save-restore into ~snappy-hwe-team/snappy-hwe-snaps/+git/alsa-utils:master
- Git
- lp:~ssweeny/snappy-hwe-snaps/+git/alsa-utils
- workaround-save-restore
- Merge into master
Status: | Merged |
---|---|
Approved by: | Simon Fels |
Approved revision: | 6cf55a2ee065a80627adb47f837fd8eb22bb7b32 |
Merged at revision: | 53029e71760eed16791d5a3b159091050f78afcc |
Proposed branch: | ~ssweeny/snappy-hwe-snaps/+git/alsa-utils:workaround-save-restore |
Merge into: | ~snappy-hwe-team/snappy-hwe-snaps/+git/alsa-utils:master |
Diff against target: |
464 lines (+373/-4) 10 files modified
.tests_config (+1/-0) bin/alsa-stated (+26/-0) docs/index.md (+4/-2) docs/metadata.yaml (+2/-0) docs/reference/content-mixer-state.md (+57/-0) run-tests.sh (+7/-1) snapcraft.yaml (+17/-1) tests/integration/main/content-statefile/asound.state (+149/-0) tests/integration/main/content-statefile/task.yaml (+81/-0) tests/integration/main/save-restore/task.yaml (+29/-0) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Simon Fels | Approve | ||
System Enablement Bot | continuous-integration | Approve | |
Review via email: mp+318915@code.launchpad.net |
Commit message
Add mixer state save/restore
Adds a small daemon which does little but call alsactl store/restore upon startup and shutdown.
Also adds the ability to read an initial state file provided via the content interface.
Description of the change
Add mixer state save/restore
Adds a small daemon which does little but call alsactl store/restore upon startup and shutdown.
Also adds the ability to read an initial state file provided via the content interface.
System Enablement Bot (system-enablement-ci-bot) wrote : | # |
Simon Fels (morphis) : | # |
Scott Sweeny (ssweeny) : | # |
System Enablement Bot (system-enablement-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:8181650b441
https:/
Executed test runs:
FAILURE: https:/
None: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
System Enablement Bot (system-enablement-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:8181650b441
https:/
Executed test runs:
FAILURE: https:/
None: https:/
Click here to trigger a rebuild:
https:/
Simon Fels (morphis) : | # |
System Enablement Bot (system-enablement-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:8181650b441
https:/
Executed test runs:
None: https:/
Click here to trigger a rebuild:
https:/
System Enablement Bot (system-enablement-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:8181650b441
https:/
Executed test runs:
FAILURE: https:/
None: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
System Enablement Bot (system-enablement-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:ac1f2062b0b
https:/
Executed test runs:
SUCCESS: https:/
None: https:/
SUCCESS: https:/
Click here to trigger a rebuild:
https:/
System Enablement Bot (system-enablement-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:50530a84a6e
https:/
Executed test runs:
SUCCESS: https:/
None: https:/
SUCCESS: https:/
Click here to trigger a rebuild:
https:/
Simon Fels (morphis) wrote : | # |
Gernally LGTM, but a few comments inline.
System Enablement Bot (system-enablement-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:5a6118ab527
https:/
Executed test runs:
FAILURE: https:/
None: https:/
FAILURE: https:/
SUCCESS: https:/
Click here to trigger a rebuild:
https:/
System Enablement Bot (system-enablement-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:5a6118ab527
https:/
Executed test runs:
SUCCESS: https:/
None: https:/
SUCCESS: https:/
None: https:/
Click here to trigger a rebuild:
https:/
Simon Fels (morphis) : | # |
Simon Fels (morphis) wrote : | # |
A few last comments otherwise this looks ready to me. Lets try to get this in today and a new snap pushed to candidate.
System Enablement Bot (system-enablement-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:6cf55a2ee06
https:/
Executed test runs:
SUCCESS: https:/
None: https:/
SUCCESS: https:/
None: https:/
Click here to trigger a rebuild:
https:/
Preview Diff
1 | diff --git a/.tests_config b/.tests_config |
2 | new file mode 100644 |
3 | index 0000000..8d460d9 |
4 | --- /dev/null |
5 | +++ b/.tests_config |
6 | @@ -0,0 +1 @@ |
7 | +export EXTRA_ARGS="--image-unsigned-gadget" |
8 | diff --git a/bin/alsa-stated b/bin/alsa-stated |
9 | new file mode 100755 |
10 | index 0000000..4a55a7f |
11 | --- /dev/null |
12 | +++ b/bin/alsa-stated |
13 | @@ -0,0 +1,26 @@ |
14 | +#!/bin/bash |
15 | + |
16 | +LOCAL_STATEFILE=$SNAP_COMMON/asound.state |
17 | +GADGET_STATEFILE=$SNAP/var/lib/alsa/asound.state |
18 | + |
19 | +store() { |
20 | + echo "Caught SIGTERM, storing state..." |
21 | + $SNAP/usr/sbin/alsactl -f $LOCAL_STATEFILE store |
22 | +} |
23 | + |
24 | +# Store the state on SIGTERM |
25 | +trap store SIGTERM |
26 | + |
27 | +# On first run we won't have our own state file yet |
28 | +if [ -f $LOCAL_STATEFILE ]; then |
29 | + echo "Restoring from local state file" |
30 | + $SNAP/usr/sbin/alsactl -f $LOCAL_STATEFILE restore |
31 | + |
32 | +# If the gadget snap provided one use that on first run |
33 | +elif [ -f $GADGET_STATEFILE ]; then |
34 | + echo "Loading gadget state file" |
35 | + $SNAP/usr/sbin/alsactl -f $GADGET_STATEFILE restore |
36 | +fi |
37 | + |
38 | +# Wait to be SIGTERM'd |
39 | +sleep infinity |
40 | diff --git a/docs/index.md b/docs/index.md |
41 | index d267a7c..f059bb2 100644 |
42 | --- a/docs/index.md |
43 | +++ b/docs/index.md |
44 | @@ -5,8 +5,10 @@ table_of_contents: True |
45 | |
46 | # About alsa-utils |
47 | |
48 | -The alsa-utils snap provides a few very basic utilities to deal with the |
49 | -Linux kernel ALSA audio subsystem. |
50 | +The alsa-utils snap provides a few very basic utilities to deal with the Linux |
51 | +kernel ALSA audio subsystem. It also supports automatic saving and restoring of |
52 | +the mixer state, as well as importing a mixer state file via the content |
53 | +interface. |
54 | |
55 | ## Upstream documentation |
56 | |
57 | diff --git a/docs/metadata.yaml b/docs/metadata.yaml |
58 | index 05475a0..bd330f4 100644 |
59 | --- a/docs/metadata.yaml |
60 | +++ b/docs/metadata.yaml |
61 | @@ -7,3 +7,5 @@ navigation: |
62 | children: |
63 | - title: Available tools |
64 | location: reference/available-utilities.md |
65 | + - title: Device-specific initial ALSA state configuration |
66 | + location: reference/content-mixer-state.md |
67 | diff --git a/docs/reference/content-mixer-state.md b/docs/reference/content-mixer-state.md |
68 | new file mode 100644 |
69 | index 0000000..baaac89 |
70 | --- /dev/null |
71 | +++ b/docs/reference/content-mixer-state.md |
72 | @@ -0,0 +1,57 @@ |
73 | +--- |
74 | +title: "Device-specific initial ALSA state configuration" |
75 | +table_of_contents: True |
76 | +--- |
77 | + |
78 | +# Device-specific initial ALSA state configuration |
79 | + |
80 | +The alsa-utils snap supports importing a mixer state file from the device |
81 | +gadget snap. It defines a [content |
82 | +interface](https://snapcraft.io/docs/reference/interfaces) plug which will be |
83 | +connected to a slot on the gadget snap which then allows both snaps to share |
84 | +the initial ALSA state configuration. |
85 | + |
86 | +Here's a simple example of how to modify the gadget snap's `snapcraft.yaml` to |
87 | +provide the necessary content interface slot: |
88 | + |
89 | +``` |
90 | +# This part adds the state file to the snap in the path expected by the |
91 | +# content stanza below |
92 | +parts: |
93 | + alsa-state: |
94 | + plugin: dump |
95 | + source: alsa |
96 | + organize: |
97 | + asound.state: alsa-conf/asound.state |
98 | + |
99 | +slots: |
100 | + alsa: |
101 | + content: alsa-conf |
102 | + interface: content |
103 | + read: |
104 | + - alsa-conf |
105 | +``` |
106 | + |
107 | +*NOTE:* The alsa-utils snap expects the content field to specify `alsa-conf`. |
108 | + |
109 | +After installing the alsa-utils snap you will need to manually connect the |
110 | +content interface and restart the alsa-utils service, like so: |
111 | + |
112 | +``` |
113 | +$ snap disable alsa-utils |
114 | +$ rm -f /var/snap/alsa-utils/common/asound.state |
115 | +$ snap connect alsa-utils:device-conf <your-snap>:alsa |
116 | +$ snap enable alsa-utils |
117 | +``` |
118 | + |
119 | +*NOTE:* Because of a [bug in snapd](https://bugs.launchpad.net/bugs/1645731) |
120 | +you currently need to take some additional manual steps to ensure that the file |
121 | +is properly imported. The full set of steps is as follows: |
122 | + |
123 | +``` |
124 | +$ snap disable alsa-utils |
125 | +$ rm -f /var/snap/alsa-utils/common/asound.state |
126 | +$ snap connect alsa-utils:device-conf <your-snap>:alsa |
127 | +$ /usr/lib/snapd/snap-discard-ns alsa-utils |
128 | +$ snap enable alsa-utils |
129 | +``` |
130 | diff --git a/run-tests.sh b/run-tests.sh |
131 | index fdba1d8..f030283 100755 |
132 | --- a/run-tests.sh |
133 | +++ b/run-tests.sh |
134 | @@ -75,5 +75,11 @@ else |
135 | clone_tests_extras |
136 | fi |
137 | |
138 | +# Any project-specific options for test-runner should be specified in |
139 | +# .tests_config |
140 | +if [ -e ".tests_config" ]; then |
141 | + . .tests_config |
142 | +fi |
143 | + |
144 | echo "INFO: Executing tests runner" |
145 | -cd $TESTS_EXTRAS_PATH && ./tests-runner.sh $@ |
146 | +cd $TESTS_EXTRAS_PATH && ./tests-runner.sh "$@" "$EXTRA_ARGS" |
147 | diff --git a/snapcraft.yaml b/snapcraft.yaml |
148 | index d7c0091..7b5efbf 100644 |
149 | --- a/snapcraft.yaml |
150 | +++ b/snapcraft.yaml |
151 | @@ -10,6 +10,10 @@ confinement: strict |
152 | grade: stable |
153 | |
154 | apps: |
155 | + alsa-restore: |
156 | + daemon: simple |
157 | + command: bin/alsa-stated |
158 | + plugs: [alsa, gadget] |
159 | speaker-test: |
160 | command: usr/bin/speaker-test |
161 | plugs: [ alsa, home ] |
162 | @@ -96,6 +100,12 @@ apps: |
163 | aliases: |
164 | - arecord |
165 | |
166 | +plugs: |
167 | + device-conf: |
168 | + interface: content |
169 | + content: alsa-conf |
170 | + target: var/lib/alsa |
171 | + |
172 | parts: |
173 | alsa-lib: |
174 | plugin: autotools |
175 | @@ -139,5 +149,11 @@ parts: |
176 | - libncursesw5 |
177 | - libsamplerate0 |
178 | - libtinfo5 |
179 | - snap: |
180 | + prime: |
181 | - -usr/include |
182 | + |
183 | + alsa-stated: |
184 | + plugin: dump |
185 | + source: bin |
186 | + organize: |
187 | + alsa-stated: bin/ |
188 | diff --git a/tests/integration/main/content-statefile/asound.state b/tests/integration/main/content-statefile/asound.state |
189 | new file mode 100644 |
190 | index 0000000..dc1f935 |
191 | --- /dev/null |
192 | +++ b/tests/integration/main/content-statefile/asound.state |
193 | @@ -0,0 +1,149 @@ |
194 | +state.Dummy { |
195 | + control.1 { |
196 | + iface MIXER |
197 | + name 'Master Volume' |
198 | + value.0 34 |
199 | + value.1 34 |
200 | + comment { |
201 | + access 'read write' |
202 | + type INTEGER |
203 | + count 2 |
204 | + range '-50 - 100' |
205 | + dbmin -4500 |
206 | + dbmax 0 |
207 | + dbvalue.0 -1980 |
208 | + dbvalue.1 -1980 |
209 | + } |
210 | + } |
211 | + control.2 { |
212 | + iface MIXER |
213 | + name 'Master Capture Switch' |
214 | + value.0 false |
215 | + value.1 false |
216 | + comment { |
217 | + access 'read write' |
218 | + type BOOLEAN |
219 | + count 2 |
220 | + } |
221 | + } |
222 | + control.3 { |
223 | + iface MIXER |
224 | + name 'Synth Volume' |
225 | + value.0 0 |
226 | + value.1 0 |
227 | + comment { |
228 | + access 'read write' |
229 | + type INTEGER |
230 | + count 2 |
231 | + range '-50 - 100' |
232 | + dbmin -4500 |
233 | + dbmax 0 |
234 | + dbvalue.0 -3000 |
235 | + dbvalue.1 -3000 |
236 | + } |
237 | + } |
238 | + control.4 { |
239 | + iface MIXER |
240 | + name 'Synth Capture Switch' |
241 | + value.0 false |
242 | + value.1 false |
243 | + comment { |
244 | + access 'read write' |
245 | + type BOOLEAN |
246 | + count 2 |
247 | + } |
248 | + } |
249 | + control.5 { |
250 | + iface MIXER |
251 | + name 'Line Volume' |
252 | + value.0 0 |
253 | + value.1 0 |
254 | + comment { |
255 | + access 'read write' |
256 | + type INTEGER |
257 | + count 2 |
258 | + range '-50 - 100' |
259 | + dbmin -4500 |
260 | + dbmax 0 |
261 | + dbvalue.0 -3000 |
262 | + dbvalue.1 -3000 |
263 | + } |
264 | + } |
265 | + control.6 { |
266 | + iface MIXER |
267 | + name 'Line Capture Switch' |
268 | + value.0 false |
269 | + value.1 false |
270 | + comment { |
271 | + access 'read write' |
272 | + type BOOLEAN |
273 | + count 2 |
274 | + } |
275 | + } |
276 | + control.7 { |
277 | + iface MIXER |
278 | + name 'Mic Volume' |
279 | + value.0 72 |
280 | + value.1 72 |
281 | + comment { |
282 | + access 'read write' |
283 | + type INTEGER |
284 | + count 2 |
285 | + range '-50 - 100' |
286 | + dbmin -4500 |
287 | + dbmax 0 |
288 | + dbvalue.0 -840 |
289 | + dbvalue.1 -840 |
290 | + } |
291 | + } |
292 | + control.8 { |
293 | + iface MIXER |
294 | + name 'Mic Capture Switch' |
295 | + value.0 false |
296 | + value.1 false |
297 | + comment { |
298 | + access 'read write' |
299 | + type BOOLEAN |
300 | + count 2 |
301 | + } |
302 | + } |
303 | + control.9 { |
304 | + iface MIXER |
305 | + name 'CD Volume' |
306 | + value.0 -6 |
307 | + value.1 -6 |
308 | + comment { |
309 | + access 'read write' |
310 | + type INTEGER |
311 | + count 2 |
312 | + range '-50 - 100' |
313 | + dbmin -4500 |
314 | + dbmax 0 |
315 | + dbvalue.0 -3180 |
316 | + dbvalue.1 -3180 |
317 | + } |
318 | + } |
319 | + control.10 { |
320 | + iface MIXER |
321 | + name 'CD Capture Switch' |
322 | + value.0 false |
323 | + value.1 false |
324 | + comment { |
325 | + access 'read write' |
326 | + type BOOLEAN |
327 | + count 2 |
328 | + } |
329 | + } |
330 | + control.11 { |
331 | + iface MIXER |
332 | + name 'External I/O Box' |
333 | + value 'CD Player' |
334 | + comment { |
335 | + access 'read write' |
336 | + type ENUMERATED |
337 | + count 1 |
338 | + item.0 None |
339 | + item.1 'CD Player' |
340 | + } |
341 | + } |
342 | +} |
343 | diff --git a/tests/integration/main/content-statefile/task.yaml b/tests/integration/main/content-statefile/task.yaml |
344 | new file mode 100644 |
345 | index 0000000..2782c35 |
346 | --- /dev/null |
347 | +++ b/tests/integration/main/content-statefile/task.yaml |
348 | @@ -0,0 +1,81 @@ |
349 | +summary: Verify that initial state file can be pulled over the content interface |
350 | + |
351 | +prepare: | |
352 | + . $TESTSLIB/snap-names.sh |
353 | + snap list | grep $gadget_name | awk '{print $2}' > gadget_version |
354 | + |
355 | +restore: | |
356 | + . $TESTSLIB/snap-names.sh |
357 | + # Restore the original gadget snap so that any following tests don't suffer |
358 | + # from our modified gadget |
359 | + original_revision=`cat gadget_version` |
360 | + current_revision=`snap list | grep $gadget_name | awk '{print $2}'` |
361 | + if [ $current_revision -ne $original_revision ]; then |
362 | + snap revert --revision=$original_revision $gadget_name |
363 | + fi |
364 | + |
365 | +execute: | |
366 | + . $TESTSLIB/snap-names.sh |
367 | + . $TESTSLIB/utilities.sh |
368 | + |
369 | + # Load a dummy sound card so alsa is happy |
370 | + modprobe snd-dummy |
371 | + modprobe snd-pcm-oss |
372 | + modprobe snd-mixer-oss |
373 | + |
374 | + if [ $SPREAD_REBOOT = 0 ]; then |
375 | + snap install --edge --devmode se-test-tools |
376 | + |
377 | + # We need a custom gadget snap for this so let's fetch one from the store |
378 | + # and modify it |
379 | + snap download --stable $gadget_name |
380 | + /snap/bin/se-test-tools.unsquashfs -d gadget ${gadget_name}_*.snap |
381 | + cat << EOF >> gadget/meta/snap.yaml |
382 | + slots: |
383 | + alsa: |
384 | + content: alsa-conf |
385 | + interface: content |
386 | + read: |
387 | + - alsa-conf |
388 | + EOF |
389 | + mkdir gadget/alsa-conf |
390 | + cp asound.state gadget/alsa-conf/ |
391 | + /snap/bin/se-test-tools.mksquashfs gadget $gadget_name.snap -comp xz -no-xattrs |
392 | + snap install --dangerous $gadget_name.snap |
393 | + |
394 | + systemctl stop snap.alsa-utils.alsa-restore |
395 | + rm -f /var/snap/alsa-utils/common/asound.state # Simulate starting from scratch |
396 | + # The content interface will be hooked up automatically on a real system, |
397 | + # but we lack the assertions here so we need to fake it |
398 | + snap connect alsa-utils:device-conf pc:alsa |
399 | + /usr/lib/snapd/snap-discard-ns alsa-utils # Work around LP: #1645731 |
400 | + systemctl start snap.alsa-utils.alsa-restore |
401 | + wait_for_systemd_service snap.alsa-utils.alsa-restore |
402 | + |
403 | + # Make sure we found the right file |
404 | + journalctl -u snap.alsa-utils.alsa-restore | grep "Loading gadget state file" |
405 | + |
406 | + # Make sure there were no errors |
407 | + systemctl show snap.alsa-utils.alsa-restore | grep ActiveState=active |
408 | + systemctl show snap.alsa-utils.alsa-restore | grep SubState=running |
409 | + |
410 | + # Make sure the mixer values represent what's in the state file |
411 | + /snap/bin/amixer -c 0 get Master | grep "Front Left: 34 \[56%\] \[-19.80dB\] Capture \[off\]" |
412 | + /snap/bin/amixer -c 0 get Master | grep "Front Right: 34 \[56%\] \[-19.80dB\] Capture \[off\]" |
413 | + |
414 | + # Make sure changes are saved over a reboot |
415 | + /snap/bin/amixer -c 0 set Master 50,50 |
416 | + REBOOT |
417 | + fi |
418 | + |
419 | + # Make sure alsa starts up with the dummy drivers present |
420 | + systemctl restart snap.alsa-utils.alsa-restore |
421 | + wait_for_systemd_service snap.alsa-utils.alsa-restore |
422 | + |
423 | + # Make sure there were no errors |
424 | + systemctl show snap.alsa-utils.alsa-restore | grep ActiveState=active |
425 | + systemctl show snap.alsa-utils.alsa-restore | grep SubState=running |
426 | + |
427 | + /snap/bin/amixer -c 0 get Master | grep "Front Left: 50 \[67%\] \[-15.00dB\] Capture \[off\]" |
428 | + /snap/bin/amixer -c 0 get Master | grep "Front Right: 50 \[67%\] \[-15.00dB\] Capture \[off\]" |
429 | + |
430 | diff --git a/tests/integration/main/save-restore/task.yaml b/tests/integration/main/save-restore/task.yaml |
431 | new file mode 100644 |
432 | index 0000000..c34252f |
433 | --- /dev/null |
434 | +++ b/tests/integration/main/save-restore/task.yaml |
435 | @@ -0,0 +1,29 @@ |
436 | +summary: Verify that mixer state is saved and restored on shutdown/startup |
437 | + |
438 | +execute: | |
439 | + . $TESTSLIB/utilities.sh |
440 | + |
441 | + # Load a dummy sound card so alsa is happy |
442 | + modprobe snd-dummy |
443 | + modprobe snd-pcm-oss |
444 | + modprobe snd-mixer-oss |
445 | + |
446 | + # Make sure alsa sees the dummy sound card |
447 | + systemctl restart snap.alsa-utils.alsa-restore |
448 | + |
449 | + wait_for_systemd_service snap.alsa-utils.alsa-restore |
450 | + |
451 | + systemctl stop snap.alsa-utils.alsa-restore |
452 | + |
453 | + wait_for_systemd_service_exit snap.alsa-utils.alsa-restore |
454 | + |
455 | + # Make sure we saved a state file |
456 | + test -f /var/snap/alsa-utils/common/asound.state |
457 | + |
458 | + systemctl start snap.alsa-utils.alsa-restore |
459 | + |
460 | + wait_for_systemd_service snap.alsa-utils.alsa-restore |
461 | + |
462 | + # Make sure there were no errors |
463 | + systemctl show snap.alsa-utils.alsa-restore | grep ActiveState=active |
464 | + systemctl show snap.alsa-utils.alsa-restore | grep SubState=running |
PASSED: Continuous integration, rev:d287182115e d80b437767941b9 4accf77e379102 /jenkins. canonical. com/system- enablement/ job/generic- build-snap/ 1156/ /jenkins. canonical. com/system- enablement/ job/generic- build-snap- worker/ 184 /jenkins. canonical. com/system- enablement/ job/generic- update- snap-mp/ 1064/console /jenkins. canonical. com/system- enablement/ job/generic- test-snap/ 869
https:/
Executed test runs:
SUCCESS: https:/
None: https:/
SUCCESS: https:/
Click here to trigger a rebuild: /jenkins. canonical. com/system- enablement/ job/generic- build-snap/ 1156/rebuild
https:/