20#include <winpr/assert.h>
21#include <winpr/cast.h>
22#include <winpr/interlocked.h>
26#define TAG CHANNELS_TAG("rdpecam-device.client")
33#if defined(WITH_INPUT_FORMAT_H264)
34 { CAM_MEDIA_FORMAT_H264, CAM_MEDIA_FORMAT_H264 },
35 { CAM_MEDIA_FORMAT_MJPG_H264, CAM_MEDIA_FORMAT_H264 },
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 },
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 },
47static const size_t nSupportedFormats = ARRAYSIZE(supportedFormats);
51 WINPR_ASSERT(mediaType);
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));
65 WINPR_ASSERT(mediaType);
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);
80 WINPR_ASSERT(mediaType);
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);
91static UINT ecam_dev_send_sample_response(
CameraDevice* dev,
size_t streamIndex,
const BYTE* sample,
97 CAM_MSG_ID msg = CAM_MSG_ID_SampleResponse;
99 Stream_SetPosition(stream->sampleRespBuffer, 0);
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));
106 Stream_Write(stream->sampleRespBuffer, sample, size);
109 return ecam_channel_write(dev->ecam, stream->hSampleReqChannel, msg, stream->sampleRespBuffer,
113static BOOL mediaSupportDrops(CAM_MEDIA_FORMAT format)
117 case CAM_MEDIA_FORMAT_H264:
127 WINPR_ASSERT(stream);
129 if (stream->samplesRequested <= 0)
131 WLog_VRB(TAG,
"Frame delayed: No sample requested");
132 return CHANNEL_RC_OK;
135 if (!stream->haveSample)
137 WLog_VRB(TAG,
"Frame response delayed: No sample available");
138 return CHANNEL_RC_OK;
141 BYTE* encodedSample = Stream_Buffer(stream->pendingSample);
142 size_t encodedSize = Stream_Length(stream->pendingSample);
143 if (streamInputFormat(stream) != streamOutputFormat(stream))
145 if (!ecam_encoder_compress(stream, encodedSample, encodedSize, &encodedSample,
148 WLog_DBG(TAG,
"Frame dropped: error in ecam_encoder_compress");
149 stream->haveSample = FALSE;
150 return CHANNEL_RC_OK;
153 if (!stream->streaming)
155 WLog_DBG(TAG,
"Frame delayed/dropped: stream stopped");
156 return CHANNEL_RC_OK;
160 stream->samplesRequested--;
161 stream->haveSample = FALSE;
163 return ecam_dev_send_sample_response(dev, WINPR_ASSERTING_INT_CAST(
size_t, streamIndex),
164 encodedSample, encodedSize);
167static UINT ecam_dev_sample_captured_callback(
CameraDevice* dev,
int streamIndex,
168 const BYTE* sample,
size_t size)
172 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
173 return ERROR_INVALID_INDEX;
177 if (!stream->streaming)
179 WLog_DBG(TAG,
"Frame drop: stream not running");
180 return CHANNEL_RC_OK;
183 EnterCriticalSection(&stream->lock);
184 UINT ret = CHANNEL_RC_NO_MEMORY;
191 if (stream->haveSample && !mediaSupportDrops(stream->formats.inputFormat))
200 DWORD waitDelay = (1000 * stream->currMediaType.FrameRateDenominator) /
201 stream->currMediaType.FrameRateNumerator;
207 while (stream->haveSample && stream->streaming)
209 LeaveCriticalSection(&stream->lock);
211 SleepEx(waitDelay, TRUE);
213 EnterCriticalSection(&stream->lock);
216 if (!stream->streaming)
218 WLog_DBG(TAG,
"Frame drop: stream not running");
224 Stream_SetPosition(stream->pendingSample, 0);
225 if (!Stream_EnsureRemainingCapacity(stream->pendingSample, size))
228 Stream_Write(stream->pendingSample, sample, size);
229 Stream_SealLength(stream->pendingSample);
230 stream->haveSample = TRUE;
232 ret = ecam_dev_send_pending(dev, streamIndex, stream);
235 LeaveCriticalSection(&stream->lock);
239static void ecam_dev_stop_stream(
CameraDevice* dev,
size_t streamIndex)
243 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
248 if (stream->streaming)
250 stream->streaming = FALSE;
251 dev->ihal->StopStream(dev->ihal, dev->deviceId, 0);
253 DeleteCriticalSection(&stream->lock);
256 Stream_Free(stream->sampleRespBuffer, TRUE);
257 stream->sampleRespBuffer = NULL;
259 Stream_Free(stream->pendingSample, TRUE);
260 stream->pendingSample = NULL;
262 ecam_encoder_context_free(stream);
270static UINT ecam_dev_process_stop_streams_request(
CameraDevice* dev,
276 for (
size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
277 ecam_dev_stop_stream(dev, i);
279 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
287static UINT ecam_dev_process_start_streams_request(
CameraDevice* dev,
290 BYTE streamIndex = 0;
295 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1 + 26))
296 return ERROR_INVALID_DATA;
298 Stream_Read_UINT8(s, streamIndex);
300 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
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;
307 if (!ecam_dev_read_media_type(s, &mediaType))
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;
314 ecam_dev_print_media_type(&mediaType);
318 if (stream->streaming)
320 WLog_ERR(TAG,
"Streaming already in progress, device %s, streamIndex %d", dev->deviceId,
322 return CAM_ERROR_CODE_UnexpectedError;
328 stream->currMediaType = mediaType;
331 if (streamInputFormat(stream) != streamOutputFormat(stream) &&
332 !ecam_encoder_context_init(stream))
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;
339 stream->sampleRespBuffer = Stream_New(NULL, ECAM_SAMPLE_RESPONSE_BUFFER_SIZE);
340 if (!stream->sampleRespBuffer)
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;
349 mediaType.Format = streamInputFormat(stream);
351 stream->samplesRequested = 0;
352 stream->haveSample = FALSE;
354 if (!InitializeCriticalSectionEx(&stream->lock, 0, 0))
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;
362 stream->pendingSample = Stream_New(NULL, 4ull * mediaType.Width * mediaType.Height);
363 if (!stream->pendingSample)
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;
371 UINT error = dev->ihal->StartStream(dev->ihal, dev, streamIndex, &mediaType,
372 ecam_dev_sample_captured_callback);
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;
381 stream->streaming = TRUE;
382 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
390static UINT ecam_dev_process_property_list_request(
CameraDevice* dev,
397 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_PropertyListResponse);
405static UINT ecam_dev_send_current_media_type_response(
CameraDevice* dev,
409 CAM_MSG_ID msg = CAM_MSG_ID_CurrentMediaTypeResponse;
416 WLog_ERR(TAG,
"Stream_New failed");
417 return ERROR_NOT_ENOUGH_MEMORY;
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));
423 ecam_dev_write_media_type(s, mediaType);
425 return ecam_channel_write(dev->ecam, hchannel, msg, s, TRUE);
436 BYTE streamIndex = 0;
440 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
441 return ERROR_INVALID_DATA;
443 Stream_Read_UINT8(s, streamIndex);
445 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
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;
454 EnterCriticalSection(&stream->lock);
457 if (stream->hSampleReqChannel != hchannel)
458 stream->hSampleReqChannel = hchannel;
460 stream->samplesRequested++;
461 const UINT ret = ecam_dev_send_pending(dev, streamIndex, stream);
463 LeaveCriticalSection(&stream->lock);
472static UINT ecam_dev_process_current_media_type_request(
CameraDevice* dev,
476 BYTE streamIndex = 0;
480 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
481 return ERROR_INVALID_DATA;
483 Stream_Read_UINT8(s, streamIndex);
485 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
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;
494 if (stream->currMediaType.Format == 0)
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;
501 return ecam_dev_send_current_media_type_response(dev, hchannel, &stream->currMediaType);
509static UINT ecam_dev_send_media_type_list_response(
CameraDevice* dev,
514 CAM_MSG_ID msg = CAM_MSG_ID_MediaTypeListResponse;
518 wStream* s = Stream_New(NULL, CAM_HEADER_SIZE + ECAM_MAX_MEDIA_TYPE_DESCRIPTORS *
522 WLog_ERR(TAG,
"Stream_New failed");
523 return ERROR_NOT_ENOUGH_MEMORY;
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));
529 for (
size_t i = 0; i < nMediaTypes; i++, mediaTypes++)
531 ecam_dev_write_media_type(s, mediaTypes);
534 return ecam_channel_write(dev->ecam, hchannel, msg, s, TRUE);
542static UINT ecam_dev_process_media_type_list_request(
CameraDevice* dev,
545 UINT error = CHANNEL_RC_OK;
546 BYTE streamIndex = 0;
548 size_t nMediaTypes = ECAM_MAX_MEDIA_TYPE_DESCRIPTORS;
552 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
553 return ERROR_INVALID_DATA;
555 Stream_Read_UINT8(s, streamIndex);
557 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
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;
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;
575 dev->ihal->GetMediaTypeDescriptions(dev->ihal, dev->deviceId, streamIndex, supportedFormats,
576 nSupportedFormats, mediaTypes, &nMediaTypes);
577 if (formatIndex == -1 || nMediaTypes == 0)
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;
585 stream->formats = supportedFormats[formatIndex];
588 for (
size_t i = 0; i < nMediaTypes; i++)
590 mediaTypes[i].Format = streamOutputFormat(stream);
591 mediaTypes[i].Flags = CAM_MEDIA_TYPE_DESCRIPTION_FLAG_DecodingRequired;
594 if (stream->currMediaType.Format == 0)
597 stream->currMediaType = mediaTypes[0];
600 error = ecam_dev_send_media_type_list_response(dev, hchannel, mediaTypes, nMediaTypes);
612static UINT ecam_dev_send_stream_list_response(
CameraDevice* dev,
615 CAM_MSG_ID msg = CAM_MSG_ID_StreamListResponse;
622 WLog_ERR(TAG,
"Stream_New failed");
623 return ERROR_NOT_ENOUGH_MEMORY;
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));
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 );
633 Stream_Write_UINT8(s, FALSE );
635 return ecam_channel_write(dev->ecam, hchannel, msg, s, TRUE);
643static UINT ecam_dev_process_stream_list_request(
CameraDevice* dev,
647 return ecam_dev_send_stream_list_response(dev, hchannel);
655static UINT ecam_dev_process_activate_device_request(
CameraDevice* dev,
660 UINT32 errorCode = 0;
662 if (dev->ihal->Activate(dev->ihal, dev->deviceId, &errorCode))
663 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
665 return ecam_channel_send_error_response(dev->ecam, hchannel, errorCode);
673static UINT ecam_dev_process_deactivate_device_request(
CameraDevice* dev,
680 for (
size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
681 ecam_dev_stop_stream(dev, i);
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);
687 return ecam_channel_send_error_response(dev->ecam, hchannel, errorCode);
695static UINT ecam_dev_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
wStream* data)
697 UINT error = CHANNEL_RC_OK;
702 if (!hchannel || !data)
703 return ERROR_INVALID_PARAMETER;
708 return ERROR_INTERNAL_ERROR;
710 if (!Stream_CheckAndLogRequiredCapacity(TAG, data, CAM_HEADER_SIZE))
711 return ERROR_NO_DATA;
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);
720 case CAM_MSG_ID_ActivateDeviceRequest:
721 error = ecam_dev_process_activate_device_request(dev, hchannel, data);
724 case CAM_MSG_ID_DeactivateDeviceRequest:
725 error = ecam_dev_process_deactivate_device_request(dev, hchannel, data);
728 case CAM_MSG_ID_StreamListRequest:
729 error = ecam_dev_process_stream_list_request(dev, hchannel, data);
732 case CAM_MSG_ID_MediaTypeListRequest:
733 error = ecam_dev_process_media_type_list_request(dev, hchannel, data);
736 case CAM_MSG_ID_CurrentMediaTypeRequest:
737 error = ecam_dev_process_current_media_type_request(dev, hchannel, data);
740 case CAM_MSG_ID_PropertyListRequest:
741 error = ecam_dev_process_property_list_request(dev, hchannel, data);
744 case CAM_MSG_ID_StartStreamsRequest:
745 error = ecam_dev_process_start_streams_request(dev, hchannel, data);
748 case CAM_MSG_ID_StopStreamsRequest:
749 error = ecam_dev_process_stop_streams_request(dev, hchannel, data);
752 case CAM_MSG_ID_SampleRequest:
753 error = ecam_dev_process_sample_request(dev, hchannel, data);
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);
772static UINT ecam_dev_on_open(WINPR_ATTR_UNUSED IWTSVirtualChannelCallback* pChannelCallback)
774 WLog_DBG(TAG,
"entered");
775 return CHANNEL_RC_OK;
783static UINT ecam_dev_on_close(IWTSVirtualChannelCallback* pChannelCallback)
786 WINPR_ASSERT(hchannel);
791 WLog_DBG(TAG,
"entered");
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;
799 return CHANNEL_RC_OK;
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)
815 if (!hlistener || !hlistener->plugin)
816 return ERROR_INTERNAL_ERROR;
818 WLog_DBG(TAG,
"entered");
824 WLog_ERR(TAG,
"calloc failed");
825 return CHANNEL_RC_NO_MEMORY;
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;
844 WINPR_ATTR_UNUSED
const char* deviceName)
847 WINPR_ASSERT(ecam->hlistener);
849 IWTSVirtualChannelManager* pChannelMgr = ecam->hlistener->channel_mgr;
850 WINPR_ASSERT(pChannelMgr);
852 WLog_DBG(TAG,
"entered for %s", deviceId);
858 WLog_ERR(TAG,
"calloc failed");
863 dev->ihal = ecam->ihal;
864 strncpy(dev->deviceId, deviceId,
sizeof(dev->deviceId) - 1);
870 WLog_ERR(TAG,
"calloc failed");
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))
880 free(dev->hlistener);
882 WLog_ERR(TAG,
"CreateListener failed");
900 WLog_DBG(TAG,
"entered for %s", dev->deviceId);
904 IWTSVirtualChannelManager* mgr = dev->hlistener->channel_mgr;
906 IFCALL(mgr->DestroyListener, mgr, dev->listener);
909 free(dev->hlistener);
911 for (
size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
912 ecam_dev_stop_stream(dev, i);