Commit | Line | Data |
---|---|---|
e99d42b1 | 1 | /* |
2 | * This file is part of DisOrder | |
a35bb7cc | 3 | * Copyright (C) 2007, 2008 Richard Kettlewell |
313acc77 | 4 | * Portions copyright (C) 2007 Ross Younger |
e99d42b1 | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 2 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, but | |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, write to the Free Software | |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | |
19 | * USA | |
20 | */ | |
21 | /** @file server/speaker-oss.c | |
22 | * @brief Support for @ref BACKEND_OSS */ | |
23 | ||
05b75f8d | 24 | #include "common.h" |
e99d42b1 | 25 | |
26 | #if HAVE_SYS_SOUNDCARD_H | |
27 | ||
e99d42b1 | 28 | #include <unistd.h> |
29 | #include <poll.h> | |
e99d42b1 | 30 | #include <fcntl.h> |
31 | #include <unistd.h> | |
32 | #include <errno.h> | |
33 | #include <sys/ioctl.h> | |
34 | #include <sys/soundcard.h> | |
35 | ||
36 | #include "configuration.h" | |
37 | #include "syscalls.h" | |
38 | #include "log.h" | |
39 | #include "speaker-protocol.h" | |
40 | #include "speaker.h" | |
41 | ||
42 | /** @brief Current device */ | |
43 | static int ossfd = -1; | |
44 | ||
45 | /** @brief OSS backend initialization */ | |
46 | static void oss_init(void) { | |
47 | info("selected OSS backend"); | |
48 | } | |
49 | ||
50 | /** @brief OSS deactivation */ | |
51 | static void oss_deactivate(void) { | |
52 | if(ossfd != -1) { | |
53 | xclose(ossfd); | |
54 | ossfd = -1; | |
55 | device_state = device_closed; | |
56 | D(("released audio device")); | |
57 | } | |
58 | } | |
59 | ||
60 | /** @brief OSS backend activation */ | |
61 | static void oss_activate(void) { | |
62 | int stereo, format, rate; | |
63 | const char *device; | |
64 | ||
65 | if(ossfd == -1) { | |
66 | /* Try to pick a device */ | |
67 | if(!strcmp(config->device, "default")) { | |
68 | if(access("/dev/dsp", W_OK) == 0) | |
69 | device = "/dev/dsp"; | |
70 | else if(access("/dev/audio", W_OK) == 0) | |
71 | device = "/dev/audio"; | |
c62ae947 | 72 | else { |
a35bb7cc RK |
73 | static int reported; |
74 | ||
75 | if(!reported) { | |
76 | error(0, "cannot determine default OSS device"); | |
77 | reported = 1; | |
78 | } | |
c62ae947 RK |
79 | goto failed; |
80 | } | |
e99d42b1 | 81 | } else |
82 | device = config->device; /* just believe the user */ | |
83 | /* Open the device */ | |
84 | if((ossfd = open(device, O_WRONLY, 0)) < 0) { | |
85 | error(errno, "error opening %s", device); | |
86 | goto failed; | |
87 | } | |
88 | /* Set the audio format */ | |
89 | stereo = (config->sample_format.channels == 2); | |
90 | if(ioctl(ossfd, SNDCTL_DSP_STEREO, &stereo) < 0) { | |
91 | error(errno, "error calling ioctl SNDCTL_DSP_STEREO %d", stereo); | |
92 | goto failed; | |
93 | } | |
94 | if(config->sample_format.bits == 8) | |
95 | format = AFMT_U8; | |
96 | else if(config->sample_format.bits == 16) | |
97 | format = (config->sample_format.endian == ENDIAN_LITTLE | |
98 | ? AFMT_S16_LE : AFMT_S16_BE); | |
99 | else { | |
100 | error(0, "unsupported sample_format for oss backend"); | |
101 | goto failed; | |
102 | } | |
103 | if(ioctl(ossfd, SNDCTL_DSP_SETFMT, &format) < 0) { | |
104 | error(errno, "error calling ioctl SNDCTL_DSP_SETFMT %#x", format); | |
105 | goto failed; | |
106 | } | |
107 | rate = config->sample_format.rate; | |
108 | if(ioctl(ossfd, SNDCTL_DSP_SPEED, &rate) < 0) { | |
109 | error(errno, "error calling ioctl SNDCTL_DSP_SPEED %d", rate); | |
110 | goto failed; | |
111 | } | |
112 | if((unsigned)rate != config->sample_format.rate) | |
113 | error(0, "asked for %luHz, got %dHz", | |
114 | (unsigned long)config->sample_format.rate, rate); | |
115 | nonblock(ossfd); | |
116 | device_state = device_open; | |
117 | } | |
118 | return; | |
119 | failed: | |
120 | device_state = device_error; | |
c62ae947 | 121 | if(ossfd >= 0) { |
e99d42b1 | 122 | xclose(ossfd); |
c62ae947 RK |
123 | ossfd = -1; |
124 | } | |
e99d42b1 | 125 | } |
126 | ||
127 | /** @brief Play via OSS */ | |
128 | static size_t oss_play(size_t frames) { | |
129 | const size_t bytes_to_play = frames * bpf; | |
130 | ssize_t bytes_written; | |
131 | ||
132 | bytes_written = write(ossfd, playing->buffer + playing->start, | |
133 | bytes_to_play); | |
134 | if(bytes_written < 0) | |
135 | switch(errno) { | |
136 | case EINTR: /* interruped */ | |
137 | case EAGAIN: /* overrun */ | |
138 | return 0; /* try again later */ | |
139 | default: | |
140 | fatal(errno, "error writing to audio device"); | |
141 | } | |
142 | return bytes_written / bpf; | |
143 | } | |
144 | ||
145 | static int oss_slot; | |
146 | ||
147 | /** @brief Fill in poll fd array for OSS */ | |
e84fb5f0 | 148 | static void oss_beforepoll(int attribute((unused)) *timeoutp) { |
e99d42b1 | 149 | oss_slot = addfd(ossfd, POLLOUT|POLLERR); |
150 | } | |
151 | ||
152 | /** @brief Process poll() results for OSS */ | |
153 | static int oss_ready(void) { | |
154 | return !!(fds[oss_slot].revents & (POLLOUT|POLLERR)); | |
155 | } | |
156 | ||
157 | const struct speaker_backend oss_backend = { | |
158 | BACKEND_OSS, | |
159 | 0, | |
160 | oss_init, | |
161 | oss_activate, | |
162 | oss_play, | |
163 | oss_deactivate, | |
164 | oss_beforepoll, | |
165 | oss_ready | |
166 | }; | |
167 | ||
168 | #endif | |
169 | ||
170 | /* | |
171 | Local Variables: | |
172 | c-basic-offset:2 | |
173 | comment-column:40 | |
174 | fill-column:79 | |
175 | indent-tabs-mode:nil | |
176 | End: | |
177 | */ |