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#include "rdpecam-utils.h"
26
27#define TAG CHANNELS_TAG("rdpecam-device.client")
28
38static const CAM_MEDIA_FORMAT_INFO* getSupportedFormats(size_t* pCount)
39{
40 WINPR_ASSERT(pCount);
41
42 const CAM_MEDIA_FORMAT available[] = { CAM_MEDIA_FORMAT_H264, CAM_MEDIA_FORMAT_MJPG,
43 CAM_MEDIA_FORMAT_YUY2, CAM_MEDIA_FORMAT_NV12,
44 CAM_MEDIA_FORMAT_I420, CAM_MEDIA_FORMAT_RGB24,
45 CAM_MEDIA_FORMAT_RGB32 };
46
48 formats[ARRAYSIZE(available) * ARRAYSIZE(available)]; /* Max possible formats */
49 static size_t count = 0;
50 static BOOL initialized = FALSE;
51
52 if (!initialized)
53 {
54 for (size_t dst = 0; dst < ARRAYSIZE(available); dst++)
55 {
56 const CAM_MEDIA_FORMAT dstFormat = available[dst];
57
58 for (size_t src = 0; src < ARRAYSIZE(available); src++)
59 {
60 const CAM_MEDIA_FORMAT srcFormat = available[src];
61 if (freerdp_video_conversion_supported(ecamToVideoFormat(srcFormat),
62 ecamToVideoFormat(dstFormat)))
63 {
64 formats[count++] = (CAM_MEDIA_FORMAT_INFO){ srcFormat, dstFormat };
65 }
66 }
67 }
68 initialized = TRUE;
69 }
70
71 *pCount = count;
72 return formats;
73}
74
75static void ecam_dev_write_media_type(wStream* s, CAM_MEDIA_TYPE_DESCRIPTION* mediaType)
76{
77 WINPR_ASSERT(mediaType);
78
79 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, mediaType->Format));
80 Stream_Write_UINT32(s, mediaType->Width);
81 Stream_Write_UINT32(s, mediaType->Height);
82 Stream_Write_UINT32(s, mediaType->FrameRateNumerator);
83 Stream_Write_UINT32(s, mediaType->FrameRateDenominator);
84 Stream_Write_UINT32(s, mediaType->PixelAspectRatioNumerator);
85 Stream_Write_UINT32(s, mediaType->PixelAspectRatioDenominator);
86 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, mediaType->Flags));
87}
88
89static BOOL ecam_dev_read_media_type(wStream* s, CAM_MEDIA_TYPE_DESCRIPTION* mediaType)
90{
91 WINPR_ASSERT(mediaType);
92
93 const uint8_t format = Stream_Get_UINT8(s);
94 if (!rdpecam_valid_CamMediaFormat(format))
95 return FALSE;
96
97 mediaType->Format = WINPR_ASSERTING_INT_CAST(CAM_MEDIA_FORMAT, format);
98 mediaType->Width = Stream_Get_UINT32(s);
99 mediaType->Height = Stream_Get_UINT32(s);
100 mediaType->FrameRateNumerator = Stream_Get_UINT32(s);
101 mediaType->FrameRateDenominator = Stream_Get_UINT32(s);
102 mediaType->PixelAspectRatioNumerator = Stream_Get_UINT32(s);
103 mediaType->PixelAspectRatioDenominator = Stream_Get_UINT32(s);
104
105 if (mediaType->FrameRateNumerator == 0)
106 return FALSE;
107 if (mediaType->FrameRateDenominator == 0)
108 return FALSE;
109 if (mediaType->PixelAspectRatioNumerator == 0)
110 return FALSE;
111 if (mediaType->PixelAspectRatioDenominator == 0)
112 return FALSE;
113
114 const uint8_t flags = Stream_Get_UINT8(s);
115 if (!rdpecam_valid_MediaTypeDescriptionFlags(flags))
116 return FALSE;
117 mediaType->Flags = WINPR_ASSERTING_INT_CAST(CAM_MEDIA_TYPE_DESCRIPTION_FLAGS, flags);
118 return TRUE;
119}
120
121static void ecam_dev_print_media_type(CAM_MEDIA_TYPE_DESCRIPTION* mediaType)
122{
123 WINPR_ASSERT(mediaType);
124
125 WLog_DBG(TAG, "Format: %u, width: %u, height: %u, fps: %u, flags: %u", mediaType->Format,
126 mediaType->Width, mediaType->Height, mediaType->FrameRateNumerator, mediaType->Flags);
127}
128
134WINPR_ATTR_NODISCARD
135static wStream* ecam_dev_prepare_sample_response(CameraDevice* dev, size_t streamIndex)
136{
137 WINPR_ASSERT(dev);
138
139 CameraDeviceStream* stream = &dev->streams[streamIndex];
140 CAM_MSG_ID msg = CAM_MSG_ID_SampleResponse;
141
142 Stream_ResetPosition(stream->sampleRespBuffer);
143 if (!Stream_EnsureRemainingCapacity(stream->sampleRespBuffer, 3))
144 return nullptr;
145
146 Stream_Write_UINT8(stream->sampleRespBuffer,
147 WINPR_ASSERTING_INT_CAST(uint8_t, dev->ecam->version));
148 Stream_Write_UINT8(stream->sampleRespBuffer, WINPR_ASSERTING_INT_CAST(uint8_t, msg));
149 Stream_Write_UINT8(stream->sampleRespBuffer, WINPR_ASSERTING_INT_CAST(uint8_t, streamIndex));
150
151 return stream->sampleRespBuffer;
152}
153
154static BOOL mediaSupportDrops(CAM_MEDIA_FORMAT format)
155{
156 switch (format)
157 {
158 case CAM_MEDIA_FORMAT_H264:
159 return FALSE;
160 default:
161 return TRUE;
162 }
163}
164
165static UINT ecam_dev_send_pending(CameraDevice* dev, size_t streamIndex, CameraDeviceStream* stream)
166{
167 WINPR_ASSERT(dev);
168 WINPR_ASSERT(stream);
169
170 if (stream->samplesRequested <= 0)
171 {
172 WLog_VRB(TAG, "Frame delayed: No sample requested");
173 return CHANNEL_RC_OK;
174 }
175
176 if (!stream->haveSample)
177 {
178 WLog_VRB(TAG, "Frame response delayed: No sample available");
179 return CHANNEL_RC_OK;
180 }
181
182 wStream* output = ecam_dev_prepare_sample_response(dev, streamIndex);
183 if (!output)
184 return CHANNEL_RC_OK;
185
186 const BYTE* encodedSample = Stream_Buffer(stream->pendingSample);
187 const size_t encodedSize = Stream_Length(stream->pendingSample);
188 if (!ecam_encoder_compress(stream, encodedSample, encodedSize, output))
189 {
190 WLog_DBG(TAG, "Frame dropped: error in ecam_encoder_compress");
191 stream->haveSample = FALSE;
192 return CHANNEL_RC_OK;
193 }
194
195 if (!stream->streaming)
196 {
197 WLog_DBG(TAG, "Frame delayed/dropped: stream stopped");
198 return CHANNEL_RC_OK;
199 }
200
201 stream->samplesRequested--;
202 stream->haveSample = FALSE;
203
204 /* channel write is protected by critical section in dvcman_write_channel */
205 return ecam_channel_write(dev->ecam, stream->hSampleReqChannel, CAM_MSG_ID_SampleResponse,
206 output, FALSE /* don't free stream */);
207}
208
209static UINT ecam_dev_sample_captured_callback(CameraDevice* dev, size_t streamIndex,
210 const BYTE* sample, size_t size)
211{
212 WINPR_ASSERT(dev);
213
214 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
215 return ERROR_INVALID_INDEX;
216
217 CameraDeviceStream* stream = &dev->streams[streamIndex];
218
219 if (!stream->streaming)
220 {
221 WLog_DBG(TAG, "Frame drop: stream not running");
222 return CHANNEL_RC_OK;
223 }
224
225 EnterCriticalSection(&stream->lock);
226 UINT ret = CHANNEL_RC_NO_MEMORY;
227
228 /* If we already have a waiting sample, let's see if the input format support dropping
229 * frames so that we could just "refresh" the pending sample, otherwise we must wait until
230 * a frame request flushes it
231 */
232
233 if (stream->haveSample && !mediaSupportDrops(stream->formats.inputFormat))
234 {
235 /* we can't drop samples, so we have to wait until the pending sample is
236 * sent, by a sample request.
237 *
238 * When we're here we already have a sample ready to be sent, the delay between 2 frames
239 * seems like a reasonable wait delay. For instance 60 FPS means a frame every 16ms.
240 * We also cap that wait delay to not spinloop and not get stuck for too long.
241 * */
242 DWORD waitDelay = (1000 * stream->currMediaType.FrameRateDenominator) /
243 stream->currMediaType.FrameRateNumerator;
244 if (waitDelay < 16)
245 waitDelay = 16;
246 if (waitDelay > 100)
247 waitDelay = 100;
248
249 while (stream->haveSample && stream->streaming)
250 {
251 LeaveCriticalSection(&stream->lock);
252
253 SleepEx(waitDelay, TRUE);
254
255 EnterCriticalSection(&stream->lock);
256 }
257
258 if (!stream->streaming)
259 {
260 WLog_DBG(TAG, "Frame drop: stream not running");
261 ret = CHANNEL_RC_OK;
262 goto out;
263 }
264 }
265
266 Stream_ResetPosition(stream->pendingSample);
267 if (!Stream_EnsureRemainingCapacity(stream->pendingSample, size))
268 goto out;
269
270 Stream_Write(stream->pendingSample, sample, size);
271 Stream_SealLength(stream->pendingSample);
272 stream->haveSample = TRUE;
273
274 ret = ecam_dev_send_pending(dev, streamIndex, stream);
275
276out:
277 LeaveCriticalSection(&stream->lock);
278 return ret;
279}
280
281static void ecam_dev_stop_stream(CameraDevice* dev, size_t streamIndex)
282{
283 WINPR_ASSERT(dev);
284
285 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
286 return;
287
288 CameraDeviceStream* stream = &dev->streams[streamIndex];
289
290 if (stream->streaming)
291 {
292 stream->streaming = FALSE;
293 dev->ihal->StopStream(dev->ihal, dev->deviceId, 0);
294
295 DeleteCriticalSection(&stream->lock);
296 }
297
298 Stream_Free(stream->sampleRespBuffer, TRUE);
299 stream->sampleRespBuffer = nullptr;
300
301 Stream_Free(stream->pendingSample, TRUE);
302 stream->pendingSample = nullptr;
303
304 ecam_encoder_context_free(stream);
305}
306
312static UINT ecam_dev_process_stop_streams_request(CameraDevice* dev,
313 GENERIC_CHANNEL_CALLBACK* hchannel, wStream* s)
314{
315 WINPR_ASSERT(dev);
316 WINPR_UNUSED(s);
317
318 for (size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
319 ecam_dev_stop_stream(dev, i);
320
321 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
322}
323
329static UINT ecam_dev_process_start_streams_request(CameraDevice* dev,
330 GENERIC_CHANNEL_CALLBACK* hchannel, wStream* s)
331{
332 BYTE streamIndex = 0;
333 CAM_MEDIA_TYPE_DESCRIPTION mediaType = WINPR_C_ARRAY_INIT;
334
335 WINPR_ASSERT(dev);
336
337 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1 + 26))
338 return ERROR_INVALID_DATA;
339
340 Stream_Read_UINT8(s, streamIndex);
341
342 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
343 {
344 WLog_ERR(TAG, "Incorrect streamIndex %" PRIu8, streamIndex);
345 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_InvalidStreamNumber);
346 return ERROR_INVALID_INDEX;
347 }
348
349 if (!ecam_dev_read_media_type(s, &mediaType))
350 {
351 WLog_ERR(TAG, "Unable to read MEDIA_TYPE_DESCRIPTION");
352 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_InvalidMessage);
353 return ERROR_INVALID_DATA;
354 }
355
356 ecam_dev_print_media_type(&mediaType);
357
358 CameraDeviceStream* stream = &dev->streams[streamIndex];
359
360 if (stream->streaming)
361 {
362 WLog_ERR(TAG, "Streaming already in progress, device %s, streamIndex %u", dev->deviceId,
363 streamIndex);
364 return CAM_ERROR_CODE_UnexpectedError;
365 }
366
367 /* saving media type description for CurrentMediaTypeRequest,
368 * to be done before calling ecam_encoder_context_init
369 */
370 stream->currMediaType = mediaType;
371
372 if (!ecam_encoder_context_init(stream))
373 {
374 WLog_ERR(TAG, "stream_ecam_encoder_init failed");
375 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_UnexpectedError);
376 return ERROR_INVALID_DATA;
377 }
378
379 stream->sampleRespBuffer = Stream_New(nullptr, ECAM_SAMPLE_RESPONSE_BUFFER_SIZE);
380 if (!stream->sampleRespBuffer)
381 {
382 WLog_ERR(TAG, "Stream_New failed");
383 ecam_dev_stop_stream(dev, streamIndex);
384 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_OutOfMemory);
385 return ERROR_INVALID_DATA;
386 }
387
388 /* replacing outputFormat with inputFormat in mediaType before starting stream */
389 mediaType.Format = streamInputFormat(stream);
390
391 stream->samplesRequested = 0;
392 stream->haveSample = FALSE;
393
394 if (!InitializeCriticalSectionEx(&stream->lock, 0, 0))
395 {
396 WLog_ERR(TAG, "InitializeCriticalSectionEx failed");
397 ecam_dev_stop_stream(dev, streamIndex);
398 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_OutOfMemory);
399 return ERROR_INVALID_DATA;
400 }
401
402 stream->pendingSample = Stream_New(nullptr, 4ull * mediaType.Width * mediaType.Height);
403 if (!stream->pendingSample)
404 {
405 WLog_ERR(TAG, "pending stream failed");
406 ecam_dev_stop_stream(dev, streamIndex);
407 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_OutOfMemory);
408 return ERROR_INVALID_DATA;
409 }
410
411 const CAM_ERROR_CODE error = dev->ihal->StartStream(dev->ihal, dev, streamIndex, &mediaType,
412 ecam_dev_sample_captured_callback);
413 if (error)
414 {
415 WLog_ERR(TAG, "StartStream failure");
416 ecam_dev_stop_stream(dev, streamIndex);
417 ecam_channel_send_error_response(dev->ecam, hchannel, error);
418 return ERROR_INVALID_DATA;
419 }
420
421 stream->streaming = TRUE;
422 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
423}
424
430static UINT ecam_dev_process_property_list_request(CameraDevice* dev,
431 GENERIC_CHANNEL_CALLBACK* hchannel,
432 WINPR_ATTR_UNUSED wStream* s)
433{
434 WINPR_ASSERT(dev);
435 // TODO: supported properties implementation
436
437 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_PropertyListResponse);
438}
439
445static UINT ecam_dev_send_current_media_type_response(CameraDevice* dev,
446 GENERIC_CHANNEL_CALLBACK* hchannel,
448{
449 CAM_MSG_ID msg = CAM_MSG_ID_CurrentMediaTypeResponse;
450
451 WINPR_ASSERT(dev);
452
453 wStream* s = Stream_New(nullptr, CAM_HEADER_SIZE + sizeof(CAM_MEDIA_TYPE_DESCRIPTION));
454 if (!s)
455 {
456 WLog_ERR(TAG, "Stream_New failed");
457 return ERROR_NOT_ENOUGH_MEMORY;
458 }
459
460 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, dev->ecam->version));
461 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, msg));
462
463 ecam_dev_write_media_type(s, mediaType);
464
465 return ecam_channel_write(dev->ecam, hchannel, msg, s, TRUE);
466}
467
473static UINT ecam_dev_process_sample_request(CameraDevice* dev, GENERIC_CHANNEL_CALLBACK* hchannel,
474 wStream* s)
475{
476 BYTE streamIndex = 0;
477
478 WINPR_ASSERT(dev);
479
480 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
481 return ERROR_INVALID_DATA;
482
483 Stream_Read_UINT8(s, streamIndex);
484
485 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
486 {
487 WLog_ERR(TAG, "Incorrect streamIndex %u", streamIndex);
488 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_InvalidStreamNumber);
489 return ERROR_INVALID_INDEX;
490 }
491
492 CameraDeviceStream* stream = &dev->streams[streamIndex];
493
494 EnterCriticalSection(&stream->lock);
495
496 /* need to save channel because responses are asynchronous and coming from capture thread */
497 if (stream->hSampleReqChannel != hchannel)
498 stream->hSampleReqChannel = hchannel;
499
500 stream->samplesRequested++;
501 const UINT ret = ecam_dev_send_pending(dev, streamIndex, stream);
502
503 LeaveCriticalSection(&stream->lock);
504 return ret;
505}
506
512static UINT ecam_dev_process_current_media_type_request(CameraDevice* dev,
513 GENERIC_CHANNEL_CALLBACK* hchannel,
514 wStream* s)
515{
516 BYTE streamIndex = 0;
517
518 WINPR_ASSERT(dev);
519
520 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
521 return ERROR_INVALID_DATA;
522
523 Stream_Read_UINT8(s, streamIndex);
524
525 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
526 {
527 WLog_ERR(TAG, "Incorrect streamIndex %u", streamIndex);
528 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_InvalidStreamNumber);
529 return ERROR_INVALID_INDEX;
530 }
531
532 CameraDeviceStream* stream = &dev->streams[streamIndex];
533
534 if (stream->currMediaType.Format == 0)
535 {
536 WLog_ERR(TAG, "Current media type unknown for streamIndex %u", streamIndex);
537 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_NotInitialized);
538 return ERROR_DEVICE_REINITIALIZATION_NEEDED;
539 }
540
541 return ecam_dev_send_current_media_type_response(dev, hchannel, &stream->currMediaType);
542}
543
549static UINT ecam_dev_send_media_type_list_response(CameraDevice* dev,
550 GENERIC_CHANNEL_CALLBACK* hchannel,
551 CAM_MEDIA_TYPE_DESCRIPTION* mediaTypes,
552 size_t nMediaTypes)
553{
554 CAM_MSG_ID msg = CAM_MSG_ID_MediaTypeListResponse;
555
556 WINPR_ASSERT(dev);
557
558 wStream* s = Stream_New(nullptr, CAM_HEADER_SIZE + ECAM_MAX_MEDIA_TYPE_DESCRIPTORS *
560 if (!s)
561 {
562 WLog_ERR(TAG, "Stream_New failed");
563 return ERROR_NOT_ENOUGH_MEMORY;
564 }
565
566 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, dev->ecam->version));
567 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, msg));
568
569 for (size_t i = 0; i < nMediaTypes; i++, mediaTypes++)
570 {
571 ecam_dev_write_media_type(s, mediaTypes);
572 }
573
574 return ecam_channel_write(dev->ecam, hchannel, msg, s, TRUE);
575}
576
582static UINT ecam_dev_process_media_type_list_request(CameraDevice* dev,
583 GENERIC_CHANNEL_CALLBACK* hchannel, wStream* s)
584{
585 UINT error = CHANNEL_RC_OK;
586 BYTE streamIndex = 0;
587 CAM_MEDIA_TYPE_DESCRIPTION* mediaTypes = nullptr;
588 size_t nMediaTypes = ECAM_MAX_MEDIA_TYPE_DESCRIPTORS;
589
590 WINPR_ASSERT(dev);
591
592 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
593 return ERROR_INVALID_DATA;
594
595 Stream_Read_UINT8(s, streamIndex);
596
597 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
598 {
599 WLog_ERR(TAG, "Incorrect streamIndex %u", streamIndex);
600 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_InvalidStreamNumber);
601 return ERROR_INVALID_INDEX;
602 }
603 CameraDeviceStream* stream = &dev->streams[streamIndex];
604
605 mediaTypes =
606 (CAM_MEDIA_TYPE_DESCRIPTION*)calloc(nMediaTypes, sizeof(CAM_MEDIA_TYPE_DESCRIPTION));
607 if (!mediaTypes)
608 {
609 WLog_ERR(TAG, "calloc failed");
610 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_OutOfMemory);
611 return CHANNEL_RC_NO_MEMORY;
612 }
613
614 size_t nSupportedFormats = 0;
615 const CAM_MEDIA_FORMAT_INFO* supportedFormats = getSupportedFormats(&nSupportedFormats);
616
617 INT16 formatIndex =
618 dev->ihal->GetMediaTypeDescriptions(dev->ihal, dev->deviceId, streamIndex, supportedFormats,
619 nSupportedFormats, mediaTypes, &nMediaTypes);
620 if (formatIndex == -1 || nMediaTypes == 0)
621 {
622 WLog_ERR(TAG, "Camera doesn't support any compatible video formats");
623 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_ItemNotFound);
624 error = ERROR_DEVICE_FEATURE_NOT_SUPPORTED;
625 goto error;
626 }
627
628 stream->formats = supportedFormats[formatIndex];
629
630 /* replacing inputFormat with outputFormat in mediaTypes before sending response */
631 for (size_t i = 0; i < nMediaTypes; i++)
632 {
633 mediaTypes[i].Format = streamOutputFormat(stream);
634 mediaTypes[i].Flags = CAM_MEDIA_TYPE_DESCRIPTION_FLAG_DecodingRequired;
635 }
636
637 if (stream->currMediaType.Format == 0)
638 {
639 /* saving 1st media type description for CurrentMediaTypeRequest */
640 stream->currMediaType = mediaTypes[0];
641 }
642
643 error = ecam_dev_send_media_type_list_response(dev, hchannel, mediaTypes, nMediaTypes);
644
645error:
646 free(mediaTypes);
647 return error;
648}
649
655static UINT ecam_dev_send_stream_list_response(CameraDevice* dev,
656 GENERIC_CHANNEL_CALLBACK* hchannel)
657{
658 CAM_MSG_ID msg = CAM_MSG_ID_StreamListResponse;
659
660 WINPR_ASSERT(dev);
661
662 wStream* s = Stream_New(nullptr, CAM_HEADER_SIZE + sizeof(CAM_STREAM_DESCRIPTION));
663 if (!s)
664 {
665 WLog_ERR(TAG, "Stream_New failed");
666 return ERROR_NOT_ENOUGH_MEMORY;
667 }
668
669 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, dev->ecam->version));
670 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, msg));
671
672 /* single stream description */
673 Stream_Write_UINT16(s, CAM_STREAM_FRAME_SOURCE_TYPE_Color);
674 Stream_Write_UINT8(s, CAM_STREAM_CATEGORY_Capture);
675 Stream_Write_UINT8(s, TRUE /* Selected */);
676 Stream_Write_UINT8(s, FALSE /* CanBeShared */);
677
678 return ecam_channel_write(dev->ecam, hchannel, msg, s, TRUE);
679}
680
686static UINT ecam_dev_process_stream_list_request(CameraDevice* dev,
687 GENERIC_CHANNEL_CALLBACK* hchannel,
688 WINPR_ATTR_UNUSED wStream* s)
689{
690 return ecam_dev_send_stream_list_response(dev, hchannel);
691}
692
698static UINT ecam_dev_process_activate_device_request(CameraDevice* dev,
699 GENERIC_CHANNEL_CALLBACK* hchannel,
700 WINPR_ATTR_UNUSED wStream* s)
701{
702 WINPR_ASSERT(dev);
703 CAM_ERROR_CODE errorCode = CAM_ERROR_CODE_None;
704
705 if (dev->ihal->Activate(dev->ihal, dev->deviceId, &errorCode))
706 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
707
708 return ecam_channel_send_error_response(dev->ecam, hchannel, errorCode);
709}
710
716static UINT ecam_dev_process_deactivate_device_request(CameraDevice* dev,
717 GENERIC_CHANNEL_CALLBACK* hchannel,
718 wStream* s)
719{
720 WINPR_ASSERT(dev);
721 WINPR_UNUSED(s);
722
723 for (size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
724 ecam_dev_stop_stream(dev, i);
725
726 CAM_ERROR_CODE errorCode = CAM_ERROR_CODE_None;
727 if (dev->ihal->Deactivate(dev->ihal, dev->deviceId, &errorCode))
728 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
729
730 return ecam_channel_send_error_response(dev->ecam, hchannel, errorCode);
731}
732
738static UINT ecam_dev_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data)
739{
740 UINT error = CHANNEL_RC_OK;
741 BYTE version = 0;
742 BYTE messageId = 0;
743 GENERIC_CHANNEL_CALLBACK* hchannel = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback;
744
745 if (!hchannel || !data)
746 return ERROR_INVALID_PARAMETER;
747
748 CameraDevice* dev = (CameraDevice*)hchannel->plugin;
749
750 if (!dev)
751 return ERROR_INTERNAL_ERROR;
752
753 if (!Stream_CheckAndLogRequiredLength(TAG, data, CAM_HEADER_SIZE))
754 return ERROR_NO_DATA;
755
756 Stream_Read_UINT8(data, version);
757 Stream_Read_UINT8(data, messageId);
758 WLog_DBG(TAG, "ChannelId=%" PRIu32 ", MessageId=0x%02" PRIx8 ", Version=%d",
759 hchannel->channel_mgr->GetChannelId(hchannel->channel), messageId, version);
760
761 switch (messageId)
762 {
763 case CAM_MSG_ID_ActivateDeviceRequest:
764 error = ecam_dev_process_activate_device_request(dev, hchannel, data);
765 break;
766
767 case CAM_MSG_ID_DeactivateDeviceRequest:
768 error = ecam_dev_process_deactivate_device_request(dev, hchannel, data);
769 break;
770
771 case CAM_MSG_ID_StreamListRequest:
772 error = ecam_dev_process_stream_list_request(dev, hchannel, data);
773 break;
774
775 case CAM_MSG_ID_MediaTypeListRequest:
776 error = ecam_dev_process_media_type_list_request(dev, hchannel, data);
777 break;
778
779 case CAM_MSG_ID_CurrentMediaTypeRequest:
780 error = ecam_dev_process_current_media_type_request(dev, hchannel, data);
781 break;
782
783 case CAM_MSG_ID_PropertyListRequest:
784 error = ecam_dev_process_property_list_request(dev, hchannel, data);
785 break;
786
787 case CAM_MSG_ID_StartStreamsRequest:
788 error = ecam_dev_process_start_streams_request(dev, hchannel, data);
789 break;
790
791 case CAM_MSG_ID_StopStreamsRequest:
792 error = ecam_dev_process_stop_streams_request(dev, hchannel, data);
793 break;
794
795 case CAM_MSG_ID_SampleRequest:
796 error = ecam_dev_process_sample_request(dev, hchannel, data);
797 break;
798
799 default:
800 WLog_WARN(TAG, "unknown MessageId=0x%02" PRIx8 "", messageId);
801 error = ERROR_INVALID_DATA;
802 ecam_channel_send_error_response(dev->ecam, hchannel,
803 CAM_ERROR_CODE_OperationNotSupported);
804 break;
805 }
806
807 return error;
808}
809
815static UINT ecam_dev_on_open(WINPR_ATTR_UNUSED IWTSVirtualChannelCallback* pChannelCallback)
816{
817 WLog_DBG(TAG, "entered");
818 return CHANNEL_RC_OK;
819}
820
826static UINT ecam_dev_on_close(IWTSVirtualChannelCallback* pChannelCallback)
827{
828 GENERIC_CHANNEL_CALLBACK* hchannel = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback;
829 WINPR_ASSERT(hchannel);
830
831 CameraDevice* dev = (CameraDevice*)hchannel->plugin;
832 WINPR_ASSERT(dev);
833
834 WLog_DBG(TAG, "entered");
835
836 for (size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
837 ecam_dev_stop_stream(dev, i);
838
839 /* make sure this channel is not used for sample responses */
840 for (size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
841 if (dev->streams[i].hSampleReqChannel == hchannel)
842 dev->streams[i].hSampleReqChannel = nullptr;
843
844 free(hchannel);
845 return CHANNEL_RC_OK;
846}
847
853static UINT ecam_dev_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
854 IWTSVirtualChannel* pChannel,
855 WINPR_ATTR_UNUSED BYTE* Data,
856 WINPR_ATTR_UNUSED BOOL* pbAccept,
857 IWTSVirtualChannelCallback** ppCallback)
858{
859 GENERIC_LISTENER_CALLBACK* hlistener = (GENERIC_LISTENER_CALLBACK*)pListenerCallback;
860
861 if (!hlistener || !hlistener->plugin)
862 return ERROR_INTERNAL_ERROR;
863
864 WLog_DBG(TAG, "entered");
865 GENERIC_CHANNEL_CALLBACK* hchannel =
867
868 if (!hchannel)
869 {
870 WLog_ERR(TAG, "calloc failed");
871 return CHANNEL_RC_NO_MEMORY;
872 }
873
874 hchannel->iface.OnDataReceived = ecam_dev_on_data_received;
875 hchannel->iface.OnOpen = ecam_dev_on_open;
876 hchannel->iface.OnClose = ecam_dev_on_close;
877 hchannel->plugin = hlistener->plugin;
878 hchannel->channel_mgr = hlistener->channel_mgr;
879 hchannel->channel = pChannel;
880 *ppCallback = (IWTSVirtualChannelCallback*)hchannel;
881 return CHANNEL_RC_OK;
882}
883
889CameraDevice* ecam_dev_create(CameraPlugin* ecam, const char* deviceId,
890 WINPR_ATTR_UNUSED const char* deviceName)
891{
892 WINPR_ASSERT(ecam);
893 WINPR_ASSERT(ecam->hlistener);
894
895 IWTSVirtualChannelManager* pChannelMgr = ecam->hlistener->channel_mgr;
896 WINPR_ASSERT(pChannelMgr);
897
898 WLog_DBG(TAG, "entered for %s", deviceId);
899
900 CameraDevice* dev = (CameraDevice*)calloc(1, sizeof(CameraDevice));
901
902 if (!dev)
903 {
904 WLog_ERR(TAG, "calloc failed");
905 return nullptr;
906 }
907
908 dev->ecam = ecam;
909 dev->ihal = ecam->ihal;
910 strncpy(dev->deviceId, deviceId, sizeof(dev->deviceId) - 1);
911 dev->hlistener = (GENERIC_LISTENER_CALLBACK*)calloc(1, sizeof(GENERIC_LISTENER_CALLBACK));
912
913 if (!dev->hlistener)
914 {
915 free(dev);
916 WLog_ERR(TAG, "calloc failed");
917 return nullptr;
918 }
919
920 dev->hlistener->iface.OnNewChannelConnection = ecam_dev_on_new_channel_connection;
921 dev->hlistener->plugin = (IWTSPlugin*)dev;
922 dev->hlistener->channel_mgr = pChannelMgr;
923 if (CHANNEL_RC_OK != pChannelMgr->CreateListener(pChannelMgr, deviceId, 0,
924 &dev->hlistener->iface, &dev->listener))
925 {
926 free(dev->hlistener);
927 free(dev);
928 WLog_ERR(TAG, "CreateListener failed");
929 return nullptr;
930 }
931
932 return dev;
933}
934
941void ecam_dev_destroy(CameraDevice* dev)
942{
943 if (!dev)
944 return;
945
946 WLog_DBG(TAG, "entered for %s", dev->deviceId);
947
948 if (dev->hlistener)
949 {
950 IWTSVirtualChannelManager* mgr = dev->hlistener->channel_mgr;
951 if (mgr)
952 IFCALL(mgr->DestroyListener, mgr, dev->listener);
953 }
954
955 free(dev->hlistener);
956
957 for (size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
958 ecam_dev_stop_stream(dev, i);
959
960 free(dev);
961}