Commit 46d9a93a authored by Mike Gabriel's avatar Mike Gabriel
Browse files

Imported Upstream version 1.1.0~beta1+git20130629

parent 2c19218f
# CMake
CMakeFiles/
CMakeScripts/
CMakeCache.txt
config.h
install_manifest.txt
install_manifest*.txt
CTestTestfile.cmake
freerdp.pc
Makefile
Testing
cmake_install.cmake
CPackConfig.cmake
CPackSourceConfig.cmake
DartConfiguration.tcl
_CPack_Packages
external/*
!external/README
# Packages
*.zip
*.exe
*.sh
*.deb
*.rpm
*.tar.Z
*.tar.gz
# Eclipse
*.project
*.cproject
*.settings
# .rdp files
*.rdp
*.RDP
# Documentation
docs/api
client/X11/xfreerdp.1
# Mac OS X
.DS_Store
*.xcodeproj/
DerivedData/
# iOS
FreeRDP.build
Debug-*
Release-*
# Windows
*.vcxproj
*.vcxproj.*
*.vcproj
*.vcproj.*
*.sdf
*.sln
*.suo
*.ncb
*.opensdf
Thumbs.db
ipch
Debug
RelWithDebInfo
# Binaries
*.a
*.so
*.so.*
*.dylib
bin
libs
cunit/test_freerdp
client/X11/xfreerdp
client/test/freerdp-test
client/Mac/xcode
client/Sample/sfreerdp
client/DirectFB/dfreerdp
server/test/tfreerdp-server
server/Sample/sfreerdp-server
server/X11/xfreerdp-server
xcode
# Other
*~
*.dir
Release
Win32
build*/
*.orig
default.log
*Amplifier XE*
*Inspector XE*
*.cbp
*.txt.user
*.autosave
This diff is collapsed.
2013-01-02 Version 1.0.2
FreeRDP 1.0.2 is a maintenance release which contains several bug and stability fixes.
* xfreerdp:
* new parameter --from-stdin - prompts for unspecified arguments username, password, domain and host.
* fix compability with x2go
* fix keyboard state in remote app
* documentation fixes
* fixed crash when started with --authonly (#843)
* libfreerdp-core:
* several memory leaks and double frees were fixed
* support for FastPath PDUs up to 32767
* register audio only if plugin is registered
* load extensions after argument parsing
* libfreerdp-utils:
* fixed crash when HOME environment variable wasn't set
* xfreerdp-server
* deadlock fixed
* accept TLSv1 and SSLv3
* smartcard
* don't incorrectly set SCARD_STATE_IGNORE
* libfreerdp-codec
* performance improvement
* libfreerdp-gdi
* support for PatBlt DPa operation
* plugin
* ignore CHANNEL_FLAG_SUSPEND/CHANNEL_FLAG_RESUME to prevent possible crash
For a detailed list of changes use "git log 1.0.1..1.0.2"
Known problems:
* If windows input language is set to german pressing the divde key (/) on the keypad
results in minus (-) (see issue #811)
2012-02-07 Version 1.0.1
FreeRDP 1.0.1 is a maintenance release to address a certain number of
......
......@@ -8,10 +8,12 @@ interoperability can finally liberate your computing experience.
Resources
---------
Website: http://www.freerdp.com/
Wiki: https://github.com/FreeRDP/FreeRDP/wiki
Project website: http://www.freerdp.com/
Issue tracker: https://github.com/FreeRDP/FreeRDP/issues
Sources: https://github.com/FreeRDP/FreeRDP/
API doc: http://www.freerdp.com/api/
Wiki: https://github.com/FreeRDP/FreeRDP/wiki
Downloads and other resources: http://pub.freerdp.com
API doc: http://pub.freerdp.com/api/
IRC channel: #freerdp @ irc.freenode.net
Mailing list: https://lists.sourceforge.net/lists/listinfo/freerdp-devel
......
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string></string>
<key>CFBundleIconFile</key>
<string>FreeRDP</string>
<key>CFBundleIdentifier</key>
<string>FreeRDP.Mac</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string></string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string></string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2012 __MyCompanyName__. All rights reserved.</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>
# FreeRDP: A Remote Desktop Protocol Client
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2011 O.S. Systems Software Ltda.
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
# Copyright 2012 Marc-Andre 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.
......@@ -17,10 +15,221 @@
# See the License for the specific language governing permissions and
# limitations under the License.
add_subdirectory(cliprdr)
add_subdirectory(drdynvc)
add_subdirectory(rdpdbg)
add_subdirectory(rdpdr)
add_subdirectory(rail)
add_subdirectory(rdpsnd)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
include(CMakeParseArguments)
include(CMakeDependentOption)
macro(define_channel_options)
set(PREFIX "CHANNEL")
cmake_parse_arguments(${PREFIX}
""
"NAME;TYPE;DESCRIPTION;SPECIFICATIONS;DEFAULT"
""
${ARGN})
string(TOUPPER "CHANNEL_${CHANNEL_NAME}" CHANNEL_OPTION)
string(TOUPPER "CHANNEL_${CHANNEL_NAME}_CLIENT" CHANNEL_CLIENT_OPTION)
string(TOUPPER "CHANNEL_${CHANNEL_NAME}_SERVER" CHANNEL_SERVER_OPTION)
if(${${CHANNEL_CLIENT_OPTION}})
set(OPTION_CLIENT_DEFAULT ${${CHANNEL_CLIENT_OPTION}})
endif()
if(${${CHANNEL_SERVER_OPTION}})
set(OPTION_SERVER_DEFAULT ${${CHANNEL_SERVER_OPTION}})
endif()
if(${${CHANNEL_OPTION}})
set(OPTION_DEFAULT ${${CHANNEL_OPTION}})
endif()
if(${OPTION_CLIENT_DEFAULT} OR ${OPTION_SERVER_DEFAULT})
set(OPTION_DEFAULT "ON")
endif()
set(CHANNEL_DEFAULT ${OPTION_DEFAULT})
set(CHANNEL_OPTION_DOC "Build ${CHANNEL_NAME} ${CHANNEL_TYPE} channel")
option(${CHANNEL_OPTION} "${CHANNEL_OPTION_DOC}" ${CHANNEL_DEFAULT})
endmacro(define_channel_options)
macro(define_channel_client_options _channel_client_default)
string(TOUPPER "CHANNEL_${CHANNEL_NAME}_CLIENT" CHANNEL_CLIENT_OPTION)
set(CHANNEL_CLIENT_OPTION_DOC "Build ${CHANNEL_NAME} ${CHANNEL_TYPE} channel client")
option(${CHANNEL_CLIENT_OPTION} "${CHANNEL_CLIENT_OPTION_DOC}" ${_channel_client_default})
cmake_dependent_option(${CHANNEL_CLIENT_OPTION} "${CHANNEL_CLIENT_OPTION_DOC}"
${_channel_client_default} "${CHANNEL_OPTION}" OFF)
endmacro(define_channel_client_options)
macro(define_channel_server_options _channel_server_default)
string(TOUPPER "CHANNEL_${CHANNEL_NAME}_SERVER" CHANNEL_SERVER_OPTION)
set(CHANNEL_SERVER_OPTION_DOC "Build ${CHANNEL_NAME} ${CHANNEL_TYPE} channel server")
option(${CHANNEL_SERVER_OPTION} "${CHANNEL_SERVER_OPTION_DOC}" ${_channel_server_default})
cmake_dependent_option(${CHANNEL_SERVER_OPTION} "${CHANNEL_SERVER_OPTION_DOC}"
${_channel_server_default} "${CHANNEL_OPTION}" OFF)
endmacro(define_channel_server_options)
macro(define_channel _channel_name)
set(CHANNEL_NAME ${_channel_name})
set(MODULE_NAME ${CHANNEL_NAME})
string(TOUPPER "CHANNEL_${CHANNEL_NAME}" MODULE_PREFIX)
endmacro(define_channel)
macro(define_channel_client _channel_name)
set(CHANNEL_NAME ${_channel_name})
set(MODULE_NAME "${CHANNEL_NAME}-client")
string(TOUPPER "CHANNEL_${CHANNEL_NAME}_CLIENT" MODULE_PREFIX)
endmacro(define_channel_client)
macro(define_channel_server _channel_name)
set(CHANNEL_NAME ${_channel_name})
set(MODULE_NAME "${CHANNEL_NAME}-server")
string(TOUPPER "CHANNEL_${CHANNEL_NAME}_SERVER" MODULE_PREFIX)
endmacro(define_channel_server)
macro(define_channel_client_subsystem _channel_name _subsystem _type)
set(CHANNEL_NAME ${_channel_name})
set(CHANNEL_SUBSYSTEM ${_subsystem})
string(LENGTH "${_type}" _type_length)
string(TOUPPER "CHANNEL_${CHANNEL_NAME}_CLIENT" CHANNEL_PREFIX)
if(_type_length GREATER 0)
set(SUBSYSTEM_TYPE ${_type})
set(MODULE_NAME "${CHANNEL_NAME}-client-${CHANNEL_SUBSYSTEM}-${SUBSYSTEM_TYPE}")
string(TOUPPER "CHANNEL_${CHANNEL_NAME}_CLIENT_${CHANNEL_SUBSYSTEM}_${SUBSYSTEM_TYPE}" MODULE_PREFIX)
else()
set(MODULE_NAME "${CHANNEL_NAME}-client-${CHANNEL_SUBSYSTEM}")
string(TOUPPER "CHANNEL_${CHANNEL_NAME}_CLIENT_${CHANNEL_SUBSYSTEM}" MODULE_PREFIX)
endif()
endmacro(define_channel_client_subsystem)
macro(define_channel_server_subsystem _channel_name _subsystem _type)
set(CHANNEL_NAME ${_channel_name})
set(CHANNEL_SUBSYSTEM ${_subsystem})
set(MODULE_NAME "${CHANNEL_NAME}-server-${CHANNEL_SUBSYSTEM}")
string(TOUPPER "CHANNEL_${CHANNEL_NAME}_server_${CHANNEL_SUBSYSTEM}" MODULE_PREFIX)
endmacro(define_channel_server_subsystem)
macro(add_channel_client _channel_prefix _channel_name)
add_subdirectory(client)
if(${${_channel_prefix}_CLIENT_STATIC})
set(CHANNEL_STATIC_CLIENT_MODULES ${CHANNEL_STATIC_CLIENT_MODULES} ${_channel_prefix} PARENT_SCOPE)
set(${_channel_prefix}_CLIENT_NAME ${${_channel_prefix}_CLIENT_NAME} PARENT_SCOPE)
set(${_channel_prefix}_CLIENT_CHANNEL ${${_channel_prefix}_CLIENT_CHANNEL} PARENT_SCOPE)
set(${_channel_prefix}_CLIENT_ENTRY ${${_channel_prefix}_CLIENT_ENTRY} PARENT_SCOPE)
set(CHANNEL_STATIC_CLIENT_ENTRIES ${CHANNEL_STATIC_CLIENT_ENTRIES} ${${_channel_prefix}_CLIENT_ENTRY} PARENT_SCOPE)
endif()
endmacro(add_channel_client)
macro(add_channel_server _channel_prefix _channel_name)
add_subdirectory(server)
if(${${_channel_prefix}_SERVER_STATIC})
set(CHANNEL_STATIC_SERVER_MODULES ${CHANNEL_STATIC_SERVER_MODULES} ${_channel_prefix} PARENT_SCOPE)
set(${_channel_prefix}_SERVER_NAME ${${_channel_prefix}_SERVER_NAME} PARENT_SCOPE)
set(${_channel_prefix}_SERVER_CHANNEL ${${_channel_prefix}_SERVER_CHANNEL} PARENT_SCOPE)
set(${_channel_prefix}_SERVER_ENTRY ${${_channel_prefix}_SERVER_ENTRY} PARENT_SCOPE)
set(CHANNEL_STATIC_SERVER_ENTRIES ${CHANNEL_STATIC_SERVER_ENTRIES} ${${_channel_prefix}_SERVER_ENTRY} PARENT_SCOPE)
endif()
endmacro(add_channel_server)
macro(add_channel_client_subsystem _channel_prefix _channel_name _subsystem _type)
add_subdirectory(${_subsystem})
set(_channel_module_name "${_channel_name}-client")
string(LENGTH "${_type}" _type_length)
if(_type_length GREATER 0)
string(TOUPPER "CHANNEL_${_channel_name}_CLIENT_${_subsystem}_${_type}" _subsystem_prefix)
else()
string(TOUPPER "CHANNEL_${_channel_name}_CLIENT_${_subsystem}" _subsystem_prefix)
endif()
if(${${_subsystem_prefix}_STATIC})
get_target_property(CHANNEL_SUBSYSTEMS ${_channel_module_name} SUBSYSTEMS)
if(_type_length GREATER 0)
set(SUBSYSTEMS ${SUBSYSTEMS} "${_subsystem}-${_type}")
else()
set(SUBSYSTEMS ${SUBSYSTEMS} ${_subsystem})
endif()
set_target_properties(${_channel_module_name} PROPERTIES SUBSYSTEMS "${SUBSYSTEMS}")
endif()
endmacro(add_channel_client_subsystem)
macro(add_channel_client_library _module_prefix _module_name _channel_name _dynamic _entry)
if(${_dynamic} AND MSVC AND (NOT STATIC_CHANNELS))
set(${_module_prefix}_SRCS ${${_module_prefix}_SRCS} module.def)
endif()
if(${_dynamic} AND (NOT STATIC_CHANNELS))
add_library(${_module_name} ${${_module_prefix}_SRCS})
else()
set(${_module_prefix}_STATIC ON PARENT_SCOPE)
set(${_module_prefix}_NAME ${_module_name} PARENT_SCOPE)
set(${_module_prefix}_CHANNEL ${_channel_name} PARENT_SCOPE)
set(${_module_prefix}_ENTRY ${_entry} PARENT_SCOPE)
add_library(${_module_name} STATIC ${${_module_prefix}_SRCS})
endif()
endmacro(add_channel_client_library)
macro(add_channel_client_subsystem_library _module_prefix _module_name _channel_name _type _dynamic _entry)
if(${_dynamic} AND MSVC AND (NOT STATIC_CHANNELS))
set(${_module_prefix}_SRCS ${${_module_prefix}_SRCS} module.def)
endif()
if(${_dynamic} AND (NOT STATIC_CHANNELS))
add_library(${_module_name} ${${_module_prefix}_SRCS})
else()
set(${_module_prefix}_STATIC ON PARENT_SCOPE)
set(${_module_prefix}_NAME ${_module_name} PARENT_SCOPE)
set(${_module_prefix}_TYPE ${_type} PARENT_SCOPE)
add_library(${_module_name} STATIC ${${_module_prefix}_SRCS})
endif()
endmacro(add_channel_client_subsystem_library)
macro(add_channel_server_library _module_prefix _module_name _channel_name _dynamic _entry)
if(${_dynamic} AND MSVC AND (NOT STATIC_CHANNELS))
set(${_module_prefix}_SRCS ${${_module_prefix}_SRCS} module.def)
endif()
if(${_dynamic} AND (NOT STATIC_CHANNELS))
add_library(${_module_name} ${${_module_prefix}_SRCS})
else()
set(${_module_prefix}_STATIC ON PARENT_SCOPE)
set(${_module_prefix}_NAME ${_module_name} PARENT_SCOPE)
set(${_module_prefix}_CHANNEL ${_channel_name} PARENT_SCOPE)
set(${_module_prefix}_ENTRY ${_entry} PARENT_SCOPE)
add_library(${_module_name} STATIC ${${_module_prefix}_SRCS})
endif()
endmacro(add_channel_server_library)
set(FILENAME "ChannelOptions.cmake")
file(GLOB FILEPATHS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*/${FILENAME}")
foreach(FILEPATH ${FILEPATHS})
if(${FILEPATH} MATCHES "^([^/]*)//${FILENAME}")
string(REGEX REPLACE "^([^/]*)//${FILENAME}" "\\1" DIR ${FILEPATH})
set(CHANNEL_OPTION)
include(${FILEPATH})
if(${CHANNEL_OPTION})
set(CHANNEL_MESSAGE "Adding ${CHANNEL_TYPE} channel")
if(${CHANNEL_CLIENT_OPTION})
set(CHANNEL_MESSAGE "${CHANNEL_MESSAGE} client")
endif()
if(${CHANNEL_SERVER_OPTION})
set(CHANNEL_MESSAGE "${CHANNEL_MESSAGE} server")
endif()
set(CHANNEL_MESSAGE "${CHANNEL_MESSAGE} \"${CHANNEL_NAME}\"")
set(CHANNEL_MESSAGE "${CHANNEL_MESSAGE}: ${CHANNEL_DESCRIPTION}")
message(STATUS "${CHANNEL_MESSAGE}")
add_subdirectory(${DIR})
endif()
endif()
endforeach(FILEPATH)
if(WITH_CLIENT_CHANNELS)
add_subdirectory(client)
set(FREERDP_CHANNELS_CLIENT_SRCS ${FREERDP_CHANNELS_CLIENT_SRCS} PARENT_SCOPE)
set(FREERDP_CHANNELS_CLIENT_LIBS ${FREERDP_CHANNELS_CLIENT_LIBS} PARENT_SCOPE)
endif()
if(WITH_SERVER_CHANNELS)
add_subdirectory(server)
set(FREERDP_CHANNELS_SERVER_SRCS ${FREERDP_CHANNELS_SERVER_SRCS} PARENT_SCOPE)
set(FREERDP_CHANNELS_SERVER_LIBS ${FREERDP_CHANNELS_SERVER_LIBS} PARENT_SCOPE)
endif()
# FreeRDP: A Remote Desktop Protocol Client
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2011 O.S. Systems Software Ltda.
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
# Copyright 2012 Marc-Andre 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.
......@@ -17,13 +15,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.
set(RDPDBG_SRCS
rdpdbg_main.c
)
define_channel("audin")
add_library(rdpdbg ${RDPDBG_SRCS})
set_target_properties(rdpdbg PROPERTIES PREFIX "")
if(WITH_CLIENT_CHANNELS)
add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME})
endif()
target_link_libraries(rdpdbg freerdp-utils)
install(TARGETS rdpdbg DESTINATION ${FREERDP_PLUGIN_PATH})
if(WITH_SERVER_CHANNELS)
add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME})
endif()
set(OPTION_DEFAULT OFF)
set(OPTION_CLIENT_DEFAULT ON)
set(OPTION_SERVER_DEFAULT ON)
if(ANDROID)
set(OPTION_CLIENT_DEFAULT OFF)
set(OPTION_SERVER_DEFAULT OFF)
endif()
define_channel_options(NAME "audin" TYPE "dynamic"
DESCRIPTION "Audio Input Redirection Virtual Channel Extension"
SPECIFICATIONS "[MS-RDPEAI]"
DEFAULT ${OPTION_DEFAULT})
define_channel_client_options(${OPTION_CLIENT_DEFAULT})
define_channel_server_options(${OPTION_SERVER_DEFAULT})
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2012 Marc-Andre 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_channel_client("audin")
set(${MODULE_PREFIX}_SRCS
audin_main.c
audin_main.h)
include_directories(..)
add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry")
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE freerdp
MODULES freerdp-common freerdp-utils)
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
if(NOT STATIC_CHANNELS)
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_PLUGIN_PATH})
endif()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client")
if(WITH_ALSA)
add_channel_client_subsystem(${MODULE_PREFIX} ${CHANNEL_NAME} "alsa" "")
endif()
if(WITH_PULSE)
add_channel_client_subsystem(${MODULE_PREFIX} ${CHANNEL_NAME} "pulse" "")
endif()
# FreeRDP: A Remote Desktop Protocol Client
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2011 O.S. Systems Software Ltda.
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
# Copyright 2012 Marc-Andre 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.
......@@ -17,17 +15,27 @@
# See the License for the specific language governing permissions and
# limitations under the License.
set(RDPSND_ALSA_SRCS
rdpsnd_alsa.c
)
define_channel_client_subsystem("audin" "alsa" "")
set(${MODULE_PREFIX}_SRCS
audin_alsa.c)
include_directories(..)
include_directories(${ALSA_INCLUDE_DIRS})
add_library(rdpsnd_alsa ${RDPSND_ALSA_SRCS})
set_target_properties(rdpsnd_alsa PROPERTIES PREFIX "")
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE freerdp
MODULES freerdp-utils)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${ALSA_LIBRARIES})
target_link_libraries(rdpsnd_alsa freerdp-utils)
target_link_libraries(rdpsnd_alsa ${ALSA_LIBRARIES})
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
install(TARGETS rdpsnd_alsa DESTINATION ${FREERDP_PLUGIN_PATH})
if(NOT STATIC_CHANNELS)
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH})
endif()
/**
* FreeRDP: A Remote Desktop Protocol client.
* FreeRDP: A Remote Desktop Protocol Implementation
* Audio Input Redirection Virtual Channel - ALSA implementation
*
* Copyright 2010-2011 Vic Lee
......@@ -17,13 +17,24 @@
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winpr/crt.h>
#include <winpr/synch.h>
#include <winpr/thread.h>
#include <winpr/cmdline.h>
#include <alsa/asoundlib.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/thread.h>
#include <freerdp/utils/dsp.h>
#include <freerdp/addin.h>
#include <freerdp/codec/dsp.h>
#include <freerdp/channels/rdpsnd.h>
#include "audin_main.h"
......@@ -31,28 +42,30 @@ typedef struct _AudinALSADevice
{
IAudinDevice iface;
char device_name[32];
uint32 frames_per_packet;
uint32 target_rate;
uint32 actual_rate;
char* device_name;
UINT32 frames_per_packet;
UINT32 target_rate;
UINT32 actual_rate;
snd_pcm_format_t format;
uint32 target_channels;
uint32 actual_channels;
UINT32 target_channels;
UINT32 actual_channels;
int bytes_per_channel;
int wformat;
int block_size;
ADPCM adpcm;
freerdp_thread* thread;
FREERDP_DSP_CONTEXT* dsp_context;
uint8* buffer;
HANDLE thread;
HANDLE stopEvent;
BYTE* buffer;
int buffer_frames;
AudinReceive receive;
void* user_data;
} AudinALSADevice;
static boolean audin_alsa_set_params(AudinALSADevice* alsa, snd_pcm_t* capture_handle)
static BOOL audin_alsa_set_params(AudinALSADevice* alsa, snd_pcm_t* capture_handle)
{
int error;
snd_pcm_hw_params_t* hw_params;
......@@ -61,17 +74,14 @@ static boolean audin_alsa_set_params(AudinALSADevice* alsa, snd_pcm_t* capture_h
{
DEBUG_WARN("snd_pcm_hw_params_malloc (%s)",
snd_strerror(error));
return false;
return FALSE;
}
snd_pcm_hw_params_any(capture_handle, hw_params);
snd_pcm_hw_params_set_access(capture_handle, hw_params,
SND_PCM_ACCESS_RW_INTERLEAVED);
snd_pcm_hw_params_set_format(capture_handle, hw_params,
alsa->format);
snd_pcm_hw_params_set_rate_near(capture_handle, hw_params,
&alsa->actual_rate, NULL);
snd_pcm_hw_params_set_channels_near(capture_handle, hw_params,
&alsa->actual_channels);
snd_pcm_hw_params_set_access(capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
snd_pcm_hw_params_set_format(capture_handle, hw_params, alsa->format);
snd_pcm_hw_params_set_rate_near(capture_handle, hw_params, &alsa->actual_rate, NULL);
snd_pcm_hw_params_set_channels_near(capture_handle, hw_params, &alsa->actual_channels);
snd_pcm_hw_params(capture_handle, hw_params);
snd_pcm_hw_params_free(hw_params);
snd_pcm_prepare(capture_handle);
......@@ -84,19 +94,19 @@ static boolean audin_alsa_set_params(AudinALSADevice* alsa, snd_pcm_t* capture_h
alsa->actual_rate, alsa->actual_channels,
alsa->target_rate, alsa->target_channels);
}
return true;
return TRUE;
}
static boolean audin_alsa_thread_receive(AudinALSADevice* alsa, uint8* src, int size)
static BOOL audin_alsa_thread_receive(AudinALSADevice* alsa, BYTE* src, int size)
{
int frames;
int cframes;
int ret = 0;
int encoded_size;
uint8* encoded_data;
BYTE* encoded_data;
int rbytes_per_frame;
int tbytes_per_frame;
uint8* resampled_data;
rbytes_per_frame = alsa->actual_channels * alsa->bytes_per_channel;
tbytes_per_frame = alsa->target_channels * alsa->bytes_per_channel;
......@@ -104,38 +114,45 @@ static boolean audin_alsa_thread_receive(AudinALSADevice* alsa, uint8* src, int
if ((alsa->target_rate == alsa->actual_rate) &&
(alsa->target_channels == alsa->actual_channels))
{
resampled_data = NULL;
frames = size / rbytes_per_frame;
}
else
{
resampled_data = dsp_resample(src, alsa->bytes_per_channel,
alsa->dsp_context->resample(alsa->dsp_context, src, alsa->bytes_per_channel,
alsa->actual_channels, alsa->actual_rate, size / rbytes_per_frame,
alsa->target_channels, alsa->target_rate, &frames);
alsa->target_channels, alsa->target_rate);
frames = alsa->dsp_context->resampled_frames;
DEBUG_DVC("resampled %d frames at %d to %d frames at %d",
size / rbytes_per_frame, alsa->actual_rate, frames, alsa->target_rate);
size = frames * tbytes_per_frame;
src = resampled_data;
src = alsa->dsp_context->resampled_buffer;
}
while (frames > 0)
{
if (freerdp_thread_is_stopped(alsa->thread))
if (WaitForSingleObject(alsa->stopEvent, 0) == WAIT_OBJECT_0)
break;
cframes = alsa->frames_per_packet - alsa->buffer_frames;
if (cframes > frames)
cframes = frames;
memcpy(alsa->buffer + alsa->buffer_frames * tbytes_per_frame,
src, cframes * tbytes_per_frame);
CopyMemory(alsa->buffer + alsa->buffer_frames * tbytes_per_frame, src, cframes * tbytes_per_frame);
alsa->buffer_frames += cframes;
if (alsa->buffer_frames >= alsa->frames_per_packet)
{
if (alsa->wformat == 0x11)
if (alsa->wformat == WAVE_FORMAT_DVI_ADPCM)
{
encoded_data = dsp_encode_ima_adpcm(&alsa->adpcm,
alsa->dsp_context->encode_ima_adpcm(alsa->dsp_context,
alsa->buffer, alsa->buffer_frames * tbytes_per_frame,
alsa->target_channels, alsa->block_size, &encoded_size);
alsa->target_channels, alsa->block_size);
encoded_data = alsa->dsp_context->adpcm_buffer;
encoded_size = alsa->dsp_context->adpcm_size;
DEBUG_DVC("encoded %d to %d",
alsa->buffer_frames * tbytes_per_frame, encoded_size);
}
......@@ -145,33 +162,33 @@ static boolean audin_alsa_thread_receive(AudinALSADevice* alsa, uint8* src, int
encoded_size = alsa->buffer_frames * tbytes_per_frame;
}
if (freerdp_thread_is_stopped(alsa->thread))
if (WaitForSingleObject(alsa->stopEvent, 0) == WAIT_OBJECT_0)
{
ret = 0;
frames = 0;
}
else
{
ret = alsa->receive(encoded_data, encoded_size, alsa->user_data);
}
alsa->buffer_frames = 0;
if (encoded_data != alsa->buffer)
xfree(encoded_data);
if (!ret)
break;
}
src += cframes * tbytes_per_frame;
frames -= cframes;
}
if (resampled_data)
xfree(resampled_data);
return ret;
}
static void* audin_alsa_thread_func(void* arg)
{
int error;
uint8* buffer;
BYTE* buffer;
int rbytes_per_frame;
int tbytes_per_frame;
snd_pcm_t* capture_handle = NULL;
......@@ -181,10 +198,13 @@ static void* audin_alsa_thread_func(void* arg)
rbytes_per_frame = alsa->actual_channels * alsa->bytes_per_channel;
tbytes_per_frame = alsa->target_channels * alsa->bytes_per_channel;
alsa->buffer = (uint8*) xzalloc(tbytes_per_frame * alsa->frames_per_packet);
alsa->buffer = (BYTE*) malloc(tbytes_per_frame * alsa->frames_per_packet);
ZeroMemory(alsa->buffer, tbytes_per_frame * alsa->frames_per_packet);
alsa->buffer_frames = 0;
buffer = (uint8*) xzalloc(rbytes_per_frame * alsa->frames_per_packet);
memset(&alsa->adpcm, 0, sizeof(ADPCM));
buffer = (BYTE*) malloc(rbytes_per_frame * alsa->frames_per_packet);
ZeroMemory(buffer, rbytes_per_frame * alsa->frames_per_packet);
freerdp_dsp_context_reset_adpcm(alsa->dsp_context);
do
{
if ((error = snd_pcm_open(&capture_handle, alsa->device_name, SND_PCM_STREAM_CAPTURE, 0)) < 0)
......@@ -192,14 +212,16 @@ static void* audin_alsa_thread_func(void* arg)
DEBUG_WARN("snd_pcm_open (%s)", snd_strerror(error));
break;
}
if (!audin_alsa_set_params(alsa, capture_handle))
{
break;
}
while (!freerdp_thread_is_stopped(alsa->thread))
while (!(WaitForSingleObject(alsa->stopEvent, 0) == WAIT_OBJECT_0))
{
error = snd_pcm_readi(capture_handle, buffer, alsa->frames_per_packet);
if (error == -EPIPE)
{
snd_pcm_recover(capture_handle, error, 0);
......@@ -210,18 +232,22 @@ static void* audin_alsa_thread_func(void* arg)
DEBUG_WARN("snd_pcm_readi (%s)", snd_strerror(error));
break;
}
if (!audin_alsa_thread_receive(alsa, buffer, error * rbytes_per_frame))
break;
}
} while (0);
}
while (0);
free(buffer);
xfree(buffer);
xfree(alsa->buffer);
free(alsa->buffer);
alsa->buffer = NULL;
if (capture_handle)
snd_pcm_close(capture_handle);
freerdp_thread_quit(alsa->thread);
SetEvent(alsa->stopEvent);
DEBUG_DVC("out");
......@@ -232,37 +258,43 @@ static void audin_alsa_free(IAudinDevice* device)
{
AudinALSADevice* alsa = (AudinALSADevice*) device;
freerdp_thread_free(alsa->thread);
xfree(alsa);
SetEvent(alsa->stopEvent);
freerdp_dsp_context_free(alsa->dsp_context);
free(alsa->device_name);
free(alsa);
}
static boolean audin_alsa_format_supported(IAudinDevice* device, audinFormat* format)
static BOOL audin_alsa_format_supported(IAudinDevice* device, audinFormat* format)
{
switch (format->wFormatTag)
{
case 1: /* PCM */
case WAVE_FORMAT_PCM:
if (format->cbSize == 0 &&
(format->nSamplesPerSec <= 48000) &&
(format->wBitsPerSample == 8 || format->wBitsPerSample == 16) &&
(format->nChannels == 1 || format->nChannels == 2))
{
return true;
return TRUE;
}
break;
case 0x11: /* IMA ADPCM */
case WAVE_FORMAT_DVI_ADPCM:
if ((format->nSamplesPerSec <= 48000) &&
(format->wBitsPerSample == 4) &&
(format->nChannels == 1 || format->nChannels == 2))
{
return true;
return TRUE;
}
break;
}
return false;
return FALSE;
}
static void audin_alsa_set_format(IAudinDevice* device, audinFormat* format, uint32 FramesPerPacket)
static void audin_alsa_set_format(IAudinDevice* device, audinFormat* format, UINT32 FramesPerPacket)
{
int bs;
AudinALSADevice* alsa = (AudinALSADevice*) device;
......@@ -271,9 +303,10 @@ static void audin_alsa_set_format(IAudinDevice* device, audinFormat* format, uin
alsa->actual_rate = format->nSamplesPerSec;
alsa->target_channels = format->nChannels;
alsa->actual_channels = format->nChannels;
switch (format->wFormatTag)
{
case 1: /* PCM */
case WAVE_FORMAT_PCM:
switch (format->wBitsPerSample)
{
case 8:
......@@ -287,7 +320,7 @@ static void audin_alsa_set_format(IAudinDevice* device, audinFormat* format, uin
}
break;
case 0x11: /* IMA ADPCM */
case WAVE_FORMAT_DVI_ADPCM:
alsa->format = SND_PCM_FORMAT_S16_LE;
alsa->bytes_per_channel = 2;
bs = (format->nBlockAlign - 4 * format->nChannels) * 4;
......@@ -297,6 +330,7 @@ static void audin_alsa_set_format(IAudinDevice* device, audinFormat* format, uin
alsa->frames_per_packet);
break;
}
alsa->wformat = format->wFormatTag;
alsa->block_size = format->nBlockAlign;
}
......@@ -310,7 +344,8 @@ static void audin_alsa_open(IAudinDevice* device, AudinReceive receive, void* us
alsa->receive = receive;
alsa->user_data = user_data;
freerdp_thread_start(alsa->thread, audin_alsa_thread_func, alsa);
alsa->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
alsa->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) audin_alsa_thread_func, alsa, 0, NULL);
}
static void audin_alsa_close(IAudinDevice* device)
......@@ -319,18 +354,59 @@ static void audin_alsa_close(IAudinDevice* device)
DEBUG_DVC("");
freerdp_thread_stop(alsa->thread);
SetEvent(alsa->stopEvent);
alsa->receive = NULL;
alsa->user_data = NULL;
}
int FreeRDPAudinDeviceEntry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints)
COMMAND_LINE_ARGUMENT_A audin_alsa_args[] =
{
{ "audio-dev", COMMAND_LINE_VALUE_REQUIRED, "<device>", NULL, NULL, -1, NULL, "audio device name" },
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
};
static void audin_alsa_parse_addin_args(AudinALSADevice* device, ADDIN_ARGV* args)
{
int status;
DWORD flags;
COMMAND_LINE_ARGUMENT_A* arg;
AudinALSADevice* alsa = (AudinALSADevice*) device;
flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON;
status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv, audin_alsa_args, flags, alsa, NULL, NULL);
arg = audin_alsa_args;
do
{
if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
continue;
CommandLineSwitchStart(arg)
CommandLineSwitchCase(arg, "audio-dev")
{
alsa->device_name = _strdup(arg->Value);
}
CommandLineSwitchEnd(arg)
}
while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
}
#ifdef STATIC_CHANNELS
#define freerdp_audin_client_subsystem_entry alsa_freerdp_audin_client_subsystem_entry
#endif
int freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints)
{
ADDIN_ARGV* args;
AudinALSADevice* alsa;
RDP_PLUGIN_DATA* data;
alsa = xnew(AudinALSADevice);
alsa = (AudinALSADevice*) malloc(sizeof(AudinALSADevice));
ZeroMemory(alsa, sizeof(AudinALSADevice));
alsa->iface.Open = audin_alsa_open;
alsa->iface.FormatSupported = audin_alsa_format_supported;
......@@ -338,17 +414,12 @@ int FreeRDPAudinDeviceEntry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints)
alsa->iface.Close = audin_alsa_close;
alsa->iface.Free = audin_alsa_free;
data = pEntryPoints->plugin_data;
if (data && data->data[0] && strcmp(data->data[0], "audin") == 0 &&
data->data[1] && strcmp(data->data[1], "alsa") == 0)
{
if (data[2].size)
strncpy(alsa->device_name, (char*)data->data[2], sizeof(alsa->device_name));
}
if (alsa->device_name[0] == '\0')
{
strcpy(alsa->device_name, "default");
}
args = pEntryPoints->args;
audin_alsa_parse_addin_args(alsa, args);
if (!alsa->device_name)
alsa->device_name = _strdup("default");
alsa->frames_per_packet = 128;
alsa->target_rate = 22050;
......@@ -357,10 +428,10 @@ int FreeRDPAudinDeviceEntry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints)
alsa->target_channels = 2;
alsa->actual_channels = 2;
alsa->bytes_per_channel = 2;
alsa->thread = freerdp_thread_new();
alsa->dsp_context = freerdp_dsp_context_new();
pEntryPoints->pRegisterAudinDevice(pEntryPoints->plugin, (IAudinDevice*) alsa);
return 0;
}
/**
* FreeRDP: A Remote Desktop Protocol client.
* FreeRDP: A Remote Desktop Protocol Implementation
* Audio Input Redirection Virtual Channel
*
* Copyright 2010-2011 Vic Lee
......@@ -17,12 +17,20 @@
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/stream.h>
#include <freerdp/utils/load_plugin.h>
#include <winpr/crt.h>
#include <winpr/cmdline.h>
#include <freerdp/addin.h>
#include <winpr/stream.h>
#include "audin_main.h"
......@@ -69,82 +77,85 @@ struct _AUDIN_PLUGIN
AUDIN_LISTENER_CALLBACK* listener_callback;
/* Parsed plugin data */
uint16 fixed_format;
uint16 fixed_channel;
uint32 fixed_rate;
UINT16 fixed_format;
UINT16 fixed_channel;
UINT32 fixed_rate;
char* subsystem;
char* device_name;
/* Device interface */
IAudinDevice* device;
};
static int audin_process_version(IWTSVirtualChannelCallback* pChannelCallback, STREAM* s)
static int audin_process_version(IWTSVirtualChannelCallback* pChannelCallback, wStream* s)
{
int error;
STREAM* out;
uint32 Version;
wStream* out;
UINT32 Version;
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
stream_read_uint32(s, Version);
Stream_Read_UINT32(s, Version);
DEBUG_DVC("Version=%d", Version);
out = stream_new(5);
stream_write_uint8(out, MSG_SNDIN_VERSION);
stream_write_uint32(out, Version);
error = callback->channel->Write(callback->channel, stream_get_length(s), stream_get_head(s), NULL);
stream_free(out);
out = Stream_New(NULL, 5);
Stream_Write_UINT8(out, MSG_SNDIN_VERSION);
Stream_Write_UINT32(out, Version);
error = callback->channel->Write(callback->channel, Stream_GetPosition(s), Stream_Buffer(s), NULL);
Stream_Free(out, TRUE);
return error;
}
static int audin_send_incoming_data_pdu(IWTSVirtualChannelCallback* pChannelCallback)
{
uint8 out_data[1];
BYTE out_data[1];
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
out_data[0] = MSG_SNDIN_DATA_INCOMING;
return callback->channel->Write(callback->channel, 1, out_data, NULL);
}
static int audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback, STREAM* s)
static int audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback, wStream* s)
{
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) callback->plugin;
uint32 i;
uint8* fm;
UINT32 i;
BYTE* fm;
int error;
STREAM* out;
uint32 NumFormats;
wStream* out;
UINT32 NumFormats;
audinFormat format;
uint32 cbSizeFormatsPacket;
UINT32 cbSizeFormatsPacket;
stream_read_uint32(s, NumFormats);
Stream_Read_UINT32(s, NumFormats);
DEBUG_DVC("NumFormats %d", NumFormats);
if ((NumFormats < 1) || (NumFormats > 1000))
{
DEBUG_WARN("bad NumFormats %d", NumFormats);
return 1;
}
stream_seek_uint32(s); /* cbSizeFormatsPacket */
Stream_Seek_UINT32(s); /* cbSizeFormatsPacket */
callback->formats = (audinFormat*) xzalloc(NumFormats * sizeof(audinFormat));
callback->formats = (audinFormat*) malloc(NumFormats * sizeof(audinFormat));
ZeroMemory(callback->formats, NumFormats * sizeof(audinFormat));
out = stream_new(9);
stream_seek(out, 9);
out = Stream_New(NULL, 9);
Stream_Seek(out, 9);
/* SoundFormats (variable) */
for (i = 0; i < NumFormats; i++)
{
stream_get_mark(s, fm);
stream_read_uint16(s, format.wFormatTag);
stream_read_uint16(s, format.nChannels);
stream_read_uint32(s, format.nSamplesPerSec);
stream_seek_uint32(s); /* nAvgBytesPerSec */
stream_read_uint16(s, format.nBlockAlign);
stream_read_uint16(s, format.wBitsPerSample);
stream_read_uint16(s, format.cbSize);
format.data = stream_get_tail(s);
stream_seek(s, format.cbSize);
Stream_GetPointer(s, fm);
Stream_Read_UINT16(s, format.wFormatTag);
Stream_Read_UINT16(s, format.nChannels);
Stream_Read_UINT32(s, format.nSamplesPerSec);
Stream_Seek_UINT32(s); /* nAvgBytesPerSec */
Stream_Read_UINT16(s, format.nBlockAlign);
Stream_Read_UINT16(s, format.wBitsPerSample);
Stream_Read_UINT16(s, format.cbSize);
format.data = Stream_Pointer(s);
Stream_Seek(s, format.cbSize);
DEBUG_DVC("wFormatTag=%d nChannels=%d nSamplesPerSec=%d "
"nBlockAlign=%d wBitsPerSample=%d cbSize=%d",
......@@ -164,91 +175,91 @@ static int audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback, S
/* Store the agreed format in the corresponding index */
callback->formats[callback->formats_count++] = format;
/* Put the format to output buffer */
stream_check_size(out, 18 + format.cbSize);
stream_write(out, fm, 18 + format.cbSize);
Stream_EnsureRemainingCapacity(out, 18 + format.cbSize);
Stream_Write(out, fm, 18 + format.cbSize);
}
}
audin_send_incoming_data_pdu(pChannelCallback);
cbSizeFormatsPacket = stream_get_pos(out);
stream_set_pos(out, 0);
cbSizeFormatsPacket = Stream_GetPosition(out);
Stream_SetPosition(out, 0);
stream_write_uint8(out, MSG_SNDIN_FORMATS); /* Header (1 byte) */
stream_write_uint32(out, callback->formats_count); /* NumFormats (4 bytes) */
stream_write_uint32(out, cbSizeFormatsPacket); /* cbSizeFormatsPacket (4 bytes) */
Stream_Write_UINT8(out, MSG_SNDIN_FORMATS); /* Header (1 byte) */
Stream_Write_UINT32(out, callback->formats_count); /* NumFormats (4 bytes) */
Stream_Write_UINT32(out, cbSizeFormatsPacket); /* cbSizeFormatsPacket (4 bytes) */
error = callback->channel->Write(callback->channel, cbSizeFormatsPacket, stream_get_head(out), NULL);
stream_free(out);
error = callback->channel->Write(callback->channel, cbSizeFormatsPacket, Stream_Buffer(out), NULL);
Stream_Free(out, TRUE);
return error;
}
static int audin_send_format_change_pdu(IWTSVirtualChannelCallback* pChannelCallback, uint32 NewFormat)
static int audin_send_format_change_pdu(IWTSVirtualChannelCallback* pChannelCallback, UINT32 NewFormat)
{
int error;
STREAM* out;
wStream* out;
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
out = stream_new(5);
stream_write_uint8(out, MSG_SNDIN_FORMATCHANGE);
stream_write_uint32(out, NewFormat);
error = callback->channel->Write(callback->channel, 5, stream_get_head(out), NULL);
stream_free(out);
out = Stream_New(NULL, 5);
Stream_Write_UINT8(out, MSG_SNDIN_FORMATCHANGE);
Stream_Write_UINT32(out, NewFormat);
error = callback->channel->Write(callback->channel, 5, Stream_Buffer(out), NULL);
Stream_Free(out, TRUE);
return error;
}
static int audin_send_open_reply_pdu(IWTSVirtualChannelCallback* pChannelCallback, uint32 Result)
static int audin_send_open_reply_pdu(IWTSVirtualChannelCallback* pChannelCallback, UINT32 Result)
{
int error;
STREAM* out;
wStream* out;
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
out = stream_new(5);
stream_write_uint8(out, MSG_SNDIN_OPEN_REPLY);
stream_write_uint32(out, Result);
error = callback->channel->Write(callback->channel, 5, stream_get_head(out), NULL);
stream_free(out);
out = Stream_New(NULL, 5);
Stream_Write_UINT8(out, MSG_SNDIN_OPEN_REPLY);
Stream_Write_UINT32(out, Result);
error = callback->channel->Write(callback->channel, 5, Stream_Buffer(out), NULL);
Stream_Free(out, TRUE);
return error;
}
static boolean audin_receive_wave_data(uint8* data, int size, void* user_data)
static BOOL audin_receive_wave_data(BYTE* data, int size, void* user_data)
{
int error;
STREAM* out;
wStream* out;
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) user_data;
error = audin_send_incoming_data_pdu((IWTSVirtualChannelCallback*) callback);
if (error != 0)
return false;
return FALSE;
out = stream_new(size + 1);
stream_write_uint8(out, MSG_SNDIN_DATA);
stream_write(out, data, size);
error = callback->channel->Write(callback->channel, stream_get_length(out), stream_get_head(out), NULL);
stream_free(out);
out = Stream_New(NULL, size + 1);
Stream_Write_UINT8(out, MSG_SNDIN_DATA);
Stream_Write(out, data, size);
error = callback->channel->Write(callback->channel, Stream_GetPosition(out), Stream_Buffer(out), NULL);
Stream_Free(out, TRUE);
return (error == 0 ? true : false);
return (error == 0 ? TRUE : FALSE);
}
static int audin_process_open(IWTSVirtualChannelCallback* pChannelCallback, STREAM* s)
static int audin_process_open(IWTSVirtualChannelCallback* pChannelCallback, wStream* s)
{
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) callback->plugin;
audinFormat* format;
uint32 initialFormat;
uint32 FramesPerPacket;
UINT32 initialFormat;
UINT32 FramesPerPacket;
stream_read_uint32(s, FramesPerPacket);
stream_read_uint32(s, initialFormat);
Stream_Read_UINT32(s, FramesPerPacket);
Stream_Read_UINT32(s, initialFormat);
DEBUG_DVC("FramesPerPacket=%d initialFormat=%d",
FramesPerPacket, initialFormat);
if (initialFormat >= callback->formats_count)
if (initialFormat >= (UINT32) callback->formats_count)
{
DEBUG_WARN("invalid format index %d (total %d)",
initialFormat, callback->formats_count);
......@@ -268,18 +279,18 @@ static int audin_process_open(IWTSVirtualChannelCallback* pChannelCallback, STRE
return 0;
}
static int audin_process_format_change(IWTSVirtualChannelCallback* pChannelCallback, STREAM* s)
static int audin_process_format_change(IWTSVirtualChannelCallback* pChannelCallback, wStream* s)
{
AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback;
AUDIN_PLUGIN * audin = (AUDIN_PLUGIN*) callback->plugin;
uint32 NewFormat;
UINT32 NewFormat;
audinFormat* format;
stream_read_uint32(s, NewFormat);
Stream_Read_UINT32(s, NewFormat);
DEBUG_DVC("NewFormat=%d", NewFormat);
if (NewFormat >= callback->formats_count)
if (NewFormat >= (UINT32) callback->formats_count)
{
DEBUG_WARN("invalid format index %d (total %d)",
NewFormat, callback->formats_count);
......@@ -300,16 +311,15 @@ static int audin_process_format_change(IWTSVirtualChannelCallback* pChannelCallb
return 0;
}
static int audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, uint32 cbSize, uint8* pBuffer)
static int audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, UINT32 cbSize, BYTE* pBuffer)
{
int error;
STREAM* s;
uint8 MessageId;
wStream* s;
BYTE MessageId;
s = stream_new(0);
stream_attach(s, pBuffer, cbSize);
s = Stream_New(pBuffer, cbSize);
stream_read_uint8(s, MessageId);
Stream_Read_UINT8(s, MessageId);
DEBUG_DVC("MessageId=0x%x", MessageId);
......@@ -337,8 +347,7 @@ static int audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
break;
}
stream_detach(s);
stream_free(s);
Stream_Free(s, FALSE);
return error;
}
......@@ -353,14 +362,14 @@ static int audin_on_close(IWTSVirtualChannelCallback* pChannelCallback)
if (audin->device)
IFCALL(audin->device->Close, audin->device);
xfree(callback->formats);
xfree(callback);
free(callback->formats);
free(callback);
return 0;
}
static int audin_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
IWTSVirtualChannel* pChannel, uint8* Data, int* pbAccept,
IWTSVirtualChannel* pChannel, BYTE* Data, int* pbAccept,
IWTSVirtualChannelCallback** ppCallback)
{
AUDIN_CHANNEL_CALLBACK* callback;
......@@ -368,7 +377,8 @@ static int audin_on_new_channel_connection(IWTSListenerCallback* pListenerCallba
DEBUG_DVC("");
callback = xnew(AUDIN_CHANNEL_CALLBACK);
callback = (AUDIN_CHANNEL_CALLBACK*) malloc(sizeof(AUDIN_CHANNEL_CALLBACK));
ZeroMemory(callback, sizeof(AUDIN_CHANNEL_CALLBACK));
callback->iface.OnDataReceived = audin_on_data_received;
callback->iface.OnClose = audin_on_close;
......@@ -387,7 +397,8 @@ static int audin_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManage
DEBUG_DVC("");
audin->listener_callback = xnew(AUDIN_LISTENER_CALLBACK);
audin->listener_callback = (AUDIN_LISTENER_CALLBACK*) malloc(sizeof(AUDIN_LISTENER_CALLBACK));
ZeroMemory(audin->listener_callback, sizeof(AUDIN_LISTENER_CALLBACK));
audin->listener_callback->iface.OnNewChannelConnection = audin_on_new_channel_connection;
audin->listener_callback->plugin = pPlugin;
......@@ -410,8 +421,8 @@ static int audin_plugin_terminated(IWTSPlugin* pPlugin)
audin->device = NULL;
}
xfree(audin->listener_callback);
xfree(audin);
free(audin->listener_callback);
free(audin);
return 0;
}
......@@ -431,114 +442,159 @@ static void audin_register_device_plugin(IWTSPlugin* pPlugin, IAudinDevice* devi
audin->device = device;
}
static boolean audin_load_device_plugin(IWTSPlugin* pPlugin, const char* name, RDP_PLUGIN_DATA* data)
static BOOL audin_load_device_plugin(IWTSPlugin* pPlugin, const char* name, ADDIN_ARGV* args)
{
char* fullname;
PFREERDP_AUDIN_DEVICE_ENTRY entry;
FREERDP_AUDIN_DEVICE_ENTRY_POINTS entryPoints;
if (strrchr(name, '.') != NULL)
{
entry = (PFREERDP_AUDIN_DEVICE_ENTRY) freerdp_load_plugin(name, AUDIN_DEVICE_EXPORT_FUNC_NAME);
}
else
{
fullname = xzalloc(strlen(name) + 8);
strcpy(fullname, "audin_");
strcat(fullname, name);
entry = (PFREERDP_AUDIN_DEVICE_ENTRY) freerdp_load_plugin(fullname, AUDIN_DEVICE_EXPORT_FUNC_NAME);
xfree(fullname);
}
entry = (PFREERDP_AUDIN_DEVICE_ENTRY) freerdp_load_channel_addin_entry("audin", (LPSTR) name, NULL, 0);
if (entry == NULL)
return false;
return FALSE;
entryPoints.plugin = pPlugin;
entryPoints.pRegisterAudinDevice = audin_register_device_plugin;
entryPoints.plugin_data = data;
entryPoints.args = args;
if (entry(&entryPoints) != 0)
{
DEBUG_WARN("%s entry returns error.", name);
return false;
return FALSE;
}
return true;
return TRUE;
}
void audin_set_subsystem(AUDIN_PLUGIN* audin, char* subsystem)
{
if (audin->subsystem)
free(audin->subsystem);
audin->subsystem = _strdup(subsystem);
}
void audin_set_device_name(AUDIN_PLUGIN* audin, char* device_name)
{
if (audin->device_name)
free(audin->device_name);
audin->device_name = _strdup(device_name);
}
static boolean audin_process_plugin_data(IWTSPlugin* pPlugin, RDP_PLUGIN_DATA* data)
COMMAND_LINE_ARGUMENT_A audin_args[] =
{
boolean ret;
{ "sys", COMMAND_LINE_VALUE_REQUIRED, "<subsystem>", NULL, NULL, -1, NULL, "subsystem" },
{ "dev", COMMAND_LINE_VALUE_REQUIRED, "<device>", NULL, NULL, -1, NULL, "device" },
{ "format", COMMAND_LINE_VALUE_REQUIRED, "<format>", NULL, NULL, -1, NULL, "format" },
{ "rate", COMMAND_LINE_VALUE_REQUIRED, "<rate>", NULL, NULL, -1, NULL, "rate" },
{ "channel", COMMAND_LINE_VALUE_REQUIRED, "<channel>", NULL, NULL, -1, NULL, "channel" },
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
};
static BOOL audin_process_addin_args(IWTSPlugin* pPlugin, ADDIN_ARGV* args)
{
int status;
DWORD flags;
COMMAND_LINE_ARGUMENT_A* arg;
AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin;
RDP_PLUGIN_DATA default_data[2] = { { 0 }, { 0 } };
if (data->data[0] && (strcmp((char*)data->data[0], "audin") == 0 || strstr((char*) data->data[0], "/audin.") != NULL))
flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON;
status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv,
audin_args, flags, audin, NULL, NULL);
arg = audin_args;
do
{
if (data->data[1] && strcmp((char*)data->data[1], "format") == 0)
if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
continue;
CommandLineSwitchStart(arg)
CommandLineSwitchCase(arg, "sys")
{
audin->fixed_format = atoi(data->data[2]);
return true;
audin_set_subsystem(audin, arg->Value);
}
else if (data->data[1] && strcmp((char*)data->data[1], "rate") == 0)
CommandLineSwitchCase(arg, "dev")
{
audin->fixed_rate = atoi(data->data[2]);
return true;
audin_set_device_name(audin, arg->Value);
}
else if (data->data[1] && strcmp((char*)data->data[1], "channel") == 0)
CommandLineSwitchCase(arg, "format")
{
audin->fixed_channel = atoi(data->data[2]);
return true;
audin->fixed_format = atoi(arg->Value);
}
else if (data->data[1] && ((char*)data->data[1])[0])
CommandLineSwitchCase(arg, "rate")
{
return audin_load_device_plugin(pPlugin, (char*) data->data[1], data);
audin->fixed_rate = atoi(arg->Value);
}
else
CommandLineSwitchCase(arg, "channel")
{
default_data[0].size = sizeof(RDP_PLUGIN_DATA);
default_data[0].data[0] = "audin";
default_data[0].data[1] = "pulse";
default_data[0].data[2] = "";
ret = audin_load_device_plugin(pPlugin, "pulse", default_data);
if (!ret)
{
default_data[0].size = sizeof(RDP_PLUGIN_DATA);
default_data[0].data[0] = "audin";
default_data[0].data[1] = "alsa";
default_data[0].data[2] = "default";
ret = audin_load_device_plugin(pPlugin, "alsa", default_data);
}
return ret;
audin->fixed_channel = atoi(arg->Value);
}
CommandLineSwitchDefault(arg)
{
}
CommandLineSwitchEnd(arg)
}
while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
return true;
return TRUE;
}
#ifdef STATIC_CHANNELS
#define DVCPluginEntry audin_DVCPluginEntry
#endif
int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
{
int error = 0;
ADDIN_ARGV* args;
AUDIN_PLUGIN* audin;
audin = (AUDIN_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "audin");
if (audin == NULL)
{
audin = xnew(AUDIN_PLUGIN);
audin = (AUDIN_PLUGIN*) malloc(sizeof(AUDIN_PLUGIN));
ZeroMemory(audin, sizeof(AUDIN_PLUGIN));
audin->iface.Initialize = audin_plugin_initialize;
audin->iface.Connected = NULL;
audin->iface.Disconnected = NULL;
audin->iface.Terminated = audin_plugin_terminated;
error = pEntryPoints->RegisterPlugin(pEntryPoints, "audin", (IWTSPlugin*) audin);
}
args = pEntryPoints->GetPluginData(pEntryPoints);
if (error == 0)
audin_process_plugin_data((IWTSPlugin*) audin, pEntryPoints->GetPluginData(pEntryPoints));
audin_process_addin_args((IWTSPlugin*) audin, args);
if (audin->subsystem)
audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args);
if (!audin->device)
{
audin_set_subsystem(audin, "pulse");
audin_set_device_name(audin, "");
audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args);
}
if (!audin->device)
{
audin_set_subsystem(audin, "alsa");
audin_set_device_name(audin, "default");
audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args);
}
if (audin->device == NULL)
{
DEBUG_WARN("no sound device.");
}
return error;
}
/**
* FreeRDP: A Remote Desktop Protocol client.
* FreeRDP: A Remote Desktop Protocol Implementation
* Audio Input Redirection Virtual Channel
*
* Copyright 2010-2011 Vic Lee
......@@ -20,33 +20,46 @@
#ifndef __AUDIN_MAIN_H
#define __AUDIN_MAIN_H
#include "drdynvc_types.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
typedef boolean (*AudinReceive) (uint8* data, int size, void* user_data);
#include <freerdp/dvc.h>
#include <freerdp/types.h>
#include <freerdp/addin.h>
#include <freerdp/utils/debug.h>
#ifdef WITH_DEBUG_DVC
#define DEBUG_DVC(fmt, ...) DEBUG_CLASS(DVC, fmt, ## __VA_ARGS__)
#else
#define DEBUG_DVC(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
#endif
typedef BOOL (*AudinReceive) (BYTE* data, int size, void* user_data);
typedef struct audin_format audinFormat;
struct audin_format
{
uint16 wFormatTag;
uint16 nChannels;
uint32 nSamplesPerSec;
uint16 nBlockAlign;
uint16 wBitsPerSample;
uint16 cbSize;
uint8* data;
UINT16 wFormatTag;
UINT16 nChannels;
UINT32 nSamplesPerSec;
UINT16 nBlockAlign;
UINT16 wBitsPerSample;
UINT16 cbSize;
BYTE* data;
};
typedef struct _IAudinDevice IAudinDevice;
struct _IAudinDevice
{
void (*Open) (IAudinDevice* devplugin, AudinReceive receive, void* user_data);
boolean (*FormatSupported) (IAudinDevice* devplugin, audinFormat* format);
void (*SetFormat) (IAudinDevice* devplugin, audinFormat* format, uint32 FramesPerPacket);
BOOL (*FormatSupported) (IAudinDevice* devplugin, audinFormat* format);
void (*SetFormat) (IAudinDevice* devplugin, audinFormat* format, UINT32 FramesPerPacket);
void (*Close) (IAudinDevice* devplugin);
void (*Free) (IAudinDevice* devplugin);
};
#define AUDIN_DEVICE_EXPORT_FUNC_NAME "FreeRDPAudinDeviceEntry"
#define AUDIN_DEVICE_EXPORT_FUNC_NAME "freerdp_audin_client_subsystem_entry"
typedef void (*PREGISTERAUDINDEVICE)(IWTSPlugin* plugin, IAudinDevice* device);
......@@ -54,7 +67,7 @@ struct _FREERDP_AUDIN_DEVICE_ENTRY_POINTS
{
IWTSPlugin* plugin;
PREGISTERAUDINDEVICE pRegisterAudinDevice;
RDP_PLUGIN_DATA* plugin_data;
ADDIN_ARGV* args;
};
typedef struct _FREERDP_AUDIN_DEVICE_ENTRY_POINTS FREERDP_AUDIN_DEVICE_ENTRY_POINTS;
typedef FREERDP_AUDIN_DEVICE_ENTRY_POINTS* PFREERDP_AUDIN_DEVICE_ENTRY_POINTS;
......
# FreeRDP: A Remote Desktop Protocol Client
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2011 O.S. Systems Software Ltda.
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
# Copyright 2012 Marc-Andre 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.
......@@ -17,41 +15,27 @@
# See the License for the specific language governing permissions and
# limitations under the License.
set(TSMF_SRCS
tsmf_audio.c
tsmf_audio.h
tsmf_codec.c
tsmf_codec.h
tsmf_constants.h
tsmf_decoder.c
tsmf_decoder.h
tsmf_ifman.c
tsmf_ifman.h
tsmf_main.c
tsmf_main.h
tsmf_media.c
tsmf_media.h
tsmf_types.h
)
define_channel_client_subsystem("audin" "pulse" "")
set(${MODULE_PREFIX}_SRCS
audin_pulse.c)
include_directories(..)
include_directories(${PULSE_INCLUDE_DIR})
add_library(tsmf ${TSMF_SRCS})
set_target_properties(tsmf PROPERTIES PREFIX "")
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
target_link_libraries(tsmf freerdp-utils)
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
install(TARGETS tsmf DESTINATION ${FREERDP_PLUGIN_PATH})
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE freerdp
MODULES freerdp-utils)
if(WITH_FFMPEG)
add_subdirectory(ffmpeg)
endif()
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${PULSE_LIBRARY})
if(WITH_ALSA)
add_subdirectory(alsa)
endif()
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
if(WITH_PULSEAUDIO)
add_subdirectory(pulse)
if(NOT STATIC_CHANNELS)
install(TARGETS ${MODULE_NAME} DESTINATION ${FREERDP_ADDIN_PATH})
endif()
/**
* FreeRDP: A Remote Desktop Protocol client.
* FreeRDP: A Remote Desktop Protocol Implementation
* Audio Input Redirection Virtual Channel - PulseAudio implementation
*
* Copyright 2010-2011 Vic Lee
......@@ -17,13 +17,22 @@
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winpr/crt.h>
#include <winpr/cmdline.h>
#include <pulse/pulseaudio.h>
#include <freerdp/types.h>
#include <freerdp/utils/memory.h>
#include <freerdp/utils/dsp.h>
#include <freerdp/addin.h>
#include <freerdp/codec/dsp.h>
#include "audin_main.h"
......@@ -31,18 +40,19 @@ typedef struct _AudinPulseDevice
{
IAudinDevice iface;
char device_name[32];
uint32 frames_per_packet;
char* device_name;
UINT32 frames_per_packet;
pa_threaded_mainloop* mainloop;
pa_context* context;
pa_sample_spec sample_spec;
pa_stream* stream;
int format;
int block_size;
ADPCM adpcm;
FREERDP_DSP_CONTEXT* dsp_context;
int bytes_per_frame;
uint8* buffer;
BYTE* buffer;
int buffer_frames;
AudinReceive receive;
......@@ -74,19 +84,19 @@ static void audin_pulse_context_state_callback(pa_context* context, void* userda
}
}
static boolean audin_pulse_connect(IAudinDevice* device)
static BOOL audin_pulse_connect(IAudinDevice* device)
{
pa_context_state_t state;
AudinPulseDevice* pulse = (AudinPulseDevice*) device;
if (!pulse->context)
return false;
return FALSE;
if (pa_context_connect(pulse->context, NULL, 0, NULL))
{
DEBUG_WARN("pa_context_connect failed (%d)",
pa_context_errno(pulse->context));
return false;
return FALSE;
}
pa_threaded_mainloop_lock(pulse->mainloop);
if (pa_threaded_mainloop_start(pulse->mainloop) < 0)
......@@ -94,7 +104,7 @@ static boolean audin_pulse_connect(IAudinDevice* device)
pa_threaded_mainloop_unlock(pulse->mainloop);
DEBUG_WARN("pa_threaded_mainloop_start failed (%d)",
pa_context_errno(pulse->context));
return false;
return FALSE;
}
for (;;)
{
......@@ -113,12 +123,12 @@ static boolean audin_pulse_connect(IAudinDevice* device)
if (state == PA_CONTEXT_READY)
{
DEBUG_DVC("connected");
return true;
return TRUE;
}
else
{
pa_context_disconnect(pulse->context);
return false;
return FALSE;
}
}
......@@ -145,10 +155,11 @@ static void audin_pulse_free(IAudinDevice* device)
pa_threaded_mainloop_free(pulse->mainloop);
pulse->mainloop = NULL;
}
xfree(pulse);
freerdp_dsp_context_free(pulse->dsp_context);
free(pulse);
}
static boolean audin_pulse_format_supported(IAudinDevice* device, audinFormat* format)
static BOOL audin_pulse_format_supported(IAudinDevice* device, audinFormat* format)
{
AudinPulseDevice* pulse = (AudinPulseDevice*) device;
......@@ -163,7 +174,7 @@ static boolean audin_pulse_format_supported(IAudinDevice* device, audinFormat* f
(format->wBitsPerSample == 8 || format->wBitsPerSample == 16) &&
(format->nChannels >= 1 && format->nChannels <= PA_CHANNELS_MAX))
{
return true;
return TRUE;
}
break;
......@@ -174,7 +185,7 @@ static boolean audin_pulse_format_supported(IAudinDevice* device, audinFormat* f
(format->wBitsPerSample == 8) &&
(format->nChannels >= 1 && format->nChannels <= PA_CHANNELS_MAX))
{
return true;
return TRUE;
}
break;
......@@ -183,14 +194,14 @@ static boolean audin_pulse_format_supported(IAudinDevice* device, audinFormat* f
(format->wBitsPerSample == 4) &&
(format->nChannels == 1 || format->nChannels == 2))
{
return true;
return TRUE;
}
break;
}
return false;
return FALSE;
}
static void audin_pulse_set_format(IAudinDevice* device, audinFormat* format, uint32 FramesPerPacket)
static void audin_pulse_set_format(IAudinDevice* device, audinFormat* format, UINT32 FramesPerPacket)
{
int bs;
pa_sample_spec sample_spec = { 0 };
......@@ -272,11 +283,11 @@ static void audin_pulse_stream_request_callback(pa_stream* stream, size_t length
{
int frames;
int cframes;
boolean ret;
BOOL ret;
const void* data;
const uint8* src;
const BYTE* src;
int encoded_size;
uint8* encoded_data;
BYTE* encoded_data;
AudinPulseDevice* pulse = (AudinPulseDevice*) userdata;
pa_stream_peek(stream, &data, &length);
......@@ -284,7 +295,7 @@ static void audin_pulse_stream_request_callback(pa_stream* stream, size_t length
DEBUG_DVC("length %d frames %d", (int) length, frames);
src = (const uint8*) data;
src = (const BYTE*) data;
while (frames > 0)
{
cframes = pulse->frames_per_packet - pulse->buffer_frames;
......@@ -297,9 +308,11 @@ static void audin_pulse_stream_request_callback(pa_stream* stream, size_t length
{
if (pulse->format == 0x11)
{
encoded_data = dsp_encode_ima_adpcm(&pulse->adpcm,
pulse->dsp_context->encode_ima_adpcm(pulse->dsp_context,
pulse->buffer, pulse->buffer_frames * pulse->bytes_per_frame,
pulse->sample_spec.channels, pulse->block_size, &encoded_size);
pulse->sample_spec.channels, pulse->block_size);
encoded_data = pulse->dsp_context->adpcm_buffer;
encoded_size = pulse->dsp_context->adpcm_size;
DEBUG_DVC("encoded %d to %d",
pulse->buffer_frames * pulse->bytes_per_frame, encoded_size);
}
......@@ -311,8 +324,6 @@ static void audin_pulse_stream_request_callback(pa_stream* stream, size_t length
ret = pulse->receive(encoded_data, encoded_size, pulse->user_data);
pulse->buffer_frames = 0;
if (encoded_data != pulse->buffer)
xfree(encoded_data);
if (!ret)
break;
}
......@@ -343,7 +354,7 @@ static void audin_pulse_close(IAudinDevice* device)
pulse->user_data = NULL;
if (pulse->buffer)
{
xfree(pulse->buffer);
free(pulse->buffer);
pulse->buffer = NULL;
pulse->buffer_frames = 0;
}
......@@ -380,10 +391,10 @@ static void audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u
audin_pulse_stream_state_callback, pulse);
pa_stream_set_read_callback(pulse->stream,
audin_pulse_stream_request_callback, pulse);
buffer_attr.maxlength = (uint32_t) -1;
buffer_attr.tlength = (uint32_t) -1;
buffer_attr.prebuf = (uint32_t) -1;
buffer_attr.minreq = (uint32_t) -1;
buffer_attr.maxlength = (UINT32) -1;
buffer_attr.tlength = (UINT32) -1;
buffer_attr.prebuf = (UINT32) -1;
buffer_attr.minreq = (UINT32) -1;
/* 500ms latency */
buffer_attr.fragsize = pa_usec_to_bytes(500000, &pulse->sample_spec);
if (pa_stream_connect_record(pulse->stream,
......@@ -412,8 +423,9 @@ static void audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u
pa_threaded_mainloop_unlock(pulse->mainloop);
if (state == PA_STREAM_READY)
{
memset(&pulse->adpcm, 0, sizeof(ADPCM));
pulse->buffer = xzalloc(pulse->bytes_per_frame * pulse->frames_per_packet);
freerdp_dsp_context_reset_adpcm(pulse->dsp_context);
pulse->buffer = malloc(pulse->bytes_per_frame * pulse->frames_per_packet);
ZeroMemory(pulse->buffer, pulse->bytes_per_frame * pulse->frames_per_packet);
pulse->buffer_frames = 0;
DEBUG_DVC("connected");
}
......@@ -423,12 +435,53 @@ static void audin_pulse_open(IAudinDevice* device, AudinReceive receive, void* u
}
}
int FreeRDPAudinDeviceEntry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints)
COMMAND_LINE_ARGUMENT_A audin_pulse_args[] =
{
{ "audio-dev", COMMAND_LINE_VALUE_REQUIRED, "<device>", NULL, NULL, -1, NULL, "audio device name" },
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
};
static void audin_pulse_parse_addin_args(AudinPulseDevice* device, ADDIN_ARGV* args)
{
int status;
DWORD flags;
COMMAND_LINE_ARGUMENT_A* arg;
AudinPulseDevice* pulse = (AudinPulseDevice*) device;
flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON;
status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv, audin_pulse_args, flags, pulse, NULL, NULL);
arg = audin_pulse_args;
do
{
if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
continue;
CommandLineSwitchStart(arg)
CommandLineSwitchCase(arg, "audio-dev")
{
pulse->device_name = _strdup(arg->Value);
}
CommandLineSwitchEnd(arg)
}
while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
}
#ifdef STATIC_CHANNELS
#define freerdp_audin_client_subsystem_entry pulse_freerdp_audin_client_subsystem_entry
#endif
int freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints)
{
ADDIN_ARGV* args;
AudinPulseDevice* pulse;
RDP_PLUGIN_DATA * data;
pulse = xnew(AudinPulseDevice);
pulse = (AudinPulseDevice*) malloc(sizeof(AudinPulseDevice));
ZeroMemory(pulse, sizeof(AudinPulseDevice));
pulse->iface.Open = audin_pulse_open;
pulse->iface.FormatSupported = audin_pulse_format_supported;
......@@ -436,28 +489,35 @@ int FreeRDPAudinDeviceEntry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints)
pulse->iface.Close = audin_pulse_close;
pulse->iface.Free = audin_pulse_free;
data = pEntryPoints->plugin_data;
if (data && data->data[0] && strcmp(data->data[0], "audin") == 0 &&
data->data[1] && strcmp(data->data[1], "pulse") == 0)
{
strncpy(pulse->device_name, (char*)data->data[2], sizeof(pulse->device_name));
}
args = pEntryPoints->args;
audin_pulse_parse_addin_args(pulse, args);
if (!pulse->device_name)
pulse->device_name = _strdup("default");
pulse->dsp_context = freerdp_dsp_context_new();
pulse->mainloop = pa_threaded_mainloop_new();
if (!pulse->mainloop)
{
DEBUG_WARN("pa_threaded_mainloop_new failed");
audin_pulse_free((IAudinDevice*) pulse);
return 1;
}
pulse->context = pa_context_new(pa_threaded_mainloop_get_api(pulse->mainloop), "freerdp");
if (!pulse->context)
{
DEBUG_WARN("pa_context_new failed");
audin_pulse_free((IAudinDevice*) pulse);
return 1;
}
pa_context_set_state_callback(pulse->context, audin_pulse_context_state_callback, pulse);
if (!audin_pulse_connect((IAudinDevice*) pulse))
{
audin_pulse_free((IAudinDevice*) pulse);
......@@ -468,4 +528,3 @@ int FreeRDPAudinDeviceEntry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEntryPoints)
return 0;
}
# FreeRDP: A Remote Desktop Protocol Client
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2011 O.S. Systems Software Ltda.
# Copyright 2011 Otavio Salvador <otavio@ossystems.com.br>
# Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
# Copyright 2012 Marc-Andre 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.
......@@ -17,18 +15,18 @@
# See the License for the specific language governing permissions and
# limitations under the License.
set(TSMF_ALSA_SRCS
tsmf_alsa.c
)
define_channel_server("audin")
include_directories(..)
include_directories(${ALSA_INCLUDE_DIRS})
set(${MODULE_PREFIX}_SRCS
audin.c)
add_library(tsmf_alsa ${TSMF_ALSA_SRCS})
set_target_properties(tsmf_alsa PROPERTIES PREFIX "")
add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "DVCPluginEntry")
target_link_libraries(tsmf_alsa freerdp-utils)
target_link_libraries(tsmf_alsa ${ALSA_LIBRARIES})
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
install(TARGETS tsmf_alsa DESTINATION ${FREERDP_PLUGIN_PATH})
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE freerdp
MODULES freerdp-codec freerdp-utils)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server")
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Server Audio Input Virtual Channel
*
* Copyright 2012 Vic Lee
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winpr/crt.h>
#include <winpr/synch.h>
#include <winpr/thread.h>
#include <winpr/stream.h>
#include <freerdp/codec/dsp.h>
#include <freerdp/codec/audio.h>
#include <freerdp/channels/wtsvc.h>
#include <freerdp/server/audin.h>
#define MSG_SNDIN_VERSION 0x01
#define MSG_SNDIN_FORMATS 0x02
#define MSG_SNDIN_OPEN 0x03
#define MSG_SNDIN_OPEN_REPLY 0x04
#define MSG_SNDIN_DATA_INCOMING 0x05
#define MSG_SNDIN_DATA 0x06
#define MSG_SNDIN_FORMATCHANGE 0x07
typedef struct _audin_server
{
audin_server_context context;
BOOL opened;
HANDLE event;
HANDLE stopEvent;
HANDLE thread;
void* audin_channel;
FREERDP_DSP_CONTEXT* dsp_context;
} audin_server;
static void audin_server_select_format(audin_server_context* context, int client_format_index)
{
audin_server* audin = (audin_server*) context;
if (client_format_index >= context->num_client_formats)
return;
context->selected_client_format = client_format_index;
if (audin->opened)
{
/* TODO: send MSG_SNDIN_FORMATCHANGE */
}
}
static void audin_server_send_version(audin_server* audin, wStream* s)
{
Stream_Write_UINT8(s, MSG_SNDIN_VERSION);
Stream_Write_UINT32(s, 1); /* Version (4 bytes) */
WTSVirtualChannelWrite(audin->audin_channel, Stream_Buffer(s), Stream_GetPosition(s), NULL);
}
static BOOL audin_server_recv_version(audin_server* audin, wStream* s, UINT32 length)
{
UINT32 Version;
if (length < 4)
return FALSE;
Stream_Read_UINT32(s, Version);
if (Version < 1)
return FALSE;
return TRUE;
}
static void audin_server_send_formats(audin_server* audin, wStream* s)
{
int i;
UINT32 nAvgBytesPerSec;
Stream_SetPosition(s, 0);
Stream_Write_UINT8(s, MSG_SNDIN_FORMATS);
Stream_Write_UINT32(s, audin->context.num_server_formats); /* NumFormats (4 bytes) */
Stream_Write_UINT32(s, 0); /* cbSizeFormatsPacket (4 bytes), client-to-server only */
for (i = 0; i < audin->context.num_server_formats; i++)
{
nAvgBytesPerSec = audin->context.server_formats[i].nSamplesPerSec *
audin->context.server_formats[i].nChannels *
audin->context.server_formats[i].wBitsPerSample / 8;
Stream_EnsureRemainingCapacity(s, 18);
Stream_Write_UINT16(s, audin->context.server_formats[i].wFormatTag);
Stream_Write_UINT16(s, audin->context.server_formats[i].nChannels);
Stream_Write_UINT32(s, audin->context.server_formats[i].nSamplesPerSec);
Stream_Write_UINT32(s, nAvgBytesPerSec);
Stream_Write_UINT16(s, audin->context.server_formats[i].nBlockAlign);
Stream_Write_UINT16(s, audin->context.server_formats[i].wBitsPerSample);
Stream_Write_UINT16(s, audin->context.server_formats[i].cbSize);
if (audin->context.server_formats[i].cbSize)
{
Stream_EnsureRemainingCapacity(s, audin->context.server_formats[i].cbSize);
Stream_Write(s, audin->context.server_formats[i].data,
audin->context.server_formats[i].cbSize);
}
}
WTSVirtualChannelWrite(audin->audin_channel, Stream_Buffer(s), Stream_GetPosition(s), NULL);
}
static BOOL audin_server_recv_formats(audin_server* audin, wStream* s, UINT32 length)
{
int i;
if (length < 8)
return FALSE;
Stream_Read_UINT32(s, audin->context.num_client_formats); /* NumFormats (4 bytes) */
Stream_Seek_UINT32(s); /* cbSizeFormatsPacket (4 bytes) */
length -= 8;
if (audin->context.num_client_formats <= 0)
return FALSE;
audin->context.client_formats = malloc(audin->context.num_client_formats * sizeof(AUDIO_FORMAT));
ZeroMemory(audin->context.client_formats, audin->context.num_client_formats * sizeof(AUDIO_FORMAT));
for (i = 0; i < audin->context.num_client_formats; i++)
{
if (length < 18)
{
free(audin->context.client_formats);
audin->context.client_formats = NULL;
return FALSE;
}
Stream_Read_UINT16(s, audin->context.client_formats[i].wFormatTag);
Stream_Read_UINT16(s, audin->context.client_formats[i].nChannels);
Stream_Read_UINT32(s, audin->context.client_formats[i].nSamplesPerSec);
Stream_Seek_UINT32(s); /* nAvgBytesPerSec */
Stream_Read_UINT16(s, audin->context.client_formats[i].nBlockAlign);
Stream_Read_UINT16(s, audin->context.client_formats[i].wBitsPerSample);
Stream_Read_UINT16(s, audin->context.client_formats[i].cbSize);
if (audin->context.client_formats[i].cbSize > 0)
{
Stream_Seek(s, audin->context.client_formats[i].cbSize);
}
}
IFCALL(audin->context.Opening, &audin->context);
return TRUE;
}
static void audin_server_send_open(audin_server* audin, wStream* s)
{
if (audin->context.selected_client_format < 0)
return;
audin->opened = TRUE;
Stream_SetPosition(s, 0);
Stream_Write_UINT8(s, MSG_SNDIN_OPEN);
Stream_Write_UINT32(s, audin->context.frames_per_packet); /* FramesPerPacket (4 bytes) */
Stream_Write_UINT32(s, audin->context.selected_client_format); /* initialFormat (4 bytes) */
/*
* [MS-RDPEAI] 3.2.5.1.6
* The second format specify the format that SHOULD be used to capture data from
* the actual audio input device.
*/
Stream_Write_UINT16(s, 1); /* wFormatTag = PCM */
Stream_Write_UINT16(s, 2); /* nChannels */
Stream_Write_UINT32(s, 44100); /* nSamplesPerSec */
Stream_Write_UINT32(s, 44100 * 2 * 2); /* nAvgBytesPerSec */
Stream_Write_UINT16(s, 4); /* nBlockAlign */
Stream_Write_UINT16(s, 16); /* wBitsPerSample */
Stream_Write_UINT16(s, 0); /* cbSize */
WTSVirtualChannelWrite(audin->audin_channel, Stream_Buffer(s), Stream_GetPosition(s), NULL);
}
static BOOL audin_server_recv_open_reply(audin_server* audin, wStream* s, UINT32 length)
{
UINT32 Result;
if (length < 4)
return FALSE;
Stream_Read_UINT32(s, Result);
IFCALL(audin->context.OpenResult, &audin->context, Result);
return TRUE;
}
static BOOL audin_server_recv_data(audin_server* audin, wStream* s, UINT32 length)
{
AUDIO_FORMAT* format;
int sbytes_per_sample;
int sbytes_per_frame;
BYTE* src;
int size;
int frames;
if (audin->context.selected_client_format < 0)
return FALSE;
format = &audin->context.client_formats[audin->context.selected_client_format];
if (format->wFormatTag == WAVE_FORMAT_ADPCM)
{
audin->dsp_context->decode_ms_adpcm(audin->dsp_context,
Stream_Pointer(s), length, format->nChannels, format->nBlockAlign);
size = audin->dsp_context->adpcm_size;
src = audin->dsp_context->adpcm_buffer;
sbytes_per_sample = 2;
sbytes_per_frame = format->nChannels * 2;
}
else if (format->wFormatTag == WAVE_FORMAT_DVI_ADPCM)
{
audin->dsp_context->decode_ima_adpcm(audin->dsp_context,
Stream_Pointer(s), length, format->nChannels, format->nBlockAlign);
size = audin->dsp_context->adpcm_size;
src = audin->dsp_context->adpcm_buffer;
sbytes_per_sample = 2;
sbytes_per_frame = format->nChannels * 2;
}
else
{
size = length;
src = Stream_Pointer(s);
sbytes_per_sample = format->wBitsPerSample / 8;
sbytes_per_frame = format->nChannels * sbytes_per_sample;
}
if (format->nSamplesPerSec == audin->context.dst_format.nSamplesPerSec && format->nChannels == audin->context.dst_format.nChannels)
{
frames = size / sbytes_per_frame;
}
else
{
audin->dsp_context->resample(audin->dsp_context, src, sbytes_per_sample,
format->nChannels, format->nSamplesPerSec, size / sbytes_per_frame,
audin->context.dst_format.nChannels, audin->context.dst_format.nSamplesPerSec);
frames = audin->dsp_context->resampled_frames;
src = audin->dsp_context->resampled_buffer;
}
IFCALL(audin->context.ReceiveSamples, &audin->context, src, frames);
return TRUE;
}
static void* audin_server_thread_func(void* arg)
{
void* fd;
wStream* s;
void* buffer;
BYTE MessageId;
BOOL ready = FALSE;
UINT32 bytes_returned = 0;
audin_server* audin = (audin_server*) arg;
if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualFileHandle, &buffer, &bytes_returned) == TRUE)
{
fd = *((void**) buffer);
WTSFreeMemory(buffer);
audin->event = CreateWaitObjectEvent(NULL, TRUE, FALSE, fd);
}
/* Wait for the client to confirm that the Audio Input dynamic channel is ready */
while (1)
{
WaitForSingleObject(audin->event, INFINITE);
if (WaitForSingleObject(audin->stopEvent, 0) == WAIT_OBJECT_0)
break;
if (WTSVirtualChannelQuery(audin->audin_channel, WTSVirtualChannelReady, &buffer, &bytes_returned) == FALSE)
break;
ready = *((BOOL*) buffer);
WTSFreeMemory(buffer);
if (ready)
break;
}
s = Stream_New(NULL, 4096);
if (ready)
{
audin_server_send_version(audin, s);
}
while (ready)
{
WaitForSingleObject(audin->event, INFINITE);
if (WaitForSingleObject(audin->stopEvent, 0) == WAIT_OBJECT_0)
break;
Stream_SetPosition(s, 0);
if (WTSVirtualChannelRead(audin->audin_channel, 0, Stream_Buffer(s),
Stream_Capacity(s), &bytes_returned) == FALSE)
{
if (bytes_returned == 0)
break;
Stream_EnsureRemainingCapacity(s, (int) bytes_returned);
if (WTSVirtualChannelRead(audin->audin_channel, 0, Stream_Buffer(s),
Stream_Capacity(s), &bytes_returned) == FALSE)
break;
}
if (bytes_returned < 1)
continue;
Stream_Read_UINT8(s, MessageId);
bytes_returned--;
switch (MessageId)
{
case MSG_SNDIN_VERSION:
if (audin_server_recv_version(audin, s, bytes_returned))
audin_server_send_formats(audin, s);
break;
case MSG_SNDIN_FORMATS:
if (audin_server_recv_formats(audin, s, bytes_returned))
audin_server_send_open(audin, s);
break;
case MSG_SNDIN_OPEN_REPLY:
audin_server_recv_open_reply(audin, s, bytes_returned);
break;
case MSG_SNDIN_DATA_INCOMING:
break;
case MSG_SNDIN_DATA:
audin_server_recv_data(audin, s, bytes_returned);
break;
case MSG_SNDIN_FORMATCHANGE:
break;
default:
fprintf(stderr, "audin_server_thread_func: unknown MessageId %d\n", MessageId);
break;
}
}
Stream_Free(s, TRUE);
WTSVirtualChannelClose(audin->audin_channel);
audin->audin_channel = NULL;
return NULL;
}
static BOOL audin_server_open(audin_server_context* context)
{
audin_server* audin = (audin_server*) context;
if (!audin->thread)
{
audin->audin_channel = WTSVirtualChannelOpenEx(context->vcm, "AUDIO_INPUT", WTS_CHANNEL_OPTION_DYNAMIC);
if (!audin->audin_channel)
return FALSE;
audin->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
audin->thread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE) audin_server_thread_func, (void*) audin, 0, NULL);
return TRUE;
}
return FALSE;
}
static BOOL audin_server_close(audin_server_context* context)
{
audin_server* audin = (audin_server*) context;
if (audin->thread)
{
SetEvent(audin->stopEvent);
WaitForSingleObject(audin->thread, INFINITE);
CloseHandle(audin->thread);
audin->thread = NULL;
}
if (audin->audin_channel)
{
WTSVirtualChannelClose(audin->audin_channel);
audin->audin_channel = NULL;
}
audin->context.selected_client_format = -1;
return TRUE;
}
audin_server_context* audin_server_context_new(WTSVirtualChannelManager* vcm)
{
audin_server* audin;
audin = (audin_server*) malloc(sizeof(audin_server));
ZeroMemory(audin, sizeof(audin_server));
audin->context.vcm = vcm;
audin->context.selected_client_format = -1;
audin->context.frames_per_packet = 4096;
audin->context.SelectFormat = audin_server_select_format;
audin->context.Open = audin_server_open;
audin->context.Close = audin_server_close;
audin->dsp_context = freerdp_dsp_context_new();
return (audin_server_context*) audin;
}
void audin_server_context_free(audin_server_context* context)
{
audin_server* audin = (audin_server*) context;
audin_server_close(context);
if (audin->dsp_context)
freerdp_dsp_context_free(audin->dsp_context);
if (audin->context.client_formats)
free(audin->context.client_formats);
free(audin);
}
# FreeRDP: A Remote Desktop Protocol Implementation
# FreeRDP cmake build script
#
# Copyright 2012 Marc-Andre 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.
set(MODULE_NAME "freerdp-channels-client")
set(MODULE_PREFIX "FREERDP_CHANNELS_CLIENT")
set(${MODULE_PREFIX}_SRCS
tables.c
tables.h
addin.c
addin.h
init.c
init.h
open.c
open.h
channels.c
channels.h)
list(REMOVE_DUPLICATES CHANNEL_STATIC_CLIENT_ENTRIES)
foreach(STATIC_ENTRY ${CHANNEL_STATIC_CLIENT_ENTRIES})
foreach(STATIC_MODULE ${CHANNEL_STATIC_CLIENT_MODULES})
if(${${STATIC_MODULE}_CLIENT_ENTRY} STREQUAL ${STATIC_ENTRY})
set(STATIC_MODULE_NAME ${${STATIC_MODULE}_CLIENT_NAME})
set(STATIC_MODULE_CHANNEL ${${STATIC_MODULE}_CLIENT_CHANNEL})
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${STATIC_MODULE_NAME})
set(ENTRY_POINT_NAME "${STATIC_MODULE_CHANNEL}_${${STATIC_MODULE}_CLIENT_ENTRY}")
set(ENTRY_POINT_IMPORT "extern void ${ENTRY_POINT_NAME}();")
set(${STATIC_ENTRY}_IMPORTS "${${STATIC_ENTRY}_IMPORTS}\n${ENTRY_POINT_IMPORT}")
set(${STATIC_ENTRY}_TABLE "${${STATIC_ENTRY}_TABLE}\n\t{ \"${STATIC_MODULE_CHANNEL}\", ${ENTRY_POINT_NAME} },")
endif()
endforeach()
endforeach()
set(CLIENT_STATIC_ENTRY_TABLES_LIST "${CLIENT_STATIC_ENTRY_TABLES_LIST}\nconst STATIC_ENTRY_TABLE CLIENT_STATIC_ENTRY_TABLES[] =\n{")
foreach(STATIC_ENTRY ${CHANNEL_STATIC_CLIENT_ENTRIES})
set(CLIENT_STATIC_ENTRY_IMPORTS "${CLIENT_STATIC_ENTRY_IMPORTS}\n${${STATIC_ENTRY}_IMPORTS}")
set(CLIENT_STATIC_ENTRY_TABLES "${CLIENT_STATIC_ENTRY_TABLES}\nconst STATIC_ENTRY CLIENT_${STATIC_ENTRY}_TABLE[] =\n{")
set(CLIENT_STATIC_ENTRY_TABLES "${CLIENT_STATIC_ENTRY_TABLES}\n${${STATIC_ENTRY}_TABLE}")
set(CLIENT_STATIC_ENTRY_TABLES "${CLIENT_STATIC_ENTRY_TABLES}\n\t{ NULL, NULL }\n};")
set(CLIENT_STATIC_ENTRY_TABLES_LIST "${CLIENT_STATIC_ENTRY_TABLES_LIST}\n\t{ \"${STATIC_ENTRY}\", CLIENT_${STATIC_ENTRY}_TABLE },")
endforeach()
set(CLIENT_STATIC_ENTRY_TABLES_LIST "${CLIENT_STATIC_ENTRY_TABLES_LIST}\n\t{ NULL, NULL }\n};")
set(CLIENT_STATIC_ADDIN_TABLE "const STATIC_ADDIN_TABLE CLIENT_STATIC_ADDIN_TABLE[] =\n{")
foreach(STATIC_MODULE ${CHANNEL_STATIC_CLIENT_MODULES})
set(STATIC_MODULE_NAME ${${STATIC_MODULE}_CLIENT_NAME})
set(STATIC_MODULE_CHANNEL ${${STATIC_MODULE}_CLIENT_CHANNEL})
string(TOUPPER "CLIENT_${STATIC_MODULE_CHANNEL}_SUBSYSTEM_TABLE" SUBSYSTEM_TABLE_NAME)
set(SUBSYSTEM_TABLE "const STATIC_SUBSYSTEM_ENTRY ${SUBSYSTEM_TABLE_NAME}[] =\n{")
get_target_property(CHANNEL_SUBSYSTEMS ${STATIC_MODULE_NAME} SUBSYSTEMS)
if(CHANNEL_SUBSYSTEMS MATCHES "NOTFOUND")
set(CHANNEL_SUBSYSTEMS "")
endif()
foreach(STATIC_SUBSYSTEM ${CHANNEL_SUBSYSTEMS})
if(${STATIC_SUBSYSTEM} MATCHES "^([^-]*)-(.*)")
string(REGEX REPLACE "^([^-]*)-(.*)" "\\1" STATIC_SUBSYSTEM_NAME ${STATIC_SUBSYSTEM})
string(REGEX REPLACE "^([^-]*)-(.*)" "\\2" STATIC_SUBSYSTEM_TYPE ${STATIC_SUBSYSTEM})
else()
set(STATIC_SUBSYSTEM_NAME "${STATIC_SUBSYSTEM}")
set(STATIC_SUBSYSTEM_TYPE "")
endif()
string(LENGTH "${STATIC_SUBSYSTEM_TYPE}" _type_length)
set(SUBSYSTEM_MODULE_NAME "${STATIC_MODULE_NAME}-${STATIC_SUBSYSTEM}")
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${SUBSYSTEM_MODULE_NAME})
if(_type_length GREATER 0)
set(STATIC_SUBSYSTEM_ENTRY "${STATIC_SUBSYSTEM_NAME}_freerdp_${STATIC_MODULE_CHANNEL}_client_${STATIC_SUBSYSTEM_TYPE}_subsystem_entry")
else()
set(STATIC_SUBSYSTEM_ENTRY "${STATIC_SUBSYSTEM_NAME}_freerdp_${STATIC_MODULE_CHANNEL}_client_subsystem_entry")
endif()
set(SUBSYSTEM_TABLE "${SUBSYSTEM_TABLE}\n\t{ \"${STATIC_SUBSYSTEM_NAME}\", \"${STATIC_SUBSYSTEM_TYPE}\", ${STATIC_SUBSYSTEM_ENTRY} },")
set(SUBSYSTEM_IMPORT "extern void ${STATIC_SUBSYSTEM_ENTRY}();")
set(CLIENT_STATIC_SUBSYSTEM_IMPORTS "${CLIENT_STATIC_SUBSYSTEM_IMPORTS}\n${SUBSYSTEM_IMPORT}")
endforeach()
set(SUBSYSTEM_TABLE "${SUBSYSTEM_TABLE}\n\t{ NULL, NULL, NULL }\n};")
set(CLIENT_STATIC_SUBSYSTEM_TABLES "${CLIENT_STATIC_SUBSYSTEM_TABLES}\n${SUBSYSTEM_TABLE}")
set(ENTRY_POINT_NAME "${STATIC_MODULE_CHANNEL}_${${STATIC_MODULE}_CLIENT_ENTRY}")
set(CLIENT_STATIC_ADDIN_TABLE "${CLIENT_STATIC_ADDIN_TABLE}\n\t{ \"${STATIC_MODULE_CHANNEL}\", ${ENTRY_POINT_NAME}, ${SUBSYSTEM_TABLE_NAME} },")
endforeach()
set(CLIENT_STATIC_ADDIN_TABLE "${CLIENT_STATIC_ADDIN_TABLE}\n\t{ NULL, NULL, NULL }\n};")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tables.c.in ${CMAKE_CURRENT_SOURCE_DIR}/tables.c)
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE freerdp
MODULES freerdp-utils)
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE winpr
MODULES winpr-crt winpr-path winpr-file winpr-synch winpr-library winpr-interlocked)
set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} PARENT_SCOPE)
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE)
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Channel Addins
*
* Copyright 2012 Marc-Andre 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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <winpr/crt.h>
#include <winpr/path.h>
#include <winpr/file.h>
#include <winpr/synch.h>
#include <winpr/library.h>
#include <winpr/collections.h>
#include <freerdp/addin.h>
#include <freerdp/client/channels.h>
#include "tables.h"
#include "addin.h"
extern const STATIC_ENTRY_TABLE CLIENT_STATIC_ENTRY_TABLES[];
void* freerdp_channels_find_static_entry_in_table(const STATIC_ENTRY_TABLE* table, const char* identifier)
{
int index = 0;
STATIC_ENTRY* pEntry;
pEntry = (STATIC_ENTRY*) &table->table[index++];
while (pEntry->entry != NULL)
{
if (strcmp(pEntry->name, identifier) == 0)
{
return (void*) pEntry->entry;
}
pEntry = (STATIC_ENTRY*) &table->table[index++];
}
return NULL;
}
void* freerdp_channels_client_find_static_entry(const char* name, const char* identifier)
{
int index = 0;
STATIC_ENTRY_TABLE* pEntry;
pEntry = (STATIC_ENTRY_TABLE*) &CLIENT_STATIC_ENTRY_TABLES[index++];
while (pEntry->table != NULL)
{
if (strcmp(pEntry->name, name) == 0)
{
return freerdp_channels_find_static_entry_in_table(pEntry, identifier);
}
pEntry = (STATIC_ENTRY_TABLE*) &CLIENT_STATIC_ENTRY_TABLES[index++];
}
return NULL;
}
extern const STATIC_ADDIN_TABLE CLIENT_STATIC_ADDIN_TABLE[];
FREERDP_ADDIN** freerdp_channels_list_client_static_addins(LPSTR pszName, LPSTR pszSubsystem, LPSTR pszType, DWORD dwFlags)
{
int i, j;
DWORD nAddins;
FREERDP_ADDIN* pAddin;
FREERDP_ADDIN** ppAddins = NULL;
STATIC_SUBSYSTEM_ENTRY* subsystems;
nAddins = 0;
ppAddins = (FREERDP_ADDIN**) malloc(sizeof(FREERDP_ADDIN*) * 128);
ppAddins[nAddins] = NULL;
for (i = 0; CLIENT_STATIC_ADDIN_TABLE[i].name != NULL; i++)
{
pAddin = (FREERDP_ADDIN*) malloc(sizeof(FREERDP_ADDIN));
ZeroMemory(pAddin, sizeof(FREERDP_ADDIN));
strcpy(pAddin->cName, CLIENT_STATIC_ADDIN_TABLE[i].name);
pAddin->dwFlags = FREERDP_ADDIN_CLIENT;
pAddin->dwFlags |= FREERDP_ADDIN_STATIC;
pAddin->dwFlags |= FREERDP_ADDIN_NAME;
ppAddins[nAddins++] = pAddin;
subsystems = (STATIC_SUBSYSTEM_ENTRY*) CLIENT_STATIC_ADDIN_TABLE[i].table;
for (j = 0; subsystems[j].name != NULL; j++)
{
pAddin = (FREERDP_ADDIN*) malloc(sizeof(FREERDP_ADDIN));
ZeroMemory(pAddin, sizeof(FREERDP_ADDIN));
strcpy(pAddin->cName, CLIENT_STATIC_ADDIN_TABLE[i].name);
strcpy(pAddin->cSubsystem, subsystems[j].name);
pAddin->dwFlags = FREERDP_ADDIN_CLIENT;
pAddin->dwFlags |= FREERDP_ADDIN_STATIC;
pAddin->dwFlags |= FREERDP_ADDIN_NAME;
pAddin->dwFlags |= FREERDP_ADDIN_SUBSYSTEM;
ppAddins[nAddins++] = pAddin;
}
}
ppAddins[nAddins] = NULL;
return ppAddins;
}
FREERDP_ADDIN** freerdp_channels_list_dynamic_addins(LPSTR pszName, LPSTR pszSubsystem, LPSTR pszType, DWORD dwFlags)
{
int index;
int nDashes;
HANDLE hFind;
DWORD nAddins;
LPSTR pszPattern;
size_t cchPattern;
LPCSTR pszAddinPath = FREERDP_ADDIN_PATH;
LPCSTR pszInstallPrefix = FREERDP_INSTALL_PREFIX;
LPCSTR pszExtension;
LPSTR pszSearchPath;
size_t cchSearchPath;
size_t cchAddinPath;
size_t cchInstallPrefix;
FREERDP_ADDIN** ppAddins;
WIN32_FIND_DATAA FindData;
cchAddinPath = strlen(pszAddinPath);
cchInstallPrefix = strlen(pszInstallPrefix);
pszExtension = PathGetSharedLibraryExtensionA(0);
cchPattern = 128 + strlen(pszExtension) + 2;
pszPattern = (LPSTR) malloc(cchPattern + 1);
if (pszName && pszSubsystem && pszType)
{
sprintf_s(pszPattern, cchPattern, "%s-client-%s-%s.%s", pszName, pszSubsystem, pszType, pszExtension);
}
else if (pszName && pszType)
{
sprintf_s(pszPattern, cchPattern, "%s-client-?-%s.%s", pszName, pszType, pszExtension);
}
else if (pszName)
{
sprintf_s(pszPattern, cchPattern, "%s-client*.%s", pszName, pszExtension);
}
else
{
sprintf_s(pszPattern, cchPattern, "?-client*.%s", pszExtension);
}
cchPattern = strlen(pszPattern);
cchSearchPath = cchInstallPrefix + cchAddinPath + cchPattern + 3;
pszSearchPath = (LPSTR) malloc(cchSearchPath + 1);
CopyMemory(pszSearchPath, pszInstallPrefix, cchInstallPrefix);
pszSearchPath[cchInstallPrefix] = '\0';
NativePathCchAppendA(pszSearchPath, cchSearchPath + 1, pszAddinPath);
NativePathCchAppendA(pszSearchPath, cchSearchPath + 1, pszPattern);
cchSearchPath = strlen(pszSearchPath);
hFind = FindFirstFileA(pszSearchPath, &FindData);
nAddins = 0;
ppAddins = (FREERDP_ADDIN**) malloc(sizeof(FREERDP_ADDIN*) * 128);
ppAddins[nAddins] = NULL;
if (hFind == INVALID_HANDLE_VALUE)
return ppAddins;
do
{
char* p[5];
FREERDP_ADDIN* pAddin;
nDashes = 0;
pAddin = (FREERDP_ADDIN*) malloc(sizeof(FREERDP_ADDIN));
ZeroMemory(pAddin, sizeof(FREERDP_ADDIN));
for (index = 0; FindData.cFileName[index]; index++)
nDashes += (FindData.cFileName[index] == '-') ? 1 : 0;
if (nDashes == 1)
{
/* <name>-client.<extension> */
p[0] = FindData.cFileName;
p[1] = strchr(p[0], '-') + 1;
strncpy(pAddin->cName, p[0], (p[1] - p[0]) - 1);
pAddin->dwFlags = FREERDP_ADDIN_CLIENT;
pAddin->dwFlags |= FREERDP_ADDIN_DYNAMIC;
pAddin->dwFlags |= FREERDP_ADDIN_NAME;
ppAddins[nAddins++] = pAddin;
}
else if (nDashes == 2)
{
/* <name>-client-<subsystem>.<extension> */
p[0] = FindData.cFileName;
p[1] = strchr(p[0], '-') + 1;
p[2] = strchr(p[1], '-') + 1;
p[3] = strchr(p[2], '.') + 1;
strncpy(pAddin->cName, p[0], (p[1] - p[0]) - 1);
strncpy(pAddin->cSubsystem, p[2], (p[3] - p[2]) - 1);
pAddin->dwFlags = FREERDP_ADDIN_CLIENT;
pAddin->dwFlags |= FREERDP_ADDIN_DYNAMIC;
pAddin->dwFlags |= FREERDP_ADDIN_NAME;
pAddin->dwFlags |= FREERDP_ADDIN_SUBSYSTEM;
ppAddins[nAddins++] = pAddin;
}
else if (nDashes == 3)
{
/* <name>-client-<subsystem>-<type>.<extension> */
p[0] = FindData.cFileName;
p[1] = strchr(p[0], '-') + 1;
p[2] = strchr(p[1], '-') + 1;
p[3] = strchr(p[2], '-') + 1;
p[4] = strchr(p[3], '.') + 1;
strncpy(pAddin->cName, p[0], (p[1] - p[0]) - 1);
strncpy(pAddin->cSubsystem, p[2], (p[3] - p[2]) - 1);
strncpy(pAddin->cType, p[3], (p[4] - p[3]) - 1);
pAddin->dwFlags = FREERDP_ADDIN_CLIENT;
pAddin->dwFlags |= FREERDP_ADDIN_DYNAMIC;
pAddin->dwFlags |= FREERDP_ADDIN_NAME;
pAddin->dwFlags |= FREERDP_ADDIN_SUBSYSTEM;
pAddin->dwFlags |= FREERDP_ADDIN_TYPE;
ppAddins[nAddins++] = pAddin;
}
else
{
free(pAddin);
}
}
while (FindNextFileA(hFind, &FindData));
FindClose(hFind);
ppAddins[nAddins] = NULL;
return ppAddins;
}
FREERDP_ADDIN** freerdp_channels_list_addins(LPSTR pszName, LPSTR pszSubsystem, LPSTR pszType, DWORD dwFlags)
{
if (dwFlags & FREERDP_ADDIN_STATIC)
return freerdp_channels_list_client_static_addins(pszName, pszSubsystem, pszType, dwFlags);
else if (dwFlags & FREERDP_ADDIN_DYNAMIC)
return freerdp_channels_list_dynamic_addins(pszName, pszSubsystem, pszType, dwFlags);
return NULL;
}
void freerdp_channels_addin_list_free(FREERDP_ADDIN** ppAddins)
{
int index;
for (index = 0; ppAddins[index] != NULL; index++)
free(ppAddins[index]);
free(ppAddins);
}
void* freerdp_channels_load_static_addin_entry(LPCSTR pszName, LPSTR pszSubsystem, LPSTR pszType, DWORD dwFlags)
{
int i, j;
STATIC_SUBSYSTEM_ENTRY* subsystems;
for (i = 0; CLIENT_STATIC_ADDIN_TABLE[i].name != NULL; i++)
{
if (strcmp(CLIENT_STATIC_ADDIN_TABLE[i].name, pszName) == 0)
{
if (pszSubsystem != NULL)
{
subsystems = (STATIC_SUBSYSTEM_ENTRY*) CLIENT_STATIC_ADDIN_TABLE[i].table;
for (j = 0; subsystems[j].name != NULL; j++)
{
if (strcmp(subsystems[j].name, pszSubsystem) == 0)
{
if (pszType)
{
if (strcmp(subsystems[j].type, pszType) == 0)
return (void*) subsystems[j].entry;
}
else
{
return (void*) subsystems[j].entry;
}
}
}
}
else
{
return (void*) CLIENT_STATIC_ADDIN_TABLE[i].entry;
}
}
}
return NULL;
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment