chansrv: added opus audio compression for playback
This commit is contained in:
parent
46215e36d1
commit
2f5b84b712
11
configure.ac
11
configure.ac
@ -69,6 +69,10 @@ AC_ARG_ENABLE(rfxcodec, AS_HELP_STRING([--enable-rfxcodec],
|
||||
[Build using librfxcodec (default: no)]),
|
||||
[], [enable_rfxcodec=no])
|
||||
AM_CONDITIONAL(XRDP_RFXCODEC, [test x$enable_rfxcodec = xyes])
|
||||
AC_ARG_ENABLE(opus, AS_HELP_STRING([--enable-opus],
|
||||
[Build opus(audio codec) (default: no)]),
|
||||
[], [enable_opus=no])
|
||||
AM_CONDITIONAL(XRDP_OPUS, [test x$enable_opus = xyes])
|
||||
|
||||
AM_CONDITIONAL(GOT_PREFIX, test "x${prefix}" != "xNONE"])
|
||||
|
||||
@ -122,6 +126,13 @@ then
|
||||
[#define _FILE_OFFSET_BITS 64])
|
||||
fi
|
||||
|
||||
# checking for opus
|
||||
if test "x$enable_opus" = "xyes"
|
||||
then
|
||||
AC_CHECK_HEADER([opus/opus.h], [],
|
||||
[AC_MSG_ERROR([please install libopus-dev or opus-devel])])
|
||||
fi
|
||||
|
||||
# checking for TurboJPEG
|
||||
if test "x$enable_tjpeg" = "xyes"
|
||||
then
|
||||
|
@ -22,6 +22,11 @@ EXTRA_DEFINES += -DXRDP_FUSE
|
||||
EXTRA_LIBS += -lfuse
|
||||
endif
|
||||
|
||||
if XRDP_OPUS
|
||||
EXTRA_DEFINES += -DXRDP_OPUS
|
||||
EXTRA_LIBS += -lopus
|
||||
endif
|
||||
|
||||
AM_CFLAGS = \
|
||||
-DXRDP_CFG_PATH=\"${sysconfdir}/xrdp\" \
|
||||
-DXRDP_SBIN_PATH=\"${sbindir}\" \
|
||||
|
@ -30,6 +30,11 @@
|
||||
#include "file_loc.h"
|
||||
#include "chansrv_common.h"
|
||||
|
||||
#if defined(XRDP_OPUS)
|
||||
#include <opus/opus.h>
|
||||
static OpusEncoder *g_opus_encoder = 0;
|
||||
#endif
|
||||
|
||||
extern int g_rdpsnd_chan_id; /* in chansrv.c */
|
||||
extern int g_display_num; /* in chansrv.c */
|
||||
|
||||
@ -50,11 +55,13 @@ static int g_bytes_in_fifo = 0;
|
||||
static struct stream *g_stream_inp = NULL;
|
||||
static struct stream *g_stream_incoming_packet = NULL;
|
||||
|
||||
#define BBUF_SIZE (1024 * 8)
|
||||
char g_buffer[BBUF_SIZE];
|
||||
int g_buf_index = 0;
|
||||
int g_sent_time[256];
|
||||
int g_sent_flag[256];
|
||||
#define MAX_BBUF_SIZE (1024 * 16)
|
||||
static char g_buffer[MAX_BBUF_SIZE];
|
||||
static int g_buf_index = 0;
|
||||
static int g_sent_time[256];
|
||||
static int g_sent_flag[256];
|
||||
|
||||
static int g_bbuf_size = 1024 * 8; /* may change later */
|
||||
|
||||
struct xr_wave_format_ex
|
||||
{
|
||||
@ -96,12 +103,39 @@ static struct xr_wave_format_ex g_pcm_44100 =
|
||||
g_pcm_44100_data /* data */
|
||||
};
|
||||
|
||||
static char g_opus_44100_data[] = { 0 };
|
||||
static struct xr_wave_format_ex g_opus_44100 =
|
||||
{
|
||||
0x0069, /* wFormatTag - WAVE_FORMAT_OPUS */
|
||||
2, /* num of channels */
|
||||
44100, /* samples per sec */
|
||||
176400, /* avg bytes per sec */
|
||||
4, /* block align */
|
||||
16, /* bits per sample */
|
||||
0, /* data size */
|
||||
g_opus_44100_data /* data */
|
||||
};
|
||||
|
||||
|
||||
#if defined(XRDP_OPUS)
|
||||
#define SND_NUM_OUTP_FORMATS 3
|
||||
static struct xr_wave_format_ex *g_wave_outp_formats[SND_NUM_OUTP_FORMATS] =
|
||||
{
|
||||
&g_pcm_44100,
|
||||
&g_pcm_22050,
|
||||
&g_opus_44100
|
||||
};
|
||||
#else
|
||||
#define SND_NUM_OUTP_FORMATS 2
|
||||
static struct xr_wave_format_ex *g_wave_outp_formats[SND_NUM_OUTP_FORMATS] =
|
||||
{
|
||||
&g_pcm_44100,
|
||||
&g_pcm_22050
|
||||
};
|
||||
#endif
|
||||
|
||||
static int g_client_does_opus = 0;
|
||||
static int g_client_opus_index = 0;
|
||||
|
||||
/* index into list from client */
|
||||
static int g_current_client_format_index = 0;
|
||||
@ -302,6 +336,14 @@ sound_process_output_format(int aindex, int wFormatTag, int nChannels,
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (wFormatTag == 0x0069)
|
||||
{
|
||||
g_client_does_opus = 1;
|
||||
g_client_opus_index = aindex;
|
||||
g_bbuf_size = 11520;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -355,6 +397,72 @@ sound_process_output_formats(struct stream *s, int size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(XRDP_OPUS)
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
sound_wave_compress(char *data, int data_bytes, int *format_index)
|
||||
{
|
||||
unsigned char *cdata;
|
||||
int cdata_bytes;
|
||||
int rv;
|
||||
int error;
|
||||
opus_int16 *os16;
|
||||
|
||||
if (g_client_does_opus == 0)
|
||||
{
|
||||
return data_bytes;
|
||||
}
|
||||
if (g_opus_encoder == 0)
|
||||
{
|
||||
// NB (narrowband) 8 kHz
|
||||
// MB (medium-band) 12 kHz
|
||||
// WB (wideband) 16 kHz
|
||||
// SWB (super-wideband) 24 kHz
|
||||
// FB (fullband) 48 kHz
|
||||
g_opus_encoder = opus_encoder_create(48000, 2,
|
||||
OPUS_APPLICATION_AUDIO,
|
||||
&error);
|
||||
if (g_opus_encoder == 0)
|
||||
{
|
||||
LOG(0, ("sound_wave_compress: opus_encoder_create failed"));
|
||||
return data_bytes;
|
||||
}
|
||||
}
|
||||
rv = data_bytes;
|
||||
cdata_bytes = data_bytes;
|
||||
cdata = (unsigned char *) g_malloc(cdata_bytes, 0);
|
||||
os16 = (opus_int16 *) data;
|
||||
// at 48000 we have
|
||||
// 2.5 ms 480
|
||||
// 5 ms 960
|
||||
// 10 ms 1920
|
||||
// 20 ms 3840
|
||||
// 40 ms 7680
|
||||
// 60 ms 11520
|
||||
cdata_bytes = opus_encode(g_opus_encoder, os16, data_bytes / 4,
|
||||
cdata, cdata_bytes);
|
||||
if ((cdata_bytes > 0) && (cdata_bytes < data_bytes))
|
||||
{
|
||||
*format_index = g_client_opus_index;
|
||||
g_memcpy(data, cdata, cdata_bytes);
|
||||
rv = cdata_bytes;
|
||||
}
|
||||
g_free(cdata);
|
||||
return rv;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
sound_wave_compress(char *data, int data_bytes, int *format_index)
|
||||
{
|
||||
return data_bytes;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* send wave message to client */
|
||||
static int
|
||||
@ -363,6 +471,7 @@ sound_send_wave_data_chunk(char *data, int data_bytes)
|
||||
struct stream *s;
|
||||
int bytes;
|
||||
int time;
|
||||
int format_index;
|
||||
char *size_ptr;
|
||||
|
||||
LOG(10, ("sound_send_wave_data_chunk: data_bytes %d", data_bytes));
|
||||
@ -385,6 +494,10 @@ sound_send_wave_data_chunk(char *data, int data_bytes)
|
||||
LOG(10, ("sound_send_wave_data_chunk: got room"));
|
||||
}
|
||||
|
||||
/* compress, if available */
|
||||
format_index = g_current_client_format_index;
|
||||
data_bytes = sound_wave_compress(data, data_bytes, &format_index);
|
||||
|
||||
/* part one of 2 PDU wave info */
|
||||
|
||||
LOG(10, ("sound_send_wave_data_chunk: sending %d bytes", data_bytes));
|
||||
@ -396,7 +509,7 @@ sound_send_wave_data_chunk(char *data, int data_bytes)
|
||||
out_uint16_le(s, 0); /* size, set later */
|
||||
time = g_time2();
|
||||
out_uint16_le(s, time);
|
||||
out_uint16_le(s, g_current_client_format_index); /* wFormatNo */
|
||||
out_uint16_le(s, format_index); /* wFormatNo */
|
||||
g_cBlockNo++;
|
||||
out_uint8(s, g_cBlockNo);
|
||||
g_sent_time[g_cBlockNo & 0xff] = time;
|
||||
@ -445,7 +558,7 @@ sound_send_wave_data(char *data, int data_bytes)
|
||||
error = 0;
|
||||
while (data_bytes > 0)
|
||||
{
|
||||
space_left = BBUF_SIZE - g_buf_index;
|
||||
space_left = g_bbuf_size - g_buf_index;
|
||||
chunk_bytes = MIN(space_left, data_bytes);
|
||||
if (chunk_bytes < 1)
|
||||
{
|
||||
@ -455,10 +568,10 @@ sound_send_wave_data(char *data, int data_bytes)
|
||||
}
|
||||
g_memcpy(g_buffer + g_buf_index, data + data_index, chunk_bytes);
|
||||
g_buf_index += chunk_bytes;
|
||||
if (g_buf_index >= BBUF_SIZE)
|
||||
if (g_buf_index >= g_bbuf_size)
|
||||
{
|
||||
g_buf_index = 0;
|
||||
res = sound_send_wave_data_chunk(g_buffer, BBUF_SIZE);
|
||||
res = sound_send_wave_data_chunk(g_buffer, g_bbuf_size);
|
||||
if (res == 2)
|
||||
{
|
||||
/* don't need to error on this */
|
||||
|
Loading…
Reference in New Issue
Block a user