/[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 1269 - (show annotations)
Mon Sep 18 10:17:24 2006 UTC (17 years, 8 months ago) by stargo
File MIME type: text/plain
File size: 5680 byte(s)
fall back to software volume control when the mixer ioctl fails on the
dsp fd

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 perror("MIXER_WRITE(SOUND_MIXER_PCM)");
166 oss_driver.wave_out_volume = rdpsnd_dsp_softvol_set;
167 return;
168 }
169 }
170
171 void
172 oss_play(void)
173 {
174 struct audio_packet *packet;
175 ssize_t len;
176 STREAM out;
177 static long startedat_us;
178 static long startedat_s;
179 static BOOL started = False;
180 struct timeval tv;
181
182 if (rdpsnd_queue_empty())
183 {
184 g_dsp_busy = 0;
185 return;
186 }
187
188 packet = rdpsnd_queue_current_packet();
189 out = &packet->s;
190
191 if (!started)
192 {
193 gettimeofday(&tv, NULL);
194 startedat_us = tv.tv_usec;
195 startedat_s = tv.tv_sec;
196 started = True;
197 }
198
199 len = out->end - out->p;
200
201 len = write(g_dsp_fd, out->p, (len > MAX_LEN) ? MAX_LEN : len);
202 if (len == -1)
203 {
204 if (errno != EWOULDBLOCK)
205 perror("write audio");
206 g_dsp_busy = 1;
207 return;
208 }
209
210 out->p += len;
211 if (out->p == out->end)
212 {
213 long long duration;
214 long elapsed;
215
216 gettimeofday(&tv, NULL);
217 duration = (out->size * (1000000 / (samplewidth * snd_rate)));
218 elapsed = (tv.tv_sec - startedat_s) * 1000000 + (tv.tv_usec - startedat_us);
219
220 if (elapsed >= (duration * 85) / 100)
221 {
222 /* We need to add 50 to tell windows that time has passed while
223 * playing this packet */
224 rdpsnd_send_completion(packet->tick + 50, packet->index);
225 rdpsnd_queue_next();
226 started = False;
227 }
228 else
229 {
230 g_dsp_busy = 1;
231 return;
232 }
233 }
234 g_dsp_busy = 1;
235 return;
236 }
237
238 struct audio_driver *
239 oss_register(char *options)
240 {
241 oss_driver.wave_out_write = rdpsnd_queue_write;
242 oss_driver.wave_out_open = oss_open;
243 oss_driver.wave_out_close = oss_close;
244 oss_driver.wave_out_format_supported = oss_format_supported;
245 oss_driver.wave_out_set_format = oss_set_format;
246 oss_driver.wave_out_volume = oss_volume;
247 oss_driver.wave_out_play = oss_play;
248 oss_driver.name = xstrdup("oss");
249 oss_driver.description =
250 xstrdup("OSS output driver, default device: " DEFAULTDEVICE " or $AUDIODEV");
251 oss_driver.need_byteswap_on_be = 0;
252 oss_driver.next = NULL;
253
254 if (options)
255 {
256 dsp_dev = xstrdup(options);
257 }
258 else
259 {
260 dsp_dev = getenv("AUDIODEV");
261
262 if (dsp_dev == NULL)
263 {
264 dsp_dev = xstrdup(DEFAULTDEVICE);
265 }
266 }
267
268 return &oss_driver;
269 }

  ViewVC Help
Powered by ViewVC 1.1.26