/[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 1247 - (show 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 /* -*- 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 <unistd.h>
32 #include <fcntl.h>
33 #include <errno.h>
34 #include <sys/time.h>
35 #include <sys/ioctl.h>
36 #include <sys/soundcard.h>
37
38 #define MAX_LEN 512
39 #define MAX_QUEUE 10
40
41 int g_dsp_fd;
42 BOOL g_dsp_busy = False;
43 static int snd_rate;
44 static short samplewidth;
45
46 static struct audio_packet
47 {
48 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 char *dsp_dev = getenv("AUDIODEV");
58
59 if (dsp_dev == NULL)
60 {
61 dsp_dev = xstrdup("/dev/dsp");
62 }
63
64 if ((g_dsp_fd = open(dsp_dev, O_WRONLY)) == -1)
65 {
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 wave_out_format_supported(WAVEFORMATEX * pwfx)
81 {
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 wave_out_set_format(WAVEFORMATEX * pwfx)
94 {
95 int stereo, format, fragments;
96 static BOOL driver_broken = False;
97
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 samplewidth = pwfx->wBitsPerSample / 8;
107
108 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 if (pwfx->nChannels == 2)
116 {
117 stereo = 1;
118 samplewidth *= 2;
119 }
120 else
121 {
122 stereo = 0;
123 }
124
125 if (ioctl(g_dsp_fd, SNDCTL_DSP_STEREO, &stereo) == -1)
126 {
127 perror("SNDCTL_DSP_CHANNELS");
128 close(g_dsp_fd);
129 return False;
130 }
131
132 snd_rate = pwfx->nSamplesPerSec;
133 if (ioctl(g_dsp_fd, SNDCTL_DSP_SPEED, &snd_rate) == -1)
134 {
135 perror("SNDCTL_DSP_SPEED");
136 close(g_dsp_fd);
137 return False;
138 }
139
140 /* try to get 12 fragments of 2^12 bytes size */
141 fragments = (12 << 16) + 12;
142 ioctl(g_dsp_fd, SNDCTL_DSP_SETFRAGMENT, &fragments);
143
144 if (!driver_broken)
145 {
146 audio_buf_info info;
147
148 memset(&info, 0, sizeof(info));
149 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 driver_broken = True;
162 }
163 }
164
165 return True;
166 }
167
168 void
169 wave_out_volume(uint16 left, uint16 right)
170 {
171 static BOOL use_dev_mixer = False;
172 uint32 volume;
173 int fd_mix = -1;
174
175 volume = left / (65536 / 100);
176 volume |= right / (65536 / 100) << 8;
177
178 if (use_dev_mixer)
179 {
180 if ((fd_mix = open("/dev/mixer", O_RDWR | O_NONBLOCK)) == -1)
181 {
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 if (ioctl(g_dsp_fd, MIXER_WRITE(SOUND_MIXER_PCM), &volume) == -1)
196 {
197 perror("MIXER_WRITE(SOUND_MIXER_PCM)");
198 use_dev_mixer = True;
199 return;
200 }
201 }
202
203 void
204 wave_out_write(STREAM s, uint16 tick, uint8 index)
205 {
206 struct audio_packet *packet = &packet_queue[queue_hi];
207 unsigned int next_hi = (queue_hi + 1) % MAX_QUEUE;
208
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 packet->s.p += 4;
221
222 /* we steal the data buffer from s, give it a new one */
223 s->data = (uint8 *) malloc(s->size);
224
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 static long startedat_us;
236 static long startedat_s;
237 static BOOL started = False;
238 struct timeval tv;
239
240 if (queue_lo == queue_hi)
241 {
242 g_dsp_busy = 0;
243 return;
244 }
245
246 packet = &packet_queue[queue_lo];
247 out = &packet->s;
248
249 if (!started)
250 {
251 gettimeofday(&tv, NULL);
252 startedat_us = tv.tv_usec;
253 startedat_s = tv.tv_sec;
254 started = True;
255 }
256
257 len = out->end - out->p;
258
259 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
268 out->p += len;
269 if (out->p == out->end)
270 {
271 long long duration;
272 long elapsed;
273
274 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
278 if (elapsed >= (duration * 85) / 100)
279 {
280 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 g_dsp_busy = 1;
288 return;
289 }
290 }
291 g_dsp_busy = 1;
292 return;
293 }

  ViewVC Help
Powered by ViewVC 1.1.26