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 Stream_Read_UINT32(s, mediaType->Width);
99 Stream_Read_UINT32(s, mediaType->Height);
100 Stream_Read_UINT32(s, mediaType->FrameRateNumerator);
101 Stream_Read_UINT32(s, mediaType->FrameRateDenominator);
102 Stream_Read_UINT32(s, mediaType->PixelAspectRatioNumerator);
103 Stream_Read_UINT32(s, mediaType->PixelAspectRatioDenominator);
104
105 const uint8_t flags = Stream_Get_UINT8(s);
106 if (!rdpecam_valid_MediaTypeDescriptionFlags(flags))
107 return FALSE;
108 mediaType->Flags = WINPR_ASSERTING_INT_CAST(CAM_MEDIA_TYPE_DESCRIPTION_FLAGS, flags);
109 return TRUE;
110}
111
112static void ecam_dev_print_media_type(CAM_MEDIA_TYPE_DESCRIPTION* mediaType)
113{
114 WINPR_ASSERT(mediaType);
115
116 WLog_DBG(TAG, "Format: %u, width: %u, height: %u, fps: %u, flags: %u", mediaType->Format,
117 mediaType->Width, mediaType->Height, mediaType->FrameRateNumerator, mediaType->Flags);
118}
119
125WINPR_ATTR_NODISCARD
126static wStream* ecam_dev_prepare_sample_response(CameraDevice* dev, size_t streamIndex)
127{
128 WINPR_ASSERT(dev);
129
130 CameraDeviceStream* stream = &dev->streams[streamIndex];
131 CAM_MSG_ID msg = CAM_MSG_ID_SampleResponse;
132
133 Stream_ResetPosition(stream->sampleRespBuffer);
134 if (!Stream_EnsureRemainingCapacity(stream->sampleRespBuffer, 3))
135 return nullptr;
136
137 Stream_Write_UINT8(stream->sampleRespBuffer,
138 WINPR_ASSERTING_INT_CAST(uint8_t, dev->ecam->version));
139 Stream_Write_UINT8(stream->sampleRespBuffer, WINPR_ASSERTING_INT_CAST(uint8_t, msg));
140 Stream_Write_UINT8(stream->sampleRespBuffer, WINPR_ASSERTING_INT_CAST(uint8_t, streamIndex));
141
142 return stream->sampleRespBuffer;
143}
144
145static BOOL mediaSupportDrops(CAM_MEDIA_FORMAT format)
146{
147 switch (format)
148 {
149 case CAM_MEDIA_FORMAT_H264:
150 return FALSE;
151 default:
152 return TRUE;
153 }
154}
155
156static UINT ecam_dev_send_pending(CameraDevice* dev, size_t streamIndex, CameraDeviceStream* stream)
157{
158 WINPR_ASSERT(dev);
159 WINPR_ASSERT(stream);
160
161 if (stream->samplesRequested <= 0)
162 {
163 WLog_VRB(TAG, "Frame delayed: No sample requested");
164 return CHANNEL_RC_OK;
165 }
166
167 if (!stream->haveSample)
168 {
169 WLog_VRB(TAG, "Frame response delayed: No sample available");
170 return CHANNEL_RC_OK;
171 }
172
173 wStream* output = ecam_dev_prepare_sample_response(dev, streamIndex);
174 if (!output)
175 return CHANNEL_RC_OK;
176
177 const BYTE* encodedSample = Stream_Buffer(stream->pendingSample);
178 const size_t encodedSize = Stream_Length(stream->pendingSample);
179 if (!ecam_encoder_compress(stream, encodedSample, encodedSize, output))
180 {
181 WLog_DBG(TAG, "Frame dropped: error in ecam_encoder_compress");
182 stream->haveSample = FALSE;
183 return CHANNEL_RC_OK;
184 }
185
186 if (!stream->streaming)
187 {
188 WLog_DBG(TAG, "Frame delayed/dropped: stream stopped");
189 return CHANNEL_RC_OK;
190 }
191
192 stream->samplesRequested--;
193 stream->haveSample = FALSE;
194
195 /* channel write is protected by critical section in dvcman_write_channel */
196 return ecam_channel_write(dev->ecam, stream->hSampleReqChannel, CAM_MSG_ID_SampleResponse,
197 output, FALSE /* don't free stream */);
198}
199
200static UINT ecam_dev_sample_captured_callback(CameraDevice* dev, size_t streamIndex,
201 const BYTE* sample, size_t size)
202{
203 WINPR_ASSERT(dev);
204
205 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
206 return ERROR_INVALID_INDEX;
207
208 CameraDeviceStream* stream = &dev->streams[streamIndex];
209
210 if (!stream->streaming)
211 {
212 WLog_DBG(TAG, "Frame drop: stream not running");
213 return CHANNEL_RC_OK;
214 }
215
216 EnterCriticalSection(&stream->lock);
217 UINT ret = CHANNEL_RC_NO_MEMORY;
218
219 /* If we already have a waiting sample, let's see if the input format support dropping
220 * frames so that we could just "refresh" the pending sample, otherwise we must wait until
221 * a frame request flushes it
222 */
223
224 if (stream->haveSample && !mediaSupportDrops(stream->formats.inputFormat))
225 {
226 /* we can't drop samples, so we have to wait until the pending sample is
227 * sent, by a sample request.
228 *
229 * When we're here we already have a sample ready to be sent, the delay between 2 frames
230 * seems like a reasonable wait delay. For instance 60 FPS means a frame every 16ms.
231 * We also cap that wait delay to not spinloop and not get stuck for too long.
232 * */
233 DWORD waitDelay = (1000 * stream->currMediaType.FrameRateDenominator) /
234 stream->currMediaType.FrameRateNumerator;
235 if (waitDelay < 16)
236 waitDelay = 16;
237 if (waitDelay > 100)
238 waitDelay = 100;
239
240 while (stream->haveSample && stream->streaming)
241 {
242 LeaveCriticalSection(&stream->lock);
243
244 SleepEx(waitDelay, TRUE);
245
246 EnterCriticalSection(&stream->lock);
247 }
248
249 if (!stream->streaming)
250 {
251 WLog_DBG(TAG, "Frame drop: stream not running");
252 ret = CHANNEL_RC_OK;
253 goto out;
254 }
255 }
256
257 Stream_ResetPosition(stream->pendingSample);
258 if (!Stream_EnsureRemainingCapacity(stream->pendingSample, size))
259 goto out;
260
261 Stream_Write(stream->pendingSample, sample, size);
262 Stream_SealLength(stream->pendingSample);
263 stream->haveSample = TRUE;
264
265 ret = ecam_dev_send_pending(dev, streamIndex, stream);
266
267out:
268 LeaveCriticalSection(&stream->lock);
269 return ret;
270}
271
272static void ecam_dev_stop_stream(CameraDevice* dev, size_t streamIndex)
273{
274 WINPR_ASSERT(dev);
275
276 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
277 return;
278
279 CameraDeviceStream* stream = &dev->streams[streamIndex];
280
281 if (stream->streaming)
282 {
283 stream->streaming = FALSE;
284 dev->ihal->StopStream(dev->ihal, dev->deviceId, 0);
285
286 DeleteCriticalSection(&stream->lock);
287 }
288
289 Stream_Free(stream->sampleRespBuffer, TRUE);
290 stream->sampleRespBuffer = nullptr;
291
292 Stream_Free(stream->pendingSample, TRUE);
293 stream->pendingSample = nullptr;
294
295 ecam_encoder_context_free(stream);
296}
297
303static UINT ecam_dev_process_stop_streams_request(CameraDevice* dev,
304 GENERIC_CHANNEL_CALLBACK* hchannel, wStream* s)
305{
306 WINPR_ASSERT(dev);
307 WINPR_UNUSED(s);
308
309 for (size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
310 ecam_dev_stop_stream(dev, i);
311
312 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
313}
314
320static UINT ecam_dev_process_start_streams_request(CameraDevice* dev,
321 GENERIC_CHANNEL_CALLBACK* hchannel, wStream* s)
322{
323 BYTE streamIndex = 0;
324 CAM_MEDIA_TYPE_DESCRIPTION mediaType = WINPR_C_ARRAY_INIT;
325
326 WINPR_ASSERT(dev);
327
328 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1 + 26))
329 return ERROR_INVALID_DATA;
330
331 Stream_Read_UINT8(s, streamIndex);
332
333 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
334 {
335 WLog_ERR(TAG, "Incorrect streamIndex %" PRIu8, streamIndex);
336 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_InvalidStreamNumber);
337 return ERROR_INVALID_INDEX;
338 }
339
340 if (!ecam_dev_read_media_type(s, &mediaType))
341 {
342 WLog_ERR(TAG, "Unable to read MEDIA_TYPE_DESCRIPTION");
343 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_InvalidMessage);
344 return ERROR_INVALID_DATA;
345 }
346
347 ecam_dev_print_media_type(&mediaType);
348
349 CameraDeviceStream* stream = &dev->streams[streamIndex];
350
351 if (stream->streaming)
352 {
353 WLog_ERR(TAG, "Streaming already in progress, device %s, streamIndex %u", dev->deviceId,
354 streamIndex);
355 return CAM_ERROR_CODE_UnexpectedError;
356 }
357
358 /* saving media type description for CurrentMediaTypeRequest,
359 * to be done before calling ecam_encoder_context_init
360 */
361 stream->currMediaType = mediaType;
362
363 if (!ecam_encoder_context_init(stream))
364 {
365 WLog_ERR(TAG, "stream_ecam_encoder_init failed");
366 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_UnexpectedError);
367 return ERROR_INVALID_DATA;
368 }
369
370 stream->sampleRespBuffer = Stream_New(nullptr, ECAM_SAMPLE_RESPONSE_BUFFER_SIZE);
371 if (!stream->sampleRespBuffer)
372 {
373 WLog_ERR(TAG, "Stream_New failed");
374 ecam_dev_stop_stream(dev, streamIndex);
375 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_OutOfMemory);
376 return ERROR_INVALID_DATA;
377 }
378
379 /* replacing outputFormat with inputFormat in mediaType before starting stream */
380 mediaType.Format = streamInputFormat(stream);
381
382 stream->samplesRequested = 0;
383 stream->haveSample = FALSE;
384
385 if (!InitializeCriticalSectionEx(&stream->lock, 0, 0))
386 {
387 WLog_ERR(TAG, "InitializeCriticalSectionEx failed");
388 ecam_dev_stop_stream(dev, streamIndex);
389 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_OutOfMemory);
390 return ERROR_INVALID_DATA;
391 }
392
393 stream->pendingSample = Stream_New(nullptr, 4ull * mediaType.Width * mediaType.Height);
394 if (!stream->pendingSample)
395 {
396 WLog_ERR(TAG, "pending stream 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 const CAM_ERROR_CODE error = dev->ihal->StartStream(dev->ihal, dev, streamIndex, &mediaType,
403 ecam_dev_sample_captured_callback);
404 if (error)
405 {
406 WLog_ERR(TAG, "StartStream failure");
407 ecam_dev_stop_stream(dev, streamIndex);
408 ecam_channel_send_error_response(dev->ecam, hchannel, error);
409 return ERROR_INVALID_DATA;
410 }
411
412 stream->streaming = TRUE;
413 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
414}
415
421static UINT ecam_dev_process_property_list_request(CameraDevice* dev,
422 GENERIC_CHANNEL_CALLBACK* hchannel,
423 WINPR_ATTR_UNUSED wStream* s)
424{
425 WINPR_ASSERT(dev);
426 // TODO: supported properties implementation
427
428 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_PropertyListResponse);
429}
430
436static UINT ecam_dev_send_current_media_type_response(CameraDevice* dev,
437 GENERIC_CHANNEL_CALLBACK* hchannel,
439{
440 CAM_MSG_ID msg = CAM_MSG_ID_CurrentMediaTypeResponse;
441
442 WINPR_ASSERT(dev);
443
444 wStream* s = Stream_New(nullptr, CAM_HEADER_SIZE + sizeof(CAM_MEDIA_TYPE_DESCRIPTION));
445 if (!s)
446 {
447 WLog_ERR(TAG, "Stream_New failed");
448 return ERROR_NOT_ENOUGH_MEMORY;
449 }
450
451 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, dev->ecam->version));
452 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, msg));
453
454 ecam_dev_write_media_type(s, mediaType);
455
456 return ecam_channel_write(dev->ecam, hchannel, msg, s, TRUE);
457}
458
464static UINT ecam_dev_process_sample_request(CameraDevice* dev, GENERIC_CHANNEL_CALLBACK* hchannel,
465 wStream* s)
466{
467 BYTE streamIndex = 0;
468
469 WINPR_ASSERT(dev);
470
471 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
472 return ERROR_INVALID_DATA;
473
474 Stream_Read_UINT8(s, streamIndex);
475
476 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
477 {
478 WLog_ERR(TAG, "Incorrect streamIndex %u", streamIndex);
479 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_InvalidStreamNumber);
480 return ERROR_INVALID_INDEX;
481 }
482
483 CameraDeviceStream* stream = &dev->streams[streamIndex];
484
485 EnterCriticalSection(&stream->lock);
486
487 /* need to save channel because responses are asynchronous and coming from capture thread */
488 if (stream->hSampleReqChannel != hchannel)
489 stream->hSampleReqChannel = hchannel;
490
491 stream->samplesRequested++;
492 const UINT ret = ecam_dev_send_pending(dev, streamIndex, stream);
493
494 LeaveCriticalSection(&stream->lock);
495 return ret;
496}
497
503static UINT ecam_dev_process_current_media_type_request(CameraDevice* dev,
504 GENERIC_CHANNEL_CALLBACK* hchannel,
505 wStream* s)
506{
507 BYTE streamIndex = 0;
508
509 WINPR_ASSERT(dev);
510
511 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
512 return ERROR_INVALID_DATA;
513
514 Stream_Read_UINT8(s, streamIndex);
515
516 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
517 {
518 WLog_ERR(TAG, "Incorrect streamIndex %u", streamIndex);
519 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_InvalidStreamNumber);
520 return ERROR_INVALID_INDEX;
521 }
522
523 CameraDeviceStream* stream = &dev->streams[streamIndex];
524
525 if (stream->currMediaType.Format == 0)
526 {
527 WLog_ERR(TAG, "Current media type unknown for streamIndex %u", streamIndex);
528 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_NotInitialized);
529 return ERROR_DEVICE_REINITIALIZATION_NEEDED;
530 }
531
532 return ecam_dev_send_current_media_type_response(dev, hchannel, &stream->currMediaType);
533}
534
540static UINT ecam_dev_send_media_type_list_response(CameraDevice* dev,
541 GENERIC_CHANNEL_CALLBACK* hchannel,
542 CAM_MEDIA_TYPE_DESCRIPTION* mediaTypes,
543 size_t nMediaTypes)
544{
545 CAM_MSG_ID msg = CAM_MSG_ID_MediaTypeListResponse;
546
547 WINPR_ASSERT(dev);
548
549 wStream* s = Stream_New(nullptr, CAM_HEADER_SIZE + ECAM_MAX_MEDIA_TYPE_DESCRIPTORS *
551 if (!s)
552 {
553 WLog_ERR(TAG, "Stream_New failed");
554 return ERROR_NOT_ENOUGH_MEMORY;
555 }
556
557 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, dev->ecam->version));
558 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, msg));
559
560 for (size_t i = 0; i < nMediaTypes; i++, mediaTypes++)
561 {
562 ecam_dev_write_media_type(s, mediaTypes);
563 }
564
565 return ecam_channel_write(dev->ecam, hchannel, msg, s, TRUE);
566}
567
573static UINT ecam_dev_process_media_type_list_request(CameraDevice* dev,
574 GENERIC_CHANNEL_CALLBACK* hchannel, wStream* s)
575{
576 UINT error = CHANNEL_RC_OK;
577 BYTE streamIndex = 0;
578 CAM_MEDIA_TYPE_DESCRIPTION* mediaTypes = nullptr;
579 size_t nMediaTypes = ECAM_MAX_MEDIA_TYPE_DESCRIPTORS;
580
581 WINPR_ASSERT(dev);
582
583 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
584 return ERROR_INVALID_DATA;
585
586 Stream_Read_UINT8(s, streamIndex);
587
588 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
589 {
590 WLog_ERR(TAG, "Incorrect streamIndex %u", streamIndex);
591 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_InvalidStreamNumber);
592 return ERROR_INVALID_INDEX;
593 }
594 CameraDeviceStream* stream = &dev->streams[streamIndex];
595
596 mediaTypes =
597 (CAM_MEDIA_TYPE_DESCRIPTION*)calloc(nMediaTypes, sizeof(CAM_MEDIA_TYPE_DESCRIPTION));
598 if (!mediaTypes)
599 {
600 WLog_ERR(TAG, "calloc failed");
601 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_OutOfMemory);
602 return CHANNEL_RC_NO_MEMORY;
603 }
604
605 size_t nSupportedFormats = 0;
606 const CAM_MEDIA_FORMAT_INFO* supportedFormats = getSupportedFormats(&nSupportedFormats);
607
608 INT16 formatIndex =
609 dev->ihal->GetMediaTypeDescriptions(dev->ihal, dev->deviceId, streamIndex, supportedFormats,
610 nSupportedFormats, mediaTypes, &nMediaTypes);
611 if (formatIndex == -1 || nMediaTypes == 0)
612 {
613 WLog_ERR(TAG, "Camera doesn't support any compatible video formats");
614 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_ItemNotFound);
615 error = ERROR_DEVICE_FEATURE_NOT_SUPPORTED;
616 goto error;
617 }
618
619 stream->formats = supportedFormats[formatIndex];
620
621 /* replacing inputFormat with outputFormat in mediaTypes before sending response */
622 for (size_t i = 0; i < nMediaTypes; i++)
623 {
624 mediaTypes[i].Format = streamOutputFormat(stream);
625 mediaTypes[i].Flags = CAM_MEDIA_TYPE_DESCRIPTION_FLAG_DecodingRequired;
626 }
627
628 if (stream->currMediaType.Format == 0)
629 {
630 /* saving 1st media type description for CurrentMediaTypeRequest */
631 stream->currMediaType = mediaTypes[0];
632 }
633
634 error = ecam_dev_send_media_type_list_response(dev, hchannel, mediaTypes, nMediaTypes);
635
636error:
637 free(mediaTypes);
638 return error;
639}
640
646static UINT ecam_dev_send_stream_list_response(CameraDevice* dev,
647 GENERIC_CHANNEL_CALLBACK* hchannel)
648{
649 CAM_MSG_ID msg = CAM_MSG_ID_StreamListResponse;
650
651 WINPR_ASSERT(dev);
652
653 wStream* s = Stream_New(nullptr, CAM_HEADER_SIZE + sizeof(CAM_STREAM_DESCRIPTION));
654 if (!s)
655 {
656 WLog_ERR(TAG, "Stream_New failed");
657 return ERROR_NOT_ENOUGH_MEMORY;
658 }
659
660 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, dev->ecam->version));
661 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, msg));
662
663 /* single stream description */
664 Stream_Write_UINT16(s, CAM_STREAM_FRAME_SOURCE_TYPE_Color);
665 Stream_Write_UINT8(s, CAM_STREAM_CATEGORY_Capture);
666 Stream_Write_UINT8(s, TRUE /* Selected */);
667 Stream_Write_UINT8(s, FALSE /* CanBeShared */);
668
669 return ecam_channel_write(dev->ecam, hchannel, msg, s, TRUE);
670}
671
677static UINT ecam_dev_process_stream_list_request(CameraDevice* dev,
678 GENERIC_CHANNEL_CALLBACK* hchannel,
679 WINPR_ATTR_UNUSED wStream* s)
680{
681 return ecam_dev_send_stream_list_response(dev, hchannel);
682}
683
689static UINT ecam_dev_process_activate_device_request(CameraDevice* dev,
690 GENERIC_CHANNEL_CALLBACK* hchannel,
691 WINPR_ATTR_UNUSED wStream* s)
692{
693 WINPR_ASSERT(dev);
694 CAM_ERROR_CODE errorCode = CAM_ERROR_CODE_None;
695
696 if (dev->ihal->Activate(dev->ihal, dev->deviceId, &errorCode))
697 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
698
699 return ecam_channel_send_error_response(dev->ecam, hchannel, errorCode);
700}
701
707static UINT ecam_dev_process_deactivate_device_request(CameraDevice* dev,
708 GENERIC_CHANNEL_CALLBACK* hchannel,
709 wStream* s)
710{
711 WINPR_ASSERT(dev);
712 WINPR_UNUSED(s);
713
714 for (size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
715 ecam_dev_stop_stream(dev, i);
716
717 CAM_ERROR_CODE errorCode = CAM_ERROR_CODE_None;
718 if (dev->ihal->Deactivate(dev->ihal, dev->deviceId, &errorCode))
719 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
720
721 return ecam_channel_send_error_response(dev->ecam, hchannel, errorCode);
722}
723
729static UINT ecam_dev_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data)
730{
731 UINT error = CHANNEL_RC_OK;
732 BYTE version = 0;
733 BYTE messageId = 0;
734 GENERIC_CHANNEL_CALLBACK* hchannel = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback;
735
736 if (!hchannel || !data)
737 return ERROR_INVALID_PARAMETER;
738
739 CameraDevice* dev = (CameraDevice*)hchannel->plugin;
740
741 if (!dev)
742 return ERROR_INTERNAL_ERROR;
743
744 if (!Stream_CheckAndLogRequiredCapacity(TAG, data, CAM_HEADER_SIZE))
745 return ERROR_NO_DATA;
746
747 Stream_Read_UINT8(data, version);
748 Stream_Read_UINT8(data, messageId);
749 WLog_DBG(TAG, "ChannelId=%" PRIu32 ", MessageId=0x%02" PRIx8 ", Version=%d",
750 hchannel->channel_mgr->GetChannelId(hchannel->channel), messageId, version);
751
752 switch (messageId)
753 {
754 case CAM_MSG_ID_ActivateDeviceRequest:
755 error = ecam_dev_process_activate_device_request(dev, hchannel, data);
756 break;
757
758 case CAM_MSG_ID_DeactivateDeviceRequest:
759 error = ecam_dev_process_deactivate_device_request(dev, hchannel, data);
760 break;
761
762 case CAM_MSG_ID_StreamListRequest:
763 error = ecam_dev_process_stream_list_request(dev, hchannel, data);
764 break;
765
766 case CAM_MSG_ID_MediaTypeListRequest:
767 error = ecam_dev_process_media_type_list_request(dev, hchannel, data);
768 break;
769
770 case CAM_MSG_ID_CurrentMediaTypeRequest:
771 error = ecam_dev_process_current_media_type_request(dev, hchannel, data);
772 break;
773
774 case CAM_MSG_ID_PropertyListRequest:
775 error = ecam_dev_process_property_list_request(dev, hchannel, data);
776 break;
777
778 case CAM_MSG_ID_StartStreamsRequest:
779 error = ecam_dev_process_start_streams_request(dev, hchannel, data);
780 break;
781
782 case CAM_MSG_ID_StopStreamsRequest:
783 error = ecam_dev_process_stop_streams_request(dev, hchannel, data);
784 break;
785
786 case CAM_MSG_ID_SampleRequest:
787 error = ecam_dev_process_sample_request(dev, hchannel, data);
788 break;
789
790 default:
791 WLog_WARN(TAG, "unknown MessageId=0x%02" PRIx8 "", messageId);
792 error = ERROR_INVALID_DATA;
793 ecam_channel_send_error_response(dev->ecam, hchannel,
794 CAM_ERROR_CODE_OperationNotSupported);
795 break;
796 }
797
798 return error;
799}
800
806static UINT ecam_dev_on_open(WINPR_ATTR_UNUSED IWTSVirtualChannelCallback* pChannelCallback)
807{
808 WLog_DBG(TAG, "entered");
809 return CHANNEL_RC_OK;
810}
811
817static UINT ecam_dev_on_close(IWTSVirtualChannelCallback* pChannelCallback)
818{
819 GENERIC_CHANNEL_CALLBACK* hchannel = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback;
820 WINPR_ASSERT(hchannel);
821
822 CameraDevice* dev = (CameraDevice*)hchannel->plugin;
823 WINPR_ASSERT(dev);
824
825 WLog_DBG(TAG, "entered");
826
827 for (size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
828 ecam_dev_stop_stream(dev, i);
829
830 /* make sure this channel is not used for sample responses */
831 for (size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
832 if (dev->streams[i].hSampleReqChannel == hchannel)
833 dev->streams[i].hSampleReqChannel = nullptr;
834
835 free(hchannel);
836 return CHANNEL_RC_OK;
837}
838
844static UINT ecam_dev_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
845 IWTSVirtualChannel* pChannel,
846 WINPR_ATTR_UNUSED BYTE* Data,
847 WINPR_ATTR_UNUSED BOOL* pbAccept,
848 IWTSVirtualChannelCallback** ppCallback)
849{
850 GENERIC_LISTENER_CALLBACK* hlistener = (GENERIC_LISTENER_CALLBACK*)pListenerCallback;
851
852 if (!hlistener || !hlistener->plugin)
853 return ERROR_INTERNAL_ERROR;
854
855 WLog_DBG(TAG, "entered");
856 GENERIC_CHANNEL_CALLBACK* hchannel =
858
859 if (!hchannel)
860 {
861 WLog_ERR(TAG, "calloc failed");
862 return CHANNEL_RC_NO_MEMORY;
863 }
864
865 hchannel->iface.OnDataReceived = ecam_dev_on_data_received;
866 hchannel->iface.OnOpen = ecam_dev_on_open;
867 hchannel->iface.OnClose = ecam_dev_on_close;
868 hchannel->plugin = hlistener->plugin;
869 hchannel->channel_mgr = hlistener->channel_mgr;
870 hchannel->channel = pChannel;
871 *ppCallback = (IWTSVirtualChannelCallback*)hchannel;
872 return CHANNEL_RC_OK;
873}
874
880CameraDevice* ecam_dev_create(CameraPlugin* ecam, const char* deviceId,
881 WINPR_ATTR_UNUSED const char* deviceName)
882{
883 WINPR_ASSERT(ecam);
884 WINPR_ASSERT(ecam->hlistener);
885
886 IWTSVirtualChannelManager* pChannelMgr = ecam->hlistener->channel_mgr;
887 WINPR_ASSERT(pChannelMgr);
888
889 WLog_DBG(TAG, "entered for %s", deviceId);
890
891 CameraDevice* dev = (CameraDevice*)calloc(1, sizeof(CameraDevice));
892
893 if (!dev)
894 {
895 WLog_ERR(TAG, "calloc failed");
896 return nullptr;
897 }
898
899 dev->ecam = ecam;
900 dev->ihal = ecam->ihal;
901 strncpy(dev->deviceId, deviceId, sizeof(dev->deviceId) - 1);
902 dev->hlistener = (GENERIC_LISTENER_CALLBACK*)calloc(1, sizeof(GENERIC_LISTENER_CALLBACK));
903
904 if (!dev->hlistener)
905 {
906 free(dev);
907 WLog_ERR(TAG, "calloc failed");
908 return nullptr;
909 }
910
911 dev->hlistener->iface.OnNewChannelConnection = ecam_dev_on_new_channel_connection;
912 dev->hlistener->plugin = (IWTSPlugin*)dev;
913 dev->hlistener->channel_mgr = pChannelMgr;
914 if (CHANNEL_RC_OK != pChannelMgr->CreateListener(pChannelMgr, deviceId, 0,
915 &dev->hlistener->iface, &dev->listener))
916 {
917 free(dev->hlistener);
918 free(dev);
919 WLog_ERR(TAG, "CreateListener failed");
920 return nullptr;
921 }
922
923 return dev;
924}
925
932void ecam_dev_destroy(CameraDevice* dev)
933{
934 if (!dev)
935 return;
936
937 WLog_DBG(TAG, "entered for %s", dev->deviceId);
938
939 if (dev->hlistener)
940 {
941 IWTSVirtualChannelManager* mgr = dev->hlistener->channel_mgr;
942 if (mgr)
943 IFCALL(mgr->DestroyListener, mgr, dev->listener);
944 }
945
946 free(dev->hlistener);
947
948 for (size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
949 ecam_dev_stop_stream(dev, i);
950
951 free(dev);
952}