Project

General

Profile

0001-Add-Sndio-plugin.patch

Brad Smith, April 12, 2012 01:30

View differences:

configure.ac
623 623
	OUTPUT_PLUGINS="$OUTPUT_PLUGINS sdlout"
624 624
fi
625 625

  
626
dnl *** sndio output
627

  
628
AC_ARG_ENABLE(sndio,
629
    [  --disable-sndio         disable sndio output plugin (default=enabled) ],
630
    [have_sndio=$enableval],
631
    [have_sndio=yes]
632
)
633

  
634
if test "x$have_sndio" = "xyes"; then
635
	AC_CHECK_HEADER(sndio.h,, have_sndio=no)
636
        if test x$have_sndio = xyes; then  
637
		AC_CHECK_LIB(sndio, sio_open, haves_sndio=yes, have_sndio=no)
638
        fi
639
fi
640

  
641
if test "x$have_sndio" = "xyes"; then
642
	OUTPUT_PLUGINS="$OUTPUT_PLUGINS sndio"
643
	SNDIO_LIBS="-lsndio"
644
	AC_SUBST(SNDIO_LIBS)
645
fi
626 646

  
627 647
dnl *** amidi-plug (note: to avoid checking twice ALSA, this should appear somewhere after the alsa output plugin check)
628 648

  
......
1075 1095
echo "  --------------"
1076 1096
echo "  Open Sound System (oss4):               $enable_oss4"
1077 1097
echo "  Advanced Linux Sound Arch. (alsa):      $have_alsa"
1098
echo "  Sndio (sndio):                          $have_sndio"
1078 1099
echo "  PulseAudio (pulse):                     $have_pulse"
1079 1100
echo "  Jack Audio Connection Kit (jack):       $enable_jack"
1080 1101
echo "  Simple DirectMedia Layer (sdlout):      $enable_sdlout"
extra.mk.in
98 98
SIDPLAY2_LIBS ?= @SIDPLAY2_LIBS@
99 99
SNDFILE_CFLAGS ?= @SNDFILE_CFLAGS@
100 100
SNDFILE_LIBS ?= @SNDFILE_LIBS@
101
SNDIO_LIBS ?= @SNDIO_LIBS@
101 102
WAVPACK_CFLAGS ?= @WAVPACK_CFLAGS@
102 103
WAVPACK_LIBS ?= @WAVPACK_LIBS@
103 104
XCOMPOSITE_CFLAGS ?= @XCOMPOSITE_CFLAGS@
src/sndio/Makefile
1
PLUGIN = sndio${PLUGIN_SUFFIX}
2

  
3
SRCS =	sndio.c
4

  
5
include ../../buildsys.mk
6
include ../../extra.mk
7

  
8
plugindir := ${plugindir}/${OUTPUT_PLUGIN_DIR}
9

  
10
CFLAGS += ${PLUGIN_CFLAGS}
11
CPPFLAGS += ${PLUGIN_CPPFLAGS} ${GTK_CFLAGS} ${GLIB_CFLAGS} -I../..
12
LIBS += ${GTK_LIBS} ${GLIB_LIBS} ${SNDIO_LIBS}
src/sndio/sndio.c
1
/*
2
 * Copyright (c) 2008, 2009 Thomas Pfaff <tpfaff@tp76.info>
3
 * Copyright (c) 2012 Alexandre Ratchov <alex@caoua.org>
4
 *
5
 * Permission to use, copy, modify, and distribute this software for any
6
 * purpose with or without fee is hereby granted, provided that the above
7
 * copyright notice and this permission notice appear in all copies.
8
 *
9
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
17

  
18
#include <sndio.h>
19
#include <stdio.h>
20
#include <stdlib.h>
21
#include <string.h>
22
#include <pthread.h>
23
#include <gtk/gtk.h>
24
#include <audacious/plugin.h>
25
#include <audacious/misc.h>
26
#include <audacious/i18n.h>
27
#include <audacious/plugin.h>
28
#include <libaudgui/libaudgui.h>
29
#include <libaudgui/libaudgui-gtk.h>
30

  
31
#include "config.h"
32

  
33
bool_t	sndio_init(void);
34
void	sndio_cleanup(void);
35
void	sndio_about(void);
36
int	sndio_take_message(const char *, const void *, int);
37
void	sndio_configure(void);
38
void	sndio_get_volume(int *, int *);
39
void	sndio_set_volume(int, int);
40
bool_t	sndio_open(int, int, int);
41
void	sndio_close(void);
42
void	sndio_write(void *, int);
43
void	sndio_pause(bool_t);
44
void	sndio_flush(int);
45
int	sndio_output_time(void);
46
int	sndio_written_time(void);
47
void	sndio_drain(void);
48
void	sndio_set_written_time(int);
49

  
50
void	onmove_cb(void *, int);
51
void	onvol_cb(void *, unsigned);
52

  
53
void	configure_win_ok_cb(GtkWidget *, gpointer);
54

  
55
static struct sio_par par;
56
static struct sio_hdl *hdl;
57
static long long rdpos;
58
static long long wrpos;
59
static int paused, flushed, volume;
60
static int flush_time, pause_flag, volume_target;
61
static int writing, pause_pending, flush_pending, volume_pending;
62
static int bytes_per_sec;
63
static pthread_mutex_t mtx;
64
static pthread_t sndio_thread;
65

  
66
static GtkWidget *configure_win;
67
static GtkWidget *adevice_entry;
68
static gchar *audiodev;
69

  
70
AUD_OUTPUT_PLUGIN
71
(
72
	.name = "sndio",
73
	.init = sndio_init,
74
	.cleanup = sndio_cleanup,
75
	.about = sndio_about,
76
	.configure = sndio_configure,
77
	.probe_priority = 2,
78
	.get_volume = sndio_get_volume,
79
	.set_volume = sndio_set_volume,
80
	.open_audio = sndio_open,
81
	.write_audio = sndio_write,
82
	.close_audio = sndio_close,
83
	.flush = sndio_flush,
84
	.pause = sndio_pause,
85
	.output_time = sndio_output_time,
86
	.written_time = sndio_written_time,
87
	.set_written_time = sndio_set_written_time,
88
	.drain = sndio_drain
89
)
90

  
91
static struct fmt_to_par {
92
	int fmt, bits, sig, le;
93
} fmt_to_par[] = {
94
	{FMT_S8,      8, 1, 0}, {FMT_U8,      8, 1, 0},
95
	{FMT_S16_LE, 16, 1, 1}, {FMT_S16_BE, 16, 1, 0},
96
	{FMT_U16_LE, 16, 0, 1},	{FMT_U16_BE, 16, 0, 0},
97
	{FMT_S24_LE, 24, 1, 1},	{FMT_S24_BE, 24, 1, 0},
98
	{FMT_U24_LE, 24, 0, 1},	{FMT_U24_BE, 24, 0, 0},
99
	{FMT_S32_LE, 32, 1, 1},	{FMT_S32_BE, 32, 1, 0},
100
	{FMT_U32_LE, 32, 0, 1},	{FMT_U32_BE, 32, 0, 0}
101
};
102

  
103
static void
104
volume_do(int v)
105
{
106
	if (writing) {
107
		volume_target = v;
108
		volume_pending = 1;
109
	} else {
110
		if (hdl)
111
			sio_setvol(hdl, v * SIO_MAXVOL / 100);
112
		volume_pending = 0;
113
	}
114
}
115

  
116
static void
117
pause_do(int flag)
118
{
119
	if (writing) {
120
		pause_flag = flag;
121
		pause_pending = 1;
122
	} else {
123
		if (flag && !paused && !flushed) {
124
			sio_stop(hdl);
125
			sio_start(hdl);
126
			rdpos = wrpos;
127
		}
128
		paused = flag;
129
		pause_pending = 0;
130
	}
131
}
132

  
133
static void
134
flush_do(int time)
135
{
136
	if (writing) {
137
		flush_time = time;
138
		flush_pending = 1;
139
	} else {
140
		if (!paused && !flushed) {
141
			sio_stop(hdl);
142
			sio_start(hdl);
143
		}
144
		rdpos = wrpos = (long long)time * bytes_per_sec / 1000;
145
		flush_pending = 0;
146
		flushed = 1;
147
	}
148
}
149

  
150
void
151
sndio_about(void)
152
{
153
	static GtkWidget *about = NULL;
154

  
155
	audgui_simple_message(&about, GTK_MESSAGE_INFO,
156
	    _("About Sndio Output Plugin"),
157
	    _("Sndio Output Plugin\n\n"
158
	    "Written by Thomas Pfaff <tpfaff@tp76.info>\n"));
159
}
160

  
161
static const gchar * const sndio_defaults[] = {
162
 "volume", "100",
163
 "audiodev", "",
164
 NULL,
165
};
166

  
167
bool_t
168
sndio_init(void)
169
{
170
	pthread_mutex_init(&mtx, NULL);
171

  
172
	aud_config_set_defaults("sndio", sndio_defaults);
173
	volume = aud_get_int("sndio", "volume");
174
	audiodev = aud_get_string("sndio", "audiodev");
175

  
176
	return (1);
177
}
178

  
179
void
180
sndio_cleanup(void)
181
{
182
	aud_set_int("sndio", "volume", volume);
183
	aud_set_string("sndio", "audiodev", audiodev);
184
	pthread_mutex_destroy(&mtx);
185
}
186

  
187
void
188
sndio_get_volume(int *l, int *r)
189
{
190
	pthread_mutex_lock(&mtx);
191
	*l = *r = volume;
192
	pthread_mutex_unlock(&mtx);
193
}
194

  
195
void
196
sndio_set_volume(int l, int r)
197
{
198
	/* Ignore balance control, so use unattenuated channel. */
199
	pthread_mutex_lock(&mtx);
200
	volume = l > r ? l : r;
201
	volume_do(volume);
202
	pthread_mutex_unlock(&mtx);
203
}
204

  
205
bool_t
206
sndio_open(int fmt, int rate, int nch)
207
{
208
	int i;
209
	struct sio_par askpar;
210
	GtkWidget *dialog = NULL;
211

  
212
	hdl = sio_open(strlen(audiodev) > 0 ? audiodev : NULL, SIO_PLAY, 0);
213
	if (!hdl) {
214
		g_warning("failed to open audio device %s", audiodev);
215
		return (0);
216
	}
217
	sio_initpar(&askpar);
218
	for (i = 0; ; i++) {
219
		if (i == sizeof(fmt_to_par) / sizeof(struct fmt_to_par)) {
220
			g_warning("unknown format %d requested", fmt);
221
			sndio_close();
222
			return 0;
223
		}
224
		if (fmt_to_par[i].fmt == fmt)
225
			break;
226
	}
227
	askpar.bits = fmt_to_par[i].bits;
228
	askpar.bps = SIO_BPS(askpar.bits);
229
	askpar.sig = fmt_to_par[i].sig;
230
	if (askpar.bits > 8)
231
		askpar.le = fmt_to_par[i].le;
232
	askpar.pchan = nch;
233
	askpar.rate = rate;
234
	askpar.appbufsz = aud_get_int(NULL, "output_buffer_size");
235
	if (!sio_setpar(hdl, &askpar) || !sio_getpar(hdl, &par)) {
236
		g_warning("failed to set parameters");
237
		sndio_close();
238
		return (0);
239
	}
240
	if ((par.bps > 1 && par.le != askpar.le) ||
241
	    (par.bits < par.bps * 8 && !par.msb) ||
242
	    par.bps != askpar.bps ||
243
	    par.sig != askpar.sig ||
244
	    par.pchan != askpar.pchan ||
245
            par.rate != askpar.rate) {
246
		g_warning("parameters not supported by the audio device");
247
		audgui_simple_message(&dialog, GTK_MESSAGE_INFO,
248
		    _("Unsupported format"),
249
		    _("A format not supported by the audio device "
250
		    "was requested.\n\n"
251
		    "Please try again with the sndiod(1) server running."));
252
		sndio_close();
253
		return (0);
254
	}
255
	rdpos = 0;
256
	wrpos = 0;
257
	sio_onmove(hdl, onmove_cb, NULL);
258
	sio_onvol(hdl, onvol_cb, NULL);
259
	volume_do(volume);
260
	if (!sio_start(hdl)) {
261
		g_warning("failed to start audio device");
262
		sndio_close();
263
		return (0);
264
	}
265
	pause_pending = flush_pending = volume_pending = 0;
266
	bytes_per_sec = par.bps * par.pchan * par.rate;
267
	flushed = 1;
268
	paused = 0;
269
	return (1);
270
}
271

  
272
void
273
sndio_write(void *ptr, int length)
274
{
275
	unsigned n;
276

  
277
	pthread_mutex_lock(&mtx);
278
	flushed = 0;
279
	if (!paused) {	
280
		writing = 1;
281
		pthread_mutex_unlock(&mtx);
282
		n = sio_write(hdl, ptr, length);
283
		pthread_mutex_lock(&mtx);
284
		writing = 0;
285
		wrpos += n;
286
	}
287
	if (volume_pending)
288
		volume_do(volume);
289
	if (flush_pending)
290
		flush_do(flush_time);
291
	if (pause_pending)
292
		pause_do(pause_flag);
293
	if (paused) {
294
		pthread_mutex_unlock(&mtx);
295
		usleep(10000);
296
		pthread_mutex_lock(&mtx);
297
	}
298
	pthread_mutex_unlock(&mtx);
299
}
300

  
301
void
302
sndio_close(void)
303
{
304
	if (!hdl)
305
		return;
306
	sio_close(hdl);
307
	hdl = NULL;
308
}
309

  
310
void
311
sndio_flush(int time)
312
{
313
	pthread_mutex_lock(&mtx);
314
	flush_do(time);
315
	pthread_mutex_unlock(&mtx);
316
}
317

  
318
void
319
sndio_pause(bool_t flag)
320
{	
321
	pthread_mutex_lock(&mtx);
322
	pause_do(flag);
323
	pthread_mutex_unlock(&mtx);
324
}
325

  
326
void
327
sndio_drain(void)
328
{
329
	/* sndio always drains */
330
}
331

  
332
int
333
sndio_output_time(void)
334
{
335
	int time;
336

  
337
	pthread_mutex_lock(&mtx);
338
	time = rdpos * 1000 / bytes_per_sec;
339
	pthread_mutex_unlock(&mtx);
340
	return time;
341
}
342

  
343
int
344
sndio_written_time(void)
345
{
346
	int time;
347

  
348
	pthread_mutex_lock(&mtx);
349
	time = wrpos * 1000 / bytes_per_sec;
350
	pthread_mutex_unlock(&mtx);
351
	return time;
352
}
353

  
354
void
355
sndio_set_written_time(int time)
356
{
357
	int used;
358

  
359
	pthread_mutex_lock(&mtx);
360
	wrpos = time * bytes_per_sec / 1000;
361
	used = wrpos - rdpos;
362
	rdpos = time * bytes_per_sec / 1000;
363
	wrpos = rdpos + used;
364
	pthread_mutex_unlock(&mtx);
365
}
366

  
367
void
368
onmove_cb(void *addr, int delta)
369
{
370
	pthread_mutex_lock(&mtx);
371
	rdpos += delta * (int)(par.bps * par.pchan);
372
	pthread_mutex_unlock(&mtx);
373
}
374

  
375
void
376
onvol_cb(void *addr, unsigned ctl)
377
{
378
	/* Update volume only if it actually changed */
379
	pthread_mutex_lock(&mtx);
380
	if (ctl != volume * SIO_MAXVOL / 100)
381
		volume = ctl * 100 / SIO_MAXVOL;
382
	pthread_mutex_unlock(&mtx);
383
}
384

  
385
void
386
configure_win_ok_cb(GtkWidget *w, gpointer data)
387
{
388
	strlcpy(audiodev, gtk_entry_get_text(GTK_ENTRY(adevice_entry)),
389
	    PATH_MAX);
390
	aud_set_string("sndio", "audiodev", audiodev);
391
	gtk_widget_destroy(configure_win);
392
}
393

  
394
void
395
sndio_configure(void)
396
{
397
	GtkWidget *vbox;
398
	GtkWidget *adevice_frame, *adevice_text, *adevice_vbox;
399
	GtkWidget *bbox, *ok, *cancel;
400

  
401
	if (configure_win) {
402
		gtk_window_present(GTK_WINDOW(configure_win));
403
		return;
404
	}
405

  
406
	configure_win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
407
	g_signal_connect(configure_win, "destroy",
408
	    G_CALLBACK(gtk_widget_destroyed), &configure_win);
409

  
410
	gtk_window_set_title(GTK_WINDOW(configure_win), _("sndio device"));
411
	gtk_window_set_resizable(GTK_WINDOW(configure_win), FALSE);
412
	gtk_window_set_position(GTK_WINDOW(configure_win), GTK_WIN_POS_MOUSE);
413
	gtk_container_set_border_width(GTK_CONTAINER(configure_win), 10);
414

  
415
	vbox = gtk_vbox_new(FALSE, 5);
416
	gtk_container_add(GTK_CONTAINER(configure_win), vbox);
417
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
418

  
419
	adevice_frame = gtk_frame_new(_("Audio device:"));
420
	gtk_box_pack_start(GTK_BOX(vbox), adevice_frame, FALSE, FALSE, 0);
421

  
422
	adevice_vbox = gtk_vbox_new(FALSE, 5);
423
	gtk_container_set_border_width(GTK_CONTAINER(adevice_vbox), 5);
424
	gtk_container_add(GTK_CONTAINER(adevice_frame), adevice_vbox);
425

  
426
	adevice_text = gtk_label_new(_("(empty means default)"));
427
	gtk_box_pack_start(GTK_BOX(adevice_vbox), adevice_text, TRUE, TRUE, 0);
428

  
429
	adevice_entry = gtk_entry_new();
430
	gtk_entry_set_text(GTK_ENTRY(adevice_entry), audiodev);
431
	gtk_box_pack_start(GTK_BOX(adevice_vbox), adevice_entry, TRUE, TRUE, 0);
432

  
433
	bbox = gtk_hbutton_box_new();
434
	gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
435
	gtk_box_set_spacing(GTK_BOX(bbox), 5);
436
	gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0);
437

  
438
	ok = gtk_button_new_with_label(_("OK"));
439
	g_signal_connect(ok, "clicked",
440
	    G_CALLBACK(configure_win_ok_cb), NULL);
441

  
442
	gtk_widget_set_can_default(ok, TRUE);
443
	gtk_box_pack_start(GTK_BOX(bbox), ok, TRUE, TRUE, 0);
444
	gtk_widget_grab_default(ok);
445

  
446
	cancel = gtk_button_new_with_label(_("Cancel"));
447
	g_signal_connect(cancel, "clicked",
448
	    G_CALLBACK(gtk_widget_destroy), &configure_win);
449

  
450
	gtk_widget_set_can_default(cancel, TRUE);
451
	gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0);
452

  
453
	gtk_widget_show_all(configure_win);
454
}
0
-