Lars Martin Hambro <lars_martin4 AT hotmail DOT com>
[reactos.git] / base / applications / tsclient / rdesktop / rdpsnd_sgi.c
1 /* -*- c-basic-offset: 8 -*-
2 rdesktop: A Remote Desktop Protocol client.
3 Sound Channel Process Functions - SGI/IRIX
4 Copyright (C) Matthew Chapman 2003
5 Copyright (C) GuoJunBo guojunbo@ict.ac.cn 2003
6 Copyright (C) Jeremy Meng void.foo@gmail.com 2004, 2005
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "rdesktop.h"
24 #include <errno.h>
25 #include <dmedia/audio.h>
26
27 /* #define IRIX_DEBUG 1 */
28
29 #define IRIX_MAX_VOL 65535
30
31 #define MAX_QUEUE 10
32
33 int This->dsp_;
34 ALconfig audioconfig;
35 ALport output_port;
36
37 BOOL This->dsp_bu = False;
38 static BOOL g_swapaudio;
39 static int g_snd_rate;
40 static BOOL g_swapaudio;
41 static int width = AL_SAMPLE_16;
42
43 double min_volume, max_volume, volume_range;
44 int resource, maxFillable;
45 int combinedFrameSize;
46
47 static struct audio_packet
48 {
49 struct stream s;
50 uint16 tick;
51 uint8 index;
52 } packet_queue[MAX_QUEUE];
53 static unsigned int queue_hi, queue_lo;
54
55 BOOL
56 wave_out_open(void)
57 {
58 ALparamInfo pinfo;
59
60 #if (defined(IRIX_DEBUG))
61 fprintf(stderr, "wave_out_open: begin\n");
62 #endif
63
64 if (alGetParamInfo(AL_DEFAULT_OUTPUT, AL_GAIN, &pinfo) < 0)
65 {
66 fprintf(stderr, "wave_out_open: alGetParamInfo failed: %s\n",
67 alGetErrorString(oserror()));
68 }
69 min_volume = alFixedToDouble(pinfo.min.ll);
70 max_volume = alFixedToDouble(pinfo.max.ll);
71 volume_range = (max_volume - min_volume);
72 #if (defined(IRIX_DEBUG))
73 fprintf(stderr, "wave_out_open: minvol = %lf, maxvol= %lf, range = %lf.\n",
74 min_volume, max_volume, volume_range);
75 #endif
76
77 queue_lo = queue_hi = 0;
78
79 audioconfig = alNewConfig();
80 if (audioconfig == (ALconfig) 0)
81 {
82 fprintf(stderr, "wave_out_open: alNewConfig failed: %s\n",
83 alGetErrorString(oserror()));
84 return False;
85 }
86
87 output_port = alOpenPort("rdpsnd", "w", 0);
88 if (output_port == (ALport) 0)
89 {
90 fprintf(stderr, "wave_out_open: alOpenPort failed: %s\n",
91 alGetErrorString(oserror()));
92 return False;
93 }
94
95 #if (defined(IRIX_DEBUG))
96 fprintf(stderr, "wave_out_open: returning\n");
97 #endif
98 return True;
99 }
100
101 void
102 wave_out_close(void)
103 {
104 /* Ack all remaining packets */
105 #if (defined(IRIX_DEBUG))
106 fprintf(stderr, "wave_out_close: begin\n");
107 #endif
108
109 while (queue_lo != queue_hi)
110 {
111 rdpsnd_send_completion(packet_queue[queue_lo].tick, packet_queue[queue_lo].index);
112 free(packet_queue[queue_lo].s.data);
113 queue_lo = (queue_lo + 1) % MAX_QUEUE;
114 }
115 alDiscardFrames(output_port, 0);
116
117 alClosePort(output_port);
118 alFreeConfig(audioconfig);
119 #if (defined(IRIX_DEBUG))
120 fprintf(stderr, "wave_out_close: returning\n");
121 #endif
122 }
123
124 BOOL
125 wave_out_format_supported(WAVEFORMATEX * pwfx)
126 {
127 if (pwfx->wFormatTag != WAVE_FORMAT_PCM)
128 return False;
129 if ((pwfx->nChannels != 1) && (pwfx->nChannels != 2))
130 return False;
131 if ((pwfx->wBitsPerSample != 8) && (pwfx->wBitsPerSample != 16))
132 return False;
133
134 return True;
135 }
136
137 BOOL
138 wave_out_set_format(WAVEFORMATEX * pwfx)
139 {
140 int channels;
141 int frameSize, channelCount;
142 ALpv params;
143
144 #if (defined(IRIX_DEBUG))
145 fprintf(stderr, "wave_out_set_format: init...\n");
146 #endif
147
148 g_swapaudio = False;
149 if (pwfx->wBitsPerSample == 8)
150 width = AL_SAMPLE_8;
151 else if (pwfx->wBitsPerSample == 16)
152 {
153 width = AL_SAMPLE_16;
154 /* Do we need to swap the 16bit values? (Are we BigEndian) */
155 #if (defined(B_ENDIAN))
156 g_swapaudio = 1;
157 #else
158 g_swapaudio = 0;
159 #endif
160 }
161
162 /* Limited support to configure an opened audio port in IRIX. The
163 number of channels is a static setting and can not be changed after
164 a port is opened. So if the number of channels remains the same, we
165 can configure other settings; otherwise we have to reopen the audio
166 port, using same config. */
167
168 channels = pwfx->nChannels;
169 g_snd_rate = pwfx->nSamplesPerSec;
170
171 alSetSampFmt(audioconfig, AL_SAMPFMT_TWOSCOMP);
172 alSetWidth(audioconfig, width);
173 if (channels != alGetChannels(audioconfig))
174 {
175 alClosePort(output_port);
176 alSetChannels(audioconfig, channels);
177 output_port = alOpenPort("rdpsnd", "w", audioconfig);
178
179 if (output_port == (ALport) 0)
180 {
181 fprintf(stderr, "wave_out_set_format: alOpenPort failed: %s\n",
182 alGetErrorString(oserror()));
183 return False;
184 }
185
186 }
187
188 resource = alGetResource(output_port);
189 maxFillable = alGetFillable(output_port);
190 channelCount = alGetChannels(audioconfig);
191 frameSize = alGetWidth(audioconfig);
192
193 if (frameSize == 0 || channelCount == 0)
194 {
195 fprintf(stderr, "wave_out_set_format: bad frameSize or channelCount\n");
196 return False;
197 }
198 combinedFrameSize = frameSize * channelCount;
199
200 params.param = AL_RATE;
201 params.value.ll = (long long) g_snd_rate << 32;
202
203 if (alSetParams(resource, &params, 1) < 0)
204 {
205 fprintf(stderr, "wave_set_format: alSetParams failed: %s\n",
206 alGetErrorString(oserror()));
207 return False;
208 }
209 if (params.sizeOut < 0)
210 {
211 fprintf(stderr, "wave_set_format: invalid rate %d\n", g_snd_rate);
212 return False;
213 }
214
215 #if (defined(IRIX_DEBUG))
216 fprintf(stderr, "wave_out_set_format: returning...\n");
217 #endif
218 return True;
219 }
220
221 void
222 wave_out_volume(uint16 left, uint16 right)
223 {
224 double gainleft, gainright;
225 ALpv pv[1];
226 ALfixed gain[8];
227
228 #if (defined(IRIX_DEBUG))
229 fprintf(stderr, "wave_out_volume: begin\n");
230 fprintf(stderr, "left='%d', right='%d'\n", left, right);
231 #endif
232
233 gainleft = (double) left / IRIX_MAX_VOL;
234 gainright = (double) right / IRIX_MAX_VOL;
235
236 gain[0] = alDoubleToFixed(min_volume + gainleft * volume_range);
237 gain[1] = alDoubleToFixed(min_volume + gainright * volume_range);
238
239 pv[0].param = AL_GAIN;
240 pv[0].value.ptr = gain;
241 pv[0].sizeIn = 8;
242 if (alSetParams(AL_DEFAULT_OUTPUT, pv, 1) < 0)
243 {
244 fprintf(stderr, "wave_out_volume: alSetParams failed: %s\n",
245 alGetErrorString(oserror()));
246 return;
247 }
248
249 #if (defined(IRIX_DEBUG))
250 fprintf(stderr, "wave_out_volume: returning\n");
251 #endif
252 }
253
254 void
255 wave_out_write(STREAM s, uint16 tick, uint8 index)
256 {
257 struct audio_packet *packet = &packet_queue[queue_hi];
258 unsigned int next_hi = (queue_hi + 1) % MAX_QUEUE;
259
260 if (next_hi == queue_lo)
261 {
262 fprintf(stderr, "No space to queue audio packet\n");
263 return;
264 }
265
266 queue_hi = next_hi;
267
268 packet->s = *s;
269 packet->tick = tick;
270 packet->index = index;
271 packet->s.p += 4;
272
273 /* we steal the data buffer from s, give it a new one */
274 s->data = malloc(s->size);
275
276 if (!This->dsp_bu)
277 wave_out_play();
278 }
279
280 void
281 wave_out_play(void)
282 {
283 struct audio_packet *packet;
284 ssize_t len;
285 unsigned int i;
286 uint8 swap;
287 STREAM out;
288 static BOOL swapped = False;
289 int gf;
290
291 while (1)
292 {
293 if (queue_lo == queue_hi)
294 {
295 This->dsp_bu = False;
296 return;
297 }
298
299 packet = &packet_queue[queue_lo];
300 out = &packet->s;
301
302 /* Swap the current packet, but only once */
303 if (g_swapaudio && !swapped)
304 {
305 for (i = 0; i < out->end - out->p; i += 2)
306 {
307 swap = *(out->p + i);
308 *(out->p + i) = *(out->p + i + 1);
309 *(out->p + i + 1) = swap;
310 }
311 swapped = True;
312 }
313
314 len = out->end - out->p;
315
316 alWriteFrames(output_port, out->p, len / combinedFrameSize);
317
318 out->p += len;
319 if (out->p == out->end)
320 {
321 gf = alGetFilled(output_port);
322 if (gf < (4 * maxFillable / 10))
323 {
324 rdpsnd_send_completion(packet->tick, packet->index);
325 free(out->data);
326 queue_lo = (queue_lo + 1) % MAX_QUEUE;
327 swapped = False;
328 }
329 else
330 {
331 #if (defined(IRIX_DEBUG))
332 /* fprintf(stderr,"Busy playing...\n"); */
333 #endif
334 This->dsp_bu = True;
335 usleep(10);
336 return;
337 }
338 }
339 }
340 }