/[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 794 - (show annotations)
Wed Nov 3 10:05:02 2004 UTC (19 years, 6 months ago) by stargo
File MIME type: text/plain
File size: 6224 byte(s)
strdup the audio-device

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

  ViewVC Help
Powered by ViewVC 1.1.26