From e8e4800c5e481d59b0d2e9ad4a3516020ee04d97 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 7 Nov 2018 14:14:15 +0100 Subject: [PATCH 01/13] Added resampling to freerdp_dsp_encode. --- libfreerdp/codec/dsp.c | 49 +++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/libfreerdp/codec/dsp.c b/libfreerdp/codec/dsp.c index 5dac569d0..22b2d3423 100644 --- a/libfreerdp/codec/dsp.c +++ b/libfreerdp/codec/dsp.c @@ -21,6 +21,7 @@ #include "config.h" #endif +#include #include #include #include @@ -104,19 +105,27 @@ struct _FREERDP_DSP_CONTEXT */ static BOOL freerdp_dsp_resample(FREERDP_DSP_CONTEXT* context, - const BYTE* src, size_t bytes_per_sample, - UINT32 schan, UINT32 srate, size_t sframes, - UINT32 rchan, UINT32 rrate) + const BYTE* src, size_t size, + const AUDIO_FORMAT* srcFormat) { BYTE* p; - int rframes; - int rsize; - int i, j; - int n1, n2; - int sbytes, rbytes; - sbytes = bytes_per_sample * schan; - rbytes = bytes_per_sample * rchan; - rframes = sframes * rrate / srate; + size_t sframes, rframes; + size_t rsize; + size_t i, j; + size_t sbytes, rbytes; + size_t srcBytePerFrame; + + if (!context || !src || !srcFormat) + return FALSE; + + assert(srcFormat->wFormatTag == WAVE_FORMAT_PCM); + srcBytePerFrame = (srcFormat->wBitsPerSample > 8) ? 2 : 1; + sbytes = srcFormat->nChannels * srcBytePerFrame; + sframes = size / sbytes; + rbytes = srcBytePerFrame * context->format.nChannels; + /* Integer rounding correct division */ + rframes = (sframes * context->format.nSamplesPerSec + (srcFormat->nSamplesPerSec + 1) / 2) / + srcFormat->nSamplesPerSec; rsize = rbytes * rframes; if (!Stream_EnsureCapacity(context->resample, rsize + 1024)) @@ -126,17 +135,20 @@ static BOOL freerdp_dsp_resample(FREERDP_DSP_CONTEXT* context, for (i = 0; i < rframes; i++) { - n1 = i * srate / rrate; + size_t n2; + size_t n1 = (i * srcFormat->nSamplesPerSec) / context->format.nSamplesPerSec; if (n1 >= sframes) n1 = sframes - 1; - n2 = (n1 * rrate == i * srate || n1 == sframes - 1 ? n1 : n1 + 1); + n2 = ((n1 * context->format.nSamplesPerSec == i * srcFormat->nSamplesPerSec) || + ((n1 == sframes - 1) ? n1 : n1 + 1)); for (j = 0; j < rbytes; j++) { /* Nearest Interpolation, probably the easiest, but works */ - *p++ = (i * srate - n1 * rrate > n2 * rrate - i * srate ? + *p++ = (i * srcFormat->nSamplesPerSec - n1 * context->format.nSamplesPerSec > n2 * + context->format.nSamplesPerSec - i * srcFormat->nSamplesPerSec ? src[n2 * sbytes + (j % sbytes)] : src[n1 * sbytes + (j % sbytes)]); } @@ -1032,7 +1044,14 @@ BOOL freerdp_dsp_encode(FREERDP_DSP_CONTEXT* context, const AUDIO_FORMAT* srcFor if (!context || !context->encoder || !srcFormat || !data || !out) return FALSE; - // TODO: Resample + if (srcFormat->nSamplesPerSec != context->format.nSamplesPerSec) + { + if (!freerdp_dsp_resample(context, data, length, srcFormat)) + return FALSE; + + data = Stream_Buffer(context->resample); + length = Stream_GetPosition(context->resample); + } switch (context->format.wFormatTag) { From 60025dde8ea66090266786a240473efc91a27bd7 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 9 Nov 2018 09:08:06 +0100 Subject: [PATCH 02/13] Fixed unused function warnings when FFMPEG backend is used. --- libfreerdp/codec/dsp.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/libfreerdp/codec/dsp.c b/libfreerdp/codec/dsp.c index 22b2d3423..ea1ea5a7d 100644 --- a/libfreerdp/codec/dsp.c +++ b/libfreerdp/codec/dsp.c @@ -31,6 +31,7 @@ #include #include +#if !defined(WITH_DSP_FFMPEG) #if defined(WITH_GSM) #include #endif @@ -39,10 +40,6 @@ #include #endif -#if defined(WITH_DSP_FFMPEG) -#include "dsp_ffmpeg.h" -#endif - #if defined(WITH_FAAD2) #include #endif @@ -51,8 +48,14 @@ #include #endif +#else +#include "dsp_ffmpeg.h" +#endif + #define TAG FREERDP_TAG("dsp") +#if !defined(WITH_DSP_FFMPEG) + union _ADPCM { struct @@ -923,6 +926,8 @@ static BOOL freerdp_dsp_encode_ms_adpcm(FREERDP_DSP_CONTEXT* context, const BYTE return TRUE; } +#endif + FREERDP_DSP_CONTEXT* freerdp_dsp_context_new(BOOL encoder) { #if defined(WITH_DSP_FFMPEG) From 83f959ce6bbae4389acdf40066710b1c5724349d Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 9 Nov 2018 10:05:11 +0100 Subject: [PATCH 03/13] Fixed format issues with server sound channel (review by @llysz) --- channels/rdpsnd/server/rdpsnd_main.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/channels/rdpsnd/server/rdpsnd_main.c b/channels/rdpsnd/server/rdpsnd_main.c index 4be0b3078..ccfcb23aa 100644 --- a/channels/rdpsnd/server/rdpsnd_main.c +++ b/channels/rdpsnd/server/rdpsnd_main.c @@ -301,8 +301,7 @@ static UINT rdpsnd_server_select_format(RdpsndServerContext* context, AUDIO_FORMAT* format; UINT error = CHANNEL_RC_OK; - if ((client_format_index < 0) - || (client_format_index >= context->num_client_formats) + if ((client_format_index >= context->num_client_formats) || (!context->src_format)) { WLog_ERR(TAG, "index %d is not correct.", client_format_index); @@ -415,6 +414,10 @@ static UINT rdpsnd_server_send_wave_pdu(RdpsndServerContext* context, ULONG written; wStream* s = context->priv->rdpsnd_pdu; UINT error = CHANNEL_RC_OK; + + if (context->selected_client_format >= context->num_client_formats) + return ERROR_INTERNAL_ERROR; + format = &context->client_formats[context->selected_client_format]; /* WaveInfo PDU */ Stream_SetPosition(s, 0); @@ -429,7 +432,7 @@ static UINT rdpsnd_server_send_wave_pdu(RdpsndServerContext* context, src = context->priv->out_buffer; length = context->priv->out_pending_frames * context->priv->src_bytes_per_frame; - if (!freerdp_dsp_encode(context->priv->dsp_context, format, src, length, s)) + if (!freerdp_dsp_encode(context->priv->dsp_context, context->src_format, src, length, s)) return ERROR_INTERNAL_ERROR; else { @@ -491,6 +494,10 @@ static UINT rdpsnd_server_send_wave2_pdu(RdpsndServerContext* context, ULONG written; wStream* s = context->priv->rdpsnd_pdu; UINT error = CHANNEL_RC_OK; + + if (context->selected_client_format >= context->num_client_formats) + return ERROR_INTERNAL_ERROR; + format = &context->client_formats[context->selected_client_format]; /* WaveInfo PDU */ Stream_SetPosition(s, 0); @@ -501,7 +508,7 @@ static UINT rdpsnd_server_send_wave2_pdu(RdpsndServerContext* context, Stream_Write_UINT16(s, context->selected_client_format); /* wFormatNo */ Stream_Write_UINT8(s, context->block_no); /* cBlockNo */ Stream_Seek(s, 3); /* bPad */ - Stream_Write_UINT16(s, wTimestamp); /* dwAudioTimeStamp */ + Stream_Write_UINT32(s, wTimestamp); /* dwAudioTimeStamp */ src = context->priv->out_buffer; length = context->priv->out_pending_frames * context->priv->src_bytes_per_frame; @@ -558,7 +565,7 @@ static UINT rdpsnd_server_send_samples(RdpsndServerContext* context, UINT error = CHANNEL_RC_OK; EnterCriticalSection(&context->priv->lock); - if (context->selected_client_format < 0) + if (context->selected_client_format >= context->num_client_formats) { /* It's possible while format negotiation has not been done */ WLog_WARN(TAG, "Drop samples because client format has not been negotiated."); @@ -636,7 +643,7 @@ static UINT rdpsnd_server_close(RdpsndServerContext* context) if (context->priv->out_pending_frames > 0) { - if (context->selected_client_format < 0) + if (context->selected_client_format >= context->num_client_formats) { WLog_ERR(TAG, "Pending audio frame exists while no format selected."); error = ERROR_INVALID_DATA; @@ -652,7 +659,7 @@ static UINT rdpsnd_server_close(RdpsndServerContext* context) if (error) return error; - context->selected_client_format = -1; + context->selected_client_format = 0xFFFF; Stream_Write_UINT8(s, SNDC_CLOSE); Stream_Write_UINT8(s, 0); Stream_Seek_UINT16(s); @@ -807,7 +814,7 @@ RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm) context->vcm = vcm; context->Start = rdpsnd_server_start; context->Stop = rdpsnd_server_stop; - context->selected_client_format = -1; + context->selected_client_format = 0xFFFF; context->Initialize = rdpsnd_server_initialize; context->SelectFormat = rdpsnd_server_select_format; context->SendSamples = rdpsnd_server_send_samples; From ab15e340321aa6cfd2fe444dbcaae8f7d3ee78ff Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 9 Nov 2018 10:15:14 +0100 Subject: [PATCH 04/13] Refactored freerdp_dsp_resample, checks now done internally. --- libfreerdp/codec/dsp.c | 68 +++++++++++++++++++++++++++++++----------- 1 file changed, 50 insertions(+), 18 deletions(-) diff --git a/libfreerdp/codec/dsp.c b/libfreerdp/codec/dsp.c index ea1ea5a7d..d5cbb6c87 100644 --- a/libfreerdp/codec/dsp.c +++ b/libfreerdp/codec/dsp.c @@ -29,6 +29,7 @@ #include #include +#include #include #if !defined(WITH_DSP_FFMPEG) @@ -109,29 +110,65 @@ struct _FREERDP_DSP_CONTEXT static BOOL freerdp_dsp_resample(FREERDP_DSP_CONTEXT* context, const BYTE* src, size_t size, - const AUDIO_FORMAT* srcFormat) + const AUDIO_FORMAT* srcFormat, + const BYTE** data, size_t* length) { BYTE* p; size_t sframes, rframes; size_t rsize; size_t i, j; size_t sbytes, rbytes; - size_t srcBytePerFrame; + size_t srcBytesPerFrame, dstBytesPerFrame; + size_t srcChannels, dstChannels; + AUDIO_FORMAT format; - if (!context || !src || !srcFormat) + if (!context || !src || !srcFormat || !data || !length) return FALSE; - assert(srcFormat->wFormatTag == WAVE_FORMAT_PCM); - srcBytePerFrame = (srcFormat->wBitsPerSample > 8) ? 2 : 1; - sbytes = srcFormat->nChannels * srcBytePerFrame; + if (srcFormat->wFormatTag != WAVE_FORMAT_PCM) + { + WLog_ERR(TAG, "%s requires %s for sample input, got %s", __FUNCTION__, + audio_format_get_tag_string(WAVE_FORMAT_PCM), + audio_format_get_tag_string(srcFormat->wFormatTag)); + return FALSE; + } + + srcChannels = srcFormat->nChannels; + dstChannels = context->format.nChannels; + srcBytesPerFrame = (srcFormat->wBitsPerSample > 8) ? 2 : 1; + dstBytesPerFrame = (context->format.wBitsPerSample > 8) ? 2 : 1; + /* We want to ignore differences of source and destination format. */ + format = *srcFormat; + format.wFormatTag = WAVE_FORMAT_UNKNOWN; + + if (audio_format_compatible(&format, &context->format)) + return TRUE; + + /* TODO: Currently sample size conversion is not implemented. */ + if (srcFormat->wBitsPerSample != context->format.wBitsPerSample) + { + WLog_ERR(TAG, "%s does not support changing sample bit width [in=%"PRId16", out=%"PRId16"]", + __FUNCTION__, srcFormat->wBitsPerSample, context->format.wBitsPerSample); + return FALSE; + } + + /* TODO: Currently sample size conversion is not implemented. */ + if (srcChannels != dstChannels) + { + WLog_ERR(TAG, "%s does not support changing number of channels [in=%"PRIdz", out=%"PRIdz"]", + __FUNCTION__, srcChannels, dstChannels); + return FALSE; + } + + sbytes = srcChannels * srcBytesPerFrame; sframes = size / sbytes; - rbytes = srcBytePerFrame * context->format.nChannels; + rbytes = dstBytesPerFrame * dstChannels; /* Integer rounding correct division */ rframes = (sframes * context->format.nSamplesPerSec + (srcFormat->nSamplesPerSec + 1) / 2) / srcFormat->nSamplesPerSec; - rsize = rbytes * rframes; + rsize = rframes * rbytes; - if (!Stream_EnsureCapacity(context->resample, rsize + 1024)) + if (!Stream_EnsureCapacity(context->resample, rsize)) return FALSE; p = Stream_Buffer(context->resample); @@ -159,6 +196,8 @@ static BOOL freerdp_dsp_resample(FREERDP_DSP_CONTEXT* context, Stream_SetPointer(context->resample, p); Stream_SealLength(context->resample); + *data = Stream_Buffer(context->resample); + *length = Stream_Length(context->resample); return TRUE; } @@ -1049,14 +1088,8 @@ BOOL freerdp_dsp_encode(FREERDP_DSP_CONTEXT* context, const AUDIO_FORMAT* srcFor if (!context || !context->encoder || !srcFormat || !data || !out) return FALSE; - if (srcFormat->nSamplesPerSec != context->format.nSamplesPerSec) - { - if (!freerdp_dsp_resample(context, data, length, srcFormat)) - return FALSE; - - data = Stream_Buffer(context->resample); - length = Stream_GetPosition(context->resample); - } + if (!freerdp_dsp_resample(context, data, length, srcFormat, &data, &length)) + return FALSE; switch (context->format.wFormatTag) { @@ -1196,7 +1229,6 @@ BOOL freerdp_dsp_supports_format(const AUDIO_FORMAT* format, BOOL encode) #endif } - BOOL freerdp_dsp_context_reset(FREERDP_DSP_CONTEXT* context, const AUDIO_FORMAT* targetFormat) { #if defined(WITH_DSP_FFMPEG) From e93aab2f7f55565bc5418d37c9251c654579185b Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 13 Nov 2018 09:13:52 +0100 Subject: [PATCH 05/13] Added CMake detection support for libsoxr --- CMakeLists.txt | 5 ++++ cmake/Findsoxr.cmake | 61 ++++++++++++++++++++++++++++++++++++++++++++ config.h.in | 1 + 3 files changed, 67 insertions(+) create mode 100644 cmake/Findsoxr.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 306354f7b..1d7a541a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -770,6 +770,10 @@ set(FAAC_FEATURE_TYPE "OPTIONAL") set(FAAC_FEATURE_PURPOSE "codec") set(FAAC_FEATURE_DESCRIPTION "FAAC AAC audio codec library") +set(SOXR_FEATURE_TYPE "OPTIONAL") +set(SOXR_FEATURE_PURPOSE "codec") +set(SOXR_FEATURE_DESCRIPTION "SOX audio resample library") + set(GSSAPI_FEATURE_TYPE "OPTIONAL") set(GSSAPI_FEATURE_PURPOSE "auth") set(GSSAPI_FEATURE_DESCRIPTION "add kerberos support") @@ -873,6 +877,7 @@ find_feature(GSM ${GSM_FEATURE_TYPE} ${GSM_FEATURE_PURPOSE} ${GSM_FEATURE_DESCRI find_feature(LAME ${LAME_FEATURE_TYPE} ${LAME_FEATURE_PURPOSE} ${LAME_FEATURE_DESCRIPTION}) find_feature(FAAD2 ${FAAD2_FEATURE_TYPE} ${FAAD2_FEATURE_PURPOSE} ${FAAD2_FEATURE_DESCRIPTION}) find_feature(FAAC ${FAAC_FEATURE_TYPE} ${FAAC_FEATURE_PURPOSE} ${FAAC_FEATURE_DESCRIPTION}) +find_feature(soxr ${SOXR_FEATURE_TYPE} ${SOXR_FEATURE_PURPOSE} ${SOXR_FEATURE_DESCRIPTION}) find_feature(GSSAPI ${GSSAPI_FEATURE_TYPE} ${GSSAPI_FEATURE_PURPOSE} ${GSSAPI_FEATURE_DESCRIPTION}) diff --git a/cmake/Findsoxr.cmake b/cmake/Findsoxr.cmake new file mode 100644 index 000000000..e62da2f9c --- /dev/null +++ b/cmake/Findsoxr.cmake @@ -0,0 +1,61 @@ +# Try to find the soxr library +# +# Copyright 2018 Thincast Technologies GmbH +# Copyright 2018 Armin Novak +# +# 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 +# +# Once done this will define +# +# SOXR_ROOT - A list of search hints +# +# SOXR_FOUND - system has soxr +# SOXR_INCLUDE_DIR - the soxr include directory +# SOXR_LIBRARIES - libsoxr library + +if (UNIX AND NOT ANDROID) + find_package(PkgConfig QUIET) + pkg_check_modules(PC_SOXR QUIET soxr) +endif (UNIX AND NOT ANDROID) + +if (SOXR_INCLUDE_DIR AND SOXR_LIBRARY) + set(SOXR_FIND_QUIETLY TRUE) +endif (SOXR_INCLUDE_DIR AND SOXR_LIBRARY) + +find_path(SOXR_INCLUDE_DIR NAMES soxr.h + PATH_SUFFIXES include + HINTS ${SOXR_ROOT} ${PC_SOXR_INCLUDE_DIRS}) +find_library(SOXR_LIBRARY + NAMES soxr + PATH_SUFFIXES lib + HINTS ${SOXR_ROOT} ${PC_SOXR_LIBRARY_DIRS}) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(soxr DEFAULT_MSG SOXR_LIBRARY SOXR_INCLUDE_DIR) + +if (SOXR_INCLUDE_DIR AND SOXR_LIBRARY) + set(SOXR_FOUND TRUE) + set(SOXR_LIBRARIES ${SOXR_LIBRARY}) +endif (SOXR_INCLUDE_DIR AND SOXR_LIBRARY) + +if (SOXR_FOUND) + if (NOT SOXR_FIND_QUIETLY) + message(STATUS "Found soxr: ${SOXR_LIBRARIES}") + endif (NOT SOXR_FIND_QUIETLY) +else (SOXR_FOUND) + if (SOXR_FIND_REQUIRED) + message(FATAL_ERROR "soxr was not found") + endif(SOXR_FIND_REQUIRED) +endif (SOXR_FOUND) + +mark_as_advanced(SOXR_INCLUDE_DIR SOXR_LIBRARY) + diff --git a/config.h.in b/config.h.in index 26bc059f7..92f447e6b 100644 --- a/config.h.in +++ b/config.h.in @@ -57,6 +57,7 @@ #cmakedefine WITH_LAME #cmakedefine WITH_FAAD2 #cmakedefine WITH_FAAC +#cmakedefine WITH_SOXR #cmakedefine WITH_GFX_H264 #cmakedefine WITH_OPENH264 #cmakedefine WITH_FFMPEG From b362b61a1a096475aa74c71781859dd8b4678e77 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 13 Nov 2018 10:59:30 +0100 Subject: [PATCH 06/13] Added libsoxr based resampling. --- libfreerdp/codec/dsp.c | 83 +++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 45 deletions(-) diff --git a/libfreerdp/codec/dsp.c b/libfreerdp/codec/dsp.c index d5cbb6c87..3a58009cf 100644 --- a/libfreerdp/codec/dsp.c +++ b/libfreerdp/codec/dsp.c @@ -49,6 +49,10 @@ #include #endif +#if defined(WITH_SOXR) +#include +#endif + #else #include "dsp_ffmpeg.h" #endif @@ -101,6 +105,10 @@ struct _FREERDP_DSP_CONTEXT unsigned long faacInputSamples; unsigned long faacMaxOutputBytes; #endif + +#if defined(WITH_SOXR) + soxr_t sox; +#endif }; /** @@ -113,10 +121,11 @@ static BOOL freerdp_dsp_resample(FREERDP_DSP_CONTEXT* context, const AUDIO_FORMAT* srcFormat, const BYTE** data, size_t* length) { - BYTE* p; + soxr_error_t error; + size_t idone, odone; size_t sframes, rframes; size_t rsize; - size_t i, j; + size_t j; size_t sbytes, rbytes; size_t srcBytesPerFrame, dstBytesPerFrame; size_t srcChannels, dstChannels; @@ -137,6 +146,7 @@ static BOOL freerdp_dsp_resample(FREERDP_DSP_CONTEXT* context, dstChannels = context->format.nChannels; srcBytesPerFrame = (srcFormat->wBitsPerSample > 8) ? 2 : 1; dstBytesPerFrame = (context->format.wBitsPerSample > 8) ? 2 : 1; + /* We want to ignore differences of source and destination format. */ format = *srcFormat; format.wFormatTag = WAVE_FORMAT_UNKNOWN; @@ -144,22 +154,6 @@ static BOOL freerdp_dsp_resample(FREERDP_DSP_CONTEXT* context, if (audio_format_compatible(&format, &context->format)) return TRUE; - /* TODO: Currently sample size conversion is not implemented. */ - if (srcFormat->wBitsPerSample != context->format.wBitsPerSample) - { - WLog_ERR(TAG, "%s does not support changing sample bit width [in=%"PRId16", out=%"PRId16"]", - __FUNCTION__, srcFormat->wBitsPerSample, context->format.wBitsPerSample); - return FALSE; - } - - /* TODO: Currently sample size conversion is not implemented. */ - if (srcChannels != dstChannels) - { - WLog_ERR(TAG, "%s does not support changing number of channels [in=%"PRIdz", out=%"PRIdz"]", - __FUNCTION__, srcChannels, dstChannels); - return FALSE; - } - sbytes = srcChannels * srcBytesPerFrame; sframes = size / sbytes; rbytes = dstBytesPerFrame * dstChannels; @@ -171,34 +165,14 @@ static BOOL freerdp_dsp_resample(FREERDP_DSP_CONTEXT* context, if (!Stream_EnsureCapacity(context->resample, rsize)) return FALSE; - p = Stream_Buffer(context->resample); + error = soxr_process(context->sox, src, sframes, &idone, + Stream_Buffer(context->resample), + Stream_Capacity(context->resample)/rbytes, &odone); - for (i = 0; i < rframes; i++) - { - size_t n2; - size_t n1 = (i * srcFormat->nSamplesPerSec) / context->format.nSamplesPerSec; - - if (n1 >= sframes) - n1 = sframes - 1; - - n2 = ((n1 * context->format.nSamplesPerSec == i * srcFormat->nSamplesPerSec) || - ((n1 == sframes - 1) ? n1 : n1 + 1)); - - for (j = 0; j < rbytes; j++) - { - /* Nearest Interpolation, probably the easiest, but works */ - *p++ = (i * srcFormat->nSamplesPerSec - n1 * context->format.nSamplesPerSec > n2 * - context->format.nSamplesPerSec - i * srcFormat->nSamplesPerSec ? - src[n2 * sbytes + (j % sbytes)] : - src[n1 * sbytes + (j % sbytes)]); - } - } - - Stream_SetPointer(context->resample, p); - Stream_SealLength(context->resample); + Stream_SetLength(context->resample, odone * rbytes); *data = Stream_Buffer(context->resample); *length = Stream_Length(context->resample); - return TRUE; + return (error == 0) ? TRUE : FALSE; } /** @@ -465,16 +439,18 @@ static BOOL freerdp_dsp_encode_faac(FREERDP_DSP_CONTEXT* context, { int16_t* inSamples = (int16_t*)src; int32_t* outSamples; + unsigned int bpp; unsigned int nrSamples, x; int rc; if (!context || !src || !out) return FALSE; - nrSamples = size / context->format.nChannels / context->format.wBitsPerSample / 8; + bpp = context->format.wBitsPerSample / 8 * context->format.nChannels; + nrSamples = size / bpp; if (!Stream_EnsureCapacity(context->buffer, - context->faacInputSamples * sizeof(int32_t) * context->format.nChannels)) + nrSamples * sizeof(int32_t) * context->format.nChannels)) return FALSE; if (!Stream_EnsureRemainingCapacity(out, context->faacMaxOutputBytes)) @@ -1071,6 +1047,9 @@ void freerdp_dsp_context_free(FREERDP_DSP_CONTEXT* context) if (context->faac) faacEncClose(context->faac); +#endif +#if defined(WITH_SOXR) + soxr_delete(context->sox); #endif free(context); } @@ -1262,6 +1241,20 @@ BOOL freerdp_dsp_context_reset(FREERDP_DSP_CONTEXT* context, const AUDIO_FORMAT* faacEncSetConfiguration(context->faac, cfg); } +#endif +#if defined(WITH_SOXR) + { + soxr_io_spec_t iospec = soxr_io_spec(SOXR_INT16, SOXR_INT16); + soxr_error_t error; + soxr_delete(context->sox); + + context->sox = soxr_create(context->format.nSamplesPerSec, targetFormat->nSamplesPerSec, + targetFormat->nChannels, &error, &iospec, NULL, NULL); + + if (!context->sox || (error != 0)) + return FALSE; + + } #endif return TRUE; #endif From 93eea24120e08d0889759a7e49d0e1d327c9da4a Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 13 Nov 2018 10:59:41 +0100 Subject: [PATCH 07/13] Fixed possible NULL pointer dereference --- channels/audin/client/pulse/audin_pulse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/channels/audin/client/pulse/audin_pulse.c b/channels/audin/client/pulse/audin_pulse.c index 3a5ff734f..d22de87d2 100644 --- a/channels/audin/client/pulse/audin_pulse.c +++ b/channels/audin/client/pulse/audin_pulse.c @@ -306,7 +306,7 @@ static void audin_pulse_stream_request_callback(pa_stream* stream, size_t length AudinPulseDevice* pulse = (AudinPulseDevice*) userdata; UINT error = CHANNEL_RC_OK; pa_stream_peek(stream, &data, &length); - error = pulse->receive(&pulse->format, data, length, pulse->user_data); + error = IFCALLRESULT(CHANNEL_RC_OK, pulse->receive, &pulse->format, data, length, pulse->user_data); pa_stream_drop(stream); if (error && pulse->rdpcontext) From 0f45a570fadced039eb86f0de717fb509ddae770 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 13 Nov 2018 11:00:39 +0100 Subject: [PATCH 08/13] Added fallback for supported sample rates if original not supported. Added format compatibility check between recording input and destination. --- channels/audin/client/audin_main.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/channels/audin/client/audin_main.c b/channels/audin/client/audin_main.c index 8b86830c1..b7ce33042 100644 --- a/channels/audin/client/audin_main.c +++ b/channels/audin/client/audin_main.c @@ -341,6 +341,7 @@ static UINT audin_receive_wave_data(const AUDIO_FORMAT* format, const BYTE* data, size_t size, void* user_data) { UINT error; + BOOL compatible; AUDIN_PLUGIN* audin; AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) user_data; @@ -362,7 +363,8 @@ static UINT audin_receive_wave_data(const AUDIO_FORMAT* format, Stream_Write_UINT8(audin->data, MSG_SNDIN_DATA); - if (audin->device->FormatSupported(audin->device, audin->format)) + compatible = audio_format_compatible(format, audin->format); + if (compatible && audin->device->FormatSupported(audin->device, audin->format)) { if (!Stream_EnsureRemainingCapacity(audin->data, size)) return CHANNEL_RC_NO_MEMORY; @@ -408,8 +410,31 @@ static BOOL audin_open_device(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callb if (!supported) { + /* Default sample rates supported by most backends. */ + const UINT32 samplerates[] = { + 96000, + 48000, + 44100, + 22050 + }; + BOOL test = FALSE; + format.wFormatTag = WAVE_FORMAT_PCM; format.wBitsPerSample = 16; + test = IFCALLRESULT(FALSE, audin->device->FormatSupported, audin->device, &format); + if (!test) + { + size_t x; + for (x=0; xdevice->FormatSupported, audin->device, &format); + if (test) + break; + } + } + if (!test) + return FALSE; } IFCALLRET(audin->device->SetFormat, error, From 6af56458ad430787ff63b5cb2acfc356493ac701 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 13 Nov 2018 11:03:09 +0100 Subject: [PATCH 09/13] Marked custom ADPCM codecs experimental. --- libfreerdp/codec/dsp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libfreerdp/codec/dsp.c b/libfreerdp/codec/dsp.c index 3a58009cf..08279a8cc 100644 --- a/libfreerdp/codec/dsp.c +++ b/libfreerdp/codec/dsp.c @@ -146,7 +146,6 @@ static BOOL freerdp_dsp_resample(FREERDP_DSP_CONTEXT* context, dstChannels = context->format.nChannels; srcBytesPerFrame = (srcFormat->wBitsPerSample > 8) ? 2 : 1; dstBytesPerFrame = (context->format.wBitsPerSample > 8) ? 2 : 1; - /* We want to ignore differences of source and destination format. */ format = *srcFormat; format.wFormatTag = WAVE_FORMAT_UNKNOWN; @@ -166,9 +165,8 @@ static BOOL freerdp_dsp_resample(FREERDP_DSP_CONTEXT* context, return FALSE; error = soxr_process(context->sox, src, sframes, &idone, - Stream_Buffer(context->resample), - Stream_Capacity(context->resample)/rbytes, &odone); - + Stream_Buffer(context->resample), + Stream_Capacity(context->resample) / rbytes, &odone); Stream_SetLength(context->resample, odone * rbytes); *data = Stream_Buffer(context->resample); *length = Stream_Length(context->resample); @@ -1165,9 +1163,13 @@ BOOL freerdp_dsp_supports_format(const AUDIO_FORMAT* format, BOOL encode) switch (format->wFormatTag) { case WAVE_FORMAT_PCM: + return TRUE; +#if defined(WITH_DSP_EXPERIMENTAL) + case WAVE_FORMAT_ADPCM: case WAVE_FORMAT_DVI_ADPCM: return TRUE; +#endif #if defined(WITH_GSM) case WAVE_FORMAT_GSM610: @@ -1247,13 +1249,11 @@ BOOL freerdp_dsp_context_reset(FREERDP_DSP_CONTEXT* context, const AUDIO_FORMAT* soxr_io_spec_t iospec = soxr_io_spec(SOXR_INT16, SOXR_INT16); soxr_error_t error; soxr_delete(context->sox); - context->sox = soxr_create(context->format.nSamplesPerSec, targetFormat->nSamplesPerSec, targetFormat->nChannels, &error, &iospec, NULL, NULL); if (!context->sox || (error != 0)) return FALSE; - } #endif return TRUE; From 5b363e72aa714061d827d7dcf7f666c5998fa514 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 13 Nov 2018 11:06:38 +0100 Subject: [PATCH 10/13] Allow building without libsoxr support. --- libfreerdp/codec/dsp.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libfreerdp/codec/dsp.c b/libfreerdp/codec/dsp.c index 08279a8cc..7d896ef00 100644 --- a/libfreerdp/codec/dsp.c +++ b/libfreerdp/codec/dsp.c @@ -131,9 +131,6 @@ static BOOL freerdp_dsp_resample(FREERDP_DSP_CONTEXT* context, size_t srcChannels, dstChannels; AUDIO_FORMAT format; - if (!context || !src || !srcFormat || !data || !length) - return FALSE; - if (srcFormat->wFormatTag != WAVE_FORMAT_PCM) { WLog_ERR(TAG, "%s requires %s for sample input, got %s", __FUNCTION__, @@ -153,6 +150,7 @@ static BOOL freerdp_dsp_resample(FREERDP_DSP_CONTEXT* context, if (audio_format_compatible(&format, &context->format)) return TRUE; +#if defined(WITH_SOXR) sbytes = srcChannels * srcBytesPerFrame; sframes = size / sbytes; rbytes = dstBytesPerFrame * dstChannels; @@ -171,6 +169,10 @@ static BOOL freerdp_dsp_resample(FREERDP_DSP_CONTEXT* context, *data = Stream_Buffer(context->resample); *length = Stream_Length(context->resample); return (error == 0) ? TRUE : FALSE; +#else + WLog_ERR(TAG, "Missing resample support, recompile -DWITH_SOXR=ON or -DWITH_DSP_FFMPEG=ON"); + return FALSE; +#endif } /** From 9766161f104bac8c9fb88ba7dc8e9cc0bc6d73ae Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 13 Nov 2018 12:29:19 +0100 Subject: [PATCH 11/13] Added missing define guards. --- libfreerdp/codec/dsp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libfreerdp/codec/dsp.c b/libfreerdp/codec/dsp.c index 7d896ef00..4e83791d7 100644 --- a/libfreerdp/codec/dsp.c +++ b/libfreerdp/codec/dsp.c @@ -121,8 +121,10 @@ static BOOL freerdp_dsp_resample(FREERDP_DSP_CONTEXT* context, const AUDIO_FORMAT* srcFormat, const BYTE** data, size_t* length) { +#if defined(WITH_SOXR) soxr_error_t error; size_t idone, odone; +#endif size_t sframes, rframes; size_t rsize; size_t j; From e5197f529d4c872add056df26ec919b07130d083 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 13 Nov 2018 14:04:43 +0100 Subject: [PATCH 12/13] Add soxr library and include paths. --- cmake/Findsoxr.cmake | 1 + libfreerdp/CMakeLists.txt | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/cmake/Findsoxr.cmake b/cmake/Findsoxr.cmake index e62da2f9c..8a19946cb 100644 --- a/cmake/Findsoxr.cmake +++ b/cmake/Findsoxr.cmake @@ -44,6 +44,7 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(soxr DEFAULT_MSG SOXR_LIBRARY SOXR_INCLUDE_DIR if (SOXR_INCLUDE_DIR AND SOXR_LIBRARY) set(SOXR_FOUND TRUE) + set(SOXR_INCLUDE_DIRS ${SOXR_INCLUDE_DIR}) set(SOXR_LIBRARIES ${SOXR_LIBRARY}) endif (SOXR_INCLUDE_DIR AND SOXR_LIBRARY) diff --git a/libfreerdp/CMakeLists.txt b/libfreerdp/CMakeLists.txt index e71a180a0..fe05a79ef 100644 --- a/libfreerdp/CMakeLists.txt +++ b/libfreerdp/CMakeLists.txt @@ -162,6 +162,11 @@ if (WITH_DSP_FFMPEG) codec/dsp_ffmpeg.h) endif (WITH_DSP_FFMPEG) +if (WITH_SOXR) + freerdp_library_add(${SOXR_LIBRARIES}) + include_directories(${SOXR_INCLUDE_DIR}) +endif(WITH_SOXR) + if(GSM_FOUND) freerdp_library_add(${GSM_LIBRARIES}) include_directories(${GSM_INCLUDE_DIRS}) From 5490ceb4ed04d68c3edafffdf36821cea1ba1d40 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 13 Nov 2018 14:46:51 +0100 Subject: [PATCH 13/13] Fixed source format for freerdp_dsp_encode in rdpsnd_server_send_wave_pdu --- channels/rdpsnd/server/rdpsnd_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/channels/rdpsnd/server/rdpsnd_main.c b/channels/rdpsnd/server/rdpsnd_main.c index ccfcb23aa..53d4d5c32 100644 --- a/channels/rdpsnd/server/rdpsnd_main.c +++ b/channels/rdpsnd/server/rdpsnd_main.c @@ -512,7 +512,7 @@ static UINT rdpsnd_server_send_wave2_pdu(RdpsndServerContext* context, src = context->priv->out_buffer; length = context->priv->out_pending_frames * context->priv->src_bytes_per_frame; - if (!freerdp_dsp_encode(context->priv->dsp_context, format, src, length, s)) + if (!freerdp_dsp_encode(context->priv->dsp_context, context->src_format, src, length, s)) error = ERROR_INTERNAL_ERROR; else {