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