FreeRDP
client/camera_device_main.c
1 
20 #include <winpr/assert.h>
21 
22 #include "camera.h"
23 
24 #define TAG CHANNELS_TAG("rdpecam-device.client")
25 
26 /* supported formats in preference order:
27  * H264, MJPG, I420 (used as input for H264 encoder), other YUV based, RGB based
28  */
29 static const CAM_MEDIA_FORMAT_INFO supportedFormats[] = {
30 /* inputFormat, outputFormat */
31 #if defined(WITH_INPUT_FORMAT_H264)
32  { CAM_MEDIA_FORMAT_H264, CAM_MEDIA_FORMAT_H264 }, /* passthrough */
33 #endif
34 #if defined(WITH_INPUT_FORMAT_MJPG)
35  { CAM_MEDIA_FORMAT_MJPG, CAM_MEDIA_FORMAT_H264 },
36 #endif
37  { CAM_MEDIA_FORMAT_I420, CAM_MEDIA_FORMAT_H264 },
38  { CAM_MEDIA_FORMAT_YUY2, CAM_MEDIA_FORMAT_H264 },
39  { CAM_MEDIA_FORMAT_NV12, CAM_MEDIA_FORMAT_H264 },
40  { CAM_MEDIA_FORMAT_RGB24, CAM_MEDIA_FORMAT_H264 },
41  { CAM_MEDIA_FORMAT_RGB32, CAM_MEDIA_FORMAT_H264 },
42 };
43 static const size_t nSupportedFormats = ARRAYSIZE(supportedFormats);
44 
45 static void ecam_dev_write_media_type(wStream* s, CAM_MEDIA_TYPE_DESCRIPTION* mediaType)
46 {
47  WINPR_ASSERT(mediaType);
48 
49  Stream_Write_UINT8(s, mediaType->Format);
50  Stream_Write_UINT32(s, mediaType->Width);
51  Stream_Write_UINT32(s, mediaType->Height);
52  Stream_Write_UINT32(s, mediaType->FrameRateNumerator);
53  Stream_Write_UINT32(s, mediaType->FrameRateDenominator);
54  Stream_Write_UINT32(s, mediaType->PixelAspectRatioNumerator);
55  Stream_Write_UINT32(s, mediaType->PixelAspectRatioDenominator);
56  Stream_Write_UINT8(s, mediaType->Flags);
57 }
58 
59 static BOOL ecam_dev_read_media_type(wStream* s, CAM_MEDIA_TYPE_DESCRIPTION* mediaType)
60 {
61  WINPR_ASSERT(mediaType);
62 
63  Stream_Read_UINT8(s, mediaType->Format);
64  Stream_Read_UINT32(s, mediaType->Width);
65  Stream_Read_UINT32(s, mediaType->Height);
66  Stream_Read_UINT32(s, mediaType->FrameRateNumerator);
67  Stream_Read_UINT32(s, mediaType->FrameRateDenominator);
68  Stream_Read_UINT32(s, mediaType->PixelAspectRatioNumerator);
69  Stream_Read_UINT32(s, mediaType->PixelAspectRatioDenominator);
70  Stream_Read_UINT8(s, mediaType->Flags);
71  return TRUE;
72 }
73 
74 static void ecam_dev_print_media_type(CAM_MEDIA_TYPE_DESCRIPTION* mediaType)
75 {
76  WINPR_ASSERT(mediaType);
77 
78  WLog_DBG(TAG, "Format: %d, width: %d, height: %d, fps: %d, flags: %d", mediaType->Format,
79  mediaType->Width, mediaType->Height, mediaType->FrameRateNumerator, mediaType->Flags);
80 }
81 
87 static UINT ecam_dev_send_sample_response(CameraDevice* dev, size_t streamIndex, const BYTE* sample,
88  size_t size)
89 {
90  WINPR_ASSERT(dev);
91 
92  CameraDeviceStream* stream = &dev->streams[streamIndex];
93  CAM_MSG_ID msg = CAM_MSG_ID_SampleResponse;
94 
95  Stream_SetPosition(stream->sampleRespBuffer, 0);
96 
97  Stream_Write_UINT8(stream->sampleRespBuffer, dev->ecam->version);
98  Stream_Write_UINT8(stream->sampleRespBuffer, msg);
99  Stream_Write_UINT8(stream->sampleRespBuffer, streamIndex);
100 
101  Stream_Write(stream->sampleRespBuffer, sample, size);
102 
103  /* channel write is protected by critical section in dvcman_write_channel */
104  return ecam_channel_write(dev->ecam, stream->hSampleReqChannel, msg, stream->sampleRespBuffer,
105  FALSE /* don't free stream */);
106 }
107 
113 static UINT ecam_dev_sample_captured_callback(CameraDevice* dev, int streamIndex,
114  const BYTE* sample, size_t size)
115 {
116  BYTE* encodedSample = NULL;
117  size_t encodedSize = 0;
118 
119  WINPR_ASSERT(dev);
120 
121  if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
122  return ERROR_INVALID_INDEX;
123 
124  CameraDeviceStream* stream = &dev->streams[streamIndex];
125 
126  if (!stream->streaming)
127  return CHANNEL_RC_OK;
128 
129  if (streamInputFormat(stream) != streamOutputFormat(stream))
130  {
131  if (!ecam_encoder_compress(stream, sample, size, &encodedSample, &encodedSize))
132  {
133  WLog_DBG(TAG, "Frame drop or error in ecam_encoder_compress");
134  return CHANNEL_RC_OK;
135  }
136 
137  if (!stream->streaming)
138  return CHANNEL_RC_OK;
139  }
140  else /* passthrough */
141  {
142  encodedSample = WINPR_CAST_CONST_PTR_AWAY(sample, BYTE*);
143  encodedSize = size;
144  }
145 
146  if (stream->nSampleCredits == 0)
147  {
148  WLog_DBG(TAG, "Skip sample: no credits left");
149  return CHANNEL_RC_OK;
150  }
151  stream->nSampleCredits--;
152 
153  return ecam_dev_send_sample_response(dev, streamIndex, encodedSample, encodedSize);
154 }
155 
156 static void ecam_dev_stop_stream(CameraDevice* dev, size_t streamIndex)
157 {
158  WINPR_ASSERT(dev);
159 
160  if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
161  return;
162 
163  CameraDeviceStream* stream = &dev->streams[streamIndex];
164 
165  if (stream->streaming)
166  {
167  stream->streaming = FALSE;
168  dev->ihal->StopStream(dev->ihal, dev->deviceId, 0);
169  }
170 
171  if (stream->sampleRespBuffer)
172  {
173  Stream_Free(stream->sampleRespBuffer, TRUE);
174  stream->sampleRespBuffer = NULL;
175  }
176 
177  ecam_encoder_context_free(stream);
178 }
179 
185 static UINT ecam_dev_process_stop_streams_request(CameraDevice* dev,
186  GENERIC_CHANNEL_CALLBACK* hchannel, wStream* s)
187 {
188  WINPR_ASSERT(dev);
189  WINPR_UNUSED(s);
190 
191  for (size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
192  ecam_dev_stop_stream(dev, i);
193 
194  return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
195 }
196 
202 static UINT ecam_dev_process_start_streams_request(CameraDevice* dev,
203  GENERIC_CHANNEL_CALLBACK* hchannel, wStream* s)
204 {
205  BYTE streamIndex = 0;
206  CAM_MEDIA_TYPE_DESCRIPTION mediaType = { 0 };
207 
208  WINPR_ASSERT(dev);
209 
210  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1 + 26))
211  return ERROR_INVALID_DATA;
212 
213  Stream_Read_UINT8(s, streamIndex);
214 
215  if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
216  {
217  WLog_ERR(TAG, "Incorrect streamIndex %" PRIuz, streamIndex);
218  ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_InvalidStreamNumber);
219  return ERROR_INVALID_INDEX;
220  }
221 
222  if (!ecam_dev_read_media_type(s, &mediaType))
223  {
224  WLog_ERR(TAG, "Unable to read MEDIA_TYPE_DESCRIPTION");
225  ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_InvalidMessage);
226  return ERROR_INVALID_DATA;
227  }
228 
229  ecam_dev_print_media_type(&mediaType);
230 
231  CameraDeviceStream* stream = &dev->streams[streamIndex];
232 
233  if (stream->streaming)
234  {
235  WLog_ERR(TAG, "Streaming already in progress, device %s, streamIndex %d", dev->deviceId,
236  streamIndex);
237  return CAM_ERROR_CODE_UnexpectedError;
238  }
239 
240  /* saving media type description for CurrentMediaTypeRequest,
241  * to be done before calling ecam_encoder_context_init
242  */
243  stream->currMediaType = mediaType;
244 
245  /* initialize encoder, if input and output formats differ */
246  if (streamInputFormat(stream) != streamOutputFormat(stream) &&
247  !ecam_encoder_context_init(stream))
248  {
249  WLog_ERR(TAG, "stream_ecam_encoder_init failed");
250  ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_UnexpectedError);
251  return ERROR_INVALID_DATA;
252  }
253 
254  stream->sampleRespBuffer = Stream_New(NULL, ECAM_SAMPLE_RESPONSE_BUFFER_SIZE);
255  if (!stream->sampleRespBuffer)
256  {
257  WLog_ERR(TAG, "Stream_New failed");
258  ecam_dev_stop_stream(dev, streamIndex);
259  ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_OutOfMemory);
260  return ERROR_INVALID_DATA;
261  }
262 
263  /* replacing outputFormat with inputFormat in mediaType before starting stream */
264  mediaType.Format = streamInputFormat(stream);
265 
266  stream->nSampleCredits = 0;
267 
268  UINT error = dev->ihal->StartStream(dev->ihal, dev, streamIndex, &mediaType,
269  ecam_dev_sample_captured_callback);
270  if (error)
271  {
272  WLog_ERR(TAG, "StartStream failure");
273  ecam_dev_stop_stream(dev, streamIndex);
274  ecam_channel_send_error_response(dev->ecam, hchannel, error);
275  return ERROR_INVALID_DATA;
276  }
277 
278  stream->streaming = TRUE;
279  return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
280 }
281 
287 static UINT ecam_dev_process_property_list_request(CameraDevice* dev,
288  GENERIC_CHANNEL_CALLBACK* hchannel, wStream* s)
289 {
290  WINPR_ASSERT(dev);
291  // TODO: supported properties implementation
292 
293  return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_PropertyListResponse);
294 }
295 
301 static UINT ecam_dev_send_current_media_type_response(CameraDevice* dev,
302  GENERIC_CHANNEL_CALLBACK* hchannel,
303  CAM_MEDIA_TYPE_DESCRIPTION* mediaType)
304 {
305  CAM_MSG_ID msg = CAM_MSG_ID_CurrentMediaTypeResponse;
306 
307  WINPR_ASSERT(dev);
308 
309  wStream* s = Stream_New(NULL, CAM_HEADER_SIZE + sizeof(CAM_MEDIA_TYPE_DESCRIPTION));
310  if (!s)
311  {
312  WLog_ERR(TAG, "Stream_New failed");
313  return ERROR_NOT_ENOUGH_MEMORY;
314  }
315 
316  Stream_Write_UINT8(s, dev->ecam->version);
317  Stream_Write_UINT8(s, msg);
318 
319  ecam_dev_write_media_type(s, mediaType);
320 
321  return ecam_channel_write(dev->ecam, hchannel, msg, s, TRUE);
322 }
323 
329 static UINT ecam_dev_process_sample_request(CameraDevice* dev, GENERIC_CHANNEL_CALLBACK* hchannel,
330  wStream* s)
331 {
332  BYTE streamIndex = 0;
333 
334  WINPR_ASSERT(dev);
335 
336  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
337  return ERROR_INVALID_DATA;
338 
339  Stream_Read_UINT8(s, streamIndex);
340 
341  if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
342  {
343  WLog_ERR(TAG, "Incorrect streamIndex %d", streamIndex);
344  ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_InvalidStreamNumber);
345  return ERROR_INVALID_INDEX;
346  }
347 
348  CameraDeviceStream* stream = &dev->streams[streamIndex];
349 
350  /* need to save channel because responses are asynchronous and coming from capture thread */
351  if (stream->hSampleReqChannel != hchannel)
352  stream->hSampleReqChannel = hchannel;
353 
354  /* allow to send that many unsolicited samples */
355  stream->nSampleCredits = ECAM_MAX_SAMPLE_CREDITS;
356 
357  return CHANNEL_RC_OK;
358 }
359 
365 static UINT ecam_dev_process_current_media_type_request(CameraDevice* dev,
366  GENERIC_CHANNEL_CALLBACK* hchannel,
367  wStream* s)
368 {
369  BYTE streamIndex = 0;
370 
371  WINPR_ASSERT(dev);
372 
373  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
374  return ERROR_INVALID_DATA;
375 
376  Stream_Read_UINT8(s, streamIndex);
377 
378  if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
379  {
380  WLog_ERR(TAG, "Incorrect streamIndex %d", streamIndex);
381  ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_InvalidStreamNumber);
382  return ERROR_INVALID_INDEX;
383  }
384 
385  CameraDeviceStream* stream = &dev->streams[streamIndex];
386 
387  if (stream->currMediaType.Format == 0)
388  {
389  WLog_ERR(TAG, "Current media type unknown for streamIndex %d", streamIndex);
390  ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_NotInitialized);
391  return ERROR_DEVICE_REINITIALIZATION_NEEDED;
392  }
393 
394  return ecam_dev_send_current_media_type_response(dev, hchannel, &stream->currMediaType);
395 }
396 
402 static UINT ecam_dev_send_media_type_list_response(CameraDevice* dev,
403  GENERIC_CHANNEL_CALLBACK* hchannel,
404  CAM_MEDIA_TYPE_DESCRIPTION* mediaTypes,
405  size_t nMediaTypes)
406 {
407  CAM_MSG_ID msg = CAM_MSG_ID_MediaTypeListResponse;
408 
409  WINPR_ASSERT(dev);
410 
411  wStream* s = Stream_New(NULL, CAM_HEADER_SIZE + ECAM_MAX_MEDIA_TYPE_DESCRIPTORS *
413  if (!s)
414  {
415  WLog_ERR(TAG, "Stream_New failed");
416  return ERROR_NOT_ENOUGH_MEMORY;
417  }
418 
419  Stream_Write_UINT8(s, dev->ecam->version);
420  Stream_Write_UINT8(s, msg);
421 
422  for (size_t i = 0; i < nMediaTypes; i++, mediaTypes++)
423  {
424  ecam_dev_write_media_type(s, mediaTypes);
425  }
426 
427  return ecam_channel_write(dev->ecam, hchannel, msg, s, TRUE);
428 }
429 
435 static UINT ecam_dev_process_media_type_list_request(CameraDevice* dev,
436  GENERIC_CHANNEL_CALLBACK* hchannel, wStream* s)
437 {
438  UINT error = CHANNEL_RC_OK;
439  BYTE streamIndex = 0;
440  CAM_MEDIA_TYPE_DESCRIPTION* mediaTypes = NULL;
441  size_t nMediaTypes = ECAM_MAX_MEDIA_TYPE_DESCRIPTORS;
442 
443  WINPR_ASSERT(dev);
444 
445  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
446  return ERROR_INVALID_DATA;
447 
448  Stream_Read_UINT8(s, streamIndex);
449 
450  if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
451  {
452  WLog_ERR(TAG, "Incorrect streamIndex %d", streamIndex);
453  ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_InvalidStreamNumber);
454  return ERROR_INVALID_INDEX;
455  }
456  CameraDeviceStream* stream = &dev->streams[streamIndex];
457 
458  mediaTypes =
459  (CAM_MEDIA_TYPE_DESCRIPTION*)calloc(nMediaTypes, sizeof(CAM_MEDIA_TYPE_DESCRIPTION));
460  if (!mediaTypes)
461  {
462  WLog_ERR(TAG, "calloc failed");
463  ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_OutOfMemory);
464  return CHANNEL_RC_NO_MEMORY;
465  }
466 
467  INT16 formatIndex =
468  dev->ihal->GetMediaTypeDescriptions(dev->ihal, dev->deviceId, streamIndex, supportedFormats,
469  nSupportedFormats, mediaTypes, &nMediaTypes);
470  if (formatIndex == -1 || nMediaTypes == 0)
471  {
472  WLog_ERR(TAG, "Camera doesn't support any compatible video formats");
473  ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_ItemNotFound);
474  error = ERROR_DEVICE_FEATURE_NOT_SUPPORTED;
475  goto error;
476  }
477 
478  stream->formats = supportedFormats[formatIndex];
479 
480  /* replacing inputFormat with outputFormat in mediaTypes before sending response */
481  for (size_t i = 0; i < nMediaTypes; i++)
482  {
483  mediaTypes[i].Format = streamOutputFormat(stream);
484  mediaTypes[i].Flags = CAM_MEDIA_TYPE_DESCRIPTION_FLAG_DecodingRequired;
485  }
486 
487  if (stream->currMediaType.Format == 0)
488  {
489  /* saving 1st media type description for CurrentMediaTypeRequest */
490  stream->currMediaType = mediaTypes[0];
491  }
492 
493  error = ecam_dev_send_media_type_list_response(dev, hchannel, mediaTypes, nMediaTypes);
494 
495 error:
496  free(mediaTypes);
497  return error;
498 }
499 
505 static UINT ecam_dev_send_stream_list_response(CameraDevice* dev,
506  GENERIC_CHANNEL_CALLBACK* hchannel)
507 {
508  CAM_MSG_ID msg = CAM_MSG_ID_StreamListResponse;
509 
510  WINPR_ASSERT(dev);
511 
512  wStream* s = Stream_New(NULL, CAM_HEADER_SIZE + sizeof(CAM_STREAM_DESCRIPTION));
513  if (!s)
514  {
515  WLog_ERR(TAG, "Stream_New failed");
516  return ERROR_NOT_ENOUGH_MEMORY;
517  }
518 
519  Stream_Write_UINT8(s, dev->ecam->version);
520  Stream_Write_UINT8(s, msg);
521 
522  /* single stream description */
523  Stream_Write_UINT16(s, CAM_STREAM_FRAME_SOURCE_TYPE_Color);
524  Stream_Write_UINT8(s, CAM_STREAM_CATEGORY_Capture);
525  Stream_Write_UINT8(s, TRUE /* Selected */);
526  Stream_Write_UINT8(s, FALSE /* CanBeShared */);
527 
528  return ecam_channel_write(dev->ecam, hchannel, msg, s, TRUE);
529 }
530 
536 static UINT ecam_dev_process_stream_list_request(CameraDevice* dev,
537  GENERIC_CHANNEL_CALLBACK* hchannel, wStream* s)
538 {
539  return ecam_dev_send_stream_list_response(dev, hchannel);
540 }
541 
547 static UINT ecam_dev_process_activate_device_request(CameraDevice* dev,
548  GENERIC_CHANNEL_CALLBACK* hchannel, wStream* s)
549 {
550  WINPR_ASSERT(dev);
551 
552  /* TODO: TBD if this is required */
553  return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
554 }
555 
561 static UINT ecam_dev_process_deactivate_device_request(CameraDevice* dev,
562  GENERIC_CHANNEL_CALLBACK* hchannel,
563  wStream* s)
564 {
565  WINPR_ASSERT(dev);
566  WINPR_UNUSED(s);
567 
568  for (size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
569  ecam_dev_stop_stream(dev, i);
570 
571  return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
572 }
573 
579 static UINT ecam_dev_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data)
580 {
581  UINT error = CHANNEL_RC_OK;
582  BYTE version = 0;
583  BYTE messageId = 0;
584  GENERIC_CHANNEL_CALLBACK* hchannel = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback;
585 
586  if (!hchannel || !data)
587  return ERROR_INVALID_PARAMETER;
588 
589  CameraDevice* dev = (CameraDevice*)hchannel->plugin;
590 
591  if (!dev)
592  return ERROR_INTERNAL_ERROR;
593 
594  if (!Stream_CheckAndLogRequiredCapacity(TAG, data, CAM_HEADER_SIZE))
595  return ERROR_NO_DATA;
596 
597  Stream_Read_UINT8(data, version);
598  Stream_Read_UINT8(data, messageId);
599  WLog_DBG(TAG, "ChannelId=%d, MessageId=0x%02" PRIx8 ", Version=%d",
600  hchannel->channel_mgr->GetChannelId(hchannel->channel), messageId, version);
601 
602  switch (messageId)
603  {
604  case CAM_MSG_ID_ActivateDeviceRequest:
605  error = ecam_dev_process_activate_device_request(dev, hchannel, data);
606  break;
607 
608  case CAM_MSG_ID_DeactivateDeviceRequest:
609  error = ecam_dev_process_deactivate_device_request(dev, hchannel, data);
610  break;
611 
612  case CAM_MSG_ID_StreamListRequest:
613  error = ecam_dev_process_stream_list_request(dev, hchannel, data);
614  break;
615 
616  case CAM_MSG_ID_MediaTypeListRequest:
617  error = ecam_dev_process_media_type_list_request(dev, hchannel, data);
618  break;
619 
620  case CAM_MSG_ID_CurrentMediaTypeRequest:
621  error = ecam_dev_process_current_media_type_request(dev, hchannel, data);
622  break;
623 
624  case CAM_MSG_ID_PropertyListRequest:
625  error = ecam_dev_process_property_list_request(dev, hchannel, data);
626  break;
627 
628  case CAM_MSG_ID_StartStreamsRequest:
629  error = ecam_dev_process_start_streams_request(dev, hchannel, data);
630  break;
631 
632  case CAM_MSG_ID_StopStreamsRequest:
633  error = ecam_dev_process_stop_streams_request(dev, hchannel, data);
634  break;
635 
636  case CAM_MSG_ID_SampleRequest:
637  error = ecam_dev_process_sample_request(dev, hchannel, data);
638  break;
639 
640  default:
641  WLog_WARN(TAG, "unknown MessageId=0x%02" PRIx8 "", messageId);
642  error = ERROR_INVALID_DATA;
643  ecam_channel_send_error_response(dev->ecam, hchannel,
644  CAM_ERROR_CODE_OperationNotSupported);
645  break;
646  }
647 
648  return error;
649 }
650 
656 static UINT ecam_dev_on_open(IWTSVirtualChannelCallback* pChannelCallback)
657 {
658  GENERIC_CHANNEL_CALLBACK* hchannel = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback;
659  WINPR_ASSERT(hchannel);
660 
661  CameraDevice* dev = (CameraDevice*)hchannel->plugin;
662  WINPR_ASSERT(dev);
663 
664  WLog_DBG(TAG, "entered");
665  return CHANNEL_RC_OK;
666 }
667 
673 static UINT ecam_dev_on_close(IWTSVirtualChannelCallback* pChannelCallback)
674 {
675  GENERIC_CHANNEL_CALLBACK* hchannel = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback;
676  WINPR_ASSERT(hchannel);
677 
678  CameraDevice* dev = (CameraDevice*)hchannel->plugin;
679  WINPR_ASSERT(dev);
680 
681  WLog_DBG(TAG, "entered");
682 
683  /* make sure this channel is not used for sample responses */
684  for (size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
685  if (dev->streams[i].hSampleReqChannel == hchannel)
686  dev->streams[i].hSampleReqChannel = NULL;
687 
688  free(hchannel);
689  return CHANNEL_RC_OK;
690 }
691 
697 static UINT ecam_dev_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
698  IWTSVirtualChannel* pChannel, BYTE* Data,
699  BOOL* pbAccept,
700  IWTSVirtualChannelCallback** ppCallback)
701 {
702  GENERIC_LISTENER_CALLBACK* hlistener = (GENERIC_LISTENER_CALLBACK*)pListenerCallback;
703 
704  if (!hlistener || !hlistener->plugin)
705  return ERROR_INTERNAL_ERROR;
706 
707  WLog_DBG(TAG, "entered");
708  GENERIC_CHANNEL_CALLBACK* hchannel =
710 
711  if (!hchannel)
712  {
713  WLog_ERR(TAG, "calloc failed");
714  return CHANNEL_RC_NO_MEMORY;
715  }
716 
717  hchannel->iface.OnDataReceived = ecam_dev_on_data_received;
718  hchannel->iface.OnOpen = ecam_dev_on_open;
719  hchannel->iface.OnClose = ecam_dev_on_close;
720  hchannel->plugin = hlistener->plugin;
721  hchannel->channel_mgr = hlistener->channel_mgr;
722  hchannel->channel = pChannel;
723  *ppCallback = (IWTSVirtualChannelCallback*)hchannel;
724  return CHANNEL_RC_OK;
725 }
726 
732 CameraDevice* ecam_dev_create(CameraPlugin* ecam, const char* deviceId, const char* deviceName)
733 {
734  WINPR_ASSERT(ecam);
735  WINPR_ASSERT(ecam->hlistener);
736 
737  IWTSVirtualChannelManager* pChannelMgr = ecam->hlistener->channel_mgr;
738  WINPR_ASSERT(pChannelMgr);
739 
740  WLog_DBG(TAG, "entered for %s", deviceId);
741 
742  CameraDevice* dev = (CameraDevice*)calloc(1, sizeof(CameraDevice));
743 
744  if (!dev)
745  {
746  WLog_ERR(TAG, "calloc failed");
747  return NULL;
748  }
749 
750  dev->ecam = ecam;
751  dev->ihal = ecam->ihal;
752  strncpy(dev->deviceId, deviceId, sizeof(dev->deviceId) - 1);
753  dev->hlistener = (GENERIC_LISTENER_CALLBACK*)calloc(1, sizeof(GENERIC_LISTENER_CALLBACK));
754 
755  if (!dev->hlistener)
756  {
757  free(dev);
758  WLog_ERR(TAG, "calloc failed");
759  return NULL;
760  }
761 
762  dev->hlistener->iface.OnNewChannelConnection = ecam_dev_on_new_channel_connection;
763  dev->hlistener->plugin = (IWTSPlugin*)dev;
764  dev->hlistener->channel_mgr = pChannelMgr;
765  if (CHANNEL_RC_OK != pChannelMgr->CreateListener(pChannelMgr, deviceId, 0,
766  &dev->hlistener->iface, &dev->listener))
767  {
768  free(dev->hlistener);
769  free(dev);
770  WLog_ERR(TAG, "CreateListener failed");
771  return NULL;
772  }
773 
774  return dev;
775 }
776 
783 void ecam_dev_destroy(CameraDevice* dev)
784 {
785  if (!dev)
786  return;
787 
788  WLog_DBG(TAG, "entered for %s", dev->deviceId);
789 
790  if (dev->hlistener)
791  {
792  IWTSVirtualChannelManager* mgr = dev->hlistener->channel_mgr;
793  if (mgr)
794  IFCALL(mgr->DestroyListener, mgr, dev->listener);
795  }
796 
797  free(dev->hlistener);
798 
799  for (int i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
800  ecam_dev_stop_stream(dev, i);
801 
802  free(dev);
803 }