FreeRDP/channels/tsmf/client/tsmf_ifman.c

835 lines
22 KiB
C
Raw Normal View History

2011-09-19 18:54:09 +04:00
/**
2012-10-09 07:02:04 +04:00
* FreeRDP: A Remote Desktop Protocol Implementation
2011-09-19 18:54:09 +04:00
* Video Redirection Virtual Channel - Interface Manipulation
*
* Copyright 2010-2011 Vic Lee
* Copyright 2012 Hewlett-Packard Development Company, L.P.
* Copyright 2015 Thincast Technologies GmbH
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
2011-09-19 18:54:09 +04:00
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
2011-09-19 18:54:09 +04:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winpr/crt.h>
#include <winpr/stream.h>
2011-09-19 18:54:09 +04:00
#include "tsmf_types.h"
2011-09-19 18:54:09 +04:00
#include "tsmf_constants.h"
#include "tsmf_media.h"
#include "tsmf_codec.h"
#include "tsmf_ifman.h"
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT tsmf_ifman_rim_exchange_capability_request(TSMF_IFMAN* ifman)
2011-09-19 18:54:09 +04:00
{
2012-10-09 11:26:39 +04:00
UINT32 CapabilityValue;
2014-11-10 22:02:54 +03:00
if (Stream_GetRemainingLength(ifman->input) < 4)
return ERROR_INVALID_DATA;
2014-11-10 22:02:54 +03:00
Stream_Read_UINT32(ifman->input, CapabilityValue);
DEBUG_TSMF("server CapabilityValue %"PRIu32"", CapabilityValue);
2014-11-10 22:02:54 +03:00
if (!Stream_EnsureRemainingCapacity(ifman->output, 8))
return ERROR_INVALID_DATA;
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(ifman->output, 1); /* CapabilityValue */
Stream_Write_UINT32(ifman->output, 0); /* Result */
return CHANNEL_RC_OK;
2011-09-19 18:54:09 +04:00
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT tsmf_ifman_exchange_capability_request(TSMF_IFMAN* ifman)
2011-09-19 18:54:09 +04:00
{
2012-10-09 11:26:39 +04:00
UINT32 i;
UINT32 v;
UINT32 pos;
UINT32 CapabilityType;
UINT32 cbCapabilityLength;
UINT32 numHostCapabilities;
2014-11-10 22:02:54 +03:00
if (!Stream_EnsureRemainingCapacity(ifman->output, ifman->input_size + 4))
return ERROR_OUTOFMEMORY;
pos = Stream_GetPosition(ifman->output);
2016-03-01 13:39:21 +03:00
Stream_Copy(ifman->input, ifman->output, ifman->input_size);
Stream_SetPosition(ifman->output, pos);
if (Stream_GetRemainingLength(ifman->output) < 4)
return ERROR_INVALID_DATA;
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(ifman->output, numHostCapabilities);
2014-11-10 22:02:54 +03:00
for (i = 0; i < numHostCapabilities; i++)
2011-09-19 18:54:09 +04:00
{
if (Stream_GetRemainingLength(ifman->output) < 8)
return ERROR_INVALID_DATA;
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(ifman->output, CapabilityType);
Stream_Read_UINT32(ifman->output, cbCapabilityLength);
if (Stream_GetRemainingLength(ifman->output) < cbCapabilityLength)
return ERROR_INVALID_DATA;
pos = Stream_GetPosition(ifman->output);
2014-11-10 22:02:54 +03:00
switch (CapabilityType)
2011-09-19 18:54:09 +04:00
{
case 1: /* Protocol version request */
if (Stream_GetRemainingLength(ifman->output) < 4)
return ERROR_INVALID_DATA;
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(ifman->output, v);
DEBUG_TSMF("server protocol version %"PRIu32"", v);
2011-09-19 18:54:09 +04:00
break;
2011-09-19 18:54:09 +04:00
case 2: /* Supported platform */
if (Stream_GetRemainingLength(ifman->output) < 4)
return ERROR_INVALID_DATA;
2013-05-09 00:27:21 +04:00
Stream_Peek_UINT32(ifman->output, v);
DEBUG_TSMF("server supported platform %"PRIu32"", v);
2011-09-19 18:54:09 +04:00
/* Claim that we support both MF and DShow platforms. */
Stream_Write_UINT32(ifman->output,
MMREDIR_CAPABILITY_PLATFORM_MF | MMREDIR_CAPABILITY_PLATFORM_DSHOW);
2011-09-19 18:54:09 +04:00
break;
2011-09-19 18:54:09 +04:00
default:
WLog_ERR(TAG, "skipping unknown capability type %"PRIu32"", CapabilityType);
2011-09-19 18:54:09 +04:00
break;
}
Stream_SetPosition(ifman->output, pos + cbCapabilityLength);
2011-09-19 18:54:09 +04:00
}
2014-11-10 22:02:54 +03:00
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(ifman->output, 0); /* Result */
2011-09-19 18:54:09 +04:00
ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
return CHANNEL_RC_OK;
2011-09-19 18:54:09 +04:00
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT tsmf_ifman_check_format_support_request(TSMF_IFMAN* ifman)
2011-09-19 18:54:09 +04:00
{
2012-10-09 11:26:39 +04:00
UINT32 numMediaType;
UINT32 PlatformCookie;
UINT32 FormatSupported = 1;
2014-11-10 22:02:54 +03:00
if (Stream_GetRemainingLength(ifman->input) < 12)
return ERROR_INVALID_DATA;
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(ifman->input, PlatformCookie);
Stream_Seek_UINT32(ifman->input); /* NoRolloverFlags (4 bytes) */
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(ifman->input, numMediaType);
DEBUG_TSMF("PlatformCookie %"PRIu32" numMediaType %"PRIu32"", PlatformCookie, numMediaType);
2014-11-10 22:02:54 +03:00
if (!tsmf_codec_check_media_type(ifman->decoder_name, ifman->input))
2011-09-19 18:54:09 +04:00
FormatSupported = 0;
2014-11-10 22:02:54 +03:00
if (FormatSupported)
DEBUG_TSMF("format ok.");
2014-11-10 22:02:54 +03:00
if (!Stream_EnsureRemainingCapacity(ifman->output, 12))
return -1;
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(ifman->output, FormatSupported);
Stream_Write_UINT32(ifman->output, PlatformCookie);
Stream_Write_UINT32(ifman->output, 0); /* Result */
2011-09-19 18:54:09 +04:00
ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
return CHANNEL_RC_OK;
2011-09-19 18:54:09 +04:00
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT tsmf_ifman_on_new_presentation(TSMF_IFMAN* ifman)
2011-09-19 18:54:09 +04:00
{
UINT status = CHANNEL_RC_OK;
2014-11-10 22:02:54 +03:00
TSMF_PRESENTATION* presentation;
DEBUG_TSMF("");
2014-11-10 22:02:54 +03:00
if (Stream_GetRemainingLength(ifman->input) < GUID_SIZE)
return ERROR_INVALID_DATA;
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
2014-11-10 22:02:54 +03:00
if (presentation)
{
DEBUG_TSMF("Presentation already exists");
ifman->output_pending = FALSE;
return CHANNEL_RC_OK;
}
2014-11-10 22:02:54 +03:00
presentation = tsmf_presentation_new(Stream_Pointer(ifman->input), ifman->channel_callback);
2014-11-10 22:02:54 +03:00
if (!presentation)
status = ERROR_OUTOFMEMORY;
else
tsmf_presentation_set_audio_device(presentation, ifman->audio_name, ifman->audio_device);
2014-11-10 22:02:54 +03:00
ifman->output_pending = TRUE;
return status;
2011-09-19 18:54:09 +04:00
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT tsmf_ifman_add_stream(TSMF_IFMAN* ifman, rdpContext* rdpcontext)
2011-09-19 18:54:09 +04:00
{
2012-10-09 11:26:39 +04:00
UINT32 StreamId;
UINT status = CHANNEL_RC_OK;
2014-11-10 22:02:54 +03:00
TSMF_STREAM* stream;
TSMF_PRESENTATION* presentation;
DEBUG_TSMF("");
2014-11-10 22:02:54 +03:00
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, GUID_SIZE);
2014-11-10 22:02:54 +03:00
if (!presentation)
{
WLog_ERR(TAG, "unknown presentation id");
status = ERROR_NOT_FOUND;
}
2011-09-19 18:54:09 +04:00
else
{
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(ifman->input, StreamId);
Stream_Seek_UINT32(ifman->input); /* numMediaType */
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);
2011-09-19 18:54:09 +04:00
}
ifman->output_pending = TRUE;
return status;
2011-09-19 18:54:09 +04:00
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT tsmf_ifman_set_topology_request(TSMF_IFMAN* ifman)
2011-09-19 18:54:09 +04:00
{
DEBUG_TSMF("");
if (!Stream_EnsureRemainingCapacity(ifman->output, 8))
return ERROR_OUTOFMEMORY;
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(ifman->output, 1); /* TopologyReady */
Stream_Write_UINT32(ifman->output, 0); /* Result */
2011-09-19 18:54:09 +04:00
ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
return CHANNEL_RC_OK;
2011-09-19 18:54:09 +04:00
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT tsmf_ifman_remove_stream(TSMF_IFMAN* ifman)
2011-09-19 18:54:09 +04:00
{
int status = CHANNEL_RC_OK;
2012-10-09 11:26:39 +04:00
UINT32 StreamId;
2014-11-10 22:02:54 +03:00
TSMF_STREAM* stream;
TSMF_PRESENTATION* presentation;
DEBUG_TSMF("");
2014-11-10 22:02:54 +03:00
if (Stream_GetRemainingLength(ifman->input) < 20)
return ERROR_INVALID_DATA;
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
Stream_Seek(ifman->input, GUID_SIZE);
2014-11-10 22:02:54 +03:00
if (!presentation)
{
status = ERROR_NOT_FOUND;
}
2011-09-19 18:54:09 +04:00
else
{
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(ifman->input, StreamId);
2011-09-19 18:54:09 +04:00
stream = tsmf_stream_find_by_id(presentation, StreamId);
2014-11-10 22:02:54 +03:00
if (stream)
2011-09-19 18:54:09 +04:00
tsmf_stream_free(stream);
else
status = ERROR_NOT_FOUND;
2011-09-19 18:54:09 +04:00
}
2014-11-10 22:02:54 +03:00
ifman->output_pending = TRUE;
return status;
2011-09-19 18:54:09 +04:00
}
float tsmf_stream_read_float(wStream* s)
{
float fValue;
UINT32 iValue;
Stream_Read_UINT32(s, iValue);
CopyMemory(&fValue, &iValue, 4);
return fValue;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT tsmf_ifman_set_source_video_rect(TSMF_IFMAN* ifman)
{
UINT status = CHANNEL_RC_OK;
float Left, Top;
float Right, Bottom;
2014-11-10 22:02:54 +03:00
TSMF_PRESENTATION* presentation;
DEBUG_TSMF("");
2014-11-10 22:02:54 +03:00
if (Stream_GetRemainingLength(ifman->input) < 32)
return ERROR_INVALID_DATA;
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
Stream_Seek(ifman->input, GUID_SIZE);
2014-11-10 22:02:54 +03:00
if (!presentation)
{
status = ERROR_NOT_FOUND;
}
else
{
Left = tsmf_stream_read_float(ifman->input); /* Left (4 bytes) */
Top = tsmf_stream_read_float(ifman->input); /* Top (4 bytes) */
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);
}
2014-11-10 22:02:54 +03:00
ifman->output_pending = TRUE;
return status;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT tsmf_ifman_shutdown_presentation(TSMF_IFMAN* ifman)
2011-09-19 18:54:09 +04:00
{
2014-11-10 22:02:54 +03:00
TSMF_PRESENTATION* presentation;
DEBUG_TSMF("");
2014-11-10 22:02:54 +03:00
if (Stream_GetRemainingLength(ifman->input) < GUID_SIZE)
return ERROR_INVALID_DATA;
2014-11-10 22:02:54 +03:00
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
2014-11-10 22:02:54 +03:00
if (presentation)
2011-09-19 18:54:09 +04:00
tsmf_presentation_free(presentation);
else
{
WLog_ERR(TAG, "unknown presentation id");
return ERROR_NOT_FOUND;
}
2014-11-10 22:02:54 +03:00
if (!Stream_EnsureRemainingCapacity(ifman->output, 4))
return ERROR_OUTOFMEMORY;
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(ifman->output, 0); /* Result */
2011-09-19 18:54:09 +04:00
ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
return CHANNEL_RC_OK;
2011-09-19 18:54:09 +04:00
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT tsmf_ifman_on_stream_volume(TSMF_IFMAN* ifman)
2011-09-19 18:54:09 +04:00
{
2014-11-10 22:02:54 +03:00
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));
2014-11-10 22:02:54 +03:00
if (!presentation)
{
WLog_ERR(TAG, "unknown presentation id");
return ERROR_NOT_FOUND;
}
2014-11-10 22:02:54 +03:00
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;
2011-09-19 18:54:09 +04:00
return 0;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT tsmf_ifman_on_channel_volume(TSMF_IFMAN* ifman)
2011-09-19 18:54:09 +04:00
{
2014-11-10 22:02:54 +03:00
TSMF_PRESENTATION* presentation;
DEBUG_TSMF("on channel volume");
2014-11-10 22:02:54 +03:00
if (Stream_GetRemainingLength(ifman->input) < GUID_SIZE + 8)
return ERROR_INVALID_DATA;
2014-11-10 22:02:54 +03:00
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
2014-11-10 22:02:54 +03:00
if (presentation)
{
2012-10-09 11:26:39 +04:00
UINT32 channelVolume;
UINT32 changedChannel;
Stream_Seek(ifman->input, 16);
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(ifman->input, channelVolume);
DEBUG_TSMF("on channel volume: channel volume=[%"PRIu32"]", channelVolume);
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(ifman->input, changedChannel);
DEBUG_TSMF("on stream volume: changed channel=[%"PRIu32"]", changedChannel);
}
2014-11-10 22:02:54 +03:00
ifman->output_pending = TRUE;
return CHANNEL_RC_OK;
2011-09-19 18:54:09 +04:00
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT tsmf_ifman_set_video_window(TSMF_IFMAN* ifman)
2011-09-19 18:54:09 +04:00
{
DEBUG_TSMF("");
ifman->output_pending = TRUE;
return CHANNEL_RC_OK;
2011-09-19 18:54:09 +04:00
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT tsmf_ifman_update_geometry_info(TSMF_IFMAN* ifman)
2011-09-19 18:54:09 +04:00
{
2014-11-10 22:02:54 +03:00
TSMF_PRESENTATION* presentation;
2012-10-09 11:26:39 +04:00
UINT32 numGeometryInfo;
UINT32 Left;
UINT32 Top;
UINT32 Width;
UINT32 Height;
UINT32 cbVisibleRect;
RDP_RECT* rects = NULL;
2011-09-19 18:54:09 +04:00
int num_rects = 0;
UINT error = CHANNEL_RC_OK;
2011-09-19 18:54:09 +04:00
int i;
size_t 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);
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(ifman->input, numGeometryInfo);
pos = Stream_GetPosition(ifman->input);
Stream_Seek(ifman->input, 12); /* VideoWindowId (8 bytes), VideoWindowState (4 bytes) */
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(ifman->input, Width);
Stream_Read_UINT32(ifman->input, Height);
Stream_Read_UINT32(ifman->input, Left);
Stream_Read_UINT32(ifman->input, Top);
Stream_SetPosition(ifman->input, pos + numGeometryInfo);
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(ifman->input, cbVisibleRect);
2011-09-19 18:54:09 +04:00
num_rects = cbVisibleRect / 16;
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);
if (num_rects > 0)
2011-09-19 18:54:09 +04:00
{
rects = (RDP_RECT*) calloc(num_rects, sizeof(RDP_RECT));
for (i = 0; i < num_rects; i++)
2011-09-19 18:54:09 +04:00
{
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);
2011-09-19 18:54:09 +04:00
}
}
2014-11-10 22:02:54 +03:00
if (!tsmf_presentation_set_geometry_info(presentation, Left, Top, Width, Height, num_rects, rects))
return ERROR_INVALID_OPERATION;
ifman->output_pending = TRUE;
2011-09-19 18:54:09 +04:00
return error;
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT tsmf_ifman_set_allocator(TSMF_IFMAN* ifman)
2011-09-19 18:54:09 +04:00
{
DEBUG_TSMF("");
ifman->output_pending = TRUE;
return CHANNEL_RC_OK;
2011-09-19 18:54:09 +04:00
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT tsmf_ifman_notify_preroll(TSMF_IFMAN* ifman)
2011-09-19 18:54:09 +04:00
{
DEBUG_TSMF("");
- Use decodebin2 instead of old decodebin - decodebin has issues - Use autovideosink - xvimagesink does not work with cards with no xv ports available and cant be used if wanted to use the fluendo hardware accelerated playback codec - Use autoaudiosink - let gstreamer choose best audio playback plugin - Catch when autosinks add known elements so that we can manipulate properties on them - Adjust caps of various media types to work better with gstreamer, some codecs are picky about having certain fields available - Remove unneeded plugins such as "ffmpegcolorspace" and "videoscale" - these do not work correctly with fluendo hardware accelerated playback codec - Name audio/video gstreamer elements better for easier debugging - Update gstreamer pipeline and element properties to handle playback better - Detect when valid timestamps are available for buffer from server and try to account for when they are not valid - Start time is much more reliable then end time from server for various media formats, so use it when possible to make decisions instead of end time - Do not rebuild gstreamer pipeline for a seek(very expensive), instead reset gstreamer time to 0 and maintain offset between real time and gstreamer time - Change buffer filled function back to a buffer level function, so that we can use buffer level to make better choices above gstreamer decoder in tsmf - Remove ack function from gstreamer, instead rely on ack thread to handle acks - Rework X11 gstreamer code to handle various videosinks which implement the XOverlayInterface and to keep more detailed information on the sub-window that is used for display - Add check to see if a decoder is available for telling the server the client various media types - Add in support for M4S2 and WMA1 media types - Fix flush message handling, they are for individual streams and not the entire presentation - Delay eos response to try to allow more time for buffers to be loaded into decoder, as we anticipate acks to server and the server will issue stop as soon as we ack eos. - Fix issue with geometry info being ignored when resent for new streams within existing presentation - Fixed volume level initialization issue when a stream is stopped and restarted - Attempt to sync video/audio streams...because we run two different gstreamer pipelines - they can enter pause/playing states at different times and are thus not synchronized. Attempt to adjust video buffer timestamps based on difference between audio/video running time to account for this difference. This logic accounts for a huge improvement in audio/video sync(ie. lip sync to words)
2015-07-08 00:39:29 +03:00
tsmf_ifman_on_playback_paused(ifman);
ifman->output_pending = TRUE;
return CHANNEL_RC_OK;
2011-09-19 18:54:09 +04:00
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT tsmf_ifman_on_sample(TSMF_IFMAN* ifman)
2011-09-19 18:54:09 +04:00
{
2014-11-10 22:02:54 +03:00
TSMF_PRESENTATION* presentation;
TSMF_STREAM* stream;
2012-10-09 11:26:39 +04:00
UINT32 StreamId;
UINT64 SampleStartTime;
UINT64 SampleEndTime;
UINT64 ThrottleDuration;
UINT32 SampleExtensions;
UINT32 cbData;
UINT error;
2014-11-10 22:02:54 +03:00
if (Stream_GetRemainingLength(ifman->input) < 60)
return ERROR_INVALID_DATA;
2014-11-10 22:02:54 +03:00
Stream_Seek(ifman->input, 16);
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(ifman->input, StreamId);
Stream_Seek_UINT32(ifman->input); /* numSample */
2013-05-09 00:09:16 +04:00
Stream_Read_UINT64(ifman->input, SampleStartTime);
Stream_Read_UINT64(ifman->input, SampleEndTime);
Stream_Read_UINT64(ifman->input, ThrottleDuration);
Stream_Seek_UINT32(ifman->input); /* SampleFlags */
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(ifman->input, SampleExtensions);
Stream_Read_UINT32(ifman->input, cbData);
2014-11-10 22:02:54 +03:00
if (Stream_GetRemainingLength(ifman->input) < cbData)
return ERROR_INVALID_DATA;
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);
2011-09-19 18:54:09 +04:00
presentation = tsmf_presentation_find_by_id(ifman->presentation_id);
2014-11-10 22:02:54 +03:00
if (!presentation)
2011-09-19 18:54:09 +04:00
{
WLog_ERR(TAG, "unknown presentation id");
return ERROR_NOT_FOUND;
2011-09-19 18:54:09 +04:00
}
2014-11-10 22:02:54 +03:00
2011-09-19 18:54:09 +04:00
stream = tsmf_stream_find_by_id(presentation, StreamId);
2014-11-10 22:02:54 +03:00
if (!stream)
2011-09-19 18:54:09 +04:00
{
WLog_ERR(TAG, "unknown stream id");
return ERROR_NOT_FOUND;
2011-09-19 18:54:09 +04:00
}
2014-11-10 22:02:54 +03:00
if (!tsmf_stream_push_sample(stream, ifman->channel_callback,
ifman->message_id, SampleStartTime, SampleEndTime,
ThrottleDuration, SampleExtensions, cbData, Stream_Pointer(ifman->input)))
{
WLog_ERR(TAG, "unable to push sample");
return ERROR_OUTOFMEMORY;
}
2014-11-10 22:02:54 +03:00
if ((error = tsmf_presentation_sync(presentation)))
{
WLog_ERR(TAG, "tsmf_presentation_sync failed with error %"PRIu32"", error);
return error;
}
2014-11-10 22:02:54 +03:00
ifman->output_pending = TRUE;
return CHANNEL_RC_OK;
2011-09-19 18:54:09 +04:00
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT tsmf_ifman_on_flush(TSMF_IFMAN* ifman)
2011-09-19 18:54:09 +04:00
{
2012-10-09 11:26:39 +04:00
UINT32 StreamId;
2014-11-10 22:02:54 +03:00
TSMF_PRESENTATION* presentation;
- Use decodebin2 instead of old decodebin - decodebin has issues - Use autovideosink - xvimagesink does not work with cards with no xv ports available and cant be used if wanted to use the fluendo hardware accelerated playback codec - Use autoaudiosink - let gstreamer choose best audio playback plugin - Catch when autosinks add known elements so that we can manipulate properties on them - Adjust caps of various media types to work better with gstreamer, some codecs are picky about having certain fields available - Remove unneeded plugins such as "ffmpegcolorspace" and "videoscale" - these do not work correctly with fluendo hardware accelerated playback codec - Name audio/video gstreamer elements better for easier debugging - Update gstreamer pipeline and element properties to handle playback better - Detect when valid timestamps are available for buffer from server and try to account for when they are not valid - Start time is much more reliable then end time from server for various media formats, so use it when possible to make decisions instead of end time - Do not rebuild gstreamer pipeline for a seek(very expensive), instead reset gstreamer time to 0 and maintain offset between real time and gstreamer time - Change buffer filled function back to a buffer level function, so that we can use buffer level to make better choices above gstreamer decoder in tsmf - Remove ack function from gstreamer, instead rely on ack thread to handle acks - Rework X11 gstreamer code to handle various videosinks which implement the XOverlayInterface and to keep more detailed information on the sub-window that is used for display - Add check to see if a decoder is available for telling the server the client various media types - Add in support for M4S2 and WMA1 media types - Fix flush message handling, they are for individual streams and not the entire presentation - Delay eos response to try to allow more time for buffers to be loaded into decoder, as we anticipate acks to server and the server will issue stop as soon as we ack eos. - Fix issue with geometry info being ignored when resent for new streams within existing presentation - Fixed volume level initialization issue when a stream is stopped and restarted - Attempt to sync video/audio streams...because we run two different gstreamer pipelines - they can enter pause/playing states at different times and are thus not synchronized. Attempt to adjust video buffer timestamps based on difference between audio/video running time to account for this difference. This logic accounts for a huge improvement in audio/video sync(ie. lip sync to words)
2015-07-08 00:39:29 +03:00
TSMF_STREAM* stream;
2014-11-10 22:02:54 +03:00
if (Stream_GetRemainingLength(ifman->input) < 20)
return ERROR_INVALID_DATA;
Stream_Seek(ifman->input, 16);
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(ifman->input, StreamId);
DEBUG_TSMF("StreamId %"PRIu32"", StreamId);
2011-09-19 18:54:09 +04:00
presentation = tsmf_presentation_find_by_id(ifman->presentation_id);
2014-11-10 22:02:54 +03:00
if (!presentation)
2011-09-19 18:54:09 +04:00
{
WLog_ERR(TAG, "unknown presentation id");
return ERROR_NOT_FOUND;
2011-09-19 18:54:09 +04:00
}
2014-11-10 22:02:54 +03:00
/* Flush message is for a stream, not the entire presentation
* therefore we only flush the stream as intended per the MS-RDPEV spec
*/
- Use decodebin2 instead of old decodebin - decodebin has issues - Use autovideosink - xvimagesink does not work with cards with no xv ports available and cant be used if wanted to use the fluendo hardware accelerated playback codec - Use autoaudiosink - let gstreamer choose best audio playback plugin - Catch when autosinks add known elements so that we can manipulate properties on them - Adjust caps of various media types to work better with gstreamer, some codecs are picky about having certain fields available - Remove unneeded plugins such as "ffmpegcolorspace" and "videoscale" - these do not work correctly with fluendo hardware accelerated playback codec - Name audio/video gstreamer elements better for easier debugging - Update gstreamer pipeline and element properties to handle playback better - Detect when valid timestamps are available for buffer from server and try to account for when they are not valid - Start time is much more reliable then end time from server for various media formats, so use it when possible to make decisions instead of end time - Do not rebuild gstreamer pipeline for a seek(very expensive), instead reset gstreamer time to 0 and maintain offset between real time and gstreamer time - Change buffer filled function back to a buffer level function, so that we can use buffer level to make better choices above gstreamer decoder in tsmf - Remove ack function from gstreamer, instead rely on ack thread to handle acks - Rework X11 gstreamer code to handle various videosinks which implement the XOverlayInterface and to keep more detailed information on the sub-window that is used for display - Add check to see if a decoder is available for telling the server the client various media types - Add in support for M4S2 and WMA1 media types - Fix flush message handling, they are for individual streams and not the entire presentation - Delay eos response to try to allow more time for buffers to be loaded into decoder, as we anticipate acks to server and the server will issue stop as soon as we ack eos. - Fix issue with geometry info being ignored when resent for new streams within existing presentation - Fixed volume level initialization issue when a stream is stopped and restarted - Attempt to sync video/audio streams...because we run two different gstreamer pipelines - they can enter pause/playing states at different times and are thus not synchronized. Attempt to adjust video buffer timestamps based on difference between audio/video running time to account for this difference. This logic accounts for a huge improvement in audio/video sync(ie. lip sync to words)
2015-07-08 00:39:29 +03:00
stream = tsmf_stream_find_by_id(presentation, StreamId);
2014-11-10 22:02:54 +03:00
- Use decodebin2 instead of old decodebin - decodebin has issues - Use autovideosink - xvimagesink does not work with cards with no xv ports available and cant be used if wanted to use the fluendo hardware accelerated playback codec - Use autoaudiosink - let gstreamer choose best audio playback plugin - Catch when autosinks add known elements so that we can manipulate properties on them - Adjust caps of various media types to work better with gstreamer, some codecs are picky about having certain fields available - Remove unneeded plugins such as "ffmpegcolorspace" and "videoscale" - these do not work correctly with fluendo hardware accelerated playback codec - Name audio/video gstreamer elements better for easier debugging - Update gstreamer pipeline and element properties to handle playback better - Detect when valid timestamps are available for buffer from server and try to account for when they are not valid - Start time is much more reliable then end time from server for various media formats, so use it when possible to make decisions instead of end time - Do not rebuild gstreamer pipeline for a seek(very expensive), instead reset gstreamer time to 0 and maintain offset between real time and gstreamer time - Change buffer filled function back to a buffer level function, so that we can use buffer level to make better choices above gstreamer decoder in tsmf - Remove ack function from gstreamer, instead rely on ack thread to handle acks - Rework X11 gstreamer code to handle various videosinks which implement the XOverlayInterface and to keep more detailed information on the sub-window that is used for display - Add check to see if a decoder is available for telling the server the client various media types - Add in support for M4S2 and WMA1 media types - Fix flush message handling, they are for individual streams and not the entire presentation - Delay eos response to try to allow more time for buffers to be loaded into decoder, as we anticipate acks to server and the server will issue stop as soon as we ack eos. - Fix issue with geometry info being ignored when resent for new streams within existing presentation - Fixed volume level initialization issue when a stream is stopped and restarted - Attempt to sync video/audio streams...because we run two different gstreamer pipelines - they can enter pause/playing states at different times and are thus not synchronized. Attempt to adjust video buffer timestamps based on difference between audio/video running time to account for this difference. This logic accounts for a huge improvement in audio/video sync(ie. lip sync to words)
2015-07-08 00:39:29 +03:00
if (stream)
{
- Use decodebin2 instead of old decodebin - decodebin has issues - Use autovideosink - xvimagesink does not work with cards with no xv ports available and cant be used if wanted to use the fluendo hardware accelerated playback codec - Use autoaudiosink - let gstreamer choose best audio playback plugin - Catch when autosinks add known elements so that we can manipulate properties on them - Adjust caps of various media types to work better with gstreamer, some codecs are picky about having certain fields available - Remove unneeded plugins such as "ffmpegcolorspace" and "videoscale" - these do not work correctly with fluendo hardware accelerated playback codec - Name audio/video gstreamer elements better for easier debugging - Update gstreamer pipeline and element properties to handle playback better - Detect when valid timestamps are available for buffer from server and try to account for when they are not valid - Start time is much more reliable then end time from server for various media formats, so use it when possible to make decisions instead of end time - Do not rebuild gstreamer pipeline for a seek(very expensive), instead reset gstreamer time to 0 and maintain offset between real time and gstreamer time - Change buffer filled function back to a buffer level function, so that we can use buffer level to make better choices above gstreamer decoder in tsmf - Remove ack function from gstreamer, instead rely on ack thread to handle acks - Rework X11 gstreamer code to handle various videosinks which implement the XOverlayInterface and to keep more detailed information on the sub-window that is used for display - Add check to see if a decoder is available for telling the server the client various media types - Add in support for M4S2 and WMA1 media types - Fix flush message handling, they are for individual streams and not the entire presentation - Delay eos response to try to allow more time for buffers to be loaded into decoder, as we anticipate acks to server and the server will issue stop as soon as we ack eos. - Fix issue with geometry info being ignored when resent for new streams within existing presentation - Fixed volume level initialization issue when a stream is stopped and restarted - Attempt to sync video/audio streams...because we run two different gstreamer pipelines - they can enter pause/playing states at different times and are thus not synchronized. Attempt to adjust video buffer timestamps based on difference between audio/video running time to account for this difference. This logic accounts for a huge improvement in audio/video sync(ie. lip sync to words)
2015-07-08 00:39:29 +03:00
if (!tsmf_stream_flush(stream))
return ERROR_INVALID_OPERATION;
}
- Use decodebin2 instead of old decodebin - decodebin has issues - Use autovideosink - xvimagesink does not work with cards with no xv ports available and cant be used if wanted to use the fluendo hardware accelerated playback codec - Use autoaudiosink - let gstreamer choose best audio playback plugin - Catch when autosinks add known elements so that we can manipulate properties on them - Adjust caps of various media types to work better with gstreamer, some codecs are picky about having certain fields available - Remove unneeded plugins such as "ffmpegcolorspace" and "videoscale" - these do not work correctly with fluendo hardware accelerated playback codec - Name audio/video gstreamer elements better for easier debugging - Update gstreamer pipeline and element properties to handle playback better - Detect when valid timestamps are available for buffer from server and try to account for when they are not valid - Start time is much more reliable then end time from server for various media formats, so use it when possible to make decisions instead of end time - Do not rebuild gstreamer pipeline for a seek(very expensive), instead reset gstreamer time to 0 and maintain offset between real time and gstreamer time - Change buffer filled function back to a buffer level function, so that we can use buffer level to make better choices above gstreamer decoder in tsmf - Remove ack function from gstreamer, instead rely on ack thread to handle acks - Rework X11 gstreamer code to handle various videosinks which implement the XOverlayInterface and to keep more detailed information on the sub-window that is used for display - Add check to see if a decoder is available for telling the server the client various media types - Add in support for M4S2 and WMA1 media types - Fix flush message handling, they are for individual streams and not the entire presentation - Delay eos response to try to allow more time for buffers to be loaded into decoder, as we anticipate acks to server and the server will issue stop as soon as we ack eos. - Fix issue with geometry info being ignored when resent for new streams within existing presentation - Fixed volume level initialization issue when a stream is stopped and restarted - Attempt to sync video/audio streams...because we run two different gstreamer pipelines - they can enter pause/playing states at different times and are thus not synchronized. Attempt to adjust video buffer timestamps based on difference between audio/video running time to account for this difference. This logic accounts for a huge improvement in audio/video sync(ie. lip sync to words)
2015-07-08 00:39:29 +03:00
else
WLog_ERR(TAG, "unknown stream id");
ifman->output_pending = TRUE;
return CHANNEL_RC_OK;
2011-09-19 18:54:09 +04:00
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT tsmf_ifman_on_end_of_stream(TSMF_IFMAN* ifman)
2011-09-19 18:54:09 +04:00
{
2012-10-09 11:26:39 +04:00
UINT32 StreamId;
- Use decodebin2 instead of old decodebin - decodebin has issues - Use autovideosink - xvimagesink does not work with cards with no xv ports available and cant be used if wanted to use the fluendo hardware accelerated playback codec - Use autoaudiosink - let gstreamer choose best audio playback plugin - Catch when autosinks add known elements so that we can manipulate properties on them - Adjust caps of various media types to work better with gstreamer, some codecs are picky about having certain fields available - Remove unneeded plugins such as "ffmpegcolorspace" and "videoscale" - these do not work correctly with fluendo hardware accelerated playback codec - Name audio/video gstreamer elements better for easier debugging - Update gstreamer pipeline and element properties to handle playback better - Detect when valid timestamps are available for buffer from server and try to account for when they are not valid - Start time is much more reliable then end time from server for various media formats, so use it when possible to make decisions instead of end time - Do not rebuild gstreamer pipeline for a seek(very expensive), instead reset gstreamer time to 0 and maintain offset between real time and gstreamer time - Change buffer filled function back to a buffer level function, so that we can use buffer level to make better choices above gstreamer decoder in tsmf - Remove ack function from gstreamer, instead rely on ack thread to handle acks - Rework X11 gstreamer code to handle various videosinks which implement the XOverlayInterface and to keep more detailed information on the sub-window that is used for display - Add check to see if a decoder is available for telling the server the client various media types - Add in support for M4S2 and WMA1 media types - Fix flush message handling, they are for individual streams and not the entire presentation - Delay eos response to try to allow more time for buffers to be loaded into decoder, as we anticipate acks to server and the server will issue stop as soon as we ack eos. - Fix issue with geometry info being ignored when resent for new streams within existing presentation - Fixed volume level initialization issue when a stream is stopped and restarted - Attempt to sync video/audio streams...because we run two different gstreamer pipelines - they can enter pause/playing states at different times and are thus not synchronized. Attempt to adjust video buffer timestamps based on difference between audio/video running time to account for this difference. This logic accounts for a huge improvement in audio/video sync(ie. lip sync to words)
2015-07-08 00:39:29 +03:00
TSMF_STREAM* stream = NULL;
2014-11-10 22:02:54 +03:00
TSMF_PRESENTATION* presentation;
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);
2013-05-09 00:09:16 +04:00
Stream_Read_UINT32(ifman->input, StreamId);
2014-11-10 22:02:54 +03:00
if (presentation)
{
stream = tsmf_stream_find_by_id(presentation, StreamId);
2014-11-10 22:02:54 +03:00
if (stream)
tsmf_stream_end(stream, ifman->message_id, ifman->channel_callback);
}
2014-11-10 22:02:54 +03:00
DEBUG_TSMF("StreamId %"PRIu32"", StreamId);
- Use decodebin2 instead of old decodebin - decodebin has issues - Use autovideosink - xvimagesink does not work with cards with no xv ports available and cant be used if wanted to use the fluendo hardware accelerated playback codec - Use autoaudiosink - let gstreamer choose best audio playback plugin - Catch when autosinks add known elements so that we can manipulate properties on them - Adjust caps of various media types to work better with gstreamer, some codecs are picky about having certain fields available - Remove unneeded plugins such as "ffmpegcolorspace" and "videoscale" - these do not work correctly with fluendo hardware accelerated playback codec - Name audio/video gstreamer elements better for easier debugging - Update gstreamer pipeline and element properties to handle playback better - Detect when valid timestamps are available for buffer from server and try to account for when they are not valid - Start time is much more reliable then end time from server for various media formats, so use it when possible to make decisions instead of end time - Do not rebuild gstreamer pipeline for a seek(very expensive), instead reset gstreamer time to 0 and maintain offset between real time and gstreamer time - Change buffer filled function back to a buffer level function, so that we can use buffer level to make better choices above gstreamer decoder in tsmf - Remove ack function from gstreamer, instead rely on ack thread to handle acks - Rework X11 gstreamer code to handle various videosinks which implement the XOverlayInterface and to keep more detailed information on the sub-window that is used for display - Add check to see if a decoder is available for telling the server the client various media types - Add in support for M4S2 and WMA1 media types - Fix flush message handling, they are for individual streams and not the entire presentation - Delay eos response to try to allow more time for buffers to be loaded into decoder, as we anticipate acks to server and the server will issue stop as soon as we ack eos. - Fix issue with geometry info being ignored when resent for new streams within existing presentation - Fixed volume level initialization issue when a stream is stopped and restarted - Attempt to sync video/audio streams...because we run two different gstreamer pipelines - they can enter pause/playing states at different times and are thus not synchronized. Attempt to adjust video buffer timestamps based on difference between audio/video running time to account for this difference. This logic accounts for a huge improvement in audio/video sync(ie. lip sync to words)
2015-07-08 00:39:29 +03:00
ifman->output_pending = TRUE;
ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
return CHANNEL_RC_OK;
2011-09-19 18:54:09 +04:00
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT tsmf_ifman_on_playback_started(TSMF_IFMAN* ifman)
2011-09-19 18:54:09 +04:00
{
2014-11-10 22:02:54 +03:00
TSMF_PRESENTATION* presentation;
DEBUG_TSMF("");
2014-11-10 22:02:54 +03:00
if (Stream_GetRemainingLength(ifman->input) < 16)
return ERROR_INVALID_DATA;
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
2014-11-10 22:02:54 +03:00
if (presentation)
2011-09-19 18:54:09 +04:00
tsmf_presentation_start(presentation);
else
WLog_ERR(TAG, "unknown presentation id");
2014-11-10 22:02:54 +03:00
if (!Stream_EnsureRemainingCapacity(ifman->output, 16))
return ERROR_OUTOFMEMORY;
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */
Stream_Write_UINT32(ifman->output, 0); /* StreamId */
Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_START_COMPLETED); /* EventId */
Stream_Write_UINT32(ifman->output, 0); /* cbData */
2011-09-19 18:54:09 +04:00
ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
return CHANNEL_RC_OK;
2011-09-19 18:54:09 +04:00
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT tsmf_ifman_on_playback_paused(TSMF_IFMAN* ifman)
2011-09-19 18:54:09 +04:00
{
2014-11-10 22:02:54 +03:00
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));
2014-11-10 22:02:54 +03:00
if (presentation)
{
if (!tsmf_presentation_paused(presentation))
return ERROR_INVALID_OPERATION;
}
else
WLog_ERR(TAG, "unknown presentation id");
2014-11-10 22:02:54 +03:00
return CHANNEL_RC_OK;
2011-09-19 18:54:09 +04:00
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT tsmf_ifman_on_playback_restarted(TSMF_IFMAN* ifman)
2011-09-19 18:54:09 +04:00
{
2014-11-10 22:02:54 +03:00
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));
2014-11-10 22:02:54 +03:00
if (presentation)
{
if (!tsmf_presentation_restarted(presentation))
return ERROR_INVALID_OPERATION;
}
else
WLog_ERR(TAG, "unknown presentation id");
2014-11-10 22:02:54 +03:00
return CHANNEL_RC_OK;
2011-09-19 18:54:09 +04:00
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT tsmf_ifman_on_playback_stopped(TSMF_IFMAN* ifman)
2011-09-19 18:54:09 +04:00
{
2014-11-10 22:02:54 +03:00
TSMF_PRESENTATION* presentation;
DEBUG_TSMF("");
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
2014-11-10 22:02:54 +03:00
if (presentation)
{
if (!tsmf_presentation_stop(presentation))
return ERROR_INVALID_OPERATION;
}
2011-09-19 18:54:09 +04:00
else
WLog_ERR(TAG, "unknown presentation id");
2014-11-10 22:02:54 +03:00
if (!Stream_EnsureRemainingCapacity(ifman->output, 16))
return ERROR_OUTOFMEMORY;
2013-05-09 00:09:16 +04:00
Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */
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 CHANNEL_RC_OK;
2011-09-19 18:54:09 +04:00
}
/**
* Function description
*
* @return 0 on success, otherwise a Win32 error code
*/
UINT tsmf_ifman_on_playback_rate_changed(TSMF_IFMAN* ifman)
2011-09-19 18:54:09 +04:00
{
DEBUG_TSMF("");
if (!Stream_EnsureRemainingCapacity(ifman->output, 16))
return ERROR_OUTOFMEMORY;
2013-05-09 00:09:16 +04:00
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 */
Stream_Write_UINT32(ifman->output, 0); /* cbData */
2011-09-19 18:54:09 +04:00
ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
return CHANNEL_RC_OK;
2011-09-19 18:54:09 +04:00
}