-revert janderwalds change until because it breaks the gcc 4.x build
[reactos.git] / reactos / base / applications / tsclient / rdesktop / rdpsnd.c
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
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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 }