From f89c1857b9773fe0a472caf95bc533f43abad48d Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 20 Feb 2018 12:15:30 +0100 Subject: [PATCH] Rewrite of sound and microphone channels The sound and microphone redirection channels (and in part TSMF) did not properly decouple encoding/decoding from the backends used to play/record sound. Encapsulating encoding/decoding in rewritten freerdp_dsp_* functions with variable backends, simplifying alsa/oss/pulse/... audio backends. --- CMakeLists.txt | 15 + channels/audin/client/alsa/audin_alsa.c | 282 ++--- channels/audin/client/audin_main.c | 405 ++++---- channels/audin/client/mac/audin_mac.c | 587 +++++------ .../audin/client/opensles/audin_opensl_es.c | 242 ++--- channels/audin/client/oss/audin_oss.c | 103 +- channels/audin/client/pulse/audin_pulse.c | 156 +-- channels/audin/client/winmm/audin_winmm.c | 966 +++++++++--------- channels/audin/server/audin.c | 60 +- channels/rdpsnd/client/CMakeLists.txt | 3 - channels/rdpsnd/client/alsa/rdpsnd_alsa.c | 271 +---- channels/rdpsnd/client/ios/rdpsnd_ios.c | 8 +- channels/rdpsnd/client/mac/rdpsnd_mac.c | 207 ++-- .../rdpsnd/client/opensles/rdpsnd_opensles.c | 87 +- channels/rdpsnd/client/oss/rdpsnd_oss.c | 104 +- channels/rdpsnd/client/pulse/CMakeLists.txt | 6 - channels/rdpsnd/client/pulse/rdpsnd_pulse.c | 273 ++--- channels/rdpsnd/client/rdpsnd_main.c | 732 +++++-------- channels/rdpsnd/client/rdpsnd_main.h | 2 - channels/rdpsnd/client/winmm/rdpsnd_winmm.c | 187 +--- channels/rdpsnd/server/rdpsnd_main.c | 104 +- channels/tsmf/client/alsa/tsmf_alsa.c | 139 +-- channels/tsmf/client/oss/tsmf_oss.c | 16 +- channels/tsmf/client/pulse/tsmf_pulse.c | 227 ++-- channels/tsmf/client/tsmf_audio.h | 17 +- channels/tsmf/client/tsmf_media.c | 33 +- cmake/ConfigOptions.cmake | 4 + cmake/FindFAAC.cmake | 13 + cmake/FindFAAD2.cmake | 13 + cmake/FindFFmpeg.cmake | 42 +- cmake/FindLAME.cmake | 13 + config.h.in | 4 + include/freerdp/client/audin.h | 30 +- include/freerdp/client/rdpsnd.h | 50 +- include/freerdp/codec/audio.h | 10 +- include/freerdp/codec/dsp.h | 63 +- libfreerdp/CMakeLists.txt | 28 + libfreerdp/codec/audio.c | 32 +- libfreerdp/codec/dsp.c | 792 +++++++++++--- libfreerdp/codec/dsp.h | 34 + libfreerdp/codec/dsp_ffmpeg.c | 566 ++++++++++ libfreerdp/codec/dsp_ffmpeg.h | 42 + server/shadow/shadow_audin.c | 7 +- 43 files changed, 3424 insertions(+), 3551 deletions(-) create mode 100644 cmake/FindFAAC.cmake create mode 100644 cmake/FindFAAD2.cmake create mode 100644 cmake/FindLAME.cmake create mode 100644 libfreerdp/codec/dsp.h create mode 100644 libfreerdp/codec/dsp_ffmpeg.c create mode 100644 libfreerdp/codec/dsp_ffmpeg.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d9d3382f..2fcb17ac7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -704,6 +704,18 @@ set(GSM_FEATURE_TYPE "OPTIONAL") set(GSM_FEATURE_PURPOSE "codec") set(GSM_FEATURE_DESCRIPTION "GSM audio codec library") +set(LAME_FEATURE_TYPE "OPTIONAL") +set(LAME_FEATURE_PURPOSE "codec") +set(LAME_FEATURE_DESCRIPTION "lame MP3 audio codec library") + +set(FAAD2_FEATURE_TYPE "OPTIONAL") +set(FAAD2_FEATURE_PURPOSE "codec") +set(FAAD2_FEATURE_DESCRIPTION "FAAD2 AAC audio codec library") + +set(FAAC_FEATURE_TYPE "OPTIONAL") +set(FAAC_FEATURE_PURPOSE "codec") +set(FAAC_FEATURE_DESCRIPTION "FAAC AAC audio codec library") + set(GSSAPI_FEATURE_TYPE "OPTIONAL") set(GSSAPI_FEATURE_PURPOSE "auth") set(GSSAPI_FEATURE_DESCRIPTION "add kerberos support") @@ -804,6 +816,9 @@ find_feature(JPEG ${JPEG_FEATURE_TYPE} ${JPEG_FEATURE_PURPOSE} ${JPEG_FEATURE_DE find_feature(x264 ${X264_FEATURE_TYPE} ${X264_FEATURE_PURPOSE} ${X264_FEATURE_DESCRIPTION}) find_feature(OpenH264 ${OPENH264_FEATURE_TYPE} ${OPENH264_FEATURE_PURPOSE} ${OPENH264_FEATURE_DESCRIPTION}) find_feature(GSM ${GSM_FEATURE_TYPE} ${GSM_FEATURE_PURPOSE} ${GSM_FEATURE_DESCRIPTION}) +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(GSSAPI ${GSSAPI_FEATURE_TYPE} ${GSSAPI_FEATURE_PURPOSE} ${GSSAPI_FEATURE_DESCRIPTION}) diff --git a/channels/audin/client/alsa/audin_alsa.c b/channels/audin/client/alsa/audin_alsa.c index d8217104e..f68d3cd21 100644 --- a/channels/audin/client/alsa/audin_alsa.c +++ b/channels/audin/client/alsa/audin_alsa.c @@ -35,7 +35,6 @@ #include #include -#include #include #include "audin_main.h" @@ -46,34 +45,52 @@ typedef struct _AudinALSADevice char* device_name; UINT32 frames_per_packet; - UINT32 target_rate; - UINT32 actual_rate; - snd_pcm_format_t format; - UINT32 target_channels; - UINT32 actual_channels; - int bytes_per_channel; - int wformat; - int block_size; - - FREERDP_DSP_CONTEXT* dsp_context; + AUDIO_FORMAT aformat; HANDLE thread; HANDLE stopEvent; - BYTE* buffer; - int buffer_frames; - AudinReceive receive; void* user_data; rdpContext* rdpcontext; } AudinALSADevice; +static snd_pcm_format_t audin_alsa_format(UINT32 wFormatTag, UINT32 bitPerChannel) +{ + switch (wFormatTag) + { + case WAVE_FORMAT_PCM: + switch (bitPerChannel) + { + case 16: + return SND_PCM_FORMAT_S16_LE; + + case 8: + return SND_PCM_FORMAT_S8; + + default: + return SND_PCM_FORMAT_UNKNOWN; + } + + case WAVE_FORMAT_ALAW: + return SND_PCM_FORMAT_A_LAW; + + case WAVE_FORMAT_MULAW: + return SND_PCM_FORMAT_MU_LAW; + + default: + return SND_PCM_FORMAT_UNKNOWN; + } +} + static BOOL audin_alsa_set_params(AudinALSADevice* alsa, snd_pcm_t* capture_handle) { int error; + UINT32 channels = alsa->aformat.nChannels; snd_pcm_hw_params_t* hw_params; + snd_pcm_format_t format = audin_alsa_format(alsa->aformat.wFormatTag, alsa->aformat.wBitsPerSample); if ((error = snd_pcm_hw_params_malloc(&hw_params)) < 0) { @@ -85,150 +102,27 @@ static BOOL audin_alsa_set_params(AudinALSADevice* alsa, snd_pcm_hw_params_any(capture_handle, hw_params); snd_pcm_hw_params_set_access(capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); - snd_pcm_hw_params_set_format(capture_handle, hw_params, alsa->format); - snd_pcm_hw_params_set_rate_near(capture_handle, hw_params, &alsa->actual_rate, - NULL); + snd_pcm_hw_params_set_format(capture_handle, hw_params, format); + snd_pcm_hw_params_set_rate_near(capture_handle, hw_params, + &alsa->aformat.nSamplesPerSec, NULL); snd_pcm_hw_params_set_channels_near(capture_handle, hw_params, - &alsa->actual_channels); + &channels); snd_pcm_hw_params(capture_handle, hw_params); snd_pcm_hw_params_free(hw_params); snd_pcm_prepare(capture_handle); - - if ((alsa->actual_rate != alsa->target_rate) || - (alsa->actual_channels != alsa->target_channels)) - { - DEBUG_DVC("actual rate %"PRIu32" / channel %"PRIu32" is " - "different from target rate %"PRIu32" / channel %"PRIu32", resampling required.", - alsa->actual_rate, alsa->actual_channels, - alsa->target_rate, alsa->target_channels); - } - + alsa->aformat.nChannels = channels; return TRUE; } -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT audin_alsa_thread_receive(AudinALSADevice* alsa, BYTE* src, - int size) -{ - int frames; - int cframes; - UINT ret = CHANNEL_RC_OK; - int encoded_size; - BYTE* encoded_data; - int rbytes_per_frame; - int tbytes_per_frame; - int status; - rbytes_per_frame = alsa->actual_channels * alsa->bytes_per_channel; - tbytes_per_frame = alsa->target_channels * alsa->bytes_per_channel; - - if ((alsa->target_rate == alsa->actual_rate) && - (alsa->target_channels == alsa->actual_channels)) - { - frames = size / rbytes_per_frame; - } - else - { - alsa->dsp_context->resample(alsa->dsp_context, src, alsa->bytes_per_channel, - alsa->actual_channels, alsa->actual_rate, size / rbytes_per_frame, - alsa->target_channels, alsa->target_rate); - frames = alsa->dsp_context->resampled_frames; - DEBUG_DVC("resampled %d frames at %"PRIu32" to %d frames at %"PRIu32"", - size / rbytes_per_frame, alsa->actual_rate, frames, alsa->target_rate); - src = alsa->dsp_context->resampled_buffer; - } - - while (frames > 0) - { - status = WaitForSingleObject(alsa->stopEvent, 0); - - if (status == WAIT_FAILED) - { - ret = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", ret); - break; - } - - if (status == WAIT_OBJECT_0) - break; - - cframes = alsa->frames_per_packet - alsa->buffer_frames; - - if (cframes > frames) - cframes = frames; - - CopyMemory(alsa->buffer + alsa->buffer_frames * tbytes_per_frame, src, - cframes * tbytes_per_frame); - alsa->buffer_frames += cframes; - - if (alsa->buffer_frames >= alsa->frames_per_packet) - { - if (alsa->wformat == WAVE_FORMAT_DVI_ADPCM) - { - if (!alsa->dsp_context->encode_ima_adpcm(alsa->dsp_context, - alsa->buffer, alsa->buffer_frames * tbytes_per_frame, - alsa->target_channels, alsa->block_size)) - { - ret = ERROR_INTERNAL_ERROR; - break; - } - - encoded_data = alsa->dsp_context->adpcm_buffer; - encoded_size = alsa->dsp_context->adpcm_size; - DEBUG_DVC("encoded %d to %d", - alsa->buffer_frames * tbytes_per_frame, encoded_size); - } - else - { - encoded_data = alsa->buffer; - encoded_size = alsa->buffer_frames * tbytes_per_frame; - } - - status = WaitForSingleObject(alsa->stopEvent, 0); - - if (status == WAIT_FAILED) - { - ret = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", ret); - break; - } - - if (status == WAIT_OBJECT_0) - break; - else - { - DEBUG_DVC("encoded %d [%d] to %d [%X]", alsa->buffer_frames, - tbytes_per_frame, encoded_size, - alsa->wformat); - ret = alsa->receive(encoded_data, encoded_size, alsa->user_data); - } - - alsa->buffer_frames = 0; - - if (ret != CHANNEL_RC_OK) - break; - } - - src += cframes * tbytes_per_frame; - frames -= cframes; - } - - return ret; -} - static DWORD WINAPI audin_alsa_thread_func(LPVOID arg) { long error; BYTE* buffer; - int rbytes_per_frame; snd_pcm_t* capture_handle = NULL; AudinALSADevice* alsa = (AudinALSADevice*) arg; + const size_t rbytes_per_frame = alsa->aformat.nChannels * 4; DWORD status; DEBUG_DVC("in"); - rbytes_per_frame = alsa->actual_channels * alsa->bytes_per_channel; buffer = (BYTE*) calloc(alsa->frames_per_packet, rbytes_per_frame); if (!buffer) @@ -238,8 +132,6 @@ static DWORD WINAPI audin_alsa_thread_func(LPVOID arg) goto out; } - freerdp_dsp_context_reset_adpcm(alsa->dsp_context); - if ((error = snd_pcm_open(&capture_handle, alsa->device_name, SND_PCM_STREAM_CAPTURE, 0)) < 0) { @@ -281,7 +173,10 @@ static DWORD WINAPI audin_alsa_thread_func(LPVOID arg) break; } - if ((error = audin_alsa_thread_receive(alsa, buffer, error * rbytes_per_frame))) + error = alsa->receive(&alsa->aformat, + buffer, error, alsa->user_data); + + if (error) { WLog_ERR(TAG, "audin_alsa_thread_receive failed with error %ld", error); break; @@ -312,14 +207,13 @@ out: static UINT audin_alsa_free(IAudinDevice* device) { AudinALSADevice* alsa = (AudinALSADevice*) device; - freerdp_dsp_context_free(alsa->dsp_context); free(alsa->device_name); free(alsa); return CHANNEL_RC_OK; } static BOOL audin_alsa_format_supported(IAudinDevice* device, - audinFormat* format) + const AUDIO_FORMAT* format) { switch (format->wFormatTag) { @@ -334,15 +228,12 @@ static BOOL audin_alsa_format_supported(IAudinDevice* device, break; - case WAVE_FORMAT_DVI_ADPCM: - if ((format->nSamplesPerSec <= 48000) && - (format->wBitsPerSample == 4) && - (format->nChannels == 1 || format->nChannels == 2)) - { - return TRUE; - } + case WAVE_FORMAT_ALAW: + case WAVE_FORMAT_MULAW: + return TRUE; - break; + default: + return FALSE; } return FALSE; @@ -353,47 +244,16 @@ static BOOL audin_alsa_format_supported(IAudinDevice* device, * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_alsa_set_format(IAudinDevice* device, audinFormat* format, +static UINT audin_alsa_set_format(IAudinDevice* device, const AUDIO_FORMAT* format, UINT32 FramesPerPacket) { - int bs; AudinALSADevice* alsa = (AudinALSADevice*) device; - alsa->target_rate = format->nSamplesPerSec; - alsa->actual_rate = format->nSamplesPerSec; - alsa->target_channels = format->nChannels; - alsa->actual_channels = format->nChannels; + alsa->aformat = *format; + alsa->frames_per_packet = FramesPerPacket; - switch (format->wFormatTag) - { - case WAVE_FORMAT_PCM: - switch (format->wBitsPerSample) - { - case 8: - alsa->format = SND_PCM_FORMAT_S8; - alsa->bytes_per_channel = 1; - break; + if (audin_alsa_format(format->wFormatTag, format->wBitsPerSample) == SND_PCM_FORMAT_UNKNOWN) + return ERROR_INTERNAL_ERROR; - case 16: - alsa->format = SND_PCM_FORMAT_S16_LE; - alsa->bytes_per_channel = 2; - break; - } - - break; - - case WAVE_FORMAT_DVI_ADPCM: - alsa->format = SND_PCM_FORMAT_S16_LE; - alsa->bytes_per_channel = 2; - bs = (format->nBlockAlign - 4 * format->nChannels) * 4; - alsa->frames_per_packet = (alsa->frames_per_packet * format->nChannels * 2 / - bs + 1) * bs / (format->nChannels * 2); - DEBUG_DVC("aligned FramesPerPacket=%"PRIu32"", - alsa->frames_per_packet); - break; - } - - alsa->wformat = format->wFormatTag; - alsa->block_size = format->nBlockAlign; return CHANNEL_RC_OK; } @@ -405,20 +265,9 @@ static UINT audin_alsa_set_format(IAudinDevice* device, audinFormat* format, static UINT audin_alsa_open(IAudinDevice* device, AudinReceive receive, void* user_data) { - int tbytes_per_frame; AudinALSADevice* alsa = (AudinALSADevice*) device; alsa->receive = receive; alsa->user_data = user_data; - tbytes_per_frame = alsa->target_channels * alsa->bytes_per_channel; - alsa->buffer = (BYTE*) calloc(alsa->frames_per_packet, tbytes_per_frame); - - if (!alsa->buffer) - { - WLog_ERR(TAG, "calloc failed!"); - return ERROR_NOT_ENOUGH_MEMORY; - } - - alsa->buffer_frames = 0; if (!(alsa->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) { @@ -427,7 +276,7 @@ static UINT audin_alsa_open(IAudinDevice* device, AudinReceive receive, } if (!(alsa->thread = CreateThread(NULL, 0, - audin_alsa_thread_func, alsa, 0, NULL))) + audin_alsa_thread_func, alsa, 0, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); goto error_out; @@ -435,8 +284,6 @@ static UINT audin_alsa_open(IAudinDevice* device, AudinReceive receive, return CHANNEL_RC_OK; error_out: - free(alsa->buffer); - alsa->buffer = NULL; CloseHandle(alsa->stopEvent); alsa->stopEvent = NULL; return ERROR_INTERNAL_ERROR; @@ -469,14 +316,12 @@ static UINT audin_alsa_close(IAudinDevice* device) alsa->thread = NULL; } - free(alsa->buffer); - alsa->buffer = NULL; alsa->receive = NULL; alsa->user_data = NULL; return error; } -COMMAND_LINE_ARGUMENT_A audin_alsa_args[] = +static COMMAND_LINE_ARGUMENT_A audin_alsa_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "audio device name" }, { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } @@ -579,20 +424,10 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS } alsa->frames_per_packet = 128; - alsa->target_rate = 22050; - alsa->actual_rate = 22050; - alsa->format = SND_PCM_FORMAT_S16_LE; - alsa->target_channels = 2; - alsa->actual_channels = 2; - alsa->bytes_per_channel = 2; - alsa->dsp_context = freerdp_dsp_context_new(); - - if (!alsa->dsp_context) - { - WLog_ERR(TAG, "freerdp_dsp_context_new failed!"); - error = CHANNEL_RC_NO_MEMORY; - goto error_out; - } + alsa->aformat.nChannels = 2; + alsa->aformat.wBitsPerSample = 16; + alsa->aformat.wFormatTag = WAVE_FORMAT_PCM; + alsa->aformat.nSamplesPerSec = 44100; if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) alsa))) @@ -603,7 +438,6 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS return CHANNEL_RC_OK; error_out: - freerdp_dsp_context_free(alsa->dsp_context); free(alsa->device_name); free(alsa); return error; diff --git a/channels/audin/client/audin_main.c b/channels/audin/client/audin_main.c index b04c2583c..32e5364b3 100644 --- a/channels/audin/client/audin_main.c +++ b/channels/audin/client/audin_main.c @@ -32,11 +32,13 @@ #include #include -#include -#include #include + +#include #include +#include + #include "audin_main.h" #define MSG_SNDIN_VERSION 0x01 @@ -70,7 +72,7 @@ struct _AUDIN_CHANNEL_CALLBACK * be stored as reference when the server sends the format index in * Open PDU and Format Change PDU */ - audinFormat* formats; + AUDIO_FORMAT* formats; UINT32 formats_count; }; @@ -93,45 +95,65 @@ struct _AUDIN_PLUGIN rdpContext* rdpcontext; BOOL attached; - wLog* log; + wStream* data; + AUDIO_FORMAT* format; + UINT32 FramesPerPacket; + + FREERDP_DSP_CONTEXT* dsp_context; }; static BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args); -static UINT audin_write_and_free_stream(AUDIN_CHANNEL_CALLBACK* callback, wStream* s) +static UINT audin_channel_write_and_free(AUDIN_CHANNEL_CALLBACK* callback, wStream* out, + BOOL freeStream) { - UINT error = ERROR_INTERNAL_ERROR; - const size_t length = Stream_GetPosition(s); - const BYTE* data = Stream_Buffer(s); + UINT error; - if (callback && callback->channel && callback->channel->Write) - error = callback->channel->Write(callback->channel, length, data, NULL); + if (!callback || !out) + return ERROR_INVALID_PARAMETER; + + if (!callback->channel || !callback->channel->Write) + return ERROR_INTERNAL_ERROR; + + Stream_SealLength(out); + error = callback->channel->Write(callback->channel, + Stream_Length(out), + Stream_Buffer(out), NULL); + + if (freeStream) + Stream_Free(out, TRUE); - Stream_Free(s, TRUE); return error; } + + /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_process_version(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback, wStream* s) +static UINT audin_process_version(IWTSVirtualChannelCallback* pChannelCallback, wStream* s) { wStream* out; UINT32 Version; + AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback; + + if (Stream_GetRemainingLength(s) < 4) + return ERROR_INVALID_DATA; + Stream_Read_UINT32(s, Version); DEBUG_DVC("Version=%"PRIu32"", Version); out = Stream_New(NULL, 5); if (!out) { - WLog_Print(audin->log, WLOG_ERROR, "Stream_New failed!"); + WLog_ERR(TAG, "Stream_New failed!"); return ERROR_OUTOFMEMORY; } Stream_Write_UINT8(out, MSG_SNDIN_VERSION); Stream_Write_UINT32(out, Version); - return audin_write_and_free_stream(callback, out); + return audin_channel_write_and_free(callback, out, TRUE); } /** @@ -139,13 +161,11 @@ static UINT audin_process_version(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* c * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_send_incoming_data_pdu(AUDIN_CHANNEL_CALLBACK* callback) +static UINT audin_send_incoming_data_pdu(IWTSVirtualChannelCallback* pChannelCallback) { - BYTE out_data[1] = { MSG_SNDIN_DATA_INCOMING }; - - if (!callback || !callback->channel || !callback->channel->Write) - return ERROR_INTERNAL_ERROR; - + BYTE out_data[1]; + AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback; + out_data[0] = MSG_SNDIN_DATA_INCOMING; return callback->channel->Write(callback->channel, 1, out_data, NULL); } @@ -154,34 +174,35 @@ static UINT audin_send_incoming_data_pdu(AUDIN_CHANNEL_CALLBACK* callback) * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_process_formats(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback, wStream* s) +static UINT audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback, wStream* s) { + AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback; + AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) callback->plugin; UINT32 i; - BYTE* fm; UINT error; wStream* out; UINT32 NumFormats; - audinFormat format; - size_t cbSizeFormatsPacket; + AUDIO_FORMAT format; + UINT32 cbSizeFormatsPacket; if (Stream_GetRemainingLength(s) < 8) - return ERROR_NO_DATA; + return ERROR_INVALID_DATA; Stream_Read_UINT32(s, NumFormats); DEBUG_DVC("NumFormats %"PRIu32"", NumFormats); if ((NumFormats < 1) || (NumFormats > 1000)) { - WLog_Print(audin->log, WLOG_ERROR, "bad NumFormats %"PRIu32"", NumFormats); + WLog_ERR(TAG, "bad NumFormats %"PRIu32"", NumFormats); return ERROR_INVALID_DATA; } Stream_Seek_UINT32(s); /* cbSizeFormatsPacket */ - callback->formats = (audinFormat*) calloc(NumFormats, sizeof(audinFormat)); + callback->formats = (AUDIO_FORMAT*) calloc(NumFormats, sizeof(AUDIO_FORMAT)); if (!callback->formats) { - WLog_Print(audin->log, WLOG_ERROR, "calloc failed!"); + WLog_ERR(TAG, "calloc failed!"); return ERROR_INVALID_DATA; } @@ -190,7 +211,7 @@ static UINT audin_process_formats(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* c if (!out) { error = CHANNEL_RC_NO_MEMORY; - WLog_Print(audin->log, WLOG_ERROR, "Stream_New failed!"); + WLog_ERR(TAG, "Stream_New failed!"); goto out; } @@ -199,21 +220,23 @@ static UINT audin_process_formats(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* c /* SoundFormats (variable) */ for (i = 0; i < NumFormats; i++) { + BYTE* fm; + if (Stream_GetRemainingLength(s) < 18) - return ERROR_NO_DATA; + return ERROR_INVALID_DATA; Stream_GetPointer(s, fm); Stream_Read_UINT16(s, format.wFormatTag); Stream_Read_UINT16(s, format.nChannels); Stream_Read_UINT32(s, format.nSamplesPerSec); - Stream_Seek_UINT32(s); /* nAvgBytesPerSec */ + Stream_Read_UINT32(s, format.nAvgBytesPerSec); Stream_Read_UINT16(s, format.nBlockAlign); Stream_Read_UINT16(s, format.wBitsPerSample); Stream_Read_UINT16(s, format.cbSize); format.data = Stream_Pointer(s); if (Stream_GetRemainingLength(s) < format.cbSize) - return ERROR_NO_DATA; + return ERROR_INVALID_DATA; Stream_Seek(s, format.cbSize); DEBUG_DVC("wFormatTag=%"PRIu16" nChannels=%"PRIu16" nSamplesPerSec=%"PRIu32" " @@ -230,9 +253,9 @@ static UINT audin_process_formats(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* c if (audin->fixed_rate > 0 && audin->fixed_rate != format.nSamplesPerSec) continue; - if (audin->device && audin->device->FormatSupported(audin->device, &format)) + if (freerdp_dsp_supports_format(&format, TRUE) || + audin->device->FormatSupported(audin->device, &format)) { - DEBUG_DVC("format ok"); /* Store the agreed format in the corresponding index */ callback->formats[callback->formats_count++] = format; @@ -240,7 +263,7 @@ static UINT audin_process_formats(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* c if (!Stream_EnsureRemainingCapacity(out, 18 + format.cbSize)) { error = CHANNEL_RC_NO_MEMORY; - WLog_Print(audin->log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!"); + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); goto out; } @@ -248,19 +271,19 @@ static UINT audin_process_formats(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* c } } - if ((error = audin_send_incoming_data_pdu(callback))) + if ((error = audin_send_incoming_data_pdu(pChannelCallback))) { - WLog_Print(audin->log, WLOG_ERROR, "audin_send_incoming_data_pdu failed!"); + WLog_ERR(TAG, "audin_send_incoming_data_pdu failed!"); goto out; } - cbSizeFormatsPacket = Stream_GetPosition(out); + cbSizeFormatsPacket = (UINT32) Stream_GetPosition(out); Stream_SetPosition(out, 0); Stream_Write_UINT8(out, MSG_SNDIN_FORMATS); /* Header (1 byte) */ Stream_Write_UINT32(out, callback->formats_count); /* NumFormats (4 bytes) */ Stream_Write_UINT32(out, cbSizeFormatsPacket); /* cbSizeFormatsPacket (4 bytes) */ Stream_SetPosition(out, cbSizeFormatsPacket); - error = audin_write_and_free_stream(callback, out); + error = audin_channel_write_and_free(callback, out, TRUE); out: if (error != CHANNEL_RC_OK) @@ -277,20 +300,22 @@ out: * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_send_format_change_pdu(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback, +static UINT audin_send_format_change_pdu(IWTSVirtualChannelCallback* pChannelCallback, UINT32 NewFormat) { - wStream* out = Stream_New(NULL, 5); + wStream* out; + AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback; + out = Stream_New(NULL, 5); if (!out) { - WLog_Print(audin->log, WLOG_ERROR, "Stream_New failed!"); + WLog_ERR(TAG, "Stream_New failed!"); return CHANNEL_RC_OK; } Stream_Write_UINT8(out, MSG_SNDIN_FORMATCHANGE); Stream_Write_UINT32(out, NewFormat); - return audin_write_and_free_stream(callback, out); + return audin_channel_write_and_free(callback, out, TRUE); } /** @@ -298,20 +323,21 @@ static UINT audin_send_format_change_pdu(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALL * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_send_open_reply_pdu(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback, - UINT32 Result) +static UINT audin_send_open_reply_pdu(IWTSVirtualChannelCallback* pChannelCallback, UINT32 Result) { - wStream* out = Stream_New(NULL, 5); + wStream* out; + AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback; + out = Stream_New(NULL, 5); if (!out) { - WLog_Print(audin->log, WLOG_ERROR, "Stream_New failed!"); + WLog_ERR(TAG, "Stream_New failed!"); return CHANNEL_RC_NO_MEMORY; } Stream_Write_UINT8(out, MSG_SNDIN_OPEN_REPLY); Stream_Write_UINT32(out, Result); - return audin_write_and_free_stream(callback, out); + return audin_channel_write_and_free(callback, out, TRUE); } /** @@ -319,10 +345,10 @@ static UINT audin_send_open_reply_pdu(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBAC * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_receive_wave_data(const BYTE* data, int size, void* user_data) +static UINT audin_receive_wave_data(const AUDIO_FORMAT* format, + const BYTE* data, size_t size, void* user_data) { UINT error; - wStream* out; AUDIN_PLUGIN* audin; AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) user_data; @@ -337,84 +363,125 @@ static UINT audin_receive_wave_data(const BYTE* data, int size, void* user_data) if (!audin->attached) return CHANNEL_RC_OK; - if ((error = audin_send_incoming_data_pdu(callback))) + Stream_SetPosition(audin->data, 0); + + if (!Stream_EnsureRemainingCapacity(audin->data, 1)) + return CHANNEL_RC_NO_MEMORY; + + Stream_Write_UINT8(audin->data, MSG_SNDIN_DATA); + + if (audin->device->FormatSupported(audin->device, audin->format)) { - WLog_Print(audin->log, WLOG_ERROR, "audin_send_incoming_data_pdu failed!"); + if (!Stream_EnsureRemainingCapacity(audin->data, size)) + return CHANNEL_RC_NO_MEMORY; + + Stream_Write(audin->data, data, size); + } + else if (!freerdp_dsp_encode(audin->dsp_context, format, data, size, audin->data)) + return ERROR_INTERNAL_ERROR; + + if (Stream_GetPosition(audin->data) <= 1) + return CHANNEL_RC_OK; + + if ((error = audin_send_incoming_data_pdu((IWTSVirtualChannelCallback*) callback))) + { + WLog_ERR(TAG, "audin_send_incoming_data_pdu failed!"); return error; } - out = Stream_New(NULL, size + 1); - - if (!out) - { - WLog_Print(audin->log, WLOG_ERROR, "Stream_New failed!"); - return ERROR_NOT_ENOUGH_MEMORY; - } - - Stream_Write_UINT8(out, MSG_SNDIN_DATA); - Stream_Write(out, data, size); - return audin_write_and_free_stream(callback, out); + return audin_channel_write_and_free(callback, audin->data, FALSE); } +static BOOL audin_open_device(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback) +{ + UINT error = ERROR_INTERNAL_ERROR; + BOOL supported; + AUDIO_FORMAT format; + + if (!audin || !audin->device) + return FALSE; + + format = *audin->format; + supported = IFCALLRESULT(FALSE, audin->device->FormatSupported, audin->device, &format); + + WLog_DBG(TAG, "microphone uses %s codec", + rdpsnd_get_audio_tag_string(format.wFormatTag)); + + if (!supported) + { + format.wFormatTag = WAVE_FORMAT_PCM; + format.wBitsPerSample = 16; + } + + IFCALLRET(audin->device->SetFormat, error, + audin->device, &format, + audin->FramesPerPacket); + + if (error != CHANNEL_RC_OK) + { + WLog_ERR(TAG, "SetFormat failed with errorcode %"PRIu32"", error); + return FALSE; + } + + if (!audin->device->FormatSupported(audin->device, audin->format)) + { + if (!freerdp_dsp_context_reset(audin->dsp_context, audin->format)) + return FALSE; + } + + IFCALLRET(audin->device->Open, error, audin->device, + audin_receive_wave_data, callback); + + if (error != CHANNEL_RC_OK) + { + WLog_ERR(TAG, "Open failed with errorcode %"PRIu32"", error); + return FALSE; + } + + return TRUE; +} /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_process_open(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback, wStream* s) +static UINT audin_process_open(IWTSVirtualChannelCallback* pChannelCallback, wStream* s) { - audinFormat* format; + AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback; + AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) callback->plugin; UINT32 initialFormat; UINT32 FramesPerPacket; UINT error = CHANNEL_RC_OK; - if (!audin || !callback || !s) - return ERROR_INTERNAL_ERROR; - if (Stream_GetRemainingLength(s) < 8) - return ERROR_NO_DATA; + return ERROR_INVALID_DATA; Stream_Read_UINT32(s, FramesPerPacket); Stream_Read_UINT32(s, initialFormat); DEBUG_DVC("FramesPerPacket=%"PRIu32" initialFormat=%"PRIu32"", FramesPerPacket, initialFormat); + audin->FramesPerPacket = FramesPerPacket; - if (initialFormat >= (UINT32) callback->formats_count) + if (initialFormat >= callback->formats_count) { - WLog_Print(audin->log, WLOG_ERROR, "invalid format index %"PRIu32" (total %d)", - initialFormat, callback->formats_count); + WLog_ERR(TAG, "invalid format index %"PRIu32" (total %d)", + initialFormat, callback->formats_count); return ERROR_INVALID_DATA; } - format = &callback->formats[initialFormat]; + audin->format = &callback->formats[initialFormat]; - if (audin->device) + if (!audin_open_device(audin, callback)) + return ERROR_INTERNAL_ERROR; + + if ((error = audin_send_format_change_pdu(pChannelCallback, initialFormat))) { - IFCALLRET(audin->device->SetFormat, error, audin->device, format, FramesPerPacket); - - if (error != CHANNEL_RC_OK) - { - WLog_Print(audin->log, WLOG_ERROR, "SetFormat failed with errorcode %"PRIu32"", error); - return error; - } - - IFCALLRET(audin->device->Open, error, audin->device, audin_receive_wave_data, callback); - - if (error != CHANNEL_RC_OK) - { - WLog_Print(audin->log, WLOG_ERROR, "Open failed with errorcode %"PRIu32"", error); - return error; - } - } - - if ((error = audin_send_format_change_pdu(audin, callback, initialFormat))) - { - WLog_Print(audin->log, WLOG_ERROR, "audin_send_format_change_pdu failed!"); + WLog_ERR(TAG, "audin_send_format_change_pdu failed!"); return error; } - if ((error = audin_send_open_reply_pdu(audin, callback, 0))) - WLog_Print(audin->log, WLOG_ERROR, "audin_send_open_reply_pdu failed!"); + if ((error = audin_send_open_reply_pdu(pChannelCallback, 0))) + WLog_ERR(TAG, "audin_send_open_reply_pdu failed!"); return error; } @@ -424,30 +491,27 @@ static UINT audin_process_open(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* call * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_process_format_change(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback, - wStream* s) +static UINT audin_process_format_change(IWTSVirtualChannelCallback* pChannelCallback, wStream* s) { + AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback; + AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) callback->plugin; UINT32 NewFormat; - audinFormat* format; UINT error = CHANNEL_RC_OK; - if (!audin || !callback || !s) - return ERROR_INTERNAL_ERROR; - if (Stream_GetRemainingLength(s) < 4) - return ERROR_NO_DATA; + return ERROR_INVALID_DATA; Stream_Read_UINT32(s, NewFormat); DEBUG_DVC("NewFormat=%"PRIu32"", NewFormat); - if (NewFormat >= callback->formats_count) + if (NewFormat >= (UINT32) callback->formats_count) { - WLog_Print(audin->log, WLOG_ERROR, "invalid format index %"PRIu32" (total %d)", - NewFormat, callback->formats_count); + WLog_ERR(TAG, "invalid format index %"PRIu32" (total %d)", + NewFormat, callback->formats_count); return ERROR_INVALID_DATA; } - format = &callback->formats[NewFormat]; + audin->format = &callback->formats[NewFormat]; if (audin->device) { @@ -455,29 +519,16 @@ static UINT audin_process_format_change(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLB if (error != CHANNEL_RC_OK) { - WLog_Print(audin->log, WLOG_ERROR, "Close failed with errorcode %"PRIu32"", error); - return error; - } - - IFCALLRET(audin->device->SetFormat, error, audin->device, format, 0); - - if (error != CHANNEL_RC_OK) - { - WLog_Print(audin->log, WLOG_ERROR, "SetFormat failed with errorcode %"PRIu32"", error); - return error; - } - - IFCALLRET(audin->device->Open, error, audin->device, audin_receive_wave_data, callback); - - if (error != CHANNEL_RC_OK) - { - WLog_Print(audin->log, WLOG_ERROR, "Open failed with errorcode %"PRIu32"", error); + WLog_ERR(TAG, "Close failed with errorcode %"PRIu32"", error); return error; } } - if ((error = audin_send_format_change_pdu(audin, callback, NewFormat))) - WLog_Print(audin->log, WLOG_ERROR, "audin_send_format_change_pdu failed!"); + if (!audin_open_device(audin, callback)) + return ERROR_INTERNAL_ERROR; + + if ((error = audin_send_format_change_pdu(pChannelCallback, NewFormat))) + WLog_ERR(TAG, "audin_send_format_change_pdu failed!"); return error; } @@ -491,19 +542,9 @@ static UINT audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, { UINT error; BYTE MessageId; - AUDIN_PLUGIN* audin; - AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback; - if (!callback || !data) - return ERROR_INVALID_PARAMETER; - - audin = (AUDIN_PLUGIN*) callback->plugin; - - if (!audin) - return ERROR_INTERNAL_ERROR; - - if (Stream_GetRemainingCapacity(data) < 1) - return ERROR_NO_DATA; + if (Stream_GetRemainingLength(data) < 1) + return ERROR_INVALID_DATA; Stream_Read_UINT8(data, MessageId); DEBUG_DVC("MessageId=0x%02"PRIx8"", MessageId); @@ -511,23 +552,23 @@ static UINT audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, switch (MessageId) { case MSG_SNDIN_VERSION: - error = audin_process_version(audin, callback, data); + error = audin_process_version(pChannelCallback, data); break; case MSG_SNDIN_FORMATS: - error = audin_process_formats(audin, callback, data); + error = audin_process_formats(pChannelCallback, data); break; case MSG_SNDIN_OPEN: - error = audin_process_open(audin, callback, data); + error = audin_process_open(pChannelCallback, data); break; case MSG_SNDIN_FORMATCHANGE: - error = audin_process_format_change(audin, callback, data); + error = audin_process_format_change(pChannelCallback, data); break; default: - WLog_Print(audin->log, WLOG_ERROR, "unknown MessageId=0x%02"PRIx8"", MessageId); + WLog_ERR(TAG, "unknown MessageId=0x%02"PRIx8"", MessageId); error = ERROR_INVALID_DATA; break; } @@ -552,9 +593,10 @@ static UINT audin_on_close(IWTSVirtualChannelCallback* pChannelCallback) IFCALLRET(audin->device->Close, error, audin->device); if (error != CHANNEL_RC_OK) - WLog_Print(audin->log, WLOG_ERROR, "Close failed with errorcode %"PRIu32"", error); + WLog_ERR(TAG, "Close failed with errorcode %"PRIu32"", error); } + audin->format = NULL; free(callback->formats); free(callback); return error; @@ -570,19 +612,13 @@ static UINT audin_on_new_channel_connection(IWTSListenerCallback* pListenerCallb IWTSVirtualChannelCallback** ppCallback) { AUDIN_CHANNEL_CALLBACK* callback; - AUDIN_PLUGIN* audin; AUDIN_LISTENER_CALLBACK* listener_callback = (AUDIN_LISTENER_CALLBACK*) pListenerCallback; - - if (!listener_callback || !listener_callback->plugin) - return ERROR_INTERNAL_ERROR; - - audin = (AUDIN_PLUGIN*) listener_callback->plugin; DEBUG_DVC("..."); callback = (AUDIN_CHANNEL_CALLBACK*) calloc(1, sizeof(AUDIN_CHANNEL_CALLBACK)); if (!callback) { - WLog_Print(audin->log, WLOG_ERROR, "calloc failed!"); + WLog_ERR(TAG, "calloc failed!"); return CHANNEL_RC_NO_MEMORY; } @@ -608,7 +644,7 @@ static UINT audin_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManag if (!audin->listener_callback) { - WLog_Print(audin->log, WLOG_ERROR, "calloc failed!"); + WLog_ERR(TAG, "calloc failed!"); return CHANNEL_RC_NO_MEMORY; } @@ -636,17 +672,16 @@ static UINT audin_plugin_terminated(IWTSPlugin* pPlugin) if (error != CHANNEL_RC_OK) { - WLog_Print(audin->log, WLOG_ERROR, "Free failed with errorcode %"PRIu32"", error); + WLog_ERR(TAG, "Free failed with errorcode %"PRIu32"", error); // dont stop on error } audin->device = NULL; } + Stream_Free(audin->data, TRUE); free(audin->subsystem); - audin->subsystem = NULL; free(audin->device_name); - audin->device_name = NULL; free(audin->listener_callback); free(audin); return CHANNEL_RC_OK; @@ -687,7 +722,7 @@ static UINT audin_register_device_plugin(IWTSPlugin* pPlugin, IAudinDevice* devi if (audin->device) { - WLog_Print(audin->log, WLOG_ERROR, "existing device, abort."); + WLog_ERR(TAG, "existing device, abort."); return ERROR_ALREADY_EXISTS; } @@ -701,34 +736,33 @@ static UINT audin_register_device_plugin(IWTSPlugin* pPlugin, IAudinDevice* devi * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_load_device_plugin(AUDIN_PLUGIN* audin, char* name, ADDIN_ARGV* args) +static UINT audin_load_device_plugin(IWTSPlugin* pPlugin, const char* name, ADDIN_ARGV* args) { PFREERDP_AUDIN_DEVICE_ENTRY entry; FREERDP_AUDIN_DEVICE_ENTRY_POINTS entryPoints; UINT error; - entry = (PFREERDP_AUDIN_DEVICE_ENTRY) freerdp_load_channel_addin_entry("audin", name, NULL, + entry = (PFREERDP_AUDIN_DEVICE_ENTRY) freerdp_load_channel_addin_entry("audin", (LPSTR) name, NULL, 0); if (entry == NULL) { - WLog_Print(audin->log, WLOG_ERROR, - "freerdp_load_channel_addin_entry did not return any function pointers for %s ", - name); + WLog_ERR(TAG, "freerdp_load_channel_addin_entry did not return any function pointers for %s ", + name); return ERROR_INVALID_FUNCTION; } - entryPoints.plugin = (IWTSPlugin*) audin; + entryPoints.plugin = pPlugin; entryPoints.pRegisterAudinDevice = audin_register_device_plugin; entryPoints.args = args; - entryPoints.rdpcontext = audin->rdpcontext; + entryPoints.rdpcontext = ((AUDIN_PLUGIN*)pPlugin)->rdpcontext; if ((error = entry(&entryPoints))) { - WLog_Print(audin->log, WLOG_ERROR, "%s entry returned error %"PRIu32".", name, error); + WLog_ERR(TAG, "%s entry returned error %"PRIu32".", name, error); return error; } - WLog_Print(audin->log, WLOG_INFO, "Loaded %s backend for audin", name); + WLog_INFO(TAG, "Loaded %s backend for audin", name); return CHANNEL_RC_OK; } @@ -744,7 +778,7 @@ static UINT audin_set_subsystem(AUDIN_PLUGIN* audin, const char* subsystem) if (!audin->subsystem) { - WLog_Print(audin->log, WLOG_ERROR, "_strdup failed!"); + WLog_ERR(TAG, "_strdup failed!"); return ERROR_NOT_ENOUGH_MEMORY; } @@ -763,7 +797,7 @@ static UINT audin_set_device_name(AUDIN_PLUGIN* audin, char* device_name) if (!audin->device_name) { - WLog_Print(audin->log, WLOG_ERROR, "_strdup failed!"); + WLog_ERR(TAG, "_strdup failed!"); return ERROR_NOT_ENOUGH_MEMORY; } @@ -810,7 +844,7 @@ BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args) { if ((error = audin_set_subsystem(audin, arg->Value))) { - WLog_Print(audin->log, WLOG_ERROR, "audin_set_subsystem failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "audin_set_subsystem failed with error %"PRIu32"!", error); return FALSE; } } @@ -818,7 +852,7 @@ BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args) { if ((error = audin_set_device_name(audin, arg->Value))) { - WLog_Print(audin->log, WLOG_ERROR, "audin_set_device_name failed with error %"PRIu32"!", error); + WLog_ERR(TAG, "audin_set_device_name failed with error %"PRIu32"!", error); return FALSE; } } @@ -916,7 +950,16 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) return CHANNEL_RC_NO_MEMORY; } - audin->log = WLog_Get(TAG); + audin->data = Stream_New(NULL, 4096); + + if (!audin->data) + goto out; + + audin->dsp_context = freerdp_dsp_context_new(TRUE); + + if (!audin->dsp_context) + goto out; + audin->attached = TRUE; audin->iface.Initialize = audin_plugin_initialize; audin->iface.Connected = NULL; @@ -936,10 +979,10 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) if (audin->subsystem) { - if ((error = audin_load_device_plugin(audin, audin->subsystem, args))) + if ((error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args))) { - WLog_Print(audin->log, WLOG_ERROR, "audin_load_device_plugin %s failed with error %"PRIu32"!", - audin->subsystem, error); + WLog_ERR(TAG, "audin_load_device_plugin %s failed with error %"PRIu32"!", + audin->subsystem, error); goto out; } } @@ -949,18 +992,18 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) { if ((error = audin_set_subsystem(audin, entry->subsystem))) { - WLog_Print(audin->log, WLOG_ERROR, "audin_set_subsystem for %s failed with error %"PRIu32"!", - entry->subsystem, error); + WLog_ERR(TAG, "audin_set_subsystem for %s failed with error %"PRIu32"!", + entry->subsystem, error); } else if ((error = audin_set_device_name(audin, entry->device))) { - WLog_Print(audin->log, WLOG_ERROR, "audin_set_device_name for %s failed with error %"PRIu32"!", - entry->subsystem, error); + WLog_ERR(TAG, "audin_set_device_name for %s failed with error %"PRIu32"!", + entry->subsystem, error); } - else if ((error = audin_load_device_plugin(audin, audin->subsystem, args))) + else if ((error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args))) { - WLog_Print(audin->log, WLOG_ERROR, "audin_load_device_plugin %s failed with error %"PRIu32"!", - entry->subsystem, error); + WLog_ERR(TAG, "audin_load_device_plugin %s failed with error %"PRIu32"!", + entry->subsystem, error); } entry++; @@ -968,7 +1011,7 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) } if (audin->device == NULL) - WLog_Print(audin->log, WLOG_ERROR, "no sound device."); + WLog_ERR(TAG, "no sound device."); error = pEntryPoints->RegisterPlugin(pEntryPoints, "audin", (IWTSPlugin*) audin); out: diff --git a/channels/audin/client/mac/audin_mac.c b/channels/audin/client/mac/audin_mac.c index d35783849..5a18ca2ea 100644 --- a/channels/audin/client/mac/audin_mac.c +++ b/channels/audin/client/mac/audin_mac.c @@ -42,7 +42,6 @@ #include #include -#include #include #include "audin_main.h" @@ -52,75 +51,74 @@ typedef struct _AudinMacDevice { - IAudinDevice iface; + IAudinDevice iface; - FREERDP_DSP_CONTEXT* dsp_context; + AUDIO_FORMAT format; + UINT32 FramesPerPacket; + int dev_unit; - audinFormat format; - UINT32 FramesPerPacket; - int dev_unit; + AudinReceive receive; + void* user_data; - AudinReceive receive; - void* user_data; + rdpContext* rdpcontext; - rdpContext* rdpcontext; - - bool isOpen; - AudioQueueRef audioQueue; - AudioStreamBasicDescription audioFormat; - AudioQueueBufferRef audioBuffers[MAC_AUDIO_QUEUE_NUM_BUFFERS]; + bool isOpen; + AudioQueueRef audioQueue; + AudioStreamBasicDescription audioFormat; + AudioQueueBufferRef audioBuffers[MAC_AUDIO_QUEUE_NUM_BUFFERS]; } AudinMacDevice; -static AudioFormatID audin_mac_get_format(const audinFormat* format) +static AudioFormatID audin_mac_get_format(const AUDIO_FORMAT* format) { - switch (format->wFormatTag) - { - case WAVE_FORMAT_PCM: - return kAudioFormatLinearPCM; - /* - case WAVE_FORMAT_GSM610: - return kAudioFormatMicrosoftGSM; - case WAVE_FORMAT_ALAW: - return kAudioFormatALaw; - case WAVE_FORMAT_MULAW: - return kAudioFormatULaw; - case WAVE_FORMAT_AAC_MS: - return kAudioFormatMPEG4AAC; - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - return kAudioFormatLinearPCM; - */ - } + switch (format->wFormatTag) + { + case WAVE_FORMAT_PCM: + return kAudioFormatLinearPCM; + /* + case WAVE_FORMAT_GSM610: + return kAudioFormatMicrosoftGSM; + case WAVE_FORMAT_ALAW: + return kAudioFormatALaw; + case WAVE_FORMAT_MULAW: + return kAudioFormatULaw; + case WAVE_FORMAT_AAC_MS: + return kAudioFormatMPEG4AAC; + case WAVE_FORMAT_ADPCM: + case WAVE_FORMAT_DVI_ADPCM: + return kAudioFormatLinearPCM; + */ + } - return 0; + return 0; } -static AudioFormatFlags audin_mac_get_flags_for_format(const audinFormat* format) +static AudioFormatFlags audin_mac_get_flags_for_format(const AUDIO_FORMAT* format) { - switch(format->wFormatTag) - { - case WAVE_FORMAT_DVI_ADPCM: - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_PCM: - return kAudioFormatFlagIsSignedInteger; - default: - return 0; - } + switch (format->wFormatTag) + { + case WAVE_FORMAT_DVI_ADPCM: + case WAVE_FORMAT_ADPCM: + case WAVE_FORMAT_PCM: + return kAudioFormatFlagIsSignedInteger; + + default: + return 0; + } } -static BOOL audin_mac_format_supported(IAudinDevice* device, audinFormat* format) +static BOOL audin_mac_format_supported(IAudinDevice* device, const AUDIO_FORMAT* format) { - AudioFormatID req_fmt = 0; + AudioFormatID req_fmt = 0; - if (device == NULL || format == NULL) - return FALSE; + if (device == NULL || format == NULL) + return FALSE; - req_fmt = audin_mac_get_format(format); + req_fmt = audin_mac_get_format(format); - if (req_fmt == 0) - return FALSE; + if (req_fmt == 0) + return FALSE; - return TRUE; + return TRUE; } /** @@ -128,279 +126,248 @@ static BOOL audin_mac_format_supported(IAudinDevice* device, audinFormat* format * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_mac_set_format(IAudinDevice* device, audinFormat* format, UINT32 FramesPerPacket) +static UINT audin_mac_set_format(IAudinDevice* device, const AUDIO_FORMAT* format, + UINT32 FramesPerPacket) { - AudinMacDevice* mac = (AudinMacDevice*)device; + AudinMacDevice* mac = (AudinMacDevice*)device; - if (device == NULL || format == NULL) - return ERROR_INVALID_PARAMETER; + if (device == NULL || format == NULL) + return ERROR_INVALID_PARAMETER; - mac->FramesPerPacket = FramesPerPacket; - CopyMemory(&(mac->format), format, sizeof(audinFormat)); + mac->FramesPerPacket = FramesPerPacket; + mac->format = *format; + WLog_INFO(TAG, "Audio Format %s [channels=%d, samples=%d, bits=%d]", + rdpsnd_get_audio_tag_string(format->wFormatTag), + format->nChannels, format->nSamplesPerSec, format->wBitsPerSample); - WLog_INFO(TAG, "Audio Format %s [channels=%d, samples=%d, bits=%d]", - rdpsnd_get_audio_tag_string(format->wFormatTag), - format->nChannels, format->nSamplesPerSec, format->wBitsPerSample); + switch (format->wFormatTag) + { + case WAVE_FORMAT_ADPCM: + case WAVE_FORMAT_DVI_ADPCM: + mac->FramesPerPacket *= 4; /* Compression ratio. */ + mac->format.wBitsPerSample *= 4; + break; + } - switch (format->wFormatTag) - { - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - mac->FramesPerPacket *= 4; /* Compression ratio. */ - mac->format.wBitsPerSample *= 4; - break; - } - - mac->audioFormat.mBitsPerChannel = mac->format.wBitsPerSample; - mac->audioFormat.mChannelsPerFrame = mac->format.nChannels; - mac->audioFormat.mFormatFlags = audin_mac_get_flags_for_format(format); - mac->audioFormat.mFormatID = audin_mac_get_format(format); - mac->audioFormat.mFramesPerPacket = 1; - mac->audioFormat.mSampleRate = mac->format.nSamplesPerSec; - mac->audioFormat.mBytesPerFrame = - mac->audioFormat.mChannelsPerFrame * mac->audioFormat.mBitsPerChannel / 8; - mac->audioFormat.mBytesPerPacket = - mac->audioFormat.mBytesPerFrame * mac->audioFormat.mFramesPerPacket; - - return CHANNEL_RC_OK; + mac->audioFormat.mBitsPerChannel = mac->format.wBitsPerSample; + mac->audioFormat.mChannelsPerFrame = mac->format.nChannels; + mac->audioFormat.mFormatFlags = audin_mac_get_flags_for_format(format); + mac->audioFormat.mFormatID = audin_mac_get_format(format); + mac->audioFormat.mFramesPerPacket = 1; + mac->audioFormat.mSampleRate = mac->format.nSamplesPerSec; + mac->audioFormat.mBytesPerFrame = + mac->audioFormat.mChannelsPerFrame * mac->audioFormat.mBitsPerChannel / 8; + mac->audioFormat.mBytesPerPacket = + mac->audioFormat.mBytesPerFrame * mac->audioFormat.mFramesPerPacket; + return CHANNEL_RC_OK; } -static void mac_audio_queue_input_cb(void *aqData, +static void mac_audio_queue_input_cb(void* aqData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer, - const AudioTimeStamp *inStartTime, + const AudioTimeStamp* inStartTime, UInt32 inNumPackets, - const AudioStreamPacketDescription *inPacketDesc) + const AudioStreamPacketDescription* inPacketDesc) { - AudinMacDevice* mac = (AudinMacDevice*)aqData; - UINT error; - int encoded_size = 0; - const BYTE *encoded_data; - BYTE *buffer = inBuffer->mAudioData; - int buffer_size = inBuffer->mAudioDataByteSize; - - (void)inAQ; - (void)inStartTime; - (void)inNumPackets; - (void)inPacketDesc; - - - /* Process. */ - switch (mac->format.wFormatTag) { - case WAVE_FORMAT_ADPCM: - if (!mac->dsp_context->encode_ms_adpcm(mac->dsp_context, - buffer, buffer_size, mac->format.nChannels, mac->format.nBlockAlign)) - { - SetLastError(ERROR_INTERNAL_ERROR); - return; - } - encoded_data = mac->dsp_context->adpcm_buffer; - encoded_size = mac->dsp_context->adpcm_size; - break; - case WAVE_FORMAT_DVI_ADPCM: - if (!mac->dsp_context->encode_ima_adpcm(mac->dsp_context, - buffer, buffer_size, mac->format.nChannels, mac->format.nBlockAlign)) - { - SetLastError(ERROR_INTERNAL_ERROR); - break; - } - encoded_data = mac->dsp_context->adpcm_buffer; - encoded_size = mac->dsp_context->adpcm_size; - break; - default: - encoded_data = buffer; - encoded_size = buffer_size; - break; - } - - if ((error = mac->receive(encoded_data, encoded_size, mac->user_data))) - { - WLog_ERR(TAG, "mac->receive failed with error %"PRIu32"", error); - SetLastError(ERROR_INTERNAL_ERROR); - return; - } + AudinMacDevice* mac = (AudinMacDevice*)aqData; + UINT error; + const BYTE* buffer = inBuffer->mAudioData; + int buffer_size = inBuffer->mAudioDataByteSize; + (void)inAQ; + (void)inStartTime; + (void)inNumPackets; + (void)inPacketDesc; + if ((error = mac->receive(&mac->format, buffer, buffer_size, mac->user_data))) + { + WLog_ERR(TAG, "mac->receive failed with error %"PRIu32"", error); + SetLastError(ERROR_INTERNAL_ERROR); + return; + } } -static UINT audin_mac_close(IAudinDevice *device) +static UINT audin_mac_close(IAudinDevice* device) { - UINT errCode = CHANNEL_RC_OK; - char errString[1024]; - OSStatus devStat; - AudinMacDevice *mac = (AudinMacDevice*)device; + UINT errCode = CHANNEL_RC_OK; + char errString[1024]; + OSStatus devStat; + AudinMacDevice* mac = (AudinMacDevice*)device; - if (device == NULL) - return ERROR_INVALID_PARAMETER; + if (device == NULL) + return ERROR_INVALID_PARAMETER; - if (mac->isOpen) - { - devStat = AudioQueueStop(mac->audioQueue, true); - if (devStat != 0) - { - errCode = GetLastError(); - WLog_ERR(TAG, "AudioQueueStop failed with %s [%"PRIu32"]", - winpr_strerror(errCode, errString, sizeof(errString)), errCode); - } - mac->isOpen = false; - } + if (mac->isOpen) + { + devStat = AudioQueueStop(mac->audioQueue, true); - if (mac->audioQueue) - { - devStat = AudioQueueDispose(mac->audioQueue, true); - if (devStat != 0) - { - errCode = GetLastError(); - WLog_ERR(TAG, "AudioQueueDispose failed with %s [%"PRIu32"]", - winpr_strerror(errCode, errString, sizeof(errString)), errCode); - } + if (devStat != 0) + { + errCode = GetLastError(); + WLog_ERR(TAG, "AudioQueueStop failed with %s [%"PRIu32"]", + winpr_strerror(errCode, errString, sizeof(errString)), errCode); + } - mac->audioQueue = NULL; - } + mac->isOpen = false; + } - mac->receive = NULL; - mac->user_data = NULL; + if (mac->audioQueue) + { + devStat = AudioQueueDispose(mac->audioQueue, true); - return errCode; + if (devStat != 0) + { + errCode = GetLastError(); + WLog_ERR(TAG, "AudioQueueDispose failed with %s [%"PRIu32"]", + winpr_strerror(errCode, errString, sizeof(errString)), errCode); + } + + mac->audioQueue = NULL; + } + + mac->receive = NULL; + mac->user_data = NULL; + return errCode; } -static UINT audin_mac_open(IAudinDevice *device, AudinReceive receive, void *user_data) { - AudinMacDevice *mac = (AudinMacDevice*)device; - DWORD errCode; - char errString[1024]; - OSStatus devStat; - size_t index; +static UINT audin_mac_open(IAudinDevice* device, AudinReceive receive, void* user_data) +{ + AudinMacDevice* mac = (AudinMacDevice*)device; + DWORD errCode; + char errString[1024]; + OSStatus devStat; + size_t index; + mac->receive = receive; + mac->user_data = user_data; + devStat = AudioQueueNewInput(&(mac->audioFormat), mac_audio_queue_input_cb, + mac, NULL, kCFRunLoopCommonModes, 0, &(mac->audioQueue)); - mac->receive = receive; - mac->user_data = user_data; + if (devStat != 0) + { + errCode = GetLastError(); + WLog_ERR(TAG, "AudioQueueNewInput failed with %s [%"PRIu32"]", + winpr_strerror(errCode, errString, sizeof(errString)), errCode); + goto err_out; + } - devStat = AudioQueueNewInput(&(mac->audioFormat), mac_audio_queue_input_cb, - mac, NULL, kCFRunLoopCommonModes, 0, &(mac->audioQueue)); - if (devStat != 0) - { - errCode = GetLastError(); - WLog_ERR(TAG, "AudioQueueNewInput failed with %s [%"PRIu32"]", - winpr_strerror(errCode, errString, sizeof(errString)), errCode); - goto err_out; - } + for (index = 0; index < MAC_AUDIO_QUEUE_NUM_BUFFERS; index++) + { + devStat = AudioQueueAllocateBuffer(mac->audioQueue, MAC_AUDIO_QUEUE_BUFFER_SIZE, + &mac->audioBuffers[index]); - for (index = 0; index < MAC_AUDIO_QUEUE_NUM_BUFFERS; index++) - { - devStat = AudioQueueAllocateBuffer(mac->audioQueue, MAC_AUDIO_QUEUE_BUFFER_SIZE, - &mac->audioBuffers[index]); - if (devStat != 0) - { - errCode = GetLastError(); - WLog_ERR(TAG, "AudioQueueAllocateBuffer failed with %s [%"PRIu32"]", - winpr_strerror(errCode, errString, sizeof(errString)), errCode); - goto err_out; - } + if (devStat != 0) + { + errCode = GetLastError(); + WLog_ERR(TAG, "AudioQueueAllocateBuffer failed with %s [%"PRIu32"]", + winpr_strerror(errCode, errString, sizeof(errString)), errCode); + goto err_out; + } - devStat = AudioQueueEnqueueBuffer(mac->audioQueue, - mac->audioBuffers[index], - 0, - NULL); - if (devStat != 0) - { - errCode = GetLastError(); - WLog_ERR(TAG, "AudioQueueEnqueueBuffer failed with %s [%"PRIu32"]", - winpr_strerror(errCode, errString, sizeof(errString)), errCode); - goto err_out; - } - } + devStat = AudioQueueEnqueueBuffer(mac->audioQueue, + mac->audioBuffers[index], + 0, + NULL); - freerdp_dsp_context_reset_adpcm(mac->dsp_context); + if (devStat != 0) + { + errCode = GetLastError(); + WLog_ERR(TAG, "AudioQueueEnqueueBuffer failed with %s [%"PRIu32"]", + winpr_strerror(errCode, errString, sizeof(errString)), errCode); + goto err_out; + } + } - devStat = AudioQueueStart(mac->audioQueue, NULL); - if (devStat != 0) - { - errCode = GetLastError(); - WLog_ERR(TAG, "AudioQueueStart failed with %s [%"PRIu32"]", - winpr_strerror(errCode, errString, sizeof(errString)), errCode); - goto err_out; - } - mac->isOpen = true; + devStat = AudioQueueStart(mac->audioQueue, NULL); - return CHANNEL_RC_OK; + if (devStat != 0) + { + errCode = GetLastError(); + WLog_ERR(TAG, "AudioQueueStart failed with %s [%"PRIu32"]", + winpr_strerror(errCode, errString, sizeof(errString)), errCode); + goto err_out; + } + mac->isOpen = true; + return CHANNEL_RC_OK; err_out: - audin_mac_close(device); - return CHANNEL_RC_INITIALIZATION_ERROR; + audin_mac_close(device); + return CHANNEL_RC_INITIALIZATION_ERROR; } static UINT audin_mac_free(IAudinDevice* device) { - AudinMacDevice *mac = (AudinMacDevice*)device; + AudinMacDevice* mac = (AudinMacDevice*)device; + int error; - int error; + if (device == NULL) + return ERROR_INVALID_PARAMETER; - if (device == NULL) - return ERROR_INVALID_PARAMETER; + if ((error = audin_mac_close(device))) + { + WLog_ERR(TAG, "audin_oss_close failed with error code %d!", error); + } - if ((error = audin_mac_close(device))) - { - WLog_ERR(TAG, "audin_oss_close failed with error code %d!", error); - } - freerdp_dsp_context_free(mac->dsp_context); - free(mac); - - return CHANNEL_RC_OK; + free(mac); + return CHANNEL_RC_OK; } static COMMAND_LINE_ARGUMENT_A audin_mac_args[] = { - { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "audio device name" }, - { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } + { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "audio device name" }, + { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; -static UINT audin_mac_parse_addin_args(AudinMacDevice *device, ADDIN_ARGV *args) +static UINT audin_mac_parse_addin_args(AudinMacDevice* device, ADDIN_ARGV* args) { - DWORD errCode; - char errString[1024]; - int status; - char* str_num, *eptr; - DWORD flags; - COMMAND_LINE_ARGUMENT_A* arg; - AudinMacDevice* mac = (AudinMacDevice*)device; + DWORD errCode; + char errString[1024]; + int status; + char* str_num, *eptr; + DWORD flags; + COMMAND_LINE_ARGUMENT_A* arg; + AudinMacDevice* mac = (AudinMacDevice*)device; - if (args->argc == 1) - return CHANNEL_RC_OK; + if (args->argc == 1) + return CHANNEL_RC_OK; - flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; - status = CommandLineParseArgumentsA(args->argc, (const char**)args->argv, audin_mac_args, flags, mac, NULL, NULL); + flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; + status = CommandLineParseArgumentsA(args->argc, (const char**)args->argv, audin_mac_args, flags, + mac, NULL, NULL); - if (status < 0) - return ERROR_INVALID_PARAMETER; + if (status < 0) + return ERROR_INVALID_PARAMETER; - arg = audin_mac_args; + arg = audin_mac_args; - do - { - if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) - continue; + do + { + if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) + continue; - CommandLineSwitchStart(arg) - CommandLineSwitchCase(arg, "dev") - { - str_num = _strdup(arg->Value); - if (!str_num) - { - errCode = GetLastError(); - WLog_ERR(TAG, "_strdup failed with %s [%d]", - winpr_strerror(errCode, errString, sizeof(errString)), errCode); - return CHANNEL_RC_NO_MEMORY; - } - mac->dev_unit = strtol(str_num, &eptr, 10); + CommandLineSwitchStart(arg) + CommandLineSwitchCase(arg, "dev") + { + str_num = _strdup(arg->Value); - if (mac->dev_unit < 0 || *eptr != '\0') - mac->dev_unit = -1; + if (!str_num) + { + errCode = GetLastError(); + WLog_ERR(TAG, "_strdup failed with %s [%d]", + winpr_strerror(errCode, errString, sizeof(errString)), errCode); + return CHANNEL_RC_NO_MEMORY; + } - free(str_num); - } - CommandLineSwitchEnd(arg) - } - while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + mac->dev_unit = strtol(str_num, &eptr, 10); - return CHANNEL_RC_OK; + if (mac->dev_unit < 0 || *eptr != '\0') + mac->dev_unit = -1; + + free(str_num); + } + CommandLineSwitchEnd(arg) + } + while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + + return CHANNEL_RC_OK; } #ifdef BUILTIN_CHANNELS @@ -411,56 +378,44 @@ static UINT audin_mac_parse_addin_args(AudinMacDevice *device, ADDIN_ARGV *args) UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints) { - DWORD errCode; - char errString[1024]; - ADDIN_ARGV *args; - AudinMacDevice *mac; - UINT error; + DWORD errCode; + char errString[1024]; + ADDIN_ARGV* args; + AudinMacDevice* mac; + UINT error; + mac = (AudinMacDevice*)calloc(1, sizeof(AudinMacDevice)); - mac = (AudinMacDevice*)calloc(1, sizeof(AudinMacDevice)); - if (!mac) - { - errCode = GetLastError(); - WLog_ERR(TAG, "calloc failed with %s [%"PRIu32"]", - winpr_strerror(errCode, errString, sizeof(errString)), errCode); - return CHANNEL_RC_NO_MEMORY; - } + if (!mac) + { + errCode = GetLastError(); + WLog_ERR(TAG, "calloc failed with %s [%"PRIu32"]", + winpr_strerror(errCode, errString, sizeof(errString)), errCode); + return CHANNEL_RC_NO_MEMORY; + } - mac->iface.Open = audin_mac_open; - mac->iface.FormatSupported = audin_mac_format_supported; - mac->iface.SetFormat = audin_mac_set_format; - mac->iface.Close = audin_mac_close; - mac->iface.Free = audin_mac_free; - mac->rdpcontext = pEntryPoints->rdpcontext; + mac->iface.Open = audin_mac_open; + mac->iface.FormatSupported = audin_mac_format_supported; + mac->iface.SetFormat = audin_mac_set_format; + mac->iface.Close = audin_mac_close; + mac->iface.Free = audin_mac_free; + mac->rdpcontext = pEntryPoints->rdpcontext; + mac->dev_unit = -1; + args = pEntryPoints->args; - mac->dev_unit = -1; - args = pEntryPoints->args; + if ((error = audin_mac_parse_addin_args(mac, args))) + { + WLog_ERR(TAG, "audin_mac_parse_addin_args failed with %"PRIu32"!", error); + goto error_out; + } - if ((error = audin_mac_parse_addin_args(mac, args))) - { - WLog_ERR(TAG, "audin_mac_parse_addin_args failed with %"PRIu32"!", error); - goto error_out; - } - - mac->dsp_context = freerdp_dsp_context_new(); - if (!mac->dsp_context) - { - WLog_ERR(TAG, "freerdp_dsp_context_new failed!"); - error = CHANNEL_RC_NO_MEMORY; - goto error_out; - } - - if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) mac))) - { - WLog_ERR(TAG, "RegisterAudinDevice failed with error %"PRIu32"!", error); - goto error_out; - } - - return CHANNEL_RC_OK; + if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) mac))) + { + WLog_ERR(TAG, "RegisterAudinDevice failed with error %"PRIu32"!", error); + goto error_out; + } + return CHANNEL_RC_OK; error_out: - freerdp_dsp_context_free(mac->dsp_context); - free(mac); - return error; - + free(mac); + return error; } diff --git a/channels/audin/client/opensles/audin_opensl_es.c b/channels/audin/client/opensles/audin_opensl_es.c index 8a11aff8f..760c748eb 100644 --- a/channels/audin/client/opensles/audin_opensl_es.c +++ b/channels/audin/client/opensles/audin_opensl_es.c @@ -34,7 +34,6 @@ #include #include -#include #include #include @@ -48,18 +47,13 @@ typedef struct _AudinOpenSLESDevice IAudinDevice iface; char* device_name; - OPENSL_STREAM *stream; + OPENSL_STREAM* stream; + AUDIO_FORMAT format; UINT32 frames_per_packet; - UINT32 rate; - UINT32 channels; UINT32 bytes_per_channel; - UINT32 format; - UINT32 block_size; - - FREERDP_DSP_CONTEXT* dsp_context; AudinReceive receive; HANDLE thread; @@ -74,94 +68,59 @@ static DWORD WINAPI audin_opensles_thread_func(LPVOID arg) { union { - void *v; + void* v; short* s; - BYTE *b; + BYTE* b; } buffer; AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) arg; const size_t raw_size = opensles->frames_per_packet * opensles->bytes_per_channel; int rc = CHANNEL_RC_OK; UINT error = CHANNEL_RC_OK; - DWORD status; - + DWORD status; DEBUG_DVC("opensles=%p", (void*) opensles); - assert(opensles); assert(opensles->frames_per_packet > 0); - assert(opensles->dsp_context); assert(opensles->stopEvent); assert(opensles->stream); - buffer.v = calloc(1, raw_size); + if (!buffer.v) { - error = CHANNEL_RC_NO_MEMORY; + error = CHANNEL_RC_NO_MEMORY; WLog_ERR(TAG, "calloc failed!"); - if (opensles->rdpcontext) - setChannelError(opensles->rdpcontext, CHANNEL_RC_NO_MEMORY, "audin_opensles_thread_func reported an error"); - goto out; - } - freerdp_dsp_context_reset_adpcm(opensles->dsp_context); + if (opensles->rdpcontext) + setChannelError(opensles->rdpcontext, CHANNEL_RC_NO_MEMORY, + "audin_opensles_thread_func reported an error"); + + goto out; + } while (1) { + status = WaitForSingleObject(opensles->stopEvent, 0); - status = WaitForSingleObject(opensles->stopEvent, 0); + if (status == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); + break; + } - if (status == WAIT_FAILED) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); - break; - } - - if (status == WAIT_OBJECT_0) - break; - - size_t encoded_size; - void *encoded_data; + if (status == WAIT_OBJECT_0) + break; rc = android_RecIn(opensles->stream, buffer.s, raw_size); + if (rc < 0) { WLog_ERR(TAG, "android_RecIn %d", rc); continue; } - assert(rc == raw_size); - if (opensles->format == WAVE_FORMAT_ADPCM) - { - if (!opensles->dsp_context->encode_ms_adpcm(opensles->dsp_context, - buffer.b, rc, opensles->channels, opensles->block_size)) - { - error = ERROR_INTERNAL_ERROR; - break; - } + error = opensles->receive(&opensles->format, + buffer.v, raw_size, opensles->user_data); - encoded_data = opensles->dsp_context->adpcm_buffer; - encoded_size = opensles->dsp_context->adpcm_size; - } - else if (opensles->format == WAVE_FORMAT_DVI_ADPCM) - { - if (!opensles->dsp_context->encode_ima_adpcm(opensles->dsp_context, - buffer.b, rc, - opensles->channels, opensles->block_size)) - { - error = ERROR_INTERNAL_ERROR; - break; - } - - encoded_data = opensles->dsp_context->adpcm_buffer; - encoded_size = opensles->dsp_context->adpcm_size; - } - else - { - encoded_data = buffer.v; - encoded_size = rc; - } - - error = opensles->receive(encoded_data, encoded_size, opensles->user_data); if (error) break; } @@ -185,7 +144,6 @@ out: static UINT audin_opensles_free(IAudinDevice* device) { AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device; - DEBUG_DVC("device=%p", (void*) device); /* The function may have been called out of order, @@ -194,53 +152,38 @@ static UINT audin_opensles_free(IAudinDevice* device) return CHANNEL_RC_OK; assert(opensles); - assert(opensles->dsp_context); assert(!opensles->stream); - - freerdp_dsp_context_free(opensles->dsp_context); - free(opensles->device_name); - free(opensles); - return CHANNEL_RC_OK; } -static BOOL audin_opensles_format_supported(IAudinDevice* device, audinFormat* format) +static BOOL audin_opensles_format_supported(IAudinDevice* device, + const AUDIO_FORMAT* format) { #ifdef WITH_DEBUG_DVC AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device; #endif - DEBUG_DVC("device=%p, format=%p", (void*) opensles, (void*) format); - assert(format); switch (format->wFormatTag) { case WAVE_FORMAT_PCM: /* PCM */ if (format->cbSize == 0 && - (format->nSamplesPerSec <= 48000) && - (format->wBitsPerSample == 8 || format->wBitsPerSample == 16) && - (format->nChannels >= 1 && format->nChannels <= 2)) - { - return TRUE; - } - break; - /* TODO: Deactivated format, does not work, find out why */ -// case WAVE_FORMAT_ADPCM: /* IMA ADPCM */ - case WAVE_FORMAT_DVI_ADPCM: - if ((format->nSamplesPerSec <= 48000) && - (format->wBitsPerSample == 4) && - (format->nChannels == 1 || format->nChannels == 2)) + (format->nSamplesPerSec <= 48000) && + (format->wBitsPerSample == 8 || format->wBitsPerSample == 16) && + (format->nChannels >= 1 && format->nChannels <= 2)) { return TRUE; } + break; + default: DEBUG_DVC("Encoding '%s' [0x%04X"PRIX16"] not supported", - rdpsnd_get_audio_tag_string(format->wFormatTag), - format->wFormatTag); + rdpsnd_get_audio_tag_string(format->wFormatTag), + format->wFormatTag); break; } @@ -253,14 +196,11 @@ static BOOL audin_opensles_format_supported(IAudinDevice* device, audinFormat* f * @return 0 on success, otherwise a Win32 error code */ static UINT audin_opensles_set_format(IAudinDevice* device, - audinFormat* format, UINT32 FramesPerPacket) + const AUDIO_FORMAT* format, UINT32 FramesPerPacket) { - int bs; AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device; - DEBUG_DVC("device=%p, format=%p, FramesPerPacket=%"PRIu32"", (void*) device, (void*) format, FramesPerPacket); - assert(format); /* The function may have been called out of order, ignore @@ -268,52 +208,42 @@ static UINT audin_opensles_set_format(IAudinDevice* device, if (!opensles) return CHANNEL_RC_OK; + opensles->format = *format; + switch (format->wFormatTag) { case WAVE_FORMAT_PCM: opensles->frames_per_packet = FramesPerPacket; + switch (format->wBitsPerSample) { case 4: opensles->bytes_per_channel = 1; break; + case 8: opensles->bytes_per_channel = 1; break; + case 16: opensles->bytes_per_channel = 2; break; + + default: + return ERROR_UNSUPPORTED_TYPE; } - break; - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - opensles->bytes_per_channel = 2; - bs = (format->nBlockAlign - 4 * format->nChannels) * 4; - - opensles->frames_per_packet = - (FramesPerPacket * format->nChannels * 2 / - bs + 1) * bs / (format->nChannels * 2); - break; - case WAVE_FORMAT_ALAW: - case WAVE_FORMAT_MULAW: - opensles->frames_per_packet = FramesPerPacket; + break; default: WLog_ERR(TAG, "Encoding '%"PRIu16"' [%04"PRIX16"] not supported", - format->wFormatTag, - format->wFormatTag); + format->wFormatTag, + format->wFormatTag); return ERROR_UNSUPPORTED_TYPE; } - opensles->rate = format->nSamplesPerSec; - opensles->channels = format->nChannels; - - opensles->format = format->wFormatTag; - opensles->block_size = format->nBlockAlign; - DEBUG_DVC("aligned frames_per_packet=%"PRIu32", block_size=%"PRIu32"", - opensles->frames_per_packet, opensles->block_size); + opensles->frames_per_packet, opensles->block_size); return CHANNEL_RC_OK; } @@ -323,25 +253,24 @@ static UINT audin_opensles_set_format(IAudinDevice* device, * @return 0 on success, otherwise a Win32 error code */ static UINT audin_opensles_open(IAudinDevice* device, AudinReceive receive, - void* user_data) + void* user_data) { AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device; - - DEBUG_DVC("device=%p, receive=%p, user_data=%p", (void*) device, (void*) receive, (void*) user_data); - + DEBUG_DVC("device=%p, receive=%p, user_data=%p", (void*) device, (void*) receive, + (void*) user_data); assert(opensles); /* The function may have been called out of order, * ignore duplicate open requests. */ - if(opensles->stream) + if (opensles->stream) return CHANNEL_RC_OK; - if(!(opensles->stream = android_OpenRecDevice( - opensles->device_name, - opensles->rate, - opensles->channels, - opensles->frames_per_packet, - opensles->bytes_per_channel * 8))) + if (!(opensles->stream = android_OpenRecDevice( + opensles->device_name, + opensles->format.nSamplesPerSec, + opensles->format.nChannels, + opensles->frames_per_packet, + opensles->format.wBitsPerSample))) { WLog_ERR(TAG, "android_OpenRecDevice failed!"); return ERROR_INTERNAL_ERROR; @@ -355,13 +284,14 @@ static UINT audin_opensles_open(IAudinDevice* device, AudinReceive receive, WLog_ERR(TAG, "CreateEvent failed!"); goto error_out; } + if (!(opensles->thread = CreateThread(NULL, 0, - audin_opensles_thread_func, - opensles, 0, NULL))) + audin_opensles_thread_func, opensles, 0, NULL))) { WLog_ERR(TAG, "CreateThread failed!"); goto error_out; } + return CHANNEL_RC_OK; error_out: android_CloseRecDevice(opensles->stream); @@ -378,11 +308,9 @@ error_out: */ static UINT audin_opensles_close(IAudinDevice* device) { - UINT error; + UINT error; AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device; - DEBUG_DVC("device=%p", (void*) device); - assert(opensles); /* The function may have been called out of order, @@ -396,32 +324,32 @@ static UINT audin_opensles_close(IAudinDevice* device) assert(opensles->stopEvent); assert(opensles->thread); assert(opensles->stream); - SetEvent(opensles->stopEvent); + if (WaitForSingleObject(opensles->thread, INFINITE) == WAIT_FAILED) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error); - return error; - } + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"", error); + return error; + } + CloseHandle(opensles->stopEvent); CloseHandle(opensles->thread); - android_CloseRecDevice(opensles->stream); - opensles->stopEvent = NULL; opensles->thread = NULL; opensles->receive = NULL; opensles->user_data = NULL; opensles->stream = NULL; - return CHANNEL_RC_OK; } static COMMAND_LINE_ARGUMENT_A audin_opensles_args[] = { - { "dev", COMMAND_LINE_VALUE_REQUIRED, "", - NULL, NULL, -1, NULL, "audio device name" }, + { + "dev", COMMAND_LINE_VALUE_REQUIRED, "", + NULL, NULL, -1, NULL, "audio device name" + }, { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; @@ -431,19 +359,17 @@ static COMMAND_LINE_ARGUMENT_A audin_opensles_args[] = * @return 0 on success, otherwise a Win32 error code */ static UINT audin_opensles_parse_addin_args(AudinOpenSLESDevice* device, - ADDIN_ARGV* args) + ADDIN_ARGV* args) { UINT status; DWORD flags; COMMAND_LINE_ARGUMENT_A* arg; AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device; - DEBUG_DVC("device=%p, args=%p", (void*) device, (void*) args); - flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; - status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv, - audin_opensles_args, flags, opensles, NULL, NULL); + audin_opensles_args, flags, opensles, NULL, NULL); + if (status < 0) return status; @@ -455,17 +381,16 @@ static UINT audin_opensles_parse_addin_args(AudinOpenSLESDevice* device, continue; CommandLineSwitchStart(arg) - CommandLineSwitchCase(arg, "dev") { opensles->device_name = _strdup(arg->Value); + if (!opensles->device_name) { WLog_ERR(TAG, "_strdup failed!"); return CHANNEL_RC_NO_MEMORY; } } - CommandLineSwitchEnd(arg) } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); @@ -487,15 +412,14 @@ static UINT audin_opensles_parse_addin_args(AudinOpenSLESDevice* device, * @return 0 on success, otherwise a Win32 error code */ UINT freerdp_audin_client_subsystem_entry( - PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints) + PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints) { ADDIN_ARGV* args; AudinOpenSLESDevice* opensles; UINT error; - DEBUG_DVC("pEntryPoints=%p", (void*) pEntryPoints); - opensles = (AudinOpenSLESDevice*) calloc(1, sizeof(AudinOpenSLESDevice)); + if (!opensles) { WLog_ERR(TAG, "calloc failed!"); @@ -508,7 +432,6 @@ UINT freerdp_audin_client_subsystem_entry( opensles->iface.Close = audin_opensles_close; opensles->iface.Free = audin_opensles_free; opensles->rdpcontext = pEntryPoints->rdpcontext; - args = pEntryPoints->args; if ((error = audin_opensles_parse_addin_args(opensles, args))) @@ -517,14 +440,6 @@ UINT freerdp_audin_client_subsystem_entry( goto error_out; } - opensles->dsp_context = freerdp_dsp_context_new(); - if (!opensles->dsp_context) - { - WLog_ERR(TAG, "freerdp_dsp_context_new failed!"); - error = CHANNEL_RC_NO_MEMORY; - goto error_out; - } - if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) opensles))) { WLog_ERR(TAG, "RegisterAudinDevice failed with error %"PRIu32"!", error); @@ -533,7 +448,6 @@ UINT freerdp_audin_client_subsystem_entry( return CHANNEL_RC_OK; error_out: - freerdp_dsp_context_free(opensles->dsp_context); free(opensles); return error; } diff --git a/channels/audin/client/oss/audin_oss.c b/channels/audin/client/oss/audin_oss.c index fb72ea280..a958a54e1 100644 --- a/channels/audin/client/oss/audin_oss.c +++ b/channels/audin/client/oss/audin_oss.c @@ -47,7 +47,6 @@ #include #include -#include #include #include "audin_main.h" @@ -56,12 +55,10 @@ typedef struct _AudinOSSDevice { IAudinDevice iface; - FREERDP_DSP_CONTEXT* dsp_context; - HANDLE thread; HANDLE stopEvent; - audinFormat format; + AUDIO_FORMAT format; UINT32 FramesPerPacket; int dev_unit; @@ -76,7 +73,7 @@ typedef struct _AudinOSSDevice WLog_ERR(TAG, "%s: %i - %s\n", _text, _error, strerror(_error)); -static int audin_oss_get_format(audinFormat* format) +static int audin_oss_get_format(const AUDIO_FORMAT* format) { switch (format->wFormatTag) { @@ -94,25 +91,17 @@ static int audin_oss_get_format(audinFormat* format) case WAVE_FORMAT_ALAW: return AFMT_A_LAW; -#if 0 /* This does not work on my desktop. */ case WAVE_FORMAT_MULAW: return AFMT_MU_LAW; -#endif - - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - return AFMT_S16_LE; } return 0; } static BOOL audin_oss_format_supported(IAudinDevice* device, - audinFormat* format) + const AUDIO_FORMAT* format) { - int req_fmt = 0; - if (device == NULL || format == NULL) return FALSE; @@ -127,21 +116,14 @@ static BOOL audin_oss_format_supported(IAudinDevice* device, break; - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - if (format->nSamplesPerSec > 48000 || - format->wBitsPerSample != 4 || - (format->nChannels != 1 && format->nChannels != 2)) - return FALSE; + case WAVE_FORMAT_ALAW: + case WAVE_FORMAT_MULAW: + return TRUE; - break; + default: + return FALSE; } - req_fmt = audin_oss_get_format(format); - - if (req_fmt == 0) - return FALSE; - return TRUE; } @@ -150,7 +132,7 @@ static BOOL audin_oss_format_supported(IAudinDevice* device, * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_oss_set_format(IAudinDevice* device, audinFormat* format, +static UINT audin_oss_set_format(IAudinDevice* device, const AUDIO_FORMAT* format, UINT32 FramesPerPacket) { AudinOSSDevice* oss = (AudinOSSDevice*)device; @@ -159,17 +141,7 @@ static UINT audin_oss_set_format(IAudinDevice* device, audinFormat* format, return ERROR_INVALID_PARAMETER; oss->FramesPerPacket = FramesPerPacket; - CopyMemory(&(oss->format), format, sizeof(audinFormat)); - - switch (format->wFormatTag) - { - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - oss->FramesPerPacket *= 4; /* Compression ratio. */ - oss->format.wBitsPerSample *= 4; - break; - } - + oss->format = *format; return CHANNEL_RC_OK; } @@ -178,8 +150,9 @@ static DWORD WINAPI audin_oss_thread_func(LPVOID arg) char dev_name[PATH_MAX] = "/dev/dsp"; char mixer_name[PATH_MAX] = "/dev/mixer"; int pcm_handle = -1, mixer_handle; - BYTE* buffer = NULL, *encoded_data = NULL; - int tmp, buffer_size, encoded_size; + BYTE* buffer = NULL; + int tmp; + size_t buffer_size; AudinOSSDevice* oss = (AudinOSSDevice*)arg; UINT error = 0; DWORD status; @@ -271,8 +244,6 @@ static DWORD WINAPI audin_oss_thread_func(LPVOID arg) goto err_out; } - freerdp_dsp_context_reset_adpcm(oss->dsp_context); - while (1) { status = WaitForSingleObject(oss->stopEvent, 0); @@ -299,40 +270,7 @@ static DWORD WINAPI audin_oss_thread_func(LPVOID arg) if (tmp < buffer_size) /* Not enouth data. */ continue; - /* Process. */ - switch (oss->format.wFormatTag) - { - case WAVE_FORMAT_ADPCM: - if (!oss->dsp_context->encode_ms_adpcm(oss->dsp_context, - buffer, buffer_size, oss->format.nChannels, oss->format.nBlockAlign)) - { - error = ERROR_INTERNAL_ERROR; - goto err_out; - } - - encoded_data = oss->dsp_context->adpcm_buffer; - encoded_size = oss->dsp_context->adpcm_size; - break; - - case WAVE_FORMAT_DVI_ADPCM: - if (!oss->dsp_context->encode_ima_adpcm(oss->dsp_context, - buffer, buffer_size, oss->format.nChannels, oss->format.nBlockAlign)) - { - error = ERROR_INTERNAL_ERROR; - goto err_out; - } - - encoded_data = oss->dsp_context->adpcm_buffer; - encoded_size = oss->dsp_context->adpcm_size; - break; - - default: - encoded_data = buffer; - encoded_size = buffer_size; - break; - } - - if ((error = oss->receive(encoded_data, encoded_size, oss->user_data))) + if ((error = oss->receive(&oss->format, buffer, buffer_size, oss->user_data))) { WLog_ERR(TAG, "oss->receive failed with error %"PRIu32"", error); break; @@ -438,12 +376,11 @@ static UINT audin_oss_free(IAudinDevice* device) WLog_ERR(TAG, "audin_oss_close failed with error code %d!", error); } - freerdp_dsp_context_free(oss->dsp_context); free(oss); return CHANNEL_RC_OK; } -COMMAND_LINE_ARGUMENT_A audin_oss_args[] = +static COMMAND_LINE_ARGUMENT_A audin_oss_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "audio device name" }, { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } @@ -552,15 +489,6 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS goto error_out; } - oss->dsp_context = freerdp_dsp_context_new(); - - if (!oss->dsp_context) - { - WLog_ERR(TAG, "freerdp_dsp_context_new failed!"); - error = CHANNEL_RC_NO_MEMORY; - goto error_out; - } - if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) oss))) { @@ -570,7 +498,6 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS return CHANNEL_RC_OK; error_out: - freerdp_dsp_context_free(oss->dsp_context); free(oss); return error; } diff --git a/channels/audin/client/pulse/audin_pulse.c b/channels/audin/client/pulse/audin_pulse.c index e3b163ea4..f0743e231 100644 --- a/channels/audin/client/pulse/audin_pulse.c +++ b/channels/audin/client/pulse/audin_pulse.c @@ -34,7 +34,7 @@ #include #include -#include +#include #include #include "audin_main.h" @@ -49,14 +49,10 @@ typedef struct _AudinPulseDevice pa_context* context; pa_sample_spec sample_spec; pa_stream* stream; - int format; - int block_size; + AUDIO_FORMAT format; - FREERDP_DSP_CONTEXT* dsp_context; - - int bytes_per_frame; - BYTE* buffer; - int buffer_frames; + size_t bytes_per_frame; + size_t buffer_frames; AudinReceive receive; void* user_data; @@ -172,12 +168,11 @@ static UINT audin_pulse_free(IAudinDevice* device) pulse->mainloop = NULL; } - freerdp_dsp_context_free(pulse->dsp_context); free(pulse); return CHANNEL_RC_OK; } -static BOOL audin_pulse_format_supported(IAudinDevice* device, audinFormat* format) +static BOOL audin_pulse_format_supported(IAudinDevice* device, const AUDIO_FORMAT* format) { AudinPulseDevice* pulse = (AudinPulseDevice*) device; @@ -186,7 +181,7 @@ static BOOL audin_pulse_format_supported(IAudinDevice* device, audinFormat* form switch (format->wFormatTag) { - case 1: /* PCM */ + case WAVE_FORMAT_PCM: if (format->cbSize == 0 && (format->nSamplesPerSec <= PA_RATE_MAX) && (format->wBitsPerSample == 8 || format->wBitsPerSample == 16) && @@ -197,8 +192,8 @@ static BOOL audin_pulse_format_supported(IAudinDevice* device, audinFormat* form break; - case 6: /* A-LAW */ - case 7: /* U-LAW */ + case WAVE_FORMAT_ALAW: /* A-LAW */ + case WAVE_FORMAT_MULAW: /* U-LAW */ if (format->cbSize == 0 && (format->nSamplesPerSec <= PA_RATE_MAX) && (format->wBitsPerSample == 8) && @@ -209,15 +204,8 @@ static BOOL audin_pulse_format_supported(IAudinDevice* device, audinFormat* form break; - case 0x11: /* IMA ADPCM */ - if ((format->nSamplesPerSec <= PA_RATE_MAX) && - (format->wBitsPerSample == 4) && - (format->nChannels == 1 || format->nChannels == 2)) - { - return TRUE; - } - - break; + default: + return FALSE; } return FALSE; @@ -228,10 +216,9 @@ static BOOL audin_pulse_format_supported(IAudinDevice* device, audinFormat* form * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_pulse_set_format(IAudinDevice* device, audinFormat* format, +static UINT audin_pulse_set_format(IAudinDevice* device, const AUDIO_FORMAT* format, UINT32 FramesPerPacket) { - int bs; pa_sample_spec sample_spec = { 0 }; AudinPulseDevice* pulse = (AudinPulseDevice*) device; @@ -239,16 +226,14 @@ static UINT audin_pulse_set_format(IAudinDevice* device, audinFormat* format, return ERROR_INVALID_PARAMETER; if (FramesPerPacket > 0) - { pulse->frames_per_packet = FramesPerPacket; - } sample_spec.rate = format->nSamplesPerSec; sample_spec.channels = format->nChannels; switch (format->wFormatTag) { - case 1: /* PCM */ + case WAVE_FORMAT_PCM: /* PCM */ switch (format->wBitsPerSample) { case 8: @@ -258,31 +243,27 @@ static UINT audin_pulse_set_format(IAudinDevice* device, audinFormat* format, case 16: sample_spec.format = PA_SAMPLE_S16LE; break; + + default: + return ERROR_INTERNAL_ERROR; } break; - case 6: /* A-LAW */ + case WAVE_FORMAT_ALAW: /* A-LAW */ sample_spec.format = PA_SAMPLE_ALAW; break; - case 7: /* U-LAW */ + case WAVE_FORMAT_MULAW: /* U-LAW */ sample_spec.format = PA_SAMPLE_ULAW; break; - case 0x11: /* IMA ADPCM */ - sample_spec.format = PA_SAMPLE_S16LE; - bs = (format->nBlockAlign - 4 * format->nChannels) * 4; - pulse->frames_per_packet = (pulse->frames_per_packet * format->nChannels * 2 / - bs + 1) * bs / (format->nChannels * 2); - DEBUG_DVC("aligned FramesPerPacket=%"PRIu32"", - pulse->frames_per_packet); - break; + default: + return ERROR_INTERNAL_ERROR; } pulse->sample_spec = sample_spec; - pulse->format = format->wFormatTag; - pulse->block_size = format->nBlockAlign; + pulse->format = *format; return CHANNEL_RC_OK; } @@ -313,81 +294,15 @@ static void audin_pulse_stream_state_callback(pa_stream* stream, void* userdata) static void audin_pulse_stream_request_callback(pa_stream* stream, size_t length, void* userdata) { - int frames; - int cframes; const void* data; - const BYTE* src; - int encoded_size; - BYTE* encoded_data; AudinPulseDevice* pulse = (AudinPulseDevice*) userdata; UINT error = CHANNEL_RC_OK; - - /* There is a race condition here where we may receive this callback - * before the buffer has been set up in the main code. It's probably - * possible to fix with additional locking, but it's easier just to - * ignore input until the buffer is ready. - */ - if (pulse->buffer == NULL) - { - /* WLog_ERR(TAG, "%s: ignoring input, pulse buffer not ready.\n", __func__); */ - return; - } - pa_stream_peek(stream, &data, &length); - frames = length / pulse->bytes_per_frame; - DEBUG_DVC("length %"PRIdz" frames %d", length, frames); - src = (const BYTE*) data; - - while (frames > 0) - { - cframes = pulse->frames_per_packet - pulse->buffer_frames; - - if (cframes > frames) - cframes = frames; - - memcpy(pulse->buffer + pulse->buffer_frames * pulse->bytes_per_frame, - src, cframes * pulse->bytes_per_frame); - pulse->buffer_frames += cframes; - - if (pulse->buffer_frames >= pulse->frames_per_packet) - { - if (pulse->format == 0x11) - { - if (!pulse->dsp_context->encode_ima_adpcm(pulse->dsp_context, - pulse->buffer, pulse->buffer_frames * pulse->bytes_per_frame, - pulse->sample_spec.channels, pulse->block_size)) - { - error = ERROR_INTERNAL_ERROR; - break; - } - - encoded_data = pulse->dsp_context->adpcm_buffer; - encoded_size = pulse->dsp_context->adpcm_size; - } - else - { - encoded_data = pulse->buffer; - encoded_size = pulse->buffer_frames * pulse->bytes_per_frame; - } - - DEBUG_DVC("encoded %d [%d] to %d [%X]", - pulse->buffer_frames, pulse->bytes_per_frame, encoded_size, - pulse->format); - error = pulse->receive(encoded_data, encoded_size, pulse->user_data); - pulse->buffer_frames = 0; - - if (!error) - break; - } - - src += cframes * pulse->bytes_per_frame; - frames -= cframes; - } - + error = pulse->receive(&pulse->format, data, length, pulse->user_data); pa_stream_drop(stream); if (error && pulse->rdpcontext) - setChannelError(pulse->rdpcontext, error, "audin_oss_thread_func reported an error"); + setChannelError(pulse->rdpcontext, error, "audin_pulse_thread_func reported an error"); } @@ -411,14 +326,6 @@ static UINT audin_pulse_close(IAudinDevice* device) pulse->receive = NULL; pulse->user_data = NULL; - - if (pulse->buffer) - { - free(pulse->buffer); - pulse->buffer = NULL; - pulse->buffer_frames = 0; - } - return CHANNEL_RC_OK; } @@ -439,7 +346,6 @@ static UINT audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u if (!pulse->sample_spec.rate || pulse->stream) return ERROR_INVALID_PARAMETER; - pulse->buffer = NULL; pulse->receive = receive; pulse->user_data = user_data; pa_threaded_mainloop_lock(pulse->mainloop); @@ -496,15 +402,6 @@ static UINT audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u } pa_threaded_mainloop_unlock(pulse->mainloop); - freerdp_dsp_context_reset_adpcm(pulse->dsp_context); - pulse->buffer = calloc(pulse->frames_per_packet, pulse->bytes_per_frame); - - if (!pulse->buffer) - { - WLog_ERR(TAG, "calloc failed!"); - return CHANNEL_RC_NO_MEMORY; - } - pulse->buffer_frames = 0; DEBUG_DVC("connected"); return CHANNEL_RC_OK; @@ -597,15 +494,6 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn goto error_out; } - pulse->dsp_context = freerdp_dsp_context_new(); - - if (!pulse->dsp_context) - { - WLog_ERR(TAG, "freerdp_dsp_context_new failed!"); - error = CHANNEL_RC_NO_MEMORY; - goto error_out; - } - pulse->mainloop = pa_threaded_mainloop_new(); if (!pulse->mainloop) diff --git a/channels/audin/client/winmm/audin_winmm.c b/channels/audin/client/winmm/audin_winmm.c index aff631c1f..b3a49a4f1 100644 --- a/channels/audin/client/winmm/audin_winmm.c +++ b/channels/audin/client/winmm/audin_winmm.c @@ -1,464 +1,502 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * Audio Input Redirection Virtual Channel - WinMM implementation - * - * Copyright 2013 Zhang Zhaolong - * Copyright 2015 Thincast Technologies GmbH - * Copyright 2015 DI (FH) Martin Haimberger - * - * 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 - * limitations under the License. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include "audin_main.h" - -typedef struct _AudinWinmmDevice -{ - IAudinDevice iface; - - char* device_name; - AudinReceive receive; - void* user_data; - HANDLE thread; - HANDLE stopEvent; - HWAVEIN hWaveIn; - PWAVEFORMATEX *ppwfx; - PWAVEFORMATEX pwfx_cur; - UINT32 ppwfx_size; - UINT32 cFormats; - UINT32 frames_per_packet; - rdpContext* rdpcontext; -} AudinWinmmDevice; - -static void CALLBACK waveInProc(HWAVEIN hWaveIn, UINT uMsg, DWORD_PTR dwInstance, - DWORD_PTR dwParam1, DWORD_PTR dwParam2) -{ - AudinWinmmDevice* winmm = (AudinWinmmDevice*) dwInstance; - PWAVEHDR pWaveHdr; - UINT error = CHANNEL_RC_OK; - MMRESULT mmResult; - - switch(uMsg) - { - case WIM_CLOSE: - break; - - case WIM_DATA: - pWaveHdr = (WAVEHDR *)dwParam1; - if (WHDR_DONE == (WHDR_DONE & pWaveHdr->dwFlags)) - { - if (pWaveHdr->dwBytesRecorded - && !(WaitForSingleObject(winmm->stopEvent, 0) == WAIT_OBJECT_0)) - { - if ((error = winmm->receive(pWaveHdr->lpData, pWaveHdr->dwBytesRecorded, winmm->user_data))) - break; - mmResult = waveInAddBuffer(hWaveIn, pWaveHdr, sizeof(WAVEHDR)); - if (mmResult != MMSYSERR_NOERROR) - error = ERROR_INTERNAL_ERROR; - } - } - break; - - case WIM_OPEN: - break; - - default: - break; - } - if (error && winmm->rdpcontext) - setChannelError(winmm->rdpcontext, error, "waveInProc reported an error"); -} - -static DWORD WINAPI audin_winmm_thread_func(LPVOID arg) -{ - AudinWinmmDevice* winmm = (AudinWinmmDevice*) arg; - char *buffer; - int size, i; - WAVEHDR waveHdr[4]; - DWORD status; - MMRESULT rc; - - if (!winmm->hWaveIn) - { - if (MMSYSERR_NOERROR != waveInOpen(&winmm->hWaveIn, WAVE_MAPPER, winmm->pwfx_cur, - (DWORD_PTR)waveInProc, (DWORD_PTR)winmm, CALLBACK_FUNCTION)) - { - if (winmm->rdpcontext) - setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, "audin_winmm_thread_func reported an error"); - return 0; - } - } - - size = (winmm->pwfx_cur->wBitsPerSample * winmm->pwfx_cur->nChannels * winmm->frames_per_packet + 7) / 8; - for (i = 0; i < 4; i++) - { - buffer = (char *) malloc(size); - if (!buffer) - return CHANNEL_RC_NO_MEMORY; - waveHdr[i].dwBufferLength = size; - waveHdr[i].dwFlags = 0; - waveHdr[i].lpData = buffer; - - rc = waveInPrepareHeader(winmm->hWaveIn, &waveHdr[i], sizeof(waveHdr[i])); - if (MMSYSERR_NOERROR != rc) - { - DEBUG_DVC("waveInPrepareHeader failed. %"PRIu32"", rc); - if (winmm->rdpcontext) - setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, "audin_winmm_thread_func reported an error"); - } - - rc = waveInAddBuffer(winmm->hWaveIn, &waveHdr[i], sizeof(waveHdr[i])); - if (MMSYSERR_NOERROR != rc) - { - DEBUG_DVC("waveInAddBuffer failed. %"PRIu32"", rc); - if (winmm->rdpcontext) - setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, "audin_winmm_thread_func reported an error"); - } - } - - rc = waveInStart(winmm->hWaveIn); - if (MMSYSERR_NOERROR != rc) - { - DEBUG_DVC("waveInStart failed. %"PRIu32"", rc); - if (winmm->rdpcontext) - setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, "audin_winmm_thread_func reported an error"); - } - - status = WaitForSingleObject(winmm->stopEvent, INFINITE); - - if (status == WAIT_FAILED) -{ - DEBUG_DVC("WaitForSingleObject failed."); - if (winmm->rdpcontext) - setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, "audin_winmm_thread_func reported an error"); - } - - rc = waveInReset(winmm->hWaveIn); - if (MMSYSERR_NOERROR != rc) - { - DEBUG_DVC("waveInReset failed. %"PRIu32"", rc); - if (winmm->rdpcontext) - setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, "audin_winmm_thread_func reported an error"); - } - - for (i = 0; i < 4; i++) - { - rc = waveInUnprepareHeader(winmm->hWaveIn, &waveHdr[i], sizeof(waveHdr[i])); - if (MMSYSERR_NOERROR != rc) - { - DEBUG_DVC("waveInUnprepareHeader failed. %"PRIu32"", rc); - if (winmm->rdpcontext) - setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, "audin_winmm_thread_func reported an error"); - } - free(waveHdr[i].lpData); - } - - rc = waveInClose(winmm->hWaveIn); - if (MMSYSERR_NOERROR != rc) - { - DEBUG_DVC("waveInClose failed. %"PRIu32"", rc); - if (winmm->rdpcontext) - setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, "audin_winmm_thread_func reported an error"); - } - winmm->hWaveIn = NULL; - - return 0; -} - -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT audin_winmm_free(IAudinDevice* device) -{ - UINT32 i; - AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; - - for (i = 0; i < winmm->cFormats; i++) - { - free(winmm->ppwfx[i]); - } - - free(winmm->ppwfx); - free(winmm->device_name); - free(winmm); - - return CHANNEL_RC_OK; -} - -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT audin_winmm_close(IAudinDevice* device) -{ - DWORD status; - UINT error = CHANNEL_RC_OK; - AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; - - SetEvent(winmm->stopEvent); - - status = WaitForSingleObject(winmm->thread, INFINITE); - - if (status == WAIT_FAILED) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); - return error; - } - - CloseHandle(winmm->thread); - CloseHandle(winmm->stopEvent); - - winmm->thread = NULL; - winmm->stopEvent = NULL; - winmm->receive = NULL; - winmm->user_data = NULL; - - return error; -} - -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT audin_winmm_set_format(IAudinDevice* device, audinFormat* format, UINT32 FramesPerPacket) -{ - UINT32 i; - AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; - - winmm->frames_per_packet = FramesPerPacket; - - for (i = 0; i < winmm->cFormats; i++) - { - if (winmm->ppwfx[i]->wFormatTag == format->wFormatTag - && winmm->ppwfx[i]->nChannels == format->nChannels - && winmm->ppwfx[i]->wBitsPerSample == format->wBitsPerSample) - { - winmm->pwfx_cur = winmm->ppwfx[i]; - break; - } - } - return CHANNEL_RC_OK; -} - -static BOOL audin_winmm_format_supported(IAudinDevice* device, audinFormat* format) -{ - AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; - PWAVEFORMATEX pwfx; - BYTE *data; - - pwfx = (PWAVEFORMATEX)malloc(sizeof(WAVEFORMATEX) + format->cbSize); - if (!pwfx) - return FALSE; - pwfx->cbSize = format->cbSize; - pwfx->wFormatTag = format->wFormatTag; - pwfx->nChannels = format->nChannels; - pwfx->nSamplesPerSec = format->nSamplesPerSec; - pwfx->nBlockAlign = format->nBlockAlign; - pwfx->wBitsPerSample = format->wBitsPerSample; - data = (BYTE *)pwfx + sizeof(WAVEFORMATEX); - - memcpy(data, format->data, format->cbSize); - - if (pwfx->wFormatTag == WAVE_FORMAT_PCM) - { - pwfx->nAvgBytesPerSec = pwfx->nSamplesPerSec * pwfx->nBlockAlign; - if (MMSYSERR_NOERROR == waveInOpen(NULL, WAVE_MAPPER, pwfx, 0, 0, WAVE_FORMAT_QUERY)) - { - if (winmm->cFormats >= winmm->ppwfx_size) - { - PWAVEFORMATEX *tmp_ppwfx; - tmp_ppwfx = realloc(winmm->ppwfx, sizeof(PWAVEFORMATEX) * winmm->ppwfx_size * 2); - if (!tmp_ppwfx) - return FALSE; - - winmm->ppwfx_size *= 2; - winmm->ppwfx = tmp_ppwfx; - } - winmm->ppwfx[winmm->cFormats++] = pwfx; - - return TRUE; - } - } - - free(pwfx); - return FALSE; -} - -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT audin_winmm_open(IAudinDevice* device, AudinReceive receive, void* user_data) -{ - AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; - - winmm->receive = receive; - winmm->user_data = user_data; - - if (!(winmm->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) - { - WLog_ERR(TAG, "CreateEvent failed!"); - return ERROR_INTERNAL_ERROR; - } - - if (!(winmm->thread = CreateThread(NULL, 0, audin_winmm_thread_func, winmm, 0, NULL))) - { - WLog_ERR(TAG, "CreateThread failed!"); - CloseHandle(winmm->stopEvent); - winmm->stopEvent = NULL; - return ERROR_INTERNAL_ERROR; - } - return CHANNEL_RC_OK; -} - -static COMMAND_LINE_ARGUMENT_A audin_winmm_args[] = -{ - { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "audio device name" }, - { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } -}; - -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT audin_winmm_parse_addin_args(AudinWinmmDevice* device, ADDIN_ARGV* args) -{ - int status; - DWORD flags; - COMMAND_LINE_ARGUMENT_A* arg; - AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; - - flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; - - status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv, audin_winmm_args, flags, winmm, NULL, NULL); - - arg = audin_winmm_args; - - do - { - if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) - continue; - - CommandLineSwitchStart(arg) - - CommandLineSwitchCase(arg, "dev") - { - winmm->device_name = _strdup(arg->Value); - if (!winmm->device_name) - { - WLog_ERR(TAG, "_strdup failed!"); - return CHANNEL_RC_NO_MEMORY; - } - } - - CommandLineSwitchEnd(arg) - } - while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); - - return CHANNEL_RC_OK; -} - -#ifdef BUILTIN_CHANNELS -#define freerdp_audin_client_subsystem_entry winmm_freerdp_audin_client_subsystem_entry -#else -#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry -#endif - -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints) -{ - ADDIN_ARGV* args; - AudinWinmmDevice* winmm; - UINT error; - - winmm = (AudinWinmmDevice*) calloc(1, sizeof(AudinWinmmDevice)); - if (!winmm) - { - WLog_ERR(TAG, "calloc failed!"); - return CHANNEL_RC_NO_MEMORY; - } - - winmm->iface.Open = audin_winmm_open; - winmm->iface.FormatSupported = audin_winmm_format_supported; - winmm->iface.SetFormat = audin_winmm_set_format; - winmm->iface.Close = audin_winmm_close; - winmm->iface.Free = audin_winmm_free; - winmm->rdpcontext = pEntryPoints->rdpcontext; - - args = pEntryPoints->args; - - if ((error = audin_winmm_parse_addin_args(winmm, args))) - { - WLog_ERR(TAG, "audin_winmm_parse_addin_args failed with error %"PRIu32"!", error); - goto error_out; - } - - if (!winmm->device_name) - { - winmm->device_name = _strdup("default"); - if (!winmm->device_name) - { - WLog_ERR(TAG, "_strdup failed!"); - error = CHANNEL_RC_NO_MEMORY; - goto error_out; - } - } - - winmm->ppwfx_size = 10; - winmm->ppwfx = malloc(sizeof(PWAVEFORMATEX) * winmm->ppwfx_size); - if (!winmm->ppwfx) - { - WLog_ERR(TAG, "malloc failed!"); - error = CHANNEL_RC_NO_MEMORY; - goto error_out; - } - - if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) winmm))) - { - WLog_ERR(TAG, "RegisterAudinDevice failed with error %"PRIu32"!", error); - goto error_out; - } - - return CHANNEL_RC_OK; -error_out: - free(winmm->ppwfx); - free(winmm->device_name); - free(winmm); - return error; -} +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Audio Input Redirection Virtual Channel - WinMM implementation + * + * Copyright 2013 Zhang Zhaolong + * Copyright 2015 Thincast Technologies GmbH + * Copyright 2015 DI (FH) Martin Haimberger + * + * 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 + * limitations under the License. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "audin_main.h" + +typedef struct _AudinWinmmDevice +{ + IAudinDevice iface; + + char* device_name; + AudinReceive receive; + void* user_data; + HANDLE thread; + HANDLE stopEvent; + HWAVEIN hWaveIn; + PWAVEFORMATEX* ppwfx; + PWAVEFORMATEX pwfx_cur; + UINT32 ppwfx_size; + UINT32 cFormats; + UINT32 frames_per_packet; + rdpContext* rdpcontext; +} AudinWinmmDevice; + +static void CALLBACK waveInProc(HWAVEIN hWaveIn, UINT uMsg, DWORD_PTR dwInstance, + DWORD_PTR dwParam1, DWORD_PTR dwParam2) +{ + AudinWinmmDevice* winmm = (AudinWinmmDevice*) dwInstance; + PWAVEHDR pWaveHdr; + UINT error = CHANNEL_RC_OK; + MMRESULT mmResult; + + switch (uMsg) + { + case WIM_CLOSE: + break; + + case WIM_DATA: + pWaveHdr = (WAVEHDR*)dwParam1; + + if (WHDR_DONE == (WHDR_DONE & pWaveHdr->dwFlags)) + { + if (pWaveHdr->dwBytesRecorded + && !(WaitForSingleObject(winmm->stopEvent, 0) == WAIT_OBJECT_0)) + { + AUDIO_FORMAT format; + format.cbSize = winmm->pwfx_cur->cbSize; + format.nBlockAlign = winmm->pwfx_cur->nBlockAlign; + format.nAvgBytesPerSec = winmm->pwfx_cur->nAvgBytesPerSec; + format.nChannels = winmm->pwfx_cur->nChannels; + format.nSamplesPerSec = winmm->pwfx_cur->nSamplesPerSec; + format.wBitsPerSample = winmm->pwfx_cur->wBitsPerSample; + format.wFormatTag = winmm->pwfx_cur->wFormatTag; + + if ((error = winmm->receive(&format, pWaveHdr->lpData, pWaveHdr->dwBytesRecorded, + winmm->user_data))) + break; + + mmResult = waveInAddBuffer(hWaveIn, pWaveHdr, sizeof(WAVEHDR)); + + if (mmResult != MMSYSERR_NOERROR) + error = ERROR_INTERNAL_ERROR; + } + } + + break; + + case WIM_OPEN: + break; + + default: + break; + } + + if (error && winmm->rdpcontext) + setChannelError(winmm->rdpcontext, error, "waveInProc reported an error"); +} + +static DWORD WINAPI audin_winmm_thread_func(LPVOID arg) +{ + AudinWinmmDevice* winmm = (AudinWinmmDevice*) arg; + char* buffer; + int size, i; + WAVEHDR waveHdr[4]; + DWORD status; + MMRESULT rc; + + if (!winmm->hWaveIn) + { + if (MMSYSERR_NOERROR != waveInOpen(&winmm->hWaveIn, WAVE_MAPPER, winmm->pwfx_cur, + (DWORD_PTR)waveInProc, (DWORD_PTR)winmm, CALLBACK_FUNCTION)) + { + if (winmm->rdpcontext) + setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, + "audin_winmm_thread_func reported an error"); + + return ERROR_INTERNAL_ERROR; + } + } + + size = (winmm->pwfx_cur->wBitsPerSample * winmm->pwfx_cur->nChannels * winmm->frames_per_packet + + 7) / 8; + + for (i = 0; i < 4; i++) + { + buffer = (char*) malloc(size); + + if (!buffer) + return CHANNEL_RC_NO_MEMORY; + + waveHdr[i].dwBufferLength = size; + waveHdr[i].dwFlags = 0; + waveHdr[i].lpData = buffer; + rc = waveInPrepareHeader(winmm->hWaveIn, &waveHdr[i], sizeof(waveHdr[i])); + + if (MMSYSERR_NOERROR != rc) + { + DEBUG_DVC("waveInPrepareHeader failed. %"PRIu32"", rc); + + if (winmm->rdpcontext) + setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, + "audin_winmm_thread_func reported an error"); + } + + rc = waveInAddBuffer(winmm->hWaveIn, &waveHdr[i], sizeof(waveHdr[i])); + + if (MMSYSERR_NOERROR != rc) + { + DEBUG_DVC("waveInAddBuffer failed. %"PRIu32"", rc); + + if (winmm->rdpcontext) + setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, + "audin_winmm_thread_func reported an error"); + } + } + + rc = waveInStart(winmm->hWaveIn); + + if (MMSYSERR_NOERROR != rc) + { + DEBUG_DVC("waveInStart failed. %"PRIu32"", rc); + + if (winmm->rdpcontext) + setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, + "audin_winmm_thread_func reported an error"); + } + + status = WaitForSingleObject(winmm->stopEvent, INFINITE); + + if (status == WAIT_FAILED) + { + DEBUG_DVC("WaitForSingleObject failed."); + + if (winmm->rdpcontext) + setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, + "audin_winmm_thread_func reported an error"); + } + + rc = waveInReset(winmm->hWaveIn); + + if (MMSYSERR_NOERROR != rc) + { + DEBUG_DVC("waveInReset failed. %"PRIu32"", rc); + + if (winmm->rdpcontext) + setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, + "audin_winmm_thread_func reported an error"); + } + + for (i = 0; i < 4; i++) + { + rc = waveInUnprepareHeader(winmm->hWaveIn, &waveHdr[i], sizeof(waveHdr[i])); + + if (MMSYSERR_NOERROR != rc) + { + DEBUG_DVC("waveInUnprepareHeader failed. %"PRIu32"", rc); + + if (winmm->rdpcontext) + setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, + "audin_winmm_thread_func reported an error"); + } + + free(waveHdr[i].lpData); + } + + rc = waveInClose(winmm->hWaveIn); + + if (MMSYSERR_NOERROR != rc) + { + DEBUG_DVC("waveInClose failed. %"PRIu32"", rc); + + if (winmm->rdpcontext) + setChannelError(winmm->rdpcontext, ERROR_INTERNAL_ERROR, + "audin_winmm_thread_func reported an error"); + } + + winmm->hWaveIn = NULL; + return 0; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT audin_winmm_free(IAudinDevice* device) +{ + UINT32 i; + AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; + + for (i = 0; i < winmm->cFormats; i++) + { + free(winmm->ppwfx[i]); + } + + free(winmm->ppwfx); + free(winmm->device_name); + free(winmm); + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT audin_winmm_close(IAudinDevice* device) +{ + DWORD status; + UINT error = CHANNEL_RC_OK; + AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; + SetEvent(winmm->stopEvent); + status = WaitForSingleObject(winmm->thread, INFINITE); + + if (status == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); + return error; + } + + CloseHandle(winmm->thread); + CloseHandle(winmm->stopEvent); + winmm->thread = NULL; + winmm->stopEvent = NULL; + winmm->receive = NULL; + winmm->user_data = NULL; + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT audin_winmm_set_format(IAudinDevice* device, const AUDIO_FORMAT* format, + UINT32 FramesPerPacket) +{ + UINT32 i; + AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; + winmm->frames_per_packet = FramesPerPacket; + + for (i = 0; i < winmm->cFormats; i++) + { + if (winmm->ppwfx[i]->wFormatTag == format->wFormatTag + && winmm->ppwfx[i]->nChannels == format->nChannels + && winmm->ppwfx[i]->wBitsPerSample == format->wBitsPerSample) + { + winmm->pwfx_cur = winmm->ppwfx[i]; + break; + } + } + + return CHANNEL_RC_OK; +} + +static BOOL audin_winmm_format_supported(IAudinDevice* device, const AUDIO_FORMAT* format) +{ + AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; + PWAVEFORMATEX pwfx; + BYTE* data; + pwfx = (PWAVEFORMATEX)malloc(sizeof(WAVEFORMATEX) + format->cbSize); + + if (!pwfx) + return FALSE; + + pwfx->cbSize = format->cbSize; + pwfx->wFormatTag = format->wFormatTag; + pwfx->nChannels = format->nChannels; + pwfx->nSamplesPerSec = format->nSamplesPerSec; + pwfx->nBlockAlign = format->nBlockAlign; + pwfx->wBitsPerSample = format->wBitsPerSample; + data = (BYTE*)pwfx + sizeof(WAVEFORMATEX); + memcpy(data, format->data, format->cbSize); + + if (pwfx->wFormatTag == WAVE_FORMAT_PCM) + { + pwfx->nAvgBytesPerSec = pwfx->nSamplesPerSec * pwfx->nBlockAlign; + + if (MMSYSERR_NOERROR == waveInOpen(NULL, WAVE_MAPPER, pwfx, 0, 0, WAVE_FORMAT_QUERY)) + { + if (winmm->cFormats >= winmm->ppwfx_size) + { + PWAVEFORMATEX* tmp_ppwfx; + tmp_ppwfx = realloc(winmm->ppwfx, sizeof(PWAVEFORMATEX) * winmm->ppwfx_size * 2); + + if (!tmp_ppwfx) + return FALSE; + + winmm->ppwfx_size *= 2; + winmm->ppwfx = tmp_ppwfx; + } + + winmm->ppwfx[winmm->cFormats++] = pwfx; + return TRUE; + } + } + + free(pwfx); + return FALSE; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT audin_winmm_open(IAudinDevice* device, AudinReceive receive, void* user_data) +{ + AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; + winmm->receive = receive; + winmm->user_data = user_data; + + if (!(winmm->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) + { + WLog_ERR(TAG, "CreateEvent failed!"); + return ERROR_INTERNAL_ERROR; + } + + if (!(winmm->thread = CreateThread(NULL, 0, + audin_winmm_thread_func, winmm, 0, NULL))) + { + WLog_ERR(TAG, "CreateThread failed!"); + CloseHandle(winmm->stopEvent); + winmm->stopEvent = NULL; + return ERROR_INTERNAL_ERROR; + } + + return CHANNEL_RC_OK; +} + +static COMMAND_LINE_ARGUMENT_A audin_winmm_args[] = +{ + { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "audio device name" }, + { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } +}; + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT audin_winmm_parse_addin_args(AudinWinmmDevice* device, ADDIN_ARGV* args) +{ + int status; + DWORD flags; + COMMAND_LINE_ARGUMENT_A* arg; + AudinWinmmDevice* winmm = (AudinWinmmDevice*) device; + flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; + status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv, audin_winmm_args, flags, + winmm, NULL, NULL); + arg = audin_winmm_args; + + do + { + if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) + continue; + + CommandLineSwitchStart(arg) + CommandLineSwitchCase(arg, "dev") + { + winmm->device_name = _strdup(arg->Value); + + if (!winmm->device_name) + { + WLog_ERR(TAG, "_strdup failed!"); + return CHANNEL_RC_NO_MEMORY; + } + } + CommandLineSwitchEnd(arg) + } + while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + + return CHANNEL_RC_OK; +} + +#ifdef BUILTIN_CHANNELS +#define freerdp_audin_client_subsystem_entry winmm_freerdp_audin_client_subsystem_entry +#else +#define freerdp_audin_client_subsystem_entry FREERDP_API freerdp_audin_client_subsystem_entry +#endif + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints) +{ + ADDIN_ARGV* args; + AudinWinmmDevice* winmm; + UINT error; + winmm = (AudinWinmmDevice*) calloc(1, sizeof(AudinWinmmDevice)); + + if (!winmm) + { + WLog_ERR(TAG, "calloc failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + winmm->iface.Open = audin_winmm_open; + winmm->iface.FormatSupported = audin_winmm_format_supported; + winmm->iface.SetFormat = audin_winmm_set_format; + winmm->iface.Close = audin_winmm_close; + winmm->iface.Free = audin_winmm_free; + winmm->rdpcontext = pEntryPoints->rdpcontext; + args = pEntryPoints->args; + + if ((error = audin_winmm_parse_addin_args(winmm, args))) + { + WLog_ERR(TAG, "audin_winmm_parse_addin_args failed with error %"PRIu32"!", error); + goto error_out; + } + + if (!winmm->device_name) + { + winmm->device_name = _strdup("default"); + + if (!winmm->device_name) + { + WLog_ERR(TAG, "_strdup failed!"); + error = CHANNEL_RC_NO_MEMORY; + goto error_out; + } + } + + winmm->ppwfx_size = 10; + winmm->ppwfx = malloc(sizeof(PWAVEFORMATEX) * winmm->ppwfx_size); + + if (!winmm->ppwfx) + { + WLog_ERR(TAG, "malloc failed!"); + error = CHANNEL_RC_NO_MEMORY; + goto error_out; + } + + if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) winmm))) + { + WLog_ERR(TAG, "RegisterAudinDevice failed with error %"PRIu32"!", error); + goto error_out; + } + + return CHANNEL_RC_OK; +error_out: + free(winmm->ppwfx); + free(winmm->device_name); + free(winmm); + return error; +} diff --git a/channels/audin/server/audin.c b/channels/audin/server/audin.c index fc42fe1c3..3457774c2 100644 --- a/channels/audin/server/audin.c +++ b/channels/audin/server/audin.c @@ -339,10 +339,9 @@ static UINT audin_server_recv_data(audin_server* audin, wStream* s, AUDIO_FORMAT* format; int sbytes_per_sample; int sbytes_per_frame; - BYTE* src; - int size; int frames; - UINT success = CHANNEL_RC_OK; + wStream* out; + UINT success = ERROR_INTERNAL_ERROR; if (audin->context.selected_client_format < 0) { @@ -351,53 +350,26 @@ static UINT audin_server_recv_data(audin_server* audin, wStream* s, return ERROR_INVALID_DATA; } + out = Stream_New(NULL, 4096); + + if (!out) + return ERROR_OUTOFMEMORY; + format = &audin->context.client_formats[audin->context.selected_client_format]; - if (format->wFormatTag == WAVE_FORMAT_ADPCM) + if (freerdp_dsp_decode(audin->dsp_context, format, Stream_Pointer(s), length, out)) { - audin->dsp_context->decode_ms_adpcm(audin->dsp_context, - Stream_Pointer(s), length, format->nChannels, format->nBlockAlign); - size = audin->dsp_context->adpcm_size; - src = audin->dsp_context->adpcm_buffer; - sbytes_per_sample = 2; - sbytes_per_frame = format->nChannels * 2; - } - else if (format->wFormatTag == WAVE_FORMAT_DVI_ADPCM) - { - audin->dsp_context->decode_ima_adpcm(audin->dsp_context, - Stream_Pointer(s), length, format->nChannels, format->nBlockAlign); - size = audin->dsp_context->adpcm_size; - src = audin->dsp_context->adpcm_buffer; - sbytes_per_sample = 2; - sbytes_per_frame = format->nChannels * 2; - } - else - { - size = length; - src = Stream_Pointer(s); + Stream_SealLength(out); sbytes_per_sample = format->wBitsPerSample / 8; sbytes_per_frame = format->nChannels * sbytes_per_sample; + frames = Stream_Length(out) / sbytes_per_frame; + IFCALLRET(audin->context.ReceiveSamples, success, &audin->context, Stream_Buffer(out), frames); + + if (success) + WLog_ERR(TAG, "context.ReceiveSamples failed with error %"PRIu32"", success); } - if (format->nSamplesPerSec == audin->context.dst_format.nSamplesPerSec - && format->nChannels == audin->context.dst_format.nChannels) - { - frames = size / sbytes_per_frame; - } - else - { - audin->dsp_context->resample(audin->dsp_context, src, sbytes_per_sample, - format->nChannels, format->nSamplesPerSec, size / sbytes_per_frame, - audin->context.dst_format.nChannels, audin->context.dst_format.nSamplesPerSec); - frames = audin->dsp_context->resampled_frames; - src = audin->dsp_context->resampled_buffer; - } - - IFCALLRET(audin->context.ReceiveSamples, success, &audin->context, src, frames); - - if (success) - WLog_ERR(TAG, "context.ReceiveSamples failed with error %"PRIu32"", success); - + Stream_Free(out, TRUE); return success; } @@ -694,7 +666,7 @@ audin_server_context* audin_server_context_new(HANDLE vcm) audin->context.SelectFormat = audin_server_select_format; audin->context.Open = audin_server_open; audin->context.Close = audin_server_close; - audin->dsp_context = freerdp_dsp_context_new(); + audin->dsp_context = freerdp_dsp_context_new(FALSE); if (!audin->dsp_context) { diff --git a/channels/rdpsnd/client/CMakeLists.txt b/channels/rdpsnd/client/CMakeLists.txt index 6e166b2c5..65c3bb346 100644 --- a/channels/rdpsnd/client/CMakeLists.txt +++ b/channels/rdpsnd/client/CMakeLists.txt @@ -23,11 +23,8 @@ set(${MODULE_PREFIX}_SRCS add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntryEx") - - target_link_libraries(${MODULE_NAME} winpr freerdp ${CMAKE_THREAD_LIBS_INIT}) - set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") if(WITH_OSS) diff --git a/channels/rdpsnd/client/alsa/rdpsnd_alsa.c b/channels/rdpsnd/client/alsa/rdpsnd_alsa.c index 9ab422259..7ef65df05 100644 --- a/channels/rdpsnd/client/alsa/rdpsnd_alsa.c +++ b/channels/rdpsnd/client/alsa/rdpsnd_alsa.c @@ -47,22 +47,18 @@ struct rdpsnd_alsa_plugin { rdpsndDevicePlugin device; - int latency; - int wformat; - int block_size; + UINT32 latency; + AUDIO_FORMAT aformat; char* device_name; snd_pcm_t* pcm_handle; snd_mixer_t* mixer_handle; - UINT32 source_rate; + UINT32 actual_rate; - UINT32 wLocalTimeClose; snd_pcm_format_t format; - UINT32 source_channels; UINT32 actual_channels; - int bytes_per_channel; + snd_pcm_uframes_t buffer_size; snd_pcm_uframes_t period_size; - FREERDP_DSP_CONTEXT* dsp_context; }; #define SND_PCM_CHECK(_func, _status) \ @@ -77,33 +73,25 @@ static int rdpsnd_alsa_set_hw_params(rdpsndAlsaPlugin* alsa) int status; snd_pcm_hw_params_t* hw_params; snd_pcm_uframes_t buffer_size_max; - status = snd_pcm_hw_params_malloc(&hw_params); SND_PCM_CHECK("snd_pcm_hw_params_malloc", status); - status = snd_pcm_hw_params_any(alsa->pcm_handle, hw_params); SND_PCM_CHECK("snd_pcm_hw_params_any", status); - /* Set interleaved read/write access */ status = snd_pcm_hw_params_set_access(alsa->pcm_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); SND_PCM_CHECK("snd_pcm_hw_params_set_access", status); - /* Set sample format */ status = snd_pcm_hw_params_set_format(alsa->pcm_handle, hw_params, alsa->format); SND_PCM_CHECK("snd_pcm_hw_params_set_format", status); - /* Set sample rate */ status = snd_pcm_hw_params_set_rate_near(alsa->pcm_handle, hw_params, &alsa->actual_rate, NULL); SND_PCM_CHECK("snd_pcm_hw_params_set_rate_near", status); - /* Set number of channels */ status = snd_pcm_hw_params_set_channels(alsa->pcm_handle, hw_params, alsa->actual_channels); SND_PCM_CHECK("snd_pcm_hw_params_set_channels", status); - /* Get maximum buffer size */ status = snd_pcm_hw_params_get_buffer_size_max(hw_params, &buffer_size_max); SND_PCM_CHECK("snd_pcm_hw_params_get_buffer_size_max", status); - /** * ALSA Parameters * @@ -122,33 +110,28 @@ static int rdpsnd_alsa_set_hw_params(rdpsndAlsaPlugin* alsa) * Commonly this is (2 * period_size), but some hardware can do 8 periods per buffer. * It is also possible for the buffer size to not be an integer multiple of the period size. */ - int interrupts_per_sec_near = 50; - int bytes_per_sec = (alsa->actual_rate * alsa->bytes_per_channel * alsa->actual_channels); - + int bytes_per_sec = (alsa->actual_rate * alsa->aformat.wBitsPerSample / 8 * alsa->actual_channels); alsa->buffer_size = buffer_size_max; alsa->period_size = (bytes_per_sec / interrupts_per_sec_near); if (alsa->period_size > buffer_size_max) { WLog_ERR(TAG, "Warning: requested sound buffer size %lu, got %lu instead\n", - alsa->buffer_size, buffer_size_max); + alsa->buffer_size, buffer_size_max); alsa->period_size = (buffer_size_max / 8); } /* Set buffer size */ status = snd_pcm_hw_params_set_buffer_size_near(alsa->pcm_handle, hw_params, &alsa->buffer_size); SND_PCM_CHECK("snd_pcm_hw_params_set_buffer_size_near", status); - /* Set period size */ - status = snd_pcm_hw_params_set_period_size_near(alsa->pcm_handle, hw_params, &alsa->period_size, NULL); + status = snd_pcm_hw_params_set_period_size_near(alsa->pcm_handle, hw_params, &alsa->period_size, + NULL); SND_PCM_CHECK("snd_pcm_hw_params_set_period_size_near", status); - status = snd_pcm_hw_params(alsa->pcm_handle, hw_params); SND_PCM_CHECK("snd_pcm_hw_params", status); - snd_pcm_hw_params_free(hw_params); - return 0; } @@ -156,27 +139,20 @@ static int rdpsnd_alsa_set_sw_params(rdpsndAlsaPlugin* alsa) { int status; snd_pcm_sw_params_t* sw_params; - status = snd_pcm_sw_params_malloc(&sw_params); SND_PCM_CHECK("snd_pcm_sw_params_malloc", status); - status = snd_pcm_sw_params_current(alsa->pcm_handle, sw_params); SND_PCM_CHECK("snd_pcm_sw_params_current", status); - - status = snd_pcm_sw_params_set_avail_min(alsa->pcm_handle, sw_params, (alsa->bytes_per_channel * alsa->actual_channels)); + status = snd_pcm_sw_params_set_avail_min(alsa->pcm_handle, sw_params, + (alsa->aformat.nChannels * alsa->actual_channels)); SND_PCM_CHECK("snd_pcm_sw_params_set_avail_min", status); - - status = snd_pcm_sw_params_set_start_threshold(alsa->pcm_handle, sw_params, alsa->block_size); + status = snd_pcm_sw_params_set_start_threshold(alsa->pcm_handle, sw_params, alsa->aformat.nBlockAlign); SND_PCM_CHECK("snd_pcm_sw_params_set_start_threshold", status); - status = snd_pcm_sw_params(alsa->pcm_handle, sw_params); SND_PCM_CHECK("snd_pcm_sw_params", status); - snd_pcm_sw_params_free(sw_params); - status = snd_pcm_prepare(alsa->pcm_handle); SND_PCM_CHECK("snd_pcm_prepare", status); - return 0; } @@ -185,10 +161,8 @@ static int rdpsnd_alsa_validate_params(rdpsndAlsaPlugin* alsa) int status; snd_pcm_uframes_t buffer_size; snd_pcm_uframes_t period_size; - status = snd_pcm_get_params(alsa->pcm_handle, &buffer_size, &period_size); SND_PCM_CHECK("snd_pcm_get_params", status); - return 0; } @@ -205,15 +179,14 @@ static int rdpsnd_alsa_set_params(rdpsndAlsaPlugin* alsa) return rdpsnd_alsa_validate_params(alsa); } -static BOOL rdpsnd_alsa_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) +static BOOL rdpsnd_alsa_set_format(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, + UINT32 latency) { rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device; if (format) { - alsa->source_rate = format->nSamplesPerSec; alsa->actual_rate = format->nSamplesPerSec; - alsa->source_channels = format->nChannels; alsa->actual_channels = format->nChannels; switch (format->wFormatTag) @@ -223,29 +196,28 @@ static BOOL rdpsnd_alsa_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* for { case 8: alsa->format = SND_PCM_FORMAT_S8; - alsa->bytes_per_channel = 1; break; case 16: alsa->format = SND_PCM_FORMAT_S16_LE; - alsa->bytes_per_channel = 2; break; + + default: + return FALSE; } + break; - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - alsa->format = SND_PCM_FORMAT_S16_LE; - alsa->bytes_per_channel = 2; + case WAVE_FORMAT_ALAW: + case WAVE_FORMAT_MULAW: break; + + default: + return FALSE; } - - alsa->wformat = format->wFormatTag; - alsa->block_size = format->nBlockAlign; } alsa->latency = latency; - return (rdpsnd_alsa_set_params(alsa) == 0); } @@ -257,6 +229,7 @@ static BOOL rdpsnd_alsa_open_mixer(rdpsndAlsaPlugin* alsa) return TRUE; status = snd_mixer_open(&alsa->mixer_handle, 0); + if (status < 0) { WLog_ERR(TAG, "snd_mixer_open failed"); @@ -264,6 +237,7 @@ static BOOL rdpsnd_alsa_open_mixer(rdpsndAlsaPlugin* alsa) } status = snd_mixer_attach(alsa->mixer_handle, alsa->device_name); + if (status < 0) { WLog_ERR(TAG, "snd_mixer_attach failed"); @@ -272,6 +246,7 @@ static BOOL rdpsnd_alsa_open_mixer(rdpsndAlsaPlugin* alsa) } status = snd_mixer_selem_register(alsa->mixer_handle, NULL, NULL); + if (status < 0) { WLog_ERR(TAG, "snd_mixer_selem_register failed"); @@ -280,6 +255,7 @@ static BOOL rdpsnd_alsa_open_mixer(rdpsndAlsaPlugin* alsa) } status = snd_mixer_load(alsa->mixer_handle); + if (status < 0) { WLog_ERR(TAG, "snd_mixer_load failed"); @@ -290,7 +266,7 @@ static BOOL rdpsnd_alsa_open_mixer(rdpsndAlsaPlugin* alsa) return TRUE; } -static BOOL rdpsnd_alsa_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) +static BOOL rdpsnd_alsa_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, UINT32 latency) { int mode; int status; @@ -301,18 +277,16 @@ static BOOL rdpsnd_alsa_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, i mode = 0; /*mode |= SND_PCM_NONBLOCK;*/ - status = snd_pcm_open(&alsa->pcm_handle, alsa->device_name, SND_PCM_STREAM_PLAYBACK, mode); + if (status < 0) { WLog_ERR(TAG, "snd_pcm_open failed"); return FALSE; } - freerdp_dsp_context_reset_adpcm(alsa->dsp_context); - return rdpsnd_alsa_set_format(device, format, latency) && - rdpsnd_alsa_open_mixer(alsa); + rdpsnd_alsa_open_mixer(alsa); } static void rdpsnd_alsa_close(rdpsndDevicePlugin* device) @@ -329,9 +303,6 @@ static void rdpsnd_alsa_close(rdpsndDevicePlugin* device) if (status != 0) frames = 0; - - alsa->wLocalTimeClose = GetTickCount(); - alsa->wLocalTimeClose += (((frames * 1000) / alsa->actual_rate) / alsa->actual_channels); } static void rdpsnd_alsa_free(rdpsndDevicePlugin* device) @@ -352,40 +323,22 @@ static void rdpsnd_alsa_free(rdpsndDevicePlugin* device) } free(alsa->device_name); - - freerdp_dsp_context_free(alsa->dsp_context); - free(alsa); } -static BOOL rdpsnd_alsa_format_supported(rdpsndDevicePlugin* device, AUDIO_FORMAT* format) +static BOOL rdpsnd_alsa_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format) { switch (format->wFormatTag) { case WAVE_FORMAT_PCM: if (format->cbSize == 0 && - format->nSamplesPerSec <= 48000 && - (format->wBitsPerSample == 8 || format->wBitsPerSample == 16) && - (format->nChannels == 1 || format->nChannels == 2)) + format->nSamplesPerSec <= 48000 && + (format->wBitsPerSample == 8 || format->wBitsPerSample == 16) && + (format->nChannels == 1 || format->nChannels == 2)) { return TRUE; } - break; - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - if (format->nSamplesPerSec <= 48000 && - format->wBitsPerSample == 4 && - (format->nChannels == 1 || format->nChannels == 2)) - { - return TRUE; - } - break; - - case WAVE_FORMAT_ALAW: - case WAVE_FORMAT_MULAW: - case WAVE_FORMAT_GSM610: - default: break; } @@ -403,7 +356,6 @@ static UINT32 rdpsnd_alsa_get_volume(rdpsndDevicePlugin* device) UINT16 dwVolumeRight; snd_mixer_elem_t* elem; rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device; - dwVolumeLeft = ((50 * 0xFFFF) / 100); /* 50% */ dwVolumeRight = ((50 * 0xFFFF) / 100); /* 50% */ @@ -417,16 +369,13 @@ static UINT32 rdpsnd_alsa_get_volume(rdpsndDevicePlugin* device) snd_mixer_selem_get_playback_volume_range(elem, &volume_min, &volume_max); snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, &volume_left); snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, &volume_right); - - dwVolumeLeft = (UINT16) (((volume_left * 0xFFFF) - volume_min) / (volume_max - volume_min)); - dwVolumeRight = (UINT16) (((volume_right * 0xFFFF) - volume_min) / (volume_max - volume_min)); - + dwVolumeLeft = (UINT16)(((volume_left * 0xFFFF) - volume_min) / (volume_max - volume_min)); + dwVolumeRight = (UINT16)(((volume_right * 0xFFFF) - volume_min) / (volume_max - volume_min)); break; } } dwVolume = (dwVolumeLeft << 16) | dwVolumeRight; - return dwVolume; } @@ -442,11 +391,11 @@ static BOOL rdpsnd_alsa_set_volume(rdpsndDevicePlugin* device, UINT32 value) rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device; if (!alsa->mixer_handle && !rdpsnd_alsa_open_mixer(alsa)) - return FALSE; + return FALSE; left = (value & 0xFFFF); right = ((value >> 16) & 0xFFFF); - + for (elem = snd_mixer_first_elem(alsa->mixer_handle); elem; elem = snd_mixer_elem_next(elem)) { if (snd_mixer_selem_has_playback_volume(elem)) @@ -454,8 +403,9 @@ static BOOL rdpsnd_alsa_set_volume(rdpsndDevicePlugin* device, UINT32 value) snd_mixer_selem_get_playback_volume_range(elem, &volume_min, &volume_max); volume_left = volume_min + (left * (volume_max - volume_min)) / 0xFFFF; volume_right = volume_min + (right * (volume_max - volume_min)) / 0xFFFF; + if ((snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, volume_left) < 0) || - (snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, volume_right) < 0)) + (snd_mixer_selem_set_playback_volume(elem, SND_MIXER_SCHN_FRONT_RIGHT, volume_right) < 0)) { WLog_ERR(TAG, "error setting the volume\n"); return FALSE; @@ -466,108 +416,18 @@ static BOOL rdpsnd_alsa_set_volume(rdpsndDevicePlugin* device, UINT32 value) return TRUE; } -static BYTE* rdpsnd_alsa_process_audio_sample(rdpsndDevicePlugin* device, BYTE* data, int* size) +static UINT rdpsnd_alsa_play(rdpsndDevicePlugin* device, const BYTE* data, size_t size) { - int frames; - BYTE* srcData; - int srcFrameSize; - int dstFrameSize; - rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device; - - if (alsa->wformat == WAVE_FORMAT_ADPCM) - { - alsa->dsp_context->decode_ms_adpcm(alsa->dsp_context, - data, *size, alsa->source_channels, alsa->block_size); - - *size = alsa->dsp_context->adpcm_size; - srcData = alsa->dsp_context->adpcm_buffer; - } - else if (alsa->wformat == WAVE_FORMAT_DVI_ADPCM) - { - alsa->dsp_context->decode_ima_adpcm(alsa->dsp_context, - data, *size, alsa->source_channels, alsa->block_size); - - *size = alsa->dsp_context->adpcm_size; - srcData = alsa->dsp_context->adpcm_buffer; - } - else - { - srcData = data; - } - - srcFrameSize = alsa->source_channels * alsa->bytes_per_channel; - dstFrameSize = alsa->actual_channels * alsa->bytes_per_channel; - - if ((*size % srcFrameSize) != 0) - return NULL; - - if (!((alsa->source_rate == alsa->actual_rate) && (alsa->source_channels == alsa->actual_channels))) - { - alsa->dsp_context->resample(alsa->dsp_context, srcData, alsa->bytes_per_channel, - alsa->source_channels, alsa->source_rate, *size / srcFrameSize, - alsa->actual_channels, alsa->actual_rate); - - frames = alsa->dsp_context->resampled_frames; - - *size = frames * dstFrameSize; - srcData = alsa->dsp_context->resampled_buffer; - } - - data = srcData; - - return data; -} - -static BOOL rdpsnd_alsa_wave_decode(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) -{ - int size; - BYTE* data; - - size = wave->length; - data = rdpsnd_alsa_process_audio_sample(device, wave->data, &size); - - wave->data = (BYTE*) malloc(size); - if (!wave->data) - return FALSE; - CopyMemory(wave->data, data, size); - wave->length = size; - - return TRUE; -} - -static void rdpsnd_alsa_wave_play(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) -{ - BYTE* data; - int offset; - int length; - int status; + size_t offset; int frame_size; - UINT32 wCurrentTime; - snd_htimestamp_t tstamp; - snd_pcm_uframes_t frames; rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device; - offset = 0; - data = wave->data; - length = wave->length; - frame_size = alsa->actual_channels * alsa->bytes_per_channel; + frame_size = alsa->actual_channels * alsa->aformat.wBitsPerSample / 8; - if (alsa->wLocalTimeClose) + while (offset < size) { - wCurrentTime = GetTickCount(); - - if (snd_pcm_htimestamp(alsa->pcm_handle, &frames, &tstamp) == -EPIPE) - { - if (wCurrentTime > alsa->wLocalTimeClose) - snd_pcm_recover(alsa->pcm_handle, -EPIPE, 1); - } - - alsa->wLocalTimeClose = 0; - } - - while (offset < length) - { - status = snd_pcm_writei(alsa->pcm_handle, &data[offset], (length - offset) / frame_size); + snd_pcm_sframes_t status = snd_pcm_writei(alsa->pcm_handle, &data[offset], + (size - offset) / frame_size); if (status == -EPIPE) { @@ -590,11 +450,7 @@ static void rdpsnd_alsa_wave_play(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) offset += status * frame_size; } - free(data); - - /* From rdpsnd_main.c */ - wave->wTimeStampB = wave->wTimeStampA + wave->wAudioLength + 65; - wave->wLocalTimeB = wave->wLocalTimeA + wave->wAudioLength + 65; + return 10; /* TODO: Get real latency in [ms] */ } static COMMAND_LINE_ARGUMENT_A rdpsnd_alsa_args[] = @@ -614,10 +470,10 @@ static UINT rdpsnd_alsa_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* DWORD flags; COMMAND_LINE_ARGUMENT_A* arg; rdpsndAlsaPlugin* alsa = (rdpsndAlsaPlugin*) device; - flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; + status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv, rdpsnd_alsa_args, flags, + alsa, NULL, NULL); - status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv, rdpsnd_alsa_args, flags, alsa, NULL, NULL); if (status < 0) { WLog_ERR(TAG, "CommandLineParseArgumentsA failed!"); @@ -632,14 +488,13 @@ static UINT rdpsnd_alsa_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* continue; CommandLineSwitchStart(arg) - CommandLineSwitchCase(arg, "dev") { alsa->device_name = _strdup(arg->Value); + if (!alsa->device_name) return CHANNEL_RC_NO_MEMORY; } - CommandLineSwitchEnd(arg) } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); @@ -663,8 +518,8 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p ADDIN_ARGV* args; rdpsndAlsaPlugin* alsa; UINT error; - alsa = (rdpsndAlsaPlugin*) calloc(1, sizeof(rdpsndAlsaPlugin)); + if (!alsa) { WLog_ERR(TAG, "calloc failed!"); @@ -673,28 +528,26 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p alsa->device.Open = rdpsnd_alsa_open; alsa->device.FormatSupported = rdpsnd_alsa_format_supported; - alsa->device.SetFormat = rdpsnd_alsa_set_format; alsa->device.GetVolume = rdpsnd_alsa_get_volume; alsa->device.SetVolume = rdpsnd_alsa_set_volume; - alsa->device.WaveDecode = rdpsnd_alsa_wave_decode; - alsa->device.WavePlay = rdpsnd_alsa_wave_play; + alsa->device.Play = rdpsnd_alsa_play; alsa->device.Close = rdpsnd_alsa_close; alsa->device.Free = rdpsnd_alsa_free; - args = pEntryPoints->args; + if (args->argc > 1) { - if ((error = rdpsnd_alsa_parse_addin_args((rdpsndDevicePlugin *) alsa, args))) + if ((error = rdpsnd_alsa_parse_addin_args((rdpsndDevicePlugin*) alsa, args))) { WLog_ERR(TAG, "rdpsnd_alsa_parse_addin_args failed with error %"PRIu32"", error); goto error_parse_args; } } - if (!alsa->device_name) { alsa->device_name = _strdup("default"); + if (!alsa->device_name) { WLog_ERR(TAG, "_strdup failed!"); @@ -704,27 +557,11 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p } alsa->pcm_handle = 0; - alsa->source_rate = 22050; alsa->actual_rate = 22050; alsa->format = SND_PCM_FORMAT_S16_LE; - alsa->source_channels = 2; alsa->actual_channels = 2; - alsa->bytes_per_channel = 2; - - alsa->dsp_context = freerdp_dsp_context_new(); - if (!alsa->dsp_context) - { - WLog_ERR(TAG, "freerdp_dsp_context_new failed!"); - error = CHANNEL_RC_NO_MEMORY; - goto error_dsp_context; - } - pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*) alsa); - return CHANNEL_RC_OK; - -error_dsp_context: - freerdp_dsp_context_free(alsa->dsp_context); error_strdup: free(alsa->device_name); error_parse_args: diff --git a/channels/rdpsnd/client/ios/rdpsnd_ios.c b/channels/rdpsnd/client/ios/rdpsnd_ios.c index 6108defd2..bed2e9208 100644 --- a/channels/rdpsnd/client/ios/rdpsnd_ios.c +++ b/channels/rdpsnd/client/ios/rdpsnd_ios.c @@ -144,17 +144,17 @@ static void rdpsnd_ios_stop(rdpsndDevicePlugin* __unused device) } } -static void rdpsnd_ios_play(rdpsndDevicePlugin* device, BYTE* data, int size) +static UINT rdpsnd_ios_play(rdpsndDevicePlugin* device, BYTE* data, int size) { rdpsndIOSPlugin *p = THIS(device); const BOOL ok = TPCircularBufferProduceBytes(&p->buffer, data, size); if (!ok) - { - return; - } + return 0; rdpsnd_ios_start(device); + + return 10; /* TODO: Get real latencry in [ms] */ } static BOOL rdpsnd_ios_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int __unused latency) diff --git a/channels/rdpsnd/client/mac/rdpsnd_mac.c b/channels/rdpsnd/client/mac/rdpsnd_mac.c index 93e448f78..7cc599e7d 100644 --- a/channels/rdpsnd/client/mac/rdpsnd_mac.c +++ b/channels/rdpsnd/client/mac/rdpsnd_mac.c @@ -32,7 +32,6 @@ #include #include -#include #define __COREFOUNDATION_CFPLUGINCOM__ 1 #define IUNKNOWN_C_GUTS void *_reserved; void* QueryInterface; void* AddRef; void* Release @@ -51,41 +50,36 @@ struct rdpsnd_mac_plugin BOOL isOpen; BOOL isPlaying; - + UINT32 latency; AUDIO_FORMAT format; size_t lastAudioBufferIndex; size_t audioBufferIndex; - + AudioQueueRef audioQueue; AudioStreamBasicDescription audioFormat; AudioQueueBufferRef audioBuffers[MAC_AUDIO_QUEUE_NUM_BUFFERS]; - - Float64 lastStartTime; - - int wformat; - int block_size; - FREERDP_DSP_CONTEXT* dsp_context; }; typedef struct rdpsnd_mac_plugin rdpsndMacPlugin; -static void mac_audio_queue_output_cb(void* inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) +static void mac_audio_queue_output_cb(void* inUserData, AudioQueueRef inAQ, + AudioQueueBufferRef inBuffer) { rdpsndMacPlugin* mac = (rdpsndMacPlugin*)inUserData; - if (inBuffer == mac->audioBuffers[mac->lastAudioBufferIndex]) { + if (inBuffer == mac->audioBuffers[mac->lastAudioBufferIndex]) + { AudioQueuePause(mac->audioQueue); mac->isPlaying = FALSE; } } -static BOOL rdpsnd_mac_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) +static BOOL rdpsnd_mac_set_format(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, + UINT32 latency) { rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device; - mac->latency = (UINT32) latency; CopyMemory(&(mac->format), format, sizeof(AUDIO_FORMAT)); - mac->audioFormat.mSampleRate = format->nSamplesPerSec; mac->audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; mac->audioFormat.mFramesPerPacket = 1; @@ -94,101 +88,78 @@ static BOOL rdpsnd_mac_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* form mac->audioFormat.mBytesPerFrame = (format->wBitsPerSample * format->nChannels) / 8; mac->audioFormat.mBytesPerPacket = format->nBlockAlign; mac->audioFormat.mReserved = 0; - + switch (format->wFormatTag) { case WAVE_FORMAT_ALAW: mac->audioFormat.mFormatID = kAudioFormatALaw; break; - + case WAVE_FORMAT_MULAW: mac->audioFormat.mFormatID = kAudioFormatULaw; break; - + case WAVE_FORMAT_PCM: mac->audioFormat.mFormatID = kAudioFormatLinearPCM; break; - - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - mac->audioFormat.mFormatID = kAudioFormatLinearPCM; - mac->audioFormat.mBitsPerChannel = 16; - mac->audioFormat.mBytesPerFrame = (16 * format->nChannels) / 8; - mac->audioFormat.mBytesPerPacket = mac->audioFormat.mFramesPerPacket * mac->audioFormat.mBytesPerFrame; - break; - - case WAVE_FORMAT_GSM610: - mac->audioFormat.mFormatID = kAudioFormatMicrosoftGSM; - break; - + default: break; } - - mac->wformat = format->wFormatTag; - mac->block_size = format->nBlockAlign; - + rdpsnd_print_audio_format(format); return TRUE; } -static BOOL rdpsnd_mac_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) +static BOOL rdpsnd_mac_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, UINT32 latency) { int index; OSStatus status; - rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device; - + if (mac->isOpen) return TRUE; - + mac->audioBufferIndex = 0; - - if (!device->SetFormat(device, format, 0)) - { - WLog_ERR(TAG, "SetFormat failure\n"); + + if (!rdpsnd_mac_set_format(device, format, latency)) return FALSE; - } - - freerdp_dsp_context_reset_adpcm(mac->dsp_context); status = AudioQueueNewOutput(&(mac->audioFormat), - mac_audio_queue_output_cb, mac, - NULL, NULL, 0, &(mac->audioQueue)); - + mac_audio_queue_output_cb, mac, + NULL, NULL, 0, &(mac->audioQueue)); + if (status != 0) { WLog_ERR(TAG, "AudioQueueNewOutput failure\n"); return FALSE; } - + UInt32 DecodeBufferSizeFrames; UInt32 propertySize = sizeof(DecodeBufferSizeFrames); - status = AudioQueueGetProperty(mac->audioQueue, - kAudioQueueProperty_DecodeBufferSizeFrames, - &DecodeBufferSizeFrames, - &propertySize); - + kAudioQueueProperty_DecodeBufferSizeFrames, + &DecodeBufferSizeFrames, + &propertySize); + if (status != 0) { WLog_DBG(TAG, "AudioQueueGetProperty failure: kAudioQueueProperty_DecodeBufferSizeFrames\n"); return FALSE; } - + for (index = 0; index < MAC_AUDIO_QUEUE_NUM_BUFFERS; index++) { - status = AudioQueueAllocateBuffer(mac->audioQueue, MAC_AUDIO_QUEUE_BUFFER_SIZE, &mac->audioBuffers[index]); - + status = AudioQueueAllocateBuffer(mac->audioQueue, MAC_AUDIO_QUEUE_BUFFER_SIZE, + &mac->audioBuffers[index]); + if (status != 0) { WLog_ERR(TAG, "AudioQueueAllocateBuffer failed\n"); return FALSE; } } - - mac->lastStartTime = 0; - + mac->isOpen = TRUE; return TRUE; } @@ -196,14 +167,13 @@ static BOOL rdpsnd_mac_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in static void rdpsnd_mac_close(rdpsndDevicePlugin* device) { rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device; - + if (mac->isOpen) { size_t index; mac->isOpen = FALSE; - AudioQueueStop(mac->audioQueue, true); - + for (index = 0; index < MAC_AUDIO_QUEUE_NUM_BUFFERS; index++) { AudioQueueFreeBuffer(mac->audioQueue, mac->audioBuffers[index]); @@ -211,7 +181,6 @@ static void rdpsnd_mac_close(rdpsndDevicePlugin* device) AudioQueueDispose(mac->audioQueue, true); mac->audioQueue = NULL; - mac->isPlaying = FALSE; } } @@ -219,28 +188,24 @@ static void rdpsnd_mac_close(rdpsndDevicePlugin* device) static void rdpsnd_mac_free(rdpsndDevicePlugin* device) { rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device; - device->Close(device); - - freerdp_dsp_context_free(mac->dsp_context); - free(mac); } -static BOOL rdpsnd_mac_format_supported(rdpsndDevicePlugin* device, AUDIO_FORMAT* format) +static BOOL rdpsnd_mac_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format) { switch (format->wFormatTag) { case WAVE_FORMAT_PCM: case WAVE_FORMAT_ALAW: case WAVE_FORMAT_MULAW: - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - return TRUE; case WAVE_FORMAT_GSM610: + return TRUE; + + default: return FALSE; } - + return FALSE; } @@ -251,17 +216,15 @@ static BOOL rdpsnd_mac_set_volume(rdpsndDevicePlugin* device, UINT32 value) UINT16 volumeLeft; UINT16 volumeRight; rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device; - + if (!mac->audioQueue) return FALSE; - + volumeLeft = (value & 0xFFFF); volumeRight = ((value >> 16) & 0xFFFF); - fVolume = ((float) volumeLeft) / 65535.0; - status = AudioQueueSetParameter(mac->audioQueue, kAudioQueueParam_Volume, fVolume); - + if (status != 0) { WLog_ERR(TAG, "AudioQueueSetParameter kAudioQueueParam_Volume failed: %f\n", fVolume); @@ -274,87 +237,51 @@ static BOOL rdpsnd_mac_set_volume(rdpsndDevicePlugin* device, UINT32 value) static void rdpsnd_mac_start(rdpsndDevicePlugin* device) { rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device; - + if (!mac->isPlaying) { OSStatus status; - + if (!mac->audioQueue) return; - + status = AudioQueueStart(mac->audioQueue, NULL); - + if (status != 0) { WLog_ERR(TAG, "AudioQueueStart failed\n"); } - + mac->isPlaying = TRUE; } } -static BOOL rdpsnd_mac_wave_decode(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) +static UINT rdpsnd_mac_play(rdpsndDevicePlugin* device, const BYTE* data, size_t size) { - int length; - BYTE* data; - rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device; - - if (mac->wformat == WAVE_FORMAT_ADPCM) - { - mac->dsp_context->decode_ms_adpcm(mac->dsp_context, wave->data, wave->length, mac->format.nChannels, mac->block_size); - length = mac->dsp_context->adpcm_size; - data = mac->dsp_context->adpcm_buffer; - } - else if (mac->wformat == WAVE_FORMAT_DVI_ADPCM) - { - mac->dsp_context->decode_ima_adpcm(mac->dsp_context, wave->data, wave->length, mac->format.nChannels, mac->block_size); - length = mac->dsp_context->adpcm_size; - data = mac->dsp_context->adpcm_buffer; - } - else - { - length = wave->length; - data = wave->data; - } - - wave->data = (BYTE*) malloc(length); - CopyMemory(wave->data, data, length); - wave->length = length; - - return TRUE; -} - -static void rdpsnd_mac_waveplay(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) -{ - int length; + size_t length; AudioQueueBufferRef audioBuffer; AudioTimeStamp outActualStartTime; rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device; - + if (!mac->isOpen) - return; + return 0; audioBuffer = mac->audioBuffers[mac->audioBufferIndex]; - - length = wave->length > audioBuffer->mAudioDataBytesCapacity ? audioBuffer->mAudioDataBytesCapacity : wave->length; - - CopyMemory(audioBuffer->mAudioData, wave->data, length); - free(wave->data); - wave->data = NULL; + + length = size > audioBuffer->mAudioDataBytesCapacity ? audioBuffer->mAudioDataBytesCapacity : size; + + CopyMemory(audioBuffer->mAudioData, data, length); audioBuffer->mAudioDataByteSize = length; - audioBuffer->mUserData = wave; - + audioBuffer->mUserData = mac; + AudioQueueEnqueueBufferWithParameters(mac->audioQueue, audioBuffer, 0, 0, 0, 0, 0, NULL, NULL, &outActualStartTime); - UInt64 startTimeDelta = (outActualStartTime.mSampleTime - mac->lastStartTime) / 100.0; - wave->wLocalTimeB = wave->wLocalTimeA + startTimeDelta + wave->wAudioLength; - wave->wTimeStampB = wave->wTimeStampA + wave->wLocalTimeB - wave->wLocalTimeA; - mac->lastStartTime = outActualStartTime.mSampleTime; - + mac->lastAudioBufferIndex = mac->audioBufferIndex; mac->audioBufferIndex++; mac->audioBufferIndex %= MAC_AUDIO_QUEUE_NUM_BUFFERS; - - device->Start(device); + + rdpsnd_mac_start(device); + return 10; /* TODO: Get real latencry in [ms] */ } #ifdef BUILTIN_CHANNELS @@ -371,25 +298,17 @@ static void rdpsnd_mac_waveplay(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pEntryPoints) { rdpsndMacPlugin* mac; - mac = (rdpsndMacPlugin*) calloc(1, sizeof(rdpsndMacPlugin)); - + if (!mac) return CHANNEL_RC_NO_MEMORY; - + mac->device.Open = rdpsnd_mac_open; mac->device.FormatSupported = rdpsnd_mac_format_supported; - mac->device.SetFormat = rdpsnd_mac_set_format; mac->device.SetVolume = rdpsnd_mac_set_volume; - mac->device.WaveDecode = rdpsnd_mac_wave_decode; - mac->device.WavePlay = rdpsnd_mac_waveplay; - mac->device.Start = rdpsnd_mac_start; + mac->device.Play = rdpsnd_mac_play; mac->device.Close = rdpsnd_mac_close; mac->device.Free = rdpsnd_mac_free; - - mac->dsp_context = freerdp_dsp_context_new(); - pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*) mac); - return CHANNEL_RC_OK; } diff --git a/channels/rdpsnd/client/opensles/rdpsnd_opensles.c b/channels/rdpsnd/client/opensles/rdpsnd_opensles.c index 234685523..4f82a3aa9 100644 --- a/channels/rdpsnd/client/opensles/rdpsnd_opensles.c +++ b/channels/rdpsnd/client/opensles/rdpsnd_opensles.c @@ -36,7 +36,6 @@ #include #include -#include #include #include "opensl_io.h" @@ -48,7 +47,7 @@ struct rdpsnd_opensles_plugin { rdpsndDevicePlugin device; - int latency; + UINT32 latency; int wformat; int block_size; char* device_name; @@ -60,7 +59,6 @@ struct rdpsnd_opensles_plugin UINT32 rate; UINT32 channels; int format; - FREERDP_DSP_CONTEXT* dsp_context; }; static int rdpsnd_opensles_volume_to_millibel(unsigned short level, int max) @@ -91,9 +89,6 @@ static bool rdpsnd_opensles_check_handle(const rdpsndopenslesPlugin* hdl) rc = false; else { - if (!hdl->dsp_context) - rc = false; - if (!hdl->stream) rc = false; } @@ -120,11 +115,11 @@ static int rdpsnd_opensles_set_params(rdpsndopenslesPlugin* opensles) } static BOOL rdpsnd_opensles_set_format(rdpsndDevicePlugin* device, - AUDIO_FORMAT* format, int latency) + const AUDIO_FORMAT* format, UINT32 latency) { rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device; rdpsnd_opensles_check_handle(opensles); - DEBUG_SND("opensles=%p format=%p, latency=%d", (void*) opensles, (void*) format, latency); + DEBUG_SND("opensles=%p format=%p, latency=%"PRIu32, (void*) opensles, (void*) format, latency); if (format) { @@ -143,11 +138,11 @@ static BOOL rdpsnd_opensles_set_format(rdpsndDevicePlugin* device, } static BOOL rdpsnd_opensles_open(rdpsndDevicePlugin* device, - AUDIO_FORMAT* format, int latency) + const AUDIO_FORMAT* format, UINT32 latency) { rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device; - DEBUG_SND("opensles=%p format=%p, latency=%d, rate=%"PRIu32"", - (void*) opensles, (void*) format, latency, opensles->rate); + DEBUG_SND("opensles=%p format=%p, latency=%"PRIu32", rate=%"PRIu32"", + (void*) opensles, (void*) format, latency, opensles->rate); if (rdpsnd_opensles_check_handle(opensles)) return TRUE; @@ -161,8 +156,7 @@ static BOOL rdpsnd_opensles_open(rdpsndDevicePlugin* device, else rdpsnd_opensles_set_volume(device, opensles->volume); - rdpsnd_opensles_set_format(device, format, latency); - return TRUE; + return rdpsnd_opensles_set_format(device, format, latency); } static void rdpsnd_opensles_close(rdpsndDevicePlugin* device) @@ -184,13 +178,11 @@ static void rdpsnd_opensles_free(rdpsndDevicePlugin* device) assert(opensles); assert(opensles->device_name); free(opensles->device_name); - assert(opensles->dsp_context); - freerdp_dsp_context_free(opensles->dsp_context); free(opensles); } static BOOL rdpsnd_opensles_format_supported(rdpsndDevicePlugin* device, - AUDIO_FORMAT* format) + const AUDIO_FORMAT* format) { DEBUG_SND("format=%"PRIu16", cbsize=%"PRIu16", samples=%"PRIu32", bits=%"PRIu16", channels=%"PRIu16", align=%"PRIu16"", format->wFormatTag, format->cbSize, format->nSamplesPerSec, @@ -211,20 +203,6 @@ static BOOL rdpsnd_opensles_format_supported(rdpsndDevicePlugin* device, break; - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - if (format->nSamplesPerSec <= 48000 && - format->wBitsPerSample == 4 && - (format->nChannels == 1 || format->nChannels == 2)) - { - return TRUE; - } - - break; - - case WAVE_FORMAT_ALAW: - case WAVE_FORMAT_MULAW: - case WAVE_FORMAT_GSM610: default: break; } @@ -283,46 +261,22 @@ static BOOL rdpsnd_opensles_set_volume(rdpsndDevicePlugin* device, return TRUE; } -static void rdpsnd_opensles_play(rdpsndDevicePlugin* device, - BYTE* data, int size) +static UINT rdpsnd_opensles_play(rdpsndDevicePlugin* device, + const BYTE* data, size_t size) { union { - BYTE* b; - short* s; + const BYTE* b; + const short* s; } src; int ret; rdpsndopenslesPlugin* opensles = (rdpsndopenslesPlugin*) device; DEBUG_SND("opensles=%p, data=%p, size=%d", (void*) opensles, (void*) data, size); if (!rdpsnd_opensles_check_handle(opensles)) - return; - - if (opensles->format == WAVE_FORMAT_ADPCM) - { - DEBUG_SND("dsp_context=%p, channels=%"PRIu32", block_size=%d", - (void*) opensles->dsp_context, opensles->channels, opensles->block_size); - - opensles->dsp_context->decode_ms_adpcm(opensles->dsp_context, - data, size, opensles->channels, opensles->block_size); - size = opensles->dsp_context->adpcm_size; - src.b = opensles->dsp_context->adpcm_buffer; - } - else if (opensles->format == WAVE_FORMAT_DVI_ADPCM) - { - DEBUG_SND("dsp_context=%p, channels=%"PRIu32", block_size=%d", - (void*) opensles->dsp_context, opensles->channels, opensles->block_size); - - opensles->dsp_context->decode_ima_adpcm(opensles->dsp_context, - data, size, opensles->channels, opensles->block_size); - size = opensles->dsp_context->adpcm_size; - src.b = opensles->dsp_context->adpcm_buffer; - } - else - { - src.b = data; - } + return 0; + src.b = data; DEBUG_SND("size=%d, src=%p", size, (void*) src.b); assert(0 == size % 2); assert(size > 0); @@ -331,6 +285,8 @@ static void rdpsnd_opensles_play(rdpsndDevicePlugin* device, if (ret < 0) WLog_ERR(TAG, "android_AudioOut failed (%d)", ret); + + return 10; /* TODO: Get real latencry in [ms] */ } static void rdpsnd_opensles_start(rdpsndDevicePlugin* device) @@ -416,7 +372,6 @@ UINT freerdp_rdpsnd_client_subsystem_entry( opensles->device.Open = rdpsnd_opensles_open; opensles->device.FormatSupported = rdpsnd_opensles_format_supported; - opensles->device.SetFormat = rdpsnd_opensles_set_format; opensles->device.GetVolume = rdpsnd_opensles_get_volume; opensles->device.SetVolume = rdpsnd_opensles_set_volume; opensles->device.Start = rdpsnd_opensles_start; @@ -440,20 +395,10 @@ UINT freerdp_rdpsnd_client_subsystem_entry( opensles->rate = 44100; opensles->channels = 2; opensles->format = WAVE_FORMAT_ADPCM; - opensles->dsp_context = freerdp_dsp_context_new(); - - if (!opensles->dsp_context) - { - error = CHANNEL_RC_NO_MEMORY; - goto out_dsp_new; - } - pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*) opensles); DEBUG_SND("success"); return CHANNEL_RC_OK; -out_dsp_new: - free(opensles->device_name); outstrdup: free(opensles); return error; diff --git a/channels/rdpsnd/client/oss/rdpsnd_oss.c b/channels/rdpsnd/client/oss/rdpsnd_oss.c index 9a9d10373..d43e42c02 100644 --- a/channels/rdpsnd/client/oss/rdpsnd_oss.c +++ b/channels/rdpsnd/client/oss/rdpsnd_oss.c @@ -47,7 +47,6 @@ #include #include -#include #include #include "rdpsnd_main.h" @@ -64,10 +63,8 @@ struct rdpsnd_oss_plugin int supported_formats; - int latency; + UINT32 latency; AUDIO_FORMAT format; - - FREERDP_DSP_CONTEXT* dsp_context; }; #define OSS_LOG_ERR(_text, _error) \ @@ -77,7 +74,7 @@ struct rdpsnd_oss_plugin } -static int rdpsnd_oss_get_format(AUDIO_FORMAT* format) +static int rdpsnd_oss_get_format(const AUDIO_FORMAT* format) { switch (format->wFormatTag) { @@ -95,21 +92,15 @@ static int rdpsnd_oss_get_format(AUDIO_FORMAT* format) case WAVE_FORMAT_ALAW: return AFMT_A_LAW; -#if 0 /* This does not work on my desktop. */ case WAVE_FORMAT_MULAW: return AFMT_MU_LAW; -#endif - - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - return AFMT_S16_LE; } return 0; } -static BOOL rdpsnd_oss_format_supported(rdpsndDevicePlugin* device, AUDIO_FORMAT* format) +static BOOL rdpsnd_oss_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format) { int req_fmt = 0; rdpsndOssPlugin* oss = (rdpsndOssPlugin*)device; @@ -128,14 +119,12 @@ static BOOL rdpsnd_oss_format_supported(rdpsndDevicePlugin* device, AUDIO_FORMAT break; - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - if (format->nSamplesPerSec > 48000 || - format->wBitsPerSample != 4 || - (format->nChannels != 1 && format->nChannels != 2)) - return FALSE; - + case WAVE_FORMAT_MULAW: + case WAVE_FORMAT_ALAW: break; + + default: + return FALSE; } req_fmt = rdpsnd_oss_get_format(format); @@ -155,7 +144,8 @@ static BOOL rdpsnd_oss_format_supported(rdpsndDevicePlugin* device, AUDIO_FORMAT return TRUE; } -static BOOL rdpsnd_oss_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) +static BOOL rdpsnd_oss_set_format(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, + UINT32 latency) { int tmp; rdpsndOssPlugin* oss = (rdpsndOssPlugin*)device; @@ -227,7 +217,7 @@ static void rdpsnd_oss_open_mixer(rdpsndOssPlugin* oss) } } -static BOOL rdpsnd_oss_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) +static BOOL rdpsnd_oss_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, UINT32 latency) { char dev_name[PATH_MAX] = "/dev/dsp"; rdpsndOssPlugin* oss = (rdpsndOssPlugin*)device; @@ -272,7 +262,6 @@ static BOOL rdpsnd_oss_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in return FALSE; } - freerdp_dsp_context_reset_adpcm(oss->dsp_context); rdpsnd_oss_set_format(device, format, latency); rdpsnd_oss_open_mixer(oss); return TRUE; @@ -308,7 +297,6 @@ static void rdpsnd_oss_free(rdpsndDevicePlugin* device) return; rdpsnd_oss_close(device); - freerdp_dsp_context_free(oss->dsp_context); free(oss); } @@ -370,68 +358,36 @@ static BOOL rdpsnd_oss_set_volume(rdpsndDevicePlugin* device, UINT32 value) return TRUE; } -static BOOL rdpsnd_oss_wave_decode(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) +static UINT rdpsnd_oss_play(rdpsndDevicePlugin* device, const BYTE* data, size_t size) { rdpsndOssPlugin* oss = (rdpsndOssPlugin*)device; - if (device == NULL || wave == NULL) - return FALSE; + if (device == NULL || oss->mixer_handle == -1) + return 0; - switch (oss->format.wFormatTag) + while (size > 0) { - case WAVE_FORMAT_ADPCM: - oss->dsp_context->decode_ms_adpcm(oss->dsp_context, - wave->data, wave->length, oss->format.nChannels, oss->format.nBlockAlign); - wave->length = oss->dsp_context->adpcm_size; - wave->data = oss->dsp_context->adpcm_buffer; - break; - - case WAVE_FORMAT_DVI_ADPCM: - oss->dsp_context->decode_ima_adpcm(oss->dsp_context, - wave->data, wave->length, oss->format.nChannels, oss->format.nBlockAlign); - wave->length = oss->dsp_context->adpcm_size; - wave->data = oss->dsp_context->adpcm_buffer; - break; - } - - return TRUE; -} - -static void rdpsnd_oss_wave_play(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) -{ - BYTE* data; - int offset, size, status, latency; - rdpsndOssPlugin* oss = (rdpsndOssPlugin*)device; - - if (device == NULL || wave == NULL) - return; - - offset = 0; - data = wave->data; - size = wave->length; - latency = oss->latency; - - while (offset < size) - { - status = write(oss->pcm_handle, &data[offset], (size - offset)); + ssize_t status = write(oss->pcm_handle, data, size); if (status < 0) { OSS_LOG_ERR("write fail", errno); rdpsnd_oss_close(device); - rdpsnd_oss_open(device, NULL, latency); + rdpsnd_oss_open(device, NULL, oss->latency); break; } - offset += status; + data += status; + + if (status <= size) + size -= status; + else + size = 0; } - /* From rdpsnd_main.c */ - wave->wTimeStampB = wave->wTimeStampA + wave->wAudioLength + 65 + latency; - wave->wLocalTimeB = wave->wLocalTimeA + wave->wAudioLength + 65 + latency; + return 10; /* TODO: Get real latency in [ms] */ } - static COMMAND_LINE_ARGUMENT_A rdpsnd_oss_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "device" }, @@ -514,11 +470,9 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p oss->device.Open = rdpsnd_oss_open; oss->device.FormatSupported = rdpsnd_oss_format_supported; - oss->device.SetFormat = rdpsnd_oss_set_format; oss->device.GetVolume = rdpsnd_oss_get_volume; oss->device.SetVolume = rdpsnd_oss_set_volume; - oss->device.WaveDecode = rdpsnd_oss_wave_decode; - oss->device.WavePlay = rdpsnd_oss_wave_play; + oss->device.Play = rdpsnd_oss_play; oss->device.Close = rdpsnd_oss_close; oss->device.Free = rdpsnd_oss_free; oss->pcm_handle = -1; @@ -526,14 +480,6 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p oss->dev_unit = -1; args = pEntryPoints->args; rdpsnd_oss_parse_addin_args((rdpsndDevicePlugin*)oss, args); - oss->dsp_context = freerdp_dsp_context_new(); - - if (!oss->dsp_context) - { - free(oss); - return CHANNEL_RC_NO_MEMORY; - } - pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*)oss); return CHANNEL_RC_OK; } diff --git a/channels/rdpsnd/client/pulse/CMakeLists.txt b/channels/rdpsnd/client/pulse/CMakeLists.txt index 6160ec23d..3a5744819 100644 --- a/channels/rdpsnd/client/pulse/CMakeLists.txt +++ b/channels/rdpsnd/client/pulse/CMakeLists.txt @@ -25,16 +25,10 @@ include_directories(${PULSE_INCLUDE_DIR}) add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "") - - list(APPEND ${MODULE_PREFIX}_LIBS ${PULSE_LIBRARY}) list(APPEND ${MODULE_PREFIX}_LIBS freerdp) list(APPEND ${MODULE_PREFIX}_LIBS winpr) -if(GSM_FOUND) - list(APPEND ${MODULE_PREFIX}_LIBS ${GSM_LIBRARIES}) -endif() - target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client/Pulse") diff --git a/channels/rdpsnd/client/pulse/rdpsnd_pulse.c b/channels/rdpsnd/client/pulse/rdpsnd_pulse.c index 2191ec9cf..b134b637e 100644 --- a/channels/rdpsnd/client/pulse/rdpsnd_pulse.c +++ b/channels/rdpsnd/client/pulse/rdpsnd_pulse.c @@ -33,10 +33,6 @@ #include -#ifdef WITH_GSM -#include -#endif - #include #include @@ -53,23 +49,15 @@ struct rdpsnd_pulse_plugin pa_context* context; pa_sample_spec sample_spec; pa_stream* stream; - int format; - int block_size; - int latency; - - FREERDP_DSP_CONTEXT* dsp_context; - -#ifdef WITH_GSM - gsm gsm_context; - wStream* gsmBuffer; -#endif + UINT32 latency; }; +static BOOL rdpsnd_pulse_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format); + static void rdpsnd_pulse_context_state_callback(pa_context* context, void* userdata) { pa_context_state_t state; rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) userdata; - state = pa_context_get_state(context); switch (state) @@ -140,7 +128,6 @@ static BOOL rdpsnd_pulse_connect(rdpsndDevicePlugin* device) static void rdpsnd_pulse_stream_success_callback(pa_stream* stream, int success, void* userdata) { rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) userdata; - pa_threaded_mainloop_signal(pulse->mainloop, 0); } @@ -161,7 +148,6 @@ static void rdpsnd_pulse_stream_state_callback(pa_stream* stream, void* userdata { pa_stream_state_t state; rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) userdata; - state = pa_stream_get_state(stream); switch (state) @@ -183,7 +169,6 @@ static void rdpsnd_pulse_stream_state_callback(pa_stream* stream, void* userdata static void rdpsnd_pulse_stream_request_callback(pa_stream* stream, size_t length, void* userdata) { rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) userdata; - pa_threaded_mainloop_signal(pulse->mainloop, 0); } @@ -191,30 +176,27 @@ static void rdpsnd_pulse_close(rdpsndDevicePlugin* device) { rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device; -#ifdef WITH_GSM - if (pulse->gsm_context) - gsm_destroy(pulse->gsm_context); -#endif - if (!pulse->context || !pulse->stream) return; pa_threaded_mainloop_lock(pulse->mainloop); - - rdpsnd_pulse_wait_for_operation(pulse, pa_stream_drain(pulse->stream, rdpsnd_pulse_stream_success_callback, pulse)); + rdpsnd_pulse_wait_for_operation(pulse, pa_stream_drain(pulse->stream, + rdpsnd_pulse_stream_success_callback, pulse)); pa_stream_disconnect(pulse->stream); pa_stream_unref(pulse->stream); pulse->stream = NULL; - pa_threaded_mainloop_unlock(pulse->mainloop); } -static void rdpsnd_pulse_set_format_spec(rdpsndPulsePlugin* pulse, AUDIO_FORMAT* format) +static BOOL rdpsnd_pulse_set_format_spec(rdpsndPulsePlugin* pulse, const AUDIO_FORMAT* format) { pa_sample_spec sample_spec = { 0 }; if (!pulse->context) - return; + return FALSE; + + if (!rdpsnd_pulse_format_supported(&pulse->device, format)) + return FALSE; sample_spec.rate = format->nSamplesPerSec; sample_spec.channels = format->nChannels; @@ -227,15 +209,15 @@ static void rdpsnd_pulse_set_format_spec(rdpsndPulsePlugin* pulse, AUDIO_FORMAT* case 8: sample_spec.format = PA_SAMPLE_U8; break; + case 16: sample_spec.format = PA_SAMPLE_S16LE; break; - } - break; - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - sample_spec.format = PA_SAMPLE_S16LE; + default: + return FALSE; + } + break; case WAVE_FORMAT_ALAW: @@ -246,17 +228,16 @@ static void rdpsnd_pulse_set_format_spec(rdpsndPulsePlugin* pulse, AUDIO_FORMAT* sample_spec.format = PA_SAMPLE_ULAW; break; - case WAVE_FORMAT_GSM610: - sample_spec.format = PA_SAMPLE_S16LE; - break; + default: + return FALSE; } pulse->sample_spec = sample_spec; - pulse->format = format->wFormatTag; - pulse->block_size = format->nBlockAlign; + return TRUE; } -static BOOL rdpsnd_pulse_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) +static BOOL rdpsnd_pulse_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, + UINT32 latency) { pa_stream_state_t state; pa_stream_flags_t flags; @@ -267,7 +248,9 @@ static BOOL rdpsnd_pulse_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, if (!pulse->context || pulse->stream) return TRUE; - rdpsnd_pulse_set_format_spec(pulse, format); + if (!rdpsnd_pulse_set_format_spec(pulse, format)) + return FALSE; + pulse->latency = latency; if (pa_sample_spec_valid(&pulse->sample_spec) == 0) @@ -277,8 +260,8 @@ static BOOL rdpsnd_pulse_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, } pa_threaded_mainloop_lock(pulse->mainloop); - pulse->stream = pa_stream_new(pulse->context, "freerdp", &pulse->sample_spec, NULL); + if (!pulse->stream) { pa_threaded_mainloop_unlock(pulse->mainloop); @@ -288,21 +271,20 @@ static BOOL rdpsnd_pulse_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, /* register essential callbacks */ pa_stream_set_state_callback(pulse->stream, rdpsnd_pulse_stream_state_callback, pulse); pa_stream_set_write_callback(pulse->stream, rdpsnd_pulse_stream_request_callback, pulse); - flags = PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE; if (pulse->latency > 0) { buffer_attr.maxlength = pa_usec_to_bytes(pulse->latency * 2 * 1000, &pulse->sample_spec); buffer_attr.tlength = pa_usec_to_bytes(pulse->latency * 1000, &pulse->sample_spec); - buffer_attr.prebuf = (UINT32) -1; - buffer_attr.minreq = (UINT32) -1; - buffer_attr.fragsize = (UINT32) -1; + buffer_attr.prebuf = (UINT32) - 1; + buffer_attr.minreq = (UINT32) - 1; + buffer_attr.fragsize = (UINT32) - 1; flags |= PA_STREAM_ADJUST_LATENCY; } if (pa_stream_connect_playback(pulse->stream, - pulse->device_name, pulse->latency > 0 ? &buffer_attr : NULL, flags, NULL, NULL) < 0) + pulse->device_name, pulse->latency > 0 ? &buffer_attr : NULL, flags, NULL, NULL) < 0) { pa_threaded_mainloop_unlock(pulse->mainloop); return TRUE; @@ -326,17 +308,7 @@ static BOOL rdpsnd_pulse_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, pa_threaded_mainloop_unlock(pulse->mainloop); if (state == PA_STREAM_READY) - { - freerdp_dsp_context_reset_adpcm(pulse->dsp_context); - -#ifdef WITH_GSM - if (pulse->gsm_context) - gsm_destroy(pulse->gsm_context); - - pulse->gsm_context = gsm_create(); -#endif return TRUE; - } rdpsnd_pulse_close(device); return FALSE; @@ -369,16 +341,11 @@ static void rdpsnd_pulse_free(rdpsndDevicePlugin* device) pulse->mainloop = NULL; } -#ifdef WITH_GSM - Stream_Free(pulse->gsmBuffer, TRUE); -#endif - free(pulse->device_name); - freerdp_dsp_context_free(pulse->dsp_context); free(pulse); } -static BOOL rdpsnd_pulse_format_supported(rdpsndDevicePlugin* device, AUDIO_FORMAT* format) +BOOL rdpsnd_pulse_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format) { rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; @@ -389,65 +356,31 @@ static BOOL rdpsnd_pulse_format_supported(rdpsndDevicePlugin* device, AUDIO_FORM { case WAVE_FORMAT_PCM: if (format->cbSize == 0 && - (format->nSamplesPerSec <= PA_RATE_MAX) && - (format->wBitsPerSample == 8 || format->wBitsPerSample == 16) && - (format->nChannels >= 1 && format->nChannels <= PA_CHANNELS_MAX)) + (format->nSamplesPerSec <= PA_RATE_MAX) && + (format->wBitsPerSample == 8 || format->wBitsPerSample == 16) && + (format->nChannels >= 1 && format->nChannels <= PA_CHANNELS_MAX)) { return TRUE; } + break; case WAVE_FORMAT_ALAW: case WAVE_FORMAT_MULAW: if (format->cbSize == 0 && - (format->nSamplesPerSec <= PA_RATE_MAX) && - (format->wBitsPerSample == 8) && - (format->nChannels >= 1 && format->nChannels <= PA_CHANNELS_MAX)) + (format->nSamplesPerSec <= PA_RATE_MAX) && + (format->wBitsPerSample == 8) && + (format->nChannels >= 1 && format->nChannels <= PA_CHANNELS_MAX)) { return TRUE; } - break; - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - if ((format->nSamplesPerSec <= PA_RATE_MAX) && - (format->wBitsPerSample == 4) && - (format->nChannels == 1 || format->nChannels == 2)) - { - return TRUE; - } break; - -#ifdef WITH_GSM - case WAVE_FORMAT_GSM610: - if ((format->nSamplesPerSec <= PA_RATE_MAX) && - (format->nBlockAlign == 65) && (format->nChannels == 1)) - { - return TRUE; - } - break; -#endif } return FALSE; } -static BOOL rdpsnd_pulse_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) -{ - rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device; - - if (pulse->stream) - { - pa_threaded_mainloop_lock(pulse->mainloop); - pa_stream_disconnect(pulse->stream); - pa_stream_unref(pulse->stream); - pulse->stream = NULL; - pa_threaded_mainloop_unlock(pulse->mainloop); - } - - return rdpsnd_pulse_open(device, format, latency); -} - static BOOL rdpsnd_pulse_set_volume(rdpsndDevicePlugin* device, UINT32 value) { pa_cvolume cv; @@ -459,17 +392,15 @@ static BOOL rdpsnd_pulse_set_volume(rdpsndDevicePlugin* device, UINT32 value) if (!pulse->context || !pulse->stream) return FALSE; - left = (pa_volume_t) (value & 0xFFFF); - right = (pa_volume_t) ((value >> 16) & 0xFFFF); - + left = (pa_volume_t)(value & 0xFFFF); + right = (pa_volume_t)((value >> 16) & 0xFFFF); pa_cvolume_init(&cv); cv.channels = 2; cv.values[0] = PA_VOLUME_MUTED + (left * (PA_VOLUME_NORM - PA_VOLUME_MUTED)) / 0xFFFF; cv.values[1] = PA_VOLUME_MUTED + (right * (PA_VOLUME_NORM - PA_VOLUME_MUTED)) / 0xFFFF; - pa_threaded_mainloop_lock(pulse->mainloop); - - operation = pa_context_set_sink_input_volume(pulse->context, pa_stream_get_index(pulse->stream), &cv, NULL, NULL); + operation = pa_context_set_sink_input_volume(pulse->context, pa_stream_get_index(pulse->stream), + &cv, NULL, NULL); if (operation) pa_operation_unref(operation); @@ -478,93 +409,23 @@ static BOOL rdpsnd_pulse_set_volume(rdpsndDevicePlugin* device, UINT32 value) return TRUE; } -static BYTE* rdpsnd_pulse_convert_audio(rdpsndDevicePlugin* device, BYTE* data, int* size) +static UINT rdpsnd_pulse_play(rdpsndDevicePlugin* device, const BYTE* data, size_t size) { - BYTE* pcmData = NULL; - rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device; - - if (pulse->format == WAVE_FORMAT_ADPCM) - { - pulse->dsp_context->decode_ms_adpcm(pulse->dsp_context, - data, *size, pulse->sample_spec.channels, pulse->block_size); - - *size = pulse->dsp_context->adpcm_size; - pcmData = pulse->dsp_context->adpcm_buffer; - } - else if (pulse->format == WAVE_FORMAT_DVI_ADPCM) - { - pulse->dsp_context->decode_ima_adpcm(pulse->dsp_context, - data, *size, pulse->sample_spec.channels, pulse->block_size); - - *size = pulse->dsp_context->adpcm_size; - pcmData = pulse->dsp_context->adpcm_buffer; - } -#ifdef WITH_GSM - else if (pulse->format == WAVE_FORMAT_GSM610) - { - int inPos = 0; - int inSize = *size; - UINT16 gsmBlockBuffer[160]; - - Stream_SetPosition(pulse->gsmBuffer, 0); - - while (inSize) - { - ZeroMemory(gsmBlockBuffer, sizeof(gsmBlockBuffer)); - gsm_decode(pulse->gsm_context, (gsm_byte*) &data[inPos], (gsm_signal*) gsmBlockBuffer); - - if ((inPos % 65) == 0) - { - inPos += 33; - inSize -= 33; - } - else - { - inPos += 32; - inSize -= 32; - } - - if (!Stream_EnsureRemainingCapacity(pulse->gsmBuffer, 160 * 2)) - return NULL; - Stream_Write(pulse->gsmBuffer, (void*) gsmBlockBuffer, 160 * 2); - } - - Stream_SealLength(pulse->gsmBuffer); - - pcmData = Stream_Buffer(pulse->gsmBuffer); - *size = Stream_Length(pulse->gsmBuffer); - } -#endif - else - { - pcmData = data; - } - - return pcmData; -} - -static void rdpsnd_pulse_play(rdpsndDevicePlugin* device, BYTE* data, int size) -{ - int length; + size_t length; int status; - BYTE* pcmData; + pa_usec_t latency; + int negative; rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device; - if (!pulse->stream) - return; - - pcmData = rdpsnd_pulse_convert_audio(device, data, &size); - if (!pcmData) - return; + if (!pulse->stream || !data) + return 0; pa_threaded_mainloop_lock(pulse->mainloop); while (size > 0) { while ((length = pa_stream_writable_size(pulse->stream)) == 0) - { pa_threaded_mainloop_wait(pulse->mainloop); - } if (length < 0) break; @@ -572,18 +433,23 @@ static void rdpsnd_pulse_play(rdpsndDevicePlugin* device, BYTE* data, int size) if (length > size) length = size; - status = pa_stream_write(pulse->stream, pcmData, length, NULL, 0LL, PA_SEEK_RELATIVE); + status = pa_stream_write(pulse->stream, data, length, NULL, 0LL, PA_SEEK_RELATIVE); if (status < 0) { break; } - pcmData += length; + data += length; size -= length; } + if (pa_stream_get_latency(pulse->stream, &latency, &negative) != 0) + latency = 0; + pa_threaded_mainloop_unlock(pulse->mainloop); + + return latency / 1000; } static void rdpsnd_pulse_start(rdpsndDevicePlugin* device) @@ -598,7 +464,7 @@ static void rdpsnd_pulse_start(rdpsndDevicePlugin* device) pa_threaded_mainloop_unlock(pulse->mainloop); } -COMMAND_LINE_ARGUMENT_A rdpsnd_pulse_args[] = +static COMMAND_LINE_ARGUMENT_A rdpsnd_pulse_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "device" }, { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } @@ -615,29 +481,28 @@ static UINT rdpsnd_pulse_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV DWORD flags; COMMAND_LINE_ARGUMENT_A* arg; rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device; - flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; - status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv, - rdpsnd_pulse_args, flags, pulse, NULL, NULL); + rdpsnd_pulse_args, flags, pulse, NULL, NULL); + if (status < 0) return ERROR_INVALID_DATA; arg = rdpsnd_pulse_args; + do { if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) continue; CommandLineSwitchStart(arg) - CommandLineSwitchCase(arg, "dev") { pulse->device_name = _strdup(arg->Value); + if (!pulse->device_name) return ERROR_OUTOFMEMORY; } - CommandLineSwitchEnd(arg) } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); @@ -661,24 +526,24 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p ADDIN_ARGV* args; rdpsndPulsePlugin* pulse; UINT ret; - pulse = (rdpsndPulsePlugin*) calloc(1, sizeof(rdpsndPulsePlugin)); + if (!pulse) return CHANNEL_RC_NO_MEMORY; pulse->device.Open = rdpsnd_pulse_open; pulse->device.FormatSupported = rdpsnd_pulse_format_supported; - pulse->device.SetFormat = rdpsnd_pulse_set_format; pulse->device.SetVolume = rdpsnd_pulse_set_volume; pulse->device.Play = rdpsnd_pulse_play; pulse->device.Start = rdpsnd_pulse_start; pulse->device.Close = rdpsnd_pulse_close; pulse->device.Free = rdpsnd_pulse_free; - args = pEntryPoints->args; + if (args->argc > 1) { - ret = rdpsnd_pulse_parse_addin_args((rdpsndDevicePlugin *) pulse, args); + ret = rdpsnd_pulse_parse_addin_args((rdpsndDevicePlugin*) pulse, args); + if (ret != CHANNEL_RC_OK) { WLog_ERR(TAG, "error parsing arguments"); @@ -687,17 +552,6 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p } ret = CHANNEL_RC_NO_MEMORY; - pulse->dsp_context = freerdp_dsp_context_new(); - if (!pulse->dsp_context) - goto error; - -#ifdef WITH_GSM - pulse->gsmBuffer = Stream_New(NULL, 4096); - if (!pulse->gsmBuffer) - goto error; -#endif - - pulse->mainloop = pa_threaded_mainloop_new(); if (!pulse->mainloop) @@ -709,14 +563,13 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p goto error; pa_context_set_state_callback(pulse->context, rdpsnd_pulse_context_state_callback, pulse); - ret = ERROR_INVALID_OPERATION; + if (!rdpsnd_pulse_connect((rdpsndDevicePlugin*)pulse)) goto error; pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*) pulse); return CHANNEL_RC_OK; - error: rdpsnd_pulse_free((rdpsndDevicePlugin*)pulse); return ret; diff --git a/channels/rdpsnd/client/rdpsnd_main.c b/channels/rdpsnd/client/rdpsnd_main.c index 4c327f7d0..d00f62561 100644 --- a/channels/rdpsnd/client/rdpsnd_main.c +++ b/channels/rdpsnd/client/rdpsnd_main.c @@ -45,29 +45,28 @@ #include #include +#include #include "rdpsnd_main.h" -#define TIME_DELAY_MS 65 - struct rdpsnd_plugin { CHANNEL_DEF channelDef; CHANNEL_ENTRY_POINTS_FREERDP_EX channelEntryPoints; HANDLE thread; + wStreamPool* pool; wStream* data_in; + void* InitHandle; DWORD OpenHandle; - wMessagePipe* MsgPipe; wLog* log; HANDLE stopEvent; - HANDLE ScheduleThread; BYTE cBlockNo; UINT16 wQualityMode; - int wCurrentFormatNo; + UINT16 wCurrentFormatNo; AUDIO_FORMAT* ServerFormats; UINT16 NumberOfServerFormats; @@ -81,8 +80,9 @@ struct rdpsnd_plugin BYTE waveData[4]; UINT16 waveDataSize; UINT32 wTimeStamp; + UINT32 wArrivalTime; - int latency; + UINT32 latency; BOOL isOpen; UINT16 fixedFormat; UINT16 fixedChannel; @@ -94,6 +94,9 @@ struct rdpsnd_plugin /* Device plugin */ rdpsndDevicePlugin* device; rdpContext* rdpcontext; + + wQueue* queue; + FREERDP_DSP_CONTEXT* dsp_context; }; /** @@ -101,91 +104,7 @@ struct rdpsnd_plugin * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpsnd_confirm_wave(rdpsndPlugin* rdpsnd, RDPSND_WAVE* wave); - -static DWORD WINAPI rdpsnd_schedule_thread(LPVOID arg) -{ - wMessage message; - UINT16 wTimeDiff; - UINT16 wTimeStamp; - UINT16 wCurrentTime; - RDPSND_WAVE* wave; - rdpsndPlugin* rdpsnd = (rdpsndPlugin*) arg; - HANDLE events[2]; - UINT error = CHANNEL_RC_OK; - DWORD status; - events[0] = MessageQueue_Event(rdpsnd->MsgPipe->Out); - events[1] = rdpsnd->stopEvent; - - while (1) - { - status = WaitForMultipleObjects(2, events, FALSE, INFINITE); - - if (status == WAIT_FAILED) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %"PRIu32"!", error); - break; - } - - status = WaitForSingleObject(rdpsnd->stopEvent, 0); - - if (status == WAIT_FAILED) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); - break; - } - - if (status == WAIT_OBJECT_0) - break; - - status = WaitForSingleObject(events[0], 0); - - if (status == WAIT_FAILED) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); - break; - } - - if (!MessageQueue_Peek(rdpsnd->MsgPipe->Out, &message, TRUE)) - { - WLog_ERR(TAG, "MessageQueue_Peek failed!"); - error = ERROR_INTERNAL_ERROR; - break; - } - - if (message.id == WMQ_QUIT) - break; - - wave = (RDPSND_WAVE*) message.wParam; - wCurrentTime = (UINT16) GetTickCount(); - wTimeStamp = wave->wLocalTimeB; - - if (wCurrentTime <= wTimeStamp) - { - wTimeDiff = wTimeStamp - wCurrentTime; - Sleep(wTimeDiff); - } - - if ((error = rdpsnd_confirm_wave(rdpsnd, wave))) - { - WLog_ERR(TAG, "error confirming wave"); - break; - } - - message.wParam = NULL; - free(wave); - } - - if (error && rdpsnd->rdpcontext) - setChannelError(rdpsnd->rdpcontext, error, - "rdpsnd_schedule_thread reported an error"); - - ExitThread(error); - return error; -} +static UINT rdpsnd_virtual_channel_write(rdpsndPlugin* rdpsnd, wStream* s); /** * Function description @@ -214,9 +133,7 @@ static UINT rdpsnd_send_quality_mode_pdu(rdpsndPlugin* rdpsnd) static void rdpsnd_select_supported_audio_formats(rdpsndPlugin* rdpsnd) { - int index; - AUDIO_FORMAT* serverFormat; - AUDIO_FORMAT* clientFormat; + UINT16 index; rdpsnd_free_audio_formats(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats); rdpsnd->NumberOfClientFormats = 0; rdpsnd->ClientFormats = NULL; @@ -231,48 +148,35 @@ static void rdpsnd_select_supported_audio_formats(rdpsndPlugin* rdpsnd) if (!rdpsnd->ClientFormats) return; - for (index = 0; index < (int) rdpsnd->NumberOfServerFormats; index++) + for (index = 0; index < rdpsnd->NumberOfServerFormats; index++) { - serverFormat = &rdpsnd->ServerFormats[index]; + const AUDIO_FORMAT* serverFormat = &rdpsnd->ServerFormats[index]; - if (rdpsnd->fixedFormat > 0 - && (rdpsnd->fixedFormat != serverFormat->wFormatTag)) + if ((rdpsnd->fixedFormat > 0) && + (rdpsnd->fixedFormat != serverFormat->wFormatTag)) continue; - if (rdpsnd->fixedChannel > 0 - && (rdpsnd->fixedChannel != serverFormat->nChannels)) + if ((rdpsnd->fixedChannel > 0) && + (rdpsnd->fixedChannel != serverFormat->nChannels)) continue; - if (rdpsnd->fixedRate > 0 - && (rdpsnd->fixedRate != serverFormat->nSamplesPerSec)) + if ((rdpsnd->fixedRate > 0) && + (rdpsnd->fixedRate != serverFormat->nSamplesPerSec)) continue; - if (rdpsnd->device - && rdpsnd->device->FormatSupported(rdpsnd->device, serverFormat)) + if (freerdp_dsp_supports_format(serverFormat, FALSE) || + rdpsnd->device->FormatSupported(rdpsnd->device, serverFormat)) { - clientFormat = &rdpsnd->ClientFormats[rdpsnd->NumberOfClientFormats++]; - CopyMemory(clientFormat, serverFormat, sizeof(AUDIO_FORMAT)); - clientFormat->cbSize = 0; + AUDIO_FORMAT* clientFormat = &rdpsnd->ClientFormats[rdpsnd->NumberOfClientFormats++]; + *clientFormat = *serverFormat; if (serverFormat->cbSize > 0) { clientFormat->data = (BYTE*) malloc(serverFormat->cbSize); CopyMemory(clientFormat->data, serverFormat->data, serverFormat->cbSize); - clientFormat->cbSize = serverFormat->cbSize; } } } - -#if 0 - WLog_ERR(TAG, "Server "); - rdpsnd_print_audio_formats(rdpsnd->ServerFormats, - rdpsnd->NumberOfServerFormats); - WLog_ERR(TAG, ""); - WLog_ERR(TAG, "Client "); - rdpsnd_print_audio_formats(rdpsnd->ClientFormats, - rdpsnd->NumberOfClientFormats); - WLog_ERR(TAG, ""); -#endif } /** @@ -282,28 +186,17 @@ static void rdpsnd_select_supported_audio_formats(rdpsndPlugin* rdpsnd) */ static UINT rdpsnd_send_client_audio_formats(rdpsndPlugin* rdpsnd) { - int index; + UINT16 index; wStream* pdu; UINT16 length; UINT32 dwVolume; - UINT16 dwVolumeLeft; - UINT16 dwVolumeRight; UINT16 wNumberOfFormats; - AUDIO_FORMAT* clientFormat; - dwVolumeLeft = ((50 * 0xFFFF) / 100); /* 50% */ - dwVolumeRight = ((50 * 0xFFFF) / 100); /* 50% */ - dwVolume = (dwVolumeLeft << 16) | dwVolumeRight; - - if (rdpsnd->device) - { - if (rdpsnd->device->GetVolume) - dwVolume = rdpsnd->device->GetVolume(rdpsnd->device); - } + dwVolume = IFCALLRESULT(0, rdpsnd->device->GetVolume, rdpsnd->device); wNumberOfFormats = rdpsnd->NumberOfClientFormats; length = 4 + 20; - for (index = 0; index < (int) wNumberOfFormats; index++) + for (index = 0; index < wNumberOfFormats; index++) length += (18 + rdpsnd->ClientFormats[index].cbSize); pdu = Stream_New(NULL, length); @@ -326,9 +219,9 @@ static UINT rdpsnd_send_client_audio_formats(rdpsndPlugin* rdpsnd) Stream_Write_UINT16(pdu, 6); /* wVersion */ Stream_Write_UINT8(pdu, 0); /* bPad */ - for (index = 0; index < (int) wNumberOfFormats; index++) + for (index = 0; index < wNumberOfFormats; index++) { - clientFormat = &rdpsnd->ClientFormats[index]; + const AUDIO_FORMAT* clientFormat = &rdpsnd->ClientFormats[index]; Stream_Write_UINT16(pdu, clientFormat->wFormatTag); Stream_Write_UINT16(pdu, clientFormat->nChannels); Stream_Write_UINT32(pdu, clientFormat->nSamplesPerSec); @@ -353,9 +246,8 @@ static UINT rdpsnd_send_client_audio_formats(rdpsndPlugin* rdpsnd) static UINT rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, wStream* s) { - int index; + UINT16 index; UINT16 wVersion; - AUDIO_FORMAT* format; UINT16 wNumberOfFormats; UINT ret = ERROR_BAD_LENGTH; rdpsnd_free_audio_formats(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats); @@ -385,9 +277,9 @@ static UINT rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, if (!rdpsnd->ServerFormats) return CHANNEL_RC_NO_MEMORY; - for (index = 0; index < (int) wNumberOfFormats; index++) + for (index = 0; index < wNumberOfFormats; index++) { - format = &rdpsnd->ServerFormats[index]; + AUDIO_FORMAT* format = &rdpsnd->ServerFormats[index]; if (Stream_GetRemainingLength(s) < 14) goto out_fail; @@ -429,12 +321,9 @@ static UINT rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, return ret; out_fail: - - for (index = 0; index < (int) wNumberOfFormats; index++) - free(format->data); - - free(rdpsnd->ServerFormats); + rdpsnd_free_audio_formats(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats); rdpsnd->ServerFormats = NULL; + rdpsnd->NumberOfServerFormats = 0; return ret; } @@ -496,47 +385,61 @@ static UINT rdpsnd_recv_wave_info_pdu(rdpsndPlugin* rdpsnd, wStream* s, UINT16 BodySize) { UINT16 wFormatNo; - AUDIO_FORMAT* format; - rdpsnd->expectingWave = TRUE; + const AUDIO_FORMAT* format; if (Stream_GetRemainingLength(s) < 12) return ERROR_BAD_LENGTH; + rdpsnd->wArrivalTime = GetTickCount(); Stream_Read_UINT16(s, rdpsnd->wTimeStamp); Stream_Read_UINT16(s, wFormatNo); + + if (wFormatNo >= rdpsnd->NumberOfClientFormats) + return ERROR_INVALID_DATA; + Stream_Read_UINT8(s, rdpsnd->cBlockNo); Stream_Seek(s, 3); /* bPad */ Stream_Read(s, rdpsnd->waveData, 4); rdpsnd->waveDataSize = BodySize - 8; format = &rdpsnd->ClientFormats[wFormatNo]; - WLog_Print(rdpsnd->log, WLOG_DEBUG, "WaveInfo: cBlockNo: %"PRIu8" wFormatNo: %"PRIu16"", - rdpsnd->cBlockNo, wFormatNo); + WLog_Print(rdpsnd->log, WLOG_DEBUG, "WaveInfo: cBlockNo: %"PRIu8" wFormatNo: %"PRIu16" [%s]", + rdpsnd->cBlockNo, wFormatNo, rdpsnd_get_audio_tag_string(format->wFormatTag)); - if (!rdpsnd->isOpen) + if (!rdpsnd->isOpen || (wFormatNo != rdpsnd->wCurrentFormatNo)) { - rdpsnd->isOpen = TRUE; - rdpsnd->wCurrentFormatNo = wFormatNo; + BOOL rc; + AUDIO_FORMAT deviceFormat = *format; - //rdpsnd_print_audio_format(format); + if (rdpsnd->isOpen) + IFCALL(rdpsnd->device->Close, rdpsnd->device); - if (rdpsnd->device && rdpsnd->device->Open && - !rdpsnd->device->Open(rdpsnd->device, format, rdpsnd->latency)) + rc = IFCALLRESULT(FALSE, rdpsnd->device->FormatSupported, rdpsnd->device, format); + + if (!rc) { - return CHANNEL_RC_INITIALIZATION_ERROR; + deviceFormat.wFormatTag = WAVE_FORMAT_PCM; + deviceFormat.wBitsPerSample = 16; + deviceFormat.cbSize = 0; } - } - else if (wFormatNo != rdpsnd->wCurrentFormatNo) - { - rdpsnd->wCurrentFormatNo = wFormatNo; - if (rdpsnd->device) + rc = IFCALLRESULT(FALSE, rdpsnd->device->Open, rdpsnd->device, &deviceFormat, rdpsnd->latency); + + if (!rc) + return CHANNEL_RC_INITIALIZATION_ERROR; + + rc = IFCALLRESULT(FALSE, rdpsnd->device->FormatSupported, rdpsnd->device, format); + + if (!rc) { - if (rdpsnd->device->SetFormat - && !rdpsnd->device->SetFormat(rdpsnd->device, format, rdpsnd->latency)) + if (!freerdp_dsp_context_reset(rdpsnd->dsp_context, format)) return CHANNEL_RC_INITIALIZATION_ERROR; } + + rdpsnd->isOpen = TRUE; + rdpsnd->wCurrentFormatNo = wFormatNo; } + rdpsnd->expectingWave = TRUE; return CHANNEL_RC_OK; } @@ -566,40 +469,6 @@ static UINT rdpsnd_send_wave_confirm_pdu(rdpsndPlugin* rdpsnd, return rdpsnd_virtual_channel_write(rdpsnd, pdu); } -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT rdpsnd_confirm_wave(rdpsndPlugin* rdpsnd, RDPSND_WAVE* wave) -{ - WLog_Print(rdpsnd->log, WLOG_DEBUG, - "WaveConfirm: cBlockNo: %"PRIu8" wTimeStamp: %"PRIu16" wTimeDiff: %d", - wave->cBlockNo, wave->wTimeStampB, wave->wTimeStampB - wave->wTimeStampA); - return rdpsnd_send_wave_confirm_pdu(rdpsnd, wave->wTimeStampB, wave->cBlockNo); -} - -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ -static UINT rdpsnd_device_send_wave_confirm_pdu(rdpsndDevicePlugin* device, - RDPSND_WAVE* wave) -{ - if (device->DisableConfirmThread) - return rdpsnd_confirm_wave(device->rdpsnd, wave); - - if (!MessageQueue_Post(device->rdpsnd->MsgPipe->Out, NULL, 0, (void*) wave, - NULL)) - { - WLog_ERR(TAG, "MessageQueue_Post failed!"); - return ERROR_INTERNAL_ERROR; - } - - return CHANNEL_RC_OK; -} - /** * Function description * @@ -607,11 +476,13 @@ static UINT rdpsnd_device_send_wave_confirm_pdu(rdpsndDevicePlugin* device, */ static UINT rdpsnd_recv_wave_pdu(rdpsndPlugin* rdpsnd, wStream* s) { - int size; + size_t size; BYTE* data; - RDPSND_WAVE* wave; AUDIO_FORMAT* format; UINT status; + DWORD end; + DWORD diffMS; + UINT latency = 0; rdpsnd->expectingWave = FALSE; /** * The Wave PDU is a special case: it is always sent after a Wave Info PDU, @@ -621,74 +492,44 @@ static UINT rdpsnd_recv_wave_pdu(rdpsndPlugin* rdpsnd, wStream* s) */ CopyMemory(Stream_Buffer(s), rdpsnd->waveData, 4); data = Stream_Buffer(s); - size = (int) Stream_Capacity(s); - wave = (RDPSND_WAVE*) calloc(1, sizeof(RDPSND_WAVE)); - - if (!wave) - { - WLog_ERR(TAG, "calloc failed!"); - return CHANNEL_RC_NO_MEMORY; - } - - wave->wLocalTimeA = GetTickCount(); - wave->wTimeStampA = rdpsnd->wTimeStamp; - wave->wFormatNo = rdpsnd->wCurrentFormatNo; - wave->cBlockNo = rdpsnd->cBlockNo; - wave->data = data; - wave->length = size; - wave->AutoConfirm = TRUE; + size = Stream_Length(s); format = &rdpsnd->ClientFormats[rdpsnd->wCurrentFormatNo]; - wave->wAudioLength = rdpsnd_compute_audio_time_length(format, size); WLog_Print(rdpsnd->log, WLOG_DEBUG, "Wave: cBlockNo: %"PRIu8" wTimeStamp: %"PRIu16"", - wave->cBlockNo, wave->wTimeStampA); + rdpsnd->cBlockNo, rdpsnd->wTimeStamp); - if (!rdpsnd->device) + if (rdpsnd->device) { - wave->wLocalTimeB = wave->wLocalTimeA; - wave->wTimeStampB = wave->wTimeStampA; - status = rdpsnd_confirm_wave(rdpsnd, wave); - free(wave); - return status; + wStream* pcmData = StreamPool_Take(rdpsnd->pool, 4096); + + if (rdpsnd->device->FormatSupported(rdpsnd->device, format)) + { + latency = IFCALLRESULT(0, rdpsnd->device->Play, rdpsnd->device, data, size); + status = CHANNEL_RC_OK; + } + else if (freerdp_dsp_decode(rdpsnd->dsp_context, format, data, size, pcmData)) + { + Stream_SealLength(pcmData); + latency = IFCALLRESULT(0, rdpsnd->device->Play, rdpsnd->device, Stream_Buffer(pcmData), Stream_Length(pcmData)); + status = CHANNEL_RC_OK; + } + + StreamPool_Return(rdpsnd->pool, pcmData); + + if (status != CHANNEL_RC_OK) + return status; } - if (rdpsnd->device->WaveDecode - && !rdpsnd->device->WaveDecode(rdpsnd->device, wave)) - { - free(wave); - return CHANNEL_RC_NO_MEMORY; - } - - if (rdpsnd->device->WavePlay) - { - IFCALL(rdpsnd->device->WavePlay, rdpsnd->device, wave); - } - else - { - IFCALL(rdpsnd->device->Play, rdpsnd->device, data, size); - } - - if (!rdpsnd->device->WavePlay) - { - wave->wTimeStampB = rdpsnd->wTimeStamp + wave->wAudioLength + TIME_DELAY_MS; - wave->wLocalTimeB = wave->wLocalTimeA + wave->wAudioLength + TIME_DELAY_MS; - } - - status = CHANNEL_RC_OK; - - if (wave->AutoConfirm) - status = rdpsnd->device->WaveConfirm(rdpsnd->device, wave); - - return status; + end = GetTickCount(); + diffMS = end - rdpsnd->wArrivalTime + latency; + return rdpsnd_send_wave_confirm_pdu(rdpsnd, rdpsnd->wTimeStamp + diffMS, rdpsnd->cBlockNo); } static void rdpsnd_recv_close_pdu(rdpsndPlugin* rdpsnd) { WLog_Print(rdpsnd->log, WLOG_DEBUG, "Close"); - if (rdpsnd->device) - { + if (rdpsnd->isOpen) IFCALL(rdpsnd->device->Close, rdpsnd->device); - } rdpsnd->isOpen = FALSE; } @@ -700,6 +541,7 @@ static void rdpsnd_recv_close_pdu(rdpsndPlugin* rdpsnd) */ static UINT rdpsnd_recv_volume_pdu(rdpsndPlugin* rdpsnd, wStream* s) { + BOOL error; UINT32 dwVolume; if (Stream_GetRemainingLength(s) < 4) @@ -707,9 +549,9 @@ static UINT rdpsnd_recv_volume_pdu(rdpsndPlugin* rdpsnd, wStream* s) Stream_Read_UINT32(s, dwVolume); WLog_Print(rdpsnd->log, WLOG_DEBUG, "Volume: 0x%08"PRIX32"", dwVolume); + error = IFCALLRESULT(FALSE, rdpsnd->device->SetVolume, rdpsnd->device, dwVolume); - if (rdpsnd->device && rdpsnd->device->SetVolume && - !rdpsnd->device->SetVolume(rdpsnd->device, dwVolume)) + if (error) { WLog_ERR(TAG, "error setting volume"); return CHANNEL_RC_INITIALIZATION_ERROR; @@ -778,7 +620,7 @@ static UINT rdpsnd_recv_pdu(rdpsndPlugin* rdpsnd, wStream* s) } out: - Stream_Free(s, TRUE); + StreamPool_Return(rdpsnd->pool, s); return status; } @@ -793,7 +635,6 @@ static void rdpsnd_register_device_plugin(rdpsndPlugin* rdpsnd, rdpsnd->device = device; device->rdpsnd = rdpsnd; - device->WaveConfirm = rdpsnd_device_send_wave_confirm_pdu; } /** @@ -967,10 +808,38 @@ static UINT rdpsnd_process_addin_args(rdpsndPlugin* rdpsnd, ADDIN_ARGV* args) */ static UINT rdpsnd_process_connect(rdpsndPlugin* rdpsnd) { + const struct + { + const char* subsystem; + const char* device; + } + backends[] = + { +#if defined(WITH_IOSAUDIO) + {"ios", ""}, +#endif +#if defined(WITH_OPENSLES) + {"opensles", ""}, +#endif +#if defined(WITH_PULSE) + {"pulse", ""}, +#endif +#if defined(WITH_ALSA) + {"alsa", "default"}, +#endif +#if defined(WITH_OSS) + {"oss", ""}, +#endif +#if defined(WITH_MACAUDIO) + {"mac", "default"}, +#endif +#if defined(WITH_WINMM) + { "winmm", ""}, +#endif + }; ADDIN_ARGV* args; UINT status = ERROR_INTERNAL_ERROR; - char* subsystem_name = NULL, *device_name = NULL; - rdpsnd->latency = -1; + rdpsnd->latency = 0; args = (ADDIN_ARGV*) rdpsnd->channelEntryPoints.pExtendedData; if (args) @@ -995,134 +864,29 @@ static UINT rdpsnd_process_connect(rdpsndPlugin* rdpsnd) } else { -#if defined(WITH_IOSAUDIO) + size_t x; - if (!rdpsnd->device) + for (x = 0; x < ARRAYSIZE(backends); x++) { - subsystem_name = "ios"; - device_name = ""; + const char* subsystem_name = backends[x].subsystem; + const char* device_name = backends[x].device; if ((status = rdpsnd_load_device_plugin(rdpsnd, subsystem_name, args))) WLog_ERR(TAG, "unable to load the %s subsystem plugin because of error %"PRIu32"", subsystem_name, status); - } -#endif -#if defined(WITH_OPENSLES) + if (!rdpsnd->device) + continue; - if (!rdpsnd->device) - { - subsystem_name = "opensles"; - device_name = ""; - - if ((status = rdpsnd_load_device_plugin(rdpsnd, subsystem_name, args))) - WLog_ERR(TAG, "unable to load the %s subsystem plugin because of error %"PRIu32"", - subsystem_name, status); - } - -#endif -#if defined(WITH_PULSE) - - if (!rdpsnd->device) - { - subsystem_name = "pulse"; - device_name = ""; - - if ((status = rdpsnd_load_device_plugin(rdpsnd, subsystem_name, args))) - WLog_ERR(TAG, "unable to load the %s subsystem plugin because of error %"PRIu32"", - subsystem_name, status); - } - -#endif -#if defined(WITH_ALSA) - - if (!rdpsnd->device) - { - subsystem_name = "alsa"; - device_name = "default"; - - if ((status = rdpsnd_load_device_plugin(rdpsnd, subsystem_name, args))) - WLog_ERR(TAG, "unable to load the %s subsystem plugin because of error %"PRIu32"", - subsystem_name, status); - } - -#endif -#if defined(WITH_OSS) - - if (!rdpsnd->device) - { - subsystem_name = "oss"; - device_name = ""; - - if ((status = rdpsnd_load_device_plugin(rdpsnd, subsystem_name, args))) - WLog_ERR(TAG, "unable to load the %s subsystem plugin because of error %"PRIu32"", - subsystem_name, status); - } - -#endif -#if defined(WITH_MACAUDIO) - - if (!rdpsnd->device) - { - subsystem_name = "mac"; - device_name = "default"; - - if ((status = rdpsnd_load_device_plugin(rdpsnd, subsystem_name, args))) - WLog_ERR(TAG, "unable to load the %s subsystem plugin because of error %"PRIu32"", - subsystem_name, status); - } - -#endif -#if defined(WITH_WINMM) - - if (!rdpsnd->device) - { - subsystem_name = "winmm"; - device_name = ""; - - if ((status = rdpsnd_load_device_plugin(rdpsnd, subsystem_name, args))) - WLog_ERR(TAG, "unable to load the %s subsystem plugin because of error %"PRIu32"", - subsystem_name, status); - } - -#endif - - if (status) - return status; - - if (rdpsnd->device) - { - if (!rdpsnd_set_subsystem(rdpsnd, subsystem_name) - || !rdpsnd_set_device_name(rdpsnd, device_name)) + if (!rdpsnd_set_subsystem(rdpsnd, subsystem_name) || + !rdpsnd_set_device_name(rdpsnd, device_name)) return CHANNEL_RC_NO_MEMORY; + + break; } - } - if (!rdpsnd->device) - { - WLog_ERR(TAG, "no sound device."); - return CHANNEL_RC_INITIALIZATION_ERROR; - } - - if (!rdpsnd->device->DisableConfirmThread) - { - rdpsnd->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - - if (!rdpsnd->stopEvent) - { - WLog_ERR(TAG, "CreateEvent failed!"); + if (!rdpsnd->device || status) return CHANNEL_RC_INITIALIZATION_ERROR; - } - - rdpsnd->ScheduleThread = CreateThread(NULL, 0, - rdpsnd_schedule_thread, - (void*) rdpsnd, 0, NULL); - - if (!rdpsnd->ScheduleThread) - { - WLog_ERR(TAG, "CreateThread failed!"); - return CHANNEL_RC_INITIALIZATION_ERROR; - } } return CHANNEL_RC_OK; @@ -1130,19 +894,6 @@ static UINT rdpsnd_process_connect(rdpsndPlugin* rdpsnd) static void rdpsnd_process_disconnect(rdpsndPlugin* rdpsnd) { - if (rdpsnd->ScheduleThread) - { - SetEvent(rdpsnd->stopEvent); - - if (WaitForSingleObject(rdpsnd->ScheduleThread, INFINITE) == WAIT_FAILED) - { - WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", GetLastError()); - return; - } - - CloseHandle(rdpsnd->ScheduleThread); - CloseHandle(rdpsnd->stopEvent); - } } /** @@ -1152,13 +903,9 @@ static void rdpsnd_process_disconnect(rdpsndPlugin* rdpsnd) */ UINT rdpsnd_virtual_channel_write(rdpsndPlugin* rdpsnd, wStream* s) { - UINT status; + UINT status = CHANNEL_RC_BAD_INIT_HANDLE; - if (!rdpsnd) - { - status = CHANNEL_RC_BAD_INIT_HANDLE; - } - else + if (rdpsnd) { status = rdpsnd->channelEntryPoints.pVirtualChannelWriteEx(rdpsnd->InitHandle, rdpsnd->OpenHandle, Stream_Buffer(s), (UINT32) Stream_GetPosition(s), s); @@ -1182,54 +929,34 @@ UINT rdpsnd_virtual_channel_write(rdpsndPlugin* rdpsnd, wStream* s) static UINT rdpsnd_virtual_channel_event_data_received(rdpsndPlugin* plugin, void* pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) { - wStream* s; - if ((dataFlags & CHANNEL_FLAG_SUSPEND) || (dataFlags & CHANNEL_FLAG_RESUME)) - { return CHANNEL_RC_OK; - } if (dataFlags & CHANNEL_FLAG_FIRST) { - if (plugin->data_in != NULL) - Stream_Free(plugin->data_in, TRUE); - - plugin->data_in = Stream_New(NULL, totalLength); - if (!plugin->data_in) - { - WLog_ERR(TAG, "Stream_New failed!"); - return CHANNEL_RC_NO_MEMORY; - } + plugin->data_in = StreamPool_Take(plugin->pool, totalLength); + + Stream_SetPosition(plugin->data_in, 0); } - s = plugin->data_in; - - if (!Stream_EnsureRemainingCapacity(s, (int) dataLength)) - { - WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + if (!Stream_EnsureRemainingCapacity(plugin->data_in, dataLength)) return CHANNEL_RC_NO_MEMORY; - } - Stream_Write(s, pData, dataLength); + Stream_Write(plugin->data_in, pData, dataLength); if (dataFlags & CHANNEL_FLAG_LAST) { - if (Stream_Capacity(s) != Stream_GetPosition(s)) + Stream_SealLength(plugin->data_in); + Stream_SetPosition(plugin->data_in, 0); + + if (!Queue_Enqueue(plugin->queue, plugin->data_in)) { - WLog_ERR(TAG, "rdpsnd_virtual_channel_event_data_received: read error"); + WLog_ERR(TAG, "Queue_Enqueue failed!"); return ERROR_INTERNAL_ERROR; } plugin->data_in = NULL; - Stream_SealLength(s); - Stream_SetPosition(s, 0); - - if (!MessageQueue_Post(plugin->MsgPipe->In, NULL, 0, (void*) s, NULL)) - { - WLog_ERR(TAG, "MessageQueue_Post failed!"); - return ERROR_INTERNAL_ERROR; - } } return CHANNEL_RC_OK; @@ -1273,10 +1000,10 @@ static VOID VCAPITYPE rdpsnd_virtual_channel_open_event_ex(LPVOID lpUserParam, D static DWORD WINAPI rdpsnd_virtual_channel_client_thread(LPVOID arg) { - wStream* data; - wMessage message; + BOOL running = TRUE; rdpsndPlugin* rdpsnd = (rdpsndPlugin*) arg; - UINT error; + DWORD error = CHANNEL_RC_OK; + HANDLE events[2]; if ((error = rdpsnd_process_connect(rdpsnd))) { @@ -1284,36 +1011,32 @@ static DWORD WINAPI rdpsnd_virtual_channel_client_thread(LPVOID arg) goto out; } - while (1) + events[1] = rdpsnd->stopEvent; + events[0] = Queue_Event(rdpsnd->queue); + + do { - if (!MessageQueue_Wait(rdpsnd->MsgPipe->In)) + const DWORD status = WaitForMultipleObjects(ARRAYSIZE(events), events, FALSE, INFINITE); + + switch (status) { - WLog_ERR(TAG, "MessageQueue_Wait failed!"); - error = ERROR_INTERNAL_ERROR; - break; - } - - if (!MessageQueue_Peek(rdpsnd->MsgPipe->In, &message, TRUE)) - { - WLog_ERR(TAG, "MessageQueue_Peek failed!"); - error = ERROR_INTERNAL_ERROR; - break; - } - - if (message.id == WMQ_QUIT) - break; - - if (message.id == 0) - { - data = (wStream*) message.wParam; - - if ((error = rdpsnd_recv_pdu(rdpsnd, data))) - { - WLog_ERR(TAG, "error treating sound channel message"); + case WAIT_OBJECT_0: + { + wStream* s = Queue_Dequeue(rdpsnd->queue); + error = rdpsnd_recv_pdu(rdpsnd, s); + } + break; + + case WAIT_OBJECT_0 + 1: + running = FALSE; + break; + + default: + error = status; break; - } } } + while ((error == CHANNEL_RC_OK) && running); out: @@ -1322,10 +1045,19 @@ out: "rdpsnd_virtual_channel_client_thread reported an error"); rdpsnd_process_disconnect(rdpsnd); - ExitThread(error); + ExitThread((DWORD)error); return error; } +/* Called during cleanup. + * All streams still in the queue have been removed + * from the streampool and nead cleanup. */ +static void rdpsnd_queue_free(void* data) +{ + wStream* s = (wStream*)data; + Stream_Free(s, TRUE); +} + /** * Function description * @@ -1346,27 +1078,47 @@ static UINT rdpsnd_virtual_channel_event_connected(rdpsndPlugin* rdpsnd, return status; } - rdpsnd->MsgPipe = MessagePipe_New(); + rdpsnd->dsp_context = freerdp_dsp_context_new(FALSE); - if (!rdpsnd->MsgPipe) - { - WLog_ERR(TAG, "unable to create message pipe"); - return CHANNEL_RC_NO_MEMORY; - } + if (!rdpsnd->dsp_context) + goto fail; + + rdpsnd->queue = Queue_New(TRUE, 32, 2); + + if (!rdpsnd->queue) + goto fail; + + rdpsnd->queue->object.fnObjectFree = rdpsnd_queue_free; + rdpsnd->pool = StreamPool_New(TRUE, 4096); + + if (!rdpsnd->pool) + goto fail; + + rdpsnd->stopEvent = CreateEventA(NULL, TRUE, FALSE, "rdpsnd->stopEvent"); + + if (!rdpsnd->stopEvent) + goto fail; rdpsnd->thread = CreateThread(NULL, 0, - rdpsnd_virtual_channel_client_thread, (void*) rdpsnd, + rdpsnd_virtual_channel_client_thread, (void*) rdpsnd, 0, NULL); if (!rdpsnd->thread) - { - WLog_ERR(TAG, "unable to create thread"); - MessagePipe_Free(rdpsnd->MsgPipe); - rdpsnd->MsgPipe = NULL; - return ERROR_INTERNAL_ERROR; - } + goto fail; return CHANNEL_RC_OK; +fail: + freerdp_dsp_context_free(rdpsnd->dsp_context); + StreamPool_Free(rdpsnd->pool); + Queue_Free(rdpsnd->queue); + + if (rdpsnd->stopEvent) + CloseHandle(rdpsnd->stopEvent); + + if (rdpsnd->thread) + CloseHandle(rdpsnd->thread); + + return CHANNEL_RC_NO_MEMORY; } /** @@ -1377,7 +1129,7 @@ static UINT rdpsnd_virtual_channel_event_connected(rdpsndPlugin* rdpsnd, static UINT rdpsnd_virtual_channel_event_disconnected(rdpsndPlugin* rdpsnd) { UINT error; - MessagePipe_PostQuit(rdpsnd->MsgPipe, 0); + SetEvent(rdpsnd->stopEvent); if (WaitForSingleObject(rdpsnd->thread, INFINITE) == WAIT_FAILED) { @@ -1387,7 +1139,7 @@ static UINT rdpsnd_virtual_channel_event_disconnected(rdpsndPlugin* rdpsnd) } CloseHandle(rdpsnd->thread); - rdpsnd->thread = NULL; + CloseHandle(rdpsnd->stopEvent); error = rdpsnd->channelEntryPoints.pVirtualChannelCloseEx(rdpsnd->InitHandle, rdpsnd->OpenHandle); if (CHANNEL_RC_OK != error) @@ -1398,15 +1150,10 @@ static UINT rdpsnd_virtual_channel_event_disconnected(rdpsndPlugin* rdpsnd) } rdpsnd->OpenHandle = 0; - - if (rdpsnd->data_in) - { - Stream_Free(rdpsnd->data_in, TRUE); - rdpsnd->data_in = NULL; - } - - MessagePipe_Free(rdpsnd->MsgPipe); - rdpsnd->MsgPipe = NULL; + freerdp_dsp_context_free(rdpsnd->dsp_context); + StreamPool_Return(rdpsnd->pool, rdpsnd->data_in); + StreamPool_Free(rdpsnd->pool); + Queue_Free(rdpsnd->queue); rdpsnd_free_audio_formats(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats); rdpsnd->NumberOfClientFormats = 0; rdpsnd->ClientFormats = NULL; @@ -1420,24 +1167,16 @@ static UINT rdpsnd_virtual_channel_event_disconnected(rdpsndPlugin* rdpsnd) rdpsnd->device = NULL; } - if (rdpsnd->subsystem) - { - free(rdpsnd->subsystem); - rdpsnd->subsystem = NULL; - } - - if (rdpsnd->device_name) - { - free(rdpsnd->device_name); - rdpsnd->device_name = NULL; - } - + free(rdpsnd->subsystem); + free(rdpsnd->device_name); return CHANNEL_RC_OK; } static void rdpsnd_virtual_channel_event_terminated(rdpsndPlugin* rdpsnd) { - rdpsnd->InitHandle = 0; + if (rdpsnd) + rdpsnd->InitHandle = 0; + free(rdpsnd); } @@ -1500,27 +1239,14 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx; if (!pEntryPoints) - { return FALSE; - } rdpsnd = (rdpsndPlugin*) calloc(1, sizeof(rdpsndPlugin)); if (!rdpsnd) - { - WLog_ERR(TAG, "calloc failed!"); return FALSE; - } rdpsnd->attached = TRUE; -#if !defined(_WIN32) && !defined(ANDROID) - { - sigset_t mask; - sigemptyset(&mask); - sigaddset(&mask, SIGIO); - pthread_sigmask(SIG_BLOCK, &mask, NULL); - } -#endif rdpsnd->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP; diff --git a/channels/rdpsnd/client/rdpsnd_main.h b/channels/rdpsnd/client/rdpsnd_main.h index 81cb426be..aee865816 100644 --- a/channels/rdpsnd/client/rdpsnd_main.h +++ b/channels/rdpsnd/client/rdpsnd_main.h @@ -35,6 +35,4 @@ #define DEBUG_SND(...) do { } while (0) #endif -UINT rdpsnd_virtual_channel_write(rdpsndPlugin* rdpsnd, wStream* s); - #endif /* FREERDP_CHANNEL_RDPSND_CLIENT_MAIN_H */ diff --git a/channels/rdpsnd/client/winmm/rdpsnd_winmm.c b/channels/rdpsnd/client/winmm/rdpsnd_winmm.c index 9c24c43d5..bc8895456 100644 --- a/channels/rdpsnd/client/winmm/rdpsnd_winmm.c +++ b/channels/rdpsnd/client/winmm/rdpsnd_winmm.c @@ -36,7 +36,6 @@ #include #include -#include #include #include "rdpsnd_main.h" @@ -49,15 +48,14 @@ struct rdpsnd_winmm_plugin HWAVEOUT hWaveOut; WAVEFORMATEX format; - int wformat; - int block_size; UINT32 volume; - FREERDP_DSP_CONTEXT* dsp_context; + HANDLE next; }; static BOOL rdpsnd_winmm_convert_format(const AUDIO_FORMAT* in, WAVEFORMATEX* out) { - BOOL result = FALSE; + if (!in || !out) + return FALSE; ZeroMemory(out, sizeof(WAVEFORMATEX)); out->wFormatTag = WAVE_FORMAT_PCM; @@ -68,40 +66,31 @@ static BOOL rdpsnd_winmm_convert_format(const AUDIO_FORMAT* in, WAVEFORMATEX* ou { case WAVE_FORMAT_PCM: out->wBitsPerSample = in->wBitsPerSample; - result = TRUE; break; - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - out->wBitsPerSample = 16; - result = TRUE; - break; + default: + return FALSE; } out->nBlockAlign = out->nChannels * out->wBitsPerSample / 8; out->nAvgBytesPerSec = out->nSamplesPerSec * out->nBlockAlign; - - return result; -} - -static BOOL rdpsnd_winmm_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) -{ - rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; - - if (format) - { - if (!rdpsnd_winmm_convert_format(format, &winmm->format)) - return FALSE; - - winmm->wformat = format->wFormatTag; - winmm->block_size = format->nBlockAlign; - } return TRUE; } -static void CALLBACK rdpsnd_winmm_callback_function(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) +static BOOL rdpsnd_winmm_set_format(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, + UINT32 latency) +{ + rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; + + if (!rdpsnd_winmm_convert_format(format, &winmm->format)) + return FALSE; + + return TRUE; +} + +static void CALLBACK rdpsnd_winmm_callback_function(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance, + DWORD_PTR dwParam1, DWORD_PTR dwParam2) { - RDPSND_WAVE* wave; LPWAVEHDR lpWaveHdr; rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) dwInstance; @@ -110,42 +99,27 @@ static void CALLBACK rdpsnd_winmm_callback_function(HWAVEOUT hwo, UINT uMsg, DWO case MM_WOM_OPEN: WLog_DBG(TAG, "MM_WOM_OPEN"); break; - + case MM_WOM_CLOSE: WLog_DBG(TAG, "MM_WOM_CLOSE"); + SetEvent(winmm->next); break; case MM_WOM_DONE: - { - UINT32 wTimeDelta; - lpWaveHdr = (LPWAVEHDR) dwParam1; + WLog_DBG(TAG, "MM_WOM_DONE"); + lpWaveHdr = (LPWAVEHDR) dwParam1; + free(lpWaveHdr); + SetEvent(winmm->next); + break; - if (!lpWaveHdr) - return; - - wave = (RDPSND_WAVE*) lpWaveHdr->dwUser; - - if (!wave) - return; - - WLog_DBG(TAG, "MM_WOM_DONE: dwBufferLength: %"PRIu32" cBlockNo: %"PRIu8"", - lpWaveHdr->dwBufferLength, wave->cBlockNo); - wave->wLocalTimeB = GetTickCount(); - wTimeDelta = wave->wLocalTimeB - wave->wLocalTimeA; - wave->wTimeStampB = wave->wTimeStampA + wTimeDelta; - - winmm->device.WaveConfirm(&(winmm->device), wave); - - free(lpWaveHdr->lpData); - free(lpWaveHdr); - - free(wave); - } + default: + WLog_DBG(TAG, "UNKNOWN [0x%08"PRIx32"]", uMsg); break; } } -static BOOL rdpsnd_winmm_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency) +static BOOL rdpsnd_winmm_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, + UINT32 latency) { MMRESULT mmResult; rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; @@ -153,15 +127,15 @@ static BOOL rdpsnd_winmm_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, if (winmm->hWaveOut) return TRUE; - rdpsnd_winmm_set_format(device, format, latency); - freerdp_dsp_context_reset_adpcm(winmm->dsp_context); + if (!rdpsnd_winmm_set_format(device, format, latency)) + return FALSE; mmResult = waveOutOpen(&winmm->hWaveOut, WAVE_MAPPER, &winmm->format, - (DWORD_PTR) rdpsnd_winmm_callback_function, (DWORD_PTR) winmm, CALLBACK_FUNCTION); + (DWORD_PTR) rdpsnd_winmm_callback_function, (DWORD_PTR) winmm, CALLBACK_FUNCTION); if (mmResult != MMSYSERR_NOERROR) { - WLog_ERR(TAG, "waveOutOpen failed: %"PRIu32"", mmResult); + WLog_ERR(TAG, "waveOutOpen failed: %"PRIu32"", mmResult); return FALSE; } @@ -169,7 +143,7 @@ static BOOL rdpsnd_winmm_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, if (mmResult != MMSYSERR_NOERROR) { - WLog_ERR(TAG, "waveOutSetVolume failed: %"PRIu32"", mmResult); + WLog_ERR(TAG, "waveOutSetVolume failed: %"PRIu32"", mmResult); return FALSE; } @@ -184,14 +158,13 @@ static void rdpsnd_winmm_close(rdpsndDevicePlugin* device) if (winmm->hWaveOut) { mmResult = waveOutReset(winmm->hWaveOut); - mmResult = waveOutClose(winmm->hWaveOut); if (mmResult != MMSYSERR_NOERROR) { WLog_ERR(TAG, "waveOutClose failure: %"PRIu32"", mmResult); } - + winmm->hWaveOut = NULL; } } @@ -203,14 +176,12 @@ static void rdpsnd_winmm_free(rdpsndDevicePlugin* device) if (winmm) { rdpsnd_winmm_close(device); - - freerdp_dsp_context_free(winmm->dsp_context); - + CloseHandle(winmm->next); free(winmm); } } -static BOOL rdpsnd_winmm_format_supported(rdpsndDevicePlugin* device, AUDIO_FORMAT* format) +static BOOL rdpsnd_winmm_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format) { MMRESULT result; WAVEFORMATEX out; @@ -231,9 +202,7 @@ static UINT32 rdpsnd_winmm_get_volume(rdpsndDevicePlugin* device) DWORD dwVolume; UINT16 dwVolumeLeft; UINT16 dwVolumeRight; - rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; - dwVolumeLeft = ((50 * 0xFFFF) / 100); /* 50% */ dwVolumeRight = ((50 * 0xFFFF) / 100); /* 50% */ dwVolume = (dwVolumeLeft << 16) | dwVolumeRight; @@ -242,14 +211,12 @@ static UINT32 rdpsnd_winmm_get_volume(rdpsndDevicePlugin* device) return dwVolume; waveOutGetVolume(winmm->hWaveOut, &dwVolume); - return dwVolume; } static BOOL rdpsnd_winmm_set_volume(rdpsndDevicePlugin* device, UINT32 value) { rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; - winmm->volume = value; if (!winmm->hWaveOut) @@ -258,72 +225,38 @@ static BOOL rdpsnd_winmm_set_volume(rdpsndDevicePlugin* device, UINT32 value) return (waveOutSetVolume(winmm->hWaveOut, value) == MMSYSERR_NOERROR); } -static BOOL rdpsnd_winmm_wave_decode(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) +static void rdpsnd_winmm_start(rdpsndDevicePlugin* device) { - int length; - BYTE* data; - rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; - - if (winmm->wformat == WAVE_FORMAT_ADPCM) - { - winmm->dsp_context->decode_ms_adpcm(winmm->dsp_context, - wave->data, wave->length, winmm->format.nChannels, winmm->block_size); - length = winmm->dsp_context->adpcm_size; - data = winmm->dsp_context->adpcm_buffer; - } - else if (winmm->wformat == WAVE_FORMAT_DVI_ADPCM) - { - winmm->dsp_context->decode_ima_adpcm(winmm->dsp_context, - wave->data, wave->length, winmm->format.nChannels, winmm->block_size); - length = winmm->dsp_context->adpcm_size; - data = winmm->dsp_context->adpcm_buffer; - } - else - { - length = wave->length; - data = wave->data; - } - - wave->data = (BYTE*) malloc(length); - if (!wave->data) - return FALSE; - CopyMemory(wave->data, data, length); - wave->length = length; - - return TRUE; + //rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; } -void rdpsnd_winmm_wave_play(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) +static UINT rdpsnd_winmm_play(rdpsndDevicePlugin* device, const BYTE* data, size_t size) { MMRESULT mmResult; LPWAVEHDR lpWaveHdr; rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; if (!winmm->hWaveOut) - return; - - wave->AutoConfirm = FALSE; + return 0; lpWaveHdr = (LPWAVEHDR) malloc(sizeof(WAVEHDR)); if (!lpWaveHdr) - return; + return 0; ZeroMemory(lpWaveHdr, sizeof(WAVEHDR)); - lpWaveHdr->dwFlags = 0; lpWaveHdr->dwLoops = 0; - lpWaveHdr->lpData = (LPSTR) wave->data; - lpWaveHdr->dwBufferLength = wave->length; - lpWaveHdr->dwUser = (DWORD_PTR) wave; + lpWaveHdr->lpData = (LPSTR) data; + lpWaveHdr->dwBufferLength = size; + lpWaveHdr->dwUser = NULL; lpWaveHdr->lpNext = NULL; - mmResult = waveOutPrepareHeader(winmm->hWaveOut, lpWaveHdr, sizeof(WAVEHDR)); if (mmResult != MMSYSERR_NOERROR) { WLog_ERR(TAG, "waveOutPrepareHeader failure: %"PRIu32"", mmResult); - return; + return 0; } mmResult = waveOutWrite(winmm->hWaveOut, lpWaveHdr, sizeof(WAVEHDR)); @@ -333,18 +266,16 @@ void rdpsnd_winmm_wave_play(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) WLog_ERR(TAG, "waveOutWrite failure: %"PRIu32"", mmResult); waveOutUnprepareHeader(winmm->hWaveOut, lpWaveHdr, sizeof(WAVEHDR)); free(lpWaveHdr); - return; + return 0; } -} -static void rdpsnd_winmm_start(rdpsndDevicePlugin* device) -{ - //rdpsndWinmmPlugin* winmm = (rdpsndWinmmPlugin*) device; + WaitForSingleObject(winmm->next, INFINITE); + + return 10; /* TODO: Get real latencry in [ms] */ } static void rdpsnd_winmm_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* args) { - } #ifdef BUILTIN_CHANNELS @@ -362,38 +293,30 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p { ADDIN_ARGV* args; rdpsndWinmmPlugin* winmm; - winmm = (rdpsndWinmmPlugin*) calloc(1, sizeof(rdpsndWinmmPlugin)); if (!winmm) return CHANNEL_RC_NO_MEMORY; - winmm->device.DisableConfirmThread = TRUE; - winmm->device.Open = rdpsnd_winmm_open; winmm->device.FormatSupported = rdpsnd_winmm_format_supported; - winmm->device.SetFormat = rdpsnd_winmm_set_format; winmm->device.GetVolume = rdpsnd_winmm_get_volume; winmm->device.SetVolume = rdpsnd_winmm_set_volume; - winmm->device.WaveDecode = rdpsnd_winmm_wave_decode; - winmm->device.WavePlay = rdpsnd_winmm_wave_play; winmm->device.Start = rdpsnd_winmm_start; + winmm->device.Play = rdpsnd_winmm_play; winmm->device.Close = rdpsnd_winmm_close; winmm->device.Free = rdpsnd_winmm_free; + winmm->next = CreateEventA(NULL, FALSE, FALSE, "winmm-play-event"); - args = pEntryPoints->args; - rdpsnd_winmm_parse_addin_args((rdpsndDevicePlugin*) winmm, args); - - winmm->dsp_context = freerdp_dsp_context_new(); - if (!winmm->dsp_context) + if (!winmm->next) { free(winmm); return CHANNEL_RC_NO_MEMORY; } + args = pEntryPoints->args; + rdpsnd_winmm_parse_addin_args((rdpsndDevicePlugin*) winmm, args); winmm->volume = 0xFFFFFFFF; - pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*) winmm); - return CHANNEL_RC_OK; } diff --git a/channels/rdpsnd/server/rdpsnd_main.c b/channels/rdpsnd/server/rdpsnd_main.c index b144e53b0..6c565e9a1 100644 --- a/channels/rdpsnd/server/rdpsnd_main.c +++ b/channels/rdpsnd/server/rdpsnd_main.c @@ -246,7 +246,6 @@ static DWORD WINAPI rdpsnd_server_thread(LPVOID arg) RdpsndServerContext* context; UINT error = CHANNEL_RC_OK; context = (RdpsndServerContext*)arg; - nCount = 0; events[nCount++] = context->priv->channelEvent; events[nCount++] = context->priv->StopEvent; @@ -393,7 +392,7 @@ static UINT rdpsnd_server_select_format(RdpsndServerContext* context, context->priv->out_buffer_size = out_buffer_size; } - freerdp_dsp_context_reset_adpcm(context->priv->dsp_context); + freerdp_dsp_context_reset(context->priv->dsp_context, format); out: LeaveCriticalSection(&context->priv->lock); return error; @@ -408,103 +407,55 @@ out: static UINT rdpsnd_server_send_audio_pdu(RdpsndServerContext* context, UINT16 wTimestamp) { - int size; - BYTE* src; - int frames; - int fill_size; + size_t length; + size_t start, end = 0; + const BYTE* src; BOOL status; AUDIO_FORMAT* format; - int tbytes_per_frame; ULONG written; wStream* s = context->priv->rdpsnd_pdu; UINT error = CHANNEL_RC_OK; format = &context->client_formats[context->selected_client_format]; - tbytes_per_frame = format->nChannels * context->priv->src_bytes_per_sample; - - if ((format->nSamplesPerSec == context->src_format.nSamplesPerSec) && - (format->nChannels == context->src_format.nChannels)) - { - src = context->priv->out_buffer; - frames = context->priv->out_pending_frames; - } - else - { - context->priv->dsp_context->resample(context->priv->dsp_context, - context->priv->out_buffer, - context->priv->src_bytes_per_sample, context->src_format.nChannels, - context->src_format.nSamplesPerSec, context->priv->out_pending_frames, - format->nChannels, format->nSamplesPerSec); - frames = context->priv->dsp_context->resampled_frames; - src = context->priv->dsp_context->resampled_buffer; - } - - size = frames * tbytes_per_frame; - - if (format->wFormatTag == WAVE_FORMAT_DVI_ADPCM) - { - context->priv->dsp_context->encode_ima_adpcm(context->priv->dsp_context, - src, size, format->nChannels, format->nBlockAlign); - src = context->priv->dsp_context->adpcm_buffer; - size = context->priv->dsp_context->adpcm_size; - } - else if (format->wFormatTag == WAVE_FORMAT_ADPCM) - { - context->priv->dsp_context->encode_ms_adpcm(context->priv->dsp_context, - src, size, format->nChannels, format->nBlockAlign); - src = context->priv->dsp_context->adpcm_buffer; - size = context->priv->dsp_context->adpcm_size; - } - - context->block_no = (context->block_no + 1) % 256; - /* Fill to nBlockAlign for the last audio packet */ - fill_size = 0; - - if ((format->wFormatTag == WAVE_FORMAT_DVI_ADPCM - || format->wFormatTag == WAVE_FORMAT_ADPCM) && - (context->priv->out_pending_frames < context->priv->out_frames) - && ((size % format->nBlockAlign) != 0)) - { - fill_size = format->nBlockAlign - (size % format->nBlockAlign); - } /* WaveInfo PDU */ Stream_SetPosition(s, 0); Stream_Write_UINT8(s, SNDC_WAVE); /* msgType */ Stream_Write_UINT8(s, 0); /* bPad */ - Stream_Write_UINT16(s, size + fill_size + 8); /* BodySize */ + Stream_Write_UINT16(s, 0); /* BodySize */ Stream_Write_UINT16(s, wTimestamp); /* wTimeStamp */ Stream_Write_UINT16(s, context->selected_client_format); /* wFormatNo */ Stream_Write_UINT8(s, context->block_no); /* cBlockNo */ Stream_Seek(s, 3); /* bPad */ - Stream_Write(s, src, 4); - status = WTSVirtualChannelWrite(context->priv->ChannelHandle, - (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written); + start = Stream_GetPosition(s); + src = context->priv->out_buffer; + length = context->priv->out_pending_frames * context->priv->src_bytes_per_frame; - if (!status) + if (!freerdp_dsp_encode(context->priv->dsp_context, format, src, length, s)) + status = ERROR_INTERNAL_ERROR; + else + { + /* Set stream size */ + end = Stream_GetPosition(s); + Stream_SetPosition(s, 2); + Stream_Write_UINT16(s, end - start + 8); + Stream_SetPosition(s, end); + context->block_no = (context->block_no + 1) % 256; + status = WTSVirtualChannelWrite(context->priv->ChannelHandle, + (PCHAR) Stream_Buffer(s), start + 4, &written); + } + + if (status != CHANNEL_RC_OK) { WLog_ERR(TAG, "WTSVirtualChannelWrite failed!"); error = ERROR_INTERNAL_ERROR; goto out; } - Stream_SetPosition(s, 0); - - /* Wave PDU */ - if (!Stream_EnsureRemainingCapacity(s, size + fill_size)) - { - WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); - error = CHANNEL_RC_NO_MEMORY; - goto out; - } - + Stream_SetPosition(s, start); Stream_Write_UINT32(s, 0); /* bPad */ - Stream_Write(s, src + 4, size - 4); - - if (fill_size > 0) - Stream_Zero(s, fill_size); - + Stream_SetPosition(s, start); status = WTSVirtualChannelWrite(context->priv->ChannelHandle, - (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written); + (PCHAR) Stream_Pointer(s), end - start, &written); if (!status) { @@ -578,7 +529,6 @@ static UINT rdpsnd_server_set_volume(RdpsndServerContext* context, int left, BOOL status; ULONG written; wStream* s = context->priv->rdpsnd_pdu; - Stream_Write_UINT8(s, SNDC_SETVOLUME); Stream_Write_UINT8(s, 0); Stream_Seek_UINT16(s); @@ -790,7 +740,7 @@ RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm) goto out_free; } - priv->dsp_context = freerdp_dsp_context_new(); + priv->dsp_context = freerdp_dsp_context_new(TRUE); if (!priv->dsp_context) { diff --git a/channels/tsmf/client/alsa/tsmf_alsa.c b/channels/tsmf/client/alsa/tsmf_alsa.c index 78a0a6694..3cf821b60 100644 --- a/channels/tsmf/client/alsa/tsmf_alsa.c +++ b/channels/tsmf/client/alsa/tsmf_alsa.c @@ -40,33 +40,34 @@ typedef struct _TSMFALSAAudioDevice ITSMFAudioDevice iface; char device[32]; - snd_pcm_t *out_handle; + snd_pcm_t* out_handle; UINT32 source_rate; UINT32 actual_rate; UINT32 source_channels; UINT32 actual_channels; UINT32 bytes_per_sample; - - FREERDP_DSP_CONTEXT *dsp_context; } TSMFAlsaAudioDevice; -static BOOL tsmf_alsa_open_device(TSMFAlsaAudioDevice *alsa) +static BOOL tsmf_alsa_open_device(TSMFAlsaAudioDevice* alsa) { int error; error = snd_pcm_open(&alsa->out_handle, alsa->device, SND_PCM_STREAM_PLAYBACK, 0); - if(error < 0) + + if (error < 0) { WLog_ERR(TAG, "failed to open device %s", alsa->device); return FALSE; } + DEBUG_TSMF("open device %s", alsa->device); return TRUE; } -static BOOL tsmf_alsa_open(ITSMFAudioDevice *audio, const char *device) +static BOOL tsmf_alsa_open(ITSMFAudioDevice* audio, const char* device) { - TSMFAlsaAudioDevice *alsa = (TSMFAlsaAudioDevice *) audio; - if(!device) + TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio; + + if (!device) { strncpy(alsa->device, "default", sizeof(alsa->device)); } @@ -74,114 +75,109 @@ static BOOL tsmf_alsa_open(ITSMFAudioDevice *audio, const char *device) { strncpy(alsa->device, device, sizeof(alsa->device) - 1); } + return tsmf_alsa_open_device(alsa); } -static BOOL tsmf_alsa_set_format(ITSMFAudioDevice *audio, - UINT32 sample_rate, UINT32 channels, UINT32 bits_per_sample) +static BOOL tsmf_alsa_set_format(ITSMFAudioDevice* audio, + UINT32 sample_rate, UINT32 channels, UINT32 bits_per_sample) { int error; snd_pcm_uframes_t frames; - snd_pcm_hw_params_t *hw_params; - snd_pcm_sw_params_t *sw_params; - TSMFAlsaAudioDevice *alsa = (TSMFAlsaAudioDevice *) audio; - if(!alsa->out_handle) + snd_pcm_hw_params_t* hw_params; + snd_pcm_sw_params_t* sw_params; + TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio; + + if (!alsa->out_handle) return FALSE; + snd_pcm_drop(alsa->out_handle); alsa->actual_rate = alsa->source_rate = sample_rate; alsa->actual_channels = alsa->source_channels = channels; alsa->bytes_per_sample = bits_per_sample / 8; error = snd_pcm_hw_params_malloc(&hw_params); - if(error < 0) + + if (error < 0) { WLog_ERR(TAG, "snd_pcm_hw_params_malloc failed"); return FALSE; } + snd_pcm_hw_params_any(alsa->out_handle, hw_params); snd_pcm_hw_params_set_access(alsa->out_handle, hw_params, - SND_PCM_ACCESS_RW_INTERLEAVED); + SND_PCM_ACCESS_RW_INTERLEAVED); snd_pcm_hw_params_set_format(alsa->out_handle, hw_params, - SND_PCM_FORMAT_S16_LE); + SND_PCM_FORMAT_S16_LE); snd_pcm_hw_params_set_rate_near(alsa->out_handle, hw_params, - &alsa->actual_rate, NULL); + &alsa->actual_rate, NULL); snd_pcm_hw_params_set_channels_near(alsa->out_handle, hw_params, - &alsa->actual_channels); + &alsa->actual_channels); frames = sample_rate; snd_pcm_hw_params_set_buffer_size_near(alsa->out_handle, hw_params, - &frames); + &frames); snd_pcm_hw_params(alsa->out_handle, hw_params); snd_pcm_hw_params_free(hw_params); error = snd_pcm_sw_params_malloc(&sw_params); - if(error < 0) + + if (error < 0) { WLog_ERR(TAG, "snd_pcm_sw_params_malloc"); return FALSE; } + snd_pcm_sw_params_current(alsa->out_handle, sw_params); snd_pcm_sw_params_set_start_threshold(alsa->out_handle, sw_params, - frames / 2); + frames / 2); snd_pcm_sw_params(alsa->out_handle, sw_params); snd_pcm_sw_params_free(sw_params); snd_pcm_prepare(alsa->out_handle); DEBUG_TSMF("sample_rate %"PRIu32" channels %"PRIu32" bits_per_sample %"PRIu32"", - sample_rate, channels, bits_per_sample); + sample_rate, channels, bits_per_sample); DEBUG_TSMF("hardware buffer %lu frames", frames); - if((alsa->actual_rate != alsa->source_rate) || - (alsa->actual_channels != alsa->source_channels)) + + if ((alsa->actual_rate != alsa->source_rate) || + (alsa->actual_channels != alsa->source_channels)) { DEBUG_TSMF("actual rate %"PRIu32" / channel %"PRIu32" is different " "from source rate %"PRIu32" / channel %"PRIu32", resampling required.", - alsa->actual_rate, alsa->actual_channels, - alsa->source_rate, alsa->source_channels); + alsa->actual_rate, alsa->actual_channels, + alsa->source_rate, alsa->source_channels); } + return TRUE; } -static BOOL tsmf_alsa_play(ITSMFAudioDevice *audio, BYTE *data, UINT32 data_size) +static BOOL tsmf_alsa_play(ITSMFAudioDevice* audio, const BYTE* src, UINT32 data_size) { int len; int error; int frames; - BYTE *end; - BYTE *src; - BYTE *pindex; + const BYTE* end; + const BYTE* pindex; int rbytes_per_frame; int sbytes_per_frame; - TSMFAlsaAudioDevice *alsa = (TSMFAlsaAudioDevice *) audio; + TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio; DEBUG_TSMF("data_size %"PRIu32"", data_size); - if(alsa->out_handle) + + if (alsa->out_handle) { sbytes_per_frame = alsa->source_channels * alsa->bytes_per_sample; rbytes_per_frame = alsa->actual_channels * alsa->bytes_per_sample; - if((alsa->source_rate == alsa->actual_rate) && - (alsa->source_channels == alsa->actual_channels)) - { - src = data; - } - else - { - alsa->dsp_context->resample(alsa->dsp_context, data, alsa->bytes_per_sample, - alsa->source_channels, alsa->source_rate, data_size / sbytes_per_frame, - alsa->actual_channels, alsa->actual_rate); - frames = alsa->dsp_context->resampled_frames; - DEBUG_TSMF("resampled %"PRIu32" frames at %"PRIu32" to %d frames at %"PRIu32"", - data_size / sbytes_per_frame, alsa->source_rate, frames, alsa->actual_rate); - data_size = frames * rbytes_per_frame; - src = alsa->dsp_context->resampled_buffer; - } pindex = src; end = pindex + data_size; - while(pindex < end) + + while (pindex < end) { len = end - pindex; frames = len / rbytes_per_frame; error = snd_pcm_writei(alsa->out_handle, pindex, frames); - if(error == -EPIPE) + + if (error == -EPIPE) { snd_pcm_recover(alsa->out_handle, error, 0); error = 0; } - else if(error < 0) + else if (error < 0) { DEBUG_TSMF("error len %d", error); snd_pcm_close(alsa->out_handle); @@ -189,45 +185,51 @@ static BOOL tsmf_alsa_play(ITSMFAudioDevice *audio, BYTE *data, UINT32 data_size tsmf_alsa_open_device(alsa); break; } + DEBUG_TSMF("%d frames played.", error); - if(error == 0) + + if (error == 0) break; + pindex += error * rbytes_per_frame; } } - free(data); + return TRUE; } -static UINT64 tsmf_alsa_get_latency(ITSMFAudioDevice *audio) +static UINT64 tsmf_alsa_get_latency(ITSMFAudioDevice* audio) { UINT64 latency = 0; snd_pcm_sframes_t frames = 0; - TSMFAlsaAudioDevice *alsa = (TSMFAlsaAudioDevice *) audio; - if(alsa->out_handle && alsa->actual_rate > 0 && - snd_pcm_delay(alsa->out_handle, &frames) == 0 && - frames > 0) + TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio; + + if (alsa->out_handle && alsa->actual_rate > 0 && + snd_pcm_delay(alsa->out_handle, &frames) == 0 && + frames > 0) { latency = ((UINT64)frames) * 10000000LL / (UINT64) alsa->actual_rate; } + return latency; } -static BOOL tsmf_alsa_flush(ITSMFAudioDevice *audio) +static BOOL tsmf_alsa_flush(ITSMFAudioDevice* audio) { return TRUE; } -static void tsmf_alsa_free(ITSMFAudioDevice *audio) +static void tsmf_alsa_free(ITSMFAudioDevice* audio) { - TSMFAlsaAudioDevice *alsa = (TSMFAlsaAudioDevice *) audio; + TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio; DEBUG_TSMF(""); - if(alsa->out_handle) + + if (alsa->out_handle) { snd_pcm_drain(alsa->out_handle); snd_pcm_close(alsa->out_handle); } - freerdp_dsp_context_free(alsa->dsp_context); + free(alsa); } @@ -237,10 +239,10 @@ static void tsmf_alsa_free(ITSMFAudioDevice *audio) #define freerdp_tsmf_client_audio_subsystem_entry FREERDP_API freerdp_tsmf_client_audio_subsystem_entry #endif -ITSMFAudioDevice *freerdp_tsmf_client_audio_subsystem_entry(void) +ITSMFAudioDevice* freerdp_tsmf_client_audio_subsystem_entry(void) { - TSMFAlsaAudioDevice *alsa; - alsa = (TSMFAlsaAudioDevice *) malloc(sizeof(TSMFAlsaAudioDevice)); + TSMFAlsaAudioDevice* alsa; + alsa = (TSMFAlsaAudioDevice*) malloc(sizeof(TSMFAlsaAudioDevice)); ZeroMemory(alsa, sizeof(TSMFAlsaAudioDevice)); alsa->iface.Open = tsmf_alsa_open; alsa->iface.SetFormat = tsmf_alsa_set_format; @@ -248,6 +250,5 @@ ITSMFAudioDevice *freerdp_tsmf_client_audio_subsystem_entry(void) alsa->iface.GetLatency = tsmf_alsa_get_latency; alsa->iface.Flush = tsmf_alsa_flush; alsa->iface.Free = tsmf_alsa_free; - alsa->dsp_context = freerdp_dsp_context_new(); - return (ITSMFAudioDevice *) alsa; + return (ITSMFAudioDevice*) alsa; } diff --git a/channels/tsmf/client/oss/tsmf_oss.c b/channels/tsmf/client/oss/tsmf_oss.c index db88ddbf7..67a792728 100644 --- a/channels/tsmf/client/oss/tsmf_oss.c +++ b/channels/tsmf/client/oss/tsmf_oss.c @@ -35,9 +35,9 @@ #include #include #if defined(__OpenBSD__) - #include +#include #else - #include +#include #endif #include @@ -129,7 +129,8 @@ static BOOL tsmf_oss_open(ITSMFAudioDevice* audio, const char* device) return TRUE; } -static BOOL tsmf_oss_set_format(ITSMFAudioDevice* audio, UINT32 sample_rate, UINT32 channels, UINT32 bits_per_sample) +static BOOL tsmf_oss_set_format(ITSMFAudioDevice* audio, UINT32 sample_rate, UINT32 channels, + UINT32 bits_per_sample) { int tmp; TSMFOssAudioDevice* oss = (TSMFOssAudioDevice*)audio; @@ -161,11 +162,11 @@ static BOOL tsmf_oss_set_format(ITSMFAudioDevice* audio, UINT32 sample_rate, UIN OSS_LOG_ERR("SNDCTL_DSP_SETFRAGMENT failed", errno); DEBUG_TSMF("sample_rate %"PRIu32" channels %"PRIu32" bits_per_sample %"PRIu32"", - sample_rate, channels, bits_per_sample); + sample_rate, channels, bits_per_sample); return TRUE; } -static BOOL tsmf_oss_play(ITSMFAudioDevice* audio, BYTE* data, UINT32 data_size) +static BOOL tsmf_oss_play(ITSMFAudioDevice* audio, const BYTE* data, UINT32 data_size) { int status; UINT32 offset; @@ -176,10 +177,7 @@ static BOOL tsmf_oss_play(ITSMFAudioDevice* audio, BYTE* data, UINT32 data_size) return FALSE; if (data == NULL || data_size == 0) - { - free(data); return TRUE; - } offset = 0; oss->data_size_last = data_size; @@ -191,14 +189,12 @@ static BOOL tsmf_oss_play(ITSMFAudioDevice* audio, BYTE* data, UINT32 data_size) if (status < 0) { OSS_LOG_ERR("write fail", errno); - free(data); return FALSE; } offset += status; } - free(data); return TRUE; } diff --git a/channels/tsmf/client/pulse/tsmf_pulse.c b/channels/tsmf/client/pulse/tsmf_pulse.c index e6da92509..b19f111f6 100644 --- a/channels/tsmf/client/pulse/tsmf_pulse.c +++ b/channels/tsmf/client/pulse/tsmf_pulse.c @@ -37,68 +37,81 @@ typedef struct _TSMFPulseAudioDevice ITSMFAudioDevice iface; char device[32]; - pa_threaded_mainloop *mainloop; - pa_context *context; + pa_threaded_mainloop* mainloop; + pa_context* context; pa_sample_spec sample_spec; - pa_stream *stream; + pa_stream* stream; } TSMFPulseAudioDevice; -static void tsmf_pulse_context_state_callback(pa_context *context, void *userdata) +static void tsmf_pulse_context_state_callback(pa_context* context, void* userdata) { - TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) userdata; + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) userdata; pa_context_state_t state; state = pa_context_get_state(context); - switch(state) + + switch (state) { case PA_CONTEXT_READY: DEBUG_TSMF("PA_CONTEXT_READY"); pa_threaded_mainloop_signal(pulse->mainloop, 0); break; + case PA_CONTEXT_FAILED: case PA_CONTEXT_TERMINATED: DEBUG_TSMF("state %d", state); pa_threaded_mainloop_signal(pulse->mainloop, 0); break; + default: DEBUG_TSMF("state %d", state); break; } } -static BOOL tsmf_pulse_connect(TSMFPulseAudioDevice *pulse) +static BOOL tsmf_pulse_connect(TSMFPulseAudioDevice* pulse) { pa_context_state_t state; - if(!pulse->context) + + if (!pulse->context) return FALSE; - if(pa_context_connect(pulse->context, NULL, 0, NULL)) + + if (pa_context_connect(pulse->context, NULL, 0, NULL)) { WLog_ERR(TAG, "pa_context_connect failed (%d)", - pa_context_errno(pulse->context)); + pa_context_errno(pulse->context)); return FALSE; } + pa_threaded_mainloop_lock(pulse->mainloop); - if(pa_threaded_mainloop_start(pulse->mainloop) < 0) + + if (pa_threaded_mainloop_start(pulse->mainloop) < 0) { pa_threaded_mainloop_unlock(pulse->mainloop); WLog_ERR(TAG, "pa_threaded_mainloop_start failed (%d)", - pa_context_errno(pulse->context)); + pa_context_errno(pulse->context)); return FALSE; } - for(;;) + + for (;;) { state = pa_context_get_state(pulse->context); - if(state == PA_CONTEXT_READY) + + if (state == PA_CONTEXT_READY) break; - if(!PA_CONTEXT_IS_GOOD(state)) + + if (!PA_CONTEXT_IS_GOOD(state)) { DEBUG_TSMF("bad context state (%d)", - pa_context_errno(pulse->context)); + pa_context_errno(pulse->context)); break; } + pa_threaded_mainloop_wait(pulse->mainloop); } + pa_threaded_mainloop_unlock(pulse->mainloop); - if(state == PA_CONTEXT_READY) + + if (state == PA_CONTEXT_READY) { DEBUG_TSMF("connected"); return TRUE; @@ -110,90 +123,104 @@ static BOOL tsmf_pulse_connect(TSMFPulseAudioDevice *pulse) } } -static BOOL tsmf_pulse_open(ITSMFAudioDevice *audio, const char *device) +static BOOL tsmf_pulse_open(ITSMFAudioDevice* audio, const char* device) { - TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio; - if(device) + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio; + + if (device) { strncpy(pulse->device, device, sizeof(pulse->device) - 1); } + pulse->mainloop = pa_threaded_mainloop_new(); - if(!pulse->mainloop) + + if (!pulse->mainloop) { WLog_ERR(TAG, "pa_threaded_mainloop_new failed"); return FALSE; } + pulse->context = pa_context_new(pa_threaded_mainloop_get_api(pulse->mainloop), "freerdp"); - if(!pulse->context) + + if (!pulse->context) { WLog_ERR(TAG, "pa_context_new failed"); return FALSE; } + pa_context_set_state_callback(pulse->context, tsmf_pulse_context_state_callback, pulse); - if(!tsmf_pulse_connect(pulse)) + + if (!tsmf_pulse_connect(pulse)) { WLog_ERR(TAG, "tsmf_pulse_connect failed"); return FALSE; } + DEBUG_TSMF("open device %s", pulse->device); return TRUE; } -static void tsmf_pulse_stream_success_callback(pa_stream *stream, int success, void *userdata) +static void tsmf_pulse_stream_success_callback(pa_stream* stream, int success, void* userdata) { - TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) userdata; + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) userdata; pa_threaded_mainloop_signal(pulse->mainloop, 0); } -static void tsmf_pulse_wait_for_operation(TSMFPulseAudioDevice *pulse, pa_operation *operation) +static void tsmf_pulse_wait_for_operation(TSMFPulseAudioDevice* pulse, pa_operation* operation) { - if(operation == NULL) + if (operation == NULL) return; - while(pa_operation_get_state(operation) == PA_OPERATION_RUNNING) + + while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) { pa_threaded_mainloop_wait(pulse->mainloop); } + pa_operation_unref(operation); } -static void tsmf_pulse_stream_state_callback(pa_stream *stream, void *userdata) +static void tsmf_pulse_stream_state_callback(pa_stream* stream, void* userdata) { - TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) userdata; + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) userdata; pa_stream_state_t state; state = pa_stream_get_state(stream); - switch(state) + + switch (state) { case PA_STREAM_READY: DEBUG_TSMF("PA_STREAM_READY"); pa_threaded_mainloop_signal(pulse->mainloop, 0); break; + case PA_STREAM_FAILED: case PA_STREAM_TERMINATED: DEBUG_TSMF("state %d", state); pa_threaded_mainloop_signal(pulse->mainloop, 0); break; + default: DEBUG_TSMF("state %d", state); break; } } -static void tsmf_pulse_stream_request_callback(pa_stream *stream, size_t length, void *userdata) +static void tsmf_pulse_stream_request_callback(pa_stream* stream, size_t length, void* userdata) { - TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) userdata; + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) userdata; DEBUG_TSMF("%"PRIdz"", length); pa_threaded_mainloop_signal(pulse->mainloop, 0); } -static BOOL tsmf_pulse_close_stream(TSMFPulseAudioDevice *pulse) +static BOOL tsmf_pulse_close_stream(TSMFPulseAudioDevice* pulse) { - if(!pulse->context || !pulse->stream) + if (!pulse->context || !pulse->stream) return FALSE; + DEBUG_TSMF(""); pa_threaded_mainloop_lock(pulse->mainloop); pa_stream_set_write_callback(pulse->stream, NULL, NULL); tsmf_pulse_wait_for_operation(pulse, - pa_stream_drain(pulse->stream, tsmf_pulse_stream_success_callback, pulse)); + pa_stream_drain(pulse->stream, tsmf_pulse_stream_success_callback, pulse)); pa_stream_disconnect(pulse->stream); pa_stream_unref(pulse->stream); pulse->stream = NULL; @@ -201,57 +228,68 @@ static BOOL tsmf_pulse_close_stream(TSMFPulseAudioDevice *pulse) return TRUE; } -static BOOL tsmf_pulse_open_stream(TSMFPulseAudioDevice *pulse) +static BOOL tsmf_pulse_open_stream(TSMFPulseAudioDevice* pulse) { pa_stream_state_t state; pa_buffer_attr buffer_attr = { 0 }; - if(!pulse->context) + + if (!pulse->context) return FALSE; + DEBUG_TSMF(""); pa_threaded_mainloop_lock(pulse->mainloop); pulse->stream = pa_stream_new(pulse->context, "freerdp", - &pulse->sample_spec, NULL); - if(!pulse->stream) + &pulse->sample_spec, NULL); + + if (!pulse->stream) { pa_threaded_mainloop_unlock(pulse->mainloop); WLog_ERR(TAG, "pa_stream_new failed (%d)", - pa_context_errno(pulse->context)); + pa_context_errno(pulse->context)); return FALSE; } + pa_stream_set_state_callback(pulse->stream, - tsmf_pulse_stream_state_callback, pulse); + tsmf_pulse_stream_state_callback, pulse); pa_stream_set_write_callback(pulse->stream, - tsmf_pulse_stream_request_callback, pulse); + tsmf_pulse_stream_request_callback, pulse); buffer_attr.maxlength = pa_usec_to_bytes(500000, &pulse->sample_spec); buffer_attr.tlength = pa_usec_to_bytes(250000, &pulse->sample_spec); - buffer_attr.prebuf = (UINT32) -1; - buffer_attr.minreq = (UINT32) -1; - buffer_attr.fragsize = (UINT32) -1; - if(pa_stream_connect_playback(pulse->stream, - pulse->device[0] ? pulse->device : NULL, &buffer_attr, - PA_STREAM_ADJUST_LATENCY | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE, - NULL, NULL) < 0) + buffer_attr.prebuf = (UINT32) - 1; + buffer_attr.minreq = (UINT32) - 1; + buffer_attr.fragsize = (UINT32) - 1; + + if (pa_stream_connect_playback(pulse->stream, + pulse->device[0] ? pulse->device : NULL, &buffer_attr, + PA_STREAM_ADJUST_LATENCY | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE, + NULL, NULL) < 0) { pa_threaded_mainloop_unlock(pulse->mainloop); WLog_ERR(TAG, "pa_stream_connect_playback failed (%d)", - pa_context_errno(pulse->context)); + pa_context_errno(pulse->context)); return FALSE; } - for(;;) + + for (;;) { state = pa_stream_get_state(pulse->stream); - if(state == PA_STREAM_READY) + + if (state == PA_STREAM_READY) break; - if(!PA_STREAM_IS_GOOD(state)) + + if (!PA_STREAM_IS_GOOD(state)) { WLog_ERR(TAG, "bad stream state (%d)", - pa_context_errno(pulse->context)); + pa_context_errno(pulse->context)); break; } + pa_threaded_mainloop_wait(pulse->mainloop); } + pa_threaded_mainloop_unlock(pulse->mainloop); - if(state == PA_STREAM_READY) + + if (state == PA_STREAM_READY) { DEBUG_TSMF("connected"); return TRUE; @@ -263,118 +301,133 @@ static BOOL tsmf_pulse_open_stream(TSMFPulseAudioDevice *pulse) } } -static BOOL tsmf_pulse_set_format(ITSMFAudioDevice *audio, - UINT32 sample_rate, UINT32 channels, UINT32 bits_per_sample) +static BOOL tsmf_pulse_set_format(ITSMFAudioDevice* audio, + UINT32 sample_rate, UINT32 channels, UINT32 bits_per_sample) { - TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio; + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio; DEBUG_TSMF("sample_rate %"PRIu32" channels %"PRIu32" bits_per_sample %"PRIu32"", - sample_rate, channels, bits_per_sample); + sample_rate, channels, bits_per_sample); pulse->sample_spec.rate = sample_rate; pulse->sample_spec.channels = channels; pulse->sample_spec.format = PA_SAMPLE_S16LE; return tsmf_pulse_open_stream(pulse); } -static BOOL tsmf_pulse_play(ITSMFAudioDevice *audio, BYTE *data, UINT32 data_size) +static BOOL tsmf_pulse_play(ITSMFAudioDevice* audio, const BYTE* data, UINT32 data_size) { - TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio; - BYTE *src; + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio; + const BYTE* src; int len; int ret; DEBUG_TSMF("data_size %"PRIu32"", data_size); - if(pulse->stream) + + if (pulse->stream) { pa_threaded_mainloop_lock(pulse->mainloop); src = data; - while(data_size > 0) + + while (data_size > 0) { - while((len = pa_stream_writable_size(pulse->stream)) == 0) + while ((len = pa_stream_writable_size(pulse->stream)) == 0) { DEBUG_TSMF("waiting"); pa_threaded_mainloop_wait(pulse->mainloop); } - if(len < 0) + + if (len < 0) break; - if(len > data_size) + + if (len > data_size) len = data_size; + ret = pa_stream_write(pulse->stream, src, len, NULL, 0LL, PA_SEEK_RELATIVE); - if(ret < 0) + + if (ret < 0) { DEBUG_TSMF("pa_stream_write failed (%d)", - pa_context_errno(pulse->context)); + pa_context_errno(pulse->context)); break; } + src += len; data_size -= len; } + pa_threaded_mainloop_unlock(pulse->mainloop); } - free(data); + return TRUE; } -static UINT64 tsmf_pulse_get_latency(ITSMFAudioDevice *audio) +static UINT64 tsmf_pulse_get_latency(ITSMFAudioDevice* audio) { pa_usec_t usec; UINT64 latency = 0; - TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio; - if(pulse->stream && pa_stream_get_latency(pulse->stream, &usec, NULL) == 0) + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio; + + if (pulse->stream && pa_stream_get_latency(pulse->stream, &usec, NULL) == 0) { latency = ((UINT64)usec) * 10LL; } + return latency; } -static BOOL tsmf_pulse_flush(ITSMFAudioDevice *audio) +static BOOL tsmf_pulse_flush(ITSMFAudioDevice* audio) { - TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio; + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio; pa_threaded_mainloop_lock(pulse->mainloop); tsmf_pulse_wait_for_operation(pulse, - pa_stream_flush(pulse->stream, tsmf_pulse_stream_success_callback, pulse)); + pa_stream_flush(pulse->stream, tsmf_pulse_stream_success_callback, pulse)); pa_threaded_mainloop_unlock(pulse->mainloop); return TRUE; } -static void tsmf_pulse_free(ITSMFAudioDevice *audio) +static void tsmf_pulse_free(ITSMFAudioDevice* audio) { - TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio; + TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio; DEBUG_TSMF(""); tsmf_pulse_close_stream(pulse); - if(pulse->mainloop) + + if (pulse->mainloop) { pa_threaded_mainloop_stop(pulse->mainloop); } - if(pulse->context) + + if (pulse->context) { pa_context_disconnect(pulse->context); pa_context_unref(pulse->context); pulse->context = NULL; } - if(pulse->mainloop) + + if (pulse->mainloop) { pa_threaded_mainloop_free(pulse->mainloop); pulse->mainloop = NULL; } + free(pulse); } #ifdef BUILTIN_CHANNELS -ITSMFAudioDevice *pulse_freerdp_tsmf_client_audio_subsystem_entry(void) +ITSMFAudioDevice* pulse_freerdp_tsmf_client_audio_subsystem_entry(void) #else -FREERDP_API ITSMFAudioDevice *freerdp_tsmf_client_audio_subsystem_entry(void) +FREERDP_API ITSMFAudioDevice* freerdp_tsmf_client_audio_subsystem_entry(void) #endif { - TSMFPulseAudioDevice *pulse; + TSMFPulseAudioDevice* pulse; + pulse = (TSMFPulseAudioDevice*) calloc(1, sizeof(TSMFPulseAudioDevice)); - pulse = (TSMFPulseAudioDevice *) calloc(1, sizeof(TSMFPulseAudioDevice)); if (!pulse) return NULL; + pulse->iface.Open = tsmf_pulse_open; pulse->iface.SetFormat = tsmf_pulse_set_format; pulse->iface.Play = tsmf_pulse_play; pulse->iface.GetLatency = tsmf_pulse_get_latency; pulse->iface.Flush = tsmf_pulse_flush; pulse->iface.Free = tsmf_pulse_free; - return (ITSMFAudioDevice *) pulse; + return (ITSMFAudioDevice*) pulse; } diff --git a/channels/tsmf/client/tsmf_audio.h b/channels/tsmf/client/tsmf_audio.h index a8c7a49be..d589d5489 100644 --- a/channels/tsmf/client/tsmf_audio.h +++ b/channels/tsmf/client/tsmf_audio.h @@ -27,23 +27,24 @@ typedef struct _ITSMFAudioDevice ITSMFAudioDevice; struct _ITSMFAudioDevice { /* Open the audio device. */ - BOOL (*Open) (ITSMFAudioDevice* audio, const char* device); + BOOL (*Open)(ITSMFAudioDevice* audio, const char* device); /* Set the audio data format. */ - BOOL (*SetFormat) (ITSMFAudioDevice* audio, UINT32 sample_rate, UINT32 channels, UINT32 bits_per_sample); + BOOL (*SetFormat)(ITSMFAudioDevice* audio, UINT32 sample_rate, UINT32 channels, + UINT32 bits_per_sample); /* Play audio data. */ - BOOL (*Play) (ITSMFAudioDevice* audio, BYTE* data, UINT32 data_size); + BOOL (*Play)(ITSMFAudioDevice* audio, const BYTE* data, UINT32 data_size); /* Get the latency of the last written sample, in 100ns */ - UINT64 (*GetLatency) (ITSMFAudioDevice* audio); + UINT64(*GetLatency)(ITSMFAudioDevice* audio); /* Change the playback volume level */ - BOOL (*ChangeVolume) (ITSMFAudioDevice* audio, UINT32 newVolume, UINT32 muted); + BOOL (*ChangeVolume)(ITSMFAudioDevice* audio, UINT32 newVolume, UINT32 muted); /* Flush queued audio data */ - BOOL (*Flush) (ITSMFAudioDevice* audio); + BOOL (*Flush)(ITSMFAudioDevice* audio); /* Free the audio device */ - void (*Free) (ITSMFAudioDevice* audio); + void (*Free)(ITSMFAudioDevice* audio); }; #define TSMF_AUDIO_DEVICE_EXPORT_FUNC_NAME "TSMFAudioDeviceEntry" -typedef ITSMFAudioDevice* (*TSMF_AUDIO_DEVICE_ENTRY) (void); +typedef ITSMFAudioDevice* (*TSMF_AUDIO_DEVICE_ENTRY)(void); ITSMFAudioDevice* tsmf_load_audio_device(const char* name, const char* device); diff --git a/channels/tsmf/client/tsmf_media.c b/channels/tsmf/client/tsmf_media.c index ada248c78..05ca6c4fd 100644 --- a/channels/tsmf/client/tsmf_media.c +++ b/channels/tsmf/client/tsmf_media.c @@ -159,8 +159,8 @@ struct _TSMF_SAMPLE static wArrayList* presentation_list = NULL; static int TERMINATING = 0; -static void _tsmf_presentation_free(TSMF_PRESENTATION* presentation); -static void _tsmf_stream_free(TSMF_STREAM* stream); +static void _tsmf_presentation_free(void* obj); +static void _tsmf_stream_free(void* obj); static UINT64 get_current_time(void) { @@ -367,7 +367,7 @@ TSMF_PRESENTATION* tsmf_presentation_new(const BYTE* guid, goto error_stream_list; ArrayList_Object(presentation->stream_list)->fnObjectFree = - (OBJECT_FREE_FN) _tsmf_stream_free; + _tsmf_stream_free; if (ArrayList_Add(presentation_list, presentation) < 0) goto error_add; @@ -528,6 +528,7 @@ static BOOL tsmf_sample_playback_audio(TSMF_SAMPLE* sample) { ret = sample->stream->audio->Play(sample->stream->audio, sample->data, sample->decoded_size); + free(sample->data); sample->data = NULL; sample->decoded_size = 0; @@ -1193,14 +1194,19 @@ BOOL tsmf_stream_flush(TSMF_STREAM* stream) return TRUE; } -void _tsmf_presentation_free(TSMF_PRESENTATION* presentation) +void _tsmf_presentation_free(void* obj) { - tsmf_presentation_stop(presentation); - ArrayList_Clear(presentation->stream_list); - ArrayList_Free(presentation->stream_list); - free(presentation->rects); - ZeroMemory(presentation, sizeof(TSMF_PRESENTATION)); - free(presentation); + TSMF_PRESENTATION* presentation = (TSMF_PRESENTATION*)obj; + + if (presentation) + { + tsmf_presentation_stop(presentation); + ArrayList_Clear(presentation->stream_list); + ArrayList_Free(presentation->stream_list); + free(presentation->rects); + ZeroMemory(presentation, sizeof(TSMF_PRESENTATION)); + free(presentation); + } } void tsmf_presentation_free(TSMF_PRESENTATION* presentation) @@ -1414,8 +1420,10 @@ void tsmf_stream_end(TSMF_STREAM* stream, UINT32 message_id, stream->eos_channel_callback = pChannelCallback; } -void _tsmf_stream_free(TSMF_STREAM* stream) +void _tsmf_stream_free(void* obj) { + TSMF_STREAM* stream = (TSMF_STREAM*)obj; + if (!stream) return; @@ -1552,8 +1560,7 @@ BOOL tsmf_media_init(void) if (!presentation_list) return FALSE; - ArrayList_Object(presentation_list)->fnObjectFree = (OBJECT_FREE_FN) - _tsmf_presentation_free; + ArrayList_Object(presentation_list)->fnObjectFree = _tsmf_presentation_free; } return TRUE; diff --git a/cmake/ConfigOptions.cmake b/cmake/ConfigOptions.cmake index ae6b69021..9c13e4d45 100644 --- a/cmake/ConfigOptions.cmake +++ b/cmake/ConfigOptions.cmake @@ -132,6 +132,10 @@ option(WITH_DEBUG_SYMBOLS "Pack debug symbols to installer" OFF) option(WITH_CCACHE "Use ccache support if available" ON) option(WITH_ICU "Use ICU for unicode conversion" OFF) +if (WITH_FFMPEG) + option(WITH_DSP_FFMPEG "Use FFMPEG for audio encoding/decoding" OFF) +endif(WITH_FFMPEG) + option(USE_VERSION_FROM_GIT_TAG "Extract FreeRDP version from git tag." OFF) if(ANDROID) diff --git a/cmake/FindFAAC.cmake b/cmake/FindFAAC.cmake new file mode 100644 index 000000000..61e0d2747 --- /dev/null +++ b/cmake/FindFAAC.cmake @@ -0,0 +1,13 @@ + +find_path(FAAC_INCLUDE_DIR faac.h) + +find_library(FAAC_LIBRARY faac) + +find_package_handle_standard_args(FAAC DEFAULT_MSG FAAC_INCLUDE_DIR FAAC_LIBRARY) + +if(FAAC_FOUND) + set(FAAC_LIBRARIES ${FAAC_LIBRARY}) + set(FAAC_INCLUDE_DIRS ${FAAC_INCLUDE_DIR}) +endif() + +mark_as_advanced(FAAC_INCLUDE_DIR FAAC_LIBRARY) diff --git a/cmake/FindFAAD2.cmake b/cmake/FindFAAD2.cmake new file mode 100644 index 000000000..d9387de49 --- /dev/null +++ b/cmake/FindFAAD2.cmake @@ -0,0 +1,13 @@ + +find_path(FAAD2_INCLUDE_DIR faad.h) + +find_library(FAAD2_LIBRARY faad) + +find_package_handle_standard_args(FAAD2 DEFAULT_MSG FAAD2_INCLUDE_DIR FAAD2_LIBRARY) + +if(FAAD2_FOUND) + set(FAAD2_LIBRARIES ${FAAD2_LIBRARY}) + set(FAAD2_INCLUDE_DIRS ${FAAD2_INCLUDE_DIR}) +endif() + +mark_as_advanced(FAAD2_INCLUDE_DIR FAAD2_LIBRARY) diff --git a/cmake/FindFFmpeg.cmake b/cmake/FindFFmpeg.cmake index b25ad63c7..645971e5e 100644 --- a/cmake/FindFFmpeg.cmake +++ b/cmake/FindFFmpeg.cmake @@ -10,42 +10,48 @@ set(REQUIRED_AVCODEC_API_VERSION 53.25.0) include(FindPkgConfig) -if(PKG_CONFIG_FOUND) +if (PKG_CONFIG_FOUND) pkg_check_modules(AVCODEC libavcodec) pkg_check_modules(AVUTIL libavutil) -endif() + pkg_check_modules(AVRESAMPLE libavresample) +endif(PKG_CONFIG_FOUND) # avcodec find_path(AVCODEC_INCLUDE_DIR libavcodec/avcodec.h PATHS ${AVCODEC_INCLUDE_DIRS}) -find_library(AVCODEC_LIBRARY avcodec PATHS ${AVCODEC_LIBRARY_DIRS}) +find_library(AVCODEC_LIBRARY avcodec PATHS $ {AVCODEC_LIBRARY_DIRS}) # avutil find_path(AVUTIL_INCLUDE_DIR libavutil/avutil.h PATHS ${AVUTIL_INCLUDE_DIRS}) find_library(AVUTIL_LIBRARY avutil PATHS ${AVUTIL_LIBRARY_DIRS}) -if(AVCODEC_INCLUDE_DIR AND AVCODEC_LIBRARY) - set(AVCODEC_FOUND TRUE) -endif() +# avresample +find_path(AVRESAMPLE_INCLUDE_DIR libavresample/avresample.h PATHS ${AVRESAMPLE_INCLUDE_DIRS}) +find_library(AVRESAMPLE_LIBRARY avresample PATHS ${AVRESAMPLE_LIBRARY_DIRS}) -if(AVUTIL_INCLUDE_DIR AND AVUTIL_LIBRARY) + +if (AVCODEC_INCLUDE_DIR AND AVCODEC_LIBRARY AND AVRESAMPLE_LIBRARY) + set(AVCODEC_FOUND TRUE) +endif(AVCODEC_INCLUDE_DIR AND AVCODEC_LIBRARY AND AVRESAMPLE_LIBRARY) + +if (AVUTIL_INCLUDE_DIR AND AVUTIL_LIBRARY) set(AVUTIL_FOUND TRUE) -endif() +endif(AVUTIL_INCLUDE_DIR AND AVUTIL_LIBRARY) include(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(FFmpeg DEFAULT_MSG AVUTIL_FOUND AVCODEC_FOUND) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(FFmpeg DEFAULT_MSG AVUTIL_FOUND AVCODEC_FOUND AVRESAMPLE_FOUND) if (AVCODEC_VERSION) if (${AVCODEC_VERSION} VERSION_LESS ${REQUIRED_AVCODEC_API_VERSION}) - message(FATAL_ERROR "libavcodec version >= ${REQUIRED_AVCODEC_VERSION} (API >= ${REQUIRED_AVCODEC_API_VERSION}) is required") + message(FATAL_ERROR + "libavcodec version >= ${REQUIRED_AVCODEC_VERSION} (API >= ${REQUIRED_AVCODEC_API_VERSION}) is required") endif() -else() - message("Note: To build libavcodec version >= ${REQUIRED_AVCODEC_VERSION} (API >= ${REQUIRED_AVCODEC_API_VERSION}) is required") -endif() +else(AVCODEC_VERSION) + message("Note: To build libavcodec version >= ${REQUIRED_AVCODEC_VERSION} (API >= ${REQUIRED_AVCODEC_API_VERSION}) is required") +endif(AVCODEC_VERSION) -if(FFMPEG_FOUND) - set(FFMPEG_INCLUDE_DIRS ${AVCODEC_INCLUDE_DIR} ${AVUTIL_INCLUDE_DIR}) - set(FFMPEG_LIBRARIES ${AVCODEC_LIBRARY} ${AVUTIL_LIBRARY}) -endif() +if (FFMPEG_FOUND) + set(FFMPEG_INCLUDE_DIRS ${AVCODEC_INCLUDE_DIR} ${AVUTIL_INCLUDE_DIR} ${AVRESAMPLE_INCLUDE_DIR}) + set(FFMPEG_LIBRARIES ${AVCODEC_LIBRARY} ${AVUTIL_LIBRARY} ${AVRESAMPLE_LIBRARY}) +endif(FFMPEG_FOUND) mark_as_advanced(FFMPEG_INCLUDE_DIRS FFMPEG_LIBRARIES) - diff --git a/cmake/FindLAME.cmake b/cmake/FindLAME.cmake new file mode 100644 index 000000000..0fec8e8fb --- /dev/null +++ b/cmake/FindLAME.cmake @@ -0,0 +1,13 @@ + +find_path(LAME_INCLUDE_DIR lame/lame.h) + +find_library(LAME_LIBRARY NAMES lame mp3lame) + +find_package_handle_standard_args(LAME DEFAULT_MSG LAME_INCLUDE_DIR LAME_LIBRARY) + +if (LAME_FOUND) + set(LAME_LIBRARIES ${LAME_LIBRARY}) + set(LAME_INCLUDE_DIRS ${LAME_INCLUDE_DIR}) +endif() + +mark_as_advanced(LAME_INCLUDE_DIR LAME_LIBRARY) diff --git a/config.h.in b/config.h.in index 96e6e9b61..875db0af6 100644 --- a/config.h.in +++ b/config.h.in @@ -52,9 +52,13 @@ #cmakedefine WITH_IOSAUDIO #cmakedefine WITH_OPENSLES #cmakedefine WITH_GSM +#cmakedefine WITH_LAME +#cmakedefine WITH_FAAD2 +#cmakedefine WITH_FAAC #cmakedefine WITH_GFX_H264 #cmakedefine WITH_OPENH264 #cmakedefine WITH_FFMPEG +#cmakedefine WITH_DSP_FFMPEG #cmakedefine WITH_X264 #cmakedefine WITH_MEDIA_FOUNDATION diff --git a/include/freerdp/client/audin.h b/include/freerdp/client/audin.h index e78e4b1ea..c1e98c0d7 100644 --- a/include/freerdp/client/audin.h +++ b/include/freerdp/client/audin.h @@ -24,38 +24,28 @@ #include #include +#include /** * Subsystem Interface */ -typedef UINT (*AudinReceive) (const BYTE* data, int size, void* userData); - -typedef struct audin_format audinFormat; -struct audin_format -{ - UINT16 wFormatTag; - UINT16 nChannels; - UINT32 nSamplesPerSec; - UINT16 nBlockAlign; - UINT16 wBitsPerSample; - UINT16 cbSize; - BYTE* data; -}; +typedef UINT(*AudinReceive)(const AUDIO_FORMAT* format, + const BYTE* data, size_t size, void* userData); typedef struct _IAudinDevice IAudinDevice; struct _IAudinDevice { - UINT (*Open) (IAudinDevice* devplugin, AudinReceive receive, void* userData); - BOOL (*FormatSupported) (IAudinDevice* devplugin, audinFormat* format); - UINT (*SetFormat) (IAudinDevice* devplugin, audinFormat* format, UINT32 FramesPerPacket); - UINT (*Close) (IAudinDevice* devplugin); - UINT (*Free) (IAudinDevice* devplugin); + UINT(*Open)(IAudinDevice* devplugin, AudinReceive receive, void* userData); + BOOL (*FormatSupported)(IAudinDevice* devplugin, const AUDIO_FORMAT* format); + UINT(*SetFormat)(IAudinDevice* devplugin, const AUDIO_FORMAT* format, UINT32 FramesPerPacket); + UINT(*Close)(IAudinDevice* devplugin); + UINT(*Free)(IAudinDevice* devplugin); }; #define AUDIN_DEVICE_EXPORT_FUNC_NAME "freerdp_audin_client_subsystem_entry" -typedef UINT (*PREGISTERAUDINDEVICE)(IWTSPlugin* plugin, IAudinDevice* device); +typedef UINT(*PREGISTERAUDINDEVICE)(IWTSPlugin* plugin, IAudinDevice* device); struct _FREERDP_AUDIN_DEVICE_ENTRY_POINTS { @@ -67,7 +57,7 @@ struct _FREERDP_AUDIN_DEVICE_ENTRY_POINTS typedef struct _FREERDP_AUDIN_DEVICE_ENTRY_POINTS FREERDP_AUDIN_DEVICE_ENTRY_POINTS; typedef FREERDP_AUDIN_DEVICE_ENTRY_POINTS* PFREERDP_AUDIN_DEVICE_ENTRY_POINTS; -typedef UINT (*PFREERDP_AUDIN_DEVICE_ENTRY)(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints); +typedef UINT(*PFREERDP_AUDIN_DEVICE_ENTRY)(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints); #endif /* FREERDP_CHANNEL_AUDIN_CLIENT_AUDIN_H */ diff --git a/include/freerdp/client/rdpsnd.h b/include/freerdp/client/rdpsnd.h index 089046cd2..d4a5979fc 100644 --- a/include/freerdp/client/rdpsnd.h +++ b/include/freerdp/client/rdpsnd.h @@ -26,43 +26,18 @@ /** * Subsystem Interface */ - -struct _RDPSND_WAVE -{ - BYTE* data; - int length; - - BYTE cBlockNo; - UINT16 wFormatNo; - UINT16 wTimeStampA; - UINT16 wTimeStampB; - - UINT16 wAudioLength; - - UINT32 wLocalTimeA; - UINT32 wLocalTimeB; - - BOOL AutoConfirm; -}; -typedef struct _RDPSND_WAVE RDPSND_WAVE; - typedef struct rdpsnd_plugin rdpsndPlugin; typedef struct rdpsnd_device_plugin rdpsndDevicePlugin; -typedef BOOL (*pcFormatSupported) (rdpsndDevicePlugin* device, AUDIO_FORMAT* format); -typedef BOOL (*pcOpen) (rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency); -typedef BOOL (*pcSetFormat) (rdpsndDevicePlugin* device, AUDIO_FORMAT* format, int latency); -typedef UINT32 (*pcGetVolume) (rdpsndDevicePlugin* device); -typedef BOOL (*pcSetVolume) (rdpsndDevicePlugin* device, UINT32 value); -typedef void (*pcPlay) (rdpsndDevicePlugin* device, BYTE* data, int size); -typedef void (*pcStart) (rdpsndDevicePlugin* device); -typedef void (*pcClose) (rdpsndDevicePlugin* device); -typedef void (*pcFree) (rdpsndDevicePlugin* device); - -typedef BOOL (*pcWaveDecode) (rdpsndDevicePlugin* device, RDPSND_WAVE* wave); -typedef void (*pcWavePlay) (rdpsndDevicePlugin* device, RDPSND_WAVE* wave); -typedef UINT (*pcWaveConfirm) (rdpsndDevicePlugin* device, RDPSND_WAVE* wave); +typedef BOOL (*pcFormatSupported)(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format); +typedef BOOL (*pcOpen)(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, UINT32 latency); +typedef UINT32(*pcGetVolume)(rdpsndDevicePlugin* device); +typedef BOOL (*pcSetVolume)(rdpsndDevicePlugin* device, UINT32 value); +typedef UINT (*pcPlay)(rdpsndDevicePlugin* device, const BYTE* data, size_t size); +typedef void (*pcStart)(rdpsndDevicePlugin* device); +typedef void (*pcClose)(rdpsndDevicePlugin* device); +typedef void (*pcFree)(rdpsndDevicePlugin* device); struct rdpsnd_device_plugin { @@ -70,19 +45,12 @@ struct rdpsnd_device_plugin pcFormatSupported FormatSupported; pcOpen Open; - pcSetFormat SetFormat; pcGetVolume GetVolume; pcSetVolume SetVolume; pcPlay Play; pcStart Start; pcClose Close; pcFree Free; - - pcWaveDecode WaveDecode; - pcWavePlay WavePlay; - pcWaveConfirm WaveConfirm; - - BOOL DisableConfirmThread; }; #define RDPSND_DEVICE_EXPORT_FUNC_NAME "freerdp_rdpsnd_client_subsystem_entry" @@ -98,7 +66,7 @@ struct _FREERDP_RDPSND_DEVICE_ENTRY_POINTS typedef struct _FREERDP_RDPSND_DEVICE_ENTRY_POINTS FREERDP_RDPSND_DEVICE_ENTRY_POINTS; typedef FREERDP_RDPSND_DEVICE_ENTRY_POINTS* PFREERDP_RDPSND_DEVICE_ENTRY_POINTS; -typedef UINT (*PFREERDP_RDPSND_DEVICE_ENTRY)(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pEntryPoints); +typedef UINT(*PFREERDP_RDPSND_DEVICE_ENTRY)(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pEntryPoints); #endif /* FREERDP_CHANNEL_RDPSND_CLIENT_RDPSND_H */ diff --git a/include/freerdp/codec/audio.h b/include/freerdp/codec/audio.h index c018c715b..73ee571b2 100644 --- a/include/freerdp/codec/audio.h +++ b/include/freerdp/codec/audio.h @@ -188,20 +188,20 @@ typedef struct AUDIO_FORMAT AUDIO_FORMAT; */ #ifdef __cplusplus - extern "C" { +extern "C" { #endif -FREERDP_API UINT32 rdpsnd_compute_audio_time_length(AUDIO_FORMAT* format, int size); +FREERDP_API UINT32 rdpsnd_compute_audio_time_length(const AUDIO_FORMAT* format, size_t size); FREERDP_API char* rdpsnd_get_audio_tag_string(UINT16 wFormatTag); -FREERDP_API void rdpsnd_print_audio_format(AUDIO_FORMAT* format); -FREERDP_API void rdpsnd_print_audio_formats(AUDIO_FORMAT* formats, UINT16 count); +FREERDP_API void rdpsnd_print_audio_format(const AUDIO_FORMAT* format); +FREERDP_API void rdpsnd_print_audio_formats(const AUDIO_FORMAT* formats, UINT16 count); FREERDP_API void rdpsnd_free_audio_formats(AUDIO_FORMAT* formats, UINT16 count); #ifdef __cplusplus - } +} #endif #endif /* FREERDP_CODEC_AUDIO_H */ diff --git a/include/freerdp/codec/dsp.h b/include/freerdp/codec/dsp.h index d364b96d1..10a6f2941 100644 --- a/include/freerdp/codec/dsp.h +++ b/include/freerdp/codec/dsp.h @@ -20,63 +20,30 @@ #ifndef FREERDP_CODEC_DSP_H #define FREERDP_CODEC_DSP_H -#include +#include -union _ADPCM -{ - struct - { - INT16 last_sample[2]; - INT16 last_step[2]; - } ima; - struct - { - BYTE predictor[2]; - INT32 delta[2]; - INT32 sample1[2]; - INT32 sample2[2]; - } ms; -}; -typedef union _ADPCM ADPCM; +#include +#include typedef struct _FREERDP_DSP_CONTEXT FREERDP_DSP_CONTEXT; -struct _FREERDP_DSP_CONTEXT -{ - BYTE* resampled_buffer; - UINT32 resampled_size; - UINT32 resampled_frames; - UINT32 resampled_maxlength; - - BYTE* adpcm_buffer; - UINT32 adpcm_size; - UINT32 adpcm_maxlength; - - ADPCM adpcm; - - BOOL (*resample)(FREERDP_DSP_CONTEXT* context, - const BYTE* src, int bytes_per_sample, - UINT32 schan, UINT32 srate, int sframes, - UINT32 rchan, UINT32 rrate); - - BOOL (*decode_ima_adpcm)(FREERDP_DSP_CONTEXT* context, - const BYTE* src, int size, int channels, int block_size); - BOOL (*encode_ima_adpcm)(FREERDP_DSP_CONTEXT* context, - const BYTE* src, int size, int channels, int block_size); - - BOOL (*decode_ms_adpcm)(FREERDP_DSP_CONTEXT* context, - const BYTE* src, int size, int channels, int block_size); - BOOL (*encode_ms_adpcm)(FREERDP_DSP_CONTEXT* context, - const BYTE* src, int size, int channels, int block_size); -}; - #ifdef __cplusplus extern "C" { #endif -FREERDP_API FREERDP_DSP_CONTEXT* freerdp_dsp_context_new(void); +FREERDP_API FREERDP_DSP_CONTEXT* freerdp_dsp_context_new(BOOL encoder); +FREERDP_API BOOL freerdp_dsp_supports_format(const AUDIO_FORMAT* format, BOOL encode); +FREERDP_API BOOL freerdp_dsp_encode(FREERDP_DSP_CONTEXT* context, + const AUDIO_FORMAT* srcFormat, + const BYTE* data, size_t length, + wStream* out); +FREERDP_API BOOL freerdp_dsp_decode(FREERDP_DSP_CONTEXT* context, + const AUDIO_FORMAT* srcFormat, + const BYTE* data, size_t length, + wStream* out); FREERDP_API void freerdp_dsp_context_free(FREERDP_DSP_CONTEXT* context); -#define freerdp_dsp_context_reset_adpcm(_c) memset(&_c->adpcm, 0, sizeof(ADPCM)) +FREERDP_API BOOL freerdp_dsp_context_reset(FREERDP_DSP_CONTEXT* context, + const AUDIO_FORMAT* targetFormat); #ifdef __cplusplus } diff --git a/libfreerdp/CMakeLists.txt b/libfreerdp/CMakeLists.txt index e6095f67a..80b3bcd28 100644 --- a/libfreerdp/CMakeLists.txt +++ b/libfreerdp/CMakeLists.txt @@ -155,6 +155,33 @@ if(WITH_SSE2) endif() endif() +if (WITH_DSP_FFMPEG) + set(CODEC_SRCS + ${CODEC_SRCS} + codec/dsp_ffmpeg.c + codec/dsp_ffmpeg.h) +endif (WITH_DSP_FFMPEG) + +if(GSM_FOUND) + freerdp_library_add(${GSM_LIBRARIES}) + include_directories(${GSM_INCLUDE_DIRS}) +endif() + +if(LAME_FOUND) + freerdp_library_add(${LAME_LIBRARIES}) + include_directories(${LAME_INCLUDE_DIRS}) +endif() + +if(FAAD2_FOUND) + freerdp_library_add(${FAAD2_LIBRARIES}) + include_directories(${FAAD2_INCLUDE_DIRS}) +endif() + +if(FAAC_FOUND) + freerdp_library_add(${FAAC_LIBRARIES}) + include_directories(${FAAC_INCLUDE_DIRS}) +endif() + if(WITH_NEON) set_source_files_properties(${CODEC_NEON_SRCS} PROPERTIES COMPILE_FLAGS "-mfpu=neon -Wno-unused-variable" ) set(CODEC_SRCS ${CODEC_SRCS} ${CODEC_NEON_SRCS}) @@ -324,6 +351,7 @@ endif() target_link_libraries(${MODULE_NAME} ${PRIVATE_KEYWORD} ${LIBFREERDP_LIBS} winpr) + install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries EXPORT FreeRDPTargets) if (WITH_DEBUG_SYMBOLS AND MSVC AND BUILD_SHARED_LIBS) get_target_property(OUTPUT_FILENAME ${MODULE_NAME} OUTPUT_NAME) diff --git a/libfreerdp/codec/audio.c b/libfreerdp/codec/audio.c index 2303e03a4..d5e52d7c1 100644 --- a/libfreerdp/codec/audio.c +++ b/libfreerdp/codec/audio.c @@ -28,7 +28,7 @@ #define TAG FREERDP_TAG("codec") -UINT32 rdpsnd_compute_audio_time_length(AUDIO_FORMAT* format, int size) +UINT32 rdpsnd_compute_audio_time_length(const AUDIO_FORMAT* format, size_t size) { UINT32 mstime; UINT32 wSamples; @@ -54,7 +54,6 @@ UINT32 rdpsnd_compute_audio_time_length(AUDIO_FORMAT* format, int size) if ((format->cbSize == 2) && (format->data)) { nSamplesPerBlock = *((UINT16*) format->data); - wSamples = (size / format->nBlockAlign) * nSamplesPerBlock; mstime = (((wSamples * 1000) / format->nSamplesPerSec) / format->nChannels); } @@ -113,25 +112,25 @@ char* rdpsnd_get_audio_tag_string(UINT16 wFormatTag) return "WAVE_FORMAT_UNKNOWN"; } -void rdpsnd_print_audio_format(AUDIO_FORMAT* format) +void rdpsnd_print_audio_format(const AUDIO_FORMAT* format) { WLog_INFO(TAG, "%s:\t wFormatTag: 0x%04"PRIX16" nChannels: %"PRIu16" nSamplesPerSec: %"PRIu32" " - "nAvgBytesPerSec: %"PRIu32" nBlockAlign: %"PRIu16" wBitsPerSample: %"PRIu16" cbSize: %"PRIu16"", - rdpsnd_get_audio_tag_string(format->wFormatTag), format->wFormatTag, - format->nChannels, format->nSamplesPerSec, format->nAvgBytesPerSec, - format->nBlockAlign, format->wBitsPerSample, format->cbSize); + "nAvgBytesPerSec: %"PRIu32" nBlockAlign: %"PRIu16" wBitsPerSample: %"PRIu16" cbSize: %"PRIu16"", + rdpsnd_get_audio_tag_string(format->wFormatTag), format->wFormatTag, + format->nChannels, format->nSamplesPerSec, format->nAvgBytesPerSec, + format->nBlockAlign, format->wBitsPerSample, format->cbSize); } -void rdpsnd_print_audio_formats(AUDIO_FORMAT* formats, UINT16 count) +void rdpsnd_print_audio_formats(const AUDIO_FORMAT* formats, UINT16 count) { - int index; - AUDIO_FORMAT* format; + UINT16 index; + const AUDIO_FORMAT* format; if (formats) { WLog_INFO(TAG, "AUDIO_FORMATS (%"PRIu16") ={", count); - for (index = 0; index < (int) count; index++) + for (index = 0; index < count; index++) { format = &formats[index]; WLog_ERR(TAG, "\t"); @@ -144,17 +143,14 @@ void rdpsnd_print_audio_formats(AUDIO_FORMAT* formats, UINT16 count) void rdpsnd_free_audio_formats(AUDIO_FORMAT* formats, UINT16 count) { - int index; - AUDIO_FORMAT* format; + UINT16 index; if (formats) { - for (index = 0; index < (int) count; index++) + for (index = 0; index < count; index++) { - format = &formats[index]; - - if (format->cbSize) - free(format->data); + AUDIO_FORMAT* format = &formats[index]; + free(format->data); } free(formats); diff --git a/libfreerdp/codec/dsp.c b/libfreerdp/codec/dsp.c index be5e98f95..81107d48a 100644 --- a/libfreerdp/codec/dsp.c +++ b/libfreerdp/codec/dsp.c @@ -28,44 +28,101 @@ #include #include - #include +#if defined(WITH_GSM) +#include +#endif + +#if defined(WITH_LAME) +#include +#endif + +#if defined(WITH_DSP_FFMPEG) +#include "dsp_ffmpeg.h" +#endif + +#if defined(WITH_FAAD2) +#include +#endif + +#if defined(WITH_FAAC) +#include +#endif + +#define TAG FREERDP_TAG("dsp") + +union _ADPCM +{ + struct + { + INT16 last_sample[2]; + INT16 last_step[2]; + } ima; + struct + { + BYTE predictor[2]; + INT32 delta[2]; + INT32 sample1[2]; + INT32 sample2[2]; + } ms; +}; +typedef union _ADPCM ADPCM; + +struct _FREERDP_DSP_CONTEXT +{ + BOOL encoder; + + ADPCM adpcm; + AUDIO_FORMAT format; + + wStream* buffer; + wStream* resample; + +#if defined(WITH_GSM) + gsm gsm; +#endif +#if defined(WITH_LAME) + lame_t lame; + hip_t hip; +#endif +#if defined(WITH_FAAD2) + NeAACDecHandle faad; + BOOL faadSetup; +#endif + +#if defined(WITH_FAAC) + faacEncHandle faac; + unsigned long faacInputSamples; + unsigned long faacMaxOutputBytes; +#endif +}; + /** * Microsoft Multimedia Standards Update * http://download.microsoft.com/download/9/8/6/9863C72A-A3AA-4DDB-B1BA-CA8D17EFD2D4/RIFFNEW.pdf */ static BOOL freerdp_dsp_resample(FREERDP_DSP_CONTEXT* context, - const BYTE* src, int bytes_per_sample, - UINT32 schan, UINT32 srate, int sframes, - UINT32 rchan, UINT32 rrate) + const BYTE* src, size_t bytes_per_sample, + UINT32 schan, UINT32 srate, size_t sframes, + UINT32 rchan, UINT32 rrate) { - BYTE* dst; 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; rsize = rbytes * rframes; - if (rsize > (int) context->resampled_maxlength) - { - BYTE *newBuffer = (BYTE*) realloc(context->resampled_buffer, rsize + 1024); - if (!newBuffer) - return FALSE; + if (!Stream_EnsureCapacity(context->resample, rsize + 1024)) + return FALSE; - context->resampled_maxlength = rsize + 1024; - context->resampled_buffer = newBuffer; - } - dst = context->resampled_buffer; - - p = dst; + p = Stream_Buffer(context->resample); for (i = 0; i < rframes; i++) { @@ -80,13 +137,13 @@ static BOOL freerdp_dsp_resample(FREERDP_DSP_CONTEXT* context, { /* Nearest Interpolation, probably the easiest, but works */ *p++ = (i * srate - n1 * rrate > n2 * rrate - i * srate ? - src[n2 * sbytes + (j % sbytes)] : - src[n1 * sbytes + (j % sbytes)]); + src[n2 * sbytes + (j % sbytes)] : + src[n1 * sbytes + (j % sbytes)]); } } - context->resampled_frames = rframes; - context->resampled_size = rsize; + Stream_SetPointer(context->resample, p); + Stream_SealLength(context->resample); return TRUE; } @@ -105,33 +162,34 @@ static const INT16 ima_step_index_table[] = static const INT16 ima_step_size_table[] = { - 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, - 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, - 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, + 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, + 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, + 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, - 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, + 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, - 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, - 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 + 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, + 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 }; static UINT16 dsp_decode_ima_adpcm_sample(ADPCM* adpcm, - unsigned int channel, BYTE sample) + unsigned int channel, BYTE sample) { INT32 ss; INT32 d; - ss = ima_step_size_table[adpcm->ima.last_step[channel]]; - d = (ss >> 3); if (sample & 1) d += (ss >> 2); + if (sample & 2) d += (ss >> 1); + if (sample & 4) d += ss; + if (sample & 8) d = -d; @@ -143,7 +201,6 @@ static UINT16 dsp_decode_ima_adpcm_sample(ADPCM* adpcm, d = 32767; adpcm->ima.last_sample[channel] = (INT16) d; - adpcm->ima.last_step[channel] += ima_step_index_table[sample]; if (adpcm->ima.last_step[channel] < 0) @@ -155,43 +212,36 @@ static UINT16 dsp_decode_ima_adpcm_sample(ADPCM* adpcm, } static BOOL freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* context, - const BYTE* src, int size, int channels, int block_size) + const BYTE* src, size_t size, wStream* out) { BYTE* dst; BYTE sample; UINT16 decoded; - UINT32 out_size; - int channel; + UINT32 out_size = size * 4; + UINT32 channel; + const UINT32 block_size = context->format.nBlockAlign; + const UINT32 channels = context->format.nChannels; int i; - out_size = size * 4; + if (!Stream_EnsureCapacity(out, out_size)) + return FALSE; - if (out_size > context->adpcm_maxlength) - { - BYTE *newBuffer = realloc(context->adpcm_buffer, out_size + 1024); - if (!newBuffer) - return FALSE; - - context->adpcm_maxlength = out_size + 1024; - context->adpcm_buffer = newBuffer; - } - - dst = context->adpcm_buffer; + dst = Stream_Buffer(out); while (size > 0) { if (size % block_size == 0) { - context->adpcm.ima.last_sample[0] = (INT16) (((UINT16)(*src)) | (((UINT16)(*(src + 1))) << 8)); - context->adpcm.ima.last_step[0] = (INT16) (*(src + 2)); + context->adpcm.ima.last_sample[0] = (INT16)(((UINT16)(*src)) | (((UINT16)(*(src + 1))) << 8)); + context->adpcm.ima.last_step[0] = (INT16)(*(src + 2)); src += 4; size -= 4; out_size -= 16; if (channels > 1) { - context->adpcm.ima.last_sample[1] = (INT16) (((UINT16)(*src)) | (((UINT16)(*(src + 1))) << 8)); - context->adpcm.ima.last_step[1] = (INT16) (*(src + 2)); + context->adpcm.ima.last_sample[1] = (INT16)(((UINT16)(*src)) | (((UINT16)(*(src + 1))) << 8)); + context->adpcm.ima.last_step[1] = (INT16)(*(src + 2)); src += 4; size -= 4; out_size -= 16; @@ -204,12 +254,10 @@ static BOOL freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* context, { channel = (i < 4 ? 0 : 1); sample = ((*src) & 0x0f); - decoded = dsp_decode_ima_adpcm_sample(&context->adpcm, channel, sample); dst[((i & 3) << 3) + (channel << 1)] = (decoded & 0xFF); dst[((i & 3) << 3) + (channel << 1) + 1] = (decoded >> 8); sample = ((*src) >> 4); - decoded = dsp_decode_ima_adpcm_sample(&context->adpcm, channel, sample); dst[((i & 3) << 3) + (channel << 1) + 4] = (decoded & 0xFF); dst[((i & 3) << 3) + (channel << 1) + 5] = (decoded >> 8); @@ -222,12 +270,10 @@ static BOOL freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* context, else { sample = ((*src) & 0x0f); - decoded = dsp_decode_ima_adpcm_sample(&context->adpcm, 0, sample); *dst++ = (decoded & 0xFF); *dst++ = (decoded >> 8); sample = ((*src) >> 4); - decoded = dsp_decode_ima_adpcm_sample(&context->adpcm, 0, sample); *dst++ = (decoded & 0xFF); *dst++ = (decoded >> 8); @@ -236,10 +282,224 @@ static BOOL freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* context, } } - context->adpcm_size = dst - context->adpcm_buffer; + Stream_SetPointer(out, dst); return TRUE; } +#if defined(WITH_GSM) +static BOOL freerdp_dsp_decode_gsm610(FREERDP_DSP_CONTEXT* context, + const BYTE* src, size_t size, wStream* out) +{ + size_t offset = 0; + + while (offset < size) + { + int rc; + gsm_signal gsmBlockBuffer[160] = { 0 }; + rc = gsm_decode(context->gsm, (gsm_byte*) &src[offset], gsmBlockBuffer); + if (rc < 0) + return FALSE; + + if ((offset % 65) == 0) + offset += 33; + else + offset += 32; + + if (!Stream_EnsureRemainingCapacity(out, sizeof(gsmBlockBuffer))) + return FALSE; + + Stream_Write(out, (void*) gsmBlockBuffer, sizeof(gsmBlockBuffer)); + } + + return TRUE; +} + +static BOOL freerdp_dsp_encode_gsm610(FREERDP_DSP_CONTEXT* context, + const BYTE* src, size_t size, wStream* out) +{ + size_t offset = 0; + + while (offset < size) + { + gsm_signal* signal = (gsm_signal*)&src[offset]; + + if (!Stream_EnsureRemainingCapacity(out, sizeof(gsm_frame))) + return FALSE; + + gsm_encode(context->gsm, signal, Stream_Pointer(out)); + if ((offset % 65) == 0) + Stream_Seek(out, 33); + else + Stream_Seek(out, 32); + offset += 160; + } + + return TRUE; +} +#endif + +#if defined(WITH_LAME) +static BOOL freerdp_dsp_decode_mp3(FREERDP_DSP_CONTEXT* context, + const BYTE* src, size_t size, wStream* out) +{ + int rc, x; + short* pcm_l; + short* pcm_r; + size_t buffer_size; + + if (!context || !src || !out) + return FALSE; + + buffer_size = 2 * context->format.nChannels * context->format.nSamplesPerSec; + + if (!Stream_EnsureCapacity(context->buffer, 2 * buffer_size)) + return FALSE; + + pcm_l = (short*)Stream_Buffer(context->buffer); + pcm_r = (short*)Stream_Buffer(context->buffer) + buffer_size; + rc = hip_decode(context->hip, (unsigned char*)/* API is not modifying content */src, + size, pcm_l, pcm_r); + + if (rc <= 0) + return FALSE; + + if (!Stream_EnsureRemainingCapacity(out, rc * context->format.nChannels * 2)) + return FALSE; + + for (x = 0; x < rc; x++) + { + Stream_Write_UINT16(out, pcm_l[x]); + Stream_Write_UINT16(out, pcm_r[x]); + } + + return TRUE; +} + +static BOOL freerdp_dsp_encode_mp3(FREERDP_DSP_CONTEXT* context, + const BYTE* src, size_t size, wStream* out) +{ + size_t samples_per_channel; + int rc; + + if (!context || !src || !out) + return FALSE; + + samples_per_channel = size / context->format.nChannels / context->format.wBitsPerSample / 8; + + /* Ensure worst case buffer size for mp3 stream taken from LAME header */ + if (!Stream_EnsureRemainingCapacity(out, 1.25 * samples_per_channel + 7200)) + return FALSE; + + samples_per_channel = size / 2 /* size of a sample */ / context->format.nChannels; + rc = lame_encode_buffer_interleaved(context->lame, (short*)src, samples_per_channel, + Stream_Pointer(out), Stream_GetRemainingCapacity(out)); + + if (rc < 0) + return FALSE; + + Stream_Seek(out, rc); + return TRUE; +} +#endif + +#if defined(WITH_FAAC) +static BOOL freerdp_dsp_encode_faac(FREERDP_DSP_CONTEXT* context, + const BYTE* src, size_t size, wStream* out) +{ + int16_t* inSamples = (int16_t*)src; + int32_t* outSamples; + unsigned int nrSamples, x; + int rc; + + if (!context || !src || !out) + return FALSE; + + nrSamples = size / context->format.nChannels / context->format.wBitsPerSample / 8; + + if (!Stream_EnsureCapacity(context->buffer, + context->faacInputSamples * sizeof(int32_t) * context->format.nChannels)) + return FALSE; + + if (!Stream_EnsureRemainingCapacity(out, context->faacMaxOutputBytes)) + return FALSE; + + outSamples = Stream_Buffer(context->buffer); + + for (x = 0; x < nrSamples * context->format.nChannels; x++) + outSamples[x] = inSamples[x]; + + rc = faacEncEncode(context->faac, outSamples, nrSamples * context->format.nChannels, + Stream_Pointer(out), Stream_GetRemainingCapacity(out)); + + if (rc < 0) + return FALSE; + else if (rc > 0) + Stream_Seek(out, rc); + + return TRUE; +} +#endif + +#if defined(WITH_FAAD2) +static BOOL freerdp_dsp_decode_faad(FREERDP_DSP_CONTEXT* context, + const BYTE* src, size_t size, wStream* out) +{ + NeAACDecFrameInfo info; + void* output; + size_t offset = 0; + + if (!context || !src || !out) + return FALSE; + + if (!context->faadSetup) + { + unsigned long samplerate; + unsigned char channels; + char err = NeAACDecInit(context->faad, /* API is not modifying content */(unsigned char*)src, + size, &samplerate, &channels); + + if (err != 0) + return FALSE; + + if (channels != context->format.nChannels) + return FALSE; + + if (samplerate != context->format.nSamplesPerSec) + return FALSE; + + context->faadSetup = TRUE; + } + + while (offset < size) + { + size_t outSize; + void* sample_buffer; + outSize = context->format.nSamplesPerSec * context->format.nChannels * + context->format.wBitsPerSample / 8; + + if (!Stream_EnsureRemainingCapacity(out, outSize)) + return FALSE; + + sample_buffer = Stream_Pointer(out); + output = NeAACDecDecode2(context->faad, &info, (unsigned char*)&src[offset], size - offset, + &sample_buffer, Stream_GetRemainingCapacity(out)); + + if (info.error != 0) + return FALSE; + + offset += info.bytesconsumed; + + if (info.samples == 0) + continue; + + Stream_Seek(out, info.samples * context->format.wBitsPerSample / 8); + } + + return TRUE; +} + +#endif + /** * 0 1 2 3 * 2 0 6 4 10 8 14 12 @@ -278,7 +538,6 @@ static BYTE dsp_encode_ima_adpcm_sample(ADPCM* adpcm, int channel, INT16 sample) INT32 ss; BYTE enc; INT32 diff; - ss = ima_step_size_table[adpcm->ima.last_step[channel]]; d = e = sample - adpcm->ima.last_sample[channel]; diff = ss >> 3; @@ -325,7 +584,6 @@ static BYTE dsp_encode_ima_adpcm_sample(ADPCM* adpcm, int channel, INT16 sample) diff = 32767; adpcm->ima.last_sample[channel] = (INT16) diff; - adpcm->ima.last_step[channel] += ima_step_index_table[enc]; if (adpcm->ima.last_step[channel] < 0) @@ -337,38 +595,30 @@ static BYTE dsp_encode_ima_adpcm_sample(ADPCM* adpcm, int channel, INT16 sample) } static BOOL freerdp_dsp_encode_ima_adpcm(FREERDP_DSP_CONTEXT* context, - const BYTE* src, int size, int channels, int block_size) + const BYTE* src, size_t size, wStream* out) { int i; BYTE* dst; INT16 sample; BYTE encoded; UINT32 out_size; - out_size = size / 2; - if (out_size > context->adpcm_maxlength) - { - BYTE *newBuffer = realloc(context->adpcm_buffer, out_size + 1024); - if (!newBuffer) - return FALSE; + if (!Stream_EnsureRemainingCapacity(out, out_size)) + return FALSE; - context->adpcm_maxlength = out_size + 1024; - context->adpcm_buffer = newBuffer; - } - - dst = context->adpcm_buffer; + dst = Stream_Buffer(out); while (size > 0) { - if ((dst - context->adpcm_buffer) % block_size == 0) + if ((dst - Stream_Buffer(out)) % context->format.nBlockAlign == 0) { *dst++ = context->adpcm.ima.last_sample[0] & 0xFF; *dst++ = (context->adpcm.ima.last_sample[0] >> 8) & 0xFF; *dst++ = (BYTE) context->adpcm.ima.last_step[0]; *dst++ = 0; - if (channels > 1) + if (context->format.nChannels > 1) { *dst++ = context->adpcm.ima.last_sample[1] & 0xFF; *dst++ = (context->adpcm.ima.last_sample[1] >> 8) & 0xFF; @@ -377,13 +627,13 @@ static BOOL freerdp_dsp_encode_ima_adpcm(FREERDP_DSP_CONTEXT* context, } } - if (channels > 1) + if (context->format.nChannels > 1) { ZeroMemory(dst, 8); for (i = 0; i < 16; i++) { - sample = (INT16) (((UINT16)(*src)) | (((UINT16)(*(src + 1))) << 8)); + sample = (INT16)(((UINT16)(*src)) | (((UINT16)(*(src + 1))) << 8)); src += 2; encoded = dsp_encode_ima_adpcm_sample(&context->adpcm, i % 2, sample); dst[ima_stereo_encode_map[i].byte_num] |= encoded << ima_stereo_encode_map[i].byte_shift; @@ -394,18 +644,18 @@ static BOOL freerdp_dsp_encode_ima_adpcm(FREERDP_DSP_CONTEXT* context, } else { - sample = (INT16) (((UINT16)(*src)) | (((UINT16)(*(src + 1))) << 8)); + sample = (INT16)(((UINT16)(*src)) | (((UINT16)(*(src + 1))) << 8)); src += 2; encoded = dsp_encode_ima_adpcm_sample(&context->adpcm, 0, sample); - sample = (INT16) (((UINT16)(*src)) | (((UINT16)(*(src + 1))) << 8)); + sample = (INT16)(((UINT16)(*src)) | (((UINT16)(*(src + 1))) << 8)); src += 2; encoded |= dsp_encode_ima_adpcm_sample(&context->adpcm, 0, sample) << 4; *dst++ = encoded; size -= 4; } } - - context->adpcm_size = dst - context->adpcm_buffer; + + Stream_SetPointer(out, dst); return TRUE; } @@ -435,12 +685,9 @@ static INLINE INT16 freerdp_dsp_decode_ms_adpcm_sample(ADPCM* adpcm, BYTE sample { INT8 nibble; INT32 presample; - nibble = (sample & 0x08 ? (INT8) sample - 16 : sample); - presample = ((adpcm->ms.sample1[channel] * ms_adpcm_coeffs1[adpcm->ms.predictor[channel]]) + - (adpcm->ms.sample2[channel] * ms_adpcm_coeffs2[adpcm->ms.predictor[channel]])) / 256; - + (adpcm->ms.sample2[channel] * ms_adpcm_coeffs2[adpcm->ms.predictor[channel]])) / 256; presample += nibble * adpcm->ms.delta[channel]; if (presample > 32767) @@ -459,25 +706,18 @@ static INLINE INT16 freerdp_dsp_decode_ms_adpcm_sample(ADPCM* adpcm, BYTE sample } static BOOL freerdp_dsp_decode_ms_adpcm(FREERDP_DSP_CONTEXT* context, - const BYTE* src, int size, int channels, int block_size) + const BYTE* src, size_t size, wStream* out) { BYTE* dst; BYTE sample; - UINT32 out_size; + const UINT32 out_size = size * 4; + const UINT32 channels = context->format.nChannels; + const UINT32 block_size = context->format.nBlockAlign; - out_size = size * 4; + if (!Stream_EnsureCapacity(out, out_size)) + return FALSE; - if (out_size > context->adpcm_maxlength) - { - BYTE *newBuffer = realloc(context->adpcm_buffer, out_size + 1024); - if (!newBuffer) - return FALSE; - - context->adpcm_maxlength = out_size + 1024; - context->adpcm_buffer = newBuffer; - } - - dst = context->adpcm_buffer; + dst = Stream_Buffer(out); while (size > 0) { @@ -500,7 +740,6 @@ static BOOL freerdp_dsp_decode_ms_adpcm(FREERDP_DSP_CONTEXT* context, context->adpcm.ms.sample2[1] = *((INT16*) src); src += 2; size -= 14; - *((INT16*) dst) = context->adpcm.ms.sample2[0]; dst += 2; *((INT16*) dst) = context->adpcm.ms.sample2[1]; @@ -520,7 +759,6 @@ static BOOL freerdp_dsp_decode_ms_adpcm(FREERDP_DSP_CONTEXT* context, context->adpcm.ms.sample2[0] = *((INT16*) src); src += 2; size -= 7; - *((INT16*) dst) = context->adpcm.ms.sample2[0]; dst += 2; *((INT16*) dst) = context->adpcm.ms.sample1[0]; @@ -536,7 +774,6 @@ static BOOL freerdp_dsp_decode_ms_adpcm(FREERDP_DSP_CONTEXT* context, dst += 2; *((INT16*) dst) = freerdp_dsp_decode_ms_adpcm_sample(&context->adpcm, sample & 0x0F, 1); dst += 2; - sample = *src++; size--; *((INT16*) dst) = freerdp_dsp_decode_ms_adpcm_sample(&context->adpcm, sample >> 4, 0); @@ -555,7 +792,7 @@ static BOOL freerdp_dsp_decode_ms_adpcm(FREERDP_DSP_CONTEXT* context, } } - context->adpcm_size = dst - context->adpcm_buffer; + Stream_SetPointer(out, dst); return TRUE; } @@ -563,9 +800,8 @@ static BYTE freerdp_dsp_encode_ms_adpcm_sample(ADPCM* adpcm, INT32 sample, int c { INT32 presample; INT32 errordelta; - presample = ((adpcm->ms.sample1[channel] * ms_adpcm_coeffs1[adpcm->ms.predictor[channel]]) + - (adpcm->ms.sample2[channel] * ms_adpcm_coeffs2[adpcm->ms.predictor[channel]])) / 256; + (adpcm->ms.sample2[channel] * ms_adpcm_coeffs2[adpcm->ms.predictor[channel]])) / 256; errordelta = (sample - presample) / adpcm->ms.delta[channel]; if ((sample - presample) % adpcm->ms.delta[channel] > adpcm->ms.delta[channel] / 2) @@ -585,7 +821,8 @@ static BYTE freerdp_dsp_encode_ms_adpcm_sample(ADPCM* adpcm, INT32 sample, int c adpcm->ms.sample2[channel] = adpcm->ms.sample1[channel]; adpcm->ms.sample1[channel] = presample; - adpcm->ms.delta[channel] = adpcm->ms.delta[channel] * ms_adpcm_adaptation_table[(((BYTE) errordelta) & 0x0F)] / 256; + adpcm->ms.delta[channel] = adpcm->ms.delta[channel] * ms_adpcm_adaptation_table[((( + BYTE) errordelta) & 0x0F)] / 256; if (adpcm->ms.delta[channel] < 16) adpcm->ms.delta[channel] = 16; @@ -593,26 +830,18 @@ static BYTE freerdp_dsp_encode_ms_adpcm_sample(ADPCM* adpcm, INT32 sample, int c return ((BYTE) errordelta) & 0x0F; } -static BOOL freerdp_dsp_encode_ms_adpcm(FREERDP_DSP_CONTEXT* context, - const BYTE* src, int size, int channels, int block_size) +static BOOL freerdp_dsp_encode_ms_adpcm(FREERDP_DSP_CONTEXT* context, const BYTE* src, size_t size, + wStream* out) { BYTE* dst; INT32 sample; UINT32 out_size; - out_size = size / 2; - if (out_size > context->adpcm_maxlength) - { - BYTE *newBuffer = realloc(context->adpcm_buffer, out_size + 1024); - if (!newBuffer) - return FALSE; + if (!Stream_EnsureRemainingCapacity(out, out_size)) + return FALSE; - context->adpcm_maxlength = out_size + 1024; - context->adpcm_buffer = newBuffer; - } - - dst = context->adpcm_buffer; + dst = Stream_Buffer(out); if (context->adpcm.ms.delta[0] < 16) context->adpcm.ms.delta[0] = 16; @@ -622,24 +851,24 @@ static BOOL freerdp_dsp_encode_ms_adpcm(FREERDP_DSP_CONTEXT* context, while (size > 0) { - if ((dst - context->adpcm_buffer) % block_size == 0) + if ((dst - Stream_Buffer(out)) % context->format.nBlockAlign == 0) { - if (channels > 1) + if (context->format.nChannels > 1) { *dst++ = context->adpcm.ms.predictor[0]; *dst++ = context->adpcm.ms.predictor[1]; - *dst++ = (BYTE) (context->adpcm.ms.delta[0] & 0xFF); - *dst++ = (BYTE) ((context->adpcm.ms.delta[0] >> 8) & 0xFF); - *dst++ = (BYTE) (context->adpcm.ms.delta[1] & 0xFF); - *dst++ = (BYTE) ((context->adpcm.ms.delta[1] >> 8) & 0xFF); - context->adpcm.ms.sample1[0] = *((INT16*) (src + 4)); - context->adpcm.ms.sample1[1] = *((INT16*) (src + 6)); - context->adpcm.ms.sample2[0] = *((INT16*) (src + 0)); - context->adpcm.ms.sample2[1] = *((INT16*) (src + 2)); - *((INT16*) (dst + 0)) = (INT16) context->adpcm.ms.sample1[0]; - *((INT16*) (dst + 2)) = (INT16) context->adpcm.ms.sample1[1]; - *((INT16*) (dst + 4)) = (INT16) context->adpcm.ms.sample2[0]; - *((INT16*) (dst + 6)) = (INT16) context->adpcm.ms.sample2[1]; + *dst++ = (BYTE)(context->adpcm.ms.delta[0] & 0xFF); + *dst++ = (BYTE)((context->adpcm.ms.delta[0] >> 8) & 0xFF); + *dst++ = (BYTE)(context->adpcm.ms.delta[1] & 0xFF); + *dst++ = (BYTE)((context->adpcm.ms.delta[1] >> 8) & 0xFF); + context->adpcm.ms.sample1[0] = *((INT16*)(src + 4)); + context->adpcm.ms.sample1[1] = *((INT16*)(src + 6)); + context->adpcm.ms.sample2[0] = *((INT16*)(src + 0)); + context->adpcm.ms.sample2[1] = *((INT16*)(src + 2)); + *((INT16*)(dst + 0)) = (INT16) context->adpcm.ms.sample1[0]; + *((INT16*)(dst + 2)) = (INT16) context->adpcm.ms.sample1[1]; + *((INT16*)(dst + 4)) = (INT16) context->adpcm.ms.sample2[0]; + *((INT16*)(dst + 6)) = (INT16) context->adpcm.ms.sample2[1]; dst += 8; src += 8; size -= 8; @@ -647,12 +876,12 @@ static BOOL freerdp_dsp_encode_ms_adpcm(FREERDP_DSP_CONTEXT* context, else { *dst++ = context->adpcm.ms.predictor[0]; - *dst++ = (BYTE) (context->adpcm.ms.delta[0] & 0xFF); - *dst++ = (BYTE) ((context->adpcm.ms.delta[0] >> 8) & 0xFF); - context->adpcm.ms.sample1[0] = *((INT16*) (src + 2)); - context->adpcm.ms.sample2[0] = *((INT16*) (src + 0)); - *((INT16*) (dst + 0)) = (INT16) context->adpcm.ms.sample1[0]; - *((INT16*) (dst + 2)) = (INT16) context->adpcm.ms.sample2[0]; + *dst++ = (BYTE)(context->adpcm.ms.delta[0] & 0xFF); + *dst++ = (BYTE)((context->adpcm.ms.delta[0] >> 8) & 0xFF); + context->adpcm.ms.sample1[0] = *((INT16*)(src + 2)); + context->adpcm.ms.sample2[0] = *((INT16*)(src + 0)); + *((INT16*)(dst + 0)) = (INT16) context->adpcm.ms.sample1[0]; + *((INT16*)(dst + 2)) = (INT16) context->adpcm.ms.sample2[0]; dst += 4; src += 4; size -= 4; @@ -664,38 +893,305 @@ static BOOL freerdp_dsp_encode_ms_adpcm(FREERDP_DSP_CONTEXT* context, *dst = freerdp_dsp_encode_ms_adpcm_sample(&context->adpcm, sample, 0) << 4; sample = *((INT16*) src); src += 2; - *dst += freerdp_dsp_encode_ms_adpcm_sample(&context->adpcm, sample, channels > 1 ? 1 : 0); + *dst += freerdp_dsp_encode_ms_adpcm_sample(&context->adpcm, sample, + context->format.nChannels > 1 ? 1 : 0); dst++; size -= 4; } - - context->adpcm_size = dst - context->adpcm_buffer; + + Stream_SetPointer(out, dst); return TRUE; } -FREERDP_DSP_CONTEXT* freerdp_dsp_context_new(void) +FREERDP_DSP_CONTEXT* freerdp_dsp_context_new(BOOL encoder) { - FREERDP_DSP_CONTEXT* context; +#if defined(WITH_DSP_FFMPEG) + return freerdp_dsp_ffmpeg_context_new(encoder); +#else + FREERDP_DSP_CONTEXT* context = calloc(1, sizeof(FREERDP_DSP_CONTEXT)); - context = (FREERDP_DSP_CONTEXT*) calloc(1, sizeof(FREERDP_DSP_CONTEXT)); if (!context) return NULL; - context->resample = freerdp_dsp_resample; - context->decode_ima_adpcm = freerdp_dsp_decode_ima_adpcm; - context->encode_ima_adpcm = freerdp_dsp_encode_ima_adpcm; - context->decode_ms_adpcm = freerdp_dsp_decode_ms_adpcm; - context->encode_ms_adpcm = freerdp_dsp_encode_ms_adpcm; + context->buffer = Stream_New(NULL, 4096); + if (!context->buffer) + goto fail; + + context->resample = Stream_New(NULL, 4096); + + if (!context->resample) + goto fail; + + context->encoder = encoder; +#if defined(WITH_GSM) + context->gsm = gsm_create(); + + if (!context->gsm) + goto fail; + + { + int rc; + int val = 1; + + rc = gsm_option(context->gsm, GSM_OPT_WAV49, &val); + + if (rc < 0) + goto fail; + } +#endif +#if defined(WITH_LAME) + + if (encoder) + { + context->lame = lame_init(); + + if (!context->lame) + goto fail; + } + else + { + context->hip = hip_decode_init(); + + if (!context->hip) + goto fail; + } + +#endif +#if defined(WITH_FAAD2) + + if (!encoder) + { + context->faad = NeAACDecOpen(); + + if (!context->faad) + goto fail; + } + +#endif return context; +fail: + freerdp_dsp_context_free(context); + return NULL; +#endif } void freerdp_dsp_context_free(FREERDP_DSP_CONTEXT* context) { +#if defined(WITH_DSP_FFMPEG) + freerdp_dsp_ffmpeg_context_free(context); +#else + if (context) { - free(context->resampled_buffer); - free(context->adpcm_buffer); + Stream_Free(context->buffer, TRUE); + Stream_Free(context->resample, TRUE); +#if defined(WITH_GSM) + gsm_destroy(context->gsm); +#endif +#if defined(WITH_LAME) + + if (context->encoder) + lame_close(context->lame); + else + hip_decode_exit(context->hip); + +#endif +#if defined(WITH_FAAD2) + + if (!context->encoder) + NeAACDecClose(context->faad); + +#endif +#if defined (WITH_FAAC) + + if (context->faac) + faacEncClose(context->faac); + +#endif free(context); } + +#endif +} + +BOOL freerdp_dsp_encode(FREERDP_DSP_CONTEXT* context, const AUDIO_FORMAT* srcFormat, + const BYTE* data, size_t length, wStream* out) +{ +#if defined(WITH_DSP_FFMPEG) + return freerdp_dsp_ffmpeg_encode(context, srcFormat, data, length, out); +#else + + if (!context || !context->encoder || !srcFormat || !data || !out) + return FALSE; + + // TODO: Resample + + switch (context->format.wFormatTag) + { + case WAVE_FORMAT_PCM: + if (!Stream_EnsureRemainingCapacity(out, length)) + return FALSE; + + Stream_Write(out, data, length); + return TRUE; + + case WAVE_FORMAT_ADPCM: + return freerdp_dsp_encode_ms_adpcm(context, data, length, out); + + case WAVE_FORMAT_DVI_ADPCM: + return freerdp_dsp_encode_ima_adpcm(context, data, length, out); +#if defined(WITH_GSM) + + case WAVE_FORMAT_GSM610: + return freerdp_dsp_encode_gsm610(context, data, length, out); +#endif +#if defined(WITH_LAME) + + case WAVE_FORMAT_MPEGLAYER3: + return freerdp_dsp_encode_mp3(context, data, length, out); +#endif +#if defined(WITH_FAAC) + + case WAVE_FORMAT_AAC_MS: + return freerdp_dsp_encode_faac(context, data, length, out); +#endif + + default: + return FALSE; + } + + return FALSE; +#endif +} + +BOOL freerdp_dsp_decode(FREERDP_DSP_CONTEXT* context, const AUDIO_FORMAT* srcFormat, + const BYTE* data, size_t length, wStream* out) +{ +#if defined(WITH_DSP_FFMPEG) + return freerdp_dsp_ffmpeg_decode(context, srcFormat, data, length, out); +#else + + if (!context || context->encoder || !srcFormat || !data || !out) + return FALSE; + + switch (context->format.wFormatTag) + { + case WAVE_FORMAT_PCM: + if (!Stream_EnsureRemainingCapacity(out, length)) + return FALSE; + + Stream_Write(out, data, length); + return TRUE; + + case WAVE_FORMAT_ADPCM: + return freerdp_dsp_decode_ms_adpcm(context, data, length, out); + + case WAVE_FORMAT_DVI_ADPCM: + return freerdp_dsp_decode_ima_adpcm(context, data, length, out); +#if defined(WITH_GSM) + + case WAVE_FORMAT_GSM610: + return freerdp_dsp_decode_gsm610(context, data, length, out); +#endif +#if defined(WITH_LAME) + + case WAVE_FORMAT_MPEGLAYER3: + return freerdp_dsp_decode_mp3(context, data, length, out); +#endif +#if defined(WITH_FAAD2) + + case WAVE_FORMAT_AAC_MS: + return freerdp_dsp_decode_faad(context, data, length, out); +#endif + + default: + return FALSE; + } + + return FALSE; +#endif +} + +BOOL freerdp_dsp_supports_format(const AUDIO_FORMAT* format, BOOL encode) +{ +#if defined(WITH_DSP_FFMPEG) + return freerdp_dsp_ffmpeg_supports_format(format, encode); +#else + + switch (format->wFormatTag) + { + case WAVE_FORMAT_PCM: + case WAVE_FORMAT_ADPCM: + case WAVE_FORMAT_DVI_ADPCM: + return TRUE; +#if defined(WITH_GSM) + + case WAVE_FORMAT_GSM610: + return TRUE; +#endif +#if defined(WITH_LAME) + + case WAVE_FORMAT_MPEGLAYER3: + return TRUE; +#endif + + case WAVE_FORMAT_AAC_MS: +#if defined(WITH_FAAD2) + if (!encode) + return TRUE; + +#endif +#if defined(WITH_FAAC) + + if (encode) + return TRUE; + +#endif + + default: + return FALSE; + } + + return FALSE; +#endif +} + + +BOOL freerdp_dsp_context_reset(FREERDP_DSP_CONTEXT* context, const AUDIO_FORMAT* targetFormat) +{ +#if defined(WITH_DSP_FFMPEG) + return freerdp_dsp_ffmpeg_context_reset(context, targetFormat); +#else + + if (!context || !targetFormat) + return FALSE; + + context->format = *targetFormat; +#if defined(WITH_FAAD2) + context->faadSetup = FALSE; +#endif +#if defined(WITH_FAAC) + + if (context->encoder) + { + faacEncConfigurationPtr cfg; + + if (context->faac) + faacEncClose(context->faac); + + context->faac = faacEncOpen(targetFormat->nSamplesPerSec, targetFormat->nChannels, + &context->faacInputSamples, &context->faacMaxOutputBytes); + + if (!context->faac) + return FALSE; + + cfg = faacEncGetCurrentConfiguration(context->faac); + cfg->bitRate = 10000; + faacEncSetConfiguration(context->faac, cfg); + } + +#endif + return TRUE; +#endif } diff --git a/libfreerdp/codec/dsp.h b/libfreerdp/codec/dsp.h new file mode 100644 index 000000000..c932efe77 --- /dev/null +++ b/libfreerdp/codec/dsp.h @@ -0,0 +1,34 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Digital Sound Processing - backend + * + * Copyright 2018 Armin Novak + * Copyright 2018 Thincast Technologies GmbH + * + * 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 + * limitations under the License. + */ + +#ifndef FREERDP_LIB_CODEC_DSP_H +#define FREERDP_LIB_CODEC_DSP_H + +#include +#include +#include + +struct _FREERDP_DSP_COMMON_CONTEXT +{ + wStream* buffer; + wStream* resample; +}; + +#endif /* FREERDP_LIB_CODEC_DSP_H */ diff --git a/libfreerdp/codec/dsp_ffmpeg.c b/libfreerdp/codec/dsp_ffmpeg.c new file mode 100644 index 000000000..b48dbbf64 --- /dev/null +++ b/libfreerdp/codec/dsp_ffmpeg.c @@ -0,0 +1,566 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Digital Sound Processing - FFMPEG backend + * + * Copyright 2018 Armin Novak + * Copyright 2018 Thincast Technologies GmbH + * + * 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 + * limitations under the License. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include +#include +#include +#include + +#include "dsp.h" +#include "dsp_ffmpeg.h" + +#define TAG FREERDP_TAG("dsp.ffmpeg") + +struct _FREERDP_DSP_CONTEXT +{ + AUDIO_FORMAT format; + + BOOL isOpen; + BOOL encoder; + + UINT32 bufferedSamples; + + enum AVCodecID id; + AVCodec* codec; + AVCodecContext* context; + AVFrame* frame; + AVFrame* resampled; + AVFrame* buffered; + AVPacket* packet; + AVAudioResampleContext* rcontext; +}; + +static enum AVCodecID ffmpeg_get_avcodec(const AUDIO_FORMAT* format) +{ + const char* id; + + if (!format) + return AV_CODEC_ID_NONE; + + id = rdpsnd_get_audio_tag_string(format->wFormatTag); + + switch (format->wFormatTag) + { + case WAVE_FORMAT_UNKNOWN: + return AV_CODEC_ID_NONE; + + case WAVE_FORMAT_PCM: + switch (format->wBitsPerSample) + { + case 16: + return AV_CODEC_ID_PCM_U16LE; + + case 8: + return AV_CODEC_ID_PCM_U8; + + default: + return AV_CODEC_ID_NONE; + } + + case WAVE_FORMAT_DVI_ADPCM: + return AV_CODEC_ID_ADPCM_MS; + + case WAVE_FORMAT_ADPCM: + return AV_CODEC_ID_ADPCM_MS; + + case WAVE_FORMAT_ALAW: + return AV_CODEC_ID_PCM_ALAW; + + case WAVE_FORMAT_MULAW: + return AV_CODEC_ID_PCM_MULAW; + + case WAVE_FORMAT_GSM610: + return AV_CODEC_ID_GSM_MS; + + case WAVE_FORMAT_AAC_MS: + return AV_CODEC_ID_AAC; + + default: + return AV_CODEC_ID_NONE; + } +} + + +static int ffmpeg_sample_format(const AUDIO_FORMAT* format) +{ + switch (format->wFormatTag) + { + case WAVE_FORMAT_PCM: + switch (format->wBitsPerSample) + { + case 8: + return AV_SAMPLE_FMT_U8; + + case 16: + return AV_SAMPLE_FMT_S16; + + default: + return FALSE; + } + + case WAVE_FORMAT_DVI_ADPCM: + case WAVE_FORMAT_ADPCM: + return AV_SAMPLE_FMT_S16P; + + case WAVE_FORMAT_MPEGLAYER3: + case WAVE_FORMAT_AAC_MS: + return AV_SAMPLE_FMT_FLTP; + + case WAVE_FORMAT_GSM610: + return AV_SAMPLE_FMT_S16P; + + case WAVE_FORMAT_ALAW: + return AV_SAMPLE_FMT_S16; + + default: + return FALSE; + } +} + +static void ffmpeg_close_context(FREERDP_DSP_CONTEXT* context) +{ + if (context) + { + if (context->context) + avcodec_free_context(&context->context); + + if (context->frame) + av_frame_free(&context->frame); + + if (context->resampled) + av_frame_free(&context->resampled); + + if (context->buffered) + av_frame_free(&context->buffered); + + if (context->packet) + av_packet_free(&context->packet); + + if (context->rcontext) + avresample_free(&context->rcontext); + + context->id = AV_CODEC_ID_NONE; + context->codec = NULL; + context->isOpen = FALSE; + context->context = NULL; + context->frame = NULL; + context->resampled = NULL; + context->packet = NULL; + context->rcontext = NULL; + } +} +static BOOL ffmpeg_open_context(FREERDP_DSP_CONTEXT* context) +{ + int ret; + int layout; + const AUDIO_FORMAT* format; + + if (!context || context->isOpen) + return FALSE; + + format = &context->format; + + if (!format) + return FALSE; + + layout = av_get_default_channel_layout(format->nChannels); + context->id = ffmpeg_get_avcodec(format); + + if (context->id == AV_CODEC_ID_NONE) + goto fail; + + if (context->encoder) + context->codec = avcodec_find_encoder(context->id); + else + context->codec = avcodec_find_decoder(context->id); + + if (!context->codec) + goto fail; + + context->context = avcodec_alloc_context3(context->codec); + + if (!context->context) + goto fail; + + switch(context->id) + { + /* We need support for multichannel and sample rates != 8000 */ + case AV_CODEC_ID_GSM_MS: + context->context->strict_std_compliance = FF_COMPLIANCE_UNOFFICIAL; + break; + default: + break; + } + + context->context->channels = format->nChannels; + context->context->channel_layout = layout; + context->context->sample_rate = format->nSamplesPerSec; + context->context->block_align = format->nBlockAlign; + context->context->bit_rate = format->nAvgBytesPerSec * 8; + context->context->sample_fmt = ffmpeg_sample_format(format); + context->context->time_base = av_make_q(1, context->context->sample_rate); + + if ((ret = avcodec_open2(context->context, context->codec, NULL)) < 0) + { + const char* err = av_err2str(ret); + WLog_ERR(TAG, "Error avcodec_open2 %s [%d]", err, ret); + goto fail; + } + + context->packet = av_packet_alloc(); + + if (!context->packet) + goto fail; + + context->frame = av_frame_alloc(); + + if (!context->frame) + goto fail; + + context->resampled = av_frame_alloc(); + + if (!context->resampled) + goto fail; + + context->buffered = av_frame_alloc(); + + if (!context->buffered) + goto fail; + + context->rcontext = avresample_alloc_context(); + + if (!context->rcontext) + goto fail; + + context->frame->channel_layout = layout; + context->frame->channels = format->nChannels; + context->frame->sample_rate = format->nSamplesPerSec; + context->frame->format = AV_SAMPLE_FMT_S16; + + if (context->encoder) + { + context->resampled->format = context->context->sample_fmt; + context->resampled->sample_rate = context->context->sample_rate; + } + else + { + context->resampled->format = AV_SAMPLE_FMT_S16; + context->resampled->sample_rate = format->nSamplesPerSec; + } + + context->resampled->channel_layout = layout; + context->resampled->channels = format->nChannels; + + if (context->context->frame_size > 0) + { + context->buffered->channel_layout = context->resampled->channel_layout; + context->buffered->channels = context->resampled->channels; + context->buffered->format = context->resampled->format; + context->buffered->nb_samples = context->context->frame_size; + + if ((ret = av_frame_get_buffer(context->buffered, 1)) < 0) + goto fail; + } + + context->isOpen = TRUE; + return TRUE; +fail: + ffmpeg_close_context(context); + return FALSE; +} +static BOOL ffmpeg_resample_frame(AVAudioResampleContext* context, + AVFrame* in, AVFrame* out) +{ + int ret; + + if (!avresample_is_open(context)) + { + if ((ret = avresample_config(context, out, in)) < 0) + { + const char* err = av_err2str(ret); + WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret); + return FALSE; + } + + if ((ret = (avresample_open(context))) < 0) + { + const char* err = av_err2str(ret); + WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret); + return FALSE; + } + } + + if ((ret = avresample_convert_frame(context, out, in)) < 0) + { + const char* err = av_err2str(ret); + WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret); + return FALSE; + } + + return TRUE; +} +static BOOL ffmpeg_encode_frame(AVCodecContext* context, AVFrame* in, + AVPacket* packet, wStream* out) +{ + int ret; + /* send the packet with the compressed data to the encoder */ + ret = avcodec_send_frame(context, in); + + if (ret < 0) + { + const char* err = av_err2str(ret); + WLog_ERR(TAG, "Error submitting the packet to the encoder %s [%d]", + err, ret); + return FALSE; + } + + /* read all the output frames (in general there may be any number of them */ + while (ret >= 0) + { + ret = avcodec_receive_packet(context, packet); + + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) + return TRUE; + else if (ret < 0) + { + const char* err = av_err2str(ret); + WLog_ERR(TAG, "Error during encoding %s [%d]", err, ret); + return FALSE; + } + + if (!Stream_EnsureRemainingCapacity(out, packet->size)) + return FALSE; + + Stream_Write(out, packet->data, packet->size); + av_packet_unref(packet); + } + + return TRUE; +} + +static BOOL ffmpeg_fill_frame(AVFrame* frame, const AUDIO_FORMAT* inputFormat, + const BYTE* data, size_t size) +{ + int ret, bpp; + frame->channels = inputFormat->nChannels; + frame->sample_rate = inputFormat->nSamplesPerSec; + frame->format = ffmpeg_sample_format(inputFormat); + frame->channel_layout = av_get_default_channel_layout(frame->channels); + bpp = av_get_bytes_per_sample(frame->format); + frame->nb_samples = size / inputFormat->nChannels / bpp; + + if ((ret = avcodec_fill_audio_frame(frame, frame->channels, + frame->format, + data, size, 1)) < 0) + { + const char* err = av_err2str(ret); + WLog_ERR(TAG, "Error during audio frame fill %s [%d]", err, ret); + return FALSE; + } + + return TRUE; +} +static BOOL ffmpeg_decode(AVCodecContext* dec_ctx, AVPacket* pkt, + AVFrame* frame, + AVAudioResampleContext* resampleContext, + AVFrame* resampled, wStream* out) +{ + int ret; + /* send the packet with the compressed data to the decoder */ + ret = avcodec_send_packet(dec_ctx, pkt); + + if (ret < 0) + { + const char* err = av_err2str(ret); + WLog_ERR(TAG, "Error submitting the packet to the decoder %s [%d]", + err, ret); + return FALSE; + } + + /* read all the output frames (in general there may be any number of them */ + while (ret >= 0) + { + ret = avcodec_receive_frame(dec_ctx, frame); + + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) + return TRUE; + else if (ret < 0) + { + const char* err = av_err2str(ret); + WLog_ERR(TAG, "Error during decoding %s [%d]", err, ret); + return FALSE; + } + + if (!avresample_is_open(resampleContext)) + { + if ((ret = avresample_config(resampleContext, resampled, frame)) < 0) + { + const char* err = av_err2str(ret); + WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret); + return FALSE; + } + + if ((ret = (avresample_open(resampleContext))) < 0) + { + const char* err = av_err2str(ret); + WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret); + return FALSE; + } + } + + if ((ret = avresample_convert_frame(resampleContext, resampled, frame)) < 0) + { + const char* err = av_err2str(ret); + WLog_ERR(TAG, "Error during resampling %s [%d]", err, ret); + return FALSE; + } + + { + const size_t data_size = resampled->channels * resampled->nb_samples * 2; + Stream_EnsureRemainingCapacity(out, data_size); + Stream_Write(out, resampled->data[0], data_size); + } + } + + return TRUE; +} + +BOOL freerdp_dsp_ffmpeg_supports_format(const AUDIO_FORMAT* format, BOOL encode) +{ + enum AVCodecID id = ffmpeg_get_avcodec(format); + + if (id == AV_CODEC_ID_NONE) + return FALSE; + + if (encode) + return avcodec_find_encoder(id) != NULL; + else + return avcodec_find_decoder(id) != NULL; +} + +FREERDP_DSP_CONTEXT* freerdp_dsp_ffmpeg_context_new(BOOL encode) +{ + FREERDP_DSP_CONTEXT* context; + avcodec_register_all(); + context = calloc(1, sizeof(FREERDP_DSP_CONTEXT)); + + if (!context) + return NULL; + + context->encoder = encode; + return context; +} + +void freerdp_dsp_ffmpeg_context_free(FREERDP_DSP_CONTEXT* context) +{ + if (context) + { + ffmpeg_close_context(context); + free(context); + } +} + +BOOL freerdp_dsp_ffmpeg_context_reset(FREERDP_DSP_CONTEXT* context, + const AUDIO_FORMAT* targetFormat) +{ + if (!context || !targetFormat) + return FALSE; + + ffmpeg_close_context(context); + context->format = *targetFormat; + return ffmpeg_open_context(context); +} + +BOOL freerdp_dsp_ffmpeg_encode(FREERDP_DSP_CONTEXT* context, const AUDIO_FORMAT* format, + const BYTE* data, size_t length, wStream* out) +{ + int rc; + int samples, rest; + + if (!context || !format || !data || !out || !context->encoder) + return FALSE; + + if (!context || !data || !out) + return FALSE; + + /* Create input frame */ + if (!ffmpeg_fill_frame(context->frame, format, data, length)) + return FALSE; + + /* Resample to desired format. */ + if (!ffmpeg_resample_frame(context->rcontext, + context->frame, + context->resampled)) + return FALSE; + + if (context->context->frame_size <= 0) + { + return ffmpeg_encode_frame(context->context, context->resampled, + context->packet, out); + } + else + { + rest = samples = context->resampled->nb_samples; + + do + { + if (samples + context->bufferedSamples > context->context->frame_size) + samples = context->context->frame_size - context->bufferedSamples; + + rc = av_samples_copy(context->buffered->extended_data, context->resampled->extended_data, + context->bufferedSamples, 0, samples, + context->context->channels, context->context->sample_fmt); + rest -= samples; + context->bufferedSamples += samples; + + if (context->context->frame_size <= context->bufferedSamples) + { + /* Encode in desired format. */ + if (!ffmpeg_encode_frame(context->context, context->buffered, + context->packet, out)) + return FALSE; + + context->bufferedSamples = 0; + } + } + while (rest > 0); + + return TRUE; + } +} + +BOOL freerdp_dsp_ffmpeg_decode(FREERDP_DSP_CONTEXT* context, const AUDIO_FORMAT* srcFormat, + const BYTE* data, size_t length, wStream* out) +{ + if (!context || !srcFormat || !data || !out || context->encoder) + return FALSE; + + av_init_packet(context->packet); + context->packet->data = data; + context->packet->size = length; + return ffmpeg_decode(context->context, context->packet, context->frame, + context->rcontext, context->resampled, out); +} diff --git a/libfreerdp/codec/dsp_ffmpeg.h b/libfreerdp/codec/dsp_ffmpeg.h new file mode 100644 index 000000000..450cee8bf --- /dev/null +++ b/libfreerdp/codec/dsp_ffmpeg.h @@ -0,0 +1,42 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Digital Sound Processing - FFMPEG backend + * + * Copyright 2018 Armin Novak + * Copyright 2018 Thincast Technologies GmbH + * + * 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 + * limitations under the License. + */ + +#ifndef FREERDP_LIB_CODEC_DSP_FFMPEG_H +#define FREERDP_LIB_CODEC_DSP_FFMPEG_H + +#include +#include +#include + +FREERDP_DSP_CONTEXT* freerdp_dsp_ffmpeg_context_new(BOOL encode); +BOOL freerdp_dsp_ffmpeg_supports_format(const AUDIO_FORMAT* format, BOOL encode); +BOOL freerdp_dsp_ffmpeg_encode(FREERDP_DSP_CONTEXT* context, + const AUDIO_FORMAT* srcFormat, + const BYTE* data, size_t length, + wStream* out); +BOOL freerdp_dsp_ffmpeg_decode(FREERDP_DSP_CONTEXT* context, + const AUDIO_FORMAT* srcFormat, + const BYTE* data, size_t length, + wStream* out); +void freerdp_dsp_ffmpeg_context_free(FREERDP_DSP_CONTEXT* context); +BOOL freerdp_dsp_ffmpeg_context_reset(FREERDP_DSP_CONTEXT* context, + const AUDIO_FORMAT* targetFormat); + +#endif /* FREERDP_LIB_CODEC_DSP_FFMPEG_H */ diff --git a/server/shadow/shadow_audin.c b/server/shadow/shadow_audin.c index fa04d4f51..0c5f421d9 100644 --- a/server/shadow/shadow_audin.c +++ b/server/shadow/shadow_audin.c @@ -43,6 +43,7 @@ static UINT AudinServerOpening(audin_server_context* context) { AUDIO_FORMAT* agreed_format = NULL; int i = 0, j = 0; + for (i = 0; i < context->num_client_formats; i++) { for (j = 0; j < context->num_server_formats; j++) @@ -55,9 +56,9 @@ static UINT AudinServerOpening(audin_server_context* context) break; } } + if (agreed_format != NULL) break; - } if (agreed_format == NULL) @@ -94,6 +95,7 @@ static UINT AudinServerReceiveSamples(audin_server_context* context, const void* if (subsystem->AudinServerReceiveSamples) subsystem->AudinServerReceiveSamples(subsystem, client, buf, nframes); + return CHANNEL_RC_OK; } @@ -101,6 +103,7 @@ int shadow_client_audin_init(rdpShadowClient* client) { audin_server_context* audin; audin = client->audin = audin_server_context_new(client->vcm); + if (!audin) { return 0; @@ -121,11 +124,9 @@ int shadow_client_audin_init(rdpShadowClient* client) } audin->dst_format = audin->server_formats[0]; - audin->Opening = AudinServerOpening; audin->OpenResult = AudinServerOpenResult; audin->ReceiveSamples = AudinServerReceiveSamples; - return 1; }