server: Add channel handling for camera device and enumerator channel

This commit is contained in:
Pascal Nowack 2022-06-15 05:20:17 +02:00 committed by akallabeth
parent 5637aeed91
commit 78fc60802c
10 changed files with 2411 additions and 0 deletions

View File

@ -0,0 +1,23 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2022 Pascal Nowack <Pascal.Nowack@gmx.de>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
define_channel("camera-device")
define_channel("camera-device-enumerator")
if(WITH_SERVER_CHANNELS)
add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME})
endif()

View File

@ -0,0 +1,17 @@
set(OPTION_DEFAULT OFF)
set(OPTION_CLIENT_DEFAULT OFF)
set(OPTION_SERVER_DEFAULT ON)
define_channel_options(NAME "camera-device" TYPE "dynamic"
DESCRIPTION "Video Capture Virtual Channel Extension"
SPECIFICATIONS "[MS-RDPECAM]"
DEFAULT ${OPTION_DEFAULT})
define_channel_options(NAME "camera-device-enumerator" TYPE "dynamic"
DESCRIPTION "Video Capture Virtual Channel Extension"
SPECIFICATIONS "[MS-RDPECAM]"
DEFAULT ${OPTION_DEFAULT})
define_channel_server_options(${OPTION_SERVER_DEFAULT})

View File

@ -0,0 +1,28 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2022 Pascal Nowack <Pascal.Nowack@gmx.de>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
define_channel_server("camera-device")
define_channel_server("camera-device-enumerator")
set(${MODULE_PREFIX}_SRCS
camera_device_enumerator_main.c
camera_device_main.c)
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "DVCPluginEntry")
target_link_libraries(${MODULE_NAME} freerdp)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server")

View File

@ -0,0 +1,610 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Video Capture Virtual Channel Extension
*
* Copyright 2022 Pascal Nowack <Pascal.Nowack@gmx.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <freerdp/config.h>
#include <freerdp/channels/log.h>
#include <freerdp/server/camera-device-enumerator.h>
#define TAG CHANNELS_TAG("cam-dev-enum.server")
typedef enum
{
ENUMERATOR_INITIAL,
ENUMERATOR_OPENED,
} eEnumeratorChannelState;
typedef struct
{
CamDevEnumServerContext context;
HANDLE stopEvent;
HANDLE thread;
void* enumerator_channel;
DWORD SessionId;
BOOL isOpened;
BOOL externalThread;
/* Channel state */
eEnumeratorChannelState state;
wStream* buffer;
} enumerator_server;
static UINT enumerator_server_initialize(CamDevEnumServerContext* context, BOOL externalThread)
{
UINT error = CHANNEL_RC_OK;
enumerator_server* enumerator = (enumerator_server*)context;
WINPR_ASSERT(enumerator);
if (enumerator->isOpened)
{
WLog_WARN(TAG, "Application error: Camera Device Enumerator channel already initialized, "
"calling in this state is not possible!");
return ERROR_INVALID_STATE;
}
enumerator->externalThread = externalThread;
return error;
}
static UINT enumerator_server_open_channel(enumerator_server* enumerator)
{
CamDevEnumServerContext* context = &enumerator->context;
DWORD Error = ERROR_SUCCESS;
HANDLE hEvent;
DWORD BytesReturned = 0;
PULONG pSessionId = NULL;
UINT32 channelId;
BOOL status = TRUE;
WINPR_ASSERT(enumerator);
if (WTSQuerySessionInformationA(enumerator->context.vcm, WTS_CURRENT_SESSION, WTSSessionId,
(LPSTR*)&pSessionId, &BytesReturned) == FALSE)
{
WLog_ERR(TAG, "WTSQuerySessionInformationA failed!");
return ERROR_INTERNAL_ERROR;
}
enumerator->SessionId = (DWORD)*pSessionId;
WTSFreeMemory(pSessionId);
hEvent = WTSVirtualChannelManagerGetEventHandle(enumerator->context.vcm);
if (WaitForSingleObject(hEvent, 1000) == WAIT_FAILED)
{
Error = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", Error);
return Error;
}
enumerator->enumerator_channel = WTSVirtualChannelOpenEx(
enumerator->SessionId, CAM_DEVICE_ENUMERATOR_DVC_CHANNEL_NAME, WTS_CHANNEL_OPTION_DYNAMIC);
if (!enumerator->enumerator_channel)
{
Error = GetLastError();
WLog_ERR(TAG, "WTSVirtualChannelOpenEx failed with error %" PRIu32 "!", Error);
return Error;
}
channelId = WTSChannelGetIdByHandle(enumerator->enumerator_channel);
IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
if (!status)
{
WLog_ERR(TAG, "context->ChannelIdAssigned failed!");
return ERROR_INTERNAL_ERROR;
}
return Error;
}
static UINT enumerator_server_handle_select_version_request(CamDevEnumServerContext* context,
wStream* s,
const CAM_SHARED_MSG_HEADER* header)
{
CAM_SELECT_VERSION_REQUEST pdu = {};
UINT error = CHANNEL_RC_OK;
WINPR_ASSERT(context);
WINPR_ASSERT(header);
pdu.Header = *header;
IFCALLRET(context->SelectVersionRequest, error, context, &pdu);
if (error)
WLog_ERR(TAG, "context->SelectVersionRequest failed with error %" PRIu32 "", error);
return error;
}
static UINT enumerator_server_recv_device_added_notification(CamDevEnumServerContext* context,
wStream* s,
const CAM_SHARED_MSG_HEADER* header)
{
CAM_DEVICE_ADDED_NOTIFICATION pdu;
UINT error = CHANNEL_RC_OK;
size_t remaining_length;
WCHAR* channel_name_start;
char* tmp;
size_t i;
WINPR_ASSERT(context);
WINPR_ASSERT(header);
pdu.Header = *header;
/*
* RequiredLength 4:
*
* Nullterminator DeviceName (2),
* VirtualChannelName (>= 1),
* Nullterminator VirtualChannelName (1)
*/
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
return ERROR_NO_DATA;
pdu.DeviceName = (WCHAR*)Stream_Pointer(s);
remaining_length = Stream_GetRemainingLength(s);
channel_name_start = (WCHAR*)Stream_Pointer(s);
/* Search for null terminator of DeviceName */
for (i = 0; i < remaining_length; i += sizeof(WCHAR), ++channel_name_start)
{
if (*channel_name_start == L'\0')
break;
}
if (*channel_name_start != L'\0')
{
WLog_ERR(TAG, "enumerator_server_recv_device_added_notification: Invalid DeviceName!");
return ERROR_INVALID_DATA;
}
pdu.VirtualChannelName = (char*)++channel_name_start;
++i;
if (i >= remaining_length || *pdu.VirtualChannelName == '\0')
{
WLog_ERR(TAG,
"enumerator_server_recv_device_added_notification: Invalid VirtualChannelName!");
return ERROR_INVALID_DATA;
}
tmp = pdu.VirtualChannelName;
for (; i < remaining_length; ++i, ++tmp)
{
if (*tmp == '\0')
break;
}
if (*tmp != '\0')
{
WLog_ERR(TAG,
"enumerator_server_recv_device_added_notification: Invalid VirtualChannelName!");
return ERROR_INVALID_DATA;
}
IFCALLRET(context->DeviceAddedNotification, error, context, &pdu);
if (error)
WLog_ERR(TAG, "context->DeviceAddedNotification failed with error %" PRIu32 "", error);
return error;
}
static UINT enumerator_server_recv_device_removed_notification(CamDevEnumServerContext* context,
wStream* s,
const CAM_SHARED_MSG_HEADER* header)
{
CAM_DEVICE_REMOVED_NOTIFICATION pdu;
UINT error = CHANNEL_RC_OK;
size_t remaining_length;
char* tmp;
size_t i;
WINPR_ASSERT(context);
WINPR_ASSERT(header);
pdu.Header = *header;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
return ERROR_NO_DATA;
pdu.VirtualChannelName = (char*)Stream_Pointer(s);
remaining_length = Stream_GetRemainingLength(s);
tmp = (char*)(Stream_Pointer(s) + 1);
for (i = 1; i < remaining_length; ++i, ++tmp)
{
if (*tmp == '\0')
break;
}
if (*tmp != '\0')
{
WLog_ERR(TAG,
"enumerator_server_recv_device_removed_notification: Invalid VirtualChannelName!");
return ERROR_INVALID_DATA;
}
IFCALLRET(context->DeviceRemovedNotification, error, context, &pdu);
if (error)
WLog_ERR(TAG, "context->DeviceRemovedNotification failed with error %" PRIu32 "", error);
return error;
}
static UINT enumerator_process_message(enumerator_server* enumerator)
{
BOOL rc;
UINT error = ERROR_INTERNAL_ERROR;
ULONG BytesReturned;
CAM_SHARED_MSG_HEADER header = {};
wStream* s;
WINPR_ASSERT(enumerator);
WINPR_ASSERT(enumerator->enumerator_channel);
s = enumerator->buffer;
WINPR_ASSERT(s);
Stream_SetPosition(s, 0);
rc = WTSVirtualChannelRead(enumerator->enumerator_channel, 0, NULL, 0, &BytesReturned);
if (!rc)
goto out;
if (BytesReturned < 1)
{
error = CHANNEL_RC_OK;
goto out;
}
if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
{
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
error = CHANNEL_RC_NO_MEMORY;
goto out;
}
if (WTSVirtualChannelRead(enumerator->enumerator_channel, 0, (PCHAR)Stream_Buffer(s),
(ULONG)Stream_Capacity(s), &BytesReturned) == FALSE)
{
WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
goto out;
}
if (!Stream_CheckAndLogRequiredLength(TAG, s, CAM_HEADER_SIZE))
return ERROR_NO_DATA;
Stream_SetLength(s, BytesReturned);
Stream_Read_UINT8(s, header.Version);
Stream_Read_UINT8(s, header.MessageId);
switch (header.MessageId)
{
case CAM_MSG_ID_SelectVersionRequest:
error =
enumerator_server_handle_select_version_request(&enumerator->context, s, &header);
break;
case CAM_MSG_ID_DeviceAddedNotification:
error =
enumerator_server_recv_device_added_notification(&enumerator->context, s, &header);
break;
case CAM_MSG_ID_DeviceRemovedNotification:
error = enumerator_server_recv_device_removed_notification(&enumerator->context, s,
&header);
break;
default:
WLog_ERR(TAG, "enumerator_process_message: unknown or invalid MessageId %" PRIu8 "",
header.MessageId);
break;
}
out:
if (error)
WLog_ERR(TAG, "Response failed with error %" PRIu32 "!", error);
return error;
}
static UINT enumerator_server_context_poll_int(CamDevEnumServerContext* context)
{
enumerator_server* enumerator = (enumerator_server*)context;
UINT error = ERROR_INTERNAL_ERROR;
WINPR_ASSERT(enumerator);
switch (enumerator->state)
{
case ENUMERATOR_INITIAL:
error = enumerator_server_open_channel(enumerator);
if (error)
WLog_ERR(TAG, "enumerator_server_open_channel failed with error %" PRIu32 "!",
error);
else
enumerator->state = ENUMERATOR_OPENED;
break;
case ENUMERATOR_OPENED:
error = enumerator_process_message(enumerator);
break;
}
return error;
}
static HANDLE enumerator_server_get_channel_handle(enumerator_server* enumerator)
{
void* buffer = NULL;
DWORD BytesReturned = 0;
HANDLE ChannelEvent = NULL;
WINPR_ASSERT(enumerator);
if (WTSVirtualChannelQuery(enumerator->enumerator_channel, WTSVirtualEventHandle, &buffer,
&BytesReturned) == TRUE)
{
if (BytesReturned == sizeof(HANDLE))
CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE));
WTSFreeMemory(buffer);
}
return ChannelEvent;
}
static DWORD WINAPI enumerator_server_thread_func(LPVOID arg)
{
DWORD nCount;
HANDLE events[2] = { 0 };
enumerator_server* enumerator = (enumerator_server*)arg;
UINT error = CHANNEL_RC_OK;
DWORD status;
WINPR_ASSERT(enumerator);
nCount = 0;
events[nCount++] = enumerator->stopEvent;
while ((error == CHANNEL_RC_OK) && (WaitForSingleObject(events[0], 0) != WAIT_OBJECT_0))
{
switch (enumerator->state)
{
case ENUMERATOR_INITIAL:
error = enumerator_server_context_poll_int(&enumerator->context);
if (error == CHANNEL_RC_OK)
{
events[1] = enumerator_server_get_channel_handle(enumerator);
nCount = 2;
}
break;
case ENUMERATOR_OPENED:
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
switch (status)
{
case WAIT_OBJECT_0:
break;
case WAIT_OBJECT_0 + 1:
case WAIT_TIMEOUT:
error = enumerator_server_context_poll_int(&enumerator->context);
break;
case WAIT_FAILED:
default:
error = ERROR_INTERNAL_ERROR;
break;
}
break;
}
}
WTSVirtualChannelClose(enumerator->enumerator_channel);
enumerator->enumerator_channel = NULL;
if (error && enumerator->context.rdpcontext)
setChannelError(enumerator->context.rdpcontext, error,
"enumerator_server_thread_func reported an error");
ExitThread(error);
return error;
}
static UINT enumerator_server_open(CamDevEnumServerContext* context)
{
enumerator_server* enumerator = (enumerator_server*)context;
WINPR_ASSERT(enumerator);
if (!enumerator->externalThread && (enumerator->thread == NULL))
{
enumerator->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!enumerator->stopEvent)
{
WLog_ERR(TAG, "CreateEvent failed!");
return ERROR_INTERNAL_ERROR;
}
enumerator->thread =
CreateThread(NULL, 0, enumerator_server_thread_func, enumerator, 0, NULL);
if (!enumerator->thread)
{
WLog_ERR(TAG, "CreateThread failed!");
CloseHandle(enumerator->stopEvent);
enumerator->stopEvent = NULL;
return ERROR_INTERNAL_ERROR;
}
}
enumerator->isOpened = TRUE;
return CHANNEL_RC_OK;
}
static UINT enumerator_server_close(CamDevEnumServerContext* context)
{
UINT error = CHANNEL_RC_OK;
enumerator_server* enumerator = (enumerator_server*)context;
WINPR_ASSERT(enumerator);
if (!enumerator->externalThread && enumerator->thread)
{
SetEvent(enumerator->stopEvent);
if (WaitForSingleObject(enumerator->thread, INFINITE) == WAIT_FAILED)
{
error = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
return error;
}
CloseHandle(enumerator->thread);
CloseHandle(enumerator->stopEvent);
enumerator->thread = NULL;
enumerator->stopEvent = NULL;
}
if (enumerator->externalThread)
{
if (enumerator->state != ENUMERATOR_INITIAL)
{
WTSVirtualChannelClose(enumerator->enumerator_channel);
enumerator->enumerator_channel = NULL;
enumerator->state = ENUMERATOR_INITIAL;
}
}
enumerator->isOpened = FALSE;
return error;
}
static UINT enumerator_server_context_poll(CamDevEnumServerContext* context)
{
enumerator_server* enumerator = (enumerator_server*)context;
WINPR_ASSERT(enumerator);
if (!enumerator->externalThread)
return ERROR_INTERNAL_ERROR;
return enumerator_server_context_poll_int(context);
}
static BOOL enumerator_server_context_handle(CamDevEnumServerContext* context, HANDLE* handle)
{
enumerator_server* enumerator = (enumerator_server*)context;
WINPR_ASSERT(enumerator);
WINPR_ASSERT(handle);
if (!enumerator->externalThread)
return FALSE;
if (enumerator->state == ENUMERATOR_INITIAL)
return FALSE;
*handle = enumerator_server_get_channel_handle(enumerator);
return TRUE;
}
static UINT enumerator_server_packet_send(CamDevEnumServerContext* context, wStream* s)
{
enumerator_server* enumerator = (enumerator_server*)context;
UINT error = CHANNEL_RC_OK;
ULONG written;
if (!WTSVirtualChannelWrite(enumerator->enumerator_channel, (PCHAR)Stream_Buffer(s),
Stream_GetPosition(s), &written))
{
WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
error = ERROR_INTERNAL_ERROR;
goto out;
}
if (written < Stream_GetPosition(s))
{
WLog_WARN(TAG, "Unexpected bytes written: %" PRIu32 "/%" PRIuz "", written,
Stream_GetPosition(s));
}
out:
Stream_Free(s, TRUE);
return error;
}
static UINT enumerator_send_select_version_response_pdu(
CamDevEnumServerContext* context, const CAM_SELECT_VERSION_RESPONSE* selectVersionResponse)
{
wStream* s;
s = Stream_New(NULL, CAM_HEADER_SIZE);
if (!s)
{
WLog_ERR(TAG, "Stream_New failed!");
return ERROR_NOT_ENOUGH_MEMORY;
}
Stream_Write_UINT8(s, selectVersionResponse->Header.Version);
Stream_Write_UINT8(s, selectVersionResponse->Header.MessageId);
return enumerator_server_packet_send(context, s);
}
CamDevEnumServerContext* cam_dev_enum_server_context_new(HANDLE vcm)
{
enumerator_server* enumerator = (enumerator_server*)calloc(1, sizeof(enumerator_server));
if (!enumerator)
return NULL;
enumerator->context.vcm = vcm;
enumerator->context.Initialize = enumerator_server_initialize;
enumerator->context.Open = enumerator_server_open;
enumerator->context.Close = enumerator_server_close;
enumerator->context.Poll = enumerator_server_context_poll;
enumerator->context.ChannelHandle = enumerator_server_context_handle;
enumerator->context.SelectVersionResponse = enumerator_send_select_version_response_pdu;
enumerator->buffer = Stream_New(NULL, 4096);
if (!enumerator->buffer)
goto fail;
return &enumerator->context;
fail:
cam_dev_enum_server_context_free(&enumerator->context);
return NULL;
}
void cam_dev_enum_server_context_free(CamDevEnumServerContext* context)
{
enumerator_server* enumerator = (enumerator_server*)context;
if (enumerator)
{
enumerator_server_close(context);
Stream_Free(enumerator->buffer, TRUE);
}
free(enumerator);
}

View File

@ -0,0 +1,972 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Video Capture Virtual Channel Extension
*
* Copyright 2022 Pascal Nowack <Pascal.Nowack@gmx.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <freerdp/config.h>
#include <freerdp/channels/log.h>
#include <freerdp/server/camera-device.h>
#define TAG CHANNELS_TAG("camera-device.server")
typedef enum
{
CAMERA_DEVICE_INITIAL,
CAMERA_DEVICE_OPENED,
} eCameraDeviceChannelState;
typedef struct
{
CameraDeviceServerContext context;
HANDLE stopEvent;
HANDLE thread;
void* device_channel;
DWORD SessionId;
BOOL isOpened;
BOOL externalThread;
/* Channel state */
eCameraDeviceChannelState state;
wStream* buffer;
} device_server;
static UINT device_server_initialize(CameraDeviceServerContext* context, BOOL externalThread)
{
UINT error = CHANNEL_RC_OK;
device_server* device = (device_server*)context;
WINPR_ASSERT(device);
if (device->isOpened)
{
WLog_WARN(TAG, "Application error: Camera channel already initialized, "
"calling in this state is not possible!");
return ERROR_INVALID_STATE;
}
device->externalThread = externalThread;
return error;
}
static UINT device_server_open_channel(device_server* device)
{
CameraDeviceServerContext* context = &device->context;
DWORD Error = ERROR_SUCCESS;
HANDLE hEvent;
DWORD BytesReturned = 0;
PULONG pSessionId = NULL;
UINT32 channelId;
BOOL status = TRUE;
WINPR_ASSERT(device);
if (WTSQuerySessionInformationA(device->context.vcm, WTS_CURRENT_SESSION, WTSSessionId,
(LPSTR*)&pSessionId, &BytesReturned) == FALSE)
{
WLog_ERR(TAG, "WTSQuerySessionInformationA failed!");
return ERROR_INTERNAL_ERROR;
}
device->SessionId = (DWORD)*pSessionId;
WTSFreeMemory(pSessionId);
hEvent = WTSVirtualChannelManagerGetEventHandle(device->context.vcm);
if (WaitForSingleObject(hEvent, 1000) == WAIT_FAILED)
{
Error = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", Error);
return Error;
}
device->device_channel = WTSVirtualChannelOpenEx(device->SessionId, context->virtualChannelName,
WTS_CHANNEL_OPTION_DYNAMIC);
if (!device->device_channel)
{
Error = GetLastError();
WLog_ERR(TAG, "WTSVirtualChannelOpenEx failed with error %" PRIu32 "!", Error);
return Error;
}
channelId = WTSChannelGetIdByHandle(device->device_channel);
IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
if (!status)
{
WLog_ERR(TAG, "context->ChannelIdAssigned failed!");
return ERROR_INTERNAL_ERROR;
}
return Error;
}
static UINT device_server_handle_success_response(CameraDeviceServerContext* context, wStream* s,
const CAM_SHARED_MSG_HEADER* header)
{
CAM_SUCCESS_RESPONSE pdu = {};
UINT error = CHANNEL_RC_OK;
WINPR_ASSERT(context);
WINPR_ASSERT(header);
pdu.Header = *header;
IFCALLRET(context->SuccessResponse, error, context, &pdu);
if (error)
WLog_ERR(TAG, "context->SuccessResponse failed with error %" PRIu32 "", error);
return error;
}
static UINT device_server_recv_error_response(CameraDeviceServerContext* context, wStream* s,
const CAM_SHARED_MSG_HEADER* header)
{
CAM_ERROR_RESPONSE pdu = {};
UINT error = CHANNEL_RC_OK;
WINPR_ASSERT(context);
WINPR_ASSERT(header);
pdu.Header = *header;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
return ERROR_NO_DATA;
Stream_Read_UINT32(s, pdu.ErrorCode);
IFCALLRET(context->ErrorResponse, error, context, &pdu);
if (error)
WLog_ERR(TAG, "context->ErrorResponse failed with error %" PRIu32 "", error);
return error;
}
static UINT device_server_recv_stream_list_response(CameraDeviceServerContext* context, wStream* s,
const CAM_SHARED_MSG_HEADER* header)
{
CAM_STREAM_LIST_RESPONSE pdu = {};
UINT error = CHANNEL_RC_OK;
BYTE i;
WINPR_ASSERT(context);
WINPR_ASSERT(header);
pdu.Header = *header;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 5))
return ERROR_NO_DATA;
pdu.N_Descriptions = MIN(Stream_GetRemainingLength(s) / 5, 255);
for (i = 0; i < pdu.N_Descriptions; ++i)
{
CAM_STREAM_DESCRIPTION* StreamDescription = &pdu.StreamDescriptions[i];
Stream_Read_UINT16(s, StreamDescription->FrameSourceTypes);
Stream_Read_UINT8(s, StreamDescription->StreamCategory);
Stream_Read_UINT8(s, StreamDescription->Selected);
Stream_Read_UINT8(s, StreamDescription->CanBeShared);
}
IFCALLRET(context->StreamListResponse, error, context, &pdu);
if (error)
WLog_ERR(TAG, "context->StreamListResponse failed with error %" PRIu32 "", error);
return error;
}
static UINT device_server_recv_media_type_list_response(CameraDeviceServerContext* context,
wStream* s,
const CAM_SHARED_MSG_HEADER* header)
{
CAM_MEDIA_TYPE_LIST_RESPONSE pdu = {};
UINT error = CHANNEL_RC_OK;
BYTE i;
WINPR_ASSERT(context);
WINPR_ASSERT(header);
pdu.Header = *header;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 26))
return ERROR_NO_DATA;
pdu.N_Descriptions = Stream_GetRemainingLength(s) / 26;
pdu.MediaTypeDescriptions = calloc(pdu.N_Descriptions, sizeof(CAM_MEDIA_TYPE_DESCRIPTION));
if (!pdu.MediaTypeDescriptions)
{
WLog_ERR(TAG, "Failed to allocate %zu CAM_MEDIA_TYPE_DESCRIPTION structs",
pdu.N_Descriptions);
return ERROR_NOT_ENOUGH_MEMORY;
}
for (i = 0; i < pdu.N_Descriptions; ++i)
{
CAM_MEDIA_TYPE_DESCRIPTION* MediaTypeDescriptions = &pdu.MediaTypeDescriptions[i];
Stream_Read_UINT8(s, MediaTypeDescriptions->Format);
Stream_Read_UINT32(s, MediaTypeDescriptions->Width);
Stream_Read_UINT32(s, MediaTypeDescriptions->Height);
Stream_Read_UINT32(s, MediaTypeDescriptions->FrameRateNumerator);
Stream_Read_UINT32(s, MediaTypeDescriptions->FrameRateDenominator);
Stream_Read_UINT32(s, MediaTypeDescriptions->PixelAspectRatioNumerator);
Stream_Read_UINT32(s, MediaTypeDescriptions->PixelAspectRatioDenominator);
Stream_Read_UINT8(s, MediaTypeDescriptions->Flags);
}
IFCALLRET(context->MediaTypeListResponse, error, context, &pdu);
if (error)
WLog_ERR(TAG, "context->MediaTypeListResponse failed with error %" PRIu32 "", error);
free(pdu.MediaTypeDescriptions);
return error;
}
static UINT device_server_recv_current_media_type_response(CameraDeviceServerContext* context,
wStream* s,
const CAM_SHARED_MSG_HEADER* header)
{
CAM_CURRENT_MEDIA_TYPE_RESPONSE pdu = {};
UINT error = CHANNEL_RC_OK;
WINPR_ASSERT(context);
WINPR_ASSERT(header);
pdu.Header = *header;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 26))
return ERROR_NO_DATA;
Stream_Read_UINT8(s, pdu.MediaTypeDescription.Format);
Stream_Read_UINT32(s, pdu.MediaTypeDescription.Width);
Stream_Read_UINT32(s, pdu.MediaTypeDescription.Height);
Stream_Read_UINT32(s, pdu.MediaTypeDescription.FrameRateNumerator);
Stream_Read_UINT32(s, pdu.MediaTypeDescription.FrameRateDenominator);
Stream_Read_UINT32(s, pdu.MediaTypeDescription.PixelAspectRatioNumerator);
Stream_Read_UINT32(s, pdu.MediaTypeDescription.PixelAspectRatioDenominator);
Stream_Read_UINT8(s, pdu.MediaTypeDescription.Flags);
IFCALLRET(context->CurrentMediaTypeResponse, error, context, &pdu);
if (error)
WLog_ERR(TAG, "context->CurrentMediaTypeResponse failed with error %" PRIu32 "", error);
return error;
}
static UINT device_server_recv_sample_response(CameraDeviceServerContext* context, wStream* s,
const CAM_SHARED_MSG_HEADER* header)
{
CAM_SAMPLE_RESPONSE pdu = {};
UINT error = CHANNEL_RC_OK;
WINPR_ASSERT(context);
WINPR_ASSERT(header);
pdu.Header = *header;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
return ERROR_NO_DATA;
Stream_Read_UINT8(s, pdu.StreamIndex);
pdu.SampleSize = Stream_GetRemainingLength(s);
pdu.Sample = Stream_Pointer(s);
IFCALLRET(context->SampleResponse, error, context, &pdu);
if (error)
WLog_ERR(TAG, "context->SampleResponse failed with error %" PRIu32 "", error);
return error;
}
static UINT device_server_recv_sample_error_response(CameraDeviceServerContext* context, wStream* s,
const CAM_SHARED_MSG_HEADER* header)
{
CAM_SAMPLE_ERROR_RESPONSE pdu = {};
UINT error = CHANNEL_RC_OK;
WINPR_ASSERT(context);
WINPR_ASSERT(header);
pdu.Header = *header;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 5))
return ERROR_NO_DATA;
Stream_Read_UINT8(s, pdu.StreamIndex);
Stream_Read_UINT32(s, pdu.ErrorCode);
IFCALLRET(context->SampleErrorResponse, error, context, &pdu);
if (error)
WLog_ERR(TAG, "context->SampleErrorResponse failed with error %" PRIu32 "", error);
return error;
}
static UINT device_server_recv_property_list_response(CameraDeviceServerContext* context,
wStream* s,
const CAM_SHARED_MSG_HEADER* header)
{
CAM_PROPERTY_LIST_RESPONSE pdu = {};
UINT error = CHANNEL_RC_OK;
WINPR_ASSERT(context);
WINPR_ASSERT(header);
pdu.Header = *header;
pdu.N_Properties = Stream_GetRemainingLength(s) / 19;
if (pdu.N_Properties > 0)
{
size_t i;
pdu.Properties = calloc(pdu.N_Properties, sizeof(CAM_PROPERTY_DESCRIPTION));
if (!pdu.Properties)
{
WLog_ERR(TAG, "Failed to allocate %zu CAM_PROPERTY_DESCRIPTION structs",
pdu.N_Properties);
return ERROR_NOT_ENOUGH_MEMORY;
}
for (i = 0; i < pdu.N_Properties; ++i)
{
Stream_Read_UINT8(s, pdu.Properties[i].PropertySet);
Stream_Read_UINT8(s, pdu.Properties[i].PropertyId);
Stream_Read_UINT8(s, pdu.Properties[i].Capabilities);
Stream_Read_INT32(s, pdu.Properties[i].MinValue);
Stream_Read_INT32(s, pdu.Properties[i].MaxValue);
Stream_Read_INT32(s, pdu.Properties[i].Step);
Stream_Read_INT32(s, pdu.Properties[i].DefaultValue);
}
}
IFCALLRET(context->PropertyListResponse, error, context, &pdu);
if (error)
WLog_ERR(TAG, "context->PropertyListResponse failed with error %" PRIu32 "", error);
free(pdu.Properties);
return error;
}
static UINT device_server_recv_property_value_response(CameraDeviceServerContext* context,
wStream* s,
const CAM_SHARED_MSG_HEADER* header)
{
CAM_PROPERTY_VALUE_RESPONSE pdu = {};
UINT error = CHANNEL_RC_OK;
WINPR_ASSERT(context);
WINPR_ASSERT(header);
pdu.Header = *header;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 5))
return ERROR_NO_DATA;
Stream_Read_UINT8(s, pdu.PropertyValue.Mode);
Stream_Read_INT32(s, pdu.PropertyValue.Value);
IFCALLRET(context->PropertyValueResponse, error, context, &pdu);
if (error)
WLog_ERR(TAG, "context->PropertyValueResponse failed with error %" PRIu32 "", error);
return error;
}
static UINT device_process_message(device_server* device)
{
BOOL rc;
UINT error = ERROR_INTERNAL_ERROR;
ULONG BytesReturned;
CAM_SHARED_MSG_HEADER header = {};
wStream* s;
WINPR_ASSERT(device);
WINPR_ASSERT(device->device_channel);
s = device->buffer;
WINPR_ASSERT(s);
Stream_SetPosition(s, 0);
rc = WTSVirtualChannelRead(device->device_channel, 0, NULL, 0, &BytesReturned);
if (!rc)
goto out;
if (BytesReturned < 1)
{
error = CHANNEL_RC_OK;
goto out;
}
if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
{
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
error = CHANNEL_RC_NO_MEMORY;
goto out;
}
if (WTSVirtualChannelRead(device->device_channel, 0, (PCHAR)Stream_Buffer(s),
(ULONG)Stream_Capacity(s), &BytesReturned) == FALSE)
{
WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
goto out;
}
if (!Stream_CheckAndLogRequiredLength(TAG, s, CAM_HEADER_SIZE))
return ERROR_NO_DATA;
Stream_SetLength(s, BytesReturned);
Stream_Read_UINT8(s, header.Version);
Stream_Read_UINT8(s, header.MessageId);
switch (header.MessageId)
{
case CAM_MSG_ID_SuccessResponse:
error = device_server_handle_success_response(&device->context, s, &header);
break;
case CAM_MSG_ID_ErrorResponse:
error = device_server_recv_error_response(&device->context, s, &header);
break;
case CAM_MSG_ID_StreamListResponse:
error = device_server_recv_stream_list_response(&device->context, s, &header);
break;
case CAM_MSG_ID_MediaTypeListResponse:
error = device_server_recv_media_type_list_response(&device->context, s, &header);
break;
case CAM_MSG_ID_CurrentMediaTypeResponse:
error = device_server_recv_current_media_type_response(&device->context, s, &header);
break;
case CAM_MSG_ID_SampleResponse:
error = device_server_recv_sample_response(&device->context, s, &header);
break;
case CAM_MSG_ID_SampleErrorResponse:
error = device_server_recv_sample_error_response(&device->context, s, &header);
break;
case CAM_MSG_ID_PropertyListResponse:
error = device_server_recv_property_list_response(&device->context, s, &header);
break;
case CAM_MSG_ID_PropertyValueResponse:
error = device_server_recv_property_value_response(&device->context, s, &header);
break;
default:
WLog_ERR(TAG, "device_process_message: unknown or invalid MessageId %" PRIu8 "",
header.MessageId);
break;
}
out:
if (error)
WLog_ERR(TAG, "Response failed with error %" PRIu32 "!", error);
return error;
}
static UINT device_server_context_poll_int(CameraDeviceServerContext* context)
{
device_server* device = (device_server*)context;
UINT error = ERROR_INTERNAL_ERROR;
WINPR_ASSERT(device);
switch (device->state)
{
case CAMERA_DEVICE_INITIAL:
error = device_server_open_channel(device);
if (error)
WLog_ERR(TAG, "device_server_open_channel failed with error %" PRIu32 "!", error);
else
device->state = CAMERA_DEVICE_OPENED;
break;
case CAMERA_DEVICE_OPENED:
error = device_process_message(device);
break;
}
return error;
}
static HANDLE device_server_get_channel_handle(device_server* device)
{
void* buffer = NULL;
DWORD BytesReturned = 0;
HANDLE ChannelEvent = NULL;
WINPR_ASSERT(device);
if (WTSVirtualChannelQuery(device->device_channel, WTSVirtualEventHandle, &buffer,
&BytesReturned) == TRUE)
{
if (BytesReturned == sizeof(HANDLE))
CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE));
WTSFreeMemory(buffer);
}
return ChannelEvent;
}
static DWORD WINAPI device_server_thread_func(LPVOID arg)
{
DWORD nCount;
HANDLE events[2] = { 0 };
device_server* device = (device_server*)arg;
UINT error = CHANNEL_RC_OK;
DWORD status;
WINPR_ASSERT(device);
nCount = 0;
events[nCount++] = device->stopEvent;
while ((error == CHANNEL_RC_OK) && (WaitForSingleObject(events[0], 0) != WAIT_OBJECT_0))
{
switch (device->state)
{
case CAMERA_DEVICE_INITIAL:
error = device_server_context_poll_int(&device->context);
if (error == CHANNEL_RC_OK)
{
events[1] = device_server_get_channel_handle(device);
nCount = 2;
}
break;
case CAMERA_DEVICE_OPENED:
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
switch (status)
{
case WAIT_OBJECT_0:
break;
case WAIT_OBJECT_0 + 1:
case WAIT_TIMEOUT:
error = device_server_context_poll_int(&device->context);
break;
case WAIT_FAILED:
default:
error = ERROR_INTERNAL_ERROR;
break;
}
break;
}
}
WTSVirtualChannelClose(device->device_channel);
device->device_channel = NULL;
if (error && device->context.rdpcontext)
setChannelError(device->context.rdpcontext, error,
"device_server_thread_func reported an error");
ExitThread(error);
return error;
}
static UINT device_server_open(CameraDeviceServerContext* context)
{
device_server* device = (device_server*)context;
WINPR_ASSERT(device);
if (!device->externalThread && (device->thread == NULL))
{
device->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!device->stopEvent)
{
WLog_ERR(TAG, "CreateEvent failed!");
return ERROR_INTERNAL_ERROR;
}
device->thread = CreateThread(NULL, 0, device_server_thread_func, device, 0, NULL);
if (!device->thread)
{
WLog_ERR(TAG, "CreateThread failed!");
CloseHandle(device->stopEvent);
device->stopEvent = NULL;
return ERROR_INTERNAL_ERROR;
}
}
device->isOpened = TRUE;
return CHANNEL_RC_OK;
}
static UINT device_server_close(CameraDeviceServerContext* context)
{
UINT error = CHANNEL_RC_OK;
device_server* device = (device_server*)context;
WINPR_ASSERT(device);
if (!device->externalThread && device->thread)
{
SetEvent(device->stopEvent);
if (WaitForSingleObject(device->thread, INFINITE) == WAIT_FAILED)
{
error = GetLastError();
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
return error;
}
CloseHandle(device->thread);
CloseHandle(device->stopEvent);
device->thread = NULL;
device->stopEvent = NULL;
}
if (device->externalThread)
{
if (device->state != CAMERA_DEVICE_INITIAL)
{
WTSVirtualChannelClose(device->device_channel);
device->device_channel = NULL;
device->state = CAMERA_DEVICE_INITIAL;
}
}
device->isOpened = FALSE;
return error;
}
static UINT device_server_context_poll(CameraDeviceServerContext* context)
{
device_server* device = (device_server*)context;
WINPR_ASSERT(device);
if (!device->externalThread)
return ERROR_INTERNAL_ERROR;
return device_server_context_poll_int(context);
}
static BOOL device_server_context_handle(CameraDeviceServerContext* context, HANDLE* handle)
{
device_server* device = (device_server*)context;
WINPR_ASSERT(device);
WINPR_ASSERT(handle);
if (!device->externalThread)
return FALSE;
if (device->state == CAMERA_DEVICE_INITIAL)
return FALSE;
*handle = device_server_get_channel_handle(device);
return TRUE;
}
static wStream* device_server_packet_new(size_t size, BYTE version, BYTE messageId)
{
wStream* s;
WINPR_ASSERT(size > 0);
s = Stream_New(NULL, size);
if (!s)
{
WLog_ERR(TAG, "Stream_New failed!");
return NULL;
}
Stream_Write_UINT8(s, version);
Stream_Write_UINT8(s, messageId);
return s;
}
static UINT device_server_packet_send(CameraDeviceServerContext* context, wStream* s)
{
device_server* device = (device_server*)context;
UINT error = CHANNEL_RC_OK;
ULONG written;
WINPR_ASSERT(context);
WINPR_ASSERT(s);
if (!WTSVirtualChannelWrite(device->device_channel, (PCHAR)Stream_Buffer(s),
Stream_GetPosition(s), &written))
{
WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
error = ERROR_INTERNAL_ERROR;
goto out;
}
if (written < Stream_GetPosition(s))
{
WLog_WARN(TAG, "Unexpected bytes written: %" PRIu32 "/%" PRIuz "", written,
Stream_GetPosition(s));
}
out:
Stream_Free(s, TRUE);
return error;
}
static UINT device_server_write_and_send_header(CameraDeviceServerContext* context, BYTE messageId)
{
wStream* s;
WINPR_ASSERT(context);
s = device_server_packet_new(CAM_HEADER_SIZE, context->protocolVersion, messageId);
if (!s)
return ERROR_NOT_ENOUGH_MEMORY;
return device_server_packet_send(context, s);
}
static UINT
device_send_activate_device_request_pdu(CameraDeviceServerContext* context,
const CAM_ACTIVATE_DEVICE_REQUEST* activateDeviceRequest)
{
WINPR_ASSERT(context);
return device_server_write_and_send_header(context, CAM_MSG_ID_ActivateDeviceRequest);
}
static UINT device_send_deactivate_device_request_pdu(
CameraDeviceServerContext* context,
const CAM_DEACTIVATE_DEVICE_REQUEST* deactivateDeviceRequest)
{
WINPR_ASSERT(context);
return device_server_write_and_send_header(context, CAM_MSG_ID_DeactivateDeviceRequest);
}
static UINT device_send_stream_list_request_pdu(CameraDeviceServerContext* context,
const CAM_STREAM_LIST_REQUEST* streamListRequest)
{
WINPR_ASSERT(context);
return device_server_write_and_send_header(context, CAM_MSG_ID_StreamListRequest);
}
static UINT
device_send_media_type_list_request_pdu(CameraDeviceServerContext* context,
const CAM_MEDIA_TYPE_LIST_REQUEST* mediaTypeListRequest)
{
wStream* s;
WINPR_ASSERT(context);
WINPR_ASSERT(mediaTypeListRequest);
s = device_server_packet_new(CAM_HEADER_SIZE + 1, context->protocolVersion,
CAM_MSG_ID_MediaTypeListRequest);
if (!s)
return ERROR_NOT_ENOUGH_MEMORY;
Stream_Write_UINT8(s, mediaTypeListRequest->StreamIndex);
return device_server_packet_send(context, s);
}
static UINT device_send_current_media_type_request_pdu(
CameraDeviceServerContext* context,
const CAM_CURRENT_MEDIA_TYPE_REQUEST* currentMediaTypeRequest)
{
wStream* s;
WINPR_ASSERT(context);
WINPR_ASSERT(currentMediaTypeRequest);
s = device_server_packet_new(CAM_HEADER_SIZE + 1, context->protocolVersion,
CAM_MSG_ID_CurrentMediaTypeRequest);
if (!s)
return ERROR_NOT_ENOUGH_MEMORY;
Stream_Write_UINT8(s, currentMediaTypeRequest->StreamIndex);
return device_server_packet_send(context, s);
}
static UINT
device_send_start_streams_request_pdu(CameraDeviceServerContext* context,
const CAM_START_STREAMS_REQUEST* startStreamsRequest)
{
wStream* s;
size_t i;
WINPR_ASSERT(context);
WINPR_ASSERT(startStreamsRequest);
s = device_server_packet_new(CAM_HEADER_SIZE + startStreamsRequest->N_Infos * 27,
context->protocolVersion, CAM_MSG_ID_StartStreamsRequest);
if (!s)
return ERROR_NOT_ENOUGH_MEMORY;
for (i = 0; i < startStreamsRequest->N_Infos; ++i)
{
const CAM_START_STREAM_INFO* info = &startStreamsRequest->StartStreamsInfo[i];
const CAM_MEDIA_TYPE_DESCRIPTION* description = &info->MediaTypeDescription;
Stream_Write_UINT8(s, info->StreamIndex);
Stream_Write_UINT8(s, description->Format);
Stream_Write_UINT32(s, description->Width);
Stream_Write_UINT32(s, description->Height);
Stream_Write_UINT32(s, description->FrameRateNumerator);
Stream_Write_UINT32(s, description->FrameRateDenominator);
Stream_Write_UINT32(s, description->PixelAspectRatioNumerator);
Stream_Write_UINT32(s, description->PixelAspectRatioDenominator);
Stream_Write_UINT8(s, description->Flags);
}
return device_server_packet_send(context, s);
}
static UINT device_send_stop_streams_request_pdu(CameraDeviceServerContext* context,
const CAM_STOP_STREAMS_REQUEST* stopStreamsRequest)
{
WINPR_ASSERT(context);
return device_server_write_and_send_header(context, CAM_MSG_ID_StopStreamsRequest);
}
static UINT device_send_sample_request_pdu(CameraDeviceServerContext* context,
const CAM_SAMPLE_REQUEST* sampleRequest)
{
wStream* s;
WINPR_ASSERT(context);
WINPR_ASSERT(sampleRequest);
s = device_server_packet_new(CAM_HEADER_SIZE + 1, context->protocolVersion,
CAM_MSG_ID_SampleRequest);
if (!s)
return ERROR_NOT_ENOUGH_MEMORY;
Stream_Write_UINT8(s, sampleRequest->StreamIndex);
return device_server_packet_send(context, s);
}
static UINT
device_send_property_list_request_pdu(CameraDeviceServerContext* context,
const CAM_PROPERTY_LIST_REQUEST* propertyListRequest)
{
WINPR_ASSERT(context);
return device_server_write_and_send_header(context, CAM_MSG_ID_PropertyListRequest);
}
static UINT
device_send_property_value_request_pdu(CameraDeviceServerContext* context,
const CAM_PROPERTY_VALUE_REQUEST* propertyValueRequest)
{
wStream* s;
WINPR_ASSERT(context);
WINPR_ASSERT(propertyValueRequest);
s = device_server_packet_new(CAM_HEADER_SIZE + 2, context->protocolVersion,
CAM_MSG_ID_PropertyValueRequest);
if (!s)
return ERROR_NOT_ENOUGH_MEMORY;
Stream_Write_UINT8(s, propertyValueRequest->PropertySet);
Stream_Write_UINT8(s, propertyValueRequest->PropertyId);
return device_server_packet_send(context, s);
}
static UINT device_send_set_property_value_request_pdu(
CameraDeviceServerContext* context,
const CAM_SET_PROPERTY_VALUE_REQUEST* setPropertyValueRequest)
{
wStream* s;
WINPR_ASSERT(context);
WINPR_ASSERT(setPropertyValueRequest);
s = device_server_packet_new(CAM_HEADER_SIZE + 2 + 5, context->protocolVersion,
CAM_MSG_ID_SetPropertyValueRequest);
if (!s)
return ERROR_NOT_ENOUGH_MEMORY;
Stream_Write_UINT8(s, setPropertyValueRequest->PropertySet);
Stream_Write_UINT8(s, setPropertyValueRequest->PropertyId);
Stream_Write_UINT8(s, setPropertyValueRequest->PropertyValue.Mode);
Stream_Write_INT32(s, setPropertyValueRequest->PropertyValue.Value);
return device_server_packet_send(context, s);
}
CameraDeviceServerContext* camera_device_server_context_new(HANDLE vcm)
{
device_server* device = (device_server*)calloc(1, sizeof(device_server));
if (!device)
return NULL;
device->context.vcm = vcm;
device->context.Initialize = device_server_initialize;
device->context.Open = device_server_open;
device->context.Close = device_server_close;
device->context.Poll = device_server_context_poll;
device->context.ChannelHandle = device_server_context_handle;
device->context.ActivateDeviceRequest = device_send_activate_device_request_pdu;
device->context.DeactivateDeviceRequest = device_send_deactivate_device_request_pdu;
device->context.StreamListRequest = device_send_stream_list_request_pdu;
device->context.MediaTypeListRequest = device_send_media_type_list_request_pdu;
device->context.CurrentMediaTypeRequest = device_send_current_media_type_request_pdu;
device->context.StartStreamsRequest = device_send_start_streams_request_pdu;
device->context.StopStreamsRequest = device_send_stop_streams_request_pdu;
device->context.SampleRequest = device_send_sample_request_pdu;
device->context.PropertyListRequest = device_send_property_list_request_pdu;
device->context.PropertyValueRequest = device_send_property_value_request_pdu;
device->context.SetPropertyValueRequest = device_send_set_property_value_request_pdu;
device->buffer = Stream_New(NULL, 4096);
if (!device->buffer)
goto fail;
return &device->context;
fail:
camera_device_server_context_free(&device->context);
return NULL;
}
void camera_device_server_context_free(CameraDeviceServerContext* context)
{
device_server* device = (device_server*)context;
if (device)
{
device_server_close(context);
Stream_Free(device->buffer, TRUE);
}
free(context->virtualChannelName);
free(device);
}

View File

@ -51,7 +51,12 @@
#include <freerdp/server/telemetry.h>
#include <freerdp/server/rdpgfx.h>
#include <freerdp/server/disp.h>
#include <freerdp/server/camera-device-enumerator.h>
#include <freerdp/server/camera-device.h>
#ifdef WITH_CHANNEL_GFXREDIR
#include <freerdp/server/gfxredir.h>
#endif /* WITH_CHANNEL_GFXREDIR */
#if defined(CHANNEL_AINPUT_SERVER)
#include <freerdp/server/ainput.h>
@ -74,6 +79,8 @@ void freerdp_channels_dummy(void)
TelemetryServerContext* telemetry;
RdpgfxServerContext* rdpgfx;
DispServerContext* disp;
CamDevEnumServerContext* camera_enumerator;
CameraDeviceServerContext* camera_device;
#ifdef WITH_CHANNEL_GFXREDIR
GfxRedirServerContext* gfxredir;
#endif // WITH_CHANNEL_GFXREDIR
@ -103,6 +110,10 @@ void freerdp_channels_dummy(void)
rdpgfx_server_context_free(rdpgfx);
disp = disp_server_context_new(NULL);
disp_server_context_free(disp);
camera_enumerator = cam_dev_enum_server_context_new(NULL);
cam_dev_enum_server_context_free(camera_enumerator);
camera_device = camera_device_server_context_new(NULL);
camera_device_server_context_free(camera_device);
#ifdef WITH_CHANNEL_GFXREDIR
gfxredir = gfxredir_server_context_new(NULL);
gfxredir_server_context_free(gfxredir);

View File

@ -62,6 +62,9 @@
#cmakedefine CHANNEL_AUDIN
#cmakedefine CHANNEL_AUDIN_CLIENT
#cmakedefine CHANNEL_AUDIN_SERVER
#cmakedefine CHANNEL_CAMERA
#cmakedefine CHANNEL_CAMERA_CLIENT
#cmakedefine CHANNEL_CAMERA_SERVER
#cmakedefine CHANNEL_CLIPRDR
#cmakedefine CHANNEL_CLIPRDR_CLIENT
#cmakedefine CHANNEL_CLIPRDR_SERVER

View File

@ -0,0 +1,335 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Video Capture Virtual Channel Extension
*
* Copyright 2022 Pascal Nowack <Pascal.Nowack@gmx.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CHANNEL_CAMERA_DEVICE_H
#define FREERDP_CHANNEL_CAMERA_DEVICE_H
#include <freerdp/api.h>
#include <freerdp/dvc.h>
#include <freerdp/types.h>
#define CAM_DEVICE_ENUMERATOR_DVC_CHANNEL_NAME "RDCamera_Device_Enumerator"
typedef enum
{
CAM_MSG_ID_SuccessResponse = 0x01,
CAM_MSG_ID_ErrorResponse = 0x02,
CAM_MSG_ID_SelectVersionRequest = 0x03,
CAM_MSG_ID_SelectVersionResponse = 0x04,
CAM_MSG_ID_DeviceAddedNotification = 0x05,
CAM_MSG_ID_DeviceRemovedNotification = 0x06,
CAM_MSG_ID_ActivateDeviceRequest = 0x07,
CAM_MSG_ID_DeactivateDeviceRequest = 0x08,
CAM_MSG_ID_StreamListRequest = 0x09,
CAM_MSG_ID_StreamListResponse = 0x0A,
CAM_MSG_ID_MediaTypeListRequest = 0x0B,
CAM_MSG_ID_MediaTypeListResponse = 0x0C,
CAM_MSG_ID_CurrentMediaTypeRequest = 0x0D,
CAM_MSG_ID_CurrentMediaTypeResponse = 0x0E,
CAM_MSG_ID_StartStreamsRequest = 0x0F,
CAM_MSG_ID_StopStreamsRequest = 0x10,
CAM_MSG_ID_SampleRequest = 0x11,
CAM_MSG_ID_SampleResponse = 0x12,
CAM_MSG_ID_SampleErrorResponse = 0x13,
CAM_MSG_ID_PropertyListRequest = 0x14,
CAM_MSG_ID_PropertyListResponse = 0x15,
CAM_MSG_ID_PropertyValueRequest = 0x16,
CAM_MSG_ID_PropertyValueResponse = 0x17,
CAM_MSG_ID_SetPropertyValueRequest = 0x18,
} CAM_MSG_ID;
#define CAM_HEADER_SIZE 2
typedef struct
{
BYTE Version;
CAM_MSG_ID MessageId;
} CAM_SHARED_MSG_HEADER;
/* Messages Exchanged on the Device Enumeration Channel (2.2.2) */
typedef struct
{
CAM_SHARED_MSG_HEADER Header;
} CAM_SELECT_VERSION_REQUEST;
typedef struct
{
CAM_SHARED_MSG_HEADER Header;
} CAM_SELECT_VERSION_RESPONSE;
typedef struct
{
CAM_SHARED_MSG_HEADER Header;
WCHAR* DeviceName;
char* VirtualChannelName;
} CAM_DEVICE_ADDED_NOTIFICATION;
typedef struct
{
CAM_SHARED_MSG_HEADER Header;
char* VirtualChannelName;
} CAM_DEVICE_REMOVED_NOTIFICATION;
/* Messages Exchanged on Device Channels (2.2.3) */
typedef struct
{
CAM_SHARED_MSG_HEADER Header;
} CAM_SUCCESS_RESPONSE;
typedef enum
{
CAM_ERROR_CODE_UnexpectedError = 0x00000001,
CAM_ERROR_CODE_InvalidMessage = 0x00000002,
CAM_ERROR_CODE_NotInitialized = 0x00000003,
CAM_ERROR_CODE_InvalidRequest = 0x00000004,
CAM_ERROR_CODE_InvalidStreamNumber = 0x00000005,
CAM_ERROR_CODE_InvalidMediaType = 0x00000006,
CAM_ERROR_CODE_OutOfMemory = 0x00000007,
CAM_ERROR_CODE_ItemNotFound = 0x00000008,
CAM_ERROR_CODE_SetNotFound = 0x00000009,
CAM_ERROR_CODE_OperationNotSupported = 0x0000000A,
} CAM_ERROR_CODE;
typedef struct
{
CAM_SHARED_MSG_HEADER Header;
CAM_ERROR_CODE ErrorCode;
} CAM_ERROR_RESPONSE;
typedef struct
{
CAM_SHARED_MSG_HEADER Header;
} CAM_ACTIVATE_DEVICE_REQUEST;
typedef struct
{
CAM_SHARED_MSG_HEADER Header;
} CAM_DEACTIVATE_DEVICE_REQUEST;
typedef struct
{
CAM_SHARED_MSG_HEADER Header;
} CAM_STREAM_LIST_REQUEST;
typedef enum
{
CAM_STREAM_FRAME_SOURCE_TYPE_Color = 0x0001,
CAM_STREAM_FRAME_SOURCE_TYPE_Infrared = 0x0002,
CAM_STREAM_FRAME_SOURCE_TYPE_Custom = 0x0008,
} CAM_STREAM_FRAME_SOURCE_TYPES;
typedef enum
{
CAM_STREAM_CATEGORY_Capture = 0x01,
} CAM_STREAM_CATEGORY;
typedef struct
{
CAM_STREAM_FRAME_SOURCE_TYPES FrameSourceTypes;
CAM_STREAM_CATEGORY StreamCategory;
BYTE Selected;
BYTE CanBeShared;
} CAM_STREAM_DESCRIPTION;
typedef struct
{
CAM_SHARED_MSG_HEADER Header;
BYTE N_Descriptions;
CAM_STREAM_DESCRIPTION StreamDescriptions[255];
} CAM_STREAM_LIST_RESPONSE;
typedef struct
{
CAM_SHARED_MSG_HEADER Header;
BYTE StreamIndex;
} CAM_MEDIA_TYPE_LIST_REQUEST;
typedef enum
{
CAM_MEDIA_FORMAT_H264 = 0x01,
CAM_MEDIA_FORMAT_MJPG = 0x02,
CAM_MEDIA_FORMAT_YUY2 = 0x03,
CAM_MEDIA_FORMAT_NV12 = 0x04,
CAM_MEDIA_FORMAT_I420 = 0x05,
CAM_MEDIA_FORMAT_RGB24 = 0x06,
CAM_MEDIA_FORMAT_RGB32 = 0x07,
} CAM_MEDIA_FORMAT;
typedef enum
{
CAM_MEDIA_TYPE_DESCRIPTION_FLAG_DecodingRequired = 0x01,
CAM_MEDIA_TYPE_DESCRIPTION_FLAG_BottomUpImage = 0x02,
} CAM_MEDIA_TYPE_DESCRIPTION_FLAGS;
typedef struct
{
CAM_MEDIA_FORMAT Format;
UINT32 Width;
UINT32 Height;
UINT32 FrameRateNumerator;
UINT32 FrameRateDenominator;
UINT32 PixelAspectRatioNumerator;
UINT32 PixelAspectRatioDenominator;
CAM_MEDIA_TYPE_DESCRIPTION_FLAGS Flags;
} CAM_MEDIA_TYPE_DESCRIPTION;
typedef struct
{
CAM_SHARED_MSG_HEADER Header;
size_t N_Descriptions;
CAM_MEDIA_TYPE_DESCRIPTION* MediaTypeDescriptions;
} CAM_MEDIA_TYPE_LIST_RESPONSE;
typedef struct
{
CAM_SHARED_MSG_HEADER Header;
BYTE StreamIndex;
} CAM_CURRENT_MEDIA_TYPE_REQUEST;
typedef struct
{
CAM_SHARED_MSG_HEADER Header;
CAM_MEDIA_TYPE_DESCRIPTION MediaTypeDescription;
} CAM_CURRENT_MEDIA_TYPE_RESPONSE;
typedef struct
{
BYTE StreamIndex;
CAM_MEDIA_TYPE_DESCRIPTION MediaTypeDescription;
} CAM_START_STREAM_INFO;
typedef struct
{
CAM_SHARED_MSG_HEADER Header;
BYTE N_Infos;
CAM_START_STREAM_INFO StartStreamsInfo[255];
} CAM_START_STREAMS_REQUEST;
typedef struct
{
CAM_SHARED_MSG_HEADER Header;
} CAM_STOP_STREAMS_REQUEST;
typedef struct
{
CAM_SHARED_MSG_HEADER Header;
BYTE StreamIndex;
} CAM_SAMPLE_REQUEST;
typedef struct
{
CAM_SHARED_MSG_HEADER Header;
BYTE StreamIndex;
size_t SampleSize;
BYTE* Sample;
} CAM_SAMPLE_RESPONSE;
typedef struct
{
CAM_SHARED_MSG_HEADER Header;
BYTE StreamIndex;
CAM_ERROR_CODE ErrorCode;
} CAM_SAMPLE_ERROR_RESPONSE;
typedef struct
{
CAM_SHARED_MSG_HEADER Header;
} CAM_PROPERTY_LIST_REQUEST;
typedef enum
{
CAM_PROPERTY_SET_CameraControl = 0x01,
CAM_PROPERTY_SET_VideoProcAmp = 0x02,
} CAM_PROPERTY_SET;
/* CameraControl properties */
#define CAM_PROPERTY_ID_CAMERA_CONTROL_Exposure 0x01
#define CAM_PROPERTY_ID_CAMERA_CONTROL_Focus 0x02
#define CAM_PROPERTY_ID_CAMERA_CONTROL_Pan 0x03
#define CAM_PROPERTY_ID_CAMERA_CONTROL_Roll 0x04
#define CAM_PROPERTY_ID_CAMERA_CONTROL_Tilt 0x05
#define CAM_PROPERTY_ID_CAMERA_CONTROL_Zoom 0x06
/* VideoProcAmp properties */
#define CAM_PROPERTY_ID_VIDEO_PROC_AMP_BacklightCompensation 0x01
#define CAM_PROPERTY_ID_VIDEO_PROC_AMP_Brightness 0x02
#define CAM_PROPERTY_ID_VIDEO_PROC_AMP_Contrast 0x03
#define CAM_PROPERTY_ID_VIDEO_PROC_AMP_Hue 0x04
#define CAM_PROPERTY_ID_VIDEO_PROC_AMP_WhiteBalance 0x05
typedef enum
{
CAM_PROPERTY_CAPABILITY_Manual = 0x01,
CAM_PROPERTY_CAPABILITY_Auto = 0x02,
} CAM_PROPERTY_CAPABILITIES;
typedef struct
{
CAM_PROPERTY_SET PropertySet;
BYTE PropertyId;
CAM_PROPERTY_CAPABILITIES Capabilities;
INT32 MinValue;
INT32 MaxValue;
INT32 Step;
INT32 DefaultValue;
} CAM_PROPERTY_DESCRIPTION;
typedef struct
{
CAM_SHARED_MSG_HEADER Header;
size_t N_Properties;
CAM_PROPERTY_DESCRIPTION* Properties;
} CAM_PROPERTY_LIST_RESPONSE;
typedef struct
{
CAM_SHARED_MSG_HEADER Header;
CAM_PROPERTY_SET PropertySet;
BYTE PropertyId;
} CAM_PROPERTY_VALUE_REQUEST;
typedef enum
{
CAM_PROPERTY_MODE_Manual = 0x01,
CAM_PROPERTY_MODE_Auto = 0x02,
} CAM_PROPERTY_MODE;
typedef struct
{
CAM_PROPERTY_MODE Mode;
INT32 Value;
} CAM_PROPERTY_VALUE;
typedef struct
{
CAM_SHARED_MSG_HEADER Header;
CAM_PROPERTY_VALUE PropertyValue;
} CAM_PROPERTY_VALUE_RESPONSE;
typedef struct
{
CAM_SHARED_MSG_HEADER Header;
CAM_PROPERTY_SET PropertySet;
BYTE PropertyId;
CAM_PROPERTY_VALUE PropertyValue;
} CAM_SET_PROPERTY_VALUE_REQUEST;
#endif /* FREERDP_CHANNEL_CAMERA_DEVICE_H */

View File

@ -0,0 +1,134 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Video Capture Virtual Channel Extension
*
* Copyright 2022 Pascal Nowack <Pascal.Nowack@gmx.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CHANNEL_CAM_DEV_ENUM_SERVER_CAM_DEV_ENUM_H
#define FREERDP_CHANNEL_CAM_DEV_ENUM_SERVER_CAM_DEV_ENUM_H
#include <freerdp/channels/camera-device.h>
#include <freerdp/channels/wtsvc.h>
typedef struct _cam_dev_enum_server_context CamDevEnumServerContext;
typedef UINT (*psCamDevEnumServerServerOpen)(CamDevEnumServerContext* context);
typedef UINT (*psCamDevEnumServerServerClose)(CamDevEnumServerContext* context);
typedef BOOL (*psCamDevEnumServerServerChannelIdAssigned)(CamDevEnumServerContext* context,
UINT32 channelId);
typedef UINT (*psCamDevEnumServerServerInitialize)(CamDevEnumServerContext* context,
BOOL externalThread);
typedef UINT (*psCamDevEnumServerServerPoll)(CamDevEnumServerContext* context);
typedef BOOL (*psCamDevEnumServerServerChannelHandle)(CamDevEnumServerContext* context,
HANDLE* handle);
typedef UINT (*psCamDevEnumServerServerSelectVersionRequest)(
CamDevEnumServerContext* context, const CAM_SELECT_VERSION_REQUEST* selectVersionRequest);
typedef UINT (*psCamDevEnumServerServerSelectVersionResponse)(
CamDevEnumServerContext* context, const CAM_SELECT_VERSION_RESPONSE* selectVersionResponse);
typedef UINT (*psCamDevEnumServerServerDeviceAddedNotification)(
CamDevEnumServerContext* context, const CAM_DEVICE_ADDED_NOTIFICATION* deviceAddedNotification);
typedef UINT (*psCamDevEnumServerServerDeviceRemovedNotification)(
CamDevEnumServerContext* context,
const CAM_DEVICE_REMOVED_NOTIFICATION* deviceRemovedNotification);
struct _cam_dev_enum_server_context
{
HANDLE vcm;
/* Server self-defined pointer. */
void* userdata;
/*** APIs called by the server. ***/
/**
* Optional: Set thread handling.
* When externalThread=TRUE, the application is responsible to call
* Poll() periodically to process channel events.
*
* Defaults to externalThread=FALSE
*/
psCamDevEnumServerServerInitialize Initialize;
/**
* Open the camera device enumerator channel.
*/
psCamDevEnumServerServerOpen Open;
/**
* Close the camera device enumerator channel.
*/
psCamDevEnumServerServerClose Close;
/**
* Poll
* When externalThread=TRUE, call Poll() periodically from your main loop.
* If externalThread=FALSE do not call.
*/
psCamDevEnumServerServerPoll Poll;
/**
* Retrieve the channel handle for use in conjunction with Poll().
* If externalThread=FALSE do not call.
*/
psCamDevEnumServerServerChannelHandle ChannelHandle;
/*
* Send a Select Version Response PDU.
*/
psCamDevEnumServerServerSelectVersionResponse SelectVersionResponse;
/*** Callbacks registered by the server. ***/
/**
* Callback, when the channel got its id assigned.
*/
psCamDevEnumServerServerChannelIdAssigned ChannelIdAssigned;
/**
* Callback for the Select Version Request PDU.
*/
psCamDevEnumServerServerSelectVersionRequest SelectVersionRequest;
/**
* Callback for the Device Added Notification PDU.
*/
psCamDevEnumServerServerDeviceAddedNotification DeviceAddedNotification;
/**
* Callback for the Device Removed Notification PDU.
*/
psCamDevEnumServerServerDeviceRemovedNotification DeviceRemovedNotification;
rdpContext* rdpcontext;
};
#ifdef __cplusplus
extern "C"
{
#endif
FREERDP_API CamDevEnumServerContext* cam_dev_enum_server_context_new(HANDLE vcm);
FREERDP_API void cam_dev_enum_server_context_free(CamDevEnumServerContext* context);
#ifdef __cplusplus
}
#endif
#endif /* FREERDP_CHANNEL_CAM_DEV_ENUM_SERVER_CAM_DEV_ENUM_H */

View File

@ -0,0 +1,278 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Video Capture Virtual Channel Extension
*
* Copyright 2022 Pascal Nowack <Pascal.Nowack@gmx.de>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FREERDP_CHANNEL_CAMERA_DEVICE_SERVER_CAMERA_DEVICE_H
#define FREERDP_CHANNEL_CAMERA_DEVICE_SERVER_CAMERA_DEVICE_H
#include <freerdp/channels/camera-device.h>
#include <freerdp/channels/wtsvc.h>
typedef struct _camera_device_server_context CameraDeviceServerContext;
typedef UINT (*psCameraDeviceServerOpen)(CameraDeviceServerContext* context);
typedef UINT (*psCameraDeviceServerClose)(CameraDeviceServerContext* context);
typedef BOOL (*psCameraDeviceServerChannelIdAssigned)(CameraDeviceServerContext* context,
UINT32 channelId);
typedef UINT (*psCameraDeviceServerInitialize)(CameraDeviceServerContext* context,
BOOL externalThread);
typedef UINT (*psCameraDeviceServerPoll)(CameraDeviceServerContext* context);
typedef BOOL (*psCameraDeviceServerChannelHandle)(CameraDeviceServerContext* context,
HANDLE* handle);
typedef UINT (*psCameraDeviceServerSuccessResponse)(CameraDeviceServerContext* context,
const CAM_SUCCESS_RESPONSE* successResponse);
typedef UINT (*psCameraDeviceServerErrorResponse)(CameraDeviceServerContext* context,
const CAM_ERROR_RESPONSE* errorResponse);
typedef UINT (*psCameraDeviceServerActivateDeviceRequest)(
CameraDeviceServerContext* context, const CAM_ACTIVATE_DEVICE_REQUEST* activateDeviceRequest);
typedef UINT (*psCameraDeviceServerDeactivateDeviceRequest)(
CameraDeviceServerContext* context,
const CAM_DEACTIVATE_DEVICE_REQUEST* deactivateDeviceRequest);
typedef UINT (*psCameraDeviceServerStreamListRequest)(
CameraDeviceServerContext* context, const CAM_STREAM_LIST_REQUEST* streamListRequest);
typedef UINT (*psCameraDeviceServerStreamListResponse)(
CameraDeviceServerContext* context, const CAM_STREAM_LIST_RESPONSE* streamListResponse);
typedef UINT (*psCameraDeviceServerMediaTypeListRequest)(
CameraDeviceServerContext* context, const CAM_MEDIA_TYPE_LIST_REQUEST* mediaTypeListRequest);
typedef UINT (*psCameraDeviceServerMediaTypeListResponse)(
CameraDeviceServerContext* context, const CAM_MEDIA_TYPE_LIST_RESPONSE* mediaTypeListResponse);
typedef UINT (*psCameraDeviceServerCurrentMediaTypeRequest)(
CameraDeviceServerContext* context,
const CAM_CURRENT_MEDIA_TYPE_REQUEST* currentMediaTypeRequest);
typedef UINT (*psCameraDeviceServerCurrentMediaTypeResponse)(
CameraDeviceServerContext* context,
const CAM_CURRENT_MEDIA_TYPE_RESPONSE* currentMediaTypeResponse);
typedef UINT (*psCameraDeviceServerStartStreamsRequest)(
CameraDeviceServerContext* context, const CAM_START_STREAMS_REQUEST* startStreamsRequest);
typedef UINT (*psCameraDeviceServerStopStreamsRequest)(
CameraDeviceServerContext* context, const CAM_STOP_STREAMS_REQUEST* stopStreamsRequest);
typedef UINT (*psCameraDeviceServerSampleRequest)(CameraDeviceServerContext* context,
const CAM_SAMPLE_REQUEST* sampleRequest);
typedef UINT (*psCameraDeviceServerSampleResponse)(CameraDeviceServerContext* context,
const CAM_SAMPLE_RESPONSE* sampleResponse);
typedef UINT (*psCameraDeviceServerSampleErrorResponse)(
CameraDeviceServerContext* context, const CAM_SAMPLE_ERROR_RESPONSE* sampleErrorResponse);
typedef UINT (*psCameraDeviceServerPropertyListRequest)(
CameraDeviceServerContext* context, const CAM_PROPERTY_LIST_REQUEST* propertyListRequest);
typedef UINT (*psCameraDeviceServerPropertyListResponse)(
CameraDeviceServerContext* context, const CAM_PROPERTY_LIST_RESPONSE* propertyListResponse);
typedef UINT (*psCameraDeviceServerPropertyValueRequest)(
CameraDeviceServerContext* context, const CAM_PROPERTY_VALUE_REQUEST* propertyValueRequest);
typedef UINT (*psCameraDeviceServerPropertyValueResponse)(
CameraDeviceServerContext* context, const CAM_PROPERTY_VALUE_RESPONSE* propertyValueResponse);
typedef UINT (*psCameraDeviceServerSetPropertyValueRequest)(
CameraDeviceServerContext* context,
const CAM_SET_PROPERTY_VALUE_REQUEST* setPropertyValueRequest);
struct _camera_device_server_context
{
HANDLE vcm;
/* Server self-defined pointer. */
void* userdata;
/**
* Name of the virtual channel. Pointer owned by the CameraDeviceServerContext,
* meaning camera_device_server_context_free() takes care of freeing the pointer.
*
* Server implementations should sanitize the virtual channel name for invalid
* names, like names for other known channels
* ("ECHO", "AUDIO_PLAYBACK_DVC", etc.)
*/
char* virtualChannelName;
/**
* Protocol version to be used. Every sent server to client PDU has the
* version value in the Header set to the following value.
*/
BYTE protocolVersion;
/*** APIs called by the server. ***/
/**
* Optional: Set thread handling.
* When externalThread=TRUE, the application is responsible to call
* Poll() periodically to process channel events.
*
* Defaults to externalThread=FALSE
*/
psCameraDeviceServerInitialize Initialize;
/**
* Open the camera device channel.
*/
psCameraDeviceServerOpen Open;
/**
* Close the camera device channel.
*/
psCameraDeviceServerClose Close;
/**
* Poll
* When externalThread=TRUE, call Poll() periodically from your main loop.
* If externalThread=FALSE do not call.
*/
psCameraDeviceServerPoll Poll;
/**
* Retrieve the channel handle for use in conjunction with Poll().
* If externalThread=FALSE do not call.
*/
psCameraDeviceServerChannelHandle ChannelHandle;
/**
* For the following server to client PDUs,
* the message header does not have to be set.
*/
/**
* Send a Activate Device Request PDU.
*/
psCameraDeviceServerActivateDeviceRequest ActivateDeviceRequest;
/**
* Send a Deactivate Device Request PDU.
*/
psCameraDeviceServerDeactivateDeviceRequest DeactivateDeviceRequest;
/**
* Send a Stream List Request PDU.
*/
psCameraDeviceServerStreamListRequest StreamListRequest;
/**
* Send a Media Type List Request PDU.
*/
psCameraDeviceServerMediaTypeListRequest MediaTypeListRequest;
/**
* Send a Current Media Type Request PDU.
*/
psCameraDeviceServerCurrentMediaTypeRequest CurrentMediaTypeRequest;
/**
* Send a Start Streams Request PDU.
*/
psCameraDeviceServerStartStreamsRequest StartStreamsRequest;
/**
* Send a Stop Streams Request PDU.
*/
psCameraDeviceServerStopStreamsRequest StopStreamsRequest;
/**
* Send a Sample Request PDU.
*/
psCameraDeviceServerSampleRequest SampleRequest;
/**
* Send a Property List Request PDU.
*/
psCameraDeviceServerPropertyListRequest PropertyListRequest;
/**
* Send a Property Value Request PDU.
*/
psCameraDeviceServerPropertyValueRequest PropertyValueRequest;
/**
* Send a Set Property Value Request PDU.
*/
psCameraDeviceServerSetPropertyValueRequest SetPropertyValueRequest;
/*** Callbacks registered by the server. ***/
/**
* Callback, when the channel got its id assigned.
*/
psCameraDeviceServerChannelIdAssigned ChannelIdAssigned;
/**
* Callback for the Success Response PDU.
*/
psCameraDeviceServerSuccessResponse SuccessResponse;
/**
* Callback for the Error Response PDU.
*/
psCameraDeviceServerErrorResponse ErrorResponse;
/**
* Callback for the Stream List Response PDU.
*/
psCameraDeviceServerStreamListResponse StreamListResponse;
/**
* Callback for the Media Type List Response PDU.
*/
psCameraDeviceServerMediaTypeListResponse MediaTypeListResponse;
/**
* Callback for the Current Media Type Response PDU.
*/
psCameraDeviceServerCurrentMediaTypeResponse CurrentMediaTypeResponse;
/**
* Callback for the Sample Response PDU.
*/
psCameraDeviceServerSampleResponse SampleResponse;
/**
* Callback for the Sample Error Response PDU.
*/
psCameraDeviceServerSampleErrorResponse SampleErrorResponse;
/**
* Callback for the Property List Response PDU.
*/
psCameraDeviceServerPropertyListResponse PropertyListResponse;
/**
* Callback for the Property Value Response PDU.
*/
psCameraDeviceServerPropertyValueResponse PropertyValueResponse;
rdpContext* rdpcontext;
};
#ifdef __cplusplus
extern "C"
{
#endif
FREERDP_API CameraDeviceServerContext* camera_device_server_context_new(HANDLE vcm);
FREERDP_API void camera_device_server_context_free(CameraDeviceServerContext* context);
#ifdef __cplusplus
}
#endif
#endif /* FREERDP_CHANNEL_CAMERA_DEVICE_SERVER_CAMERA_DEVICE_H */