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
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.
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.
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.
23 This is a workaround for Esound bug 312665.
24 FIXME: Remove this when Esound is fixed.
26 #ifdef _FILE_OFFSET_BITS
27 #undef _FILE_OFFSET_BITS
35 #include <sys/ioctl.h>
36 #include <sys/soundcard.h>
41 BOOL This
->dsp_bu
= False
;
42 static int g_snd_rate
;
43 static short g_samplewidth
;
44 static BOOL g_driver_broken
= False
;
46 static struct audio_packet
51 } packet_queue
[MAX_QUEUE
];
52 static unsigned int queue_hi
, queue_lo
;
57 char *dsp_dev
= getenv("AUDIODEV");
61 dsp_dev
= xstrdup("/dev/dsp");
64 if ((This
->dsp_
= open(dsp_dev
, O_WRONLY
| O_NONBLOCK
)) == -1)
70 /* Non-blocking so that user interface is responsive */
71 fcntl(This
->dsp_
, F_SETFL
, fcntl(This
->dsp_
, F_GETFL
) | O_NONBLOCK
);
82 wave_out_format_supported(WAVEFORMATEX
* pwfx
)
84 if (pwfx
->wFormatTag
!= WAVE_FORMAT_PCM
)
86 if ((pwfx
->nChannels
!= 1) && (pwfx
->nChannels
!= 2))
88 if ((pwfx
->wBitsPerSample
!= 8) && (pwfx
->wBitsPerSample
!= 16))
95 wave_out_set_format(WAVEFORMATEX
* pwfx
)
97 int stereo
, format
, fragments
;
99 ioctl(This
->dsp_
, SNDCTL_DSP_RESET
, NULL
);
100 ioctl(This
->dsp_
, SNDCTL_DSP_SYNC
, NULL
);
102 if (pwfx
->wBitsPerSample
== 8)
104 else if (pwfx
->wBitsPerSample
== 16)
105 format
= AFMT_S16_LE
;
107 g_samplewidth
= pwfx
->wBitsPerSample
/ 8;
109 if (ioctl(This
->dsp_
, SNDCTL_DSP_SETFMT
, &format
) == -1)
111 perror("SNDCTL_DSP_SETFMT");
116 if (pwfx
->nChannels
== 2)
126 if (ioctl(This
->dsp_
, SNDCTL_DSP_STEREO
, &stereo
) == -1)
128 perror("SNDCTL_DSP_CHANNELS");
133 g_snd_rate
= pwfx
->nSamplesPerSec
;
134 if (ioctl(This
->dsp_
, SNDCTL_DSP_SPEED
, &g_snd_rate
) == -1)
136 perror("SNDCTL_DSP_SPEED");
141 /* try to get 7 fragments of 2^12 bytes size */
142 fragments
= (7 << 16) + 12;
143 ioctl(This
->dsp_
, SNDCTL_DSP_SETFRAGMENT
, &fragments
);
145 if (!g_driver_broken
)
149 memset(&info
, 0, sizeof(info
));
150 if (ioctl(This
->dsp_
, SNDCTL_DSP_GETOSPACE
, &info
) == -1)
152 perror("SNDCTL_DSP_GETOSPACE");
157 if (info
.fragments
== 0 || info
.fragstotal
== 0 || info
.fragsize
== 0)
160 "Broken OSS-driver detected: fragments: %d, fragstotal: %d, fragsize: %d\n",
161 info
.fragments
, info
.fragstotal
, info
.fragsize
);
162 g_driver_broken
= True
;
170 wave_out_volume(uint16 left
, uint16 right
)
172 static BOOL use_dev_mixer
= False
;
176 volume
= left
/ (65536 / 100);
177 volume
|= right
/ (65536 / 100) << 8;
181 if ((fd_mix
= open("/dev/mixer", O_RDWR
| O_NONBLOCK
)) == -1)
183 perror("open /dev/mixer");
187 if (ioctl(fd_mix
, MIXER_WRITE(SOUND_MIXER_PCM
), &volume
) == -1)
189 perror("MIXER_WRITE(SOUND_MIXER_PCM)");
196 if (ioctl(This
->dsp_
, MIXER_WRITE(SOUND_MIXER_PCM
), &volume
) == -1)
198 perror("MIXER_WRITE(SOUND_MIXER_PCM)");
199 use_dev_mixer
= True
;
205 wave_out_write(STREAM s
, uint16 tick
, uint8 index
)
207 struct audio_packet
*packet
= &packet_queue
[queue_hi
];
208 unsigned int next_hi
= (queue_hi
+ 1) % MAX_QUEUE
;
210 if (next_hi
== queue_lo
)
212 error("No space to queue audio packet\n");
220 packet
->index
= index
;
223 /* we steal the data buffer from s, give it a new one */
224 s
->data
= (uint8
*) malloc(s
->size
);
233 struct audio_packet
*packet
;
236 static long startedat_us
;
237 static long startedat_s
;
238 static BOOL started
= False
;
244 if (queue_lo
== queue_hi
)
250 packet
= &packet_queue
[queue_lo
];
255 gettimeofday(&tv
, NULL
);
256 startedat_us
= tv
.tv_usec
;
257 startedat_s
= tv
.tv_sec
;
261 len
= out
->end
- out
->p
;
263 if (!g_driver_broken
)
265 memset(&info
, 0, sizeof(info
));
266 if (ioctl(This
->dsp_
, SNDCTL_DSP_GETOSPACE
, &info
) == -1)
268 perror("SNDCTL_DSP_GETOSPACE");
272 if (info
.fragments
== 0)
278 if (info
.fragments
* info
.fragsize
< len
279 && info
.fragments
* info
.fragsize
> 0)
281 len
= info
.fragments
* info
.fragsize
;
286 len
= write(This
->dsp_
, out
->p
, len
);
289 if (errno
!= EWOULDBLOCK
)
290 perror("write audio");
296 if (out
->p
== out
->end
)
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
);
305 if (elapsed
>= (duration
* 85) / 100)
307 rdpsnd_send_completion(packet
->tick
, packet
->index
);
309 queue_lo
= (queue_lo
+ 1) % MAX_QUEUE
;