⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rdpsnd.c

📁 LInux 下的远程桌面工具 Rdesktop
💻 C
📖 第 1 页 / 共 2 页
字号:
/* -*- c-basic-offset: 8 -*-   rdesktop: A Remote Desktop Protocol client.   Sound Channel Process Functions   Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB   Copyright (C) Matthew Chapman 2003-2007   Copyright (C) GuoJunBo guojunbo@ict.ac.cn 2003   This program is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 2 of the License, or   (at your option) any later version.   This program is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.   You should have received a copy of the GNU General Public License   along with this program; if not, write to the Free Software   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include <assert.h>#include "rdesktop.h"#include "rdpsnd.h"#include "rdpsnd_dsp.h"#define RDPSND_CLOSE		1#define RDPSND_WRITE		2#define RDPSND_SET_VOLUME	3#define RDPSND_UNKNOWN4		4#define RDPSND_COMPLETION	5#define RDPSND_PING			6#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		50static VCHANNEL *rdpsnd_channel;static VCHANNEL *rdpsnddbg_channel;static struct audio_driver *drivers = NULL;struct audio_driver *current_driver = NULL;static RD_BOOL device_open;static RD_BOOL rec_device_open;static RD_WAVEFORMATEX formats[MAX_FORMATS];static unsigned int format_count;static unsigned int current_format;static RD_WAVEFORMATEX rec_formats[MAX_FORMATS];static unsigned int rec_format_count;static unsigned int rec_current_format;unsigned int queue_hi, queue_lo, queue_pending;struct audio_packet packet_queue[MAX_QUEUE];static char record_buffer[8192];static uint32 record_buffer_size;static uint8 packet_opcode;static struct stream packet;void (*wave_out_play) (void);static void rdpsnd_queue_write(STREAM s, uint16 tick, uint8 index);static void rdpsnd_queue_init(void);static void rdpsnd_queue_complete_pending(void);static long rdpsnd_queue_next_completion(void);static STREAMrdpsnd_init_packet(uint16 type, uint16 size){	STREAM s;	s = channel_init(rdpsnd_channel, size + 4);	out_uint16_le(s, type);	out_uint16_le(s, size);	return s;}static voidrdpsnd_send(STREAM s){	channel_send(s, rdpsnd_channel);}static voidrdpsnd_send_completion(uint16 tick, uint8 packet_index){	STREAM s;	s = rdpsnd_init_packet(RDPSND_COMPLETION, 4);	out_uint16_le(s, tick);	out_uint8(s, packet_index);	out_uint8(s, 0);	s_mark_end(s);	rdpsnd_send(s);	DEBUG_SOUND(("RDPSND: -> RDPSND_COMPLETION(tick: %u, index: %u)\n",		     (unsigned) tick, (unsigned) packet_index));}static voidrdpsnd_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;}voidrdpsnd_record(const void *data, unsigned int size){	uint32 remain, chunk;	assert(rec_device_open);	while (size)	{		remain = sizeof(record_buffer) - record_buffer_size;		if (size >= remain)			chunk = remain;		else			chunk = size;		memcpy(record_buffer + record_buffer_size, data, chunk);#ifdef B_ENDIAN		if (current_driver->need_byteswap_on_be)			rdpsnd_dsp_swapbytes(record_buffer + record_buffer_size,					     chunk, &rec_formats[rec_current_format]);#endif		record_buffer_size += chunk;		data = (const char *) data + chunk;		size -= chunk;		if (record_buffer_size == sizeof(record_buffer))			rdpsnd_flush_record();	}}static RD_BOOLrdpsnd_auto_select(void){	static RD_BOOL failed = False;	if (!failed)	{		current_driver = drivers;		while (current_driver != NULL)		{			DEBUG(("trying %s...\n", current_driver->name));			if (current_driver->wave_out_open())			{				DEBUG(("selected %s\n", current_driver->name));				current_driver->wave_out_close();				return True;			}			current_driver = current_driver->next;		}		warning("no working audio-driver found\n");		failed = True;		current_driver = NULL;	}	return False;}static voidrdpsnd_process_negotiate(STREAM in){	uint16 in_format_count, i;	uint8 pad;	uint16 version;	RD_WAVEFORMATEX *format;	STREAM out;	RD_BOOL device_available = False;	int readcnt;	int discardcnt;	in_uint8s(in, 14);	/* initial bytes not valid from server */	in_uint16_le(in, in_format_count);	in_uint8(in, pad);	in_uint16_le(in, version);	in_uint8s(in, 1);	/* padding */	DEBUG_SOUND(("RDPSND: RDPSND_NEGOTIATE(formats: %d, pad: 0x%02x, version: %x)\n",		     (int) in_format_count, (unsigned) pad, (unsigned) version));	if (!current_driver)		device_available = rdpsnd_auto_select();	if (current_driver && !device_available && current_driver->wave_out_open())	{		current_driver->wave_out_close();		device_available = True;	}	format_count = 0;	if (s_check_rem(in, 18 * in_format_count))	{		for (i = 0; i < in_format_count; i++)		{			format = &formats[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 (current_driver && current_driver->wave_out_format_supported(format))			{				format_count++;				if (format_count == MAX_FORMATS)					break;			}		}	}	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 */	out_uint16(out, 0);	/* UDP port */	out_uint16_le(out, format_count);	out_uint8(out, 0);	/* padding */	out_uint16_le(out, 2);	/* version */	out_uint8(out, 0);	/* padding */	for (i = 0; i < format_count; i++)	{		format = &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_NEGOTIATE(formats: %d)\n", (int) format_count));	rdpsnd_send(out);}static voidrdpsnd_process_ping(STREAM in){	uint16 tick;	STREAM out;	in_uint16_le(in, tick);	DEBUG_SOUND(("RDPSND: RDPSND_PING(tick: 0x%04x)\n", (unsigned) tick));	out = rdpsnd_init_packet(RDPSND_PING | 0x2300, 4);	out_uint16_le(out, tick);	out_uint16_le(out, 0);	s_mark_end(out);	rdpsnd_send(out);	DEBUG_SOUND(("RDPSND: -> (tick: 0x%04x)\n", (unsigned) tick));}static voidrdpsnd_process_rec_negotiate(STREAM in){	uint16 in_format_count, i;	uint16 version;	RD_WAVEFORMATEX *format;	STREAM out;	RD_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 (current_driver && current_driver->wave_in_format_supported			    && 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 voidrdpsnd_process_packet(uint8 opcode, STREAM s){	uint16 vol_left, vol_right;	static uint16 tick, format;	static uint8 packet_index;	switch (opcode)	{		case RDPSND_WRITE:			in_uint16_le(s, tick);			in_uint16_le(s, format);			in_uint8(s, packet_index);			in_uint8s(s, 3);			DEBUG_SOUND(("RDPSND: RDPSND_WRITE(tick: %u, format: %u, index: %u, data: %u bytes)\n", (unsigned) tick, (unsigned) format, (unsigned) packet_index, (unsigned) s->size - 8));			if (format >= MAX_FORMATS)			{				error("RDPSND: Invalid format index\n");				break;			}			if (!device_open || (format != current_format))			{				/*				 * If we haven't selected a device by now, then either				 * we've failed to find a working device, or the server				 * is sending bogus RDPSND_WRITE.				 */				if (!current_driver)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -