20 #include <winpr/assert.h>
24 #define TAG CHANNELS_TAG("rdpecam-enum.client")
34 CAM_MSG_ID msg = CAM_MSG_ID_ErrorResponse;
38 wStream* s = Stream_New(NULL, CAM_HEADER_SIZE + 4);
41 WLog_ERR(TAG,
"Stream_New failed!");
42 return ERROR_NOT_ENOUGH_MEMORY;
45 Stream_Write_UINT8(s, ecam->version);
46 Stream_Write_UINT8(s, msg);
47 Stream_Write_UINT32(s, code);
49 return ecam_channel_write(ecam, hchannel, msg, s, TRUE);
62 wStream* s = Stream_New(NULL, CAM_HEADER_SIZE);
65 WLog_ERR(TAG,
"Stream_New failed!");
66 return ERROR_NOT_ENOUGH_MEMORY;
69 Stream_Write_UINT8(s, ecam->version);
70 Stream_Write_UINT8(s, msg);
72 return ecam_channel_write(ecam, hchannel, msg, s, TRUE);
83 if (!hchannel || !out)
84 return ERROR_INVALID_PARAMETER;
86 Stream_SealLength(out);
87 WINPR_ASSERT(Stream_Length(out) <= UINT32_MAX);
89 WLog_DBG(TAG,
"ChannelId=%d, MessageId=0x%02" PRIx8
", Length=%d",
90 hchannel->channel_mgr->GetChannelId(hchannel->channel), msg, Stream_Length(out));
92 const UINT error = hchannel->channel->Write(hchannel->channel, (ULONG)Stream_Length(out),
93 Stream_Buffer(out), NULL);
96 Stream_Free(out, TRUE);
106 static UINT ecam_send_device_added_notification(
CameraPlugin* ecam,
108 const char* deviceName,
const char* channelName)
110 CAM_MSG_ID msg = CAM_MSG_ID_DeviceAddedNotification;
114 wStream* s = Stream_New(NULL, 256);
117 WLog_ERR(TAG,
"Stream_New failed!");
118 return ERROR_NOT_ENOUGH_MEMORY;
121 Stream_Write_UINT8(s, ecam->version);
122 Stream_Write_UINT8(s, msg);
124 size_t devNameLen = strlen(deviceName);
125 if (Stream_Write_UTF16_String_From_UTF8(s, devNameLen + 1, deviceName, devNameLen, TRUE) < 0)
127 Stream_Free(s, TRUE);
128 return ERROR_INTERNAL_ERROR;
130 Stream_Write(s, channelName, strlen(channelName) + 1);
132 return ecam_channel_write(ecam, hchannel, msg, s, TRUE);
141 const char* deviceId,
const char* deviceName)
143 WLog_DBG(TAG,
"deviceId=%s, deviceName=%s", deviceId, deviceName);
145 if (!HashTable_ContainsKey(ecam->devices, deviceId))
147 CameraDevice* dev = ecam_dev_create(ecam, deviceId, deviceName);
148 if (!HashTable_Insert(ecam->devices, deviceId, dev))
150 ecam_dev_destroy(dev);
151 return ERROR_INTERNAL_ERROR;
156 WLog_DBG(TAG,
"Device %s already exists", deviceId);
159 ecam_send_device_added_notification(ecam, hchannel, deviceName, deviceId );
161 return CHANNEL_RC_OK;
171 ecam->ihal->Enumerate(ecam->ihal, ecam_ihal_device_added_callback, ecam, hchannel);
173 return CHANNEL_RC_OK;
181 static UINT ecam_process_select_version_response(
CameraPlugin* ecam,
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;
213 static 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=%d, 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);
257 static 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);
274 static UINT ecam_on_close(IWTSVirtualChannelCallback* pChannelCallback)
277 WINPR_ASSERT(hchannel);
279 WLog_DBG(TAG,
"entered");
282 return CHANNEL_RC_OK;
290 static UINT ecam_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
291 IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept,
292 IWTSVirtualChannelCallback** ppCallback)
296 if (!hlistener || !hlistener->plugin)
297 return ERROR_INTERNAL_ERROR;
299 WLog_DBG(TAG,
"entered");
305 WLog_ERR(TAG,
"calloc failed!");
306 return CHANNEL_RC_NO_MEMORY;
309 hchannel->iface.OnDataReceived = ecam_on_data_received;
310 hchannel->iface.OnOpen = ecam_on_open;
311 hchannel->iface.OnClose = ecam_on_close;
312 hchannel->plugin = hlistener->plugin;
313 hchannel->channel_mgr = hlistener->channel_mgr;
314 hchannel->channel = pChannel;
315 *ppCallback = (IWTSVirtualChannelCallback*)hchannel;
316 return CHANNEL_RC_OK;
319 static void ecam_dev_destroy_pv(
void* obj)
322 ecam_dev_destroy(dev);
330 static UINT ecam_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
334 WLog_DBG(TAG,
"entered");
336 if (!ecam || !pChannelMgr)
337 return ERROR_INVALID_PARAMETER;
339 if (ecam->initialized)
341 WLog_ERR(TAG,
"[%s] plugin initialized twice, aborting", RDPECAM_CONTROL_DVC_CHANNEL_NAME);
342 return ERROR_INVALID_DATA;
345 ecam->version = ECAM_PROTO_VERSION;
347 ecam->devices = HashTable_New(FALSE);
350 WLog_ERR(TAG,
"HashTable_New failed!");
351 return CHANNEL_RC_NO_MEMORY;
354 HashTable_SetupForStringData(ecam->devices, FALSE);
356 wObject* obj = HashTable_ValueObject(ecam->devices);
358 obj->fnObjectFree = ecam_dev_destroy_pv;
362 if (!ecam->hlistener)
364 WLog_ERR(TAG,
"calloc failed!");
365 return CHANNEL_RC_NO_MEMORY;
368 ecam->hlistener->iface.OnNewChannelConnection = ecam_on_new_channel_connection;
369 ecam->hlistener->plugin = pPlugin;
370 ecam->hlistener->channel_mgr = pChannelMgr;
371 const UINT rc = pChannelMgr->CreateListener(pChannelMgr, RDPECAM_CONTROL_DVC_CHANNEL_NAME, 0,
372 &ecam->hlistener->iface, &ecam->listener);
374 ecam->initialized = (rc == CHANNEL_RC_OK);
383 static UINT ecam_plugin_terminated(IWTSPlugin* pPlugin)
388 return ERROR_INVALID_DATA;
390 WLog_DBG(TAG,
"entered");
394 IWTSVirtualChannelManager* mgr = ecam->hlistener->channel_mgr;
396 IFCALL(mgr->DestroyListener, mgr, ecam->listener);
399 free(ecam->hlistener);
401 HashTable_Free(ecam->devices);
404 ecam->ihal->Free(ecam->ihal);
407 return CHANNEL_RC_OK;
415 static UINT ecam_plugin_attached(IWTSPlugin* pPlugin)
418 UINT error = CHANNEL_RC_OK;
421 return ERROR_INVALID_PARAMETER;
423 ecam->attached = TRUE;
432 static UINT ecam_plugin_detached(IWTSPlugin* pPlugin)
435 UINT error = CHANNEL_RC_OK;
438 return ERROR_INVALID_PARAMETER;
440 ecam->attached = FALSE;
449 static UINT ecam_register_hal_plugin(IWTSPlugin* pPlugin, ICamHal* ihal)
457 WLog_DBG(TAG,
"already registered");
458 return ERROR_ALREADY_EXISTS;
461 WLog_DBG(TAG,
"HAL registered");
463 return CHANNEL_RC_OK;
476 UINT error = ERROR_INTERNAL_ERROR;
479 PVIRTUALCHANNELENTRY pvce;
480 const PFREERDP_CAMERA_HAL_ENTRY entry;
482 cnv.pvce = freerdp_load_channel_addin_entry(RDPECAM_CHANNEL_NAME, name, NULL, 0);
484 if (cnv.entry == NULL)
487 "freerdp_load_channel_addin_entry did not return any function pointers for %s ",
489 return ERROR_INVALID_FUNCTION;
492 entryPoints.plugin = &ecam->iface;
493 entryPoints.pRegisterCameraHal = ecam_register_hal_plugin;
494 entryPoints.args = args;
495 entryPoints.ecam = ecam;
497 error = cnv.entry(&entryPoints);
500 WLog_ERR(TAG,
"%s entry returned error %" PRIu32
".", name, error);
504 WLog_INFO(TAG,
"Loaded %s HAL for ecam", name);
505 return CHANNEL_RC_OK;
513 FREERDP_ENTRY_POINT(UINT VCAPITYPE rdpecam_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints))
515 UINT error = CHANNEL_RC_INITIALIZATION_ERROR;
517 WINPR_ASSERT(pEntryPoints);
518 WINPR_ASSERT(pEntryPoints->GetPlugin);
522 return CHANNEL_RC_ALREADY_INITIALIZED;
528 WLog_ERR(TAG,
"calloc failed!");
529 return CHANNEL_RC_NO_MEMORY;
532 ecam->attached = TRUE;
533 ecam->iface.Initialize = ecam_plugin_initialize;
534 ecam->iface.Connected = NULL;
535 ecam->iface.Disconnected = NULL;
536 ecam->iface.Terminated = ecam_plugin_terminated;
537 ecam->iface.Attached = ecam_plugin_attached;
538 ecam->iface.Detached = ecam_plugin_detached;
541 #if defined(WITH_V4L)
542 ecam->subsystem =
"v4l";
544 ecam->subsystem = NULL;
549 if ((error = ecam_load_hal_plugin(ecam, ecam->subsystem, NULL )))
552 "Unable to load camera redirection subsystem %s because of error %" PRIu32
"",
553 ecam->subsystem, error);
558 error = pEntryPoints->RegisterPlugin(pEntryPoints, RDPECAM_CHANNEL_NAME, &ecam->iface);
559 if (error == CHANNEL_RC_OK)
563 ecam_plugin_terminated(&ecam->iface);
This struct contains function pointer to initialize/free objects.