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