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