/[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 1275 - (show annotations)
Sun Oct 1 11:08:09 2006 UTC (17 years, 8 months ago) by stargo
File MIME type: text/plain
File size: 5771 byte(s)
do not lose the first mixer event in oss

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 snd_rate = pwfx->nSamplesPerSec;
120 if (ioctl(g_dsp_fd, SNDCTL_DSP_SPEED, &snd_rate) == -1)
121 {
122 perror("SNDCTL_DSP_SPEED");
123 close(g_dsp_fd);
124 return False;
125 }
126
127 /* try to get 12 fragments of 2^12 bytes size */
128 fragments = (12 << 16) + 12;
129 ioctl(g_dsp_fd, SNDCTL_DSP_SETFRAGMENT, &fragments);
130
131 if (!driver_broken)
132 {
133 audio_buf_info info;
134
135 memset(&info, 0, sizeof(info));
136 if (ioctl(g_dsp_fd, SNDCTL_DSP_GETOSPACE, &info) == -1)
137 {
138 perror("SNDCTL_DSP_GETOSPACE");
139 close(g_dsp_fd);
140 return False;
141 }
142
143 if (info.fragments == 0 || info.fragstotal == 0 || info.fragsize == 0)
144 {
145 fprintf(stderr,
146 "Broken OSS-driver detected: fragments: %d, fragstotal: %d, fragsize: %d\n",
147 info.fragments, info.fragstotal, info.fragsize);
148 driver_broken = True;
149 }
150 }
151
152 return True;
153 }
154
155 void
156 oss_volume(uint16 left, uint16 right)
157 {
158 uint32 volume;
159
160 volume = left / (65536 / 100);
161 volume |= right / (65536 / 100) << 8;
162
163 if (ioctl(g_dsp_fd, MIXER_WRITE(SOUND_MIXER_PCM), &volume) == -1)
164 {
165 warning("hardware volume control unavailable, falling back to software volume control!\n");
166 oss_driver.wave_out_volume = rdpsnd_dsp_softvol_set;
167 rdpsnd_dsp_softvol_set(left, right);
168 return;
169 }
170 }
171
172 void
173 oss_play(void)
174 {
175 struct audio_packet *packet;
176 ssize_t len;
177 STREAM out;
178 static long startedat_us;
179 static long startedat_s;
180 static BOOL started = False;
181 struct timeval tv;
182
183 if (rdpsnd_queue_empty())
184 {
185 g_dsp_busy = 0;
186 return;
187 }
188
189 packet = rdpsnd_queue_current_packet();
190 out = &packet->s;
191
192 if (!started)
193 {
194 gettimeofday(&tv, NULL);
195 startedat_us = tv.tv_usec;
196 startedat_s = tv.tv_sec;
197 started = True;
198 }
199
200 len = out->end - out->p;
201
202 len = write(g_dsp_fd, out->p, (len > MAX_LEN) ? MAX_LEN : len);
203 if (len == -1)
204 {
205 if (errno != EWOULDBLOCK)
206 perror("write audio");
207 g_dsp_busy = 1;
208 return;
209 }
210
211 out->p += len;
212 if (out->p == out->end)
213 {
214 long long duration;
215 long elapsed;
216
217 gettimeofday(&tv, NULL);
218 duration = (out->size * (1000000 / (samplewidth * snd_rate)));
219 elapsed = (tv.tv_sec - startedat_s) * 1000000 + (tv.tv_usec - startedat_us);
220
221 if (elapsed >= (duration * 85) / 100)
222 {
223 /* We need to add 50 to tell windows that time has passed while
224 * playing this packet */
225 rdpsnd_send_completion(packet->tick + 50, packet->index);
226 rdpsnd_queue_next();
227 started = False;
228 }
229 else
230 {
231 g_dsp_busy = 1;
232 return;
233 }
234 }
235 g_dsp_busy = 1;
236 return;
237 }
238
239 struct audio_driver *
240 oss_register(char *options)
241 {
242 oss_driver.wave_out_write = rdpsnd_queue_write;
243 oss_driver.wave_out_open = oss_open;
244 oss_driver.wave_out_close = oss_close;
245 oss_driver.wave_out_format_supported = oss_format_supported;
246 oss_driver.wave_out_set_format = oss_set_format;
247 oss_driver.wave_out_volume = oss_volume;
248 oss_driver.wave_out_play = oss_play;
249 oss_driver.name = xstrdup("oss");
250 oss_driver.description =
251 xstrdup("OSS output driver, default device: " DEFAULTDEVICE " or $AUDIODEV");
252 oss_driver.need_byteswap_on_be = 0;
253 oss_driver.next = NULL;
254
255 if (options)
256 {
257 dsp_dev = xstrdup(options);
258 }
259 else
260 {
261 dsp_dev = getenv("AUDIODEV");
262
263 if (dsp_dev == NULL)
264 {
265 dsp_dev = xstrdup(DEFAULTDEVICE);
266 }
267 }
268
269 return &oss_driver;
270 }

  ViewVC Help
Powered by ViewVC 1.1.26