/[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 1247 - (hide annotations)
Wed Jul 12 09:57:05 2006 UTC (17 years, 11 months ago) by stargo
File MIME type: text/plain
File size: 5850 byte(s)
Fix high cpu-usage in OSS-driver

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

  ViewVC Help
Powered by ViewVC 1.1.26