Mercurial > mplayer.hg
annotate libao2/ao_pulse.c @ 35418:cedb0ba2b5c6
Move the code to set guiInfo's Track, Chapter and Angle start values.
Set them before checking whether there is any media opened, because
with no media opened we clear the counters.
author | ib |
---|---|
date | Thu, 29 Nov 2012 14:11:03 +0000 |
parents | aa10c22f69f4 |
children | 99708d402208 |
rev | line source |
---|---|
24782 | 1 /* |
2 * PulseAudio audio output driver. | |
3 * Copyright (C) 2006 Lennart Poettering | |
4 * Copyright (C) 2007 Reimar Doeffinger | |
5 * | |
6 * This file is part of MPlayer. | |
7 * | |
8 * MPlayer is free software; you can redistribute it and/or modify | |
9 * it under the terms of the GNU General Public License as published by | |
10 * the Free Software Foundation; either version 2 of the License, or | |
11 * (at your option) any later version. | |
12 * | |
13 * MPlayer is distributed in the hope that it will be useful, | |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 * GNU General Public License for more details. | |
17 * | |
26743
0f42fb42843c
Use standard license headers with standard formatting.
diego
parents:
26649
diff
changeset
|
18 * You should have received a copy of the GNU General Public License along |
0f42fb42843c
Use standard license headers with standard formatting.
diego
parents:
26649
diff
changeset
|
19 * with MPlayer; if not, write to the Free Software Foundation, Inc., |
0f42fb42843c
Use standard license headers with standard formatting.
diego
parents:
26649
diff
changeset
|
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
24782 | 21 */ |
26743
0f42fb42843c
Use standard license headers with standard formatting.
diego
parents:
26649
diff
changeset
|
22 |
24782 | 23 #include <string.h> |
24 | |
25 #include <pulse/pulseaudio.h> | |
26 | |
27 #include "config.h" | |
28 #include "libaf/af_format.h" | |
34564
96019b1174b8
Workaround a bug in Pulse Audio (http://pulseaudio.org/ticket/866)
iive
parents:
30020
diff
changeset
|
29 #include "osdep/timer.h" |
24782 | 30 #include "mp_msg.h" |
31 #include "audio_out.h" | |
32 #include "audio_out_internal.h" | |
34696
f2c90c9dd61c
Add suboption parsing support to ao_pulse and add an
reimar
parents:
34638
diff
changeset
|
33 #include "subopt-helper.h" |
24782 | 34 |
35 #define PULSE_CLIENT_NAME "MPlayer" | |
36 | |
37 /** General driver info */ | |
28823 | 38 static const ao_info_t info = { |
24782 | 39 "PulseAudio audio output", |
40 "pulse", | |
41 "Lennart Poettering", | |
42 "" | |
43 }; | |
44 | |
45 /** PulseAudio playback stream object */ | |
46 static struct pa_stream *stream; | |
47 | |
48 /** PulseAudio connection context */ | |
49 static struct pa_context *context; | |
50 | |
51 /** Main event loop object */ | |
52 static struct pa_threaded_mainloop *mainloop; | |
53 | |
28633
28fe0787a67c
Work around a PulseAudio bug that causes MPlayer to hang after unpausing.
reimar
parents:
26743
diff
changeset
|
54 static int broken_pause; |
28fe0787a67c
Work around a PulseAudio bug that causes MPlayer to hang after unpausing.
reimar
parents:
26743
diff
changeset
|
55 |
24782 | 56 LIBAO_EXTERN(pulse) |
57 | |
58 #define GENERIC_ERR_MSG(ctx, str) \ | |
59 mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] "str": %s\n", \ | |
60 pa_strerror(pa_context_errno(ctx))) | |
61 | |
62 static void context_state_cb(pa_context *c, void *userdata) { | |
63 switch (pa_context_get_state(c)) { | |
64 case PA_CONTEXT_READY: | |
65 case PA_CONTEXT_TERMINATED: | |
66 case PA_CONTEXT_FAILED: | |
67 pa_threaded_mainloop_signal(mainloop, 0); | |
68 break; | |
69 } | |
70 } | |
71 | |
72 static void stream_state_cb(pa_stream *s, void *userdata) { | |
73 switch (pa_stream_get_state(s)) { | |
74 case PA_STREAM_READY: | |
75 case PA_STREAM_FAILED: | |
76 case PA_STREAM_TERMINATED: | |
77 pa_threaded_mainloop_signal(mainloop, 0); | |
78 break; | |
79 } | |
80 } | |
81 | |
82 static void stream_request_cb(pa_stream *s, size_t length, void *userdata) { | |
83 pa_threaded_mainloop_signal(mainloop, 0); | |
84 } | |
85 | |
86 static void stream_latency_update_cb(pa_stream *s, void *userdata) { | |
87 pa_threaded_mainloop_signal(mainloop, 0); | |
88 } | |
89 | |
90 static void success_cb(pa_stream *s, int success, void *userdata) { | |
91 if (userdata) | |
92 *(int *)userdata = success; | |
93 pa_threaded_mainloop_signal(mainloop, 0); | |
94 } | |
95 | |
25383 | 96 /** |
97 * \brief waits for a pulseaudio operation to finish, frees it and | |
98 * unlocks the mainloop | |
99 * \param op operation to wait for | |
100 * \return 1 if operation has finished normally (DONE state), 0 otherwise | |
101 */ | |
24782 | 102 static int waitop(pa_operation *op) { |
103 pa_operation_state_t state; | |
29117
010781e92294
Make sure waitop always unlocks the mainloop even if the operation could not
reimar
parents:
28823
diff
changeset
|
104 if (!op) { |
010781e92294
Make sure waitop always unlocks the mainloop even if the operation could not
reimar
parents:
28823
diff
changeset
|
105 pa_threaded_mainloop_unlock(mainloop); |
010781e92294
Make sure waitop always unlocks the mainloop even if the operation could not
reimar
parents:
28823
diff
changeset
|
106 return 0; |
010781e92294
Make sure waitop always unlocks the mainloop even if the operation could not
reimar
parents:
28823
diff
changeset
|
107 } |
24782 | 108 state = pa_operation_get_state(op); |
109 while (state == PA_OPERATION_RUNNING) { | |
110 pa_threaded_mainloop_wait(mainloop); | |
111 state = pa_operation_get_state(op); | |
112 } | |
113 pa_operation_unref(op); | |
114 pa_threaded_mainloop_unlock(mainloop); | |
115 return state == PA_OPERATION_DONE; | |
116 } | |
117 | |
118 static const struct format_map_s { | |
119 int mp_format; | |
120 pa_sample_format_t pa_format; | |
121 } format_maps[] = { | |
122 {AF_FORMAT_S16_LE, PA_SAMPLE_S16LE}, | |
123 {AF_FORMAT_S16_BE, PA_SAMPLE_S16BE}, | |
26649 | 124 #ifdef PA_SAMPLE_S32NE |
26603 | 125 {AF_FORMAT_S32_LE, PA_SAMPLE_S32LE}, |
126 {AF_FORMAT_S32_BE, PA_SAMPLE_S32BE}, | |
26649 | 127 #endif |
128 #ifdef PA_SAMPLE_FLOAT32NE | |
24782 | 129 {AF_FORMAT_FLOAT_LE, PA_SAMPLE_FLOAT32LE}, |
130 {AF_FORMAT_FLOAT_BE, PA_SAMPLE_FLOAT32BE}, | |
26649 | 131 #endif |
26602
d48e2d7191df
Make ao_pulse fall back to s16le format instead of just failing.
reimar
parents:
25386
diff
changeset
|
132 {AF_FORMAT_U8, PA_SAMPLE_U8}, |
24782 | 133 {AF_FORMAT_MU_LAW, PA_SAMPLE_ULAW}, |
134 {AF_FORMAT_A_LAW, PA_SAMPLE_ALAW}, | |
135 {AF_FORMAT_UNKNOWN, 0} | |
136 }; | |
137 | |
34696
f2c90c9dd61c
Add suboption parsing support to ao_pulse and add an
reimar
parents:
34638
diff
changeset
|
138 static const opt_t subopts[] = { |
f2c90c9dd61c
Add suboption parsing support to ao_pulse and add an
reimar
parents:
34638
diff
changeset
|
139 {"broken_pause", OPT_ARG_BOOL, &broken_pause, NULL}, |
f2c90c9dd61c
Add suboption parsing support to ao_pulse and add an
reimar
parents:
34638
diff
changeset
|
140 {NULL} |
f2c90c9dd61c
Add suboption parsing support to ao_pulse and add an
reimar
parents:
34638
diff
changeset
|
141 }; |
f2c90c9dd61c
Add suboption parsing support to ao_pulse and add an
reimar
parents:
34638
diff
changeset
|
142 |
24782 | 143 static int init(int rate_hz, int channels, int format, int flags) { |
144 struct pa_sample_spec ss; | |
145 struct pa_channel_map map; | |
146 const struct format_map_s *fmt_map; | |
24921
148ca265fcb6
Change parsing to allow host == NULL and sink != NULL
reimar
parents:
24920
diff
changeset
|
147 char *devarg = NULL; |
24782 | 148 char *host = NULL; |
24919
51372a34bc7d
Make sink variable local, it is only used in one place
reimar
parents:
24782
diff
changeset
|
149 char *sink = NULL; |
30020 | 150 const char *version = pa_get_library_version(); |
24782 | 151 |
34696
f2c90c9dd61c
Add suboption parsing support to ao_pulse and add an
reimar
parents:
34638
diff
changeset
|
152 broken_pause = -1; |
24782 | 153 if (ao_subdevice) { |
34696
f2c90c9dd61c
Add suboption parsing support to ao_pulse and add an
reimar
parents:
34638
diff
changeset
|
154 char *opts; |
24921
148ca265fcb6
Change parsing to allow host == NULL and sink != NULL
reimar
parents:
24920
diff
changeset
|
155 devarg = strdup(ao_subdevice); |
148ca265fcb6
Change parsing to allow host == NULL and sink != NULL
reimar
parents:
24920
diff
changeset
|
156 sink = strchr(devarg, ':'); |
24920 | 157 if (sink) *sink++ = 0; |
24921
148ca265fcb6
Change parsing to allow host == NULL and sink != NULL
reimar
parents:
24920
diff
changeset
|
158 if (devarg[0]) host = devarg; |
35202
aa10c22f69f4
Fix crash when only specifying a host for -ao pulse.
reimar
parents:
34696
diff
changeset
|
159 opts = sink ? strchr(sink, ':') : NULL; |
34696
f2c90c9dd61c
Add suboption parsing support to ao_pulse and add an
reimar
parents:
34638
diff
changeset
|
160 if (opts) { |
f2c90c9dd61c
Add suboption parsing support to ao_pulse and add an
reimar
parents:
34638
diff
changeset
|
161 *opts++ = 0; |
f2c90c9dd61c
Add suboption parsing support to ao_pulse and add an
reimar
parents:
34638
diff
changeset
|
162 if (!sink[0]) sink = NULL; |
f2c90c9dd61c
Add suboption parsing support to ao_pulse and add an
reimar
parents:
34638
diff
changeset
|
163 if (subopt_parse(opts, subopts)) |
f2c90c9dd61c
Add suboption parsing support to ao_pulse and add an
reimar
parents:
34638
diff
changeset
|
164 goto fail; |
f2c90c9dd61c
Add suboption parsing support to ao_pulse and add an
reimar
parents:
34638
diff
changeset
|
165 } |
24782 | 166 } |
167 | |
29120
aa06c29db609
Disable pause-hack from PulseAudio 0.9.15 on, it should be fixed.
reimar
parents:
29119
diff
changeset
|
168 // not sure which versions are affected, assume 0.9.11* to 0.9.14* |
28633
28fe0787a67c
Work around a PulseAudio bug that causes MPlayer to hang after unpausing.
reimar
parents:
26743
diff
changeset
|
169 // known bad: 0.9.14, 0.9.13 |
29120
aa06c29db609
Disable pause-hack from PulseAudio 0.9.15 on, it should be fixed.
reimar
parents:
29119
diff
changeset
|
170 // known good: 0.9.9, 0.9.10, 0.9.15 |
28633
28fe0787a67c
Work around a PulseAudio bug that causes MPlayer to hang after unpausing.
reimar
parents:
26743
diff
changeset
|
171 // to test: pause, wait ca. 5 seconds framestep and see if MPlayer hangs somewhen |
34696
f2c90c9dd61c
Add suboption parsing support to ao_pulse and add an
reimar
parents:
34638
diff
changeset
|
172 if (broken_pause == -1) |
f2c90c9dd61c
Add suboption parsing support to ao_pulse and add an
reimar
parents:
34638
diff
changeset
|
173 broken_pause = strncmp(version, "0.9.1", 5) == 0 && version[5] >= '1' && version[5] <= '4'; |
f2c90c9dd61c
Add suboption parsing support to ao_pulse and add an
reimar
parents:
34638
diff
changeset
|
174 if (broken_pause) { |
28633
28fe0787a67c
Work around a PulseAudio bug that causes MPlayer to hang after unpausing.
reimar
parents:
26743
diff
changeset
|
175 mp_msg(MSGT_AO, MSGL_WARN, "[pulse] working around probably broken pause functionality,\n" |
28fe0787a67c
Work around a PulseAudio bug that causes MPlayer to hang after unpausing.
reimar
parents:
26743
diff
changeset
|
176 " see http://www.pulseaudio.org/ticket/440\n"); |
28fe0787a67c
Work around a PulseAudio bug that causes MPlayer to hang after unpausing.
reimar
parents:
26743
diff
changeset
|
177 } |
28fe0787a67c
Work around a PulseAudio bug that causes MPlayer to hang after unpausing.
reimar
parents:
26743
diff
changeset
|
178 |
24782 | 179 ss.channels = channels; |
180 ss.rate = rate_hz; | |
181 | |
182 ao_data.samplerate = rate_hz; | |
183 ao_data.channels = channels; | |
34638 | 184 ao_data.outburst = 8 * channels * (rate_hz / 64); |
24782 | 185 |
186 fmt_map = format_maps; | |
187 while (fmt_map->mp_format != format) { | |
188 if (fmt_map->mp_format == AF_FORMAT_UNKNOWN) { | |
26602
d48e2d7191df
Make ao_pulse fall back to s16le format instead of just failing.
reimar
parents:
25386
diff
changeset
|
189 mp_msg(MSGT_AO, MSGL_V, "AO: [pulse] Unsupported format, using default\n"); |
d48e2d7191df
Make ao_pulse fall back to s16le format instead of just failing.
reimar
parents:
25386
diff
changeset
|
190 fmt_map = format_maps; |
d48e2d7191df
Make ao_pulse fall back to s16le format instead of just failing.
reimar
parents:
25386
diff
changeset
|
191 break; |
24782 | 192 } |
193 fmt_map++; | |
194 } | |
26602
d48e2d7191df
Make ao_pulse fall back to s16le format instead of just failing.
reimar
parents:
25386
diff
changeset
|
195 ao_data.format = fmt_map->mp_format; |
24782 | 196 ss.format = fmt_map->pa_format; |
197 | |
198 if (!pa_sample_spec_valid(&ss)) { | |
199 mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Invalid sample spec\n"); | |
200 goto fail; | |
201 } | |
202 | |
203 pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA); | |
204 ao_data.bps = pa_bytes_per_second(&ss); | |
205 | |
206 if (!(mainloop = pa_threaded_mainloop_new())) { | |
207 mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to allocate main loop\n"); | |
208 goto fail; | |
209 } | |
210 | |
211 if (!(context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), PULSE_CLIENT_NAME))) { | |
212 mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to allocate context\n"); | |
213 goto fail; | |
214 } | |
215 | |
216 pa_context_set_state_callback(context, context_state_cb, NULL); | |
217 | |
218 if (pa_context_connect(context, host, 0, NULL) < 0) | |
219 goto fail; | |
220 | |
221 pa_threaded_mainloop_lock(mainloop); | |
222 | |
223 if (pa_threaded_mainloop_start(mainloop) < 0) | |
224 goto unlock_and_fail; | |
225 | |
226 /* Wait until the context is ready */ | |
227 pa_threaded_mainloop_wait(mainloop); | |
228 | |
229 if (pa_context_get_state(context) != PA_CONTEXT_READY) | |
230 goto unlock_and_fail; | |
231 | |
232 if (!(stream = pa_stream_new(context, "audio stream", &ss, &map))) | |
233 goto unlock_and_fail; | |
234 | |
235 pa_stream_set_state_callback(stream, stream_state_cb, NULL); | |
236 pa_stream_set_write_callback(stream, stream_request_cb, NULL); | |
237 pa_stream_set_latency_update_callback(stream, stream_latency_update_cb, NULL); | |
238 | |
30019
2d62e9614c8d
Allow pulseaudio to restore the previous volume on init instead of forcing to
reimar
parents:
30018
diff
changeset
|
239 if (pa_stream_connect_playback(stream, sink, NULL, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) < 0) |
24782 | 240 goto unlock_and_fail; |
241 | |
242 /* Wait until the stream is ready */ | |
243 pa_threaded_mainloop_wait(mainloop); | |
244 | |
245 if (pa_stream_get_state(stream) != PA_STREAM_READY) | |
246 goto unlock_and_fail; | |
247 | |
248 pa_threaded_mainloop_unlock(mainloop); | |
249 | |
24921
148ca265fcb6
Change parsing to allow host == NULL and sink != NULL
reimar
parents:
24920
diff
changeset
|
250 free(devarg); |
24782 | 251 return 1; |
252 | |
253 unlock_and_fail: | |
254 | |
255 if (mainloop) | |
256 pa_threaded_mainloop_unlock(mainloop); | |
257 | |
258 fail: | |
259 if (context) | |
260 GENERIC_ERR_MSG(context, "Init failed"); | |
24921
148ca265fcb6
Change parsing to allow host == NULL and sink != NULL
reimar
parents:
24920
diff
changeset
|
261 free(devarg); |
24782 | 262 uninit(1); |
263 return 0; | |
264 } | |
265 | |
266 /** Destroy libao driver */ | |
267 static void uninit(int immed) { | |
268 if (stream && !immed) { | |
34564
96019b1174b8
Workaround a bug in Pulse Audio (http://pulseaudio.org/ticket/866)
iive
parents:
30020
diff
changeset
|
269 /* Workaround the bug in pa_stream_drain that causes |
96019b1174b8
Workaround a bug in Pulse Audio (http://pulseaudio.org/ticket/866)
iive
parents:
30020
diff
changeset
|
270 a delay of 2 second if the buffer is not empty */ |
96019b1174b8
Workaround a bug in Pulse Audio (http://pulseaudio.org/ticket/866)
iive
parents:
30020
diff
changeset
|
271 usec_sleep(get_delay() * 1000 * 1000); |
96019b1174b8
Workaround a bug in Pulse Audio (http://pulseaudio.org/ticket/866)
iive
parents:
30020
diff
changeset
|
272 |
24782 | 273 pa_threaded_mainloop_lock(mainloop); |
274 waitop(pa_stream_drain(stream, success_cb, NULL)); | |
275 } | |
276 | |
277 if (mainloop) | |
278 pa_threaded_mainloop_stop(mainloop); | |
279 | |
280 if (stream) { | |
281 pa_stream_disconnect(stream); | |
282 pa_stream_unref(stream); | |
283 stream = NULL; | |
284 } | |
285 | |
286 if (context) { | |
287 pa_context_disconnect(context); | |
288 pa_context_unref(context); | |
289 context = NULL; | |
290 } | |
291 | |
292 if (mainloop) { | |
293 pa_threaded_mainloop_free(mainloop); | |
294 mainloop = NULL; | |
295 } | |
296 } | |
297 | |
298 /** Play the specified data to the pulseaudio server */ | |
299 static int play(void* data, int len, int flags) { | |
25386
bd46b759fd35
pa_stream_write reportedly needs locking of the main loop
reimar
parents:
25385
diff
changeset
|
300 pa_threaded_mainloop_lock(mainloop); |
25385 | 301 if (pa_stream_write(stream, data, len, NULL, 0, PA_SEEK_RELATIVE) < 0) { |
302 GENERIC_ERR_MSG(context, "pa_stream_write() failed"); | |
25386
bd46b759fd35
pa_stream_write reportedly needs locking of the main loop
reimar
parents:
25385
diff
changeset
|
303 len = -1; |
25385 | 304 } |
25386
bd46b759fd35
pa_stream_write reportedly needs locking of the main loop
reimar
parents:
25385
diff
changeset
|
305 pa_threaded_mainloop_unlock(mainloop); |
24782 | 306 return len; |
307 } | |
308 | |
309 static void cork(int b) { | |
310 int success = 0; | |
311 pa_threaded_mainloop_lock(mainloop); | |
312 if (!waitop(pa_stream_cork(stream, b, success_cb, &success)) || | |
313 !success) | |
314 GENERIC_ERR_MSG(context, "pa_stream_cork() failed"); | |
315 } | |
316 | |
317 /** Pause the audio stream by corking it on the server */ | |
318 static void audio_pause(void) { | |
319 cork(1); | |
320 } | |
321 | |
322 /** Resume the audio stream by uncorking it on the server */ | |
323 static void audio_resume(void) { | |
28633
28fe0787a67c
Work around a PulseAudio bug that causes MPlayer to hang after unpausing.
reimar
parents:
26743
diff
changeset
|
324 // without this, certain versions will cause an infinite hang because |
28fe0787a67c
Work around a PulseAudio bug that causes MPlayer to hang after unpausing.
reimar
parents:
26743
diff
changeset
|
325 // pa_stream_writable_size returns 0 always. |
28fe0787a67c
Work around a PulseAudio bug that causes MPlayer to hang after unpausing.
reimar
parents:
26743
diff
changeset
|
326 // Note that this workaround causes A-V desync after pause |
28fe0787a67c
Work around a PulseAudio bug that causes MPlayer to hang after unpausing.
reimar
parents:
26743
diff
changeset
|
327 if (broken_pause) reset(); |
24782 | 328 cork(0); |
329 } | |
330 | |
331 /** Reset the audio stream, i.e. flush the playback buffer on the server side */ | |
332 static void reset(void) { | |
333 int success = 0; | |
334 pa_threaded_mainloop_lock(mainloop); | |
335 if (!waitop(pa_stream_flush(stream, success_cb, &success)) || | |
336 !success) | |
337 GENERIC_ERR_MSG(context, "pa_stream_flush() failed"); | |
338 } | |
339 | |
340 /** Return number of bytes that may be written to the server without blocking */ | |
341 static int get_space(void) { | |
342 size_t l; | |
343 pa_threaded_mainloop_lock(mainloop); | |
344 l = pa_stream_writable_size(stream); | |
345 pa_threaded_mainloop_unlock(mainloop); | |
24923 | 346 return l; |
24782 | 347 } |
348 | |
349 /** Return the current latency in seconds */ | |
350 static float get_delay(void) { | |
351 pa_usec_t latency = (pa_usec_t) -1; | |
352 pa_threaded_mainloop_lock(mainloop); | |
353 while (pa_stream_get_latency(stream, &latency, NULL) < 0) { | |
354 if (pa_context_errno(context) != PA_ERR_NODATA) { | |
355 GENERIC_ERR_MSG(context, "pa_stream_get_latency() failed"); | |
356 break; | |
357 } | |
358 /* Wait until latency data is available again */ | |
359 pa_threaded_mainloop_wait(mainloop); | |
360 } | |
361 pa_threaded_mainloop_unlock(mainloop); | |
362 return latency == (pa_usec_t) -1 ? 0 : latency / 1000000.0; | |
363 } | |
364 | |
365 /** A callback function that is called when the | |
366 * pa_context_get_sink_input_info() operation completes. Saves the | |
367 * volume field of the specified structure to the global variable volume. */ | |
368 static void info_func(struct pa_context *c, const struct pa_sink_input_info *i, int is_last, void *userdata) { | |
30018
ae5d67d8ee95
Get rid of global volume variable, it is only used for temporary values.
reimar
parents:
29120
diff
changeset
|
369 struct pa_cvolume *volume = userdata; |
24782 | 370 if (is_last < 0) { |
371 GENERIC_ERR_MSG(context, "Failed to get sink input info"); | |
372 return; | |
373 } | |
374 if (!i) | |
375 return; | |
30018
ae5d67d8ee95
Get rid of global volume variable, it is only used for temporary values.
reimar
parents:
29120
diff
changeset
|
376 *volume = i->volume; |
24782 | 377 pa_threaded_mainloop_signal(mainloop, 0); |
378 } | |
379 | |
380 static int control(int cmd, void *arg) { | |
381 switch (cmd) { | |
382 case AOCONTROL_GET_VOLUME: { | |
383 ao_control_vol_t *vol = arg; | |
384 uint32_t devidx = pa_stream_get_index(stream); | |
30018
ae5d67d8ee95
Get rid of global volume variable, it is only used for temporary values.
reimar
parents:
29120
diff
changeset
|
385 struct pa_cvolume volume; |
24782 | 386 pa_threaded_mainloop_lock(mainloop); |
30018
ae5d67d8ee95
Get rid of global volume variable, it is only used for temporary values.
reimar
parents:
29120
diff
changeset
|
387 if (!waitop(pa_context_get_sink_input_info(context, devidx, info_func, &volume))) { |
24782 | 388 GENERIC_ERR_MSG(context, "pa_stream_get_sink_input_info() failed"); |
389 return CONTROL_ERROR; | |
390 } | |
391 | |
392 if (volume.channels != 2) | |
393 vol->left = vol->right = pa_cvolume_avg(&volume)*100/PA_VOLUME_NORM; | |
394 else { | |
395 vol->left = volume.values[0]*100/PA_VOLUME_NORM; | |
396 vol->right = volume.values[1]*100/PA_VOLUME_NORM; | |
397 } | |
398 | |
399 return CONTROL_OK; | |
400 } | |
401 | |
402 case AOCONTROL_SET_VOLUME: { | |
403 const ao_control_vol_t *vol = arg; | |
404 pa_operation *o; | |
30018
ae5d67d8ee95
Get rid of global volume variable, it is only used for temporary values.
reimar
parents:
29120
diff
changeset
|
405 struct pa_cvolume volume; |
24782 | 406 |
30018
ae5d67d8ee95
Get rid of global volume variable, it is only used for temporary values.
reimar
parents:
29120
diff
changeset
|
407 pa_cvolume_reset(&volume, ao_data.channels); |
24782 | 408 if (volume.channels != 2) |
409 pa_cvolume_set(&volume, volume.channels, (pa_volume_t)vol->left*PA_VOLUME_NORM/100); | |
410 else { | |
411 volume.values[0] = (pa_volume_t)vol->left*PA_VOLUME_NORM/100; | |
412 volume.values[1] = (pa_volume_t)vol->right*PA_VOLUME_NORM/100; | |
413 } | |
414 | |
29118
17c6a6c192a7
Also lock the mainloop when doing adjusting the volume for PulseAudio.
reimar
parents:
29117
diff
changeset
|
415 pa_threaded_mainloop_lock(mainloop); |
29119
52afd0fe451b
Split oversized of "argument" onto a separate line.
reimar
parents:
29118
diff
changeset
|
416 o = pa_context_set_sink_input_volume(context, pa_stream_get_index(stream), &volume, NULL, NULL); |
52afd0fe451b
Split oversized of "argument" onto a separate line.
reimar
parents:
29118
diff
changeset
|
417 if (!o) { |
29118
17c6a6c192a7
Also lock the mainloop when doing adjusting the volume for PulseAudio.
reimar
parents:
29117
diff
changeset
|
418 pa_threaded_mainloop_unlock(mainloop); |
24782 | 419 GENERIC_ERR_MSG(context, "pa_context_set_sink_input_volume() failed"); |
420 return CONTROL_ERROR; | |
421 } | |
422 /* We don't wait for completion here */ | |
423 pa_operation_unref(o); | |
29118
17c6a6c192a7
Also lock the mainloop when doing adjusting the volume for PulseAudio.
reimar
parents:
29117
diff
changeset
|
424 pa_threaded_mainloop_unlock(mainloop); |
24782 | 425 return CONTROL_OK; |
426 } | |
427 | |
428 default: | |
429 return CONTROL_UNKNOWN; | |
430 } | |
431 } |