/[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 1302 - (hide annotations)
Thu Oct 26 09:47:17 2006 UTC (17 years, 7 months ago) by ossman_
File MIME type: text/plain
File size: 6738 byte(s)
Rewrite the queue management a bit so that blocks are not completed until
they have finished playing. This also makes the queue system mandatory for
all backends.

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 stargo 1254 #include "rdpsnd.h"
32 stargo 1269 #include "rdpsnd_dsp.h"
33 matthewc 475 #include <unistd.h>
34     #include <fcntl.h>
35     #include <errno.h>
36 ossman_ 1302 #include <unistd.h>
37 stargo 510 #include <sys/time.h>
38 matthewc 475 #include <sys/ioctl.h>
39     #include <sys/soundcard.h>
40 ossman_ 1302 #include <sys/types.h>
41     #include <sys/stat.h>
42 matthewc 475
43 stargo 1254 #define DEFAULTDEVICE "/dev/dsp"
44 stargo 1247 #define MAX_LEN 512
45 matthewc 475
46 stargo 1247 static int snd_rate;
47     static short samplewidth;
48 stargo 1255 static char *dsp_dev;
49 stargo 1269 static struct audio_driver oss_driver;
50 ossman_ 1302 static BOOL in_esddsp;
51 matthewc 475
52 ossman_ 1302 static BOOL
53     detect_esddsp(void)
54     {
55     struct stat s;
56     char *preload;
57    
58     if (fstat(g_dsp_fd, &s) == -1)
59     return False;
60    
61     if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
62     return False;
63    
64     preload = getenv("LD_PRELOAD");
65     if (preload == NULL)
66     return False;
67    
68     if (strstr(preload, "esddsp") == NULL)
69     return False;
70    
71     return True;
72     }
73    
74 matthewc 475 BOOL
75 stargo 1255 oss_open(void)
76 matthewc 475 {
77 stargo 1247 if ((g_dsp_fd = open(dsp_dev, O_WRONLY)) == -1)
78 matthewc 475 {
79     perror(dsp_dev);
80     return False;
81     }
82    
83 ossman_ 1302 in_esddsp = detect_esddsp();
84    
85 matthewc 475 return True;
86     }
87    
88     void
89 stargo 1255 oss_close(void)
90 matthewc 475 {
91     close(g_dsp_fd);
92     }
93    
94     BOOL
95 stargo 1255 oss_format_supported(WAVEFORMATEX * pwfx)
96 matthewc 475 {
97     if (pwfx->wFormatTag != WAVE_FORMAT_PCM)
98     return False;
99     if ((pwfx->nChannels != 1) && (pwfx->nChannels != 2))
100     return False;
101     if ((pwfx->wBitsPerSample != 8) && (pwfx->wBitsPerSample != 16))
102     return False;
103    
104     return True;
105     }
106    
107     BOOL
108 stargo 1255 oss_set_format(WAVEFORMATEX * pwfx)
109 matthewc 475 {
110 stargo 761 int stereo, format, fragments;
111 stargo 1247 static BOOL driver_broken = False;
112 matthewc 475
113     ioctl(g_dsp_fd, SNDCTL_DSP_RESET, NULL);
114     ioctl(g_dsp_fd, SNDCTL_DSP_SYNC, NULL);
115    
116     if (pwfx->wBitsPerSample == 8)
117     format = AFMT_U8;
118     else if (pwfx->wBitsPerSample == 16)
119     format = AFMT_S16_LE;
120    
121 stargo 1247 samplewidth = pwfx->wBitsPerSample / 8;
122 stargo 510
123 matthewc 475 if (ioctl(g_dsp_fd, SNDCTL_DSP_SETFMT, &format) == -1)
124     {
125     perror("SNDCTL_DSP_SETFMT");
126     close(g_dsp_fd);
127     return False;
128     }
129    
130 stargo 760 if (pwfx->nChannels == 2)
131 matthewc 475 {
132 stargo 760 stereo = 1;
133 stargo 1247 samplewidth *= 2;
134 stargo 760 }
135     else
136     {
137     stereo = 0;
138     }
139    
140     if (ioctl(g_dsp_fd, SNDCTL_DSP_STEREO, &stereo) == -1)
141     {
142 matthewc 475 perror("SNDCTL_DSP_CHANNELS");
143     close(g_dsp_fd);
144     return False;
145     }
146    
147 stargo 1286 oss_driver.need_resampling = 0;
148 stargo 1247 snd_rate = pwfx->nSamplesPerSec;
149     if (ioctl(g_dsp_fd, SNDCTL_DSP_SPEED, &snd_rate) == -1)
150 stargo 510 {
151 stargo 1286 int rates[] = { 44100, 48000, 0 };
152     int *prates = rates;
153    
154     while (*prates != 0)
155     {
156     if ((pwfx->nSamplesPerSec != *prates)
157     && (ioctl(g_dsp_fd, SNDCTL_DSP_SPEED, prates) != -1))
158     {
159     oss_driver.need_resampling = 1;
160     snd_rate = *prates;
161     if (rdpsnd_dsp_resample_set
162     (snd_rate, pwfx->wBitsPerSample, pwfx->nChannels) == False)
163     {
164     error("rdpsnd_dsp_resample_set failed");
165     close(g_dsp_fd);
166     return False;
167     }
168    
169     break;
170     }
171     prates++;
172     }
173    
174     if (*prates == 0)
175     {
176     perror("SNDCTL_DSP_SPEED");
177     close(g_dsp_fd);
178     return False;
179     }
180 matthewc 475 }
181    
182 stargo 1247 /* try to get 12 fragments of 2^12 bytes size */
183     fragments = (12 << 16) + 12;
184 stargo 761 ioctl(g_dsp_fd, SNDCTL_DSP_SETFRAGMENT, &fragments);
185    
186 stargo 1247 if (!driver_broken)
187 stargo 761 {
188     audio_buf_info info;
189    
190 astrand 801 memset(&info, 0, sizeof(info));
191 stargo 761 if (ioctl(g_dsp_fd, SNDCTL_DSP_GETOSPACE, &info) == -1)
192     {
193     perror("SNDCTL_DSP_GETOSPACE");
194     close(g_dsp_fd);
195     return False;
196     }
197    
198     if (info.fragments == 0 || info.fragstotal == 0 || info.fragsize == 0)
199     {
200     fprintf(stderr,
201     "Broken OSS-driver detected: fragments: %d, fragstotal: %d, fragsize: %d\n",
202     info.fragments, info.fragstotal, info.fragsize);
203 stargo 1247 driver_broken = True;
204 stargo 761 }
205     }
206    
207 matthewc 475 return True;
208     }
209    
210     void
211 stargo 1255 oss_volume(uint16 left, uint16 right)
212 stargo 491 {
213     uint32 volume;
214    
215 astrand 499 volume = left / (65536 / 100);
216     volume |= right / (65536 / 100) << 8;
217 stargo 509
218 stargo 491 if (ioctl(g_dsp_fd, MIXER_WRITE(SOUND_MIXER_PCM), &volume) == -1)
219     {
220 stargo 1275 warning("hardware volume control unavailable, falling back to software volume control!\n");
221 stargo 1269 oss_driver.wave_out_volume = rdpsnd_dsp_softvol_set;
222 stargo 1275 rdpsnd_dsp_softvol_set(left, right);
223 stargo 491 return;
224     }
225     }
226    
227     void
228 stargo 1255 oss_play(void)
229 matthewc 475 {
230     struct audio_packet *packet;
231     ssize_t len;
232     STREAM out;
233    
234 stargo 1254 if (rdpsnd_queue_empty())
235 matthewc 475 {
236 stargo 1247 g_dsp_busy = 0;
237     return;
238     }
239 matthewc 475
240 stargo 1254 packet = rdpsnd_queue_current_packet();
241 stargo 1247 out = &packet->s;
242 matthewc 475
243 stargo 1247 len = out->end - out->p;
244 stargo 761
245 stargo 1247 len = write(g_dsp_fd, out->p, (len > MAX_LEN) ? MAX_LEN : len);
246     if (len == -1)
247     {
248     if (errno != EWOULDBLOCK)
249     perror("write audio");
250     g_dsp_busy = 1;
251     return;
252     }
253 stargo 761
254 stargo 1247 out->p += len;
255 ossman_ 1302
256 stargo 1247 if (out->p == out->end)
257     {
258 ossman_ 1302 int delay_bytes;
259     unsigned long delay_us;
260     audio_buf_info info;
261 stargo 761
262 ossman_ 1302 if (in_esddsp)
263 matthewc 475 {
264 ossman_ 1302 /* EsounD has no way of querying buffer status, so we have to
265     * go with a fixed size. */
266     delay_bytes = out->size;
267 stargo 1247 }
268     else
269     {
270 ossman_ 1302 #ifdef SNDCTL_DSP_GETODELAY
271     delay_bytes = 0;
272     if (ioctl(g_dsp_fd, SNDCTL_DSP_GETODELAY, &delay_bytes) == -1)
273     delay_bytes = -1;
274     #else
275     delay_bytes = -1;
276     #endif
277    
278     if (delay_bytes == -1)
279     {
280     if (ioctl(g_dsp_fd, SNDCTL_DSP_GETOSPACE, &info) != -1)
281     delay_bytes = info.fragstotal * info.fragsize - info.bytes;
282     else
283     delay_bytes = out->size;
284     }
285 matthewc 475 }
286 ossman_ 1302
287     delay_us = delay_bytes * (1000000 / (samplewidth * snd_rate));
288     rdpsnd_queue_next(delay_us);
289 matthewc 475 }
290 ossman_ 1302 else
291     {
292     g_dsp_busy = 1;
293     }
294    
295 stargo 1247 return;
296 matthewc 475 }
297 stargo 1255
298     struct audio_driver *
299     oss_register(char *options)
300     {
301 stargo 1256 oss_driver.wave_out_open = oss_open;
302     oss_driver.wave_out_close = oss_close;
303     oss_driver.wave_out_format_supported = oss_format_supported;
304     oss_driver.wave_out_set_format = oss_set_format;
305     oss_driver.wave_out_volume = oss_volume;
306     oss_driver.wave_out_play = oss_play;
307     oss_driver.name = xstrdup("oss");
308     oss_driver.description =
309     xstrdup("OSS output driver, default device: " DEFAULTDEVICE " or $AUDIODEV");
310 stargo 1260 oss_driver.need_byteswap_on_be = 0;
311 stargo 1279 oss_driver.need_resampling = 0;
312 stargo 1256 oss_driver.next = NULL;
313    
314 stargo 1255 if (options)
315     {
316     dsp_dev = xstrdup(options);
317     }
318     else
319     {
320     dsp_dev = getenv("AUDIODEV");
321    
322     if (dsp_dev == NULL)
323     {
324     dsp_dev = xstrdup(DEFAULTDEVICE);
325     }
326     }
327    
328     return &oss_driver;
329     }

  ViewVC Help
Powered by ViewVC 1.1.26