diff --git a/.gitignore b/.gitignore index 98ca450a2..34ff16e31 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,8 @@ LICENSE.txt *Config.cmake *ConfigVersion.cmake include/freerdp/version.h +include/freerdp/build-config.h +buildflags.h *.a.objlist.cmake *.a.objlist diff --git a/CMakeCPack.cmake b/CMakeCPack.cmake index f33be3db1..ca749c0cc 100644 --- a/CMakeCPack.cmake +++ b/CMakeCPack.cmake @@ -60,7 +60,7 @@ set(CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}/resources\\\\FreeRDP_Install.bmp") set(CPACK_NSIS_MUI_ICON "${CMAKE_SOURCE_DIR}/resources\\\\FreeRDP_Icon_96px.ico") set(CPACK_NSIS_MUI_UNICON "${CMAKE_SOURCE_DIR}/resource\\\\FreeRDP_Icon_96px.ico") -set(CPACK_COMPONENTS_ALL client server libraries headers) +set(CPACK_COMPONENTS_ALL client server libraries headers symbols tools) if(MSVC) if(MSVC_RUNTIME STREQUAL "dynamic") @@ -85,6 +85,12 @@ set(CPACK_COMPONENT_LIBRARIES_GROUP "Runtime") set(CPACK_COMPONENT_HEADERS_DISPLAY_NAME "Headers") set(CPACK_COMPONENT_HEADERS_GROUP "Development") +set(CPACK_COMPONENT_SYMBOLS_DISPLAY_NAME "Symbols") +set(CPACK_COMPONENT_SYMBOLS_GROUP "Development") + +set(CPACK_COMPONENT_TOOLS_DISPLAY_NAME "Tools") +set(CPACK_COMPONENT_TOOLS_GROUP "Applications") + set(CPACK_COMPONENT_GROUP_RUNTIME_DESCRIPTION "Runtime") set(CPACK_COMPONENT_GROUP_APPLICATIONS_DESCRIPTION "Applications") set(CPACK_COMPONENT_GROUP_DEVELOPMENT_DESCRIPTION "Development") diff --git a/CMakeLists.txt b/CMakeLists.txt index 85d3c4687..5c2e83ac5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,29 +68,40 @@ if ($ENV{BUILD_NUMBER}) set(BUILD_NUMBER $ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(FREERDP_VERSION_MAJOR "1") -set(FREERDP_VERSION_MINOR "2") -set(FREERDP_VERSION_REVISION "5") +set(FREERDP_VERSION_MAJOR "2") +set(FREERDP_VERSION_MINOR "0") +set(FREERDP_VERSION_REVISION "0") set(FREERDP_VERSION_SUFFIX "dev") -set(FREERDP_API_VERSION "${FREERDP_VERSION_MAJOR}.${FREERDP_VERSION_MINOR}") -set(FREERDP_VERSION "${FREERDP_API_VERSION}.${FREERDP_VERSION_REVISION}") +set(FREERDP_API_VERSION "${FREERDP_VERSION_MAJOR}") +set(FREERDP_VERSION "${FREERDP_VERSION_MAJOR}.${FREERDP_VERSION_MINOR}.${FREERDP_VERSION_REVISION}") if (FREERDP_VERSION_SUFFIX) set(FREERDP_VERSION_FULL "${FREERDP_VERSION}-${FREERDP_VERSION_SUFFIX}") else() set(FREERDP_VERSION_FULL "${FREERDP_VERSION}") endif() +set(FREERDP_INCLUDE_DIR "include/freerdp${FREERDP_VERSION_MAJOR}/") + +# Make paths absolute +if (CMAKE_INSTALL_PREFIX) + get_filename_component(CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}" ABSOLUTE) +endif() +if (FREERDP_EXTERNAL_PATH) + get_filename_component (FREERDP_EXTERNAL_PATH "${FREERDP_EXTERNAL_PATH}" ABSOLUTE) +endif() # Allow to search the host machine for git if(ANDROID OR IOS) SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH) endif(ANDROID OR IOS) + include(GetGitRevisionDescription) git_get_exact_tag(GIT_REVISION --tags --always) + if (${GIT_REVISION} STREQUAL "n/a") - git_rev_parse(GIT_REVISION --short) + git_rev_parse (GIT_REVISION --short) endif() if(ANDROID OR IOS) - SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) + SET (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) endif(ANDROID OR IOS) message(STATUS "Git Revision ${GIT_REVISION}") @@ -104,7 +115,7 @@ if(NOT CMAKE_BUILD_TYPE) endif() if(NOT DEFINED BUILD_SHARED_LIBS) - if(ANDROID OR IOS OR APPLE) + if(IOS OR APPLE) set(BUILD_SHARED_LIBS OFF) else() set(BUILD_SHARED_LIBS ON) @@ -246,6 +257,30 @@ if(${CMAKE_C_COMPILER_ID} STREQUAL "Clang") endif() endif() +# Enable address sanitizer, where supported and when required +if(${CMAKE_C_COMPILER_ID} STREQUAL "Clang" OR CMAKE_COMPILER_IS_GNUCC) + if(WITH_SANITIZE_ADDRESS) + if (DEFINED CMAKE_REQUIRED_FLAGS) + set(SAVE_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) + endif() + set(CMAKE_REQUIRED_FLAGS "-fsanitize=address") + CHECK_C_COMPILER_FLAG ("-fsanitize=address" fsanitize-address) + if(fsanitize-address) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address") + endif() + if (DEFINED SAVE_CMAKE_REQUIRED_FLAGS) + set(CMAKE_REQUIRED_FLAGS ${SAVE_CMAKE_REQUIRED_FLAGS}) + else() + unset(CMAKE_REQUIRED_FLAGS) + endif() + + CHECK_C_COMPILER_FLAG ("-fno-omit-frame-pointer" fno-omit-frame-pointer) + if(fno-omit-frame-pointer) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-omit-frame-pointer") + endif() + endif() +endif() + if(MSVC) # Remove previous warning definitions, # NMake is otherwise complaining. @@ -274,11 +309,11 @@ if(MSVC) set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}) set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}) - if(CMAKE_BUILD_TYPE STREQUAL "Release") - else() - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Zi") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zi") - endif() + if(CMAKE_BUILD_TYPE STREQUAL "Release") + else() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Zi") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zi") + endif() endif() @@ -287,6 +322,15 @@ if(WIN32) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_CRT_SECURE_NO_WARNINGS") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWIN32_LEAN_AND_MEAN") + set(CMAKE_USE_RELATIVE_PATH ON) + if (${CMAKE_GENERATOR} MATCHES "NMake Makefile*") + set(CMAKE_PDB_BINARY_DIR ${CMAKE_BINARY_DIR}) + elseif (${CMAKE_GENERATOR} MATCHES "Visual Studio*") + set(CMAKE_PDB_BINARY_DIR "${CMAKE_BINARY_DIR}/\${CMAKE_INSTALL_CONFIG_NAME}") + else() + message(FATAL "Unknown generator ${CMAKE_GENERATOR}") + endif() + # Set product and vendor for dll and exe version information. set(RC_VERSION_VENDOR ${VENDOR}) set(RC_VERSION_PRODUCT ${PRODUCT}) @@ -327,17 +371,16 @@ if(NOT IOS) check_include_files(fcntl.h HAVE_FCNTL_H) check_include_files(unistd.h HAVE_UNISTD_H) check_include_files(execinfo.h HAVE_EXECINFO_H) - check_include_files(stdint.h HAVE_STDINT_H) check_include_files(inttypes.h HAVE_INTTYPES_H) check_include_files(sys/modem.h HAVE_SYS_MODEM_H) check_include_files(sys/filio.h HAVE_SYS_FILIO_H) check_include_files(sys/sockio.h HAVE_SYS_SOCKIO_H) check_include_files(sys/strtio.h HAVE_SYS_STRTIO_H) check_include_files(sys/select.h HAVE_SYS_SELECT_H) + check_include_files(syslog.h HAVE_SYSLOG_H) else() set(HAVE_FCNTL_H 1) set(HAVE_UNISTD_H 1) - set(HAVE_STDINT_H 1) set(HAVE_INTTYPES_H 1) set(HAVE_SYS_FILIO_H 1) endif() @@ -369,9 +412,9 @@ if(APPLE) # Temporarily disabled, causes the cmake script to be reexecuted, causing the compilation to fail. # Workaround: specify the parameter in the command-line -# if(WITH_CLANG) -# set(CMAKE_C_COMPILER "clang") -# endif() +# if(WITH_CLANG) +# set(CMAKE_C_COMPILER "clang") +# endif() if (WITH_VERBOSE) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -v") @@ -383,14 +426,18 @@ endif(APPLE) if(OPENBSD) set(WITH_MANPAGES "ON") set(WITH_ALSA "OFF") - set(WITH_PULSE "OFF") - set(WITH_OSS "ON") + set(WITH_PULSE "OFF") + set(WITH_OSS "ON") set(WITH_WAYLAND "OFF") endif() # Android if(ANDROID) - set(WITH_LIBRARY_VERSIONING "OFF") + set(WITH_LIBRARY_VERSIONING "OFF") + + if (${ANDROID_ABI} STREQUAL "armeabi") + set (WITH_NEON OFF) + endif() if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") add_definitions(-DNDK_DEBUG=1) @@ -402,40 +449,23 @@ if(ANDROID) endif() set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} -llog") - if (NOT FREERDP_EXTERNAL_JPEG_PATH) - if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/external/jpeg8d") - set(FREERDP_EXTERNAL_JPEG_PATH "${CMAKE_CURRENT_SOURCE_DIR}/external/jpeg8d") + if (NOT FREERDP_EXTERNAL_PATH) + if (IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/external/") + set (FREERDP_EXTERNAL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/external/") else() - message(STATUS "FREERDP_EXTERNAL_SSL_PATH not set! - Needs to be set if openssl is not found in the android NDK (which usually isn't)") + message(STATUS "FREERDP_EXTERNAL_PATH not set!") endif() endif() - if (NOT FREERDP_EXTERNAL_SSL_PATH) - if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/external/openssl") - set(FREERDP_EXTERNAL_SSL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/external/openssl") - else() - message(STATUS "FREERDP_EXTERNAL_SSL_PATH not set! - Needs to be set if openssl is not found in the android NDK (which usually isn't)") - endif() - if(WITH_GPROF) - if (NOT FREERDP_EXTERNAL_PROFILER_PATH) - if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/external/android-ndk-profiler") - set(FREERDP_EXTERNAL_PROFILER_PATH - "${CMAKE_CURRENT_SOURCE_DIR}/external/android-ndk-profiler") - else() - message(STATUS "FREERDP_EXTERNAL_PROFILER_PATH not set!") - endif() - endif() - endif() -endif() -set(CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH} ${FREERDP_EXTERNAL_SSL_PATH} ${FREERDP_EXTERNAL_JPEG_PATH}) -set(CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH} ${FREERDP_EXTERNAL_PROFILER_PATH}) - set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/client/Android/FreeRDPCore/jni/${ANDROID_ABI}) - CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/scripts/regenerate_jni_headers.sh.cmake - ${CMAKE_BINARY_DIR}/scripts/regenerate_jni_headers.sh @ONLY) + list (APPEND CMAKE_INCLUDE_PATH ${FREERDP_EXTERNAL_PATH}/include) + list (APPEND CMAKE_LIBRARY_PATH ${FREERDP_EXTERNAL_PATH}/${ANDROID_ABI}/ ) + set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH ) + set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH ) + if (WITH_GPROF) - CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/scripts/gprof_generate.sh.cmake ${CMAKE_BINARY_DIR}/scripts/gprof_generate.sh @ONLY) + CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/scripts/gprof_generate.sh.cmake + ${CMAKE_BINARY_DIR}/scripts/gprof_generate.sh @ONLY) endif(WITH_GPROF) - endif() set(CMAKE_THREAD_PREFER_PTHREAD TRUE) @@ -449,9 +479,9 @@ if(NOT WIN32) endif() if(WITH_VALGRIND_MEMCHECK) - check_include_files(valgrind/memcheck.h HAVE_VALGRIND_MEMCHECK_H) + check_include_files(valgrind/memcheck.h HAVE_VALGRIND_MEMCHECK_H) else() - unset(HAVE_VALGRIND_MEMCHECK_H CACHE) + unset(HAVE_VALGRIND_MEMCHECK_H CACHE) endif() if(UNIX OR CYGWIN) @@ -589,6 +619,21 @@ if(APPLE) set(OPENSLES_FEATURE_TYPE "DISABLED") endif() +if(UNIX AND NOT ANDROID) + set(WLOG_SYSTEMD_JOURNAL_FEATURE_TYPE "RECOMMENDED") + set(WLOG_SYSTEMD_JOURNAL_FEATURE_PURPOSE "systemd journal appender") + set(WLOG_SYSTEMD_JOURNAL_FEATURE_DESCRIPTION "allows to export wLog to systemd journal") + + #include(Findlibsystemd) + find_feature(libsystemd ${WLOG_SYSTEMD_JOURNAL_FEATURE_TYPE} ${WLOG_SYSTEMD_JOURNAL_FEATURE_PURPOSE} ${WLOG_SYSTEMD_JOURNAL_FEATURE_DESCRIPTION}) + + if(LIBSYSTEMD_FOUND) + set(HAVE_JOURNALD_H TRUE) + else() + unset(HAVE_JOURNALD_H) + endif() +endif(UNIX AND NOT ANDROID) + if(ANDROID) set(X11_FEATURE_TYPE "DISABLED") set(WAYLAND_FEATURE_TYPE "DISABLED") @@ -604,7 +649,6 @@ if(ANDROID) set(OPENSLES_FEATURE_TYPE "REQUIRED") endif() - find_feature(X11 ${X11_FEATURE_TYPE} ${X11_FEATURE_PURPOSE} ${X11_FEATURE_DESCRIPTION}) find_feature(Wayland ${WAYLAND_FEATURE_TYPE} ${WAYLAND_FEATURE_PURPOSE} ${WAYLAND_FEATURE_DESCRIPTION}) find_feature(DirectFB ${DIRECTFB_FEATURE_TYPE} ${DIRECTFB_FEATURE_PURPOSE} ${DIRECTFB_FEATURE_DESCRIPTION}) @@ -677,8 +721,8 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DI # RPATH configuration if(CMAKE_SKIP_RPATH) - set(CMAKE_SKIP_RPATH FALSE) - set(CMAKE_SKIP_INSTALL_RPATH TRUE) + set(CMAKE_SKIP_RPATH FALSE) + set(CMAKE_SKIP_INSTALL_RPATH TRUE) endif() set(CMAKE_SKIP_BUILD_RPATH FALSE) set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) @@ -761,42 +805,22 @@ if(WITH_CHANNELS) add_subdirectory(channels) endif() -if(WITH_CLIENT) - add_subdirectory(client) +if (${CMAKE_VERSION} VERSION_LESS 2.8.12) + set(PUBLIC_KEYWORD "") + set(PRIVATE_KEYWORD "") +else() + set(PUBLIC_KEYWORD "PUBLIC") + set(PRIVATE_KEYWORD "PRIVATE") +endif() + +if(WITH_CLIENT_COMMON OR WITH_CLIENT) +add_subdirectory(client) endif() if(WITH_SERVER) add_subdirectory(server) endif() - -# Exporting - -if(${CMAKE_VERSION} VERSION_GREATER "2.8.10") - - export(PACKAGE freerdp) - - set(FREERDP_CMAKE_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/FreeRDP") - - set(FREERDP_INCLUDE_DIR "include") - - # keep for legacy builds - set(FREERDP_MONOLITHIC_BUILD OFF) - - configure_package_config_file(FreeRDPConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/FreeRDPConfig.cmake - INSTALL_DESTINATION ${FREERDP_CMAKE_INSTALL_DIR} - PATH_VARS FREERDP_INCLUDE_DIR FREERDP_MONOLITHIC_BUILD) - - write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/FreeRDPConfigVersion.cmake - VERSION ${FREERDP_VERSION} COMPATIBILITY SameMajorVersion) - - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/FreeRDPConfig.cmake ${CMAKE_CURRENT_BINARY_DIR}/FreeRDPConfigVersion.cmake - DESTINATION ${FREERDP_CMAKE_INSTALL_DIR}) - - install(EXPORT FreeRDPTargets DESTINATION ${FREERDP_CMAKE_INSTALL_DIR}) - -endif() - # Packaging set(CMAKE_CPACK_INCLUDE_FILE "CMakeCPack.cmake") @@ -813,13 +837,12 @@ endif() include(${CMAKE_CPACK_INCLUDE_FILE}) -set(FREERDP_PC_LIBS "-lfreerdp -lfreerdp-client") -set(WINPR_PC_LIBS "-lwinpr") -if (WITH_SERVER) - set(FREERDP_PC_LIBS "${FREERDP_PC_LIBS} -lfreerdp-server") -endif() - -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/freerdp.pc.in ${CMAKE_CURRENT_BINARY_DIR}/freerdp.pc @ONLY) -configure_file(${CMAKE_CURRENT_SOURCE_DIR}/winpr.pc.in ${CMAKE_CURRENT_BINARY_DIR}/winpr.pc @ONLY) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/freerdp.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/winpr.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) +set(FREERDP_BUILD_CONFIG_LIST "") +GET_CMAKE_PROPERTY(res VARIABLES) +FOREACH(var ${res}) + IF (var MATCHES "^WITH_*|^BUILD_TESTING|^STATIC_CHANNELS|^HAVE_*") + LIST(APPEND FREERDP_BUILD_CONFIG_LIST "${var}=${${var}}") + ENDIF() +ENDFOREACH() +string(REPLACE ";" " " FREERDP_BUILD_CONFIG "${FREERDP_BUILD_CONFIG_LIST}") +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/buildflags.h.in ${CMAKE_CURRENT_BINARY_DIR}/buildflags.h) diff --git a/buildflags.h.in b/buildflags.h.in new file mode 100644 index 000000000..0b8b31092 --- /dev/null +++ b/buildflags.h.in @@ -0,0 +1,11 @@ +#ifndef _FREERDP_BUILD_FLAGS_H +#define _FREERDP_BUILD_FLAGS_H + +#define CFLAGS "${CMAKE_C_FLAGS}" +#define COMPILER_ID "${CMAKE_C_COMPILER_ID}" +#define COMPILER_VERSION "${CMAKE_C_COMPILER_VERSION}" +#define TARGET_ARCH "${TARGET_ARCH}" +#define BUILD_CONFIG "${FREERDP_BUILD_CONFIG}" +#define BUILD_TYPE "${CMAKE_BUILD_TYPE}" + +#endif /*_FREERDP_BUILD_FLAGS_H */ diff --git a/channels/CMakeLists.txt b/channels/CMakeLists.txt index 540b1ac91..a39569758 100644 --- a/channels/CMakeLists.txt +++ b/channels/CMakeLists.txt @@ -154,11 +154,19 @@ macro(add_channel_client_subsystem _channel_prefix _channel_name _subsystem _typ endif() endmacro(add_channel_client_subsystem) -macro(add_channel_client_library _module_prefix _module_name _channel_name _dynamic _entry) - if(${_dynamic} AND MSVC AND (NOT STATIC_CHANNELS)) - set(${_module_prefix}_SRCS ${${_module_prefix}_SRCS} module.def) - endif() +macro(channel_install _targets _destination _export_target) + install(TARGETS ${_targets} DESTINATION ${_destination} EXPORT ${_export_target}) +endmacro(channel_install) +macro(server_channel_install _targets _destination) + channel_install(${_targets} ${_destination} "FreeRDP-ServerTargets") +endmacro(server_channel_install) + +macro(client_channel_install _targets _destination) + channel_install(${_targets} ${_destination} "FreeRDP-ClientTargets") +endmacro(client_channel_install) + +macro(add_channel_client_library _module_prefix _module_name _channel_name _dynamic _entry) if(${_dynamic} AND (NOT STATIC_CHANNELS)) # On windows create dll version information. # Vendor, product and year are already set in top level CMakeLists.txt @@ -178,19 +186,20 @@ macro(add_channel_client_library _module_prefix _module_name _channel_name _dyna endif() add_library(${_module_name} ${${_module_prefix}_SRCS}) + client_channel_install(${_module_name} ${FREERDP_ADDIN_PATH}) else() set(${_module_prefix}_STATIC ON PARENT_SCOPE) set(${_module_prefix}_NAME ${_module_name} PARENT_SCOPE) set(${_module_prefix}_CHANNEL ${_channel_name} PARENT_SCOPE) set(${_module_prefix}_ENTRY ${_entry} PARENT_SCOPE) add_library(${_module_name} STATIC ${${_module_prefix}_SRCS}) + if (${CMAKE_VERSION} VERSION_LESS 2.8.12) + client_channel_install(${_module_name} ${FREERDP_ADDIN_PATH}) + endif() endif() endmacro(add_channel_client_library) macro(add_channel_client_subsystem_library _module_prefix _module_name _channel_name _type _dynamic _entry) - if(${_dynamic} AND MSVC AND (NOT STATIC_CHANNELS)) - set(${_module_prefix}_SRCS ${${_module_prefix}_SRCS} module.def) - endif() if(${_dynamic} AND (NOT STATIC_CHANNELS)) # On windows create dll version information. # Vendor, product and year are already set in top level CMakeLists.txt @@ -210,18 +219,19 @@ macro(add_channel_client_subsystem_library _module_prefix _module_name _channel_ endif() add_library(${_module_name} ${${_module_prefix}_SRCS}) + client_channel_install(${_module_name} ${FREERDP_ADDIN_PATH}) else() set(${_module_prefix}_STATIC ON PARENT_SCOPE) set(${_module_prefix}_NAME ${_module_name} PARENT_SCOPE) set(${_module_prefix}_TYPE ${_type} PARENT_SCOPE) add_library(${_module_name} STATIC ${${_module_prefix}_SRCS}) + if (${CMAKE_VERSION} VERSION_LESS 2.8.12) + client_channel_install(${_module_name} ${FREERDP_ADDIN_PATH}) + endif() endif() endmacro(add_channel_client_subsystem_library) macro(add_channel_server_library _module_prefix _module_name _channel_name _dynamic _entry) - if(${_dynamic} AND MSVC AND (NOT STATIC_CHANNELS)) - set(${_module_prefix}_SRCS ${${_module_prefix}_SRCS} module.def) - endif() if(${_dynamic} AND (NOT STATIC_CHANNELS)) # On windows create dll version information. # Vendor, product and year are already set in top level CMakeLists.txt @@ -240,12 +250,16 @@ macro(add_channel_server_library _module_prefix _module_name _channel_name _dyna endif() add_library(${_module_name} ${${_module_prefix}_SRCS}) + server_channel_install(${_module_name} ${FREERDP_ADDIN_PATH}) else() set(${_module_prefix}_STATIC ON PARENT_SCOPE) set(${_module_prefix}_NAME ${_module_name} PARENT_SCOPE) set(${_module_prefix}_CHANNEL ${_channel_name} PARENT_SCOPE) set(${_module_prefix}_ENTRY ${_entry} PARENT_SCOPE) add_library(${_module_name} STATIC ${${_module_prefix}_SRCS}) + if (${CMAKE_VERSION} VERSION_LESS 2.8.12) + server_channel_install(${_module_name} ${FREERDP_ADDIN_PATH}) + endif() endif() endmacro(add_channel_server_library) diff --git a/channels/audin/client/CMakeLists.txt b/channels/audin/client/CMakeLists.txt index 81b9cbb4e..1f593b8e2 100644 --- a/channels/audin/client/CMakeLists.txt +++ b/channels/audin/client/CMakeLists.txt @@ -25,11 +25,11 @@ include_directories(..) add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry") - - target_link_libraries(${MODULE_NAME} freerdp) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) +if (WITH_DEBUG_SYMBOLS AND MSVC AND NOT STATIC_CHANNELS AND BUILD_SHARED_LIBS) + install(FILES ${CMAKE_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${FREERDP_ADDIN_PATH} COMPONENT symbols) +endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") @@ -52,3 +52,7 @@ endif() if(WITH_WINMM) add_channel_client_subsystem(${MODULE_PREFIX} ${CHANNEL_NAME} "winmm" "") endif() + +if(WITH_MACAUDIO) + add_channel_client_subsystem(${MODULE_PREFIX} ${CHANNEL_NAME} "mac" "") +endif() diff --git a/channels/audin/client/alsa/CMakeLists.txt b/channels/audin/client/alsa/CMakeLists.txt index 46c756bc7..9a90387d9 100644 --- a/channels/audin/client/alsa/CMakeLists.txt +++ b/channels/audin/client/alsa/CMakeLists.txt @@ -30,6 +30,3 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N set(${MODULE_PREFIX}_LIBS freerdp ${ALSA_LIBRARIES}) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) - diff --git a/channels/audin/client/audin_main.c b/channels/audin/client/audin_main.c index 455257066..373ae86dc 100644 --- a/channels/audin/client/audin_main.c +++ b/channels/audin/client/audin_main.c @@ -5,6 +5,7 @@ * Copyright 2010-2011 Vic Lee * Copyright 2015 Thincast Technologies GmbH * Copyright 2015 DI (FH) Martin Haimberger + * Copyright 2015 Armin Novak * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -195,7 +196,7 @@ static UINT audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback, Stream_Read_UINT16(s, format.cbSize); format.data = Stream_Pointer(s); Stream_Seek(s, format.cbSize); - + DEBUG_DVC("wFormatTag=%d nChannels=%d nSamplesPerSec=%d " "nBlockAlign=%d wBitsPerSample=%d cbSize=%d", format.wFormatTag, format.nChannels, format.nSamplesPerSec, @@ -310,7 +311,7 @@ static UINT audin_send_open_reply_pdu(IWTSVirtualChannelCallback* pChannelCallba * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_receive_wave_data(BYTE* data, int size, void* user_data) +static UINT audin_receive_wave_data(const BYTE* data, int size, void* user_data) { UINT error; wStream* out; @@ -521,7 +522,7 @@ static UINT audin_on_close(IWTSVirtualChannelCallback* pChannelCallback) * @return 0 on success, otherwise a Win32 error code */ static UINT audin_on_new_channel_connection(IWTSListenerCallback* pListenerCallback, - IWTSVirtualChannel* pChannel, BYTE* Data, int* pbAccept, + IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept, IWTSVirtualChannelCallback** ppCallback) { AUDIN_CHANNEL_CALLBACK* callback; @@ -667,7 +668,7 @@ static UINT audin_load_device_plugin(IWTSPlugin* pPlugin, const char* name, ADDI * * @return 0 on success, otherwise a Win32 error code */ -UINT audin_set_subsystem(AUDIN_PLUGIN* audin, char* subsystem) +static UINT audin_set_subsystem(AUDIN_PLUGIN* audin, char* subsystem) { free(audin->subsystem); audin->subsystem = _strdup(subsystem); @@ -684,7 +685,7 @@ UINT audin_set_subsystem(AUDIN_PLUGIN* audin, char* subsystem) * * @return 0 on success, otherwise a Win32 error code */ -UINT audin_set_device_name(AUDIN_PLUGIN* audin, char* device_name) +static UINT audin_set_device_name(AUDIN_PLUGIN* audin, char* device_name) { free(audin->device_name); audin->device_name = _strdup(device_name); @@ -696,7 +697,7 @@ UINT audin_set_device_name(AUDIN_PLUGIN* audin, char* device_name) return CHANNEL_RC_OK; } -COMMAND_LINE_ARGUMENT_A audin_args[] = +static COMMAND_LINE_ARGUMENT_A audin_args[] = { { "sys", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "subsystem" }, { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "device" }, @@ -779,9 +780,38 @@ static BOOL audin_process_addin_args(IWTSPlugin* pPlugin, ADDIN_ARGV* args) */ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) { + struct SubsystemEntry + { + char *subsystem; + char *device; + }; + UINT error = CHANNEL_RC_OK; ADDIN_ARGV* args; AUDIN_PLUGIN* audin; + struct SubsystemEntry entries[] = + { +#if defined(WITH_PULSE) + {"pulse", ""}, +#endif +#if defined(WITH_OSS) + {"oss", "default"}, +#endif +#if defined(WITH_ALSA) + {"alsa", "default"}, +#endif +#if defined(WITH_OPENSLES) + {"opensles", "default"}, +#endif +#if defined(WITH_WINMM) + {"winmm", "default"}, +#endif +#if defined(WITH_MACAUDIO) + {"mac", "default"}, +#endif + {NULL,NULL} + }; + struct SubsystemEntry *entry = &entries[0]; assert(pEntryPoints); assert(pEntryPoints->GetPlugin); @@ -807,123 +837,26 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) args = pEntryPoints->GetPluginData(pEntryPoints); audin->rdpcontext = ((freerdp*)((rdpSettings*) pEntryPoints->GetRdpSettings(pEntryPoints))->instance)->context; - if (error == CHANNEL_RC_OK) - audin_process_addin_args((IWTSPlugin*) audin, args); - else + while (entry && entry->subsystem && !audin->device) { - WLog_ERR(TAG, "RegisterPlugin failed with error %lu!", error); - return error; - } + if ((error = audin_set_subsystem(audin, entry->subsystem))) + { + WLog_ERR(TAG, "audin_set_subsystem for %s failed with error %lu!", + entry->subsystem, error); + } + else if ((error = audin_set_device_name(audin, entry->device))) + { + WLog_ERR(TAG, "audin_set_device_name for %s failed with error %lu!", + entry->subsystem, error); + } + else if ((error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args))) + { + WLog_ERR(TAG, "audin_load_device_plugin %s failed with error %lu!", + entry->subsystem, error); + } - if (audin->subsystem && (error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args))) { - WLog_ERR(TAG, "audin_load_device_plugin failed!"); - return error; - } - -#if defined(WITH_PULSE) - if (!audin->device) - { - if ((error = audin_set_subsystem(audin, "pulse"))) - { - WLog_ERR(TAG, "audin_set_subsystem for pulse failed with error %lu!", error); - return error; - } - if ((error = audin_set_device_name(audin, ""))) - { - WLog_ERR(TAG, "audin_set_device_name for pulse failed with error %lu!", error); - return error; - } - if ((error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args))) - { - WLog_ERR(TAG, "audin_load_device_plugin for pulse failed with error %lu!", error); - return error; - } + entry++; } -#endif - -#if defined(WITH_OSS) - if (!audin->device) - { - if ((error = audin_set_subsystem(audin, "oss"))) - { - WLog_ERR(TAG, "audin_set_subsystem for oss failed with error %lu!", error); - return error; - } - if ((error = audin_set_device_name(audin, "default"))) - { - WLog_ERR(TAG, "audin_set_device_name for oss failed with error %lu!", error); - return error; - } - if ((error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args))) - { - WLog_ERR(TAG, "audin_load_device_plugin oss pulse failed with error %lu!", error); - return error; - } - } -#endif - -#if defined(WITH_ALSA) - if (!audin->device) - { - if ((error = audin_set_subsystem(audin, "alsa"))) - { - WLog_ERR(TAG, "audin_set_subsystem for alsa failed with error %lu!", error); - return error; - } - if ((error = audin_set_device_name(audin, "default"))) - { - WLog_ERR(TAG, "audin_set_device_name for alsa failed with error %lu!", error); - return error; - } - if ((error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args))) - { - WLog_ERR(TAG, "audin_load_device_plugin oss alsa failed with error %lu!", error); - return error; - } - } -#endif - -#if defined(WITH_OPENSLES) - if (!audin->device) - { - if ((error = audin_set_subsystem(audin, "opensles"))) - { - WLog_ERR(TAG, "audin_set_subsystem for opensles failed with error %lu!", error); - return error; - } - if ((error = audin_set_device_name(audin, "default"))) - { - WLog_ERR(TAG, "audin_set_device_name for opensles failed with error %lu!", error); - return error; - } - if ((error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args))) - { - WLog_ERR(TAG, "audin_load_device_plugin oss opensles failed with error %lu!", error); - return error; - } - } -#endif - -#if defined(WITH_WINMM) - if (!audin->device) - { - if ((error = audin_set_subsystem(audin, "winmm"))) - { - WLog_ERR(TAG, "audin_set_subsystem for winmm failed with error %lu!", error); - return error; - } - if ((error = audin_set_device_name(audin, "default"))) - { - WLog_ERR(TAG, "audin_set_device_name for winmm failed with error %lu!", error); - return error; - } - if ((error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args))) - { - WLog_ERR(TAG, "audin_load_device_plugin oss winmm failed with error %lu!", error); - return error; - } - } -#endif if (audin->device == NULL) { diff --git a/client/Android/aFreeRDP/jni/CMakeLists.txt b/channels/audin/client/mac/CMakeLists.txt similarity index 54% rename from client/Android/aFreeRDP/jni/CMakeLists.txt rename to channels/audin/client/mac/CMakeLists.txt index a8753679b..a5371c1ea 100644 --- a/client/Android/aFreeRDP/jni/CMakeLists.txt +++ b/channels/audin/client/mac/CMakeLists.txt @@ -1,7 +1,8 @@ # FreeRDP: A Remote Desktop Protocol Implementation -# Android Client +# FreeRDP cmake build script # -# Copyright 2013 Armin Novak +# Copyright (c) 2015 Armin Novak +# Copyright (c) 2015 Thincast Technologies GmbH # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,8 +16,16 @@ # See the License for the specific language governing permissions and # limitations under the License. -CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/Application.mk.cmake - ${CMAKE_CURRENT_BINARY_DIR}/Application.mk @ONLY) -CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/Android.mk.cmake - ${CMAKE_CURRENT_BINARY_DIR}/Android.mk @ONLY) +define_channel_client_subsystem("audin" "mac" "") +set(${MODULE_PREFIX}_SRCS + audin_mac.c) + +include_directories(..) +include_directories(${MAC_INCLUDE_DIRS}) + +add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "") + +set(${MODULE_PREFIX}_LIBS freerdp ${MAC_LIBRARIES}) + +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/channels/audin/client/mac/audin_mac.c b/channels/audin/client/mac/audin_mac.c new file mode 100644 index 000000000..07b789477 --- /dev/null +++ b/channels/audin/client/mac/audin_mac.c @@ -0,0 +1,461 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Audio Input Redirection Virtual Channel - Mac OS X implementation + * + * Copyright (c) 2015 Armin Novak + * Copyright 2015 Thincast Technologies GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "audin_main.h" + +#define MAC_AUDIO_QUEUE_NUM_BUFFERS 100 +#define MAC_AUDIO_QUEUE_BUFFER_SIZE 32768 + +typedef struct _AudinMacDevice +{ + IAudinDevice iface; + + FREERDP_DSP_CONTEXT* dsp_context; + + audinFormat format; + UINT32 FramesPerPacket; + int dev_unit; + + AudinReceive receive; + void* user_data; + + rdpContext* rdpcontext; + + bool isOpen; + AudioQueueRef audioQueue; + AudioStreamBasicDescription audioFormat; + AudioQueueBufferRef audioBuffers[MAC_AUDIO_QUEUE_NUM_BUFFERS]; +} AudinMacDevice; + +static AudioFormatID audin_mac_get_format(const audinFormat* format) +{ + switch (format->wFormatTag) + { + case WAVE_FORMAT_PCM: + return kAudioFormatLinearPCM; + /* + case WAVE_FORMAT_GSM610: + return kAudioFormatMicrosoftGSM; + case WAVE_FORMAT_ALAW: + return kAudioFormatALaw; + case WAVE_FORMAT_MULAW: + return kAudioFormatULaw; + case WAVE_FORMAT_AAC_MS: + return kAudioFormatMPEG4AAC; + case WAVE_FORMAT_ADPCM: + case WAVE_FORMAT_DVI_ADPCM: + return kAudioFormatLinearPCM; + */ + } + + return 0; +} + +static AudioFormatFlags audin_mac_get_flags_for_format(const audinFormat* format) +{ + switch(format->wFormatTag) + { + case WAVE_FORMAT_DVI_ADPCM: + case WAVE_FORMAT_ADPCM: + case WAVE_FORMAT_PCM: + return kAudioFormatFlagIsSignedInteger; + default: + return 0; + } +} + +static BOOL audin_mac_format_supported(IAudinDevice* device, audinFormat* format) +{ + AudioFormatID req_fmt = 0; + + if (device == NULL || format == NULL) + return FALSE; + + req_fmt = audin_mac_get_format(format); + + if (req_fmt == 0) + return FALSE; + + return TRUE; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT audin_mac_set_format(IAudinDevice* device, audinFormat* format, UINT32 FramesPerPacket) +{ + AudinMacDevice* mac = (AudinMacDevice*)device; + + if (device == NULL || format == NULL) + return ERROR_INVALID_PARAMETER; + + mac->FramesPerPacket = FramesPerPacket; + CopyMemory(&(mac->format), format, sizeof(audinFormat)); + + WLog_INFO(TAG, "Audio Format %s [channels=%d, samples=%d, bits=%d]", + rdpsnd_get_audio_tag_string(format->wFormatTag), + format->nChannels, format->nSamplesPerSec, format->wBitsPerSample); + + switch (format->wFormatTag) + { + case WAVE_FORMAT_ADPCM: + case WAVE_FORMAT_DVI_ADPCM: + mac->FramesPerPacket *= 4; /* Compression ratio. */ + mac->format.wBitsPerSample *= 4; + break; + } + + mac->audioFormat.mBitsPerChannel = mac->format.wBitsPerSample; + mac->audioFormat.mChannelsPerFrame = mac->format.nChannels; + mac->audioFormat.mFormatFlags = audin_mac_get_flags_for_format(format); + mac->audioFormat.mFormatID = audin_mac_get_format(format); + mac->audioFormat.mFramesPerPacket = 1; + mac->audioFormat.mSampleRate = mac->format.nSamplesPerSec; + mac->audioFormat.mBytesPerFrame = + mac->audioFormat.mChannelsPerFrame * mac->audioFormat.mBitsPerChannel / 8; + mac->audioFormat.mBytesPerPacket = + mac->audioFormat.mBytesPerFrame * mac->audioFormat.mFramesPerPacket; + + return CHANNEL_RC_OK; +} + +static void mac_audio_queue_input_cb(void *aqData, + AudioQueueRef inAQ, + AudioQueueBufferRef inBuffer, + const AudioTimeStamp *inStartTime, + UInt32 inNumPackets, + const AudioStreamPacketDescription *inPacketDesc) +{ + AudinMacDevice* mac = (AudinMacDevice*)aqData; + UINT error; + int encoded_size; + const BYTE *encoded_data; + BYTE *buffer = inBuffer->mAudioData; + int buffer_size = inBuffer->mAudioDataByteSize; + + (void)inAQ; + (void)inStartTime; + (void)inNumPackets; + (void)inPacketDesc; + + + /* Process. */ + switch (mac->format.wFormatTag) { + case WAVE_FORMAT_ADPCM: + if (!mac->dsp_context->encode_ms_adpcm(mac->dsp_context, + buffer, buffer_size, mac->format.nChannels, mac->format.nBlockAlign)) + { + SetLastError(ERROR_INTERNAL_ERROR); + return; + } + encoded_data = mac->dsp_context->adpcm_buffer; + encoded_size = mac->dsp_context->adpcm_size; + break; + case WAVE_FORMAT_DVI_ADPCM: + if (!mac->dsp_context->encode_ima_adpcm(mac->dsp_context, + buffer, buffer_size, mac->format.nChannels, mac->format.nBlockAlign)) + { + SetLastError(ERROR_INTERNAL_ERROR); + break; + } + encoded_data = mac->dsp_context->adpcm_buffer; + encoded_size = mac->dsp_context->adpcm_size; + break; + default: + encoded_data = buffer; + encoded_size = buffer_size; + break; + } + + if ((error = mac->receive(encoded_data, encoded_size, mac->user_data))) + { + WLog_ERR(TAG, "mac->receive failed with error %lu", error); + SetLastError(ERROR_INTERNAL_ERROR); + return; + } + +} + +static UINT audin_mac_close(IAudinDevice *device) +{ + UINT errCode = CHANNEL_RC_OK; + char errString[1024]; + OSStatus devStat; + AudinMacDevice *mac = (AudinMacDevice*)device; + + if (device == NULL) + return ERROR_INVALID_PARAMETER; + + if (mac->isOpen) + { + devStat = AudioQueueStop(mac->audioQueue, true); + if (devStat != 0) + { + errCode = GetLastError(); + WLog_ERR(TAG, "AudioQueueStop failed with %s [%d]", + winpr_strerror(errCode, errString, sizeof(errString)), errCode); + } + mac->isOpen = false; + } + + if (mac->audioQueue) + { + devStat = AudioQueueDispose(mac->audioQueue, true); + if (devStat != 0) + { + errCode = GetLastError(); + WLog_ERR(TAG, "AudioQueueDispose failed with %s [%d]", + winpr_strerror(errCode, errString, sizeof(errString)), errCode); + } + + mac->audioQueue = NULL; + } + + mac->receive = NULL; + mac->user_data = NULL; + + return errCode; +} + +static UINT audin_mac_open(IAudinDevice *device, AudinReceive receive, void *user_data) { + AudinMacDevice *mac = (AudinMacDevice*)device; + DWORD errCode; + char errString[1024]; + OSStatus devStat; + size_t index; + + mac->receive = receive; + mac->user_data = user_data; + + devStat = AudioQueueNewInput(&(mac->audioFormat), mac_audio_queue_input_cb, + mac, NULL, kCFRunLoopCommonModes, 0, &(mac->audioQueue)); + if (devStat != 0) + { + errCode = GetLastError(); + WLog_ERR(TAG, "AudioQueueNewInput failed with %s [%d]", + winpr_strerror(errCode, errString, sizeof(errString)), errCode); + goto err_out; + } + + for (index = 0; index < MAC_AUDIO_QUEUE_NUM_BUFFERS; index++) + { + devStat = AudioQueueAllocateBuffer(mac->audioQueue, MAC_AUDIO_QUEUE_BUFFER_SIZE, + &mac->audioBuffers[index]); + if (devStat != 0) + { + errCode = GetLastError(); + WLog_ERR(TAG, "AudioQueueAllocateBuffer failed with %s [%d]", + winpr_strerror(errCode, errString, sizeof(errString)), errCode); + goto err_out; + } + + devStat = AudioQueueEnqueueBuffer(mac->audioQueue, + mac->audioBuffers[index], + 0, + NULL); + if (devStat != 0) + { + errCode = GetLastError(); + WLog_ERR(TAG, "AudioQueueEnqueueBuffer failed with %s [%d]", + winpr_strerror(errCode, errString, sizeof(errString)), errCode); + goto err_out; + } + } + + freerdp_dsp_context_reset_adpcm(mac->dsp_context); + + devStat = AudioQueueStart(mac->audioQueue, NULL); + if (devStat != 0) + { + errCode = GetLastError(); + WLog_ERR(TAG, "AudioQueueStart failed with %s [%d]", + winpr_strerror(errCode, errString, sizeof(errString)), errCode); + goto err_out; + } + mac->isOpen = true; + + return CHANNEL_RC_OK; + +err_out: + audin_mac_close(device); + return CHANNEL_RC_INITIALIZATION_ERROR; +} + +static UINT audin_mac_free(IAudinDevice* device) +{ + AudinMacDevice *mac = (AudinMacDevice*)device; + + int error; + + if (device == NULL) + return ERROR_INVALID_PARAMETER; + + if ((error = audin_mac_close(device))) + { + WLog_ERR(TAG, "audin_oss_close failed with error code %d!", error); + } + freerdp_dsp_context_free(mac->dsp_context); + free(mac); + + return CHANNEL_RC_OK; +} + +static COMMAND_LINE_ARGUMENT_A audin_mac_args[] = +{ + { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "audio device name" }, + { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } +}; + +static UINT audin_mac_parse_addin_args(AudinMacDevice *device, ADDIN_ARGV *args) +{ + DWORD errCode; + char errString[1024]; + int status; + char* str_num, *eptr; + DWORD flags; + COMMAND_LINE_ARGUMENT_A* arg; + AudinMacDevice* mac = (AudinMacDevice*)device; + + if (args->argc == 1) + return CHANNEL_RC_OK; + + flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; + status = CommandLineParseArgumentsA(args->argc, (const char**)args->argv, audin_mac_args, flags, mac, NULL, NULL); + + if (status < 0) + return ERROR_INVALID_PARAMETER; + + arg = audin_mac_args; + + do + { + if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT)) + continue; + + CommandLineSwitchStart(arg) + CommandLineSwitchCase(arg, "dev") + { + str_num = _strdup(arg->Value); + if (!str_num) + { + errCode = GetLastError(); + WLog_ERR(TAG, "_strdup failed with %s [%d]", + winpr_strerror(errCode, errString, sizeof(errString)), errCode); + return CHANNEL_RC_NO_MEMORY; + } + mac->dev_unit = strtol(str_num, &eptr, 10); + + if (mac->dev_unit < 0 || *eptr != '\0') + mac->dev_unit = -1; + + free(str_num); + } + CommandLineSwitchEnd(arg) + } + while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + + return CHANNEL_RC_OK; +} + +#ifdef STATIC_CHANNELS +#define freerdp_audin_client_subsystem_entry mac_freerdp_audin_client_subsystem_entry +#endif + +UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints) +{ + DWORD errCode; + char errString[1024]; + ADDIN_ARGV *args; + AudinMacDevice *mac; + UINT error; + + mac = (AudinMacDevice*)calloc(1, sizeof(AudinMacDevice)); + if (!mac) + { + errCode = GetLastError(); + WLog_ERR(TAG, "calloc failed with %s [%d]", + winpr_strerror(errCode, errString, sizeof(errString)), errCode); + return CHANNEL_RC_NO_MEMORY; + } + + mac->iface.Open = audin_mac_open; + mac->iface.FormatSupported = audin_mac_format_supported; + mac->iface.SetFormat = audin_mac_set_format; + mac->iface.Close = audin_mac_close; + mac->iface.Free = audin_mac_free; + mac->rdpcontext = pEntryPoints->rdpcontext; + + mac->dev_unit = -1; + args = pEntryPoints->args; + + if ((error = audin_mac_parse_addin_args(mac, args))) + { + WLog_ERR(TAG, "audin_mac_parse_addin_args failed with %lu!", error); + goto error_out; + } + + mac->dsp_context = freerdp_dsp_context_new(); + if (!mac->dsp_context) + { + WLog_ERR(TAG, "freerdp_dsp_context_new failed!"); + error = CHANNEL_RC_NO_MEMORY; + goto error_out; + } + + if ((error = pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) mac))) + { + WLog_ERR(TAG, "RegisterAudinDevice failed with error %lu!", error); + goto error_out; + } + + return CHANNEL_RC_OK; + +error_out: + freerdp_dsp_context_free(mac->dsp_context); + free(mac); + return error; + +} diff --git a/channels/audin/client/opensles/CMakeLists.txt b/channels/audin/client/opensles/CMakeLists.txt index 8844c22ec..abc69219f 100644 --- a/channels/audin/client/opensles/CMakeLists.txt +++ b/channels/audin/client/opensles/CMakeLists.txt @@ -31,5 +31,3 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N set(${MODULE_PREFIX}_LIBS freerdp ${OPENSLES_LIBRARIES}) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/audin/client/oss/CMakeLists.txt b/channels/audin/client/oss/CMakeLists.txt index 1b34fd0de..315e71e60 100644 --- a/channels/audin/client/oss/CMakeLists.txt +++ b/channels/audin/client/oss/CMakeLists.txt @@ -31,5 +31,3 @@ set(${MODULE_PREFIX}_LIBS freerdp ${OSS_LIBRARIES}) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) - diff --git a/channels/audin/client/pulse/CMakeLists.txt b/channels/audin/client/pulse/CMakeLists.txt index 5047aaef5..10000f4b3 100644 --- a/channels/audin/client/pulse/CMakeLists.txt +++ b/channels/audin/client/pulse/CMakeLists.txt @@ -30,5 +30,3 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N set(${MODULE_PREFIX}_LIBS freerdp ${PULSE_LIBRARY}) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/audin/client/winmm/CMakeLists.txt b/channels/audin/client/winmm/CMakeLists.txt index a71f1c6d8..c7d3e2b14 100644 --- a/channels/audin/client/winmm/CMakeLists.txt +++ b/channels/audin/client/winmm/CMakeLists.txt @@ -31,6 +31,8 @@ set(${MODULE_PREFIX}_LIBS freerdp winmm.lib) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) +if (WITH_DEBUG_SYMBOLS AND MSVC AND NOT STATIC_CHANNELS AND BUILD_SHARED_LIBS) + install(FILES ${CMAKE_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${FREERDP_ADDIN_PATH} COMPONENT symbols) +endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client/winmm") diff --git a/channels/audin/server/CMakeLists.txt b/channels/audin/server/CMakeLists.txt index 7f5308957..4d4004fb3 100644 --- a/channels/audin/server/CMakeLists.txt +++ b/channels/audin/server/CMakeLists.txt @@ -26,6 +26,4 @@ add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE target_link_libraries(${MODULE_NAME} freerdp) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) - set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server") diff --git a/channels/client/addin.c b/channels/client/addin.c index 8f4d54bc3..a2d688006 100644 --- a/channels/client/addin.c +++ b/channels/client/addin.c @@ -31,6 +31,7 @@ #include #include +#include #include #include "tables.h" @@ -181,22 +182,22 @@ FREERDP_ADDIN** freerdp_channels_list_dynamic_addins(LPSTR pszName, LPSTR pszSub if (pszName && pszSubsystem && pszType) { - sprintf_s(pszPattern, cchPattern, CMAKE_SHARED_LIBRARY_PREFIX"%s-client-%s-%s.%s", + sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX"%s-client-%s-%s.%s", pszName, pszSubsystem, pszType, pszExtension); } else if (pszName && pszType) { - sprintf_s(pszPattern, cchPattern, CMAKE_SHARED_LIBRARY_PREFIX"%s-client-?-%s.%s", + sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX"%s-client-?-%s.%s", pszName, pszType, pszExtension); } else if (pszName) { - sprintf_s(pszPattern, cchPattern, CMAKE_SHARED_LIBRARY_PREFIX"%s-client*.%s", + sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX"%s-client*.%s", pszName, pszExtension); } else { - sprintf_s(pszPattern, cchPattern, CMAKE_SHARED_LIBRARY_PREFIX"?-client*.%s", + sprintf_s(pszPattern, cchPattern, FREERDP_SHARED_LIBRARY_PREFIX"?-client*.%s", pszExtension); } diff --git a/channels/cliprdr/client/CMakeLists.txt b/channels/cliprdr/client/CMakeLists.txt index 99f3b6621..c8ca54482 100644 --- a/channels/cliprdr/client/CMakeLists.txt +++ b/channels/cliprdr/client/CMakeLists.txt @@ -25,10 +25,6 @@ set(${MODULE_PREFIX}_SRCS add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry") - - set(${MODULE_PREFIX}_LIBS freerdp winpr) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) - set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/cliprdr/client/cliprdr_main.c b/channels/cliprdr/client/cliprdr_main.c index 708663381..18b594ed0 100644 --- a/channels/cliprdr/client/cliprdr_main.c +++ b/channels/cliprdr/client/cliprdr_main.c @@ -46,7 +46,7 @@ const char* const CB_MSG_TYPE_STRINGS[] = "CB_CLIP_CAPS", "CB_FILECONTENTS_REQUEST", "CB_FILECONTENTS_RESPONSE", - "CB_LOCK_CLIPDATA" + "CB_LOCK_CLIPDATA", "CB_UNLOCK_CLIPDATA" }; @@ -471,9 +471,9 @@ static UINT cliprdr_order_recv(cliprdrPlugin* cliprdr, wStream* s) Stream_Read_UINT16(s, msgFlags); /* msgFlags (2 bytes) */ Stream_Read_UINT32(s, dataLen); /* dataLen (4 bytes) */ - DEBUG_CLIPRDR("msgType: %s (%d), msgFlags: %d dataLen: %d", - CB_MSG_TYPE_STRINGS[msgType], msgType, msgFlags, dataLen); #ifdef WITH_DEBUG_CLIPRDR + WLog_DBG(TAG, "msgType: %s (%d), msgFlags: %d dataLen: %d", + CB_MSG_TYPE_STRINGS[msgType], msgType, msgFlags, dataLen); winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), dataLen + 8); #endif @@ -910,7 +910,7 @@ UINT cliprdr_client_file_contents_response(CliprdrClientContext* context, CLIPRD if (fileContentsResponse->dwFlags & FILECONTENTS_SIZE) fileContentsResponse->cbRequested = sizeof(UINT64); - s = cliprdr_packet_new(CB_FILECONTENTS_REQUEST, 0, + s = cliprdr_packet_new(CB_FILECONTENTS_RESPONSE, fileContentsResponse->msgFlags, 4 + fileContentsResponse->cbRequested); if (!s) diff --git a/channels/cliprdr/server/CMakeLists.txt b/channels/cliprdr/server/CMakeLists.txt index 41d993236..911c7a4ad 100644 --- a/channels/cliprdr/server/CMakeLists.txt +++ b/channels/cliprdr/server/CMakeLists.txt @@ -23,10 +23,6 @@ set(${MODULE_PREFIX}_SRCS add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry") - - target_link_libraries(${MODULE_NAME} freerdp) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) - set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server") diff --git a/channels/cliprdr/server/cliprdr_main.c b/channels/cliprdr/server/cliprdr_main.c index 4480f9716..24a34c57f 100644 --- a/channels/cliprdr/server/cliprdr_main.c +++ b/channels/cliprdr/server/cliprdr_main.c @@ -193,7 +193,7 @@ static UINT cliprdr_server_format_list(CliprdrServerContext* context, CLIPRDR_FO CLIPRDR_FORMAT* format; CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*) context->handle; - if (!cliprdr->useLongFormatNames) + if (!context->useLongFormatNames) { length = formatList->numFormats * 36; @@ -470,7 +470,7 @@ static UINT cliprdr_server_file_contents_response(CliprdrServerContext* context, if (fileContentsResponse->dwFlags & FILECONTENTS_SIZE) fileContentsResponse->cbRequested = sizeof(UINT64); - s = cliprdr_server_packet_new(CB_FILECONTENTS_REQUEST, 0, + s = cliprdr_server_packet_new(CB_FILECONTENTS_RESPONSE, fileContentsResponse->msgFlags, 4 + fileContentsResponse->cbRequested); if (!s) @@ -504,22 +504,21 @@ static UINT cliprdr_server_receive_general_capability(CliprdrServerContext* cont { UINT32 version; UINT32 generalFlags; - CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*) context->handle; Stream_Read_UINT32(s, version); /* version (4 bytes) */ Stream_Read_UINT32(s, generalFlags); /* generalFlags (4 bytes) */ - if (generalFlags & CB_USE_LONG_FORMAT_NAMES) - cliprdr->useLongFormatNames = TRUE; + if (context->useLongFormatNames) + context->useLongFormatNames = (generalFlags & CB_USE_LONG_FORMAT_NAMES) ? TRUE : FALSE; - if (generalFlags & CB_STREAM_FILECLIP_ENABLED) - cliprdr->streamFileClipEnabled = TRUE; + if (context->streamFileClipEnabled) + context->streamFileClipEnabled = (generalFlags & CB_STREAM_FILECLIP_ENABLED) ? TRUE : FALSE; - if (generalFlags & CB_FILECLIP_NO_FILE_PATHS) - cliprdr->fileClipNoFilePaths = TRUE; + if (context->fileClipNoFilePaths) + context->fileClipNoFilePaths = (generalFlags & CB_FILECLIP_NO_FILE_PATHS) ? TRUE : FALSE; - if (generalFlags & CB_CAN_LOCK_CLIPDATA) - cliprdr->canLockClipData = TRUE; + if (context->canLockClipData) + context->canLockClipData = (generalFlags & CB_CAN_LOCK_CLIPDATA) ? TRUE : FALSE; return CHANNEL_RC_OK; } @@ -634,7 +633,6 @@ static UINT cliprdr_server_receive_format_list(CliprdrServerContext* context, wS WCHAR* wszFormatName; CLIPRDR_FORMAT* formats = NULL; CLIPRDR_FORMAT_LIST formatList; - CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*) context->handle; UINT error = CHANNEL_RC_OK; dataLen = header->dataLen; @@ -654,7 +652,7 @@ static UINT cliprdr_server_receive_format_list(CliprdrServerContext* context, wS formatList.formats = NULL; formatList.numFormats = 0; } - else if (!cliprdr->useLongFormatNames) + else if (!context->useLongFormatNames) { formatList.numFormats = (dataLen / 36); @@ -957,7 +955,7 @@ static UINT cliprdr_server_receive_filecontents_request(CliprdrServerContext* co request.msgFlags = header->msgFlags; request.dataLen = header->dataLen; - if (Stream_GetRemainingLength(s) < 28) + if (Stream_GetRemainingLength(s) < 24) { WLog_ERR(TAG, "not enought data in stream!"); return ERROR_INVALID_DATA; @@ -969,7 +967,10 @@ static UINT cliprdr_server_receive_filecontents_request(CliprdrServerContext* co Stream_Read_UINT32(s, request.nPositionLow); /* nPositionLow (4 bytes) */ Stream_Read_UINT32(s, request.nPositionHigh); /* nPositionHigh (4 bytes) */ Stream_Read_UINT32(s, request.cbRequested); /* cbRequested (4 bytes) */ - Stream_Read_UINT32(s, request.clipDataId); /* clipDataId (4 bytes) */ + if (Stream_GetRemainingLength(s) < 4) /* clipDataId (4 bytes) optional */ + request.clipDataId = 0; + else + Stream_Read_UINT32(s, request.clipDataId); IFCALLRET(context->ClientFileContentsRequest, error, context, &request); if (error) @@ -1005,9 +1006,9 @@ static UINT cliprdr_server_receive_filecontents_response(CliprdrServerContext* c response.cbRequested = header->dataLen - 4; response.requestedData = Stream_Pointer(s); /* requestedFileContentsData */ - IFCALLRET(context->ServerFileContentsResponse, error, context, &response); + IFCALLRET(context->ClientFileContentsResponse, error, context, &response); if (error) - WLog_ERR(TAG, "ServerFileContentsResponse failed with error %lu!", error); + WLog_ERR(TAG, "ClientFileContentsResponse failed with error %lu!", error); return error; } @@ -1095,7 +1096,6 @@ static UINT cliprdr_server_init(CliprdrServerContext* context) CLIPRDR_CAPABILITIES capabilities; CLIPRDR_MONITOR_READY monitorReady; CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet; - CliprdrServerPrivate* cliprdr = (CliprdrServerPrivate*) context->handle; UINT error; ZeroMemory(&capabilities, sizeof(capabilities)); @@ -1103,9 +1103,18 @@ static UINT cliprdr_server_init(CliprdrServerContext* context) generalFlags = 0; - if (cliprdr->useLongFormatNames) + if (context->useLongFormatNames) generalFlags |= CB_USE_LONG_FORMAT_NAMES; + if (context->streamFileClipEnabled) + generalFlags |= CB_STREAM_FILECLIP_ENABLED; + + if (context->fileClipNoFilePaths) + generalFlags |= CB_FILECLIP_NO_FILE_PATHS; + + if (context->canLockClipData) + generalFlags |= CB_CAN_LOCK_CLIPDATA; + capabilities.msgType = CB_CLIP_CAPS; capabilities.msgFlags = 0; capabilities.dataLen = 4 + CB_CAPSTYPE_GENERAL_LEN; @@ -1409,12 +1418,6 @@ static UINT cliprdr_server_close(CliprdrServerContext* context) cliprdr->ChannelHandle = NULL; } - if (cliprdr->ChannelEvent) - { - CloseHandle(cliprdr->ChannelEvent); - cliprdr->ChannelEvent = NULL; - } - return CHANNEL_RC_OK; } @@ -1533,11 +1536,6 @@ CliprdrServerContext* cliprdr_server_context_new(HANDLE vcm) { cliprdr->vcm = vcm; - cliprdr->useLongFormatNames = TRUE; - cliprdr->streamFileClipEnabled = TRUE; - cliprdr->fileClipNoFilePaths = TRUE; - cliprdr->canLockClipData = TRUE; - cliprdr->s = Stream_New(NULL, 4096); if(!cliprdr->s) @@ -1572,5 +1570,6 @@ void cliprdr_server_context_free(CliprdrServerContext* context) free(cliprdr->temporaryDirectory); } + free(context->handle); free(context); } diff --git a/channels/cliprdr/server/cliprdr_main.h b/channels/cliprdr/server/cliprdr_main.h index 0c51e5c99..362d85a83 100644 --- a/channels/cliprdr/server/cliprdr_main.h +++ b/channels/cliprdr/server/cliprdr_main.h @@ -40,11 +40,6 @@ struct _cliprdr_server_private void* ChannelHandle; HANDLE ChannelEvent; - BOOL useLongFormatNames; - BOOL streamFileClipEnabled; - BOOL fileClipNoFilePaths; - BOOL canLockClipData; - wStream* s; char* temporaryDirectory; }; diff --git a/channels/disp/client/CMakeLists.txt b/channels/disp/client/CMakeLists.txt index f5072e5d9..6bed7bfff 100644 --- a/channels/disp/client/CMakeLists.txt +++ b/channels/disp/client/CMakeLists.txt @@ -31,6 +31,9 @@ set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) + +if (WITH_DEBUG_SYMBOLS AND MSVC AND NOT STATIC_CHANNELS AND BUILD_SHARED_LIBS) + install(FILES ${CMAKE_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${FREERDP_ADDIN_PATH} COMPONENT symbols) +endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/disp/client/disp_main.c b/channels/disp/client/disp_main.c index 6486388ba..d70f61964 100644 --- a/channels/disp/client/disp_main.c +++ b/channels/disp/client/disp_main.c @@ -254,7 +254,7 @@ static UINT disp_on_close(IWTSVirtualChannelCallback* pChannelCallback) * @return 0 on success, otherwise a Win32 error code */ static UINT disp_on_new_channel_connection(IWTSListenerCallback* pListenerCallback, - IWTSVirtualChannel* pChannel, BYTE* Data, int* pbAccept, + IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept, IWTSVirtualChannelCallback** ppCallback) { DISP_CHANNEL_CALLBACK* callback; diff --git a/channels/drdynvc/client/CMakeLists.txt b/channels/drdynvc/client/CMakeLists.txt index 3401865af..244d1985f 100644 --- a/channels/drdynvc/client/CMakeLists.txt +++ b/channels/drdynvc/client/CMakeLists.txt @@ -23,6 +23,5 @@ set(${MODULE_PREFIX}_SRCS add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry") -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) - + set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/drdynvc/client/drdynvc_main.c b/channels/drdynvc/client/drdynvc_main.c index cfe8679bc..29111fde8 100644 --- a/channels/drdynvc/client/drdynvc_main.c +++ b/channels/drdynvc/client/drdynvc_main.c @@ -436,7 +436,7 @@ static UINT dvcman_close_channel_iface(IWTSVirtualChannel* pChannel) UINT dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, const char* ChannelName) { int i; - int bAccept; + BOOL bAccept; DVCMAN_LISTENER* listener; DVCMAN_CHANNEL* channel; DrdynvcClientContext* context; @@ -462,11 +462,11 @@ UINT dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 Channe channel->iface.Write = dvcman_write_channel; channel->iface.Close = dvcman_close_channel_iface; - bAccept = 1; + bAccept = TRUE; pCallback = NULL; if ((error = listener->listener_callback->OnNewChannelConnection(listener->listener_callback, - (IWTSVirtualChannel*) channel, NULL, &bAccept, &pCallback)) == CHANNEL_RC_OK && bAccept == 1) + (IWTSVirtualChannel*) channel, NULL, &bAccept, &pCallback)) == CHANNEL_RC_OK && bAccept) { WLog_DBG(TAG, "listener %s created new channel %d", listener->channel_name, channel->channel_id); @@ -728,7 +728,7 @@ UINT drdynvc_send(drdynvcPlugin* drdynvc, wStream* s) UINT drdynvc_write_data(drdynvcPlugin* drdynvc, UINT32 ChannelId, BYTE* data, UINT32 dataSize) { wStream* data_out; - unsigned long pos = 0; + unsigned long pos; UINT32 cbChId; UINT32 cbLen; unsigned long chunkLength; @@ -747,9 +747,9 @@ UINT drdynvc_write_data(drdynvcPlugin* drdynvc, UINT32 ChannelId, BYTE* data, UI Stream_SetPosition(data_out, 1); cbChId = drdynvc_write_variable_uint(data_out, ChannelId); + pos = Stream_GetPosition(data_out); if (dataSize == 0) { - pos = Stream_GetPosition(data_out); Stream_SetPosition(data_out, 0); Stream_Write_UINT8(data_out, 0x40 | cbChId); Stream_SetPosition(data_out, pos); @@ -758,7 +758,6 @@ UINT drdynvc_write_data(drdynvcPlugin* drdynvc, UINT32 ChannelId, BYTE* data, UI } else if (dataSize <= CHANNEL_CHUNK_LENGTH - pos) { - pos = Stream_GetPosition(data_out); Stream_SetPosition(data_out, 0); Stream_Write_UINT8(data_out, 0x30 | cbChId); Stream_SetPosition(data_out, pos); diff --git a/channels/drdynvc/server/CMakeLists.txt b/channels/drdynvc/server/CMakeLists.txt index 4729a8287..fe2bd61c2 100644 --- a/channels/drdynvc/server/CMakeLists.txt +++ b/channels/drdynvc/server/CMakeLists.txt @@ -27,6 +27,5 @@ add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE target_link_libraries(${MODULE_NAME} freerdp) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server") diff --git a/channels/drive/client/CMakeLists.txt b/channels/drive/client/CMakeLists.txt index a9e0c2631..3d5afae04 100644 --- a/channels/drive/client/CMakeLists.txt +++ b/channels/drive/client/CMakeLists.txt @@ -35,6 +35,9 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE target_link_libraries(${MODULE_NAME} winpr freerdp) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) + +if (WITH_DEBUG_SYMBOLS AND MSVC AND NOT STATIC_CHANNELS AND BUILD_SHARED_LIBS) + install(FILES ${CMAKE_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${FREERDP_ADDIN_PATH} COMPONENT symbols) +endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/echo/client/CMakeLists.txt b/channels/echo/client/CMakeLists.txt index 9db6718bf..7c15794dc 100644 --- a/channels/echo/client/CMakeLists.txt +++ b/channels/echo/client/CMakeLists.txt @@ -29,6 +29,9 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE target_link_libraries(${MODULE_NAME} freerdp) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) + +if (WITH_DEBUG_SYMBOLS AND MSVC AND NOT STATIC_CHANNELS AND BUILD_SHARED_LIBS) + install(FILES ${CMAKE_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${FREERDP_ADDIN_PATH} COMPONENT symbols) +endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/echo/client/echo_main.c b/channels/echo/client/echo_main.c index 871b75b89..fe2d3631c 100644 --- a/channels/echo/client/echo_main.c +++ b/channels/echo/client/echo_main.c @@ -96,7 +96,7 @@ static UINT echo_on_close(IWTSVirtualChannelCallback* pChannelCallback) * @return 0 on success, otherwise a Win32 error code */ static UINT echo_on_new_channel_connection(IWTSListenerCallback* pListenerCallback, - IWTSVirtualChannel* pChannel, BYTE* Data, int* pbAccept, + IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept, IWTSVirtualChannelCallback** ppCallback) { ECHO_CHANNEL_CALLBACK* callback; diff --git a/channels/echo/server/CMakeLists.txt b/channels/echo/server/CMakeLists.txt index 4fcf3a3b8..e69b55501 100644 --- a/channels/echo/server/CMakeLists.txt +++ b/channels/echo/server/CMakeLists.txt @@ -26,6 +26,5 @@ add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE target_link_libraries(${MODULE_NAME} freerdp) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) - + set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server") diff --git a/channels/encomsp/client/CMakeLists.txt b/channels/encomsp/client/CMakeLists.txt index f4d0e4c70..dd855b830 100644 --- a/channels/encomsp/client/CMakeLists.txt +++ b/channels/encomsp/client/CMakeLists.txt @@ -26,9 +26,4 @@ set(${MODULE_PREFIX}_SRCS add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry") - -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr) - -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) - set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/encomsp/server/CMakeLists.txt b/channels/encomsp/server/CMakeLists.txt index 24246268d..10ac0c6d9 100644 --- a/channels/encomsp/server/CMakeLists.txt +++ b/channels/encomsp/server/CMakeLists.txt @@ -31,6 +31,5 @@ set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server") diff --git a/channels/parallel/client/CMakeLists.txt b/channels/parallel/client/CMakeLists.txt index 6966ed5ea..21f4a03d6 100644 --- a/channels/parallel/client/CMakeLists.txt +++ b/channels/parallel/client/CMakeLists.txt @@ -26,6 +26,9 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE target_link_libraries(${MODULE_NAME} freerdp winpr) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) + +if (WITH_DEBUG_SYMBOLS AND MSVC AND NOT STATIC_CHANNELS AND BUILD_SHARED_LIBS) + install(FILES ${CMAKE_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${FREERDP_ADDIN_PATH} COMPONENT symbols) +endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/printer/client/CMakeLists.txt b/channels/printer/client/CMakeLists.txt index 0d43436c2..b433d8a4f 100644 --- a/channels/printer/client/CMakeLists.txt +++ b/channels/printer/client/CMakeLists.txt @@ -48,6 +48,9 @@ endif() target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) + +if (WITH_DEBUG_SYMBOLS AND MSVC AND NOT STATIC_CHANNELS AND BUILD_SHARED_LIBS) + install(FILES ${CMAKE_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${FREERDP_ADDIN_PATH} COMPONENT symbols) +endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/rail/client/CMakeLists.txt b/channels/rail/client/CMakeLists.txt index 111e59263..a4653e08d 100644 --- a/channels/rail/client/CMakeLists.txt +++ b/channels/rail/client/CMakeLists.txt @@ -31,6 +31,5 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE target_link_libraries(${MODULE_NAME} freerdp) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/rdpdr/client/CMakeLists.txt b/channels/rdpdr/client/CMakeLists.txt index 884bf98be..488c174c2 100644 --- a/channels/rdpdr/client/CMakeLists.txt +++ b/channels/rdpdr/client/CMakeLists.txt @@ -33,6 +33,5 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE target_link_libraries(${MODULE_NAME} winpr freerdp) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/rdpdr/client/devman.c b/channels/rdpdr/client/devman.c index 2e1666204..60a5cb474 100644 --- a/channels/rdpdr/client/devman.c +++ b/channels/rdpdr/client/devman.c @@ -6,6 +6,7 @@ * Copyright 2010-2012 Marc-Andre Moreau * Copyright 2015 Thincast Technologies GmbH * Copyright 2015 DI (FH) Martin Haimberger + * Copyright 2016 Armin Novak * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -42,6 +43,9 @@ void devman_device_free(DEVICE* device) { + if (!device) + return; + IFCALL(device->Free, device); } @@ -49,6 +53,9 @@ DEVMAN* devman_new(rdpdrPlugin* rdpdr) { DEVMAN* devman; + if (!rdpdr) + return NULL; + devman = (DEVMAN*) calloc(1, sizeof(DEVMAN)); if (!devman) @@ -84,6 +91,9 @@ void devman_unregister_device(DEVMAN* devman, void* key) { DEVICE* device; + if (!devman || !key) + return; + device = (DEVICE*) ListDictionary_Remove(devman->devices, key); if (device) @@ -99,6 +109,9 @@ static UINT devman_register_device(DEVMAN* devman, DEVICE* device) { void* key = NULL; + if (!devman || !device) + return ERROR_INVALID_PARAMETER; + device->id = devman->id_sequence++; key = (void*) (size_t) device->id; @@ -115,6 +128,9 @@ DEVICE* devman_get_device_by_id(DEVMAN* devman, UINT32 id) DEVICE* device = NULL; void* key = (void*) (size_t) id; + if (!devman) + return NULL; + device = (DEVICE*) ListDictionary_GetItemValue(devman->devices, key); return device; @@ -137,6 +153,9 @@ UINT devman_load_device_service(DEVMAN* devman, RDPDR_DEVICE* device, rdpContext DEVICE_SERVICE_ENTRY_POINTS ep; PDEVICE_SERVICE_ENTRY entry = NULL; + if (!devman || !device || !rdpcontext) + return ERROR_INVALID_PARAMETER; + if (device->Type == RDPDR_DTYP_FILESYSTEM) ServiceName = DRIVE_SERVICE_NAME; else if (device->Type == RDPDR_DTYP_PRINT) diff --git a/channels/rdpdr/client/irp.c b/channels/rdpdr/client/irp.c index 2d1f96506..d8eaece36 100644 --- a/channels/rdpdr/client/irp.c +++ b/channels/rdpdr/client/irp.c @@ -77,18 +77,28 @@ static UINT irp_complete(IRP* irp) return error; } -IRP* irp_new(DEVMAN* devman, wStream* s) +IRP* irp_new(DEVMAN* devman, wStream* s, UINT* error) { IRP* irp; DEVICE* device; UINT32 DeviceId; + if (Stream_GetRemainingLength(s) < 20) + { + if (error) + *error = ERROR_INVALID_DATA; + return NULL; + } + Stream_Read_UINT32(s, DeviceId); /* DeviceId (4 bytes) */ device = devman_get_device_by_id(devman, DeviceId); if (!device) { - WLog_ERR(TAG, "devman_get_device_by_id failed!"); + WLog_WARN(TAG, "devman_get_device_by_id failed!"); + if (error) + *error = CHANNEL_RC_OK; + return NULL; }; @@ -97,6 +107,8 @@ IRP* irp_new(DEVMAN* devman, wStream* s) if (!irp) { WLog_ERR(TAG, "_aligned_malloc failed!"); + if (error) + *error = CHANNEL_RC_NO_MEMORY; return NULL; } @@ -117,6 +129,8 @@ IRP* irp_new(DEVMAN* devman, wStream* s) { WLog_ERR(TAG, "Stream_New failed!"); _aligned_free(irp); + if (error) + *error = CHANNEL_RC_NO_MEMORY; return NULL; } Stream_Write_UINT16(irp->output, RDPDR_CTYP_CORE); /* Component (2 bytes) */ @@ -131,5 +145,8 @@ IRP* irp_new(DEVMAN* devman, wStream* s) irp->thread = NULL; irp->cancelled = FALSE; + if (error) + *error = CHANNEL_RC_OK; + return irp; } diff --git a/channels/rdpdr/client/irp.h b/channels/rdpdr/client/irp.h index d94366373..17d75acde 100644 --- a/channels/rdpdr/client/irp.h +++ b/channels/rdpdr/client/irp.h @@ -23,6 +23,6 @@ #include "rdpdr_main.h" -IRP* irp_new(DEVMAN* devman, wStream* s); +IRP* irp_new(DEVMAN* devman, wStream* s, UINT* error); #endif /* FREERDP_CHANNEL_RDPDR_CLIENT_IRP_H */ diff --git a/channels/rdpdr/client/rdpdr_capabilities.c b/channels/rdpdr/client/rdpdr_capabilities.c index 26f6d529e..4ff3ef594 100644 --- a/channels/rdpdr/client/rdpdr_capabilities.c +++ b/channels/rdpdr/client/rdpdr_capabilities.c @@ -4,8 +4,9 @@ * * Copyright 2010-2011 Vic Lee * Copyright 2010-2012 Marc-Andre Moreau - * Copyright 2015 Thincast Technologies GmbH + * Copyright 2015-2016 Thincast Technologies GmbH * Copyright 2015 DI (FH) Martin Haimberger + * Copyright 2016 Armin Novak * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -60,12 +61,21 @@ static void rdpdr_write_general_capset(rdpdrPlugin* rdpdr, wStream* s) } /* Process device direction general capability set */ -static void rdpdr_process_general_capset(rdpdrPlugin* rdpdr, wStream* s) +static UINT rdpdr_process_general_capset(rdpdrPlugin* rdpdr, wStream* s) { UINT16 capabilityLength; + if (Stream_GetRemainingLength(s) < 2) + return ERROR_INVALID_DATA; + Stream_Read_UINT16(s, capabilityLength); + + if (Stream_GetRemainingLength(s) < capabilityLength - 4) + return ERROR_INVALID_DATA; + Stream_Seek(s, capabilityLength - 4); + + return CHANNEL_RC_OK; } /* Output printer direction capability set */ @@ -75,12 +85,21 @@ static void rdpdr_write_printer_capset(rdpdrPlugin* rdpdr, wStream* s) } /* Process printer direction capability set */ -static void rdpdr_process_printer_capset(rdpdrPlugin* rdpdr, wStream* s) +static UINT rdpdr_process_printer_capset(rdpdrPlugin* rdpdr, wStream* s) { UINT16 capabilityLength; + if (Stream_GetRemainingLength(s) < 2) + return ERROR_INVALID_DATA; + Stream_Read_UINT16(s, capabilityLength); + + if (Stream_GetRemainingLength(s) < capabilityLength - 4) + return ERROR_INVALID_DATA; + Stream_Seek(s, capabilityLength - 4); + + return CHANNEL_RC_OK; } /* Output port redirection capability set */ @@ -90,12 +109,21 @@ static void rdpdr_write_port_capset(rdpdrPlugin* rdpdr, wStream* s) } /* Process port redirection capability set */ -static void rdpdr_process_port_capset(rdpdrPlugin* rdpdr, wStream* s) +static UINT rdpdr_process_port_capset(rdpdrPlugin* rdpdr, wStream* s) { UINT16 capabilityLength; + if (Stream_GetRemainingLength(s) < 2) + return ERROR_INVALID_DATA; + Stream_Read_UINT16(s, capabilityLength); + + if (Stream_GetRemainingLength(s) < capabilityLength - 4) + return ERROR_INVALID_DATA; + Stream_Seek(s, capabilityLength - 4); + + return CHANNEL_RC_OK; } /* Output drive redirection capability set */ @@ -105,12 +133,21 @@ static void rdpdr_write_drive_capset(rdpdrPlugin* rdpdr, wStream* s) } /* Process drive redirection capability set */ -static void rdpdr_process_drive_capset(rdpdrPlugin* rdpdr, wStream* s) +static UINT rdpdr_process_drive_capset(rdpdrPlugin* rdpdr, wStream* s) { UINT16 capabilityLength; + if (Stream_GetRemainingLength(s) < 2) + return ERROR_INVALID_DATA; + Stream_Read_UINT16(s, capabilityLength); + + if (Stream_GetRemainingLength(s) < capabilityLength - 4) + return ERROR_INVALID_DATA; + Stream_Seek(s, capabilityLength - 4); + + return CHANNEL_RC_OK; } /* Output smart card redirection capability set */ @@ -120,53 +157,77 @@ static void rdpdr_write_smartcard_capset(rdpdrPlugin* rdpdr, wStream* s) } /* Process smartcard redirection capability set */ -static void rdpdr_process_smartcard_capset(rdpdrPlugin* rdpdr, wStream* s) +static UINT rdpdr_process_smartcard_capset(rdpdrPlugin* rdpdr, wStream* s) { UINT16 capabilityLength; + if (Stream_GetRemainingLength(s) < 2) + return ERROR_INVALID_DATA; + Stream_Read_UINT16(s, capabilityLength); + + if (Stream_GetRemainingLength(s) < capabilityLength - 4) + return ERROR_INVALID_DATA; + Stream_Seek(s, capabilityLength - 4); + + return CHANNEL_RC_OK; } -void rdpdr_process_capability_request(rdpdrPlugin* rdpdr, wStream* s) +UINT rdpdr_process_capability_request(rdpdrPlugin* rdpdr, wStream* s) { + UINT status = CHANNEL_RC_OK; UINT16 i; UINT16 numCapabilities; UINT16 capabilityType; + if (!rdpdr || !s) + return CHANNEL_RC_NULL_DATA; + + if (Stream_GetRemainingLength(s) < 4) + return ERROR_INVALID_DATA; + Stream_Read_UINT16(s, numCapabilities); Stream_Seek(s, 2); /* pad (2 bytes) */ for (i = 0; i < numCapabilities; i++) { + if (Stream_GetRemainingLength(s) < sizeof(UINT16)) + return ERROR_INVALID_DATA; + Stream_Read_UINT16(s, capabilityType); switch (capabilityType) { - case CAP_GENERAL_TYPE: - rdpdr_process_general_capset(rdpdr, s); - break; + case CAP_GENERAL_TYPE: + status = rdpdr_process_general_capset(rdpdr, s); + break; - case CAP_PRINTER_TYPE: - rdpdr_process_printer_capset(rdpdr, s); - break; + case CAP_PRINTER_TYPE: + status = rdpdr_process_printer_capset(rdpdr, s); + break; - case CAP_PORT_TYPE: - rdpdr_process_port_capset(rdpdr, s); - break; + case CAP_PORT_TYPE: + status = rdpdr_process_port_capset(rdpdr, s); + break; - case CAP_DRIVE_TYPE: - rdpdr_process_drive_capset(rdpdr, s); - break; + case CAP_DRIVE_TYPE: + status = rdpdr_process_drive_capset(rdpdr, s); + break; - case CAP_SMARTCARD_TYPE: - rdpdr_process_smartcard_capset(rdpdr, s); - break; + case CAP_SMARTCARD_TYPE: + status = rdpdr_process_smartcard_capset(rdpdr, s); + break; - default: - break; + default: + break; } + + if (status != CHANNEL_RC_OK) + return status; } + + return CHANNEL_RC_OK; } /** diff --git a/channels/rdpdr/client/rdpdr_capabilities.h b/channels/rdpdr/client/rdpdr_capabilities.h index bc2ef8b9e..d4e1ecb27 100644 --- a/channels/rdpdr/client/rdpdr_capabilities.h +++ b/channels/rdpdr/client/rdpdr_capabilities.h @@ -25,7 +25,7 @@ #include "rdpdr_main.h" -void rdpdr_process_capability_request(rdpdrPlugin* rdpdr, wStream* s); +UINT rdpdr_process_capability_request(rdpdrPlugin* rdpdr, wStream* s); UINT rdpdr_send_capability_response(rdpdrPlugin* rdpdr); #endif /* FREERDP_CHANNEL_RDPDR_CLIENT_CAPABILITIES_H */ diff --git a/channels/rdpdr/client/rdpdr_main.c b/channels/rdpdr/client/rdpdr_main.c index 24f228e12..87ee6fbdb 100644 --- a/channels/rdpdr/client/rdpdr_main.c +++ b/channels/rdpdr/client/rdpdr_main.c @@ -4,8 +4,9 @@ * * Copyright 2010-2011 Vic Lee * Copyright 2010-2012 Marc-Andre Moreau - * Copyright 2015 Thincast Technologies GmbH + * Copyright 2015-2016 Thincast Technologies GmbH * Copyright 2015 DI (FH) Martin Haimberger + * Copyright 2016 Armin Novak * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -81,7 +82,7 @@ static UINT rdpdr_send_device_list_remove_request(rdpdrPlugin* rdpdr, UINT32 cou UINT32 i; wStream* s; - s = Stream_New(NULL, 256); + s = Stream_New(NULL, count * sizeof(UINT32) + 8); if (!s) { WLog_ERR(TAG, "Stream_New failed!"); @@ -413,6 +414,8 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr) dev_array[size].path = word; dev_array[size++].to_add = TRUE; } + else + free (word); } free(line); } @@ -427,7 +430,7 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr) BOOL dev_found = FALSE; device_ext = (DEVICE_DRIVE_EXT *)ListDictionary_GetItemValue(rdpdr->devman->devices, (void *)keys[j]); - if (!device_ext) + if (!device_ext || !device_ext->path) continue; /* not plugable device */ @@ -494,7 +497,6 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr) free(drive->Path); free(drive->Name); free(drive); - error = CHANNEL_RC_NO_MEMORY; goto cleanup; } } @@ -502,7 +504,7 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr) cleanup: for (i = 0; i < size; i++) - free (dev_array[size].path); + free (dev_array[i].path); return error ? error : rdpdr_send_device_list_announce_request(rdpdr, TRUE); } @@ -515,15 +517,15 @@ static void* drive_hotplug_thread_func(void* arg) struct timeval tv; int rv; UINT error; - DWORD status; + DWORD status; rdpdr = (rdpdrPlugin*) arg; if (!(rdpdr->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) { WLog_ERR(TAG, "CreateEvent failed!"); - error = ERROR_INTERNAL_ERROR; - goto out; + error = ERROR_INTERNAL_ERROR; + goto out; } mfd = open("/proc/mounts", O_RDONLY, 0); @@ -531,8 +533,8 @@ static void* drive_hotplug_thread_func(void* arg) if (mfd < 0) { WLog_ERR(TAG, "ERROR: Unable to open /proc/mounts."); - error = ERROR_INTERNAL_ERROR; - goto out; + error = ERROR_INTERNAL_ERROR; + goto out; } FD_ZERO(&rfds); @@ -543,18 +545,18 @@ static void* drive_hotplug_thread_func(void* arg) if ((error = handle_hotplug(rdpdr))) { WLog_ERR(TAG, "handle_hotplug failed with error %lu!", error); - goto out; + goto out; } while ((rv = select(mfd+1, NULL, NULL, &rfds, &tv)) >= 0) { - status = WaitForSingleObject(rdpdr->stopEvent, 0); - if (status == WAIT_FAILED) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", error); - goto out; - } + status = WaitForSingleObject(rdpdr->stopEvent, 0); + if (status == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", error); + goto out; + } if (status == WAIT_OBJECT_0) break; @@ -564,7 +566,7 @@ static void* drive_hotplug_thread_func(void* arg) if ((error = handle_hotplug(rdpdr))) { WLog_ERR(TAG, "handle_hotplug failed with error %lu!", error); - goto out; + goto out; } } @@ -575,11 +577,11 @@ static void* drive_hotplug_thread_func(void* arg) } out: - if (error && rdpdr->rdpcontext) - setChannelError(rdpdr->rdpcontext, error, "drive_hotplug_thread_func reported an error"); + if (error && rdpdr->rdpcontext) + setChannelError(rdpdr->rdpcontext, error, "drive_hotplug_thread_func reported an error"); - ExitThread((DWORD)error); - return NULL; + ExitThread((DWORD)error); + return NULL; } /** @@ -589,21 +591,22 @@ out: */ static UINT drive_hotplug_thread_terminate(rdpdrPlugin* rdpdr) { - UINT error; + UINT error; + if (rdpdr->hotplugThread) { if (rdpdr->stopEvent) SetEvent(rdpdr->stopEvent); if (WaitForSingleObject(rdpdr->hotplugThread, INFINITE) == WAIT_FAILED) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", error); - return error; - } + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", error); + return error; + } rdpdr->hotplugThread = NULL; } - return CHANNEL_RC_OK; + return CHANNEL_RC_OK; } #endif @@ -659,13 +662,18 @@ static UINT rdpdr_process_connect(rdpdrPlugin* rdpdr) return error; } -static void rdpdr_process_server_announce_request(rdpdrPlugin* rdpdr, wStream* s) +static UINT rdpdr_process_server_announce_request(rdpdrPlugin* rdpdr, wStream* s) { + if (Stream_GetRemainingLength(s) < 8) + return ERROR_INVALID_DATA; + Stream_Read_UINT16(s, rdpdr->versionMajor); Stream_Read_UINT16(s, rdpdr->versionMinor); Stream_Read_UINT32(s, rdpdr->clientID); rdpdr->sequenceId++; + + return CHANNEL_RC_OK; } /** @@ -681,7 +689,7 @@ static UINT rdpdr_send_client_announce_reply(rdpdrPlugin* rdpdr) if (!s) { WLog_ERR(TAG, "Stream_New failed!"); - return CHANNEL_RC_OK; + return CHANNEL_RC_NO_MEMORY; } Stream_Write_UINT16(s, RDPDR_CTYP_CORE); /* Component (2 bytes) */ @@ -731,12 +739,15 @@ static UINT rdpdr_send_client_name_request(rdpdrPlugin* rdpdr) return rdpdr_send(rdpdr, s); } -static void rdpdr_process_server_clientid_confirm(rdpdrPlugin* rdpdr, wStream* s) +static UINT rdpdr_process_server_clientid_confirm(rdpdrPlugin* rdpdr, wStream* s) { UINT16 versionMajor; UINT16 versionMinor; UINT32 clientID; + if (Stream_GetRemainingLength(s) < 8) + return ERROR_INVALID_DATA; + Stream_Read_UINT16(s, versionMajor); Stream_Read_UINT16(s, versionMinor); Stream_Read_UINT32(s, clientID); @@ -748,9 +759,9 @@ static void rdpdr_process_server_clientid_confirm(rdpdrPlugin* rdpdr, wStream* s } if (clientID != rdpdr->clientID) - { rdpdr->clientID = clientID; - } + + return CHANNEL_RC_OK; } /** @@ -802,13 +813,13 @@ static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, BOOL use */ if ((rdpdr->versionMinor == 0x0005) || - (device->type == RDPDR_DTYP_SMARTCARD) || userLoggedOn) + (device->type == RDPDR_DTYP_SMARTCARD) || userLoggedOn) { data_len = (int) (device->data == NULL ? 0 : Stream_GetPosition(device->data)); if (!Stream_EnsureRemainingCapacity(s, 20 + data_len)) { WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); - return CHANNEL_RC_NO_MEMORY; + return ERROR_INVALID_DATA; } Stream_Write_UINT32(s, device->type); /* deviceType */ @@ -857,20 +868,20 @@ static UINT rdpdr_process_irp(rdpdrPlugin* rdpdr, wStream* s) IRP* irp; UINT error = CHANNEL_RC_OK; - irp = irp_new(rdpdr->devman, s); + irp = irp_new(rdpdr->devman, s, &error); if (!irp) { - WLog_ERR(TAG, "irp_new failed!"); - return CHANNEL_RC_NO_MEMORY; + WLog_ERR(TAG, "irp_new failed with %lu!", error); + return error; } IFCALLRET(irp->device->IRPRequest, error, irp->device, irp); - if (error) - WLog_ERR(TAG, "device->IRPRequest failed with error %lu", error); + if (error) + WLog_ERR(TAG, "device->IRPRequest failed with error %lu", error); - return error; + return error; } /** @@ -919,6 +930,12 @@ static UINT rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s) UINT32 status; UINT error; + if (!rdpdr || !s) + return CHANNEL_RC_NULL_DATA; + + if (Stream_GetRemainingLength(s) < 4) + return ERROR_INVALID_DATA; + Stream_Read_UINT16(s, component); /* Component (2 bytes) */ Stream_Read_UINT16(s, packetId); /* PacketId (2 bytes) */ @@ -926,70 +943,77 @@ static UINT rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s) { switch (packetId) { - case PAKID_CORE_SERVER_ANNOUNCE: - rdpdr_process_server_announce_request(rdpdr, s); - if ((error = rdpdr_send_client_announce_reply(rdpdr))) - { - WLog_ERR(TAG, "rdpdr_send_client_announce_reply failed with error %lu", error); - return error; - } - if ((error = rdpdr_send_client_name_request(rdpdr))) - { - WLog_ERR(TAG, "rdpdr_send_client_name_request failed with error %lu", error); - return error; - } - if ((error = rdpdr_process_init(rdpdr))) - { - WLog_ERR(TAG, "rdpdr_process_init failed with error %lu", error); - return error; - } - break; + case PAKID_CORE_SERVER_ANNOUNCE: + if ((error = rdpdr_process_server_announce_request(rdpdr, s))) + return error; + if ((error = rdpdr_send_client_announce_reply(rdpdr))) + { + WLog_ERR(TAG, "rdpdr_send_client_announce_reply failed with error %lu", error); + return error; + } + if ((error = rdpdr_send_client_name_request(rdpdr))) + { + WLog_ERR(TAG, "rdpdr_send_client_name_request failed with error %lu", error); + return error; + } + if ((error = rdpdr_process_init(rdpdr))) + { + WLog_ERR(TAG, "rdpdr_process_init failed with error %lu", error); + return error; + } + break; - case PAKID_CORE_SERVER_CAPABILITY: - rdpdr_process_capability_request(rdpdr, s); - if ((error = rdpdr_send_capability_response(rdpdr))) - { - WLog_ERR(TAG, "rdpdr_send_capability_response failed with error %lu", error); - return error; - } - break; + case PAKID_CORE_SERVER_CAPABILITY: + if ((error = rdpdr_process_capability_request(rdpdr, s))) + return error; + if ((error = rdpdr_send_capability_response(rdpdr))) + { + WLog_ERR(TAG, "rdpdr_send_capability_response failed with error %lu", error); + return error; + } + break; - case PAKID_CORE_CLIENTID_CONFIRM: - rdpdr_process_server_clientid_confirm(rdpdr, s); - if ((error = rdpdr_send_device_list_announce_request(rdpdr, FALSE))) - { - WLog_ERR(TAG, "rdpdr_send_device_list_announce_request failed with error %lu", error); - return error; - } - break; + case PAKID_CORE_CLIENTID_CONFIRM: + if ((error = rdpdr_process_server_clientid_confirm(rdpdr, s))) + return error; - case PAKID_CORE_USER_LOGGEDON: - if ((error = rdpdr_send_device_list_announce_request(rdpdr, TRUE))) - { - WLog_ERR(TAG, "rdpdr_send_device_list_announce_request failed with error %lu", error); - return error; - } - break; + if ((error = rdpdr_send_device_list_announce_request(rdpdr, FALSE))) + { + WLog_ERR(TAG, "rdpdr_send_device_list_announce_request failed with error %lu", error); + return error; + } + break; - case PAKID_CORE_DEVICE_REPLY: - /* connect to a specific resource */ - Stream_Read_UINT32(s, deviceId); - Stream_Read_UINT32(s, status); - break; + case PAKID_CORE_USER_LOGGEDON: + if ((error = rdpdr_send_device_list_announce_request(rdpdr, TRUE))) + { + WLog_ERR(TAG, "rdpdr_send_device_list_announce_request failed with error %lu", error); + return error; + } + break; - case PAKID_CORE_DEVICE_IOREQUEST: - if ((error = rdpdr_process_irp(rdpdr, s))) - { - WLog_ERR(TAG, "rdpdr_process_irp failed with error %lu", error); - return error; - } - s = NULL; - break; - - default: - WLog_ERR(TAG, "RDPDR_CTYP_CORE unknown PacketId: 0x%04X", packetId); + case PAKID_CORE_DEVICE_REPLY: + /* connect to a specific resource */ + if (Stream_GetRemainingLength(s) < 8) return ERROR_INVALID_DATA; - break; + + Stream_Read_UINT32(s, deviceId); + Stream_Read_UINT32(s, status); + break; + + case PAKID_CORE_DEVICE_IOREQUEST: + if ((error = rdpdr_process_irp(rdpdr, s))) + { + WLog_ERR(TAG, "rdpdr_process_irp failed with error %lu", error); + return error; + } + s = NULL; + break; + + default: + WLog_ERR(TAG, "RDPDR_CTYP_CORE unknown PacketId: 0x%04X", packetId); + return ERROR_INVALID_DATA; + break; } } @@ -997,21 +1021,24 @@ static UINT rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s) { switch (packetId) { - case PAKID_PRN_CACHE_DATA: - { - UINT32 eventID; - Stream_Read_UINT32(s, eventID); - WLog_ERR(TAG, "Ignoring unhandled message PAKID_PRN_CACHE_DATA (EventID: 0x%04X)", eventID); - } - break; - - case PAKID_PRN_USING_XPS: - WLog_ERR(TAG, "Ignoring unhandled message PAKID_PRN_USING_XPS"); - break; - - default: - WLog_ERR(TAG, "Unknown printing component packetID: 0x%04X", packetId); + case PAKID_PRN_CACHE_DATA: + { + UINT32 eventID; + if (Stream_GetRemainingLength(s) < 4) return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, eventID); + WLog_ERR(TAG, "Ignoring unhandled message PAKID_PRN_CACHE_DATA (EventID: 0x%04X)", eventID); + } + break; + + case PAKID_PRN_USING_XPS: + WLog_ERR(TAG, "Ignoring unhandled message PAKID_PRN_USING_XPS"); + break; + + default: + WLog_ERR(TAG, "Unknown printing component packetID: 0x%04X", packetId); + return ERROR_INVALID_DATA; } } else @@ -1130,14 +1157,15 @@ UINT rdpdr_send(rdpdrPlugin* rdpdr, wStream* s) UINT status; rdpdrPlugin* plugin = (rdpdrPlugin*) rdpdr; + if (!rdpdr || !s) + return CHANNEL_RC_NULL_DATA; + if (!plugin) - { status = CHANNEL_RC_BAD_INIT_HANDLE; - } else { status = plugin->channelEntryPoints.pVirtualChannelWrite(plugin->OpenHandle, - Stream_Buffer(s), (UINT32) Stream_GetPosition(s), s); + Stream_Buffer(s), (UINT32) Stream_GetPosition(s), s); } if (status != CHANNEL_RC_OK) @@ -1156,7 +1184,7 @@ UINT rdpdr_send(rdpdrPlugin* rdpdr, wStream* s) * @return 0 on success, otherwise a Win32 error code */ static UINT rdpdr_virtual_channel_event_data_received(rdpdrPlugin* rdpdr, - void* pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) + void* pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) { wStream* data_in; @@ -1188,7 +1216,7 @@ static UINT rdpdr_virtual_channel_event_data_received(rdpdrPlugin* rdpdr, if (!Stream_EnsureRemainingCapacity(data_in, (int) dataLength)) { WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); - return CHANNEL_RC_NO_MEMORY; + return ERROR_INVALID_DATA; } Stream_Write(data_in, pData, dataLength); @@ -1214,14 +1242,14 @@ static UINT rdpdr_virtual_channel_event_data_received(rdpdrPlugin* rdpdr, } static VOID VCAPITYPE rdpdr_virtual_channel_open_event(DWORD openHandle, UINT event, - LPVOID pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) + LPVOID pData, UINT32 dataLength, UINT32 totalLength, UINT32 dataFlags) { rdpdrPlugin* rdpdr; UINT error = CHANNEL_RC_OK; rdpdr = (rdpdrPlugin*) rdpdr_get_open_handle_data(openHandle); - if (!rdpdr) + if (!rdpdr || !pData) { WLog_ERR(TAG, "rdpdr_virtual_channel_open_event: error no match"); return; @@ -1229,17 +1257,17 @@ static VOID VCAPITYPE rdpdr_virtual_channel_open_event(DWORD openHandle, UINT ev switch (event) { - case CHANNEL_EVENT_DATA_RECEIVED: - if ((error = rdpdr_virtual_channel_event_data_received(rdpdr, pData, dataLength, totalLength, dataFlags))) - WLog_ERR(TAG, "rdpdr_virtual_channel_event_data_received failed with error %lu!", error ); - break; + case CHANNEL_EVENT_DATA_RECEIVED: + if ((error = rdpdr_virtual_channel_event_data_received(rdpdr, pData, dataLength, totalLength, dataFlags))) + WLog_ERR(TAG, "rdpdr_virtual_channel_event_data_received failed with error %lu!", error ); + break; - case CHANNEL_EVENT_WRITE_COMPLETE: - Stream_Free((wStream*) pData, TRUE); - break; + case CHANNEL_EVENT_WRITE_COMPLETE: + Stream_Free((wStream*) pData, TRUE); + break; - case CHANNEL_EVENT_USER: - break; + case CHANNEL_EVENT_USER: + break; } if (error && rdpdr->rdpcontext) setChannelError(rdpdr->rdpcontext, error, "rdpdr_virtual_channel_open_event reported an error"); @@ -1254,6 +1282,12 @@ static void* rdpdr_virtual_channel_client_thread(void* arg) rdpdrPlugin* rdpdr = (rdpdrPlugin*) arg; UINT error; + if (!rdpdr) + { + ExitThread((DWORD) CHANNEL_RC_NULL_DATA); + return NULL; + } + if ((error = rdpdr_process_connect(rdpdr))) { WLog_ERR(TAG, "rdpdr_process_connect failed with error %lu!", error); @@ -1303,16 +1337,16 @@ static UINT rdpdr_virtual_channel_event_connected(rdpdrPlugin* rdpdr, LPVOID pDa UINT error; status = rdpdr->channelEntryPoints.pVirtualChannelOpen(rdpdr->InitHandle, - &rdpdr->OpenHandle, rdpdr->channelDef.name, rdpdr_virtual_channel_open_event); + &rdpdr->OpenHandle, rdpdr->channelDef.name, rdpdr_virtual_channel_open_event); - if (status != CHANNEL_RC_OK) - { - WLog_ERR(TAG, "pVirtualChannelOpen failed with %s [%08X]", - WTSErrorToString(status), status); - return status; - } + if (status != CHANNEL_RC_OK) + { + WLog_ERR(TAG, "pVirtualChannelOpen failed with %s [%08X]", + WTSErrorToString(status), status); + return status; + } - if ((error = rdpdr_add_open_handle_data(rdpdr->OpenHandle, rdpdr))) + if ((error = rdpdr_add_open_handle_data(rdpdr->OpenHandle, rdpdr))) { WLog_ERR(TAG, "rdpdr_add_open_handle_data failed with error %lu!", error); return error; @@ -1344,11 +1378,11 @@ static UINT rdpdr_virtual_channel_event_disconnected(rdpdrPlugin* rdpdr) UINT error; if (MessageQueue_PostQuit(rdpdr->queue, 0) && (WaitForSingleObject(rdpdr->thread, INFINITE) == WAIT_FAILED)) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", error); - return error; - } + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", error); + return error; + } MessageQueue_Free(rdpdr->queue); CloseHandle(rdpdr->thread); @@ -1357,10 +1391,10 @@ static UINT rdpdr_virtual_channel_event_disconnected(rdpdrPlugin* rdpdr) rdpdr->thread = NULL; if ((error = drive_hotplug_thread_terminate(rdpdr))) - { - WLog_ERR(TAG, "drive_hotplug_thread_terminate failed with error %lu!", error); - return error; - } + { + WLog_ERR(TAG, "drive_hotplug_thread_terminate failed with error %lu!", error); + return error; + } error = rdpdr->channelEntryPoints.pVirtualChannelClose(rdpdr->OpenHandle); if (CHANNEL_RC_OK != error) @@ -1407,25 +1441,25 @@ static VOID VCAPITYPE rdpdr_virtual_channel_init_event(LPVOID pInitHandle, UINT switch (event) { - case CHANNEL_EVENT_INITIALIZED: - break; - case CHANNEL_EVENT_CONNECTED: - if ((error = rdpdr_virtual_channel_event_connected(rdpdr, pData, dataLength))) - WLog_ERR(TAG, "rdpdr_virtual_channel_event_connected failed with error %lu!", error); - break; + case CHANNEL_EVENT_INITIALIZED: + break; + case CHANNEL_EVENT_CONNECTED: + if ((error = rdpdr_virtual_channel_event_connected(rdpdr, pData, dataLength))) + WLog_ERR(TAG, "rdpdr_virtual_channel_event_connected failed with error %lu!", error); + break; - case CHANNEL_EVENT_DISCONNECTED: - if ((error = rdpdr_virtual_channel_event_disconnected(rdpdr))) - WLog_ERR(TAG, "rdpdr_virtual_channel_event_disconnected failed with error %lu!", error); - break; + case CHANNEL_EVENT_DISCONNECTED: + if ((error = rdpdr_virtual_channel_event_disconnected(rdpdr))) + WLog_ERR(TAG, "rdpdr_virtual_channel_event_disconnected failed with error %lu!", error); + break; - case CHANNEL_EVENT_TERMINATED: - rdpdr_virtual_channel_event_terminated(rdpdr); - break; - default: - WLog_ERR(TAG, "unknown event %d!", event); - error = ERROR_INVALID_DATA; - break; + case CHANNEL_EVENT_TERMINATED: + rdpdr_virtual_channel_event_terminated(rdpdr); + break; + default: + WLog_ERR(TAG, "unknown event %d!", event); + error = ERROR_INVALID_DATA; + break; } if (error && rdpdr->rdpcontext) @@ -1442,7 +1476,6 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints) rdpdrPlugin* rdpdr; CHANNEL_ENTRY_POINTS_FREERDP* pEntryPointsEx; - rdpdr = (rdpdrPlugin*) calloc(1, sizeof(rdpdrPlugin)); if (!rdpdr) @@ -1471,7 +1504,6 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints) CopyMemory(&(rdpdr->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP)); - rc = rdpdr->channelEntryPoints.pVirtualChannelInit(&rdpdr->InitHandle, &rdpdr->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, rdpdr_virtual_channel_init_event); diff --git a/channels/rdpdr/server/CMakeLists.txt b/channels/rdpdr/server/CMakeLists.txt index e5a98cb64..63f8a0437 100644 --- a/channels/rdpdr/server/CMakeLists.txt +++ b/channels/rdpdr/server/CMakeLists.txt @@ -27,6 +27,5 @@ add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE target_link_libraries(${MODULE_NAME} freerdp) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server") diff --git a/channels/rdpei/client/CMakeLists.txt b/channels/rdpei/client/CMakeLists.txt index 875efac86..723cbc0fc 100644 --- a/channels/rdpei/client/CMakeLists.txt +++ b/channels/rdpei/client/CMakeLists.txt @@ -30,6 +30,9 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE target_link_libraries(${MODULE_NAME} winpr freerdp) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) + +if (WITH_DEBUG_SYMBOLS AND MSVC AND NOT STATIC_CHANNELS AND BUILD_SHARED_LIBS) + install(FILES ${CMAKE_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${FREERDP_ADDIN_PATH} COMPONENT symbols) +endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/rdpei/client/rdpei_main.c b/channels/rdpei/client/rdpei_main.c index 7494d4b0e..d1cbb7c07 100644 --- a/channels/rdpei/client/rdpei_main.c +++ b/channels/rdpei/client/rdpei_main.c @@ -596,7 +596,7 @@ static UINT rdpei_on_close(IWTSVirtualChannelCallback* pChannelCallback) * @return 0 on success, otherwise a Win32 error code */ static UINT rdpei_on_new_channel_connection(IWTSListenerCallback* pListenerCallback, - IWTSVirtualChannel* pChannel, BYTE* Data, int* pbAccept, + IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept, IWTSVirtualChannelCallback** ppCallback) { RDPEI_CHANNEL_CALLBACK* callback; diff --git a/channels/rdpei/server/CMakeLists.txt b/channels/rdpei/server/CMakeLists.txt index e98c4576f..9f531da0d 100644 --- a/channels/rdpei/server/CMakeLists.txt +++ b/channels/rdpei/server/CMakeLists.txt @@ -33,6 +33,5 @@ set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server") diff --git a/channels/rdpgfx/client/CMakeLists.txt b/channels/rdpgfx/client/CMakeLists.txt index c06274d7a..1dbf82f80 100644 --- a/channels/rdpgfx/client/CMakeLists.txt +++ b/channels/rdpgfx/client/CMakeLists.txt @@ -33,7 +33,9 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE target_link_libraries(${MODULE_NAME} winpr freerdp) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) +if (WITH_DEBUG_SYMBOLS AND MSVC AND NOT STATIC_CHANNELS AND BUILD_SHARED_LIBS) + install(FILES ${CMAKE_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${FREERDP_ADDIN_PATH} COMPONENT symbols) +endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/rdpgfx/client/rdpgfx_main.c b/channels/rdpgfx/client/rdpgfx_main.c index cf18fc4c7..7da8c9fd2 100644 --- a/channels/rdpgfx/client/rdpgfx_main.c +++ b/channels/rdpgfx/client/rdpgfx_main.c @@ -1265,7 +1265,7 @@ static UINT rdpgfx_on_close(IWTSVirtualChannelCallback* pChannelCallback) * @return 0 on success, otherwise a Win32 error code */ static UINT rdpgfx_on_new_channel_connection(IWTSListenerCallback* pListenerCallback, - IWTSVirtualChannel* pChannel, BYTE* Data, int* pbAccept, + IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept, IWTSVirtualChannelCallback** ppCallback) { RDPGFX_CHANNEL_CALLBACK* callback; diff --git a/channels/rdpsnd/client/CMakeLists.txt b/channels/rdpsnd/client/CMakeLists.txt index de63a3261..f2fc1aa16 100644 --- a/channels/rdpsnd/client/CMakeLists.txt +++ b/channels/rdpsnd/client/CMakeLists.txt @@ -27,7 +27,6 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE target_link_libraries(${MODULE_NAME} winpr freerdp) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/rdpsnd/client/alsa/CMakeLists.txt b/channels/rdpsnd/client/alsa/CMakeLists.txt index cdbce489d..761a639d0 100644 --- a/channels/rdpsnd/client/alsa/CMakeLists.txt +++ b/channels/rdpsnd/client/alsa/CMakeLists.txt @@ -33,6 +33,4 @@ set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${ALSA_LIBRARIES}) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) - set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client/ALSA") diff --git a/channels/rdpsnd/client/ios/CMakeLists.txt b/channels/rdpsnd/client/ios/CMakeLists.txt index b9a961714..ae9f9a797 100644 --- a/channels/rdpsnd/client/ios/CMakeLists.txt +++ b/channels/rdpsnd/client/ios/CMakeLists.txt @@ -38,10 +38,8 @@ set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${CORE_AUDIO} ${CORE_FOUNDATION}) -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp} +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) - set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client/ios") diff --git a/channels/rdpsnd/client/ios/TPCircularBuffer.c b/channels/rdpsnd/client/ios/TPCircularBuffer.c index 137ec789f..1c9402799 100644 --- a/channels/rdpsnd/client/ios/TPCircularBuffer.c +++ b/channels/rdpsnd/client/ios/TPCircularBuffer.c @@ -30,6 +30,7 @@ #include #include "TPCircularBuffer.h" +#include "rdpsnd_main.h" #include #include diff --git a/channels/rdpsnd/client/mac/CMakeLists.txt b/channels/rdpsnd/client/mac/CMakeLists.txt index 035d16cb4..449b345a1 100644 --- a/channels/rdpsnd/client/mac/CMakeLists.txt +++ b/channels/rdpsnd/client/mac/CMakeLists.txt @@ -42,6 +42,4 @@ set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) - set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client/Mac") diff --git a/channels/rdpsnd/client/mac/rdpsnd_mac.c b/channels/rdpsnd/client/mac/rdpsnd_mac.c index 00588f52a..5867480bd 100644 --- a/channels/rdpsnd/client/mac/rdpsnd_mac.c +++ b/channels/rdpsnd/client/mac/rdpsnd_mac.c @@ -5,6 +5,8 @@ * Copyright 2012 Laxmikant Rashinkar * Copyright 2015 Thincast Technologies GmbH * Copyright 2015 DI (FH) Martin Haimberger + * Copyright 2016 Inuvika Inc. + * Copyright 2016 David PHAM-VAN * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,6 +56,12 @@ struct rdpsnd_mac_plugin AudioQueueRef audioQueue; AudioStreamBasicDescription audioFormat; AudioQueueBufferRef audioBuffers[MAC_AUDIO_QUEUE_NUM_BUFFERS]; + + Float64 lastStartTime; + + int wformat; + int block_size; + FREERDP_DSP_CONTEXT* dsp_context; }; typedef struct rdpsnd_mac_plugin rdpsndMacPlugin; @@ -69,6 +77,15 @@ static BOOL rdpsnd_mac_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* form mac->latency = (UINT32) latency; CopyMemory(&(mac->format), format, sizeof(AUDIO_FORMAT)); + mac->audioFormat.mSampleRate = format->nSamplesPerSec; + mac->audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; + mac->audioFormat.mFramesPerPacket = 1; + mac->audioFormat.mChannelsPerFrame = format->nChannels; + mac->audioFormat.mBitsPerChannel = format->wBitsPerSample; + mac->audioFormat.mBytesPerFrame = (format->wBitsPerSample * format->nChannels) / 8; + mac->audioFormat.mBytesPerPacket = format->nBlockAlign; + mac->audioFormat.mReserved = 0; + switch (format->wFormatTag) { case WAVE_FORMAT_ALAW: @@ -83,6 +100,14 @@ static BOOL rdpsnd_mac_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* form mac->audioFormat.mFormatID = kAudioFormatLinearPCM; break; + case WAVE_FORMAT_ADPCM: + case WAVE_FORMAT_DVI_ADPCM: + mac->audioFormat.mFormatID = kAudioFormatLinearPCM; + mac->audioFormat.mBitsPerChannel = 16; + mac->audioFormat.mBytesPerFrame = (16 * format->nChannels) / 8; + mac->audioFormat.mBytesPerPacket = mac->audioFormat.mFramesPerPacket * mac->audioFormat.mBytesPerFrame; + break; + case WAVE_FORMAT_GSM610: mac->audioFormat.mFormatID = kAudioFormatMicrosoftGSM; break; @@ -91,14 +116,8 @@ static BOOL rdpsnd_mac_set_format(rdpsndDevicePlugin* device, AUDIO_FORMAT* form break; } - mac->audioFormat.mSampleRate = format->nSamplesPerSec; - mac->audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; - mac->audioFormat.mFramesPerPacket = 1; - mac->audioFormat.mChannelsPerFrame = format->nChannels; - mac->audioFormat.mBitsPerChannel = format->wBitsPerSample; - mac->audioFormat.mBytesPerFrame = (format->wBitsPerSample * format->nChannels) / 8; - mac->audioFormat.mBytesPerPacket = format->nBlockAlign; - mac->audioFormat.mReserved = 0; + mac->wformat = format->wFormatTag; + mac->block_size = format->nBlockAlign; rdpsnd_print_audio_format(format); return TRUE; @@ -122,6 +141,8 @@ static BOOL rdpsnd_mac_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in return FALSE; } + freerdp_dsp_context_reset_adpcm(mac->dsp_context); + status = AudioQueueNewOutput(&(mac->audioFormat), mac_audio_queue_output_cb, mac, NULL, NULL, 0, &(mac->audioQueue)); @@ -156,7 +177,9 @@ static BOOL rdpsnd_mac_open(rdpsndDevicePlugin* device, AUDIO_FORMAT* format, in return FALSE; } } - + + mac->lastStartTime = 0; + mac->isOpen = TRUE; return TRUE; } @@ -184,27 +207,24 @@ static void rdpsnd_mac_free(rdpsndDevicePlugin* device) device->Close(device); + freerdp_dsp_context_free(mac->dsp_context); + free(mac); } static BOOL rdpsnd_mac_format_supported(rdpsndDevicePlugin* device, AUDIO_FORMAT* format) { - if (format->wFormatTag == WAVE_FORMAT_PCM) - { - return TRUE; - } - else if (format->wFormatTag == WAVE_FORMAT_ALAW) - { - return TRUE; - } - else if (format->wFormatTag == WAVE_FORMAT_MULAW) - { - return TRUE; - } - else if (format->wFormatTag == WAVE_FORMAT_GSM610) - { - return FALSE; - } + switch (format->wFormatTag) + { + case WAVE_FORMAT_PCM: + case WAVE_FORMAT_ALAW: + case WAVE_FORMAT_MULAW: + case WAVE_FORMAT_ADPCM: + case WAVE_FORMAT_DVI_ADPCM: + return TRUE; + case WAVE_FORMAT_GSM610: + return FALSE; + } return FALSE; } @@ -258,10 +278,42 @@ static void rdpsnd_mac_start(rdpsndDevicePlugin* device) } } -static void rdpsnd_mac_play(rdpsndDevicePlugin* device, BYTE* data, int size) +static BOOL rdpsnd_mac_wave_decode(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) +{ + int length; + BYTE* data; + rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device; + + if (mac->wformat == WAVE_FORMAT_ADPCM) + { + mac->dsp_context->decode_ms_adpcm(mac->dsp_context, wave->data, wave->length, mac->format.nChannels, mac->block_size); + length = mac->dsp_context->adpcm_size; + data = mac->dsp_context->adpcm_buffer; + } + else if (mac->wformat == WAVE_FORMAT_DVI_ADPCM) + { + mac->dsp_context->decode_ima_adpcm(mac->dsp_context, wave->data, wave->length, mac->format.nChannels, mac->block_size); + length = mac->dsp_context->adpcm_size; + data = mac->dsp_context->adpcm_buffer; + } + else + { + length = wave->length; + data = wave->data; + } + + wave->data = (BYTE*) malloc(length); + CopyMemory(wave->data, data, length); + wave->length = length; + + return TRUE; +} + +static void rdpsnd_mac_waveplay(rdpsndDevicePlugin* device, RDPSND_WAVE* wave) { int length; AudioQueueBufferRef audioBuffer; + AudioTimeStamp outActualStartTime; rdpsndMacPlugin* mac = (rdpsndMacPlugin*) device; if (!mac->isOpen) @@ -269,13 +321,18 @@ static void rdpsnd_mac_play(rdpsndDevicePlugin* device, BYTE* data, int size) audioBuffer = mac->audioBuffers[mac->audioBufferIndex]; - length = size > audioBuffer->mAudioDataBytesCapacity ? audioBuffer->mAudioDataBytesCapacity : size; + length = wave->length > audioBuffer->mAudioDataBytesCapacity ? audioBuffer->mAudioDataBytesCapacity : wave->length; - CopyMemory(audioBuffer->mAudioData, data, length); + CopyMemory(audioBuffer->mAudioData, wave->data, length); audioBuffer->mAudioDataByteSize = length; - - AudioQueueEnqueueBuffer(mac->audioQueue, audioBuffer, 0, 0); - + audioBuffer->mUserData = wave; + + AudioQueueEnqueueBufferWithParameters(mac->audioQueue, audioBuffer, 0, 0, 0, 0, 0, NULL, NULL, &outActualStartTime); + UInt64 startTimeDelta = (outActualStartTime.mSampleTime - mac->lastStartTime) / 100.0; + wave->wLocalTimeB = wave->wLocalTimeA + startTimeDelta + wave->wAudioLength; + wave->wTimeStampB = wave->wTimeStampA + wave->wLocalTimeB - wave->wLocalTimeA; + mac->lastStartTime = outActualStartTime.mSampleTime; + mac->audioBufferIndex++; if (mac->audioBufferIndex >= MAC_AUDIO_QUEUE_NUM_BUFFERS) @@ -308,10 +365,13 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p mac->device.FormatSupported = rdpsnd_mac_format_supported; mac->device.SetFormat = rdpsnd_mac_set_format; mac->device.SetVolume = rdpsnd_mac_set_volume; - mac->device.Play = rdpsnd_mac_play; + mac->device.WaveDecode = rdpsnd_mac_wave_decode; + mac->device.WavePlay = rdpsnd_mac_waveplay; mac->device.Start = rdpsnd_mac_start; mac->device.Close = rdpsnd_mac_close; mac->device.Free = rdpsnd_mac_free; + + mac->dsp_context = freerdp_dsp_context_new(); pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*) mac); diff --git a/channels/rdpsnd/client/opensles/CMakeLists.txt b/channels/rdpsnd/client/opensles/CMakeLists.txt index 7153eed82..410a4b425 100644 --- a/channels/rdpsnd/client/opensles/CMakeLists.txt +++ b/channels/rdpsnd/client/opensles/CMakeLists.txt @@ -31,5 +31,3 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N set(${MODULE_PREFIX}_LIBS freerdp ${OPENSLES_LIBRARIES}) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/rdpsnd/client/opensles/opensl_io.c b/channels/rdpsnd/client/opensles/opensl_io.c index 0a5ba8a06..282268e32 100644 --- a/channels/rdpsnd/client/opensles/opensl_io.c +++ b/channels/rdpsnd/client/opensles/opensl_io.c @@ -306,6 +306,7 @@ int android_AudioOut(OPENSL_STREAM *p, const short *buffer,int size) return -1; } memcpy(data, buffer, size * sizeof(short)); + Queue_Enqueue(p->queue, data); (*p->bqPlayerBufferQueue)->Enqueue(p->bqPlayerBufferQueue, data, sizeof(short) * size); diff --git a/channels/rdpsnd/client/opensles/rdpsnd_opensles.c b/channels/rdpsnd/client/opensles/rdpsnd_opensles.c index d0400149f..c42f1b207 100644 --- a/channels/rdpsnd/client/opensles/rdpsnd_opensles.c +++ b/channels/rdpsnd/client/opensles/rdpsnd_opensles.c @@ -138,32 +138,7 @@ static BOOL rdpsnd_opensles_set_format(rdpsndDevicePlugin* device, opensles->rate = format->nSamplesPerSec; opensles->channels = format->nChannels; - - switch (format->wFormatTag) - { - case WAVE_FORMAT_PCM: - switch (format->wBitsPerSample) - { - case 4: - opensles->format = WAVE_FORMAT_ADPCM; - break; - - case 8: - opensles->format = WAVE_FORMAT_PCM; - break; - - case 16: - opensles->format = WAVE_FORMAT_ADPCM; - break; - } - break; - - case WAVE_FORMAT_ADPCM: - case WAVE_FORMAT_DVI_ADPCM: - opensles->format = format->wFormatTag; - break; - } - + opensles->format = format->wFormatTag; opensles->wformat = format->wFormatTag; opensles->block_size = format->nBlockAlign; } diff --git a/channels/rdpsnd/client/oss/CMakeLists.txt b/channels/rdpsnd/client/oss/CMakeLists.txt index c5f9618fc..53ae5fa7b 100644 --- a/channels/rdpsnd/client/oss/CMakeLists.txt +++ b/channels/rdpsnd/client/oss/CMakeLists.txt @@ -33,6 +33,4 @@ set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${OSS_LIBRARIES}) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) - set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client/OSS") diff --git a/channels/rdpsnd/client/pulse/CMakeLists.txt b/channels/rdpsnd/client/pulse/CMakeLists.txt index 79095223e..a12d71844 100644 --- a/channels/rdpsnd/client/pulse/CMakeLists.txt +++ b/channels/rdpsnd/client/pulse/CMakeLists.txt @@ -36,6 +36,4 @@ endif() target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) - set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client/Pulse") diff --git a/channels/rdpsnd/client/winmm/CMakeLists.txt b/channels/rdpsnd/client/winmm/CMakeLists.txt index 11fa19026..43c7257a3 100644 --- a/channels/rdpsnd/client/winmm/CMakeLists.txt +++ b/channels/rdpsnd/client/winmm/CMakeLists.txt @@ -32,6 +32,8 @@ set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) +if (WITH_DEBUG_SYMBOLS AND MSVC AND NOT STATIC_CHANNELS AND BUILD_SHARED_LIBS) + install(FILES ${CMAKE_PDB_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${FREERDP_ADDIN_PATH} COMPONENT symbols) +endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client/WinMM") diff --git a/channels/rdpsnd/server/CMakeLists.txt b/channels/rdpsnd/server/CMakeLists.txt index afdd9db56..62d57be5e 100644 --- a/channels/rdpsnd/server/CMakeLists.txt +++ b/channels/rdpsnd/server/CMakeLists.txt @@ -27,6 +27,5 @@ add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE target_link_libraries(${MODULE_NAME} freerdp) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server") diff --git a/channels/remdesk/client/CMakeLists.txt b/channels/remdesk/client/CMakeLists.txt index 570c5e62c..1c289b9d8 100644 --- a/channels/remdesk/client/CMakeLists.txt +++ b/channels/remdesk/client/CMakeLists.txt @@ -27,6 +27,5 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/remdesk/server/CMakeLists.txt b/channels/remdesk/server/CMakeLists.txt index dad21c276..dc59a1129 100644 --- a/channels/remdesk/server/CMakeLists.txt +++ b/channels/remdesk/server/CMakeLists.txt @@ -23,12 +23,9 @@ set(${MODULE_PREFIX}_SRCS add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "VirtualChannelEntry") - - set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server") diff --git a/channels/serial/client/CMakeLists.txt b/channels/serial/client/CMakeLists.txt index 3ca69cc89..086e1419e 100644 --- a/channels/serial/client/CMakeLists.txt +++ b/channels/serial/client/CMakeLists.txt @@ -26,6 +26,9 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE target_link_libraries(${MODULE_NAME} winpr freerdp) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) + +if (WITH_DEBUG_SYMBOLS AND MSVC AND NOT STATIC_CHANNELS AND BUILD_SHARED_LIBS) + install(FILES ${CMAKE_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${FREERDP_ADDIN_PATH} COMPONENT symbols) +endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/server/channels.c b/channels/server/channels.c index cb312c849..84ccf6e15 100644 --- a/channels/server/channels.c +++ b/channels/server/channels.c @@ -47,6 +47,8 @@ #include #include #include +#include +#include void freerdp_channels_dummy() { @@ -70,6 +72,13 @@ void freerdp_channels_dummy() rdpei_server_context_new(NULL); rdpei_server_context_free(NULL); + + remdesk_server_context_new(NULL); + remdesk_server_context_free(NULL); + + encomsp_server_context_new(NULL); + encomsp_server_context_free(NULL); + } /** diff --git a/channels/smartcard/client/CMakeLists.txt b/channels/smartcard/client/CMakeLists.txt index 05e4405c9..1af49ef87 100644 --- a/channels/smartcard/client/CMakeLists.txt +++ b/channels/smartcard/client/CMakeLists.txt @@ -30,6 +30,5 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE target_link_libraries(${MODULE_NAME} winpr freerdp) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/tsmf/client/CMakeLists.txt b/channels/tsmf/client/CMakeLists.txt index b47a616a2..24866029c 100644 --- a/channels/tsmf/client/CMakeLists.txt +++ b/channels/tsmf/client/CMakeLists.txt @@ -42,7 +42,9 @@ add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE target_link_libraries(${MODULE_NAME} freerdp) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) +if (WITH_DEBUG_SYMBOLS AND MSVC AND NOT STATIC_CHANNELS AND BUILD_SHARED_LIBS) + install(FILES ${CMAKE_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${FREERDP_ADDIN_PATH} COMPONENT symbols) +endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/tsmf/client/alsa/CMakeLists.txt b/channels/tsmf/client/alsa/CMakeLists.txt index 0466de04c..f1d5292dc 100644 --- a/channels/tsmf/client/alsa/CMakeLists.txt +++ b/channels/tsmf/client/alsa/CMakeLists.txt @@ -28,5 +28,3 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N target_link_libraries(${MODULE_NAME} freerdp ${ALSA_LIBRARIES}) - -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/tsmf/client/ffmpeg/CMakeLists.txt b/channels/tsmf/client/ffmpeg/CMakeLists.txt index 96c3efb4b..e18e0b3e2 100644 --- a/channels/tsmf/client/ffmpeg/CMakeLists.txt +++ b/channels/tsmf/client/ffmpeg/CMakeLists.txt @@ -39,4 +39,7 @@ else() target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) endif() -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) +if (WITH_DEBUG_SYMBOLS AND MSVC AND NOT STATIC_CHANNELS AND BUILD_SHARED_LIBS) + install(FILES ${CMAKE_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${FREERDP_ADDIN_PATH} COMPONENT symbols) +endif() + diff --git a/channels/tsmf/client/gstreamer/CMakeLists.txt b/channels/tsmf/client/gstreamer/CMakeLists.txt index 766c9e958..8557f6e09 100644 --- a/channels/tsmf/client/gstreamer/CMakeLists.txt +++ b/channels/tsmf/client/gstreamer/CMakeLists.txt @@ -48,9 +48,7 @@ else() tsmf_X11.c) set(LIBS ${LIBS} ${X11_LIBRARIES} ${XEXT_LIBRARIES}) - if(NOT XEXT_FOUND) - message(FATAL_ERROR "Xext library not found, but required for TSMF module.") - else() + if(XEXT_FOUND) add_definitions(-DWITH_XEXT=1) endif() @@ -65,5 +63,3 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N target_link_libraries(${MODULE_NAME} ${LIBS} freerdp) - -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/tsmf/client/gstreamer/tsmf_X11.c b/channels/tsmf/client/gstreamer/tsmf_X11.c index 0ea6a166f..4d1be90dd 100644 --- a/channels/tsmf/client/gstreamer/tsmf_X11.c +++ b/channels/tsmf/client/gstreamer/tsmf_X11.c @@ -61,6 +61,16 @@ struct X11Handle #endif Display *disp; Window subwin; + BOOL subwinMapped; +#if GST_VERSION_MAJOR > 0 + GstVideoOverlay *overlay; +#else + GstXOverlay *overlay; +#endif + int subwinWidth; + int subwinHeight; + int subwinX; + int subwinY; }; static const char* get_shm_id() @@ -70,9 +80,71 @@ static const char* get_shm_id() return shm_id; } +static GstBusSyncReply tsmf_platform_bus_sync_handler(GstBus *bus, GstMessage *message, gpointer user_data) +{ + struct X11Handle* hdl; + + TSMFGstreamerDecoder* decoder = user_data; + + if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT) + return GST_BUS_PASS; + +#if GST_VERSION_MAJOR > 0 + if (!gst_is_video_overlay_prepare_window_handle_message (message)) + return GST_BUS_PASS; +#else + if (!gst_structure_has_name (message->structure, "prepare-xwindow-id")) + return GST_BUS_PASS; +#endif + + hdl = (struct X11Handle*) decoder->platform; + + if (hdl->subwin) + { +#if GST_VERSION_MAJOR > 0 + hdl->overlay = GST_VIDEO_OVERLAY (GST_MESSAGE_SRC (message)); + gst_video_overlay_set_window_handle(hdl->overlay, hdl->subwin); + gst_video_overlay_handle_events(hdl->overlay, TRUE); +#else + hdl->overlay = GST_X_OVERLAY (GST_MESSAGE_SRC (message)); + gst_x_overlay_set_window_handle(hdl->overlay, hdl->subwin); + gst_x_overlay_handle_events(hdl->overlay, TRUE); +#endif + + if (hdl->subwinWidth != -1 && hdl->subwinHeight != -1 && hdl->subwinX != -1 && hdl->subwinY != -1) + { +#if GST_VERSION_MAJOR > 0 + if (!gst_video_overlay_set_render_rectangle(hdl->overlay, 0, 0, hdl->subwinWidth, hdl->subwinHeight)) + { + WLog_ERR(TAG, "Could not resize overlay!"); + } + + gst_video_overlay_expose(hdl->overlay); +#else + if (!gst_x_overlay_set_render_rectangle(hdl->overlay, 0, 0, hdl->subwinWidth, hdl->subwinHeight)) + { + WLog_ERR(TAG, "Could not resize overlay!"); + } + + gst_x_overlay_expose(hdl->overlay); +#endif + XLockDisplay(hdl->disp); + XMoveResizeWindow(hdl->disp, hdl->subwin, hdl->subwinX, hdl->subwinY, hdl->subwinWidth, hdl->subwinHeight); + XSync(hdl->disp, FALSE); + XUnlockDisplay(hdl->disp); + } + } else { + g_warning ("Window was not available before retrieving the overlay!"); + } + + gst_message_unref (message); + + return GST_BUS_DROP; +} + const char* tsmf_platform_get_video_sink(void) { - return "xvimagesink"; + return "autovideosink"; } const char* tsmf_platform_get_audio_sink(void) @@ -119,6 +191,12 @@ int tsmf_platform_create(TSMFGstreamerDecoder* decoder) return -4; } + hdl->subwinMapped = FALSE; + hdl->subwinX = -1; + hdl->subwinY = -1; + hdl->subwinWidth = -1; + hdl->subwinHeight = -1; + return 0; } @@ -147,12 +225,20 @@ int tsmf_platform_register_handler(TSMFGstreamerDecoder* decoder) bus = gst_pipeline_get_bus(GST_PIPELINE(decoder->pipe)); +#if GST_VERSION_MAJOR > 0 + gst_bus_set_sync_handler (bus, (GstBusSyncHandler) tsmf_platform_bus_sync_handler, decoder, NULL); +#else + gst_bus_set_sync_handler (bus, (GstBusSyncHandler) tsmf_platform_bus_sync_handler, decoder); +#endif + if (!bus) { WLog_ERR(TAG, "gst_pipeline_get_bus failed!"); return 1; } + gst_object_unref (bus); + return 0; } @@ -189,12 +275,6 @@ int tsmf_window_create(TSMFGstreamerDecoder* decoder) } else { -#if GST_VERSION_MAJOR > 0 - GstVideoOverlay *overlay = GST_VIDEO_OVERLAY(decoder->outsink); -#else - GstXOverlay *overlay = GST_X_OVERLAY(decoder->outsink); -#endif - if (!decoder) return -1; @@ -205,38 +285,32 @@ int tsmf_window_create(TSMFGstreamerDecoder* decoder) if (!hdl->subwin) { - int event, error; + XLockDisplay(hdl->disp); hdl->subwin = XCreateSimpleWindow(hdl->disp, *(int *)hdl->xfwin, 0, 0, 1, 1, 0, 0, 0); + XUnlockDisplay(hdl->disp); if (!hdl->subwin) { WLog_ERR(TAG, "Could not create subwindow!"); } - - XMapWindow(hdl->disp, hdl->subwin); - XSync(hdl->disp, FALSE); -#if GST_VERSION_MAJOR > 0 - gst_video_overlay_set_window_handle(overlay, hdl->subwin); -#else - gst_x_overlay_set_window_handle(overlay, hdl->subwin); -#endif - decoder->ready = TRUE; -#if defined(WITH_XEXT) - hdl->has_shape = XShapeQueryExtension(hdl->disp, &event, &error); -#endif } -#if GST_VERSION_MAJOR > 0 - gst_video_overlay_handle_events(overlay, TRUE); -#else - gst_x_overlay_handle_events(overlay, TRUE); + tsmf_window_map(decoder); + + decoder->ready = TRUE; +#if defined(WITH_XEXT) + int event, error; + XLockDisplay(hdl->disp); + hdl->has_shape = XShapeQueryExtension(hdl->disp, &event, &error); + XUnlockDisplay(hdl->disp); #endif - return 0; } + + return 0; } int tsmf_window_resize(TSMFGstreamerDecoder* decoder, int x, int y, int width, - int height, int nr_rects, RDP_RECT *rects) + int height, int nr_rects, RDP_RECT *rects) { struct X11Handle* hdl; @@ -245,11 +319,6 @@ int tsmf_window_resize(TSMFGstreamerDecoder* decoder, int x, int y, int width, return -3; } -#if GST_VERSION_MAJOR > 0 - GstVideoOverlay *overlay = GST_VIDEO_OVERLAY(decoder->outsink); -#else - GstXOverlay *overlay = GST_X_OVERLAY(decoder->outsink); -#endif if (!decoder) return -1; @@ -259,49 +328,78 @@ int tsmf_window_resize(TSMFGstreamerDecoder* decoder, int x, int y, int width, hdl = (struct X11Handle*) decoder->platform; DEBUG_TSMF("resize: x=%d, y=%d, w=%d, h=%d", x, y, width, height); + if (hdl->overlay) + { #if GST_VERSION_MAJOR > 0 - if (!gst_video_overlay_set_render_rectangle(overlay, 0, 0, width, height)) - { - WLog_ERR(TAG, "Could not resize overlay!"); - } + if (!gst_video_overlay_set_render_rectangle(hdl->overlay, 0, 0, width, height)) + { + WLog_ERR(TAG, "Could not resize overlay!"); + } - gst_video_overlay_expose(overlay); + gst_video_overlay_expose(hdl->overlay); #else - if (!gst_x_overlay_set_render_rectangle(overlay, 0, 0, width, height)) - { - WLog_ERR(TAG, "Could not resize overlay!"); - } + if (!gst_x_overlay_set_render_rectangle(hdl->overlay, 0, 0, width, height)) + { + WLog_ERR(TAG, "Could not resize overlay!"); + } - gst_x_overlay_expose(overlay); + gst_x_overlay_expose(hdl->overlay); #endif + } if (hdl->subwin) { - XMoveResizeWindow(hdl->disp, hdl->subwin, x, y, width, height); -#if defined(WITH_XEXT) + hdl->subwinX = x; + hdl->subwinY = y; + hdl->subwinWidth = width; + hdl->subwinHeight = height; + XLockDisplay(hdl->disp); + XMoveResizeWindow(hdl->disp, hdl->subwin, hdl->subwinX, hdl->subwinY, hdl->subwinWidth, hdl->subwinHeight); + + /* Unmap the window if there are no visibility rects */ + if (nr_rects == 0) + tsmf_window_unmap(decoder); + else + tsmf_window_map(decoder); + +#if defined(WITH_XEXT) if (hdl->has_shape) { int i; - XRectangle *xrects = calloc(nr_rects, sizeof(XRectangle)); - if (!xrects) - return -1; + XRectangle *xrects = NULL; - for (i = 0; i < nr_rects; i++) + if (nr_rects == 0) { - xrects[i].x = rects[i].x - x; - xrects[i].y = rects[i].y - y; - xrects[i].width = rects[i].width; - xrects[i].height = rects[i].height; + xrects = calloc(1, sizeof(XRectangle)); + xrects->x = x; + xrects->y = y; + xrects->width = width; + xrects->height = height; } + else + { + xrects = calloc(nr_rects, sizeof(XRectangle)); + } + + if (xrects) + { + for (i = 0; i < nr_rects; i++) + { + xrects[i].x = rects[i].x - x; + xrects[i].y = rects[i].y - y; + xrects[i].width = rects[i].width; + xrects[i].height = rects[i].height; + } - XShapeCombineRectangles(hdl->disp, hdl->subwin, ShapeBounding, x, y, xrects, nr_rects, ShapeSet, 0); - free(xrects); + XShapeCombineRectangles(hdl->disp, hdl->subwin, ShapeBounding, x, y, xrects, nr_rects, ShapeSet, 0); + free(xrects); + } } - #endif XSync(hdl->disp, FALSE); + XUnlockDisplay(hdl->disp); } return 0; @@ -323,6 +421,49 @@ int tsmf_window_resume(TSMFGstreamerDecoder* decoder) return 0; } +int tsmf_window_map(TSMFGstreamerDecoder* decoder) +{ + struct X11Handle* hdl; + if (!decoder) + return -1; + + hdl = (struct X11Handle*) decoder->platform; + + /* Only need to map the window if it is not currently mapped */ + if ((hdl->subwin) && (!hdl->subwinMapped)) + { + XLockDisplay(hdl->disp); + XMapWindow(hdl->disp, hdl->subwin); + hdl->subwinMapped = TRUE; + XSync(hdl->disp, FALSE); + XUnlockDisplay(hdl->disp); + } + + return 0; +} + +int tsmf_window_unmap(TSMFGstreamerDecoder* decoder) +{ + struct X11Handle* hdl; + if (!decoder) + return -1; + + hdl = (struct X11Handle*) decoder->platform; + + /* only need to unmap window if it is currently mapped */ + if ((hdl->subwin) && (hdl->subwinMapped)) + { + XLockDisplay(hdl->disp); + XUnmapWindow(hdl->disp, hdl->subwin); + hdl->subwinMapped = FALSE; + XSync(hdl->disp, FALSE); + XUnlockDisplay(hdl->disp); + } + + return 0; +} + + int tsmf_window_destroy(TSMFGstreamerDecoder* decoder) { struct X11Handle* hdl; @@ -341,11 +482,19 @@ int tsmf_window_destroy(TSMFGstreamerDecoder* decoder) if (hdl->subwin) { + XLockDisplay(hdl->disp); XDestroyWindow(hdl->disp, hdl->subwin); XSync(hdl->disp, FALSE); + XUnlockDisplay(hdl->disp); } + hdl->overlay = NULL; hdl->subwin = 0; + hdl->subwinMapped = FALSE; + hdl->subwinX = -1; + hdl->subwinY = -1; + hdl->subwinWidth = -1; + hdl->subwinHeight = -1; return 0; } diff --git a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c index fac74c12a..0e35f73fa 100644 --- a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c +++ b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c @@ -45,20 +45,52 @@ #include #endif +/* 1 second = 10,000,000 100ns units*/ +#define SEEK_TOLERANCE 10*1000*1000 + 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); +static BOOL tsmf_gstreamer_buffer_level(ITSMFDecoder* decoder); const char* get_type(TSMFGstreamerDecoder* mdecoder) { if (!mdecoder) return NULL; - if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) - return "VIDEO"; - else - return "AUDIO"; + switch (mdecoder->media_type) + { + case TSMF_MAJOR_TYPE_VIDEO: + return "VIDEO"; + case TSMF_MAJOR_TYPE_AUDIO: + return "AUDIO"; + default: + return "UNKNOWN"; + } +} + +static void cb_child_added(GstChildProxy *child_proxy, GObject *object, TSMFGstreamerDecoder* mdecoder) +{ + DEBUG_TSMF("NAME: %s", G_OBJECT_TYPE_NAME(object)); + + if (!g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstXvImageSink") || !g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstXImageSink") || !g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstFluVAAutoSink")) + { + gst_base_sink_set_max_lateness((GstBaseSink *) object, 10000000); /* nanoseconds */ + g_object_set(G_OBJECT(object), "sync", TRUE, NULL); /* synchronize on the clock */ + g_object_set(G_OBJECT(object), "async", TRUE, NULL); /* no async state changes */ + } + + else if (!g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstAlsaSink") || !g_strcmp0(G_OBJECT_TYPE_NAME(object), "GstPulseSink")) + { + gst_base_sink_set_max_lateness((GstBaseSink *) object, 10000000); /* nanoseconds */ + g_object_set(G_OBJECT(object), "slave-method", 1, NULL); + g_object_set(G_OBJECT(object), "buffer-time", (gint64) 20000, NULL); /* microseconds */ + g_object_set(G_OBJECT(object), "drift-tolerance", (gint64) 20000, NULL); /* microseconds */ + g_object_set(G_OBJECT(object), "latency-time", (gint64) 10000, NULL); /* microseconds */ + g_object_set(G_OBJECT(object), "sync", TRUE, NULL); /* synchronize on the clock */ + g_object_set(G_OBJECT(object), "async", TRUE, NULL); /* no async state changes */ + } } static void tsmf_gstreamer_enough_data(GstAppSrc *src, gpointer user_data) @@ -81,16 +113,32 @@ static gboolean tsmf_gstreamer_seek_data(GstAppSrc *src, guint64 offset, gpointe (void) mdecoder; DEBUG_TSMF("%s offset=%llu", get_type(mdecoder), offset); - if (!mdecoder->paused) - tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PAUSED); + return TRUE; +} - gst_app_src_end_of_stream((GstAppSrc*) mdecoder->src); +static BOOL tsmf_gstreamer_change_volume(ITSMFDecoder* decoder, UINT32 newVolume, UINT32 muted) +{ + TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder; - if (!mdecoder->paused) - tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PLAYING); + if (!mdecoder || !mdecoder->pipe) + return TRUE; - if (mdecoder->sync_cb) - mdecoder->sync_cb(mdecoder->stream); + if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) + return TRUE; + + mdecoder->gstMuted = (BOOL) muted; + DEBUG_TSMF("mute=[%d]", mdecoder->gstMuted); + mdecoder->gstVolume = (double) newVolume / (double) 10000; + DEBUG_TSMF("gst_new_vol=[%f]", mdecoder->gstVolume); + + if (!mdecoder->volume) + return TRUE; + + if (!G_IS_OBJECT(mdecoder->volume)) + return TRUE; + + g_object_set(mdecoder->volume, "mute", mdecoder->gstMuted, NULL); + g_object_set(mdecoder->volume, "volume", mdecoder->gstVolume, NULL); return TRUE; } @@ -209,10 +257,17 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* m { case TSMF_SUB_TYPE_WVC1: mdecoder->gst_caps = gst_caps_new_simple("video/x-wmv", + "bitrate", G_TYPE_UINT, media_type->BitRate, "width", G_TYPE_INT, media_type->Width, "height", G_TYPE_INT, media_type->Height, "wmvversion", G_TYPE_INT, 3, +#if GST_VERSION_MAJOR > 0 "format", G_TYPE_STRING, "WVC1", +#else + "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('W', 'V', 'C', '1'), +#endif + "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, + "pixel-aspect-ratio", GST_TYPE_FRACTION, 1 , 1, NULL); break; case TSMF_SUB_TYPE_MP4S: @@ -221,6 +276,12 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* m "bitrate", G_TYPE_UINT, media_type->BitRate, "width", G_TYPE_INT, media_type->Width, "height", G_TYPE_INT, media_type->Height, +#if GST_VERSION_MAJOR > 0 + "format", G_TYPE_STRING, "MP42", +#else + "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('M', 'P', '4', '2'), +#endif + "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, NULL); break; case TSMF_SUB_TYPE_MP42: @@ -229,15 +290,41 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* m "bitrate", G_TYPE_UINT, media_type->BitRate, "width", G_TYPE_INT, media_type->Width, "height", G_TYPE_INT, media_type->Height, +#if GST_VERSION_MAJOR > 0 + "format", G_TYPE_STRING, "MP42", +#else + "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('M', 'P', '4', '2'), +#endif + "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, NULL); break; case TSMF_SUB_TYPE_MP43: mdecoder->gst_caps = gst_caps_new_simple("video/x-msmpeg", + "msmpegversion", G_TYPE_INT, 43, "bitrate", G_TYPE_UINT, media_type->BitRate, "width", G_TYPE_INT, media_type->Width, "height", G_TYPE_INT, media_type->Height, +#if GST_VERSION_MAJOR > 0 + "format", G_TYPE_STRING, "MP43", +#else + "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('M', 'P', '4', '3'), +#endif + "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, NULL); break; + case TSMF_SUB_TYPE_M4S2: + mdecoder->gst_caps = gst_caps_new_simple ("video/mpeg", + "mpegversion", G_TYPE_INT, 4, + "width", G_TYPE_INT, media_type->Width, + "height", G_TYPE_INT, media_type->Height, +#if GST_VERSION_MAJOR > 0 + "format", G_TYPE_STRING, "M4S2", +#else + "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('M', '4', 'S', '2'), +#endif + "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, + NULL); + break; case TSMF_SUB_TYPE_WMA9: mdecoder->gst_caps = gst_caps_new_simple("audio/x-wma", "wmaversion", G_TYPE_INT, 3, @@ -249,6 +336,17 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* m "block_align", G_TYPE_INT, media_type->BlockAlign, NULL); break; + case TSMF_SUB_TYPE_WMA1: + mdecoder->gst_caps = gst_caps_new_simple ("audio/x-wma", + "wmaversion", G_TYPE_INT, 1, + "rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator, + "channels", G_TYPE_INT, media_type->Channels, + "bitrate", G_TYPE_INT, media_type->BitRate, + "depth", G_TYPE_INT, media_type->BitsPerSample, + "width", G_TYPE_INT, media_type->BitsPerSample, + "block_align", G_TYPE_INT, media_type->BlockAlign, + NULL); + break; case TSMF_SUB_TYPE_WMA2: mdecoder->gst_caps = gst_caps_new_simple("audio/x-wma", "wmaversion", G_TYPE_INT, 2, @@ -274,6 +372,12 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* m "width", G_TYPE_INT, media_type->Width, "height", G_TYPE_INT, media_type->Height, "wmvversion", G_TYPE_INT, 1, +#if GST_VERSION_MAJOR > 0 + "format", G_TYPE_STRING, "WMV1", +#else + "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('W', 'M', 'V', '1'), +#endif + "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, NULL); break; case TSMF_SUB_TYPE_WMV2: @@ -281,6 +385,13 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* m "width", G_TYPE_INT, media_type->Width, "height", G_TYPE_INT, media_type->Height, "wmvversion", G_TYPE_INT, 2, +#if GST_VERSION_MAJOR > 0 + "format", G_TYPE_STRING, "WMV2", +#else + "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('W', 'M', 'V', '2'), +#endif + "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, + "pixel-aspect-ratio", GST_TYPE_FRACTION, 1 , 1, NULL); break; case TSMF_SUB_TYPE_WMV3: @@ -289,6 +400,13 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* m "width", G_TYPE_INT, media_type->Width, "height", G_TYPE_INT, media_type->Height, "wmvversion", G_TYPE_INT, 3, +#if GST_VERSION_MAJOR > 0 + "format", G_TYPE_STRING, "WMV3", +#else + "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('W', 'M', 'V', '3'), +#endif + "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, + "pixel-aspect-ratio", GST_TYPE_FRACTION, 1 , 1, NULL); break; case TSMF_SUB_TYPE_AVC1: @@ -296,6 +414,10 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* m mdecoder->gst_caps = gst_caps_new_simple("video/x-h264", "width", G_TYPE_INT, media_type->Width, "height", G_TYPE_INT, media_type->Height, + "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, + "pixel-aspect-ratio", GST_TYPE_FRACTION, 1 , 1, + "stream-format", G_TYPE_STRING, "byte-stream", + "alignment", G_TYPE_STRING, "nal", NULL); break; case TSMF_SUB_TYPE_AC3: @@ -319,6 +441,8 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* m "rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator, "channels", G_TYPE_INT, media_type->Channels, "mpegversion", G_TYPE_INT, 4, + "framed", G_TYPE_BOOLEAN, TRUE, + "stream-format", G_TYPE_STRING, "raw", NULL); break; case TSMF_SUB_TYPE_MP1A: @@ -347,6 +471,7 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* m "format", G_TYPE_STRING, "YUY2", "width", G_TYPE_INT, media_type->Width, "height", G_TYPE_INT, media_type->Height, + "framerate", GST_TYPE_FRACTION, media_type->SamplesPerSecond.Numerator, media_type->SamplesPerSecond.Denominator, NULL); #endif break; @@ -358,11 +483,14 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* m break; case TSMF_SUB_TYPE_MP2A: mdecoder->gst_caps = gst_caps_new_simple("audio/mpeg", - "mpegversion", G_TYPE_INT, 2, + "mpegversion", G_TYPE_INT, 1, "rate", G_TYPE_INT, media_type->SamplesPerSecond.Numerator, "channels", G_TYPE_INT, media_type->Channels, NULL); break; + case TSMF_SUB_TYPE_FLAC: + mdecoder->gst_caps = gst_caps_new_simple("audio/x-flac", "", NULL); + break; default: WLog_ERR(TAG, "unknown format:(%d).", media_type->SubType); return FALSE; @@ -404,17 +532,23 @@ void tsmf_gstreamer_clean_up(TSMFGstreamerDecoder* mdecoder) gst_object_unref(mdecoder->pipe); } - tsmf_window_destroy(mdecoder); mdecoder->ready = FALSE; + mdecoder->paused = FALSE; + mdecoder->pipe = NULL; mdecoder->src = NULL; + mdecoder->queue = NULL; } 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 !"; +#if GST_VERSION_MAJOR > 0 + const char* video = "appsrc name=videosource ! queue2 name=videoqueue ! decodebin name=videodecoder !"; + const char* audio = "appsrc name=audiosource ! queue2 name=audioqueue ! decodebin name=audiodecoder ! audioconvert ! audiorate ! audioresample ! volume name=audiovolume !"; +#else + const char* video = "appsrc name=videosource ! queue2 name=videoqueue ! decodebin2 name=videodecoder !"; + const char* audio = "appsrc name=audiosource ! queue2 name=audioqueue ! decodebin2 name=audiodecoder ! audioconvert ! audiorate ! audioresample ! volume name=audiovolume !"; +#endif char pipeline[1024]; if (!mdecoder) @@ -424,9 +558,9 @@ BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder* mdecoder) * The only fixed elements necessary are appsrc and the volume element for audio streams. * The rest could easily be provided in gstreamer pipeline notation from command line. */ if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) - sprintf_s(pipeline, sizeof(pipeline), "%s %s %s name=outsink", appsrc, video, tsmf_platform_get_video_sink()); + sprintf_s(pipeline, sizeof(pipeline), "%s %s name=videosink", video, tsmf_platform_get_video_sink()); else - sprintf_s(pipeline, sizeof(pipeline), "%s %s %s name=outsink", appsrc, audio, tsmf_platform_get_audio_sink()); + sprintf_s(pipeline, sizeof(pipeline), "%s %s name=audiosink", audio, tsmf_platform_get_audio_sink()); DEBUG_TSMF("pipeline=%s", pipeline); mdecoder->pipe = gst_parse_launch(pipeline, NULL); @@ -437,7 +571,10 @@ BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder* mdecoder) return FALSE; } - mdecoder->src = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "source"); + if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) + mdecoder->src = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "videosource"); + else + mdecoder->src = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "audiosource"); if (!mdecoder->src) { @@ -445,7 +582,21 @@ BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder* mdecoder) return FALSE; } - mdecoder->outsink = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "outsink"); + if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) + mdecoder->queue = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "videoqueue"); + else + mdecoder->queue = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "audioqueue"); + + if (!mdecoder->queue) + { + WLog_ERR(TAG, "Failed to get queue"); + return FALSE; + } + + if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) + mdecoder->outsink = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "videosink"); + else + mdecoder->outsink = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "audiosink"); if (!mdecoder->outsink) { @@ -453,7 +604,9 @@ BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder* mdecoder) return FALSE; } - if (mdecoder->media_type != TSMF_MAJOR_TYPE_VIDEO) + g_signal_connect(mdecoder->outsink, "child-added", G_CALLBACK(cb_child_added), mdecoder); + + if (mdecoder->media_type == TSMF_MAJOR_TYPE_AUDIO) { mdecoder->volume = gst_bin_get_by_name(GST_BIN(mdecoder->pipe), "audiovolume"); @@ -462,6 +615,8 @@ BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder* mdecoder) WLog_ERR(TAG, "Failed to get volume"); return FALSE; } + + tsmf_gstreamer_change_volume((ITSMFDecoder*)mdecoder, mdecoder->gstVolume*((double) 10000), mdecoder->gstMuted); } tsmf_platform_register_handler(mdecoder); @@ -473,16 +628,45 @@ BOOL tsmf_gstreamer_pipeline_build(TSMFGstreamerDecoder* mdecoder) tsmf_gstreamer_seek_data }; g_object_set(mdecoder->src, "format", GST_FORMAT_TIME, NULL); - g_object_set(mdecoder->src, "is-live", TRUE, NULL); - g_object_set(mdecoder->src, "block", TRUE, NULL); + g_object_set(mdecoder->src, "is-live", FALSE, NULL); + g_object_set(mdecoder->src, "block", FALSE, NULL); + g_object_set(mdecoder->src, "blocksize", 1024, NULL); gst_app_src_set_caps((GstAppSrc *) mdecoder->src, mdecoder->gst_caps); gst_app_src_set_callbacks((GstAppSrc *)mdecoder->src, &callbacks, mdecoder, NULL); gst_app_src_set_stream_type((GstAppSrc *) mdecoder->src, GST_APP_STREAM_TYPE_SEEKABLE); + gst_app_src_set_latency((GstAppSrc *) mdecoder->src, 0, -1); + gst_app_src_set_max_bytes((GstAppSrc *) mdecoder->src, (guint64) 0);//unlimited + g_object_set(G_OBJECT(mdecoder->queue), "use-buffering", FALSE, NULL); + g_object_set(G_OBJECT(mdecoder->queue), "use-rate-estimate", FALSE, NULL); + g_object_set(G_OBJECT(mdecoder->queue), "max-size-buffers", 0, NULL); + g_object_set(G_OBJECT(mdecoder->queue), "max-size-bytes", 0, NULL); + g_object_set(G_OBJECT(mdecoder->queue), "max-size-time", (guint64) 0, NULL); + + /* Only set these properties if not an autosink, otherwise we will set properties when real sinks are added */ + if (!g_strcmp0(G_OBJECT_TYPE_NAME(mdecoder->outsink), "GstAutoVideoSink") && !g_strcmp0(G_OBJECT_TYPE_NAME(mdecoder->outsink), "GstAutoAudioSink")) + { + if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) + { + gst_base_sink_set_max_lateness((GstBaseSink *) mdecoder->outsink, 10000000); /* nanoseconds */ + } + else + { + gst_base_sink_set_max_lateness((GstBaseSink *) mdecoder->outsink, 10000000); /* nanoseconds */ + g_object_set(G_OBJECT(mdecoder->outsink), "buffer-time", (gint64) 20000, NULL); /* microseconds */ + g_object_set(G_OBJECT(mdecoder->outsink), "drift-tolerance", (gint64) 20000, NULL); /* microseconds */ + g_object_set(G_OBJECT(mdecoder->outsink), "latency-time", (gint64) 10000, NULL); /* microseconds */ + g_object_set(G_OBJECT(mdecoder->outsink), "slave-method", 1, NULL); + } + g_object_set(G_OBJECT(mdecoder->outsink), "sync", TRUE, NULL); /* synchronize on the clock */ + g_object_set(G_OBJECT(mdecoder->outsink), "async", TRUE, NULL); /* no async state changes */ + } + tsmf_window_create(mdecoder); tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_READY); tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PLAYING); mdecoder->pipeline_start_time_valid = 0; mdecoder->shutdown = 0; + mdecoder->paused = FALSE; GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(mdecoder->pipe), GST_DEBUG_GRAPH_SHOW_ALL, get_type(mdecoder)); @@ -495,7 +679,7 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder* decoder, const BYTE *data, UIN GstBuffer *gst_buf; 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); + BOOL useTimestamps = TRUE; if (!mdecoder) { @@ -509,9 +693,15 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder* decoder, const BYTE *data, UIN * We don't expect to block here often, since the pipeline should * have more than enough buffering. */ - DEBUG_TSMF("%s. Start:(%llu) End:(%llu) Duration:(%llu) Last End:(%llu)", - get_type(mdecoder), start_time, end_time, duration, - mdecoder->last_sample_end_time); + DEBUG_TSMF("%s. Start:(%lu) End:(%lu) Duration:(%d) Last Start:(%lu)", + get_type(mdecoder), start_time, end_time, (int)duration, + mdecoder->last_sample_start_time); + + if (mdecoder->shutdown) + { + WLog_ERR(TAG, "decodeEx called on shutdown decoder"); + return TRUE; + } if (mdecoder->gst_caps == NULL) { @@ -519,6 +709,9 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder* decoder, const BYTE *data, UIN return FALSE; } + if (!mdecoder->pipe) + tsmf_gstreamer_pipeline_build(mdecoder); + if (!mdecoder->src) { WLog_ERR(TAG, "failed to construct pipeline correctly. Unable to push buffer to source element."); @@ -533,53 +726,115 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder* decoder, const BYTE *data, UIN return FALSE; } + /* Relative timestamping will sometimes be set to 0 + * so we ignore these timestamps just to be safe(bit 8) + */ + if (extensions & 0x00000080) + { + DEBUG_TSMF("Ignoring the timestamps - relative - bit 8"); + useTimestamps = FALSE; + } + + /* If no timestamps exist then we dont want to look at the timestamp values (bit 7) */ + if (extensions & 0x00000040) + { + DEBUG_TSMF("Ignoring the timestamps - none - bit 7"); + useTimestamps = FALSE; + } + + /* If performing a seek */ + if (mdecoder->seeking) + { + mdecoder->seeking = FALSE; + tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PAUSED); + mdecoder->pipeline_start_time_valid = 0; + } + if (mdecoder->pipeline_start_time_valid) { - long long diff = start_time; - diff -= mdecoder->last_sample_end_time; + DEBUG_TSMF("%s start time %lu", get_type(mdecoder), start_time); - if (diff < 0) - diff *= -1; + /* Adjusted the condition for a seek to be based on start time only + * WMV1 and WMV2 files in particular have bad end time and duration values + * there seems to be no real side effects of just using the start time instead + */ + UINT64 minTime = mdecoder->last_sample_start_time - (UINT64) SEEK_TOLERANCE; + UINT64 maxTime = mdecoder->last_sample_start_time + (UINT64) SEEK_TOLERANCE; - /* The pipe is initialized, but there is a discontinuity. - * Seek to the start position... */ - if (diff > 50) + /* Make sure the minTime stops at 0 , should we be at the beginning of the stream */ + if (mdecoder->last_sample_start_time < (UINT64) SEEK_TOLERANCE) + minTime = 0; + + /* If the start_time is valid and different from the previous start time by more than the seek tolerance, then we have a seek condition */ + if (((start_time > maxTime) || (start_time < minTime)) && useTimestamps) { - DEBUG_TSMF("%s seeking to %lld", get_type(mdecoder), start_time); + DEBUG_TSMF("tsmf_gstreamer_decodeEx: start_time=[%lu] > last_sample_start_time=[%lu] OR ", start_time, mdecoder->last_sample_start_time); + DEBUG_TSMF("tsmf_gstreamer_decodeEx: start_time=[%lu] < last_sample_start_time=[%lu] with", start_time, mdecoder->last_sample_start_time); + DEBUG_TSMF("tsmf_gstreamer_decodeEX: a tolerance of more than [%lu] from the last sample", SEEK_TOLERANCE); + DEBUG_TSMF("tsmf_gstreamer_decodeEX: minTime=[%lu] maxTime=[%lu]", minTime, maxTime); - if (!gst_element_seek(mdecoder->pipe, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, - GST_SEEK_TYPE_SET, sample_time, - GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) - { - WLog_ERR(TAG, "seek failed"); - } + mdecoder->seeking = TRUE; - mdecoder->pipeline_start_time_valid = 0; + /* since we cant make the gstreamer pipeline jump to the new start time after a seek - we just maintain + * a offset between realtime and gstreamer time + */ + mdecoder->seek_offset = start_time; } } else { - DEBUG_TSMF("%s start time %llu", get_type(mdecoder), sample_time); + DEBUG_TSMF("%s start time %lu", get_type(mdecoder), start_time); + /* Always set base/start time to 0. Will use seek offset to translate real buffer times + * back to 0. This allows the video to be started from anywhere and the ability to handle seeks + * without rebuilding the pipeline, etc. since that is costly + */ + gst_element_set_base_time(mdecoder->pipe, tsmf_gstreamer_timestamp_ms_to_gst(0)); + gst_element_set_start_time(mdecoder->pipe, tsmf_gstreamer_timestamp_ms_to_gst(0)); mdecoder->pipeline_start_time_valid = 1; + + /* Set the seek offset if buffer has valid timestamps. */ + if (useTimestamps) + mdecoder->seek_offset = start_time; + + if (!gst_element_seek(mdecoder->pipe, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, + GST_SEEK_TYPE_SET, 0, + GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE)) + { + WLog_ERR(TAG, "seek failed"); + } } #if GST_VERSION_MAJOR > 0 - GST_BUFFER_PTS(gst_buf) = sample_time; + if (useTimestamps) + GST_BUFFER_PTS(gst_buf) = sample_time - tsmf_gstreamer_timestamp_ms_to_gst(mdecoder->seek_offset); + else + GST_BUFFER_PTS(gst_buf) = GST_CLOCK_TIME_NONE; #else - GST_BUFFER_TIMESTAMP(gst_buf) = sample_time; + if (useTimestamps) + GST_BUFFER_TIMESTAMP(gst_buf) = sample_time - tsmf_gstreamer_timestamp_ms_to_gst(mdecoder->seek_offset); + else + GST_BUFFER_TIMESTAMP(gst_buf) = GST_CLOCK_TIME_NONE; +#endif + GST_BUFFER_DURATION(gst_buf) = GST_CLOCK_TIME_NONE; + GST_BUFFER_OFFSET(gst_buf) = GST_BUFFER_OFFSET_NONE; +#if GST_VERSION_MAJOR > 0 +#else + gst_buffer_set_caps(gst_buf, mdecoder->gst_caps); #endif - GST_BUFFER_DURATION(gst_buf) = sample_duration; gst_app_src_push_buffer(GST_APP_SRC(mdecoder->src), gst_buf); - if (mdecoder->ack_cb) - mdecoder->ack_cb(mdecoder->stream, TRUE); - - mdecoder->last_sample_end_time = end_time; - - if (GST_STATE(mdecoder->pipe) != GST_STATE_PLAYING) + /* Should only update the last timestamps if the current ones are valid */ + if (useTimestamps) { - DEBUG_TSMF("%s: state=%s", get_type(mdecoder), gst_element_state_get_name(GST_STATE(mdecoder->pipe))); + mdecoder->last_sample_start_time = start_time; + mdecoder->last_sample_end_time = end_time; + } + if (mdecoder->pipe && (GST_STATE(mdecoder->pipe) != GST_STATE_PLAYING)) + { + DEBUG_TSMF("%s: state=%s", get_type(mdecoder), gst_element_state_get_name(GST_STATE(mdecoder->pipe))); + + DEBUG_TSMF("%s Paused: %i Shutdown: %i Ready: %i", get_type(mdecoder), mdecoder->paused, mdecoder->shutdown, mdecoder->ready); if (!mdecoder->paused && !mdecoder->shutdown && mdecoder->ready) tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PLAYING); } @@ -587,38 +842,15 @@ static BOOL tsmf_gstreamer_decodeEx(ITSMFDecoder* decoder, const BYTE *data, UIN return TRUE; } -static BOOL tsmf_gstreamer_change_volume(ITSMFDecoder* decoder, UINT32 newVolume, UINT32 muted) -{ - TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder; - - if (!mdecoder || !mdecoder->pipe) - return FALSE; - - if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) - return TRUE; - - mdecoder->gstMuted = (BOOL) muted; - DEBUG_TSMF("mute=[%d]", mdecoder->gstMuted); - mdecoder->gstVolume = (double) newVolume / (double) 10000; - DEBUG_TSMF("gst_new_vol=[%f]", mdecoder->gstVolume); - - if (!mdecoder->volume) - return FALSE; - - if (!G_IS_OBJECT(mdecoder->volume)) - return FALSE; - - g_object_set(mdecoder->volume, "mute", mdecoder->gstMuted, NULL); - g_object_set(mdecoder->volume, "volume", mdecoder->gstVolume, NULL); - return TRUE; -} - static BOOL tsmf_gstreamer_control(ITSMFDecoder* decoder, ITSMFControlMsg control_msg, UINT32 *arg) { TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder; if (!mdecoder) - return FALSE; + { + WLog_ERR(TAG, "Control called with no decoder!"); + return TRUE; + } if (control_msg == Control_Pause) { @@ -626,15 +858,13 @@ static BOOL tsmf_gstreamer_control(ITSMFDecoder* decoder, ITSMFControlMsg contro if (mdecoder->paused) { - WLog_ERR(TAG, "%s: Ignoring control PAUSE, already received!", get_type(mdecoder)); + WLog_ERR(TAG, "%s: Ignoring Control_Pause, already received!", get_type(mdecoder)); return TRUE; } tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PAUSED); + mdecoder->shutdown = 0; mdecoder->paused = TRUE; - - if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) - tsmf_window_pause(mdecoder); } else if (control_msg == Control_Resume) { @@ -642,17 +872,12 @@ static BOOL tsmf_gstreamer_control(ITSMFDecoder* decoder, ITSMFControlMsg contro if (!mdecoder->paused && !mdecoder->shutdown) { - WLog_ERR(TAG, "%s: Ignoring control RESUME, already received!", get_type(mdecoder)); + WLog_ERR(TAG, "%s: Ignoring Control_Resume, already received!", get_type(mdecoder)); return TRUE; } + mdecoder->shutdown = 0; mdecoder->paused = FALSE; - mdecoder->shutdown = FALSE; - - if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) - tsmf_window_resume(mdecoder); - - tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PLAYING); } else if (control_msg == Control_Stop) { @@ -660,18 +885,29 @@ static BOOL tsmf_gstreamer_control(ITSMFDecoder* decoder, ITSMFControlMsg contro if (mdecoder->shutdown) { - WLog_ERR(TAG, "%s: Ignoring control STOP, already received!", get_type(mdecoder)); + WLog_ERR(TAG, "%s: Ignoring Control_Stop, already received!", get_type(mdecoder)); return TRUE; } - mdecoder->shutdown = TRUE; /* Reset stamps, flush buffers, etc */ - tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PAUSED); + if (mdecoder->pipe) + { + tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_NULL); + tsmf_window_destroy(mdecoder); + tsmf_gstreamer_clean_up(mdecoder); + } + mdecoder->seek_offset = 0; + mdecoder->pipeline_start_time_valid = 0; + mdecoder->shutdown = 1; + } + else if (control_msg == Control_Restart) + { + DEBUG_TSMF("Control_Restart %s", get_type(mdecoder)); + mdecoder->shutdown = 0; + mdecoder->paused = FALSE; - if (mdecoder->media_type == TSMF_MAJOR_TYPE_VIDEO) - tsmf_window_pause(mdecoder); - - gst_app_src_end_of_stream((GstAppSrc *)mdecoder->src); + if (mdecoder->pipeline_start_time_valid) + tsmf_gstreamer_pipeline_set_state(mdecoder, GST_STATE_PLAYING); } else WLog_ERR(TAG, "Unknown control message %08x", control_msg); @@ -679,7 +915,7 @@ static BOOL tsmf_gstreamer_control(ITSMFDecoder* decoder, ITSMFControlMsg contro return TRUE; } -static BOOL tsmf_gstreamer_buffer_filled(ITSMFDecoder* decoder) +static BOOL tsmf_gstreamer_buffer_level(ITSMFDecoder* decoder) { TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder; DEBUG_TSMF(""); @@ -687,10 +923,13 @@ static BOOL tsmf_gstreamer_buffer_filled(ITSMFDecoder* decoder) if (!mdecoder) return FALSE; - guint buff_max = 0; guint clbuff = 0; - DEBUG_TSMF("%s buffer fill %u/%u", get_type(mdecoder), clbuff, buff_max); - return clbuff >= buff_max ? TRUE : FALSE; + + if (G_IS_OBJECT(mdecoder->queue)) + g_object_get(mdecoder->queue, "current-level-buffers", &clbuff, NULL); + + DEBUG_TSMF("%s buffer level %u", get_type(mdecoder), clbuff); + return clbuff; } static void tsmf_gstreamer_free(ITSMFDecoder* decoder) @@ -700,7 +939,7 @@ static void tsmf_gstreamer_free(ITSMFDecoder* decoder) if (mdecoder) { - mdecoder->shutdown = 1; + tsmf_window_destroy(mdecoder); tsmf_gstreamer_clean_up(mdecoder); if (mdecoder->gst_caps) @@ -721,19 +960,19 @@ static UINT64 tsmf_gstreamer_get_running_time(ITSMFDecoder* decoder) return 0; if (!mdecoder->outsink) - return mdecoder->last_sample_end_time; + return mdecoder->last_sample_start_time; - if (GST_STATE(mdecoder->pipe) != GST_STATE_PLAYING) + if (!mdecoder->pipe) return 0; GstFormat fmt = GST_FORMAT_TIME; gint64 pos = 0; #if GST_VERSION_MAJOR > 0 - gst_element_query_position(mdecoder->outsink, fmt, &pos); + gst_element_query_position(mdecoder->pipe, fmt, &pos); #else - gst_element_query_position(mdecoder->outsink, &fmt, &pos); + gst_element_query_position(mdecoder->pipe, &fmt, &pos); #endif - return pos/100; + return (UINT64) (pos/100 + mdecoder->seek_offset); } static BOOL tsmf_gstreamer_update_rendering_area(ITSMFDecoder* decoder, @@ -757,7 +996,7 @@ BOOL tsmf_gstreamer_ack(ITSMFDecoder* decoder, BOOL (*cb)(void *, BOOL), void *s { TSMFGstreamerDecoder* mdecoder = (TSMFGstreamerDecoder *) decoder; DEBUG_TSMF(""); - mdecoder->ack_cb = cb; + mdecoder->ack_cb = NULL; mdecoder->stream = stream; return TRUE; } @@ -800,13 +1039,17 @@ ITSMFDecoder* freerdp_tsmf_client_subsystem_entry(void) decoder->iface.Control = tsmf_gstreamer_control; decoder->iface.DecodeEx = tsmf_gstreamer_decodeEx; decoder->iface.ChangeVolume = tsmf_gstreamer_change_volume; - decoder->iface.BufferFilled = tsmf_gstreamer_buffer_filled; + decoder->iface.BufferLevel = tsmf_gstreamer_buffer_level; decoder->iface.SetAckFunc = tsmf_gstreamer_ack; decoder->iface.SetSyncFunc = tsmf_gstreamer_sync; decoder->paused = FALSE; decoder->gstVolume = 0.5; decoder->gstMuted = FALSE; decoder->state = GST_STATE_VOID_PENDING; /* No real state yet */ + decoder->last_sample_start_time = 0; + decoder->last_sample_end_time = 0; + decoder->seek_offset = 0; + decoder->seeking = FALSE; if (tsmf_platform_create(decoder) < 0) { diff --git a/channels/tsmf/client/gstreamer/tsmf_platform.h b/channels/tsmf/client/gstreamer/tsmf_platform.h index 6748f4ea8..0d6fc5aa0 100644 --- a/channels/tsmf/client/gstreamer/tsmf_platform.h +++ b/channels/tsmf/client/gstreamer/tsmf_platform.h @@ -38,12 +38,16 @@ typedef struct _TSMFGstreamerDecoder GstElement *pipe; GstElement *src; + GstElement *queue; GstElement *outsink; GstElement *volume; BOOL ready; BOOL paused; + UINT64 last_sample_start_time; UINT64 last_sample_end_time; + BOOL seeking; + UINT64 seek_offset; double gstVolume; BOOL gstMuted; @@ -74,8 +78,8 @@ 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_pause(TSMFGstreamerDecoder* decoder); -int tsmf_window_resume(TSMFGstreamerDecoder* decoder); +int tsmf_window_map(TSMFGstreamerDecoder* decoder); +int tsmf_window_unmap(TSMFGstreamerDecoder* decoder); BOOL tsmf_gstreamer_add_pad(TSMFGstreamerDecoder* mdecoder); void tsmf_gstreamer_remove_pad(TSMFGstreamerDecoder* mdecoder); diff --git a/channels/tsmf/client/oss/CMakeLists.txt b/channels/tsmf/client/oss/CMakeLists.txt index b0d39b6a9..4137f437b 100644 --- a/channels/tsmf/client/oss/CMakeLists.txt +++ b/channels/tsmf/client/oss/CMakeLists.txt @@ -28,5 +28,3 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N target_link_libraries(${MODULE_NAME} freerdp ${OSS_LIBRARIES}) - -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/tsmf/client/pulse/CMakeLists.txt b/channels/tsmf/client/pulse/CMakeLists.txt index a93854a53..ab8a5ac4b 100644 --- a/channels/tsmf/client/pulse/CMakeLists.txt +++ b/channels/tsmf/client/pulse/CMakeLists.txt @@ -28,5 +28,3 @@ add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_N target_link_libraries(${MODULE_NAME} freerdp) - -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) diff --git a/channels/tsmf/client/tsmf_codec.c b/channels/tsmf/client/tsmf_codec.c index 7ae5e283d..b5e5a42cd 100644 --- a/channels/tsmf/client/tsmf_codec.c +++ b/channels/tsmf/client/tsmf_codec.c @@ -75,6 +75,13 @@ static const TSMFMediaTypeMap tsmf_sub_type_map[] = TSMF_SUB_TYPE_WVC1 }, + /* 00000160-0000-0010-8000-00AA00389B71 */ + { + { 0x60, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 }, + "MEDIASUBTYPE_WMAudioV1", /* V7, V8 has the same GUID */ + TSMF_SUB_TYPE_WMA1 + }, + /* 00000161-0000-0010-8000-00AA00389B71 */ { { 0x61, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 }, @@ -173,6 +180,13 @@ static const TSMFMediaTypeMap tsmf_sub_type_map[] = TSMF_SUB_TYPE_MP42 }, + /* 3253344D-0000-0010-8000-00AA00389B71 */ + { + { 0x4D, 0x34, 0x53, 0x32, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 }, + "MEDIASUBTYPE_MP42", + TSMF_SUB_TYPE_M4S2 + }, + /* E436EB81-524F-11CE-9F53-0020AF0BA770 */ { { 0x81, 0xEB, 0x36, 0xE4, 0x4F, 0x52, 0xCE, 0x11, 0x9F, 0x53, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70 }, @@ -605,11 +619,22 @@ BOOL tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE* mediatype, wStream* s) BOOL tsmf_codec_check_media_type(const char* decoder_name, wStream* s) { BYTE* m; - BOOL ret; + BOOL ret = FALSE; TS_AM_MEDIA_TYPE mediatype; + static BOOL decoderAvailable = FALSE; + static BOOL firstRun = TRUE; + + if (firstRun) + { + firstRun =FALSE; + if (tsmf_check_decoder_available(decoder_name)) + decoderAvailable = TRUE; + } + Stream_GetPointer(s, m); - ret = tsmf_codec_parse_media_type(&mediatype, s); + if (decoderAvailable) + ret = tsmf_codec_parse_media_type(&mediatype, s); Stream_SetPointer(s, m); if (ret) diff --git a/channels/tsmf/client/tsmf_constants.h b/channels/tsmf/client/tsmf_constants.h index 1fee13a67..3ca92f645 100644 --- a/channels/tsmf/client/tsmf_constants.h +++ b/channels/tsmf/client/tsmf_constants.h @@ -125,6 +125,8 @@ #define TSMF_SUB_TYPE_VP8 24 #define TSMF_SUB_TYPE_VP9 25 #define TSMF_SUB_TYPE_H263 26 +#define TSMF_SUB_TYPE_M4S2 27 +#define TSMF_SUB_TYPE_WMA1 28 /* FormatType */ #define TSMF_FORMAT_TYPE_UNKNOWN 0 diff --git a/channels/tsmf/client/tsmf_decoder.c b/channels/tsmf/client/tsmf_decoder.c index 164e0d8be..319dbfcac 100644 --- a/channels/tsmf/client/tsmf_decoder.c +++ b/channels/tsmf/client/tsmf_decoder.c @@ -32,7 +32,7 @@ #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) { ITSMFDecoder* decoder; TSMF_DECODER_ENTRY entry; @@ -50,33 +50,74 @@ static ITSMFDecoder* tsmf_load_decoder_by_name(const char *name, TS_AM_MEDIA_TYP return NULL; } - if (!decoder->SetFormat(decoder, media_type)) - { - decoder->Free(decoder); - decoder = NULL; - } - return decoder; } +static BOOL tsmf_decoder_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE* media_type) +{ + if (decoder->SetFormat(decoder, media_type)) + return TRUE; + else + return FALSE; +} + ITSMFDecoder* tsmf_load_decoder(const char* name, TS_AM_MEDIA_TYPE* media_type) { ITSMFDecoder* decoder = NULL; if (name) { - decoder = tsmf_load_decoder_by_name(name, media_type); + decoder = tsmf_load_decoder_by_name(name); } #if defined(WITH_GSTREAMER_1_0) || defined(WITH_GSTREAMER_0_10) if (!decoder) - decoder = tsmf_load_decoder_by_name("gstreamer", media_type); + decoder = tsmf_load_decoder_by_name("gstreamer"); #endif #if defined(WITH_FFMPEG) if (!decoder) - decoder = tsmf_load_decoder_by_name("ffmpeg", media_type); + decoder = tsmf_load_decoder_by_name("ffmpeg"); #endif + if (decoder) + { + if (!tsmf_decoder_set_format(decoder, media_type)) + { + decoder->Free(decoder); + decoder = NULL; + } + } + return decoder; } + +BOOL tsmf_check_decoder_available(const char* name) +{ + ITSMFDecoder* decoder = NULL; + BOOL retValue = FALSE; + + if (name) + { + decoder = tsmf_load_decoder_by_name(name); + } +#if defined(WITH_GSTREAMER_1_0) || defined(WITH_GSTREAMER_0_10) + if (!decoder) + decoder = tsmf_load_decoder_by_name("gstreamer"); +#endif + +#if defined(WITH_FFMPEG) + if (!decoder) + decoder = tsmf_load_decoder_by_name("ffmpeg"); +#endif + + if (decoder) + { + decoder->Free(decoder); + decoder = NULL; + retValue = TRUE; + } + + return retValue; +} + diff --git a/channels/tsmf/client/tsmf_decoder.h b/channels/tsmf/client/tsmf_decoder.h index d507b9e1b..e4c71dac6 100644 --- a/channels/tsmf/client/tsmf_decoder.h +++ b/channels/tsmf/client/tsmf_decoder.h @@ -27,6 +27,7 @@ typedef enum _ITSMFControlMsg { Control_Pause, Control_Resume, + Control_Restart, Control_Stop } ITSMFControlMsg; @@ -49,7 +50,7 @@ struct _ITSMFDecoder /* Optional Contol function */ BOOL (*Control)(ITSMFDecoder *decoder, ITSMFControlMsg control_msg, UINT32 *arg); /* Decode a sample with extended interface. */ - int (*DecodeEx)(ITSMFDecoder *decoder, const BYTE *data, UINT32 data_size, UINT32 extensions, + BOOL (*DecodeEx)(ITSMFDecoder *decoder, const BYTE *data, UINT32 data_size, UINT32 extensions, UINT64 start_time, UINT64 end_time, UINT64 duration); /* Get current play time */ UINT64(*GetRunningTime)(ITSMFDecoder *decoder); @@ -58,7 +59,7 @@ struct _ITSMFDecoder /* Change Gstreamer Audio Volume */ BOOL (*ChangeVolume)(ITSMFDecoder *decoder, UINT32 newVolume, UINT32 muted); /* Check buffer level */ - BOOL (*BufferFilled)(ITSMFDecoder *decoder); + BOOL (*BufferLevel)(ITSMFDecoder *decoder); /* Register a callback for frame ack. */ BOOL (*SetAckFunc)(ITSMFDecoder *decoder, BOOL (*cb)(void *,BOOL), void *stream); /* Register a callback for stream seek detection. */ @@ -69,6 +70,7 @@ struct _ITSMFDecoder typedef ITSMFDecoder *(*TSMF_DECODER_ENTRY)(void); ITSMFDecoder *tsmf_load_decoder(const char *name, TS_AM_MEDIA_TYPE *media_type); +BOOL tsmf_check_decoder_available(const char* name); #endif diff --git a/channels/tsmf/client/tsmf_ifman.c b/channels/tsmf/client/tsmf_ifman.c index 392377210..b4a84dfdb 100644 --- a/channels/tsmf/client/tsmf_ifman.c +++ b/channels/tsmf/client/tsmf_ifman.c @@ -224,6 +224,7 @@ UINT tsmf_ifman_add_stream(TSMF_IFMAN* ifman, rdpContext* rdpcontext) if (!presentation) { + WLog_ERR(TAG, "unknown presentation id"); status = ERROR_NOT_FOUND; } else @@ -232,10 +233,16 @@ UINT tsmf_ifman_add_stream(TSMF_IFMAN* ifman, rdpContext* rdpcontext) Stream_Seek_UINT32(ifman->input); /* numMediaType */ stream = tsmf_stream_new(presentation, StreamId, rdpcontext); if (!stream) + { + WLog_ERR(TAG, "failed to create stream"); return ERROR_OUTOFMEMORY; + } if (!tsmf_stream_set_format(stream, ifman->decoder_name, ifman->input)) + { + WLog_ERR(TAG, "failed to set stream format"); return ERROR_OUTOFMEMORY; + } } ifman->output_pending = TRUE; @@ -553,6 +560,7 @@ UINT tsmf_ifman_set_allocator(TSMF_IFMAN* ifman) UINT tsmf_ifman_notify_preroll(TSMF_IFMAN* ifman) { DEBUG_TSMF(""); + tsmf_ifman_on_playback_paused(ifman); ifman->output_pending = TRUE; return CHANNEL_RC_OK; } @@ -589,9 +597,9 @@ UINT tsmf_ifman_on_sample(TSMF_IFMAN* ifman) if (Stream_GetRemainingLength(ifman->input) < cbData) return ERROR_INVALID_DATA; - DEBUG_TSMF("MessageId %d StreamId %d SampleStartTime %d SampleEndTime %d " + DEBUG_TSMF("MessageId %d StreamId %d SampleStartTime %lu SampleEndTime %lu " "ThrottleDuration %d SampleExtensions %d cbData %d", - ifman->message_id, StreamId, (int)SampleStartTime, (int)SampleEndTime, + ifman->message_id, StreamId, SampleStartTime, SampleEndTime, (int)ThrottleDuration, SampleExtensions, cbData); presentation = tsmf_presentation_find_by_id(ifman->presentation_id); @@ -637,6 +645,7 @@ UINT tsmf_ifman_on_flush(TSMF_IFMAN* ifman) { UINT32 StreamId; TSMF_PRESENTATION* presentation; + TSMF_STREAM* stream; if (Stream_GetRemainingLength(ifman->input) < 20) return ERROR_INVALID_DATA; @@ -653,8 +662,18 @@ UINT tsmf_ifman_on_flush(TSMF_IFMAN* ifman) return ERROR_NOT_FOUND; } - if (!tsmf_presentation_flush(presentation)) - return ERROR_INVALID_OPERATION; + /* Flush message is for a stream, not the entire presentation + * therefore we only flush the stream as intended per the MS-RDPEV spec + */ + stream = tsmf_stream_find_by_id(presentation, StreamId); + if (stream) + { + if (!tsmf_stream_flush(stream)) + return ERROR_INVALID_OPERATION; + } + else + WLog_ERR(TAG, "unknown stream id"); + ifman->output_pending = TRUE; return CHANNEL_RC_OK; @@ -668,7 +687,7 @@ UINT tsmf_ifman_on_flush(TSMF_IFMAN* ifman) UINT tsmf_ifman_on_end_of_stream(TSMF_IFMAN* ifman) { UINT32 StreamId; - TSMF_STREAM* stream; + TSMF_STREAM* stream = NULL; TSMF_PRESENTATION* presentation; if (Stream_GetRemainingLength(ifman->input) < 20) @@ -684,17 +703,12 @@ UINT tsmf_ifman_on_end_of_stream(TSMF_IFMAN* ifman) stream = tsmf_stream_find_by_id(presentation, StreamId); if (stream) - tsmf_stream_end(stream); + tsmf_stream_end(stream, ifman->message_id, ifman->channel_callback); } DEBUG_TSMF("StreamId %d", StreamId); - if (!Stream_EnsureRemainingCapacity(ifman->output, 16)) - return ERROR_OUTOFMEMORY; - Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */ - Stream_Write_UINT32(ifman->output, StreamId); /* StreamId */ - Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_ENDOFSTREAM); /* EventId */ - Stream_Write_UINT32(ifman->output, 0); /* cbData */ + ifman->output_pending = TRUE; ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY; return CHANNEL_RC_OK; diff --git a/channels/tsmf/client/tsmf_main.c b/channels/tsmf/client/tsmf_main.c index 0c8bdea3a..6e373ecb9 100644 --- a/channels/tsmf/client/tsmf_main.c +++ b/channels/tsmf/client/tsmf_main.c @@ -36,10 +36,46 @@ #include "tsmf_main.h" +BOOL tsmf_send_eos_response(IWTSVirtualChannelCallback* pChannelCallback, UINT32 message_id) +{ + wStream* s = NULL; + int status = -1; + TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*) pChannelCallback; + + if (!callback) + { + DEBUG_TSMF("No callback reference - unable to send eos response!"); + return FALSE; + } + + if (callback && callback->stream_id && callback->channel && callback->channel->Write) + { + s = Stream_New(NULL, 24); + if (!s) + return FALSE; + Stream_Write_UINT32(s, TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY); + Stream_Write_UINT32(s, message_id); + Stream_Write_UINT32(s, CLIENT_EVENT_NOTIFICATION); /* FunctionId */ + Stream_Write_UINT32(s, callback->stream_id); /* StreamId */ + Stream_Write_UINT32(s, TSMM_CLIENT_EVENT_ENDOFSTREAM); /* EventId */ + Stream_Write_UINT32(s, 0); /* cbData */ + DEBUG_TSMF("EOS response size %i", Stream_GetPosition(s)); + + status = callback->channel->Write(callback->channel, Stream_GetPosition(s), Stream_Buffer(s), NULL); + if (status) + { + WLog_ERR(TAG, "response error %d", status); + } + Stream_Free(s, TRUE); + } + + return (status == 0); +} + BOOL tsmf_playback_ack(IWTSVirtualChannelCallback *pChannelCallback, UINT32 message_id, UINT64 duration, UINT32 data_size) { - wStream *s; + wStream *s = NULL; int status = -1; TSMF_CHANNEL_CALLBACK *callback = (TSMF_CHANNEL_CALLBACK *) pChannelCallback; @@ -54,7 +90,7 @@ BOOL tsmf_playback_ack(IWTSVirtualChannelCallback *pChannelCallback, Stream_Write_UINT64(s, duration); /* DataDuration */ Stream_Write_UINT64(s, data_size); /* cbData */ - DEBUG_TSMF("response size %d", (int) Stream_GetPosition(s)); + DEBUG_TSMF("ACK response size %d", (int) Stream_GetPosition(s)); if (!callback || !callback->channel || !callback->channel->Write) { @@ -267,6 +303,11 @@ static UINT tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, input = NULL; ifman.input = NULL; + if (error) + { + WLog_ERR(TAG, "ifman data received processing error %d", error); + } + if (!processed) { switch (FunctionId) @@ -351,7 +392,7 @@ static UINT tsmf_on_close(IWTSVirtualChannelCallback *pChannelCallback) static UINT tsmf_on_new_channel_connection(IWTSListenerCallback *pListenerCallback, IWTSVirtualChannel *pChannel, BYTE *Data, - int *pbAccept, + BOOL *pbAccept, IWTSVirtualChannelCallback **ppCallback) { TSMF_CHANNEL_CALLBACK* callback; diff --git a/channels/tsmf/client/tsmf_main.h b/channels/tsmf/client/tsmf_main.h index e29a00ad4..db3c94582 100644 --- a/channels/tsmf/client/tsmf_main.h +++ b/channels/tsmf/client/tsmf_main.h @@ -64,6 +64,7 @@ struct _TSMF_PLUGIN rdpContext* rdpcontext; }; +BOOL tsmf_send_eos_response(IWTSVirtualChannelCallback* pChannelCallback, UINT32 message_id); BOOL tsmf_playback_ack(IWTSVirtualChannelCallback* pChannelCallback, UINT32 message_id, UINT64 duration, UINT32 data_size); diff --git a/channels/tsmf/client/tsmf_media.c b/channels/tsmf/client/tsmf_media.c index 09b43efb8..2b1a57441 100644 --- a/channels/tsmf/client/tsmf_media.c +++ b/channels/tsmf/client/tsmf_media.c @@ -56,13 +56,23 @@ #define AUDIO_TOLERANCE 10000000LL +/* 1 second = 10,000,000 100ns units*/ +#define VIDEO_ADJUST_MAX 10*1000*1000 + +#define MAX_ACK_TIME 666667 + +#define AUDIO_MIN_BUFFER_LEVEL 3 +#define AUDIO_MAX_BUFFER_LEVEL 6 + +#define VIDEO_MIN_BUFFER_LEVEL 10 +#define VIDEO_MAX_BUFFER_LEVEL 30 + struct _TSMF_PRESENTATION { BYTE presentation_id[GUID_SIZE]; const char *audio_name; const char *audio_device; - int eos; IWTSVirtualChannelCallback *channel_callback; @@ -93,6 +103,9 @@ struct _TSMF_STREAM int major_type; int eos; + UINT32 eos_message_id; + IWTSVirtualChannelCallback* eos_channel_callback; + int delayed_stop; UINT32 width; UINT32 height; @@ -101,11 +114,17 @@ struct _TSMF_STREAM UINT32 channels; UINT32 bits_per_sample; + /* The start time of last played sample */ + UINT64 last_start_time; /* The end_time of last played sample */ UINT64 last_end_time; /* Next sample should not start before this system time. */ UINT64 next_start_time; + UINT32 minBufferLevel; + UINT32 maxBufferLevel; + UINT32 currentBufferLevel; + HANDLE play_thread; HANDLE ack_thread; HANDLE stopEvent; @@ -114,6 +133,8 @@ struct _TSMF_STREAM wQueue *sample_list; wQueue *sample_ack_list; rdpContext* rdpcontext; + + BOOL seeking; }; struct _TSMF_SAMPLE @@ -128,6 +149,8 @@ struct _TSMF_SAMPLE UINT32 decoded_size; UINT32 pixfmt; + BOOL invalidTimestamps; + TSMF_STREAM* stream; IWTSVirtualChannelCallback *channel_callback; UINT64 ack_time; @@ -170,7 +193,10 @@ static TSMF_SAMPLE* tsmf_stream_pop_sample(TSMF_STREAM* stream, int sync) if (stream->major_type == TSMF_MAJOR_TYPE_AUDIO) { /* Check if some other stream has earlier sample that needs to be played first */ - if (stream->last_end_time > AUDIO_TOLERANCE) + /* Start time is more reliable than end time as some stream types seem to have incorrect + * end times from the server + */ + if (stream->last_start_time > AUDIO_TOLERANCE) { ArrayList_Lock(presentation->stream_list); count = ArrayList_Count(presentation->stream_list); @@ -179,9 +205,13 @@ static TSMF_SAMPLE* tsmf_stream_pop_sample(TSMF_STREAM* stream, int sync) { s = (TSMF_STREAM *) ArrayList_GetItem(presentation->stream_list, index); - if (s != stream && !s->eos && s->last_end_time && - s->last_end_time < stream->last_end_time - AUDIO_TOLERANCE) + /* Start time is more reliable than end time as some stream types seem to have incorrect + * end times from the server + */ + if (s != stream && !s->eos && s->last_start_time && + s->last_start_time < stream->last_start_time - AUDIO_TOLERANCE) { + DEBUG_TSMF("Pending due to audio tolerance"); pending = TRUE; break; } @@ -192,8 +222,12 @@ static TSMF_SAMPLE* tsmf_stream_pop_sample(TSMF_STREAM* stream, int sync) } else { - if (stream->last_end_time > presentation->audio_end_time) + /* Start time is more reliable than end time as some stream types seem to have incorrect + * end times from the server + */ + if (stream->last_start_time > presentation->audio_start_time) { + DEBUG_TSMF("Pending due to stream start time > audio start time"); pending = TRUE; } } @@ -206,9 +240,14 @@ static TSMF_SAMPLE* tsmf_stream_pop_sample(TSMF_STREAM* stream, int sync) sample = (TSMF_SAMPLE *) Queue_Dequeue(stream->sample_list); - if (sample && (sample->end_time > stream->last_end_time)) + /* Only update stream last end time if the sample end time is valid and greater than the current stream end time */ + if (sample && (sample->end_time > stream->last_end_time) && (!sample->invalidTimestamps)) stream->last_end_time = sample->end_time; + /* Only update stream last start time if the sample start time is valid and greater than the current stream start time */ + if (sample && (sample->start_time > stream->last_start_time) && (!sample->invalidTimestamps)) + stream->last_start_time = sample->start_time; + return sample; } @@ -242,6 +281,9 @@ static BOOL tsmf_sample_queue_ack(TSMF_SAMPLE* sample) return Queue_Enqueue(sample->stream->sample_ack_list, sample); } +/* Returns TRUE if no more samples are currently available + * Returns FALSE otherwise + */ static BOOL tsmf_stream_process_ack(void* arg, BOOL force) { TSMF_STREAM* stream = arg; @@ -250,26 +292,42 @@ static BOOL tsmf_stream_process_ack(void* arg, BOOL force) BOOL rc = FALSE; if (!stream) - return FALSE; + return TRUE; Queue_Lock(stream->sample_ack_list); sample = (TSMF_SAMPLE*) Queue_Peek(stream->sample_ack_list); if (!sample) + { + rc = TRUE; goto finally; + } if (!force) { + /* Do some min/max ack limiting if we have access to Buffer level information */ + if (stream->decoder->BufferLevel) + { + /* Try to keep buffer level below max by withholding acks */ + if (stream->currentBufferLevel > stream->maxBufferLevel) + goto finally; + /* Try to keep buffer level above min by pushing acks through quickly */ + else if (stream->currentBufferLevel < stream->minBufferLevel) + goto dequeue; + } + + /* Time based acks only */ ack_time = get_current_time(); if (sample->ack_time > ack_time) goto finally; } +dequeue: sample = Queue_Dequeue(stream->sample_ack_list); if (sample) { - rc = tsmf_sample_ack(sample); + tsmf_sample_ack(sample); tsmf_sample_free(sample); } @@ -295,6 +353,7 @@ TSMF_PRESENTATION* tsmf_presentation_new(const BYTE* guid, IWTSVirtualChannelCal CopyMemory(presentation->presentation_id, guid, GUID_SIZE); presentation->channel_callback = pChannelCallback; presentation->volume = 5000; /* 50% */ + presentation->muted = 0; if (!(presentation->stream_list = ArrayList_New(TRUE))) goto error_stream_list; @@ -372,9 +431,12 @@ static BOOL tsmf_sample_playback_video(TSMF_SAMPLE* sample) { t = get_current_time(); + /* Start time is more reliable than end time as some stream types seem to have incorrect + * end times from the server + */ if (stream->next_start_time > t && - (sample->end_time >= presentation->audio_start_time || - sample->end_time < stream->last_end_time)) + ((sample->start_time >= presentation->audio_start_time) || + ((sample->start_time < stream->last_start_time) && (!sample->invalidTimestamps)))) { USleep((stream->next_start_time - t) / 10); } @@ -449,9 +511,15 @@ static BOOL tsmf_sample_playback_audio(TSMF_SAMPLE* sample) } sample->ack_time = latency + get_current_time(); - stream->last_end_time = sample->end_time + latency; - stream->presentation->audio_start_time = sample->start_time + latency; - stream->presentation->audio_end_time = sample->end_time + latency; + + /* Only update stream times if the sample timestamps are valid */ + if (!sample->invalidTimestamps) + { + stream->last_start_time = sample->start_time + latency; + stream->last_end_time = sample->end_time + latency; + stream->presentation->audio_start_time = sample->start_time + latency; + stream->presentation->audio_end_time = sample->end_time + latency; + } return ret; } @@ -467,6 +535,46 @@ static BOOL tsmf_sample_playback(TSMF_SAMPLE* sample) { if (stream->decoder->DecodeEx) { + /* Try to "sync" video buffers to audio buffers by looking at the running time for each stream + * The difference between the two running times causes an offset between audio and video actual + * render times. So, we try to adjust timestamps on the video buffer to match those on the audio buffer. + */ + if (stream->major_type == TSMF_MAJOR_TYPE_VIDEO) + { + TSMF_STREAM* temp_stream = NULL; + TSMF_PRESENTATION* presentation = stream->presentation; + ArrayList_Lock(presentation->stream_list); + int count = ArrayList_Count(presentation->stream_list); + int index = 0; + for (index = 0; index < count; index++) + { + UINT64 time_diff; + + temp_stream = (TSMF_STREAM*) ArrayList_GetItem(presentation->stream_list, index); + if (temp_stream->major_type == TSMF_MAJOR_TYPE_AUDIO) + { + UINT64 video_time = (UINT64) stream->decoder->GetRunningTime(stream->decoder); + UINT64 audio_time = (UINT64) temp_stream->decoder->GetRunningTime(temp_stream->decoder); + UINT64 max_adjust = VIDEO_ADJUST_MAX; + + if (video_time < audio_time) + max_adjust = -VIDEO_ADJUST_MAX; + + if (video_time > audio_time) + time_diff = video_time - audio_time; + else + time_diff = audio_time - video_time; + + time_diff = time_diff < VIDEO_ADJUST_MAX ? time_diff : max_adjust; + sample->start_time += time_diff; + sample->end_time += time_diff; + + break; + } + } + ArrayList_Unlock(presentation->stream_list); + } + ret = stream->decoder->DecodeEx(stream->decoder, sample->data, sample->data_size, sample->extensions, sample->start_time, sample->end_time, sample->duration); } @@ -478,9 +586,12 @@ static BOOL tsmf_sample_playback(TSMF_SAMPLE* sample) if (!ret) { - WLog_ERR(TAG, "decode error"); + WLog_ERR(TAG, "decode error, queue ack anyways"); if (!tsmf_sample_queue_ack(sample)) + { + WLog_ERR(TAG, "error queuing sample for ack"); return FALSE; + } return TRUE; } @@ -499,7 +610,7 @@ static BOOL tsmf_sample_playback(TSMF_SAMPLE* sample) WLog_ERR(TAG, "unable to decode video format"); if (!tsmf_sample_queue_ack(sample)) { - WLog_ERR(TAG, "error acking sample"); + WLog_ERR(TAG, "error queuing sample for ack"); } return FALSE; } @@ -507,8 +618,6 @@ static BOOL tsmf_sample_playback(TSMF_SAMPLE* sample) sample->pixfmt = pixfmt; } - ret = FALSE; - if (stream->decoder->GetDecodedDimension) { ret = stream->decoder->GetDecodedDimension(stream->decoder, &width, &height); @@ -543,54 +652,43 @@ static BOOL tsmf_sample_playback(TSMF_SAMPLE* sample) { TSMF_STREAM* stream = sample->stream; UINT64 ack_anticipation_time = get_current_time(); - UINT64 currentRunningTime = sample->start_time; BOOL buffer_filled = TRUE; - if (stream->decoder->GetRunningTime) + /* Classify the buffer as filled once it reaches minimum level */ + if (stream->decoder->BufferLevel) { - currentRunningTime = stream->decoder->GetRunningTime(stream->decoder); - } - - if (stream->decoder->BufferFilled) - { - buffer_filled = stream->decoder->BufferFilled(stream->decoder); + if (stream->currentBufferLevel < stream->minBufferLevel) + buffer_filled = FALSE; } if (buffer_filled) { - if (currentRunningTime > sample->start_time) - { - ack_anticipation_time += sample->duration; - } - else if (currentRunningTime == 0) - { - ack_anticipation_time += sample->duration; - } - else - { - ack_anticipation_time += (sample->start_time - currentRunningTime); - } + ack_anticipation_time += (sample->duration/2 < MAX_ACK_TIME) ? sample->duration/2 : MAX_ACK_TIME; } else { - ack_anticipation_time += sample->duration / 2; + ack_anticipation_time += (sample->duration/2 < MAX_ACK_TIME) ? sample->duration/2 : MAX_ACK_TIME; } switch (sample->stream->major_type) { case TSMF_MAJOR_TYPE_VIDEO: - { - break; - } + { + break; + } case TSMF_MAJOR_TYPE_AUDIO: - { - break; - } + { + break; + } } sample->ack_time = ack_anticipation_time; - ret = tsmf_sample_queue_ack(sample); + if (!tsmf_sample_queue_ack(sample)) + { + WLog_ERR(TAG, "error queuing sample for ack"); + ret = FALSE; + } } return ret; @@ -608,31 +706,63 @@ static void* tsmf_stream_ack_func(void *arg) while (1) { - DWORD ev = WaitForMultipleObjects(2, hdl, FALSE, INFINITE); + DWORD ev = WaitForMultipleObjects(2, hdl, FALSE, 1000); - if (ev == WAIT_FAILED) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %lu!", error); - break; - } - - if (ev == WAIT_OBJECT_0) - break; - - if (!stream->decoder) - continue; - - if (stream->decoder->SetAckFunc) - continue; - - if (tsmf_stream_process_ack(stream, FALSE)) + if (ev == WAIT_FAILED) { - error = ERROR_INTERNAL_ERROR; - WLog_ERR(TAG, "tsmf_stream_process_ack failed!"); + error = GetLastError(); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %lu!", error); break; } + if (stream->decoder) + if (stream->decoder->BufferLevel) + stream->currentBufferLevel = stream->decoder->BufferLevel(stream->decoder); + + if (stream->eos) + { + while ((stream->currentBufferLevel > 0) || !(tsmf_stream_process_ack(stream, TRUE))) + { + DEBUG_TSMF("END OF STREAM PROCESSING!"); + if (stream->decoder->BufferLevel) + stream->currentBufferLevel = stream->decoder->BufferLevel(stream->decoder); + else + stream->currentBufferLevel = 1; + + USleep(1000); + } + + tsmf_send_eos_response(stream->eos_channel_callback, stream->eos_message_id); + stream->eos = 0; + + if (stream->delayed_stop) + { + DEBUG_TSMF("Finishing delayed stream stop, now that eos has processed."); + tsmf_stream_flush(stream); + + if (stream->decoder->Control) + stream->decoder->Control(stream->decoder, Control_Stop, NULL); + } + } + + /* Stream stopped force all of the acks to happen */ + if (ev == WAIT_OBJECT_0) + { + DEBUG_TSMF("ack: Stream stopped!"); + while(1) + { + if (tsmf_stream_process_ack(stream, TRUE)) + break; + USleep(1000); + } + break; + } + + if (tsmf_stream_process_ack(stream, FALSE)) + continue; + + if (stream->currentBufferLevel > stream->minBufferLevel) + USleep(1000); } if (error && stream->rdpcontext) @@ -646,11 +776,11 @@ static void* tsmf_stream_ack_func(void *arg) static void* tsmf_stream_playback_func(void *arg) { HANDLE hdl[2]; - TSMF_SAMPLE* sample; + TSMF_SAMPLE* sample = NULL; TSMF_STREAM* stream = (TSMF_STREAM *) arg; TSMF_PRESENTATION* presentation = stream->presentation; UINT error = CHANNEL_RC_OK; - DWORD status; + DWORD status; DEBUG_TSMF("in %d", stream->stream_id); @@ -678,28 +808,32 @@ static void* tsmf_stream_playback_func(void *arg) while (1) { - status = WaitForMultipleObjects(2, hdl, FALSE, INFINITE); + status = WaitForMultipleObjects(2, hdl, FALSE, 1000); - if (status == WAIT_FAILED) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %lu!", error); - break; - } + if (status == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %lu!", error); + break; + } - status = WaitForSingleObject(stream->stopEvent, 0); + status = WaitForSingleObject(stream->stopEvent, 0); - if (status == WAIT_FAILED) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", error); - break; - } + if (status == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", error); + break; + } - if (status == WAIT_OBJECT_0) - break; + if (status == WAIT_OBJECT_0) + break; - sample = tsmf_stream_pop_sample(stream, 0); + if (stream->decoder) + if (stream->decoder->BufferLevel) + stream->currentBufferLevel = stream->decoder->BufferLevel(stream->decoder); + + sample = tsmf_stream_pop_sample(stream, 0); if (sample && !tsmf_sample_playback(sample)) { @@ -707,8 +841,12 @@ static void* tsmf_stream_playback_func(void *arg) error = ERROR_INTERNAL_ERROR; break; } + + if (stream->currentBufferLevel > stream->minBufferLevel) + USleep(1000); } + if (stream->audio) { stream->audio->Free(stream->audio); @@ -728,7 +866,9 @@ static BOOL tsmf_stream_start(TSMF_STREAM* stream) if (!stream || !stream->presentation || !stream->decoder || !stream->decoder->Control) return TRUE; - return stream->decoder->Control(stream->decoder, Control_Resume, NULL); + stream->eos = 0; + + return stream->decoder->Control(stream->decoder, Control_Restart, NULL); } static BOOL tsmf_stream_stop(TSMF_STREAM* stream) @@ -736,7 +876,24 @@ static BOOL tsmf_stream_stop(TSMF_STREAM* stream) if (!stream || !stream->decoder || !stream->decoder->Control) return TRUE; - return stream->decoder->Control(stream->decoder, Control_Stop, NULL); + /* If stopping after eos - we delay until the eos has been processed + * this allows us to process any buffers that have been acked even though + * they have not actually been completely processes by the decoder + */ + if (stream->eos) + { + DEBUG_TSMF("Setting up a delayed stop for once the eos has been processed."); + stream->delayed_stop = 1; + return TRUE; + } + /* Otherwise force stop immediately */ + else + { + DEBUG_TSMF("Stop with no pending eos response, so do it immediately."); + tsmf_stream_flush(stream); + + return stream->decoder->Control(stream->decoder, Control_Stop, NULL); + } } static BOOL tsmf_stream_pause(TSMF_STREAM* stream) @@ -752,7 +909,9 @@ static BOOL tsmf_stream_restart(TSMF_STREAM* stream) if (!stream || !stream->decoder || !stream->decoder->Control) return TRUE; - return stream->decoder->Control(stream->decoder, Control_Resume, NULL); + stream->eos = 0; + + return stream->decoder->Control(stream->decoder, Control_Restart, NULL); } static BOOL tsmf_stream_change_volume(TSMF_STREAM* stream, UINT32 newVolume, UINT32 muted) @@ -863,7 +1022,7 @@ UINT tsmf_presentation_sync(TSMF_PRESENTATION* presentation) { UINT32 index; UINT32 count; - UINT error; + UINT error; ArrayList_Lock(presentation->stream_list); count = ArrayList_Count(presentation->stream_list); @@ -872,15 +1031,15 @@ UINT tsmf_presentation_sync(TSMF_PRESENTATION* presentation) { TSMF_STREAM* stream = (TSMF_STREAM *) ArrayList_GetItem(presentation->stream_list, index); if (WaitForSingleObject(stream->ready, 500) == WAIT_FAILED) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", error); - return error; - } + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", error); + return error; + } } ArrayList_Unlock(presentation->stream_list); - return CHANNEL_RC_OK; + return CHANNEL_RC_OK; } BOOL tsmf_presentation_stop(TSMF_PRESENTATION* presentation) @@ -890,8 +1049,6 @@ BOOL tsmf_presentation_stop(TSMF_PRESENTATION* presentation) TSMF_STREAM* stream; BOOL ret = TRUE; - ret &= tsmf_presentation_flush(presentation); - ArrayList_Lock(presentation->stream_list); count = ArrayList_Count(presentation->stream_list); @@ -902,6 +1059,9 @@ BOOL tsmf_presentation_stop(TSMF_PRESENTATION* presentation) } ArrayList_Unlock(presentation->stream_list); + presentation->audio_start_time = 0; + presentation->audio_end_time = 0; + return ret; } @@ -911,33 +1071,26 @@ BOOL tsmf_presentation_set_geometry_info(TSMF_PRESENTATION* presentation, UINT32 index; UINT32 count; TSMF_STREAM* stream; - void *tmp_rects; + void *tmp_rects = NULL; BOOL ret = TRUE; - if (num_rects < 1 || !rects) - return TRUE; - /* The server may send messages with invalid width / height. * Ignore those messages. */ if (!width || !height) return TRUE; - if ((width == presentation->width) && (height == presentation->height) && - (x == presentation->x) && (y == presentation->y) && - (num_rects == presentation->nr_rects) && - (0 == memcmp(rects, presentation->rects, num_rects * sizeof(RDP_RECT)))) - { - return TRUE; - } + /* Streams can be added/removed from the presentation and the server will resend geometry info when a new stream is + * added to the presentation. Also, num_rects is used to indicate whether or not the window is visible. + * So, always process a valid message with unchanged position/size and/or no visibility rects. + */ presentation->x = x; presentation->y = y; presentation->width = width; presentation->height = height; - + tmp_rects = realloc(presentation->rects, sizeof(RDP_RECT) * num_rects); - if (!tmp_rects) - return FALSE; + presentation->nr_rects = num_rects; presentation->rects = tmp_rects; @@ -969,7 +1122,7 @@ void tsmf_presentation_set_audio_device(TSMF_PRESENTATION* presentation, const c presentation->audio_device = device; } -static BOOL tsmf_stream_flush(TSMF_STREAM* stream) +BOOL tsmf_stream_flush(TSMF_STREAM* stream) { BOOL ret = TRUE; @@ -979,6 +1132,9 @@ static BOOL tsmf_stream_flush(TSMF_STREAM* stream) ret = stream->audio->Flush(stream->audio); stream->eos = 0; + stream->eos_message_id = 0; + stream->eos_channel_callback = NULL; + stream->delayed_stop = 0; stream->last_end_time = 0; stream->next_start_time = 0; @@ -990,30 +1146,6 @@ static BOOL tsmf_stream_flush(TSMF_STREAM* stream) return TRUE; } -BOOL tsmf_presentation_flush(TSMF_PRESENTATION* presentation) -{ - UINT32 index; - UINT32 count; - TSMF_STREAM* stream; - BOOL ret = TRUE; - - 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); - ret &= tsmf_stream_flush(stream); - } - - ArrayList_Unlock(presentation->stream_list); - presentation->eos = 0; - presentation->audio_start_time = 0; - presentation->audio_end_time = 0; - - return ret; -} - void _tsmf_presentation_free(TSMF_PRESENTATION* presentation) { tsmf_presentation_stop(presentation); @@ -1049,6 +1181,14 @@ TSMF_STREAM* tsmf_stream_new(TSMF_PRESENTATION* presentation, UINT32 stream_id, return NULL; } + stream->minBufferLevel = VIDEO_MIN_BUFFER_LEVEL; + stream->maxBufferLevel = VIDEO_MAX_BUFFER_LEVEL; + stream->currentBufferLevel = 1; + + stream->seeking = FALSE; + stream->eos = 0; + stream->eos_message_id = 0; + stream->eos_channel_callback = NULL; stream->stream_id = stream_id; stream->presentation = presentation; stream->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); @@ -1083,11 +1223,11 @@ TSMF_STREAM* tsmf_stream_new(TSMF_PRESENTATION* presentation, UINT32 stream_id, error_add: SetEvent(stream->stopEvent); if (WaitForSingleObject(stream->ack_thread, INFINITE) == WAIT_FAILED) - WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", GetLastError()); + WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", GetLastError()); error_ack_thread: SetEvent(stream->stopEvent); if (WaitForSingleObject(stream->play_thread, INFINITE) == WAIT_FAILED) - WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", GetLastError()); + WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", GetLastError()); error_play_thread: Queue_Free(stream->sample_ack_list); error_sample_ack_list: @@ -1144,7 +1284,10 @@ BOOL tsmf_stream_set_format(TSMF_STREAM* stream, const char *name, wStream *s) } if (!tsmf_codec_parse_media_type(&mediatype, s)) + { + WLog_ERR(TAG, "unable to parse media type"); return FALSE; + } if (mediatype.MajorType == TSMF_MAJOR_TYPE_VIDEO) { @@ -1152,6 +1295,9 @@ BOOL tsmf_stream_set_format(TSMF_STREAM* stream, const char *name, wStream *s) mediatype.Width, mediatype.Height, mediatype.BitRate, (double) mediatype.SamplesPerSecond.Numerator / (double) mediatype.SamplesPerSecond.Denominator, mediatype.ExtraDataSize); + + stream->minBufferLevel = VIDEO_MIN_BUFFER_LEVEL; + stream->maxBufferLevel = VIDEO_MAX_BUFFER_LEVEL; } else if (mediatype.MajorType == TSMF_MAJOR_TYPE_AUDIO) { @@ -1164,6 +1310,9 @@ BOOL tsmf_stream_set_format(TSMF_STREAM* stream, const char *name, wStream *s) if (stream->bits_per_sample == 0) stream->bits_per_sample = 16; + + stream->minBufferLevel = AUDIO_MIN_BUFFER_LEVEL; + stream->maxBufferLevel = AUDIO_MAX_BUFFER_LEVEL; } stream->major_type = mediatype.MajorType; @@ -1183,13 +1332,14 @@ BOOL tsmf_stream_set_format(TSMF_STREAM* stream, const char *name, wStream *s) return ret; } -void tsmf_stream_end(TSMF_STREAM* stream) +void tsmf_stream_end(TSMF_STREAM* stream, UINT32 message_id, IWTSVirtualChannelCallback* pChannelCallback) { if (!stream) return; stream->eos = 1; - stream->presentation->eos = 1; + stream->eos_message_id = message_id; + stream->eos_channel_callback = pChannelCallback; } void _tsmf_stream_free(TSMF_STREAM* stream) @@ -1197,17 +1347,16 @@ void _tsmf_stream_free(TSMF_STREAM* stream) if (!stream) return; - if (tsmf_stream_stop(stream)) - tsmf_stream_flush(stream); + tsmf_stream_stop(stream); SetEvent(stream->stopEvent); if (stream->play_thread) { if (WaitForSingleObject(stream->play_thread, INFINITE) == WAIT_FAILED) - { - WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", GetLastError()); - return; - } + { + WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", GetLastError()); + return; + } CloseHandle(stream->play_thread); stream->play_thread = NULL; @@ -1216,10 +1365,10 @@ void _tsmf_stream_free(TSMF_STREAM* stream) if (stream->ack_thread) { if (WaitForSingleObject(stream->ack_thread, INFINITE) == WAIT_FAILED) - { - WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", GetLastError()); - return; - } + { + WLog_ERR(TAG, "WaitForSingleObject failed with error %lu!", GetLastError()); + return; + } CloseHandle(stream->ack_thread); stream->ack_thread = NULL; } @@ -1267,6 +1416,10 @@ BOOL tsmf_stream_push_sample(TSMF_STREAM* stream, IWTSVirtualChannelCallback *pC sample->end_time = end_time; sample->duration = duration; sample->extensions = extensions; + if ((sample->extensions & 0x00000080) || (sample->extensions & 0x00000040)) + sample->invalidTimestamps = TRUE; + else + sample->invalidTimestamps = FALSE; sample->stream = stream; sample->channel_callback = pChannelCallback; sample->data_size = data_size; diff --git a/channels/tsmf/client/tsmf_media.h b/channels/tsmf/client/tsmf_media.h index f697080f6..1760fe05a 100644 --- a/channels/tsmf/client/tsmf_media.h +++ b/channels/tsmf/client/tsmf_media.h @@ -49,14 +49,14 @@ BOOL tsmf_presentation_set_geometry_info(TSMF_PRESENTATION *presentation, int num_rects, RDP_RECT *rects); void tsmf_presentation_set_audio_device(TSMF_PRESENTATION *presentation, const char *name, const char *device); -BOOL tsmf_presentation_flush(TSMF_PRESENTATION *presentation); void tsmf_presentation_free(TSMF_PRESENTATION *presentation); TSMF_STREAM *tsmf_stream_new(TSMF_PRESENTATION *presentation, UINT32 stream_id, rdpContext* rdpcontext); TSMF_STREAM *tsmf_stream_find_by_id(TSMF_PRESENTATION *presentation, UINT32 stream_id); BOOL tsmf_stream_set_format(TSMF_STREAM *stream, const char *name, wStream *s); -void tsmf_stream_end(TSMF_STREAM *stream); +void tsmf_stream_end(TSMF_STREAM *stream, UINT32 message_id, IWTSVirtualChannelCallback* pChannelCallback); void tsmf_stream_free(TSMF_STREAM *stream); +BOOL tsmf_stream_flush(TSMF_STREAM* stream); BOOL tsmf_stream_push_sample(TSMF_STREAM *stream, IWTSVirtualChannelCallback *pChannelCallback, UINT32 sample_id, UINT64 start_time, UINT64 end_time, UINT64 duration, UINT32 extensions, diff --git a/channels/urbdrc/client/CMakeLists.txt b/channels/urbdrc/client/CMakeLists.txt index 5b0bc314a..5b2a831c0 100644 --- a/channels/urbdrc/client/CMakeLists.txt +++ b/channels/urbdrc/client/CMakeLists.txt @@ -48,7 +48,9 @@ set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) +if (WITH_DEBUG_SYMBOLS AND MSVC AND NOT STATIC_CHANNELS AND BUILD_SHARED_LIBS) + install(FILES ${CMAKE_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${FREERDP_ADDIN_PATH} COMPONENT symbols) +endif() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/urbdrc/client/libusb/CMakeLists.txt b/channels/urbdrc/client/libusb/CMakeLists.txt index 696523d17..84a857d07 100644 --- a/channels/urbdrc/client/libusb/CMakeLists.txt +++ b/channels/urbdrc/client/libusb/CMakeLists.txt @@ -44,5 +44,7 @@ set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) -install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH} EXPORT FreeRDPTargets) +if (WITH_DEBUG_SYMBOLS AND MSVC AND NOT STATIC_CHANNELS AND BUILD_SHARED_LIBS) + install(FILES ${CMAKE_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${FREERDP_ADDIN_PATH} COMPONENT symbols) +endif() diff --git a/channels/urbdrc/client/urbdrc_main.c b/channels/urbdrc/client/urbdrc_main.c index d69205d60..78cd77da0 100644 --- a/channels/urbdrc/client/urbdrc_main.c +++ b/channels/urbdrc/client/urbdrc_main.c @@ -1335,7 +1335,7 @@ static UINT urbdrc_on_close(IWTSVirtualChannelCallback * pChannelCallback) * @return 0 on success, otherwise a Win32 error code */ static UINT urbdrc_on_new_channel_connection(IWTSListenerCallback* pListenerCallback, - IWTSVirtualChannel * pChannel, BYTE* pData, int* pbAccept, IWTSVirtualChannelCallback** ppCallback) + IWTSVirtualChannel * pChannel, BYTE* pData, BOOL* pbAccept, IWTSVirtualChannelCallback** ppCallback) { URBDRC_LISTENER_CALLBACK* listener_callback = (URBDRC_LISTENER_CALLBACK*) pListenerCallback; URBDRC_CHANNEL_CALLBACK* callback; diff --git a/client/.gitignore b/client/.gitignore index e40f517bf..9ad5b74c0 100644 --- a/client/.gitignore +++ b/client/.gitignore @@ -9,3 +9,4 @@ !/X11 !/Wayland !/CMakeLists.txt +!*.in diff --git a/client/Android/.gitignore b/client/Android/.gitignore deleted file mode 100644 index 5eb07b8f5..000000000 --- a/client/Android/.gitignore +++ /dev/null @@ -1,15 +0,0 @@ -# Ignore directories -bin/ -obj/ -gen/ -jni/external/* -!libs -libs/armeabi* -AndroidManifest.xml -local.properties -!.project -appcompat_v7 - -FreeRDPCore/project.properties -FreeRDPCore/src/com/freerdp/freerdpcore/utils/BuildConfiguration.java -aFreeRDP/project.properties diff --git a/client/Android/CMakeLists.txt b/client/Android/CMakeLists.txt index 1ddef5ba6..d238eb6d2 100644 --- a/client/Android/CMakeLists.txt +++ b/client/Android/CMakeLists.txt @@ -1,6 +1,7 @@ # FreeRDP: A Remote Desktop Protocol Implementation # Android Client # +# Copyright 2012 Marc-Andre Moreau # Copyright 2013 Bernhard Miklautz # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,68 +16,39 @@ # See the License for the specific language governing permissions and # limitations under the License. -if (NOT ANDROID_NDK) - message(FATAL_ERROR "ANDROID_NDK not set but required for building android native library.") +set(MODULE_NAME "freerdp-android") +set(MODULE_PREFIX "FREERDP_CLIENT_ANDROID") + +include_directories(.) + +if(CMAKE_COMPILER_IS_GNUCC) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-pointer-sign") endif() -set(CMAKE_PROGRAM_PATH ${ANDROID_NDK}) -find_program(NDK_COMMAND ndk-build CMAKE_FIND_ROOT_PATH_BOTH) +set(${MODULE_PREFIX}_SRCS + android_event.c + android_event.h + android_freerdp.c + android_freerdp.h + android_jni_utils.c + android_jni_utils.h + android_jni_callback.c + android_jni_callback.h) -if(NDK_COMMAND STREQUAL "NDK_COMMAND-NOTFOUND") - message(FATAL_ERROR "ndk-build not found but required to build native lib") +if(WITH_CLIENT_CHANNELS) + set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} + android_cliprdr.c + android_cliprdr.h) endif() -set(NDK_LIB_CFG "${CMAKE_CURRENT_BINARY_DIR}/FreeRDPCore/jni/Android.mk") -if(ANDROID_BUILD_JAVA) - if (NOT ANDROID_SDK) - message(FATAL_ERROR "ANDROID_SDK not set but required for building the java gui (ANDROID_BUILD_JAVA)") - endif() - # And isn't shiped with the android ndk/sdk so - # we need to find it on the local machine - SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH) - find_program(ANT_COMMAND ant) - SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) +add_library(${MODULE_NAME} SHARED ${${MODULE_PREFIX}_SRCS}) - if(ANT_COMMAND STREQUAL "ANT_COMMAND-NOTFOUND") - message(FATAL_ERROR "ant not found but required to build android java") - endif() -endif(ANDROID_BUILD_JAVA) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-client) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp) -set(ANDROID_COMMAND "${ANDROID_SDK}/tools/android") -if(NOT EXISTS ${ANDROID_COMMAND}) - message(FATAL_ERROR "android not found but required to build android java") -endif() +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} dl) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} log) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} jnigraphics) -if(ANDROID_BUILD_JAVA_DEBUG) - set(ANDROID_BUILD_TYPE "debug") -else() - set(ANDROID_BUILD_TYPE "release") -endif() - -if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") - set(ANDROID_DEBUG_ENABLE "true") - set(NDK_DEBUG "1") -else() - set(ANDROID_DEBUG_ENABLE "false") - set(NDK_DEBUG "0") -endif() - -set(APPCOMPAT_DIR "${CMAKE_CURRENT_BINARY_DIR}/appcompat_v7") -set(supportdir "${ANDROID_SDK}/extras/android/support/v7/appcompat") -set(compatibilitydir "${ANDROID_SDK}/extras/android/compatibility/v7/appcompat") -if(EXISTS "${supportdir}" AND IS_DIRECTORY "${supportdir}") - add_custom_target(copy_appcompat ALL - COMMAND ${CMAKE_COMMAND} -E copy_directory "${supportdir}" ${APPCOMPAT_DIR} - COMMAND ${ANDROID_COMMAND} update lib-project -p ${APPCOMPAT_DIR} -t android-${ANDROID_APP_TARGET_SDK} - ) -elseif(EXISTS "${compatibilitydir}" AND IS_DIRECTORY "${compatibilitydir}") - add_custom_target(copy_appcompat ALL - COMMAND ${CMAKE_COMMAND} -E copy_directory "${compatibilitydir}" ${APPCOMPAT_DIR} - COMMAND ${ANDROID_COMMAND} update lib-project -p ${APPCOMPAT_DIR} -t android-${ANDROID_APP_TARGET_SDK} - ) -else() - message( FATAL_ERROR "${ANDROID_SDK}/extras/android/{support|compatibility}/v7/appcompat directory not found. Please install a recent version of Android Support Library, CMake will now exit." ) -endif() - -add_subdirectory(FreeRDPCore) -add_subdirectory(aFreeRDP) +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) +install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries EXPORT AndroidTargets) diff --git a/client/Android/FreeRDPCore/.classpath b/client/Android/FreeRDPCore/.classpath deleted file mode 100644 index 51769745b..000000000 --- a/client/Android/FreeRDPCore/.classpath +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/client/Android/FreeRDPCore/.gitignore b/client/Android/FreeRDPCore/.gitignore deleted file mode 100644 index 2d8df2acd..000000000 --- a/client/Android/FreeRDPCore/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -ant.properties -build.xml -jni/Android.mk -jni/Application.mk diff --git a/client/Android/FreeRDPCore/.project b/client/Android/FreeRDPCore/.project deleted file mode 100644 index bfc09afd1..000000000 --- a/client/Android/FreeRDPCore/.project +++ /dev/null @@ -1,53 +0,0 @@ - - - FreeRDPCore - - - - - - org.eclipse.ui.externaltools.ExternalToolBuilder - full,incremental, - - - LaunchConfigHandle - <project>/.externalToolBuilders/org.eclipse.cdt.managedbuilder.core.genmakebuilder.launch - - - - - com.android.ide.eclipse.adt.ResourceManagerBuilder - - - - - com.android.ide.eclipse.adt.PreCompilerBuilder - - - - - org.eclipse.jdt.core.javabuilder - - - - - com.android.ide.eclipse.adt.ApkBuilder - - - - - org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder - full,incremental, - - - - - - com.android.ide.eclipse.adt.AndroidNature - org.eclipse.jdt.core.javanature - org.eclipse.cdt.core.cnature - org.eclipse.cdt.core.ccnature - org.eclipse.cdt.managedbuilder.core.managedBuildNature - org.eclipse.cdt.managedbuilder.core.ScannerConfigNature - - diff --git a/client/Android/FreeRDPCore/CMakeLists.txt b/client/Android/FreeRDPCore/CMakeLists.txt deleted file mode 100644 index a95f11f2d..000000000 --- a/client/Android/FreeRDPCore/CMakeLists.txt +++ /dev/null @@ -1,48 +0,0 @@ -# FreeRDP: A Remote Desktop Protocol Implementation -# Android Client -# -# Copyright 2012 Marc-Andre Moreau -# Copyright 2013 Bernhard Miklautz -# -# 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. - -set(ANDROID_PACKAGE_NAME "aFreeRDPCore") - -CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/AndroidManifest.xml.cmake - ${CMAKE_CURRENT_BINARY_DIR}/AndroidManifest.xml @ONLY) -CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/build.xml.cmake - ${CMAKE_CURRENT_BINARY_DIR}/build.xml @ONLY) -CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/project.properties.cmake - ${CMAKE_CURRENT_BINARY_DIR}/project.properties @ONLY) -CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/ant.properties.cmake - ${CMAKE_CURRENT_BINARY_DIR}/ant.properties @ONLY) - -# Generate a Java class with static members set to the CMake -# configuration properties. -set(JAVA_CFG "src/com/freerdp/freerdpcore/utils/BuildConfiguration.java") -set(JAVA_CFG_OUT "${CMAKE_CURRENT_BINARY_DIR}/${JAVA_CFG}") -set(JAVA_CFG_IN "${CMAKE_CURRENT_SOURCE_DIR}/${JAVA_CFG}.in") - -CONFIGURE_FILE(${JAVA_CFG_IN} ${JAVA_CFG_OUT}) - -file(COPY res DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) - -if (ANDROID_SDK) - CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/local.properties.cmake - ${CMAKE_CURRENT_BINARY_DIR}/local.properties @ONLY) -endif() - -add_subdirectory(jni) - -SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "gen;bin;obj;libs") - diff --git a/client/Android/FreeRDPCore/ant.properties.cmake b/client/Android/FreeRDPCore/ant.properties.cmake deleted file mode 100644 index 83cd860ec..000000000 --- a/client/Android/FreeRDPCore/ant.properties.cmake +++ /dev/null @@ -1,20 +0,0 @@ -# This file is used to override default values used by the Ant build system. -# -# This file must be checked into Version Control Systems, as it is -# integral to the build system of your project. - -# This file is only used by the Ant script. - -# You can use this to override default values such as -# 'source.dir' for the location of your java source folder and -# 'out.dir' for the location of your output folder. - -# You can also use it define how the release builds are signed by declaring -# the following properties: -# 'key.store' for the location of your keystore and -# 'key.alias' for the name of the key to use. -# The password will be asked during the build when you use the 'release' target. -build.dir=@CMAKE_CURRENT_BINARY_DIR@ -source.path=@CMAKE_CURRENT_SOURCE_DIR@/src:@CMAKE_CURRENT_BINARY_DIR@/src -out.dir=@CMAKE_CURRENT_BINARY_DIR@/bin - diff --git a/client/Android/FreeRDPCore/build.xml.cmake b/client/Android/FreeRDPCore/build.xml.cmake deleted file mode 100644 index f07d7de42..000000000 --- a/client/Android/FreeRDPCore/build.xml.cmake +++ /dev/null @@ -1,92 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/client/Android/FreeRDPCore/jni/Android.mk.cmake b/client/Android/FreeRDPCore/jni/Android.mk.cmake deleted file mode 100644 index 94452ea92..000000000 --- a/client/Android/FreeRDPCore/jni/Android.mk.cmake +++ /dev/null @@ -1,8 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := freerdp-android -LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/libfreerdp-android.so -LOCAL_EXPORT_C_INCLUDES := ../../../../include -include $(PREBUILT_SHARED_LIBRARY) diff --git a/client/Android/FreeRDPCore/jni/Application.mk.cmake b/client/Android/FreeRDPCore/jni/Application.mk.cmake deleted file mode 100644 index 3655c4062..000000000 --- a/client/Android/FreeRDPCore/jni/Application.mk.cmake +++ /dev/null @@ -1 +0,0 @@ -APP_ABI := @ANDROID_ABI@ diff --git a/client/Android/FreeRDPCore/jni/CMakeLists.txt b/client/Android/FreeRDPCore/jni/CMakeLists.txt deleted file mode 100644 index 2b704b79d..000000000 --- a/client/Android/FreeRDPCore/jni/CMakeLists.txt +++ /dev/null @@ -1,73 +0,0 @@ -# FreeRDP: A Remote Desktop Protocol Implementation -# Android Client -# -# Copyright 2012 Marc-Andre Moreau -# Copyright 2013 Bernhard Miklautz -# -# 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. - -set(MODULE_NAME "freerdp-android") -set(MODULE_PREFIX "FREERDP_CLIENT_ANDROID") - -include_directories(.) -include_directories(generated) - -CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/Application.mk.cmake - ${CMAKE_CURRENT_BINARY_DIR}/Application.mk @ONLY) -CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/Android.mk.cmake - ${CMAKE_CURRENT_BINARY_DIR}/Android.mk @ONLY) - -if(CMAKE_COMPILER_IS_GNUCC) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-pointer-sign") -endif() - -set(${MODULE_PREFIX}_SRCS - android_debug.h - android_event.c - android_event.h - android_freerdp.c - android_freerdp.h - android_jni_utils.c - android_jni_utils.h - android_jni_callback.c - android_jni_callback.h) - -set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} - generated/android_freerdp_jni.c - generated/android_freerdp_jni.h) - -if(WITH_CLIENT_CHANNELS) - set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} - android_cliprdr.c - android_cliprdr.h) -endif() - -add_library(${MODULE_NAME} SHARED ${${MODULE_PREFIX}_SRCS}) - -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-client) -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp) - -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} dl) -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} log) -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} jnigraphics) - -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) - -file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${ANDROID_ABI}") -set_target_properties(${MODULE_NAME} - PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${ANDROID_ABI}") - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Client/Android") - -get_property(LIB_ABSNAME TARGET ${MODULE_NAME} PROPERTY LOCATION) - diff --git a/client/Android/FreeRDPCore/jni/android_debug.h b/client/Android/FreeRDPCore/jni/android_debug.h deleted file mode 100644 index b48e7f469..000000000 --- a/client/Android/FreeRDPCore/jni/android_debug.h +++ /dev/null @@ -1,31 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * Android Debug Interface - * - * Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -#ifndef FREERDP_ANDROID_DEBUG_H -#define FREERDP_ANDROID_DEBUG_H - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#define ANDROID_TAG CLIENT_TAG("android") -#ifdef WITH_DEBUG_ANDROID_JNI -#define DEBUG_ANDROID(fmt, ...) WLog_DBG(ANDROID_TAG, fmt, ## __VA_ARGS__) -#else -#define DEBUG_ANDROID(fmt, ...) do { } while (0) -#endif - - - -#endif /* FREERDP_ANDROID_DEBUG_H */ - diff --git a/client/Android/FreeRDPCore/jni/android_freerdp.c b/client/Android/FreeRDPCore/jni/android_freerdp.c deleted file mode 100644 index 01bc19122..000000000 --- a/client/Android/FreeRDPCore/jni/android_freerdp.c +++ /dev/null @@ -1,1290 +0,0 @@ -/* - Android JNI Client Layer - - Copyright 2010-2012 Marc-Andre Moreau - Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - Copyright 2013 Thincast Technologies GmbH, Author: Armin Novak - Copyright 2015 Bernhard Miklautz - - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "android_freerdp.h" -#include "android_jni_callback.h" -#include "android_jni_utils.h" -#include "android_debug.h" -#include "android_cliprdr.h" - -#if defined(WITH_GPROF) -#include "jni/prof.h" -#endif - - -static BOOL android_context_new(freerdp* instance, rdpContext* context) -{ - if (!(context->channels = freerdp_channels_new())) - return FALSE; - - if (!android_event_queue_init(instance)) - { - freerdp_channels_free(context->channels); - return FALSE; - } - return TRUE; -} - -static void android_context_free(freerdp* instance, rdpContext* context) -{ - if (context && context->channels) - { - freerdp_channels_close(context->channels, instance); - freerdp_channels_free(context->channels); - context->channels = NULL; - } - android_event_queue_uninit(instance); -} - -static void android_OnChannelConnectedEventHandler(rdpContext* context, ChannelConnectedEventArgs* e) -{ - rdpSettings* settings = context->settings; - androidContext* afc = (androidContext*) context; - - if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) - { - DEBUG_ANDROID("Unhandled case.. RDPEI_DVC_CHANNEL_NAME"); - } - else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) - { - if (settings->SoftwareGdi) - gdi_graphics_pipeline_init(context->gdi, (RdpgfxClientContext*) e->pInterface); - } - else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) - { - android_cliprdr_init(afc, (CliprdrClientContext*) e->pInterface); - } -} - -static void android_OnChannelDisconnectedEventHandler(rdpContext* context, ChannelDisconnectedEventArgs* e) -{ - rdpSettings* settings = context->settings; - androidContext* afc = (androidContext*) context; - - if (strcmp(e->name, RDPEI_DVC_CHANNEL_NAME) == 0) - { - DEBUG_ANDROID("Unhandled case.. RDPEI_DVC_CHANNEL_NAME"); - } - else if (strcmp(e->name, RDPGFX_DVC_CHANNEL_NAME) == 0) - { - if (settings->SoftwareGdi) - gdi_graphics_pipeline_uninit(context->gdi, (RdpgfxClientContext*) e->pInterface); - } - else if (strcmp(e->name, CLIPRDR_SVC_CHANNEL_NAME) == 0) - { - android_cliprdr_uninit(afc, (CliprdrClientContext*) e->pInterface); - } -} - -static BOOL android_begin_paint(rdpContext* context) -{ - rdpGdi* gdi = context->gdi; - gdi->primary->hdc->hwnd->invalid->null = 1; - gdi->primary->hdc->hwnd->ninvalid = 0; - return TRUE; -} - -static BOOL android_end_paint(rdpContext* context) -{ - int i; - int ninvalid; - HGDI_RGN cinvalid; - int x1, y1, x2, y2; - androidContext *ctx = (androidContext*)context; - rdpSettings* settings = context->instance->settings; - - assert(ctx); - assert(settings); - assert(context->instance); - - ninvalid = ctx->rdpCtx.gdi->primary->hdc->hwnd->ninvalid; - if (ninvalid == 0) - { - DEBUG_ANDROID("ui_update: ninvalid=%d", ninvalid); - return TRUE; - } - - cinvalid = ctx->rdpCtx.gdi->primary->hdc->hwnd->cinvalid; - - x1 = cinvalid[0].x; - y1 = cinvalid[0].y; - x2 = cinvalid[0].x + cinvalid[0].w; - y2 = cinvalid[0].y + cinvalid[0].h; - - for (i = 0; i < ninvalid; i++) - { - x1 = MIN(x1, cinvalid[i].x); - y1 = MIN(y1, cinvalid[i].y); - x2 = MAX(x2, cinvalid[i].x + cinvalid[i].w); - y2 = MAX(y2, cinvalid[i].y + cinvalid[i].h); - } - - DEBUG_ANDROID("ui_update: ninvalid=%d x=%d, y=%d, width=%d, height=%d, bpp=%d", - ninvalid, x1, y1, x2 - x1, y2 - y1, settings->ColorDepth); - - freerdp_callback("OnGraphicsUpdate", "(IIIII)V", context->instance, - x1, y1, x2 - x1, y2 - y1); - return TRUE; -} - -static BOOL android_desktop_resize(rdpContext* context) -{ - DEBUG_ANDROID("ui_desktop_resize"); - - assert(context); - assert(context->settings); - assert(context->instance); - - freerdp_callback("OnGraphicsResize", "(IIII)V", - context->instance, context->settings->DesktopWidth, - context->settings->DesktopHeight, context->settings->ColorDepth); - return TRUE; -} - -static BOOL android_pre_connect(freerdp* instance) -{ - DEBUG_ANDROID("android_pre_connect"); - - rdpSettings* settings = instance->settings; - BOOL bitmap_cache = settings->BitmapCacheEnabled; - settings->OrderSupport[NEG_DSTBLT_INDEX] = TRUE; - settings->OrderSupport[NEG_PATBLT_INDEX] = TRUE; - settings->OrderSupport[NEG_SCRBLT_INDEX] = TRUE; - settings->OrderSupport[NEG_OPAQUE_RECT_INDEX] = TRUE; - settings->OrderSupport[NEG_DRAWNINEGRID_INDEX] = FALSE; - settings->OrderSupport[NEG_MULTIDSTBLT_INDEX] = FALSE; - settings->OrderSupport[NEG_MULTIPATBLT_INDEX] = FALSE; - settings->OrderSupport[NEG_MULTISCRBLT_INDEX] = FALSE; - settings->OrderSupport[NEG_MULTIOPAQUERECT_INDEX] = TRUE; - settings->OrderSupport[NEG_MULTI_DRAWNINEGRID_INDEX] = FALSE; - settings->OrderSupport[NEG_LINETO_INDEX] = TRUE; - settings->OrderSupport[NEG_POLYLINE_INDEX] = TRUE; - settings->OrderSupport[NEG_MEMBLT_INDEX] = bitmap_cache; - settings->OrderSupport[NEG_MEM3BLT_INDEX] = TRUE; - settings->OrderSupport[NEG_MEMBLT_V2_INDEX] = bitmap_cache; - settings->OrderSupport[NEG_MEM3BLT_V2_INDEX] = FALSE; - settings->OrderSupport[NEG_SAVEBITMAP_INDEX] = FALSE; - settings->OrderSupport[NEG_GLYPH_INDEX_INDEX] = TRUE; - settings->OrderSupport[NEG_FAST_INDEX_INDEX] = TRUE; - settings->OrderSupport[NEG_FAST_GLYPH_INDEX] = TRUE; - settings->OrderSupport[NEG_POLYGON_SC_INDEX] = FALSE; - settings->OrderSupport[NEG_POLYGON_CB_INDEX] = FALSE; - settings->OrderSupport[NEG_ELLIPSE_SC_INDEX] = FALSE; - settings->OrderSupport[NEG_ELLIPSE_CB_INDEX] = FALSE; - - settings->FrameAcknowledge = 10; - - PubSub_SubscribeChannelConnected(instance->context->pubSub, - (pChannelConnectedEventHandler) android_OnChannelConnectedEventHandler); - - PubSub_SubscribeChannelDisconnected(instance->context->pubSub, - (pChannelDisconnectedEventHandler) android_OnChannelDisconnectedEventHandler); - - freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0); - freerdp_client_load_addins(instance->context->channels, instance->settings); - - freerdp_channels_pre_connect(instance->context->channels, instance); - - return TRUE; -} - -static BOOL android_post_connect(freerdp* instance) -{ - UINT32 gdi_flags; - rdpSettings *settings = instance->settings; - - DEBUG_ANDROID("android_post_connect"); - - assert(instance); - assert(settings); - - freerdp_callback("OnSettingsChanged", "(IIII)V", instance, - settings->DesktopWidth, settings->DesktopHeight, - settings->ColorDepth); - - if (!(instance->context->cache = cache_new(settings))) - return FALSE; - - if (instance->settings->ColorDepth > 16) - gdi_flags = CLRBUF_32BPP | CLRCONV_ALPHA | CLRCONV_INVERT; - else - gdi_flags = CLRBUF_16BPP; - - if (!gdi_init(instance, gdi_flags, NULL)) - return FALSE; - - instance->update->BeginPaint = android_begin_paint; - instance->update->EndPaint = android_end_paint; - instance->update->DesktopResize = android_desktop_resize; - - if (freerdp_channels_post_connect(instance->context->channels, instance) < 0) - return FALSE; - - freerdp_callback("OnConnectionSuccess", "(I)V", instance); - - return TRUE; -} - -static void android_post_disconnect(freerdp* instance) -{ - DEBUG_ANDROID("android_post_disconnect"); - gdi_free(instance); - cache_free(instance->context->cache); -} - -static BOOL android_authenticate(freerdp* instance, char** username, char** password, char** domain) -{ - DEBUG_ANDROID("Authenticate user:"); - DEBUG_ANDROID(" Username: %s", *username); - DEBUG_ANDROID(" Domain: %s", *domain); - - JNIEnv* env; - jboolean attached = jni_attach_thread(&env); - jobject jstr1 = create_string_builder(env, *username); - jobject jstr2 = create_string_builder(env, *domain); - jobject jstr3 = create_string_builder(env, *password); - - jboolean res = freerdp_callback_bool_result("OnAuthenticate", "(ILjava/lang/StringBuilder;Ljava/lang/StringBuilder;Ljava/lang/StringBuilder;)Z", instance, jstr1, jstr2, jstr3); - - if (res == JNI_TRUE) - { - // read back string values - free(*username); - *username = get_string_from_string_builder(env, jstr1); - - free(*domain); - *domain = get_string_from_string_builder(env, jstr2); - - free(*password); - *password = get_string_from_string_builder(env, jstr3); - } - - if (attached == JNI_TRUE) - jni_detach_thread(); - - return ((res == JNI_TRUE) ? TRUE : FALSE); -} - -static BOOL android_verify_certificate(freerdp* instance, char* subject, char* issuer, char* fingerprint) -{ - DEBUG_ANDROID("Certificate details:"); - DEBUG_ANDROID("\tSubject: %s", subject); - DEBUG_ANDROID("\tIssuer: %s", issuer); - DEBUG_ANDROID("\tThumbprint: %s", fingerprint); - DEBUG_ANDROID("The above X.509 certificate could not be verified, possibly because you do not have " - "the CA certificate in your certificate store, or the certificate has expired." - "Please look at the documentation on how to create local certificate store for a private CA.\n"); - - JNIEnv* env; - jboolean attached = jni_attach_thread(&env); - jstring jstr1 = (*env)->NewStringUTF(env, subject); - jstring jstr2 = (*env)->NewStringUTF(env, issuer); - jstring jstr3 = (*env)->NewStringUTF(env, fingerprint); - - jboolean res = freerdp_callback_bool_result("OnVerifyCertificate", "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z", instance, jstr1, jstr2, jstr3); - - if (attached == JNI_TRUE) - jni_detach_thread(); - - return ((res == JNI_TRUE) ? TRUE : FALSE); -} - -static BOOL android_verify_changed_certificate(freerdp* instance, char* subject, char* issuer, - char* new_fingerprint, char* old_subject, char* old_issuer, char* old_fingerprint) -{ - return android_verify_certificate(instance, subject, issuer, new_fingerprint); -} - -static void* jni_input_thread(void* arg) -{ - HANDLE event[3]; - wMessageQueue* queue; - freerdp* instance = (freerdp*) arg; - androidContext *aCtx = (androidContext*)instance->context; - - assert(NULL != instance); - assert(NULL != aCtx); - - DEBUG_ANDROID("input_thread Start."); - - if (!(queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE))) - goto fail_get_message_queue; - - if (!(event[0] = CreateFileDescriptorEvent(NULL, FALSE, FALSE, - aCtx->event_queue->pipe_fd[0], WINPR_FD_READ))) - goto fail_create_event_0; - - if (!(event[1] = CreateFileDescriptorEvent(NULL, FALSE, FALSE, - aCtx->event_queue->pipe_fd[1], WINPR_FD_READ))) - goto fail_create_event_1; - - if (!(event[2] = freerdp_get_message_queue_event_handle(instance, FREERDP_INPUT_MESSAGE_QUEUE))) - goto fail_get_message_queue_event; - - do - { - DWORD rc = WaitForMultipleObjects(3, event, FALSE, INFINITE); - if ((rc < WAIT_OBJECT_0) || (rc > WAIT_OBJECT_0 + 2)) - continue; - - if (rc == WAIT_OBJECT_0 + 2) - { - wMessage msg; - - MessageQueue_Peek(queue, &msg, FALSE); - if (msg.id == WMQ_QUIT) - break; - } - if (android_check_fds(instance) != TRUE) - break; - } - while(1); - - DEBUG_ANDROID("input_thread Quit."); - -fail_get_message_queue_event: - CloseHandle(event[1]); -fail_create_event_1: - CloseHandle(event[0]); -fail_create_event_0: - MessageQueue_PostQuit(queue, 0); -fail_get_message_queue: - - ExitThread(0); - return NULL; -} - -static void* jni_channels_thread(void* arg) -{ - int status; - HANDLE event; - rdpChannels* channels; - freerdp* instance = (freerdp*) arg; - - assert(NULL != instance); - - DEBUG_ANDROID("Channels_thread Start."); - - channels = instance->context->channels; - event = freerdp_channels_get_event_handle(instance); - - while (WaitForSingleObject(event, INFINITE) == WAIT_OBJECT_0) - { - status = freerdp_channels_process_pending_messages(instance); - - if (!status) - break; - } - - DEBUG_ANDROID("channels_thread Quit."); - - ExitThread(0); - return NULL; -} - -static int android_freerdp_run(freerdp* instance) -{ - int i; - int fds; - int max_fds; - int rcount; - int wcount; - int fd_input_event; - HANDLE input_event = NULL; - void* rfds[32]; - void* wfds[32]; - fd_set rfds_set; - fd_set wfds_set; - int select_status; - struct timeval timeout; - - const rdpSettings* settings = instance->context->settings; - - HANDLE input_thread = NULL; - HANDLE channels_thread = NULL; - - BOOL async_input = settings->AsyncInput; - BOOL async_channels = settings->AsyncChannels; - BOOL async_transport = settings->AsyncTransport; - - DEBUG_ANDROID("AsyncUpdate=%d", settings->AsyncUpdate); - DEBUG_ANDROID("AsyncInput=%d", settings->AsyncInput); - DEBUG_ANDROID("AsyncChannels=%d", settings->AsyncChannels); - DEBUG_ANDROID("AsyncTransport=%d", settings->AsyncTransport); - - memset(rfds, 0, sizeof(rfds)); - memset(wfds, 0, sizeof(wfds)); - - if (!freerdp_connect(instance)) - { - freerdp_callback("OnConnectionFailure", "(I)V", instance); - return 0; - } - - if (async_input) - { - if (!(input_thread = CreateThread(NULL, 0, - (LPTHREAD_START_ROUTINE) jni_input_thread, instance, 0, NULL))) - { - DEBUG_ANDROID("Failed to create async input thread\n"); - goto disconnect; - } - } - - if (async_channels) - { - if (!(channels_thread = CreateThread(NULL, 0, - (LPTHREAD_START_ROUTINE) jni_channels_thread, instance, 0, NULL))) - { - DEBUG_ANDROID("Failed to create async channels thread\n"); - goto disconnect; - } - } - - ((androidContext*)instance->context)->is_connected = TRUE; - while (!freerdp_shall_disconnect(instance)) - { - rcount = 0; - wcount = 0; - - if (!async_transport) - { - if (freerdp_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE) - { - DEBUG_ANDROID("Failed to get FreeRDP file descriptor\n"); - break; - } - } - - if (!async_channels) - { - if (freerdp_channels_get_fds(instance->context->channels, instance, rfds, &rcount, wfds, &wcount) != TRUE) - { - DEBUG_ANDROID("Failed to get channel manager file descriptor\n"); - break; - } - } - - if (!async_input) - { - if (android_get_fds(instance, rfds, &rcount, wfds, &wcount) != TRUE) - { - DEBUG_ANDROID("Failed to get android file descriptor\n"); - break; - } - } - else - { - input_event = freerdp_get_message_queue_event_handle(instance, FREERDP_INPUT_MESSAGE_QUEUE); - fd_input_event = GetEventFileDescriptor(input_event); - rfds[rcount++] = (void*) (long) fd_input_event; - } - - 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; - - timeout.tv_sec = 1; - timeout.tv_usec = 0; - - select_status = select(max_fds + 1, &rfds_set, NULL, NULL, &timeout); - - if (select_status == 0) - continue; - else if (select_status == -1) - { - /* these are not really errors */ - if (!((errno == EAGAIN) || - (errno == EWOULDBLOCK) || - (errno == EINPROGRESS) || - (errno == EINTR))) /* signal occurred */ - { - DEBUG_ANDROID("android_run: select failed\n"); - break; - } - } - - if (freerdp_shall_disconnect(instance)) - break; - - if (!async_transport) - { - if (freerdp_check_fds(instance) != TRUE) - { - DEBUG_ANDROID("Failed to check FreeRDP file descriptor\n"); - break; - } - } - - if (!async_input) - { - if (android_check_fds(instance) != TRUE) - { - DEBUG_ANDROID("Failed to check android file descriptor\n"); - break; - } - } - else if (input_event) - { - if (WaitForSingleObject(input_event, 0) == WAIT_OBJECT_0) - { - if (!freerdp_message_queue_process_pending_messages(instance, - FREERDP_INPUT_MESSAGE_QUEUE)) - { - DEBUG_ANDROID("User Disconnect"); - break; - } - } - } - - if (!async_channels) - { - if (freerdp_channels_check_fds(instance->context->channels, instance) != TRUE) - { - DEBUG_ANDROID("Failed to check channel manager file descriptor\n"); - break; - } - } - } - -disconnect: - DEBUG_ANDROID("Prepare shutdown..."); - - // issue another OnDisconnecting here in case the disconnect was initiated by the server and not our client - freerdp_callback("OnDisconnecting", "(I)V", instance); - - DEBUG_ANDROID("Close channels..."); - freerdp_channels_disconnect(instance->context->channels, instance); - - DEBUG_ANDROID("Cleanup threads..."); - - if (async_channels && channels_thread) - { - WaitForSingleObject(channels_thread, INFINITE); - CloseHandle(channels_thread); - } - - if (async_input && input_thread) - { - wMessageQueue* input_queue = freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE); - if (input_queue) - { - if (MessageQueue_PostQuit(input_queue, 0)) - WaitForSingleObject(input_thread, INFINITE); - } - CloseHandle(input_thread); - } - - DEBUG_ANDROID("run Disconnecting..."); - freerdp_disconnect(instance); - freerdp_callback("OnDisconnected", "(I)V", instance); - - DEBUG_ANDROID("run Quit."); - - return 0; -} - -static void* android_thread_func(void* param) -{ - freerdp* instance = param; - - DEBUG_ANDROID("android_thread_func Start."); - - assert(instance); - - android_freerdp_run(instance); - - DEBUG_ANDROID("android_thread_func Quit."); - - ExitThread(0); - return NULL; -} - -JNIEXPORT jint JNICALL jni_freerdp_new(JNIEnv *env, jclass cls) -{ - freerdp* instance; - -#if defined(WITH_GPROF) - setenv("CPUPROFILE_FREQUENCY", "200", 1); - monstartup("libfreerdp-android.so"); -#endif - - // create instance - if (!(instance = freerdp_new())) - return (jint)NULL; - instance->PreConnect = android_pre_connect; - instance->PostConnect = android_post_connect; - instance->PostDisconnect = android_post_disconnect; - instance->Authenticate = android_authenticate; - instance->VerifyCertificate = android_verify_certificate; - instance->VerifyChangedCertificate = android_verify_changed_certificate; - - // create context - instance->ContextSize = sizeof(androidContext); - instance->ContextNew = android_context_new; - instance->ContextFree = android_context_free; - - if (!freerdp_context_new(instance)) - { - freerdp_free(instance); - instance = NULL; - } - - return (jint) instance; -} - -JNIEXPORT void JNICALL jni_freerdp_free(JNIEnv *env, jclass cls, jint instance) -{ - freerdp* inst = (freerdp*)instance; - - freerdp_context_free(inst); - freerdp_free(inst); - -#if defined(WITH_GPROF) - moncleanup(); -#endif -} - -JNIEXPORT jboolean JNICALL jni_freerdp_connect(JNIEnv *env, jclass cls, jint instance) -{ - freerdp* inst = (freerdp*)instance; - androidContext* ctx = (androidContext*)inst->context; - - assert(inst); - assert(ctx); - - if (!(ctx->thread = CreateThread(NULL, 0, - (LPTHREAD_START_ROUTINE)android_thread_func, inst, 0, NULL))) - { - return JNI_FALSE; - } - - return JNI_TRUE; -} - -JNIEXPORT jboolean JNICALL jni_freerdp_disconnect(JNIEnv *env, jclass cls, jint instance) -{ - freerdp* inst = (freerdp*)instance; - androidContext* ctx = (androidContext*)inst->context; - ANDROID_EVENT* event = (ANDROID_EVENT*)android_event_disconnect_new(); - if (!event) - return JNI_FALSE; - - DEBUG_ANDROID("DISCONNECT!"); - - assert(inst); - assert(ctx); - assert(event); - - if (!android_push_event(inst, event)) - { - android_event_disconnect_free(event); - return JNI_FALSE; - } - - WaitForSingleObject(ctx->thread, INFINITE); - CloseHandle(ctx->thread); - ctx->thread = NULL; - - freerdp_callback("OnDisconnecting", "(I)V", instance); - - return (jboolean) JNI_TRUE; -} - -JNIEXPORT jboolean JNICALL jni_freerdp_cancel_connection(JNIEnv *env, jclass cls, jint instance) -{ - return jni_freerdp_disconnect(env, cls, instance); -} - -JNIEXPORT jboolean JNICALL jni_freerdp_set_data_directory(JNIEnv *env, jclass cls, jint instance, jstring jdirectory) -{ - freerdp* inst = (freerdp*)instance; - rdpSettings * settings = inst->settings; - - const jbyte* directory = (*env)->GetStringUTFChars(env, jdirectory, NULL); - if (!directory) - return JNI_FALSE; - - free(settings->HomePath); - free(settings->ConfigPath); - settings->HomePath = settings->ConfigPath = NULL; - - int config_dir_len = strlen(directory) + 10; /* +9 chars for /.freerdp and +1 for \0 */ - char* config_dir_buf = (char*)malloc(config_dir_len); - if (!config_dir_buf) - goto out_malloc_fail; - - strcpy(config_dir_buf, directory); - strcat(config_dir_buf, "/.freerdp"); - settings->HomePath = strdup(directory); - if (!settings->HomePath) - goto out_strdup_fail; - settings->ConfigPath = config_dir_buf; /* will be freed by freerdp library */ - - (*env)->ReleaseStringUTFChars(env, jdirectory, directory); - return JNI_TRUE; - -out_strdup_fail: - free(config_dir_buf); -out_malloc_fail: - (*env)->ReleaseStringUTFChars(env, jdirectory, directory); - return JNI_FALSE; - -} - -JNIEXPORT jboolean JNICALL jni_freerdp_set_connection_info(JNIEnv *env, jclass cls, jint instance, - jstring jhostname, jstring jusername, jstring jpassword, jstring jdomain, jint width, jint height, - jint color_depth, jint port, jboolean console, jint security, jstring jcertname) -{ - freerdp* inst = (freerdp*)instance; - rdpSettings * settings = inst->settings; - - const jbyte *hostname; - const jbyte *username; - const jbyte *password; - const jbyte *domain; - const jbyte *certname; - - if(!(hostname = (*env)->GetStringUTFChars(env, jhostname, NULL))) - return JNI_FALSE; - if (!(username = (*env)->GetStringUTFChars(env, jusername, NULL))) - goto out_fail_username; - if (!(password = (*env)->GetStringUTFChars(env, jpassword, NULL))) - goto out_fail_password; - if (!(domain = (*env)->GetStringUTFChars(env, jdomain, NULL))) - goto out_fail_domain; - if (!(certname = (*env)->GetStringUTFChars(env, jcertname, NULL))) - goto out_fail_certname; - - - DEBUG_ANDROID("hostname: %s", (char*) hostname); - DEBUG_ANDROID("username: %s", (char*) username); - DEBUG_ANDROID("password: %s", (char*) password); - DEBUG_ANDROID("domain: %s", (char*) domain); - DEBUG_ANDROID("width: %d", width); - DEBUG_ANDROID("height: %d", height); - DEBUG_ANDROID("color depth: %d", color_depth); - DEBUG_ANDROID("port: %d", port); - DEBUG_ANDROID("security: %d", security); - - settings->DesktopWidth = width; - settings->DesktopHeight = height; - settings->ColorDepth = color_depth; - settings->ServerPort = port; - - // Hack for 16 bit RDVH connections: - // In this case we get screen corruptions when we have an odd screen resolution width ... need to investigate what is causing this... - if (color_depth <= 16) - settings->DesktopWidth &= (~1); - - if (!(settings->ServerHostname = strdup(hostname))) - goto out_fail_strdup; - - if (username && strlen(username) > 0) - { - if (!(settings->Username = strdup(username))) - goto out_fail_strdup; - } - - if (password && strlen(password) > 0) - { - if (!(settings->Password = strdup(password))) - goto out_fail_strdup; - settings->AutoLogonEnabled = TRUE; - } - - if (!(settings->Domain = strdup(domain))) - goto out_fail_strdup; - - if (certname && strlen(certname) > 0) - { - if (!(settings->CertificateName = strdup(certname))) - goto out_fail_strdup; - } - - settings->ConsoleSession = (console == JNI_TRUE) ? TRUE : FALSE; - - settings->SoftwareGdi = TRUE; - settings->BitmapCacheV3Enabled = TRUE; - - switch ((int) security) - { - case 1: - /* Standard RDP */ - settings->RdpSecurity = TRUE; - settings->TlsSecurity = FALSE; - settings->NlaSecurity = FALSE; - settings->ExtSecurity = FALSE; - settings->UseRdpSecurityLayer = TRUE; - break; - - case 2: - /* TLS */ - settings->NlaSecurity = FALSE; - settings->TlsSecurity = TRUE; - settings->RdpSecurity = FALSE; - settings->ExtSecurity = FALSE; - break; - - case 3: - /* NLA */ - settings->NlaSecurity = TRUE; - settings->TlsSecurity = FALSE; - settings->RdpSecurity = FALSE; - settings->ExtSecurity = FALSE; - break; - - default: - break; - } - - // set US keyboard layout - settings->KeyboardLayout = 0x0409; - - (*env)->ReleaseStringUTFChars(env, jhostname, hostname); - (*env)->ReleaseStringUTFChars(env, jusername, username); - (*env)->ReleaseStringUTFChars(env, jpassword, password); - (*env)->ReleaseStringUTFChars(env, jdomain, domain); - (*env)->ReleaseStringUTFChars(env, jcertname, certname); - - return JNI_TRUE; - - -out_fail_strdup: - (*env)->ReleaseStringUTFChars(env, jcertname, certname); -out_fail_certname: - (*env)->ReleaseStringUTFChars(env, jdomain, domain); -out_fail_domain: - (*env)->ReleaseStringUTFChars(env, jpassword, password); -out_fail_password: - (*env)->ReleaseStringUTFChars(env, jusername, username); -out_fail_username: - (*env)->ReleaseStringUTFChars(env, jhostname, hostname); - return JNI_FALSE; -} - -JNIEXPORT void JNICALL jni_freerdp_set_performance_flags( - JNIEnv *env, jclass cls, jint instance, jboolean remotefx, - jboolean disableWallpaper, jboolean disableFullWindowDrag, - jboolean disableMenuAnimations, jboolean disableTheming, - jboolean enableFontSmoothing, jboolean enableDesktopComposition) -{ - freerdp* inst = (freerdp*)instance; - rdpSettings * settings = inst->settings; - - DEBUG_ANDROID("remotefx: %d", (remotefx == JNI_TRUE) ? 1 : 0); - if (remotefx == JNI_TRUE) - { - settings->RemoteFxCodec = TRUE; - settings->FastPathOutput = TRUE; - settings->ColorDepth = 32; - settings->LargePointerFlag = TRUE; - settings->FrameMarkerCommandEnabled = TRUE; - } - else - { - /* enable NSCodec if we don't use remotefx */ - settings->NSCodec = TRUE; - } - - /* store performance settings */ - settings->DisableWallpaper = (disableWallpaper == JNI_TRUE) ? TRUE : FALSE; - settings->DisableFullWindowDrag = (disableFullWindowDrag == JNI_TRUE) ? TRUE : FALSE; - settings->DisableMenuAnims = (disableMenuAnimations == JNI_TRUE) ? TRUE : FALSE; - settings->DisableThemes = (disableTheming == JNI_TRUE) ? TRUE : FALSE; - settings->AllowFontSmoothing = (enableFontSmoothing == JNI_TRUE) ? TRUE : FALSE; - settings->AllowDesktopComposition = (enableDesktopComposition == JNI_TRUE) ? TRUE : FALSE; - - /* Create performance flags from settings */ - freerdp_performance_flags_make(settings); - - DEBUG_ANDROID("performance_flags: %04X", settings->PerformanceFlags); -} - -JNIEXPORT jboolean JNICALL jni_freerdp_set_advanced_settings(JNIEnv *env, jclass cls, - jint instance, jstring jRemoteProgram, jstring jWorkDir, - jboolean async_channel, jboolean async_transport, jboolean async_input, - jboolean async_update) -{ - freerdp* inst = (freerdp*)instance; - rdpSettings * settings = inst->settings; - jboolean ret = JNI_FALSE; - - const jbyte *remote_program; - const jbyte *work_dir; - - if (!(remote_program = (*env)->GetStringUTFChars(env, jRemoteProgram, NULL))) - return JNI_FALSE; - - if (!(work_dir = (*env)->GetStringUTFChars(env, jWorkDir, NULL))) - goto out_fail_work_dir; - - DEBUG_ANDROID("Remote Program: %s", (char*) remote_program); - DEBUG_ANDROID("Work Dir: %s", (char*) work_dir); - - /* Enable async mode. */ - settings->AsyncUpdate = async_update; - settings->AsyncChannels = async_channel; - settings->AsyncTransport = async_transport; - settings->AsyncInput = async_input; - - if (remote_program && strlen(remote_program) > 0) - { - if (!(settings->AlternateShell = strdup(remote_program))) - goto out_fail_strdup; - } - - if (work_dir && strlen(work_dir) > 0) - { - if (!(settings->ShellWorkingDirectory = strdup(work_dir))) - goto out_fail_strdup; - } - - ret = JNI_TRUE; - -out_fail_strdup: - (*env)->ReleaseStringUTFChars(env, jWorkDir, work_dir); -out_fail_work_dir: - (*env)->ReleaseStringUTFChars(env, jRemoteProgram, remote_program); - return ret; -} - -JNIEXPORT jboolean JNICALL jni_freerdp_set_drive_redirection(JNIEnv *env, jclass cls, jint instance, jstring jpath) -{ - freerdp* inst = (freerdp*)instance; - rdpSettings * settings = inst->settings; - char* args[] = {"drive", "Android", ""}; - jboolean ret = JNI_FALSE; - - const jbyte *path = (*env)->GetStringUTFChars(env, jpath, NULL); - if (!path) - return JNI_FALSE; - DEBUG_ANDROID("drive redirect: %s", (char*)path); - - args[2] = (char*)path; - if (freerdp_client_add_device_channel(settings, 3, args) == -1) - { - settings->DeviceRedirection = FALSE; - goto out_fail; - } - - settings->DeviceRedirection = TRUE; - - ret = JNI_TRUE; -out_fail: - (*env)->ReleaseStringUTFChars(env, jpath, path); - return ret; -} - -JNIEXPORT jboolean JNICALL jni_freerdp_set_sound_redirection(JNIEnv *env, - jclass cls, jint instance, jint redirect) -{ - freerdp* inst = (freerdp*)instance; - rdpSettings * settings = inst->settings; - - DEBUG_ANDROID("sound: %s", - redirect ? ((redirect == 1) ? "Server" : "Redirect") : "None"); - - settings->AudioPlayback = (redirect == 2) ? TRUE : FALSE; - if (settings->AudioPlayback) - { - int ret; - char* p[1] = {"rdpsnd"}; - int count = 1; - - ret = freerdp_client_add_static_channel(settings, count, p); - - if(ret == -1) - return JNI_FALSE; - } - settings->RemoteConsoleAudio = (redirect == 1) ? TRUE : FALSE; - return JNI_TRUE; -} - -JNIEXPORT jboolean JNICALL jni_freerdp_set_microphone_redirection(JNIEnv *env, - jclass cls, jint instance, jboolean enable) -{ - freerdp* inst = (freerdp*)instance; - rdpSettings * settings = inst->settings; - - DEBUG_ANDROID("microphone redirect: %s", enable ? "TRUE" : "FALSE"); - - settings->AudioCapture = enable; - if (enable) - { - int ret; - char* p[1] = {"audin"}; - int count = 1; - - ret = freerdp_client_add_dynamic_channel(settings, count, p); - - if (ret == -1) - return JNI_FALSE; - - } - return JNI_TRUE; -} - -JNIEXPORT void JNICALL jni_freerdp_set_clipboard_redirection(JNIEnv *env, jclass cls, jint instance, jboolean enable) -{ - freerdp* inst = (freerdp*)instance; - rdpSettings * settings = inst->settings; - - DEBUG_ANDROID("clipboard redirect: %s", enable ? "TRUE" : "FALSE"); - - settings->RedirectClipboard = enable ? TRUE : FALSE; -} - -JNIEXPORT jboolean JNICALL jni_freerdp_set_gateway_info(JNIEnv *env, jclass cls, jint instance, jstring jgatewayhostname, jint port, - jstring jgatewayusername, jstring jgatewaypassword, jstring jgatewaydomain) -{ - freerdp* inst = (freerdp*)instance; - rdpSettings * settings = inst->settings; - jboolean ret = JNI_FALSE; - - const jbyte *gatewayhostname; - const jbyte *gatewayusername; - const jbyte *gatewaypassword; - const jbyte *gatewaydomain; - - if (!(gatewayhostname = (*env)->GetStringUTFChars(env, jgatewayhostname, NULL))) - return JNI_FALSE; - if (!(gatewayusername = (*env)->GetStringUTFChars(env, jgatewayusername, NULL))) - goto out_fail_username; - if (!(gatewaypassword = (*env)->GetStringUTFChars(env, jgatewaypassword, NULL))) - goto out_fail_password; - if (!(gatewaydomain = (*env)->GetStringUTFChars(env, jgatewaydomain, NULL))) - goto out_fail_domain; - - DEBUG_ANDROID("gatewayhostname: %s", (char*) gatewayhostname); - DEBUG_ANDROID("gatewayport: %d", port); - DEBUG_ANDROID("gatewayusername: %s", (char*) gatewayusername); - DEBUG_ANDROID("gatewaypassword: %s", (char*) gatewaypassword); - DEBUG_ANDROID("gatewaydomain: %s", (char*) gatewaydomain); - - settings->GatewayPort = port; - settings->GatewayUsageMethod = TSC_PROXY_MODE_DIRECT; - settings->GatewayEnabled = TRUE; - settings->GatewayUseSameCredentials = FALSE; - settings->GatewayHostname = strdup(gatewayhostname); - settings->GatewayUsername = strdup(gatewayusername); - settings->GatewayPassword = strdup(gatewaypassword); - settings->GatewayDomain = strdup(gatewaydomain); - if (!settings->GatewayHostname || !settings->GatewayUsername || - !settings->GatewayPassword || !settings->GatewayDomain) - { - goto out_fail_strdup; - } - - - ret = JNI_TRUE; - -out_fail_strdup: - (*env)->ReleaseStringUTFChars(env, jgatewaydomain, gatewaydomain); -out_fail_domain: - (*env)->ReleaseStringUTFChars(env, jgatewaypassword, gatewaypassword); -out_fail_password: - (*env)->ReleaseStringUTFChars(env, jgatewayusername, gatewayusername); -out_fail_username: - (*env)->ReleaseStringUTFChars(env, jgatewayhostname, gatewayhostname); - - return ret; -} - -static void copy_pixel_buffer(UINT8* dstBuf, UINT8* srcBuf, int x, int y, int width, int height, int wBuf, int hBuf, int bpp) -{ - int i; - int length; - int scanline; - UINT8 *dstp, *srcp; - - length = width * bpp; - scanline = wBuf * bpp; - - srcp = (UINT8*) &srcBuf[(scanline * y) + (x * bpp)]; - dstp = (UINT8*) &dstBuf[(scanline * y) + (x * bpp)]; - - for (i = 0; i < height; i++) - { - memcpy(dstp, srcp, length); - srcp += scanline; - dstp += scanline; - } -} - -JNIEXPORT jboolean JNICALL jni_freerdp_update_graphics( - JNIEnv *env, jclass cls, jint instance, jobject bitmap, jint x, jint y, jint width, jint height) -{ - - int ret; - void* pixels; - AndroidBitmapInfo info; - freerdp* inst = (freerdp*)instance; - rdpGdi *gdi = inst->context->gdi; - - if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) - { - DEBUG_ANDROID("AndroidBitmap_getInfo() failed ! error=%d", ret); - return JNI_FALSE; - } - - if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) - { - DEBUG_ANDROID("AndroidBitmap_lockPixels() failed ! error=%d", ret); - return JNI_FALSE; - } - - copy_pixel_buffer(pixels, gdi->primary_buffer, x, y, width, height, gdi->width, gdi->height, gdi->bytesPerPixel); - - AndroidBitmap_unlockPixels(env, bitmap); - - return JNI_TRUE; -} - -JNIEXPORT jboolean JNICALL jni_freerdp_send_key_event( - JNIEnv *env, jclass cls, jint instance, jint keycode, jboolean down) -{ - DWORD scancode; - ANDROID_EVENT* event; - - freerdp* inst = (freerdp*)instance; - - scancode = GetVirtualScanCodeFromVirtualKeyCode(keycode, 4); - int flags = (down == JNI_TRUE) ? KBD_FLAGS_DOWN : KBD_FLAGS_RELEASE; - flags |= (scancode & KBDEXT) ? KBD_FLAGS_EXTENDED : 0; - event = (ANDROID_EVENT*) android_event_key_new(flags, scancode & 0xFF); - if (!event) - return JNI_FALSE; - - if (!android_push_event(inst, event)) - { - android_event_key_free((ANDROID_EVENT_KEY *)event); - return JNI_FALSE; - } - - DEBUG_ANDROID("send_key_event: %d, %d", (int)scancode, flags); - return JNI_TRUE; -} - -JNIEXPORT jboolean JNICALL jni_freerdp_send_unicodekey_event( - JNIEnv *env, jclass cls, jint instance, jint keycode) -{ - ANDROID_EVENT* event; - - freerdp* inst = (freerdp*)instance; - event = (ANDROID_EVENT*) android_event_unicodekey_new(keycode); - if (!event) - return JNI_FALSE; - if (!android_push_event(inst, event)) - { - android_event_unicodekey_free((ANDROID_EVENT_KEY *)event); - return JNI_FALSE; - } - - DEBUG_ANDROID("send_unicodekey_event: %d", keycode); - return JNI_TRUE; -} - -JNIEXPORT jboolean JNICALL jni_freerdp_send_cursor_event( - JNIEnv *env, jclass cls, jint instance, jint x, jint y, jint flags) -{ - ANDROID_EVENT* event; - - freerdp* inst = (freerdp*)instance; - event = (ANDROID_EVENT*) android_event_cursor_new(flags, x, y); - if (!event) - return JNI_FALSE; - - if (!android_push_event(inst, event)) - { - android_event_cursor_free((ANDROID_EVENT_CURSOR *)event); - return JNI_FALSE; - } - - DEBUG_ANDROID("send_cursor_event: (%d, %d), %d", x, y, flags); - return JNI_TRUE; -} - -JNIEXPORT jboolean JNICALL jni_freerdp_send_clipboard_data(JNIEnv *env, jclass cls, jint instance, jstring jdata) -{ - ANDROID_EVENT* event; - freerdp* inst = (freerdp*)instance; - const jbyte *data = jdata != NULL ? (*env)->GetStringUTFChars(env, jdata, NULL) : NULL; - int data_length = data ? strlen(data) : 0; - jboolean ret = JNI_FALSE;; - - event = (ANDROID_EVENT*) android_event_clipboard_new((void*)data, data_length); - if (!event) - goto out_fail; - - if (!android_push_event(inst, event)) - { - android_event_clipboard_free((ANDROID_EVENT_CLIPBOARD *)event); - goto out_fail; - } - - DEBUG_ANDROID("send_clipboard_data: (%s)", data); - - ret = JNI_TRUE; -out_fail: - if (data) - (*env)->ReleaseStringUTFChars(env, jdata, data); - return ret; -} - -JNIEXPORT jstring JNICALL jni_freerdp_get_version(JNIEnv *env, jclass cls) -{ - return (*env)->NewStringUTF(env, GIT_REVISION); -} diff --git a/client/Android/FreeRDPCore/jni/android_freerdp.h b/client/Android/FreeRDPCore/jni/android_freerdp.h deleted file mode 100644 index d6f5f4dfe..000000000 --- a/client/Android/FreeRDPCore/jni/android_freerdp.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - Android JNI Client Layer - - Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -*/ - -#ifndef __ANDROID_FREERDP_H -#define __ANDROID_FREERDP_H - -#include - -#include -#include - -#include -#include - -#include "android_event.h" - -struct android_context -{ - rdpContext rdpCtx; - - ANDROID_EVENT_QUEUE* event_queue; - HANDLE thread; - - BOOL is_connected; - - BOOL clipboardSync; - wClipboard* clipboard; - UINT32 numServerFormats; - UINT32 requestedFormatId; - HANDLE clipboardRequestEvent; - CLIPRDR_FORMAT* serverFormats; - CliprdrClientContext* cliprdr; - UINT32 clipboardCapabilities; -}; -typedef struct android_context androidContext; - -JNIEXPORT jint JNICALL jni_freerdp_new(JNIEnv *env, jclass cls); -JNIEXPORT void JNICALL jni_freerdp_free(JNIEnv *env, jclass cls, jint instance); -JNIEXPORT jboolean JNICALL jni_freerdp_connect(JNIEnv *env, jclass cls, jint instance); -JNIEXPORT jboolean JNICALL jni_freerdp_disconnect(JNIEnv *env, jclass cls, jint instance); -JNIEXPORT jboolean JNICALL jni_freerdp_cancel_connection(JNIEnv *env, jclass cls, jint instance); -JNIEXPORT jboolean JNICALL jni_freerdp_set_connection_info(JNIEnv *env, jclass cls, jint instance, - jstring jhostname, jstring jusername, jstring jpassword, jstring jdomain, jint width, - jint height, jint color_depth, jint port, jboolean console, jint security, jstring jcertname); -JNIEXPORT void JNICALL jni_freerdp_set_performance_flags(JNIEnv *env, jclass cls, jint instance, jboolean remotefx, jboolean disableWallpaper, jboolean disableFullWindowDrag, - jboolean disableMenuAnimations, jboolean disableTheming, jboolean enableFontSmoothing, jboolean enableDesktopComposition); -JNIEXPORT jboolean JNICALL jni_freerdp_set_advanced_settings(JNIEnv *env, jclass cls, - jint instance, jstring jRemoteProgram, jstring jWorkDir, - jboolean async_channel, jboolean async_transport, jboolean async_input, - jboolean async_update); -JNIEXPORT jboolean JNICALL jni_freerdp_set_drive_redirection(JNIEnv *env, jclass cls, jint instance, jstring jpath); -JNIEXPORT jboolean JNICALL jni_freerdp_set_sound_redirection(JNIEnv *env, jclass cls, jint instance, jint redirect); -JNIEXPORT jboolean JNICALL jni_freerdp_set_microphone_redirection(JNIEnv *env, jclass cls, jint instance, jboolean enable); -JNIEXPORT void JNICALL jni_freerdp_set_clipboard_redirection(JNIEnv *env, jclass cls, jint instance, jboolean enable); -JNIEXPORT jboolean JNICALL jni_freerdp_set_gateway_info(JNIEnv *env, jclass cls, jint instance, jstring jgatewayhostname, jint port, jstring jgatewayusername, jstring jgatewaypassword, jstring jgatewaydomain); -JNIEXPORT jboolean JNICALL jni_freerdp_set_data_directory(JNIEnv *env, jclass cls, jint instance, jstring jdirectory); -JNIEXPORT jboolean JNICALL jni_freerdp_update_graphics(JNIEnv *env, jclass cls, jint instance, jobject bitmap, jint x, jint y, jint width, jint height); -JNIEXPORT jboolean JNICALL jni_freerdp_send_cursor_event(JNIEnv *env, jclass cls, jint instance, jint x, jint y, jint flags); -JNIEXPORT jboolean JNICALL jni_freerdp_send_key_event(JNIEnv *env, jclass cls, jint instance, jint keycode, jboolean down); -JNIEXPORT jboolean JNICALL jni_freerdp_send_unicodekey_event(JNIEnv *env, jclass cls, jint instance, jint keycode); -JNIEXPORT jboolean JNICALL jni_freerdp_send_clipboard_data(JNIEnv *env, jclass cls, jint instance, jstring jdata); -JNIEXPORT jstring JNICALL jni_freerdp_get_version(JNIEnv *env, jclass cls); - -#endif /* __ANDROID_FREERDP_H */ - diff --git a/client/Android/FreeRDPCore/jni/generated/android_freerdp_jni.c b/client/Android/FreeRDPCore/jni/generated/android_freerdp_jni.c deleted file mode 100644 index 77b9137fb..000000000 --- a/client/Android/FreeRDPCore/jni/generated/android_freerdp_jni.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - FreeRDP: A Remote Desktop Protocol client. - Android JNI Bindings and Native Code - - Copyright 2010 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. -*/ - -#include "android_freerdp.h" -#include "android_freerdp_jni.h" - -JNIEXPORT jint JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1new(JNIEnv *env, jclass cls) -{ - return jni_freerdp_new(env, cls); -} - -JNIEXPORT void JNICALL JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1free(JNIEnv *env, jclass cls, jint instance) -{ - jni_freerdp_free(env, cls, instance); -} - -JNIEXPORT jboolean JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1connect(JNIEnv *env, jclass cls, jint instance) -{ - return jni_freerdp_connect(env, cls, instance); -} - -JNIEXPORT jboolean JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1disconnect(JNIEnv *env, jclass cls, jint instance) -{ - return jni_freerdp_disconnect(env, cls, instance); -} - -JNIEXPORT jboolean JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1cancel_1connection(JNIEnv *env, jclass cls, jint instance) -{ - return jni_freerdp_cancel_connection(env, cls, instance); -} - -JNIEXPORT jboolean JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1set_1connection_1info(JNIEnv *env, jclass cls, jint instance, - jstring jhostname, jstring jusername, jstring jpassword, jstring jdomain, jint width, jint height, jint color_depth, jint port, - jboolean console, jint security, jstring certname) -{ - return jni_freerdp_set_connection_info(env, cls, instance, jhostname, jusername, jpassword, jdomain, - width, height, color_depth, port, console, security, certname); -} - -JNIEXPORT jboolean JNICALL -Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1set_1advanced_1settings( - JNIEnv *env, jclass cls, jint instance, jstring remote_program, jstring work_dir, - jboolean async_channel, jboolean async_transport, jboolean async_input, - jboolean async_update) -{ - return jni_freerdp_set_advanced_settings(env, cls, instance, remote_program, work_dir, - async_channel, async_transport, async_input, async_update); -} - -JNIEXPORT jboolean JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1set_1data_1directory(JNIEnv *env, jclass cls, jint instance, jstring directory) -{ - return jni_freerdp_set_data_directory(env, cls, instance, directory); -} - -JNIEXPORT void JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1set_1performance_1flags( - JNIEnv *env, jclass cls, jint instance, jboolean remotefx, jboolean disableWallpaper, jboolean disableFullWindowDrag, - jboolean disableMenuAnimations, jboolean disableTheming, jboolean enableFontSmoothing, jboolean enableDesktopComposition) -{ - jni_freerdp_set_performance_flags(env, cls, instance, remotefx, disableWallpaper, disableFullWindowDrag, disableMenuAnimations, disableTheming, enableFontSmoothing, enableDesktopComposition); -} - -JNIEXPORT void JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1set_1clipboard_1redirection - (JNIEnv *env, jclass cls, jint inst, jboolean enable) -{ - jni_freerdp_set_clipboard_redirection(env, cls, inst, enable); -} - -JNIEXPORT jboolean JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1set_1sound_1redirection - (JNIEnv *env, jclass cls, jint inst, jint redirect) -{ - return jni_freerdp_set_sound_redirection(env, cls, inst, redirect); -} - -JNIEXPORT jboolean JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1set_1microphone_1redirection - (JNIEnv *env, jclass cls, jint inst, jboolean redirect) -{ - return jni_freerdp_set_microphone_redirection(env, cls, inst, redirect); -} - -JNIEXPORT jboolean JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1set_1drive_1redirection - (JNIEnv *env, jclass cls, jint inst, jstring path) -{ - return jni_freerdp_set_drive_redirection(env, cls, inst, path); -} - -JNIEXPORT jboolean JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1set_1gateway_1info - (JNIEnv *env, jclass cls, jint inst, jstring hostname, jint port, jstring username, jstring password, jstring domain) -{ - return jni_freerdp_set_gateway_info(env, cls, inst, hostname, port, username, password, domain); -} - -JNIEXPORT jboolean JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1update_1graphics( - JNIEnv *env, jclass cls, jint instance, jobject bitmap, jint x, jint y, jint width, jint height) -{ - return jni_freerdp_update_graphics(env, cls, instance, bitmap, x, y, width, height); -} - -JNIEXPORT jboolean JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1send_1cursor_1event( - JNIEnv *env, jclass cls, jint instance, jint x, jint y, jint flags) -{ - return jni_freerdp_send_cursor_event(env, cls, instance, x, y, flags); -} - -JNIEXPORT jboolean JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1send_1key_1event( - JNIEnv *env, jclass cls, jint instance, jint keycode, jboolean down) -{ - return jni_freerdp_send_key_event(env, cls, instance, keycode, down); -} - -JNIEXPORT jboolean JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1send_1unicodekey_1event - (JNIEnv *env, jclass cls, jint instance, jint keycode) -{ - return jni_freerdp_send_unicodekey_event(env, cls, instance, keycode); -} - -JNIEXPORT jboolean JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1send_1clipboard_1data - (JNIEnv *env, jclass cls, jint instance, jstring data) -{ - return jni_freerdp_send_clipboard_data(env, cls, instance, data); -} - -JNIEXPORT jstring JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1get_1version(JNIEnv *env, jclass cls) -{ - return jni_freerdp_get_version(env, cls); -} - diff --git a/client/Android/FreeRDPCore/jni/generated/com_freerdp_freerdpcore_services_LibFreeRDP.h b/client/Android/FreeRDPCore/jni/generated/com_freerdp_freerdpcore_services_LibFreeRDP.h deleted file mode 100644 index 50b0c74f8..000000000 --- a/client/Android/FreeRDPCore/jni/generated/com_freerdp_freerdpcore_services_LibFreeRDP.h +++ /dev/null @@ -1,173 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class com_freerdp_freerdpcore_services_LibFreeRDP */ - -#ifndef _Included_com_freerdp_freerdpcore_services_LibFreeRDP -#define _Included_com_freerdp_freerdpcore_services_LibFreeRDP -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: com_freerdp_freerdpcore_services_LibFreeRDP - * Method: freerdp_new - * Signature: ()I - */ -JNIEXPORT jint JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1new - (JNIEnv *, jclass); - -/* - * Class: com_freerdp_freerdpcore_services_LibFreeRDP - * Method: freerdp_free - * Signature: (I)V - */ -JNIEXPORT void JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1free - (JNIEnv *, jclass, jint); - -/* - * Class: com_freerdp_freerdpcore_services_LibFreeRDP - * Method: freerdp_connect - * Signature: (I)Z - */ -JNIEXPORT jboolean JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1connect - (JNIEnv *, jclass, jint); - -/* - * Class: com_freerdp_freerdpcore_services_LibFreeRDP - * Method: freerdp_disconnect - * Signature: (I)Z - */ -JNIEXPORT jboolean JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1disconnect - (JNIEnv *, jclass, jint); - -/* - * Class: com_freerdp_freerdpcore_services_LibFreeRDP - * Method: freerdp_cancel_connection - * Signature: (I)Z - */ -JNIEXPORT jboolean JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1cancel_1connection - (JNIEnv *, jclass, jint); - -/* - * Class: com_freerdp_freerdpcore_services_LibFreeRDP - * Method: freerdp_set_connection_info - * Signature: (ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IIIIZILjava/lang/String;)Z - */ -JNIEXPORT jboolean JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1set_1connection_1info - (JNIEnv *, jclass, jint, jstring, jstring, jstring, jstring, jint, jint, jint, jint, jboolean, jint, jstring); - -/* - * Class: com_freerdp_freerdpcore_services_LibFreeRDP - * Method: freerdp_set_performance_flags - * Signature: (IZZZZZZZ)V - */ -JNIEXPORT void JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1set_1performance_1flags - (JNIEnv *, jclass, jint, jboolean, jboolean, jboolean, jboolean, jboolean, jboolean, jboolean); - -/* - * Class: com_freerdp_freerdpcore_services_LibFreeRDP - * Method: freerdp_set_advanced_settings - * Signature: (ILjava/lang/String;Ljava/lang/String;ZZZZ)Z - */ -JNIEXPORT jboolean JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1set_1advanced_1settings - (JNIEnv *, jclass, jint, jstring, jstring, jboolean, jboolean, jboolean, jboolean); - -/* - * Class: com_freerdp_freerdpcore_services_LibFreeRDP - * Method: freerdp_set_data_directory - * Signature: (ILjava/lang/String;)Z - */ -JNIEXPORT jboolean JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1set_1data_1directory - (JNIEnv *, jclass, jint, jstring); - -/* - * Class: com_freerdp_freerdpcore_services_LibFreeRDP - * Method: freerdp_set_clipboard_redirection - * Signature: (IZ)V - */ -JNIEXPORT void JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1set_1clipboard_1redirection - (JNIEnv *, jclass, jint, jboolean); - -/* - * Class: com_freerdp_freerdpcore_services_LibFreeRDP - * Method: freerdp_set_sound_redirection - * Signature: (II)Z - */ -JNIEXPORT jboolean JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1set_1sound_1redirection - (JNIEnv *, jclass, jint, jint); - -/* - * Class: com_freerdp_freerdpcore_services_LibFreeRDP - * Method: freerdp_set_microphone_redirection - * Signature: (IZ)Z - */ -JNIEXPORT jboolean JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1set_1microphone_1redirection - (JNIEnv *, jclass, jint, jboolean); - -/* - * Class: com_freerdp_freerdpcore_services_LibFreeRDP - * Method: freerdp_set_drive_redirection - * Signature: (ILjava/lang/String;)Z - */ -JNIEXPORT jboolean JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1set_1drive_1redirection - (JNIEnv *, jclass, jint, jstring); - -/* - * Class: com_freerdp_freerdpcore_services_LibFreeRDP - * Method: freerdp_set_gateway_info - * Signature: (ILjava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z - */ -JNIEXPORT jboolean JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1set_1gateway_1info - (JNIEnv *, jclass, jint, jstring, jint, jstring, jstring, jstring); - -/* - * Class: com_freerdp_freerdpcore_services_LibFreeRDP - * Method: freerdp_update_graphics - * Signature: (ILandroid/graphics/Bitmap;IIII)Z - */ -JNIEXPORT jboolean JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1update_1graphics - (JNIEnv *, jclass, jint, jobject, jint, jint, jint, jint); - -/* - * Class: com_freerdp_freerdpcore_services_LibFreeRDP - * Method: freerdp_send_cursor_event - * Signature: (IIII)Z - */ -JNIEXPORT jboolean JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1send_1cursor_1event - (JNIEnv *, jclass, jint, jint, jint, jint); - -/* - * Class: com_freerdp_freerdpcore_services_LibFreeRDP - * Method: freerdp_send_key_event - * Signature: (IIZ)Z - */ -JNIEXPORT jboolean JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1send_1key_1event - (JNIEnv *, jclass, jint, jint, jboolean); - -/* - * Class: com_freerdp_freerdpcore_services_LibFreeRDP - * Method: freerdp_send_unicodekey_event - * Signature: (II)Z - */ -JNIEXPORT jboolean JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1send_1unicodekey_1event - (JNIEnv *, jclass, jint, jint); - -/* - * Class: com_freerdp_freerdpcore_services_LibFreeRDP - * Method: freerdp_send_clipboard_data - * Signature: (ILjava/lang/String;)Z - */ -JNIEXPORT jboolean JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1send_1clipboard_1data - (JNIEnv *, jclass, jint, jstring); - -/* - * Class: com_freerdp_freerdpcore_services_LibFreeRDP - * Method: freerdp_get_version - * Signature: ()Ljava/lang/String; - */ -JNIEXPORT jstring JNICALL Java_com_freerdp_freerdpcore_services_LibFreeRDP_freerdp_1get_1version - (JNIEnv *, jclass); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/client/Android/FreeRDPCore/lint.xml b/client/Android/FreeRDPCore/lint.xml deleted file mode 100644 index ee0eead5b..000000000 --- a/client/Android/FreeRDPCore/lint.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/client/Android/FreeRDPCore/local.properties.cmake b/client/Android/FreeRDPCore/local.properties.cmake deleted file mode 100644 index 159126370..000000000 --- a/client/Android/FreeRDPCore/local.properties.cmake +++ /dev/null @@ -1,2 +0,0 @@ -# This file is automatically generated by cmake. -sdk.dir=@ANDROID_SDK@ diff --git a/client/Android/FreeRDPCore/project.properties.cmake b/client/Android/FreeRDPCore/project.properties.cmake deleted file mode 100644 index 09c72f4a9..000000000 --- a/client/Android/FreeRDPCore/project.properties.cmake +++ /dev/null @@ -1,16 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must be checked in Version Control Systems. -# -# To customize properties used by the Ant build system edit -# "ant.properties", and override values to adapt the script to your -# project structure. -# -# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): -#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt - -# Project target. -target=android-@ANDROID_APP_TARGET_SDK@ -android.library=true -android.library.reference.1=../appcompat_v7 diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/application/GlobalApp.java b/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/application/GlobalApp.java deleted file mode 100644 index eea1bfd4f..000000000 --- a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/application/GlobalApp.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - Android Main Application - - Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -*/ - -package com.freerdp.freerdpcore.application; - -import android.app.Application; -import android.content.Intent; -import android.content.IntentFilter; -import android.util.Log; - -import java.util.*; - -import com.freerdp.freerdpcore.application.SessionState; -import com.freerdp.freerdpcore.domain.BookmarkBase; -import com.freerdp.freerdpcore.services.BookmarkDB; -import com.freerdp.freerdpcore.services.HistoryDB; -import com.freerdp.freerdpcore.services.LibFreeRDP; -import com.freerdp.freerdpcore.services.ManualBookmarkGateway; -import com.freerdp.freerdpcore.services.QuickConnectHistoryGateway; - -public class GlobalApp extends Application implements LibFreeRDP.EventListener -{ - private static Map sessionMap; - - public static boolean ConnectedTo3G = false; - - // event notification defines - public static final String EVENT_TYPE = "EVENT_TYPE"; - public static final String EVENT_PARAM = "EVENT_PARAM"; - public static final String EVENT_STATUS = "EVENT_STATUS"; - public static final String EVENT_ERROR = "EVENT_ERROR"; - - public static final String ACTION_EVENT_FREERDP = "com.freerdp.freerdp.event.freerdp"; - - public static final int FREERDP_EVENT_CONNECTION_SUCCESS = 1; - public static final int FREERDP_EVENT_CONNECTION_FAILURE = 2; - public static final int FREERDP_EVENT_DISCONNECTED = 3; - - private static BookmarkDB bookmarkDB; - private static ManualBookmarkGateway manualBookmarkGateway; - - private static HistoryDB historyDB; - private static QuickConnectHistoryGateway quickConnectHistoryGateway; - - // timer for disconnecting sessions after the screen was turned off - private static Timer disconnectTimer = null; - - // TimerTask for disconnecting sessions after screen was turned off - private static class DisconnectTask extends TimerTask - { - @Override - public void run() { - Log.v("DisconnectTask", "Doing action"); - - // disconnect any running rdp session - Collection sessions = GlobalApp.getSessions(); - for (SessionState session : sessions) - { - LibFreeRDP.disconnect(session.getInstance()); - } - } - } - - - public GlobalApp() - { - sessionMap = Collections.synchronizedMap(new HashMap()); - - GlobalApp.load(); - LibFreeRDP.setEventListener(this); - } - - @Override - public void onCreate() - { - super.onCreate(); - - bookmarkDB = new BookmarkDB(this); - - manualBookmarkGateway = new ManualBookmarkGateway(bookmarkDB); - - historyDB = new HistoryDB(this); - quickConnectHistoryGateway = new QuickConnectHistoryGateway(historyDB); - - GlobalSettings.init(this); - ConnectedTo3G = NetworkStateReceiver.isConnectedTo3G(this); - - // init screen receiver here (this can't be declared in AndroidManifest - refer to: - // http://thinkandroid.wordpress.com/2010/01/24/handling-screen-off-and-screen-on-intents/ - IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON); - filter.addAction(Intent.ACTION_SCREEN_OFF); - registerReceiver(new ScreenReceiver(), filter); - } - - public static ManualBookmarkGateway getManualBookmarkGateway() - { - return manualBookmarkGateway; - } - - public static QuickConnectHistoryGateway getQuickConnectHistoryGateway() - { - return quickConnectHistoryGateway; - } - - static private void load() - { - final String libname = "freerdp-android"; - final String LD_PATH = System.getProperty("java.library.path"); - - Log.v("LibFreeRDP", "Trying to load library " + libname + " from LD_PATH: " + LD_PATH); - - try { - System.loadLibrary(libname); - } catch (UnsatisfiedLinkError e) { - Log.e("LibFreeRDP", e.toString()); - } - } - - // Disconnect handling for Screen on/off events - static public void startDisconnectTimer() - { - int timeoutMinutes = GlobalSettings.getDisconnectTimeout(); - if (timeoutMinutes > 0) - { - // start disconnect timeout... - disconnectTimer = new Timer(); - disconnectTimer.schedule(new DisconnectTask(), timeoutMinutes * 60 * 1000); - } - } - - static public void cancelDisconnectTimer() - { - // cancel any pending timer events - if (disconnectTimer != null) - { - disconnectTimer.cancel(); - disconnectTimer.purge(); - disconnectTimer = null; - } - } - - // RDP session handling - static public SessionState createSession(BookmarkBase bookmark) - { - SessionState session = new SessionState(LibFreeRDP.newInstance(), bookmark); - sessionMap.put(Integer.valueOf(session.getInstance()), session); - return session; - } - - static public SessionState getSession(int instance) - { - return sessionMap.get(instance); - } - - static public Collection getSessions() - { - // return a copy of the session items - return new ArrayList(sessionMap.values()); - } - - static public void freeSession(int instance) - { - if (GlobalApp.sessionMap.containsKey(instance)) - { - GlobalApp.sessionMap.remove(instance); - LibFreeRDP.freeInstance(instance); - } - } - - // helper to send FreeRDP notifications - private void sendRDPNotification(int type, int param) - { - // send broadcast - Intent intent = new Intent(ACTION_EVENT_FREERDP); - intent.putExtra(EVENT_TYPE, type); - intent.putExtra(EVENT_PARAM, param); - sendBroadcast(intent); - } - - // ////////////////////////////////////////////////////////////////////// - // Implementation of LibFreeRDP.EventListener - public void OnConnectionSuccess(int instance) - { - Log.v("LibFreeRDP", "OnConnectionSuccess"); - sendRDPNotification(FREERDP_EVENT_CONNECTION_SUCCESS, instance); - } - - public void OnConnectionFailure(int instance) - { - Log.v("LibFreeRDP", "OnConnectionFailure"); - - // send notification to session activity - sendRDPNotification(FREERDP_EVENT_CONNECTION_FAILURE, instance); - } - - public void OnDisconnecting(int instance) - { - Log.v("LibFreeRDP", "OnDisconnecting"); - - // send disconnect notification - sendRDPNotification(FREERDP_EVENT_DISCONNECTED, instance); - } - - public void OnDisconnected(int instance) - { - Log.v("LibFreeRDP", "OnDisconnected"); - } -} diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/services/BookmarkDB.java b/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/services/BookmarkDB.java deleted file mode 100644 index b1f47cb49..000000000 --- a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/services/BookmarkDB.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - Android Bookmark Database - - Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -*/ - -package com.freerdp.freerdpcore.services; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import android.content.Context; -import android.provider.BaseColumns; -import android.util.Log; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; - -public class BookmarkDB extends SQLiteOpenHelper -{ - private static final int DB_VERSION = 6; - private static final String DB_NAME = "bookmarks.db"; - - public static final String ID = BaseColumns._ID; - - public BookmarkDB(Context context) - { - super(context, DB_NAME, null, DB_VERSION); - } - - @Override - public void onCreate(SQLiteDatabase db) - { - String sqlScreenSettings = - "CREATE TABLE tbl_screen_settings (" - + ID + " INTEGER PRIMARY KEY, " - + "colors INTEGER DEFAULT 16, " - + "resolution INTEGER DEFAULT 0, " - + "width, " - + "height);"; - - db.execSQL(sqlScreenSettings); - - String sqlPerformanceFlags = - "CREATE TABLE tbl_performance_flags (" - + ID + " INTEGER PRIMARY KEY, " - + "perf_remotefx INTEGER, " - + "perf_wallpaper INTEGER, " - + "perf_theming INTEGER, " - + "perf_full_window_drag INTEGER, " - + "perf_menu_animations INTEGER, " - + "perf_font_smoothing INTEGER, " - + "perf_desktop_composition INTEGER);"; - - db.execSQL(sqlPerformanceFlags); - - String sqlManualBookmarks = getManualBookmarksCreationString(); - db.execSQL(sqlManualBookmarks); - - - // Insert a test entry - String sqlInsertDefaultScreenEntry = - "INSERT INTO tbl_screen_settings (" - + "colors, " - + "resolution, " - + "width, " - + "height) " - + "VALUES ( " - + "32, 1, 1024, 768);"; - db.execSQL(sqlInsertDefaultScreenEntry); - db.execSQL(sqlInsertDefaultScreenEntry); - - String sqlInsertDefaultPerfFlags = - "INSERT INTO tbl_performance_flags (" - + "perf_remotefx, " - + "perf_wallpaper, " - + "perf_theming, " - + "perf_full_window_drag, " - + "perf_menu_animations, " - + "perf_font_smoothing, " - + "perf_desktop_composition) " - + "VALUES ( " - + "1, 0, 0, 0, 0, 0, 0);"; - db.execSQL(sqlInsertDefaultPerfFlags); - db.execSQL(sqlInsertDefaultPerfFlags); - - String sqlInsertDefaultSessionEntry = - "INSERT INTO tbl_manual_bookmarks (" - + "label, " - + "hostname, " - + "username, " - + "password, " - + "domain, " - + "port, " - + "screen_settings, " - + "performance_flags, " - + "screen_3g, " - + "performance_3g, " - + "redirect_sdcard, " - + "redirect_sound, " - + "redirect_microphone, " - + "security, " - + "remote_program, " - + "work_dir, " - + "async_channel, " - + "async_transport, " - + "async_input, " - + "async_update, " - + "console_mode, " - + "debug_level ) " - + "VALUES ( " - + "'Test Server', " - + "'testservice.afreerdp.com', " - + "'', " - + "'', " - + "'', " - + "3389, " - + "1, 1, 2, 2, 0, 0, 0, 0, " - + "'', '', " - + "1, 1, 1, 1, 0, 0);"; - db.execSQL(sqlInsertDefaultSessionEntry); - } - - private String getManualBookmarksCreationString() - { - return ( - "CREATE TABLE IF NOT EXISTS tbl_manual_bookmarks (" - + ID + " INTEGER PRIMARY KEY, " - + "label TEXT NOT NULL, " - + "hostname TEXT NOT NULL, " - + "username TEXT NOT NULL, " - + "password TEXT, " - + "domain TEXT, " - + "port TEXT, " - + "screen_settings INTEGER NOT NULL, " - + "performance_flags INTEGER NOT NULL, " - - + "enable_gateway_settings INTEGER DEFAULT 0, " - + "gateway_hostname TEXT, " - + "gateway_port INTEGER DEFAULT 443, " - + "gateway_username TEXT, " - + "gateway_password TEXT, " - + "gateway_domain TEXT, " - - + "enable_3g_settings INTEGER DEFAULT 0, " - + "screen_3g INTEGER NOT NULL, " - + "performance_3g INTEGER NOT NULL, " - + "redirect_sdcard INTEGER DEFAULT 0, " - + "redirect_sound INTEGER DEFAULT 0, " - + "redirect_microphone INTEGER DEFAULT 0, " - + "security INTEGER, " - + "remote_program TEXT, " - + "work_dir TEXT, " - + "async_channel INTEGER DEFAULT 0, " - + "async_transport INTEGER DEFAULT 0, " - + "async_input INTEGER DEFAULT 0, " - + "async_update INTEGER DEFAULT 0, " - + "console_mode INTEGER, " - + "debug_level INTEGER DEFAULT 0, " - - + "FOREIGN KEY(screen_settings) REFERENCES tbl_screen_settings(" + ID + "), " - + "FOREIGN KEY(performance_flags) REFERENCES tbl_performance_flags(" + ID + "), " - + "FOREIGN KEY(screen_3g) REFERENCES tbl_screen_settings(" + ID + "), " - + "FOREIGN KEY(performance_3g) REFERENCES tbl_performance_flags(" + ID + ") " - - + ");"); - } - - // from http://stackoverflow.com/questions/3424156/upgrade-sqlite-database-from-one-version-to-another - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) - { - db.beginTransaction(); - - // run a table creation with if not exists (we are doing an upgrade, so the table might - // not exists yet, it will fail alter and drop) - db.execSQL(getManualBookmarksCreationString()); - // put in a list the existing columns - List columns = GetColumns(db, "tbl_manual_bookmarks"); - // backup table - db.execSQL("ALTER TABLE tbl_manual_bookmarks RENAME TO 'temp_tbl_manual_bookmarks'"); - // create new table (with new scheme) - db.execSQL(getManualBookmarksCreationString()); - // get the intersection with the new columns, this time columns taken from the upgraded table - columns.retainAll(GetColumns(db, "tbl_manual_bookmarks")); - // restore data - String cols = joinStrings(columns, ","); - db.execSQL(String.format("INSERT INTO %s (%s) SELECT %s from 'temp_%s", "tbl_manual_bookmarks", cols, cols, "tbl_manual_bookmarks'")); - // remove backup table - db.execSQL("DROP table 'temp_tbl_manual_bookmarks'"); - - db.setTransactionSuccessful(); - db.endTransaction(); - } - - private static List GetColumns(SQLiteDatabase db, String tableName) { - List ar = null; - Cursor c = null; - try { - c = db.rawQuery("SELECT * FROM " + tableName + " LIMIT 1", null); - if (c != null) { - ar = new ArrayList(Arrays.asList(c.getColumnNames())); - } - } catch (Exception e) { - Log.v(tableName, e.getMessage(), e); - e.printStackTrace(); - } finally { - if (c != null) - c.close(); - } - return ar; - } - - private static String joinStrings(List list, String delim) { - StringBuilder buf = new StringBuilder(); - int num = list.size(); - for (int i = 0; i < num; i++) { - if (i != 0) - buf.append(delim); - buf.append((String) list.get(i)); - } - return buf.toString(); - } -} diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/services/LibFreeRDP.java b/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/services/LibFreeRDP.java deleted file mode 100644 index c5e896f34..000000000 --- a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/services/LibFreeRDP.java +++ /dev/null @@ -1,308 +0,0 @@ -/* - Android FreeRDP JNI Wrapper - - Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz - - This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. - If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -*/ - -package com.freerdp.freerdpcore.services; - - -import com.freerdp.freerdpcore.application.GlobalApp; -import com.freerdp.freerdpcore.application.SessionState; -import com.freerdp.freerdpcore.domain.BookmarkBase; -import com.freerdp.freerdpcore.domain.ManualBookmark; - -import android.graphics.Bitmap; - -public class LibFreeRDP -{ - private static native int freerdp_new(); - private static native void freerdp_free(int inst); - private static native boolean freerdp_connect(int inst); - private static native boolean freerdp_disconnect(int inst); - private static native boolean freerdp_cancel_connection(int inst); - - private static native boolean freerdp_set_connection_info(int inst, - String hostname, String username, String password, String domain, - int width, int height, int color_depth, int port, boolean console, - int security, String certname); - - private static native void freerdp_set_performance_flags(int inst, - boolean remotefx, boolean disableWallpaper, boolean disableFullWindowDrag, - boolean disableMenuAnimations, boolean disableTheming, - boolean enableFontSmoothing, boolean enableDesktopComposition); - - private static native boolean freerdp_set_advanced_settings(int inst, - String remoteProgram, String workDir, boolean async_channel, - boolean async_transport, boolean async_input, boolean async_update); - - private static native boolean freerdp_set_data_directory(int inst, String directory); - - private static native void freerdp_set_clipboard_redirection(int inst, boolean enable); - private static native boolean freerdp_set_sound_redirection(int inst, int redirect); - private static native boolean freerdp_set_microphone_redirection(int inst, boolean enable); - private static native boolean freerdp_set_drive_redirection(int inst, String path); - - private static native boolean freerdp_set_gateway_info(int inst, String gatewayhostname, int port, - String gatewayusername, String gatewaypassword, String gatewaydomain); - - private static native boolean freerdp_update_graphics(int inst, - Bitmap bitmap, int x, int y, int width, int height); - - private static native boolean freerdp_send_cursor_event(int inst, int x, int y, int flags); - private static native boolean freerdp_send_key_event(int inst, int keycode, boolean down); - private static native boolean freerdp_send_unicodekey_event(int inst, int keycode); - private static native boolean freerdp_send_clipboard_data(int inst, String data); - - private static native String freerdp_get_version(); - - private static final String TAG = "LibFreeRDP"; - - public static interface EventListener - { - void OnConnectionSuccess(int instance); - void OnConnectionFailure(int instance); - void OnDisconnecting(int instance); - void OnDisconnected(int instance); - } - - public static interface UIEventListener - { - void OnSettingsChanged(int width, int height, int bpp); - boolean OnAuthenticate(StringBuilder username, StringBuilder domain, StringBuilder password); - boolean OnVerifiyCertificate(String subject, String issuer, String fingerprint); - void OnGraphicsUpdate(int x, int y, int width, int height); - void OnGraphicsResize(int width, int height, int bpp); - void OnRemoteClipboardChanged(String data); - } - - private static EventListener listener; - - public static void setEventListener(EventListener l) - { - listener = l; - } - - public static int newInstance() - { - return freerdp_new(); - } - - public static void freeInstance(int inst) - { - freerdp_free(inst); - } - - public static boolean connect(int inst) - { - return freerdp_connect(inst); - } - - public static boolean disconnect(int inst) - { - return freerdp_disconnect(inst); - } - - public static boolean cancelConnection(int inst) - { - return freerdp_cancel_connection(inst); - } - - public static boolean setConnectionInfo(int inst, BookmarkBase bookmark) - { - BookmarkBase.ScreenSettings screenSettings = bookmark.getActiveScreenSettings(); - - int port; - String hostname; - String certName = ""; - if(bookmark.getType() == BookmarkBase.TYPE_MANUAL) - { - port = bookmark.get().getPort(); - hostname = bookmark.get().getHostname(); - } - else - { - assert false; - return false; - } - - freerdp_set_connection_info(inst, - hostname, - bookmark.getUsername(), - bookmark.getPassword(), - bookmark.getDomain(), - screenSettings.getWidth(), - screenSettings.getHeight(), - screenSettings.getColors(), - port, - bookmark.getAdvancedSettings().getConsoleMode(), - bookmark.getAdvancedSettings().getSecurity(), - certName); - - BookmarkBase.PerformanceFlags flags = bookmark.getActivePerformanceFlags(); - freerdp_set_performance_flags(inst, - flags.getRemoteFX(), - !flags.getWallpaper(), - !flags.getFullWindowDrag(), - !flags.getMenuAnimations(), - !flags.getTheming(), - flags.getFontSmoothing(), - flags.getDesktopComposition()); - - BookmarkBase.AdvancedSettings advancedSettings = bookmark.getAdvancedSettings(); - BookmarkBase.DebugSettings debugSettings = bookmark.getDebugSettings(); - freerdp_set_advanced_settings(inst, advancedSettings.getRemoteProgram(), - advancedSettings.getWorkDir(), debugSettings.getAsyncChannel(), - debugSettings.getAsyncTransport(), debugSettings.getAsyncInput(), - debugSettings.getAsyncUpdate()); - - // drive redirection enabled? - if (advancedSettings.getRedirectSDCard()) - freerdp_set_drive_redirection(inst, android.os.Environment.getExternalStorageDirectory().getPath()); - - // always enable clipboard redirection - freerdp_set_clipboard_redirection(inst, true); - - // Gateway enabled? - if (bookmark.getType() == BookmarkBase.TYPE_MANUAL && bookmark.get().getEnableGatewaySettings()) - { - ManualBookmark.GatewaySettings gatewaySettings = bookmark.get().getGatewaySettings(); - freerdp_set_gateway_info(inst, gatewaySettings.getHostname(), gatewaySettings.getPort(), - gatewaySettings.getUsername(), gatewaySettings.getPassword(), gatewaySettings.getDomain()); - } - - // Sound redirection - freerdp_set_sound_redirection(inst, - advancedSettings.getRedirectSound()); - - // Microphone redirection - freerdp_set_microphone_redirection(inst, - advancedSettings.getRedirectMicrophone()); - - return true; - } - - public static boolean setDataDirectory(int inst, String directory) - { - return freerdp_set_data_directory(inst, directory); - } - - public static boolean updateGraphics(int inst, Bitmap bitmap, int x, int y, int width, int height) - { - return freerdp_update_graphics(inst, bitmap, x, y, width, height); - } - - public static boolean sendCursorEvent(int inst, int x, int y, int flags) - { - return freerdp_send_cursor_event(inst, x, y, flags); - } - - public static boolean sendKeyEvent(int inst, int keycode, boolean down) - { - return freerdp_send_key_event(inst, keycode, down); - } - - public static boolean sendUnicodeKeyEvent(int inst, int keycode) - { - return freerdp_send_unicodekey_event(inst, keycode); - } - - public static boolean sendClipboardData(int inst, String data) - { - return freerdp_send_clipboard_data(inst, data); - } - - private static void OnConnectionSuccess(int inst) - { - if (listener != null) - listener.OnConnectionSuccess(inst); - } - - private static void OnConnectionFailure(int inst) - { - if (listener != null) - listener.OnConnectionFailure(inst); - } - - private static void OnDisconnecting(int inst) - { - if (listener != null) - listener.OnDisconnecting(inst); - } - - private static void OnDisconnected(int inst) - { - if (listener != null) - listener.OnDisconnected(inst); - } - - private static void OnSettingsChanged(int inst, int width, int height, int bpp) - { - SessionState s = GlobalApp.getSession(inst); - if (s == null) - return; - UIEventListener uiEventListener = s.getUIEventListener(); - if (uiEventListener != null) - uiEventListener.OnSettingsChanged(width, height, bpp); - } - - private static boolean OnAuthenticate(int inst, StringBuilder username, StringBuilder domain, StringBuilder password) - { - SessionState s = GlobalApp.getSession(inst); - if (s == null) - return false; - UIEventListener uiEventListener = s.getUIEventListener(); - if (uiEventListener != null) - return uiEventListener.OnAuthenticate(username, domain, password); - return false; - } - - private static boolean OnVerifyCertificate(int inst, String subject, String issuer, String fingerprint) - { - SessionState s = GlobalApp.getSession(inst); - if (s == null) - return false; - UIEventListener uiEventListener = s.getUIEventListener(); - if (uiEventListener != null) - return uiEventListener.OnVerifiyCertificate(subject, issuer, fingerprint); - return false; - } - - private static void OnGraphicsUpdate(int inst, int x, int y, int width, int height) - { - SessionState s = GlobalApp.getSession(inst); - if (s == null) - return; - UIEventListener uiEventListener = s.getUIEventListener(); - if (uiEventListener != null) - uiEventListener.OnGraphicsUpdate(x, y, width, height); - } - - private static void OnGraphicsResize(int inst, int width, int height, int bpp) - { - SessionState s = GlobalApp.getSession(inst); - if (s == null) - return; - UIEventListener uiEventListener = s.getUIEventListener(); - if (uiEventListener != null) - uiEventListener.OnGraphicsResize(width, height, bpp); - } - - private static void OnRemoteClipboardChanged(int inst, String data) - { - SessionState s = GlobalApp.getSession(inst); - if (s == null) - return; - UIEventListener uiEventListener = s.getUIEventListener(); - if (uiEventListener != null) - uiEventListener.OnRemoteClipboardChanged(data); - } - - public static String getVersion() - { - return freerdp_get_version(); - } -} diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/utils/BuildConfiguration.java.in b/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/utils/BuildConfiguration.java.in deleted file mode 100644 index e0a72c95a..000000000 --- a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/utils/BuildConfiguration.java.in +++ /dev/null @@ -1,15 +0,0 @@ -package com.freerdp.freerdpcore.utils; - -public class BuildConfiguration { - public static final String WITH_ANDROID_DEBUG_MENU = "@WITH_ANDROID_DEBUG_MENU@"; - - public static final int FREERDP_VERSION_MAJOR = @FREERDP_VERSION_MAJOR@; - public static final int FREERDP_VERSION_MINOR = @FREERDP_VERSION_MINOR@; - public static final int FREERDP_VERSION_REVISION = @FREERDP_VERSION_REVISION@; - - public static final String FREERDP_VERSION_SUFFIX = "@FREERDP_VERSION_SUFFIX@"; - public static final String FREERDP_API_VERSION = "@FREERDP_API_VERSION@"; - public static final String FREERDP_VERSION = "@FREERDP_VERSION@"; - public static final String FREERDP_VERSION_FULL = "@FREERDP_VERSION_FULL@"; - public static final String GIT_REVISION = "@GIT_REVISION@"; - } diff --git a/client/Android/ModuleOptions.cmake b/client/Android/ModuleOptions.cmake deleted file mode 100644 index 38f85b400..000000000 --- a/client/Android/ModuleOptions.cmake +++ /dev/null @@ -1,4 +0,0 @@ - -set(FREERDP_CLIENT_NAME "afreerdp") -set(FREERDP_CLIENT_PLATFORM "Android") -set(FREERDP_CLIENT_VENDOR "FreeRDP") diff --git a/client/Android/Studio/.gitignore b/client/Android/Studio/.gitignore new file mode 100644 index 000000000..a2dc2317b --- /dev/null +++ b/client/Android/Studio/.gitignore @@ -0,0 +1,37 @@ +#built application files +*.apk +*.ap_ + +# files for the dex VM +*.dex + +# Java class files +*.class + +# generated files +bin/ +gen/ + +# Local configuration file (sdk path, etc) +local.properties + +# Windows thumbnail db +Thumbs.db + +# OSX files +.DS_Store + +# Eclipse project files +.classpath +.project + +# Android Studio +*.iml +.idea +#.idea/workspace.xml - remove # and delete .idea if it better suit your needs. +.gradle +build/ + +#NDK +obj/ +jniLibs/ diff --git a/client/Android/Studio/aFreeRDP/build.gradle b/client/Android/Studio/aFreeRDP/build.gradle new file mode 100644 index 000000000..ff43e71cf --- /dev/null +++ b/client/Android/Studio/aFreeRDP/build.gradle @@ -0,0 +1,23 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 21 + buildToolsVersion "23.0.2" + + defaultConfig { + applicationId "com.freerdp.afreerdp" + minSdkVersion 14 + targetSdkVersion 21 + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + } + } +} + +dependencies { + compile project(':freeRDPCore') +} diff --git a/client/Android/Studio/aFreeRDP/lint.xml b/client/Android/Studio/aFreeRDP/lint.xml new file mode 100644 index 000000000..8423c0ef9 --- /dev/null +++ b/client/Android/Studio/aFreeRDP/lint.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/client/Android/aFreeRDP/AndroidManifest.xml.cmake b/client/Android/Studio/aFreeRDP/src/main/AndroidManifest.xml similarity index 90% rename from client/Android/aFreeRDP/AndroidManifest.xml.cmake rename to client/Android/Studio/aFreeRDP/src/main/AndroidManifest.xml index 8cec9833d..0d7915c5f 100644 --- a/client/Android/aFreeRDP/AndroidManifest.xml.cmake +++ b/client/Android/Studio/aFreeRDP/src/main/AndroidManifest.xml @@ -1,14 +1,14 @@ - + + android:versionCode="3" + android:versionName="e83f97b" > + android:targetSdkVersion="21" + android:minSdkVersion="14"/> diff --git a/client/Android/aFreeRDP/assets/FreeRDP_Logo.png b/client/Android/Studio/aFreeRDP/src/main/assets/FreeRDP_Logo.png similarity index 100% rename from client/Android/aFreeRDP/assets/FreeRDP_Logo.png rename to client/Android/Studio/aFreeRDP/src/main/assets/FreeRDP_Logo.png diff --git a/client/Android/aFreeRDP/assets/about_page/about.html b/client/Android/Studio/aFreeRDP/src/main/assets/about_page/about.html similarity index 100% rename from client/Android/aFreeRDP/assets/about_page/about.html rename to client/Android/Studio/aFreeRDP/src/main/assets/about_page/about.html diff --git a/client/Android/aFreeRDP/assets/about_page/about_phone.html b/client/Android/Studio/aFreeRDP/src/main/assets/about_page/about_phone.html similarity index 100% rename from client/Android/aFreeRDP/assets/about_page/about_phone.html rename to client/Android/Studio/aFreeRDP/src/main/assets/about_page/about_phone.html diff --git a/client/Android/aFreeRDP/assets/about_page/background_transparent.png b/client/Android/Studio/aFreeRDP/src/main/assets/about_page/background_transparent.png similarity index 100% rename from client/Android/aFreeRDP/assets/about_page/background_transparent.png rename to client/Android/Studio/aFreeRDP/src/main/assets/about_page/background_transparent.png diff --git a/client/Android/aFreeRDP/assets/background.jpg b/client/Android/Studio/aFreeRDP/src/main/assets/background.jpg similarity index 100% rename from client/Android/aFreeRDP/assets/background.jpg rename to client/Android/Studio/aFreeRDP/src/main/assets/background.jpg diff --git a/client/Android/aFreeRDP/assets/de_about_page/about.html b/client/Android/Studio/aFreeRDP/src/main/assets/de_about_page/about.html similarity index 100% rename from client/Android/aFreeRDP/assets/de_about_page/about.html rename to client/Android/Studio/aFreeRDP/src/main/assets/de_about_page/about.html diff --git a/client/Android/aFreeRDP/assets/de_about_page/about_phone.html b/client/Android/Studio/aFreeRDP/src/main/assets/de_about_page/about_phone.html similarity index 100% rename from client/Android/aFreeRDP/assets/de_about_page/about_phone.html rename to client/Android/Studio/aFreeRDP/src/main/assets/de_about_page/about_phone.html diff --git a/client/Android/aFreeRDP/assets/de_about_page/background_transparent.png b/client/Android/Studio/aFreeRDP/src/main/assets/de_about_page/background_transparent.png similarity index 100% rename from client/Android/aFreeRDP/assets/de_about_page/background_transparent.png rename to client/Android/Studio/aFreeRDP/src/main/assets/de_about_page/background_transparent.png diff --git a/client/Android/aFreeRDP/assets/de_help_page/gestures.html b/client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/gestures.html similarity index 100% rename from client/Android/aFreeRDP/assets/de_help_page/gestures.html rename to client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/gestures.html diff --git a/client/Android/aFreeRDP/assets/de_help_page/gestures.png b/client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/gestures.png similarity index 100% rename from client/Android/aFreeRDP/assets/de_help_page/gestures.png rename to client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/gestures.png diff --git a/client/Android/aFreeRDP/assets/de_help_page/gestures_phone.html b/client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/gestures_phone.html similarity index 100% rename from client/Android/aFreeRDP/assets/de_help_page/gestures_phone.html rename to client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/gestures_phone.html diff --git a/client/Android/aFreeRDP/assets/de_help_page/gestures_phone.png b/client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/gestures_phone.png similarity index 100% rename from client/Android/aFreeRDP/assets/de_help_page/gestures_phone.png rename to client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/gestures_phone.png diff --git a/client/Android/aFreeRDP/assets/de_help_page/nav_gestures.png b/client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/nav_gestures.png similarity index 100% rename from client/Android/aFreeRDP/assets/de_help_page/nav_gestures.png rename to client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/nav_gestures.png diff --git a/client/Android/aFreeRDP/assets/de_help_page/nav_toolbar.png b/client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/nav_toolbar.png similarity index 100% rename from client/Android/aFreeRDP/assets/de_help_page/nav_toolbar.png rename to client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/nav_toolbar.png diff --git a/client/Android/aFreeRDP/assets/de_help_page/nav_touch_pointer.png b/client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/nav_touch_pointer.png similarity index 100% rename from client/Android/aFreeRDP/assets/de_help_page/nav_touch_pointer.png rename to client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/nav_touch_pointer.png diff --git a/client/Android/aFreeRDP/assets/de_help_page/toolbar.html b/client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/toolbar.html similarity index 100% rename from client/Android/aFreeRDP/assets/de_help_page/toolbar.html rename to client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/toolbar.html diff --git a/client/Android/aFreeRDP/assets/de_help_page/toolbar.png b/client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/toolbar.png similarity index 100% rename from client/Android/aFreeRDP/assets/de_help_page/toolbar.png rename to client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/toolbar.png diff --git a/client/Android/aFreeRDP/assets/de_help_page/toolbar_phone.html b/client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/toolbar_phone.html similarity index 100% rename from client/Android/aFreeRDP/assets/de_help_page/toolbar_phone.html rename to client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/toolbar_phone.html diff --git a/client/Android/aFreeRDP/assets/de_help_page/toolbar_phone.png b/client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/toolbar_phone.png similarity index 100% rename from client/Android/aFreeRDP/assets/de_help_page/toolbar_phone.png rename to client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/toolbar_phone.png diff --git a/client/Android/aFreeRDP/assets/de_help_page/touch_pointer.html b/client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/touch_pointer.html similarity index 100% rename from client/Android/aFreeRDP/assets/de_help_page/touch_pointer.html rename to client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/touch_pointer.html diff --git a/client/Android/aFreeRDP/assets/de_help_page/touch_pointer.png b/client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/touch_pointer.png similarity index 100% rename from client/Android/aFreeRDP/assets/de_help_page/touch_pointer.png rename to client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/touch_pointer.png diff --git a/client/Android/aFreeRDP/assets/de_help_page/touch_pointer_phone.html b/client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/touch_pointer_phone.html similarity index 100% rename from client/Android/aFreeRDP/assets/de_help_page/touch_pointer_phone.html rename to client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/touch_pointer_phone.html diff --git a/client/Android/aFreeRDP/assets/de_help_page/touch_pointer_phone.png b/client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/touch_pointer_phone.png similarity index 100% rename from client/Android/aFreeRDP/assets/de_help_page/touch_pointer_phone.png rename to client/Android/Studio/aFreeRDP/src/main/assets/de_help_page/touch_pointer_phone.png diff --git a/client/Android/aFreeRDP/assets/help_page/gestures.html b/client/Android/Studio/aFreeRDP/src/main/assets/help_page/gestures.html similarity index 100% rename from client/Android/aFreeRDP/assets/help_page/gestures.html rename to client/Android/Studio/aFreeRDP/src/main/assets/help_page/gestures.html diff --git a/client/Android/aFreeRDP/assets/help_page/gestures.png b/client/Android/Studio/aFreeRDP/src/main/assets/help_page/gestures.png similarity index 100% rename from client/Android/aFreeRDP/assets/help_page/gestures.png rename to client/Android/Studio/aFreeRDP/src/main/assets/help_page/gestures.png diff --git a/client/Android/aFreeRDP/assets/help_page/gestures_phone.html b/client/Android/Studio/aFreeRDP/src/main/assets/help_page/gestures_phone.html similarity index 100% rename from client/Android/aFreeRDP/assets/help_page/gestures_phone.html rename to client/Android/Studio/aFreeRDP/src/main/assets/help_page/gestures_phone.html diff --git a/client/Android/aFreeRDP/assets/help_page/gestures_phone.png b/client/Android/Studio/aFreeRDP/src/main/assets/help_page/gestures_phone.png similarity index 100% rename from client/Android/aFreeRDP/assets/help_page/gestures_phone.png rename to client/Android/Studio/aFreeRDP/src/main/assets/help_page/gestures_phone.png diff --git a/client/Android/aFreeRDP/assets/help_page/nav_gestures.png b/client/Android/Studio/aFreeRDP/src/main/assets/help_page/nav_gestures.png similarity index 100% rename from client/Android/aFreeRDP/assets/help_page/nav_gestures.png rename to client/Android/Studio/aFreeRDP/src/main/assets/help_page/nav_gestures.png diff --git a/client/Android/aFreeRDP/assets/help_page/nav_toolbar.png b/client/Android/Studio/aFreeRDP/src/main/assets/help_page/nav_toolbar.png similarity index 100% rename from client/Android/aFreeRDP/assets/help_page/nav_toolbar.png rename to client/Android/Studio/aFreeRDP/src/main/assets/help_page/nav_toolbar.png diff --git a/client/Android/aFreeRDP/assets/help_page/nav_touch_pointer.png b/client/Android/Studio/aFreeRDP/src/main/assets/help_page/nav_touch_pointer.png similarity index 100% rename from client/Android/aFreeRDP/assets/help_page/nav_touch_pointer.png rename to client/Android/Studio/aFreeRDP/src/main/assets/help_page/nav_touch_pointer.png diff --git a/client/Android/aFreeRDP/assets/help_page/toolbar.html b/client/Android/Studio/aFreeRDP/src/main/assets/help_page/toolbar.html similarity index 100% rename from client/Android/aFreeRDP/assets/help_page/toolbar.html rename to client/Android/Studio/aFreeRDP/src/main/assets/help_page/toolbar.html diff --git a/client/Android/aFreeRDP/assets/help_page/toolbar.png b/client/Android/Studio/aFreeRDP/src/main/assets/help_page/toolbar.png similarity index 100% rename from client/Android/aFreeRDP/assets/help_page/toolbar.png rename to client/Android/Studio/aFreeRDP/src/main/assets/help_page/toolbar.png diff --git a/client/Android/aFreeRDP/assets/help_page/toolbar_phone.html b/client/Android/Studio/aFreeRDP/src/main/assets/help_page/toolbar_phone.html similarity index 100% rename from client/Android/aFreeRDP/assets/help_page/toolbar_phone.html rename to client/Android/Studio/aFreeRDP/src/main/assets/help_page/toolbar_phone.html diff --git a/client/Android/aFreeRDP/assets/help_page/toolbar_phone.png b/client/Android/Studio/aFreeRDP/src/main/assets/help_page/toolbar_phone.png similarity index 100% rename from client/Android/aFreeRDP/assets/help_page/toolbar_phone.png rename to client/Android/Studio/aFreeRDP/src/main/assets/help_page/toolbar_phone.png diff --git a/client/Android/aFreeRDP/assets/help_page/touch_pointer.html b/client/Android/Studio/aFreeRDP/src/main/assets/help_page/touch_pointer.html similarity index 100% rename from client/Android/aFreeRDP/assets/help_page/touch_pointer.html rename to client/Android/Studio/aFreeRDP/src/main/assets/help_page/touch_pointer.html diff --git a/client/Android/aFreeRDP/assets/help_page/touch_pointer.png b/client/Android/Studio/aFreeRDP/src/main/assets/help_page/touch_pointer.png similarity index 100% rename from client/Android/aFreeRDP/assets/help_page/touch_pointer.png rename to client/Android/Studio/aFreeRDP/src/main/assets/help_page/touch_pointer.png diff --git a/client/Android/aFreeRDP/assets/help_page/touch_pointer_phone.html b/client/Android/Studio/aFreeRDP/src/main/assets/help_page/touch_pointer_phone.html similarity index 100% rename from client/Android/aFreeRDP/assets/help_page/touch_pointer_phone.html rename to client/Android/Studio/aFreeRDP/src/main/assets/help_page/touch_pointer_phone.html diff --git a/client/Android/aFreeRDP/assets/help_page/touch_pointer_phone.png b/client/Android/Studio/aFreeRDP/src/main/assets/help_page/touch_pointer_phone.png similarity index 100% rename from client/Android/aFreeRDP/assets/help_page/touch_pointer_phone.png rename to client/Android/Studio/aFreeRDP/src/main/assets/help_page/touch_pointer_phone.png diff --git a/client/Android/aFreeRDP/src/com/freerdp/afreerdp/application/GlobalApp.java b/client/Android/Studio/aFreeRDP/src/main/java/com/freerdp/afreerdp/application/GlobalApp.java similarity index 100% rename from client/Android/aFreeRDP/src/com/freerdp/afreerdp/application/GlobalApp.java rename to client/Android/Studio/aFreeRDP/src/main/java/com/freerdp/afreerdp/application/GlobalApp.java diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_launcher_freerdp.png b/client/Android/Studio/aFreeRDP/src/main/res/drawable-hdpi/icon_launcher_freerdp.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-hdpi/icon_launcher_freerdp.png rename to client/Android/Studio/aFreeRDP/src/main/res/drawable-hdpi/icon_launcher_freerdp.png diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_launcher_freerdp.png b/client/Android/Studio/aFreeRDP/src/main/res/drawable-ldpi/icon_launcher_freerdp.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-ldpi/icon_launcher_freerdp.png rename to client/Android/Studio/aFreeRDP/src/main/res/drawable-ldpi/icon_launcher_freerdp.png diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_launcher_freerdp.png b/client/Android/Studio/aFreeRDP/src/main/res/drawable-mdpi/icon_launcher_freerdp.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-mdpi/icon_launcher_freerdp.png rename to client/Android/Studio/aFreeRDP/src/main/res/drawable-mdpi/icon_launcher_freerdp.png diff --git a/client/Android/FreeRDPCore/res/drawable/button_background.xml b/client/Android/Studio/aFreeRDP/src/main/res/drawable/button_background.xml similarity index 100% rename from client/Android/FreeRDPCore/res/drawable/button_background.xml rename to client/Android/Studio/aFreeRDP/src/main/res/drawable/button_background.xml diff --git a/client/Android/FreeRDPCore/res/drawable/icon_launcher_freerdp.png b/client/Android/Studio/aFreeRDP/src/main/res/drawable/icon_launcher_freerdp.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable/icon_launcher_freerdp.png rename to client/Android/Studio/aFreeRDP/src/main/res/drawable/icon_launcher_freerdp.png diff --git a/client/Android/FreeRDPCore/res/drawable/separator_background.xml b/client/Android/Studio/aFreeRDP/src/main/res/drawable/separator_background.xml similarity index 100% rename from client/Android/FreeRDPCore/res/drawable/separator_background.xml rename to client/Android/Studio/aFreeRDP/src/main/res/drawable/separator_background.xml diff --git a/client/Android/aFreeRDP/res/values-es/strings.xml b/client/Android/Studio/aFreeRDP/src/main/res/values-es/strings.xml similarity index 80% rename from client/Android/aFreeRDP/res/values-es/strings.xml rename to client/Android/Studio/aFreeRDP/src/main/res/values-es/strings.xml index f0aa7c6af..23ba45774 100644 --- a/client/Android/aFreeRDP/res/values-es/strings.xml +++ b/client/Android/Studio/aFreeRDP/src/main/res/values-es/strings.xml @@ -1,4 +1,4 @@ - + aFreeRDP diff --git a/client/Android/aFreeRDP/res/values-fr/strings.xml b/client/Android/Studio/aFreeRDP/src/main/res/values-fr/strings.xml similarity index 80% rename from client/Android/aFreeRDP/res/values-fr/strings.xml rename to client/Android/Studio/aFreeRDP/src/main/res/values-fr/strings.xml index 3c36d79ff..980236c4b 100644 --- a/client/Android/aFreeRDP/res/values-fr/strings.xml +++ b/client/Android/Studio/aFreeRDP/src/main/res/values-fr/strings.xml @@ -1,4 +1,4 @@ - + aFreeRDP diff --git a/client/Android/aFreeRDP/res/values-nl/strings.xml b/client/Android/Studio/aFreeRDP/src/main/res/values-nl/strings.xml similarity index 80% rename from client/Android/aFreeRDP/res/values-nl/strings.xml rename to client/Android/Studio/aFreeRDP/src/main/res/values-nl/strings.xml index f0aa7c6af..23ba45774 100644 --- a/client/Android/aFreeRDP/res/values-nl/strings.xml +++ b/client/Android/Studio/aFreeRDP/src/main/res/values-nl/strings.xml @@ -1,4 +1,4 @@ - + aFreeRDP diff --git a/client/Android/aFreeRDP/res/values/strings.xml b/client/Android/Studio/aFreeRDP/src/main/res/values/strings.xml similarity index 80% rename from client/Android/aFreeRDP/res/values/strings.xml rename to client/Android/Studio/aFreeRDP/src/main/res/values/strings.xml index f0aa7c6af..23ba45774 100644 --- a/client/Android/aFreeRDP/res/values/strings.xml +++ b/client/Android/Studio/aFreeRDP/src/main/res/values/strings.xml @@ -1,4 +1,4 @@ - + aFreeRDP diff --git a/client/Android/aFreeRDP/res/xml/searchable.xml b/client/Android/Studio/aFreeRDP/src/main/res/xml/searchable.xml similarity index 100% rename from client/Android/aFreeRDP/res/xml/searchable.xml rename to client/Android/Studio/aFreeRDP/src/main/res/xml/searchable.xml diff --git a/client/Android/Studio/build.gradle b/client/Android/Studio/build.gradle new file mode 100644 index 000000000..f4d8c542e --- /dev/null +++ b/client/Android/Studio/build.gradle @@ -0,0 +1,15 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.5.0' + } +} + +allprojects { + repositories { + jcenter() + } +} diff --git a/client/Android/Studio/freeRDPCore/build.gradle b/client/Android/Studio/freeRDPCore/build.gradle new file mode 100644 index 000000000..44467f784 --- /dev/null +++ b/client/Android/Studio/freeRDPCore/build.gradle @@ -0,0 +1,22 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 21 + buildToolsVersion "23.0.2" + + defaultConfig { + minSdkVersion 14 + targetSdkVersion 21 + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + } + } +} + +dependencies { + compile 'com.android.support:appcompat-v7:21.0.3' +} diff --git a/client/Android/Studio/freeRDPCore/lint.xml b/client/Android/Studio/freeRDPCore/lint.xml new file mode 100644 index 000000000..8423c0ef9 --- /dev/null +++ b/client/Android/Studio/freeRDPCore/lint.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/client/Android/FreeRDPCore/AndroidManifest.xml.cmake b/client/Android/Studio/freeRDPCore/src/main/AndroidManifest.xml similarity index 86% rename from client/Android/FreeRDPCore/AndroidManifest.xml.cmake rename to client/Android/Studio/freeRDPCore/src/main/AndroidManifest.xml index 1e50d7caf..cebe55dfe 100644 --- a/client/Android/FreeRDPCore/AndroidManifest.xml.cmake +++ b/client/Android/Studio/freeRDPCore/src/main/AndroidManifest.xml @@ -1,21 +1,23 @@ - + + android:versionCode="3" + android:versionName="e83f97b" > + android:targetSdkVersion="21" + android:minSdkVersion="14"/> - - + + + + + android:theme="@style/Theme.Main"> sessionMap; + + private static final String TAG = "GlobalApp"; + + public static boolean ConnectedTo3G = false; + + // event notification defines + public static final String EVENT_TYPE = "EVENT_TYPE"; + public static final String EVENT_PARAM = "EVENT_PARAM"; + public static final String EVENT_STATUS = "EVENT_STATUS"; + public static final String EVENT_ERROR = "EVENT_ERROR"; + + public static final String ACTION_EVENT_FREERDP = "com.freerdp.freerdp.event.freerdp"; + + public static final int FREERDP_EVENT_CONNECTION_SUCCESS = 1; + public static final int FREERDP_EVENT_CONNECTION_FAILURE = 2; + public static final int FREERDP_EVENT_DISCONNECTED = 3; + + private static BookmarkDB bookmarkDB; + private static ManualBookmarkGateway manualBookmarkGateway; + + private static HistoryDB historyDB; + private static QuickConnectHistoryGateway quickConnectHistoryGateway; + + // timer for disconnecting sessions after the screen was turned off + private static Timer disconnectTimer = null; + + // TimerTask for disconnecting sessions after screen was turned off + private static class DisconnectTask extends TimerTask { + @Override + public void run() { + Log.v("DisconnectTask", "Doing action"); + + // disconnect any running rdp session + Collection sessions = GlobalApp.getSessions(); + for (SessionState session : sessions) { + LibFreeRDP.disconnect(session.getInstance()); + } + } + } + + + public GlobalApp() { + sessionMap = Collections.synchronizedMap(new HashMap()); + + LibFreeRDP.setEventListener(this); + } + + @Override + public void onCreate() { + super.onCreate(); + + bookmarkDB = new BookmarkDB(this); + + manualBookmarkGateway = new ManualBookmarkGateway(bookmarkDB); + + historyDB = new HistoryDB(this); + quickConnectHistoryGateway = new QuickConnectHistoryGateway(historyDB); + + GlobalSettings.init(this); + ConnectedTo3G = NetworkStateReceiver.isConnectedTo3G(this); + + // init screen receiver here (this can't be declared in AndroidManifest - refer to: + // http://thinkandroid.wordpress.com/2010/01/24/handling-screen-off-and-screen-on-intents/ + IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON); + filter.addAction(Intent.ACTION_SCREEN_OFF); + registerReceiver(new ScreenReceiver(), filter); + } + + public static ManualBookmarkGateway getManualBookmarkGateway() { + return manualBookmarkGateway; + } + + public static QuickConnectHistoryGateway getQuickConnectHistoryGateway() { + return quickConnectHistoryGateway; + } + + // Disconnect handling for Screen on/off events + static public void startDisconnectTimer() { + int timeoutMinutes = GlobalSettings.getDisconnectTimeout(); + if (timeoutMinutes > 0) { + // start disconnect timeout... + disconnectTimer = new Timer(); + disconnectTimer.schedule(new DisconnectTask(), timeoutMinutes * 60 * 1000); + } + } + + static public void cancelDisconnectTimer() { + // cancel any pending timer events + if (disconnectTimer != null) { + disconnectTimer.cancel(); + disconnectTimer.purge(); + disconnectTimer = null; + } + } + + // RDP session handling + static public SessionState createSession(BookmarkBase bookmark, Context context) { + SessionState session = new SessionState(LibFreeRDP.newInstance(context), bookmark); + sessionMap.put(Integer.valueOf(session.getInstance()), session); + return session; + } + + static public SessionState getSession(int instance) { + return sessionMap.get(instance); + } + + static public Collection getSessions() { + // return a copy of the session items + return new ArrayList(sessionMap.values()); + } + + static public void freeSession(int instance) { + if (GlobalApp.sessionMap.containsKey(instance)) { + GlobalApp.sessionMap.remove(instance); + LibFreeRDP.freeInstance(instance); + } + } + + // helper to send FreeRDP notifications + private void sendRDPNotification(int type, int param) { + // send broadcast + Intent intent = new Intent(ACTION_EVENT_FREERDP); + intent.putExtra(EVENT_TYPE, type); + intent.putExtra(EVENT_PARAM, param); + sendBroadcast(intent); + } + + @Override + public void OnPreConnect(int instance) { + Log.v(TAG, "OnPreConnect"); + } + + // ////////////////////////////////////////////////////////////////////// + // Implementation of LibFreeRDP.EventListener + public void OnConnectionSuccess(int instance) { + Log.v(TAG, "OnConnectionSuccess"); + sendRDPNotification(FREERDP_EVENT_CONNECTION_SUCCESS, instance); + } + + public void OnConnectionFailure(int instance) { + Log.v(TAG, "OnConnectionFailure"); + + // send notification to session activity + sendRDPNotification(FREERDP_EVENT_CONNECTION_FAILURE, instance); + } + + public void OnDisconnecting(int instance) { + Log.v(TAG, "OnDisconnecting"); + + // send disconnect notification + sendRDPNotification(FREERDP_EVENT_DISCONNECTED, instance); + } + + public void OnDisconnected(int instance) { + Log.v(TAG, "OnDisconnected"); + } +} diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/application/GlobalSettings.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/application/GlobalSettings.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/application/GlobalSettings.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/application/GlobalSettings.java diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/application/NetworkStateReceiver.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/application/NetworkStateReceiver.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/application/NetworkStateReceiver.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/application/NetworkStateReceiver.java diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/application/ScreenReceiver.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/application/ScreenReceiver.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/application/ScreenReceiver.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/application/ScreenReceiver.java diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/application/SessionState.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/application/SessionState.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/application/SessionState.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/application/SessionState.java diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/domain/BookmarkBase.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/BookmarkBase.java similarity index 98% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/domain/BookmarkBase.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/BookmarkBase.java index eb8176ca2..eaf1eb68a 100644 --- a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/domain/BookmarkBase.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/BookmarkBase.java @@ -27,6 +27,8 @@ public class BookmarkBase implements Parcelable, Cloneable { // performance flags public static class PerformanceFlags implements Parcelable { private boolean remotefx; + private boolean gfx; + private boolean h264; private boolean wallpaper; private boolean theming; private boolean fullWindowDrag; @@ -36,6 +38,8 @@ public class BookmarkBase implements Parcelable, Cloneable { public PerformanceFlags() { remotefx = false; + gfx = false; + h264 = false; wallpaper = false; theming = false; fullWindowDrag = false; @@ -46,6 +50,8 @@ public class BookmarkBase implements Parcelable, Cloneable { public PerformanceFlags(Parcel parcel) { remotefx = parcel.readInt() == 1; + gfx = parcel.readInt() == 1; + h264 = parcel.readInt() == 1; wallpaper = parcel.readInt() == 1; theming = parcel.readInt() == 1; fullWindowDrag = (parcel.readInt() == 1); @@ -57,11 +63,27 @@ public class BookmarkBase implements Parcelable, Cloneable { public boolean getRemoteFX() { return remotefx; } - + public void setRemoteFX(boolean remotefx) { this.remotefx = remotefx; } + public boolean getGfx() { + return gfx; + } + + public void setGfx(boolean gfx) { + this.gfx = gfx; + } + + public boolean getH264() { + return h264; + } + + public void setH264(boolean h264) { + this.h264 = h264; + } + public boolean getWallpaper() { return wallpaper; } @@ -129,6 +151,8 @@ public class BookmarkBase implements Parcelable, Cloneable { @Override public void writeToParcel(Parcel out, int flags) { out.writeInt(remotefx ? 1 : 0); + out.writeInt(gfx ? 1 : 0); + out.writeInt(h264 ? 1 : 0); out.writeInt(wallpaper ? 1 : 0); out.writeInt(theming ? 1 : 0); out.writeInt(fullWindowDrag ? 1 : 0); diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/domain/ConnectionReference.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/ConnectionReference.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/domain/ConnectionReference.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/ConnectionReference.java diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/domain/ManualBookmark.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/ManualBookmark.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/domain/ManualBookmark.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/ManualBookmark.java diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/domain/PlaceholderBookmark.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/PlaceholderBookmark.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/domain/PlaceholderBookmark.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/PlaceholderBookmark.java diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/domain/QuickConnectBookmark.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/QuickConnectBookmark.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/domain/QuickConnectBookmark.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/domain/QuickConnectBookmark.java diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/presentation/AboutActivity.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/AboutActivity.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/presentation/AboutActivity.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/AboutActivity.java diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/presentation/ApplicationSettingsActivity.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/ApplicationSettingsActivity.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/presentation/ApplicationSettingsActivity.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/ApplicationSettingsActivity.java diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/presentation/BookmarkActivity.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/BookmarkActivity.java similarity index 98% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/presentation/BookmarkActivity.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/BookmarkActivity.java index 5df4b776e..9c8140ecb 100644 --- a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/presentation/BookmarkActivity.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/BookmarkActivity.java @@ -20,7 +20,6 @@ import com.freerdp.freerdpcore.domain.ConnectionReference; import com.freerdp.freerdpcore.domain.ManualBookmark; import com.freerdp.freerdpcore.services.BookmarkBaseGateway; import com.freerdp.freerdpcore.utils.RDPFileParser; -import com.freerdp.freerdpcore.utils.BuildConfiguration; import android.app.AlertDialog; import android.content.ComponentName; @@ -172,16 +171,6 @@ public class BookmarkActivity extends PreferenceActivity implements current_preferences = PREFERENCES_BOOKMARK; } - // Hide debug settings, if not activated. - if (!BuildConfiguration.WITH_ANDROID_DEBUG_MENU - .equalsIgnoreCase("ON")) { - Preference pref = findPreference("bookmark.debug"); - PreferenceCategory cat = (PreferenceCategory)findPreference("category.settings"); - if (pref != null) { - cat.removePreference(pref); - } - } - // update UI with bookmark data SharedPreferences spref = getPreferenceManager().getSharedPreferences(); initSettings(spref); diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/presentation/HelpActivity.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/HelpActivity.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/presentation/HelpActivity.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/HelpActivity.java diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/presentation/HomeActivity.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/HomeActivity.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/presentation/HomeActivity.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/HomeActivity.java diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/presentation/ScrollView2D.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/ScrollView2D.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/presentation/ScrollView2D.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/ScrollView2D.java diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/presentation/SessionActivity.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/SessionActivity.java similarity index 91% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/presentation/SessionActivity.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/SessionActivity.java index fcae85a57..08bc61395 100644 --- a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/presentation/SessionActivity.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/SessionActivity.java @@ -83,71 +83,71 @@ public class SessionActivity extends ActionBarActivity implements @Override public void handleMessage(Message msg) { switch (msg.what) { - case GRAPHICS_CHANGED: { - sessionView.onSurfaceChange(session); - scrollView.requestLayout(); - break; - } - case REFRESH_SESSIONVIEW: { - sessionView.invalidateRegion(); - break; - } - case DISPLAY_TOAST: { - Toast errorToast = Toast.makeText(getApplicationContext(), - msg.obj.toString(), Toast.LENGTH_LONG); - errorToast.show(); - break; - } - case HIDE_ZOOMCONTROLS: { - zoomControls.hide(); - break; - } - case SEND_MOVE_EVENT: { - LibFreeRDP.sendCursorEvent(session.getInstance(), msg.arg1, - msg.arg2, Mouse.getMoveEvent()); - break; - } - case SHOW_DIALOG: { - // create and show the dialog - ((Dialog) msg.obj).show(); - break; - } - case SCROLLING_REQUESTED: { - int scrollX = 0; - int scrollY = 0; - float[] pointerPos = touchPointerView.getPointerPosition(); + case GRAPHICS_CHANGED: { + sessionView.onSurfaceChange(session); + scrollView.requestLayout(); + break; + } + case REFRESH_SESSIONVIEW: { + sessionView.invalidateRegion(); + break; + } + case DISPLAY_TOAST: { + Toast errorToast = Toast.makeText(getApplicationContext(), + msg.obj.toString(), Toast.LENGTH_LONG); + errorToast.show(); + break; + } + case HIDE_ZOOMCONTROLS: { + zoomControls.hide(); + break; + } + case SEND_MOVE_EVENT: { + LibFreeRDP.sendCursorEvent(session.getInstance(), msg.arg1, + msg.arg2, Mouse.getMoveEvent()); + break; + } + case SHOW_DIALOG: { + // create and show the dialog + ((Dialog) msg.obj).show(); + break; + } + case SCROLLING_REQUESTED: { + int scrollX = 0; + int scrollY = 0; + float[] pointerPos = touchPointerView.getPointerPosition(); - if (pointerPos[0] > (screen_width - touchPointerView - .getPointerWidth())) - scrollX = SCROLLING_DISTANCE; - else if (pointerPos[0] < 0) - scrollX = -SCROLLING_DISTANCE; + if (pointerPos[0] > (screen_width - touchPointerView + .getPointerWidth())) + scrollX = SCROLLING_DISTANCE; + else if (pointerPos[0] < 0) + scrollX = -SCROLLING_DISTANCE; - if (pointerPos[1] > (screen_height - touchPointerView - .getPointerHeight())) - scrollY = SCROLLING_DISTANCE; - else if (pointerPos[1] < 0) - scrollY = -SCROLLING_DISTANCE; + if (pointerPos[1] > (screen_height - touchPointerView + .getPointerHeight())) + scrollY = SCROLLING_DISTANCE; + else if (pointerPos[1] < 0) + scrollY = -SCROLLING_DISTANCE; - scrollView.scrollBy(scrollX, scrollY); + scrollView.scrollBy(scrollX, scrollY); - // see if we reached the min/max scroll positions - if (scrollView.getScrollX() == 0 - || scrollView.getScrollX() == (sessionView.getWidth() - scrollView - .getWidth())) - scrollX = 0; - if (scrollView.getScrollY() == 0 - || scrollView.getScrollY() == (sessionView.getHeight() - scrollView - .getHeight())) - scrollY = 0; + // see if we reached the min/max scroll positions + if (scrollView.getScrollX() == 0 + || scrollView.getScrollX() == (sessionView.getWidth() - scrollView + .getWidth())) + scrollX = 0; + if (scrollView.getScrollY() == 0 + || scrollView.getScrollY() == (sessionView.getHeight() - scrollView + .getHeight())) + scrollY = 0; - if (scrollX != 0 || scrollY != 0) - uiHandler.sendEmptyMessageDelayed(SCROLLING_REQUESTED, - SCROLLING_TIMEOUT); - else - Log.v(TAG, "Stopping auto-scroll"); - break; - } + if (scrollX != 0 || scrollY != 0) + uiHandler.sendEmptyMessageDelayed(SCROLLING_REQUESTED, + SCROLLING_TIMEOUT); + else + Log.v(TAG, "Stopping auto-scroll"); + break; + } } } } @@ -216,16 +216,16 @@ public class SessionActivity extends ActionBarActivity implements return; switch (intent.getExtras().getInt(GlobalApp.EVENT_TYPE, -1)) { - case GlobalApp.FREERDP_EVENT_CONNECTION_SUCCESS: - OnConnectionSuccess(context); - break; + case GlobalApp.FREERDP_EVENT_CONNECTION_SUCCESS: + OnConnectionSuccess(context); + break; - case GlobalApp.FREERDP_EVENT_CONNECTION_FAILURE: - OnConnectionFailure(context); - break; - case GlobalApp.FREERDP_EVENT_DISCONNECTED: - OnDisconnected(context); - break; + case GlobalApp.FREERDP_EVENT_CONNECTION_FAILURE: + OnConnectionFailure(context); + break; + case GlobalApp.FREERDP_EVENT_DISCONNECTED: + OnDisconnected(context); + break; } } @@ -247,7 +247,7 @@ public class SessionActivity extends ActionBarActivity implements if (ConnectionReference.isHostnameReference(bundle .getString(PARAM_CONNECTION_REFERENCE))) { assert session.getBookmark().getType() == BookmarkBase.TYPE_MANUAL; - String item = session.getBookmark(). get() + String item = session.getBookmark().get() .getHostname(); if (!GlobalApp.getQuickConnectHistoryGateway() .historyItemExists(item)) @@ -361,7 +361,7 @@ public class SessionActivity extends ActionBarActivity implements new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, - int which) { + int which) { callbackDialogResult = true; synchronized (dialog) { dialog.notify(); @@ -372,7 +372,7 @@ public class SessionActivity extends ActionBarActivity implements new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, - int which) { + int which) { callbackDialogResult = false; connectCancelledByUser = true; synchronized (dialog) { @@ -391,7 +391,7 @@ public class SessionActivity extends ActionBarActivity implements new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, - int which) { + int which) { callbackDialogResult = true; synchronized (dialog) { dialog.notify(); @@ -402,7 +402,7 @@ public class SessionActivity extends ActionBarActivity implements new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, - int which) { + int which) { callbackDialogResult = false; connectCancelledByUser = true; synchronized (dialog) { @@ -415,14 +415,14 @@ public class SessionActivity extends ActionBarActivity implements private boolean hasHardwareMenuButton() { if (Build.VERSION.SDK_INT <= 10) return true; - + if (Build.VERSION.SDK_INT >= 14) { boolean rc = false; final ViewConfiguration cfg = ViewConfiguration.get(this); - + return cfg.hasPermanentMenuKey(); } - + return false; } @@ -626,7 +626,7 @@ public class SessionActivity extends ActionBarActivity implements String refStr = bundle.getString(PARAM_CONNECTION_REFERENCE); if (ConnectionReference.isHostnameReference(refStr)) { bookmark = new ManualBookmark(); - bookmark. get().setHostname( + bookmark.get().setHostname( ConnectionReference.getHostname(refStr)); } else if (ConnectionReference.isBookmarkReference(refStr)) { if (ConnectionReference.isManualBookmarkReference(refStr)) @@ -647,13 +647,9 @@ public class SessionActivity extends ActionBarActivity implements } private void connect(BookmarkBase bookmark) { - session = GlobalApp.createSession(bookmark); + session = GlobalApp.createSession(bookmark, getApplicationContext()); session.setUIEventListener(this); - // set writeable data directory - LibFreeRDP.setDataDirectory(session.getInstance(), getFilesDir() - .toString()); - BookmarkBase.ScreenSettings screenSettings = session.getBookmark() .getActiveScreenSettings(); Log.v(TAG, "Screen Resolution: " + screenSettings.getResolutionString()); @@ -712,7 +708,7 @@ public class SessionActivity extends ActionBarActivity implements // displays either the system or the extended keyboard or non of them private void showKeyboard(boolean showSystemKeyboard, - boolean showExtendedKeyboard) { + boolean showExtendedKeyboard) { // no matter what we are doing ... hide the zoom controls // TODO: this is not working correctly as hiding the keyboard issues a // onScrollChange notification showing the control again ... @@ -769,25 +765,25 @@ public class SessionActivity extends ActionBarActivity implements // check if any key is in the keycodes list List keys = modifiersKeyboard.getKeys(); - for (Iterator it = keys.iterator(); it.hasNext();) { + for (Iterator it = keys.iterator(); it.hasNext(); ) { // if the key is a sticky key - just set it to off Keyboard.Key curKey = it.next(); if (curKey.sticky) { switch (keyboardMapper.getModifierState(curKey.codes[0])) { - case KeyboardMapper.KEYSTATE_ON: - curKey.on = true; - curKey.pressed = false; - break; + case KeyboardMapper.KEYSTATE_ON: + curKey.on = true; + curKey.pressed = false; + break; - case KeyboardMapper.KEYSTATE_OFF: - curKey.on = false; - curKey.pressed = false; - break; + case KeyboardMapper.KEYSTATE_OFF: + curKey.on = false; + curKey.pressed = false; + break; - case KeyboardMapper.KEYSTATE_LOCKED: - curKey.on = true; - curKey.pressed = true; - break; + case KeyboardMapper.KEYSTATE_LOCKED: + curKey.on = true; + curKey.pressed = true; + break; } } } @@ -860,6 +856,15 @@ public class SessionActivity extends ActionBarActivity implements keyboardMapper.sendAltF4(); } + @Override + public boolean onKeyLongPress(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + LibFreeRDP.disconnect(session.getInstance()); + return true; + } + return super.onKeyLongPress(keyCode, event); + } + // android keyboard input handling // We always use the unicode value to process input from the android // keyboard except if key modifiers @@ -933,20 +938,20 @@ public class SessionActivity extends ActionBarActivity implements @Override public void switchKeyboard(int keyboardType) { switch (keyboardType) { - case KeyboardMapper.KEYBOARD_TYPE_FUNCTIONKEYS: - keyboardView.setKeyboard(specialkeysKeyboard); - break; + case KeyboardMapper.KEYBOARD_TYPE_FUNCTIONKEYS: + keyboardView.setKeyboard(specialkeysKeyboard); + break; - case KeyboardMapper.KEYBOARD_TYPE_NUMPAD: - keyboardView.setKeyboard(numpadKeyboard); - break; + case KeyboardMapper.KEYBOARD_TYPE_NUMPAD: + keyboardView.setKeyboard(numpadKeyboard); + break; - case KeyboardMapper.KEYBOARD_TYPE_CURSOR: - keyboardView.setKeyboard(cursorKeyboard); - break; + case KeyboardMapper.KEYBOARD_TYPE_CURSOR: + keyboardView.setKeyboard(cursorKeyboard); + break; - default: - break; + default: + break; } } @@ -1020,7 +1025,7 @@ public class SessionActivity extends ActionBarActivity implements @Override public boolean OnAuthenticate(StringBuilder username, StringBuilder domain, - StringBuilder password) { + StringBuilder password) { // this is where the return code of our dialog will be stored callbackDialogResult = false; @@ -1062,7 +1067,7 @@ public class SessionActivity extends ActionBarActivity implements @Override public boolean OnVerifiyCertificate(String subject, String issuer, - String fingerprint) { + String fingerprint) { // see if global settings says accept all if (GlobalSettings.getAcceptAllCertificates()) @@ -1109,7 +1114,7 @@ public class SessionActivity extends ActionBarActivity implements @Override public void onScrollChanged(ScrollView2D scrollView, int x, int y, - int oldx, int oldy) { + int oldx, int oldy) { zoomControls.setIsZoomInEnabled(!sessionView.isAtMaxZoom()); zoomControls.setIsZoomOutEnabled(!sessionView.isAtMinZoom()); if (!GlobalSettings.getHideZoomControls() diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/presentation/SessionView.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/SessionView.java similarity index 99% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/presentation/SessionView.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/SessionView.java index ea2b0cc07..6d0780690 100644 --- a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/presentation/SessionView.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/SessionView.java @@ -28,6 +28,8 @@ import com.freerdp.freerdpcore.utils.GestureDetector; public class SessionView extends View { + private static final String TAG = "SessionView"; + public interface SessionViewListener { abstract void onSessionViewBeginTouch(); abstract void onSessionViewEndTouch(); @@ -291,7 +293,7 @@ public class SessionView extends View @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - Log.v("SessionView", width + "x" + height); + Log.v(TAG, width + "x" + height); this.setMeasuredDimension((int)(width * scaleFactor) + touchPointerPaddingWidth, (int)(height * scaleFactor) + touchPointerPaddingHeight); } diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/presentation/ShortcutsActivity.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/ShortcutsActivity.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/presentation/ShortcutsActivity.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/ShortcutsActivity.java diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/presentation/TouchPointerView.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/TouchPointerView.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/presentation/TouchPointerView.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/presentation/TouchPointerView.java diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/services/BookmarkBaseGateway.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/BookmarkBaseGateway.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/services/BookmarkBaseGateway.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/BookmarkBaseGateway.java diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/BookmarkDB.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/BookmarkDB.java new file mode 100644 index 000000000..7796f440a --- /dev/null +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/BookmarkDB.java @@ -0,0 +1,227 @@ +/* + Android Bookmark Database + + Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz + + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ + +package com.freerdp.freerdpcore.services; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import android.content.Context; +import android.provider.BaseColumns; +import android.util.Log; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +public class BookmarkDB extends SQLiteOpenHelper { + private static final int DB_VERSION = 7; + private static final String DB_NAME = "bookmarks.db"; + + public static final String ID = BaseColumns._ID; + + public BookmarkDB(Context context) { + super(context, DB_NAME, null, DB_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase db) { + String sqlScreenSettings = + "CREATE TABLE tbl_screen_settings (" + + ID + " INTEGER PRIMARY KEY, " + + "colors INTEGER DEFAULT 16, " + + "resolution INTEGER DEFAULT 0, " + + "width, " + + "height);"; + + db.execSQL(sqlScreenSettings); + + String sqlPerformanceFlags = + "CREATE TABLE tbl_performance_flags (" + + ID + " INTEGER PRIMARY KEY, " + + "perf_remotefx INTEGER, " + + "perf_gfx INTEGER," + + "perf_gfx_h264 INTEGER," + + "perf_wallpaper INTEGER, " + + "perf_theming INTEGER, " + + "perf_full_window_drag INTEGER, " + + "perf_menu_animations INTEGER, " + + "perf_font_smoothing INTEGER, " + + "perf_desktop_composition INTEGER);"; + + db.execSQL(sqlPerformanceFlags); + + String sqlManualBookmarks = getManualBookmarksCreationString(); + db.execSQL(sqlManualBookmarks); + + + // Insert a test entry + String sqlInsertDefaultScreenEntry = + "INSERT INTO tbl_screen_settings (" + + "colors, " + + "resolution, " + + "width, " + + "height) " + + "VALUES ( " + + "32, 1, 1024, 768);"; + db.execSQL(sqlInsertDefaultScreenEntry); + db.execSQL(sqlInsertDefaultScreenEntry); + + String sqlInsertDefaultPerfFlags = + "INSERT INTO tbl_performance_flags (" + + "perf_remotefx, " + + "perf_gfx" + + "perf_gfx_h264" + + "perf_wallpaper, " + + "perf_theming, " + + "perf_full_window_drag, " + + "perf_menu_animations, " + + "perf_font_smoothing, " + + "perf_desktop_composition) " + + "VALUES ( " + + "1, 1, 1, 0, 0, 0, 0, 0, 0);"; + db.execSQL(sqlInsertDefaultPerfFlags); + db.execSQL(sqlInsertDefaultPerfFlags); + + String sqlInsertDefaultSessionEntry = + "INSERT INTO tbl_manual_bookmarks (" + + "label, " + + "hostname, " + + "username, " + + "password, " + + "domain, " + + "port, " + + "screen_settings, " + + "performance_flags, " + + "screen_3g, " + + "performance_3g, " + + "redirect_sdcard, " + + "redirect_sound, " + + "redirect_microphone, " + + "security, " + + "remote_program, " + + "work_dir, " + + "async_channel, " + + "async_transport, " + + "async_input, " + + "async_update, " + + "console_mode, " + + "debug_level ) " + + "VALUES ( " + + "'Test Server', " + + "'testservice.afreerdp.com', " + + "'', " + + "'', " + + "'', " + + "3389, " + + "1, 1, 2, 2, 0, 0, 0, 0, " + + "'', '', " + + "1, 1, 1, 1, 0, 0);"; + db.execSQL(sqlInsertDefaultSessionEntry); + } + + private String getManualBookmarksCreationString() { + return ( + "CREATE TABLE IF NOT EXISTS tbl_manual_bookmarks (" + + ID + " INTEGER PRIMARY KEY, " + + "label TEXT NOT NULL, " + + "hostname TEXT NOT NULL, " + + "username TEXT NOT NULL, " + + "password TEXT, " + + "domain TEXT, " + + "port TEXT, " + + "screen_settings INTEGER NOT NULL, " + + "performance_flags INTEGER NOT NULL, " + + + "enable_gateway_settings INTEGER DEFAULT 0, " + + "gateway_hostname TEXT, " + + "gateway_port INTEGER DEFAULT 443, " + + "gateway_username TEXT, " + + "gateway_password TEXT, " + + "gateway_domain TEXT, " + + + "enable_3g_settings INTEGER DEFAULT 0, " + + "screen_3g INTEGER NOT NULL, " + + "performance_3g INTEGER NOT NULL, " + + "redirect_sdcard INTEGER DEFAULT 0, " + + "redirect_sound INTEGER DEFAULT 0, " + + "redirect_microphone INTEGER DEFAULT 0, " + + "security INTEGER, " + + "remote_program TEXT, " + + "work_dir TEXT, " + + "async_channel INTEGER DEFAULT 0, " + + "async_transport INTEGER DEFAULT 0, " + + "async_input INTEGER DEFAULT 0, " + + "async_update INTEGER DEFAULT 0, " + + "console_mode INTEGER, " + + "debug_level INTEGER DEFAULT 0, " + + + "FOREIGN KEY(screen_settings) REFERENCES tbl_screen_settings(" + ID + "), " + + "FOREIGN KEY(performance_flags) REFERENCES tbl_performance_flags(" + ID + "), " + + "FOREIGN KEY(screen_3g) REFERENCES tbl_screen_settings(" + ID + "), " + + "FOREIGN KEY(performance_3g) REFERENCES tbl_performance_flags(" + ID + ") " + + + ");"); + } + + // from http://stackoverflow.com/questions/3424156/upgrade-sqlite-database-from-one-version-to-another + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + db.beginTransaction(); + + // run a table creation with if not exists (we are doing an upgrade, so the table might + // not exists yet, it will fail alter and drop) + db.execSQL(getManualBookmarksCreationString()); + // put in a list the existing columns + List columns = GetColumns(db, "tbl_manual_bookmarks"); + // backup table + db.execSQL("ALTER TABLE tbl_manual_bookmarks RENAME TO 'temp_tbl_manual_bookmarks'"); + // create new table (with new scheme) + db.execSQL(getManualBookmarksCreationString()); + // get the intersection with the new columns, this time columns taken from the upgraded table + columns.retainAll(GetColumns(db, "tbl_manual_bookmarks")); + // restore data + String cols = joinStrings(columns, ","); + db.execSQL(String.format("INSERT INTO %s (%s) SELECT %s from 'temp_%s", "tbl_manual_bookmarks", cols, cols, "tbl_manual_bookmarks'")); + // remove backup table + db.execSQL("DROP table 'temp_tbl_manual_bookmarks'"); + + db.setTransactionSuccessful(); + db.endTransaction(); + } + + private static List GetColumns(SQLiteDatabase db, String tableName) { + List ar = null; + Cursor c = null; + try { + c = db.rawQuery("SELECT * FROM " + tableName + " LIMIT 1", null); + if (c != null) { + ar = new ArrayList(Arrays.asList(c.getColumnNames())); + } + } catch (Exception e) { + Log.v(tableName, e.getMessage(), e); + e.printStackTrace(); + } finally { + if (c != null) + c.close(); + } + return ar; + } + + private static String joinStrings(List list, String delim) { + StringBuilder buf = new StringBuilder(); + int num = list.size(); + for (int i = 0; i < num; i++) { + if (i != 0) + buf.append(delim); + buf.append((String) list.get(i)); + } + return buf.toString(); + } +} diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/services/FreeRDPSuggestionProvider.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/FreeRDPSuggestionProvider.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/services/FreeRDPSuggestionProvider.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/FreeRDPSuggestionProvider.java diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/services/HistoryDB.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/HistoryDB.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/services/HistoryDB.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/HistoryDB.java diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/LibFreeRDP.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/LibFreeRDP.java new file mode 100644 index 000000000..c07a5d26e --- /dev/null +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/LibFreeRDP.java @@ -0,0 +1,373 @@ +/* + Android FreeRDP JNI Wrapper + + Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz + + This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +*/ + +package com.freerdp.freerdpcore.services; + + +import com.freerdp.freerdpcore.application.GlobalApp; +import com.freerdp.freerdpcore.application.SessionState; +import com.freerdp.freerdpcore.domain.BookmarkBase; +import com.freerdp.freerdpcore.domain.ManualBookmark; + +import android.content.Context; +import android.graphics.Bitmap; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +public class LibFreeRDP { + private static final String TAG = "LibFreeRDP"; + + static { + final String[] libraries = { + "openh264", "crypto", "ssl", "jpeg", "winpr", + "freerdp", "freerdp-client", "freerdp-android"}; + final String LD_PATH = System.getProperty("java.library.path"); + + for (String lib : libraries) { + try { + Log.v(TAG, "Trying to load library " + lib + " from LD_PATH: " + LD_PATH); + System.loadLibrary(lib); + } catch (UnsatisfiedLinkError e) { + Log.e(TAG, "Failed to load library " + lib + ": " + e.toString()); + } + } + } + + private static native String freerdp_get_jni_version(); + + private static native String freerdp_get_version(); + + private static native String freerdp_get_build_date(); + + private static native String freerdp_get_build_revision(); + + private static native String freerdp_get_build_config(); + + private static native int freerdp_new(Context context); + + private static native void freerdp_free(int inst); + + private static native boolean freerdp_parse_arguments(int inst, String[] args); + + private static native boolean freerdp_connect(int inst); + + private static native boolean freerdp_disconnect(int inst); + + private static native boolean freerdp_update_graphics(int inst, + Bitmap bitmap, int x, int y, int width, int height); + + private static native boolean freerdp_send_cursor_event(int inst, int x, int y, int flags); + + private static native boolean freerdp_send_key_event(int inst, int keycode, boolean down); + + private static native boolean freerdp_send_unicodekey_event(int inst, int keycode); + + private static native boolean freerdp_send_clipboard_data(int inst, String data); + + public static interface EventListener { + void OnPreConnect(int instance); + + void OnConnectionSuccess(int instance); + + void OnConnectionFailure(int instance); + + void OnDisconnecting(int instance); + + void OnDisconnected(int instance); + } + + public static interface UIEventListener { + void OnSettingsChanged(int width, int height, int bpp); + + boolean OnAuthenticate(StringBuilder username, StringBuilder domain, StringBuilder password); + + boolean OnVerifiyCertificate(String subject, String issuer, String fingerprint); + + void OnGraphicsUpdate(int x, int y, int width, int height); + + void OnGraphicsResize(int width, int height, int bpp); + + void OnRemoteClipboardChanged(String data); + } + + private static EventListener listener; + + public static void setEventListener(EventListener l) { + listener = l; + } + + public static int newInstance(Context context) { + return freerdp_new(context); + } + + public static void freeInstance(int inst) { + freerdp_free(inst); + } + + public static boolean connect(int inst) { + return freerdp_connect(inst); + } + + public static boolean disconnect(int inst) { + return freerdp_disconnect(inst); + } + + public static boolean cancelConnection(int inst) { + return freerdp_disconnect(inst); + } + + private static String addFlag(String name, boolean enabled) { + if (enabled) { + return "+" + name; + } + return "-" + name; + } + + public static boolean setConnectionInfo(int inst, BookmarkBase bookmark) { + BookmarkBase.ScreenSettings screenSettings = bookmark.getActiveScreenSettings(); + BookmarkBase.AdvancedSettings advanced = bookmark.getAdvancedSettings(); + BookmarkBase.DebugSettings debug = bookmark.getDebugSettings(); + + String arg; + ArrayList args = new ArrayList(); + + args.add(TAG); + args.add("/gdi:sw"); + + String certName = ""; + if (bookmark.getType() != BookmarkBase.TYPE_MANUAL) { + return false; + } + + int port = bookmark.get().getPort(); + String hostname = bookmark.get().getHostname(); + + args.add("/v:" + hostname); + args.add("/port:" + String.valueOf(port)); + + arg = bookmark.getUsername(); + if (!arg.isEmpty()) { + args.add("/u:" + arg); + } + arg = bookmark.getDomain(); + if (!arg.isEmpty()) { + args.add("/d:" + arg); + } + arg = bookmark.getPassword(); + if (!arg.isEmpty()) { + args.add("/p:" + arg); + } + + args.add(String.format("/size:%dx%d", screenSettings.getWidth(), + screenSettings.getHeight())); + args.add("/bpp:" + String.valueOf(screenSettings.getColors())); + + if (advanced.getConsoleMode()) { + args.add("/admin"); + } + + switch (advanced.getSecurity()) { + case 3: // NLA + args.add("/sec-nla"); + break; + case 2: // TLS + args.add("/sec-tls"); + break; + case 1: // RDP + args.add("/sec-rdp"); + break; + default: + break; + } + + if (!certName.isEmpty()) { + args.add("/cert-name:" + certName); + } + + BookmarkBase.PerformanceFlags flags = bookmark.getActivePerformanceFlags(); + if (flags.getRemoteFX()) { + args.add("/rfx"); + } + + if (flags.getGfx()) { + args.add("/gfx"); + } + + if (flags.getH264()) { + args.add("/h264"); + } + + args.add(addFlag("wallpaper", flags.getWallpaper())); + args.add(addFlag("window-drag", flags.getFullWindowDrag())); + args.add(addFlag("menu-anims", flags.getMenuAnimations())); + args.add(addFlag("themes", flags.getTheming())); + args.add(addFlag("fonts", flags.getFontSmoothing())); + args.add(addFlag("aero", flags.getDesktopComposition())); + + if (!advanced.getRemoteProgram().isEmpty()) { + args.add("/app:" + advanced.getRemoteProgram()); + } + + if (!advanced.getWorkDir().isEmpty()) { + args.add("/shell-dir:" + advanced.getWorkDir()); + } + + args.add(addFlag("async-channels", debug.getAsyncChannel())); + args.add(addFlag("async-transport", debug.getAsyncTransport())); + args.add(addFlag("async-input", debug.getAsyncInput())); + args.add(addFlag("async-update", debug.getAsyncUpdate())); + + if (advanced.getRedirectSDCard()) { + String path = android.os.Environment.getExternalStorageDirectory().getPath(); + args.add("/drive:sdcard," + path); + } + + args.add("/clipboard"); + + // Gateway enabled? + if (bookmark.getType() == BookmarkBase.TYPE_MANUAL && bookmark.get().getEnableGatewaySettings()) { + ManualBookmark.GatewaySettings gateway = bookmark.get().getGatewaySettings(); + + args.add(String.format("/g:%s:%d", gateway.getHostname(), gateway.getPort())); + + arg = gateway.getUsername(); + if (!arg.isEmpty()) { + args.add("/gu:" + arg); + } + arg = gateway.getDomain(); + if (!arg.isEmpty()) { + args.add("/gd:" + arg); + } + arg = gateway.getPassword(); + if (!arg.isEmpty()) { + args.add("/gp:" + arg); + } + } + + /* 0 ... disable + 1 ... local + 2 ... remote */ + args.add("/audio-mode:" + String.valueOf(advanced.getRedirectSound())); + + if (advanced.getRedirectMicrophone()) { + args.add("/microphone"); + } + + args.add("/log-level:TRACE"); + String[] arrayArgs = args.toArray(new String[args.size()]); + return freerdp_parse_arguments(inst, arrayArgs); + } + + public static boolean updateGraphics(int inst, Bitmap bitmap, int x, int y, int width, int height) { + return freerdp_update_graphics(inst, bitmap, x, y, width, height); + } + + public static boolean sendCursorEvent(int inst, int x, int y, int flags) { + return freerdp_send_cursor_event(inst, x, y, flags); + } + + public static boolean sendKeyEvent(int inst, int keycode, boolean down) { + return freerdp_send_key_event(inst, keycode, down); + } + + public static boolean sendUnicodeKeyEvent(int inst, int keycode) { + return freerdp_send_unicodekey_event(inst, keycode); + } + + public static boolean sendClipboardData(int inst, String data) { + return freerdp_send_clipboard_data(inst, data); + } + + private static void OnConnectionSuccess(int inst) { + if (listener != null) + listener.OnConnectionSuccess(inst); + } + + private static void OnConnectionFailure(int inst) { + if (listener != null) + listener.OnConnectionFailure(inst); + } + + private static void OnPreConnect(int inst) { + if (listener != null) + listener.OnPreConnect(inst); + } + + private static void OnDisconnecting(int inst) { + if (listener != null) + listener.OnDisconnecting(inst); + } + + private static void OnDisconnected(int inst) { + if (listener != null) + listener.OnDisconnected(inst); + } + + private static void OnSettingsChanged(int inst, int width, int height, int bpp) { + SessionState s = GlobalApp.getSession(inst); + if (s == null) + return; + UIEventListener uiEventListener = s.getUIEventListener(); + if (uiEventListener != null) + uiEventListener.OnSettingsChanged(width, height, bpp); + } + + private static boolean OnAuthenticate(int inst, StringBuilder username, StringBuilder domain, StringBuilder password) { + SessionState s = GlobalApp.getSession(inst); + if (s == null) + return false; + UIEventListener uiEventListener = s.getUIEventListener(); + if (uiEventListener != null) + return uiEventListener.OnAuthenticate(username, domain, password); + return false; + } + + private static boolean OnVerifyCertificate(int inst, String subject, String issuer, String fingerprint) { + SessionState s = GlobalApp.getSession(inst); + if (s == null) + return false; + UIEventListener uiEventListener = s.getUIEventListener(); + if (uiEventListener != null) + return uiEventListener.OnVerifiyCertificate(subject, issuer, fingerprint); + return false; + } + + private static void OnGraphicsUpdate(int inst, int x, int y, int width, int height) { + SessionState s = GlobalApp.getSession(inst); + if (s == null) + return; + UIEventListener uiEventListener = s.getUIEventListener(); + if (uiEventListener != null) + uiEventListener.OnGraphicsUpdate(x, y, width, height); + } + + private static void OnGraphicsResize(int inst, int width, int height, int bpp) { + SessionState s = GlobalApp.getSession(inst); + if (s == null) + return; + UIEventListener uiEventListener = s.getUIEventListener(); + if (uiEventListener != null) + uiEventListener.OnGraphicsResize(width, height, bpp); + } + + private static void OnRemoteClipboardChanged(int inst, String data) { + SessionState s = GlobalApp.getSession(inst); + if (s == null) + return; + UIEventListener uiEventListener = s.getUIEventListener(); + if (uiEventListener != null) + uiEventListener.OnRemoteClipboardChanged(data); + } + + public static String getVersion() { + return freerdp_get_version(); + } +} diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/services/ManualBookmarkGateway.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/ManualBookmarkGateway.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/services/ManualBookmarkGateway.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/ManualBookmarkGateway.java diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/services/QuickConnectHistoryGateway.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/QuickConnectHistoryGateway.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/services/QuickConnectHistoryGateway.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/QuickConnectHistoryGateway.java diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/services/SessionRequestHandlerActivity.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/SessionRequestHandlerActivity.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/services/SessionRequestHandlerActivity.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/SessionRequestHandlerActivity.java diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/utils/BookmarkArrayAdapter.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/BookmarkArrayAdapter.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/utils/BookmarkArrayAdapter.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/BookmarkArrayAdapter.java diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/utils/ButtonPreference.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/ButtonPreference.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/utils/ButtonPreference.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/ButtonPreference.java diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/utils/ClipboardManagerProxy.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/ClipboardManagerProxy.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/utils/ClipboardManagerProxy.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/ClipboardManagerProxy.java diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/utils/DoubleGestureDetector.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/DoubleGestureDetector.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/utils/DoubleGestureDetector.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/DoubleGestureDetector.java diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/utils/GestureDetector.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/GestureDetector.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/utils/GestureDetector.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/GestureDetector.java diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/utils/IntEditTextPreference.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/IntEditTextPreference.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/utils/IntEditTextPreference.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/IntEditTextPreference.java diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/utils/IntListPreference.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/IntListPreference.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/utils/IntListPreference.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/IntListPreference.java diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/utils/KeyboardMapper.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/KeyboardMapper.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/utils/KeyboardMapper.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/KeyboardMapper.java diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/utils/Mouse.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/Mouse.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/utils/Mouse.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/Mouse.java diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/utils/RDPFileParser.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/RDPFileParser.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/utils/RDPFileParser.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/RDPFileParser.java diff --git a/client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/utils/SeparatedListAdapter.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/SeparatedListAdapter.java similarity index 100% rename from client/Android/FreeRDPCore/src/com/freerdp/freerdpcore/utils/SeparatedListAdapter.java rename to client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/SeparatedListAdapter.java diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_button_add.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_button_add.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-hdpi/icon_button_add.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_button_add.png diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_edittext_clear.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_edittext_clear.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-hdpi/icon_edittext_clear.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_edittext_clear.png diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_edittext_search.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_edittext_search.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-hdpi/icon_edittext_search.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_edittext_search.png diff --git a/client/Android/aFreeRDP/res/drawable-hdpi/icon_launcher_freerdp.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_launcher_freerdp.png similarity index 100% rename from client/Android/aFreeRDP/res/drawable-hdpi/icon_launcher_freerdp.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_launcher_freerdp.png diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_about.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_menu_about.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_about.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_menu_about.png diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_add.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_menu_add.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_add.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_menu_add.png diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_close.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_menu_close.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_close.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_menu_close.png diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_disconnect.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_menu_disconnect.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_disconnect.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_menu_disconnect.png diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_ext_keyboard.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_menu_ext_keyboard.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_ext_keyboard.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_menu_ext_keyboard.png diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_help.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_menu_help.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_help.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_menu_help.png diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_preferences.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_menu_preferences.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_preferences.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_menu_preferences.png diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_settings.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_menu_settings.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_settings.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_menu_settings.png diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_sys_keyboard.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_menu_sys_keyboard.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_sys_keyboard.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_menu_sys_keyboard.png diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_touch_pointer.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_menu_touch_pointer.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-hdpi/icon_menu_touch_pointer.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_menu_touch_pointer.png diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_star_off.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_star_off.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-hdpi/icon_star_off.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_star_off.png diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/icon_star_on.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_star_on.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-hdpi/icon_star_on.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/icon_star_on.png diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/search_plate.9.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/search_plate.9.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-hdpi/search_plate.9.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/search_plate.9.png diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/sym_keyboard_delete.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/sym_keyboard_delete.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-hdpi/sym_keyboard_delete.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/sym_keyboard_delete.png diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/sym_keyboard_feedback_delete.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/sym_keyboard_feedback_delete.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-hdpi/sym_keyboard_feedback_delete.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/sym_keyboard_feedback_delete.png diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/sym_keyboard_feedback_return.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/sym_keyboard_feedback_return.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-hdpi/sym_keyboard_feedback_return.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/sym_keyboard_feedback_return.png diff --git a/client/Android/FreeRDPCore/res/drawable-hdpi/sym_keyboard_return.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/sym_keyboard_return.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-hdpi/sym_keyboard_return.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-hdpi/sym_keyboard_return.png diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_button_add.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_button_add.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-ldpi/icon_button_add.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_button_add.png diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_edittext_search.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_edittext_search.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-ldpi/icon_edittext_search.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_edittext_search.png diff --git a/client/Android/aFreeRDP/res/drawable-ldpi/icon_launcher_freerdp.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_launcher_freerdp.png similarity index 100% rename from client/Android/aFreeRDP/res/drawable-ldpi/icon_launcher_freerdp.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_launcher_freerdp.png diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_about.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_menu_about.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_about.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_menu_about.png diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_add.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_menu_add.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_add.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_menu_add.png diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_disconnect.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_menu_disconnect.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_disconnect.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_menu_disconnect.png diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_exit.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_menu_exit.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_exit.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_menu_exit.png diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_ext_keyboard.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_menu_ext_keyboard.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_ext_keyboard.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_menu_ext_keyboard.png diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_help.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_menu_help.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_help.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_menu_help.png diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_preferences.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_menu_preferences.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_preferences.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_menu_preferences.png diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_settings.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_menu_settings.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_settings.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_menu_settings.png diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_sys_keyboard.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_menu_sys_keyboard.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_sys_keyboard.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_menu_sys_keyboard.png diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_touch_pointer.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_menu_touch_pointer.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-ldpi/icon_menu_touch_pointer.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_menu_touch_pointer.png diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_star_off.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_star_off.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-ldpi/icon_star_off.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_star_off.png diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/icon_star_on.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_star_on.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-ldpi/icon_star_on.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/icon_star_on.png diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/search_plate.9.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/search_plate.9.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-ldpi/search_plate.9.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/search_plate.9.png diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/sym_keyboard_delete.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/sym_keyboard_delete.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-ldpi/sym_keyboard_delete.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/sym_keyboard_delete.png diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/sym_keyboard_feedback_delete.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/sym_keyboard_feedback_delete.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-ldpi/sym_keyboard_feedback_delete.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/sym_keyboard_feedback_delete.png diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/sym_keyboard_feedback_return.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/sym_keyboard_feedback_return.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-ldpi/sym_keyboard_feedback_return.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/sym_keyboard_feedback_return.png diff --git a/client/Android/FreeRDPCore/res/drawable-ldpi/sym_keyboard_return.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/sym_keyboard_return.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-ldpi/sym_keyboard_return.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-ldpi/sym_keyboard_return.png diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_button_add.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_button_add.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-mdpi/icon_button_add.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_button_add.png diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_edittext_clear.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_edittext_clear.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-mdpi/icon_edittext_clear.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_edittext_clear.png diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_edittext_search.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_edittext_search.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-mdpi/icon_edittext_search.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_edittext_search.png diff --git a/client/Android/aFreeRDP/res/drawable-mdpi/icon_launcher_freerdp.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_launcher_freerdp.png similarity index 100% rename from client/Android/aFreeRDP/res/drawable-mdpi/icon_launcher_freerdp.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_launcher_freerdp.png diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_about.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_menu_about.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_about.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_menu_about.png diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_add.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_menu_add.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_add.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_menu_add.png diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_disconnect.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_menu_disconnect.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_disconnect.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_menu_disconnect.png diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_exit.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_menu_exit.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_exit.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_menu_exit.png diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_ext_keyboard.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_menu_ext_keyboard.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_ext_keyboard.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_menu_ext_keyboard.png diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_help.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_menu_help.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_help.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_menu_help.png diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_preferences.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_menu_preferences.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_preferences.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_menu_preferences.png diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_settings.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_menu_settings.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_settings.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_menu_settings.png diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_sys_keyboard.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_menu_sys_keyboard.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_sys_keyboard.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_menu_sys_keyboard.png diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_touch_pointer.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_menu_touch_pointer.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-mdpi/icon_menu_touch_pointer.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_menu_touch_pointer.png diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_star_off.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_star_off.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-mdpi/icon_star_off.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_star_off.png diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/icon_star_on.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_star_on.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-mdpi/icon_star_on.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/icon_star_on.png diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/search_plate.9.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/search_plate.9.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-mdpi/search_plate.9.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/search_plate.9.png diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/sym_keyboard_delete.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/sym_keyboard_delete.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-mdpi/sym_keyboard_delete.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/sym_keyboard_delete.png diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/sym_keyboard_feedback_delete.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/sym_keyboard_feedback_delete.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-mdpi/sym_keyboard_feedback_delete.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/sym_keyboard_feedback_delete.png diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/sym_keyboard_feedback_return.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/sym_keyboard_feedback_return.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-mdpi/sym_keyboard_feedback_return.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/sym_keyboard_feedback_return.png diff --git a/client/Android/FreeRDPCore/res/drawable-mdpi/sym_keyboard_return.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/sym_keyboard_return.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable-mdpi/sym_keyboard_return.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable-mdpi/sym_keyboard_return.png diff --git a/client/Android/aFreeRDP/res/drawable/button_background.xml b/client/Android/Studio/freeRDPCore/src/main/res/drawable/button_background.xml similarity index 100% rename from client/Android/aFreeRDP/res/drawable/button_background.xml rename to client/Android/Studio/freeRDPCore/src/main/res/drawable/button_background.xml diff --git a/client/Android/FreeRDPCore/res/drawable/icon_button_cancel.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable/icon_button_cancel.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable/icon_button_cancel.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable/icon_button_cancel.png diff --git a/client/Android/aFreeRDP/res/drawable/icon_launcher_freerdp.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable/icon_launcher_freerdp.png similarity index 100% rename from client/Android/aFreeRDP/res/drawable/icon_launcher_freerdp.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable/icon_launcher_freerdp.png diff --git a/client/Android/aFreeRDP/res/drawable/separator_background.xml b/client/Android/Studio/freeRDPCore/src/main/res/drawable/separator_background.xml similarity index 100% rename from client/Android/aFreeRDP/res/drawable/separator_background.xml rename to client/Android/Studio/freeRDPCore/src/main/res/drawable/separator_background.xml diff --git a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_arrows.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable/sym_keyboard_arrows.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable/sym_keyboard_arrows.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable/sym_keyboard_arrows.png diff --git a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_arrows_black.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable/sym_keyboard_arrows_black.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable/sym_keyboard_arrows_black.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable/sym_keyboard_arrows_black.png diff --git a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_down_arrow.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable/sym_keyboard_down_arrow.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable/sym_keyboard_down_arrow.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable/sym_keyboard_down_arrow.png diff --git a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_down_arrow_black.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable/sym_keyboard_down_arrow_black.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable/sym_keyboard_down_arrow_black.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable/sym_keyboard_down_arrow_black.png diff --git a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_left_arrow.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable/sym_keyboard_left_arrow.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable/sym_keyboard_left_arrow.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable/sym_keyboard_left_arrow.png diff --git a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_left_arrow_black.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable/sym_keyboard_left_arrow_black.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable/sym_keyboard_left_arrow_black.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable/sym_keyboard_left_arrow_black.png diff --git a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_menu.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable/sym_keyboard_menu.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable/sym_keyboard_menu.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable/sym_keyboard_menu.png diff --git a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_menu_black.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable/sym_keyboard_menu_black.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable/sym_keyboard_menu_black.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable/sym_keyboard_menu_black.png diff --git a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_right_arrow.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable/sym_keyboard_right_arrow.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable/sym_keyboard_right_arrow.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable/sym_keyboard_right_arrow.png diff --git a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_right_arrow_black.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable/sym_keyboard_right_arrow_black.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable/sym_keyboard_right_arrow_black.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable/sym_keyboard_right_arrow_black.png diff --git a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_up_arrow.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable/sym_keyboard_up_arrow.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable/sym_keyboard_up_arrow.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable/sym_keyboard_up_arrow.png diff --git a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_up_arrow_black.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable/sym_keyboard_up_arrow_black.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable/sym_keyboard_up_arrow_black.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable/sym_keyboard_up_arrow_black.png diff --git a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_winkey.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable/sym_keyboard_winkey.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable/sym_keyboard_winkey.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable/sym_keyboard_winkey.png diff --git a/client/Android/FreeRDPCore/res/drawable/sym_keyboard_winkey_black.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable/sym_keyboard_winkey_black.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable/sym_keyboard_winkey_black.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable/sym_keyboard_winkey_black.png diff --git a/client/Android/FreeRDPCore/res/drawable/touch_pointer_active.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable/touch_pointer_active.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable/touch_pointer_active.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable/touch_pointer_active.png diff --git a/client/Android/FreeRDPCore/res/drawable/touch_pointer_default.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable/touch_pointer_default.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable/touch_pointer_default.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable/touch_pointer_default.png diff --git a/client/Android/FreeRDPCore/res/drawable/touch_pointer_extkeyboard.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable/touch_pointer_extkeyboard.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable/touch_pointer_extkeyboard.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable/touch_pointer_extkeyboard.png diff --git a/client/Android/FreeRDPCore/res/drawable/touch_pointer_keyboard.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable/touch_pointer_keyboard.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable/touch_pointer_keyboard.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable/touch_pointer_keyboard.png diff --git a/client/Android/FreeRDPCore/res/drawable/touch_pointer_lclick.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable/touch_pointer_lclick.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable/touch_pointer_lclick.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable/touch_pointer_lclick.png diff --git a/client/Android/FreeRDPCore/res/drawable/touch_pointer_rclick.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable/touch_pointer_rclick.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable/touch_pointer_rclick.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable/touch_pointer_rclick.png diff --git a/client/Android/FreeRDPCore/res/drawable/touch_pointer_reset.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable/touch_pointer_reset.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable/touch_pointer_reset.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable/touch_pointer_reset.png diff --git a/client/Android/FreeRDPCore/res/drawable/touch_pointer_scroll.png b/client/Android/Studio/freeRDPCore/src/main/res/drawable/touch_pointer_scroll.png similarity index 100% rename from client/Android/FreeRDPCore/res/drawable/touch_pointer_scroll.png rename to client/Android/Studio/freeRDPCore/src/main/res/drawable/touch_pointer_scroll.png diff --git a/client/Android/FreeRDPCore/res/layout/bookmark_list_item.xml b/client/Android/Studio/freeRDPCore/src/main/res/layout/bookmark_list_item.xml similarity index 100% rename from client/Android/FreeRDPCore/res/layout/bookmark_list_item.xml rename to client/Android/Studio/freeRDPCore/src/main/res/layout/bookmark_list_item.xml diff --git a/client/Android/FreeRDPCore/res/layout/button_preference.xml b/client/Android/Studio/freeRDPCore/src/main/res/layout/button_preference.xml similarity index 100% rename from client/Android/FreeRDPCore/res/layout/button_preference.xml rename to client/Android/Studio/freeRDPCore/src/main/res/layout/button_preference.xml diff --git a/client/Android/FreeRDPCore/res/layout/credentials.xml b/client/Android/Studio/freeRDPCore/src/main/res/layout/credentials.xml similarity index 100% rename from client/Android/FreeRDPCore/res/layout/credentials.xml rename to client/Android/Studio/freeRDPCore/src/main/res/layout/credentials.xml diff --git a/client/Android/FreeRDPCore/res/layout/dont_show_again_dialog.xml b/client/Android/Studio/freeRDPCore/src/main/res/layout/dont_show_again_dialog.xml similarity index 100% rename from client/Android/FreeRDPCore/res/layout/dont_show_again_dialog.xml rename to client/Android/Studio/freeRDPCore/src/main/res/layout/dont_show_again_dialog.xml diff --git a/client/Android/FreeRDPCore/res/layout/home.xml b/client/Android/Studio/freeRDPCore/src/main/res/layout/home.xml similarity index 95% rename from client/Android/FreeRDPCore/res/layout/home.xml rename to client/Android/Studio/freeRDPCore/src/main/res/layout/home.xml index bc311f573..519bd8327 100644 --- a/client/Android/FreeRDPCore/res/layout/home.xml +++ b/client/Android/Studio/freeRDPCore/src/main/res/layout/home.xml @@ -1,4 +1,4 @@ - + Ja diff --git a/client/Android/FreeRDPCore/res/values-es/strings.xml b/client/Android/Studio/freeRDPCore/src/main/res/values-es/strings.xml similarity index 97% rename from client/Android/FreeRDPCore/res/values-es/strings.xml rename to client/Android/Studio/freeRDPCore/src/main/res/values-es/strings.xml index 192045a0a..161629954 100644 --- a/client/Android/FreeRDPCore/res/values-es/strings.xml +++ b/client/Android/Studio/freeRDPCore/src/main/res/values-es/strings.xml @@ -1,4 +1,4 @@ - + Si diff --git a/client/Android/FreeRDPCore/res/values-fr/strings.xml b/client/Android/Studio/freeRDPCore/src/main/res/values-fr/strings.xml similarity index 100% rename from client/Android/FreeRDPCore/res/values-fr/strings.xml rename to client/Android/Studio/freeRDPCore/src/main/res/values-fr/strings.xml diff --git a/client/Android/FreeRDPCore/res/values-land/dimens.xml b/client/Android/Studio/freeRDPCore/src/main/res/values-land/dimens.xml similarity index 100% rename from client/Android/FreeRDPCore/res/values-land/dimens.xml rename to client/Android/Studio/freeRDPCore/src/main/res/values-land/dimens.xml diff --git a/client/Android/FreeRDPCore/res/values-nl/strings.xml b/client/Android/Studio/freeRDPCore/src/main/res/values-nl/strings.xml similarity index 99% rename from client/Android/FreeRDPCore/res/values-nl/strings.xml rename to client/Android/Studio/freeRDPCore/src/main/res/values-nl/strings.xml index 5a28bb7d9..6167cb12f 100644 --- a/client/Android/FreeRDPCore/res/values-nl/strings.xml +++ b/client/Android/Studio/freeRDPCore/src/main/res/values-nl/strings.xml @@ -1,4 +1,4 @@ - + Ja diff --git a/client/Android/Studio/freeRDPCore/src/main/res/values-zh/strings.xml b/client/Android/Studio/freeRDPCore/src/main/res/values-zh/strings.xml new file mode 100644 index 000000000..bb98f94c9 --- /dev/null +++ b/client/Android/Studio/freeRDPCore/src/main/res/values-zh/strings.xml @@ -0,0 +1,199 @@ + + + + + + 取消 + 继续 + 登录 + 断开 + + 退出 + 关于 + 帮助 + 新建连接 + 设置 + + 操作 + 连接 + 编辑 + 删除 + + 键盘 + 功能键 + 触控鼠标 + 主目录 + 断开连接 + + 手动连接 + 活动会话数 + + 搜索 + + 登录 + 没有服务 + 连接中 … + 正在断开连接 … + 连接丢失 + 密码错误 + 用户名错误 + 新建连接 + + 主机信息 + 标签* + 远程主机ip或域名 + 端口 + 登录信息 + 登录信息 + 用户名 + 密码 + + 设置 + 显示 + 显示设置 + 颜色深度 + + High Color (16 Bit) + True Color (24 Bit) + Highest Quality (32 Bit) + + + 16 + 24 + 32 + + 分辨率 + 自动 + 全屏 + 自定义 + + 自动 + 全屏 + 自定义 + 640x480 + 720x480 + 800x600 + 1024x768 + 1280x1024 + 1440x900 + 1920x1080 + 1920x1200 + + + 自动 + 全屏 + 自定义 + 640x480 + 720x480 + 800x600 + 1024x768 + 1280x1024 + 1440x900 + 1920x1080 + 1920x1200 + + 宽度 + 高度 + 连接性能 + 性能设置 + RemoteFX + 桌面背景 + 字体平滑 + 桌面拼合 + 拖动是显示窗口内容 + 菜单动画效果 + 视觉样式 + 高级 + 高级设置 + 3G设置 + 使用3G网络时的显示设置 + 使用3G网络时的连接性能 + 路由 + 使用路由 + 路由设置 + SDCard 重定向 + 音频重定向 + + 不要播放 + 在远程主机播放 + 在此设备上播放 + + + 0 + 1 + 2 + + 麦克风重定向 + 连接协议 + + 自动 + RDP + TLS + NLA + + + 0 + 1 + 2 + 3 + + 远程程序 + 工作目录 + Async channel + Async transport + Async input + Async update + 控制台模式 + + ******* + 未设置 + 用户界面 + 隐藏状态栏 + 隐藏缩放控件 + 交换鼠标左右键 + 翻转滚动 + 触摸指针自动滚屏 + 退出时确认是否退出 + 省电设计 + 关闭空闲连接 + 安全 + 接受所有证书 + 清除证书缓存 + %1$d 秒后 + Disabled + + 连接设置 + 设置 + aFreeRDP - FreeRDP for Android + RDP Connections + 帮助 + 关于 + + 不保存即退出? + 点击 “继续” 继续编辑,点击 "取消" 放弃当前更改 + 建立连接失败! + + 由于主机不支持您的设置所以显示设置已经修改为适应主机的设置! + 清除证书缓存成功! + 清楚证书缓存失败! + + 证书验证 + 未能验证远程主机证书的安全性,是否连接? + 请输入您的证书 + 创建快捷方式 + 快捷方式名称: + 连接中 … + 正在登录 … + 关于aFreeRDP + 是否保存连接设置? + 连接设置还没保存! 是否保存? + 保存? + 是否保存更改? + 不再提示 + 退出? + 是否退出? + 清除证书缓存? + 是否清除所有的证书缓存? + Debug Level + Debug Settings + diff --git a/client/Android/FreeRDPCore/res/values/attrs.xml b/client/Android/Studio/freeRDPCore/src/main/res/values/attrs.xml similarity index 100% rename from client/Android/FreeRDPCore/res/values/attrs.xml rename to client/Android/Studio/freeRDPCore/src/main/res/values/attrs.xml diff --git a/client/Android/FreeRDPCore/res/values/dimens.xml b/client/Android/Studio/freeRDPCore/src/main/res/values/dimens.xml similarity index 100% rename from client/Android/FreeRDPCore/res/values/dimens.xml rename to client/Android/Studio/freeRDPCore/src/main/res/values/dimens.xml diff --git a/client/Android/FreeRDPCore/res/values/integers.xml b/client/Android/Studio/freeRDPCore/src/main/res/values/integers.xml similarity index 100% rename from client/Android/FreeRDPCore/res/values/integers.xml rename to client/Android/Studio/freeRDPCore/src/main/res/values/integers.xml diff --git a/client/Android/FreeRDPCore/res/values/strings.xml b/client/Android/Studio/freeRDPCore/src/main/res/values/strings.xml similarity index 98% rename from client/Android/FreeRDPCore/res/values/strings.xml rename to client/Android/Studio/freeRDPCore/src/main/res/values/strings.xml index d2342e0fe..495c9b85c 100644 --- a/client/Android/FreeRDPCore/res/values/strings.xml +++ b/client/Android/Studio/freeRDPCore/src/main/res/values/strings.xml @@ -1,4 +1,4 @@ - + Yes @@ -27,6 +27,7 @@ Manual Connections Active Sessions + foobar Connect to Computer @@ -97,6 +98,8 @@ Performance Performance Settings RemoteFX + GFX + H264 Desktop Background Font Smoothing Desktop Composition diff --git a/client/Android/FreeRDPCore/res/values/theme.xml b/client/Android/Studio/freeRDPCore/src/main/res/values/theme.xml similarity index 98% rename from client/Android/FreeRDPCore/res/values/theme.xml rename to client/Android/Studio/freeRDPCore/src/main/res/values/theme.xml index 5457b1991..99a6103fa 100644 --- a/client/Android/FreeRDPCore/res/values/theme.xml +++ b/client/Android/Studio/freeRDPCore/src/main/res/values/theme.xml @@ -1,4 +1,4 @@ - +