/[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 1286 - (show annotations)
Sun Oct 1 18:47:04 2006 UTC (17 years, 8 months ago) by stargo
File MIME type: text/plain
File size: 6357 byte(s)
use resampling in OSS driver when native samplerate is not available

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

  ViewVC Help
Powered by ViewVC 1.1.26