Merge branch 'patch-2' of https://github.com/AMV007/FreeRDP into AMV007-patch-2
authorArmin Novak <armin.novak@thincast.com>
Tue, 17 Jan 2017 09:03:05 +0000 (10:03 +0100)
committerArmin Novak <armin.novak@thincast.com>
Tue, 17 Jan 2017 09:03:05 +0000 (10:03 +0100)
Conflicts:
channels/tsmf/client/tsmf_ifman.c
channels/tsmf/client/tsmf_media.c

1  2 
channels/tsmf/client/tsmf_ifman.c
channels/tsmf/client/tsmf_media.c

@@@ -48,26 -41,19 +48,26 @@@ UINT tsmf_ifman_rim_exchange_capability
  {
        UINT32 CapabilityValue;
  
 -      Stream_Read_UINT32(ifman->input, CapabilityValue);
 +      if (Stream_GetRemainingLength(ifman->input) < 4)
 +              return ERROR_INVALID_DATA;
-       Stream_Read_UINT32(ifman->input, CapabilityValue);
  
 -      DEBUG_TSMF("server CapabilityValue %d", CapabilityValue);
++      Stream_Read_UINT32(ifman->input, CapabilityValue);
 +      DEBUG_TSMF("server CapabilityValue %"PRIu32"", CapabilityValue);
  
        if (!Stream_EnsureRemainingCapacity(ifman->output, 8))
 -              return -1;
 +              return ERROR_INVALID_DATA;
++
        Stream_Write_UINT32(ifman->output, 1); /* CapabilityValue */
        Stream_Write_UINT32(ifman->output, 0); /* Result */
--
 -      return 0;
 +      return CHANNEL_RC_OK;
  }
  
 -int tsmf_ifman_exchange_capability_request(TSMF_IFMAN* ifman)
 +/**
 + * Function description
 + *
 + * @return 0 on success, otherwise a Win32 error code
 + */
 +UINT tsmf_ifman_exchange_capability_request(TSMF_IFMAN* ifman)
  {
        UINT32 i;
        UINT32 v;
        UINT32 numHostCapabilities;
  
        if (!Stream_EnsureRemainingCapacity(ifman->output, ifman->input_size + 4))
 -              return -1;
 +              return ERROR_OUTOFMEMORY;
++
        pos = Stream_GetPosition(ifman->output);
 -      Stream_Copy(ifman->output, ifman->input, ifman->input_size);
 +      Stream_Copy(ifman->input, ifman->output, ifman->input_size);
        Stream_SetPosition(ifman->output, pos);
 +
 +      if (Stream_GetRemainingLength(ifman->output) < 4)
 +              return ERROR_INVALID_DATA;
++
        Stream_Read_UINT32(ifman->output, numHostCapabilities);
  
        for (i = 0; i < numHostCapabilities; i++)
                switch (CapabilityType)
                {
                        case 1: /* Protocol version request */
 +                              if (Stream_GetRemainingLength(ifman->output) < 4)
 +                                      return ERROR_INVALID_DATA;
 +
                                Stream_Read_UINT32(ifman->output, v);
 -                              DEBUG_TSMF("server protocol version %d", v);
 +                              DEBUG_TSMF("server protocol version %"PRIu32"", v);
                                break;
++
                        case 2: /* Supported platform */
 +                              if (Stream_GetRemainingLength(ifman->output) < 4)
 +                                      return ERROR_INVALID_DATA;
 +
                                Stream_Peek_UINT32(ifman->output, v);
 -                              DEBUG_TSMF("server supported platform %d", v);
 +                              DEBUG_TSMF("server supported platform %"PRIu32"", v);
                                /* Claim that we support both MF and DShow platforms. */
--                              Stream_Write_UINT32(ifman->output, MMREDIR_CAPABILITY_PLATFORM_MF | MMREDIR_CAPABILITY_PLATFORM_DSHOW);
++                              Stream_Write_UINT32(ifman->output,
++                                                  MMREDIR_CAPABILITY_PLATFORM_MF | MMREDIR_CAPABILITY_PLATFORM_DSHOW);
                                break;
++
                        default:
 -                              WLog_ERR(TAG, "unknown capability type %d", CapabilityType);
 +                              WLog_ERR(TAG, "skipping unknown capability type %"PRIu32"", CapabilityType);
                                break;
                }
++
                Stream_SetPosition(ifman->output, pos + cbCapabilityLength);
        }
  
        Stream_Write_UINT32(ifman->output, 0); /* Result */
        ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
--
 -      return 0;
 +      return CHANNEL_RC_OK;
  }
  
 -int tsmf_ifman_check_format_support_request(TSMF_IFMAN* ifman)
 +/**
 + * Function description
 + *
 + * @return 0 on success, otherwise a Win32 error code
 + */
 +UINT tsmf_ifman_check_format_support_request(TSMF_IFMAN* ifman)
  {
        UINT32 numMediaType;
        UINT32 PlatformCookie;
        Stream_Read_UINT32(ifman->input, PlatformCookie);
        Stream_Seek_UINT32(ifman->input); /* NoRolloverFlags (4 bytes) */
        Stream_Read_UINT32(ifman->input, numMediaType);
--
 -      DEBUG_TSMF("PlatformCookie %d numMediaType %d", PlatformCookie, numMediaType);
 +      DEBUG_TSMF("PlatformCookie %"PRIu32" numMediaType %"PRIu32"", PlatformCookie, numMediaType);
  
        if (!tsmf_codec_check_media_type(ifman->decoder_name, ifman->input))
                FormatSupported = 0;
  
        if (!Stream_EnsureRemainingCapacity(ifman->output, 12))
                return -1;
++
        Stream_Write_UINT32(ifman->output, FormatSupported);
        Stream_Write_UINT32(ifman->output, PlatformCookie);
        Stream_Write_UINT32(ifman->output, 0); /* Result */
        ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
--
 -      return 0;
 +      return CHANNEL_RC_OK;
  }
  
 -int tsmf_ifman_on_new_presentation(TSMF_IFMAN* ifman)
 +/**
 + * Function description
 + *
 + * @return 0 on success, otherwise a Win32 error code
 + */
 +UINT tsmf_ifman_on_new_presentation(TSMF_IFMAN* ifman)
  {
 -      int status = 0;
 +      UINT status = CHANNEL_RC_OK;
        TSMF_PRESENTATION* presentation;
--
        DEBUG_TSMF("");
  
 +      if (Stream_GetRemainingLength(ifman->input) < GUID_SIZE)
 +              return ERROR_INVALID_DATA;
 +
        presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
  
        if (presentation)
                tsmf_presentation_set_audio_device(presentation, ifman->audio_name, ifman->audio_device);
  
        ifman->output_pending = TRUE;
--
        return status;
  }
  
 -int tsmf_ifman_add_stream(TSMF_IFMAN* ifman)
 +/**
 + * Function description
 + *
 + * @return 0 on success, otherwise a Win32 error code
 + */
 +UINT tsmf_ifman_add_stream(TSMF_IFMAN* ifman, rdpContext* rdpcontext)
  {
        UINT32 StreamId;
 -      int status = 0;
 +      UINT status = CHANNEL_RC_OK;
        TSMF_STREAM* stream;
        TSMF_PRESENTATION* presentation;
--
        DEBUG_TSMF("");
  
 +      if (Stream_GetRemainingLength(ifman->input) < GUID_SIZE + 8)
 +              return ERROR_INVALID_DATA;
 +
        presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
 -      Stream_Seek(ifman->input, 16);
 +      Stream_Seek(ifman->input, GUID_SIZE);
  
        if (!presentation)
        {
        {
                Stream_Read_UINT32(ifman->input, StreamId);
                Stream_Seek_UINT32(ifman->input); /* numMediaType */
 -              stream = tsmf_stream_new(presentation, StreamId);
 -              if (stream)
 -                      tsmf_stream_set_format(stream, ifman->decoder_name, ifman->input);
 +              stream = tsmf_stream_new(presentation, StreamId, rdpcontext);
++
 +              if (!stream)
 +              {
 +                      WLog_ERR(TAG, "failed to create stream");
 +                      return ERROR_OUTOFMEMORY;
 +              }
 +
 +              if (!tsmf_stream_set_format(stream, ifman->decoder_name, ifman->input))
 +              {
 +                      WLog_ERR(TAG, "failed to set stream format");
 +                      return ERROR_OUTOFMEMORY;
 +              }
++
+               tsmf_stream_start_threads(stream);
        }
 +
        ifman->output_pending = TRUE;
        return status;
  }
  
 -int tsmf_ifman_set_topology_request(TSMF_IFMAN* ifman)
 +/**
 + * Function description
 + *
 + * @return 0 on success, otherwise a Win32 error code
 + */
 +UINT tsmf_ifman_set_topology_request(TSMF_IFMAN* ifman)
  {
        DEBUG_TSMF("");
++
        if (!Stream_EnsureRemainingCapacity(ifman->output, 8))
 -              return -1;
 +              return ERROR_OUTOFMEMORY;
 +
        Stream_Write_UINT32(ifman->output, 1); /* TopologyReady */
        Stream_Write_UINT32(ifman->output, 0); /* Result */
        ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
@@@ -277,15 -202,12 +282,13 @@@ UINT tsmf_ifman_remove_stream(TSMF_IFMA
        UINT32 StreamId;
        TSMF_STREAM* stream;
        TSMF_PRESENTATION* presentation;
--
        DEBUG_TSMF("");
  
 -      presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
 +      if (Stream_GetRemainingLength(ifman->input) < 20)
 +              return ERROR_INVALID_DATA;
  
 -      Stream_Seek(ifman->input, 16);
 +      presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
 +      Stream_Seek(ifman->input, GUID_SIZE);
  
        if (!presentation)
        {
        }
  
        ifman->output_pending = TRUE;
--
        return status;
  }
  
--float tsmf_stream_read_float(wStream *s)
++float tsmf_stream_read_float(wStreams)
  {
        float fValue;
        UINT32 iValue;
@@@ -327,15 -244,12 +329,13 @@@ UINT tsmf_ifman_set_source_video_rect(T
        float Left, Top;
        float Right, Bottom;
        TSMF_PRESENTATION* presentation;
--
        DEBUG_TSMF("");
  
 -      presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
 +      if (Stream_GetRemainingLength(ifman->input) < 32)
 +              return ERROR_INVALID_DATA;
  
 -      Stream_Seek(ifman->input, 16);
 +      presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
 +      Stream_Seek(ifman->input, GUID_SIZE);
  
        if (!presentation)
        {
                Right = tsmf_stream_read_float(ifman->input); /* Right (4 bytes) */
                Bottom = tsmf_stream_read_float(ifman->input); /* Bottom (4 bytes) */
                DEBUG_TSMF("SetSourceVideoRect: Left: %f Top: %f Right: %f Bottom: %f",
--                                 Left, Top, Right, Bottom);
++                         Left, Top, Right, Bottom);
        }
  
        ifman->output_pending = TRUE;
--
        return status;
  }
  
 -int tsmf_ifman_shutdown_presentation(TSMF_IFMAN* ifman)
 +/**
 + * Function description
 + *
 + * @return 0 on success, otherwise a Win32 error code
 + */
 +UINT tsmf_ifman_shutdown_presentation(TSMF_IFMAN* ifman)
  {
        TSMF_PRESENTATION* presentation;
--
        DEBUG_TSMF("");
  
 +      if (Stream_GetRemainingLength(ifman->input) < GUID_SIZE)
 +              return ERROR_INVALID_DATA;
 +
        presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
        if (presentation)
                tsmf_presentation_free(presentation);
        else
 +      {
                WLog_ERR(TAG, "unknown presentation id");
 +              return ERROR_NOT_FOUND;
 +      }
  
        if (!Stream_EnsureRemainingCapacity(ifman->output, 4))
 -              return -1;
 +              return ERROR_OUTOFMEMORY;
 +
        Stream_Write_UINT32(ifman->output, 0); /* Result */
        ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
--
 -      return 0;
 +      return CHANNEL_RC_OK;
  }
  
 -int tsmf_ifman_on_stream_volume(TSMF_IFMAN* ifman)
 +/**
 + * Function description
 + *
 + * @return 0 on success, otherwise a Win32 error code
 + */
 +UINT tsmf_ifman_on_stream_volume(TSMF_IFMAN* ifman)
  {
        TSMF_PRESENTATION* presentation;
 +      UINT32 newVolume;
 +      UINT32 muted;
        DEBUG_TSMF("on stream volume");
 +
 +      if (Stream_GetRemainingLength(ifman->input) < GUID_SIZE + 8)
 +              return ERROR_INVALID_DATA;
 +
        presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
  
 -      if (presentation)
 -      {
 -              UINT32 newVolume;
 -              UINT32 muted;
 -              Stream_Seek(ifman->input, 16);
 -              Stream_Read_UINT32(ifman->input, newVolume);
 -              DEBUG_TSMF("on stream volume: new volume=[%d]", newVolume);
 -              Stream_Read_UINT32(ifman->input, muted);
 -              DEBUG_TSMF("on stream volume: muted=[%d]", muted);
 -              tsmf_presentation_volume_changed(presentation, newVolume, muted);
 -      }
 -      else
 +      if (!presentation)
        {
                WLog_ERR(TAG, "unknown presentation id");
 +              return ERROR_NOT_FOUND;
        }
  
 -      ifman->output_pending = TRUE;
 +      Stream_Seek(ifman->input, 16);
 +      Stream_Read_UINT32(ifman->input, newVolume);
 +      DEBUG_TSMF("on stream volume: new volume=[%"PRIu32"]", newVolume);
 +      Stream_Read_UINT32(ifman->input, muted);
 +      DEBUG_TSMF("on stream volume: muted=[%"PRIu32"]", muted);
 +
 +      if (!tsmf_presentation_volume_changed(presentation, newVolume, muted))
 +              return ERROR_INVALID_OPERATION;
  
 +      ifman->output_pending = TRUE;
        return 0;
  }
  
 -int tsmf_ifman_on_channel_volume(TSMF_IFMAN* ifman)
 +/**
 + * Function description
 + *
 + * @return 0 on success, otherwise a Win32 error code
 + */
 +UINT tsmf_ifman_on_channel_volume(TSMF_IFMAN* ifman)
  {
        TSMF_PRESENTATION* presentation;
--
        DEBUG_TSMF("on channel volume");
  
 +      if (Stream_GetRemainingLength(ifman->input) < GUID_SIZE + 8)
 +              return ERROR_INVALID_DATA;
 +
        presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
        if (presentation)
        {
                UINT32 channelVolume;
        }
  
        ifman->output_pending = TRUE;
--
 -      return 0;
 +      return CHANNEL_RC_OK;
  }
  
 -int tsmf_ifman_set_video_window(TSMF_IFMAN* ifman)
 +/**
 + * Function description
 + *
 + * @return 0 on success, otherwise a Win32 error code
 + */
 +UINT tsmf_ifman_set_video_window(TSMF_IFMAN* ifman)
  {
        DEBUG_TSMF("");
        ifman->output_pending = TRUE;
@@@ -483,19 -358,12 +478,20 @@@ UINT tsmf_ifman_update_geometry_info(TS
        UINT32 Width;
        UINT32 Height;
        UINT32 cbVisibleRect;
--      RDP_RECT *rects = NULL;
++      RDP_RECTrects = NULL;
        int num_rects = 0;
 -      int error = 0;
 +      UINT error = CHANNEL_RC_OK;
        int i;
        int pos;
 +
 +      if (Stream_GetRemainingLength(ifman->input) < GUID_SIZE + 32)
 +              return ERROR_INVALID_DATA;
 +
        presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
++
 +      if (!presentation)
 +              return ERROR_NOT_FOUND;
 +
        Stream_Seek(ifman->input, 16);
        Stream_Read_UINT32(ifman->input, numGeometryInfo);
        pos = Stream_GetPosition(ifman->input);
        Stream_SetPosition(ifman->input, pos + numGeometryInfo);
        Stream_Read_UINT32(ifman->input, cbVisibleRect);
        num_rects = cbVisibleRect / 16;
 -      DEBUG_TSMF("numGeometryInfo %d Width %d Height %d Left %d Top %d cbVisibleRect %d num_rects %d",
 -                         numGeometryInfo, Width, Height, Left, Top, cbVisibleRect, num_rects);
 -      if (presentation == NULL)
 -      {
 -              error = 1;
 -      }
 -      else
 +      DEBUG_TSMF("numGeometryInfo %"PRIu32" Width %"PRIu32" Height %"PRIu32" Left %"PRIu32" Top %"PRIu32" cbVisibleRect %"PRIu32" num_rects %d",
-                          numGeometryInfo, Width, Height, Left, Top, cbVisibleRect, num_rects);
++                 numGeometryInfo, Width, Height, Left, Top, cbVisibleRect, num_rects);
 +
 +      if (num_rects > 0)
        {
 -              if (num_rects > 0)
 +              rects = (RDP_RECT*) calloc(num_rects, sizeof(RDP_RECT));
 +
 +              for (i = 0; i < num_rects; i++)
                {
 -                      rects = (RDP_RECT*) calloc(num_rects, sizeof(RDP_RECT));
 -
 -                      for (i = 0; i < num_rects; i++)
 -                      {
 -                              Stream_Read_UINT16(ifman->input, rects[i].y); /* Top */
 -                              Stream_Seek_UINT16(ifman->input);
 -                              Stream_Read_UINT16(ifman->input, rects[i].x); /* Left */
 -                              Stream_Seek_UINT16(ifman->input);
 -                              Stream_Read_UINT16(ifman->input, rects[i].height); /* Bottom */
 -                              Stream_Seek_UINT16(ifman->input);
 -                              Stream_Read_UINT16(ifman->input, rects[i].width); /* Right */
 -                              Stream_Seek_UINT16(ifman->input);
 -                              rects[i].width -= rects[i].x;
 -                              rects[i].height -= rects[i].y;
 -                              DEBUG_TSMF("rect %d: %d %d %d %d", i,
 -                                                 rects[i].x, rects[i].y, rects[i].width, rects[i].height);
 -                      }
 +                      Stream_Read_UINT16(ifman->input, rects[i].y); /* Top */
 +                      Stream_Seek_UINT16(ifman->input);
 +                      Stream_Read_UINT16(ifman->input, rects[i].x); /* Left */
 +                      Stream_Seek_UINT16(ifman->input);
 +                      Stream_Read_UINT16(ifman->input, rects[i].height); /* Bottom */
 +                      Stream_Seek_UINT16(ifman->input);
 +                      Stream_Read_UINT16(ifman->input, rects[i].width); /* Right */
 +                      Stream_Seek_UINT16(ifman->input);
 +                      rects[i].width -= rects[i].x;
 +                      rects[i].height -= rects[i].y;
 +                      DEBUG_TSMF("rect %d: %"PRId16" %"PRId16" %"PRId16" %"PRId16"", i,
-                                          rects[i].x, rects[i].y, rects[i].width, rects[i].height);
++                                 rects[i].x, rects[i].y, rects[i].width, rects[i].height);
                }
 -
 -              tsmf_presentation_set_geometry_info(presentation, Left, Top, Width, Height, num_rects, rects);
        }
  
 -      ifman->output_pending = TRUE;
 +      if (!tsmf_presentation_set_geometry_info(presentation, Left, Top, Width, Height, num_rects, rects))
 +              return ERROR_INVALID_OPERATION;
  
 +      ifman->output_pending = TRUE;
        return error;
  }
  
@@@ -580,10 -436,7 +574,11 @@@ UINT tsmf_ifman_on_sample(TSMF_IFMAN* i
        UINT64 ThrottleDuration;
        UINT32 SampleExtensions;
        UINT32 cbData;
 +      UINT error;
 +
 +      if (Stream_GetRemainingLength(ifman->input) < 60)
 +              return ERROR_INVALID_DATA;
        Stream_Seek(ifman->input, 16);
        Stream_Read_UINT32(ifman->input, StreamId);
        Stream_Seek_UINT32(ifman->input); /* numSample */
        Stream_Read_UINT32(ifman->input, SampleExtensions);
        Stream_Read_UINT32(ifman->input, cbData);
  
 -      DEBUG_TSMF("MessageId %d StreamId %d SampleStartTime %d SampleEndTime %d "
 -                         "ThrottleDuration %d SampleExtensions %d cbData %d",
 -                         ifman->message_id, StreamId, (int)SampleStartTime, (int)SampleEndTime,
 -                         (int)ThrottleDuration, SampleExtensions, cbData);
 +      if (Stream_GetRemainingLength(ifman->input) < cbData)
 +              return ERROR_INVALID_DATA;
  
-                          "ThrottleDuration %"PRIu64" SampleExtensions %"PRIu32" cbData %"PRIu32"",
-                          ifman->message_id, StreamId, SampleStartTime, SampleEndTime,
-                          ThrottleDuration, SampleExtensions, cbData);
 +      DEBUG_TSMF("MessageId %"PRIu32" StreamId %"PRIu32" SampleStartTime %"PRIu64" SampleEndTime %"PRIu64" "
++                 "ThrottleDuration %"PRIu64" SampleExtensions %"PRIu32" cbData %"PRIu32"",
++                 ifman->message_id, StreamId, SampleStartTime, SampleEndTime,
++                 ThrottleDuration, SampleExtensions, cbData);
        presentation = tsmf_presentation_find_by_id(ifman->presentation_id);
  
        if (!presentation)
        if (!stream)
        {
                WLog_ERR(TAG, "unknown stream id");
 -              return 1;
 +              return ERROR_NOT_FOUND;
        }
  
 -      tsmf_stream_push_sample(stream, ifman->channel_callback,
 -                      ifman->message_id, SampleStartTime, SampleEndTime,
 -                      ThrottleDuration, SampleExtensions, cbData, Stream_Pointer(ifman->input));
 +      if (!tsmf_stream_push_sample(stream, ifman->channel_callback,
-                       ifman->message_id, SampleStartTime, SampleEndTime,
-                       ThrottleDuration, SampleExtensions, cbData, Stream_Pointer(ifman->input)))
++                                   ifman->message_id, SampleStartTime, SampleEndTime,
++                                   ThrottleDuration, SampleExtensions, cbData, Stream_Pointer(ifman->input)))
 +      {
 +              WLog_ERR(TAG, "unable to push sample");
 +              return ERROR_OUTOFMEMORY;
 +      }
  
 -      tsmf_presentation_sync(presentation);
 -      ifman->output_pending = TRUE;
 +      if ((error = tsmf_presentation_sync(presentation)))
-     {
-         WLog_ERR(TAG, "tsmf_presentation_sync failed with error %"PRIu32"", error);
-         return error;
-     }
-       ifman->output_pending = TRUE;
++      {
++              WLog_ERR(TAG, "tsmf_presentation_sync failed with error %"PRIu32"", error);
++              return error;
++      }
  
 -      return 0;
++      ifman->output_pending = TRUE;
 +      return CHANNEL_RC_OK;
  }
  
 -int tsmf_ifman_on_flush(TSMF_IFMAN* ifman)
 +/**
 + * Function description
 + *
 + * @return 0 on success, otherwise a Win32 error code
 + */
 +UINT tsmf_ifman_on_flush(TSMF_IFMAN* ifman)
  {
        UINT32 StreamId;
        TSMF_PRESENTATION* presentation;
  
        Stream_Seek(ifman->input, 16);
        Stream_Read_UINT32(ifman->input, StreamId);
 -
 -      DEBUG_TSMF("StreamId %d", StreamId);
--
 +      DEBUG_TSMF("StreamId %"PRIu32"", StreamId);
        presentation = tsmf_presentation_find_by_id(ifman->presentation_id);
        if (!presentation)
        {
                WLog_ERR(TAG, "unknown presentation id");
 -              return 1;
 +              return ERROR_NOT_FOUND;
        }
  
 -      tsmf_presentation_flush(presentation);
 -      ifman->output_pending = TRUE;
 +      /* Flush message is for a stream, not the entire presentation
 +       * therefore we only flush the stream as intended per the MS-RDPEV spec
 +       */
 +      stream = tsmf_stream_find_by_id(presentation, StreamId);
 -      return 0;
 +      if (stream)
 +      {
 +              if (!tsmf_stream_flush(stream))
 +                      return ERROR_INVALID_OPERATION;
 +      }
 +      else
 +              WLog_ERR(TAG, "unknown stream id");
 +
 +      ifman->output_pending = TRUE;
 +      return CHANNEL_RC_OK;
  }
  
 -int tsmf_ifman_on_end_of_stream(TSMF_IFMAN* ifman)
 +/**
 + * Function description
 + *
 + * @return 0 on success, otherwise a Win32 error code
 + */
 +UINT tsmf_ifman_on_end_of_stream(TSMF_IFMAN* ifman)
  {
        UINT32 StreamId;
 -      TSMF_STREAM* stream;
 +      TSMF_STREAM* stream = NULL;
        TSMF_PRESENTATION* presentation;
  
 -      presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
 +      if (Stream_GetRemainingLength(ifman->input) < 20)
 +              return ERROR_INVALID_DATA;
  
 +      presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
        Stream_Seek(ifman->input, 16);
        Stream_Read_UINT32(ifman->input, StreamId);
  
                stream = tsmf_stream_find_by_id(presentation, StreamId);
  
                if (stream)
-                       tsmf_stream_end(stream, ifman->message_id, ifman->channel_callback);
 -                      tsmf_stream_end(stream);
++                      tsmf_stream_end(stream, ifman->message_id, ifman->channel_callback);
        }
  
 -      DEBUG_TSMF("StreamId %d", StreamId);
 -      if (!Stream_EnsureRemainingCapacity(ifman->output, 16))
 -              return -1;
 -      Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */
 -      Stream_Write_UINT32(ifman->output, StreamId); /* StreamId */
 -      Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_ENDOFSTREAM); /* EventId */
 -      Stream_Write_UINT32(ifman->output, 0); /* cbData */
 +      DEBUG_TSMF("StreamId %"PRIu32"", StreamId);
 +      ifman->output_pending = TRUE;
        ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
 -
 -      return 0;
 +      return CHANNEL_RC_OK;
  }
  
 -int tsmf_ifman_on_playback_started(TSMF_IFMAN* ifman)
 +/**
 + * Function description
 + *
 + * @return 0 on success, otherwise a Win32 error code
 + */
 +UINT tsmf_ifman_on_playback_started(TSMF_IFMAN* ifman)
  {
        TSMF_PRESENTATION* presentation;
--
        DEBUG_TSMF("");
  
 +      if (Stream_GetRemainingLength(ifman->input) < 16)
 +              return ERROR_INVALID_DATA;
 +
        presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
  
        if (presentation)
        Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_START_COMPLETED); /* EventId */
        Stream_Write_UINT32(ifman->output, 0); /* cbData */
        ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
--
 -      return 0;
 +      return CHANNEL_RC_OK;
  }
  
 -int tsmf_ifman_on_playback_paused(TSMF_IFMAN* ifman)
 +/**
 + * Function description
 + *
 + * @return 0 on success, otherwise a Win32 error code
 + */
 +UINT tsmf_ifman_on_playback_paused(TSMF_IFMAN* ifman)
  {
        TSMF_PRESENTATION* presentation;
--
        DEBUG_TSMF("");
        ifman->output_pending = TRUE;
--
        /* Added pause control so gstreamer pipeline can be paused accordingly */
        presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
  
        else
                WLog_ERR(TAG, "unknown presentation id");
  
 -      return 0;
 +      return CHANNEL_RC_OK;
  }
  
 -int tsmf_ifman_on_playback_restarted(TSMF_IFMAN* ifman)
 +/**
 + * Function description
 + *
 + * @return 0 on success, otherwise a Win32 error code
 + */
 +UINT tsmf_ifman_on_playback_restarted(TSMF_IFMAN* ifman)
  {
        TSMF_PRESENTATION* presentation;
--
        DEBUG_TSMF("");
        ifman->output_pending = TRUE;
--
        /* Added restart control so gstreamer pipeline can be resumed accordingly */
        presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
        if (presentation)
 -              tsmf_presentation_restarted(presentation);
 +      {
 +              if (!tsmf_presentation_restarted(presentation))
 +                      return ERROR_INVALID_OPERATION;
 +      }
        else
                WLog_ERR(TAG, "unknown presentation id");
  
 -      return 0;
 +      return CHANNEL_RC_OK;
  }
  
 -int tsmf_ifman_on_playback_stopped(TSMF_IFMAN* ifman)
 +/**
 + * Function description
 + *
 + * @return 0 on success, otherwise a Win32 error code
 + */
 +UINT tsmf_ifman_on_playback_stopped(TSMF_IFMAN* ifman)
  {
        TSMF_PRESENTATION* presentation;
--
        DEBUG_TSMF("");
--
        presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
        if (presentation)
 -              tsmf_presentation_stop(presentation);
 +      {
 +              if (!tsmf_presentation_stop(presentation))
 +                      return ERROR_INVALID_OPERATION;
 +      }
        else
                WLog_ERR(TAG, "unknown presentation id");
  
        Stream_Write_UINT32(ifman->output, 0); /* StreamId */
        Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_STOP_COMPLETED); /* EventId */
        Stream_Write_UINT32(ifman->output, 0); /* cbData */
        ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
 -
 -      return 0;
 +      return CHANNEL_RC_OK;
  }
  
 -int tsmf_ifman_on_playback_rate_changed(TSMF_IFMAN* ifman)
 +/**
 + * Function description
 + *
 + * @return 0 on success, otherwise a Win32 error code
 + */
 +UINT tsmf_ifman_on_playback_rate_changed(TSMF_IFMAN* ifman)
  {
        DEBUG_TSMF("");
 +
        if (!Stream_EnsureRemainingCapacity(ifman->output, 16))
 -              return -1;
 +              return ERROR_OUTOFMEMORY;
 +
        Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */
        Stream_Write_UINT32(ifman->output, 0); /* StreamId */
        Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_MONITORCHANGED); /* EventId */
@@@ -455,6 -374,25 +455,26 @@@ static BOOL tsmf_sample_playback_video(
                event.framePixFmt = sample->pixfmt;
                event.frameWidth = sample->stream->width;
                event.frameHeight = sample->stream->height;
 -
+               event.x = presentation->x;
+               event.y = presentation->y;
+               event.width = presentation->width;
+               event.height = presentation->height;
+               if (presentation->nr_rects > 0)
+               {
+                       event.numVisibleRects = presentation->nr_rects;
+                       event.visibleRects = (RECTANGLE_16*) calloc(1, event.numVisibleRects * sizeof(RECTANGLE_16));
++
+                       if (!event.visibleRects)
+                       {
+                               WLog_ERR(TAG, "can't allocate memory for copy rectangles");
+                               return;
+                       }
++
+                       memcpy(event.visibleRects, presentation->rects, presentation->nr_rects * sizeof(RDP_RECT));
+                       presentation->nr_rects = 0;
+               }
  #if 0
                /* Dump a .ppm image for every 30 frames. Assuming the frame is in YUV format, we
                   extract the Y values to create a grayscale image. */
                        tsmf->FrameEvent(tsmf, &event);
  
                free(event.frameData);
 -              if(event.visibleRects != NULL)
++              if (event.visibleRects != NULL)
+                       free(event.visibleRects);
        }
 +
 +      return TRUE;
  }
  
 -static void tsmf_sample_playback_audio(TSMF_SAMPLE* sample)
 +static BOOL tsmf_sample_playback_audio(TSMF_SAMPLE* sample)
  {
        UINT64 latency = 0;
        TSMF_STREAM* stream = sample->stream;
@@@ -716,9 -594,8 +739,8 @@@ static void* tsmf_stream_ack_func(void
  {
        HANDLE hdl[2];
        TSMF_STREAM* stream = (TSMF_STREAM*) arg;
 -      DEBUG_TSMF("in %d", stream->stream_id);
 -
 +      UINT error = CHANNEL_RC_OK;
 +      DEBUG_TSMF("in %"PRIu32"", stream->stream_id);
        hdl[0] = stream->stopEvent;
        hdl[1] = Queue_Event(stream->sample_ack_list);
  
@@@ -1108,10 -859,20 +1130,17 @@@ BOOL tsmf_presentation_set_geometry_inf
        presentation->y = y;
        presentation->width = width;
        presentation->height = height;
 -
        tmp_rects = realloc(presentation->rects, sizeof(RDP_RECT) * num_rects);
 -      if(!num_rects)
 -              presentation->rects=NULL;
 -      if (!tmp_rects&&num_rects)
++      if (!num_rects)
++              presentation->rects = NULL;
++      if (!tmp_rects && num_rects)
+               return;
        presentation->nr_rects = num_rects;
        presentation->rects = tmp_rects;
 -
        CopyMemory(presentation->rects, rects, sizeof(RDP_RECT) * num_rects);
 -
        ArrayList_Lock(presentation->stream_list);
        count = ArrayList_Count(presentation->stream_list);
  
@@@ -1210,71 -976,27 +1239,77 @@@ TSMF_STREAM* tsmf_stream_new(TSMF_PRESE
        stream->stream_id = stream_id;
        stream->presentation = presentation;
        stream->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
 +
 +      if (!stream->stopEvent)
 +              goto error_stopEvent;
 +
        stream->ready = CreateEvent(NULL, TRUE, TRUE, NULL);
 +
 +      if (!stream->ready)
 +              goto error_ready;
 +
        stream->sample_list = Queue_New(TRUE, -1, -1);
 +
 +      if (!stream->sample_list)
 +              goto error_sample_list;
 +
        stream->sample_list->object.fnObjectFree = tsmf_sample_free;
        stream->sample_ack_list = Queue_New(TRUE, -1, -1);
 +
 +      if (!stream->sample_ack_list)
 +              goto error_sample_ack_list;
 +
        stream->sample_ack_list->object.fnObjectFree = tsmf_sample_free;
-       stream->play_thread = CreateThread(NULL, 0,
-                                          (LPTHREAD_START_ROUTINE) tsmf_stream_playback_func, stream, 0, NULL);
++      stream->play_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) tsmf_stream_playback_func,
++                                         stream, CREATE_SUSPENDED, NULL);
 +
 +      if (!stream->play_thread)
 +              goto error_play_thread;
 +
-       stream->ack_thread = CreateThread(NULL, 0,
-                                         (LPTHREAD_START_ROUTINE)tsmf_stream_ack_func, stream, 0, NULL);
++      stream->ack_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)tsmf_stream_ack_func, stream,
++                                        CREATE_SUSPENDED, NULL);
  
 -      stream->play_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) tsmf_stream_playback_func, stream, CREATE_SUSPENDED, NULL);
 -      stream->ack_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)tsmf_stream_ack_func, stream, CREATE_SUSPENDED, NULL);
 +      if (!stream->ack_thread)
 +              goto error_ack_thread;
  
 -      ArrayList_Add(presentation->stream_list, stream);
 +      if (ArrayList_Add(presentation->stream_list, stream) < 0)
 +              goto error_add;
  
 +      stream->rdpcontext = rdpcontext;
        return stream;
 +error_add:
 +      SetEvent(stream->stopEvent);
 +
 +      if (WaitForSingleObject(stream->ack_thread, INFINITE) == WAIT_FAILED)
 +              WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", GetLastError());
 +
 +error_ack_thread:
 +      SetEvent(stream->stopEvent);
 +
 +      if (WaitForSingleObject(stream->play_thread, INFINITE) == WAIT_FAILED)
 +              WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", GetLastError());
 +
 +error_play_thread:
 +      Queue_Free(stream->sample_ack_list);
 +error_sample_ack_list:
 +      Queue_Free(stream->sample_list);
 +error_sample_list:
 +      CloseHandle(stream->ready);
 +error_ready:
 +      CloseHandle(stream->stopEvent);
 +error_stopEvent:
 +      free(stream);
 +      return NULL;
  }
  
 -void tsmf_stream_start_threads (TSMF_STREAM* stream)
++void tsmf_stream_start_threads(TSMF_STREAM* stream)
+ {
+       ResumeThread(stream->play_thread);
+       ResumeThread(stream->ack_thread);
+ }
 -TSMF_STREAM *tsmf_stream_find_by_id(TSMF_PRESENTATION* presentation, UINT32 stream_id)
 +TSMF_STREAM* tsmf_stream_find_by_id(TSMF_PRESENTATION* presentation,
 +                                    UINT32 stream_id)
  {
        UINT32 index;
        UINT32 count;