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