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 UINT32 errorCode = 0;
559
560 if (dev->ihal->Activate(dev->ihal, dev->deviceId, &errorCode))
561 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
562
563 return ecam_channel_send_error_response(dev->ecam, hchannel, errorCode);
564}
565
571static UINT ecam_dev_process_deactivate_device_request(CameraDevice* dev,
572 GENERIC_CHANNEL_CALLBACK* hchannel,
573 wStream* s)
574{
575 WINPR_ASSERT(dev);
576 WINPR_UNUSED(s);
577
578 for (size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
579 ecam_dev_stop_stream(dev, i);
580
581 UINT32 errorCode = 0;
582 if (dev->ihal->Deactivate(dev->ihal, dev->deviceId, &errorCode))
583 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
584
585 return ecam_channel_send_error_response(dev->ecam, hchannel, errorCode);
586}
587
593static UINT ecam_dev_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data)
594{
595 UINT error = CHANNEL_RC_OK;
596 BYTE version = 0;
597 BYTE messageId = 0;
598 GENERIC_CHANNEL_CALLBACK* hchannel = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback;
599
600 if (!hchannel || !data)
601 return ERROR_INVALID_PARAMETER;
602
603 CameraDevice* dev = (CameraDevice*)hchannel->plugin;
604
605 if (!dev)
606 return ERROR_INTERNAL_ERROR;
607
608 if (!Stream_CheckAndLogRequiredCapacity(TAG, data, CAM_HEADER_SIZE))
609 return ERROR_NO_DATA;
610
611 Stream_Read_UINT8(data, version);
612 Stream_Read_UINT8(data, messageId);
613 WLog_DBG(TAG, "ChannelId=%d, MessageId=0x%02" PRIx8 ", Version=%d",
614 hchannel->channel_mgr->GetChannelId(hchannel->channel), messageId, version);
615
616 switch (messageId)
617 {
618 case CAM_MSG_ID_ActivateDeviceRequest:
619 error = ecam_dev_process_activate_device_request(dev, hchannel, data);
620 break;
621
622 case CAM_MSG_ID_DeactivateDeviceRequest:
623 error = ecam_dev_process_deactivate_device_request(dev, hchannel, data);
624 break;
625
626 case CAM_MSG_ID_StreamListRequest:
627 error = ecam_dev_process_stream_list_request(dev, hchannel, data);
628 break;
629
630 case CAM_MSG_ID_MediaTypeListRequest:
631 error = ecam_dev_process_media_type_list_request(dev, hchannel, data);
632 break;
633
634 case CAM_MSG_ID_CurrentMediaTypeRequest:
635 error = ecam_dev_process_current_media_type_request(dev, hchannel, data);
636 break;
637
638 case CAM_MSG_ID_PropertyListRequest:
639 error = ecam_dev_process_property_list_request(dev, hchannel, data);
640 break;
641
642 case CAM_MSG_ID_StartStreamsRequest:
643 error = ecam_dev_process_start_streams_request(dev, hchannel, data);
644 break;
645
646 case CAM_MSG_ID_StopStreamsRequest:
647 error = ecam_dev_process_stop_streams_request(dev, hchannel, data);
648 break;
649
650 case CAM_MSG_ID_SampleRequest:
651 error = ecam_dev_process_sample_request(dev, hchannel, data);
652 break;
653
654 default:
655 WLog_WARN(TAG, "unknown MessageId=0x%02" PRIx8 "", messageId);
656 error = ERROR_INVALID_DATA;
657 ecam_channel_send_error_response(dev->ecam, hchannel,
658 CAM_ERROR_CODE_OperationNotSupported);
659 break;
660 }
661
662 return error;
663}
664
670static UINT ecam_dev_on_open(WINPR_ATTR_UNUSED IWTSVirtualChannelCallback* pChannelCallback)
671{
672 WLog_DBG(TAG, "entered");
673 return CHANNEL_RC_OK;
674}
675
681static UINT ecam_dev_on_close(IWTSVirtualChannelCallback* pChannelCallback)
682{
683 GENERIC_CHANNEL_CALLBACK* hchannel = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback;
684 WINPR_ASSERT(hchannel);
685
686 CameraDevice* dev = (CameraDevice*)hchannel->plugin;
687 WINPR_ASSERT(dev);
688
689 WLog_DBG(TAG, "entered");
690
691 /* make sure this channel is not used for sample responses */
692 for (size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
693 if (dev->streams[i].hSampleReqChannel == hchannel)
694 dev->streams[i].hSampleReqChannel = NULL;
695
696 free(hchannel);
697 return CHANNEL_RC_OK;
698}
699
705static UINT ecam_dev_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
706 IWTSVirtualChannel* pChannel,
707 WINPR_ATTR_UNUSED BYTE* Data,
708 WINPR_ATTR_UNUSED BOOL* pbAccept,
709 IWTSVirtualChannelCallback** ppCallback)
710{
711 GENERIC_LISTENER_CALLBACK* hlistener = (GENERIC_LISTENER_CALLBACK*)pListenerCallback;
712
713 if (!hlistener || !hlistener->plugin)
714 return ERROR_INTERNAL_ERROR;
715
716 WLog_DBG(TAG, "entered");
717 GENERIC_CHANNEL_CALLBACK* hchannel =
719
720 if (!hchannel)
721 {
722 WLog_ERR(TAG, "calloc failed");
723 return CHANNEL_RC_NO_MEMORY;
724 }
725
726 hchannel->iface.OnDataReceived = ecam_dev_on_data_received;
727 hchannel->iface.OnOpen = ecam_dev_on_open;
728 hchannel->iface.OnClose = ecam_dev_on_close;
729 hchannel->plugin = hlistener->plugin;
730 hchannel->channel_mgr = hlistener->channel_mgr;
731 hchannel->channel = pChannel;
732 *ppCallback = (IWTSVirtualChannelCallback*)hchannel;
733 return CHANNEL_RC_OK;
734}
735
741CameraDevice* ecam_dev_create(CameraPlugin* ecam, const char* deviceId,
742 WINPR_ATTR_UNUSED const char* deviceName)
743{
744 WINPR_ASSERT(ecam);
745 WINPR_ASSERT(ecam->hlistener);
746
747 IWTSVirtualChannelManager* pChannelMgr = ecam->hlistener->channel_mgr;
748 WINPR_ASSERT(pChannelMgr);
749
750 WLog_DBG(TAG, "entered for %s", deviceId);
751
752 CameraDevice* dev = (CameraDevice*)calloc(1, sizeof(CameraDevice));
753
754 if (!dev)
755 {
756 WLog_ERR(TAG, "calloc failed");
757 return NULL;
758 }
759
760 dev->ecam = ecam;
761 dev->ihal = ecam->ihal;
762 strncpy(dev->deviceId, deviceId, sizeof(dev->deviceId) - 1);
763 dev->hlistener = (GENERIC_LISTENER_CALLBACK*)calloc(1, sizeof(GENERIC_LISTENER_CALLBACK));
764
765 if (!dev->hlistener)
766 {
767 free(dev);
768 WLog_ERR(TAG, "calloc failed");
769 return NULL;
770 }
771
772 dev->hlistener->iface.OnNewChannelConnection = ecam_dev_on_new_channel_connection;
773 dev->hlistener->plugin = (IWTSPlugin*)dev;
774 dev->hlistener->channel_mgr = pChannelMgr;
775 if (CHANNEL_RC_OK != pChannelMgr->CreateListener(pChannelMgr, deviceId, 0,
776 &dev->hlistener->iface, &dev->listener))
777 {
778 free(dev->hlistener);
779 free(dev);
780 WLog_ERR(TAG, "CreateListener failed");
781 return NULL;
782 }
783
784 return dev;
785}
786
793void ecam_dev_destroy(CameraDevice* dev)
794{
795 if (!dev)
796 return;
797
798 WLog_DBG(TAG, "entered for %s", dev->deviceId);
799
800 if (dev->hlistener)
801 {
802 IWTSVirtualChannelManager* mgr = dev->hlistener->channel_mgr;
803 if (mgr)
804 IFCALL(mgr->DestroyListener, mgr, dev->listener);
805 }
806
807 free(dev->hlistener);
808
809 for (size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
810 ecam_dev_stop_stream(dev, i);
811
812 free(dev);
813}