/[rdesktop]/sourceforge.net/trunk/rdesktop/rdpsnd_sun.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_sun.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1428 - (show annotations)
Tue Jan 22 10:42:55 2008 UTC (16 years, 4 months ago) by ossman_
File MIME type: text/plain
File size: 8011 byte(s)
Record support for Sun audio backend. Also do some general improvements and
get it more in line with the OSS backend.

1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Sound Channel Process Functions - Sun
4 Copyright (C) Matthew Chapman 2003-2007
5 Copyright (C) GuoJunBo guojunbo@ict.ac.cn 2003
6 Copyright (C) Michael Gernoth mike@zerfleddert.de 2003-2007
7 Copyright 2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "rdesktop.h"
25 #include "rdpsnd.h"
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <errno.h>
29 #include <sys/ioctl.h>
30 #include <sys/audioio.h>
31
32 #if (defined(sun) && (defined(__svr4__) || defined(__SVR4)))
33 #include <stropts.h>
34 #endif
35
36 #define DEFAULTDEVICE "/dev/audio"
37 #define MAX_LEN 512
38
39 static int dsp_fd = -1;
40 static int dsp_mode;
41 static int dsp_refs;
42
43 static RD_BOOL dsp_configured;
44 static RD_BOOL dsp_broken;
45
46 static RD_BOOL dsp_out;
47 static RD_BOOL dsp_in;
48
49 static int stereo;
50 static int format;
51 static uint32 snd_rate;
52 static short samplewidth;
53 static char *dsp_dev;
54
55 static uint_t written_samples;
56
57 void sun_play(void);
58 void sun_record(void);
59
60 void
61 sun_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv)
62 {
63 if (dsp_fd == -1)
64 return;
65
66 if (dsp_out && !rdpsnd_queue_empty())
67 FD_SET(dsp_fd, wfds);
68 if (dsp_in)
69 FD_SET(dsp_fd, rfds);
70 if (dsp_fd > *n)
71 *n = dsp_fd;
72 }
73
74 void
75 sun_check_fds(fd_set * rfds, fd_set * wfds)
76 {
77 if (FD_ISSET(dsp_fd, wfds))
78 sun_play();
79 if (FD_ISSET(dsp_fd, rfds))
80 sun_record();
81 }
82
83 RD_BOOL
84 sun_open(int mode)
85 {
86 audio_info_t info;
87
88 if (dsp_fd != -1)
89 {
90 dsp_refs++;
91
92 if (dsp_mode == O_RDWR)
93 return True;
94
95 if (dsp_mode == mode)
96 return True;
97
98 dsp_refs--;
99 return False;
100 }
101
102 dsp_configured = False;
103 dsp_broken = False;
104
105 written_samples = 0;
106
107 dsp_mode = O_RDWR;
108 dsp_fd = open(dsp_dev, O_RDWR | O_NONBLOCK);
109 if (dsp_fd != -1)
110 {
111 AUDIO_INITINFO(&info);
112
113 if ((ioctl(dsp_fd, AUDIO_GETINFO, &info) == -1)
114 || !(info.hw_features & AUDIO_HWFEATURE_DUPLEX))
115 {
116 close(dsp_fd);
117 dsp_fd = -1;
118 }
119 }
120
121 if (dsp_fd == -1)
122 {
123 dsp_mode = mode;
124
125 dsp_fd = open(dsp_dev, dsp_mode | O_NONBLOCK);
126 if (dsp_fd == -1)
127 {
128 perror(dsp_dev);
129 return False;
130 }
131 }
132
133 dsp_refs++;
134
135 return True;
136 }
137
138 void
139 sun_close(void)
140 {
141 dsp_refs--;
142
143 if (dsp_refs != 0)
144 return;
145
146 close(dsp_fd);
147 dsp_fd = -1;
148 }
149
150 RD_BOOL
151 sun_open_out(void)
152 {
153 if (!sun_open(O_WRONLY))
154 return False;
155
156 dsp_out = True;
157
158 return True;
159 }
160
161 void
162 sun_close_out(void)
163 {
164 #if defined I_FLUSH && defined FLUSHW
165 /* Flush the audiobuffer */
166 ioctl(dsp_fd, I_FLUSH, FLUSHW);
167 #endif
168 #if defined AUDIO_FLUSH
169 ioctl(dsp_fd, AUDIO_FLUSH, NULL);
170 #endif
171
172 sun_close();
173
174 /* Ack all remaining packets */
175 while (!rdpsnd_queue_empty())
176 rdpsnd_queue_next(0);
177
178 dsp_out = False;
179 }
180
181 RD_BOOL
182 sun_open_in(void)
183 {
184 if (!sun_open(O_RDONLY))
185 return False;
186
187 dsp_in = True;
188
189 return True;
190 }
191
192 void
193 sun_close_in(void)
194 {
195 sun_close();
196
197 dsp_in = False;
198 }
199
200 RD_BOOL
201 sun_format_supported(RD_WAVEFORMATEX * pwfx)
202 {
203 if (pwfx->wFormatTag != WAVE_FORMAT_PCM)
204 return False;
205 if ((pwfx->nChannels != 1) && (pwfx->nChannels != 2))
206 return False;
207 if ((pwfx->wBitsPerSample != 8) && (pwfx->wBitsPerSample != 16))
208 return False;
209
210 return True;
211 }
212
213 RD_BOOL
214 sun_set_format(RD_WAVEFORMATEX * pwfx)
215 {
216 audio_info_t info;
217
218 ioctl(dsp_fd, AUDIO_DRAIN, 0);
219 AUDIO_INITINFO(&info);
220
221 if (dsp_configured)
222 {
223 if ((pwfx->wBitsPerSample == 8) && (format != AUDIO_ENCODING_LINEAR8))
224 return False;
225 if ((pwfx->wBitsPerSample == 16) && (format != AUDIO_ENCODING_LINEAR))
226 return False;
227
228 if ((pwfx->nChannels == 2) != !!stereo)
229 return False;
230
231 if (pwfx->nSamplesPerSec != snd_rate)
232 return False;
233
234 return True;
235 }
236
237 if (pwfx->wBitsPerSample == 8)
238 {
239 info.play.encoding = AUDIO_ENCODING_LINEAR8;
240 }
241 else if (pwfx->wBitsPerSample == 16)
242 {
243 info.play.encoding = AUDIO_ENCODING_LINEAR;
244 }
245
246 samplewidth = pwfx->wBitsPerSample / 8;
247
248 if (pwfx->nChannels == 1)
249 {
250 info.play.channels = 1;
251 }
252 else if (pwfx->nChannels == 2)
253 {
254 info.play.channels = 2;
255 samplewidth *= 2;
256 }
257
258 snd_rate = pwfx->nSamplesPerSec;
259
260 info.play.sample_rate = pwfx->nSamplesPerSec;
261 info.play.precision = pwfx->wBitsPerSample;
262 info.play.samples = 0;
263 info.play.eof = 0;
264 info.play.error = 0;
265
266 info.record.sample_rate = info.play.sample_rate;
267 info.record.channels = info.play.channels;
268 info.record.precision = info.play.precision;
269 info.record.encoding = info.play.encoding;
270 info.record.samples = 0;
271 info.record.error = 0;
272
273 if (ioctl(dsp_fd, AUDIO_SETINFO, &info) == -1)
274 {
275 perror("AUDIO_SETINFO");
276 sun_close();
277 return False;
278 }
279
280 dsp_configured = True;
281
282 return True;
283 }
284
285 void
286 sun_volume(uint16 left, uint16 right)
287 {
288 audio_info_t info;
289 uint balance;
290 uint volume;
291
292 AUDIO_INITINFO(&info);
293
294 volume = (left > right) ? left : right;
295
296 if (volume / AUDIO_MID_BALANCE != 0)
297 {
298 balance =
299 AUDIO_MID_BALANCE - (left / (volume / AUDIO_MID_BALANCE)) +
300 (right / (volume / AUDIO_MID_BALANCE));
301 }
302 else
303 {
304 balance = AUDIO_MID_BALANCE;
305 }
306
307 info.play.gain = volume / (65536 / AUDIO_MAX_GAIN);
308 info.play.balance = balance;
309
310 if (ioctl(dsp_fd, AUDIO_SETINFO, &info) == -1)
311 {
312 perror("AUDIO_SETINFO");
313 return;
314 }
315 }
316
317 void
318 sun_play(void)
319 {
320 struct audio_packet *packet;
321 ssize_t len;
322 STREAM out;
323
324 /* We shouldn't be called if the queue is empty, but still */
325 if (rdpsnd_queue_empty())
326 return;
327
328 packet = rdpsnd_queue_current_packet();
329 out = &packet->s;
330
331 len = out->end - out->p;
332
333 len = write(dsp_fd, out->p, (len > MAX_LEN) ? MAX_LEN : len);
334 if (len == -1)
335 {
336 if (errno != EWOULDBLOCK)
337 {
338 if (!dsp_broken)
339 perror("RDPSND: write()");
340 dsp_broken = True;
341 rdpsnd_queue_next(0);
342 }
343 return;
344 }
345
346 written_samples += len / (samplewidth * (stereo ? 2 : 1));
347
348 dsp_broken = False;
349
350 out->p += len;
351
352 if (out->p == out->end)
353 {
354 audio_info_t info;
355 uint_t delay_samples;
356 unsigned long delay_us;
357
358 if (ioctl(dsp_fd, AUDIO_GETINFO, &info) != -1)
359 delay_samples = written_samples - info.play.samples;
360 else
361 delay_samples = out->size / (samplewidth * (stereo ? 2 : 1));
362
363 delay_us = delay_samples * (1000000 / snd_rate);
364 rdpsnd_queue_next(delay_us);
365 }
366 }
367
368 void
369 sun_record(void)
370 {
371 char buffer[32768];
372 int len;
373
374 len = read(dsp_fd, buffer, sizeof(buffer));
375 if (len == -1)
376 {
377 if (errno != EWOULDBLOCK)
378 perror("read audio");
379 return;
380 }
381
382 rdpsnd_record(buffer, len);
383 }
384
385 struct audio_driver *
386 sun_register(char *options)
387 {
388 static struct audio_driver sun_driver;
389
390 memset(&sun_driver, 0, sizeof(sun_driver));
391
392 sun_driver.name = "sun";
393 sun_driver.description =
394 "SUN/BSD output driver, default device: " DEFAULTDEVICE " or $AUDIODEV";
395
396 sun_driver.add_fds = sun_add_fds;
397 sun_driver.check_fds = sun_check_fds;
398
399 sun_driver.wave_out_open = sun_open_out;
400 sun_driver.wave_out_close = sun_close_out;
401 sun_driver.wave_out_format_supported = sun_format_supported;
402 sun_driver.wave_out_set_format = sun_set_format;
403 sun_driver.wave_out_volume = sun_volume;
404
405 sun_driver.wave_in_open = sun_open_in;
406 sun_driver.wave_in_close = sun_close_in;
407 sun_driver.wave_in_format_supported = sun_format_supported;
408 sun_driver.wave_in_set_format = sun_set_format;
409 sun_driver.wave_in_volume = NULL; /* FIXME */
410
411 sun_driver.need_byteswap_on_be = 1;
412 sun_driver.need_resampling = 0;
413
414 if (options)
415 {
416 dsp_dev = xstrdup(options);
417 }
418 else
419 {
420 dsp_dev = getenv("AUDIODEV");
421
422 if (dsp_dev == NULL)
423 {
424 dsp_dev = DEFAULTDEVICE;
425 }
426 }
427
428 return &sun_driver;
429 }

  ViewVC Help
Powered by ViewVC 1.1.26