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