20#include <winpr/assert.h>
21#include <winpr/cast.h>
22#include <winpr/interlocked.h>
25#include "rdpecam-utils.h"
27#define TAG CHANNELS_TAG("rdpecam-device.client")
34#if defined(WITH_INPUT_FORMAT_H264)
35 { CAM_MEDIA_FORMAT_H264, CAM_MEDIA_FORMAT_H264 },
36 { CAM_MEDIA_FORMAT_MJPG_H264, CAM_MEDIA_FORMAT_H264 },
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 },
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 },
48static const size_t nSupportedFormats = ARRAYSIZE(supportedFormats);
52 WINPR_ASSERT(mediaType);
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));
66 WINPR_ASSERT(mediaType);
68 const uint8_t format = Stream_Get_UINT8(s);
69 if (!rdpecam_valid_CamMediaFormat(format))
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);
80 const uint8_t flags = Stream_Get_UINT8(s);
81 if (!rdpecam_valid_MediaTypeDescriptionFlags(flags))
83 mediaType->Flags = WINPR_ASSERTING_INT_CAST(CAM_MEDIA_TYPE_DESCRIPTION_FLAGS, flags);
89 WINPR_ASSERT(mediaType);
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);
100static UINT ecam_dev_send_sample_response(
CameraDevice* dev,
size_t streamIndex,
const BYTE* sample,
106 CAM_MSG_ID msg = CAM_MSG_ID_SampleResponse;
108 Stream_SetPosition(stream->sampleRespBuffer, 0);
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));
115 Stream_Write(stream->sampleRespBuffer, sample, size);
118 return ecam_channel_write(dev->ecam, stream->hSampleReqChannel, msg, stream->sampleRespBuffer,
122static BOOL mediaSupportDrops(CAM_MEDIA_FORMAT format)
126 case CAM_MEDIA_FORMAT_H264:
136 WINPR_ASSERT(stream);
138 if (stream->samplesRequested <= 0)
140 WLog_VRB(TAG,
"Frame delayed: No sample requested");
141 return CHANNEL_RC_OK;
144 if (!stream->haveSample)
146 WLog_VRB(TAG,
"Frame response delayed: No sample available");
147 return CHANNEL_RC_OK;
150 BYTE* encodedSample = Stream_Buffer(stream->pendingSample);
151 size_t encodedSize = Stream_Length(stream->pendingSample);
152 if (streamInputFormat(stream) != streamOutputFormat(stream))
154 if (!ecam_encoder_compress(stream, encodedSample, encodedSize, &encodedSample,
157 WLog_DBG(TAG,
"Frame dropped: error in ecam_encoder_compress");
158 stream->haveSample = FALSE;
159 return CHANNEL_RC_OK;
162 if (!stream->streaming)
164 WLog_DBG(TAG,
"Frame delayed/dropped: stream stopped");
165 return CHANNEL_RC_OK;
169 stream->samplesRequested--;
170 stream->haveSample = FALSE;
172 return ecam_dev_send_sample_response(dev, streamIndex, encodedSample, encodedSize);
175static UINT ecam_dev_sample_captured_callback(
CameraDevice* dev,
size_t streamIndex,
176 const BYTE* sample,
size_t size)
180 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
181 return ERROR_INVALID_INDEX;
185 if (!stream->streaming)
187 WLog_DBG(TAG,
"Frame drop: stream not running");
188 return CHANNEL_RC_OK;
191 EnterCriticalSection(&stream->lock);
192 UINT ret = CHANNEL_RC_NO_MEMORY;
199 if (stream->haveSample && !mediaSupportDrops(stream->formats.inputFormat))
208 DWORD waitDelay = (1000 * stream->currMediaType.FrameRateDenominator) /
209 stream->currMediaType.FrameRateNumerator;
215 while (stream->haveSample && stream->streaming)
217 LeaveCriticalSection(&stream->lock);
219 SleepEx(waitDelay, TRUE);
221 EnterCriticalSection(&stream->lock);
224 if (!stream->streaming)
226 WLog_DBG(TAG,
"Frame drop: stream not running");
232 Stream_SetPosition(stream->pendingSample, 0);
233 if (!Stream_EnsureRemainingCapacity(stream->pendingSample, size))
236 Stream_Write(stream->pendingSample, sample, size);
237 Stream_SealLength(stream->pendingSample);
238 stream->haveSample = TRUE;
240 ret = ecam_dev_send_pending(dev, streamIndex, stream);
243 LeaveCriticalSection(&stream->lock);
247static void ecam_dev_stop_stream(
CameraDevice* dev,
size_t streamIndex)
251 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
256 if (stream->streaming)
258 stream->streaming = FALSE;
259 dev->ihal->StopStream(dev->ihal, dev->deviceId, 0);
261 DeleteCriticalSection(&stream->lock);
264 Stream_Free(stream->sampleRespBuffer, TRUE);
265 stream->sampleRespBuffer = NULL;
267 Stream_Free(stream->pendingSample, TRUE);
268 stream->pendingSample = NULL;
270 ecam_encoder_context_free(stream);
278static UINT ecam_dev_process_stop_streams_request(
CameraDevice* dev,
284 for (
size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
285 ecam_dev_stop_stream(dev, i);
287 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
295static UINT ecam_dev_process_start_streams_request(
CameraDevice* dev,
298 BYTE streamIndex = 0;
303 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1 + 26))
304 return ERROR_INVALID_DATA;
306 Stream_Read_UINT8(s, streamIndex);
308 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
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;
315 if (!ecam_dev_read_media_type(s, &mediaType))
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;
322 ecam_dev_print_media_type(&mediaType);
326 if (stream->streaming)
328 WLog_ERR(TAG,
"Streaming already in progress, device %s, streamIndex %d", dev->deviceId,
330 return CAM_ERROR_CODE_UnexpectedError;
336 stream->currMediaType = mediaType;
339 if (streamInputFormat(stream) != streamOutputFormat(stream) &&
340 !ecam_encoder_context_init(stream))
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;
347 stream->sampleRespBuffer = Stream_New(NULL, ECAM_SAMPLE_RESPONSE_BUFFER_SIZE);
348 if (!stream->sampleRespBuffer)
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;
357 mediaType.Format = streamInputFormat(stream);
359 stream->samplesRequested = 0;
360 stream->haveSample = FALSE;
362 if (!InitializeCriticalSectionEx(&stream->lock, 0, 0))
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;
370 stream->pendingSample = Stream_New(NULL, 4ull * mediaType.Width * mediaType.Height);
371 if (!stream->pendingSample)
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;
379 const CAM_ERROR_CODE error = dev->ihal->StartStream(dev->ihal, dev, streamIndex, &mediaType,
380 ecam_dev_sample_captured_callback);
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;
389 stream->streaming = TRUE;
390 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
398static UINT ecam_dev_process_property_list_request(
CameraDevice* dev,
405 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_PropertyListResponse);
413static UINT ecam_dev_send_current_media_type_response(
CameraDevice* dev,
417 CAM_MSG_ID msg = CAM_MSG_ID_CurrentMediaTypeResponse;
424 WLog_ERR(TAG,
"Stream_New failed");
425 return ERROR_NOT_ENOUGH_MEMORY;
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));
431 ecam_dev_write_media_type(s, mediaType);
433 return ecam_channel_write(dev->ecam, hchannel, msg, s, TRUE);
444 BYTE streamIndex = 0;
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;
462 EnterCriticalSection(&stream->lock);
465 if (stream->hSampleReqChannel != hchannel)
466 stream->hSampleReqChannel = hchannel;
468 stream->samplesRequested++;
469 const UINT ret = ecam_dev_send_pending(dev, streamIndex, stream);
471 LeaveCriticalSection(&stream->lock);
480static UINT ecam_dev_process_current_media_type_request(
CameraDevice* dev,
484 BYTE streamIndex = 0;
488 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
489 return ERROR_INVALID_DATA;
491 Stream_Read_UINT8(s, streamIndex);
493 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
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;
502 if (stream->currMediaType.Format == 0)
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;
509 return ecam_dev_send_current_media_type_response(dev, hchannel, &stream->currMediaType);
517static UINT ecam_dev_send_media_type_list_response(
CameraDevice* dev,
522 CAM_MSG_ID msg = CAM_MSG_ID_MediaTypeListResponse;
526 wStream* s = Stream_New(NULL, CAM_HEADER_SIZE + ECAM_MAX_MEDIA_TYPE_DESCRIPTORS *
530 WLog_ERR(TAG,
"Stream_New failed");
531 return ERROR_NOT_ENOUGH_MEMORY;
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));
537 for (
size_t i = 0; i < nMediaTypes; i++, mediaTypes++)
539 ecam_dev_write_media_type(s, mediaTypes);
542 return ecam_channel_write(dev->ecam, hchannel, msg, s, TRUE);
550static UINT ecam_dev_process_media_type_list_request(
CameraDevice* dev,
553 UINT error = CHANNEL_RC_OK;
554 BYTE streamIndex = 0;
556 size_t nMediaTypes = ECAM_MAX_MEDIA_TYPE_DESCRIPTORS;
560 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
561 return ERROR_INVALID_DATA;
563 Stream_Read_UINT8(s, streamIndex);
565 if (streamIndex >= ECAM_DEVICE_MAX_STREAMS)
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;
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;
583 dev->ihal->GetMediaTypeDescriptions(dev->ihal, dev->deviceId, streamIndex, supportedFormats,
584 nSupportedFormats, mediaTypes, &nMediaTypes);
585 if (formatIndex == -1 || nMediaTypes == 0)
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;
593 stream->formats = supportedFormats[formatIndex];
596 for (
size_t i = 0; i < nMediaTypes; i++)
598 mediaTypes[i].Format = streamOutputFormat(stream);
599 mediaTypes[i].Flags = CAM_MEDIA_TYPE_DESCRIPTION_FLAG_DecodingRequired;
602 if (stream->currMediaType.Format == 0)
605 stream->currMediaType = mediaTypes[0];
608 error = ecam_dev_send_media_type_list_response(dev, hchannel, mediaTypes, nMediaTypes);
620static UINT ecam_dev_send_stream_list_response(
CameraDevice* dev,
623 CAM_MSG_ID msg = CAM_MSG_ID_StreamListResponse;
630 WLog_ERR(TAG,
"Stream_New failed");
631 return ERROR_NOT_ENOUGH_MEMORY;
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));
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 );
641 Stream_Write_UINT8(s, FALSE );
643 return ecam_channel_write(dev->ecam, hchannel, msg, s, TRUE);
651static UINT ecam_dev_process_stream_list_request(
CameraDevice* dev,
655 return ecam_dev_send_stream_list_response(dev, hchannel);
663static UINT ecam_dev_process_activate_device_request(
CameraDevice* dev,
668 CAM_ERROR_CODE errorCode = CAM_ERROR_CODE_None;
670 if (dev->ihal->Activate(dev->ihal, dev->deviceId, &errorCode))
671 return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
673 return ecam_channel_send_error_response(dev->ecam, hchannel, errorCode);
681static UINT ecam_dev_process_deactivate_device_request(
CameraDevice* dev,
688 for (
size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
689 ecam_dev_stop_stream(dev, i);
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);
695 return ecam_channel_send_error_response(dev->ecam, hchannel, errorCode);
703static UINT ecam_dev_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
wStream* data)
705 UINT error = CHANNEL_RC_OK;
710 if (!hchannel || !data)
711 return ERROR_INVALID_PARAMETER;
716 return ERROR_INTERNAL_ERROR;
718 if (!Stream_CheckAndLogRequiredCapacity(TAG, data, CAM_HEADER_SIZE))
719 return ERROR_NO_DATA;
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);
728 case CAM_MSG_ID_ActivateDeviceRequest:
729 error = ecam_dev_process_activate_device_request(dev, hchannel, data);
732 case CAM_MSG_ID_DeactivateDeviceRequest:
733 error = ecam_dev_process_deactivate_device_request(dev, hchannel, data);
736 case CAM_MSG_ID_StreamListRequest:
737 error = ecam_dev_process_stream_list_request(dev, hchannel, data);
740 case CAM_MSG_ID_MediaTypeListRequest:
741 error = ecam_dev_process_media_type_list_request(dev, hchannel, data);
744 case CAM_MSG_ID_CurrentMediaTypeRequest:
745 error = ecam_dev_process_current_media_type_request(dev, hchannel, data);
748 case CAM_MSG_ID_PropertyListRequest:
749 error = ecam_dev_process_property_list_request(dev, hchannel, data);
752 case CAM_MSG_ID_StartStreamsRequest:
753 error = ecam_dev_process_start_streams_request(dev, hchannel, data);
756 case CAM_MSG_ID_StopStreamsRequest:
757 error = ecam_dev_process_stop_streams_request(dev, hchannel, data);
760 case CAM_MSG_ID_SampleRequest:
761 error = ecam_dev_process_sample_request(dev, hchannel, data);
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);
780static UINT ecam_dev_on_open(WINPR_ATTR_UNUSED IWTSVirtualChannelCallback* pChannelCallback)
782 WLog_DBG(TAG,
"entered");
783 return CHANNEL_RC_OK;
791static UINT ecam_dev_on_close(IWTSVirtualChannelCallback* pChannelCallback)
794 WINPR_ASSERT(hchannel);
799 WLog_DBG(TAG,
"entered");
801 for (
size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
802 ecam_dev_stop_stream(dev, i);
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;
810 return CHANNEL_RC_OK;
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)
826 if (!hlistener || !hlistener->plugin)
827 return ERROR_INTERNAL_ERROR;
829 WLog_DBG(TAG,
"entered");
835 WLog_ERR(TAG,
"calloc failed");
836 return CHANNEL_RC_NO_MEMORY;
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;
855 WINPR_ATTR_UNUSED
const char* deviceName)
858 WINPR_ASSERT(ecam->hlistener);
860 IWTSVirtualChannelManager* pChannelMgr = ecam->hlistener->channel_mgr;
861 WINPR_ASSERT(pChannelMgr);
863 WLog_DBG(TAG,
"entered for %s", deviceId);
869 WLog_ERR(TAG,
"calloc failed");
874 dev->ihal = ecam->ihal;
875 strncpy(dev->deviceId, deviceId,
sizeof(dev->deviceId) - 1);
881 WLog_ERR(TAG,
"calloc failed");
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))
891 free(dev->hlistener);
893 WLog_ERR(TAG,
"CreateListener failed");
911 WLog_DBG(TAG,
"entered for %s", dev->deviceId);
915 IWTSVirtualChannelManager* mgr = dev->hlistener->channel_mgr;
917 IFCALL(mgr->DestroyListener, mgr, dev->listener);
920 free(dev->hlistener);
922 for (
size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
923 ecam_dev_stop_stream(dev, i);