20#include <winpr/assert.h>
21#include <winpr/cast.h>
25#define TAG CHANNELS_TAG("rdpecam-device.client")
32#if defined(WITH_INPUT_FORMAT_H264)
33 { CAM_MEDIA_FORMAT_H264, CAM_MEDIA_FORMAT_H264 },
34 { CAM_MEDIA_FORMAT_MJPG_H264, CAM_MEDIA_FORMAT_H264 },
36#if defined(WITH_INPUT_FORMAT_MJPG)
37 { CAM_MEDIA_FORMAT_MJPG, CAM_MEDIA_FORMAT_H264 },
39 { CAM_MEDIA_FORMAT_I420, CAM_MEDIA_FORMAT_H264 },
40 { CAM_MEDIA_FORMAT_YUY2, CAM_MEDIA_FORMAT_H264 },
41 { CAM_MEDIA_FORMAT_NV12, CAM_MEDIA_FORMAT_H264 },
42 { CAM_MEDIA_FORMAT_RGB24, CAM_MEDIA_FORMAT_H264 },
43 { CAM_MEDIA_FORMAT_RGB32, CAM_MEDIA_FORMAT_H264 },
45static const size_t nSupportedFormats = ARRAYSIZE(supportedFormats);
49 WINPR_ASSERT(mediaType);
51 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, mediaType->Format));
52 Stream_Write_UINT32(s, mediaType->Width);
53 Stream_Write_UINT32(s, mediaType->Height);
54 Stream_Write_UINT32(s, mediaType->FrameRateNumerator);
55 Stream_Write_UINT32(s, mediaType->FrameRateDenominator);
56 Stream_Write_UINT32(s, mediaType->PixelAspectRatioNumerator);
57 Stream_Write_UINT32(s, mediaType->PixelAspectRatioDenominator);
58 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, mediaType->Flags));
63 WINPR_ASSERT(mediaType);
65 Stream_Read_UINT8(s, mediaType->Format);
66 Stream_Read_UINT32(s, mediaType->Width);
67 Stream_Read_UINT32(s, mediaType->Height);
68 Stream_Read_UINT32(s, mediaType->FrameRateNumerator);
69 Stream_Read_UINT32(s, mediaType->FrameRateDenominator);
70 Stream_Read_UINT32(s, mediaType->PixelAspectRatioNumerator);
71 Stream_Read_UINT32(s, mediaType->PixelAspectRatioDenominator);
72 Stream_Read_UINT8(s, mediaType->Flags);
78 WINPR_ASSERT(mediaType);
80 WLog_DBG(TAG,
"Format: %d, width: %d, height: %d, fps: %d, flags: %d", mediaType->Format,
81 mediaType->Width, mediaType->Height, mediaType->FrameRateNumerator, mediaType->Flags);
89static UINT ecam_dev_send_sample_response(
CameraDevice* dev,
size_t streamIndex,
const BYTE* sample,
95 CAM_MSG_ID msg = CAM_MSG_ID_SampleResponse;
97 Stream_SetPosition(stream->sampleRespBuffer, 0);
99 Stream_Write_UINT8(stream->sampleRespBuffer,
100 WINPR_ASSERTING_INT_CAST(uint8_t, dev->ecam->version));
101 Stream_Write_UINT8(stream->sampleRespBuffer, WINPR_ASSERTING_INT_CAST(uint8_t, msg));
102 Stream_Write_UINT8(stream->sampleRespBuffer, WINPR_ASSERTING_INT_CAST(uint8_t, streamIndex));
104 Stream_Write(stream->sampleRespBuffer, sample, size);
107 return ecam_channel_write(dev->ecam, stream->hSampleReqChannel, msg, stream->sampleRespBuffer,
116static UINT ecam_dev_sample_captured_callback(
CameraDevice* dev,
int streamIndex,
117 const BYTE* sample,
size_t size)
119 BYTE* encodedSample = NULL;
120 size_t encodedSize = 0;
124 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
125 return ERROR_INVALID_INDEX;
129 if (!stream->streaming)
130 return CHANNEL_RC_OK;
132 if (streamInputFormat(stream) != streamOutputFormat(stream))
134 if (!ecam_encoder_compress(stream, sample, size, &encodedSample, &encodedSize))
136 WLog_DBG(TAG,
"Frame drop or error in ecam_encoder_compress");
137 return CHANNEL_RC_OK;
140 if (!stream->streaming)
141 return CHANNEL_RC_OK;
145 encodedSample = WINPR_CAST_CONST_PTR_AWAY(sample, BYTE*);
149 if (stream->nSampleCredits == 0)
151 WLog_DBG(TAG,
"Skip sample: no credits left");
152 return CHANNEL_RC_OK;
154 stream->nSampleCredits--;
156 return ecam_dev_send_sample_response(dev, WINPR_ASSERTING_INT_CAST(
size_t, streamIndex),
157 encodedSample, encodedSize);
160static void ecam_dev_stop_stream(
CameraDevice* dev,
size_t streamIndex)
164 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
169 if (stream->streaming)
171 stream->streaming = FALSE;
172 dev->ihal->StopStream(dev->ihal, dev->deviceId, 0);
175 if (stream->sampleRespBuffer)
177 Stream_Free(stream->sampleRespBuffer, TRUE);
178 stream->sampleRespBuffer = NULL;
181 ecam_encoder_context_free(stream);
189static UINT ecam_dev_process_stop_streams_request(
CameraDevice* dev,
195 for (
size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
196 ecam_dev_stop_stream(dev, i);
198 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
206static UINT ecam_dev_process_start_streams_request(
CameraDevice* dev,
209 BYTE streamIndex = 0;
214 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1 + 26))
215 return ERROR_INVALID_DATA;
217 Stream_Read_UINT8(s, streamIndex);
219 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
221 WLog_ERR(TAG,
"Incorrect streamIndex %" PRIuz, streamIndex);
222 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_InvalidStreamNumber);
223 return ERROR_INVALID_INDEX;
226 if (!ecam_dev_read_media_type(s, &mediaType))
228 WLog_ERR(TAG,
"Unable to read MEDIA_TYPE_DESCRIPTION");
229 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_InvalidMessage);
230 return ERROR_INVALID_DATA;
233 ecam_dev_print_media_type(&mediaType);
237 if (stream->streaming)
239 WLog_ERR(TAG,
"Streaming already in progress, device %s, streamIndex %d", dev->deviceId,
241 return CAM_ERROR_CODE_UnexpectedError;
247 stream->currMediaType = mediaType;
250 if (streamInputFormat(stream) != streamOutputFormat(stream) &&
251 !ecam_encoder_context_init(stream))
253 WLog_ERR(TAG,
"stream_ecam_encoder_init failed");
254 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_UnexpectedError);
255 return ERROR_INVALID_DATA;
258 stream->sampleRespBuffer = Stream_New(NULL, ECAM_SAMPLE_RESPONSE_BUFFER_SIZE);
259 if (!stream->sampleRespBuffer)
261 WLog_ERR(TAG,
"Stream_New failed");
262 ecam_dev_stop_stream(dev, streamIndex);
263 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_OutOfMemory);
264 return ERROR_INVALID_DATA;
268 mediaType.Format = streamInputFormat(stream);
270 stream->nSampleCredits = 0;
272 UINT error = dev->ihal->StartStream(dev->ihal, dev, streamIndex, &mediaType,
273 ecam_dev_sample_captured_callback);
276 WLog_ERR(TAG,
"StartStream failure");
277 ecam_dev_stop_stream(dev, streamIndex);
278 ecam_channel_send_error_response(dev->ecam, hchannel, error);
279 return ERROR_INVALID_DATA;
282 stream->streaming = TRUE;
283 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
291static UINT ecam_dev_process_property_list_request(
CameraDevice* dev,
298 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_PropertyListResponse);
306static UINT ecam_dev_send_current_media_type_response(
CameraDevice* dev,
310 CAM_MSG_ID msg = CAM_MSG_ID_CurrentMediaTypeResponse;
317 WLog_ERR(TAG,
"Stream_New failed");
318 return ERROR_NOT_ENOUGH_MEMORY;
321 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, dev->ecam->version));
322 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, msg));
324 ecam_dev_write_media_type(s, mediaType);
326 return ecam_channel_write(dev->ecam, hchannel, msg, s, TRUE);
337 BYTE streamIndex = 0;
341 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
342 return ERROR_INVALID_DATA;
344 Stream_Read_UINT8(s, streamIndex);
346 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
348 WLog_ERR(TAG,
"Incorrect streamIndex %d", streamIndex);
349 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_InvalidStreamNumber);
350 return ERROR_INVALID_INDEX;
356 if (stream->hSampleReqChannel != hchannel)
357 stream->hSampleReqChannel = hchannel;
360 stream->nSampleCredits = ECAM_MAX_SAMPLE_CREDITS;
362 return CHANNEL_RC_OK;
370static UINT ecam_dev_process_current_media_type_request(
CameraDevice* dev,
374 BYTE streamIndex = 0;
378 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
379 return ERROR_INVALID_DATA;
381 Stream_Read_UINT8(s, streamIndex);
383 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
385 WLog_ERR(TAG,
"Incorrect streamIndex %d", streamIndex);
386 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_InvalidStreamNumber);
387 return ERROR_INVALID_INDEX;
392 if (stream->currMediaType.Format == 0)
394 WLog_ERR(TAG,
"Current media type unknown for streamIndex %d", streamIndex);
395 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_NotInitialized);
396 return ERROR_DEVICE_REINITIALIZATION_NEEDED;
399 return ecam_dev_send_current_media_type_response(dev, hchannel, &stream->currMediaType);
407static UINT ecam_dev_send_media_type_list_response(
CameraDevice* dev,
412 CAM_MSG_ID msg = CAM_MSG_ID_MediaTypeListResponse;
416 wStream* s = Stream_New(NULL, CAM_HEADER_SIZE + ECAM_MAX_MEDIA_TYPE_DESCRIPTORS *
420 WLog_ERR(TAG,
"Stream_New failed");
421 return ERROR_NOT_ENOUGH_MEMORY;
424 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, dev->ecam->version));
425 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, msg));
427 for (
size_t i = 0; i < nMediaTypes; i++, mediaTypes++)
429 ecam_dev_write_media_type(s, mediaTypes);
432 return ecam_channel_write(dev->ecam, hchannel, msg, s, TRUE);
440static UINT ecam_dev_process_media_type_list_request(
CameraDevice* dev,
443 UINT error = CHANNEL_RC_OK;
444 BYTE streamIndex = 0;
446 size_t nMediaTypes = ECAM_MAX_MEDIA_TYPE_DESCRIPTORS;
450 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
451 return ERROR_INVALID_DATA;
453 Stream_Read_UINT8(s, streamIndex);
455 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
457 WLog_ERR(TAG,
"Incorrect streamIndex %d", streamIndex);
458 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_InvalidStreamNumber);
459 return ERROR_INVALID_INDEX;
467 WLog_ERR(TAG,
"calloc failed");
468 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_OutOfMemory);
469 return CHANNEL_RC_NO_MEMORY;
473 dev->ihal->GetMediaTypeDescriptions(dev->ihal, dev->deviceId, streamIndex, supportedFormats,
474 nSupportedFormats, mediaTypes, &nMediaTypes);
475 if (formatIndex == -1 || nMediaTypes == 0)
477 WLog_ERR(TAG,
"Camera doesn't support any compatible video formats");
478 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_ItemNotFound);
479 error = ERROR_DEVICE_FEATURE_NOT_SUPPORTED;
483 stream->formats = supportedFormats[formatIndex];
486 for (
size_t i = 0; i < nMediaTypes; i++)
488 mediaTypes[i].Format = streamOutputFormat(stream);
489 mediaTypes[i].Flags = CAM_MEDIA_TYPE_DESCRIPTION_FLAG_DecodingRequired;
492 if (stream->currMediaType.Format == 0)
495 stream->currMediaType = mediaTypes[0];
498 error = ecam_dev_send_media_type_list_response(dev, hchannel, mediaTypes, nMediaTypes);
510static UINT ecam_dev_send_stream_list_response(
CameraDevice* dev,
513 CAM_MSG_ID msg = CAM_MSG_ID_StreamListResponse;
520 WLog_ERR(TAG,
"Stream_New failed");
521 return ERROR_NOT_ENOUGH_MEMORY;
524 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, dev->ecam->version));
525 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, msg));
528 Stream_Write_UINT16(s, CAM_STREAM_FRAME_SOURCE_TYPE_Color);
529 Stream_Write_UINT8(s, CAM_STREAM_CATEGORY_Capture);
530 Stream_Write_UINT8(s, TRUE );
531 Stream_Write_UINT8(s, FALSE );
533 return ecam_channel_write(dev->ecam, hchannel, msg, s, TRUE);
541static UINT ecam_dev_process_stream_list_request(
CameraDevice* dev,
545 return ecam_dev_send_stream_list_response(dev, hchannel);
553static UINT ecam_dev_process_activate_device_request(
CameraDevice* dev,
560 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
568static UINT ecam_dev_process_deactivate_device_request(
CameraDevice* dev,
575 for (
size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
576 ecam_dev_stop_stream(dev, i);
578 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
586static UINT ecam_dev_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
wStream* data)
588 UINT error = CHANNEL_RC_OK;
593 if (!hchannel || !data)
594 return ERROR_INVALID_PARAMETER;
599 return ERROR_INTERNAL_ERROR;
601 if (!Stream_CheckAndLogRequiredCapacity(TAG, data, CAM_HEADER_SIZE))
602 return ERROR_NO_DATA;
604 Stream_Read_UINT8(data, version);
605 Stream_Read_UINT8(data, messageId);
606 WLog_DBG(TAG,
"ChannelId=%d, MessageId=0x%02" PRIx8
", Version=%d",
607 hchannel->channel_mgr->GetChannelId(hchannel->channel), messageId, version);
611 case CAM_MSG_ID_ActivateDeviceRequest:
612 error = ecam_dev_process_activate_device_request(dev, hchannel, data);
615 case CAM_MSG_ID_DeactivateDeviceRequest:
616 error = ecam_dev_process_deactivate_device_request(dev, hchannel, data);
619 case CAM_MSG_ID_StreamListRequest:
620 error = ecam_dev_process_stream_list_request(dev, hchannel, data);
623 case CAM_MSG_ID_MediaTypeListRequest:
624 error = ecam_dev_process_media_type_list_request(dev, hchannel, data);
627 case CAM_MSG_ID_CurrentMediaTypeRequest:
628 error = ecam_dev_process_current_media_type_request(dev, hchannel, data);
631 case CAM_MSG_ID_PropertyListRequest:
632 error = ecam_dev_process_property_list_request(dev, hchannel, data);
635 case CAM_MSG_ID_StartStreamsRequest:
636 error = ecam_dev_process_start_streams_request(dev, hchannel, data);
639 case CAM_MSG_ID_StopStreamsRequest:
640 error = ecam_dev_process_stop_streams_request(dev, hchannel, data);
643 case CAM_MSG_ID_SampleRequest:
644 error = ecam_dev_process_sample_request(dev, hchannel, data);
648 WLog_WARN(TAG,
"unknown MessageId=0x%02" PRIx8
"", messageId);
649 error = ERROR_INVALID_DATA;
650 ecam_channel_send_error_response(dev->ecam, hchannel,
651 CAM_ERROR_CODE_OperationNotSupported);
663static UINT ecam_dev_on_open(WINPR_ATTR_UNUSED IWTSVirtualChannelCallback* pChannelCallback)
665 WLog_DBG(TAG,
"entered");
666 return CHANNEL_RC_OK;
674static UINT ecam_dev_on_close(IWTSVirtualChannelCallback* pChannelCallback)
677 WINPR_ASSERT(hchannel);
682 WLog_DBG(TAG,
"entered");
685 for (
size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
686 if (dev->streams[i].hSampleReqChannel == hchannel)
687 dev->streams[i].hSampleReqChannel = NULL;
690 return CHANNEL_RC_OK;
698static UINT ecam_dev_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
699 IWTSVirtualChannel* pChannel,
700 WINPR_ATTR_UNUSED BYTE* Data,
701 WINPR_ATTR_UNUSED BOOL* pbAccept,
702 IWTSVirtualChannelCallback** ppCallback)
706 if (!hlistener || !hlistener->plugin)
707 return ERROR_INTERNAL_ERROR;
709 WLog_DBG(TAG,
"entered");
715 WLog_ERR(TAG,
"calloc failed");
716 return CHANNEL_RC_NO_MEMORY;
719 hchannel->iface.OnDataReceived = ecam_dev_on_data_received;
720 hchannel->iface.OnOpen = ecam_dev_on_open;
721 hchannel->iface.OnClose = ecam_dev_on_close;
722 hchannel->plugin = hlistener->plugin;
723 hchannel->channel_mgr = hlistener->channel_mgr;
724 hchannel->channel = pChannel;
725 *ppCallback = (IWTSVirtualChannelCallback*)hchannel;
726 return CHANNEL_RC_OK;
735 WINPR_ATTR_UNUSED
const char* deviceName)
738 WINPR_ASSERT(ecam->hlistener);
740 IWTSVirtualChannelManager* pChannelMgr = ecam->hlistener->channel_mgr;
741 WINPR_ASSERT(pChannelMgr);
743 WLog_DBG(TAG,
"entered for %s", deviceId);
749 WLog_ERR(TAG,
"calloc failed");
754 dev->ihal = ecam->ihal;
755 strncpy(dev->deviceId, deviceId,
sizeof(dev->deviceId) - 1);
761 WLog_ERR(TAG,
"calloc failed");
765 dev->hlistener->iface.OnNewChannelConnection = ecam_dev_on_new_channel_connection;
766 dev->hlistener->plugin = (IWTSPlugin*)dev;
767 dev->hlistener->channel_mgr = pChannelMgr;
768 if (CHANNEL_RC_OK != pChannelMgr->CreateListener(pChannelMgr, deviceId, 0,
769 &dev->hlistener->iface, &dev->listener))
771 free(dev->hlistener);
773 WLog_ERR(TAG,
"CreateListener failed");
791 WLog_DBG(TAG,
"entered for %s", dev->deviceId);
795 IWTSVirtualChannelManager* mgr = dev->hlistener->channel_mgr;
797 IFCALL(mgr->DestroyListener, mgr, dev->listener);
800 free(dev->hlistener);
802 for (
size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
803 ecam_dev_stop_stream(dev, i);