diff --git a/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c b/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c index 657ac29c7..f047693e1 100644 --- a/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c +++ b/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c @@ -28,7 +28,6 @@ #include #include -#include #include #include @@ -83,11 +82,11 @@ typedef struct _TSMFFFmpegDecoder UINT32 decoded_size_max; } TSMFFFmpegDecoder; -static BOOL tsmf_ffmpeg_init_context(ITSMFDecoder *decoder) +static BOOL tsmf_ffmpeg_init_context(ITSMFDecoder* decoder) { - TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder; + TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder; mdecoder->codec_context = avcodec_alloc_context3(NULL); - if(!mdecoder->codec_context) + if (!mdecoder->codec_context) { WLog_ERR(TAG, "avcodec_alloc_context failed."); return FALSE; @@ -95,9 +94,9 @@ static BOOL tsmf_ffmpeg_init_context(ITSMFDecoder *decoder) return TRUE; } -static BOOL tsmf_ffmpeg_init_video_stream(ITSMFDecoder *decoder, const TS_AM_MEDIA_TYPE *media_type) +static BOOL tsmf_ffmpeg_init_video_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYPE *media_type) { - TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder; + TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder; mdecoder->codec_context->width = media_type->Width; mdecoder->codec_context->height = media_type->Height; mdecoder->codec_context->bit_rate = media_type->BitRate; @@ -107,9 +106,9 @@ static BOOL tsmf_ffmpeg_init_video_stream(ITSMFDecoder *decoder, const TS_AM_MED return TRUE; } -static BOOL tsmf_ffmpeg_init_audio_stream(ITSMFDecoder *decoder, const TS_AM_MEDIA_TYPE *media_type) +static BOOL tsmf_ffmpeg_init_audio_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYPE *media_type) { - TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder; + TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder; mdecoder->codec_context->sample_rate = media_type->SamplesPerSecond.Numerator; mdecoder->codec_context->bit_rate = media_type->BitRate; mdecoder->codec_context->channels = media_type->Channels; @@ -134,34 +133,34 @@ static BOOL tsmf_ffmpeg_init_audio_stream(ITSMFDecoder *decoder, const TS_AM_MED return TRUE; } -static BOOL tsmf_ffmpeg_init_stream(ITSMFDecoder *decoder, const TS_AM_MEDIA_TYPE *media_type) +static BOOL tsmf_ffmpeg_init_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYPE *media_type) { BYTE *p; UINT32 size; const BYTE *s; - TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder; + TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder; mdecoder->codec = avcodec_find_decoder(mdecoder->codec_id); - if(!mdecoder->codec) + if (!mdecoder->codec) { WLog_ERR(TAG, "avcodec_find_decoder failed."); return FALSE; } mdecoder->codec_context->codec_id = mdecoder->codec_id; mdecoder->codec_context->codec_type = mdecoder->media_type; - if(mdecoder->media_type == AVMEDIA_TYPE_VIDEO) + if (mdecoder->media_type == AVMEDIA_TYPE_VIDEO) { - if(!tsmf_ffmpeg_init_video_stream(decoder, media_type)) + if (!tsmf_ffmpeg_init_video_stream(decoder, media_type)) return FALSE; } else - if(mdecoder->media_type == AVMEDIA_TYPE_AUDIO) + if (mdecoder->media_type == AVMEDIA_TYPE_AUDIO) { - if(!tsmf_ffmpeg_init_audio_stream(decoder, media_type)) + if (!tsmf_ffmpeg_init_audio_stream(decoder, media_type)) return FALSE; } - if(media_type->ExtraData) + if (media_type->ExtraData) { - if(media_type->SubType == TSMF_SUB_TYPE_AVC1 && + if (media_type->SubType == TSMF_SUB_TYPE_AVC1 && media_type->FormatType == TSMF_FORMAT_TYPE_MPEG2VIDEOINFO) { /* The extradata format that FFmpeg uses is following CodecPrivate in Matroska. @@ -195,15 +194,15 @@ static BOOL tsmf_ffmpeg_init_stream(ITSMFDecoder *decoder, const TS_AM_MEDIA_TYP memset(mdecoder->codec_context->extradata + media_type->ExtraDataSize, 0, 8); } } - if(mdecoder->codec->capabilities & CODEC_CAP_TRUNCATED) + if (mdecoder->codec->capabilities & CODEC_CAP_TRUNCATED) mdecoder->codec_context->flags |= CODEC_FLAG_TRUNCATED; return TRUE; } -static BOOL tsmf_ffmpeg_prepare(ITSMFDecoder *decoder) +static BOOL tsmf_ffmpeg_prepare(ITSMFDecoder* decoder) { - TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder; - if(avcodec_open2(mdecoder->codec_context, mdecoder->codec, NULL) < 0) + TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder; + if (avcodec_open2(mdecoder->codec_context, mdecoder->codec, NULL) < 0) { WLog_ERR(TAG, "avcodec_open2 failed."); return FALSE; @@ -212,9 +211,9 @@ static BOOL tsmf_ffmpeg_prepare(ITSMFDecoder *decoder) return TRUE; } -static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *media_type) +static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE *media_type) { - TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder; + TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder; switch(media_type->MajorType) { case TSMF_MAJOR_TYPE_VIDEO: @@ -254,7 +253,7 @@ static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *medi /* For AAC the pFormat is a HEAACWAVEINFO struct, and the codec data is at the end of it. See http://msdn.microsoft.com/en-us/library/dd757806.aspx */ - if(media_type->ExtraData) + if (media_type->ExtraData) { media_type->ExtraData += 12; media_type->ExtraDataSize -= 12; @@ -270,18 +269,18 @@ static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *medi default: return FALSE; } - if(!tsmf_ffmpeg_init_context(decoder)) + if (!tsmf_ffmpeg_init_context(decoder)) return FALSE; - if(!tsmf_ffmpeg_init_stream(decoder, media_type)) + if (!tsmf_ffmpeg_init_stream(decoder, media_type)) return FALSE; - if(!tsmf_ffmpeg_prepare(decoder)) + if (!tsmf_ffmpeg_prepare(decoder)) return FALSE; return TRUE; } -static BOOL tsmf_ffmpeg_decode_video(ITSMFDecoder *decoder, const BYTE *data, UINT32 data_size, UINT32 extensions) +static BOOL tsmf_ffmpeg_decode_video(ITSMFDecoder* decoder, const BYTE *data, UINT32 data_size, UINT32 extensions) { - TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder; + TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder; int decoded; int len; AVFrame *frame; @@ -294,12 +293,12 @@ static BOOL tsmf_ffmpeg_decode_video(ITSMFDecoder *decoder, const BYTE *data, UI av_init_packet(&pkt); pkt.data = (BYTE *) data; pkt.size = data_size; - if(extensions & TSMM_SAMPLE_EXT_CLEANPOINT) + if (extensions & TSMM_SAMPLE_EXT_CLEANPOINT) pkt.flags |= AV_PKT_FLAG_KEY; len = avcodec_decode_video2(mdecoder->codec_context, mdecoder->frame, &decoded, &pkt); } #endif - if(len < 0) + if (len < 0) { WLog_ERR(TAG, "data_size %d, avcodec_decode_video failed (%d)", data_size, len); ret = FALSE; @@ -334,9 +333,9 @@ static BOOL tsmf_ffmpeg_decode_video(ITSMFDecoder *decoder, const BYTE *data, UI return ret; } -static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder *decoder, const BYTE *data, UINT32 data_size, UINT32 extensions) +static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder* decoder, const BYTE *data, UINT32 data_size, UINT32 extensions) { - TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder; + TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder; int len; int frame_size; UINT32 src_size; @@ -349,11 +348,11 @@ static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder *decoder, const BYTE *data, UI for(i = 0; i < data_size; i++) { WLog_DBG(TAG, ("%02X ", data[i])); - if(i % 16 == 15) + if (i % 16 == 15) WLog_DBG(TAG, ("\n")); } #endif - if(mdecoder->decoded_size_max == 0) + if (mdecoder->decoded_size_max == 0) mdecoder->decoded_size_max = MAX_AUDIO_FRAME_SIZE + 16; mdecoder->decoded_data = malloc(mdecoder->decoded_size_max); ZeroMemory(mdecoder->decoded_data, mdecoder->decoded_size_max); @@ -365,12 +364,12 @@ static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder *decoder, const BYTE *data, UI while(src_size > 0) { /* Ensure enough space for decoding */ - if(mdecoder->decoded_size_max - mdecoder->decoded_size < MAX_AUDIO_FRAME_SIZE) + if (mdecoder->decoded_size_max - mdecoder->decoded_size < MAX_AUDIO_FRAME_SIZE) { mdecoder->decoded_size_max = mdecoder->decoded_size_max * 2 + 16; mdecoder->decoded_data = realloc(mdecoder->decoded_data, mdecoder->decoded_size_max); dst = (BYTE *)(((uintptr_t)mdecoder->decoded_data + 15) & ~ 0x0F); - if(dst - mdecoder->decoded_data != dst_offset) + if (dst - mdecoder->decoded_data != dst_offset) { /* re-align the memory if the alignment has changed after realloc */ memmove(dst, mdecoder->decoded_data + dst_offset, mdecoder->decoded_size); @@ -391,7 +390,7 @@ static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder *decoder, const BYTE *data, UI pkt.data = (BYTE *) src; pkt.size = src_size; len = avcodec_decode_audio4(mdecoder->codec_context, decoded_frame, &got_frame, &pkt); - if(len >= 0 && got_frame) + if (len >= 0 && got_frame) { frame_size = av_samples_get_buffer_size(NULL, mdecoder->codec_context->channels, decoded_frame->nb_samples, mdecoder->codec_context->sample_fmt, 1); @@ -400,7 +399,7 @@ static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder *decoder, const BYTE *data, UI av_free(decoded_frame); } #endif - if(len <= 0 || frame_size <= 0) + if (len <= 0 || frame_size <= 0) { WLog_ERR(TAG, "error decoding"); break; @@ -410,13 +409,13 @@ static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder *decoder, const BYTE *data, UI mdecoder->decoded_size += frame_size; dst += frame_size; } - if(mdecoder->decoded_size == 0) + if (mdecoder->decoded_size == 0) { free(mdecoder->decoded_data); mdecoder->decoded_data = NULL; } else - if(dst_offset) + if (dst_offset) { /* move the aligned decoded data to original place */ memmove(mdecoder->decoded_data, mdecoder->decoded_data + dst_offset, mdecoder->decoded_size); @@ -426,10 +425,10 @@ static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder *decoder, const BYTE *data, UI return TRUE; } -static BOOL tsmf_ffmpeg_decode(ITSMFDecoder *decoder, const BYTE *data, UINT32 data_size, UINT32 extensions) +static BOOL tsmf_ffmpeg_decode(ITSMFDecoder* decoder, const BYTE *data, UINT32 data_size, UINT32 extensions) { - TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder; - if(mdecoder->decoded_data) + TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder; + if (mdecoder->decoded_data) { free(mdecoder->decoded_data); mdecoder->decoded_data = NULL; @@ -447,10 +446,10 @@ static BOOL tsmf_ffmpeg_decode(ITSMFDecoder *decoder, const BYTE *data, UINT32 d } } -static BYTE *tsmf_ffmpeg_get_decoded_data(ITSMFDecoder *decoder, UINT32 *size) +static BYTE *tsmf_ffmpeg_get_decoded_data(ITSMFDecoder* decoder, UINT32 *size) { BYTE *buf; - TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder; + TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder; *size = mdecoder->decoded_size; buf = mdecoder->decoded_data; mdecoder->decoded_data = NULL; @@ -458,10 +457,11 @@ static BYTE *tsmf_ffmpeg_get_decoded_data(ITSMFDecoder *decoder, UINT32 *size) return buf; } -static UINT32 tsmf_ffmpeg_get_decoded_format(ITSMFDecoder *decoder) +static UINT32 tsmf_ffmpeg_get_decoded_format(ITSMFDecoder* decoder) { - TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder; - switch(mdecoder->codec_context->pix_fmt) + TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder; + + switch (mdecoder->codec_context->pix_fmt) { case PIX_FMT_YUV420P: return RDP_PIXFMT_I420; @@ -472,10 +472,11 @@ static UINT32 tsmf_ffmpeg_get_decoded_format(ITSMFDecoder *decoder) } } -static BOOL tsmf_ffmpeg_get_decoded_dimension(ITSMFDecoder *decoder, UINT32 *width, UINT32 *height) +static BOOL tsmf_ffmpeg_get_decoded_dimension(ITSMFDecoder* decoder, UINT32 *width, UINT32 *height) { - TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder; - if(mdecoder->codec_context->width > 0 && mdecoder->codec_context->height > 0) + TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder; + + if (mdecoder->codec_context->width > 0 && mdecoder->codec_context->height > 0) { *width = mdecoder->codec_context->width; *height = mdecoder->codec_context->height; @@ -487,18 +488,18 @@ static BOOL tsmf_ffmpeg_get_decoded_dimension(ITSMFDecoder *decoder, UINT32 *wid } } -static void tsmf_ffmpeg_free(ITSMFDecoder *decoder) +static void tsmf_ffmpeg_free(ITSMFDecoder* decoder) { - TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder; - if(mdecoder->frame) + TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder; + if (mdecoder->frame) av_free(mdecoder->frame); - if(mdecoder->decoded_data) + if (mdecoder->decoded_data) free(mdecoder->decoded_data); - if(mdecoder->codec_context) + if (mdecoder->codec_context) { - if(mdecoder->prepared) + if (mdecoder->prepared) avcodec_close(mdecoder->codec_context); - if(mdecoder->codec_context->extradata) + if (mdecoder->codec_context->extradata) free(mdecoder->codec_context->extradata); av_free(mdecoder->codec_context); } @@ -511,23 +512,29 @@ static BOOL initialized = FALSE; #define freerdp_tsmf_client_subsystem_entry ffmpeg_freerdp_tsmf_client_decoder_subsystem_entry #endif -ITSMFDecoder *freerdp_tsmf_client_subsystem_entry(void) +ITSMFDecoder* freerdp_tsmf_client_subsystem_entry(void) { - TSMFFFmpegDecoder *decoder; - if(!initialized) + TSMFFFmpegDecoder* decoder; + + if (!initialized) { avcodec_register_all(); initialized = TRUE; } WLog_DBG(TAG, "TSMFDecoderEntry FFMPEG"); - decoder = (TSMFFFmpegDecoder*) malloc(sizeof(TSMFFFmpegDecoder)); - ZeroMemory(decoder, sizeof(TSMFFFmpegDecoder)); + + decoder = (TSMFFFmpegDecoder*) calloc(1, sizeof(TSMFFFmpegDecoder)); + + if (!decoder) + return NULL; + decoder->iface.SetFormat = tsmf_ffmpeg_set_format; decoder->iface.Decode = tsmf_ffmpeg_decode; decoder->iface.GetDecodedData = tsmf_ffmpeg_get_decoded_data; decoder->iface.GetDecodedFormat = tsmf_ffmpeg_get_decoded_format; decoder->iface.GetDecodedDimension = tsmf_ffmpeg_get_decoded_dimension; decoder->iface.Free = tsmf_ffmpeg_free; - return (ITSMFDecoder *) decoder; + + return (ITSMFDecoder*) decoder; } diff --git a/channels/tsmf/client/gstreamer/tsmf_X11.c b/channels/tsmf/client/gstreamer/tsmf_X11.c index 1bfc11e51..d4cbcb486 100644 --- a/channels/tsmf/client/gstreamer/tsmf_X11.c +++ b/channels/tsmf/client/gstreamer/tsmf_X11.c @@ -18,8 +18,6 @@ * limitations under the License. */ -#include - #include #include #include @@ -61,29 +59,34 @@ struct X11Handle Window subwin; }; -static const char *get_shm_id() +static const char* get_shm_id() { static char shm_id[64]; snprintf(shm_id, sizeof(shm_id), "com.freerdp.xfreerpd.tsmf_%016X", GetCurrentProcessId()); return shm_id; } -const char *tsmf_platform_get_video_sink(void) +const char* tsmf_platform_get_video_sink(void) { return "xvimagesink"; } -const char *tsmf_platform_get_audio_sink(void) +const char* tsmf_platform_get_audio_sink(void) { return "autoaudiosink"; } -int tsmf_platform_create(TSMFGstreamerDecoder *decoder) +int tsmf_platform_create(TSMFGstreamerDecoder* decoder) { - struct X11Handle *hdl; - assert(decoder); - assert(!decoder->platform); - hdl = malloc(sizeof(struct X11Handle)); + struct X11Handle* hdl; + + if (!decoder) + return -1; + + if (decoder->platform) + return -1; + + hdl = calloc(1, sizeof(struct X11Handle)); if (!hdl) { @@ -91,7 +94,6 @@ int tsmf_platform_create(TSMFGstreamerDecoder *decoder) return -1; } - memset(hdl, 0, sizeof(struct X11Handle)); decoder->platform = hdl; hdl->shmid = shm_open(get_shm_id(), O_RDWR, PROT_READ | PROT_WRITE);; @@ -101,9 +103,11 @@ int tsmf_platform_create(TSMFGstreamerDecoder *decoder) return -2; } else + { hdl->xfwin = mmap(0, sizeof(void *), PROT_READ | PROT_WRITE, MAP_SHARED, hdl->shmid, 0); + } - if (hdl->xfwin == (int *)-1) + if (hdl->xfwin == (int*)-1) { WLog_ERR(TAG, "shmat failed!"); return -3; @@ -120,22 +124,30 @@ int tsmf_platform_create(TSMFGstreamerDecoder *decoder) return 0; } -int tsmf_platform_set_format(TSMFGstreamerDecoder *decoder) +int tsmf_platform_set_format(TSMFGstreamerDecoder* decoder) { - assert(decoder); + if (!decoder) + return -1; if (decoder->media_type == TSMF_MAJOR_TYPE_VIDEO) { + } return 0; } -int tsmf_platform_register_handler(TSMFGstreamerDecoder *decoder) +int tsmf_platform_register_handler(TSMFGstreamerDecoder* decoder) { - assert(decoder); - assert(decoder->pipe); - GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(decoder->pipe)); + GstBus* bus; + + if (!decoder) + return -1; + + if (!decoder->pipe) + return -1; + + bus = gst_pipeline_get_bus(GST_PIPELINE(decoder->pipe)); if (!bus) { @@ -146,9 +158,9 @@ int tsmf_platform_register_handler(TSMFGstreamerDecoder *decoder) return 0; } -int tsmf_platform_free(TSMFGstreamerDecoder *decoder) +int tsmf_platform_free(TSMFGstreamerDecoder* decoder) { - struct X11Handle *hdl = decoder->platform; + struct X11Handle* hdl = decoder->platform; if (!hdl) return -1; @@ -157,18 +169,21 @@ int tsmf_platform_free(TSMFGstreamerDecoder *decoder) XCloseDisplay(hdl->disp); if (hdl->xfwin) - munmap(0, sizeof(void *)); + munmap(0, sizeof(void*)); if (hdl->shmid >= 0) close(hdl->shmid); free(hdl); decoder->platform = NULL; + return 0; } -int tsmf_window_create(TSMFGstreamerDecoder *decoder) +int tsmf_window_create(TSMFGstreamerDecoder* decoder) { + struct X11Handle* hdl; + if (decoder->media_type != TSMF_MAJOR_TYPE_VIDEO) { decoder->ready = TRUE; @@ -181,9 +196,14 @@ int tsmf_window_create(TSMFGstreamerDecoder *decoder) #else GstXOverlay *overlay = GST_X_OVERLAY(decoder->outsink); #endif - struct X11Handle *hdl = (struct X11Handle *)decoder->platform; - assert(decoder); - assert(hdl); + + if (!decoder) + return -1; + + if (!decoder->platform) + return -1; + + hdl = (struct X11Handle*) decoder->platform; if (!hdl->subwin) { @@ -217,11 +237,15 @@ int tsmf_window_create(TSMFGstreamerDecoder *decoder) } } -int tsmf_window_resize(TSMFGstreamerDecoder *decoder, int x, int y, int width, +int tsmf_window_resize(TSMFGstreamerDecoder* decoder, int x, int y, int width, int height, int nr_rects, RDP_RECT *rects) { + struct X11Handle* hdl; + if (decoder->media_type != TSMF_MAJOR_TYPE_VIDEO) + { return -3; + } else { #if GST_VERSION_MAJOR > 0 @@ -229,10 +253,15 @@ int tsmf_window_resize(TSMFGstreamerDecoder *decoder, int x, int y, int width, #else GstXOverlay *overlay = GST_X_OVERLAY(decoder->outsink); #endif - struct X11Handle *hdl = (struct X11Handle *)decoder->platform; + if (!decoder) + return -1; + + if (!decoder->platform) + return -1; + + hdl = (struct X11Handle*) decoder->platform; DEBUG_TSMF("resize: x=%d, y=%d, w=%d, h=%d", x, y, width, height); - assert(decoder); - assert(hdl); + #if GST_VERSION_MAJOR > 0 if (!gst_video_overlay_set_render_rectangle(overlay, 0, 0, width, height)) @@ -280,28 +309,37 @@ int tsmf_window_resize(TSMFGstreamerDecoder *decoder, int x, int y, int width, } } -int tsmf_window_pause(TSMFGstreamerDecoder *decoder) +int tsmf_window_pause(TSMFGstreamerDecoder* decoder) { - assert(decoder); + if (!decoder) + return -1; + return 0; } -int tsmf_window_resume(TSMFGstreamerDecoder *decoder) +int tsmf_window_resume(TSMFGstreamerDecoder* decoder) { - assert(decoder); + if (!decoder) + return -1; + return 0; } -int tsmf_window_destroy(TSMFGstreamerDecoder *decoder) +int tsmf_window_destroy(TSMFGstreamerDecoder* decoder) { - struct X11Handle *hdl = (struct X11Handle *)decoder->platform; + struct X11Handle* hdl; decoder->ready = FALSE; if (decoder->media_type != TSMF_MAJOR_TYPE_VIDEO) return -3; - assert(decoder); - assert(hdl); + if (!decoder) + return -1; + + if (!decoder->platform) + return -1; + + hdl = (struct X11Handle*) decoder->platform; if (hdl->subwin) { diff --git a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c index 0139b8996..713edeba2 100644 --- a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c +++ b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c @@ -43,14 +43,15 @@ #include #endif -static BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder *mdecoder); -static void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder *mdecoder); -static int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder *mdecoder, +static BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder* mdecoder); +static void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder* mdecoder); +static int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder* mdecoder, GstState desired_state); -const char *get_type(TSMFGstreamerDecoder *mdecoder) +const char* get_type(TSMFGstreamerDecoder* mdecoder) { - assert(mdecoder); + if (!mdecoder) + return NULL; if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) return "VIDEO"; @@ -60,28 +61,28 @@ const char *get_type(TSMFGstreamerDecoder *mdecoder) static void tsmf_gstreamer_enough_data(GstAppSrc *src, gpointer user_data) { - TSMFGstreamerDecoder *mdecoder = user_data; - (void)mdecoder; + TSMFGstreamerDecoder* mdecoder = user_data; + (void) mdecoder; DEBUG_TSMF("%s", get_type(mdecoder)); } static void tsmf_gstreamer_need_data(GstAppSrc *src, guint length, gpointer user_data) { - TSMFGstreamerDecoder *mdecoder = user_data; - (void)mdecoder; + TSMFGstreamerDecoder* mdecoder = user_data; + (void) mdecoder; DEBUG_TSMF("%s length=%lu", get_type(mdecoder), length); } static gboolean tsmf_gstreamer_seek_data(GstAppSrc *src, guint64 offset, gpointer user_data) { - TSMFGstreamerDecoder *mdecoder = user_data; - (void)mdecoder; + TSMFGstreamerDecoder* mdecoder = user_data; + (void) mdecoder; DEBUG_TSMF("%s offset=%llu", get_type(mdecoder), offset); if (!mdecoder->paused) tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PAUSED); - gst_app_src_end_of_stream((GstAppSrc *)mdecoder->src); + gst_app_src_end_of_stream((GstAppSrc*) mdecoder->src); if (!mdecoder->paused) tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PLAYING); @@ -100,11 +101,11 @@ static inline const GstClockTime tsmf_gstreamer_timestamp_ms_to_gst(UINT64 ms_ti return (GstClockTime)(ms_timestamp * 100); } -int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder *mdecoder, GstState desired_state) +int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder* mdecoder, GstState desired_state) { GstStateChangeReturn state_change; - const char *name; - const char *sname = get_type(mdecoder); + const char* name; + const char* sname = get_type(mdecoder); if (!mdecoder) return 0; @@ -120,24 +121,33 @@ int tsmf_gstreamer_pipeline_set_state(TSMFGstreamerDecoder *mdecoder, GstState d state_change = gst_element_set_state(mdecoder->pipe, desired_state); if (state_change == GST_STATE_CHANGE_FAILURE) + { WLog_ERR(TAG, "%s: (%s) GST_STATE_CHANGE_FAILURE.", sname, name); + } else if (state_change == GST_STATE_CHANGE_ASYNC) { WLog_ERR(TAG, "%s: (%s) GST_STATE_CHANGE_ASYNC.", sname, name); mdecoder->state = desired_state; } else + { mdecoder->state = desired_state; + } return 0; } -static GstBuffer *tsmf_get_buffer_from_data(const void *raw_data, gsize size) +static GstBuffer* tsmf_get_buffer_from_data(const void* raw_data, gsize size) { - GstBuffer *buffer; + GstBuffer* buffer; gpointer data; - assert(raw_data); - assert(size > 0); + + if (!raw_data) + return NULL; + + if (size < 1) + return NULL; + data = g_malloc(size); if (!data) @@ -146,7 +156,8 @@ static GstBuffer *tsmf_get_buffer_from_data(const void *raw_data, gsize size) return NULL; } - memcpy(data, raw_data, size); + CopyMemory(data, raw_data, size); + #if GST_VERSION_MAJOR > 0 buffer = gst_buffer_new_wrapped(data, size); #else @@ -163,12 +174,13 @@ static GstBuffer *tsmf_get_buffer_from_data(const void *raw_data, gsize size) GST_BUFFER_SIZE(buffer) = size; GST_BUFFER_DATA(buffer) = GST_BUFFER_MALLOCDATA(buffer); #endif + return buffer; } -static BOOL tsmf_gstreamer_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *media_type) +static BOOL tsmf_gstreamer_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* media_type) { - TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder; + TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder*) decoder; if (!mdecoder) return FALSE; @@ -377,7 +389,6 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *m void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder* mdecoder) { - //Cleaning up elements if (!mdecoder || !mdecoder->pipe) return; @@ -393,11 +404,11 @@ void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder* mdecoder) mdecoder->src = NULL; } -BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder *mdecoder) +BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder* mdecoder) { - const char *appsrc = "appsrc name=source ! decodebin name=decoder !"; - const char *video = "autovideoconvert ! videoscale !"; - const char *audio = "audioconvert ! audiorate ! audioresample ! volume name=audiovolume !"; + const char* appsrc = "appsrc name=source ! decodebin name=decoder !"; + const char* video = "autovideoconvert ! videoscale !"; + const char* audio = "audioconvert ! audiorate ! audioresample ! volume name=audiovolume !"; char pipeline[1024]; if (!mdecoder) @@ -467,16 +478,16 @@ BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder *mdecoder) mdecoder->pipeline_start_time_valid = 0; mdecoder->shutdown = 0; - GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(mdecoder->pipe), GST_DEBUG_GRAPH_SHOW_ALL, get_type(mdecoder)); + GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(mdecoder->pipe), GST_DEBUG_GRAPH_SHOW_ALL, get_type(mdecoder)); return TRUE; } -static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder *decoder, const BYTE *data, UINT32 data_size, UINT32 extensions, +static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder* decoder, const BYTE *data, UINT32 data_size, UINT32 extensions, UINT64 start_time, UINT64 end_time, UINT64 duration) { GstBuffer *gst_buf; - TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder; + TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder; UINT64 sample_time = tsmf_gstreamer_timestamp_ms_to_gst(start_time); UINT64 sample_duration = tsmf_gstreamer_timestamp_ms_to_gst(duration); @@ -570,9 +581,9 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder *decoder, const BYTE *data, UIN return TRUE; } -static void tsmf_gstreamer_change_volume(ITSMFDecoder *decoder, UINT32 newVolume, UINT32 muted) +static void tsmf_gstreamer_change_volume(ITSMFDecoder* decoder, UINT32 newVolume, UINT32 muted) { - TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder; + TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder; if (!mdecoder || !mdecoder->pipe) return; @@ -595,9 +606,9 @@ static void tsmf_gstreamer_change_volume(ITSMFDecoder *decoder, UINT32 newVolume g_object_set(mdecoder->volume, "volume", mdecoder->gstVolume, NULL); } -static void tsmf_gstreamer_control(ITSMFDecoder *decoder, ITSMFControlMsg control_msg, UINT32 *arg) +static void tsmf_gstreamer_control(ITSMFDecoder* decoder, ITSMFControlMsg control_msg, UINT32 *arg) { - TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder; + TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder; if (!mdecoder) return; @@ -659,9 +670,9 @@ static void tsmf_gstreamer_control(ITSMFDecoder *decoder, ITSMFControlMsg contro WLog_ERR(TAG, "Unknown control message %08x", control_msg); } -static BOOL tsmf_gstreamer_buffer_filled(ITSMFDecoder *decoder) +static BOOL tsmf_gstreamer_buffer_filled(ITSMFDecoder* decoder) { - TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder; + TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder; DEBUG_TSMF(""); if (!mdecoder) @@ -673,9 +684,9 @@ static BOOL tsmf_gstreamer_buffer_filled(ITSMFDecoder *decoder) return clbuff >= buff_max ? TRUE : FALSE; } -static void tsmf_gstreamer_free(ITSMFDecoder *decoder) +static void tsmf_gstreamer_free(ITSMFDecoder* decoder) { - TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder; + TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder; DEBUG_TSMF("%s", get_type(mdecoder)); if (mdecoder) @@ -687,15 +698,15 @@ static void tsmf_gstreamer_free(ITSMFDecoder *decoder) gst_caps_unref(mdecoder->gst_caps); tsmf_platform_free(mdecoder); - memset(mdecoder, 0, sizeof(TSMFGstreamerDecoder)); + ZeroMemory(mdecoder, sizeof(TSMFGstreamerDecoder)); free(mdecoder); mdecoder = NULL; } } -static UINT64 tsmf_gstreamer_get_running_time(ITSMFDecoder *decoder) +static UINT64 tsmf_gstreamer_get_running_time(ITSMFDecoder* decoder) { - TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder; + TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder; if (!mdecoder) return 0; @@ -716,31 +727,33 @@ static UINT64 tsmf_gstreamer_get_running_time(ITSMFDecoder *decoder) return pos/100; } -static void tsmf_gstreamer_update_rendering_area(ITSMFDecoder *decoder, +static void tsmf_gstreamer_update_rendering_area(ITSMFDecoder* decoder, int newX, int newY, int newWidth, int newHeight, int numRectangles, RDP_RECT *rectangles) { - TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder; + TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder; DEBUG_TSMF("x=%d, y=%d, w=%d, h=%d, rect=%d", newX, newY, newWidth, newHeight, numRectangles); if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) + { tsmf_window_resize(mdecoder, newX, newY, newWidth, newHeight, numRectangles, rectangles); + } } -BOOL tsmf_gstreamer_ack(ITSMFDecoder *decoder, BOOL (*cb)(void *, BOOL), void *stream) +BOOL tsmf_gstreamer_ack(ITSMFDecoder* decoder, BOOL (*cb)(void *, BOOL), void *stream) { - TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder; + TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder; DEBUG_TSMF(""); mdecoder->ack_cb = cb; mdecoder->stream = stream; return TRUE; } -BOOL tsmf_gstreamer_sync(ITSMFDecoder *decoder, void (*cb)(void *), void *stream) +BOOL tsmf_gstreamer_sync(ITSMFDecoder* decoder, void (*cb)(void *), void *stream) { - TSMFGstreamerDecoder *mdecoder = (TSMFGstreamerDecoder *) decoder; + TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder; DEBUG_TSMF(""); mdecoder->sync_cb = NULL; mdecoder->stream = stream; @@ -751,7 +764,7 @@ BOOL tsmf_gstreamer_sync(ITSMFDecoder *decoder, void (*cb)(void *), void *stream #define freerdp_tsmf_client_subsystem_entry gstreamer_freerdp_tsmf_client_decoder_subsystem_entry #endif -ITSMFDecoder *freerdp_tsmf_client_subsystem_entry(void) +ITSMFDecoder* freerdp_tsmf_client_subsystem_entry(void) { TSMFGstreamerDecoder *decoder; @@ -760,8 +773,11 @@ ITSMFDecoder *freerdp_tsmf_client_subsystem_entry(void) gst_init(NULL, NULL); } - decoder = malloc(sizeof(TSMFGstreamerDecoder)); - memset(decoder, 0, sizeof(TSMFGstreamerDecoder)); + decoder = calloc(1, sizeof(TSMFGstreamerDecoder)); + + if (!decoder) + return NULL; + decoder->iface.SetFormat = tsmf_gstreamer_set_format; decoder->iface.Decode = NULL; decoder->iface.GetDecodedData = NULL; @@ -780,6 +796,8 @@ ITSMFDecoder *freerdp_tsmf_client_subsystem_entry(void) decoder->gstVolume = 0.5; decoder->gstMuted = FALSE; decoder->state = GST_STATE_VOID_PENDING; /* No real state yet */ + tsmf_platform_create(decoder); - return (ITSMFDecoder *) decoder; + + return (ITSMFDecoder*) decoder; } diff --git a/channels/tsmf/client/gstreamer/tsmf_platform.h b/channels/tsmf/client/gstreamer/tsmf_platform.h index 32484236e..6748f4ea8 100644 --- a/channels/tsmf/client/gstreamer/tsmf_platform.h +++ b/channels/tsmf/client/gstreamer/tsmf_platform.h @@ -59,25 +59,25 @@ typedef struct _TSMFGstreamerDecoder } TSMFGstreamerDecoder; -const char *get_type(TSMFGstreamerDecoder *mdecoder); +const char* get_type(TSMFGstreamerDecoder* mdecoder); -const char *tsmf_platform_get_video_sink(void); -const char *tsmf_platform_get_audio_sink(void); +const char* tsmf_platform_get_video_sink(void); +const char* tsmf_platform_get_audio_sink(void); -int tsmf_platform_create(TSMFGstreamerDecoder *decoder); -int tsmf_platform_set_format(TSMFGstreamerDecoder *decoder); -int tsmf_platform_register_handler(TSMFGstreamerDecoder *decoder); -int tsmf_platform_free(TSMFGstreamerDecoder *decoder); +int tsmf_platform_create(TSMFGstreamerDecoder* decoder); +int tsmf_platform_set_format(TSMFGstreamerDecoder* decoder); +int tsmf_platform_register_handler(TSMFGstreamerDecoder* decoder); +int tsmf_platform_free(TSMFGstreamerDecoder* decoder); -int tsmf_window_create(TSMFGstreamerDecoder *decoder); -int tsmf_window_resize(TSMFGstreamerDecoder *decoder, int x, int y, +int tsmf_window_create(TSMFGstreamerDecoder* decoder); +int tsmf_window_resize(TSMFGstreamerDecoder* decoder, int x, int y, int width, int height, int nr_rect, RDP_RECT *visible); -int tsmf_window_destroy(TSMFGstreamerDecoder *decoder); +int tsmf_window_destroy(TSMFGstreamerDecoder* decoder); -int tsmf_window_pause(TSMFGstreamerDecoder *decoder); -int tsmf_window_resume(TSMFGstreamerDecoder *decoder); +int tsmf_window_pause(TSMFGstreamerDecoder* decoder); +int tsmf_window_resume(TSMFGstreamerDecoder* decoder); -BOOL tsmf_gstreamer_add_pad(TSMFGstreamerDecoder *mdecoder); -void tsmf_gstreamer_remove_pad(TSMFGstreamerDecoder *mdecoder); +BOOL tsmf_gstreamer_add_pad(TSMFGstreamerDecoder* mdecoder); +void tsmf_gstreamer_remove_pad(TSMFGstreamerDecoder* mdecoder); #endif diff --git a/channels/tsmf/client/tsmf_audio.c b/channels/tsmf/client/tsmf_audio.c index d03ebbcef..5b4e7fdb9 100644 --- a/channels/tsmf/client/tsmf_audio.c +++ b/channels/tsmf/client/tsmf_audio.c @@ -34,12 +34,12 @@ static ITSMFAudioDevice* tsmf_load_audio_device_by_name(const char* name, const entry = (TSMF_AUDIO_DEVICE_ENTRY) freerdp_load_channel_addin_entry("tsmf", (LPSTR) name, "audio", 0); - if (entry == NULL) + if (!entry) return NULL; audio = entry(); - if (audio == NULL) + if (!audio) { WLog_ERR(TAG, "failed to call export function in %s", name); return NULL; diff --git a/channels/tsmf/client/tsmf_codec.c b/channels/tsmf/client/tsmf_codec.c index 5657a8dd0..e4ae51a30 100644 --- a/channels/tsmf/client/tsmf_codec.c +++ b/channels/tsmf/client/tsmf_codec.c @@ -22,13 +22,11 @@ #include "config.h" #endif -#include -#include -#include - +#include #include #include +#include "tsmf_decoder.h" #include "tsmf_constants.h" #include "tsmf_types.h" @@ -176,40 +174,64 @@ static const TSMFMediaTypeMap tsmf_sub_type_map[] = }, /* E436EB81-524F-11CE-9F53-0020AF0BA770 */ - /* { { 0x81, 0xEB, 0x36, 0xE4, 0x4F, 0x52, 0xCE, 0x11, 0x9F, 0x53, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70 }, "MEDIASUBTYPE_MP1V", TSMF_SUB_TYPE_MP1V }, - */ /* 00000050-0000-0010-8000-00AA00389B71 */ - /* { { 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 }, "MEDIASUBTYPE_MP1A", TSMF_SUB_TYPE_MP1A }, - */ /* E06D802C-DB46-11CF-B4D1-00805F6CBBEA */ - /* { { 0x2C, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA }, "MEDIASUBTYPE_DOLBY_AC3", TSMF_SUB_TYPE_AC3 }, - */ /* 32595559-0000-0010-8000-00AA00389B71 */ - /* { { 0x59, 0x55, 0x59, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 }, "MEDIASUBTYPE_YUY2", TSMF_SUB_TYPE_YUY2 }, - */ + + /* Opencodec IDS */ + { + {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71}, + "MEDIASUBTYPE_FLAC", + TSMF_SUB_TYPE_FLAC + }, + + { + {0x61, 0x34, 0x70, 0x6D, 0x7A, 0x76, 0x4D, 0x49, 0xB4, 0x78, 0xF2, 0x9D, 0x25, 0xDC, 0x90, 0x37}, + "MEDIASUBTYPE_OGG", + TSMF_SUB_TYPE_OGG + }, + + { + {0x4D, 0x34, 0x53, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71}, + "MEDIASUBTYPE_H263", + TSMF_SUB_TYPE_H263 + }, + + /* WebMMF codec IDS */ + { + {0x56, 0x50, 0x38, 0x30, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71}, + "MEDIASUBTYPE_VP8", + TSMF_SUB_TYPE_VP8 + }, + + { + {0x0B, 0xD1, 0x2F, 0x8D, 0x41, 0x58, 0x6B, 0x4A, 0x89, 0x05, 0x58, 0x8F, 0xEC, 0x1A, 0xDE, 0xD9}, + "MEDIASUBTYPE_OGG", + TSMF_SUB_TYPE_OGG + }, { { 0 }, @@ -525,13 +547,30 @@ BOOL tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE* mediatype, wStream* s) return ret; } -BOOL tsmf_codec_check_media_type(wStream* s) +BOOL tsmf_codec_check_media_type(const char* decoder_name, wStream* s) { BYTE* m; BOOL ret; TS_AM_MEDIA_TYPE mediatype; + Stream_GetPointer(s, m); ret = tsmf_codec_parse_media_type(&mediatype, s); Stream_SetPointer(s, m); + + if (ret) + { + ITSMFDecoder* decoder = tsmf_load_decoder(decoder_name, &mediatype); + + if (!decoder) + { + WLog_WARN(TAG, "Format not supported by decoder %s", decoder_name); + ret = FALSE; + } + else + { + decoder->Free(decoder); + } + } + return ret; } diff --git a/channels/tsmf/client/tsmf_codec.h b/channels/tsmf/client/tsmf_codec.h index 5fc3a0a13..0dd419837 100644 --- a/channels/tsmf/client/tsmf_codec.h +++ b/channels/tsmf/client/tsmf_codec.h @@ -23,7 +23,7 @@ #include "tsmf_types.h" BOOL tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE* mediatype, wStream* s); -BOOL tsmf_codec_check_media_type(wStream* s); +BOOL tsmf_codec_check_media_type(const char* decoder_name, wStream* s); #endif diff --git a/channels/tsmf/client/tsmf_constants.h b/channels/tsmf/client/tsmf_constants.h index 4e3a666a5..1fee13a67 100644 --- a/channels/tsmf/client/tsmf_constants.h +++ b/channels/tsmf/client/tsmf_constants.h @@ -118,6 +118,13 @@ #define TSMF_SUB_TYPE_MP43 17 #define TSMF_SUB_TYPE_MP4S 18 #define TSMF_SUB_TYPE_MP42 19 +#define TSMF_SUB_TYPE_OGG 20 +#define TSMF_SUB_TYPE_SPEEX 21 +#define TSMF_SUB_TYPE_THEORA 22 +#define TSMF_SUB_TYPE_FLAC 23 +#define TSMF_SUB_TYPE_VP8 24 +#define TSMF_SUB_TYPE_VP9 25 +#define TSMF_SUB_TYPE_H263 26 /* FormatType */ #define TSMF_FORMAT_TYPE_UNKNOWN 0 diff --git a/channels/tsmf/client/tsmf_decoder.c b/channels/tsmf/client/tsmf_decoder.c index 0067cd548..164e0d8be 100644 --- a/channels/tsmf/client/tsmf_decoder.c +++ b/channels/tsmf/client/tsmf_decoder.c @@ -32,41 +32,51 @@ #include "tsmf_constants.h" #include "tsmf_decoder.h" -static ITSMFDecoder *tsmf_load_decoder_by_name(const char *name, TS_AM_MEDIA_TYPE *media_type) +static ITSMFDecoder* tsmf_load_decoder_by_name(const char *name, TS_AM_MEDIA_TYPE *media_type) { - ITSMFDecoder *decoder; + ITSMFDecoder* decoder; TSMF_DECODER_ENTRY entry; + entry = (TSMF_DECODER_ENTRY) freerdp_load_channel_addin_entry("tsmf", (LPSTR) name, "decoder", 0); - if(entry == NULL) + + if (!entry) return NULL; + decoder = entry(); - if(decoder == NULL) + + if (!decoder) { WLog_ERR(TAG, "failed to call export function in %s", name); return NULL; } - if(!decoder->SetFormat(decoder, media_type)) + + if (!decoder->SetFormat(decoder, media_type)) { decoder->Free(decoder); decoder = NULL; } + return decoder; } -ITSMFDecoder *tsmf_load_decoder(const char *name, TS_AM_MEDIA_TYPE *media_type) +ITSMFDecoder* tsmf_load_decoder(const char* name, TS_AM_MEDIA_TYPE* media_type) { - ITSMFDecoder *decoder = NULL; - if(name) + ITSMFDecoder* decoder = NULL; + + if (name) { decoder = tsmf_load_decoder_by_name(name, media_type); } + #if defined(WITH_GSTREAMER_1_0) || defined(WITH_GSTREAMER_0_10) - if(!decoder) + if (!decoder) decoder = tsmf_load_decoder_by_name("gstreamer", media_type); #endif + #if defined(WITH_FFMPEG) - if(!decoder) + if (!decoder) decoder = tsmf_load_decoder_by_name("ffmpeg", media_type); #endif + return decoder; } diff --git a/channels/tsmf/client/tsmf_ifman.c b/channels/tsmf/client/tsmf_ifman.c index 18c654b27..a982efdd0 100644 --- a/channels/tsmf/client/tsmf_ifman.c +++ b/channels/tsmf/client/tsmf_ifman.c @@ -37,18 +37,22 @@ #include "tsmf_ifman.h" -int tsmf_ifman_rim_exchange_capability_request(TSMF_IFMAN *ifman) +int tsmf_ifman_rim_exchange_capability_request(TSMF_IFMAN* ifman) { UINT32 CapabilityValue; + Stream_Read_UINT32(ifman->input, CapabilityValue); + DEBUG_TSMF("server CapabilityValue %d", CapabilityValue); + Stream_EnsureRemainingCapacity(ifman->output, 8); Stream_Write_UINT32(ifman->output, 1); /* CapabilityValue */ Stream_Write_UINT32(ifman->output, 0); /* Result */ + return 0; } -int tsmf_ifman_exchange_capability_request(TSMF_IFMAN *ifman) +int tsmf_ifman_exchange_capability_request(TSMF_IFMAN* ifman) { UINT32 i; UINT32 v; @@ -56,17 +60,20 @@ int tsmf_ifman_exchange_capability_request(TSMF_IFMAN *ifman) UINT32 CapabilityType; UINT32 cbCapabilityLength; UINT32 numHostCapabilities; + pos = Stream_GetPosition(ifman->output); Stream_EnsureRemainingCapacity(ifman->output, ifman->input_size + 4); Stream_Copy(ifman->output, ifman->input, ifman->input_size); Stream_SetPosition(ifman->output, pos); Stream_Read_UINT32(ifman->output, numHostCapabilities); - for(i = 0; i < numHostCapabilities; i++) + + for (i = 0; i < numHostCapabilities; i++) { Stream_Read_UINT32(ifman->output, CapabilityType); Stream_Read_UINT32(ifman->output, cbCapabilityLength); pos = Stream_GetPosition(ifman->output); - switch(CapabilityType) + + switch (CapabilityType) { case 1: /* Protocol version request */ Stream_Read_UINT32(ifman->output, v); @@ -76,8 +83,7 @@ int tsmf_ifman_exchange_capability_request(TSMF_IFMAN *ifman) Stream_Peek_UINT32(ifman->output, v); DEBUG_TSMF("server supported platform %d", 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); @@ -85,63 +91,81 @@ int tsmf_ifman_exchange_capability_request(TSMF_IFMAN *ifman) } 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; } -int tsmf_ifman_check_format_support_request(TSMF_IFMAN *ifman) +int tsmf_ifman_check_format_support_request(TSMF_IFMAN* ifman) { UINT32 numMediaType; UINT32 PlatformCookie; UINT32 FormatSupported = 1; + 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); - if(!tsmf_codec_check_media_type(ifman->input)) + + if (!tsmf_codec_check_media_type(ifman->decoder_name, ifman->input)) FormatSupported = 0; - if(FormatSupported) + + if (FormatSupported) DEBUG_TSMF("format ok."); + Stream_EnsureRemainingCapacity(ifman->output, 12); 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; } -int tsmf_ifman_on_new_presentation(TSMF_IFMAN *ifman) +int tsmf_ifman_on_new_presentation(TSMF_IFMAN* ifman) { int status = 0; - TSMF_PRESENTATION *presentation; + TSMF_PRESENTATION* presentation; + DEBUG_TSMF(""); + presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input)); - if(presentation) + + if (presentation) { DEBUG_TSMF("Presentation already exists"); ifman->output_pending = FALSE; return 0; } + presentation = tsmf_presentation_new(Stream_Pointer(ifman->input), ifman->channel_callback); - if(presentation == NULL) + + if (!presentation) status = 1; else 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) +int tsmf_ifman_add_stream(TSMF_IFMAN* ifman) { UINT32 StreamId; int status = 0; - TSMF_STREAM *stream; - TSMF_PRESENTATION *presentation; + TSMF_STREAM* stream; + TSMF_PRESENTATION* presentation; + DEBUG_TSMF(""); + presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input)); Stream_Seek(ifman->input, 16); - if(presentation == NULL) + + if (!presentation) { status = 1; } @@ -150,14 +174,14 @@ int tsmf_ifman_add_stream(TSMF_IFMAN *ifman) Stream_Read_UINT32(ifman->input, StreamId); Stream_Seek_UINT32(ifman->input); /* numMediaType */ stream = tsmf_stream_new(presentation, StreamId); - if(stream) + if (stream) tsmf_stream_set_format(stream, ifman->decoder_name, ifman->input); } ifman->output_pending = TRUE; return status; } -int tsmf_ifman_set_topology_request(TSMF_IFMAN *ifman) +int tsmf_ifman_set_topology_request(TSMF_IFMAN* ifman) { DEBUG_TSMF(""); Stream_EnsureRemainingCapacity(ifman->output, 8); @@ -167,16 +191,20 @@ int tsmf_ifman_set_topology_request(TSMF_IFMAN *ifman) return 0; } -int tsmf_ifman_remove_stream(TSMF_IFMAN *ifman) +int tsmf_ifman_remove_stream(TSMF_IFMAN* ifman) { int status = 0; UINT32 StreamId; - TSMF_STREAM *stream; - TSMF_PRESENTATION *presentation; + TSMF_STREAM* stream; + TSMF_PRESENTATION* presentation; + DEBUG_TSMF(""); + presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input)); + Stream_Seek(ifman->input, 16); - if(presentation == NULL) + + if (!presentation) { status = 1; } @@ -184,12 +212,15 @@ int tsmf_ifman_remove_stream(TSMF_IFMAN *ifman) { Stream_Read_UINT32(ifman->input, StreamId); stream = tsmf_stream_find_by_id(presentation, StreamId); - if(stream) + + if (stream) tsmf_stream_free(stream); else status = 1; } + ifman->output_pending = TRUE; + return status; } @@ -202,16 +233,20 @@ float tsmf_stream_read_float(wStream *s) return fValue; } -int tsmf_ifman_set_source_video_rect(TSMF_IFMAN *ifman) +int tsmf_ifman_set_source_video_rect(TSMF_IFMAN* ifman) { int status = 0; float Left, Top; float Right, Bottom; - TSMF_PRESENTATION *presentation; + TSMF_PRESENTATION* presentation; + DEBUG_TSMF(""); + presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input)); + Stream_Seek(ifman->input, 16); - if(!presentation) + + if (!presentation) { status = 1; } @@ -224,31 +259,39 @@ int tsmf_ifman_set_source_video_rect(TSMF_IFMAN *ifman) DEBUG_TSMF("SetSourceVideoRect: Left: %f Top: %f Right: %f Bottom: %f", Left, Top, Right, Bottom); } + ifman->output_pending = TRUE; + return status; } -int tsmf_ifman_shutdown_presentation(TSMF_IFMAN *ifman) +int tsmf_ifman_shutdown_presentation(TSMF_IFMAN* ifman) { - TSMF_PRESENTATION *presentation; + TSMF_PRESENTATION* presentation; + DEBUG_TSMF(""); + presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input)); - if(presentation) + + if (presentation) tsmf_presentation_free(presentation); else WLog_ERR(TAG, "unknown presentation id"); + Stream_EnsureRemainingCapacity(ifman->output, 4); Stream_Write_UINT32(ifman->output, 0); /* Result */ ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB; + return 0; } -int tsmf_ifman_on_stream_volume(TSMF_IFMAN *ifman) +int tsmf_ifman_on_stream_volume(TSMF_IFMAN* ifman) { - TSMF_PRESENTATION *presentation; + TSMF_PRESENTATION* presentation; DEBUG_TSMF("on stream volume"); presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input)); - if(presentation) + + if (presentation) { UINT32 newVolume; UINT32 muted; @@ -263,16 +306,21 @@ int tsmf_ifman_on_stream_volume(TSMF_IFMAN *ifman) { WLog_ERR(TAG, "unknown presentation id"); } + ifman->output_pending = TRUE; + return 0; } -int tsmf_ifman_on_channel_volume(TSMF_IFMAN *ifman) +int tsmf_ifman_on_channel_volume(TSMF_IFMAN* ifman) { - TSMF_PRESENTATION *presentation; + TSMF_PRESENTATION* presentation; + DEBUG_TSMF("on channel volume"); + presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input)); - if(presentation) + + if (presentation) { UINT32 channelVolume; UINT32 changedChannel; @@ -282,20 +330,22 @@ int tsmf_ifman_on_channel_volume(TSMF_IFMAN *ifman) Stream_Read_UINT32(ifman->input, changedChannel); DEBUG_TSMF("on stream volume: changed channel=[%d]", changedChannel); } + ifman->output_pending = TRUE; + return 0; } -int tsmf_ifman_set_video_window(TSMF_IFMAN *ifman) +int tsmf_ifman_set_video_window(TSMF_IFMAN* ifman) { DEBUG_TSMF(""); ifman->output_pending = TRUE; return 0; } -int tsmf_ifman_update_geometry_info(TSMF_IFMAN *ifman) +int tsmf_ifman_update_geometry_info(TSMF_IFMAN* ifman) { - TSMF_PRESENTATION *presentation; + TSMF_PRESENTATION* presentation; UINT32 numGeometryInfo; UINT32 Left; UINT32 Top; @@ -321,17 +371,17 @@ int tsmf_ifman_update_geometry_info(TSMF_IFMAN *ifman) 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) + if (presentation == NULL) { error = 1; } else { - if(num_rects > 0) + if (num_rects > 0) { - rects = (RDP_RECT *) malloc(sizeof(RDP_RECT) * num_rects); - ZeroMemory(rects, sizeof(RDP_RECT) * num_rects); - 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); @@ -347,36 +397,40 @@ int tsmf_ifman_update_geometry_info(TSMF_IFMAN *ifman) 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; + return error; } -int tsmf_ifman_set_allocator(TSMF_IFMAN *ifman) +int tsmf_ifman_set_allocator(TSMF_IFMAN* ifman) { DEBUG_TSMF(""); ifman->output_pending = TRUE; return 0; } -int tsmf_ifman_notify_preroll(TSMF_IFMAN *ifman) +int tsmf_ifman_notify_preroll(TSMF_IFMAN* ifman) { DEBUG_TSMF(""); ifman->output_pending = TRUE; return 0; } -int tsmf_ifman_on_sample(TSMF_IFMAN *ifman) +int tsmf_ifman_on_sample(TSMF_IFMAN* ifman) { - TSMF_PRESENTATION *presentation; - TSMF_STREAM *stream; + TSMF_PRESENTATION* presentation; + TSMF_STREAM* stream; UINT32 StreamId; UINT64 SampleStartTime; UINT64 SampleEndTime; UINT64 ThrottleDuration; UINT32 SampleExtensions; UINT32 cbData; + Stream_Seek(ifman->input, 16); Stream_Read_UINT32(ifman->input, StreamId); Stream_Seek_UINT32(ifman->input); /* numSample */ @@ -386,62 +440,81 @@ int tsmf_ifman_on_sample(TSMF_IFMAN *ifman) Stream_Seek_UINT32(ifman->input); /* SampleFlags */ 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); + presentation = tsmf_presentation_find_by_id(ifman->presentation_id); - if(presentation == NULL) + + if (!presentation) { WLog_ERR(TAG, "unknown presentation id"); return 1; } + stream = tsmf_stream_find_by_id(presentation, StreamId); - if(stream == NULL) + + if (!stream) { WLog_ERR(TAG, "unknown stream id"); return 1; } + 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)); + tsmf_presentation_sync(presentation); ifman->output_pending = TRUE; + return 0; } -int tsmf_ifman_on_flush(TSMF_IFMAN *ifman) +int tsmf_ifman_on_flush(TSMF_IFMAN* ifman) { UINT32 StreamId; - TSMF_PRESENTATION *presentation; + TSMF_PRESENTATION* presentation; + Stream_Seek(ifman->input, 16); Stream_Read_UINT32(ifman->input, StreamId); + DEBUG_TSMF("StreamId %d", StreamId); + presentation = tsmf_presentation_find_by_id(ifman->presentation_id); - if(presentation == NULL) + + if (!presentation) { WLog_ERR(TAG, "unknown presentation id"); return 1; } + tsmf_presentation_flush(presentation); ifman->output_pending = TRUE; + return 0; } -int tsmf_ifman_on_end_of_stream(TSMF_IFMAN *ifman) +int tsmf_ifman_on_end_of_stream(TSMF_IFMAN* ifman) { UINT32 StreamId; - TSMF_STREAM *stream; - TSMF_PRESENTATION *presentation; + TSMF_STREAM* stream; + TSMF_PRESENTATION* presentation; + presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input)); + Stream_Seek(ifman->input, 16); Stream_Read_UINT32(ifman->input, StreamId); - if(presentation) + + if (presentation) { stream = tsmf_stream_find_by_id(presentation, StreamId); - if(stream) + + if (stream) tsmf_stream_end(stream); } + DEBUG_TSMF("StreamId %d", StreamId); Stream_EnsureRemainingCapacity(ifman->output, 16); Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */ @@ -449,74 +522,93 @@ int tsmf_ifman_on_end_of_stream(TSMF_IFMAN *ifman) Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_ENDOFSTREAM); /* EventId */ Stream_Write_UINT32(ifman->output, 0); /* cbData */ ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY; + return 0; } -int tsmf_ifman_on_playback_started(TSMF_IFMAN *ifman) +int tsmf_ifman_on_playback_started(TSMF_IFMAN* ifman) { - TSMF_PRESENTATION *presentation; + TSMF_PRESENTATION* presentation; + DEBUG_TSMF(""); + presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input)); - if(presentation) + + if (presentation) tsmf_presentation_start(presentation); else WLog_ERR(TAG, "unknown presentation id"); + Stream_EnsureRemainingCapacity(ifman->output, 16); 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 */ ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY; + return 0; } -int tsmf_ifman_on_playback_paused(TSMF_IFMAN *ifman) +int tsmf_ifman_on_playback_paused(TSMF_IFMAN* ifman) { - TSMF_PRESENTATION *presentation; + 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)); - if(presentation) + + if (presentation) tsmf_presentation_paused(presentation); else WLog_ERR(TAG, "unknown presentation id"); + return 0; } -int tsmf_ifman_on_playback_restarted(TSMF_IFMAN *ifman) +int tsmf_ifman_on_playback_restarted(TSMF_IFMAN* ifman) { - TSMF_PRESENTATION *presentation; + 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 (presentation) tsmf_presentation_restarted(presentation); else WLog_ERR(TAG, "unknown presentation id"); + return 0; } -int tsmf_ifman_on_playback_stopped(TSMF_IFMAN *ifman) +int tsmf_ifman_on_playback_stopped(TSMF_IFMAN* ifman) { - TSMF_PRESENTATION *presentation; + TSMF_PRESENTATION* presentation; + DEBUG_TSMF(""); + presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input)); - if(presentation) + + if (presentation) tsmf_presentation_stop(presentation); else WLog_ERR(TAG, "unknown presentation id"); + Stream_EnsureRemainingCapacity(ifman->output, 16); 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 0; } -int tsmf_ifman_on_playback_rate_changed(TSMF_IFMAN *ifman) +int tsmf_ifman_on_playback_rate_changed(TSMF_IFMAN* ifman) { DEBUG_TSMF(""); Stream_EnsureRemainingCapacity(ifman->output, 16); diff --git a/channels/tsmf/client/tsmf_main.c b/channels/tsmf/client/tsmf_main.c index 65ce35b4c..68e05e43a 100644 --- a/channels/tsmf/client/tsmf_main.c +++ b/channels/tsmf/client/tsmf_main.c @@ -21,14 +21,11 @@ #include "config.h" #endif -#include -#include -#include - #include +#include #include -#include +#include #include "tsmf_types.h" #include "tsmf_constants.h" @@ -37,81 +34,41 @@ #include "tsmf_main.h" -typedef struct _TSMF_LISTENER_CALLBACK TSMF_LISTENER_CALLBACK; - -typedef struct _TSMF_CHANNEL_CALLBACK TSMF_CHANNEL_CALLBACK; - -typedef struct _TSMF_PLUGIN TSMF_PLUGIN; - -struct _TSMF_LISTENER_CALLBACK -{ - IWTSListenerCallback iface; - - IWTSPlugin *plugin; - IWTSVirtualChannelManager *channel_mgr; -}; - -struct _TSMF_CHANNEL_CALLBACK -{ - IWTSVirtualChannelCallback iface; - - IWTSPlugin *plugin; - IWTSVirtualChannelManager *channel_mgr; - IWTSVirtualChannel *channel; - - BYTE presentation_id[GUID_SIZE]; - UINT32 stream_id; -}; - -struct _TSMF_PLUGIN -{ - IWTSPlugin iface; - - TSMF_LISTENER_CALLBACK *listener_callback; - - const char *decoder_name; - const char *audio_name; - const char *audio_device; -}; - void tsmf_playback_ack(IWTSVirtualChannelCallback *pChannelCallback, - UINT32 message_id, UINT64 duration, UINT32 data_size) + UINT32 message_id, UINT64 duration, UINT32 data_size) { wStream *s; int status = -1; TSMF_CHANNEL_CALLBACK *callback = (TSMF_CHANNEL_CALLBACK *) pChannelCallback; + s = Stream_New(NULL, 32); + Stream_Write_UINT32(s, TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY); Stream_Write_UINT32(s, message_id); Stream_Write_UINT32(s, PLAYBACK_ACK); /* FunctionId */ Stream_Write_UINT32(s, callback->stream_id); /* StreamId */ Stream_Write_UINT64(s, duration); /* DataDuration */ Stream_Write_UINT64(s, data_size); /* cbData */ + DEBUG_TSMF("response size %d", (int) Stream_GetPosition(s)); - if(!callback || !callback->channel || !callback->channel->Write) + + if (!callback || !callback->channel || !callback->channel->Write) + { WLog_ERR(TAG, "callback=%p, channel=%p, write=%p", callback, callback->channel, callback->channel->Write); + } else + { status = callback->channel->Write(callback->channel, - Stream_GetPosition(s), Stream_Buffer(s), NULL); - if(status) - { - WLog_ERR(TAG, "response error %d", status); + Stream_GetPosition(s), Stream_Buffer(s), NULL); } - Stream_Free(s, TRUE); -} -BOOL tsmf_push_event(IWTSVirtualChannelCallback *pChannelCallback, wMessage *event) -{ - int status; - TSMF_CHANNEL_CALLBACK *callback = (TSMF_CHANNEL_CALLBACK *) pChannelCallback; - status = callback->channel_mgr->PushEvent(callback->channel_mgr, event); - if(status) + if (status) { WLog_ERR(TAG, "response error %d", status); - return FALSE; } - return TRUE; + + Stream_Free(s, TRUE); } static int tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *data) @@ -128,7 +85,7 @@ static int tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, w UINT32 cbSize = Stream_GetRemainingLength(data); /* 2.2.1 Shared Message Header (SHARED_MSG_HEADER) */ - if(cbSize < 12) + if (cbSize < 12) { WLog_ERR(TAG, "invalid size. cbSize=%d", cbSize); return 1; @@ -137,17 +94,19 @@ static int tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, w input = data; output = Stream_New(NULL, 256); Stream_Seek(output, 8); - Stream_Read_UINT32(input, InterfaceId); - Stream_Read_UINT32(input, MessageId); - Stream_Read_UINT32(input, FunctionId); + Stream_Read_UINT32(input, InterfaceId); /* InterfaceId (4 bytes) */ + Stream_Read_UINT32(input, MessageId); /* MessageId (4 bytes) */ + Stream_Read_UINT32(input, FunctionId); /* FunctionId (4 bytes) */ + DEBUG_TSMF("cbSize=%d InterfaceId=0x%X MessageId=0x%X FunctionId=0x%X", cbSize, InterfaceId, MessageId, FunctionId); - memset(&ifman, 0, sizeof(TSMF_IFMAN)); + + ZeroMemory(&ifman, sizeof(TSMF_IFMAN)); ifman.channel_callback = pChannelCallback; - ifman.decoder_name = ((TSMF_PLUGIN *) callback->plugin)->decoder_name; - ifman.audio_name = ((TSMF_PLUGIN *) callback->plugin)->audio_name; - ifman.audio_device = ((TSMF_PLUGIN *) callback->plugin)->audio_device; - memcpy(ifman.presentation_id, callback->presentation_id, GUID_SIZE); + ifman.decoder_name = ((TSMF_PLUGIN*) callback->plugin)->decoder_name; + ifman.audio_name = ((TSMF_PLUGIN*) callback->plugin)->audio_name; + ifman.audio_device = ((TSMF_PLUGIN*) callback->plugin)->audio_device; + CopyMemory(ifman.presentation_id, callback->presentation_id, GUID_SIZE); ifman.stream_id = callback->stream_id; ifman.message_id = MessageId; ifman.input = input; @@ -155,23 +114,30 @@ static int tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, w ifman.output = output; ifman.output_pending = FALSE; ifman.output_interface_id = InterfaceId; - switch(InterfaceId) + + //fprintf(stderr, "InterfaceId: 0x%04X MessageId: 0x%04X FunctionId: 0x%04X\n", InterfaceId, MessageId, FunctionId); + + switch (InterfaceId) { case TSMF_INTERFACE_CAPABILITIES | STREAM_ID_NONE: - switch(FunctionId) + switch (FunctionId) { case RIM_EXCHANGE_CAPABILITY_REQUEST: status = tsmf_ifman_rim_exchange_capability_request(&ifman); break; + case RIMCALL_RELEASE: + case RIMCALL_QUERYINTERFACE: + break; default: break; } break; + case TSMF_INTERFACE_DEFAULT | STREAM_ID_PROXY: - switch(FunctionId) + switch (FunctionId) { case SET_CHANNEL_PARAMS: - memcpy(callback->presentation_id, Stream_Pointer(input), GUID_SIZE); + CopyMemory(callback->presentation_id, Stream_Pointer(input), GUID_SIZE); Stream_Seek(input, GUID_SIZE); Stream_Read_UINT32(input, callback->stream_id); DEBUG_TSMF("SET_CHANNEL_PARAMS StreamId=%d", callback->stream_id); @@ -244,19 +210,24 @@ static int tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, w case ON_PLAYBACK_RATE_CHANGED: status = tsmf_ifman_on_playback_rate_changed(&ifman); break; + case RIMCALL_RELEASE: + case RIMCALL_QUERYINTERFACE: + break; default: break; } break; + default: break; } input = NULL; ifman.input = NULL; - if(status == -1) + + if (status == -1) { - switch(FunctionId) + switch (FunctionId) { case RIMCALL_RELEASE: /* [MS-RDPEXPS] 2.2.2.2 Interface Release (IFACE_RELEASE) @@ -270,15 +241,17 @@ static int tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, w status = 0; break; } - if(status == -1) + + if (status == -1) { - WLog_ERR(TAG, "InterfaceId 0x%X FunctionId 0x%X not processed.", - InterfaceId, FunctionId); + WLog_ERR(TAG, "Unknown InterfaceId: 0x%04X MessageId: 0x%04X FunctionId: 0x%04X\n", InterfaceId, MessageId, FunctionId); /* When a request is not implemented we return empty response indicating error */ } + status = 0; } - if(status == 0 && !ifman.output_pending) + + if (status == 0 && !ifman.output_pending) { /* Response packet does not have FunctionId */ length = Stream_GetPosition(output); @@ -287,31 +260,37 @@ static int tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, w Stream_Write_UINT32(output, MessageId); DEBUG_TSMF("response size %d", length); status = callback->channel->Write(callback->channel, length, Stream_Buffer(output), NULL); - if(status) + + if (status) { WLog_ERR(TAG, "response error %d", status); } } + Stream_Free(output, TRUE); return status; } static int tsmf_on_close(IWTSVirtualChannelCallback *pChannelCallback) { - TSMF_STREAM *stream; - TSMF_PRESENTATION *presentation; - TSMF_CHANNEL_CALLBACK *callback = (TSMF_CHANNEL_CALLBACK *) pChannelCallback; + TSMF_STREAM* stream; + TSMF_PRESENTATION* presentation; + TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*) pChannelCallback; + DEBUG_TSMF(""); - if(callback->stream_id) + + if (callback->stream_id) { presentation = tsmf_presentation_find_by_id(callback->presentation_id); - if(presentation) + + if (presentation) { stream = tsmf_stream_find_by_id(presentation, callback->stream_id); - if(stream) + if (stream) tsmf_stream_free(stream); } } + free(pChannelCallback); return 0; } @@ -322,41 +301,63 @@ static int tsmf_on_new_channel_connection(IWTSListenerCallback *pListenerCallbac int *pbAccept, IWTSVirtualChannelCallback **ppCallback) { - TSMF_CHANNEL_CALLBACK *callback; - TSMF_LISTENER_CALLBACK *listener_callback = (TSMF_LISTENER_CALLBACK *) pListenerCallback; + TSMF_CHANNEL_CALLBACK* callback; + TSMF_LISTENER_CALLBACK* listener_callback = (TSMF_LISTENER_CALLBACK*) pListenerCallback; + DEBUG_TSMF(""); - callback = (TSMF_CHANNEL_CALLBACK *) malloc(sizeof(TSMF_CHANNEL_CALLBACK)); - ZeroMemory(callback, sizeof(TSMF_CHANNEL_CALLBACK)); + + callback = (TSMF_CHANNEL_CALLBACK*) calloc(1, sizeof(TSMF_CHANNEL_CALLBACK)); + + if (!callback) + return -1; + callback->iface.OnDataReceived = tsmf_on_data_received; callback->iface.OnClose = tsmf_on_close; callback->iface.OnOpen = NULL; callback->plugin = listener_callback->plugin; callback->channel_mgr = listener_callback->channel_mgr; callback->channel = pChannel; - *ppCallback = (IWTSVirtualChannelCallback *) callback; + + *ppCallback = (IWTSVirtualChannelCallback*) callback; + return 0; } -static int tsmf_plugin_initialize(IWTSPlugin *pPlugin, IWTSVirtualChannelManager *pChannelMgr) +static int tsmf_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr) { - TSMF_PLUGIN *tsmf = (TSMF_PLUGIN *) pPlugin; + int status; + TSMF_PLUGIN* tsmf = (TSMF_PLUGIN*) pPlugin; + DEBUG_TSMF(""); - tsmf->listener_callback = (TSMF_LISTENER_CALLBACK *) malloc(sizeof(TSMF_LISTENER_CALLBACK)); - ZeroMemory(tsmf->listener_callback, sizeof(TSMF_LISTENER_CALLBACK)); + + tsmf->listener_callback = (TSMF_LISTENER_CALLBACK*) calloc(1, sizeof(TSMF_LISTENER_CALLBACK)); + + if (!tsmf->listener_callback) + return -1; + tsmf->listener_callback->iface.OnNewChannelConnection = tsmf_on_new_channel_connection; tsmf->listener_callback->plugin = pPlugin; tsmf->listener_callback->channel_mgr = pChannelMgr; - return pChannelMgr->CreateListener(pChannelMgr, "TSMF", 0, - (IWTSListenerCallback *) tsmf->listener_callback, NULL); + + status = pChannelMgr->CreateListener(pChannelMgr, "TSMF", 0, + (IWTSListenerCallback*) tsmf->listener_callback, &(tsmf->listener)); + + tsmf->listener->pInterface = tsmf->iface.pInterface; + + return status; } -static int tsmf_plugin_terminated(IWTSPlugin *pPlugin) +static int tsmf_plugin_terminated(IWTSPlugin* pPlugin) { - TSMF_PLUGIN *tsmf = (TSMF_PLUGIN *) pPlugin; + TSMF_PLUGIN* tsmf = (TSMF_PLUGIN*) pPlugin; + DEBUG_TSMF(""); - if(tsmf->listener_callback) + + if (tsmf->listener_callback) free(tsmf->listener_callback); + free(tsmf); + return 0; } @@ -372,15 +373,18 @@ static void tsmf_process_addin_args(IWTSPlugin *pPlugin, ADDIN_ARGV *args) { int status; DWORD flags; - COMMAND_LINE_ARGUMENT_A *arg; - TSMF_PLUGIN *tsmf = (TSMF_PLUGIN *) pPlugin; + COMMAND_LINE_ARGUMENT_A* arg; + TSMF_PLUGIN* tsmf = (TSMF_PLUGIN*) pPlugin; + flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON; - status = CommandLineParseArgumentsA(args->argc, (const char **) args->argv, - tsmf_args, flags, tsmf, NULL, NULL); + + status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv, + tsmf_args, flags, tsmf, NULL, NULL); arg = tsmf_args; + do { - if(!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) + if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) continue; CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "audio") @@ -400,32 +404,50 @@ static void tsmf_process_addin_args(IWTSPlugin *pPlugin, ADDIN_ARGV *args) } CommandLineSwitchEnd(arg) } - while((arg = CommandLineFindNextArgumentA(arg)) != NULL); + while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); } #ifdef STATIC_CHANNELS #define DVCPluginEntry tsmf_DVCPluginEntry #endif -int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS *pEntryPoints) +int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) { int status = 0; - TSMF_PLUGIN *tsmf; - tsmf = (TSMF_PLUGIN *) pEntryPoints->GetPlugin(pEntryPoints, "tsmf"); - if(tsmf == NULL) + TSMF_PLUGIN* tsmf; + TsmfClientContext* context; + + tsmf = (TSMF_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "tsmf"); + + if (!tsmf) { - tsmf = (TSMF_PLUGIN *) malloc(sizeof(TSMF_PLUGIN)); - ZeroMemory(tsmf, sizeof(TSMF_PLUGIN)); + tsmf = (TSMF_PLUGIN*) calloc(1, sizeof(TSMF_PLUGIN)); + + if (!tsmf) + return -1; + tsmf->iface.Initialize = tsmf_plugin_initialize; tsmf->iface.Connected = NULL; tsmf->iface.Disconnected = NULL; tsmf->iface.Terminated = tsmf_plugin_terminated; - status = pEntryPoints->RegisterPlugin(pEntryPoints, "tsmf", (IWTSPlugin *) tsmf); + + context = (TsmfClientContext*) calloc(1, sizeof(TsmfClientContext)); + + if (!context) + return -1; + + context->handle = (void*) tsmf; + tsmf->iface.pInterface = (void*) context; + tsmf_media_init(); + + status = pEntryPoints->RegisterPlugin(pEntryPoints, "tsmf", (IWTSPlugin*) tsmf); } - if(status == 0) + + if (status == 0) { - tsmf_process_addin_args((IWTSPlugin *) tsmf, pEntryPoints->GetPluginData(pEntryPoints)); + tsmf_process_addin_args((IWTSPlugin*) tsmf, pEntryPoints->GetPluginData(pEntryPoints)); } + return status; } diff --git a/channels/tsmf/client/tsmf_main.h b/channels/tsmf/client/tsmf_main.h index d5de07f09..8c287c932 100644 --- a/channels/tsmf/client/tsmf_main.h +++ b/channels/tsmf/client/tsmf_main.h @@ -20,10 +20,46 @@ #ifndef __TSMF_MAIN_H #define __TSMF_MAIN_H +typedef struct _TSMF_LISTENER_CALLBACK TSMF_LISTENER_CALLBACK; + +typedef struct _TSMF_CHANNEL_CALLBACK TSMF_CHANNEL_CALLBACK; + +typedef struct _TSMF_PLUGIN TSMF_PLUGIN; + +struct _TSMF_LISTENER_CALLBACK +{ + IWTSListenerCallback iface; + + IWTSPlugin* plugin; + IWTSVirtualChannelManager* channel_mgr; +}; + +struct _TSMF_CHANNEL_CALLBACK +{ + IWTSVirtualChannelCallback iface; + + IWTSPlugin* plugin; + IWTSVirtualChannelManager* channel_mgr; + IWTSVirtualChannel* channel; + + BYTE presentation_id[GUID_SIZE]; + UINT32 stream_id; +}; + +struct _TSMF_PLUGIN +{ + IWTSPlugin iface; + + IWTSListener* listener; + TSMF_LISTENER_CALLBACK* listener_callback; + + const char* decoder_name; + const char* audio_name; + const char* audio_device; +}; + void tsmf_playback_ack(IWTSVirtualChannelCallback* pChannelCallback, - UINT32 message_id, UINT64 duration, UINT32 data_size); -BOOL tsmf_push_event(IWTSVirtualChannelCallback* pChannelCallback, - wMessage* event); + UINT32 message_id, UINT64 duration, UINT32 data_size); #endif diff --git a/channels/tsmf/client/tsmf_media.c b/channels/tsmf/client/tsmf_media.c index 6538983f6..fa4e06f12 100644 --- a/channels/tsmf/client/tsmf_media.c +++ b/channels/tsmf/client/tsmf_media.c @@ -22,8 +22,6 @@ #include "config.h" #endif -#include - #include #include #include @@ -43,7 +41,6 @@ #include #include -#include #include #include "tsmf_constants.h" @@ -87,7 +84,7 @@ struct _TSMF_STREAM { UINT32 stream_id; - TSMF_PRESENTATION *presentation; + TSMF_PRESENTATION* presentation; ITSMFDecoder *decoder; @@ -127,7 +124,7 @@ struct _TSMF_SAMPLE UINT32 decoded_size; UINT32 pixfmt; - TSMF_STREAM *stream; + TSMF_STREAM* stream; IWTSVirtualChannelCallback *channel_callback; UINT64 ack_time; }; @@ -135,8 +132,8 @@ struct _TSMF_SAMPLE static wArrayList *presentation_list = NULL; static int TERMINATING = 0; -static void _tsmf_presentation_free(TSMF_PRESENTATION *presentation); -static void _tsmf_stream_free(TSMF_STREAM *stream); +static void _tsmf_presentation_free(TSMF_PRESENTATION* presentation); +static void _tsmf_stream_free(TSMF_STREAM* stream); static UINT64 get_current_time(void) { @@ -145,15 +142,17 @@ static UINT64 get_current_time(void) return ((UINT64)tp.tv_sec) * 10000000LL + ((UINT64)tp.tv_usec) * 10LL; } -static TSMF_SAMPLE *tsmf_stream_pop_sample(TSMF_STREAM *stream, int sync) +static TSMF_SAMPLE* tsmf_stream_pop_sample(TSMF_STREAM* stream, int sync) { UINT32 index; UINT32 count; TSMF_STREAM *s; - TSMF_SAMPLE *sample; + TSMF_SAMPLE* sample; BOOL pending = FALSE; - TSMF_PRESENTATION *presentation = stream->presentation; - assert(stream); + TSMF_PRESENTATION* presentation = stream->presentation; + + if (!stream) + return NULL; if (Queue_Count(stream->sample_list) < 1) return NULL; @@ -211,8 +210,10 @@ static TSMF_SAMPLE *tsmf_stream_pop_sample(TSMF_STREAM *stream, int sync) static void tsmf_sample_free(void *arg) { - TSMF_SAMPLE *sample = arg; - assert(sample); + TSMF_SAMPLE* sample = arg; + + if (!sample) + return; if (sample->data) free(sample->data); @@ -220,28 +221,37 @@ static void tsmf_sample_free(void *arg) free(sample); } -static void tsmf_sample_ack(TSMF_SAMPLE *sample) +static void tsmf_sample_ack(TSMF_SAMPLE* sample) { - assert(sample); + if (!sample) + return; + tsmf_playback_ack(sample->channel_callback, sample->sample_id, sample->duration, sample->data_size); } -static void tsmf_sample_queue_ack(TSMF_SAMPLE *sample) +static void tsmf_sample_queue_ack(TSMF_SAMPLE* sample) { - assert(sample); - assert(sample->stream); + if (!sample) + return; + + if (!sample->stream) + return; + Queue_Enqueue(sample->stream->sample_ack_list, sample); } -static BOOL tsmf_stream_process_ack(void *arg, BOOL force) +static BOOL tsmf_stream_process_ack(void* arg, BOOL force) { - TSMF_STREAM *stream = arg; - TSMF_SAMPLE *sample; + TSMF_STREAM* stream = arg; + TSMF_SAMPLE* sample; UINT64 ack_time; BOOL rc = FALSE; - assert(stream); + + if (!stream) + return FALSE; + Queue_Lock(stream->sample_ack_list); - sample = (TSMF_SAMPLE *) Queue_Peek(stream->sample_ack_list); + sample = (TSMF_SAMPLE*) Queue_Peek(stream->sample_ack_list); if (!sample) goto finally; @@ -257,17 +267,20 @@ static BOOL tsmf_stream_process_ack(void *arg, BOOL force) sample = Queue_Dequeue(stream->sample_ack_list); tsmf_sample_ack(sample); tsmf_sample_free(sample); + finally: Queue_Unlock(stream->sample_ack_list); return rc; } -TSMF_PRESENTATION *tsmf_presentation_new(const BYTE *guid, IWTSVirtualChannelCallback *pChannelCallback) +TSMF_PRESENTATION* tsmf_presentation_new(const BYTE* guid, IWTSVirtualChannelCallback* pChannelCallback) { - TSMF_PRESENTATION *presentation; - assert(guid); - assert(pChannelCallback); - presentation = (TSMF_PRESENTATION *) calloc(1, sizeof(TSMF_PRESENTATION)); + TSMF_PRESENTATION* presentation; + + if (!guid || !pChannelCallback) + return NULL; + + presentation = (TSMF_PRESENTATION*) calloc(1, sizeof(TSMF_PRESENTATION)); if (!presentation) { @@ -280,15 +293,18 @@ TSMF_PRESENTATION *tsmf_presentation_new(const BYTE *guid, IWTSVirtualChannelCal presentation->volume = 5000; /* 50% */ presentation->stream_list = ArrayList_New(TRUE); ArrayList_Object(presentation->stream_list)->fnObjectFree = (OBJECT_FREE_FN) _tsmf_stream_free; + ArrayList_Add(presentation_list, presentation); + return presentation; } -static char *guid_to_string(const BYTE *guid, char *str, size_t len) +static char* guid_to_string(const BYTE* guid, char* str, size_t len) { int i; - assert(guid); - assert(str); + + if (!guid || !str) + return NULL; for (i=0; i 2*i; i++) snprintf(str + (2*i), len - 2*i, "%02X", guid[i]); @@ -296,19 +312,20 @@ static char *guid_to_string(const BYTE *guid, char *str, size_t len) return str; } -TSMF_PRESENTATION *tsmf_presentation_find_by_id(const BYTE *guid) +TSMF_PRESENTATION* tsmf_presentation_find_by_id(const BYTE *guid) { - char guid_str[GUID_SIZE * 2 + 1]; UINT32 index; UINT32 count; BOOL found = FALSE; - TSMF_PRESENTATION *presentation; + char guid_str[GUID_SIZE * 2 + 1]; + TSMF_PRESENTATION* presentation; + ArrayList_Lock(presentation_list); count = ArrayList_Count(presentation_list); for (index = 0; index < count; index++) { - presentation = (TSMF_PRESENTATION *) ArrayList_GetItem(presentation_list, index); + presentation = (TSMF_PRESENTATION*) ArrayList_GetItem(presentation_list, index); if (memcmp(presentation->presentation_id, guid, GUID_SIZE) == 0) { @@ -325,14 +342,17 @@ TSMF_PRESENTATION *tsmf_presentation_find_by_id(const BYTE *guid) return (found) ? presentation : NULL; } -static void tsmf_sample_playback_video(TSMF_SAMPLE *sample) +static void tsmf_sample_playback_video(TSMF_SAMPLE* sample) { UINT64 t; - RDP_VIDEO_FRAME_EVENT *vevent; - TSMF_STREAM *stream = sample->stream; - TSMF_PRESENTATION *presentation = stream->presentation; + TSMF_VIDEO_FRAME_EVENT event; + TSMF_STREAM* stream = sample->stream; + TSMF_PRESENTATION* presentation = stream->presentation; + TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*) sample->channel_callback; + TsmfClientContext* tsmf = (TsmfClientContext*) callback->plugin->pInterface; + DEBUG_TSMF("MessageId %d EndTime %d data_size %d consumed.", - sample->sample_id, (int)sample->end_time, sample->data_size); + sample->sample_id, (int) sample->end_time, sample->data_size); if (sample->data) { @@ -346,21 +366,21 @@ static void tsmf_sample_playback_video(TSMF_SAMPLE *sample) } stream->next_start_time = t + sample->duration - 50000; - vevent = (RDP_VIDEO_FRAME_EVENT *) freerdp_event_new(TsmfChannel_Class, TsmfChannel_VideoFrame, - NULL, NULL); - vevent->frame_data = sample->data; - vevent->frame_size = sample->decoded_size; - vevent->frame_pixfmt = sample->pixfmt; - vevent->frame_width = sample->stream->width; - vevent->frame_height = sample->stream->height; + + ZeroMemory(&event, sizeof(TSMF_VIDEO_FRAME_EVENT)); + + event.frameData = sample->data; + event.frameSize = sample->decoded_size; + event.framePixFmt = sample->pixfmt; + event.frameWidth = sample->stream->width; + event.frameHeight = sample->stream->height; + /* The frame data ownership is passed to the event object, and is freed after the event is processed. */ sample->data = NULL; sample->decoded_size = 0; - if (!tsmf_push_event(sample->channel_callback, (wMessage *) vevent)) - { - freerdp_event_free((wMessage *) vevent); - } + if (tsmf->FrameEvent) + tsmf->FrameEvent(tsmf, &event); #if 0 /* Dump a .ppm image for every 30 frames. Assuming the frame is in YUV format, we @@ -387,17 +407,17 @@ static void tsmf_sample_playback_video(TSMF_SAMPLE *sample) } } -static void tsmf_sample_playback_audio(TSMF_SAMPLE *sample) +static void tsmf_sample_playback_audio(TSMF_SAMPLE* sample) { UINT64 latency = 0; - TSMF_STREAM *stream = sample->stream; + TSMF_STREAM* stream = sample->stream; + DEBUG_TSMF("MessageId %d EndTime %d consumed.", sample->sample_id, (int)sample->end_time); if (sample->stream->audio && sample->data) { - sample->stream->audio->Play(sample->stream->audio, - sample->data, sample->decoded_size); + sample->stream->audio->Play(sample->stream->audio, sample->data, sample->decoded_size); sample->data = NULL; sample->decoded_size = 0; @@ -415,21 +435,25 @@ static void tsmf_sample_playback_audio(TSMF_SAMPLE *sample) stream->presentation->audio_end_time = sample->end_time + latency; } -static void tsmf_sample_playback(TSMF_SAMPLE *sample) +static void tsmf_sample_playback(TSMF_SAMPLE* sample) { BOOL ret = FALSE; UINT32 width; UINT32 height; UINT32 pixfmt = 0; - TSMF_STREAM *stream = sample->stream; + TSMF_STREAM* stream = sample->stream; if (stream->decoder) { if (stream->decoder->DecodeEx) + { ret = stream->decoder->DecodeEx(stream->decoder, sample->data, sample->data_size, sample->extensions, - sample->start_time, sample->end_time, sample->duration); + sample->start_time, sample->end_time, sample->duration); + } else + { ret = stream->decoder->Decode(stream->decoder, sample->data, sample->data_size, sample->extensions); + } } if (!ret) @@ -456,7 +480,7 @@ static void tsmf_sample_playback(TSMF_SAMPLE *sample) sample->pixfmt = pixfmt; } - ret = FALSE ; + ret = FALSE; if (stream->decoder->GetDecodedDimension) { @@ -490,7 +514,7 @@ static void tsmf_sample_playback(TSMF_SAMPLE *sample) } else { - TSMF_STREAM *stream = sample->stream; + TSMF_STREAM* stream = sample->stream; UINT64 ack_anticipation_time = get_current_time(); UINT64 currentRunningTime = sample->start_time; BOOL buffer_filled = TRUE; @@ -521,7 +545,9 @@ static void tsmf_sample_playback(TSMF_SAMPLE *sample) } } else + { ack_anticipation_time += sample->duration / 2; + } switch (sample->stream->major_type) { @@ -541,11 +567,12 @@ static void tsmf_sample_playback(TSMF_SAMPLE *sample) } } -static void *tsmf_stream_ack_func(void *arg) +static void* tsmf_stream_ack_func(void *arg) { - TSMF_STREAM *stream = (TSMF_STREAM *) arg; HANDLE hdl[2]; + TSMF_STREAM* stream = (TSMF_STREAM*) arg; DEBUG_TSMF("in %d", stream->stream_id); + hdl[0] = stream->stopEvent; hdl[1] = Queue_Event(stream->sample_ack_list); @@ -571,12 +598,13 @@ static void *tsmf_stream_ack_func(void *arg) return NULL; } -static void *tsmf_stream_playback_func(void *arg) +static void* tsmf_stream_playback_func(void *arg) { HANDLE hdl[2]; - TSMF_SAMPLE *sample; - TSMF_STREAM *stream = (TSMF_STREAM *) arg; - TSMF_PRESENTATION *presentation = stream->presentation; + TSMF_SAMPLE* sample; + TSMF_STREAM* stream = (TSMF_STREAM *) arg; + TSMF_PRESENTATION* presentation = stream->presentation; + DEBUG_TSMF("in %d", stream->stream_id); if (stream->major_type == TSMF_MAJOR_TYPE_AUDIO && @@ -587,13 +615,12 @@ static void *tsmf_stream_playback_func(void *arg) if (stream->decoder->GetDecodedData) { stream->audio = tsmf_load_audio_device( - presentation->audio_name && presentation->audio_name[0] ? presentation->audio_name : NULL, - presentation->audio_device && presentation->audio_device[0] ? presentation->audio_device : NULL); + presentation->audio_name && presentation->audio_name[0] ? presentation->audio_name : NULL, + presentation->audio_device && presentation->audio_device[0] ? presentation->audio_device : NULL); if (stream->audio) { - stream->audio->SetFormat(stream->audio, - stream->sample_rate, stream->channels, stream->bits_per_sample); + stream->audio->SetFormat(stream->audio, stream->sample_rate, stream->channels, stream->bits_per_sample); } } } @@ -621,7 +648,7 @@ static void *tsmf_stream_playback_func(void *arg) return NULL; } -static void tsmf_stream_start(TSMF_STREAM *stream) +static void tsmf_stream_start(TSMF_STREAM* stream) { if (!stream || !stream->presentation || !stream->decoder) return; @@ -632,7 +659,7 @@ static void tsmf_stream_start(TSMF_STREAM *stream) } } -static void tsmf_stream_stop(TSMF_STREAM *stream) +static void tsmf_stream_stop(TSMF_STREAM* stream) { if (!stream || !stream->decoder) return; @@ -643,7 +670,7 @@ static void tsmf_stream_stop(TSMF_STREAM *stream) } } -static void tsmf_stream_pause(TSMF_STREAM *stream) +static void tsmf_stream_pause(TSMF_STREAM* stream) { if (!stream || !stream->decoder) return; @@ -654,7 +681,7 @@ static void tsmf_stream_pause(TSMF_STREAM *stream) } } -static void tsmf_stream_restart(TSMF_STREAM *stream) +static void tsmf_stream_restart(TSMF_STREAM* stream) { if (!stream || !stream->decoder) return; @@ -665,7 +692,7 @@ static void tsmf_stream_restart(TSMF_STREAM *stream) } } -static void tsmf_stream_change_volume(TSMF_STREAM *stream, UINT32 newVolume, UINT32 muted) +static void tsmf_stream_change_volume(TSMF_STREAM* stream, UINT32 newVolume, UINT32 muted) { if (!stream || !stream->decoder) return; @@ -680,11 +707,11 @@ static void tsmf_stream_change_volume(TSMF_STREAM *stream, UINT32 newVolume, UIN } } -void tsmf_presentation_volume_changed(TSMF_PRESENTATION *presentation, UINT32 newVolume, UINT32 muted) +void tsmf_presentation_volume_changed(TSMF_PRESENTATION* presentation, UINT32 newVolume, UINT32 muted) { UINT32 index; UINT32 count; - TSMF_STREAM *stream; + TSMF_STREAM* stream; presentation->volume = newVolume; presentation->muted = muted; ArrayList_Lock(presentation->stream_list); @@ -699,11 +726,11 @@ void tsmf_presentation_volume_changed(TSMF_PRESENTATION *presentation, UINT32 ne ArrayList_Unlock(presentation->stream_list); } -void tsmf_presentation_paused(TSMF_PRESENTATION *presentation) +void tsmf_presentation_paused(TSMF_PRESENTATION* presentation) { UINT32 index; UINT32 count; - TSMF_STREAM *stream; + TSMF_STREAM* stream; ArrayList_Lock(presentation->stream_list); count = ArrayList_Count(presentation->stream_list); @@ -716,11 +743,11 @@ void tsmf_presentation_paused(TSMF_PRESENTATION *presentation) ArrayList_Unlock(presentation->stream_list); } -void tsmf_presentation_restarted(TSMF_PRESENTATION *presentation) +void tsmf_presentation_restarted(TSMF_PRESENTATION* presentation) { UINT32 index; UINT32 count; - TSMF_STREAM *stream; + TSMF_STREAM* stream; ArrayList_Lock(presentation->stream_list); count = ArrayList_Count(presentation->stream_list); @@ -733,11 +760,11 @@ void tsmf_presentation_restarted(TSMF_PRESENTATION *presentation) ArrayList_Unlock(presentation->stream_list); } -void tsmf_presentation_start(TSMF_PRESENTATION *presentation) +void tsmf_presentation_start(TSMF_PRESENTATION* presentation) { UINT32 index; UINT32 count; - TSMF_STREAM *stream; + TSMF_STREAM* stream; ArrayList_Lock(presentation->stream_list); count = ArrayList_Count(presentation->stream_list); @@ -750,7 +777,7 @@ void tsmf_presentation_start(TSMF_PRESENTATION *presentation) ArrayList_Unlock(presentation->stream_list); } -void tsmf_presentation_sync(TSMF_PRESENTATION *presentation) +void tsmf_presentation_sync(TSMF_PRESENTATION* presentation) { UINT32 index; UINT32 count; @@ -759,18 +786,18 @@ void tsmf_presentation_sync(TSMF_PRESENTATION *presentation) for (index = 0; index < count; index++) { - TSMF_STREAM *stream = (TSMF_STREAM *) ArrayList_GetItem(presentation->stream_list, index); + TSMF_STREAM* stream = (TSMF_STREAM *) ArrayList_GetItem(presentation->stream_list, index); WaitForSingleObject(stream->ready, 500); } ArrayList_Unlock(presentation->stream_list); } -void tsmf_presentation_stop(TSMF_PRESENTATION *presentation) +void tsmf_presentation_stop(TSMF_PRESENTATION* presentation) { UINT32 index; UINT32 count; - TSMF_STREAM *stream; + TSMF_STREAM* stream; tsmf_presentation_flush(presentation); ArrayList_Lock(presentation->stream_list); count = ArrayList_Count(presentation->stream_list); @@ -784,12 +811,12 @@ void tsmf_presentation_stop(TSMF_PRESENTATION *presentation) ArrayList_Unlock(presentation->stream_list); } -void tsmf_presentation_set_geometry_info(TSMF_PRESENTATION *presentation, +void tsmf_presentation_set_geometry_info(TSMF_PRESENTATION* presentation, UINT32 x, UINT32 y, UINT32 width, UINT32 height, int num_rects, RDP_RECT *rects) { UINT32 index; UINT32 count; - TSMF_STREAM *stream; + TSMF_STREAM* stream; /* The server may send messages with invalid width / height. * Ignore those messages. */ @@ -812,7 +839,7 @@ void tsmf_presentation_set_geometry_info(TSMF_PRESENTATION *presentation, presentation->rects = realloc(presentation->rects, sizeof(RDP_RECT) * num_rects); if (presentation->rects) - memcpy(presentation->rects, rects, sizeof(RDP_RECT) * num_rects); + CopyMemory(presentation->rects, rects, sizeof(RDP_RECT) * num_rects); ArrayList_Lock(presentation->stream_list); count = ArrayList_Count(presentation->stream_list); @@ -833,13 +860,13 @@ void tsmf_presentation_set_geometry_info(TSMF_PRESENTATION *presentation, ArrayList_Unlock(presentation->stream_list); } -void tsmf_presentation_set_audio_device(TSMF_PRESENTATION *presentation, const char *name, const char *device) +void tsmf_presentation_set_audio_device(TSMF_PRESENTATION* presentation, const char *name, const char *device) { presentation->audio_name = name; presentation->audio_device = device; } -static void tsmf_stream_flush(TSMF_STREAM *stream) +static void tsmf_stream_flush(TSMF_STREAM* stream) { //TSMF_SAMPLE* sample; /* TODO: free lists */ @@ -857,17 +884,17 @@ static void tsmf_stream_flush(TSMF_STREAM *stream) } } -void tsmf_presentation_flush(TSMF_PRESENTATION *presentation) +void tsmf_presentation_flush(TSMF_PRESENTATION* presentation) { UINT32 index; UINT32 count; - TSMF_STREAM *stream; + TSMF_STREAM* stream; ArrayList_Lock(presentation->stream_list); count = ArrayList_Count(presentation->stream_list); for (index = 0; index < count; index++) { - stream = (TSMF_STREAM *) ArrayList_GetItem(presentation->stream_list, index); + stream = (TSMF_STREAM*) ArrayList_GetItem(presentation->stream_list, index); tsmf_stream_flush(stream); } @@ -877,7 +904,7 @@ void tsmf_presentation_flush(TSMF_PRESENTATION *presentation) presentation->audio_end_time = 0; } -void _tsmf_presentation_free(TSMF_PRESENTATION *presentation) +void _tsmf_presentation_free(TSMF_PRESENTATION* presentation) { tsmf_presentation_stop(presentation); ArrayList_Clear(presentation->stream_list); @@ -886,18 +913,18 @@ void _tsmf_presentation_free(TSMF_PRESENTATION *presentation) if (presentation->rects) free(presentation->rects); - memset(presentation, 0, sizeof(TSMF_PRESENTATION)); + ZeroMemory(presentation, sizeof(TSMF_PRESENTATION)); free(presentation); } -void tsmf_presentation_free(TSMF_PRESENTATION *presentation) +void tsmf_presentation_free(TSMF_PRESENTATION* presentation) { ArrayList_Remove(presentation_list, presentation); } -TSMF_STREAM *tsmf_stream_new(TSMF_PRESENTATION *presentation, UINT32 stream_id) +TSMF_STREAM* tsmf_stream_new(TSMF_PRESENTATION* presentation, UINT32 stream_id) { - TSMF_STREAM *stream; + TSMF_STREAM* stream; stream = tsmf_stream_find_by_id(presentation, stream_id); if (stream) @@ -906,7 +933,7 @@ TSMF_STREAM *tsmf_stream_new(TSMF_PRESENTATION *presentation, UINT32 stream_id) return NULL; } - stream = (TSMF_STREAM *) calloc(1, sizeof(TSMF_STREAM)); + stream = (TSMF_STREAM*) calloc(1, sizeof(TSMF_STREAM)); if (!stream) { @@ -922,26 +949,27 @@ TSMF_STREAM *tsmf_stream_new(TSMF_PRESENTATION *presentation, UINT32 stream_id) stream->sample_list->object.fnObjectFree = tsmf_sample_free; stream->sample_ack_list = Queue_New(TRUE, -1, -1); 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->ack_thread = CreateThread(NULL, 0, - (LPTHREAD_START_ROUTINE)tsmf_stream_ack_func, stream, 0, NULL); + stream->play_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) tsmf_stream_playback_func, stream, 0, NULL); + stream->ack_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)tsmf_stream_ack_func, stream, 0, NULL); + ArrayList_Add(presentation->stream_list, stream); + return stream; } -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; BOOL found = FALSE; - TSMF_STREAM *stream; + TSMF_STREAM* stream; + ArrayList_Lock(presentation->stream_list); count = ArrayList_Count(presentation->stream_list); for (index = 0; index < count; index++) { - stream = (TSMF_STREAM *) ArrayList_GetItem(presentation->stream_list, index); + stream = (TSMF_STREAM*) ArrayList_GetItem(presentation->stream_list, index); if (stream->stream_id == stream_id) { @@ -956,11 +984,11 @@ TSMF_STREAM *tsmf_stream_find_by_id(TSMF_PRESENTATION *presentation, UINT32 stre static void tsmf_stream_resync(void *arg) { - TSMF_STREAM *stream = arg; + TSMF_STREAM* stream = arg; ResetEvent(stream->ready); } -void tsmf_stream_set_format(TSMF_STREAM *stream, const char *name, wStream *s) +void tsmf_stream_set_format(TSMF_STREAM* stream, const char *name, wStream *s) { TS_AM_MEDIA_TYPE mediatype; @@ -1008,16 +1036,20 @@ void tsmf_stream_set_format(TSMF_STREAM *stream, const char *name, wStream *s) stream->decoder->SetSyncFunc(stream->decoder, tsmf_stream_resync, stream); } -void tsmf_stream_end(TSMF_STREAM *stream) +void tsmf_stream_end(TSMF_STREAM* stream) { - assert(stream); + if (!stream) + return; + stream->eos = 1; stream->presentation->eos = 1; } -void _tsmf_stream_free(TSMF_STREAM *stream) +void _tsmf_stream_free(TSMF_STREAM* stream) { - assert(stream); + if (!stream) + return; + tsmf_stream_stop(stream); tsmf_stream_flush(stream); SetEvent(stream->stopEvent); @@ -1047,27 +1079,27 @@ void _tsmf_stream_free(TSMF_STREAM *stream) CloseHandle(stream->stopEvent); CloseHandle(stream->ready); - memset(stream, 0, sizeof(TSMF_STREAM)); + ZeroMemory(stream, sizeof(TSMF_STREAM)); free(stream); } -void tsmf_stream_free(TSMF_STREAM *stream) +void tsmf_stream_free(TSMF_STREAM* stream) { - TSMF_PRESENTATION *presentation = stream->presentation; + TSMF_PRESENTATION* presentation = stream->presentation; ArrayList_Remove(presentation->stream_list, stream); } -void 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) +void 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) { - TSMF_SAMPLE *sample; + TSMF_SAMPLE* sample; SetEvent(stream->ready); if (TERMINATING) return; - sample = (TSMF_SAMPLE *) calloc(1, sizeof(TSMF_SAMPLE)); + sample = (TSMF_SAMPLE*) calloc(1, sizeof(TSMF_SAMPLE)); if (!sample) { diff --git a/client/Mac/CMakeLists.txt b/client/Mac/CMakeLists.txt index 863ec827a..8f0aca4dc 100644 --- a/client/Mac/CMakeLists.txt +++ b/client/Mac/CMakeLists.txt @@ -32,6 +32,7 @@ set(${MODULE_PREFIX}_OBJECTIVE_SOURCES MRDPCursor.m MRDPView.m Keyboard.m + Clipboard.m PasswordDialog.m) list(APPEND ${MODULE_PREFIX}_SOURCES ${${MODULE_PREFIX}_OBJECTIVE_SOURCES}) @@ -42,6 +43,7 @@ set(${MODULE_PREFIX}_HEADERS MRDPCursor.h MRDPView.h Keyboard.h + Clipboard.h PasswordDialog.h) set(${MODULE_PREFIX}_RESOURCES "en.lproj/InfoPlist.strings") diff --git a/client/Mac/Clipboard.h b/client/Mac/Clipboard.h new file mode 100644 index 000000000..2445ab8e9 --- /dev/null +++ b/client/Mac/Clipboard.h @@ -0,0 +1,29 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * Copyright 2014 Marc-Andre Moreau + * + * 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. + */ + +#import "mfreerdp.h" +#import "mf_client.h" + +#import "freerdp/freerdp.h" +#import "freerdp/channels/channels.h" +#import "freerdp/client/cliprdr.h" + +int mac_cliprdr_send_client_format_list(CliprdrClientContext* cliprdr); + +void mac_cliprdr_init(mfContext* mfc, CliprdrClientContext* cliprdr); +void mac_cliprdr_uninit(mfContext* mfc, CliprdrClientContext* cliprdr); diff --git a/client/Mac/Clipboard.m b/client/Mac/Clipboard.m new file mode 100644 index 000000000..d0e9575b0 --- /dev/null +++ b/client/Mac/Clipboard.m @@ -0,0 +1,328 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * Copyright 2014 Marc-Andre Moreau + * + * 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. + */ + +#import "Clipboard.h" + +int mac_cliprdr_send_client_format_list(CliprdrClientContext* cliprdr) +{ + UINT32 index; + UINT32 formatId; + UINT32 numFormats; + UINT32* pFormatIds; + const char* formatName; + CLIPRDR_FORMAT* formats; + CLIPRDR_FORMAT_LIST formatList; + mfContext* mfc = (mfContext*) cliprdr->custom; + + ZeroMemory(&formatList, sizeof(CLIPRDR_FORMAT_LIST)); + + pFormatIds = NULL; + numFormats = ClipboardGetFormatIds(mfc->clipboard, &pFormatIds); + + formats = (CLIPRDR_FORMAT*) calloc(numFormats, sizeof(CLIPRDR_FORMAT)); + + if (!formats) + return -1; + + for (index = 0; index < numFormats; index++) + { + formatId = pFormatIds[index]; + formatName = ClipboardGetFormatName(mfc->clipboard, formatId); + + formats[index].formatId = formatId; + formats[index].formatName = NULL; + + if ((formatId > CF_MAX) && formatName) + formats[index].formatName = _strdup(formatName); + } + + formatList.msgFlags = CB_RESPONSE_OK; + formatList.numFormats = numFormats; + formatList.formats = formats; + + mfc->cliprdr->ClientFormatList(mfc->cliprdr, &formatList); + + free(pFormatIds); + free(formats); + + return 1; +} + +int mac_cliprdr_send_client_format_data_request(CliprdrClientContext* cliprdr, UINT32 formatId) +{ + CLIPRDR_FORMAT_DATA_REQUEST formatDataRequest; + mfContext* mfc = (mfContext*) cliprdr->custom; + + ZeroMemory(&formatDataRequest, sizeof(CLIPRDR_FORMAT_DATA_REQUEST)); + + formatDataRequest.msgType = CB_FORMAT_DATA_REQUEST; + formatDataRequest.msgFlags = 0; + + formatDataRequest.requestedFormatId = formatId; + mfc->requestedFormatId = formatId; + ResetEvent(mfc->clipboardRequestEvent); + + cliprdr->ClientFormatDataRequest(cliprdr, &formatDataRequest); + + return 1; +} + +int mac_cliprdr_send_client_capabilities(CliprdrClientContext* cliprdr) +{ + CLIPRDR_CAPABILITIES capabilities; + CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet; + + capabilities.cCapabilitiesSets = 1; + capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET*) &(generalCapabilitySet); + + generalCapabilitySet.capabilitySetType = CB_CAPSTYPE_GENERAL; + generalCapabilitySet.capabilitySetLength = 12; + + generalCapabilitySet.version = CB_CAPS_VERSION_2; + generalCapabilitySet.generalFlags = CB_USE_LONG_FORMAT_NAMES; + + cliprdr->ClientCapabilities(cliprdr, &capabilities); + + return 1; +} + +int mac_cliprdr_monitor_ready(CliprdrClientContext* cliprdr, CLIPRDR_MONITOR_READY* monitorReady) +{ + mfContext* mfc = (mfContext*) cliprdr->custom; + + mfc->clipboardSync = TRUE; + mac_cliprdr_send_client_capabilities(cliprdr); + mac_cliprdr_send_client_format_list(cliprdr); + + return 1; +} + +int mac_cliprdr_server_capabilities(CliprdrClientContext* cliprdr, CLIPRDR_CAPABILITIES* capabilities) +{ + UINT32 index; + CLIPRDR_CAPABILITY_SET* capabilitySet; + mfContext* mfc = (mfContext*) cliprdr->custom; + + for (index = 0; index < capabilities->cCapabilitiesSets; index++) + { + capabilitySet = &(capabilities->capabilitySets[index]); + + if ((capabilitySet->capabilitySetType == CB_CAPSTYPE_GENERAL) && + (capabilitySet->capabilitySetLength >= CB_CAPSTYPE_GENERAL_LEN)) + { + CLIPRDR_GENERAL_CAPABILITY_SET* generalCapabilitySet + = (CLIPRDR_GENERAL_CAPABILITY_SET*) capabilitySet; + + mfc->clipboardCapabilities = generalCapabilitySet->generalFlags; + break; + } + } + + return 1; +} + +int mac_cliprdr_server_format_list(CliprdrClientContext* cliprdr, CLIPRDR_FORMAT_LIST* formatList) +{ + UINT32 index; + CLIPRDR_FORMAT* format; + mfContext* mfc = (mfContext*) cliprdr->custom; + + if (mfc->serverFormats) + { + for (index = 0; index < mfc->numServerFormats; index++) + { + free(mfc->serverFormats[index].formatName); + } + + free(mfc->serverFormats); + mfc->serverFormats = NULL; + mfc->numServerFormats = 0; + } + + if (formatList->numFormats < 1) + return 1; + + mfc->numServerFormats = formatList->numFormats; + mfc->serverFormats = (CLIPRDR_FORMAT*) calloc(mfc->numServerFormats, sizeof(CLIPRDR_FORMAT)); + + if (!mfc->serverFormats) + return -1; + + for (index = 0; index < mfc->numServerFormats; index++) + { + mfc->serverFormats[index].formatId = formatList->formats[index].formatId; + mfc->serverFormats[index].formatName = NULL; + + if (formatList->formats[index].formatName) + mfc->serverFormats[index].formatName = _strdup(formatList->formats[index].formatName); + } + + for (index = 0; index < mfc->numServerFormats; index++) + { + format = &(mfc->serverFormats[index]); + + if (format->formatId == CF_UNICODETEXT) + { + mac_cliprdr_send_client_format_data_request(cliprdr, CF_UNICODETEXT); + break; + } + else if (format->formatId == CF_TEXT) + { + mac_cliprdr_send_client_format_data_request(cliprdr, CF_TEXT); + break; + } + } + + return 1; +} + +int mac_cliprdr_server_format_list_response(CliprdrClientContext* cliprdr, CLIPRDR_FORMAT_LIST_RESPONSE* formatListResponse) +{ + return 1; +} + +int mac_cliprdr_server_lock_clipboard_data(CliprdrClientContext* cliprdr, CLIPRDR_LOCK_CLIPBOARD_DATA* lockClipboardData) +{ + return 1; +} + +int mac_cliprdr_server_unlock_clipboard_data(CliprdrClientContext* cliprdr, CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockClipboardData) +{ + return 1; +} + +int mac_cliprdr_server_format_data_request(CliprdrClientContext* cliprdr, CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest) +{ + BYTE* data; + UINT32 size; + UINT32 formatId; + CLIPRDR_FORMAT_DATA_RESPONSE response; + mfContext* mfc = (mfContext*) cliprdr->custom; + + ZeroMemory(&response, sizeof(CLIPRDR_FORMAT_DATA_RESPONSE)); + + formatId = formatDataRequest->requestedFormatId; + data = (BYTE*) ClipboardGetData(mfc->clipboard, formatId, &size); + + response.msgFlags = CB_RESPONSE_OK; + response.dataLen = size; + response.requestedFormatData = data; + + if (!data) + { + response.msgFlags = CB_RESPONSE_FAIL; + response.dataLen = 0; + response.requestedFormatData = NULL; + } + + cliprdr->ClientFormatDataResponse(cliprdr, &response); + + free(data); + + return 1; +} + +int mac_cliprdr_server_format_data_response(CliprdrClientContext* cliprdr, CLIPRDR_FORMAT_DATA_RESPONSE* formatDataResponse) +{ + BYTE* data; + UINT32 size; + UINT32 index; + UINT32 formatId; + CLIPRDR_FORMAT* format = NULL; + mfContext* mfc = (mfContext*) cliprdr->custom; + MRDPView* view = (MRDPView*) mfc->view; + + for (index = 0; index < mfc->numServerFormats; index++) + { + if (mfc->requestedFormatId == mfc->serverFormats[index].formatId) + format = &(mfc->serverFormats[index]); + } + + if (!format) + { + SetEvent(mfc->clipboardRequestEvent); + return -1; + } + + if (format->formatName) + formatId = ClipboardRegisterFormat(mfc->clipboard, format->formatName); + else + formatId = format->formatId; + + size = formatDataResponse->dataLen; + data = (BYTE*) malloc(size); + CopyMemory(data, formatDataResponse->requestedFormatData, size); + + ClipboardSetData(mfc->clipboard, formatId, data, size); + + SetEvent(mfc->clipboardRequestEvent); + + if ((formatId == CF_TEXT) || (formatId == CF_UNICODETEXT)) + { + formatId = ClipboardRegisterFormat(mfc->clipboard, "UTF8_STRING"); + + data = (void*) ClipboardGetData(mfc->clipboard, formatId, &size); + NSString* str = [[NSString alloc] initWithBytes: (void*) data length:size encoding:NSUTF8StringEncoding]; + free(data); + + NSArray* types = [[NSArray alloc] initWithObjects:NSStringPboardType, nil]; + [view->pasteboard_wr declareTypes:types owner:view]; + [view->pasteboard_wr setString:str forType:NSStringPboardType]; + } + + return 1; +} + +int mac_cliprdr_server_file_contents_request(CliprdrClientContext* cliprdr, CLIPRDR_FILE_CONTENTS_REQUEST* fileContentsRequest) +{ + return 1; +} + +int mac_cliprdr_server_file_contents_response(CliprdrClientContext* cliprdr, CLIPRDR_FILE_CONTENTS_RESPONSE* fileContentsResponse) +{ + return 1; +} + +void mac_cliprdr_init(mfContext* mfc, CliprdrClientContext* cliprdr) +{ + cliprdr->custom = (void*) mfc; + mfc->cliprdr = cliprdr; + + mfc->clipboard = ClipboardCreate(); + mfc->clipboardRequestEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + cliprdr->MonitorReady = mac_cliprdr_monitor_ready; + cliprdr->ServerCapabilities = mac_cliprdr_server_capabilities; + cliprdr->ServerFormatList = mac_cliprdr_server_format_list; + cliprdr->ServerFormatListResponse = mac_cliprdr_server_format_list_response; + cliprdr->ServerLockClipboardData = mac_cliprdr_server_lock_clipboard_data; + cliprdr->ServerUnlockClipboardData = mac_cliprdr_server_unlock_clipboard_data; + cliprdr->ServerFormatDataRequest = mac_cliprdr_server_format_data_request; + cliprdr->ServerFormatDataResponse = mac_cliprdr_server_format_data_response; + cliprdr->ServerFileContentsRequest = mac_cliprdr_server_file_contents_request; + cliprdr->ServerFileContentsResponse = mac_cliprdr_server_file_contents_response; +} + +void mac_cliprdr_uninit(mfContext* mfc, CliprdrClientContext* cliprdr) +{ + cliprdr->custom = NULL; + mfc->cliprdr = NULL; + + ClipboardDestroy(mfc->clipboard); + CloseHandle(mfc->clipboardRequestEvent); +} diff --git a/client/Mac/MRDPView.h b/client/Mac/MRDPView.h index 70ef3130d..7231d0657 100644 --- a/client/Mac/MRDPView.h +++ b/client/Mac/MRDPView.h @@ -51,8 +51,8 @@ BOOL skipMoveWindowOnce; @public - NSPasteboard* pasteboard_rd; /* for reading from clipboard */ - NSPasteboard* pasteboard_wr; /* for writing to clipboard */ + NSPasteboard* pasteboard_rd; + NSPasteboard* pasteboard_wr; int pasteboard_changecount; int pasteboard_format; int is_connected; @@ -63,6 +63,8 @@ - (void) setScrollOffset:(int)xOffset y:(int)yOffset w:(int)width h:(int)height; - (void) onPasteboardTimerFired :(NSTimer *) timer; +- (void) pause; +- (void) resume; - (void) releaseResources; @property (assign) int is_connected; diff --git a/client/Mac/MRDPView.m b/client/Mac/MRDPView.m index ded7f9b9a..4d963253b 100644 --- a/client/Mac/MRDPView.m +++ b/client/Mac/MRDPView.m @@ -23,6 +23,7 @@ #import "mfreerdp.h" #import "MRDPView.h" #import "MRDPCursor.h" +#import "Clipboard.h" #import "PasswordDialog.h" #include @@ -39,8 +40,6 @@ #import "freerdp/gdi/dc.h" #import "freerdp/gdi/region.h" #import "freerdp/graphics.h" -#import "freerdp/utils/event.h" -#import "freerdp/client/cliprdr.h" #import "freerdp/client/file.h" #import "freerdp/client/cmdline.h" #import "freerdp/log.h" @@ -59,39 +58,9 @@ void mac_desktop_resize(rdpContext* context); static void update_activity_cb(freerdp* instance); static void input_activity_cb(freerdp* instance); -static void channel_activity_cb(freerdp* instance); - -int process_plugin_args(rdpSettings* settings, const char* name, RDP_PLUGIN_DATA* plugin_data, void* user_data); -int receive_channel_data(freerdp* instance, int chan_id, BYTE* data, int size, int flags, int total_size); - -void process_cliprdr_event(freerdp* instance, wMessage* event); -void cliprdr_process_cb_format_list_event(freerdp* instance, RDP_CB_FORMAT_LIST_EVENT* event); -void cliprdr_send_data_request(freerdp* instance, UINT32 format); -void cliprdr_process_cb_monitor_ready_event(freerdp* inst); -void cliprdr_process_cb_data_response_event(freerdp* instance, RDP_CB_DATA_RESPONSE_EVENT* event); -void cliprdr_process_text(freerdp* instance, BYTE* data, int len); -void cliprdr_send_supported_format_list(freerdp* instance); -int register_channel_fds(int* fds, int count, freerdp* instance); DWORD mac_client_thread(void* param); -struct cursor -{ - rdpPointer* pointer; - BYTE* cursor_data; - void* bmiRep; /* NSBitmapImageRep */ - void* nsCursor; /* NSCursor */ - void* nsImage; /* NSImage */ -}; - -struct rgba_data -{ - char red; - char green; - char blue; - char alpha; -}; - @implementation MRDPView @synthesize is_connected; @@ -183,43 +152,6 @@ DWORD mac_client_input_thread(void* param) return 0; } -DWORD mac_client_channels_thread(void* param) -{ - int status; - wMessage* event; - HANDLE channelsEvent; - rdpChannels* channels; - rdpContext* context = (rdpContext*) param; - - channels = context->channels; - channelsEvent = freerdp_channels_get_event_handle(context->instance); - - while (WaitForSingleObject(channelsEvent, INFINITE) == WAIT_OBJECT_0) - { - status = freerdp_channels_process_pending_messages(context->instance); - - if (!status) - break; - - event = freerdp_channels_pop_event(context->channels); - - if (event) - { - switch (GetMessageClass(event->id)) - { - case CliprdrChannel_Class: - process_cliprdr_event(context->instance, event); - break; - } - - freerdp_event_free(event); - } - } - - ExitThread(0); - return 0; -} - DWORD mac_client_thread(void* param) { @autoreleasepool @@ -231,7 +163,6 @@ DWORD mac_client_thread(void* param) HANDLE updateEvent; HANDLE updateThread; HANDLE channelsEvent; - HANDLE channelsThread; DWORD nCount; rdpContext* context = (rdpContext*) param; @@ -272,14 +203,7 @@ DWORD mac_client_thread(void* param) events[nCount++] = inputEvent = freerdp_get_message_queue_event_handle(instance, FREERDP_INPUT_MESSAGE_QUEUE); } - if (settings->AsyncChannels) - { - channelsThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) mac_client_channels_thread, context, 0, NULL); - } - else - { - events[nCount++] = channelsEvent = freerdp_channels_get_event_handle(instance); - } + events[nCount++] = channelsEvent = freerdp_channels_get_event_handle(instance); while (1) { @@ -307,12 +231,9 @@ DWORD mac_client_thread(void* param) } } - if (!settings->AsyncChannels) + if (WaitForSingleObject(channelsEvent, 0) == WAIT_OBJECT_0) { - if (WaitForSingleObject(channelsEvent, 0) == WAIT_OBJECT_0) - { - channel_activity_cb(instance); - } + freerdp_channels_process_pending_messages(instance); } } @@ -332,12 +253,6 @@ DWORD mac_client_thread(void* param) CloseHandle(inputThread); } - if (settings->AsyncChannels) - { - WaitForSingleObject(channelsThread, INFINITE); - CloseHandle(channelsThread); - } - ExitThread(0); return 0; } @@ -798,21 +713,87 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) - (void) onPasteboardTimerFired :(NSTimer*) timer { - int i; - NSArray* types; + BYTE* data; + UINT32 size; + UINT32 formatId; + BOOL formatMatch; + int changeCount; + NSData* formatData; + const char* formatType; + NSPasteboardItem* item; - i = (int) [pasteboard_rd changeCount]; + changeCount = (int) [pasteboard_rd changeCount]; - if (i != pasteboard_changecount) + if (changeCount == pasteboard_changecount) + return; + + pasteboard_changecount = changeCount; + + NSArray* items = [pasteboard_rd pasteboardItems]; + + if ([items count] < 1) + return; + + item = [items objectAtIndex:0]; + + /** + * System-Declared Uniform Type Identifiers: + * https://developer.apple.com/library/ios/documentation/Miscellaneous/Reference/UTIRef/Articles/System-DeclaredUniformTypeIdentifiers.html + */ + + formatMatch = FALSE; + + for (NSString* type in [item types]) { - pasteboard_changecount = i; - types = [NSArray arrayWithObject:NSStringPboardType]; - NSString *str = [pasteboard_rd availableTypeFromArray:types]; - if (str != nil) + formatType = [type UTF8String]; + + if (strcmp(formatType, "public.utf8-plain-text") == 0) { - cliprdr_send_supported_format_list(instance); + formatData = [item dataForType:type]; + formatId = ClipboardRegisterFormat(mfc->clipboard, "UTF8_STRING"); + + size = (UINT32) [formatData length]; + + data = (BYTE*) malloc(size); + [formatData getBytes:data length:size]; + + ClipboardSetData(mfc->clipboard, formatId, (void*) data, size); + formatMatch = TRUE; + + break; } } + + if (!formatMatch) + ClipboardEmpty(mfc->clipboard); + + if (mfc->clipboardSync) + mac_cliprdr_send_client_format_list(mfc->cliprdr); +} + +- (void) pause +{ + dispatch_async(dispatch_get_main_queue(), ^{ + [self->pasteboard_timer invalidate]; + }); + + NSArray* trackingAreas = self.trackingAreas; + + for (NSTrackingArea* ta in trackingAreas) + { + [self removeTrackingArea:ta]; + } +} + +- (void)resume +{ + dispatch_async(dispatch_get_main_queue(), ^{ + self->pasteboard_timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(onPasteboardTimerFired:) userInfo:nil repeats:YES]; + }); + + NSTrackingArea * trackingArea = [[NSTrackingArea alloc] initWithRect:[self visibleRect] options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingCursorUpdate | NSTrackingEnabledDuringMouseDrag | NSTrackingActiveWhenFirstResponder owner:self userInfo:nil]; + [self addTrackingArea:trackingArea]; + [trackingArea release]; } - (void) setScrollOffset:(int)xOffset y:(int)yOffset w:(int)width h:(int)height @@ -826,6 +807,7 @@ DWORD fixKeyCode(DWORD keyCode, unichar keyChar, enum APPLE_KEYBOARD_TYPE type) void mac_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEventArgs* e) { rdpSettings* settings = context->settings; + mfContext* mfc = (mfContext*) context; if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) { @@ -836,6 +818,10 @@ void mac_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEve if (settings->SoftwareGdi) gdi_graphics_pipeline_init(context->gdi, (RdpgfxClientContext*) e->pInterface); } + else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) + { + mac_cliprdr_init(mfc, (CliprdrClientContext*) e->pInterface); + } else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) { @@ -845,6 +831,7 @@ void mac_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEve void mac_OnChannelDisconnectedEventHandler(rdpContext* context, ChannelDisconnectedEventArgs* e) { rdpSettings* settings = context->settings; + mfContext* mfc = (mfContext*) context; if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) { @@ -855,6 +842,10 @@ void mac_OnChannelDisconnectedEventHandler(rdpContext* context, ChannelDisconnec if (settings->SoftwareGdi) gdi_graphics_pipeline_uninit(context->gdi, (RdpgfxClientContext*) e->pInterface); } + else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) + { + mac_cliprdr_uninit(mfc, (CliprdrClientContext*) e->pInterface); + } else if (strcmp(e->name, ENCOMSP_SVC_CHANNEL_NAME) == 0) { @@ -963,9 +954,12 @@ BOOL mac_post_connect(freerdp* instance) view->pasteboard_wr = [NSPasteboard generalPasteboard]; /* setup pasteboard for read operations */ - view->pasteboard_rd = [NSPasteboard generalPasteboard]; - view->pasteboard_changecount = (int) [view->pasteboard_rd changeCount]; - view->pasteboard_timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:mfc->view selector:@selector(onPasteboardTimerFired:) userInfo:nil repeats:YES]; + dispatch_async(dispatch_get_main_queue(), ^{ + view->pasteboard_rd = [NSPasteboard generalPasteboard]; + view->pasteboard_changecount = -1; + }); + + [view resume]; mfc->appleKeyboardType = mac_detect_keyboard_type(); @@ -1272,212 +1266,6 @@ static void input_activity_cb(freerdp* instance) } } -static void channel_activity_cb(freerdp* instance) -{ - wMessage* event; - - freerdp_channels_process_pending_messages(instance); - event = freerdp_channels_pop_event(instance->context->channels); - - if (event) - { - WLog_DBG(TAG, "channel_activity_cb: message %d", event->id); - - switch (GetMessageClass(event->id)) - { - case CliprdrChannel_Class: - process_cliprdr_event(instance, event); - break; - } - - freerdp_event_free(event); - } -} - -int process_plugin_args(rdpSettings* settings, const char* name, RDP_PLUGIN_DATA* plugin_data, void* user_data) -{ - rdpChannels* channels = (rdpChannels*) user_data; - - freerdp_channels_load_plugin(channels, settings, name, plugin_data); - - return 1; -} - -/* - * stuff related to clipboard redirection - */ - -void cliprdr_process_cb_data_request_event(freerdp* instance) -{ - int len; - NSArray* types; - RDP_CB_DATA_RESPONSE_EVENT* event; - mfContext* mfc = (mfContext*) instance->context; - MRDPView* view = (MRDPView*) mfc->view; - - event = (RDP_CB_DATA_RESPONSE_EVENT*) freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_DataResponse, NULL, NULL); - - types = [NSArray arrayWithObject:NSStringPboardType]; - NSString* str = [view->pasteboard_rd availableTypeFromArray:types]; - - if (str == nil) - { - event->data = NULL; - event->size = 0; - } - else - { - NSString* data = [view->pasteboard_rd stringForType:NSStringPboardType]; - len = (int) ([data length] * 2 + 2); - event->data = malloc(len); - [data getCString:(char *) event->data maxLength:len encoding:NSUnicodeStringEncoding]; - event->size = len; - } - - freerdp_channels_send_event(instance->context->channels, (wMessage*) event); -} - -void cliprdr_send_data_request(freerdp* instance, UINT32 format) -{ - RDP_CB_DATA_REQUEST_EVENT* event; - - event = (RDP_CB_DATA_REQUEST_EVENT*) freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_DataRequest, NULL, NULL); - - event->format = format; - freerdp_channels_send_event(instance->context->channels, (wMessage*) event); -} - -/** - * at the moment, only the following formats are supported - * CF_TEXT - * CF_UNICODETEXT - */ - -void cliprdr_process_cb_data_response_event(freerdp* instance, RDP_CB_DATA_RESPONSE_EVENT* event) -{ - NSString* str; - NSArray* types; - mfContext* mfc = (mfContext*) instance->context; - MRDPView* view = (MRDPView*) mfc->view; - - if (event->size == 0) - return; - - if (view->pasteboard_format == CF_TEXT || view->pasteboard_format == CF_UNICODETEXT) - { - str = [[NSString alloc] initWithCharacters:(unichar *) event->data length:event->size / 2]; - types = [[NSArray alloc] initWithObjects:NSStringPboardType, nil]; - [view->pasteboard_wr declareTypes:types owner:mfc->view]; - [view->pasteboard_wr setString:str forType:NSStringPboardType]; - } -} - -void cliprdr_process_cb_monitor_ready_event(freerdp* instance) -{ - wMessage* event; - RDP_CB_FORMAT_LIST_EVENT* format_list_event; - - event = freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_FormatList, NULL, NULL); - - format_list_event = (RDP_CB_FORMAT_LIST_EVENT*) event; - format_list_event->num_formats = 0; - - freerdp_channels_send_event(instance->context->channels, event); -} - -/** - * list of supported clipboard formats; currently only the following are supported - * CF_TEXT - * CF_UNICODETEXT - */ - -void cliprdr_process_cb_format_list_event(freerdp* instance, RDP_CB_FORMAT_LIST_EVENT* event) -{ - int i; - mfContext* mfc = (mfContext*) instance->context; - MRDPView* view = (MRDPView*) mfc->view; - - if (event->num_formats == 0) - return; - - for (i = 0; i < event->num_formats; i++) - { - switch (event->formats[i]) - { - case CF_TEXT: - case CF_UNICODETEXT: - view->pasteboard_format = CF_UNICODETEXT; - cliprdr_send_data_request(instance, CF_UNICODETEXT); - return; - break; - } - } -} - -void process_cliprdr_event(freerdp* instance, wMessage* event) -{ - if (event) - { - switch (GetMessageType(event->id)) - { - /* - * Monitor Ready PDU is sent by server to indicate that it has been - * initialized and is ready. This PDU is transmitted by the server after it has sent - * Clipboard Capabilities PDU - */ - case CliprdrChannel_MonitorReady: - cliprdr_process_cb_monitor_ready_event(instance); - break; - - /* - * The Format List PDU is sent either by the client or the server when its - * local system clipboard is updated with new clipboard data. This PDU - * contains the Clipboard Format ID and name pairs of the new Clipboard - * Formats on the clipboard - */ - case CliprdrChannel_FormatList: - cliprdr_process_cb_format_list_event(instance, (RDP_CB_FORMAT_LIST_EVENT*) event); - break; - - /* - * The Format Data Request PDU is sent by the receipient of the Format List PDU. - * It is used to request the data for one of the formats that was listed in the - * Format List PDU - */ - case CliprdrChannel_DataRequest: - cliprdr_process_cb_data_request_event(instance); - break; - - /* - * The Format Data Response PDU is sent as a reply to the Format Data Request PDU. - * It is used to indicate whether processing of the Format Data Request PDU - * was successful. If the processing was successful, the Format Data Response PDU - * includes the contents of the requested clipboard data - */ - case CliprdrChannel_DataResponse: - cliprdr_process_cb_data_response_event(instance, (RDP_CB_DATA_RESPONSE_EVENT*) event); - break; - - default: - WLog_ERR(TAG, "process_cliprdr_event: unknown event type %d", GetMessageType(event->id)); - break; - } - } -} - -void cliprdr_send_supported_format_list(freerdp* instance) -{ - RDP_CB_FORMAT_LIST_EVENT* event; - - event = (RDP_CB_FORMAT_LIST_EVENT*) freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_FormatList, NULL, NULL); - - event->formats = (UINT32*) malloc(sizeof(UINT32) * 1); - event->num_formats = 1; - event->formats[0] = CF_UNICODETEXT; - - freerdp_channels_send_event(instance->context->channels, (wMessage*) event); -} - /** * given a rect with 0,0 at the top left (windows cords) * convert it to a rect with 0,0 at the bottom left (apple cords) diff --git a/client/Mac/mf_client.m b/client/Mac/mf_client.m index 9b22e94c8..9b5427792 100644 --- a/client/Mac/mf_client.m +++ b/client/Mac/mf_client.m @@ -99,10 +99,8 @@ int mfreerdp_client_new(freerdp* instance, rdpContext* context) settings = instance->settings; settings->AsyncTransport = TRUE; - settings->AsyncUpdate = TRUE; settings->AsyncInput = TRUE; - settings->AsyncChannels = TRUE; return 0; } diff --git a/client/Mac/mfreerdp.h b/client/Mac/mfreerdp.h index 37eb3b4a6..a84a5d559 100644 --- a/client/Mac/mfreerdp.h +++ b/client/Mac/mfreerdp.h @@ -19,11 +19,13 @@ typedef struct mf_context mfContext; #include #include #include +#include #include #include #include #include +#include #include "MRDPView.h" #include "Keyboard.h" @@ -63,6 +65,15 @@ struct mf_context DWORD keyboardThreadId; BOOL disconnect; BOOL sw_gdi; + + BOOL clipboardSync; + wClipboard* clipboard; + UINT32 numServerFormats; + UINT32 requestedFormatId; + HANDLE clipboardRequestEvent; + CLIPRDR_FORMAT* serverFormats; + CliprdrClientContext* cliprdr; + UINT32 clipboardCapabilities; rdpFile* connectionRdpFile; diff --git a/client/Sample/freerdp.c b/client/Sample/freerdp.c index d426bbc85..9b5e486ae 100644 --- a/client/Sample/freerdp.c +++ b/client/Sample/freerdp.c @@ -50,28 +50,12 @@ #define TAG CLIENT_TAG("sample") -struct tf_info -{ - void* data; -}; -typedef struct tf_info tfInfo; - struct tf_context { rdpContext _p; - - tfInfo* tfi; }; typedef struct tf_context tfContext; -HANDLE g_sem; -static int g_thread_count = 0; - -struct thread_data -{ - freerdp* instance; -}; - int tf_context_new(freerdp* instance, rdpContext* context) { context->channels = freerdp_channels_new(); @@ -97,59 +81,12 @@ void tf_end_paint(rdpContext* context) return; } -int tf_receive_channel_data(freerdp* instance, UINT16 channelId, BYTE* data, int size, int flags, int total_size) -{ - return freerdp_channels_data(instance, channelId, data, size, flags, total_size); -} - -void tf_process_cb_monitor_ready_event(rdpChannels* channels, freerdp* instance) -{ - wMessage* event; - RDP_CB_FORMAT_LIST_EVENT* format_list_event; - - event = freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_FormatList, NULL, NULL); - - format_list_event = (RDP_CB_FORMAT_LIST_EVENT*) event; - format_list_event->num_formats = 0; - - freerdp_channels_send_event(channels, event); -} - -void tf_process_channel_event(rdpChannels* channels, freerdp* instance) -{ - wMessage* event; - - event = freerdp_channels_pop_event(channels); - - if (event) - { - switch (GetMessageType(event->id)) - { - case CliprdrChannel_MonitorReady: - tf_process_cb_monitor_ready_event(channels, instance); - break; - - default: - WLog_ERR(TAG, "unknown event type %d", GetMessageType(event->id)); - break; - } - - freerdp_event_free(event); - } -} - BOOL tf_pre_connect(freerdp* instance) { - tfInfo* tfi; - tfContext* context; + tfContext* tfc; rdpSettings* settings; - context = (tfContext*) instance->context; - - tfi = (tfInfo*) malloc(sizeof(tfInfo)); - ZeroMemory(tfi, sizeof(tfInfo)); - - context->tfi = tfi; + tfc = (tfContext*) instance->context; settings = instance->settings; @@ -220,12 +157,14 @@ int tfreerdp_run(freerdp* instance) ZeroMemory(rfds, sizeof(rfds)); ZeroMemory(wfds, sizeof(wfds)); - if (freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE) + + if (!freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount)) { WLog_ERR(TAG, "Failed to get FreeRDP file descriptor"); break; } - if (freerdp_channels_get_fds(channels, instance, rfds, &rcount, wfds, &wcount) != TRUE) + + if (!freerdp_channels_get_fds(channels, instance, rfds, &rcount, wfds, &wcount)) { WLog_ERR(TAG, "Failed to get channel manager file descriptor"); break; @@ -261,17 +200,17 @@ int tfreerdp_run(freerdp* instance) } } - if (freerdp_check_fds(instance) != TRUE) + if (!freerdp_check_fds(instance)) { WLog_ERR(TAG, "Failed to check FreeRDP file descriptor"); break; } - if (freerdp_channels_check_fds(channels, instance) != TRUE) + + if (!freerdp_channels_check_fds(channels, instance)) { WLog_ERR(TAG, "Failed to check channel manager file descriptor"); break; } - tf_process_channel_event(channels, instance); } freerdp_channels_close(channels, instance); @@ -281,21 +220,89 @@ int tfreerdp_run(freerdp* instance) return 0; } -void* thread_func(void* param) +void* tf_client_thread_proc(freerdp* instance) { - struct thread_data* data; - data = (struct thread_data*) param; + int i; + int fds; + int max_fds; + int rcount; + int wcount; + void* rfds[32]; + void* wfds[32]; + fd_set rfds_set; + fd_set wfds_set; + rdpChannels* channels; - tfreerdp_run(data->instance); + channels = instance->context->channels; - free(data); + freerdp_connect(instance); - pthread_detach(pthread_self()); + while (1) + { + rcount = 0; + wcount = 0; - g_thread_count--; + ZeroMemory(rfds, sizeof(rfds)); + ZeroMemory(wfds, sizeof(wfds)); - if (g_thread_count < 1) - ReleaseSemaphore(g_sem, 1, NULL); + if (!freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount)) + { + WLog_ERR(TAG, "Failed to get FreeRDP file descriptor"); + break; + } + + if (!freerdp_channels_get_fds(channels, instance, rfds, &rcount, wfds, &wcount)) + { + WLog_ERR(TAG, "Failed to get channel manager file descriptor"); + break; + } + + max_fds = 0; + FD_ZERO(&rfds_set); + FD_ZERO(&wfds_set); + + for (i = 0; i < rcount; i++) + { + fds = (int)(long)(rfds[i]); + + if (fds > max_fds) + max_fds = fds; + + FD_SET(fds, &rfds_set); + } + + if (max_fds == 0) + break; + + if (select(max_fds + 1, &rfds_set, &wfds_set, NULL, NULL) == -1) + { + /* these are not really errors */ + if (!((errno == EAGAIN) || + (errno == EWOULDBLOCK) || + (errno == EINPROGRESS) || + (errno == EINTR))) /* signal occurred */ + { + WLog_ERR(TAG, "tfreerdp_run: select failed"); + break; + } + } + + if (!freerdp_check_fds(instance)) + { + WLog_ERR(TAG, "Failed to check FreeRDP file descriptor"); + break; + } + + if (!freerdp_channels_check_fds(channels, instance)) + { + WLog_ERR(TAG, "Failed to check channel manager file descriptor"); + break; + } + } + + freerdp_channels_close(channels, instance); + freerdp_channels_free(channels); + freerdp_free(instance); ExitThread(0); return NULL; @@ -304,17 +311,13 @@ void* thread_func(void* param) int main(int argc, char* argv[]) { int status; - pthread_t thread; + HANDLE thread; freerdp* instance; rdpChannels* channels; - struct thread_data* data; - - g_sem = CreateSemaphore(NULL, 0, 1, NULL); instance = freerdp_new(); instance->PreConnect = tf_pre_connect; instance->PostConnect = tf_post_connect; - instance->ReceiveChannelData = tf_receive_channel_data; instance->ContextSize = sizeof(tfContext); instance->ContextNew = tf_context_new; @@ -326,22 +329,16 @@ int main(int argc, char* argv[]) status = freerdp_client_settings_parse_command_line(instance->settings, argc, argv); if (status < 0) + { exit(0); + } freerdp_client_load_addins(instance->context->channels, instance->settings); - data = (struct thread_data*) malloc(sizeof(struct thread_data)); - ZeroMemory(data, sizeof(sizeof(struct thread_data))); + thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) + tf_client_thread_proc, instance, 0, NULL); - data->instance = instance; - - g_thread_count++; - pthread_create(&thread, 0, thread_func, data); - - while (g_thread_count > 0) - { - WaitForSingleObject(g_sem, INFINITE); - } + WaitForSingleObject(thread, INFINITE); return 0; } diff --git a/client/X11/xf_channels.c b/client/X11/xf_channels.c index dc787bde6..9fb8d595b 100644 --- a/client/X11/xf_channels.c +++ b/client/X11/xf_channels.c @@ -27,6 +27,7 @@ #include "xfreerdp.h" #include "xf_gfx.h" +#include "xf_tsmf.h" #include "xf_cliprdr.h" void xf_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEventArgs* e) @@ -38,6 +39,10 @@ void xf_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEven { xfc->rdpei = (RdpeiClientContext*) e->pInterface; } + else if (strcmp(e->name, TSMF_DVC_CHANNEL_NAME) == 0) + { + xf_tsmf_init(xfc, (TsmfClientContext*) e->pInterface); + } else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) { if (settings->SoftwareGdi) @@ -64,6 +69,10 @@ void xf_OnChannelDisconnectedEventHandler(rdpContext* context, ChannelDisconnect { xfc->rdpei = NULL; } + else if (strcmp(e->name, TSMF_DVC_CHANNEL_NAME) == 0) + { + xf_tsmf_uninit(xfc, (TsmfClientContext*) e->pInterface); + } else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) { if (settings->SoftwareGdi) diff --git a/client/X11/xf_channels.h b/client/X11/xf_channels.h index 96fd3e52d..18db6c532 100644 --- a/client/X11/xf_channels.h +++ b/client/X11/xf_channels.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index 7ca8c1a83..34a67bcd6 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -104,7 +104,6 @@ #include #define TAG CLIENT_TAG("x11") -static long xv_port = 0; static const size_t password_size = 512; void xf_transform_window(xfContext *xfc) @@ -1020,7 +1019,6 @@ BOOL xf_post_connect(freerdp *instance) xfc->clipboard = xf_clipboard_new(xfc); freerdp_channels_post_connect(channels, instance); - xf_tsmf_init(xfc, xv_port); EventArgsInit(&e, "xfreerdp"); e.width = settings->DesktopWidth; @@ -1121,10 +1119,6 @@ void xf_process_channel_event(rdpChannels* channels, freerdp* instance) xf_process_rail_event(xfc, channels, event); break; - case TsmfChannel_Class: - xf_process_tsmf_event(xfc, event); - break; - default: break; } @@ -1195,7 +1189,7 @@ void xf_window_free(xfContext *xfc) if (xfc->xv_context) { - xf_tsmf_uninit(xfc); + xf_tsmf_uninit(xfc, NULL); xfc->xv_context = NULL; } diff --git a/client/X11/xf_gdi.c b/client/X11/xf_gdi.c index 78d536f48..17d7363db 100644 --- a/client/X11/xf_gdi.c +++ b/client/X11/xf_gdi.c @@ -217,28 +217,6 @@ BOOL xf_set_rop3(xfContext* xfc, int rop3) return TRUE; } -unsigned long xf_gdi_get_color(xfContext* xfc, GDI_COLOR color) -{ - XColor x11_color; - - x11_color.flags = DoRed | DoGreen | DoBlue; - GetRGB32(x11_color.red, x11_color.green, x11_color.blue, color); - x11_color.red = x11_color.red << 8; - x11_color.green = x11_color.green << 8; - x11_color.blue = x11_color.blue << 8; - - if (XAllocColor(xfc->display, xfc->colormap, &x11_color) != 0) - { - XFreeColors(xfc->display, xfc->colormap, &x11_color.pixel, 1, 0); - } - else - { - x11_color.pixel = BlackPixel(xfc->display, xfc->screen_number); - } - - return x11_color.pixel; -} - Pixmap xf_brush_new(xfContext* xfc, int width, int height, int bpp, BYTE* data) { GC gc; @@ -488,9 +466,7 @@ void xf_gdi_patblt(rdpContext* context, PATBLT_ORDER* patblt) xf_set_rop3(xfc, gdi_rop3_code(patblt->bRop)); foreColor = freerdp_convert_gdi_order_color(patblt->foreColor, context->settings->ColorDepth, xfc->format, xfc->palette); - foreColor = xf_gdi_get_color(xfc, foreColor); backColor = freerdp_convert_gdi_order_color(patblt->backColor, context->settings->ColorDepth, xfc->format, xfc->palette); - backColor = xf_gdi_get_color(xfc, backColor); if (brush->style == GDI_BS_SOLID) { @@ -610,7 +586,6 @@ void xf_gdi_opaque_rect(rdpContext* context, OPAQUE_RECT_ORDER* opaque_rect) xf_lock_x11(xfc, FALSE); color = freerdp_convert_gdi_order_color(opaque_rect->color, context->settings->ColorDepth, xfc->format, xfc->palette); - color = xf_gdi_get_color(xfc, color); XSetFunction(xfc->display, xfc->gc, GXcopy); XSetFillStyle(xfc->display, xfc->gc, FillSolid); @@ -646,7 +621,6 @@ void xf_gdi_multi_opaque_rect(rdpContext* context, MULTI_OPAQUE_RECT_ORDER* mult xf_lock_x11(xfc, FALSE); color = freerdp_convert_gdi_order_color(multi_opaque_rect->color, context->settings->ColorDepth, xfc->format, xfc->palette); - color = xf_gdi_get_color(xfc, color); XSetFunction(xfc->display, xfc->gc, GXcopy); XSetFillStyle(xfc->display, xfc->gc, FillSolid); @@ -689,7 +663,6 @@ void xf_gdi_line_to(rdpContext* context, LINE_TO_ORDER* line_to) xf_set_rop2(xfc, line_to->bRop2); color = freerdp_convert_gdi_order_color(line_to->penColor, context->settings->ColorDepth, xfc->format, xfc->palette); - color = xf_gdi_get_color(xfc, color); XSetFillStyle(xfc->display, xfc->gc, FillSolid); XSetForeground(xfc->display, xfc->gc, color); @@ -741,7 +714,6 @@ void xf_gdi_polyline(rdpContext* context, POLYLINE_ORDER* polyline) xf_set_rop2(xfc, polyline->bRop2); color = freerdp_convert_gdi_order_color(polyline->penColor, context->settings->ColorDepth, xfc->format, xfc->palette); - color = xf_gdi_get_color(xfc, color); XSetFillStyle(xfc->display, xfc->gc, FillSolid); XSetForeground(xfc->display, xfc->gc, color); @@ -841,9 +813,7 @@ void xf_gdi_mem3blt(rdpContext* context, MEM3BLT_ORDER* mem3blt) bitmap = (xfBitmap*) mem3blt->bitmap; xf_set_rop3(xfc, gdi_rop3_code(mem3blt->bRop)); foreColor = freerdp_convert_gdi_order_color(mem3blt->foreColor, context->settings->ColorDepth, xfc->format, xfc->palette); - foreColor = xf_gdi_get_color(xfc, foreColor); backColor = freerdp_convert_gdi_order_color(mem3blt->backColor, context->settings->ColorDepth, xfc->format, xfc->palette); - backColor = xf_gdi_get_color(xfc, backColor); if (brush->style == GDI_BS_PATTERN) { @@ -916,7 +886,6 @@ void xf_gdi_polygon_sc(rdpContext* context, POLYGON_SC_ORDER* polygon_sc) xf_set_rop2(xfc, polygon_sc->bRop2); brush_color = freerdp_convert_gdi_order_color(polygon_sc->brushColor, context->settings->ColorDepth, xfc->format, xfc->palette); - brush_color = xf_gdi_get_color(xfc, brush_color); npoints = polygon_sc->numPoints + 1; points = malloc(sizeof(XPoint) * npoints); @@ -978,9 +947,7 @@ void xf_gdi_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb) brush = &(polygon_cb->brush); xf_set_rop2(xfc, polygon_cb->bRop2); foreColor = freerdp_convert_gdi_order_color(polygon_cb->foreColor, context->settings->ColorDepth, xfc->format, xfc->palette); - foreColor = xf_gdi_get_color(xfc, foreColor); backColor = freerdp_convert_gdi_order_color(polygon_cb->backColor, context->settings->ColorDepth, xfc->format, xfc->palette); - backColor = xf_gdi_get_color(xfc, backColor); npoints = polygon_cb->numPoints + 1; points = malloc(sizeof(XPoint) * npoints); @@ -1005,7 +972,7 @@ void xf_gdi_polygon_cb(rdpContext* context, POLYGON_CB_ORDER* polygon_cb) break; default: - WLog_ERR(TAG, "PolygonCB unknown fillMode: %d", polygon_cb->fillMode); + WLog_ERR(TAG, "PolygonCB unknown fillMode: %d", polygon_cb->fillMode); break; } diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c index 18f8d0c08..e73833aed 100644 --- a/client/X11/xf_graphics.c +++ b/client/X11/xf_graphics.c @@ -386,9 +386,6 @@ void xf_Glyph_BeginDraw(rdpContext* context, int x, int y, int width, int height xf_lock_x11(xfc, FALSE); - fgcolor = xf_gdi_get_color(xfc, fgcolor); - bgcolor = xf_gdi_get_color(xfc, bgcolor); - XSetFunction(xfc->display, xfc->gc, GXcopy); if (width && height) diff --git a/client/X11/xf_tsmf.c b/client/X11/xf_tsmf.c index 62d322a8a..3a9350d43 100644 --- a/client/X11/xf_tsmf.c +++ b/client/X11/xf_tsmf.c @@ -21,9 +21,7 @@ #include "config.h" #endif -#include -#include -#include +#include #include #include @@ -33,8 +31,6 @@ #include #include -#include - #include #include #include @@ -46,7 +42,7 @@ #include #include -typedef struct xf_xv_context xfXvContext; +static long xv_port = 0; struct xf_xv_context { @@ -57,15 +53,256 @@ struct xf_xv_context char* xv_shmaddr; UINT32* xv_pixfmts; }; +typedef struct xf_xv_context xfXvContext; #define TAG CLIENT_TAG("x11") -#ifdef WITH_DEBUG_XV -#define DEBUG_XV(fmt, ...) WLog_DBG(TAG, fmt, ## __VA_ARGS__) -#else -#define DEBUG_XV(fmt, ...) do { } while (0) -#endif -void xf_tsmf_init(xfContext* xfc, long xv_port) +static BOOL xf_tsmf_is_format_supported(xfXvContext* xv, UINT32 pixfmt) +{ + int i; + + if (!xv->xv_pixfmts) + return FALSE; + + for (i = 0; xv->xv_pixfmts[i]; i++) + { + if (xv->xv_pixfmts[i] == pixfmt) + return TRUE; + } + + return FALSE; +} + +int xf_tsmf_xv_video_frame_event(TsmfClientContext* tsmf, TSMF_VIDEO_FRAME_EVENT* event) +{ + int i; + int x, y; + UINT32 width; + UINT32 height; + BYTE* data1; + BYTE* data2; + UINT32 pixfmt; + UINT32 xvpixfmt; + XvImage* image; + int colorkey = 0; + int numRects = 0; + xfContext* xfc; + xfXvContext* xv; + XRectangle* xrects; + XShmSegmentInfo shminfo; + BOOL converti420yv12 = FALSE; + + if (!tsmf) + return -1; + + xfc = (xfContext*) tsmf->custom; + + if (!xfc) + return -1; + + xv = (xfXvContext*) xfc->xv_context; + + if (!xv) + return -1; + + if (xv->xv_port == 0) + return -1001; + + /* In case the player is minimized */ + if (event->x < -2048 || event->y < -2048 || event->numVisibleRects < 0) + { + return -1002; + } + + xrects = NULL; + numRects = event->numVisibleRects; + + if (numRects > 0) + { + xrects = (XRectangle*) calloc(numRects, sizeof(XRectangle)); + + if (!xrects) + return -1; + + for (i = 0; i < numRects; i++) + { + x = event->x + event->visibleRects[i].left; + y = event->y + event->visibleRects[i].top; + width = event->visibleRects[i].right - event->visibleRects[i].left; + height = event->visibleRects[i].bottom - event->visibleRects[i].top; + + xrects[i].x = x; + xrects[i].y = y; + xrects[i].width = width; + xrects[i].height = height; + } + } + + if (xv->xv_colorkey_atom != None) + { + XvGetPortAttribute(xfc->display, xv->xv_port, xv->xv_colorkey_atom, &colorkey); + XSetFunction(xfc->display, xfc->gc, GXcopy); + XSetFillStyle(xfc->display, xfc->gc, FillSolid); + XSetForeground(xfc->display, xfc->gc, colorkey); + + if (event->numVisibleRects < 1) + { + XSetClipMask(xfc->display, xfc->gc, None); + } + else + { + XFillRectangles(xfc->display, xfc->window->handle, xfc->gc, xrects, numRects); + } + } + else + { + XSetFunction(xfc->display, xfc->gc, GXcopy); + XSetFillStyle(xfc->display, xfc->gc, FillSolid); + + if (event->numVisibleRects < 1) + { + XSetClipMask(xfc->display, xfc->gc, None); + } + else + { + XSetClipRectangles(xfc->display, xfc->gc, 0, 0, xrects, numRects, YXBanded); + } + } + + pixfmt = event->framePixFmt; + + if (xf_tsmf_is_format_supported(xv, pixfmt)) + { + xvpixfmt = pixfmt; + } + else if (pixfmt == RDP_PIXFMT_I420 && xf_tsmf_is_format_supported(xv, RDP_PIXFMT_YV12)) + { + xvpixfmt = RDP_PIXFMT_YV12; + converti420yv12 = TRUE; + } + else if (pixfmt == RDP_PIXFMT_YV12 && xf_tsmf_is_format_supported(xv, RDP_PIXFMT_I420)) + { + xvpixfmt = RDP_PIXFMT_I420; + converti420yv12 = TRUE; + } + else + { + WLog_DBG(TAG, "pixel format 0x%X not supported by hardware.", pixfmt); + return -1003; + } + + image = XvShmCreateImage(xfc->display, xv->xv_port, + xvpixfmt, 0, event->frameWidth, event->frameHeight, &shminfo); + + if (xv->xv_image_size != image->data_size) + { + if (xv->xv_image_size > 0) + { + shmdt(xv->xv_shmaddr); + shmctl(xv->xv_shmid, IPC_RMID, NULL); + } + + xv->xv_image_size = image->data_size; + xv->xv_shmid = shmget(IPC_PRIVATE, image->data_size, IPC_CREAT | 0777); + xv->xv_shmaddr = shmat(xv->xv_shmid, 0, 0); + } + + shminfo.shmid = xv->xv_shmid; + shminfo.shmaddr = image->data = xv->xv_shmaddr; + shminfo.readOnly = FALSE; + + if (!XShmAttach(xfc->display, &shminfo)) + { + XFree(image); + WLog_DBG(TAG, "XShmAttach failed."); + return -1004; + } + + /* The video driver may align each line to a different size + and we need to convert our original image data. */ + switch (pixfmt) + { + case RDP_PIXFMT_I420: + case RDP_PIXFMT_YV12: + /* Y */ + if (image->pitches[0] == event->frameWidth) + { + CopyMemory(image->data + image->offsets[0], + event->frameData, + event->frameWidth * event->frameHeight); + } + else + { + for (i = 0; i < event->frameHeight; i++) + { + CopyMemory(image->data + image->offsets[0] + i * image->pitches[0], + event->frameData + i * event->frameWidth, + event->frameWidth); + } + } + /* UV */ + /* Conversion between I420 and YV12 is to simply swap U and V */ + if (!converti420yv12) + { + data1 = event->frameData + event->frameWidth * event->frameHeight; + data2 = event->frameData + event->frameWidth * event->frameHeight + + event->frameWidth * event->frameHeight / 4; + } + else + { + data2 = event->frameData + event->frameWidth * event->frameHeight; + data1 = event->frameData + event->frameWidth * event->frameHeight + + event->frameWidth * event->frameHeight / 4; + image->id = pixfmt == RDP_PIXFMT_I420 ? RDP_PIXFMT_YV12 : RDP_PIXFMT_I420; + } + + if (image->pitches[1] * 2 == event->frameWidth) + { + CopyMemory(image->data + image->offsets[1], + data1, + event->frameWidth * event->frameHeight / 4); + CopyMemory(image->data + image->offsets[2], + data2, + event->frameWidth * event->frameHeight / 4); + } + else + { + for (i = 0; i < event->frameHeight / 2; i++) + { + CopyMemory(image->data + image->offsets[1] + i * image->pitches[1], + data1 + i * event->frameWidth / 2, + event->frameWidth / 2); + CopyMemory(image->data + image->offsets[2] + i * image->pitches[2], + data2 + i * event->frameWidth / 2, + event->frameWidth / 2); + } + } + break; + + default: + CopyMemory(image->data, event->frameData, image->data_size <= event->frameSize ? + image->data_size : event->frameSize); + break; + } + + XvShmPutImage(xfc->display, xv->xv_port, xfc->window->handle, xfc->gc, + image, 0, 0, image->width, image->height, + event->x, event->y, event->width, event->height, FALSE); + + if (xv->xv_colorkey_atom == None) + XSetClipMask(xfc->display, xfc->gc, None); + + XSync(xfc->display, FALSE); + + XShmDetach(xfc->display, &shminfo); + XFree(image); + + free(xrects); + + return 1; +} + +int xf_tsmf_xv_init(xfContext* xfc, TsmfClientContext* tsmf) { int ret; unsigned int i; @@ -80,8 +317,13 @@ void xf_tsmf_init(xfContext* xfc, long xv_port) XvAttribute* attr; XvImageFormatValues* fo; - xv = (xfXvContext*) malloc(sizeof(xfXvContext)); - ZeroMemory(xv, sizeof(xfXvContext)); + if (xfc->xv_context) + return 1; /* context already created */ + + xv = (xfXvContext*) calloc(1, sizeof(xfXvContext)); + + if (!xv) + return -1; xfc->xv_context = xv; @@ -91,30 +333,34 @@ void xf_tsmf_init(xfContext* xfc, long xv_port) if (!XShmQueryExtension(xfc->display)) { - DEBUG_XV("no shmem available."); - return; + WLog_DBG(TAG, "no xshm available."); + return -1; } ret = XvQueryExtension(xfc->display, &version, &release, &request_base, &event_base, &error_base); + if (ret != Success) { - DEBUG_XV("XvQueryExtension failed %d.", ret); - return; + WLog_DBG(TAG, "XvQueryExtension failed %d.", ret); + return -1; } - DEBUG_XV("version %u release %u", version, release); + + WLog_DBG(TAG, "version %u release %u", version, release); ret = XvQueryAdaptors(xfc->display, DefaultRootWindow(xfc->display), &num_adaptors, &ai); + if (ret != Success) { - DEBUG_XV("XvQueryAdaptors failed %d.", ret); - return; + WLog_DBG(TAG, "XvQueryAdaptors failed %d.", ret); + return -1; } for (i = 0; i < num_adaptors; i++) { - DEBUG_XV("adapter port %ld-%ld (%s)", ai[i].base_id, + WLog_DBG(TAG, "adapter port %ld-%ld (%s)", ai[i].base_id, ai[i].base_id + ai[i].num_ports - 1, ai[i].name); + if (xv->xv_port == 0 && i == num_adaptors - 1) xv->xv_port = ai[i].base_id; } @@ -124,12 +370,13 @@ void xf_tsmf_init(xfContext* xfc, long xv_port) if (xv->xv_port == 0) { - DEBUG_XV("no adapter selected, video frames will not be processed."); - return; + WLog_DBG(TAG, "no adapter selected, video frames will not be processed."); + return -1; } - DEBUG_XV("selected %ld", xv->xv_port); + WLog_DBG(TAG, "selected %ld", xv->xv_port); attr = XvQueryPortAttributes(xfc->display, xv->xv_port, &ret); + for (i = 0; i < (unsigned int)ret; i++) { if (strcmp(attr[i].name, "XV_COLORKEY") == 0) @@ -141,29 +388,36 @@ void xf_tsmf_init(xfContext* xfc, long xv_port) } XFree(attr); -#ifdef WITH_DEBUG_XV WLog_DBG(TAG, "xf_tsmf_init: pixel format "); -#endif + fo = XvListImageFormats(xfc->display, xv->xv_port, &ret); + if (ret > 0) { - xv->xv_pixfmts = (UINT32*) malloc((ret + 1) * sizeof(UINT32)); - ZeroMemory(xv->xv_pixfmts, (ret + 1) * sizeof(UINT32)); + xv->xv_pixfmts = (UINT32*) calloc((ret + 1), sizeof(UINT32)); for (i = 0; i < ret; i++) { xv->xv_pixfmts[i] = fo[i].id; -#ifdef WITH_DEBUG_XV WLog_DBG(TAG, "%c%c%c%c ", ((char*)(xv->xv_pixfmts + i))[0], ((char*)(xv->xv_pixfmts + i))[1], ((char*)(xv->xv_pixfmts + i))[2], ((char*)(xv->xv_pixfmts + i))[3]); -#endif } xv->xv_pixfmts[i] = 0; } XFree(fo); + + if (tsmf) + { + xfc->tsmf = tsmf; + tsmf->custom = (void*) xfc; + + tsmf->FrameEvent = xf_tsmf_xv_video_frame_event; + } + + return 1; } -void xf_tsmf_uninit(xfContext* xfc) +int xf_tsmf_xv_uninit(xfContext* xfc, TsmfClientContext* tsmf) { xfXvContext* xv = (xfXvContext*) xfc->xv_context; @@ -182,226 +436,33 @@ void xf_tsmf_uninit(xfContext* xfc) free(xv); xfc->xv_context = NULL; } + + if (xfc->tsmf) + { + xfc->tsmf->custom = NULL; + xfc->tsmf = NULL; + } + + return 1; } -static BOOL -xf_tsmf_is_format_supported(xfXvContext* xv, UINT32 pixfmt) +#endif + +int xf_tsmf_init(xfContext* xfc, TsmfClientContext* tsmf) { - int i; +#ifdef WITH_XV + return xf_tsmf_xv_init(xfc, tsmf); +#endif - if (!xv->xv_pixfmts) - return FALSE; - - for (i = 0; xv->xv_pixfmts[i]; i++) - { - if (xv->xv_pixfmts[i] == pixfmt) - return TRUE; - } - - return FALSE; + return 1; } -static void xf_process_tsmf_video_frame_event(xfContext* xfc, RDP_VIDEO_FRAME_EVENT* vevent) +int xf_tsmf_uninit(xfContext* xfc, TsmfClientContext* tsmf) { - int i; - BYTE* data1; - BYTE* data2; - UINT32 pixfmt; - UINT32 xvpixfmt; - BOOL converti420yv12 = FALSE; - XvImage * image; - int colorkey = 0; - XShmSegmentInfo shminfo; - xfXvContext* xv = (xfXvContext*) xfc->xv_context; +#ifdef WITH_XV + return xf_tsmf_xv_uninit(xfc, tsmf); +#endif - if (xv->xv_port == 0) - return; - - /* In case the player is minimized */ - if (vevent->x < -2048 || vevent->y < -2048 || vevent->num_visible_rects <= 0) - return; - - if (xv->xv_colorkey_atom != None) - { - XvGetPortAttribute(xfc->display, xv->xv_port, xv->xv_colorkey_atom, &colorkey); - XSetFunction(xfc->display, xfc->gc, GXcopy); - XSetFillStyle(xfc->display, xfc->gc, FillSolid); - XSetForeground(xfc->display, xfc->gc, colorkey); - - for (i = 0; i < vevent->num_visible_rects; i++) - { - XFillRectangle(xfc->display, xfc->window->handle, xfc->gc, - vevent->x + vevent->visible_rects[i].x, - vevent->y + vevent->visible_rects[i].y, - vevent->visible_rects[i].width, - vevent->visible_rects[i].height); - } - } - else - { - XSetClipRectangles(xfc->display, xfc->gc, vevent->x, vevent->y, - (XRectangle*) vevent->visible_rects, vevent->num_visible_rects, YXBanded); - } - - pixfmt = vevent->frame_pixfmt; - - if (xf_tsmf_is_format_supported(xv, pixfmt)) - { - xvpixfmt = pixfmt; - } - else if (pixfmt == RDP_PIXFMT_I420 && xf_tsmf_is_format_supported(xv, RDP_PIXFMT_YV12)) - { - xvpixfmt = RDP_PIXFMT_YV12; - converti420yv12 = TRUE; - } - else if (pixfmt == RDP_PIXFMT_YV12 && xf_tsmf_is_format_supported(xv, RDP_PIXFMT_I420)) - { - xvpixfmt = RDP_PIXFMT_I420; - converti420yv12 = TRUE; - } - else - { - DEBUG_XV("pixel format 0x%X not supported by hardware.", pixfmt); - return; - } - - image = XvShmCreateImage(xfc->display, xv->xv_port, - xvpixfmt, 0, vevent->frame_width, vevent->frame_height, &shminfo); - - if (xv->xv_image_size != image->data_size) - { - if (xv->xv_image_size > 0) - { - shmdt(xv->xv_shmaddr); - shmctl(xv->xv_shmid, IPC_RMID, NULL); - } - xv->xv_image_size = image->data_size; - xv->xv_shmid = shmget(IPC_PRIVATE, image->data_size, IPC_CREAT | 0777); - xv->xv_shmaddr = shmat(xv->xv_shmid, 0, 0); - } - shminfo.shmid = xv->xv_shmid; - shminfo.shmaddr = image->data = xv->xv_shmaddr; - shminfo.readOnly = FALSE; - - if (!XShmAttach(xfc->display, &shminfo)) - { - XFree(image); - DEBUG_XV("XShmAttach failed."); - return; - } - - /* The video driver may align each line to a different size - and we need to convert our original image data. */ - switch (pixfmt) - { - case RDP_PIXFMT_I420: - case RDP_PIXFMT_YV12: - /* Y */ - if (image->pitches[0] == vevent->frame_width) - { - memcpy(image->data + image->offsets[0], - vevent->frame_data, - vevent->frame_width * vevent->frame_height); - } - else - { - for (i = 0; i < vevent->frame_height; i++) - { - memcpy(image->data + image->offsets[0] + i * image->pitches[0], - vevent->frame_data + i * vevent->frame_width, - vevent->frame_width); - } - } - /* UV */ - /* Conversion between I420 and YV12 is to simply swap U and V */ - if (converti420yv12 == FALSE) - { - data1 = vevent->frame_data + vevent->frame_width * vevent->frame_height; - data2 = vevent->frame_data + vevent->frame_width * vevent->frame_height + - vevent->frame_width * vevent->frame_height / 4; - } - else - { - data2 = vevent->frame_data + vevent->frame_width * vevent->frame_height; - data1 = vevent->frame_data + vevent->frame_width * vevent->frame_height + - vevent->frame_width * vevent->frame_height / 4; - image->id = pixfmt == RDP_PIXFMT_I420 ? RDP_PIXFMT_YV12 : RDP_PIXFMT_I420; - } - if (image->pitches[1] * 2 == vevent->frame_width) - { - memcpy(image->data + image->offsets[1], - data1, - vevent->frame_width * vevent->frame_height / 4); - memcpy(image->data + image->offsets[2], - data2, - vevent->frame_width * vevent->frame_height / 4); - } - else - { - for (i = 0; i < vevent->frame_height / 2; i++) - { - memcpy(image->data + image->offsets[1] + i * image->pitches[1], - data1 + i * vevent->frame_width / 2, - vevent->frame_width / 2); - memcpy(image->data + image->offsets[2] + i * image->pitches[2], - data2 + i * vevent->frame_width / 2, - vevent->frame_width / 2); - } - } - break; - - default: - memcpy(image->data, vevent->frame_data, image->data_size <= vevent->frame_size ? - image->data_size : vevent->frame_size); - break; - } - - XvShmPutImage(xfc->display, xv->xv_port, xfc->window->handle, xfc->gc, image, - 0, 0, image->width, image->height, - vevent->x, vevent->y, vevent->width, vevent->height, FALSE); - if (xv->xv_colorkey_atom == None) - XSetClipMask(xfc->display, xfc->gc, None); - XSync(xfc->display, FALSE); - - XShmDetach(xfc->display, &shminfo); - XFree(image); + return 1; } -static void xf_process_tsmf_redraw_event(xfContext* xfc, RDP_REDRAW_EVENT* revent) -{ - XSetFunction(xfc->display, xfc->gc, GXcopy); - XSetFillStyle(xfc->display, xfc->gc, FillSolid); - XCopyArea(xfc->display, xfc->primary, xfc->window->handle, xfc->gc, - revent->x, revent->y, revent->width, revent->height, revent->x, revent->y); -} - -void xf_process_tsmf_event(xfContext* xfc, wMessage* event) -{ - switch (GetMessageType(event->id)) - { - case TsmfChannel_VideoFrame: - xf_process_tsmf_video_frame_event(xfc, (RDP_VIDEO_FRAME_EVENT*) event); - break; - - case TsmfChannel_Redraw: - xf_process_tsmf_redraw_event(xfc, (RDP_REDRAW_EVENT*) event); - break; - - } -} - -#else /* WITH_XV */ - -void xf_tsmf_init(xfContext* xfc, long xv_port) -{ -} - -void xf_tsmf_uninit(xfContext* xfc) -{ -} - -void xf_process_tsmf_event(xfContext* xfc, wMessage* event) -{ -} - -#endif /* WITH_XV */ diff --git a/client/X11/xf_tsmf.h b/client/X11/xf_tsmf.h index eb7981851..0469d6860 100644 --- a/client/X11/xf_tsmf.h +++ b/client/X11/xf_tsmf.h @@ -23,8 +23,7 @@ #include "xf_client.h" #include "xfreerdp.h" -void xf_tsmf_init(xfContext* xfc, long xv_port); -void xf_tsmf_uninit(xfContext* xfc); -void xf_process_tsmf_event(xfContext* xfc, wMessage* event); +int xf_tsmf_init(xfContext* xfc, TsmfClientContext* tsmf); +int xf_tsmf_uninit(xfContext* xfc, TsmfClientContext* tsmf); #endif /* __XF_TSMF_H */ diff --git a/client/X11/xfreerdp.h b/client/X11/xfreerdp.h index bb222a964..c972d0778 100644 --- a/client/X11/xfreerdp.h +++ b/client/X11/xfreerdp.h @@ -158,6 +158,7 @@ struct xf_context BOOL complex_regions; VIRTUAL_SCREEN vscreen; void* xv_context; + TsmfClientContext* tsmf; xfClipboard* clipboard; CliprdrClientContext* cliprdr; @@ -248,8 +249,6 @@ void xf_unlock_x11(xfContext* xfc, BOOL display); void xf_draw_screen_scaled(xfContext* xfc, int x, int y, int w, int h, BOOL scale); void xf_transform_window(xfContext* xfc); -unsigned long xf_gdi_get_color(xfContext* xfc, GDI_COLOR color); - FREERDP_API DWORD xf_exit_code_from_disconnect_reason(DWORD reason); #endif /* __XFREERDP_H */ diff --git a/include/freerdp/channels/tsmf.h b/include/freerdp/channels/tsmf.h index f6a7ef4c2..3ef76d40f 100644 --- a/include/freerdp/channels/tsmf.h +++ b/include/freerdp/channels/tsmf.h @@ -18,46 +18,11 @@ * limitations under the License. */ -#ifndef _TSMF_H_ -#define _TSMF_H_ +#ifndef FREERDP_CHANNEL_TSMF_H +#define FREERDP_CHANNEL_TSMF_H #include -/* Callback function setup order: - * - * When the channel is loaded, it calls TSMF_REGISTER to register the - * decoder handle with the client. - * The client then stores the handle and calls TSMF_REGISTER_INSTANCE - * to give the channel the current handle to the session necessary - * to call other functions. - * After this initial setup the other functions can be used. - */ -/* Functions called from client -> registered by channel */ -#define TSMF_GET_INSTANCE "tsmf_get_instance" -typedef void (*tsmf_get_instance)(void *instance, void *decoder); - -#define TSMF_ADD_WINDOW_HANDLE "tsmf_add_window_handle" -typedef void (*tsmf_add_window_handle)(void *instance, void *decoder, void *window); - -#define TSMF_DEL_WINDOW_HANDLE "tsmf_del_window_handle" -typedef void (*tsmf_del_window_handle)(void *instance, void *decoder); - -/* Functions called from channel -> registered by client */ -#define TSMF_REGISTER "tsmf_register" -typedef void (*tsmf_register)(void *instance, void *decoder); - -#define TSMF_DESTROY "tsmf_destroy" -typedef void (*tsmf_destroy)(void *instance, void *decoder); - -#define TSMF_PLAY "tsmf_play" -typedef void (*tsmf_play)(void *instance, void *decoder); - -#define TSMF_PAUSE "tsmf_pause" -typedef void (*tsmf_pause)(void *instance, void *decoder); - -#define TSMF_RESIZE_WINDOW "tsmf_resize_window" -typedef void (*tsmf_resize_window)(void *instance, void *decoder, int x, int y, int width, - int height, int nr_rect, RDP_RECT *visible); - -#endif +#define TSMF_DVC_CHANNEL_NAME "TSMF" +#endif /* FREERDP_CHANNEL_TSMF_H */ diff --git a/include/freerdp/client/tsmf.h b/include/freerdp/client/tsmf.h index d8b884f94..674a9c737 100644 --- a/include/freerdp/client/tsmf.h +++ b/include/freerdp/client/tsmf.h @@ -20,36 +20,45 @@ #ifndef FREERDP_CHANNEL_CLIENT_TSMF_H #define FREERDP_CHANNEL_CLIENT_TSMF_H -struct _RDP_VIDEO_FRAME_EVENT -{ - wMessage event; - BYTE* frame_data; - UINT32 frame_size; - UINT32 frame_pixfmt; - INT16 frame_width; - INT16 frame_height; - INT16 x; - INT16 y; - INT16 width; - INT16 height; - UINT16 num_visible_rects; - RDP_RECT* visible_rects; -}; -typedef struct _RDP_VIDEO_FRAME_EVENT RDP_VIDEO_FRAME_EVENT; +#include -struct _RDP_REDRAW_EVENT -{ - wMessage event; - INT16 x; - INT16 y; - INT16 width; - INT16 height; -}; -typedef struct _RDP_REDRAW_EVENT RDP_REDRAW_EVENT; +#include /* RDP_VIDEO_FRAME_EVENT.frame_pixfmt */ /* http://www.fourcc.org/yuv.php */ #define RDP_PIXFMT_I420 0x30323449 #define RDP_PIXFMT_YV12 0x32315659 +struct _TSMF_VIDEO_FRAME_EVENT +{ + BYTE* frameData; + UINT32 frameSize; + UINT32 framePixFmt; + INT16 frameWidth; + INT16 frameHeight; + INT16 x; + INT16 y; + INT16 width; + INT16 height; + UINT16 numVisibleRects; + RECTANGLE_16* visibleRects; +}; +typedef struct _TSMF_VIDEO_FRAME_EVENT TSMF_VIDEO_FRAME_EVENT; + +/** + * Client Interface + */ + +typedef struct _tsmf_client_context TsmfClientContext; + +typedef int (*pcTsmfFrameEvent)(TsmfClientContext* context, TSMF_VIDEO_FRAME_EVENT* event); + +struct _tsmf_client_context +{ + void* handle; + void* custom; + + pcTsmfFrameEvent FrameEvent; +}; + #endif /* FREERDP_CHANNEL_CLIENT_TSMF_H */ diff --git a/include/freerdp/server/shadow.h b/include/freerdp/server/shadow.h index a3ff1b4b0..4a0164d68 100644 --- a/include/freerdp/server/shadow.h +++ b/include/freerdp/server/shadow.h @@ -87,6 +87,9 @@ struct rdp_shadow_client rdpShadowEncoder* encoder; rdpShadowSubsystem* subsystem; + UINT32 pointerX; + UINT32 pointerY; + HANDLE vcm; EncomspServerContext* encomsp; RemdeskServerContext* remdesk; @@ -145,6 +148,8 @@ struct _RDP_SHADOW_ENTRY_POINTS REGION16 invalidRegion; \ wMessagePipe* MsgPipe; \ SYNCHRONIZATION_BARRIER barrier; \ + UINT32 pointerX; \ + UINT32 pointerY; \ \ pfnShadowSynchronizeEvent SynchronizeEvent; \ pfnShadowKeyboardEvent KeyboardEvent; \ diff --git a/libfreerdp/core/listener.c b/libfreerdp/core/listener.c index 5920a9bbf..9f2a7e5e1 100644 --- a/libfreerdp/core/listener.c +++ b/libfreerdp/core/listener.c @@ -105,7 +105,7 @@ static BOOL freerdp_listener_open(freerdp_listener* instance, const char* bind_a if (status != 0) { #ifdef _WIN32 - WLog_ERR(_T("getaddrinfo error: %s"), gai_strerror(status)); + WLog_ERR("getaddrinfo error: %s", gai_strerrorA(status)); #else WLog_ERR(TAG, "getaddrinfo"); #endif diff --git a/libfreerdp/core/update.c b/libfreerdp/core/update.c index 6fefa13e0..0adfbeb8f 100644 --- a/libfreerdp/core/update.c +++ b/libfreerdp/core/update.c @@ -1506,9 +1506,25 @@ static void update_send_pointer_system(rdpContext* context, POINTER_SYSTEM_UPDAT Stream_Release(s); } +static void update_send_pointer_position(rdpContext* context, POINTER_POSITION_UPDATE* pointerPosition) +{ + wStream* s; + rdpRdp* rdp = context->rdp; + + s = fastpath_update_pdu_init(rdp->fastpath); + + Stream_EnsureRemainingCapacity(s, 16); + + Stream_Write_UINT16(s, pointerPosition->xPos); /* xPos (2 bytes) */ + Stream_Write_UINT16(s, pointerPosition->yPos); /* yPos (2 bytes) */ + + fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_PTR_POSITION, s, FALSE); + Stream_Release(s); +} + static void update_write_pointer_color(wStream* s, POINTER_COLOR_UPDATE* pointer_color) { - Stream_EnsureRemainingCapacity(s, 15 + (int) pointer_color->lengthAndMask + (int) pointer_color->lengthXorMask); + Stream_EnsureRemainingCapacity(s, 32 + (int) pointer_color->lengthAndMask + (int) pointer_color->lengthXorMask); Stream_Write_UINT16(s, pointer_color->cacheIndex); Stream_Write_UINT16(s, pointer_color->xPos); @@ -1544,9 +1560,14 @@ static void update_send_pointer_new(rdpContext* context, POINTER_NEW_UPDATE* poi rdpRdp* rdp = context->rdp; s = fastpath_update_pdu_init(rdp->fastpath); + + Stream_EnsureRemainingCapacity(s, 16); + Stream_Write_UINT16(s, pointer_new->xorBpp); /* xorBpp (2 bytes) */ update_write_pointer_color(s, &pointer_new->colorPtrAttr); + fastpath_send_update_pdu(rdp->fastpath, FASTPATH_UPDATETYPE_POINTER, s, FALSE); + Stream_Release(s); } @@ -1614,14 +1635,14 @@ BOOL update_read_suppress_output(rdpUpdate* update, wStream* s) static void update_send_set_keyboard_indicators(rdpContext* context, UINT16 led_flags) { - wStream* s; - rdpRdp* rdp = context->rdp; + wStream* s; + rdpRdp* rdp = context->rdp; - s = rdp_data_pdu_init(rdp); - Stream_Write_UINT16(s, 0); /* unitId should be 0 according to MS-RDPBCGR 2.2.8.2.1.1 */ - Stream_Write_UINT16(s, led_flags); /* ledFlags (2 bytes) */ - rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_SET_KEYBOARD_INDICATORS, rdp->mcs->userId); - Stream_Release(s); + s = rdp_data_pdu_init(rdp); + Stream_Write_UINT16(s, 0); /* unitId should be 0 according to MS-RDPBCGR 2.2.8.2.1.1 */ + Stream_Write_UINT16(s, led_flags); /* ledFlags (2 bytes) */ + rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_SET_KEYBOARD_INDICATORS, rdp->mcs->userId); + Stream_Release(s); } void update_register_server_callbacks(rdpUpdate* update) @@ -1655,6 +1676,7 @@ void update_register_server_callbacks(rdpUpdate* update) update->altsec->CreateOffscreenBitmap = update_send_create_offscreen_bitmap_order; update->altsec->SwitchSurface = update_send_switch_surface_order; update->pointer->PointerSystem = update_send_pointer_system; + update->pointer->PointerPosition = update_send_pointer_position; update->pointer->PointerColor = update_send_pointer_color; update->pointer->PointerNew = update_send_pointer_new; update->pointer->PointerCached = update_send_pointer_cached; diff --git a/libfreerdp/gdi/gdi.c b/libfreerdp/gdi/gdi.c index 5ce219024..34fdf9b55 100644 --- a/libfreerdp/gdi/gdi.c +++ b/libfreerdp/gdi/gdi.c @@ -528,7 +528,7 @@ static void gdi_bitmap_update(rdpContext* context, BITMAP_UPDATE* bitmapUpdate) pSrcData = gdi->bitmap_buffer; } - nSrcStep = nWidth * 4; + nSrcStep = nWidth * gdi->bytesPerPixel; pDstData = gdi->primary_buffer; nDstStep = gdi->width * gdi->bytesPerPixel; diff --git a/libfreerdp/utils/event.c b/libfreerdp/utils/event.c index d8cd80d80..c8772c905 100644 --- a/libfreerdp/utils/event.c +++ b/libfreerdp/utils/event.c @@ -21,16 +21,11 @@ #include "config.h" #endif -#include -#include -#include - #include #include #include #include -#include #include static wMessage* freerdp_cliprdr_event_new(UINT16 event_type) @@ -109,33 +104,6 @@ static wMessage* freerdp_cliprdr_event_new(UINT16 event_type) return event.m; } -static wMessage* freerdp_tsmf_event_new(UINT16 event_type) -{ - union - { - void *v; - wMessage* m; - } event; - - event.m = NULL; - switch (event_type) - { - case TsmfChannel_VideoFrame: - event.v = malloc(sizeof(RDP_VIDEO_FRAME_EVENT)); - ZeroMemory(event.v, sizeof(RDP_VIDEO_FRAME_EVENT)); - event.m->id = MakeMessageId(TsmfChannel, VideoFrame); - break; - - case TsmfChannel_Redraw: - event.v = malloc(sizeof(RDP_REDRAW_EVENT)); - ZeroMemory(event.v, sizeof(RDP_REDRAW_EVENT)); - event.m->id = MakeMessageId(TsmfChannel, Redraw); - break; - } - - return event.v; -} - static wMessage* freerdp_rail_event_new(UINT16 event_type) { wMessage* event = NULL; @@ -153,19 +121,10 @@ wMessage* freerdp_event_new(UINT16 event_class, UINT16 event_type, switch (event_class) { - case DebugChannel_Class: - event = (wMessage*) malloc(sizeof(wMessage)); - ZeroMemory(event, sizeof(wMessage)); - break; - case CliprdrChannel_Class: event = freerdp_cliprdr_event_new(event_type); break; - case TsmfChannel_Class: - event = freerdp_tsmf_event_new(event_type); - break; - case RailChannel_Class: event = freerdp_rail_event_new(event_type); break; @@ -202,20 +161,6 @@ static void freerdp_cliprdr_event_free(wMessage* event) } } -static void freerdp_tsmf_event_free(wMessage* event) -{ - switch (GetMessageType(event->id)) - { - case TsmfChannel_VideoFrame: - { - RDP_VIDEO_FRAME_EVENT* vevent = (RDP_VIDEO_FRAME_EVENT*)event; - free(vevent->frame_data); - free(vevent->visible_rects); - } - break; - } -} - static void freerdp_rail_event_free(wMessage* event) { @@ -234,10 +179,6 @@ void freerdp_event_free(wMessage* event) freerdp_cliprdr_event_free(event); break; - case TsmfChannel_Class: - freerdp_tsmf_event_free(event); - break; - case RailChannel_Class: freerdp_rail_event_free(event); break; diff --git a/server/shadow/X11/x11_shadow.c b/server/shadow/X11/x11_shadow.c index 943bc0b63..3f1a96408 100644 --- a/server/shadow/X11/x11_shadow.c +++ b/server/shadow/X11/x11_shadow.c @@ -231,11 +231,13 @@ void x11_shadow_input_keyboard_event(x11ShadowSubsystem* subsystem, UINT16 flags XTestGrabControl(subsystem->display, True); if (flags & KBD_FLAGS_DOWN) - XTestFakeKeyEvent(subsystem->display, keycode, True, 0); + XTestFakeKeyEvent(subsystem->display, keycode, True, CurrentTime); else if (flags & KBD_FLAGS_RELEASE) - XTestFakeKeyEvent(subsystem->display, keycode, False, 0); + XTestFakeKeyEvent(subsystem->display, keycode, False, CurrentTime); XTestGrabControl(subsystem->display, False); + + XFlush(subsystem->display); } #endif } @@ -276,13 +278,13 @@ void x11_shadow_input_mouse_event(x11ShadowSubsystem* subsystem, UINT16 flags, U button = (negative) ? 5 : 4; - XTestFakeButtonEvent(subsystem->display, button, True, 0); - XTestFakeButtonEvent(subsystem->display, button, False, 0); + XTestFakeButtonEvent(subsystem->display, button, True, CurrentTime); + XTestFakeButtonEvent(subsystem->display, button, False, CurrentTime); } else { if (flags & PTR_FLAGS_MOVE) - XTestFakeMotionEvent(subsystem->display, 0, x, y, 0); + XTestFakeMotionEvent(subsystem->display, 0, x, y, CurrentTime); if (flags & PTR_FLAGS_BUTTON1) button = 1; @@ -295,10 +297,12 @@ void x11_shadow_input_mouse_event(x11ShadowSubsystem* subsystem, UINT16 flags, U down = TRUE; if (button) - XTestFakeButtonEvent(subsystem->display, button, down, 0); + XTestFakeButtonEvent(subsystem->display, button, down, CurrentTime); } XTestGrabControl(subsystem->display, False); + + XFlush(subsystem->display); #endif } @@ -335,12 +339,63 @@ void x11_shadow_input_extended_mouse_event(x11ShadowSubsystem* subsystem, UINT16 down = TRUE; if (button) - XTestFakeButtonEvent(subsystem->display, button, down, 0); + XTestFakeButtonEvent(subsystem->display, button, down, CurrentTime); XTestGrabControl(subsystem->display, False); + + XFlush(subsystem->display); #endif } +int x11_shadow_pointer_position_update(x11ShadowSubsystem* subsystem) +{ + SHADOW_MSG_OUT_POINTER_POSITION_UPDATE* msg; + UINT32 msgId = SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID; + wMessagePipe* MsgPipe = subsystem->MsgPipe; + + msg = (SHADOW_MSG_OUT_POINTER_POSITION_UPDATE*) calloc(1, sizeof(SHADOW_MSG_OUT_POINTER_POSITION_UPDATE)); + + if (!msg) + return -1; + + msg->xPos = subsystem->pointerX; + msg->yPos = subsystem->pointerY; + + MessageQueue_Post(MsgPipe->Out, NULL, msgId, (void*) msg, NULL); + + return 1; +} + +int x11_shadow_pointer_alpha_update(x11ShadowSubsystem* subsystem) +{ + SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE* msg; + UINT32 msgId = SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID; + wMessagePipe* MsgPipe = subsystem->MsgPipe; + + msg = (SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE*) calloc(1, sizeof(SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE)); + + if (!msg) + return -1; + + msg->xHot = subsystem->cursorHotX; + msg->yHot = subsystem->cursorHotY; + msg->width = subsystem->cursorWidth; + msg->height = subsystem->cursorHeight; + msg->scanline = msg->width * 4; + + msg->pixels = (BYTE*) malloc(msg->scanline * msg->height); + + if (!msg->pixels) + return -1; + + CopyMemory(msg->pixels, subsystem->cursorPixels, msg->scanline * msg->height); + msg->premultiplied = TRUE; + + MessageQueue_Post(MsgPipe->Out, NULL, msgId, (void*) msg, NULL); + + return 1; +} + int x11_shadow_query_cursor(x11ShadowSubsystem* subsystem, BOOL getImage) { int x, y, n, k; @@ -358,6 +413,9 @@ int x11_shadow_query_cursor(x11ShadowSubsystem* subsystem, BOOL getImage) ci = XFixesGetCursorImage(subsystem->display); + if (!ci) + return -1; + x = ci->x; y = ci->y; @@ -385,6 +443,8 @@ int x11_shadow_query_cursor(x11ShadowSubsystem* subsystem, BOOL getImage) } XFree(ci); + + x11_shadow_pointer_alpha_update(subsystem); #endif } else @@ -404,8 +464,13 @@ int x11_shadow_query_cursor(x11ShadowSubsystem* subsystem, BOOL getImage) y = root_y; } - subsystem->cursorX = x; - subsystem->cursorY = y; + if ((x != subsystem->pointerX) || (y != subsystem->pointerY)) + { + subsystem->pointerX = x; + subsystem->pointerY = y; + + x11_shadow_pointer_position_update(subsystem); + } return 1; } @@ -416,13 +481,16 @@ int x11_shadow_handle_xevent(x11ShadowSubsystem* subsystem, XEvent* xevent) { } - #ifdef WITH_XFIXES - if (xevent->type == subsystem->xfixes_cursor_notify_event) + else if (xevent->type == subsystem->xfixes_cursor_notify_event) { x11_shadow_query_cursor(subsystem, TRUE); } #endif + else + { + + } return 1; } @@ -473,8 +541,8 @@ int x11_shadow_blend_cursor(x11ShadowSubsystem* subsystem) nWidth = subsystem->cursorWidth; nHeight = subsystem->cursorHeight; - nXDst = subsystem->cursorX - surface->x - subsystem->cursorHotX; - nYDst = subsystem->cursorY - surface->y - subsystem->cursorHotY; + nXDst = subsystem->pointerX - surface->x - subsystem->cursorHotX; + nYDst = subsystem->pointerY - surface->y - subsystem->cursorHotY; if (nXDst >= surface->width) return 1; @@ -633,7 +701,7 @@ int x11_shadow_screen_grab(x11ShadowSubsystem* subsystem) (BYTE*) image->data, PIXEL_FORMAT_XRGB32, image->bytes_per_line, x, y, NULL); - x11_shadow_blend_cursor(subsystem); + //x11_shadow_blend_cursor(subsystem); count = ArrayList_Count(server->clients); @@ -767,8 +835,8 @@ void* x11_shadow_subsystem_thread(x11ShadowSubsystem* subsystem) if ((status == WAIT_TIMEOUT) || (GetTickCount64() > frameTime)) { - x11_shadow_query_cursor(subsystem, FALSE); x11_shadow_screen_grab(subsystem); + x11_shadow_query_cursor(subsystem, FALSE); dwInterval = 1000 / subsystem->captureFrameRate; frameTime += dwInterval; @@ -804,7 +872,7 @@ int x11_shadow_subsystem_base_init(x11ShadowSubsystem* subsystem) subsystem->depth = DefaultDepthOfScreen(subsystem->screen); subsystem->width = WidthOfScreen(subsystem->screen); subsystem->height = HeightOfScreen(subsystem->screen); - subsystem->root_window = DefaultRootWindow(subsystem->display); + subsystem->root_window = RootWindow(subsystem->display, subsystem->number); return 1; } @@ -824,7 +892,8 @@ int x11_shadow_xfixes_init(x11ShadowSubsystem* subsystem) subsystem->xfixes_cursor_notify_event = xfixes_event + XFixesCursorNotify; - XFixesSelectCursorInput(subsystem->display, DefaultRootWindow(subsystem->display), XFixesDisplayCursorNotifyMask); + XFixesSelectCursorInput(subsystem->display, subsystem->root_window, + XFixesDisplayCursorNotifyMask); return 1; #else diff --git a/server/shadow/X11/x11_shadow.h b/server/shadow/X11/x11_shadow.h index 31233e233..fbb247496 100644 --- a/server/shadow/X11/x11_shadow.h +++ b/server/shadow/X11/x11_shadow.h @@ -80,8 +80,6 @@ struct x11_shadow_subsystem Window root_window; XShmSegmentInfo fb_shm_info; - int cursorX; - int cursorY; int cursorHotX; int cursorHotY; int cursorWidth; diff --git a/server/shadow/shadow_capture.c b/server/shadow/shadow_capture.c index 6b1ffeb76..7aa321e67 100644 --- a/server/shadow/shadow_capture.c +++ b/server/shadow/shadow_capture.c @@ -94,10 +94,10 @@ int shadow_capture_compare(BYTE* pData1, int nStep1, int nWidth, int nHeight, BY BOOL grid[1024][1024]; allEqual = TRUE; + ZeroMemory(rect, sizeof(RECTANGLE_16)); FillMemory(rows, sizeof(rows), 0xFF); FillMemory(cols, sizeof(cols), 0xFF); FillMemory(grid, sizeof(grid), 0xFF); - ZeroMemory(rect, sizeof(RECTANGLE_16)); nrow = (nHeight + 15) / 16; ncol = (nWidth + 15) / 16; diff --git a/server/shadow/shadow_client.c b/server/shadow/shadow_client.c index 2c7d35272..63d0b9e97 100644 --- a/server/shadow/shadow_client.c +++ b/server/shadow/shadow_client.c @@ -56,6 +56,8 @@ void shadow_client_context_new(freerdp_peer* peer, rdpShadowClient* client) settings->DrawAllowColorSubsampling = TRUE; settings->DrawAllowDynamicColorFidelity = TRUE; + settings->CompressionLevel = PACKET_COMPR_TYPE_RDP6; + settings->RdpSecurity = TRUE; settings->TlsSecurity = TRUE; settings->NlaSecurity = FALSE; @@ -162,6 +164,9 @@ BOOL shadow_client_post_connect(freerdp_peer* peer) if (settings->ColorDepth == 24) settings->ColorDepth = 16; /* disable 24bpp */ + if (settings->MultifragMaxRequestSize < 0x3F0000) + settings->NSCodec = FALSE; /* NSCodec compressor does not support fragmentation yet */ + WLog_ERR(TAG, "Client from %s is activated (%dx%d@%d)", peer->hostname, settings->DesktopWidth, settings->DesktopHeight, settings->ColorDepth); @@ -266,7 +271,7 @@ BOOL shadow_client_activate(freerdp_peer* peer) rdpSettings* settings = peer->settings; rdpShadowClient* client = (rdpShadowClient*) peer->context; - if (strcmp(settings->ClientDir, "librdp") == 0) + if (settings->ClientDir && (strcmp(settings->ClientDir, "librdp") == 0)) { /* Hack for Mac/iOS/Android Microsoft RDP clients */ @@ -595,10 +600,47 @@ int shadow_client_send_bitmap_update(rdpShadowClient* client, rdpShadowSurface* if (updateSizeEstimate > maxUpdateSize) { - fprintf(stderr, "update size estimate larger than maximum update size\n"); - } + UINT32 i, j; + UINT32 updateSize; + UINT32 newUpdateSize; + BITMAP_DATA* fragBitmapData; - IFCALL(update->BitmapUpdate, context, &bitmapUpdate); + fragBitmapData = (BITMAP_DATA*) malloc(sizeof(BITMAP_DATA) * k); + bitmapUpdate.rectangles = fragBitmapData; + + i = j = 0; + updateSize = 1024; + + while (i < k) + { + newUpdateSize = updateSize + (bitmapData[i].bitmapLength + 16); + + if ((newUpdateSize < maxUpdateSize) && ((i + 1) < k)) + { + CopyMemory(&fragBitmapData[j++], &bitmapData[i++], sizeof(BITMAP_DATA)); + updateSize = newUpdateSize; + } + else + { + if ((i + 1) >= k) + { + CopyMemory(&fragBitmapData[j++], &bitmapData[i++], sizeof(BITMAP_DATA)); + updateSize = newUpdateSize; + } + + bitmapUpdate.count = bitmapUpdate.number = j; + IFCALL(update->BitmapUpdate, context, &bitmapUpdate); + updateSize = 1024; + j = 0; + } + } + + free(fragBitmapData); + } + else + { + IFCALL(update->BitmapUpdate, context, &bitmapUpdate); + } free(bitmapData); @@ -696,10 +738,151 @@ int shadow_client_surface_update(rdpShadowClient* client, REGION16* region) return 1; } +int shadow_client_convert_alpha_pointer_data(BYTE* pixels, BOOL premultiplied, + UINT32 width, UINT32 height, POINTER_COLOR_UPDATE* pointerColor) +{ + UINT32 x, y; + BYTE* pSrc8; + BYTE* pDst8; + int xorStep; + int andStep; + UINT32 andBit; + BYTE* andBits; + UINT32 andPixel; + BYTE A, R, G, B; + + xorStep = (width * 3); + xorStep += (xorStep % 2); + + andStep = ((width + 7) / 8); + andStep += (andStep % 2); + + pointerColor->lengthXorMask = height * xorStep; + pointerColor->xorMaskData = (BYTE*) calloc(1, pointerColor->lengthXorMask); + + if (!pointerColor->xorMaskData) + return -1; + + pointerColor->lengthAndMask = height * andStep; + pointerColor->andMaskData = (BYTE*) calloc(1, pointerColor->lengthAndMask); + + if (!pointerColor->andMaskData) + return -1; + + for (y = 0; y < height; y++) + { + pSrc8 = &pixels[(width * 4) * (height - 1 - y)]; + pDst8 = &(pointerColor->xorMaskData[y * xorStep]); + + andBit = 0x80; + andBits = &(pointerColor->andMaskData[andStep * y]); + + for (x = 0; x < width; x++) + { + B = *pSrc8++; + G = *pSrc8++; + R = *pSrc8++; + A = *pSrc8++; + + andPixel = 0; + + if (A < 64) + A = 0; /* pixel cannot be partially transparent */ + + if (!A) + { + /* transparent pixel: XOR = black, AND = 1 */ + andPixel = 1; + B = G = R = 0; + } + else + { + if (premultiplied) + { + B = (B * 0xFF ) / A; + G = (G * 0xFF ) / A; + R = (R * 0xFF ) / A; + } + } + + *pDst8++ = B; + *pDst8++ = G; + *pDst8++ = R; + + if (andPixel) *andBits |= andBit; + if (!(andBit >>= 1)) { andBits++; andBit = 0x80; } + } + } + + return 1; +} + +int shadow_client_subsystem_process_message(rdpShadowClient* client, wMessage* message) +{ + rdpContext* context = (rdpContext*) client; + rdpUpdate* update = context->update; + + /* FIXME: the pointer updates appear to be broken when used with bulk compression and mstsc */ + + if (message->id == SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID) + { + POINTER_POSITION_UPDATE pointerPosition; + SHADOW_MSG_OUT_POINTER_POSITION_UPDATE* msg = (SHADOW_MSG_OUT_POINTER_POSITION_UPDATE*) message->wParam; + + pointerPosition.xPos = msg->xPos; + pointerPosition.yPos = msg->yPos; + + if ((msg->xPos != client->pointerX) || (msg->yPos != client->pointerY)) + { + IFCALL(update->pointer->PointerPosition, context, &pointerPosition); + + client->pointerX = msg->xPos; + client->pointerY = msg->yPos; + } + + free(msg); + } + else if (message->id == SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID) + { + POINTER_NEW_UPDATE pointerNew; + POINTER_COLOR_UPDATE* pointerColor; + POINTER_CACHED_UPDATE pointerCached; + SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE* msg = (SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE*) message->wParam; + + ZeroMemory(&pointerNew, sizeof(POINTER_NEW_UPDATE)); + + pointerNew.xorBpp = 24; + pointerColor = &(pointerNew.colorPtrAttr); + + pointerColor->cacheIndex = 0; + pointerColor->xPos = msg->xHot; + pointerColor->yPos = msg->yHot; + pointerColor->width = msg->width; + pointerColor->height = msg->height; + + pointerCached.cacheIndex = pointerColor->cacheIndex; + + shadow_client_convert_alpha_pointer_data(msg->pixels, msg->premultiplied, + msg->width, msg->height, pointerColor); + + IFCALL(update->pointer->PointerNew, context, &pointerNew); + IFCALL(update->pointer->PointerCached, context, &pointerCached); + + free(pointerColor->xorMaskData); + free(pointerColor->andMaskData); + + free(msg->pixels); + free(msg); + } + + return 1; +} + void* shadow_client_thread(rdpShadowClient* client) { DWORD status; DWORD nCount; + wMessage message; HANDLE events[32]; HANDLE StopEvent; HANDLE ClientEvent; @@ -712,6 +895,7 @@ void* shadow_client_thread(rdpShadowClient* client) rdpShadowScreen* screen; rdpShadowEncoder* encoder; rdpShadowSubsystem* subsystem; + wMessagePipe* MsgPipe = client->subsystem->MsgPipe; server = client->server; screen = server->screen; @@ -746,6 +930,7 @@ void* shadow_client_thread(rdpShadowClient* client) events[nCount++] = UpdateEvent; events[nCount++] = ClientEvent; events[nCount++] = ChannelEvent; + events[nCount++] = MessageQueue_Event(MsgPipe->Out); status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); @@ -793,12 +978,23 @@ void* shadow_client_thread(rdpShadowClient* client) if (WaitForSingleObject(ChannelEvent, 0) == WAIT_OBJECT_0) { - if (WTSVirtualChannelManagerCheckFileDescriptor(client->vcm) != TRUE) + if (!WTSVirtualChannelManagerCheckFileDescriptor(client->vcm)) { WLog_ERR(TAG, "WTSVirtualChannelManagerCheckFileDescriptor failure"); break; } } + + if (WaitForSingleObject(MessageQueue_Event(MsgPipe->Out), 0) == WAIT_OBJECT_0) + { + if (MessageQueue_Peek(MsgPipe->Out, &message, TRUE)) + { + if (message.id == WMQ_QUIT) + break; + + shadow_client_subsystem_process_message(client, &message); + } + } } peer->Disconnect(peer); diff --git a/server/shadow/shadow_input.c b/server/shadow/shadow_input.c index f5cc078dc..b3e732036 100644 --- a/server/shadow/shadow_input.c +++ b/server/shadow/shadow_input.c @@ -69,6 +69,21 @@ void shadow_input_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) rdpShadowClient* client = (rdpShadowClient*) input->context; rdpShadowSubsystem* subsystem = client->server->subsystem; + if (!(flags & PTR_FLAGS_WHEEL)) + { + client->pointerX = x; + client->pointerY = y; + + if ((client->pointerX == subsystem->pointerX) && + (client->pointerY == subsystem->pointerY)) + { + flags &= ~PTR_FLAGS_MOVE; + + if (!(flags & (PTR_FLAGS_BUTTON1 | PTR_FLAGS_BUTTON2 | PTR_FLAGS_BUTTON3))) + return; + } + } + if (!client->mayInteract) return; @@ -83,6 +98,9 @@ void shadow_input_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, rdpShadowClient* client = (rdpShadowClient*) input->context; rdpShadowSubsystem* subsystem = client->server->subsystem; + client->pointerX = x; + client->pointerY = y; + if (!client->mayInteract) return; diff --git a/server/shadow/shadow_subsystem.h b/server/shadow/shadow_subsystem.h index 2ddbce864..9ad710475 100644 --- a/server/shadow/shadow_subsystem.h +++ b/server/shadow/shadow_subsystem.h @@ -41,6 +41,28 @@ struct _SHADOW_MSG_IN_SUPPRESS_OUTPUT }; typedef struct _SHADOW_MSG_IN_SUPPRESS_OUTPUT SHADOW_MSG_IN_SUPPRESS_OUTPUT; +#define SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID 2001 +#define SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID 2002 + +struct _SHADOW_MSG_OUT_POINTER_POSITION_UPDATE +{ + UINT32 xPos; + UINT32 yPos; +}; +typedef struct _SHADOW_MSG_OUT_POINTER_POSITION_UPDATE SHADOW_MSG_OUT_POINTER_POSITION_UPDATE; + +struct _SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE +{ + UINT32 xHot; + UINT32 yHot; + UINT32 width; + UINT32 height; + BYTE* pixels; + int scanline; + BOOL premultiplied; +}; +typedef struct _SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE; + #ifdef __cplusplus extern "C" { #endif diff --git a/winpr/libwinpr/environment/environment.c b/winpr/libwinpr/environment/environment.c index f473bcd96..70768be25 100644 --- a/winpr/libwinpr/environment/environment.c +++ b/winpr/libwinpr/environment/environment.c @@ -23,9 +23,11 @@ #include "config.h" #endif -#include +#include #include +#include + #ifndef _WIN32 #define stricmp strcasecmp @@ -326,7 +328,7 @@ LPCH MergeEnvironmentStrings(PCSTR original, PCSTR merge) if (mergeStringLength == mergeArraySize) { mergeArraySize += 128; - mergeStrings = (LPCSTR*) realloc(mergeStrings, mergeArraySize * sizeof(char*)); + mergeStrings = (const char**) realloc((void*) mergeStrings, mergeArraySize * sizeof(char*)); if (!mergeStrings) return NULL; @@ -441,7 +443,7 @@ LPCH MergeEnvironmentStrings(PCSTR original, PCSTR merge) lpszEnvironmentBlock[offset] = '\0'; - free(mergeStrings); + free((void*) mergeStrings); return lpszEnvironmentBlock; } diff --git a/winpr/libwinpr/pool/pool.c b/winpr/libwinpr/pool/pool.c index df5c17087..0b097e81d 100644 --- a/winpr/libwinpr/pool/pool.c +++ b/winpr/libwinpr/pool/pool.c @@ -181,9 +181,6 @@ VOID CloseThreadpool(PTP_POOL ptpp) if (pCloseThreadpool) pCloseThreadpool(ptpp); #else - int index; - HANDLE thread; - SetEvent(ptpp->TerminateEvent); ArrayList_Free(ptpp->Threads); diff --git a/winpr/libwinpr/smartcard/smartcard_pcsc.c b/winpr/libwinpr/smartcard/smartcard_pcsc.c index ebf4420be..a0d14c998 100644 --- a/winpr/libwinpr/smartcard/smartcard_pcsc.c +++ b/winpr/libwinpr/smartcard/smartcard_pcsc.c @@ -1382,6 +1382,8 @@ WINSCARDAPI LONG WINAPI PCSC_SCardGetStatusChange_Internal(SCARDCONTEXT hContext { int i, j; int* map; + DWORD dwEventState; + BOOL stateChanged = FALSE; PCSC_DWORD cMappedReaders; PCSC_SCARD_READERSTATE* states; LONG status = SCARD_S_SUCCESS; @@ -1469,11 +1471,7 @@ WINSCARDAPI LONG WINAPI PCSC_SCardGetStatusChange_Internal(SCARDCONTEXT hContext rgReaderStates[i].dwCurrentState = states[j].dwCurrentState; rgReaderStates[i].cbAtr = states[j].cbAtr; CopyMemory(&(rgReaderStates[i].rgbAtr), &(states[j].rgbAtr), PCSC_MAX_ATR_SIZE); - /** - * Why we should interpret and modify the results of pcsc-lite ScardGetStatusChange ? - * Should not we just act as a pass-through between the client and the remote smartcard subsystem ? - */ -#if 0 + /* pcsc-lite puts an event count in the higher bits of dwEventState */ states[j].dwEventState &= 0xFFFF; dwEventState = states[j].dwEventState & ~SCARD_STATE_CHANGED; @@ -1497,19 +1495,14 @@ WINSCARDAPI LONG WINAPI PCSC_SCardGetStatusChange_Internal(SCARDCONTEXT hContext if (rgReaderStates[i].dwCurrentState & SCARD_STATE_IGNORE) rgReaderStates[i].dwEventState = SCARD_STATE_IGNORE; -#endif + rgReaderStates[i].dwEventState = states[j].dwEventState; } - /** - * Why we should interpret and modify the results of pcsc-lite ScardGetStatusChange ? - * Should not we just act as a pass-through between the client and the remote smartcard subsystem ? - */ -#if 0 + if ((status == SCARD_S_SUCCESS) && !stateChanged) status = SCARD_E_TIMEOUT; else if ((status == SCARD_E_TIMEOUT) && stateChanged) return SCARD_S_SUCCESS; -#endif free(states); free(map); diff --git a/winpr/libwinpr/thread/thread.c b/winpr/libwinpr/thread/thread.c index b9107f7bd..461f5765b 100644 --- a/winpr/libwinpr/thread/thread.c +++ b/winpr/libwinpr/thread/thread.c @@ -267,7 +267,7 @@ exit: if (thread->detached || !thread->started) cleanup_handle(thread); - pthread_exit(thread->dwExitCode); + pthread_exit((void*) (size_t) thread->dwExitCode); return rc; } @@ -426,12 +426,13 @@ VOID ExitThread(DWORD dwExitCode) { pthread_t tid = pthread_self(); - if (NULL == thread_list) + if (!thread_list) { WLog_ERR(TAG, "function called without existing thread list!"); #if defined(WITH_DEBUG_THREADS) DumpThreadHandles(); #endif + pthread_exit(0); } else if (!ListDictionary_Contains(thread_list, &tid)) { @@ -439,12 +440,15 @@ VOID ExitThread(DWORD dwExitCode) #if defined(WITH_DEBUG_THREADS) DumpThreadHandles(); #endif + pthread_exit(0); } else { - WINPR_THREAD *thread; + WINPR_THREAD* thread; + ListDictionary_Lock(thread_list); thread = ListDictionary_GetItemValue(thread_list, &tid); + assert(thread); thread->exited = TRUE; thread->dwExitCode = dwExitCode; @@ -457,7 +461,7 @@ VOID ExitThread(DWORD dwExitCode) if (thread->detached || !thread->started) cleanup_handle(thread); - pthread_exit(thread->dwExitCode); + pthread_exit((void*) (size_t) thread->dwExitCode); } } diff --git a/winpr/libwinpr/wtsapi/wtsapi_win32.c b/winpr/libwinpr/wtsapi/wtsapi_win32.c index 252c3e26e..9a0adc697 100644 --- a/winpr/libwinpr/wtsapi/wtsapi_win32.c +++ b/winpr/libwinpr/wtsapi/wtsapi_win32.c @@ -689,7 +689,6 @@ BOOL WINAPI Win32_WTSVirtualChannelQuery(HANDLE hChannelHandle, WTS_VIRTUAL_CLAS VOID WINAPI Win32_WTSFreeMemory(PVOID pMemory) { LocalFree(pMemory); - return TRUE; } BOOL WINAPI Win32_WTSFreeMemoryExW(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory, ULONG NumberOfEntries)