1
/* XMMS2 - X Music Multiplexer System
2
* Copyright (C) 2003-2007 XMMS2 Team
4
* PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public
8
* License as published by the Free Software Foundation; either
9
* version 2.1 of the License, or (at your option) any later version.
11
* This library is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* Lesser General Public License for more details.
17
#include "xmms/xmms_outputplugin.h"
18
#include "xmms/xmms_log.h"
24
#include <pulse/pulseaudio.h>
28
xmms_sample_format_t xmms_fmt;
29
pa_sample_format_t pulse_fmt;
30
} xmms_pulse_formats[] = {
31
{XMMS_SAMPLE_FORMAT_U8, PA_SAMPLE_U8},
32
#if G_BYTE_ORDER == G_LITTLE_ENDIAN /* Yes, there is PA_SAMPLE_xxNE,
33
but they does only work
34
if you can be sure that
35
WORDS_BIGENDIAN is correctly
37
{XMMS_SAMPLE_FORMAT_S16, PA_SAMPLE_S16LE},
38
{XMMS_SAMPLE_FORMAT_FLOAT, PA_SAMPLE_FLOAT32LE},
40
{XMMS_SAMPLE_FORMAT_S16, PA_SAMPLE_S16BE},
41
{XMMS_SAMPLE_FORMAT_FLOAT, PA_SAMPLE_FLOAT32BE},
46
pa_threaded_mainloop *mainloop;
49
pa_sample_spec sample_spec;
50
pa_channel_map channel_map;
52
int operation_success;
55
static gboolean check_pulse_health(xmms_pulse *p, int *rerror) {
56
if (!p->context || pa_context_get_state(p->context) != PA_CONTEXT_READY ||
57
!p->stream || pa_stream_get_state(p->stream) != PA_STREAM_READY) {
59
pa_context_get_state(p->context) == PA_CONTEXT_FAILED) ||
61
pa_stream_get_state(p->stream) == PA_STREAM_FAILED)) {
63
*(rerror) = pa_context_errno(p->context);
65
*(rerror) = PA_ERR_BADSTATE;
72
* Callbacks to handle updates from the Pulse daemon.
74
static void signal_mainloop(void *userdata) {
75
xmms_pulse *p = userdata;
78
pa_threaded_mainloop_signal(p->mainloop, 0);
81
static void context_state_cb(pa_context *c, void *userdata) {
84
switch (pa_context_get_state(c)) {
85
case PA_CONTEXT_READY:
86
case PA_CONTEXT_TERMINATED:
87
case PA_CONTEXT_FAILED:
88
signal_mainloop(userdata);
90
case PA_CONTEXT_UNCONNECTED:
91
case PA_CONTEXT_CONNECTING:
92
case PA_CONTEXT_AUTHORIZING:
93
case PA_CONTEXT_SETTING_NAME:
98
static void stream_state_cb(pa_stream *s, void * userdata) {
101
switch (pa_stream_get_state(s)) {
102
case PA_STREAM_READY:
103
case PA_STREAM_FAILED:
104
case PA_STREAM_TERMINATED:
105
signal_mainloop(userdata);
107
case PA_STREAM_UNCONNECTED:
108
case PA_STREAM_CREATING:
113
static void stream_latency_update_cb(pa_stream *s, void *userdata) {
114
signal_mainloop(userdata);
117
static void stream_request_cb(pa_stream *s, size_t length, void *userdata) {
118
signal_mainloop(userdata);
121
static void drain_result_cb(pa_stream *s, int success, void *userdata) {
122
xmms_pulse *p = userdata;
126
p->operation_success = success;
127
signal_mainloop(userdata);
135
xmms_pulse_backend_new(const char *server, const char *name,
138
int error = PA_ERR_INTERNAL;
140
if (server && !*server) {
142
*rerror = PA_ERR_INVALID;
146
p = g_new0(xmms_pulse, 1);
150
p->mainloop = pa_threaded_mainloop_new();
154
p->context = pa_context_new(pa_threaded_mainloop_get_api(p->mainloop), name);
158
pa_context_set_state_callback(p->context, context_state_cb, p);
160
if (pa_context_connect(p->context, server, 0, NULL) < 0) {
161
error = pa_context_errno(p->context);
165
pa_threaded_mainloop_lock(p->mainloop);
167
if (pa_threaded_mainloop_start(p->mainloop) < 0)
168
goto unlock_and_fail;
170
/* Wait until the context is ready */
171
pa_threaded_mainloop_wait(p->mainloop);
173
if (pa_context_get_state(p->context) != PA_CONTEXT_READY) {
174
error = pa_context_errno(p->context);
175
goto unlock_and_fail;
178
pa_threaded_mainloop_unlock(p->mainloop);
182
pa_threaded_mainloop_unlock(p->mainloop);
186
xmms_pulse_backend_free(p);
191
void xmms_pulse_backend_free(xmms_pulse *p) {
195
xmms_pulse_backend_close_stream(p);
197
pa_threaded_mainloop_stop(p->mainloop);
199
pa_context_unref(p->context);
201
pa_threaded_mainloop_free(p->mainloop);
207
gboolean xmms_pulse_backend_set_stream(xmms_pulse *p, const char *stream_name,
209
xmms_sample_format_t format,
210
int samplerate, int channels,
212
pa_sample_format_t pa_format = PA_SAMPLE_INVALID;
213
int error = PA_ERR_INTERNAL;
218
/* Convert the XMMS2 sample format to the pulse format. */
219
for (i = 0; i < G_N_ELEMENTS(xmms_pulse_formats); i++) {
220
if (xmms_pulse_formats[i].xmms_fmt == format) {
221
pa_format = xmms_pulse_formats[i].pulse_fmt;
225
g_return_val_if_fail (pa_format != PA_SAMPLE_INVALID, FALSE);
227
/* If there is an existing stream, check to see if it can do the
229
if (p->stream && p->sample_spec.format == pa_format &&
230
p->sample_spec.rate == samplerate &&
231
p->sample_spec.channels == channels)
234
/* The existing stream needs to be shut down. */
236
xmms_pulse_backend_close_stream(p);
238
pa_threaded_mainloop_lock(p->mainloop);
241
/* Configure the new stream. */
242
p->sample_spec.format = pa_format;
243
p->sample_spec.rate = samplerate;
244
p->sample_spec.channels = channels;
245
pa_channel_map_init_auto(&p->channel_map, channels, PA_CHANNEL_MAP_DEFAULT);
247
/* Create and set up the new stream. */
248
p->stream = pa_stream_new(p->context, stream_name, &p->sample_spec, &p->channel_map);
250
error = pa_context_errno(p->context);
251
goto unlock_and_fail;
254
pa_stream_set_state_callback(p->stream, stream_state_cb, p);
255
pa_stream_set_write_callback(p->stream, stream_request_cb, p);
256
pa_stream_set_latency_update_callback(p->stream, stream_latency_update_cb, p);
258
ret = pa_stream_connect_playback(
259
p->stream, sink, NULL,
260
PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE,
264
error = pa_context_errno(p->context);
265
goto unlock_and_fail;
268
/* Wait until the stream is ready */
269
while (pa_stream_get_state(p->stream) == PA_STREAM_CREATING) {
270
pa_threaded_mainloop_wait(p->mainloop);
272
if (pa_stream_get_state(p->stream) != PA_STREAM_READY) {
273
error = pa_context_errno(p->context);
274
goto unlock_and_fail;
277
pa_threaded_mainloop_unlock(p->mainloop);
281
pa_threaded_mainloop_unlock(p->mainloop);
285
pa_stream_unref(p->stream);
291
void xmms_pulse_backend_close_stream(xmms_pulse *p)
295
pa_threaded_mainloop_lock(p->mainloop);
297
/* We're killing it anyway, sod errors. */
298
xmms_pulse_backend_drain(p, NULL);
300
pa_stream_disconnect(p->stream);
301
pa_stream_unref(p->stream);
304
pa_threaded_mainloop_unlock(p->mainloop);
307
gboolean xmms_pulse_backend_write(xmms_pulse *p, const char *data,
308
size_t length, int *rerror)
312
if (!data || !length) {
314
*rerror = PA_ERR_INVALID;
318
pa_threaded_mainloop_lock(p->mainloop);
319
if (!check_pulse_health(p, rerror))
320
goto unlock_and_fail;
326
while (!(buf_len = pa_stream_writable_size(p->stream))) {
327
pa_threaded_mainloop_wait(p->mainloop);
328
if (!check_pulse_health(p, rerror))
329
goto unlock_and_fail;
332
if (buf_len == (size_t)-1) {
334
*rerror = pa_context_errno((p)->context);
335
goto unlock_and_fail;
337
if (buf_len > length)
340
ret = pa_stream_write(p->stream, data, buf_len, NULL, 0, PA_SEEK_RELATIVE);
343
*rerror = pa_context_errno((p)->context);
344
goto unlock_and_fail;
351
pa_threaded_mainloop_unlock(p->mainloop);
355
pa_threaded_mainloop_unlock(p->mainloop);
360
gboolean xmms_pulse_backend_drain(xmms_pulse *p, int *rerror) {
361
pa_operation *o = NULL;
364
if (!check_pulse_health(p, rerror))
365
goto unlock_and_fail;
367
o = pa_stream_drain(p->stream, drain_result_cb, p);
370
*rerror = pa_context_errno((p)->context);
371
goto unlock_and_fail;
374
p->operation_success = 0;
375
while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
376
pa_threaded_mainloop_wait(p->mainloop);
377
if (!check_pulse_health(p, rerror))
378
goto unlock_and_fail;
380
pa_operation_unref(o);
382
if (!p->operation_success) {
384
*rerror = pa_context_errno((p)->context);
385
goto unlock_and_fail;
392
pa_operation_cancel(o);
393
pa_operation_unref(o);
400
gboolean xmms_pulse_backend_flush(xmms_pulse *p, int *rerror) {
403
pa_threaded_mainloop_lock(p->mainloop);
404
if (!check_pulse_health(p, rerror))
405
goto unlock_and_fail;
407
o = pa_stream_flush(p->stream, drain_result_cb, p);
410
*rerror = pa_context_errno((p)->context);
411
goto unlock_and_fail;
414
p->operation_success = 0;
415
while (pa_operation_get_state(o) != PA_OPERATION_DONE) {
416
pa_threaded_mainloop_wait(p->mainloop);
417
if (!check_pulse_health(p, rerror))
418
goto unlock_and_fail;
420
pa_operation_unref(o);
422
if (!p->operation_success) {
424
*rerror = pa_context_errno((p)->context);
425
goto unlock_and_fail;
428
pa_threaded_mainloop_unlock(p->mainloop);
433
pa_operation_cancel(o);
434
pa_operation_unref(o);
437
pa_threaded_mainloop_unlock(p->mainloop);
442
int xmms_pulse_backend_get_latency(xmms_pulse *p, int *rerror) {
447
pa_threaded_mainloop_lock(p->mainloop);
450
if (!check_pulse_health(p, rerror))
451
goto unlock_and_fail;
453
if (pa_stream_get_latency(p->stream, &t, &negative) >= 0)
456
r = pa_context_errno(p->context);
457
if (r != PA_ERR_NODATA) {
460
goto unlock_and_fail;
462
/* Wait until latency data is available again */
463
pa_threaded_mainloop_wait(p->mainloop);
466
pa_threaded_mainloop_unlock(p->mainloop);
468
return negative ? 0 : t;
471
pa_threaded_mainloop_unlock(p->mainloop);