diff --git a/channels/audin/client/audin_main.c b/channels/audin/client/audin_main.c index ea552d40c..f9cead2d8 100644 --- a/channels/audin/client/audin_main.c +++ b/channels/audin/client/audin_main.c @@ -416,22 +416,24 @@ 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 }; + const UINT32 samplerates[] = { format.nSamplesPerSec, 96000, 48000, 44100, 22050 }; BOOL test = FALSE; + size_t x; format.wFormatTag = WAVE_FORMAT_PCM; format.wBitsPerSample = 16; - test = IFCALLRESULT(FALSE, audin->device->FormatSupported, audin->device, &format); - if (!test) + format.cbSize = 0; + for (x = 0; x < ARRAYSIZE(samplerates); x++) { - size_t x; - for (x = 0; x < ARRAYSIZE(samplerates); x++) - { - format.nSamplesPerSec = samplerates[x]; - test = IFCALLRESULT(FALSE, audin->device->FormatSupported, audin->device, &format); - if (test) - break; - } + format.nSamplesPerSec = samplerates[x]; + format.nChannels = audin->format->nChannels; + test = IFCALLRESULT(FALSE, audin->device->FormatSupported, audin->device, &format); + if (test) + break; + format.nChannels = 3 - format.nChannels; + test = IFCALLRESULT(FALSE, audin->device->FormatSupported, audin->device, &format); + if (test) + break; } if (!test) return FALSE; @@ -447,7 +449,7 @@ static BOOL audin_open_device(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callb if (!supported) { - if (!freerdp_dsp_context_reset(audin->dsp_context, audin->format)) + if (!freerdp_dsp_context_reset(audin->dsp_context, audin->format, audin->FramesPerPacket)) return FALSE; } @@ -943,7 +945,7 @@ BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, const ADDIN_ARGV* args) { unsigned long val = strtoul(arg->Value, NULL, 0); - if ((errno != 0) || (val > UINT16_MAX)) + if ((errno != 0) || (val < UINT16_MAX)) audin->fixed_format->nChannels = val; } CommandLineSwitchDefault(arg) diff --git a/channels/audin/client/mac/audin_mac.m b/channels/audin/client/mac/audin_mac.m index 48dce2695..a974837f1 100644 --- a/channels/audin/client/mac/audin_mac.m +++ b/channels/audin/client/mac/audin_mac.m @@ -120,6 +120,9 @@ static BOOL audin_mac_format_supported(IAudinDevice *device, const AUDIO_FORMAT if (device == NULL || format == NULL) return FALSE; + if (format->nChannels != 2) + return FALSE; + req_fmt = audin_mac_get_format(format); if (req_fmt == 0) diff --git a/channels/audin/server/audin.c b/channels/audin/server/audin.c index 13e4cf754..10d61ed26 100644 --- a/channels/audin/server/audin.c +++ b/channels/audin/server/audin.c @@ -86,7 +86,7 @@ static UINT audin_server_select_format(audin_server_context* context, size_t cli context->selected_client_format = (SSIZE_T)client_format_index; if (!freerdp_dsp_context_reset(audin->dsp_context, - &audin->context.client_formats[client_format_index])) + &audin->context.client_formats[client_format_index], 0u)) { WLog_ERR(TAG, "Failed to reset dsp context format!"); return ERROR_INTERNAL_ERROR; diff --git a/channels/rdpsnd/client/mac/rdpsnd_mac.m b/channels/rdpsnd/client/mac/rdpsnd_mac.m index 8a01d9b73..d8c4da8d6 100644 --- a/channels/rdpsnd/client/mac/rdpsnd_mac.m +++ b/channels/rdpsnd/client/mac/rdpsnd_mac.m @@ -237,6 +237,9 @@ static BOOL rdpsnd_mac_format_supported(rdpsndDevicePlugin *device, const AUDIO_ case WAVE_FORMAT_PCM: if (format->wBitsPerSample != 16) return FALSE; + + if (format->nChannels != 2) + return FALSE; return TRUE; default: diff --git a/channels/rdpsnd/client/rdpsnd_main.c b/channels/rdpsnd/client/rdpsnd_main.c index be48c420c..95fc2cd6e 100644 --- a/channels/rdpsnd/client/rdpsnd_main.c +++ b/channels/rdpsnd/client/rdpsnd_main.c @@ -407,7 +407,7 @@ static BOOL rdpsnd_ensure_device_is_open(rdpsndPlugin* rdpsnd, UINT32 wFormatNo, if (!supported) { - if (!freerdp_dsp_context_reset(rdpsnd->dsp_context, format)) + if (!freerdp_dsp_context_reset(rdpsnd->dsp_context, format, 0u)) return FALSE; } diff --git a/channels/rdpsnd/server/rdpsnd_main.c b/channels/rdpsnd/server/rdpsnd_main.c index 8e72a76cf..a52f5d72d 100644 --- a/channels/rdpsnd/server/rdpsnd_main.c +++ b/channels/rdpsnd/server/rdpsnd_main.c @@ -365,7 +365,7 @@ static UINT rdpsnd_server_select_format(RdpsndServerContext* context, UINT16 cli context->priv->out_buffer_size = out_buffer_size; } - freerdp_dsp_context_reset(context->priv->dsp_context, format); + freerdp_dsp_context_reset(context->priv->dsp_context, format, 0u); out: LeaveCriticalSection(&context->priv->lock); return error; diff --git a/include/freerdp/codec/dsp.h b/include/freerdp/codec/dsp.h index 7776885ff..779966169 100644 --- a/include/freerdp/codec/dsp.h +++ b/include/freerdp/codec/dsp.h @@ -40,7 +40,8 @@ extern "C" const BYTE* data, size_t length, wStream* out); FREERDP_API void freerdp_dsp_context_free(FREERDP_DSP_CONTEXT* context); FREERDP_API BOOL freerdp_dsp_context_reset(FREERDP_DSP_CONTEXT* context, - const AUDIO_FORMAT* targetFormat); + const AUDIO_FORMAT* targetFormat, + UINT32 FramesPerPacket); #ifdef __cplusplus } diff --git a/libfreerdp/codec/dsp.c b/libfreerdp/codec/dsp.c index 9c5d8f7ec..29f8ace79 100644 --- a/libfreerdp/codec/dsp.c +++ b/libfreerdp/codec/dsp.c @@ -64,6 +64,7 @@ union _ADPCM { struct { + size_t packet_size; INT16 last_sample[2]; INT16 last_step[2]; } ima; @@ -84,8 +85,9 @@ struct _FREERDP_DSP_CONTEXT ADPCM adpcm; AUDIO_FORMAT format; - wStream* buffer; + wStream* channelmix; wStream* resample; + wStream* buffer; #if defined(WITH_GSM) gsm gsm; @@ -136,7 +138,7 @@ static BOOL freerdp_dsp_channel_mix(FREERDP_DSP_CONTEXT* context, const BYTE* sr return FALSE; bpp = srcFormat->wBitsPerSample > 8 ? 2 : 1; - samples = size / bpp; + samples = size / bpp / srcFormat->nChannels; if (context->format.nChannels == srcFormat->nChannels) { @@ -145,7 +147,7 @@ static BOOL freerdp_dsp_channel_mix(FREERDP_DSP_CONTEXT* context, const BYTE* sr return TRUE; } - Stream_SetPosition(context->buffer, 0); + Stream_SetPosition(context->channelmix, 0); /* Destination has more channels than source */ if (context->format.nChannels > srcFormat->nChannels) @@ -153,21 +155,21 @@ static BOOL freerdp_dsp_channel_mix(FREERDP_DSP_CONTEXT* context, const BYTE* sr switch (srcFormat->nChannels) { case 1: - if (!Stream_EnsureCapacity(context->buffer, size * 2)) + if (!Stream_EnsureCapacity(context->channelmix, size * 2)) return FALSE; for (x = 0; x < samples; x++) { for (y = 0; y < bpp; y++) - Stream_Write_UINT8(context->buffer, src[x * bpp + y]); + Stream_Write_UINT8(context->channelmix, src[x * bpp + y]); for (y = 0; y < bpp; y++) - Stream_Write_UINT8(context->buffer, src[x * bpp + y]); + Stream_Write_UINT8(context->channelmix, src[x * bpp + y]); } - Stream_SealLength(context->buffer); - *data = Stream_Buffer(context->buffer); - *length = Stream_Length(context->buffer); + Stream_SealLength(context->channelmix); + *data = Stream_Buffer(context->channelmix); + *length = Stream_Length(context->channelmix); return TRUE; case 2: /* We only support stereo, so we can not handle this case. */ @@ -180,7 +182,7 @@ static BOOL freerdp_dsp_channel_mix(FREERDP_DSP_CONTEXT* context, const BYTE* sr switch (srcFormat->nChannels) { case 2: - if (!Stream_EnsureCapacity(context->buffer, size / 2)) + if (!Stream_EnsureCapacity(context->channelmix, size / 2)) return FALSE; /* Simply drop second channel. @@ -188,12 +190,12 @@ static BOOL freerdp_dsp_channel_mix(FREERDP_DSP_CONTEXT* context, const BYTE* sr for (x = 0; x < samples; x++) { for (y = 0; y < bpp; y++) - Stream_Write_UINT8(context->buffer, src[2 * x * bpp + y]); + Stream_Write_UINT8(context->channelmix, src[2 * x * bpp + y]); } - Stream_SealLength(context->buffer); - *data = Stream_Buffer(context->buffer); - *length = Stream_Length(context->buffer); + Stream_SealLength(context->channelmix); + *data = Stream_Buffer(context->channelmix); + *length = Stream_Length(context->channelmix); return TRUE; case 1: /* Invalid, do we want to use a 0 channel sound? */ @@ -238,9 +240,14 @@ static BOOL freerdp_dsp_resample(FREERDP_DSP_CONTEXT* context, const BYTE* src, /* We want to ignore differences of source and destination format. */ format = *srcFormat; format.wFormatTag = WAVE_FORMAT_UNKNOWN; + format.wBitsPerSample = 0; if (audio_format_compatible(&format, &context->format)) + { + *data = src; + *length = size; return TRUE; + } #if defined(WITH_SOXR) sbytes = srcChannels * srcBytesPerFrame; @@ -261,10 +268,6 @@ static BOOL freerdp_dsp_resample(FREERDP_DSP_CONTEXT* context, const BYTE* src, *length = Stream_Length(context->resample); return (error == 0) ? TRUE : FALSE; #else - WINPR_UNUSED(src); - WINPR_UNUSED(size); - WINPR_UNUSED(data); - WINPR_UNUSED(length); WLog_ERR(TAG, "Missing resample support, recompile -DWITH_SOXR=ON or -DWITH_DSP_FFMPEG=ON"); return FALSE; #endif @@ -720,10 +723,11 @@ static BOOL freerdp_dsp_encode_ima_adpcm(FREERDP_DSP_CONTEXT* context, const BYT if (!Stream_EnsureRemainingCapacity(out, size)) return FALSE; - start = dst = Stream_Pointer(out); + start = Stream_Buffer(context->buffer); + dst = Stream_Pointer(context->buffer); align = (context->format.nChannels > 1) ? 32 : 4; - while (size > align) + while (size >= align) { if ((dst - start) % context->format.nBlockAlign == 0) { @@ -768,9 +772,15 @@ static BOOL freerdp_dsp_encode_ima_adpcm(FREERDP_DSP_CONTEXT* context, const BYT *dst++ = encoded; size -= 4; } + + if (dst - start == context->adpcm.ima.packet_size) + { + Stream_Write(out, start, context->adpcm.ima.packet_size); + dst = Stream_Buffer(context->buffer); + } } - Stream_SetPointer(out, dst); + Stream_SetPointer(context->buffer, dst); return TRUE; } @@ -1025,9 +1035,9 @@ FREERDP_DSP_CONTEXT* freerdp_dsp_context_new(BOOL encoder) if (!context) return NULL; - context->buffer = Stream_New(NULL, 4096); + context->channelmix = Stream_New(NULL, 4096); - if (!context->buffer) + if (!context->channelmix) goto fail; context->resample = Stream_New(NULL, 4096); @@ -1035,6 +1045,11 @@ FREERDP_DSP_CONTEXT* freerdp_dsp_context_new(BOOL encoder) if (!context->resample) goto fail; + context->buffer = Stream_New(NULL, 4096); + + if (!context->buffer) + goto fail; + context->encoder = encoder; #if defined(WITH_GSM) context->gsm = gsm_create(); @@ -1095,8 +1110,9 @@ void freerdp_dsp_context_free(FREERDP_DSP_CONTEXT* context) if (context) { - Stream_Free(context->buffer, TRUE); + Stream_Free(context->channelmix, TRUE); Stream_Free(context->resample, TRUE); + Stream_Free(context->buffer, TRUE); #if defined(WITH_GSM) gsm_destroy(context->gsm); #endif @@ -1254,6 +1270,7 @@ BOOL freerdp_dsp_supports_format(const AUDIO_FORMAT* format, BOOL encode) #if defined(WITH_DSP_EXPERIMENTAL) case WAVE_FORMAT_ADPCM: + return FALSE; case WAVE_FORMAT_DVI_ADPCM: return TRUE; #endif @@ -1297,7 +1314,8 @@ 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) +BOOL freerdp_dsp_context_reset(FREERDP_DSP_CONTEXT* context, const AUDIO_FORMAT* targetFormat, + UINT32 FramesPerPacket) { #if defined(WITH_DSP_FFMPEG) return freerdp_dsp_ffmpeg_context_reset(context, targetFormat); @@ -1307,6 +1325,22 @@ BOOL freerdp_dsp_context_reset(FREERDP_DSP_CONTEXT* context, const AUDIO_FORMAT* return FALSE; context->format = *targetFormat; + + if (context->format.wFormatTag == WAVE_FORMAT_DVI_ADPCM) + { + size_t min_frame_data = + context->format.wBitsPerSample * context->format.nChannels * FramesPerPacket * 1ULL; + size_t data_per_block = (context->format.nBlockAlign - 4 * context->format.nChannels) * 8; + size_t nb_block_per_packet = min_frame_data / data_per_block; + + if (min_frame_data % data_per_block) + nb_block_per_packet++; + + context->adpcm.ima.packet_size = nb_block_per_packet * context->format.nBlockAlign; + Stream_EnsureCapacity(context->buffer, context->adpcm.ima.packet_size); + Stream_SetPosition(context->buffer, 0); + } + #if defined(WITH_FAAD2) context->faadSetup = FALSE; #endif