[channel,audin] move common code to server channel
* manage channel related callbacks with default implementations * use dynamic logger for server audin channel
This commit is contained in:
parent
c5278c874f
commit
105f0d2366
@ -29,10 +29,11 @@
|
|||||||
#include <winpr/stream.h>
|
#include <winpr/stream.h>
|
||||||
|
|
||||||
#include <freerdp/freerdp.h>
|
#include <freerdp/freerdp.h>
|
||||||
|
#include <freerdp/server/server-common.h>
|
||||||
#include <freerdp/server/audin.h>
|
#include <freerdp/server/audin.h>
|
||||||
#include <freerdp/channels/log.h>
|
#include <freerdp/channels/log.h>
|
||||||
|
|
||||||
#define TAG CHANNELS_TAG("audin.server")
|
#define AUDIN_TAG CHANNELS_TAG("audin.server")
|
||||||
|
|
||||||
#define SNDIN_HEADER_SIZE 1
|
#define SNDIN_HEADER_SIZE 1
|
||||||
|
|
||||||
@ -57,11 +58,18 @@ typedef struct
|
|||||||
void* audin_channel;
|
void* audin_channel;
|
||||||
|
|
||||||
DWORD SessionId;
|
DWORD SessionId;
|
||||||
|
|
||||||
|
AUDIO_FORMAT* audin_server_formats;
|
||||||
|
size_t audin_n_server_formats;
|
||||||
|
AUDIO_FORMAT* audin_negotiated_format;
|
||||||
|
UINT32 audin_client_format_idx;
|
||||||
|
wLog* log;
|
||||||
} audin_server;
|
} audin_server;
|
||||||
|
|
||||||
static UINT audin_server_recv_version(audin_server_context* context, wStream* s,
|
static UINT audin_server_recv_version(audin_server_context* context, wStream* s,
|
||||||
const SNDIN_PDU* header)
|
const SNDIN_PDU* header)
|
||||||
{
|
{
|
||||||
|
audin_server* audin = (audin_server*)context;
|
||||||
SNDIN_VERSION pdu = { 0 };
|
SNDIN_VERSION pdu = { 0 };
|
||||||
UINT error = CHANNEL_RC_OK;
|
UINT error = CHANNEL_RC_OK;
|
||||||
|
|
||||||
@ -70,14 +78,15 @@ static UINT audin_server_recv_version(audin_server_context* context, wStream* s,
|
|||||||
|
|
||||||
pdu.Header = *header;
|
pdu.Header = *header;
|
||||||
|
|
||||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
|
if (!Stream_CheckAndLogRequiredLengthWLog(audin->log, s, 4))
|
||||||
return ERROR_NO_DATA;
|
return ERROR_NO_DATA;
|
||||||
|
|
||||||
Stream_Read_UINT32(s, pdu.Version);
|
Stream_Read_UINT32(s, pdu.Version);
|
||||||
|
|
||||||
IFCALLRET(context->ReceiveVersion, error, context, &pdu);
|
IFCALLRET(context->ReceiveVersion, error, context, &pdu);
|
||||||
if (error)
|
if (error)
|
||||||
WLog_ERR(TAG, "context->ReceiveVersion failed with error %" PRIu32 "", error);
|
WLog_Print(audin->log, WLOG_ERROR, "context->ReceiveVersion failed with error %" PRIu32 "",
|
||||||
|
error);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
@ -85,6 +94,7 @@ static UINT audin_server_recv_version(audin_server_context* context, wStream* s,
|
|||||||
static UINT audin_server_recv_formats(audin_server_context* context, wStream* s,
|
static UINT audin_server_recv_formats(audin_server_context* context, wStream* s,
|
||||||
const SNDIN_PDU* header)
|
const SNDIN_PDU* header)
|
||||||
{
|
{
|
||||||
|
audin_server* audin = (audin_server*)context;
|
||||||
SNDIN_FORMATS pdu = { 0 };
|
SNDIN_FORMATS pdu = { 0 };
|
||||||
UINT error = CHANNEL_RC_OK;
|
UINT error = CHANNEL_RC_OK;
|
||||||
|
|
||||||
@ -94,7 +104,7 @@ static UINT audin_server_recv_formats(audin_server_context* context, wStream* s,
|
|||||||
pdu.Header = *header;
|
pdu.Header = *header;
|
||||||
|
|
||||||
/* Implementations MUST, at a minimum, support WAVE_FORMAT_PCM (0x0001) */
|
/* Implementations MUST, at a minimum, support WAVE_FORMAT_PCM (0x0001) */
|
||||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4 + 4 + 18))
|
if (!Stream_CheckAndLogRequiredLengthWLog(audin->log, s, 4 + 4 + 18))
|
||||||
return ERROR_NO_DATA;
|
return ERROR_NO_DATA;
|
||||||
|
|
||||||
Stream_Read_UINT32(s, pdu.NumFormats);
|
Stream_Read_UINT32(s, pdu.NumFormats);
|
||||||
@ -102,14 +112,14 @@ static UINT audin_server_recv_formats(audin_server_context* context, wStream* s,
|
|||||||
|
|
||||||
if (pdu.NumFormats == 0)
|
if (pdu.NumFormats == 0)
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "Sound Formats PDU contains no formats");
|
WLog_Print(audin->log, WLOG_ERROR, "Sound Formats PDU contains no formats");
|
||||||
return ERROR_INVALID_DATA;
|
return ERROR_INVALID_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
pdu.SoundFormats = audio_formats_new(pdu.NumFormats);
|
pdu.SoundFormats = audio_formats_new(pdu.NumFormats);
|
||||||
if (!pdu.SoundFormats)
|
if (!pdu.SoundFormats)
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "Failed to allocate %u SoundFormats", pdu.NumFormats);
|
WLog_Print(audin->log, WLOG_ERROR, "Failed to allocate %u SoundFormats", pdu.NumFormats);
|
||||||
return ERROR_NOT_ENOUGH_MEMORY;
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,18 +129,19 @@ static UINT audin_server_recv_formats(audin_server_context* context, wStream* s,
|
|||||||
|
|
||||||
if (!audio_format_read(s, format))
|
if (!audio_format_read(s, format))
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "Failed to read audio format");
|
WLog_Print(audin->log, WLOG_ERROR, "Failed to read audio format");
|
||||||
audio_formats_free(pdu.SoundFormats, i + i);
|
audio_formats_free(pdu.SoundFormats, i + i);
|
||||||
return ERROR_INVALID_DATA;
|
return ERROR_INVALID_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
audio_format_print(WLog_Get(TAG), WLOG_DEBUG, format);
|
audio_format_print(audin->log, WLOG_DEBUG, format);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pdu.cbSizeFormatsPacket != Stream_GetPosition(s))
|
if (pdu.cbSizeFormatsPacket != Stream_GetPosition(s))
|
||||||
{
|
{
|
||||||
WLog_WARN(TAG, "cbSizeFormatsPacket is invalid! Expected: %u Got: %zu. Fixing size",
|
WLog_Print(audin->log, WLOG_WARN,
|
||||||
pdu.cbSizeFormatsPacket, Stream_GetPosition(s));
|
"cbSizeFormatsPacket is invalid! Expected: %u Got: %zu. Fixing size",
|
||||||
|
pdu.cbSizeFormatsPacket, Stream_GetPosition(s));
|
||||||
pdu.cbSizeFormatsPacket = Stream_GetPosition(s);
|
pdu.cbSizeFormatsPacket = Stream_GetPosition(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +149,8 @@ static UINT audin_server_recv_formats(audin_server_context* context, wStream* s,
|
|||||||
|
|
||||||
IFCALLRET(context->ReceiveFormats, error, context, &pdu);
|
IFCALLRET(context->ReceiveFormats, error, context, &pdu);
|
||||||
if (error)
|
if (error)
|
||||||
WLog_ERR(TAG, "context->ReceiveFormats failed with error %" PRIu32 "", error);
|
WLog_Print(audin->log, WLOG_ERROR, "context->ReceiveFormats failed with error %" PRIu32 "",
|
||||||
|
error);
|
||||||
|
|
||||||
audio_formats_free(pdu.SoundFormats, pdu.NumFormats);
|
audio_formats_free(pdu.SoundFormats, pdu.NumFormats);
|
||||||
|
|
||||||
@ -148,6 +160,7 @@ static UINT audin_server_recv_formats(audin_server_context* context, wStream* s,
|
|||||||
static UINT audin_server_recv_open_reply(audin_server_context* context, wStream* s,
|
static UINT audin_server_recv_open_reply(audin_server_context* context, wStream* s,
|
||||||
const SNDIN_PDU* header)
|
const SNDIN_PDU* header)
|
||||||
{
|
{
|
||||||
|
audin_server* audin = (audin_server*)context;
|
||||||
SNDIN_OPEN_REPLY pdu = { 0 };
|
SNDIN_OPEN_REPLY pdu = { 0 };
|
||||||
UINT error = CHANNEL_RC_OK;
|
UINT error = CHANNEL_RC_OK;
|
||||||
|
|
||||||
@ -156,14 +169,15 @@ static UINT audin_server_recv_open_reply(audin_server_context* context, wStream*
|
|||||||
|
|
||||||
pdu.Header = *header;
|
pdu.Header = *header;
|
||||||
|
|
||||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
|
if (!Stream_CheckAndLogRequiredLengthWLog(audin->log, s, 4))
|
||||||
return ERROR_NO_DATA;
|
return ERROR_NO_DATA;
|
||||||
|
|
||||||
Stream_Read_UINT32(s, pdu.Result);
|
Stream_Read_UINT32(s, pdu.Result);
|
||||||
|
|
||||||
IFCALLRET(context->OpenReply, error, context, &pdu);
|
IFCALLRET(context->OpenReply, error, context, &pdu);
|
||||||
if (error)
|
if (error)
|
||||||
WLog_ERR(TAG, "context->OpenReply failed with error %" PRIu32 "", error);
|
WLog_Print(audin->log, WLOG_ERROR, "context->OpenReply failed with error %" PRIu32 "",
|
||||||
|
error);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
@ -171,6 +185,7 @@ static UINT audin_server_recv_open_reply(audin_server_context* context, wStream*
|
|||||||
static UINT audin_server_recv_data_incoming(audin_server_context* context, wStream* s,
|
static UINT audin_server_recv_data_incoming(audin_server_context* context, wStream* s,
|
||||||
const SNDIN_PDU* header)
|
const SNDIN_PDU* header)
|
||||||
{
|
{
|
||||||
|
audin_server* audin = (audin_server*)context;
|
||||||
SNDIN_DATA_INCOMING pdu = { 0 };
|
SNDIN_DATA_INCOMING pdu = { 0 };
|
||||||
UINT error = CHANNEL_RC_OK;
|
UINT error = CHANNEL_RC_OK;
|
||||||
|
|
||||||
@ -181,7 +196,8 @@ static UINT audin_server_recv_data_incoming(audin_server_context* context, wStre
|
|||||||
|
|
||||||
IFCALLRET(context->IncomingData, error, context, &pdu);
|
IFCALLRET(context->IncomingData, error, context, &pdu);
|
||||||
if (error)
|
if (error)
|
||||||
WLog_ERR(TAG, "context->IncomingData failed with error %" PRIu32 "", error);
|
WLog_Print(audin->log, WLOG_ERROR, "context->IncomingData failed with error %" PRIu32 "",
|
||||||
|
error);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
@ -189,6 +205,7 @@ static UINT audin_server_recv_data_incoming(audin_server_context* context, wStre
|
|||||||
static UINT audin_server_recv_data(audin_server_context* context, wStream* s,
|
static UINT audin_server_recv_data(audin_server_context* context, wStream* s,
|
||||||
const SNDIN_PDU* header)
|
const SNDIN_PDU* header)
|
||||||
{
|
{
|
||||||
|
audin_server* audin = (audin_server*)context;
|
||||||
SNDIN_DATA pdu = { 0 };
|
SNDIN_DATA pdu = { 0 };
|
||||||
wStream dataBuffer = { 0 };
|
wStream dataBuffer = { 0 };
|
||||||
UINT error = CHANNEL_RC_OK;
|
UINT error = CHANNEL_RC_OK;
|
||||||
@ -202,7 +219,7 @@ static UINT audin_server_recv_data(audin_server_context* context, wStream* s,
|
|||||||
|
|
||||||
IFCALLRET(context->Data, error, context, &pdu);
|
IFCALLRET(context->Data, error, context, &pdu);
|
||||||
if (error)
|
if (error)
|
||||||
WLog_ERR(TAG, "context->Data failed with error %" PRIu32 "", error);
|
WLog_Print(audin->log, WLOG_ERROR, "context->Data failed with error %" PRIu32 "", error);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
@ -210,6 +227,7 @@ static UINT audin_server_recv_data(audin_server_context* context, wStream* s,
|
|||||||
static UINT audin_server_recv_format_change(audin_server_context* context, wStream* s,
|
static UINT audin_server_recv_format_change(audin_server_context* context, wStream* s,
|
||||||
const SNDIN_PDU* header)
|
const SNDIN_PDU* header)
|
||||||
{
|
{
|
||||||
|
audin_server* audin = (audin_server*)context;
|
||||||
SNDIN_FORMATCHANGE pdu = { 0 };
|
SNDIN_FORMATCHANGE pdu = { 0 };
|
||||||
UINT error = CHANNEL_RC_OK;
|
UINT error = CHANNEL_RC_OK;
|
||||||
|
|
||||||
@ -218,32 +236,31 @@ static UINT audin_server_recv_format_change(audin_server_context* context, wStre
|
|||||||
|
|
||||||
pdu.Header = *header;
|
pdu.Header = *header;
|
||||||
|
|
||||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
|
if (!Stream_CheckAndLogRequiredLengthWLog(audin->log, s, 4))
|
||||||
return ERROR_NO_DATA;
|
return ERROR_NO_DATA;
|
||||||
|
|
||||||
Stream_Read_UINT32(s, pdu.NewFormat);
|
Stream_Read_UINT32(s, pdu.NewFormat);
|
||||||
|
|
||||||
IFCALLRET(context->ReceiveFormatChange, error, context, &pdu);
|
IFCALLRET(context->ReceiveFormatChange, error, context, &pdu);
|
||||||
if (error)
|
if (error)
|
||||||
WLog_ERR(TAG, "context->ReceiveFormatChange failed with error %" PRIu32 "", error);
|
WLog_Print(audin->log, WLOG_ERROR,
|
||||||
|
"context->ReceiveFormatChange failed with error %" PRIu32 "", error);
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DWORD WINAPI audin_server_thread_func(LPVOID arg)
|
static DWORD WINAPI audin_server_thread_func(LPVOID arg)
|
||||||
{
|
{
|
||||||
wStream* s;
|
wStream* s = NULL;
|
||||||
void* buffer;
|
void* buffer = NULL;
|
||||||
DWORD nCount;
|
DWORD nCount = 0;
|
||||||
HANDLE events[8];
|
HANDLE events[8] = { 0 };
|
||||||
BOOL ready = FALSE;
|
BOOL ready = FALSE;
|
||||||
HANDLE ChannelEvent;
|
HANDLE ChannelEvent = NULL;
|
||||||
DWORD BytesReturned = 0;
|
DWORD BytesReturned = 0;
|
||||||
audin_server* audin = (audin_server*)arg;
|
audin_server* audin = (audin_server*)arg;
|
||||||
UINT error = CHANNEL_RC_OK;
|
UINT error = CHANNEL_RC_OK;
|
||||||
DWORD status;
|
DWORD status = ERROR_INTERNAL_ERROR;
|
||||||
buffer = NULL;
|
|
||||||
ChannelEvent = NULL;
|
|
||||||
|
|
||||||
WINPR_ASSERT(audin);
|
WINPR_ASSERT(audin);
|
||||||
|
|
||||||
@ -257,7 +274,7 @@ static DWORD WINAPI audin_server_thread_func(LPVOID arg)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "WTSVirtualChannelQuery failed");
|
WLog_Print(audin->log, WLOG_ERROR, "WTSVirtualChannelQuery failed");
|
||||||
error = ERROR_INTERNAL_ERROR;
|
error = ERROR_INTERNAL_ERROR;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -276,7 +293,8 @@ static DWORD WINAPI audin_server_thread_func(LPVOID arg)
|
|||||||
if (status == WAIT_FAILED)
|
if (status == WAIT_FAILED)
|
||||||
{
|
{
|
||||||
error = GetLastError();
|
error = GetLastError();
|
||||||
WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error);
|
WLog_Print(audin->log, WLOG_ERROR,
|
||||||
|
"WaitForMultipleObjects failed with error %" PRIu32 "", error);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if (status == WAIT_OBJECT_0)
|
if (status == WAIT_OBJECT_0)
|
||||||
@ -285,7 +303,7 @@ static DWORD WINAPI audin_server_thread_func(LPVOID arg)
|
|||||||
if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualChannelReady, &buffer,
|
if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualChannelReady, &buffer,
|
||||||
&BytesReturned) == FALSE)
|
&BytesReturned) == FALSE)
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "WTSVirtualChannelQuery failed");
|
WLog_Print(audin->log, WLOG_ERROR, "WTSVirtualChannelQuery failed");
|
||||||
error = ERROR_INTERNAL_ERROR;
|
error = ERROR_INTERNAL_ERROR;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -301,7 +319,7 @@ static DWORD WINAPI audin_server_thread_func(LPVOID arg)
|
|||||||
|
|
||||||
if (!s)
|
if (!s)
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "Stream_New failed!");
|
WLog_Print(audin->log, WLOG_ERROR, "Stream_New failed!");
|
||||||
error = CHANNEL_RC_NO_MEMORY;
|
error = CHANNEL_RC_NO_MEMORY;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -314,7 +332,7 @@ static DWORD WINAPI audin_server_thread_func(LPVOID arg)
|
|||||||
|
|
||||||
if ((error = audin->context.SendVersion(&audin->context, &version)))
|
if ((error = audin->context.SendVersion(&audin->context, &version)))
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "SendVersion failed with error %" PRIu32 "!", error);
|
WLog_Print(audin->log, WLOG_ERROR, "SendVersion failed with error %" PRIu32 "!", error);
|
||||||
goto out_capacity;
|
goto out_capacity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -329,7 +347,8 @@ static DWORD WINAPI audin_server_thread_func(LPVOID arg)
|
|||||||
if (status == WAIT_FAILED)
|
if (status == WAIT_FAILED)
|
||||||
{
|
{
|
||||||
error = GetLastError();
|
error = GetLastError();
|
||||||
WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error);
|
WLog_Print(audin->log, WLOG_ERROR,
|
||||||
|
"WaitForMultipleObjects failed with error %" PRIu32 "", error);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (status == WAIT_OBJECT_0)
|
if (status == WAIT_OBJECT_0)
|
||||||
@ -339,7 +358,7 @@ static DWORD WINAPI audin_server_thread_func(LPVOID arg)
|
|||||||
|
|
||||||
if (!WTSVirtualChannelRead(audin->audin_channel, 0, NULL, 0, &BytesReturned))
|
if (!WTSVirtualChannelRead(audin->audin_channel, 0, NULL, 0, &BytesReturned))
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
|
WLog_Print(audin->log, WLOG_ERROR, "WTSVirtualChannelRead failed!");
|
||||||
error = ERROR_INTERNAL_ERROR;
|
error = ERROR_INTERNAL_ERROR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -354,13 +373,13 @@ static DWORD WINAPI audin_server_thread_func(LPVOID arg)
|
|||||||
if (WTSVirtualChannelRead(audin->audin_channel, 0, (PCHAR)Stream_Buffer(s),
|
if (WTSVirtualChannelRead(audin->audin_channel, 0, (PCHAR)Stream_Buffer(s),
|
||||||
(ULONG)Stream_Capacity(s), &BytesReturned) == FALSE)
|
(ULONG)Stream_Capacity(s), &BytesReturned) == FALSE)
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
|
WLog_Print(audin->log, WLOG_ERROR, "WTSVirtualChannelRead failed!");
|
||||||
error = ERROR_INTERNAL_ERROR;
|
error = ERROR_INTERNAL_ERROR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream_SetLength(s, BytesReturned);
|
Stream_SetLength(s, BytesReturned);
|
||||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, SNDIN_HEADER_SIZE))
|
if (!Stream_CheckAndLogRequiredLengthWLog(audin->log, s, SNDIN_HEADER_SIZE))
|
||||||
{
|
{
|
||||||
error = ERROR_INTERNAL_ERROR;
|
error = ERROR_INTERNAL_ERROR;
|
||||||
break;
|
break;
|
||||||
@ -389,8 +408,9 @@ static DWORD WINAPI audin_server_thread_func(LPVOID arg)
|
|||||||
error = audin_server_recv_format_change(&audin->context, s, &header);
|
error = audin_server_recv_format_change(&audin->context, s, &header);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
WLog_ERR(TAG, "audin_server_thread_func: unknown or invalid MessageId %" PRIu8 "",
|
WLog_Print(audin->log, WLOG_ERROR,
|
||||||
header.MessageId);
|
"audin_server_thread_func: unknown or invalid MessageId %" PRIu8 "",
|
||||||
|
header.MessageId);
|
||||||
error = ERROR_INVALID_DATA;
|
error = ERROR_INVALID_DATA;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -437,7 +457,7 @@ static BOOL audin_server_open(audin_server_context* context)
|
|||||||
|
|
||||||
if (!audin->audin_channel)
|
if (!audin->audin_channel)
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "WTSVirtualChannelOpenEx failed!");
|
WLog_Print(audin->log, WLOG_ERROR, "WTSVirtualChannelOpenEx failed!");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -446,20 +466,20 @@ static BOOL audin_server_open(audin_server_context* context)
|
|||||||
IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
|
IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
|
||||||
if (!status)
|
if (!status)
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "context->ChannelIdAssigned failed!");
|
WLog_Print(audin->log, WLOG_ERROR, "context->ChannelIdAssigned failed!");
|
||||||
return ERROR_INTERNAL_ERROR;
|
return ERROR_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(audin->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
|
if (!(audin->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "CreateEvent failed!");
|
WLog_Print(audin->log, WLOG_ERROR, "CreateEvent failed!");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(audin->thread =
|
if (!(audin->thread =
|
||||||
CreateThread(NULL, 0, audin_server_thread_func, (void*)audin, 0, NULL)))
|
CreateThread(NULL, 0, audin_server_thread_func, (void*)audin, 0, NULL)))
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "CreateThread failed!");
|
WLog_Print(audin->log, WLOG_ERROR, "CreateThread failed!");
|
||||||
CloseHandle(audin->stopEvent);
|
CloseHandle(audin->stopEvent);
|
||||||
audin->stopEvent = NULL;
|
audin->stopEvent = NULL;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@ -468,7 +488,7 @@ static BOOL audin_server_open(audin_server_context* context)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
WLog_ERR(TAG, "thread already running!");
|
WLog_Print(audin->log, WLOG_ERROR, "thread already running!");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -491,7 +511,8 @@ static BOOL audin_server_close(audin_server_context* context)
|
|||||||
|
|
||||||
if (WaitForSingleObject(audin->thread, INFINITE) == WAIT_FAILED)
|
if (WaitForSingleObject(audin->thread, INFINITE) == WAIT_FAILED)
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", GetLastError());
|
WLog_Print(audin->log, WLOG_ERROR, "WaitForSingleObject failed with error %" PRIu32 "",
|
||||||
|
GetLastError());
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -510,15 +531,15 @@ static BOOL audin_server_close(audin_server_context* context)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static wStream* audin_server_packet_new(size_t size, BYTE MessageId)
|
static wStream* audin_server_packet_new(wLog* log, size_t size, BYTE MessageId)
|
||||||
{
|
{
|
||||||
wStream* s;
|
WINPR_ASSERT(log);
|
||||||
|
|
||||||
/* Allocate what we need plus header bytes */
|
/* Allocate what we need plus header bytes */
|
||||||
s = Stream_New(NULL, size + SNDIN_HEADER_SIZE);
|
wStream* s = Stream_New(NULL, size + SNDIN_HEADER_SIZE);
|
||||||
if (!s)
|
if (!s)
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "Stream_New failed!");
|
WLog_Print(log, WLOG_ERROR, "Stream_New failed!");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -539,15 +560,15 @@ static UINT audin_server_packet_send(audin_server_context* context, wStream* s)
|
|||||||
if (!WTSVirtualChannelWrite(audin->audin_channel, (PCHAR)Stream_Buffer(s),
|
if (!WTSVirtualChannelWrite(audin->audin_channel, (PCHAR)Stream_Buffer(s),
|
||||||
Stream_GetPosition(s), &written))
|
Stream_GetPosition(s), &written))
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
|
WLog_Print(audin->log, WLOG_ERROR, "WTSVirtualChannelWrite failed!");
|
||||||
error = ERROR_INTERNAL_ERROR;
|
error = ERROR_INTERNAL_ERROR;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (written < Stream_GetPosition(s))
|
if (written < Stream_GetPosition(s))
|
||||||
{
|
{
|
||||||
WLog_WARN(TAG, "Unexpected bytes written: %" PRIu32 "/%" PRIuz "", written,
|
WLog_Print(audin->log, WLOG_WARN, "Unexpected bytes written: %" PRIu32 "/%" PRIuz "",
|
||||||
Stream_GetPosition(s));
|
written, Stream_GetPosition(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@ -557,12 +578,12 @@ out:
|
|||||||
|
|
||||||
static UINT audin_server_send_version(audin_server_context* context, const SNDIN_VERSION* version)
|
static UINT audin_server_send_version(audin_server_context* context, const SNDIN_VERSION* version)
|
||||||
{
|
{
|
||||||
wStream* s;
|
audin_server* audin = (audin_server*)context;
|
||||||
|
|
||||||
WINPR_ASSERT(context);
|
WINPR_ASSERT(context);
|
||||||
WINPR_ASSERT(version);
|
WINPR_ASSERT(version);
|
||||||
|
|
||||||
s = audin_server_packet_new(4, MSG_SNDIN_VERSION);
|
wStream* s = audin_server_packet_new(audin->log, 4, MSG_SNDIN_VERSION);
|
||||||
if (!s)
|
if (!s)
|
||||||
return ERROR_NOT_ENOUGH_MEMORY;
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
|
||||||
@ -573,12 +594,12 @@ static UINT audin_server_send_version(audin_server_context* context, const SNDIN
|
|||||||
|
|
||||||
static UINT audin_server_send_formats(audin_server_context* context, const SNDIN_FORMATS* formats)
|
static UINT audin_server_send_formats(audin_server_context* context, const SNDIN_FORMATS* formats)
|
||||||
{
|
{
|
||||||
wStream* s;
|
audin_server* audin = (audin_server*)context;
|
||||||
|
|
||||||
WINPR_ASSERT(context);
|
WINPR_ASSERT(context);
|
||||||
WINPR_ASSERT(formats);
|
WINPR_ASSERT(formats);
|
||||||
|
|
||||||
s = audin_server_packet_new(4 + 4 + 18, MSG_SNDIN_FORMATS);
|
wStream* s = audin_server_packet_new(audin->log, 4 + 4 + 18, MSG_SNDIN_FORMATS);
|
||||||
if (!s)
|
if (!s)
|
||||||
return ERROR_NOT_ENOUGH_MEMORY;
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
|
||||||
@ -591,7 +612,7 @@ static UINT audin_server_send_formats(audin_server_context* context, const SNDIN
|
|||||||
|
|
||||||
if (!audio_format_write(s, format))
|
if (!audio_format_write(s, format))
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "Failed to write audio format");
|
WLog_Print(audin->log, WLOG_ERROR, "Failed to write audio format");
|
||||||
Stream_Free(s, TRUE);
|
Stream_Free(s, TRUE);
|
||||||
return CHANNEL_RC_NO_MEMORY;
|
return CHANNEL_RC_NO_MEMORY;
|
||||||
}
|
}
|
||||||
@ -602,12 +623,11 @@ static UINT audin_server_send_formats(audin_server_context* context, const SNDIN
|
|||||||
|
|
||||||
static UINT audin_server_send_open(audin_server_context* context, const SNDIN_OPEN* open)
|
static UINT audin_server_send_open(audin_server_context* context, const SNDIN_OPEN* open)
|
||||||
{
|
{
|
||||||
wStream* s;
|
audin_server* audin = (audin_server*)context;
|
||||||
|
|
||||||
WINPR_ASSERT(context);
|
WINPR_ASSERT(context);
|
||||||
WINPR_ASSERT(open);
|
WINPR_ASSERT(open);
|
||||||
|
|
||||||
s = audin_server_packet_new(4 + 4 + 18 + 22, MSG_SNDIN_OPEN);
|
wStream* s = audin_server_packet_new(audin->log, 4 + 4 + 18 + 22, MSG_SNDIN_OPEN);
|
||||||
if (!s)
|
if (!s)
|
||||||
return ERROR_NOT_ENOUGH_MEMORY;
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
|
||||||
@ -653,12 +673,12 @@ static UINT audin_server_send_open(audin_server_context* context, const SNDIN_OP
|
|||||||
static UINT audin_server_send_format_change(audin_server_context* context,
|
static UINT audin_server_send_format_change(audin_server_context* context,
|
||||||
const SNDIN_FORMATCHANGE* format_change)
|
const SNDIN_FORMATCHANGE* format_change)
|
||||||
{
|
{
|
||||||
wStream* s;
|
audin_server* audin = (audin_server*)context;
|
||||||
|
|
||||||
WINPR_ASSERT(context);
|
WINPR_ASSERT(context);
|
||||||
WINPR_ASSERT(format_change);
|
WINPR_ASSERT(format_change);
|
||||||
|
|
||||||
s = audin_server_packet_new(4, MSG_SNDIN_FORMATCHANGE);
|
wStream* s = audin_server_packet_new(audin->log, 4, MSG_SNDIN_FORMATCHANGE);
|
||||||
if (!s)
|
if (!s)
|
||||||
return ERROR_NOT_ENOUGH_MEMORY;
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||||||
|
|
||||||
@ -667,17 +687,134 @@ static UINT audin_server_send_format_change(audin_server_context* context,
|
|||||||
return audin_server_packet_send(context, s);
|
return audin_server_packet_send(context, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static UINT audin_server_receive_version_default(audin_server_context* audin_ctx,
|
||||||
|
const SNDIN_VERSION* version)
|
||||||
|
{
|
||||||
|
audin_server* audin = (audin_server*)audin_ctx;
|
||||||
|
SNDIN_FORMATS formats = { 0 };
|
||||||
|
|
||||||
|
WINPR_ASSERT(audin);
|
||||||
|
WINPR_ASSERT(version);
|
||||||
|
|
||||||
|
if (version->Version == 0)
|
||||||
|
{
|
||||||
|
WLog_Print(audin->log, WLOG_ERROR, "Received invalid AUDIO_INPUT version from client");
|
||||||
|
return ERROR_INVALID_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
WLog_Print(audin->log, WLOG_DEBUG, "AUDIO_INPUT version of client: %u", version->Version);
|
||||||
|
|
||||||
|
formats.NumFormats = audin->audin_n_server_formats;
|
||||||
|
formats.SoundFormats = audin->audin_server_formats;
|
||||||
|
|
||||||
|
return audin->context.SendFormats(&audin->context, &formats);
|
||||||
|
}
|
||||||
|
|
||||||
|
static UINT send_open(audin_server* audin)
|
||||||
|
{
|
||||||
|
SNDIN_OPEN open = { 0 };
|
||||||
|
|
||||||
|
WINPR_ASSERT(audin);
|
||||||
|
|
||||||
|
open.FramesPerPacket = 441;
|
||||||
|
open.initialFormat = audin->audin_client_format_idx;
|
||||||
|
open.captureFormat.wFormatTag = WAVE_FORMAT_PCM;
|
||||||
|
open.captureFormat.nChannels = 2;
|
||||||
|
open.captureFormat.nSamplesPerSec = 44100;
|
||||||
|
open.captureFormat.nAvgBytesPerSec = 44100 * 2 * 2;
|
||||||
|
open.captureFormat.nBlockAlign = 4;
|
||||||
|
open.captureFormat.wBitsPerSample = 16;
|
||||||
|
|
||||||
|
WINPR_ASSERT(audin->context.SendOpen);
|
||||||
|
return audin->context.SendOpen(&audin->context, &open);
|
||||||
|
}
|
||||||
|
|
||||||
|
static UINT audin_server_receive_formats_default(audin_server_context* context,
|
||||||
|
const SNDIN_FORMATS* formats)
|
||||||
|
{
|
||||||
|
audin_server* audin = (audin_server*)context;
|
||||||
|
WINPR_ASSERT(audin);
|
||||||
|
WINPR_ASSERT(formats);
|
||||||
|
|
||||||
|
if (audin->audin_negotiated_format)
|
||||||
|
{
|
||||||
|
WLog_Print(audin->log, WLOG_ERROR,
|
||||||
|
"Received client formats, but negotiation was already done");
|
||||||
|
return ERROR_INVALID_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < audin->audin_n_server_formats; ++i)
|
||||||
|
{
|
||||||
|
for (UINT32 j = 0; j < formats->NumFormats; ++j)
|
||||||
|
{
|
||||||
|
if (audio_format_compatible(&audin->audin_server_formats[i], &formats->SoundFormats[j]))
|
||||||
|
{
|
||||||
|
audin->audin_negotiated_format = &audin->audin_server_formats[i];
|
||||||
|
audin->audin_client_format_idx = i;
|
||||||
|
return send_open(audin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WLog_Print(audin->log, WLOG_ERROR, "Could not agree on a audio format with the server");
|
||||||
|
|
||||||
|
return ERROR_INVALID_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
static UINT audin_server_receive_format_change_default(audin_server_context* context,
|
||||||
|
const SNDIN_FORMATCHANGE* format_change)
|
||||||
|
{
|
||||||
|
audin_server* audin = (audin_server*)context;
|
||||||
|
|
||||||
|
WINPR_ASSERT(audin);
|
||||||
|
WINPR_ASSERT(format_change);
|
||||||
|
|
||||||
|
if (format_change->NewFormat != audin->audin_client_format_idx)
|
||||||
|
{
|
||||||
|
WLog_Print(audin->log, WLOG_ERROR,
|
||||||
|
"NewFormat in FormatChange differs from requested format");
|
||||||
|
return ERROR_INVALID_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
WLog_Print(audin->log, WLOG_DEBUG, "Received Format Change PDU: %u", format_change->NewFormat);
|
||||||
|
|
||||||
|
return CHANNEL_RC_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static UINT audin_server_incoming_data_default(audin_server_context* context,
|
||||||
|
const SNDIN_DATA_INCOMING* data_incoming)
|
||||||
|
{
|
||||||
|
audin_server* audin = (audin_server*)context;
|
||||||
|
WINPR_ASSERT(audin);
|
||||||
|
WINPR_ASSERT(data_incoming);
|
||||||
|
|
||||||
|
/* TODO: Implement bandwidth measure of clients uplink */
|
||||||
|
WLog_Print(audin->log, WLOG_DEBUG, "Received Incoming Data PDU");
|
||||||
|
return CHANNEL_RC_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static UINT audin_server_open_reply_default(audin_server_context* context,
|
||||||
|
const SNDIN_OPEN_REPLY* open_reply)
|
||||||
|
{
|
||||||
|
audin_server* audin = (audin_server*)context;
|
||||||
|
WINPR_ASSERT(audin);
|
||||||
|
WINPR_ASSERT(open_reply);
|
||||||
|
|
||||||
|
/* TODO: Implement failure handling */
|
||||||
|
WLog_Print(audin->log, WLOG_DEBUG, "Open Reply PDU: Result: %i", open_reply->Result);
|
||||||
|
return CHANNEL_RC_OK;
|
||||||
|
}
|
||||||
|
|
||||||
audin_server_context* audin_server_context_new(HANDLE vcm)
|
audin_server_context* audin_server_context_new(HANDLE vcm)
|
||||||
{
|
{
|
||||||
audin_server* audin;
|
audin_server* audin = (audin_server*)calloc(1, sizeof(audin_server));
|
||||||
audin = (audin_server*)calloc(1, sizeof(audin_server));
|
|
||||||
|
|
||||||
if (!audin)
|
if (!audin)
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "calloc failed!");
|
WLog_Print(audin->log, WLOG_ERROR, "calloc failed!");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
audin->log = WLog_Get(AUDIN_TAG);
|
||||||
audin->context.vcm = vcm;
|
audin->context.vcm = vcm;
|
||||||
audin->context.Open = audin_server_open;
|
audin->context.Open = audin_server_open;
|
||||||
audin->context.IsOpen = audin_server_is_open;
|
audin->context.IsOpen = audin_server_is_open;
|
||||||
@ -690,8 +827,13 @@ audin_server_context* audin_server_context_new(HANDLE vcm)
|
|||||||
|
|
||||||
/* Default values */
|
/* Default values */
|
||||||
audin->context.serverVersion = SNDIN_VERSION_Version_2;
|
audin->context.serverVersion = SNDIN_VERSION_Version_2;
|
||||||
|
audin->context.ReceiveVersion = audin_server_receive_version_default;
|
||||||
|
audin->context.ReceiveFormats = audin_server_receive_formats_default;
|
||||||
|
audin->context.ReceiveFormatChange = audin_server_receive_format_change_default;
|
||||||
|
audin->context.IncomingData = audin_server_incoming_data_default;
|
||||||
|
audin->context.OpenReply = audin_server_open_reply_default;
|
||||||
|
|
||||||
return (audin_server_context*)audin;
|
return &audin->context;
|
||||||
}
|
}
|
||||||
|
|
||||||
void audin_server_context_free(audin_server_context* context)
|
void audin_server_context_free(audin_server_context* context)
|
||||||
@ -702,5 +844,49 @@ void audin_server_context_free(audin_server_context* context)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
audin_server_close(context);
|
audin_server_close(context);
|
||||||
|
audio_formats_free(audin->audin_server_formats, audin->audin_n_server_formats);
|
||||||
|
audin->audin_server_formats = NULL;
|
||||||
free(audin);
|
free(audin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOL audin_server_set_formats(audin_server_context* context, SSIZE_T count,
|
||||||
|
const AUDIO_FORMAT* formats)
|
||||||
|
{
|
||||||
|
audin_server* audin = (audin_server*)context;
|
||||||
|
WINPR_ASSERT(audin);
|
||||||
|
|
||||||
|
audio_formats_free(audin->audin_server_formats, audin->audin_n_server_formats);
|
||||||
|
audin->audin_n_server_formats = 0;
|
||||||
|
audin->audin_server_formats = NULL;
|
||||||
|
audin->audin_negotiated_format = NULL;
|
||||||
|
|
||||||
|
if (count < 0)
|
||||||
|
audin->audin_n_server_formats = server_audin_get_formats(&audin->audin_server_formats);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AUDIO_FORMAT* audin_server_formats = audio_formats_new(count);
|
||||||
|
if (!audin_server_formats)
|
||||||
|
return count == 0;
|
||||||
|
|
||||||
|
for (size_t x = 0; x < count; x++)
|
||||||
|
{
|
||||||
|
if (!audio_format_copy(&formats[x], &audin_server_formats[x]))
|
||||||
|
{
|
||||||
|
audio_formats_free(audin_server_formats, count);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
audin->audin_server_formats = audin_server_formats;
|
||||||
|
audin->audin_n_server_formats = count;
|
||||||
|
}
|
||||||
|
return audin->audin_n_server_formats > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AUDIO_FORMAT* audin_server_get_negotiated_format(const audin_server_context* context)
|
||||||
|
{
|
||||||
|
const audin_server* audin = (const audin_server*)context;
|
||||||
|
WINPR_ASSERT(audin);
|
||||||
|
|
||||||
|
return audin->audin_negotiated_format;
|
||||||
|
}
|
||||||
|
@ -160,6 +160,20 @@ extern "C"
|
|||||||
FREERDP_API audin_server_context* audin_server_context_new(HANDLE vcm);
|
FREERDP_API audin_server_context* audin_server_context_new(HANDLE vcm);
|
||||||
FREERDP_API void audin_server_context_free(audin_server_context* context);
|
FREERDP_API void audin_server_context_free(audin_server_context* context);
|
||||||
|
|
||||||
|
/** \brief sets the supported audio formats for AUDIN server channel context.
|
||||||
|
*
|
||||||
|
* \param context The context to set the formats for
|
||||||
|
* \param count The number of formats found in \formats. Use \b -1 to set to default formats
|
||||||
|
* supported by FreeRDP \param formats An array of \b count elements
|
||||||
|
*
|
||||||
|
* \return \b TRUE if successful and at least one format is supported, \b FALSE otherwise.
|
||||||
|
*/
|
||||||
|
FREERDP_API BOOL audin_server_set_formats(audin_server_context* context, SSIZE_T count,
|
||||||
|
const AUDIO_FORMAT* formats);
|
||||||
|
|
||||||
|
FREERDP_API const AUDIO_FORMAT*
|
||||||
|
audin_server_get_negotiated_format(const audin_server_context* context);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -129,10 +129,6 @@ extern "C"
|
|||||||
RdpsndServerContext* rdpsnd;
|
RdpsndServerContext* rdpsnd;
|
||||||
#if defined(CHANNEL_AUDIN_SERVER)
|
#if defined(CHANNEL_AUDIN_SERVER)
|
||||||
audin_server_context* audin;
|
audin_server_context* audin;
|
||||||
AUDIO_FORMAT* audin_server_formats;
|
|
||||||
size_t audin_n_server_formats;
|
|
||||||
AUDIO_FORMAT* audin_negotiated_format;
|
|
||||||
UINT32 audin_client_format_idx;
|
|
||||||
#endif
|
#endif
|
||||||
RdpgfxServerContext* rdpgfx;
|
RdpgfxServerContext* rdpgfx;
|
||||||
|
|
||||||
|
@ -30,110 +30,6 @@
|
|||||||
#include <freerdp/log.h>
|
#include <freerdp/log.h>
|
||||||
#define TAG SERVER_TAG("mac")
|
#define TAG SERVER_TAG("mac")
|
||||||
|
|
||||||
static UINT mf_peer_audin_receive_version(audin_server_context* audin, const SNDIN_VERSION* version)
|
|
||||||
{
|
|
||||||
mfPeerContext* context;
|
|
||||||
SNDIN_FORMATS formats = { 0 };
|
|
||||||
|
|
||||||
WINPR_ASSERT(audin);
|
|
||||||
WINPR_ASSERT(version);
|
|
||||||
|
|
||||||
context = audin->userdata;
|
|
||||||
WINPR_ASSERT(context);
|
|
||||||
|
|
||||||
if (version->Version == 0)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "Received invalid AUDIO_INPUT version from client");
|
|
||||||
return ERROR_INVALID_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
WLog_DBG(TAG, "AUDIO_INPUT version of client: %u", version->Version);
|
|
||||||
|
|
||||||
formats.NumFormats = context->audin_n_server_formats;
|
|
||||||
formats.SoundFormats = context->audin_server_formats;
|
|
||||||
|
|
||||||
return audin->SendFormats(audin, &formats);
|
|
||||||
}
|
|
||||||
|
|
||||||
static UINT send_open(audin_server_context* audin)
|
|
||||||
{
|
|
||||||
mfPeerContext* context;
|
|
||||||
SNDIN_OPEN open = { 0 };
|
|
||||||
|
|
||||||
WINPR_ASSERT(audin);
|
|
||||||
|
|
||||||
context = audin->userdata;
|
|
||||||
WINPR_ASSERT(context);
|
|
||||||
|
|
||||||
open.FramesPerPacket = 441;
|
|
||||||
open.initialFormat = context->audin_client_format_idx;
|
|
||||||
open.captureFormat.wFormatTag = WAVE_FORMAT_PCM;
|
|
||||||
open.captureFormat.nChannels = 2;
|
|
||||||
open.captureFormat.nSamplesPerSec = 44100;
|
|
||||||
open.captureFormat.nAvgBytesPerSec = 44100 * 2 * 2;
|
|
||||||
open.captureFormat.nBlockAlign = 4;
|
|
||||||
open.captureFormat.wBitsPerSample = 16;
|
|
||||||
|
|
||||||
return audin->SendOpen(audin, &open);
|
|
||||||
}
|
|
||||||
|
|
||||||
static UINT mf_peer_audin_receive_formats(audin_server_context* audin, const SNDIN_FORMATS* formats)
|
|
||||||
{
|
|
||||||
mfPeerContext* context;
|
|
||||||
|
|
||||||
WINPR_ASSERT(audin);
|
|
||||||
WINPR_ASSERT(formats);
|
|
||||||
|
|
||||||
context = audin->userdata;
|
|
||||||
WINPR_ASSERT(context);
|
|
||||||
|
|
||||||
if (context->audin_negotiated_format)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "Received client formats, but negotiation was already done");
|
|
||||||
return ERROR_INVALID_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < context->audin_n_server_formats; ++i)
|
|
||||||
{
|
|
||||||
for (UINT32 j = 0; j < formats->NumFormats; ++j)
|
|
||||||
{
|
|
||||||
if (audio_format_compatible(&context->audin_server_formats[i],
|
|
||||||
&formats->SoundFormats[j]))
|
|
||||||
{
|
|
||||||
context->audin_negotiated_format = &context->audin_server_formats[i];
|
|
||||||
context->audin_client_format_idx = i;
|
|
||||||
return send_open(audin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WLog_ERR(TAG, "Could not agree on a audio format with the server");
|
|
||||||
|
|
||||||
return ERROR_INVALID_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
static UINT mf_peer_audin_open_reply(audin_server_context* audin,
|
|
||||||
const SNDIN_OPEN_REPLY* open_reply)
|
|
||||||
{
|
|
||||||
WINPR_ASSERT(audin);
|
|
||||||
WINPR_ASSERT(open_reply);
|
|
||||||
|
|
||||||
/* TODO: Implement failure handling */
|
|
||||||
WLog_DBG(TAG, "Open Reply PDU: Result: %i", open_reply->Result);
|
|
||||||
return CHANNEL_RC_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static UINT mf_peer_audin_incoming_data(audin_server_context* audin,
|
|
||||||
const SNDIN_DATA_INCOMING* data_incoming)
|
|
||||||
{
|
|
||||||
WINPR_ASSERT(audin);
|
|
||||||
WINPR_ASSERT(data_incoming);
|
|
||||||
|
|
||||||
/* TODO: Implement bandwidth measure of clients uplink */
|
|
||||||
WLog_DBG(TAG, "Received Incoming Data PDU");
|
|
||||||
return CHANNEL_RC_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static UINT mf_peer_audin_data(audin_server_context* audin, const SNDIN_DATA* data)
|
static UINT mf_peer_audin_data(audin_server_context* audin, const SNDIN_DATA* data)
|
||||||
{
|
{
|
||||||
/* TODO: Implement */
|
/* TODO: Implement */
|
||||||
@ -145,29 +41,7 @@ static UINT mf_peer_audin_data(audin_server_context* audin, const SNDIN_DATA* da
|
|||||||
return CHANNEL_RC_OK;
|
return CHANNEL_RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static UINT mf_peer_audin_receive_format_change(audin_server_context* audin,
|
BOOL mf_peer_audin_init(mfPeerContext* context)
|
||||||
const SNDIN_FORMATCHANGE* format_change)
|
|
||||||
{
|
|
||||||
mfPeerContext* context;
|
|
||||||
|
|
||||||
WINPR_ASSERT(audin);
|
|
||||||
WINPR_ASSERT(format_change);
|
|
||||||
|
|
||||||
context = audin->userdata;
|
|
||||||
WINPR_ASSERT(context);
|
|
||||||
|
|
||||||
if (format_change->NewFormat != context->audin_client_format_idx)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "NewFormat in FormatChange differs from requested format");
|
|
||||||
return ERROR_INVALID_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
WLog_DBG(TAG, "Received Format Change PDU: %u", format_change->NewFormat);
|
|
||||||
|
|
||||||
return CHANNEL_RC_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mf_peer_audin_init(mfPeerContext* context)
|
|
||||||
{
|
{
|
||||||
WINPR_ASSERT(context);
|
WINPR_ASSERT(context);
|
||||||
|
|
||||||
@ -175,25 +49,15 @@ void mf_peer_audin_init(mfPeerContext* context)
|
|||||||
context->audin->rdpcontext = &context->_p;
|
context->audin->rdpcontext = &context->_p;
|
||||||
context->audin->userdata = context;
|
context->audin->userdata = context;
|
||||||
|
|
||||||
context->audin->ReceiveVersion = mf_peer_audin_receive_version;
|
|
||||||
context->audin->ReceiveFormats = mf_peer_audin_receive_formats;
|
|
||||||
context->audin->OpenReply = mf_peer_audin_open_reply;
|
|
||||||
context->audin->IncomingData = mf_peer_audin_incoming_data;
|
|
||||||
context->audin->Data = mf_peer_audin_data;
|
context->audin->Data = mf_peer_audin_data;
|
||||||
context->audin->ReceiveFormatChange = mf_peer_audin_receive_format_change;
|
|
||||||
|
|
||||||
context->audin_n_server_formats = server_audin_get_formats(&context->audin_server_formats);
|
return audin_server_set_formats(context->audin, -1, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mf_peer_audin_uninit(mfPeerContext* context)
|
void mf_peer_audin_uninit(mfPeerContext* context)
|
||||||
{
|
{
|
||||||
WINPR_ASSERT(context);
|
WINPR_ASSERT(context);
|
||||||
|
|
||||||
if (context->audin)
|
audin_server_context_free(context->audin);
|
||||||
{
|
context->audin = NULL;
|
||||||
audio_formats_free(context->audin_server_formats, context->audin_n_server_formats);
|
|
||||||
context->audin_server_formats = NULL;
|
|
||||||
audin_server_context_free(context->audin);
|
|
||||||
context->audin = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -27,8 +27,7 @@
|
|||||||
#include "mf_interface.h"
|
#include "mf_interface.h"
|
||||||
#include "mfreerdp.h"
|
#include "mfreerdp.h"
|
||||||
|
|
||||||
void mf_peer_audin_init(mfPeerContext* context);
|
BOOL mf_peer_audin_init(mfPeerContext* context);
|
||||||
|
|
||||||
void mf_peer_audin_uninit(mfPeerContext* context);
|
void mf_peer_audin_uninit(mfPeerContext* context);
|
||||||
|
|
||||||
#endif /* FREERDP_SERVER_MAC_AUDIN_H */
|
#endif /* FREERDP_SERVER_MAC_AUDIN_H */
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include <freerdp/config.h>
|
||||||
#include <freerdp/codec/rfx.h>
|
#include <freerdp/codec/rfx.h>
|
||||||
#include <freerdp/codec/nsc.h>
|
#include <freerdp/codec/nsc.h>
|
||||||
#include <freerdp/listener.h>
|
#include <freerdp/listener.h>
|
||||||
@ -30,19 +31,19 @@
|
|||||||
|
|
||||||
#include <winpr/crt.h>
|
#include <winpr/crt.h>
|
||||||
|
|
||||||
// #ifdef WITH_SERVER_CHANNELS
|
#ifdef WITH_SERVER_CHANNELS
|
||||||
#include <freerdp/channels/wtsvc.h>
|
#include <freerdp/channels/wtsvc.h>
|
||||||
// #endif
|
#endif
|
||||||
|
|
||||||
// #ifdef CHANNEL_RDPSND_SERVER
|
#ifdef CHANNEL_RDPSND_SERVER
|
||||||
#include <freerdp/server/rdpsnd.h>
|
#include <freerdp/server/rdpsnd.h>
|
||||||
// #include "mf_rdpsnd.h"
|
#include "mf_rdpsnd.h"
|
||||||
// #endif
|
#endif
|
||||||
|
|
||||||
// #ifdef CHANNEL_AUDIN_SERVER
|
#ifdef CHANNEL_AUDIN_SERVER
|
||||||
#include <freerdp/server/audin.h>
|
#include <freerdp/server/audin.h>
|
||||||
// #include "mf_audin.h"
|
#include "mf_audin.h"
|
||||||
// #endif
|
#endif
|
||||||
|
|
||||||
typedef struct mf_info mfInfo;
|
typedef struct mf_info mfInfo;
|
||||||
typedef struct mf_peer_context mfPeerContext;
|
typedef struct mf_peer_context mfPeerContext;
|
||||||
@ -59,20 +60,15 @@ struct mf_peer_context
|
|||||||
RFX_CONTEXT* rfx_context;
|
RFX_CONTEXT* rfx_context;
|
||||||
NSC_CONTEXT* nsc_context;
|
NSC_CONTEXT* nsc_context;
|
||||||
|
|
||||||
// #ifdef WITH_SERVER_CHANNELS
|
#ifdef WITH_SERVER_CHANNELS
|
||||||
HANDLE vcm;
|
HANDLE vcm;
|
||||||
// #endif
|
#endif
|
||||||
// #ifdef CHANNEL_AUDIN_SERVER
|
#ifdef CHANNEL_AUDIN_SERVER
|
||||||
audin_server_context* audin;
|
audin_server_context* audin;
|
||||||
AUDIO_FORMAT* audin_server_formats;
|
|
||||||
size_t audin_n_server_formats;
|
|
||||||
AUDIO_FORMAT* audin_negotiated_format;
|
|
||||||
UINT32 audin_client_format_idx;
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifdef CHANNEL_RDPSND_SERVER
|
#ifdef CHANNEL_RDPSND_SERVER
|
||||||
RdpsndServerContext* rdpsnd;
|
RdpsndServerContext* rdpsnd;
|
||||||
// #endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mf_info
|
struct mf_info
|
||||||
|
@ -33,109 +33,6 @@
|
|||||||
#define TAG SERVER_TAG("sample")
|
#define TAG SERVER_TAG("sample")
|
||||||
|
|
||||||
#if defined(CHANNEL_AUDIN_SERVER)
|
#if defined(CHANNEL_AUDIN_SERVER)
|
||||||
static UINT sf_peer_audin_receive_version(audin_server_context* audin, const SNDIN_VERSION* version)
|
|
||||||
{
|
|
||||||
testPeerContext* context;
|
|
||||||
SNDIN_FORMATS formats = { 0 };
|
|
||||||
|
|
||||||
WINPR_ASSERT(audin);
|
|
||||||
WINPR_ASSERT(version);
|
|
||||||
|
|
||||||
context = audin->userdata;
|
|
||||||
WINPR_ASSERT(context);
|
|
||||||
|
|
||||||
if (version->Version == 0)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "Received invalid AUDIO_INPUT version from client");
|
|
||||||
return ERROR_INVALID_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
WLog_DBG(TAG, "AUDIO_INPUT version of client: %u", version->Version);
|
|
||||||
|
|
||||||
formats.NumFormats = context->audin_n_server_formats;
|
|
||||||
formats.SoundFormats = context->audin_server_formats;
|
|
||||||
|
|
||||||
return audin->SendFormats(audin, &formats);
|
|
||||||
}
|
|
||||||
|
|
||||||
static UINT send_open(audin_server_context* audin)
|
|
||||||
{
|
|
||||||
testPeerContext* context;
|
|
||||||
SNDIN_OPEN open = { 0 };
|
|
||||||
|
|
||||||
WINPR_ASSERT(audin);
|
|
||||||
|
|
||||||
context = audin->userdata;
|
|
||||||
WINPR_ASSERT(context);
|
|
||||||
|
|
||||||
open.FramesPerPacket = 441;
|
|
||||||
open.initialFormat = context->audin_client_format_idx;
|
|
||||||
open.captureFormat.wFormatTag = WAVE_FORMAT_PCM;
|
|
||||||
open.captureFormat.nChannels = 2;
|
|
||||||
open.captureFormat.nSamplesPerSec = 44100;
|
|
||||||
open.captureFormat.nAvgBytesPerSec = 44100 * 2 * 2;
|
|
||||||
open.captureFormat.nBlockAlign = 4;
|
|
||||||
open.captureFormat.wBitsPerSample = 16;
|
|
||||||
|
|
||||||
return audin->SendOpen(audin, &open);
|
|
||||||
}
|
|
||||||
|
|
||||||
static UINT sf_peer_audin_receive_formats(audin_server_context* audin, const SNDIN_FORMATS* formats)
|
|
||||||
{
|
|
||||||
testPeerContext* context;
|
|
||||||
|
|
||||||
WINPR_ASSERT(audin);
|
|
||||||
WINPR_ASSERT(formats);
|
|
||||||
|
|
||||||
context = audin->userdata;
|
|
||||||
WINPR_ASSERT(context);
|
|
||||||
|
|
||||||
if (context->audin_negotiated_format)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "Received client formats, but negotiation was already done");
|
|
||||||
return ERROR_INVALID_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < context->audin_n_server_formats; ++i)
|
|
||||||
{
|
|
||||||
for (UINT32 j = 0; j < formats->NumFormats; ++j)
|
|
||||||
{
|
|
||||||
if (audio_format_compatible(&context->audin_server_formats[i],
|
|
||||||
&formats->SoundFormats[j]))
|
|
||||||
{
|
|
||||||
context->audin_negotiated_format = &context->audin_server_formats[i];
|
|
||||||
context->audin_client_format_idx = i;
|
|
||||||
return send_open(audin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WLog_ERR(TAG, "Could not agree on a audio format with the server");
|
|
||||||
|
|
||||||
return ERROR_INVALID_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
static UINT sf_peer_audin_open_reply(audin_server_context* audin,
|
|
||||||
const SNDIN_OPEN_REPLY* open_reply)
|
|
||||||
{
|
|
||||||
WINPR_ASSERT(audin);
|
|
||||||
WINPR_ASSERT(open_reply);
|
|
||||||
|
|
||||||
/* TODO: Implement failure handling */
|
|
||||||
WLog_DBG(TAG, "Open Reply PDU: Result: %i", open_reply->Result);
|
|
||||||
return CHANNEL_RC_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static UINT sf_peer_audin_incoming_data(audin_server_context* audin,
|
|
||||||
const SNDIN_DATA_INCOMING* data_incoming)
|
|
||||||
{
|
|
||||||
WINPR_ASSERT(audin);
|
|
||||||
WINPR_ASSERT(data_incoming);
|
|
||||||
|
|
||||||
/* TODO: Implement bandwidth measure of clients uplink */
|
|
||||||
WLog_DBG(TAG, "Received Incoming Data PDU");
|
|
||||||
return CHANNEL_RC_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static UINT sf_peer_audin_data(audin_server_context* audin, const SNDIN_DATA* data)
|
static UINT sf_peer_audin_data(audin_server_context* audin, const SNDIN_DATA* data)
|
||||||
{
|
{
|
||||||
@ -148,30 +45,9 @@ static UINT sf_peer_audin_data(audin_server_context* audin, const SNDIN_DATA* da
|
|||||||
return CHANNEL_RC_OK;
|
return CHANNEL_RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static UINT sf_peer_audin_receive_format_change(audin_server_context* audin,
|
|
||||||
const SNDIN_FORMATCHANGE* format_change)
|
|
||||||
{
|
|
||||||
testPeerContext* context;
|
|
||||||
|
|
||||||
WINPR_ASSERT(audin);
|
|
||||||
WINPR_ASSERT(format_change);
|
|
||||||
|
|
||||||
context = audin->userdata;
|
|
||||||
WINPR_ASSERT(context);
|
|
||||||
|
|
||||||
if (format_change->NewFormat != context->audin_client_format_idx)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "NewFormat in FormatChange differs from requested format");
|
|
||||||
return ERROR_INVALID_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
WLog_DBG(TAG, "Received Format Change PDU: %u", format_change->NewFormat);
|
|
||||||
|
|
||||||
return CHANNEL_RC_OK;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void sf_peer_audin_init(testPeerContext* context)
|
BOOL sf_peer_audin_init(testPeerContext* context)
|
||||||
{
|
{
|
||||||
WINPR_ASSERT(context);
|
WINPR_ASSERT(context);
|
||||||
#if defined(CHANNEL_AUDIN_SERVER)
|
#if defined(CHANNEL_AUDIN_SERVER)
|
||||||
@ -181,14 +57,11 @@ void sf_peer_audin_init(testPeerContext* context)
|
|||||||
context->audin->rdpcontext = &context->_p;
|
context->audin->rdpcontext = &context->_p;
|
||||||
context->audin->userdata = context;
|
context->audin->userdata = context;
|
||||||
|
|
||||||
context->audin->ReceiveVersion = sf_peer_audin_receive_version;
|
|
||||||
context->audin->ReceiveFormats = sf_peer_audin_receive_formats;
|
|
||||||
context->audin->OpenReply = sf_peer_audin_open_reply;
|
|
||||||
context->audin->IncomingData = sf_peer_audin_incoming_data;
|
|
||||||
context->audin->Data = sf_peer_audin_data;
|
context->audin->Data = sf_peer_audin_data;
|
||||||
context->audin->ReceiveFormatChange = sf_peer_audin_receive_format_change;
|
|
||||||
|
|
||||||
context->audin_n_server_formats = server_audin_get_formats(&context->audin_server_formats);
|
return audin_server_set_formats(context->audin, -1, NULL);
|
||||||
|
#else
|
||||||
|
return TRUE;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,12 +106,7 @@ void sf_peer_audin_uninit(testPeerContext* context)
|
|||||||
WINPR_ASSERT(context);
|
WINPR_ASSERT(context);
|
||||||
|
|
||||||
#if defined(CHANNEL_AUDIN_SERVER)
|
#if defined(CHANNEL_AUDIN_SERVER)
|
||||||
if (context->audin)
|
audin_server_context_free(context->audin);
|
||||||
{
|
context->audin = NULL;
|
||||||
audio_formats_free(context->audin_server_formats, context->audin_n_server_formats);
|
|
||||||
context->audin_server_formats = NULL;
|
|
||||||
audin_server_context_free(context->audin);
|
|
||||||
context->audin = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
#include "sfreerdp.h"
|
#include "sfreerdp.h"
|
||||||
|
|
||||||
void sf_peer_audin_init(testPeerContext* context);
|
BOOL sf_peer_audin_init(testPeerContext* context);
|
||||||
void sf_peer_audin_uninit(testPeerContext* context);
|
void sf_peer_audin_uninit(testPeerContext* context);
|
||||||
|
|
||||||
BOOL sf_peer_audin_running(testPeerContext* context);
|
BOOL sf_peer_audin_running(testPeerContext* context);
|
||||||
|
@ -60,10 +60,6 @@ struct test_peer_context
|
|||||||
HANDLE debug_channel_thread;
|
HANDLE debug_channel_thread;
|
||||||
#if defined(CHANNEL_AUDIN_SERVER)
|
#if defined(CHANNEL_AUDIN_SERVER)
|
||||||
audin_server_context* audin;
|
audin_server_context* audin;
|
||||||
AUDIO_FORMAT* audin_server_formats;
|
|
||||||
size_t audin_n_server_formats;
|
|
||||||
AUDIO_FORMAT* audin_negotiated_format;
|
|
||||||
UINT32 audin_client_format_idx;
|
|
||||||
#endif
|
#endif
|
||||||
BOOL audin_open;
|
BOOL audin_open;
|
||||||
#if defined(CHANNEL_AINPUT_SERVER)
|
#if defined(CHANNEL_AINPUT_SERVER)
|
||||||
|
@ -33,109 +33,6 @@
|
|||||||
|
|
||||||
#if defined(CHANNEL_AUDIN_SERVER)
|
#if defined(CHANNEL_AUDIN_SERVER)
|
||||||
|
|
||||||
static UINT AudinServerReceiveVersion(audin_server_context* audin, const SNDIN_VERSION* version)
|
|
||||||
{
|
|
||||||
rdpShadowClient* client;
|
|
||||||
SNDIN_FORMATS formats = { 0 };
|
|
||||||
|
|
||||||
WINPR_ASSERT(audin);
|
|
||||||
WINPR_ASSERT(version);
|
|
||||||
|
|
||||||
client = audin->userdata;
|
|
||||||
WINPR_ASSERT(client);
|
|
||||||
|
|
||||||
if (version->Version == 0)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "Received invalid AUDIO_INPUT version from client");
|
|
||||||
return ERROR_INVALID_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
WLog_DBG(TAG, "AUDIO_INPUT version of client: %u", version->Version);
|
|
||||||
|
|
||||||
formats.NumFormats = client->audin_n_server_formats;
|
|
||||||
formats.SoundFormats = client->audin_server_formats;
|
|
||||||
|
|
||||||
return audin->SendFormats(audin, &formats);
|
|
||||||
}
|
|
||||||
|
|
||||||
static UINT send_open(audin_server_context* audin)
|
|
||||||
{
|
|
||||||
rdpShadowClient* client = audin->userdata;
|
|
||||||
SNDIN_OPEN open = { 0 };
|
|
||||||
|
|
||||||
WINPR_ASSERT(audin);
|
|
||||||
|
|
||||||
client = audin->userdata;
|
|
||||||
WINPR_ASSERT(client);
|
|
||||||
|
|
||||||
open.FramesPerPacket = 441;
|
|
||||||
open.initialFormat = client->audin_client_format_idx;
|
|
||||||
open.captureFormat.wFormatTag = WAVE_FORMAT_PCM;
|
|
||||||
open.captureFormat.nChannels = 2;
|
|
||||||
open.captureFormat.nSamplesPerSec = 44100;
|
|
||||||
open.captureFormat.nAvgBytesPerSec = 44100 * 2 * 2;
|
|
||||||
open.captureFormat.nBlockAlign = 4;
|
|
||||||
open.captureFormat.wBitsPerSample = 16;
|
|
||||||
|
|
||||||
return audin->SendOpen(audin, &open);
|
|
||||||
}
|
|
||||||
|
|
||||||
static UINT AudinServerReceiveFormats(audin_server_context* audin, const SNDIN_FORMATS* formats)
|
|
||||||
{
|
|
||||||
rdpShadowClient* client;
|
|
||||||
|
|
||||||
WINPR_ASSERT(audin);
|
|
||||||
WINPR_ASSERT(formats);
|
|
||||||
|
|
||||||
client = audin->userdata;
|
|
||||||
WINPR_ASSERT(client);
|
|
||||||
|
|
||||||
if (client->audin_negotiated_format)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "Received client formats, but negotiation was already done");
|
|
||||||
return ERROR_INVALID_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < client->audin_n_server_formats; ++i)
|
|
||||||
{
|
|
||||||
for (UINT32 j = 0; j < formats->NumFormats; ++j)
|
|
||||||
{
|
|
||||||
if (audio_format_compatible(&client->audin_server_formats[i],
|
|
||||||
&formats->SoundFormats[j]))
|
|
||||||
{
|
|
||||||
client->audin_negotiated_format = &client->audin_server_formats[i];
|
|
||||||
client->audin_client_format_idx = i;
|
|
||||||
return send_open(audin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WLog_ERR(TAG, "Could not agree on a audio format with the server");
|
|
||||||
|
|
||||||
return ERROR_INVALID_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
static UINT AudinServerOpenReply(audin_server_context* audin, const SNDIN_OPEN_REPLY* open_reply)
|
|
||||||
{
|
|
||||||
WINPR_ASSERT(audin);
|
|
||||||
WINPR_ASSERT(open_reply);
|
|
||||||
|
|
||||||
/* TODO: Implement failure handling */
|
|
||||||
WLog_DBG(TAG, "Open Reply PDU: Result: %i", open_reply->Result);
|
|
||||||
return CHANNEL_RC_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static UINT AudinServerIncomingData(audin_server_context* audin,
|
|
||||||
const SNDIN_DATA_INCOMING* data_incoming)
|
|
||||||
{
|
|
||||||
WINPR_ASSERT(audin);
|
|
||||||
WINPR_ASSERT(data_incoming);
|
|
||||||
|
|
||||||
/* TODO: Implement bandwidth measure of clients uplink */
|
|
||||||
WLog_DBG(TAG, "Received Incoming Data PDU");
|
|
||||||
return CHANNEL_RC_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static UINT AudinServerData(audin_server_context* audin, const SNDIN_DATA* data)
|
static UINT AudinServerData(audin_server_context* audin, const SNDIN_DATA* data)
|
||||||
{
|
{
|
||||||
rdpShadowClient* client;
|
rdpShadowClient* client;
|
||||||
@ -154,33 +51,12 @@ static UINT AudinServerData(audin_server_context* audin, const SNDIN_DATA* data)
|
|||||||
return CHANNEL_RC_OK;
|
return CHANNEL_RC_OK;
|
||||||
|
|
||||||
if (!IFCALLRESULT(TRUE, subsystem->AudinServerReceiveSamples, subsystem, client,
|
if (!IFCALLRESULT(TRUE, subsystem->AudinServerReceiveSamples, subsystem, client,
|
||||||
client->audin_negotiated_format, data->Data))
|
audin_server_get_negotiated_format(client->audin), data->Data))
|
||||||
return ERROR_INTERNAL_ERROR;
|
return ERROR_INTERNAL_ERROR;
|
||||||
|
|
||||||
return CHANNEL_RC_OK;
|
return CHANNEL_RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static UINT AudinServerReceiveFormatChange(audin_server_context* audin,
|
|
||||||
const SNDIN_FORMATCHANGE* format_change)
|
|
||||||
{
|
|
||||||
rdpShadowClient* client;
|
|
||||||
|
|
||||||
WINPR_ASSERT(audin);
|
|
||||||
WINPR_ASSERT(format_change);
|
|
||||||
|
|
||||||
client = audin->userdata;
|
|
||||||
WINPR_ASSERT(client);
|
|
||||||
|
|
||||||
if (format_change->NewFormat != client->audin_client_format_idx)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "NewFormat in FormatChange differs from requested format");
|
|
||||||
return ERROR_INVALID_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
WLog_DBG(TAG, "Received Format Change PDU: %u", format_change->NewFormat);
|
|
||||||
|
|
||||||
return CHANNEL_RC_OK;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
BOOL shadow_client_audin_init(rdpShadowClient* client)
|
BOOL shadow_client_audin_init(rdpShadowClient* client)
|
||||||
@ -188,48 +64,27 @@ BOOL shadow_client_audin_init(rdpShadowClient* client)
|
|||||||
WINPR_ASSERT(client);
|
WINPR_ASSERT(client);
|
||||||
|
|
||||||
#if defined(CHANNEL_AUDIN_SERVER)
|
#if defined(CHANNEL_AUDIN_SERVER)
|
||||||
audin_server_context* audin;
|
audin_server_context* audin = client->audin = audin_server_context_new(client->vcm);
|
||||||
audin = client->audin = audin_server_context_new(client->vcm);
|
|
||||||
|
|
||||||
if (!audin)
|
if (!audin)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
audin->userdata = client;
|
audin->userdata = client;
|
||||||
|
|
||||||
audin->ReceiveVersion = AudinServerReceiveVersion;
|
|
||||||
audin->ReceiveFormats = AudinServerReceiveFormats;
|
|
||||||
audin->OpenReply = AudinServerOpenReply;
|
|
||||||
audin->IncomingData = AudinServerIncomingData;
|
|
||||||
audin->Data = AudinServerData;
|
audin->Data = AudinServerData;
|
||||||
audin->ReceiveFormatChange = AudinServerReceiveFormatChange;
|
|
||||||
|
|
||||||
if (client->subsystem->audinFormats)
|
if (client->subsystem->audinFormats)
|
||||||
{
|
{
|
||||||
size_t x;
|
if (!audin_server_set_formats(client->audin, client->subsystem->nAudinFormats,
|
||||||
client->audin_server_formats = audio_formats_new(client->subsystem->nAudinFormats);
|
client->subsystem->audinFormats))
|
||||||
|
|
||||||
if (!client->audin_server_formats)
|
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
for (x = 0; x < client->subsystem->nAudinFormats; x++)
|
|
||||||
{
|
|
||||||
if (!audio_format_copy(&client->subsystem->audinFormats[x],
|
|
||||||
&client->audin_server_formats[x]))
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
client->audin_n_server_formats = client->subsystem->nAudinFormats;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
client->audin_n_server_formats = server_audin_get_formats(&client->audin_server_formats);
|
if (!audin_server_set_formats(client->audin, -1, NULL))
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (client->audin_n_server_formats < 1)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
client->audin_negotiated_format = NULL;
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
fail:
|
fail:
|
||||||
audin_server_context_free(audin);
|
audin_server_context_free(audin);
|
||||||
@ -243,12 +98,7 @@ void shadow_client_audin_uninit(rdpShadowClient* client)
|
|||||||
WINPR_ASSERT(client);
|
WINPR_ASSERT(client);
|
||||||
|
|
||||||
#if defined(CHANNEL_AUDIN_SERVER)
|
#if defined(CHANNEL_AUDIN_SERVER)
|
||||||
if (client->audin)
|
audin_server_context_free(client->audin);
|
||||||
{
|
client->audin = NULL;
|
||||||
audio_formats_free(client->audin_server_formats, client->audin_n_server_formats);
|
|
||||||
client->audin_server_formats = NULL;
|
|
||||||
audin_server_context_free(client->audin);
|
|
||||||
client->audin = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user