Update upstream source from tag 'upstream/2.6.0+dfsg1'
Update to upstream version '2.6.0+dfsg1'
with Debian dir e82f2caa6e
This commit is contained in:
commit
4ab6e978fe
@ -41,7 +41,6 @@ addons:
|
||||
- libgsm1-dev
|
||||
- libavcodec-dev
|
||||
- libavutil-dev
|
||||
- libx264-dev
|
||||
- libxext-dev
|
||||
- ninja-build
|
||||
- libsystemd-dev
|
||||
|
||||
@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER})
|
||||
endif()
|
||||
set(WITH_LIBRARY_VERSIONING "ON")
|
||||
|
||||
set(RAW_VERSION_STRING "2.5.0")
|
||||
set(RAW_VERSION_STRING "2.6.0")
|
||||
if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag")
|
||||
file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING)
|
||||
elseif(USE_VERSION_FROM_GIT_TAG)
|
||||
@ -652,6 +652,7 @@ if(UNIX OR CYGWIN)
|
||||
include(CheckFunctionExists)
|
||||
|
||||
check_function_exists(getlogin_r HAVE_GETLOGIN_R)
|
||||
check_function_exists(getpwuid_r HAVE_GETPWUID_R)
|
||||
else()
|
||||
set(X11_FEATURE_TYPE "DISABLED")
|
||||
set(WAYLAND_FEATURE_TYPE "DISABLED")
|
||||
@ -719,10 +720,6 @@ set(JPEG_FEATURE_TYPE "OPTIONAL")
|
||||
set(JPEG_FEATURE_PURPOSE "codec")
|
||||
set(JPEG_FEATURE_DESCRIPTION "use JPEG library")
|
||||
|
||||
set(X264_FEATURE_TYPE "OPTIONAL")
|
||||
set(X264_FEATURE_PURPOSE "codec")
|
||||
set(X264_FEATURE_DESCRIPTION "use x264 library")
|
||||
|
||||
set(OPENH264_FEATURE_TYPE "OPTIONAL")
|
||||
set(OPENH264_FEATURE_PURPOSE "codec")
|
||||
set(OPENH264_FEATURE_DESCRIPTION "use OpenH264 library")
|
||||
@ -808,7 +805,6 @@ if(ANDROID)
|
||||
set(PULSE_FEATURE_TYPE "DISABLED")
|
||||
set(CUPS_FEATURE_TYPE "DISABLED")
|
||||
set(PCSC_FEATURE_TYPE "DISABLED")
|
||||
set(FFMPEG_FEATURE_TYPE "DISABLED")
|
||||
set(VAAPI_FEATURE_TYPE "DISABLED")
|
||||
set(OPENSLES_FEATURE_TYPE "REQUIRED")
|
||||
endif()
|
||||
@ -831,7 +827,6 @@ find_feature(PCSC ${PCSC_FEATURE_TYPE} ${PCSC_FEATURE_PURPOSE} ${PCSC_FEATURE_DE
|
||||
find_feature(FFmpeg ${FFMPEG_FEATURE_TYPE} ${FFMPEG_FEATURE_PURPOSE} ${FFMPEG_FEATURE_DESCRIPTION})
|
||||
|
||||
find_feature(JPEG ${JPEG_FEATURE_TYPE} ${JPEG_FEATURE_PURPOSE} ${JPEG_FEATURE_DESCRIPTION})
|
||||
find_feature(x264 ${X264_FEATURE_TYPE} ${X264_FEATURE_PURPOSE} ${X264_FEATURE_DESCRIPTION})
|
||||
find_feature(OpenH264 ${OPENH264_FEATURE_TYPE} ${OPENH264_FEATURE_PURPOSE} ${OPENH264_FEATURE_DESCRIPTION})
|
||||
find_feature(OpenCL ${OPENCL_FEATURE_TYPE} ${OPENCL_FEATURE_PURPOSE} ${OPENCL_FEATURE_DESCRIPTION})
|
||||
find_feature(GSM ${GSM_FEATURE_TYPE} ${GSM_FEATURE_PURPOSE} ${GSM_FEATURE_DESCRIPTION})
|
||||
@ -917,7 +912,7 @@ if(MBEDTLS_FOUND)
|
||||
add_definitions("-DWITH_MBEDTLS")
|
||||
endif()
|
||||
|
||||
if (WITH_X264 OR WITH_OPENH264 OR WITH_MEDIA_FOUNDATION OR WITH_FFMPEG)
|
||||
if (WITH_OPENH264 OR WITH_MEDIA_FOUNDATION OR WITH_FFMPEG OR WITH_MEDIACODEC)
|
||||
set(WITH_GFX_H264 ON)
|
||||
else()
|
||||
set(WITH_GFX_H264 OFF)
|
||||
|
||||
23
ChangeLog
23
ChangeLog
@ -1,3 +1,26 @@
|
||||
# 2022-02-22 Version 2.6.0
|
||||
|
||||
Noteworthy changes:
|
||||
* Backported android FFMPEG build scripts
|
||||
* Updated android build dependencies
|
||||
|
||||
Fixed issues:
|
||||
* Backported #7303: Fix PDU length for RDPINPUT_PROTOCOL_V300
|
||||
* Backported #7658: Sanitize optional physical monitor size values
|
||||
* Backported #7426: Wayland memory corruption
|
||||
* Backported #7293: Remove unused codec x264
|
||||
* Backported #7541: Allow resolutions larger 2048x2048
|
||||
* Backported #7574: FFMPEG 5.0 support
|
||||
* Backported #7578: FFMPEG 5.0 support
|
||||
* Backported #7580: Fixed device hotplugging
|
||||
* Backported #7583: GetUserNameExA: Prefer getpwuid_r over getlogin_r over getlogin
|
||||
* Backported #7585: Android Mediacodec support
|
||||
|
||||
Important notes:
|
||||
|
||||
For a complete and detailed change log since the last release run:
|
||||
git log 2.5.0..2.6.0
|
||||
|
||||
# 2022-01-12 Version 2.5.0
|
||||
|
||||
Noteworthy changes:
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
# FreeRDP cmake android options
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP cmake build script
|
||||
#
|
||||
# Copyright 2013 Thincast Technologies GmbH
|
||||
# Copyright 2013 Bernhard Miklautz <bernhard.miklautz@thincast.com>
|
||||
# Copyright 2022 Armin Novak <anovak@thincast.com>
|
||||
# Copyright 2022 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,12 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
option(WITH_OPENSLES "Enable sound and microphone redirection using OpenSLES" ON)
|
||||
define_channel("ainput")
|
||||
|
||||
set(ANDROID_APP_TARGET_SDK 21 CACHE STRING "Application target android SDK")
|
||||
set(ANDROID_APP_MIN_SDK 14 CACHE STRING "Application minimum android SDK requirement")
|
||||
if(WITH_CLIENT_CHANNELS)
|
||||
add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME})
|
||||
endif()
|
||||
|
||||
if(WITH_SERVER_CHANNELS)
|
||||
add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME})
|
||||
endif()
|
||||
13
channels/ainput/ChannelOptions.cmake
Normal file
13
channels/ainput/ChannelOptions.cmake
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
set(OPTION_DEFAULT OFF)
|
||||
set(OPTION_CLIENT_DEFAULT ON)
|
||||
set(OPTION_SERVER_DEFAULT ON)
|
||||
|
||||
define_channel_options(NAME "ainput" TYPE "dynamic"
|
||||
DESCRIPTION "Advanced Input Virtual Channel Extension"
|
||||
SPECIFICATIONS "[XXXXX]"
|
||||
DEFAULT ${OPTION_DEFAULT})
|
||||
|
||||
define_channel_client_options(${OPTION_CLIENT_DEFAULT})
|
||||
define_channel_server_options(${OPTION_SERVER_DEFAULT})
|
||||
|
||||
34
channels/ainput/client/CMakeLists.txt
Normal file
34
channels/ainput/client/CMakeLists.txt
Normal file
@ -0,0 +1,34 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP cmake build script
|
||||
#
|
||||
# Copyright 2022 Armin Novak <anovak@thincast.com>
|
||||
# Copyright 2022 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.
|
||||
|
||||
define_channel_client("ainput")
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
ainput_main.c
|
||||
ainput_main.h)
|
||||
|
||||
include_directories(..)
|
||||
|
||||
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry")
|
||||
|
||||
if (WITH_DEBUG_SYMBOLS AND MSVC AND NOT BUILTIN_CHANNELS AND BUILD_SHARED_LIBS)
|
||||
install(FILES ${PROJECT_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${FREERDP_ADDIN_PATH} COMPONENT symbols)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${MODULE_NAME} winpr)
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client")
|
||||
317
channels/ainput/client/ainput_main.c
Normal file
317
channels/ainput/client/ainput_main.c
Normal file
@ -0,0 +1,317 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Advanced Input Virtual Channel Extension
|
||||
*
|
||||
* Copyright 2022 Armin Novak <anovak@thincast.com>
|
||||
* Copyright 2022 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 <winpr/crt.h>
|
||||
#include <assert.h>
|
||||
#include <winpr/stream.h>
|
||||
#include <winpr/sysinfo.h>
|
||||
|
||||
#include "ainput_main.h"
|
||||
#include <freerdp/channels/log.h>
|
||||
#include <freerdp/client/ainput.h>
|
||||
#include <freerdp/channels/ainput.h>
|
||||
|
||||
#include "../common/ainput_common.h"
|
||||
|
||||
#define WINPR_ASSERT(x) assert(x)
|
||||
|
||||
#define TAG CHANNELS_TAG("ainput.client")
|
||||
|
||||
typedef struct AINPUT_CHANNEL_CALLBACK_ AINPUT_CHANNEL_CALLBACK;
|
||||
struct AINPUT_CHANNEL_CALLBACK_
|
||||
{
|
||||
IWTSVirtualChannelCallback iface;
|
||||
|
||||
IWTSPlugin* plugin;
|
||||
IWTSVirtualChannelManager* channel_mgr;
|
||||
IWTSVirtualChannel* channel;
|
||||
};
|
||||
|
||||
typedef struct AINPUT_LISTENER_CALLBACK_ AINPUT_LISTENER_CALLBACK;
|
||||
struct AINPUT_LISTENER_CALLBACK_
|
||||
{
|
||||
IWTSListenerCallback iface;
|
||||
|
||||
IWTSPlugin* plugin;
|
||||
IWTSVirtualChannelManager* channel_mgr;
|
||||
AINPUT_CHANNEL_CALLBACK* channel_callback;
|
||||
};
|
||||
|
||||
typedef struct AINPUT_PLUGIN_ AINPUT_PLUGIN;
|
||||
struct AINPUT_PLUGIN_
|
||||
{
|
||||
IWTSPlugin iface;
|
||||
|
||||
AINPUT_LISTENER_CALLBACK* listener_callback;
|
||||
IWTSListener* listener;
|
||||
UINT32 MajorVersion;
|
||||
UINT32 MinorVersion;
|
||||
BOOL initialized;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT ainput_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data)
|
||||
{
|
||||
UINT16 type;
|
||||
AINPUT_PLUGIN* ainput;
|
||||
AINPUT_CHANNEL_CALLBACK* callback = (AINPUT_CHANNEL_CALLBACK*)pChannelCallback;
|
||||
|
||||
WINPR_ASSERT(callback);
|
||||
WINPR_ASSERT(data);
|
||||
|
||||
ainput = (AINPUT_PLUGIN*)callback->plugin;
|
||||
WINPR_ASSERT(ainput);
|
||||
|
||||
if (Stream_GetRemainingLength(data) < 2)
|
||||
return ERROR_NO_DATA;
|
||||
Stream_Read_UINT16(data, type);
|
||||
switch (type)
|
||||
{
|
||||
case MSG_AINPUT_VERSION:
|
||||
if (Stream_GetRemainingLength(data) < 8)
|
||||
return ERROR_NO_DATA;
|
||||
Stream_Read_UINT32(data, ainput->MajorVersion);
|
||||
Stream_Read_UINT32(data, ainput->MinorVersion);
|
||||
break;
|
||||
default:
|
||||
WLog_WARN(TAG, "Received unsupported message type 0x%04" PRIx16, type);
|
||||
break;
|
||||
}
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static UINT ainput_send_input_event(AInputClientContext* context, UINT64 flags, INT32 x, INT32 y)
|
||||
{
|
||||
AINPUT_PLUGIN* ainput;
|
||||
AINPUT_CHANNEL_CALLBACK* callback;
|
||||
BYTE buffer[32] = { 0 };
|
||||
UINT64 time;
|
||||
wStream sbuffer = { 0 };
|
||||
wStream* s = &sbuffer;
|
||||
|
||||
Stream_StaticInit(&sbuffer, buffer, sizeof(buffer));
|
||||
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(context);
|
||||
|
||||
time = GetTickCount64();
|
||||
ainput = (AINPUT_PLUGIN*)context->handle;
|
||||
WINPR_ASSERT(ainput);
|
||||
WINPR_ASSERT(ainput->listener_callback);
|
||||
|
||||
if (ainput->MajorVersion != AINPUT_VERSION_MAJOR)
|
||||
{
|
||||
WLog_WARN(TAG, "Unsupported channel version %" PRIu32 ".%" PRIu32 ", aborting.",
|
||||
ainput->MajorVersion, ainput->MinorVersion);
|
||||
return CHANNEL_RC_UNSUPPORTED_VERSION;
|
||||
}
|
||||
callback = ainput->listener_callback->channel_callback;
|
||||
WINPR_ASSERT(callback);
|
||||
|
||||
{
|
||||
char buffer[128] = { 0 };
|
||||
WLog_VRB(TAG, "[%s] sending timestamp=0x%08" PRIx64 ", flags=%s, %" PRId32 "x%" PRId32,
|
||||
__FUNCTION__, time, ainput_flags_to_string(flags, buffer, sizeof(buffer)), x, y);
|
||||
}
|
||||
|
||||
/* Message type */
|
||||
Stream_Write_UINT16(s, MSG_AINPUT_MOUSE);
|
||||
|
||||
/* Event data */
|
||||
Stream_Write_UINT64(s, time);
|
||||
Stream_Write_UINT64(s, flags);
|
||||
Stream_Write_INT32(s, x);
|
||||
Stream_Write_INT32(s, y);
|
||||
Stream_SealLength(s);
|
||||
|
||||
/* ainput back what we have received. AINPUT does not have any message IDs. */
|
||||
WINPR_ASSERT(callback->channel);
|
||||
WINPR_ASSERT(callback->channel->Write);
|
||||
return callback->channel->Write(callback->channel, (ULONG)Stream_Length(s), Stream_Buffer(s),
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT ainput_on_close(IWTSVirtualChannelCallback* pChannelCallback)
|
||||
{
|
||||
AINPUT_CHANNEL_CALLBACK* callback = (AINPUT_CHANNEL_CALLBACK*)pChannelCallback;
|
||||
|
||||
free(callback);
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT ainput_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
|
||||
IWTSVirtualChannel* pChannel, BYTE* Data,
|
||||
BOOL* pbAccept,
|
||||
IWTSVirtualChannelCallback** ppCallback)
|
||||
{
|
||||
AINPUT_CHANNEL_CALLBACK* callback;
|
||||
AINPUT_LISTENER_CALLBACK* listener_callback = (AINPUT_LISTENER_CALLBACK*)pListenerCallback;
|
||||
|
||||
WINPR_ASSERT(listener_callback);
|
||||
WINPR_UNUSED(Data);
|
||||
WINPR_UNUSED(pbAccept);
|
||||
|
||||
callback = (AINPUT_CHANNEL_CALLBACK*)calloc(1, sizeof(AINPUT_CHANNEL_CALLBACK));
|
||||
|
||||
if (!callback)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
callback->iface.OnDataReceived = ainput_on_data_received;
|
||||
callback->iface.OnClose = ainput_on_close;
|
||||
callback->plugin = listener_callback->plugin;
|
||||
callback->channel_mgr = listener_callback->channel_mgr;
|
||||
callback->channel = pChannel;
|
||||
listener_callback->channel_callback = callback;
|
||||
|
||||
*ppCallback = &callback->iface;
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT ainput_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
|
||||
{
|
||||
UINT status;
|
||||
AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)pPlugin;
|
||||
|
||||
WINPR_ASSERT(ainput);
|
||||
|
||||
if (ainput->initialized)
|
||||
{
|
||||
WLog_ERR(TAG, "[%s] channel initialized twice, aborting", AINPUT_DVC_CHANNEL_NAME);
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
ainput->listener_callback =
|
||||
(AINPUT_LISTENER_CALLBACK*)calloc(1, sizeof(AINPUT_LISTENER_CALLBACK));
|
||||
|
||||
if (!ainput->listener_callback)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
ainput->listener_callback->iface.OnNewChannelConnection = ainput_on_new_channel_connection;
|
||||
ainput->listener_callback->plugin = pPlugin;
|
||||
ainput->listener_callback->channel_mgr = pChannelMgr;
|
||||
|
||||
status = pChannelMgr->CreateListener(pChannelMgr, AINPUT_DVC_CHANNEL_NAME, 0,
|
||||
&ainput->listener_callback->iface, &ainput->listener);
|
||||
|
||||
ainput->listener->pInterface = ainput->iface.pInterface;
|
||||
ainput->initialized = status == CHANNEL_RC_OK;
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT ainput_plugin_terminated(IWTSPlugin* pPlugin)
|
||||
{
|
||||
AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)pPlugin;
|
||||
if (ainput && ainput->listener_callback)
|
||||
{
|
||||
IWTSVirtualChannelManager* mgr = ainput->listener_callback->channel_mgr;
|
||||
if (mgr)
|
||||
IFCALL(mgr->DestroyListener, mgr, ainput->listener);
|
||||
}
|
||||
if (ainput)
|
||||
{
|
||||
free(ainput->listener_callback);
|
||||
free(ainput->iface.pInterface);
|
||||
}
|
||||
free(ainput);
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
#ifdef BUILTIN_CHANNELS
|
||||
#define DVCPluginEntry ainput_DVCPluginEntry
|
||||
#else
|
||||
#define DVCPluginEntry FREERDP_API DVCPluginEntry
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||
{
|
||||
UINT status = CHANNEL_RC_OK;
|
||||
AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "ainput");
|
||||
|
||||
if (!ainput)
|
||||
{
|
||||
AInputClientContext* context = (AInputClientContext*)calloc(1, sizeof(AInputClientContext));
|
||||
ainput = (AINPUT_PLUGIN*)calloc(1, sizeof(AINPUT_PLUGIN));
|
||||
|
||||
if (!ainput || !context)
|
||||
{
|
||||
free(context);
|
||||
free(ainput);
|
||||
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
ainput->iface.Initialize = ainput_plugin_initialize;
|
||||
ainput->iface.Terminated = ainput_plugin_terminated;
|
||||
|
||||
context->handle = (void*)ainput;
|
||||
context->AInputSendInputEvent = ainput_send_input_event;
|
||||
ainput->iface.pInterface = (void*)context;
|
||||
|
||||
status = pEntryPoints->RegisterPlugin(pEntryPoints, AINPUT_CHANNEL_NAME, &ainput->iface);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
43
channels/ainput/client/ainput_main.h
Normal file
43
channels/ainput/client/ainput_main.h
Normal file
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Advanced Input Virtual Channel Extension
|
||||
*
|
||||
* Copyright 2022 Armin Novak <anovak@thincast.com>
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_CHANNEL_AINPUT_CLIENT_MAIN_H
|
||||
#define FREERDP_CHANNEL_AINPUT_CLIENT_MAIN_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <freerdp/dvc.h>
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/addin.h>
|
||||
#include <freerdp/channels/log.h>
|
||||
|
||||
#define DVC_TAG CHANNELS_TAG("ainput.client")
|
||||
#ifdef WITH_DEBUG_DVC
|
||||
#define DEBUG_DVC(...) WLog_DBG(DVC_TAG, __VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG_DVC(...) \
|
||||
do \
|
||||
{ \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_CHANNEL_AINPUT_CLIENT_MAIN_H */
|
||||
81
channels/ainput/common/ainput_common.h
Normal file
81
channels/ainput/common/ainput_common.h
Normal file
@ -0,0 +1,81 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Audio Input Redirection Virtual Channel
|
||||
*
|
||||
* Copyright 2022 Armin Novak <anovak@thincast.com>
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_INT_AINPUT_COMMON_H
|
||||
#define FREERDP_INT_AINPUT_COMMON_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <winpr/string.h>
|
||||
|
||||
#include <freerdp/channels/ainput.h>
|
||||
|
||||
static INLINE void ainput_append(char* buffer, size_t size, const char* what, BOOL separator)
|
||||
{
|
||||
size_t have;
|
||||
size_t toadd;
|
||||
|
||||
assert(buffer || (size == 0));
|
||||
assert(what);
|
||||
|
||||
have = strnlen(buffer, size);
|
||||
toadd = strlen(what);
|
||||
if (have > 0)
|
||||
toadd += 1;
|
||||
|
||||
if (size - have < toadd + 1)
|
||||
return;
|
||||
|
||||
if (have > 0)
|
||||
strcat(buffer, separator ? "|" : " ");
|
||||
strcat(buffer, what);
|
||||
}
|
||||
|
||||
static INLINE const char* ainput_flags_to_string(UINT64 flags, char* buffer, size_t size)
|
||||
{
|
||||
char number[32] = { 0 };
|
||||
|
||||
if (flags & AINPUT_FLAGS_HAVE_REL)
|
||||
ainput_append(buffer, size, "AINPUT_FLAGS_HAVE_REL", TRUE);
|
||||
if (flags & AINPUT_FLAGS_WHEEL)
|
||||
ainput_append(buffer, size, "AINPUT_FLAGS_WHEEL", TRUE);
|
||||
if (flags & AINPUT_FLAGS_MOVE)
|
||||
ainput_append(buffer, size, "AINPUT_FLAGS_MOVE", TRUE);
|
||||
if (flags & AINPUT_FLAGS_DOWN)
|
||||
ainput_append(buffer, size, "AINPUT_FLAGS_DOWN", TRUE);
|
||||
if (flags & AINPUT_FLAGS_REL)
|
||||
ainput_append(buffer, size, "AINPUT_FLAGS_REL", TRUE);
|
||||
if (flags & AINPUT_FLAGS_BUTTON1)
|
||||
ainput_append(buffer, size, "AINPUT_FLAGS_BUTTON1", TRUE);
|
||||
if (flags & AINPUT_FLAGS_BUTTON2)
|
||||
ainput_append(buffer, size, "AINPUT_FLAGS_BUTTON2", TRUE);
|
||||
if (flags & AINPUT_FLAGS_BUTTON3)
|
||||
ainput_append(buffer, size, "AINPUT_FLAGS_BUTTON3", TRUE);
|
||||
if (flags & AINPUT_XFLAGS_BUTTON1)
|
||||
ainput_append(buffer, size, "AINPUT_XFLAGS_BUTTON1", TRUE);
|
||||
if (flags & AINPUT_XFLAGS_BUTTON2)
|
||||
ainput_append(buffer, size, "AINPUT_XFLAGS_BUTTON2", TRUE);
|
||||
|
||||
_snprintf(number, sizeof(number), "[0x%08" PRIx64 "]", flags);
|
||||
ainput_append(buffer, size, number, FALSE);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
#endif /* FREERDP_INT_AINPUT_COMMON_H */
|
||||
27
channels/ainput/server/CMakeLists.txt
Normal file
27
channels/ainput/server/CMakeLists.txt
Normal file
@ -0,0 +1,27 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# FreeRDP cmake build script
|
||||
#
|
||||
# Copyright 2022 Armin Novak <anovak@thincast.com>
|
||||
# Copyright 2022 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.
|
||||
|
||||
define_channel_server("ainput")
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
ainput_main.c)
|
||||
|
||||
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "DVCPluginEntry")
|
||||
|
||||
target_link_libraries(${MODULE_NAME} freerdp)
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server")
|
||||
546
channels/ainput/server/ainput_main.c
Normal file
546
channels/ainput/server/ainput_main.c
Normal file
@ -0,0 +1,546 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Advanced Input Virtual Channel Extension
|
||||
*
|
||||
* Copyright 2022 Armin Novak <anovak@thincast.com>
|
||||
* Copyright 2022 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 <assert.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
#include <winpr/stream.h>
|
||||
#include <winpr/sysinfo.h>
|
||||
|
||||
#include <freerdp/server/ainput.h>
|
||||
#include <freerdp/channels/ainput.h>
|
||||
#include <freerdp/channels/log.h>
|
||||
|
||||
#include "../common/ainput_common.h"
|
||||
|
||||
#define WINPR_ASSERT(x) assert(x)
|
||||
|
||||
#define TAG CHANNELS_TAG("ainput.server")
|
||||
|
||||
typedef enum
|
||||
{
|
||||
AINPUT_INITIAL,
|
||||
AINPUT_OPENED,
|
||||
AINPUT_VERSION_SENT,
|
||||
} eAInputChannelState;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ainput_server_context context;
|
||||
|
||||
BOOL opened;
|
||||
|
||||
HANDLE stopEvent;
|
||||
|
||||
HANDLE thread;
|
||||
void* ainput_channel;
|
||||
|
||||
DWORD SessionId;
|
||||
|
||||
BOOL isOpened;
|
||||
BOOL externalThread;
|
||||
|
||||
/* Channel state */
|
||||
eAInputChannelState state;
|
||||
|
||||
wStream* buffer;
|
||||
} ainput_server;
|
||||
|
||||
static UINT ainput_server_context_poll(ainput_server_context* context);
|
||||
static BOOL ainput_server_context_handle(ainput_server_context* context, HANDLE* handle);
|
||||
static UINT ainput_server_context_poll_int(ainput_server_context* context);
|
||||
|
||||
static BOOL ainput_server_is_open(ainput_server_context* context)
|
||||
{
|
||||
ainput_server* ainput = (ainput_server*)context;
|
||||
|
||||
WINPR_ASSERT(ainput);
|
||||
return ainput->isOpened;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT ainput_server_open_channel(ainput_server* ainput)
|
||||
{
|
||||
DWORD Error;
|
||||
HANDLE hEvent;
|
||||
DWORD StartTick;
|
||||
DWORD BytesReturned = 0;
|
||||
PULONG pSessionId = NULL;
|
||||
|
||||
WINPR_ASSERT(ainput);
|
||||
|
||||
if (WTSQuerySessionInformationA(ainput->context.vcm, WTS_CURRENT_SESSION, WTSSessionId,
|
||||
(LPSTR*)&pSessionId, &BytesReturned) == FALSE)
|
||||
{
|
||||
WLog_ERR(TAG, "WTSQuerySessionInformationA failed!");
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
ainput->SessionId = (DWORD)*pSessionId;
|
||||
WTSFreeMemory(pSessionId);
|
||||
hEvent = WTSVirtualChannelManagerGetEventHandle(ainput->context.vcm);
|
||||
StartTick = GetTickCount();
|
||||
|
||||
while (ainput->ainput_channel == NULL)
|
||||
{
|
||||
if (WaitForSingleObject(hEvent, 1000) == WAIT_FAILED)
|
||||
{
|
||||
Error = GetLastError();
|
||||
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", Error);
|
||||
return Error;
|
||||
}
|
||||
|
||||
ainput->ainput_channel = WTSVirtualChannelOpenEx(ainput->SessionId, AINPUT_DVC_CHANNEL_NAME,
|
||||
WTS_CHANNEL_OPTION_DYNAMIC);
|
||||
|
||||
if (ainput->ainput_channel)
|
||||
break;
|
||||
|
||||
Error = GetLastError();
|
||||
|
||||
if (Error == ERROR_NOT_FOUND)
|
||||
break;
|
||||
|
||||
if (GetTickCount() - StartTick > 5000)
|
||||
break;
|
||||
}
|
||||
|
||||
return ainput->ainput_channel ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
static UINT ainput_server_send_version(ainput_server* ainput)
|
||||
{
|
||||
ULONG written;
|
||||
wStream* s;
|
||||
|
||||
WINPR_ASSERT(ainput);
|
||||
|
||||
s = ainput->buffer;
|
||||
WINPR_ASSERT(s);
|
||||
|
||||
Stream_SetPosition(s, 0);
|
||||
if (!Stream_EnsureCapacity(s, 10))
|
||||
return ERROR_OUTOFMEMORY;
|
||||
|
||||
Stream_Write_UINT16(s, MSG_AINPUT_VERSION);
|
||||
Stream_Write_UINT32(s, AINPUT_VERSION_MAJOR); /* Version (4 bytes) */
|
||||
Stream_Write_UINT32(s, AINPUT_VERSION_MINOR); /* Version (4 bytes) */
|
||||
|
||||
WINPR_ASSERT(Stream_GetPosition(s) <= ULONG_MAX);
|
||||
if (!WTSVirtualChannelWrite(ainput->ainput_channel, (PCHAR)Stream_Buffer(s),
|
||||
(ULONG)Stream_GetPosition(s), &written))
|
||||
{
|
||||
WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
static UINT ainput_server_recv_mouse_event(ainput_server* ainput, wStream* s)
|
||||
{
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
UINT64 flags, time;
|
||||
INT32 x, y;
|
||||
char buffer[128] = { 0 };
|
||||
|
||||
WINPR_ASSERT(ainput);
|
||||
WINPR_ASSERT(s);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 24)
|
||||
return ERROR_NO_DATA;
|
||||
|
||||
Stream_Read_UINT64(s, time);
|
||||
Stream_Read_UINT64(s, flags);
|
||||
Stream_Read_INT32(s, x);
|
||||
Stream_Read_INT32(s, y);
|
||||
|
||||
WLog_VRB(TAG, "[%s] received: time=0x%08" PRIx64 ", flags=%s, %" PRId32 "x%" PRId32,
|
||||
__FUNCTION__, time, ainput_flags_to_string(flags, buffer, sizeof(buffer)), x, y);
|
||||
IFCALLRET(ainput->context.MouseEvent, error, &ainput->context, time, flags, x, y);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static HANDLE ainput_server_get_channel_handle(ainput_server* ainput)
|
||||
{
|
||||
BYTE* buffer = NULL;
|
||||
DWORD BytesReturned = 0;
|
||||
HANDLE ChannelEvent = NULL;
|
||||
|
||||
WINPR_ASSERT(ainput);
|
||||
|
||||
if (WTSVirtualChannelQuery(ainput->ainput_channel, WTSVirtualEventHandle, &buffer,
|
||||
&BytesReturned) == TRUE)
|
||||
{
|
||||
if (BytesReturned == sizeof(HANDLE))
|
||||
CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE));
|
||||
|
||||
WTSFreeMemory(buffer);
|
||||
}
|
||||
|
||||
return ChannelEvent;
|
||||
}
|
||||
|
||||
static DWORD WINAPI ainput_server_thread_func(LPVOID arg)
|
||||
{
|
||||
DWORD nCount;
|
||||
HANDLE events[2] = { 0 };
|
||||
ainput_server* ainput = (ainput_server*)arg;
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
DWORD status;
|
||||
|
||||
WINPR_ASSERT(ainput);
|
||||
|
||||
nCount = 0;
|
||||
events[nCount++] = ainput->stopEvent;
|
||||
|
||||
while ((error == CHANNEL_RC_OK) && (WaitForSingleObject(events[0], 0) != WAIT_OBJECT_0))
|
||||
{
|
||||
switch (ainput->state)
|
||||
{
|
||||
case AINPUT_OPENED:
|
||||
events[1] = ainput_server_get_channel_handle(ainput);
|
||||
nCount = 2;
|
||||
status = WaitForMultipleObjects(nCount, events, FALSE, 100);
|
||||
switch (status)
|
||||
{
|
||||
case WAIT_TIMEOUT:
|
||||
case WAIT_OBJECT_0 + 1:
|
||||
case WAIT_OBJECT_0:
|
||||
error = ainput_server_context_poll_int(&ainput->context);
|
||||
|
||||
case WAIT_FAILED:
|
||||
default:
|
||||
error = ERROR_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case AINPUT_VERSION_SENT:
|
||||
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
|
||||
switch (status)
|
||||
{
|
||||
case WAIT_TIMEOUT:
|
||||
case WAIT_OBJECT_0 + 1:
|
||||
case WAIT_OBJECT_0:
|
||||
error = ainput_server_context_poll_int(&ainput->context);
|
||||
|
||||
case WAIT_FAILED:
|
||||
default:
|
||||
error = ERROR_INTERNAL_ERROR;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error = ainput_server_context_poll_int(&ainput->context);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
WTSVirtualChannelClose(ainput->ainput_channel);
|
||||
ainput->ainput_channel = NULL;
|
||||
|
||||
if (error && ainput->context.rdpcontext)
|
||||
setChannelError(ainput->context.rdpcontext, error,
|
||||
"ainput_server_thread_func reported an error");
|
||||
|
||||
ExitThread(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT ainput_server_open(ainput_server_context* context)
|
||||
{
|
||||
ainput_server* ainput = (ainput_server*)context;
|
||||
|
||||
WINPR_ASSERT(ainput);
|
||||
|
||||
if (!ainput->externalThread && (ainput->thread == NULL))
|
||||
{
|
||||
ainput->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
if (!ainput->stopEvent)
|
||||
{
|
||||
WLog_ERR(TAG, "CreateEvent failed!");
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
ainput->thread = CreateThread(NULL, 0, ainput_server_thread_func, ainput, 0, NULL);
|
||||
if (!ainput->thread)
|
||||
{
|
||||
WLog_ERR(TAG, "CreateEvent failed!");
|
||||
CloseHandle(ainput->stopEvent);
|
||||
ainput->stopEvent = NULL;
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
}
|
||||
ainput->isOpened = TRUE;
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function description
|
||||
*
|
||||
* @return 0 on success, otherwise a Win32 error code
|
||||
*/
|
||||
static UINT ainput_server_close(ainput_server_context* context)
|
||||
{
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
ainput_server* ainput = (ainput_server*)context;
|
||||
|
||||
WINPR_ASSERT(ainput);
|
||||
|
||||
if (!ainput->externalThread && ainput->thread)
|
||||
{
|
||||
SetEvent(ainput->stopEvent);
|
||||
|
||||
if (WaitForSingleObject(ainput->thread, INFINITE) == WAIT_FAILED)
|
||||
{
|
||||
error = GetLastError();
|
||||
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
CloseHandle(ainput->thread);
|
||||
CloseHandle(ainput->stopEvent);
|
||||
ainput->thread = NULL;
|
||||
ainput->stopEvent = NULL;
|
||||
}
|
||||
if (ainput->externalThread)
|
||||
{
|
||||
if (ainput->state != AINPUT_INITIAL)
|
||||
{
|
||||
WTSVirtualChannelClose(ainput->ainput_channel);
|
||||
ainput->ainput_channel = NULL;
|
||||
ainput->state = AINPUT_INITIAL;
|
||||
}
|
||||
}
|
||||
ainput->isOpened = FALSE;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static UINT ainput_server_initialize(ainput_server_context* context, BOOL externalThread)
|
||||
{
|
||||
UINT error = CHANNEL_RC_OK;
|
||||
ainput_server* ainput = (ainput_server*)context;
|
||||
|
||||
WINPR_ASSERT(ainput);
|
||||
|
||||
if (ainput->isOpened)
|
||||
{
|
||||
WLog_WARN(TAG, "Application error: AINPUT channel already initialized, calling in this "
|
||||
"state is not possible!");
|
||||
return ERROR_INVALID_STATE;
|
||||
}
|
||||
ainput->externalThread = externalThread;
|
||||
return error;
|
||||
}
|
||||
|
||||
ainput_server_context* ainput_server_context_new(HANDLE vcm)
|
||||
{
|
||||
ainput_server* ainput = (ainput_server*)calloc(1, sizeof(ainput_server));
|
||||
|
||||
if (!ainput)
|
||||
return NULL;
|
||||
|
||||
ainput->context.vcm = vcm;
|
||||
ainput->context.Open = ainput_server_open;
|
||||
ainput->context.IsOpen = ainput_server_is_open;
|
||||
ainput->context.Close = ainput_server_close;
|
||||
ainput->context.Initialize = ainput_server_initialize;
|
||||
ainput->context.Poll = ainput_server_context_poll;
|
||||
ainput->context.ChannelHandle = ainput_server_context_handle;
|
||||
|
||||
ainput->buffer = Stream_New(NULL, 4096);
|
||||
if (!ainput->buffer)
|
||||
goto fail;
|
||||
return &ainput->context;
|
||||
fail:
|
||||
ainput_server_context_free(ainput);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ainput_server_context_free(ainput_server_context* context)
|
||||
{
|
||||
ainput_server* ainput = (ainput_server*)context;
|
||||
if (ainput)
|
||||
{
|
||||
ainput_server_close(context);
|
||||
Stream_Free(ainput->buffer, TRUE);
|
||||
}
|
||||
free(ainput);
|
||||
}
|
||||
|
||||
static UINT ainput_process_message(ainput_server* ainput)
|
||||
{
|
||||
BOOL rc;
|
||||
UINT error = ERROR_INTERNAL_ERROR;
|
||||
ULONG BytesReturned;
|
||||
UINT16 MessageId;
|
||||
wStream* s;
|
||||
|
||||
WINPR_ASSERT(ainput);
|
||||
WINPR_ASSERT(ainput->ainput_channel);
|
||||
|
||||
s = ainput->buffer;
|
||||
WINPR_ASSERT(s);
|
||||
|
||||
Stream_SetPosition(s, 0);
|
||||
rc = WTSVirtualChannelRead(ainput->ainput_channel, 0, NULL, 0, &BytesReturned);
|
||||
if (!rc)
|
||||
goto out;
|
||||
|
||||
if (BytesReturned < 2)
|
||||
{
|
||||
error = CHANNEL_RC_OK;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
|
||||
error = CHANNEL_RC_NO_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (WTSVirtualChannelRead(ainput->ainput_channel, 0, (PCHAR)Stream_Buffer(s),
|
||||
(ULONG)Stream_Capacity(s), &BytesReturned) == FALSE)
|
||||
{
|
||||
WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
|
||||
goto out;
|
||||
}
|
||||
|
||||
Stream_SetLength(s, BytesReturned);
|
||||
Stream_Read_UINT16(s, MessageId);
|
||||
|
||||
switch (MessageId)
|
||||
{
|
||||
case MSG_AINPUT_MOUSE:
|
||||
error = ainput_server_recv_mouse_event(ainput, s);
|
||||
break;
|
||||
|
||||
default:
|
||||
WLog_ERR(TAG, "audin_server_thread_func: unknown MessageId %" PRIu8 "", MessageId);
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
if (error)
|
||||
WLog_ERR(TAG, "Response failed with error %" PRIu32 "!", error);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
BOOL ainput_server_context_handle(ainput_server_context* context, HANDLE* handle)
|
||||
{
|
||||
ainput_server* ainput = (ainput_server*)context;
|
||||
WINPR_ASSERT(ainput);
|
||||
WINPR_ASSERT(handle);
|
||||
|
||||
if (!ainput->externalThread)
|
||||
return FALSE;
|
||||
if (ainput->state == AINPUT_INITIAL)
|
||||
return FALSE;
|
||||
*handle = ainput_server_get_channel_handle(ainput);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
UINT ainput_server_context_poll_int(ainput_server_context* context)
|
||||
{
|
||||
ainput_server* ainput = (ainput_server*)context;
|
||||
UINT error = ERROR_INTERNAL_ERROR;
|
||||
|
||||
WINPR_ASSERT(ainput);
|
||||
|
||||
switch (ainput->state)
|
||||
{
|
||||
case AINPUT_INITIAL:
|
||||
error = ainput_server_open_channel(ainput);
|
||||
if (error)
|
||||
WLog_ERR(TAG, "ainput_server_open_channel failed with error %" PRIu32 "!", error);
|
||||
else
|
||||
ainput->state = AINPUT_OPENED;
|
||||
break;
|
||||
case AINPUT_OPENED:
|
||||
{
|
||||
BYTE* buffer = NULL;
|
||||
DWORD BytesReturned = 0;
|
||||
|
||||
if (WTSVirtualChannelQuery(ainput->ainput_channel, WTSVirtualChannelReady, &buffer,
|
||||
&BytesReturned) != TRUE)
|
||||
{
|
||||
WLog_ERR(TAG, "WTSVirtualChannelReady failed,");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*buffer != 0)
|
||||
{
|
||||
error = ainput_server_send_version(ainput);
|
||||
if (error)
|
||||
WLog_ERR(TAG, "audin_server_send_version failed with error %" PRIu32 "!",
|
||||
error);
|
||||
else
|
||||
ainput->state = AINPUT_VERSION_SENT;
|
||||
}
|
||||
else
|
||||
error = CHANNEL_RC_OK;
|
||||
}
|
||||
WTSFreeMemory(buffer);
|
||||
}
|
||||
break;
|
||||
case AINPUT_VERSION_SENT:
|
||||
error = ainput_process_message(ainput);
|
||||
break;
|
||||
|
||||
default:
|
||||
WLog_ERR(TAG, "AINPUT chanel is in invalid state %d", ainput->state);
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
UINT ainput_server_context_poll(ainput_server_context* context)
|
||||
{
|
||||
ainput_server* ainput = (ainput_server*)context;
|
||||
|
||||
WINPR_ASSERT(ainput);
|
||||
if (!ainput->externalThread)
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
return ainput_server_context_poll_int(context);
|
||||
}
|
||||
@ -444,11 +444,8 @@ static BOOL audin_open_device(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callb
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!supported)
|
||||
{
|
||||
if (!freerdp_dsp_context_reset(audin->dsp_context, audin->format))
|
||||
return FALSE;
|
||||
}
|
||||
if (!freerdp_dsp_context_reset(audin->dsp_context, audin->format))
|
||||
return FALSE;
|
||||
|
||||
IFCALLRET(audin->device->Open, error, audin->device, audin_receive_wave_data, callback);
|
||||
|
||||
|
||||
@ -345,7 +345,9 @@ static UINT audin_winmm_set_format(IAudinDevice* device, const AUDIO_FORMAT* for
|
||||
if (ppwfx->nBlockAlign != 2)
|
||||
{
|
||||
ppwfx->nBlockAlign = 2;
|
||||
ppwfx->nAvgBytesPerSec = ppwfx->nSamplesPerSec * ppwfx->nBlockAlign;
|
||||
}
|
||||
|
||||
if (!test_format_supported(ppwfx))
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
winmm->pwfx_cur = ppwfx;
|
||||
|
||||
@ -72,6 +72,24 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void disp_server_sanitize_monitor_layout(DISPLAY_CONTROL_MONITOR_LAYOUT* monitor)
|
||||
{
|
||||
if (monitor->PhysicalWidth < DISPLAY_CONTROL_MIN_PHYSICAL_MONITOR_WIDTH ||
|
||||
monitor->PhysicalWidth > DISPLAY_CONTROL_MAX_PHYSICAL_MONITOR_WIDTH ||
|
||||
monitor->PhysicalHeight < DISPLAY_CONTROL_MIN_PHYSICAL_MONITOR_HEIGHT ||
|
||||
monitor->PhysicalHeight > DISPLAY_CONTROL_MAX_PHYSICAL_MONITOR_HEIGHT)
|
||||
{
|
||||
if (monitor->PhysicalWidth != 0 || monitor->PhysicalHeight != 0)
|
||||
WLog_DBG(
|
||||
TAG,
|
||||
"Sanitizing invalid physical monitor size. Old physical monitor size: [%" PRIu32
|
||||
", %" PRIu32 "]",
|
||||
monitor->PhysicalWidth, monitor->PhysicalHeight);
|
||||
|
||||
monitor->PhysicalWidth = monitor->PhysicalHeight = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL disp_server_is_monitor_layout_valid(DISPLAY_CONTROL_MONITOR_LAYOUT* monitor)
|
||||
{
|
||||
if (monitor->Width < DISPLAY_CONTROL_MIN_MONITOR_WIDTH ||
|
||||
@ -88,22 +106,6 @@ static BOOL disp_server_is_monitor_layout_valid(DISPLAY_CONTROL_MONITOR_LAYOUT*
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (monitor->PhysicalWidth < DISPLAY_CONTROL_MIN_PHYSICAL_MONITOR_WIDTH ||
|
||||
monitor->PhysicalWidth > DISPLAY_CONTROL_MAX_PHYSICAL_MONITOR_WIDTH)
|
||||
{
|
||||
WLog_WARN(TAG, "Received invalid value for monitor->PhysicalWidth: %" PRIu32 "",
|
||||
monitor->PhysicalWidth);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (monitor->PhysicalHeight < DISPLAY_CONTROL_MIN_PHYSICAL_MONITOR_HEIGHT ||
|
||||
monitor->PhysicalHeight > DISPLAY_CONTROL_MAX_PHYSICAL_MONITOR_HEIGHT)
|
||||
{
|
||||
WLog_WARN(TAG, "Received invalid value for monitor->Height: %" PRIu32 "",
|
||||
monitor->PhysicalHeight);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
switch (monitor->Orientation)
|
||||
{
|
||||
case ORIENTATION_LANDSCAPE:
|
||||
@ -183,6 +185,8 @@ static UINT disp_recv_display_control_monitor_layout_pdu(wStream* s, DispServerC
|
||||
Stream_Read_UINT32(s, monitor->Orientation); /* Orientation (4 bytes) */
|
||||
Stream_Read_UINT32(s, monitor->DesktopScaleFactor); /* DesktopScaleFactor (4 bytes) */
|
||||
Stream_Read_UINT32(s, monitor->DeviceScaleFactor); /* DeviceScaleFactor (4 bytes) */
|
||||
|
||||
disp_server_sanitize_monitor_layout(monitor);
|
||||
WLog_DBG(TAG,
|
||||
"\t%d : Flags: 0x%08" PRIX32 " Left/Top: (%" PRId32 ",%" PRId32 ") W/H=%" PRIu32
|
||||
"x%" PRIu32 ")",
|
||||
|
||||
@ -33,6 +33,8 @@
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#include <winpr/sspicli.h>
|
||||
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/constants.h>
|
||||
#include <freerdp/channels/log.h>
|
||||
@ -204,7 +206,6 @@ LRESULT CALLBACK hotplug_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
|
||||
|
||||
drive.Type = RDPDR_DTYP_FILESYSTEM;
|
||||
drive.Path = drive_path;
|
||||
drive_path[1] = '\0';
|
||||
drive.automount = TRUE;
|
||||
drive.Name = drive_name;
|
||||
devman_load_device_service(rdpdr->devman,
|
||||
@ -583,7 +584,6 @@ static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg)
|
||||
|
||||
#else
|
||||
|
||||
|
||||
static const char* automountLocations[] = { "/run/user/%lu/gvfs", "/run/media/%s", "/media/%s",
|
||||
"/media", "/mnt" };
|
||||
|
||||
@ -591,16 +591,13 @@ static BOOL isAutomountLocation(const char* path)
|
||||
{
|
||||
const size_t nrLocations = sizeof(automountLocations) / sizeof(automountLocations[0]);
|
||||
size_t x;
|
||||
char buffer[MAX_PATH];
|
||||
char buffer[MAX_PATH] = { 0 };
|
||||
uid_t uid = getuid();
|
||||
char uname[MAX_PATH] = { 0 };
|
||||
ULONG size = sizeof(uname) - 1;
|
||||
|
||||
#ifndef HAVE_GETLOGIN_R
|
||||
strncpy(uname, getlogin(), sizeof(uname));
|
||||
#else
|
||||
if (getlogin_r(uname, sizeof(uname)) != 0)
|
||||
if (!GetUserNameExA(NameSamCompatible, uname, &size))
|
||||
return FALSE;
|
||||
#endif
|
||||
|
||||
if (!path)
|
||||
return FALSE;
|
||||
@ -656,7 +653,7 @@ static void handle_mountpoint(hotplug_dev* dev_array, size_t* size, const char*
|
||||
if (isAutomountLocation(mountpoint) && (*size < MAX_USB_DEVICES))
|
||||
{
|
||||
dev_array[*size].path = _strdup(mountpoint);
|
||||
dev_array[*size + 1].to_add = TRUE;
|
||||
dev_array[*size].to_add = TRUE;
|
||||
(*size)++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -612,6 +612,7 @@ UINT rdpei_server_send_sc_ready_ex(RdpeiServerContext* context, UINT32 version,
|
||||
{
|
||||
ULONG written;
|
||||
RdpeiServerPrivate* priv = context->priv;
|
||||
UINT32 pduLen = 4;
|
||||
|
||||
if (priv->automataState != STATE_INITIAL)
|
||||
{
|
||||
@ -621,14 +622,17 @@ UINT rdpei_server_send_sc_ready_ex(RdpeiServerContext* context, UINT32 version,
|
||||
|
||||
Stream_SetPosition(priv->outputStream, 0);
|
||||
|
||||
if (!Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH + 4))
|
||||
if (version >= RDPINPUT_PROTOCOL_V300)
|
||||
pduLen += 4;
|
||||
|
||||
if (!Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH + pduLen))
|
||||
{
|
||||
WLog_ERR(TAG, "Stream_EnsureCapacity failed!");
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
}
|
||||
|
||||
Stream_Write_UINT16(priv->outputStream, EVENTID_SC_READY);
|
||||
Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH + 4);
|
||||
Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH + pduLen);
|
||||
Stream_Write_UINT32(priv->outputStream, version);
|
||||
if (version >= RDPINPUT_PROTOCOL_V300)
|
||||
Stream_Write_UINT32(priv->outputStream, features);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
/**
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Graphics Pipeline Extension
|
||||
*
|
||||
@ -24,9 +24,12 @@
|
||||
#endif
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <assert.h>
|
||||
#include <winpr/stream.h>
|
||||
#include <freerdp/channels/log.h>
|
||||
|
||||
#define WINPR_ASSERT(x) assert(x)
|
||||
|
||||
#define TAG CHANNELS_TAG("rdpgfx.common")
|
||||
|
||||
#include "rdpgfx_common.h"
|
||||
@ -110,6 +113,9 @@ const char* rdpgfx_get_codec_id_string(UINT16 codecId)
|
||||
*/
|
||||
UINT rdpgfx_read_header(wStream* s, RDPGFX_HEADER* header)
|
||||
{
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(header);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 8)
|
||||
{
|
||||
WLog_ERR(TAG, "calloc failed!");
|
||||
@ -119,6 +125,13 @@ UINT rdpgfx_read_header(wStream* s, RDPGFX_HEADER* header)
|
||||
Stream_Read_UINT16(s, header->cmdId); /* cmdId (2 bytes) */
|
||||
Stream_Read_UINT16(s, header->flags); /* flags (2 bytes) */
|
||||
Stream_Read_UINT32(s, header->pduLength); /* pduLength (4 bytes) */
|
||||
|
||||
if ((header->pduLength < 8) || (Stream_GetRemainingLength(s) < (header->pduLength - 8)))
|
||||
{
|
||||
WLog_ERR(TAG, "header->pduLength %u less than 8!", header->pduLength);
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
return CHANNEL_RC_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -53,6 +53,12 @@
|
||||
#include <freerdp/server/rdpgfx.h>
|
||||
#include <freerdp/server/disp.h>
|
||||
|
||||
#if defined(CHANNEL_AINPUT_SERVER)
|
||||
#include <freerdp/server/ainput.h>
|
||||
#endif
|
||||
|
||||
extern void freerdp_channels_dummy(void);
|
||||
|
||||
void freerdp_channels_dummy(void)
|
||||
{
|
||||
audin_server_context* audin;
|
||||
@ -91,6 +97,12 @@ void freerdp_channels_dummy(void)
|
||||
rdpgfx_server_context_free(rdpgfx);
|
||||
disp = disp_server_context_new(NULL);
|
||||
disp_server_context_free(disp);
|
||||
#if defined(CHANNEL_AINPUT_SERVER)
|
||||
{
|
||||
ainput_server_context* ainput = ainput_server_context_new(NULL);
|
||||
ainput_server_context_free(ainput);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -615,7 +615,9 @@ static void tsmf_ffmpeg_free(ITSMFDecoder* decoder)
|
||||
static INIT_ONCE g_Initialized = INIT_ONCE_STATIC_INIT;
|
||||
static BOOL CALLBACK InitializeAvCodecs(PINIT_ONCE once, PVOID param, PVOID* context)
|
||||
{
|
||||
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100)
|
||||
avcodec_register_all();
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
message("PRELOADING android cache")
|
||||
set(CMAKE_TOOLCHAIN_FILE "$ANDROID_NDK/build/cmake/android.toolchain.cmake" CACHE PATH "ToolChain file")
|
||||
set(WITH_SANITIZE_ADDRESS ON)
|
||||
set(FREERDP_EXTERNAL_SSL_PATH $ENV{ANDROID_SSL_PATH} CACHE PATH "android ssl")
|
||||
# ANDROID_NDK and ANDROID_SDK must be set as environment variable
|
||||
#set(ANDROID_NDK $ENV{ANDROID_SDK} CACHE PATH "Android NDK")
|
||||
#set(ANDROID_SDK "${ANDROID_NDK}" CACHE PATH "android SDK")
|
||||
@ -1,11 +0,0 @@
|
||||
message("PRELOADING cache")
|
||||
set (WITH_MANPAGES OFF CACHE BOOL "man pages")
|
||||
set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type")
|
||||
set (WITH_CUPS OFF CACHE BOOL "CUPS printing")
|
||||
set (WITH_GSSAPI ON CACHE BOOL "Kerberos support")
|
||||
set (WITH_ALSA OFF CACHE BOOL "alsa audio")
|
||||
set (WITH_FFMPEG OFF CACHE BOOL "ffmepg support")
|
||||
set (WITH_XV OFF CACHE BOOL "xvideo support")
|
||||
set (BUILD_TESTING ON CACHE BOOL "build testing")
|
||||
set (WITH_XSHM OFF CACHE BOOL "build with xshm support")
|
||||
set (WITH_SANITIZE_ADDRESS ON)
|
||||
@ -1,7 +0,0 @@
|
||||
message("PRELOADING iOS cache")
|
||||
set (CMAKE_TOOLCHAIN_FILE "cmake/iOSToolchain.cmake" CACHE PATH "ToolChain file")
|
||||
set (FREERDP_IOS_EXTERNAL_SSL_PATH $ENV{FREERDP_IOS_EXTERNAL_SSL_PATH} CACHE PATH "android ssl")
|
||||
set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type")
|
||||
set (IOS_PLATFORM "SIMULATOR" CACHE STRING "iso platfrorm to build")
|
||||
set (WITH_SANITIZE_ADDRESS ON CACHE BOOL "build with address sanitizer")
|
||||
set (WITH_CLIENT OFF CACHE BOOL "disable iOS client")
|
||||
@ -1,53 +0,0 @@
|
||||
message("PRELOADING cache")
|
||||
set (BUILD_TESTING ON CACHE BOOL "testing")
|
||||
set (WITH_MANPAGES OFF CACHE BOOL "man pages")
|
||||
set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type")
|
||||
set (BUILD_TESTING ON CACHE BOOL "build testing")
|
||||
set (WITH_PULSE ON CACHE BOOL "pulse")
|
||||
set (WITH_CHANNELS ON CACHE BOOL "channels")
|
||||
set (BUILTIN_CHANNELS ON CACHE BOOL "static channels")
|
||||
set (WITH_CUPS ON CACHE BOOL "cups")
|
||||
set (WITH_WAYLAND ON CACHE BOOL "wayland")
|
||||
set (WITH_GSSAPI ON CACHE BOOL "Kerberos support")
|
||||
set (WITH_PCSC ON CACHE BOOL "PCSC")
|
||||
set (WITH_JPEG ON CACHE BOOL "jpeg")
|
||||
set (WITH_GSTREAMER_0_10 ON CACHE BOOL "gstreamer")
|
||||
set (WITH_GSM ON CACHE BOOL "gsm")
|
||||
set (CHANNEL_URBDRC ON CACHE BOOL "urbdrc")
|
||||
set (CHANNEL_URBDRC_CLIENT ON CACHE BOOL "urbdrc client")
|
||||
set (WITH_SERVER ON CACHE BOOL "server side")
|
||||
set (WITH_DEBUG_ALL OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_CAPABILITIES OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_CERTIFICATE OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_CHANNELS OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_CLIPRDR OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_RDPGFX OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_DVC OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_KBD OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_LICENSE OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_NEGO OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_NLA OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_NTLM OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_RAIL OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_RDP OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_RDPEI OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_REDIR OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_RDPDR OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_RFX OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_SCARD OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_SND OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_SVC OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_THREADS OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_TIMEZONE OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_TRANSPORT OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_TSG OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_TSMF OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_WND OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_X11 OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_X11_CLIPRDR OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_X11_LOCAL_MOVESIZE OFF CACHE BOOL "enable debug")
|
||||
set (WITH_DEBUG_XV OFF CACHE BOOL "enable debug")
|
||||
set (WITH_SAMPLE ON CACHE BOOL "samples")
|
||||
set (WITH_NO_UNDEFINED ON CACHE BOOL "don't link with undefined symbols")
|
||||
set (WITH_SANITIZE_ADDRESS ON)
|
||||
set (WITH_PROXY_MODULES OFF CACHE BOOL "compile proxy modules")
|
||||
@ -1,8 +0,0 @@
|
||||
message("PRELOADING mac cache")
|
||||
set (WITH_MANPAGES OFF CACHE BOOL "man pages")
|
||||
set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type")
|
||||
set (WITH_CUPS ON CACHE BOOL "CUPS printing")
|
||||
set (CHANNEL_URBDRC OFF CACHE BOOL "USB redirection")
|
||||
set (WITH_X11 ON CACHE BOOL "Enable X11")
|
||||
set (BUILD_TESTING ON CACHE BOOL "build testing")
|
||||
set (WITH_SANITIZE_ADDRESS ON)
|
||||
@ -1,11 +0,0 @@
|
||||
message("PRELOADING cache")
|
||||
set (WITH_MANPAGES OFF CACHE BOOL "man pages")
|
||||
set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type")
|
||||
set (WITH_CUPS OFF CACHE BOOL "CUPS printing")
|
||||
set (WITH_GSSAPI ON CACHE BOOL "Kerberos support")
|
||||
set (WITH_ALSA OFF CACHE BOOL "alsa audio")
|
||||
set (WITH_FFMPEG OFF CACHE BOOL "ffmepg support")
|
||||
set (WITH_XV OFF CACHE BOOL "xvideo support")
|
||||
set (BUILD_TESTING ON CACHE BOOL "build testing")
|
||||
set (WITH_XSHM OFF CACHE BOOL "build with xshm support")
|
||||
set (WITH_SANITIZE_ADDRESS ON)
|
||||
@ -1,6 +0,0 @@
|
||||
message("PRELOADING windows cache")
|
||||
set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type")
|
||||
set (WITH_SERVER "ON" CACHE BOOL "Build server binaries")
|
||||
set (CHANNEL_URBDRC OFF CACHE BOOL "USB redirection")
|
||||
set (BUILD_TESTING ON CACHE BOOL "build testing")
|
||||
set (WITH_SANITIZE_ADDRESS ON)
|
||||
@ -43,7 +43,10 @@ if(FREERDP_VENDOR AND WITH_CLIENT)
|
||||
add_subdirectory(iOS)
|
||||
endif()
|
||||
else()
|
||||
add_subdirectory(Mac)
|
||||
option(WITH_CLIENT_MAC "Build native mac client" ON)
|
||||
if (WITH_CLIENT_MAC)
|
||||
add_subdirectory(Mac)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <winpr/sspicli.h>
|
||||
#include <float.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
@ -1183,20 +1184,12 @@ static BOOL xf_pre_connect(freerdp* instance)
|
||||
|
||||
if (!settings->Username && !settings->CredentialsFromStdin && !settings->SmartcardLogon)
|
||||
{
|
||||
int rc;
|
||||
char login_name[MAX_PATH] = { 0 };
|
||||
ULONG size = sizeof(login_name) - 1;
|
||||
|
||||
#ifdef HAVE_GETLOGIN_R
|
||||
rc = getlogin_r(login_name, sizeof(login_name));
|
||||
#else
|
||||
strncpy(login_name, getlogin(), sizeof(login_name));
|
||||
rc = 0;
|
||||
#endif
|
||||
if (rc == 0)
|
||||
if (GetUserNameExA(NameSamCompatible, login_name, &size))
|
||||
{
|
||||
settings->Username = _strdup(login_name);
|
||||
|
||||
if (!settings->Username)
|
||||
if (!freerdp_settings_set_string(settings, FreeRDP_Username, login_name))
|
||||
return FALSE;
|
||||
|
||||
WLog_INFO(TAG, "No user name set. - Using login name: %s", settings->Username);
|
||||
|
||||
@ -1,33 +0,0 @@
|
||||
|
||||
if (X264_INCLUDE_DIR AND X264_LIBRARY)
|
||||
set(X264_FIND_QUIETLY TRUE)
|
||||
endif (X264_INCLUDE_DIR AND X264_LIBRARY)
|
||||
|
||||
find_path(X264_INCLUDE_DIR NAMES x264.h
|
||||
PATH_SUFFIXES include
|
||||
HINTS ${X264_ROOT})
|
||||
find_library(X264_LIBRARY
|
||||
NAMES x264
|
||||
PATH_SUFFIXES lib
|
||||
HINTS ${X264_ROOT})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(x264 DEFAULT_MSG X264_LIBRARY X264_INCLUDE_DIR)
|
||||
|
||||
if (X264_INCLUDE_DIR AND X264_LIBRARY)
|
||||
set(X264_FOUND TRUE)
|
||||
set(X264_LIBRARIES ${X264_LIBRARY})
|
||||
endif (X264_INCLUDE_DIR AND X264_LIBRARY)
|
||||
|
||||
if (X264_FOUND)
|
||||
if (NOT X264_FIND_QUIETLY)
|
||||
message(STATUS "Found x264: ${X264_LIBRARIES}")
|
||||
endif (NOT X264_FIND_QUIETLY)
|
||||
else (X264_FOUND)
|
||||
if (X264_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "x264 was not found")
|
||||
endif(X264_FIND_REQUIRED)
|
||||
endif (X264_FOUND)
|
||||
|
||||
mark_as_advanced(X264_INCLUDE_DIR X264_LIBRARY)
|
||||
|
||||
@ -1,196 +0,0 @@
|
||||
# This file is based off of the Platform/Darwin.cmake and Platform/UnixPaths.cmake
|
||||
# files which are included with CMake 2.8.4
|
||||
# It has been altered for iOS development
|
||||
|
||||
# Options:
|
||||
#
|
||||
# IOS_PLATFORM = OS (default) or SIMULATOR
|
||||
# This decides if SDKS will be selected from the iPhoneOS.platform or iPhoneSimulator.platform folders
|
||||
# OS - the default, used to build for iPhone and iPad physical devices, which have an arm arch.
|
||||
# SIMULATOR - used to build for the Simulator platforms, which have an x86 arch.
|
||||
#
|
||||
# CMAKE_IOS_DEVELOPER_ROOT = automatic(default) or /path/to/platform/Developer folder
|
||||
# By default this location is automatcially chosen based on the IOS_PLATFORM value above.
|
||||
# If set manually, it will override the default location and force the user of a particular Developer Platform
|
||||
#
|
||||
# CMAKE_IOS_SDK_ROOT = automatic(default) or /path/to/platform/Developer/SDKs/SDK folder
|
||||
# By default this location is automatcially chosen based on the CMAKE_IOS_DEVELOPER_ROOT value.
|
||||
# In this case it will always be the most up-to-date SDK found in the CMAKE_IOS_DEVELOPER_ROOT path.
|
||||
# If set manually, this will force the use of a specific SDK version
|
||||
|
||||
# Macros:
|
||||
#
|
||||
# set_xcode_property (TARGET XCODE_PROPERTY XCODE_VALUE)
|
||||
# A convenience macro for setting xcode specific properties on targets
|
||||
# example: set_xcode_property (myioslib IPHONEOS_DEPLOYMENT_TARGET "3.1")
|
||||
#
|
||||
# find_host_package (PROGRAM ARGS)
|
||||
# A macro used to find executable programs on the host system, not within the iOS environment.
|
||||
# Thanks to the android-cmake project for providing the command
|
||||
|
||||
|
||||
# Standard settings
|
||||
set (CMAKE_SYSTEM_NAME Darwin)
|
||||
set (CMAKE_SYSTEM_VERSION 1)
|
||||
set (UNIX True)
|
||||
set (APPLE True)
|
||||
set (IOS True)
|
||||
|
||||
# Required as of cmake 2.8.10
|
||||
#set (CMAKE_OSX_DEPLOYMENT_TARGET "" CACHE STRING "Force unset of the deployment target for iOS" FORCE)
|
||||
|
||||
# Determine the cmake host system version so we know where to find the iOS SDKs
|
||||
find_program (CMAKE_UNAME uname /bin /usr/bin /usr/local/bin)
|
||||
if (CMAKE_UNAME)
|
||||
exec_program(uname ARGS -r OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION)
|
||||
string (REGEX REPLACE "^([0-9]+)\\.([0-9]+).*$" "\\1" DARWIN_MAJOR_VERSION "${CMAKE_HOST_SYSTEM_VERSION}")
|
||||
endif (CMAKE_UNAME)
|
||||
|
||||
# Force the compilers to gcc for iOS
|
||||
include (CMakeForceCompiler)
|
||||
CMAKE_FORCE_C_COMPILER (/usr/bin/clang Apple)
|
||||
CMAKE_FORCE_CXX_COMPILER (/usr/bin/clang++ Apple)
|
||||
set(CMAKE_AR ar CACHE FILEPATH "" FORCE)
|
||||
|
||||
# Skip the platform compiler checks for cross compiling
|
||||
#set (CMAKE_CXX_COMPILER_WORKS TRUE)
|
||||
#set (CMAKE_C_COMPILER_WORKS TRUE)
|
||||
|
||||
# All iOS/Darwin specific settings - some may be redundant
|
||||
set (CMAKE_SHARED_LIBRARY_PREFIX "lib")
|
||||
set (CMAKE_SHARED_LIBRARY_SUFFIX ".dylib")
|
||||
set (CMAKE_SHARED_MODULE_PREFIX "lib")
|
||||
set (CMAKE_SHARED_MODULE_SUFFIX ".so")
|
||||
set (CMAKE_MODULE_EXISTS 1)
|
||||
set (CMAKE_DL_LIBS "")
|
||||
|
||||
set (CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ")
|
||||
set (CMAKE_C_OSX_CURRENT_VERSION_FLAG "-current_version ")
|
||||
set (CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}")
|
||||
set (CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}")
|
||||
|
||||
# Hidden visibilty is required for cxx on iOS
|
||||
set (CMAKE_C_FLAGS_INIT "")
|
||||
set (CMAKE_CXX_FLAGS_INIT "-fvisibility=hidden -fvisibility-inlines-hidden -isysroot ${CMAKE_OSX_SYSROOT}")
|
||||
|
||||
set (CMAKE_C_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}")
|
||||
set (CMAKE_CXX_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}")
|
||||
|
||||
set (CMAKE_PLATFORM_HAS_INSTALLNAME 1)
|
||||
set (CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-dynamiclib -headerpad_max_install_names")
|
||||
set (CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle -headerpad_max_install_names")
|
||||
set (CMAKE_SHARED_MODULE_LOADER_C_FLAG "-Wl,-bundle_loader,")
|
||||
set (CMAKE_SHARED_MODULE_LOADER_CXX_FLAG "-Wl,-bundle_loader,")
|
||||
set (CMAKE_FIND_LIBRARY_SUFFIXES ".dylib" ".so" ".a")
|
||||
|
||||
# hack: if a new cmake (which uses CMAKE_INSTALL_NAME_TOOL) runs on an old build tree
|
||||
# (where install_name_tool was hardcoded) and where CMAKE_INSTALL_NAME_TOOL isn't in the cache
|
||||
# and still cmake didn't fail in CMakeFindBinUtils.cmake (because it isn't rerun)
|
||||
# hardcode CMAKE_INSTALL_NAME_TOOL here to install_name_tool, so it behaves as it did before, Alex
|
||||
if (NOT DEFINED CMAKE_INSTALL_NAME_TOOL)
|
||||
find_program(CMAKE_INSTALL_NAME_TOOL install_name_tool)
|
||||
endif (NOT DEFINED CMAKE_INSTALL_NAME_TOOL)
|
||||
|
||||
# Setup iOS platform unless specified manually with IOS_PLATFORM
|
||||
if (NOT DEFINED IOS_PLATFORM)
|
||||
set (IOS_PLATFORM "OS")
|
||||
endif (NOT DEFINED IOS_PLATFORM)
|
||||
set (IOS_PLATFORM ${IOS_PLATFORM} CACHE STRING "Type of iOS Platform")
|
||||
|
||||
# Check the platform selection and setup for developer root
|
||||
if (${IOS_PLATFORM} STREQUAL "OS")
|
||||
set (IOS_PLATFORM_LOCATION "iPhoneOS.platform")
|
||||
|
||||
# This causes the installers to properly locate the output libraries
|
||||
set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphoneos")
|
||||
elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR")
|
||||
set (IOS_PLATFORM_LOCATION "iPhoneSimulator.platform")
|
||||
|
||||
# This causes the installers to properly locate the output libraries
|
||||
set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator")
|
||||
else (${IOS_PLATFORM} STREQUAL "OS")
|
||||
message (FATAL_ERROR "Unsupported IOS_PLATFORM value selected. Please choose OS or SIMULATOR")
|
||||
endif (${IOS_PLATFORM} STREQUAL "OS")
|
||||
|
||||
# Setup iOS developer location unless specified manually with CMAKE_IOS_DEVELOPER_ROOT
|
||||
# Note Xcode 4.3 changed the installation location, choose the most recent one available
|
||||
set (XCODE_POST_43_ROOT "/Applications/Xcode.app/Contents/Developer/Platforms/${IOS_PLATFORM_LOCATION}/Developer")
|
||||
set (XCODE_PRE_43_ROOT "/Developer/Platforms/${IOS_PLATFORM_LOCATION}/Developer")
|
||||
if (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT)
|
||||
if (EXISTS ${XCODE_POST_43_ROOT})
|
||||
set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_POST_43_ROOT})
|
||||
elseif(EXISTS ${XCODE_PRE_43_ROOT})
|
||||
set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_PRE_43_ROOT})
|
||||
endif (EXISTS ${XCODE_POST_43_ROOT})
|
||||
endif (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT)
|
||||
set (CMAKE_IOS_DEVELOPER_ROOT ${CMAKE_IOS_DEVELOPER_ROOT} CACHE PATH "Location of iOS Platform")
|
||||
|
||||
# Find and use the most recent iOS sdk unless specified manually with CMAKE_IOS_SDK_ROOT
|
||||
if (NOT DEFINED CMAKE_IOS_SDK_ROOT)
|
||||
file (GLOB _CMAKE_IOS_SDKS "${CMAKE_IOS_DEVELOPER_ROOT}/SDKs/*")
|
||||
if (_CMAKE_IOS_SDKS)
|
||||
list (SORT _CMAKE_IOS_SDKS)
|
||||
list (REVERSE _CMAKE_IOS_SDKS)
|
||||
list (GET _CMAKE_IOS_SDKS 0 CMAKE_IOS_SDK_ROOT)
|
||||
else (_CMAKE_IOS_SDKS)
|
||||
message (FATAL_ERROR "No iOS SDK's found in default search path ${CMAKE_IOS_DEVELOPER_ROOT}. Manually set CMAKE_IOS_SDK_ROOT or install the iOS SDK.")
|
||||
endif (_CMAKE_IOS_SDKS)
|
||||
message (STATUS "Toolchain using default iOS SDK: ${CMAKE_IOS_SDK_ROOT}")
|
||||
endif (NOT DEFINED CMAKE_IOS_SDK_ROOT)
|
||||
set (CMAKE_IOS_SDK_ROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Location of the selected iOS SDK")
|
||||
|
||||
# Set the sysroot default to the most recent SDK
|
||||
set (CMAKE_OSX_SYSROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Sysroot used for iOS support")
|
||||
|
||||
# set the architecture for iOS
|
||||
# NOTE: Currently both ARCHS_STANDARD_32_BIT and ARCHS_UNIVERSAL_IPHONE_OS set armv7 only, so set both manually
|
||||
if (${IOS_PLATFORM} STREQUAL "OS")
|
||||
set (IOS_ARCH armv7 armv7s)
|
||||
set (CMAKE_SYSTEM_PROCESSOR armv7)
|
||||
else (${IOS_PLATFORM} STREQUAL "OS")
|
||||
set (IOS_ARCH i386)
|
||||
set (CMAKE_SYSTEM_PROCESSOR i386)
|
||||
endif (${IOS_PLATFORM} STREQUAL "OS")
|
||||
|
||||
set (CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE string "Build architecture for iOS")
|
||||
|
||||
# Set the find root to the iOS developer roots and to user defined paths
|
||||
set (CMAKE_FIND_ROOT_PATH ${CMAKE_IOS_DEVELOPER_ROOT} ${CMAKE_IOS_SDK_ROOT} ${CMAKE_PREFIX_PATH} CACHE string "iOS find search path root")
|
||||
|
||||
# default to searching for frameworks first
|
||||
set (CMAKE_FIND_FRAMEWORK FIRST)
|
||||
|
||||
# set up the default search directories for frameworks
|
||||
set (CMAKE_SYSTEM_FRAMEWORK_PATH
|
||||
${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks
|
||||
${CMAKE_IOS_SDK_ROOT}/System/Library/PrivateFrameworks
|
||||
${CMAKE_IOS_SDK_ROOT}/Developer/Library/Frameworks
|
||||
)
|
||||
|
||||
# only search the iOS sdks, not the remainder of the host filesystem
|
||||
set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
|
||||
set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
|
||||
|
||||
# This little macro lets you set any XCode specific property
|
||||
macro (set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE)
|
||||
set_property (TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY} ${XCODE_VALUE})
|
||||
endmacro (set_xcode_property)
|
||||
|
||||
|
||||
# This macro lets you find executable programs on the host system
|
||||
macro (find_host_package)
|
||||
set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER)
|
||||
set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER)
|
||||
set (IOS FALSE)
|
||||
|
||||
find_package(${ARGN})
|
||||
|
||||
set (IOS TRUE)
|
||||
set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
|
||||
set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
endmacro (find_host_package)
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
#cmakedefine HAVE_VALGRIND_MEMCHECK_H
|
||||
#cmakedefine HAVE_EXECINFO_H
|
||||
#cmakedefine HAVE_GETLOGIN_R
|
||||
#cmakedefine HAVE_GETPWUID_R
|
||||
|
||||
/* Features */
|
||||
#cmakedefine SWRESAMPLE_FOUND
|
||||
@ -63,9 +64,9 @@
|
||||
#cmakedefine WITH_FFMPEG
|
||||
#cmakedefine WITH_DSP_EXPERIMENTAL
|
||||
#cmakedefine WITH_DSP_FFMPEG
|
||||
#cmakedefine WITH_X264
|
||||
#cmakedefine WITH_OPENCL
|
||||
#cmakedefine WITH_MEDIA_FOUNDATION
|
||||
#cmakedefine WITH_MEDIACODEC
|
||||
|
||||
#cmakedefine WITH_VAAPI
|
||||
|
||||
@ -74,6 +75,9 @@
|
||||
#cmakedefine WITH_RDPDR
|
||||
|
||||
/* Channels */
|
||||
#cmakedefine CHANNEL_AINPUT
|
||||
#cmakedefine CHANNEL_AINPUT_CLIENT
|
||||
#cmakedefine CHANNEL_AINPUT_SERVER
|
||||
#cmakedefine CHANNEL_AUDIN
|
||||
#cmakedefine CHANNEL_AUDIN_CLIENT
|
||||
#cmakedefine CHANNEL_AUDIN_SERVER
|
||||
|
||||
@ -1,86 +0,0 @@
|
||||
Overview
|
||||
========
|
||||
|
||||
The FreeRDP Android port consists of three parts:
|
||||
* Android Java GUI (client/Android/Studio)
|
||||
* FreeRDP library and its dependencies
|
||||
* JNI bindings (client/Android/android_freerdp.c
|
||||
and client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/LibFreeRDP.java)
|
||||
|
||||
Build requirements
|
||||
=================
|
||||
|
||||
For the Android port some additional dependencies need to be fulfilled:
|
||||
|
||||
* for JNI
|
||||
- CMake >= 3.0
|
||||
- Android NDK (>= r9)
|
||||
|
||||
* for the Java GUI
|
||||
- Android SDK
|
||||
|
||||
FreeRDP requires openssl libraries for building but they are not part of the
|
||||
Android NDK and therefore they need to be prebuild manually.
|
||||
|
||||
For jpeg support https://github.com/akallabeth/jpeg8d has been tested and used.
|
||||
However, any other static builds should work as well.
|
||||
|
||||
Build native libraries:
|
||||
======================
|
||||
From the project root run the build script
|
||||
./scripts/android-build-freerdp.sh --ndk <ANDROID_NDK> --sdk <ANDROID_SDK>
|
||||
Set ANDROID_NDK and ANDROID_SDK to the absolute paths on your machine.
|
||||
This will fetch sources from git and build OpenSSL, OpenH264, libJPEG.
|
||||
The native FreeRDP libraries will also be build.
|
||||
|
||||
Currently the default script builds for:
|
||||
* armeabi
|
||||
* armeabi-v7a
|
||||
* x86
|
||||
* mips
|
||||
* arm64-v8a
|
||||
* x86_64
|
||||
* mips64
|
||||
|
||||
When the script is finished the libraries are ready for android studio to
|
||||
be picked up in client/Android/Studio/freeRDPCore/src/main/jniLibs
|
||||
|
||||
The default configuration build configuration can be found in
|
||||
./scripts/android-build.conf and is configured to provide debug builds.
|
||||
They are limited to API level 21 and above.
|
||||
|
||||
If release binaries (and old android API support) are required, build 32 bit architectures with
|
||||
./scripts/android-build-freerdp.sh --ndk <ANDROID_NDK> --sdk <ANDROID_SDK> --conf ./scripts/android-build-32.conf
|
||||
and 64 bit architectures with
|
||||
./scripts/android-build-freerdp.sh --ndk <ANDROID_NDK> --sdk <ANDROID_SDK> --conf ./scripts/android-build-64.conf
|
||||
|
||||
Building the APK (Android Studio)
|
||||
================
|
||||
|
||||
* Import the folder client/Android/Studio in Android Studio
|
||||
* You are ready to go
|
||||
|
||||
Building the APK (gradle)
|
||||
================
|
||||
|
||||
* change to directory client/Android/Studio
|
||||
* run ./gradlew build to build
|
||||
* run ./gradlew tasks for other gradle options
|
||||
|
||||
Development
|
||||
===========
|
||||
|
||||
Updating JNI
|
||||
------------
|
||||
|
||||
Whenever the FreeRDP API changes or you need some extra functionality in your Java
|
||||
GUI the JNI needs to be updated.
|
||||
|
||||
The JNI functions are defined in client/Android/android_freerdp.c
|
||||
Add the new functions to the methods struct.
|
||||
|
||||
* edit client/Android/src/com/freerdp/afreerdp/services/LibFreeRDP.Java to
|
||||
reflect your changes
|
||||
* edit client/Android/android_freerdp.c and adjust the methods struct to reflect
|
||||
the changes made.
|
||||
|
||||
100
docs/README.ios
100
docs/README.ios
@ -1,100 +0,0 @@
|
||||
Overview
|
||||
========
|
||||
|
||||
The FreeRDP iOS port allows users to enjoy FreeRDP features on Apple iOS devices.
|
||||
The application was written to be compatible with devices running iOS 4.3 or higher.
|
||||
|
||||
Build requirements
|
||||
==================
|
||||
|
||||
The following prerequisites are required in order to build the iOS port:
|
||||
|
||||
- cmake version >= 2.8.9
|
||||
- latest Xcode installed (>= 4.6)
|
||||
- installed Provisioning Profile and iOS Developer Certificate for code signing
|
||||
(not required for simulator builds)
|
||||
- pre-build static OpenSSL libraries (see below)
|
||||
|
||||
FreeRDP requires OpenSSL libraries for building but they are not part of the iOS SDK and therefore they need to be pre-build manually.
|
||||
There are various versions and builds of static OpenSSL libraries floating around like iOSPorts.
|
||||
At the time of writing we have tested and used a small script (OpenSSL-DownloadAndBuild.command) that downloads and builds armv7, armv7s and i386 versions of the OpenSSL 1.0.0e libraries.
|
||||
|
||||
If you don't care about modifying the OpenSSL build you can run the following command in the FreeRDP root directory:
|
||||
|
||||
./scripts/OpenSSL-DownloadAndBuild.command
|
||||
|
||||
The output of the script will be found in external/openssl/. In case you want a
|
||||
different install/build directory you specify it as first parameter:
|
||||
|
||||
./scripts/OpenSSL-DownloadAndBuild.command /tmp/
|
||||
|
||||
In the example above the output can then be found in /tmp/openssl.
|
||||
|
||||
The script uses oldest iOS/iPhoneSimulator SDK found on the build machine per default. If it is required to build against a specific SDK version
|
||||
the variable SDK_VERSION can be used to specify it. The minimum SDK version that should be used can be set with MIN_SDK_VERSION within the script.
|
||||
|
||||
When the script is finished you will find libcrypto.a and libssl.at, both universal libraries containing all openssl/lib
|
||||
subfolder in the specified
|
||||
install directory (external per default)
|
||||
|
||||
When the script finishes you will find libcrypto.a and libssl.a, both universal
|
||||
binary libraries containing arm and i386 targets in order to compile FreeRDP for
|
||||
iOS devices and the simulator, in the lib subfolder of your installation
|
||||
directory.
|
||||
|
||||
If you build OpenSSL youself or with an install directory specified you need to set FREERDP_IOS_EXTERNAL_SSL_PATH when running cmake.
|
||||
|
||||
|
||||
Building
|
||||
========
|
||||
|
||||
Run the following commands in the top level FreeRDP directory:
|
||||
|
||||
cmake -DCMAKE_TOOLCHAIN_FILE=cmake/iOSToolchain.cmake -GXcode
|
||||
|
||||
This command will create a XCode project in the FreeRDP root folder called FreeRDP.xcodeproj.
|
||||
Open the project in XCode and modify, build or run the app.
|
||||
|
||||
Alternatively you can also build the project from the command line using xcodebuild:
|
||||
|
||||
xcodebuild -project FreeRDP.xcodeproj -configuration Debug -sdk iphoneos6.1
|
||||
|
||||
or with cmake --build . in your build directory.
|
||||
|
||||
Notes:
|
||||
|
||||
* XCode, by default will build the application into its derived data location (usually in ~/Library/Developer/...).
|
||||
If you want to specify an output directory add CONFIGURATION_BUILD_DIR=<output-path-here> to the end of above command line.
|
||||
|
||||
* If using XCode choose "Open Other" from the welcome screen, browse to the FreeRDP root directory and select FreeRDP.xcodeproj. Alternatively you can
|
||||
also start it with "open FreeRDP.xcodeproj".
|
||||
|
||||
* If you switch between platforms (OS and SIMULATOR) please remove CMakeCache.txt and CMakeFiles/ before calling cmake again.
|
||||
Otherwise build errors might occur (this seems to be a bug with cmake or the cmake scripts). To switch between platforms do:
|
||||
|
||||
rm CMakeCache.txt
|
||||
rm -rf CMakeFiles/
|
||||
|
||||
before you run a new cmake command with the desired platform.
|
||||
|
||||
|
||||
cmake variables
|
||||
===============
|
||||
|
||||
CMAKE_TOOLCHAIN_FILE
|
||||
* the toolchain file to use must be cmake/iOSToolchain.cmake
|
||||
|
||||
IOS_PLATFORM (OS (default), SIMULATOR)
|
||||
* the platform for which to build iFreeRDP. OS compiles for iOS devices (using armv7 and armv7s ABIs) and SIMULATOR compiles for the iOS Simulator (i386)
|
||||
|
||||
CMAKE_IOS_DEVELOPER_ROOT (used by toolchain file)
|
||||
* absolute path to the iOS developer platform (i.e. /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer) the toolchain file will usually auto-detect the correct Developer platform depending on IOS_PLATFORM
|
||||
|
||||
CMAKE_IOS_SDK_ROOT (used by toolchain file)
|
||||
* absolute path to the iOS SDK (i.e. /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.1.sdk) the toolchain file will usually auto-detect the correct SDK, depending on IOS_PLATFORM
|
||||
|
||||
FREERDP_IOS_EXTERNAL_SSL_PATH (used by FindOpenSSL)
|
||||
* absolut root path to the pre-built static OpenSSL libraries
|
||||
|
||||
CODE_SIGN_IDENTITY
|
||||
* specify the identity to sign the code with
|
||||
@ -1,7 +0,0 @@
|
||||
Starting with "El Capitan" Apple removed the openssl headers. Therefore it's
|
||||
required to build openssl manually upfront. For example by using MacPorts or Homebrew.
|
||||
To build FreeRDP against this library it's required to set the PKG_CONFIG_PATH
|
||||
pointing to the openssl root directory befor building.
|
||||
For example with brew it would look like this:
|
||||
|
||||
export PKG_CONFIG_PATH=$(brew --prefix)/opt/openssl/lib/pkgconfig
|
||||
61
include/freerdp/channels/ainput.h
Normal file
61
include/freerdp/channels/ainput.h
Normal file
@ -0,0 +1,61 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Audio Input Redirection Virtual Channel
|
||||
*
|
||||
* Copyright 2022 Armin Novak <anovak@thincast.com>
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_CHANNEL_AINPUT_H
|
||||
#define FREERDP_CHANNEL_AINPUT_H
|
||||
|
||||
#include <freerdp/api.h>
|
||||
#include <freerdp/dvc.h>
|
||||
#include <freerdp/types.h>
|
||||
|
||||
#define AINPUT_CHANNEL_NAME "ainput"
|
||||
#define AINPUT_DVC_CHANNEL_NAME "FreeRDP::Advanced::Input"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MSG_AINPUT_VERSION = 0x01,
|
||||
MSG_AINPUT_MOUSE = 0x02
|
||||
} eAInputMsgType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
AINPUT_FLAGS_WHEEL = 0x0001,
|
||||
AINPUT_FLAGS_MOVE = 0x0004,
|
||||
AINPUT_FLAGS_DOWN = 0x0008,
|
||||
|
||||
AINPUT_FLAGS_REL = 0x0010,
|
||||
AINPUT_FLAGS_HAVE_REL = 0x0020,
|
||||
|
||||
/* Pointer Flags */
|
||||
AINPUT_FLAGS_BUTTON1 = 0x1000, /* left */
|
||||
AINPUT_FLAGS_BUTTON2 = 0x2000, /* right */
|
||||
AINPUT_FLAGS_BUTTON3 = 0x4000, /* middle */
|
||||
|
||||
/* Extended Pointer Flags */
|
||||
AINPUT_XFLAGS_BUTTON1 = 0x0100,
|
||||
AINPUT_XFLAGS_BUTTON2 = 0x0200
|
||||
} AInputEventFlags;
|
||||
|
||||
typedef struct ainput_client_context AInputClientContext;
|
||||
|
||||
#define AINPUT_VERSION_MAJOR 1
|
||||
#define AINPUT_VERSION_MINOR 0
|
||||
|
||||
#endif /* FREERDP_CHANNEL_AINPUT_H */
|
||||
38
include/freerdp/client/ainput.h
Normal file
38
include/freerdp/client/ainput.h
Normal file
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Display Update Virtual Channel Extension
|
||||
*
|
||||
* Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2015 Thincast Technologies GmbH
|
||||
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_CHANNEL_AINPUT_CLIENT_AINPUT_H
|
||||
#define FREERDP_CHANNEL_AINPUT_CLIENT_AINPUT_H
|
||||
|
||||
#include <freerdp/channels/ainput.h>
|
||||
|
||||
typedef UINT (*pcAInputSendInputEvent)(AInputClientContext* context, UINT64 flags, INT32 x,
|
||||
INT32 y);
|
||||
|
||||
struct ainput_client_context
|
||||
{
|
||||
void* handle;
|
||||
void* custom;
|
||||
|
||||
pcAInputSendInputEvent AInputSendInputEvent;
|
||||
};
|
||||
|
||||
#endif /* FREERDP_CHANNEL_AINPUT_CLIENT_AINPUT_H */
|
||||
114
include/freerdp/server/ainput.h
Normal file
114
include/freerdp/server/ainput.h
Normal file
@ -0,0 +1,114 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* AInput Virtual Channel Extension
|
||||
*
|
||||
* Copyright 2022 Armin Novak <anovak@thincast.com>
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
#ifndef FREERDP_CHANNEL_AINPUT_SERVER_H
|
||||
#define FREERDP_CHANNEL_AINPUT_SERVER_H
|
||||
|
||||
#include <freerdp/channels/wtsvc.h>
|
||||
|
||||
typedef enum AINPUT_SERVER_OPEN_RESULT
|
||||
{
|
||||
AINPUT_SERVER_OPEN_RESULT_OK = 0,
|
||||
AINPUT_SERVER_OPEN_RESULT_CLOSED = 1,
|
||||
AINPUT_SERVER_OPEN_RESULT_NOTSUPPORTED = 2,
|
||||
AINPUT_SERVER_OPEN_RESULT_ERROR = 3
|
||||
} AINPUT_SERVER_OPEN_RESULT;
|
||||
|
||||
typedef struct _ainput_server_context ainput_server_context;
|
||||
|
||||
typedef UINT (*psAInputServerInitialize)(ainput_server_context* context, BOOL externalThread);
|
||||
typedef UINT (*psAInputServerPoll)(ainput_server_context* context);
|
||||
typedef BOOL (*psAInputServerChannelHandle)(ainput_server_context* context, HANDLE* handle);
|
||||
|
||||
typedef UINT (*psAInputServerOpen)(ainput_server_context* context);
|
||||
typedef UINT (*psAInputServerClose)(ainput_server_context* context);
|
||||
typedef BOOL (*psAInputServerIsOpen)(ainput_server_context* context);
|
||||
|
||||
typedef UINT (*psAInputServerOpenResult)(ainput_server_context* context,
|
||||
AINPUT_SERVER_OPEN_RESULT result);
|
||||
typedef UINT (*psAInputServerMouseEvent)(ainput_server_context* context, UINT64 timestamp,
|
||||
UINT64 flags, INT32 x, INT32 y);
|
||||
|
||||
struct _ainput_server_context
|
||||
{
|
||||
HANDLE vcm;
|
||||
|
||||
/* Server self-defined pointer. */
|
||||
void* data;
|
||||
|
||||
/*** APIs called by the server. ***/
|
||||
/**
|
||||
* Open the ainput channel.
|
||||
*/
|
||||
psAInputServerOpen Open;
|
||||
|
||||
/**
|
||||
* Optional: Set thread handling.
|
||||
* When externalThread=TRUE the application is responsible to call
|
||||
* ainput_server_context_poll periodically to process input events.
|
||||
*
|
||||
* Defaults to externalThread=FALSE
|
||||
*/
|
||||
psAInputServerInitialize Initialize;
|
||||
|
||||
/**
|
||||
* @brief Poll When externalThread=TRUE call periodically from your main loop.
|
||||
* if externalThread=FALSE do not call.
|
||||
*/
|
||||
psAInputServerPoll Poll;
|
||||
|
||||
/**
|
||||
* @brief Poll When externalThread=TRUE call to get a handle to wait for events.
|
||||
* Will return FALSE until the handle is available.
|
||||
*/
|
||||
psAInputServerChannelHandle ChannelHandle;
|
||||
|
||||
/**
|
||||
* Close the ainput channel.
|
||||
*/
|
||||
psAInputServerClose Close;
|
||||
/**
|
||||
* Status of the ainput channel.
|
||||
*/
|
||||
psAInputServerIsOpen IsOpen;
|
||||
|
||||
/*** Callbacks registered by the server. ***/
|
||||
|
||||
/**
|
||||
* Receive ainput mouse event PDU.
|
||||
*/
|
||||
psAInputServerMouseEvent MouseEvent;
|
||||
|
||||
rdpContext* rdpcontext;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
FREERDP_API ainput_server_context* ainput_server_context_new(HANDLE vcm);
|
||||
FREERDP_API void ainput_server_context_free(ainput_server_context* context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_CHANNEL_AINPUT_SERVER_H */
|
||||
@ -220,12 +220,6 @@ if(WITH_JPEG)
|
||||
freerdp_library_add(${JPEG_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(WITH_X264)
|
||||
set(CODEC_SRCS ${CODEC_SRCS} codec/h264_x264.c)
|
||||
freerdp_include_directory_add(${X264_INCLUDE_DIR})
|
||||
freerdp_library_add(${X264_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(WITH_OPENH264)
|
||||
set(CODEC_SRCS ${CODEC_SRCS} codec/h264_openh264.c)
|
||||
freerdp_include_directory_add(${OPENH264_INCLUDE_DIR})
|
||||
@ -244,6 +238,10 @@ if(WIN32 AND WITH_MEDIA_FOUNDATION)
|
||||
set(CODEC_SRCS ${CODEC_SRCS} codec/h264_mf.c)
|
||||
endif()
|
||||
|
||||
if(ANDROID AND WITH_MEDIACODEC)
|
||||
list(APPEND CODEC_SRCS codec/h264_mediacodec.c)
|
||||
endif()
|
||||
|
||||
freerdp_module_add(${CODEC_SRCS})
|
||||
|
||||
if(BUILD_TESTING)
|
||||
|
||||
@ -571,7 +571,9 @@ BOOL freerdp_dsp_ffmpeg_supports_format(const AUDIO_FORMAT* format, BOOL encode)
|
||||
FREERDP_DSP_CONTEXT* freerdp_dsp_ffmpeg_context_new(BOOL encode)
|
||||
{
|
||||
FREERDP_DSP_CONTEXT* context;
|
||||
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100)
|
||||
avcodec_register_all();
|
||||
#endif
|
||||
context = calloc(1, sizeof(FREERDP_DSP_CONTEXT));
|
||||
|
||||
if (!context)
|
||||
@ -667,7 +669,9 @@ BOOL freerdp_dsp_ffmpeg_decode(FREERDP_DSP_CONTEXT* context, const AUDIO_FORMAT*
|
||||
if (!context || !srcFormat || !data || !out || context->encoder)
|
||||
return FALSE;
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 133, 100)
|
||||
av_init_packet(context->packet);
|
||||
#endif
|
||||
context->packet->data = (uint8_t*)data;
|
||||
context->packet->size = length;
|
||||
return ffmpeg_decode(context->context, context->packet, context->frame, context->rcontext,
|
||||
|
||||
@ -484,7 +484,7 @@ INT32 avc444_decompress(H264_CONTEXT* h264, BYTE op, RECTANGLE_16* regionRects,
|
||||
|
||||
#define MAX_SUBSYSTEMS 10
|
||||
static INIT_ONCE subsystems_once = INIT_ONCE_STATIC_INIT;
|
||||
static H264_CONTEXT_SUBSYSTEM* subSystems[MAX_SUBSYSTEMS];
|
||||
static H264_CONTEXT_SUBSYSTEM* subSystems[MAX_SUBSYSTEMS] = { 0 };
|
||||
|
||||
#if defined(_WIN32) && defined(WITH_MEDIA_FOUNDATION)
|
||||
extern H264_CONTEXT_SUBSYSTEM g_Subsystem_MF;
|
||||
@ -493,7 +493,14 @@ extern H264_CONTEXT_SUBSYSTEM g_Subsystem_MF;
|
||||
static BOOL CALLBACK h264_register_subsystems(PINIT_ONCE once, PVOID param, PVOID* context)
|
||||
{
|
||||
int i = 0;
|
||||
ZeroMemory(subSystems, sizeof(subSystems));
|
||||
|
||||
#ifdef WITH_MEDIACODEC
|
||||
{
|
||||
extern H264_CONTEXT_SUBSYSTEM g_Subsystem_mediacodec;
|
||||
subSystems[i] = &g_Subsystem_mediacodec;
|
||||
i++;
|
||||
}
|
||||
#endif
|
||||
#if defined(_WIN32) && defined(WITH_MEDIA_FOUNDATION)
|
||||
{
|
||||
subSystems[i] = &g_Subsystem_MF;
|
||||
@ -513,13 +520,6 @@ static BOOL CALLBACK h264_register_subsystems(PINIT_ONCE once, PVOID param, PVOI
|
||||
subSystems[i] = &g_Subsystem_libavcodec;
|
||||
i++;
|
||||
}
|
||||
#endif
|
||||
#ifdef WITH_X264
|
||||
{
|
||||
extern H264_CONTEXT_SUBSYSTEM g_Subsystem_x264;
|
||||
subSystems[i] = &g_Subsystem_x264;
|
||||
i++;
|
||||
}
|
||||
#endif
|
||||
return i > 0;
|
||||
}
|
||||
|
||||
649
libfreerdp/codec/h264_mediacodec.c
Normal file
649
libfreerdp/codec/h264_mediacodec.c
Normal file
@ -0,0 +1,649 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* H.264 Bitmap Compression
|
||||
*
|
||||
* Copyright 2022 Ely Ronnen <elyronnen@gmail.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.
|
||||
*/
|
||||
|
||||
#include <winpr/wlog.h>
|
||||
#include <assert.h>
|
||||
#include <winpr/library.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#include <freerdp/codec/h264.h>
|
||||
|
||||
#include <media/NdkMediaCodec.h>
|
||||
#include <media/NdkMediaFormat.h>
|
||||
|
||||
#include "h264.h"
|
||||
|
||||
#define WINPR_ASSERT(x) assert(x)
|
||||
|
||||
#define RESOLVE_MEDIANDK_FUNC(sys, name) \
|
||||
({ \
|
||||
BOOL rc = TRUE; \
|
||||
sys->fn##name = GetProcAddress(sys->mediandkLibrary, #name); \
|
||||
if (sys->fn##name == NULL) \
|
||||
{ \
|
||||
WLog_Print(h264->log, WLOG_ERROR, \
|
||||
"Error resolving function " #name " from libmediandk.so"); \
|
||||
rc = FALSE; \
|
||||
} \
|
||||
rc; \
|
||||
})
|
||||
|
||||
#define RESOLVE_MEDIANDK_VARIABLE(sys, member, exported) \
|
||||
({ \
|
||||
BOOL rc = FALSE; \
|
||||
const char** temp = GetProcAddress(sys->mediandkLibrary, exported); \
|
||||
if (temp == NULL) \
|
||||
{ \
|
||||
WLog_Print(h264->log, WLOG_ERROR, \
|
||||
"Error resolving variable " exported " from libmediandk.so"); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
sys->member = *temp; \
|
||||
rc = TRUE; \
|
||||
} \
|
||||
rc; \
|
||||
})
|
||||
|
||||
typedef AMediaFormat* (*AMediaFormat_new_t)(void);
|
||||
typedef media_status_t (*AMediaFormat_delete_t)(AMediaFormat*);
|
||||
typedef const char* (*AMediaFormat_toString_t)(AMediaFormat*);
|
||||
typedef void (*AMediaFormat_setInt32_t)(AMediaFormat*, const char*, int32_t);
|
||||
typedef void (*AMediaFormat_setString_t)(AMediaFormat*, const char*, const char*);
|
||||
typedef AMediaCodec* (*AMediaCodec_createDecoderByType_t)(const char*);
|
||||
typedef media_status_t (*AMediaCodec_delete_t)(AMediaCodec*);
|
||||
typedef media_status_t (*AMediaCodec_configure_t)(AMediaCodec*, const AMediaFormat*, ANativeWindow*,
|
||||
AMediaCrypto*, uint32_t);
|
||||
typedef media_status_t (*AMediaCodec_start_t)(AMediaCodec*);
|
||||
typedef media_status_t (*AMediaCodec_stop_t)(AMediaCodec*);
|
||||
typedef uint8_t* (*AMediaCodec_getInputBuffer_t)(AMediaCodec*, size_t, size_t*);
|
||||
typedef uint8_t* (*AMediaCodec_getOutputBuffer_t)(AMediaCodec*, size_t, size_t*);
|
||||
typedef ssize_t (*AMediaCodec_dequeueInputBuffer_t)(AMediaCodec*, int64_t);
|
||||
typedef media_status_t (*AMediaCodec_queueInputBuffer_t)(AMediaCodec*, size_t, ssize_t, size_t,
|
||||
uint64_t, uint32_t);
|
||||
typedef ssize_t (*AMediaCodec_dequeueOutputBuffer_t)(AMediaCodec*, AMediaCodecBufferInfo*, int64_t);
|
||||
typedef AMediaFormat* (*AMediaCodec_getOutputFormat_t)(AMediaCodec*);
|
||||
typedef media_status_t (*AMediaCodec_releaseOutputBuffer_t)(AMediaCodec*, size_t, bool);
|
||||
typedef media_status_t (*AMediaCodec_setParameters_t)(AMediaCodec*, const AMediaFormat*); // 26
|
||||
typedef media_status_t (*AMediaCodec_getName_t)(AMediaCodec*, char**); // 28
|
||||
typedef void (*AMediaCodec_releaseName_t)(AMediaCodec*, char*); // 28
|
||||
typedef AMediaFormat* (*AMediaCodec_getInputFormat_t)(AMediaCodec*); // 28
|
||||
|
||||
const int COLOR_FormatYUV420Planar = 19;
|
||||
const int COLOR_FormatYUV420Flexible = 0x7f420888;
|
||||
|
||||
struct _H264_CONTEXT_MEDIACODEC
|
||||
{
|
||||
AMediaCodec* decoder;
|
||||
AMediaFormat* inputFormat;
|
||||
AMediaFormat* outputFormat;
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
ssize_t currentOutputBufferIndex;
|
||||
|
||||
// libmediandk.so imports
|
||||
HMODULE mediandkLibrary;
|
||||
|
||||
AMediaFormat_new_t fnAMediaFormat_new;
|
||||
AMediaFormat_delete_t fnAMediaFormat_delete;
|
||||
AMediaFormat_toString_t fnAMediaFormat_toString;
|
||||
AMediaFormat_setInt32_t fnAMediaFormat_setInt32;
|
||||
AMediaFormat_setString_t fnAMediaFormat_setString;
|
||||
AMediaCodec_createDecoderByType_t fnAMediaCodec_createDecoderByType;
|
||||
AMediaCodec_delete_t fnAMediaCodec_delete;
|
||||
AMediaCodec_configure_t fnAMediaCodec_configure;
|
||||
AMediaCodec_start_t fnAMediaCodec_start;
|
||||
AMediaCodec_stop_t fnAMediaCodec_stop;
|
||||
AMediaCodec_getInputBuffer_t fnAMediaCodec_getInputBuffer;
|
||||
AMediaCodec_getOutputBuffer_t fnAMediaCodec_getOutputBuffer;
|
||||
AMediaCodec_dequeueInputBuffer_t fnAMediaCodec_dequeueInputBuffer;
|
||||
AMediaCodec_queueInputBuffer_t fnAMediaCodec_queueInputBuffer;
|
||||
AMediaCodec_dequeueOutputBuffer_t fnAMediaCodec_dequeueOutputBuffer;
|
||||
AMediaCodec_getOutputFormat_t fnAMediaCodec_getOutputFormat;
|
||||
AMediaCodec_releaseOutputBuffer_t fnAMediaCodec_releaseOutputBuffer;
|
||||
AMediaCodec_setParameters_t fnAMediaCodec_setParameters;
|
||||
AMediaCodec_getName_t fnAMediaCodec_getName;
|
||||
AMediaCodec_releaseName_t fnAMediaCodec_releaseName;
|
||||
AMediaCodec_getInputFormat_t fnAMediaCodec_getInputFormat;
|
||||
|
||||
const char* gAMediaFormatKeyMime;
|
||||
const char* gAMediaFormatKeyWidth;
|
||||
const char* gAMediaFormatKeyHeight;
|
||||
const char* gAMediaFormatKeyColorFormat;
|
||||
};
|
||||
|
||||
typedef struct _H264_CONTEXT_MEDIACODEC H264_CONTEXT_MEDIACODEC;
|
||||
|
||||
static int load_libmediandk(H264_CONTEXT* h264)
|
||||
{
|
||||
BOOL rc;
|
||||
H264_CONTEXT_MEDIACODEC* sys;
|
||||
|
||||
WINPR_ASSERT(h264);
|
||||
|
||||
sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData;
|
||||
WINPR_ASSERT(sys);
|
||||
|
||||
WLog_Print(h264->log, WLOG_DEBUG, "MediaCodec Loading libmediandk.so");
|
||||
|
||||
sys->mediandkLibrary = LoadLibraryA("libmediandk.so");
|
||||
if (sys->mediandkLibrary == NULL)
|
||||
{
|
||||
WLog_Print(h264->log, WLOG_WARN, "Error loading libmediandk.so");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_new);
|
||||
if (!rc)
|
||||
return -1;
|
||||
rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_delete);
|
||||
if (!rc)
|
||||
return -1;
|
||||
rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_toString);
|
||||
if (!rc)
|
||||
return -1;
|
||||
rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_setInt32);
|
||||
if (!rc)
|
||||
return -1;
|
||||
rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_setString);
|
||||
if (!rc)
|
||||
return -1;
|
||||
rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_createDecoderByType);
|
||||
if (!rc)
|
||||
return -1;
|
||||
rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_delete);
|
||||
if (!rc)
|
||||
return -1;
|
||||
rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_configure);
|
||||
if (!rc)
|
||||
return -1;
|
||||
rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_start);
|
||||
if (!rc)
|
||||
return -1;
|
||||
rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_stop);
|
||||
if (!rc)
|
||||
return -1;
|
||||
rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getInputBuffer);
|
||||
if (!rc)
|
||||
return -1;
|
||||
rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getOutputBuffer);
|
||||
if (!rc)
|
||||
return -1;
|
||||
rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_dequeueInputBuffer);
|
||||
if (!rc)
|
||||
return -1;
|
||||
rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_queueInputBuffer);
|
||||
if (!rc)
|
||||
return -1;
|
||||
rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_dequeueOutputBuffer);
|
||||
if (!rc)
|
||||
return -1;
|
||||
rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getOutputFormat);
|
||||
if (!rc)
|
||||
return -1;
|
||||
rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_releaseOutputBuffer);
|
||||
if (!rc)
|
||||
return -1;
|
||||
rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_setParameters);
|
||||
if (!rc)
|
||||
return -1;
|
||||
rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getName);
|
||||
if (!rc)
|
||||
return -1;
|
||||
rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_releaseName);
|
||||
if (!rc)
|
||||
return -1;
|
||||
rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getInputFormat);
|
||||
if (!rc)
|
||||
return -1;
|
||||
|
||||
rc = RESOLVE_MEDIANDK_VARIABLE(sys, gAMediaFormatKeyMime, "AMEDIAFORMAT_KEY_MIME");
|
||||
if (!rc)
|
||||
return -1;
|
||||
rc = RESOLVE_MEDIANDK_VARIABLE(sys, gAMediaFormatKeyWidth, "AMEDIAFORMAT_KEY_WIDTH");
|
||||
if (!rc)
|
||||
return -1;
|
||||
rc = RESOLVE_MEDIANDK_VARIABLE(sys, gAMediaFormatKeyHeight, "AMEDIAFORMAT_KEY_HEIGHT");
|
||||
if (!rc)
|
||||
return -1;
|
||||
rc = RESOLVE_MEDIANDK_VARIABLE(sys, gAMediaFormatKeyColorFormat,
|
||||
"AMEDIAFORMAT_KEY_COLOR_FORMAT");
|
||||
if (!rc)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void unload_libmediandk(H264_CONTEXT* h264)
|
||||
{
|
||||
H264_CONTEXT_MEDIACODEC* sys;
|
||||
|
||||
WINPR_ASSERT(h264);
|
||||
|
||||
sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData;
|
||||
WINPR_ASSERT(sys);
|
||||
|
||||
if (NULL == sys->mediandkLibrary)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FreeLibrary(sys->mediandkLibrary);
|
||||
}
|
||||
|
||||
static void set_mediacodec_format(H264_CONTEXT* h264, AMediaFormat** formatVariable,
|
||||
AMediaFormat* newFormat)
|
||||
{
|
||||
media_status_t status = AMEDIA_OK;
|
||||
H264_CONTEXT_MEDIACODEC* sys;
|
||||
|
||||
WINPR_ASSERT(h264);
|
||||
WINPR_ASSERT(formatVariable);
|
||||
|
||||
sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData;
|
||||
WINPR_ASSERT(sys);
|
||||
|
||||
if (*formatVariable != NULL)
|
||||
{
|
||||
status = sys->fnAMediaFormat_delete(*formatVariable);
|
||||
if (status != AMEDIA_OK)
|
||||
{
|
||||
WLog_Print(h264->log, WLOG_ERROR, "Error AMediaFormat_delete %d", status);
|
||||
}
|
||||
}
|
||||
|
||||
*formatVariable = newFormat;
|
||||
}
|
||||
|
||||
static void release_current_outputbuffer(H264_CONTEXT* h264)
|
||||
{
|
||||
media_status_t status = AMEDIA_OK;
|
||||
H264_CONTEXT_MEDIACODEC* sys;
|
||||
|
||||
WINPR_ASSERT(h264);
|
||||
sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData;
|
||||
WINPR_ASSERT(sys);
|
||||
|
||||
if (sys->currentOutputBufferIndex < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
status =
|
||||
sys->fnAMediaCodec_releaseOutputBuffer(sys->decoder, sys->currentOutputBufferIndex, FALSE);
|
||||
if (status != AMEDIA_OK)
|
||||
{
|
||||
WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_releaseOutputBuffer %d", status);
|
||||
}
|
||||
|
||||
sys->currentOutputBufferIndex = -1;
|
||||
}
|
||||
|
||||
static int mediacodec_compress(H264_CONTEXT* h264, const BYTE** pSrcYuv, const UINT32* pStride,
|
||||
BYTE** ppDstData, UINT32* pDstSize)
|
||||
{
|
||||
WINPR_ASSERT(h264);
|
||||
WINPR_ASSERT(pSrcYuv);
|
||||
WINPR_ASSERT(pStride);
|
||||
WINPR_ASSERT(ppDstData);
|
||||
WINPR_ASSERT(pDstSize);
|
||||
|
||||
WLog_Print(h264->log, WLOG_ERROR, "MediaCodec is not supported as an encoder");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int mediacodec_decompress(H264_CONTEXT* h264, const BYTE* pSrcData, UINT32 SrcSize)
|
||||
{
|
||||
ssize_t inputBufferId = -1;
|
||||
size_t inputBufferSize, outputBufferSize;
|
||||
uint8_t* inputBuffer;
|
||||
media_status_t status;
|
||||
const char* media_format;
|
||||
BYTE** pYUVData;
|
||||
UINT32* iStride;
|
||||
H264_CONTEXT_MEDIACODEC* sys;
|
||||
|
||||
WINPR_ASSERT(h264);
|
||||
WINPR_ASSERT(pSrcData);
|
||||
|
||||
sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData;
|
||||
WINPR_ASSERT(sys);
|
||||
|
||||
pYUVData = h264->pYUVData;
|
||||
WINPR_ASSERT(pYUVData);
|
||||
|
||||
iStride = h264->iStride;
|
||||
WINPR_ASSERT(iStride);
|
||||
|
||||
release_current_outputbuffer(h264);
|
||||
|
||||
if (sys->width == 0)
|
||||
{
|
||||
int32_t width = h264->width;
|
||||
int32_t height = h264->height;
|
||||
if (width % 16 != 0)
|
||||
width += 16 - width % 16;
|
||||
if (height % 16 != 0)
|
||||
height += 16 - height % 16;
|
||||
|
||||
WLog_Print(h264->log, WLOG_DEBUG, "MediaCodec setting width and height [%d,%d]", width,
|
||||
height);
|
||||
sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyWidth, width);
|
||||
sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyHeight, height);
|
||||
|
||||
status = sys->fnAMediaCodec_setParameters(sys->decoder, sys->inputFormat);
|
||||
if (status != AMEDIA_OK)
|
||||
{
|
||||
WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_setParameters failed: %d", status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sys->width = width;
|
||||
sys->height = height;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
UINT32 inputBufferCurrnetOffset = 0;
|
||||
while (inputBufferCurrnetOffset < SrcSize)
|
||||
{
|
||||
UINT32 numberOfBytesToCopy = SrcSize - inputBufferCurrnetOffset;
|
||||
inputBufferId = sys->fnAMediaCodec_dequeueInputBuffer(sys->decoder, -1);
|
||||
if (inputBufferId < 0)
|
||||
{
|
||||
WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_dequeueInputBuffer failed [%d]",
|
||||
inputBufferId);
|
||||
// TODO: sleep?
|
||||
continue;
|
||||
}
|
||||
|
||||
inputBuffer =
|
||||
sys->fnAMediaCodec_getInputBuffer(sys->decoder, inputBufferId, &inputBufferSize);
|
||||
if (inputBuffer == NULL)
|
||||
{
|
||||
WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getInputBuffer failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (numberOfBytesToCopy > inputBufferSize)
|
||||
{
|
||||
WLog_Print(h264->log, WLOG_WARN,
|
||||
"MediaCodec inputBufferSize: got [%d] but wanted [%d]", inputBufferSize,
|
||||
numberOfBytesToCopy);
|
||||
numberOfBytesToCopy = inputBufferSize;
|
||||
}
|
||||
|
||||
memcpy(inputBuffer, pSrcData + inputBufferCurrnetOffset, numberOfBytesToCopy);
|
||||
inputBufferCurrnetOffset += numberOfBytesToCopy;
|
||||
|
||||
status = sys->fnAMediaCodec_queueInputBuffer(sys->decoder, inputBufferId, 0,
|
||||
numberOfBytesToCopy, 0, 0);
|
||||
if (status != AMEDIA_OK)
|
||||
{
|
||||
WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_queueInputBuffer %d", status);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
AMediaCodecBufferInfo bufferInfo;
|
||||
ssize_t outputBufferId =
|
||||
sys->fnAMediaCodec_dequeueOutputBuffer(sys->decoder, &bufferInfo, -1);
|
||||
if (outputBufferId >= 0)
|
||||
{
|
||||
sys->currentOutputBufferIndex = outputBufferId;
|
||||
|
||||
uint8_t* outputBuffer;
|
||||
outputBuffer = sys->fnAMediaCodec_getOutputBuffer(sys->decoder, outputBufferId,
|
||||
&outputBufferSize);
|
||||
sys->currentOutputBufferIndex = outputBufferId;
|
||||
|
||||
if (outputBufferSize != (sys->width * sys->height +
|
||||
((sys->width + 1) / 2) * ((sys->height + 1) / 2) * 2))
|
||||
{
|
||||
WLog_Print(h264->log, WLOG_ERROR, "Error unexpected output buffer size %d",
|
||||
outputBufferSize);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO: work with AImageReader and get AImage object instead of
|
||||
// COLOR_FormatYUV420Planar buffer.
|
||||
iStride[0] = sys->width;
|
||||
iStride[1] = (sys->width + 1) / 2;
|
||||
iStride[2] = (sys->width + 1) / 2;
|
||||
pYUVData[0] = outputBuffer;
|
||||
pYUVData[1] = outputBuffer + iStride[0] * sys->height;
|
||||
pYUVData[2] =
|
||||
outputBuffer + iStride[0] * sys->height + iStride[1] * ((sys->height + 1) / 2);
|
||||
break;
|
||||
}
|
||||
else if (outputBufferId == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED)
|
||||
{
|
||||
AMediaFormat* outputFormat;
|
||||
outputFormat = sys->fnAMediaCodec_getOutputFormat(sys->decoder);
|
||||
if (outputFormat == NULL)
|
||||
{
|
||||
WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getOutputFormat failed");
|
||||
return -1;
|
||||
}
|
||||
set_mediacodec_format(h264, &sys->outputFormat, outputFormat);
|
||||
|
||||
media_format = sys->fnAMediaFormat_toString(sys->outputFormat);
|
||||
if (media_format == NULL)
|
||||
{
|
||||
WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (outputBufferId == AMEDIACODEC_INFO_TRY_AGAIN_LATER)
|
||||
{
|
||||
WLog_Print(h264->log, WLOG_WARN,
|
||||
"AMediaCodec_dequeueOutputBuffer need to try again later");
|
||||
// TODO: sleep?
|
||||
}
|
||||
else if (outputBufferId == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED)
|
||||
{
|
||||
WLog_Print(h264->log, WLOG_WARN,
|
||||
"AMediaCodec_dequeueOutputBuffer returned deprecated value "
|
||||
"AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED, ignoring");
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_Print(h264->log, WLOG_ERROR,
|
||||
"AMediaCodec_dequeueOutputBuffer returned unknown value [%d]",
|
||||
outputBufferId);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void mediacodec_uninit(H264_CONTEXT* h264)
|
||||
{
|
||||
media_status_t status = AMEDIA_OK;
|
||||
H264_CONTEXT_MEDIACODEC* sys;
|
||||
|
||||
WINPR_ASSERT(h264);
|
||||
|
||||
sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData;
|
||||
|
||||
WLog_Print(h264->log, WLOG_DEBUG, "Uninitializing MediaCodec");
|
||||
|
||||
if (!sys)
|
||||
return;
|
||||
|
||||
if (sys->decoder != NULL)
|
||||
{
|
||||
release_current_outputbuffer(h264);
|
||||
status = sys->fnAMediaCodec_stop(sys->decoder);
|
||||
if (status != AMEDIA_OK)
|
||||
{
|
||||
WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_stop %d", status);
|
||||
}
|
||||
|
||||
status = sys->fnAMediaCodec_delete(sys->decoder);
|
||||
if (status != AMEDIA_OK)
|
||||
{
|
||||
WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_delete %d", status);
|
||||
}
|
||||
|
||||
sys->decoder = NULL;
|
||||
}
|
||||
|
||||
set_mediacodec_format(h264, &sys->inputFormat, NULL);
|
||||
set_mediacodec_format(h264, &sys->outputFormat, NULL);
|
||||
|
||||
unload_libmediandk(h264);
|
||||
|
||||
free(sys);
|
||||
h264->pSystemData = NULL;
|
||||
}
|
||||
|
||||
static BOOL mediacodec_init(H264_CONTEXT* h264)
|
||||
{
|
||||
H264_CONTEXT_MEDIACODEC* sys;
|
||||
media_status_t status;
|
||||
const char* media_format;
|
||||
char* codec_name;
|
||||
AMediaFormat *inputFormat, *outputFormat;
|
||||
|
||||
WINPR_ASSERT(h264);
|
||||
|
||||
if (h264->Compressor)
|
||||
{
|
||||
WLog_Print(h264->log, WLOG_ERROR, "MediaCodec is not supported as an encoder");
|
||||
goto EXCEPTION;
|
||||
}
|
||||
|
||||
WLog_Print(h264->log, WLOG_DEBUG, "Initializing MediaCodec");
|
||||
|
||||
sys = (H264_CONTEXT_MEDIACODEC*)calloc(1, sizeof(H264_CONTEXT_MEDIACODEC));
|
||||
|
||||
if (!sys)
|
||||
{
|
||||
goto EXCEPTION;
|
||||
}
|
||||
|
||||
h264->pSystemData = (void*)sys;
|
||||
|
||||
if (load_libmediandk(h264) < 0)
|
||||
{
|
||||
goto EXCEPTION;
|
||||
}
|
||||
|
||||
sys->currentOutputBufferIndex = -1;
|
||||
sys->width = sys->height = 0; // update when we're given the height and width
|
||||
sys->decoder = sys->fnAMediaCodec_createDecoderByType("video/avc");
|
||||
if (sys->decoder == NULL)
|
||||
{
|
||||
WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_createCodecByName failed");
|
||||
goto EXCEPTION;
|
||||
}
|
||||
|
||||
status = sys->fnAMediaCodec_getName(sys->decoder, &codec_name);
|
||||
if (status != AMEDIA_OK)
|
||||
{
|
||||
WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getName failed: %d", status);
|
||||
goto EXCEPTION;
|
||||
}
|
||||
|
||||
WLog_Print(h264->log, WLOG_DEBUG, "MediaCodec using video/avc codec [%s]", codec_name);
|
||||
sys->fnAMediaCodec_releaseName(sys->decoder, codec_name);
|
||||
|
||||
sys->inputFormat = sys->fnAMediaFormat_new();
|
||||
if (sys->inputFormat == NULL)
|
||||
{
|
||||
WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_new failed");
|
||||
goto EXCEPTION;
|
||||
}
|
||||
|
||||
sys->fnAMediaFormat_setString(sys->inputFormat, sys->gAMediaFormatKeyMime, "video/avc");
|
||||
sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyWidth, sys->width);
|
||||
sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyHeight, sys->height);
|
||||
sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyColorFormat,
|
||||
COLOR_FormatYUV420Planar);
|
||||
|
||||
media_format = sys->fnAMediaFormat_toString(sys->inputFormat);
|
||||
if (media_format == NULL)
|
||||
{
|
||||
WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed");
|
||||
goto EXCEPTION;
|
||||
}
|
||||
|
||||
status = sys->fnAMediaCodec_configure(sys->decoder, sys->inputFormat, NULL, NULL, 0);
|
||||
if (status != AMEDIA_OK)
|
||||
{
|
||||
WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_configure failed: %d", status);
|
||||
goto EXCEPTION;
|
||||
}
|
||||
|
||||
inputFormat = sys->fnAMediaCodec_getInputFormat(sys->decoder);
|
||||
if (inputFormat == NULL)
|
||||
{
|
||||
WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getInputFormat failed");
|
||||
goto EXCEPTION;
|
||||
}
|
||||
set_mediacodec_format(h264, &sys->inputFormat, inputFormat);
|
||||
|
||||
media_format = sys->fnAMediaFormat_toString(sys->inputFormat);
|
||||
if (media_format == NULL)
|
||||
{
|
||||
WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed");
|
||||
goto EXCEPTION;
|
||||
}
|
||||
WLog_Print(h264->log, WLOG_DEBUG, "Using MediaCodec with input MediaFormat [%s]", media_format);
|
||||
|
||||
outputFormat = sys->fnAMediaCodec_getOutputFormat(sys->decoder);
|
||||
if (outputFormat == NULL)
|
||||
{
|
||||
WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getOutputFormat failed");
|
||||
goto EXCEPTION;
|
||||
}
|
||||
set_mediacodec_format(h264, &sys->outputFormat, outputFormat);
|
||||
|
||||
media_format = sys->fnAMediaFormat_toString(sys->outputFormat);
|
||||
if (media_format == NULL)
|
||||
{
|
||||
WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed");
|
||||
goto EXCEPTION;
|
||||
}
|
||||
WLog_Print(h264->log, WLOG_DEBUG, "Using MediaCodec with output MediaFormat [%s]",
|
||||
media_format);
|
||||
|
||||
WLog_Print(h264->log, WLOG_DEBUG, "Starting MediaCodec");
|
||||
status = sys->fnAMediaCodec_start(sys->decoder);
|
||||
if (status != AMEDIA_OK)
|
||||
{
|
||||
WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_start failed %d", status);
|
||||
goto EXCEPTION;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
EXCEPTION:
|
||||
mediacodec_uninit(h264);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
H264_CONTEXT_SUBSYSTEM g_Subsystem_mediacodec = { "MediaCodec", mediacodec_init, mediacodec_uninit,
|
||||
mediacodec_decompress, mediacodec_compress };
|
||||
@ -1,117 +0,0 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* H.264 Bitmap Compression
|
||||
*
|
||||
* Copyright 2015 Marc-André Moreau <marcandre.moreau@gmail.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.
|
||||
*/
|
||||
|
||||
#define NAL_UNKNOWN X264_NAL_UNKNOWN
|
||||
#define NAL_SLICE X264_NAL_SLICE
|
||||
#define NAL_SLICE_DPA X264_NAL_SLICE_DPA
|
||||
#define NAL_SLICE_DPB X264_NAL_SLICE_DPB
|
||||
#define NAL_SLICE_DPC X264_NAL_SLICE_DPC
|
||||
#define NAL_SLICE_IDR X264_NAL_SLICE_IDR
|
||||
#define NAL_SEI X264_NAL_SEI
|
||||
#define NAL_SPS X264_NAL_SPS
|
||||
#define NAL_PPS X264_NAL_PPS
|
||||
#define NAL_AUD X264_NAL_AUD
|
||||
#define NAL_FILLER X264_NAL_FILLER
|
||||
|
||||
#define NAL_PRIORITY_DISPOSABLE X264_NAL_PRIORITY_DISPOSABLE
|
||||
#define NAL_PRIORITY_LOW X264_NAL_PRIORITY_LOW
|
||||
#define NAL_PRIORITY_HIGH X264_NAL_PRIORITY_HIGH
|
||||
#define NAL_PRIORITY_HIGHEST X264_NAL_PRIORITY_HIGHEST
|
||||
|
||||
#include <stdint.h>
|
||||
#include <x264.h>
|
||||
#include <freerdp/codec/h264.h>
|
||||
|
||||
#error "X264 backend not implemented, please review your configuration!"
|
||||
|
||||
struct _H264_CONTEXT_X264
|
||||
{
|
||||
void* dummy;
|
||||
};
|
||||
typedef struct _H264_CONTEXT_X264 H264_CONTEXT_X264;
|
||||
|
||||
static int x264_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize)
|
||||
{
|
||||
// H264_CONTEXT_X264* sys = (H264_CONTEXT_X264*) h264->pSystemData;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int x264_compress(H264_CONTEXT* h264, const BYTE** ppSrcYuv, const UINT32* pStride,
|
||||
BYTE** ppDstData, UINT32* pDstSize)
|
||||
{
|
||||
// H264_CONTEXT_X264* sys = (H264_CONTEXT_X264*) h264->pSystemData;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void x264_uninit(H264_CONTEXT* h264)
|
||||
{
|
||||
H264_CONTEXT_X264* sys = (H264_CONTEXT_X264*)h264->pSystemData;
|
||||
|
||||
if (sys)
|
||||
{
|
||||
free(sys);
|
||||
h264->pSystemData = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL x264_init(H264_CONTEXT* h264)
|
||||
{
|
||||
H264_CONTEXT_X264* sys;
|
||||
h264->numSystemData = 1;
|
||||
sys = (H264_CONTEXT_X264*)calloc(h264->numSystemData, sizeof(H264_CONTEXT_X264));
|
||||
|
||||
if (!sys)
|
||||
{
|
||||
goto EXCEPTION;
|
||||
}
|
||||
|
||||
h264->pSystemData = (void*)sys;
|
||||
|
||||
if (h264->Compressor)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
EXCEPTION:
|
||||
x264_uninit(h264);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
H264_CONTEXT_SUBSYSTEM g_Subsystem_x264 = { "x264", x264_init, x264_uninit, x264_decompress,
|
||||
x264_compress };
|
||||
|
||||
#undef NAL_UNKNOWN
|
||||
#undef NAL_SLICE
|
||||
#undef NAL_SLICE_DPA
|
||||
#undef NAL_SLICE_DPB
|
||||
#undef NAL_SLICE_DPC
|
||||
#undef NAL_SLICE_IDR
|
||||
#undef NAL_SEI
|
||||
#undef NAL_SPS
|
||||
#undef NAL_PPS
|
||||
#undef NAL_AUD
|
||||
#undef NAL_FILLER
|
||||
|
||||
#undef NAL_PRIORITY_DISPOSABLE
|
||||
#undef NAL_PRIORITY_LOW
|
||||
#undef NAL_PRIORITY_HIGH
|
||||
#undef NAL_PRIORITY_HIGHEST
|
||||
@ -23,6 +23,7 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/print.h>
|
||||
#include <winpr/bitstream.h>
|
||||
@ -40,6 +41,8 @@
|
||||
#include "rfx_types.h"
|
||||
#include "progressive.h"
|
||||
|
||||
#define WINPR_ASSERT(x) assert(x)
|
||||
|
||||
#define TAG FREERDP_TAG("codec.progressive")
|
||||
|
||||
struct _RFX_PROGRESSIVE_UPGRADE_STATE
|
||||
@ -434,6 +437,36 @@ static INLINE BOOL progressive_tile_allocate(RFX_PROGRESSIVE_TILE* tile)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL progressive_allocate_tile_cache(PROGRESSIVE_SURFACE_CONTEXT* surface)
|
||||
{
|
||||
size_t oldIndex;
|
||||
|
||||
WINPR_ASSERT(surface);
|
||||
WINPR_ASSERT(surface->gridSize > 0);
|
||||
|
||||
oldIndex = surface->gridSize;
|
||||
if (surface->tiles)
|
||||
surface->gridSize *= 2;
|
||||
|
||||
{
|
||||
void* tmp = realloc(surface->tiles, surface->gridSize * sizeof(RFX_PROGRESSIVE_TILE));
|
||||
if (!tmp)
|
||||
return FALSE;
|
||||
surface->tiles = tmp;
|
||||
memset(&surface->tiles[oldIndex], 0,
|
||||
(surface->gridSize - oldIndex) * sizeof(RFX_PROGRESSIVE_TILE));
|
||||
}
|
||||
{
|
||||
void* tmp = realloc(surface->updatedTileIndices, surface->gridSize * sizeof(UINT32));
|
||||
if (!tmp)
|
||||
return FALSE;
|
||||
surface->updatedTileIndices = tmp;
|
||||
memset(&surface->updatedTileIndices[oldIndex], 0,
|
||||
(surface->gridSize - oldIndex) * sizeof(UINT32));
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static PROGRESSIVE_SURFACE_CONTEXT* progressive_surface_context_new(UINT16 surfaceId, UINT32 width,
|
||||
UINT32 height)
|
||||
{
|
||||
@ -450,14 +483,10 @@ static PROGRESSIVE_SURFACE_CONTEXT* progressive_surface_context_new(UINT16 surfa
|
||||
surface->gridWidth = (width + (64 - width % 64)) / 64;
|
||||
surface->gridHeight = (height + (64 - height % 64)) / 64;
|
||||
surface->gridSize = surface->gridWidth * surface->gridHeight;
|
||||
surface->tiles = (RFX_PROGRESSIVE_TILE*)calloc(surface->gridSize, sizeof(RFX_PROGRESSIVE_TILE));
|
||||
surface->updatedTileIndices = (UINT32*)calloc(surface->gridSize, sizeof(UINT32));
|
||||
|
||||
if (!surface->tiles || !surface->updatedTileIndices)
|
||||
if (!progressive_allocate_tile_cache(surface))
|
||||
{
|
||||
free(surface->updatedTileIndices);
|
||||
free(surface->tiles);
|
||||
free(surface);
|
||||
progressive_surface_context_free(surface);
|
||||
return NULL;
|
||||
}
|
||||
for (x = 0; x < surface->gridSize; x++)
|
||||
@ -549,8 +578,8 @@ static BOOL progressive_surface_tile_replace(PROGRESSIVE_SURFACE_CONTEXT* surfac
|
||||
}
|
||||
if (surface->numUpdatedTiles >= surface->gridSize)
|
||||
{
|
||||
WLog_ERR(TAG, "Invalid total tile count, maximum %" PRIu32, surface->gridSize);
|
||||
return FALSE;
|
||||
if (!progressive_allocate_tile_cache(surface))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
region->tiles[region->usedTiles++] = t;
|
||||
|
||||
@ -181,7 +181,8 @@ BOOL freerdp_connect(freerdp* instance)
|
||||
if (status)
|
||||
status2 = freerdp_channels_pre_connect(instance->context->channels, instance);
|
||||
|
||||
if (settings->KeyboardLayout == KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002)
|
||||
if (settings->KeyboardLayout == KBD_JAPANESE ||
|
||||
settings->KeyboardLayout == KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002)
|
||||
{
|
||||
settings->KeyboardType = 7;
|
||||
settings->KeyboardSubType = 2;
|
||||
|
||||
@ -1,29 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Android build confguration
|
||||
#
|
||||
# Note: This is a simple configuration to build all
|
||||
# architectures in one rush.
|
||||
# Since android 64 bit support was introduced with NDK API 21
|
||||
# this is the minimal common denominator.
|
||||
# If you require support for older NDK API levels,
|
||||
# create seperate configurations for each NDK API level
|
||||
# and architecture you want to support.
|
||||
WITH_JPEG=0
|
||||
WITH_OPENH264=1
|
||||
WITH_OPENSSL=1
|
||||
BUILD_DEPS=1
|
||||
DEPS_ONLY=0
|
||||
NDK_TARGET=21
|
||||
|
||||
JPEG_TAG=master
|
||||
OPENH264_TAG=v1.8.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0
|
||||
OPENSSL_TAG=OpenSSL_1_1_1j
|
||||
|
||||
SRC_DIR=$SCRIPT_PATH/..
|
||||
BUILD_DST=$SCRIPT_PATH/../client/Android/Studio/freeRDPCore/src/main/jniLibs
|
||||
BUILD_SRC=$SRC_DIR/build
|
||||
|
||||
CMAKE_BUILD_TYPE=Release
|
||||
|
||||
BUILD_ARCH="armeabi-v7a x86"
|
||||
@ -1,29 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Android build confguration
|
||||
#
|
||||
# Note: This is a simple configuration to build all
|
||||
# architectures in one rush.
|
||||
# Since android 64 bit support was introduced with NDK API 21
|
||||
# this is the minimal common denominator.
|
||||
# If you require support for older NDK API levels,
|
||||
# create seperate configurations for each NDK API level
|
||||
# and architecture you want to support.
|
||||
WITH_JPEG=0
|
||||
WITH_OPENH264=1
|
||||
WITH_OPENSSL=1
|
||||
BUILD_DEPS=1
|
||||
DEPS_ONLY=0
|
||||
NDK_TARGET=21
|
||||
|
||||
JPEG_TAG=master
|
||||
OPENH264_TAG=v1.8.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0
|
||||
OPENSSL_TAG=OpenSSL_1_1_1j
|
||||
|
||||
SRC_DIR=$SCRIPT_PATH/..
|
||||
BUILD_DST=$SCRIPT_PATH/../client/Android/Studio/freeRDPCore/src/main/jniLibs
|
||||
BUILD_SRC=$SRC_DIR/build
|
||||
|
||||
CMAKE_BUILD_TYPE=Release
|
||||
|
||||
BUILD_ARCH="arm64-v8a x86_64"
|
||||
@ -1,292 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
SCRIPT_PATH=$(dirname "${BASH_SOURCE[0]}")
|
||||
SCRIPT_PATH=$(realpath "$SCRIPT_PATH")
|
||||
|
||||
if [ -z $BUILD_ARCH ]; then
|
||||
BUILD_ARCH="armeabi-v7a x86 x86_64 arm64-v8a"
|
||||
fi
|
||||
|
||||
if [ -z $NDK_TARGET ]; then
|
||||
NDK_TARGET=21
|
||||
fi
|
||||
|
||||
if [ -z $CMAKE_PROGRAM ]; then
|
||||
CMAKE_PROGRAM=$(find $ANDROID_SDK/cmake -name cmake -type f -executable -print -quit)
|
||||
fi
|
||||
|
||||
if [ -z $CCACHE ]; then
|
||||
CCACHE=$(which ccache)
|
||||
fi
|
||||
|
||||
if [ -z $ANDROID_NDK ]; then
|
||||
ANDROID_NDK="missing"
|
||||
fi
|
||||
|
||||
if [ -z $ANDROID_SDK ]; then
|
||||
ANDROID_SDK="missing"
|
||||
fi
|
||||
|
||||
if [ -z $BUILD_DST ]; then
|
||||
BUILD_DST=$(pwd)/libs
|
||||
fi
|
||||
|
||||
if [ -z $BUILD_SRC ]; then
|
||||
BUILD_SRC=$(pwd)/src
|
||||
fi
|
||||
|
||||
if [ -z $SCM_URL ]; then
|
||||
SCM_URL="missing"
|
||||
fi
|
||||
|
||||
if [ -z $SCM_TAG ]; then
|
||||
SCM_TAG=master
|
||||
fi
|
||||
|
||||
CLEAN_BUILD_DIR=0
|
||||
|
||||
function common_help {
|
||||
echo "$(BASHSOURCE[0]) supports the following arguments:"
|
||||
echo " --ndk The base directory of your android NDK defa"
|
||||
echo " ANDROID_NDK=$ANDROID_NDK"
|
||||
echo " --sdk The base directory of your android SDK defa"
|
||||
echo " ANDROID_SDK=$ANDROID_SDK"
|
||||
echo " --arch A list of architectures to build"
|
||||
echo " BUILD_ARCH=$BUILD_ARCH"
|
||||
echo " --dst The destination directory for include and library files"
|
||||
echo " BUILD_DST=$BUILD_DST"
|
||||
echo " --src The source directory for SCM checkout"
|
||||
echo " BUILD_SRC=$BUILD_SRC"
|
||||
echo " --url The SCM source url"
|
||||
echo " SCM_URL=$SCM_URL"
|
||||
echo " --tag The SCM branch or tag to check out"
|
||||
echo " SCM_TAG=$SCM_TAG"
|
||||
echo " --clean Clean the destination before build"
|
||||
echo " --help Display this help"
|
||||
exit 0
|
||||
}
|
||||
|
||||
function common_run {
|
||||
echo "[RUN] $@"
|
||||
"$@"
|
||||
RES=$?
|
||||
if [[ $RES -ne 0 ]];
|
||||
then
|
||||
echo "[ERROR] $@ retured $RES"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function common_parse_arguments {
|
||||
while [[ $# > 0 ]]
|
||||
do
|
||||
key="$1"
|
||||
case $key in
|
||||
--conf)
|
||||
source "$2"
|
||||
shift
|
||||
;;
|
||||
|
||||
--target)
|
||||
NDK_TARGET="$2"
|
||||
shift
|
||||
;;
|
||||
|
||||
--ndk)
|
||||
ANDROID_NDK="$2"
|
||||
shift
|
||||
;;
|
||||
|
||||
--sdk)
|
||||
ANDROID_SDK="$2"
|
||||
CMAKE_PROGRAM=$(find $ANDROID_SDK/cmake -name cmake -type f -executable -print -quit)
|
||||
shift
|
||||
;;
|
||||
|
||||
--arch)
|
||||
BUILD_ARCH="$2"
|
||||
shift
|
||||
;;
|
||||
|
||||
--dst)
|
||||
BUILD_DST="$2"
|
||||
shift
|
||||
;;
|
||||
|
||||
--src)
|
||||
BUILD_SRC="$2"
|
||||
shift
|
||||
;;
|
||||
|
||||
--url)
|
||||
SCM_URL="$2"
|
||||
shift
|
||||
;;
|
||||
|
||||
--tag)
|
||||
SCM_TAG="$2"
|
||||
shift
|
||||
;;
|
||||
|
||||
--clean)
|
||||
CLEAN_BUILD_DIR=1
|
||||
shift
|
||||
;;
|
||||
|
||||
--help)
|
||||
common_help
|
||||
shift
|
||||
;;
|
||||
|
||||
*) # Unknown
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
}
|
||||
|
||||
function common_check_requirements {
|
||||
if [[ ! -d $ANDROID_NDK ]];
|
||||
then
|
||||
echo "export ANDROID_NDK to point to your NDK location."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -d $ANDROID_SDK ]];
|
||||
then
|
||||
echo "export ANDROID_SDK to point to your SDK location."
|
||||
exit 1
|
||||
fi
|
||||
if [[ -z $BUILD_DST ]];
|
||||
then
|
||||
echo "Destination directory not valid"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z $BUILD_SRC ]];
|
||||
then
|
||||
echo "Source directory not valid"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z $SCM_URL ]];
|
||||
then
|
||||
echo "Source URL not defined! Define SCM_URL"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z $SCM_TAG ]];
|
||||
then
|
||||
echo "SCM TAG / BRANCH not defined! Define SCM_TAG"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z $NDK_TARGET ]];
|
||||
then
|
||||
echo "Android platform NDK_TARGET not defined"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -x $ANDROID_NDK/ndk-build ]; then
|
||||
NDK_BUILD=$ANDROID_NDK/ndk-build
|
||||
else
|
||||
echo "ndk-build not found in NDK directory $ANDROID_NDK"
|
||||
echo "assuming ndk-build is in path..."
|
||||
NDK_BUILD=ndk-build
|
||||
fi
|
||||
|
||||
if [ -z $CMAKE_PROGRAM ]; then
|
||||
CMAKE_PROGRAM=$(find $ANDROID_SDK/cmake -name cmake -type f -executable -print -quit)
|
||||
fi
|
||||
|
||||
for CMD in make git $CMAKE_PROGRAM $NDK_BUILD
|
||||
do
|
||||
if ! type $CMD >/dev/null; then
|
||||
echo "Command $CMD not found. Install and add it to the PATH."
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "${BUILD_SRC:0:1}" != "/" ];
|
||||
then
|
||||
BUILD_SRC=$(pwd)/$BUILD_SRC
|
||||
fi
|
||||
if [ "${BUILD_DST:0:1}" != "/" ];
|
||||
then
|
||||
BUILD_DST=$(pwd)/$BUILD_DST
|
||||
fi
|
||||
}
|
||||
|
||||
function common_update {
|
||||
if [ $# -ne 3 ];
|
||||
then
|
||||
echo "Invalid arguments to update function $@"
|
||||
exit 1
|
||||
fi
|
||||
SCM_URL=$1
|
||||
SCM_TAG=$2
|
||||
BUILD_SRC=$3
|
||||
|
||||
echo "Preparing checkout..."
|
||||
BASE=$(pwd)
|
||||
CACHE=$SCRIPT_PATH/../cache
|
||||
common_run mkdir -p $CACHE
|
||||
TARFILE="$CACHE/$SCM_TAG.tar.gz"
|
||||
|
||||
|
||||
if [[ ! -f "$TARFILE" ]];
|
||||
then
|
||||
common_run wget -O "$TARFILE" "$SCM_URL/archive/$SCM_TAG.tar.gz"
|
||||
fi
|
||||
|
||||
if [[ -d $BUILD_SRC ]];
|
||||
then
|
||||
common_run rm -rf $BUILD_SRC
|
||||
fi
|
||||
common_run mkdir -p $BUILD_SRC
|
||||
common_run cd $BUILD_SRC
|
||||
common_run tar zxf "$TARFILE" --strip 1
|
||||
common_run cd $BASE
|
||||
|
||||
}
|
||||
|
||||
function common_clean {
|
||||
if [ $CLEAN_BUILD_DIR -ne 1 ];
|
||||
then
|
||||
return
|
||||
fi
|
||||
|
||||
if [ $# -ne 1 ];
|
||||
then
|
||||
echo "Invalid arguments to clean function $@"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Cleaning up $1..."
|
||||
common_run rm -rf $1
|
||||
}
|
||||
|
||||
function common_copy {
|
||||
if [ $# -ne 2 ];
|
||||
then
|
||||
echo "Invalid arguments to copy function $@"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -d $1 ] || [ ! -d $1/include ] || [ ! -d $1/libs ];
|
||||
then
|
||||
echo "Invalid source $1"
|
||||
exit 1
|
||||
fi
|
||||
if [ -z $2 ];
|
||||
then
|
||||
echo "Invalid destination $2"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -d $2 ];
|
||||
then
|
||||
common_run mkdir -p $2
|
||||
fi
|
||||
common_run cp -L -r $1/include $2
|
||||
common_run cp -L -r $1/libs/* $2
|
||||
}
|
||||
@ -1,168 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
JPEG_TAG=master
|
||||
OPENH264_TAG=master
|
||||
OPENSSL_TAG=master
|
||||
|
||||
WITH_JPEG=0
|
||||
WITH_OPENH264=0
|
||||
WITH_OPENSSL=0
|
||||
|
||||
SRC_DIR=$(dirname "${BASH_SOURCE[0]}")
|
||||
SRC_DIR=$(realpath "$SRC_DIR")
|
||||
BUILD_SRC=$(pwd)
|
||||
BUILD_DST=$(pwd)
|
||||
|
||||
CMAKE_BUILD_TYPE=Debug
|
||||
BUILD_DEPS=0
|
||||
|
||||
SCRIPT_PATH=$(dirname "${BASH_SOURCE[0]}")
|
||||
source $SCRIPT_PATH/android-build-common.sh
|
||||
source $SCRIPT_PATH/android-build.conf
|
||||
|
||||
# Parse arguments.
|
||||
REMAINING=""
|
||||
while [[ $# > 0 ]]
|
||||
do
|
||||
key="$1"
|
||||
case $key in
|
||||
--freerdp-src)
|
||||
SRC_DIR="$2"
|
||||
shift
|
||||
;;
|
||||
--jpeg)
|
||||
WITH_JPEG=1
|
||||
shift
|
||||
;;
|
||||
--openh264)
|
||||
WITH_OPENH264=1
|
||||
shift
|
||||
;;
|
||||
--openh264-ndk)
|
||||
shift
|
||||
ANDROID_NDK_OPENH264=$1
|
||||
shift
|
||||
;;
|
||||
--openssl)
|
||||
WITH_OPENSSL=1
|
||||
shift
|
||||
;;
|
||||
--debug)
|
||||
CMAKE_BUILD_TYPE=Debug
|
||||
shift
|
||||
;;
|
||||
--release)
|
||||
CMAKE_BUILD_TYPE=Release
|
||||
shift
|
||||
;;
|
||||
--relWithDebug)
|
||||
CMAKE_BUILD_TYPE=RelWithDebug
|
||||
shift
|
||||
;;
|
||||
--build-deps)
|
||||
BUILD_DEPS=1
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
REMAINING="$REMAINING $key"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
common_parse_arguments $REMAINING
|
||||
|
||||
# clean up top
|
||||
if [ -d $BUILD_SRC ];
|
||||
then
|
||||
common_clean $BUILD_SRC
|
||||
fi
|
||||
|
||||
if [ -d $BUILD_DST ];
|
||||
then
|
||||
common_run mkdir -p $BUILD_DST
|
||||
fi
|
||||
|
||||
# Prepare the environment
|
||||
common_run mkdir -p $BUILD_SRC
|
||||
|
||||
CMAKE_CMD_ARGS="-DANDROID_NDK=$ANDROID_NDK \
|
||||
-DANDROID_NATIVE_API_LEVEL=android-${NDK_TARGET} \
|
||||
-DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \
|
||||
-DCMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE \
|
||||
-DFREERDP_EXTERNAL_PATH=$BUILD_DST \
|
||||
-DCMAKE_MAKE_PROGRAM=make"
|
||||
|
||||
BASE=$(pwd)
|
||||
for ARCH in $BUILD_ARCH
|
||||
do
|
||||
# build dependencies.
|
||||
if [ $WITH_JPEG -ne 0 ];
|
||||
then
|
||||
if [ $BUILD_DEPS -ne 0 ];
|
||||
then
|
||||
common_run bash $SCRIPT_PATH/android-build-jpeg.sh \
|
||||
--src $BUILD_SRC/jpeg --dst $BUILD_DST \
|
||||
--ndk $ANDROID_NDK \
|
||||
--arch $ARCH \
|
||||
--target $NDK_TARGET \
|
||||
--tag $JPEG_TAG
|
||||
fi
|
||||
CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_JPEG=ON"
|
||||
else
|
||||
CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_JPEG=OFF"
|
||||
fi
|
||||
if [ $WITH_OPENH264 -ne 0 ];
|
||||
then
|
||||
if [ -z "$ANDROID_NDK_OPENH264" ]
|
||||
then
|
||||
echo
|
||||
echo "Warning: Missing openh264-ndk, using $ANDROID_NDK" >&2
|
||||
echo
|
||||
ANDROID_NDK_OPENH264=$ANDROID_NDK
|
||||
fi
|
||||
if [ $BUILD_DEPS -ne 0 ];
|
||||
then
|
||||
common_run bash $SCRIPT_PATH/android-build-openh264.sh \
|
||||
--src $BUILD_SRC/openh264 --dst $BUILD_DST \
|
||||
--sdk "$ANDROID_SDK" \
|
||||
--ndk "$ANDROID_NDK_OPENH264" \
|
||||
--arch $ARCH \
|
||||
--target $NDK_TARGET \
|
||||
--tag $OPENH264_TAG
|
||||
fi
|
||||
CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_OPENH264=ON"
|
||||
else
|
||||
CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_OPENH264=OFF"
|
||||
fi
|
||||
if [ $WITH_OPENSSL -ne 0 ];
|
||||
then
|
||||
if [ $BUILD_DEPS -ne 0 ];
|
||||
then
|
||||
common_run bash $SCRIPT_PATH/android-build-openssl.sh \
|
||||
--src $BUILD_SRC/openssl --dst $BUILD_DST \
|
||||
--sdk "$ANDROID_SDK" \
|
||||
--ndk $ANDROID_NDK \
|
||||
--arch $ARCH \
|
||||
--target $NDK_TARGET \
|
||||
--tag $OPENSSL_TAG
|
||||
fi
|
||||
fi
|
||||
|
||||
# Build and install the library.
|
||||
if [ $DEPS_ONLY -eq 0 ];
|
||||
then
|
||||
common_run cd $BASE
|
||||
common_run mkdir -p $BUILD_SRC/freerdp-build/$ARCH
|
||||
common_run cd $BUILD_SRC/freerdp-build/$ARCH
|
||||
common_run export ANDROID_NDK=$ANDROID_NDK
|
||||
common_run $CMAKE_PROGRAM $CMAKE_CMD_ARGS \
|
||||
-DANDROID_ABI=$ARCH \
|
||||
-DCMAKE_INSTALL_PREFIX=$BUILD_DST/$ARCH \
|
||||
-DCMAKE_INSTALL_LIBDIR=. \
|
||||
$SRC_DIR
|
||||
echo $(pwd)
|
||||
common_run cmake --build . --target install
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Successfully build library for architectures $BUILD_ARCH"
|
||||
@ -1,40 +0,0 @@
|
||||
#!/bin/bash
|
||||
SCM_URL=https://github.com/akallabeth/jpeg8d
|
||||
SCM_TAG=master
|
||||
|
||||
source $(dirname "${BASH_SOURCE[0]}")/android-build-common.sh
|
||||
|
||||
function usage {
|
||||
echo $0 [arguments]
|
||||
echo "\tThe script checks out the OpenH264 git repository"
|
||||
echo "\tto a local source directory, builds and installs"
|
||||
echo "\tthe library for all architectures defined to"
|
||||
echo "\tthe destination directory."
|
||||
echo ""
|
||||
echo "\t[-s|--source-dir <path>]"
|
||||
echo "\t[-d|--destination-dir <path>]"
|
||||
echo "\t[-a|--arch <architectures>]"
|
||||
echo "\t[-t|--tag <tag or branch>]"
|
||||
echo "\t[--scm-url <url>]"
|
||||
echo "\t[--ndk <android NDK path>]"
|
||||
echo "\t[--sdk <android SDK path>]"
|
||||
exit 1
|
||||
}
|
||||
|
||||
function build {
|
||||
echo "Building architectures $BUILD_ARCH..."
|
||||
BASE=$(pwd)
|
||||
common_run cd $BUILD_SRC
|
||||
common_run $NDK_BUILD V=1 APP_ABI="${BUILD_ARCH}" NDK_TOOLCHAIN_VERSION=4.9 -j clean
|
||||
common_run $NDK_BUILD V=1 APP_ABI="${BUILD_ARCH}" NDK_TOOLCHAIN_VERSION=4.9 -j
|
||||
common_run cd $BASE
|
||||
}
|
||||
|
||||
# Run the main program.
|
||||
common_parse_arguments $@
|
||||
common_check_requirements
|
||||
common_update $SCM_URL $SCM_TAG $BUILD_SRC
|
||||
|
||||
build
|
||||
|
||||
common_copy $BUILD_SRC $BUILD_DST
|
||||
@ -1,64 +0,0 @@
|
||||
#!/bin/bash
|
||||
SCM_URL=https://github.com/cisco/openh264
|
||||
SCM_TAG=master
|
||||
|
||||
source $(dirname "${BASH_SOURCE[0]}")/android-build-common.sh
|
||||
|
||||
function build {
|
||||
echo "Building architecture $1..."
|
||||
BASE=$(pwd)
|
||||
common_run cd $BUILD_SRC
|
||||
PATH=$ANDROID_NDK:$PATH
|
||||
MAKE="make PATH=$PATH ENABLEPIC=Yes OS=android NDKROOT=$ANDROID_NDK TARGET=android-$2 NDKLEVEL=$2 ARCH=$1 -j libraries"
|
||||
|
||||
common_run export QUIET_AR="$CCACHE "
|
||||
common_run export QUIET_ASM="$CCACHE "
|
||||
common_run export QUIET_CC="$CCACHE "
|
||||
common_run export QUIET_CCAR="$CCACHE "
|
||||
common_run export QUIET_CXX="$CCACHE "
|
||||
|
||||
common_run $MAKE -j
|
||||
# Install creates a non optimal directory layout, fix that
|
||||
common_run $MAKE PREFIX=$BUILD_SRC/libs/$1 install
|
||||
common_run cd $BASE
|
||||
}
|
||||
|
||||
# Run the main program.
|
||||
common_parse_arguments $@
|
||||
common_check_requirements
|
||||
common_update $SCM_URL $SCM_TAG $BUILD_SRC
|
||||
|
||||
|
||||
for ARCH in $BUILD_ARCH
|
||||
do
|
||||
case $ARCH in
|
||||
"armeabi")
|
||||
OARCH="arm"
|
||||
;;
|
||||
"armeabi-v7a")
|
||||
OARCH="arm"
|
||||
;;
|
||||
"arm64-v8a")
|
||||
OARCH="arm64"
|
||||
;;
|
||||
*)
|
||||
OARCH=$ARCH
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "$ARCH=$OARCH"
|
||||
|
||||
build $OARCH $NDK_TARGET
|
||||
|
||||
if [ ! -d $BUILD_DST/$ARCH/include ];
|
||||
then
|
||||
common_run mkdir -p $BUILD_DST/$ARCH/include
|
||||
fi
|
||||
|
||||
common_run cp -L -r $BUILD_SRC/libs/$OARCH/include/ $BUILD_DST/$ARCH/
|
||||
if [ ! -d $BUILD_DST/$ARCH ];
|
||||
then
|
||||
common_run mkdir -p $BUILD_DST/$ARCH
|
||||
fi
|
||||
common_run cp -L $BUILD_SRC/libs/$OARCH/lib/*.so $BUILD_DST/$ARCH/
|
||||
done
|
||||
@ -1,77 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
SCM_URL=https://github.com/openssl/openssl
|
||||
SCM_TAG=master
|
||||
|
||||
COMPILER=4.9
|
||||
|
||||
source $(dirname "${BASH_SOURCE[0]}")/android-build-common.sh
|
||||
|
||||
function build {
|
||||
if [ $# -ne 2 ];
|
||||
then
|
||||
echo "Invalid arguments $@"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CONFIG=$1
|
||||
DST_PREFIX=$2
|
||||
|
||||
common_run export CC=clang
|
||||
common_run export PATH=$(${SCRIPT_PATH}/toolchains_path.py --ndk ${ANDROID_NDK}):$ORG_PATH
|
||||
common_run export ANDROID_NDK
|
||||
|
||||
echo "CONFIG=$CONFIG"
|
||||
echo "DST_PREFIX=$DST_PREFIX"
|
||||
echo "PATH=$PATH"
|
||||
|
||||
BASE=$(pwd)
|
||||
DST_DIR=$BUILD_DST/$DST_PREFIX
|
||||
common_run cd $BUILD_SRC
|
||||
common_run ./Configure ${CONFIG} -D__ANDROID_API__=$NDK_TARGET
|
||||
common_run make SHLIB_EXT=.so -j build_libs
|
||||
|
||||
if [ ! -d $DST_DIR ];
|
||||
then
|
||||
common_run mkdir -p $DST_DIR
|
||||
fi
|
||||
|
||||
common_run cp *.so $DST_DIR/
|
||||
common_run cd $BASE
|
||||
}
|
||||
|
||||
# Run the main program.
|
||||
common_parse_arguments $@
|
||||
common_check_requirements
|
||||
common_update $SCM_URL $SCM_TAG $BUILD_SRC
|
||||
|
||||
ORG_PATH=$PATH
|
||||
for ARCH in $BUILD_ARCH
|
||||
do
|
||||
|
||||
case $ARCH in
|
||||
"armeabi-v7a")
|
||||
build "android-arm" "armeabi-v7a"
|
||||
;;
|
||||
"x86")
|
||||
build "android-x86" "x86"
|
||||
;;
|
||||
"arm64-v8a")
|
||||
build "android-arm64" "arm64-v8a"
|
||||
;;
|
||||
"x86_64")
|
||||
build "android-x86_64" "x86_64"
|
||||
;;
|
||||
*)
|
||||
echo "[WARNING] Skipping unsupported architecture $ARCH"
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ ! -d $BUILD_DST/$ARCH/include ];
|
||||
then
|
||||
common_run mkdir -p $BUILD_DST/$ARCH/include
|
||||
fi
|
||||
common_run cp -L -R $BUILD_SRC/include/openssl $BUILD_DST/$ARCH/include/
|
||||
|
||||
@ -1,29 +0,0 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Android build confguration
|
||||
#
|
||||
# Note: This is a simple configuration to build all
|
||||
# architectures in one rush.
|
||||
# Since android 64 bit support was introduced with NDK API 21
|
||||
# this is the minimal common denominator.
|
||||
# If you require support for older NDK API levels,
|
||||
# create seperate configurations for each NDK API level
|
||||
# and architecture you want to support.
|
||||
WITH_JPEG=0
|
||||
WITH_OPENH264=0
|
||||
WITH_OPENSSL=1
|
||||
BUILD_DEPS=1
|
||||
DEPS_ONLY=0
|
||||
NDK_TARGET=26
|
||||
|
||||
JPEG_TAG=master
|
||||
OPENH264_TAG=v1.8.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0
|
||||
OPENSSL_TAG=OpenSSL_1_1_1j
|
||||
|
||||
SRC_DIR=$SCRIPT_PATH/..
|
||||
BUILD_DST=$SCRIPT_PATH/../client/Android/Studio/freeRDPCore/src/main/jniLibs
|
||||
BUILD_SRC=$SRC_DIR/build
|
||||
|
||||
CMAKE_BUILD_TYPE=Debug
|
||||
|
||||
BUILD_ARCH="armeabi-v7a x86 arm64-v8a x86_64"
|
||||
@ -255,6 +255,14 @@ struct uwac_window
|
||||
int pointer_current_cursor;
|
||||
};
|
||||
|
||||
/**@brief data to pass to wl_buffer release listener */
|
||||
struct uwac_buffer_release_data
|
||||
{
|
||||
UwacWindow* window;
|
||||
int bufferIdx;
|
||||
};
|
||||
typedef struct uwac_buffer_release_data UwacBufferReleaseData;
|
||||
|
||||
/* in uwa-display.c */
|
||||
UwacEvent* UwacDisplayNewEvent(UwacDisplay* d, int type);
|
||||
int UwacDisplayWatchFd(UwacDisplay* display, int fd, uint32_t events, UwacTask* task);
|
||||
|
||||
@ -46,7 +46,8 @@ static int bppFromShmFormat(enum wl_shm_format format)
|
||||
|
||||
static void buffer_release(void* data, struct wl_buffer* buffer)
|
||||
{
|
||||
UwacBuffer* uwacBuffer = (UwacBuffer*)data;
|
||||
UwacBufferReleaseData* releaseData = data;
|
||||
UwacBuffer* uwacBuffer = &releaseData->window->buffers[releaseData->bufferIdx];
|
||||
uwacBuffer->used = false;
|
||||
}
|
||||
|
||||
@ -64,7 +65,10 @@ static void UwacWindowDestroyBuffers(UwacWindow* w)
|
||||
#else
|
||||
region16_uninit(&buffer->damage);
|
||||
#endif
|
||||
UwacBufferReleaseData* releaseData =
|
||||
(UwacBufferReleaseData*)wl_buffer_get_user_data(buffer->wayland_buffer);
|
||||
wl_buffer_destroy(buffer->wayland_buffer);
|
||||
free(releaseData);
|
||||
munmap(buffer->data, buffer->size);
|
||||
}
|
||||
|
||||
@ -342,7 +346,8 @@ int UwacWindowShmAllocBuffers(UwacWindow* w, int nbuffers, int allocSize, uint32
|
||||
|
||||
for (i = 0; i < nbuffers; i++)
|
||||
{
|
||||
UwacBuffer* buffer = &w->buffers[w->nbuffers + i];
|
||||
int bufferIdx = w->nbuffers + i;
|
||||
UwacBuffer* buffer = &w->buffers[bufferIdx];
|
||||
#ifdef HAVE_PIXMAN_REGION
|
||||
pixman_region32_init(&buffer->damage);
|
||||
#else
|
||||
@ -352,7 +357,10 @@ int UwacWindowShmAllocBuffers(UwacWindow* w, int nbuffers, int allocSize, uint32
|
||||
buffer->size = allocSize;
|
||||
buffer->wayland_buffer =
|
||||
wl_shm_pool_create_buffer(pool, allocSize * i, width, height, w->stride, format);
|
||||
wl_buffer_add_listener(buffer->wayland_buffer, &buffer_listener, buffer);
|
||||
UwacBufferReleaseData* listener_data = xmalloc(sizeof(UwacBufferReleaseData));
|
||||
listener_data->window = w;
|
||||
listener_data->bufferIdx = bufferIdx;
|
||||
wl_buffer_add_listener(buffer->wayland_buffer, &buffer_listener, listener_data);
|
||||
}
|
||||
|
||||
wl_shm_pool_destroy(pool);
|
||||
|
||||
@ -51,7 +51,7 @@ if (NOT WIN32)
|
||||
endif()
|
||||
|
||||
# Soname versioning
|
||||
set(RAW_VERSION_STRING "2.5.0")
|
||||
set(RAW_VERSION_STRING "2.6.0")
|
||||
if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag")
|
||||
file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING)
|
||||
elseif(USE_VERSION_FROM_GIT_TAG)
|
||||
|
||||
@ -30,7 +30,7 @@ endif(NOT WITH_ICU)
|
||||
|
||||
if (WITH_ICU)
|
||||
find_package(ICU REQUIRED i18n uc io)
|
||||
include_directories(${ICU_INCLUDE_DIRS})
|
||||
winpr_include_directory_add(${ICU_INCLUDE_DIRS})
|
||||
winpr_library_add_private(${ICU_LIBRARIES})
|
||||
endif (WITH_ICU)
|
||||
|
||||
|
||||
@ -21,8 +21,11 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <winpr/sspicli.h>
|
||||
|
||||
#define WINPR_ASSERT(x) assert(x)
|
||||
|
||||
/**
|
||||
* sspicli.dll:
|
||||
*
|
||||
@ -60,6 +63,12 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_GETPWUID_R)
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include <pwd.h>
|
||||
@ -200,31 +209,33 @@ BOOL LogonUserExW(LPCWSTR lpszUsername, LPCWSTR lpszDomain, LPCWSTR lpszPassword
|
||||
|
||||
BOOL GetUserNameExA(EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize)
|
||||
{
|
||||
size_t length;
|
||||
char login[MAX_PATH];
|
||||
WINPR_ASSERT(lpNameBuffer);
|
||||
WINPR_ASSERT(nSize);
|
||||
|
||||
switch (NameFormat)
|
||||
{
|
||||
case NameSamCompatible:
|
||||
#ifndef HAVE_GETLOGIN_R
|
||||
strncpy(login, getlogin(), sizeof(login));
|
||||
#else
|
||||
if (getlogin_r(login, sizeof(login)) != 0)
|
||||
#if defined(HAVE_GETPWUID_R)
|
||||
{
|
||||
int rc;
|
||||
struct passwd pwd = { 0 };
|
||||
struct passwd* result = NULL;
|
||||
uid_t uid = getuid();
|
||||
|
||||
rc = getpwuid_r(uid, &pwd, lpNameBuffer, *nSize, &result);
|
||||
if (rc != 0)
|
||||
return FALSE;
|
||||
if (result == NULL)
|
||||
return FALSE;
|
||||
}
|
||||
#elif defined(HAVE_GETLOGIN_R)
|
||||
if (getlogin_r(lpNameBuffer, *nSize) != 0)
|
||||
return FALSE;
|
||||
#else
|
||||
strncpy(lpNameBuffer, getlogin(), *nSize);
|
||||
#endif
|
||||
length = strlen(login);
|
||||
|
||||
if (*nSize >= length)
|
||||
{
|
||||
CopyMemory(lpNameBuffer, login, length + 1);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
*nSize = length + 1;
|
||||
}
|
||||
|
||||
break;
|
||||
*nSize = strnlen(lpNameBuffer, *nSize);
|
||||
return TRUE;
|
||||
|
||||
case NameFullyQualifiedDN:
|
||||
case NameDisplay:
|
||||
@ -245,7 +256,29 @@ BOOL GetUserNameExA(EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG
|
||||
|
||||
BOOL GetUserNameExW(EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize)
|
||||
{
|
||||
return 0;
|
||||
int res;
|
||||
BOOL rc = FALSE;
|
||||
char* name;
|
||||
|
||||
WINPR_ASSERT(nSize);
|
||||
WINPR_ASSERT(lpNameBuffer);
|
||||
|
||||
name = calloc(1, *nSize + 1);
|
||||
if (!name)
|
||||
goto fail;
|
||||
|
||||
if (!GetUserNameExA(NameFormat, name, nSize))
|
||||
goto fail;
|
||||
|
||||
res = ConvertToUnicode(CP_UTF8, 0, name, -1, &lpNameBuffer, *nSize);
|
||||
if (res < 0)
|
||||
goto fail;
|
||||
|
||||
*nSize = res + 1;
|
||||
rc = TRUE;
|
||||
fail:
|
||||
free(name);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -1,15 +1,14 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
|
||||
#define THREADS 24
|
||||
#define THREADS 8
|
||||
|
||||
static DWORD WINAPI test_thread(LPVOID arg)
|
||||
{
|
||||
long timeout = 100 + (rand() % 1000);
|
||||
long timeout = 30 + (rand() % 100);
|
||||
WINPR_UNUSED(arg);
|
||||
Sleep(timeout);
|
||||
ExitThread(0);
|
||||
@ -22,7 +21,7 @@ static int start_threads(DWORD count, HANDLE* threads)
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
threads[i] = CreateThread(NULL, 0, test_thread, NULL, 0, NULL);
|
||||
threads[i] = CreateThread(NULL, 0, test_thread, NULL, CREATE_SUSPENDED, NULL);
|
||||
|
||||
if (!threads[i])
|
||||
{
|
||||
@ -31,38 +30,45 @@ static int start_threads(DWORD count, HANDLE* threads)
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
ResumeThread(threads[i]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int close_threads(DWORD count, HANDLE* threads)
|
||||
{
|
||||
int rc = 0;
|
||||
DWORD i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (!threads[i])
|
||||
continue;
|
||||
|
||||
if (!CloseHandle(threads[i]))
|
||||
{
|
||||
fprintf(stderr, "%s: CloseHandle [%" PRIu32 "] failure\n", __FUNCTION__, i);
|
||||
return -1;
|
||||
rc = -1;
|
||||
}
|
||||
threads[i] = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL TestWaitForAll(void)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
DWORD ret;
|
||||
HANDLE threads[THREADS];
|
||||
HANDLE threads[THREADS] = { 0 };
|
||||
/* WaitForAll, timeout */
|
||||
if (start_threads(THREADS, threads))
|
||||
{
|
||||
fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__);
|
||||
return FALSE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = WaitForMultipleObjects(THREADS, threads, TRUE, 50);
|
||||
ret = WaitForMultipleObjects(THREADS, threads, TRUE, 10);
|
||||
if (ret != WAIT_TIMEOUT)
|
||||
{
|
||||
fprintf(stderr, "%s: WaitForMultipleObjects bWaitAll, timeout 50 failed, ret=%d\n",
|
||||
@ -76,14 +82,14 @@ static BOOL TestWaitForAll(void)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = TRUE;
|
||||
fail:
|
||||
if (close_threads(THREADS, threads))
|
||||
{
|
||||
fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
rc = TRUE;
|
||||
fail:
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -91,12 +97,12 @@ static BOOL TestWaitOne(void)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
DWORD ret;
|
||||
HANDLE threads[THREADS];
|
||||
HANDLE threads[THREADS] = { 0 };
|
||||
/* WaitForAll, timeout */
|
||||
if (start_threads(THREADS, threads))
|
||||
{
|
||||
fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__);
|
||||
return FALSE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = WaitForMultipleObjects(THREADS, threads, FALSE, INFINITE);
|
||||
@ -112,14 +118,14 @@ static BOOL TestWaitOne(void)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = TRUE;
|
||||
fail:
|
||||
if (close_threads(THREADS, threads))
|
||||
{
|
||||
fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
rc = TRUE;
|
||||
fail:
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -127,15 +133,15 @@ static BOOL TestWaitOneTimeout(void)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
DWORD ret;
|
||||
HANDLE threads[THREADS];
|
||||
HANDLE threads[THREADS] = { 0 };
|
||||
/* WaitForAll, timeout */
|
||||
if (start_threads(THREADS, threads))
|
||||
{
|
||||
fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__);
|
||||
return FALSE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = WaitForMultipleObjects(THREADS, threads, FALSE, 50);
|
||||
ret = WaitForMultipleObjects(THREADS, threads, FALSE, 1);
|
||||
if (ret != WAIT_TIMEOUT)
|
||||
{
|
||||
fprintf(stderr, "%s: WaitForMultipleObjects timeout 50 failed, ret=%d\n", __FUNCTION__,
|
||||
@ -148,15 +154,14 @@ static BOOL TestWaitOneTimeout(void)
|
||||
fprintf(stderr, "%s: WaitForMultipleObjects bWaitAll, INFINITE failed\n", __FUNCTION__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = TRUE;
|
||||
fail:
|
||||
if (close_threads(THREADS, threads))
|
||||
{
|
||||
fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
rc = TRUE;
|
||||
fail:
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -164,12 +169,12 @@ static BOOL TestWaitOneTimeoutMultijoin(void)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
DWORD ret, i;
|
||||
HANDLE threads[THREADS];
|
||||
HANDLE threads[THREADS] = { 0 };
|
||||
/* WaitForAll, timeout */
|
||||
if (start_threads(THREADS, threads))
|
||||
{
|
||||
fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__);
|
||||
return FALSE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (i = 0; i < THREADS; i++)
|
||||
@ -177,7 +182,7 @@ static BOOL TestWaitOneTimeoutMultijoin(void)
|
||||
ret = WaitForMultipleObjects(THREADS, threads, FALSE, 0);
|
||||
if (ret != WAIT_TIMEOUT)
|
||||
{
|
||||
fprintf(stderr, "%s: WaitForMultipleObjects timeout 50 failed, ret=%d\n", __FUNCTION__,
|
||||
fprintf(stderr, "%s: WaitForMultipleObjects timeout 0 failed, ret=%d\n", __FUNCTION__,
|
||||
ret);
|
||||
goto fail;
|
||||
}
|
||||
@ -189,34 +194,37 @@ static BOOL TestWaitOneTimeoutMultijoin(void)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = TRUE;
|
||||
fail:
|
||||
if (close_threads(THREADS, threads))
|
||||
{
|
||||
fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
rc = TRUE;
|
||||
fail:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL TestDetach(void)
|
||||
{
|
||||
HANDLE threads[THREADS];
|
||||
BOOL rc = FALSE;
|
||||
HANDLE threads[THREADS] = { 0 };
|
||||
/* WaitForAll, timeout */
|
||||
if (start_threads(THREADS, threads))
|
||||
{
|
||||
fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__);
|
||||
return FALSE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = TRUE;
|
||||
fail:
|
||||
if (close_threads(THREADS, threads))
|
||||
{
|
||||
fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int TestSynchMultipleThreads(int argc, char* argv[])
|
||||
|
||||
@ -173,23 +173,29 @@ static void SamLookupFinish(WINPR_SAM* sam)
|
||||
static void HexStrToBin(const char* str, BYTE* bin, size_t length)
|
||||
{
|
||||
size_t i;
|
||||
CharUpperBuffA(str, length * 2);
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
bin[i] = 0;
|
||||
char cur = str[2 * i];
|
||||
char curNext = str[2 * i + 1];
|
||||
BYTE* curBin = &bin[i];
|
||||
|
||||
if ((str[i * 2] >= '0') && (str[i * 2] <= '9'))
|
||||
bin[i] |= (str[i * 2] - '0') << 4;
|
||||
CharUpperBuffA(&cur, 1);
|
||||
CharUpperBuffA(&curNext, 1);
|
||||
|
||||
if ((str[i * 2] >= 'A') && (str[i * 2] <= 'F'))
|
||||
bin[i] |= (str[i * 2] - 'A' + 10) << 4;
|
||||
*curBin = 0;
|
||||
|
||||
if ((str[i * 2 + 1] >= '0') && (str[i * 2 + 1] <= '9'))
|
||||
bin[i] |= (str[i * 2 + 1] - '0');
|
||||
if ((cur >= '0') && (cur <= '9'))
|
||||
*curBin |= (cur - '0') << 4;
|
||||
|
||||
if ((str[i * 2 + 1] >= 'A') && (str[i * 2 + 1] <= 'F'))
|
||||
bin[i] |= (str[i * 2 + 1] - 'A' + 10);
|
||||
if ((cur >= 'A') && (cur <= 'F'))
|
||||
*curBin |= (cur - 'A' + 10) << 4;
|
||||
|
||||
if ((curNext >= '0') && (curNext <= '9'))
|
||||
*curBin |= (curNext - '0');
|
||||
|
||||
if ((curNext >= 'A') && (curNext <= 'F'))
|
||||
*curBin |= (curNext - 'A' + 10);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user