hardend channel audin
This commit is contained in:
parent
d06da4f1bd
commit
156f86e487
@ -3,6 +3,8 @@
|
||||
* Audio Input Redirection Virtual Channel - ALSA implementation
|
||||
*
|
||||
* Copyright 2010-2011 Vic Lee
|
||||
* Copyright 2015 Thincast Technologies GmbH
|
||||
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -98,11 +100,11 @@ static BOOL audin_alsa_set_params(AudinALSADevice* alsa, snd_pcm_t* capture_hand
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL audin_alsa_thread_receive(AudinALSADevice* alsa, BYTE* src, int size)
|
||||
static WIN32ERROR audin_alsa_thread_receive(AudinALSADevice* alsa, BYTE* src, int size)
|
||||
{
|
||||
int frames;
|
||||
int cframes;
|
||||
int ret = 0;
|
||||
WIN32ERROR ret = CHANNEL_RC_OK;
|
||||
int encoded_size;
|
||||
BYTE* encoded_data;
|
||||
int rbytes_per_frame;
|
||||
@ -174,7 +176,7 @@ static BOOL audin_alsa_thread_receive(AudinALSADevice* alsa, BYTE* src, int size
|
||||
|
||||
alsa->buffer_frames = 0;
|
||||
|
||||
if (!ret)
|
||||
if (ret != CHANNEL_RC_OK)
|
||||
break;
|
||||
}
|
||||
|
||||
@ -182,12 +184,12 @@ static BOOL audin_alsa_thread_receive(AudinALSADevice* alsa, BYTE* src, int size
|
||||
frames -= cframes;
|
||||
}
|
||||
|
||||
return (ret) ? TRUE : FALSE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void* audin_alsa_thread_func(void* arg)
|
||||
{
|
||||
int error;
|
||||
long error;
|
||||
BYTE* buffer;
|
||||
int rbytes_per_frame;
|
||||
int tbytes_per_frame;
|
||||
@ -198,8 +200,15 @@ static void* audin_alsa_thread_func(void* arg)
|
||||
|
||||
rbytes_per_frame = alsa->actual_channels * alsa->bytes_per_channel;
|
||||
tbytes_per_frame = alsa->target_channels * alsa->bytes_per_channel;
|
||||
buffer = (BYTE*) malloc(rbytes_per_frame * alsa->frames_per_packet);
|
||||
ZeroMemory(buffer, rbytes_per_frame * alsa->frames_per_packet);
|
||||
buffer = (BYTE*) calloc(1, rbytes_per_frame * alsa->frames_per_packet);
|
||||
if (!buffer)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
//TODO: signal error to freerdp
|
||||
ExitThread((DWORD)CHANNEL_RC_NO_MEMORY);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
freerdp_dsp_context_reset_adpcm(alsa->dsp_context);
|
||||
|
||||
do
|
||||
@ -230,9 +239,13 @@ static void* audin_alsa_thread_func(void* arg)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!audin_alsa_thread_receive(alsa, buffer, error * rbytes_per_frame))
|
||||
if ((error = audin_alsa_thread_receive(alsa, buffer, error * rbytes_per_frame)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_alsa_thread_receive failed with error %lu", error);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
while (0);
|
||||
|
||||
@ -242,12 +255,12 @@ static void* audin_alsa_thread_func(void* arg)
|
||||
snd_pcm_close(capture_handle);
|
||||
|
||||
DEBUG_DVC("out");
|
||||
ExitThread(0);
|
||||
ExitThread((DWORD)error);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void audin_alsa_free(IAudinDevice* device)
|
||||
static WIN32ERROR audin_alsa_free(IAudinDevice* device)
|
||||
{
|
||||
AudinALSADevice* alsa = (AudinALSADevice*) device;
|
||||
|
||||
@ -256,6 +269,7 @@ static void audin_alsa_free(IAudinDevice* device)
|
||||
free(alsa->device_name);
|
||||
|
||||
free(alsa);
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static BOOL audin_alsa_format_supported(IAudinDevice* device, audinFormat* format)
|
||||
@ -285,7 +299,7 @@ static BOOL audin_alsa_format_supported(IAudinDevice* device, audinFormat* forma
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void audin_alsa_set_format(IAudinDevice* device, audinFormat* format, UINT32 FramesPerPacket)
|
||||
static WIN32ERROR audin_alsa_set_format(IAudinDevice* device, audinFormat* format, UINT32 FramesPerPacket)
|
||||
{
|
||||
int bs;
|
||||
AudinALSADevice* alsa = (AudinALSADevice*) device;
|
||||
@ -324,36 +338,51 @@ static void audin_alsa_set_format(IAudinDevice* device, audinFormat* format, UIN
|
||||
|
||||
alsa->wformat = format->wFormatTag;
|
||||
alsa->block_size = format->nBlockAlign;
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static void audin_alsa_open(IAudinDevice* device, AudinReceive receive, void* user_data)
|
||||
static WIN32ERROR audin_alsa_open(IAudinDevice* device, AudinReceive receive, void* user_data)
|
||||
{
|
||||
int rbytes_per_frame;
|
||||
int tbytes_per_frame;
|
||||
AudinALSADevice* alsa = (AudinALSADevice*) device;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
alsa->receive = receive;
|
||||
alsa->user_data = user_data;
|
||||
|
||||
rbytes_per_frame = alsa->actual_channels * alsa->bytes_per_channel;
|
||||
tbytes_per_frame = alsa->target_channels * alsa->bytes_per_channel;
|
||||
alsa->buffer = (BYTE*) malloc(tbytes_per_frame * alsa->frames_per_packet);
|
||||
ZeroMemory(alsa->buffer, tbytes_per_frame * alsa->frames_per_packet);
|
||||
alsa->buffer = (BYTE*) calloc(1, tbytes_per_frame * alsa->frames_per_packet);
|
||||
if (!alsa->buffer)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
alsa->buffer_frames = 0;
|
||||
|
||||
alsa->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
alsa->thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) audin_alsa_thread_func, alsa, 0, NULL);
|
||||
if (!(alsa->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateEvent failed!");
|
||||
goto error_out;
|
||||
}
|
||||
// TODO: add mechanism that threads can signal failure
|
||||
if (!(alsa->thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) audin_alsa_thread_func, alsa, 0, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateThread failed!");
|
||||
goto error_out;
|
||||
}
|
||||
return CHANNEL_RC_OK;
|
||||
error_out:
|
||||
free(alsa->buffer);
|
||||
alsa->buffer = NULL;
|
||||
CloseHandle(alsa->stopEvent);
|
||||
alsa->stopEvent = NULL;
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
static void audin_alsa_close(IAudinDevice* device)
|
||||
static WIN32ERROR audin_alsa_close(IAudinDevice* device)
|
||||
{
|
||||
AudinALSADevice* alsa = (AudinALSADevice*) device;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
if (alsa->stopEvent)
|
||||
{
|
||||
SetEvent(alsa->stopEvent);
|
||||
@ -371,6 +400,8 @@ static void audin_alsa_close(IAudinDevice* device)
|
||||
|
||||
alsa->receive = NULL;
|
||||
alsa->user_data = NULL;
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
COMMAND_LINE_ARGUMENT_A audin_alsa_args[] =
|
||||
@ -379,7 +410,7 @@ COMMAND_LINE_ARGUMENT_A audin_alsa_args[] =
|
||||
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
|
||||
};
|
||||
|
||||
static void audin_alsa_parse_addin_args(AudinALSADevice* device, ADDIN_ARGV* args)
|
||||
static WIN32ERROR audin_alsa_parse_addin_args(AudinALSADevice* device, ADDIN_ARGV* args)
|
||||
{
|
||||
int status;
|
||||
DWORD flags;
|
||||
@ -402,24 +433,36 @@ static void audin_alsa_parse_addin_args(AudinALSADevice* device, ADDIN_ARGV* arg
|
||||
CommandLineSwitchCase(arg, "dev")
|
||||
{
|
||||
alsa->device_name = _strdup(arg->Value);
|
||||
if(!alsa->device_name)
|
||||
{
|
||||
WLog_ERR(TAG, "_strdup failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
CommandLineSwitchEnd(arg)
|
||||
}
|
||||
while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
#ifdef STATIC_CHANNELS
|
||||
#define freerdp_audin_client_subsystem_entry alsa_freerdp_audin_client_subsystem_entry
|
||||
#endif
|
||||
|
||||
int freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints)
|
||||
WIN32ERROR freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints)
|
||||
{
|
||||
ADDIN_ARGV* args;
|
||||
AudinALSADevice* alsa;
|
||||
WIN32ERROR error;
|
||||
|
||||
alsa = (AudinALSADevice*) malloc(sizeof(AudinALSADevice));
|
||||
ZeroMemory(alsa, sizeof(AudinALSADevice));
|
||||
alsa = (AudinALSADevice*) calloc(1, sizeof(AudinALSADevice));
|
||||
if (!alsa)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
alsa->iface.Open = audin_alsa_open;
|
||||
alsa->iface.FormatSupported = audin_alsa_format_supported;
|
||||
@ -429,10 +472,22 @@ int freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEnt
|
||||
|
||||
args = pEntryPoints->args;
|
||||
|
||||
audin_alsa_parse_addin_args(alsa, args);
|
||||
if ((error = audin_alsa_parse_addin_args(alsa, args)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_alsa_parse_addin_args failed with errorcode %lu!", error);
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
if (!alsa->device_name)
|
||||
{
|
||||
alsa->device_name = _strdup("default");
|
||||
if (!alsa->device_name)
|
||||
{
|
||||
WLog_ERR(TAG, "_strdup failed!");
|
||||
error = CHANNEL_RC_NO_MEMORY;
|
||||
goto error_out;
|
||||
}
|
||||
}
|
||||
|
||||
alsa->frames_per_packet = 128;
|
||||
alsa->target_rate = 22050;
|
||||
@ -443,8 +498,23 @@ int freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEnt
|
||||
alsa->bytes_per_channel = 2;
|
||||
|
||||
alsa->dsp_context = freerdp_dsp_context_new();
|
||||
|
||||
pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) alsa);
|
||||
|
||||
return 0;
|
||||
if (!alsa->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*) alsa)))
|
||||
{
|
||||
WLog_ERR(TAG, "RegisterAudinDevice failed with error %lu!", error);
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
error_out:
|
||||
freerdp_dsp_context_free(alsa->dsp_context);
|
||||
free(alsa->device_name);
|
||||
free(alsa);
|
||||
return error;
|
||||
}
|
||||
|
@ -3,6 +3,8 @@
|
||||
* Audio Input Redirection Virtual Channel
|
||||
*
|
||||
* Copyright 2010-2011 Vic Lee
|
||||
* Copyright 2015 Thincast Technologies GmbH
|
||||
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -32,7 +34,7 @@
|
||||
#include <freerdp/addin.h>
|
||||
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#include <winpr/win32error.h>
|
||||
#include "audin_main.h"
|
||||
|
||||
#define MSG_SNDIN_VERSION 0x01
|
||||
@ -88,9 +90,9 @@ struct _AUDIN_PLUGIN
|
||||
IAudinDevice* device;
|
||||
};
|
||||
|
||||
static int audin_process_version(IWTSVirtualChannelCallback* pChannelCallback, wStream* s)
|
||||
static WIN32ERROR audin_process_version(IWTSVirtualChannelCallback* pChannelCallback, wStream* s)
|
||||
{
|
||||
int error;
|
||||
WIN32ERROR error;
|
||||
wStream* out;
|
||||
UINT32 Version;
|
||||
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
@ -100,6 +102,13 @@ static int audin_process_version(IWTSVirtualChannelCallback* pChannelCallback, w
|
||||
DEBUG_DVC("process_version: Version=%d", Version);
|
||||
|
||||
out = Stream_New(NULL, 5);
|
||||
|
||||
if (!out)
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_New failed!");
|
||||
return ERROR_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
Stream_Write_UINT8(out, MSG_SNDIN_VERSION);
|
||||
Stream_Write_UINT32(out, Version);
|
||||
error = callback->channel->Write(callback->channel, (UINT32) Stream_GetPosition(out), Stream_Buffer(out), NULL);
|
||||
@ -108,7 +117,7 @@ static int audin_process_version(IWTSVirtualChannelCallback* pChannelCallback, w
|
||||
return error;
|
||||
}
|
||||
|
||||
static int audin_send_incoming_data_pdu(IWTSVirtualChannelCallback* pChannelCallback)
|
||||
static WIN32ERROR audin_send_incoming_data_pdu(IWTSVirtualChannelCallback* pChannelCallback)
|
||||
{
|
||||
BYTE out_data[1];
|
||||
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
@ -117,13 +126,13 @@ static int audin_send_incoming_data_pdu(IWTSVirtualChannelCallback* pChannelCall
|
||||
return callback->channel->Write(callback->channel, 1, out_data, NULL);
|
||||
}
|
||||
|
||||
static int audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback, wStream* s)
|
||||
static WIN32ERROR 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;
|
||||
int error;
|
||||
WIN32ERROR error;
|
||||
wStream* out;
|
||||
UINT32 NumFormats;
|
||||
audinFormat format;
|
||||
@ -134,14 +143,26 @@ static int audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback, w
|
||||
if ((NumFormats < 1) || (NumFormats > 1000))
|
||||
{
|
||||
WLog_ERR(TAG, "bad NumFormats %d", NumFormats);
|
||||
return 1;
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
Stream_Seek_UINT32(s); /* cbSizeFormatsPacket */
|
||||
|
||||
callback->formats = (audinFormat*) malloc(NumFormats * sizeof(audinFormat));
|
||||
ZeroMemory(callback->formats, NumFormats * sizeof(audinFormat));
|
||||
callback->formats = (audinFormat*) calloc(1, NumFormats * sizeof(audinFormat));
|
||||
if (!callback->formats)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
out = Stream_New(NULL, 9);
|
||||
|
||||
if (!out)
|
||||
{
|
||||
error = CHANNEL_RC_NO_MEMORY;
|
||||
WLog_ERR(TAG, "Stream_New failed!");
|
||||
goto out;
|
||||
}
|
||||
|
||||
Stream_Seek(out, 9);
|
||||
|
||||
/* SoundFormats (variable) */
|
||||
@ -178,9 +199,9 @@ static int audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback, w
|
||||
/* Put the format to output buffer */
|
||||
if (!Stream_EnsureRemainingCapacity(out, 18 + format.cbSize))
|
||||
{
|
||||
free(callback->formats);
|
||||
Stream_Free(out, TRUE);
|
||||
return 1;
|
||||
error = CHANNEL_RC_NO_MEMORY;
|
||||
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
@ -188,7 +209,11 @@ static int audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback, w
|
||||
}
|
||||
}
|
||||
|
||||
audin_send_incoming_data_pdu(pChannelCallback);
|
||||
if ((error = audin_send_incoming_data_pdu(pChannelCallback)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_send_incoming_data_pdu failed!");
|
||||
goto out;
|
||||
}
|
||||
|
||||
cbSizeFormatsPacket = (UINT32) Stream_GetPosition(out);
|
||||
Stream_SetPosition(out, 0);
|
||||
@ -198,18 +223,31 @@ static int audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback, w
|
||||
Stream_Write_UINT32(out, cbSizeFormatsPacket); /* cbSizeFormatsPacket (4 bytes) */
|
||||
|
||||
error = callback->channel->Write(callback->channel, cbSizeFormatsPacket, Stream_Buffer(out), NULL);
|
||||
out:
|
||||
if (error != CHANNEL_RC_OK)
|
||||
{
|
||||
free(callback->formats);
|
||||
callback->formats = NULL;
|
||||
}
|
||||
Stream_Free(out, TRUE);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int audin_send_format_change_pdu(IWTSVirtualChannelCallback* pChannelCallback, UINT32 NewFormat)
|
||||
static WIN32ERROR audin_send_format_change_pdu(IWTSVirtualChannelCallback* pChannelCallback, UINT32 NewFormat)
|
||||
{
|
||||
int error;
|
||||
WIN32ERROR error;
|
||||
wStream* out;
|
||||
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
|
||||
out = Stream_New(NULL, 5);
|
||||
|
||||
if (!out)
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_New failed!");
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
Stream_Write_UINT8(out, MSG_SNDIN_FORMATCHANGE);
|
||||
Stream_Write_UINT32(out, NewFormat);
|
||||
error = callback->channel->Write(callback->channel, 5, Stream_Buffer(out), NULL);
|
||||
@ -218,13 +256,20 @@ static int audin_send_format_change_pdu(IWTSVirtualChannelCallback* pChannelCall
|
||||
return error;
|
||||
}
|
||||
|
||||
static int audin_send_open_reply_pdu(IWTSVirtualChannelCallback* pChannelCallback, UINT32 Result)
|
||||
static WIN32ERROR audin_send_open_reply_pdu(IWTSVirtualChannelCallback* pChannelCallback, UINT32 Result)
|
||||
{
|
||||
int error;
|
||||
WIN32ERROR error;
|
||||
wStream* out;
|
||||
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
|
||||
out = Stream_New(NULL, 5);
|
||||
|
||||
if (!out)
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_New failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
Stream_Write_UINT8(out, MSG_SNDIN_OPEN_REPLY);
|
||||
Stream_Write_UINT32(out, Result);
|
||||
error = callback->channel->Write(callback->channel, 5, Stream_Buffer(out), NULL);
|
||||
@ -233,33 +278,42 @@ static int audin_send_open_reply_pdu(IWTSVirtualChannelCallback* pChannelCallbac
|
||||
return error;
|
||||
}
|
||||
|
||||
static BOOL audin_receive_wave_data(BYTE* data, int size, void* user_data)
|
||||
static WIN32ERROR audin_receive_wave_data(BYTE* data, int size, void* user_data)
|
||||
{
|
||||
int error;
|
||||
WIN32ERROR error;
|
||||
wStream* out;
|
||||
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) user_data;
|
||||
|
||||
error = audin_send_incoming_data_pdu((IWTSVirtualChannelCallback*) callback);
|
||||
|
||||
if (error != 0)
|
||||
return FALSE;
|
||||
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_ERR(TAG, "Stream_New failed!");
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
|
||||
Stream_Write_UINT8(out, MSG_SNDIN_DATA);
|
||||
Stream_Write(out, data, size);
|
||||
error = callback->channel->Write(callback->channel, (UINT32) Stream_GetPosition(out), Stream_Buffer(out), NULL);
|
||||
Stream_Free(out, TRUE);
|
||||
|
||||
return (error == 0 ? TRUE : FALSE);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int audin_process_open(IWTSVirtualChannelCallback* pChannelCallback, wStream* s)
|
||||
static WIN32ERROR audin_process_open(IWTSVirtualChannelCallback* pChannelCallback, wStream* s)
|
||||
{
|
||||
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) callback->plugin;
|
||||
audinFormat* format;
|
||||
UINT32 initialFormat;
|
||||
UINT32 FramesPerPacket;
|
||||
WIN32ERROR error = CHANNEL_RC_OK;
|
||||
|
||||
Stream_Read_UINT32(s, FramesPerPacket);
|
||||
Stream_Read_UINT32(s, initialFormat);
|
||||
@ -271,28 +325,45 @@ static int audin_process_open(IWTSVirtualChannelCallback* pChannelCallback, wStr
|
||||
{
|
||||
WLog_ERR(TAG, "invalid format index %d (total %d)",
|
||||
initialFormat, callback->formats_count);
|
||||
return 1;
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
format = &callback->formats[initialFormat];
|
||||
if (audin->device)
|
||||
{
|
||||
IFCALL(audin->device->SetFormat, audin->device, format, FramesPerPacket);
|
||||
IFCALL(audin->device->Open, audin->device, audin_receive_wave_data, callback);
|
||||
IFCALLRET(audin->device->SetFormat, error, audin->device, format, FramesPerPacket);
|
||||
if (error != CHANNEL_RC_OK)
|
||||
{
|
||||
WLog_ERR(TAG, "SetFormat failed with errorcode %lu", error);
|
||||
return error;
|
||||
}
|
||||
IFCALLRET(audin->device->Open, error, audin->device, audin_receive_wave_data, callback);
|
||||
if (error != CHANNEL_RC_OK)
|
||||
{
|
||||
WLog_ERR(TAG, "Open failed with errorcode %lu", error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
audin_send_format_change_pdu(pChannelCallback, initialFormat);
|
||||
audin_send_open_reply_pdu(pChannelCallback, 0);
|
||||
|
||||
return 0;
|
||||
if ((error = audin_send_format_change_pdu(pChannelCallback, initialFormat)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_send_format_change_pdu failed!");
|
||||
return error;
|
||||
}
|
||||
|
||||
static int audin_process_format_change(IWTSVirtualChannelCallback* pChannelCallback, wStream* s)
|
||||
if ((error = audin_send_open_reply_pdu(pChannelCallback, 0)))
|
||||
WLog_ERR(TAG, "audin_send_open_reply_pdu failed!");
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static WIN32ERROR 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;
|
||||
WIN32ERROR error = CHANNEL_RC_OK;
|
||||
|
||||
Stream_Read_UINT32(s, NewFormat);
|
||||
|
||||
@ -302,26 +373,42 @@ static int audin_process_format_change(IWTSVirtualChannelCallback* pChannelCallb
|
||||
{
|
||||
WLog_ERR(TAG, "invalid format index %d (total %d)",
|
||||
NewFormat, callback->formats_count);
|
||||
return 1;
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
format = &callback->formats[NewFormat];
|
||||
|
||||
if (audin->device)
|
||||
{
|
||||
IFCALL(audin->device->Close, audin->device);
|
||||
IFCALL(audin->device->SetFormat, audin->device, format, 0);
|
||||
IFCALL(audin->device->Open, audin->device, audin_receive_wave_data, callback);
|
||||
}
|
||||
|
||||
audin_send_format_change_pdu(pChannelCallback, NewFormat);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *data)
|
||||
IFCALLRET(audin->device->Close, error, audin->device);
|
||||
if (error != CHANNEL_RC_OK)
|
||||
{
|
||||
int error;
|
||||
WLog_ERR(TAG, "Close failed with errorcode %lu", error);
|
||||
return error;
|
||||
}
|
||||
IFCALLRET(audin->device->SetFormat, error, audin->device, format, 0);
|
||||
if (error != CHANNEL_RC_OK)
|
||||
{
|
||||
WLog_ERR(TAG, "SetFormat failed with errorcode %lu", error);
|
||||
return error;
|
||||
}
|
||||
IFCALLRET(audin->device->Open, error, audin->device, audin_receive_wave_data, callback);
|
||||
if (error != CHANNEL_RC_OK)
|
||||
{
|
||||
WLog_ERR(TAG, "Open failed with errorcode %lu", error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
if ((error = audin_send_format_change_pdu(pChannelCallback, NewFormat)))
|
||||
WLog_ERR(TAG, "audin_send_format_change_pdu failed!");
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static WIN32ERROR audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *data)
|
||||
{
|
||||
WIN32ERROR error;
|
||||
BYTE MessageId;
|
||||
|
||||
Stream_Read_UINT8(data, MessageId);
|
||||
@ -348,30 +435,38 @@ static int audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
|
||||
|
||||
default:
|
||||
WLog_ERR(TAG, "unknown MessageId=0x%x", MessageId);
|
||||
error = 1;
|
||||
error = ERROR_INVALID_DATA;
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int audin_on_close(IWTSVirtualChannelCallback* pChannelCallback)
|
||||
static WIN32ERROR audin_on_close(IWTSVirtualChannelCallback* pChannelCallback)
|
||||
{
|
||||
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) callback->plugin;
|
||||
WIN32ERROR error = CHANNEL_RC_OK;
|
||||
|
||||
DEBUG_DVC("on_close");
|
||||
|
||||
if (audin->device)
|
||||
IFCALL(audin->device->Close, audin->device);
|
||||
{
|
||||
IFCALLRET(audin->device->Close, error, audin->device);
|
||||
if (error != CHANNEL_RC_OK)
|
||||
{
|
||||
WLog_ERR(TAG, "Close failed with errorcode %lu", error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
free(callback->formats);
|
||||
free(callback);
|
||||
|
||||
return 0;
|
||||
return error;
|
||||
}
|
||||
|
||||
static int audin_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
|
||||
static WIN32ERROR audin_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
|
||||
IWTSVirtualChannel* pChannel, BYTE* Data, int* pbAccept,
|
||||
IWTSVirtualChannelCallback** ppCallback)
|
||||
{
|
||||
@ -380,8 +475,12 @@ static int audin_on_new_channel_connection(IWTSListenerCallback* pListenerCallba
|
||||
|
||||
DEBUG_DVC("on_new_channel_connection");
|
||||
|
||||
callback = (AUDIN_CHANNEL_CALLBACK*) malloc(sizeof(AUDIN_CHANNEL_CALLBACK));
|
||||
ZeroMemory(callback, sizeof(AUDIN_CHANNEL_CALLBACK));
|
||||
callback = (AUDIN_CHANNEL_CALLBACK*) calloc(1, sizeof(AUDIN_CHANNEL_CALLBACK));
|
||||
if (!callback)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
callback->iface.OnDataReceived = audin_on_data_received;
|
||||
callback->iface.OnClose = audin_on_close;
|
||||
@ -391,17 +490,21 @@ static int audin_on_new_channel_connection(IWTSListenerCallback* pListenerCallba
|
||||
|
||||
*ppCallback = (IWTSVirtualChannelCallback*) callback;
|
||||
|
||||
return 0;
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static int audin_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
|
||||
static WIN32ERROR audin_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
|
||||
{
|
||||
AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin;
|
||||
|
||||
DEBUG_DVC("plugin_initialize");
|
||||
|
||||
audin->listener_callback = (AUDIN_LISTENER_CALLBACK*) malloc(sizeof(AUDIN_LISTENER_CALLBACK));
|
||||
ZeroMemory(audin->listener_callback, sizeof(AUDIN_LISTENER_CALLBACK));
|
||||
audin->listener_callback = (AUDIN_LISTENER_CALLBACK*) calloc(1, sizeof(AUDIN_LISTENER_CALLBACK));
|
||||
if (!audin->listener_callback)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
audin->listener_callback->iface.OnNewChannelConnection = audin_on_new_channel_connection;
|
||||
audin->listener_callback->plugin = pPlugin;
|
||||
@ -411,15 +514,21 @@ static int audin_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManage
|
||||
(IWTSListenerCallback*) audin->listener_callback, NULL);
|
||||
}
|
||||
|
||||
static int audin_plugin_terminated(IWTSPlugin* pPlugin)
|
||||
static WIN32ERROR audin_plugin_terminated(IWTSPlugin* pPlugin)
|
||||
{
|
||||
AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin;
|
||||
WIN32ERROR error = CHANNEL_RC_OK;
|
||||
|
||||
DEBUG_DVC("plugin_terminated");
|
||||
|
||||
if (audin->device)
|
||||
{
|
||||
IFCALL(audin->device->Free, audin->device);
|
||||
IFCALLRET(audin->device->Free, error, audin->device);
|
||||
if (error != CHANNEL_RC_OK)
|
||||
{
|
||||
WLog_ERR(TAG, "Free failed with errorcode %lu", error);
|
||||
// dont stop on error
|
||||
}
|
||||
audin->device = NULL;
|
||||
}
|
||||
|
||||
@ -432,57 +541,74 @@ static int audin_plugin_terminated(IWTSPlugin* pPlugin)
|
||||
free(audin->listener_callback);
|
||||
free(audin);
|
||||
|
||||
return 0;
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static void audin_register_device_plugin(IWTSPlugin* pPlugin, IAudinDevice* device)
|
||||
static WIN32ERROR audin_register_device_plugin(IWTSPlugin* pPlugin, IAudinDevice* device)
|
||||
{
|
||||
AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin;
|
||||
|
||||
if (audin->device)
|
||||
{
|
||||
WLog_ERR(TAG, "existing device, abort.");
|
||||
return;
|
||||
return ERROR_ALREADY_EXISTS;
|
||||
}
|
||||
|
||||
DEBUG_DVC("register_device_plugin: device registered.");
|
||||
|
||||
audin->device = device;
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static BOOL audin_load_device_plugin(IWTSPlugin* pPlugin, const char* name, ADDIN_ARGV* args)
|
||||
static WIN32ERROR audin_load_device_plugin(IWTSPlugin* pPlugin, const char* name, ADDIN_ARGV* args)
|
||||
{
|
||||
PFREERDP_AUDIN_DEVICE_ENTRY entry;
|
||||
FREERDP_AUDIN_DEVICE_ENTRY_POINTS entryPoints;
|
||||
WIN32ERROR error;
|
||||
|
||||
entry = (PFREERDP_AUDIN_DEVICE_ENTRY) freerdp_load_channel_addin_entry("audin", (LPSTR) name, NULL, 0);
|
||||
|
||||
if (entry == NULL)
|
||||
return FALSE;
|
||||
{
|
||||
WLog_ERR(TAG, "freerdp_load_channel_addin_entry did not return any function pointers for %s ", name);
|
||||
return ERROR_INVALID_FUNCTION;
|
||||
}
|
||||
|
||||
entryPoints.plugin = pPlugin;
|
||||
entryPoints.pRegisterAudinDevice = audin_register_device_plugin;
|
||||
entryPoints.args = args;
|
||||
|
||||
if (entry(&entryPoints) != 0)
|
||||
if ((error = entry(&entryPoints)))
|
||||
{
|
||||
WLog_ERR(TAG, "%s entry returns error.", name);
|
||||
return FALSE;
|
||||
WLog_ERR(TAG, "%s entry returned error %lu.", name, error);
|
||||
return error;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
void audin_set_subsystem(AUDIN_PLUGIN* audin, char* subsystem)
|
||||
WIN32ERROR audin_set_subsystem(AUDIN_PLUGIN* audin, char* subsystem)
|
||||
{
|
||||
free(audin->subsystem);
|
||||
audin->subsystem = _strdup(subsystem);
|
||||
if (!audin->subsystem)
|
||||
{
|
||||
WLog_ERR(TAG, "_strdup failed!");
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
void audin_set_device_name(AUDIN_PLUGIN* audin, char* device_name)
|
||||
WIN32ERROR audin_set_device_name(AUDIN_PLUGIN* audin, char* device_name)
|
||||
{
|
||||
free(audin->device_name);
|
||||
audin->device_name = _strdup(device_name);
|
||||
if (!audin->device_name)
|
||||
{
|
||||
WLog_ERR(TAG, "_strdup failed!");
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
}
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
COMMAND_LINE_ARGUMENT_A audin_args[] =
|
||||
@ -501,6 +627,7 @@ static BOOL audin_process_addin_args(IWTSPlugin* pPlugin, ADDIN_ARGV* args)
|
||||
DWORD flags;
|
||||
COMMAND_LINE_ARGUMENT_A* arg;
|
||||
AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin;
|
||||
WIN32ERROR error;
|
||||
|
||||
flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON;
|
||||
|
||||
@ -518,11 +645,19 @@ static BOOL audin_process_addin_args(IWTSPlugin* pPlugin, ADDIN_ARGV* args)
|
||||
|
||||
CommandLineSwitchCase(arg, "sys")
|
||||
{
|
||||
audin_set_subsystem(audin, arg->Value);
|
||||
if ((error = audin_set_subsystem(audin, arg->Value)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_set_subsystem failed with error %lu!", error);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
CommandLineSwitchCase(arg, "dev")
|
||||
{
|
||||
audin_set_device_name(audin, arg->Value);
|
||||
if ((error = audin_set_device_name(audin, arg->Value)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_set_device_name failed with error %lu!", error);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
CommandLineSwitchCase(arg, "format")
|
||||
{
|
||||
@ -552,9 +687,9 @@ static BOOL audin_process_addin_args(IWTSPlugin* pPlugin, ADDIN_ARGV* args)
|
||||
#define DVCPluginEntry audin_DVCPluginEntry
|
||||
#endif
|
||||
|
||||
int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||
WIN32ERROR DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||
{
|
||||
int error = 0;
|
||||
WIN32ERROR error = CHANNEL_RC_OK;
|
||||
ADDIN_ARGV* args;
|
||||
AUDIN_PLUGIN* audin;
|
||||
|
||||
@ -564,8 +699,12 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||
audin = (AUDIN_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "audin");
|
||||
if (audin == NULL)
|
||||
{
|
||||
audin = (AUDIN_PLUGIN*) malloc(sizeof(AUDIN_PLUGIN));
|
||||
ZeroMemory(audin, sizeof(AUDIN_PLUGIN));
|
||||
audin = (AUDIN_PLUGIN*) calloc(1, sizeof(AUDIN_PLUGIN));
|
||||
if (!audin)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
audin->iface.Initialize = audin_plugin_initialize;
|
||||
audin->iface.Connected = NULL;
|
||||
@ -577,54 +716,121 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||
|
||||
args = pEntryPoints->GetPluginData(pEntryPoints);
|
||||
|
||||
if (error == 0)
|
||||
if (error == CHANNEL_RC_OK)
|
||||
audin_process_addin_args((IWTSPlugin*) audin, args);
|
||||
else
|
||||
{
|
||||
WLog_ERR(TAG, "RegisterPlugin failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
if (audin->subsystem)
|
||||
audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args);
|
||||
if (audin->subsystem && (error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args))) {
|
||||
WLog_ERR(TAG, "audin_load_device_plugin failed!");
|
||||
return error;
|
||||
}
|
||||
|
||||
#if defined(WITH_PULSE)
|
||||
if (!audin->device)
|
||||
{
|
||||
audin_set_subsystem(audin, "pulse");
|
||||
audin_set_device_name(audin, "");
|
||||
audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args);
|
||||
if ((error = audin_set_subsystem(audin, "pulse")))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_set_subsystem for pulse failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
if ((error = audin_set_device_name(audin, "")))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_set_device_name for pulse failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
if ((error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_load_device_plugin for pulse failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WITH_OSS)
|
||||
if (!audin->device)
|
||||
{
|
||||
audin_set_subsystem(audin, "oss");
|
||||
audin_set_device_name(audin, "default");
|
||||
audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args);
|
||||
if ((error = audin_set_subsystem(audin, "oss")))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_set_subsystem for oss failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
if ((error = audin_set_device_name(audin, "default")))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_set_device_name for oss failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
if ((error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_load_device_plugin oss pulse failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WITH_ALSA)
|
||||
if (!audin->device)
|
||||
{
|
||||
audin_set_subsystem(audin, "alsa");
|
||||
audin_set_device_name(audin, "default");
|
||||
audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args);
|
||||
if ((error = audin_set_subsystem(audin, "alsa")))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_set_subsystem for alsa failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
if ((error = audin_set_device_name(audin, "default")))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_set_device_name for alsa failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
if ((error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_load_device_plugin oss alsa failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WITH_OPENSLES)
|
||||
if (!audin->device)
|
||||
{
|
||||
audin_set_subsystem(audin, "opensles");
|
||||
audin_set_device_name(audin, "default");
|
||||
audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args);
|
||||
if ((error = audin_set_subsystem(audin, "opensles")))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_set_subsystem for opensles failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
if ((error = audin_set_device_name(audin, "default")))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_set_device_name for opensles failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
if ((error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_load_device_plugin oss opensles failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WITH_WINMM)
|
||||
if (!audin->device)
|
||||
{
|
||||
audin_set_subsystem(audin, "winmm");
|
||||
audin_set_device_name(audin, "default");
|
||||
audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args);
|
||||
if ((error = audin_set_subsystem(audin, "winmm")))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_set_subsystem for winmm failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
if ((error = audin_set_device_name(audin, "default")))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_set_device_name for winmm failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
if ((error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_load_device_plugin oss winmm failed with error %lu!", error);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -3,6 +3,8 @@
|
||||
* Audio Input Redirection Virtual Channel - OpenSL ES implementation
|
||||
*
|
||||
* Copyright 2013 Armin Novak <armin.novak@gmail.com>
|
||||
* Copyright 2015 Thincast Technologies GmbH
|
||||
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -30,6 +32,7 @@
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
#include <winpr/cmdline.h>
|
||||
#include <winpr/win32error.h>
|
||||
|
||||
#include <freerdp/addin.h>
|
||||
#include <freerdp/codec/dsp.h>
|
||||
@ -75,6 +78,7 @@ static void* audin_opensles_thread_func(void* arg)
|
||||
} buffer;
|
||||
AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) arg;
|
||||
const size_t raw_size = opensles->frames_per_packet * opensles->bytes_per_channel;
|
||||
int rc = CHANNEL_RC_OK;
|
||||
|
||||
DEBUG_DVC("opensles=%p", opensles);
|
||||
|
||||
@ -84,19 +88,26 @@ static void* audin_opensles_thread_func(void* arg)
|
||||
assert(opensles->stopEvent);
|
||||
assert(opensles->stream);
|
||||
|
||||
buffer.v = malloc(raw_size);
|
||||
ZeroMemory(buffer.v, raw_size);
|
||||
buffer.v = calloc(1, raw_size);
|
||||
if (!buffer.v)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
//TODO: signal error to freerdp
|
||||
ExitThread((DWORD)CHANNEL_RC_NO_MEMORY);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
freerdp_dsp_context_reset_adpcm(opensles->dsp_context);
|
||||
|
||||
while (!(WaitForSingleObject(opensles->stopEvent, 0) == WAIT_OBJECT_0))
|
||||
while (WAIT_OBJECT_0 != WaitForSingleObject(opensles->stopEvent, 0))
|
||||
{
|
||||
size_t encoded_size;
|
||||
void *encoded_data;
|
||||
|
||||
int rc = android_RecIn(opensles->stream, buffer.s, raw_size);
|
||||
rc = android_RecIn(opensles->stream, buffer.s, raw_size);
|
||||
if (rc < 0)
|
||||
{
|
||||
WLog_ERR(TAG, "android_RecIn %d", rc);
|
||||
WLog_ERR(TAG, "android_RecIn %lu", rc);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -125,7 +136,7 @@ static void* audin_opensles_thread_func(void* arg)
|
||||
}
|
||||
|
||||
rc = opensles->receive(encoded_data, encoded_size, opensles->user_data);
|
||||
if (!rc)
|
||||
if (rc)
|
||||
break;
|
||||
}
|
||||
|
||||
@ -133,11 +144,11 @@ static void* audin_opensles_thread_func(void* arg)
|
||||
|
||||
DEBUG_DVC("thread shutdown.");
|
||||
|
||||
ExitThread(0);
|
||||
ExitThread((DWORD)rc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void audin_opensles_free(IAudinDevice* device)
|
||||
static WIN32ERROR audin_opensles_free(IAudinDevice* device)
|
||||
{
|
||||
AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device;
|
||||
|
||||
@ -146,7 +157,7 @@ static void audin_opensles_free(IAudinDevice* device)
|
||||
/* The function may have been called out of order,
|
||||
* ignore duplicate requests. */
|
||||
if (!opensles)
|
||||
return;
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
assert(opensles);
|
||||
assert(opensles->dsp_context);
|
||||
@ -157,6 +168,8 @@ static void audin_opensles_free(IAudinDevice* device)
|
||||
free(opensles->device_name);
|
||||
|
||||
free(opensles);
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static BOOL audin_opensles_format_supported(IAudinDevice* device, audinFormat* format)
|
||||
@ -201,7 +214,7 @@ static BOOL audin_opensles_format_supported(IAudinDevice* device, audinFormat* f
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void audin_opensles_set_format(IAudinDevice* device,
|
||||
static WIN32ERROR audin_opensles_set_format(IAudinDevice* device,
|
||||
audinFormat* format, UINT32 FramesPerPacket)
|
||||
{
|
||||
int bs;
|
||||
@ -215,7 +228,7 @@ static void audin_opensles_set_format(IAudinDevice* device,
|
||||
/* The function may have been called out of order, ignore
|
||||
* requests before the device is available. */
|
||||
if (!opensles)
|
||||
return;
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
switch (format->wFormatTag)
|
||||
{
|
||||
@ -252,7 +265,7 @@ static void audin_opensles_set_format(IAudinDevice* device,
|
||||
WLog_ERR(TAG, "Encoding '%d' [%08X] not supported",
|
||||
(format->wFormatTag),
|
||||
format->wFormatTag);
|
||||
return;
|
||||
return ERROR_UNSUPPORTED_TYPE;
|
||||
}
|
||||
|
||||
opensles->rate = format->nSamplesPerSec;
|
||||
@ -263,9 +276,10 @@ static void audin_opensles_set_format(IAudinDevice* device,
|
||||
|
||||
DEBUG_DVC("aligned frames_per_packet=%d, block_size=%d",
|
||||
opensles->frames_per_packet, opensles->block_size);
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static void audin_opensles_open(IAudinDevice* device, AudinReceive receive,
|
||||
static WIN32ERROR audin_opensles_open(IAudinDevice* device, AudinReceive receive,
|
||||
void* user_data)
|
||||
{
|
||||
AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device;
|
||||
@ -277,26 +291,45 @@ static void audin_opensles_open(IAudinDevice* device, AudinReceive receive,
|
||||
/* The function may have been called out of order,
|
||||
* ignore duplicate open requests. */
|
||||
if(opensles->stream)
|
||||
return;
|
||||
return CHANNEL_RC_OK;
|
||||
|
||||
opensles->stream = android_OpenRecDevice(
|
||||
if(!(opensles->stream = android_OpenRecDevice(
|
||||
opensles->device_name,
|
||||
opensles->rate,
|
||||
opensles->channels,
|
||||
opensles->frames_per_packet,
|
||||
opensles->bytes_per_channel * 8);
|
||||
assert(opensles->stream);
|
||||
opensles->bytes_per_channel * 8)))
|
||||
{
|
||||
WLog_ERR(TAG, "android_OpenRecDevice failed!");
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
opensles->receive = receive;
|
||||
opensles->user_data = user_data;
|
||||
|
||||
opensles->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
opensles->thread = CreateThread(NULL, 0,
|
||||
if (!(opensles->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateEvent failed!");
|
||||
goto error_out;
|
||||
}
|
||||
// TODO: add mechanism that threads can signal failure
|
||||
if (!(opensles->thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) audin_opensles_thread_func,
|
||||
opensles, 0, NULL);
|
||||
opensles, 0, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateThread failed!");
|
||||
goto error_out;
|
||||
}
|
||||
return CHANNEL_RC_OK;
|
||||
error_out:
|
||||
android_CloseRecDevice(opensles->stream);
|
||||
opensles->stream = NULL;
|
||||
CloseHandle(opensles->stopEvent);
|
||||
opensles->stopEvent = NULL;
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
static void audin_opensles_close(IAudinDevice* device)
|
||||
static WIN32ERROR audin_opensles_close(IAudinDevice* device)
|
||||
{
|
||||
AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device;
|
||||
|
||||
@ -309,7 +342,7 @@ static void audin_opensles_close(IAudinDevice* device)
|
||||
if (!opensles->stopEvent)
|
||||
{
|
||||
WLog_ERR(TAG, "[ERROR] function called without matching open.");
|
||||
return;
|
||||
return ERROR_REQUEST_OUT_OF_SEQUENCE;
|
||||
}
|
||||
|
||||
assert(opensles->stopEvent);
|
||||
@ -328,6 +361,8 @@ static void audin_opensles_close(IAudinDevice* device)
|
||||
opensles->receive = NULL;
|
||||
opensles->user_data = NULL;
|
||||
opensles->stream = NULL;
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static COMMAND_LINE_ARGUMENT_A audin_opensles_args[] =
|
||||
@ -337,10 +372,10 @@ static COMMAND_LINE_ARGUMENT_A audin_opensles_args[] =
|
||||
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
|
||||
};
|
||||
|
||||
static int audin_opensles_parse_addin_args(AudinOpenSLESDevice* device,
|
||||
static WIN32ERROR audin_opensles_parse_addin_args(AudinOpenSLESDevice* device,
|
||||
ADDIN_ARGV* args)
|
||||
{
|
||||
int status;
|
||||
WIN32ERROR status;
|
||||
DWORD flags;
|
||||
COMMAND_LINE_ARGUMENT_A* arg;
|
||||
AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*) device;
|
||||
@ -366,13 +401,18 @@ static int audin_opensles_parse_addin_args(AudinOpenSLESDevice* device,
|
||||
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);
|
||||
|
||||
return status;
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
#ifdef STATIC_CHANNELS
|
||||
@ -380,16 +420,21 @@ static int audin_opensles_parse_addin_args(AudinOpenSLESDevice* device,
|
||||
opensles_freerdp_audin_client_subsystem_entry
|
||||
#endif
|
||||
|
||||
int freerdp_audin_client_subsystem_entry(
|
||||
WIN32ERROR freerdp_audin_client_subsystem_entry(
|
||||
PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints)
|
||||
{
|
||||
ADDIN_ARGV* args;
|
||||
AudinOpenSLESDevice* opensles;
|
||||
WIN32ERROR error;
|
||||
|
||||
DEBUG_DVC("pEntryPoints=%p", pEntryPoints);
|
||||
|
||||
opensles = (AudinOpenSLESDevice*) malloc(sizeof(AudinOpenSLESDevice));
|
||||
ZeroMemory(opensles, sizeof(AudinOpenSLESDevice));
|
||||
opensles = (AudinOpenSLESDevice*) calloc(1, sizeof(AudinOpenSLESDevice));
|
||||
if (!opensles)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
opensles->iface.Open = audin_opensles_open;
|
||||
opensles->iface.FormatSupported = audin_opensles_format_supported;
|
||||
@ -399,12 +444,29 @@ int freerdp_audin_client_subsystem_entry(
|
||||
|
||||
args = pEntryPoints->args;
|
||||
|
||||
audin_opensles_parse_addin_args(opensles, args);
|
||||
if ((error = audin_opensles_parse_addin_args(opensles, args)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_opensles_parse_addin_args failed with errorcode %d!", error);
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
opensles->dsp_context = freerdp_dsp_context_new();
|
||||
|
||||
pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin,
|
||||
(IAudinDevice*) opensles);
|
||||
|
||||
return 0;
|
||||
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 %d!", error);
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
error_out:
|
||||
freerdp_dsp_context_free(opensles->dsp_context);
|
||||
free(opensles);
|
||||
return error;
|
||||
}
|
||||
|
@ -3,6 +3,8 @@
|
||||
* Audio Input Redirection Virtual Channel - OSS implementation
|
||||
*
|
||||
* Copyright (c) 2015 Rozhuk Ivan <rozhuk.im@gmail.com>
|
||||
* Copyright 2015 Thincast Technologies GmbH
|
||||
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -29,6 +31,7 @@
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
#include <winpr/cmdline.h>
|
||||
#include <winpr/win32error.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
@ -125,11 +128,11 @@ static BOOL audin_oss_format_supported(IAudinDevice *device, audinFormat *format
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void audin_oss_set_format(IAudinDevice *device, audinFormat *format, UINT32 FramesPerPacket) {
|
||||
static WIN32ERROR audin_oss_set_format(IAudinDevice *device, audinFormat *format, UINT32 FramesPerPacket) {
|
||||
AudinOSSDevice *oss = (AudinOSSDevice*)device;
|
||||
|
||||
if (device == NULL || format == NULL)
|
||||
return;
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
oss->FramesPerPacket = FramesPerPacket;
|
||||
CopyMemory(&(oss->format), format, sizeof(audinFormat));
|
||||
@ -140,6 +143,7 @@ static void audin_oss_set_format(IAudinDevice *device, audinFormat *format, UINT
|
||||
oss->format.wBitsPerSample *= 4;
|
||||
break;
|
||||
}
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static void *audin_oss_thread_func(void *arg)
|
||||
@ -149,6 +153,7 @@ static void *audin_oss_thread_func(void *arg)
|
||||
BYTE *buffer = NULL, *encoded_data;
|
||||
int tmp, buffer_size, encoded_size;
|
||||
AudinOSSDevice *oss = (AudinOSSDevice*)arg;
|
||||
WIN32ERROR error;
|
||||
|
||||
if (arg == NULL)
|
||||
goto err_out;
|
||||
@ -184,12 +189,11 @@ static void *audin_oss_thread_func(void *arg)
|
||||
OSS_LOG_ERR("SNDCTL_DSP_SETFRAGMENT failed", errno);
|
||||
|
||||
buffer_size = (oss->FramesPerPacket * oss->format.nChannels * (oss->format.wBitsPerSample / 8));
|
||||
buffer = (BYTE*)malloc((buffer_size + sizeof(void*)));
|
||||
buffer = (BYTE*)calloc(1, (buffer_size + sizeof(void*)));
|
||||
if (NULL == buffer) {
|
||||
OSS_LOG_ERR("malloc() fail", errno);
|
||||
goto err_out;
|
||||
}
|
||||
ZeroMemory(buffer, buffer_size);
|
||||
|
||||
freerdp_dsp_context_reset_adpcm(oss->dsp_context);
|
||||
|
||||
@ -220,10 +224,14 @@ static void *audin_oss_thread_func(void *arg)
|
||||
encoded_size = buffer_size;
|
||||
break;
|
||||
}
|
||||
if (0 != oss->receive(encoded_data, encoded_size, oss->user_data))
|
||||
if ((error = oss->receive(encoded_data, encoded_size, oss->user_data)))
|
||||
{
|
||||
WLog_ERR(TAG, "oss->receive failed with error %lu", error);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
err_out:
|
||||
if (pcm_handle != -1)
|
||||
close(pcm_handle);
|
||||
@ -234,21 +242,35 @@ err_out:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void audin_oss_open(IAudinDevice *device, AudinReceive receive, void *user_data) {
|
||||
static WIN32ERROR audin_oss_open(IAudinDevice *device, AudinReceive receive, void *user_data) {
|
||||
AudinOSSDevice *oss = (AudinOSSDevice*)device;
|
||||
|
||||
oss->receive = receive;
|
||||
oss->user_data = user_data;
|
||||
|
||||
oss->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
oss->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)audin_oss_thread_func, oss, 0, NULL);
|
||||
if (!(oss->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateEvent failed!");
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
// TODO: add mechanism that threads can signal failure
|
||||
if (!(oss->thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE)audin_oss_thread_func, oss, 0, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateThread failed!");
|
||||
CloseHandle(oss->stopEvent);
|
||||
oss->stopEvent = NULL;
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
static void audin_oss_close(IAudinDevice *device) {
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static WIN32ERROR audin_oss_close(IAudinDevice *device) {
|
||||
AudinOSSDevice *oss = (AudinOSSDevice*)device;
|
||||
|
||||
if (device == NULL)
|
||||
return;
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (oss->stopEvent != NULL) {
|
||||
SetEvent(oss->stopEvent);
|
||||
@ -263,18 +285,27 @@ static void audin_oss_close(IAudinDevice *device) {
|
||||
|
||||
oss->receive = NULL;
|
||||
oss->user_data = NULL;
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static void audin_oss_free(IAudinDevice *device) {
|
||||
static WIN32ERROR audin_oss_free(IAudinDevice *device) {
|
||||
AudinOSSDevice *oss = (AudinOSSDevice*)device;
|
||||
|
||||
if (device == NULL)
|
||||
return;
|
||||
int error;
|
||||
|
||||
audin_oss_close(device);
|
||||
if (device == NULL)
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if ((error = audin_oss_close(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[] = {
|
||||
@ -282,7 +313,7 @@ COMMAND_LINE_ARGUMENT_A audin_oss_args[] = {
|
||||
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
|
||||
};
|
||||
|
||||
static void audin_oss_parse_addin_args(AudinOSSDevice *device, ADDIN_ARGV *args) {
|
||||
static WIN32ERROR audin_oss_parse_addin_args(AudinOSSDevice *device, ADDIN_ARGV *args) {
|
||||
int status;
|
||||
char *str_num, *eptr;
|
||||
DWORD flags;
|
||||
@ -293,7 +324,7 @@ static void audin_oss_parse_addin_args(AudinOSSDevice *device, ADDIN_ARGV *args)
|
||||
|
||||
status = CommandLineParseArgumentsA(args->argc, (const char**)args->argv, audin_oss_args, flags, oss, NULL, NULL);
|
||||
if (status < 0)
|
||||
return;
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
arg = audin_oss_args;
|
||||
|
||||
@ -305,6 +336,11 @@ static void audin_oss_parse_addin_args(AudinOSSDevice *device, ADDIN_ARGV *args)
|
||||
|
||||
CommandLineSwitchCase(arg, "dev") {
|
||||
str_num = _strdup(arg->Value);
|
||||
if (!str_num)
|
||||
{
|
||||
WLog_ERR(TAG, "_strdup failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
oss->dev_unit = strtol(str_num, &eptr, 10);
|
||||
if (oss->dev_unit < 0 || *eptr != '\0')
|
||||
oss->dev_unit = -1;
|
||||
@ -313,18 +349,25 @@ static void audin_oss_parse_addin_args(AudinOSSDevice *device, ADDIN_ARGV *args)
|
||||
|
||||
CommandLineSwitchEnd(arg)
|
||||
} while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
#ifdef STATIC_CHANNELS
|
||||
#define freerdp_audin_client_subsystem_entry oss_freerdp_audin_client_subsystem_entry
|
||||
#endif
|
||||
|
||||
int freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints) {
|
||||
WIN32ERROR freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints) {
|
||||
ADDIN_ARGV *args;
|
||||
AudinOSSDevice *oss;
|
||||
WIN32ERROR error;
|
||||
|
||||
oss = (AudinOSSDevice*)malloc(sizeof(AudinOSSDevice));
|
||||
ZeroMemory(oss, sizeof(AudinOSSDevice));
|
||||
oss = (AudinOSSDevice*)calloc(1, sizeof(AudinOSSDevice));
|
||||
if (!oss)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
oss->iface.Open = audin_oss_open;
|
||||
oss->iface.FormatSupported = audin_oss_format_supported;
|
||||
@ -335,11 +378,31 @@ int freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEnt
|
||||
oss->dev_unit = -1;
|
||||
|
||||
args = pEntryPoints->args;
|
||||
audin_oss_parse_addin_args(oss, args);
|
||||
|
||||
if ((error = audin_oss_parse_addin_args(oss, args)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_oss_parse_addin_args failed with errorcode %lu!", error);
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
oss->dsp_context = freerdp_dsp_context_new();
|
||||
|
||||
pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*)oss);
|
||||
|
||||
return 0;
|
||||
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)))
|
||||
{
|
||||
WLog_ERR(TAG, "RegisterAudinDevice failed with error %lu!", error);
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
error_out:
|
||||
freerdp_dsp_context_free(oss->dsp_context);
|
||||
free(oss);
|
||||
return error;
|
||||
|
||||
}
|
||||
|
@ -3,6 +3,8 @@
|
||||
* Audio Input Redirection Virtual Channel - PulseAudio implementation
|
||||
*
|
||||
* Copyright 2010-2011 Vic Lee
|
||||
* Copyright 2015 Thincast Technologies GmbH
|
||||
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -27,6 +29,7 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/cmdline.h>
|
||||
#include <winpr/win32error.h>
|
||||
|
||||
#include <pulse/pulseaudio.h>
|
||||
|
||||
@ -84,19 +87,19 @@ static void audin_pulse_context_state_callback(pa_context* context, void* userda
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL audin_pulse_connect(IAudinDevice* device)
|
||||
static WIN32ERROR audin_pulse_connect(IAudinDevice* device)
|
||||
{
|
||||
pa_context_state_t state;
|
||||
AudinPulseDevice* pulse = (AudinPulseDevice*) device;
|
||||
|
||||
if (!pulse->context)
|
||||
return FALSE;
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (pa_context_connect(pulse->context, NULL, 0, NULL))
|
||||
{
|
||||
WLog_ERR(TAG, "pa_context_connect failed (%d)",
|
||||
pa_context_errno(pulse->context));
|
||||
return FALSE;
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
pa_threaded_mainloop_lock(pulse->mainloop);
|
||||
if (pa_threaded_mainloop_start(pulse->mainloop) < 0)
|
||||
@ -104,7 +107,7 @@ static BOOL audin_pulse_connect(IAudinDevice* device)
|
||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||
WLog_ERR(TAG, "pa_threaded_mainloop_start failed (%d)",
|
||||
pa_context_errno(pulse->context));
|
||||
return FALSE;
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
for (;;)
|
||||
{
|
||||
@ -115,31 +118,22 @@ static BOOL audin_pulse_connect(IAudinDevice* device)
|
||||
{
|
||||
WLog_ERR(TAG, "bad context state (%d)",
|
||||
pa_context_errno(pulse->context));
|
||||
break;
|
||||
pa_context_disconnect(pulse->context);
|
||||
return ERROR_INVALID_STATE;
|
||||
}
|
||||
pa_threaded_mainloop_wait(pulse->mainloop);
|
||||
}
|
||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||
if (state == PA_CONTEXT_READY)
|
||||
{
|
||||
DEBUG_DVC("connected");
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
pa_context_disconnect(pulse->context);
|
||||
return FALSE;
|
||||
}
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static void audin_pulse_free(IAudinDevice* device)
|
||||
static WIN32ERROR audin_pulse_free(IAudinDevice* device)
|
||||
{
|
||||
AudinPulseDevice* pulse = (AudinPulseDevice*) device;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
if (!pulse)
|
||||
return;
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
if (pulse->mainloop)
|
||||
{
|
||||
pa_threaded_mainloop_stop(pulse->mainloop);
|
||||
@ -157,6 +151,8 @@ static void audin_pulse_free(IAudinDevice* device)
|
||||
}
|
||||
freerdp_dsp_context_free(pulse->dsp_context);
|
||||
free(pulse);
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static BOOL audin_pulse_format_supported(IAudinDevice* device, audinFormat* format)
|
||||
@ -201,14 +197,14 @@ static BOOL audin_pulse_format_supported(IAudinDevice* device, audinFormat* form
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void audin_pulse_set_format(IAudinDevice* device, audinFormat* format, UINT32 FramesPerPacket)
|
||||
static WIN32ERROR audin_pulse_set_format(IAudinDevice* device, audinFormat* format, UINT32 FramesPerPacket)
|
||||
{
|
||||
int bs;
|
||||
pa_sample_spec sample_spec = { 0 };
|
||||
AudinPulseDevice* pulse = (AudinPulseDevice*) device;
|
||||
|
||||
if (!pulse->context)
|
||||
return;
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
if (FramesPerPacket > 0)
|
||||
{
|
||||
@ -252,6 +248,7 @@ static void audin_pulse_set_format(IAudinDevice* device, audinFormat* format, UI
|
||||
pulse->sample_spec = sample_spec;
|
||||
pulse->format = format->wFormatTag;
|
||||
pulse->block_size = format->nBlockAlign;
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static void audin_pulse_stream_state_callback(pa_stream* stream, void* userdata)
|
||||
@ -347,14 +344,12 @@ static void audin_pulse_stream_request_callback(pa_stream* stream, size_t length
|
||||
}
|
||||
|
||||
|
||||
static void audin_pulse_close(IAudinDevice* device)
|
||||
static WIN32ERROR audin_pulse_close(IAudinDevice* device)
|
||||
{
|
||||
AudinPulseDevice* pulse = (AudinPulseDevice*) device;
|
||||
|
||||
if (!pulse->context || !pulse->stream)
|
||||
return;
|
||||
|
||||
DEBUG_DVC("");
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
pa_threaded_mainloop_lock(pulse->mainloop);
|
||||
pa_stream_disconnect(pulse->stream);
|
||||
@ -370,20 +365,19 @@ static void audin_pulse_close(IAudinDevice* device)
|
||||
pulse->buffer = NULL;
|
||||
pulse->buffer_frames = 0;
|
||||
}
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static void audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* user_data)
|
||||
static WIN32ERROR audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* user_data)
|
||||
{
|
||||
pa_stream_state_t state;
|
||||
pa_buffer_attr buffer_attr = { 0 };
|
||||
AudinPulseDevice* pulse = (AudinPulseDevice*) device;
|
||||
|
||||
if (!pulse->context)
|
||||
return;
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
if (!pulse->sample_spec.rate || pulse->stream)
|
||||
return;
|
||||
|
||||
DEBUG_DVC("");
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
pulse->buffer = NULL;
|
||||
pulse->receive = receive;
|
||||
@ -397,7 +391,7 @@ static void audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u
|
||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||
DEBUG_DVC("pa_stream_new failed (%d)",
|
||||
pa_context_errno(pulse->context));
|
||||
return;
|
||||
return pa_context_errno(pulse->context);
|
||||
}
|
||||
pulse->bytes_per_frame = pa_frame_size(&pulse->sample_spec);
|
||||
pa_stream_set_state_callback(pulse->stream,
|
||||
@ -417,7 +411,7 @@ static void audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u
|
||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||
WLog_ERR(TAG, "pa_stream_connect_playback failed (%d)",
|
||||
pa_context_errno(pulse->context));
|
||||
return;
|
||||
return pa_context_errno(pulse->context);
|
||||
}
|
||||
|
||||
for (;;)
|
||||
@ -427,25 +421,24 @@ static void audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u
|
||||
break;
|
||||
if (!PA_STREAM_IS_GOOD(state))
|
||||
{
|
||||
audin_pulse_close(device);
|
||||
WLog_ERR(TAG, "bad stream state (%d)",
|
||||
pa_context_errno(pulse->context));
|
||||
break;
|
||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||
return pa_context_errno(pulse->context);
|
||||
}
|
||||
pa_threaded_mainloop_wait(pulse->mainloop);
|
||||
}
|
||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||
if (state == PA_STREAM_READY)
|
||||
{
|
||||
freerdp_dsp_context_reset_adpcm(pulse->dsp_context);
|
||||
pulse->buffer = malloc(pulse->bytes_per_frame * pulse->frames_per_packet);
|
||||
ZeroMemory(pulse->buffer, pulse->bytes_per_frame * pulse->frames_per_packet);
|
||||
pulse->buffer = calloc(1, pulse->bytes_per_frame * pulse->frames_per_packet);
|
||||
if (!pulse->buffer) {
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
pulse->buffer_frames = 0;
|
||||
DEBUG_DVC("connected");
|
||||
}
|
||||
else
|
||||
{
|
||||
audin_pulse_close(device);
|
||||
}
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static COMMAND_LINE_ARGUMENT_A audin_pulse_args[] =
|
||||
@ -454,7 +447,7 @@ static COMMAND_LINE_ARGUMENT_A audin_pulse_args[] =
|
||||
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
|
||||
};
|
||||
|
||||
static void audin_pulse_parse_addin_args(AudinPulseDevice* device, ADDIN_ARGV* args)
|
||||
static WIN32ERROR audin_pulse_parse_addin_args(AudinPulseDevice* device, ADDIN_ARGV* args)
|
||||
{
|
||||
int status;
|
||||
DWORD flags;
|
||||
@ -477,24 +470,36 @@ static void audin_pulse_parse_addin_args(AudinPulseDevice* device, ADDIN_ARGV* a
|
||||
CommandLineSwitchCase(arg, "dev")
|
||||
{
|
||||
pulse->device_name = _strdup(arg->Value);
|
||||
if (!pulse->device_name)
|
||||
{
|
||||
WLog_ERR(TAG, "_strdup failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
CommandLineSwitchEnd(arg)
|
||||
}
|
||||
while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
#ifdef STATIC_CHANNELS
|
||||
#define freerdp_audin_client_subsystem_entry pulse_freerdp_audin_client_subsystem_entry
|
||||
#endif
|
||||
|
||||
int freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints)
|
||||
WIN32ERROR freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints)
|
||||
{
|
||||
ADDIN_ARGV* args;
|
||||
AudinPulseDevice* pulse;
|
||||
WIN32ERROR error;
|
||||
|
||||
pulse = (AudinPulseDevice*) malloc(sizeof(AudinPulseDevice));
|
||||
ZeroMemory(pulse, sizeof(AudinPulseDevice));
|
||||
pulse = (AudinPulseDevice*) calloc(1, sizeof(AudinPulseDevice));
|
||||
if (!pulse)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
pulse->iface.Open = audin_pulse_open;
|
||||
pulse->iface.FormatSupported = audin_pulse_format_supported;
|
||||
@ -504,17 +509,27 @@ int freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEnt
|
||||
|
||||
args = pEntryPoints->args;
|
||||
|
||||
audin_pulse_parse_addin_args(pulse, args);
|
||||
if ((error = audin_pulse_parse_addin_args(pulse, args)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_pulse_parse_addin_args failed with error %lu!", error);
|
||||
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)
|
||||
{
|
||||
WLog_ERR(TAG, "pa_threaded_mainloop_new failed");
|
||||
audin_pulse_free((IAudinDevice*) pulse);
|
||||
return 1;
|
||||
error = CHANNEL_RC_NO_MEMORY;
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
pulse->context = pa_context_new(pa_threaded_mainloop_get_api(pulse->mainloop), "freerdp");
|
||||
@ -522,20 +537,27 @@ int freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEnt
|
||||
if (!pulse->context)
|
||||
{
|
||||
WLog_ERR(TAG, "pa_context_new failed");
|
||||
audin_pulse_free((IAudinDevice*) pulse);
|
||||
return 1;
|
||||
error = CHANNEL_RC_NO_MEMORY;
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
pa_context_set_state_callback(pulse->context, audin_pulse_context_state_callback, pulse);
|
||||
|
||||
if (!audin_pulse_connect((IAudinDevice*) pulse))
|
||||
if ((error = audin_pulse_connect((IAudinDevice*) pulse)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_pulse_connect failed");
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) pulse)))
|
||||
{
|
||||
WLog_ERR(TAG, "RegisterAudinDevice failed with error %lu!", error);
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
error_out:
|
||||
audin_pulse_free((IAudinDevice*)pulse);
|
||||
return 1;
|
||||
}
|
||||
|
||||
pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) pulse);
|
||||
|
||||
return 0;
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,8 @@
|
||||
* Audio Input Redirection Virtual Channel - WinMM implementation
|
||||
*
|
||||
* Copyright 2013 Zhang Zhaolong <zhangzl2013@126.com>
|
||||
* Copyright 2015 Thincast Technologies GmbH
|
||||
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -103,6 +105,8 @@ static DWORD audin_winmm_thread_func(void* arg)
|
||||
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;
|
||||
@ -136,7 +140,7 @@ static DWORD audin_winmm_thread_func(void* arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void audin_winmm_free(IAudinDevice* device)
|
||||
static WIN32ERROR audin_winmm_free(IAudinDevice* device)
|
||||
{
|
||||
UINT32 i;
|
||||
AudinWinmmDevice* winmm = (AudinWinmmDevice*) device;
|
||||
@ -149,14 +153,14 @@ static void audin_winmm_free(IAudinDevice* device)
|
||||
free(winmm->ppwfx);
|
||||
free(winmm->device_name);
|
||||
free(winmm);
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static void audin_winmm_close(IAudinDevice* device)
|
||||
static WIN32ERROR audin_winmm_close(IAudinDevice* device)
|
||||
{
|
||||
AudinWinmmDevice* winmm = (AudinWinmmDevice*) device;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
SetEvent(winmm->stopEvent);
|
||||
|
||||
WaitForSingleObject(winmm->thread, INFINITE);
|
||||
@ -168,9 +172,11 @@ static void audin_winmm_close(IAudinDevice* device)
|
||||
winmm->stopEvent = NULL;
|
||||
winmm->receive = NULL;
|
||||
winmm->user_data = NULL;
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static void audin_winmm_set_format(IAudinDevice* device, audinFormat* format, UINT32 FramesPerPacket)
|
||||
static WIN32ERROR audin_winmm_set_format(IAudinDevice* device, audinFormat* format, UINT32 FramesPerPacket)
|
||||
{
|
||||
UINT32 i;
|
||||
AudinWinmmDevice* winmm = (AudinWinmmDevice*) device;
|
||||
@ -187,6 +193,7 @@ static void audin_winmm_set_format(IAudinDevice* device, audinFormat* format, UI
|
||||
break;
|
||||
}
|
||||
}
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static BOOL audin_winmm_format_supported(IAudinDevice* device, audinFormat* format)
|
||||
@ -196,6 +203,8 @@ static BOOL audin_winmm_format_supported(IAudinDevice* device, audinFormat* form
|
||||
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;
|
||||
@ -216,32 +225,43 @@ static BOOL audin_winmm_format_supported(IAudinDevice* device, audinFormat* form
|
||||
PWAVEFORMATEX *tmp_ppwfx;
|
||||
tmp_ppwfx = realloc(winmm->ppwfx, sizeof(PWAVEFORMATEX) * winmm->ppwfx_size * 2);
|
||||
if (!tmp_ppwfx)
|
||||
return 0;
|
||||
return FALSE;
|
||||
|
||||
winmm->ppwfx_size *= 2;
|
||||
winmm->ppwfx = tmp_ppwfx;
|
||||
}
|
||||
winmm->ppwfx[winmm->cFormats++] = pwfx;
|
||||
|
||||
return 1;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
free(pwfx);
|
||||
return 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void audin_winmm_open(IAudinDevice* device, AudinReceive receive, void* user_data)
|
||||
static WIN32ERROR audin_winmm_open(IAudinDevice* device, AudinReceive receive, void* user_data)
|
||||
{
|
||||
AudinWinmmDevice* winmm = (AudinWinmmDevice*) device;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
winmm->receive = receive;
|
||||
winmm->user_data = user_data;
|
||||
|
||||
winmm->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
winmm->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) audin_winmm_thread_func, winmm, 0, NULL);
|
||||
if (!(winmm->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateEvent failed!");
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
// TODO: add mechanism that threads can signal failure
|
||||
if (!(winmm->thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) 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[] =
|
||||
@ -250,7 +270,7 @@ static COMMAND_LINE_ARGUMENT_A audin_winmm_args[] =
|
||||
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
|
||||
};
|
||||
|
||||
static void audin_winmm_parse_addin_args(AudinWinmmDevice* device, ADDIN_ARGV* args)
|
||||
static WIN32ERROR audin_winmm_parse_addin_args(AudinWinmmDevice* device, ADDIN_ARGV* args)
|
||||
{
|
||||
int status;
|
||||
DWORD flags;
|
||||
@ -273,24 +293,36 @@ static void audin_winmm_parse_addin_args(AudinWinmmDevice* device, ADDIN_ARGV* a
|
||||
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 STATIC_CHANNELS
|
||||
#define freerdp_audin_client_subsystem_entry winmm_freerdp_audin_client_subsystem_entry
|
||||
#endif
|
||||
|
||||
int freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints)
|
||||
WIN32ERROR freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints)
|
||||
{
|
||||
ADDIN_ARGV* args;
|
||||
AudinWinmmDevice* winmm;
|
||||
WIN32ERROR error;
|
||||
|
||||
winmm = (AudinWinmmDevice*) malloc(sizeof(AudinWinmmDevice));
|
||||
ZeroMemory(winmm, sizeof(AudinWinmmDevice));
|
||||
winmm = (AudinWinmmDevice*) calloc(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;
|
||||
@ -300,15 +332,42 @@ int freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEnt
|
||||
|
||||
args = pEntryPoints->args;
|
||||
|
||||
audin_winmm_parse_addin_args(winmm, args);
|
||||
if ((error = audin_winmm_parse_addin_args(winmm, args)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_winmm_parse_addin_args failed with error %d!", 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);
|
||||
|
||||
pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) winmm);
|
||||
|
||||
return 0;
|
||||
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 %d!", error);
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
error_out:
|
||||
free(winmm->ppwfx);
|
||||
free(winmm->device_name);
|
||||
free(winmm);
|
||||
return error;
|
||||
}
|
||||
|
@ -3,6 +3,8 @@
|
||||
* Server Audio Input Virtual Channel
|
||||
*
|
||||
* Copyright 2012 Vic Lee
|
||||
* Copyright 2015 Thincast Technologies GmbH
|
||||
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -29,6 +31,7 @@
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
#include <winpr/stream.h>
|
||||
#include <winpr/win32error.h>
|
||||
|
||||
#include <freerdp/codec/dsp.h>
|
||||
#include <freerdp/codec/audio.h>
|
||||
@ -62,12 +65,15 @@ typedef struct _audin_server
|
||||
|
||||
} audin_server;
|
||||
|
||||
static void audin_server_select_format(audin_server_context* context, int client_format_index)
|
||||
static WIN32ERROR audin_server_select_format(audin_server_context* context, int client_format_index)
|
||||
{
|
||||
audin_server* audin = (audin_server*) context;
|
||||
|
||||
if (client_format_index >= context->num_client_formats)
|
||||
return;
|
||||
{
|
||||
WLog_ERR(TAG, "error in protocol: client_format_index >= context->num_client_formats!");
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
context->selected_client_format = client_format_index;
|
||||
|
||||
@ -75,33 +81,45 @@ static void audin_server_select_format(audin_server_context* context, int client
|
||||
{
|
||||
/* TODO: send MSG_SNDIN_FORMATCHANGE */
|
||||
}
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static void audin_server_send_version(audin_server* audin, wStream* s)
|
||||
static WIN32ERROR audin_server_send_version(audin_server* audin, wStream* s)
|
||||
{
|
||||
ULONG written;
|
||||
|
||||
Stream_Write_UINT8(s, MSG_SNDIN_VERSION);
|
||||
Stream_Write_UINT32(s, 1); /* Version (4 bytes) */
|
||||
WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written);
|
||||
if (!WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written))
|
||||
{
|
||||
WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static BOOL audin_server_recv_version(audin_server* audin, wStream* s, UINT32 length)
|
||||
static WIN32ERROR audin_server_recv_version(audin_server* audin, wStream* s, UINT32 length)
|
||||
{
|
||||
UINT32 Version;
|
||||
|
||||
if (length < 4)
|
||||
return FALSE;
|
||||
{
|
||||
WLog_ERR(TAG, "error parsing version info: expected at least 4 bytes, got %d", length);
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
Stream_Read_UINT32(s, Version);
|
||||
|
||||
if (Version < 1)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
{
|
||||
WLog_ERR(TAG, "expected Version > 0 but got %d", Version);
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
static void audin_server_send_formats(audin_server* audin, wStream* s)
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static WIN32ERROR audin_server_send_formats(audin_server* audin, wStream* s)
|
||||
{
|
||||
int i;
|
||||
UINT32 nAvgBytesPerSec;
|
||||
@ -119,7 +137,10 @@ static void audin_server_send_formats(audin_server* audin, wStream* s)
|
||||
audin->context.server_formats[i].wBitsPerSample / 8;
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(s, 18))
|
||||
return;
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
Stream_Write_UINT16(s, audin->context.server_formats[i].wFormatTag);
|
||||
Stream_Write_UINT16(s, audin->context.server_formats[i].nChannels);
|
||||
@ -132,29 +153,39 @@ static void audin_server_send_formats(audin_server* audin, wStream* s)
|
||||
if (audin->context.server_formats[i].cbSize)
|
||||
{
|
||||
if (!Stream_EnsureRemainingCapacity(s, audin->context.server_formats[i].cbSize))
|
||||
return;
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
Stream_Write(s, audin->context.server_formats[i].data,
|
||||
audin->context.server_formats[i].cbSize);
|
||||
}
|
||||
}
|
||||
|
||||
WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written);
|
||||
return WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written) ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
static BOOL audin_server_recv_formats(audin_server* audin, wStream* s, UINT32 length)
|
||||
static WIN32ERROR audin_server_recv_formats(audin_server* audin, wStream* s, UINT32 length)
|
||||
{
|
||||
int i;
|
||||
WIN32ERROR success = CHANNEL_RC_OK;
|
||||
|
||||
if (length < 8)
|
||||
return FALSE;
|
||||
{
|
||||
WLog_ERR(TAG, "error parsing rec formats: expected at least 8 bytes, got %d", length);
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
Stream_Read_UINT32(s, audin->context.num_client_formats); /* NumFormats (4 bytes) */
|
||||
Stream_Seek_UINT32(s); /* cbSizeFormatsPacket (4 bytes) */
|
||||
length -= 8;
|
||||
|
||||
if (audin->context.num_client_formats <= 0)
|
||||
return FALSE;
|
||||
{
|
||||
WLog_ERR(TAG, "num_client_formats expected > 0 but got %d", audin->context.num_client_formats);
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
audin->context.client_formats = malloc(audin->context.num_client_formats * sizeof(AUDIO_FORMAT));
|
||||
ZeroMemory(audin->context.client_formats, audin->context.num_client_formats * sizeof(AUDIO_FORMAT));
|
||||
@ -165,7 +196,8 @@ static BOOL audin_server_recv_formats(audin_server* audin, wStream* s, UINT32 le
|
||||
{
|
||||
free(audin->context.client_formats);
|
||||
audin->context.client_formats = NULL;
|
||||
return FALSE;
|
||||
WLog_ERR(TAG, "expected length at least 18, but got %d", length);
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
Stream_Read_UINT16(s, audin->context.client_formats[i].wFormatTag);
|
||||
@ -182,17 +214,20 @@ static BOOL audin_server_recv_formats(audin_server* audin, wStream* s, UINT32 le
|
||||
}
|
||||
}
|
||||
|
||||
IFCALL(audin->context.Opening, &audin->context);
|
||||
|
||||
return TRUE;
|
||||
IFCALLRET(audin->context.Opening, success, &audin->context);
|
||||
return success;
|
||||
}
|
||||
|
||||
static void audin_server_send_open(audin_server* audin, wStream* s)
|
||||
static WIN32ERROR audin_server_send_open(audin_server* audin, wStream* s)
|
||||
{
|
||||
ULONG written;
|
||||
|
||||
if (audin->context.selected_client_format < 0)
|
||||
return;
|
||||
{
|
||||
WLog_ERR(TAG, "audin->context.selected_client_format = %d",
|
||||
audin->context.selected_client_format);
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
audin->opened = TRUE;
|
||||
|
||||
@ -213,24 +248,29 @@ static void audin_server_send_open(audin_server* audin, wStream* s)
|
||||
Stream_Write_UINT16(s, 16); /* wBitsPerSample */
|
||||
Stream_Write_UINT16(s, 0); /* cbSize */
|
||||
|
||||
WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written);
|
||||
return WTSVirtualChannelWrite(audin->audin_channel, (PCHAR) Stream_Buffer(s), Stream_GetPosition(s), &written) ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
static BOOL audin_server_recv_open_reply(audin_server* audin, wStream* s, UINT32 length)
|
||||
static WIN32ERROR audin_server_recv_open_reply(audin_server* audin, wStream* s, UINT32 length)
|
||||
{
|
||||
|
||||
UINT32 Result;
|
||||
WIN32ERROR success = CHANNEL_RC_OK;
|
||||
|
||||
if (length < 4)
|
||||
return FALSE;
|
||||
{
|
||||
WLog_ERR(TAG, "error parsing version info: expected at least 4 bytes, got %d", length);
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
Stream_Read_UINT32(s, Result);
|
||||
|
||||
IFCALL(audin->context.OpenResult, &audin->context, Result);
|
||||
IFCALLRET(audin->context.OpenResult, success, &audin->context, Result);
|
||||
|
||||
return TRUE;
|
||||
return success;
|
||||
}
|
||||
|
||||
static BOOL audin_server_recv_data(audin_server* audin, wStream* s, UINT32 length)
|
||||
static WIN32ERROR audin_server_recv_data(audin_server* audin, wStream* s, UINT32 length)
|
||||
{
|
||||
AUDIO_FORMAT* format;
|
||||
int sbytes_per_sample;
|
||||
@ -238,9 +278,14 @@ static BOOL audin_server_recv_data(audin_server* audin, wStream* s, UINT32 lengt
|
||||
BYTE* src;
|
||||
int size;
|
||||
int frames;
|
||||
WIN32ERROR success = CHANNEL_RC_OK;
|
||||
|
||||
if (audin->context.selected_client_format < 0)
|
||||
return FALSE;
|
||||
{
|
||||
WLog_ERR(TAG, "audin->context.selected_client_format = %d",
|
||||
audin->context.selected_client_format);
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
format = &audin->context.client_formats[audin->context.selected_client_format];
|
||||
|
||||
@ -283,9 +328,9 @@ static BOOL audin_server_recv_data(audin_server* audin, wStream* s, UINT32 lengt
|
||||
src = audin->dsp_context->resampled_buffer;
|
||||
}
|
||||
|
||||
IFCALL(audin->context.ReceiveSamples, &audin->context, src, frames);
|
||||
IFCALLRET(audin->context.ReceiveSamples, success, &audin->context, src, frames);
|
||||
|
||||
return TRUE;
|
||||
return success;
|
||||
}
|
||||
|
||||
static void* audin_server_thread_func(void* arg)
|
||||
@ -299,6 +344,7 @@ static void* audin_server_thread_func(void* arg)
|
||||
HANDLE ChannelEvent;
|
||||
DWORD BytesReturned = 0;
|
||||
audin_server* audin = (audin_server*) arg;
|
||||
WIN32ERROR error = CHANNEL_RC_OK;
|
||||
|
||||
buffer = NULL;
|
||||
BytesReturned = 0;
|
||||
@ -311,6 +357,12 @@ static void* audin_server_thread_func(void* arg)
|
||||
|
||||
WTSFreeMemory(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_ERR(TAG, "WTSVirtualChannelQuery failed");
|
||||
error = ERROR_INTERNAL_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
nCount = 0;
|
||||
events[nCount++] = audin->stopEvent;
|
||||
@ -321,10 +373,14 @@ static void* audin_server_thread_func(void* arg)
|
||||
while (1)
|
||||
{
|
||||
if (WaitForMultipleObjects(nCount, events, FALSE, 100) == WAIT_OBJECT_0)
|
||||
break;
|
||||
goto out;
|
||||
|
||||
if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualChannelReady, &buffer, &BytesReturned) == FALSE)
|
||||
break;
|
||||
{
|
||||
WLog_ERR(TAG, "WTSVirtualChannelQuery failed");
|
||||
error = ERROR_INTERNAL_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ready = *((BOOL*) buffer);
|
||||
|
||||
@ -336,11 +392,20 @@ static void* audin_server_thread_func(void* arg)
|
||||
|
||||
s = Stream_New(NULL, 4096);
|
||||
if (!s)
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_New failed!");
|
||||
error = CHANNEL_RC_NO_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
if (ready)
|
||||
{
|
||||
audin_server_send_version(audin, s);
|
||||
if ((error = audin_server_send_version(audin, s)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_server_send_version failed with error %lu!", error);
|
||||
goto out_capacity;
|
||||
}
|
||||
}
|
||||
|
||||
while (ready)
|
||||
@ -350,14 +415,21 @@ static void* audin_server_thread_func(void* arg)
|
||||
|
||||
Stream_SetPosition(s, 0);
|
||||
|
||||
WTSVirtualChannelRead(audin->audin_channel, 0, NULL, 0, &BytesReturned);
|
||||
if (!WTSVirtualChannelRead(audin->audin_channel, 0, NULL, 0, &BytesReturned))
|
||||
{
|
||||
WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
|
||||
error = ERROR_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
if (BytesReturned < 1)
|
||||
continue;
|
||||
if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
|
||||
goto out_capacity;
|
||||
break;
|
||||
if (WTSVirtualChannelRead(audin->audin_channel, 0, (PCHAR) Stream_Buffer(s),
|
||||
Stream_Capacity(s), &BytesReturned) == FALSE)
|
||||
{
|
||||
WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
|
||||
error = ERROR_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -367,24 +439,48 @@ static void* audin_server_thread_func(void* arg)
|
||||
switch (MessageId)
|
||||
{
|
||||
case MSG_SNDIN_VERSION:
|
||||
if (audin_server_recv_version(audin, s, BytesReturned))
|
||||
audin_server_send_formats(audin, s);
|
||||
if ((error = audin_server_recv_version(audin, s, BytesReturned)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_server_recv_version failed with error %lu!", error);
|
||||
goto out_capacity;
|
||||
}
|
||||
if ((error = audin_server_send_formats(audin, s)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_server_send_formats failed with error %lu!", error);
|
||||
goto out_capacity;
|
||||
}
|
||||
break;
|
||||
|
||||
case MSG_SNDIN_FORMATS:
|
||||
if (audin_server_recv_formats(audin, s, BytesReturned))
|
||||
audin_server_send_open(audin, s);
|
||||
if ((error = audin_server_recv_formats(audin, s, BytesReturned)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_server_recv_formats failed with error %lu!", error);
|
||||
goto out_capacity;
|
||||
}
|
||||
if ((error = audin_server_send_open(audin, s)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_server_send_open failed with error %lu!", error);
|
||||
goto out_capacity;
|
||||
}
|
||||
break;
|
||||
|
||||
case MSG_SNDIN_OPEN_REPLY:
|
||||
audin_server_recv_open_reply(audin, s, BytesReturned);
|
||||
if ((error = audin_server_recv_open_reply(audin, s, BytesReturned)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_server_recv_open_reply failed with error %lu!", error);
|
||||
goto out_capacity;
|
||||
}
|
||||
break;
|
||||
|
||||
case MSG_SNDIN_DATA_INCOMING:
|
||||
break;
|
||||
|
||||
case MSG_SNDIN_DATA:
|
||||
audin_server_recv_data(audin, s, BytesReturned);
|
||||
if ((error = audin_server_recv_data(audin, s, BytesReturned)))
|
||||
{
|
||||
WLog_ERR(TAG, "audin_server_recv_data failed with error %lu!", error);
|
||||
goto out_capacity;
|
||||
};
|
||||
break;
|
||||
|
||||
case MSG_SNDIN_FORMATCHANGE:
|
||||
@ -401,7 +497,7 @@ out_capacity:
|
||||
out:
|
||||
WTSVirtualChannelClose(audin->audin_channel);
|
||||
audin->audin_channel = NULL;
|
||||
|
||||
ExitThread((DWORD)error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -427,16 +523,30 @@ static BOOL audin_server_open(audin_server_context* context)
|
||||
"AUDIO_INPUT", WTS_CHANNEL_OPTION_DYNAMIC);
|
||||
|
||||
if (!audin->audin_channel)
|
||||
{
|
||||
WLog_ERR(TAG, "WTSVirtualChannelOpenEx failed!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
audin->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
if (!(audin->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateEvent failed!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
audin->thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) audin_server_thread_func, (void*) audin, 0, NULL);
|
||||
// TODO: implement signaling an error
|
||||
if (!(audin->thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) audin_server_thread_func, (void*) audin, 0, NULL)))
|
||||
{
|
||||
WLog_ERR(TAG, "CreateThread failed!");
|
||||
CloseHandle(audin->stopEvent);
|
||||
audin->stopEvent = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
WLog_ERR(TAG, "thread already running!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -470,6 +580,11 @@ audin_server_context* audin_server_context_new(HANDLE vcm)
|
||||
audin_server* audin;
|
||||
|
||||
audin = (audin_server *)calloc(1, sizeof(audin_server));
|
||||
if (!audin)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
audin->context.vcm = vcm;
|
||||
audin->context.selected_client_format = -1;
|
||||
@ -480,6 +595,13 @@ audin_server_context* audin_server_context_new(HANDLE vcm)
|
||||
|
||||
audin->dsp_context = freerdp_dsp_context_new();
|
||||
|
||||
if (!audin->dsp_context)
|
||||
{
|
||||
WLog_ERR(TAG, "freerdp_dsp_context_new failed!");
|
||||
free(audin);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (audin_server_context*) audin;
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,8 @@
|
||||
* Audio Input Redirection Virtual Channel
|
||||
*
|
||||
* Copyright 2010-2011 Vic Lee
|
||||
* Copyright 2015 Thincast Technologies GmbH
|
||||
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -26,7 +28,7 @@
|
||||
* Subsystem Interface
|
||||
*/
|
||||
|
||||
typedef BOOL (*AudinReceive) (BYTE* data, int size, void* userData);
|
||||
typedef WIN32ERROR (*AudinReceive) (BYTE* data, int size, void* userData);
|
||||
|
||||
typedef struct audin_format audinFormat;
|
||||
struct audin_format
|
||||
@ -43,16 +45,16 @@ struct audin_format
|
||||
typedef struct _IAudinDevice IAudinDevice;
|
||||
struct _IAudinDevice
|
||||
{
|
||||
void (*Open) (IAudinDevice* devplugin, AudinReceive receive, void* userData);
|
||||
WIN32ERROR (*Open) (IAudinDevice* devplugin, AudinReceive receive, void* userData);
|
||||
BOOL (*FormatSupported) (IAudinDevice* devplugin, audinFormat* format);
|
||||
void (*SetFormat) (IAudinDevice* devplugin, audinFormat* format, UINT32 FramesPerPacket);
|
||||
void (*Close) (IAudinDevice* devplugin);
|
||||
void (*Free) (IAudinDevice* devplugin);
|
||||
WIN32ERROR (*SetFormat) (IAudinDevice* devplugin, audinFormat* format, UINT32 FramesPerPacket);
|
||||
WIN32ERROR (*Close) (IAudinDevice* devplugin);
|
||||
WIN32ERROR (*Free) (IAudinDevice* devplugin);
|
||||
};
|
||||
|
||||
#define AUDIN_DEVICE_EXPORT_FUNC_NAME "freerdp_audin_client_subsystem_entry"
|
||||
|
||||
typedef void (*PREGISTERAUDINDEVICE)(IWTSPlugin* plugin, IAudinDevice* device);
|
||||
typedef WIN32ERROR (*PREGISTERAUDINDEVICE)(IWTSPlugin* plugin, IAudinDevice* device);
|
||||
|
||||
struct _FREERDP_AUDIN_DEVICE_ENTRY_POINTS
|
||||
{
|
||||
@ -63,7 +65,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 int (*PFREERDP_AUDIN_DEVICE_ENTRY)(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints);
|
||||
typedef WIN32ERROR (*PFREERDP_AUDIN_DEVICE_ENTRY)(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints);
|
||||
|
||||
#endif /* FREERDP_CHANNEL_CLIENT_AUDIN_H */
|
||||
|
||||
|
@ -3,6 +3,8 @@
|
||||
* Server Audio Input Virtual Channel
|
||||
*
|
||||
* Copyright 2012 Vic Lee
|
||||
* Copyright 2015 Thincast Technologies GmbH
|
||||
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -23,16 +25,17 @@
|
||||
#include <freerdp/codec/audio.h>
|
||||
#include <freerdp/channels/wtsvc.h>
|
||||
#include <freerdp/channels/rdpsnd.h>
|
||||
#include <winpr/win32error.h>
|
||||
|
||||
typedef struct _audin_server_context audin_server_context;
|
||||
|
||||
typedef void (*psAudinServerSelectFormat)(audin_server_context* context, int client_format_index);
|
||||
typedef WIN32ERROR (*psAudinServerSelectFormat)(audin_server_context* context, int client_format_index);
|
||||
typedef BOOL (*psAudinServerOpen)(audin_server_context* context);
|
||||
typedef BOOL (*psAudinServerClose)(audin_server_context* context);
|
||||
|
||||
typedef void (*psAudinServerOpening)(audin_server_context* context);
|
||||
typedef void (*psAudinServerOpenResult)(audin_server_context* context, UINT32 result);
|
||||
typedef void (*psAudinServerReceiveSamples)(audin_server_context* context, const void* buf, int nframes);
|
||||
typedef WIN32ERROR (*psAudinServerOpening)(audin_server_context* context);
|
||||
typedef WIN32ERROR (*psAudinServerOpenResult)(audin_server_context* context, UINT32 result);
|
||||
typedef WIN32ERROR (*psAudinServerReceiveSamples)(audin_server_context* context, const void* buf, int nframes);
|
||||
|
||||
struct _audin_server_context
|
||||
{
|
||||
|
@ -3,6 +3,8 @@
|
||||
* FreeRDP Sample Server (Audio Input)
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2015 Thincast Technologies GmbH
|
||||
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -28,6 +30,7 @@
|
||||
#include "sf_audin.h"
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#include <winpr/win32error.h>
|
||||
#define TAG SERVER_TAG("sample")
|
||||
|
||||
static const AUDIO_FORMAT test_audio_formats[] =
|
||||
@ -36,21 +39,24 @@ static const AUDIO_FORMAT test_audio_formats[] =
|
||||
{ WAVE_FORMAT_ALAW, 2, 22050, 44100, 2, 8, 0, NULL }
|
||||
};
|
||||
|
||||
static void sf_peer_audin_opening(audin_server_context* context)
|
||||
static WIN32ERROR sf_peer_audin_opening(audin_server_context* context)
|
||||
{
|
||||
WLog_DBG(TAG, "AUDIN opening.");
|
||||
/* Simply choose the first format supported by the client. */
|
||||
context->SelectFormat(context, 0);
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static void sf_peer_audin_open_result(audin_server_context* context, UINT32 result)
|
||||
static WIN32ERROR sf_peer_audin_open_result(audin_server_context* context, UINT32 result)
|
||||
{
|
||||
WLog_DBG(TAG, "AUDIN open result %d.", result);
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static void sf_peer_audin_receive_samples(audin_server_context* context, const void* buf, int nframes)
|
||||
static WIN32ERROR sf_peer_audin_receive_samples(audin_server_context* context, const void* buf, int nframes)
|
||||
{
|
||||
WLog_DBG(TAG, "AUDIN receive %d frames.", nframes);
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
void sf_peer_audin_init(testPeerContext* context)
|
||||
|
Loading…
Reference in New Issue
Block a user