ReactOS 0.4.15-dev-7924-g5949c20
rdpsnd_oss.c
Go to the documentation of this file.
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 along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 <unistd.h>
32#include <fcntl.h>
33#include <errno.h>
34#include <sys/time.h>
35#include <sys/ioctl.h>
36#include <sys/soundcard.h>
37
38#define MAX_QUEUE 10
39
40int This->dsp_;
41BOOL This->dsp_bu = False;
42static int g_snd_rate;
43static short g_samplewidth;
45
46static struct audio_packet
47{
48 struct stream s;
52static unsigned int queue_hi, queue_lo;
53
54BOOL
56{
57 char *dsp_dev = getenv("AUDIODEV");
58
59 if (dsp_dev == NULL)
60 {
61 dsp_dev = xstrdup("/dev/dsp");
62 }
63
64 if ((This->dsp_ = open(dsp_dev, O_WRONLY | O_NONBLOCK)) == -1)
65 {
66 perror(dsp_dev);
67 return False;
68 }
69
70 /* Non-blocking so that user interface is responsive */
71 fcntl(This->dsp_, F_SETFL, fcntl(This->dsp_, F_GETFL) | O_NONBLOCK);
72 return True;
73}
74
75void
77{
78 close(This->dsp_);
79}
80
81BOOL
83{
84 if (pwfx->wFormatTag != WAVE_FORMAT_PCM)
85 return False;
86 if ((pwfx->nChannels != 1) && (pwfx->nChannels != 2))
87 return False;
88 if ((pwfx->wBitsPerSample != 8) && (pwfx->wBitsPerSample != 16))
89 return False;
90
91 return True;
92}
93
94BOOL
96{
97 int stereo, format, fragments;
98
99 ioctl(This->dsp_, SNDCTL_DSP_RESET, NULL);
100 ioctl(This->dsp_, SNDCTL_DSP_SYNC, NULL);
101
102 if (pwfx->wBitsPerSample == 8)
103 format = AFMT_U8;
104 else if (pwfx->wBitsPerSample == 16)
105 format = AFMT_S16_LE;
106
107 g_samplewidth = pwfx->wBitsPerSample / 8;
108
109 if (ioctl(This->dsp_, SNDCTL_DSP_SETFMT, &format) == -1)
110 {
111 perror("SNDCTL_DSP_SETFMT");
112 close(This->dsp_);
113 return False;
114 }
115
116 if (pwfx->nChannels == 2)
117 {
118 stereo = 1;
119 g_samplewidth *= 2;
120 }
121 else
122 {
123 stereo = 0;
124 }
125
126 if (ioctl(This->dsp_, SNDCTL_DSP_STEREO, &stereo) == -1)
127 {
128 perror("SNDCTL_DSP_CHANNELS");
129 close(This->dsp_);
130 return False;
131 }
132
134 if (ioctl(This->dsp_, SNDCTL_DSP_SPEED, &g_snd_rate) == -1)
135 {
136 perror("SNDCTL_DSP_SPEED");
137 close(This->dsp_);
138 return False;
139 }
140
141 /* try to get 7 fragments of 2^12 bytes size */
142 fragments = (7 << 16) + 12;
143 ioctl(This->dsp_, SNDCTL_DSP_SETFRAGMENT, &fragments);
144
145 if (!g_driver_broken)
146 {
147 audio_buf_info info;
148
149 memset(&info, 0, sizeof(info));
150 if (ioctl(This->dsp_, SNDCTL_DSP_GETOSPACE, &info) == -1)
151 {
152 perror("SNDCTL_DSP_GETOSPACE");
153 close(This->dsp_);
154 return False;
155 }
156
157 if (info.fragments == 0 || info.fragstotal == 0 || info.fragsize == 0)
158 {
160 "Broken OSS-driver detected: fragments: %d, fragstotal: %d, fragsize: %d\n",
161 info.fragments, info.fragstotal, info.fragsize);
163 }
164 }
165
166 return True;
167}
168
169void
171{
172 static BOOL use_dev_mixer = False;
174 int fd_mix = -1;
175
176 volume = left / (65536 / 100);
177 volume |= right / (65536 / 100) << 8;
178
179 if (use_dev_mixer)
180 {
181 if ((fd_mix = open("/dev/mixer", O_RDWR | O_NONBLOCK)) == -1)
182 {
183 perror("open /dev/mixer");
184 return;
185 }
186
187 if (ioctl(fd_mix, MIXER_WRITE(SOUND_MIXER_PCM), &volume) == -1)
188 {
189 perror("MIXER_WRITE(SOUND_MIXER_PCM)");
190 return;
191 }
192
193 close(fd_mix);
194 }
195
196 if (ioctl(This->dsp_, MIXER_WRITE(SOUND_MIXER_PCM), &volume) == -1)
197 {
198 perror("MIXER_WRITE(SOUND_MIXER_PCM)");
199 use_dev_mixer = True;
200 return;
201 }
202}
203
204void
206{
208 unsigned int next_hi = (queue_hi + 1) % MAX_QUEUE;
209
210 if (next_hi == queue_lo)
211 {
212 error("No space to queue audio packet\n");
213 return;
214 }
215
216 queue_hi = next_hi;
217
218 packet->s = *s;
219 packet->tick = tick;
220 packet->index = index;
221 packet->s.p += 4;
222
223 /* we steal the data buffer from s, give it a new one */
224 s->data = (uint8 *) malloc(s->size);
225
226 if (!This->dsp_bu)
228}
229
230void
232{
233 struct audio_packet *packet;
234 ssize_t len;
235 STREAM out;
236 static long startedat_us;
237 static long startedat_s;
238 static BOOL started = False;
239 struct timeval tv;
240 audio_buf_info info;
241
242 while (1)
243 {
244 if (queue_lo == queue_hi)
245 {
246 This->dsp_bu = 0;
247 return;
248 }
249
251 out = &packet->s;
252
253 if (!started)
254 {
255 gettimeofday(&tv, NULL);
256 startedat_us = tv.tv_usec;
257 startedat_s = tv.tv_sec;
258 started = True;
259 }
260
261 len = out->end - out->p;
262
263 if (!g_driver_broken)
264 {
265 memset(&info, 0, sizeof(info));
266 if (ioctl(This->dsp_, SNDCTL_DSP_GETOSPACE, &info) == -1)
267 {
268 perror("SNDCTL_DSP_GETOSPACE");
269 return;
270 }
271
272 if (info.fragments == 0)
273 {
274 This->dsp_bu = 1;
275 return;
276 }
277
278 if (info.fragments * info.fragsize < len
279 && info.fragments * info.fragsize > 0)
280 {
281 len = info.fragments * info.fragsize;
282 }
283 }
284
285
286 len = write(This->dsp_, out->p, len);
287 if (len == -1)
288 {
289 if (errno != EWOULDBLOCK)
290 perror("write audio");
291 This->dsp_bu = 1;
292 return;
293 }
294
295 out->p += len;
296 if (out->p == out->end)
297 {
298 long long duration;
299 long elapsed;
300
301 gettimeofday(&tv, NULL);
302 duration = (out->size * (1000000 / (g_samplewidth * g_snd_rate)));
303 elapsed = (tv.tv_sec - startedat_s) * 1000000 + (tv.tv_usec - startedat_us);
304
305 if (elapsed >= (duration * 85) / 100)
306 {
307 rdpsnd_send_completion(packet->tick, packet->index);
308 free(out->data);
309 queue_lo = (queue_lo + 1) % MAX_QUEUE;
310 started = False;
311 }
312 else
313 {
314 This->dsp_bu = 1;
315 return;
316 }
317 }
318 }
319}
#define O_WRONLY
Definition: acwin.h:111
#define open
Definition: acwin.h:95
#define close
Definition: acwin.h:98
#define write
Definition: acwin.h:97
#define gettimeofday(tv, tz)
Definition: adns_win32.h:159
#define WAVE_FORMAT_PCM
Definition: constants.h:425
char * xstrdup(const char *s)
Definition: uimain.c:768
unsigned short uint16
Definition: types.h:30
unsigned int uint32
Definition: types.h:32
#define False
Definition: types.h:25
#define True
Definition: types.h:24
unsigned char uint8
Definition: types.h:28
#define index(s, c)
Definition: various.h:29
#define free
Definition: debug_ros.c:5
#define malloc
Definition: debug_ros.c:4
#define NULL
Definition: types.h:112
#define EWOULDBLOCK
Definition: errno.h:42
unsigned int BOOL
Definition: ntddk_ex.h:94
GLdouble s
Definition: gl.h:2039
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl.h:1546
GLuint index
Definition: glext.h:6031
GLdouble GLdouble right
Definition: glext.h:10859
GLint left
Definition: glext.h:7726
GLenum GLsizei len
Definition: glext.h:6722
#define O_RDWR
Definition: fcntl.h:36
_CRTIMP void __cdecl perror(_In_opt_z_ const char *_ErrMsg)
#define stderr
Definition: stdio.h:100
_Check_return_opt_ _CRTIMP int __cdecl fprintf(_Inout_ FILE *_File, _In_z_ _Printf_format_string_ const char *_Format,...)
_Check_return_ char *__cdecl getenv(_In_z_ const char *_VarName)
#define error(str)
Definition: mkdosfs.c:1605
#define O_NONBLOCK
Definition: port.h:158
void rdpsnd_send_completion(RDPCLIENT *This, uint16 tick, uint8 packet_index)
Definition: rdpsnd.c:55
static unsigned int queue_lo
Definition: rdpsnd_oss.c:52
BOOL wave_out_open(void)
Definition: rdpsnd_oss.c:55
static short g_samplewidth
Definition: rdpsnd_oss.c:43
BOOL wave_out_format_supported(WAVEFORMATEX *pwfx)
Definition: rdpsnd_oss.c:82
void wave_out_write(STREAM s, uint16 tick, uint8 index)
Definition: rdpsnd_oss.c:205
BOOL wave_out_set_format(WAVEFORMATEX *pwfx)
Definition: rdpsnd_oss.c:95
void wave_out_close(void)
Definition: rdpsnd_oss.c:76
void wave_out_volume(uint16 left, uint16 right)
Definition: rdpsnd_oss.c:170
void wave_out_play(void)
Definition: rdpsnd_oss.c:231
static unsigned int queue_hi
Definition: rdpsnd_oss.c:52
#define MAX_QUEUE
Definition: rdpsnd_oss.c:38
static int g_snd_rate
Definition: rdpsnd_oss.c:42
static struct audio_packet packet_queue[MAX_QUEUE]
static BOOL g_driver_broken
Definition: rdpsnd_oss.c:44
static FILE * out
Definition: regtests2xml.c:44
int ssize_t
Definition: rosdhcp.h:48
#define errno
Definition: errno.h:18
#define memset(x, y, z)
Definition: compat.h:39
WORD wBitsPerSample
Definition: audioclient.idl:45
DWORD nSamplesPerSec
Definition: audioclient.idl:42
Definition: dhcpd.h:135
Definition: parse.h:23
unsigned long tv_sec
Definition: linux.h:1738
unsigned long tv_usec
Definition: linux.h:1739
#define ioctl
Definition: wintirpc.h:60