Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/openal-0.0.8/src/backends/alc_backend_bsd.c @ 17

Last change on this file since 17 was 17, checked in by landauf, 16 years ago

added openal

File size: 7.5 KB
Line 
1/* -*- mode: C; tab-width:8; c-basic-offset:8 -*-
2 * vi:set ts=8:
3 *
4 * bsd_dsp.c
5 *
6 * functions related to the aquisition and management of /dev/dsp under
7 * bsd.
8 *
9 */
10#include "al_siteconfig.h"
11
12#include <AL/al.h>
13#include <assert.h>
14#include <fcntl.h>
15#include <sys/soundcard.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <sys/ioctl.h>
20#include <sys/mman.h>
21#include <sys/stat.h>
22#include <sys/time.h>
23#include <sys/types.h>
24#include <unistd.h>
25
26#include "backends/alc_backend.h"
27
28/* is this right? */
29#define _AL_DEF_BUFSIZ _ALC_DEF_BUFSIZ
30
31#include "al_main.h"
32#include "al_debug.h"
33#include "alc/alc_context.h"
34
35#ifdef WORDS_BIGENDIAN
36#define AFMT_S16 AFMT_S16_BE
37#else
38#define AFMT_S16 AFMT_S16_LE
39#endif /* WORDS_BIGENDIAN */
40
41static int grab_mixerfd(void);
42static int alcChannel_to_dsp_channel(ALuint alcc);
43
44/* /dev/dsp variables */
45static fd_set dsp_fd_set;
46static int dsp_fd      = -1; /* /dev/dsp file descriptor */
47static int mixer_fd    = -1; /* /dev/mixer file descriptor */
48
49/* convert the format channel from /dev/dsp to openal format */
50static int BSD2ALFMT(int fmt, int channels) {
51        switch(fmt) {
52                case AFMT_U8:
53                        switch(channels)
54                        {
55                                case 1: return AL_FORMAT_MONO8;
56                                case 2: return AL_FORMAT_STEREO8;
57                                default: return -1;
58                        }
59                        break;
60                case AFMT_S16:
61                        switch(channels)
62                        {
63                                case 1: return AL_FORMAT_MONO16;
64                                case 2: return AL_FORMAT_STEREO16;
65                                default: return -1;
66                        }
67                        break;
68                default:
69#ifdef DEBUG_MAXIMUS
70                        fprintf(stderr, "unsupported dsp format\n");
71#endif
72                        return -1;
73                        break;
74        }
75
76        return -1;
77}
78
79/* convert the format channel from openal to /dev/dsp format */
80static int AL2BSDFMT(int fmt)
81{
82        switch(fmt)
83        {
84                case AL_FORMAT_MONO16:
85                case AL_FORMAT_STEREO16:
86                        return AFMT_S16;
87                        break;
88                case AL_FORMAT_MONO8:
89                case AL_FORMAT_STEREO8:
90                        return AFMT_U8;
91                        break;
92                default:
93#ifdef DEBUG_MAXIMUS
94                  fprintf(stderr, "unknown format 0x%x\n", fmt);
95#endif
96                  break;
97        }
98
99        return -1;
100}
101
102/*
103 *
104 *  Format of divisor is bit field where:
105 *
106 *
107 *         MSHW          LSHW
108 *  [ some big value |     x  ]
109 *
110 *  where x is translated into 2^x, and used as the
111 *  dma buffer size.
112 *
113 */
114static void *grab_write_native(void) {
115        const char *dsppath = "/dev/dsp";
116        int divisor = _alSpot(_AL_DEF_BUFSIZ) | (2<<16);
117
118        dsp_fd = open(dsppath, O_WRONLY | O_NONBLOCK);
119
120        if(dsp_fd < 0) {
121                perror("open /dev/dsp");
122                return NULL;
123        }
124
125        if(fcntl(dsp_fd, F_SETFL, ~O_NONBLOCK) == -1) {
126                perror("fcntl");
127        }
128
129        if(ioctl(dsp_fd, SNDCTL_DSP_SETFRAGMENT, &divisor) < 0) {
130                perror("ioctl SETFRAGMENT");
131        }
132
133        FD_ZERO(&dsp_fd_set);
134        FD_SET(dsp_fd, &dsp_fd_set);
135
136        /* now get mixer_fd */
137        mixer_fd = grab_mixerfd();
138
139#ifdef DEBUG
140        fprintf(stderr, "Got /dev/dsp\n");
141#endif
142        return &dsp_fd;
143}
144
145int grab_mixerfd(void) {
146        mixer_fd = open("/dev/mixer", O_WRONLY | O_NONBLOCK);
147
148        if(mixer_fd > 0) {
149                if(fcntl(mixer_fd, F_SETFL, ~O_NONBLOCK) == -1) {
150                        perror("fcntl");
151                }
152
153                return mixer_fd;
154        } else {
155                perror("open /dev/mixer");
156        }
157
158        return -1;
159}
160
161void native_blitbuffer(void *handle, void *dataptr, int bytes_to_write) {
162        struct timeval tv = { 1, 0 }; /* wait 1 sec max */
163        int iterator = 0;
164        int err;
165        int fd;
166
167        if(handle == NULL) {
168                return;
169        }
170
171        fd = *(int *) handle;
172
173        for(iterator = bytes_to_write; iterator > 0; ) {
174                if(select(fd + 1, NULL, &dsp_fd_set, NULL, &tv) == 0) {
175                        /* timeout occured, don't try and write */
176#ifdef DEBUG_MAXIMUS
177                        fprintf(stderr, "native_blitbuffer: timeout occured\n");
178#endif
179                        return;
180                }
181
182                FD_ZERO(&dsp_fd_set);
183                FD_SET(fd, &dsp_fd_set);
184
185                assert(iterator > 0);
186                assert(iterator <= bytes_to_write);
187
188                err = write(fd,
189                            (char *) dataptr + bytes_to_write - iterator,
190                            iterator);
191                if(err < 0) {
192#ifdef DEBUG_MAXIMUS
193                        perror("write");
194#endif
195                        return;
196                }
197
198                iterator -= err;
199        };
200
201        return;
202}
203
204void release_native(void *handle) {
205        int handle_fd;
206
207        if(handle == NULL) {
208                return;
209        }
210
211        handle_fd = *(int *) handle;
212
213        if(ioctl(handle_fd, SNDCTL_DSP_RESET) < 0) {
214#ifdef DEBUG_MAXIMUS
215                fprintf(stderr, "Couldn't reset dsp\n");
216#endif
217        }
218
219        ioctl(handle_fd, SNDCTL_DSP_SYNC, NULL);
220        if((close(handle_fd) < 0) || (close(mixer_fd) < 0)) {
221                return;
222        }
223
224        *(int *) handle = -1;
225        mixer_fd        = -1;
226
227        return;
228}
229
230ALfloat get_nativechannel(UNUSED(void *handle), ALuint channel) {
231        int retval = 0;
232
233        channel = alcChannel_to_dsp_channel(channel);
234
235        if(ioctl(mixer_fd, MIXER_READ(channel), &retval) < 0) {
236                return -1;
237        }
238
239        return (retval >> 8) / 100.0;
240}
241
242
243/*
244 * Okay:
245 *
246 * Set audio channel expects an integer, in the range of
247 * 0 - 100.  But wait!  It expects the integer to be
248 * partitioned into a 16bit empty, L/R channel pair (high bits left,
249 * low bits right), each 8 bit pair in the range 0 - 100.
250 *
251 * Kludgey, and obviously not the right way to do this
252 */
253int set_nativechannel(UNUSED(void *handle), ALuint channel, ALfloat volume) {
254        int unnormalizedvolume;
255
256        unnormalizedvolume = volume * 100;
257        unnormalizedvolume <<= 8;
258        unnormalizedvolume += (volume * 100);
259
260        channel = alcChannel_to_dsp_channel(channel);
261
262        if(ioctl(mixer_fd, MIXER_WRITE(channel), &unnormalizedvolume) < 0) {
263                return -1;
264        }
265
266        return 0;
267}
268
269/* convert the mixer channel from ALC to /dev/mixer format */
270static int alcChannel_to_dsp_channel(ALuint alcc) {
271        switch(alcc) {
272                case ALC_CHAN_MAIN_LOKI: return SOUND_MIXER_VOLUME;
273                case ALC_CHAN_CD_LOKI:   return SOUND_MIXER_CD;
274                case ALC_CHAN_PCM_LOKI:  return SOUND_MIXER_PCM;
275                default: return -1;
276        }
277
278        return -1;
279}
280
281void pause_nativedevice(void *handle) {
282        int fd;
283
284        if(handle == NULL) {
285                return;
286        }
287
288        fd = *(int *) handle;
289
290        if(ioctl(fd, SNDCTL_DSP_POST, 0) == -1) {
291                perror("ioctl");
292        }
293
294        return;
295}
296
297void resume_nativedevice(void *handle) {
298        int fd;
299
300        if(handle == NULL) {
301                return;
302        }
303
304        fd = *(int *) handle;
305
306        if(ioctl(fd, SNDCTL_DSP_POST, 0) == -1) {
307                perror("ioctl");
308        }
309
310        return;
311}
312
313ALsizei capture_nativedevice(UNUSED(void *handle),
314                          UNUSED(void *capture_buffer),
315                          UNUSED(int bufsiz)) {
316        /* unimplemented */
317        return 0;
318}
319
320static ALboolean set_write_native(UNUSED(void *handle),
321                                  UNUSED(unsigned int *bufsiz),
322                                  ALenum *fmt,
323                                  unsigned int *speed) {
324        ALuint channels = _alGetChannelsFromFormat(*fmt);
325
326        if(dsp_fd < 0) {
327                return AL_FALSE;
328        }
329
330        *fmt  = AL2BSDFMT(*fmt);
331
332        /* reset card defaults */
333        if(ioctl(dsp_fd, SNDCTL_DSP_RESET, NULL) < 0) {
334#ifdef DEBUG_MAXIMUS
335                perror("set_devsp reset ioctl");
336#endif
337                return AL_FALSE;
338        }
339
340        if(ioctl(dsp_fd, SNDCTL_DSP_SPEED, speed) < 0) {
341#ifdef DEBUG_MAXIMUS
342                fprintf(stderr, "speed %d\n", *speed);
343                perror("set_devsp speed ioctl");
344#endif
345                return AL_FALSE;
346        }
347
348        if(ioctl(dsp_fd, SNDCTL_DSP_SETFMT, fmt) < 0) {
349#ifdef DEBUG_MAXIMUS
350                fprintf(stderr, "fmt %d\n", *fmt);
351                perror("set_devsp format ioctl");
352#endif
353                return AL_FALSE;
354        }
355
356        if(ioctl(dsp_fd, SOUND_PCM_WRITE_CHANNELS, &channels)) {
357#ifdef DEBUG_MAXIMUS
358                fprintf(stderr, "channels %d\n", channels);
359                perror("set_devsp channels ioctl");
360#endif
361                return AL_FALSE;
362        }
363
364
365        *fmt = BSD2ALFMT(*fmt, channels);
366
367        return AL_TRUE;
368}
369
370static ALboolean set_read_native(UNUSED(void *handle),
371                                 UNUSED(unsigned int *bufsiz),
372                                 UNUSED(ALenum *fmt),
373                                 UNUSED(unsigned int *speed)) {
374        return AL_FALSE;
375}
376
377ALboolean
378alcBackendSetAttributesNative_(ALC_OpenMode mode, void *handle, ALuint *bufsiz, ALenum *fmt, ALuint *speed)
379{
380        return mode == ALC_OPEN_INPUT_ ?
381                set_read_native(handle, bufsiz, fmt, speed) :
382                set_write_native(handle, bufsiz, fmt, speed);
383}
384
385static void *grab_read_native(void)
386{
387        fprintf(stderr,"grab_read_native Not implemented! (%s:%d)\n",__FILE__,__LINE__);
388        return;
389}
390
391void *
392alcBackendOpenNative_( ALC_OpenMode mode )
393{
394        return mode == ALC_OPEN_INPUT_ ? grab_read_native() : grab_write_native();
395}
Note: See TracBrowser for help on using the repository browser.