FreeRDP
Loading...
Searching...
No Matches
server/camera_device_main.c
1
20#include <winpr/cast.h>
21
22#include <freerdp/config.h>
23
24#include <freerdp/freerdp.h>
25#include <freerdp/channels/log.h>
26#include <freerdp/server/rdpecam.h>
27
28#include "rdpecam-utils.h"
29
30#define TAG CHANNELS_TAG("rdpecam.server")
31
32typedef enum
33{
34 CAMERA_DEVICE_INITIAL,
35 CAMERA_DEVICE_OPENED,
36} eCameraDeviceChannelState;
37
38typedef struct
39{
40 CameraDeviceServerContext context;
41
42 HANDLE stopEvent;
43
44 HANDLE thread;
45 void* device_channel;
46
47 DWORD SessionId;
48
49 BOOL isOpened;
50 BOOL externalThread;
51
52 /* Channel state */
53 eCameraDeviceChannelState state;
54
55 wStream* buffer;
56} device_server;
57
58static UINT device_server_initialize(CameraDeviceServerContext* context, BOOL externalThread)
59{
60 UINT error = CHANNEL_RC_OK;
61 device_server* device = (device_server*)context;
62
63 WINPR_ASSERT(device);
64
65 if (device->isOpened)
66 {
67 WLog_WARN(TAG, "Application error: Camera channel already initialized, "
68 "calling in this state is not possible!");
69 return ERROR_INVALID_STATE;
70 }
71
72 device->externalThread = externalThread;
73
74 return error;
75}
76
77static UINT device_server_open_channel(device_server* device)
78{
79 CameraDeviceServerContext* context = &device->context;
80 DWORD Error = ERROR_SUCCESS;
81 HANDLE hEvent = nullptr;
82 DWORD BytesReturned = 0;
83 PULONG pSessionId = nullptr;
84 UINT32 channelId = 0;
85 BOOL status = TRUE;
86
87 WINPR_ASSERT(device);
88
89 if (WTSQuerySessionInformationA(device->context.vcm, WTS_CURRENT_SESSION, WTSSessionId,
90 (LPSTR*)&pSessionId, &BytesReturned) == FALSE)
91 {
92 WLog_ERR(TAG, "WTSQuerySessionInformationA failed!");
93 return ERROR_INTERNAL_ERROR;
94 }
95
96 device->SessionId = (DWORD)*pSessionId;
97 WTSFreeMemory(pSessionId);
98 hEvent = WTSVirtualChannelManagerGetEventHandle(device->context.vcm);
99
100 if (WaitForSingleObject(hEvent, 1000) == WAIT_FAILED)
101 {
102 Error = GetLastError();
103 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", Error);
104 return Error;
105 }
106
107 device->device_channel = WTSVirtualChannelOpenEx(device->SessionId, context->virtualChannelName,
108 WTS_CHANNEL_OPTION_DYNAMIC);
109 if (!device->device_channel)
110 {
111 Error = GetLastError();
112 WLog_ERR(TAG, "WTSVirtualChannelOpenEx failed with error %" PRIu32 "!", Error);
113 return Error;
114 }
115
116 channelId = WTSChannelGetIdByHandle(device->device_channel);
117
118 IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
119 if (!status)
120 {
121 WLog_ERR(TAG, "context->ChannelIdAssigned failed!");
122 return ERROR_INTERNAL_ERROR;
123 }
124
125 return Error;
126}
127
128static UINT device_server_handle_success_response(CameraDeviceServerContext* context,
129 WINPR_ATTR_UNUSED wStream* s,
130 const CAM_SHARED_MSG_HEADER* header)
131{
132 CAM_SUCCESS_RESPONSE pdu = WINPR_C_ARRAY_INIT;
133 UINT error = CHANNEL_RC_OK;
134
135 WINPR_ASSERT(context);
136 WINPR_ASSERT(header);
137
138 pdu.Header = *header;
139
140 IFCALLRET(context->SuccessResponse, error, context, &pdu);
141 if (error)
142 WLog_ERR(TAG, "context->SuccessResponse failed with error %" PRIu32 "", error);
143
144 return error;
145}
146
147static UINT device_server_recv_error_response(CameraDeviceServerContext* context, wStream* s,
148 const CAM_SHARED_MSG_HEADER* header)
149{
150 CAM_ERROR_RESPONSE pdu = WINPR_C_ARRAY_INIT;
151 UINT error = CHANNEL_RC_OK;
152
153 WINPR_ASSERT(context);
154 WINPR_ASSERT(header);
155
156 pdu.Header = *header;
157
158 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
159 return ERROR_NO_DATA;
160
161 {
162 const UINT32 val = Stream_Get_UINT32(s);
163 if (!rdpecam_valid_CamErrorCode(val))
164 return ERROR_INVALID_DATA;
165 pdu.ErrorCode = (CAM_ERROR_CODE)val;
166 }
167
168 IFCALLRET(context->ErrorResponse, error, context, &pdu);
169 if (error)
170 WLog_ERR(TAG, "context->ErrorResponse failed with error %" PRIu32 "", error);
171
172 return error;
173}
174
175static UINT device_server_recv_stream_list_response(CameraDeviceServerContext* context, wStream* s,
176 const CAM_SHARED_MSG_HEADER* header)
177{
178 CAM_STREAM_LIST_RESPONSE pdu = WINPR_C_ARRAY_INIT;
179 UINT error = CHANNEL_RC_OK;
180
181 WINPR_ASSERT(context);
182 WINPR_ASSERT(header);
183
184 pdu.Header = *header;
185
186 if (!Stream_CheckAndLogRequiredLength(TAG, s, 5))
187 return ERROR_NO_DATA;
188
189 pdu.N_Descriptions = 255;
190 const size_t len = Stream_GetRemainingLength(s) / 5;
191 if (len < 255)
192 pdu.N_Descriptions = (BYTE)len;
193
194 for (BYTE i = 0; i < pdu.N_Descriptions; ++i)
195 {
196 CAM_STREAM_DESCRIPTION* StreamDescription = &pdu.StreamDescriptions[i];
197
198 {
199 const UINT16 val = Stream_Get_UINT16(s);
200 if (!rdpecam_valid_CamStreamFrameSourceType(val))
201 return ERROR_INVALID_DATA;
202 StreamDescription->FrameSourceTypes = (CAM_STREAM_FRAME_SOURCE_TYPES)val;
203 }
204 {
205 const UINT8 val = Stream_Get_UINT8(s);
206 if (!rdpecam_valid_CamStreamCategory(val))
207 return ERROR_INVALID_DATA;
208 StreamDescription->StreamCategory = (CAM_STREAM_CATEGORY)val;
209 }
210 Stream_Read_UINT8(s, StreamDescription->Selected);
211 Stream_Read_UINT8(s, StreamDescription->CanBeShared);
212 }
213
214 IFCALLRET(context->StreamListResponse, error, context, &pdu);
215 if (error)
216 WLog_ERR(TAG, "context->StreamListResponse failed with error %" PRIu32 "", error);
217
218 return error;
219}
220
221static UINT device_server_recv_media_type_list_response(CameraDeviceServerContext* context,
222 wStream* s,
223 const CAM_SHARED_MSG_HEADER* header)
224{
225 CAM_MEDIA_TYPE_LIST_RESPONSE pdu = WINPR_C_ARRAY_INIT;
226 UINT error = CHANNEL_RC_OK;
227
228 WINPR_ASSERT(context);
229 WINPR_ASSERT(header);
230
231 pdu.Header = *header;
232
233 if (!Stream_CheckAndLogRequiredLength(TAG, s, 26))
234 return ERROR_NO_DATA;
235
236 pdu.N_Descriptions = Stream_GetRemainingLength(s) / 26;
237
238 pdu.MediaTypeDescriptions = calloc(pdu.N_Descriptions, sizeof(CAM_MEDIA_TYPE_DESCRIPTION));
239 if (!pdu.MediaTypeDescriptions)
240 {
241 WLog_ERR(TAG, "Failed to allocate %zu CAM_MEDIA_TYPE_DESCRIPTION structs",
242 pdu.N_Descriptions);
243 return ERROR_NOT_ENOUGH_MEMORY;
244 }
245
246 for (size_t i = 0; i < pdu.N_Descriptions; ++i)
247 {
248 CAM_MEDIA_TYPE_DESCRIPTION* MediaTypeDescriptions = &pdu.MediaTypeDescriptions[i];
249
250 {
251 const UINT8 val = Stream_Get_UINT8(s);
252 if (!rdpecam_valid_CamMediaFormat(val))
253 {
254 free(pdu.MediaTypeDescriptions);
255 return ERROR_INVALID_DATA;
256 }
257 MediaTypeDescriptions->Format = (CAM_MEDIA_FORMAT)val;
258 }
259 Stream_Read_UINT32(s, MediaTypeDescriptions->Width);
260 Stream_Read_UINT32(s, MediaTypeDescriptions->Height);
261 Stream_Read_UINT32(s, MediaTypeDescriptions->FrameRateNumerator);
262 Stream_Read_UINT32(s, MediaTypeDescriptions->FrameRateDenominator);
263 Stream_Read_UINT32(s, MediaTypeDescriptions->PixelAspectRatioNumerator);
264 Stream_Read_UINT32(s, MediaTypeDescriptions->PixelAspectRatioDenominator);
265 {
266 const UINT8 val = Stream_Get_UINT8(s);
267 if (!rdpecam_valid_MediaTypeDescriptionFlags(val))
268 {
269 free(pdu.MediaTypeDescriptions);
270 return ERROR_INVALID_DATA;
271 }
272 MediaTypeDescriptions->Flags = (CAM_MEDIA_TYPE_DESCRIPTION_FLAGS)val;
273 }
274 }
275
276 IFCALLRET(context->MediaTypeListResponse, error, context, &pdu);
277 if (error)
278 WLog_ERR(TAG, "context->MediaTypeListResponse failed with error %" PRIu32 "", error);
279
280 free(pdu.MediaTypeDescriptions);
281
282 return error;
283}
284
285static UINT device_server_recv_current_media_type_response(CameraDeviceServerContext* context,
286 wStream* s,
287 const CAM_SHARED_MSG_HEADER* header)
288{
289 CAM_CURRENT_MEDIA_TYPE_RESPONSE pdu = WINPR_C_ARRAY_INIT;
290 UINT error = CHANNEL_RC_OK;
291
292 WINPR_ASSERT(context);
293 WINPR_ASSERT(header);
294
295 pdu.Header = *header;
296
297 if (!Stream_CheckAndLogRequiredLength(TAG, s, 26))
298 return ERROR_NO_DATA;
299
300 {
301 const UINT8 val = Stream_Get_UINT8(s);
302 if (!rdpecam_valid_CamMediaFormat(val))
303 return ERROR_INVALID_DATA;
304 pdu.MediaTypeDescription.Format = (CAM_MEDIA_FORMAT)val;
305 }
306
307 Stream_Read_UINT32(s, pdu.MediaTypeDescription.Width);
308 Stream_Read_UINT32(s, pdu.MediaTypeDescription.Height);
309 Stream_Read_UINT32(s, pdu.MediaTypeDescription.FrameRateNumerator);
310 Stream_Read_UINT32(s, pdu.MediaTypeDescription.FrameRateDenominator);
311 Stream_Read_UINT32(s, pdu.MediaTypeDescription.PixelAspectRatioNumerator);
312 Stream_Read_UINT32(s, pdu.MediaTypeDescription.PixelAspectRatioDenominator);
313 {
314 const UINT8 val = Stream_Get_UINT8(s);
315 if (!rdpecam_valid_MediaTypeDescriptionFlags(val))
316 return ERROR_INVALID_DATA;
317 pdu.MediaTypeDescription.Flags = (CAM_MEDIA_TYPE_DESCRIPTION_FLAGS)val;
318 }
319
320 IFCALLRET(context->CurrentMediaTypeResponse, error, context, &pdu);
321 if (error)
322 WLog_ERR(TAG, "context->CurrentMediaTypeResponse failed with error %" PRIu32 "", error);
323
324 return error;
325}
326
327static UINT device_server_recv_sample_response(CameraDeviceServerContext* context, wStream* s,
328 const CAM_SHARED_MSG_HEADER* header)
329{
330 CAM_SAMPLE_RESPONSE pdu = WINPR_C_ARRAY_INIT;
331 UINT error = CHANNEL_RC_OK;
332
333 WINPR_ASSERT(context);
334 WINPR_ASSERT(header);
335
336 pdu.Header = *header;
337
338 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
339 return ERROR_NO_DATA;
340
341 Stream_Read_UINT8(s, pdu.StreamIndex);
342
343 pdu.SampleSize = Stream_GetRemainingLength(s);
344 pdu.Sample = Stream_Pointer(s);
345
346 IFCALLRET(context->SampleResponse, error, context, &pdu);
347 if (error)
348 WLog_ERR(TAG, "context->SampleResponse failed with error %" PRIu32 "", error);
349
350 return error;
351}
352
353static UINT device_server_recv_sample_error_response(CameraDeviceServerContext* context, wStream* s,
354 const CAM_SHARED_MSG_HEADER* header)
355{
356 CAM_SAMPLE_ERROR_RESPONSE pdu = WINPR_C_ARRAY_INIT;
357 UINT error = CHANNEL_RC_OK;
358
359 WINPR_ASSERT(context);
360 WINPR_ASSERT(header);
361
362 pdu.Header = *header;
363
364 if (!Stream_CheckAndLogRequiredLength(TAG, s, 5))
365 return ERROR_NO_DATA;
366
367 Stream_Read_UINT8(s, pdu.StreamIndex);
368 {
369 const UINT32 val = Stream_Get_UINT32(s);
370 if (!rdpecam_valid_CamErrorCode(val))
371 return ERROR_INVALID_DATA;
372 pdu.ErrorCode = (CAM_ERROR_CODE)val;
373 }
374
375 IFCALLRET(context->SampleErrorResponse, error, context, &pdu);
376 if (error)
377 WLog_ERR(TAG, "context->SampleErrorResponse failed with error %" PRIu32 "", error);
378
379 return error;
380}
381
382static UINT device_server_recv_property_list_response(CameraDeviceServerContext* context,
383 wStream* s,
384 const CAM_SHARED_MSG_HEADER* header)
385{
386 CAM_PROPERTY_LIST_RESPONSE pdu = WINPR_C_ARRAY_INIT;
387 UINT error = ERROR_INVALID_DATA;
388
389 WINPR_ASSERT(context);
390 WINPR_ASSERT(header);
391
392 pdu.Header = *header;
393
394 pdu.N_Properties = Stream_GetRemainingLength(s) / 19;
395
396 if (pdu.N_Properties > 0)
397 {
398 pdu.Properties = calloc(pdu.N_Properties, sizeof(CAM_PROPERTY_DESCRIPTION));
399 if (!pdu.Properties)
400 {
401 WLog_ERR(TAG, "Failed to allocate %zu CAM_PROPERTY_DESCRIPTION structs",
402 pdu.N_Properties);
403 return ERROR_NOT_ENOUGH_MEMORY;
404 }
405
406 for (size_t i = 0; i < pdu.N_Properties; ++i)
407 {
408 CAM_PROPERTY_DESCRIPTION* cur = &pdu.Properties[i];
409 {
410 const UINT8 val = Stream_Get_UINT8(s);
411 if (!rdpecam_valid_CamPropertySet(val))
412 goto fail;
413 cur->PropertySet = (CAM_PROPERTY_SET)val;
414 }
415 cur->PropertyId = Stream_Get_UINT8(s);
416 cur->Capabilities = Stream_Get_UINT8(s);
417 if (!rdpecam_valid_CamPropertyCapabilities(cur->Capabilities))
418 goto fail;
419 cur->MinValue = Stream_Get_INT32(s);
420 cur->MaxValue = Stream_Get_INT32(s);
421 cur->Step = Stream_Get_INT32(s);
422 cur->DefaultValue = Stream_Get_INT32(s);
423 }
424 }
425
426 error = IFCALLRESULT(CHANNEL_RC_OK, context->PropertyListResponse, context, &pdu);
427
428fail:
429 if (error)
430 WLog_ERR(TAG, "context->PropertyListResponse failed with error %" PRIu32 "", error);
431
432 free(pdu.Properties);
433
434 return error;
435}
436
437static UINT device_server_recv_property_value_response(CameraDeviceServerContext* context,
438 wStream* s,
439 const CAM_SHARED_MSG_HEADER* header)
440{
441 CAM_PROPERTY_VALUE_RESPONSE pdu = WINPR_C_ARRAY_INIT;
442 UINT error = CHANNEL_RC_OK;
443
444 WINPR_ASSERT(context);
445 WINPR_ASSERT(header);
446
447 pdu.Header = *header;
448
449 if (!Stream_CheckAndLogRequiredLength(TAG, s, 5))
450 return ERROR_NO_DATA;
451
452 {
453 const UINT8 val = Stream_Get_UINT8(s);
454 if (!rdpecam_valid_CamPropertyMode(val))
455 return ERROR_INVALID_DATA;
456 pdu.PropertyValue.Mode = (CAM_PROPERTY_MODE)val;
457 }
458
459 Stream_Read_INT32(s, pdu.PropertyValue.Value);
460
461 IFCALLRET(context->PropertyValueResponse, error, context, &pdu);
462 if (error)
463 WLog_ERR(TAG, "context->PropertyValueResponse failed with error %" PRIu32 "", error);
464
465 return error;
466}
467
468static UINT device_process_message(device_server* device)
469{
470 BOOL rc = 0;
471 UINT error = ERROR_INTERNAL_ERROR;
472 ULONG BytesReturned = 0;
473 CAM_SHARED_MSG_HEADER header = WINPR_C_ARRAY_INIT;
474 wStream* s = nullptr;
475
476 WINPR_ASSERT(device);
477 WINPR_ASSERT(device->device_channel);
478
479 s = device->buffer;
480 WINPR_ASSERT(s);
481
482 Stream_ResetPosition(s);
483 rc = WTSVirtualChannelRead(device->device_channel, 0, nullptr, 0, &BytesReturned);
484 if (!rc)
485 goto out;
486
487 if (BytesReturned < 1)
488 {
489 error = CHANNEL_RC_OK;
490 goto out;
491 }
492
493 if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
494 {
495 WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
496 error = CHANNEL_RC_NO_MEMORY;
497 goto out;
498 }
499
500 if (WTSVirtualChannelRead(device->device_channel, 0, Stream_BufferAs(s, char),
501 (ULONG)Stream_Capacity(s), &BytesReturned) == FALSE)
502 {
503 WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
504 goto out;
505 }
506
507 if (!Stream_SetLength(s, BytesReturned))
508 goto out;
509
510 if (!Stream_CheckAndLogRequiredLength(TAG, s, CAM_HEADER_SIZE))
511 return ERROR_NO_DATA;
512
513 Stream_Read_UINT8(s, header.Version);
514 {
515 const UINT8 id = Stream_Get_UINT8(s);
516 if (!rdpecam_valid_messageId(id))
517 return ERROR_INVALID_DATA;
518 header.MessageId = (CAM_MSG_ID)id;
519 }
520
521 switch (header.MessageId)
522 {
523 case CAM_MSG_ID_SuccessResponse:
524 error = device_server_handle_success_response(&device->context, s, &header);
525 break;
526 case CAM_MSG_ID_ErrorResponse:
527 error = device_server_recv_error_response(&device->context, s, &header);
528 break;
529 case CAM_MSG_ID_StreamListResponse:
530 error = device_server_recv_stream_list_response(&device->context, s, &header);
531 break;
532 case CAM_MSG_ID_MediaTypeListResponse:
533 error = device_server_recv_media_type_list_response(&device->context, s, &header);
534 break;
535 case CAM_MSG_ID_CurrentMediaTypeResponse:
536 error = device_server_recv_current_media_type_response(&device->context, s, &header);
537 break;
538 case CAM_MSG_ID_SampleResponse:
539 error = device_server_recv_sample_response(&device->context, s, &header);
540 break;
541 case CAM_MSG_ID_SampleErrorResponse:
542 error = device_server_recv_sample_error_response(&device->context, s, &header);
543 break;
544 case CAM_MSG_ID_PropertyListResponse:
545 error = device_server_recv_property_list_response(&device->context, s, &header);
546 break;
547 case CAM_MSG_ID_PropertyValueResponse:
548 error = device_server_recv_property_value_response(&device->context, s, &header);
549 break;
550 default:
551 WLog_ERR(TAG, "device_process_message: unknown or invalid MessageId %" PRIu8 "",
552 header.MessageId);
553 break;
554 }
555
556out:
557 if (error)
558 WLog_ERR(TAG, "Response failed with error %" PRIu32 "!", error);
559
560 return error;
561}
562
563static UINT device_server_context_poll_int(CameraDeviceServerContext* context)
564{
565 device_server* device = (device_server*)context;
566 UINT error = ERROR_INTERNAL_ERROR;
567
568 WINPR_ASSERT(device);
569
570 switch (device->state)
571 {
572 case CAMERA_DEVICE_INITIAL:
573 error = device_server_open_channel(device);
574 if (error)
575 WLog_ERR(TAG, "device_server_open_channel failed with error %" PRIu32 "!", error);
576 else
577 device->state = CAMERA_DEVICE_OPENED;
578 break;
579 case CAMERA_DEVICE_OPENED:
580 error = device_process_message(device);
581 break;
582 default:
583 break;
584 }
585
586 return error;
587}
588
589static HANDLE device_server_get_channel_handle(device_server* device)
590{
591 void* buffer = nullptr;
592 DWORD BytesReturned = 0;
593 HANDLE ChannelEvent = nullptr;
594
595 WINPR_ASSERT(device);
596
597 if (WTSVirtualChannelQuery(device->device_channel, WTSVirtualEventHandle, &buffer,
598 &BytesReturned) == TRUE)
599 {
600 if (BytesReturned == sizeof(HANDLE))
601 ChannelEvent = *(HANDLE*)buffer;
602
603 WTSFreeMemory(buffer);
604 }
605
606 return ChannelEvent;
607}
608
609static DWORD WINAPI device_server_thread_func(LPVOID arg)
610{
611 DWORD nCount = 0;
612 HANDLE events[2] = WINPR_C_ARRAY_INIT;
613 device_server* device = (device_server*)arg;
614 UINT error = CHANNEL_RC_OK;
615 DWORD status = 0;
616
617 WINPR_ASSERT(device);
618
619 nCount = 0;
620 events[nCount++] = device->stopEvent;
621
622 while ((error == CHANNEL_RC_OK) && (WaitForSingleObject(events[0], 0) != WAIT_OBJECT_0))
623 {
624 switch (device->state)
625 {
626 case CAMERA_DEVICE_INITIAL:
627 error = device_server_context_poll_int(&device->context);
628 if (error == CHANNEL_RC_OK)
629 {
630 events[1] = device_server_get_channel_handle(device);
631 nCount = 2;
632 }
633 break;
634 case CAMERA_DEVICE_OPENED:
635 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
636 switch (status)
637 {
638 case WAIT_OBJECT_0:
639 break;
640 case WAIT_OBJECT_0 + 1:
641 case WAIT_TIMEOUT:
642 error = device_server_context_poll_int(&device->context);
643 break;
644
645 case WAIT_FAILED:
646 default:
647 error = ERROR_INTERNAL_ERROR;
648 break;
649 }
650 break;
651 default:
652 break;
653 }
654 }
655
656 (void)WTSVirtualChannelClose(device->device_channel);
657 device->device_channel = nullptr;
658
659 if (error && device->context.rdpcontext)
660 setChannelError(device->context.rdpcontext, error,
661 "device_server_thread_func reported an error");
662
663 ExitThread(error);
664 return error;
665}
666
667static UINT device_server_open(CameraDeviceServerContext* context)
668{
669 device_server* device = (device_server*)context;
670
671 WINPR_ASSERT(device);
672
673 if (!device->externalThread && (device->thread == nullptr))
674 {
675 device->stopEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
676 if (!device->stopEvent)
677 {
678 WLog_ERR(TAG, "CreateEvent failed!");
679 return ERROR_INTERNAL_ERROR;
680 }
681
682 device->thread = CreateThread(nullptr, 0, device_server_thread_func, device, 0, nullptr);
683 if (!device->thread)
684 {
685 WLog_ERR(TAG, "CreateThread failed!");
686 (void)CloseHandle(device->stopEvent);
687 device->stopEvent = nullptr;
688 return ERROR_INTERNAL_ERROR;
689 }
690 }
691 device->isOpened = TRUE;
692
693 return CHANNEL_RC_OK;
694}
695
696static UINT device_server_close(CameraDeviceServerContext* context)
697{
698 UINT error = CHANNEL_RC_OK;
699 device_server* device = (device_server*)context;
700
701 WINPR_ASSERT(device);
702
703 if (!device->externalThread && device->thread)
704 {
705 (void)SetEvent(device->stopEvent);
706
707 if (WaitForSingleObject(device->thread, INFINITE) == WAIT_FAILED)
708 {
709 error = GetLastError();
710 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
711 return error;
712 }
713
714 (void)CloseHandle(device->thread);
715 (void)CloseHandle(device->stopEvent);
716 device->thread = nullptr;
717 device->stopEvent = nullptr;
718 }
719 if (device->externalThread)
720 {
721 if (device->state != CAMERA_DEVICE_INITIAL)
722 {
723 (void)WTSVirtualChannelClose(device->device_channel);
724 device->device_channel = nullptr;
725 device->state = CAMERA_DEVICE_INITIAL;
726 }
727 }
728 device->isOpened = FALSE;
729
730 return error;
731}
732
733static UINT device_server_context_poll(CameraDeviceServerContext* context)
734{
735 device_server* device = (device_server*)context;
736
737 WINPR_ASSERT(device);
738
739 if (!device->externalThread)
740 return ERROR_INTERNAL_ERROR;
741
742 return device_server_context_poll_int(context);
743}
744
745static BOOL device_server_context_handle(CameraDeviceServerContext* context, HANDLE* handle)
746{
747 device_server* device = (device_server*)context;
748
749 WINPR_ASSERT(device);
750 WINPR_ASSERT(handle);
751
752 if (!device->externalThread)
753 return FALSE;
754 if (device->state == CAMERA_DEVICE_INITIAL)
755 return FALSE;
756
757 *handle = device_server_get_channel_handle(device);
758
759 return TRUE;
760}
761
762static wStream* device_server_packet_new(size_t size, BYTE version, BYTE messageId)
763{
764 wStream* s = nullptr;
765
766 /* Allocate what we need plus header bytes */
767 s = Stream_New(nullptr, size + CAM_HEADER_SIZE);
768 if (!s)
769 {
770 WLog_ERR(TAG, "Stream_New failed!");
771 return nullptr;
772 }
773
774 Stream_Write_UINT8(s, version);
775 Stream_Write_UINT8(s, messageId);
776
777 return s;
778}
779
780static UINT device_server_packet_send(CameraDeviceServerContext* context, wStream* s)
781{
782 device_server* device = (device_server*)context;
783 UINT error = CHANNEL_RC_OK;
784 ULONG written = 0;
785
786 WINPR_ASSERT(context);
787 WINPR_ASSERT(s);
788
789 const size_t len = Stream_GetPosition(s);
790 WINPR_ASSERT(len <= UINT32_MAX);
791 if (!WTSVirtualChannelWrite(device->device_channel, Stream_BufferAs(s, char), (UINT32)len,
792 &written))
793 {
794 WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
795 error = ERROR_INTERNAL_ERROR;
796 goto out;
797 }
798
799 if (written < Stream_GetPosition(s))
800 {
801 WLog_WARN(TAG, "Unexpected bytes written: %" PRIu32 "/%" PRIuz "", written,
802 Stream_GetPosition(s));
803 }
804
805out:
806 Stream_Free(s, TRUE);
807 return error;
808}
809
810static UINT device_server_write_and_send_header(CameraDeviceServerContext* context, BYTE messageId)
811{
812 wStream* s = nullptr;
813
814 WINPR_ASSERT(context);
815
816 s = device_server_packet_new(0, context->protocolVersion, messageId);
817 if (!s)
818 return ERROR_NOT_ENOUGH_MEMORY;
819
820 return device_server_packet_send(context, s);
821}
822
823static UINT device_send_activate_device_request_pdu(
824 CameraDeviceServerContext* context,
825 WINPR_ATTR_UNUSED const CAM_ACTIVATE_DEVICE_REQUEST* activateDeviceRequest)
826{
827 WINPR_ASSERT(context);
828
829 return device_server_write_and_send_header(context, CAM_MSG_ID_ActivateDeviceRequest);
830}
831
832static UINT device_send_deactivate_device_request_pdu(
833 CameraDeviceServerContext* context,
834 WINPR_ATTR_UNUSED const CAM_DEACTIVATE_DEVICE_REQUEST* deactivateDeviceRequest)
835{
836 WINPR_ASSERT(context);
837
838 return device_server_write_and_send_header(context, CAM_MSG_ID_DeactivateDeviceRequest);
839}
840
841static UINT device_send_stream_list_request_pdu(
842 CameraDeviceServerContext* context,
843 WINPR_ATTR_UNUSED const CAM_STREAM_LIST_REQUEST* streamListRequest)
844{
845 WINPR_ASSERT(context);
846
847 return device_server_write_and_send_header(context, CAM_MSG_ID_StreamListRequest);
848}
849
850static UINT
851device_send_media_type_list_request_pdu(CameraDeviceServerContext* context,
852 const CAM_MEDIA_TYPE_LIST_REQUEST* mediaTypeListRequest)
853{
854 wStream* s = nullptr;
855
856 WINPR_ASSERT(context);
857 WINPR_ASSERT(mediaTypeListRequest);
858
859 s = device_server_packet_new(1, context->protocolVersion, CAM_MSG_ID_MediaTypeListRequest);
860 if (!s)
861 return ERROR_NOT_ENOUGH_MEMORY;
862
863 Stream_Write_UINT8(s, mediaTypeListRequest->StreamIndex);
864
865 return device_server_packet_send(context, s);
866}
867
868static UINT device_send_current_media_type_request_pdu(
869 CameraDeviceServerContext* context,
870 const CAM_CURRENT_MEDIA_TYPE_REQUEST* currentMediaTypeRequest)
871{
872 wStream* s = nullptr;
873
874 WINPR_ASSERT(context);
875 WINPR_ASSERT(currentMediaTypeRequest);
876
877 s = device_server_packet_new(1, context->protocolVersion, CAM_MSG_ID_CurrentMediaTypeRequest);
878 if (!s)
879 return ERROR_NOT_ENOUGH_MEMORY;
880
881 Stream_Write_UINT8(s, currentMediaTypeRequest->StreamIndex);
882
883 return device_server_packet_send(context, s);
884}
885
886static UINT
887device_send_start_streams_request_pdu(CameraDeviceServerContext* context,
888 const CAM_START_STREAMS_REQUEST* startStreamsRequest)
889{
890 wStream* s = nullptr;
891
892 WINPR_ASSERT(context);
893 WINPR_ASSERT(startStreamsRequest);
894
895 s = device_server_packet_new(startStreamsRequest->N_Infos * 27ul, context->protocolVersion,
896 CAM_MSG_ID_StartStreamsRequest);
897 if (!s)
898 return ERROR_NOT_ENOUGH_MEMORY;
899
900 for (size_t i = 0; i < startStreamsRequest->N_Infos; ++i)
901 {
902 const CAM_START_STREAM_INFO* info = &startStreamsRequest->StartStreamsInfo[i];
903 const CAM_MEDIA_TYPE_DESCRIPTION* description = &info->MediaTypeDescription;
904
905 Stream_Write_UINT8(s, info->StreamIndex);
906
907 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, description->Format));
908 Stream_Write_UINT32(s, description->Width);
909 Stream_Write_UINT32(s, description->Height);
910 Stream_Write_UINT32(s, description->FrameRateNumerator);
911 Stream_Write_UINT32(s, description->FrameRateDenominator);
912 Stream_Write_UINT32(s, description->PixelAspectRatioNumerator);
913 Stream_Write_UINT32(s, description->PixelAspectRatioDenominator);
914 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, description->Flags));
915 }
916
917 return device_server_packet_send(context, s);
918}
919
920static UINT device_send_stop_streams_request_pdu(
921 CameraDeviceServerContext* context,
922 WINPR_ATTR_UNUSED const CAM_STOP_STREAMS_REQUEST* stopStreamsRequest)
923{
924 WINPR_ASSERT(context);
925
926 return device_server_write_and_send_header(context, CAM_MSG_ID_StopStreamsRequest);
927}
928
929static UINT device_send_sample_request_pdu(CameraDeviceServerContext* context,
930 const CAM_SAMPLE_REQUEST* sampleRequest)
931{
932 wStream* s = nullptr;
933
934 WINPR_ASSERT(context);
935 WINPR_ASSERT(sampleRequest);
936
937 s = device_server_packet_new(1, context->protocolVersion, CAM_MSG_ID_SampleRequest);
938 if (!s)
939 return ERROR_NOT_ENOUGH_MEMORY;
940
941 Stream_Write_UINT8(s, sampleRequest->StreamIndex);
942
943 return device_server_packet_send(context, s);
944}
945
946static UINT device_send_property_list_request_pdu(
947 CameraDeviceServerContext* context,
948 WINPR_ATTR_UNUSED const CAM_PROPERTY_LIST_REQUEST* propertyListRequest)
949{
950 WINPR_ASSERT(context);
951
952 return device_server_write_and_send_header(context, CAM_MSG_ID_PropertyListRequest);
953}
954
955static UINT
956device_send_property_value_request_pdu(CameraDeviceServerContext* context,
957 const CAM_PROPERTY_VALUE_REQUEST* propertyValueRequest)
958{
959 wStream* s = nullptr;
960
961 WINPR_ASSERT(context);
962 WINPR_ASSERT(propertyValueRequest);
963
964 s = device_server_packet_new(2, context->protocolVersion, CAM_MSG_ID_PropertyValueRequest);
965 if (!s)
966 return ERROR_NOT_ENOUGH_MEMORY;
967
968 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, propertyValueRequest->PropertySet));
969 Stream_Write_UINT8(s, propertyValueRequest->PropertyId);
970
971 return device_server_packet_send(context, s);
972}
973
974static UINT device_send_set_property_value_request_pdu(
975 CameraDeviceServerContext* context,
976 const CAM_SET_PROPERTY_VALUE_REQUEST* setPropertyValueRequest)
977{
978 wStream* s = nullptr;
979
980 WINPR_ASSERT(context);
981 WINPR_ASSERT(setPropertyValueRequest);
982
983 s = device_server_packet_new(2 + 5, context->protocolVersion,
984 CAM_MSG_ID_SetPropertyValueRequest);
985 if (!s)
986 return ERROR_NOT_ENOUGH_MEMORY;
987
988 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, setPropertyValueRequest->PropertySet));
989 Stream_Write_UINT8(s, setPropertyValueRequest->PropertyId);
990
991 Stream_Write_UINT8(
992 s, WINPR_ASSERTING_INT_CAST(uint8_t, setPropertyValueRequest->PropertyValue.Mode));
993 Stream_Write_INT32(s, setPropertyValueRequest->PropertyValue.Value);
994
995 return device_server_packet_send(context, s);
996}
997
998CameraDeviceServerContext* camera_device_server_context_new(HANDLE vcm)
999{
1000 device_server* device = (device_server*)calloc(1, sizeof(device_server));
1001
1002 if (!device)
1003 return nullptr;
1004
1005 device->context.vcm = vcm;
1006 device->context.Initialize = device_server_initialize;
1007 device->context.Open = device_server_open;
1008 device->context.Close = device_server_close;
1009 device->context.Poll = device_server_context_poll;
1010 device->context.ChannelHandle = device_server_context_handle;
1011
1012 device->context.ActivateDeviceRequest = device_send_activate_device_request_pdu;
1013 device->context.DeactivateDeviceRequest = device_send_deactivate_device_request_pdu;
1014
1015 device->context.StreamListRequest = device_send_stream_list_request_pdu;
1016 device->context.MediaTypeListRequest = device_send_media_type_list_request_pdu;
1017 device->context.CurrentMediaTypeRequest = device_send_current_media_type_request_pdu;
1018
1019 device->context.StartStreamsRequest = device_send_start_streams_request_pdu;
1020 device->context.StopStreamsRequest = device_send_stop_streams_request_pdu;
1021 device->context.SampleRequest = device_send_sample_request_pdu;
1022
1023 device->context.PropertyListRequest = device_send_property_list_request_pdu;
1024 device->context.PropertyValueRequest = device_send_property_value_request_pdu;
1025 device->context.SetPropertyValueRequest = device_send_set_property_value_request_pdu;
1026
1027 device->buffer = Stream_New(nullptr, 4096);
1028 if (!device->buffer)
1029 goto fail;
1030
1031 return &device->context;
1032fail:
1033 WINPR_PRAGMA_DIAG_PUSH
1034 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1035 camera_device_server_context_free(&device->context);
1036 WINPR_PRAGMA_DIAG_POP
1037 return nullptr;
1038}
1039
1040void camera_device_server_context_free(CameraDeviceServerContext* context)
1041{
1042 device_server* device = (device_server*)context;
1043
1044 if (device)
1045 {
1046 device_server_close(context);
1047 Stream_Free(device->buffer, TRUE);
1048 }
1049
1050 free(context->virtualChannelName);
1051
1052 free(device);
1053}