summaryrefslogtreecommitdiffstats
path: root/README.md
blob: 629b95b9bc2d8ff70826f80a3b2b9920d42bc194 (plain)
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
# Pulseaudio 4A (AGL Advanced Audio Agent) Client Module

This module allows pulseaudio to work as a client of the AGL Advanced Audio Agent.

## Dependencies

#### libafbwsc
This library is used to communicate with AFB (Application Framework Binder),
the interface that is being used by 4A.

#### libsystemd
This is needed for the systemd event loop implementation which is a hard
requirement of libafbwsc.

#### json-c
This is needed for json message parsing, also a hard requirement of libafbwsc.

## Building

This is meant to be built as part of the AGL distribution, using its bitbake
recipe. It depends on an AGL-specific patch on pulseaudio that installs the
module development headers on the system. On other distributions the source
files of this repository should be copied into the pulseaudio source tree
and pulseaudio's build system should be adjusted accordingly.

On AGL, pulseaudio is enabled by the 'agl-pulseaudio' feature, which is also
included by default in the 'agl-demo' feature. If you wish to disable it
explicitly on the demo, you can use the 'agl-demo-nopulseaudio' feature instead.

## Operation

* module-4a-client initially calls ahl-4a/get_roles to retrieve the available
roles in 4a
* When a new sink-input appears, it uses its media.role property and the
available roles to figure out which role it should use
* if the role turns out to be empty, it uses the default_role parameter to
assign a role to it
* it calls ahl-4a/<role> {"action": "open"} to open the device and get an ALSA
device uri
* it loads module-alsa-sink with the device uri set to whatever ahl-4a returned
* if all goes well, it moves the new sink-input to this new alsa sink
* otherwise it takes no action and expects pulseaudio configuration to be set
up in such a way so that the sink-input is muted
* when the sink-input disappears, it unloads the relevant module-alsa-sink
instance and calls ahl-4a/<role> {"action": "close"} to close the device in 4A

## Configuration

module-4a-client is recommended to be loaded from pulseaudio's default.pa config
file and it should be loaded in combination with a null sink:

```
load-module module-null-sink sink_name=aaaa_null_sink sink_properties="device.description='4A Null Output'"
set-default-sink aaaa_null_sink
load-module module-4a-client
```

This is because it expects that all new clients will automatically connect
to a sink that is not one of the sinks that it loads internally.

Additionally, for correct operation, it should **not** be loaded together
with one of the following:

* module-alsa-card
* module-udev-detect
* module-detect
* module-default-device-restore
* module-role-cork

... or anything else that might automatically load new sinks, move
clients on other sinks and alter stream volumes (volumes are meant to
be handled by 4A, pulseaudio should be dummy in this usage scenario)

### Parameters

The module accepts two parameters, both optional.

* 'uri' - The URI of the socket that will be used to talk to ahl-4a.
Defaults to 'unix:/run/user/0/apis/ws/ahl-4a'

* 'default_role' - The name of the role that will be used as a fallback for
clients that do not specify 'media.role'. Defaults to 'multimedia'

## Testing

### With PulseAudio started by systemd

On AGL, if PulseAudio is enabled on the image (enabled by default), it will be
started automatically by systemd. PulseAudio uses the socket activation feature
of systemd, so it will only be loaded on demand if a client tries to connect to
it.

If you want to trigger manual activation, you can do so using systemctl:
```
# systemctl --user start pulseaudio
```

Note: on the demo environment, some pulseaudio tools like 'pacmd' may
not trigger socket activation because they are running as root, which is
prohibited by pulseaudio. In order to use them, start pulseaudio manually first,
or start a client.

### Starting PulseAudio manually

Save this example configuration in a file called config.pa:
```
#!/usr/bin/pulseaudio -nF

.fail

load-module module-augment-properties
load-module module-native-protocol-unix

load-module module-null-sink sink_name=aaaa_null_sink sink_properties="device.description='4A Null Output'"
set-default-sink aaaa_null_sink
load-module module-4a-client

load-module module-rescue-streams
load-module module-always-sink
load-module module-suspend-on-idle
```

Start pulseaudio with the above example config:
```
# pulseaudio -nF config.pa
...
```

### Running a PulseAudio client

Here is a simple gstreamer-based client you can run for testing on a terminal:
```
# gst-launch-1.0 audiotestsrc ! pulsesink stream-properties="props,media.role=(string)emergency"
```

You can substitute "emergency" with any other available role, or just omit the
whole stream-properties=... part to get assigned the default role ("multimedia")

In your own application, in C, you can assign the role by setting this
property on the pulsesink GStreamer element like this:

```
GstElement *pulsesink = ...;
GstStructure *s = gst_structure_new ("props",
    "media.role", G_TYPE_STRING, "emergency", NULL);
g_object_set (pulsesink, "stream-properties", s, NULL);
gst_structure_unref (s);
```

## Missing functionality

The following functionality still needs to be implemented:

* Handle source-outputs in the same way as sink-inputs
* Cork sink-inputs that have been denied access to the device, so that the
client can act on it.
* Enforce security requirements - no other client should be allowed to
connect to the internally loaded alsa sinks
* Propagate the SMACK label of clients to 4A - this is supposed to allow 4A
to restrict which clients are allowed to output audio