-
Notifications
You must be signed in to change notification settings - Fork 7
/
example_test.go
228 lines (184 loc) · 6.37 KB
/
example_test.go
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
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
package pulseaudio_test
import (
"github.com/godbus/dbus"
"github.com/sqp/pulseaudio"
"fmt"
"log"
"strconv"
"time"
)
//
//--------------------------------------------------------------------[ MAIN ]--
// Create a pulse dbus service with 2 clients, listen to events,
// then use some properties.
//
func Example() {
// Load pulseaudio DBus module if needed. This module is mandatory, but it
// can also be configured in system files. See package doc.
isLoaded, e := pulseaudio.ModuleIsLoaded()
testFatal(e, "test pulse dbus module is loaded")
if !isLoaded {
e = pulseaudio.LoadModule()
testFatal(e, "load pulse dbus module")
defer pulseaudio.UnloadModule() // has error to test
}
// Connect to the pulseaudio dbus service.
pulse, e := pulseaudio.New()
testFatal(e, "connect to the pulse service")
defer pulse.Close() // has error to test
// Create and register a first client.
app := &AppPulse{}
pulse.Register(app)
defer pulse.Unregister(app) // has errors to test
// Create and register a second client (optional).
two := &ClientTwo{pulse}
pulse.Register(two)
defer pulse.Unregister(two) // has errors to test
// Listen to registered events.
go pulse.Listen()
defer pulse.StopListening()
// Use some properties.
GetProps(pulse)
SetProps(pulse)
// Output:
// two: device mute updated /org/pulseaudio/core1/sink0 true
// sink muted
// two: device mute updated /org/pulseaudio/core1/sink0 false
// sink restored
}
//
//--------------------------------------------------------------[ CLIENT ONE ]--
// AppPulse is a client that connects 6 callbacks.
//
type AppPulse struct{}
// NewSink is called when a sink is added.
//
func (ap *AppPulse) NewSink(path dbus.ObjectPath) {
log.Println("one: new sink", path)
}
// SinkRemoved is called when a sink is removed.
//
func (ap *AppPulse) SinkRemoved(path dbus.ObjectPath) {
log.Println("one: sink removed", path)
}
// NewPlaybackStream is called when a playback stream is added.
//
func (ap *AppPulse) NewPlaybackStream(path dbus.ObjectPath) {
log.Println("one: new playback stream", path)
}
// PlaybackStreamRemoved is called when a playback stream is removed.
//
func (ap *AppPulse) PlaybackStreamRemoved(path dbus.ObjectPath) {
log.Println("one: playback stream removed", path)
}
// DeviceVolumeUpdated is called when the volume has changed on a device.
//
func (ap *AppPulse) DeviceVolumeUpdated(path dbus.ObjectPath, values []uint32) {
log.Println("one: device volume updated", path, values)
}
// DeviceActiveCardUpdated is called when active card has changed on a device.
// i.e. headphones injected.
func (ap *AppPulse) DeviceActiveCardUpdated(path dbus.ObjectPath, port dbus.ObjectPath) {
log.Println("one: device active card updated", path, port)
}
// StreamVolumeUpdated is called when the volume has changed on a stream.
//
func (ap *AppPulse) StreamVolumeUpdated(path dbus.ObjectPath, values []uint32) {
log.Println("one: stream volume", path, values)
}
//
//--------------------------------------------------------------[ CLIENT TWO ]--
// ClientTwo is a client that also connects some callbacks (3).
//
type ClientTwo struct {
*pulseaudio.Client
}
// DeviceVolumeUpdated is called when the volume has changed on a device.
//
func (two *ClientTwo) DeviceVolumeUpdated(path dbus.ObjectPath, values []uint32) {
log.Println("two: device volume updated", path, values)
}
// DeviceMuteUpdated is called when the output has been (un)muted.
//
func (two *ClientTwo) DeviceMuteUpdated(path dbus.ObjectPath, state bool) {
fmt.Println("two: device mute updated", path, state)
}
// DeviceActivePortUpdated is called when the port has changed on a device.
// Like a cable connected.
//
func (two *ClientTwo) DeviceActivePortUpdated(path, path2 dbus.ObjectPath) {
log.Println("two: device port updated", path, path2)
}
//
//----------------------------------------------[ GET OBJECTS AND PROPERTIES ]--
// GetProps is an example to show how to get properties.
func GetProps(client *pulseaudio.Client) {
// Get the list of streams from the Core and show some informations about them.
// You better handle errors that were not checked here for code clarity.
// Get the list of playback streams from the core.
streams, _ := client.Core().ListPath("PlaybackStreams") // []ObjectPath
for _, stream := range streams {
// Get the device to query properties for the stream referenced by his path.
dev := client.Stream(stream)
// Get some informations about this stream.
mute, _ := dev.Bool("Mute") // bool
vols, _ := dev.ListUint32("Volume") // []uint32
latency, _ := dev.Uint64("Latency") // uint64
sampleRate, _ := dev.Uint32("SampleRate") // uint32
log.Println("stream", volumeText(mute, vols), "latency", latency, "sampleRate", sampleRate)
props, e := dev.MapString("PropertyList") // map[string]string
testFatal(e, "get device PropertyList")
log.Println(props)
// Get the client associated with the stream.
devcltpath, _ := dev.ObjectPath("Client") // ObjectPath
devclt := client.Client(devcltpath)
devcltdrv, _ := devclt.String("Driver") // string
log.Println("device client driver", devcltdrv)
}
}
// SetProps is an example to show how to set properties.
// Toggles twice the mute state of the first sink device.
func SetProps(client *pulseaudio.Client) {
sinks, e := client.Core().ListPath("Sinks")
testFatal(e, "get list of sinks")
if len(sinks) == 0 {
fmt.Println("no sinks to test")
return
}
dev := client.Device(sinks[0]) // Only use the first sink for the test.
var muted bool
e = dev.Get("Mute", &muted) // Get is a generic method to get properties.
testFatal(e, "get sink muted state")
e = dev.Set("Mute", !muted)
testFatal(e, "set sink muted state")
<-time.After(time.Millisecond * 100)
fmt.Println("sink muted")
e = dev.Set("Mute", muted) // For properties tagged RW in the doc.
testFatal(e, "set sink muted state")
<-time.After(time.Millisecond * 100)
fmt.Println("sink restored")
}
//
//------------------------------------------------------------------[ COMMON ]--
func volumeText(mute bool, vals []uint32) string {
if mute {
return "muted"
}
vol := int(volumeAverage(vals)) * 100 / 65535
return " " + strconv.Itoa(vol) + "% "
}
func volumeAverage(vals []uint32) uint32 {
var vol uint32
if len(vals) > 0 {
for _, cur := range vals {
vol += cur
}
vol /= uint32(len(vals))
}
return vol
}
func testFatal(e error, msg string) {
if e != nil {
log.Fatalln(msg+":", e)
}
}