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(NULL, 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(NULL, 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);
84 if (!hchannel || !out)
85 return ERROR_INVALID_PARAMETER;
87 Stream_SealLength(out);
88 WINPR_ASSERT(Stream_Length(out) <= UINT32_MAX);
90 WLog_DBG(TAG,
"ChannelId=%d, MessageId=0x%02" PRIx8
", Length=%d",
91 hchannel->channel_mgr->GetChannelId(hchannel->channel), msg, Stream_Length(out));
93 const UINT error = hchannel->channel->Write(hchannel->channel, (ULONG)Stream_Length(out),
94 Stream_Buffer(out), NULL);
97 Stream_Free(out, TRUE);
107 static UINT ecam_send_device_added_notification(
CameraPlugin* ecam,
109 const char* deviceName,
const char* channelName)
111 CAM_MSG_ID msg = CAM_MSG_ID_DeviceAddedNotification;
115 wStream* s = Stream_New(NULL, 256);
118 WLog_ERR(TAG,
"Stream_New failed!");
119 return ERROR_NOT_ENOUGH_MEMORY;
122 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, ecam->version));
123 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, msg));
125 size_t devNameLen = strlen(deviceName);
126 if (Stream_Write_UTF16_String_From_UTF8(s, devNameLen + 1, deviceName, devNameLen, TRUE) < 0)
128 Stream_Free(s, TRUE);
129 return ERROR_INTERNAL_ERROR;
131 Stream_Write(s, channelName, strlen(channelName) + 1);
133 return ecam_channel_write(ecam, hchannel, msg, s, TRUE);
142 const char* deviceId,
const char* deviceName)
144 WLog_DBG(TAG,
"deviceId=%s, deviceName=%s", deviceId, deviceName);
146 if (!HashTable_ContainsKey(ecam->devices, deviceId))
148 CameraDevice* dev = ecam_dev_create(ecam, deviceId, deviceName);
149 if (!HashTable_Insert(ecam->devices, deviceId, dev))
151 ecam_dev_destroy(dev);
152 return ERROR_INTERNAL_ERROR;
157 WLog_DBG(TAG,
"Device %s already exists", deviceId);
160 ecam_send_device_added_notification(ecam, hchannel, deviceName, deviceId );
162 return CHANNEL_RC_OK;
172 ecam->ihal->Enumerate(ecam->ihal, ecam_ihal_device_added_callback, ecam, hchannel);
174 return CHANNEL_RC_OK;
182 static UINT ecam_process_select_version_response(
CameraPlugin* ecam,
186 const BYTE clientVersion = ECAM_PROTO_VERSION;
190 WLog_DBG(TAG,
"ServerVersion=%" PRIu8
", ClientVersion=%" PRIu8, serverVersion, clientVersion);
192 if (serverVersion > clientVersion)
195 "Incompatible protocol version server=%" PRIu8
", client supports version=%" PRIu8,
196 serverVersion, clientVersion);
197 return CHANNEL_RC_OK;
199 ecam->version = serverVersion;
202 ecam_enumerate_devices(ecam, hchannel);
204 WLog_ERR(TAG,
"No HAL registered");
206 return CHANNEL_RC_OK;
214 static UINT ecam_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
wStream* data)
216 UINT error = CHANNEL_RC_OK;
221 if (!hchannel || !data)
222 return ERROR_INVALID_PARAMETER;
227 return ERROR_INTERNAL_ERROR;
229 if (!Stream_CheckAndLogRequiredCapacity(TAG, data, CAM_HEADER_SIZE))
230 return ERROR_NO_DATA;
232 Stream_Read_UINT8(data, version);
233 Stream_Read_UINT8(data, messageId);
234 WLog_DBG(TAG,
"ChannelId=%d, MessageId=0x%02" PRIx8
", Version=%d",
235 hchannel->channel_mgr->GetChannelId(hchannel->channel), messageId, version);
239 case CAM_MSG_ID_SelectVersionResponse:
240 error = ecam_process_select_version_response(ecam, hchannel, data, version);
244 WLog_WARN(TAG,
"unknown MessageId=0x%02" PRIx8
"", messageId);
245 error = ERROR_INVALID_DATA;
246 ecam_channel_send_error_response(ecam, hchannel, CAM_ERROR_CODE_OperationNotSupported);
258 static UINT ecam_on_open(IWTSVirtualChannelCallback* pChannelCallback)
261 WINPR_ASSERT(hchannel);
266 WLog_DBG(TAG,
"entered");
267 return ecam_channel_send_generic_msg(ecam, hchannel, CAM_MSG_ID_SelectVersionRequest);
275 static UINT ecam_on_close(IWTSVirtualChannelCallback* pChannelCallback)
278 WINPR_ASSERT(hchannel);
280 WLog_DBG(TAG,
"entered");
283 return CHANNEL_RC_OK;
291 static UINT ecam_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
292 IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept,
293 IWTSVirtualChannelCallback** ppCallback)
297 if (!hlistener || !hlistener->plugin)
298 return ERROR_INTERNAL_ERROR;
300 WLog_DBG(TAG,
"entered");
306 WLog_ERR(TAG,
"calloc failed!");
307 return CHANNEL_RC_NO_MEMORY;
310 hchannel->iface.OnDataReceived = ecam_on_data_received;
311 hchannel->iface.OnOpen = ecam_on_open;
312 hchannel->iface.OnClose = ecam_on_close;
313 hchannel->plugin = hlistener->plugin;
314 hchannel->channel_mgr = hlistener->channel_mgr;
315 hchannel->channel = pChannel;
316 *ppCallback = (IWTSVirtualChannelCallback*)hchannel;
317 return CHANNEL_RC_OK;
320 static void ecam_dev_destroy_pv(
void* obj)
323 ecam_dev_destroy(dev);
331 static UINT ecam_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
335 WLog_DBG(TAG,
"entered");
337 if (!ecam || !pChannelMgr)
338 return ERROR_INVALID_PARAMETER;
340 if (ecam->initialized)
342 WLog_ERR(TAG,
"[%s] plugin initialized twice, aborting", RDPECAM_CONTROL_DVC_CHANNEL_NAME);
343 return ERROR_INVALID_DATA;
346 ecam->version = ECAM_PROTO_VERSION;
348 ecam->devices = HashTable_New(FALSE);
351 WLog_ERR(TAG,
"HashTable_New failed!");
352 return CHANNEL_RC_NO_MEMORY;
355 HashTable_SetupForStringData(ecam->devices, FALSE);
357 wObject* obj = HashTable_ValueObject(ecam->devices);
359 obj->fnObjectFree = ecam_dev_destroy_pv;
363 if (!ecam->hlistener)
365 WLog_ERR(TAG,
"calloc failed!");
366 return CHANNEL_RC_NO_MEMORY;
369 ecam->hlistener->iface.OnNewChannelConnection = ecam_on_new_channel_connection;
370 ecam->hlistener->plugin = pPlugin;
371 ecam->hlistener->channel_mgr = pChannelMgr;
372 const UINT rc = pChannelMgr->CreateListener(pChannelMgr, RDPECAM_CONTROL_DVC_CHANNEL_NAME, 0,
373 &ecam->hlistener->iface, &ecam->listener);
375 ecam->initialized = (rc == CHANNEL_RC_OK);
384 static UINT ecam_plugin_terminated(IWTSPlugin* pPlugin)
389 return ERROR_INVALID_DATA;
391 WLog_DBG(TAG,
"entered");
395 IWTSVirtualChannelManager* mgr = ecam->hlistener->channel_mgr;
397 IFCALL(mgr->DestroyListener, mgr, ecam->listener);
400 free(ecam->hlistener);
402 HashTable_Free(ecam->devices);
405 ecam->ihal->Free(ecam->ihal);
408 return CHANNEL_RC_OK;
416 static UINT ecam_plugin_attached(IWTSPlugin* pPlugin)
419 UINT error = CHANNEL_RC_OK;
422 return ERROR_INVALID_PARAMETER;
424 ecam->attached = TRUE;
433 static UINT ecam_plugin_detached(IWTSPlugin* pPlugin)
436 UINT error = CHANNEL_RC_OK;
439 return ERROR_INVALID_PARAMETER;
441 ecam->attached = FALSE;
450 static UINT ecam_register_hal_plugin(IWTSPlugin* pPlugin, ICamHal* ihal)
458 WLog_DBG(TAG,
"already registered");
459 return ERROR_ALREADY_EXISTS;
462 WLog_DBG(TAG,
"HAL registered");
464 return CHANNEL_RC_OK;
477 UINT error = ERROR_INTERNAL_ERROR;
480 PVIRTUALCHANNELENTRY pvce;
481 const PFREERDP_CAMERA_HAL_ENTRY entry;
483 cnv.pvce = freerdp_load_channel_addin_entry(RDPECAM_CHANNEL_NAME, name, NULL, 0);
485 if (cnv.entry == NULL)
488 "freerdp_load_channel_addin_entry did not return any function pointers for %s ",
490 return ERROR_INVALID_FUNCTION;
493 entryPoints.plugin = &ecam->iface;
494 entryPoints.pRegisterCameraHal = ecam_register_hal_plugin;
495 entryPoints.args = args;
496 entryPoints.ecam = ecam;
498 error = cnv.entry(&entryPoints);
501 WLog_ERR(TAG,
"%s entry returned error %" PRIu32
".", name, error);
505 WLog_INFO(TAG,
"Loaded %s HAL for ecam", name);
506 return CHANNEL_RC_OK;
514 FREERDP_ENTRY_POINT(UINT VCAPITYPE rdpecam_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints))
516 UINT error = CHANNEL_RC_INITIALIZATION_ERROR;
518 WINPR_ASSERT(pEntryPoints);
519 WINPR_ASSERT(pEntryPoints->GetPlugin);
523 return CHANNEL_RC_ALREADY_INITIALIZED;
529 WLog_ERR(TAG,
"calloc failed!");
530 return CHANNEL_RC_NO_MEMORY;
533 ecam->attached = TRUE;
534 ecam->iface.Initialize = ecam_plugin_initialize;
535 ecam->iface.Connected = NULL;
536 ecam->iface.Disconnected = NULL;
537 ecam->iface.Terminated = ecam_plugin_terminated;
538 ecam->iface.Attached = ecam_plugin_attached;
539 ecam->iface.Detached = ecam_plugin_detached;
542 #if defined(WITH_V4L)
543 ecam->subsystem =
"v4l";
545 ecam->subsystem = NULL;
550 if ((error = ecam_load_hal_plugin(ecam, ecam->subsystem, NULL )))
553 "Unable to load camera redirection subsystem %s because of error %" PRIu32
"",
554 ecam->subsystem, error);
559 error = pEntryPoints->RegisterPlugin(pEntryPoints, RDPECAM_CHANNEL_NAME, &ecam->iface);
560 if (error == CHANNEL_RC_OK)
564 ecam_plugin_terminated(&ecam->iface);
This struct contains function pointer to initialize/free objects.