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