20#include <winpr/assert.h>
21#include <winpr/cast.h>
25#define TAG CHANNELS_TAG("rdpecam-enum.client")
35 CAM_MSG_ID msg = CAM_MSG_ID_ErrorResponse;
39 wStream* s = Stream_New(
nullptr, CAM_HEADER_SIZE + 4);
42 WLog_ERR(TAG,
"Stream_New failed!");
43 return ERROR_NOT_ENOUGH_MEMORY;
46 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, ecam->version));
47 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, msg));
48 Stream_Write_UINT32(s, code);
50 return ecam_channel_write(ecam, hchannel, msg, s, TRUE);
63 wStream* s = Stream_New(
nullptr, CAM_HEADER_SIZE);
66 WLog_ERR(TAG,
"Stream_New failed!");
67 return ERROR_NOT_ENOUGH_MEMORY;
70 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, ecam->version));
71 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, msg));
73 return ecam_channel_write(ecam, hchannel, msg, s, TRUE);
82 CAM_MSG_ID msg,
wStream* out, BOOL freeStream)
84 if (!hchannel || !out)
85 return ERROR_INVALID_PARAMETER;
87 Stream_SealLength(out);
89 const ULONG len = WINPR_ASSERTING_INT_CAST(ULONG, Stream_Length(out));
91 WLog_DBG(TAG,
"ChannelId=%" PRIu32
", MessageId=0x%02" PRIx8
", Length=%" PRIu32,
92 hchannel->channel_mgr->GetChannelId(hchannel->channel), msg, len);
95 hchannel->channel->Write(hchannel->channel, len, Stream_Buffer(out),
nullptr);
98 Stream_Free(out, TRUE);
108static UINT ecam_send_device_added_notification(
CameraPlugin* ecam,
110 const char* deviceName,
const char* channelName)
112 CAM_MSG_ID msg = CAM_MSG_ID_DeviceAddedNotification;
116 wStream* s = Stream_New(
nullptr, 256);
119 WLog_ERR(TAG,
"Stream_New failed!");
120 return ERROR_NOT_ENOUGH_MEMORY;
123 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, ecam->version));
124 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, msg));
126 size_t devNameLen = strlen(deviceName);
127 if (Stream_Write_UTF16_String_From_UTF8(s, devNameLen + 1, deviceName, devNameLen, TRUE) < 0)
129 Stream_Free(s, TRUE);
130 return ERROR_INTERNAL_ERROR;
132 Stream_Write(s, channelName, strlen(channelName) + 1);
134 return ecam_channel_write(ecam, hchannel, msg, s, TRUE);
143 const char* deviceId,
const char* deviceName)
145 WLog_DBG(TAG,
"deviceId=%s, deviceName=%s", deviceId, deviceName);
147 if (!HashTable_ContainsKey(ecam->devices, deviceId))
149 CameraDevice* dev = ecam_dev_create(ecam, deviceId, deviceName);
150 if (!HashTable_Insert(ecam->devices, deviceId, dev))
152 ecam_dev_destroy(dev);
153 return ERROR_INTERNAL_ERROR;
158 WLog_DBG(TAG,
"Device %s already exists", deviceId);
161 ecam_send_device_added_notification(ecam, hchannel, deviceName, deviceId );
163 return CHANNEL_RC_OK;
173 return ecam->ihal->Enumerate(ecam->ihal, ecam_ihal_device_added_callback, ecam, hchannel);
181static UINT ecam_process_select_version_response(
CameraPlugin* ecam,
183 WINPR_ATTR_UNUSED
wStream* s, BYTE serverVersion)
185 const BYTE clientVersion = ECAM_PROTO_VERSION;
189 WLog_DBG(TAG,
"ServerVersion=%" PRIu8
", ClientVersion=%" PRIu8, serverVersion, clientVersion);
191 if (serverVersion > clientVersion)
194 "Incompatible protocol version server=%" PRIu8
", client supports version=%" PRIu8,
195 serverVersion, clientVersion);
196 return CHANNEL_RC_OK;
198 ecam->version = serverVersion;
201 ecam_enumerate_devices(ecam, hchannel);
203 WLog_ERR(TAG,
"No HAL registered");
205 return CHANNEL_RC_OK;
213static UINT ecam_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
wStream* data)
215 UINT error = CHANNEL_RC_OK;
220 if (!hchannel || !data)
221 return ERROR_INVALID_PARAMETER;
226 return ERROR_INTERNAL_ERROR;
228 if (!Stream_CheckAndLogRequiredCapacity(TAG, data, CAM_HEADER_SIZE))
229 return ERROR_NO_DATA;
231 Stream_Read_UINT8(data, version);
232 Stream_Read_UINT8(data, messageId);
233 WLog_DBG(TAG,
"ChannelId=%" PRIu32
", MessageId=0x%02" PRIx8
", Version=%d",
234 hchannel->channel_mgr->GetChannelId(hchannel->channel), messageId, version);
238 case CAM_MSG_ID_SelectVersionResponse:
239 error = ecam_process_select_version_response(ecam, hchannel, data, version);
243 WLog_WARN(TAG,
"unknown MessageId=0x%02" PRIx8
"", messageId);
244 error = ERROR_INVALID_DATA;
245 ecam_channel_send_error_response(ecam, hchannel, CAM_ERROR_CODE_OperationNotSupported);
257static UINT ecam_on_open(IWTSVirtualChannelCallback* pChannelCallback)
260 WINPR_ASSERT(hchannel);
265 WLog_DBG(TAG,
"entered");
266 return ecam_channel_send_generic_msg(ecam, hchannel, CAM_MSG_ID_SelectVersionRequest);
274static UINT ecam_on_close(IWTSVirtualChannelCallback* pChannelCallback)
277 WINPR_ASSERT(hchannel);
279 WLog_DBG(TAG,
"entered");
282 return CHANNEL_RC_OK;
290static UINT ecam_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
291 IWTSVirtualChannel* pChannel,
292 WINPR_ATTR_UNUSED BYTE* Data,
293 WINPR_ATTR_UNUSED BOOL* pbAccept,
294 IWTSVirtualChannelCallback** ppCallback)
298 if (!hlistener || !hlistener->plugin)
299 return ERROR_INTERNAL_ERROR;
301 WLog_DBG(TAG,
"entered");
307 WLog_ERR(TAG,
"calloc failed!");
308 return CHANNEL_RC_NO_MEMORY;
311 hchannel->iface.OnDataReceived = ecam_on_data_received;
312 hchannel->iface.OnOpen = ecam_on_open;
313 hchannel->iface.OnClose = ecam_on_close;
314 hchannel->plugin = hlistener->plugin;
315 hchannel->channel_mgr = hlistener->channel_mgr;
316 hchannel->channel = pChannel;
317 *ppCallback = (IWTSVirtualChannelCallback*)hchannel;
318 return CHANNEL_RC_OK;
321static void ecam_dev_destroy_pv(
void* obj)
324 ecam_dev_destroy(dev);
332static UINT ecam_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
336 WLog_DBG(TAG,
"entered");
338 if (!ecam || !pChannelMgr)
339 return ERROR_INVALID_PARAMETER;
341 if (ecam->initialized)
343 WLog_ERR(TAG,
"[%s] plugin initialized twice, aborting", RDPECAM_CONTROL_DVC_CHANNEL_NAME);
344 return ERROR_INVALID_DATA;
347 ecam->version = ECAM_PROTO_VERSION;
349 ecam->devices = HashTable_New(FALSE);
352 WLog_ERR(TAG,
"HashTable_New failed!");
353 return CHANNEL_RC_NO_MEMORY;
356 if (!HashTable_SetupForStringData(ecam->devices, FALSE))
358 HashTable_Free(ecam->devices);
359 ecam->devices =
nullptr;
360 return ERROR_INTERNAL_ERROR;
363 wObject* obj = HashTable_ValueObject(ecam->devices);
369 if (!ecam->hlistener)
371 WLog_ERR(TAG,
"calloc failed!");
372 return CHANNEL_RC_NO_MEMORY;
375 ecam->hlistener->iface.OnNewChannelConnection = ecam_on_new_channel_connection;
376 ecam->hlistener->plugin = pPlugin;
377 ecam->hlistener->channel_mgr = pChannelMgr;
378 const UINT rc = pChannelMgr->CreateListener(pChannelMgr, RDPECAM_CONTROL_DVC_CHANNEL_NAME, 0,
379 &ecam->hlistener->iface, &ecam->listener);
381 ecam->initialized = (rc == CHANNEL_RC_OK);
390static UINT ecam_plugin_terminated(IWTSPlugin* pPlugin)
395 return ERROR_INVALID_DATA;
397 WLog_DBG(TAG,
"entered");
401 IWTSVirtualChannelManager* mgr = ecam->hlistener->channel_mgr;
403 IFCALL(mgr->DestroyListener, mgr, ecam->listener);
406 free(ecam->hlistener);
408 HashTable_Free(ecam->devices);
410 UINT rc = CHANNEL_RC_OK;
412 rc = ecam->ihal->Free(ecam->ihal);
423static UINT ecam_plugin_attached(IWTSPlugin* pPlugin)
426 UINT error = CHANNEL_RC_OK;
429 return ERROR_INVALID_PARAMETER;
431 ecam->attached = TRUE;
440static UINT ecam_plugin_detached(IWTSPlugin* pPlugin)
443 UINT error = CHANNEL_RC_OK;
446 return ERROR_INVALID_PARAMETER;
448 ecam->attached = FALSE;
457static UINT ecam_register_hal_plugin(IWTSPlugin* pPlugin, ICamHal* ihal)
465 WLog_DBG(TAG,
"already registered");
466 return ERROR_ALREADY_EXISTS;
469 WLog_DBG(TAG,
"HAL registered");
471 return CHANNEL_RC_OK;
484 UINT error = ERROR_INTERNAL_ERROR;
487 PVIRTUALCHANNELENTRY pvce;
488 const PFREERDP_CAMERA_HAL_ENTRY entry;
490 cnv.pvce = freerdp_load_channel_addin_entry(RDPECAM_CHANNEL_NAME, name,
nullptr, 0);
492 if (cnv.entry ==
nullptr)
495 "freerdp_load_channel_addin_entry did not return any function pointers for %s ",
497 return ERROR_INVALID_FUNCTION;
500 entryPoints.plugin = &ecam->iface;
501 entryPoints.pRegisterCameraHal = ecam_register_hal_plugin;
502 entryPoints.args = args;
503 entryPoints.ecam = ecam;
505 error = cnv.entry(&entryPoints);
508 WLog_ERR(TAG,
"%s entry returned error %" PRIu32
".", name, error);
512 WLog_INFO(TAG,
"Loaded %s HAL for ecam", name);
513 return CHANNEL_RC_OK;
521FREERDP_ENTRY_POINT(UINT VCAPITYPE rdpecam_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints))
523 UINT error = CHANNEL_RC_INITIALIZATION_ERROR;
525 WINPR_ASSERT(pEntryPoints);
526 WINPR_ASSERT(pEntryPoints->GetPlugin);
530 return CHANNEL_RC_ALREADY_INITIALIZED;
536 WLog_ERR(TAG,
"calloc failed!");
537 return CHANNEL_RC_NO_MEMORY;
540 ecam->attached = TRUE;
541 ecam->iface.Initialize = ecam_plugin_initialize;
542 ecam->iface.Connected =
nullptr;
543 ecam->iface.Disconnected =
nullptr;
544 ecam->iface.Terminated = ecam_plugin_terminated;
545 ecam->iface.Attached = ecam_plugin_attached;
546 ecam->iface.Detached = ecam_plugin_detached;
550 ecam->subsystem =
"v4l";
552 ecam->subsystem =
nullptr;
557 if ((error = ecam_load_hal_plugin(ecam, ecam->subsystem,
nullptr )))
560 "Unable to load camera redirection subsystem %s because of error %" PRIu32
"",
561 ecam->subsystem, error);
566 error = pEntryPoints->RegisterPlugin(pEntryPoints, RDPECAM_CHANNEL_NAME, &ecam->iface);
567 if (error == CHANNEL_RC_OK)
571 ecam_plugin_terminated(&ecam->iface);
This struct contains function pointer to initialize/free objects.
OBJECT_FREE_FN fnObjectFree