mirror of https://github.com/neutrinolabs/xrdp
chansrv: simple pulse audio support
This commit is contained in:
parent
17a65f90f7
commit
7fa4f936e4
11
configure.ac
11
configure.ac
|
@ -31,6 +31,10 @@ AC_ARG_ENABLE(jpeg, AS_HELP_STRING([--enable-jpeg],
|
|||
[Build jpeg module (default: no)]),
|
||||
[jpeg=true], [jpeg=false])
|
||||
AM_CONDITIONAL(XRDP_JPEG, [test x$jpeg = xtrue])
|
||||
AC_ARG_ENABLE(simplesound, AS_HELP_STRING([--enable-simplesound],
|
||||
[Build simple pulse audio interface (default: no)]),
|
||||
[simplesound=true], [simplesound=false])
|
||||
AM_CONDITIONAL(XRDP_SIMPLESOUND, [test x$simplesound = xtrue])
|
||||
|
||||
AM_CONDITIONAL(GOT_PREFIX, test "x${prefix}" != "xNONE"])
|
||||
|
||||
|
@ -58,6 +62,13 @@ then
|
|||
[AC_MSG_ERROR([please install libjpeg-dev or libjpeg-devel])])
|
||||
fi
|
||||
|
||||
# checking for libpulse libpulse-simple
|
||||
if ! test -z "$enable_simplesound"
|
||||
then
|
||||
AC_CHECK_HEADER([pulse/simple.h], [],
|
||||
[AC_MSG_ERROR([please install libpulse-dev or libpulse-devel])])
|
||||
fi
|
||||
|
||||
# checking for Xlib, Xfixes
|
||||
AC_CHECK_HEADER([X11/Xlib.h], [],
|
||||
[AC_MSG_ERROR([please install libx11-dev or libX11-devel])])
|
||||
|
|
|
@ -1,13 +1,25 @@
|
|||
EXTRA_DIST = chansrv.h clipboard.h devredir.h sound.h
|
||||
|
||||
EXTRA_DEFINES =
|
||||
EXTRA_INCLUDES =
|
||||
EXTRA_LIBS =
|
||||
EXTRA_FLAGS =
|
||||
|
||||
if XRDP_SIMPLESOUND
|
||||
EXTRA_DEFINES += -DXRDP_SIMPLESOUND
|
||||
EXTRA_LIBS += -lpthread -lpulse -lpulse-simple
|
||||
endif
|
||||
|
||||
AM_CFLAGS = \
|
||||
-DXRDP_CFG_PATH=\"${sysconfdir}/xrdp\" \
|
||||
-DXRDP_SBIN_PATH=\"${sbindir}\" \
|
||||
-DXRDP_SHARE_PATH=\"${datadir}/xrdp\" \
|
||||
-DXRDP_PID_PATH=\"${localstatedir}/run\"
|
||||
-DXRDP_PID_PATH=\"${localstatedir}/run\" \
|
||||
$(EXTRA_DEFINES)
|
||||
|
||||
INCLUDES = \
|
||||
-I$(top_srcdir)/common
|
||||
-I$(top_srcdir)/common \
|
||||
$(EXTRA_INCLUDES)
|
||||
|
||||
sbin_PROGRAMS = \
|
||||
xrdp-chansrv
|
||||
|
@ -18,7 +30,11 @@ xrdp_chansrv_SOURCES = \
|
|||
clipboard.c \
|
||||
devredir.c
|
||||
|
||||
xrdp_chansrv_LDFLAGS = \
|
||||
$(EXTRA_FLAGS)
|
||||
|
||||
xrdp_chansrv_LDADD = \
|
||||
-L/usr/X11R6/lib \
|
||||
$(top_srcdir)/common/libcommon.la \
|
||||
-lX11 -lXfixes
|
||||
-lX11 -lXfixes \
|
||||
$(EXTRA_LIBS)
|
||||
|
|
|
@ -1,32 +1,343 @@
|
|||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2009-2012
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "sound.h"
|
||||
|
||||
extern int g_rdpsnd_chan_id; /* in chansrv.c */
|
||||
extern int g_display_num; /* in chansrv.c */
|
||||
|
||||
static struct trans *g_audio_l_trans = 0; // listener
|
||||
static struct trans *g_audio_c_trans = 0; // connection
|
||||
static int g_training_sent_time = 0;
|
||||
static int g_cBlockNo = 0;
|
||||
|
||||
/*****************************************************************************/
|
||||
static int APP_CC
|
||||
sound_send_server_formats(void)
|
||||
{
|
||||
struct stream* s;
|
||||
int bytes;
|
||||
char* size_ptr;
|
||||
|
||||
print_got_here();
|
||||
|
||||
make_stream(s);
|
||||
init_stream(s, 8182);
|
||||
out_uint16_le(s, SNDC_FORMATS);
|
||||
size_ptr = s->p;
|
||||
out_uint16_le(s, 0); /* size, set later */
|
||||
out_uint32_le(s, 0); /* dwFlags */
|
||||
out_uint32_le(s, 0); /* dwVolume */
|
||||
out_uint32_le(s, 0); /* dwPitch */
|
||||
out_uint16_le(s, 0); /* wDGramPort */
|
||||
out_uint16_le(s, 1); /* wNumberOfFormats */
|
||||
out_uint8(s, g_cBlockNo); /* cLastBlockConfirmed */
|
||||
out_uint16_le(s, 2); /* wVersion */
|
||||
out_uint8(s, 0); /* bPad */
|
||||
|
||||
/* sndFormats */
|
||||
/*
|
||||
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
|
||||
*/
|
||||
|
||||
/* examples
|
||||
01 00 02 00 44 ac 00 00 10 b1 02 00 04 00 10 00 ....D...........
|
||||
00 00
|
||||
01 00 02 00 22 56 00 00 88 58 01 00 04 00 10 00 ...."V...X......
|
||||
00 00
|
||||
*/
|
||||
|
||||
out_uint16_le(s, 1); // wFormatTag - WAVE_FORMAT_PCM
|
||||
out_uint16_le(s, 2); // num of channels
|
||||
out_uint32_le(s, 44100); // samples per sec
|
||||
out_uint32_le(s, 176400); // avg bytes per sec
|
||||
out_uint16_le(s, 4); // block align
|
||||
out_uint16_le(s, 16); // bits per sample
|
||||
out_uint16_le(s, 0); // size
|
||||
|
||||
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
|
||||
sound_send_training(void)
|
||||
{
|
||||
struct stream* s;
|
||||
int bytes;
|
||||
int time;
|
||||
char* size_ptr;
|
||||
|
||||
print_got_here();
|
||||
|
||||
make_stream(s);
|
||||
init_stream(s, 8182);
|
||||
out_uint16_le(s, SNDC_TRAINING);
|
||||
size_ptr = s->p;
|
||||
out_uint16_le(s, 0); /* size, set later */
|
||||
time = g_time2();
|
||||
g_training_sent_time = time;
|
||||
out_uint16_le(s, time);
|
||||
out_uint16_le(s, 1024);
|
||||
out_uint8s(s, (1024 - 4));
|
||||
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;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
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.
|
||||
|
||||
xrdp: A Remote Desktop Protocol server.
|
||||
Copyright (C) Jay Sorg 2009-2010
|
||||
0000 07 02 26 00 03 00 80 00 ff ff ff ff 00 00 00 00 ..&.............
|
||||
0010 00 00 01 00 00 02 00 00 01 00 02 00 44 ac 00 00 ............D...
|
||||
0020 10 b1 02 00 04 00 10 00 00 00
|
||||
*/
|
||||
|
||||
#include "arch.h"
|
||||
#include "parse.h"
|
||||
#include "os_calls.h"
|
||||
static int APP_CC
|
||||
sound_process_formats(struct stream* s, int size)
|
||||
{
|
||||
int num_formats;
|
||||
|
||||
extern int g_rdpsnd_chan_id; /* in chansrv.c */
|
||||
print_got_here();
|
||||
|
||||
LOG(0, ("sound_process_formats:"));
|
||||
if (size < 16)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
in_uint8s(s, 14);
|
||||
in_uint16_le(s, num_formats);
|
||||
if (num_formats > 0)
|
||||
{
|
||||
sound_send_training();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
sound_send_wave_data(char* data, int data_bytes)
|
||||
{
|
||||
struct stream* s;
|
||||
int bytes;
|
||||
int time;
|
||||
char* size_ptr;
|
||||
|
||||
print_got_here();
|
||||
|
||||
if ((data_bytes < 4) || (data_bytes > 32 * 1024))
|
||||
{
|
||||
LOG(0, ("sound_send_wave_data: bad data_bytes %d", data_bytes));
|
||||
}
|
||||
|
||||
/* part one of 2 PDU wave info */
|
||||
|
||||
LOG(3, ("sound_send_wave_data: sending %d bytes", data_bytes));
|
||||
|
||||
make_stream(s);
|
||||
init_stream(s, data_bytes);
|
||||
out_uint16_le(s, SNDC_WAVE);
|
||||
size_ptr = s->p;
|
||||
out_uint16_le(s, 0); /* size, set later */
|
||||
time = g_time2();
|
||||
out_uint16_le(s, time);
|
||||
out_uint16_le(s, 0); /* wFormatNo */
|
||||
g_cBlockNo++;
|
||||
out_uint8(s, g_cBlockNo);
|
||||
|
||||
LOG(3, ("sound_send_wave_data: sending time %d, g_cBlockNo %d",
|
||||
time & 0xffff, g_cBlockNo & 0xff));
|
||||
|
||||
out_uint8s(s, 3);
|
||||
out_uint8a(s, data, 4);
|
||||
s_mark_end(s);
|
||||
bytes = (int)((s->end - s->data) - 4);
|
||||
bytes += data_bytes;
|
||||
bytes -= 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);
|
||||
|
||||
/* part two of 2 PDU wave info */
|
||||
init_stream(s, data_bytes);
|
||||
out_uint32_le(s, 0);
|
||||
out_uint8a(s, data + 4, data_bytes - 4);
|
||||
s_mark_end(s);
|
||||
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_training(struct stream* s, int size)
|
||||
{
|
||||
int time_diff;
|
||||
char buf[256];
|
||||
|
||||
print_got_here();
|
||||
|
||||
time_diff = g_time2() - g_training_sent_time;
|
||||
LOG(0, ("sound_process_training: round trip time %u", time_diff));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int APP_CC
|
||||
sound_process_wave_confirm(struct stream* s, int size)
|
||||
{
|
||||
int wTimeStamp;
|
||||
int cConfirmedBlockNo;
|
||||
|
||||
print_got_here();
|
||||
|
||||
in_uint16_le(s, wTimeStamp);
|
||||
in_uint8(s, cConfirmedBlockNo);
|
||||
|
||||
LOG(3, ("sound_process_wave_confirm: wTimeStamp %d, cConfirmedBlockNo %d",
|
||||
wTimeStamp, cConfirmedBlockNo));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int APP_CC
|
||||
process_pcm_message(int id, int size, struct stream* s)
|
||||
{
|
||||
print_got_here();
|
||||
|
||||
sound_send_wave_data(s->p, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* data coming in from audio source, eg pulse, alsa */
|
||||
static int DEFAULT_CC
|
||||
sound_trans_audio_data_in(struct trans* trans)
|
||||
{
|
||||
struct stream *s;
|
||||
int id;
|
||||
int size;
|
||||
int error;
|
||||
|
||||
if (trans == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (trans != g_audio_c_trans)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
s = trans_get_in_s(trans);
|
||||
in_uint32_le(s, id);
|
||||
in_uint32_le(s, size);
|
||||
if ((id != 0) || (size > 32 * 1024 + 8) || (size < 1))
|
||||
{
|
||||
LOG(0, ("sound_trans_audio_data_in: bad message id %d size %d", id, size));
|
||||
return 1;
|
||||
}
|
||||
error = trans_force_read(trans, size - 8);
|
||||
if (error == 0)
|
||||
{
|
||||
/* here, the entire message block is read in, process it */
|
||||
error = process_pcm_message(id, size - 8, s);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int DEFAULT_CC
|
||||
sound_trans_audio_conn_in(struct trans *trans, struct trans *new_trans)
|
||||
{
|
||||
print_got_here();
|
||||
|
||||
if (trans == 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (trans != g_audio_l_trans)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (g_audio_c_trans != 0) /* if already set, error */
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (new_trans == 0)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
g_audio_c_trans = new_trans;
|
||||
g_audio_c_trans->trans_data_in = sound_trans_audio_data_in;
|
||||
g_audio_c_trans->header_size = 8;
|
||||
trans_delete(g_audio_l_trans);
|
||||
g_audio_l_trans = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
int APP_CC
|
||||
sound_init(void)
|
||||
{
|
||||
char port[256];
|
||||
int error;
|
||||
pthread_t thread;
|
||||
|
||||
print_got_here();
|
||||
LOG(0, ("sound_init:"));
|
||||
|
||||
sound_send_server_formats();
|
||||
g_audio_l_trans = trans_create(2, 33 * 1024, 8192);
|
||||
g_snprintf(port, 255, "/tmp/xrdp_chansrv_audio_socket_%d", 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)
|
||||
{
|
||||
LOG(0, ("sound_init: trans_listen failed"));
|
||||
}
|
||||
|
||||
#if defined(XRDP_SIMPLESOUND)
|
||||
|
||||
// start thread to read raw audio data from pulseaudio device
|
||||
pthread_create(&thread, 0, read_raw_audio_data, NULL);
|
||||
pthread_detach(thread);
|
||||
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -34,14 +345,54 @@ sound_init(void)
|
|||
int APP_CC
|
||||
sound_deinit(void)
|
||||
{
|
||||
print_got_here();
|
||||
|
||||
if (g_audio_l_trans != 0)
|
||||
{
|
||||
trans_delete(g_audio_l_trans);
|
||||
g_audio_l_trans = 0;
|
||||
}
|
||||
if (g_audio_c_trans != 0)
|
||||
{
|
||||
trans_delete(g_audio_c_trans);
|
||||
g_audio_l_trans = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* data in from client ( clinet -> xrdp -> chansrv ) */
|
||||
int APP_CC
|
||||
sound_data_in(struct stream* s, int chan_id, int chan_flags, int length,
|
||||
int total_length)
|
||||
{
|
||||
int code;
|
||||
int size;
|
||||
|
||||
print_got_here();
|
||||
|
||||
in_uint8(s, code);
|
||||
in_uint8s(s, 1);
|
||||
in_uint16_le(s, size);
|
||||
switch (code)
|
||||
{
|
||||
case SNDC_WAVECONFIRM:
|
||||
sound_process_wave_confirm(s, size);
|
||||
break;
|
||||
|
||||
case SNDC_TRAINING:
|
||||
sound_process_training(s, size);
|
||||
break;
|
||||
|
||||
case SNDC_FORMATS:
|
||||
sound_process_formats(s, size);
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG(0, ("sound_data_in: unknown code %d size %d", code, size));
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -49,6 +400,20 @@ sound_data_in(struct stream* s, int chan_id, int chan_flags, int length,
|
|||
int APP_CC
|
||||
sound_get_wait_objs(tbus* objs, int* count, int* timeout)
|
||||
{
|
||||
int lcount;
|
||||
|
||||
lcount = *count;
|
||||
if (g_audio_l_trans != 0)
|
||||
{
|
||||
objs[lcount] = g_audio_l_trans->sck;
|
||||
lcount++;
|
||||
}
|
||||
if (g_audio_c_trans != 0)
|
||||
{
|
||||
objs[lcount] = g_audio_c_trans->sck;
|
||||
lcount++;
|
||||
}
|
||||
*count = lcount;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -56,5 +421,129 @@ sound_get_wait_objs(tbus* objs, int* count, int* timeout)
|
|||
int APP_CC
|
||||
sound_check_wait_objs(void)
|
||||
{
|
||||
if (g_audio_l_trans != 0)
|
||||
{
|
||||
trans_check_wait_objs(g_audio_l_trans);
|
||||
}
|
||||
|
||||
if (g_audio_c_trans != 0)
|
||||
{
|
||||
trans_check_wait_objs(g_audio_c_trans);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(XRDP_SIMPLESOUND)
|
||||
|
||||
/**
|
||||
* read raw audio data from pulseaudio device and write it
|
||||
* to a unix domain socket on which trans server is listening
|
||||
*/
|
||||
|
||||
static void *
|
||||
read_raw_audio_data(void* arg)
|
||||
{
|
||||
struct sockaddr_un serv_addr;
|
||||
pa_sample_spec samp_spec;
|
||||
pa_simple* simple = NULL;
|
||||
|
||||
uint32_t bytes_read;
|
||||
uint8_t audio_buf[AUDIO_BUF_SIZE + 8];
|
||||
char* cptr;
|
||||
int i;
|
||||
int error;
|
||||
int skt_fd;
|
||||
|
||||
// create client socket
|
||||
if ((skt_fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
|
||||
{
|
||||
LOG(0, ("read_raw_audio_data: error creating unix domain socket\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// setup server address and bind to it
|
||||
memset(&serv_addr, 0, sizeof(struct sockaddr_un));
|
||||
serv_addr.sun_family = AF_UNIX;
|
||||
g_snprintf(serv_addr.sun_path, 255, "/tmp/xrdp_chansrv_audio_socket_%d", g_display_num);
|
||||
|
||||
if (connect(skt_fd, (struct sockaddr *) &serv_addr, sizeof(struct sockaddr_un)) < 0)
|
||||
{
|
||||
LOG(0, ("read_raw_audio_data: error connecting to server\n"));
|
||||
close(skt_fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// setup audio format
|
||||
samp_spec.format = PA_SAMPLE_S16LE;
|
||||
samp_spec.rate = 44100;
|
||||
samp_spec.channels = 2;
|
||||
|
||||
// if we are root, then for first 8 seconds connection to pulseaudo server
|
||||
// fails; if we are non-root, then connection succeeds on first attempt;
|
||||
// for now we have changed code to be non-root, but this may change in the
|
||||
// future - so pretend we are root and try connecting to pulseaudio server
|
||||
// for upto one minute
|
||||
for (i = 0; i < 60; i++)
|
||||
{
|
||||
simple = pa_simple_new(NULL, "xrdp", PA_STREAM_RECORD, NULL,
|
||||
"record", &samp_spec, NULL, NULL, &error);
|
||||
if (simple)
|
||||
{
|
||||
// connected to pulseaudio server
|
||||
LOG(0, ("read_raw_audio_data: connected to pulseaudio server\n"));
|
||||
break;
|
||||
}
|
||||
LOG(0, ("read_raw_audio_data: ERROR creating PulseAudio async interface\n"));
|
||||
LOG(0, ("read_raw_audio_data: %s\n", pa_strerror(error)));
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
if (i == 60)
|
||||
{
|
||||
// failed to connect to audio server
|
||||
close(skt_fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// insert header just once
|
||||
cptr = audio_buf;
|
||||
ins_uint32_le(cptr, 0);
|
||||
ins_uint32_le(cptr, AUDIO_BUF_SIZE + 8);
|
||||
|
||||
while (1)
|
||||
{
|
||||
// read a block of raw audio data...
|
||||
if ((bytes_read = pa_simple_read(simple, cptr, AUDIO_BUF_SIZE, &error)) < 0)
|
||||
{
|
||||
LOG(0, ("read_raw_audio_data: ERROR reading from pulseaudio stream\n"));
|
||||
LOG(0, ("read_raw_audio_data: %s\n", pa_strerror(error)));
|
||||
break;
|
||||
}
|
||||
|
||||
// bug workaround:
|
||||
// even when there is no audio data, pulseaudio is returning without
|
||||
// errors but the data itself is zero; we use this zero data to
|
||||
// determine that there is no audio data present
|
||||
if (*cptr == 0 && *(cptr + 1) == 0 && *(cptr + 2) == 0 && *(cptr + 3) == 0)
|
||||
{
|
||||
usleep(10000);
|
||||
continue;
|
||||
}
|
||||
|
||||
// ... and write it to a unix domain socket
|
||||
if (write(skt_fd, audio_buf, AUDIO_BUF_SIZE + 8) < 0)
|
||||
{
|
||||
LOG(0, ("read_raw_audio_data: ERROR writing audio data to server\n"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
pa_simple_free(simple);
|
||||
close(skt_fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,20 +1,101 @@
|
|||
/**
|
||||
* xrdp: A Remote Desktop Protocol server.
|
||||
*
|
||||
* Copyright (C) Jay Sorg 2009-2012
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#if !defined(SOUND_H)
|
||||
#define SOUND_H
|
||||
#ifndef _SOUND_H_
|
||||
#define _SOUND_H_
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#if defined(XRDP_SIMPLESOUND)
|
||||
#include <pulse/simple.h>
|
||||
#include <pulse/error.h>
|
||||
#endif
|
||||
|
||||
#include "arch.h"
|
||||
#include "parse.h"
|
||||
#include "os_calls.h"
|
||||
#include "chansrv.h"
|
||||
#include "trans.h"
|
||||
|
||||
#define _DEBUG_RDPSND
|
||||
|
||||
#ifdef DEBUG_RDPSND
|
||||
#include <stdio.h>
|
||||
#define print_got_here() printf("****** got here: %s : %s : %d\n", \
|
||||
__FILE__, __func__, __LINE__);
|
||||
#else
|
||||
#define print_got_here()
|
||||
#endif
|
||||
|
||||
/**
|
||||
* insert a uint32_t value into specified byte array
|
||||
*
|
||||
* @param p pointer to byte array
|
||||
* @param v value to insert into byte array
|
||||
*/
|
||||
|
||||
#if defined(B_ENDIAN) || defined(NEED_ALIGN)
|
||||
#define ins_uint32_le(p, v) \
|
||||
{ \
|
||||
*p++ = (unsigned char) v; \
|
||||
*p++ = (unsigned char) (v >> 8); \
|
||||
*p++ = (unsigned char) (v >> 16); \
|
||||
*p++ = (unsigned char) (v >> 24); \
|
||||
}
|
||||
#else
|
||||
#define ins_uint32_le(p, v) \
|
||||
{ \
|
||||
*((uint32_t *) p) = v; \
|
||||
p += 4; \
|
||||
}
|
||||
#endif
|
||||
|
||||
#define AUDIO_BUF_SIZE 2048
|
||||
|
||||
#define SNDC_CLOSE 0x01
|
||||
#define SNDC_WAVE 0x02
|
||||
#define SNDC_SETVOLUME 0x03
|
||||
#define SNDC_SETPITCH 0x04
|
||||
#define SNDC_WAVECONFIRM 0x05
|
||||
#define SNDC_TRAINING 0x06
|
||||
#define SNDC_FORMATS 0x07
|
||||
#define SNDC_CRYPTKEY 0x08
|
||||
#define SNDC_WAVEENCRYPT 0x09
|
||||
#define SNDC_UDPWAVE 0x0A
|
||||
#define SNDC_UDPWAVELAST 0x0B
|
||||
#define SNDC_QUALITYMODE 0x0C
|
||||
|
||||
int APP_CC
|
||||
sound_init(void);
|
||||
int APP_CC
|
||||
sound_deinit(void);
|
||||
int APP_CC
|
||||
sound_data_in(struct stream* s, int chan_id, int chan_flags, int length,
|
||||
int total_length);
|
||||
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);
|
||||
|
||||
#if defined(XRDP_SIMPLESOUND)
|
||||
static void*
|
||||
read_raw_audio_data(void* arg);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue