FreeRDP
Loading...
Searching...
No Matches
client/camera_device_main.c
1
20#include <winpr/assert.h>
21#include <winpr/cast.h>
22#include <winpr/interlocked.h>
23
24#include "camera.h"
25
26#define TAG CHANNELS_TAG("rdpecam-device.client")
27
28/* supported formats in preference order:
29 * H264, MJPG, I420 (used as input for H264 encoder), other YUV based, RGB based
30 */
31static const CAM_MEDIA_FORMAT_INFO supportedFormats[] = {
32/* inputFormat, outputFormat */
33#if defined(WITH_INPUT_FORMAT_H264)
34 { CAM_MEDIA_FORMAT_H264, CAM_MEDIA_FORMAT_H264 }, /* passthrough */
35 { CAM_MEDIA_FORMAT_MJPG_H264, CAM_MEDIA_FORMAT_H264 },
36#endif
37#if defined(WITH_INPUT_FORMAT_MJPG)
38 { CAM_MEDIA_FORMAT_MJPG, CAM_MEDIA_FORMAT_H264 },
39 { CAM_MEDIA_FORMAT_MJPG, CAM_MEDIA_FORMAT_MJPG },
40#endif
41 { CAM_MEDIA_FORMAT_I420, CAM_MEDIA_FORMAT_H264 },
42 { CAM_MEDIA_FORMAT_YUY2, CAM_MEDIA_FORMAT_H264 },
43 { CAM_MEDIA_FORMAT_NV12, CAM_MEDIA_FORMAT_H264 },
44 { CAM_MEDIA_FORMAT_RGB24, CAM_MEDIA_FORMAT_H264 },
45 { CAM_MEDIA_FORMAT_RGB32, CAM_MEDIA_FORMAT_H264 },
46};
47static const size_t nSupportedFormats = ARRAYSIZE(supportedFormats);
48
49static void ecam_dev_write_media_type(wStream* s, CAM_MEDIA_TYPE_DESCRIPTION* mediaType)
50{
51 WINPR_ASSERT(mediaType);
52
53 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, mediaType->Format));
54 Stream_Write_UINT32(s, mediaType->Width);
55 Stream_Write_UINT32(s, mediaType->Height);
56 Stream_Write_UINT32(s, mediaType->FrameRateNumerator);
57 Stream_Write_UINT32(s, mediaType->FrameRateDenominator);
58 Stream_Write_UINT32(s, mediaType->PixelAspectRatioNumerator);
59 Stream_Write_UINT32(s, mediaType->PixelAspectRatioDenominator);
60 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, mediaType->Flags));
61}
62
63static BOOL ecam_dev_read_media_type(wStream* s, CAM_MEDIA_TYPE_DESCRIPTION* mediaType)
64{
65 WINPR_ASSERT(mediaType);
66
67 Stream_Read_UINT8(s, mediaType->Format);
68 Stream_Read_UINT32(s, mediaType->Width);
69 Stream_Read_UINT32(s, mediaType->Height);
70 Stream_Read_UINT32(s, mediaType->FrameRateNumerator);
71 Stream_Read_UINT32(s, mediaType->FrameRateDenominator);
72 Stream_Read_UINT32(s, mediaType->PixelAspectRatioNumerator);
73 Stream_Read_UINT32(s, mediaType->PixelAspectRatioDenominator);
74 Stream_Read_UINT8(s, mediaType->Flags);
75 return TRUE;
76}
77
78static void ecam_dev_print_media_type(CAM_MEDIA_TYPE_DESCRIPTION* mediaType)
79{
80 WINPR_ASSERT(mediaType);
81
82 WLog_DBG(TAG, "Format: %u, width: %u, height: %u, fps: %u, flags: %u", mediaType->Format,
83 mediaType->Width, mediaType->Height, mediaType->FrameRateNumerator, mediaType->Flags);
84}
85
91static UINT ecam_dev_send_sample_response(CameraDevice* dev, size_t streamIndex, const BYTE* sample,
92 size_t size)
93{
94 WINPR_ASSERT(dev);
95
96 CameraDeviceStream* stream = &dev->streams[streamIndex];
97 CAM_MSG_ID msg = CAM_MSG_ID_SampleResponse;
98
99 Stream_SetPosition(stream->sampleRespBuffer, 0);
100
101 Stream_Write_UINT8(stream->sampleRespBuffer,
102 WINPR_ASSERTING_INT_CAST(uint8_t, dev->ecam->version));
103 Stream_Write_UINT8(stream->sampleRespBuffer, WINPR_ASSERTING_INT_CAST(uint8_t, msg));
104 Stream_Write_UINT8(stream->sampleRespBuffer, WINPR_ASSERTING_INT_CAST(uint8_t, streamIndex));
105
106 Stream_Write(stream->sampleRespBuffer, sample, size);
107
108 /* channel write is protected by critical section in dvcman_write_channel */
109 return ecam_channel_write(dev->ecam, stream->hSampleReqChannel, msg, stream->sampleRespBuffer,
110 FALSE /* don't free stream */);
111}
112
113static BOOL mediaSupportDrops(CAM_MEDIA_FORMAT format)
114{
115 switch (format)
116 {
117 case CAM_MEDIA_FORMAT_H264:
118 return FALSE;
119 default:
120 return TRUE;
121 }
122}
123
124static UINT ecam_dev_send_pending(CameraDevice* dev, size_t streamIndex, CameraDeviceStream* stream)
125{
126 WINPR_ASSERT(dev);
127 WINPR_ASSERT(stream);
128
129 if (stream->samplesRequested <= 0)
130 {
131 WLog_VRB(TAG, "Frame delayed: No sample requested");
132 return CHANNEL_RC_OK;
133 }
134
135 if (!stream->haveSample)
136 {
137 WLog_VRB(TAG, "Frame response delayed: No sample available");
138 return CHANNEL_RC_OK;
139 }
140
141 BYTE* encodedSample = Stream_Buffer(stream->pendingSample);
142 size_t encodedSize = Stream_Length(stream->pendingSample);
143 if (streamInputFormat(stream) != streamOutputFormat(stream))
144 {
145 if (!ecam_encoder_compress(stream, encodedSample, encodedSize, &encodedSample,
146 &encodedSize))
147 {
148 WLog_DBG(TAG, "Frame dropped: error in ecam_encoder_compress");
149 stream->haveSample = FALSE;
150 return CHANNEL_RC_OK;
151 }
152
153 if (!stream->streaming)
154 {
155 WLog_DBG(TAG, "Frame delayed/dropped: stream stopped");
156 return CHANNEL_RC_OK;
157 }
158 }
159
160 stream->samplesRequested--;
161 stream->haveSample = FALSE;
162
163 return ecam_dev_send_sample_response(dev, streamIndex, encodedSample, encodedSize);
164}
165
166static UINT ecam_dev_sample_captured_callback(CameraDevice* dev, int streamIndex,
167 const BYTE* sample, size_t size)
168{
169 WINPR_ASSERT(dev);
170
171 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
172 return ERROR_INVALID_INDEX;
173
174 CameraDeviceStream* stream = &dev->streams[streamIndex];
175
176 if (!stream->streaming)
177 {
178 WLog_DBG(TAG, "Frame drop: stream not running");
179 return CHANNEL_RC_OK;
180 }
181
182 EnterCriticalSection(&stream->lock);
183 UINT ret = CHANNEL_RC_NO_MEMORY;
184
185 /* If we already have a waiting sample, let's see if the input format support dropping
186 * frames so that we could just "refresh" the pending sample, otherwise we must wait until
187 * a frame request flushes it
188 */
189
190 if (stream->haveSample && !mediaSupportDrops(stream->formats.inputFormat))
191 {
192 /* we can't drop samples, so we have to wait until the pending sample is
193 * sent, by a sample request.
194 *
195 * When we're here we already have a sample ready to be sent, the delay between 2 frames
196 * seems like a reasonable wait delay. For instance 60 FPS means a frame every 16ms.
197 * We also cap that wait delay to not spinloop and not get stuck for too long.
198 * */
199 DWORD waitDelay = (1000 * stream->currMediaType.FrameRateDenominator) /
200 stream->currMediaType.FrameRateNumerator;
201 if (waitDelay < 16)
202 waitDelay = 16;
203 if (waitDelay > 100)
204 waitDelay = 100;
205
206 while (stream->haveSample && stream->streaming)
207 {
208 LeaveCriticalSection(&stream->lock);
209
210 SleepEx(waitDelay, TRUE);
211
212 EnterCriticalSection(&stream->lock);
213 }
214
215 if (!stream->streaming)
216 {
217 WLog_DBG(TAG, "Frame drop: stream not running");
218 ret = CHANNEL_RC_OK;
219 goto out;
220 }
221 }
222
223 Stream_SetPosition(stream->pendingSample, 0);
224 if (!Stream_EnsureRemainingCapacity(stream->pendingSample, size))
225 goto out;
226
227 Stream_Write(stream->pendingSample, sample, size);
228 Stream_SealLength(stream->pendingSample);
229 stream->haveSample = TRUE;
230
231 ret = ecam_dev_send_pending(dev, WINPR_ASSERTING_INT_CAST(size_t, streamIndex), stream);
232
233out:
234 LeaveCriticalSection(&stream->lock);
235 return ret;
236}
237
238static void ecam_dev_stop_stream(CameraDevice* dev, size_t streamIndex)
239{
240 WINPR_ASSERT(dev);
241
242 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
243 return;
244
245 CameraDeviceStream* stream = &dev->streams[streamIndex];
246
247 if (stream->streaming)
248 {
249 stream->streaming = FALSE;
250 dev->ihal->StopStream(dev->ihal, dev->deviceId, 0);
251
252 DeleteCriticalSection(&stream->lock);
253 }
254
255 Stream_Free(stream->sampleRespBuffer, TRUE);
256 stream->sampleRespBuffer = NULL;
257
258 Stream_Free(stream->pendingSample, TRUE);
259 stream->pendingSample = NULL;
260
261 ecam_encoder_context_free(stream);
262}
263
269static UINT ecam_dev_process_stop_streams_request(CameraDevice* dev,
270 GENERIC_CHANNEL_CALLBACK* hchannel, wStream* s)
271{
272 WINPR_ASSERT(dev);
273 WINPR_UNUSED(s);
274
275 for (size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
276 ecam_dev_stop_stream(dev, i);
277
278 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
279}
280
286static UINT ecam_dev_process_start_streams_request(CameraDevice* dev,
287 GENERIC_CHANNEL_CALLBACK* hchannel, wStream* s)
288{
289 BYTE streamIndex = 0;
290 CAM_MEDIA_TYPE_DESCRIPTION mediaType = { 0 };
291
292 WINPR_ASSERT(dev);
293
294 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1 + 26))
295 return ERROR_INVALID_DATA;
296
297 Stream_Read_UINT8(s, streamIndex);
298
299 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
300 {
301 WLog_ERR(TAG, "Incorrect streamIndex %" PRIu8, streamIndex);
302 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_InvalidStreamNumber);
303 return ERROR_INVALID_INDEX;
304 }
305
306 if (!ecam_dev_read_media_type(s, &mediaType))
307 {
308 WLog_ERR(TAG, "Unable to read MEDIA_TYPE_DESCRIPTION");
309 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_InvalidMessage);
310 return ERROR_INVALID_DATA;
311 }
312
313 ecam_dev_print_media_type(&mediaType);
314
315 CameraDeviceStream* stream = &dev->streams[streamIndex];
316
317 if (stream->streaming)
318 {
319 WLog_ERR(TAG, "Streaming already in progress, device %s, streamIndex %d", dev->deviceId,
320 streamIndex);
321 return CAM_ERROR_CODE_UnexpectedError;
322 }
323
324 /* saving media type description for CurrentMediaTypeRequest,
325 * to be done before calling ecam_encoder_context_init
326 */
327 stream->currMediaType = mediaType;
328
329 /* initialize encoder, if input and output formats differ */
330 if (streamInputFormat(stream) != streamOutputFormat(stream) &&
331 !ecam_encoder_context_init(stream))
332 {
333 WLog_ERR(TAG, "stream_ecam_encoder_init failed");
334 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_UnexpectedError);
335 return ERROR_INVALID_DATA;
336 }
337
338 stream->sampleRespBuffer = Stream_New(NULL, ECAM_SAMPLE_RESPONSE_BUFFER_SIZE);
339 if (!stream->sampleRespBuffer)
340 {
341 WLog_ERR(TAG, "Stream_New failed");
342 ecam_dev_stop_stream(dev, streamIndex);
343 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_OutOfMemory);
344 return ERROR_INVALID_DATA;
345 }
346
347 /* replacing outputFormat with inputFormat in mediaType before starting stream */
348 mediaType.Format = streamInputFormat(stream);
349
350 stream->samplesRequested = 0;
351 stream->haveSample = FALSE;
352
353 if (!InitializeCriticalSectionEx(&stream->lock, 0, 0))
354 {
355 WLog_ERR(TAG, "InitializeCriticalSectionEx failed");
356 ecam_dev_stop_stream(dev, streamIndex);
357 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_OutOfMemory);
358 return ERROR_INVALID_DATA;
359 }
360
361 stream->pendingSample = Stream_New(NULL, 4ull * mediaType.Width * mediaType.Height);
362 if (!stream->pendingSample)
363 {
364 WLog_ERR(TAG, "pending stream failed");
365 ecam_dev_stop_stream(dev, streamIndex);
366 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_OutOfMemory);
367 return ERROR_INVALID_DATA;
368 }
369
370 UINT error = dev->ihal->StartStream(dev->ihal, dev, streamIndex, &mediaType,
371 ecam_dev_sample_captured_callback);
372 if (error)
373 {
374 WLog_ERR(TAG, "StartStream failure");
375 ecam_dev_stop_stream(dev, streamIndex);
376 ecam_channel_send_error_response(dev->ecam, hchannel, error);
377 return ERROR_INVALID_DATA;
378 }
379
380 stream->streaming = TRUE;
381 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
382}
383
389static UINT ecam_dev_process_property_list_request(CameraDevice* dev,
390 GENERIC_CHANNEL_CALLBACK* hchannel,
391 WINPR_ATTR_UNUSED wStream* s)
392{
393 WINPR_ASSERT(dev);
394 // TODO: supported properties implementation
395
396 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_PropertyListResponse);
397}
398
404static UINT ecam_dev_send_current_media_type_response(CameraDevice* dev,
405 GENERIC_CHANNEL_CALLBACK* hchannel,
407{
408 CAM_MSG_ID msg = CAM_MSG_ID_CurrentMediaTypeResponse;
409
410 WINPR_ASSERT(dev);
411
412 wStream* s = Stream_New(NULL, CAM_HEADER_SIZE + sizeof(CAM_MEDIA_TYPE_DESCRIPTION));
413 if (!s)
414 {
415 WLog_ERR(TAG, "Stream_New failed");
416 return ERROR_NOT_ENOUGH_MEMORY;
417 }
418
419 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, dev->ecam->version));
420 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, msg));
421
422 ecam_dev_write_media_type(s, mediaType);
423
424 return ecam_channel_write(dev->ecam, hchannel, msg, s, TRUE);
425}
426
432static UINT ecam_dev_process_sample_request(CameraDevice* dev, GENERIC_CHANNEL_CALLBACK* hchannel,
433 wStream* s)
434{
435 BYTE streamIndex = 0;
436
437 WINPR_ASSERT(dev);
438
439 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
440 return ERROR_INVALID_DATA;
441
442 Stream_Read_UINT8(s, streamIndex);
443
444 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
445 {
446 WLog_ERR(TAG, "Incorrect streamIndex %d", streamIndex);
447 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_InvalidStreamNumber);
448 return ERROR_INVALID_INDEX;
449 }
450
451 CameraDeviceStream* stream = &dev->streams[streamIndex];
452
453 EnterCriticalSection(&stream->lock);
454
455 /* need to save channel because responses are asynchronous and coming from capture thread */
456 if (stream->hSampleReqChannel != hchannel)
457 stream->hSampleReqChannel = hchannel;
458
459 stream->samplesRequested++;
460 const UINT ret = ecam_dev_send_pending(dev, streamIndex, stream);
461
462 LeaveCriticalSection(&stream->lock);
463 return ret;
464}
465
471static UINT ecam_dev_process_current_media_type_request(CameraDevice* dev,
472 GENERIC_CHANNEL_CALLBACK* hchannel,
473 wStream* s)
474{
475 BYTE streamIndex = 0;
476
477 WINPR_ASSERT(dev);
478
479 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
480 return ERROR_INVALID_DATA;
481
482 Stream_Read_UINT8(s, streamIndex);
483
484 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
485 {
486 WLog_ERR(TAG, "Incorrect streamIndex %d", streamIndex);
487 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_InvalidStreamNumber);
488 return ERROR_INVALID_INDEX;
489 }
490
491 CameraDeviceStream* stream = &dev->streams[streamIndex];
492
493 if (stream->currMediaType.Format == 0)
494 {
495 WLog_ERR(TAG, "Current media type unknown for streamIndex %d", streamIndex);
496 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_NotInitialized);
497 return ERROR_DEVICE_REINITIALIZATION_NEEDED;
498 }
499
500 return ecam_dev_send_current_media_type_response(dev, hchannel, &stream->currMediaType);
501}
502
508static UINT ecam_dev_send_media_type_list_response(CameraDevice* dev,
509 GENERIC_CHANNEL_CALLBACK* hchannel,
510 CAM_MEDIA_TYPE_DESCRIPTION* mediaTypes,
511 size_t nMediaTypes)
512{
513 CAM_MSG_ID msg = CAM_MSG_ID_MediaTypeListResponse;
514
515 WINPR_ASSERT(dev);
516
517 wStream* s = Stream_New(NULL, CAM_HEADER_SIZE + ECAM_MAX_MEDIA_TYPE_DESCRIPTORS *
519 if (!s)
520 {
521 WLog_ERR(TAG, "Stream_New failed");
522 return ERROR_NOT_ENOUGH_MEMORY;
523 }
524
525 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, dev->ecam->version));
526 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, msg));
527
528 for (size_t i = 0; i < nMediaTypes; i++, mediaTypes++)
529 {
530 ecam_dev_write_media_type(s, mediaTypes);
531 }
532
533 return ecam_channel_write(dev->ecam, hchannel, msg, s, TRUE);
534}
535
541static UINT ecam_dev_process_media_type_list_request(CameraDevice* dev,
542 GENERIC_CHANNEL_CALLBACK* hchannel, wStream* s)
543{
544 UINT error = CHANNEL_RC_OK;
545 BYTE streamIndex = 0;
546 CAM_MEDIA_TYPE_DESCRIPTION* mediaTypes = NULL;
547 size_t nMediaTypes = ECAM_MAX_MEDIA_TYPE_DESCRIPTORS;
548
549 WINPR_ASSERT(dev);
550
551 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
552 return ERROR_INVALID_DATA;
553
554 Stream_Read_UINT8(s, streamIndex);
555
556 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
557 {
558 WLog_ERR(TAG, "Incorrect streamIndex %d", streamIndex);
559 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_InvalidStreamNumber);
560 return ERROR_INVALID_INDEX;
561 }
562 CameraDeviceStream* stream = &dev->streams[streamIndex];
563
564 mediaTypes =
565 (CAM_MEDIA_TYPE_DESCRIPTION*)calloc(nMediaTypes, sizeof(CAM_MEDIA_TYPE_DESCRIPTION));
566 if (!mediaTypes)
567 {
568 WLog_ERR(TAG, "calloc failed");
569 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_OutOfMemory);
570 return CHANNEL_RC_NO_MEMORY;
571 }
572
573 INT16 formatIndex =
574 dev->ihal->GetMediaTypeDescriptions(dev->ihal, dev->deviceId, streamIndex, supportedFormats,
575 nSupportedFormats, mediaTypes, &nMediaTypes);
576 if (formatIndex == -1 || nMediaTypes == 0)
577 {
578 WLog_ERR(TAG, "Camera doesn't support any compatible video formats");
579 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_ItemNotFound);
580 error = ERROR_DEVICE_FEATURE_NOT_SUPPORTED;
581 goto error;
582 }
583
584 stream->formats = supportedFormats[formatIndex];
585
586 /* replacing inputFormat with outputFormat in mediaTypes before sending response */
587 for (size_t i = 0; i < nMediaTypes; i++)
588 {
589 mediaTypes[i].Format = streamOutputFormat(stream);
590 mediaTypes[i].Flags = CAM_MEDIA_TYPE_DESCRIPTION_FLAG_DecodingRequired;
591 }
592
593 if (stream->currMediaType.Format == 0)
594 {
595 /* saving 1st media type description for CurrentMediaTypeRequest */
596 stream->currMediaType = mediaTypes[0];
597 }
598
599 error = ecam_dev_send_media_type_list_response(dev, hchannel, mediaTypes, nMediaTypes);
600
601error:
602 free(mediaTypes);
603 return error;
604}
605
611static UINT ecam_dev_send_stream_list_response(CameraDevice* dev,
612 GENERIC_CHANNEL_CALLBACK* hchannel)
613{
614 CAM_MSG_ID msg = CAM_MSG_ID_StreamListResponse;
615
616 WINPR_ASSERT(dev);
617
618 wStream* s = Stream_New(NULL, CAM_HEADER_SIZE + sizeof(CAM_STREAM_DESCRIPTION));
619 if (!s)
620 {
621 WLog_ERR(TAG, "Stream_New failed");
622 return ERROR_NOT_ENOUGH_MEMORY;
623 }
624
625 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, dev->ecam->version));
626 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, msg));
627
628 /* single stream description */
629 Stream_Write_UINT16(s, CAM_STREAM_FRAME_SOURCE_TYPE_Color);
630 Stream_Write_UINT8(s, CAM_STREAM_CATEGORY_Capture);
631 Stream_Write_UINT8(s, TRUE /* Selected */);
632 Stream_Write_UINT8(s, FALSE /* CanBeShared */);
633
634 return ecam_channel_write(dev->ecam, hchannel, msg, s, TRUE);
635}
636
642static UINT ecam_dev_process_stream_list_request(CameraDevice* dev,
643 GENERIC_CHANNEL_CALLBACK* hchannel,
644 WINPR_ATTR_UNUSED wStream* s)
645{
646 return ecam_dev_send_stream_list_response(dev, hchannel);
647}
648
654static UINT ecam_dev_process_activate_device_request(CameraDevice* dev,
655 GENERIC_CHANNEL_CALLBACK* hchannel,
656 WINPR_ATTR_UNUSED wStream* s)
657{
658 WINPR_ASSERT(dev);
659 UINT32 errorCode = 0;
660
661 if (dev->ihal->Activate(dev->ihal, dev->deviceId, &errorCode))
662 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
663
664 return ecam_channel_send_error_response(dev->ecam, hchannel, errorCode);
665}
666
672static UINT ecam_dev_process_deactivate_device_request(CameraDevice* dev,
673 GENERIC_CHANNEL_CALLBACK* hchannel,
674 wStream* s)
675{
676 WINPR_ASSERT(dev);
677 WINPR_UNUSED(s);
678
679 for (size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
680 ecam_dev_stop_stream(dev, i);
681
682 UINT32 errorCode = 0;
683 if (dev->ihal->Deactivate(dev->ihal, dev->deviceId, &errorCode))
684 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
685
686 return ecam_channel_send_error_response(dev->ecam, hchannel, errorCode);
687}
688
694static UINT ecam_dev_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data)
695{
696 UINT error = CHANNEL_RC_OK;
697 BYTE version = 0;
698 BYTE messageId = 0;
699 GENERIC_CHANNEL_CALLBACK* hchannel = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback;
700
701 if (!hchannel || !data)
702 return ERROR_INVALID_PARAMETER;
703
704 CameraDevice* dev = (CameraDevice*)hchannel->plugin;
705
706 if (!dev)
707 return ERROR_INTERNAL_ERROR;
708
709 if (!Stream_CheckAndLogRequiredCapacity(TAG, data, CAM_HEADER_SIZE))
710 return ERROR_NO_DATA;
711
712 Stream_Read_UINT8(data, version);
713 Stream_Read_UINT8(data, messageId);
714 WLog_DBG(TAG, "ChannelId=%" PRIu32 ", MessageId=0x%02" PRIx8 ", Version=%d",
715 hchannel->channel_mgr->GetChannelId(hchannel->channel), messageId, version);
716
717 switch (messageId)
718 {
719 case CAM_MSG_ID_ActivateDeviceRequest:
720 error = ecam_dev_process_activate_device_request(dev, hchannel, data);
721 break;
722
723 case CAM_MSG_ID_DeactivateDeviceRequest:
724 error = ecam_dev_process_deactivate_device_request(dev, hchannel, data);
725 break;
726
727 case CAM_MSG_ID_StreamListRequest:
728 error = ecam_dev_process_stream_list_request(dev, hchannel, data);
729 break;
730
731 case CAM_MSG_ID_MediaTypeListRequest:
732 error = ecam_dev_process_media_type_list_request(dev, hchannel, data);
733 break;
734
735 case CAM_MSG_ID_CurrentMediaTypeRequest:
736 error = ecam_dev_process_current_media_type_request(dev, hchannel, data);
737 break;
738
739 case CAM_MSG_ID_PropertyListRequest:
740 error = ecam_dev_process_property_list_request(dev, hchannel, data);
741 break;
742
743 case CAM_MSG_ID_StartStreamsRequest:
744 error = ecam_dev_process_start_streams_request(dev, hchannel, data);
745 break;
746
747 case CAM_MSG_ID_StopStreamsRequest:
748 error = ecam_dev_process_stop_streams_request(dev, hchannel, data);
749 break;
750
751 case CAM_MSG_ID_SampleRequest:
752 error = ecam_dev_process_sample_request(dev, hchannel, data);
753 break;
754
755 default:
756 WLog_WARN(TAG, "unknown MessageId=0x%02" PRIx8 "", messageId);
757 error = ERROR_INVALID_DATA;
758 ecam_channel_send_error_response(dev->ecam, hchannel,
759 CAM_ERROR_CODE_OperationNotSupported);
760 break;
761 }
762
763 return error;
764}
765
771static UINT ecam_dev_on_open(WINPR_ATTR_UNUSED IWTSVirtualChannelCallback* pChannelCallback)
772{
773 WLog_DBG(TAG, "entered");
774 return CHANNEL_RC_OK;
775}
776
782static UINT ecam_dev_on_close(IWTSVirtualChannelCallback* pChannelCallback)
783{
784 GENERIC_CHANNEL_CALLBACK* hchannel = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback;
785 WINPR_ASSERT(hchannel);
786
787 CameraDevice* dev = (CameraDevice*)hchannel->plugin;
788 WINPR_ASSERT(dev);
789
790 WLog_DBG(TAG, "entered");
791
792 for (size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
793 ecam_dev_stop_stream(dev, i);
794
795 /* make sure this channel is not used for sample responses */
796 for (size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
797 if (dev->streams[i].hSampleReqChannel == hchannel)
798 dev->streams[i].hSampleReqChannel = NULL;
799
800 free(hchannel);
801 return CHANNEL_RC_OK;
802}
803
809static UINT ecam_dev_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
810 IWTSVirtualChannel* pChannel,
811 WINPR_ATTR_UNUSED BYTE* Data,
812 WINPR_ATTR_UNUSED BOOL* pbAccept,
813 IWTSVirtualChannelCallback** ppCallback)
814{
815 GENERIC_LISTENER_CALLBACK* hlistener = (GENERIC_LISTENER_CALLBACK*)pListenerCallback;
816
817 if (!hlistener || !hlistener->plugin)
818 return ERROR_INTERNAL_ERROR;
819
820 WLog_DBG(TAG, "entered");
821 GENERIC_CHANNEL_CALLBACK* hchannel =
823
824 if (!hchannel)
825 {
826 WLog_ERR(TAG, "calloc failed");
827 return CHANNEL_RC_NO_MEMORY;
828 }
829
830 hchannel->iface.OnDataReceived = ecam_dev_on_data_received;
831 hchannel->iface.OnOpen = ecam_dev_on_open;
832 hchannel->iface.OnClose = ecam_dev_on_close;
833 hchannel->plugin = hlistener->plugin;
834 hchannel->channel_mgr = hlistener->channel_mgr;
835 hchannel->channel = pChannel;
836 *ppCallback = (IWTSVirtualChannelCallback*)hchannel;
837 return CHANNEL_RC_OK;
838}
839
845CameraDevice* ecam_dev_create(CameraPlugin* ecam, const char* deviceId,
846 WINPR_ATTR_UNUSED const char* deviceName)
847{
848 WINPR_ASSERT(ecam);
849 WINPR_ASSERT(ecam->hlistener);
850
851 IWTSVirtualChannelManager* pChannelMgr = ecam->hlistener->channel_mgr;
852 WINPR_ASSERT(pChannelMgr);
853
854 WLog_DBG(TAG, "entered for %s", deviceId);
855
856 CameraDevice* dev = (CameraDevice*)calloc(1, sizeof(CameraDevice));
857
858 if (!dev)
859 {
860 WLog_ERR(TAG, "calloc failed");
861 return NULL;
862 }
863
864 dev->ecam = ecam;
865 dev->ihal = ecam->ihal;
866 strncpy(dev->deviceId, deviceId, sizeof(dev->deviceId) - 1);
867 dev->hlistener = (GENERIC_LISTENER_CALLBACK*)calloc(1, sizeof(GENERIC_LISTENER_CALLBACK));
868
869 if (!dev->hlistener)
870 {
871 free(dev);
872 WLog_ERR(TAG, "calloc failed");
873 return NULL;
874 }
875
876 dev->hlistener->iface.OnNewChannelConnection = ecam_dev_on_new_channel_connection;
877 dev->hlistener->plugin = (IWTSPlugin*)dev;
878 dev->hlistener->channel_mgr = pChannelMgr;
879 if (CHANNEL_RC_OK != pChannelMgr->CreateListener(pChannelMgr, deviceId, 0,
880 &dev->hlistener->iface, &dev->listener))
881 {
882 free(dev->hlistener);
883 free(dev);
884 WLog_ERR(TAG, "CreateListener failed");
885 return NULL;
886 }
887
888 return dev;
889}
890
897void ecam_dev_destroy(CameraDevice* dev)
898{
899 if (!dev)
900 return;
901
902 WLog_DBG(TAG, "entered for %s", dev->deviceId);
903
904 if (dev->hlistener)
905 {
906 IWTSVirtualChannelManager* mgr = dev->hlistener->channel_mgr;
907 if (mgr)
908 IFCALL(mgr->DestroyListener, mgr, dev->listener);
909 }
910
911 free(dev->hlistener);
912
913 for (size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
914 ecam_dev_stop_stream(dev, i);
915
916 free(dev);
917}