VirtualBox

source: vbox/trunk/src/VBox/RDP/client/rdpsnd.c@ 9580

Last change on this file since 9580 was 7826, checked in by vboxsync, 17 years ago

Export modified rdesktop version including USB support to OSE. It's GPL anyway.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette