Mercurial > audio-send
comparison Alc/backends/sndio.c @ 0:f9476ff7637e
initial forking of open-al to create multiple listeners
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Tue, 25 Oct 2011 13:02:31 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:f9476ff7637e |
---|---|
1 /** | |
2 * OpenAL cross platform audio library | |
3 * Copyright (C) 1999-2007 by authors. | |
4 * This library is free software; you can redistribute it and/or | |
5 * modify it under the terms of the GNU Library General Public | |
6 * License as published by the Free Software Foundation; either | |
7 * version 2 of the License, or (at your option) any later version. | |
8 * | |
9 * This library is distributed in the hope that it will be useful, | |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
12 * Library General Public License for more details. | |
13 * | |
14 * You should have received a copy of the GNU Library General Public | |
15 * License along with this library; if not, write to the | |
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
17 * Boston, MA 02111-1307, USA. | |
18 * Or go to http://www.gnu.org/copyleft/lgpl.html | |
19 */ | |
20 | |
21 #include "config.h" | |
22 | |
23 #include <stdio.h> | |
24 #include <stdlib.h> | |
25 #include <string.h> | |
26 #include "alMain.h" | |
27 #include "AL/al.h" | |
28 #include "AL/alc.h" | |
29 | |
30 #include <sndio.h> | |
31 | |
32 | |
33 static const ALCchar sndio_device[] = "SndIO Default"; | |
34 | |
35 | |
36 static void *sndio_handle; | |
37 #ifdef HAVE_DYNLOAD | |
38 #define MAKE_FUNC(x) static typeof(x) * p##x | |
39 MAKE_FUNC(sio_initpar); | |
40 MAKE_FUNC(sio_open); | |
41 MAKE_FUNC(sio_close); | |
42 MAKE_FUNC(sio_setpar); | |
43 MAKE_FUNC(sio_getpar); | |
44 MAKE_FUNC(sio_getcap); | |
45 MAKE_FUNC(sio_onmove); | |
46 MAKE_FUNC(sio_write); | |
47 MAKE_FUNC(sio_read); | |
48 MAKE_FUNC(sio_start); | |
49 MAKE_FUNC(sio_stop); | |
50 MAKE_FUNC(sio_nfds); | |
51 MAKE_FUNC(sio_pollfd); | |
52 MAKE_FUNC(sio_revents); | |
53 MAKE_FUNC(sio_eof); | |
54 MAKE_FUNC(sio_setvol); | |
55 MAKE_FUNC(sio_onvol); | |
56 | |
57 #define sio_initpar psio_initpar | |
58 #define sio_open psio_open | |
59 #define sio_close psio_close | |
60 #define sio_setpar psio_setpar | |
61 #define sio_getpar psio_getpar | |
62 #define sio_getcap psio_getcap | |
63 #define sio_onmove psio_onmove | |
64 #define sio_write psio_write | |
65 #define sio_read psio_read | |
66 #define sio_start psio_start | |
67 #define sio_stop psio_stop | |
68 #define sio_nfds psio_nfds | |
69 #define sio_pollfd psio_pollfd | |
70 #define sio_revents psio_revents | |
71 #define sio_eof psio_eof | |
72 #define sio_setvol psio_setvol | |
73 #define sio_onvol psio_onvol | |
74 #endif | |
75 | |
76 | |
77 static ALCboolean sndio_load(void) | |
78 { | |
79 if(!sndio_handle) | |
80 { | |
81 #ifdef HAVE_DYNLOAD | |
82 sndio_handle = LoadLib("libsndio.so"); | |
83 if(!sndio_handle) | |
84 return ALC_FALSE; | |
85 | |
86 #define LOAD_FUNC(f) do { \ | |
87 p##f = GetSymbol(sndio_handle, #f); \ | |
88 if(p##f == NULL) { \ | |
89 CloseLib(sndio_handle); \ | |
90 sndio_handle = NULL; \ | |
91 return ALC_FALSE; \ | |
92 } \ | |
93 } while(0) | |
94 LOAD_FUNC(sio_initpar); | |
95 LOAD_FUNC(sio_open); | |
96 LOAD_FUNC(sio_close); | |
97 LOAD_FUNC(sio_setpar); | |
98 LOAD_FUNC(sio_getpar); | |
99 LOAD_FUNC(sio_getcap); | |
100 LOAD_FUNC(sio_onmove); | |
101 LOAD_FUNC(sio_write); | |
102 LOAD_FUNC(sio_read); | |
103 LOAD_FUNC(sio_start); | |
104 LOAD_FUNC(sio_stop); | |
105 LOAD_FUNC(sio_nfds); | |
106 LOAD_FUNC(sio_pollfd); | |
107 LOAD_FUNC(sio_revents); | |
108 LOAD_FUNC(sio_eof); | |
109 LOAD_FUNC(sio_setvol); | |
110 LOAD_FUNC(sio_onvol); | |
111 #undef LOAD_FUNC | |
112 #else | |
113 sndio_handle = (void*)0xDEADBEEF; | |
114 #endif | |
115 } | |
116 return ALC_TRUE; | |
117 } | |
118 | |
119 | |
120 typedef struct { | |
121 struct sio_hdl *sndHandle; | |
122 | |
123 ALvoid *mix_data; | |
124 ALsizei data_size; | |
125 | |
126 volatile int killNow; | |
127 ALvoid *thread; | |
128 } sndio_data; | |
129 | |
130 | |
131 static ALuint sndio_proc(ALvoid *ptr) | |
132 { | |
133 ALCdevice *device = ptr; | |
134 sndio_data *data = device->ExtraData; | |
135 ALsizei frameSize; | |
136 size_t wrote; | |
137 | |
138 SetRTPriority(); | |
139 | |
140 frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); | |
141 | |
142 while(!data->killNow && device->Connected) | |
143 { | |
144 ALsizei len = data->data_size; | |
145 ALubyte *WritePtr = data->mix_data; | |
146 | |
147 aluMixData(device, WritePtr, len/frameSize); | |
148 while(len > 0 && !data->killNow) | |
149 { | |
150 wrote = sio_write(data->sndHandle, WritePtr, len); | |
151 if(wrote == 0) | |
152 { | |
153 ERR("sio_write failed\n"); | |
154 aluHandleDisconnect(device); | |
155 break; | |
156 } | |
157 | |
158 len -= wrote; | |
159 WritePtr += wrote; | |
160 } | |
161 } | |
162 | |
163 return 0; | |
164 } | |
165 | |
166 | |
167 | |
168 static ALCboolean sndio_open_playback(ALCdevice *device, const ALCchar *deviceName) | |
169 { | |
170 sndio_data *data; | |
171 | |
172 if(!deviceName) | |
173 deviceName = sndio_device; | |
174 else if(strcmp(deviceName, sndio_device) != 0) | |
175 return ALC_FALSE; | |
176 | |
177 data = calloc(1, sizeof(*data)); | |
178 data->killNow = 0; | |
179 | |
180 data->sndHandle = sio_open(NULL, SIO_PLAY, 0); | |
181 if(data->sndHandle == NULL) | |
182 { | |
183 free(data); | |
184 ERR("Could not open device\n"); | |
185 return ALC_FALSE; | |
186 } | |
187 | |
188 device->szDeviceName = strdup(deviceName); | |
189 device->ExtraData = data; | |
190 | |
191 return ALC_TRUE; | |
192 } | |
193 | |
194 static void sndio_close_playback(ALCdevice *device) | |
195 { | |
196 sndio_data *data = device->ExtraData; | |
197 | |
198 sio_close(data->sndHandle); | |
199 free(data); | |
200 device->ExtraData = NULL; | |
201 } | |
202 | |
203 static ALCboolean sndio_reset_playback(ALCdevice *device) | |
204 { | |
205 sndio_data *data = device->ExtraData; | |
206 struct sio_par par; | |
207 | |
208 sio_initpar(&par); | |
209 | |
210 par.rate = device->Frequency; | |
211 | |
212 par.pchan = ((device->FmtChans != DevFmtMono) ? 2 : 1); | |
213 | |
214 switch(device->FmtType) | |
215 { | |
216 case DevFmtByte: | |
217 par.bits = 8; | |
218 par.sig = 1; | |
219 break; | |
220 case DevFmtUByte: | |
221 par.bits = 8; | |
222 par.sig = 0; | |
223 break; | |
224 case DevFmtFloat: | |
225 device->FmtType = DevFmtShort; | |
226 /* fall-through */ | |
227 case DevFmtShort: | |
228 par.bits = 16; | |
229 par.sig = 1; | |
230 break; | |
231 case DevFmtUShort: | |
232 par.bits = 16; | |
233 par.sig = 0; | |
234 break; | |
235 } | |
236 par.le = SIO_LE_NATIVE; | |
237 | |
238 par.round = device->UpdateSize; | |
239 par.appbufsz = device->UpdateSize * (device->NumUpdates-1); | |
240 if(!par.appbufsz) par.appbufsz = device->UpdateSize; | |
241 | |
242 | |
243 if(!sio_setpar(data->sndHandle, &par) || !sio_getpar(data->sndHandle, &par)) | |
244 { | |
245 ERR("Failed to set device parameters\n"); | |
246 return ALC_FALSE; | |
247 } | |
248 | |
249 if(par.rate != device->Frequency) | |
250 { | |
251 if((device->Flags&DEVICE_FREQUENCY_REQUEST)) | |
252 ERR("Failed to set frequency %uhz, got %uhz instead\n", device->Frequency, par.rate); | |
253 device->Flags &= ~DEVICE_FREQUENCY_REQUEST; | |
254 device->Frequency = par.rate; | |
255 } | |
256 | |
257 if(par.pchan != ChannelsFromDevFmt(device->FmtChans)) | |
258 { | |
259 if(par.pchan != 1 && par.pchan != 2) | |
260 { | |
261 ERR("Unhandled channel count: %u\n", par.pchan); | |
262 return ALC_FALSE; | |
263 } | |
264 if((device->Flags&DEVICE_CHANNELS_REQUEST)) | |
265 ERR("Failed to set %s, got %u channels instead\n", DevFmtChannelsString(device->FmtChans), par.pchan); | |
266 device->Flags &= ~DEVICE_CHANNELS_REQUEST; | |
267 device->FmtChans = ((par.pchan==1) ? DevFmtMono : DevFmtStereo); | |
268 } | |
269 | |
270 if(par.bits != par.bps*8) | |
271 { | |
272 ERR("Padded samples not supported (%u of %u bits)\n", par.bits, par.bps*8); | |
273 return ALC_FALSE; | |
274 } | |
275 | |
276 if(par.bits == 8 && par.sig == 1) | |
277 device->FmtType = DevFmtByte; | |
278 else if(par.bits == 8 && par.sig == 0) | |
279 device->FmtType = DevFmtUByte; | |
280 else if(par.bits == 16 && par.sig == 1) | |
281 device->FmtType = DevFmtShort; | |
282 else if(par.bits == 16 && par.sig == 0) | |
283 device->FmtType = DevFmtUShort; | |
284 else | |
285 { | |
286 ERR("Unhandled sample format: %s %u-bit\n", (par.sig?"signed":"unsigned"), par.bits); | |
287 return ALC_FALSE; | |
288 } | |
289 | |
290 | |
291 device->UpdateSize = par.round; | |
292 device->NumUpdates = (par.bufsz/par.round) + 1; | |
293 | |
294 SetDefaultChannelOrder(device); | |
295 | |
296 | |
297 if(!sio_start(data->sndHandle)) | |
298 { | |
299 ERR("Error starting playback\n"); | |
300 return ALC_FALSE; | |
301 } | |
302 | |
303 data->data_size = device->UpdateSize * par.bps * par.pchan; | |
304 data->mix_data = calloc(1, data->data_size); | |
305 | |
306 data->thread = StartThread(sndio_proc, device); | |
307 if(data->thread == NULL) | |
308 { | |
309 sio_stop(data->sndHandle); | |
310 free(data->mix_data); | |
311 data->mix_data = NULL; | |
312 return ALC_FALSE; | |
313 } | |
314 | |
315 return ALC_TRUE; | |
316 } | |
317 | |
318 static void sndio_stop_playback(ALCdevice *device) | |
319 { | |
320 sndio_data *data = device->ExtraData; | |
321 | |
322 if(!data->thread) | |
323 return; | |
324 | |
325 data->killNow = 1; | |
326 StopThread(data->thread); | |
327 data->thread = NULL; | |
328 | |
329 data->killNow = 0; | |
330 if(!sio_stop(data->sndHandle)) | |
331 ERR("Error stopping device\n"); | |
332 | |
333 free(data->mix_data); | |
334 data->mix_data = NULL; | |
335 } | |
336 | |
337 | |
338 static const BackendFuncs sndio_funcs = { | |
339 sndio_open_playback, | |
340 sndio_close_playback, | |
341 sndio_reset_playback, | |
342 sndio_stop_playback, | |
343 NULL, | |
344 NULL, | |
345 NULL, | |
346 NULL, | |
347 NULL, | |
348 NULL | |
349 }; | |
350 | |
351 ALCboolean alc_sndio_init(BackendFuncs *func_list) | |
352 { | |
353 if(!sndio_load()) | |
354 return ALC_FALSE; | |
355 *func_list = sndio_funcs; | |
356 return ALC_TRUE; | |
357 } | |
358 | |
359 void alc_sndio_deinit(void) | |
360 { | |
361 #ifdef HAVE_DYNLOAD | |
362 if(sndio_handle) | |
363 CloseLib(sndio_handle); | |
364 sndio_handle = NULL; | |
365 #endif | |
366 } | |
367 | |
368 void alc_sndio_probe(enum DevProbe type) | |
369 { | |
370 switch(type) | |
371 { | |
372 case DEVICE_PROBE: | |
373 AppendDeviceList(sndio_device); | |
374 break; | |
375 case ALL_DEVICE_PROBE: | |
376 AppendAllDeviceList(sndio_device); | |
377 break; | |
378 case CAPTURE_DEVICE_PROBE: | |
379 break; | |
380 } | |
381 } |