diff --git a/channels/tsmf/client/tsmf_ifman.c b/channels/tsmf/client/tsmf_ifman.c index f0f38516c..5af0e7b10 100644 --- a/channels/tsmf/client/tsmf_ifman.c +++ b/channels/tsmf/client/tsmf_ifman.c @@ -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; } diff --git a/channels/tsmf/client/tsmf_media.c b/channels/tsmf/client/tsmf_media.c index 4e5483e5d..9b93cace2 100644 --- a/channels/tsmf/client/tsmf_media.c +++ b/channels/tsmf/client/tsmf_media.c @@ -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) { diff --git a/channels/tsmf/client/tsmf_media.h b/channels/tsmf/client/tsmf_media.h index 1760fe05a..3a08b1c6a 100644 --- a/channels/tsmf/client/tsmf_media.h +++ b/channels/tsmf/client/tsmf_media.h @@ -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