ReactOS  0.4.13-dev-92-gf251225
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 
40 int This->dsp_;
41 BOOL This->dsp_bu = False;
42 static int g_snd_rate;
43 static short g_samplewidth;
45 
46 static struct audio_packet
47 {
48  struct stream s;
49  uint16 tick;
50  uint8 index;
52 static unsigned int queue_hi, queue_lo;
53 
54 BOOL
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 
75 void
77 {
78  close(This->dsp_);
79 }
80 
81 BOOL
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 
94 BOOL
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 
133  g_snd_rate = pwfx->nSamplesPerSec;
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  {
159  fprintf(stderr,
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 
169 void
171 {
172  static BOOL use_dev_mixer = False;
173  uint32 volume;
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 
204 void
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)
227  wave_out_play();
228 }
229 
230 void
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 error(str)
Definition: mkdosfs.c:1605
UCHAR packet[_PAGE_SIZE]
Definition: serial.c:53
#define open
Definition: acwin.h:71
static unsigned int queue_lo
Definition: rdpsnd_oss.c:52
unsigned int uint32
Definition: types.h:32
void wave_out_write(STREAM s, uint16 tick, uint8 index)
Definition: rdpsnd_oss.c:205
#define O_NONBLOCK
Definition: port.h:158
#define free
Definition: debug_ros.c:5
static int g_snd_rate
Definition: rdpsnd_oss.c:42
unsigned long tv_sec
Definition: linux.h:1738
BOOL wave_out_open(void)
Definition: rdpsnd_oss.c:55
int errno
void wave_out_play(void)
Definition: rdpsnd_oss.c:231
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: gl.h:1546
struct _test_info info[]
Definition: SetCursorPos.c:19
#define write
Definition: acwin.h:73
#define gettimeofday(tv, tz)
Definition: adns_win32.h:159
#define WAVE_FORMAT_PCM
Definition: constants.h:425
_CRTIMP void __cdecl perror(_In_opt_z_ const char *_ErrMsg)
unsigned int BOOL
Definition: ntddk_ex.h:94
_Check_return_opt_ _CRTIMP int __cdecl fprintf(_Inout_ FILE *_File, _In_z_ _Printf_format_string_ const char *_Format,...)
#define O_WRONLY
Definition: acwin.h:85
#define ioctl
Definition: wintirpc.h:60
#define EWOULDBLOCK
Definition: errno.h:42
WORD wBitsPerSample
Definition: audioclient.idl:45
smooth NULL
Definition: ftsmooth.c:416
unsigned long tv_usec
Definition: linux.h:1739
GLuint index
Definition: glext.h:6031
DWORD nSamplesPerSec
Definition: audioclient.idl:42
Definition: dhcpd.h:135
#define True
Definition: types.h:24
#define False
Definition: types.h:25
static FILE * out
Definition: regtests2xml.c:44
GLint left
Definition: glext.h:7726
unsigned char uint8
Definition: types.h:28
GLdouble GLdouble right
Definition: glext.h:10859
static BOOL g_driver_broken
Definition: rdpsnd_oss.c:44
#define index(s, c)
Definition: various.h:29
#define MAX_QUEUE
Definition: rdpsnd_oss.c:38
Definition: parse.h:22
GLenum GLsizei len
Definition: glext.h:6722
int ssize_t
Definition: rosdhcp.h:48
GLdouble s
Definition: gl.h:2039
static unsigned int queue_hi
Definition: rdpsnd_oss.c:52
#define close
Definition: acwin.h:74
_Check_return_ char *__cdecl getenv(_In_z_ const char *_VarName)
void rdpsnd_send_completion(RDPCLIENT *This, uint16 tick, uint8 packet_index)
Definition: rdpsnd.c:55
static short g_samplewidth
Definition: rdpsnd_oss.c:43
BOOL wave_out_format_supported(WAVEFORMATEX *pwfx)
Definition: rdpsnd_oss.c:82
unsigned short uint16
Definition: types.h:30
#define O_RDWR
Definition: fcntl.h:36
void wave_out_close(void)
Definition: rdpsnd_oss.c:76
FILE * stderr
#define malloc
Definition: debug_ros.c:4
BOOL wave_out_set_format(WAVEFORMATEX *pwfx)
Definition: rdpsnd_oss.c:95
static struct audio_packet packet_queue[MAX_QUEUE]
char * xstrdup(const char *s)
Definition: uimain.c:768
#define memset(x, y, z)
Definition: compat.h:39
char data[MTU]
Definition: ipreceive.c:8
void wave_out_volume(uint16 left, uint16 right)
Definition: rdpsnd_oss.c:170