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