chiark / gitweb /
Abolish uaudio_apis[]. Instead, define UAUDIO_DEFAULT to indicate
[disorder] / lib / uaudio-oss.c
1 /*
2  * This file is part of DisOrder.
3  * Copyright (C) 2009 Richard Kettlewell
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * 
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 /** @file lib/uaudio-oss.c
19  * @brief Support for OSS backend */
20 #include "common.h"
21
22 #if HAVE_SYS_SOUNDCARD_H || EMPEG_HOST
23
24 #if HAVE_SYS_SOUNDCARD_H
25 # include <sys/soundcard.h>
26 #endif
27 #include <sys/ioctl.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <errno.h>
31
32 #include "mem.h"
33 #include "log.h"
34 #include "uaudio.h"
35
36 #ifndef AFMT_U16_NE
37 # if BYTE_ORDER == BIG_ENDIAN
38 #  define AFMT_U16_NE AFMT_U16_BE
39 # else
40 #  define AFMT_U16_NE AFMT_U16_LE
41 # endif
42 #endif
43
44 static int oss_fd = -1;
45
46 static const char *const oss_options[] = {
47   "device",
48   NULL
49 };
50
51 /** @brief Actually play sound via OSS */
52 static size_t oss_play(void *buffer, size_t samples) {
53   const size_t bytes = samples * uaudio_sample_size;
54   int rc = write(oss_fd, buffer, bytes);
55   if(rc < 0)
56     fatal(errno, "error writing to sound device");
57   return rc / uaudio_sample_size;
58 }
59
60 /** @brief Open the OSS sound device */
61 static void oss_open(void) {
62   const char *device = uaudio_get("device");
63
64 #if EMPEG_HOST
65   if(!device || !*device || !strcmp(device, "default"))
66     device "/dev/audio";
67 #else
68   if(!device || !*device || !strcmp(device, "default")) {
69     if(access("/dev/dsp", W_OK) == 0)
70       device = "/dev/dsp";
71     else
72       device = "/dev/audio";
73   }
74 #endif
75   if((oss_fd = open(device, O_WRONLY, 0)) < 0)
76     fatal(errno, "error opening %s", device);
77 #if !EMPEG_HOST
78   int stereo = (uaudio_channels == 2), format;
79   if(ioctl(oss_fd, SNDCTL_DSP_STEREO, &stereo) < 0)
80     fatal(errno, "error calling ioctl SNDCTL_DSP_STEREO %d", stereo);
81   if(uaudio_bits == 16)
82     format = uaudio_signed ? AFMT_S16_NE : AFMT_U16_NE;
83   else
84     format = uaudio_signed ? AFMT_S8 : AFMT_U8;
85   if(ioctl(oss_fd, SNDCTL_DSP_SETFMT, &format) < 0)
86     fatal(errno, "error calling ioctl SNDCTL_DSP_SETFMT %#x", format);
87   int rate = uaudio_rate;
88   if(ioctl(oss_fd, SNDCTL_DSP_SPEED, &rate) < 0)
89     fatal(errno, "error calling ioctl SNDCTL_DSP_SPEED %d", rate);
90   if(rate != uaudio_rate)
91     error(0, "asked for %dHz, got %dHz", uaudio_rate, rate);
92 #endif
93 }
94
95 static void oss_activate(void) {
96   oss_open();
97   uaudio_thread_activate();
98 }
99
100 static void oss_deactivate(void) {
101   uaudio_thread_deactivate();
102   close(oss_fd);
103   oss_fd = -1;
104 }
105   
106 static void oss_start(uaudio_callback *callback,
107                       void *userdata) {
108   if(uaudio_channels != 1 && uaudio_channels != 2)
109     fatal(0, "asked for %d channels but only support 1 or 2",
110           uaudio_channels); 
111   if(uaudio_bits != 8 && uaudio_bits != 16)
112     fatal(0, "asked for %d bits/channel but only support 8 or 16",
113           uaudio_bits); 
114 #if EMPEG_HOST
115   /* Very specific buffer size requirements here apparently */
116   uaudio_thread_start(callback, userdata, oss_play, 
117                       4608 / uaudio_sample_size,
118                       4608 / uaudio_sample_size);
119 #else
120   /* We could SNDCTL_DSP_GETBLKSIZE but only when the device is already open,
121    * which is kind of inconvenient.  We go with 1-4Kbyte for now. */
122   uaudio_thread_start(callback, userdata, oss_play, 
123                       32 / uaudio_sample_size,
124                       4096 / uaudio_sample_size);
125 #endif
126 }
127
128 static void oss_stop(void) {
129   uaudio_thread_stop();
130 }
131
132 const struct uaudio uaudio_oss = {
133   .name = "oss",
134   .options = oss_options,
135   .start = oss_start,
136   .stop = oss_stop,
137   .activate = oss_activate,
138   .deactivate = oss_deactivate
139 };
140
141 #endif
142
143 /*
144 Local Variables:
145 c-basic-offset:2
146 comment-column:40
147 fill-column:79
148 indent-tabs-mode:nil
149 End:
150 */