Merge branch 'master' of github.com:FreeRDP/FreeRDP

This commit is contained in:
Marc-André Moreau 2016-02-05 11:39:45 -05:00
commit bfca674f2d
582 changed files with 12444 additions and 8294 deletions

2
.gitignore vendored
View File

@ -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

View File

@ -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")

View File

@ -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)

11
buildflags.h.in Normal file
View File

@ -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 */

View File

@ -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)

View File

@ -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()

View File

@ -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)

View File

@ -5,6 +5,7 @@
* Copyright 2010-2011 Vic Lee
* Copyright 2015 Thincast Technologies GmbH
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
* Copyright 2015 Armin Novak <armin.novak@thincast.com>
*
* 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, "<subsystem>", NULL, NULL, -1, NULL, "subsystem" },
{ "dev", COMMAND_LINE_VALUE_REQUIRED, "<device>", 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)
{

View File

@ -1,7 +1,8 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# Android Client
# FreeRDP cmake build script
#
# Copyright 2013 Armin Novak <armin.novak@thincast.com>
# Copyright (c) 2015 Armin Novak <armin.novak@thincast.com>
# 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})

View File

@ -0,0 +1,461 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Audio Input Redirection Virtual Channel - Mac OS X implementation
*
* Copyright (c) 2015 Armin Novak <armin.novak@thincast.com>
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winpr/crt.h>
#include <winpr/synch.h>
#include <winpr/string.h>
#include <winpr/thread.h>
#include <winpr/debug.h>
#include <winpr/cmdline.h>
#include <CoreAudio/CoreAudioTypes.h>
#include <CoreAudio/CoreAudio.h>
#include <AudioToolbox/AudioToolbox.h>
#include <AudioToolbox/AudioQueue.h>
#include <freerdp/addin.h>
#include <freerdp/codec/dsp.h>
#include <freerdp/channels/rdpsnd.h>
#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, "<device>", 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;
}

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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")

View File

@ -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")

View File

@ -31,6 +31,7 @@
#include <winpr/collections.h>
#include <freerdp/addin.h>
#include <freerdp/build-config.h>
#include <freerdp/client/channels.h>
#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);
}

View File

@ -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")

View File

@ -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)

View File

@ -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")

View File

@ -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);
}

View File

@ -40,11 +40,6 @@ struct _cliprdr_server_private
void* ChannelHandle;
HANDLE ChannelEvent;
BOOL useLongFormatNames;
BOOL streamFileClipEnabled;
BOOL fileClipNoFilePaths;
BOOL canLockClipData;
wStream* s;
char* temporaryDirectory;
};

View File

@ -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")

View File

@ -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;

View File

@ -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")

View File

@ -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);

View File

@ -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")

View File

@ -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")

View File

@ -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")

View File

@ -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;

View File

@ -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")

View File

@ -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")

View File

@ -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")

View File

@ -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")

View File

@ -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")

View File

@ -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")

View File

@ -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")

View File

@ -6,6 +6,7 @@
* Copyright 2010-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2015 Thincast Technologies GmbH
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
* Copyright 2016 Armin Novak <armin.novak@gmail.com>
*
* 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)

View File

@ -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;
}

View File

@ -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 */

View File

@ -4,8 +4,9 @@
*
* Copyright 2010-2011 Vic Lee
* Copyright 2010-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2015 Thincast Technologies GmbH
* Copyright 2015-2016 Thincast Technologies GmbH
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
* Copyright 2016 Armin Novak <armin.novak@thincast.com>
*
* 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;
}
/**

View File

@ -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 */

View File

@ -4,8 +4,9 @@
*
* Copyright 2010-2011 Vic Lee
* Copyright 2010-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2015 Thincast Technologies GmbH
* Copyright 2015-2016 Thincast Technologies GmbH
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
* Copyright 2016 Armin Novak <armin.novak@thincast.com>
*
* 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);

View File

@ -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")

View File

@ -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")

View File

@ -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;

View File

@ -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")

View File

@ -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")

View File

@ -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;

View File

@ -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")

View File

@ -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")

View File

@ -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")

View File

@ -30,6 +30,7 @@
#include <winpr/wlog.h>
#include "TPCircularBuffer.h"
#include "rdpsnd_main.h"
#include <mach/mach.h>
#include <stdio.h>

View File

@ -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")

View File

@ -5,6 +5,8 @@
* Copyright 2012 Laxmikant Rashinkar <LK.Rashinkar@gmail.com>
* Copyright 2015 Thincast Technologies GmbH
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
* Copyright 2016 Inuvika Inc.
* Copyright 2016 David PHAM-VAN <d.phamvan@inuvika.com>
*
* 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);

View File

@ -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)

View File

@ -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);

View File

@ -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;
}

View File

@ -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")

View File

@ -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")

View File

@ -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")

View File

@ -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")

View File

@ -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")

View File

@ -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")

View File

@ -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")

View File

@ -47,6 +47,8 @@
#include <freerdp/server/rdpdr.h>
#include <freerdp/server/rdpei.h>
#include <freerdp/server/drdynvc.h>
#include <freerdp/server/remdesk.h>
#include <freerdp/server/encomsp.h>
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);
}
/**

View File

@ -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")

View File

@ -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")

View File

@ -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)

View File

@ -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()

View File

@ -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)

View File

@ -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;
}

View File

@ -45,20 +45,52 @@
#include <inttypes.h>
#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)
{

View File

@ -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);

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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,

View File

@ -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")

View File

@ -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()

View File

@ -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;

1
client/.gitignore vendored
View File

@ -9,3 +9,4 @@
!/X11
!/Wayland
!/CMakeLists.txt
!*.in

View File

@ -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

View File

@ -1,6 +1,7 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# Android Client
#
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
# Copyright 2013 Bernhard Miklautz <bernhard.miklautz@thincast.com>
#
# 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)

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

View File

@ -1,4 +0,0 @@
ant.properties
build.xml
jni/Android.mk
jni/Application.mk

View File

@ -1,53 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>FreeRDPCore</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.ui.externaltools.ExternalToolBuilder</name>
<triggers>full,incremental,</triggers>
<arguments>
<dictionary>
<key>LaunchConfigHandle</key>
<value>&lt;project&gt;/.externalToolBuilders/org.eclipse.cdt.managedbuilder.core.genmakebuilder.launch</value>
</dictionary>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
<triggers>full,incremental,</triggers>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.cdt.core.cnature</nature>
<nature>org.eclipse.cdt.core.ccnature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
</natures>
</projectDescription>

View File

@ -1,48 +0,0 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# Android Client
#
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
# Copyright 2013 Bernhard Miklautz <bernhard.miklautz@thincast.com>
#
# 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")

View File

@ -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

View File

@ -1,92 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="." default="help">
<!-- The local.properties file is created and updated by the 'android' tool.
It contains the path to the SDK. It should *NOT* be checked into
Version Control Systems. -->
<property file="local.properties" />
<!-- The ant.properties file can be created by you. It is only edited by the
'android' tool to add properties to it.
This is the place to change some Ant specific build properties.
Here are some properties you may want to change/update:
source.dir
The name of the source directory. Default is 'src'.
out.dir
The name of the output directory. Default is 'bin'.
For other overridable properties, look at the beginning of the rules
files in the SDK, at tools/ant/build.xml
Properties related to the SDK location or the project target should
be updated using the 'android' tool with the 'update' action.
This file is an integral part of the build system for your
application and should be checked into Version Control Systems.
-->
<property file="ant.properties" />
<!-- if sdk.dir was not set from one of the property file, then
get it from the ANDROID_HOME env var.
This must be done before we load project.properties since
the proguard config can use sdk.dir -->
<property environment="env" />
<condition property="sdk.dir" value="${env.ANDROID_HOME}">
<isset property="env.ANDROID_HOME" />
</condition>
<!-- The project.properties file is created and updated by the 'android'
tool, as well as ADT.
This contains project specific properties such as project target, and library
dependencies. Lower level build properties are stored in ant.properties
(or in .classpath for Eclipse projects).
This file is an integral part of the build system for your
application and should be checked into Version Control Systems. -->
<loadproperties srcFile="project.properties" />
<!-- quick check on sdk.dir -->
<fail
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
unless="sdk.dir"
/>
<!--
Import per project custom build rules if present at the root of the project.
This is the place to put custom intermediary targets such as:
-pre-build
-pre-compile
-post-compile (This is typically used for code obfuscation.
Compiled code location: ${out.classes.absolute.dir}
If this is not done in place, override ${out.dex.input.absolute.dir})
-post-package
-post-build
-pre-clean
-->
<import file="custom_rules.xml" optional="true" />
<!-- Import the actual build file.
To customize existing targets, there are two options:
- Customize only one target:
- copy/paste the target into this file, *before* the
<import> task.
- customize it to your needs.
- Customize the whole content of build.xml
- copy/paste the content of the rules files (minus the top node)
into this file, replacing the <import> task.
- customize to your needs.
***********************
****** IMPORTANT ******
***********************
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
in order to avoid having your file be overridden by tools such as "android update project"
-->
<!-- version-tag: 1 -->
<import file="${sdk.dir}/tools/ant/build.xml" />
</project>

View File

@ -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)

View File

@ -1 +0,0 @@
APP_ABI := @ANDROID_ABI@

View File

@ -1,73 +0,0 @@
# FreeRDP: A Remote Desktop Protocol Implementation
# Android Client
#
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
# Copyright 2013 Bernhard Miklautz <bernhard.miklautz@thincast.com>
#
# 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)

View File

@ -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 <freerdp/log.h>
#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 */

Some files were not shown because too many files have changed in this diff Show More