]> git.sesse.net Git - vlc/blob - modules/audio_output/sndio.c
direct3d11: catch texture mapping errors
[vlc] / modules / audio_output / sndio.c
1 /*****************************************************************************
2  * sndio.c : sndio plugin for VLC
3  *****************************************************************************
4  * Copyright (C) 2012 RĂ©mi Denis-Courmont
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2.1 of the License, or
9  * (at your option) any later version.
10  *
11  * This program 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
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19  *****************************************************************************/
20
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
24
25 #include <math.h>
26 #include <assert.h>
27
28 #include <vlc_common.h>
29 #include <vlc_plugin.h>
30 #include <vlc_aout.h>
31
32 #include <sndio.h>
33
34 static int Open (vlc_object_t *);
35 static void Close (vlc_object_t *);
36
37 vlc_module_begin ()
38     set_shortname ("sndio")
39     set_description (N_("OpenBSD sndio audio output"))
40     set_category (CAT_AUDIO)
41     set_subcategory (SUBCAT_AUDIO_AOUT)
42     set_capability ("audio output", 120)
43     set_callbacks (Open, Close)
44 vlc_module_end ()
45
46 static int TimeGet (audio_output_t *, mtime_t *);
47 static void Play (audio_output_t *, block_t *);
48 static void Flush (audio_output_t *, bool);
49 static int VolumeSet (audio_output_t *, float);
50 static int MuteSet (audio_output_t *, bool);
51 static void VolumeChanged (void *, unsigned);
52 static void PositionChanged (void *, int);
53
54 struct aout_sys_t
55 {
56     struct sio_hdl *hdl;
57     int started;
58     int delay;
59     unsigned rate;
60     unsigned volume;
61     bool mute;
62 };
63
64 /** Initializes an sndio playback stream */
65 static int Start (audio_output_t *aout, audio_sample_format_t *restrict fmt)
66 {
67     aout_sys_t *sys = aout->sys;
68
69     sys->hdl = sio_open (NULL, SIO_PLAY, 0 /* blocking */);
70     if (sys->hdl == NULL)
71     {
72         msg_Err (aout, "cannot create audio playback stream");
73         return VLC_EGENERIC;
74     }
75
76     struct sio_par par;
77     sio_initpar (&par);
78     switch (fmt->i_format) {
79     case VLC_CODEC_U8:
80         par.bits = 8;
81         par.sig = 0;
82         break;
83     case VLC_CODEC_S16N:
84         par.bits = 16;
85         par.sig = 1;
86         par.le = SIO_LE_NATIVE;
87         break;
88     case VLC_CODEC_S32N:
89     case VLC_CODEC_FL32:
90     case VLC_CODEC_FL64:
91         par.bits = 32;
92         par.sig = 1;
93         par.le = SIO_LE_NATIVE;
94         break;
95     default:
96         /* use a common audio format */
97         par.bits = 16;
98         par.sig = 1;
99         par.le = SIO_LE_NATIVE;
100     }
101     par.pchan = aout_FormatNbChannels (fmt);
102     par.rate = fmt->i_rate;
103     par.round = par.rate / 50;
104     par.appbufsz = par.rate / 4;
105
106     if (!sio_setpar (sys->hdl, &par) || !sio_getpar (sys->hdl, &par))
107     {
108         msg_Err (aout, "cannot negotiate audio playback parameters");
109         goto error;
110     }
111
112     if (par.bps != par.bits >> 3 && !par.msb)
113     {
114         msg_Err (aout, "unsupported audio sample format (%u bits in %u bytes)",
115                  par.bits, par.bps);
116         goto error;
117     }
118     if (par.sig != (par.bits != 8))
119     {
120         msg_Err (aout, "unsupported audio sample format (%ssigned)",
121                  par.sig ? "" : "un");
122         goto error;
123     }
124     if (par.bps > 1 && par.le != SIO_LE_NATIVE)
125     {
126         msg_Err (aout, "unsupported audio sample format (%s endian)",
127                  par.le ? "little" : "big");
128         goto error;
129     }
130     switch (par.bits)
131     {
132         case 8:
133             fmt->i_format = VLC_CODEC_U8;
134             break;
135         case 16:
136             fmt->i_format = VLC_CODEC_S16N;
137             break;
138         case 32:
139             fmt->i_format = VLC_CODEC_S32N;
140             break;
141         default:
142             msg_Err (aout, "unsupported audio sample format (%u bits)",
143                      par.bits);
144             goto error;
145     }
146
147     fmt->i_rate = par.rate;
148     sys->rate = par.rate;
149
150     /* Channel map */
151     unsigned chans;
152     switch (par.pchan)
153     {
154         case 1:
155             chans = AOUT_CHAN_CENTER;
156             break;
157         case 2:
158             chans = AOUT_CHANS_STEREO;
159             break;
160         case 4:
161             chans = AOUT_CHANS_4_0;
162             break;
163         case 6:
164             chans = AOUT_CHANS_5_1;
165             break;
166         case 8:
167             chans = AOUT_CHANS_7_1;
168             break;
169         default:
170             msg_Err (aout, "unknown %u channels map", par.pchan);
171             goto error;
172     }
173
174     fmt->i_original_channels = fmt->i_physical_channels = chans;
175     aout_FormatPrepare (fmt);
176
177     aout->time_get = TimeGet;
178     aout->play = Play;
179     aout->pause = NULL;
180     aout->flush = Flush;
181     if (sio_onvol(sys->hdl, VolumeChanged, aout))
182     {
183         aout->volume_set = VolumeSet;
184         aout->mute_set = MuteSet;
185     }
186     else
187     {
188         aout->volume_set = NULL;
189         aout->mute_set = NULL;
190     }
191
192     sys->started = 0;
193     sys->delay = 0;
194     sio_onmove (sys->hdl, PositionChanged, aout);
195     sio_start (sys->hdl);
196     return VLC_SUCCESS;
197
198 error:
199     sio_close (sys->hdl);
200     return VLC_EGENERIC;
201 }
202
203 static void Stop (audio_output_t *aout)
204 {
205     aout_sys_t *sys = aout->sys;
206
207     sio_close (sys->hdl);
208 }
209
210 static void PositionChanged (void *arg, int delta)
211 {
212     audio_output_t *aout = arg;
213     aout_sys_t *sys = aout->sys;
214
215     sys->delay -= delta;
216     sys->started = 1;
217 }
218
219 static int TimeGet (audio_output_t *aout, mtime_t *restrict delay)
220 {
221     aout_sys_t *sys = aout->sys;
222
223     if (!sys->started)
224         return -1;
225     *delay = (mtime_t)sys->delay * CLOCK_FREQ / sys->rate;
226     return 0;
227 }
228
229 static void Play (audio_output_t *aout, block_t *block)
230 {
231     aout_sys_t *sys = aout->sys;
232
233     sio_write (sys->hdl, block->p_buffer, block->i_buffer);
234     sys->delay += block->i_nb_samples;
235     block_Release (block);
236 }
237
238 static void Flush (audio_output_t *aout, bool wait)
239 {
240     aout_sys_t *sys = aout->sys;
241
242     sio_stop (sys->hdl);
243     sys->started = 0;
244     sys->delay = 0;
245     sio_start (sys->hdl);
246     (void)wait;
247 }
248
249 static void VolumeChanged (void *arg, unsigned volume)
250 {
251     audio_output_t *aout = arg;
252     float fvol = (float)volume / (float)SIO_MAXVOL;
253
254     aout_VolumeReport (aout, fvol);
255     aout_MuteReport (aout, volume == 0);
256     if (volume) /* remember last non-zero volume to unmute later */
257         aout->sys->volume = volume;
258 }
259
260 static int VolumeSet (audio_output_t *aout, float fvol)
261 {
262     aout_sys_t *sys = aout->sys;
263     unsigned volume;
264
265     if (fvol < 0)
266         fvol = 0;
267     if (fvol > 1)
268         fvol = 1;
269     volume = lroundf (fvol * SIO_MAXVOL);
270     if (!sys->mute && !sio_setvol (sys->hdl, volume))
271         return -1;
272     sys->volume = volume;
273     return 0;
274 }
275
276 static int MuteSet (audio_output_t *aout, bool mute)
277 {
278     aout_sys_t *sys = aout->sys;
279
280     if (!sio_setvol (sys->hdl, mute ? 0 : sys->volume))
281         return -1;
282
283     sys->mute = mute;
284     return 0;
285 }
286
287 static int Open (vlc_object_t *obj)
288 {
289     audio_output_t *aout = (audio_output_t *)obj;
290     aout_sys_t *sys = malloc (sizeof (*sys));
291     if (unlikely(sys == NULL))
292         return VLC_ENOMEM;
293
294     aout->sys = sys;
295     aout->start = Start;
296     aout->stop = Stop;
297     /* FIXME: set volume/mute here */
298     return VLC_SUCCESS;
299 }
300
301 static void Close (vlc_object_t *obj)
302 {
303     audio_output_t *aout = (audio_output_t *)obj;
304     aout_sys_t *sys = aout->sys;
305
306     free (sys);
307 }
308