1 /*
2 * Copyright (c) 2008 Alexandre Ratchov <alex at caoua.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include <string.h>
18 #include <sndio.h>
19 #include <ao/ao.h>
20 #include <ao/plugin.h>
21
22 static char *ao_sndio_options[] = {
23 "verbose",
24 "quiet",
25 "matrix",
26 "debug",
27 "dev",
28 "id"
29 };
30
31 ao_info ao_sndio_info = {
32 AO_TYPE_LIVE,
33 "sndio audio output",
34 "sndio",
35 "Alexandre Ratchov <alex at caoua.org>",
36 "Outputs to the sndio library",
37 AO_FMT_NATIVE,
38 30,
39 ao_sndio_options,
40 sizeof(ao_sndio_options)/sizeof(*ao_sndio_options)
41 };
42
43 typedef struct ao_sndio_internal
44 {
45 struct sio_hdl *hdl;
46 char *dev;
47 int id;
48 } ao_sndio_internal;
49
ao_plugin_test()50 int ao_plugin_test()
51 {
52 struct sio_hdl *hdl;
53
54 hdl = sio_open(NULL, SIO_PLAY, 0);
55 if (hdl == NULL)
56 return 0;
57 sio_close(hdl);
58 return 1;
59 }
60
ao_plugin_driver_info(void)61 ao_info *ao_plugin_driver_info(void)
62 {
63 return &ao_sndio_info;
64 }
65
ao_plugin_device_init(ao_device * device)66 int ao_plugin_device_init(ao_device *device)
67 {
68 ao_sndio_internal *internal;
69 internal = (ao_sndio_internal *) calloc(1,sizeof(*internal));
70 internal->id=-1;
71 device->internal = internal;
72 device->output_matrix_order = AO_OUTPUT_MATRIX_FIXED;
73 return 1;
74 }
75
ao_plugin_set_option(ao_device * device,const char * key,const char * value)76 int ao_plugin_set_option(ao_device *device, const char *key, const char *value)
77 {
78 ao_sndio_internal *internal = (ao_sndio_internal *) device->internal;
79
80 if (!strcmp(key, "dev")) {
81 if (internal->dev)
82 free (internal->dev);
83 if(!value){
84 internal->dev=NULL;
85 }else{
86 if (!(internal->dev = strdup(value)))
87 return 0;
88 }
89 }
90 if (!strcmp(key, "id")) {
91 if(internal->dev)
92 free (internal->dev);
93 internal->dev=NULL;
94 internal->id=atoi(value);
95 }
96 return 1;
97 }
98
ao_plugin_open(ao_device * device,ao_sample_format * format)99 int ao_plugin_open(ao_device *device, ao_sample_format *format)
100 {
101 ao_sndio_internal *internal = (ao_sndio_internal *) device->internal;
102 struct sio_hdl *hdl;
103 struct sio_par par;
104
105 if(!internal->dev && internal->id>=0){
106 char buf[80];
107 sprintf(buf,"sun:%d",internal->id);
108 internal->dev = strdup(buf);
109 }
110
111 hdl = sio_open(internal->dev, SIO_PLAY, 0);
112 if (hdl == NULL)
113 return 0;
114 internal->hdl = hdl;
115
116 sio_initpar(&par);
117 par.sig = 1;
118 if (format->bits > 8)
119 par.le = device->client_byte_format == AO_FMT_LITTLE ? 1 : 0;
120 par.bits = format->bits;
121 par.rate = format->rate;
122 par.pchan = device->output_channels;
123 if (!sio_setpar(hdl, &par))
124 return 0;
125 if (!sio_getpar(hdl, &par))
126 return 0;
127 if (par.bits != format->bits)
128 return 0;
129 device->driver_byte_format = par.le ? AO_FMT_LITTLE : AO_FMT_BIG;
130 if (!sio_start(hdl))
131 return 0;
132
133 if(!device->inter_matrix){
134 /* set up matrix such that users are warned about > stereo playback */
135 if(device->output_channels<=2)
136 device->inter_matrix=strdup("L,R");
137 //else no matrix, which results in a warning
138 }
139
140 return 1;
141 }
142
ao_plugin_play(ao_device * device,const char * output_samples,uint_32 num_bytes)143 int ao_plugin_play(ao_device *device, const char *output_samples, uint_32 num_bytes)
144 {
145 ao_sndio_internal *internal = (ao_sndio_internal *) device->internal;
146 struct sio_hdl *hdl = internal->hdl;
147
148 if (!sio_write(hdl, output_samples, num_bytes))
149 return 0;
150 return 1;
151 }
152
ao_plugin_close(ao_device * device)153 int ao_plugin_close(ao_device *device)
154 {
155 ao_sndio_internal *internal = (ao_sndio_internal *) device->internal;
156 struct sio_hdl *hdl = internal->hdl;
157
158 if(hdl){
159 sio_close(hdl);
160 internal->hdl = NULL;
161 }
162 return 1;
163 }
164
ao_plugin_device_clear(ao_device * device)165 void ao_plugin_device_clear(ao_device *device)
166 {
167 ao_sndio_internal *internal = (ao_sndio_internal *) device->internal;
168 struct sio_hdl *hdl = internal->hdl;
169
170 if(hdl)
171 sio_close(hdl);
172 if(internal->dev)
173 free(internal->dev);
174 free(internal);
175 device->internal=NULL;
176 }
177