20#include <winpr/assert.h>
21#include <winpr/cast.h>
22#include <winpr/string.h>
26#define TAG CHANNELS_TAG("rdpecam-enum.client")
36 CAM_MSG_ID msg = CAM_MSG_ID_ErrorResponse;
40 wStream* s = Stream_New(
nullptr, CAM_HEADER_SIZE + 4);
43 WLog_ERR(TAG,
"Stream_New failed!");
44 return ERROR_NOT_ENOUGH_MEMORY;
47 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, ecam->version));
48 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, msg));
49 Stream_Write_UINT32(s, code);
51 return ecam_channel_write(ecam, hchannel, msg, s, TRUE);
64 wStream* s = Stream_New(
nullptr, CAM_HEADER_SIZE);
67 WLog_ERR(TAG,
"Stream_New failed!");
68 return ERROR_NOT_ENOUGH_MEMORY;
71 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, ecam->version));
72 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, msg));
74 return ecam_channel_write(ecam, hchannel, msg, s, TRUE);
83 CAM_MSG_ID msg,
wStream* out, BOOL freeStream)
85 if (!hchannel || !out)
86 return ERROR_INVALID_PARAMETER;
88 Stream_SealLength(out);
90 const ULONG len = WINPR_ASSERTING_INT_CAST(ULONG, Stream_Length(out));
92 WLog_DBG(TAG,
"ChannelId=%" PRIu32
", MessageId=0x%02" PRIx8
", Length=%" PRIu32,
93 hchannel->channel_mgr->GetChannelId(hchannel->channel), msg, len);
96 hchannel->channel->Write(hchannel->channel, len, Stream_Buffer(out),
nullptr);
99 Stream_Free(out, TRUE);
109static UINT ecam_send_device_added_notification(
CameraPlugin* ecam,
111 const char* deviceName,
const char* channelName)
113 CAM_MSG_ID msg = CAM_MSG_ID_DeviceAddedNotification;
117 wStream* s = Stream_New(
nullptr, 256);
120 WLog_ERR(TAG,
"Stream_New failed!");
121 return ERROR_NOT_ENOUGH_MEMORY;
124 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, ecam->version));
125 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, msg));
127 const size_t devNameLen = strlen(deviceName);
128 const SSIZE_T devNameWLen = ConvertUtf8ToWChar(deviceName,
nullptr, 0);
129 if ((devNameWLen < 0) || Stream_Write_UTF16_String_From_UTF8(s, (
size_t)devNameWLen + 1,
130 deviceName, devNameLen, TRUE) < 0)
132 Stream_Free(s, TRUE);
133 return ERROR_INTERNAL_ERROR;
135 Stream_Write(s, channelName, strlen(channelName) + 1);
137 return ecam_channel_write(ecam, hchannel, msg, s, TRUE);
146 const char* deviceId,
const char* deviceName)
148 WLog_DBG(TAG,
"deviceId=%s, deviceName=%s", deviceId, deviceName);
150 if (!HashTable_ContainsKey(ecam->devices, deviceId))
152 CameraDevice* dev = ecam_dev_create(ecam, deviceId, deviceName);
153 if (!HashTable_Insert(ecam->devices, deviceId, dev))
155 ecam_dev_destroy(dev);
156 return ERROR_INTERNAL_ERROR;
161 WLog_DBG(TAG,
"Device %s already exists", deviceId);
164 ecam_send_device_added_notification(ecam, hchannel, deviceName, deviceId );
166 return CHANNEL_RC_OK;
176 return ecam->ihal->Enumerate(ecam->ihal, ecam_ihal_device_added_callback, ecam, hchannel);
184static UINT ecam_process_select_version_response(
CameraPlugin* ecam,
186 WINPR_ATTR_UNUSED
wStream* s, BYTE serverVersion)
188 const BYTE clientVersion = ECAM_PROTO_VERSION;
192 WLog_DBG(TAG,
"ServerVersion=%" PRIu8
", ClientVersion=%" PRIu8, serverVersion, clientVersion);
194 if (serverVersion > clientVersion)
197 "Incompatible protocol version server=%" PRIu8
", client supports version=%" PRIu8,
198 serverVersion, clientVersion);
199 return CHANNEL_RC_OK;
201 ecam->version = serverVersion;
204 ecam_enumerate_devices(ecam, hchannel);
206 WLog_ERR(TAG,
"No HAL registered");
208 return CHANNEL_RC_OK;
216static UINT ecam_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
wStream* data)
218 UINT error = CHANNEL_RC_OK;
223 if (!hchannel || !data)
224 return ERROR_INVALID_PARAMETER;
229 return ERROR_INTERNAL_ERROR;
231 if (!Stream_CheckAndLogRequiredLength(TAG, data, CAM_HEADER_SIZE))
232 return ERROR_NO_DATA;
234 Stream_Read_UINT8(data, version);
235 Stream_Read_UINT8(data, messageId);
236 WLog_DBG(TAG,
"ChannelId=%" PRIu32
", MessageId=0x%02" PRIx8
", Version=%d",
237 hchannel->channel_mgr->GetChannelId(hchannel->channel), messageId, version);
241 case CAM_MSG_ID_SelectVersionResponse:
242 error = ecam_process_select_version_response(ecam, hchannel, data, version);
246 WLog_WARN(TAG,
"unknown MessageId=0x%02" PRIx8
"", messageId);
247 error = ERROR_INVALID_DATA;
248 ecam_channel_send_error_response(ecam, hchannel, CAM_ERROR_CODE_OperationNotSupported);
260static UINT ecam_on_open(IWTSVirtualChannelCallback* pChannelCallback)
263 WINPR_ASSERT(hchannel);
268 WLog_DBG(TAG,
"entered");
269 return ecam_channel_send_generic_msg(ecam, hchannel, CAM_MSG_ID_SelectVersionRequest);
277static UINT ecam_on_close(IWTSVirtualChannelCallback* pChannelCallback)
280 WINPR_ASSERT(hchannel);
282 WLog_DBG(TAG,
"entered");
285 return CHANNEL_RC_OK;
293static UINT ecam_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
294 IWTSVirtualChannel* pChannel,
295 WINPR_ATTR_UNUSED BYTE* Data,
296 WINPR_ATTR_UNUSED BOOL* pbAccept,
297 IWTSVirtualChannelCallback** ppCallback)
301 if (!hlistener || !hlistener->plugin)
302 return ERROR_INTERNAL_ERROR;
304 WLog_DBG(TAG,
"entered");
310 WLog_ERR(TAG,
"calloc failed!");
311 return CHANNEL_RC_NO_MEMORY;
314 hchannel->iface.OnDataReceived = ecam_on_data_received;
315 hchannel->iface.OnOpen = ecam_on_open;
316 hchannel->iface.OnClose = ecam_on_close;
317 hchannel->plugin = hlistener->plugin;
318 hchannel->channel_mgr = hlistener->channel_mgr;
319 hchannel->channel = pChannel;
320 *ppCallback = (IWTSVirtualChannelCallback*)hchannel;
321 return CHANNEL_RC_OK;
324static void ecam_dev_destroy_pv(
void* obj)
327 ecam_dev_destroy(dev);
335static UINT ecam_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
339 WLog_DBG(TAG,
"entered");
341 if (!ecam || !pChannelMgr)
342 return ERROR_INVALID_PARAMETER;
344 if (ecam->initialized)
346 WLog_ERR(TAG,
"[%s] plugin initialized twice, aborting", RDPECAM_CONTROL_DVC_CHANNEL_NAME);
347 return ERROR_INVALID_DATA;
350 ecam->version = ECAM_PROTO_VERSION;
352 ecam->devices = HashTable_New(FALSE);
355 WLog_ERR(TAG,
"HashTable_New failed!");
356 return CHANNEL_RC_NO_MEMORY;
359 if (!HashTable_SetupForStringData(ecam->devices, FALSE))
361 HashTable_Free(ecam->devices);
362 ecam->devices =
nullptr;
363 return ERROR_INTERNAL_ERROR;
366 wObject* obj = HashTable_ValueObject(ecam->devices);
372 if (!ecam->hlistener)
374 WLog_ERR(TAG,
"calloc failed!");
375 return CHANNEL_RC_NO_MEMORY;
378 ecam->hlistener->iface.OnNewChannelConnection = ecam_on_new_channel_connection;
379 ecam->hlistener->plugin = pPlugin;
380 ecam->hlistener->channel_mgr = pChannelMgr;
381 const UINT rc = pChannelMgr->CreateListener(pChannelMgr, RDPECAM_CONTROL_DVC_CHANNEL_NAME, 0,
382 &ecam->hlistener->iface, &ecam->listener);
384 ecam->initialized = (rc == CHANNEL_RC_OK);
393static UINT ecam_plugin_terminated(IWTSPlugin* pPlugin)
398 return ERROR_INVALID_DATA;
400 WLog_DBG(TAG,
"entered");
404 IWTSVirtualChannelManager* mgr = ecam->hlistener->channel_mgr;
406 IFCALL(mgr->DestroyListener, mgr, ecam->listener);
409 free(ecam->hlistener);
411 HashTable_Free(ecam->devices);
413 UINT rc = CHANNEL_RC_OK;
415 rc = ecam->ihal->Free(ecam->ihal);
426static UINT ecam_plugin_attached(IWTSPlugin* pPlugin)
429 UINT error = CHANNEL_RC_OK;
432 return ERROR_INVALID_PARAMETER;
434 ecam->attached = TRUE;
443static UINT ecam_plugin_detached(IWTSPlugin* pPlugin)
446 UINT error = CHANNEL_RC_OK;
449 return ERROR_INVALID_PARAMETER;
451 ecam->attached = FALSE;
460static UINT ecam_register_hal_plugin(IWTSPlugin* pPlugin, ICamHal* ihal)
468 WLog_DBG(TAG,
"already registered");
469 return ERROR_ALREADY_EXISTS;
472 WLog_DBG(TAG,
"HAL registered");
474 return CHANNEL_RC_OK;
487 UINT error = ERROR_INTERNAL_ERROR;
490 PVIRTUALCHANNELENTRY pvce;
491 const PFREERDP_CAMERA_HAL_ENTRY entry;
493 cnv.pvce = freerdp_load_channel_addin_entry(RDPECAM_CHANNEL_NAME, name,
nullptr, 0);
495 if (cnv.entry ==
nullptr)
498 "freerdp_load_channel_addin_entry did not return any function pointers for %s ",
500 return ERROR_INVALID_FUNCTION;
503 entryPoints.plugin = &ecam->iface;
504 entryPoints.pRegisterCameraHal = ecam_register_hal_plugin;
505 entryPoints.args = args;
506 entryPoints.ecam = ecam;
508 error = cnv.entry(&entryPoints);
511 WLog_ERR(TAG,
"%s entry returned error %" PRIu32
".", name, error);
515 WLog_INFO(TAG,
"Loaded %s HAL for ecam", name);
516 return CHANNEL_RC_OK;
524FREERDP_ENTRY_POINT(UINT VCAPITYPE rdpecam_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints))
526 UINT error = CHANNEL_RC_INITIALIZATION_ERROR;
528 WINPR_ASSERT(pEntryPoints);
529 WINPR_ASSERT(pEntryPoints->GetPlugin);
533 return CHANNEL_RC_ALREADY_INITIALIZED;
539 WLog_ERR(TAG,
"calloc failed!");
540 return CHANNEL_RC_NO_MEMORY;
543 ecam->attached = TRUE;
544 ecam->iface.Initialize = ecam_plugin_initialize;
545 ecam->iface.Connected =
nullptr;
546 ecam->iface.Disconnected =
nullptr;
547 ecam->iface.Terminated = ecam_plugin_terminated;
548 ecam->iface.Attached = ecam_plugin_attached;
549 ecam->iface.Detached = ecam_plugin_detached;
553 ecam->subsystem =
"v4l";
554#elif defined(__ANDROID__)
555 ecam->subsystem =
"android";
557 ecam->subsystem =
nullptr;
562 if ((error = ecam_load_hal_plugin(ecam, ecam->subsystem,
nullptr )))
565 "Unable to load camera redirection subsystem %s because of error %" PRIu32
"",
566 ecam->subsystem, error);
571 error = pEntryPoints->RegisterPlugin(pEntryPoints, RDPECAM_CHANNEL_NAME, &ecam->iface);
572 if (error == CHANNEL_RC_OK)
576 ecam_plugin_terminated(&ecam->iface);
This struct contains function pointer to initialize/free objects.
OBJECT_FREE_FN fnObjectFree