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,
 
  558  UINT32 errorCode = 0;
 
  560  if (dev->ihal->Activate(dev->ihal, dev->deviceId, &errorCode))
 
  561    return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
 
  563  return ecam_channel_send_error_response(dev->ecam, hchannel, errorCode);
 
  571static UINT ecam_dev_process_deactivate_device_request(
CameraDevice* dev,
 
  578  for (
size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
 
  579    ecam_dev_stop_stream(dev, i);
 
  581  UINT32 errorCode = 0;
 
  582  if (dev->ihal->Deactivate(dev->ihal, dev->deviceId, &errorCode))
 
  583    return ecam_channel_send_generic_msg(dev->ecam, hchannel, CAM_MSG_ID_SuccessResponse);
 
  585  return ecam_channel_send_error_response(dev->ecam, hchannel, errorCode);
 
  593static UINT ecam_dev_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, 
wStream* data)
 
  595  UINT error = CHANNEL_RC_OK;
 
  600  if (!hchannel || !data)
 
  601    return ERROR_INVALID_PARAMETER;
 
  606    return ERROR_INTERNAL_ERROR;
 
  608  if (!Stream_CheckAndLogRequiredCapacity(TAG, data, CAM_HEADER_SIZE))
 
  609    return ERROR_NO_DATA;
 
  611  Stream_Read_UINT8(data, version);
 
  612  Stream_Read_UINT8(data, messageId);
 
  613  WLog_DBG(TAG, 
"ChannelId=%d, MessageId=0x%02" PRIx8 
", Version=%d",
 
  614           hchannel->channel_mgr->GetChannelId(hchannel->channel), messageId, version);
 
  618    case CAM_MSG_ID_ActivateDeviceRequest:
 
  619      error = ecam_dev_process_activate_device_request(dev, hchannel, data);
 
  622    case CAM_MSG_ID_DeactivateDeviceRequest:
 
  623      error = ecam_dev_process_deactivate_device_request(dev, hchannel, data);
 
  626    case CAM_MSG_ID_StreamListRequest:
 
  627      error = ecam_dev_process_stream_list_request(dev, hchannel, data);
 
  630    case CAM_MSG_ID_MediaTypeListRequest:
 
  631      error = ecam_dev_process_media_type_list_request(dev, hchannel, data);
 
  634    case CAM_MSG_ID_CurrentMediaTypeRequest:
 
  635      error = ecam_dev_process_current_media_type_request(dev, hchannel, data);
 
  638    case CAM_MSG_ID_PropertyListRequest:
 
  639      error = ecam_dev_process_property_list_request(dev, hchannel, data);
 
  642    case CAM_MSG_ID_StartStreamsRequest:
 
  643      error = ecam_dev_process_start_streams_request(dev, hchannel, data);
 
  646    case CAM_MSG_ID_StopStreamsRequest:
 
  647      error = ecam_dev_process_stop_streams_request(dev, hchannel, data);
 
  650    case CAM_MSG_ID_SampleRequest:
 
  651      error = ecam_dev_process_sample_request(dev, hchannel, data);
 
  655      WLog_WARN(TAG, 
"unknown MessageId=0x%02" PRIx8 
"", messageId);
 
  656      error = ERROR_INVALID_DATA;
 
  657      ecam_channel_send_error_response(dev->ecam, hchannel,
 
  658                                       CAM_ERROR_CODE_OperationNotSupported);
 
  670static UINT ecam_dev_on_open(WINPR_ATTR_UNUSED IWTSVirtualChannelCallback* pChannelCallback)
 
  672  WLog_DBG(TAG, 
"entered");
 
  673  return CHANNEL_RC_OK;
 
  681static UINT ecam_dev_on_close(IWTSVirtualChannelCallback* pChannelCallback)
 
  684  WINPR_ASSERT(hchannel);
 
  689  WLog_DBG(TAG, 
"entered");
 
  692  for (
size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
 
  693    if (dev->streams[i].hSampleReqChannel == hchannel)
 
  694      dev->streams[i].hSampleReqChannel = NULL;
 
  697  return CHANNEL_RC_OK;
 
  705static UINT ecam_dev_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
 
  706                                               IWTSVirtualChannel* pChannel,
 
  707                                               WINPR_ATTR_UNUSED BYTE* Data,
 
  708                                               WINPR_ATTR_UNUSED BOOL* pbAccept,
 
  709                                               IWTSVirtualChannelCallback** ppCallback)
 
  713  if (!hlistener || !hlistener->plugin)
 
  714    return ERROR_INTERNAL_ERROR;
 
  716  WLog_DBG(TAG, 
"entered");
 
  722    WLog_ERR(TAG, 
"calloc failed");
 
  723    return CHANNEL_RC_NO_MEMORY;
 
  726  hchannel->iface.OnDataReceived = ecam_dev_on_data_received;
 
  727  hchannel->iface.OnOpen = ecam_dev_on_open;
 
  728  hchannel->iface.OnClose = ecam_dev_on_close;
 
  729  hchannel->plugin = hlistener->plugin;
 
  730  hchannel->channel_mgr = hlistener->channel_mgr;
 
  731  hchannel->channel = pChannel;
 
  732  *ppCallback = (IWTSVirtualChannelCallback*)hchannel;
 
  733  return CHANNEL_RC_OK;
 
  742                              WINPR_ATTR_UNUSED 
const char* deviceName)
 
  745  WINPR_ASSERT(ecam->hlistener);
 
  747  IWTSVirtualChannelManager* pChannelMgr = ecam->hlistener->channel_mgr;
 
  748  WINPR_ASSERT(pChannelMgr);
 
  750  WLog_DBG(TAG, 
"entered for %s", deviceId);
 
  756    WLog_ERR(TAG, 
"calloc failed");
 
  761  dev->ihal = ecam->ihal;
 
  762  strncpy(dev->deviceId, deviceId, 
sizeof(dev->deviceId) - 1);
 
  768    WLog_ERR(TAG, 
"calloc failed");
 
  772  dev->hlistener->iface.OnNewChannelConnection = ecam_dev_on_new_channel_connection;
 
  773  dev->hlistener->plugin = (IWTSPlugin*)dev;
 
  774  dev->hlistener->channel_mgr = pChannelMgr;
 
  775  if (CHANNEL_RC_OK != pChannelMgr->CreateListener(pChannelMgr, deviceId, 0,
 
  776                                                   &dev->hlistener->iface, &dev->listener))
 
  778    free(dev->hlistener);
 
  780    WLog_ERR(TAG, 
"CreateListener failed");
 
  798  WLog_DBG(TAG, 
"entered for %s", dev->deviceId);
 
  802    IWTSVirtualChannelManager* mgr = dev->hlistener->channel_mgr;
 
  804      IFCALL(mgr->DestroyListener, mgr, dev->listener);
 
  807  free(dev->hlistener);
 
  809  for (
size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++)
 
  810    ecam_dev_stop_stream(dev, i);