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[ECAM_MAX_MEDIA_TYPE_DESCRIPTORS] = { 0 };
446 size_t nMediaTypes = ARRAYSIZE(mediaTypes);
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 INT16 formatIndex =
464 dev->ihal->GetMediaTypeDescriptions(dev->ihal, dev->deviceId, streamIndex, supportedFormats,
465 nSupportedFormats, mediaTypes, &nMediaTypes);
466 if ((formatIndex < 0) || (nMediaTypes == 0))
467 {
468 WLog_ERR(TAG,
469 "Camera doesn't support any compatible video formats [streamIndex=%" PRIu32
470 ", formatIndex=%" PRId16 ", nMediaTypes=%" PRIu32 "]",
471 streamIndex, formatIndex, nMediaTypes);
472 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_ItemNotFound);
473 return ERROR_DEVICE_FEATURE_NOT_SUPPORTED;
474 }
475
476 stream->formats = supportedFormats[formatIndex];
477
478 /* replacing inputFormat with outputFormat in mediaTypes before sending response */
479 for (size_t i = 0; i < nMediaTypes; i++)
480 {
481 mediaTypes[i].Format = streamOutputFormat(stream);
482 mediaTypes[i].Flags = CAM_MEDIA_TYPE_DESCRIPTION_FLAG_DecodingRequired;
483 }
484
485 if (stream->currMediaType.Format == 0)
486 {
487 /* saving 1st media type description for CurrentMediaTypeRequest */
488 stream->currMediaType = mediaTypes[0];
489 }
490
491 return ecam_dev_send_media_type_list_response(dev, hchannel, mediaTypes, nMediaTypes);
492}
493
499static UINT ecam_dev_send_stream_list_response(CameraDevice* dev,
500 GENERIC_CHANNEL_CALLBACK* hchannel)
501{
502 CAM_MSG_ID msg = CAM_MSG_ID_StreamListResponse;
503
504 WINPR_ASSERT(dev);
505
506 wStream* s = Stream_New(NULL, CAM_HEADER_SIZE + sizeof(CAM_STREAM_DESCRIPTION));
507 if (!s)
508 {
509 WLog_ERR(TAG, "Stream_New failed");
510 return ERROR_NOT_ENOUGH_MEMORY;
511 }
512
513 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, dev->ecam->version));
514 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, msg));
515
516 /* single stream description */
517 Stream_Write_UINT16(s, CAM_STREAM_FRAME_SOURCE_TYPE_Color);
518 Stream_Write_UINT8(s, CAM_STREAM_CATEGORY_Capture);
519 Stream_Write_UINT8(s, TRUE /* Selected */);
520 Stream_Write_UINT8(s, FALSE /* CanBeShared */);
521
522 return ecam_channel_write(dev->ecam, hchannel, msg, s, TRUE);
523}
524
530static UINT ecam_dev_process_stream_list_request(CameraDevice* dev,
531 GENERIC_CHANNEL_CALLBACK* hchannel,
532 WINPR_ATTR_UNUSED wStream* s)
533{
534 return ecam_dev_send_stream_list_response(dev, hchannel);
535}
536
542static UINT ecam_dev_process_activate_device_request(CameraDevice* dev,
543 GENERIC_CHANNEL_CALLBACK* hchannel,
544 WINPR_ATTR_UNUSED wStream* s)
545{
546 WINPR_ASSERT(dev);
547 UINT32 errorCode = 0;
548
549 if (dev->ihal->Activate(dev->ihal, dev->deviceId, &errorCode))
550 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
551
552 return ecam_channel_send_error_response(dev->ecam, hchannel, errorCode);
553}
554
560static UINT ecam_dev_process_deactivate_device_request(CameraDevice* dev,
561 GENERIC_CHANNEL_CALLBACK* hchannel,
562 wStream* s)
563{
564 WINPR_ASSERT(dev);
565 WINPR_UNUSED(s);
566
567 for (size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
568 ecam_dev_stop_stream(dev, i);
569
570 UINT32 errorCode = 0;
571 if (dev->ihal->Deactivate(dev->ihal, dev->deviceId, &errorCode))
572 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
573
574 return ecam_channel_send_error_response(dev->ecam, hchannel, errorCode);
575}
576
582static 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
659static UINT ecam_dev_on_open(WINPR_ATTR_UNUSED IWTSVirtualChannelCallback* pChannelCallback)
660{
661 WLog_DBG(TAG, "entered");
662 return CHANNEL_RC_OK;
663}
664
670static UINT ecam_dev_on_close(IWTSVirtualChannelCallback* pChannelCallback)
671{
672 GENERIC_CHANNEL_CALLBACK* hchannel = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback;
673 WINPR_ASSERT(hchannel);
674
675 CameraDevice* dev = (CameraDevice*)hchannel->plugin;
676 WINPR_ASSERT(dev);
677
678 WLog_DBG(TAG, "entered");
679
680 /* make sure this channel is not used for sample responses */
681 for (size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
682 if (dev->streams[i].hSampleReqChannel == hchannel)
683 dev->streams[i].hSampleReqChannel = NULL;
684
685 free(hchannel);
686 return CHANNEL_RC_OK;
687}
688
694static UINT ecam_dev_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
695 IWTSVirtualChannel* pChannel,
696 WINPR_ATTR_UNUSED BYTE* Data,
697 WINPR_ATTR_UNUSED BOOL* pbAccept,
698 IWTSVirtualChannelCallback** ppCallback)
699{
700 GENERIC_LISTENER_CALLBACK* hlistener = (GENERIC_LISTENER_CALLBACK*)pListenerCallback;
701
702 if (!hlistener || !hlistener->plugin)
703 return ERROR_INTERNAL_ERROR;
704
705 WLog_DBG(TAG, "entered");
706 GENERIC_CHANNEL_CALLBACK* hchannel =
708
709 if (!hchannel)
710 {
711 WLog_ERR(TAG, "calloc failed");
712 return CHANNEL_RC_NO_MEMORY;
713 }
714
715 hchannel->iface.OnDataReceived = ecam_dev_on_data_received;
716 hchannel->iface.OnOpen = ecam_dev_on_open;
717 hchannel->iface.OnClose = ecam_dev_on_close;
718 hchannel->plugin = hlistener->plugin;
719 hchannel->channel_mgr = hlistener->channel_mgr;
720 hchannel->channel = pChannel;
721 *ppCallback = (IWTSVirtualChannelCallback*)hchannel;
722 return CHANNEL_RC_OK;
723}
724
730CameraDevice* ecam_dev_create(CameraPlugin* ecam, const char* deviceId,
731 WINPR_ATTR_UNUSED const char* deviceName)
732{
733 WINPR_ASSERT(ecam);
734 WINPR_ASSERT(ecam->hlistener);
735
736 IWTSVirtualChannelManager* pChannelMgr = ecam->hlistener->channel_mgr;
737 WINPR_ASSERT(pChannelMgr);
738
739 WLog_DBG(TAG, "entered for %s", deviceId);
740
741 CameraDevice* dev = (CameraDevice*)calloc(1, sizeof(CameraDevice));
742
743 if (!dev)
744 {
745 WLog_ERR(TAG, "calloc failed");
746 return NULL;
747 }
748
749 dev->ecam = ecam;
750 dev->ihal = ecam->ihal;
751 strncpy(dev->deviceId, deviceId, sizeof(dev->deviceId) - 1);
752 dev->hlistener = (GENERIC_LISTENER_CALLBACK*)calloc(1, sizeof(GENERIC_LISTENER_CALLBACK));
753
754 if (!dev->hlistener)
755 {
756 free(dev);
757 WLog_ERR(TAG, "calloc failed");
758 return NULL;
759 }
760
761 dev->hlistener->iface.OnNewChannelConnection = ecam_dev_on_new_channel_connection;
762 dev->hlistener->plugin = (IWTSPlugin*)dev;
763 dev->hlistener->channel_mgr = pChannelMgr;
764 if (CHANNEL_RC_OK != pChannelMgr->CreateListener(pChannelMgr, deviceId, 0,
765 &dev->hlistener->iface, &dev->listener))
766 {
767 free(dev->hlistener);
768 free(dev);
769 WLog_ERR(TAG, "CreateListener failed");
770 return NULL;
771 }
772
773 return dev;
774}
775
782void ecam_dev_destroy(CameraDevice* dev)
783{
784 if (!dev)
785 return;
786
787 WLog_DBG(TAG, "entered for %s", dev->deviceId);
788
789 if (dev->hlistener)
790 {
791 IWTSVirtualChannelManager* mgr = dev->hlistener->channel_mgr;
792 if (mgr)
793 IFCALL(mgr->DestroyListener, mgr, dev->listener);
794 }
795
796 free(dev->hlistener);
797
798 for (size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
799 ecam_dev_stop_stream(dev, i);
800
801 free(dev);
802}