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 },
35 #if defined(WITH_INPUT_FORMAT_MJPG)
36 { CAM_MEDIA_FORMAT_MJPG, CAM_MEDIA_FORMAT_H264 },
38 { CAM_MEDIA_FORMAT_I420, CAM_MEDIA_FORMAT_H264 },
39 { CAM_MEDIA_FORMAT_YUY2, CAM_MEDIA_FORMAT_H264 },
40 { CAM_MEDIA_FORMAT_NV12, CAM_MEDIA_FORMAT_H264 },
41 { CAM_MEDIA_FORMAT_RGB24, CAM_MEDIA_FORMAT_H264 },
42 { CAM_MEDIA_FORMAT_RGB32, CAM_MEDIA_FORMAT_H264 },
44 static const size_t nSupportedFormats = ARRAYSIZE(supportedFormats);
48 WINPR_ASSERT(mediaType);
50 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, mediaType->Format));
51 Stream_Write_UINT32(s, mediaType->Width);
52 Stream_Write_UINT32(s, mediaType->Height);
53 Stream_Write_UINT32(s, mediaType->FrameRateNumerator);
54 Stream_Write_UINT32(s, mediaType->FrameRateDenominator);
55 Stream_Write_UINT32(s, mediaType->PixelAspectRatioNumerator);
56 Stream_Write_UINT32(s, mediaType->PixelAspectRatioDenominator);
57 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, mediaType->Flags));
62 WINPR_ASSERT(mediaType);
64 Stream_Read_UINT8(s, mediaType->Format);
65 Stream_Read_UINT32(s, mediaType->Width);
66 Stream_Read_UINT32(s, mediaType->Height);
67 Stream_Read_UINT32(s, mediaType->FrameRateNumerator);
68 Stream_Read_UINT32(s, mediaType->FrameRateDenominator);
69 Stream_Read_UINT32(s, mediaType->PixelAspectRatioNumerator);
70 Stream_Read_UINT32(s, mediaType->PixelAspectRatioDenominator);
71 Stream_Read_UINT8(s, mediaType->Flags);
77 WINPR_ASSERT(mediaType);
79 WLog_DBG(TAG,
"Format: %d, width: %d, height: %d, fps: %d, flags: %d", mediaType->Format,
80 mediaType->Width, mediaType->Height, mediaType->FrameRateNumerator, mediaType->Flags);
88 static UINT ecam_dev_send_sample_response(
CameraDevice* dev,
size_t streamIndex,
const BYTE* sample,
94 CAM_MSG_ID msg = CAM_MSG_ID_SampleResponse;
96 Stream_SetPosition(stream->sampleRespBuffer, 0);
98 Stream_Write_UINT8(stream->sampleRespBuffer,
99 WINPR_ASSERTING_INT_CAST(uint8_t, dev->ecam->version));
100 Stream_Write_UINT8(stream->sampleRespBuffer, WINPR_ASSERTING_INT_CAST(uint8_t, msg));
101 Stream_Write_UINT8(stream->sampleRespBuffer, WINPR_ASSERTING_INT_CAST(uint8_t, streamIndex));
103 Stream_Write(stream->sampleRespBuffer, sample, size);
106 return ecam_channel_write(dev->ecam, stream->hSampleReqChannel, msg, stream->sampleRespBuffer,
115 static UINT ecam_dev_sample_captured_callback(
CameraDevice* dev,
int streamIndex,
116 const BYTE* sample,
size_t size)
118 BYTE* encodedSample = NULL;
119 size_t encodedSize = 0;
123 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
124 return ERROR_INVALID_INDEX;
128 if (!stream->streaming)
129 return CHANNEL_RC_OK;
131 if (streamInputFormat(stream) != streamOutputFormat(stream))
133 if (!ecam_encoder_compress(stream, sample, size, &encodedSample, &encodedSize))
135 WLog_DBG(TAG,
"Frame drop or error in ecam_encoder_compress");
136 return CHANNEL_RC_OK;
139 if (!stream->streaming)
140 return CHANNEL_RC_OK;
144 encodedSample = WINPR_CAST_CONST_PTR_AWAY(sample, BYTE*);
148 if (stream->nSampleCredits == 0)
150 WLog_DBG(TAG,
"Skip sample: no credits left");
151 return CHANNEL_RC_OK;
153 stream->nSampleCredits--;
155 return ecam_dev_send_sample_response(dev, WINPR_ASSERTING_INT_CAST(
size_t, streamIndex),
156 encodedSample, encodedSize);
159 static void ecam_dev_stop_stream(
CameraDevice* dev,
size_t streamIndex)
163 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
168 if (stream->streaming)
170 stream->streaming = FALSE;
171 dev->ihal->StopStream(dev->ihal, dev->deviceId, 0);
174 if (stream->sampleRespBuffer)
176 Stream_Free(stream->sampleRespBuffer, TRUE);
177 stream->sampleRespBuffer = NULL;
180 ecam_encoder_context_free(stream);
188 static UINT ecam_dev_process_stop_streams_request(
CameraDevice* dev,
194 for (
size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
195 ecam_dev_stop_stream(dev, i);
197 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
205 static UINT ecam_dev_process_start_streams_request(
CameraDevice* dev,
208 BYTE streamIndex = 0;
213 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1 + 26))
214 return ERROR_INVALID_DATA;
216 Stream_Read_UINT8(s, streamIndex);
218 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
220 WLog_ERR(TAG,
"Incorrect streamIndex %" PRIuz, streamIndex);
221 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_InvalidStreamNumber);
222 return ERROR_INVALID_INDEX;
225 if (!ecam_dev_read_media_type(s, &mediaType))
227 WLog_ERR(TAG,
"Unable to read MEDIA_TYPE_DESCRIPTION");
228 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_InvalidMessage);
229 return ERROR_INVALID_DATA;
232 ecam_dev_print_media_type(&mediaType);
236 if (stream->streaming)
238 WLog_ERR(TAG,
"Streaming already in progress, device %s, streamIndex %d", dev->deviceId,
240 return CAM_ERROR_CODE_UnexpectedError;
246 stream->currMediaType = mediaType;
249 if (streamInputFormat(stream) != streamOutputFormat(stream) &&
250 !ecam_encoder_context_init(stream))
252 WLog_ERR(TAG,
"stream_ecam_encoder_init failed");
253 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_UnexpectedError);
254 return ERROR_INVALID_DATA;
257 stream->sampleRespBuffer = Stream_New(NULL, ECAM_SAMPLE_RESPONSE_BUFFER_SIZE);
258 if (!stream->sampleRespBuffer)
260 WLog_ERR(TAG,
"Stream_New failed");
261 ecam_dev_stop_stream(dev, streamIndex);
262 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_OutOfMemory);
263 return ERROR_INVALID_DATA;
267 mediaType.Format = streamInputFormat(stream);
269 stream->nSampleCredits = 0;
271 UINT error = dev->ihal->StartStream(dev->ihal, dev, streamIndex, &mediaType,
272 ecam_dev_sample_captured_callback);
275 WLog_ERR(TAG,
"StartStream failure");
276 ecam_dev_stop_stream(dev, streamIndex);
277 ecam_channel_send_error_response(dev->ecam, hchannel, error);
278 return ERROR_INVALID_DATA;
281 stream->streaming = TRUE;
282 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
290 static UINT ecam_dev_process_property_list_request(
CameraDevice* dev,
296 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_PropertyListResponse);
304 static UINT ecam_dev_send_current_media_type_response(
CameraDevice* dev,
308 CAM_MSG_ID msg = CAM_MSG_ID_CurrentMediaTypeResponse;
315 WLog_ERR(TAG,
"Stream_New failed");
316 return ERROR_NOT_ENOUGH_MEMORY;
319 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, dev->ecam->version));
320 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, msg));
322 ecam_dev_write_media_type(s, mediaType);
324 return ecam_channel_write(dev->ecam, hchannel, msg, s, TRUE);
335 BYTE streamIndex = 0;
339 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
340 return ERROR_INVALID_DATA;
342 Stream_Read_UINT8(s, streamIndex);
344 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
346 WLog_ERR(TAG,
"Incorrect streamIndex %d", streamIndex);
347 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_InvalidStreamNumber);
348 return ERROR_INVALID_INDEX;
354 if (stream->hSampleReqChannel != hchannel)
355 stream->hSampleReqChannel = hchannel;
358 stream->nSampleCredits = ECAM_MAX_SAMPLE_CREDITS;
360 return CHANNEL_RC_OK;
368 static UINT ecam_dev_process_current_media_type_request(
CameraDevice* dev,
372 BYTE streamIndex = 0;
376 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
377 return ERROR_INVALID_DATA;
379 Stream_Read_UINT8(s, streamIndex);
381 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
383 WLog_ERR(TAG,
"Incorrect streamIndex %d", streamIndex);
384 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_InvalidStreamNumber);
385 return ERROR_INVALID_INDEX;
390 if (stream->currMediaType.Format == 0)
392 WLog_ERR(TAG,
"Current media type unknown for streamIndex %d", streamIndex);
393 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_NotInitialized);
394 return ERROR_DEVICE_REINITIALIZATION_NEEDED;
397 return ecam_dev_send_current_media_type_response(dev, hchannel, &stream->currMediaType);
405 static UINT ecam_dev_send_media_type_list_response(
CameraDevice* dev,
410 CAM_MSG_ID msg = CAM_MSG_ID_MediaTypeListResponse;
414 wStream* s = Stream_New(NULL, CAM_HEADER_SIZE + ECAM_MAX_MEDIA_TYPE_DESCRIPTORS *
418 WLog_ERR(TAG,
"Stream_New failed");
419 return ERROR_NOT_ENOUGH_MEMORY;
422 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, dev->ecam->version));
423 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, msg));
425 for (
size_t i = 0; i < nMediaTypes; i++, mediaTypes++)
427 ecam_dev_write_media_type(s, mediaTypes);
430 return ecam_channel_write(dev->ecam, hchannel, msg, s, TRUE);
438 static UINT ecam_dev_process_media_type_list_request(
CameraDevice* dev,
441 UINT error = CHANNEL_RC_OK;
442 BYTE streamIndex = 0;
444 size_t nMediaTypes = ECAM_MAX_MEDIA_TYPE_DESCRIPTORS;
448 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
449 return ERROR_INVALID_DATA;
451 Stream_Read_UINT8(s, streamIndex);
453 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
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;
465 WLog_ERR(TAG,
"calloc failed");
466 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_OutOfMemory);
467 return CHANNEL_RC_NO_MEMORY;
471 dev->ihal->GetMediaTypeDescriptions(dev->ihal, dev->deviceId, streamIndex, supportedFormats,
472 nSupportedFormats, mediaTypes, &nMediaTypes);
473 if (formatIndex == -1 || nMediaTypes == 0)
475 WLog_ERR(TAG,
"Camera doesn't support any compatible video formats");
476 ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_ItemNotFound);
477 error = ERROR_DEVICE_FEATURE_NOT_SUPPORTED;
481 stream->formats = supportedFormats[formatIndex];
484 for (
size_t i = 0; i < nMediaTypes; i++)
486 mediaTypes[i].Format = streamOutputFormat(stream);
487 mediaTypes[i].Flags = CAM_MEDIA_TYPE_DESCRIPTION_FLAG_DecodingRequired;
490 if (stream->currMediaType.Format == 0)
493 stream->currMediaType = mediaTypes[0];
496 error = ecam_dev_send_media_type_list_response(dev, hchannel, mediaTypes, nMediaTypes);
508 static UINT ecam_dev_send_stream_list_response(
CameraDevice* dev,
511 CAM_MSG_ID msg = CAM_MSG_ID_StreamListResponse;
518 WLog_ERR(TAG,
"Stream_New failed");
519 return ERROR_NOT_ENOUGH_MEMORY;
522 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, dev->ecam->version));
523 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(uint8_t, msg));
526 Stream_Write_UINT16(s, CAM_STREAM_FRAME_SOURCE_TYPE_Color);
527 Stream_Write_UINT8(s, CAM_STREAM_CATEGORY_Capture);
528 Stream_Write_UINT8(s, TRUE );
529 Stream_Write_UINT8(s, FALSE );
531 return ecam_channel_write(dev->ecam, hchannel, msg, s, TRUE);
539 static UINT ecam_dev_process_stream_list_request(
CameraDevice* dev,
542 return ecam_dev_send_stream_list_response(dev, hchannel);
550 static UINT ecam_dev_process_activate_device_request(
CameraDevice* dev,
556 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
564 static UINT ecam_dev_process_deactivate_device_request(
CameraDevice* dev,
571 for (
size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
572 ecam_dev_stop_stream(dev, i);
574 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
582 static UINT ecam_dev_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
wStream* data)
584 UINT error = CHANNEL_RC_OK;
589 if (!hchannel || !data)
590 return ERROR_INVALID_PARAMETER;
595 return ERROR_INTERNAL_ERROR;
597 if (!Stream_CheckAndLogRequiredCapacity(TAG, data, CAM_HEADER_SIZE))
598 return ERROR_NO_DATA;
600 Stream_Read_UINT8(data, version);
601 Stream_Read_UINT8(data, messageId);
602 WLog_DBG(TAG,
"ChannelId=%d, MessageId=0x%02" PRIx8
", Version=%d",
603 hchannel->channel_mgr->GetChannelId(hchannel->channel), messageId, version);
607 case CAM_MSG_ID_ActivateDeviceRequest:
608 error = ecam_dev_process_activate_device_request(dev, hchannel, data);
611 case CAM_MSG_ID_DeactivateDeviceRequest:
612 error = ecam_dev_process_deactivate_device_request(dev, hchannel, data);
615 case CAM_MSG_ID_StreamListRequest:
616 error = ecam_dev_process_stream_list_request(dev, hchannel, data);
619 case CAM_MSG_ID_MediaTypeListRequest:
620 error = ecam_dev_process_media_type_list_request(dev, hchannel, data);
623 case CAM_MSG_ID_CurrentMediaTypeRequest:
624 error = ecam_dev_process_current_media_type_request(dev, hchannel, data);
627 case CAM_MSG_ID_PropertyListRequest:
628 error = ecam_dev_process_property_list_request(dev, hchannel, data);
631 case CAM_MSG_ID_StartStreamsRequest:
632 error = ecam_dev_process_start_streams_request(dev, hchannel, data);
635 case CAM_MSG_ID_StopStreamsRequest:
636 error = ecam_dev_process_stop_streams_request(dev, hchannel, data);
639 case CAM_MSG_ID_SampleRequest:
640 error = ecam_dev_process_sample_request(dev, hchannel, data);
644 WLog_WARN(TAG,
"unknown MessageId=0x%02" PRIx8
"", messageId);
645 error = ERROR_INVALID_DATA;
646 ecam_channel_send_error_response(dev->ecam, hchannel,
647 CAM_ERROR_CODE_OperationNotSupported);
659 static UINT ecam_dev_on_open(IWTSVirtualChannelCallback* pChannelCallback)
662 WINPR_ASSERT(hchannel);
667 WLog_DBG(TAG,
"entered");
668 return CHANNEL_RC_OK;
676 static UINT ecam_dev_on_close(IWTSVirtualChannelCallback* pChannelCallback)
679 WINPR_ASSERT(hchannel);
684 WLog_DBG(TAG,
"entered");
687 for (
size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
688 if (dev->streams[i].hSampleReqChannel == hchannel)
689 dev->streams[i].hSampleReqChannel = NULL;
692 return CHANNEL_RC_OK;
700 static UINT ecam_dev_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
701 IWTSVirtualChannel* pChannel, BYTE* Data,
703 IWTSVirtualChannelCallback** ppCallback)
707 if (!hlistener || !hlistener->plugin)
708 return ERROR_INTERNAL_ERROR;
710 WLog_DBG(TAG,
"entered");
716 WLog_ERR(TAG,
"calloc failed");
717 return CHANNEL_RC_NO_MEMORY;
720 hchannel->iface.OnDataReceived = ecam_dev_on_data_received;
721 hchannel->iface.OnOpen = ecam_dev_on_open;
722 hchannel->iface.OnClose = ecam_dev_on_close;
723 hchannel->plugin = hlistener->plugin;
724 hchannel->channel_mgr = hlistener->channel_mgr;
725 hchannel->channel = pChannel;
726 *ppCallback = (IWTSVirtualChannelCallback*)hchannel;
727 return CHANNEL_RC_OK;
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);