summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Sorg <jay.sorg@gmail.com>2015-01-09 23:31:28 -0800
committerJay Sorg <jay.sorg@gmail.com>2015-01-09 23:31:28 -0800
commit2f5b84b71273f942023259d64b27ddd6f4625046 (patch)
treecfd85619c39c335560df3c2d3c895601a5fc4bee
parent46215e36d116aeb506bd142df46de1aa0a95e5bd (diff)
downloadxrdp-proprietary-2f5b84b71273f942023259d64b27ddd6f4625046.tar.gz
xrdp-proprietary-2f5b84b71273f942023259d64b27ddd6f4625046.zip
chansrv: added opus audio compression for playback
-rw-r--r--configure.ac11
-rw-r--r--sesman/chansrv/Makefile.am5
-rw-r--r--sesman/chansrv/sound.c131
3 files changed, 138 insertions, 9 deletions
diff --git a/configure.ac b/configure.ac
index e1a150e8..9730aaad 100644
--- a/configure.ac
+++ b/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
diff --git a/sesman/chansrv/Makefile.am b/sesman/chansrv/Makefile.am
index 7a97c136..ed55ae02 100644
--- a/sesman/chansrv/Makefile.am
+++ b/sesman/chansrv/Makefile.am
@@ -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}\" \
diff --git a/sesman/chansrv/sound.c b/sesman/chansrv/sound.c
index e0628a87..a3ee337c 100644
--- a/sesman/chansrv/sound.c
+++ b/sesman/chansrv/sound.c
@@ -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 */