From bf0d56c3141e3b177020ecd78d449f46555154ec Mon Sep 17 00:00:00 2001 From: Jay Sorg Date: Thu, 27 Jul 2017 22:02:04 -0700 Subject: [PATCH] chansrv: sound, add aac --- common/xrdp_constants.h | 1 + configure.ac | 11 ++ sesman/chansrv/Makefile.am | 5 + sesman/chansrv/sound.c | 243 ++++++++++++++++++++++++++++++++++++- 4 files changed, 258 insertions(+), 2 deletions(-) diff --git a/common/xrdp_constants.h b/common/xrdp_constants.h index 0b11b5bd..3512cb1e 100644 --- a/common/xrdp_constants.h +++ b/common/xrdp_constants.h @@ -401,6 +401,7 @@ #define WAVE_FORMAT_MULAW 0x0007 #define WAVE_FORMAT_MPEGLAYER3 0x0055 #define WAVE_FORMAT_OPUS 0x0069 +#define WAVE_FORMAT_AAC_MS 0xA106 /* Virtual channel options */ #define XR_CHANNEL_OPTION_SHOW_PROTOCOL 0x00200000 diff --git a/configure.ac b/configure.ac index def4bfd6..caa9fcf0 100644 --- a/configure.ac +++ b/configure.ac @@ -116,6 +116,10 @@ AC_ARG_ENABLE(xrdpvr, AS_HELP_STRING([--enable-xrdpvr], [Build xrdpvr module (default: no)]), [], [enable_xrdpvr=no]) AM_CONDITIONAL(XRDP_XRDPVR, [test x$enable_xrdpvr = xyes]) +AC_ARG_ENABLE(fdkaac, AS_HELP_STRING([--enable-fdkaac], + [Build aac(audio codec) (default: no)]), + [], [enable_fdkaac=no]) +AM_CONDITIONAL(XRDP_FDK_AAC, [test x$enable_fdkaac = xyes]) AC_ARG_ENABLE(opus, AS_HELP_STRING([--enable-opus], [Build opus(audio codec) (default: no)]), [], [enable_opus=no]) @@ -230,6 +234,13 @@ then [AC_MSG_ERROR([please install libfuse-dev or fuse-devel])]) fi +# checking for fdk aac +if test "x$enable_fdkaac" = "xyes" +then + AC_CHECK_HEADER([fdk-aac/aacenc_lib.h], [], + [AC_MSG_ERROR([please install libfdk-aac-dev or dontknow-devel])]) +fi + # checking for opus if test "x$enable_opus" = "xyes" then diff --git a/sesman/chansrv/Makefile.am b/sesman/chansrv/Makefile.am index 1df6c762..1e72b4ef 100644 --- a/sesman/chansrv/Makefile.am +++ b/sesman/chansrv/Makefile.am @@ -23,6 +23,11 @@ AM_CPPFLAGS += -DXRDP_FUSE $(FUSE_CFLAGS) CHANSRV_EXTRA_LIBS += $(FUSE_LIBS) endif +if XRDP_FDK_AAC +AM_CPPFLAGS += -DXRDP_FDK_AAC +CHANSRV_EXTRA_LIBS += -lfdk-aac +endif + if XRDP_OPUS AM_CPPFLAGS += -DXRDP_OPUS CHANSRV_EXTRA_LIBS += -lopus diff --git a/sesman/chansrv/sound.c b/sesman/chansrv/sound.c index e9fcb067..5a0db94b 100644 --- a/sesman/chansrv/sound.c +++ b/sesman/chansrv/sound.c @@ -35,6 +35,11 @@ #include "xrdp_sockets.h" #include "chansrv_common.h" +#if defined(XRDP_FDK_AAC) +#include +static HANDLE_AACENCODER g_fdk_aac_encoder = 0; +#endif + #if defined(XRDP_OPUS) #include static OpusEncoder *g_opus_encoder = 0; @@ -114,6 +119,21 @@ static struct xr_wave_format_ex g_pcm_44100 = g_pcm_44100_data /* data */ }; +#if defined(XRDP_FDK_AAC) +static tui8 g_fdk_aac_44100_data[] = { 0 }; +static struct xr_wave_format_ex g_fdk_aac_44100 = +{ + WAVE_FORMAT_AAC_MS, /* wFormatTag */ + 2, /* num of channels */ + 44100, /* samples per sec */ + 12000, /* avg bytes per sec */ + 4, /* block align */ + 16, /* bits per sample */ + 0, /* data size */ + g_fdk_aac_44100_data /* data */ +}; +#endif + #if defined(XRDP_OPUS) static tui8 g_opus_44100_data[] = { 0 }; static struct xr_wave_format_ex g_opus_44100 = @@ -148,6 +168,9 @@ static struct xr_wave_format_ex *g_wave_outp_formats[] = { &g_pcm_44100, &g_pcm_22050, +#if defined(XRDP_FDK_AAC) + &g_fdk_aac_44100, +#endif #if defined(XRDP_OPUS) &g_opus_44100, #endif @@ -157,6 +180,9 @@ static struct xr_wave_format_ex *g_wave_outp_formats[] = 0 }; +static int g_client_does_fdk_aac = 0; +static int g_client_fdk_aac_index = 0; + static int g_client_does_opus = 0; static int g_client_opus_index = 0; @@ -187,7 +213,7 @@ static struct xr_wave_format_ex g_pcm_inp_22050 = static tui8 g_pcm_inp_44100_data[] = { 0 }; static struct xr_wave_format_ex g_pcm_inp_44100 = { - 1, /* wFormatTag */ + WAVE_FORMAT_PCM, /* wFormatTag */ 2, /* num of channels */ 44100, /* samples per sec */ 176400, /* avg bytes per sec */ @@ -370,6 +396,12 @@ sound_process_output_format(int aindex, int wFormatTag, int nChannels, switch(wFormatTag) { + case WAVE_FORMAT_AAC_MS: + LOG(0, ("wFormatTag, fdk aac")); + g_client_does_fdk_aac = 1; + g_client_fdk_aac_index = aindex; + g_bbuf_size = 4096; + break; case WAVE_FORMAT_MPEGLAYER3: LOG(0, ("wFormatTag, mp3")); g_client_does_mp3lame = 1; @@ -437,6 +469,206 @@ sound_process_output_formats(struct stream *s, int size) return 0; } +#if defined(XRDP_FDK_AAC) + +/*****************************************************************************/ +static int +sound_wave_compress_fdk_aac(char *data, int data_bytes, int *format_index) +{ + int rv; + int cdata_bytes; + char *cdata; + + AACENC_ERROR error; + int aot; + int sample_rate; + int mode; + int bitrate; + int afterburner; + int channel_order; + AACENC_InfoStruct info = { 0 }; + AACENC_BufDesc in_buf = { 0 }; + AACENC_BufDesc out_buf = { 0 }; + AACENC_InArgs in_args = { 0 }; + AACENC_OutArgs out_args = { 0 }; + void *in_buffer[1]; + int in_identifier[1]; + int in_size[1]; + int in_elem_size[1]; + void *out_buffer[1]; + int out_identifier[1]; + int out_size[1]; + int out_elem_size[1]; + + rv = data_bytes; + + if (g_client_does_fdk_aac == 0) + { + return rv; + } + + if (g_fdk_aac_encoder == 0) + { + /* init fdk aac encoder */ + LOG(0, ("sound_wave_compress_fdk_aac: using fdk aac")); + + error = aacEncOpen(&g_fdk_aac_encoder, 0, 2); + if (error != AACENC_OK) + { + LOG(0, ("sound_wave_compress_fdk_aac: aacEncOpen() failed")); + return rv; + } + + aot = 2; /* MPEG-4 AAC Low Complexity. */ + //aot = 129; /* MPEG-2 AAC Low Complexity. */ + error = aacEncoder_SetParam(g_fdk_aac_encoder, AACENC_AOT, aot); + if (error != AACENC_OK) + { + LOG(0, ("sound_wave_compress_fdk_aac: aacEncoder_SetParam() " + "AACENC_AOT failed")); + } + + sample_rate = g_fdk_aac_44100.nSamplesPerSec; + error = aacEncoder_SetParam(g_fdk_aac_encoder, AACENC_SAMPLERATE, + sample_rate); + if (error != AACENC_OK) + { + LOG(0, ("sound_wave_compress_fdk_aac: aacEncoder_SetParam() " + "AACENC_SAMPLERATE failed")); + } + + mode = MODE_2; + error = aacEncoder_SetParam(g_fdk_aac_encoder, + AACENC_CHANNELMODE, mode); + if (error != AACENC_OK) + { + LOG(0, ("sound_wave_compress_fdk_aac: aacEncoder_SetParam() " + "AACENC_CHANNELMODE failed")); + } + + channel_order = 1; /* WAVE file format channel ordering */ + error = aacEncoder_SetParam(g_fdk_aac_encoder, AACENC_CHANNELORDER, + channel_order); + if (error != AACENC_OK) + { + LOG(0, ("sound_wave_compress_fdk_aac: aacEncoder_SetParam() " + "AACENC_CHANNELORDER failed")); + } + + /* bytes rate to bit rate */ + bitrate = g_fdk_aac_44100.nAvgBytesPerSec * 8; + error = aacEncoder_SetParam(g_fdk_aac_encoder, AACENC_BITRATE, + bitrate); + if (error != AACENC_OK) + { + LOG(0, ("sound_wave_compress_fdk_aac: aacEncoder_SetParam() " + "AACENC_BITRATE failed")); + } + + error = aacEncoder_SetParam(g_fdk_aac_encoder, AACENC_TRANSMUX, 0); + if (error != AACENC_OK) + { + LOG(0, ("sound_wave_compress_fdk_aac: aacEncoder_SetParam() " + "AACENC_TRANSMUX failed")); + } + + afterburner = 1; + error = aacEncoder_SetParam(g_fdk_aac_encoder, AACENC_AFTERBURNER, + afterburner); + if (error != AACENC_OK) + { + LOG(0, ("sound_wave_compress_fdk_aac: aacEncoder_SetParam() " + "AACENC_AFTERBURNER failed")); + } + + error = aacEncEncode(g_fdk_aac_encoder, NULL, NULL, NULL, NULL); + if (error != AACENC_OK) + { + LOG(0, ("sound_wave_compress_fdk_aac: Unable to initialize " + "the encoder")); + } + + error = aacEncInfo(g_fdk_aac_encoder, &info); + if (error != AACENC_OK) + { + LOG(0, ("sound_wave_compress_fdk_aac: aacEncInfo failed")); + } + + LOG(0, ("sound_wave_compress_fdk_aac:")); + LOG(0, (" AACENC_InfoStruct")); + LOG(0, (" maxOutBufBytes %d", info.maxOutBufBytes)); + LOG(0, (" maxAncBytes %d", info.maxAncBytes)); + LOG(0, (" inBufFillLevel %d", info.inBufFillLevel)); + LOG(0, (" inputChannels %d", info.inputChannels)); + LOG(0, (" frameLength %d", info.frameLength)); + LOG(0, (" encoderDelay %d", info.encoderDelay)); + LOG(0, (" confBuf")); + LOG(0, (" confSize %d", info.confSize)); + } + + rv = data_bytes; + cdata_bytes = data_bytes; + cdata = (char *) g_malloc(cdata_bytes, 0); + if (data_bytes < g_bbuf_size) + { + g_memset(data + data_bytes, 0, g_bbuf_size - data_bytes); + data_bytes = g_bbuf_size; + } + + in_buffer[0] = data; + in_identifier[0] = IN_AUDIO_DATA; + in_size[0] = data_bytes; + in_elem_size[0] = 2; + + in_args.numInSamples = data_bytes / 2; + in_buf.numBufs = 1; + in_buf.bufs = in_buffer; + in_buf.bufferIdentifiers = in_identifier; + in_buf.bufSizes = in_size; + in_buf.bufElSizes = in_elem_size; + + out_buffer[0] = cdata; + out_identifier[0] = OUT_BITSTREAM_DATA; + out_size[0] = cdata_bytes; + out_elem_size[0] = 1; + + out_buf.numBufs = 1; + out_buf.bufs = out_buffer; + out_buf.bufferIdentifiers = out_identifier; + out_buf.bufSizes = out_size; + out_buf.bufElSizes = out_elem_size; + + error = aacEncEncode(g_fdk_aac_encoder, &in_buf, &out_buf, + &in_args, &out_args); + if (error == AACENC_OK) + { + cdata_bytes = out_args.numOutBytes; + LOG(10, ("sound_wave_compress_fdk_aac: aacEncEncode ok " + "cdata_bytes %d", cdata_bytes)); + *format_index = g_client_fdk_aac_index; + g_memcpy(data, cdata, cdata_bytes); + rv = cdata_bytes; + } + else + { + LOG(0, ("sound_wave_compress_fdk_aac: aacEncEncode failed")); + } + g_free(cdata); + + return rv; +} + +#else + +/*****************************************************************************/ +static int +sound_wave_compress_fdk_aac(char *data, int data_bytes, int *format_index) +{ + return data_bytes; +} + +#endif + #if defined(XRDP_OPUS) /*****************************************************************************/ @@ -602,7 +834,11 @@ sound_wave_compress_mp3lame(char *data, int data_bytes, int *format_index) static int sound_wave_compress(char *data, int data_bytes, int *format_index) { - if (g_client_does_opus) + if (g_client_does_fdk_aac) + { + return sound_wave_compress_fdk_aac(data, data_bytes, format_index); + } + else if (g_client_does_opus) { return sound_wave_compress_opus(data, data_bytes, format_index); } @@ -982,6 +1218,9 @@ sound_init(void) /* save data from sound_server_source */ fifo_init(&g_in_fifo, 100); + g_client_does_fdk_aac = 0; + g_client_fdk_aac_index = 0; + g_client_does_opus = 0; g_client_opus_index = 0;