missed some files for microphone redirection using rdesktop

ulab-next
Laxmikant Rashinkar 11 years ago
parent f0560e1467
commit 43b7b84182

@ -1,18 +1,17 @@
#
# build xrdp pulseaudio modules
#
PULSE_DIR = /home/lk/pulseaudio-1.1
CFLAGS = -Wall -O2 -I$(PULSE_DIR) -I$(PULSE_DIR)/src -DHAVE_CONFIG_H -fPIC
#PULSE_DIR=/home/jay/temp/pulseaudio-0.9.21 all: module-xrdp-sink.so module-xrdp-source.so
#PULSE_DIR=/home/jay/pulseaudio-0.9.22
#PULSE_DIR=/home/jay/pulseaudio-0.9.21
PULSE_DIR=/home/jay/pulseaudio-2.0
OBJS = module-xrdp-sink.o module-xrdp-sink.so: module-xrdp-sink.o
$(CC) $(LDFLAGS) -shared -o module-xrdp-sink.so module-xrdp-sink.o
CFLAGS = -Wall -O2 -I$(PULSE_DIR) -I$(PULSE_DIR)/src -DHAVE_CONFIG_H -fPIC module-xrdp-source.so: module-xrdp-source.o
$(CC) $(LDFLAGS) -shared -o module-xrdp-source.so module-xrdp-source.o
all: module-xrdp-sink.so
module-xrdp-sink.so: $(OBJS)
$(CC) $(LDFLAGS) -shared -o module-xrdp-sink.so $(OBJS)
clean: clean:
rm -f $(OBJS) module-xrdp-sink.so rm -f module-xrdp-sink.o module-xrdp-sink.so module-xrdp-source.o module-xrdp-source.so

@ -75,7 +75,7 @@ PA_MODULE_USAGE(
#define DEFAULT_SINK_NAME "xrdp" #define DEFAULT_SINK_NAME "xrdp"
#define BLOCK_USEC 30000 #define BLOCK_USEC 30000
//#define BLOCK_USEC (PA_USEC_PER_SEC * 2) //#define BLOCK_USEC (PA_USEC_PER_SEC * 2)
#define CHANSRV_PORT_STR "/tmp/.xrdp/xrdp_chansrv_audio_socket_%d" #define CHANSRV_PORT_STR "/tmp/.xrdp/xrdp_chansrv_audio_out_socket_%d"
struct userdata { struct userdata {
pa_core *core; pa_core *core;

@ -1,34 +1,80 @@
this is /etc/apt/sources.list o append the following line to /etc/apt/sources.list
I added the deb-src line
---------------------- deb-src http://archive.ubuntu.com/ubuntu/ precise-updates main restricted universe multiverse
deb http://packages.linuxmint.com/ maya main upstream import
deb http://archive.ubuntu.com/ubuntu/ precise main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu/ precise-updates main restricted universe multiverse
deb-src http://archive.ubuntu.com/ubuntu/ precise-updates main restricted universe multiverse
deb http://security.ubuntu.com/ubuntu/ precise-security main restricted universe multiverse
deb http://archive.canonical.com/ubuntu/ precise partner
deb http://packages.medibuntu.org/ precise free non-free
#deb http://archive.getdeb.net/ubuntu precise-getdeb apps this is what my /etc/apt/sources.list looks like
#deb http://archive.getdeb.net/ubuntu precise-getdeb games
deb http://drbl.sourceforge.net/drbl-core drbl stable
----------------------
do all this in a new directory deb http://packages.linuxmint.com/ maya main upstream import
deb http://archive.ubuntu.com/ubuntu/ precise main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu/ precise-updates main restricted universe multiverse
deb http://security.ubuntu.com/ubuntu/ precise-security main restricted universe multiverse
deb http://archive.canonical.com/ubuntu/ precise partner
deb http://packages.medibuntu.org/ precise free non-free
root #deb http://archive.getdeb.net/ubuntu precise-getdeb apps
sudo apt-get install dpkg-dev #deb http://archive.getdeb.net/ubuntu precise-getdeb games
deb http://drbl.sourceforge.net/drbl-core drbl stable
deb-src http://archive.ubuntu.com/ubuntu/ precise-updates main restricted universe multiverse
NOTE: If you get an error message that goes something like this:
non root E: You must put some 'source' URIs in your sources.list
apt-get source pulseaudio
root try running the following command first:
sudo apt-get build-dep pulseaudio
cd pulseaudio-1.1 apt-get source pulseaudio
non root o run these commands in your home directory
dpkg-buildpackage -rfakeroot -uc -b
cd
sudo apt-get install dpkg-dev
apt-get source pulseaudio
sudo apt-get build-dep pulseaudio
cd pulseaudio-1.1
dpkg-buildpackage -rfakeroot -uc -b
o edit Makefile and point PULSE_DIR to ~/pulseaudio<version> dir
o run make; the outputs will be
module-xrdp-sink.so
module-xrdp-source.so
o sudo cp module-xrdp-sink.so /usr/lib/pulse-<version>/modules
sudo cp module-xrdp-source.so /usr/lib/pulse-<version>/modules
note: on a 64bit machine use lib64 instead of lib
o cd /etc/pulse
o sudo mv default.pa default.pa.orig
o sudo vi default.pa and add the following lines to it
.nofail
.fail
load-module module-augment-properties
#load-module module-alsa-sink device=hw:0
#load-module module-alsa-source device=hw:0
#load-module module-pipe-sink
#load-module module-pipe-source
#load-module module-null-sink
load-module module-xrdp-sink
load-module module-xrdp-source
load-module module-native-protocol-unix
#load-module module-udev-detect tsched=0
o sudo apt-get install pavucontrol
o pulseaudio --kill
o mplayer -ao pulse <audio file>
o in another window run pavucontrol and you should see xrdp-sink in use
o to enable pulseaudio log
o edit /etc/pulse/daemon.conf and set
log-target = syslog
log-level = notice
o pulseaudio --kill
o log output will be in /var/log/syslog or /var/log/messages

@ -19,14 +19,25 @@
#include "sound.h" #include "sound.h"
#include "thread_calls.h" #include "thread_calls.h"
#include "defines.h" #include "defines.h"
#include "fifo.h"
extern int g_rdpsnd_chan_id; /* in chansrv.c */ extern int g_rdpsnd_chan_id; /* in chansrv.c */
extern int g_display_num; /* in chansrv.c */ extern int g_display_num; /* in chansrv.c */
static struct trans *g_audio_l_trans = 0; /* listener */ /* audio out: sound_server -> xrdp -> NeutrinoRDP */
static struct trans *g_audio_c_trans = 0; /* connection */ static struct trans *g_audio_l_trans_out = 0; /* listener */
static int g_training_sent_time = 0; static struct trans *g_audio_c_trans_out = 0; /* connection */
static int g_cBlockNo = 0;
/* audio in: sound_server <- xrdp <- NeutrinoRDP */
static struct trans *g_audio_l_trans_in = 0; /* listener */
static struct trans *g_audio_c_trans_in = 0; /* connection */
static int g_training_sent_time = 0;
static int g_cBlockNo = 0;
static int g_bytes_in_stream = 0;
static FIFO in_fifo;
static struct stream *g_stream_inp = NULL;
#define BBUF_SIZE (1024 * 8) #define BBUF_SIZE (1024 * 8)
char g_buffer[BBUF_SIZE]; char g_buffer[BBUF_SIZE];
@ -38,7 +49,8 @@ static void *DEFAULT_CC
read_raw_audio_data(void *arg); read_raw_audio_data(void *arg);
#endif #endif
#define CHANSRV_PORT_STR "/tmp/.xrdp/xrdp_chansrv_audio_socket_%d" #define CHANSRV_PORT_OUT_STR "/tmp/.xrdp/xrdp_chansrv_audio_out_socket_%d"
#define CHANSRV_PORT_IN_STR "/tmp/.xrdp/xrdp_chansrv_audio_in_socket_%d"
struct xr_wave_format_ex struct xr_wave_format_ex
{ {
@ -52,8 +64,10 @@ struct xr_wave_format_ex
char *data; char *data;
}; };
static char g_pmc_22050_data[] = { 0 }; /* output formats */
static struct xr_wave_format_ex g_pmc_22050 =
static char g_pcm_22050_data[] = { 0 };
static struct xr_wave_format_ex g_pcm_22050 =
{ {
1, /* wFormatTag - WAVE_FORMAT_PCM */ 1, /* wFormatTag - WAVE_FORMAT_PCM */
2, /* num of channels */ 2, /* num of channels */
@ -62,11 +76,11 @@ static struct xr_wave_format_ex g_pmc_22050 =
4, /* block align */ 4, /* block align */
16, /* bits per sample */ 16, /* bits per sample */
0, /* data size */ 0, /* data size */
g_pmc_22050_data /* data */ g_pcm_22050_data /* data */
}; };
static char g_pmc_44100_data[] = { 0 }; static char g_pcm_44100_data[] = { 0 };
static struct xr_wave_format_ex g_pmc_44100 = static struct xr_wave_format_ex g_pcm_44100 =
{ {
1, /* wFormatTag - WAVE_FORMAT_PCM */ 1, /* wFormatTag - WAVE_FORMAT_PCM */
2, /* num of channels */ 2, /* num of channels */
@ -75,24 +89,63 @@ static struct xr_wave_format_ex g_pmc_44100 =
4, /* block align */ 4, /* block align */
16, /* bits per sample */ 16, /* bits per sample */
0, /* data size */ 0, /* data size */
g_pmc_44100_data /* data */ g_pcm_44100_data /* data */
}; };
#define NUM_BUILT_IN 2 #define SND_NUM_OUTP_FORMATS 2
static struct xr_wave_format_ex *g_wave_formats[NUM_BUILT_IN] = static struct xr_wave_format_ex *g_wave_outp_formats[SND_NUM_OUTP_FORMATS] =
{ {
&g_pmc_44100, &g_pcm_44100,
&g_pmc_22050 &g_pcm_22050
}; };
/* index into list from client */ /* index into list from client */
static int g_current_client_format_index = 0; static int g_current_client_format_index = 0;
/* index into list from server */ /* index into list from server */
static int g_current_server_format_index = 0; static int g_current_server_format_index = 0;
/* input formats */
static char g_pcm_inp_22050_data[] = { 0 };
static struct xr_wave_format_ex g_pcm_inp_22050 =
{
1, /* wFormatTag - WAVE_FORMAT_PCM */
2, /* num of channels */
22050, /* samples per sec */
88200, /* avg bytes per sec */
4, /* block align */
16, /* bits per sample */
0, /* data size */
g_pcm_inp_22050_data /* data */
};
static char g_pcm_inp_44100_data[] = { 0 };
static struct xr_wave_format_ex g_pcm_inp_44100 =
{
1, /* wFormatTag - WAVE_FORMAT_PCM */
2, /* num of channels */
44100, /* samples per sec */
176400, /* avg bytes per sec */
4, /* block align */
16, /* bits per sample */
0, /* data size */
g_pcm_inp_44100_data /* data */
};
#define SND_NUM_INP_FORMATS 2
static struct xr_wave_format_ex *g_wave_inp_formats[SND_NUM_INP_FORMATS] =
{
&g_pcm_inp_22050,
&g_pcm_inp_44100
};
static int g_client_input_format_index = 0;
static int g_server_input_format_index = 0;
/*****************************************************************************/ /*****************************************************************************/
static int APP_CC static int APP_CC
sound_send_server_formats(void) sound_send_server_output_formats(void)
{ {
struct stream *s; struct stream *s;
int bytes; int bytes;
@ -103,15 +156,15 @@ sound_send_server_formats(void)
init_stream(s, 8182); init_stream(s, 8182);
out_uint16_le(s, SNDC_FORMATS); out_uint16_le(s, SNDC_FORMATS);
size_ptr = s->p; size_ptr = s->p;
out_uint16_le(s, 0); /* size, set later */ out_uint16_le(s, 0); /* size, set later */
out_uint32_le(s, 0); /* dwFlags */ out_uint32_le(s, 0); /* dwFlags */
out_uint32_le(s, 0); /* dwVolume */ out_uint32_le(s, 0); /* dwVolume */
out_uint32_le(s, 0); /* dwPitch */ out_uint32_le(s, 0); /* dwPitch */
out_uint16_le(s, 0); /* wDGramPort */ out_uint16_le(s, 0); /* wDGramPort */
out_uint16_le(s, NUM_BUILT_IN); /* wNumberOfFormats */ out_uint16_le(s, SND_NUM_OUTP_FORMATS); /* wNumberOfFormats */
out_uint8(s, g_cBlockNo); /* cLastBlockConfirmed */ out_uint8(s, g_cBlockNo); /* cLastBlockConfirmed */
out_uint16_le(s, 2); /* wVersion */ out_uint16_le(s, 2); /* wVersion */
out_uint8(s, 0); /* bPad */ out_uint8(s, 0); /* bPad */
/* sndFormats */ /* sndFormats */
/* /*
@ -132,19 +185,19 @@ sound_send_server_formats(void)
00 00 00 00
*/ */
for (index = 0; index < NUM_BUILT_IN; index++) for (index = 0; index < SND_NUM_OUTP_FORMATS; index++)
{ {
out_uint16_le(s, g_wave_formats[index]->wFormatTag); out_uint16_le(s, g_wave_outp_formats[index]->wFormatTag);
out_uint16_le(s, g_wave_formats[index]->nChannels); out_uint16_le(s, g_wave_outp_formats[index]->nChannels);
out_uint32_le(s, g_wave_formats[index]->nSamplesPerSec); out_uint32_le(s, g_wave_outp_formats[index]->nSamplesPerSec);
out_uint32_le(s, g_wave_formats[index]->nAvgBytesPerSec); out_uint32_le(s, g_wave_outp_formats[index]->nAvgBytesPerSec);
out_uint16_le(s, g_wave_formats[index]->nBlockAlign); out_uint16_le(s, g_wave_outp_formats[index]->nBlockAlign);
out_uint16_le(s, g_wave_formats[index]->wBitsPerSample); out_uint16_le(s, g_wave_outp_formats[index]->wBitsPerSample);
bytes = g_wave_formats[index]->cbSize; bytes = g_wave_outp_formats[index]->cbSize;
out_uint16_le(s, bytes); out_uint16_le(s, bytes);
if (bytes > 0) if (bytes > 0)
{ {
out_uint8p(s, g_wave_formats[index]->data, bytes); out_uint8p(s, g_wave_outp_formats[index]->data, bytes);
} }
} }
@ -159,6 +212,7 @@ sound_send_server_formats(void)
} }
/*****************************************************************************/ /*****************************************************************************/
static int static int
sound_send_training(void) sound_send_training(void)
{ {
@ -189,26 +243,29 @@ sound_send_training(void)
/*****************************************************************************/ /*****************************************************************************/
static int APP_CC static int APP_CC
sound_process_format(int aindex, int wFormatTag, int nChannels, sound_process_output_format(int aindex, int wFormatTag, int nChannels,
int nSamplesPerSec, int nAvgBytesPerSec, int nSamplesPerSec, int nAvgBytesPerSec,
int nBlockAlign, int wBitsPerSample, int nBlockAlign, int wBitsPerSample,
int cbSize, char *data) int cbSize, char *data)
{ {
LOG(0, ("sound_process_format:")); LOG(1, ("sound_process_output_format:"));
LOG(0, (" wFormatTag %d", wFormatTag)); LOG(1, (" wFormatTag %d", wFormatTag));
LOG(0, (" nChannels %d", nChannels)); LOG(1, (" nChannels %d", nChannels));
LOG(0, (" nSamplesPerSec %d", nSamplesPerSec)); LOG(1, (" nSamplesPerSec %d", nSamplesPerSec));
LOG(0, (" nAvgBytesPerSec %d", nAvgBytesPerSec)); LOG(1, (" nAvgBytesPerSec %d", nAvgBytesPerSec));
LOG(0, (" nBlockAlign %d", nBlockAlign)); LOG(1, (" nBlockAlign %d", nBlockAlign));
LOG(0, (" wBitsPerSample %d", wBitsPerSample)); LOG(1, (" wBitsPerSample %d", wBitsPerSample));
LOG(0, (" cbSize %d", cbSize)); LOG(1, (" cbSize %d", cbSize));
g_hexdump(data, cbSize); g_hexdump(data, cbSize);
if (wFormatTag == g_pmc_44100.wFormatTag &&
nChannels == g_pmc_44100.nChannels && /* select CD quality audio */
nSamplesPerSec == g_pmc_44100.nSamplesPerSec && if (wFormatTag == g_pcm_44100.wFormatTag &&
nAvgBytesPerSec == g_pmc_44100.nAvgBytesPerSec && nChannels == g_pcm_44100.nChannels &&
nBlockAlign == g_pmc_44100.nBlockAlign && nSamplesPerSec == g_pcm_44100.nSamplesPerSec &&
wBitsPerSample == g_pmc_44100.wBitsPerSample) nAvgBytesPerSec == g_pcm_44100.nAvgBytesPerSec &&
nBlockAlign == g_pcm_44100.nBlockAlign &&
wBitsPerSample == g_pcm_44100.wBitsPerSample)
{ {
g_current_client_format_index = aindex; g_current_client_format_index = aindex;
g_current_server_format_index = 0; g_current_server_format_index = 0;
@ -239,7 +296,7 @@ sound_process_format(int aindex, int wFormatTag, int nChannels,
*/ */
static int APP_CC static int APP_CC
sound_process_formats(struct stream *s, int size) sound_process_output_formats(struct stream *s, int size)
{ {
int num_formats; int num_formats;
int index; int index;
@ -252,12 +309,8 @@ sound_process_formats(struct stream *s, int size)
int cbSize; int cbSize;
char *data; char *data;
LOG(0, ("sound_process_formats:"));
if (size < 16) if (size < 16)
{
return 1; return 1;
}
in_uint8s(s, 14); in_uint8s(s, 14);
in_uint16_le(s, num_formats); in_uint16_le(s, num_formats);
@ -275,9 +328,9 @@ sound_process_formats(struct stream *s, int size)
in_uint16_le(s, wBitsPerSample); in_uint16_le(s, wBitsPerSample);
in_uint16_le(s, cbSize); in_uint16_le(s, cbSize);
in_uint8p(s, data, cbSize); in_uint8p(s, data, cbSize);
sound_process_format(index, wFormatTag, nChannels, nSamplesPerSec, sound_process_output_format(index, wFormatTag, nChannels, nSamplesPerSec,
nAvgBytesPerSec, nBlockAlign, wBitsPerSample, nAvgBytesPerSec, nBlockAlign, wBitsPerSample,
cbSize, data); cbSize, data);
} }
sound_send_training(); sound_send_training();
} }
@ -458,16 +511,18 @@ process_pcm_message(int id, int size, struct stream *s)
sound_send_close(); sound_send_close();
break; break;
default: default:
LOG(0, ("process_pcm_message: unknown id %d", id)); LOG(10, ("process_pcm_message: unknown id %d", id));
break; break;
} }
return 0; return 0;
} }
/*****************************************************************************/ /*****************************************************************************/
/* data in from audio source, eg pulse, alsa */
/* data in from sound_server_sink */
static int DEFAULT_CC static int DEFAULT_CC
sound_trans_audio_data_in(struct trans *trans) sound_sndsrvr_sink_data_in(struct trans *trans)
{ {
struct stream *s; struct stream *s;
int id; int id;
@ -475,14 +530,10 @@ sound_trans_audio_data_in(struct trans *trans)
int error; int error;
if (trans == 0) if (trans == 0)
{
return 0; return 0;
}
if (trans != g_audio_c_trans) if (trans != g_audio_c_trans_out)
{
return 1; return 1;
}
s = trans_get_in_s(trans); s = trans_get_in_s(trans);
in_uint32_le(s, id); in_uint32_le(s, id);
@ -490,10 +541,11 @@ sound_trans_audio_data_in(struct trans *trans)
if ((id & ~3) || (size > 128 * 1024 + 8) || (size < 8)) if ((id & ~3) || (size > 128 * 1024 + 8) || (size < 8))
{ {
LOG(0, ("sound_trans_audio_data_in: bad message id %d size %d", id, size)); LOG(0, ("sound_sndsrvr_sink_data_in: bad message id %d size %d", id, size));
return 1; return 1;
} }
LOG(10, ("sound_trans_audio_data_in: good message id %d size %d", id, size));
LOG(10, ("sound_sndsrvr_sink_data_in: good message id %d size %d", id, size));
error = trans_force_read(trans, size - 8); error = trans_force_read(trans, size - 8);
@ -507,37 +559,62 @@ sound_trans_audio_data_in(struct trans *trans)
} }
/*****************************************************************************/ /*****************************************************************************/
/* this is a connection in on the unix domain socket */
/* incoming connection on unix domain socket - sound_server_sink -> xrdp */
static int DEFAULT_CC static int DEFAULT_CC
sound_trans_audio_conn_in(struct trans *trans, struct trans *new_trans) sound_sndsrvr_sink_conn_in(struct trans *trans, struct trans *new_trans)
{ {
LOG(0, ("sound_trans_audio_conn_in:")); LOG(0, ("sound_sndsrvr_sink_conn_in:"));
if (trans == 0) if (trans == 0)
{
return 1; return 1;
}
if (trans != g_audio_l_trans) if (trans != g_audio_l_trans_out)
{
return 1; return 1;
}
if (g_audio_c_trans != 0) /* if already set, error */ if (g_audio_c_trans_out != 0) /* if already set, error */
{
return 1; return 1;
}
if (new_trans == 0) if (new_trans == 0)
{
return 1; return 1;
}
g_audio_c_trans = new_trans; g_audio_c_trans_out = new_trans;
g_audio_c_trans->trans_data_in = sound_trans_audio_data_in; g_audio_c_trans_out->trans_data_in = sound_sndsrvr_sink_data_in;
g_audio_c_trans->header_size = 8; g_audio_c_trans_out->header_size = 8;
trans_delete(g_audio_l_trans); trans_delete(g_audio_l_trans_out);
g_audio_l_trans = 0; g_audio_l_trans_out = 0;
return 0;
}
/*****************************************************************************/
/* incoming connection on unix domain socket - sound_server_source -> xrdp */
static int DEFAULT_CC
sound_sndsrvr_source_conn_in(struct trans *trans, struct trans *new_trans)
{
LOG(0, ("sound_sndsrvr_source_conn_in: client connected"));
if (trans == 0)
return 1;
if (trans != g_audio_l_trans_in)
return 1;
if (g_audio_c_trans_in != 0) /* if already set, error */
return 1;
if (new_trans == 0)
return 1;
g_audio_c_trans_in = new_trans;
g_audio_c_trans_in->trans_data_in = sound_sndsrvr_source_data_in;
g_audio_c_trans_in->header_size = 8;
trans_delete(g_audio_l_trans_in);
g_audio_l_trans_in = 0;
return 0; return 0;
} }
@ -546,21 +623,33 @@ int APP_CC
sound_init(void) sound_init(void)
{ {
char port[256]; char port[256];
int error;
LOG(0, ("sound_init:")); LOG(0, ("sound_init:"));
sound_send_server_formats(); /* init sound output */
g_audio_l_trans = trans_create(TRANS_MODE_UNIX, 128 * 1024, 8192); sound_send_server_output_formats();
g_audio_l_trans->is_term = g_is_term;
g_snprintf(port, 255, CHANSRV_PORT_STR, g_display_num);
g_audio_l_trans->trans_conn_in = sound_trans_audio_conn_in;
error = trans_listen(g_audio_l_trans, port);
if (error != 0) g_audio_l_trans_out = trans_create(TRANS_MODE_UNIX, 128 * 1024, 8192);
{ g_audio_l_trans_out->is_term = g_is_term;
g_snprintf(port, 255, CHANSRV_PORT_OUT_STR, g_display_num);
g_audio_l_trans_out->trans_conn_in = sound_sndsrvr_sink_conn_in;
if (trans_listen(g_audio_l_trans_out, port) != 0)
LOG(0, ("sound_init: trans_listen failed")); LOG(0, ("sound_init: trans_listen failed"));
}
/* init sound input */
sound_send_server_input_formats();
g_audio_l_trans_in = trans_create(TRANS_MODE_UNIX, 128 * 1024, 8192);
g_audio_l_trans_in->is_term = g_is_term;
g_snprintf(port, 255, CHANSRV_PORT_IN_STR, g_display_num);
g_audio_l_trans_in->trans_conn_in = sound_sndsrvr_source_conn_in;
if (trans_listen(g_audio_l_trans_in, port) != 0)
LOG(0, ("sound_init: trans_listen failed"));
/* save data from sound_server_source */
fifo_init(&in_fifo, 100);
#if defined(XRDP_SIMPLESOUND) #if defined(XRDP_SIMPLESOUND)
@ -576,25 +665,39 @@ sound_init(void)
int APP_CC int APP_CC
sound_deinit(void) sound_deinit(void)
{ {
LOG(0, ("sound_deinit:")); if (g_audio_l_trans_out != 0)
{
trans_delete(g_audio_l_trans_out);
g_audio_l_trans_out = 0;
}
if (g_audio_l_trans != 0) if (g_audio_c_trans_out != 0)
{ {
trans_delete(g_audio_l_trans); trans_delete(g_audio_c_trans_out);
g_audio_l_trans = 0; g_audio_c_trans_out = 0;
} }
if (g_audio_c_trans != 0) if (g_audio_l_trans_in != 0)
{ {
trans_delete(g_audio_c_trans); trans_delete(g_audio_l_trans_in);
g_audio_c_trans = 0; g_audio_l_trans_in = 0;
} }
if (g_audio_c_trans_in != 0)
{
trans_delete(g_audio_c_trans_in);
g_audio_c_trans_in = 0;
}
fifo_deinit(&in_fifo);
return 0; return 0;
} }
/*****************************************************************************/ /*****************************************************************************/
/* data in from client ( client -> xrdp -> chansrv ) */ /* data in from client ( client -> xrdp -> chansrv ) */
int APP_CC int APP_CC
sound_data_in(struct stream *s, int chan_id, int chan_flags, int length, sound_data_in(struct stream *s, int chan_id, int chan_flags, int length,
int total_length) int total_length)
@ -617,11 +720,19 @@ sound_data_in(struct stream *s, int chan_id, int chan_flags, int length,
break; break;
case SNDC_FORMATS: case SNDC_FORMATS:
sound_process_formats(s, size); sound_process_output_formats(s, size);
break;
case SNDC_REC_NEGOTIATE:
sound_process_input_formats(s, size);
break;
case SNDC_REC_DATA:
sound_process_input_data(s, size);
break; break;
default: default:
LOG(0, ("sound_data_in: unknown code %d size %d", code, size)); LOG(10, ("sound_data_in: unknown code %d size %d", code, size));
break; break;
} }
@ -636,15 +747,27 @@ sound_get_wait_objs(tbus *objs, int *count, int *timeout)
lcount = *count; lcount = *count;
if (g_audio_l_trans != 0) if (g_audio_l_trans_out != 0)
{ {
objs[lcount] = g_audio_l_trans->sck; objs[lcount] = g_audio_l_trans_out->sck;
lcount++; lcount++;
} }
if (g_audio_c_trans != 0) if (g_audio_c_trans_out != 0)
{ {
objs[lcount] = g_audio_c_trans->sck; objs[lcount] = g_audio_c_trans_out->sck;
lcount++;
}
if (g_audio_l_trans_in != 0)
{
objs[lcount] = g_audio_l_trans_in->sck;
lcount++;
}
if (g_audio_c_trans_in != 0)
{
objs[lcount] = g_audio_c_trans_in->sck;
lcount++; lcount++;
} }
@ -656,19 +779,365 @@ sound_get_wait_objs(tbus *objs, int *count, int *timeout)
int APP_CC int APP_CC
sound_check_wait_objs(void) sound_check_wait_objs(void)
{ {
if (g_audio_l_trans != 0) if (g_audio_l_trans_out != 0)
{
trans_check_wait_objs(g_audio_l_trans_out);
}
if (g_audio_c_trans_out != 0)
{
trans_check_wait_objs(g_audio_c_trans_out);
}
if (g_audio_l_trans_in != 0)
{
trans_check_wait_objs(g_audio_l_trans_in);
}
if (g_audio_c_trans_in != 0)
{
trans_check_wait_objs(g_audio_c_trans_in);
}
return 0;
}
/******************************************************************************
** **
** Microphone releated code **
** **
******************************************************************************/
/**
*
*****************************************************************************/
static int APP_CC
sound_send_server_input_formats(void)
{
struct stream* s;
int bytes;
int index;
char* size_ptr;
make_stream(s);
init_stream(s, 8182);
out_uint16_le(s, SNDC_REC_NEGOTIATE);
size_ptr = s->p;
out_uint16_le(s, 0); /* size, set later */
out_uint32_le(s, 0); /* unused */
out_uint32_le(s, 0); /* unused */
out_uint16_le(s, SND_NUM_INP_FORMATS); /* wNumberOfFormats */
out_uint16_le(s, 2); /* wVersion */
/*
wFormatTag 2 byte offset 0
nChannels 2 byte offset 2
nSamplesPerSec 4 byte offset 4
nAvgBytesPerSec 4 byte offset 8
nBlockAlign 2 byte offset 12
wBitsPerSample 2 byte offset 14
cbSize 2 byte offset 16
data variable offset 18
*/
for (index = 0; index < SND_NUM_INP_FORMATS; index++)
{
out_uint16_le(s, g_wave_inp_formats[index]->wFormatTag);
out_uint16_le(s, g_wave_inp_formats[index]->nChannels);
out_uint32_le(s, g_wave_inp_formats[index]->nSamplesPerSec);
out_uint32_le(s, g_wave_inp_formats[index]->nAvgBytesPerSec);
out_uint16_le(s, g_wave_inp_formats[index]->nBlockAlign);
out_uint16_le(s, g_wave_inp_formats[index]->wBitsPerSample);
bytes = g_wave_inp_formats[index]->cbSize;
out_uint16_le(s, bytes);
if (bytes > 0)
{
out_uint8p(s, g_wave_inp_formats[index]->data, bytes);
}
}
s_mark_end(s);
bytes = (int)((s->end - s->data) - 4);
size_ptr[0] = bytes;
size_ptr[1] = bytes >> 8;
bytes = (int)(s->end - s->data);
send_channel_data(g_rdpsnd_chan_id, s->data, bytes);
free_stream(s);
return 0;
}
/**
*
*****************************************************************************/
static int APP_CC
sound_process_input_format(int aindex, int wFormatTag, int nChannels,
int nSamplesPerSec, int nAvgBytesPerSec,
int nBlockAlign, int wBitsPerSample,
int cbSize, char *data)
{
LOG(10, ("sound_process_input_format:"));
LOG(10, (" wFormatTag %d", wFormatTag));
LOG(10, (" nChannels %d", nChannels));
LOG(10, (" nSamplesPerSec %d", nSamplesPerSec));
LOG(10, (" nAvgBytesPerSec %d", nAvgBytesPerSec));
LOG(10, (" nBlockAlign %d", nBlockAlign));
LOG(10, (" wBitsPerSample %d", wBitsPerSample));
LOG(10, (" cbSize %d", cbSize));
#if 0
/* select CD quality audio */
if (wFormatTag == g_pcm_inp_44100.wFormatTag &&
nChannels == g_pcm_inp_44100.nChannels &&
nSamplesPerSec == g_pcm_inp_44100.nSamplesPerSec &&
nAvgBytesPerSec == g_pcm_inp_44100.nAvgBytesPerSec &&
nBlockAlign == g_pcm_inp_44100.nBlockAlign &&
wBitsPerSample == g_pcm_inp_44100.wBitsPerSample)
{ {
trans_check_wait_objs(g_audio_l_trans); g_client_input_format_index = aindex;
g_server_input_format_index = 0;
} }
#else
/* select half of CD quality audio */
if (wFormatTag == g_pcm_inp_22050.wFormatTag &&
nChannels == g_pcm_inp_22050.nChannels &&
nSamplesPerSec == g_pcm_inp_22050.nSamplesPerSec &&
nAvgBytesPerSec == g_pcm_inp_22050.nAvgBytesPerSec &&
nBlockAlign == g_pcm_inp_22050.nBlockAlign &&
wBitsPerSample == g_pcm_inp_22050.wBitsPerSample)
{
g_client_input_format_index = aindex;
g_server_input_format_index = 0;
}
#endif
return 0;
}
/**
*
*****************************************************************************/
if (g_audio_c_trans != 0) static int APP_CC
sound_process_input_formats(struct stream *s, int size)
{
int num_formats;
int index;
int wFormatTag;
int nChannels;
int nSamplesPerSec;
int nAvgBytesPerSec;
int nBlockAlign;
int wBitsPerSample;
int cbSize;
char *data;
LOG(10, ("sound_process_input_formats: size=%d", size));
in_uint8s(s, 8); /* skip 8 bytes */
in_uint16_le(s, num_formats);
in_uint8s(s, 2); /* skip version */
if (num_formats > 0)
{ {
trans_check_wait_objs(g_audio_c_trans); for (index = 0; index < num_formats; index++)
{
in_uint16_le(s, wFormatTag);
in_uint16_le(s, nChannels);
in_uint32_le(s, nSamplesPerSec);
in_uint32_le(s, nAvgBytesPerSec);
in_uint16_le(s, nBlockAlign);
in_uint16_le(s, wBitsPerSample);
in_uint16_le(s, cbSize);
in_uint8p(s, data, cbSize);
sound_process_input_format(index, wFormatTag, nChannels, nSamplesPerSec,
nAvgBytesPerSec, nBlockAlign, wBitsPerSample,
cbSize, data);
}
} }
return 0; return 0;
} }
/**
*
*****************************************************************************/
static int APP_CC
sound_input_start_recording()
{
struct stream* s;
/* if there is any data in FIFO, discard it */
while ((s = (struct stream *) fifo_remove(&in_fifo)) != NULL)
xstream_free(s);
xstream_new(s, 1024);
/*
* command format
*
* 02 bytes command SNDC_REC_START
* 02 bytes length
* 02 bytes data format received earlier
*/
out_uint16_le(s, SNDC_REC_START);
out_uint16_le(s, 2);
out_uint16_le(s, g_client_input_format_index);
s_mark_end(s);
send_channel_data(g_rdpsnd_chan_id, s->data, 6);
xstream_free(s);
return 0;
}
/**
*
*****************************************************************************/
static int APP_CC
sound_input_stop_recording()
{
struct stream* s;
xstream_new(s, 1024);
/*
* command format
*
* 02 bytes command SNDC_REC_STOP
* 02 bytes length (zero)
*/
out_uint16_le(s, SNDC_REC_STOP);
out_uint16_le(s, 0);
s_mark_end(s);
send_channel_data(g_rdpsnd_chan_id, s->data, 4);
xstream_free(s);
return 0;
}
/**
* Process data: xrdp <- client
*****************************************************************************/
static unsigned char data = 0;
static int APP_CC
sound_process_input_data(struct stream *s, int bytes)
{
struct stream *ls;
xstream_new(ls, bytes);
memcpy(ls->data, s->p, bytes);
ls->p += bytes;
s_mark_end(ls);
fifo_insert(&in_fifo, (void *) ls);
return 0;
}
/**
* Got a command from sound_server_source
*****************************************************************************/
static int DEFAULT_CC
sound_sndsrvr_source_data_in(struct trans *trans)
{
struct stream *ts = NULL;
struct stream *s = NULL;
tui16 bytes_req = 0;
int bytes_read = 0;
int cmd;
int i;
if (trans == 0)
return 0;
if (trans != g_audio_c_trans_in)
return 1;
ts = trans_get_in_s(trans);
trans_force_read(trans, 3);
ts->p = ts->data + 8;
in_uint8(ts, cmd);
in_uint16_le(ts, bytes_req);
if (bytes_req != 0)
xstream_new(s, bytes_req + 2);
if (cmd == PA_CMD_SEND_DATA)
{
/* set real len later */
out_uint16_le(s, 0);
while (bytes_read < bytes_req)
{
if (g_stream_inp == NULL)
g_stream_inp = (struct stream *) fifo_remove(&in_fifo);
if (g_stream_inp == NULL)
{
/* no more data, send what we have */
break;
}
else
{
if (g_bytes_in_stream == 0)
g_bytes_in_stream = g_stream_inp->size;
i = bytes_req - bytes_read;
if (i < g_bytes_in_stream)
{
xstream_copyin(s, &g_stream_inp->data[g_stream_inp->size - g_bytes_in_stream], i);
bytes_read += i;
g_bytes_in_stream -= i;
}
else
{
xstream_copyin(s, &g_stream_inp->data[g_stream_inp->size - g_bytes_in_stream], g_bytes_in_stream);
bytes_read += g_bytes_in_stream;
g_bytes_in_stream = 0;
xstream_free(g_stream_inp);
g_stream_inp = NULL;
}
}
}
if (bytes_read)
{
s->data[0] = (char) (bytes_read & 0xff);
s->data[1] = (char) ((bytes_read >> 8) & 0xff);
}
s_mark_end(s);
trans_force_write_s(trans, s);
xstream_free(s);
}
else if (cmd == PA_CMD_START_REC)
{
sound_input_start_recording();
}
else if (cmd == PA_CMD_STOP_REC)
{
sound_input_stop_recording();
}
return 0;
}
/*****************************************************************************/
#if defined(XRDP_SIMPLESOUND) #if defined(XRDP_SIMPLESOUND)
#define AUDIO_BUF_SIZE 2048 #define AUDIO_BUF_SIZE 2048

@ -43,16 +43,36 @@
#define SNDC_UDPWAVELAST 0x0B #define SNDC_UDPWAVELAST 0x0B
#define SNDC_QUALITYMODE 0x0C #define SNDC_QUALITYMODE 0x0C
int APP_CC /* used for sound input (mic) */
sound_init(void); #define SNDC_REC_NEGOTIATE 39
int APP_CC #define SNDC_REC_START 40
sound_deinit(void); #define SNDC_REC_STOP 41
int APP_CC #define SNDC_REC_DATA 42
sound_get_wait_objs(tbus* objs, int* count, int* timeout); #define SNDC_REC_SET_VOLUME 43
int APP_CC
sound_check_wait_objs(void);
int APP_CC
sound_data_in(struct stream* s, int chan_id, int chan_flags,
int length, int total_length);
/* commands recvd from pulseaudio source */
#define PA_CMD_START_REC 1
#define PA_CMD_STOP_REC 2
#define PA_CMD_SEND_DATA 3
int APP_CC sound_init(void);
int APP_CC sound_deinit(void);
int APP_CC sound_get_wait_objs(tbus* objs, int* count, int* timeout);
int APP_CC sound_check_wait_objs(void);
int APP_CC sound_data_in(struct stream* s, int chan_id, int chan_flags,
int length, int total_length);
/* microphone related */
static int APP_CC sound_send_server_input_formats(void);
static int APP_CC sound_process_input_format(int aindex, int wFormatTag,
int nChannels, int nSamplesPerSec, int nAvgBytesPerSec,
int nBlockAlign, int wBitsPerSample, int cbSize, char *data);
static int APP_CC sound_process_input_formats(struct stream *s, int size);
static int APP_CC sound_input_start_recording();
static int APP_CC sound_input_stop_recording();
static int APP_CC sound_process_input_data(struct stream *s, int bytes);
static int DEFAULT_CC sound_sndsrvr_source_data_in(struct trans *trans);
#endif #endif

Loading…
Cancel
Save