34 |
#define RDPSND_PING 6 |
#define RDPSND_PING 6 |
35 |
#define RDPSND_NEGOTIATE 7 |
#define RDPSND_NEGOTIATE 7 |
36 |
|
|
37 |
|
#define RDPSND_REC_NEGOTIATE 39 |
38 |
|
#define RDPSND_REC_START 40 |
39 |
|
#define RDPSND_REC_STOP 41 |
40 |
|
#define RDPSND_REC_DATA 42 |
41 |
|
#define RDPSND_REC_SET_VOLUME 43 |
42 |
|
|
43 |
|
#define RDPSND_FLAG_RECORD 0x00800000 |
44 |
|
|
45 |
#define MAX_FORMATS 10 |
#define MAX_FORMATS 10 |
46 |
#define MAX_QUEUE 10 |
#define MAX_QUEUE 50 |
47 |
|
|
48 |
static VCHANNEL *rdpsnd_channel; |
static VCHANNEL *rdpsnd_channel; |
49 |
|
static VCHANNEL *rdpsnddbg_channel; |
50 |
static struct audio_driver *drivers = NULL; |
static struct audio_driver *drivers = NULL; |
51 |
struct audio_driver *current_driver = NULL; |
struct audio_driver *current_driver = NULL; |
52 |
|
|
53 |
static BOOL device_open; |
static BOOL device_open; |
54 |
|
static BOOL rec_device_open; |
55 |
|
|
56 |
static WAVEFORMATEX formats[MAX_FORMATS]; |
static WAVEFORMATEX formats[MAX_FORMATS]; |
57 |
static unsigned int format_count; |
static unsigned int format_count; |
58 |
static unsigned int current_format; |
static unsigned int current_format; |
59 |
|
|
60 |
|
static WAVEFORMATEX rec_formats[MAX_FORMATS]; |
61 |
|
static unsigned int rec_format_count; |
62 |
|
|
63 |
unsigned int queue_hi, queue_lo, queue_pending; |
unsigned int queue_hi, queue_lo, queue_pending; |
64 |
struct audio_packet packet_queue[MAX_QUEUE]; |
struct audio_packet packet_queue[MAX_QUEUE]; |
65 |
|
|
66 |
|
static char record_buffer[8192]; |
67 |
|
static int record_buffer_size; |
68 |
|
|
69 |
static uint8 packet_opcode; |
static uint8 packet_opcode; |
70 |
static struct stream packet; |
static struct stream packet; |
71 |
|
|
109 |
(unsigned) tick, (unsigned) packet_index)); |
(unsigned) tick, (unsigned) packet_index)); |
110 |
} |
} |
111 |
|
|
112 |
|
static void |
113 |
|
rdpsnd_flush_record(void) |
114 |
|
{ |
115 |
|
STREAM s; |
116 |
|
unsigned int chunk_size; |
117 |
|
char *data; |
118 |
|
|
119 |
|
if (record_buffer_size == 0) |
120 |
|
return; |
121 |
|
|
122 |
|
assert(record_buffer_size <= sizeof(record_buffer)); |
123 |
|
|
124 |
|
data = record_buffer; |
125 |
|
|
126 |
|
/* |
127 |
|
* Microsoft's RDP server keeps dropping chunks, so we need to |
128 |
|
* transmit everything inside one channel fragment or we risk |
129 |
|
* making the rdpsnd server go out of sync with the byte stream. |
130 |
|
*/ |
131 |
|
while (record_buffer_size) |
132 |
|
{ |
133 |
|
if (record_buffer_size < 1596) |
134 |
|
chunk_size = record_buffer_size; |
135 |
|
else |
136 |
|
chunk_size = 1596; |
137 |
|
|
138 |
|
s = rdpsnd_init_packet(RDPSND_REC_DATA, chunk_size); |
139 |
|
out_uint8p(s, data, chunk_size); |
140 |
|
|
141 |
|
s_mark_end(s); |
142 |
|
rdpsnd_send(s); |
143 |
|
|
144 |
|
data = data + chunk_size; |
145 |
|
record_buffer_size -= chunk_size; |
146 |
|
|
147 |
|
DEBUG_SOUND(("RDPSND: -> RDPSND_REC_DATA(length: %u)\n", (unsigned) chunk_size)); |
148 |
|
} |
149 |
|
|
150 |
|
record_buffer_size = 0; |
151 |
|
} |
152 |
|
|
153 |
|
void |
154 |
|
rdpsnd_record(const void *data, unsigned int size) |
155 |
|
{ |
156 |
|
int remain; |
157 |
|
|
158 |
|
assert(rec_device_open); |
159 |
|
|
160 |
|
while (size) |
161 |
|
{ |
162 |
|
remain = sizeof(record_buffer) - record_buffer_size; |
163 |
|
|
164 |
|
if (size >= remain) |
165 |
|
{ |
166 |
|
memcpy(record_buffer + record_buffer_size, data, remain); |
167 |
|
record_buffer_size += remain; |
168 |
|
rdpsnd_flush_record(); |
169 |
|
data = (const char *) data + remain; |
170 |
|
size -= remain; |
171 |
|
} |
172 |
|
else |
173 |
|
{ |
174 |
|
memcpy(record_buffer + record_buffer_size, data, size); |
175 |
|
record_buffer_size += size; |
176 |
|
size = 0; |
177 |
|
} |
178 |
|
} |
179 |
|
} |
180 |
|
|
181 |
static BOOL |
static BOOL |
182 |
rdpsnd_auto_select(void) |
rdpsnd_auto_select(void) |
273 |
} |
} |
274 |
|
|
275 |
out = rdpsnd_init_packet(RDPSND_NEGOTIATE | 0x200, 20 + 18 * format_count); |
out = rdpsnd_init_packet(RDPSND_NEGOTIATE | 0x200, 20 + 18 * format_count); |
276 |
out_uint32_le(out, 3); /* flags */ |
out_uint32_le(out, 0x00800003); /* flags */ |
277 |
out_uint32(out, 0xffffffff); /* volume */ |
out_uint32(out, 0xffffffff); /* volume */ |
278 |
out_uint32(out, 0); /* pitch */ |
out_uint32(out, 0); /* pitch */ |
279 |
out_uint16(out, 0); /* UDP port */ |
out_uint16(out, 0); /* UDP port */ |
322 |
} |
} |
323 |
|
|
324 |
static void |
static void |
325 |
|
rdpsnd_process_rec_negotiate(STREAM in) |
326 |
|
{ |
327 |
|
uint16 in_format_count, i; |
328 |
|
uint16 version; |
329 |
|
WAVEFORMATEX *format; |
330 |
|
STREAM out; |
331 |
|
BOOL device_available = False; |
332 |
|
int readcnt; |
333 |
|
int discardcnt; |
334 |
|
|
335 |
|
in_uint8s(in, 8); /* initial bytes not valid from server */ |
336 |
|
in_uint16_le(in, in_format_count); |
337 |
|
in_uint16_le(in, version); |
338 |
|
|
339 |
|
DEBUG_SOUND(("RDPSND: RDPSND_REC_NEGOTIATE(formats: %d, version: %x)\n", |
340 |
|
(int) in_format_count, (unsigned) version)); |
341 |
|
|
342 |
|
if (!current_driver) |
343 |
|
device_available = rdpsnd_auto_select(); |
344 |
|
|
345 |
|
if (current_driver && !device_available && current_driver->wave_in_open |
346 |
|
&& current_driver->wave_in_open()) |
347 |
|
{ |
348 |
|
current_driver->wave_in_close(); |
349 |
|
device_available = True; |
350 |
|
} |
351 |
|
|
352 |
|
rec_format_count = 0; |
353 |
|
if (s_check_rem(in, 18 * in_format_count)) |
354 |
|
{ |
355 |
|
for (i = 0; i < in_format_count; i++) |
356 |
|
{ |
357 |
|
format = &rec_formats[rec_format_count]; |
358 |
|
in_uint16_le(in, format->wFormatTag); |
359 |
|
in_uint16_le(in, format->nChannels); |
360 |
|
in_uint32_le(in, format->nSamplesPerSec); |
361 |
|
in_uint32_le(in, format->nAvgBytesPerSec); |
362 |
|
in_uint16_le(in, format->nBlockAlign); |
363 |
|
in_uint16_le(in, format->wBitsPerSample); |
364 |
|
in_uint16_le(in, format->cbSize); |
365 |
|
|
366 |
|
/* read in the buffer of unknown use */ |
367 |
|
readcnt = format->cbSize; |
368 |
|
discardcnt = 0; |
369 |
|
if (format->cbSize > MAX_CBSIZE) |
370 |
|
{ |
371 |
|
fprintf(stderr, "cbSize too large for buffer: %d\n", |
372 |
|
format->cbSize); |
373 |
|
readcnt = MAX_CBSIZE; |
374 |
|
discardcnt = format->cbSize - MAX_CBSIZE; |
375 |
|
} |
376 |
|
in_uint8a(in, format->cb, readcnt); |
377 |
|
in_uint8s(in, discardcnt); |
378 |
|
|
379 |
|
if (device_available && current_driver->wave_in_format_supported(format)) |
380 |
|
{ |
381 |
|
rec_format_count++; |
382 |
|
if (rec_format_count == MAX_FORMATS) |
383 |
|
break; |
384 |
|
} |
385 |
|
} |
386 |
|
} |
387 |
|
|
388 |
|
out = rdpsnd_init_packet(RDPSND_REC_NEGOTIATE, 12 + 18 * rec_format_count); |
389 |
|
out_uint32_le(out, 0x00000000); /* flags */ |
390 |
|
out_uint32_le(out, 0xffffffff); /* volume */ |
391 |
|
out_uint16_le(out, rec_format_count); |
392 |
|
out_uint16_le(out, 1); /* version */ |
393 |
|
|
394 |
|
for (i = 0; i < rec_format_count; i++) |
395 |
|
{ |
396 |
|
format = &rec_formats[i]; |
397 |
|
out_uint16_le(out, format->wFormatTag); |
398 |
|
out_uint16_le(out, format->nChannels); |
399 |
|
out_uint32_le(out, format->nSamplesPerSec); |
400 |
|
out_uint32_le(out, format->nAvgBytesPerSec); |
401 |
|
out_uint16_le(out, format->nBlockAlign); |
402 |
|
out_uint16_le(out, format->wBitsPerSample); |
403 |
|
out_uint16(out, 0); /* cbSize */ |
404 |
|
} |
405 |
|
|
406 |
|
s_mark_end(out); |
407 |
|
|
408 |
|
DEBUG_SOUND(("RDPSND: -> RDPSND_REC_NEGOTIATE(formats: %d)\n", (int) rec_format_count)); |
409 |
|
|
410 |
|
rdpsnd_send(out); |
411 |
|
} |
412 |
|
|
413 |
|
static void |
414 |
rdpsnd_process_packet(uint8 opcode, STREAM s) |
rdpsnd_process_packet(uint8 opcode, STREAM s) |
415 |
{ |
{ |
416 |
uint16 vol_left, vol_right; |
uint16 vol_left, vol_right; |
484 |
if (device_open) |
if (device_open) |
485 |
current_driver->wave_out_volume(vol_left, vol_right); |
current_driver->wave_out_volume(vol_left, vol_right); |
486 |
break; |
break; |
487 |
|
case RDPSND_REC_NEGOTIATE: |
488 |
|
rdpsnd_process_rec_negotiate(s); |
489 |
|
break; |
490 |
|
case RDPSND_REC_START: |
491 |
|
in_uint16_le(s, format); |
492 |
|
DEBUG_SOUND(("RDPSND: RDPSND_REC_START(format: %u)\n", (unsigned) format)); |
493 |
|
|
494 |
|
if (format >= MAX_FORMATS) |
495 |
|
{ |
496 |
|
error("RDPSND: Invalid format index\n"); |
497 |
|
break; |
498 |
|
} |
499 |
|
|
500 |
|
if (rec_device_open) |
501 |
|
{ |
502 |
|
error("RDPSND: Multiple RDPSND_REC_START\n"); |
503 |
|
break; |
504 |
|
} |
505 |
|
|
506 |
|
if (!current_driver->wave_in_open()) |
507 |
|
break; |
508 |
|
|
509 |
|
if (!current_driver->wave_in_set_format(&rec_formats[format])) |
510 |
|
{ |
511 |
|
error("RDPSND: Device not accepting format\n"); |
512 |
|
current_driver->wave_in_close(); |
513 |
|
break; |
514 |
|
} |
515 |
|
rec_device_open = True; |
516 |
|
break; |
517 |
|
case RDPSND_REC_STOP: |
518 |
|
DEBUG_SOUND(("RDPSND: RDPSND_REC_STOP()\n")); |
519 |
|
rdpsnd_flush_record(); |
520 |
|
if (rec_device_open) |
521 |
|
current_driver->wave_in_close(); |
522 |
|
rec_device_open = False; |
523 |
|
break; |
524 |
|
case RDPSND_REC_SET_VOLUME: |
525 |
|
in_uint16_le(s, vol_left); |
526 |
|
in_uint16_le(s, vol_right); |
527 |
|
DEBUG_SOUND(("RDPSND: RDPSND_REC_VOLUME(left: 0x%04x (%u %%), right: 0x%04x (%u %%))\n", (unsigned) vol_left, (unsigned) vol_left / 655, (unsigned) vol_right, (unsigned) vol_right / 655)); |
528 |
|
if (rec_device_open) |
529 |
|
current_driver->wave_in_volume(vol_left, vol_right); |
530 |
|
break; |
531 |
default: |
default: |
532 |
unimpl("RDPSND packet type %x\n", opcode); |
unimpl("RDPSND packet type %x\n", opcode); |
533 |
break; |
break; |
592 |
} |
} |
593 |
} |
} |
594 |
|
|
595 |
|
static BOOL |
596 |
|
rdpsnddbg_line_handler(const char *line, void *data) |
597 |
|
{ |
598 |
|
#ifdef WITH_DEBUG_SOUND |
599 |
|
fprintf(stderr, "SNDDBG: %s\n", line); |
600 |
|
#endif |
601 |
|
return True; |
602 |
|
} |
603 |
|
|
604 |
|
static void |
605 |
|
rdpsnddbg_process(STREAM s) |
606 |
|
{ |
607 |
|
unsigned int pkglen; |
608 |
|
static char *rest = NULL; |
609 |
|
char *buf; |
610 |
|
|
611 |
|
pkglen = s->end - s->p; |
612 |
|
/* str_handle_lines requires null terminated strings */ |
613 |
|
buf = xmalloc(pkglen + 1); |
614 |
|
STRNCPY(buf, (char *) s->p, pkglen + 1); |
615 |
|
|
616 |
|
str_handle_lines(buf, &rest, rdpsnddbg_line_handler, NULL); |
617 |
|
|
618 |
|
xfree(buf); |
619 |
|
} |
620 |
|
|
621 |
static void |
static void |
622 |
rdpsnd_register_drivers(char *options) |
rdpsnd_register_drivers(char *options) |
623 |
{ |
{ |
670 |
channel_register("rdpsnd", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP, |
channel_register("rdpsnd", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP, |
671 |
rdpsnd_process); |
rdpsnd_process); |
672 |
|
|
673 |
if (rdpsnd_channel == NULL) |
rdpsnddbg_channel = |
674 |
|
channel_register("snddbg", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP, |
675 |
|
rdpsnddbg_process); |
676 |
|
|
677 |
|
if ((rdpsnd_channel == NULL) || (rdpsnddbg_channel == NULL)) |
678 |
{ |
{ |
679 |
error("channel_register\n"); |
error("channel_register\n"); |
680 |
return False; |
return False; |
738 |
{ |
{ |
739 |
long next_pending; |
long next_pending; |
740 |
|
|
741 |
if (device_open) |
if (device_open || rec_device_open) |
742 |
current_driver->add_fds(n, rfds, wfds, tv); |
current_driver->add_fds(n, rfds, wfds, tv); |
743 |
|
|
744 |
next_pending = rdpsnd_queue_next_completion(); |
next_pending = rdpsnd_queue_next_completion(); |
760 |
{ |
{ |
761 |
rdpsnd_queue_complete_pending(); |
rdpsnd_queue_complete_pending(); |
762 |
|
|
763 |
if (device_open) |
if (device_open || rec_device_open) |
764 |
current_driver->check_fds(rfds, wfds); |
current_driver->check_fds(rfds, wfds); |
765 |
} |
} |
766 |
|
|