~ubuntu-branches/ubuntu/dapper/rdesktop/dapper

« back to all changes in this revision

Viewing changes to rdpsnd.c

  • Committer: Bazaar Package Importer
  • Author(s): Sam Johnston
  • Date: 2004-02-04 17:52:26 UTC
  • Revision ID: james.westby@ubuntu.com-20040204175226-87kz4bzs1nimji68
Tags: upstream-1.3.1
ImportĀ upstreamĀ versionĀ 1.3.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
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_UNKNOWN6         6
 
30
#define RDPSND_NEGOTIATE        7
 
31
 
 
32
#define MAX_FORMATS             10
 
33
 
 
34
static VCHANNEL *rdpsnd_channel;
 
35
 
 
36
static BOOL device_open;
 
37
static WAVEFORMATEX formats[MAX_FORMATS];
 
38
static unsigned int format_count;
 
39
static unsigned int current_format;
 
40
 
 
41
STREAM
 
42
rdpsnd_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
 
 
52
void
 
53
rdpsnd_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
 
 
63
void
 
64
rdpsnd_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
 
 
76
void
 
77
rdpsnd_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
 
 
159
void
 
160
rdpsnd_process_unknown6(STREAM in)
 
161
{
 
162
        uint16 unknown1, unknown2;
 
163
        STREAM out;
 
164
 
 
165
        /* in_uint8s(in, 4); unknown */
 
166
        in_uint16_le(in, unknown1);
 
167
        in_uint16_le(in, unknown2);
 
168
 
 
169
        out = rdpsnd_init_packet(RDPSND_UNKNOWN6 | 0x2300, 4);
 
170
        out_uint16_le(out, unknown1);
 
171
        out_uint16_le(out, unknown2);
 
172
        s_mark_end(out);
 
173
        rdpsnd_send(out);
 
174
}
 
175
 
 
176
void
 
177
rdpsnd_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_UNKNOWN6:
 
242
                        rdpsnd_process_unknown6(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
 
 
257
BOOL
 
258
rdpsnd_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
}