/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1227 - (hide annotations)
Thu Apr 13 07:37:24 2006 UTC (18 years, 2 months ago) by astrand
File MIME type: text/plain
File size: 6413 byte(s)
Make rdpsnd_oss work with Esound again, even with largefile enabled: build this compilation unit without largefile support.

1 astrand 963 /* -*- c-basic-offset: 8 -*-
2 matthewc 475 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 astrand 1227 /*
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 matthewc 475 #include "rdesktop.h"
31     #include <unistd.h>
32     #include <fcntl.h>
33     #include <errno.h>
34 stargo 510 #include <sys/time.h>
35 matthewc 475 #include <sys/ioctl.h>
36     #include <sys/soundcard.h>
37    
38     #define MAX_QUEUE 10
39    
40     int g_dsp_fd;
41 stargo 504 BOOL g_dsp_busy = False;
42 stargo 510 static int g_snd_rate;
43     static short g_samplewidth;
44 stargo 761 static BOOL g_driver_broken = False;
45 matthewc 475
46 astrand 499 static struct audio_packet
47     {
48 matthewc 475 struct stream s;
49     uint16 tick;
50     uint8 index;
51     } packet_queue[MAX_QUEUE];
52     static unsigned int queue_hi, queue_lo;
53    
54     BOOL
55     wave_out_open(void)
56     {
57 stargo 751 char *dsp_dev = getenv("AUDIODEV");
58 matthewc 475
59 stargo 751 if (dsp_dev == NULL)
60     {
61 astrand 974 dsp_dev = xstrdup("/dev/dsp");
62 stargo 751 }
63    
64 astrand 499 if ((g_dsp_fd = open(dsp_dev, O_WRONLY | O_NONBLOCK)) == -1)
65 matthewc 475 {
66     perror(dsp_dev);
67     return False;
68     }
69    
70     /* Non-blocking so that user interface is responsive */
71 astrand 499 fcntl(g_dsp_fd, F_SETFL, fcntl(g_dsp_fd, F_GETFL) | O_NONBLOCK);
72 matthewc 475 return True;
73     }
74    
75     void
76     wave_out_close(void)
77     {
78     close(g_dsp_fd);
79     }
80    
81     BOOL
82 astrand 499 wave_out_format_supported(WAVEFORMATEX * pwfx)
83 matthewc 475 {
84     if (pwfx->wFormatTag != WAVE_FORMAT_PCM)
85     return False;
86     if ((pwfx->nChannels != 1) && (pwfx->nChannels != 2))
87     return False;
88     if ((pwfx->wBitsPerSample != 8) && (pwfx->wBitsPerSample != 16))
89     return False;
90    
91     return True;
92     }
93    
94     BOOL
95 astrand 499 wave_out_set_format(WAVEFORMATEX * pwfx)
96 matthewc 475 {
97 stargo 761 int stereo, format, fragments;
98 matthewc 475
99     ioctl(g_dsp_fd, SNDCTL_DSP_RESET, NULL);
100     ioctl(g_dsp_fd, SNDCTL_DSP_SYNC, NULL);
101    
102     if (pwfx->wBitsPerSample == 8)
103     format = AFMT_U8;
104     else if (pwfx->wBitsPerSample == 16)
105     format = AFMT_S16_LE;
106    
107 stargo 510 g_samplewidth = pwfx->wBitsPerSample / 8;
108    
109 matthewc 475 if (ioctl(g_dsp_fd, SNDCTL_DSP_SETFMT, &format) == -1)
110     {
111     perror("SNDCTL_DSP_SETFMT");
112     close(g_dsp_fd);
113     return False;
114     }
115    
116 stargo 760 if (pwfx->nChannels == 2)
117 matthewc 475 {
118 stargo 760 stereo = 1;
119     g_samplewidth *= 2;
120     }
121     else
122     {
123     stereo = 0;
124     }
125    
126     if (ioctl(g_dsp_fd, SNDCTL_DSP_STEREO, &stereo) == -1)
127     {
128 matthewc 475 perror("SNDCTL_DSP_CHANNELS");
129     close(g_dsp_fd);
130     return False;
131     }
132    
133 stargo 510 g_snd_rate = pwfx->nSamplesPerSec;
134     if (ioctl(g_dsp_fd, SNDCTL_DSP_SPEED, &g_snd_rate) == -1)
135     {
136 matthewc 475 perror("SNDCTL_DSP_SPEED");
137     close(g_dsp_fd);
138     return False;
139     }
140    
141 stargo 761 /* try to get 7 fragments of 2^12 bytes size */
142     fragments = (7 << 16) + 12;
143     ioctl(g_dsp_fd, SNDCTL_DSP_SETFRAGMENT, &fragments);
144    
145     if (!g_driver_broken)
146     {
147     audio_buf_info info;
148    
149 astrand 801 memset(&info, 0, sizeof(info));
150 stargo 761 if (ioctl(g_dsp_fd, SNDCTL_DSP_GETOSPACE, &info) == -1)
151     {
152     perror("SNDCTL_DSP_GETOSPACE");
153     close(g_dsp_fd);
154     return False;
155     }
156    
157     if (info.fragments == 0 || info.fragstotal == 0 || info.fragsize == 0)
158     {
159     fprintf(stderr,
160     "Broken OSS-driver detected: fragments: %d, fragstotal: %d, fragsize: %d\n",
161     info.fragments, info.fragstotal, info.fragsize);
162     g_driver_broken = True;
163     }
164     }
165    
166 matthewc 475 return True;
167     }
168    
169     void
170 stargo 491 wave_out_volume(uint16 left, uint16 right)
171     {
172 stargo 509 static BOOL use_dev_mixer = False;
173 stargo 491 uint32 volume;
174 stargo 509 int fd_mix = -1;
175 stargo 491
176 astrand 499 volume = left / (65536 / 100);
177     volume |= right / (65536 / 100) << 8;
178 stargo 509
179     if (use_dev_mixer)
180     {
181 astrand 532 if ((fd_mix = open("/dev/mixer", O_RDWR | O_NONBLOCK)) == -1)
182 stargo 509 {
183     perror("open /dev/mixer");
184     return;
185     }
186    
187     if (ioctl(fd_mix, MIXER_WRITE(SOUND_MIXER_PCM), &volume) == -1)
188     {
189     perror("MIXER_WRITE(SOUND_MIXER_PCM)");
190     return;
191     }
192    
193     close(fd_mix);
194     }
195    
196 stargo 491 if (ioctl(g_dsp_fd, MIXER_WRITE(SOUND_MIXER_PCM), &volume) == -1)
197     {
198     perror("MIXER_WRITE(SOUND_MIXER_PCM)");
199 stargo 509 use_dev_mixer = True;
200 stargo 491 return;
201     }
202     }
203    
204     void
205 matthewc 475 wave_out_write(STREAM s, uint16 tick, uint8 index)
206     {
207 matthewc 476 struct audio_packet *packet = &packet_queue[queue_hi];
208     unsigned int next_hi = (queue_hi + 1) % MAX_QUEUE;
209 matthewc 475
210     if (next_hi == queue_lo)
211     {
212     error("No space to queue audio packet\n");
213     return;
214     }
215    
216     queue_hi = next_hi;
217    
218     packet->s = *s;
219     packet->tick = tick;
220     packet->index = index;
221 stargo 491 packet->s.p += 4;
222 matthewc 475
223     /* we steal the data buffer from s, give it a new one */
224 jsorg71 778 s->data = (uint8 *) malloc(s->size);
225 matthewc 475
226     if (!g_dsp_busy)
227     wave_out_play();
228     }
229    
230     void
231     wave_out_play(void)
232     {
233     struct audio_packet *packet;
234     ssize_t len;
235     STREAM out;
236 stargo 510 static long startedat_us;
237     static long startedat_s;
238     static BOOL started = False;
239     struct timeval tv;
240 stargo 761 audio_buf_info info;
241 matthewc 475
242     while (1)
243     {
244     if (queue_lo == queue_hi)
245     {
246     g_dsp_busy = 0;
247     return;
248     }
249    
250     packet = &packet_queue[queue_lo];
251     out = &packet->s;
252    
253 stargo 510 if (!started)
254     {
255     gettimeofday(&tv, NULL);
256     startedat_us = tv.tv_usec;
257     startedat_s = tv.tv_sec;
258     started = True;
259     }
260    
261 stargo 761 len = out->end - out->p;
262    
263     if (!g_driver_broken)
264     {
265 astrand 801 memset(&info, 0, sizeof(info));
266 stargo 761 if (ioctl(g_dsp_fd, SNDCTL_DSP_GETOSPACE, &info) == -1)
267     {
268     perror("SNDCTL_DSP_GETOSPACE");
269     return;
270     }
271    
272     if (info.fragments == 0)
273     {
274     g_dsp_busy = 1;
275     return;
276     }
277    
278     if (info.fragments * info.fragsize < len
279     && info.fragments * info.fragsize > 0)
280     {
281     len = info.fragments * info.fragsize;
282     }
283     }
284    
285    
286     len = write(g_dsp_fd, out->p, len);
287 matthewc 475 if (len == -1)
288     {
289     if (errno != EWOULDBLOCK)
290     perror("write audio");
291     g_dsp_busy = 1;
292     return;
293     }
294    
295     out->p += len;
296     if (out->p == out->end)
297     {
298 stargo 510 long long duration;
299     long elapsed;
300 astrand 532
301 stargo 510 gettimeofday(&tv, NULL);
302 astrand 532 duration = (out->size * (1000000 / (g_samplewidth * g_snd_rate)));
303     elapsed = (tv.tv_sec - startedat_s) * 1000000 + (tv.tv_usec - startedat_us);
304 stargo 510
305 stargo 753 if (elapsed >= (duration * 85) / 100)
306 stargo 510 {
307     rdpsnd_send_completion(packet->tick, packet->index);
308     free(out->data);
309     queue_lo = (queue_lo + 1) % MAX_QUEUE;
310     started = False;
311     }
312     else
313     {
314     g_dsp_busy = 1;
315     return;
316     }
317 matthewc 475 }
318     }
319     }

  ViewVC Help
Powered by ViewVC 1.1.26