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
|
Softmixer controller for 4A (AGL Advance Audio Architecture).
------------------------------------------------------------
* Object: Simulate a hardware mixer through and snd-aloop driver and a user space mixer
* Status: In Progress
* Author: Fulup Ar Foll fulup@iot.bzh
* Author: Thierry Bultel thierry.bultel@iot.bzh
* Date : July-2018
## Features
* Definition of multiple audio zones, and multiple audio cards
* Usage of streams to access audio zones
* Direct read from HW capture devices (eg radio chips & microphones)
## Attach verb json format (TO UPDATE)
* The `uid` field will be the name of the mixer corresponding to your hal.
* The `mixerapi` field should contain the name of the api to call for reaching the mixer
(not need to be changed if you use '4a-softmixer').
* The `prefix` field is not mandatory, it is where you precise the prefix that will be applied
when the mixer attach call happens. All the streams the mixer creates will be prefixed with this field.
* In `ramps` section:
* Define the ramp that you can use in your mixer (ramps in example files can be used).
* The `uid` field is where you specify the name of the ramp.
* The ramp will set the current volume to the targeted volume step by step:
* The `delay` field is the delay between two volume modification.
* The `up` field is the volume increase in one step (when increasing volume is requested).
* The `down` field is the volume decrease in one step (when decreasing volume is requested).
* The `playbacks` section will contain your output audio information (such as the path to you alsa audio device
and the configuration of your device):
* A `uid` field that will be used by the mixer to identify the playback.
* The `params` field is an optional field where you can specify some parameters
for your playback (such as rate).
* The `sink` field is where you describe your playback:
* The `controls` field must contain the alsa control labels
that the mixer will use to set/mute volume on your audio device.
* The `channels` field must contain an object that will link an `uid` to
a physical output audio `port` that will be used in zone.
* The `captures` section will contain your input audio information (such as the path to you alsa audio device
and the configuration of your device):
* A `uid` field that will be used by the mixer to identify the capture.
* The `params` field is an optional field where you can specify some parameters
for your capture (such as rate).
* The `sink` field is where you describe your capture:
* The `controls` field must contain the alsa control labels
that the mixer will use to set/mute volume on your audio device.
* The `channels` field must contain an object that will link an `uid` to
a physical input audio `port` that will be used in zone.
* In `zones` section: (zones in example files can be used):
* You can define the zones that you want for your mixer.
* You must define which sink will be used in these zones.
* These zones will be used to define streams.
* The `sink` field must contain objects that will link a physical ouput audio port
(defined in `playbacks` section) using `target` field to a logical output audio `channel`
that will be used in zone.
* The `source` field must contain objects that will link a physical input audio port
(defined in `captures` section) using `target` field to a logical input audio `channel`
that will be used in zone.
* In `streams` section: (streams in example files can be used):
* You can define the streams that you want for your mixer.
* Mandatory fields:
* A `uid` field, it is the name used by the mixer to identify streams (e.g. when using `info` verb)
* The `verb` field is the name used by the mixer to declare the stream verb
(but prefixing it with `prefix` if defined).
It is also used by the hal to declare a verb to make it accessible from a hal point of view.
* The `zone` field must correspond to the wanted zone of the stream.
* Optional fields:
* The `source` is where you can precise which loop to use for this stream (not the default one).
The loop are defined in the mixer configuration file.
* The `params` is where you can specify some parameters for your stream (such as rate).
* `volume` and `mute` fields are initiate values of the stream.
NOTE : This json format is used by 4a-hal-generic.
## Compile
```
mkdir build
cd build
cmake ..
make
```
## Install Alsa Loopback Driver
```
sudo modprobe snd-aloop
```
## Assert LUA config file match your config
```
vim $PROJECT_ROOT/conf.d/project/lua.d/softmixer-01.lua
# make sure both your loopback and targeted sound card path are valid
```
## Run from shell
```
afb-daemon --name 4a-softmixer-afbd --port=1234 --workdir=/home/fulup/Workspace/Audio-4a/4a-softmixer/build \
--binding=package/lib/softmixer-binding.so --roothttp=package/htdocs --token= --tracereq=common --verbose
# lua test script should return a response looking like
response= {
[1] = { ["uid"] = navigation,["runid"] = 101,["alsa"] = hw:5,0,6,["volid"] = 103,}
, ["params"] = { ["channels"] = 2,["format"] = 2,["rate"] = 48000,["access"] = 3,}
,[2] = { ....
}
# runid: pause/resume alsa control you may change it with 'amixer -D hw:Loopback cset numid=101 on|off
# volid: volume alsa control you may change it from 'alsamixer -Dhw:Loppback' or with 'amixer -D hw:Loopback cset numid=103 NN (o-100%)
```
Retrieve audio-stream alsa endpoint from response to 'L2C:snd_streams' command. Depending on your config 'hw:XXX' will change.
Alsa snd-aloop impose '0' as playback device. Soft mixer will start from last subdevice and allocates one subdev for each audio-stream.
## Play some music
snd-aloop only supports these audio formats:
S16_LE
S16_BE
S32_LE
S32_BE
FLOAT_LE
FLOAT_BE
Using gstreamer is a simple way to perform the conversion, if your audio file is not of one of these.
```
gst-launch-1.0 filesrc location=insane.wav ! wavparse ! audioconvert ! audioresample ! alsasink device=hw:Loopback,0,2
```
## Warning
Alsa tries to automatically store current state into /var/lib/alsa/asound.state when developing/testing this may create impossible
situation. In order to clean up your Alsa snd-aloop config, a simple "rmmod" might not be enough in some case you may have to delete
/var/lib/alsa/asound.state before applying "modprobe".
In case of doubt check with folling command that you start from a clear green field
```
rmmod snd-aloop && modprobe --first-time snd-aloop && amixer -D hw:Loopback controls | grep vol
```
## Work in Progress
* Support capture from bluez
## Known issues
* From times to times, playing an audio file make the sound output with higher pitch
* The playback loop could be improved, using direct access to the ring buffer instead
of copies to stack (could save some CPU time)
|