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