/[rdesktop]/sourceforge.net/trunk/rdesktop/rdpsnd_oss.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /sourceforge.net/trunk/rdesktop/rdpsnd_oss.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1256 - (show annotations)
Sun Sep 17 11:42:22 2006 UTC (17 years, 7 months ago) by stargo
File MIME type: text/plain
File size: 5931 byte(s)
fix SunCC errors/warnings and configure-variable-usage (LIBS/LDFLAGS)

1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Sound Channel Process Functions - Open Sound System
4 Copyright (C) Matthew Chapman 2003
5 Copyright (C) GuoJunBo guojunbo@ict.ac.cn 2003
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 /*
23 This is a workaround for Esound bug 312665.
24 FIXME: Remove this when Esound is fixed.
25 */
26 #ifdef _FILE_OFFSET_BITS
27 #undef _FILE_OFFSET_BITS
28 #endif
29
30 #include "rdesktop.h"
31 #include "rdpsnd.h"
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <sys/time.h>
36 #include <sys/ioctl.h>
37 #include <sys/soundcard.h>
38
39 #define DEFAULTDEVICE "/dev/dsp"
40 #define MAX_LEN 512
41
42 static int snd_rate;
43 static short samplewidth;
44 static char *dsp_dev;
45
46 BOOL
47 oss_open(void)
48 {
49 if ((g_dsp_fd = open(dsp_dev, O_WRONLY)) == -1)
50 {
51 perror(dsp_dev);
52 return False;
53 }
54
55 return True;
56 }
57
58 void
59 oss_close(void)
60 {
61 close(g_dsp_fd);
62 }
63
64 BOOL
65 oss_format_supported(WAVEFORMATEX * pwfx)
66 {
67 if (pwfx->wFormatTag != WAVE_FORMAT_PCM)
68 return False;
69 if ((pwfx->nChannels != 1) && (pwfx->nChannels != 2))
70 return False;
71 if ((pwfx->wBitsPerSample != 8) && (pwfx->wBitsPerSample != 16))
72 return False;
73
74 return True;
75 }
76
77 BOOL
78 oss_set_format(WAVEFORMATEX * pwfx)
79 {
80 int stereo, format, fragments;
81 static BOOL driver_broken = False;
82
83 ioctl(g_dsp_fd, SNDCTL_DSP_RESET, NULL);
84 ioctl(g_dsp_fd, SNDCTL_DSP_SYNC, NULL);
85
86 if (pwfx->wBitsPerSample == 8)
87 format = AFMT_U8;
88 else if (pwfx->wBitsPerSample == 16)
89 format = AFMT_S16_LE;
90
91 samplewidth = pwfx->wBitsPerSample / 8;
92
93 if (ioctl(g_dsp_fd, SNDCTL_DSP_SETFMT, &format) == -1)
94 {
95 perror("SNDCTL_DSP_SETFMT");
96 close(g_dsp_fd);
97 return False;
98 }
99
100 if (pwfx->nChannels == 2)
101 {
102 stereo = 1;
103 samplewidth *= 2;
104 }
105 else
106 {
107 stereo = 0;
108 }
109
110 if (ioctl(g_dsp_fd, SNDCTL_DSP_STEREO, &stereo) == -1)
111 {
112 perror("SNDCTL_DSP_CHANNELS");
113 close(g_dsp_fd);
114 return False;
115 }
116
117 snd_rate = pwfx->nSamplesPerSec;
118 if (ioctl(g_dsp_fd, SNDCTL_DSP_SPEED, &snd_rate) == -1)
119 {
120 perror("SNDCTL_DSP_SPEED");
121 close(g_dsp_fd);
122 return False;
123 }
124
125 /* try to get 12 fragments of 2^12 bytes size */
126 fragments = (12 << 16) + 12;
127 ioctl(g_dsp_fd, SNDCTL_DSP_SETFRAGMENT, &fragments);
128
129 if (!driver_broken)
130 {
131 audio_buf_info info;
132
133 memset(&info, 0, sizeof(info));
134 if (ioctl(g_dsp_fd, SNDCTL_DSP_GETOSPACE, &info) == -1)
135 {
136 perror("SNDCTL_DSP_GETOSPACE");
137 close(g_dsp_fd);
138 return False;
139 }
140
141 if (info.fragments == 0 || info.fragstotal == 0 || info.fragsize == 0)
142 {
143 fprintf(stderr,
144 "Broken OSS-driver detected: fragments: %d, fragstotal: %d, fragsize: %d\n",
145 info.fragments, info.fragstotal, info.fragsize);
146 driver_broken = True;
147 }
148 }
149
150 return True;
151 }
152
153 void
154 oss_volume(uint16 left, uint16 right)
155 {
156 static BOOL use_dev_mixer = False;
157 uint32 volume;
158 int fd_mix = -1;
159
160 volume = left / (65536 / 100);
161 volume |= right / (65536 / 100) << 8;
162
163 if (use_dev_mixer)
164 {
165 if ((fd_mix = open("/dev/mixer", O_RDWR | O_NONBLOCK)) == -1)
166 {
167 perror("open /dev/mixer");
168 return;
169 }
170
171 if (ioctl(fd_mix, MIXER_WRITE(SOUND_MIXER_PCM), &volume) == -1)
172 {
173 perror("MIXER_WRITE(SOUND_MIXER_PCM)");
174 return;
175 }
176
177 close(fd_mix);
178 }
179
180 if (ioctl(g_dsp_fd, MIXER_WRITE(SOUND_MIXER_PCM), &volume) == -1)
181 {
182 perror("MIXER_WRITE(SOUND_MIXER_PCM)");
183 use_dev_mixer = True;
184 return;
185 }
186 }
187
188 void
189 oss_play(void)
190 {
191 struct audio_packet *packet;
192 ssize_t len;
193 STREAM out;
194 static long startedat_us;
195 static long startedat_s;
196 static BOOL started = False;
197 struct timeval tv;
198
199 if (rdpsnd_queue_empty())
200 {
201 g_dsp_busy = 0;
202 return;
203 }
204
205 packet = rdpsnd_queue_current_packet();
206 out = &packet->s;
207
208 if (!started)
209 {
210 gettimeofday(&tv, NULL);
211 startedat_us = tv.tv_usec;
212 startedat_s = tv.tv_sec;
213 started = True;
214 }
215
216 len = out->end - out->p;
217
218 len = write(g_dsp_fd, out->p, (len > MAX_LEN) ? MAX_LEN : len);
219 if (len == -1)
220 {
221 if (errno != EWOULDBLOCK)
222 perror("write audio");
223 g_dsp_busy = 1;
224 return;
225 }
226
227 out->p += len;
228 if (out->p == out->end)
229 {
230 long long duration;
231 long elapsed;
232
233 gettimeofday(&tv, NULL);
234 duration = (out->size * (1000000 / (samplewidth * snd_rate)));
235 elapsed = (tv.tv_sec - startedat_s) * 1000000 + (tv.tv_usec - startedat_us);
236
237 if (elapsed >= (duration * 85) / 100)
238 {
239 /* We need to add 50 to tell windows that time has passed while
240 * playing this packet */
241 rdpsnd_send_completion(packet->tick + 50, packet->index);
242 rdpsnd_queue_next();
243 started = False;
244 }
245 else
246 {
247 g_dsp_busy = 1;
248 return;
249 }
250 }
251 g_dsp_busy = 1;
252 return;
253 }
254
255 struct audio_driver *
256 oss_register(char *options)
257 {
258 static struct audio_driver oss_driver;
259
260 oss_driver.wave_out_write = rdpsnd_queue_write;
261 oss_driver.wave_out_open = oss_open;
262 oss_driver.wave_out_close = oss_close;
263 oss_driver.wave_out_format_supported = oss_format_supported;
264 oss_driver.wave_out_set_format = oss_set_format;
265 oss_driver.wave_out_volume = oss_volume;
266 oss_driver.wave_out_play = oss_play;
267 oss_driver.name = xstrdup("oss");
268 oss_driver.description =
269 xstrdup("OSS output driver, default device: " DEFAULTDEVICE " or $AUDIODEV");
270 oss_driver.next = NULL;
271
272 if (options)
273 {
274 dsp_dev = xstrdup(options);
275 }
276 else
277 {
278 dsp_dev = getenv("AUDIODEV");
279
280 if (dsp_dev == NULL)
281 {
282 dsp_dev = xstrdup(DEFAULTDEVICE);
283 }
284 }
285
286 return &oss_driver;
287 }

  ViewVC Help
Powered by ViewVC 1.1.26