CVS: rdesktop proto.h, 1.103, 1.104 rdpsnd.c, 1.35, 1.36 rdpsnd.h, 1.9, 1.10
Pierre Ossman <[email protected]> Tue, 02 Jan 2007 08:30:09 -0800
| Newsgroups | gmane.network.rdesktop.cvs |
|---|---|
| Message-ID | <[email protected]> |
Update of /cvsroot/rdesktop/rdesktop
In directory sc8-pr-cvs9.sourceforge.net:/tmp/cvs-serv14187
Modified Files:
proto.h rdpsnd.c rdpsnd.h
Log Message:
Add experimental extension to the RDPSND protocol that allows recording.
Index: proto.h
===================================================================
RCS file: /cvsroot/rdesktop/rdesktop/proto.h,v
retrieving revision 1.103
retrieving revision 1.104
diff -C2 -d -r1.103 -r1.104
*** proto.h 7 Dec 2006 15:23:45 -0000 1.103
--- proto.h 2 Jan 2007 16:30:06 -0000 1.104
***************
*** 167,170 ****
--- 167,171 ----
BOOL rdpdr_abort_io(uint32 fd, uint32 major, NTSTATUS status);
/* rdpsnd.c */
+ void rdpsnd_record(const void *data, unsigned int size);
BOOL rdpsnd_init(char *optarg);
void rdpsnd_show_help(void);
Index: rdpsnd.c
===================================================================
RCS file: /cvsroot/rdesktop/rdesktop/rdpsnd.c,v
retrieving revision 1.35
retrieving revision 1.36
diff -C2 -d -r1.35 -r1.36
*** rdpsnd.c 24 Dec 2006 15:22:15 -0000 1.35
--- rdpsnd.c 2 Jan 2007 16:30:06 -0000 1.36
***************
*** 35,52 ****
#define RDPSND_NEGOTIATE 7
#define MAX_FORMATS 10
! #define MAX_QUEUE 10
static VCHANNEL *rdpsnd_channel;
static struct audio_driver *drivers = NULL;
struct audio_driver *current_driver = NULL;
static BOOL device_open;
static WAVEFORMATEX formats[MAX_FORMATS];
static unsigned int format_count;
static unsigned int current_format;
unsigned int queue_hi, queue_lo, queue_pending;
struct audio_packet packet_queue[MAX_QUEUE];
static uint8 packet_opcode;
static struct stream packet;
--- 35,70 ----
#define RDPSND_NEGOTIATE 7
+ #define RDPSND_REC_NEGOTIATE 39
+ #define RDPSND_REC_START 40
+ #define RDPSND_REC_STOP 41
+ #define RDPSND_REC_DATA 42
+ #define RDPSND_REC_SET_VOLUME 43
+
+ #define RDPSND_FLAG_RECORD 0x00800000
+
#define MAX_FORMATS 10
! #define MAX_QUEUE 50
static VCHANNEL *rdpsnd_channel;
+ static VCHANNEL *rdpsnddbg_channel;
static struct audio_driver *drivers = NULL;
struct audio_driver *current_driver = NULL;
static BOOL device_open;
+ static BOOL rec_device_open;
+
static WAVEFORMATEX formats[MAX_FORMATS];
static unsigned int format_count;
static unsigned int current_format;
+
+ static WAVEFORMATEX rec_formats[MAX_FORMATS];
+ static unsigned int rec_format_count;
+
unsigned int queue_hi, queue_lo, queue_pending;
struct audio_packet packet_queue[MAX_QUEUE];
+ static char record_buffer[8192];
+ static int record_buffer_size;
+
static uint8 packet_opcode;
static struct stream packet;
***************
*** 92,95 ****
--- 110,181 ----
}
+ static void
+ rdpsnd_flush_record(void)
+ {
+ STREAM s;
+ unsigned int chunk_size;
+ char *data;
+
+ if (record_buffer_size == 0)
+ return;
+
+ assert(record_buffer_size <= sizeof(record_buffer));
+
+ data = record_buffer;
+
+ /*
+ * Microsoft's RDP server keeps dropping chunks, so we need to
+ * transmit everything inside one channel fragment or we risk
+ * making the rdpsnd server go out of sync with the byte stream.
+ */
+ while (record_buffer_size)
+ {
+ if (record_buffer_size < 1596)
+ chunk_size = record_buffer_size;
+ else
+ chunk_size = 1596;
+
+ s = rdpsnd_init_packet(RDPSND_REC_DATA, chunk_size);
+ out_uint8p(s, data, chunk_size);
+
+ s_mark_end(s);
+ rdpsnd_send(s);
+
+ data = data + chunk_size;
+ record_buffer_size -= chunk_size;
+
+ DEBUG_SOUND(("RDPSND: -> RDPSND_REC_DATA(length: %u)\n", (unsigned) chunk_size));
+ }
+
+ record_buffer_size = 0;
+ }
+
+ void
+ rdpsnd_record(const void *data, unsigned int size)
+ {
+ int remain;
+
+ assert(rec_device_open);
+
+ while (size)
+ {
+ remain = sizeof(record_buffer) - record_buffer_size;
+
+ if (size >= remain)
+ {
+ memcpy(record_buffer + record_buffer_size, data, remain);
+ record_buffer_size += remain;
+ rdpsnd_flush_record();
+ data = (const char *) data + remain;
+ size -= remain;
+ }
+ else
+ {
+ memcpy(record_buffer + record_buffer_size, data, size);
+ record_buffer_size += size;
+ size = 0;
+ }
+ }
+ }
static BOOL
***************
*** 188,192 ****
out = rdpsnd_init_packet(RDPSND_NEGOTIATE | 0x200, 20 + 18 * format_count);
! out_uint32_le(out, 3); /* flags */
out_uint32(out, 0xffffffff); /* volume */
out_uint32(out, 0); /* pitch */
--- 274,278 ----
out = rdpsnd_init_packet(RDPSND_NEGOTIATE | 0x200, 20 + 18 * format_count);
! out_uint32_le(out, 0x00800003); /* flags */
out_uint32(out, 0xffffffff); /* volume */
out_uint32(out, 0); /* pitch */
***************
*** 237,240 ****
--- 323,415 ----
static void
+ rdpsnd_process_rec_negotiate(STREAM in)
+ {
+ uint16 in_format_count, i;
+ uint16 version;
+ WAVEFORMATEX *format;
+ STREAM out;
+ BOOL device_available = False;
+ int readcnt;
+ int discardcnt;
+
+ in_uint8s(in, 8); /* initial bytes not valid from server */
+ in_uint16_le(in, in_format_count);
+ in_uint16_le(in, version);
+
+ DEBUG_SOUND(("RDPSND: RDPSND_REC_NEGOTIATE(formats: %d, version: %x)\n",
+ (int) in_format_count, (unsigned) version));
+
+ if (!current_driver)
+ device_available = rdpsnd_auto_select();
+
+ if (current_driver && !device_available && current_driver->wave_in_open
+ && current_driver->wave_in_open())
+ {
+ current_driver->wave_in_close();
+ device_available = True;
+ }
+
+ rec_format_count = 0;
+ if (s_check_rem(in, 18 * in_format_count))
+ {
+ for (i = 0; i < in_format_count; i++)
+ {
+ format = &rec_formats[rec_format_count];
+ in_uint16_le(in, format->wFormatTag);
+ in_uint16_le(in, format->nChannels);
+ in_uint32_le(in, format->nSamplesPerSec);
+ in_uint32_le(in, format->nAvgBytesPerSec);
+ in_uint16_le(in, format->nBlockAlign);
+ in_uint16_le(in, format->wBitsPerSample);
+ in_uint16_le(in, format->cbSize);
+
+ /* read in the buffer of unknown use */
+ readcnt = format->cbSize;
+ discardcnt = 0;
+ if (format->cbSize > MAX_CBSIZE)
+ {
+ fprintf(stderr, "cbSize too large for buffer: %d\n",
+ format->cbSize);
+ readcnt = MAX_CBSIZE;
+ discardcnt = format->cbSize - MAX_CBSIZE;
+ }
+ in_uint8a(in, format->cb, readcnt);
+ in_uint8s(in, discardcnt);
+
+ if (device_available && current_driver->wave_in_format_supported(format))
+ {
+ rec_format_count++;
+ if (rec_format_count == MAX_FORMATS)
+ break;
+ }
+ }
+ }
+
+ out = rdpsnd_init_packet(RDPSND_REC_NEGOTIATE, 12 + 18 * rec_format_count);
+ out_uint32_le(out, 0x00000000); /* flags */
+ out_uint32_le(out, 0xffffffff); /* volume */
+ out_uint16_le(out, rec_format_count);
+ out_uint16_le(out, 1); /* version */
+
+ for (i = 0; i < rec_format_count; i++)
+ {
+ format = &rec_formats[i];
+ out_uint16_le(out, format->wFormatTag);
+ out_uint16_le(out, format->nChannels);
+ out_uint32_le(out, format->nSamplesPerSec);
+ out_uint32_le(out, format->nAvgBytesPerSec);
+ out_uint16_le(out, format->nBlockAlign);
+ out_uint16_le(out, format->wBitsPerSample);
+ out_uint16(out, 0); /* cbSize */
+ }
+
+ s_mark_end(out);
+
+ DEBUG_SOUND(("RDPSND: -> RDPSND_REC_NEGOTIATE(formats: %d)\n", (int) rec_format_count));
+
+ rdpsnd_send(out);
+ }
+
+ static void
rdpsnd_process_packet(uint8 opcode, STREAM s)
{
***************
*** 310,313 ****
--- 485,532 ----
current_driver->wave_out_volume(vol_left, vol_right);
break;
+ case RDPSND_REC_NEGOTIATE:
+ rdpsnd_process_rec_negotiate(s);
+ break;
+ case RDPSND_REC_START:
+ in_uint16_le(s, format);
+ DEBUG_SOUND(("RDPSND: RDPSND_REC_START(format: %u)\n", (unsigned) format));
+
+ if (format >= MAX_FORMATS)
+ {
+ error("RDPSND: Invalid format index\n");
+ break;
+ }
+
+ if (rec_device_open)
+ {
+ error("RDPSND: Multiple RDPSND_REC_START\n");
+ break;
+ }
+
+ if (!current_driver->wave_in_open())
+ break;
+
+ if (!current_driver->wave_in_set_format(&rec_formats[format]))
+ {
+ error("RDPSND: Device not accepting format\n");
+ current_driver->wave_in_close();
+ break;
+ }
+ rec_device_open = True;
+ break;
+ case RDPSND_REC_STOP:
+ DEBUG_SOUND(("RDPSND: RDPSND_REC_STOP()\n"));
+ rdpsnd_flush_record();
+ if (rec_device_open)
+ current_driver->wave_in_close();
+ rec_device_open = False;
+ break;
+ case RDPSND_REC_SET_VOLUME:
+ in_uint16_le(s, vol_left);
+ in_uint16_le(s, vol_right);
+ 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));
+ if (rec_device_open)
+ current_driver->wave_in_volume(vol_left, vol_right);
+ break;
default:
unimpl("RDPSND packet type %x\n", opcode);
***************
*** 374,377 ****
--- 593,622 ----
}
+ static BOOL
+ rdpsnddbg_line_handler(const char *line, void *data)
+ {
+ #ifdef WITH_DEBUG_SOUND
+ fprintf(stderr, "SNDDBG: %s\n", line);
+ #endif
+ return True;
+ }
+
+ static void
+ rdpsnddbg_process(STREAM s)
+ {
+ unsigned int pkglen;
+ static char *rest = NULL;
+ char *buf;
+
+ pkglen = s->end - s->p;
+ /* str_handle_lines requires null terminated strings */
+ buf = xmalloc(pkglen + 1);
+ STRNCPY(buf, (char *) s->p, pkglen + 1);
+
+ str_handle_lines(buf, &rest, rdpsnddbg_line_handler, NULL);
+
+ xfree(buf);
+ }
+
static void
rdpsnd_register_drivers(char *options)
***************
*** 426,430 ****
rdpsnd_process);
! if (rdpsnd_channel == NULL)
{
error("channel_register\n");
--- 671,679 ----
rdpsnd_process);
! rdpsnddbg_channel =
! channel_register("snddbg", CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP,
! rdpsnddbg_process);
!
! if ((rdpsnd_channel == NULL) || (rdpsnddbg_channel == NULL))
{
error("channel_register\n");
***************
*** 490,494 ****
long next_pending;
! if (device_open)
current_driver->add_fds(n, rfds, wfds, tv);
--- 739,743 ----
long next_pending;
! if (device_open || rec_device_open)
current_driver->add_fds(n, rfds, wfds, tv);
***************
*** 512,516 ****
rdpsnd_queue_complete_pending();
! if (device_open)
current_driver->check_fds(rfds, wfds);
}
--- 761,765 ----
rdpsnd_queue_complete_pending();
! if (device_open || rec_device_open)
current_driver->check_fds(rfds, wfds);
}
Index: rdpsnd.h
===================================================================
RCS file: /cvsroot/rdesktop/rdesktop/rdpsnd.h,v
retrieving revision 1.9
retrieving revision 1.10
diff -C2 -d -r1.9 -r1.10
*** rdpsnd.h 7 Dec 2006 15:23:45 -0000 1.9
--- rdpsnd.h 2 Jan 2007 16:30:06 -0000 1.10
***************
*** 40,43 ****
--- 40,49 ----
void (*wave_out_volume) (uint16 left, uint16 right);
+ BOOL(*wave_in_open) (void);
+ void (*wave_in_close) (void);
+ BOOL(*wave_in_format_supported) (WAVEFORMATEX * pwfx);
+ BOOL(*wave_in_set_format) (WAVEFORMATEX * pwfx);
+ void (*wave_in_volume) (uint16 left, uint16 right);
+
char *name;
char *description;
-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV