Merge pull request #3707 from akallabeth/AMV007-patch-2

Rebased #2541
This commit is contained in:
Bernhard Miklautz 2017-01-18 13:45:34 +01:00 committed by GitHub
commit 497db0d53e
3 changed files with 102 additions and 82 deletions

View File

@ -50,15 +50,15 @@ UINT tsmf_ifman_rim_exchange_capability_request(TSMF_IFMAN* ifman)
if (Stream_GetRemainingLength(ifman->input) < 4)
return ERROR_INVALID_DATA;
Stream_Read_UINT32(ifman->input, CapabilityValue);
Stream_Read_UINT32(ifman->input, CapabilityValue);
DEBUG_TSMF("server CapabilityValue %"PRIu32"", CapabilityValue);
if (!Stream_EnsureRemainingCapacity(ifman->output, 8))
return ERROR_INVALID_DATA;
Stream_Write_UINT32(ifman->output, 1); /* CapabilityValue */
Stream_Write_UINT32(ifman->output, 0); /* Result */
return CHANNEL_RC_OK;
}
@ -78,12 +78,14 @@ UINT tsmf_ifman_exchange_capability_request(TSMF_IFMAN* ifman)
if (!Stream_EnsureRemainingCapacity(ifman->output, ifman->input_size + 4))
return ERROR_OUTOFMEMORY;
pos = Stream_GetPosition(ifman->output);
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++)
@ -108,6 +110,7 @@ UINT tsmf_ifman_exchange_capability_request(TSMF_IFMAN* ifman)
Stream_Read_UINT32(ifman->output, v);
DEBUG_TSMF("server protocol version %"PRIu32"", v);
break;
case 2: /* Supported platform */
if (Stream_GetRemainingLength(ifman->output) < 4)
return ERROR_INVALID_DATA;
@ -115,18 +118,20 @@ UINT tsmf_ifman_exchange_capability_request(TSMF_IFMAN* ifman)
Stream_Peek_UINT32(ifman->output, 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, "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 CHANNEL_RC_OK;
}
@ -147,7 +152,6 @@ UINT tsmf_ifman_check_format_support_request(TSMF_IFMAN* ifman)
Stream_Read_UINT32(ifman->input, PlatformCookie);
Stream_Seek_UINT32(ifman->input); /* NoRolloverFlags (4 bytes) */
Stream_Read_UINT32(ifman->input, numMediaType);
DEBUG_TSMF("PlatformCookie %"PRIu32" numMediaType %"PRIu32"", PlatformCookie, numMediaType);
if (!tsmf_codec_check_media_type(ifman->decoder_name, ifman->input))
@ -158,11 +162,11 @@ UINT tsmf_ifman_check_format_support_request(TSMF_IFMAN* ifman)
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 CHANNEL_RC_OK;
}
@ -175,7 +179,6 @@ UINT tsmf_ifman_on_new_presentation(TSMF_IFMAN* ifman)
{
UINT status = CHANNEL_RC_OK;
TSMF_PRESENTATION* presentation;
DEBUG_TSMF("");
if (Stream_GetRemainingLength(ifman->input) < GUID_SIZE)
@ -198,7 +201,6 @@ UINT tsmf_ifman_on_new_presentation(TSMF_IFMAN* ifman)
tsmf_presentation_set_audio_device(presentation, ifman->audio_name, ifman->audio_device);
ifman->output_pending = TRUE;
return status;
}
@ -213,7 +215,6 @@ UINT tsmf_ifman_add_stream(TSMF_IFMAN* ifman, rdpContext* rdpcontext)
UINT status = CHANNEL_RC_OK;
TSMF_STREAM* stream;
TSMF_PRESENTATION* presentation;
DEBUG_TSMF("");
if (Stream_GetRemainingLength(ifman->input) < GUID_SIZE + 8)
@ -232,6 +233,7 @@ UINT tsmf_ifman_add_stream(TSMF_IFMAN* ifman, rdpContext* rdpcontext)
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");
@ -243,6 +245,8 @@ UINT tsmf_ifman_add_stream(TSMF_IFMAN* ifman, rdpContext* rdpcontext)
WLog_ERR(TAG, "failed to set stream format");
return ERROR_OUTOFMEMORY;
}
tsmf_stream_start_threads(stream);
}
ifman->output_pending = TRUE;
@ -257,6 +261,7 @@ UINT tsmf_ifman_add_stream(TSMF_IFMAN* ifman, rdpContext* rdpcontext)
UINT tsmf_ifman_set_topology_request(TSMF_IFMAN* ifman)
{
DEBUG_TSMF("");
if (!Stream_EnsureRemainingCapacity(ifman->output, 8))
return ERROR_OUTOFMEMORY;
@ -277,14 +282,12 @@ UINT tsmf_ifman_remove_stream(TSMF_IFMAN* ifman)
UINT32 StreamId;
TSMF_STREAM* stream;
TSMF_PRESENTATION* presentation;
DEBUG_TSMF("");
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);
if (!presentation)
@ -303,11 +306,10 @@ UINT tsmf_ifman_remove_stream(TSMF_IFMAN* ifman)
}
ifman->output_pending = TRUE;
return status;
}
float tsmf_stream_read_float(wStream *s)
float tsmf_stream_read_float(wStream* s)
{
float fValue;
UINT32 iValue;
@ -327,14 +329,12 @@ UINT tsmf_ifman_set_source_video_rect(TSMF_IFMAN* ifman)
float Left, Top;
float Right, Bottom;
TSMF_PRESENTATION* presentation;
DEBUG_TSMF("");
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);
if (!presentation)
@ -348,11 +348,10 @@ UINT tsmf_ifman_set_source_video_rect(TSMF_IFMAN* ifman)
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;
}
@ -364,13 +363,13 @@ UINT tsmf_ifman_set_source_video_rect(TSMF_IFMAN* ifman)
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
@ -384,7 +383,6 @@ UINT tsmf_ifman_shutdown_presentation(TSMF_IFMAN* ifman)
Stream_Write_UINT32(ifman->output, 0); /* Result */
ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
return CHANNEL_RC_OK;
}
@ -398,7 +396,6 @@ 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)
@ -422,7 +419,6 @@ UINT tsmf_ifman_on_stream_volume(TSMF_IFMAN* ifman)
return ERROR_INVALID_OPERATION;
ifman->output_pending = TRUE;
return 0;
}
@ -434,13 +430,13 @@ UINT tsmf_ifman_on_stream_volume(TSMF_IFMAN* ifman)
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;
@ -453,7 +449,6 @@ UINT tsmf_ifman_on_channel_volume(TSMF_IFMAN* ifman)
}
ifman->output_pending = TRUE;
return CHANNEL_RC_OK;
}
@ -483,7 +478,7 @@ UINT tsmf_ifman_update_geometry_info(TSMF_IFMAN* ifman)
UINT32 Width;
UINT32 Height;
UINT32 cbVisibleRect;
RDP_RECT *rects = NULL;
RDP_RECT* rects = NULL;
int num_rects = 0;
UINT error = CHANNEL_RC_OK;
int i;
@ -493,6 +488,7 @@ UINT tsmf_ifman_update_geometry_info(TSMF_IFMAN* ifman)
return ERROR_INVALID_DATA;
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
if (!presentation)
return ERROR_NOT_FOUND;
@ -504,12 +500,11 @@ UINT tsmf_ifman_update_geometry_info(TSMF_IFMAN* ifman)
Stream_Read_UINT32(ifman->input, Height);
Stream_Read_UINT32(ifman->input, Left);
Stream_Read_UINT32(ifman->input, Top);
Stream_SetPosition(ifman->input, pos + numGeometryInfo);
Stream_Read_UINT32(ifman->input, cbVisibleRect);
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);
numGeometryInfo, Width, Height, Left, Top, cbVisibleRect, num_rects);
if (num_rects > 0)
{
@ -528,7 +523,7 @@ UINT tsmf_ifman_update_geometry_info(TSMF_IFMAN* ifman)
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);
}
}
@ -536,7 +531,6 @@ UINT tsmf_ifman_update_geometry_info(TSMF_IFMAN* ifman)
return ERROR_INVALID_OPERATION;
ifman->output_pending = TRUE;
return error;
}
@ -584,6 +578,7 @@ UINT tsmf_ifman_on_sample(TSMF_IFMAN* ifman)
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 */
@ -598,10 +593,9 @@ UINT tsmf_ifman_on_sample(TSMF_IFMAN* ifman)
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);
"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)
@ -619,20 +613,20 @@ UINT tsmf_ifman_on_sample(TSMF_IFMAN* ifman)
}
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;
}
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;
}
ifman->output_pending = TRUE;
return CHANNEL_RC_OK;
}
@ -652,10 +646,9 @@ UINT tsmf_ifman_on_flush(TSMF_IFMAN* ifman)
Stream_Seek(ifman->input, 16);
Stream_Read_UINT32(ifman->input, StreamId);
DEBUG_TSMF("StreamId %"PRIu32"", StreamId);
presentation = tsmf_presentation_find_by_id(ifman->presentation_id);
if (!presentation)
{
WLog_ERR(TAG, "unknown presentation id");
@ -666,6 +659,7 @@ UINT tsmf_ifman_on_flush(TSMF_IFMAN* ifman)
* therefore we only flush the stream as intended per the MS-RDPEV spec
*/
stream = tsmf_stream_find_by_id(presentation, StreamId);
if (stream)
{
if (!tsmf_stream_flush(stream))
@ -675,7 +669,6 @@ UINT tsmf_ifman_on_flush(TSMF_IFMAN* ifman)
WLog_ERR(TAG, "unknown stream id");
ifman->output_pending = TRUE;
return CHANNEL_RC_OK;
}
@ -694,7 +687,6 @@ UINT tsmf_ifman_on_end_of_stream(TSMF_IFMAN* ifman)
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);
@ -703,13 +695,11 @@ UINT tsmf_ifman_on_end_of_stream(TSMF_IFMAN* ifman)
stream = tsmf_stream_find_by_id(presentation, StreamId);
if (stream)
tsmf_stream_end(stream, ifman->message_id, ifman->channel_callback);
tsmf_stream_end(stream, ifman->message_id, ifman->channel_callback);
}
DEBUG_TSMF("StreamId %"PRIu32"", StreamId);
ifman->output_pending = TRUE;
ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
return CHANNEL_RC_OK;
}
@ -722,7 +712,6 @@ UINT tsmf_ifman_on_end_of_stream(TSMF_IFMAN* ifman)
UINT tsmf_ifman_on_playback_started(TSMF_IFMAN* ifman)
{
TSMF_PRESENTATION* presentation;
DEBUG_TSMF("");
if (Stream_GetRemainingLength(ifman->input) < 16)
@ -743,7 +732,6 @@ UINT tsmf_ifman_on_playback_started(TSMF_IFMAN* ifman)
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 CHANNEL_RC_OK;
}
@ -755,10 +743,8 @@ UINT tsmf_ifman_on_playback_started(TSMF_IFMAN* ifman)
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));
@ -781,12 +767,11 @@ UINT tsmf_ifman_on_playback_paused(TSMF_IFMAN* ifman)
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)
{
if (!tsmf_presentation_restarted(presentation))
@ -806,10 +791,9 @@ UINT tsmf_ifman_on_playback_restarted(TSMF_IFMAN* ifman)
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)
{
if (!tsmf_presentation_stop(presentation))
@ -825,7 +809,6 @@ UINT tsmf_ifman_on_playback_stopped(TSMF_IFMAN* ifman)
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;
}

View File

@ -455,6 +455,26 @@ static BOOL tsmf_sample_playback_video(TSMF_SAMPLE* sample)
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 FALSE;
}
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. */
@ -486,6 +506,9 @@ static BOOL tsmf_sample_playback_video(TSMF_SAMPLE* sample)
tsmf->FrameEvent(tsmf, &event);
free(event.frameData);
if (event.visibleRects != NULL)
free(event.visibleRects);
}
return TRUE;
@ -718,7 +741,6 @@ static void* tsmf_stream_ack_func(void* arg)
TSMF_STREAM* stream = (TSMF_STREAM*) arg;
UINT error = CHANNEL_RC_OK;
DEBUG_TSMF("in %"PRIu32"", stream->stream_id);
hdl[0] = stream->stopEvent;
hdl[1] = Queue_Event(stream->sample_ack_list);
@ -1109,6 +1131,10 @@ BOOL tsmf_presentation_set_geometry_info(TSMF_PRESENTATION* presentation,
presentation->width = width;
presentation->height = height;
tmp_rects = realloc(presentation->rects, sizeof(RDP_RECT) * num_rects);
if (!tmp_rects && num_rects)
return FALSE;
presentation->nr_rects = num_rects;
presentation->rects = tmp_rects;
CopyMemory(presentation->rects, rects, sizeof(RDP_RECT) * num_rects);
@ -1231,14 +1257,14 @@ TSMF_STREAM* tsmf_stream_new(TSMF_PRESENTATION* presentation, UINT32 stream_id,
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);
if (!stream->ack_thread)
goto error_ack_thread;
@ -1273,6 +1299,12 @@ error_stopEvent:
return NULL;
}
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)
{

View File

@ -36,33 +36,38 @@ typedef struct _TSMF_STREAM TSMF_STREAM;
typedef struct _TSMF_SAMPLE TSMF_SAMPLE;
TSMF_PRESENTATION *tsmf_presentation_new(const BYTE *guid, IWTSVirtualChannelCallback *pChannelCallback);
TSMF_PRESENTATION *tsmf_presentation_find_by_id(const BYTE *guid);
BOOL tsmf_presentation_start(TSMF_PRESENTATION *presentation);
BOOL tsmf_presentation_stop(TSMF_PRESENTATION *presentation);
UINT tsmf_presentation_sync(TSMF_PRESENTATION *presentation);
BOOL tsmf_presentation_paused(TSMF_PRESENTATION *presentation);
BOOL tsmf_presentation_restarted(TSMF_PRESENTATION *presentation);
BOOL tsmf_presentation_volume_changed(TSMF_PRESENTATION *presentation, UINT32 newVolume, UINT32 muted);
BOOL tsmf_presentation_set_geometry_info(TSMF_PRESENTATION *presentation,
UINT32 x, UINT32 y, UINT32 width, UINT32 height,
int num_rects, RDP_RECT *rects);
void tsmf_presentation_set_audio_device(TSMF_PRESENTATION *presentation,
const char *name, const char *device);
void tsmf_presentation_free(TSMF_PRESENTATION *presentation);
TSMF_PRESENTATION* tsmf_presentation_new(const BYTE* guid,
IWTSVirtualChannelCallback* pChannelCallback);
TSMF_PRESENTATION* tsmf_presentation_find_by_id(const BYTE* guid);
BOOL tsmf_presentation_start(TSMF_PRESENTATION* presentation);
BOOL tsmf_presentation_stop(TSMF_PRESENTATION* presentation);
UINT tsmf_presentation_sync(TSMF_PRESENTATION* presentation);
BOOL tsmf_presentation_paused(TSMF_PRESENTATION* presentation);
BOOL tsmf_presentation_restarted(TSMF_PRESENTATION* presentation);
BOOL tsmf_presentation_volume_changed(TSMF_PRESENTATION* presentation, UINT32 newVolume,
UINT32 muted);
BOOL tsmf_presentation_set_geometry_info(TSMF_PRESENTATION* presentation,
UINT32 x, UINT32 y, UINT32 width, UINT32 height,
int num_rects, RDP_RECT* rects);
void tsmf_presentation_set_audio_device(TSMF_PRESENTATION* presentation,
const char* name, const char* device);
void tsmf_presentation_free(TSMF_PRESENTATION* presentation);
TSMF_STREAM *tsmf_stream_new(TSMF_PRESENTATION *presentation, UINT32 stream_id, rdpContext* rdpcontext);
TSMF_STREAM *tsmf_stream_find_by_id(TSMF_PRESENTATION *presentation, UINT32 stream_id);
BOOL tsmf_stream_set_format(TSMF_STREAM *stream, const char *name, wStream *s);
void tsmf_stream_end(TSMF_STREAM *stream, UINT32 message_id, IWTSVirtualChannelCallback* pChannelCallback);
void tsmf_stream_free(TSMF_STREAM *stream);
TSMF_STREAM* tsmf_stream_new(TSMF_PRESENTATION* presentation, UINT32 stream_id,
rdpContext* rdpcontext);
TSMF_STREAM* tsmf_stream_find_by_id(TSMF_PRESENTATION* presentation, UINT32 stream_id);
BOOL tsmf_stream_set_format(TSMF_STREAM* stream, const char* name, wStream* s);
void tsmf_stream_end(TSMF_STREAM* stream, UINT32 message_id,
IWTSVirtualChannelCallback* pChannelCallback);
void tsmf_stream_free(TSMF_STREAM* stream);
BOOL tsmf_stream_flush(TSMF_STREAM* stream);
BOOL tsmf_stream_push_sample(TSMF_STREAM *stream, IWTSVirtualChannelCallback *pChannelCallback,
UINT32 sample_id, UINT64 start_time, UINT64 end_time, UINT64 duration, UINT32 extensions,
UINT32 data_size, BYTE *data);
BOOL tsmf_stream_push_sample(TSMF_STREAM* stream, IWTSVirtualChannelCallback* pChannelCallback,
UINT32 sample_id, UINT64 start_time, UINT64 end_time, UINT64 duration, UINT32 extensions,
UINT32 data_size, BYTE* data);
BOOL tsmf_media_init(void);
void tsmf_stream_start_threads(TSMF_STREAM* stream);
#endif