mirror of
https://github.com/FreeRDP/FreeRDP.git
synced 2024-11-23 01:44:35 +08:00
channels/rdpsnd: initial attempt at adding GSM610 support
This commit is contained in:
parent
690a6b624d
commit
76c842285d
@ -381,6 +381,10 @@ set(JPEG_FEATURE_TYPE "OPTIONAL")
|
||||
set(JPEG_FEATURE_PURPOSE "codec")
|
||||
set(JPEG_FEATURE_DESCRIPTION "use JPEG library")
|
||||
|
||||
set(GSM_FEATURE_TYPE "OPTIONAL")
|
||||
set(GSM_FEATURE_PURPOSE "codec")
|
||||
set(GSM_FEATURE_DESCRIPTION "GSM audio codec library")
|
||||
|
||||
if(WIN32)
|
||||
set(X11_FEATURE_TYPE "DISABLED")
|
||||
set(ZLIB_FEATURE_TYPE "DISABLED")
|
||||
@ -445,6 +449,7 @@ find_feature(FFmpeg ${FFMPEG_FEATURE_TYPE} ${FFMPEG_FEATURE_PURPOSE} ${FFMPEG_FE
|
||||
find_feature(Gstreamer ${GSTREAMER_FEATURE_TYPE} ${GSTREAMER_FEATURE_PURPOSE} ${GSTREAMER_FEATURE_DESCRIPTION})
|
||||
|
||||
find_feature(JPEG ${JPEG_FEATURE_TYPE} ${JPEG_FEATURE_PURPOSE} ${JPEG_FEATURE_DESCRIPTION})
|
||||
find_feature(GSM ${GSM_FEATURE_TYPE} ${GSM_FEATURE_PURPOSE} ${GSM_FEATURE_DESCRIPTION})
|
||||
|
||||
if(TARGET_ARCH MATCHES "x86|x64")
|
||||
if (NOT APPLE)
|
||||
|
@ -32,7 +32,11 @@ set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
||||
MODULE freerdp
|
||||
MODULES freerdp-codec freerdp-utils)
|
||||
|
||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${PULSE_LIBRARY})
|
||||
list(APPEND ${MODULE_PREFIX}_LIBS ${PULSE_LIBRARY})
|
||||
|
||||
if(GSM_FOUND)
|
||||
list(APPEND ${MODULE_PREFIX}_LIBS ${GSM_LIBRARIES})
|
||||
endif()
|
||||
|
||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||
|
||||
|
@ -26,10 +26,15 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/stream.h>
|
||||
#include <winpr/cmdline.h>
|
||||
|
||||
#include <pulse/pulseaudio.h>
|
||||
|
||||
#ifdef WITH_GSM
|
||||
#include <gsm/gsm.h>
|
||||
#endif
|
||||
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/codec/dsp.h>
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
@ -52,6 +57,11 @@ struct rdpsnd_pulse_plugin
|
||||
int latency;
|
||||
|
||||
FREERDP_DSP_CONTEXT* dsp_context;
|
||||
|
||||
#ifdef WITH_GSM
|
||||
gsm gsm_context;
|
||||
wStream* gsmBuffer;
|
||||
#endif
|
||||
};
|
||||
|
||||
static void rdpsnd_pulse_context_state_callback(pa_context* context, void* userdata)
|
||||
@ -241,6 +251,7 @@ static void rdpsnd_pulse_set_format_spec(rdpsndPulsePlugin* pulse, AUDIO_FORMAT*
|
||||
break;
|
||||
|
||||
case WAVE_FORMAT_GSM610:
|
||||
sample_spec.format = PA_SAMPLE_S16LE;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -331,6 +342,14 @@ static void rdpsnd_pulse_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format,
|
||||
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
|
||||
|
||||
DEBUG_SVC("connected");
|
||||
}
|
||||
else
|
||||
@ -410,7 +429,18 @@ static BOOL rdpsnd_pulse_format_supported(rdpsndDevicePlugin* device, AUDIO_FORM
|
||||
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;
|
||||
}
|
||||
|
||||
@ -459,63 +489,108 @@ static void rdpsnd_pulse_set_volume(rdpsndDevicePlugin* device, UINT32 value)
|
||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||
}
|
||||
|
||||
static BYTE* rdpsnd_pulse_convert_audio(rdpsndDevicePlugin* device, BYTE* data, int* 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;
|
||||
}
|
||||
|
||||
Stream_EnsureRemainingCapacity(pulse->gsmBuffer, 160 * 2);
|
||||
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 len;
|
||||
int ret;
|
||||
BYTE* src;
|
||||
int length;
|
||||
int status;
|
||||
BYTE* pcmData;
|
||||
rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*) device;
|
||||
|
||||
if (!pulse->stream)
|
||||
return;
|
||||
|
||||
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;
|
||||
src = 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;
|
||||
src = pulse->dsp_context->adpcm_buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
src = data;
|
||||
}
|
||||
pcmData = rdpsnd_pulse_convert_audio(device, data, &size);
|
||||
|
||||
pa_threaded_mainloop_lock(pulse->mainloop);
|
||||
|
||||
while (size > 0)
|
||||
{
|
||||
while ((len = pa_stream_writable_size(pulse->stream)) == 0)
|
||||
while ((length = pa_stream_writable_size(pulse->stream)) == 0)
|
||||
{
|
||||
pa_threaded_mainloop_wait(pulse->mainloop);
|
||||
}
|
||||
|
||||
if (len < 0)
|
||||
if (length < 0)
|
||||
break;
|
||||
|
||||
if (len > size)
|
||||
len = size;
|
||||
if (length > size)
|
||||
length = size;
|
||||
|
||||
ret = pa_stream_write(pulse->stream, src, len, NULL, 0LL, PA_SEEK_RELATIVE);
|
||||
status = pa_stream_write(pulse->stream, pcmData, length, NULL, 0LL, PA_SEEK_RELATIVE);
|
||||
|
||||
if (ret < 0)
|
||||
if (status < 0)
|
||||
{
|
||||
DEBUG_WARN("pa_stream_write failed (%d)",
|
||||
pa_context_errno(pulse->context));
|
||||
break;
|
||||
}
|
||||
|
||||
src += len;
|
||||
size -= len;
|
||||
pcmData += length;
|
||||
size -= length;
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||
@ -595,6 +670,10 @@ int freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pE
|
||||
|
||||
pulse->dsp_context = freerdp_dsp_context_new();
|
||||
|
||||
#ifdef WITH_GSM
|
||||
pulse->gsmBuffer = Stream_New(NULL, 4096);
|
||||
#endif
|
||||
|
||||
pulse->mainloop = pa_threaded_mainloop_new();
|
||||
|
||||
if (!pulse->mainloop)
|
||||
|
13
cmake/FindGSM.cmake
Normal file
13
cmake/FindGSM.cmake
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
find_path(GSM_INCLUDE_DIR gsm/gsm.h)
|
||||
|
||||
find_library(GSM_LIBRARY gsm)
|
||||
|
||||
find_package_handle_standard_args(GSM DEFAULT_MSG GSM_INCLUDE_DIR GSM_LIBRARY)
|
||||
|
||||
if(GSM_FOUND)
|
||||
set(GSM_LIBRARIES ${GSM_LIBRARY})
|
||||
set(GSM_INCLUDE_DIRS ${GSM_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
mark_as_advanced(GSM_INCLUDE_DIR GSM_LIBRARY)
|
@ -44,6 +44,7 @@
|
||||
#cmakedefine WITH_PULSE
|
||||
#cmakedefine WITH_IOSAUDIO
|
||||
#cmakedefine WITH_OPENSLES
|
||||
#cmakedefine WITH_GSM
|
||||
|
||||
/* Plugins */
|
||||
#cmakedefine STATIC_CHANNELS
|
||||
|
@ -35,8 +35,36 @@ UINT32 rdpsnd_compute_audio_time_length(AUDIO_FORMAT* format, int size)
|
||||
* http://msdn.microsoft.com/en-us/library/ms713497.aspx
|
||||
*/
|
||||
|
||||
wSamples = (size * 8) / format->wBitsPerSample;
|
||||
mstime = (((wSamples * 1000) / format->nSamplesPerSec) / format->nChannels);
|
||||
if (format->wBitsPerSample)
|
||||
{
|
||||
wSamples = (size * 8) / format->wBitsPerSample;
|
||||
mstime = (((wSamples * 1000) / format->nSamplesPerSec) / format->nChannels);
|
||||
}
|
||||
else
|
||||
{
|
||||
mstime = 0;
|
||||
|
||||
if (format->wFormatTag == WAVE_FORMAT_GSM610)
|
||||
{
|
||||
UINT16 nSamplesPerBlock;
|
||||
|
||||
if ((format->cbSize == 2) && (format->data))
|
||||
{
|
||||
nSamplesPerBlock = *((UINT16*) format->data);
|
||||
|
||||
wSamples = (size / format->nBlockAlign) * nSamplesPerBlock;
|
||||
mstime = (((wSamples * 1000) / format->nSamplesPerSec) / format->nChannels);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "rdpsnd_compute_audio_time_length: invalid WAVE_FORMAT_GSM610 format\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "rdpsnd_compute_audio_time_length: unknown format %d\n", format->wFormatTag);
|
||||
}
|
||||
}
|
||||
|
||||
return mstime;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user