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 along
19    with this program; if not, write to the Free Software Foundation, Inc.,
20    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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
wave_out_open(void)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
wave_out_close(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
wave_out_format_supported(WAVEFORMATEX * pwfx)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
wave_out_set_format(WAVEFORMATEX * pwfx)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
wave_out_volume(uint16 left,uint16 right)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
wave_out_write(STREAM s,uint16 tick,uint8 index)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
wave_out_play(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 }
341