Small clean up to http_open()
[cmus.git] / oss.c
blob6fab1d4e3a96680c27c2b83abe5ccd2989cc2d01
1 /*
2 * Copyright 2004-2005 Timo Hirvonen
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17 * 02111-1307, USA.
20 #include "op.h"
21 #include "sf.h"
22 #include "xmalloc.h"
23 #include "debug.h"
25 #if defined(__OpenBSD__)
26 #include <soundcard.h>
27 #else
28 #include <sys/soundcard.h>
29 #endif
30 #include <sys/ioctl.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <unistd.h>
34 #include <fcntl.h>
36 static sample_format_t oss_sf;
37 static int oss_fd = -1;
39 /* configuration */
40 static char *oss_dsp_device = NULL;
42 static int oss_close(void);
44 static int oss_reset(void)
46 if (fcntl(oss_fd, SNDCTL_DSP_RESET, 0) == -1) {
47 return -1;
49 return 0;
52 static int oss_set_sf(sample_format_t sf)
54 int tmp, log2_fragment_size, nr_fragments, bytes_per_second;
56 oss_reset();
57 oss_sf = sf;
58 tmp = sf_get_channels(oss_sf) - 1;
59 if (ioctl(oss_fd, SNDCTL_DSP_STEREO, &tmp) == -1) {
60 d_print("SNDCTL_DSP_STEREO failed: %s\n", strerror(errno));
61 return -1;
63 if (sf_get_bits(oss_sf) == 16) {
64 if (sf_get_signed(oss_sf)) {
65 if (sf_get_bigendian(oss_sf)) {
66 tmp = AFMT_S16_BE;
67 } else {
68 tmp = AFMT_S16_LE;
70 } else {
71 if (sf_get_bigendian(oss_sf)) {
72 tmp = AFMT_U16_BE;
73 } else {
74 tmp = AFMT_U16_LE;
77 } else if (sf_get_bits(oss_sf) == 8) {
78 if (sf_get_signed(oss_sf)) {
79 tmp = AFMT_S8;
80 } else {
81 tmp = AFMT_U8;
83 } else {
84 d_print("bits is neither 8 nor 16\n");
85 return -1;
87 if (ioctl(oss_fd, SNDCTL_DSP_SAMPLESIZE, &tmp) == -1) {
88 d_print("SNDCTL_DSP_SAMPLESIZE failed: %s\n", strerror(errno));
89 return -1;
91 tmp = sf_get_rate(oss_sf);
92 if (ioctl(oss_fd, SNDCTL_DSP_SPEED, &tmp) == -1) {
93 d_print("SNDCTL_DSP_SPEED failed: %s\n", strerror(errno));
94 return -1;
96 #if 1
97 bytes_per_second = sf_get_second_size(oss_sf);
98 log2_fragment_size = 0;
99 while (1 << log2_fragment_size < bytes_per_second / 25)
100 log2_fragment_size++;
101 log2_fragment_size--;
102 nr_fragments = 32;
103 /* device_buffer_size = (1 << log2_fragment_size) * (nr_fragments + 1); */
104 /* bits 0..15 = size of fragment, 16..31 = log2(number of fragments) */
105 tmp = (nr_fragments << 16) + log2_fragment_size;
106 d_print("fragment: %d\n", tmp);
107 if (ioctl(oss_fd, SNDCTL_DSP_SETFRAGMENT, &tmp) == -1) {
108 d_print("fragment: %d\n", tmp);
109 d_print("SNDCTL_DSP_SETFRAGMENT failed: %s\n", strerror(errno));
110 return -1;
112 #endif
113 return 0;
116 static int oss_device_exists(const char *device)
118 struct stat s;
120 if (stat(device, &s) == 0) {
121 d_print("device %s exists\n", device);
122 return 1;
124 d_print("device %s does not exist\n", device);
125 return 0;
128 static int oss_init(void)
130 const char *new_dsp_dev = "/dev/sound/dsp";
131 const char *dsp_dev = "/dev/dsp";
133 if (oss_dsp_device) {
134 if (oss_device_exists(oss_dsp_device))
135 return 0;
136 free(oss_dsp_device);
137 oss_dsp_device = NULL;
138 return -1;
140 if (oss_device_exists(new_dsp_dev)) {
141 oss_dsp_device = xstrdup(new_dsp_dev);
142 return 0;
144 if (oss_device_exists(dsp_dev)) {
145 oss_dsp_device = xstrdup(dsp_dev);
146 return 0;
148 return -1;
151 static int oss_exit(void)
153 free(oss_dsp_device);
154 oss_dsp_device = NULL;
155 return 0;
158 static int oss_open(sample_format_t sf)
160 oss_fd = open(oss_dsp_device, O_WRONLY);
161 if (oss_fd == -1)
162 return -1;
163 if (oss_set_sf(sf) == -1) {
164 oss_close();
165 return -1;
167 return 0;
170 static int oss_close(void)
172 close(oss_fd);
173 oss_fd = -1;
174 return 0;
177 static int oss_write(const char *buffer, int count)
179 int rc;
181 count /= 4;
182 count *= 4;
183 rc = write(oss_fd, buffer, count);
184 return rc;
187 static int oss_pause(void)
189 if (ioctl(oss_fd, SNDCTL_DSP_POST, NULL) == -1)
190 return -1;
191 return 0;
194 static int oss_unpause(void)
196 return 0;
199 static int oss_buffer_space(void)
201 audio_buf_info info;
202 int space;
204 if (ioctl(oss_fd, SNDCTL_DSP_GETOSPACE, &info) == -1)
205 return -1;
206 space = info.bytes;
207 /* d_print("%d\n", space); */
208 return space;
211 static int op_oss_set_option(int key, const char *val)
213 switch (key) {
214 case 0:
215 free(oss_dsp_device);
216 oss_dsp_device = xstrdup(val);
217 break;
218 default:
219 return -OP_ERROR_NOT_OPTION;
221 return 0;
224 static int op_oss_get_option(int key, char **val)
226 switch (key) {
227 case 0:
228 if (oss_dsp_device)
229 *val = xstrdup(oss_dsp_device);
230 break;
231 default:
232 return -OP_ERROR_NOT_OPTION;
234 return 0;
237 const struct output_plugin_ops op_pcm_ops = {
238 .init = oss_init,
239 .exit = oss_exit,
240 .open = oss_open,
241 .close = oss_close,
242 .write = oss_write,
243 .pause = oss_pause,
244 .unpause = oss_unpause,
245 .buffer_space = oss_buffer_space,
246 .set_option = op_oss_set_option,
247 .get_option = op_oss_get_option
250 const char * const op_pcm_options[] = {
251 "device",
252 NULL
255 const int op_priority = 1;