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