1 /* -*- c-basic-offset: 8 -*-
2    rdesktop: A Remote Desktop Protocol client.
3    Sound Channel Process Functions
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 #include "rdesktop.h"
23 
24 #define RDPSND_CLOSE		1
25 #define RDPSND_WRITE		2
26 #define RDPSND_SET_VOLUME	3
27 #define RDPSND_UNKNOWN4		4
28 #define RDPSND_COMPLETION	5
29 #define RDPSND_SERVERTICK	6
30 #define RDPSND_NEGOTIATE	7
31 
32 static STREAM
33 rdpsnd_init_packet(RDPCLIENT * This, uint16 type, uint16 size)
34 {
35 	STREAM s;
36 
37 	s = channel_init(This, This->rdpsnd.channel, size + 4);
38 	out_uint16_le(s, type);
39 	out_uint16_le(s, size);
40 	return s;
41 }
42 
43 static void
44 rdpsnd_send(RDPCLIENT * This, STREAM s)
45 {
46 #ifdef RDPSND_DEBUG
47 	printf("RDPSND send:\n");
48 	hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8);
49 #endif
50 
51 	channel_send(This, s, This->rdpsnd.channel);
52 }
53 
54 void
55 rdpsnd_send_completion(RDPCLIENT * This, uint16 tick, uint8 packet_index)
56 {
57 	STREAM s;
58 
59 	s = rdpsnd_init_packet(This, RDPSND_COMPLETION, 4);
60 	out_uint16_le(s, tick + 50);
61 	out_uint8(s, packet_index);
62 	out_uint8(s, 0);
63 	s_mark_end(s);
64 	rdpsnd_send(This, s);
65 }
66 
67 static void
68 rdpsnd_process_negotiate(RDPCLIENT * This, STREAM in)
69 {
70 	unsigned int in_format_count, i;
71 	WAVEFORMATEX *format;
72 	STREAM out;
73 	BOOL device_available = False;
74 	int readcnt;
75 	int discardcnt;
76 
77 	in_uint8s(in, 14);	/* flags, volume, pitch, UDP port */
78 	in_uint16_le(in, in_format_count);
79 	in_uint8s(in, 4);	/* pad, status, pad */
80 
81 	if (wave_out_open())
82 	{
83 		wave_out_close();
84 		device_available = True;
85 	}
86 
87 	This->rdpsnd.format_count = 0;
88 	if (s_check_rem(in, 18 * in_format_count))
89 	{
90 		for (i = 0; i < in_format_count; i++)
91 		{
92 			format = &This->rdpsnd.formats[This->rdpsnd.format_count];
93 			in_uint16_le(in, format->wFormatTag);
94 			in_uint16_le(in, format->nChannels);
95 			in_uint32_le(in, format->nSamplesPerSec);
96 			in_uint32_le(in, format->nAvgBytesPerSec);
97 			in_uint16_le(in, format->nBlockAlign);
98 			in_uint16_le(in, format->wBitsPerSample);
99 			in_uint16_le(in, format->cbSize);
100 
101 			/* read in the buffer of unknown use */
102 			readcnt = format->cbSize;
103 			discardcnt = 0;
104 			if (format->cbSize > MAX_CBSIZE)
105 			{
106 				fprintf(stderr, "cbSize too large for buffer: %d\n",
107 					format->cbSize);
108 				readcnt = MAX_CBSIZE;
109 				discardcnt = format->cbSize - MAX_CBSIZE;
110 			}
111 			in_uint8a(in, format->cb, readcnt);
112 			in_uint8s(in, discardcnt);
113 
114 			if (device_available && wave_out_format_supported(format))
115 			{
116 				This->rdpsnd.format_count++;
117 				if (This->rdpsnd.format_count == MAX_FORMATS)
118 					break;
119 			}
120 		}
121 	}
122 
123 	out = rdpsnd_init_packet(This, RDPSND_NEGOTIATE | 0x200, 20 + 18 * This->rdpsnd.format_count);
124 	out_uint32_le(out, 3);	/* flags */
125 	out_uint32(out, 0xffffffff);	/* volume */
126 	out_uint32(out, 0);	/* pitch */
127 	out_uint16(out, 0);	/* UDP port */
128 
129 	out_uint16_le(out, This->rdpsnd.format_count);
130 	out_uint8(out, 0x95);	/* pad? */
131 	out_uint16_le(out, 2);	/* status */
132 	out_uint8(out, 0x77);	/* pad? */
133 
134 	for (i = 0; i < This->rdpsnd.format_count; i++)
135 	{
136 		format = &This->rdpsnd.formats[i];
137 		out_uint16_le(out, format->wFormatTag);
138 		out_uint16_le(out, format->nChannels);
139 		out_uint32_le(out, format->nSamplesPerSec);
140 		out_uint32_le(out, format->nAvgBytesPerSec);
141 		out_uint16_le(out, format->nBlockAlign);
142 		out_uint16_le(out, format->wBitsPerSample);
143 		out_uint16(out, 0);	/* cbSize */
144 	}
145 
146 	s_mark_end(out);
147 	rdpsnd_send(This, out);
148 }
149 
150 static void
151 rdpsnd_process_servertick(RDPCLIENT * This, STREAM in)
152 {
153 	uint16 tick1, tick2;
154 	STREAM out;
155 
156 	/* in_uint8s(in, 4); unknown */
157 	in_uint16_le(in, tick1);
158 	in_uint16_le(in, tick2);
159 
160 	out = rdpsnd_init_packet(This, RDPSND_SERVERTICK | 0x2300, 4);
161 	out_uint16_le(out, tick1);
162 	out_uint16_le(out, tick2);
163 	s_mark_end(out);
164 	rdpsnd_send(This, out);
165 }
166 
167 static void
168 rdpsnd_process(RDPCLIENT * This, STREAM s)
169 {
170 	uint8 type;
171 	uint16 datalen;
172 	uint32 volume;
173 	static uint16 tick, format;
174 	static uint8 packet_index;
175 	static BOOL awaiting_data_packet;
176 
177 #ifdef RDPSND_DEBUG
178 	printf("RDPSND recv:\n");
179 	hexdump(s->p, s->end - s->p);
180 #endif
181 
182 	if (awaiting_data_packet)
183 	{
184 		if (format >= MAX_FORMATS)
185 		{
186 			error("RDPSND: Invalid format index\n");
187 			return;
188 		}
189 
190 		if (!This->rdpsnd.device_open || (format != This->rdpsnd.current_format))
191 		{
192 			if (!This->rdpsnd.device_open && !wave_out_open())
193 			{
194 				rdpsnd_send_completion(This, tick, packet_index);
195 				return;
196 			}
197 			if (!wave_out_set_format(&This->rdpsnd.formats[format]))
198 			{
199 				rdpsnd_send_completion(This, tick, packet_index);
200 				wave_out_close();
201 				This->rdpsnd.device_open = False;
202 				return;
203 			}
204 			This->rdpsnd.device_open = True;
205 			This->rdpsnd.current_format = format;
206 		}
207 
208 		wave_out_write(s, tick, packet_index);
209 		awaiting_data_packet = False;
210 		return;
211 	}
212 
213 	in_uint8(s, type);
214 	in_uint8s(s, 1);	/* unknown? */
215 	in_uint16_le(s, datalen);
216 
217 	switch (type)
218 	{
219 		case RDPSND_WRITE:
220 			in_uint16_le(s, tick);
221 			in_uint16_le(s, format);
222 			in_uint8(s, packet_index);
223 			awaiting_data_packet = True;
224 			break;
225 		case RDPSND_CLOSE:
226 			wave_out_close();
227 			This->rdpsnd.device_open = False;
228 			break;
229 		case RDPSND_NEGOTIATE:
230 			rdpsnd_process_negotiate(This, s);
231 			break;
232 		case RDPSND_SERVERTICK:
233 			rdpsnd_process_servertick(This, s);
234 			break;
235 		case RDPSND_SET_VOLUME:
236 			in_uint32(s, volume);
237 			if (This->rdpsnd.device_open)
238 			{
239 				wave_out_volume((volume & 0xffff), (volume & 0xffff0000) >> 16);
240 			}
241 			break;
242 		default:
243 			unimpl("RDPSND packet type %d\n", type);
244 			break;
245 	}
246 }
247 
248 BOOL
249 rdpsnd_init(RDPCLIENT * This)
250 {
251 	This->rdpsnd.channel =
252 		channel_register(This, "rdpsnd", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP,
253 				 rdpsnd_process);
254 	return (This->rdpsnd.channel != NULL);
255 }
256